mirror of
https://github.com/Sollace/Unicopia.git
synced 2024-11-24 05:47:59 +01:00
Refactor again and add recipe types for the crafting table \o/
This commit is contained in:
parent
94952f5c16
commit
e9041347e0
14 changed files with 660 additions and 116 deletions
|
@ -1,77 +0,0 @@
|
|||
package com.minelittlepony.unicopia.recipe;
|
||||
|
||||
import java.util.List;
|
||||
import com.google.common.collect.Lists;
|
||||
import net.minecraft.inventory.Inventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.recipe.Recipe;
|
||||
import net.minecraft.util.DefaultedList;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
/**
|
||||
* Basic crafting recipe that uses our custom ingredients.
|
||||
*/
|
||||
public abstract class AbstractShapelessPredicatedRecipe<C extends Inventory> implements Recipe<C> {
|
||||
|
||||
protected final Ingredient output;
|
||||
|
||||
protected final DefaultedList<Ingredient> ingredients;
|
||||
|
||||
private final Identifier id;
|
||||
|
||||
public AbstractShapelessPredicatedRecipe(Identifier id, Ingredient output, DefaultedList<Ingredient> ingredients) {
|
||||
this.id = id;
|
||||
this.output = output;
|
||||
this.ingredients = ingredients;
|
||||
}
|
||||
|
||||
protected abstract int getInputMultiplier(C inv, World worldIn);
|
||||
|
||||
@Override
|
||||
public boolean matches(C inv, World worldIn) {
|
||||
int materialMult = getInputMultiplier(inv, worldIn);
|
||||
|
||||
if (materialMult == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
List<Ingredient> toMatch = Lists.newArrayList(ingredients);
|
||||
|
||||
for (int i = 0; i < inv.getInvSize(); i++) {
|
||||
ItemStack stack = inv.getInvStack(i);
|
||||
|
||||
if (!stack.isEmpty()) {
|
||||
if (toMatch.isEmpty() || !removeMatch(toMatch, stack, materialMult)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return toMatch.isEmpty();
|
||||
}
|
||||
|
||||
private boolean removeMatch(List<Ingredient> toMatch, ItemStack stack, int materialMult) {
|
||||
return toMatch.stream()
|
||||
.filter(s -> s.matches(stack, materialMult))
|
||||
.findFirst()
|
||||
.filter(toMatch::remove)
|
||||
.isPresent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Identifier getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack craft(C inv) {
|
||||
return getOutput();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean fits(int width, int height) {
|
||||
return width * height < ingredients.size();
|
||||
}
|
||||
|
||||
}
|
220
src/main/java/com/minelittlepony/unicopia/recipe/Pattern.java
Normal file
220
src/main/java/com/minelittlepony/unicopia/recipe/Pattern.java
Normal file
|
@ -0,0 +1,220 @@
|
|||
package com.minelittlepony.unicopia.recipe;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
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 net.minecraft.inventory.CraftingInventory;
|
||||
import net.minecraft.util.DefaultedList;
|
||||
import net.minecraft.util.JsonHelper;
|
||||
import net.minecraft.util.PacketByteBuf;
|
||||
import net.minecraft.util.Util;
|
||||
|
||||
public class Pattern {
|
||||
|
||||
public static Pattern read(PacketByteBuf buf) {
|
||||
return new Pattern(
|
||||
Utils.read(buf, Ingredient.EMPTY, Ingredient::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"));
|
||||
|
||||
return new Pattern(patterns, ingredients);
|
||||
}
|
||||
|
||||
public final DefaultedList<Ingredient> matrix;
|
||||
|
||||
public final int width;
|
||||
public final int height;
|
||||
|
||||
public Pattern(DefaultedList<Ingredient> matrix, int width, int height) {
|
||||
this.matrix = matrix;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
public Pattern(String[] pattern, Map<String, Ingredient> ingredients) {
|
||||
this(pattern, ingredients, pattern[0].length(), pattern.length);
|
||||
}
|
||||
|
||||
private Pattern(String[] pattern, Map<String, Ingredient> 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)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void write(PacketByteBuf buf) {
|
||||
Utils.write(buf, matrix, Ingredient::write);
|
||||
buf.writeVarInt(width);
|
||||
buf.writeVarInt(height);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return matrix.size();
|
||||
}
|
||||
|
||||
private boolean matchesSmall(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) {
|
||||
if (reflected) {
|
||||
ingredient = matrix.get(width - k - 1 + l * this.width);
|
||||
} else {
|
||||
ingredient = matrix.get(k + l * this.width);
|
||||
}
|
||||
}
|
||||
|
||||
if (!ingredient.matches(inv.getInvStack(x + y * inv.getWidth()), 1)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
Set<String> unsolved = Sets.newHashSet(ingredients.keySet());
|
||||
unsolved.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);
|
||||
|
||||
if (ingredient == null) {
|
||||
throw new JsonSyntaxException("Pattern references symbol '" + key + "' but it's not defined in the key");
|
||||
}
|
||||
|
||||
unsolved.remove(key);
|
||||
result.set(j + width * i, ingredient);
|
||||
}
|
||||
}
|
||||
|
||||
if (!unsolved.isEmpty()) {
|
||||
throw new JsonSyntaxException("Key defines symbols that aren't used in pattern: " + unsolved);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static String[] combinePatternMatrix(String... lines) {
|
||||
int i = Integer.MAX_VALUE;
|
||||
int j = 0;
|
||||
int k = 0;
|
||||
int l = 0;
|
||||
|
||||
for(int row = 0; row < lines.length; ++row) {
|
||||
String line = lines[row];
|
||||
|
||||
i = Math.min(i, lookAhead(line));
|
||||
|
||||
int n = lookBack(line);
|
||||
|
||||
j = Math.max(j, n);
|
||||
if (n < 0) {
|
||||
if (k == row) {
|
||||
++k;
|
||||
}
|
||||
|
||||
++l;
|
||||
} else {
|
||||
l = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (lines.length == l) {
|
||||
return new String[0];
|
||||
}
|
||||
|
||||
String[] strings = new String[lines.length - l - k];
|
||||
|
||||
for(int o = 0; o < strings.length; ++o) {
|
||||
strings[o] = lines[o + k].substring(i, j + 1);
|
||||
}
|
||||
|
||||
return strings;
|
||||
}
|
||||
|
||||
private static int lookAhead(String pattern) {
|
||||
int i;
|
||||
for(i = 0; i < pattern.length() && pattern.charAt(i) == ' '; ++i) {}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
private static int lookBack(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) {
|
||||
throw new JsonSyntaxException("Invalid pattern: too many columns, 3 is maximum");
|
||||
}
|
||||
|
||||
if (i > 0 && strings[0].length() != string.length()) {
|
||||
throw new JsonSyntaxException("Invalid pattern: each row must be the same width");
|
||||
}
|
||||
|
||||
strings[i] = string;
|
||||
}
|
||||
|
||||
return strings;
|
||||
}
|
||||
}
|
||||
|
||||
static Map<String, Ingredient> readIngredients(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).");
|
||||
}
|
||||
|
||||
if (" ".equals(e.getKey())) {
|
||||
throw new JsonSyntaxException("Invalid key entry: ' ' is a reserved symbol.");
|
||||
}
|
||||
|
||||
return e.getKey();
|
||||
},
|
||||
e -> Ingredient.one(e.getValue())
|
||||
)), m -> m.put(" ", Ingredient.EMPTY));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
package com.minelittlepony.unicopia.recipe;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.minelittlepony.unicopia.recipe.ingredient.Ingredient;
|
||||
|
||||
import net.minecraft.inventory.CraftingInventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.recipe.RecipeSerializer;
|
||||
import net.minecraft.recipe.SpecialCraftingRecipe;
|
||||
import net.minecraft.util.DefaultedList;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.JsonHelper;
|
||||
import net.minecraft.util.PacketByteBuf;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public class ShapedSpecialRecipe extends SpecialCraftingRecipe {
|
||||
|
||||
private static final Random RANDOM = new Random();
|
||||
|
||||
private final Pattern pattern;
|
||||
private final Ingredient output;
|
||||
private final String group;
|
||||
|
||||
public ShapedSpecialRecipe(Identifier id, String group, Pattern pattern, Ingredient output) {
|
||||
super(id);
|
||||
this.group = group;
|
||||
this.pattern = pattern;
|
||||
this.output = output;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(CraftingInventory inv, World world) {
|
||||
return pattern.matches(inv);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack craft(CraftingInventory inv) {
|
||||
return getOutput().copy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean fits(int width, int height) {
|
||||
return width * height >= pattern.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getOutput() {
|
||||
return output.getStack(RANDOM);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGroup() {
|
||||
return this.group;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecipeSerializer<?> getSerializer() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isIgnoredInRecipeBook() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultedList<net.minecraft.recipe.Ingredient> getPreviewInputs() {
|
||||
return Ingredient.preview(pattern.matrix);
|
||||
}
|
||||
|
||||
public static class Serializer implements RecipeSerializer<ShapedSpecialRecipe> {
|
||||
@Override
|
||||
public ShapedSpecialRecipe read(Identifier id, JsonObject json) {
|
||||
return new ShapedSpecialRecipe(id,
|
||||
JsonHelper.getString(json, "group", ""),
|
||||
Pattern.read(json),
|
||||
Ingredient.one(json.get("result"))
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShapedSpecialRecipe read(Identifier id, PacketByteBuf buf) {
|
||||
return new ShapedSpecialRecipe(id,
|
||||
buf.readString(32767),
|
||||
Pattern.read(buf),
|
||||
Ingredient.read(buf)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(PacketByteBuf buf, ShapedSpecialRecipe recipe) {
|
||||
buf.writeString(recipe.group);
|
||||
recipe.pattern.write(buf);
|
||||
recipe.output.write(buf);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
package com.minelittlepony.unicopia.recipe;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.minelittlepony.unicopia.recipe.ingredient.Ingredient;
|
||||
|
||||
import net.minecraft.inventory.CraftingInventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.recipe.RecipeSerializer;
|
||||
import net.minecraft.recipe.SpecialCraftingRecipe;
|
||||
import net.minecraft.util.DefaultedList;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.JsonHelper;
|
||||
import net.minecraft.util.PacketByteBuf;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public class ShapelessSpecialRecipe extends SpecialCraftingRecipe {
|
||||
|
||||
private final String group;
|
||||
private final Ingredient output;
|
||||
|
||||
private final DefaultedList<Ingredient> input;
|
||||
|
||||
public ShapelessSpecialRecipe(Identifier id, String group, Ingredient output, DefaultedList<Ingredient> input) {
|
||||
super(id);
|
||||
this.group = group;
|
||||
this.output = output;
|
||||
this.input = input;
|
||||
|
||||
if (input.isEmpty()) {
|
||||
throw new JsonParseException("No ingredients for shapeless recipe");
|
||||
}
|
||||
if (input.size() > 9) {
|
||||
throw new JsonParseException("Too many ingredients for shapeless recipe");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(CraftingInventory inv, World world) {
|
||||
return Utils.matchShapeless(input, inv, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack craft(CraftingInventory inv) {
|
||||
return getOutput().copy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean fits(int width, int height) {
|
||||
return width * height >= input.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getOutput() {
|
||||
return output.getStack(Utils.RANDOM);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGroup() {
|
||||
return group;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecipeSerializer<?> getSerializer() {
|
||||
return URecipes.CRAFTING_SHAPELESS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultedList<net.minecraft.recipe.Ingredient> getPreviewInputs() {
|
||||
return Ingredient.preview(input);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isIgnoredInRecipeBook() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static class Serializer implements RecipeSerializer<ShapelessSpecialRecipe> {
|
||||
@Override
|
||||
public ShapelessSpecialRecipe read(Identifier identifier, JsonObject jsonObject) {
|
||||
return new ShapelessSpecialRecipe(identifier,
|
||||
JsonHelper.getString(jsonObject, "group", ""),
|
||||
Ingredient.one(jsonObject.get("output")),
|
||||
Ingredient.many(JsonHelper.getArray(jsonObject, "ingredients"))
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShapelessSpecialRecipe read(Identifier identifier, PacketByteBuf buf) {
|
||||
return new ShapelessSpecialRecipe(identifier,
|
||||
buf.readString(32767),
|
||||
Ingredient.read(buf),
|
||||
Utils.read(buf, Ingredient.EMPTY, Ingredient::read));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(PacketByteBuf buf, ShapelessSpecialRecipe recipe) {
|
||||
buf.writeString(recipe.group);
|
||||
recipe.output.write(buf);
|
||||
buf.writeVarInt(recipe.input.size());
|
||||
Utils.write(buf, recipe.input, Ingredient::write);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,52 +1,80 @@
|
|||
package com.minelittlepony.unicopia.recipe;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
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 net.minecraft.inventory.CraftingInventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.recipe.Recipe;
|
||||
import net.minecraft.recipe.RecipeSerializer;
|
||||
import net.minecraft.recipe.RecipeType;
|
||||
import net.minecraft.util.DefaultedList;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.JsonHelper;
|
||||
import net.minecraft.util.PacketByteBuf;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
/**
|
||||
* Spellbook recipe accepting an item to enchant, a number of ingredients to use, an ingredient to compose the output.
|
||||
*/
|
||||
public class SpellBookRecipe extends AbstractShapelessPredicatedRecipe<CraftingInventory> {
|
||||
public class SpellBookRecipe implements Recipe<CraftingInventory> {
|
||||
|
||||
private static final Random RANDOM = new Random();
|
||||
private final Ingredient input;
|
||||
|
||||
protected final Ingredient input;
|
||||
private final Ingredient output;
|
||||
|
||||
private final DefaultedList<Ingredient> ingredients;
|
||||
|
||||
private final Identifier id;
|
||||
|
||||
public SpellBookRecipe(Identifier id, Ingredient input, Ingredient output, DefaultedList<Ingredient> ingredients) {
|
||||
super(id, output, ingredients);
|
||||
this.id = id;
|
||||
this.output = output;
|
||||
this.ingredients = ingredients;
|
||||
this.input = input;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getInputMultiplier(CraftingInventory inv, World worldIn) {
|
||||
public boolean matches(CraftingInventory inv, World world) {
|
||||
|
||||
ItemStack enchantedStack = ((SpellBookInventory)inv).getCraftResultMatrix().getInvStack(0);
|
||||
|
||||
if (enchantedStack.isEmpty() || enchantedStack.getItem() == null) {
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!input.matches(enchantedStack, enchantedStack.getCount())) {
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
return enchantedStack.getCount();
|
||||
return Utils.matchShapeless(ingredients, inv, enchantedStack.getCount());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Identifier getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack craft(CraftingInventory inv) {
|
||||
return getOutput();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean fits(int width, int height) {
|
||||
return width * height < ingredients.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultedList<net.minecraft.recipe.Ingredient> getPreviewInputs() {
|
||||
return Ingredient.preview(ingredients, DefaultedList.copyOf(null, input.getPreview()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getOutput() {
|
||||
return output.getStack(RANDOM);
|
||||
return output.getStack(Utils.RANDOM);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -70,30 +98,24 @@ public class SpellBookRecipe extends AbstractShapelessPredicatedRecipe<CraftingI
|
|||
return new SpellBookRecipe(id,
|
||||
Ingredient.one(json.get("input")),
|
||||
Ingredient.one(json.get("result")),
|
||||
Ingredient.many(json.get("ingredients").getAsJsonArray())
|
||||
Ingredient.many(JsonHelper.getArray(json, "ingredients"))
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpellBookRecipe read(Identifier id, PacketByteBuf buf) {
|
||||
Ingredient input = Ingredient.read(buf);
|
||||
Ingredient output = Ingredient.read(buf);
|
||||
int length = buf.readInt();
|
||||
DefaultedList<Ingredient> ingredients = DefaultedList.copyOf(Ingredient.EMPTY);
|
||||
while (ingredients.size() < length) {
|
||||
ingredients.add(Ingredient.read(buf));
|
||||
}
|
||||
|
||||
return new SpellBookRecipe(id, input, output, ingredients);
|
||||
return new SpellBookRecipe(id,
|
||||
Ingredient.read(buf),
|
||||
Ingredient.read(buf),
|
||||
Utils.read(buf, Ingredient.EMPTY, Ingredient::read)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(PacketByteBuf buf, SpellBookRecipe recipe) {
|
||||
recipe.input.write(buf);
|
||||
recipe.output.write(buf);
|
||||
DefaultedList<Ingredient> ingredients = recipe.ingredients;
|
||||
buf.writeInt(ingredients.size());
|
||||
ingredients.forEach(i -> i.write(buf));
|
||||
Utils.write(buf, recipe.ingredients, Ingredient::write);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,7 +10,8 @@ public interface URecipes {
|
|||
RecipeType<SpellBookRecipe> SPELL_BOOK = register("spell_book");
|
||||
|
||||
RecipeSerializer<SpellBookRecipe> ENCHANTING_SPELL_SERIALIZER = register("enchanting_spell", new SpellBookRecipe.Serializer());
|
||||
RecipeSerializer<SpellBookRecipe> CRAFTING_SPELL_SERIALIZER = register("crafting_spell", new SpellBookRecipe.Serializer());
|
||||
RecipeSerializer<ShapelessSpecialRecipe> CRAFTING_SHAPELESS = register("crafting_shapeless", new ShapelessSpecialRecipe.Serializer());
|
||||
RecipeSerializer<ShapedSpecialRecipe> CRAFTING_SHAPED = register("crafting_shaped", new ShapedSpecialRecipe.Serializer());
|
||||
|
||||
static <T extends Recipe<?>> RecipeType<T> register(final String id) {
|
||||
return Registry.register(Registry.RECIPE_TYPE, new Identifier("unicopia", id), new RecipeType<T>() {
|
||||
|
|
62
src/main/java/com/minelittlepony/unicopia/recipe/Utils.java
Normal file
62
src/main/java/com/minelittlepony/unicopia/recipe/Utils.java
Normal file
|
@ -0,0 +1,62 @@
|
|||
package com.minelittlepony.unicopia.recipe;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.minelittlepony.unicopia.recipe.ingredient.Ingredient;
|
||||
|
||||
import net.minecraft.inventory.Inventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.DefaultedList;
|
||||
import net.minecraft.util.PacketByteBuf;
|
||||
|
||||
public class Utils {
|
||||
|
||||
static final Random RANDOM = new Random();
|
||||
|
||||
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));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
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 <C extends Inventory> boolean matchShapeless(DefaultedList<Ingredient> ingredients, C inv, int mult) {
|
||||
if (mult == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
List<Ingredient> toMatch = Lists.newArrayList(ingredients);
|
||||
|
||||
for (int i = 0; i < inv.getInvSize(); i++) {
|
||||
ItemStack stack = inv.getInvStack(i);
|
||||
|
||||
if (!stack.isEmpty()) {
|
||||
if (toMatch.isEmpty() || !removeMatch(toMatch, stack, mult)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return toMatch.isEmpty();
|
||||
}
|
||||
|
||||
private static boolean removeMatch(List<Ingredient> toMatch, ItemStack stack, int materialMult) {
|
||||
return toMatch.stream()
|
||||
.filter(s -> s.matches(stack, materialMult))
|
||||
.findFirst()
|
||||
.filter(toMatch::remove)
|
||||
.isPresent();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package com.minelittlepony.unicopia.recipe;
|
||||
package com.minelittlepony.unicopia.recipe.ingredient;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
@ -8,8 +8,11 @@ import com.google.gson.JsonArray;
|
|||
import net.minecraft.item.ItemStack;
|
||||
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));
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
package com.minelittlepony.unicopia.recipe.ingredient;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.function.BiPredicate;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
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);
|
||||
map.put("<", (a, b) -> a < b);
|
||||
map.put("<=", (a, b) -> a <= b);
|
||||
map.put(">", (a, b) -> a > b);
|
||||
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;
|
||||
|
||||
DamagePredicate(int damage, String op) {
|
||||
this.op = op.trim();
|
||||
this.damage = damage;
|
||||
this.operation = new Lazy<>(() -> OPERATIONS.get(op));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack applyModifiers(ItemStack output, Random random) {
|
||||
output.setDamage(damage);
|
||||
return output;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<ItemStack> getMatchingStacks() {
|
||||
return Stream.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(ItemStack other, int materialMult) {
|
||||
return !other.isEmpty() && operation.get().test(other.getDamage(), damage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(PacketByteBuf buf) {
|
||||
buf.writeInt(1);
|
||||
buf.writeInt(damage);
|
||||
buf.writeString(op);
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package com.minelittlepony.unicopia.recipe;
|
||||
package com.minelittlepony.unicopia.recipe.ingredient;
|
||||
|
||||
import java.util.Random;
|
||||
import java.util.stream.Stream;
|
||||
|
@ -15,10 +15,10 @@ import net.minecraft.util.PacketByteBuf;
|
|||
import net.minecraft.util.registry.Registry;
|
||||
|
||||
/**
|
||||
* A predicate that tests for a specific enchantment on an input item.
|
||||
* 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) {
|
|
@ -1,4 +1,4 @@
|
|||
package com.minelittlepony.unicopia.recipe;
|
||||
package com.minelittlepony.unicopia.recipe.ingredient;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
@ -18,7 +18,7 @@ import net.minecraft.util.Lazy;
|
|||
import net.minecraft.util.PacketByteBuf;
|
||||
|
||||
@Immutable
|
||||
class Ingredient {
|
||||
public class Ingredient {
|
||||
public static final Ingredient EMPTY = new Ingredient(Predicate.EMPTY, Predicate.EMPTY, Predicate.EMPTY, Predicate.EMPTY);
|
||||
|
||||
private final Predicate stack;
|
||||
|
@ -27,6 +27,7 @@ class Ingredient {
|
|||
private final Predicate enchantment;
|
||||
|
||||
private final Lazy<List<ItemStack>> matchingStacks;
|
||||
private final Lazy<net.minecraft.recipe.Ingredient> preview;
|
||||
|
||||
Ingredient(Predicate stack, Predicate tag, Predicate spell, Predicate enchantment) {
|
||||
this.stack = stack;
|
||||
|
@ -42,12 +43,19 @@ class Ingredient {
|
|||
).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 = ItemStack.EMPTY.copy();
|
||||
stack.applyModifiers(output, random);
|
||||
|
@ -64,7 +72,6 @@ class Ingredient {
|
|||
&& enchantment.matches(other, materialMult);
|
||||
}
|
||||
|
||||
|
||||
public void write(PacketByteBuf buf) {
|
||||
stack.write(buf);
|
||||
tag.write(buf);
|
||||
|
@ -110,6 +117,15 @@ class Ingredient {
|
|||
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
|
|
@ -1,4 +1,4 @@
|
|||
package com.minelittlepony.unicopia.recipe;
|
||||
package com.minelittlepony.unicopia.recipe.ingredient;
|
||||
|
||||
import java.util.Random;
|
||||
import java.util.stream.Stream;
|
||||
|
@ -9,6 +9,10 @@ import com.minelittlepony.unicopia.magic.spell.SpellRegistry;
|
|||
import net.minecraft.item.ItemStack;
|
||||
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();
|
|
@ -1,10 +1,8 @@
|
|||
package com.minelittlepony.unicopia.recipe;
|
||||
package com.minelittlepony.unicopia.recipe.ingredient;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.Random;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.google.common.collect.Streams;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
|
@ -17,6 +15,10 @@ import net.minecraft.util.Identifier;
|
|||
import net.minecraft.util.PacketByteBuf;
|
||||
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();
|
||||
|
@ -81,7 +83,7 @@ class StackPredicate implements Ingredient.Predicate {
|
|||
return subItems.stream();
|
||||
}
|
||||
|
||||
return Streams.stream(Optional.ofNullable(stack));
|
||||
return Stream.of(stack);
|
||||
}
|
||||
|
||||
@Override
|
|
@ -1,4 +1,4 @@
|
|||
package com.minelittlepony.unicopia.recipe;
|
||||
package com.minelittlepony.unicopia.recipe.ingredient;
|
||||
|
||||
import java.util.Random;
|
||||
import java.util.stream.Stream;
|
||||
|
@ -13,6 +13,10 @@ import net.minecraft.tag.Tag;
|
|||
import net.minecraft.util.Identifier;
|
||||
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();
|
Loading…
Reference in a new issue