diff --git a/build.gradle b/build.gradle index acbbfe37e..2cd1372c6 100644 --- a/build.gradle +++ b/build.gradle @@ -314,6 +314,19 @@ project(':forge') { args '--mod', 'forge', '--all', '--output', rootProject.file('src/generated/resources/') } + + forge_test_data { + parent runs.forge_data + taskName 'forge_test_data' + + environment 'MOD_CLASSES', 'dummy' // Needed to work around FG limitation, FG will replace this! + + mods { + tests { sources sourceSets.test } + } + + args '--mod', 'data_gen_test', '--all', '--output', rootProject.file('src/generated_test/resources/') + } } } diff --git a/patches/minecraft/net/minecraft/advancements/AdvancementManager.java.patch b/patches/minecraft/net/minecraft/advancements/AdvancementManager.java.patch new file mode 100644 index 000000000..ff31f937d --- /dev/null +++ b/patches/minecraft/net/minecraft/advancements/AdvancementManager.java.patch @@ -0,0 +1,15 @@ +--- a/net/minecraft/advancements/AdvancementManager.java ++++ b/net/minecraft/advancements/AdvancementManager.java +@@ -36,7 +36,11 @@ + Map map = Maps.newHashMap(); + p_212853_1_.forEach((p_223387_1_, p_223387_2_) -> { + try { +- Advancement.Builder advancement$builder = field_192783_b.fromJson(p_223387_2_, Advancement.Builder.class); ++ Advancement.Builder advancement$builder = net.minecraftforge.common.crafting.ConditionalAdvancement.read(field_192783_b, p_223387_1_, p_223387_2_); ++ if (advancement$builder == null) { ++ field_192782_a.info("Skipping loading advancement {} as it's conditions were not met", p_223387_1_); ++ return; ++ } + map.put(p_223387_1_, advancement$builder); + } catch (IllegalArgumentException | JsonParseException jsonparseexception) { + field_192782_a.error("Parsing error loading custom advancement {}: {}", p_223387_1_, jsonparseexception.getMessage()); diff --git a/patches/minecraft/net/minecraft/data/RecipeProvider.java.patch b/patches/minecraft/net/minecraft/data/RecipeProvider.java.patch new file mode 100644 index 000000000..894fb0051 --- /dev/null +++ b/patches/minecraft/net/minecraft/data/RecipeProvider.java.patch @@ -0,0 +1,10 @@ +--- a/net/minecraft/data/RecipeProvider.java ++++ b/net/minecraft/data/RecipeProvider.java +@@ -58,6 +58,7 @@ + + } + }); ++ if (this.getClass() == RecipeProvider.class) //Forge: Subclasses don't need this. + this.func_208310_b(p_200398_1_, Advancement.Builder.func_200278_a().func_200275_a("impossible", new ImpossibleTrigger.Instance()).func_200273_b(), path.resolve("data/minecraft/advancements/recipes/root.json")); + } + diff --git a/patches/minecraft/net/minecraft/item/crafting/IRecipeSerializer.java.patch b/patches/minecraft/net/minecraft/item/crafting/IRecipeSerializer.java.patch index be748fa25..6d1c6fd51 100644 --- a/patches/minecraft/net/minecraft/item/crafting/IRecipeSerializer.java.patch +++ b/patches/minecraft/net/minecraft/item/crafting/IRecipeSerializer.java.patch @@ -9,3 +9,11 @@ IRecipeSerializer field_222157_a = func_222156_a("crafting_shaped", new ShapedRecipe.Serializer()); IRecipeSerializer field_222158_b = func_222156_a("crafting_shapeless", new ShapelessRecipe.Serializer()); SpecialRecipeSerializer field_222159_c = func_222156_a("crafting_special_armordye", new SpecialRecipeSerializer<>(ArmorDyeRecipe::new)); +@@ -29,6 +29,7 @@ + + T func_199425_a_(ResourceLocation p_199425_1_, JsonObject p_199425_2_); + ++ @javax.annotation.Nullable + T func_199426_a_(ResourceLocation p_199426_1_, PacketBuffer p_199426_2_); + + void func_199427_a_(PacketBuffer p_199427_1_, T p_199427_2_); diff --git a/patches/minecraft/net/minecraft/item/crafting/Ingredient.java.patch b/patches/minecraft/net/minecraft/item/crafting/Ingredient.java.patch index d31a39773..29df8567b 100644 --- a/patches/minecraft/net/minecraft/item/crafting/Ingredient.java.patch +++ b/patches/minecraft/net/minecraft/item/crafting/Ingredient.java.patch @@ -59,7 +59,7 @@ + + public net.minecraftforge.common.crafting.IIngredientSerializer getSerializer() { + if (!isVanilla()) throw new IllegalStateException("Modderrs must implement Ingredient.getSerializer in their custom Ingredients: " + this); -+ return net.minecraftforge.common.crafting.CraftingHelper.INGREDIENT_VANILLA; ++ return net.minecraftforge.common.crafting.VanillaIngredientSerializer.INSTANCE; + } + public static Ingredient func_209357_a(Stream p_209357_0_) { @@ -84,19 +84,7 @@ if (p_199802_0_.isJsonObject()) { return func_209357_a(Stream.of(func_199803_a(p_199802_0_.getAsJsonObject()))); } else if (p_199802_0_.isJsonArray()) { -@@ -169,6 +206,11 @@ - } - - public static Ingredient.IItemList func_199803_a(JsonObject p_199803_0_) { -+ if (p_199803_0_.has("constant")) { -+ Ingredient.IItemList ret = net.minecraftforge.common.crafting.CraftingHelper.getConstant(new ResourceLocation(JSONUtils.func_151200_h(p_199803_0_, "constant"))); -+ if (ret == null) throw new JsonSyntaxException("Ingredient referenced invalid constant: " + JSONUtils.func_151200_h(p_199803_0_, "constant")); -+ return ret; -+ } - if (p_199803_0_.has("item") && p_199803_0_.has("tag")) { - throw new JsonParseException("An ingredient entry is either a tag or an item, not both"); - } else if (p_199803_0_.has("item")) { -@@ -190,6 +232,12 @@ +@@ -190,6 +227,12 @@ } } @@ -109,3 +97,13 @@ public interface IItemList { Collection func_199799_a(); +@@ -228,6 +271,9 @@ + list.add(new ItemStack(item)); + } + ++ if (list.size() == 0 && !net.minecraftforge.common.ForgeConfig.SERVER.treatEmptyTagsAsAir.get()) { ++ list.add(new ItemStack(net.minecraft.block.Blocks.field_180401_cv).func_200302_a(new net.minecraft.util.text.StringTextComponent("Empty Tag: " + field_199800_a.func_199886_b().toString()))); ++ } + return list; + } + diff --git a/patches/minecraft/net/minecraft/item/crafting/RecipeManager.java.patch b/patches/minecraft/net/minecraft/item/crafting/RecipeManager.java.patch index c59bfb90d..f0fa1ba6f 100644 --- a/patches/minecraft/net/minecraft/item/crafting/RecipeManager.java.patch +++ b/patches/minecraft/net/minecraft/item/crafting/RecipeManager.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/item/crafting/RecipeManager.java +++ b/net/minecraft/item/crafting/RecipeManager.java -@@ -50,8 +50,13 @@ +@@ -50,9 +50,18 @@ for(Entry entry : p_212853_1_.entrySet()) { ResourceLocation resourcelocation = entry.getKey(); @@ -12,5 +12,10 @@ + continue; + } IRecipe irecipe = func_215377_a(resourcelocation, entry.getValue()); ++ if (irecipe == null) { ++ field_199521_c.info("Skipping loading recipe {} as it's serializer returned null", resourcelocation); ++ continue; ++ } map.computeIfAbsent(irecipe.func_222127_g(), (p_223391_0_) -> { return ImmutableMap.builder(); + }).put(resourcelocation, irecipe); diff --git a/src/generated_test/resources/.cache/cache b/src/generated_test/resources/.cache/cache new file mode 100644 index 000000000..508842c77 --- /dev/null +++ b/src/generated_test/resources/.cache/cache @@ -0,0 +1,2 @@ +4fbaf6f4a3ea05cc071076e27f44ac81f9cc50e3 data\data_gen_test\advancements\conditional.json +ed4cbf1a3a2f5d8969f6346fdc9acdbe81d0c919 data\data_gen_test\recipes\conditional.json diff --git a/src/generated_test/resources/data/data_gen_test/advancements/conditional.json b/src/generated_test/resources/data/data_gen_test/advancements/conditional.json new file mode 100644 index 000000000..2f1825f7c --- /dev/null +++ b/src/generated_test/resources/data/data_gen_test/advancements/conditional.json @@ -0,0 +1,67 @@ +{ + "advancements": [ + { + "conditions": [ + { + "values": [ + { + "value": { + "modid": "minecraft", + "type": "forge:mod_loaded" + }, + "type": "forge:not" + }, + { + "item": "minecraft:dirt", + "type": "forge:item_exists" + }, + { + "type": "forge:false" + } + ], + "type": "forge:and" + } + ], + "advancement": { + "parent": "minecraft:root", + "display": { + "icon": { + "item": "minecraft:diamond_block" + }, + "title": { + "text": "Dirt2Diamonds" + }, + "description": { + "text": "The BEST crafting recipe in the game!" + }, + "frame": "task", + "show_toast": false, + "announce_to_chat": false, + "hidden": false + }, + "rewards": { + "recipes": [ + "data_gen_test:conditional" + ] + }, + "criteria": { + "has_dirt": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "minecraft:dirt" + } + ] + } + } + }, + "requirements": [ + [ + "has_dirt" + ] + ] + } + } + ] +} \ No newline at end of file diff --git a/src/generated_test/resources/data/data_gen_test/recipes/conditional.json b/src/generated_test/resources/data/data_gen_test/recipes/conditional.json new file mode 100644 index 000000000..4c6c5fc0f --- /dev/null +++ b/src/generated_test/resources/data/data_gen_test/recipes/conditional.json @@ -0,0 +1,45 @@ +{ + "type": "forge:conditional", + "recipes": [ + { + "conditions": [ + { + "values": [ + { + "value": { + "modid": "minecraft", + "type": "forge:mod_loaded" + }, + "type": "forge:not" + }, + { + "item": "minecraft:dirt", + "type": "forge:item_exists" + }, + { + "type": "forge:false" + } + ], + "type": "forge:and" + } + ], + "recipe": { + "type": "minecraft:crafting_shaped", + "pattern": [ + "XXX", + "XXX", + "XXX" + ], + "key": { + "X": { + "item": "minecraft:dirt" + } + }, + "result": { + "item": "minecraft:diamond_block", + "count": 64 + } + } + } + ] +} \ No newline at end of file diff --git a/src/main/java/net/minecraftforge/common/ForgeConfig.java b/src/main/java/net/minecraftforge/common/ForgeConfig.java index 382cf770f..577beec74 100644 --- a/src/main/java/net/minecraftforge/common/ForgeConfig.java +++ b/src/main/java/net/minecraftforge/common/ForgeConfig.java @@ -49,6 +49,8 @@ public class ForgeConfig public final IntValue clumpingThreshold; + public final BooleanValue treatEmptyTagsAsAir; + Server(ForgeConfigSpec.Builder builder) { builder.comment("Server configuration settings") .push("server"); @@ -104,6 +106,11 @@ public class ForgeConfig .worldRestart() .defineInRange("clumpingThreshold", 64, 64, 1024); + treatEmptyTagsAsAir = builder + .comment("Vanilla will treat crafting recipess using empty tags as air, and allow you to craft with nothing in that slot. This changes empty tags to use BARRIER as the item. To prevent crafting with air.") + .translation("forge.configgui.treatEmptyTagsAsAir") + .define("treatEmptyTagsAsAir", false); + builder.pop(); } } diff --git a/src/main/java/net/minecraftforge/common/ForgeMod.java b/src/main/java/net/minecraftforge/common/ForgeMod.java index cb16ec7bf..e89c0d8d3 100644 --- a/src/main/java/net/minecraftforge/common/ForgeMod.java +++ b/src/main/java/net/minecraftforge/common/ForgeMod.java @@ -20,6 +20,7 @@ package net.minecraftforge.common; import net.minecraftforge.eventbus.api.IEventBus; +import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.*; import net.minecraftforge.fml.config.ModConfig; import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; @@ -41,14 +42,32 @@ import org.apache.logging.log4j.Logger; import net.minecraft.command.arguments.ArgumentSerializer; import net.minecraft.command.arguments.ArgumentTypes; import net.minecraft.data.DataGenerator; +import net.minecraft.item.crafting.IRecipe; +import net.minecraft.item.crafting.IRecipeSerializer; import net.minecraft.nbt.CompoundNBT; +import net.minecraft.util.ResourceLocation; import net.minecraft.world.storage.SaveHandler; import net.minecraft.world.storage.WorldInfo; +import net.minecraftforge.common.crafting.CompoundIngredient; +import net.minecraftforge.common.crafting.ConditionalRecipe; +import net.minecraftforge.common.crafting.CraftingHelper; +import net.minecraftforge.common.crafting.IngredientNBT; +import net.minecraftforge.common.crafting.VanillaIngredientSerializer; +import net.minecraftforge.common.crafting.conditions.AndCondition; +import net.minecraftforge.common.crafting.conditions.FalseCondition; +import net.minecraftforge.common.crafting.conditions.ItemExistsCondition; +import net.minecraftforge.common.crafting.conditions.ModLoadedCondition; +import net.minecraftforge.common.crafting.conditions.NotCondition; +import net.minecraftforge.common.crafting.conditions.OrCondition; +import net.minecraftforge.common.crafting.conditions.TagEmptyCondition; +import net.minecraftforge.common.crafting.conditions.TrueCondition; import net.minecraftforge.common.data.ForgeBlockTagsProvider; import net.minecraftforge.common.data.ForgeItemTagsProvider; import net.minecraftforge.common.data.ForgeRecipeProvider; import net.minecraftforge.common.model.animation.CapabilityAnimation; import net.minecraftforge.energy.CapabilityEnergy; +import net.minecraftforge.event.RegistryEvent; +import net.minecraftforge.event.entity.player.PlayerEvent; import net.minecraftforge.fml.event.lifecycle.GatherDataEvent; import net.minecraftforge.fluids.capability.CapabilityFluidHandler; import net.minecraftforge.items.CapabilityItemHandler; @@ -91,6 +110,7 @@ public class ForgeMod implements WorldPersistenceHooks.WorldPersistenceHook final IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus(); modEventBus.addListener(this::preInit); modEventBus.addListener(this::gatherData); + modEventBus.register(this); MinecraftForge.EVENT_BUS.addListener(this::serverStarting); MinecraftForge.EVENT_BUS.addListener(this::serverStopping); ModLoadingContext.get().registerConfig(ModConfig.Type.CLIENT, ForgeConfig.clientSpec); @@ -171,4 +191,24 @@ public class ForgeMod implements WorldPersistenceHooks.WorldPersistenceHook gen.addProvider(new ForgeRecipeProvider(gen)); } } + + @SubscribeEvent //ModBus, can't use addListener due to nested genetics. + public void registerRecipeSerialziers(RegistryEvent.Register> event) + { + CraftingHelper.register(AndCondition.Serializer.INSTANCE); + CraftingHelper.register(FalseCondition.Serializer.INSTANCE); + CraftingHelper.register(ItemExistsCondition.Serializer.INSTANCE); + CraftingHelper.register(ModLoadedCondition.Serializer.INSTANCE); + CraftingHelper.register(NotCondition.Serializer.INSTANCE); + CraftingHelper.register(OrCondition.Serializer.INSTANCE); + CraftingHelper.register(TrueCondition.Serializer.INSTANCE); + CraftingHelper.register(TagEmptyCondition.Serializer.INSTANCE); + + CraftingHelper.register(new ResourceLocation("forge", "compound"), CompoundIngredient.Serializer.INSTANCE); + CraftingHelper.register(new ResourceLocation("forge", "nbt"), IngredientNBT.Serializer.INSTANCE); + CraftingHelper.register(new ResourceLocation("minecraft", "item"), VanillaIngredientSerializer.INSTANCE); + + event.getRegistry().register(new ConditionalRecipe.Serializer>().setRegistryName(new ResourceLocation("forge", "conditional"))); + + } } diff --git a/src/main/java/net/minecraftforge/common/crafting/CompoundIngredient.java b/src/main/java/net/minecraftforge/common/crafting/CompoundIngredient.java index a092b9999..171f77116 100644 --- a/src/main/java/net/minecraftforge/common/crafting/CompoundIngredient.java +++ b/src/main/java/net/minecraftforge/common/crafting/CompoundIngredient.java @@ -29,6 +29,8 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; import com.google.common.collect.Lists; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonSyntaxException; @@ -41,15 +43,15 @@ import net.minecraft.network.PacketBuffer; public class CompoundIngredient extends Ingredient { - private Collection children; + private List children; private ItemStack[] stacks; private IntList itemIds; private final boolean isSimple; - protected CompoundIngredient(Collection children) + protected CompoundIngredient(List children) { super(Stream.of()); - this.children = children; + this.children = Collections.unmodifiableList(children); this.isSimple = children.stream().allMatch(Ingredient::isSimple); } @@ -110,17 +112,34 @@ public class CompoundIngredient extends Ingredient @Override public IIngredientSerializer getSerializer() { - return CraftingHelper.INGREDIENT_COMPOUND; + return Serializer.INSTANCE; } @Nonnull public Collection getChildren() { - return Collections.unmodifiableCollection(this.children); + return this.children; + } + + @Override + public JsonElement serialize() + { + if (this.children.size() == 1) + { + return this.children.get(0).serialize(); + } + else + { + JsonArray json = new JsonArray(); + this.children.stream().forEach(e -> json.add(e.serialize())); + return json; + } } public static class Serializer implements IIngredientSerializer { + public static final Serializer INSTANCE = new Serializer(); + @Override public CompoundIngredient parse(PacketBuffer buffer) { @@ -130,7 +149,7 @@ public class CompoundIngredient extends Ingredient @Override public CompoundIngredient parse(JsonObject json) { - throw new JsonSyntaxException("CompountIngredient should not be directly referenced in json, just use an array of ingredients."); + throw new JsonSyntaxException("CompoundIngredient should not be directly referenced in json, just use an array of ingredients."); } @Override diff --git a/src/main/java/net/minecraftforge/common/crafting/ConditionalAdvancement.java b/src/main/java/net/minecraftforge/common/crafting/ConditionalAdvancement.java new file mode 100644 index 000000000..c1bad65a3 --- /dev/null +++ b/src/main/java/net/minecraftforge/common/crafting/ConditionalAdvancement.java @@ -0,0 +1,130 @@ +/* + * Minecraft Forge + * Copyright (c) 2016-2019. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.common.crafting; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonSyntaxException; + +import net.minecraft.advancements.Advancement; +import net.minecraft.util.JSONUtils; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.common.crafting.conditions.ICondition; + +public class ConditionalAdvancement +{ + public static Builder builder() + { + return new Builder(); + } + + public static Advancement.Builder read(Gson gson, ResourceLocation recipeId, JsonObject json) + { + JsonArray entries = JSONUtils.getJsonArray(json, "advancements", null); + if (entries == null) + { + if (!CraftingHelper.processConditions(json, "conditions")) + return null; + return gson.fromJson(json, Advancement.Builder.class); + } + + int idx = 0; + for (JsonElement ele : entries) + { + if (!ele.isJsonObject()) + throw new JsonSyntaxException("Invalid advancement entry at index " + idx + " Must be JsonObject"); + if (CraftingHelper.processConditions(JSONUtils.getJsonArray(ele.getAsJsonObject(), "conditions"))) + return gson.fromJson(JSONUtils.getJsonObject(ele.getAsJsonObject(), "advancement"), Advancement.Builder.class); + idx++; + } + return null; + } + + public static class Builder + { + private List conditions = new ArrayList<>(); + private List advancements = new ArrayList<>(); + + private List currentConditions = new ArrayList<>(); + private boolean locked = false; + + public Builder addCondition(ICondition condition) + { + if (locked) + throw new IllegalStateException("Attempted to modify finished builder"); + currentConditions.add(condition); + return this; + } + + public Builder addAdvancement(Consumer> callable) + { + if (locked) + throw new IllegalStateException("Attempted to modify finished builder"); + callable.accept(this::addAdvancement); + return this; + } + + public Builder addAdvancement(Advancement.Builder recipe) + { + if (locked) + throw new IllegalStateException("Attempted to modify finished builder"); + if (currentConditions.isEmpty()) + throw new IllegalStateException("Can not add a advancement with no conditions."); + conditions.add(currentConditions.toArray(new ICondition[currentConditions.size()])); + advancements.add(recipe); + currentConditions.clear(); + return this; + } + + public JsonObject write() + { + if (!locked) + { + if (!currentConditions.isEmpty()) + throw new IllegalStateException("Invalid builder state: Orphaned conditions"); + if (advancements.isEmpty()) + throw new IllegalStateException("Invalid builder state: No Advancements"); + locked = true; + } + JsonObject json = new JsonObject(); + JsonArray array = new JsonArray(); + json.add("advancements", array); + for (int x = 0; x < conditions.size(); x++) + { + JsonObject holder = new JsonObject(); + + JsonArray conds = new JsonArray(); + for (ICondition c : conditions.get(x)) + conds.add(CraftingHelper.serialize(c)); + holder.add("conditions", conds); + holder.add("advancement", advancements.get(x).serialize()); + + array.add(holder); + } + return json; + } + } +} diff --git a/src/main/java/net/minecraftforge/common/crafting/ConditionalRecipe.java b/src/main/java/net/minecraftforge/common/crafting/ConditionalRecipe.java new file mode 100644 index 000000000..5af799d7d --- /dev/null +++ b/src/main/java/net/minecraftforge/common/crafting/ConditionalRecipe.java @@ -0,0 +1,219 @@ +/* + * Minecraft Forge + * Copyright (c) 2016-2019. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.common.crafting; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonSyntaxException; + +import net.minecraft.data.IFinishedRecipe; +import net.minecraft.item.crafting.IRecipe; +import net.minecraft.item.crafting.IRecipeSerializer; +import net.minecraft.item.crafting.RecipeManager; +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.JSONUtils; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.common.crafting.conditions.ICondition; +import net.minecraftforge.registries.ObjectHolder; + +public class ConditionalRecipe +{ + @ObjectHolder("forge:conditional") + public static final IRecipeSerializer> SERIALZIER = null; + + public static Builder builder() + { + return new Builder(); + } + + public static class Serializer> implements IRecipeSerializer + { + private ResourceLocation name; + + @Override + public IRecipeSerializer setRegistryName(ResourceLocation name) + { + this.name = name; + return this; + } + + @Override + public ResourceLocation getRegistryName() + { + return name; + } + + @Override + public Class> getRegistryType() + { + return Serializer.>castClass(IRecipeSerializer.class); + } + + @SuppressWarnings("unchecked") // Need this wrapper, because generics + private static Class castClass(Class cls) + { + return (Class)cls; + } + + @SuppressWarnings("unchecked") // We return a nested one, so we can't know what type it is. + @Override + public T read(ResourceLocation recipeId, JsonObject json) + { + JsonArray items = JSONUtils.getJsonArray(json, "recipes"); + int idx = 0; + for (JsonElement ele : items) + { + if (!ele.isJsonObject()) + throw new JsonSyntaxException("Invalid recipes entry at index " + idx + " Must be JsonObject"); + if (CraftingHelper.processConditions(JSONUtils.getJsonArray(ele.getAsJsonObject(), "conditions"))) + return (T)RecipeManager.deserializeRecipe(recipeId, JSONUtils.getJsonObject(ele.getAsJsonObject(), "recipe")); + idx++; + } + return null; + } + + //Should never get here as we return one of the recipes we wrap. + @Override public T read(ResourceLocation recipeId, PacketBuffer buffer) { return null; } + @Override public void write(PacketBuffer buffer, T recipe) {} + } + + public static class Builder + { + private List conditions = new ArrayList<>(); + private List recipes = new ArrayList<>(); + private ResourceLocation advId; + private ConditionalAdvancement.Builder adv; + + private List currentConditions = new ArrayList<>(); + + public Builder addCondition(ICondition condition) + { + currentConditions.add(condition); + return this; + } + + public Builder addRecipe(Consumer> callable) + { + callable.accept(this::addRecipe); + return this; + } + + public Builder addRecipe(IFinishedRecipe recipe) + { + if (currentConditions.isEmpty()) + throw new IllegalStateException("Can not add a recipe with no conditions."); + conditions.add(currentConditions.toArray(new ICondition[currentConditions.size()])); + recipes.add(recipe); + currentConditions.clear(); + return this; + } + + public Builder setAdvancement(String namespace, String path, ConditionalAdvancement.Builder advancement) + { + return setAdvancement(new ResourceLocation(namespace, path), advancement); + } + + public Builder setAdvancement(ResourceLocation id, ConditionalAdvancement.Builder advancement) + { + if (this.advId != null) + throw new IllegalStateException("Invalid ConditionalRecipeBuilder, Advancement already set"); + this.advId = id; + this.adv = advancement; + return this; + } + + public void build(Consumer consumer, String namespace, String path) + { + build(consumer, new ResourceLocation(namespace, path)); + } + + public void build(Consumer consumer, ResourceLocation id) + { + if (!currentConditions.isEmpty()) + throw new IllegalStateException("Invalid ConditionalRecipe builder, Orphaned conditions"); + if (recipes.isEmpty()) + throw new IllegalStateException("Invalid ConditionalRecipe builder, No recipes"); + + consumer.accept(new Finished(id, conditions, recipes, advId, adv)); + } + } + + private static class Finished implements IFinishedRecipe + { + private final ResourceLocation id; + private final List conditions; + private final List recipes; + private final ResourceLocation advId; + private final ConditionalAdvancement.Builder adv; + + private Finished(ResourceLocation id, List conditions, List recipes, ResourceLocation advId, ConditionalAdvancement.Builder adv) + { + this.id = id; + this.conditions = conditions; + this.recipes = recipes; + this.advId = advId; + this.adv = adv; + } + + @Override + public void serialize(JsonObject json) { + JsonArray array = new JsonArray(); + json.add("recipes", array); + for (int x = 0; x < conditions.size(); x++) + { + JsonObject holder = new JsonObject(); + + JsonArray conds = new JsonArray(); + for (ICondition c : conditions.get(x)) + conds.add(CraftingHelper.serialize(c)); + holder.add("conditions", conds); + holder.add("recipe", recipes.get(x).getRecipeJson()); + + array.add(holder); + } + } + + @Override + public ResourceLocation getID() { + return id; + } + + @Override + public IRecipeSerializer getSerializer() + { + return SERIALZIER; + } + + @Override + public JsonObject getAdvancementJson() { + return adv == null ? null : adv.write(); + } + + @Override + public ResourceLocation getAdvancementID() { + return advId; + } + } +} diff --git a/src/main/java/net/minecraftforge/common/crafting/CraftingHelper.java b/src/main/java/net/minecraftforge/common/crafting/CraftingHelper.java index 3459e1ab7..03498614b 100644 --- a/src/main/java/net/minecraftforge/common/crafting/CraftingHelper.java +++ b/src/main/java/net/minecraftforge/common/crafting/CraftingHelper.java @@ -19,19 +19,12 @@ package net.minecraftforge.common.crafting; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.function.BooleanSupplier; -import java.util.stream.Stream; import javax.annotation.Nullable; -import net.minecraftforge.fml.ModList; - import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; import com.google.common.collect.Lists; @@ -40,24 +33,21 @@ import com.google.gson.GsonBuilder; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; -import com.google.gson.JsonParseException; import com.google.gson.JsonSyntaxException; import com.mojang.brigadier.exceptions.CommandSyntaxException; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.Ingredient; -import net.minecraft.item.crafting.Ingredient.IItemList; +import net.minecraftforge.common.crafting.conditions.ICondition; +import net.minecraftforge.common.crafting.conditions.IConditionSerializer; import net.minecraft.nbt.JsonToNBT; import net.minecraft.nbt.CompoundNBT; import net.minecraft.network.PacketBuffer; -import net.minecraft.resources.IResource; -import net.minecraft.resources.IResourceManager; import net.minecraft.util.JSONUtils; import net.minecraft.util.ResourceLocation; import net.minecraftforge.registries.ForgeRegistries; -import org.apache.commons.io.IOUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Marker; @@ -65,71 +55,17 @@ import org.apache.logging.log4j.MarkerManager; public class CraftingHelper { + @SuppressWarnings("unused") private static final Logger LOGGER = LogManager.getLogger(); + @SuppressWarnings("unused") private static final Marker CRAFTHELPER = MarkerManager.getMarker("CRAFTHELPER"); private static Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create(); - private static final Map conditions = new HashMap<>(); + private static final Map> conditions = new HashMap<>(); private static final BiMap> ingredients = HashBiMap.create(); - private static Map constants = new HashMap<>(); - public static final IConditionSerializer CONDITION_MOD_LOADED = condition("mod_loaded", json -> { - String modid = JSONUtils.getString(json, "modid"); - return () -> ModList.get().isLoaded(modid); - }); - public static final IConditionSerializer CONDITION_ITEM_EXISTS = condition("item_exists", json -> { - String itemName = JSONUtils.getString(json, "item"); - return () -> ForgeRegistries.ITEMS.containsKey(new ResourceLocation(itemName)); - }); - public static final IConditionSerializer CONDITION_NOT = condition("not", json -> { - BooleanSupplier child = CraftingHelper.getCondition(JSONUtils.getJsonObject(json, "value")); - return () -> !child.getAsBoolean(); - }); - public static final IConditionSerializer CONDITION_OR = condition("or", json -> { - JsonArray values = JSONUtils.getJsonArray(json, "values"); - List children = Lists.newArrayList(); - for (JsonElement j : values) - { - if (!j.isJsonObject()) - throw new JsonSyntaxException("Or condition values must be an array of JsonObjects"); - children.add(CraftingHelper.getCondition(j.getAsJsonObject())); - } - return () -> children.stream().anyMatch(BooleanSupplier::getAsBoolean); - }); - public static final IConditionSerializer CONDITION_AND = condition("and", json -> { - JsonArray values = JSONUtils.getJsonArray(json, "values"); - List children = Lists.newArrayList(); - for (JsonElement j : values) - { - if (!j.isJsonObject()) - throw new JsonSyntaxException("And condition values must be an array of JsonObjects"); - children.add(CraftingHelper.getCondition(j.getAsJsonObject())); - } - return () -> children.stream().allMatch(c -> c.getAsBoolean()); - }); - public static final IConditionSerializer CONDITION_FALSE = condition("false", json -> () -> false); - - public static final IIngredientSerializer INGREDIENT_NBT = register(new ResourceLocation("forge", "nbt"), new IngredientNBT.Serializer()); - public static final IIngredientSerializer INGREDIENT_COMPOUND = register(new ResourceLocation("forge", "compound"), new CompoundIngredient.Serializer()); - public static final IIngredientSerializer INGREDIENT_VANILLA = register(new ResourceLocation("minecraft", "item"), new IIngredientSerializer() { - public Ingredient parse(PacketBuffer buffer) { - return Ingredient.fromItemListStream(Stream.generate(() -> new Ingredient.SingleItemList(buffer.readItemStack())).limit(buffer.readVarInt())); - } - - public Ingredient parse(JsonObject json) { - return Ingredient.fromItemListStream(Stream.of(Ingredient.deserializeItemList(json))); - } - - public void write(PacketBuffer buffer, Ingredient ingredient) { - ItemStack[] items = ingredient.getMatchingStacks(); - buffer.writeVarInt(items.length); - - for (ItemStack stack : items) - buffer.writeItemStack(stack); - } - }); - - public static IConditionSerializer register(ResourceLocation key, IConditionSerializer serializer) + public static IConditionSerializer register(IConditionSerializer serializer) { + ResourceLocation key = serializer.getID(); if (conditions.containsKey(key)) throw new IllegalStateException("Duplicate recipe condition serializer: " + key); conditions.put(key, serializer); @@ -144,11 +80,11 @@ public class CraftingHelper ingredients.put(key, serializer); return serializer; } - - private static IConditionSerializer condition(String name, IConditionSerializer serializer) { - return register(new ResourceLocation("forge", name), serializer); + @Nullable + public static ResourceLocation getID(IIngredientSerializer serializer) + { + return ingredients.inverse().get(serializer); } - public static void write(PacketBuffer buffer, T ingredient) { @SuppressWarnings("unchecked") //I wonder if there is a better way generic wise... @@ -156,7 +92,7 @@ public class CraftingHelper ResourceLocation key = ingredients.inverse().get(serializer); if (key == null) throw new IllegalArgumentException("Tried to serialize unregistered Ingredient: " + ingredient + " " + serializer); - if (serializer != INGREDIENT_VANILLA) + if (serializer != VanillaIngredientSerializer.INSTANCE) { buffer.writeVarInt(-1); //Marker to know there is a custom ingredient buffer.writeResourceLocation(key); @@ -275,94 +211,27 @@ public class CraftingHelper throw new JsonSyntaxException("Conditions must be an array of JsonObjects"); JsonObject json = conditions.get(x).getAsJsonObject(); - BooleanSupplier cond = CraftingHelper.getCondition(json); - if (!cond.getAsBoolean()) + if (!CraftingHelper.getCondition(json).test()) return false; } return true; } - public static BooleanSupplier getCondition(JsonObject json) + public static ICondition getCondition(JsonObject json) { ResourceLocation type = new ResourceLocation(JSONUtils.getString(json, "type")); - IConditionSerializer serrializer = conditions.get(type); - if (serrializer == null) + IConditionSerializer serializer = conditions.get(type); + if (serializer == null) throw new JsonSyntaxException("Unknown condition type: " + type.toString()); - return serrializer.parse(json); + return serializer.read(json); } - @Nullable - public static IItemList getConstant(ResourceLocation key) { - return constants.get(key); - } - - public static void reloadConstants(IResourceManager manager) { - Map tmp = new HashMap<>(); - for(ResourceLocation key : manager.getAllResourceLocations("recipes", filename -> filename.equals("_constants.json"))) - { - String path = key.getPath(); - if (!path.equals("recipes/_constants.json")) //Top level only - continue; - - tmp.putAll(loadConstants(manager, key)); - } - constants = tmp; - } - - public static Map loadConstants(IResourceManager manager, ResourceLocation key) { - Map tmp = new HashMap<>(); - try (IResource iresource = manager.getResource(key)) - { - JsonObject[] elements = JSONUtils.fromJson(GSON, IOUtils.toString(iresource.getInputStream(), StandardCharsets.UTF_8), JsonObject[].class); - for (int x = 0; x < elements.length; x++) - { - JsonObject json = elements[x]; - //Force namespace to the directory that this constants file is in, to prevent modders from overriding other's sneakily - //TODO: Move back to a resource pack/mod specific constant list? - ResourceLocation name = json.has("name") ? new ResourceLocation(JSONUtils.getString(json, "name")) : null; - if (name != null) - name = new ResourceLocation(key.getNamespace(), name.getPath()); - - if (json == null || json.size() == 0) - LOGGER.error(CRAFTHELPER, "Couldn't load constant #{} from {} as it's null or empty", x, key); - else if (!processConditions(json, "conditions")) - LOGGER.info(CRAFTHELPER, "Skipping loading constant #{} from {} as it's conditions were not met", x, key); - else if (name == null) - LOGGER.error(CRAFTHELPER, "Couldn't load constant #{} from {} as it's missing `name`", x, key); - else if (json.has("items")) - { - List items = new ArrayList<>(); - for (JsonElement item : JSONUtils.getJsonArray(json, "items")) - { - if (item.isJsonObject()) - items.add(getItemStack(item.getAsJsonObject(), true)); - else - { - LOGGER.error(CRAFTHELPER, "Couldn't load constant #{} from {} as it's `items` entry is not a object", x, key); - items.clear(); - break; - } - } - if (!items.isEmpty()) - tmp.put(name, new StackList(items)); - } - else if (json.has("tag")) - tmp.put(name, Ingredient.deserializeItemList(json)); - else if (json.has("item")) - tmp.put(name, new StackList(Lists.newArrayList(getItemStack(JSONUtils.getJsonObject(json, "item"), true)))); - else - LOGGER.error(CRAFTHELPER, "Couldn't load constant #{} from {} as it's missing `item` or `items` element", x, key); - } - - } - catch (IllegalArgumentException | JsonParseException e) - { - LOGGER.error(CRAFTHELPER, "Parsing error loading constants {}", key, e); - } - catch (IOException e) - { - LOGGER.error(CRAFTHELPER, "Couldn't read constants from {}", key, e); - } - return tmp; + public static JsonObject serialize(T condition) + { + @SuppressWarnings("unchecked") + IConditionSerializer serializer = (IConditionSerializer)conditions.get(condition.getID()); + if (serializer == null) + throw new JsonSyntaxException("Unknown condition type: " + condition.getID().toString()); + return serializer.getJson(condition); } } diff --git a/src/main/java/net/minecraftforge/common/crafting/IngredientNBT.java b/src/main/java/net/minecraftforge/common/crafting/IngredientNBT.java index 2f7c36010..b5d8e7d96 100644 --- a/src/main/java/net/minecraftforge/common/crafting/IngredientNBT.java +++ b/src/main/java/net/minecraftforge/common/crafting/IngredientNBT.java @@ -23,12 +23,14 @@ import java.util.stream.Stream; import javax.annotation.Nullable; +import com.google.gson.JsonElement; import com.google.gson.JsonObject; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.Ingredient; import net.minecraft.network.PacketBuffer; +//TODO: 1.15 Rename to NBTIngredient to match naming. public class IngredientNBT extends Ingredient { private final ItemStack stack; @@ -56,11 +58,25 @@ public class IngredientNBT extends Ingredient @Override public IIngredientSerializer getSerializer() { - return CraftingHelper.INGREDIENT_NBT; + return Serializer.INSTANCE; + } + + @Override + public JsonElement serialize() + { + JsonObject json = new JsonObject(); + json.addProperty("type", CraftingHelper.getID(Serializer.INSTANCE).toString()); + json.addProperty("item", stack.getItem().getRegistryName().toString()); + json.addProperty("count", stack.getCount()); + if (stack.hasTag()) + json.addProperty("nbt", stack.getTag().toString()); + return json; } public static class Serializer implements IIngredientSerializer { + public static final Serializer INSTANCE = new Serializer(); + @Override public IngredientNBT parse(PacketBuffer buffer) { return new IngredientNBT(buffer.readItemStack()); diff --git a/src/main/java/net/minecraftforge/common/crafting/VanillaIngredientSerializer.java b/src/main/java/net/minecraftforge/common/crafting/VanillaIngredientSerializer.java new file mode 100644 index 000000000..af3f5471b --- /dev/null +++ b/src/main/java/net/minecraftforge/common/crafting/VanillaIngredientSerializer.java @@ -0,0 +1,52 @@ +/* + * Minecraft Forge + * Copyright (c) 2016-2019. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.common.crafting; + +import java.util.stream.Stream; + +import com.google.gson.JsonObject; + +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.Ingredient; +import net.minecraft.network.PacketBuffer; + +public class VanillaIngredientSerializer implements IIngredientSerializer +{ + public static final VanillaIngredientSerializer INSTANCE = new VanillaIngredientSerializer(); + + public Ingredient parse(PacketBuffer buffer) + { + return Ingredient.fromItemListStream(Stream.generate(() -> new Ingredient.SingleItemList(buffer.readItemStack())).limit(buffer.readVarInt())); + } + + public Ingredient parse(JsonObject json) + { + return Ingredient.fromItemListStream(Stream.of(Ingredient.deserializeItemList(json))); + } + + public void write(PacketBuffer buffer, Ingredient ingredient) + { + ItemStack[] items = ingredient.getMatchingStacks(); + buffer.writeVarInt(items.length); + + for (ItemStack stack : items) + buffer.writeItemStack(stack); + } +} diff --git a/src/main/java/net/minecraftforge/common/crafting/conditions/AndCondition.java b/src/main/java/net/minecraftforge/common/crafting/conditions/AndCondition.java new file mode 100644 index 000000000..3d942c310 --- /dev/null +++ b/src/main/java/net/minecraftforge/common/crafting/conditions/AndCondition.java @@ -0,0 +1,109 @@ +/* + * Minecraft Forge + * Copyright (c) 2016-2019. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.common.crafting.conditions; + +import java.util.ArrayList; +import java.util.List; + +import com.google.common.base.Joiner; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonSyntaxException; + +import net.minecraft.util.JSONUtils; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.common.crafting.CraftingHelper; + +public class AndCondition implements ICondition +{ + private static final ResourceLocation NAME = new ResourceLocation("forge", "and"); + private final ICondition[] children; + + public AndCondition(ICondition... values) + { + if (values == null || values.length == 0) + throw new IllegalArgumentException("Values must not be empty"); + + for (ICondition child : values) + { + if (child == null) + throw new IllegalArgumentException("Value must not be null"); + } + + this.children = values; + } + + @Override + public ResourceLocation getID() + { + return NAME; + } + + @Override + public boolean test() + { + for (ICondition child : children) + { + if (!child.test()) + return false; + } + return true; + } + + @Override + public String toString() + { + return Joiner.on(" && ").join(children); + } + + public static class Serializer implements IConditionSerializer + { + public static final Serializer INSTANCE = new Serializer(); + + @Override + public void write(JsonObject json, AndCondition value) + { + JsonArray values = new JsonArray(); + for (ICondition child : value.children) + values.add(CraftingHelper.serialize(child)); + json.add("values", values); + } + + @Override + public AndCondition read(JsonObject json) + { + List children = new ArrayList<>(); + for (JsonElement j : JSONUtils.getJsonArray(json, "values")) + { + if (!j.isJsonObject()) + throw new JsonSyntaxException("And condition values must be an array of JsonObjects"); + children.add(CraftingHelper.getCondition(j.getAsJsonObject())); + } + return new AndCondition(children.toArray(new ICondition[children.size()])); + } + + @Override + public ResourceLocation getID() + { + return AndCondition.NAME; + } + } +} diff --git a/src/main/java/net/minecraftforge/common/crafting/conditions/FalseCondition.java b/src/main/java/net/minecraftforge/common/crafting/conditions/FalseCondition.java new file mode 100644 index 000000000..fbf05e0ad --- /dev/null +++ b/src/main/java/net/minecraftforge/common/crafting/conditions/FalseCondition.java @@ -0,0 +1,69 @@ +/* + * Minecraft Forge + * Copyright (c) 2016-2019. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.common.crafting.conditions; + +import com.google.gson.JsonObject; +import net.minecraft.util.ResourceLocation; + +public final class FalseCondition implements ICondition +{ + public static final FalseCondition INSTANCE = new FalseCondition(); + private static final ResourceLocation NAME = new ResourceLocation("forge", "false"); + + private FalseCondition() {} + + @Override + public ResourceLocation getID() + { + return NAME; + } + + @Override + public boolean test() + { + return false; + } + + @Override + public String toString() + { + return "false"; + } + + public static class Serializer implements IConditionSerializer + { + public static final Serializer INSTANCE = new Serializer(); + + @Override + public void write(JsonObject json, FalseCondition value) { } + + @Override + public FalseCondition read(JsonObject json) + { + return FalseCondition.INSTANCE; + } + + @Override + public ResourceLocation getID() + { + return FalseCondition.NAME; + } + } +} diff --git a/src/main/java/net/minecraftforge/common/crafting/IConditionSerializer.java b/src/main/java/net/minecraftforge/common/crafting/conditions/ICondition.java similarity index 77% rename from src/main/java/net/minecraftforge/common/crafting/IConditionSerializer.java rename to src/main/java/net/minecraftforge/common/crafting/conditions/ICondition.java index 37d524fc7..67981d8b4 100644 --- a/src/main/java/net/minecraftforge/common/crafting/IConditionSerializer.java +++ b/src/main/java/net/minecraftforge/common/crafting/conditions/ICondition.java @@ -17,14 +17,13 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -package net.minecraftforge.common.crafting; +package net.minecraftforge.common.crafting.conditions; -import java.util.function.BooleanSupplier; +import net.minecraft.util.ResourceLocation; -import com.google.gson.JsonObject; - -@FunctionalInterface -public interface IConditionSerializer +public interface ICondition { - BooleanSupplier parse(JsonObject json); + ResourceLocation getID(); + + boolean test(); } diff --git a/src/main/java/net/minecraftforge/common/crafting/conditions/IConditionBuilder.java b/src/main/java/net/minecraftforge/common/crafting/conditions/IConditionBuilder.java new file mode 100644 index 000000000..c0d07f7c5 --- /dev/null +++ b/src/main/java/net/minecraftforge/common/crafting/conditions/IConditionBuilder.java @@ -0,0 +1,58 @@ +/* + * Minecraft Forge + * Copyright (c) 2016-2019. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.common.crafting.conditions; + +public interface IConditionBuilder +{ + default ICondition and(ICondition... values) + { + return new AndCondition(values); + } + + default ICondition FALSE() + { + return FalseCondition.INSTANCE; + } + + default ICondition TRUE() + { + return TrueCondition.INSTANCE; + } + + default ICondition not(ICondition value) + { + return new NotCondition(value); + } + + default ICondition or(ICondition... values) + { + return new OrCondition(values); + } + + default ICondition itemExists(String namespace, String path) + { + return new ItemExistsCondition(namespace, path); + } + + default ICondition modLoaded(String modid) + { + return new ModLoadedCondition(modid); + } +} diff --git a/src/main/java/net/minecraftforge/common/crafting/conditions/IConditionSerializer.java b/src/main/java/net/minecraftforge/common/crafting/conditions/IConditionSerializer.java new file mode 100644 index 000000000..a12de6b3a --- /dev/null +++ b/src/main/java/net/minecraftforge/common/crafting/conditions/IConditionSerializer.java @@ -0,0 +1,41 @@ +/* + * Minecraft Forge + * Copyright (c) 2016-2019. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.common.crafting.conditions; + +import com.google.gson.JsonObject; + +import net.minecraft.util.ResourceLocation; + +public interface IConditionSerializer +{ + void write(JsonObject json, T value); + + T read(JsonObject json); + + ResourceLocation getID(); + + default JsonObject getJson(T value) + { + JsonObject json = new JsonObject(); + this.write(json, value); + json.addProperty("type", value.getID().toString()); + return json; + } +} diff --git a/src/main/java/net/minecraftforge/common/crafting/conditions/ItemExistsCondition.java b/src/main/java/net/minecraftforge/common/crafting/conditions/ItemExistsCondition.java new file mode 100644 index 000000000..07c9ed2b6 --- /dev/null +++ b/src/main/java/net/minecraftforge/common/crafting/conditions/ItemExistsCondition.java @@ -0,0 +1,88 @@ +/* + * Minecraft Forge + * Copyright (c) 2016-2019. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.common.crafting.conditions; + +import com.google.gson.JsonObject; + +import net.minecraft.util.JSONUtils; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.registries.ForgeRegistries; + +public class ItemExistsCondition implements ICondition +{ + private static final ResourceLocation NAME = new ResourceLocation("forge", "item_exists"); + private final ResourceLocation item; + + public ItemExistsCondition(String location) + { + this(new ResourceLocation(location)); + } + + public ItemExistsCondition(String namespace, String path) + { + this(new ResourceLocation(namespace, path)); + } + + public ItemExistsCondition(ResourceLocation item) + { + this.item = item; + } + + @Override + public ResourceLocation getID() + { + return NAME; + } + + @Override + public boolean test() + { + return ForgeRegistries.ITEMS.containsKey(item); + } + + @Override + public String toString() + { + return "item_exists(\"" + item + "\")"; + } + + public static class Serializer implements IConditionSerializer + { + public static final Serializer INSTANCE = new Serializer(); + + @Override + public void write(JsonObject json, ItemExistsCondition value) + { + json.addProperty("item", value.item.toString()); + } + + @Override + public ItemExistsCondition read(JsonObject json) + { + return new ItemExistsCondition(new ResourceLocation(JSONUtils.getString(json, "item"))); + } + + @Override + public ResourceLocation getID() + { + return ItemExistsCondition.NAME; + } + } +} diff --git a/src/main/java/net/minecraftforge/common/crafting/conditions/ModLoadedCondition.java b/src/main/java/net/minecraftforge/common/crafting/conditions/ModLoadedCondition.java new file mode 100644 index 000000000..dcdeac288 --- /dev/null +++ b/src/main/java/net/minecraftforge/common/crafting/conditions/ModLoadedCondition.java @@ -0,0 +1,78 @@ +/* + * Minecraft Forge + * Copyright (c) 2016-2019. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.common.crafting.conditions; + +import com.google.gson.JsonObject; + +import net.minecraft.util.JSONUtils; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.ModList; + +public class ModLoadedCondition implements ICondition +{ + private static final ResourceLocation NAME = new ResourceLocation("forge", "mod_loaded"); + private final String modid; + + public ModLoadedCondition(String modid) + { + this.modid = modid; + } + + @Override + public ResourceLocation getID() + { + return NAME; + } + + @Override + public boolean test() + { + return ModList.get().isLoaded(modid); + } + + @Override + public String toString() + { + return "mod_loaded(\"" + modid + "\")"; + } + + public static class Serializer implements IConditionSerializer + { + public static final Serializer INSTANCE = new Serializer(); + + @Override + public void write(JsonObject json, ModLoadedCondition value) + { + json.addProperty("modid", value.modid); + } + + @Override + public ModLoadedCondition read(JsonObject json) + { + return new ModLoadedCondition(JSONUtils.getString(json, "modid")); + } + + @Override + public ResourceLocation getID() + { + return ModLoadedCondition.NAME; + } + } +} diff --git a/src/main/java/net/minecraftforge/common/crafting/conditions/NotCondition.java b/src/main/java/net/minecraftforge/common/crafting/conditions/NotCondition.java new file mode 100644 index 000000000..f69c1d195 --- /dev/null +++ b/src/main/java/net/minecraftforge/common/crafting/conditions/NotCondition.java @@ -0,0 +1,77 @@ +/* + * Minecraft Forge + * Copyright (c) 2016-2019. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.common.crafting.conditions; + +import com.google.gson.JsonObject; +import net.minecraft.util.JSONUtils; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.common.crafting.CraftingHelper; + +public class NotCondition implements ICondition +{ + private static final ResourceLocation NAME = new ResourceLocation("forge", "not"); + private final ICondition child; + + public NotCondition(ICondition child) + { + this.child = child; + } + + @Override + public ResourceLocation getID() + { + return NAME; + } + + @Override + public boolean test() + { + return !child.test(); + } + + @Override + public String toString() + { + return "!" + child; + } + + public static class Serializer implements IConditionSerializer + { + public static final Serializer INSTANCE = new Serializer(); + + @Override + public void write(JsonObject json, NotCondition value) + { + json.add("value", CraftingHelper.serialize(value.child)); + } + + @Override + public NotCondition read(JsonObject json) + { + return new NotCondition(CraftingHelper.getCondition(JSONUtils.getJsonObject(json, "value"))); + } + + @Override + public ResourceLocation getID() + { + return NotCondition.NAME; + } + } +} diff --git a/src/main/java/net/minecraftforge/common/crafting/conditions/OrCondition.java b/src/main/java/net/minecraftforge/common/crafting/conditions/OrCondition.java new file mode 100644 index 000000000..89f58f361 --- /dev/null +++ b/src/main/java/net/minecraftforge/common/crafting/conditions/OrCondition.java @@ -0,0 +1,110 @@ +/* + * Minecraft Forge + * Copyright (c) 2016-2019. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.common.crafting.conditions; + +import java.util.ArrayList; +import java.util.List; + +import com.google.common.base.Joiner; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonSyntaxException; + +import net.minecraft.util.JSONUtils; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.common.crafting.CraftingHelper; + +public class OrCondition implements ICondition +{ + private static final ResourceLocation NAME = new ResourceLocation("forge", "or"); + private final ICondition[] children; + + public OrCondition(ICondition... values) + { + if (values == null || values.length == 0) + throw new IllegalArgumentException("Values must not be empty"); + + for (ICondition child : values) + { + if (child == null) + throw new IllegalArgumentException("Value must not be null"); + } + + this.children = values; + } + + @Override + public ResourceLocation getID() + { + return NAME; + } + + @Override + public boolean test() + { + for (ICondition child : children) + { + if (child.test()) + return true; + } + + return false; + } + + @Override + public String toString() + { + return Joiner.on(" || ").join(children); + } + + public static class Serializer implements IConditionSerializer + { + public static final Serializer INSTANCE = new Serializer(); + + @Override + public void write(JsonObject json, OrCondition value) + { + JsonArray values = new JsonArray(); + for (ICondition child : value.children) + values.add(CraftingHelper.serialize(child)); + json.add("values", values); + } + + @Override + public OrCondition read(JsonObject json) + { + List children = new ArrayList<>(); + for (JsonElement j : JSONUtils.getJsonArray(json, "values")) + { + if (!j.isJsonObject()) + throw new JsonSyntaxException("Or condition values must be an array of JsonObjects"); + children.add(CraftingHelper.getCondition(j.getAsJsonObject())); + } + return new OrCondition(children.toArray(new ICondition[children.size()])); + } + + @Override + public ResourceLocation getID() + { + return OrCondition.NAME; + } + } +} diff --git a/src/main/java/net/minecraftforge/common/crafting/conditions/TagEmptyCondition.java b/src/main/java/net/minecraftforge/common/crafting/conditions/TagEmptyCondition.java new file mode 100644 index 000000000..65e670c95 --- /dev/null +++ b/src/main/java/net/minecraftforge/common/crafting/conditions/TagEmptyCondition.java @@ -0,0 +1,91 @@ +/* + * Minecraft Forge + * Copyright (c) 2016-2019. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.common.crafting.conditions; + +import com.google.gson.JsonObject; + +import net.minecraft.item.Item; +import net.minecraft.tags.ItemTags; +import net.minecraft.tags.Tag; +import net.minecraft.util.JSONUtils; +import net.minecraft.util.ResourceLocation; + +public class TagEmptyCondition implements ICondition +{ + private static final ResourceLocation NAME = new ResourceLocation("forge", "tag_empty"); + private final ResourceLocation tag_name; + + public TagEmptyCondition(String location) + { + this(new ResourceLocation(location)); + } + + public TagEmptyCondition(String namespace, String path) + { + this(new ResourceLocation(namespace, path)); + } + + public TagEmptyCondition(ResourceLocation tag) + { + this.tag_name = tag; + } + + @Override + public ResourceLocation getID() + { + return NAME; + } + + @Override + public boolean test() + { + Tag tag = ItemTags.getCollection().get(tag_name); + return tag == null || tag.getAllElements().isEmpty(); + } + + @Override + public String toString() + { + return "tag_empty(\"" + tag_name + "\")"; + } + + public static class Serializer implements IConditionSerializer + { + public static final Serializer INSTANCE = new Serializer(); + + @Override + public void write(JsonObject json, TagEmptyCondition value) + { + json.addProperty("tag", value.tag_name.toString()); + } + + @Override + public TagEmptyCondition read(JsonObject json) + { + return new TagEmptyCondition(new ResourceLocation(JSONUtils.getString(json, "tag"))); + } + + @Override + public ResourceLocation getID() + { + return TagEmptyCondition.NAME; + } + } +} diff --git a/src/main/java/net/minecraftforge/common/crafting/conditions/TrueCondition.java b/src/main/java/net/minecraftforge/common/crafting/conditions/TrueCondition.java new file mode 100644 index 000000000..ce25b7a34 --- /dev/null +++ b/src/main/java/net/minecraftforge/common/crafting/conditions/TrueCondition.java @@ -0,0 +1,70 @@ +/* + * Minecraft Forge + * Copyright (c) 2016-2019. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.common.crafting.conditions; + +import com.google.gson.JsonObject; + +import net.minecraft.util.ResourceLocation; + +public final class TrueCondition implements ICondition +{ + public static final TrueCondition INSTANCE = new TrueCondition(); + private static final ResourceLocation NAME = new ResourceLocation("forge", "true"); + + private TrueCondition() {} + + @Override + public ResourceLocation getID() + { + return NAME; + } + + @Override + public boolean test() + { + return true; + } + + @Override + public String toString() + { + return "true"; + } + + public static class Serializer implements IConditionSerializer + { + public static final Serializer INSTANCE = new Serializer(); + + @Override + public void write(JsonObject json, TrueCondition value) { } + + @Override + public TrueCondition read(JsonObject json) + { + return TrueCondition.INSTANCE; + } + + @Override + public ResourceLocation getID() + { + return TrueCondition.NAME; + } + } +} diff --git a/src/main/java/net/minecraftforge/common/data/ForgeRecipeProvider.java b/src/main/java/net/minecraftforge/common/data/ForgeRecipeProvider.java index d83c3528d..725393660 100644 --- a/src/main/java/net/minecraftforge/common/data/ForgeRecipeProvider.java +++ b/src/main/java/net/minecraftforge/common/data/ForgeRecipeProvider.java @@ -52,16 +52,12 @@ import net.minecraftforge.common.Tags; public class ForgeRecipeProvider extends RecipeProvider { - private final DataGenerator generator; - private final Path ADV_ROOT; private Map> replacements = new HashMap<>(); private Set excludes = new HashSet<>(); public ForgeRecipeProvider(DataGenerator generatorIn) { super(generatorIn); - this.generator = generatorIn; - ADV_ROOT = this.generator.getOutputFolder().resolve("data/minecraft/advancements/recipes/root.json"); } private void exclude(IItemProvider item) @@ -101,7 +97,6 @@ public class ForgeRecipeProvider extends RecipeProvider @Override protected void saveRecipeAdvancement(DirectoryCache cache, JsonObject advancementJson, Path pathIn) { - if (pathIn.equals(ADV_ROOT)) return; //We NEVER care about this. //NOOP - We dont replace any of the advancement things yet... } diff --git a/src/main/java/net/minecraftforge/fml/ModLoader.java b/src/main/java/net/minecraftforge/fml/ModLoader.java index 2c831fb5a..0e1de13aa 100644 --- a/src/main/java/net/minecraftforge/fml/ModLoader.java +++ b/src/main/java/net/minecraftforge/fml/ModLoader.java @@ -208,7 +208,9 @@ public class ModLoader LOGGER.debug(LOADING, "ModContainer is {}", ModContainer.class.getClassLoader()); final List containers = modFile.getScanResult().getTargets().entrySet().stream(). - map(e -> buildModContainerFromTOML(modFile, modClassLoader, modInfoMap, e)).collect(Collectors.toList()); + map(e -> buildModContainerFromTOML(modFile, modClassLoader, modInfoMap, e)) + .filter(e -> e != null) + .collect(Collectors.toList()); if (containers.size() != modInfoMap.size()) { LOGGER.fatal(LOADING,"File {} constructed {} mods: {}, but had {} mods specified: {}", modFile.getFilePath(), diff --git a/src/main/java/net/minecraftforge/server/command/ConfigCommand.java b/src/main/java/net/minecraftforge/server/command/ConfigCommand.java index 8706935c5..ccea6c2b5 100644 --- a/src/main/java/net/minecraftforge/server/command/ConfigCommand.java +++ b/src/main/java/net/minecraftforge/server/command/ConfigCommand.java @@ -1,3 +1,22 @@ +/* + * Minecraft Forge + * Copyright (c) 2016-2019. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + package net.minecraftforge.server.command; import com.mojang.brigadier.CommandDispatcher; diff --git a/src/main/java/net/minecraftforge/server/command/EnumArgument.java b/src/main/java/net/minecraftforge/server/command/EnumArgument.java index 837fbc05d..4463bfef0 100644 --- a/src/main/java/net/minecraftforge/server/command/EnumArgument.java +++ b/src/main/java/net/minecraftforge/server/command/EnumArgument.java @@ -1,3 +1,22 @@ +/* + * Minecraft Forge + * Copyright (c) 2016-2019. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + package net.minecraftforge.server.command; import com.mojang.brigadier.StringReader; diff --git a/src/main/java/net/minecraftforge/server/command/ModIdArgument.java b/src/main/java/net/minecraftforge/server/command/ModIdArgument.java index 844996717..2a69835cf 100644 --- a/src/main/java/net/minecraftforge/server/command/ModIdArgument.java +++ b/src/main/java/net/minecraftforge/server/command/ModIdArgument.java @@ -1,3 +1,22 @@ +/* + * Minecraft Forge + * Copyright (c) 2016-2019. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + package net.minecraftforge.server.command; import com.google.gson.JsonObject; diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg index 6a9653d57..784a1de08 100644 --- a/src/main/resources/META-INF/accesstransformer.cfg +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -50,7 +50,13 @@ public net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher fie public net.minecraft.command.arguments.EntityOptions func_202024_a(Ljava/lang/String;Lnet/minecraft/command/arguments/EntityOptions$IFilter;Ljava/util/function/Predicate;Lnet/minecraft/util/text/ITextComponent;)V # register public net.minecraft.command.arguments.EntitySelectorParser func_197396_n()V # updateFilter public net.minecraft.command.arguments.EntitySelectorParser func_197404_d()V # parseArguments +protected net.minecraft.data.RecipeProvider field_200413_c # generator +protected net.minecraft.data.RecipeProvider func_200403_a(Lnet/minecraft/util/IItemProvider;)Lnet/minecraft/advancements/criterion/InventoryChangeTrigger$Instance; # hasItem protected net.minecraft.data.RecipeProvider func_200404_a(Ljava/util/function/Consumer;)V # registerRecipes +protected net.minecraft.data.RecipeProvider func_200405_a([Lnet/minecraft/advancements/criterion/ItemPredicate;)Lnet/minecraft/advancements/criterion/InventoryChangeTrigger$Instance; # hasItem +protected net.minecraft.data.RecipeProvider func_200407_a(Lnet/minecraft/block/Block;)Lnet/minecraft/advancements/criterion/EnterBlockTrigger$Instance; # enteredBlock +protected net.minecraft.data.RecipeProvider func_200408_a(Lnet/minecraft/advancements/criterion/MinMaxBounds$IntBound;Lnet/minecraft/util/IItemProvider;)Lnet/minecraft/advancements/criterion/InventoryChangeTrigger$Instance; # hasItem +protected net.minecraft.data.RecipeProvider func_200409_a(Lnet/minecraft/tags/Tag;)Lnet/minecraft/advancements/criterion/InventoryChangeTrigger$Instance; # hasItem protected net.minecraft.data.RecipeProvider func_208310_b(Lnet/minecraft/data/DirectoryCache;Lcom/google/gson/JsonObject;Ljava/nio/file/Path;)V # saveRecipeAdvancement public net.minecraft.data.ShapedRecipeBuilder$Result public net.minecraft.entity.Entity func_70022_Q()Ljava/lang/String; # getEntityString @@ -130,4 +136,4 @@ private-f net.minecraft.world.server.ChunkHolder field_219320_o # block update l public net.minecraft.world.server.ServerChunkProvider field_186029_c # chunkGenerator public net.minecraft.world.server.ServerChunkProvider field_73251_h # worldObj private-f net.minecraft.world.storage.loot.LootPool field_186455_c # rolls -private-f net.minecraft.world.storage.loot.LootPool field_186456_d # bonusRolls +private-f net.minecraft.world.storage.loot.LootPool field_186456_d # bonusRolls \ No newline at end of file diff --git a/src/main/resources/assets/forge/lang/en_us.json b/src/main/resources/assets/forge/lang/en_us.json index 0629ce188..c8bab64f7 100644 --- a/src/main/resources/assets/forge/lang/en_us.json +++ b/src/main/resources/assets/forge/lang/en_us.json @@ -137,6 +137,8 @@ "forge.configgui.forgeLightPipelineEnabled": "Forge Light Pipeline Enabled", "forge.configgui.selectiveResourceReloadEnabled.tooltip": "When enabled, makes specific reload tasks such as language changing quicker to run.", "forge.configgui.selectiveResourceReloadEnabled": "Enable Selective Resource Loading", + "forge.configgui.treatEmptyTagsAsAir.tooltip": "Vanilla will treat crafting recipess using empty tags as air, and allow you to craft with nothing in that slot. If false, this changes empty tags to use BARRIER as the item. To prevent crafting with air.", + "forge.configgui.treatEmptyTagsAsAir": "Treat empty tags as air", "forge.controlsgui.shift": "SHIFT + %s", "forge.controlsgui.control": "CTRL + %s", diff --git a/src/test/java/net/minecraftforge/debug/DataGeneratorTest.java b/src/test/java/net/minecraftforge/debug/DataGeneratorTest.java new file mode 100644 index 000000000..96c796ad5 --- /dev/null +++ b/src/test/java/net/minecraftforge/debug/DataGeneratorTest.java @@ -0,0 +1,110 @@ +/* + * Minecraft Forge + * Copyright (c) 2016-2019. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.debug; + +import java.util.function.Consumer; + +import net.minecraft.advancements.Advancement; +import net.minecraft.advancements.AdvancementRewards; +import net.minecraft.advancements.FrameType; +import net.minecraft.block.Blocks; +import net.minecraft.data.DataGenerator; +import net.minecraft.data.IFinishedRecipe; +import net.minecraft.data.RecipeProvider; +import net.minecraft.data.ShapedRecipeBuilder; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.text.StringTextComponent; +import net.minecraftforge.common.crafting.ConditionalAdvancement; +import net.minecraftforge.common.crafting.ConditionalRecipe; +import net.minecraftforge.common.crafting.conditions.IConditionBuilder; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus; +import net.minecraftforge.fml.event.lifecycle.GatherDataEvent; + +@Mod("data_gen_test") +@Mod.EventBusSubscriber(bus = Bus.MOD) +public class DataGeneratorTest +{ + @SubscribeEvent + public static void gatherData(GatherDataEvent event) + { + DataGenerator gen = event.getGenerator(); + + if (event.includeServer()) + { + gen.addProvider(new Recipes(gen)); + } + } + + public static class Recipes extends RecipeProvider implements IConditionBuilder + { + public Recipes(DataGenerator gen) + { + super(gen); + } + + protected void registerRecipes(Consumer consumer) + { + ResourceLocation ID = new ResourceLocation("data_gen_test", "conditional"); + + ConditionalRecipe.builder() + .addCondition( + and( + not(modLoaded("minecraft")), + itemExists("minecraft", "dirt"), + FALSE() + ) + ) + .addRecipe( + ShapedRecipeBuilder.shapedRecipe(Blocks.DIAMOND_BLOCK, 64) + .patternLine("XXX") + .patternLine("XXX") + .patternLine("XXX") + .key('X', Blocks.DIRT) + .setGroup("") + .addCriterion("has_dirt", hasItem(Blocks.DIRT)) //Doesn't actually print... TODO: nested/conditional advancements? + ::build + ) + .setAdvancement(ID, + ConditionalAdvancement.builder() + .addCondition( + and( + not(modLoaded("minecraft")), + itemExists("minecraft", "dirt"), + FALSE() + ) + ) + .addAdvancement( + Advancement.Builder.builder() + .withParentId(new ResourceLocation("minecraft", "root")) + .withDisplay(Blocks.DIAMOND_BLOCK, + new StringTextComponent("Dirt2Diamonds"), + new StringTextComponent("The BEST crafting recipe in the game!"), + null, FrameType.TASK, false, false, false + ) + .withRewards(AdvancementRewards.Builder.recipe(ID)) + .withCriterion("has_dirt", hasItem(Blocks.DIRT)) + ) + ) + .build(consumer, ID); + } + } +} diff --git a/src/test/java/net/minecraftforge/debug/block/PistonEventTest.java b/src/test/java/net/minecraftforge/debug/block/PistonEventTest.java index 47ae25e82..e3024501d 100644 --- a/src/test/java/net/minecraftforge/debug/block/PistonEventTest.java +++ b/src/test/java/net/minecraftforge/debug/block/PistonEventTest.java @@ -54,7 +54,7 @@ import net.minecraftforge.fml.common.Mod; public class PistonEventTest { - public static final String MODID = "pistoneventtest"; + public static final String MODID = "piston_event_test"; private static Block shiftOnMove = new BlockShiftOnMove(); @@ -151,4 +151,4 @@ public class PistonEventTest } -} \ No newline at end of file +} diff --git a/src/test/resources/META-INF/mods.toml b/src/test/resources/META-INF/mods.toml index a7309080b..0555ce5dd 100644 --- a/src/test/resources/META-INF/mods.toml +++ b/src/test/resources/META-INF/mods.toml @@ -42,4 +42,8 @@ loaderVersion="[28,)" [[mods]] modId="command_event_test" [[mods]] - modId="entity_selector_test" \ No newline at end of file + modId="entity_selector_test" +[[mods]] + modId="data_gen_test" +[[mods]] + modId="piston_event_test" \ No newline at end of file