server-side recipe holders

This commit is contained in:
Lorenz Wrobel 2026-05-22 17:06:51 +02:00
parent a5d25a09f7
commit 61c7a99e94
20 changed files with 137 additions and 104 deletions

View File

@ -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<? extends CrucibleRecipe> 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))) {

View File

@ -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<FluidTransformationRecipe> 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

View File

@ -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<CrucibleRecipe.Lava> getRecipe(ItemStack item) {
return getRecipeCaches().getLavaCrucibleRecipe(item);
}

View File

@ -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<Mech
}
@Nullable
private HammerRecipe canFitResultIntoOutput(ItemStack input) {
private RecipeHolder<HammerRecipe> 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<Mech
if (recipe != null) {
@SuppressWarnings("DataFlowIssue")
LootContext ctx = RecipeUtil.emptyLootContext((ServerLevel) this.level);
var resultCount = recipe.resultAmount.getInt(ctx);
var resultCount = recipe.value().resultAmount.getInt(ctx);
if (!input.is(EItemTags.HAMMER_FORTUNE_BLACKLIST)) {
resultCount += HammerLootModifier.calculateFortuneBonus(this.level.registryAccess(), this.inventory.getStackInSlot(HAMMER_SLOT), ctx.getRandom(), resultCount == 0);
}
var output = this.inventory.getStackInSlot(OUTPUT_SLOT);
if (output.isEmpty()) {
this.inventory.setStackInSlot(OUTPUT_SLOT, recipe.result.copyWithCount(resultCount));
this.inventory.setStackInSlot(OUTPUT_SLOT, recipe.value().result.copyWithCount(resultCount));
} else {
output.setCount(Math.min(output.getMaxStackSize(), resultCount + output.getCount()));
}

View File

@ -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,7 +36,7 @@ public class WaterCrucibleBlockEntity extends AbstractCrucibleBlockEntity {
}
@Override
protected @Nullable CrucibleRecipe getRecipe(ItemStack item) {
protected @Nullable RecipeHolder<CrucibleRecipe.Water> getRecipe(ItemStack item) {
return getRecipeCaches().getWaterCrucibleRecipe(item);
}

View File

@ -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<? extends SieveRecipe> getDropsFor(ItemStack contents) {
protected List<? extends RecipeHolder<? extends SieveRecipe>> getDropsFor(ItemStack contents) {
return this.owner.getRecipeCaches().getCompressedSieveRecipes(this.mesh.getItem(), contents);
}
}

View File

@ -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<? extends SieveRecipe> 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<? extends SieveRecipe> getDropsFor(ItemStack contents) {
protected List<? extends RecipeHolder<? extends SieveRecipe>> getDropsFor(ItemStack contents) {
return this.owner.getRecipeCaches().getSieveRecipes(this.mesh.getItem(), contents);
}

View File

@ -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<CrucibleRecipe> {
abstract class CrucibleCategory<T extends CrucibleRecipe> extends OneToOneCategory<T> {
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<CrucibleRecipe> {
.setFluidRenderer(Math.max(1000, recipe.getResult().getAmount()), false, 16, 16);
}
static class LavaCrucible extends CrucibleCategory {
static class LavaCrucible extends CrucibleCategory<CrucibleRecipe.Lava> {
public LavaCrucible(IGuiHelper helper, IDrawable arrow) {
super(helper, arrow, DefaultMaterials.PORCELAIN_CRUCIBLE.getItem(), TranslationKeys.LAVA_CRUCIBLE_CATEGORY_TITLE);
}
@Override
public RecipeType<CrucibleRecipe> getRecipeType() {
public RecipeType<CrucibleRecipe.Lava> getRecipeType() {
return ExDeorumJeiPlugin.LAVA_CRUCIBLE;
}
}
static class WaterCrucible extends CrucibleCategory {
static class WaterCrucible extends CrucibleCategory<CrucibleRecipe.Water> {
public WaterCrucible(IGuiHelper helper, IDrawable arrow) {
super(helper, arrow, DefaultMaterials.OAK_CRUCIBLE.getItem(), TranslationKeys.WATER_CRUCIBLE_CATEGORY_TITLE);
}
@Override
public RecipeType<CrucibleRecipe> getRecipeType() {
public RecipeType<CrucibleRecipe.Water> getRecipeType() {
return ExDeorumJeiPlugin.WATER_CRUCIBLE;
}
}

View File

@ -79,8 +79,8 @@ public class ExDeorumJeiPlugin implements IModPlugin {
static final RecipeType<BarrelCompostRecipe> BARREL_COMPOST = recipeType("barrel_compost", BarrelCompostRecipe.class);
static final RecipeType<BarrelMixingRecipe> BARREL_MIXING = recipeType("barrel_mixing", BarrelMixingRecipe.class);
static final RecipeType<BarrelFluidMixingRecipe> BARREL_FLUID_MIXING = recipeType("barrel_fluid_mixing", BarrelFluidMixingRecipe.class);
static final RecipeType<CrucibleRecipe> LAVA_CRUCIBLE = recipeType("lava_crucible", CrucibleRecipe.class);
static final RecipeType<CrucibleRecipe> WATER_CRUCIBLE = recipeType("water_crucible", CrucibleRecipe.class);
static final RecipeType<CrucibleRecipe.Lava> LAVA_CRUCIBLE = recipeType("lava_crucible", CrucibleRecipe.Lava.class);
static final RecipeType<CrucibleRecipe.Water> WATER_CRUCIBLE = recipeType("water_crucible", CrucibleRecipe.Water.class);
static final RecipeType<CrucibleHeatSourceRecipe> CRUCIBLE_HEAT_SOURCES = recipeType("crucible_heat_sources", CrucibleHeatSourceRecipe.class);
static final RecipeType<XeiSieveRecipe> SIEVE = recipeType("sieve", XeiSieveRecipe.class);
static final RecipeType<XeiSieveRecipe> 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) {

View File

@ -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<CompressedHammerRecipe> getRecipe(Item itemForm, LootContext context) {
return RecipeUtil.getCaches(context.getLevel()).getCompressedHammerRecipe(itemForm);
}
}

View File

@ -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<CrookRecipe> 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());

View File

@ -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<ItemStack> 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<? extends HammerRecipe> getRecipe(Item itemForm, LootContext context) {
return RecipeUtil.getCaches(context.getLevel()).getHammerRecipe(itemForm);
}

View File

@ -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<BarrelCompostRecipe> barrelCompostRecipeCache;
private SingleIngredientRecipeCache<CrucibleRecipe> lavaCrucibleRecipeCache;
private SingleIngredientRecipeCache<CrucibleRecipe> waterCrucibleRecipeCache;
private SingleIngredientRecipeCache<CrucibleRecipe.Lava> lavaCrucibleRecipeCache;
private SingleIngredientRecipeCache<CrucibleRecipe.Water> waterCrucibleRecipeCache;
private SingleIngredientRecipeCache<HammerRecipe> hammerRecipeCache;
private SingleIngredientRecipeCache<CompressedHammerRecipe> compressedHammerRecipeCache;
private SieveRecipeCache<SieveRecipe> sieveRecipeCache;
@ -40,31 +46,31 @@ public class RecipeCaches {
private CrookRecipeCache crookRecipeCache;
private CrucibleHeatRecipeCache crucibleHeatRecipeCache;
public List<SieveRecipe> getSieveRecipes(Item mesh, ItemStack item) {
public List<RecipeHolder<SieveRecipe>> getSieveRecipes(Item mesh, ItemStack item) {
return this.sieveRecipeCache.getRecipe(mesh, item);
}
public List<CompressedSieveRecipe> getCompressedSieveRecipes(Item mesh, ItemStack item) {
public List<RecipeHolder<CompressedSieveRecipe>> getCompressedSieveRecipes(Item mesh, ItemStack item) {
return this.compressedSieveRecipeCache.getRecipe(mesh, item);
}
@Nullable
public CrucibleRecipe getLavaCrucibleRecipe(ItemStack item) {
public RecipeHolder<CrucibleRecipe.Lava> getLavaCrucibleRecipe(ItemStack item) {
return this.lavaCrucibleRecipeCache.getRecipe(item);
}
@Nullable
public CrucibleRecipe getWaterCrucibleRecipe(ItemStack item) {
public RecipeHolder<CrucibleRecipe.Water> getWaterCrucibleRecipe(ItemStack item) {
return this.waterCrucibleRecipeCache.getRecipe(item);
}
@Nullable
public BarrelCompostRecipe getBarrelCompostRecipe(ItemStack item) {
public RecipeHolder<BarrelCompostRecipe> getBarrelCompostRecipe(ItemStack item) {
return this.barrelCompostRecipeCache.getRecipe(item);
}
@Nullable
public HammerRecipe getHammerRecipe(Item item) {
public RecipeHolder<HammerRecipe> getHammerRecipe(Item item) {
return this.hammerRecipeCache.getRecipe(item);
}
@ -73,7 +79,7 @@ public class RecipeCaches {
}
@Nullable
public CompressedHammerRecipe getCompressedHammerRecipe(Item item) {
public RecipeHolder<CompressedHammerRecipe> getCompressedHammerRecipe(Item item) {
return this.compressedHammerRecipeCache.getRecipe(item);
}
@ -81,7 +87,7 @@ public class RecipeCaches {
return this.compressedHammerRecipeCache.getAllRecipes();
}
public List<CrookRecipe> getCrookRecipes(BlockState state) {
public List<RecipeHolder<CrookRecipe>> 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<CrucibleHeatRecipe> getHeatRecipe(BlockState state) {
return this.crucibleHeatRecipeCache.getRecipe(state);
}
public ObjectSet<Object2IntMap.Entry<BlockState>> getHeatSources() {
public Set<Map.Entry<BlockState, RecipeHolder<CrucibleHeatRecipe>>> getHeatSources() {
return this.crucibleHeatRecipeCache.getEntries();
}
// todo stop using the RecipeManager
@Nullable
public BarrelMixingRecipe getBarrelMixingRecipe(RecipeManager recipes, ItemStack stack, FluidStack fluid) {
public RecipeHolder<BarrelMixingRecipe> 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<BarrelFluidMixingRecipe> 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<FluidTransformationRecipe> getFluidTransformationRecipe(Fluid baseFluid, BlockState catalystState) {
if (baseFluid != Fluids.EMPTY) {
return this.fluidTransformationRecipeCache.getRecipe(baseFluid, catalystState);
} else {

View File

@ -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<Fluid, Map<Fluid, BarrelFluidMixingRecipe>> recipes;
private Map<Fluid, Map<Fluid, RecipeHolder<BarrelFluidMixingRecipe>>> recipes;
public BarrelFluidMixingRecipeCache(RecipeManager recipeManager) {
this.recipeManager = recipeManager;
}
@Nullable
public BarrelFluidMixingRecipe getRecipe(Fluid baseFluid, Fluid additive) {
public RecipeHolder<BarrelFluidMixingRecipe> 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);
}
}
}

View File

@ -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<BlockState, List<CrookRecipe>> recipes;
private Map<BlockState, List<RecipeHolder<CrookRecipe>>> recipes;
public CrookRecipeCache(RecipeManager recipeManager) {
this.recipeManager = recipeManager;
}
public List<CrookRecipe> getRecipes(BlockState state) {
public List<RecipeHolder<CrookRecipe>> 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<BlockState, HashSet<CrookRecipe>>();
var tempRecipes = new HashMap<BlockState, HashSet<RecipeHolder<CrookRecipe>>>();
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<HashSet<CrookRecipe>, List<CrookRecipe>>();
var dedupeMap = new HashMap<HashSet<RecipeHolder<CrookRecipe>>, List<RecipeHolder<CrookRecipe>>>();
for (var entry : tempRecipes.entrySet()) {
this.recipes.put(entry.getKey(), dedupeMap.computeIfAbsent(entry.getValue(), List::copyOf));

View File

@ -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<BlockState> recipes;
private Map<BlockState, RecipeHolder<CrucibleHeatRecipe>> recipes;
public CrucibleHeatRecipeCache(RecipeManager recipeManager) {
this.recipeManager = recipeManager;
}
public int getValue(BlockState state) {
public RecipeHolder<CrucibleHeatRecipe> 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<Object2IntMap.Entry<BlockState>> getEntries() {
public Set<Map.Entry<BlockState, RecipeHolder<CrucibleHeatRecipe>>> getEntries() {
if (this.recipes == null) {
buildRecipes();
}
return this.recipes.object2IntEntrySet();
return this.recipes.entrySet();
}
}

View File

@ -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<BlockState, Map<Fluid, FluidTransformationRecipe>> recipes;
private Map<BlockState, Map<Fluid, RecipeHolder<FluidTransformationRecipe>>> recipes;
public FluidTransformationRecipeCache(RecipeManager manager) {
this.recipeManager = manager;
}
@Nullable
public FluidTransformationRecipe getRecipe(Fluid baseFluid, BlockState catalystState) {
public RecipeHolder<FluidTransformationRecipe> 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<Fluid, FluidTransformationRecipe>, Map<Fluid, FluidTransformationRecipe>>();
var dedupe = new HashMap<Map<Fluid, RecipeHolder<FluidTransformationRecipe>>, Map<Fluid, RecipeHolder<FluidTransformationRecipe>>>();
for (var entry : this.recipes.entrySet()) {
entry.setValue(dedupe.computeIfAbsent(entry.getValue(), Map::copyOf));
}

View File

@ -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<T extends SieveRecipe> {
this.recipeType = recipeType;
}
public List<T> getRecipe(Item mesh, ItemStack input) {
public List<RecipeHolder<T>> getRecipe(Item mesh, ItemStack input) {
if (this.meshCaches == null) {
buildRecipes();
}
@ -53,11 +54,11 @@ public class SieveRecipeCache<T extends SieveRecipe> {
private void buildRecipes() {
// Group recipes based on their mesh
var tempMap = new HashMap<Item, List<T>>();
var tempMap = new HashMap<Item, List<RecipeHolder<T>>>();
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<T extends SieveRecipe> {
// 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<T extends SieveRecipe> {
private final Map<Item, List<T>> simpleRecipes;
private final Map<Item, List<RecipeHolder<T>>> simpleRecipes;
private MeshRecipeCache(List<T> recipes) {
private MeshRecipeCache(List<RecipeHolder<T>> recipes) {
this.simpleRecipes = new HashMap<>();
var temp = new HashMap<Item, ImmutableList.Builder<T>>();
var temp = new HashMap<Item, ImmutableList.Builder<RecipeHolder<T>>>();
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<T extends SieveRecipe> {
}
}
public List<T> getRecipes(ItemStack input) {
public List<RecipeHolder<T>> getRecipes(ItemStack input) {
var result = this.simpleRecipes.get(input.getItem());
return result == null ? List.of() : result;
}

View File

@ -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<T extends SingleIngredientRecipe> {
private final Supplier<RecipeType<T>> recipeType;
private RecipeManager recipeManager;
@Nullable
private Map<Item, T> simpleRecipes;
private Map<Item, RecipeHolder<T>> simpleRecipes;
@Nullable
private List<T> complexRecipes;
private List<RecipeHolder<T>> complexRecipes;
@Nullable
private Collection<RecipeHolder<T>> allRecipes;
private boolean trackAllRecipes;
@ -55,12 +56,12 @@ public class SingleIngredientRecipeCache<T extends SingleIngredientRecipe> {
}
@Nullable
public T getRecipe(Item item) {
public RecipeHolder<T> getRecipe(Item item) {
return getRecipe(new ItemStack(item));
}
@Nullable
public T getRecipe(ItemStack item) {
public RecipeHolder<T> getRecipe(ItemStack item) {
if (this.simpleRecipes == null) {
buildRecipes();
}
@ -70,7 +71,7 @@ public class SingleIngredientRecipeCache<T extends SingleIngredientRecipe> {
// 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<T extends SingleIngredientRecipe> {
if (this.simpleRecipes == null) {
buildRecipes();
}
return this.allRecipes;
return Objects.requireNonNull(this.allRecipes);
}
/**
@ -99,7 +100,7 @@ public class SingleIngredientRecipeCache<T extends SingleIngredientRecipe> {
*/
private void buildRecipes() {
this.simpleRecipes = new HashMap<>();
var complexRecipes = ImmutableList.<T>builder();
var complexRecipes = ImmutableList.<RecipeHolder<T>>builder();
var allRecipes = this.recipeManager.byType(this.recipeType.get());
@ -109,10 +110,10 @@ public class SingleIngredientRecipeCache<T extends SingleIngredientRecipe> {
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);
}
}

View File

@ -43,8 +43,8 @@ public class ERecipeTypes {
public static final DeferredHolder<RecipeType<?>, RecipeType<BarrelFluidMixingRecipe>> BARREL_FLUID_MIXING = RECIPE_TYPES.register("barrel_fluid_mixing", () -> RecipeType.simple(ERecipeTypes.BARREL_FLUID_MIXING.getId()));
public static final DeferredHolder<RecipeType<?>, RecipeType<FluidTransformationRecipe>> BARREL_FLUID_TRANSFORMATION = RECIPE_TYPES.register("barrel_fluid_transformation", () -> RecipeType.simple(ERecipeTypes.BARREL_FLUID_TRANSFORMATION.getId()));
public static final DeferredHolder<RecipeType<?>, RecipeType<CrucibleRecipe>> LAVA_CRUCIBLE = RECIPE_TYPES.register("lava_crucible", () -> RecipeType.simple(ERecipeTypes.LAVA_CRUCIBLE.getId()));
public static final DeferredHolder<RecipeType<?>, RecipeType<CrucibleRecipe>> WATER_CRUCIBLE = RECIPE_TYPES.register("water_crucible", () -> RecipeType.simple(ERecipeTypes.WATER_CRUCIBLE.getId()));
public static final DeferredHolder<RecipeType<?>, RecipeType<CrucibleRecipe.Lava>> LAVA_CRUCIBLE = RECIPE_TYPES.register("lava_crucible", () -> RecipeType.simple(ERecipeTypes.LAVA_CRUCIBLE.getId()));
public static final DeferredHolder<RecipeType<?>, RecipeType<CrucibleRecipe.Water>> WATER_CRUCIBLE = RECIPE_TYPES.register("water_crucible", () -> RecipeType.simple(ERecipeTypes.WATER_CRUCIBLE.getId()));
public static final DeferredHolder<RecipeType<?>, RecipeType<HammerRecipe>> HAMMER = RECIPE_TYPES.register("hammer", () -> RecipeType.simple(ERecipeTypes.HAMMER.getId()));
public static final DeferredHolder<RecipeType<?>, RecipeType<CompressedHammerRecipe>> COMPRESSED_HAMMER = RECIPE_TYPES.register("compressed_hammer", () -> RecipeType.simple(ERecipeTypes.COMPRESSED_HAMMER.getId()));