Finally got all the recipes fixed

This commit is contained in:
Sollace 2020-05-02 18:20:41 +02:00
parent 070aeaefe3
commit 8e30e8539a
65 changed files with 861 additions and 607 deletions

View file

@ -8,7 +8,7 @@ import com.google.common.collect.Sets;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonSyntaxException;
import com.minelittlepony.unicopia.recipe.ingredient.Ingredient;
import com.minelittlepony.unicopia.recipe.ingredient.PredicatedIngredient;
import net.minecraft.inventory.CraftingInventory;
import net.minecraft.util.DefaultedList;
@ -20,42 +20,42 @@ public class Pattern {
public static Pattern read(PacketByteBuf buf) {
return new Pattern(
Utils.read(buf, Ingredient.EMPTY, Ingredient::read),
Utils.read(buf, PredicatedIngredient.EMPTY, PredicatedIngredient::read),
buf.readVarInt(),
buf.readVarInt()
);
}
public static Pattern read(JsonObject json) {
String[] patterns = combinePatternMatrix(getPattern(JsonHelper.getArray(json, "pattern")));
Map<String, Ingredient> ingredients = readIngredients(JsonHelper.getObject(json, "key"));
String[] patterns = removePadding(readPattern(JsonHelper.getArray(json, "pattern")));
Map<String, PredicatedIngredient> symbols = readSymbols(JsonHelper.getObject(json, "key"));
return new Pattern(patterns, ingredients);
return new Pattern(patterns, symbols);
}
public final DefaultedList<Ingredient> matrix;
public final DefaultedList<PredicatedIngredient> matrix;
public final int width;
public final int height;
public Pattern(DefaultedList<Ingredient> matrix, int width, int height) {
public Pattern(DefaultedList<PredicatedIngredient> matrix, int width, int height) {
this.matrix = matrix;
this.width = width;
this.height = height;
}
public Pattern(String[] pattern, Map<String, Ingredient> ingredients) {
public Pattern(String[] pattern, Map<String, PredicatedIngredient> ingredients) {
this(pattern, ingredients, pattern[0].length(), pattern.length);
}
private Pattern(String[] pattern, Map<String, Ingredient> ingredients, int width, int height) {
private Pattern(String[] pattern, Map<String, PredicatedIngredient> ingredients, int width, int height) {
this(buildIngredientMatrix(pattern, ingredients, width, height), width, height);
}
public boolean matches(CraftingInventory inv) {
for(int x = 0; x <= inv.getWidth() - width; x++) {
for(int y = 0; y <= inv.getHeight() - height; y++) {
if (matchesSmall(inv, x, y, true) || matchesSmall(inv, x, y, false)) {
if (matchesPattern(inv, x, y, true) || matchesPattern(inv, x, y, false)) {
return true;
}
}
@ -65,7 +65,7 @@ public class Pattern {
}
public void write(PacketByteBuf buf) {
Utils.write(buf, matrix, Ingredient::write);
Utils.write(buf, matrix, PredicatedIngredient::write);
buf.writeVarInt(width);
buf.writeVarInt(height);
}
@ -74,17 +74,19 @@ public class Pattern {
return matrix.size();
}
private boolean matchesSmall(CraftingInventory inv, int offsetX, int offsetY, boolean reflected) {
private boolean matchesPattern(CraftingInventory inv, int offsetX, int offsetY, boolean reflected) {
for(int x = 0; x < inv.getWidth(); ++x) {
for(int y = 0; y < inv.getHeight(); ++y) {
int k = x - offsetX;
int l = y - offsetY;
Ingredient ingredient = Ingredient.EMPTY;
if (k >= 0 && l >= 0 && k < width && l < this.height) {
int left = x - offsetX;
int top = y - offsetY;
PredicatedIngredient ingredient = PredicatedIngredient.EMPTY;
if (left >= 0 && top >= 0 && left < width && top < height) {
if (reflected) {
ingredient = matrix.get(width - k - 1 + l * this.width);
ingredient = matrix.get(width - left - 1 + top * width);
} else {
ingredient = matrix.get(k + l * this.width);
ingredient = matrix.get(left + top * width);
}
}
@ -97,111 +99,130 @@ public class Pattern {
return true;
}
static DefaultedList<Ingredient> buildIngredientMatrix(String[] pattern, Map<String, Ingredient> ingredients, int width, int height) {
DefaultedList<Ingredient> result = DefaultedList.ofSize(width * height, Ingredient.EMPTY);
static DefaultedList<PredicatedIngredient> buildIngredientMatrix(String[] pattern, Map<String, PredicatedIngredient> symbols, int width, int height) {
DefaultedList<PredicatedIngredient> result = DefaultedList.ofSize(width * height, PredicatedIngredient.EMPTY);
Set<String> unsolved = Sets.newHashSet(ingredients.keySet());
unsolved.remove(" ");
Set<String> unresolved = Sets.newHashSet(symbols.keySet());
unresolved.remove(" ");
for(int i = 0; i < pattern.length; ++i) {
for(int j = 0; j < pattern[i].length(); ++j) {
String key = pattern[i].substring(j, j + 1);
Ingredient ingredient = ingredients.get(key);
PredicatedIngredient ingredient = symbols.get(key);
if (ingredient == null) {
throw new JsonSyntaxException("Pattern references symbol '" + key + "' but it's not defined in the key");
}
unsolved.remove(key);
unresolved.remove(key);
result.set(j + width * i, ingredient);
}
}
if (!unsolved.isEmpty()) {
throw new JsonSyntaxException("Key defines symbols that aren't used in pattern: " + unsolved);
if (!unresolved.isEmpty()) {
throw new JsonSyntaxException("Key defines symbols that aren't used in pattern: " + unresolved);
}
return result;
}
static String[] combinePatternMatrix(String... lines) {
int i = Integer.MAX_VALUE;
int j = 0;
int k = 0;
int l = 0;
/**
* Removes empty space from around the recipe pattern.
*
* Turns patterns such as:
* " o"
* " a"
* " "
* Into:
* "o"
* "a"
*
* @param pattern
* @return A new recipe pattern with all leading and trailing empty rows/columns removed.
*/
static String[] removePadding(String... pattern) {
int left = Integer.MAX_VALUE;
int right = 0;
for(int row = 0; row < lines.length; ++row) {
String line = lines[row];
int top = 0;
int bottom = 0;
i = Math.min(i, lookAhead(line));
for(int yPosition = 0; yPosition < pattern.length; ++yPosition) {
String row = pattern[yPosition];
int n = lookBack(line);
left = Math.min(left, findFirstSymbol(row));
j = Math.max(j, n);
if (n < 0) {
if (k == row) {
++k;
int rowEnd = findLastSymbol(row);
right = Math.max(right, rowEnd);
if (rowEnd < 0) {
if (top == yPosition) {
top++;
}
++l;
bottom++;
} else {
l = 0;
bottom = 0;
}
}
if (lines.length == l) {
if (pattern.length == bottom) {
return new String[0];
}
String[] strings = new String[lines.length - l - k];
String[] strings = new String[pattern.length - bottom - top];
for(int o = 0; o < strings.length; ++o) {
strings[o] = lines[o + k].substring(i, j + 1);
for(int i = 0; i < strings.length; i++) {
strings[i] = pattern[i + top].substring(left, right + 1);
}
return strings;
}
private static int lookAhead(String pattern) {
private static int findFirstSymbol(String pattern) {
int i;
for(i = 0; i < pattern.length() && pattern.charAt(i) == ' '; ++i) {}
return i;
}
private static int lookBack(String pattern) {
private static int findLastSymbol(String pattern) {
int i;
for(i = pattern.length() - 1; i >= 0 && pattern.charAt(i) == ' '; --i) {}
return i;
}
static String[] getPattern(JsonArray json) {
String[] strings = new String[json.size()];
if (strings.length > 3) {
throw new JsonSyntaxException("Invalid pattern: too many rows, 3 is maximum");
} else if (strings.length == 0) {
throw new JsonSyntaxException("Invalid pattern: empty pattern not allowed");
} else {
for(int i = 0; i < strings.length; ++i) {
String string = JsonHelper.asString(json.get(i), "pattern[" + i + "]");
if (string.length() > 3) {
static String[] readPattern(JsonArray json) {
String[] rows = new String[json.size()];
if (rows.length > 3) {
throw new JsonSyntaxException("Invalid pattern: too many rows, 3 is maximum");
}
if (rows.length == 0) {
throw new JsonSyntaxException("Invalid pattern: empty pattern not allowed");
}
for(int i = 0; i < rows.length; ++i) {
String column = JsonHelper.asString(json.get(i), "pattern[" + i + "]");
if (column.length() > 3) {
throw new JsonSyntaxException("Invalid pattern: too many columns, 3 is maximum");
}
}
if (i > 0 && strings[0].length() != string.length()) {
if (i > 0 && rows[0].length() != column.length()) {
throw new JsonSyntaxException("Invalid pattern: each row must be the same width");
}
}
strings[i] = string;
}
rows[i] = column;
}
return strings;
}
return rows;
}
static Map<String, Ingredient> readIngredients(JsonObject json) {
static Map<String, PredicatedIngredient> readSymbols(JsonObject json) {
return Util.make(json.entrySet().stream().collect(Collectors.toMap(e -> {
if (e.getKey().length() != 1) {
throw new JsonSyntaxException("Invalid key entry: '" + e.getKey() + "' is an invalid symbol (must be 1 character only).");
@ -213,8 +234,7 @@ public class Pattern {
return e.getKey();
},
e -> Ingredient.one(e.getValue())
)), m -> m.put(" ", Ingredient.EMPTY));
e -> PredicatedIngredient.one(e.getValue())
)), m -> m.put(" ", PredicatedIngredient.EMPTY));
}
}

View file

@ -3,10 +3,11 @@ package com.minelittlepony.unicopia.recipe;
import java.util.Random;
import com.google.gson.JsonObject;
import com.minelittlepony.unicopia.recipe.ingredient.Ingredient;
import com.minelittlepony.unicopia.recipe.ingredient.PredicatedIngredient;
import net.minecraft.inventory.CraftingInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.recipe.Ingredient;
import net.minecraft.recipe.RecipeSerializer;
import net.minecraft.recipe.SpecialCraftingRecipe;
import net.minecraft.util.DefaultedList;
@ -20,10 +21,10 @@ public class ShapedSpecialRecipe extends SpecialCraftingRecipe {
private static final Random RANDOM = new Random();
private final Pattern pattern;
private final Ingredient output;
private final PredicatedIngredient output;
private final String group;
public ShapedSpecialRecipe(Identifier id, String group, Pattern pattern, Ingredient output) {
public ShapedSpecialRecipe(Identifier id, String group, Pattern pattern, PredicatedIngredient output) {
super(id);
this.group = group;
this.pattern = pattern;
@ -57,7 +58,7 @@ public class ShapedSpecialRecipe extends SpecialCraftingRecipe {
@Override
public RecipeSerializer<?> getSerializer() {
return null;
return URecipes.CRAFTING_SHAPED;
}
@Override
@ -66,8 +67,8 @@ public class ShapedSpecialRecipe extends SpecialCraftingRecipe {
}
@Override
public DefaultedList<net.minecraft.recipe.Ingredient> getPreviewInputs() {
return Ingredient.preview(pattern.matrix);
public DefaultedList<Ingredient> getPreviewInputs() {
return PredicatedIngredient.preview(pattern.matrix);
}
public static class Serializer implements RecipeSerializer<ShapedSpecialRecipe> {
@ -76,7 +77,7 @@ public class ShapedSpecialRecipe extends SpecialCraftingRecipe {
return new ShapedSpecialRecipe(id,
JsonHelper.getString(json, "group", ""),
Pattern.read(json),
Ingredient.one(json.get("result"))
PredicatedIngredient.one(json.get("result"))
);
}
@ -85,7 +86,7 @@ public class ShapedSpecialRecipe extends SpecialCraftingRecipe {
return new ShapedSpecialRecipe(id,
buf.readString(32767),
Pattern.read(buf),
Ingredient.read(buf)
PredicatedIngredient.read(buf)
);
}

View file

@ -2,10 +2,11 @@ package com.minelittlepony.unicopia.recipe;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.minelittlepony.unicopia.recipe.ingredient.Ingredient;
import com.minelittlepony.unicopia.recipe.ingredient.PredicatedIngredient;
import net.minecraft.inventory.CraftingInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.recipe.Ingredient;
import net.minecraft.recipe.RecipeSerializer;
import net.minecraft.recipe.SpecialCraftingRecipe;
import net.minecraft.util.DefaultedList;
@ -17,11 +18,11 @@ import net.minecraft.world.World;
public class ShapelessSpecialRecipe extends SpecialCraftingRecipe {
private final String group;
private final Ingredient output;
private final PredicatedIngredient output;
private final DefaultedList<Ingredient> input;
private final DefaultedList<PredicatedIngredient> input;
public ShapelessSpecialRecipe(Identifier id, String group, Ingredient output, DefaultedList<Ingredient> input) {
public ShapelessSpecialRecipe(Identifier id, String group, PredicatedIngredient output, DefaultedList<PredicatedIngredient> input) {
super(id);
this.group = group;
this.output = output;
@ -66,8 +67,8 @@ public class ShapelessSpecialRecipe extends SpecialCraftingRecipe {
}
@Override
public DefaultedList<net.minecraft.recipe.Ingredient> getPreviewInputs() {
return Ingredient.preview(input);
public DefaultedList<Ingredient> getPreviewInputs() {
return PredicatedIngredient.preview(input);
}
@Override
@ -77,11 +78,11 @@ public class ShapelessSpecialRecipe extends SpecialCraftingRecipe {
public static class Serializer implements RecipeSerializer<ShapelessSpecialRecipe> {
@Override
public ShapelessSpecialRecipe read(Identifier identifier, JsonObject jsonObject) {
public ShapelessSpecialRecipe read(Identifier identifier, JsonObject json) {
return new ShapelessSpecialRecipe(identifier,
JsonHelper.getString(jsonObject, "group", ""),
Ingredient.one(jsonObject.get("output")),
Ingredient.many(JsonHelper.getArray(jsonObject, "ingredients"))
JsonHelper.getString(json, "group", ""),
PredicatedIngredient.one(json.get("result")),
PredicatedIngredient.many(JsonHelper.getArray(json, "ingredients"))
);
}
@ -89,8 +90,8 @@ public class ShapelessSpecialRecipe extends SpecialCraftingRecipe {
public ShapelessSpecialRecipe read(Identifier identifier, PacketByteBuf buf) {
return new ShapelessSpecialRecipe(identifier,
buf.readString(32767),
Ingredient.read(buf),
Utils.read(buf, Ingredient.EMPTY, Ingredient::read));
PredicatedIngredient.read(buf),
Utils.read(buf, PredicatedIngredient.EMPTY, PredicatedIngredient::read));
}
@Override
@ -98,7 +99,7 @@ public class ShapelessSpecialRecipe extends SpecialCraftingRecipe {
buf.writeString(recipe.group);
recipe.output.write(buf);
buf.writeVarInt(recipe.input.size());
Utils.write(buf, recipe.input, Ingredient::write);
Utils.write(buf, recipe.input, PredicatedIngredient::write);
}
}
}

View file

@ -3,10 +3,11 @@ package com.minelittlepony.unicopia.recipe;
import com.google.gson.JsonObject;
import com.minelittlepony.unicopia.container.SpellBookInventory;
import com.minelittlepony.unicopia.item.UItems;
import com.minelittlepony.unicopia.recipe.ingredient.Ingredient;
import com.minelittlepony.unicopia.recipe.ingredient.PredicatedIngredient;
import net.minecraft.inventory.CraftingInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.recipe.Ingredient;
import net.minecraft.recipe.Recipe;
import net.minecraft.recipe.RecipeSerializer;
import net.minecraft.recipe.RecipeType;
@ -21,19 +22,17 @@ import net.minecraft.world.World;
*/
public class SpellBookRecipe implements Recipe<CraftingInventory> {
private final Ingredient input;
private final Ingredient output;
private final DefaultedList<Ingredient> ingredients;
private final Identifier id;
private final PredicatedIngredient input;
private final PredicatedIngredient output;
private final DefaultedList<PredicatedIngredient> ingredients;
public SpellBookRecipe(Identifier id, Ingredient input, Ingredient output, DefaultedList<Ingredient> ingredients) {
public SpellBookRecipe(Identifier id, String group, PredicatedIngredient input, PredicatedIngredient output, DefaultedList<PredicatedIngredient> ingredients) {
this.id = id;
this.input = input;
this.output = output;
this.ingredients = ingredients;
this.input = input;
}
@Override
@ -68,8 +67,8 @@ public class SpellBookRecipe implements Recipe<CraftingInventory> {
}
@Override
public DefaultedList<net.minecraft.recipe.Ingredient> getPreviewInputs() {
return Ingredient.preview(ingredients, DefaultedList.copyOf(null, input.getPreview()));
public DefaultedList<Ingredient> getPreviewInputs() {
return PredicatedIngredient.preview(ingredients, DefaultedList.copyOf(null, input.getPreview()));
}
@Override
@ -96,18 +95,20 @@ public class SpellBookRecipe implements Recipe<CraftingInventory> {
@Override
public SpellBookRecipe read(Identifier id, JsonObject json) {
return new SpellBookRecipe(id,
Ingredient.one(json.get("input")),
Ingredient.one(json.get("result")),
Ingredient.many(JsonHelper.getArray(json, "ingredients"))
JsonHelper.getString(json, "group", ""),
PredicatedIngredient.one(JsonHelper.getObject(json, "input")),
PredicatedIngredient.one(JsonHelper.getObject(json, "result")),
PredicatedIngredient.many(JsonHelper.getArray(json, "ingredients"))
);
}
@Override
public SpellBookRecipe read(Identifier id, PacketByteBuf buf) {
return new SpellBookRecipe(id,
Ingredient.read(buf),
Ingredient.read(buf),
Utils.read(buf, Ingredient.EMPTY, Ingredient::read)
buf.readString(32767),
PredicatedIngredient.read(buf),
PredicatedIngredient.read(buf),
Utils.read(buf, PredicatedIngredient.EMPTY, PredicatedIngredient::read)
);
}
@ -115,7 +116,7 @@ public class SpellBookRecipe implements Recipe<CraftingInventory> {
public void write(PacketByteBuf buf, SpellBookRecipe recipe) {
recipe.input.write(buf);
recipe.output.write(buf);
Utils.write(buf, recipe.ingredients, Ingredient::write);
Utils.write(buf, recipe.ingredients, PredicatedIngredient::write);
}
}
}

View file

@ -6,18 +6,24 @@ import java.util.function.BiConsumer;
import java.util.function.Function;
import com.google.common.collect.Lists;
import com.minelittlepony.unicopia.recipe.ingredient.Ingredient;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.minelittlepony.unicopia.recipe.ingredient.PredicatedIngredient;
import net.minecraft.inventory.Inventory;
import net.minecraft.item.ItemStack;
import net.minecraft.util.DefaultedList;
import net.minecraft.util.Identifier;
import net.minecraft.util.JsonHelper;
import net.minecraft.util.PacketByteBuf;
public class Utils {
public final class Utils {
private Utils() {}
static final Random RANDOM = new Random();
public static final Random RANDOM = new Random();
static <T> DefaultedList<T> read(PacketByteBuf buf, T def, Function<PacketByteBuf, T> reader) {
public static <T> DefaultedList<T> read(PacketByteBuf buf, T def, Function<PacketByteBuf, T> reader) {
DefaultedList<T> list = DefaultedList.ofSize(buf.readInt(), def);
for (int i = 0; i < list.size(); i++) {
list.set(i, reader.apply(buf));
@ -25,18 +31,32 @@ public class Utils {
return list;
}
static <T> void write(PacketByteBuf buf, DefaultedList<T> list, BiConsumer<T, PacketByteBuf> writer) {
public static <T> void write(PacketByteBuf buf, DefaultedList<T> list, BiConsumer<T, PacketByteBuf> writer) {
buf.writeInt(list.size());
list.forEach(i -> writer.accept(i, buf));
}
public static Identifier asIdentifier(JsonElement json) {
return new Identifier(json.getAsString());
}
public static <C extends Inventory> boolean matchShapeless(DefaultedList<Ingredient> ingredients, C inv, int mult) {
public static Identifier getIdentifier(JsonObject json, String property) {
return new Identifier(JsonHelper.getString(json, property));
}
public static <T> T require(T reference, String errorMessage) {
if (reference == null) {
throw new JsonParseException(errorMessage);
}
return reference;
}
public static <C extends Inventory> boolean matchShapeless(DefaultedList<PredicatedIngredient> ingredients, C inv, int mult) {
if (mult == 0) {
return false;
}
List<Ingredient> toMatch = Lists.newArrayList(ingredients);
List<PredicatedIngredient> toMatch = Lists.newArrayList(ingredients);
for (int i = 0; i < inv.getInvSize(); i++) {
ItemStack stack = inv.getInvStack(i);
@ -51,7 +71,7 @@ public class Utils {
return toMatch.isEmpty();
}
private static boolean removeMatch(List<Ingredient> toMatch, ItemStack stack, int materialMult) {
private static boolean removeMatch(List<PredicatedIngredient> toMatch, ItemStack stack, int materialMult) {
return toMatch.stream()
.filter(s -> s.matches(stack, materialMult))
.findFirst()

View file

@ -1,25 +1,27 @@
package com.minelittlepony.unicopia.recipe.ingredient;
import java.util.List;
import java.util.Random;
import java.util.stream.Stream;
import com.google.gson.JsonArray;
import com.minelittlepony.unicopia.recipe.Utils;
import net.minecraft.item.ItemStack;
import net.minecraft.util.DefaultedList;
import net.minecraft.util.PacketByteBuf;
/**
* Requires only one of the sub-ingredients to match when matching.
* Makes a random choice from a pool of alternatives when crafting.
*/
class ChoicePredicate implements Ingredient.Predicate {
static Ingredient.Predicate read(JsonArray arr) {
return new ChoicePredicate(Ingredient.many(arr));
class ChoicePredicate implements Predicate {
static Predicate read(JsonArray arr) {
return new ChoicePredicate(PredicatedIngredient.many(arr));
}
private final List<Ingredient> options;
private final DefaultedList<PredicatedIngredient> options;
ChoicePredicate(List<Ingredient> options) {
ChoicePredicate(DefaultedList<PredicatedIngredient> options) {
this.options = options;
}
@ -34,13 +36,24 @@ class ChoicePredicate implements Ingredient.Predicate {
}
@Override
public void write(PacketByteBuf buf) {
buf.writeInt(options.size());
options.forEach(i -> i.write(buf));
public Stream<ItemStack> getMatchingStacks() {
return options.stream().flatMap(PredicatedIngredient::getMatchingStacks).distinct();
}
@Override
public Stream<ItemStack> getMatchingStacks() {
return options.stream().flatMap(Ingredient::getMatchingStacks).distinct();
public PredicateSerializer<?> getSerializer() {
return PredicateSerializer.CHOICE;
}
static final class Serializer implements PredicateSerializer<ChoicePredicate> {
@Override
public Predicate read(PacketByteBuf buf) {
return new ChoicePredicate(Utils.read(buf, PredicatedIngredient.EMPTY, PredicatedIngredient::read));
}
@Override
public void write(PacketByteBuf buf, ChoicePredicate predicate) {
Utils.write(buf, predicate.options, PredicatedIngredient::write);
}
}
}

View file

@ -7,10 +7,10 @@ import java.util.function.BiPredicate;
import java.util.stream.Stream;
import com.google.gson.JsonObject;
import com.minelittlepony.unicopia.recipe.Utils;
import net.minecraft.item.ItemStack;
import net.minecraft.util.JsonHelper;
import net.minecraft.util.Lazy;
import net.minecraft.util.PacketByteBuf;
import net.minecraft.util.Util;
@ -18,7 +18,7 @@ import net.minecraft.util.Util;
* Tests for whether a tag contains the input when matching.
* Supplies a random item from the tag as the output when crafting.
*/
class DamagePredicate implements Ingredient.Predicate {
class DamagePredicate implements Predicate {
private static final Map<String, BiPredicate<Integer, Integer>> OPERATIONS = Util.make(new HashMap<>(), map -> {
map.put("==", (a, b) -> a == b);
map.put("!=", (a, b) -> a != b);
@ -28,35 +28,15 @@ class DamagePredicate implements Ingredient.Predicate {
map.put("<=", (a, b) -> a <= b);
});
static Ingredient.Predicate read(PacketByteBuf buf) {
int count = buf.readInt();
if (count == 0) {
return EMPTY;
}
return new DamagePredicate(buf.readInt(), buf.readString(32767));
}
static Ingredient.Predicate read(JsonObject json) {
if (!json.has("damage")) {
return EMPTY;
}
JsonObject o = JsonHelper.getObject(json, "damage");
return new DamagePredicate(
JsonHelper.getInt(o, "damage"),
JsonHelper.getString(o, "op")
);
}
private final String op;
private final int damage;
private final Lazy<BiPredicate<Integer, Integer>> operation;
private final BiPredicate<Integer, Integer> operation;
DamagePredicate(int damage, String op) {
this.op = op.trim();
this.damage = damage;
this.operation = new Lazy<>(() -> OPERATIONS.get(op));
this.operation = Utils.require(OPERATIONS.get(op), "Invalid damage tag '" + op + "' " + damage);
}
@Override
@ -72,13 +52,41 @@ class DamagePredicate implements Ingredient.Predicate {
@Override
public boolean matches(ItemStack other, int materialMult) {
return !other.isEmpty() && operation.get().test(other.getDamage(), damage);
return !other.isEmpty() && operation.test(other.getDamage(), damage);
}
@Override
public void write(PacketByteBuf buf) {
buf.writeInt(1);
buf.writeInt(damage);
buf.writeString(op);
public PredicateSerializer<?> getSerializer() {
return PredicateSerializer.DAMAGE;
}
static final class Serializer implements PredicateSerializer<DamagePredicate>, PredicateSerializer.JsonReader {
@Override
public Predicate read(PacketByteBuf buf) {
int count = buf.readInt();
if (count == 0) {
return Predicate.EMPTY;
}
return new DamagePredicate(buf.readInt(), buf.readString(32767));
}
@Override
public void write(PacketByteBuf buf, DamagePredicate predicate) {
buf.writeInt(predicate.damage);
buf.writeString(predicate.op);
}
@Override
public Predicate read(JsonObject json) {
if (!json.has("damage")) {
return Predicate.EMPTY;
}
JsonObject o = JsonHelper.getObject(json, "damage");
return new DamagePredicate(
JsonHelper.getInt(o, "damage"),
JsonHelper.getString(o, "op")
);
}
}
}

View file

@ -5,12 +5,14 @@ import java.util.stream.Stream;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.minelittlepony.unicopia.recipe.Utils;
import net.minecraft.enchantment.Enchantment;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.util.Identifier;
import net.minecraft.util.JsonHelper;
import net.minecraft.util.PacketByteBuf;
import net.minecraft.util.registry.Registry;
@ -18,48 +20,20 @@ import net.minecraft.util.registry.Registry;
* A predicate that tests for a specific enchantment on an input when matching.
* Appends that enchantment to the output when crafting.
*/
class EnchantmentPredicate implements Ingredient.Predicate {
public static Ingredient.Predicate read(PacketByteBuf buf) {
int level = buf.readInt();
if (level == 0) {
return EMPTY;
}
return new EnchantmentPredicate(Registry.ENCHANTMENT.get(buf.readIdentifier()), level);
}
static Ingredient.Predicate read(JsonObject json) {
if (!json.has("enchantment")) {
return EMPTY;
}
JsonElement e = json.get("enchantment");
if (e.isJsonObject()) {
JsonObject o = e.getAsJsonObject();
Enchantment enchantment = Registry.ENCHANTMENT.get(new Identifier(o.get("id").getAsString()));
int level = o.has("level") ? o.get("level").getAsInt() : 1;
return new EnchantmentPredicate(enchantment, level);
}
Enchantment enchantment = Registry.ENCHANTMENT.get(new Identifier(e.getAsString()));
return new EnchantmentPredicate(enchantment, 1);
}
class EnchantmentPredicate implements Predicate {
private final int level;
private final Enchantment enchantment;
EnchantmentPredicate(Enchantment enchantment, int level) {
this.enchantment = enchantment;
EnchantmentPredicate(Identifier id, int level) {
this.enchantment = Utils.require(Registry.ENCHANTMENT.get(id), "Invalid enchantment tag '" + id + "'");
this.level = level;
if (enchantment == null) {
throw new JsonParseException("Invalid enchantment (null)");
}
}
@Override
public ItemStack applyModifiers(ItemStack output, Random random) {
if (output.isEmpty()) {
output = new ItemStack(Items.ENCHANTED_BOOK);
}
output.addEnchantment(enchantment, level);
return output;
}
@ -69,14 +43,47 @@ class EnchantmentPredicate implements Ingredient.Predicate {
return EnchantmentHelper.getLevel(enchantment, stack) >= level;
}
@Override
public void write(PacketByteBuf buf) {
buf.writeInt(level);
buf.writeIdentifier(Registry.ENCHANTMENT.getId(enchantment));
}
@Override
public Stream<ItemStack> getMatchingStacks() {
return Stream.empty();
}
@Override
public PredicateSerializer<?> getSerializer() {
return PredicateSerializer.ENCHANTMENT;
}
static final class Serializer implements PredicateSerializer<EnchantmentPredicate>, PredicateSerializer.JsonReader {
@Override
public Predicate read(PacketByteBuf buf) {
int level = buf.readInt();
if (level == 0) {
return Predicate.EMPTY;
}
return new EnchantmentPredicate(buf.readIdentifier(), level);
}
@Override
public void write(PacketByteBuf buf, EnchantmentPredicate predicate) {
buf.writeInt(predicate.level);
buf.writeIdentifier(Registry.ENCHANTMENT.getId(predicate.enchantment));
}
@Override
public Predicate read(JsonObject json) {
if (!json.has("enchantment")) {
return Predicate.EMPTY;
}
JsonElement e = json.get("enchantment");
if (e.isJsonObject()) {
JsonObject o = e.getAsJsonObject();
return new EnchantmentPredicate(Utils.getIdentifier(o, "id"), Math.max(1, JsonHelper.getInt(o, "level", 1)));
}
return new EnchantmentPredicate(Utils.asIdentifier(e), 1);
}
}
}

View file

@ -1,140 +0,0 @@
package com.minelittlepony.unicopia.recipe.ingredient;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.annotation.concurrent.Immutable;
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.JsonParseException;
import net.minecraft.item.ItemStack;
import net.minecraft.util.DefaultedList;
import net.minecraft.util.Lazy;
import net.minecraft.util.PacketByteBuf;
@Immutable
public class Ingredient {
public static final Ingredient EMPTY = new Ingredient(Predicate.EMPTY, Predicate.EMPTY, Predicate.EMPTY, Predicate.EMPTY, Predicate.EMPTY);
private final List<Predicate> predicates;
private final Lazy<List<ItemStack>> matchingStacks;
private final Lazy<net.minecraft.recipe.Ingredient> preview;
Ingredient(Predicate... predicates) {
this.predicates = Lists.newArrayList(predicates);
this.matchingStacks = new Lazy<>(() -> {
return this.predicates.stream()
.flatMap(Predicate::getMatchingStacks)
.filter(s -> matches(s, 1))
.collect(Collectors.toList());
});
this.preview = new Lazy<>(() -> {
return net.minecraft.recipe.Ingredient.ofStacks(getMatchingStacks().toArray(ItemStack[]::new));
});
}
public Stream<ItemStack> getMatchingStacks() {
return matchingStacks.get().stream();
}
public net.minecraft.recipe.Ingredient getPreview() {
return preview.get();
}
public ItemStack getStack(Random random) {
ItemStack[] output = new ItemStack[] { ItemStack.EMPTY.copy() };
predicates.forEach(p -> output[0] = p.applyModifiers(output[0], random));
return output[0];
}
public boolean matches(ItemStack other, int materialMult) {
return predicates.stream().allMatch(p -> p.matches(other, materialMult));
}
public void write(PacketByteBuf buf) {
predicates.forEach(p -> p.write(buf));
}
public static Ingredient read(PacketByteBuf buf) {
return new Ingredient(
StackPredicate.read(buf),
TagPredicate.read(buf),
SpellPredicate.read(buf),
EnchantmentPredicate.read(buf),
ToxicityPredicate.read(buf));
}
public static Ingredient one(JsonElement json) {
if (json.isJsonArray()) {
return new Ingredient(
ChoicePredicate.read(json.getAsJsonArray()),
Predicate.EMPTY,
Predicate.EMPTY,
Predicate.EMPTY,
Predicate.EMPTY);
}
JsonObject obj = json.getAsJsonObject();
return new Ingredient(
StackPredicate.read(obj),
TagPredicate.read(obj),
SpellPredicate.read(obj),
EnchantmentPredicate.read(obj),
ToxicityPredicate.read(obj));
}
public static DefaultedList<Ingredient> many(JsonArray arr) {
DefaultedList<Ingredient> ingredients = DefaultedList.copyOf(EMPTY);
arr.forEach(i -> ingredients.add(one(i)));
if (ingredients.isEmpty()) {
throw new JsonParseException("Recipe cannot have 0 ingredients");
}
return ingredients;
}
public static DefaultedList<net.minecraft.recipe.Ingredient> preview(DefaultedList<Ingredient> input) {
return preview(input, DefaultedList.of());
}
public static DefaultedList<net.minecraft.recipe.Ingredient> preview(DefaultedList<Ingredient> input, DefaultedList<net.minecraft.recipe.Ingredient> output) {
input.stream().map(Ingredient::getPreview).forEach(output::add);
return output;
}
public interface Predicate {
Predicate EMPTY = new Predicate() {
@Override
public Stream<ItemStack> getMatchingStacks() {
return Stream.empty();
}
@Override
public boolean matches(ItemStack stack, int materialMult) {
return true;
}
};
Stream<ItemStack> getMatchingStacks();
boolean matches(ItemStack stack, int materialMult);
default ItemStack applyModifiers(ItemStack output, Random random) {
return output;
}
default void write(PacketByteBuf buf) {
buf.writeInt(0);
}
}
}

View file

@ -0,0 +1,88 @@
package com.minelittlepony.unicopia.recipe.ingredient;
import java.util.Random;
import java.util.stream.Stream;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.minelittlepony.unicopia.recipe.Utils;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.potion.Potion;
import net.minecraft.potion.PotionUtil;
import net.minecraft.potion.Potions;
import net.minecraft.util.Identifier;
import net.minecraft.util.JsonHelper;
import net.minecraft.util.PacketByteBuf;
import net.minecraft.util.registry.Registry;
/**
* A predicate that tests for a specific enchantment on an input when matching.
* Appends that enchantment to the output when crafting.
*/
class PotionPredicate implements Predicate {
private final Potion potion;
PotionPredicate(Identifier id, int level) {
this.potion = Registry.POTION.get(id);
if (potion == Potions.EMPTY) {
throw new JsonParseException("Invalid potion tag '" + id + "'");
}
}
@Override
public ItemStack applyModifiers(ItemStack output, Random random) {
if (output.isEmpty()) {
output = new ItemStack(Items.POTION);
}
PotionUtil.setPotion(output, potion);
return output;
}
@Override
public boolean matches(ItemStack stack, int materialMult) {
return PotionUtil.getPotion(stack) == potion;
}
@Override
public Stream<ItemStack> getMatchingStacks() {
return Stream.empty();
}
@Override
public PredicateSerializer<?> getSerializer() {
return PredicateSerializer.ENCHANTMENT;
}
static final class Serializer implements PredicateSerializer<PotionPredicate>, PredicateSerializer.JsonReader {
@Override
public Predicate read(PacketByteBuf buf) {
return new PotionPredicate(buf.readIdentifier(), 1);
}
@Override
public void write(PacketByteBuf buf, PotionPredicate predicate) {
buf.writeIdentifier(Registry.POTION.getId(predicate.potion));
}
@Override
public Predicate read(JsonObject json) {
if (!json.has("potion")) {
return Predicate.EMPTY;
}
JsonElement e = json.get("potion");
if (e.isJsonObject()) {
JsonObject o = e.getAsJsonObject();
return new PotionPredicate(Utils.getIdentifier(o, "id"), Math.max(1, JsonHelper.getInt(o, "level", 1)));
}
return new PotionPredicate(Utils.asIdentifier(e), 1);
}
}
}

View file

@ -0,0 +1,46 @@
package com.minelittlepony.unicopia.recipe.ingredient;
import java.util.Random;
import java.util.stream.Stream;
import net.minecraft.item.ItemStack;
import net.minecraft.util.PacketByteBuf;
public interface Predicate {
Predicate EMPTY = new Predicate() {
@Override
public Stream<ItemStack> getMatchingStacks() {
return Stream.empty();
}
@Override
public boolean matches(ItemStack stack, int materialMult) {
return true;
}
@Override
public PredicateSerializer<? super Predicate> getSerializer() {
return PredicateSerializer.EMPTY;
}
};
Stream<ItemStack> getMatchingStacks();
boolean matches(ItemStack stack, int materialMult);
PredicateSerializer<?> getSerializer();
default ItemStack applyModifiers(ItemStack output, Random random) {
return output;
}
default void write(PacketByteBuf buf) {
@SuppressWarnings("unchecked")
PredicateSerializer<Predicate> serializer = (PredicateSerializer<Predicate>)getSerializer();
buf.writeIdentifier(PredicateSerializer.REGISTRY.getId(serializer));
serializer.write(buf, this);
}
static Predicate read(PacketByteBuf buf) {
return PredicateSerializer.REGISTRY.get(buf.readIdentifier()).read(buf);
}
}

View file

@ -0,0 +1,49 @@
package com.minelittlepony.unicopia.recipe.ingredient;
import com.google.gson.JsonObject;
import net.minecraft.util.Identifier;
import net.minecraft.util.PacketByteBuf;
import net.minecraft.util.registry.Registry;
import net.minecraft.util.registry.SimpleRegistry;
public interface PredicateSerializer<T extends Predicate> {
Registry<PredicateSerializer<?>> REGISTRY = new SimpleRegistry<>();
Registry<JsonReader> JSON_READERS = new SimpleRegistry<>();
PredicateSerializer<Predicate> EMPTY = register("empty", new PredicateSerializer<Predicate>() {
@Override
public Predicate read(PacketByteBuf buf) {
return Predicate.EMPTY;
}
@Override
public void write(PacketByteBuf buf, Predicate predicate) {
}
});
PredicateSerializer<StackPredicate> STACK = register("stack", new StackPredicate.Serializer());
PredicateSerializer<TagPredicate> TAG = register("tag", new TagPredicate.Serializer());
PredicateSerializer<ChoicePredicate> CHOICE = register("choice", new ChoicePredicate.Serializer());
PredicateSerializer<SpellPredicate> SPELL = register("spell", new SpellPredicate.Serializer());
PredicateSerializer<EnchantmentPredicate> ENCHANTMENT = register("enchantment", new EnchantmentPredicate.Serializer());
PredicateSerializer<PotionPredicate> POTION = register("potion", new PotionPredicate.Serializer());
PredicateSerializer<DamagePredicate> DAMAGE = register("damage", new DamagePredicate.Serializer());
PredicateSerializer<ToxicityPredicate> TOXICITY = register("toxicity", new ToxicityPredicate.Serializer());
static <T extends Predicate> PredicateSerializer<T> register(String name, PredicateSerializer<T> entry) {
Identifier id = new Identifier("unicopia", name);
if (entry instanceof JsonReader) {
Registry.register(JSON_READERS, id, (JsonReader)entry);
}
return Registry.register(REGISTRY, id, entry);
}
Predicate read(PacketByteBuf buf);
void write(PacketByteBuf buf, T predicate);
@FunctionalInterface
interface JsonReader {
Predicate read(JsonObject json);
}
}

View file

@ -0,0 +1,123 @@
package com.minelittlepony.unicopia.recipe.ingredient;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.annotation.concurrent.Immutable;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.minelittlepony.unicopia.recipe.Utils;
import net.minecraft.item.ItemStack;
import net.minecraft.recipe.Ingredient;
import net.minecraft.util.DefaultedList;
import net.minecraft.util.Lazy;
import net.minecraft.util.PacketByteBuf;
@Immutable
public class PredicatedIngredient {
public static final PredicatedIngredient EMPTY = new PredicatedIngredient(DefaultedList.of());
private final DefaultedList<Predicate> predicates;
private final Lazy<List<ItemStack>> matchingStacks;
private final Lazy<net.minecraft.recipe.Ingredient> preview;
PredicatedIngredient(DefaultedList<Predicate> predicates) {
this.predicates = predicates;
this.matchingStacks = new Lazy<>(() -> {
return this.predicates.stream()
.flatMap(Predicate::getMatchingStacks)
.filter(s -> matches(s, 1))
.collect(Collectors.toList());
});
this.preview = new Lazy<>(() -> {
return net.minecraft.recipe.Ingredient.ofStacks(getMatchingStacks().toArray(ItemStack[]::new));
});
}
public Stream<ItemStack> getMatchingStacks() {
return matchingStacks.get().stream();
}
public net.minecraft.recipe.Ingredient getPreview() {
return preview.get();
}
public ItemStack getStack(Random random) {
ItemStack[] output = new ItemStack[] { ItemStack.EMPTY.copy() };
predicates.forEach(p -> output[0] = p.applyModifiers(output[0], random));
return output[0];
}
public boolean matches(ItemStack other, int materialMult) {
return predicates.stream().allMatch(p -> p.matches(other, materialMult));
}
public void write(PacketByteBuf buf) {
Utils.write(buf, predicates, Predicate::write);
}
public static PredicatedIngredient read(PacketByteBuf buf) {
return new PredicatedIngredient(Utils.read(buf, Predicate.EMPTY, Predicate::read));
}
public static PredicatedIngredient one(JsonElement json) {
if (json.isJsonArray()) {
return new PredicatedIngredient(DefaultedList.copyOf(Predicate.EMPTY, ChoicePredicate.read(json.getAsJsonArray())));
}
JsonObject obj = json.getAsJsonObject();
Predicate primary = StackPredicate.read(obj);
Predicate secondary = TagPredicate.read(obj);
if (primary != Predicate.EMPTY && secondary != Predicate.EMPTY) {
throw new JsonParseException("Invalid ingredient. Cannot have both an item and a tag requirement.");
}
if (primary == secondary) {
throw new JsonParseException("Invalid ingredient. Must have either an item or tag requirement.");
}
DefaultedList<Predicate> predicates = DefaultedList.of();
predicates.add(primary);
predicates.add(secondary);
PredicateSerializer.JSON_READERS.stream()
.map(reader -> reader.read(obj))
.filter(i -> i != Predicate.EMPTY)
.forEach(predicates::add);
return new PredicatedIngredient(predicates);
}
public static DefaultedList<PredicatedIngredient> many(JsonArray arr) {
if (arr.size() == 0) {
throw new JsonParseException("Recipe cannot have 0 ingredients");
}
DefaultedList<PredicatedIngredient> ingredients = DefaultedList.ofSize(arr.size(), EMPTY);
for (int i = 0; i < arr.size(); i++) {
ingredients.set(i, one(arr.get(i)));
}
return ingredients;
}
public static DefaultedList<Ingredient> preview(DefaultedList<PredicatedIngredient> input) {
return preview(input, DefaultedList.of());
}
public static DefaultedList<Ingredient> preview(DefaultedList<PredicatedIngredient> input, DefaultedList<Ingredient> output) {
input.stream().map(PredicatedIngredient::getPreview).forEach(output::add);
return output;
}
}

View file

@ -4,7 +4,10 @@ import java.util.Random;
import java.util.stream.Stream;
import com.google.gson.JsonObject;
import com.minelittlepony.unicopia.item.UItems;
import com.minelittlepony.unicopia.magic.MagicEffect;
import com.minelittlepony.unicopia.magic.spell.SpellRegistry;
import com.minelittlepony.unicopia.recipe.Utils;
import net.minecraft.item.ItemStack;
import net.minecraft.util.PacketByteBuf;
@ -13,47 +16,57 @@ import net.minecraft.util.PacketByteBuf;
* A predicate that tests for a specific spell on an input when matching.
* Appends that spell to the output when crafting.
*/
class SpellPredicate implements Ingredient.Predicate {
static Ingredient.Predicate read(PacketByteBuf buf) {
int level = buf.readInt();
if (level == 0) {
return EMPTY;
}
return new SpellPredicate(buf.readString());
}
static Ingredient.Predicate read(JsonObject json) {
if (!json.has("spell")) {
return EMPTY;
}
return new SpellPredicate(json.get("spell").getAsString());
}
private final String spell;
class SpellPredicate implements Predicate {
private final MagicEffect spell;
SpellPredicate(String spell) {
this.spell = spell;
this.spell = Utils.require(SpellRegistry.instance().getSpellFromName(spell), "Unknown spell tag '" + spell + "'");
}
@Override
public ItemStack applyModifiers(ItemStack output, Random random) {
return SpellRegistry.instance().enchantStack(output, spell);
if (output.isEmpty()) {
output = new ItemStack(UItems.GEM);
}
return SpellRegistry.instance().enchantStack(output, spell.getName());
}
@Override
public boolean matches(ItemStack stack, int materialMult) {
return SpellRegistry.getKeyFromStack(stack).equals(spell);
}
@Override
public void write(PacketByteBuf buf) {
buf.writeInt(1);
buf.writeString(spell);
return SpellRegistry.getKeyFromStack(stack).equals(spell.getName());
}
@Override
public Stream<ItemStack> getMatchingStacks() {
return Stream.empty();
}
@Override
public PredicateSerializer<?> getSerializer() {
return PredicateSerializer.SPELL;
}
static final class Serializer implements PredicateSerializer<SpellPredicate>, PredicateSerializer.JsonReader {
@Override
public Predicate read(PacketByteBuf buf) {
int level = buf.readInt();
if (level == 0) {
return SpellPredicate.EMPTY;
}
return new SpellPredicate(buf.readString());
}
@Override
public void write(PacketByteBuf buf, SpellPredicate predicate) {
buf.writeString(predicate.spell.getName());
}
@Override
public Predicate read(JsonObject json) {
if (!json.has("spell")) {
return SpellPredicate.EMPTY;
}
return new SpellPredicate(json.get("spell").getAsString());
}
}
}

View file

@ -6,12 +6,14 @@ import java.util.stream.Stream;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonSyntaxException;
import com.minelittlepony.unicopia.recipe.Utils;
import net.minecraft.item.Item;
import net.minecraft.item.ItemGroup;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.util.DefaultedList;
import net.minecraft.util.Identifier;
import net.minecraft.util.JsonHelper;
import net.minecraft.util.PacketByteBuf;
import net.minecraft.util.registry.Registry;
@ -19,26 +21,8 @@ import net.minecraft.util.registry.Registry;
* Tests for a specific item, stack size, and damage value when matching.
* Presents that item as the output when crafting.
*/
class StackPredicate implements Ingredient.Predicate {
static Ingredient.Predicate read(PacketByteBuf buf) {
int count = buf.readInt();
if (count == 0) {
return EMPTY;
}
if (count > 0) {
return new StackPredicate(buf.readItemStack());
}
DefaultedList<Ingredient> items = DefaultedList.copyOf(Ingredient.EMPTY);
while (items.size() < count) {
items.add(Ingredient.read(buf));
}
return new ChoicePredicate(items);
}
static Ingredient.Predicate read(JsonObject json) {
class StackPredicate implements Predicate {
static Predicate read(JsonObject json) {
if (!json.has("item")) {
return EMPTY;
}
@ -49,15 +33,16 @@ class StackPredicate implements Ingredient.Predicate {
return ChoicePredicate.read(e.getAsJsonArray());
}
int count = Math.max(1, JsonHelper.getInt(json, "count", 1));
if (e.isJsonObject()) {
JsonObject o = e.getAsJsonObject();
Item item = o.has("item") ? Registry.ITEM.get(new Identifier(o.get("item").getAsString())) : Items.AIR;
int size = o.has("count") ? Math.max(1, o.get("count").getAsInt()) : 1;
return new StackPredicate(new ItemStack(item, size));
Item item = o.has("item") ? Registry.ITEM.get(Utils.getIdentifier(o, "item")) : Items.AIR;
return new StackPredicate(new ItemStack(item, count));
}
return new StackPredicate(new ItemStack(Registry.ITEM.get(new Identifier(e.getAsString()))));
return new StackPredicate(new ItemStack(Registry.ITEM.get(Utils.asIdentifier(e)), count));
}
private final ItemStack stack;
@ -101,8 +86,20 @@ class StackPredicate implements Ingredient.Predicate {
}
@Override
public void write(PacketByteBuf buf) {
buf.writeInt(-1);
buf.writeItemStack(stack);
public PredicateSerializer<?> getSerializer() {
return PredicateSerializer.STACK;
}
static final class Serializer implements PredicateSerializer<StackPredicate> {
@Override
public Predicate read(PacketByteBuf buf) {
return new StackPredicate(buf.readItemStack());
}
@Override
public void write(PacketByteBuf buf, StackPredicate predicate) {
buf.writeItemStack(predicate.stack);
}
}
}

View file

@ -5,57 +5,41 @@ import java.util.stream.Stream;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonSyntaxException;
import com.minelittlepony.unicopia.recipe.Utils;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.tag.ItemTags;
import net.minecraft.tag.Tag;
import net.minecraft.util.Identifier;
import net.minecraft.util.JsonHelper;
import net.minecraft.util.PacketByteBuf;
/**
* Tests for whether a tag contains the input when matching.
* Supplies a random item from the tag as the output when crafting.
*/
class TagPredicate implements Ingredient.Predicate {
static Ingredient.Predicate read(PacketByteBuf buf) {
int count = buf.readInt();
if (count == 0) {
return EMPTY;
}
return new TagPredicate(buf.readIdentifier(), count);
}
static Ingredient.Predicate read(JsonObject json) {
class TagPredicate implements Predicate {
static Predicate read(JsonObject json) {
if (!json.has("tag")) {
return EMPTY;
return Predicate.EMPTY;
}
JsonElement e = json.get("tag");
if (e.isJsonObject()) {
JsonObject o = e.getAsJsonObject();
Identifier id = new Identifier(o.get("id").getAsString());
int count = o.has("count") ? Math.max(1, o.get("count").getAsInt()) : 1;
if (count == 0) {
return EMPTY;
}
return new TagPredicate(id, count);
return new TagPredicate(Utils.getIdentifier(o, "id"), Math.max(1, JsonHelper.getInt(o, "count", 1)));
}
return new TagPredicate(new Identifier(json.getAsString()), 1);
return new TagPredicate(Utils.asIdentifier(e), 1);
}
private final Tag<Item> tag;
private final int count;
TagPredicate(Identifier res, int count) {
tag = ItemTags.getContainer().get(res);
tag = Utils.require(ItemTags.getContainer().get(res), "Unknown item tag '" + res + "'");
this.count = count;
if (tag == null) {
throw new JsonSyntaxException("Unknown item tag '" + res + "'");
}
}
@Override
@ -80,4 +64,26 @@ class TagPredicate implements Ingredient.Predicate {
buf.writeInt(count);
buf.writeIdentifier(tag.getId());
}
@Override
public PredicateSerializer<?> getSerializer() {
return PredicateSerializer.TAG;
}
static final class Serializer implements PredicateSerializer<TagPredicate> {
@Override
public Predicate read(PacketByteBuf buf) {
int count = buf.readInt();
if (count == 0) {
return Predicate.EMPTY;
}
return new TagPredicate(buf.readIdentifier(), count);
}
@Override
public void write(PacketByteBuf buf, TagPredicate predicate) {
buf.writeInt(predicate.count);
buf.writeIdentifier(predicate.tag.getId());
}
}
}

View file

@ -5,35 +5,21 @@ import java.util.stream.Stream;
import com.google.gson.JsonObject;
import com.minelittlepony.unicopia.toxin.Toxicity;
import com.minelittlepony.unicopia.recipe.Utils;
import net.minecraft.item.ItemStack;
import net.minecraft.util.JsonHelper;
import net.minecraft.util.PacketByteBuf;
/**
* A predicate that tests for a specific spell on an input when matching.
* Appends that spell to the output when crafting.
*/
class ToxicityPredicate implements Ingredient.Predicate {
static Ingredient.Predicate read(PacketByteBuf buf) {
int ordinal = buf.readInt();
if (ordinal == 0) {
return EMPTY;
}
return new ToxicityPredicate(Toxicity.values()[ordinal - 1]);
}
static Ingredient.Predicate read(JsonObject json) {
if (!json.has("toxicity")) {
return EMPTY;
}
return new ToxicityPredicate(Toxicity.byName(json.get("toxicity").getAsString()));
}
class ToxicityPredicate implements Predicate {
private final Toxicity toxicity;
ToxicityPredicate(Toxicity toxicity) {
this.toxicity = toxicity;
ToxicityPredicate(String name) {
this.toxicity = Utils.require(Toxicity.byName(name), "Unknown toxicity tag '" + name + "'");
}
@Override
@ -46,13 +32,37 @@ class ToxicityPredicate implements Ingredient.Predicate {
return Toxicity.fromStack(stack) == toxicity;
}
@Override
public void write(PacketByteBuf buf) {
buf.writeInt(toxicity.ordinal() + 1);
}
@Override
public Stream<ItemStack> getMatchingStacks() {
return Stream.empty();
}
@Override
public PredicateSerializer<?> getSerializer() {
return PredicateSerializer.TOXICITY;
}
public static final class Serializer implements PredicateSerializer<ToxicityPredicate>, PredicateSerializer.JsonReader {
@Override
public Predicate read(PacketByteBuf buf) {
return new ToxicityPredicate(Toxicity.values()[buf.readInt()].name());
}
@Override
public void write(PacketByteBuf buf, ToxicityPredicate predicate) {
buf.writeInt(predicate.toxicity.ordinal());
}
@Override
public Predicate read(JsonObject json) {
if (!json.has("toxicity")) {
return Predicate.EMPTY;
}
return new ToxicityPredicate(JsonHelper.getString(json, "toxicity"));
}
}
}

View file

@ -81,13 +81,13 @@ public enum Toxicity implements Toxin {
if (stack.hasTag()) {
Tag tag = stack.getTag().get("toxicity");
if (tag != null) {
return byName(tag.asString());
return REGISTRY.getOrDefault(tag.asString(), SAFE);
}
}
return SAFE;
}
public static Toxicity byName(String name) {
return REGISTRY.getOrDefault(name.toUpperCase(), SAFE);
return REGISTRY.get(name.toUpperCase());
}
}

View file

@ -10,7 +10,7 @@
{ "item": "unicopia:sugar_block" }
],
"*": [
{ "item": "unicopia:crereal" }
{ "item": "unicopia:cereal" }
]
},
"result": { "item": "unicopia:boop_o_roops" }

View file

@ -7,7 +7,7 @@
],
"key": {
"#": [
{ "item": "unicopia:chitin_block" }
{ "item": "unicopia:chitin_shell_block" }
]
},
"result": { "item": "unicopia:chiseled_chitin_shell_block", "count": 4 }

View file

@ -10,5 +10,5 @@
{ "item": "unicopia:cloud_block" }
]
},
"result": { "item": "unicopia:anvil", "data": 0, "count": 1 }
"result": { "item": "unicopia:cloud_anvil", "count": 1 }
}

View file

@ -1,5 +1,5 @@
{
"type": "minecraft:crafting_shaped",
"type": "unicopia:crafting_shaped",
"pattern": [
" B ",
"FFF",
@ -10,15 +10,8 @@
{ "item": "minecraft:bread" }
],
"F": [
{ "item": "minecraft:red_flower", "data": 1 },
{ "item": "minecraft:red_flower", "data": 2 },
{ "item": "minecraft:red_flower", "data": 3 },
{ "item": "minecraft:red_flower", "data": 4 },
{ "item": "minecraft:red_flower", "data": 5 },
{ "item": "minecraft:red_flower", "data": 6 },
{ "item": "minecraft:red_flower", "data": 7 },
{ "item": "minecraft:yellow_flower", "data": 0 }
{ "tag": "unicopia:non_toxic" }
]
},
"result": { "item": "unicopia:daffodil_daisy_sandwich", "data": 0, "count": 2 }
"result": { "item": "unicopia:daffodil_daisy_sandwich", "tocicity": "safe", "count": 2 }
}

View file

@ -1,5 +1,5 @@
{
"type": "minecraft:crafting_shaped",
"type": "unicopia:crafting_shaped",
"pattern": [
" B ",
"FFF",
@ -10,17 +10,9 @@
{ "item": "minecraft:bread" }
],
"F": [
{ "item": "minecraft:red_flower", "data": 0 },
{ "item": "minecraft:red_flower", "data": 1 },
{ "item": "minecraft:red_flower", "data": 2 },
{ "item": "minecraft:red_flower", "data": 3 },
{ "item": "minecraft:red_flower", "data": 4 },
{ "item": "minecraft:red_flower", "data": 5 },
{ "item": "minecraft:red_flower", "data": 6 },
{ "item": "minecraft:red_flower", "data": 7 },
{ "item": "minecraft:red_flower", "data": 8 },
{ "item": "minecraft:yellow_flower", "data": 0 }
{ "tag": "unicopia:non_toxic" },
{ "tag": "unicopia:fairly_toxic" }
]
},
"result": { "item": "unicopia:daffodil_daisy_sandwich", "data": 2, "count": 2 }
"result": { "item": "unicopia:daffodil_daisy_sandwich", "toxicity": "fair", "count": 2 }
}

View file

@ -1,5 +1,6 @@
{
"type": "unicopia:shapeless_crafting_spell",
"type": "unicopia:enchanting_spell",
"input": { "item": "unicopia:corrupted_gem" },
"ingredients": [
{ "item": "unicopia:gem", "spell": "inferno" },
{ "item": "unicopia:gem", "spell": "darkness" },

View file

@ -2,9 +2,9 @@
"type": "unicopia:enchanting_spell",
"input": { "item": "unicopia:gem" },
"ingredients": [
{ "tag": "#unicopia:unaligned" },
{ "tag": "#unicopia:unaligned" },
{ "tag": "#unicopia:unaligned" }
{ "tag": "unicopia:harmonic_elementals" },
{ "tag": "unicopia:harmonic_elementals" },
{ "tag": "unicopia:harmonic_elementals" }
],
"result": {
"item": [

View file

@ -2,9 +2,9 @@
"type": "unicopia:enchanting_spell",
"input": { "item": "unicopia:gem" },
"ingredients": [
{ "tag": "unicopia:magic_energetic" },
{ "tag": "unicopia:knowledge_elementals" },
{ "item": "unicopia:gem", "spell": "fire" },
{ "tag": "unicopia:magic_firey" }
{ "tag": "unicopia:fire_elementals" }
],
"result": { "item": "unicopia:gem", "spell": "charge" }
}

View file

@ -4,8 +4,8 @@
"ingredients": [
{ "item": "unicopia:gem", "spell": "charge" },
{ "item": "unicopia:corrupted_gem" },
{ "tag": "unicopia:life" },
{ "item": "minecraft:red_flower", "data": 0 }
{ "tag": "unicopia:life_elementals" },
{ "item": "minecraft:poppy" }
],
"result": { "item": "unicopia:gem", "spell": "drake" }
}

View file

@ -3,8 +3,8 @@
"input": { "item": "unicopia:gem" },
"ingredients": [
{ "item": "unicopia:gem", "spell": "flame" },
{ "tag": "unicopia:fire" },
{ "tag": "unicopia:fire" }
{ "tag": "unicopia:fire_elementals" },
{ "tag": "unicopia:fire_elementals" }
],
"result": { "item": "unicopia:gem", "spell": "fire" }
}

View file

@ -2,9 +2,9 @@
"type": "unicopia:enchanting_spell",
"input": { "item": "unicopia:gem" },
"ingredients": [
{ "tag": "unicopia:fire" },
{ "tag": "unicopia:fire" },
{ "tag": "unicopia:fire" }
{ "tag": "unicopia:fire_elementals" },
{ "tag": "unicopia:fire_elementals" },
{ "tag": "unicopia:fire_elementals" }
],
"result": { "item": "unicopia:gem", "spell": "fire" }
}

View file

@ -2,9 +2,9 @@
"type": "unicopia:enchanting_spell",
"input": { "item": "unicopia:gem" },
"ingredients": [
{ "tag": "unicopia:ice" },
{ "tag": "unicopia:ice" },
{ "tag": "unicopia:ice" }
{ "tag": "unicopia:ice_elementals" },
{ "tag": "unicopia:ice_elementals" },
{ "tag": "unicopia:ice_elementals" }
],
"result": { "item": "unicopia:gem", "spell": "ice" }
}

View file

@ -3,8 +3,8 @@
"input": { "item": "unicopia:gem" },
"ingredients": [
{ "item": "unicopia:gem", "spell": "fire" },
{ "tag": "unicopia:fire" },
{ "tag": "unicopia:fire" }
{ "tag": "unicopia:fire_elementals" },
{ "tag": "unicopia:fire_elementals" }
],
"result": { "item": "unicopia:corrupted_gem", "spell": "inferno" }
}

View file

@ -2,14 +2,9 @@
"type": "unicopia:enchanting_spell",
"input": { "item": "unicopia:gem" },
"ingredients": [
{ "tag": "unicopia:light" },
{ "tag": "unicopia:light_elementals" },
{ "item": "unicopia:gem", "spell": "fire" },
[
{ "item": "minecraft:apple" },
{ "item": "unicopia:apple_green" },
{ "item": "unicopia:apple_sweet" },
{ "item": "unicopia:apple_sour" }
]
{ "tag": "unicopia:fresh_apples" }
],
"result": { "item": "unicopia:gem", "spell": "light" }
}

View file

@ -1,12 +1,12 @@
{
"type": "unicopia:enchanting_spell",
"input": { "tag": "unicopia:sound"},
"input": { "tag": "unicopia:sound_elementals"},
"ingredients": [
{ "tag": "unicopia:apple_bloom" },
{ "tag": "unicopia:scootaloo" },
{ "tag": "unicopia:sweetie_belle" }
{ "tag": "unicopia:apple_bloom_spirit" },
{ "tag": "unicopia:scootaloo_spirit" },
{ "tag": "unicopia:sweetie_belle_spirit" }
],
"output": {
"result": {
"item": "unicopia:music_disc_crusade"
}
}

View file

@ -1,12 +1,12 @@
{
"type": "unicopia:enchanting_spell",
"input": { "tag": "unicopia:sound"},
"input": { "tag": "unicopia:sound_elementals"},
"ingredients": [
{ "item": "minecraft:diamond" },
{ "item": "minecraft:diamond" },
{ "item": "unicopia:boop_o_roops" }
],
"output": {
"result": {
"item": "unicopia:music_disc_funk"
}
}

View file

@ -1,12 +1,12 @@
{
"type": "unicopia:enchanting_spell",
"input": { "tag": "unicopia:sound"},
"input": { "tag": "unicopia:sound_elementals"},
"ingredients": [
{ "item": "unicopia:gem", "spell": "awkward" },
{ "item": "minecraft:feather" },
{ "item": "minecraft:carrot" }
],
"output": {
"result": {
"item": "unicopia:music_disc_pet"
}
}

View file

@ -1,12 +1,12 @@
{
"type": "unicopia:enchanting_spell",
"input": { "tag": "unicopia:sound"},
"input": { "tag": "unicopia:sound_elementals"},
"ingredients": [
{ "item": "minecraft:diamond" },
{ "item": "minecraft:diamond" },
{ "item": "minecraft:diamond" }
],
"output": {
"result": {
"item": "unicopia:music_disc_popular"
}
}

View file

@ -1,12 +1,12 @@
{
"type": "unicopia:enchanting_spell",
"input": { "tag": "unicopia:sound"},
"input": { "tag": "unicopia:sound_elementals"},
"ingredients": [
{ "item": "unicopia:gem", "spell": "awkward" },
{ "item": "unicopia:gem", "spell": "awkward" },
{ "item": "unicopia:gem", "spell": "awkward" }
],
"output": {
"tag": "unicopia:sound"
"result": {
"tag": "unicopia:sound_elementals"
}
}

View file

@ -2,12 +2,9 @@
"type": "unicopia:enchanting_spell",
"input": { "item": "unicopia:gem" },
"ingredients": [
{ "tag": "unicopia:blood" },
{ "tag": "unicopia:energy" },
{ "tag": "unicopia:rot" }
{ "tag": "unicopia:death_elementals" },
{ "tag": "unicopia:knowledge_elementals" },
{ "tag": "unicopia:rotting_elementals" }
],
"result": {
"item": "unicopia:corrupted_gem",
"spell": "necromancy"
}
"result": { "item": "unicopia:corrupted_gem", "spell": "necromancy" }
}

View file

@ -2,8 +2,8 @@
"type": "unicopia:enchanting_spell",
"input": { "item": "unicopia:gem" },
"ingredients": [
{ "tag": "unicopia:energy" },
{ "tag": "unicopia:life" },
{ "tag": "unicopia:knowledge_elementals" },
{ "tag": "unicopia:life_elementals" },
{ "item": "unicopia:gem", "spell": "charge" }
],
"result": { "item": "unicopia:gem", "spell": "siphon" }

View file

@ -2,9 +2,9 @@
"type": "unicopia:enchanting_spell",
"input": { "item": "unicopia:gem" },
"ingredients": [
{ "tag": "unicopia:sight" },
{ "tag": "unicopia:sight_elementals" },
{ "item": "minecraft:ghast_tear" },
{ "tag": "unicopia:energy" },
{ "tag": "unicopia:knowledge_elementals" },
{ "item": "unicopia:gem", "spell": "fire" }
],
"result": { "item": "unicopia:gem", "spell": "portal" }

View file

@ -2,10 +2,10 @@
"type": "unicopia:enchanting_spell",
"input": { "item": "unicopia:gem" },
"ingredients": [
{ "tag": "unicopia:fire" },
{ "tag": "unicopia:shell" },
{ "tag": "unicopia:fire_elementals" },
{ "tag": "unicopia:shells" },
{ "item": "unicopia:gem", "spell": "shield" },
{ "tag": "unicopia:shell" }
{ "tag": "unicopia:shells" }
],
"result": {
"item": "unicopia:corrupted_gem",

View file

@ -2,9 +2,9 @@
"type": "unicopia:enchanting_spell",
"input": { "item": "unicopia:gem" },
"ingredients": [
{ "id": "unicopia:shell" },
{ "id": "unicopia:shell" },
{ "id": "unicopia:shard" }
{ "tag": "unicopia:shells" },
{ "tag": "unicopia:shells" },
{ "tag": "unicopia:shards" }
],
"result": { "item": "unicopia:gem", "spell": "shield" }
}

View file

@ -2,9 +2,9 @@
"type": "unicopia:enchanting_spell",
"input": { "item": "unicopia:gem" },
"ingredients": [
{ "id": "unicopia:energy" },
{ "id": "unicopia:life" },
{ "id": "unicopia:dark" },
{ "tag": "unicopia:knowledge_elementals" },
{ "tag": "unicopia:life_elementals" },
{ "tag": "unicopia:dark_elementals" },
{ "item": "unicopia:gem", "spell": "siphon" }
],
"result": { "item": "unicopia:corrupted_gem", "spell": "siphon" }

View file

@ -3,7 +3,7 @@
"input": { "item": "unicopia:gem" },
"ingredients": [
{ "item": "minecraft:fire_charge" },
{ "tag": "unicopia:blood" },
{ "tag": "unicopia:death_elementals" },
{ "item": "unicopia:gem", "spell": "fire" }
],
"result": { "item": "unicopia:corrupted_gem", "spell": "vortex" }

View file

@ -2,7 +2,7 @@
"type": "unicopia:enchanting_spell",
"input": { "item": "unicopia:gem" },
"ingredients": [
{ "tag": "unicopia:shell" },
{ "tag": "unicopia:shells" },
{ "item": "unicopia:gem", "spell": "shield" },
{ "item": "unicopia:gem", "spell": "portal" }
],

View file

@ -10,7 +10,22 @@
{ "item": "minecraft:andesite" }
],
"C": [
{ "item": "#minecraft:stained_hardened_clay" }
{ "item": "minecraft:white_concrete" },
{ "item": "minecraft:orange_concrete" },
{ "item": "minecraft:magenta_concrete" },
{ "item": "minecraft:light_blue_concrete" },
{ "item": "minecraft:yellow_concrete" },
{ "item": "minecraft:lime_concrete" },
{ "item": "minecraft:pink_concrete" },
{ "item": "minecraft:gray_concrete" },
{ "item": "minecraft:light_gray_concrete" },
{ "item": "minecraft:cyan_concrete" },
{ "item": "minecraft:purple_concrete" },
{ "item": "minecraft:blue_concrete" },
{ "item": "minecraft:brown_concrete" },
{ "item": "minecraft:green_concrete" },
{ "item": "minecraft:red_concrete" },
{ "item": "minecraft:black_concrete" }
],
"B": [
{ "item": "minecraft:black_dye" }

View file

@ -1,5 +1,5 @@
{
"type": "minecraft:crafting_shaped",
"type": "unicopia:crafting_shaped",
"pattern": [
"AAA",
"FTF",
@ -14,15 +14,8 @@
{ "item": "unicopia:cloudsdale_tomato" }
],
"F": [
{ "item": "minecraft:red_flower", "data": 1 },
{ "item": "minecraft:red_flower", "data": 2 },
{ "item": "minecraft:red_flower", "data": 3 },
{ "item": "minecraft:red_flower", "data": 4 },
{ "item": "minecraft:red_flower", "data": 5 },
{ "item": "minecraft:red_flower", "data": 6 },
{ "item": "minecraft:red_flower", "data": 7 },
{ "item": "minecraft:yellow_flower", "data": 0 }
{ "tag": "unicopia:non_toxic" }
]
},
"result": { "item": "unicopia:hay_burger" }
"result": { "item": "unicopia:hay_burger", "toxicity": "safe" }
}

View file

@ -1,5 +1,5 @@
{
"type": "minecraft:crafting_shaped",
"type": "unicopia:crafting_shaped",
"pattern": [
"AAA",
"FTF",
@ -10,23 +10,15 @@
{ "item": "unicopia:alfalfa_leaves" }
],
"T": [
{ "item": "unicopia:tomato", "data": 0 },
{ "item": "unicopia:tomato", "data": 1 },
{ "item": "unicopia:cloudsdale_tomato", "data": 0 },
{ "item": "unicopia:cloudsdale_tomato", "data": 1 }
{ "item": "unicopia:tomato" },
{ "item": "unicopia:rotten_tomato" },
{ "item": "unicopia:cloudsdale_tomato" },
{ "item": "unicopia:rotten_cloudsdale_tomato" }
],
"F": [
{ "item": "minecraft:red_flower", "data": 0 },
{ "item": "minecraft:red_flower", "data": 1 },
{ "item": "minecraft:red_flower", "data": 2 },
{ "item": "minecraft:red_flower", "data": 3 },
{ "item": "minecraft:red_flower", "data": 4 },
{ "item": "minecraft:red_flower", "data": 5 },
{ "item": "minecraft:red_flower", "data": 6 },
{ "item": "minecraft:red_flower", "data": 7 },
{ "item": "minecraft:red_flower", "data": 8 },
{ "item": "minecraft:yellow_flower", "data": 0 }
{ "tag": "unicopia:non_toxic" },
{ "tag": "unicopia:fairly_toxic" }
]
},
"result": { "item": "unicopia:hay_burger", "data": 2, "count": 1 }
"result": { "item": "unicopia:hay_burger", "toxicity": "fair", "count": 1 }
}

View file

@ -7,8 +7,8 @@
],
"key": {
"#": [
{ "item": "minecraft:stained_white_glass_block" }
{ "item": "minecraft:white_stained_glass" }
]
},
"result": { "item": "unicopia:misted_glass_door", "data": 0, "count": 1 }
"result": { "item": "unicopia:misted_glass_door", "count": 1 }
}

View file

@ -10,8 +10,8 @@
{ "item": "minecraft:bowl" }
],
"F": [
{ "tag": "#unicopia:non_toxic" },
{ "tag": "#unicopia:fairly_toxic" },
{ "tag": "unicopia:non_toxic" },
{ "tag": "unicopia:fairly_toxic" },
{ "item": "unicopia:alfalfa_leaves" }
]
},

View file

@ -13,9 +13,9 @@
{ "item": "minecraft:golden_apple", "data": 0 },
{ "item": "unicopia:zap_apple", "data": 0 },
{ "item": "unicopia:corrupted_gem" },
{ "tag": "#unicopia:non_toxic" },
{ "tag": "#unicopia:fairly_toxic" },
{ "tag": "#unicopia:severely_toxic" },
{ "tag": "unicopia:non_toxic" },
{ "tag": "unicopia:fairly_toxic" },
{ "tag": "unicopia:severely_toxic" },
{ "item": "unicopia:alfalfa_leaves" },
{ "item": "unicopia:wheat_worms" }
]

View file

@ -10,7 +10,7 @@
{ "item": "minecraft:bowl" }
],
"F": [
{ "tag": "#unicopia:non_toxic" },
{ "tag": "unicopia:non_toxic" },
{ "item": "unicopia:alfalfa_leaves" }
]
},

View file

@ -10,9 +10,9 @@
{ "item": "minecraft:bowl" }
],
"F": [
{ "tag": "#unicopia:non_toxic" },
{ "tag": "#unicopia:fairly_toxic" },
{ "tag": "#unicopia:severely_toxic" },
{ "tag": "unicopia:non_toxic" },
{ "tag": "unicopia:fairly_toxic" },
{ "tag": "unicopia:severely_toxic" },
{ "item": "unicopia:alfalfa_leaves" },
{ "item": "unicopia:wheat_worms" }
]

View file

@ -7,11 +7,11 @@
],
"key": {
"#": [
{ "item": "minecraft:slime" }
{ "item": "minecraft:slime_block" }
],
"*": [
{ "item": "unicopia:gem" }
]
},
"result": { "item": "unicopia:cuccoon", "count": 1 }
"result": { "item": "unicopia:slime_drop", "count": 1 }
}

View file

@ -5,7 +5,7 @@
],
"key": {
"#": [
{ "item": "minecraft:slime" }
{ "item": "minecraft:slime_block" }
]
},
"result": { "item": "unicopia:slime_layer", "count": 6 }

View file

@ -1,7 +1,7 @@
{
"type": "minecraft:crafting_shapeless",
"ingredients": [
{ "item": "#unicopia:fresh_tomatoes" }
{ "tag": "unicopia:fresh_tomatoes" }
],
"result": { "item": "unicopia:tomato_seeds", "count": 3 }
}

View file

@ -1,8 +1,11 @@
{
"type": "minecraft:crafting_shapeless",
"ingredients": [
{ "item": "unicopia:zap_apple", "data": 0 },
{ "item": "minecraft:dye", "data": 2 }
],
"result": { "item": "unicopia:zap_apple", "count": 1, "data": 2 }
"type": "unicopia:crafting_shapeless",
"ingredients": [
{ "item": "unicopia:zap_apple" },
{ "item": "minecraft:green_dye" }
],
"result": {
"item": "unicopia:zap_apple",
"appearance": "unicopia:green_apple"
}
}

View file

@ -1,8 +1,11 @@
{
"type": "minecraft:crafting_shapeless",
"ingredients": [
{ "item": "unicopia:zap_apple", "data": 0 },
{ "item": "minecraft:dye", "data": 1 }
],
"result": { "item": "unicopia:zap_apple", "count": 1, "data": 1 }
"type": "unicopia:crafting_shapeless",
"ingredients": [
{ "item": "unicopia:zap_apple" },
{ "item": "minecraft:red_dye" }
],
"result": {
"item": "unicopia:zap_apple",
"appearance": "minecraft:apple"
}
}

View file

@ -1,8 +1,11 @@
{
"type": "minecraft:crafting_shapeless",
"ingredients": [
{ "item": "unicopia:zap_apple", "data": 0 },
{ "item": "minecraft:dye", "data": 15 }
],
"result": { "item": "unicopia:zap_apple", "count": 1, "data": 4 }
"type": "unicopia:crafting_shapeless",
"ingredients": [
{ "item": "unicopia:zap_apple" },
{ "item": "minecraft:yellow_dye" }
],
"result": {
"item": "unicopia:zap_apple",
"appearance": "unicopia:sour_apple"
}
}

View file

@ -1,8 +1,11 @@
{
"type": "minecraft:crafting_shapeless",
"ingredients": [
{ "item": "unicopia:zap_apple", "data": 0 },
{ "item": "minecraft:dye", "data": 14 }
],
"result": { "item": "unicopia:zap_apple", "count": 1, "data": 3 }
"type": "unicopia:crafting_shapeless",
"ingredients": [
{ "item": "unicopia:zap_apple" },
{ "item": "minecraft:orange_dye" }
],
"result": {
"item": "unicopia:zap_apple",
"appearance": "unicopia:sweet_apple"
}
}

View file

@ -1,8 +1,11 @@
{
"type": "minecraft:crafting_shapeless",
"ingredients": [
{ "item": "unicopia:zap_apple", "data": 0 },
{ "item": "minecraft:rotten_flesh" }
],
"result": { "item": "unicopia:zap_apple", "count": 1, "data": 5 }
"type": "unicopia:crafting_shapeless",
"ingredients": [
{ "item": "unicopia:zap_apple" },
{ "item": "minecraft:rotten_flesh" }
],
"result": {
"item": "unicopia:zap_apple",
"appearance": "unicopia:cooked_zap_apple"
}
}

View file

@ -1,5 +1,5 @@
{
"type": "minecraft:crafting_shaped",
"type": "unicopia:crafting_shaped",
"pattern": [
"***",
" * ",
@ -15,8 +15,6 @@
},
"result": {
"item": "minecraft:potion",
"data": 0,
"count": 1,
"nbt": { "Potion": "minecraft:water" }
"potion": "minecraft:water"
}
}

View file

@ -13,5 +13,5 @@
{ "item": "unicopia:dew_drop" }
]
},
"result": { "item": "minecraft:water_bucket", "count": 1 }
"result": { "item": "minecraft:water_bucket" }
}

View file

@ -11,6 +11,6 @@
"minecraft:cornflower",
"minecraft:rose_bush",
"minecraft:peony",
"tall_grass"
"minecraft:tall_grass"
]
}

View file

@ -4,7 +4,7 @@
"minecraft:fern",
"minecraft:dead_bush",
"minecraft:poppy",
"minecraft:oxey_daisy",
"minecraft:oxeye_daisy",
"minecraft:large_fern"
]
}