summaryrefslogtreecommitdiff
path: root/src/main/java/lv/enes/mc/eris_alchemy/recipe/SimplifiedRecipe.java
diff options
context:
space:
mode:
authorGravatar Uko Kokņevičs2024-01-13 01:12:12 +0100
committerGravatar Uko Kokņevičs2024-01-13 01:12:12 +0100
commitdc7613dd4669393a313b270b55cfaaa3ff8c94a3 (patch)
tree657c3aa3c185cd9c8820ff4a5a32336f5cf421c6 /src/main/java/lv/enes/mc/eris_alchemy/recipe/SimplifiedRecipe.java
parentBump versions (diff)
downloadmc-eris-alchemy-dc7613dd4669393a313b270b55cfaaa3ff8c94a3.tar.gz
mc-eris-alchemy-dc7613dd4669393a313b270b55cfaaa3ff8c94a3.tar.xz
mc-eris-alchemy-dc7613dd4669393a313b270b55cfaaa3ff8c94a3.zip
Toposort recipes so it's actually usably fast
Diffstat (limited to 'src/main/java/lv/enes/mc/eris_alchemy/recipe/SimplifiedRecipe.java')
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/recipe/SimplifiedRecipe.java123
1 files changed, 123 insertions, 0 deletions
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/recipe/SimplifiedRecipe.java b/src/main/java/lv/enes/mc/eris_alchemy/recipe/SimplifiedRecipe.java
new file mode 100644
index 0000000..469ed52
--- /dev/null
+++ b/src/main/java/lv/enes/mc/eris_alchemy/recipe/SimplifiedRecipe.java
@@ -0,0 +1,123 @@
1package lv.enes.mc.eris_alchemy.recipe;
2
3import com.google.gson.JsonDeserializationContext;
4import com.google.gson.JsonDeserializer;
5import com.google.gson.JsonElement;
6import com.google.gson.JsonParseException;
7import jakarta.annotation.Nonnull;
8import lv.enes.mc.eris_alchemy.utils.IngredientProvider;
9import lv.enes.mc.eris_alchemy.utils.ItemUtils;
10import lv.enes.mc.eris_alchemy.utils.RecipeUtils;
11import net.minecraft.core.RegistryAccess;
12import net.minecraft.core.registries.BuiltInRegistries;
13import net.minecraft.resources.ResourceLocation;
14import net.minecraft.world.item.ItemStack;
15import net.minecraft.world.item.crafting.Ingredient;
16import net.minecraft.world.item.crafting.Recipe;
17import net.minecraft.world.item.crafting.ShapedRecipe;
18
19import java.lang.reflect.Type;
20import java.util.Arrays;
21import java.util.Collection;
22import java.util.List;
23import java.util.Objects;
24import java.util.function.Supplier;
25import java.util.stream.Stream;
26
27public record SimplifiedRecipe(ItemStack output, List<ItemStack> remainder, List<Supplier<Ingredient>> input) {
28 public SimplifiedRecipe(Recipe<?> recipe, RegistryAccess registryAccess) {
29 this(
30 RecipeUtils.getOutput(recipe, registryAccess),
31 List.of(), // TODO:
32 RecipeUtils.getIngredients(recipe)
33 .stream()
34 .filter(ingredient -> !ingredient.isEmpty())
35 .map(x -> (Supplier<Ingredient>) () -> x)
36 .toList()
37 );
38 }
39
40 public Stream<ResourceLocation> dependencies() {
41 return Stream.concat(
42 input.stream().map(Supplier::get).map(Ingredient::getItems).flatMap(Arrays::stream),
43 remainder.stream()
44 ).map(ItemUtils::getId);
45 }
46
47 public boolean hasDuplication() {
48 var outputId = ItemUtils.getId(output);
49 var outputsInRemainder = remainder.stream()
50 .map(ItemUtils::getId)
51 .anyMatch(id -> Objects.equals(id, outputId));
52 if (outputsInRemainder) {
53 return true;
54 }
55
56 return input.stream().anyMatch(ingredient -> ingredient.get().test(output));
57 }
58
59 public boolean isAllowed(BannedRecipe ban) {
60 if (!ban.output().get().test(output())) {
61 return true;
62 }
63
64 return dependencies().noneMatch(dep -> ban.input().get().test(ItemUtils.get(dep).getDefaultInstance()));
65 }
66
67 public boolean isAllowed(Collection<BannedRecipe> bans) {
68 return bans.stream().allMatch(this::isAllowed);
69 }
70
71 public static class Deserializer implements JsonDeserializer<SimplifiedRecipe> {
72 @Nonnull
73 @Override
74 public SimplifiedRecipe deserialize(
75 JsonElement jsonElement,
76 Type type,
77 JsonDeserializationContext jsonDeserializationContext
78 ) throws JsonParseException {
79 if (!jsonElement.isJsonObject()) {
80 throw new JsonParseException("Recipe must be an object");
81 }
82 var obj = jsonElement.getAsJsonObject();
83
84 if (obj.get("output") == null || obj.get("input") == null) {
85 throw new JsonParseException("Recipe must have 'output' and 'input' fields");
86 }
87
88 var output = parseOutputOrRemainder(obj.get("output"));
89 var remainder = parseRemainders(obj.get("remainder"));
90 var input = parseInputs(obj.get("input"));
91 return new SimplifiedRecipe(output, remainder, input);
92 }
93
94 private List<Supplier<Ingredient>> parseInputs(JsonElement el) {
95 if (el.isJsonArray()) {
96 return el.getAsJsonArray().asList().stream().map(IngredientProvider::deserialize).toList();
97 }
98
99 return List.of(IngredientProvider.deserialize(el));
100 }
101
102 private ItemStack parseOutputOrRemainder(JsonElement el) {
103 if (el.isJsonObject()) {
104 return ShapedRecipe.itemStackFromJson(el.getAsJsonObject());
105 } else if (el.isJsonPrimitive() && el.getAsJsonPrimitive().isString()) {
106 var id = new ResourceLocation(el.getAsString());
107 return BuiltInRegistries.ITEM.get(id).getDefaultInstance();
108 } else {
109 throw new JsonParseException("Recipe's output or remainder must be an object or a string");
110 }
111 }
112
113 private List<ItemStack> parseRemainders(JsonElement el) {
114 if (el == null) {
115 return List.of();
116 } else if (el.isJsonArray()) {
117 return el.getAsJsonArray().asList().stream().map(this::parseOutputOrRemainder).toList();
118 } else {
119 return List.of(parseOutputOrRemainder(el));
120 }
121 }
122 }
123}