Recipe system cleanup. (#6014)

This commit is contained in:
LexManos 2019-08-03 19:25:41 +02:00 committed by David Quintana
parent 3e9bc3c434
commit e784a7f606
38 changed files with 1675 additions and 194 deletions

View file

@ -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/')
}
}
}

View file

@ -0,0 +1,15 @@
--- a/net/minecraft/advancements/AdvancementManager.java
+++ b/net/minecraft/advancements/AdvancementManager.java
@@ -36,7 +36,11 @@
Map<ResourceLocation, Advancement.Builder> 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());

View file

@ -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"));
}

View file

@ -9,3 +9,11 @@
IRecipeSerializer<ShapedRecipe> field_222157_a = func_222156_a("crafting_shaped", new ShapedRecipe.Serializer());
IRecipeSerializer<ShapelessRecipe> field_222158_b = func_222156_a("crafting_shapeless", new ShapelessRecipe.Serializer());
SpecialRecipeSerializer<ArmorDyeRecipe> 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_);

View file

@ -59,7 +59,7 @@
+
+ public net.minecraftforge.common.crafting.IIngredientSerializer<? extends Ingredient> 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<? extends Ingredient.IItemList> 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<ItemStack> 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;
}

View file

@ -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<ResourceLocation, JsonObject> 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);

View file

@ -0,0 +1,2 @@
4fbaf6f4a3ea05cc071076e27f44ac81f9cc50e3 data\data_gen_test\advancements\conditional.json
ed4cbf1a3a2f5d8969f6346fdc9acdbe81d0c919 data\data_gen_test\recipes\conditional.json

View file

@ -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"
]
]
}
}
]
}

View file

@ -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
}
}
}
]
}

View file

@ -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();
}
}

View file

@ -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<IRecipeSerializer<?>> 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<IRecipe<?>>().setRegistryName(new ResourceLocation("forge", "conditional")));
}
}

View file

@ -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<Ingredient> children;
private List<Ingredient> children;
private ItemStack[] stacks;
private IntList itemIds;
private final boolean isSimple;
protected CompoundIngredient(Collection<Ingredient> children)
protected CompoundIngredient(List<Ingredient> 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<? extends Ingredient> getSerializer()
{
return CraftingHelper.INGREDIENT_COMPOUND;
return Serializer.INSTANCE;
}
@Nonnull
public Collection<Ingredient> 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<CompoundIngredient>
{
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

View file

@ -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<ICondition[]> conditions = new ArrayList<>();
private List<Advancement.Builder> advancements = new ArrayList<>();
private List<ICondition> 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<Consumer<Advancement.Builder>> 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;
}
}
}

View file

@ -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<IRecipe<?>> SERIALZIER = null;
public static Builder builder()
{
return new Builder();
}
public static class Serializer<T extends IRecipe<?>> implements IRecipeSerializer<T>
{
private ResourceLocation name;
@Override
public IRecipeSerializer<?> setRegistryName(ResourceLocation name)
{
this.name = name;
return this;
}
@Override
public ResourceLocation getRegistryName()
{
return name;
}
@Override
public Class<IRecipeSerializer<?>> getRegistryType()
{
return Serializer.<IRecipeSerializer<?>>castClass(IRecipeSerializer.class);
}
@SuppressWarnings("unchecked") // Need this wrapper, because generics
private static <G> Class<G> castClass(Class<?> cls)
{
return (Class<G>)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<ICondition[]> conditions = new ArrayList<>();
private List<IFinishedRecipe> recipes = new ArrayList<>();
private ResourceLocation advId;
private ConditionalAdvancement.Builder adv;
private List<ICondition> currentConditions = new ArrayList<>();
public Builder addCondition(ICondition condition)
{
currentConditions.add(condition);
return this;
}
public Builder addRecipe(Consumer<Consumer<IFinishedRecipe>> 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<IFinishedRecipe> consumer, String namespace, String path)
{
build(consumer, new ResourceLocation(namespace, path));
}
public void build(Consumer<IFinishedRecipe> 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<ICondition[]> conditions;
private final List<IFinishedRecipe> recipes;
private final ResourceLocation advId;
private final ConditionalAdvancement.Builder adv;
private Finished(ResourceLocation id, List<ICondition[]> conditions, List<IFinishedRecipe> 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;
}
}
}

View file

@ -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<ResourceLocation, IConditionSerializer> conditions = new HashMap<>();
private static final Map<ResourceLocation, IConditionSerializer<?>> conditions = new HashMap<>();
private static final BiMap<ResourceLocation, IIngredientSerializer<?>> ingredients = HashBiMap.create();
private static Map<ResourceLocation, IItemList> 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<BooleanSupplier> 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<BooleanSupplier> 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<IngredientNBT> INGREDIENT_NBT = register(new ResourceLocation("forge", "nbt"), new IngredientNBT.Serializer());
public static final IIngredientSerializer<CompoundIngredient> INGREDIENT_COMPOUND = register(new ResourceLocation("forge", "compound"), new CompoundIngredient.Serializer());
public static final IIngredientSerializer<Ingredient> INGREDIENT_VANILLA = register(new ResourceLocation("minecraft", "item"), new IIngredientSerializer<Ingredient>() {
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 <T extends Ingredient> 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<ResourceLocation, IItemList> 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<ResourceLocation, IItemList> loadConstants(IResourceManager manager, ResourceLocation key) {
Map<ResourceLocation, IItemList> 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<ItemStack> 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 <T extends ICondition> JsonObject serialize(T condition)
{
@SuppressWarnings("unchecked")
IConditionSerializer<T> serializer = (IConditionSerializer<T>)conditions.get(condition.getID());
if (serializer == null)
throw new JsonSyntaxException("Unknown condition type: " + condition.getID().toString());
return serializer.getJson(condition);
}
}

View file

@ -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<? extends Ingredient> 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<IngredientNBT>
{
public static final Serializer INSTANCE = new Serializer();
@Override
public IngredientNBT parse(PacketBuffer buffer) {
return new IngredientNBT(buffer.readItemStack());

View file

@ -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<Ingredient>
{
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);
}
}

View file

@ -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<AndCondition>
{
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<ICondition> 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;
}
}
}

View file

@ -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<FalseCondition>
{
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;
}
}
}

View file

@ -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();
}

View file

@ -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);
}
}

View file

@ -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<T extends ICondition>
{
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;
}
}

View file

@ -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<ItemExistsCondition>
{
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;
}
}
}

View file

@ -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<ModLoadedCondition>
{
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;
}
}
}

View file

@ -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<NotCondition>
{
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;
}
}
}

View file

@ -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<OrCondition>
{
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<ICondition> 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;
}
}
}

View file

@ -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<Item> 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<TagEmptyCondition>
{
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;
}
}
}

View file

@ -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<TrueCondition>
{
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;
}
}
}

View file

@ -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<Item, Tag<Item>> replacements = new HashMap<>();
private Set<ResourceLocation> 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...
}

View file

@ -208,7 +208,9 @@ public class ModLoader
LOGGER.debug(LOADING, "ModContainer is {}", ModContainer.class.getClassLoader());
final List<ModContainer> 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(),

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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

View file

@ -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",

View file

@ -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<IFinishedRecipe> 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);
}
}
}

View file

@ -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
}
}
}

View file

@ -42,4 +42,8 @@ loaderVersion="[28,)"
[[mods]]
modId="command_event_test"
[[mods]]
modId="entity_selector_test"
modId="entity_selector_test"
[[mods]]
modId="data_gen_test"
[[mods]]
modId="piston_event_test"