From 87c4f90fb26c209d44f0fb595b11c714be3b6f6f Mon Sep 17 00:00:00 2001 From: Technici4n <13494793+Technici4n@users.noreply.github.com> Date: Sat, 2 Apr 2022 09:09:20 +0200 Subject: [PATCH] Fix TagEmptyCondition by passing tag context into conditional and recipe deserializers. (#8546) --- .../advancements/Advancement.java.patch | 11 ++- .../ReloadableServerResources.java.patch | 25 +++++ .../ServerAdvancementManager.java.patch | 25 ++++- .../item/crafting/RecipeManager.java.patch | 42 ++++++++- .../item/crafting/RecipeSerializer.java.patch | 7 +- src/generated_test/resources/.cache/cache | 2 + .../advancements/recipes/conditional3.json | 91 +++++++++++++++++++ .../data_gen_test/recipes/conditional3.json | 55 +++++++++++ .../crafting/ConditionalAdvancement.java | 15 ++- .../common/crafting/ConditionalRecipe.java | 10 +- .../common/crafting/CraftingHelper.java | 22 ++++- .../crafting/conditions/AndCondition.java | 8 +- .../crafting/conditions/ConditionContext.java | 45 +++++++++ .../crafting/conditions/ICondition.java | 43 +++++++++ .../conditions/IConditionBuilder.java | 8 ++ .../crafting/conditions/NotCondition.java | 8 +- .../crafting/conditions/OrCondition.java | 8 +- .../conditions/TagEmptyCondition.java | 11 ++- .../extensions/IForgeRecipeSerializer.java | 25 +++++ src/main/resources/forge.exc | 4 + .../debug/DataGeneratorTest.java | 30 ++++++ 21 files changed, 473 insertions(+), 22 deletions(-) create mode 100644 src/generated_test/resources/data/data_gen_test/advancements/recipes/conditional3.json create mode 100644 src/generated_test/resources/data/data_gen_test/recipes/conditional3.json create mode 100644 src/main/java/net/minecraftforge/common/crafting/conditions/ConditionContext.java create mode 100644 src/main/java/net/minecraftforge/common/extensions/IForgeRecipeSerializer.java diff --git a/patches/minecraft/net/minecraft/advancements/Advancement.java.patch b/patches/minecraft/net/minecraft/advancements/Advancement.java.patch index ba02f67293..56c9ff33a3 100644 --- a/patches/minecraft/net/minecraft/advancements/Advancement.java.patch +++ b/patches/minecraft/net/minecraft/advancements/Advancement.java.patch @@ -10,11 +10,18 @@ private ResourceLocation f_138332_; @Nullable private Advancement f_138333_; -@@ -321,6 +_,7 @@ +@@ -320,7 +_,14 @@ + return "Task Advancement{parentId=" + this.f_138332_ + ", display=" + this.f_138334_ + ", rewards=" + this.f_138335_ + ", criteria=" + this.f_138336_ + ", requirements=" + Arrays.deepToString(this.f_138337_) + "}"; } ++ /** @deprecated Forge: use {@linkplain #fromJson(JsonObject, DeserializationContext, net.minecraftforge.common.crafting.conditions.ICondition.IContext) overload with context}. */ ++ @Deprecated public static Advancement.Builder m_138380_(JsonObject p_138381_, DeserializationContext p_138382_) { -+ if ((p_138381_ = net.minecraftforge.common.crafting.ConditionalAdvancement.processConditional(p_138381_)) == null) return null; ++ return fromJson(p_138381_, p_138382_, net.minecraftforge.common.crafting.conditions.ICondition.IContext.EMPTY); ++ } ++ ++ public static Advancement.Builder fromJson(JsonObject p_138381_, DeserializationContext p_138382_, net.minecraftforge.common.crafting.conditions.ICondition.IContext context) { ++ if ((p_138381_ = net.minecraftforge.common.crafting.ConditionalAdvancement.processConditional(p_138381_, context)) == null) return null; ResourceLocation resourcelocation = p_138381_.has("parent") ? new ResourceLocation(GsonHelper.m_13906_(p_138381_, "parent")) : null; DisplayInfo displayinfo = p_138381_.has("display") ? DisplayInfo.m_14981_(GsonHelper.m_13930_(p_138381_, "display")) : null; AdvancementRewards advancementrewards = p_138381_.has("rewards") ? AdvancementRewards.m_9991_(GsonHelper.m_13930_(p_138381_, "rewards")) : AdvancementRewards.f_9978_; diff --git a/patches/minecraft/net/minecraft/server/ReloadableServerResources.java.patch b/patches/minecraft/net/minecraft/server/ReloadableServerResources.java.patch index 504b073434..382dccdfdb 100644 --- a/patches/minecraft/net/minecraft/server/ReloadableServerResources.java.patch +++ b/patches/minecraft/net/minecraft/server/ReloadableServerResources.java.patch @@ -1,5 +1,30 @@ --- a/net/minecraft/server/ReloadableServerResources.java +++ b/net/minecraft/server/ReloadableServerResources.java +@@ -28,18 +_,22 @@ + private static final Logger f_206845_ = LogUtils.getLogger(); + private static final CompletableFuture f_206846_ = CompletableFuture.completedFuture(Unit.INSTANCE); + private final Commands f_206847_; +- private final RecipeManager f_206848_ = new RecipeManager(); ++ private final RecipeManager f_206848_; + private final TagManager f_206849_; + private final PredicateManager f_206850_ = new PredicateManager(); + private final LootTables f_206851_ = new LootTables(this.f_206850_); + private final ItemModifierManager f_206852_ = new ItemModifierManager(this.f_206850_, this.f_206851_); +- private final ServerAdvancementManager f_206853_ = new ServerAdvancementManager(this.f_206850_); ++ private final ServerAdvancementManager f_206853_; + private final ServerFunctionLibrary f_206854_; + + public ReloadableServerResources(RegistryAccess.Frozen p_206857_, Commands.CommandSelection p_206858_, int p_206859_) { + this.f_206849_ = new TagManager(p_206857_); + this.f_206847_ = new Commands(p_206858_); + this.f_206854_ = new ServerFunctionLibrary(p_206859_, this.f_206847_.m_82094_()); ++ // Forge: pass condition context too ++ var context = new net.minecraftforge.common.crafting.conditions.ConditionContext(this.f_206849_); ++ this.f_206848_ = new RecipeManager(context); ++ this.f_206853_ = new ServerAdvancementManager(this.f_206850_, context); + } + + public ServerFunctionLibrary m_206860_() { @@ -76,7 +_,9 @@ public static CompletableFuture m_206861_(ResourceManager p_206862_, RegistryAccess.Frozen p_206863_, Commands.CommandSelection p_206864_, int p_206865_, Executor p_206866_, Executor p_206867_) { diff --git a/patches/minecraft/net/minecraft/server/ServerAdvancementManager.java.patch b/patches/minecraft/net/minecraft/server/ServerAdvancementManager.java.patch index 0a8cbf74da..64f64a5e88 100644 --- a/patches/minecraft/net/minecraft/server/ServerAdvancementManager.java.patch +++ b/patches/minecraft/net/minecraft/server/ServerAdvancementManager.java.patch @@ -1,9 +1,30 @@ --- a/net/minecraft/server/ServerAdvancementManager.java +++ b/net/minecraft/server/ServerAdvancementManager.java -@@ -38,6 +_,10 @@ +@@ -26,10 +_,18 @@ + private static final Gson f_136022_ = (new GsonBuilder()).create(); + private AdvancementList f_136023_ = new AdvancementList(); + private final PredicateManager f_136024_; ++ private final net.minecraftforge.common.crafting.conditions.ICondition.IContext context; //Forge: add context + ++ /** @deprecated Forge: use {@linkplain ServerAdvancementManager#ServerAdvancementManager(PredicateManager, net.minecraftforge.common.crafting.conditions.ICondition.IContext) constructor with context}. */ ++ @Deprecated + public ServerAdvancementManager(PredicateManager p_136027_) { ++ this(p_136027_, net.minecraftforge.common.crafting.conditions.ICondition.IContext.EMPTY); ++ } ++ ++ public ServerAdvancementManager(PredicateManager p_136027_, net.minecraftforge.common.crafting.conditions.ICondition.IContext context) { + super(f_136022_, "advancements"); + this.f_136024_ = p_136027_; ++ this.context = context; + } + + protected void m_5787_(Map p_136034_, ResourceManager p_136035_, ProfilerFiller p_136036_) { +@@ -37,7 +_,11 @@ + p_136034_.forEach((p_136039_, p_136040_) -> { try { JsonObject jsonobject = GsonHelper.m_13918_(p_136040_, "advancement"); - Advancement.Builder advancement$builder = Advancement.Builder.m_138380_(jsonobject, new DeserializationContext(p_136039_, this.f_136024_)); +- Advancement.Builder advancement$builder = Advancement.Builder.m_138380_(jsonobject, new DeserializationContext(p_136039_, this.f_136024_)); ++ Advancement.Builder advancement$builder = Advancement.Builder.fromJson(jsonobject, new DeserializationContext(p_136039_, this.f_136024_), this.context); + if (advancement$builder == null) { + f_136021_.debug("Skipping loading advancement {} as it's conditions were not met", p_136039_); + return; diff --git a/patches/minecraft/net/minecraft/world/item/crafting/RecipeManager.java.patch b/patches/minecraft/net/minecraft/world/item/crafting/RecipeManager.java.patch index e477d21882..884dff9870 100644 --- a/patches/minecraft/net/minecraft/world/item/crafting/RecipeManager.java.patch +++ b/patches/minecraft/net/minecraft/world/item/crafting/RecipeManager.java.patch @@ -1,5 +1,23 @@ --- a/net/minecraft/world/item/crafting/RecipeManager.java +++ b/net/minecraft/world/item/crafting/RecipeManager.java +@@ -37,9 +_,17 @@ + private Map, Map>> f_44007_ = ImmutableMap.of(); + private Map> f_199900_ = ImmutableMap.of(); + private boolean f_44008_; ++ private final net.minecraftforge.common.crafting.conditions.ICondition.IContext context; //Forge: add context + ++ /** @deprecated Forge: use {@linkplain RecipeManager#RecipeManager(net.minecraftforge.common.crafting.conditions.ICondition.IContext) constructor with context}. */ ++ @Deprecated + public RecipeManager() { ++ this(net.minecraftforge.common.crafting.conditions.ICondition.IContext.EMPTY); ++ } ++ ++ public RecipeManager(net.minecraftforge.common.crafting.conditions.ICondition.IContext context) { + super(f_44005_, "recipes"); ++ this.context = context; + } + + protected void m_5787_(Map p_44037_, ResourceManager p_44038_, ProfilerFiller p_44039_) { @@ -49,9 +_,18 @@ for(Entry entry : p_44037_.entrySet()) { @@ -7,11 +25,12 @@ + if (resourcelocation.m_135815_().startsWith("_")) continue; //Forge: filter anything beginning with "_" as it's used for metadata. try { -+ if (entry.getValue().isJsonObject() && !net.minecraftforge.common.crafting.CraftingHelper.processConditions(entry.getValue().getAsJsonObject(), "conditions")) { +- Recipe recipe = m_44045_(resourcelocation, GsonHelper.m_13918_(entry.getValue(), "top element")); ++ if (entry.getValue().isJsonObject() && !net.minecraftforge.common.crafting.CraftingHelper.processConditions(entry.getValue().getAsJsonObject(), "conditions", this.context)) { + f_44006_.debug("Skipping loading recipe {} as it's conditions were not met", resourcelocation); + continue; + } - Recipe recipe = m_44045_(resourcelocation, GsonHelper.m_13918_(entry.getValue(), "top element")); ++ Recipe recipe = fromJson(resourcelocation, GsonHelper.m_13918_(entry.getValue(), "top element"), this.context); + if (recipe == null) { + f_44006_.info("Skipping loading recipe {} as it's serializer returned null", resourcelocation); + continue; @@ -19,3 +38,22 @@ map.computeIfAbsent(recipe.m_6671_(), (p_44075_) -> { return ImmutableMap.builder(); }).put(resourcelocation, recipe); +@@ -127,11 +_,17 @@ + }); + } + ++ /** @deprecated Forge: use {@linkplain #fromJson(ResourceLocation, JsonObject, net.minecraftforge.common.crafting.conditions.ICondition.IContext) overload with context}. */ ++ @Deprecated + public static Recipe m_44045_(ResourceLocation p_44046_, JsonObject p_44047_) { ++ return fromJson(p_44046_, p_44047_, net.minecraftforge.common.crafting.conditions.ICondition.IContext.EMPTY); ++ } ++ ++ public static Recipe fromJson(ResourceLocation p_44046_, JsonObject p_44047_, net.minecraftforge.common.crafting.conditions.ICondition.IContext context) { + String s = GsonHelper.m_13906_(p_44047_, "type"); + return Registry.f_122865_.m_6612_(new ResourceLocation(s)).orElseThrow(() -> { + return new JsonSyntaxException("Invalid or unsupported recipe type '" + s + "'"); +- }).m_6729_(p_44046_, p_44047_); ++ }).fromJson(p_44046_, p_44047_, context); + } + + public void m_44024_(Iterable> p_44025_) { diff --git a/patches/minecraft/net/minecraft/world/item/crafting/RecipeSerializer.java.patch b/patches/minecraft/net/minecraft/world/item/crafting/RecipeSerializer.java.patch index b095831f09..cb6936df93 100644 --- a/patches/minecraft/net/minecraft/world/item/crafting/RecipeSerializer.java.patch +++ b/patches/minecraft/net/minecraft/world/item/crafting/RecipeSerializer.java.patch @@ -5,12 +5,15 @@ import net.minecraft.resources.ResourceLocation; -public interface RecipeSerializer> { -+public interface RecipeSerializer> extends net.minecraftforge.registries.IForgeRegistryEntry> { ++public interface RecipeSerializer> extends net.minecraftforge.registries.IForgeRegistryEntry>, net.minecraftforge.common.extensions.IForgeRecipeSerializer { RecipeSerializer f_44076_ = m_44098_("crafting_shaped", new ShapedRecipe.Serializer()); RecipeSerializer f_44077_ = m_44098_("crafting_shapeless", new ShapelessRecipe.Serializer()); SimpleRecipeSerializer f_44078_ = m_44098_("crafting_special_armordye", new SimpleRecipeSerializer<>(ArmorDyeRecipe::new)); -@@ -30,6 +_,7 @@ +@@ -28,8 +_,10 @@ + RecipeSerializer f_44095_ = m_44098_("stonecutting", new SingleItemRecipe.Serializer<>(StonecutterRecipe::new)); + RecipeSerializer f_44096_ = m_44098_("smithing", new UpgradeRecipe.Serializer()); ++ //Forge: use fromJson with IContext if you need the context T m_6729_(ResourceLocation p_44103_, JsonObject p_44104_); + @javax.annotation.Nullable diff --git a/src/generated_test/resources/.cache/cache b/src/generated_test/resources/.cache/cache index 38a055837e..d69d0affe8 100644 --- a/src/generated_test/resources/.cache/cache +++ b/src/generated_test/resources/.cache/cache @@ -94,6 +94,7 @@ ba49dc1068fd9c93a458f4267896ea4476187411 assets/tag_based_tool_types/models/item ed9a05f407f40fcf73bf16a488540f33e69d79df data/data_gen_test/advancements/recipes/building_blocks/compound_ingredient_only_vanilla.json a9b940a9341ba1e6836f6cccde57fd84ac6cefde data/data_gen_test/advancements/recipes/building_blocks/intersection_ingredient.json 76e760c8e8a1bbd3fb5538bc2d773c117016c0ce data/data_gen_test/advancements/recipes/conditional2.json +08dbf1b9a554bc216b3cbf29cc54754fb427b0f4 data/data_gen_test/advancements/recipes/conditional3.json eb5a3c9b0eece693b02c1d13095e395b702a0f9d data/data_gen_test/advancements/recipes/tools/contains_nbt_ingredient_item_set.json 5b8b202b81157845e9065a0a92cfd777d0f6dc97 data/data_gen_test/advancements/recipes/tools/contains_nbt_ingredient_single_item.json 139a68aa4991369581091633c15ead8c212a70ce data/data_gen_test/advancements/recipes/tools/difference_ingredient.json @@ -102,6 +103,7 @@ b9f392d257ce4622bd7daa98d601f461b78934c9 data/data_gen_test/advancements/recipes 4b6e057c4ca229e22f57c2fb929173b6ed7dc187 data/data_gen_test/recipes/compound_ingredient_only_vanilla.json ed4cbf1a3a2f5d8969f6346fdc9acdbe81d0c919 data/data_gen_test/recipes/conditional.json ca9827bff0a49957e01cf3887ef5131ad8710320 data/data_gen_test/recipes/conditional2.json +586eb688e4af6fc7e0fc16e5237fddf8f93e9c0d data/data_gen_test/recipes/conditional3.json 82ef22fdcd68a56bfd89fcd65a7d3472761c2b67 data/data_gen_test/recipes/contains_nbt_ingredient_item_set.json 9befa598e96e2ed26ce13290164373e4a37808a7 data/data_gen_test/recipes/contains_nbt_ingredient_single_item.json d39a07652a4e5b7d38e94a00ceb3ae54298ed169 data/data_gen_test/recipes/difference_ingredient.json diff --git a/src/generated_test/resources/data/data_gen_test/advancements/recipes/conditional3.json b/src/generated_test/resources/data/data_gen_test/advancements/recipes/conditional3.json new file mode 100644 index 0000000000..800df01860 --- /dev/null +++ b/src/generated_test/resources/data/data_gen_test/advancements/recipes/conditional3.json @@ -0,0 +1,91 @@ +{ + "advancements": [ + { + "conditions": [ + { + "tag": "minecraft:planks", + "type": "forge:tag_empty" + } + ], + "advancement": { + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "minecraft:netherite_block" + ] + }, + "criteria": { + "has_diamond_block": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "minecraft:diamond_block" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "minecraft:netherite_block" + } + } + }, + "requirements": [ + [ + "has_diamond_block", + "has_the_recipe" + ] + ] + } + }, + { + "conditions": [ + { + "value": { + "tag": "minecraft:planks", + "type": "forge:tag_empty" + }, + "type": "forge:not" + } + ], + "advancement": { + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "minecraft:netherite_block" + ] + }, + "criteria": { + "has_diamond_block": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "minecraft:diamond_block" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "minecraft:netherite_block" + } + } + }, + "requirements": [ + [ + "has_diamond_block", + "has_the_recipe" + ] + ] + } + } + ] +} \ No newline at end of file diff --git a/src/generated_test/resources/data/data_gen_test/recipes/conditional3.json b/src/generated_test/resources/data/data_gen_test/recipes/conditional3.json new file mode 100644 index 0000000000..86727d0774 --- /dev/null +++ b/src/generated_test/resources/data/data_gen_test/recipes/conditional3.json @@ -0,0 +1,55 @@ +{ + "type": "forge:conditional", + "recipes": [ + { + "conditions": [ + { + "tag": "minecraft:planks", + "type": "forge:tag_empty" + } + ], + "recipe": { + "type": "minecraft:crafting_shaped", + "pattern": [ + "XX", + "XX" + ], + "key": { + "X": { + "item": "minecraft:diamond_block" + } + }, + "result": { + "item": "minecraft:netherite_block" + } + } + }, + { + "conditions": [ + { + "value": { + "tag": "minecraft:planks", + "type": "forge:tag_empty" + }, + "type": "forge:not" + } + ], + "recipe": { + "type": "minecraft:crafting_shaped", + "pattern": [ + "XX", + "XX" + ], + "key": { + "X": { + "item": "minecraft:diamond_block" + } + }, + "result": { + "item": "minecraft:netherite_block", + "count": 9 + } + } + } + ] +} \ No newline at end of file diff --git a/src/main/java/net/minecraftforge/common/crafting/ConditionalAdvancement.java b/src/main/java/net/minecraftforge/common/crafting/ConditionalAdvancement.java index 609576b68f..48fe1e3dfb 100644 --- a/src/main/java/net/minecraftforge/common/crafting/ConditionalAdvancement.java +++ b/src/main/java/net/minecraftforge/common/crafting/ConditionalAdvancement.java @@ -29,17 +29,26 @@ public class ConditionalAdvancement return new Builder(); } + /** + * @deprecated Please use {@linkplain #processConditional(JsonObject, ICondition.IContext) the more general overload}. + */ + @Deprecated(forRemoval = true, since = "1.18.2") + @Nullable + public static JsonObject processConditional(JsonObject json) { + return processConditional(json, ICondition.IContext.EMPTY); + } + /** * Processes the conditional advancement during loading. * @param json The incoming json from the advancement file. * @return The advancement that passed the conditions, or null if none did. */ @Nullable - public static JsonObject processConditional(JsonObject json) { + public static JsonObject processConditional(JsonObject json, ICondition.IContext context) { JsonArray entries = GsonHelper.getAsJsonArray(json, "advancements", null); if (entries == null) { - return CraftingHelper.processConditions(json, "conditions") ? json : null; + return CraftingHelper.processConditions(json, "conditions", context) ? json : null; } int idx = 0; @@ -47,7 +56,7 @@ public class ConditionalAdvancement { if (!ele.isJsonObject()) throw new JsonSyntaxException("Invalid advancement entry at index " + idx + " Must be JsonObject"); - if (CraftingHelper.processConditions(GsonHelper.getAsJsonArray(ele.getAsJsonObject(), "conditions"))) + if (CraftingHelper.processConditions(GsonHelper.getAsJsonArray(ele.getAsJsonObject(), "conditions"), context)) return GsonHelper.getAsJsonObject(ele.getAsJsonObject(), "advancement"); idx++; } diff --git a/src/main/java/net/minecraftforge/common/crafting/ConditionalRecipe.java b/src/main/java/net/minecraftforge/common/crafting/ConditionalRecipe.java index d8a4714f37..28f5a2362c 100644 --- a/src/main/java/net/minecraftforge/common/crafting/ConditionalRecipe.java +++ b/src/main/java/net/minecraftforge/common/crafting/ConditionalRecipe.java @@ -65,9 +65,15 @@ public class ConditionalRecipe return (Class)cls; } - @SuppressWarnings("unchecked") // We return a nested one, so we can't know what type it is. @Override public T fromJson(ResourceLocation recipeId, JsonObject json) + { + return fromJson(recipeId, json, ICondition.IContext.EMPTY); + } + + @SuppressWarnings("unchecked") // We return a nested one, so we can't know what type it is. + @Override + public T fromJson(ResourceLocation recipeId, JsonObject json, ICondition.IContext context) { JsonArray items = GsonHelper.getAsJsonArray(json, "recipes"); int idx = 0; @@ -75,7 +81,7 @@ public class ConditionalRecipe { if (!ele.isJsonObject()) throw new JsonSyntaxException("Invalid recipes entry at index " + idx + " Must be JsonObject"); - if (CraftingHelper.processConditions(GsonHelper.getAsJsonArray(ele.getAsJsonObject(), "conditions"))) + if (CraftingHelper.processConditions(GsonHelper.getAsJsonArray(ele.getAsJsonObject(), "conditions"), context)) return (T)RecipeManager.fromJson(recipeId, GsonHelper.getAsJsonObject(ele.getAsJsonObject(), "recipe")); idx++; } diff --git a/src/main/java/net/minecraftforge/common/crafting/CraftingHelper.java b/src/main/java/net/minecraftforge/common/crafting/CraftingHelper.java index 4b2e9c80bf..7ff88aeafc 100644 --- a/src/main/java/net/minecraftforge/common/crafting/CraftingHelper.java +++ b/src/main/java/net/minecraftforge/common/crafting/CraftingHelper.java @@ -199,12 +199,30 @@ public class CraftingHelper return new ItemStack(item, GsonHelper.getAsInt(json, "count", 1)); } + /** + * @deprecated Please use the {@linkplain #processConditions(JsonObject, String, ICondition.IContext) other more general overload}. + */ + @Deprecated(forRemoval = true, since = "1.18.2") public static boolean processConditions(JsonObject json, String memberName) { - return !json.has(memberName) || processConditions(GsonHelper.getAsJsonArray(json, memberName)); + return processConditions(json, memberName, ICondition.IContext.EMPTY); } + public static boolean processConditions(JsonObject json, String memberName, ICondition.IContext context) + { + return !json.has(memberName) || processConditions(GsonHelper.getAsJsonArray(json, memberName), context); + } + + /** + * @deprecated Please use the {@linkplain #processConditions(JsonArray, ICondition.IContext) other more general overload}. + */ + @Deprecated(forRemoval = true, since = "1.18.2") public static boolean processConditions(JsonArray conditions) + { + return processConditions(conditions, ICondition.IContext.EMPTY); + } + + public static boolean processConditions(JsonArray conditions, ICondition.IContext context) { for (int x = 0; x < conditions.size(); x++) { @@ -212,7 +230,7 @@ public class CraftingHelper throw new JsonSyntaxException("Conditions must be an array of JsonObjects"); JsonObject json = conditions.get(x).getAsJsonObject(); - if (!CraftingHelper.getCondition(json).test()) + if (!CraftingHelper.getCondition(json).test(context)) return false; } return true; diff --git a/src/main/java/net/minecraftforge/common/crafting/conditions/AndCondition.java b/src/main/java/net/minecraftforge/common/crafting/conditions/AndCondition.java index d836c30f83..a9d662851e 100644 --- a/src/main/java/net/minecraftforge/common/crafting/conditions/AndCondition.java +++ b/src/main/java/net/minecraftforge/common/crafting/conditions/AndCondition.java @@ -45,10 +45,16 @@ public class AndCondition implements ICondition @Override public boolean test() + { + return test(IContext.EMPTY); + } + + @Override + public boolean test(IContext context) { for (ICondition child : children) { - if (!child.test()) + if (!child.test(context)) return false; } return true; diff --git a/src/main/java/net/minecraftforge/common/crafting/conditions/ConditionContext.java b/src/main/java/net/minecraftforge/common/crafting/conditions/ConditionContext.java new file mode 100644 index 0000000000..0bd3318b60 --- /dev/null +++ b/src/main/java/net/minecraftforge/common/crafting/conditions/ConditionContext.java @@ -0,0 +1,45 @@ +/* + * Minecraft Forge - Forge Development LLC + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.common.crafting.conditions; + +import net.minecraft.core.Holder; +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.Tag; +import net.minecraft.tags.TagManager; + +import java.util.Collections; +import java.util.IdentityHashMap; +import java.util.Map; + +public class ConditionContext implements ICondition.IContext +{ + private final TagManager tagManager; + private Map, Map>>> loadedTags = null; + + public ConditionContext(TagManager tagManager) + { + this.tagManager = tagManager; + } + + @Override + public Map>> getAllTags(ResourceKey> registry) + { + if (loadedTags == null) + { + var tags = tagManager.getResult(); + if (tags.isEmpty()) throw new IllegalStateException("Tags have not been loaded yet."); + + loadedTags = new IdentityHashMap<>(); + for (var loadResult : tags) + { + loadedTags.put(loadResult.key(), (Map) Collections.unmodifiableMap(loadResult.tags())); + } + } + return (Map) loadedTags.getOrDefault(registry, Collections.emptyMap()); + } +} diff --git a/src/main/java/net/minecraftforge/common/crafting/conditions/ICondition.java b/src/main/java/net/minecraftforge/common/crafting/conditions/ICondition.java index 661f12530b..cdf4a59503 100644 --- a/src/main/java/net/minecraftforge/common/crafting/conditions/ICondition.java +++ b/src/main/java/net/minecraftforge/common/crafting/conditions/ICondition.java @@ -5,11 +5,54 @@ package net.minecraftforge.common.crafting.conditions; +import net.minecraft.core.Holder; +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.Tag; +import net.minecraft.tags.TagKey; + +import java.util.Collections; +import java.util.Map; public interface ICondition { ResourceLocation getID(); + default boolean test(IContext context) + { + return test(); + } + + /** + * @deprecated Use {@linkplain #test(IContext) the other more general overload}. + */ + @Deprecated(forRemoval = true, since = "1.18.2") boolean test(); + + interface IContext + { + IContext EMPTY = new IContext() + { + @Override + public Map>> getAllTags(ResourceKey> registry) + { + return Collections.emptyMap(); + } + }; + + /** + * Return the requested tag if available, or an empty tag otherwise. + */ + default Tag> getTag(TagKey key) + { + return getAllTags(key.registry()).getOrDefault(key.location(), Tag.empty()); + } + + /** + * Return all the loaded tags for the passed registry, or an empty map if none is available. + * Note that the map and the tags are unmodifiable. + */ + Map>> getAllTags(ResourceKey> registry); + } } diff --git a/src/main/java/net/minecraftforge/common/crafting/conditions/IConditionBuilder.java b/src/main/java/net/minecraftforge/common/crafting/conditions/IConditionBuilder.java index c6471992fb..67d6b181df 100644 --- a/src/main/java/net/minecraftforge/common/crafting/conditions/IConditionBuilder.java +++ b/src/main/java/net/minecraftforge/common/crafting/conditions/IConditionBuilder.java @@ -5,6 +5,9 @@ package net.minecraftforge.common.crafting.conditions; +import net.minecraft.tags.TagKey; +import net.minecraft.world.item.Item; + public interface IConditionBuilder { default ICondition and(ICondition... values) @@ -41,4 +44,9 @@ public interface IConditionBuilder { return new ModLoadedCondition(modid); } + + default ICondition tagEmpty(TagKey tag) + { + return new TagEmptyCondition(tag.location()); + } } diff --git a/src/main/java/net/minecraftforge/common/crafting/conditions/NotCondition.java b/src/main/java/net/minecraftforge/common/crafting/conditions/NotCondition.java index 3a424d91db..d9e5e20efa 100644 --- a/src/main/java/net/minecraftforge/common/crafting/conditions/NotCondition.java +++ b/src/main/java/net/minecraftforge/common/crafting/conditions/NotCondition.java @@ -29,7 +29,13 @@ public class NotCondition implements ICondition @Override public boolean test() { - return !child.test(); + return test(IContext.EMPTY); + } + + @Override + public boolean test(IContext context) + { + return !child.test(context); } @Override diff --git a/src/main/java/net/minecraftforge/common/crafting/conditions/OrCondition.java b/src/main/java/net/minecraftforge/common/crafting/conditions/OrCondition.java index 1e102f4ec9..a87d553dbb 100644 --- a/src/main/java/net/minecraftforge/common/crafting/conditions/OrCondition.java +++ b/src/main/java/net/minecraftforge/common/crafting/conditions/OrCondition.java @@ -45,10 +45,16 @@ public class OrCondition implements ICondition @Override public boolean test() + { + return test(IContext.EMPTY); + } + + @Override + public boolean test(IContext context) { for (ICondition child : children) { - if (child.test()) + if (child.test(context)) return true; } diff --git a/src/main/java/net/minecraftforge/common/crafting/conditions/TagEmptyCondition.java b/src/main/java/net/minecraftforge/common/crafting/conditions/TagEmptyCondition.java index c9f7fe2cb9..f3c469cbd6 100644 --- a/src/main/java/net/minecraftforge/common/crafting/conditions/TagEmptyCondition.java +++ b/src/main/java/net/minecraftforge/common/crafting/conditions/TagEmptyCondition.java @@ -7,15 +7,12 @@ package net.minecraftforge.common.crafting.conditions; import com.google.gson.JsonObject; -import net.minecraft.core.HolderSet; import net.minecraft.core.Registry; import net.minecraft.tags.TagKey; import net.minecraft.world.item.Item; import net.minecraft.util.GsonHelper; import net.minecraft.resources.ResourceLocation; -import java.util.Iterator; - public class TagEmptyCondition implements ICondition { private static final ResourceLocation NAME = new ResourceLocation("forge", "tag_empty"); @@ -42,10 +39,16 @@ public class TagEmptyCondition implements ICondition return NAME; } + @Override + public boolean test(ICondition.IContext context) + { + return context.getTag(tag).getValues().isEmpty(); + } + @Override public boolean test() { - return !Registry.ITEM.getTag(tag).map(HolderSet.Named::iterator).map(Iterator::hasNext).orElse(false); + return test(IContext.EMPTY); } @Override diff --git a/src/main/java/net/minecraftforge/common/extensions/IForgeRecipeSerializer.java b/src/main/java/net/minecraftforge/common/extensions/IForgeRecipeSerializer.java new file mode 100644 index 0000000000..c70062453f --- /dev/null +++ b/src/main/java/net/minecraftforge/common/extensions/IForgeRecipeSerializer.java @@ -0,0 +1,25 @@ +/* + * Minecraft Forge - Forge Development LLC + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.common.extensions; + +import com.google.gson.JsonObject; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.crafting.Recipe; +import net.minecraft.world.item.crafting.RecipeSerializer; +import net.minecraftforge.common.crafting.conditions.ICondition; + +public interface IForgeRecipeSerializer> +{ + private RecipeSerializer self() + { + return (RecipeSerializer) this; + } + + default T fromJson(ResourceLocation recipeLoc, JsonObject recipeJson, ICondition.IContext context) + { + return self().fromJson(recipeLoc, recipeJson); + } +} diff --git a/src/main/resources/forge.exc b/src/main/resources/forge.exc index 143373ffdc..72ee0ff9dd 100644 --- a/src/main/resources/forge.exc +++ b/src/main/resources/forge.exc @@ -1,3 +1,4 @@ +net/minecraft/advancements/Advancement$Builder.fromJson(Lcom/google/gson/JsonObject;Lnet/minecraft/advancements/critereon/DeserializationContext;Lnet/minecraftforge/common/crafting/conditions/ICondition$IContext;)Lnet/minecraft/advancements/Advancement$Builder;=|p_138381_,p_138382_,context net/minecraft/client/Minecraft.doLoadLevel(Ljava/lang/String;Ljava/util/function/Function;Ljava/util/function/Function;ZLnet/minecraft/client/Minecraft$ExperimentalDialogType;Z)V=|p_205206_,p_205207_,p_205208_,p_205209_,p_205210_,creating net/minecraft/client/gui/screens/MenuScreens.getScreenFactory(Lnet/minecraft/world/inventory/MenuType;Lnet/minecraft/client/Minecraft;ILnet/minecraft/network/chat/Component;)Ljava/util/Optional;=|p_96202_,p_96203_,p_96204_,p_96205_ net/minecraft/client/renderer/FogRenderer.setupFog(Lnet/minecraft/client/Camera;Lnet/minecraft/client/renderer/FogRenderer$FogMode;FZF)V=|p_109025_,p_109026_,p_109027_,p_109028_,partialTicks @@ -23,6 +24,7 @@ net/minecraft/data/tags/ItemTagsProvider.(Lnet/minecraft/data/DataGenerato net/minecraft/data/tags/TagsProvider.(Lnet/minecraft/data/DataGenerator;Lnet/minecraft/core/Registry;Ljava/lang/String;Lnet/minecraftforge/common/data/ExistingFileHelper;)V=|p_126546_,p_126547_,modId,existingFileHelper net/minecraft/gametest/framework/GameTestRegistry.register(Ljava/lang/reflect/Method;Ljava/util/Set;)V=|p_177504_,allowedNamespaces net/minecraft/network/FriendlyByteBuf.writeItemStack(Lnet/minecraft/world/item/ItemStack;Z)Lnet/minecraft/network/FriendlyByteBuf;=|p_130056_,limitedTag +net/minecraft/server/ServerAdvancementManager.(Lnet/minecraft/world/level/storage/loot/PredicateManager;Lnet/minecraftforge/common/crafting/conditions/ICondition$IContext;)V=|p_136027_,context net/minecraft/server/dedicated/DedicatedServer.sendMessage(Lnet/minecraft/network/chat/Component;Ljava/util/UUID;)V=|message,p_108776_ net/minecraft/server/level/ServerLevel.removeEntity(Lnet/minecraft/world/entity/Entity;Z)V=|p_8868_,keepData net/minecraft/server/level/ServerLevel.removeEntityComplete(Lnet/minecraft/world/entity/Entity;Z)V=|p_8865_,keepData @@ -45,6 +47,8 @@ net/minecraft/world/item/ItemStack.onItemUse(Lnet/minecraft/world/item/context/U net/minecraft/world/item/ItemStack.onItemUseFirst(Lnet/minecraft/world/item/context/UseOnContext;)Lnet/minecraft/world/InteractionResult;=|p_41662_ net/minecraft/world/item/MapItem.getCustomMapData(Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/level/Level;)Lnet/minecraft/world/level/saveddata/maps/MapItemSavedData;=|p_42910_,p_42911_ net/minecraft/world/item/alchemy/PotionBrewing$Mix.(Lnet/minecraftforge/registries/ForgeRegistryEntry;Lnet/minecraft/world/item/crafting/Ingredient;Lnet/minecraftforge/registries/ForgeRegistryEntry;)V=|p_43536_,p_43537_,p_43538_ +net/minecraft/world/item/crafting/RecipeManager.(Lnet/minecraftforge/common/crafting/conditions/ICondition$IContext;)V=|context +net/minecraft/world/item/crafting/RecipeManager.fromJson(Lnet/minecraft/resources/ResourceLocation;Lcom/google/gson/JsonObject;Lnet/minecraftforge/common/crafting/conditions/ICondition$IContext;)Lnet/minecraft/world/item/crafting/Recipe;=|p_44046_,p_44047_,context net/minecraft/world/level/Level.markAndNotifyBlock(Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/chunk/LevelChunk;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/block/state/BlockState;II)V=|p_46605_,levelchunk,blockstate,p_46606_,p_46607_,p_46608_ net/minecraft/world/level/LevelSettings.(Ljava/lang/String;Lnet/minecraft/world/level/GameType;ZLnet/minecraft/world/Difficulty;ZLnet/minecraft/world/level/GameRules;Lnet/minecraft/world/level/DataPackConfig;Lcom/mojang/serialization/Lifecycle;)V=|p_46910_,p_46911_,p_46912_,p_46913_,p_46914_,p_46915_,p_46916_,lifecycle net/minecraft/world/level/block/FireBlock.tryCatchFire(Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;ILjava/util/Random;ILnet/minecraft/core/Direction;)V=|p_53432_,p_53433_,p_53434_,p_53435_,p_53436_,face diff --git a/src/test/java/net/minecraftforge/debug/DataGeneratorTest.java b/src/test/java/net/minecraftforge/debug/DataGeneratorTest.java index fb0794a927..62a2e40c1c 100644 --- a/src/test/java/net/minecraftforge/debug/DataGeneratorTest.java +++ b/src/test/java/net/minecraftforge/debug/DataGeneratorTest.java @@ -235,6 +235,36 @@ public class DataGeneratorTest .generateAdvancement() .build(consumer, new ResourceLocation("data_gen_test", "conditional2")); + ConditionalRecipe.builder() + .addCondition( + tagEmpty(ItemTags.PLANKS) + ) + .addRecipe( + ShapedRecipeBuilder.shaped(Blocks.NETHERITE_BLOCK, 1) + .pattern("XX") + .pattern("XX") + .define('X', Blocks.DIAMOND_BLOCK) + .group("") + .unlockedBy("has_diamond_block", has(Blocks.DIAMOND_BLOCK)) + ::save + ) + .addCondition( + not( + tagEmpty(ItemTags.PLANKS) + ) + ) + .addRecipe( + ShapedRecipeBuilder.shaped(Blocks.NETHERITE_BLOCK, 9) + .pattern("XX") + .pattern("XX") + .define('X', Blocks.DIAMOND_BLOCK) + .group("") + .unlockedBy("has_diamond_block", has(Blocks.DIAMOND_BLOCK)) + ::save + ) + .generateAdvancement() + .build(consumer, new ResourceLocation("data_gen_test", "conditional3")); + // ingredient tests // strict NBT match - should match an unnamed iron pickaxe that lost 3 durability Ingredient nbtIngredient = NBTIngredient.of(Util.make(() ->