Compiles!

This commit is contained in:
thedarkcolour 2024-03-17 23:47:56 -07:00
parent 6e0f636950
commit 2b7645e231
123 changed files with 2387 additions and 3167 deletions

View File

@ -4,7 +4,7 @@ plugins {
id 'net.neoforged.gradle.userdev' version '7.0.80'
}
version = '1.26'
version = '2.0'
group = 'thedarkcolour.exdeorum'
base {
archivesName = 'exdeorum'
@ -103,18 +103,18 @@ dependencies {
// JEI OPTIONAL
compileOnly("mezz.jei:jei-${mc_version}-common-api:${jei_version}")
compileOnly("mezz.jei:jei-${mc_version}-neoforge-api:${jei_version}")
compileOnly("mezz.jei:jei-${mc_version}-neoforge:${jei_version}")
// REI OPTIONAL
implementation("me.shedaniel:RoughlyEnoughItems-forge:${rei_version}")
implementation("me.shedaniel.cloth:cloth-config-neoforge:${cloth_config_version}")
implementation("curse.maven:reipc-521393:4837449")
runtimeOnly("mezz.jei:jei-${mc_version}-neoforge:${jei_version}")
// REI OPTIONAL todo add
compileOnly("me.shedaniel:RoughlyEnoughItems-forge:${rei_version}")
compileOnly("me.shedaniel.cloth:cloth-config-neoforge:${cloth_config_version}")
//implementation("curse.maven:reipc-521393:4837449")
// KubeJS OPTIONAL todo add when KubeJS updates
//implementation("dev.architectury:architectury-neoforge:${architectury_version}")
//implementation("dev.latvian.mods:rhino-neoforge:${rhino_version}")
//implementation("dev.latvian.mods:kubejs-neoforge:${kubejs_version}")
// ModKit DEV ONLY
implementation('com.github.thedarkcolour:Modkit:f4039e5b6b')
implementation('com.github.thedarkcolour:Modkit:e9334176e0')
// Oculus + Embeddium OPTIONAL
compileOnly('maven.modrinth:oculus:1.20.1-1.6.9')

View File

@ -4,7 +4,7 @@ org.gradle.jvmargs=-Xmx3G
org.gradle.parallel=true
mc_version=1.20.4
neo_version=20.4.80-beta
neo_version=20.4.198
neo_version_range=[20.4,)
loader_version_range=[2,)

View File

@ -18,19 +18,22 @@
package thedarkcolour.exdeorum;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.common.ForgeMod;
import net.minecraftforge.data.loading.DatagenModLoader;
import net.minecraftforge.fml.DistExecutor;
import net.minecraftforge.fml.ModList;
import net.minecraftforge.fml.ModLoadingContext;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.config.ModConfig;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.bus.api.IEventBus;
import net.neoforged.fml.ModList;
import net.neoforged.fml.ModLoadingContext;
import net.neoforged.fml.common.Mod;
import net.neoforged.fml.config.ModConfig;
import net.neoforged.fml.javafmlmod.FMLJavaModLoadingContext;
import net.neoforged.fml.loading.FMLEnvironment;
import net.neoforged.neoforge.common.NeoForgeMod;
import net.neoforged.neoforge.data.loading.DatagenModLoader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import thedarkcolour.exdeorum.client.ClientHandler;
import thedarkcolour.exdeorum.config.EConfig;
import thedarkcolour.exdeorum.data.Data;
import thedarkcolour.exdeorum.data.ModCompatData;
import thedarkcolour.exdeorum.event.EventHandler;
import thedarkcolour.exdeorum.material.DefaultMaterials;
import thedarkcolour.exdeorum.network.NetworkHandler;
@ -45,28 +48,29 @@ public class ExDeorum {
public static final boolean DEBUG = ModList.get().isLoaded("modkit");
public static final boolean IS_JUNE = Calendar.getInstance().get(Calendar.MONTH) == Calendar.JUNE;
public ExDeorum() {
createRegistries();
NetworkHandler.register();
public ExDeorum(IEventBus modBus) {
createRegistries(modBus);
// Still enabled in Dev environment because KubeJS enables milk fluid
if (DatagenModLoader.isRunningDataGen()) {
ForgeMod.enableMilkFluid();
NeoForgeMod.enableMilkFluid();
ModCompatData.registerModData(modBus);
modBus.addListener(Data::generateData);
}
// Game Events
EventHandler.register();
// Client init
DistExecutor.safeRunWhenOn(Dist.CLIENT, () -> ClientHandlerRegistrar::register);
EventHandler.register(modBus);
// Client init (todo test that this doesn't crash servers)
if (FMLEnvironment.dist == Dist.CLIENT) {
ClientHandler.register(modBus);
}
// Config init
ModLoadingContext.get().registerConfig(ModConfig.Type.SERVER, EConfig.SERVER_SPEC);
ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, EConfig.COMMON_SPEC);
ModLoadingContext.get().registerConfig(ModConfig.Type.CLIENT, EConfig.CLIENT_SPEC);
}
private static void createRegistries() {
var modBus = FMLJavaModLoadingContext.get().getModEventBus();
private static void createRegistries(IEventBus modBus) {
EBlocks.BLOCKS.register(modBus);
EBlockEntities.BLOCK_ENTITIES.register(modBus);
EChunkGenerators.CHUNK_GENERATORS.register(modBus);
@ -82,10 +86,4 @@ public class ExDeorum {
ENumberProviders.NUMBER_PROVIDERS.register(modBus);
DefaultMaterials.registerMaterials();
}
private interface ClientHandlerRegistrar {
private static void register() {
ClientHandler.register();
}
}
}

View File

@ -29,6 +29,7 @@ import thedarkcolour.exdeorum.voidworld.VoidChunkGenerator;
import java.util.Properties;
// todo test that all of these patches still work properly
@SuppressWarnings("unused")
public final class ASMHooks {
/**

View File

@ -45,9 +45,11 @@ public abstract class AbstractCrucibleBlock extends EBlock {
@Override
public int getLightEmission(BlockState state, BlockGetter level, BlockPos pos) {
if (level.getExistingBlockEntity(pos) instanceof AbstractCrucibleBlockEntity crucible) {
return crucible.getTank().getFluid().getFluid().getFluidType().getLightLevel();
}
// todo look at auxiliary light manager
//if (level.getBlockEntity(pos) instanceof AbstractCrucibleBlockEntity crucible) {
// return crucible.getTank().getFluid().getFluid().getFluidType().getLightLevel();
//}
//return pos == BlockPos.ZERO ? 1 : 0;
return 0;
}

View File

@ -27,6 +27,7 @@ import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.EntityBlock;
import net.minecraft.world.level.block.LeavesBlock;
@ -70,7 +71,7 @@ public class InfestedLeavesBlock extends LeavesBlock implements EntityBlock {
public void setPlacedBy(Level level, BlockPos pos, BlockState pState, @Nullable LivingEntity player, ItemStack pStack) {
if (player != null) {
if (!level.isClientSide && level.getBlockEntity(pos) instanceof InfestedLeavesBlockEntity leaves) {
leaves.setProgress(1.0f);
leaves.setProgress(InfestedLeavesBlockEntity.MAX_PROGRESS);
}
}
}
@ -89,7 +90,7 @@ public class InfestedLeavesBlock extends LeavesBlock implements EntityBlock {
}
@Override
public ItemStack getCloneItemStack(BlockState state, HitResult target, BlockGetter level, BlockPos pos, Player player) {
public ItemStack getCloneItemStack(BlockState state, HitResult target, LevelReader level, BlockPos pos, Player player) {
if (level.getBlockEntity(pos) instanceof InfestedLeavesBlockEntity leaves) {
return leaves.getMimic().getCloneItemStack(target, level, pos, player);
}

View File

@ -39,10 +39,9 @@ import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BooleanProperty;
import net.minecraft.world.level.block.state.properties.DirectionProperty;
import net.minecraftforge.items.ItemStackHandler;
import net.neoforged.neoforge.items.ItemStackHandler;
import org.jetbrains.annotations.Nullable;
import thedarkcolour.exdeorum.blockentity.MechanicalHammerBlockEntity;
import thedarkcolour.exdeorum.blockentity.MechanicalSieveBlockEntity;
import thedarkcolour.exdeorum.config.EConfig;
import thedarkcolour.exdeorum.data.TranslationKeys;
import thedarkcolour.exdeorum.registry.EBlockEntities;
@ -88,7 +87,7 @@ public class MechanicalHammerBlock extends EBlock {
}
@Override
public void playerWillDestroy(Level level, BlockPos pos, BlockState pState, Player player) {
public BlockState playerWillDestroy(Level level, BlockPos pos, BlockState pState, Player player) {
if (!level.isClientSide && player.isCreative() && level.getGameRules().getBoolean(GameRules.RULE_DOBLOCKDROPS)) {
if (level.getBlockEntity(pos) instanceof MechanicalHammerBlockEntity sieve) {
if (!sieve.inventory.getStackInSlot(MechanicalHammerBlockEntity.HAMMER_SLOT).isEmpty()) {
@ -101,7 +100,7 @@ public class MechanicalHammerBlock extends EBlock {
}
}
super.playerWillDestroy(level, pos, pState, player);
return super.playerWillDestroy(level, pos, pState, player);
}
@Override

View File

@ -38,7 +38,7 @@ import net.minecraft.world.level.pathfinder.PathComputationType;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
import net.minecraftforge.items.ItemStackHandler;
import net.neoforged.neoforge.items.ItemStackHandler;
import org.jetbrains.annotations.Nullable;
import thedarkcolour.exdeorum.blockentity.MechanicalSieveBlockEntity;
import thedarkcolour.exdeorum.config.EConfig;
@ -90,7 +90,7 @@ public class MechanicalSieveBlock extends EBlock {
// Drops the item for creative mode players
@Override
public void playerWillDestroy(Level level, BlockPos pos, BlockState pState, Player player) {
public BlockState playerWillDestroy(Level level, BlockPos pos, BlockState pState, Player player) {
if (!level.isClientSide && player.isCreative() && level.getGameRules().getBoolean(GameRules.RULE_DOBLOCKDROPS)) {
if (level.getBlockEntity(pos) instanceof MechanicalSieveBlockEntity sieve) {
if (!sieve.getLogic().getMesh().isEmpty()) {
@ -103,7 +103,7 @@ public class MechanicalSieveBlock extends EBlock {
}
}
super.playerWillDestroy(level, pos, pState, player);
return super.playerWillDestroy(level, pos, pState, player);
}
@Override

View File

@ -36,7 +36,7 @@ import net.minecraft.world.level.ServerLevelAccessor;
import net.minecraft.world.level.block.LiquidBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.FlowingFluid;
import net.minecraftforge.event.ForgeEventFactory;
import net.neoforged.neoforge.event.EventHooks;
import org.jetbrains.annotations.Nullable;
import thedarkcolour.exdeorum.config.EConfig;
@ -70,7 +70,7 @@ public class WitchWaterBlock extends LiquidBlock {
zombieVillager.setTradeOffers(villager.getOffers().createTag());
zombieVillager.setVillagerXp(villager.getVillagerXp());
net.minecraftforge.event.ForgeEventFactory.onLivingConvert(villager, zombieVillager);
EventHooks.onLivingConvert(villager, zombieVillager);
villager.discard();
}
@ -123,7 +123,7 @@ public class WitchWaterBlock extends LiquidBlock {
if (newEntity != null) {
var serverLevel = (ServerLevelAccessor) level;
newEntity.copyPosition(entity);
ForgeEventFactory.onFinalizeSpawn(newEntity, serverLevel, level.getCurrentDifficultyAt(entity.blockPosition()), MobSpawnType.CONVERSION, null, null);
EventHooks.onFinalizeSpawn(newEntity, serverLevel, level.getCurrentDifficultyAt(entity.blockPosition()), MobSpawnType.CONVERSION, null, null);
newEntity.setNoAi(newEntity.isNoAi());
if (entity.hasCustomName()) {
@ -132,7 +132,7 @@ public class WitchWaterBlock extends LiquidBlock {
}
newEntity.setPersistenceRequired();
net.minecraftforge.event.ForgeEventFactory.onLivingConvert((LivingEntity) entity, newEntity);
EventHooks.onLivingConvert((LivingEntity) entity, newEntity);
serverLevel.addFreshEntityWithPassengers(newEntity);
entity.discard();
}

View File

@ -19,7 +19,6 @@
package thedarkcolour.exdeorum.blockentity;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.FriendlyByteBuf;
@ -39,17 +38,14 @@ import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.Fluid;
import net.minecraft.world.level.material.Fluids;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.ForgeCapabilities;
import net.minecraftforge.common.util.Lazy;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.FluidUtil;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.fluids.capability.templates.FluidTank;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.ItemStackHandler;
import net.minecraftforge.registries.ForgeRegistries;
import net.neoforged.neoforge.capabilities.Capabilities;
import net.neoforged.neoforge.common.util.Lazy;
import net.neoforged.neoforge.fluids.FluidStack;
import net.neoforged.neoforge.fluids.FluidUtil;
import net.neoforged.neoforge.fluids.capability.IFluidHandler;
import net.neoforged.neoforge.fluids.capability.templates.FluidTank;
import net.neoforged.neoforge.items.IItemHandler;
import net.neoforged.neoforge.items.ItemStackHandler;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import thedarkcolour.exdeorum.blockentity.helper.FluidHelper;
@ -61,7 +57,6 @@ import thedarkcolour.exdeorum.registry.EItems;
import java.util.HashMap;
import java.util.function.Consumer;
@SuppressWarnings("deprecation")
public abstract class AbstractCrucibleBlockEntity extends EBlockEntity {
public static final Lazy<HashMap<Item, Block>> MELT_OVERRIDES = Lazy.concurrentOf(() -> {
var map = new HashMap<Item, Block>();
@ -73,9 +68,6 @@ public abstract class AbstractCrucibleBlockEntity extends EBlockEntity {
private final AbstractCrucibleBlockEntity.ItemHandler item = new AbstractCrucibleBlockEntity.ItemHandler();
private final AbstractCrucibleBlockEntity.FluidHandler tank = new AbstractCrucibleBlockEntity.FluidHandler();
// Capabilities
private final LazyOptional<IItemHandler> itemHandler = LazyOptional.of(() -> this.item);
private final LazyOptional<IFluidHandler> fluidHandler = LazyOptional.of(() -> this.tank);
@Nullable
private Block lastMelted;
@ -88,35 +80,18 @@ public abstract class AbstractCrucibleBlockEntity extends EBlockEntity {
super(type, pos, state);
}
@NotNull
@Override
public <T> LazyOptional<T> getCapability(@NotNull Capability<T> cap, @Nullable Direction side) {
if (!this.remove) {
if (cap == ForgeCapabilities.FLUID_HANDLER) {
return this.fluidHandler.cast();
} else if (cap == ForgeCapabilities.ITEM_HANDLER) {
return this.itemHandler.cast();
}
}
return super.getCapability(cap, side);
}
@Override
public void invalidateCaps() {
super.invalidateCaps();
this.fluidHandler.invalidate();
this.itemHandler.invalidate();
}
// NBT
@Override
public void saveAdditional(CompoundTag nbt) {
super.saveAdditional(nbt);
nbt.put("Tank", this.tank.writeToNBT(new CompoundTag()));
nbt.putString("LastMelted", ForgeRegistries.BLOCKS.getKey(this.lastMelted).toString());
nbt.putString("Fluid", ForgeRegistries.FLUIDS.getKey(this.fluid).toString());
if (this.lastMelted != null) {
nbt.putString("LastMelted", BuiltInRegistries.BLOCK.getKey(this.lastMelted).toString());
}
if (this.fluid != null) {
nbt.putString("Fluid", BuiltInRegistries.FLUID.getKey(this.fluid).toString());
}
nbt.putShort("Solids", this.solids);
}
@ -125,8 +100,8 @@ public abstract class AbstractCrucibleBlockEntity extends EBlockEntity {
super.load(nbt);
this.tank.readFromNBT(nbt.getCompound("Tank"));
this.lastMelted = ForgeRegistries.BLOCKS.getValue(new ResourceLocation(nbt.getString("LastMelted")));
this.fluid = ForgeRegistries.FLUIDS.getValue(new ResourceLocation(nbt.getString("Fluid")));
this.lastMelted = BuiltInRegistries.BLOCK.get(new ResourceLocation(nbt.getString("LastMelted")));
this.fluid = BuiltInRegistries.FLUID.get(new ResourceLocation(nbt.getString("Fluid")));
this.solids = nbt.getShort("Solids");
this.needsLightUpdate = true;
}
@ -156,7 +131,7 @@ public abstract class AbstractCrucibleBlockEntity extends EBlockEntity {
public InteractionResult use(Level level, Player player, InteractionHand hand) {
var playerItem = player.getItemInHand(hand);
if (playerItem.getCapability(ForgeCapabilities.FLUID_HANDLER_ITEM).isPresent()) {
if (playerItem.getCapability(Capabilities.FluidHandler.ITEM) != null) {
return FluidUtil.interactWithFluidHandler(player, hand, this.tank) ? InteractionResult.sidedSuccess(level.isClientSide) : InteractionResult.PASS;
}
@ -247,6 +222,10 @@ public abstract class AbstractCrucibleBlockEntity extends EBlockEntity {
return this.tank;
}
public IItemHandler getItem() {
return this.item;
}
public abstract Block getDefaultMeltBlock();
@Nullable
@ -254,13 +233,6 @@ public abstract class AbstractCrucibleBlockEntity extends EBlockEntity {
return this.lastMelted;
}
@Override
public void setRemoved() {
this.itemHandler.invalidate();
this.fluidHandler.invalidate();
super.setRemoved();
}
private static void addMeltOverrides(HashMap<Item, Block> overrides) {
overrides.put(Items.OAK_SAPLING, Blocks.OAK_LEAVES);
overrides.put(Items.SPRUCE_SAPLING, Blocks.SPRUCE_LEAVES);
@ -277,14 +249,15 @@ public abstract class AbstractCrucibleBlockEntity extends EBlockEntity {
overrides.put(EItems.WARPED_NYLIUM_SPORES.get(), Blocks.WARPED_NYLIUM);
overrides.put(EItems.CRIMSON_NYLIUM_SPORES.get(), Blocks.CRIMSON_NYLIUM);
for (var sapling : ForgeRegistries.BLOCKS.getEntries()) {
for (var sapling : BuiltInRegistries.BLOCK.entrySet()) {
var item = sapling.getValue().asItem();
if (!overrides.containsKey(item)) {
var key = sapling.getKey().location();
if (key.getPath().endsWith("sapling")) {
try {
overrides.put(item, ForgeRegistries.BLOCKS.getValue(new ResourceLocation(key.getNamespace(), key.getPath().replace("sapling", "leaves"))));
overrides.put(item, BuiltInRegistries.BLOCK.get(new ResourceLocation(key.getNamespace(), key.getPath().replace("sapling", "leaves"))));
} catch (Exception ignored) {
}
}

View File

@ -19,7 +19,6 @@
package thedarkcolour.exdeorum.blockentity;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.Mth;
@ -31,16 +30,12 @@ import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntityTicker;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.ForgeCapabilities;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.energy.EnergyStorage;
import net.minecraftforge.network.NetworkHooks;
import net.neoforged.neoforge.energy.IEnergyStorage;
import net.neoforged.neoforge.items.IItemHandler;
import thedarkcolour.exdeorum.blockentity.helper.EnergyHelper;
import thedarkcolour.exdeorum.blockentity.helper.ItemHelper;
import thedarkcolour.exdeorum.client.screen.RedstoneControlWidget;
import javax.annotation.Nonnull;
import java.util.function.Function;
public abstract class AbstractMachineBlockEntity<M extends AbstractMachineBlockEntity<M>> extends EBlockEntity implements MenuProvider {
@ -50,18 +45,12 @@ public abstract class AbstractMachineBlockEntity<M extends AbstractMachineBlockE
// not saved to NBT
protected boolean hasRedstonePower;
private final LazyOptional<ItemHelper> capabilityInventory;
private final LazyOptional<EnergyStorage> capabilityEnergy;
@SuppressWarnings("unchecked")
public AbstractMachineBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState state, Function<M, ItemHelper> inventory, int maxEnergy) {
super(type, pos, state);
this.inventory = inventory.apply((M) this);
this.energy = new EnergyHelper(maxEnergy);
this.capabilityInventory = LazyOptional.of(() -> this.inventory);
this.capabilityEnergy = LazyOptional.of(() -> this.energy);
}
@Override
@ -99,31 +88,10 @@ public abstract class AbstractMachineBlockEntity<M extends AbstractMachineBlockE
return this.redstoneMode;
}
@SuppressWarnings("NullableProblems")
@Override
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @javax.annotation.Nullable Direction side) {
if (cap == ForgeCapabilities.ENERGY) {
return this.capabilityEnergy.cast();
} else if (cap == ForgeCapabilities.ITEM_HANDLER) {
return this.capabilityInventory.cast();
}
return super.getCapability(cap, side);
}
@Override
public void invalidateCaps() {
super.invalidateCaps();
this.capabilityEnergy.invalidate();
this.capabilityInventory.invalidate();
}
@Override
public InteractionResult use(Level level, Player player, InteractionHand hand) {
if (player instanceof ServerPlayer serverPlayer) {
NetworkHooks.openScreen(serverPlayer, this, buffer -> {
serverPlayer.openMenu(this, buffer -> {
buffer.writeBlockPos(getBlockPos());
buffer.writeByte(this.redstoneMode);
});
@ -151,6 +119,14 @@ public abstract class AbstractMachineBlockEntity<M extends AbstractMachineBlockE
protected void noEnergyTick() {}
public IItemHandler getItemHandler() {
return this.inventory;
}
public IEnergyStorage getEnergyStorage() {
return this.energy;
}
public static class ServerTicker<M extends AbstractMachineBlockEntity<M>> implements BlockEntityTicker<M> {
@Override
public void tick(Level level, BlockPos pos, BlockState state, M machine) {

View File

@ -19,7 +19,6 @@
package thedarkcolour.exdeorum.blockentity;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.FriendlyByteBuf;
@ -43,18 +42,16 @@ import net.minecraft.world.level.block.entity.BlockEntityTicker;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.FlowingFluid;
import net.minecraft.world.level.material.Fluids;
import net.minecraftforge.common.ForgeMod;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.ForgeCapabilities;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.FluidType;
import net.minecraftforge.fluids.FluidUtil;
import net.minecraftforge.fluids.IFluidTank;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.ItemHandlerHelper;
import net.minecraftforge.items.ItemStackHandler;
import net.neoforged.neoforge.capabilities.Capabilities;
import net.neoforged.neoforge.common.NeoForgeMod;
import net.neoforged.neoforge.fluids.FluidStack;
import net.neoforged.neoforge.fluids.FluidType;
import net.neoforged.neoforge.fluids.FluidUtil;
import net.neoforged.neoforge.fluids.capability.IFluidHandler;
import net.neoforged.neoforge.fluids.capability.templates.FluidTank;
import net.neoforged.neoforge.items.IItemHandler;
import net.neoforged.neoforge.items.ItemHandlerHelper;
import net.neoforged.neoforge.items.ItemStackHandler;
import org.jetbrains.annotations.Nullable;
import thedarkcolour.exdeorum.block.BarrelBlock;
import thedarkcolour.exdeorum.blockentity.helper.FluidHelper;
@ -84,33 +81,12 @@ public class BarrelBlockEntity extends EBlockEntity {
@Nullable
public FluidTransformationRecipe currentTransformRecipe = null;
private final LazyOptional<IItemHandler> itemHandler = LazyOptional.of(() -> this.item);
private final LazyOptional<IFluidHandler> fluidHandler = LazyOptional.of(() -> this.tank);
public BarrelBlockEntity(BlockPos pos, BlockState state) {
super(EBlockEntities.BARREL.get(), pos, state);
this.transparent = BarrelMaterial.TRANSPARENT_BARRELS.contains(state.getBlock());
}
@Override
public <T> LazyOptional<T> getCapability(Capability<T> cap, Direction side) {
if (cap == ForgeCapabilities.FLUID_HANDLER) {
return this.fluidHandler.cast();
} else if (cap == ForgeCapabilities.ITEM_HANDLER) {
return this.itemHandler.cast();
}
return super.getCapability(cap, side);
}
@Override
public void invalidateCaps() {
super.invalidateCaps();
this.fluidHandler.invalidate();
this.itemHandler.invalidate();
}
@Override
public void saveAdditional(CompoundTag nbt) {
super.saveAdditional(nbt);
@ -177,6 +153,7 @@ public class BarrelBlockEntity extends EBlockEntity {
return this.compost <= 0 && this.item.getStackInSlot(0).isEmpty();
}
@SuppressWarnings("deprecation")
public boolean hasFullWater() {
return this.tank.getFluidAmount() == 1000 && this.tank.getFluid().getFluid().is(FluidTags.WATER);
}
@ -187,15 +164,15 @@ public class BarrelBlockEntity extends EBlockEntity {
return fluidType.getTemperature() > 575;
}
private void spawnParticlesIfBurning() {
private void spawnParticlesIfBurning(Level level) {
if (isBurning()) {
BlockPos pos = getBlockPos();
int burnTicks = (int) (this.progress * 300);
if (burnTicks % 30 == 0) {
this.level.addParticle(ParticleTypes.LARGE_SMOKE, pos.getX() + Math.random(), pos.getY() + 1.2, pos.getZ() + Math.random(), 0.0, 0.0, 0.0);
level.addParticle(ParticleTypes.LARGE_SMOKE, pos.getX() + Math.random(), pos.getY() + 1.2, pos.getZ() + Math.random(), 0.0, 0.0, 0.0);
} else if (burnTicks % 5 == 0) {
this.level.addParticle(ParticleTypes.SMOKE, pos.getX() + Math.random(), pos.getY() + 1.2, pos.getZ() + Math.random(), 0.0, 0.0, 0.0);
level.addParticle(ParticleTypes.SMOKE, pos.getX() + Math.random(), pos.getY() + 1.2, pos.getZ() + Math.random(), 0.0, 0.0, 0.0);
}
}
}
@ -208,7 +185,7 @@ public class BarrelBlockEntity extends EBlockEntity {
this.item.setStackInSlot(0, item);
}
public IFluidTank getTank() {
public FluidTank getTank() {
return this.tank;
}
@ -264,19 +241,18 @@ public class BarrelBlockEntity extends EBlockEntity {
}
// Otherwise, mix the item's fluid into the barrel's fluid
var itemFluidCapOptional = playerItem.getCapability(ForgeCapabilities.FLUID_HANDLER_ITEM).resolve();
if (itemFluidCapOptional.isPresent()) {
var itemFluidCap = itemFluidCapOptional.get();
var itemFluidCap = playerItem.getCapability(Capabilities.FluidHandler.ITEM);
if (itemFluidCap != null) {
var itemFluid = itemFluidCap.drain(1000, IFluidHandler.FluidAction.SIMULATE);
BarrelFluidMixingRecipe recipe = RecipeUtil.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.baseFluidAmount && itemFluid.getAmount() == 1000) {
if (recipe != null && this.tank.getFluidAmount() >= recipe.baseFluidAmount() && itemFluid.getAmount() == 1000) {
if (!level.isClientSide) {
this.tank.drain(recipe.baseFluidAmount, IFluidHandler.FluidAction.EXECUTE);
setItem(new ItemStack(recipe.result));
this.tank.drain(recipe.baseFluidAmount(), IFluidHandler.FluidAction.EXECUTE);
setItem(new ItemStack(recipe.result()));
if (recipe.consumesAdditive) {
if (recipe.consumesAdditive()) {
itemFluidCap.drain(1000, IFluidHandler.FluidAction.EXECUTE);
player.setItemInHand(hand, itemFluidCap.getContainer());
}
@ -443,14 +419,14 @@ public class BarrelBlockEntity extends EBlockEntity {
if (recipe != null) {
// If additive is not consumed, just craft
// If additive is consumed, check that the additive can be consumed before crafting
if (!recipe.consumesAdditive) {
this.tank.drain(recipe.baseFluidAmount, IFluidHandler.FluidAction.EXECUTE);
setItem(new ItemStack(recipe.result));
if (!recipe.consumesAdditive()) {
this.tank.drain(recipe.baseFluidAmount(), IFluidHandler.FluidAction.EXECUTE);
setItem(new ItemStack(recipe.result()));
} else if (aboveBlockState.getBlock() instanceof BucketPickup pickup) {
// If something was picked up, we can craft
if (!pickup.pickupBlock(this.level, abovePos, aboveBlockState).isEmpty()) {
this.tank.drain(recipe.baseFluidAmount, IFluidHandler.FluidAction.EXECUTE);
setItem(new ItemStack(recipe.result));
if (!pickup.pickupBlock(null, this.level, abovePos, aboveBlockState).isEmpty()) {
this.tank.drain(recipe.baseFluidAmount(), IFluidHandler.FluidAction.EXECUTE);
setItem(new ItemStack(recipe.result()));
}
}
}
@ -468,7 +444,7 @@ public class BarrelBlockEntity extends EBlockEntity {
this.currentTransformRecipe = RecipeUtil.getFluidTransformationRecipe(this.tank.getFluid().getFluid(), belowState);
if (this.currentTransformRecipe != null) {
var color = this.currentTransformRecipe.resultColor;
var color = this.currentTransformRecipe.resultColor();
this.r = (short) ((color >> 16) & 0xff);
this.g = (short) ((color >> 8) & 0xff);
this.b = (short) ((color) & 0xff);
@ -479,6 +455,10 @@ public class BarrelBlockEntity extends EBlockEntity {
}
}
public IItemHandler getItemHandler() {
return this.item;
}
public static class Ticker implements BlockEntityTicker<BarrelBlockEntity> {
@Override
public void tick(Level level, BlockPos pos, BlockState state, BarrelBlockEntity barrel) {
@ -503,17 +483,17 @@ public class BarrelBlockEntity extends EBlockEntity {
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)) {
if (recipe.catalyst.test(level.getBlockState(cursor))) {
if (recipe.catalyst().test(level.getBlockState(cursor))) {
catalysts++;
if (!recipe.byproducts.isEmpty()) {
if (!recipe.byproducts().isEmpty()) {
var rand = level.random;
if (rand.nextInt(1500) == 0) {
var above = cursor.above();
if (level.getBlockState(above).isAir()) {
var byproduct = recipe.byproducts.getRandom(rand);
var byproduct = recipe.byproducts().getRandom(rand);
if (byproduct.canSurvive(level, above)) {
level.setBlockAndUpdate(above, byproduct);
}
@ -526,7 +506,7 @@ public class BarrelBlockEntity extends EBlockEntity {
if (catalysts == 0) {
barrel.currentTransformRecipe = null;
} else {
barrel.progress += catalysts * (1.0f / barrel.currentTransformRecipe.duration);
barrel.progress += catalysts * (1.0f / barrel.currentTransformRecipe.duration());
if (barrel.progress >= 1.0f - Mth.EPSILON) {
// Reset progress
barrel.progress = 0.0f;
@ -537,7 +517,7 @@ public class BarrelBlockEntity extends EBlockEntity {
barrel.markUpdated();
}
} else if (barrel.hasFullWater()) {
if (barrel.tank.getFluid().getFluid().getFluidType() == ForgeMod.WATER_TYPE.get()) {
if (barrel.tank.getFluid().getFluid().getFluidType() == NeoForgeMod.WATER_TYPE.value()) {
var rand = level.random;
// Leak water to create moss (only wooden barrels do this)
if (state.ignitedByLava() && rand.nextInt(500) == 0) {
@ -553,7 +533,7 @@ public class BarrelBlockEntity extends EBlockEntity {
}
}
} else {
barrel.spawnParticlesIfBurning();
barrel.spawnParticlesIfBurning(level);
}
}
}

View File

@ -30,22 +30,24 @@ import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.LeavesBlock;
import net.minecraft.world.level.block.entity.BlockEntityTicker;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.client.model.data.ModelData;
import net.minecraftforge.client.model.data.ModelProperty;
import net.neoforged.neoforge.client.model.data.ModelData;
import net.neoforged.neoforge.client.model.data.ModelProperty;
import org.jetbrains.annotations.NotNull;
import thedarkcolour.exdeorum.block.InfestedLeavesBlock;
import thedarkcolour.exdeorum.registry.EBlockEntities;
import thedarkcolour.exdeorum.registry.EBlocks;
public class InfestedLeavesBlockEntity extends EBlockEntity {
public static final float PROGRESS_INTERVAL = 0.005f;
// progress is a short between 0 and 16000 (why? because that's what the shader uses, also avoids float errors)
public static final short MAX_PROGRESS = 16000;
// 0.005 * 16000 = 80
public static final short PROGRESS_INTERVAL = 80;
public static final int SPREAD_INTERVAL = 40;
public static final ModelProperty<BlockState> MIMIC_PROPERTY = new ModelProperty<>();
// A percentage of how much this leaf is infested
// todo change this to a short between 0 and 16000
private float progress;
// value between 0 and 16000 representing infestation progress
private short progress;
// A timer that determines when this block should try to spread
private int spreadTimer;
// The state this block should render as
@ -57,33 +59,33 @@ public class InfestedLeavesBlockEntity extends EBlockEntity {
@Override
public void writeVisualData(FriendlyByteBuf buffer) {
buffer.writeFloat(this.progress);
buffer.writeShort(this.progress);
}
@Override
public void readVisualData(FriendlyByteBuf buffer) {
buffer.readFloat();
buffer.readShort();
}
// Attempt to convert a leaf block within 1 block radius around this block
private void trySpread() {
private void trySpread(Level level) {
// Get random offset
int x = this.level.random.nextInt(3) - 1;
int y = this.level.random.nextInt(3) - 1;
int z = this.level.random.nextInt(3) - 1;
int x = level.random.nextInt(3) - 1;
int y = level.random.nextInt(3) - 1;
int z = level.random.nextInt(3) - 1;
// Get the block in the world
BlockPos targetPos = getBlockPos().offset(x, y, z);
BlockState state = this.level.getBlockState(targetPos);
BlockState state = level.getBlockState(targetPos);
// DO NOT SPREAD TO ALREADY INFESTED LEAVES
if (state.is(BlockTags.LEAVES) && state.getBlock() != EBlocks.INFESTED_LEAVES.get()) {
// Spread and keep distance/persistent properties
this.level.setBlock(targetPos, EBlocks.INFESTED_LEAVES.get().defaultBlockState()
level.setBlock(targetPos, EBlocks.INFESTED_LEAVES.get().defaultBlockState()
.setValue(LeavesBlock.DISTANCE, state.getValue(LeavesBlock.DISTANCE))
.setValue(LeavesBlock.PERSISTENT, state.getValue(LeavesBlock.PERSISTENT)),
2);
var te = this.level.getBlockEntity(targetPos);
var te = level.getBlockEntity(targetPos);
// Set mimic state of other block
if (te instanceof InfestedLeavesBlockEntity leaves) {
@ -98,10 +100,9 @@ public class InfestedLeavesBlockEntity extends EBlockEntity {
super.load(nbt);
// From PistonMovingBlockEntity
@SuppressWarnings("deprecation")
var holderLookup = this.level != null ? this.level.holderLookup(Registries.BLOCK) : BuiltInRegistries.BLOCK.asLookup();
this.mimic = NbtUtils.readBlockState(holderLookup, nbt.getCompound("mimic"));
this.progress = nbt.getFloat("progress");
this.progress = nbt.getShort("progress");
}
@Override
@ -115,11 +116,11 @@ public class InfestedLeavesBlockEntity extends EBlockEntity {
nbt.putFloat("progress", this.progress);
}
public float getProgress() {
public int getProgress() {
return this.progress;
}
public void setProgress(float progress) {
public void setProgress(short progress) {
this.progress = progress;
}
@ -140,8 +141,8 @@ public class InfestedLeavesBlockEntity extends EBlockEntity {
@Override
public void tick(Level level, BlockPos pos, BlockState state, InfestedLeavesBlockEntity leaves) {
// Do progress
if (leaves.progress < 1.0f) {
leaves.progress = Math.min(1.0f, leaves.progress + PROGRESS_INTERVAL);
if (leaves.progress < MAX_PROGRESS) {
leaves.progress = (short) Math.min(MAX_PROGRESS, leaves.progress + PROGRESS_INTERVAL);
if (leaves.progress == 1.0f) {
level.setBlock(pos, state.setValue(InfestedLeavesBlock.FULLY_INFESTED, true), 1);
@ -154,7 +155,7 @@ public class InfestedLeavesBlockEntity extends EBlockEntity {
// Attempt to spread and reset the timer
if (leaves.spreadTimer >= SPREAD_INTERVAL) {
leaves.trySpread();
leaves.trySpread(level);
leaves.spreadTimer = level.random.nextInt(10);
}
}

View File

@ -38,6 +38,7 @@ import thedarkcolour.exdeorum.blockentity.helper.ItemHelper;
import thedarkcolour.exdeorum.config.EConfig;
import thedarkcolour.exdeorum.data.TranslationKeys;
import thedarkcolour.exdeorum.loot.HammerLootModifier;
import thedarkcolour.exdeorum.menu.MechanicalHammerMenu;
import thedarkcolour.exdeorum.recipe.RecipeUtil;
import thedarkcolour.exdeorum.recipe.hammer.HammerRecipe;
import thedarkcolour.exdeorum.registry.EBlockEntities;

View File

@ -29,7 +29,7 @@ import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.items.ItemHandlerHelper;
import net.neoforged.neoforge.items.ItemHandlerHelper;
import thedarkcolour.exdeorum.blockentity.helper.ItemHelper;
import thedarkcolour.exdeorum.blockentity.logic.SieveLogic;
import thedarkcolour.exdeorum.config.EConfig;

View File

@ -28,7 +28,7 @@ import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.common.util.FakePlayer;
import net.neoforged.neoforge.common.util.FakePlayer;
import thedarkcolour.exdeorum.blockentity.logic.SieveLogic;
import thedarkcolour.exdeorum.config.EConfig;
import thedarkcolour.exdeorum.registry.EBlockEntities;

View File

@ -18,7 +18,7 @@
package thedarkcolour.exdeorum.blockentity.helper;
import net.minecraftforge.energy.EnergyStorage;
import net.neoforged.neoforge.energy.EnergyStorage;
public class EnergyHelper extends EnergyStorage {
public EnergyHelper(int capacity) {

View File

@ -19,8 +19,8 @@
package thedarkcolour.exdeorum.blockentity.helper;
import net.minecraft.nbt.CompoundTag;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.templates.FluidTank;
import net.neoforged.neoforge.fluids.FluidStack;
import net.neoforged.neoforge.fluids.capability.templates.FluidTank;
// Changed behavior from FluidTank:
// - fluid stacks read from NBT are clamped.

View File

@ -20,8 +20,8 @@ package thedarkcolour.exdeorum.blockentity.helper;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.items.ItemStackHandler;
import net.minecraftforge.items.SlotItemHandler;
import net.neoforged.neoforge.items.ItemStackHandler;
import net.neoforged.neoforge.items.SlotItemHandler;
import org.jetbrains.annotations.NotNull;
// Has same behavior as ItemStackHandler but is more customizable.

View File

@ -158,7 +158,7 @@ public class SieveLogic {
public void saveNbt(CompoundTag nbt) {
if (!this.contents.isEmpty()) {
nbt.put("contents", this.contents.serializeNBT());
nbt.put("contents", this.contents.save(new CompoundTag()));
}
if (this.saveMesh && !this.mesh.isEmpty()) {
nbt.put("mesh", this.mesh.save(new CompoundTag()));

View File

@ -21,7 +21,6 @@ package thedarkcolour.exdeorum.client;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screens.MenuScreens;
import net.minecraft.client.gui.screens.worldselection.CreateWorldScreen;
import net.minecraft.client.gui.screens.worldselection.WorldCreationUiState;
import net.minecraft.client.renderer.ItemBlockRenderTypes;
@ -30,18 +29,13 @@ import net.minecraft.client.renderer.ShaderInstance;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.Unit;
import net.minecraftforge.client.event.ClientPlayerNetworkEvent;
import net.minecraftforge.client.event.EntityRenderersEvent;
import net.minecraftforge.client.event.ModelEvent;
import net.minecraftforge.client.event.RegisterClientReloadListenersEvent;
import net.minecraftforge.client.event.RegisterShadersEvent;
import net.minecraftforge.client.event.ScreenEvent;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.TagsUpdatedEvent;
import net.minecraftforge.fml.ModList;
import net.minecraftforge.fml.event.config.ModConfigEvent;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import net.neoforged.bus.api.IEventBus;
import net.neoforged.fml.ModList;
import net.neoforged.fml.event.config.ModConfigEvent;
import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent;
import net.neoforged.neoforge.client.event.*;
import net.neoforged.neoforge.common.NeoForge;
import net.neoforged.neoforge.event.TagsUpdatedEvent;
import thedarkcolour.exdeorum.ExDeorum;
import thedarkcolour.exdeorum.client.screen.MechanicalHammerScreen;
import thedarkcolour.exdeorum.client.screen.MechanicalSieveScreen;
@ -66,11 +60,11 @@ public class ClientHandler {
// This is set to true whenever the server tells a client to do so, then set back to false after cache is refreshed.
public static boolean needsRecipeCacheRefresh;
public static void register() {
var modBus = FMLJavaModLoadingContext.get().getModEventBus();
var fmlBus = MinecraftForge.EVENT_BUS;
public static void register(IEventBus modBus) {
var fmlBus = NeoForge.EVENT_BUS;
modBus.addListener(ClientHandler::clientSetup);
modBus.addListener(ClientHandler::registerMenuScreens);
modBus.addListener(ClientHandler::registerRenderers);
modBus.addListener(ClientHandler::registerShaders);
modBus.addListener(ClientHandler::addClientReloadListeners);
@ -99,11 +93,12 @@ public class ClientHandler {
}
private static void clientSetup(FMLClientSetupEvent event) {
event.enqueueWork(() -> {
setRenderLayers();
MenuScreens.register(EMenus.MECHANICAL_SIEVE.get(), MechanicalSieveScreen::new);
MenuScreens.register(EMenus.MECHANICAL_HAMMER.get(), MechanicalHammerScreen::new);
});
event.enqueueWork(ClientHandler::setRenderLayers);
}
private static void registerMenuScreens(RegisterMenuScreensEvent event) {
event.register(EMenus.MECHANICAL_SIEVE.get(), MechanicalSieveScreen::new);
event.register(EMenus.MECHANICAL_HAMMER.get(), MechanicalHammerScreen::new);
}
private static void setRenderLayers() {

View File

@ -28,17 +28,17 @@ import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
import it.unimi.dsi.fastutil.objects.ObjectSet;
import net.minecraft.client.Minecraft;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.GsonHelper;
import net.minecraft.world.inventory.InventoryMenu;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.model.data.ModelData;
import net.minecraftforge.fml.ModList;
import net.minecraftforge.fml.loading.FMLEnvironment;
import net.minecraftforge.registries.ForgeRegistries;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.fml.ModList;
import net.neoforged.fml.loading.FMLEnvironment;
import net.neoforged.neoforge.client.model.data.ModelData;
import org.apache.commons.io.IOUtils;
import org.jetbrains.annotations.Nullable;
import org.joml.Vector3i;
@ -54,11 +54,7 @@ import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.StringTokenizer;
import java.util.*;
import java.util.stream.Collectors;
// ExDeorum comes with a precomputed list of vanilla colors, since textures don't exist on the server.
@ -109,8 +105,7 @@ public class CompostColors {
// alpha doesn't matter, only RGB
image.downloadTexture(0, false);
for (var entry : ForgeRegistries.ITEMS.getEntries()) {
var item = entry.getValue();
for (var item : BuiltInRegistries.ITEM) {
var model = Minecraft.getInstance().getItemRenderer().getItemModelShaper().getItemModel(item);
if (model != null) {
@ -147,11 +142,12 @@ public class CompostColors {
private static void loadModded() {
var readMods = readModdedColorFiles();
for (var entry : ForgeRegistries.ITEMS.getEntries()) {
var modid = entry.getKey().location().getNamespace();
for (var entry : BuiltInRegistries.ITEM.entrySet()) {
var key = entry.getKey().location();
var modid = key.getNamespace();
if (!readMods.contains(modid)) {
var id = entry.getKey().location().getPath();
var id = key.getPath();
var modFile = ModList.get().getModFileById(modid);
if (modFile == null)
continue;
@ -209,8 +205,10 @@ public class CompostColors {
}
}
@SuppressWarnings("DataFlowIssue")
var entries = COLORS.keySet().stream().sorted(Comparator.comparing(ForgeRegistries.ITEMS::getKey)).collect(Collectors.groupingBy(item -> ForgeRegistries.ITEMS.getKey(item).getNamespace()));
// todo should i sort the registry before iterating it, or should I keep the sort here?
Map<String, List<Item>> entries = COLORS.keySet().stream()
.sorted(Comparator.comparing(BuiltInRegistries.ITEM::getKey))
.collect(Collectors.groupingBy(item -> BuiltInRegistries.ITEM.getKey(item).getNamespace()));
for (var entry : entries.entrySet()) {
if (!readMods.contains(entry.getKey())) {
@ -317,11 +315,11 @@ public class CompostColors {
var tokenizer = new StringTokenizer(line, ", #");
try {
var id = new ResourceLocation(modid, tokenizer.nextToken());
var item = ForgeRegistries.ITEMS.getValue(id);
var item = BuiltInRegistries.ITEM.get(id);
String token = tokenizer.nextToken();
var color = Integer.parseInt(token, 16);
if (item != null && item != Items.AIR) {
if (item != Items.AIR) {
readColors++;
COLORS.put(item, new Vector3i(
@ -353,9 +351,8 @@ public class CompostColors {
return false;
}
@SuppressWarnings("DataFlowIssue")
public static void export(String modid) {
export(modid, COLORS.keySet().stream().filter(key -> ForgeRegistries.ITEMS.getKey(key).getNamespace().equals(modid)).sorted(Comparator.comparing(ForgeRegistries.ITEMS::getKey)).toList());
export(modid, COLORS.keySet().stream().filter(key -> BuiltInRegistries.ITEM.getKey(key).getNamespace().equals(modid)).sorted(Comparator.comparing(BuiltInRegistries.ITEM::getKey)).toList());
}
// The given list should be sorted
@ -370,13 +367,13 @@ public class CompostColors {
try (var writer = new BufferedWriter(fileWriter)) {
// sort file entries alphabetically
var alphabeticalItems = new ArrayList<>(sortedToExport);
alphabeticalItems.sort(Comparator.comparing(item -> ForgeRegistries.ITEMS.getKey(item).getPath()));
alphabeticalItems.sort(Comparator.comparing(item -> BuiltInRegistries.ITEM.getKey(item).getPath()));
writer.write("// Compost colors for " + modid + ". You may add your own colors, change existing ones, or remove colors that aren't needed.\n");
for (var item : alphabeticalItems) {
if (COLORS.containsKey(item)) {
writer.write(ForgeRegistries.ITEMS.getKey(item).getPath());
writer.write(BuiltInRegistries.ITEM.getKey(item).getPath());
writer.write(", #");
var colorVec = COLORS.get(item);
writer.write(Integer.toHexString(new Color(colorVec.x, colorVec.y, colorVec.z).getRGB() & 0xffffff));
@ -393,7 +390,7 @@ public class CompostColors {
ExDeorum.LOGGER.error("Unable to save compost colors for mod \"{}\"", modid);
} catch (IOException e) {
e.printStackTrace();
ExDeorum.LOGGER.error("Encountered exception while trying to save compost colors for mod \"{}\"", modid, e);
}
}

View File

@ -26,6 +26,7 @@ import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import java.util.List;
// todo consider getting rid of this interface
public interface RenderFace {
void renderFlatSpriteLerp(MultiBufferSource buffers, PoseStack stack, float percentage, int r, int g, int b, int light, float edge, float yStart, float yEnd);

View File

@ -37,6 +37,7 @@ import net.minecraft.client.renderer.texture.TextureAtlas;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.core.BlockPos;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.Mth;
import net.minecraft.util.RandomSource;
@ -45,11 +46,9 @@ import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.levelgen.LegacyRandomSource;
import net.minecraft.world.level.material.Fluid;
import net.minecraftforge.client.extensions.common.IClientFluidTypeExtensions;
import net.minecraftforge.client.model.CompositeModel;
import net.minecraftforge.client.model.data.ModelData;
import net.minecraftforge.registries.ForgeRegistries;
import org.joml.Matrix4f;
import net.neoforged.neoforge.client.extensions.common.IClientFluidTypeExtensions;
import net.neoforged.neoforge.client.model.CompositeModel;
import net.neoforged.neoforge.client.model.data.ModelData;
import org.joml.Vector3f;
import thedarkcolour.exdeorum.ExDeorum;
import thedarkcolour.exdeorum.client.ter.SieveRenderer;
@ -148,7 +147,7 @@ public class RenderUtil {
}
private static TextureAtlasSprite getTopTexture(Block block, BakedModel model) {
var registryName = ForgeRegistries.BLOCKS.getKey(block);
var registryName = BuiltInRegistries.BLOCK.getKey(block);
var sprite = blockAtlas.getSprite(registryName.withPrefix("block/"));
// for stuff like azalea bush, retry to get the top texture
if (isMissingTexture(sprite)) {

View File

@ -27,7 +27,7 @@ import net.minecraft.util.Mth;
import net.minecraft.world.entity.player.Inventory;
import org.jetbrains.annotations.Nullable;
import thedarkcolour.exdeorum.ExDeorum;
import thedarkcolour.exdeorum.blockentity.MechanicalHammerMenu;
import thedarkcolour.exdeorum.menu.MechanicalHammerMenu;
import thedarkcolour.exdeorum.config.EConfig;
import thedarkcolour.exdeorum.data.TranslationKeys;
@ -79,7 +79,7 @@ public class MechanicalHammerScreen extends AbstractContainerScreen<MechanicalHa
@Override
public void render(GuiGraphics graphics, int mx, int my, float pPartialTick) {
renderBackground(graphics);
renderBackground(graphics, mx, my, pPartialTick);
super.render(graphics, mx, my, pPartialTick);
renderTooltip(graphics, mx, my);

View File

@ -81,7 +81,7 @@ public class MechanicalSieveScreen extends AbstractContainerScreen<MechanicalSie
@Override
public void render(GuiGraphics graphics, int mx, int my, float partialTicks) {
renderBackground(graphics);
renderBackground(graphics, mx, my, partialTicks);
super.render(graphics, mx, my, partialTicks);
renderTooltip(graphics, mx, my);

View File

@ -33,13 +33,13 @@ import net.minecraft.util.Mth;
import net.minecraft.world.inventory.InventoryMenu;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.ItemDisplayContext;
import net.minecraft.world.level.material.Fluid;
import net.minecraftforge.client.model.data.ModelData;
import net.minecraftforge.common.capabilities.ForgeCapabilities;
import net.neoforged.neoforge.client.model.data.ModelData;
import thedarkcolour.exdeorum.ExDeorum;
import thedarkcolour.exdeorum.blockentity.BarrelBlockEntity;
import thedarkcolour.exdeorum.client.RenderUtil;
import java.util.Objects;
public class BarrelRenderer implements BlockEntityRenderer<BarrelBlockEntity> {
public static final ResourceLocation COMPOST_DIRT_TEXTURE = new ResourceLocation(ExDeorum.ID, "block/compost_dirt");
private final BlockRenderDispatcher blockRenderer;
@ -63,6 +63,7 @@ public class BarrelRenderer implements BlockEntityRenderer<BarrelBlockEntity> {
stack.translate(2 / 16f, 2 / 16f, 2 / 16f);
stack.scale(12 / 16f, 12 / 16f, 12 / 16f);
//noinspection DataFlowIssue
this.blockRenderer.renderSingleBlock(state, stack, buffers, light, overlay, ModelData.EMPTY, null);
stack.popPose();
@ -74,37 +75,36 @@ public class BarrelRenderer implements BlockEntityRenderer<BarrelBlockEntity> {
stack.popPose();
}
barrel.getCapability(ForgeCapabilities.FLUID_HANDLER).ifPresent(tank -> {
var fluidStack = tank.getFluidInTank(0);
var tank = barrel.getTank();
var fluidStack = tank.getFluidInTank(0);
if (!fluidStack.isEmpty()) { // Get texture
var fluid = fluidStack.getFluid();
var level = barrel.getLevel();
var pos = barrel.getBlockPos();
var percentage = fluidStack.getAmount() / 1000.0f;
var y = Mth.lerp(percentage, 1.0f, 14.0f) / 16f;
var inputFluidColor = RenderUtil.getFluidColor(fluid, level, pos);
// Split into RGB components
var r = (inputFluidColor >> 16) & 0xff;
var g = (inputFluidColor >> 8) & 0xff;
var b = inputFluidColor & 0xff;
if (!fluidStack.isEmpty()) { // Get texture
var fluid = fluidStack.getFluid();
var level = Objects.requireNonNull(barrel.getLevel());
var pos = barrel.getBlockPos();
var percentage = fluidStack.getAmount() / 1000.0f;
var y = Mth.lerp(percentage, 1.0f, 14.0f) / 16f;
var inputFluidColor = RenderUtil.getFluidColor(fluid, level, pos);
// Split into RGB components
var r = (inputFluidColor >> 16) & 0xff;
var g = (inputFluidColor >> 8) & 0xff;
var b = inputFluidColor & 0xff;
if (barrel.isBrewing()) {
float progress = barrel.progress;
if (barrel.isBrewing()) {
float progress = barrel.progress;
// Transition between water color and witch water color (200B41)
r = (int) Mth.lerp(progress, r, barrel.r);
g = (int) Mth.lerp(progress, g, barrel.g);
b = (int) Mth.lerp(progress, b, barrel.b);
}
if (barrel.transparent) {
RenderUtil.renderFluidCube(buffers, stack, level, pos, 1 / 16f, y, 2.0f, light, r, g, b, fluid);
} else {
RenderUtil.renderFlatFluidSprite(buffers, stack, level, pos, y, 2.0f, light, r, g, b, fluid);
}
// Transition between water color and witch water color (200B41)
r = (int) Mth.lerp(progress, r, barrel.r);
g = (int) Mth.lerp(progress, g, barrel.g);
b = (int) Mth.lerp(progress, b, barrel.b);
}
});
if (barrel.transparent) {
RenderUtil.renderFluidCube(buffers, stack, level, pos, 1 / 16f, y, 2.0f, light, r, g, b, fluid);
} else {
RenderUtil.renderFlatFluidSprite(buffers, stack, level, pos, y, 2.0f, light, r, g, b, fluid);
}
}
// render compost
if (barrel.compost > 0) {
@ -126,9 +126,9 @@ public class BarrelRenderer implements BlockEntityRenderer<BarrelBlockEntity> {
}
// Transition between default green and dirt brown
r = (int) Mth.lerp(compostProgress, r, 238); // default green is
r = (int) Mth.lerp(compostProgress, r, 238); // default green is
g = (int) Mth.lerp(compostProgress, g, 169); // default green is
b = (int) Mth.lerp(compostProgress, b, 109); // default green is
b = (int) Mth.lerp(compostProgress, b, 109); // default green is
RenderUtil.renderFlatSpriteLerp(builder, stack, barrel.compost / 1000.0f, r, g, b, sprite, light, 2.0f, 1.0f, 14.0f);
}

View File

@ -23,51 +23,48 @@ import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
import net.minecraft.util.Mth;
import net.minecraft.world.level.block.Block;
import net.minecraftforge.common.capabilities.ForgeCapabilities;
import thedarkcolour.exdeorum.blockentity.AbstractCrucibleBlockEntity;
import thedarkcolour.exdeorum.client.RenderUtil;
public class CrucibleRenderer implements BlockEntityRenderer<AbstractCrucibleBlockEntity> {
@Override
public void render(AbstractCrucibleBlockEntity crucible, float partialTicks, PoseStack stack, MultiBufferSource buffers, int light, int overlay) {
crucible.getCapability(ForgeCapabilities.FLUID_HANDLER).ifPresent(tank -> {
var level = crucible.getLevel();
if (level == null) return;
var tank = crucible.getTank();
var level = crucible.getLevel();
if (level == null) return;
var fluidStack = tank.getFluidInTank(0);
var fluidStack = tank.getFluidInTank(0);
// These are percentages
var solids = (float) crucible.getSolids() / (float) AbstractCrucibleBlockEntity.MAX_SOLIDS;
var liquid = (float) fluidStack.getAmount() / (float) tank.getTankCapacity(0);
// These are percentages
var solids = (float) crucible.getSolids() / (float) AbstractCrucibleBlockEntity.MAX_SOLIDS;
var liquid = (float) fluidStack.getAmount() / (float) tank.getTankCapacity(0);
if (solids != 0 || liquid != 0) {
var pos = crucible.getBlockPos();
if (solids != 0 || liquid != 0) {
var pos = crucible.getBlockPos();
if (liquid != 0) {
var fluid = fluidStack.getFluid();
var color = RenderUtil.getFluidColor(fluid, level, pos);
float y = Mth.lerp(liquid, 4.0f, 14.0f) / 16f;
if (liquid != 0) {
var fluid = fluidStack.getFluid();
var color = RenderUtil.getFluidColor(fluid, level, pos);
float y = Mth.lerp(liquid, 4.0f, 14.0f) / 16f;
RenderUtil.renderFlatFluidSprite(buffers, stack, level, pos, y, 2.0f, light, (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff, fluid);
}
if (solids != 0) {
// eating my words rn :(
var lastMelted = crucible.getLastMelted();
if (lastMelted == null) {
lastMelted = crucible.getDefaultMeltBlock();
}
var face = RenderUtil.getTopFaceOrDefault(lastMelted, crucible.getDefaultMeltBlock());
var color = Minecraft.getInstance().getBlockColors().getColor(lastMelted.defaultBlockState(), level, pos, 0);
if (color == -1) color = 0xffffff;
face.renderFlatSpriteLerp(buffers, stack, solids, (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff, light, 2.0f, 4.0f, 14.0f);
}
RenderUtil.renderFlatFluidSprite(buffers, stack, level, pos, y, 2.0f, light, (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff, fluid);
}
});
if (solids != 0) {
// eating my words rn :(
var lastMelted = crucible.getLastMelted();
if (lastMelted == null) {
lastMelted = crucible.getDefaultMeltBlock();
}
var face = RenderUtil.getTopFaceOrDefault(lastMelted, crucible.getDefaultMeltBlock());
var color = Minecraft.getInstance().getBlockColors().getColor(lastMelted.defaultBlockState(), level, pos, 0);
if (color == -1) color = 0xffffff;
face.renderFlatSpriteLerp(buffers, stack, solids, (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff, light, 2.0f, 4.0f, 14.0f);
}
}
}
}

View File

@ -23,7 +23,7 @@ import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
import net.minecraft.world.level.block.Blocks;
import net.minecraftforge.client.model.data.ModelData;
import net.neoforged.neoforge.client.model.data.ModelData;
import thedarkcolour.exdeorum.blockentity.InfestedLeavesBlockEntity;
import thedarkcolour.exdeorum.client.RenderUtil;
import thedarkcolour.exdeorum.config.EConfig;
@ -46,7 +46,7 @@ public class InfestedLeavesRenderer implements BlockEntityRenderer<InfestedLeave
}
// Get infested percentage
int progress = Math.min((int) (te.getProgress() * 16000), 16000);
int progress = Math.min(te.getProgress(), 16000);
// Render
var model = mc.getBlockRenderer().getBlockModel(state);
var pos = te.getBlockPos();

View File

@ -59,7 +59,6 @@ public class SieveRenderer<T extends EBlockEntity & SieveLogic.Owner> implements
if (MESH_TEXTURES.containsKey(meshItem)) {
meshSprite = MESH_TEXTURES.get(meshItem);
} else {
@SuppressWarnings("deprecation")
ResourceLocation registryName = BuiltInRegistries.ITEM.getKey(meshItem);
ResourceLocation textureLoc = registryName.withPrefix("item/mesh/");
meshSprite = RenderUtil.blockAtlas.getSprite(textureLoc);

View File

@ -18,15 +18,25 @@
package thedarkcolour.exdeorum.compat;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import net.minecraft.client.Minecraft;
import net.minecraft.world.Container;
import net.minecraft.world.item.Item;
import net.minecraftforge.fml.ModList;
import net.minecraft.world.item.crafting.Recipe;
import net.minecraft.world.item.crafting.RecipeHolder;
import net.minecraft.world.item.crafting.RecipeType;
import net.neoforged.fml.ModList;
import thedarkcolour.exdeorum.material.DefaultMaterials;
import thedarkcolour.exdeorum.recipe.sieve.SieveRecipe;
import thedarkcolour.exdeorum.registry.EItems;
import thedarkcolour.exdeorum.registry.ERecipeTypes;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
public class CompatHelper {
public class CompatUtil {
public static List<Item> getAvailableBarrels(boolean registered) {
List<Item> barrels = new ArrayList<>();
for (var material : DefaultMaterials.BARRELS) {
@ -72,7 +82,15 @@ public class CompatHelper {
}
}
return waterCrucibles;
}
public static <C extends Container, R extends Recipe<C>, T> List<T> collectAllRecipes(RecipeType<R> recipeType, Function<R, T> mapper) {
var byType = Objects.requireNonNull(Minecraft.getInstance().level).getRecipeManager().byType(recipeType).values();
List<T> recipes = new ObjectArrayList<>(byType.size());
for (RecipeHolder<R> value : byType) {
recipes.add(mapper.apply(value.value()));
}
return recipes;
}
}

View File

@ -21,23 +21,27 @@ package thedarkcolour.exdeorum.compat;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Multimap;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import net.minecraft.client.Minecraft;
import net.minecraft.core.registries.BuiltInRegistries;
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.level.storage.loot.providers.number.ConstantValue;
import net.minecraft.world.level.storage.loot.providers.number.NumberProvider;
import thedarkcolour.exdeorum.recipe.RecipeUtil;
import thedarkcolour.exdeorum.recipe.sieve.SieveRecipe;
import thedarkcolour.exdeorum.registry.EItems;
import thedarkcolour.exdeorum.registry.ERecipeSerializers;
import thedarkcolour.exdeorum.registry.ERecipeTypes;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
// Since no JEI code is used here, this can be reused for REI
public record GroupedSieveRecipe(Ingredient ingredient, ItemStack mesh, List<Result> results) {
@ -46,8 +50,7 @@ public record GroupedSieveRecipe(Ingredient ingredient, ItemStack mesh, List<Res
public static ImmutableList<GroupedSieveRecipe> getAllRecipesGrouped() {
maxSieveRows = 1;
// copy the list so we can do removals
List<SieveRecipe> recipes = new ArrayList<>(Objects.requireNonNull(Minecraft.getInstance().level).getRecipeManager().getAllRecipesFor(ERecipeTypes.SIEVE.get()));
var recipes = CompatUtil.collectAllRecipes(ERecipeTypes.SIEVE.value(), Function.identity());
Multimap<Ingredient, SieveRecipe> ingredientGrouper = ArrayListMultimap.create();
for (int i = 0; i < recipes.size(); i++) {
@ -91,7 +94,7 @@ public record GroupedSieveRecipe(Ingredient ingredient, ItemStack mesh, List<Res
var results = new ArrayList<Result>(meshRecipes.size());
for (var recipe : meshRecipes) {
int resultCount = recipe.resultAmount instanceof ConstantValue constant ? Math.round(constant.value) : 1;
int resultCount = recipe.resultAmount instanceof ConstantValue constant ? Math.round(constant.value()) : 1;
results.add(new Result(new ItemStack(recipe.result, resultCount), recipe.resultAmount, recipe.byHandOnly));
}
@ -109,7 +112,6 @@ public record GroupedSieveRecipe(Ingredient ingredient, ItemStack mesh, List<Res
return jeiRecipes.build();
}
@SuppressWarnings("deprecation")
private static int meshOrder(Item mesh) {
if (mesh == EItems.STRING_MESH.get()) {
return -5;

View File

@ -26,9 +26,8 @@ import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.TagKey;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.Items;
import net.minecraftforge.common.ForgeConfigSpec;
import net.minecraftforge.fml.ModList;
import net.minecraftforge.registries.ForgeRegistries;
import net.neoforged.fml.ModList;
import net.neoforged.neoforge.common.ModConfigSpec;
import thedarkcolour.exdeorum.ExDeorum;
import thedarkcolour.exdeorum.config.EConfig;
import thedarkcolour.exdeorum.tag.EItemTags;
@ -67,13 +66,12 @@ public class PreferredOres {
* @param config A config which holds an override value chosen by the user. Could even be something that isn't an ore.
* @param defaultOre The default ore choice, picked by Ex Deorum based on which mod is the "best" choice according to thedarkcolour.
*/
@SuppressWarnings("deprecation")
private static void putPreferredOre(TagKey<Item> tag, ForgeConfigSpec.ConfigValue<String> config, Item defaultOre) {
var item = ForgeRegistries.ITEMS.getValue(new ResourceLocation(config.get()));
private static void putPreferredOre(TagKey<Item> tag, ModConfigSpec.ConfigValue<String> config, Item defaultOre) {
var item = BuiltInRegistries.ITEM.get(new ResourceLocation(config.get()));
if (item == Items.AIR) {
item = defaultOre;
ExDeorum.LOGGER.debug("No preferred ore was set for tag {}. Using default choice {}", tag.location(), item.builtInRegistryHolder().key().location());
ExDeorum.LOGGER.debug("No preferred ore was set for tag {}. Using default choice {}", tag.location(), BuiltInRegistries.ITEM.getKey(item));
}
PREFERRED_ORE_ITEMS.put(tag, defaultOre);
}
@ -84,7 +82,6 @@ public class PreferredOres {
* @return The preferred (as specified by config, or by alphabetical order)
* item from the given tag or {@link Items#AIR} if the tag is empty.
*/
@SuppressWarnings("deprecation")
public static Item getPreferredOre(TagKey<Item> tag) {
Item preferred = PREFERRED_ORE_ITEMS.get(tag);
@ -96,10 +93,10 @@ public class PreferredOres {
if (collection.isEmpty()) {
return Items.AIR;
} else {
collection.sort(Comparator.comparing(holder -> BuiltInRegistries.ITEM.getKey(holder.get())));
collection.sort(Comparator.comparing(holder -> BuiltInRegistries.ITEM.getKey(holder.value())));
// todo should the PREFERRED_ORE map be updated with this value?
return collection.get(0).get();
return collection.get(0).value();
}
}
}
@ -175,9 +172,9 @@ public class PreferredOres {
if (modId != null) {
if (modId.equals(ModIds.FACTORIUM)) {
return ForgeRegistries.ITEMS.getValue(new ResourceLocation(modId, "mat_" + path));
return BuiltInRegistries.ITEM.get(new ResourceLocation(modId, "mat_" + path));
} else {
return ForgeRegistries.ITEMS.getValue(new ResourceLocation(modId, path));
return BuiltInRegistries.ITEM.get(new ResourceLocation(modId, path));
}
} else {
return Items.AIR;

View File

@ -108,12 +108,12 @@ public abstract class BarrelMixingCategory<T> implements IRecipeCategory<T> {
@Override
public void setRecipe(IRecipeLayoutBuilder builder, BarrelFluidMixingRecipe recipe, IFocusGroup focuses) {
builder.addSlot(RecipeIngredientRole.INPUT, 1, 1).addFluidStack(recipe.baseFluid, recipe.baseFluidAmount).setFluidRenderer(1000, false, 16, 16);
IRecipeSlotBuilder additiveSlot = builder.addSlot(RecipeIngredientRole.INPUT, 33, 1).addFluidStack(recipe.additiveFluid, 1000).setFluidRenderer(1000, false, 16, 16);
if (recipe.consumesAdditive) {
builder.addSlot(RecipeIngredientRole.INPUT, 1, 1).addFluidStack(recipe.baseFluid(), recipe.baseFluidAmount()).setFluidRenderer(1000, false, 16, 16);
IRecipeSlotBuilder additiveSlot = builder.addSlot(RecipeIngredientRole.INPUT, 33, 1).addFluidStack(recipe.additiveFluid(), 1000).setFluidRenderer(1000, false, 16, 16);
if (recipe.consumesAdditive()) {
additiveSlot.addTooltipCallback((view, tooltip) -> tooltip.add(CONTENTS_ARE_CONSUMED_TOOLTIP));
}
builder.addSlot(RecipeIngredientRole.OUTPUT, 79, 1).addItemStack(new ItemStack(recipe.result));
builder.addSlot(RecipeIngredientRole.OUTPUT, 79, 1).addItemStack(new ItemStack(recipe.result()));
}
@Override
@ -125,7 +125,7 @@ public abstract class BarrelMixingCategory<T> implements IRecipeCategory<T> {
public void draw(BarrelFluidMixingRecipe recipe, IRecipeSlotsView recipeSlotsView, GuiGraphics graphics, double mouseX, double mouseY) {
super.draw(recipe, recipeSlotsView, graphics, mouseX, mouseY);
if (recipe.consumesAdditive) {
if (recipe.consumesAdditive()) {
ClientJeiUtil.renderAsterisk(graphics, 18 + 3 + 3 + 8, 0);
}
}

View File

@ -25,7 +25,6 @@ import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.Tesselator;
import com.mojang.math.Axis;
import me.shedaniel.rei.api.client.view.ViewSearchBuilder;
import me.shedaniel.rei.jeicompat.JEIPluginDetector;
import mezz.jei.api.ingredients.IIngredientRenderer;
import mezz.jei.api.ingredients.IIngredientType;
import mezz.jei.api.ingredients.ITypedIngredient;
@ -62,8 +61,8 @@ import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.lighting.LevelLightEngine;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.level.material.Fluids;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fml.ModList;
import net.neoforged.fml.ModList;
import net.neoforged.neoforge.fluids.FluidStack;
import org.jetbrains.annotations.Nullable;
import org.joml.Matrix4f;
import org.joml.Vector3f;
@ -194,31 +193,33 @@ class ClientJeiUtil {
}
// Required due to broken JEI implementation in REI plugin compatibility
public static <T> void checkTypedIngredient(IIngredientManager manager, IIngredientType<T> ingredientType, T uncheckedIngredient, Consumer<ITypedIngredient<T>> action) {
static <T> void checkTypedIngredient(IIngredientManager manager, IIngredientType<T> ingredientType, @Nullable T uncheckedIngredient, Consumer<ITypedIngredient<T>> action) {
if ((uncheckedIngredient instanceof ItemStack stack && !stack.isEmpty()) || (uncheckedIngredient instanceof FluidStack fluidStack && !fluidStack.isEmpty())) {
manager.createTypedIngredient(ingredientType, uncheckedIngredient).ifPresent(action);
}
}
public static <T> void showRecipes(IFocusFactory focusFactory, ITypedIngredient<T> ingredient) {
static <T> void showRecipes(IFocusFactory focusFactory, ITypedIngredient<T> ingredient) {
if (Minecraft.getInstance().screen instanceof IRecipesGui recipesGui) {
recipesGui.show(focusFactory.createFocus(RecipeIngredientRole.OUTPUT, ingredient));
} else if (ModList.get().isLoaded(ModIds.REI_PC)) {
ViewSearchBuilder.builder().addRecipesFor(JEIPluginDetector.unwrapStack(ingredient)).open();
// todo fix when REIPC is on 1.20.4
//ViewSearchBuilder.builder().addRecipesFor(JEIPluginDetector.unwrapStack(ingredient)).open();
}
}
public static <T> void showUsages(IFocusFactory focusFactory, ITypedIngredient<T> ingredient) {
static <T> void showUsages(IFocusFactory focusFactory, ITypedIngredient<T> ingredient) {
if (Minecraft.getInstance().screen instanceof IRecipesGui recipesGui) {
// input + catalyst
recipesGui.show(List.of(focusFactory.createFocus(RecipeIngredientRole.INPUT, ingredient), focusFactory.createFocus(RecipeIngredientRole.CATALYST, ingredient)));
} else if (ModList.get().isLoaded(ModIds.REI_PC)) {
ViewSearchBuilder.builder().addUsagesFor(JEIPluginDetector.unwrapStack(ingredient)).open();
// todo fix when REIPC is on 1.20.4
//ViewSearchBuilder.builder().addUsagesFor(JEIPluginDetector.unwrapStack(ingredient)).open();
}
}
// Takes a decimal probability and returns a user-friendly percentage value
public static Component formatChance(double probability) {
static Component formatChance(double probability) {
var chance = FORMATTER.format(probability * 100);
return Component.translatable(TranslationKeys.SIEVE_RECIPE_CHANCE, chance).withStyle(ChatFormatting.GRAY);
}
@ -239,6 +240,7 @@ class ClientJeiUtil {
return 1;
}
@SuppressWarnings("DataFlowIssue")
@Override
public LevelLightEngine getLightEngine() {
return Minecraft.getInstance().level.getLightEngine();

View File

@ -40,8 +40,8 @@ import net.minecraft.network.chat.Component;
import net.minecraft.util.RandomSource;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.client.RenderTypeHelper;
import net.minecraftforge.client.model.data.ModelData;
import net.neoforged.neoforge.client.RenderTypeHelper;
import net.neoforged.neoforge.client.model.data.ModelData;
import thedarkcolour.exdeorum.data.TranslationKeys;
import thedarkcolour.exdeorum.registry.EBlocks;
import thedarkcolour.exdeorum.registry.EItems;
@ -124,7 +124,8 @@ public class CrookCategory implements IRecipeCategory<CrookJeiRecipe> {
});
} else {
ClientJeiUtil.renderBlock(graphics, state, 28, 18, 10, 20f, (block, poseStack, buffers) -> {
Minecraft.getInstance().getBlockRenderer().renderSingleBlock(block, poseStack, buffers, 15728880, OverlayTexture.NO_OVERLAY);
//noinspection DataFlowIssue
Minecraft.getInstance().getBlockRenderer().renderSingleBlock(block, poseStack, buffers, 15728880, OverlayTexture.NO_OVERLAY, ModelData.EMPTY, null);
});
}
}

View File

@ -20,9 +20,11 @@ package thedarkcolour.exdeorum.compat.jei;
import com.google.common.collect.ImmutableList;
import com.google.gson.JsonObject;
import com.mojang.serialization.JsonOps;
import mezz.jei.api.gui.builder.IRecipeLayoutBuilder;
import mezz.jei.api.recipe.RecipeIngredientRole;
import net.minecraft.ChatFormatting;
import net.minecraft.advancements.critereon.StatePropertiesPredicate;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.network.chat.Component;
import net.minecraft.tags.TagKey;
@ -34,6 +36,7 @@ import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import org.jetbrains.annotations.Nullable;
import thedarkcolour.exdeorum.recipe.BlockPredicate;
import thedarkcolour.exdeorum.recipe.CodecUtil;
import thedarkcolour.exdeorum.recipe.crook.CrookRecipe;
import java.util.ArrayList;
@ -99,7 +102,7 @@ public sealed abstract class CrookJeiRecipe {
ImmutableList.Builder<Component> requirements = ImmutableList.builder();
if (predicate != null) {
var json = predicate.properties().serializeToJson();
var json = CodecUtil.encode(StatePropertiesPredicate.CODEC, predicate.properties());
if (json instanceof JsonObject obj) {
for (var entry : obj.entrySet()) {
requirements.add(Component.literal(" " + entry.getKey() + "=" + entry.getValue().toString()).withStyle(ChatFormatting.GRAY));

View File

@ -30,6 +30,7 @@ final class CrucibleHeatSourceRecipe {
@Nullable
private final Object ingredient;
@SuppressWarnings({"rawtypes", "unchecked"})
CrucibleHeatSourceRecipe(int meltRate, BlockState blockState, @Nullable IIngredientType ingredientType, @Nullable Object ingredient) {
this.meltRate = meltRate;
this.blockState = blockState;

View File

@ -34,10 +34,10 @@ import mezz.jei.api.runtime.IIngredientManager;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.network.chat.Component;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.TooltipFlag;
import net.minecraftforge.registries.ForgeRegistries;
import thedarkcolour.exdeorum.data.TranslationKeys;
import thedarkcolour.exdeorum.material.DefaultMaterials;
@ -88,7 +88,7 @@ class CrucibleHeatSourcesCategory implements IRecipeCategory<CrucibleHeatSourceR
@Override
public void setRecipe(IRecipeLayoutBuilder builder, CrucibleHeatSourceRecipe recipe, IFocusGroup focuses) {
if (recipe.ingredientType() != null) {
if (recipe.ingredientType() != null && recipe.ingredient() != null) {
builder.addInvisibleIngredients(RecipeIngredientRole.INPUT).addIngredient(recipe.ingredientType(), recipe.ingredient());
} else {
builder.addInvisibleIngredients(RecipeIngredientRole.INPUT).addIngredient(VanillaTypes.ITEM_STACK, ItemStack.EMPTY);
@ -104,6 +104,7 @@ class CrucibleHeatSourcesCategory implements IRecipeCategory<CrucibleHeatSourceR
graphics.drawString(font, volumeLabel, 60 - font.width(volumeLabel) / 2, 5, 0xff808080, false);
ClientJeiUtil.renderBlock(graphics, recipe.blockState(), 60, 24, 10, 20F, (block, poseStack, buffers) -> {
//noinspection deprecation
Minecraft.getInstance().getBlockRenderer().renderSingleBlock(block, poseStack, buffers, 15728880, OverlayTexture.NO_OVERLAY);
});
}
@ -111,12 +112,12 @@ class CrucibleHeatSourcesCategory implements IRecipeCategory<CrucibleHeatSourceR
@Override
public List<Component> getTooltipStrings(CrucibleHeatSourceRecipe recipe, IRecipeSlotsView recipeSlotsView, double mouseX, double mouseY) {
if (44.0 < mouseX && mouseX < 76.0 && 16 < mouseY && mouseY < 48) {
if (recipe.ingredientType() != null) {
if (recipe.ingredientType() != null && recipe.ingredient() != null) {
var tooltip = this.ingredientManager.getIngredientRenderer(recipe.ingredientType()).getTooltip(recipe.ingredient(), Minecraft.getInstance().options.advancedItemTooltips ? TooltipFlag.ADVANCED : TooltipFlag.NORMAL);
return this.modIdHelper.addModNameToIngredientTooltip(tooltip, recipe.ingredient(), this.ingredientManager.getIngredientHelper(recipe.ingredientType()));
} else {
var block = recipe.blockState().getBlock();
var modId = ForgeRegistries.BLOCKS.getKey(block).getNamespace();
var modId = BuiltInRegistries.BLOCK.getKey(block).getNamespace();
return List.of(Component.translatable(block.getDescriptionId()), Component.literal(this.modIdHelper.getFormattedModNameForModId(modId)));
}
}

View File

@ -22,9 +22,9 @@ import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import mezz.jei.api.IModPlugin;
import mezz.jei.api.JeiPlugin;
import mezz.jei.api.constants.VanillaTypes;
import mezz.jei.api.forge.ForgeTypes;
import mezz.jei.api.gui.handlers.IGuiClickableArea;
import mezz.jei.api.gui.handlers.IGuiContainerHandler;
import mezz.jei.api.neoforge.NeoForgeTypes;
import mezz.jei.api.recipe.RecipeType;
import mezz.jei.api.registration.IGuiHandlerRegistration;
import mezz.jei.api.registration.IRecipeCatalystRegistration;
@ -42,11 +42,11 @@ import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.LiquidBlock;
import net.minecraft.world.level.block.WallTorchBlock;
import net.minecraftforge.fluids.FluidStack;
import net.neoforged.neoforge.fluids.FluidStack;
import thedarkcolour.exdeorum.ExDeorum;
import thedarkcolour.exdeorum.client.screen.MechanicalHammerScreen;
import thedarkcolour.exdeorum.client.screen.MechanicalSieveScreen;
import thedarkcolour.exdeorum.compat.CompatHelper;
import thedarkcolour.exdeorum.compat.CompatUtil;
import thedarkcolour.exdeorum.compat.GroupedSieveRecipe;
import thedarkcolour.exdeorum.data.TranslationKeys;
import thedarkcolour.exdeorum.item.WateringCanItem;
@ -65,6 +65,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Supplier;
@JeiPlugin
@ -105,10 +106,10 @@ public class ExDeorumJeiPlugin implements IModPlugin {
@Override
public void registerRecipeCatalysts(IRecipeCatalystRegistration registration) {
var barrels = CompatHelper.getAvailableBarrels(true);
var sieves = CompatHelper.getAvailableSieves(true, true);
var lavaCrucibles = CompatHelper.getAvailableLavaCrucibles(true);
var waterCrucibles = CompatHelper.getAvailableWaterCrucibles(true);
var barrels = CompatUtil.getAvailableBarrels(true);
var sieves = CompatUtil.getAvailableSieves(true, true);
var lavaCrucibles = CompatUtil.getAvailableLavaCrucibles(true);
var waterCrucibles = CompatUtil.getAvailableWaterCrucibles(true);
for (var barrel : barrels) {
var stack = new ItemStack(barrel);
@ -143,12 +144,12 @@ public class ExDeorumJeiPlugin implements IModPlugin {
@Override
public void registerRecipes(IRecipeRegistration registration) {
registration.addItemStackInfo(List.of(new ItemStack(EItems.INFESTED_LEAVES.get()), new ItemStack(EItems.SILK_WORM.get())), Component.translatable(TranslationKeys.SILK_WORM_JEI_INFO));
registration.addItemStackInfo(CompatHelper.getAvailableSieves(true, false).stream().map(ItemStack::new).toList(), Component.translatable(TranslationKeys.SIEVE_JEI_INFO));
registration.addItemStackInfo(CompatUtil.getAvailableSieves(true, false).stream().map(ItemStack::new).toList(), Component.translatable(TranslationKeys.SIEVE_JEI_INFO));
registration.addItemStackInfo(List.of(new ItemStack(EItems.STRING_MESH.get()), new ItemStack(EItems.STRING_MESH.get()), new ItemStack(EItems.FLINT_MESH.get()), new ItemStack(EItems.IRON_MESH.get()), new ItemStack(EItems.GOLDEN_MESH.get()), new ItemStack(EItems.DIAMOND_MESH.get()), new ItemStack(EItems.NETHERITE_MESH.get())), Component.translatable(TranslationKeys.SIEVE_MESH_JEI_INFO));
registration.addItemStackInfo(List.of(WateringCanItem.getFull(EItems.WOODEN_WATERING_CAN), WateringCanItem.getFull(EItems.STONE_WATERING_CAN), WateringCanItem.getFull(EItems.IRON_WATERING_CAN), WateringCanItem.getFull(EItems.GOLDEN_WATERING_CAN), WateringCanItem.getFull(EItems.DIAMOND_WATERING_CAN), WateringCanItem.getFull(EItems.NETHERITE_WATERING_CAN)), Component.translatable(TranslationKeys.WATERING_CAN_JEI_INFO));
var witchWaterInfo = Component.translatable(TranslationKeys.WITCH_WATER_JEI_INFO);
registration.addItemStackInfo(List.of(new ItemStack(EItems.WITCH_WATER_BUCKET.get()), new ItemStack(EItems.PORCELAIN_WITCH_WATER_BUCKET.get())), witchWaterInfo);
registration.addIngredientInfo(new FluidStack(EFluids.WITCH_WATER.get(), 1000), ForgeTypes.FLUID_STACK, witchWaterInfo);
registration.addIngredientInfo(new FluidStack(EFluids.WITCH_WATER.get(), 1000), NeoForgeTypes.FLUID_STACK, witchWaterInfo);
registration.addItemStackInfo(new ItemStack(EItems.GRASS_SEEDS.get()), Component.translatable(TranslationKeys.GRASS_SEEDS_JEI_INFO));
registration.addItemStackInfo(new ItemStack(EItems.MYCELIUM_SPORES.get()), Component.translatable(TranslationKeys.MYCELIUM_SPORES_JEI_INFO));
registration.addItemStackInfo(new ItemStack(EItems.WARPED_NYLIUM_SPORES.get()), Component.translatable(TranslationKeys.WARPED_NYLIUM_SPORES_JEI_INFO));
@ -187,11 +188,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);
var crookRecipes = new ArrayList<CrookJeiRecipe>();
for (var recipe : Objects.requireNonNull(Minecraft.getInstance().level).getRecipeManager().getAllRecipesFor(ERecipeTypes.CROOK.get())) {
crookRecipes.add(CrookJeiRecipe.create(recipe));
}
registration.addRecipes(CROOK, crookRecipes);
registration.addRecipes(CROOK, CompatUtil.collectAllRecipes(ERecipeTypes.CROOK.get(), CrookJeiRecipe::create));
registration.addRecipes(SIEVE, GroupedSieveRecipe.getAllRecipesGrouped());
addCrucibleHeatSources(registration);
@ -275,6 +272,6 @@ public class ExDeorumJeiPlugin implements IModPlugin {
}
private static <C extends Container, T extends Recipe<C>> void addRecipes(IRecipeRegistration registration, RecipeType<T> category, Supplier<net.minecraft.world.item.crafting.RecipeType<T>> type) {
registration.addRecipes(category, Objects.requireNonNull(Minecraft.getInstance().level).getRecipeManager().getAllRecipesFor(type.get()));
registration.addRecipes(category, CompatUtil.collectAllRecipes(type.get(), Function.identity()));
}
}

View File

@ -37,7 +37,7 @@ import net.minecraft.world.level.storage.loot.providers.number.BinomialDistribut
import net.minecraft.world.level.storage.loot.providers.number.ConstantValue;
import net.minecraft.world.level.storage.loot.providers.number.NumberProvider;
import net.minecraft.world.level.storage.loot.providers.number.UniformGenerator;
import net.minecraftforge.common.util.Lazy;
import net.neoforged.neoforge.common.util.Lazy;
import thedarkcolour.exdeorum.compat.GroupedSieveRecipe;
import thedarkcolour.exdeorum.data.TranslationKeys;
import thedarkcolour.exdeorum.loot.SummationGenerator;
@ -110,14 +110,14 @@ class SieveCategory implements IRecipeCategory<GroupedSieveRecipe> {
slot.setCustomRenderer(VanillaTypes.ITEM_STACK, ClientJeiUtil.AsteriskItemRenderer.INSTANCE);
}
if (provider instanceof BinomialDistributionGenerator binomial) {
if (binomial.n instanceof ConstantValue constant && constant.value == 1) {
var chanceLabel = ClientJeiUtil.formatChance(RecipeUtil.getExpectedValue(binomial.p));
if (binomial.n() instanceof ConstantValue constant && constant.value() == 1) {
var chanceLabel = ClientJeiUtil.formatChance(RecipeUtil.getExpectedValue(binomial.p()));
tooltipLines.add(chanceLabel);
} else {
addAvgOutput(tooltipLines, RecipeUtil.getExpectedValue(provider));
}
addMinMaxes(tooltipLines, 0, getMax(binomial.n));
addMinMaxes(tooltipLines, 0, getMax(binomial.n()));
} else if (provider.getClass() != ConstantValue.class) {
var val = RecipeUtil.getExpectedValue(provider);
if (val != -1.0) {
@ -137,9 +137,9 @@ class SieveCategory implements IRecipeCategory<GroupedSieveRecipe> {
private static double getMin(NumberProvider provider) {
if (provider instanceof ConstantValue value) {
return value.value;
return value.value();
} else if (provider instanceof UniformGenerator uniform) {
return getMin(uniform.min);
return getMin(uniform.min());
} else if (provider instanceof BinomialDistributionGenerator) {
return 0;
} else if (provider instanceof SummationGenerator summation) {
@ -157,11 +157,11 @@ class SieveCategory implements IRecipeCategory<GroupedSieveRecipe> {
private static double getMax(NumberProvider provider) {
if (provider instanceof ConstantValue value) {
return value.value;
return value.value();
} else if (provider instanceof UniformGenerator uniform) {
return getMax(uniform.max);
return getMax(uniform.max());
} else if (provider instanceof BinomialDistributionGenerator binomial) {
return getMax(binomial.n);
return getMax(binomial.n());
} else if (provider instanceof SummationGenerator summation) {
double sum = 0;

View File

@ -25,7 +25,7 @@ import me.shedaniel.rei.api.common.entry.EntryStack;
import me.shedaniel.rei.api.common.entry.type.VanillaEntryTypes;
import me.shedaniel.rei.forge.REIPluginClient;
import net.minecraft.world.item.ItemStack;
import thedarkcolour.exdeorum.compat.CompatHelper;
import thedarkcolour.exdeorum.compat.CompatUtil;
@SuppressWarnings("UnstableApiUsage")
@REIPluginClient
@ -35,16 +35,16 @@ public class ExDeorumReiPlugin implements REIClientPlugin {
rule.hide(() -> {
var builder = EntryIngredient.builder();
for (var barrel : CompatHelper.getAvailableBarrels(false)) {
for (var barrel : CompatUtil.getAvailableBarrels(false)) {
builder.add(EntryStack.of(VanillaEntryTypes.ITEM, new ItemStack(barrel)));
}
for (var sieve : CompatHelper.getAvailableSieves(false, false)) {
for (var sieve : CompatUtil.getAvailableSieves(false, false)) {
builder.add(EntryStack.of(VanillaEntryTypes.ITEM, new ItemStack(sieve)));
}
for (var crucible : CompatHelper.getAvailableLavaCrucibles(false)) {
for (var crucible : CompatUtil.getAvailableLavaCrucibles(false)) {
builder.add(EntryStack.of(VanillaEntryTypes.ITEM, new ItemStack(crucible)));
}
for (var crucible : CompatHelper.getAvailableWaterCrucibles(false)) {
for (var crucible : CompatUtil.getAvailableWaterCrucibles(false)) {
builder.add(EntryStack.of(VanillaEntryTypes.ITEM, new ItemStack(crucible)));
}
return builder.build();

View File

@ -19,11 +19,11 @@
package thedarkcolour.exdeorum.config;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.common.ForgeConfigSpec;
import net.minecraftforge.common.ForgeConfigSpec.BooleanValue;
import net.minecraftforge.common.ForgeConfigSpec.ConfigValue;
import net.minecraftforge.common.ForgeConfigSpec.DoubleValue;
import net.minecraftforge.common.ForgeConfigSpec.IntValue;
import net.neoforged.neoforge.common.ModConfigSpec;
import net.neoforged.neoforge.common.ModConfigSpec.BooleanValue;
import net.neoforged.neoforge.common.ModConfigSpec.ConfigValue;
import net.neoforged.neoforge.common.ModConfigSpec.IntValue;
import net.neoforged.neoforge.common.ModConfigSpec.DoubleValue;
import org.apache.commons.lang3.text.WordUtils;
import org.apache.commons.lang3.tuple.Pair;
import thedarkcolour.exdeorum.compat.ModIds;
@ -31,9 +31,9 @@ import thedarkcolour.exdeorum.compat.ModIds;
import java.util.List;
public class EConfig {
public static final ForgeConfigSpec CLIENT_SPEC;
public static final ForgeConfigSpec COMMON_SPEC;
public static final ForgeConfigSpec SERVER_SPEC;
public static final ModConfigSpec CLIENT_SPEC;
public static final ModConfigSpec COMMON_SPEC;
public static final ModConfigSpec SERVER_SPEC;
public static final Client CLIENT;
public static final Common COMMON;
public static final Server SERVER;
@ -42,7 +42,7 @@ public class EConfig {
public final BooleanValue useFastInfestedLeaves;
public final BooleanValue setVoidWorldAsDefault;
public Client(ForgeConfigSpec.Builder builder) {
public Client(ModConfigSpec.Builder builder) {
builder.comment("Client configuration for Ex Deorum").push("client");
this.useFastInfestedLeaves = builder
@ -78,7 +78,7 @@ public class EConfig {
public final BooleanValue voidNetherGeneration;
public final BooleanValue voidEndGeneration;
public Common(ForgeConfigSpec.Builder builder) {
public Common(ModConfigSpec.Builder builder) {
// Preferred items
builder.comment("Common configuration for Ex Deorum").push("common");
@ -138,7 +138,7 @@ public class EConfig {
public final IntValue mechanicalHammerEnergyConsumption;
public final IntValue sieveIntervalTicks;
public Server(ForgeConfigSpec.Builder builder) {
public Server(ModConfigSpec.Builder builder) {
builder.comment("Server configuration for Ex Deorum").push("server");
this.startingTorch = builder
@ -200,7 +200,7 @@ public class EConfig {
}
@SuppressWarnings("deprecation")
private static ConfigValue<String> preferredOreConfig(ForgeConfigSpec.Builder builder, String name, String defaultId) {
private static ConfigValue<String> preferredOreConfig(ModConfigSpec.Builder builder, String name, String defaultId) {
return builder
.comment("The ID of the item to use for Ex Deorum recipes that craft into " + WordUtils.capitalize(name.replace('_', ' ')) + ". Leave as air for default preference, which chooses alphabetically by mod name.")
.define(List.of("preferred_" + name), defaultId, o -> o != null && o.getClass() == String.class && ResourceLocation.isValidResourceLocation((String) o));
@ -208,17 +208,17 @@ public class EConfig {
static {
{
Pair<Client, ForgeConfigSpec> specPair = new ForgeConfigSpec.Builder().configure(Client::new);
Pair<Client, ModConfigSpec> specPair = new ModConfigSpec.Builder().configure(Client::new);
CLIENT = specPair.getLeft();
CLIENT_SPEC = specPair.getRight();
}
{
Pair<Common, ForgeConfigSpec> specPair = new ForgeConfigSpec.Builder().configure(Common::new);
Pair<Common, ModConfigSpec> specPair = new ModConfigSpec.Builder().configure(Common::new);
COMMON = specPair.getLeft();
COMMON_SPEC = specPair.getRight();
}
{
Pair<Server, ForgeConfigSpec> specPair = new ForgeConfigSpec.Builder().configure(Server::new);
Pair<Server, ModConfigSpec> specPair = new ModConfigSpec.Builder().configure(Server::new);
SERVER = specPair.getLeft();
SERVER_SPEC = specPair.getRight();
}

View File

@ -18,16 +18,17 @@
package thedarkcolour.exdeorum.data;
import net.minecraft.advancements.Advancement;
import net.minecraft.advancements.FrameType;
import net.minecraft.advancements.AdvancementHolder;
import net.minecraft.advancements.AdvancementType;
import net.minecraft.advancements.CriteriaTriggers;
import net.minecraft.advancements.critereon.ImpossibleTrigger;
import net.minecraft.core.HolderLookup;
import net.minecraft.data.PackOutput;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.block.Blocks;
import net.minecraftforge.common.data.ExistingFileHelper;
import net.minecraftforge.common.data.ForgeAdvancementProvider;
import net.neoforged.neoforge.common.data.AdvancementProvider;
import net.neoforged.neoforge.common.data.ExistingFileHelper;
import thedarkcolour.exdeorum.ExDeorum;
import thedarkcolour.exdeorum.material.DefaultMaterials;
import thedarkcolour.exdeorum.registry.EItems;
@ -41,7 +42,7 @@ import static net.minecraft.advancements.Advancement.Builder.advancement;
import static net.minecraft.advancements.critereon.InventoryChangeTrigger.TriggerInstance.hasItems;
import static net.minecraft.advancements.critereon.ItemPredicate.Builder.item;
class Advancements extends ForgeAdvancementProvider {
class Advancements extends AdvancementProvider {
public Advancements(PackOutput output, CompletableFuture<HolderLookup.Provider> registries, ExistingFileHelper existingFileHelper) {
super(output, registries, existingFileHelper, List.of(new CoreAchievements()));
}
@ -52,20 +53,20 @@ class Advancements extends ForgeAdvancementProvider {
public static class CoreAchievements implements AdvancementGenerator {
@Override
public void generate(HolderLookup.Provider registries, Consumer<Advancement> saver, ExistingFileHelper helper) {
public void generate(HolderLookup.Provider registries, Consumer<AdvancementHolder> saver, ExistingFileHelper helper) {
var root = advancement()
.display(
Blocks.OAK_SAPLING,
Component.translatable(TranslationKeys.ROOT_ADVANCEMENT_TITLE),
Component.translatable(TranslationKeys.ROOT_ADVANCEMENT_DESCRIPTION),
modLoc("textures/gui/advancements/backgrounds/void.png"),
FrameType.TASK,
AdvancementType.TASK,
true,
true,
false
)
// hardcoded to EventHandler
.addCriterion("in_void_world", new ImpossibleTrigger.TriggerInstance())
.addCriterion("in_void_world", CriteriaTriggers.IMPOSSIBLE.createCriterion(new ImpossibleTrigger.TriggerInstance()))
.save(saver, modLoc("core/root"), helper);
var crook = advancement()
.parent(root)
@ -74,7 +75,7 @@ class Advancements extends ForgeAdvancementProvider {
Component.translatable(TranslationKeys.CROOK_ADVANCEMENT_TITLE),
Component.translatable(TranslationKeys.CROOK_ADVANCEMENT_DESCRIPTION),
null,
FrameType.TASK,
AdvancementType.TASK,
true,
true,
true
@ -88,7 +89,7 @@ class Advancements extends ForgeAdvancementProvider {
Component.translatable(TranslationKeys.BARREL_ADVANCEMENT_TITLE),
Component.translatable(TranslationKeys.BARREL_ADVANCEMENT_DESCRIPTION),
null,
FrameType.TASK,
AdvancementType.TASK,
true,
true,
true
@ -102,7 +103,7 @@ class Advancements extends ForgeAdvancementProvider {
Component.translatable(TranslationKeys.SILK_WORM_ADVANCEMENT_TITLE),
Component.translatable(TranslationKeys.SILK_WORM_ADVANCEMENT_DESCRIPTION),
null,
FrameType.TASK,
AdvancementType.TASK,
true,
true,
false
@ -116,7 +117,7 @@ class Advancements extends ForgeAdvancementProvider {
Component.translatable(TranslationKeys.STRING_MESH_ADVANCEMENT_TITLE),
Component.translatable(TranslationKeys.STRING_MESH_ADVANCEMENT_DESCRIPTION),
null,
FrameType.TASK,
AdvancementType.TASK,
true,
true,
false

View File

@ -18,12 +18,12 @@
package thedarkcolour.exdeorum.data;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraftforge.client.model.generators.BlockModelBuilder;
import net.minecraftforge.client.model.generators.ConfiguredModel;
import net.minecraftforge.registries.ForgeRegistries;
import net.neoforged.neoforge.client.model.generators.BlockModelBuilder;
import net.neoforged.neoforge.client.model.generators.ConfiguredModel;
import thedarkcolour.exdeorum.material.DefaultMaterials;
import thedarkcolour.exdeorum.registry.EBlocks;
import thedarkcolour.modkit.data.MKBlockModelProvider;
@ -196,7 +196,7 @@ class BlockModels {
}
private static ResourceLocation texture(Block block, String prefix, String suffix) {
var key = Objects.requireNonNull(ForgeRegistries.BLOCKS.getKey(block));
var key = Objects.requireNonNull(BuiltInRegistries.BLOCK.getKey(block));
return new ResourceLocation(key.getNamespace(), "block/" + prefix + key.getPath() + suffix);
}

View File

@ -19,10 +19,8 @@
package thedarkcolour.exdeorum.data;
import net.minecraft.core.registries.Registries;
import net.minecraftforge.data.event.GatherDataEvent;
import net.minecraftforge.data.loading.DatagenModLoader;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import net.neoforged.fml.common.Mod;
import net.neoforged.neoforge.data.event.GatherDataEvent;
import thedarkcolour.exdeorum.ExDeorum;
import thedarkcolour.exdeorum.data.recipe.Recipes;
import thedarkcolour.modkit.data.DataHelper;
@ -30,13 +28,6 @@ import thedarkcolour.modkit.data.DataHelper;
// these two annotations are equivalent to modEventBus.addListener(Data::generateData)
@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD)
public class Data {
static {
if (DatagenModLoader.isRunningDataGen()) {
ModCompatData.registerModData();
}
}
@SubscribeEvent
public static void generateData(GatherDataEvent event) {
// Two things used by data generators
var gen = event.getGenerator(); // writes to json

View File

@ -23,10 +23,12 @@ import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraftforge.data.loading.DatagenModLoader;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import net.minecraftforge.registries.DeferredRegister;
import net.minecraftforge.registries.RegistryObject;
import net.neoforged.bus.api.IEventBus;
import net.neoforged.fml.javafmlmod.FMLJavaModLoadingContext;
import net.neoforged.neoforge.data.loading.DatagenModLoader;
import net.neoforged.neoforge.registries.DeferredBlock;
import net.neoforged.neoforge.registries.DeferredItem;
import net.neoforged.neoforge.registries.DeferredRegister;
import thedarkcolour.exdeorum.compat.ModIds;
import java.util.HashMap;
@ -35,13 +37,13 @@ import java.util.Map;
// Mocks modded items so that data generation can reference modded items without needing those mods installed.
public class ModCompatData {
// Identity maps because keys are just constants from ModIds
private static final Map<String, DeferredRegister<Item>> itemRegistries = new HashMap<>();
private static final Map<String, DeferredRegister<Block>> blockRegistries = new HashMap<>();
private static final Map<String, DeferredRegister.Items> itemRegistries = new HashMap<>();
private static final Map<String, DeferredRegister.Blocks> blockRegistries = new HashMap<>();
@SuppressWarnings("DataFlowIssue")
private static RegistryObject<Item> item(String modid, String name) {
private static DeferredItem<Item> item(String modid, String name) {
if (DatagenModLoader.isRunningDataGen()) {
DeferredRegister<Item> registry = itemRegistries.computeIfAbsent(modid, key -> DeferredRegister.create(Registries.ITEM, key));
DeferredRegister.Items registry = itemRegistries.computeIfAbsent(modid, DeferredRegister::createItems);
return registry.register(name, () -> new Item(new Item.Properties()));
} else {
return null;
@ -49,9 +51,9 @@ public class ModCompatData {
}
@SuppressWarnings("DataFlowIssue")
private static RegistryObject<Block> block(String modid, String name) {
private static DeferredBlock<Block> block(String modid, String name) {
if (DatagenModLoader.isRunningDataGen()) {
DeferredRegister<Block> registry = blockRegistries.computeIfAbsent(modid, key -> DeferredRegister.create(Registries.BLOCK, key));
DeferredRegister.Blocks registry = blockRegistries.computeIfAbsent(modid, DeferredRegister::createBlocks);
return registry.register(name, () -> new Block(BlockBehaviour.Properties.of()));
} else {
return null;
@ -59,13 +61,13 @@ public class ModCompatData {
}
// Ender IO
public static final RegistryObject<Item>
public static final DeferredItem<Item>
GRAINS_OF_INFINITY = item(ModIds.ENDERIO, "grains_of_infinity");
// Bigger reactors
public static final RegistryObject<Item>
public static final DeferredItem<Item>
YELLORIUM_DUST = item(ModIds.BIGGER_REACTORS, "yellorium_dust");
// Biomes O' Plenty
public static final RegistryObject<Block>
public static final DeferredBlock<Block>
FIR_PLANKS = block(ModIds.BIOMES_O_PLENTY, "fir_planks"),
REDWOOD_PLANKS = block(ModIds.BIOMES_O_PLENTY, "redwood_planks"),
MAHOGANY_PLANKS = block(ModIds.BIOMES_O_PLENTY, "mahogany_planks"),
@ -86,7 +88,7 @@ public class ModCompatData {
MAGIC_LOG = block(ModIds.BIOMES_O_PLENTY, "magic_log"),
UMBRAN_LOG = block(ModIds.BIOMES_O_PLENTY, "umbran_log"),
HELLBARK_LOG = block(ModIds.BIOMES_O_PLENTY, "hellbark_log");
public static final RegistryObject<Item>
public static final DeferredItem<Item>
FIR_PLANKS_ITEM = item(ModIds.BIOMES_O_PLENTY, "fir_planks"),
REDWOOD_PLANKS_ITEM = item(ModIds.BIOMES_O_PLENTY, "redwood_planks"),
MAHOGANY_PLANKS_ITEM = item(ModIds.BIOMES_O_PLENTY, "mahogany_planks"),
@ -135,19 +137,19 @@ public class ModCompatData {
UMBRAN_SAPLING = item(ModIds.BIOMES_O_PLENTY, "umbran_sapling"),
HELLBARK_SAPLING = item(ModIds.BIOMES_O_PLENTY, "hellbark_sapling");
// Applied Energistics 2
public static final RegistryObject<Item>
public static final DeferredItem<Item>
CERTUS_QUARTZ_CRYSTAL = item(ModIds.APPLIED_ENERGISTICS_2, "certus_quartz_crystal"),
CHARGED_CERTUS_QUARTZ_CRYSTAL = item(ModIds.APPLIED_ENERGISTICS_2, "charged_certus_quartz_crystal"),
CERTUS_QUARTZ_DUST = item(ModIds.APPLIED_ENERGISTICS_2, "certus_quartz_dust"),
SKY_STONE_DUST = item(ModIds.APPLIED_ENERGISTICS_2, "sky_dust");
// Ars Nouveau
public static final RegistryObject<Block>
public static final DeferredBlock<Block>
CASCADING_ARCHWOOD_LOG = block(ModIds.ARS_NOUVEAU, "blue_archwood_log"),
BLAZING_ARCHWOOD_LOG = block(ModIds.ARS_NOUVEAU, "red_archwood_log"),
VEXING_ARCHWOOD_LOG = block(ModIds.ARS_NOUVEAU, "purple_archwood_log"),
FLOURISHING_ARCHWOOD_LOG = block(ModIds.ARS_NOUVEAU, "green_archwood_log"),
ARCHWOOD_PLANKS = block(ModIds.ARS_NOUVEAU, "archwood_planks");
public static final RegistryObject<Item>
public static final DeferredItem<Item>
BLUE_ARCHWOOD_SAPLING = item(ModIds.ARS_NOUVEAU, "blue_archwood_sapling"),
RED_ARCHWOOD_SAPLING = item(ModIds.ARS_NOUVEAU, "red_archwood_sapling"),
PURPLE_ARCHWOOD_SAPLING = item(ModIds.ARS_NOUVEAU, "purple_archwood_sapling"),
@ -160,17 +162,17 @@ public class ModCompatData {
ARCHWOOD_SLAB = item(ModIds.ARS_NOUVEAU, "archwood_slab"),
ARCHWOOD_PLANKS_ITEM = item(ModIds.ARS_NOUVEAU, "archwood_planks");
// Aether
public static final RegistryObject<Block>
public static final DeferredBlock<Block>
SKYROOT_PLANKS = block(ModIds.AETHER, "skyroot_planks"),
SKYROOT_LOG = block(ModIds.AETHER, "skyroot_log"),
GOLDEN_OAK_LOG = block(ModIds.AETHER, "golden_oak_log");
public static final RegistryObject<Item>
public static final DeferredItem<Item>
SKYROOT_SLAB = item(ModIds.AETHER, "skyroot_slab"),
SKYROOT_PLANKS_ITEM = item(ModIds.AETHER, "skyroot_planks"),
GOLDEN_OAK_LOG_ITEM = item(ModIds.AETHER, "golden_oak_log"),
SKYROOT_LOG_ITEM = item(ModIds.AETHER, "skyroot_log");
// Blue Skies
public static final RegistryObject<Block>
public static final DeferredBlock<Block>
BLUEBRIGHT_PLANKS = block(ModIds.BLUE_SKIES, "bluebright_planks"),
STARLIT_PLANKS = block(ModIds.BLUE_SKIES, "starlit_planks"),
FROSTBRIGHT_PLANKS = block(ModIds.BLUE_SKIES, "frostbright_planks"),
@ -187,7 +189,7 @@ public class ModCompatData {
DUSK_LOG = block(ModIds.BLUE_SKIES, "dusk_log"),
MAPLE_LOG = block(ModIds.BLUE_SKIES, "maple_log"),
CRYSTALLIZED_LOG = block(ModIds.BLUE_SKIES, "crystallized_log");
public static final RegistryObject<Item>
public static final DeferredItem<Item>
BLUEBRIGHT_PLANKS_ITEM = item(ModIds.BLUE_SKIES, "bluebright_planks"),
STARLIT_PLANKS_ITEM = item(ModIds.BLUE_SKIES, "starlit_planks"),
FROSTBRIGHT_PLANKS_ITEM = item(ModIds.BLUE_SKIES, "frostbright_planks"),
@ -225,9 +227,7 @@ public class ModCompatData {
}
}
public static void registerModData() {
var modBus = FMLJavaModLoadingContext.get().getModEventBus();
public static void registerModData(IEventBus modBus) {
for (var registry : itemRegistries.values()) {
registry.register(modBus);
}

View File

@ -20,8 +20,8 @@ package thedarkcolour.exdeorum.data.recipe;
import net.minecraft.advancements.critereon.StatePropertiesPredicate;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.data.recipes.FinishedRecipe;
import net.minecraft.data.recipes.RecipeCategory;
import net.minecraft.data.recipes.RecipeOutput;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.BlockTags;
import net.minecraft.tags.ItemTags;
@ -40,36 +40,33 @@ import net.minecraft.world.level.material.Fluids;
import net.minecraft.world.level.storage.loot.providers.number.ConstantValue;
import net.minecraft.world.level.storage.loot.providers.number.NumberProvider;
import net.minecraft.world.level.storage.loot.providers.number.UniformGenerator;
import net.minecraftforge.common.ForgeMod;
import net.minecraftforge.common.Tags;
import net.minecraftforge.common.crafting.conditions.ICondition;
import net.minecraftforge.common.crafting.conditions.ModLoadedCondition;
import net.minecraftforge.common.crafting.conditions.NotCondition;
import net.minecraftforge.common.crafting.conditions.TagEmptyCondition;
import net.minecraftforge.registries.RegistryObject;
import org.apache.commons.lang3.mutable.MutableObject;
import net.neoforged.neoforge.common.NeoForgeMod;
import net.neoforged.neoforge.common.Tags;
import net.neoforged.neoforge.common.conditions.ICondition;
import net.neoforged.neoforge.common.conditions.ModLoadedCondition;
import net.neoforged.neoforge.common.conditions.NotCondition;
import net.neoforged.neoforge.common.conditions.TagEmptyCondition;
import net.neoforged.neoforge.fluids.FluidStack;
import thedarkcolour.exdeorum.ExDeorum;
import thedarkcolour.exdeorum.block.InfestedLeavesBlock;
import thedarkcolour.exdeorum.compat.ModIds;
import thedarkcolour.exdeorum.data.ModCompatData;
import thedarkcolour.exdeorum.material.DefaultMaterials;
import thedarkcolour.exdeorum.recipe.TagResultRecipe;
import thedarkcolour.exdeorum.recipe.OreChunkRecipe;
import thedarkcolour.exdeorum.recipe.WeightedList;
import thedarkcolour.exdeorum.recipe.barrel.*;
import thedarkcolour.exdeorum.recipe.BlockPredicate;
import thedarkcolour.exdeorum.recipe.crook.FinishedCrookRecipe;
import thedarkcolour.exdeorum.recipe.crucible.FinishedCrucibleHeatRecipe;
import thedarkcolour.exdeorum.recipe.crucible.FinishedCrucibleRecipe;
import thedarkcolour.exdeorum.recipe.hammer.FinishedHammerRecipe;
import thedarkcolour.exdeorum.recipe.crook.CrookRecipe;
import thedarkcolour.exdeorum.recipe.crucible.CrucibleHeatRecipe;
import thedarkcolour.exdeorum.recipe.crucible.CrucibleRecipe;
import thedarkcolour.exdeorum.recipe.hammer.HammerRecipe;
import thedarkcolour.exdeorum.registry.EBlocks;
import thedarkcolour.exdeorum.registry.EFluids;
import thedarkcolour.exdeorum.registry.EItems;
import thedarkcolour.exdeorum.registry.ERecipeSerializers;
import thedarkcolour.exdeorum.tag.EItemTags;
import thedarkcolour.modkit.data.MKRecipeProvider;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Supplier;
import static net.minecraft.world.level.storage.loot.providers.number.UniformGenerator.between;
@ -79,7 +76,7 @@ import static thedarkcolour.modkit.data.MKRecipeProvider.path;
public class Recipes {
private static final Ingredient SPORES_AND_SEEDS = ingredient(EItems.GRASS_SEEDS, EItems.MYCELIUM_SPORES, EItems.WARPED_NYLIUM_SPORES, EItems.CRIMSON_NYLIUM_SPORES);
public static void addRecipes(Consumer<FinishedRecipe> writer, MKRecipeProvider recipes) {
public static void addRecipes(RecipeOutput writer, MKRecipeProvider recipes) {
craftingRecipes(writer, recipes);
smeltingRecipes(recipes);
SieveRecipes.sieveRecipes(writer);
@ -92,7 +89,7 @@ public class Recipes {
fluidTransformationRecipes(writer);
}
private static void craftingRecipes(Consumer<FinishedRecipe> writer, MKRecipeProvider recipes) {
private static void craftingRecipes(RecipeOutput writer, MKRecipeProvider recipes) {
// Crooks
shapedCrook(recipes, EItems.CROOK, ingredient(Tags.Items.RODS_WOODEN));
shapedCrook(recipes, EItems.BONE_CROOK, ingredient(Items.BONE));
@ -183,36 +180,36 @@ public class Recipes {
modUShaped(recipes, ModIds.BLUE_SKIES, ModCompatData.CRYSTALLIZED_PLANKS_ITEM, ModCompatData.CRYSTALLIZED_SLAB, DefaultMaterials.CRYSTALLIZED_BARREL.getItem());
// Pebbles and ore chunks
recipes.grid2x2(Items.COBBLESTONE, ingredient(EItems.STONE_PEBBLE));
recipes.grid2x2(Items.ANDESITE, ingredient(EItems.ANDESITE_PEBBLE));
recipes.grid2x2(Items.DIORITE, ingredient(EItems.DIORITE_PEBBLE));
recipes.grid2x2(Items.GRANITE, ingredient(EItems.GRANITE_PEBBLE));
recipes.grid2x2(Items.COBBLED_DEEPSLATE, ingredient(EItems.DEEPSLATE_PEBBLE));
recipes.grid2x2(Items.TUFF, ingredient(EItems.TUFF_PEBBLE));
recipes.grid2x2(Items.CALCITE, ingredient(EItems.CALCITE_PEBBLE));
recipes.grid2x2(Items.BLACKSTONE, ingredient(EItems.BLACKSTONE_PEBBLE));
recipes.grid2x2(Items.BASALT, ingredient(EItems.BASALT_PEBBLE));
recipes.grid2x2(Items.IRON_ORE, ingredient(EItems.IRON_ORE_CHUNK));
recipes.grid2x2(Items.GOLD_ORE, ingredient(EItems.GOLD_ORE_CHUNK));
recipes.grid2x2(Items.COPPER_ORE, ingredient(EItems.COPPER_ORE_CHUNK));
recipes.grid2x2(Items.MOSS_BLOCK, ingredient(EItems.GRASS_SEEDS));
recipes.grid2x2(RecipeCategory.BUILDING_BLOCKS, Items.COBBLESTONE, ingredient(EItems.STONE_PEBBLE));
recipes.grid2x2(RecipeCategory.BUILDING_BLOCKS, Items.ANDESITE, ingredient(EItems.ANDESITE_PEBBLE));
recipes.grid2x2(RecipeCategory.BUILDING_BLOCKS, Items.DIORITE, ingredient(EItems.DIORITE_PEBBLE));
recipes.grid2x2(RecipeCategory.BUILDING_BLOCKS, Items.GRANITE, ingredient(EItems.GRANITE_PEBBLE));
recipes.grid2x2(RecipeCategory.BUILDING_BLOCKS, Items.COBBLED_DEEPSLATE, ingredient(EItems.DEEPSLATE_PEBBLE));
recipes.grid2x2(RecipeCategory.BUILDING_BLOCKS, Items.TUFF, ingredient(EItems.TUFF_PEBBLE));
recipes.grid2x2(RecipeCategory.BUILDING_BLOCKS, Items.CALCITE, ingredient(EItems.CALCITE_PEBBLE));
recipes.grid2x2(RecipeCategory.BUILDING_BLOCKS, Items.BLACKSTONE, ingredient(EItems.BLACKSTONE_PEBBLE));
recipes.grid2x2(RecipeCategory.BUILDING_BLOCKS, Items.BASALT, ingredient(EItems.BASALT_PEBBLE));
recipes.grid2x2(RecipeCategory.BUILDING_BLOCKS, Items.IRON_ORE, ingredient(EItems.IRON_ORE_CHUNK));
recipes.grid2x2(RecipeCategory.BUILDING_BLOCKS, Items.GOLD_ORE, ingredient(EItems.GOLD_ORE_CHUNK));
recipes.grid2x2(RecipeCategory.BUILDING_BLOCKS, Items.COPPER_ORE, ingredient(EItems.COPPER_ORE_CHUNK));
recipes.grid2x2(RecipeCategory.BUILDING_BLOCKS, Items.MOSS_BLOCK, ingredient(EItems.GRASS_SEEDS));
// Modded ores
grid2x2TagResult(writer, recipes, EItemTags.ORES_ALUMINUM, ingredient(EItems.ALUMINUM_ORE_CHUNK));
grid2x2TagResult(writer, recipes, EItemTags.ORES_COBALT, ingredient(EItems.COBALT_ORE_CHUNK));
grid2x2TagResult(writer, recipes, EItemTags.ORES_SILVER, ingredient(EItems.SILVER_ORE_CHUNK));
grid2x2TagResult(writer, recipes, EItemTags.ORES_LEAD, ingredient(EItems.LEAD_ORE_CHUNK));
grid2x2TagResult(writer, recipes, EItemTags.ORES_PLATINUM, ingredient(EItems.PLATINUM_ORE_CHUNK));
grid2x2TagResult(writer, recipes, EItemTags.ORES_NICKEL, ingredient(EItems.NICKEL_ORE_CHUNK));
grid2x2TagResult(writer, recipes, EItemTags.ORES_URANIUM, ingredient(EItems.URANIUM_ORE_CHUNK));
grid2x2TagResult(writer, recipes, EItemTags.ORES_OSMIUM, ingredient(EItems.OSMIUM_ORE_CHUNK));
grid2x2TagResult(writer, recipes, EItemTags.ORES_TIN, ingredient(EItems.TIN_ORE_CHUNK));
grid2x2TagResult(writer, recipes, EItemTags.ORES_ZINC, ingredient(EItems.ZINC_ORE_CHUNK));
grid2x2TagResult(writer, recipes, EItemTags.ORES_IRIDIUM, ingredient(EItems.IRIDIUM_ORE_CHUNK));
grid2x2TagResult(writer, recipes, EItemTags.ORES_THORIUM, ingredient(EItems.THORIUM_ORE_CHUNK));
grid2x2TagResult(writer, recipes, EItemTags.ORES_MAGNESIUM, ingredient(EItems.MAGNESIUM_ORE_CHUNK));
grid2x2TagResult(writer, recipes, EItemTags.ORES_LITHIUM, ingredient(EItems.LITHIUM_ORE_CHUNK));
grid2x2TagResult(writer, recipes, EItemTags.ORES_BORON, ingredient(EItems.BORON_ORE_CHUNK));
grid2x2TagResult(writer, EItemTags.ORES_ALUMINUM, ingredient(EItems.ALUMINUM_ORE_CHUNK));
grid2x2TagResult(writer, EItemTags.ORES_COBALT, ingredient(EItems.COBALT_ORE_CHUNK));
grid2x2TagResult(writer, EItemTags.ORES_SILVER, ingredient(EItems.SILVER_ORE_CHUNK));
grid2x2TagResult(writer, EItemTags.ORES_LEAD, ingredient(EItems.LEAD_ORE_CHUNK));
grid2x2TagResult(writer, EItemTags.ORES_PLATINUM, ingredient(EItems.PLATINUM_ORE_CHUNK));
grid2x2TagResult(writer, EItemTags.ORES_NICKEL, ingredient(EItems.NICKEL_ORE_CHUNK));
grid2x2TagResult(writer, EItemTags.ORES_URANIUM, ingredient(EItems.URANIUM_ORE_CHUNK));
grid2x2TagResult(writer, EItemTags.ORES_OSMIUM, ingredient(EItems.OSMIUM_ORE_CHUNK));
grid2x2TagResult(writer, EItemTags.ORES_TIN, ingredient(EItems.TIN_ORE_CHUNK));
grid2x2TagResult(writer, EItemTags.ORES_ZINC, ingredient(EItems.ZINC_ORE_CHUNK));
grid2x2TagResult(writer, EItemTags.ORES_IRIDIUM, ingredient(EItems.IRIDIUM_ORE_CHUNK));
grid2x2TagResult(writer, EItemTags.ORES_THORIUM, ingredient(EItems.THORIUM_ORE_CHUNK));
grid2x2TagResult(writer, EItemTags.ORES_MAGNESIUM, ingredient(EItems.MAGNESIUM_ORE_CHUNK));
grid2x2TagResult(writer, EItemTags.ORES_LITHIUM, ingredient(EItems.LITHIUM_ORE_CHUNK));
grid2x2TagResult(writer, EItemTags.ORES_BORON, ingredient(EItems.BORON_ORE_CHUNK));
// Sieves
sieve(recipes, DefaultMaterials.OAK_SIEVE.getItem(), Items.OAK_PLANKS, Items.OAK_SLAB);
@ -322,33 +319,24 @@ public class Recipes {
});
}
private static void modUShaped(MKRecipeProvider recipes, String modid, RegistryObject<? extends Item> sides, RegistryObject<? extends Item> middle, Item result) {
private static void modUShaped(MKRecipeProvider recipes, String modid, ItemLike sides, ItemLike middle, Item result) {
recipes.conditional(path(result), List.of(modInstalled(modid)), writer1 -> {
uShaped(recipes, result, ingredient(sides), ingredient(middle));
});
}
private static void modSieve(MKRecipeProvider recipes, String modid, RegistryObject<? extends Item> planks, RegistryObject<? extends Item> slab, Item result) {
private static void modSieve(MKRecipeProvider recipes, String modid, ItemLike planks, ItemLike slab, Item result) {
recipes.conditional(path(result), List.of(modInstalled(modid)), writer1 -> {
sieve(recipes, result, planks.get(), slab.get());
sieve(recipes, result, planks, slab);
});
}
private static void grid2x2TagResult(Consumer<FinishedRecipe> writer, MKRecipeProvider recipes, TagKey<Item> resultTag, Ingredient ingredient) {
// capture the generated recipe and wrap it in a TagResultRecipe
var wrappedRecipe = new MutableObject<FinishedRecipe>();
recipes.pushWriter(wrappedRecipe::setValue, newWriter -> {
recipes.shapedCrafting(resultTag.location().getPath() + "_tag", RecipeCategory.MISC, Items.AIR, recipe -> {
recipe.define('#', ingredient);
recipe.pattern("##");
recipe.pattern("##");
});
});
writer.accept(new TagResultRecipe.Finished(resultTag, wrappedRecipe.getValue()));
private static void grid2x2TagResult(RecipeOutput writer, TagKey<Item> resultTag, Ingredient ingredient) {
writer.accept(new ResourceLocation(resultTag.location().getPath() + "_from_chunks"), new OreChunkRecipe(ingredient, resultTag), null, tagNotEmpty(resultTag));
}
private static void shapedCrook(MKRecipeProvider recipes, RegistryObject<? extends Item> crook, Ingredient stick) {
recipes.shapedCrafting(RecipeCategory.TOOLS, crook.get(), recipe -> {
private static void shapedCrook(MKRecipeProvider recipes, ItemLike crook, Ingredient stick) {
recipes.shapedCrafting(RecipeCategory.TOOLS, crook, recipe -> {
recipe.define('x', stick);
recipe.pattern("xx");
recipe.pattern(" x");
@ -356,8 +344,8 @@ public class Recipes {
});
}
private static void shapedHammer(MKRecipeProvider recipes, RegistryObject<? extends Item> hammer, Ingredient material) {
recipes.shapedCrafting(RecipeCategory.TOOLS, hammer.get(), recipe -> {
private static void shapedHammer(MKRecipeProvider recipes, ItemLike hammer, Ingredient material) {
recipes.shapedCrafting(RecipeCategory.TOOLS, hammer, recipe -> {
recipe.define('m', material);
recipe.define('s', Tags.Items.RODS_WOODEN);
recipe.pattern(" m ");
@ -376,7 +364,7 @@ public class Recipes {
});
}
private static void sieve(MKRecipeProvider recipes, Item result, Item planks, Item slab) {
private static void sieve(MKRecipeProvider recipes, ItemLike result, ItemLike planks, ItemLike slab) {
recipes.shapedCrafting(RecipeCategory.MISC, result, recipe -> {
recipe.define('O', planks);
recipe.define('_', slab);
@ -397,10 +385,10 @@ public class Recipes {
});
}
private static void meshUpgrade(MKRecipeProvider recipes, RegistryObject<? extends Item> newMesh, RegistryObject<? extends Item> previousMesh, Ingredient ingredient) {
recipes.shapedCrafting(newMesh.getId().getPath() + "_from_" + previousMesh.getId().getPath(), RecipeCategory.MISC, newMesh.get(), recipe -> {
private static void meshUpgrade(MKRecipeProvider recipes, ItemLike newMesh, ItemLike previousMesh, Ingredient ingredient) {
recipes.shapedCrafting(path(newMesh) + "_from_" + path(previousMesh), RecipeCategory.MISC, newMesh, recipe -> {
recipe.define('#', ingredient);
recipe.define('M', previousMesh.get());
recipe.define('M', previousMesh);
recipe.pattern(" # ");
recipe.pattern("#M#");
recipe.pattern(" # ");
@ -423,7 +411,7 @@ public class Recipes {
recipes.foodCooking(EItems.SILK_WORM.get(), EItems.COOKED_SILK_WORM.get(), 0.1f);
}
private static void crucibleRecipes(Consumer<FinishedRecipe> writer) {
private static void crucibleRecipes(RecipeOutput writer) {
lavaCrucible(writer, "cobblestone", ingredient(Tags.Items.COBBLESTONE), 250);
lavaCrucible(writer, "stone", ingredient(Tags.Items.STONE), 250);
lavaCrucible(writer, "gravel", ingredient(Tags.Items.GRAVEL), 250);
@ -439,7 +427,7 @@ public class Recipes {
waterCrucible(writer, "vine", ingredient(Items.VINE), 100);
waterCrucible(writer, "seeds_and_spores", SPORES_AND_SEEDS, 50);
waterCrucible(writer, "seeds", ingredient(Tags.Items.SEEDS), 50);
waterCrucible(writer, "grass", ingredient(Items.GRASS, Items.TALL_GRASS), 100);
waterCrucible(writer, "grass", ingredient(Items.SHORT_GRASS, Items.TALL_GRASS), 100);
waterCrucible(writer, "grass_block", ingredient(Items.GRASS_BLOCK), 150);
waterCrucible(writer, "sweet_berries", ingredient(Items.SWEET_BERRIES, Items.GLOW_BERRIES), 50);
waterCrucible(writer, "melon_slice", ingredient(Items.MELON_SLICE), 50);
@ -457,15 +445,15 @@ public class Recipes {
waterCrucible(writer, "spore_blossom", ingredient(Items.SPORE_BLOSSOM), 150);
}
private static void lavaCrucible(Consumer<FinishedRecipe> writer, String id, Ingredient ingredient, int volume) {
writer.accept(new FinishedCrucibleRecipe(new ResourceLocation(ExDeorum.ID, "lava_crucible/" + id), ERecipeSerializers.LAVA_CRUCIBLE.get(), ingredient, Fluids.LAVA, volume));
private static void lavaCrucible(RecipeOutput writer, String id, Ingredient ingredient, int volume) {
writer.accept(new ResourceLocation(ExDeorum.ID, "lava_crucible/" + id), new CrucibleRecipe.Lava(ingredient, new FluidStack(Fluids.LAVA, volume)), null);
}
private static void waterCrucible(Consumer<FinishedRecipe> writer, String id, Ingredient ingredient, int volume) {
writer.accept(new FinishedCrucibleRecipe(new ResourceLocation(ExDeorum.ID, "water_crucible/" + id), ERecipeSerializers.WATER_CRUCIBLE.get(), ingredient, Fluids.WATER, volume));
private static void waterCrucible(RecipeOutput writer, String id, Ingredient ingredient, int volume) {
writer.accept(new ResourceLocation(ExDeorum.ID, "water_crucible/" + id), new CrucibleRecipe.Water(ingredient, new FluidStack(Fluids.WATER, volume)), null);
}
private static void hammerRecipes(Consumer<FinishedRecipe> writer) {
private static void hammerRecipes(RecipeOutput writer) {
// Cobblestone -> Gravel -> Sand -> Dust
hammerRecipe(writer, "gravel", ingredient(Items.COBBLESTONE, Items.DIORITE, Items.GRANITE, Items.ANDESITE), Blocks.GRAVEL);
hammerRecipe(writer, "sand", ingredient(Items.GRAVEL), Blocks.SAND);
@ -500,27 +488,29 @@ public class Recipes {
hammerRecipe(writer, "pointed_dripstone", ingredient(Items.DRIPSTONE_BLOCK), Items.POINTED_DRIPSTONE, between(2, 4));
}
private static void hammerRecipe(Consumer<FinishedRecipe> writer, String name, Ingredient block, ItemLike result) {
private static void hammerRecipe(RecipeOutput writer, String name, Ingredient block, ItemLike result) {
hammerRecipe(writer, name, block, result, ConstantValue.exactly(1f));
}
private static void hammerRecipe(Consumer<FinishedRecipe> writer, String name, Ingredient block, ItemLike result, NumberProvider resultAmount) {
writer.accept(new FinishedHammerRecipe(new ResourceLocation(ExDeorum.ID, "hammer/" + name), block, result.asItem(), resultAmount));
private static void hammerRecipe(RecipeOutput writer, String name, Ingredient block, ItemLike result, NumberProvider resultAmount) {
writer.accept(new ResourceLocation(ExDeorum.ID, "hammer/" + name), new HammerRecipe(block, result.asItem(), resultAmount), null);
}
private static void crookRecipes(Consumer<FinishedRecipe> writer) {
private static void crookRecipes(RecipeOutput writer) {
crookRecipe(writer, "silkworm", BlockPredicate.blockTag(BlockTags.LEAVES), EItems.SILK_WORM.get(), 0.01f);
var fullyInfestedLeaves = BlockPredicate.blockState(EBlocks.INFESTED_LEAVES.get(), StatePropertiesPredicate.Builder.properties().hasProperty(InfestedLeavesBlock.FULLY_INFESTED, true).build());
@SuppressWarnings("OptionalGetWithoutIsPresent")
var fullyInfestedLeaves = BlockPredicate.blockState(EBlocks.INFESTED_LEAVES.get(), StatePropertiesPredicate.Builder.properties().hasProperty(InfestedLeavesBlock.FULLY_INFESTED, true).build().get());
crookRecipe(writer, "silkworm_bonus", fullyInfestedLeaves, EItems.SILK_WORM.get(), 0.01f);
crookRecipe(writer, "string_roll_1", fullyInfestedLeaves, Items.STRING, 0.4f);
crookRecipe(writer, "string_roll_2", fullyInfestedLeaves, Items.STRING, 0.1f);
}
private static void crookRecipe(Consumer<FinishedRecipe> writer, String name, BlockPredicate blockPredicate, ItemLike result, float chance) {
writer.accept(new FinishedCrookRecipe(new ResourceLocation(ExDeorum.ID, "crook/" + name), blockPredicate, result.asItem(), chance));
private static void crookRecipe(RecipeOutput writer, String name, BlockPredicate blockPredicate, ItemLike result, float chance) {
writer.accept(new ResourceLocation(ExDeorum.ID, "crook/" + name), new CrookRecipe(blockPredicate, result.asItem(), chance), null);
}
private static void crucibleHeatSources(Consumer<FinishedRecipe> writer) {
@SuppressWarnings("OptionalGetWithoutIsPresent")
private static void crucibleHeatSources(RecipeOutput writer) {
crucibleHeatSource(writer, Blocks.TORCH, 1);
crucibleHeatSource(writer, Blocks.WALL_TORCH, 1);
crucibleHeatSource(writer, Blocks.LANTERN, 1);
@ -531,19 +521,19 @@ public class Recipes {
crucibleHeatSource(writer, Blocks.FIRE, 5);
crucibleHeatSource(writer, Blocks.SOUL_FIRE, 5);
crucibleHeatSource(writer, "lit_campfire", BlockPredicate.blockState(Blocks.CAMPFIRE, StatePropertiesPredicate.Builder.properties().hasProperty(CampfireBlock.LIT, true).build()), 2);
crucibleHeatSource(writer, "lit_soul_campfire", BlockPredicate.blockState(Blocks.SOUL_CAMPFIRE, StatePropertiesPredicate.Builder.properties().hasProperty(CampfireBlock.LIT, true).build()), 2);
crucibleHeatSource(writer, "lit_campfire", BlockPredicate.blockState(Blocks.CAMPFIRE, StatePropertiesPredicate.Builder.properties().hasProperty(CampfireBlock.LIT, true).build().get()), 2);
crucibleHeatSource(writer, "lit_soul_campfire", BlockPredicate.blockState(Blocks.SOUL_CAMPFIRE, StatePropertiesPredicate.Builder.properties().hasProperty(CampfireBlock.LIT, true).build().get()), 2);
}
private static void crucibleHeatSource(Consumer<FinishedRecipe> writer, Block block, int heatValue) {
private static void crucibleHeatSource(RecipeOutput writer, Block block, int heatValue) {
crucibleHeatSource(writer, BuiltInRegistries.BLOCK.getKey(block).getPath(), BlockPredicate.singleBlock(block), heatValue);
}
private static void crucibleHeatSource(Consumer<FinishedRecipe> writer, String name, BlockPredicate blockPredicate, int heatValue) {
writer.accept(new FinishedCrucibleHeatRecipe(new ResourceLocation(ExDeorum.ID, "crucible_heat_source/" + name), blockPredicate, heatValue));
private static void crucibleHeatSource(RecipeOutput writer, String name, BlockPredicate blockPredicate, int heatValue) {
writer.accept(new ResourceLocation(ExDeorum.ID, "crucible_heat_source/" + name), new CrucibleHeatRecipe(blockPredicate, heatValue), null);
}
private static void barrelCompostRecipes(Consumer<FinishedRecipe> writer) {
private static void barrelCompostRecipes(RecipeOutput writer) {
// plants
barrelCompost(writer, "saplings", ingredient(ItemTags.SAPLINGS), 125);
barrelCompost(writer, "leaves", ingredient(ItemTags.LEAVES), 125);
@ -553,7 +543,7 @@ public class Recipes {
barrelCompost(writer, "lily_pad", ingredient(Items.LILY_PAD), 100);
barrelCompost(writer, "sugar_cane", ingredient(Items.SUGAR_CANE), 80);
barrelCompost(writer, "vine", ingredient(Items.VINE), 100);
barrelCompost(writer, "grass", ingredient(Items.GRASS, Items.FERN), 100);
barrelCompost(writer, "grass", ingredient(Items.SHORT_GRASS, Items.FERN), 100);
barrelCompost(writer, "tall_grass", ingredient(Items.TALL_GRASS, Items.LARGE_FERN), 150);
barrelCompost(writer, "seagrass", ingredient(Items.SEAGRASS), 80);
barrelCompost(writer, "nether_wart", ingredient(Items.NETHER_WART), 100);
@ -614,16 +604,16 @@ public class Recipes {
barrelCompost(writer, "golden_apples", ingredient(Items.GOLDEN_APPLE, Items.ENCHANTED_GOLDEN_APPLE), 1000);
}
private static void barrelCompost(Consumer<FinishedRecipe> writer, String id, Ingredient ingredient, int volume) {
writer.accept(new FinishedBarrelCompostRecipe(new ResourceLocation(ExDeorum.ID, "barrel_compost/" + id), ingredient, volume));
private static void barrelCompost(RecipeOutput writer, String id, Ingredient ingredient, int volume) {
writer.accept(new ResourceLocation(ExDeorum.ID, "barrel_compost/" + id), new BarrelCompostRecipe(ingredient, volume), null);
}
private static void barrelMixingRecipes(Consumer<FinishedRecipe> writer) {
private static void barrelMixingRecipes(RecipeOutput writer) {
// water
barrelMixing(writer, ingredient(EItems.DUST.get()), Fluids.WATER, Items.CLAY);
barrelMixing(writer, ingredient(Items.MILK_BUCKET), Fluids.WATER, Items.SLIME_BLOCK);
barrelMixing(writer, "_from_porcelain_bucket", ingredient(EItems.PORCELAIN_MILK_BUCKET.get()), Fluids.WATER, Items.SLIME_BLOCK);
barrelFluidMixing(writer, Fluids.WATER, ForgeMod.MILK.get(), Items.SLIME_BLOCK, true);
barrelFluidMixing(writer, Fluids.WATER, NeoForgeMod.MILK.get(), Items.SLIME_BLOCK, true);
barrelMixing(writer, ingredient(Items.SNOWBALL), Fluids.WATER, Items.ICE);
barrelFluidMixing(writer, Fluids.WATER, Fluids.LAVA, Items.STONE, false);
// lava
@ -637,20 +627,20 @@ public class Recipes {
barrelMixing(writer, ingredient(Items.SAND), EFluids.WITCH_WATER.get(), Items.SOUL_SAND);
}
private static void barrelMixing(Consumer<FinishedRecipe> writer, Ingredient ingredient, Fluid fluidType, Item result) {
private static void barrelMixing(RecipeOutput writer, Ingredient ingredient, Fluid fluidType, Item result) {
barrelMixing(writer, "", ingredient, fluidType, result);
}
private static void barrelMixing(Consumer<FinishedRecipe> writer, String suffix, Ingredient ingredient, Fluid fluidType, Item result) {
writer.accept(new FinishedBarrelMixingRecipe(new ResourceLocation(ExDeorum.ID, "barrel_mixing/" + path(result) + suffix), ingredient, fluidType, 1000, result));
private static void barrelMixing(RecipeOutput writer, String suffix, Ingredient ingredient, Fluid fluidType, Item result) {
writer.accept(modLoc("barrel_mixing/" + path(result) + suffix), new BarrelMixingRecipe(ingredient, fluidType, 1000, result), null);
}
private static void barrelFluidMixing(Consumer<FinishedRecipe> writer, Fluid base, Fluid additive, Item result, boolean consumesAdditive) {
writer.accept(new FinishedBarrelFluidMixingRecipe(new ResourceLocation(ExDeorum.ID, "barrel_fluid_mixing/" + path(result)), base, 1000, additive, result, consumesAdditive));
private static void barrelFluidMixing(RecipeOutput writer, Fluid base, Fluid additive, Item result, boolean consumesAdditive) {
writer.accept(modLoc("barrel_fluid_mixing/" + path(result)), new BarrelFluidMixingRecipe(base, 1000, additive, result, consumesAdditive), null);
}
private static void fluidTransformationRecipes(Consumer<FinishedRecipe> writer) {
writer.accept(new FinishedFluidTransformationRecipe(modLoc("barrel_fluid_transformation/witch_water"), Fluids.WATER, EFluids.WITCH_WATER.get(), 0x2B1057, BlockPredicate.singleBlock(Blocks.MYCELIUM), WeightedList.<BlockState>builder().add(50, Blocks.RED_MUSHROOM.defaultBlockState()).add(50, Blocks.BROWN_MUSHROOM.defaultBlockState()).build(), 1700));
private static void fluidTransformationRecipes(RecipeOutput writer) {
writer.accept(modLoc("barrel_fluid_transformation/witch_water"), new FluidTransformationRecipe(Fluids.WATER, EFluids.WITCH_WATER.get(), 0x2B1057, BlockPredicate.singleBlock(Blocks.MYCELIUM), WeightedList.<BlockState>builder().add(50, Blocks.RED_MUSHROOM.defaultBlockState()).add(50, Blocks.BROWN_MUSHROOM.defaultBlockState()).build(), 1700), null);
}
static ResourceLocation modLoc(String path) {

View File

@ -35,41 +35,49 @@ import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.GameRules;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.Heightmap;
import net.minecraft.world.level.levelgen.XoroshiroRandomSource;
import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.ClientChatEvent;
import net.minecraftforge.common.ForgeMod;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.AddReloadListenerEvent;
import net.minecraftforge.event.OnDatapackSyncEvent;
import net.minecraftforge.event.TickEvent;
import net.minecraftforge.event.entity.player.PlayerEvent;
import net.minecraftforge.event.level.LevelEvent;
import net.minecraftforge.event.server.ServerStoppingEvent;
import net.minecraftforge.fluids.FluidInteractionRegistry;
import net.minecraftforge.fml.DistExecutor;
import net.minecraftforge.fml.InterModComms;
import net.minecraftforge.fml.ModList;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
import net.minecraftforge.fml.event.lifecycle.InterModEnqueueEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import net.minecraftforge.fml.loading.FMLEnvironment;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.bus.api.IEventBus;
import net.neoforged.fml.DistExecutor;
import net.neoforged.fml.InterModComms;
import net.neoforged.fml.ModList;
import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent;
import net.neoforged.fml.event.lifecycle.InterModEnqueueEvent;
import net.neoforged.fml.loading.FMLEnvironment;
import net.neoforged.neoforge.capabilities.Capabilities;
import net.neoforged.neoforge.capabilities.RegisterCapabilitiesEvent;
import net.neoforged.neoforge.client.event.ClientChatEvent;
import net.neoforged.neoforge.common.NeoForge;
import net.neoforged.neoforge.common.NeoForgeMod;
import net.neoforged.neoforge.event.AddReloadListenerEvent;
import net.neoforged.neoforge.event.OnDatapackSyncEvent;
import net.neoforged.neoforge.event.TickEvent;
import net.neoforged.neoforge.event.entity.player.PlayerEvent;
import net.neoforged.neoforge.event.level.LevelEvent;
import net.neoforged.neoforge.event.server.ServerStoppingEvent;
import net.neoforged.neoforge.fluids.FluidInteractionRegistry;
import net.neoforged.neoforge.fluids.capability.wrappers.FluidBucketWrapper;
import net.neoforged.neoforge.network.event.RegisterPayloadHandlerEvent;
import net.neoforged.neoforge.network.registration.IPayloadRegistrar;
import thedarkcolour.exdeorum.ExDeorum;
import thedarkcolour.exdeorum.blockentity.helper.ItemHelper;
import thedarkcolour.exdeorum.client.CompostColors;
import thedarkcolour.exdeorum.compat.ModIds;
import thedarkcolour.exdeorum.compat.top.ExDeorumTopCompat;
import thedarkcolour.exdeorum.config.EConfig;
import thedarkcolour.exdeorum.item.PorcelainBucket;
import thedarkcolour.exdeorum.item.WateringCanItem;
import thedarkcolour.exdeorum.material.BarrelMaterial;
import thedarkcolour.exdeorum.network.ClientMessageHandler;
import thedarkcolour.exdeorum.network.MenuPropertyMessage;
import thedarkcolour.exdeorum.network.NetworkHandler;
import thedarkcolour.exdeorum.network.VisualUpdateTracker;
import thedarkcolour.exdeorum.recipe.RecipeUtil;
import thedarkcolour.exdeorum.registry.EBlockEntities;
import thedarkcolour.exdeorum.registry.EFluids;
import thedarkcolour.exdeorum.registry.EItems;
import thedarkcolour.exdeorum.tag.EBiomeTags;
@ -81,9 +89,8 @@ import java.util.Set;
import java.util.UUID;
public final class EventHandler {
public static void register() {
var fmlBus = MinecraftForge.EVENT_BUS;
var modBus = FMLJavaModLoadingContext.get().getModEventBus();
public static void register(IEventBus modBus) {
var fmlBus = NeoForge.EVENT_BUS;
fmlBus.addListener(EventHandler::onPlayerLogin);
fmlBus.addListener(EventHandler::onDataSynced);
@ -91,8 +98,10 @@ public final class EventHandler {
fmlBus.addListener(EventHandler::createSpawnTree);
modBus.addListener(EventHandler::interModEnqueue);
modBus.addListener(EventHandler::onCommonSetup);
modBus.addListener(EventHandler::registerPayloadHandler);
fmlBus.addListener(EventHandler::serverShutdown);
fmlBus.addListener(EventHandler::serverTick);
fmlBus.addListener(EventHandler::registerCapabilities);
if (ExDeorum.DEBUG) {
fmlBus.addListener(EventHandler::handleDebugCommands);
@ -147,10 +156,10 @@ public final class EventHandler {
for (var entry : EBiomeTags.TREE_TAGS.entrySet()) {
if (biome.is(entry.getKey())) {
var optional = entry.getValue().getHolder();
var optional = entry.getValue();
if (optional.isPresent()) {
holder = (optional.get());
if (optional.isBound()) {
holder = optional;
break;
}
}
@ -171,14 +180,14 @@ public final class EventHandler {
private static void onCommonSetup(FMLCommonSetupEvent event) {
event.enqueueWork(() -> {
FluidInteractionRegistry.addInteraction(ForgeMod.LAVA_TYPE.get(), new FluidInteractionRegistry.InteractionInformation(
FluidInteractionRegistry.addInteraction(NeoForgeMod.LAVA_TYPE.value(), new FluidInteractionRegistry.InteractionInformation(
EFluids.WITCH_WATER_TYPE.get(),
fluidState -> fluidState.isSource() ? Blocks.OBSIDIAN.defaultBlockState() : (EConfig.SERVER.witchWaterNetherrackGenerator.get() ? Blocks.NETHERRACK.defaultBlockState() : Blocks.COBBLESTONE.defaultBlockState())
));
var dirtVariants = new BlockState[]{Blocks.DIRT.defaultBlockState(), Blocks.PODZOL.defaultBlockState(), Blocks.COARSE_DIRT.defaultBlockState()};
var rng = RandomSource.create();
FluidInteractionRegistry.addInteraction(EFluids.WITCH_WATER_TYPE.get(), new FluidInteractionRegistry.InteractionInformation(
(level, pos, relative, state) -> level.getFluidState(relative).getFluidType() == ForgeMod.WATER_TYPE.get() && EConfig.SERVER.witchWaterDirtGenerator.get(),
(level, pos, relative, state) -> level.getFluidState(relative).getFluidType() == NeoForgeMod.WATER_TYPE.value() && EConfig.SERVER.witchWaterDirtGenerator.get(),
fluidState -> Util.getRandom(dirtVariants, rng)
));
@ -186,11 +195,16 @@ public final class EventHandler {
});
}
private static void registerPayloadHandler(RegisterPayloadHandlerEvent event) {
NetworkHandler.register(event.registrar(ExDeorum.ID));
}
private static void onDataSynced(OnDatapackSyncEvent event) {
UUID excludedUUID = null;
if (FMLEnvironment.dist == Dist.CLIENT) {
// since event code is turned into ASM, we need this to prevent ASM trying to load the LocalPlayer class
// todo check if the IF statement can work here
Player player = DistExecutor.unsafeCallWhenOn(Dist.CLIENT, () -> ClientsideCode::getLocalPlayer);
if (player == null) {
return;
@ -219,7 +233,7 @@ public final class EventHandler {
// tries to account for other SkyBlock generator mods like SkyBlockBuilder
if (generator instanceof VoidChunkGenerator || generator.getClass().getName().toLowerCase(Locale.ROOT).contains("skyblock")) {
NetworkHandler.sendVoidWorld(player);
var advancement = player.server.getAdvancements().getAdvancement(new ResourceLocation(ExDeorum.ID, "core/root"));
var advancement = player.server.getAdvancements().get(new ResourceLocation(ExDeorum.ID, "core/root"));
if (advancement != null) {
if (!player.getAdvancements().getOrStartProgress(advancement).isDone()) {
@ -262,4 +276,30 @@ public final class EventHandler {
VisualUpdateTracker.syncVisualUpdates();
}
}
private static void registerCapabilities(RegisterCapabilitiesEvent event) {
event.registerBlockEntity(Capabilities.ItemHandler.BLOCK, EBlockEntities.BARREL.get(), (barrel, direction) -> barrel.getItemHandler());
event.registerBlockEntity(Capabilities.FluidHandler.BLOCK, EBlockEntities.BARREL.get(), (barrel, direction) -> barrel.getTank());
event.registerBlockEntity(Capabilities.ItemHandler.BLOCK, EBlockEntities.MECHANICAL_SIEVE.get(), (sieve, direction) -> sieve.getItemHandler());
event.registerBlockEntity(Capabilities.EnergyStorage.BLOCK, EBlockEntities.MECHANICAL_SIEVE.get(), (sieve, direction) -> sieve.getEnergyStorage());
event.registerBlockEntity(Capabilities.ItemHandler.BLOCK, EBlockEntities.MECHANICAL_HAMMER.get(), (hammer, direction) -> hammer.getItemHandler());
event.registerBlockEntity(Capabilities.EnergyStorage.BLOCK, EBlockEntities.MECHANICAL_HAMMER.get(), (hammer, direction) -> hammer.getEnergyStorage());
event.registerBlockEntity(Capabilities.ItemHandler.BLOCK, EBlockEntities.LAVA_CRUCIBLE.get(), (hammer, direction) -> hammer.getItem());
event.registerBlockEntity(Capabilities.FluidHandler.BLOCK, EBlockEntities.LAVA_CRUCIBLE.get(), (hammer, direction) -> hammer.getTank());
event.registerBlockEntity(Capabilities.ItemHandler.BLOCK, EBlockEntities.WATER_CRUCIBLE.get(), (hammer, direction) -> hammer.getItem());
event.registerBlockEntity(Capabilities.FluidHandler.BLOCK, EBlockEntities.WATER_CRUCIBLE.get(), (hammer, direction) -> hammer.getTank());
event.registerItem(Capabilities.FluidHandler.ITEM, (stack, ctx) -> new PorcelainBucket.ItemHandler(stack),
EItems.PORCELAIN_BUCKET,
EItems.PORCELAIN_WATER_BUCKET,
EItems.PORCELAIN_LAVA_BUCKET,
EItems.PORCELAIN_MILK_BUCKET,
EItems.PORCELAIN_WITCH_WATER_BUCKET);
event.registerItem(Capabilities.FluidHandler.ITEM, (stack, ctx) -> new FluidBucketWrapper(stack), EItems.WITCH_WATER_BUCKET);
event.registerItem(Capabilities.FluidHandler.ITEM, (stack, ctx) -> new WateringCanItem.FluidHandler(stack));
}
}

View File

@ -22,10 +22,10 @@ import net.minecraft.client.Camera;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.sounds.SoundEvents;
import net.minecraftforge.client.extensions.common.IClientFluidTypeExtensions;
import net.minecraftforge.common.SoundActions;
import net.minecraftforge.fluids.FluidType;
import net.minecraftforge.fluids.ForgeFlowingFluid;
import net.neoforged.neoforge.client.extensions.common.IClientFluidTypeExtensions;
import net.neoforged.neoforge.common.SoundActions;
import net.neoforged.neoforge.fluids.BaseFlowingFluid;
import net.neoforged.neoforge.fluids.FluidType;
import org.jetbrains.annotations.NotNull;
import org.joml.Vector3f;
import thedarkcolour.exdeorum.ExDeorum;
@ -40,8 +40,8 @@ public class WitchWaterFluid extends FluidType {
private static final ResourceLocation FLOWING_TEXTURE = new ResourceLocation(ExDeorum.ID, "block/witch_water_flowing");
private static final ResourceLocation OVERLAY_TEXTURE = new ResourceLocation("block/water_overlay");
public static ForgeFlowingFluid.Properties properties() {
return new ForgeFlowingFluid.Properties(EFluids.WITCH_WATER_TYPE, EFluids.WITCH_WATER, EFluids.WITCH_WATER_FLOWING).block(EBlocks.WITCH_WATER).bucket(EItems.WITCH_WATER_BUCKET);
public static BaseFlowingFluid.Properties properties() {
return new BaseFlowingFluid.Properties(EFluids.WITCH_WATER_TYPE, EFluids.WITCH_WATER, EFluids.WITCH_WATER_FLOWING).block(EBlocks.WITCH_WATER).bucket(EItems.WITCH_WATER_BUCKET);
}
public WitchWaterFluid() {

View File

@ -32,7 +32,7 @@ import net.minecraft.world.item.enchantment.Enchantment;
import net.minecraft.world.item.enchantment.Enchantments;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.common.Tags;
import net.neoforged.neoforge.common.Tags;
import thedarkcolour.exdeorum.registry.EItems;
// Silk worms have a 1 in 100 chance to drop from regular leaves, 1 in 15 if the block is infested.

View File

@ -19,19 +19,28 @@
package thedarkcolour.exdeorum.item;
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
import net.minecraft.client.Minecraft;
import net.minecraft.tags.BlockTags;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.DiggerItem;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Tier;
import net.minecraft.world.item.crafting.RecipeHolder;
import net.minecraft.world.item.crafting.RecipeType;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.common.util.Lazy;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.fml.loading.FMLEnvironment;
import net.neoforged.neoforge.common.TierSortingRegistry;
import net.neoforged.neoforge.common.util.Lazy;
import net.neoforged.neoforge.server.ServerLifecycleHooks;
import org.jetbrains.annotations.Nullable;
import thedarkcolour.exdeorum.recipe.RecipeUtil;
import thedarkcolour.exdeorum.recipe.hammer.HammerRecipe;
import thedarkcolour.exdeorum.registry.EItems;
import thedarkcolour.exdeorum.registry.ERecipeTypes;
import java.util.Collection;
import java.util.Objects;
import java.util.Set;
public class HammerItem extends DiggerItem {
@ -42,11 +51,17 @@ public class HammerItem extends DiggerItem {
}
public static Set<Block> computeValidBlocks() {
var hammerRecipes = RecipeUtil.getCachedHammerRecipes();
Collection<RecipeHolder<HammerRecipe>> hammerRecipes;
// todo test that this works properly
if (FMLEnvironment.dist == Dist.CLIENT) {
hammerRecipes = Objects.requireNonNull(Minecraft.getInstance().level).getRecipeManager().byType(ERecipeTypes.HAMMER.get()).values();
} else {
hammerRecipes = ServerLifecycleHooks.getCurrentServer().getRecipeManager().byType(ERecipeTypes.HAMMER.get()).values();
}
var validBlocks = new ObjectOpenHashSet<Block>(hammerRecipes.size());
for (var recipe : hammerRecipes) {
for (var item : recipe.getIngredient().getItems()) {
for (var item : recipe.value().getIngredient().getItems()) {
if (item.getItem() instanceof BlockItem blockItem) {
validBlocks.add(blockItem.getBlock());
}
@ -71,10 +86,11 @@ public class HammerItem extends DiggerItem {
@Override
public boolean isCorrectToolForDrops(BlockState state) {
if (net.minecraftforge.common.TierSortingRegistry.isTierSorted(getTier())) {
return net.minecraftforge.common.TierSortingRegistry.isCorrectTierForDrops(getTier(), state) && getValidBlocks().contains(state.getBlock());
var tier = getTier();
if (TierSortingRegistry.isTierSorted(tier)) {
return TierSortingRegistry.isCorrectTierForDrops(tier, state) && getValidBlocks().contains(state.getBlock());
}
int i = this.getTier().getLevel();
int i = tier.getLevel();
if (i < 3 && state.is(BlockTags.NEEDS_DIAMOND_TOOL)) {
return false;
} else if (i < 2 && state.is(BlockTags.NEEDS_IRON_TOOL)) {
@ -87,7 +103,7 @@ public class HammerItem extends DiggerItem {
// FORGE START
@Override
public boolean isCorrectToolForDrops(ItemStack stack, BlockState state) {
return getValidBlocks().contains(state.getBlock()) && net.minecraftforge.common.TierSortingRegistry.isCorrectTierForDrops(getTier(), state);
return getValidBlocks().contains(state.getBlock()) && TierSortingRegistry.isCorrectTierForDrops(getTier(), state);
}
@Override

View File

@ -20,7 +20,7 @@ package thedarkcolour.exdeorum.item;
import net.minecraft.tags.BlockTags;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.common.Tags;
import net.neoforged.neoforge.common.Tags;
import java.util.function.Supplier;

View File

@ -20,9 +20,7 @@ package thedarkcolour.exdeorum.item;
import net.minecraft.advancements.CriteriaTriggers;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
@ -49,14 +47,13 @@ import net.minecraft.world.level.material.Fluid;
import net.minecraft.world.level.material.Fluids;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.HitResult;
import net.minecraftforge.common.ForgeMod;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.ForgeCapabilities;
import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandlerItem;
import net.neoforged.neoforge.common.NeoForgeMod;
import net.neoforged.neoforge.common.SoundActions;
import net.neoforged.neoforge.event.EventHooks;
import net.neoforged.neoforge.fluids.FluidStack;
import net.neoforged.neoforge.fluids.FluidUtil;
import net.neoforged.neoforge.fluids.capability.IFluidHandler;
import net.neoforged.neoforge.fluids.capability.IFluidHandlerItem;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import thedarkcolour.exdeorum.registry.EFluids;
@ -94,7 +91,7 @@ public class PorcelainBucket extends Item {
public InteractionResultHolder<ItemStack> use(Level level, Player player, InteractionHand pHand) {
var stack = player.getItemInHand(pHand);
var hitResult = getPlayerPOVHitResult(level, player, this.fluid.get() == Fluids.EMPTY ? ClipContext.Fluid.SOURCE_ONLY : ClipContext.Fluid.NONE);
var ret = net.minecraftforge.event.ForgeEventFactory.onBucketUse(player, level, stack, hitResult);
var ret = EventHooks.onBucketUse(player, level, stack, hitResult);
if (ret != null) return ret;
if (hitResult.getType() == HitResult.Type.MISS) {
return InteractionResultHolder.pass(stack);
@ -109,13 +106,13 @@ public class PorcelainBucket extends Item {
var state = level.getBlockState(pos);
var fluidType = state.getFluidState().getFluidType();
if (fluidType == ForgeMod.WATER_TYPE.get() || fluidType == ForgeMod.LAVA_TYPE.get() || fluidType == EFluids.WITCH_WATER_TYPE.get()) {
if (fluidType == NeoForgeMod.WATER_TYPE.value() || fluidType == NeoForgeMod.LAVA_TYPE.value() || fluidType == EFluids.WITCH_WATER_TYPE.value()) {
if (state.getBlock() instanceof BucketPickup pickup) {
var result = pickup.pickupBlock(level, pos, state);
var result = pickup.pickupBlock(player, level, pos, state);
if (fluidType == ForgeMod.WATER_TYPE.get()) {
if (fluidType == NeoForgeMod.WATER_TYPE.value()) {
result = new ItemStack(EItems.PORCELAIN_WATER_BUCKET.get());
} else if (fluidType == ForgeMod.LAVA_TYPE.get()) {
} else if (fluidType == NeoForgeMod.LAVA_TYPE.value()) {
result = new ItemStack(EItems.PORCELAIN_LAVA_BUCKET.get());
} else {
result = new ItemStack(EItems.PORCELAIN_WITCH_WATER_BUCKET.get());
@ -138,7 +135,7 @@ public class PorcelainBucket extends Item {
return InteractionResultHolder.fail(stack);
} else {
var state = level.getBlockState(pos);
var placePos = canBlockContainFluid(level, pos, state) ? pos : relative;
var placePos = canBlockContainFluid(player, level, pos, state) ? pos : relative;
if (emptyContents(player, level, placePos, hitResult, stack)) {
if (player instanceof ServerPlayer serverPlayer) {
@ -176,8 +173,8 @@ public class PorcelainBucket extends Item {
var state = level.getBlockState(pos);
var block = state.getBlock();
var replacing = state.canBeReplaced(this.fluid.get());
var canPlaceAtPos = state.isAir() || replacing || block instanceof LiquidBlockContainer liquidContainer && liquidContainer.canPlaceLiquid(level, pos, state, this.fluid.get());
var containedFluidStack = java.util.Optional.ofNullable(container).flatMap(net.minecraftforge.fluids.FluidUtil::getFluidContained);
var canPlaceAtPos = state.isAir() || replacing || block instanceof LiquidBlockContainer liquidContainer && liquidContainer.canPlaceLiquid(player, level, pos, state, this.fluid.get());
var containedFluidStack = java.util.Optional.ofNullable(container).flatMap(FluidUtil::getFluidContained);
if (!canPlaceAtPos) {
return hitResult != null && this.emptyContents(player, level, hitResult.getBlockPos().relative(hitResult.getDirection()), null, container);
@ -195,7 +192,7 @@ public class PorcelainBucket extends Item {
}
return true;
} else if (block instanceof LiquidBlockContainer liquidContainer && liquidContainer.canPlaceLiquid(level, pos, state, this.fluid.get())) {
} else if (block instanceof LiquidBlockContainer liquidContainer && liquidContainer.canPlaceLiquid(player, level, pos, state, this.fluid.get())) {
liquidContainer.placeLiquid(level, pos, state, ((FlowingFluid)this.fluid.get()).getSource(false));
playEmptySound(player, level, pos);
return true;
@ -215,7 +212,7 @@ public class PorcelainBucket extends Item {
}
protected void playEmptySound(@Nullable Player pPlayer, LevelAccessor pLevel, BlockPos pPos) {
var sound = this.fluid.get().getFluidType().getSound(pPlayer, pLevel, pPos, net.minecraftforge.common.SoundActions.BUCKET_EMPTY);
var sound = this.fluid.get().getFluidType().getSound(pPlayer, pLevel, pPos, SoundActions.BUCKET_EMPTY);
if (sound == null) {
sound = this.fluid.get().is(FluidTags.LAVA) ? SoundEvents.BUCKET_EMPTY_LAVA : SoundEvents.BUCKET_EMPTY;
}
@ -223,20 +220,14 @@ public class PorcelainBucket extends Item {
pLevel.gameEvent(pPlayer, GameEvent.FLUID_PLACE, pPos);
}
protected boolean canBlockContainFluid(Level level, BlockPos pos, BlockState state) {
return state.getBlock() instanceof LiquidBlockContainer block && block.canPlaceLiquid(level, pos, state, this.fluid.get());
protected boolean canBlockContainFluid(Player player, Level level, BlockPos pos, BlockState state) {
return state.getBlock() instanceof LiquidBlockContainer block && block.canPlaceLiquid(player, level, pos, state, this.fluid.get());
}
@Override
public @Nullable ICapabilityProvider initCapabilities(ItemStack stack, @Nullable CompoundTag nbt) {
return new PorcelainBucket.CapabilityProvider(stack);
}
static class CapabilityProvider implements ICapabilityProvider, IFluidHandlerItem {
private final LazyOptional<IFluidHandlerItem> holder = LazyOptional.of(() -> this);
public static class ItemHandler implements IFluidHandlerItem {
private ItemStack container;
public CapabilityProvider(ItemStack container) {
public ItemHandler(ItemStack container) {
this.container = container;
}
@ -246,12 +237,6 @@ public class PorcelainBucket extends Item {
return this.container;
}
@Override
@NotNull
public <T> LazyOptional<T> getCapability(@NotNull Capability<T> cap, @Nullable Direction side) {
return ForgeCapabilities.FLUID_HANDLER_ITEM.orEmpty(cap, this.holder);
}
@Override
public int getTanks() {
return 1;
@ -270,7 +255,7 @@ public class PorcelainBucket extends Item {
@Override
public boolean isFluidValid(int tank, @NotNull FluidStack stack) {
return stack.getFluid() == Fluids.LAVA || stack.getFluid() == Fluids.WATER || stack.getFluid() == EFluids.WITCH_WATER.get() || (ForgeMod.MILK.isPresent() && stack.getFluid() == ForgeMod.MILK.get());
return stack.getFluid() == Fluids.LAVA || stack.getFluid() == Fluids.WATER || stack.getFluid() == EFluids.WITCH_WATER.get() || (NeoForgeMod.MILK.isBound() && stack.getFluid() == NeoForgeMod.MILK.value());
}
@Override
@ -328,8 +313,8 @@ public class PorcelainBucket extends Item {
return new FluidStack(Fluids.WATER, 1000);
} else if (item == EItems.PORCELAIN_WITCH_WATER_BUCKET.get()) {
return new FluidStack(EFluids.WITCH_WATER.get(), 1000);
} else if (item == EItems.PORCELAIN_MILK_BUCKET.get() && ForgeMod.MILK.isPresent()) {
return new FluidStack(ForgeMod.MILK.get(), 1000);
} else if (item == EItems.PORCELAIN_MILK_BUCKET.get() && NeoForgeMod.MILK.isBound()) {
return new FluidStack(NeoForgeMod.MILK.get(), 1000);
}
return FluidStack.EMPTY;
@ -344,7 +329,7 @@ public class PorcelainBucket extends Item {
this.container = new ItemStack(EItems.PORCELAIN_WATER_BUCKET.get());
} else if (fluidStack.getFluid() == EFluids.WITCH_WATER.get()) {
this.container = new ItemStack(EItems.PORCELAIN_WITCH_WATER_BUCKET.get());
} else if (ForgeMod.MILK.isPresent() && fluidStack.getFluid() == ForgeMod.MILK.get()) {
} else if (NeoForgeMod.MILK.isBound() && fluidStack.getFluid() == NeoForgeMod.MILK.get()) {
this.container = new ItemStack(EItems.PORCELAIN_MILK_BUCKET.get());
}
}

View File

@ -18,17 +18,11 @@
package thedarkcolour.exdeorum.item;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.MilkBucketItem;
import net.minecraft.world.level.Level;
import net.minecraftforge.common.ForgeMod;
import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.fluids.FluidStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import thedarkcolour.exdeorum.registry.EItems;
public class PorcelainMilkBucket extends MilkBucketItem {
@ -46,20 +40,4 @@ public class PorcelainMilkBucket extends MilkBucketItem {
return stack;
}
}
@Override
public @Nullable ICapabilityProvider initCapabilities(ItemStack stack, @Nullable CompoundTag nbt) {
return new PorcelainBucket.CapabilityProvider(stack);
}
private static class CapabilityProvider extends PorcelainBucket.CapabilityProvider {
public CapabilityProvider(@NotNull ItemStack container) {
super(container);
}
@Override
public boolean isFluidValid(int tank, @NotNull FluidStack stack) {
return ForgeMod.MILK.isPresent();
}
}
}

View File

@ -25,7 +25,6 @@ import net.minecraft.client.player.LocalPlayer;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvents;
@ -51,15 +50,13 @@ import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.Fluids;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.HitResult;
import net.minecraftforge.client.extensions.common.IClientItemExtensions;
import net.minecraftforge.common.ForgeMod;
import net.minecraftforge.common.capabilities.ForgeCapabilities;
import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.common.util.FakePlayer;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.fluids.capability.templates.FluidHandlerItemStack;
import org.jetbrains.annotations.NotNull;
import net.neoforged.neoforge.capabilities.Capabilities;
import net.neoforged.neoforge.client.extensions.common.IClientItemExtensions;
import net.neoforged.neoforge.common.NeoForgeMod;
import net.neoforged.neoforge.common.util.FakePlayer;
import net.neoforged.neoforge.fluids.FluidStack;
import net.neoforged.neoforge.fluids.capability.IFluidHandler;
import net.neoforged.neoforge.fluids.capability.templates.FluidHandlerItemStack;
import org.jetbrains.annotations.Nullable;
import thedarkcolour.exdeorum.blockentity.BarrelBlockEntity;
import thedarkcolour.exdeorum.data.TranslationKeys;
@ -97,13 +94,21 @@ public class WateringCanItem extends Item {
public static ItemStack getFull(Supplier<? extends Item> wateringCan) {
var stack = new ItemStack(wateringCan.get());
stack.getCapability(ForgeCapabilities.FLUID_HANDLER_ITEM).ifPresent(handler -> handler.fill(new FluidStack(Fluids.WATER, Integer.MAX_VALUE), IFluidHandler.FluidAction.EXECUTE));
var fluidHandler = stack.getCapability(Capabilities.FluidHandler.ITEM);
if (fluidHandler != null) {
fluidHandler.fill(new FluidStack(Fluids.WATER, Integer.MAX_VALUE), IFluidHandler.FluidAction.EXECUTE);
}
return stack;
}
@Override
public boolean isBarVisible(ItemStack stack) {
return this.renewing ? stack.getCapability(ForgeCapabilities.FLUID_HANDLER_ITEM).map(handler -> handler.getFluidInTank(0).getAmount() < this.capacity).orElse(true) : true;
if (this.renewing) {
var fluidHandler = stack.getCapability(Capabilities.FluidHandler.ITEM);
return fluidHandler == null || fluidHandler.getFluidInTank(0).getAmount() < this.capacity;
} else {
return false;
}
}
@Override
@ -113,9 +118,12 @@ public class WateringCanItem extends Item {
@Override
public int getBarWidth(ItemStack stack) {
return stack.getCapability(ForgeCapabilities.FLUID_HANDLER_ITEM).map(fluidHandler -> {
return Math.round((float) fluidHandler.getFluidInTank(0).getAmount() * 13.0F / (float) this.capacity);
}).orElse(0);
var fluidHandler = stack.getCapability(Capabilities.FluidHandler.ITEM);
if (fluidHandler != null) {
return Math.round((float) fluidHandler.getFluidInTank(0).getAmount() * 13f / (float) this.capacity);
} else {
return 0;
}
}
@Override
@ -130,16 +138,18 @@ public class WateringCanItem extends Item {
@Override
public void appendHoverText(ItemStack stack, @Nullable Level pLevel, List<Component> tooltip, TooltipFlag pIsAdvanced) {
stack.getCapability(ForgeCapabilities.FLUID_HANDLER_ITEM).ifPresent(fluidHandler -> {
var fluidHandler = stack.getCapability(Capabilities.FluidHandler.ITEM);
if (fluidHandler != null) {
// use the block name which is guaranteed to have a vanilla translation
tooltip.add(Component.translatable("block.minecraft.water").append(Component.translatable(TranslationKeys.FRACTION_DISPLAY, fluidHandler.getFluidInTank(0).getAmount(), this.capacity)).withStyle(ChatFormatting.GRAY));
});
}
}
@Override
public InteractionResultHolder<ItemStack> use(Level level, Player player, InteractionHand hand) {
var itemInHand = player.getItemInHand(hand);
return itemInHand.getCapability(ForgeCapabilities.FLUID_HANDLER_ITEM).map(fluidHandler -> {
var fluidHandler = itemInHand.getCapability(Capabilities.FluidHandler.ITEM);
if (fluidHandler != null) {
if (fluidHandler.getFluidInTank(0).getAmount() < this.capacity) {
var hitResult = getPlayerPOVHitResult(level, player, ClipContext.Fluid.SOURCE_ONLY);
@ -150,7 +160,7 @@ public class WateringCanItem extends Item {
if (state.getFluidState().getType() == Fluids.WATER && state.getBlock() instanceof BucketPickup pickup) {
if (!level.isClientSide) {
fluidHandler.fill(new FluidStack(Fluids.WATER, 1000), IFluidHandler.FluidAction.EXECUTE);
pickup.pickupBlock(level, pos, state);
pickup.pickupBlock(player, level, pos, state);
pickup.getPickupSound(state).ifPresent(sound -> player.playSound(sound, 1.0F, 1.0F));
}
@ -170,8 +180,8 @@ public class WateringCanItem extends Item {
return InteractionResultHolder.consume(itemInHand);
}
return InteractionResultHolder.pass(itemInHand);
}).orElse(InteractionResultHolder.pass(itemInHand));
}
return InteractionResultHolder.pass(itemInHand);
}
@Override
@ -179,10 +189,11 @@ public class WateringCanItem extends Item {
var useTicks = 72000 - remainingTicks;
if (useTicks >= STARTUP_TIME || living instanceof FakePlayer) {
stack.getCapability(ForgeCapabilities.FLUID_HANDLER_ITEM).ifPresent(fluidHandler -> {
var fluidHandler = stack.getCapability(Capabilities.FluidHandler.ITEM);
if (fluidHandler != null) {
if (!fluidHandler.getFluidInTank(0).isEmpty()) {
// do watering can
var reachDist = living instanceof Player player ? player.getBlockReach() : living.getAttributeValue(ForgeMod.BLOCK_REACH.get());
var reachDist = living instanceof Player player ? player.getBlockReach() : living.getAttributeValue(NeoForgeMod.BLOCK_REACH.value());
var hit = living.pick(reachDist, 0, true);
if (hit instanceof BlockHitResult blockHit && blockHit.getType() == HitResult.Type.BLOCK) {
@ -195,7 +206,7 @@ public class WateringCanItem extends Item {
if (!this.renewing || fluidHandler.getFluidInTank(0).getAmount() != this.capacity) {
if (!(living instanceof Player player && player.getAbilities().instabuild)) {
((CapabilityProvider) fluidHandler).drain();
((FluidHandler) fluidHandler).drain();
}
}
}
@ -215,7 +226,7 @@ public class WateringCanItem extends Item {
living.stopUsingItem();
isWatering = false;
}
});
}
}
}
@ -236,7 +247,7 @@ public class WateringCanItem extends Item {
} else if (state.getBlock() instanceof SugarCaneBlock block) {
var cursor = pos.mutable();
while (level.isInWorldBounds(cursor.move(0, 1, 0)) && level.getBlockState(cursor).getBlock() == block) {
// just keep looping
// just keep looping, cursor is moved up each check
}
// randomTick only works on the top sugarcane block
var topState = level.getBlockState(cursor.move(0, -1, 0));
@ -294,19 +305,22 @@ public class WateringCanItem extends Item {
}
}
@Override
public ICapabilityProvider initCapabilities(ItemStack stack, @Nullable CompoundTag nbt) {
return new CapabilityProvider(stack, this.capacity);
}
@Override
public void initializeClient(Consumer<IClientItemExtensions> consumer) {
consumer.accept(ClientExtensions.INSTANCE);
}
private static class CapabilityProvider extends FluidHandlerItemStack {
public CapabilityProvider(@NotNull ItemStack container, int capacity) {
super(container, capacity);
public static class FluidHandler extends FluidHandlerItemStack {
public FluidHandler(ItemStack container) {
super(container, determineCapacityFromItem(container.getItem()));
}
private static int determineCapacityFromItem(Item item) {
if (item instanceof WateringCanItem wateringCan) {
return wateringCan.capacity;
} else {
throw new IllegalArgumentException("Invalid watering can");
}
}
@Override

View File

@ -18,21 +18,11 @@
package thedarkcolour.exdeorum.item;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.item.BucketItem;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.fluids.capability.wrappers.FluidBucketWrapper;
import org.jetbrains.annotations.Nullable;
import thedarkcolour.exdeorum.registry.EFluids;
public class WitchWaterBucketItem extends BucketItem {
public WitchWaterBucketItem(Properties properties) {
super(EFluids.WITCH_WATER, properties);
}
@Override
public ICapabilityProvider initCapabilities(ItemStack stack, @Nullable CompoundTag nbt) {
return new FluidBucketWrapper(stack);
}
}

View File

@ -31,8 +31,8 @@ import net.minecraft.world.level.storage.loot.LootContext;
import net.minecraft.world.level.storage.loot.LootParams;
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition;
import net.minecraftforge.common.loot.IGlobalLootModifier;
import net.minecraftforge.common.loot.LootModifier;
import net.neoforged.neoforge.common.loot.IGlobalLootModifier;
import net.neoforged.neoforge.common.loot.LootModifier;
import org.jetbrains.annotations.NotNull;
import thedarkcolour.exdeorum.recipe.RecipeUtil;
import thedarkcolour.exdeorum.recipe.crook.CrookRecipe;

View File

@ -28,8 +28,8 @@ import net.minecraft.world.item.enchantment.Enchantments;
import net.minecraft.world.level.storage.loot.LootContext;
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition;
import net.minecraftforge.common.loot.IGlobalLootModifier;
import net.minecraftforge.common.loot.LootModifier;
import net.neoforged.neoforge.common.loot.IGlobalLootModifier;
import net.neoforged.neoforge.common.loot.LootModifier;
import thedarkcolour.exdeorum.recipe.RecipeUtil;
import javax.annotation.Nonnull;

View File

@ -18,8 +18,8 @@
package thedarkcolour.exdeorum.loot;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonObject;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.storage.loot.LootContext;
@ -29,8 +29,12 @@ import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition;
import thedarkcolour.exdeorum.registry.ELootFunctions;
import java.util.List;
public class MachineLootFunction extends LootItemConditionalFunction {
protected MachineLootFunction(LootItemCondition[] conditions) {
public static final Codec<MachineLootFunction> CODEC = RecordCodecBuilder.create(instance -> commonFields(instance).apply(instance, MachineLootFunction::new));
protected MachineLootFunction(List<LootItemCondition> conditions) {
super(conditions);
}
@ -52,11 +56,4 @@ public class MachineLootFunction extends LootItemConditionalFunction {
public static LootItemConditionalFunction.Builder<?> machineLoot() {
return LootItemConditionalFunction.simpleBuilder(MachineLootFunction::new);
}
public static class LootSerializer extends LootItemConditionalFunction.Serializer<MachineLootFunction> {
@Override
public MachineLootFunction deserialize(JsonObject json, JsonDeserializationContext ctx, LootItemCondition[] conditions) {
return new MachineLootFunction(conditions);
}
}
}

View File

@ -18,17 +18,19 @@
package thedarkcolour.exdeorum.loot;
import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonObject;
import com.google.gson.JsonSerializationContext;
import net.minecraft.util.GsonHelper;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.world.level.storage.loot.LootContext;
import net.minecraft.world.level.storage.loot.providers.number.LootNumberProviderType;
import net.minecraft.world.level.storage.loot.providers.number.NumberProvider;
import net.minecraft.world.level.storage.loot.providers.number.NumberProviders;
import thedarkcolour.exdeorum.registry.ENumberProviders;
public record SummationGenerator(NumberProvider[] providers) implements NumberProvider {
import java.util.List;
public record SummationGenerator(List<NumberProvider> providers) implements NumberProvider {
public static final Codec<SummationGenerator> CODEC = RecordCodecBuilder.create(instance -> instance.group(NumberProviders.CODEC.listOf().fieldOf("values").forGetter(SummationGenerator::providers)).apply(instance, SummationGenerator::new));
@Override
public float getFloat(LootContext context) {
float sum = 0f;
@ -42,26 +44,4 @@ public record SummationGenerator(NumberProvider[] providers) implements NumberPr
public LootNumberProviderType getType() {
return ENumberProviders.SUMMATION.get();
}
public static class Serializer implements net.minecraft.world.level.storage.loot.Serializer<SummationGenerator> {
@Override
public void serialize(JsonObject json, SummationGenerator value, JsonSerializationContext ctx) {
JsonArray array = new JsonArray();
for (var provider : value.providers) {
array.add(ctx.serialize(provider, NumberProvider.class));
}
}
@Override
public SummationGenerator deserialize(JsonObject json, JsonDeserializationContext ctx) {
var valuesJson = GsonHelper.getAsJsonArray(json, "values");
NumberProvider[] providers = new NumberProvider[valuesJson.size()];
int i = 0;
for (var valueJson : valuesJson) {
providers[i++] = ctx.deserialize(valueJson, NumberProvider.class);
}
return new SummationGenerator(providers);
}
}
}

View File

@ -23,7 +23,8 @@ import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.SoundType;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraftforge.registries.RegistryObject;
import net.neoforged.neoforge.registries.DeferredBlock;
import net.neoforged.neoforge.registries.DeferredItem;
public abstract class AbstractMaterial {
// The sound this block makes (a string corresponding to a field in SoundType or a JSON object with the five sound events used to create a sound type)
@ -37,8 +38,8 @@ public abstract class AbstractMaterial {
// ID of mod that should be present
public final String requiredModId;
RegistryObject<Block> block;
RegistryObject<BlockItem> item;
DeferredBlock<Block> block;
DeferredItem<BlockItem> item;
protected AbstractMaterial(SoundType soundType, float strength, boolean needsCorrectTool, int mapColor, String requiredModId) {
this.soundType = soundType;

View File

@ -23,8 +23,8 @@ import com.google.gson.JsonPrimitive;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.block.SoundType;
import net.minecraftforge.common.util.ForgeSoundType;
import net.minecraftforge.registries.RegistryObject;
import net.neoforged.neoforge.common.util.DeferredSoundType;
import net.neoforged.neoforge.registries.DeferredHolder;
import org.jetbrains.annotations.Nullable;
import thedarkcolour.exdeorum.ExDeorum;
@ -49,7 +49,7 @@ public class MaterialParser {
if (soundTypeJson.isJsonPrimitive()) {
String soundTypeString = soundTypeJson.getAsString();
var soundType = SoundTypeResolver.VANILLA_SOUND_TYPES.get(soundTypeString);
var soundType = SoundTypeResolver.resolve(soundTypeString);
if (soundType == null) {
ExDeorum.LOGGER.error("Unknown sound type \"{}\" for material {}", soundTypeString, this.jsonPath);
@ -59,12 +59,12 @@ public class MaterialParser {
}
} else if (soundTypeJson instanceof JsonObject soundTypeObj) {
if (soundTypeObj.has("break_sound") && soundTypeObj.has("step_sound") && soundTypeObj.has("place_sound") && soundTypeObj.has("hit_sound") && soundTypeObj.has("fall_sound")) {
return new ForgeSoundType(1.0f, 1.0f,
RegistryObject.create(new ResourceLocation(soundTypeObj.get("break_sound").getAsString()), Registries.SOUND_EVENT, ExDeorum.ID),
RegistryObject.create(new ResourceLocation(soundTypeObj.get("step_sound").getAsString()), Registries.SOUND_EVENT, ExDeorum.ID),
RegistryObject.create(new ResourceLocation(soundTypeObj.get("place_sound").getAsString()), Registries.SOUND_EVENT, ExDeorum.ID),
RegistryObject.create(new ResourceLocation(soundTypeObj.get("hit_sound").getAsString()), Registries.SOUND_EVENT, ExDeorum.ID),
RegistryObject.create(new ResourceLocation(soundTypeObj.get("fall_sound").getAsString()), Registries.SOUND_EVENT, ExDeorum.ID)
return new DeferredSoundType(1.0f, 1.0f,
DeferredHolder.create(Registries.SOUND_EVENT, new ResourceLocation(soundTypeObj.get("break_sound").getAsString())),
DeferredHolder.create(Registries.SOUND_EVENT, new ResourceLocation(soundTypeObj.get("step_sound").getAsString())),
DeferredHolder.create(Registries.SOUND_EVENT, new ResourceLocation(soundTypeObj.get("place_sound").getAsString())),
DeferredHolder.create(Registries.SOUND_EVENT, new ResourceLocation(soundTypeObj.get("hit_sound").getAsString())),
DeferredHolder.create(Registries.SOUND_EVENT, new ResourceLocation(soundTypeObj.get("fall_sound").getAsString()))
);
}
} else {

View File

@ -25,7 +25,7 @@ import com.google.gson.JsonParser;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraftforge.data.loading.DatagenModLoader;
import net.neoforged.neoforge.data.loading.DatagenModLoader;
import org.jetbrains.annotations.Nullable;
import thedarkcolour.exdeorum.ExDeorum;
import thedarkcolour.exdeorum.client.CompostColors;

View File

@ -18,126 +18,24 @@
package thedarkcolour.exdeorum.material;
import com.google.common.collect.ImmutableMap;
import net.minecraft.world.level.block.SoundType;
import net.minecraftforge.fml.loading.FMLLoader;
import thedarkcolour.exdeorum.ExDeorum;
import org.jetbrains.annotations.Nullable;
import java.util.Map;
import java.util.HashMap;
import java.util.Locale;
class SoundTypeResolver {
static final Map<String, SoundType> VANILLA_SOUND_TYPES;
private static final HashMap<String, SoundType> VANILLA_SOUND_TYPES = new HashMap<>();
static {
if (ExDeorum.DEBUG && !FMLLoader.versionInfo().mcVersion().equals("1.20.1")) {
throw new RuntimeException("Update the BarrelMaterial map");
}
// Very long line of put calls that put each SoundType field and its lowercase name into the map
ImmutableMap.Builder<String, SoundType> temp = ImmutableMap.builder();
temp.put("empty", SoundType.EMPTY);
temp.put("wood", SoundType.WOOD);
temp.put("gravel", SoundType.GRAVEL);
temp.put("grass", SoundType.GRASS);
temp.put("lily_pad", SoundType.LILY_PAD);
temp.put("stone", SoundType.STONE);
temp.put("metal", SoundType.METAL);
temp.put("glass", SoundType.GLASS);
temp.put("wool", SoundType.WOOL);
temp.put("sand", SoundType.SAND);
temp.put("snow", SoundType.SNOW);
temp.put("powder_snow", SoundType.POWDER_SNOW);
temp.put("ladder", SoundType.LADDER);
temp.put("anvil", SoundType.ANVIL);
temp.put("slime_block", SoundType.SLIME_BLOCK);
temp.put("honey_block", SoundType.HONEY_BLOCK);
temp.put("wet_grass", SoundType.WET_GRASS);
temp.put("coral_block", SoundType.CORAL_BLOCK);
temp.put("bamboo", SoundType.BAMBOO);
temp.put("bamboo_sapling", SoundType.BAMBOO_SAPLING);
temp.put("scaffolding", SoundType.SCAFFOLDING);
temp.put("sweet_berry_bush", SoundType.SWEET_BERRY_BUSH);
temp.put("crop", SoundType.CROP);
temp.put("hard_crop", SoundType.HARD_CROP);
temp.put("vine", SoundType.VINE);
temp.put("nether_wart", SoundType.NETHER_WART);
temp.put("lantern", SoundType.LANTERN);
temp.put("stem", SoundType.STEM);
temp.put("nylium", SoundType.NYLIUM);
temp.put("fungus", SoundType.FUNGUS);
temp.put("roots", SoundType.ROOTS);
temp.put("shroomlight", SoundType.SHROOMLIGHT);
temp.put("weeping_vines", SoundType.WEEPING_VINES);
temp.put("twisting_vines", SoundType.TWISTING_VINES);
temp.put("soul_sand", SoundType.SOUL_SAND);
temp.put("soul_soil", SoundType.SOUL_SOIL);
temp.put("basalt", SoundType.BASALT);
temp.put("wart_block", SoundType.WART_BLOCK);
temp.put("netherrack", SoundType.NETHERRACK);
temp.put("nether_bricks", SoundType.NETHER_BRICKS);
temp.put("nether_sprouts", SoundType.NETHER_SPROUTS);
temp.put("nether_ore", SoundType.NETHER_ORE);
temp.put("bone_block", SoundType.BONE_BLOCK);
temp.put("netherite_block", SoundType.NETHERITE_BLOCK);
temp.put("ancient_debris", SoundType.ANCIENT_DEBRIS);
temp.put("lodestone", SoundType.LODESTONE);
temp.put("chain", SoundType.CHAIN);
temp.put("nether_gold_ore", SoundType.NETHER_GOLD_ORE);
temp.put("gilded_blackstone", SoundType.GILDED_BLACKSTONE);
temp.put("candle", SoundType.CANDLE);
temp.put("amethyst", SoundType.AMETHYST);
temp.put("amethyst_cluster", SoundType.AMETHYST_CLUSTER);
temp.put("small_amethyst_bud", SoundType.SMALL_AMETHYST_BUD);
temp.put("medium_amethyst_bud", SoundType.MEDIUM_AMETHYST_BUD);
temp.put("large_amethyst_bud", SoundType.LARGE_AMETHYST_BUD);
temp.put("tuff", SoundType.TUFF);
temp.put("calcite", SoundType.CALCITE);
temp.put("dripstone_block", SoundType.DRIPSTONE_BLOCK);
temp.put("pointed_dripstone", SoundType.POINTED_DRIPSTONE);
temp.put("copper", SoundType.COPPER);
temp.put("cave_vines", SoundType.CAVE_VINES);
temp.put("spore_blossom", SoundType.SPORE_BLOSSOM);
temp.put("azalea", SoundType.AZALEA);
temp.put("flowering_azalea", SoundType.FLOWERING_AZALEA);
temp.put("moss_carpet", SoundType.MOSS_CARPET);
temp.put("pink_petals", SoundType.PINK_PETALS);
temp.put("moss", SoundType.MOSS);
temp.put("big_dripleaf", SoundType.BIG_DRIPLEAF);
temp.put("small_dripleaf", SoundType.SMALL_DRIPLEAF);
temp.put("rooted_dirt", SoundType.ROOTED_DIRT);
temp.put("hanging_roots", SoundType.HANGING_ROOTS);
temp.put("azalea_leaves", SoundType.AZALEA_LEAVES);
temp.put("sculk_sensor", SoundType.SCULK_SENSOR);
temp.put("sculk_catalyst", SoundType.SCULK_CATALYST);
temp.put("sculk", SoundType.SCULK);
temp.put("sculk_vein", SoundType.SCULK_VEIN);
temp.put("sculk_shrieker", SoundType.SCULK_SHRIEKER);
temp.put("glow_lichen", SoundType.GLOW_LICHEN);
temp.put("deepslate", SoundType.DEEPSLATE);
temp.put("deepslate_bricks", SoundType.DEEPSLATE_BRICKS);
temp.put("deepslate_tiles", SoundType.DEEPSLATE_TILES);
temp.put("polished_deepslate", SoundType.POLISHED_DEEPSLATE);
temp.put("froglight", SoundType.FROGLIGHT);
temp.put("frogspawn", SoundType.FROGSPAWN);
temp.put("mangrove_roots", SoundType.MANGROVE_ROOTS);
temp.put("muddy_mangrove_roots", SoundType.MUDDY_MANGROVE_ROOTS);
temp.put("mud", SoundType.MUD);
temp.put("mud_bricks", SoundType.MUD_BRICKS);
temp.put("packed_mud", SoundType.PACKED_MUD);
temp.put("hanging_sign", SoundType.HANGING_SIGN);
temp.put("nether_wood_hanging_sign", SoundType.NETHER_WOOD_HANGING_SIGN);
temp.put("bamboo_wood_hanging_sign", SoundType.BAMBOO_WOOD_HANGING_SIGN);
temp.put("bamboo_wood", SoundType.BAMBOO_WOOD);
temp.put("nether_wood", SoundType.NETHER_WOOD);
temp.put("cherry_wood", SoundType.CHERRY_WOOD);
temp.put("cherry_sapling", SoundType.CHERRY_SAPLING);
temp.put("cherry_leaves", SoundType.CHERRY_LEAVES);
temp.put("cherry_wood_hanging_sign", SoundType.CHERRY_WOOD_HANGING_SIGN);
temp.put("chiseled_bookshelf", SoundType.CHISELED_BOOKSHELF);
temp.put("suspicious_sand", SoundType.SUSPICIOUS_SAND);
temp.put("suspicious_gravel", SoundType.SUSPICIOUS_GRAVEL);
temp.put("decorated_pot", SoundType.DECORATED_POT);
temp.put("decorated_pot_cracked", SoundType.DECORATED_POT_CRACKED);
VANILLA_SOUND_TYPES = temp.build();
@Nullable
static SoundType resolve(String name) {
return VANILLA_SOUND_TYPES.computeIfAbsent(name.toUpperCase(Locale.ROOT), (fieldName) -> {
try {
var field = SoundType.class.getDeclaredField(fieldName);
return (SoundType) field.get(null);
} catch (NoSuchFieldException | IllegalAccessException ignored) {
return null;
}
});
}
}

View File

@ -16,7 +16,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package thedarkcolour.exdeorum.blockentity;
package thedarkcolour.exdeorum.menu;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
@ -26,7 +26,7 @@ import net.minecraft.world.inventory.DataSlot;
import net.minecraft.world.inventory.InventoryMenu;
import net.minecraft.world.item.ItemStack;
import thedarkcolour.exdeorum.ExDeorum;
import thedarkcolour.exdeorum.menu.AbstractMachineMenu;
import thedarkcolour.exdeorum.blockentity.MechanicalHammerBlockEntity;
import thedarkcolour.exdeorum.registry.EMenus;
import thedarkcolour.exdeorum.tag.EItemTags;

View File

@ -43,7 +43,7 @@ public class ClientMessageHandler {
}
@SuppressWarnings("DataFlowIssue")
public static void handleVisualUpdate(VisualUpdateMessage msg) {
static void handleVisualUpdate(VisualUpdateMessage msg) {
ClientLevel level = Minecraft.getInstance().level;
if (level != null && level.getBlockEntity(msg.pos) instanceof EBlockEntity blockEntity) {
// payload should be nonnull on the client side

View File

@ -19,27 +19,27 @@
package thedarkcolour.exdeorum.network;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.fml.DistExecutor;
import net.minecraftforge.network.NetworkEvent;
import java.util.function.Supplier;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
import net.minecraft.resources.ResourceLocation;
import thedarkcolour.exdeorum.ExDeorum;
// Like ClientboundContainerSetDataPacket except that the value is 32 bits instead of 16 bits
public record MenuPropertyMessage(int containerId, int index, int value) {
public static void encode(MenuPropertyMessage msg, FriendlyByteBuf buffer) {
buffer.writeByte(msg.containerId);
buffer.writeShort(msg.index);
buffer.writeVarInt(msg.value);
public record MenuPropertyMessage(int containerId, int index, int value) implements CustomPacketPayload {
public static final ResourceLocation ID = new ResourceLocation(ExDeorum.ID, "menu_property");
@Override
public void write(FriendlyByteBuf buffer) {
buffer.writeByte(this.containerId);
buffer.writeShort(this.index);
buffer.writeVarInt(this.value);
}
@Override
public ResourceLocation id() {
return ID;
}
public static MenuPropertyMessage decode(FriendlyByteBuf buffer) {
return new MenuPropertyMessage(buffer.readByte(), buffer.readShort(), buffer.readVarInt());
}
public static void handle(MenuPropertyMessage msg, Supplier<NetworkEvent.Context> ctxSupplier) {
NetworkHandler.handle(ctxSupplier, ctx -> {
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> ClientMessageHandler.handleMenuProperty(msg));
});
}
}

View File

@ -18,43 +18,36 @@
package thedarkcolour.exdeorum.network;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.minecraftforge.network.NetworkDirection;
import net.minecraftforge.network.NetworkEvent;
import net.minecraftforge.network.NetworkRegistry;
import net.minecraftforge.network.simple.SimpleChannel;
import thedarkcolour.exdeorum.ExDeorum;
import java.util.function.Consumer;
import java.util.function.Supplier;
import net.neoforged.neoforge.network.PacketDistributor;
import net.neoforged.neoforge.network.registration.IPayloadRegistrar;
public final class NetworkHandler {
public static final String PROTOCOL_VERSION = "1";
public static final SimpleChannel CHANNEL = NetworkRegistry.newSimpleChannel(new ResourceLocation(ExDeorum.ID, "channel"), () -> PROTOCOL_VERSION, PROTOCOL_VERSION::equals, PROTOCOL_VERSION::equals);
public static void register() {
CHANNEL.registerMessage(0, VoidWorldMessage.class, VoidWorldMessage::encode, VoidWorldMessage::decode, VoidWorldMessage::handle);
CHANNEL.registerMessage(1, PlayerDataMessage.class, (msg, buffer) -> {}, buffer -> new PlayerDataMessage(), PlayerDataMessage::handle);
CHANNEL.registerMessage(2, VisualUpdateMessage.class, VisualUpdateMessage::encode, VisualUpdateMessage::decode, VisualUpdateMessage::handle);
CHANNEL.registerMessage(3, MenuPropertyMessage.class, MenuPropertyMessage::encode, MenuPropertyMessage::decode, MenuPropertyMessage::handle);
public static void register(IPayloadRegistrar registrar) {
registrar.play(MenuPropertyMessage.ID, MenuPropertyMessage::decode, sidedHandler -> {
sidedHandler.client((msg, ctx) -> ClientMessageHandler.handleMenuProperty(msg));
});
registrar.play(VisualUpdateMessage.ID, VisualUpdateMessage::decode, sidedHandler -> {
sidedHandler.client((msg, ctx) -> ClientMessageHandler.handleVisualUpdate(msg));
});
// not sure if these stop working if they're in the wrong phase, so I'll put them in both
registrar.common(VoidWorldMessage.ID, buffer -> VoidWorldMessage.INSTANCE, sidedHandler -> {
sidedHandler.client((msg, ctx) -> ClientMessageHandler.disableVoidFogRendering());
});
registrar.common(RecipeCacheResetMessage.ID, buffer -> RecipeCacheResetMessage.INSTANCE, sidedHandler -> {
sidedHandler.client((msg, ctx) -> ClientMessageHandler.reloadClientRecipeCache());
});
}
public static void sendVoidWorld(ServerPlayer pPlayer) {
CHANNEL.sendTo(new VoidWorldMessage(), pPlayer.connection.connection, NetworkDirection.PLAY_TO_CLIENT);
public static void sendVoidWorld(ServerPlayer player) {
PacketDistributor.PLAYER.with(player).send(VoidWorldMessage.INSTANCE);
}
public static void sendRecipeCacheReset(ServerPlayer player) {
CHANNEL.sendTo(new PlayerDataMessage(), player.connection.connection, NetworkDirection.PLAY_TO_CLIENT);
}
static void handle(Supplier<NetworkEvent.Context> ctxSupplier, Consumer<NetworkEvent.Context> handler) {
var ctx = ctxSupplier.get();
ctx.enqueueWork(() -> handler.accept(ctx));
ctx.setPacketHandled(true);
PacketDistributor.PLAYER.with(player).send(RecipeCacheResetMessage.INSTANCE);
}
public static void sendMenuProperty(ServerPlayer player, int containerId, int index, int prevSieveEnergy) {
CHANNEL.sendTo(new MenuPropertyMessage(containerId, index, prevSieveEnergy), player.connection.connection, NetworkDirection.PLAY_TO_CLIENT);
PacketDistributor.PLAYER.with(player).send(new MenuPropertyMessage(containerId, index, prevSieveEnergy));
}
}

View File

@ -18,19 +18,25 @@
package thedarkcolour.exdeorum.network;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.fml.DistExecutor;
import net.minecraftforge.network.NetworkEvent;
import java.util.function.Supplier;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
import net.minecraft.resources.ResourceLocation;
import thedarkcolour.exdeorum.ExDeorum;
// Server -> Client
// Fired whenever a player joins an LAN world or dedicated server to load the recipe caches
// Also fired whenever those servers reload data
public class PlayerDataMessage {
public void handle(Supplier<NetworkEvent.Context> ctxSupplier) {
NetworkHandler.handle(ctxSupplier, ctx -> {
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> ClientMessageHandler::reloadClientRecipeCache);
});
public enum RecipeCacheResetMessage implements CustomPacketPayload {
INSTANCE;
public static final ResourceLocation ID = new ResourceLocation(ExDeorum.ID, "recipe_cache_reset");
@Override
public void write(FriendlyByteBuf pBuffer) {
}
@Override
public ResourceLocation id() {
return ID;
}
}

View File

@ -21,16 +21,17 @@ package thedarkcolour.exdeorum.network;
import net.minecraft.core.BlockPos;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.fml.DistExecutor;
import net.minecraftforge.network.NetworkEvent;
import org.jetbrains.annotations.Nullable;
import thedarkcolour.exdeorum.ExDeorum;
import thedarkcolour.exdeorum.blockentity.EBlockEntity;
import java.util.function.Supplier;
// todo change this into two classes instead of having nullable fields
class VisualUpdateMessage implements CustomPacketPayload {
public static final ResourceLocation ID = new ResourceLocation(ExDeorum.ID, "visual_update");
class VisualUpdateMessage {
final BlockEntityType<?> blockEntityType;
final BlockPos pos;
// Null on the client side
@ -40,6 +41,7 @@ class VisualUpdateMessage {
@Nullable
final FriendlyByteBuf payload;
@SuppressWarnings("DataFlowIssue")
public VisualUpdateMessage(BlockPos pos, @Nullable EBlockEntity blockEntity, @Nullable FriendlyByteBuf payload) {
this.pos = pos;
this.blockEntity = blockEntity;
@ -54,20 +56,21 @@ class VisualUpdateMessage {
}
}
public static void encode(VisualUpdateMessage msg, FriendlyByteBuf buffer) {
buffer.writeBlockPos(msg.pos);
buffer.writeId(BuiltInRegistries.BLOCK_ENTITY_TYPE, msg.blockEntityType);
@SuppressWarnings("DataFlowIssue")
@Override
public void write(FriendlyByteBuf buffer) {
buffer.writeBlockPos(this.pos);
buffer.writeId(BuiltInRegistries.BLOCK_ENTITY_TYPE, this.blockEntityType);
// never null on the server side, where this packet is meant to be encoded
msg.blockEntity.writeVisualData(buffer);
this.blockEntity.writeVisualData(buffer);
}
@Override
public ResourceLocation id() {
return ID;
}
public static VisualUpdateMessage decode(FriendlyByteBuf buffer) {
return new VisualUpdateMessage(buffer.readBlockPos(), null, buffer);
}
public static void handle(VisualUpdateMessage msg, Supplier<NetworkEvent.Context> ctxSupplier) {
NetworkHandler.handle(ctxSupplier, ctx -> {
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> ClientMessageHandler.handleVisualUpdate(msg));
});
}
}

View File

@ -20,16 +20,19 @@ package thedarkcolour.exdeorum.network;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraftforge.network.PacketDistributor;
import net.neoforged.neoforge.network.PacketDistributor;
import thedarkcolour.exdeorum.blockentity.EBlockEntity;
import java.util.*;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
// Syncs certain block entity data to the client for visual purposes
// Since some block entities might change their data multiple times a tick, this class keeps track of
// whether a block entity has updated and then pushes out the changes once at the end of each tick.
public class VisualUpdateTracker {
// WeakHashMap is faster than Guava mapmaker
// WeakHashMap is faster than Guava mapmaker because it isn't thread safe
// Use sets to avoid duplicate updates
private static final Map<LevelChunk, Set<BlockPos>> UPDATES = new WeakHashMap<>();
@ -57,7 +60,7 @@ public class VisualUpdateTracker {
if (chunk.getBlockEntity(updatePos) instanceof EBlockEntity blockEntity) {
// packet uses strong reference
NetworkHandler.CHANNEL.send(PacketDistributor.TRACKING_CHUNK.with(entry::getKey), new VisualUpdateMessage(updatePos, blockEntity, null));
PacketDistributor.TRACKING_CHUNK.with(chunk).send(new VisualUpdateMessage(updatePos, blockEntity, null));
}
}

View File

@ -19,25 +19,23 @@
package thedarkcolour.exdeorum.network;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.fml.DistExecutor;
import net.minecraftforge.network.NetworkEvent;
import java.util.function.Supplier;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
import net.minecraft.resources.ResourceLocation;
import thedarkcolour.exdeorum.ExDeorum;
// Server -> Client
// used to tell the client to disable the cave darkness rendering in a void world
public class VoidWorldMessage {
public static void encode(VoidWorldMessage msg, FriendlyByteBuf packet) {
public enum VoidWorldMessage implements CustomPacketPayload {
INSTANCE;
public static final ResourceLocation ID = new ResourceLocation(ExDeorum.ID, "void_world_msg");
@Override
public void write(FriendlyByteBuf pBuffer) {
}
public static VoidWorldMessage decode(FriendlyByteBuf packet) {
return new VoidWorldMessage();
}
public static void handle(VoidWorldMessage msg, Supplier<NetworkEvent.Context> ctxSupplier) {
NetworkHandler.handle(ctxSupplier, ctx -> {
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> ClientMessageHandler::disableVoidFogRendering);
});
@Override
public ResourceLocation id() {
return ID;
}
}

View File

@ -18,9 +18,16 @@
package thedarkcolour.exdeorum.recipe;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.mojang.datafixers.util.Pair;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult;
import com.mojang.serialization.DynamicOps;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.advancements.critereon.StatePropertiesPredicate;
import net.minecraft.core.Registry;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.core.registries.Registries;
import net.minecraft.network.FriendlyByteBuf;
@ -36,11 +43,13 @@ import java.util.function.Predicate;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
@SuppressWarnings("deprecation")
public sealed interface BlockPredicate extends Predicate<BlockState> {
// used for network
byte SINGLE_BLOCK = 0, BLOCK_STATE = 1, BLOCK_TAG = 2;
// todo test this
Codec<BlockPredicate> CODEC = new BlockPredicate.SpecialCodec();
JsonObject toJson();
void toNetwork(FriendlyByteBuf buffer);
@ -70,7 +79,7 @@ public sealed interface BlockPredicate extends Predicate<BlockState> {
if (block == Blocks.AIR) return null;
if (json.has("state")) {
return new BlockStatePredicate(block, StatePropertiesPredicate.fromJson(json.get("state")));
return new BlockStatePredicate(block, CodecUtil.decode(StatePropertiesPredicate.CODEC, json.get("state")));
} else {
return new SingleBlockPredicate(block);
}
@ -84,14 +93,24 @@ public sealed interface BlockPredicate extends Predicate<BlockState> {
@Nullable
static BlockPredicate fromNetwork(FriendlyByteBuf buffer) {
return switch (buffer.readByte()) {
case SINGLE_BLOCK -> new SingleBlockPredicate(buffer.readById(BuiltInRegistries.BLOCK));
case BLOCK_STATE -> new BlockStatePredicate(buffer.readById(BuiltInRegistries.BLOCK), StatePropertiesPredicate.fromJson(JsonParser.parseString(buffer.readUtf())));
case BLOCK_TAG -> new TagPredicate(TagKey.create(Registries.BLOCK, buffer.readResourceLocation()));
case SINGLE_BLOCK -> new SingleBlockPredicate(Objects.requireNonNull(buffer.readById(BuiltInRegistries.BLOCK)));
case BLOCK_STATE -> new BlockStatePredicate(Objects.requireNonNull(buffer.readById(BuiltInRegistries.BLOCK)), decodeStatePredicate(JsonParser.parseString(buffer.readUtf())));
case BLOCK_TAG -> new TagPredicate(RecipeUtil.readTag(buffer, Registries.BLOCK));
default -> null;
};
}
private static StatePropertiesPredicate decodeStatePredicate(JsonElement json) {
return CodecUtil.decode(StatePropertiesPredicate.CODEC, json);
}
private static JsonElement encodeStatePredicate(StatePropertiesPredicate predicate) {
return CodecUtil.encode(StatePropertiesPredicate.CODEC, predicate);
}
record TagPredicate(TagKey<Block> tag) implements BlockPredicate {
private static final Codec<TagPredicate> CODEC = RecordCodecBuilder.create(instance -> instance.group(TagKey.codec(Registries.BLOCK).fieldOf("tag").forGetter(TagPredicate::tag)).apply(instance, TagPredicate::new));
@Override
public JsonObject toJson() {
var json = new JsonObject();
@ -102,7 +121,7 @@ public sealed interface BlockPredicate extends Predicate<BlockState> {
@Override
public void toNetwork(FriendlyByteBuf buffer) {
buffer.writeByte(BLOCK_TAG);
buffer.writeResourceLocation(this.tag.location());
RecipeUtil.writeTag(buffer, this.tag);
}
@Override
@ -114,16 +133,20 @@ public sealed interface BlockPredicate extends Predicate<BlockState> {
public Stream<BlockState> possibleStates() {
return StreamSupport.stream(BuiltInRegistries.BLOCK.getTagOrEmpty(this.tag).spliterator(), false)
.filter(holder -> holder.is(this.tag))
.flatMap(holder -> holder.get().getStateDefinition().getPossibleStates().stream());
.flatMap(holder -> holder.value().getStateDefinition().getPossibleStates().stream());
}
}
record BlockStatePredicate(Block block, StatePropertiesPredicate properties) implements BlockPredicate {
private static final Codec<BlockStatePredicate> CODEC = RecordCodecBuilder.create(instance -> instance.group(
CodecUtil.blockField("block", BlockStatePredicate::block),
StatePropertiesPredicate.CODEC.fieldOf("properties").forGetter(BlockStatePredicate::properties)
).apply(instance, BlockStatePredicate::new));
@Override
public JsonObject toJson() {
var json = new JsonObject();
json.addProperty("block", BuiltInRegistries.BLOCK.getKey(this.block).toString());
json.add("state", this.properties.serializeToJson());
json.add("state", encodeStatePredicate(this.properties));
return json;
}
@ -131,7 +154,7 @@ public sealed interface BlockPredicate extends Predicate<BlockState> {
public void toNetwork(FriendlyByteBuf buffer) {
buffer.writeByte(BLOCK_STATE);
buffer.writeId(BuiltInRegistries.BLOCK, this.block);
buffer.writeUtf(this.properties.serializeToJson().toString());
buffer.writeUtf(encodeStatePredicate(this.properties).toString());
}
@Override
@ -150,7 +173,7 @@ public sealed interface BlockPredicate extends Predicate<BlockState> {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
BlockStatePredicate that = (BlockStatePredicate) o;
return Objects.equals(block, that.block) && Objects.equals(properties.serializeToJson(), that.properties.serializeToJson());
return this.block == that.block && Objects.equals(encodeStatePredicate(this.properties), encodeStatePredicate(that.properties));
}
}
@ -178,4 +201,37 @@ public sealed interface BlockPredicate extends Predicate<BlockState> {
return this.block.getStateDefinition().getPossibleStates().stream();
}
}
class SpecialCodec implements Codec<BlockPredicate> {
@Override
public <T> DataResult<Pair<BlockPredicate, T>> decode(DynamicOps<T> ops, T input) {
var tagResult = TagPredicate.CODEC.decode(ops, input);
if (tagResult.error().isEmpty()) {
return CodecUtil.cast(tagResult);
} else {
var stateResult = BlockStatePredicate.CODEC.decode(ops, input);
if (stateResult.error().isEmpty()) {
return CodecUtil.cast(stateResult);
} else {
var blockResult = SingleBlockPredicate.CODEC.decode(ops, input);
return blockResult.error().isEmpty() ? CodecUtil.cast(blockResult) : DataResult.error(() -> "Invalid block predicate");
}
}
}
@Override
public <T> DataResult<T> encode(BlockPredicate input, DynamicOps<T> ops, T prefix) {
// in newer java, this should be replaced with pattern matching
if (input instanceof SingleBlockPredicate block) {
return SingleBlockPredicate.CODEC.encode(block, ops, prefix);
} else if (input instanceof BlockStatePredicate state) {
return BlockStatePredicate.CODEC.encode(state, ops, prefix);
} else {
return TagPredicate.CODEC.encode((TagPredicate) input, ops, prefix);
}
}
}
}

View File

@ -0,0 +1,73 @@
/*
* Ex Deorum
* Copyright (c) 2024 thedarkcolour
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package thedarkcolour.exdeorum.recipe;
import com.google.gson.JsonElement;
import com.mojang.datafixers.kinds.App;
import com.mojang.datafixers.util.Pair;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult;
import com.mojang.serialization.JsonOps;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.material.Fluid;
import net.neoforged.neoforge.fluids.FluidStack;
import java.util.function.Function;
@SuppressWarnings("OptionalGetWithoutIsPresent")
public class CodecUtil {
public static final Codec<FluidStack> FLUIDSTACK_CODEC = RecordCodecBuilder.create(instance -> instance.group(
fluidField("fluid", FluidStack::getFluid),
Codec.INT.fieldOf("amount").forGetter(FluidStack::getAmount),
CompoundTag.CODEC.optionalFieldOf("tag", null).forGetter(FluidStack::getTag)
).apply(instance, FluidStack::new));
public static <T extends SingleIngredientRecipe> App<RecordCodecBuilder.Mu<T>, Ingredient> ingredientField() {
return Ingredient.CODEC_NONEMPTY.fieldOf("ingredient").forGetter(SingleIngredientRecipe::getIngredient);
}
public static <T> App<RecordCodecBuilder.Mu<T>, Item> itemField(String name, Function<T, Item> getter) {
return BuiltInRegistries.ITEM.byNameCodec().fieldOf(name).forGetter(getter);
}
public static <T> App<RecordCodecBuilder.Mu<T>, Block> blockField(String name, Function<T, Block> getter) {
return BuiltInRegistries.BLOCK.byNameCodec().fieldOf(name).forGetter(getter);
}
public static <T> App<RecordCodecBuilder.Mu<T>, Fluid> fluidField(String name, Function<T, Fluid> getter) {
return BuiltInRegistries.FLUID.byNameCodec().fieldOf(name).forGetter(getter);
}
public static <T> JsonElement encode(Codec<T> codec, T object) {
return codec.encodeStart(JsonOps.INSTANCE, object).result().get();
}
public static <T> T decode(Codec<T> codec, JsonElement json) {
return codec.parse(JsonOps.INSTANCE, json).result().get();
}
public static <T, U extends T, I> DataResult<Pair<T, I>> cast(DataResult<Pair<U, I>> result) {
return result.map(pair -> pair.mapFirst(Function.identity()));
}
}

View File

@ -1,49 +0,0 @@
/*
* Ex Deorum
* Copyright (c) 2024 thedarkcolour
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package thedarkcolour.exdeorum.recipe;
import com.google.gson.JsonObject;
import net.minecraft.data.recipes.FinishedRecipe;
import net.minecraft.resources.ResourceLocation;
import org.jetbrains.annotations.Nullable;
public abstract class EFinishedRecipe implements FinishedRecipe {
private final ResourceLocation id;
public EFinishedRecipe(ResourceLocation id) {
this.id = id;
}
@Override
public ResourceLocation getId() {
return this.id;
}
@Nullable
@Override
public JsonObject serializeAdvancement() {
return null;
}
@Nullable
@Override
public ResourceLocation getAdvancementId() {
return null;
}
}

View File

@ -0,0 +1,133 @@
/*
* Ex Deorum
* Copyright (c) 2024 thedarkcolour
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package thedarkcolour.exdeorum.recipe;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.core.NonNullList;
import net.minecraft.core.RegistryAccess;
import net.minecraft.core.registries.Registries;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.tags.TagKey;
import net.minecraft.world.inventory.CraftingContainer;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.*;
import net.minecraft.world.level.Level;
import net.neoforged.neoforge.common.crafting.IShapedRecipe;
import net.neoforged.neoforge.common.util.Lazy;
import thedarkcolour.exdeorum.compat.PreferredOres;
import thedarkcolour.exdeorum.registry.ERecipeSerializers;
import java.util.List;
import java.util.Map;
public class OreChunkRecipe implements CraftingRecipe, IShapedRecipe<CraftingContainer> {
public static final Codec<OreChunkRecipe> CODEC = RecordCodecBuilder.create(instance -> instance.group(
Ingredient.CODEC_NONEMPTY.fieldOf("ore_chunk").forGetter(OreChunkRecipe::getOreChunk),
TagKey.codec(Registries.ITEM).fieldOf("ore").forGetter(OreChunkRecipe::getOre)
).apply(instance, OreChunkRecipe::new));
private static final List<String> GRID_2X2 = List.of("CC", "CC");
private final Ingredient oreChunk;
private final TagKey<Item> ore;
private final ShapedRecipePattern pattern;
private final Lazy<ItemStack> resultItem;
public OreChunkRecipe(Ingredient oreChunk, TagKey<Item> ore) {
this.oreChunk = oreChunk;
this.ore = ore;
this.pattern = ShapedRecipePattern.of(Map.of('C', oreChunk), GRID_2X2);
this.resultItem = Lazy.of(() -> {
return new ItemStack(PreferredOres.getPreferredOre(this.ore));
});
}
public Ingredient getOreChunk() {
return this.oreChunk;
}
public TagKey<Item> getOre() {
return this.ore;
}
@Override
public NonNullList<Ingredient> getIngredients() {
return this.pattern.ingredients();
}
@Override
public ItemStack getResultItem(RegistryAccess pRegistryAccess) {
return this.resultItem.get();
}
@Override
public ItemStack assemble(CraftingContainer pContainer, RegistryAccess pRegistryAccess) {
return this.resultItem.get().copy();
}
@Override
public boolean matches(CraftingContainer container, Level pLevel) {
return this.pattern.matches(container);
}
@Override
public boolean canCraftInDimensions(int width, int height) {
return width >= 2 && height >= 2;
}
@Override
public int getRecipeWidth() {
return 2;
}
@Override
public int getRecipeHeight() {
return 2;
}
@Override
public CraftingBookCategory category() {
return CraftingBookCategory.BUILDING;
}
@Override
public RecipeSerializer<?> getSerializer() {
return ERecipeSerializers.ORE_CHUNK.get();
}
public static class Serializer implements RecipeSerializer<OreChunkRecipe> {
@Override
public Codec<OreChunkRecipe> codec() {
return CODEC;
}
@Override
public OreChunkRecipe fromNetwork(FriendlyByteBuf buffer) {
return new OreChunkRecipe(Ingredient.fromNetwork(buffer), RecipeUtil.readTag(buffer, Registries.ITEM));
}
@Override
public void toNetwork(FriendlyByteBuf buffer, OreChunkRecipe recipe) {
recipe.oreChunk.toNetwork(buffer);
RecipeUtil.writeTag(buffer, recipe.ore);
}
}
}

View File

@ -18,25 +18,43 @@
package thedarkcolour.exdeorum.recipe;
import com.mojang.datafixers.Products;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.core.RegistryAccess;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.level.storage.loot.providers.number.NumberProvider;
import net.minecraft.world.level.storage.loot.providers.number.NumberProviders;
public abstract class ProbabilityRecipe extends SingleIngredientRecipe {
public final Item result;
public final NumberProvider resultAmount;
public ProbabilityRecipe(ResourceLocation id, Ingredient ingredient, Item result, NumberProvider resultAmount) {
super(id, ingredient);
public ProbabilityRecipe(Ingredient ingredient, Item result, NumberProvider resultAmount) {
super(ingredient);
this.result = result;
this.resultAmount = resultAmount;
}
protected static <T extends ProbabilityRecipe> Products.P3<RecordCodecBuilder.Mu<T>, Ingredient, Item, NumberProvider> commonFields(RecordCodecBuilder.Instance<T> instance) {
return instance.group(
CodecUtil.ingredientField(),
CodecUtil.itemField("result", ProbabilityRecipe::getResult),
NumberProviders.CODEC.fieldOf("result_amount").forGetter(ProbabilityRecipe::getResultAmount)
);
}
@Override
public ItemStack getResultItem(RegistryAccess access) {
return new ItemStack(this.result);
}
public Item getResult() {
return this.result;
}
public NumberProvider getResultAmount() {
return this.resultAmount;
}
}

View File

@ -18,49 +18,38 @@
package thedarkcolour.exdeorum.recipe;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSyntaxException;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import it.unimi.dsi.fastutil.objects.ObjectSet;
import net.minecraft.commands.arguments.blocks.BlockStateParser;
import net.minecraft.core.Registry;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.tags.TagKey;
import net.minecraft.util.GsonHelper;
import net.minecraft.world.Container;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.item.crafting.Recipe;
import net.minecraft.world.item.crafting.RecipeManager;
import net.minecraft.world.item.crafting.RecipeType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.Property;
import net.minecraft.world.level.material.Fluid;
import net.minecraft.world.level.material.Fluids;
import net.minecraft.world.level.storage.loot.LootContext;
import net.minecraft.world.level.storage.loot.LootDataType;
import net.minecraft.world.level.storage.loot.LootParams;
import net.minecraft.world.level.storage.loot.providers.number.*;
import net.minecraftforge.common.crafting.CraftingHelper;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.registries.ForgeRegistries;
import net.neoforged.neoforge.fluids.FluidStack;
import org.jetbrains.annotations.Nullable;
import thedarkcolour.exdeorum.ExDeorum;
import thedarkcolour.exdeorum.compat.PreferredOres;
import thedarkcolour.exdeorum.item.HammerItem;
import thedarkcolour.exdeorum.loot.SummationGenerator;
import thedarkcolour.exdeorum.recipe.barrel.BarrelCompostRecipe;
import thedarkcolour.exdeorum.recipe.barrel.BarrelFluidMixingRecipe;
import thedarkcolour.exdeorum.recipe.barrel.FluidTransformationRecipe;
import thedarkcolour.exdeorum.recipe.barrel.BarrelMixingRecipe;
import thedarkcolour.exdeorum.recipe.barrel.FluidTransformationRecipe;
import thedarkcolour.exdeorum.recipe.cache.*;
import thedarkcolour.exdeorum.recipe.crook.CrookRecipe;
import thedarkcolour.exdeorum.recipe.crucible.CrucibleRecipe;
@ -69,11 +58,7 @@ import thedarkcolour.exdeorum.recipe.sieve.SieveRecipe;
import thedarkcolour.exdeorum.registry.ENumberProviders;
import thedarkcolour.exdeorum.registry.ERecipeTypes;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.*;
public final class RecipeUtil {
private static final int CONSTANT_TYPE = 1;
@ -96,7 +81,7 @@ public final class RecipeUtil {
barrelCompostRecipeCache = new SingleIngredientRecipeCache<>(recipes, ERecipeTypes.BARREL_COMPOST);
lavaCrucibleRecipeCache = new SingleIngredientRecipeCache<>(recipes, ERecipeTypes.LAVA_CRUCIBLE);
waterCrucibleRecipeCache = new SingleIngredientRecipeCache<>(recipes, ERecipeTypes.WATER_CRUCIBLE);
hammerRecipeCache = new SingleIngredientRecipeCache<>(recipes, ERecipeTypes.HAMMER).trackAllRecipes();
hammerRecipeCache = new SingleIngredientRecipeCache<>(recipes, ERecipeTypes.HAMMER);
sieveRecipeCache = new SieveRecipeCache(recipes);
barrelFluidMixingRecipeCache = new BarrelFluidMixingRecipeCache(recipes);
fluidTransformationRecipeCache = new FluidTransformationRecipeCache(recipes);
@ -141,66 +126,28 @@ public final class RecipeUtil {
return hammerRecipeCache.getRecipe(item);
}
public static Collection<HammerRecipe> getCachedHammerRecipes() {
return hammerRecipeCache.getAllRecipes();
}
public static <C extends Container, T extends Recipe<C>> Collection<T> byType(RecipeManager manager, RecipeType<T> type) {
return manager.byType(type).values();
}
public static Ingredient readIngredient(JsonObject json, String key) {
if (GsonHelper.isArrayNode(json, key)) {
return Ingredient.fromJson(GsonHelper.getAsJsonArray(json, key));
} else {
return Ingredient.fromJson(GsonHelper.getAsJsonObject(json, key));
}
}
public static Item readItem(JsonObject json, String key) {
return CraftingHelper.getItem(GsonHelper.getAsString(json, key), true);
}
public static Fluid readFluid(JsonObject json, String key) {
String fluidName = GsonHelper.getAsString(json, key);
ResourceLocation fluidKey = new ResourceLocation(fluidName);
if (!ForgeRegistries.FLUIDS.containsKey(fluidKey)) {
throw new JsonSyntaxException("Unknown fluid '" + fluidName + "'");
}
Fluid fluid = ForgeRegistries.FLUIDS.getValue(fluidKey);
if (fluid == Fluids.EMPTY) {
throw new JsonSyntaxException("Invalid Fluid: " + fluidName);
}
return Objects.requireNonNull(fluid);
}
public static NumberProvider readNumberProvider(JsonObject json, String key) {
var obj = json.get(key);
return LootDataType.PREDICATE.parser().fromJson(obj, NumberProvider.class);
}
public static void toNetworkNumberProvider(FriendlyByteBuf buffer, NumberProvider provider) {
if (provider.getType() == NumberProviders.CONSTANT) {
buffer.writeByte(CONSTANT_TYPE);
buffer.writeFloat(((ConstantValue) provider).value);
buffer.writeFloat(((ConstantValue) provider).value());
} else if (provider.getType() == NumberProviders.UNIFORM) {
var uniform = (UniformGenerator) provider;
buffer.writeByte(UNIFORM_TYPE);
toNetworkNumberProvider(buffer, uniform.min);
toNetworkNumberProvider(buffer, uniform.max);
toNetworkNumberProvider(buffer, uniform.min());
toNetworkNumberProvider(buffer, uniform.max());
} else if (provider.getType() == NumberProviders.BINOMIAL) {
var binomial = (BinomialDistributionGenerator) provider;
buffer.writeByte(BINOMIAL_TYPE);
toNetworkNumberProvider(buffer, binomial.n);
toNetworkNumberProvider(buffer, binomial.p);
toNetworkNumberProvider(buffer, binomial.n());
toNetworkNumberProvider(buffer, binomial.p());
} else if (provider.getType() == ENumberProviders.SUMMATION.get()) {
var summation = (SummationGenerator) provider;
var providers = summation.providers();
int length = providers.length;
int length = providers.size();
buffer.writeByte(SUMMATION_TYPE);
buffer.writeByte(length);
for (int i = 0; i < length; i++) {
toNetworkNumberProvider(buffer, providers[i]);
toNetworkNumberProvider(buffer, providers.get(i));
}
} else {
buffer.writeByte(UNKNOWN_TYPE);
@ -220,7 +167,7 @@ public final class RecipeUtil {
for (int i = 0; i < length; i++) {
providers[i] = fromNetworkNumberProvider(buffer);
}
yield new SummationGenerator(providers);
yield new SummationGenerator(List.of(providers));
}
default -> ConstantValue.exactly(1f);
};
@ -231,7 +178,7 @@ public final class RecipeUtil {
// although unlikely, we should check this anyway
if (first == second) return true;
if (first.isVanilla() && second.isVanilla()) {
if (first.getClass() == Ingredient.class && second.getClass() == Ingredient.class) {
var firstValues = new ObjectArrayList<>(first.values);
var secondValues = new ObjectArrayList<>(second.values);
@ -270,11 +217,11 @@ public final class RecipeUtil {
if (firstKlass == secondKlass) {
if (firstKlass == Ingredient.ItemValue.class) {
// if items are different, return false
return ItemStack.matches(((Ingredient.ItemValue) firstValue).item, ((Ingredient.ItemValue) secondValue).item);
return ItemStack.matches(((Ingredient.ItemValue) firstValue).item(), ((Ingredient.ItemValue) secondValue).item());
} else if (firstKlass == Ingredient.TagValue.class) {
// if tags are different, return false
// identity comparison is okay because tags are always interned in vanilla
return ((Ingredient.TagValue) firstValue).tag == ((Ingredient.TagValue) secondValue).tag;
return ((Ingredient.TagValue) firstValue).tag() == ((Ingredient.TagValue) secondValue).tag();
} else {
var firstItems = firstValue.getItems();
var secondItems = secondValue.getItems();
@ -311,9 +258,9 @@ public final class RecipeUtil {
// todo stop using the RecipeManager
@Nullable
public static BarrelMixingRecipe getBarrelMixingRecipe(RecipeManager recipes, ItemStack stack, FluidStack fluid) {
for (var recipe : byType(recipes, ERecipeTypes.BARREL_MIXING.get())) {
if (recipe.matches(stack, fluid)) {
return recipe;
for (var recipe : recipes.byType(ERecipeTypes.BARREL_MIXING.get()).values()) {
if (recipe.value().matches(stack, fluid)) {
return recipe.value();
}
}
@ -323,7 +270,7 @@ public final class RecipeUtil {
@Nullable
public static BarrelFluidMixingRecipe getFluidMixingRecipe(FluidStack base, Fluid additive) {
var recipe = barrelFluidMixingRecipeCache.getRecipe(base.getFluid(), additive);
if (recipe != null && base.getAmount() >= recipe.baseFluidAmount) {
if (recipe != null && base.getAmount() >= recipe.baseFluidAmount()) {
return recipe;
} else {
return null;
@ -341,11 +288,11 @@ public final class RecipeUtil {
public static double getExpectedValue(NumberProvider provider) {
if (provider instanceof ConstantValue constant) {
return constant.value;
return constant.value();
} else if (provider instanceof UniformGenerator uniform) {
return getExpectedValue(uniform.min) + getExpectedValue(uniform.max) / 2.0;
return getExpectedValue(uniform.min()) + getExpectedValue(uniform.max()) / 2.0;
} else if (provider instanceof BinomialDistributionGenerator binomial) {
return getExpectedValue(binomial.n) * getExpectedValue(binomial.p);
return getExpectedValue(binomial.n()) * getExpectedValue(binomial.p());
} else if (provider instanceof SummationGenerator summation) {
double avgSum = 0.0;
@ -366,33 +313,21 @@ public final class RecipeUtil {
}
}
@Nullable
public static BlockPredicate readBlockPredicate(ResourceLocation recipeId, JsonObject json, String key) {
BlockPredicate blockPredicate = BlockPredicate.fromJson(json.getAsJsonObject(key));
if (blockPredicate == null) {
ExDeorum.LOGGER.error("Invalid {} for recipe {}, refer to Ex Deorum documentation for syntax: {}", key, recipeId, json.getAsJsonObject(key));
}
return blockPredicate;
}
@Nullable
public static BlockPredicate readBlockPredicateNetwork(ResourceLocation recipeId, FriendlyByteBuf buffer) {
public static BlockPredicate readBlockPredicateNetwork(FriendlyByteBuf buffer) {
BlockPredicate blockPredicate = BlockPredicate.fromNetwork(buffer);
if (blockPredicate == null) {
ExDeorum.LOGGER.error("Failed to read block_predicate from network for recipe {}", recipeId);
throw new IllegalStateException("Failed to read block predicate from network");
}
return blockPredicate;
}
@SuppressWarnings("deprecation")
public static boolean isTagEmpty(TagKey<Item> tag) {
return BuiltInRegistries.ITEM.getTag(tag).map(set -> !set.iterator().hasNext()).orElse(PreferredOres.getPreferredOre(tag) == Items.AIR);
}
public static LootContext emptyLootContext(ServerLevel level) {
return new LootContext.Builder(new LootParams(level, Map.of(), Map.of(), 0)).create(null);
return new LootContext.Builder(new LootParams(level, Map.of(), Map.of(), 0)).create(Optional.empty());
}
public static List<CrookRecipe> getCrookRecipes(BlockState state) {
@ -407,46 +342,14 @@ public final class RecipeUtil {
return crucibleHeatRecipeCache.getEntries();
}
public static FluidStack readFluidStack(JsonObject json, String key) {
if (json.has(key)) {
var fluidJson = json.getAsJsonObject(key);
// Since we aren't using codec anymore, we can use consistent naming with other JSON objects
if (fluidJson.has("FluidName")) {
var stack = new FluidStack(RecipeUtil.readFluid(fluidJson, "FluidName"), GsonHelper.getAsInt(fluidJson, "Amount"));
if (fluidJson.has("Tag")) {
stack.setTag(CraftingHelper.getNBT(fluidJson.get("Tag")));
}
return stack;
} else {
var stack = new FluidStack(RecipeUtil.readFluid(fluidJson, "fluid"), GsonHelper.getAsInt(fluidJson, "amount"));
if (fluidJson.has("nbt")) {
stack.setTag(CraftingHelper.getNBT(fluidJson.get("nbt")));
}
return stack;
}
} else {
throw new JsonSyntaxException("Missing fluid");
}
}
public static JsonElement writeFluidStackJson(FluidStack fluidStack) {
JsonObject object = new JsonObject();
object.addProperty("fluid", getFluidId(fluidStack.getFluid()));
object.addProperty("amount", fluidStack.getAmount());
if (fluidStack.hasTag()) {
object.addProperty("nbt", fluidStack.getTag().getAsString());
}
return object;
}
@SuppressWarnings({"unchecked", "rawtypes"})
public static JsonPrimitive writeBlockState(BlockState state) {
public static String writeBlockState(BlockState state) {
var registryKey = BuiltInRegistries.BLOCK.getKey(state.getBlock());
Collection<Property> properties = (Collection<Property>) ((Collection)state.getProperties());
if (properties.isEmpty()) {
return new JsonPrimitive(registryKey.toString());
return registryKey.toString();
} else {
StringBuilder builder = new StringBuilder();
builder.append(registryKey);
@ -461,7 +364,7 @@ public final class RecipeUtil {
}
}
builder.append(']');
return new JsonPrimitive(builder.toString());
return builder.toString();
}
}
@ -473,11 +376,11 @@ public final class RecipeUtil {
}
}
public static String getFluidId(Fluid baseFluid) {
return BuiltInRegistries.FLUID.getKey(baseFluid).toString();
public static void writeTag(FriendlyByteBuf buffer, TagKey<?> ore) {
buffer.writeResourceLocation(ore.location());
}
public static String writeItemJson(Item result) {
return BuiltInRegistries.ITEM.getKey(result).toString();
public static <T> TagKey<T> readTag(FriendlyByteBuf buffer, ResourceKey<Registry<T>> registry) {
return TagKey.create(registry, buffer.readResourceLocation());
}
}

View File

@ -20,7 +20,6 @@ package thedarkcolour.exdeorum.recipe;
import net.minecraft.core.NonNullList;
import net.minecraft.core.RegistryAccess;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.Container;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.Ingredient;
@ -34,12 +33,10 @@ import net.minecraft.world.level.Level;
* of any container will be checked, so only one slot should be present.
*/
public abstract class SingleIngredientRecipe implements Recipe<Container> {
private final ResourceLocation id;
public final Ingredient ingredient;
public final boolean dependsOnNbt;
public SingleIngredientRecipe(ResourceLocation id, Ingredient ingredient) {
this.id = id;
public SingleIngredientRecipe(Ingredient ingredient) {
this.ingredient = ingredient;
this.dependsOnNbt = !ingredient.isSimple();
}
@ -63,11 +60,6 @@ public abstract class SingleIngredientRecipe implements Recipe<Container> {
return false;
}
@Override
public ResourceLocation getId() {
return this.id;
}
@Override
public ItemStack getResultItem(RegistryAccess access) {
return ItemStack.EMPTY;

View File

@ -1,123 +0,0 @@
/*
* Ex Deorum
* Copyright (c) 2024 thedarkcolour
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package thedarkcolour.exdeorum.recipe;
import com.google.gson.JsonObject;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.core.registries.Registries;
import net.minecraft.data.recipes.FinishedRecipe;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.TagKey;
import net.minecraft.util.GsonHelper;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.crafting.Recipe;
import net.minecraft.world.item.crafting.RecipeManager;
import net.minecraft.world.item.crafting.RecipeSerializer;
import org.jetbrains.annotations.Nullable;
import thedarkcolour.exdeorum.ExDeorum;
import thedarkcolour.exdeorum.compat.PreferredOres;
import thedarkcolour.exdeorum.registry.ERecipeSerializers;
public class TagResultRecipe {
public static class Serializer<T extends Recipe<?>> implements RecipeSerializer<T> {
@SuppressWarnings({"deprecation", "unchecked"})
@Override
public T fromJson(ResourceLocation id, JsonObject json) {
var resultTag = GsonHelper.getAsString(json, "result_tag");
if (ResourceLocation.isValidResourceLocation(resultTag)) {
var tag = TagKey.create(Registries.ITEM, new ResourceLocation(resultTag));
var preferredItem = PreferredOres.getPreferredOre(tag);
if (preferredItem != Items.AIR) {
var recipeJson = GsonHelper.getAsJsonObject(json, "recipe");
if (recipeJson.has("result")) {
var resultJson = GsonHelper.getAsJsonObject(recipeJson, "result");
var itemId = preferredItem.builtInRegistryHolder().key().location().toString();
// replace item id with correct value
resultJson.addProperty("item", itemId);
return (T) RecipeManager.fromJson(id, recipeJson);
} else {
ExDeorum.LOGGER.error("Skipping recipe {} with unhandled recipe type, \"{}\". Please report to Ex Deorum GitHub.", id, recipeJson.get("type").getAsString());
}
} else {
ExDeorum.LOGGER.info("Skipping recipe {} as ExDeorum could not determine substitute for tag {}", id, tag.location());
}
} else {
ExDeorum.LOGGER.error("Invalid resource location for \"result_tag\" in recipe {}", id);
}
return null;
}
@Override
public @Nullable T fromNetwork(ResourceLocation id, FriendlyByteBuf buffer) {
return null;
}
@Override
public void toNetwork(FriendlyByteBuf buffer, T recipe) {
}
}
public static class Finished implements FinishedRecipe {
private final TagKey<Item> resultTag;
private final FinishedRecipe recipe;
public Finished(TagKey<Item> resultTag, FinishedRecipe recipe) {
this.resultTag = resultTag;
this.recipe = recipe;
}
@Override
public void serializeRecipeData(JsonObject json) {
JsonObject recipeJson = new JsonObject();
this.recipe.serializeRecipeData(recipeJson);
recipeJson.addProperty("type", BuiltInRegistries.RECIPE_SERIALIZER.getKey(this.recipe.getType()).toString());
json.addProperty("result_tag", this.resultTag.location().toString());
json.add("recipe", recipeJson);
}
@Override
public ResourceLocation getId() {
return this.recipe.getId();
}
@Override
public RecipeSerializer<?> getType() {
return ERecipeSerializers.TAG_RESULT.get();
}
@Nullable
@Override
public JsonObject serializeAdvancement() {
return this.recipe.serializeAdvancement();
}
@Nullable
@Override
public ResourceLocation getAdvancementId() {
return this.recipe.getAdvancementId();
}
}
}

View File

@ -23,7 +23,10 @@ import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonSyntaxException;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.objects.ObjectImmutableList;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.util.GsonHelper;
import net.minecraft.util.RandomSource;
@ -92,10 +95,6 @@ public class WeightedList<T> {
return result;
}
public static <T> Builder<T> builder() {
return new Builder<>();
}
public static <T> WeightedList<T> fromNetwork(FriendlyByteBuf buffer, Function<FriendlyByteBuf, T> valueReader) {
int size = buffer.readVarInt();
Object[] values = new Object[size];
@ -142,6 +141,39 @@ public class WeightedList<T> {
return list.build();
}
@SuppressWarnings({"unchecked", "rawtypes"})
public static <T> Codec<WeightedList<T>> codec(Codec<T> valueCodec) {
return Entry.codec(valueCodec).listOf().xmap(entries -> {
var builder = WeightedList.<T>builder();
for (var entry : entries) {
builder.add(entry.weight, entry.value);
}
return builder.build();
}, list -> {
var entries = new Entry[list.values.length];
var entryList = new ObjectImmutableList<Entry<T>>(entries);
for (int i = 0; i < list.values.length; i++) {
entries[i] = new Entry(list.values[i], list.weights[i]);
}
return entryList;
});
}
// Used only for Codec
private record Entry<T>(T value, int weight) {
private static <T> Codec<Entry<T>> codec(Codec<T> valueCodec) {
return RecordCodecBuilder.create(instance -> instance.group(
valueCodec.fieldOf("value").forGetter(Entry::value),
Codec.INT.fieldOf("weight").forGetter(Entry::weight)
).apply(instance, Entry::new));
}
}
public static <T> Builder<T> builder() {
return new Builder<>();
}
public static class Builder<T> {
private final ArrayList<T> values = new ArrayList<>();
private final IntArrayList weights = new IntArrayList();

View File

@ -18,23 +18,27 @@
package thedarkcolour.exdeorum.recipe.barrel;
import com.google.gson.JsonObject;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.GsonHelper;
import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.item.crafting.RecipeSerializer;
import net.minecraft.world.item.crafting.RecipeType;
import thedarkcolour.exdeorum.recipe.RecipeUtil;
import thedarkcolour.exdeorum.recipe.CodecUtil;
import thedarkcolour.exdeorum.recipe.SingleIngredientRecipe;
import thedarkcolour.exdeorum.registry.ERecipeSerializers;
import thedarkcolour.exdeorum.registry.ERecipeTypes;
public class BarrelCompostRecipe extends SingleIngredientRecipe {
public static final Codec<BarrelCompostRecipe> CODEC = RecordCodecBuilder.create(instance -> instance.group(
CodecUtil.ingredientField(),
Codec.INT.fieldOf("volume").forGetter(BarrelCompostRecipe::getVolume)
).apply(instance, BarrelCompostRecipe::new));
private final int volume;
public BarrelCompostRecipe(ResourceLocation id, Ingredient ingredient, int volume) {
super(id, ingredient);
public BarrelCompostRecipe(Ingredient ingredient, int volume) {
super(ingredient);
this.volume = volume;
}
@ -54,12 +58,9 @@ public class BarrelCompostRecipe extends SingleIngredientRecipe {
}
public static class Serializer implements RecipeSerializer<BarrelCompostRecipe> {
@Override // Creates the recipe object from a JSON file
public BarrelCompostRecipe fromJson(ResourceLocation name, JsonObject json) {
Ingredient ingredient = RecipeUtil.readIngredient(json, "ingredient");
int volume = GsonHelper.getAsInt(json, "volume");
return new BarrelCompostRecipe(name, ingredient, volume);
@Override
public Codec<BarrelCompostRecipe> codec() {
return CODEC;
}
@Override
@ -69,11 +70,11 @@ public class BarrelCompostRecipe extends SingleIngredientRecipe {
}
@Override
public BarrelCompostRecipe fromNetwork(ResourceLocation name, FriendlyByteBuf buffer) {
public BarrelCompostRecipe fromNetwork(FriendlyByteBuf buffer) {
Ingredient ingredient = Ingredient.fromNetwork(buffer);
int volume = buffer.readVarInt();
return new BarrelCompostRecipe(name, ingredient, volume);
return new BarrelCompostRecipe(ingredient, volume);
}
}
}

View File

@ -18,11 +18,11 @@
package thedarkcolour.exdeorum.recipe.barrel;
import com.google.gson.JsonObject;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.core.RegistryAccess;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.GsonHelper;
import net.minecraft.world.Container;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
@ -31,33 +31,30 @@ import net.minecraft.world.item.crafting.RecipeSerializer;
import net.minecraft.world.item.crafting.RecipeType;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.material.Fluid;
import net.minecraftforge.registries.ForgeRegistries;
import org.jetbrains.annotations.Nullable;
import thedarkcolour.exdeorum.recipe.RecipeUtil;
import thedarkcolour.exdeorum.recipe.CodecUtil;
import thedarkcolour.exdeorum.registry.ERecipeSerializers;
import thedarkcolour.exdeorum.registry.ERecipeTypes;
import java.util.Objects;
// A recipe where two fluids are mixed together, rather than a fluid and an item.
// The additive must be 1000mB or a source block worth of liquid.
// The additive is not consumed, however. Additives placed in the world are not consumed,
// so it would be unfair to consume the handheld additive.
public class BarrelFluidMixingRecipe implements Recipe<Container> {
private final ResourceLocation id;
public final Fluid baseFluid;
public final int baseFluidAmount;
public final Fluid additiveFluid;
public final Item result;
public final boolean consumesAdditive;
public BarrelFluidMixingRecipe(ResourceLocation id, Fluid baseFluid, int baseFluidAmount, Fluid additiveFluid, Item result, boolean consumesAdditive) {
this.id = id;
this.baseFluid = baseFluid;
this.baseFluidAmount = baseFluidAmount;
this.additiveFluid = additiveFluid;
this.result = result;
this.consumesAdditive = consumesAdditive;
}
public record BarrelFluidMixingRecipe(
Fluid baseFluid,
int baseFluidAmount,
Fluid additiveFluid,
Item result,
boolean consumesAdditive
) implements Recipe<Container> {
public static final Codec<BarrelFluidMixingRecipe> CODEC = RecordCodecBuilder.create(instance -> instance.group(
CodecUtil.fluidField("base_fluid", BarrelFluidMixingRecipe::baseFluid),
Codec.INT.fieldOf("base_fluid_amount").forGetter(BarrelFluidMixingRecipe::baseFluidAmount),
CodecUtil.fluidField("additive_fluid", BarrelFluidMixingRecipe::baseFluid),
CodecUtil.itemField("result", BarrelFluidMixingRecipe::result),
Codec.BOOL.optionalFieldOf("base_fluid", false).forGetter(BarrelFluidMixingRecipe::consumesAdditive)
).apply(instance, BarrelFluidMixingRecipe::new));
@Override
public boolean matches(Container pContainer, Level pLevel) {
@ -79,11 +76,6 @@ public class BarrelFluidMixingRecipe implements Recipe<Container> {
return new ItemStack(this.result);
}
@Override
public ResourceLocation getId() {
return this.id;
}
@Override
public RecipeSerializer<?> getSerializer() {
return ERecipeSerializers.BARREL_FLUID_MIXING.get();
@ -96,34 +88,28 @@ public class BarrelFluidMixingRecipe implements Recipe<Container> {
public static class Serializer implements RecipeSerializer<BarrelFluidMixingRecipe> {
@Override
public BarrelFluidMixingRecipe fromJson(ResourceLocation id, JsonObject json) {
Fluid baseFluid = RecipeUtil.readFluid(json, "base_fluid");
int baseFluidAmount = GsonHelper.getAsInt(json, "base_fluid_amount");
Fluid additiveFluid = RecipeUtil.readFluid(json, "additive_fluid");
Item result = RecipeUtil.readItem(json, "result");
boolean consumesAdditive = GsonHelper.getAsBoolean(json, "consumes_additive");
return new BarrelFluidMixingRecipe(id, baseFluid, baseFluidAmount, additiveFluid, result, consumesAdditive);
public Codec<BarrelFluidMixingRecipe> codec() {
return CODEC;
}
@Override
public void toNetwork(FriendlyByteBuf buffer, BarrelFluidMixingRecipe recipe) {
buffer.writeRegistryId(ForgeRegistries.FLUIDS, recipe.baseFluid);
buffer.writeId(BuiltInRegistries.FLUID, recipe.baseFluid);
buffer.writeVarInt(recipe.baseFluidAmount);
buffer.writeRegistryId(ForgeRegistries.FLUIDS, recipe.additiveFluid);
buffer.writeRegistryId(ForgeRegistries.ITEMS, recipe.result);
buffer.writeId(BuiltInRegistries.FLUID, recipe.additiveFluid);
buffer.writeId(BuiltInRegistries.ITEM, recipe.result);
buffer.writeBoolean(recipe.consumesAdditive);
}
@Override
public @Nullable BarrelFluidMixingRecipe fromNetwork(ResourceLocation id, FriendlyByteBuf buffer) {
Fluid baseFluid = buffer.readRegistryId();
public BarrelFluidMixingRecipe fromNetwork(FriendlyByteBuf buffer) {
Fluid baseFluid = Objects.requireNonNull(buffer.readById(BuiltInRegistries.FLUID));
int baseFluidAmount = buffer.readVarInt();
Fluid additiveFluid = buffer.readRegistryId();
Item result = buffer.readRegistryId();
Fluid additiveFluid = Objects.requireNonNull(buffer.readById(BuiltInRegistries.FLUID));
Item result = Objects.requireNonNull(buffer.readById(BuiltInRegistries.ITEM));
boolean consumesAdditive = buffer.readBoolean();
return new BarrelFluidMixingRecipe(id, baseFluid, baseFluidAmount, additiveFluid, result, consumesAdditive);
return new BarrelFluidMixingRecipe(baseFluid, baseFluidAmount, additiveFluid, result, consumesAdditive);
}
}
}

View File

@ -18,11 +18,11 @@
package thedarkcolour.exdeorum.recipe.barrel;
import com.google.gson.JsonObject;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.core.RegistryAccess;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.GsonHelper;
import net.minecraft.world.Container;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
@ -31,26 +31,45 @@ import net.minecraft.world.item.crafting.RecipeSerializer;
import net.minecraft.world.item.crafting.RecipeType;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.material.Fluid;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.registries.ForgeRegistries;
import org.jetbrains.annotations.Nullable;
import thedarkcolour.exdeorum.recipe.RecipeUtil;
import net.neoforged.neoforge.fluids.FluidStack;
import thedarkcolour.exdeorum.recipe.CodecUtil;
import thedarkcolour.exdeorum.recipe.SingleIngredientRecipe;
import thedarkcolour.exdeorum.registry.ERecipeSerializers;
import thedarkcolour.exdeorum.registry.ERecipeTypes;
import java.util.Objects;
public class BarrelMixingRecipe extends SingleIngredientRecipe {
public static final Codec<BarrelMixingRecipe> CODEC = RecordCodecBuilder.create(instance -> instance.group(
CodecUtil.ingredientField(),
CodecUtil.fluidField("fluid", BarrelMixingRecipe::getFluid),
Codec.INT.fieldOf("fluid_amount").forGetter(BarrelMixingRecipe::getFluidAmount),
CodecUtil.itemField("result", BarrelMixingRecipe::getResult)
).apply(instance, BarrelMixingRecipe::new));
public final Fluid fluid;
public final int fluidAmount;
public final Item result;
public BarrelMixingRecipe(ResourceLocation id, Ingredient ingredient, Fluid fluid, int fluidAmount, Item result) {
super(id, ingredient);
public BarrelMixingRecipe(Ingredient ingredient, Fluid fluid, int fluidAmount, Item result) {
super(ingredient);
this.fluid = fluid;
this.fluidAmount = fluidAmount;
this.result = result;
}
public Fluid getFluid() {
return this.fluid;
}
public int getFluidAmount() {
return this.fluidAmount;
}
public Item getResult() {
return this.result;
}
// Do not use
@Override
@Deprecated
@ -79,31 +98,26 @@ public class BarrelMixingRecipe extends SingleIngredientRecipe {
public static class Serializer implements RecipeSerializer<BarrelMixingRecipe> {
@Override
public BarrelMixingRecipe fromJson(ResourceLocation id, JsonObject json) {
Ingredient ingredient = RecipeUtil.readIngredient(json, "ingredient");
Fluid fluid = RecipeUtil.readFluid(json, "fluid");
int fluidAmount = GsonHelper.getAsInt(json, "fluid_amount");
Item result = RecipeUtil.readItem(json, "result");
return new BarrelMixingRecipe(id, ingredient, fluid, fluidAmount, result);
public Codec<BarrelMixingRecipe> codec() {
return CODEC;
}
@Override
public void toNetwork(FriendlyByteBuf buffer, BarrelMixingRecipe recipe) {
recipe.ingredient.toNetwork(buffer);
buffer.writeRegistryId(ForgeRegistries.FLUIDS, recipe.fluid);
buffer.writeId(BuiltInRegistries.FLUID, recipe.fluid);
buffer.writeVarInt(recipe.fluidAmount);
buffer.writeRegistryId(ForgeRegistries.ITEMS, recipe.result);
buffer.writeId(BuiltInRegistries.ITEM, recipe.result);
}
@Override
public @Nullable BarrelMixingRecipe fromNetwork(ResourceLocation id, FriendlyByteBuf buffer) {
public BarrelMixingRecipe fromNetwork(FriendlyByteBuf buffer) {
Ingredient ingredient = Ingredient.fromNetwork(buffer);
Fluid fluid = buffer.readRegistryId();
Fluid fluid = Objects.requireNonNull(buffer.readById(BuiltInRegistries.FLUID));
int fluidAmount = buffer.readVarInt();
Item result = buffer.readRegistryId();
Item result = Objects.requireNonNull(buffer.readById(BuiltInRegistries.ITEM));
return new BarrelMixingRecipe(id, ingredient, fluid, fluidAmount, result);
return new BarrelMixingRecipe(ingredient, fluid, fluidAmount, result);
}
}
}

View File

@ -1,48 +0,0 @@
/*
* Ex Deorum
* Copyright (c) 2024 thedarkcolour
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package thedarkcolour.exdeorum.recipe.barrel;
import com.google.gson.JsonObject;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.item.crafting.RecipeSerializer;
import thedarkcolour.exdeorum.recipe.EFinishedRecipe;
import thedarkcolour.exdeorum.registry.ERecipeSerializers;
public class FinishedBarrelCompostRecipe extends EFinishedRecipe {
private final Ingredient ingredient;
private final int volume;
public FinishedBarrelCompostRecipe(ResourceLocation id, Ingredient ingredient, int volume) {
super(id);
this.ingredient = ingredient;
this.volume = volume;
}
@Override
public void serializeRecipeData(JsonObject json) {
json.add("ingredient", this.ingredient.toJson());
json.addProperty("volume", this.volume);
}
@Override
public RecipeSerializer<?> getType() {
return ERecipeSerializers.BARREL_COMPOST.get();
}
}

View File

@ -1,59 +0,0 @@
/*
* Ex Deorum
* Copyright (c) 2024 thedarkcolour
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package thedarkcolour.exdeorum.recipe.barrel;
import com.google.gson.JsonObject;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.crafting.RecipeSerializer;
import net.minecraft.world.level.material.Fluid;
import thedarkcolour.exdeorum.recipe.EFinishedRecipe;
import thedarkcolour.exdeorum.recipe.RecipeUtil;
import thedarkcolour.exdeorum.registry.ERecipeSerializers;
public class FinishedBarrelFluidMixingRecipe extends EFinishedRecipe {
private final Fluid baseFluid;
private final int baseFluidAmount;
private final Fluid additiveFluid;
private final Item result;
private final boolean consumesAdditive;
public FinishedBarrelFluidMixingRecipe(ResourceLocation id, Fluid baseFluid, int baseFluidAmount, Fluid additiveFluid, Item result, boolean consumesAdditive) {
super(id);
this.baseFluid = baseFluid;
this.baseFluidAmount = baseFluidAmount;
this.additiveFluid = additiveFluid;
this.result = result;
this.consumesAdditive = consumesAdditive;
}
@Override
public void serializeRecipeData(JsonObject json) {
json.addProperty("base_fluid", RecipeUtil.getFluidId(this.baseFluid));
json.addProperty("base_fluid_amount", this.baseFluidAmount);
json.addProperty("additive_fluid", RecipeUtil.getFluidId(this.additiveFluid));
json.addProperty("consumes_additive", this.consumesAdditive);
json.addProperty("result", RecipeUtil.writeItemJson(this.result));
}
@Override
public RecipeSerializer<?> getType() {
return ERecipeSerializers.BARREL_FLUID_MIXING.get();
}
}

View File

@ -1,57 +0,0 @@
/*
* Ex Deorum
* Copyright (c) 2024 thedarkcolour
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package thedarkcolour.exdeorum.recipe.barrel;
import com.google.gson.JsonObject;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.item.crafting.RecipeSerializer;
import net.minecraft.world.level.material.Fluid;
import thedarkcolour.exdeorum.recipe.EFinishedRecipe;
import thedarkcolour.exdeorum.registry.ERecipeSerializers;
public class FinishedBarrelMixingRecipe extends EFinishedRecipe {
private final Ingredient ingredient;
private final Fluid fluid;
private final int fluidAmount;
private final Item result;
public FinishedBarrelMixingRecipe(ResourceLocation id, Ingredient ingredient, Fluid fluid, int fluidAmount, Item result) {
super(id);
this.ingredient = ingredient;
this.fluid = fluid;
this.fluidAmount = fluidAmount;
this.result = result;
}
@Override
public void serializeRecipeData(JsonObject json) {
json.add("ingredient", this.ingredient.toJson());
json.addProperty("fluid", BuiltInRegistries.FLUID.getKey(this.fluid).toString());
json.addProperty("fluid_amount", this.fluidAmount);
json.addProperty("result", BuiltInRegistries.ITEM.getKey(this.result).toString());
}
@Override
public RecipeSerializer<?> getType() {
return ERecipeSerializers.BARREL_MIXING.get();
}
}

View File

@ -1,64 +0,0 @@
/*
* Ex Deorum
* Copyright (c) 2024 thedarkcolour
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package thedarkcolour.exdeorum.recipe.barrel;
import com.google.gson.JsonObject;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.crafting.RecipeSerializer;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.Fluid;
import thedarkcolour.exdeorum.recipe.BlockPredicate;
import thedarkcolour.exdeorum.recipe.EFinishedRecipe;
import thedarkcolour.exdeorum.recipe.RecipeUtil;
import thedarkcolour.exdeorum.recipe.WeightedList;
import thedarkcolour.exdeorum.registry.ERecipeSerializers;
public class FinishedFluidTransformationRecipe extends EFinishedRecipe {
private final Fluid baseFluid;
private final Fluid resultFluid;
private final int resultColor;
private final BlockPredicate catalyst;
private final WeightedList<BlockState> byproducts;
private final int duration;
public FinishedFluidTransformationRecipe(ResourceLocation id, Fluid baseFluid, Fluid resultFluid, int resultColor, BlockPredicate catalyst, WeightedList<BlockState> byproducts, int duration) {
super(id);
this.baseFluid = baseFluid;
this.resultFluid = resultFluid;
this.resultColor = resultColor;
this.catalyst = catalyst;
this.byproducts = byproducts;
this.duration = duration;
}
@Override
public void serializeRecipeData(JsonObject json) {
json.addProperty("base_fluid", RecipeUtil.getFluidId(this.baseFluid));
json.addProperty("result_fluid", RecipeUtil.getFluidId(this.resultFluid));
json.addProperty("result_color", this.resultColor);
json.addProperty("duration", this.duration);
json.add("catalyst", this.catalyst.toJson());
json.add("byproducts", this.byproducts.toJson(RecipeUtil::writeBlockState));
}
@Override
public RecipeSerializer<?> getType() {
return ERecipeSerializers.BARREL_FLUID_TRANSFORMATION.get();
}
}

View File

@ -18,13 +18,11 @@
package thedarkcolour.exdeorum.recipe.barrel;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonSyntaxException;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.core.RegistryAccess;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.GsonHelper;
import net.minecraft.world.Container;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.Recipe;
@ -34,10 +32,8 @@ import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.Fluid;
import net.minecraftforge.registries.ForgeRegistries;
import org.jetbrains.annotations.Nullable;
import thedarkcolour.exdeorum.ExDeorum;
import thedarkcolour.exdeorum.recipe.BlockPredicate;
import thedarkcolour.exdeorum.recipe.CodecUtil;
import thedarkcolour.exdeorum.recipe.RecipeUtil;
import thedarkcolour.exdeorum.recipe.WeightedList;
import thedarkcolour.exdeorum.registry.ERecipeSerializers;
@ -46,25 +42,22 @@ import thedarkcolour.exdeorum.registry.ERecipeTypes;
import java.util.Objects;
// todo consider NBT tag of input fluid?
public class FluidTransformationRecipe implements Recipe<Container> {
private final ResourceLocation id;
public final Fluid baseFluid;
public final Fluid resultFluid;
public final int resultColor;
public final BlockPredicate catalyst;
public final WeightedList<BlockState> byproducts;
public final int duration;
public FluidTransformationRecipe(ResourceLocation id, Fluid baseFluid, Fluid resultFluid, int resultColor, BlockPredicate catalyst, WeightedList<BlockState> byproducts, int duration) {
this.id = id;
this.baseFluid = baseFluid;
this.resultFluid = resultFluid;
this.resultColor = resultColor;
this.catalyst = catalyst;
this.byproducts = byproducts;
this.duration = duration;
}
public record FluidTransformationRecipe(
Fluid baseFluid,
Fluid resultFluid,
int resultColor,
BlockPredicate catalyst,
WeightedList<BlockState> byproducts,
int duration
) implements Recipe<Container> {
public static final Codec<FluidTransformationRecipe> CODEC = RecordCodecBuilder.create(instance -> instance.group(
CodecUtil.fluidField("base_fluid", FluidTransformationRecipe::baseFluid),
CodecUtil.fluidField("result_fluid", FluidTransformationRecipe::resultFluid),
Codec.INT.fieldOf("result_color").forGetter(FluidTransformationRecipe::resultColor),
BlockPredicate.CODEC.fieldOf("catalyst").forGetter(FluidTransformationRecipe::catalyst),
WeightedList.codec(Codec.STRING.xmap(RecipeUtil::parseBlockState, RecipeUtil::writeBlockState)).fieldOf("byproducts").forGetter(FluidTransformationRecipe::byproducts),
Codec.INT.fieldOf("duration").forGetter(FluidTransformationRecipe::duration)
).apply(instance, FluidTransformationRecipe::new));
@Override
public boolean matches(Container pContainer, Level pLevel) {
@ -86,11 +79,6 @@ public class FluidTransformationRecipe implements Recipe<Container> {
return ItemStack.EMPTY;
}
@Override
public ResourceLocation getId() {
return this.id;
}
@Override
public RecipeSerializer<?> getSerializer() {
return ERecipeSerializers.BARREL_FLUID_TRANSFORMATION.get();
@ -103,32 +91,14 @@ public class FluidTransformationRecipe implements Recipe<Container> {
public static class Serializer implements RecipeSerializer<FluidTransformationRecipe> {
@Override
public FluidTransformationRecipe fromJson(ResourceLocation id, JsonObject json) {
Fluid baseFluid = RecipeUtil.readFluid(json, "base_fluid");
Fluid resultFluid = RecipeUtil.readFluid(json, "result_fluid");
int resultColor = GsonHelper.getAsInt(json, "result_color");
int duration = GsonHelper.getAsInt(json, "duration");
BlockPredicate catalyst = RecipeUtil.readBlockPredicate(id, json, "catalyst");
var byproducts = WeightedList.fromJson(json.getAsJsonArray("byproducts"), element -> {
if (element.isJsonPrimitive()) {
return RecipeUtil.parseBlockState(element.getAsString());
} else {
return null;
}
});
if (catalyst == null) {
throw new JsonSyntaxException("Failed to read barrel fluid transformation recipe catalyst");
}
if (byproducts == null) {
throw new JsonSyntaxException("Failed to read barrel fluid transformation recipe byproducts");
}
return new FluidTransformationRecipe(id, baseFluid, resultFluid, resultColor, catalyst, byproducts, duration);
public Codec<FluidTransformationRecipe> codec() {
return CODEC;
}
@Override
public void toNetwork(FriendlyByteBuf buffer, FluidTransformationRecipe recipe) {
buffer.writeRegistryId(ForgeRegistries.FLUIDS, recipe.baseFluid);
buffer.writeRegistryId(ForgeRegistries.FLUIDS, recipe.resultFluid);
buffer.writeId(BuiltInRegistries.FLUID, recipe.baseFluid);
buffer.writeId(BuiltInRegistries.FLUID, recipe.resultFluid);
buffer.writeInt(recipe.resultColor);
recipe.catalyst.toNetwork(buffer);
recipe.byproducts.toNetwork(buffer, (buf, state) -> buf.writeId(Block.BLOCK_STATE_REGISTRY, state));
@ -136,30 +106,15 @@ public class FluidTransformationRecipe implements Recipe<Container> {
}
@Override
public @Nullable FluidTransformationRecipe fromNetwork(ResourceLocation id, FriendlyByteBuf buffer) {
Fluid baseFluid = buffer.readRegistryId();
Fluid resultFluid = buffer.readRegistryId();
public FluidTransformationRecipe fromNetwork(FriendlyByteBuf buffer) {
Fluid baseFluid = Objects.requireNonNull(buffer.readById(BuiltInRegistries.FLUID));
Fluid resultFluid = Objects.requireNonNull(buffer.readById(BuiltInRegistries.FLUID));
int resultColor = buffer.readInt();
BlockPredicate catalyst = RecipeUtil.readBlockPredicateNetwork(id, buffer);
if (catalyst == null) {
return null;
}
BlockPredicate catalyst = RecipeUtil.readBlockPredicateNetwork(buffer);
WeightedList<BlockState> byproducts = WeightedList.fromNetwork(buffer, buf -> buf.readById(Block.BLOCK_STATE_REGISTRY));
int duration = buffer.readVarInt();
return new FluidTransformationRecipe(id, baseFluid, resultFluid, resultColor, catalyst, byproducts, duration);
return new FluidTransformationRecipe(baseFluid, resultFluid, resultColor, catalyst, byproducts, duration);
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
FluidTransformationRecipe that = (FluidTransformationRecipe) o;
return this.resultColor == that.resultColor && this.duration == that.duration && Objects.equals(this.id, that.id) && Objects.equals(this.baseFluid, that.baseFluid) && Objects.equals(this.resultFluid, that.resultFluid) && Objects.equals(this.catalyst, that.catalyst) && Objects.equals(this.byproducts, that.byproducts);
}
@Override
public int hashCode() {
return Objects.hash(this.id, this.baseFluid, this.resultFluid, this.resultColor, this.catalyst, this.byproducts, this.duration);
}
}

View File

@ -52,8 +52,9 @@ public class BarrelFluidMixingRecipeCache {
private void buildRecipes() {
this.recipes = new HashMap<>();
for (var recipe : this.recipeManager.byType(ERecipeTypes.BARREL_FLUID_MIXING.get()).values()) {
this.recipes.computeIfAbsent(recipe.baseFluid, key -> new HashMap<>()).put(recipe.additiveFluid, recipe);
for (var holder : this.recipeManager.byType(ERecipeTypes.BARREL_FLUID_MIXING.get()).values()) {
var recipe = holder.value();
this.recipes.computeIfAbsent(recipe.baseFluid(), key -> new HashMap<>()).put(recipe.additiveFluid(), recipe);
}
this.recipeManager = null;

View File

@ -49,8 +49,8 @@ public class CrookRecipeCache {
var tempRecipes = new HashMap<BlockState, HashSet<CrookRecipe>>();
for (var recipe : this.recipeManager.byType(ERecipeTypes.CROOK.get()).values()) {
recipe.blockPredicate().possibleStates().forEach(state -> {
tempRecipes.computeIfAbsent(state, key -> new HashSet<>()).add(recipe);
recipe.value().blockPredicate().possibleStates().forEach(state -> {
tempRecipes.computeIfAbsent(state, key -> new HashSet<>()).add(recipe.value());
});
}
// map equal sets to a single list object instead of using a bunch of duplicate sets

View File

@ -45,8 +45,9 @@ public class CrucibleHeatRecipeCache {
private void buildRecipes() {
this.recipes = new Object2IntOpenHashMap<>();
for (var recipe : this.recipeManager.byType(ERecipeTypes.CRUCIBLE_HEAT_SOURCE.get()).values()) {
recipe.blockPredicate().possibleStates().forEach(state -> recipes.put(state, recipe.heatValue()));
for (var holder : this.recipeManager.byType(ERecipeTypes.CRUCIBLE_HEAT_SOURCE.get()).values()) {
var recipe = holder.value();
recipe.blockPredicate().possibleStates().forEach(state -> this.recipes.put(state, recipe.heatValue()));
}
this.recipeManager = null;

View File

@ -52,9 +52,10 @@ public class FluidTransformationRecipeCache {
private void buildRecipes() {
this.recipes = new HashMap<>();
for (var recipe : this.recipeManager.byType(ERecipeTypes.BARREL_FLUID_TRANSFORMATION.get()).values()) {
recipe.catalyst.possibleStates().forEach(state -> {
this.recipes.computeIfAbsent(state, key -> new HashMap<>()).put(recipe.baseFluid, recipe);
for (var holder : this.recipeManager.byType(ERecipeTypes.BARREL_FLUID_TRANSFORMATION.get()).values()) {
var recipe = holder.value();
recipe.catalyst().possibleStates().forEach(state -> {
this.recipes.computeIfAbsent(state, key -> new HashMap<>()).put(recipe.baseFluid(), recipe);
});
}

View File

@ -51,7 +51,8 @@ public class SieveRecipeCache {
private void buildRecipes() {
// Group recipes based on their mesh
var tempMap = new HashMap<Item, List<SieveRecipe>>();
for (var recipe : this.recipeManager.byType(ERecipeTypes.SIEVE.get()).values()) {
for (var holder : this.recipeManager.byType(ERecipeTypes.SIEVE.get()).values()) {
var recipe = holder.value();
tempMap.computeIfAbsent(recipe.mesh, k -> new ArrayList<>()).add(recipe);
}
this.meshCaches = new HashMap<>();

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;
@ -39,20 +40,12 @@ public class SingleIngredientRecipeCache<T extends SingleIngredientRecipe> {
private Map<Item, T> simpleRecipes;
@Nullable
private List<T> complexRecipes;
@Nullable
private Collection<T> allRecipes;
private boolean trackAllRecipes;
public SingleIngredientRecipeCache(RecipeManager recipeManager, Supplier<RecipeType<T>> recipeType) {
this.recipeType = recipeType;
this.recipeManager = recipeManager;
}
public SingleIngredientRecipeCache<T> trackAllRecipes() {
this.trackAllRecipes = true;
return this;
}
@Nullable
public T getRecipe(Item item) {
return getRecipe(new ItemStack(item));
@ -81,21 +74,12 @@ public class SingleIngredientRecipeCache<T extends SingleIngredientRecipe> {
}
}
public Collection<T> getAllRecipes() {
if (this.simpleRecipes == null) {
buildRecipes();
}
return this.allRecipes;
}
/**
* Called when this recipe cache is first queried. First, scans available recipes for recipes with "simple"
* ingredients that do not check an item's NBT. All of these recipes are added to the {@link #simpleRecipes}
* map, which is indexed by the item(s) the recipe's ingredient accepts. Recipes whose ingredients are "complex"
* and consider an item's NBT are added to the separate {@link #complexRecipes} list. Unlike simpleRecipes,
* complexRecipes may be null after this method call if no complex recipes are found. The {@link #allRecipes}
* field contains all recipes, simple and complex, in one collection. If this recipe cache is not set to track
* all recipes by {@link #trackAllRecipes}, then this list is discarded afterward. Finally, after all recipes
* complexRecipes may be null after this method call if no complex recipes are found. Finally, after all recipes
* have been scanned, the {@link #recipeManager} is set to null, since it is no longer needed.
*/
private void buildRecipes() {
@ -104,7 +88,8 @@ public class SingleIngredientRecipeCache<T extends SingleIngredientRecipe> {
var allRecipes = this.recipeManager.byType(this.recipeType.get()).values();
for (var recipe : allRecipes) {
for (var holder : allRecipes) {
var recipe = holder.value();
var ingredient = recipe.getIngredient();
if (ingredient.isSimple()) {
@ -120,10 +105,6 @@ public class SingleIngredientRecipeCache<T extends SingleIngredientRecipe> {
if (this.complexRecipes.isEmpty()) {
this.complexRecipes = null;
}
// Track list of simple and complex recipes (only used by hammer so far)
if (this.trackAllRecipes) {
this.allRecipes = allRecipes;
}
this.recipeManager = null;
}

View File

@ -18,25 +18,33 @@
package thedarkcolour.exdeorum.recipe.crook;
import com.google.gson.JsonObject;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.core.RegistryAccess;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.Container;
import net.minecraft.world.item.Item;
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.RecipeSerializer;
import net.minecraft.world.item.crafting.RecipeType;
import net.minecraft.world.level.Level;
import thedarkcolour.exdeorum.recipe.BlockPredicate;
import thedarkcolour.exdeorum.recipe.CodecUtil;
import thedarkcolour.exdeorum.recipe.RecipeUtil;
import thedarkcolour.exdeorum.registry.ERecipeSerializers;
import thedarkcolour.exdeorum.registry.ERecipeTypes;
public record CrookRecipe(ResourceLocation id, BlockPredicate blockPredicate, Item result, float chance) implements Recipe<Container> {
import java.util.Objects;
public record CrookRecipe(BlockPredicate blockPredicate, Item result, float chance) implements Recipe<Container> {
public static final Codec<CrookRecipe> CODEC = RecordCodecBuilder.create(instance -> instance.group(
BlockPredicate.CODEC.fieldOf("block_predicate").forGetter(CrookRecipe::blockPredicate),
CodecUtil.itemField("result", CrookRecipe::result),
Codec.FLOAT.fieldOf("chance").forGetter(CrookRecipe::chance)
).apply(instance, CrookRecipe::new));
@Override
public boolean matches(Container pContainer, Level pLevel) {
return false;
@ -57,11 +65,6 @@ public record CrookRecipe(ResourceLocation id, BlockPredicate blockPredicate, It
return new ItemStack(this.result);
}
@Override
public ResourceLocation getId() {
return this.id;
}
@Override
public RecipeSerializer<?> getSerializer() {
return ERecipeSerializers.CROOK.get();
@ -72,32 +75,19 @@ public record CrookRecipe(ResourceLocation id, BlockPredicate blockPredicate, It
return ERecipeTypes.CROOK.get();
}
@SuppressWarnings("deprecation")
public static class Serializer implements RecipeSerializer<CrookRecipe> {
@Override
public CrookRecipe fromJson(ResourceLocation id, JsonObject json) {
BlockPredicate blockPredicate = RecipeUtil.readBlockPredicate(id, json, "block_predicate");
if (blockPredicate == null) return null;
Item result = RecipeUtil.readItem(json, "result");
float chance = json.get("chance").getAsFloat();
return new CrookRecipe(id, blockPredicate, result, chance);
public Codec<CrookRecipe> codec() {
return CODEC;
}
@Override
public CrookRecipe fromNetwork(ResourceLocation id, FriendlyByteBuf buffer) {
BlockPredicate blockPredicate = RecipeUtil.readBlockPredicateNetwork(id, buffer);
if (blockPredicate == null) return null;
Item result = buffer.readById(BuiltInRegistries.ITEM);
if (result == null || result == Items.AIR) {
return null;
}
public CrookRecipe fromNetwork(FriendlyByteBuf buffer) {
BlockPredicate blockPredicate = RecipeUtil.readBlockPredicateNetwork(buffer);
Item result = Objects.requireNonNull(buffer.readById(BuiltInRegistries.ITEM));
float chance = buffer.readFloat();
return new CrookRecipe(id, blockPredicate, result, chance);
return new CrookRecipe(blockPredicate, result, chance);
}
@Override

View File

@ -1,53 +0,0 @@
/*
* Ex Deorum
* Copyright (c) 2024 thedarkcolour
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package thedarkcolour.exdeorum.recipe.crook;
import com.google.gson.JsonObject;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.crafting.RecipeSerializer;
import thedarkcolour.exdeorum.recipe.BlockPredicate;
import thedarkcolour.exdeorum.recipe.EFinishedRecipe;
import thedarkcolour.exdeorum.registry.ERecipeSerializers;
public class FinishedCrookRecipe extends EFinishedRecipe {
private final BlockPredicate predicate;
private final Item result;
private final float chance;
public FinishedCrookRecipe(ResourceLocation id, BlockPredicate predicate, Item result, float chance) {
super(id);
this.predicate = predicate;
this.result = result;
this.chance = chance;
}
@Override
public void serializeRecipeData(JsonObject json) {
json.add("block_predicate", this.predicate.toJson());
json.addProperty("result", BuiltInRegistries.ITEM.getKey(this.result).toString());
json.addProperty("chance", this.chance);
}
@Override
public RecipeSerializer<?> getType() {
return ERecipeSerializers.CROOK.get();
}
}

View File

@ -18,10 +18,10 @@
package thedarkcolour.exdeorum.recipe.crucible;
import com.google.gson.JsonObject;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.core.RegistryAccess;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.Container;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.Recipe;
@ -33,7 +33,12 @@ import thedarkcolour.exdeorum.recipe.RecipeUtil;
import thedarkcolour.exdeorum.registry.ERecipeSerializers;
import thedarkcolour.exdeorum.registry.ERecipeTypes;
public record CrucibleHeatRecipe(ResourceLocation id, BlockPredicate blockPredicate, int heatValue) implements Recipe<Container> {
public record CrucibleHeatRecipe(BlockPredicate blockPredicate, int heatValue) implements Recipe<Container> {
public static final Codec<CrucibleHeatRecipe> CODEC = RecordCodecBuilder.create(instance -> instance.group(
BlockPredicate.CODEC.fieldOf("block_predicate").forGetter(CrucibleHeatRecipe::blockPredicate),
Codec.INT.fieldOf("heat_value").forGetter(CrucibleHeatRecipe::heatValue)
).apply(instance, CrucibleHeatRecipe::new));
@Override
public boolean matches(Container pContainer, Level pLevel) {
return false;
@ -54,11 +59,6 @@ public record CrucibleHeatRecipe(ResourceLocation id, BlockPredicate blockPredic
return ItemStack.EMPTY;
}
@Override
public ResourceLocation getId() {
return this.id;
}
@Override
public RecipeSerializer<?> getSerializer() {
return ERecipeSerializers.CRUCIBLE_HEAT_SOURCE.get();
@ -71,19 +71,15 @@ public record CrucibleHeatRecipe(ResourceLocation id, BlockPredicate blockPredic
public static class Serializer implements RecipeSerializer<CrucibleHeatRecipe> {
@Override
public CrucibleHeatRecipe fromJson(ResourceLocation id, JsonObject json) {
BlockPredicate blockPredicate = RecipeUtil.readBlockPredicate(id, json, "block_predicate");
if (blockPredicate == null) return null;
int heatValue = json.get("heat_value").getAsInt();
return new CrucibleHeatRecipe(id, blockPredicate, heatValue);
public Codec<CrucibleHeatRecipe> codec() {
return CODEC;
}
@Override
public CrucibleHeatRecipe fromNetwork(ResourceLocation id, FriendlyByteBuf buffer) {
BlockPredicate blockPredicate = RecipeUtil.readBlockPredicateNetwork(id, buffer);
if (blockPredicate == null) return null;
public CrucibleHeatRecipe fromNetwork(FriendlyByteBuf buffer) {
BlockPredicate blockPredicate = RecipeUtil.readBlockPredicateNetwork(buffer);
int heatValue = buffer.readVarInt();
return new CrucibleHeatRecipe(id, blockPredicate, heatValue);
return new CrucibleHeatRecipe(blockPredicate, heatValue);
}
@Override

Some files were not shown because too many files have changed in this diff Show More