summaryrefslogtreecommitdiff
path: root/src/main/java/lv
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/lv')
-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
19 files changed, 441 insertions, 852 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}