Posted January 29, 20232 yr Hello! When I'm trying to get items by tag during the recipe serialization, I'm getting an empty list. I have a guess that item tags're not loaded by the time minecraft loads my recipes. Here's my code: Class that saves information about ingredient's count Spoiler public class TagValueStack extends Ingredient.TagValue { private final TagKey<Item> tag; private final int count; public TagValueStack(TagKey<Item> tag, int count) { super(tag); this.tag = tag; this.count = count; } @NotNull public Collection<ItemStack> getItems() { List<ItemStack> list = Lists.newArrayList(); for(Item item : Objects.requireNonNull(ForgeRegistries.ITEMS.tags().getTag(this.tag))) { list.add(new ItemStack(item, this.count)); } if (list.size() == 0 && !net.minecraftforge.common.ForgeConfig.SERVER.treatEmptyTagsAsAir.get()) { list.add(new ItemStack(net.minecraft.world.level.block.Blocks.BARRIER).setHoverName(new net.minecraft.network.chat.TextComponent("Empty Tag: " + this.tag.location()))); } return list; } public JsonObject serialize() { JsonObject jsonobject = super.serialize(); jsonobject.addProperty("count", this.count); return jsonobject; } } Recipe serializer with some aux methods: Spoiler public static Ingredient ingredientFromJson(@Nullable JsonElement json) { if (json != null && !json.isJsonNull()) { if (json.isJsonObject()) { return Ingredient.fromValues(Stream.of(valueFromJson(json.getAsJsonObject()))); } else if (json.isJsonArray()) { JsonArray jsonarray = json.getAsJsonArray(); if (jsonarray.size() == 0) { throw new JsonSyntaxException("Item array cannot be empty, at least one item must be defined"); } else { return Ingredient.fromValues(StreamSupport.stream(jsonarray.spliterator(), false).map((p_151264_) -> { return valueFromJson(GsonHelper.convertToJsonObject(p_151264_, "item")); })); } } else { throw new JsonSyntaxException("Expected item to be object or array of objects"); } } else { throw new JsonSyntaxException("Item cannot be null"); } } public static Ingredient.Value valueFromJson(JsonObject json) { int count = GsonHelper.getAsInt(json, "count", 1); if (json.has("item") && json.has("tag")) { throw new JsonParseException("An ingredient entry is either a tag or an item, not both"); } else if (json.has("item")) { Item item = ShapedRecipe.itemFromJson(json); return new Ingredient.ItemValue(new ItemStack(item, count)); } else if (json.has("tag")) { ResourceLocation resourcelocation = new ResourceLocation(GsonHelper.getAsString(json, "tag")); //TagKey<Item> tagkey = Objects.requireNonNull(ForgeRegistries.ITEMS.tags()).createTagKey(resourcelocation); TagKey<Item> tagkey = TagKey.create(ForgeRegistries.ITEMS.getRegistryKey(), resourcelocation); return new TagValueStack(tagkey, count); } else { throw new JsonParseException("An ingredient entry needs either a tag or an item"); } } /** * Returns a key json object as a Java HashMap. */ static Map<String, Ingredient> keyFromJson(JsonObject keyentry) { Map<String, Ingredient> map = Maps.newHashMap(); for(Map.Entry<String, JsonElement> entry : keyentry.entrySet()) { if (entry.getKey().length() != 1) { throw new JsonSyntaxException("Invalid key entry: '" + entry.getKey() + "' is an invalid symbol (must be 1 character only)."); } if (" ".equals(entry.getKey())) { throw new JsonSyntaxException("Invalid key entry: ' ' is a reserved symbol."); } map.put(entry.getKey(), ingredientFromJson(entry.getValue())); } map.put(" ", Ingredient.EMPTY); return map; } public static class Serializer implements RecipeSerializer<SiegeWorkbenchRecipe> { public static final Serializer INSTANCE = new Serializer(); public static final ResourceLocation ID = new ResourceLocation(SiegeMachines.ID,"siege_workbench"); @Override public SiegeWorkbenchRecipe fromJson(ResourceLocation recipeid, JsonObject json) { Map<String, Ingredient> map = SiegeWorkbenchRecipe.keyFromJson(GsonHelper.getAsJsonObject(json, "key")); String[] astring = SiegeWorkbenchRecipe.shrink(SiegeWorkbenchRecipe.patternFromJson(GsonHelper.getAsJsonArray(json, "pattern"))); int i = astring[0].length(); int j = astring.length; NonNullList<Ingredient> nonnulllist = SiegeWorkbenchRecipe.dissolvePattern(astring, map, i, j); ItemStack result = SiegeWorkbenchRecipe.itemStackFromJson(GsonHelper.getAsJsonObject(json, "result")); System.out.println("------"); for (Ingredient ingredient : nonnulllist) { if (ingredient.getItems().length > 0) System.out.println("fromJson " + ingredient.getItems()[0].getItem() + " " + ingredient.getItems()[0].getCount()); } System.out.println("------"); return new SiegeWorkbenchRecipe(recipeid, i, j, nonnulllist, result); } @Override public SiegeWorkbenchRecipe fromNetwork(ResourceLocation recipeid, FriendlyByteBuf buffer) { int i = buffer.readVarInt(); int j = buffer.readVarInt(); NonNullList<Ingredient> nonnulllist = NonNullList.withSize(i * j, Ingredient.EMPTY); for(int k = 0; k < nonnulllist.size(); ++k) { nonnulllist.set(k, ingredientFromNetwork(buffer)); } System.out.println("------"); for (Ingredient ingredient : nonnulllist) { if (ingredient.getItems().length > 0) System.out.println("fromNetwork " + ingredient.getItems()[0].getItem() + " " + ingredient.getItems()[0].getCount()); } System.out.println("------"); ItemStack itemstack = buffer.readItem(); return new SiegeWorkbenchRecipe(recipeid, i, j, nonnulllist, itemstack); } @Override public void toNetwork(FriendlyByteBuf buffer, SiegeWorkbenchRecipe pRecipe) { buffer.writeVarInt(pRecipe.width); buffer.writeVarInt(pRecipe.height); for(Ingredient ingredient : pRecipe.recipeitems) { ingredient.toNetwork(buffer); } buffer.writeItem(pRecipe.result); } @Override public RecipeSerializer<?> setRegistryName(ResourceLocation name) { return INSTANCE; } @Nullable @Override public ResourceLocation getRegistryName() { return ID; } @Override public Class<RecipeSerializer<?>> getRegistryType() { return Serializer.castClass(RecipeSerializer.class); } @SuppressWarnings("unchecked") // Need this wrapper, because generics private static <G> Class<G> castClass(Class<?> cls) { return (Class<G>)cls; } } Registry: Spoiler public class ModRecipes { public static final DeferredRegister<RecipeSerializer<?>> SERIALIZERS = DeferredRegister.create(ForgeRegistries.RECIPE_SERIALIZERS, SiegeMachines.ID); public static final RegistryObject<RecipeSerializer<SiegeWorkbenchRecipe>> SIEGE_WORKBENCH_SERIALIZER = SERIALIZERS.register("siege_workbench", () -> SiegeWorkbenchRecipe.Serializer.INSTANCE); public static RecipeType<SiegeWorkbenchRecipe> SIEGE_WORKBENCH_RECIPE = new SiegeWorkbenchRecipe.SiegeWorkbenchRecipeType(); public static void register(IEventBus eventBus) { SERIALIZERS.register(eventBus); } } Example of the json recipe file: Spoiler { "type": "siegemachines:siege_workbench", "pattern": [ " bs", "pBi", "lr " ], "key": { "B": { "item": "siegemachines:turret_base", "count": 5 }, "b": { "item": "siegemachines:beam", "count": 8 }, "p": { "tag": "minecraft:planks", "count": 2 }, "i": { "tag": "forge:ingots/iron", "count": 8 }, "s": { "item": "minecraft:string", "count": 3 }, "l": { "item": "minecraft:leather", "count": 1 }, "r": { "tag": "forge:rods/wooden", "count": 4 } }, "result": { "item": "siegemachines:ballista", "count": 1 } } Edited January 30, 20232 yr by Magistu solved
January 29, 20232 yr Set up your serializer to read Item Stacks, then use the tags in your Json files. It will convert the tags to items automatically when crafting. Look at my files as an example here: The recipe type: https://github.com/toadie-odie/TodeVillagers/blob/10_glass_kiln_mostly_done/src/main/java/net/warrentode/todevillagers/recipes/GlassblowingRecipe.java Sample Json Recipe File using a tag for an ingredient: https://github.com/toadie-odie/TodeVillagers/blob/10_glass_kiln_mostly_done/src/main/resources/data/todevillagers/recipes/glass_from_glassblowing_sand.json I hope I fully understood what you're trying to do, and if so, I hope this helps.
January 30, 20232 yr Author not really, I'm trying to make recipes where the items must to be in a certain amount. for this reason I don't use the Ingredient.fromJson() method which doesn't take this into account https://i.ibb.co/rf5CkqM/siege-workbench.png
January 30, 20232 yr Author and Ingredient.fromJson() doesn't work with tags as well. my minecraft version is 1.18.2 and forge version is 40.1.0. maybe it's an issue of this version of forge
January 30, 20232 yr 19 minutes ago, Magistu said: not really, I'm trying to make recipes where the items must to be in a certain amount. for this reason I don't use the Ingredient.fromJson() method which doesn't take this into account https://i.ibb.co/rf5CkqM/siege-workbench.png Not sure, but you might be able to build something using the SimpleCookingRecipe Serializer as a base in order to use the count parameter?
January 30, 20232 yr 13 minutes ago, Magistu said: and Ingredient.fromJson() doesn't work with tags as well. my minecraft version is 1.18.2 and forge version is 40.1.0. maybe it's an issue of this version of forge That doesn't make sense. If that was the case, the vanilla game wouldn't be able to read tags in the recipe Json files either, but it does even in 1.18.2.
January 30, 20232 yr Author thanks for your help. I found that issue: https://github.com/MinecraftForge/MinecraftForge/issues/8498 Edited January 30, 20232 yr by Magistu
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.