summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Uko Kokņevičs2024-01-11 23:11:27 +0100
committerGravatar Uko Kokņevičs2024-01-11 23:11:27 +0100
commitbca6a74e9a17e04de419743850f66af96a6473cc (patch)
tree6f81c0ceb615b0a85810df89ea9acafe6112eba9
parentMaking SheetsMixin more extensible (diff)
downloadmc-eris-alchemy-bca6a74e9a17e04de419743850f66af96a6473cc.tar.gz
mc-eris-alchemy-bca6a74e9a17e04de419743850f66af96a6473cc.tar.xz
mc-eris-alchemy-bca6a74e9a17e04de419743850f66af96a6473cc.zip
Move default emc values to JSON files in datapack
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/EMC.java600
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/Emc.java214
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/EmcLoader.java99
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/ErisAlchemy.java11
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/SimplifiedRecipe.java89
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/block/EnergyCondenserBlock.java4
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/block/entity/EnergyCondenserEntity.java6
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/client/EnergyCondenserScreen.java4
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/client/ErisAlchemyClient.java11
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/mixin/CoralBlockMixin.java20
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/mixin/CoralFanBlockMixin.java20
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/mixin/CoralPlantBlockMixin.java20
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/mixin/CoralWallFanBlockMixin.java20
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/utils/AxeUtils.java18
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/utils/BlockUtils.java15
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/utils/CoralUtils.java44
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/utils/DyeUtils.java62
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/utils/ItemUtils.java20
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/utils/TagUtils.java16
-rw-r--r--src/main/resources/data/eris_alchemy/eris_alchemy/block_tag_emcs/minecraft.json5
-rw-r--r--src/main/resources/data/eris_alchemy/eris_alchemy/fake_recipes/fake_recipes.json5562
-rw-r--r--src/main/resources/data/eris_alchemy/eris_alchemy/item_emcs/minecraft.json307
-rw-r--r--src/main/resources/data/eris_alchemy/eris_alchemy/item_emcs/patchouli.json3
-rw-r--r--src/main/resources/data/eris_alchemy/eris_alchemy/item_tag_emcs/minecraft.json20
-rw-r--r--src/main/resources/eris_alchemy.mixins.json4
25 files changed, 1338 insertions, 856 deletions
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/EMC.java b/src/main/java/lv/enes/mc/eris_alchemy/EMC.java
deleted file mode 100644
index 92c0624..0000000
--- a/src/main/java/lv/enes/mc/eris_alchemy/EMC.java
+++ /dev/null
@@ -1,600 +0,0 @@
1package lv.enes.mc.eris_alchemy;
2
3import jakarta.annotation.Nullable;
4import lv.enes.mc.eris_alchemy.utils.*;
5import lv.enes.mc.eris_alchemy.utils.ItemUtils;
6import net.minecraft.core.RegistryAccess;
7import net.minecraft.core.registries.BuiltInRegistries;
8import net.minecraft.tags.BlockTags;
9import net.minecraft.tags.ItemTags;
10import net.minecraft.tags.TagKey;
11import net.minecraft.world.item.*;
12import net.minecraft.world.item.crafting.Ingredient;
13import net.minecraft.world.item.crafting.Recipe;
14import net.minecraft.world.level.ItemLike;
15import net.minecraft.world.level.Level;
16import net.minecraft.world.level.block.Block;
17import vazkii.patchouli.common.item.PatchouliItems;
18
19import java.text.DecimalFormat;
20import java.util.*;
21import java.util.stream.Stream;
22
23public class EMC {
24 private record SimplifiedRecipe(ItemStack output, List<ItemStack> remainder, List<Ingredient> inputs) {
25 public SimplifiedRecipe(ItemLike output, Ingredient... inputs) {
26 this(new ItemStack(output), List.of(), List.of(inputs));
27 }
28
29 public SimplifiedRecipe(ItemLike output, ItemLike... inputs) {
30 this(new ItemStack(output), List.of(), Arrays.stream(inputs).map(Ingredient::of).toList());
31 }
32
33 public SimplifiedRecipe(ItemLike output, ItemStack... inputs) {
34 this(new ItemStack(output), List.of(), Arrays.stream(inputs).map(Ingredient::of).toList());
35 }
36
37 public SimplifiedRecipe(ItemLike output, List<ItemStack> remainder, ItemLike... inputs) {
38 this(new ItemStack(output), remainder, Arrays.stream(inputs).map(Ingredient::of).toList());
39 }
40
41 public SimplifiedRecipe(ItemStack output, ItemLike... inputs) {
42 this(output, List.of(), Arrays.stream(inputs).map(Ingredient::of).toList());
43 }
44
45 public SimplifiedRecipe(ItemStack output, ItemStack... inputs) {
46 this(output, List.of(), Arrays.stream(inputs).map(Ingredient::of).toList());
47 }
48
49 public SimplifiedRecipe(Recipe<?> recipe, RegistryAccess registryAccess) {
50 this(
51 RecipeUtils.getOutput(recipe, registryAccess),
52 List.of(), // TODO:
53 RecipeUtils.getIngredients(recipe).stream().filter(ingredient -> !ingredient.isEmpty()).toList()
54 );
55 }
56 }
57
58 private static final Map<Item, Double> ITEM_COMMON_MAP = new HashMap<>();
59 private static final Map<TagKey<Item>, Double> ITEM_TAG_COMMON_MAP = new HashMap<>();
60 private static final Map<TagKey<Block>, Double> BLOCK_TAG_COMMON_MAP = new HashMap<>();
61 private static final List<SimplifiedRecipe> FAKE_RECIPES = new ArrayList<>();
62
63 private static final EMC defaultInstance = new EMC(null);
64 private static final Map<Level, EMC> instances = Collections.synchronizedMap(new WeakHashMap<>());
65
66 private static final DecimalFormat formatter = new DecimalFormat("0");
67 static {
68 formatter.setMaximumFractionDigits(1);
69 }
70
71 public static EMC getInstance(Level world) {
72 if (world == null) {
73 return defaultInstance;
74 }
75
76 if (instances.containsKey(world)) {
77 return instances.get(world);
78 }
79
80 var instance = new EMC(world);
81 instances.put(world, instance);
82 return instance;
83 }
84
85 public static String formatEmc(double value) {
86 return formatter.format(value);
87 }
88
89 private final Map<Item, Double> data;
90
91 private EMC(@Nullable Level world) {
92 data = Collections.synchronizedMap(new HashMap<>(ITEM_COMMON_MAP));
93 ITEM_TAG_COMMON_MAP.forEach(
94 (tag, emcValue) -> BuiltInRegistries.ITEM
95 .getTagOrEmpty(tag)
96 .forEach(holder -> data.putIfAbsent(holder.value(), emcValue))
97 );
98 BLOCK_TAG_COMMON_MAP.forEach(
99 (tag, emcValue) -> BuiltInRegistries.BLOCK
100 .getTagOrEmpty(tag)
101 .forEach(holder -> data.putIfAbsent(holder.value().asItem(), emcValue))
102 );
103
104 ErisAlchemy.LOGGER.info("Calculating EMC values...");
105 var recipes = getRecipes(world);
106 var configured = new HashSet<>(data.keySet());
107 BuiltInRegistries.ITEM.forEach(item -> {
108 configEmc(recipes, configured, item);
109 if (world != null && !data.containsKey(item)) {
110 ErisAlchemy.LOGGER.warn("No EMC value for '{}' known", item);
111 }
112 });
113 }
114
115 public OptionalDouble get(ItemStack stack) {
116 if (stack.isEmpty()) {
117 return OptionalDouble.empty();
118 }
119
120 var item = stack.getItem();
121 var value = data.get(item);
122 if (value == null || value <= 0) {
123 return OptionalDouble.empty();
124 }
125
126 EmcStorage storage = null;
127 if (item instanceof EmcStorage emcStorage) {
128 storage = emcStorage;
129 } else if (item instanceof BlockItem blockItem) {
130 if (blockItem.getBlock() instanceof EmcStorage emcStorage) {
131 storage = emcStorage;
132 }
133 }
134
135 if (storage != null) {
136 value += storage.getStoredEmc(stack);
137 }
138
139 return OptionalDouble.of(value);
140 }
141
142 private List<SimplifiedRecipe> getRecipes(@Nullable Level world) {
143 Stream<SimplifiedRecipe> recipes = Stream.concat(
144 FAKE_RECIPES.stream(),
145 AxeUtils.getStrippables()
146 .entrySet()
147 .stream()
148 .map(entry -> new SimplifiedRecipe(entry.getValue(), Ingredient.of(entry.getKey())))
149 );
150
151 if (world != null) {
152 recipes = Stream.concat(
153 recipes,
154 world.getRecipeManager()
155 .getRecipes()
156 .stream()
157 .map(recipe -> new SimplifiedRecipe(recipe, world.registryAccess()))
158 );
159 }
160
161 return recipes.toList();
162 }
163
164 private OptionalDouble configEmc(List<SimplifiedRecipe> recipes, Set<Item> configured, Item item) {
165 var res = get(item.getDefaultInstance());
166 if (res.isPresent() || configured.contains(item)) {
167 return res;
168 }
169
170 configured.add(item);
171
172 res = recipes.stream()
173 .filter(recipe -> recipe.output.is(item))
174 .map(recipe -> calculateEmcForRecipe(recipes, configured, recipe))
175 .filter(OptionalDouble::isPresent)
176 .mapToDouble(OptionalDouble::getAsDouble)
177 .average();
178 res.ifPresent(emc -> data.put(item, emc));
179 if (res.isPresent() && res.getAsDouble() <= 0) {
180 res = OptionalDouble.empty();
181 }
182 return res;
183 }
184
185 private OptionalDouble calculateEmcForRecipe(
186 List<SimplifiedRecipe> recipes,
187 Set<Item> configured,
188 SimplifiedRecipe recipe
189 ) {
190 try {
191 if (recipe.inputs.isEmpty()) {
192 return OptionalDouble.empty();
193 }
194
195 var inputEmc = recipe.inputs
196 .stream()
197 .map(ingredient -> calculateEmcForIngredient(recipes, configured, ingredient))
198 .mapToDouble(OptionalDouble::orElseThrow)
199 .sum();
200
201 if (inputEmc <= 0) {
202 return OptionalDouble.empty();
203 }
204
205 var remainderEmc = recipe.remainder
206 .stream()
207 .map(remainder -> configEmc(recipes, configured, remainder.getItem()))
208 .mapToDouble(OptionalDouble::orElseThrow)
209 .sum();
210
211 if (remainderEmc > inputEmc) {
212 ErisAlchemy.LOGGER.warn("Recipe generating {} creates too much EMC out of thin air!", recipe.output);
213 return OptionalDouble.empty();
214 } else if (remainderEmc < 0) {
215 return OptionalDouble.empty();
216 }
217
218 var outputDivisor = (double) recipe.output.getCount();
219
220 return OptionalDouble.of((inputEmc - remainderEmc) / outputDivisor);
221 } catch (NoSuchElementException e) {
222 return OptionalDouble.empty();
223 }
224 }
225
226 private OptionalDouble calculateEmcForIngredient(
227 List<SimplifiedRecipe> recipes,
228 Set<Item> configured,
229 Ingredient ingredient
230 ) {
231 return Arrays.stream(ingredient.getItems())
232 .map(stack -> configEmc(recipes, configured, stack.getItem()).stream()
233 .map(x -> x * stack.getCount())
234 .findFirst())
235 .filter(OptionalDouble::isPresent)
236 .mapToDouble(OptionalDouble::getAsDouble)
237 .filter(x -> x > 0)
238 .average();
239 }
240
241 static {
242 ITEM_COMMON_MAP.putAll(Map.<Item, Double>ofEntries(
243 Map.entry(Items.AIR, -1.0),
244 Map.entry(Items.AMETHYST_CLUSTER, -1.0),
245 Map.entry(Items.AMETHYST_SHARD, 1024.0),
246 Map.entry(Items.ANCIENT_DEBRIS, -1.0),
247 Map.entry(Items.APPLE, 128.0),
248 Map.entry(Items.BAMBOO, 2.0),
249 Map.entry(Items.BARRIER, -1.0),
250 Map.entry(Items.BEDROCK, -1.0),
251 Map.entry(Items.BEEF, 64.0),
252 Map.entry(Items.BEETROOT, 24.0),
253 Map.entry(Items.BEETROOT_SEEDS, 16.0),
254 Map.entry(Items.BIG_DRIPLEAF, 1.0),
255 Map.entry(Items.BLAZE_ROD, 1536.0),
256 Map.entry(Items.BONE, 96.0),
257 Map.entry(Items.BROWN_MUSHROOM, 32.0),
258 Map.entry(Items.BROWN_MUSHROOM_BLOCK, -1.0),
259 Map.entry(Items.BUDDING_AMETHYST, -1.0),
260 Map.entry(Items.BUNDLE, -1.0),
261 Map.entry(Items.CACTUS, 8.0),
262 Map.entry(Items.CARROT, 24.0),
263 Map.entry(Items.CALCITE, 1.0),
264 Map.entry(Items.CHAIN_COMMAND_BLOCK, -1.0),
265 Map.entry(Items.CHICKEN, 64.0),
266 Map.entry(Items.CHORUS_FLOWER, 32.0),
267 Map.entry(Items.CHORUS_FRUIT, 32.0),
268 Map.entry(Items.CHORUS_PLANT, 24.0),
269 Map.entry(Items.CLAY_BALL, 64.0),
270 Map.entry(Items.COAL, 128.0),
271 Map.entry(Items.COBWEB, 12.0),
272 Map.entry(Items.COBBLESTONE, 1.0),
273 Map.entry(Items.COBBLED_DEEPSLATE, 1.0),
274 Map.entry(Items.COCOA_BEANS, 8.0),
275 Map.entry(Items.COMMAND_BLOCK, -1.0),
276 Map.entry(Items.COMMAND_BLOCK_MINECART, -1.0),
277 Map.entry(Items.COPPER_INGOT, 85.0),
278 Map.entry(Items.CREEPER_HEAD, 34816.0),
279 Map.entry(Items.CRIMSON_FUNGUS, 24.0),
280 Map.entry(Items.CRIMSON_ROOTS, 1.0),
281 Map.entry(Items.CRYING_OBSIDIAN, 64.0),
282 Map.entry(Items.DEAD_BUSH, 1.0),
283 Map.entry(Items.DEBUG_STICK, -1.0),
284 Map.entry(Items.DIAMOND, 8192.0),
285 Map.entry(Items.DIRT_PATH, 1.0),
286 Map.entry(Items.DRAGON_BREATH, 34816.0),
287 Map.entry(Items.DRAGON_EGG, 139264.0),
288 Map.entry(Items.DRAGON_HEAD, 34816.0),
289 Map.entry(Items.ECHO_SHARD, 128.0),
290 Map.entry(Items.EGG, 32.0),
291 Map.entry(Items.ELYTRA, 8196.0),
292 Map.entry(Items.EMERALD, 1024.0),
293 Map.entry(Items.ENCHANTED_BOOK, -1.0),
294 Map.entry(Items.END_PORTAL_FRAME, -1.0),
295 Map.entry(Items.END_STONE, 1.0),
296 Map.entry(Items.ENDER_PEARL, 1024.0),
297 Map.entry(Items.EXPERIENCE_BOTTLE, -1.0),
298 Map.entry(Items.FARMLAND, -1.0),
299 Map.entry(Items.FEATHER, 48.0),
300 Map.entry(Items.FERN, 1.0),
301 Map.entry(Items.FIREWORK_STAR, -1.0),
302 Map.entry(Items.FLINT, 4.0),
303 Map.entry(Items.FROGSPAWN, -1.0),
304 Map.entry(Items.GHAST_TEAR, 4096.0),
305 Map.entry(Items.GLOW_BERRIES, 8.0),
306 Map.entry(Items.GLOW_LICHEN, 8.0),
307 Map.entry(Items.GLOWSTONE_DUST, 384.0),
308 Map.entry(Items.GOAT_HORN, 32.0),
309 Map.entry(Items.GOLD_INGOT, 2048.0),
310 Map.entry(Items.GOLD_NUGGET, 2048.0/9),
311 Map.entry(Items.GRASS, 1.0),
312 Map.entry(Items.GRAVEL, 4.0),
313 Map.entry(Items.GUNPOWDER, 192.0),
314 Map.entry(Items.HANGING_ROOTS, 1.0),
315 Map.entry(Items.HEART_OF_THE_SEA, 4096.0),
316 Map.entry(Items.HONEYCOMB, 24.0),
317 Map.entry(Items.ICE, 1.0),
318 Map.entry(Items.INFESTED_CHISELED_STONE_BRICKS, -1.0),
319 Map.entry(Items.INFESTED_COBBLESTONE, -1.0),
320 Map.entry(Items.INFESTED_CRACKED_STONE_BRICKS, -1.0),
321 Map.entry(Items.INFESTED_DEEPSLATE, -1.0),
322 Map.entry(Items.INFESTED_MOSSY_STONE_BRICKS, -1.0),
323 Map.entry(Items.INFESTED_STONE, -1.0),
324 Map.entry(Items.INFESTED_STONE_BRICKS, -1.0),
325 Map.entry(Items.IRON_INGOT, 256.0),
326 Map.entry(Items.IRON_NUGGET, 256.0/9),
327 Map.entry(Items.JIGSAW, -1.0),
328 Map.entry(Items.KELP, 32.0),
329 Map.entry(Items.KNOWLEDGE_BOOK, -1.0),
330 Map.entry(Items.LAPIS_LAZULI, 864.0),
331 Map.entry(Items.LARGE_AMETHYST_BUD, -1.0),
332 Map.entry(Items.LARGE_FERN, 1.0),
333 Map.entry(Items.LEATHER, 64.0),
334 Map.entry(Items.LIGHT, -1.0),
335 Map.entry(Items.LILY_PAD, 16.0),
336 Map.entry(Items.LINGERING_POTION, -1.0),
337 Map.entry(Items.MANGROVE_ROOTS, 1.0),
338 Map.entry(Items.MEDIUM_AMETHYST_BUD, -1.0),
339 Map.entry(Items.MELON_SLICE, 144.0),
340 Map.entry(Items.MUD, 1.0),
341 Map.entry(Items.MUSHROOM_STEM, -1.0),
342 Map.entry(Items.MUTTON, 64.0),
343 Map.entry(Items.NAME_TAG, -1.0),
344 Map.entry(Items.NAUTILUS_SHELL, 64.0),
345 Map.entry(Items.NETHER_QUARTZ_ORE, -1.0),
346 Map.entry(Items.NETHER_SPROUTS, 1.0),
347 Map.entry(Items.NETHER_STAR, 139264.0),
348 Map.entry(Items.NETHER_WART, 24.0),
349 Map.entry(Items.NETHERITE_SCRAP, 16384.0),
350 Map.entry(Items.OBSIDIAN, 64.0),
351 Map.entry(Items.PHANTOM_MEMBRANE, 96.0),
352 Map.entry(Items.PIGLIN_HEAD, 34816.0),
353 Map.entry(Items.PITCHER_POD, 8.0),
354 Map.entry(Items.PLAYER_HEAD, 34816.0),
355 Map.entry(Items.POINTED_DRIPSTONE, 0.25),
356 Map.entry(Items.PORKCHOP, 64.0),
357 Map.entry(Items.POTATO, 24.0),
358 Map.entry(Items.POTION, -1.0),
359 Map.entry(Items.PRISMARINE_CRYSTALS, 384.0),
360 Map.entry(Items.PRISMARINE_SHARD, 0.25),
361 Map.entry(Items.PUMPKIN, 144.0),
362 Map.entry(Items.QUARTZ, 64.0),
363 Map.entry(Items.RABBIT, 64.0),
364 Map.entry(Items.RABBIT_HIDE, 64.0),
365 Map.entry(Items.RAW_COPPER, -1.0),
366 Map.entry(Items.RAW_COPPER_BLOCK, -1.0),
367 Map.entry(Items.RAW_GOLD, -1.0),
368 Map.entry(Items.RAW_GOLD_BLOCK, -1.0),
369 Map.entry(Items.RAW_IRON, -1.0),
370 Map.entry(Items.RAW_IRON_BLOCK, -1.0),
371 Map.entry(Items.RED_MUSHROOM, 32.0),
372 Map.entry(Items.RED_MUSHROOM_BLOCK, -1.0),
373 Map.entry(Items.REDSTONE, 64.0),
374 Map.entry(Items.REINFORCED_DEEPSLATE, -1.0),
375 Map.entry(Items.REPEATING_COMMAND_BLOCK, -1.0),
376 Map.entry(Items.ROTTEN_FLESH, 24.0),
377 Map.entry(Items.SADDLE, 192.0),
378 Map.entry(Items.SCULK, 1.0),
379 Map.entry(Items.SCULK_CATALYST, 16.0),
380 Map.entry(Items.SCULK_SENSOR, 32.0),
381 Map.entry(Items.SCULK_SHRIEKER, 16.0),
382 Map.entry(Items.SCULK_VEIN, 1.0),
383 Map.entry(Items.SCUTE, 32.0),
384 Map.entry(Items.SEA_PICKLE, 1.0),
385 Map.entry(Items.SEAGRASS, 1.0),
386 Map.entry(Items.SHULKER_SHELL, 256.0),
387 Map.entry(Items.SKELETON_SKULL, 34816.0),
388 Map.entry(Items.SLIME_BALL, 24.0),
389 Map.entry(Items.SMALL_AMETHYST_BUD, -1.0),
390 Map.entry(Items.SMALL_DRIPLEAF, 1.0),
391 Map.entry(Items.SNIFFER_EGG, 32.0),
392 Map.entry(Items.SNOWBALL, 1.0),
393 Map.entry(Items.SOUL_SAND, 49.0),
394 Map.entry(Items.SOUL_SOIL, 49.0),
395 Map.entry(Items.SPAWNER, -1.0),
396 Map.entry(Items.SPIDER_EYE, 128.0),
397 Map.entry(Items.SPLASH_POTION, -1.0),
398 Map.entry(Items.SPONGE, 48.0),
399 Map.entry(Items.SPORE_BLOSSOM, 1.0),
400 Map.entry(Items.STICK, 4.0),
401 Map.entry(Items.STRING, 12.0),
402 Map.entry(Items.STRUCTURE_BLOCK, -1.0),
403 Map.entry(Items.STRUCTURE_VOID, -1.0),
404 Map.entry(Items.SUGAR_CANE, 32.0),
405 Map.entry(Items.SUSPICIOUS_GRAVEL, 4.0),
406 Map.entry(Items.SWEET_BERRIES, 8.0),
407 Map.entry(Items.TALL_GRASS, 1.0),
408 Map.entry(Items.TIPPED_ARROW, -1.0),
409 Map.entry(Items.TORCHFLOWER_SEEDS, 8.0),
410 Map.entry(Items.TOTEM_OF_UNDYING, 4096.0),
411 Map.entry(Items.TURTLE_EGG, 32.0),
412 Map.entry(Items.TWISTING_VINES, 8.0),
413 Map.entry(Items.VINE, 8.0),
414 Map.entry(Items.WARPED_FUNGUS, 24.0),
415 Map.entry(Items.WARPED_ROOTS, 1.0),
416 Map.entry(Items.WARPED_WART_BLOCK, 1.0),
417 Map.entry(Items.WEEPING_VINES, 8.0),
418 Map.entry(Items.WET_SPONGE, 48.0),
419 Map.entry(Items.WHEAT, 24.0),
420 Map.entry(Items.WHEAT_SEEDS, 16.0),
421 Map.entry(Items.WITHER_SKELETON_SKULL, 34816.0),
422 Map.entry(Items.WRITTEN_BOOK, -1.0),
423 Map.entry(Items.ZOMBIE_HEAD, 34816.0),
424
425 Map.entry(PatchouliItems.BOOK, -1.0)
426 ));
427
428 SpawnEggItem.eggs().forEach(spawnEgg -> ITEM_COMMON_MAP.put(spawnEgg, -1.0));
429
430 CoralUtils.streamAllCoralBlocks().forEach(block -> ITEM_COMMON_MAP.put(block.asItem(), 1.0));
431 CoralUtils.streamAllDeadCoralBlocks().forEach(block -> ITEM_COMMON_MAP.put(block.asItem(), 1.0));
432 CoralUtils.streamAllCorals().forEach(block -> ITEM_COMMON_MAP.put(block.asItem(), 1.0));
433 CoralUtils.streamAllDeadCorals().forEach(block -> ITEM_COMMON_MAP.put(block.asItem(), 1.0));
434
435 BLOCK_TAG_COMMON_MAP.putAll(Map.ofEntries(
436 Map.entry(BlockTags.BASE_STONE_NETHER, 1.0),
437 Map.entry(BlockTags.BASE_STONE_OVERWORLD, 1.0),
438 Map.entry(BlockTags.NYLIUM, 1.0)
439 ));
440
441 ITEM_TAG_COMMON_MAP.putAll(Map.ofEntries(
442 Map.entry(ItemTags.COAL_ORES, -1.0),
443 Map.entry(ItemTags.COPPER_ORES, -1.0),
444 Map.entry(ItemTags.DIAMOND_ORES, -1.0),
445 Map.entry(ItemTags.DIRT, 1.0),
446 Map.entry(ItemTags.MUSIC_DISCS, 4096.0),
447 Map.entry(ItemTags.EMERALD_ORES, -1.0),
448 Map.entry(ItemTags.FISHES, 64.0),
449 Map.entry(ItemTags.FLOWERS, 16.0),
450 Map.entry(ItemTags.GOLD_ORES, -1.0),
451 Map.entry(ItemTags.IRON_ORES, -1.0),
452 Map.entry(ItemTags.LAPIS_ORES, -1.0),
453 Map.entry(ItemTags.LEAVES, 1.0),
454 Map.entry(ItemTags.LOGS, 32.0),
455 Map.entry(ItemTags.REDSTONE_ORES, -1.0),
456 Map.entry(ItemTags.SAND, 1.0),
457 Map.entry(ItemTags.SAPLINGS, 32.0),
458 Map.entry(ItemTags.WOOL, 48.0)
459 ));
460
461 FAKE_RECIPES.addAll(List.of(
462 // more oxidised coppers are worth less
463 new SimplifiedRecipe(new ItemStack(Items.EXPOSED_COPPER, 4), new ItemStack(Items.COPPER_BLOCK, 3)),
464 new SimplifiedRecipe(new ItemStack(Items.WEATHERED_COPPER, 4), new ItemStack(Items.COPPER_BLOCK, 2)),
465 new SimplifiedRecipe(new ItemStack(Items.OXIDIZED_COPPER, 4), new ItemStack(Items.COPPER_BLOCK, 1)),
466
467 new SimplifiedRecipe(new ItemStack(Items.WAXED_EXPOSED_COPPER, 4), new ItemStack(Items.WAXED_COPPER_BLOCK, 3)),
468 new SimplifiedRecipe(new ItemStack(Items.WAXED_WEATHERED_COPPER, 4), new ItemStack(Items.WAXED_COPPER_BLOCK, 2)),
469 new SimplifiedRecipe(new ItemStack(Items.WAXED_OXIDIZED_COPPER, 4), new ItemStack(Items.WAXED_COPPER_BLOCK, 1)),
470
471 // more damaged anvils are worth less
472 new SimplifiedRecipe(new ItemStack(Items.CHIPPED_ANVIL, 3), new ItemStack(Items.ANVIL, 2)),
473 new SimplifiedRecipe(new ItemStack(Items.DAMAGED_ANVIL, 3), new ItemStack(Items.ANVIL, 1)),
474
475 // old oak slabs are the same value as modern ones
476 new SimplifiedRecipe(Items.PETRIFIED_OAK_SLAB, Items.OAK_SLAB),
477
478 // chainmail armour is worth the same as normal iron armor
479 new SimplifiedRecipe(Items.CHAINMAIL_HELMET, Items.IRON_HELMET),
480 new SimplifiedRecipe(Items.CHAINMAIL_CHESTPLATE, Items.IRON_CHESTPLATE),
481 new SimplifiedRecipe(Items.CHAINMAIL_LEGGINGS, Items.IRON_LEGGINGS),
482 new SimplifiedRecipe(Items.CHAINMAIL_BOOTS, Items.IRON_BOOTS),
483
484 // enchanted golden apple is worth uhh 16 times the non-enchanted one :3
485 new SimplifiedRecipe(Items.ENCHANTED_GOLDEN_APPLE, new ItemStack(Items.GOLDEN_APPLE, 16)),
486
487 // carving a pumpkin with shears
488 new SimplifiedRecipe(Items.CARVED_PUMPKIN, List.of(new ItemStack(Items.PUMPKIN_SEEDS, 4)), Items.PUMPKIN),
489
490 // gathering honey
491 new SimplifiedRecipe(Items.HONEY_BOTTLE, Items.HONEYCOMB, Items.GLASS_BOTTLE),
492
493 // smithing template duplicating recipes but -1 templates on both sides
494 new SimplifiedRecipe(Items.COAST_ARMOR_TRIM_SMITHING_TEMPLATE, new ItemStack(Items.DIAMOND, 7), new ItemStack(Items.COBBLESTONE)),
495 new SimplifiedRecipe(Items.DUNE_ARMOR_TRIM_SMITHING_TEMPLATE, new ItemStack(Items.DIAMOND, 7), new ItemStack(Items.SANDSTONE)),
496 new SimplifiedRecipe(Items.EYE_ARMOR_TRIM_SMITHING_TEMPLATE, new ItemStack(Items.DIAMOND, 7), new ItemStack(Items.END_STONE)),
497 new SimplifiedRecipe(Items.HOST_ARMOR_TRIM_SMITHING_TEMPLATE, new ItemStack(Items.DIAMOND, 7), new ItemStack(Items.TERRACOTTA)),
498 new SimplifiedRecipe(Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE, new ItemStack(Items.DIAMOND, 7), new ItemStack(Items.NETHERRACK)),
499 new SimplifiedRecipe(Items.RAISER_ARMOR_TRIM_SMITHING_TEMPLATE, new ItemStack(Items.DIAMOND, 7), new ItemStack(Items.TERRACOTTA)),
500 new SimplifiedRecipe(Items.RIB_ARMOR_TRIM_SMITHING_TEMPLATE, new ItemStack(Items.DIAMOND, 7), new ItemStack(Items.NETHERRACK)),
501 new SimplifiedRecipe(Items.SENTRY_ARMOR_TRIM_SMITHING_TEMPLATE, new ItemStack(Items.DIAMOND, 7), new ItemStack(Items.COBBLESTONE)),
502 new SimplifiedRecipe(Items.SHAPER_ARMOR_TRIM_SMITHING_TEMPLATE, new ItemStack(Items.DIAMOND, 7), new ItemStack(Items.TERRACOTTA)),
503 new SimplifiedRecipe(Items.SILENCE_ARMOR_TRIM_SMITHING_TEMPLATE, new ItemStack(Items.DIAMOND, 7), new ItemStack(Items.COBBLED_DEEPSLATE)),
504 new SimplifiedRecipe(Items.SNOUT_ARMOR_TRIM_SMITHING_TEMPLATE, new ItemStack(Items.DIAMOND, 7), new ItemStack(Items.BLACKSTONE)),
505 new SimplifiedRecipe(Items.SPIRE_ARMOR_TRIM_SMITHING_TEMPLATE, new ItemStack(Items.DIAMOND, 7), new ItemStack(Items.PURPUR_BLOCK)),
506 new SimplifiedRecipe(Items.TIDE_ARMOR_TRIM_SMITHING_TEMPLATE, new ItemStack(Items.DIAMOND, 7), new ItemStack(Items.PRISMARINE)),
507 new SimplifiedRecipe(Items.VEX_ARMOR_TRIM_SMITHING_TEMPLATE, new ItemStack(Items.DIAMOND, 7), new ItemStack(Items.COBBLESTONE)),
508 new SimplifiedRecipe(Items.WARD_ARMOR_TRIM_SMITHING_TEMPLATE, new ItemStack(Items.DIAMOND, 7), new ItemStack(Items.COBBLED_DEEPSLATE)),
509 new SimplifiedRecipe(Items.WAYFINDER_ARMOR_TRIM_SMITHING_TEMPLATE, new ItemStack(Items.DIAMOND, 7), new ItemStack(Items.TERRACOTTA)),
510 new SimplifiedRecipe(Items.WILD_ARMOR_TRIM_SMITHING_TEMPLATE, new ItemStack(Items.DIAMOND, 7), new ItemStack(Items.MOSSY_COBBLESTONE)),
511
512 // water bucket = bucket + water, water assumed to be same value as cobblestone
513 new SimplifiedRecipe(Items.WATER_BUCKET, Items.BUCKET, Items.COBBLESTONE),
514
515 // lava bucket = bucket + lava, lava assumed to be same value as obsidian
516 new SimplifiedRecipe(Items.LAVA_BUCKET, Items.BUCKET, Items.OBSIDIAN),
517
518 // powder snow bucket = bucket + snow
519 new SimplifiedRecipe(Items.POWDER_SNOW_BUCKET, Items.BUCKET, Items.SNOW_BLOCK),
520
521 // milk bucket = bucket + milk, milk assumed to be same value as wheat
522 new SimplifiedRecipe(Items.MILK_BUCKET, Items.BUCKET, Items.WHEAT),
523
524 // [fish] bucket = bucket + [fish]
525 new SimplifiedRecipe(Items.COD_BUCKET, Items.BUCKET, Items.COD),
526 new SimplifiedRecipe(Items.PUFFERFISH_BUCKET, Items.BUCKET, Items.PUFFERFISH),
527 new SimplifiedRecipe(Items.SALMON_BUCKET, Items.BUCKET, Items.SALMON),
528 new SimplifiedRecipe(Items.TROPICAL_FISH_BUCKET, Items.BUCKET, Items.TROPICAL_FISH),
529
530 // yep
531 new SimplifiedRecipe(Items.AXOLOTL_BUCKET, Items.TROPICAL_FISH_BUCKET),
532 new SimplifiedRecipe(Items.TADPOLE_BUCKET, Items.AXOLOTL_BUCKET),
533
534 // dye value is the canon
535 new SimplifiedRecipe(Items.INK_SAC, Items.BLACK_DYE),
536
537 // disc value is the canon
538 new SimplifiedRecipe(new ItemStack(Items.DISC_FRAGMENT_5, 9), Items.MUSIC_DISC_5),
539
540 // glowing ink sac is more expensive than an ink sac
541 new SimplifiedRecipe(Items.GLOW_INK_SAC, new ItemStack(Items.INK_SAC, 4)),
542
543 // activated maps cost the same as unactivated ones
544 new SimplifiedRecipe(Items.FILLED_MAP, Items.MAP),
545
546 // poisonous potato costs less than a normal one
547 new SimplifiedRecipe(new ItemStack(Items.POISONOUS_POTATO, 2), Items.POTATO),
548
549 // rabbits foot costs more than rabbit meat
550 new SimplifiedRecipe(Items.RABBIT_FOOT, new ItemStack(Items.RABBIT, 8)),
551
552 // [X] horse armor == [X] leggings
553 // wtf, why? see how much leather is used by leather horse armor
554 new SimplifiedRecipe(Items.IRON_HORSE_ARMOR, Items.IRON_LEGGINGS),
555 new SimplifiedRecipe(Items.GOLDEN_HORSE_ARMOR, Items.GOLDEN_LEGGINGS),
556 new SimplifiedRecipe(Items.DIAMOND_HORSE_ARMOR, Items.DIAMOND_LEGGINGS),
557
558 // Trident = 1.5 * iron sword
559 new SimplifiedRecipe(new ItemStack(Items.TRIDENT, 2), new ItemStack(Items.IRON_SWORD, 3)),
560
561 // an actual recipe but it's special, minecraft:crafting_special_suspiciousstew
562 new SimplifiedRecipe(Items.SUSPICIOUS_STEW, Items.BOWL, Items.BROWN_MUSHROOM, Items.RED_MUSHROOM, Items.POPPY),
563
564 // obvious
565 new SimplifiedRecipe(Items.GLOBE_BANNER_PATTERN, Items.CREEPER_BANNER_PATTERN),
566 new SimplifiedRecipe(Items.PIGLIN_BANNER_PATTERN, Items.CREEPER_BANNER_PATTERN),
567
568 // the vibes fit
569 new SimplifiedRecipe(Items.BELL, Items.SPYGLASS),
570
571 // light sources, shroomlight has no crafting uses but is brighter
572 new SimplifiedRecipe(Items.SHROOMLIGHT, Items.GLOWSTONE),
573
574 // bee nest = honeycomb block
575 new SimplifiedRecipe(Items.BEE_NEST, new ItemStack(Items.HONEYCOMB, 9)),
576
577 // gilded blackstone = blackstone with gold nuggets
578 new SimplifiedRecipe(Items.GILDED_BLACKSTONE, new ItemStack(Items.BLACKSTONE), new ItemStack(Items.GOLD_NUGGET, 4)),
579
580 // froglight = eaten magma cube
581 new SimplifiedRecipe(Items.OCHRE_FROGLIGHT, Items.MAGMA_CREAM),
582 new SimplifiedRecipe(Items.PEARLESCENT_FROGLIGHT, Items.MAGMA_CREAM),
583 new SimplifiedRecipe(Items.VERDANT_FROGLIGHT, Items.MAGMA_CREAM)
584 ));
585
586 // pot sherds can be replaced with bricks when making decorated pots
587 ItemUtils.streamTag(ItemTags.DECORATED_POT_SHERDS).forEach(sherd -> FAKE_RECIPES.add(new SimplifiedRecipe(sherd, Items.BRICK)));
588
589 for (var color : DyeColor.values()) {
590 ITEM_COMMON_MAP.put(DyeUtils.getDye(color), 8.0);
591 FAKE_RECIPES.addAll(List.of(
592 // putting concrete powder in water
593 new SimplifiedRecipe(DyeUtils.getConcrete(color), DyeUtils.getConcretePowder(color)),
594
595 // an actual recipe but it's special, minecraft:crafting_special_shulkerboxcoloring
596 new SimplifiedRecipe(DyeUtils.getShulkerBox(color), Items.SHULKER_BOX, DyeUtils.getDye(color))
597 ));
598 }
599 }
600}
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/Emc.java b/src/main/java/lv/enes/mc/eris_alchemy/Emc.java
new file mode 100644
index 0000000..fdc7c0a
--- /dev/null
+++ b/src/main/java/lv/enes/mc/eris_alchemy/Emc.java
@@ -0,0 +1,214 @@
1package lv.enes.mc.eris_alchemy;
2
3import jakarta.annotation.Nonnull;
4import jakarta.annotation.Nullable;
5import lv.enes.mc.eris_alchemy.utils.ItemUtils;
6import net.minecraft.core.registries.BuiltInRegistries;
7import net.minecraft.core.registries.Registries;
8import net.minecraft.resources.ResourceLocation;
9import net.minecraft.tags.TagKey;
10import net.minecraft.world.item.BlockItem;
11import net.minecraft.world.item.Item;
12import net.minecraft.world.item.ItemStack;
13import net.minecraft.world.item.crafting.Ingredient;
14import net.minecraft.world.level.Level;
15import net.minecraft.world.level.block.Block;
16
17import java.text.DecimalFormat;
18import java.util.*;
19import java.util.stream.Stream;
20
21public class Emc {
22 private static final Map<ResourceLocation, OptionalDouble> ITEM_VALUES = new HashMap<>();
23 private static final Map<TagKey<Item>, OptionalDouble> ITEM_TAG_VALUES = new HashMap<>();
24 private static final Map<TagKey<Block>, OptionalDouble> BLOCK_TAG_VALUES = new HashMap<>();
25 private static final List<SimplifiedRecipe> FAKE_RECIPES = new ArrayList<>();
26
27 private static final Map<Level, Emc> instances = Collections.synchronizedMap(new WeakHashMap<>());
28
29 private static final DecimalFormat formatter = new DecimalFormat("0");
30 static {
31 formatter.setMaximumFractionDigits(1);
32 }
33
34 public static Emc getInstance(@Nonnull Level world) {
35 if (instances.containsKey(world)) {
36 return instances.get(world);
37 }
38
39 var instance = new Emc(world);
40 instances.put(world, instance);
41 return instance;
42 }
43
44 public static String formatEmc(double value) {
45 return formatter.format(value);
46 }
47
48 public static void reloadData(
49 Map<ResourceLocation, OptionalDouble> itemValues,
50 Map<ResourceLocation, OptionalDouble> itemTagValues,
51 Map<ResourceLocation, OptionalDouble> blockTagValues,
52 List<SimplifiedRecipe> fakeRecipes
53 ) {
54 ITEM_VALUES.clear();
55 ITEM_VALUES.putAll(itemValues);
56
57 ITEM_TAG_VALUES.clear();
58 itemTagValues.forEach((id, value) -> ITEM_TAG_VALUES.put(TagKey.create(Registries.ITEM, id), value));
59
60 BLOCK_TAG_VALUES.clear();
61 blockTagValues.forEach((id, value) -> BLOCK_TAG_VALUES.put(TagKey.create(Registries.BLOCK, id), value));
62
63 FAKE_RECIPES.clear();
64 FAKE_RECIPES.addAll(fakeRecipes);
65
66 instances.clear();
67 }
68
69 private final Map<ResourceLocation, OptionalDouble> data;
70
71 private Emc(@Nonnull Level world) {
72 data = Collections.synchronizedMap(new HashMap<>(ITEM_VALUES));
73 ITEM_TAG_VALUES.forEach(
74 (tag, emcValue) -> BuiltInRegistries.ITEM
75 .getTagOrEmpty(tag)
76 .forEach(holder -> data.putIfAbsent(ItemUtils.getId(holder), emcValue))
77 );
78 BLOCK_TAG_VALUES.forEach(
79 (tag, emcValue) -> BuiltInRegistries.BLOCK
80 .getTagOrEmpty(tag)
81 .forEach(holder -> data.putIfAbsent(ItemUtils.getId(holder), emcValue))
82 );
83
84 ErisAlchemy.LOGGER.info("Calculating EMC values...");
85 var recipes = getRecipes(world);
86 var configured = new HashSet<>(data.keySet());
87 BuiltInRegistries.ITEM.keySet().forEach(item -> {
88 configEmc(recipes, configured, item);
89 if (!data.containsKey(item)) {
90 ErisAlchemy.LOGGER.warn("No EMC value for '{}' known", item);
91 }
92 });
93 }
94
95 public OptionalDouble get(ItemStack stack) {
96 if (stack.isEmpty()) {
97 return OptionalDouble.empty();
98 }
99
100 var item = stack.getItem();
101 var itemId = ItemUtils.getId(item);
102 return get(itemId)
103 .stream()
104 .map(value -> {
105 EmcStorage storage = null;
106 if (item instanceof EmcStorage emcStorage) {
107 storage = emcStorage;
108 } else if (item instanceof BlockItem blockItem) {
109 if (blockItem.getBlock() instanceof EmcStorage emcStorage) {
110 storage = emcStorage;
111 }
112 }
113 if (storage != null) {
114 return value + storage.getStoredEmc(stack);
115 }
116 return value;
117 })
118 .findFirst();
119 }
120
121 public OptionalDouble get(ResourceLocation itemId) {
122 return data.getOrDefault(itemId, OptionalDouble.empty());
123 }
124
125 private List<SimplifiedRecipe> getRecipes(@Nullable Level world) {
126 Stream<SimplifiedRecipe> recipes = FAKE_RECIPES.stream();
127
128 if (world != null) {
129 recipes = Stream.concat(
130 recipes,
131 world.getRecipeManager()
132 .getRecipes()
133 .stream()
134 .map(recipe -> new SimplifiedRecipe(recipe, world.registryAccess()))
135 );
136 }
137
138 return recipes.toList();
139 }
140
141 private OptionalDouble configEmc(
142 List<SimplifiedRecipe> recipes,
143 Set<ResourceLocation> configured,
144 ResourceLocation itemId
145 ) {
146 var res = get(itemId);
147 if (res.isPresent() || configured.contains(itemId)) {
148 return res;
149 }
150
151 configured.add(itemId);
152 var item = BuiltInRegistries.ITEM.get(itemId);
153 res = recipes.stream()
154 .filter(recipe -> recipe.output().is(item))
155 .map(recipe -> calculateEmcForRecipe(recipes, configured, recipe))
156 .flatMapToDouble(OptionalDouble::stream)
157 .average();
158 res.ifPresentOrElse(
159 emc -> data.put(itemId, OptionalDouble.of(emc)),
160 () -> configured.remove(itemId)
161 );
162 return res;
163 }
164
165 private OptionalDouble calculateEmcForRecipe(
166 List<SimplifiedRecipe> recipes,
167 Set<ResourceLocation> configured,
168 SimplifiedRecipe recipe
169 ) {
170 try {
171 if (recipe.input().isEmpty()) {
172 return OptionalDouble.empty();
173 }
174
175 var inputEmc = recipe.input()
176 .stream()
177 .map(ingredient -> calculateEmcForIngredient(recipes, configured, ingredient))
178 .mapToDouble(OptionalDouble::orElseThrow)
179 .sum();
180
181 var remainderEmc = recipe.remainder()
182 .stream()
183 .map(remainder -> configEmc(recipes, configured, ItemUtils.getId(remainder)))
184 .mapToDouble(OptionalDouble::orElseThrow)
185 .sum();
186
187 if (remainderEmc > inputEmc) {
188 ErisAlchemy.LOGGER.warn("Recipe generating {} creates too much EMC out of thin air!", recipe.output());
189 return OptionalDouble.empty();
190 }
191
192 var outputDivisor = (double) recipe.output().getCount();
193
194 return OptionalDouble.of((inputEmc - remainderEmc) / outputDivisor);
195 } catch (NoSuchElementException e) {
196 return OptionalDouble.empty();
197 }
198 }
199
200 private OptionalDouble calculateEmcForIngredient(
201 List<SimplifiedRecipe> recipes,
202 Set<ResourceLocation> configured,
203 Ingredient ingredient
204 ) {
205 return Arrays.stream(ingredient.getItems())
206 .map(stack -> configEmc(recipes, configured, ItemUtils.getId(stack.getItem())).stream()
207 .map(x -> x * stack.getCount())
208 .findFirst())
209 .filter(OptionalDouble::isPresent)
210 .mapToDouble(OptionalDouble::getAsDouble)
211 .filter(x -> x > 0)
212 .average();
213 }
214}
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/EmcLoader.java b/src/main/java/lv/enes/mc/eris_alchemy/EmcLoader.java
new file mode 100644
index 0000000..dd4613f
--- /dev/null
+++ b/src/main/java/lv/enes/mc/eris_alchemy/EmcLoader.java
@@ -0,0 +1,99 @@
1package lv.enes.mc.eris_alchemy;
2
3import com.google.gson.reflect.TypeToken;
4import jakarta.annotation.Nonnull;
5import net.minecraft.resources.ResourceLocation;
6import net.minecraft.server.packs.resources.ResourceManager;
7import org.quiltmc.qsl.resource.loader.api.reloader.SimpleSynchronousResourceReloader;
8
9import java.io.IOException;
10import java.io.InputStream;
11import java.io.InputStreamReader;
12import java.util.*;
13
14import static lv.enes.mc.eris_alchemy.ErisAlchemy.GSON;
15
16public class EmcLoader implements SimpleSynchronousResourceReloader {
17 public static final EmcLoader INSTANCE = new EmcLoader();
18
19 @Nonnull
20 @Override
21 public ResourceLocation getQuiltId() {
22 return new ResourceLocation(ErisAlchemy.ID, "emc_loader");
23 }
24
25 @Override
26 public void onResourceManagerReload(ResourceManager manager) {
27 var itemValues = loadAllFiles(manager, "item_emcs", new HashMap<>(), EmcLoader::loadEmcValues);
28 var itemTagValues = loadAllFiles(manager, "item_tag_emcs", new HashMap<>(), EmcLoader::loadEmcValues);
29 var blockTagValues = loadAllFiles(manager, "block_tag_emcs", new HashMap<>(), EmcLoader::loadEmcValues);
30
31 var fakeRecipes = loadAllFiles(manager, "fake_recipes", new ArrayList<>(), EmcLoader::loadFakeRecipes);
32
33 Emc.reloadData(itemValues, itemTagValues, blockTagValues, fakeRecipes);
34 }
35
36 private static <T> T loadAllFiles(
37 ResourceManager manager,
38 String path,
39 T arg,
40 Loader<T> loader
41 ) {
42 manager.listResources(
43 ErisAlchemy.ID + "/" + path,
44 loc -> loc.getPath().endsWith(".json") || loc.getPath().endsWith(".json5")
45 ).forEach((id, res) -> {
46 ErisAlchemy.LOGGER.info("Loading {}:{}...", id.getNamespace(), id.getPath());
47 try (var is = res.open()) {
48 loader.loadFile(arg, id, is);
49 } catch (IOException e) {
50 ErisAlchemy.LOGGER.error(
51 "Error occured while reading {}:{}",
52 id.getNamespace(),
53 id.getPath(),
54 e
55 );
56 }
57 });
58 return arg;
59 }
60
61 private static void loadEmcValues(Map<ResourceLocation, OptionalDouble> map, ResourceLocation id, InputStream is)
62 throws IOException
63 {
64 try (var reader = new InputStreamReader(is)) {
65 var json = GSON.fromJson(reader, new TypeToken<Map<ResourceLocation, Double>>(){});
66 json.forEach((item, newEmcRaw) -> {
67 var newEmc = newEmcRaw == null ? OptionalDouble.empty() : OptionalDouble.of(newEmcRaw);
68 var oldEmc = map.get(item);
69 if (oldEmc != null && !newEmc.equals(oldEmc)) {
70 var oldStr = oldEmc.isEmpty() ? "NONE" : Double.toString(oldEmc.getAsDouble());
71 var newStr = newEmc.isEmpty() ? "NONE" : Double.toString(newEmc.getAsDouble());
72 ErisAlchemy.LOGGER.warn(
73 "Redefining the EMC value for {} from {} to {}",
74 item,
75 oldStr,
76 newStr
77 );
78 }
79 map.put(item, newEmc);
80 });
81 }
82 }
83
84 private static void loadFakeRecipes(List<SimplifiedRecipe> recipes, ResourceLocation id, InputStream is)
85 throws IOException
86 {
87 try (var reader = new InputStreamReader(is)) {
88 var json = GSON.fromJson(reader, new TypeToken<List<SimplifiedRecipe>>(){});
89 recipes.addAll(json);
90 }
91 }
92
93 @FunctionalInterface
94 private interface Loader<T> {
95 void loadFile(T arg, ResourceLocation id, InputStream is) throws IOException;
96 }
97
98 private EmcLoader() {}
99}
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/ErisAlchemy.java b/src/main/java/lv/enes/mc/eris_alchemy/ErisAlchemy.java
index bb804b3..bb84e18 100644
--- a/src/main/java/lv/enes/mc/eris_alchemy/ErisAlchemy.java
+++ b/src/main/java/lv/enes/mc/eris_alchemy/ErisAlchemy.java
@@ -1,18 +1,27 @@
1package lv.enes.mc.eris_alchemy; 1package lv.enes.mc.eris_alchemy;
2 2
3import com.google.gson.Gson;
4import com.google.gson.GsonBuilder;
3import net.fabricmc.fabric.api.itemgroup.v1.FabricItemGroup; 5import net.fabricmc.fabric.api.itemgroup.v1.FabricItemGroup;
4import net.minecraft.core.Registry; 6import net.minecraft.core.Registry;
5import net.minecraft.core.registries.BuiltInRegistries; 7import net.minecraft.core.registries.BuiltInRegistries;
6import net.minecraft.network.chat.Component; 8import net.minecraft.network.chat.Component;
7import net.minecraft.resources.ResourceLocation; 9import net.minecraft.resources.ResourceLocation;
10import net.minecraft.server.packs.PackType;
8import net.minecraft.world.item.CreativeModeTab; 11import net.minecraft.world.item.CreativeModeTab;
9import net.minecraft.world.item.ItemStack; 12import net.minecraft.world.item.ItemStack;
10import org.quiltmc.loader.api.ModContainer; 13import org.quiltmc.loader.api.ModContainer;
11import org.quiltmc.qsl.base.api.entrypoint.ModInitializer; 14import org.quiltmc.qsl.base.api.entrypoint.ModInitializer;
15import org.quiltmc.qsl.resource.loader.api.ResourceLoader;
12import org.slf4j.Logger; 16import org.slf4j.Logger;
13import org.slf4j.LoggerFactory; 17import org.slf4j.LoggerFactory;
14 18
15public class ErisAlchemy implements ModInitializer { 19public class ErisAlchemy implements ModInitializer {
20 public static final Gson GSON = new GsonBuilder()
21 .registerTypeAdapter(ResourceLocation.class, new ResourceLocation.Serializer())
22 .registerTypeAdapter(SimplifiedRecipe.class, new SimplifiedRecipe.Deserializer())
23 .create();
24
16 public static final String ID = "eris_alchemy"; 25 public static final String ID = "eris_alchemy";
17 public static final Logger LOGGER = LoggerFactory.getLogger(ID); 26 public static final Logger LOGGER = LoggerFactory.getLogger(ID);
18 27
@@ -31,6 +40,8 @@ public class ErisAlchemy implements ModInitializer {
31 throw new RuntimeException("Hardcoded mod ID doesn't match the configured one!"); 40 throw new RuntimeException("Hardcoded mod ID doesn't match the configured one!");
32 } 41 }
33 42
43 ResourceLoader.get(PackType.SERVER_DATA).registerReloader(EmcLoader.INSTANCE);
44
34 Registry.register(BuiltInRegistries.CREATIVE_MODE_TAB, new ResourceLocation(ID, "item_group"), ITEM_GROUP); 45 Registry.register(BuiltInRegistries.CREATIVE_MODE_TAB, new ResourceLocation(ID, "item_group"), ITEM_GROUP);
35 46
36 ErisAlchemyRegistry.BlockEntities.consume( 47 ErisAlchemyRegistry.BlockEntities.consume(
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/SimplifiedRecipe.java b/src/main/java/lv/enes/mc/eris_alchemy/SimplifiedRecipe.java
new file mode 100644
index 0000000..ef69b84
--- /dev/null
+++ b/src/main/java/lv/enes/mc/eris_alchemy/SimplifiedRecipe.java
@@ -0,0 +1,89 @@
1package lv.enes.mc.eris_alchemy;
2
3import com.google.gson.*;
4import jakarta.annotation.Nonnull;
5import lv.enes.mc.eris_alchemy.utils.RecipeUtils;
6import net.minecraft.core.RegistryAccess;
7import net.minecraft.core.registries.BuiltInRegistries;
8import net.minecraft.resources.ResourceLocation;
9import net.minecraft.world.item.ItemStack;
10import net.minecraft.world.item.crafting.Ingredient;
11import net.minecraft.world.item.crafting.Recipe;
12import net.minecraft.world.item.crafting.ShapedRecipe;
13
14import java.lang.reflect.Type;
15import java.util.List;
16
17public record SimplifiedRecipe(ItemStack output, List<ItemStack> remainder, List<Ingredient> input) {
18 public SimplifiedRecipe(Recipe<?> recipe, RegistryAccess registryAccess) {
19 this(
20 RecipeUtils.getOutput(recipe, registryAccess),
21 List.of(), // TODO:
22 RecipeUtils.getIngredients(recipe).stream().filter(ingredient -> !ingredient.isEmpty()).toList()
23 );
24 }
25
26 static class Deserializer implements JsonDeserializer<SimplifiedRecipe> {
27 @Nonnull
28 @Override
29 public SimplifiedRecipe deserialize(
30 JsonElement jsonElement,
31 Type type,
32 JsonDeserializationContext jsonDeserializationContext
33 ) throws JsonParseException {
34 if (!jsonElement.isJsonObject()) {
35 throw new JsonParseException("Recipe must be an object");
36 }
37 var obj = jsonElement.getAsJsonObject();
38
39 if (obj.get("output") == null || obj.get("input") == null) {
40 throw new JsonParseException("Recipe must have 'output' and 'input' fields");
41 }
42
43 var output = parseOutputOrRemainder(obj.get("output"));
44 var remainder = parseRemainders(obj.get("remainder"));
45 var input = parseInputs(obj.get("input"));
46 return new SimplifiedRecipe(output, remainder, input);
47 }
48
49 private List<Ingredient> parseInputs(JsonElement el) {
50 if (el.isJsonArray()) {
51 return el.getAsJsonArray().asList().stream().map(this::parseInput).map(Ingredient::of).toList();
52 }
53
54 return List.of(Ingredient.of(parseInput(el)));
55 }
56
57 private ItemStack parseInput(JsonElement el) {
58 if (el.isJsonObject()) {
59 return ShapedRecipe.itemStackFromJson(el.getAsJsonObject());
60 } else if (el.isJsonPrimitive() && el.getAsJsonPrimitive().isString()) {
61 var id = new ResourceLocation(el.getAsString());
62 return BuiltInRegistries.ITEM.get(id).getDefaultInstance();
63 } else {
64 throw new JsonParseException("Every recipe input should be an object or a string");
65 }
66 }
67
68 private ItemStack parseOutputOrRemainder(JsonElement el) {
69 if (el.isJsonObject()) {
70 return ShapedRecipe.itemStackFromJson(el.getAsJsonObject());
71 } else if (el.isJsonPrimitive() && el.getAsJsonPrimitive().isString()) {
72 var id = new ResourceLocation(el.getAsString());
73 return BuiltInRegistries.ITEM.get(id).getDefaultInstance();
74 } else {
75 throw new JsonParseException("Recipe's output or remainder must be an object or a string");
76 }
77 }
78
79 private List<ItemStack> parseRemainders(JsonElement el) {
80 if (el == null) {
81 return List.of();
82 } else if (el.isJsonArray()) {
83 return el.getAsJsonArray().asList().stream().map(this::parseOutputOrRemainder).toList();
84 } else {
85 return List.of(parseOutputOrRemainder(el));
86 }
87 }
88 }
89}
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/block/EnergyCondenserBlock.java b/src/main/java/lv/enes/mc/eris_alchemy/block/EnergyCondenserBlock.java
index 86ac061..af58fc6 100644
--- a/src/main/java/lv/enes/mc/eris_alchemy/block/EnergyCondenserBlock.java
+++ b/src/main/java/lv/enes/mc/eris_alchemy/block/EnergyCondenserBlock.java
@@ -2,7 +2,7 @@ package lv.enes.mc.eris_alchemy.block;
2 2
3import jakarta.annotation.Nonnull; 3import jakarta.annotation.Nonnull;
4import jakarta.annotation.Nullable; 4import jakarta.annotation.Nullable;
5import lv.enes.mc.eris_alchemy.EMC; 5import lv.enes.mc.eris_alchemy.Emc;
6import lv.enes.mc.eris_alchemy.EmcStorage; 6import lv.enes.mc.eris_alchemy.EmcStorage;
7import lv.enes.mc.eris_alchemy.ErisAlchemyRegistry; 7import lv.enes.mc.eris_alchemy.ErisAlchemyRegistry;
8import lv.enes.mc.eris_alchemy.block.entity.EnergyCondenserEntity; 8import lv.enes.mc.eris_alchemy.block.entity.EnergyCondenserEntity;
@@ -33,7 +33,7 @@ public class EnergyCondenserBlock extends ChestLikeBlock<EnergyCondenserEntity>
33 TooltipFlag options 33 TooltipFlag options
34 ) { 34 ) {
35 if (getStoredEmc(stack) >= 0.1) { 35 if (getStoredEmc(stack) >= 0.1) {
36 tooltip.add(Component.literal("Stored EMC: %s".formatted(EMC.formatEmc(getStoredEmc(stack))))); 36 tooltip.add(Component.literal("Stored EMC: %s".formatted(Emc.formatEmc(getStoredEmc(stack)))));
37 } 37 }
38 } 38 }
39 39
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/block/entity/EnergyCondenserEntity.java b/src/main/java/lv/enes/mc/eris_alchemy/block/entity/EnergyCondenserEntity.java
index 0f39ccb..a264722 100644
--- a/src/main/java/lv/enes/mc/eris_alchemy/block/entity/EnergyCondenserEntity.java
+++ b/src/main/java/lv/enes/mc/eris_alchemy/block/entity/EnergyCondenserEntity.java
@@ -1,7 +1,7 @@
1package lv.enes.mc.eris_alchemy.block.entity; 1package lv.enes.mc.eris_alchemy.block.entity;
2 2
3import jakarta.annotation.Nonnull; 3import jakarta.annotation.Nonnull;
4import lv.enes.mc.eris_alchemy.EMC; 4import lv.enes.mc.eris_alchemy.Emc;
5import lv.enes.mc.eris_alchemy.ErisAlchemyRegistry.BlockEntities; 5import lv.enes.mc.eris_alchemy.ErisAlchemyRegistry.BlockEntities;
6import lv.enes.mc.eris_alchemy.ErisAlchemyRegistry.Blocks; 6import lv.enes.mc.eris_alchemy.ErisAlchemyRegistry.Blocks;
7import lv.enes.mc.eris_alchemy.ErisAlchemyRegistry.Materials; 7import lv.enes.mc.eris_alchemy.ErisAlchemyRegistry.Materials;
@@ -81,7 +81,7 @@ public class EnergyCondenserEntity extends ChestLikeEntity implements ExtendedSc
81 @Override 81 @Override
82 public void tick(Level world, BlockPos pos, BlockState state) { 82 public void tick(Level world, BlockPos pos, BlockState state) {
83 super.tick(world, pos, state); 83 super.tick(world, pos, state);
84 EMC.getInstance(world).get(items.get(0)).ifPresent(cost -> { 84 Emc.getInstance(world).get(items.get(0)).ifPresent(cost -> {
85 tryConsumeEmc(world, cost); 85 tryConsumeEmc(world, cost);
86 tryCloneTemplate(cost); 86 tryCloneTemplate(cost);
87 }); 87 });
@@ -128,7 +128,7 @@ public class EnergyCondenserEntity extends ChestLikeEntity implements ExtendedSc
128 return; 128 return;
129 } 129 }
130 130
131 var emc = EMC.getInstance(world); 131 var emc = Emc.getInstance(world);
132 var template = items.get(0); 132 var template = items.get(0);
133 var sacrifice = items.stream() 133 var sacrifice = items.stream()
134 .skip(1) // skip the template 134 .skip(1) // skip the template
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/client/EnergyCondenserScreen.java b/src/main/java/lv/enes/mc/eris_alchemy/client/EnergyCondenserScreen.java
index b6762c8..7b9871b 100644
--- a/src/main/java/lv/enes/mc/eris_alchemy/client/EnergyCondenserScreen.java
+++ b/src/main/java/lv/enes/mc/eris_alchemy/client/EnergyCondenserScreen.java
@@ -1,6 +1,6 @@
1package lv.enes.mc.eris_alchemy.client; 1package lv.enes.mc.eris_alchemy.client;
2 2
3import lv.enes.mc.eris_alchemy.EMC; 3import lv.enes.mc.eris_alchemy.Emc;
4import lv.enes.mc.eris_alchemy.ErisAlchemy; 4import lv.enes.mc.eris_alchemy.ErisAlchemy;
5import lv.enes.mc.eris_alchemy.menu.EnergyCondenserMenu; 5import lv.enes.mc.eris_alchemy.menu.EnergyCondenserMenu;
6import net.minecraft.client.gui.GuiGraphics; 6import net.minecraft.client.gui.GuiGraphics;
@@ -36,7 +36,7 @@ public class EnergyCondenserScreen extends ChestLikeScreen<EnergyCondenserMenu>
36 36
37 @Override 37 @Override
38 protected void renderLabels(GuiGraphics graphics, int mouseX, int mouseY) { 38 protected void renderLabels(GuiGraphics graphics, int mouseX, int mouseY) {
39 graphics.drawString(font, EMC.formatEmc(menu.getStoredEmc()), 28, 6, 0xFFFFFF); 39 graphics.drawString(font, Emc.formatEmc(menu.getStoredEmc()), 28, 6, 0xFFFFFF);
40 } 40 }
41 41
42 @Override 42 @Override
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/client/ErisAlchemyClient.java b/src/main/java/lv/enes/mc/eris_alchemy/client/ErisAlchemyClient.java
index a69d2e1..f4de045 100644
--- a/src/main/java/lv/enes/mc/eris_alchemy/client/ErisAlchemyClient.java
+++ b/src/main/java/lv/enes/mc/eris_alchemy/client/ErisAlchemyClient.java
@@ -1,6 +1,6 @@
1package lv.enes.mc.eris_alchemy.client; 1package lv.enes.mc.eris_alchemy.client;
2 2
3import lv.enes.mc.eris_alchemy.EMC; 3import lv.enes.mc.eris_alchemy.Emc;
4import net.fabricmc.fabric.api.client.rendering.v1.BuiltinItemRendererRegistry; 4import net.fabricmc.fabric.api.client.rendering.v1.BuiltinItemRendererRegistry;
5import net.minecraft.client.gui.screens.MenuScreens; 5import net.minecraft.client.gui.screens.MenuScreens;
6import net.minecraft.client.renderer.blockentity.BlockEntityRenderers; 6import net.minecraft.client.renderer.blockentity.BlockEntityRenderers;
@@ -18,9 +18,12 @@ public class ErisAlchemyClient implements ClientModInitializer {
18 ErisAlchemyClientRegistry.MenuScreens.consume(MenuScreens::register); 18 ErisAlchemyClientRegistry.MenuScreens.consume(MenuScreens::register);
19 19
20 ItemTooltipCallback.EVENT.register((stack, player, context, tooltip) -> { 20 ItemTooltipCallback.EVENT.register((stack, player, context, tooltip) -> {
21 var world = player == null ? null : player.level(); 21 if (player == null) {
22 var emc = EMC.getInstance(world).get(stack); 22 return;
23 emc.ifPresent(value -> tooltip.add(Component.literal("EMC %s".formatted(EMC.formatEmc(value))))); 23 }
24
25 var emc = Emc.getInstance(player.level()).get(stack);
26 emc.ifPresent(value -> tooltip.add(Component.literal("EMC %s".formatted(Emc.formatEmc(value)))));
24 }); 27 });
25 } 28 }
26} 29}
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/mixin/CoralBlockMixin.java b/src/main/java/lv/enes/mc/eris_alchemy/mixin/CoralBlockMixin.java
deleted file mode 100644
index d8024c9..0000000
--- a/src/main/java/lv/enes/mc/eris_alchemy/mixin/CoralBlockMixin.java
+++ /dev/null
@@ -1,20 +0,0 @@
1package lv.enes.mc.eris_alchemy.mixin;
2
3import lv.enes.mc.eris_alchemy.utils.CoralUtils;
4import net.minecraft.world.level.block.Block;
5import net.minecraft.world.level.block.CoralBlock;
6import org.spongepowered.asm.mixin.Final;
7import org.spongepowered.asm.mixin.Mixin;
8import org.spongepowered.asm.mixin.Shadow;
9
10@Mixin(CoralBlock.class)
11public abstract class CoralBlockMixin implements CoralUtils.CoralSuper {
12 @Final
13 @Shadow
14 private Block deadBlock;
15
16 @Override
17 public Block lv_enes_mc$getDead() {
18 return deadBlock;
19 }
20}
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/mixin/CoralFanBlockMixin.java b/src/main/java/lv/enes/mc/eris_alchemy/mixin/CoralFanBlockMixin.java
deleted file mode 100644
index 86ab8f6..0000000
--- a/src/main/java/lv/enes/mc/eris_alchemy/mixin/CoralFanBlockMixin.java
+++ /dev/null
@@ -1,20 +0,0 @@
1package lv.enes.mc.eris_alchemy.mixin;
2
3import lv.enes.mc.eris_alchemy.utils.CoralUtils;
4import net.minecraft.world.level.block.Block;
5import net.minecraft.world.level.block.CoralFanBlock;
6import org.spongepowered.asm.mixin.Final;
7import org.spongepowered.asm.mixin.Mixin;
8import org.spongepowered.asm.mixin.Shadow;
9
10@Mixin(CoralFanBlock.class)
11public abstract class CoralFanBlockMixin implements CoralUtils.CoralSuper {
12 @Final
13 @Shadow
14 private Block deadBlock;
15
16 @Override
17 public Block lv_enes_mc$getDead() {
18 return deadBlock;
19 }
20}
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/mixin/CoralPlantBlockMixin.java b/src/main/java/lv/enes/mc/eris_alchemy/mixin/CoralPlantBlockMixin.java
deleted file mode 100644
index a5614f9..0000000
--- a/src/main/java/lv/enes/mc/eris_alchemy/mixin/CoralPlantBlockMixin.java
+++ /dev/null
@@ -1,20 +0,0 @@
1package lv.enes.mc.eris_alchemy.mixin;
2
3import lv.enes.mc.eris_alchemy.utils.CoralUtils;
4import net.minecraft.world.level.block.Block;
5import net.minecraft.world.level.block.CoralPlantBlock;
6import org.spongepowered.asm.mixin.Final;
7import org.spongepowered.asm.mixin.Mixin;
8import org.spongepowered.asm.mixin.Shadow;
9
10@Mixin(CoralPlantBlock.class)
11public abstract class CoralPlantBlockMixin implements CoralUtils.CoralSuper {
12 @Final
13 @Shadow
14 private Block deadBlock;
15
16 @Override
17 public Block lv_enes_mc$getDead() {
18 return deadBlock;
19 }
20}
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/mixin/CoralWallFanBlockMixin.java b/src/main/java/lv/enes/mc/eris_alchemy/mixin/CoralWallFanBlockMixin.java
deleted file mode 100644
index 8ffa07e..0000000
--- a/src/main/java/lv/enes/mc/eris_alchemy/mixin/CoralWallFanBlockMixin.java
+++ /dev/null
@@ -1,20 +0,0 @@
1package lv.enes.mc.eris_alchemy.mixin;
2
3import lv.enes.mc.eris_alchemy.utils.CoralUtils;
4import net.minecraft.world.level.block.Block;
5import net.minecraft.world.level.block.CoralWallFanBlock;
6import org.spongepowered.asm.mixin.Final;
7import org.spongepowered.asm.mixin.Mixin;
8import org.spongepowered.asm.mixin.Shadow;
9
10@Mixin(CoralWallFanBlock.class)
11public abstract class CoralWallFanBlockMixin implements CoralUtils.CoralSuper {
12 @Final
13 @Shadow
14 private Block deadBlock;
15
16 @Override
17 public Block lv_enes_mc$getDead() {
18 return deadBlock;
19 }
20}
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/utils/AxeUtils.java b/src/main/java/lv/enes/mc/eris_alchemy/utils/AxeUtils.java
deleted file mode 100644
index 22c0bad..0000000
--- a/src/main/java/lv/enes/mc/eris_alchemy/utils/AxeUtils.java
+++ /dev/null
@@ -1,18 +0,0 @@
1package lv.enes.mc.eris_alchemy.utils;
2
3import net.minecraft.world.item.AxeItem;
4import net.minecraft.world.item.Tier;
5import net.minecraft.world.level.block.Block;
6
7import java.util.Map;
8
9/** This extends AxeItem only to read the STRIPPABLES variable :3 */
10public final class AxeUtils extends AxeItem {
11 public static Map<Block, Block> getStrippables() {
12 return STRIPPABLES;
13 }
14
15 private AxeUtils(Tier material, float attackDamage, float attackSpeed, Properties settings) {
16 super(material, attackDamage, attackSpeed, settings);
17 }
18}
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/utils/BlockUtils.java b/src/main/java/lv/enes/mc/eris_alchemy/utils/BlockUtils.java
deleted file mode 100644
index 88b6231..0000000
--- a/src/main/java/lv/enes/mc/eris_alchemy/utils/BlockUtils.java
+++ /dev/null
@@ -1,15 +0,0 @@
1package lv.enes.mc.eris_alchemy.utils;
2
3import net.minecraft.core.registries.BuiltInRegistries;
4import net.minecraft.tags.TagKey;
5import net.minecraft.world.level.block.Block;
6
7import java.util.stream.Stream;
8
9public final class BlockUtils {
10 public static Stream<Block> streamTag(TagKey<Block> tag) {
11 return TagUtils.stream(BuiltInRegistries.BLOCK, tag);
12 }
13
14 private BlockUtils() {}
15}
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/utils/CoralUtils.java b/src/main/java/lv/enes/mc/eris_alchemy/utils/CoralUtils.java
deleted file mode 100644
index 1136c9e..0000000
--- a/src/main/java/lv/enes/mc/eris_alchemy/utils/CoralUtils.java
+++ /dev/null
@@ -1,44 +0,0 @@
1package lv.enes.mc.eris_alchemy.utils;
2
3import net.minecraft.tags.BlockTags;
4import net.minecraft.world.level.block.*;
5
6import java.util.stream.Stream;
7
8public final class CoralUtils {
9 /**
10 * @see lv.enes.mc.eris_alchemy.mixin.CoralBlockMixin
11 * @see lv.enes.mc.eris_alchemy.mixin.CoralFanBlockMixin
12 * @see lv.enes.mc.eris_alchemy.mixin.CoralPlantBlockMixin
13 * @see lv.enes.mc.eris_alchemy.mixin.CoralWallFanBlockMixin
14 */
15 public interface CoralSuper {
16 Block lv_enes_mc$getDead();
17 }
18
19 public static Stream<CoralBlock> streamAllCoralBlocks() {
20 return BlockUtils.streamTag(BlockTags.CORAL_BLOCKS).map(b -> (CoralBlock)b);
21 }
22
23 public static Stream<BaseCoralPlantTypeBlock> streamAllCorals() {
24 return BlockUtils.streamTag(BlockTags.CORALS).map(b -> (BaseCoralPlantTypeBlock)b);
25 }
26
27 public static Stream<Block> streamAllDeadCoralBlocks() {
28 return streamAllCoralBlocks().map(CoralUtils::getDeadCoralBlock);
29 }
30
31 public static Stream<Block> streamAllDeadCorals() {
32 return streamAllCorals().map(CoralUtils::getDeadCoral);
33 }
34
35 public static Block getDeadCoral(BaseCoralPlantTypeBlock live ) {
36 return ((CoralSuper)live).lv_enes_mc$getDead();
37 }
38
39 public static Block getDeadCoralBlock(CoralBlock live) {
40 return ((CoralSuper)live).lv_enes_mc$getDead();
41 }
42
43 private CoralUtils() {}
44}
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/utils/DyeUtils.java b/src/main/java/lv/enes/mc/eris_alchemy/utils/DyeUtils.java
deleted file mode 100644
index 3ceb965..0000000
--- a/src/main/java/lv/enes/mc/eris_alchemy/utils/DyeUtils.java
+++ /dev/null
@@ -1,62 +0,0 @@
1package lv.enes.mc.eris_alchemy.utils;
2
3import net.minecraft.world.item.DyeColor;
4import net.minecraft.world.item.DyeItem;
5import net.minecraft.world.level.block.Block;
6import net.minecraft.world.level.block.Blocks;
7import net.minecraft.world.level.block.ConcretePowderBlock;
8import net.minecraft.world.level.block.ShulkerBoxBlock;
9
10public final class DyeUtils {
11 public static Block getConcrete(DyeColor color) {
12 return switch (color) {
13 case BLACK -> Blocks.BLACK_CONCRETE;
14 case BLUE -> Blocks.BLUE_CONCRETE;
15 case BROWN -> Blocks.BROWN_CONCRETE;
16 case CYAN -> Blocks.CYAN_CONCRETE;
17 case GRAY -> Blocks.GRAY_CONCRETE;
18 case GREEN -> Blocks.GREEN_CONCRETE;
19 case LIGHT_BLUE -> Blocks.LIGHT_BLUE_CONCRETE;
20 case LIGHT_GRAY -> Blocks.LIGHT_GRAY_CONCRETE;
21 case LIME -> Blocks.LIME_CONCRETE;
22 case MAGENTA -> Blocks.MAGENTA_CONCRETE;
23 case ORANGE -> Blocks.ORANGE_CONCRETE;
24 case PINK -> Blocks.PINK_CONCRETE;
25 case PURPLE -> Blocks.PURPLE_CONCRETE;
26 case RED -> Blocks.RED_CONCRETE;
27 case WHITE -> Blocks.WHITE_CONCRETE;
28 case YELLOW -> Blocks.YELLOW_CONCRETE;
29 };
30 }
31
32 public static ConcretePowderBlock getConcretePowder(DyeColor color) {
33 return (ConcretePowderBlock)switch (color) {
34 case BLACK -> Blocks.BLACK_CONCRETE_POWDER;
35 case BLUE -> Blocks.BLUE_CONCRETE_POWDER;
36 case BROWN -> Blocks.BROWN_CONCRETE_POWDER;
37 case CYAN -> Blocks.CYAN_CONCRETE_POWDER;
38 case GRAY -> Blocks.GRAY_CONCRETE_POWDER;
39 case GREEN -> Blocks.GREEN_CONCRETE_POWDER;
40 case LIGHT_BLUE -> Blocks.LIGHT_BLUE_CONCRETE_POWDER;
41 case LIGHT_GRAY -> Blocks.LIGHT_GRAY_CONCRETE_POWDER;
42 case LIME -> Blocks.LIME_CONCRETE_POWDER;
43 case MAGENTA -> Blocks.MAGENTA_CONCRETE_POWDER;
44 case ORANGE -> Blocks.ORANGE_CONCRETE_POWDER;
45 case PINK -> Blocks.PINK_CONCRETE_POWDER;
46 case PURPLE -> Blocks.PURPLE_CONCRETE_POWDER;
47 case RED -> Blocks.RED_CONCRETE_POWDER;
48 case WHITE -> Blocks.WHITE_CONCRETE_POWDER;
49 case YELLOW -> Blocks.YELLOW_CONCRETE_POWDER;
50 };
51 }
52
53 public static DyeItem getDye(DyeColor color) {
54 return DyeItem.byColor(color);
55 }
56
57 public static ShulkerBoxBlock getShulkerBox(DyeColor color) {
58 return (ShulkerBoxBlock)ShulkerBoxBlock.getBlockByColor(color);
59 }
60
61 private DyeUtils() {}
62}
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/utils/ItemUtils.java b/src/main/java/lv/enes/mc/eris_alchemy/utils/ItemUtils.java
index 26d4405..4414d06 100644
--- a/src/main/java/lv/enes/mc/eris_alchemy/utils/ItemUtils.java
+++ b/src/main/java/lv/enes/mc/eris_alchemy/utils/ItemUtils.java
@@ -1,14 +1,22 @@
1package lv.enes.mc.eris_alchemy.utils; 1package lv.enes.mc.eris_alchemy.utils;
2 2
3import net.minecraft.core.Holder;
3import net.minecraft.core.registries.BuiltInRegistries; 4import net.minecraft.core.registries.BuiltInRegistries;
4import net.minecraft.tags.TagKey; 5import net.minecraft.resources.ResourceLocation;
5import net.minecraft.world.item.Item; 6import net.minecraft.world.item.ItemStack;
6 7import net.minecraft.world.level.ItemLike;
7import java.util.stream.Stream;
8 8
9public final class ItemUtils { 9public final class ItemUtils {
10 public static Stream<Item> streamTag(TagKey<Item> tag) { 10 public static <I extends ItemLike> ResourceLocation getId(Holder<I> holder) {
11 return TagUtils.stream(BuiltInRegistries.ITEM, tag); 11 return getId(holder.value());
12 }
13
14 public static ResourceLocation getId(ItemLike item) {
15 return BuiltInRegistries.ITEM.getKey(item.asItem());
16 }
17
18 public static ResourceLocation getId(ItemStack stack) {
19 return getId(stack.getItem());
12 } 20 }
13 21
14 private ItemUtils() {} 22 private ItemUtils() {}
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/utils/TagUtils.java b/src/main/java/lv/enes/mc/eris_alchemy/utils/TagUtils.java
deleted file mode 100644
index 93e577f..0000000
--- a/src/main/java/lv/enes/mc/eris_alchemy/utils/TagUtils.java
+++ /dev/null
@@ -1,16 +0,0 @@
1package lv.enes.mc.eris_alchemy.utils;
2
3import net.minecraft.core.Holder;
4import net.minecraft.core.Registry;
5import net.minecraft.tags.TagKey;
6
7import java.util.stream.Stream;
8import java.util.stream.StreamSupport;
9
10public final class TagUtils {
11 public static <T> Stream<T> stream(Registry<T> registry, TagKey<T> tag) {
12 return StreamSupport.stream(registry.getTagOrEmpty(tag).spliterator(), false).map(Holder::value);
13 }
14
15 private TagUtils() {}
16}
diff --git a/src/main/resources/data/eris_alchemy/eris_alchemy/block_tag_emcs/minecraft.json b/src/main/resources/data/eris_alchemy/eris_alchemy/block_tag_emcs/minecraft.json
new file mode 100644
index 0000000..c271159
--- /dev/null
+++ b/src/main/resources/data/eris_alchemy/eris_alchemy/block_tag_emcs/minecraft.json
@@ -0,0 +1,5 @@
1{
2 "minecraft:base_stone_nether": 1,
3 "minecraft:base_stone_overworld": 1,
4 "minecraft:nylium": 1
5} \ No newline at end of file
diff --git a/src/main/resources/data/eris_alchemy/eris_alchemy/fake_recipes/fake_recipes.json5 b/src/main/resources/data/eris_alchemy/eris_alchemy/fake_recipes/fake_recipes.json5
new file mode 100644
index 0000000..4511005
--- /dev/null
+++ b/src/main/resources/data/eris_alchemy/eris_alchemy/fake_recipes/fake_recipes.json5
@@ -0,0 +1,562 @@
1[{
2 // More oxidised coppers are worth less
3 "output": {
4 "item": "exposed_copper",
5 "count": 4
6 },
7 "input": {
8 "item": "copper_block",
9 "count": 3
10 }
11}, {
12 "output": {
13 "item": "weathered_copper",
14 "count": 4
15 },
16 "input": {
17 "item": "copper_block",
18 "count": 2
19 }
20}, {
21 "output": {
22 "item": "oxidized_copper",
23 "count": 4
24 },
25 "input": {
26 "item": "copper_block",
27 "count": 1
28 }
29}, {
30 // More oxidised coppers are worth less also if they're waxed
31 "output": {
32 "item": "waxed_exposed_copper",
33 "count": 4
34 },
35 "input": {
36 "item": "waxed_copper_block",
37 "count": 3
38 }
39}, {
40 "output": {
41 "item": "waxed_weathered_copper",
42 "count": 4
43 },
44 "input": {
45 "item": "waxed_copper_block",
46 "count": 2
47 }
48}, {
49 "output": {
50 "item": "waxed_oxidized_copper",
51 "count": 4
52 },
53 "input": {
54 "item": "waxed_copper_block",
55 "count": 1
56 }
57}, {
58 // More damaged anvils are worth less
59 "output": {
60 "item": "chipped_anvil",
61 "count": 3
62 },
63 "input": {
64 "item": "anvil",
65 "count": 2
66 }
67}, {
68 "output": {
69 "item": "damaged_anvil",
70 "count": 3
71 },
72 "input": {
73 "item": "anvil",
74 "count": 1
75 }
76}, {
77 // Old oak slabs are the same value as modern ones
78 "output": "petrified_oak_slab",
79 "input": "oak_slab"
80}, {
81 // Chainmail armour is worth the same as normal iron armor
82 "output": "chainmail_helmet",
83 "input": "iron_helmet"
84}, {
85 "output": "chainmail_chestplate",
86 "input": "iron_chestplate"
87}, {
88 "output": "chainmail_leggings",
89 "input": "iron_leggings"
90}, {
91 "output": "chainmail_boots",
92 "input": "iron_boots"
93}, {
94 // Enchanted golden apple is worth uhh 16 times the non-enchanted one :3
95 "output": "enchanted_golden_apple",
96 "input": {
97 "item": "golden_apple",
98 "count": 16
99 }
100}, {
101 // Carving a pumpkin with shears
102 "output": "carved_pumpkin",
103 "remainder": {
104 "item": "pumpkin_seeds",
105 "count": 4
106 },
107 "input": "pumpkin"
108}, {
109 // Gathering honey
110 "output": "honey_bottle",
111 "input": [
112 "honeycomb",
113 "glass_bottle"
114 ]
115}, {
116 // Smithing template duplication recipes but -1 template on both sides
117 "output": "coast_armor_trim_smithing_template",
118 "input": [
119 {
120 "item": "diamond",
121 "count": 7
122 },
123 "cobblestone"
124 ]
125}, {
126 "output": "dune_armor_trim_smithing_template",
127 "input": [
128 {
129 "item": "diamond",
130 "count": 7
131 },
132 "sandstone"
133 ]
134}, {
135 "output": "eye_armor_trim_smithing_template",
136 "input": [
137 {
138 "item": "diamond",
139 "count": 7
140 },
141 "end_stone"
142 ]
143}, {
144 "output": "host_armor_trim_smithing_template",
145 "input": [
146 {
147 "item": "diamond",
148 "count": 7
149 },
150 "terracotta"
151 ]
152}, {
153 "output": "netherite_upgrade_smithing_template",
154 "input": [
155 {
156 "item": "diamond",
157 "count": 7
158 },
159 "netherrack"
160 ]
161}, {
162 "output": "raiser_armor_trim_smithing_template",
163 "input": [
164 {
165 "item": "diamond",
166 "count": 7
167 },
168 "terracotta"
169 ]
170}, {
171 "output": "rib_armor_trim_smithing_template",
172 "input": [
173 {
174 "item": "diamond",
175 "count": 7
176 },
177 "netherrack"
178 ]
179}, {
180 "output": "sentry_armor_trim_smithing_template",
181 "input": [
182 {
183 "item": "diamond",
184 "count": 7
185 },
186 "cobblestone"
187 ]
188}, {
189 "output": "shaper_armor_trim_smithing_template",
190 "input": [
191 {
192 "item": "diamond",
193 "count": 7
194 },
195 "terracotta"
196 ]
197}, {
198 "output": "silence_armor_trim_smithing_template",
199 "input": [
200 {
201 "item": "diamond",
202 "count": 7
203 },
204 "cobbled_deepslate"
205 ]
206}, {
207 "output": "snout_armor_trim_smithing_template",
208 "input": [
209 {
210 "item": "diamond",
211 "count": 7
212 },
213 "blackstone"
214 ]
215}, {
216 "output": "spire_armor_trim_smithing_template",
217 "input": [
218 {
219 "item": "diamond",
220 "count": 7
221 },
222 "purpur_block"
223 ]
224}, {
225 "output": "tide_armor_trim_smithing_template",
226 "input": [
227 {
228 "item": "diamond",
229 "count": 7
230 },
231 "prismarine"
232 ]
233}, {
234 "output": "vex_armor_trim_smithing_template",
235 "input": [
236 {
237 "item": "diamond",
238 "count": 7
239 },
240 "cobblestone"
241 ]
242}, {
243 "output": "ward_armor_trim_smithing_template",
244 "input": [
245 {
246 "item": "diamond",
247 "count": 7
248 },
249 "cobbled_deepslate"
250 ]
251}, {
252 "output": "wayfinder_armor_trim_smithing_template",
253 "input": [
254 {
255 "item": "diamond",
256 "count": 7
257 },
258 "terracotta"
259 ]
260}, {
261 "output": "wild_armor_trim_smithing_template",
262 "input": [
263 {
264 "item": "diamond",
265 "count": 7
266 },
267 "mossy_cobblestone"
268 ]
269}, {
270 "output": "water_bucket",
271 "input": [
272 "bucket",
273 "stone" // Pretend this is water
274 ]
275}, {
276 "output": "lava_bucket",
277 "input": [
278 "bucket",
279 "obsidian" // Pretend this is lava
280 ]
281}, {
282 "output": "powder_snow_bucket",
283 "input": [
284 "bucket",
285 "snow"
286 ]
287}, {
288 "output": "milk_bucket",
289 "input": [
290 "bucket",
291 "wheat" // Pretend this is milk
292 ]
293}, {
294 "output": "cod_bucket",
295 "input": [
296 "cod",
297 "bucket"
298 ]
299}, {
300 "output": "pufferfish_bucket",
301 "input": [
302 "pufferfish",
303 "bucket"
304 ]
305}, {
306 "output": "salmon_bucket",
307 "input": [
308 "salmon",
309 "bucket"
310 ]
311}, {
312 "output": "tropical_fish_bucket",
313 "input": [
314 "tropical_fish",
315 "bucket"
316 ]
317}, {
318 "output": "axolotl_bucket",
319 "input": "tropical_fish_bucket"
320}, {
321 "output": "tadpole_bucket",
322 "input": "axolotl_bucket"
323}, {
324 // disc value is the canon
325 "output": {
326 "item": "disc_fragment_5",
327 "count": 9
328 },
329 "input": "music_disc_5"
330}, {
331 "output": "glow_ink_sac",
332 "input": {
333 "item": "ink_sac",
334 "count": 4
335 }
336}, {
337 "output": "filled_map",
338 "input": "map"
339}, {
340 "output": {
341 "item": "poisonous_potato",
342 "count": 2
343 },
344 "input": "potato"
345}, {
346 "output": "rabbit_foot",
347 "input": {
348 "item": "rabbit",
349 "count": 8
350 }
351}, {
352 // leather horse armor takes same amount of leather as leather leggings
353 // so we do a similar exchange for iron, gold, & diamond
354 "output": "iron_horse_armor",
355 "input": "iron_leggings"
356}, {
357 "output": "golden_horse_armor",
358 "input": "golden_leggings"
359}, {
360 "output": "diamond_horse_armor",
361 "input": "diamond_leggings"
362}, {
363 "output": {
364 "item": "trident",
365 "count": 2
366 },
367 "input": {
368 "item": "iron_sword",
369 "count": 3
370 }
371}, {
372 "output": "suspicious_stew",
373 "input": [
374 "bowl",
375 "brown_mushroom",
376 "red_mushroom",
377 "poppy"
378 ]
379}, {
380 "output": "globe_banner_pattern",
381 "input": "creeper_banner_pattern"
382}, {
383 "output": "piglin_banner_pattern",
384 "input": "creeper_banner_pattern"
385}, {
386 "output": "bell",
387 "input": "spyglass"
388}, {
389 "output": "shroomlight",
390 "input": "glowstone"
391}, {
392 "output": "bee_nest",
393 "input": {
394 "item": "honeycomb",
395 "count": 9
396 }
397}, {
398 "output": "gilded_blackstone",
399 "input": [
400 "blackstone",
401 {
402 "item": "gold_nugget",
403 "count": 4
404 }
405 ]
406}, {
407 "output": "ochre_froglight",
408 "input": "magma_cream"
409}, {
410 "output": "pearlescent_froglight",
411 "input": "magma_cream"
412}, {
413 "output": "verdant_froglight",
414 "input": "magma_cream"
415}, {
416 "output": "black_concrete",
417 "input": "black_concrete_powder"
418}, {
419 "output": "blue_concrete",
420 "input": "blue_concrete_powder"
421}, {
422 "output": "brown_concrete",
423 "input": "brown_concrete_powder"
424}, {
425 "output": "cyan_concrete",
426 "input": "cyan_concrete_powder"
427}, {
428 "output": "gray_concrete",
429 "input": "gray_concrete_powder"
430}, {
431 "output": "green_concrete",
432 "input": "green_concrete_powder"
433}, {
434 "output": "light_blue_concrete",
435 "input": "light_blue_concrete_powder"
436}, {
437 "output": "light_gray_concrete",
438 "input": "light_gray_concrete_powder"
439}, {
440 "output": "lime_concrete",
441 "input": "lime_concrete_powder"
442}, {
443 "output": "magenta_concrete",
444 "input": "magenta_concrete_powder"
445}, {
446 "output": "orange_concrete",
447 "input": "orange_concrete_powder"
448}, {
449 "output": "pink_concrete",
450 "input": "pink_concrete_powder"
451}, {
452 "output": "purple_concrete",
453 "input": "purple_concrete_powder"
454}, {
455 "output": "red_concrete",
456 "input": "red_concrete_powder"
457}, {
458 "output": "white_concrete",
459 "input": "white_concrete_powder"
460}, {
461 "output": "yellow_concrete",
462 "input": "yellow_concrete_powder"
463}, {
464 "output": "black_shulker_box",
465 "input": [
466 "shulker_box",
467 "black_dye"
468 ]
469}, {
470 "output": "blue_shulker_box",
471 "input": [
472 "shulker_box",
473 "blue_dye"
474 ]
475}, {
476 "output": "brown_shulker_box",
477 "input": [
478 "shulker_box",
479 "brown_dye"
480 ]
481}, {
482 "output": "cyan_shulker_box",
483 "input": [
484 "shulker_box",
485 "cyan_dye"
486 ]
487}, {
488 "output": "gray_shulker_box",
489 "input": [
490 "shulker_box",
491 "gray_dye"
492 ]
493}, {
494 "output": "green_shulker_box",
495 "input": [
496 "shulker_box",
497 "green_dye"
498 ]
499}, {
500 "output": "light_blue_shulker_box",
501 "input": [
502 "shulker_box",
503 "light_blue_dye"
504 ]
505}, {
506 "output": "light_gray_shulker_box",
507 "input": [
508 "shulker_box",
509 "light_gray_dye"
510 ]
511}, {
512 "output": "lime_shulker_box",
513 "input": [
514 "shulker_box",
515 "lime_dye"
516 ]
517}, {
518 "output": "magenta_shulker_box",
519 "input": [
520 "shulker_box",
521 "magenta_dye"
522 ]
523}, {
524 "output": "orange_shulker_box",
525 "input": [
526 "shulker_box",
527 "orange_dye"
528 ]
529}, {
530 "output": "pink_shulker_box",
531 "input": [
532 "shulker_box",
533 "pink_dye"
534 ]
535}, {
536 "output": "purple_shulker_box",
537 "input": [
538 "shulker_box",
539 "purple_dye"
540 ]
541}, {
542 "output": "red_shulker_box",
543 "input": [
544 "shulker_box",
545 "red_dye"
546 ]
547}, {
548 "output": "white_shulker_box",
549 "input": [
550 "shulker_box",
551 "white_dye"
552 ]
553}, {
554 "output": "yellow_shulker_box",
555 "input": [
556 "shulker_box",
557 "yellow_dye"
558 ]
559}, {
560 "output": "stripped_bamboo_block",
561 "input": "bamboo_block"
562}] \ No newline at end of file
diff --git a/src/main/resources/data/eris_alchemy/eris_alchemy/item_emcs/minecraft.json b/src/main/resources/data/eris_alchemy/eris_alchemy/item_emcs/minecraft.json
new file mode 100644
index 0000000..d4066ce
--- /dev/null
+++ b/src/main/resources/data/eris_alchemy/eris_alchemy/item_emcs/minecraft.json
@@ -0,0 +1,307 @@
1{
2 "minecraft:air": null,
3 "minecraft:allay_spawn_egg": null,
4 "minecraft:amethyst_cluster": null,
5 "minecraft:amethyst_shard": 1024,
6 "minecraft:ancient_debris": null,
7 "minecraft:apple": 128,
8 "minecraft:axolotl_spawn_egg": null,
9 "minecraft:bamboo": 2,
10 "minecraft:barrier": null,
11 "minecraft:bat_spawn_egg": null,
12 "minecraft:bedrock": null,
13 "minecraft:bee_spawn_egg": null,
14 "minecraft:beef": 64,
15 "minecraft:beetroot": 24,
16 "minecraft:beetroot_seeds": 16,
17 "minecraft:big_dripleaf": 1,
18 "minecraft:black_dye": 8,
19 "minecraft:blaze_rod": 1536,
20 "minecraft:blaze_spawn_egg": null,
21 "minecraft:blue_dye": 8,
22 "minecraft:bone": 96,
23 "minecraft:brain_coral": 1.0,
24 "minecraft:brain_coral_block": 1.0,
25 "minecraft:brain_coral_fan": 1.0,
26 "minecraft:brown_dye": 8,
27 "minecraft:brown_mushroom": 32,
28 "minecraft:brown_mushroom_block": null,
29 "minecraft:bubble_coral": 1.0,
30 "minecraft:bubble_coral_block": 1.0,
31 "minecraft:bubble_coral_fan": 1.0,
32 "minecraft:budding_amethyst": null,
33 "minecraft:bundle": null,
34 "minecraft:cactus": 8,
35 "minecraft:calcite": 1,
36 "minecraft:camel_spawn_egg": null,
37 "minecraft:carrot": 24,
38 "minecraft:cat_spawn_egg": null,
39 "minecraft:cave_spider_spawn_egg": null,
40 "minecraft:chain_command_block": null,
41 "minecraft:chicken": 64,
42 "minecraft:chicken_spawn_egg": null,
43 "minecraft:chorus_flower": 32,
44 "minecraft:chorus_fruit": 32,
45 "minecraft:chorus_plant": 24,
46 "minecraft:clay_ball": 64,
47 "minecraft:coal": 128,
48 "minecraft:cobbled_deepslate": 1,
49 "minecraft:cobblestone": 1,
50 "minecraft:cobweb": 12,
51 "minecraft:cocoa_beans": 8,
52 "minecraft:cod_spawn_egg": null,
53 "minecraft:command_block": null,
54 "minecraft:command_block_minecart": null,
55 "minecraft:copper_ingot": 85,
56 "minecraft:cow_spawn_egg": null,
57 "minecraft:creeper_head": 34816,
58 "minecraft:creeper_spawn_egg": null,
59 "minecraft:crimson_fungus": 24,
60 "minecraft:crimson_roots": 1,
61 "minecraft:crying_obsidian": 64,
62 "minecraft:cyan_dye": 8,
63 "minecraft:dead_brain_coral": 1.0,
64 "minecraft:dead_brain_coral_block": 1.0,
65 "minecraft:dead_brain_coral_fan": 1.0,
66 "minecraft:dead_bubble_coral": 1.0,
67 "minecraft:dead_bubble_coral_block": 1.0,
68 "minecraft:dead_bubble_coral_fan": 1.0,
69 "minecraft:dead_bush": 1,
70 "minecraft:dead_fire_coral": 1.0,
71 "minecraft:dead_fire_coral_block": 1.0,
72 "minecraft:dead_fire_coral_fan": 1.0,
73 "minecraft:dead_horn_coral": 1.0,
74 "minecraft:dead_horn_coral_block": 1.0,
75 "minecraft:dead_horn_coral_fan": 1.0,
76 "minecraft:dead_tube_coral": 1.0,
77 "minecraft:dead_tube_coral_block": 1.0,
78 "minecraft:dead_tube_coral_fan": 1.0,
79 "minecraft:debug_stick": null,
80 "minecraft:diamond": 8192,
81 "minecraft:dirt_path": 1,
82 "minecraft:dolphin_spawn_egg": null,
83 "minecraft:donkey_spawn_egg": null,
84 "minecraft:dragon_breath": 34816,
85 "minecraft:dragon_egg": 139264,
86 "minecraft:dragon_head": 34816,
87 "minecraft:drowned_spawn_egg": null,
88 "minecraft:echo_shard": 128,
89 "minecraft:egg": 32,
90 "minecraft:elder_guardian_spawn_egg": null,
91 "minecraft:elytra": 8196,
92 "minecraft:emerald": 1024,
93 "minecraft:enchanted_book": null,
94 "minecraft:end_portal_frame": null,
95 "minecraft:end_stone": 1,
96 "minecraft:ender_dragon_spawn_egg": null,
97 "minecraft:ender_pearl": 1024,
98 "minecraft:enderman_spawn_egg": null,
99 "minecraft:endermite_spawn_egg": null,
100 "minecraft:evoker_spawn_egg": null,
101 "minecraft:experience_bottle": null,
102 "minecraft:farmland": null,
103 "minecraft:feather": 48,
104 "minecraft:fern": 1,
105 "minecraft:fire_coral": 1.0,
106 "minecraft:fire_coral_block": 1.0,
107 "minecraft:fire_coral_fan": 1.0,
108 "minecraft:firework_star": null,
109 "minecraft:flint": 4,
110 "minecraft:fox_spawn_egg": null,
111 "minecraft:frog_spawn_egg": null,
112 "minecraft:frogspawn": null,
113 "minecraft:ghast_spawn_egg": null,
114 "minecraft:ghast_tear": 4096,
115 "minecraft:glow_berries": 8,
116 "minecraft:glow_lichen": 8,
117 "minecraft:glow_squid_spawn_egg": null,
118 "minecraft:glowstone_dust": 384,
119 "minecraft:goat_horn": 32,
120 "minecraft:goat_spawn_egg": null,
121 "minecraft:gold_ingot": 2048,
122 "minecraft:gold_nugget": 227.556,
123 "minecraft:grass": 1,
124 "minecraft:gravel": 4,
125 "minecraft:gray_dye": 8,
126 "minecraft:green_dye": 8,
127 "minecraft:guardian_spawn_egg": null,
128 "minecraft:gunpowder": 192,
129 "minecraft:hanging_roots": 1,
130 "minecraft:heart_of_the_sea": 4096,
131 "minecraft:hoglin_spawn_egg": null,
132 "minecraft:honeycomb": 24,
133 "minecraft:horn_coral": 1.0,
134 "minecraft:horn_coral_block": 1.0,
135 "minecraft:horn_coral_fan": 1.0,
136 "minecraft:horse_spawn_egg": null,
137 "minecraft:husk_spawn_egg": null,
138 "minecraft:ice": 1,
139 "minecraft:infested_chiseled_stone_bricks": null,
140 "minecraft:infested_cobblestone": null,
141 "minecraft:infested_cracked_stone_bricks": null,
142 "minecraft:infested_deepslate": null,
143 "minecraft:infested_mossy_stone_bricks": null,
144 "minecraft:infested_stone": null,
145 "minecraft:infested_stone_bricks": null,
146 "minecraft:ink_sac": 8,
147 "minecraft:iron_golem_spawn_egg": null,
148 "minecraft:iron_ingot": 256,
149 "minecraft:iron_nugget": 28.4444,
150 "minecraft:jigsaw": null,
151 "minecraft:kelp": 32,
152 "minecraft:knowledge_book": null,
153 "minecraft:lapis_lazuli": 864,
154 "minecraft:large_amethyst_bud": null,
155 "minecraft:large_fern": 1,
156 "minecraft:leather": 64,
157 "minecraft:light": null,
158 "minecraft:light_blue_dye": 8,
159 "minecraft:light_gray_dye": 8,
160 "minecraft:lily_pad": 16,
161 "minecraft:lime_dye": 8,
162 "minecraft:lingering_potion": null,
163 "minecraft:llama_spawn_egg": null,
164 "minecraft:magenta_dye": 8,
165 "minecraft:magma_cube_spawn_egg": null,
166 "minecraft:mangrove_roots": 1,
167 "minecraft:medium_amethyst_bud": null,
168 "minecraft:melon_slice": 144,
169 "minecraft:mooshroom_spawn_egg": null,
170 "minecraft:mud": 1,
171 "minecraft:mule_spawn_egg": null,
172 "minecraft:mushroom_stem": null,
173 "minecraft:mutton": 64,
174 "minecraft:name_tag": null,
175 "minecraft:nautilus_shell": 64,
176 "minecraft:nether_quartz_ore": null,
177 "minecraft:nether_sprouts": 1,
178 "minecraft:nether_star": 139264,
179 "minecraft:nether_wart": 24,
180 "minecraft:netherite_scrap": 16384,
181 "minecraft:obsidian": 64,
182 "minecraft:ocelot_spawn_egg": null,
183 "minecraft:orange_dye": 8,
184 "minecraft:panda_spawn_egg": null,
185 "minecraft:parrot_spawn_egg": null,
186 "minecraft:phantom_membrane": 96,
187 "minecraft:phantom_spawn_egg": null,
188 "minecraft:pig_spawn_egg": null,
189 "minecraft:piglin_brute_spawn_egg": null,
190 "minecraft:piglin_head": 34816,
191 "minecraft:piglin_spawn_egg": null,
192 "minecraft:pillager_spawn_egg": null,
193 "minecraft:pink_dye": 8,
194 "minecraft:pitcher_pod": 8,
195 "minecraft:player_head": 34816,
196 "minecraft:pointed_dripstone": 0.25,
197 "minecraft:polar_bear_spawn_egg": null,
198 "minecraft:porkchop": 64,
199 "minecraft:potato": 24,
200 "minecraft:potion": null,
201 "minecraft:prismarine_crystals": 384,
202 "minecraft:prismarine_shard": 0.25,
203 "minecraft:pufferfish_spawn_egg": null,
204 "minecraft:pumpkin": 144,
205 "minecraft:purple_dye": 8,
206 "minecraft:quartz": 64,
207 "minecraft:rabbit": 64,
208 "minecraft:rabbit_hide": 64,
209 "minecraft:rabbit_spawn_egg": null,
210 "minecraft:ravager_spawn_egg": null,
211 "minecraft:raw_copper": null,
212 "minecraft:raw_copper_block": null,
213 "minecraft:raw_gold": null,
214 "minecraft:raw_gold_block": null,
215 "minecraft:raw_iron": null,
216 "minecraft:raw_iron_block": null,
217 "minecraft:red_dye": 8,
218 "minecraft:red_mushroom": 32,
219 "minecraft:red_mushroom_block": null,
220 "minecraft:redstone": 64,
221 "minecraft:reinforced_deepslate": null,
222 "minecraft:repeating_command_block": null,
223 "minecraft:rotten_flesh": 24,
224 "minecraft:saddle": 192,
225 "minecraft:salmon_spawn_egg": null,
226 "minecraft:sculk": 1,
227 "minecraft:sculk_catalyst": 16,
228 "minecraft:sculk_sensor": 32,
229 "minecraft:sculk_shrieker": 16,
230 "minecraft:sculk_vein": 1,
231 "minecraft:scute": 32,
232 "minecraft:sea_pickle": 1,
233 "minecraft:seagrass": 1,
234 "minecraft:sheep_spawn_egg": null,
235 "minecraft:shulker_shell": 256,
236 "minecraft:shulker_spawn_egg": null,
237 "minecraft:silverfish_spawn_egg": null,
238 "minecraft:skeleton_horse_spawn_egg": null,
239 "minecraft:skeleton_skull": 34816,
240 "minecraft:skeleton_spawn_egg": null,
241 "minecraft:slime_ball": 24,
242 "minecraft:slime_spawn_egg": null,
243 "minecraft:small_amethyst_bud": null,
244 "minecraft:small_dripleaf": 1,
245 "minecraft:sniffer_egg": 32,
246 "minecraft:sniffer_spawn_egg": null,
247 "minecraft:snow_golem_spawn_egg": null,
248 "minecraft:snowball": 1,
249 "minecraft:soul_sand": 49,
250 "minecraft:soul_soil": 49,
251 "minecraft:spawner": null,
252 "minecraft:spider_eye": 128,
253 "minecraft:spider_spawn_egg": null,
254 "minecraft:splash_potion": null,
255 "minecraft:sponge": 48,
256 "minecraft:spore_blossom": 1,
257 "minecraft:squid_spawn_egg": null,
258 "minecraft:stick": 4,
259 "minecraft:stray_spawn_egg": null,
260 "minecraft:strider_spawn_egg": null,
261 "minecraft:string": 12,
262 "minecraft:structure_block": null,
263 "minecraft:structure_void": null,
264 "minecraft:sugar_cane": 32,
265 "minecraft:suspicious_gravel": 4,
266 "minecraft:sweet_berries": 8,
267 "minecraft:tadpole_spawn_egg": null,
268 "minecraft:tall_grass": 1,
269 "minecraft:tipped_arrow": null,
270 "minecraft:torchflower_seeds": 8,
271 "minecraft:totem_of_undying": 4096,
272 "minecraft:trader_llama_spawn_egg": null,
273 "minecraft:tropical_fish_spawn_egg": null,
274 "minecraft:tube_coral": 1.0,
275 "minecraft:tube_coral_block": 1.0,
276 "minecraft:tube_coral_fan": 1.0,
277 "minecraft:turtle_egg": 32,
278 "minecraft:turtle_spawn_egg": null,
279 "minecraft:twisting_vines": 8,
280 "minecraft:vex_spawn_egg": null,
281 "minecraft:villager_spawn_egg": null,
282 "minecraft:vindicator_spawn_egg": null,
283 "minecraft:vine": 8,
284 "minecraft:wandering_trader_spawn_egg": null,
285 "minecraft:warden_spawn_egg": null,
286 "minecraft:warped_fungus": 24,
287 "minecraft:warped_roots": 1,
288 "minecraft:warped_wart_block": 1,
289 "minecraft:weeping_vines": 8,
290 "minecraft:wet_sponge": 48,
291 "minecraft:wheat": 24,
292 "minecraft:wheat_seeds": 16,
293 "minecraft:white_dye": 8,
294 "minecraft:witch_spawn_egg": null,
295 "minecraft:wither_skeleton_skull": 34816,
296 "minecraft:wither_skeleton_spawn_egg": null,
297 "minecraft:wither_spawn_egg": null,
298 "minecraft:wolf_spawn_egg": null,
299 "minecraft:written_book": null,
300 "minecraft:yellow_dye": 8,
301 "minecraft:zoglin_spawn_egg": null,
302 "minecraft:zombie_head": 34816,
303 "minecraft:zombie_horse_spawn_egg": null,
304 "minecraft:zombie_spawn_egg": null,
305 "minecraft:zombie_villager_spawn_egg": null,
306 "minecraft:zombified_piglin_spawn_egg": null
307} \ No newline at end of file
diff --git a/src/main/resources/data/eris_alchemy/eris_alchemy/item_emcs/patchouli.json b/src/main/resources/data/eris_alchemy/eris_alchemy/item_emcs/patchouli.json
new file mode 100644
index 0000000..6940bdf
--- /dev/null
+++ b/src/main/resources/data/eris_alchemy/eris_alchemy/item_emcs/patchouli.json
@@ -0,0 +1,3 @@
1{
2 "patchouli:guide_book": null
3} \ No newline at end of file
diff --git a/src/main/resources/data/eris_alchemy/eris_alchemy/item_tag_emcs/minecraft.json b/src/main/resources/data/eris_alchemy/eris_alchemy/item_tag_emcs/minecraft.json
new file mode 100644
index 0000000..70e4803
--- /dev/null
+++ b/src/main/resources/data/eris_alchemy/eris_alchemy/item_tag_emcs/minecraft.json
@@ -0,0 +1,20 @@
1{
2 "minecraft:coal_ores": null,
3 "minecraft:copper_ores": null,
4 "minecraft:decorated_pot_sherds": 64,
5 "minecraft:diamond_ores": null,
6 "minecraft:dirt": 1,
7 "minecraft:music_discs": 4096,
8 "minecraft:emerald_ores": null,
9 "minecraft:fishes": 64,
10 "minecraft:flowers": 16,
11 "minecraft:gold_ores": null,
12 "minecraft:iron_ores": null,
13 "minecraft:lapis_ores": null,
14 "minecraft:leaves": 1,
15 "minecraft:logs": 32,
16 "minecraft:redstone_ores": null,
17 "minecraft:sand": 1,
18 "minecraft:saplings": 32,
19 "minecraft:wool": 48
20} \ No newline at end of file
diff --git a/src/main/resources/eris_alchemy.mixins.json b/src/main/resources/eris_alchemy.mixins.json
index fb52b89..0fb729a 100644
--- a/src/main/resources/eris_alchemy.mixins.json
+++ b/src/main/resources/eris_alchemy.mixins.json
@@ -8,10 +8,6 @@
8 ], 8 ],
9 "mixins": [ 9 "mixins": [
10 "ContainerOpenersCounterMixin", 10 "ContainerOpenersCounterMixin",
11 "CoralBlockMixin",
12 "CoralFanBlockMixin",
13 "CoralPlantBlockMixin",
14 "CoralWallFanBlockMixin",
15 "RecipeMixin", 11 "RecipeMixin",
16 "SmithingTransformRecipeMixin" 12 "SmithingTransformRecipeMixin"
17 ], 13 ],