diff --git a/src/main/java/knightminer/inspirations/library/recipe/cauldron/CauldronIngredients.java b/src/main/java/knightminer/inspirations/library/recipe/cauldron/CauldronIngredients.java index b69206c5..b2795577 100644 --- a/src/main/java/knightminer/inspirations/library/recipe/cauldron/CauldronIngredients.java +++ b/src/main/java/knightminer/inspirations/library/recipe/cauldron/CauldronIngredients.java @@ -5,9 +5,20 @@ import com.google.gson.JsonObject; import com.google.gson.JsonSyntaxException; import io.netty.handler.codec.DecoderException; +import knightminer.inspirations.Inspirations; +import knightminer.inspirations.library.recipe.cauldron.contents.ICauldronColor; +import knightminer.inspirations.library.recipe.cauldron.contents.ICauldronContents; +import knightminer.inspirations.library.recipe.cauldron.contents.ICauldronDye; +import knightminer.inspirations.library.recipe.cauldron.contents.ICauldronPotion; +import knightminer.inspirations.library.recipe.cauldron.contenttype.MapContentType; +import knightminer.inspirations.library.recipe.cauldron.ingredient.ContentMatchIngredient; +import knightminer.inspirations.library.recipe.cauldron.ingredient.ContentTypeIngredient; +import knightminer.inspirations.library.recipe.cauldron.ingredient.FluidCauldronIngredient; import knightminer.inspirations.library.recipe.cauldron.ingredient.ICauldronIngredient; import knightminer.inspirations.library.recipe.cauldron.ingredient.ICauldronIngredientSerializer; +import net.minecraft.item.DyeColor; import net.minecraft.network.PacketBuffer; +import net.minecraft.potion.Potion; import net.minecraft.util.JSONUtils; import net.minecraft.util.ResourceLocation; @@ -20,7 +31,19 @@ public class CauldronIngredients { /* Public constants */ + /** Generic content match serializer */ + public static final ContentMatchIngredient.Serializer MATCH = register("match_content", ContentMatchIngredient.Serializer.GENERIC); + /** Generic content match serializer */ + public static final ContentTypeIngredient.Serializer TYPE = register("content_type", new ContentTypeIngredient.Serializer()); + /** Fluid content match serializer */ + public static final FluidCauldronIngredient.Serializer FLUID = register("fluid", new FluidCauldronIngredient.Serializer()); + /** Color content match serializer */ + public static final ContentMatchIngredient.Serializer COLOR = registerMatch(CauldronContentTypes.COLOR); + /** Dye content match serializer */ + public static final ContentMatchIngredient.Serializer DYE = registerMatch(CauldronContentTypes.DYE); + /** Fluid content match serializer */ + public static final ContentMatchIngredient.Serializer POTION = registerMatch(CauldronContentTypes.POTION); /** * Registers a new content type @@ -34,6 +57,31 @@ public static void register(ResourceLocation name, ICauldronIngredientSerializer INGREDIENTS.put(name, type); } + /** + * Helper to register static types + * @param name Inspirations namespace name + * @param type Type to register + * @param Output type + * @return Registered type + */ + private static > T register(String name, T type) { + register(Inspirations.getResource(name), type); + return type; + } + + /** + * Registers a generic content match type for the given type + * @param mapType Map type instance + * @param Content type + * @param Map value type + * @return Registered serializer + */ + public static ContentMatchIngredient.Serializer registerMatch(MapContentType mapType) { + ContentMatchIngredient.Serializer serializer = new ContentMatchIngredient.Serializer<>(mapType); + register(CauldronContentTypes.getName(mapType), serializer); + return serializer; + } + /** * Gets the type for the given cauldron contents * @param contents Contents object diff --git a/src/main/java/knightminer/inspirations/library/recipe/cauldron/ingredient/ContentMatchIngredient.java b/src/main/java/knightminer/inspirations/library/recipe/cauldron/ingredient/ContentMatchIngredient.java index 13f5541f..6bbf7f8b 100644 --- a/src/main/java/knightminer/inspirations/library/recipe/cauldron/ingredient/ContentMatchIngredient.java +++ b/src/main/java/knightminer/inspirations/library/recipe/cauldron/ingredient/ContentMatchIngredient.java @@ -10,15 +10,16 @@ import knightminer.inspirations.library.recipe.cauldron.contents.ICauldronContents; import knightminer.inspirations.library.recipe.cauldron.contenttype.CauldronContentType; import knightminer.inspirations.library.recipe.cauldron.contenttype.MapContentType; -import knightminer.inspirations.recipes.InspirationsRecipes; import net.minecraft.network.PacketBuffer; import net.minecraft.util.JSONUtils; import net.minecraft.util.ResourceLocation; import slimeknights.mantle.util.JsonHelper; +import javax.annotation.Nullable; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Objects; import java.util.Set; import java.util.function.Function; @@ -28,10 +29,12 @@ * @param Value type */ public abstract class ContentMatchIngredient implements ICauldronIngredient { + private final ICauldronIngredientSerializer serializer; protected final MapContentType type; @SuppressWarnings("WeakerAccess") - protected ContentMatchIngredient(MapContentType type) { + protected ContentMatchIngredient(ICauldronIngredientSerializer serializer, MapContentType type) { + this.serializer = serializer; this.type = type; } @@ -44,7 +47,7 @@ protected ContentMatchIngredient(MapContentType type) { * @return Ingredient */ public static ContentMatchIngredient of(MapContentType type, T value) { - return new Single<>(type, value); + return new Single<>(Serializer.GENERIC, type, value); } /** @@ -56,7 +59,31 @@ public static ContentMatchIngredient of(Map * @return Ingredient */ public static ContentMatchIngredient of(MapContentType type, Collection values) { - return new Multi<>(type, ImmutableSet.copyOf(values)); + return new Multi<>(Serializer.GENERIC, type, ImmutableSet.copyOf(values)); + } + + /** + * Creates an instance from the given serializer and value + * @param serializer Serializer to use + * @param value Value + * @param Content type + * @param Value type + * @return Ingredient + */ + public static ContentMatchIngredient of(Serializer serializer, T value) { + return new Single<>(serializer, Objects.requireNonNull(serializer.type), value); + } + + /** + * Creates an instance from the given serializer and values + * @param serializer Serializer to use + * @param values Values + * @param Content type + * @param Value type + * @return Ingredient + */ + public static ContentMatchIngredient of(Serializer serializer, Collection values) { + return new Multi<>(serializer, Objects.requireNonNull(serializer.type), ImmutableSet.copyOf(values)); } /** @@ -88,14 +115,14 @@ public boolean test(ICauldronContents contents) { @Override public ICauldronIngredientSerializer getSerializer() { - return InspirationsRecipes.contentMatchIngredient; + return serializer; } /** Matches a single value */ private static class Single extends ContentMatchIngredient { private final T value; - private Single(MapContentType type, T value) { - super(type); + private Single(ICauldronIngredientSerializer serializer, MapContentType type, T value) { + super(serializer, type); this.value = value; } @@ -118,8 +145,8 @@ protected void write(PacketBuffer buffer) { /** Matches from a set */ private static class Multi extends ContentMatchIngredient { private final Set values; - private Multi(MapContentType type, Set values) { - super(type); + private Multi(ICauldronIngredientSerializer serializer, MapContentType type, Set values) { + super(serializer, type); this.values = values; } @@ -146,7 +173,29 @@ protected void write(PacketBuffer buffer) { } } - public static class Serializer implements ICauldronIngredientSerializer { + public static class Serializer implements ICauldronIngredientSerializer> { + /** + * Generic recipe serializer, requires both JSON and packets to include the contents type + */ + public static final Serializer GENERIC = new Serializer<>(); + + @Nullable + private final MapContentType type; + + /** + * Creates a new serializer using the given type + * @param type Serializer type + */ + public Serializer(MapContentType type) { + this.type = type; + } + + /** + * Creates a new generic serializer + */ + private Serializer() { + this.type = null; + } /** * Helper to get a single value from a string @@ -164,6 +213,29 @@ private static ContentMatchIngredient getS return of(type, value); } + /** + * Gets a type from the given name and for the given exception function + * @param name Type name + * @param exception Exception function + * @return Type instance + * @throws RuntimeException if the type is missing or the wrong class type + */ + private static MapContentType getType(ResourceLocation name, Function exception) { + CauldronContentType type = CauldronContentTypes.get(name); + // must exist + if (type == null) { + throw exception.apply("Unknown cauldron content type '" + name + "'"); + } + // must match type + if (!(type instanceof MapContentType)) { + throw exception.apply("Cauldron content type '" + name + "' does not support content match"); + } + // only used by generic type, so type has ?,? generics + //noinspection unchecked + return (MapContentType) type; + } + + /** * Helper to get a list of values from a string * @param type Content type @@ -190,15 +262,15 @@ private static ContentMatchIngredient getL } @Override - public ContentMatchIngredient read(JsonObject json) { - ResourceLocation typeName = new ResourceLocation(JSONUtils.getString(json, "match")); - CauldronContentType baseType = CauldronContentTypes.get(typeName); - if (!(baseType instanceof MapContentType)) { - throw new JsonSyntaxException("Cauldron content type '" + typeName + "' does not support content match"); + public ContentMatchIngredient read(JsonObject json) { + // use the instance type if present + MapContentType type = this.type; + // if generic, find a type using the match key + if (type == null) { + type = getType(new ResourceLocation(JSONUtils.getString(json, "match")), JsonSyntaxException::new); } - // can be string or array - MapContentType type = (MapContentType) baseType; + // actual element can be a string or array JsonElement element = JsonHelper.getElement(json, type.getKey()); // single name @@ -217,21 +289,23 @@ public ContentMatchIngredient read(JsonObject json) { } @Override - public void write(ContentMatchIngredient ingredient, JsonObject json) { - json.addProperty("match", CauldronContentTypes.getName(ingredient.type).toString()); + public void write(ContentMatchIngredient ingredient, JsonObject json) { + if (this.type == null) { + json.addProperty("match", CauldronContentTypes.getName(ingredient.type).toString()); + } ingredient.write(json); } @Override - public ContentMatchIngredient read(PacketBuffer buffer) { - ResourceLocation typeName = buffer.readResourceLocation(); - CauldronContentType baseType = CauldronContentTypes.get(typeName); - if (!(baseType instanceof MapContentType)) { - throw new DecoderException("Cauldron content type '" + typeName + "' does not support content match"); + public ContentMatchIngredient read(PacketBuffer buffer) { + // use the instance type if present + MapContentType type = this.type; + // if generic, find a type using the match key + if (type == null) { + type = getType(buffer.readResourceLocation(), DecoderException::new); } - // read the number told - MapContentType type = (MapContentType) baseType; + // read all values from the buffer int size = buffer.readVarInt(); List names = new ArrayList<>(size); for (int i = 0; i < size; i++) { @@ -243,8 +317,11 @@ public ContentMatchIngredient read(PacketBuffer buffer) { } @Override - public void write(ContentMatchIngredient ingredient, PacketBuffer buffer) { - buffer.writeResourceLocation(CauldronContentTypes.getName(ingredient.type)); + public void write(ContentMatchIngredient ingredient, PacketBuffer buffer) { + // only write the type to the buffer if this is the generic type + if (this.type == null) { + buffer.writeResourceLocation(CauldronContentTypes.getName(ingredient.type)); + } ingredient.write(buffer); } } diff --git a/src/main/java/knightminer/inspirations/library/recipe/cauldron/ingredient/ContentTypeIngredient.java b/src/main/java/knightminer/inspirations/library/recipe/cauldron/ingredient/ContentTypeIngredient.java index b6caa315..5d98a207 100644 --- a/src/main/java/knightminer/inspirations/library/recipe/cauldron/ingredient/ContentTypeIngredient.java +++ b/src/main/java/knightminer/inspirations/library/recipe/cauldron/ingredient/ContentTypeIngredient.java @@ -4,9 +4,9 @@ import com.google.gson.JsonSyntaxException; import io.netty.handler.codec.DecoderException; import knightminer.inspirations.library.recipe.cauldron.CauldronContentTypes; +import knightminer.inspirations.library.recipe.cauldron.CauldronIngredients; import knightminer.inspirations.library.recipe.cauldron.contents.ICauldronContents; import knightminer.inspirations.library.recipe.cauldron.contenttype.CauldronContentType; -import knightminer.inspirations.recipes.InspirationsRecipes; import net.minecraft.network.PacketBuffer; import net.minecraft.util.JSONUtils; import net.minecraft.util.ResourceLocation; @@ -41,7 +41,7 @@ public boolean test(ICauldronContents contents) { @Override public ICauldronIngredientSerializer getSerializer() { - return InspirationsRecipes.contentTypeIngredient; + return CauldronIngredients.TYPE; } public static class Serializer implements ICauldronIngredientSerializer { diff --git a/src/main/java/knightminer/inspirations/library/recipe/cauldron/ingredient/FluidCauldronIngredient.java b/src/main/java/knightminer/inspirations/library/recipe/cauldron/ingredient/FluidCauldronIngredient.java index c9864602..434286ac 100644 --- a/src/main/java/knightminer/inspirations/library/recipe/cauldron/ingredient/FluidCauldronIngredient.java +++ b/src/main/java/knightminer/inspirations/library/recipe/cauldron/ingredient/FluidCauldronIngredient.java @@ -1,29 +1,22 @@ package knightminer.inspirations.library.recipe.cauldron.ingredient; import com.google.common.collect.ImmutableSet; -import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonSyntaxException; -import io.netty.handler.codec.DecoderException; import knightminer.inspirations.library.recipe.cauldron.CauldronContentTypes; +import knightminer.inspirations.library.recipe.cauldron.CauldronIngredients; import knightminer.inspirations.library.recipe.cauldron.contents.ICauldronFluid; -import knightminer.inspirations.recipes.InspirationsRecipes; import net.minecraft.fluid.Fluid; -import net.minecraft.fluid.Fluids; import net.minecraft.network.PacketBuffer; import net.minecraft.tags.FluidTags; import net.minecraft.tags.ITag; import net.minecraft.tags.TagCollectionManager; import net.minecraft.util.JSONUtils; import net.minecraft.util.ResourceLocation; -import net.minecraftforge.registries.ForgeRegistries; -import slimeknights.mantle.util.JsonHelper; -import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Objects; -import java.util.function.Function; /** * Cauldron ingredient type for fluid contents, mostly an extension of {@link ContentMatchIngredient}, but also includes tags @@ -31,7 +24,7 @@ public class FluidCauldronIngredient extends ContentMatchIngredient { private final ITag tag; private FluidCauldronIngredient(ITag tag) { - super(CauldronContentTypes.FLUID); + super(CauldronIngredients.FLUID, CauldronContentTypes.FLUID); this.tag = tag; } @@ -41,7 +34,7 @@ private FluidCauldronIngredient(ITag tag) { * @return Ingredient */ public static ContentMatchIngredient of(Fluid fluid) { - return of(CauldronContentTypes.FLUID, fluid); + return of(CauldronIngredients.FLUID, fluid); } /** @@ -50,7 +43,7 @@ public static ContentMatchIngredient of(Fluid fluid) { * @return Ingredient */ public static ContentMatchIngredient of(Collection fluids) { - return of(CauldronContentTypes.FLUID, ImmutableSet.copyOf(fluids)); + return of(CauldronIngredients.FLUID, ImmutableSet.copyOf(fluids)); } /** @@ -81,45 +74,19 @@ protected void write(PacketBuffer buffer) { } } - @Override - public ICauldronIngredientSerializer getSerializer() { - return InspirationsRecipes.fluidIngredient; - } - - public static class Serializer implements ICauldronIngredientSerializer> { + public static class Serializer extends ContentMatchIngredient.Serializer { /** - * Gets a fluid by name - * @param name Name of the fluid - * @param exception Excecption to throw if no fluid - * @return Fluid + * Creates a new serializer instance */ - private static Fluid getFluid(String name, Function exception) { - Fluid fluid = ForgeRegistries.FLUIDS.getValue(new ResourceLocation(name)); - if (fluid != null && fluid != Fluids.EMPTY) { - return fluid; - } - throw exception.apply("Unknown fluid '" + name + "'"); + public Serializer() { + super(CauldronContentTypes.FLUID); } @Override public ContentMatchIngredient read(JsonObject json) { // single fluid or array if (json.has("name")) { - // can be string or array - JsonElement element = JsonHelper.getElement(json, "name"); - - // single name - if (element.isJsonPrimitive()) { - return of(getFluid(json.getAsString(), JsonSyntaxException::new)); - } - - // array of names - if (element.isJsonArray()) { - return of(JsonHelper.parseList(element.getAsJsonArray(), "names", JSONUtils::getString, name -> getFluid(name, JsonSyntaxException::new))); - } - - // error - throw new JsonSyntaxException("Invalid 'name', must be a single value or an array"); + return super.read(json); } // tag @@ -134,31 +101,5 @@ public ContentMatchIngredient read(JsonObject json) { throw new JsonSyntaxException("Invalid cauldron fluid ingredient, must have 'name' or 'tag"); } - - @Override - public void write(ContentMatchIngredient ingredient, JsonObject json) { - ingredient.write(json); - } - - @Override - public ContentMatchIngredient read(PacketBuffer buffer) { - // read the number told - int size = buffer.readVarInt(); - List fluids = new ArrayList<>(size); - for (int i = 0; i < size; i++) { - fluids.add(getFluid(buffer.readString(Short.MAX_VALUE), DecoderException::new)); - } - - // simplify if just one fluid - if (fluids.size() == 1) { - return of(fluids.get(0)); - } - return of(fluids); - } - - @Override - public void write(ContentMatchIngredient ingredient, PacketBuffer buffer) { - ingredient.write(buffer); - } } } diff --git a/src/main/java/knightminer/inspirations/recipes/InspirationsRecipes.java b/src/main/java/knightminer/inspirations/recipes/InspirationsRecipes.java index 6f05f30e..c7a0a4e2 100644 --- a/src/main/java/knightminer/inspirations/recipes/InspirationsRecipes.java +++ b/src/main/java/knightminer/inspirations/recipes/InspirationsRecipes.java @@ -1,15 +1,9 @@ package knightminer.inspirations.recipes; -import knightminer.inspirations.Inspirations; import knightminer.inspirations.common.Config; import knightminer.inspirations.common.ModuleBase; import knightminer.inspirations.common.item.HidableItem; import knightminer.inspirations.library.recipe.cauldron.CauldronContentTypes; -import knightminer.inspirations.library.recipe.cauldron.CauldronIngredients; -import knightminer.inspirations.library.recipe.cauldron.ingredient.ContentMatchIngredient; -import knightminer.inspirations.library.recipe.cauldron.ingredient.ContentTypeIngredient; -import knightminer.inspirations.library.recipe.cauldron.ingredient.FluidCauldronIngredient; -import knightminer.inspirations.library.recipe.cauldron.ingredient.ICauldronIngredientSerializer; import knightminer.inspirations.library.recipe.cauldron.recipe.CauldronRecipe; import knightminer.inspirations.recipes.block.EnhancedCauldronBlock; import knightminer.inspirations.recipes.block.SmashingAnvilBlock; @@ -58,9 +52,6 @@ public class InspirationsRecipes extends ModuleBase { // cauldron serializers public static CauldronRecipe.Serializer cauldronSerializer; - public static ContentTypeIngredient.Serializer contentTypeIngredient; - public static ContentMatchIngredient.Serializer contentMatchIngredient; - public static FluidCauldronIngredient.Serializer fluidIngredient; @SubscribeEvent @@ -107,11 +98,6 @@ void registerSerializers(Register> event) { RegistryAdapter> registry = new RegistryAdapter<>(event.getRegistry()); cauldronSerializer = registry.register(new CauldronRecipe.Serializer(), "cauldron"); - // cauldron ingredients - fluidIngredient = registerCauldronIngredient("fluid", new FluidCauldronIngredient.Serializer()); - contentTypeIngredient = registerCauldronIngredient("type", new ContentTypeIngredient.Serializer()); - contentMatchIngredient = registerCauldronIngredient("match", new ContentMatchIngredient.Serializer()); - // add water as an override to fluids and potions CauldronWater water = CauldronContentTypes.WATER.get(); CauldronContentTypes.FLUID.addOverride(Fluids.WATER, water); @@ -160,18 +146,4 @@ public void registerRecipes(Register> event) { } } }*/ - - /* Utils */ - - /** - * Registers a cauldron ingredient to Inspirations name - * @param name Ingredient name - * @param serializer Serializer instance - * @param Class type - * @return Registered serializer - */ - private static > T registerCauldronIngredient(String name, T serializer) { - CauldronIngredients.register(Inspirations.getResource(name), serializer); - return serializer; - } }