From 61c7a99e94ffdde1d5784c73fe501168ade45e77 Mon Sep 17 00:00:00 2001 From: Lorenz Wrobel <43410952+DasBabyPixel@users.noreply.github.com> Date: Fri, 22 May 2026 17:06:51 +0200 Subject: [PATCH 1/4] server-side recipe holders --- .../AbstractCrucibleBlockEntity.java | 7 +-- .../blockentity/BarrelBlockEntity.java | 30 ++++++----- .../blockentity/LavaCrucibleBlockEntity.java | 5 +- .../MechanicalHammerBlockEntity.java | 9 ++-- .../blockentity/WaterCrucibleBlockEntity.java | 3 +- .../logic/CompressedSieveLogic.java | 3 +- .../blockentity/logic/SieveLogic.java | 6 ++- .../exdeorum/compat/jei/CrucibleCategory.java | 10 ++-- .../compat/jei/ExDeorumJeiPlugin.java | 6 +-- .../loot/CompressedHammerLootModifier.java | 4 +- .../exdeorum/loot/CrookLootModifier.java | 4 +- .../exdeorum/loot/HammerLootModifier.java | 9 ++-- .../exdeorum/recipe/RecipeCaches.java | 52 +++++++++++-------- .../cache/BarrelFluidMixingRecipeCache.java | 7 +-- .../recipe/cache/CrookRecipeCache.java | 11 ++-- .../recipe/cache/CrucibleHeatRecipeCache.java | 23 ++++---- .../cache/FluidTransformationRecipeCache.java | 9 ++-- .../recipe/cache/SieveRecipeCache.java | 20 +++---- .../cache/SingleIngredientRecipeCache.java | 19 +++---- .../exdeorum/registry/ERecipeTypes.java | 4 +- 20 files changed, 137 insertions(+), 104 deletions(-) diff --git a/src/main/java/thedarkcolour/exdeorum/blockentity/AbstractCrucibleBlockEntity.java b/src/main/java/thedarkcolour/exdeorum/blockentity/AbstractCrucibleBlockEntity.java index 60fd496a..ffa099a2 100644 --- a/src/main/java/thedarkcolour/exdeorum/blockentity/AbstractCrucibleBlockEntity.java +++ b/src/main/java/thedarkcolour/exdeorum/blockentity/AbstractCrucibleBlockEntity.java @@ -31,6 +31,7 @@ import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; +import net.minecraft.world.item.crafting.RecipeHolder; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; @@ -186,7 +187,7 @@ public abstract class AbstractCrucibleBlockEntity extends ETankBlockEntity { // Gets a crucible recipe, using the cache if possible @Nullable - protected abstract CrucibleRecipe getRecipe(ItemStack item); + protected abstract RecipeHolder getRecipe(ItemStack item); /** * Tries to melt the specified item into the crucible. @@ -206,7 +207,7 @@ public abstract class AbstractCrucibleBlockEntity extends ETankBlockEntity { if (this.level != null && this.level.isClientSide) { return true; } - var result = recipe.getResult(); + var result = recipe.value().getResult(); var contained = this.tank.getFluid(); var hadPendingSolids = this.solids > 0; shrinkAction.accept(item); @@ -240,7 +241,7 @@ public abstract class AbstractCrucibleBlockEntity extends ETankBlockEntity { var recipe = getRecipe(item); if (recipe != null) { - var result = recipe.getResult(); + var result = recipe.value().getResult(); var contained = this.tank.getFluid(); if (FluidStack.isSameFluidSameComponents(result, contained) || (contained.isEmpty() && canAddToPendingFluid(result))) { diff --git a/src/main/java/thedarkcolour/exdeorum/blockentity/BarrelBlockEntity.java b/src/main/java/thedarkcolour/exdeorum/blockentity/BarrelBlockEntity.java index 25ab33af..6069a94f 100644 --- a/src/main/java/thedarkcolour/exdeorum/blockentity/BarrelBlockEntity.java +++ b/src/main/java/thedarkcolour/exdeorum/blockentity/BarrelBlockEntity.java @@ -36,6 +36,7 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.item.alchemy.PotionContents; import net.minecraft.world.item.alchemy.Potions; +import net.minecraft.world.item.crafting.RecipeHolder; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.BucketPickup; @@ -84,7 +85,7 @@ public class BarrelBlockEntity extends ETankBlockEntity { public final boolean transparent; // Current transformation recipe @Nullable - public FluidTransformationRecipe currentTransformRecipe = null; + public RecipeHolder currentTransformRecipe = null; public BarrelBlockEntity(BlockPos pos, BlockState state) { super(EBlockEntities.BARREL.get(), pos, state); @@ -266,11 +267,12 @@ public class BarrelBlockEntity extends ETankBlockEntity { var itemFluidCap = playerItem.getCapability(Capabilities.FluidHandler.ITEM); if (itemFluidCap != null) { var itemFluid = itemFluidCap.drain(1000, IFluidHandler.FluidAction.SIMULATE); - BarrelFluidMixingRecipe recipe = getRecipeCaches().getFluidMixingRecipe(this.tank.getFluid(), itemFluid.getFluid()); + var holder = getRecipeCaches().getFluidMixingRecipe(this.tank.getFluid(), itemFluid.getFluid()); // If draining item fluid was possible and tank has enough fluid to mix... - if (recipe != null && this.tank.getFluidAmount() >= recipe.baseFluid().amount() && itemFluid.getAmount() == 1000) { + if (holder != null && this.tank.getFluidAmount() >= holder.value().baseFluid().amount() && itemFluid.getAmount() == 1000) { if (!level.isClientSide) { + var recipe = holder.value(); this.tank.drain(recipe.baseFluid().amount(), IFluidHandler.FluidAction.EXECUTE); setItem(recipe.result().copy()); @@ -370,9 +372,10 @@ public class BarrelBlockEntity extends ETankBlockEntity { return false; } - var recipe = getRecipeCaches().getBarrelMixingRecipe(this.level.getRecipeManager(), playerItem, this.tank.getFluid()); + var holder = getRecipeCaches().getBarrelMixingRecipe(this.level.getRecipeManager(), playerItem, this.tank.getFluid()); - if (recipe != null) { + if (holder != null) { + var recipe = holder.value(); if (!simulate) { // Empty barrel this.tank.drain(recipe.fluid.amount(), IFluidHandler.FluidAction.EXECUTE); @@ -391,9 +394,9 @@ public class BarrelBlockEntity extends ETankBlockEntity { if (simulate) { return getRecipeCaches().isCompostable(stack); } else { - var recipe = getRecipeCaches().getBarrelCompostRecipe(stack); - if (recipe != null) { - addCompost(stack, recipe.getVolume()); + var holder = getRecipeCaches().getBarrelCompostRecipe(stack); + if (holder != null) { + addCompost(stack, holder.value().getVolume()); return true; } else { return false; @@ -437,9 +440,10 @@ public class BarrelBlockEntity extends ETankBlockEntity { var aboveFluid = aboveFluidState.getType(); if (aboveFluid != Fluids.EMPTY) { - BarrelFluidMixingRecipe recipe = getRecipeCaches().getFluidMixingRecipe(this.tank.getFluid(), aboveFluid instanceof FlowingFluid flowing ? flowing.getSource() : aboveFluid); + var holder = getRecipeCaches().getFluidMixingRecipe(this.tank.getFluid(), aboveFluid instanceof FlowingFluid flowing ? flowing.getSource() : aboveFluid); - if (recipe != null) { + if (holder != null) { + var recipe = holder.value(); // If additive is not consumed, just craft // If additive is consumed, check that the additive can be consumed before crafting if (!recipe.consumesAdditive()) { @@ -467,7 +471,7 @@ public class BarrelBlockEntity extends ETankBlockEntity { this.currentTransformRecipe = getRecipeCaches().getFluidTransformationRecipe(this.tank.getFluid().getFluid(), belowState); if (this.currentTransformRecipe != null) { - var color = this.currentTransformRecipe.resultColor(); + var color = this.currentTransformRecipe.value().resultColor(); this.r = (short) ((color >> 16) & 0xff); this.g = (short) ((color >> 8) & 0xff); this.b = (short) ((color) & 0xff); @@ -501,7 +505,7 @@ public class BarrelBlockEntity extends ETankBlockEntity { } barrel.markUpdated(); } else if (barrel.currentTransformRecipe != null) { - var recipe = barrel.currentTransformRecipe; + var recipe = barrel.currentTransformRecipe.value(); var catalysts = 0; for (var cursor : BlockPos.betweenClosed(pos.getX() - 1, pos.getY() - 1, pos.getZ() - 1, pos.getX() + 1, pos.getY() - 1, pos.getZ() + 1)) { @@ -528,7 +532,7 @@ public class BarrelBlockEntity extends ETankBlockEntity { if (catalysts == 0) { barrel.currentTransformRecipe = null; } else { - barrel.progress += catalysts * (1.0f / barrel.currentTransformRecipe.duration()); + barrel.progress += catalysts * (1.0f / barrel.currentTransformRecipe.value().duration()); if (barrel.progress >= 1.0f - Mth.EPSILON) { // Reset progress diff --git a/src/main/java/thedarkcolour/exdeorum/blockentity/LavaCrucibleBlockEntity.java b/src/main/java/thedarkcolour/exdeorum/blockentity/LavaCrucibleBlockEntity.java index 21ad4224..59c0ad1c 100644 --- a/src/main/java/thedarkcolour/exdeorum/blockentity/LavaCrucibleBlockEntity.java +++ b/src/main/java/thedarkcolour/exdeorum/blockentity/LavaCrucibleBlockEntity.java @@ -20,6 +20,7 @@ package thedarkcolour.exdeorum.blockentity; import net.minecraft.core.BlockPos; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.RecipeHolder; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.BlockState; @@ -35,11 +36,11 @@ public class LavaCrucibleBlockEntity extends AbstractCrucibleBlockEntity { @Override public int getMeltingRate() { - return getRecipeCaches().getHeatValue(this.level.getBlockState(getBlockPos().below())); + return getRecipeCaches().getHeatRecipe(this.level.getBlockState(getBlockPos().below())).value().heatValue(); } @Override - protected @Nullable CrucibleRecipe getRecipe(ItemStack item) { + protected @Nullable RecipeHolder getRecipe(ItemStack item) { return getRecipeCaches().getLavaCrucibleRecipe(item); } diff --git a/src/main/java/thedarkcolour/exdeorum/blockentity/MechanicalHammerBlockEntity.java b/src/main/java/thedarkcolour/exdeorum/blockentity/MechanicalHammerBlockEntity.java index da187ce1..28eb53d8 100644 --- a/src/main/java/thedarkcolour/exdeorum/blockentity/MechanicalHammerBlockEntity.java +++ b/src/main/java/thedarkcolour/exdeorum/blockentity/MechanicalHammerBlockEntity.java @@ -28,6 +28,7 @@ import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.RecipeHolder; import net.minecraft.world.item.enchantment.Enchantments; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.state.BlockState; @@ -122,13 +123,13 @@ public class MechanicalHammerBlockEntity extends AbstractMachineBlockEntity canFitResultIntoOutput(ItemStack input) { var output = this.inventory.getStackInSlot(OUTPUT_SLOT); if (output.isEmpty() || output.getCount() < output.getMaxStackSize()) { var recipe = getRecipeCaches().getHammerRecipe(input.getItem()); - if (recipe != null && (output.isEmpty() || ItemStack.isSameItemSameComponents(recipe.result, output))) { + if (recipe != null && (output.isEmpty() || ItemStack.isSameItemSameComponents(recipe.value().result, output))) { return recipe; } } @@ -149,13 +150,13 @@ public class MechanicalHammerBlockEntity extends AbstractMachineBlockEntity getRecipe(ItemStack item) { return getRecipeCaches().getWaterCrucibleRecipe(item); } diff --git a/src/main/java/thedarkcolour/exdeorum/blockentity/logic/CompressedSieveLogic.java b/src/main/java/thedarkcolour/exdeorum/blockentity/logic/CompressedSieveLogic.java index cc40700a..5568acd2 100644 --- a/src/main/java/thedarkcolour/exdeorum/blockentity/logic/CompressedSieveLogic.java +++ b/src/main/java/thedarkcolour/exdeorum/blockentity/logic/CompressedSieveLogic.java @@ -1,6 +1,7 @@ package thedarkcolour.exdeorum.blockentity.logic; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.RecipeHolder; import thedarkcolour.exdeorum.recipe.sieve.SieveRecipe; import java.util.List; @@ -11,7 +12,7 @@ public class CompressedSieveLogic extends SieveLogic { } @Override - protected List getDropsFor(ItemStack contents) { + protected List> getDropsFor(ItemStack contents) { return this.owner.getRecipeCaches().getCompressedSieveRecipes(this.mesh.getItem(), contents); } } diff --git a/src/main/java/thedarkcolour/exdeorum/blockentity/logic/SieveLogic.java b/src/main/java/thedarkcolour/exdeorum/blockentity/logic/SieveLogic.java index b292fe84..4ac33ae1 100644 --- a/src/main/java/thedarkcolour/exdeorum/blockentity/logic/SieveLogic.java +++ b/src/main/java/thedarkcolour/exdeorum/blockentity/logic/SieveLogic.java @@ -28,6 +28,7 @@ import net.minecraft.util.Mth; import net.minecraft.util.RandomSource; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; +import net.minecraft.world.item.crafting.RecipeHolder; import net.minecraft.world.item.enchantment.Enchantments; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.storage.loot.LootContext; @@ -96,7 +97,8 @@ public class SieveLogic { var handledAnyDrops = false; var hasDrops = false; - for (SieveRecipe recipe : getDropsFor(this.contents)) { + for (RecipeHolder holder : getDropsFor(this.contents)) { + var recipe = holder.value(); var amount = getResultAmount(recipe, context, rand); // Split overflowing stacks (64+) into multiple stacks @@ -129,7 +131,7 @@ public class SieveLogic { this.owner.markUpdated(); } - protected List getDropsFor(ItemStack contents) { + protected List> getDropsFor(ItemStack contents) { return this.owner.getRecipeCaches().getSieveRecipes(this.mesh.getItem(), contents); } diff --git a/src/main/java/thedarkcolour/exdeorum/compat/jei/CrucibleCategory.java b/src/main/java/thedarkcolour/exdeorum/compat/jei/CrucibleCategory.java index 1ffa1f5a..24c51456 100644 --- a/src/main/java/thedarkcolour/exdeorum/compat/jei/CrucibleCategory.java +++ b/src/main/java/thedarkcolour/exdeorum/compat/jei/CrucibleCategory.java @@ -29,7 +29,7 @@ import thedarkcolour.exdeorum.data.TranslationKeys; import thedarkcolour.exdeorum.material.DefaultMaterials; import thedarkcolour.exdeorum.recipe.crucible.CrucibleRecipe; -abstract class CrucibleCategory extends OneToOneCategory { +abstract class CrucibleCategory extends OneToOneCategory { public CrucibleCategory(IGuiHelper helper, IDrawable arrow, Item iconItem, String titleKey) { super(helper, arrow, helper.createDrawableItemStack(new ItemStack(iconItem)), Component.translatable(titleKey)); } @@ -45,24 +45,24 @@ abstract class CrucibleCategory extends OneToOneCategory { .setFluidRenderer(Math.max(1000, recipe.getResult().getAmount()), false, 16, 16); } - static class LavaCrucible extends CrucibleCategory { + static class LavaCrucible extends CrucibleCategory { public LavaCrucible(IGuiHelper helper, IDrawable arrow) { super(helper, arrow, DefaultMaterials.PORCELAIN_CRUCIBLE.getItem(), TranslationKeys.LAVA_CRUCIBLE_CATEGORY_TITLE); } @Override - public RecipeType getRecipeType() { + public RecipeType getRecipeType() { return ExDeorumJeiPlugin.LAVA_CRUCIBLE; } } - static class WaterCrucible extends CrucibleCategory { + static class WaterCrucible extends CrucibleCategory { public WaterCrucible(IGuiHelper helper, IDrawable arrow) { super(helper, arrow, DefaultMaterials.OAK_CRUCIBLE.getItem(), TranslationKeys.WATER_CRUCIBLE_CATEGORY_TITLE); } @Override - public RecipeType getRecipeType() { + public RecipeType getRecipeType() { return ExDeorumJeiPlugin.WATER_CRUCIBLE; } } diff --git a/src/main/java/thedarkcolour/exdeorum/compat/jei/ExDeorumJeiPlugin.java b/src/main/java/thedarkcolour/exdeorum/compat/jei/ExDeorumJeiPlugin.java index d0929ac0..e6f6f1d5 100644 --- a/src/main/java/thedarkcolour/exdeorum/compat/jei/ExDeorumJeiPlugin.java +++ b/src/main/java/thedarkcolour/exdeorum/compat/jei/ExDeorumJeiPlugin.java @@ -79,8 +79,8 @@ public class ExDeorumJeiPlugin implements IModPlugin { static final RecipeType BARREL_COMPOST = recipeType("barrel_compost", BarrelCompostRecipe.class); static final RecipeType BARREL_MIXING = recipeType("barrel_mixing", BarrelMixingRecipe.class); static final RecipeType BARREL_FLUID_MIXING = recipeType("barrel_fluid_mixing", BarrelFluidMixingRecipe.class); - static final RecipeType LAVA_CRUCIBLE = recipeType("lava_crucible", CrucibleRecipe.class); - static final RecipeType WATER_CRUCIBLE = recipeType("water_crucible", CrucibleRecipe.class); + static final RecipeType LAVA_CRUCIBLE = recipeType("lava_crucible", CrucibleRecipe.Lava.class); + static final RecipeType WATER_CRUCIBLE = recipeType("water_crucible", CrucibleRecipe.Water.class); static final RecipeType CRUCIBLE_HEAT_SOURCES = recipeType("crucible_heat_sources", CrucibleHeatSourceRecipe.class); static final RecipeType SIEVE = recipeType("sieve", XeiSieveRecipe.class); static final RecipeType COMPRESSED_SIEVE = recipeType("compressed_sieve", XeiSieveRecipe.class); @@ -232,7 +232,7 @@ public class ExDeorumJeiPlugin implements IModPlugin { if (block instanceof WallTorchBlock) continue; if (block != Blocks.AIR) { - final int newValue = entry.getIntValue(); + final int newValue = entry.getValue().value().heatValue(); values.computeInt(block, (key, value) -> { if (value != null) { diff --git a/src/main/java/thedarkcolour/exdeorum/loot/CompressedHammerLootModifier.java b/src/main/java/thedarkcolour/exdeorum/loot/CompressedHammerLootModifier.java index 065820c8..f88bb070 100644 --- a/src/main/java/thedarkcolour/exdeorum/loot/CompressedHammerLootModifier.java +++ b/src/main/java/thedarkcolour/exdeorum/loot/CompressedHammerLootModifier.java @@ -3,12 +3,14 @@ package thedarkcolour.exdeorum.loot; import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; import net.minecraft.world.item.Item; +import net.minecraft.world.item.crafting.RecipeHolder; import net.minecraft.world.level.storage.loot.LootContext; import net.minecraft.world.level.storage.loot.predicates.LootItemCondition; import net.neoforged.neoforge.common.loot.IGlobalLootModifier; import net.neoforged.neoforge.common.loot.LootModifier; import org.jetbrains.annotations.Nullable; import thedarkcolour.exdeorum.recipe.RecipeUtil; +import thedarkcolour.exdeorum.recipe.hammer.CompressedHammerRecipe; import thedarkcolour.exdeorum.recipe.hammer.HammerRecipe; import thedarkcolour.exdeorum.tag.EItemTags; @@ -25,7 +27,7 @@ public class CompressedHammerLootModifier extends HammerLootModifier { } @Override - protected @Nullable HammerRecipe getRecipe(Item itemForm, LootContext context) { + protected @Nullable RecipeHolder getRecipe(Item itemForm, LootContext context) { return RecipeUtil.getCaches(context.getLevel()).getCompressedHammerRecipe(itemForm); } } diff --git a/src/main/java/thedarkcolour/exdeorum/loot/CrookLootModifier.java b/src/main/java/thedarkcolour/exdeorum/loot/CrookLootModifier.java index 4a5564c6..11510629 100644 --- a/src/main/java/thedarkcolour/exdeorum/loot/CrookLootModifier.java +++ b/src/main/java/thedarkcolour/exdeorum/loot/CrookLootModifier.java @@ -26,6 +26,7 @@ import net.minecraft.tags.BlockTags; import net.minecraft.util.Mth; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; +import net.minecraft.world.item.crafting.RecipeHolder; import net.minecraft.world.item.enchantment.Enchantments; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.storage.loot.LootContext; @@ -58,7 +59,8 @@ public class CrookLootModifier extends LootModifier { var fortune = stack.getEnchantmentLevel(context.getLevel().holderLookup(Registries.ENCHANTMENT).getOrThrow(Enchantments.FORTUNE)); var rolls = Math.max(1, Mth.ceil(fortune / 3f)); - for (CrookRecipe recipe : RecipeUtil.getCaches(context.getLevel()).getCrookRecipes(state)) { + for (RecipeHolder holder : RecipeUtil.getCaches(context.getLevel()).getCrookRecipes(state)) { + var recipe = holder.value(); for (int i = 0; i < rolls; i++) { if (rand.nextFloat() < recipe.chance()) { generatedLoot.add(recipe.result().copy()); diff --git a/src/main/java/thedarkcolour/exdeorum/loot/HammerLootModifier.java b/src/main/java/thedarkcolour/exdeorum/loot/HammerLootModifier.java index 599fd231..04ec3d18 100644 --- a/src/main/java/thedarkcolour/exdeorum/loot/HammerLootModifier.java +++ b/src/main/java/thedarkcolour/exdeorum/loot/HammerLootModifier.java @@ -22,12 +22,14 @@ import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import net.minecraft.core.RegistryAccess; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.Registries; import net.minecraft.tags.TagKey; import net.minecraft.util.RandomSource; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; +import net.minecraft.world.item.crafting.RecipeHolder; import net.minecraft.world.item.enchantment.Enchantments; import net.minecraft.world.level.storage.loot.LootContext; import net.minecraft.world.level.storage.loot.parameters.LootContextParams; @@ -69,10 +71,11 @@ public class HammerLootModifier extends LootModifier { return generatedLoot; } - var recipe = getRecipe(itemForm, context); - if (recipe == null) { + var holder = getRecipe(itemForm, context); + if (holder == null) { return generatedLoot; } + var recipe = holder.value(); ObjectArrayList newLoot = new ObjectArrayList<>(); var resultAmount = recipe.resultAmount.getInt(context); @@ -91,7 +94,7 @@ public class HammerLootModifier extends LootModifier { } @Nullable - protected HammerRecipe getRecipe(Item itemForm, LootContext context) { + protected RecipeHolder getRecipe(Item itemForm, LootContext context) { return RecipeUtil.getCaches(context.getLevel()).getHammerRecipe(itemForm); } diff --git a/src/main/java/thedarkcolour/exdeorum/recipe/RecipeCaches.java b/src/main/java/thedarkcolour/exdeorum/recipe/RecipeCaches.java index 5982d143..cf64b376 100644 --- a/src/main/java/thedarkcolour/exdeorum/recipe/RecipeCaches.java +++ b/src/main/java/thedarkcolour/exdeorum/recipe/RecipeCaches.java @@ -1,7 +1,5 @@ package thedarkcolour.exdeorum.recipe; -import it.unimi.dsi.fastutil.objects.Object2IntMap; -import it.unimi.dsi.fastutil.objects.ObjectSet; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.RecipeHolder; @@ -15,8 +13,14 @@ import thedarkcolour.exdeorum.recipe.barrel.BarrelCompostRecipe; import thedarkcolour.exdeorum.recipe.barrel.BarrelFluidMixingRecipe; import thedarkcolour.exdeorum.recipe.barrel.BarrelMixingRecipe; import thedarkcolour.exdeorum.recipe.barrel.FluidTransformationRecipe; -import thedarkcolour.exdeorum.recipe.cache.*; +import thedarkcolour.exdeorum.recipe.cache.BarrelFluidMixingRecipeCache; +import thedarkcolour.exdeorum.recipe.cache.CrookRecipeCache; +import thedarkcolour.exdeorum.recipe.cache.CrucibleHeatRecipeCache; +import thedarkcolour.exdeorum.recipe.cache.FluidTransformationRecipeCache; +import thedarkcolour.exdeorum.recipe.cache.SieveRecipeCache; +import thedarkcolour.exdeorum.recipe.cache.SingleIngredientRecipeCache; import thedarkcolour.exdeorum.recipe.crook.CrookRecipe; +import thedarkcolour.exdeorum.recipe.crucible.CrucibleHeatRecipe; import thedarkcolour.exdeorum.recipe.crucible.CrucibleRecipe; import thedarkcolour.exdeorum.recipe.hammer.CompressedHammerRecipe; import thedarkcolour.exdeorum.recipe.hammer.HammerRecipe; @@ -26,11 +30,13 @@ import thedarkcolour.exdeorum.registry.ERecipeTypes; import java.util.Collection; import java.util.List; +import java.util.Map; +import java.util.Set; public class RecipeCaches { private SingleIngredientRecipeCache barrelCompostRecipeCache; - private SingleIngredientRecipeCache lavaCrucibleRecipeCache; - private SingleIngredientRecipeCache waterCrucibleRecipeCache; + private SingleIngredientRecipeCache lavaCrucibleRecipeCache; + private SingleIngredientRecipeCache waterCrucibleRecipeCache; private SingleIngredientRecipeCache hammerRecipeCache; private SingleIngredientRecipeCache compressedHammerRecipeCache; private SieveRecipeCache sieveRecipeCache; @@ -40,31 +46,31 @@ public class RecipeCaches { private CrookRecipeCache crookRecipeCache; private CrucibleHeatRecipeCache crucibleHeatRecipeCache; - public List getSieveRecipes(Item mesh, ItemStack item) { + public List> getSieveRecipes(Item mesh, ItemStack item) { return this.sieveRecipeCache.getRecipe(mesh, item); } - public List getCompressedSieveRecipes(Item mesh, ItemStack item) { + public List> getCompressedSieveRecipes(Item mesh, ItemStack item) { return this.compressedSieveRecipeCache.getRecipe(mesh, item); } @Nullable - public CrucibleRecipe getLavaCrucibleRecipe(ItemStack item) { + public RecipeHolder getLavaCrucibleRecipe(ItemStack item) { return this.lavaCrucibleRecipeCache.getRecipe(item); } @Nullable - public CrucibleRecipe getWaterCrucibleRecipe(ItemStack item) { + public RecipeHolder getWaterCrucibleRecipe(ItemStack item) { return this.waterCrucibleRecipeCache.getRecipe(item); } @Nullable - public BarrelCompostRecipe getBarrelCompostRecipe(ItemStack item) { + public RecipeHolder getBarrelCompostRecipe(ItemStack item) { return this.barrelCompostRecipeCache.getRecipe(item); } @Nullable - public HammerRecipe getHammerRecipe(Item item) { + public RecipeHolder getHammerRecipe(Item item) { return this.hammerRecipeCache.getRecipe(item); } @@ -73,7 +79,7 @@ public class RecipeCaches { } @Nullable - public CompressedHammerRecipe getCompressedHammerRecipe(Item item) { + public RecipeHolder getCompressedHammerRecipe(Item item) { return this.compressedHammerRecipeCache.getRecipe(item); } @@ -81,7 +87,7 @@ public class RecipeCaches { return this.compressedHammerRecipeCache.getAllRecipes(); } - public List getCrookRecipes(BlockState state) { + public List> getCrookRecipes(BlockState state) { return this.crookRecipeCache.getRecipes(state); } @@ -89,20 +95,20 @@ public class RecipeCaches { return this.barrelCompostRecipeCache != null && this.barrelCompostRecipeCache.getRecipe(stack) != null; } - public int getHeatValue(BlockState state) { - return this.crucibleHeatRecipeCache.getValue(state); + public RecipeHolder getHeatRecipe(BlockState state) { + return this.crucibleHeatRecipeCache.getRecipe(state); } - public ObjectSet> getHeatSources() { + public Set>> getHeatSources() { return this.crucibleHeatRecipeCache.getEntries(); } // todo stop using the RecipeManager @Nullable - public BarrelMixingRecipe getBarrelMixingRecipe(RecipeManager recipes, ItemStack stack, FluidStack fluid) { + public RecipeHolder getBarrelMixingRecipe(RecipeManager recipes, ItemStack stack, FluidStack fluid) { for (var recipe : recipes.byType(ERecipeTypes.BARREL_MIXING.get())) { if (recipe.value().matches(stack, fluid)) { - return recipe.value(); + return recipe; } } @@ -110,17 +116,17 @@ public class RecipeCaches { } @Nullable - public BarrelFluidMixingRecipe getFluidMixingRecipe(FluidStack base, Fluid additive) { - var recipe = this.barrelFluidMixingRecipeCache.getRecipe(base.getFluid(), additive); - if (recipe != null && base.getAmount() >= recipe.baseFluid().amount()) { - return recipe; + public RecipeHolder getFluidMixingRecipe(FluidStack base, Fluid additive) { + var holder = this.barrelFluidMixingRecipeCache.getRecipe(base.getFluid(), additive); + if (holder != null && base.getAmount() >= holder.value().baseFluid().amount()) { + return holder; } else { return null; } } @Nullable - public FluidTransformationRecipe getFluidTransformationRecipe(Fluid baseFluid, BlockState catalystState) { + public RecipeHolder getFluidTransformationRecipe(Fluid baseFluid, BlockState catalystState) { if (baseFluid != Fluids.EMPTY) { return this.fluidTransformationRecipeCache.getRecipe(baseFluid, catalystState); } else { diff --git a/src/main/java/thedarkcolour/exdeorum/recipe/cache/BarrelFluidMixingRecipeCache.java b/src/main/java/thedarkcolour/exdeorum/recipe/cache/BarrelFluidMixingRecipeCache.java index c78ba8aa..15cd9435 100644 --- a/src/main/java/thedarkcolour/exdeorum/recipe/cache/BarrelFluidMixingRecipeCache.java +++ b/src/main/java/thedarkcolour/exdeorum/recipe/cache/BarrelFluidMixingRecipeCache.java @@ -18,6 +18,7 @@ package thedarkcolour.exdeorum.recipe.cache; +import net.minecraft.world.item.crafting.RecipeHolder; import net.minecraft.world.item.crafting.RecipeManager; import net.minecraft.world.level.material.Fluid; import org.jetbrains.annotations.Nullable; @@ -31,14 +32,14 @@ import java.util.Map; public class BarrelFluidMixingRecipeCache { private RecipeManager recipeManager; @Nullable - private Map> recipes; + private Map>> recipes; public BarrelFluidMixingRecipeCache(RecipeManager recipeManager) { this.recipeManager = recipeManager; } @Nullable - public BarrelFluidMixingRecipe getRecipe(Fluid baseFluid, Fluid additive) { + public RecipeHolder getRecipe(Fluid baseFluid, Fluid additive) { if (this.recipes == null) { buildRecipes(); } @@ -58,7 +59,7 @@ public class BarrelFluidMixingRecipeCache { var map = this.recipes.computeIfAbsent(baseStack.getFluid(), key -> new HashMap<>()); for (var additiveStack : recipe.additiveFluid().getStacks()) { - map.put(additiveStack.getFluid(), recipe); + map.put(additiveStack.getFluid(), holder); } } } diff --git a/src/main/java/thedarkcolour/exdeorum/recipe/cache/CrookRecipeCache.java b/src/main/java/thedarkcolour/exdeorum/recipe/cache/CrookRecipeCache.java index e82a3ebc..f3fe5073 100644 --- a/src/main/java/thedarkcolour/exdeorum/recipe/cache/CrookRecipeCache.java +++ b/src/main/java/thedarkcolour/exdeorum/recipe/cache/CrookRecipeCache.java @@ -18,6 +18,7 @@ package thedarkcolour.exdeorum.recipe.cache; +import net.minecraft.world.item.crafting.RecipeHolder; import net.minecraft.world.item.crafting.RecipeManager; import net.minecraft.world.level.block.state.BlockState; import org.jetbrains.annotations.Nullable; @@ -29,13 +30,13 @@ import java.util.*; public class CrookRecipeCache { private RecipeManager recipeManager; @Nullable - private Map> recipes; + private Map>> recipes; public CrookRecipeCache(RecipeManager recipeManager) { this.recipeManager = recipeManager; } - public List getRecipes(BlockState state) { + public List> getRecipes(BlockState state) { if (this.recipes == null) { buildRecipes(); } @@ -46,15 +47,15 @@ public class CrookRecipeCache { this.recipes = new HashMap<>(); // state -> set of possible recipes - var tempRecipes = new HashMap>(); + var tempRecipes = new HashMap>>(); for (var recipe : this.recipeManager.byType(ERecipeTypes.CROOK.get())) { recipe.value().blockPredicate().possibleStates().forEach(state -> { - tempRecipes.computeIfAbsent(state, key -> new HashSet<>()).add(recipe.value()); + tempRecipes.computeIfAbsent(state, key -> new HashSet<>()).add(recipe); }); } // map equal sets to a single list object instead of using a bunch of duplicate sets - var dedupeMap = new HashMap, List>(); + var dedupeMap = new HashMap>, List>>(); for (var entry : tempRecipes.entrySet()) { this.recipes.put(entry.getKey(), dedupeMap.computeIfAbsent(entry.getValue(), List::copyOf)); diff --git a/src/main/java/thedarkcolour/exdeorum/recipe/cache/CrucibleHeatRecipeCache.java b/src/main/java/thedarkcolour/exdeorum/recipe/cache/CrucibleHeatRecipeCache.java index da15ca46..753a9b70 100644 --- a/src/main/java/thedarkcolour/exdeorum/recipe/cache/CrucibleHeatRecipeCache.java +++ b/src/main/java/thedarkcolour/exdeorum/recipe/cache/CrucibleHeatRecipeCache.java @@ -18,45 +18,48 @@ package thedarkcolour.exdeorum.recipe.cache; -import it.unimi.dsi.fastutil.objects.Object2IntMap; -import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; -import it.unimi.dsi.fastutil.objects.ObjectSet; +import net.minecraft.world.item.crafting.RecipeHolder; import net.minecraft.world.item.crafting.RecipeManager; import net.minecraft.world.level.block.state.BlockState; import org.jetbrains.annotations.Nullable; +import thedarkcolour.exdeorum.recipe.crucible.CrucibleHeatRecipe; import thedarkcolour.exdeorum.registry.ERecipeTypes; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + public class CrucibleHeatRecipeCache { private RecipeManager recipeManager; @Nullable - private Object2IntMap recipes; + private Map> recipes; public CrucibleHeatRecipeCache(RecipeManager recipeManager) { this.recipeManager = recipeManager; } - public int getValue(BlockState state) { + public RecipeHolder getRecipe(BlockState state) { if (this.recipes == null) { buildRecipes(); } - return this.recipes.getInt(state); + return this.recipes.get(state); } private void buildRecipes() { - this.recipes = new Object2IntOpenHashMap<>(); + this.recipes = new HashMap<>(); for (var holder : this.recipeManager.byType(ERecipeTypes.CRUCIBLE_HEAT_SOURCE.get())) { var recipe = holder.value(); - recipe.blockPredicate().possibleStates().forEach(state -> this.recipes.put(state, recipe.heatValue())); + recipe.blockPredicate().possibleStates().forEach(state -> this.recipes.put(state, holder)); } this.recipeManager = null; } - public ObjectSet> getEntries() { + public Set>> getEntries() { if (this.recipes == null) { buildRecipes(); } - return this.recipes.object2IntEntrySet(); + return this.recipes.entrySet(); } } diff --git a/src/main/java/thedarkcolour/exdeorum/recipe/cache/FluidTransformationRecipeCache.java b/src/main/java/thedarkcolour/exdeorum/recipe/cache/FluidTransformationRecipeCache.java index c67d576f..c81821d9 100644 --- a/src/main/java/thedarkcolour/exdeorum/recipe/cache/FluidTransformationRecipeCache.java +++ b/src/main/java/thedarkcolour/exdeorum/recipe/cache/FluidTransformationRecipeCache.java @@ -18,6 +18,7 @@ package thedarkcolour.exdeorum.recipe.cache; +import net.minecraft.world.item.crafting.RecipeHolder; import net.minecraft.world.item.crafting.RecipeManager; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.material.Fluid; @@ -31,14 +32,14 @@ import java.util.Map; public class FluidTransformationRecipeCache { private RecipeManager recipeManager; @Nullable - private Map> recipes; + private Map>> recipes; public FluidTransformationRecipeCache(RecipeManager manager) { this.recipeManager = manager; } @Nullable - public FluidTransformationRecipe getRecipe(Fluid baseFluid, BlockState catalystState) { + public RecipeHolder getRecipe(Fluid baseFluid, BlockState catalystState) { if (this.recipes == null) { buildRecipes(); } @@ -56,12 +57,12 @@ public class FluidTransformationRecipeCache { var recipe = holder.value(); recipe.catalyst().possibleStates().forEach(state -> { for (var stack : recipe.baseFluid().getStacks()) { - this.recipes.computeIfAbsent(state, key -> new HashMap<>()).put(stack.getFluid(), recipe); + this.recipes.computeIfAbsent(state, key -> new HashMap<>()).put(stack.getFluid(), holder); } }); } - var dedupe = new HashMap, Map>(); + var dedupe = new HashMap>, Map>>(); for (var entry : this.recipes.entrySet()) { entry.setValue(dedupe.computeIfAbsent(entry.getValue(), Map::copyOf)); } diff --git a/src/main/java/thedarkcolour/exdeorum/recipe/cache/SieveRecipeCache.java b/src/main/java/thedarkcolour/exdeorum/recipe/cache/SieveRecipeCache.java index 165715a9..e64d45a6 100644 --- a/src/main/java/thedarkcolour/exdeorum/recipe/cache/SieveRecipeCache.java +++ b/src/main/java/thedarkcolour/exdeorum/recipe/cache/SieveRecipeCache.java @@ -21,6 +21,7 @@ package thedarkcolour.exdeorum.recipe.cache; import com.google.common.collect.ImmutableList; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.RecipeHolder; import net.minecraft.world.item.crafting.RecipeManager; import net.minecraft.world.item.crafting.RecipeType; import org.jetbrains.annotations.Nullable; @@ -43,7 +44,7 @@ public class SieveRecipeCache { this.recipeType = recipeType; } - public List getRecipe(Item mesh, ItemStack input) { + public List> getRecipe(Item mesh, ItemStack input) { if (this.meshCaches == null) { buildRecipes(); } @@ -53,11 +54,11 @@ public class SieveRecipeCache { private void buildRecipes() { // Group recipes based on their mesh - var tempMap = new HashMap>(); + var tempMap = new HashMap>>(); for (var holder : this.recipeManager.byType(this.recipeType.get())) { var recipe = holder.value(); for (var stack : recipe.mesh.getItems()) { - tempMap.computeIfAbsent(stack.getItem(), k -> new ArrayList<>()).add(recipe); + tempMap.computeIfAbsent(stack.getItem(), k -> new ArrayList<>()).add(holder); } } this.meshCaches = new HashMap<>(); @@ -73,15 +74,16 @@ public class SieveRecipeCache { // certain enchantment). Thirdly, I do not see anybody needing this use case, and if they do, they should contact // me on GitHub or Discord so that I can get around to actually implementing it. private static class MeshRecipeCache { - private final Map> simpleRecipes; + private final Map>> simpleRecipes; - private MeshRecipeCache(List recipes) { + private MeshRecipeCache(List> recipes) { this.simpleRecipes = new HashMap<>(); - var temp = new HashMap>(); + var temp = new HashMap>>(); - for (var recipe : recipes) { + for (var holder : recipes) { + var recipe = holder.value(); for (var item : recipe.ingredient.getItems()) { - temp.computeIfAbsent(item.getItem(), k -> ImmutableList.builder()).add(recipe); + temp.computeIfAbsent(item.getItem(), k -> ImmutableList.builder()).add(holder); } } @@ -90,7 +92,7 @@ public class SieveRecipeCache { } } - public List getRecipes(ItemStack input) { + public List> getRecipes(ItemStack input) { var result = this.simpleRecipes.get(input.getItem()); return result == null ? List.of() : result; } diff --git a/src/main/java/thedarkcolour/exdeorum/recipe/cache/SingleIngredientRecipeCache.java b/src/main/java/thedarkcolour/exdeorum/recipe/cache/SingleIngredientRecipeCache.java index f4ffafb8..cba79eb4 100644 --- a/src/main/java/thedarkcolour/exdeorum/recipe/cache/SingleIngredientRecipeCache.java +++ b/src/main/java/thedarkcolour/exdeorum/recipe/cache/SingleIngredientRecipeCache.java @@ -31,15 +31,16 @@ import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.function.Supplier; public class SingleIngredientRecipeCache { private final Supplier> recipeType; private RecipeManager recipeManager; @Nullable - private Map simpleRecipes; + private Map> simpleRecipes; @Nullable - private List complexRecipes; + private List> complexRecipes; @Nullable private Collection> allRecipes; private boolean trackAllRecipes; @@ -55,12 +56,12 @@ public class SingleIngredientRecipeCache { } @Nullable - public T getRecipe(Item item) { + public RecipeHolder getRecipe(Item item) { return getRecipe(new ItemStack(item)); } @Nullable - public T getRecipe(ItemStack item) { + public RecipeHolder getRecipe(ItemStack item) { if (this.simpleRecipes == null) { buildRecipes(); } @@ -70,7 +71,7 @@ public class SingleIngredientRecipeCache { // if there are complex recipes, test each one if (recipe == null && this.complexRecipes != null) { for (var complexRecipe : this.complexRecipes) { - if (complexRecipe.ingredient().test(item)) { + if (complexRecipe.value().ingredient().test(item)) { return complexRecipe; } } @@ -86,7 +87,7 @@ public class SingleIngredientRecipeCache { if (this.simpleRecipes == null) { buildRecipes(); } - return this.allRecipes; + return Objects.requireNonNull(this.allRecipes); } /** @@ -99,7 +100,7 @@ public class SingleIngredientRecipeCache { */ private void buildRecipes() { this.simpleRecipes = new HashMap<>(); - var complexRecipes = ImmutableList.builder(); + var complexRecipes = ImmutableList.>builder(); var allRecipes = this.recipeManager.byType(this.recipeType.get()); @@ -109,10 +110,10 @@ public class SingleIngredientRecipeCache { if (ingredient.isSimple()) { for (var item : ingredient.getItems()) { - this.simpleRecipes.put(item.getItem(), recipe); + this.simpleRecipes.put(item.getItem(), holder); } } else { - complexRecipes.add(recipe); + complexRecipes.add(holder); } } diff --git a/src/main/java/thedarkcolour/exdeorum/registry/ERecipeTypes.java b/src/main/java/thedarkcolour/exdeorum/registry/ERecipeTypes.java index 92660d84..4f4cb90f 100644 --- a/src/main/java/thedarkcolour/exdeorum/registry/ERecipeTypes.java +++ b/src/main/java/thedarkcolour/exdeorum/registry/ERecipeTypes.java @@ -43,8 +43,8 @@ public class ERecipeTypes { public static final DeferredHolder, RecipeType> BARREL_FLUID_MIXING = RECIPE_TYPES.register("barrel_fluid_mixing", () -> RecipeType.simple(ERecipeTypes.BARREL_FLUID_MIXING.getId())); public static final DeferredHolder, RecipeType> BARREL_FLUID_TRANSFORMATION = RECIPE_TYPES.register("barrel_fluid_transformation", () -> RecipeType.simple(ERecipeTypes.BARREL_FLUID_TRANSFORMATION.getId())); - public static final DeferredHolder, RecipeType> LAVA_CRUCIBLE = RECIPE_TYPES.register("lava_crucible", () -> RecipeType.simple(ERecipeTypes.LAVA_CRUCIBLE.getId())); - public static final DeferredHolder, RecipeType> WATER_CRUCIBLE = RECIPE_TYPES.register("water_crucible", () -> RecipeType.simple(ERecipeTypes.WATER_CRUCIBLE.getId())); + public static final DeferredHolder, RecipeType> LAVA_CRUCIBLE = RECIPE_TYPES.register("lava_crucible", () -> RecipeType.simple(ERecipeTypes.LAVA_CRUCIBLE.getId())); + public static final DeferredHolder, RecipeType> WATER_CRUCIBLE = RECIPE_TYPES.register("water_crucible", () -> RecipeType.simple(ERecipeTypes.WATER_CRUCIBLE.getId())); public static final DeferredHolder, RecipeType> HAMMER = RECIPE_TYPES.register("hammer", () -> RecipeType.simple(ERecipeTypes.HAMMER.getId())); public static final DeferredHolder, RecipeType> COMPRESSED_HAMMER = RECIPE_TYPES.register("compressed_hammer", () -> RecipeType.simple(ERecipeTypes.COMPRESSED_HAMMER.getId())); From 81c1dcc49ff8bb703e9f28be50cadee9d43062db Mon Sep 17 00:00:00 2001 From: Lorenz Wrobel <43410952+DasBabyPixel@users.noreply.github.com> Date: Sat, 23 May 2026 01:25:40 +0200 Subject: [PATCH 2/4] jei compat --- .../exdeorum/compat/CompatUtil.java | 4 +- .../exdeorum/compat/XeiSieveRecipe.java | 97 ++++++++++++--- .../compat/jei/BarrelCompostCategory.java | 13 +- .../compat/jei/BarrelMixingCategory.java | 21 ++-- .../compat/jei/CompressedSieveCategory.java | 6 +- .../exdeorum/compat/jei/CrookCategory.java | 7 ++ .../exdeorum/compat/jei/CrookJeiRecipe.java | 31 +++-- .../exdeorum/compat/jei/CrucibleCategory.java | 13 +- .../compat/jei/CrucibleHeatSourceRecipe.java | 14 ++- .../jei/CrucibleHeatSourcesCategory.java | 7 ++ .../compat/jei/ExDeorumJeiPlugin.java | 63 ++++++---- .../exdeorum/compat/jei/HammerCategory.java | 18 +-- .../exdeorum/compat/jei/SieveCategory.java | 116 +++++++++++++++++- 13 files changed, 314 insertions(+), 96 deletions(-) diff --git a/src/main/java/thedarkcolour/exdeorum/compat/CompatUtil.java b/src/main/java/thedarkcolour/exdeorum/compat/CompatUtil.java index 23f6085b..5f5f580c 100644 --- a/src/main/java/thedarkcolour/exdeorum/compat/CompatUtil.java +++ b/src/main/java/thedarkcolour/exdeorum/compat/CompatUtil.java @@ -79,11 +79,11 @@ public class CompatUtil { return materials; } - public static , T> List collectAllRecipes(RecipeManager recipeManager, RecipeType recipeType, Function mapper) { + public static , T> List collectAllRecipes(RecipeManager recipeManager, RecipeType recipeType, Function, T> mapper) { var byType = recipeManager.byType(recipeType); List recipes = new ObjectArrayList<>(byType.size()); for (RecipeHolder value : byType) { - recipes.add(mapper.apply(value.value())); + recipes.add(mapper.apply(value)); } return recipes; } diff --git a/src/main/java/thedarkcolour/exdeorum/compat/XeiSieveRecipe.java b/src/main/java/thedarkcolour/exdeorum/compat/XeiSieveRecipe.java index fae10f49..44179b19 100644 --- a/src/main/java/thedarkcolour/exdeorum/compat/XeiSieveRecipe.java +++ b/src/main/java/thedarkcolour/exdeorum/compat/XeiSieveRecipe.java @@ -22,10 +22,12 @@ import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ImmutableList; import com.google.common.collect.Multimap; import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.ResourceLocation; import net.minecraft.util.Mth; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.Ingredient; +import net.minecraft.world.item.crafting.RecipeHolder; import net.minecraft.world.item.crafting.RecipeType; import net.minecraft.world.level.storage.loot.providers.number.ConstantValue; import net.minecraft.world.level.storage.loot.providers.number.NumberProvider; @@ -34,33 +36,45 @@ import thedarkcolour.exdeorum.recipe.RecipeUtil; import thedarkcolour.exdeorum.recipe.sieve.SieveRecipe; import thedarkcolour.exdeorum.registry.EItems; +import java.math.BigInteger; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.util.ArrayList; +import java.util.Collection; import java.util.Comparator; import java.util.List; +import java.util.Objects; +import java.util.Set; import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; // Since no JEI code is used here, this can be reused for REI -public record XeiSieveRecipe(Ingredient ingredient, ItemStack mesh, List results) { +public record XeiSieveRecipe(ResourceLocation id, Ingredient ingredient, ItemStack mesh, List results) { public static final MutableInt SIEVE_ROWS = new MutableInt(0); public static final MutableInt COMPRESSED_SIEVE_ROWS = new MutableInt(0); - public static ImmutableList getAllRecipesGrouped(RecipeType recipeType, MutableInt maxRows) { + public static ImmutableList getAllRecipesGrouped(RecipeType recipeType, MutableInt maxRows) { int maxSieveRows = 1; - var recipes = CompatUtil.collectAllRecipes(RecipeUtil.getClientRecipeManager(), recipeType, Function.identity()); - Multimap ingredientGrouper = ArrayListMultimap.create(); + var recipeHolders = CompatUtil.collectAllRecipes(RecipeUtil.getClientRecipeManager(), recipeType, Function.identity()); + var recipeTypeKey = Objects.requireNonNull(BuiltInRegistries.RECIPE_TYPE.getKey(recipeType)); + Multimap> ingredientGrouper = ArrayListMultimap.create(); - for (int i = 0; i < recipes.size(); i++) { - var recipe = recipes.get(i); + for (int i = 0; i < recipeHolders.size(); i++) { + var holder = recipeHolders.get(i); + var recipe = holder.value(); - ingredientGrouper.put(recipe.ingredient(), recipe); + ingredientGrouper.put(recipe.ingredient(), holder); - for (int j = i + 1; j < recipes.size(); j++) { - var other = recipes.get(j); + for (int j = i + 1; j < recipeHolders.size(); j++) { + var otherHolder = recipeHolders.get(j); + var other = otherHolder.value(); if (RecipeUtil.areIngredientsEqual(recipe.ingredient(), other.ingredient())) { - ingredientGrouper.put(recipe.ingredient(), other); - recipes.remove(other); + ingredientGrouper.put(recipe.ingredient(), otherHolder); + recipeHolders.remove(otherHolder); j--; } } @@ -74,13 +88,23 @@ public record XeiSieveRecipe(Ingredient ingredient, ItemStack mesh, List // ingredients with common ingredients are grouped into lists (ex. dirt) for (var ingredient : ingredientGrouper.keySet()) { - Multimap meshGrouper = ArrayListMultimap.create(); + Multimap> meshGrouper = ArrayListMultimap.create(); var values = ingredientGrouper.get(ingredient); + // A unique ingredient ID, which can grow long. For same ingredient will always generate same ID, even over game restarts. + var ingredientId = "ingredient-start " + Stream + .of(ingredient.getItems()) + .map(ItemStack::getItem) + .map(BuiltInRegistries.ITEM::getKey) + .map(ResourceLocation::toString) + .sorted() + .collect(Collectors.joining(" - ")) + " ingredient-end "; + // these lists are grouped into sub lists based on their meshes (ex. dirt with string mesh) - for (var recipe : values) { + for (var holder : values) { + var recipe = holder.value(); for (var stack : recipe.mesh.getItems()) { - meshGrouper.put(stack.getItem(), recipe); + meshGrouper.put(stack.getItem(), holder); } } @@ -91,15 +115,22 @@ public record XeiSieveRecipe(Ingredient ingredient, ItemStack mesh, List for (var mesh : meshes) { var meshRecipes = meshGrouper.get(mesh); var results = new ArrayList(meshRecipes.size()); + var idList = new ArrayList(); + idList.add(ingredientId); + idList.add(BuiltInRegistries.ITEM.getKey(mesh).toString()); - for (var recipe : meshRecipes) { - int resultCount = recipe.resultAmount instanceof ConstantValue constant ? Math.round(constant.value()) : 1; - results.add(new Result(recipe.result.copyWithCount(resultCount), recipe.resultAmount, recipe.byHandOnly)); + for (var holder : meshRecipes) { + var recipe = holder.value(); + int resultCount = recipe.resultAmount instanceof ConstantValue(float value) ? Math.round(value) : 1; + results.add(new Result(holder, recipe.result.copyWithCount(resultCount), recipe.resultAmount, recipe.byHandOnly)); + + idList.add(holder.id().toString()); } - results.sort(resultSorter); + var id = ResourceLocation.fromNamespaceAndPath(recipeTypeKey.getNamespace(), recipeTypeKey.getPath() + "/" + hash512(idList)); - var jeiRecipe = new XeiSieveRecipe(ingredient, new ItemStack(mesh), results); + results.sort(resultSorter); + var jeiRecipe = new XeiSieveRecipe(id, ingredient, new ItemStack(mesh), results); jeiRecipes.add(jeiRecipe); var rows = Mth.ceil((float) meshRecipes.size() / 9f); @@ -132,13 +163,39 @@ public record XeiSieveRecipe(Ingredient ingredient, ItemStack mesh, List } } + /** + * Function to hash a collection of strings using 512 bits precision. + * The order of the input collection does not matter. + * The idea behind this is to hash all recipes that make a recipe group and give the recipe group an ID. + * We need to make sure the ID doesn't end up with any collisions, so we just use a cryptographic hash. + * It's much more likely that 100 meteors strike ones house at the same time, than that two hashes collide, + * so that should suffice for uniqueness... + */ + private static String hash512(Collection inputs) { + try { + // make a unique string out of all inputs, regardless of the order they have. + // we use a separator which is sure to be unique and never in any input: " ||| " + var sortedInputs = inputs.stream().sorted().collect(Collectors.joining(" ||| ")); + var md = MessageDigest.getInstance("SHA-512"); + var digest = md.digest(sortedInputs.getBytes(StandardCharsets.UTF_8)); + // Create a bigint out of the digest and convert it to a hex string + var bi = new BigInteger(1, digest); + return bi.toString(16); + } catch (NoSuchAlgorithmException e) { + // This is pretty bad... This shouldn't happen + throw new Error("Your java does not support SHA-512. Wat da hell? Report this to ExDeorum", e); + } + } + public static final class Result { + public final RecipeHolder holder; public final ItemStack item; public final NumberProvider provider; public final boolean byHandOnly; private final double expectedCount; - Result(ItemStack item, NumberProvider provider, boolean byHandOnly) { + Result(RecipeHolder holder, ItemStack item, NumberProvider provider, boolean byHandOnly) { + this.holder = holder; this.item = item; this.provider = provider; this.byHandOnly = byHandOnly; diff --git a/src/main/java/thedarkcolour/exdeorum/compat/jei/BarrelCompostCategory.java b/src/main/java/thedarkcolour/exdeorum/compat/jei/BarrelCompostCategory.java index aead0235..17856d44 100644 --- a/src/main/java/thedarkcolour/exdeorum/compat/jei/BarrelCompostCategory.java +++ b/src/main/java/thedarkcolour/exdeorum/compat/jei/BarrelCompostCategory.java @@ -29,11 +29,12 @@ import mezz.jei.api.recipe.category.IRecipeCategory; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.network.chat.Component; +import net.minecraft.world.item.crafting.RecipeHolder; import thedarkcolour.exdeorum.compat.ClientXeiUtil; import thedarkcolour.exdeorum.data.TranslationKeys; import thedarkcolour.exdeorum.recipe.barrel.BarrelCompostRecipe; -class BarrelCompostCategory implements IRecipeCategory { +class BarrelCompostCategory implements IRecipeCategory> { public static final int WIDTH = 120; public static final int HEIGHT = 18; @@ -50,7 +51,7 @@ class BarrelCompostCategory implements IRecipeCategory { } @Override - public RecipeType getRecipeType() { + public RecipeType> getRecipeType() { return ExDeorumJeiPlugin.BARREL_COMPOST; } @@ -70,15 +71,15 @@ class BarrelCompostCategory implements IRecipeCategory { } @Override - public void setRecipe(IRecipeLayoutBuilder builder, BarrelCompostRecipe recipe, IFocusGroup focuses) { - builder.addSlot(RecipeIngredientRole.INPUT, 1, 1).addIngredients(recipe.ingredient()); + public void setRecipe(IRecipeLayoutBuilder builder, RecipeHolder holder, IFocusGroup focuses) { + builder.addSlot(RecipeIngredientRole.INPUT, 1, 1).addIngredients(holder.value().ingredient()); } @Override - public void draw(BarrelCompostRecipe recipe, IRecipeSlotsView recipeSlotsView, GuiGraphics graphics, double mouseX, double mouseY) { + public void draw(RecipeHolder holder, IRecipeSlotsView recipeSlotsView, GuiGraphics graphics, double mouseX, double mouseY) { this.slot.draw(graphics); - var volume = recipe.getVolume(); + var volume = holder.value().getVolume(); var volumeLabel = Component.translatable(TranslationKeys.BARREL_COMPOST_RECIPE_VOLUME, volume); graphics.drawString(Minecraft.getInstance().font, volumeLabel, 24, 5, 0xff808080, false); diff --git a/src/main/java/thedarkcolour/exdeorum/compat/jei/BarrelMixingCategory.java b/src/main/java/thedarkcolour/exdeorum/compat/jei/BarrelMixingCategory.java index 1016942a..b2b2105d 100644 --- a/src/main/java/thedarkcolour/exdeorum/compat/jei/BarrelMixingCategory.java +++ b/src/main/java/thedarkcolour/exdeorum/compat/jei/BarrelMixingCategory.java @@ -31,6 +31,7 @@ import net.minecraft.client.gui.GuiGraphics; import net.minecraft.network.chat.Component; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.RecipeHolder; import thedarkcolour.exdeorum.compat.ClientXeiUtil; import thedarkcolour.exdeorum.data.TranslationKeys; import thedarkcolour.exdeorum.material.DefaultMaterials; @@ -81,25 +82,26 @@ public abstract class BarrelMixingCategory implements IRecipeCategory { this.slot.draw(graphics, 78, 0); } - public static class Items extends BarrelMixingCategory { + public static class Items extends BarrelMixingCategory> { public Items(IGuiHelper helper, IDrawable plus, IDrawable arrow) { super(helper, plus, arrow, TranslationKeys.BARREL_MIXING_CATEGORY_TITLE, DefaultMaterials.OAK_BARREL.getItem()); } @Override - public void setRecipe(IRecipeLayoutBuilder builder, BarrelMixingRecipe recipe, IFocusGroup focuses) { + public void setRecipe(IRecipeLayoutBuilder builder, RecipeHolder holder, IFocusGroup focuses) { + var recipe = holder.value(); JeiUtil.addFluidIngredient(builder.addSlot(RecipeIngredientRole.INPUT, 1, 1), recipe.fluid).setFluidRenderer(1000, false, 16, 16); builder.addSlot(RecipeIngredientRole.INPUT, 33, 1).addIngredients(recipe.ingredient()); builder.addSlot(RecipeIngredientRole.OUTPUT, 79, 1).addItemStack(recipe.result); } @Override - public RecipeType getRecipeType() { + public RecipeType> getRecipeType() { return ExDeorumJeiPlugin.BARREL_MIXING; } } - public static class Fluids extends BarrelMixingCategory { + public static class Fluids extends BarrelMixingCategory> { private static final Component CONTENTS_ARE_CONSUMED_TOOLTIP = Component.translatable(TranslationKeys.BARREL_FLUID_MIXING_CONTENTS_ARE_CONSUMED).withStyle(ChatFormatting.RED); public Fluids(IGuiHelper helper, IDrawable plus, IDrawable arrow) { @@ -107,7 +109,8 @@ public abstract class BarrelMixingCategory implements IRecipeCategory { } @Override - public void setRecipe(IRecipeLayoutBuilder builder, BarrelFluidMixingRecipe recipe, IFocusGroup focuses) { + public void setRecipe(IRecipeLayoutBuilder builder, RecipeHolder holder, IFocusGroup focuses) { + var recipe = holder.value(); JeiUtil.addFluidIngredient(builder.addSlot(RecipeIngredientRole.INPUT, 1, 1), recipe.baseFluid()) .setFluidRenderer(1000, false, 16, 16); var additiveSlot = JeiUtil.addFluidIngredient(builder.addSlot(RecipeIngredientRole.INPUT, 33, 1), recipe.additiveFluid(), 1000) @@ -119,15 +122,15 @@ public abstract class BarrelMixingCategory implements IRecipeCategory { } @Override - public RecipeType getRecipeType() { + public RecipeType> getRecipeType() { return ExDeorumJeiPlugin.BARREL_FLUID_MIXING; } @Override - public void draw(BarrelFluidMixingRecipe recipe, IRecipeSlotsView recipeSlotsView, GuiGraphics graphics, double mouseX, double mouseY) { - super.draw(recipe, recipeSlotsView, graphics, mouseX, mouseY); + public void draw(RecipeHolder holder, IRecipeSlotsView recipeSlotsView, GuiGraphics graphics, double mouseX, double mouseY) { + super.draw(holder, recipeSlotsView, graphics, mouseX, mouseY); - if (recipe.consumesAdditive()) { + if (holder.value().consumesAdditive()) { ClientXeiUtil.renderAsterisk(graphics, 18 + 3 + 3 + 8, 0); } } diff --git a/src/main/java/thedarkcolour/exdeorum/compat/jei/CompressedSieveCategory.java b/src/main/java/thedarkcolour/exdeorum/compat/jei/CompressedSieveCategory.java index 612aeaa8..e1aa5c00 100644 --- a/src/main/java/thedarkcolour/exdeorum/compat/jei/CompressedSieveCategory.java +++ b/src/main/java/thedarkcolour/exdeorum/compat/jei/CompressedSieveCategory.java @@ -1,6 +1,6 @@ package thedarkcolour.exdeorum.compat.jei; -import mezz.jei.api.helpers.IGuiHelper; +import mezz.jei.api.helpers.IJeiHelpers; import mezz.jei.api.recipe.RecipeType; import net.minecraft.network.chat.Component; import thedarkcolour.exdeorum.compat.XeiSieveRecipe; @@ -8,8 +8,8 @@ import thedarkcolour.exdeorum.data.TranslationKeys; import thedarkcolour.exdeorum.material.DefaultMaterials; class CompressedSieveCategory extends SieveCategory { - CompressedSieveCategory(IGuiHelper helper) { - super(helper, DefaultMaterials.OAK_COMPRESSED_SIEVE, Component.translatable(TranslationKeys.COMPRESSED_SIEVE_CATEGORY_TITLE), XeiSieveRecipe.COMPRESSED_SIEVE_ROWS); + CompressedSieveCategory(IJeiHelpers jeiHelpers) { + super(jeiHelpers, DefaultMaterials.OAK_COMPRESSED_SIEVE, Component.translatable(TranslationKeys.COMPRESSED_SIEVE_CATEGORY_TITLE), XeiSieveRecipe.COMPRESSED_SIEVE_ROWS); } @Override diff --git a/src/main/java/thedarkcolour/exdeorum/compat/jei/CrookCategory.java b/src/main/java/thedarkcolour/exdeorum/compat/jei/CrookCategory.java index c4d3e59c..e7e0cd6a 100644 --- a/src/main/java/thedarkcolour/exdeorum/compat/jei/CrookCategory.java +++ b/src/main/java/thedarkcolour/exdeorum/compat/jei/CrookCategory.java @@ -36,8 +36,10 @@ import net.minecraft.ChatFormatting; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.state.BlockState; +import org.jetbrains.annotations.Nullable; import thedarkcolour.exdeorum.compat.ClientXeiUtil; import thedarkcolour.exdeorum.data.TranslationKeys; import thedarkcolour.exdeorum.registry.EItems; @@ -98,6 +100,11 @@ public class CrookCategory implements IRecipeCategory { }); } + @Override + public @Nullable ResourceLocation getRegistryName(CrookJeiRecipe recipe) { + return recipe.identifier; + } + @Override public void draw(CrookJeiRecipe recipe, IRecipeSlotsView recipeSlotsView, GuiGraphics graphics, double mouseX, double mouseY) { this.timer.onDraw(); diff --git a/src/main/java/thedarkcolour/exdeorum/compat/jei/CrookJeiRecipe.java b/src/main/java/thedarkcolour/exdeorum/compat/jei/CrookJeiRecipe.java index 776a2c79..439f3ffa 100644 --- a/src/main/java/thedarkcolour/exdeorum/compat/jei/CrookJeiRecipe.java +++ b/src/main/java/thedarkcolour/exdeorum/compat/jei/CrookJeiRecipe.java @@ -23,9 +23,11 @@ import mezz.jei.api.gui.builder.IRecipeLayoutBuilder; import mezz.jei.api.recipe.RecipeIngredientRole; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; import net.minecraft.tags.TagKey; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; +import net.minecraft.world.item.crafting.RecipeHolder; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.BlockStateProperties; @@ -39,11 +41,13 @@ import java.util.HashSet; import java.util.List; public sealed abstract class CrookJeiRecipe { + public final ResourceLocation identifier; public final List states; public ItemStack result; public float chance; - public CrookJeiRecipe(List states, ItemStack result, float chance) { + public CrookJeiRecipe(ResourceLocation identifier, List states, ItemStack result, float chance) { + this.identifier = identifier; this.states = states; this.result = result; this.chance = chance; @@ -51,13 +55,18 @@ public sealed abstract class CrookJeiRecipe { public abstract void addIngredients(IRecipeLayoutBuilder builder); - static CrookJeiRecipe create(CrookRecipe recipe) { + static CrookJeiRecipe create(RecipeHolder recipeHolder) { + var recipe = recipeHolder.value(); + var id = recipeHolder.id(); switch (recipe.blockPredicate()) { case BlockPredicate.BlockStatePredicate state -> { - return new StatesRecipe(state, state.possibleStates().filter(blockState -> !blockState.hasProperty(BlockStateProperties.WATERLOGGED) || !blockState.getValue(BlockStateProperties.WATERLOGGED)).toList(), recipe.result(), recipe.chance()); + return new StatesRecipe(id, state, state + .possibleStates() + .filter(blockState -> !blockState.hasProperty(BlockStateProperties.WATERLOGGED) || !blockState.getValue(BlockStateProperties.WATERLOGGED)) + .toList(), recipe.result(), recipe.chance()); } case BlockPredicate.SingleBlockPredicate block -> { - return new BlockRecipe(block.block(), recipe.result(), recipe.chance()); + return new BlockRecipe(id, block.block(), recipe.result(), recipe.chance()); } case BlockPredicate.TagPredicate tag -> { var list = new ArrayList(); @@ -68,7 +77,7 @@ public sealed abstract class CrookJeiRecipe { } } - return new TagRecipe(tag.tag(), List.copyOf(list), recipe.result(), recipe.chance()); + return new TagRecipe(id, tag.tag(), List.copyOf(list), recipe.result(), recipe.chance()); } default -> throw new IllegalArgumentException("Invalid crook recipe?? -> " + recipe); } @@ -78,8 +87,8 @@ public sealed abstract class CrookJeiRecipe { private final List itemIngredients; public final List requirements; - StatesRecipe(@Nullable BlockPredicate.BlockStatePredicate predicate, List states, ItemStack result, float chance) { - super(states, result, chance); + StatesRecipe(ResourceLocation identifier, @Nullable BlockPredicate.BlockStatePredicate predicate, List states, ItemStack result, float chance) { + super(identifier, states, result, chance); ImmutableList.Builder itemIngredients = ImmutableList.builder(); var blocks = new HashSet(); @@ -112,8 +121,8 @@ public sealed abstract class CrookJeiRecipe { static final class TagRecipe extends StatesRecipe { public final TagKey tag; - public TagRecipe(TagKey tag, List states, ItemStack result, float chance) { - super(null, states, result, chance); + public TagRecipe(ResourceLocation identifier, TagKey tag, List states, ItemStack result, float chance) { + super(identifier, null, states, result, chance); this.tag = tag; } } @@ -121,8 +130,8 @@ public sealed abstract class CrookJeiRecipe { static final class BlockRecipe extends CrookJeiRecipe { private final ItemStack itemIngredient; - BlockRecipe(Block block, ItemStack result, float chance) { - super(ImmutableList.of(block.defaultBlockState()), result, chance); + BlockRecipe(ResourceLocation identifier, Block block, ItemStack result, float chance) { + super(identifier, ImmutableList.of(block.defaultBlockState()), result, chance); var item = block.asItem(); if (item == Items.AIR) { diff --git a/src/main/java/thedarkcolour/exdeorum/compat/jei/CrucibleCategory.java b/src/main/java/thedarkcolour/exdeorum/compat/jei/CrucibleCategory.java index 24c51456..7cf119b7 100644 --- a/src/main/java/thedarkcolour/exdeorum/compat/jei/CrucibleCategory.java +++ b/src/main/java/thedarkcolour/exdeorum/compat/jei/CrucibleCategory.java @@ -25,22 +25,25 @@ import mezz.jei.api.recipe.RecipeType; import net.minecraft.network.chat.Component; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.RecipeHolder; import thedarkcolour.exdeorum.data.TranslationKeys; import thedarkcolour.exdeorum.material.DefaultMaterials; import thedarkcolour.exdeorum.recipe.crucible.CrucibleRecipe; -abstract class CrucibleCategory extends OneToOneCategory { +abstract class CrucibleCategory extends OneToOneCategory> { public CrucibleCategory(IGuiHelper helper, IDrawable arrow, Item iconItem, String titleKey) { super(helper, arrow, helper.createDrawableItemStack(new ItemStack(iconItem)), Component.translatable(titleKey)); } @Override - protected void addInput(IRecipeSlotBuilder slot, CrucibleRecipe recipe) { + protected void addInput(IRecipeSlotBuilder slot, RecipeHolder holder) { + var recipe = holder.value(); slot.addIngredients(recipe.ingredient()); } @Override - protected void addOutput(IRecipeSlotBuilder slot, CrucibleRecipe recipe) { + protected void addOutput(IRecipeSlotBuilder slot, RecipeHolder holder) { + var recipe = holder.value(); slot.addFluidStack(recipe.getResult().getFluid(), recipe.getResult().getAmount()) .setFluidRenderer(Math.max(1000, recipe.getResult().getAmount()), false, 16, 16); } @@ -51,7 +54,7 @@ abstract class CrucibleCategory extends OneToOneCatego } @Override - public RecipeType getRecipeType() { + public RecipeType> getRecipeType() { return ExDeorumJeiPlugin.LAVA_CRUCIBLE; } } @@ -62,7 +65,7 @@ abstract class CrucibleCategory extends OneToOneCatego } @Override - public RecipeType getRecipeType() { + public RecipeType> getRecipeType() { return ExDeorumJeiPlugin.WATER_CRUCIBLE; } } diff --git a/src/main/java/thedarkcolour/exdeorum/compat/jei/CrucibleHeatSourceRecipe.java b/src/main/java/thedarkcolour/exdeorum/compat/jei/CrucibleHeatSourceRecipe.java index 9aa1242d..ff745b4c 100644 --- a/src/main/java/thedarkcolour/exdeorum/compat/jei/CrucibleHeatSourceRecipe.java +++ b/src/main/java/thedarkcolour/exdeorum/compat/jei/CrucibleHeatSourceRecipe.java @@ -19,11 +19,13 @@ package thedarkcolour.exdeorum.compat.jei; import mezz.jei.api.ingredients.IIngredientType; +import net.minecraft.world.item.crafting.RecipeHolder; import net.minecraft.world.level.block.state.BlockState; import org.jetbrains.annotations.Nullable; +import thedarkcolour.exdeorum.recipe.crucible.CrucibleHeatRecipe; final class CrucibleHeatSourceRecipe { - private final int meltRate; + private final RecipeHolder recipeHolder; private final BlockState blockState; @Nullable private final IIngredientType ingredientType; @@ -31,15 +33,19 @@ final class CrucibleHeatSourceRecipe { private final Object ingredient; @SuppressWarnings({"rawtypes", "unchecked"}) - CrucibleHeatSourceRecipe(int meltRate, BlockState blockState, @Nullable IIngredientType ingredientType, @Nullable Object ingredient) { - this.meltRate = meltRate; + CrucibleHeatSourceRecipe(RecipeHolder recipeHolder, BlockState blockState, @Nullable IIngredientType ingredientType, @Nullable Object ingredient) { + this.recipeHolder = recipeHolder; this.blockState = blockState; this.ingredientType = ingredientType; this.ingredient = ingredient; } + public RecipeHolder recipeHolder() { + return recipeHolder; + } + public int meltRate() { - return this.meltRate; + return this.recipeHolder.value().heatValue(); } public BlockState blockState() { diff --git a/src/main/java/thedarkcolour/exdeorum/compat/jei/CrucibleHeatSourcesCategory.java b/src/main/java/thedarkcolour/exdeorum/compat/jei/CrucibleHeatSourcesCategory.java index 53fe5658..52fc9c3e 100644 --- a/src/main/java/thedarkcolour/exdeorum/compat/jei/CrucibleHeatSourcesCategory.java +++ b/src/main/java/thedarkcolour/exdeorum/compat/jei/CrucibleHeatSourcesCategory.java @@ -35,8 +35,10 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.TooltipFlag; +import org.jetbrains.annotations.Nullable; import thedarkcolour.exdeorum.compat.ClientXeiUtil; import thedarkcolour.exdeorum.data.TranslationKeys; import thedarkcolour.exdeorum.material.DefaultMaterials; @@ -106,6 +108,11 @@ class CrucibleHeatSourcesCategory implements IRecipeCategory getTooltipStrings(CrucibleHeatSourceRecipe recipe, IRecipeSlotsView recipeSlotsView, double mouseX, double mouseY) { if (44.0 < mouseX && mouseX < 76.0 && 16 < mouseY && mouseY < 48) { diff --git a/src/main/java/thedarkcolour/exdeorum/compat/jei/ExDeorumJeiPlugin.java b/src/main/java/thedarkcolour/exdeorum/compat/jei/ExDeorumJeiPlugin.java index e6f6f1d5..aa410517 100644 --- a/src/main/java/thedarkcolour/exdeorum/compat/jei/ExDeorumJeiPlugin.java +++ b/src/main/java/thedarkcolour/exdeorum/compat/jei/ExDeorumJeiPlugin.java @@ -18,7 +18,6 @@ package thedarkcolour.exdeorum.compat.jei; -import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import mezz.jei.api.IModPlugin; import mezz.jei.api.JeiPlugin; import mezz.jei.api.constants.VanillaTypes; @@ -37,6 +36,7 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.item.crafting.Recipe; +import net.minecraft.world.item.crafting.RecipeHolder; import net.minecraft.world.item.crafting.RecipeInput; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; @@ -44,7 +44,6 @@ import net.minecraft.world.level.block.LiquidBlock; import net.minecraft.world.level.block.WallTorchBlock; import net.neoforged.fml.ModList; import net.neoforged.neoforge.fluids.FluidStack; -import net.neoforged.neoforge.registries.DeferredHolder; import thedarkcolour.exdeorum.ExDeorum; import thedarkcolour.exdeorum.client.ClientsideCode; import thedarkcolour.exdeorum.client.screen.MechanicalHammerScreen; @@ -58,6 +57,7 @@ import thedarkcolour.exdeorum.recipe.RecipeUtil; import thedarkcolour.exdeorum.recipe.barrel.BarrelCompostRecipe; import thedarkcolour.exdeorum.recipe.barrel.BarrelFluidMixingRecipe; import thedarkcolour.exdeorum.recipe.barrel.BarrelMixingRecipe; +import thedarkcolour.exdeorum.recipe.crucible.CrucibleHeatRecipe; import thedarkcolour.exdeorum.recipe.crucible.CrucibleRecipe; import thedarkcolour.exdeorum.recipe.hammer.CompressedHammerRecipe; import thedarkcolour.exdeorum.recipe.hammer.HammerRecipe; @@ -68,6 +68,7 @@ import thedarkcolour.exdeorum.tag.EItemTags; import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; import java.util.List; import java.util.function.Function; import java.util.function.Supplier; @@ -76,18 +77,23 @@ import java.util.function.Supplier; public class ExDeorumJeiPlugin implements IModPlugin { public static final ResourceLocation EX_DEORUM_JEI_TEXTURE = ExDeorum.loc("textures/gui/jei/enr_jei.png"); - static final RecipeType BARREL_COMPOST = recipeType("barrel_compost", BarrelCompostRecipe.class); - static final RecipeType BARREL_MIXING = recipeType("barrel_mixing", BarrelMixingRecipe.class); - static final RecipeType BARREL_FLUID_MIXING = recipeType("barrel_fluid_mixing", BarrelFluidMixingRecipe.class); - static final RecipeType LAVA_CRUCIBLE = recipeType("lava_crucible", CrucibleRecipe.Lava.class); - static final RecipeType WATER_CRUCIBLE = recipeType("water_crucible", CrucibleRecipe.Water.class); + static final RecipeType> BARREL_COMPOST = recipeType("barrel_compost"); + static final RecipeType> BARREL_MIXING = recipeType("barrel_mixing"); + static final RecipeType> BARREL_FLUID_MIXING = recipeType("barrel_fluid_mixing"); + static final RecipeType> LAVA_CRUCIBLE = recipeType("lava_crucible"); + static final RecipeType> WATER_CRUCIBLE = recipeType("water_crucible"); static final RecipeType CRUCIBLE_HEAT_SOURCES = recipeType("crucible_heat_sources", CrucibleHeatSourceRecipe.class); static final RecipeType SIEVE = recipeType("sieve", XeiSieveRecipe.class); static final RecipeType COMPRESSED_SIEVE = recipeType("compressed_sieve", XeiSieveRecipe.class); - static final RecipeType HAMMER = recipeType("hammer", HammerRecipe.class); - static final RecipeType COMPRESSED_HAMMER = recipeType("compressed_hammer", CompressedHammerRecipe.class); + static final RecipeType> HAMMER = recipeType("hammer"); + static final RecipeType> COMPRESSED_HAMMER = recipeType("compressed_hammer"); static final RecipeType CROOK = recipeType("crook", CrookJeiRecipe.class); + private static > RecipeType> recipeType(String path) { + String namespace = ModList.get().isLoaded(ModIds.EMI) ? ExDeorum.ID + "_" + ModIds.EMI : ExDeorum.ID; + return RecipeType.createRecipeHolderType(ResourceLocation.fromNamespaceAndPath(namespace, path)); + } + private static RecipeType recipeType(String path, Class type) { // use alternative namespace so that EMI doesn't skip JEI compatibility String namespace = ModList.get().isLoaded(ModIds.EMI) ? ExDeorum.ID + "_" + ModIds.EMI : ExDeorum.ID; @@ -111,10 +117,10 @@ public class ExDeorumJeiPlugin implements IModPlugin { registration.addRecipeCategories(new CrucibleCategory.LavaCrucible(helper, arrow)); registration.addRecipeCategories(new CrucibleCategory.WaterCrucible(helper, arrow)); registration.addRecipeCategories(new CrucibleHeatSourcesCategory(registration.getJeiHelpers())); - registration.addRecipeCategories(new SieveCategory(helper)); - registration.addRecipeCategories(new CompressedSieveCategory(helper)); - registration.addRecipeCategories(new HammerCategory(helper, arrow, EItems.DIAMOND_HAMMER, Component.translatable(TranslationKeys.HAMMER_CATEGORY_TITLE), HAMMER)); - registration.addRecipeCategories(new HammerCategory(helper, arrow, EItems.COMPRESSED_DIAMOND_HAMMER, Component.translatable(TranslationKeys.COMPRESSED_HAMMER_CATEGORY_TITLE), COMPRESSED_HAMMER)); + registration.addRecipeCategories(new SieveCategory(registration.getJeiHelpers())); + registration.addRecipeCategories(new CompressedSieveCategory(registration.getJeiHelpers())); + registration.addRecipeCategories(new HammerCategory<>(helper, arrow, EItems.DIAMOND_HAMMER, Component.translatable(TranslationKeys.HAMMER_CATEGORY_TITLE), HAMMER)); + registration.addRecipeCategories(new HammerCategory<>(helper, arrow, EItems.COMPRESSED_DIAMOND_HAMMER, Component.translatable(TranslationKeys.COMPRESSED_HAMMER_CATEGORY_TITLE), COMPRESSED_HAMMER)); registration.addRecipeCategories(new CrookCategory(registration.getJeiHelpers(), arrow)); } @@ -214,8 +220,7 @@ public class ExDeorumJeiPlugin implements IModPlugin { addRecipes(registration, LAVA_CRUCIBLE, ERecipeTypes.LAVA_CRUCIBLE); addRecipes(registration, WATER_CRUCIBLE, ERecipeTypes.WATER_CRUCIBLE); addRecipes(registration, HAMMER, ERecipeTypes.HAMMER); - //noinspection rawtypes,unchecked - addRecipes(registration, COMPRESSED_HAMMER, ((DeferredHolder) ERecipeTypes.COMPRESSED_HAMMER)); + addRecipes(registration, COMPRESSED_HAMMER, ERecipeTypes.COMPRESSED_HAMMER); registration.addRecipes(CROOK, CompatUtil.collectAllRecipes(RecipeUtil.getClientRecipeManager(), ERecipeTypes.CROOK.get(), CrookJeiRecipe::create)); registration.addRecipes(SIEVE, XeiSieveRecipe.getAllRecipesGrouped(ERecipeTypes.SIEVE.get(), XeiSieveRecipe.SIEVE_ROWS)); registration.addRecipes(COMPRESSED_SIEVE, XeiSieveRecipe.getAllRecipesGrouped(ERecipeTypes.COMPRESSED_SIEVE.get(), XeiSieveRecipe.COMPRESSED_SIEVE_ROWS)); @@ -224,7 +229,7 @@ public class ExDeorumJeiPlugin implements IModPlugin { } private static void addCrucibleHeatSources(IRecipeRegistration registration) { - var values = new Object2IntOpenHashMap(); + var values = new HashMap>(); for (var entry : ClientsideCode.getRecipeCaches().getHeatSources()) { var state = entry.getKey(); var block = state.getBlock(); @@ -233,13 +238,18 @@ public class ExDeorumJeiPlugin implements IModPlugin { if (block != Blocks.AIR) { final int newValue = entry.getValue().value().heatValue(); + if (newValue == 0) { + // we don't want to display useless heat sources + // why would people even create these? + continue; + } - values.computeInt(block, (key, value) -> { - if (value != null) { - return Math.max(value, newValue); - } else { - return newValue == 0 ? null : newValue; + values.compute(block, (key, value) -> { + if (value != null && value.value().heatValue() > newValue) { + // Existing entry is a better heat source + return value; } + return entry.getValue(); }); } } @@ -247,16 +257,17 @@ public class ExDeorumJeiPlugin implements IModPlugin { var fluidIngredientType = fluidHelper.getFluidIngredientType(); var recipes = new ArrayList(); - for (var entry : values.object2IntEntrySet()) { + for (var entry : values.entrySet()) { + var holder = entry.getValue(); if (entry.getKey() instanceof LiquidBlock liquid) { - recipes.add(new CrucibleHeatSourceRecipe(entry.getIntValue(), entry.getKey().defaultBlockState(), fluidIngredientType, fluidHelper.create(Holder.direct(liquid.fluid), 1000))); + recipes.add(new CrucibleHeatSourceRecipe(holder, entry.getKey().defaultBlockState(), fluidIngredientType, fluidHelper.create(Holder.direct(liquid.fluid), 1000))); } else { var itemForm = entry.getKey().asItem(); if (itemForm != Items.AIR) { - recipes.add(new CrucibleHeatSourceRecipe(entry.getIntValue(), entry.getKey().defaultBlockState(), VanillaTypes.ITEM_STACK, new ItemStack(itemForm))); + recipes.add(new CrucibleHeatSourceRecipe(holder, entry.getKey().defaultBlockState(), VanillaTypes.ITEM_STACK, new ItemStack(itemForm))); } else { - recipes.add(new CrucibleHeatSourceRecipe(entry.getIntValue(), entry.getKey().defaultBlockState(), null, null)); + recipes.add(new CrucibleHeatSourceRecipe(holder, entry.getKey().defaultBlockState(), null, null)); } } } @@ -300,7 +311,7 @@ public class ExDeorumJeiPlugin implements IModPlugin { }); } - private static > void addRecipes(IRecipeRegistration registration, RecipeType category, Supplier> type) { + private static > void addRecipes(IRecipeRegistration registration, RecipeType> category, Supplier> type) { registration.addRecipes(category, CompatUtil.collectAllRecipes(RecipeUtil.getClientRecipeManager(), type.get(), Function.identity())); } } diff --git a/src/main/java/thedarkcolour/exdeorum/compat/jei/HammerCategory.java b/src/main/java/thedarkcolour/exdeorum/compat/jei/HammerCategory.java index 0a4d237d..d2ec024e 100644 --- a/src/main/java/thedarkcolour/exdeorum/compat/jei/HammerCategory.java +++ b/src/main/java/thedarkcolour/exdeorum/compat/jei/HammerCategory.java @@ -23,34 +23,38 @@ import mezz.jei.api.gui.drawable.IDrawable; import mezz.jei.api.helpers.IGuiHelper; import mezz.jei.api.recipe.RecipeType; import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.RecipeHolder; import net.minecraft.world.level.storage.loot.providers.number.ConstantValue; +import org.jetbrains.annotations.Nullable; import thedarkcolour.exdeorum.recipe.hammer.HammerRecipe; import java.util.function.Supplier; -class HammerCategory extends OneToOneCategory { - private final RecipeType recipeType; +class HammerCategory extends OneToOneCategory> { + private final RecipeType> recipeType; - public HammerCategory(IGuiHelper helper, IDrawable arrow, Supplier icon, Component title, RecipeType recipeType) { + public HammerCategory(IGuiHelper helper, IDrawable arrow, Supplier icon, Component title, RecipeType> recipeType) { super(helper, arrow, helper.createDrawableItemStack(new ItemStack(icon.get())), title); this.recipeType = recipeType; } @Override - public RecipeType getRecipeType() { + public RecipeType> getRecipeType() { return this.recipeType; } @Override - protected void addInput(IRecipeSlotBuilder slot, HammerRecipe recipe) { - slot.addIngredients(recipe.ingredient()); + protected void addInput(IRecipeSlotBuilder slot, RecipeHolder holder) { + slot.addIngredients(holder.value().ingredient()); } @Override - protected void addOutput(IRecipeSlotBuilder slot, HammerRecipe recipe) { + protected void addOutput(IRecipeSlotBuilder slot, RecipeHolder holder) { + var recipe = holder.value(); if (recipe.resultAmount instanceof ConstantValue constant) { slot.addItemStack(recipe.result.getCount() == 1 ? recipe.result : recipe.result.copyWithCount((int) constant.value())); } else { diff --git a/src/main/java/thedarkcolour/exdeorum/compat/jei/SieveCategory.java b/src/main/java/thedarkcolour/exdeorum/compat/jei/SieveCategory.java index 52adf0cc..ee5fbcfc 100644 --- a/src/main/java/thedarkcolour/exdeorum/compat/jei/SieveCategory.java +++ b/src/main/java/thedarkcolour/exdeorum/compat/jei/SieveCategory.java @@ -21,32 +21,60 @@ package thedarkcolour.exdeorum.compat.jei; import mezz.jei.api.constants.VanillaTypes; import mezz.jei.api.gui.builder.IRecipeLayoutBuilder; import mezz.jei.api.gui.builder.IRecipeSlotBuilder; +import mezz.jei.api.gui.builder.ITooltipBuilder; import mezz.jei.api.gui.drawable.IDrawable; +import mezz.jei.api.gui.ingredient.IRecipeSlotRichTooltipCallback; +import mezz.jei.api.gui.ingredient.IRecipeSlotView; import mezz.jei.api.gui.ingredient.IRecipeSlotsView; import mezz.jei.api.helpers.IGuiHelper; +import mezz.jei.api.helpers.IJeiHelpers; +import mezz.jei.api.helpers.IModIdHelper; +import mezz.jei.api.ingredients.IIngredientHelper; +import mezz.jei.api.ingredients.IIngredientType; +import mezz.jei.api.ingredients.ITypedIngredient; import mezz.jei.api.recipe.IFocusGroup; import mezz.jei.api.recipe.RecipeIngredientRole; import mezz.jei.api.recipe.RecipeType; import mezz.jei.api.recipe.category.IRecipeCategory; +import mezz.jei.api.runtime.IIngredientManager; +import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.Screen; import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.ItemLike; import net.minecraft.world.level.storage.loot.providers.number.NumberProvider; import org.apache.commons.lang3.mutable.MutableInt; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.Nullable; import thedarkcolour.exdeorum.compat.XeiSieveRecipe; import thedarkcolour.exdeorum.compat.XeiUtil; import thedarkcolour.exdeorum.data.TranslationKeys; import thedarkcolour.exdeorum.material.DefaultMaterials; +import java.util.Optional; + class SieveCategory implements IRecipeCategory { + private final IJeiHelpers jeiHelpers; private final IDrawable slot; private final IDrawable row; private final IDrawable icon; private final Component title; private final MutableInt rows; - SieveCategory(IGuiHelper helper, ItemLike icon, Component title, MutableInt rows) { + /** + * settingSlots is a workaround to prevent JEI from adding recipe tooltips with our generated recipe IDs. + * They look ugly and clutter the screen, since they're pretty long. + */ + private boolean settingSlots = false; + + SieveCategory(IJeiHelpers jeiHelpers, ItemLike icon, Component title, MutableInt rows) { + this.jeiHelpers = jeiHelpers; + var helper = jeiHelpers.getGuiHelper(); this.slot = helper.getSlotDrawable(); this.row = helper.createDrawable(ExDeorumJeiPlugin.EX_DEORUM_JEI_TEXTURE, 0, 0, 162, 18); this.icon = helper.createDrawableItemStack(new ItemStack(icon)); @@ -54,8 +82,8 @@ class SieveCategory implements IRecipeCategory { this.rows = rows; } - SieveCategory(IGuiHelper helper) { - this(helper, DefaultMaterials.OAK_SIEVE, Component.translatable(TranslationKeys.SIEVE_CATEGORY_TITLE), XeiSieveRecipe.SIEVE_ROWS); + SieveCategory(IJeiHelpers jeiHelpers) { + this(jeiHelpers, DefaultMaterials.OAK_SIEVE, Component.translatable(TranslationKeys.SIEVE_CATEGORY_TITLE), XeiSieveRecipe.SIEVE_ROWS); } @Override @@ -83,17 +111,26 @@ class SieveCategory implements IRecipeCategory { return this.icon; } + @Override + public @Nullable ResourceLocation getRegistryName(XeiSieveRecipe recipe) { + return settingSlots ? null : recipe.id(); + } + @Override public void setRecipe(IRecipeLayoutBuilder builder, XeiSieveRecipe recipe, IFocusGroup focuses) { builder.addSlot(RecipeIngredientRole.INPUT, 59, 1).addIngredients(recipe.ingredient()); builder.addSlot(RecipeIngredientRole.CATALYST, 87, 1).addItemStack(recipe.mesh()); + settingSlots = true; for (int i = 0; i < recipe.results().size(); i++) { var result = recipe.results().get(i); var slot = builder.addSlot(RecipeIngredientRole.OUTPUT, 1 + (i % 9) * 18, 1 + XeiUtil.SIEVE_ROW_START + 18 * (i / 9)).addItemStack(result.item); + // Since we group recipes, we need to manually add the recipe ID tooltip for the given output item. + slot.addRichTooltipCallback(new OutputSlotTooltipCallback(result.holder.id(), getRecipeType())); addTooltips(slot, result.byHandOnly, result.provider); } + settingSlots = false; } public static void addTooltips(IRecipeSlotBuilder slot, boolean byHandOnly, NumberProvider provider) { @@ -116,4 +153,77 @@ class SieveCategory implements IRecipeCategory { this.row.draw(graphics, 0, 28 + i * 18); } } + + + /** + * Copied almost 1:1 from class of same name in JEI. Since this is a JEI implementation detail, it's not exposed in the API. + * Modified minimally to not use any of the other internals and compile. + */ + public class OutputSlotTooltipCallback implements IRecipeSlotRichTooltipCallback { + private static final Logger LOGGER = LogManager.getLogger(); + + private final ResourceLocation recipeName; + private final boolean recipeFromSameModAsCategory; + + public OutputSlotTooltipCallback(ResourceLocation recipeName, RecipeType recipeType) { + this.recipeName = recipeName; + this.recipeFromSameModAsCategory = recipeName.getNamespace().equals(recipeType.getUid().getNamespace()); + } + + @Override + public void onRichTooltip(IRecipeSlotView recipeSlotView, ITooltipBuilder tooltip) { + if (recipeSlotView.getRole() != RecipeIngredientRole.OUTPUT) { + return; + } + Optional> displayedIngredient = recipeSlotView.getDisplayedIngredient(); + if (displayedIngredient.isEmpty()) { + return; + } + + addRecipeBy(tooltip, displayedIngredient.get()); + + Minecraft minecraft = Minecraft.getInstance(); + boolean showAdvanced = minecraft.options.advancedItemTooltips || Screen.hasShiftDown(); + if (showAdvanced) { + MutableComponent recipeId = Component.translatable("jei.tooltip.recipe.id", Component.literal(recipeName.toString())); + tooltip.add(recipeId.withStyle(ChatFormatting.DARK_GRAY)); + } + } + + private void addRecipeBy(ITooltipBuilder tooltip, ITypedIngredient displayedIngredient) { + if (recipeFromSameModAsCategory) { + return; + } + IModIdHelper modIdHelper = jeiHelpers.getModIdHelper(); + if (!modIdHelper.isDisplayingModNameEnabled()) { + return; + } + String ingredientModId = getDisplayModId(displayedIngredient); + if (ingredientModId == null) { + return; + } + String recipeModId = recipeName.getNamespace(); + if (recipeModId.equals(ingredientModId)) { + return; + } + String modName = modIdHelper.getFormattedModNameForModId(recipeModId); + MutableComponent recipeBy = Component.translatable("jei.tooltip.recipe.by", modName); + tooltip.add(recipeBy.withStyle(ChatFormatting.GRAY)); + } + + private @Nullable String getDisplayModId(ITypedIngredient typedIngredient) { + IIngredientManager ingredientManager = jeiHelpers.getIngredientManager(); + + IIngredientType type = typedIngredient.getType(); + T ingredient = typedIngredient.getIngredient(); + IIngredientHelper ingredientHelper = ingredientManager.getIngredientHelper(type); + try { + return ingredientHelper.getDisplayModId(ingredient); + } catch (RuntimeException e) { + String ingredientInfo = ingredientHelper.getErrorInfo(ingredient); + LOGGER.error("Caught exception from ingredient without a resource location: {}", ingredientInfo, e); + return null; + } + } + } } From 693b9fd906812adf84d072c8123b1765f31cc6df Mon Sep 17 00:00:00 2001 From: Lorenz Wrobel <43410952+DasBabyPixel@users.noreply.github.com> Date: Wed, 17 Jun 2026 18:15:42 +0200 Subject: [PATCH 3/4] fix import style --- .../java/thedarkcolour/exdeorum/recipe/RecipeCaches.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/main/java/thedarkcolour/exdeorum/recipe/RecipeCaches.java b/src/main/java/thedarkcolour/exdeorum/recipe/RecipeCaches.java index cf64b376..e8dc186f 100644 --- a/src/main/java/thedarkcolour/exdeorum/recipe/RecipeCaches.java +++ b/src/main/java/thedarkcolour/exdeorum/recipe/RecipeCaches.java @@ -13,12 +13,7 @@ import thedarkcolour.exdeorum.recipe.barrel.BarrelCompostRecipe; import thedarkcolour.exdeorum.recipe.barrel.BarrelFluidMixingRecipe; import thedarkcolour.exdeorum.recipe.barrel.BarrelMixingRecipe; import thedarkcolour.exdeorum.recipe.barrel.FluidTransformationRecipe; -import thedarkcolour.exdeorum.recipe.cache.BarrelFluidMixingRecipeCache; -import thedarkcolour.exdeorum.recipe.cache.CrookRecipeCache; -import thedarkcolour.exdeorum.recipe.cache.CrucibleHeatRecipeCache; -import thedarkcolour.exdeorum.recipe.cache.FluidTransformationRecipeCache; -import thedarkcolour.exdeorum.recipe.cache.SieveRecipeCache; -import thedarkcolour.exdeorum.recipe.cache.SingleIngredientRecipeCache; +import thedarkcolour.exdeorum.recipe.cache.*; import thedarkcolour.exdeorum.recipe.crook.CrookRecipe; import thedarkcolour.exdeorum.recipe.crucible.CrucibleHeatRecipe; import thedarkcolour.exdeorum.recipe.crucible.CrucibleRecipe; From cd9017f6c35cbf3b3d35d42131c62fb30c831ee8 Mon Sep 17 00:00:00 2001 From: Lorenz Wrobel <43410952+DasBabyPixel@users.noreply.github.com> Date: Wed, 17 Jun 2026 18:23:31 +0200 Subject: [PATCH 4/4] more style changes --- .../thedarkcolour/exdeorum/compat/jei/CrookJeiRecipe.java | 5 +---- .../exdeorum/compat/jei/CrucibleHeatSourceRecipe.java | 2 +- .../thedarkcolour/exdeorum/compat/jei/SieveCategory.java | 1 - 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/main/java/thedarkcolour/exdeorum/compat/jei/CrookJeiRecipe.java b/src/main/java/thedarkcolour/exdeorum/compat/jei/CrookJeiRecipe.java index 439f3ffa..f7219351 100644 --- a/src/main/java/thedarkcolour/exdeorum/compat/jei/CrookJeiRecipe.java +++ b/src/main/java/thedarkcolour/exdeorum/compat/jei/CrookJeiRecipe.java @@ -60,10 +60,7 @@ public sealed abstract class CrookJeiRecipe { var id = recipeHolder.id(); switch (recipe.blockPredicate()) { case BlockPredicate.BlockStatePredicate state -> { - return new StatesRecipe(id, state, state - .possibleStates() - .filter(blockState -> !blockState.hasProperty(BlockStateProperties.WATERLOGGED) || !blockState.getValue(BlockStateProperties.WATERLOGGED)) - .toList(), recipe.result(), recipe.chance()); + return new StatesRecipe(id, state, state.possibleStates().filter(blockState -> !blockState.hasProperty(BlockStateProperties.WATERLOGGED) || !blockState.getValue(BlockStateProperties.WATERLOGGED)).toList(), recipe.result(), recipe.chance()); } case BlockPredicate.SingleBlockPredicate block -> { return new BlockRecipe(id, block.block(), recipe.result(), recipe.chance()); diff --git a/src/main/java/thedarkcolour/exdeorum/compat/jei/CrucibleHeatSourceRecipe.java b/src/main/java/thedarkcolour/exdeorum/compat/jei/CrucibleHeatSourceRecipe.java index ff745b4c..897e8531 100644 --- a/src/main/java/thedarkcolour/exdeorum/compat/jei/CrucibleHeatSourceRecipe.java +++ b/src/main/java/thedarkcolour/exdeorum/compat/jei/CrucibleHeatSourceRecipe.java @@ -41,7 +41,7 @@ final class CrucibleHeatSourceRecipe { } public RecipeHolder recipeHolder() { - return recipeHolder; + return this.recipeHolder; } public int meltRate() { diff --git a/src/main/java/thedarkcolour/exdeorum/compat/jei/SieveCategory.java b/src/main/java/thedarkcolour/exdeorum/compat/jei/SieveCategory.java index ee5fbcfc..f4ca5bf9 100644 --- a/src/main/java/thedarkcolour/exdeorum/compat/jei/SieveCategory.java +++ b/src/main/java/thedarkcolour/exdeorum/compat/jei/SieveCategory.java @@ -26,7 +26,6 @@ import mezz.jei.api.gui.drawable.IDrawable; import mezz.jei.api.gui.ingredient.IRecipeSlotRichTooltipCallback; import mezz.jei.api.gui.ingredient.IRecipeSlotView; import mezz.jei.api.gui.ingredient.IRecipeSlotsView; -import mezz.jei.api.helpers.IGuiHelper; import mezz.jei.api.helpers.IJeiHelpers; import mezz.jei.api.helpers.IModIdHelper; import mezz.jei.api.ingredients.IIngredientHelper;