From a30721d9b852a05acfcdeb0f470dcbb24522ba09 Mon Sep 17 00:00:00 2001 From: Eli Gibbs Date: Tue, 3 Feb 2026 14:47:35 -0500 Subject: [PATCH] pipes (not done for fabric) and tank (maybe for fabric?) --- .../net/cmr/jurassicrevived/CommonClass.java | 2 + .../block/custom/PipeBlock.java | 16 +- .../block/entity/custom/PipeBlockEntity.java | 229 ++++++++++++++---- .../block/entity/custom/TankBlockEntity.java | 221 ++++++++++++++++- .../cmr/jurassicrevived/config/JRConfig.java | 2 +- .../networking/ModPackets.java | 121 +++++++++ .../jurassicrevived/platform/Services.java | 4 + .../platform/services/IItemFluidHelper.java | 15 ++ .../platform/services/ITransferHelper.java | 16 ++ .../transfer/InternalFluidHandler.java | 10 + .../transfer/InternalFluidHandlerAdapter.java | 33 +++ .../transfer/InternalFluidProvider.java | 8 + .../transfer/PlatformEnergyHandler.java | 6 + .../transfer/PlatformFluidHandler.java | 9 + .../transfer/PlatformItemHandler.java | 9 + .../screen/custom/TankMenu.java | 79 +++++- .../screen/custom/TankScreen.java | 4 +- .../models/block/generator_lit.json | 208 ++++++++++++++++ .../models/block/white_generator_lit.json | 208 ++++++++++++++++ fabricmc/build.gradle.kts | 8 + .../java/net/cmr/jurassicrevived/JRMod.java | 57 ++++- .../platform/FabricEnergyWrapper.java | 33 +++ .../platform/FabricItemFluidHelper.java | 103 ++++++++ .../platform/FabricTransferHelper.java | 146 +++++++++++ ...revived.platform.services.IItemFluidHelper | 1 + ...crevived.platform.services.ITransferHelper | 1 + gradle.properties | 5 +- .../jurassicrevived/event/ForgeEvents.java | 106 ++++++++ .../platform/ForgeEnergyStorage.java | 36 +++ .../platform/ForgeItemFluidHelper.java | 79 ++++++ .../platform/ForgeTankFluidAdapter.java | 49 ++++ .../platform/ForgeTransferHelper.java | 148 +++++++++++ ...revived.platform.services.IItemFluidHelper | 1 + ...crevived.platform.services.ITransferHelper | 1 + .../jurassicrevived/event/NeoForgeEvents.java | 80 ++++-- .../platform/NeoForgeItemFluidHelper.java | 84 +++++++ .../platform/NeoForgeTransferHelper.java | 161 ++++++++++++ ...revived.platform.services.IItemFluidHelper | 1 + ...crevived.platform.services.ITransferHelper | 1 + 39 files changed, 2201 insertions(+), 100 deletions(-) create mode 100644 common/src/main/java/net/cmr/jurassicrevived/networking/ModPackets.java create mode 100644 common/src/main/java/net/cmr/jurassicrevived/platform/services/IItemFluidHelper.java create mode 100644 common/src/main/java/net/cmr/jurassicrevived/platform/services/ITransferHelper.java create mode 100644 common/src/main/java/net/cmr/jurassicrevived/platform/transfer/InternalFluidHandler.java create mode 100644 common/src/main/java/net/cmr/jurassicrevived/platform/transfer/InternalFluidHandlerAdapter.java create mode 100644 common/src/main/java/net/cmr/jurassicrevived/platform/transfer/InternalFluidProvider.java create mode 100644 common/src/main/java/net/cmr/jurassicrevived/platform/transfer/PlatformEnergyHandler.java create mode 100644 common/src/main/java/net/cmr/jurassicrevived/platform/transfer/PlatformFluidHandler.java create mode 100644 common/src/main/java/net/cmr/jurassicrevived/platform/transfer/PlatformItemHandler.java create mode 100644 common/src/main/resources/assets/jurassicrevived/models/block/generator_lit.json create mode 100644 common/src/main/resources/assets/jurassicrevived/models/block/white_generator_lit.json create mode 100644 fabricmc/src/main/java/net/cmr/jurassicrevived/platform/FabricEnergyWrapper.java create mode 100644 fabricmc/src/main/java/net/cmr/jurassicrevived/platform/FabricItemFluidHelper.java create mode 100644 fabricmc/src/main/java/net/cmr/jurassicrevived/platform/FabricTransferHelper.java create mode 100644 fabricmc/src/main/resources/META-INF/services/net.cmr.jurassicrevived.platform.services.IItemFluidHelper create mode 100644 fabricmc/src/main/resources/META-INF/services/net.cmr.jurassicrevived.platform.services.ITransferHelper create mode 100644 minecraftforge/src/main/java/net/cmr/jurassicrevived/event/ForgeEvents.java create mode 100644 minecraftforge/src/main/java/net/cmr/jurassicrevived/platform/ForgeEnergyStorage.java create mode 100644 minecraftforge/src/main/java/net/cmr/jurassicrevived/platform/ForgeItemFluidHelper.java create mode 100644 minecraftforge/src/main/java/net/cmr/jurassicrevived/platform/ForgeTankFluidAdapter.java create mode 100644 minecraftforge/src/main/java/net/cmr/jurassicrevived/platform/ForgeTransferHelper.java create mode 100644 minecraftforge/src/main/resources/META-INF/services/net.cmr.jurassicrevived.platform.services.IItemFluidHelper create mode 100644 minecraftforge/src/main/resources/META-INF/services/net.cmr.jurassicrevived.platform.services.ITransferHelper create mode 100644 neoforge/src/main/java/net/cmr/jurassicrevived/platform/NeoForgeItemFluidHelper.java create mode 100644 neoforge/src/main/java/net/cmr/jurassicrevived/platform/NeoForgeTransferHelper.java create mode 100644 neoforge/src/main/resources/META-INF/services/net.cmr.jurassicrevived.platform.services.IItemFluidHelper create mode 100644 neoforge/src/main/resources/META-INF/services/net.cmr.jurassicrevived.platform.services.ITransferHelper diff --git a/common/src/main/java/net/cmr/jurassicrevived/CommonClass.java b/common/src/main/java/net/cmr/jurassicrevived/CommonClass.java index 3cc00cf..9e6db74 100644 --- a/common/src/main/java/net/cmr/jurassicrevived/CommonClass.java +++ b/common/src/main/java/net/cmr/jurassicrevived/CommonClass.java @@ -7,6 +7,7 @@ import net.cmr.jurassicrevived.config.JRConfigManager; import net.cmr.jurassicrevived.entity.ModEntities; import net.cmr.jurassicrevived.item.ModCreativeTabs; import net.cmr.jurassicrevived.item.ModItems; +import net.cmr.jurassicrevived.networking.ModPackets; import net.cmr.jurassicrevived.platform.Services; import net.cmr.jurassicrevived.recipe.ModRecipes; import net.cmr.jurassicrevived.screen.ModMenuTypes; @@ -68,5 +69,6 @@ public class CommonClass ModEvents.init(); ModSounds.register(); + ModPackets.register(); } } \ No newline at end of file diff --git a/common/src/main/java/net/cmr/jurassicrevived/block/custom/PipeBlock.java b/common/src/main/java/net/cmr/jurassicrevived/block/custom/PipeBlock.java index 26ad7a4..0983305 100644 --- a/common/src/main/java/net/cmr/jurassicrevived/block/custom/PipeBlock.java +++ b/common/src/main/java/net/cmr/jurassicrevived/block/custom/PipeBlock.java @@ -5,6 +5,7 @@ import net.cmr.jurassicrevived.block.entity.custom.PipeBlockEntity; import net.cmr.jurassicrevived.block.entity.energy.ModEnergyUtil; import net.cmr.jurassicrevived.config.JRConfigManager; import net.cmr.jurassicrevived.item.ModItems; +import net.cmr.jurassicrevived.platform.Services; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.util.Mth; @@ -198,6 +199,15 @@ public class PipeBlock extends Block implements EntityBlock, SimpleWaterloggedBl }; } + if (level instanceof Level lvl) { + boolean platformHasHandler = switch (this.transport) { + case ITEMS -> Services.TRANSFER.getItemHandler(lvl, neighborPos, dir.getOpposite()).isPresent(); + case FLUIDS -> Services.TRANSFER.getFluidHandler(lvl, neighborPos, dir.getOpposite()).isPresent(); + case ENERGY -> Services.TRANSFER.getEnergyHandler(lvl, neighborPos, dir.getOpposite()).isPresent(); + }; + hasCommonConnection = hasCommonConnection || platformHasHandler; + } + if (hasCommonConnection) { if (existing == ConnectionType.CONNECTOR_PULL) { return ConnectionType.CONNECTOR_PULL; @@ -352,14 +362,14 @@ public class PipeBlock extends Block implements EntityBlock, SimpleWaterloggedBl } public int getMaxItemsPerTick() { - return Math.max(0, JRConfigManager.get().itemsPerSecond / 20); + return Math.max(1, JRConfigManager.get().itemsPerSecond / 20); } public int getMaxFluidPerTick() { - return Math.max(0, JRConfigManager.get().milliBucketsPerSecond / 20); + return Math.max(1, JRConfigManager.get().milliBucketsPerSecond / 20); } public int getMaxEnergyPerTick() { - return Math.max(0, JRConfigManager.get().fePerSecond / 20); + return Math.max(1, JRConfigManager.get().fePerSecond / 20); } } \ No newline at end of file diff --git a/common/src/main/java/net/cmr/jurassicrevived/block/entity/custom/PipeBlockEntity.java b/common/src/main/java/net/cmr/jurassicrevived/block/entity/custom/PipeBlockEntity.java index 9937bc7..5bc8138 100644 --- a/common/src/main/java/net/cmr/jurassicrevived/block/entity/custom/PipeBlockEntity.java +++ b/common/src/main/java/net/cmr/jurassicrevived/block/entity/custom/PipeBlockEntity.java @@ -1,11 +1,16 @@ package net.cmr.jurassicrevived.block.entity.custom; +import dev.architectury.fluid.FluidStack; import net.cmr.jurassicrevived.block.custom.PipeBlock; import net.cmr.jurassicrevived.block.custom.PipeBlock.ConnectionType; import net.cmr.jurassicrevived.block.custom.PipeBlock.Transport; import net.cmr.jurassicrevived.block.entity.ModBlockEntities; import net.cmr.jurassicrevived.block.entity.energy.ModEnergyStorage; import net.cmr.jurassicrevived.block.entity.energy.ModEnergyUtil; +import net.cmr.jurassicrevived.platform.Services; +import net.cmr.jurassicrevived.platform.transfer.PlatformEnergyHandler; +import net.cmr.jurassicrevived.platform.transfer.PlatformFluidHandler; +import net.cmr.jurassicrevived.platform.transfer.PlatformItemHandler; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.Container; @@ -16,7 +21,8 @@ import net.minecraft.world.level.block.state.BlockState; import java.util.*; -public class PipeBlockEntity extends BlockEntity { +public class PipeBlockEntity extends BlockEntity +{ private final Transport transport; @@ -39,9 +45,8 @@ public class PipeBlockEntity extends BlockEntity { PipeBlock block = (PipeBlock) state.getBlock(); int itemCap = block.getMaxItemsPerTick(); - // Fallback caps if Config is not ready - int fluidCap = 1000; - int energyCap = 1000; + int fluidCap = block.getMaxFluidPerTick(); + int energyCap = block.getMaxEnergyPerTick(); switch (be.transport) { case ITEMS -> transferItems(level, pos, state, itemCap); @@ -52,9 +57,12 @@ public class PipeBlockEntity extends BlockEntity { // ===== Network discovery ===== - private record PipeEndpoint(BlockPos pipePos, Direction side) {} + private record PipeEndpoint(BlockPos pipePos, Direction side) + { + } - private static class Network { + private static class Network + { final List sources = new ArrayList<>(); final List sinks = new ArrayList<>(); } @@ -99,73 +107,188 @@ public class PipeBlockEntity extends BlockEntity { private static void transferItems(Level level, BlockPos pos, BlockState state, int perTickLimit) { Network net = discoverNetwork(level, pos, Transport.ITEMS); - List outputs = new ArrayList<>(); - for (PipeEndpoint ep : net.sinks) { - BlockEntity be = level.getBlockEntity(ep.pipePos.relative(ep.side)); - if (be instanceof Container c) outputs.add(c); - } - if (outputs.isEmpty()) return; + if (net.sources.isEmpty() || net.sinks.isEmpty()) return; + + Map> sinksByPipe = indexSinksByPipe(net.sinks); int remaining = perTickLimit; - for (PipeEndpoint ep : net.sources) { + for (PipeEndpoint srcEp : net.sources) { if (remaining <= 0) break; - BlockEntity be = level.getBlockEntity(ep.pipePos.relative(ep.side)); - if (!(be instanceof Container src)) continue; - for (int i = 0; i < src.getContainerSize() && remaining > 0; i++) { - ItemStack stack = src.getItem(i); - if (stack.isEmpty()) continue; + BlockPos srcPos = srcEp.pipePos.relative(srcEp.side); + Direction srcSide = srcEp.side.getOpposite(); - ItemStack toMove = stack.copy(); - toMove.setCount(Math.min(stack.getCount(), remaining)); + PlatformItemHandler src = Services.TRANSFER + .getItemHandler(level, srcPos, srcSide) + .orElse(null); + if (src == null) continue; - for (Container out : outputs) { - // Logic to insert into vanilla container (simplified) - // You might want a helper for this - } - } + PipeEndpoint sinkEp = findNearestSink(level, srcEp.pipePos, sinksByPipe, Transport.ITEMS); + if (sinkEp == null) continue; + + BlockPos dstPos = sinkEp.pipePos.relative(sinkEp.side); + Direction dstSide = sinkEp.side.getOpposite(); + + PlatformItemHandler dst = Services.TRANSFER + .getItemHandler(level, dstPos, dstSide) + .orElse(null); + if (dst == null) continue; + + remaining = moveFromSourceToSingleTarget(src, dst, remaining); } } - // ===== Energy Transfer (Using Custom Energy System) ===== + private static PipeEndpoint findNearestSink( + Level level, + BlockPos startPipe, + Map> sinksByPipe, + Transport transport + ) { + ArrayDeque q = new ArrayDeque<>(); + HashSet seen = new HashSet<>(); + q.add(startPipe); + seen.add(startPipe); + + while (!q.isEmpty()) { + BlockPos p = q.removeFirst(); + + List sinksHere = sinksByPipe.get(p); + if (sinksHere != null && !sinksHere.isEmpty()) { + return sinksHere.get(0); + } + + BlockState st = level.getBlockState(p); + if (!(st.getBlock() instanceof PipeBlock pb) || pb.getTransport() != transport) continue; + + for (Direction d : Direction.values()) { + if (st.getValue(PipeBlock.getProp(d)) == ConnectionType.PIPE) { + BlockPos np = p.relative(d); + if (seen.add(np)) q.add(np); + } + } + } + return null; + } private static void transferEnergy(Level level, BlockPos pos, BlockState state, int perTickLimit) { Network net = discoverNetwork(level, pos, Transport.ENERGY); - List outputs = new ArrayList<>(); - for (PipeEndpoint ep : net.sinks) { - BlockEntity be = level.getBlockEntity(ep.pipePos.relative(ep.side)); - if (be instanceof ModEnergyUtil.EnergyProvider provider) { - ModEnergyStorage storage = provider.getEnergyStorage(ep.side.getOpposite()); - if (storage != null && storage.canReceive()) outputs.add(storage); - } - } - if (outputs.isEmpty()) return; + if (net.sources.isEmpty() || net.sinks.isEmpty()) return; + + Map> sinksByPipe = indexSinksByPipe(net.sinks); int remaining = perTickLimit; - for (PipeEndpoint ep : net.sources) { + for (PipeEndpoint srcEp : net.sources) { if (remaining <= 0) break; - BlockEntity be = level.getBlockEntity(ep.pipePos.relative(ep.side)); - if (be instanceof ModEnergyUtil.EnergyProvider provider) { - ModEnergyStorage src = provider.getEnergyStorage(ep.side.getOpposite()); - if (src == null || !src.canExtract()) continue; - int canExtract = src.extractEnergy(remaining, true); - if (canExtract <= 0) continue; + BlockPos srcPos = srcEp.pipePos.relative(srcEp.side); + Direction srcSide = srcEp.side.getOpposite(); - for (ModEnergyStorage out : outputs) { - int accepted = out.receiveEnergy(canExtract, true); - if (accepted > 0) { - int actuallyExtracted = src.extractEnergy(accepted, false); - out.receiveEnergy(actuallyExtracted, false); - remaining -= actuallyExtracted; - break; - } - } - } + PlatformEnergyHandler src = Services.TRANSFER + .getEnergyHandler(level, srcPos, srcSide) + .orElse(null); + if (src == null) continue; + + PipeEndpoint sinkEp = findNearestSink(level, srcEp.pipePos, sinksByPipe, Transport.ENERGY); + if (sinkEp == null) continue; + + BlockPos dstPos = sinkEp.pipePos.relative(sinkEp.side); + Direction dstSide = sinkEp.side.getOpposite(); + + PlatformEnergyHandler dst = Services.TRANSFER + .getEnergyHandler(level, dstPos, dstSide) + .orElse(null); + if (dst == null) continue; + + int available = src.extract(remaining, true); + if (available <= 0) continue; + + int accepted = dst.insert(available, true); + if (accepted <= 0) continue; + + int extracted = src.extract(accepted, false); + int inserted = dst.insert(extracted, false); + remaining -= inserted; } } private static void transferFluids(Level level, BlockPos pos, BlockState state, int perTickLimit) { - // Implementation would use Architectury FluidStack similarly to energy + Network net = discoverNetwork(level, pos, Transport.FLUIDS); + if (net.sources.isEmpty() || net.sinks.isEmpty()) return; + + Map> sinksByPipe = indexSinksByPipe(net.sinks); + + long remaining = perTickLimit; + for (PipeEndpoint srcEp : net.sources) { + if (remaining <= 0) break; + + BlockPos srcPos = srcEp.pipePos.relative(srcEp.side); + Direction srcSide = srcEp.side.getOpposite(); + + PlatformFluidHandler src = Services.TRANSFER + .getFluidHandler(level, srcPos, srcSide) + .orElse(null); + if (src == null) continue; + + PipeEndpoint sinkEp = findNearestSink(level, srcEp.pipePos, sinksByPipe, Transport.FLUIDS); + if (sinkEp == null) continue; + + BlockPos dstPos = sinkEp.pipePos.relative(sinkEp.side); + Direction dstSide = sinkEp.side.getOpposite(); + + PlatformFluidHandler dst = Services.TRANSFER + .getFluidHandler(level, dstPos, dstSide) + .orElse(null); + if (dst == null) continue; + + for (FluidStack candidate : src.getExtractableFluids()) { + if (candidate.isEmpty()) continue; + + long available = src.extract(candidate, remaining, true); + if (available <= 0) continue; + + long accepted = dst.insert(candidate, available, true); + if (accepted <= 0) continue; + + FluidStack toMove = candidate.copy(); + toMove.setAmount(accepted); + + long extracted = src.extract(toMove, accepted, false); + long inserted = dst.insert(toMove, extracted, false); + remaining -= inserted; + + if (remaining <= 0) break; + } + } + } + + private static Map> indexSinksByPipe(List sinks) { + Map> map = new HashMap<>(); + for (PipeEndpoint ep : sinks) { + map.computeIfAbsent(ep.pipePos, k -> new ArrayList<>()).add(ep); + } + return map; + } + + private static int moveFromSourceToSingleTarget(PlatformItemHandler src, PlatformItemHandler dst, int limit) { + int remaining = limit; + + for (ItemStack candidate : src.getExtractableStacks()) { + if (candidate.isEmpty()) continue; + + int available = src.extract(candidate, remaining, true); + if (available <= 0) continue; + + int accepted = dst.insert(candidate, available, true); + if (accepted <= 0) continue; + + int extracted = src.extract(candidate, accepted, false); + if (extracted <= 0) continue; + + int inserted = dst.insert(candidate, extracted, false); + remaining -= inserted; + + if (remaining <= 0) break; + } + return remaining; } } \ No newline at end of file diff --git a/common/src/main/java/net/cmr/jurassicrevived/block/entity/custom/TankBlockEntity.java b/common/src/main/java/net/cmr/jurassicrevived/block/entity/custom/TankBlockEntity.java index 4715381..4193f05 100644 --- a/common/src/main/java/net/cmr/jurassicrevived/block/entity/custom/TankBlockEntity.java +++ b/common/src/main/java/net/cmr/jurassicrevived/block/entity/custom/TankBlockEntity.java @@ -3,19 +3,29 @@ package net.cmr.jurassicrevived.block.entity.custom; import dev.architectury.fluid.FluidStack; import dev.architectury.registry.menu.ExtendedMenuProvider; import net.cmr.jurassicrevived.block.entity.ModBlockEntities; +import net.cmr.jurassicrevived.platform.transfer.InternalFluidHandler; +import net.cmr.jurassicrevived.platform.transfer.InternalFluidProvider; import net.cmr.jurassicrevived.screen.custom.TankMenu; +import net.cmr.jurassicrevived.config.JRConfigManager; +import net.cmr.jurassicrevived.platform.Services; +import net.cmr.jurassicrevived.platform.services.IItemFluidHelper; import net.minecraft.core.BlockPos; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtOps; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.game.ClientGamePacketListener; import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; +import net.minecraft.resources.ResourceLocation; import net.minecraft.world.Containers; import net.minecraft.world.SimpleContainer; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; +import net.minecraft.core.Direction; import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; @@ -25,7 +35,7 @@ import org.jetbrains.annotations.Nullable; /*import net.minecraft.core.HolderLookup; *///?} -public class TankBlockEntity extends BlockEntity implements ExtendedMenuProvider { +public class TankBlockEntity extends BlockEntity implements ExtendedMenuProvider, InternalFluidProvider { public final SimpleContainer itemHandler = new SimpleContainer(2) { @Override public void setChanged() { @@ -46,6 +56,66 @@ public class TankBlockEntity extends BlockEntity implements ExtendedMenuProvider private FluidStack fluidStack = FluidStack.empty(); private static final long CAPACITY = 64000; + public TankFluidHandler getTank(@Nullable Direction side) { + return tank; + } + + private final TankFluidHandler tank = new TankFluidHandler(); + + @Override + public InternalFluidHandler getFluidHandler(@Nullable Direction side) { + return tank; + } + + public class TankFluidHandler implements InternalFluidHandler { + @Override + public FluidStack getFluid() { + return fluidStack; + } + + @Override + public long getCapacity() { + return CAPACITY; + } + + public long fill(FluidStack stack, boolean simulate) { + if (stack.isEmpty()) return 0; + if (!fluidStack.isEmpty() && fluidStack.getFluid() != stack.getFluid()) return 0; + + long space = CAPACITY - fluidStack.getAmount(); + if (space <= 0) return 0; + + long toFill = Math.min(space, stack.getAmount()); + if (!simulate) { + fluidStack = FluidStack.create(stack.getFluid(), fluidStack.getAmount() + toFill); + setChanged(); + if (level != null && !level.isClientSide()) { + level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), 3); + } + } + return toFill; + } + + public FluidStack drain(long amount, boolean simulate) { + if (fluidStack.isEmpty() || amount <= 0) return FluidStack.empty(); + + long drained = Math.min(amount, fluidStack.getAmount()); + FluidStack out = FluidStack.create(fluidStack.getFluid(), drained); + + if (!simulate) { + long remaining = fluidStack.getAmount() - drained; + fluidStack = remaining > 0 + ? FluidStack.create(fluidStack.getFluid(), remaining) + : FluidStack.empty(); + setChanged(); + if (level != null && !level.isClientSide()) { + level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), 3); + } + } + return out; + } + } + public TankBlockEntity(BlockPos pos, BlockState blockState) { super(ModBlockEntities.TANK_BE.get(), pos, blockState); } @@ -83,6 +153,112 @@ public class TankBlockEntity extends BlockEntity implements ExtendedMenuProvider } public void tick(Level level, BlockPos blockPos, BlockState blockState) { + if (level.isClientSide) return; + + ItemStack input = itemHandler.getItem(0); + if (input.isEmpty()) return; + + ItemStack output = itemHandler.getItem(1); + + long rate = Math.max(1, JRConfigManager.get().milliBucketsPerSecond / 20); + IItemFluidHelper helper = Services.ITEM_FLUID; + + ItemStack inputOne = input.copy(); + inputOne.setCount(1); + + var containedOpt = helper.getContainedFluid(inputOne); + + if (containedOpt.isPresent() && !containedOpt.get().isEmpty()) { + FluidStack contained = containedOpt.get(); + long canFill = tank.fill(contained, true); + long toDrain = Math.min(rate, canFill); + if (toDrain <= 0) return; + + IItemFluidHelper.TransferResult drained = helper.drain(inputOne, toDrain, false); + + // If partial drain failed (amount 0), and we requested less than full capacity, try requesting full capacity + if (drained.amount() == 0 && toDrain < canFill) { + drained = helper.drain(inputOne, canFill, false); + } + + if (drained.amount() > 0) { + ItemStack resultStack = drained.stack(); + boolean emptyNow = helper.getContainedFluid(resultStack) + .map(FluidStack::isEmpty) + .orElse(true); + + if (emptyNow) { + if (canMoveToOutput(resultStack, output)) { + tank.fill(FluidStack.create(contained.getFluid(), drained.amount()), false); + input.shrink(1); + if (input.isEmpty()) { + itemHandler.setItem(0, ItemStack.EMPTY); + } else { + itemHandler.setChanged(); + } + addToOutput(resultStack, output); + } + } else { + if (input.getCount() == 1) { + tank.fill(FluidStack.create(contained.getFluid(), drained.amount()), false); + itemHandler.setItem(0, resultStack); + } + } + } + } else { + FluidStack tankFluid = tank.getFluid(); + if (tankFluid.isEmpty()) return; + + long toFill = Math.min(rate, tankFluid.getAmount()); + IItemFluidHelper.TransferResult filled = helper.fill(inputOne, tankFluid, toFill, false); + + // If partial fill failed, and we requested less than available fluid, try requesting more + if (filled.amount() == 0 && toFill < tankFluid.getAmount()) { + filled = helper.fill(inputOne, tankFluid, tankFluid.getAmount(), false); + } + + if (filled.amount() > 0) { + ItemStack resultStack = filled.stack(); + boolean fullNow = helper.fill(resultStack, tankFluid, 1, true).amount() == 0; + boolean tankWillBeEmpty = tankFluid.getAmount() - filled.amount() <= 0; + + if (fullNow || tankWillBeEmpty) { + if (canMoveToOutput(resultStack, output)) { + tank.drain(filled.amount(), false); + input.shrink(1); + if (input.isEmpty()) { + itemHandler.setItem(0, ItemStack.EMPTY); + } else { + itemHandler.setChanged(); + } + addToOutput(resultStack, output); + } + } else { + if (input.getCount() == 1) { + tank.drain(filled.amount(), false); + itemHandler.setItem(0, resultStack); + } + } + } + } + } + + private boolean canMoveToOutput(ItemStack result, ItemStack output) { + if (output.isEmpty()) return true; + //? if >1.20.1 { + /*return ItemStack.isSameItemSameComponents(result, output) && output.getCount() + result.getCount() <= output.getMaxStackSize(); + *///?} else { + return ItemStack.isSameItemSameTags(result, output) && output.getCount() + result.getCount() <= output.getMaxStackSize(); + //?} + } + + private void addToOutput(ItemStack result, ItemStack output) { + if (output.isEmpty()) { + itemHandler.setItem(1, result); + } else { + output.grow(result.getCount()); + itemHandler.setChanged(); + } } public boolean isEmptyForDrop() { @@ -94,9 +270,18 @@ public class TankBlockEntity extends BlockEntity implements ExtendedMenuProvider protected void saveAdditional(CompoundTag pTag, HolderLookup.Provider pRegistries) { super.saveAdditional(pTag, pRegistries); pTag.put("Inventory", itemHandler.createTag(pRegistries)); - CompoundTag fluidTag = new CompoundTag(); - fluidStack.write(pRegistries, fluidTag); - pTag.put("Fluid", fluidTag); + if (!fluidStack.isEmpty()) { + // Manually save fluid stack to avoid issues with Architectury's default serialization + CompoundTag fluidTag = new CompoundTag(); + fluidTag.putString("id", BuiltInRegistries.FLUID.getKey(fluidStack.getFluid()).toString()); + fluidTag.putLong("amount", fluidStack.getAmount()); + if (fluidStack.getPatch() != null && !fluidStack.getPatch().isEmpty()) { + // Fallback to standard save if components are present + pTag.put("Fluid", FluidStack.CODEC.encodeStart(NbtOps.INSTANCE, fluidStack).getOrThrow()); + } else { + pTag.put("Fluid", fluidTag); + } + } } @Override @@ -104,7 +289,23 @@ public class TankBlockEntity extends BlockEntity implements ExtendedMenuProvider super.loadAdditional(pTag, pRegistries); itemHandler.fromTag(pTag.getList("Inventory", 10), pRegistries); if (pTag.contains("Fluid")) { - this.fluidStack = FluidStack.read(pRegistries, pTag.getCompound("Fluid")).orElse(FluidStack.empty()); + CompoundTag fluidTag = pTag.getCompound("Fluid"); + if (fluidTag.contains("id") && fluidTag.contains("amount")) { + // Manual load + try { + // Use ResourceLocation.parse for 1.21.1 + net.minecraft.world.level.material.Fluid fluid = BuiltInRegistries.FLUID.get(ResourceLocation.parse(fluidTag.getString("id"))); + long amount = fluidTag.getLong("amount"); + this.fluidStack = FluidStack.create(fluid, amount); + } catch (Exception e) { + this.fluidStack = FluidStack.empty(); + } + } else { + // Standard load + this.fluidStack = FluidStack.CODEC.parse(NbtOps.INSTANCE, fluidTag).result().orElse(FluidStack.empty()); + } + } else { + this.fluidStack = FluidStack.empty(); } } *///?} else { @@ -112,9 +313,11 @@ public class TankBlockEntity extends BlockEntity implements ExtendedMenuProvider protected void saveAdditional(CompoundTag pTag) { super.saveAdditional(pTag); pTag.put("Inventory", itemHandler.createTag()); - CompoundTag fluidTag = new CompoundTag(); - fluidStack.write(fluidTag); - pTag.put("Fluid", fluidTag); + if (!fluidStack.isEmpty()) { + CompoundTag fluidTag = new CompoundTag(); + fluidStack.write(fluidTag); + pTag.put("Fluid", fluidTag); + } } @Override @@ -123,6 +326,8 @@ public class TankBlockEntity extends BlockEntity implements ExtendedMenuProvider itemHandler.fromTag(pTag.getList("Inventory", 10)); if (pTag.contains("Fluid")) { this.fluidStack = FluidStack.read(pTag.getCompound("Fluid")); + } else { + this.fluidStack = FluidStack.empty(); } } //?} diff --git a/common/src/main/java/net/cmr/jurassicrevived/config/JRConfig.java b/common/src/main/java/net/cmr/jurassicrevived/config/JRConfig.java index 5699747..896a170 100644 --- a/common/src/main/java/net/cmr/jurassicrevived/config/JRConfig.java +++ b/common/src/main/java/net/cmr/jurassicrevived/config/JRConfig.java @@ -6,7 +6,7 @@ public final class JRConfig { public int spawnWeight = 10; public boolean requirePower = true; public int fePerSecond = 1000; - public int itemsPerSecond = 10; + public int itemsPerSecond = 100; public int milliBucketsPerSecond = 1000; public JRConfig() { diff --git a/common/src/main/java/net/cmr/jurassicrevived/networking/ModPackets.java b/common/src/main/java/net/cmr/jurassicrevived/networking/ModPackets.java new file mode 100644 index 0000000..decdf91 --- /dev/null +++ b/common/src/main/java/net/cmr/jurassicrevived/networking/ModPackets.java @@ -0,0 +1,121 @@ +package net.cmr.jurassicrevived.networking; + +import dev.architectury.fluid.FluidStack; +import dev.architectury.networking.NetworkManager; +import io.netty.buffer.Unpooled; +import net.cmr.jurassicrevived.Constants; +import net.cmr.jurassicrevived.screen.custom.TankMenu; +import net.minecraft.core.component.DataComponentPatch; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.FriendlyByteBuf; +//? if >1.20.1 { +/*import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +*///?} +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.level.material.Fluid; +import net.minecraft.world.level.material.Fluids; + +public class ModPackets { + public static final ResourceLocation TANK_SYNC = Constants.rl("tank_sync"); + + public static void register() { + //? if >1.20.1 { + /*NetworkManager.registerReceiver(NetworkManager.Side.S2C, TANK_SYNC_TYPE, TANK_SYNC_STREAM_CODEC, (payload, context) -> { + FluidStack fluidStack = payload.fluidStack(); + context.queue(() -> { + Player player = context.getPlayer(); + if (player != null) { + AbstractContainerMenu menu = player.containerMenu; + if (menu instanceof TankMenu tankMenu) { + tankMenu.setFluid(fluidStack); + } + } + }); + }); + *///?} else { + NetworkManager.registerReceiver(NetworkManager.Side.S2C, TANK_SYNC, (buf, context) -> { + FluidStack fluidStack = FluidStack.read(buf); + context.queue(() -> { + Player player = context.getPlayer(); + if (player != null) { + AbstractContainerMenu menu = player.containerMenu; + if (menu instanceof TankMenu tankMenu) { + tankMenu.setFluid(fluidStack); + } + } + }); + }); + //?} + } + + public static void sendTankSync(ServerPlayer player, FluidStack fluidStack) { + //? if >1.20.1 { + /*NetworkManager.sendToPlayer(player, new TankSyncPayload(fluidStack)); + *///?} else { + FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); + fluidStack.write(buf); + NetworkManager.sendToPlayer(player, TANK_SYNC, buf); + //?} + } + + //? if >1.20.1 { + /*public static final CustomPacketPayload.Type TANK_SYNC_TYPE = new CustomPacketPayload.Type<>(TANK_SYNC); + public static final StreamCodec TANK_SYNC_STREAM_CODEC = StreamCodec.of((buf, payload) -> payload.write(buf), TankSyncPayload::new); + + public record TankSyncPayload(FluidStack fluidStack) implements CustomPacketPayload { + public TankSyncPayload(RegistryFriendlyByteBuf buf) { + this(readFluid(buf)); + } + + public void write(RegistryFriendlyByteBuf buf) { + if (fluidStack.isEmpty()) { + buf.writeBoolean(false); + } else { + buf.writeBoolean(true); + buf.writeResourceLocation(BuiltInRegistries.FLUID.getKey(fluidStack.getFluid())); + buf.writeLong(fluidStack.getAmount()); + //? if >1.20.1 { + /^DataComponentPatch.STREAM_CODEC.encode(buf, fluidStack.getPatch()); + ^///?} else { + buf.writeNbt(fluidStack.getTag()); + //?} + } + } + + private static FluidStack readFluid(RegistryFriendlyByteBuf buf) { + if (!buf.readBoolean()) { + return FluidStack.empty(); + } + ResourceLocation fluidId = buf.readResourceLocation(); + long amount = buf.readLong(); + //? if >1.20.1 { + /^DataComponentPatch patch = DataComponentPatch.STREAM_CODEC.decode(buf); + ^///?} else { + CompoundTag tag = buf.readNbt(); + //?} + Fluid fluid = BuiltInRegistries.FLUID.get(fluidId); + if (fluid == Fluids.EMPTY) { + return FluidStack.empty(); + } + //? if >1.20.1 { + /^return FluidStack.create(fluid, amount, patch); + ^///?} else { + FluidStack stack = FluidStack.create(fluid, amount); + stack.setTag(tag); + return stack; + //?} + } + + @Override + public Type type() { + return TANK_SYNC_TYPE; + } + } + *///?} +} \ No newline at end of file diff --git a/common/src/main/java/net/cmr/jurassicrevived/platform/Services.java b/common/src/main/java/net/cmr/jurassicrevived/platform/Services.java index 6247d0e..eabd1cc 100644 --- a/common/src/main/java/net/cmr/jurassicrevived/platform/Services.java +++ b/common/src/main/java/net/cmr/jurassicrevived/platform/Services.java @@ -3,6 +3,8 @@ package net.cmr.jurassicrevived.platform; import net.cmr.jurassicrevived.Constants; import net.cmr.jurassicrevived.platform.services.IPlatformHelper; +import net.cmr.jurassicrevived.platform.services.ITransferHelper; +import net.cmr.jurassicrevived.platform.services.IItemFluidHelper; import java.util.ServiceLoader; @@ -16,6 +18,8 @@ public class Services // For example this can be used to check if the code is running on Forge vs Fabric, or to ask the modloader if another // mod is loaded. public static final IPlatformHelper PLATFORM = load(IPlatformHelper.class); + public static final ITransferHelper TRANSFER = load(ITransferHelper.class); + public static final IItemFluidHelper ITEM_FLUID = load(IItemFluidHelper.class); // This code is used to load a service for the current environment. Your implementation of the service must be defined // manually by including a text file in META-INF/services named with the fully qualified class name of the service. diff --git a/common/src/main/java/net/cmr/jurassicrevived/platform/services/IItemFluidHelper.java b/common/src/main/java/net/cmr/jurassicrevived/platform/services/IItemFluidHelper.java new file mode 100644 index 0000000..df7970a --- /dev/null +++ b/common/src/main/java/net/cmr/jurassicrevived/platform/services/IItemFluidHelper.java @@ -0,0 +1,15 @@ +package net.cmr.jurassicrevived.platform.services; + +import dev.architectury.fluid.FluidStack; +import net.minecraft.world.item.ItemStack; + +import java.util.Optional; + +public interface IItemFluidHelper { + record TransferResult(long amount, ItemStack stack) {} + + Optional getContainedFluid(ItemStack stack); + TransferResult drain(ItemStack stack, long amount, boolean simulate); + TransferResult fill(ItemStack stack, FluidStack fluid, long amount, boolean simulate); + boolean isFluidHandler(ItemStack stack); +} diff --git a/common/src/main/java/net/cmr/jurassicrevived/platform/services/ITransferHelper.java b/common/src/main/java/net/cmr/jurassicrevived/platform/services/ITransferHelper.java new file mode 100644 index 0000000..535ba18 --- /dev/null +++ b/common/src/main/java/net/cmr/jurassicrevived/platform/services/ITransferHelper.java @@ -0,0 +1,16 @@ +package net.cmr.jurassicrevived.platform.services; + +import net.cmr.jurassicrevived.platform.transfer.PlatformItemHandler; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.Level; +import net.cmr.jurassicrevived.platform.transfer.PlatformEnergyHandler; +import net.cmr.jurassicrevived.platform.transfer.PlatformFluidHandler; + +import java.util.Optional; + +public interface ITransferHelper { + Optional getItemHandler(Level level, BlockPos pos, Direction side); + Optional getFluidHandler(Level level, BlockPos pos, Direction side); + Optional getEnergyHandler(Level level, BlockPos pos, Direction side); +} diff --git a/common/src/main/java/net/cmr/jurassicrevived/platform/transfer/InternalFluidHandler.java b/common/src/main/java/net/cmr/jurassicrevived/platform/transfer/InternalFluidHandler.java new file mode 100644 index 0000000..4dc353e --- /dev/null +++ b/common/src/main/java/net/cmr/jurassicrevived/platform/transfer/InternalFluidHandler.java @@ -0,0 +1,10 @@ +package net.cmr.jurassicrevived.platform.transfer; + +import dev.architectury.fluid.FluidStack; + +public interface InternalFluidHandler { + FluidStack getFluid(); + long getCapacity(); + long fill(FluidStack stack, boolean simulate); + FluidStack drain(long amount, boolean simulate); +} diff --git a/common/src/main/java/net/cmr/jurassicrevived/platform/transfer/InternalFluidHandlerAdapter.java b/common/src/main/java/net/cmr/jurassicrevived/platform/transfer/InternalFluidHandlerAdapter.java new file mode 100644 index 0000000..0b9a7dc --- /dev/null +++ b/common/src/main/java/net/cmr/jurassicrevived/platform/transfer/InternalFluidHandlerAdapter.java @@ -0,0 +1,33 @@ +package net.cmr.jurassicrevived.platform.transfer; + +import dev.architectury.fluid.FluidStack; + +import java.util.List; + +public class InternalFluidHandlerAdapter implements PlatformFluidHandler { + private final InternalFluidHandler handler; + + public InternalFluidHandlerAdapter(InternalFluidHandler handler) { + this.handler = handler; + } + + @Override + public Iterable getExtractableFluids() { + FluidStack fluid = handler.getFluid(); + return fluid.isEmpty() ? List.of() : List.of(fluid); + } + + @Override + public long extract(FluidStack stack, long amount, boolean simulate) { + if (stack.isEmpty()) return 0; + return handler.drain(amount, simulate).getAmount(); + } + + @Override + public long insert(FluidStack stack, long amount, boolean simulate) { + if (stack.isEmpty()) return 0; + FluidStack toFill = stack.copy(); + toFill.setAmount(amount); + return handler.fill(toFill, simulate); + } +} diff --git a/common/src/main/java/net/cmr/jurassicrevived/platform/transfer/InternalFluidProvider.java b/common/src/main/java/net/cmr/jurassicrevived/platform/transfer/InternalFluidProvider.java new file mode 100644 index 0000000..0cc1757 --- /dev/null +++ b/common/src/main/java/net/cmr/jurassicrevived/platform/transfer/InternalFluidProvider.java @@ -0,0 +1,8 @@ +package net.cmr.jurassicrevived.platform.transfer; + +import net.minecraft.core.Direction; +import org.jetbrains.annotations.Nullable; + +public interface InternalFluidProvider { + InternalFluidHandler getFluidHandler(@Nullable Direction side); +} diff --git a/common/src/main/java/net/cmr/jurassicrevived/platform/transfer/PlatformEnergyHandler.java b/common/src/main/java/net/cmr/jurassicrevived/platform/transfer/PlatformEnergyHandler.java new file mode 100644 index 0000000..bfff96c --- /dev/null +++ b/common/src/main/java/net/cmr/jurassicrevived/platform/transfer/PlatformEnergyHandler.java @@ -0,0 +1,6 @@ +package net.cmr.jurassicrevived.platform.transfer; + +public interface PlatformEnergyHandler { + int extract(int amount, boolean simulate); + int insert(int amount, boolean simulate); +} diff --git a/common/src/main/java/net/cmr/jurassicrevived/platform/transfer/PlatformFluidHandler.java b/common/src/main/java/net/cmr/jurassicrevived/platform/transfer/PlatformFluidHandler.java new file mode 100644 index 0000000..e0a3cfc --- /dev/null +++ b/common/src/main/java/net/cmr/jurassicrevived/platform/transfer/PlatformFluidHandler.java @@ -0,0 +1,9 @@ +package net.cmr.jurassicrevived.platform.transfer; + +import dev.architectury.fluid.FluidStack; + +public interface PlatformFluidHandler { + Iterable getExtractableFluids(); + long extract(FluidStack stack, long amount, boolean simulate); + long insert(FluidStack stack, long amount, boolean simulate); +} diff --git a/common/src/main/java/net/cmr/jurassicrevived/platform/transfer/PlatformItemHandler.java b/common/src/main/java/net/cmr/jurassicrevived/platform/transfer/PlatformItemHandler.java new file mode 100644 index 0000000..22f348c --- /dev/null +++ b/common/src/main/java/net/cmr/jurassicrevived/platform/transfer/PlatformItemHandler.java @@ -0,0 +1,9 @@ +package net.cmr.jurassicrevived.platform.transfer; + +import net.minecraft.world.item.ItemStack; + +public interface PlatformItemHandler { + Iterable getExtractableStacks(); + int extract(ItemStack stack, int amount, boolean simulate); + int insert(ItemStack stack, int amount, boolean simulate); +} diff --git a/common/src/main/java/net/cmr/jurassicrevived/screen/custom/TankMenu.java b/common/src/main/java/net/cmr/jurassicrevived/screen/custom/TankMenu.java index 02d83aa..5731df1 100644 --- a/common/src/main/java/net/cmr/jurassicrevived/screen/custom/TankMenu.java +++ b/common/src/main/java/net/cmr/jurassicrevived/screen/custom/TankMenu.java @@ -1,13 +1,18 @@ package net.cmr.jurassicrevived.screen.custom; +import dev.architectury.fluid.FluidStack; import net.cmr.jurassicrevived.block.ModBlocks; import net.cmr.jurassicrevived.block.entity.custom.TankBlockEntity; +import net.cmr.jurassicrevived.networking.ModPackets; +import net.cmr.jurassicrevived.platform.Services; import net.cmr.jurassicrevived.screen.ModMenuTypes; import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.inventory.ContainerLevelAccess; +import net.minecraft.world.inventory.DataSlot; import net.minecraft.world.inventory.Slot; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; @@ -16,6 +21,7 @@ import net.minecraft.world.level.block.entity.BlockEntity; public class TankMenu extends AbstractContainerMenu { public final TankBlockEntity blockEntity; private final Level level; + private FluidStack fluidStack = FluidStack.empty(); public TankMenu(int pContainerId, Inventory inv, FriendlyByteBuf extraData) { this(pContainerId, inv, inv.player.level().getBlockEntity(extraData.readBlockPos())); @@ -25,20 +31,81 @@ public class TankMenu extends AbstractContainerMenu { super(ModMenuTypes.TANK_MENU.get(), pContainerId); this.blockEntity = ((TankBlockEntity) blockEntity); this.level = inv.player.level(); + + // Initialize fluidStack with the current state of the block entity + // This ensures the client sees the correct fluid immediately if the BE is already synced + if (this.blockEntity != null) { + this.fluidStack = this.blockEntity.getFluid().copy(); + } addPlayerInventory(inv); addPlayerHotbar(inv); // Input Slot (0) - this.addSlot(new Slot(this.blockEntity.itemHandler, 0, 44, 34)); - - // Output Slot (1) - this.addSlot(new Slot(this.blockEntity.itemHandler, 1, 116, 34) { + this.addSlot(new Slot(this.blockEntity.itemHandler, 0, 44, 34) { @Override - public int getMaxStackSize() { - return 1; + public boolean mayPlace(ItemStack stack) { + return Services.ITEM_FLUID.isFluidHandler(stack); } }); + + // Output Slot (1) + this.addSlot(new Slot(this.blockEntity.itemHandler, 1, 116, 34){ + @Override + public boolean mayPlace(ItemStack stack) { + return false; + } + }); + + addDataSlot(new DataSlot() { + @Override + public int get() { + return 0; + } + + @Override + public void set(int pValue) { + } + }); + } + + public void setFluid(FluidStack stack) { + this.fluidStack = stack; + } + + public FluidStack getFluid() { + return this.fluidStack; + } + public void syncFluidToPlayers() { + if (this.level != null && !this.level.isClientSide()) { + for (Player player : this.level.players()) { + if (player.containerMenu == this && player instanceof ServerPlayer serverPlayer) { + ModPackets.sendTankSync(serverPlayer, this.fluidStack); + } + } + } + } + + @Override + public void sendAllDataToRemote() { + super.sendAllDataToRemote(); + // Ensure we have the latest fluid state from the block entity before syncing + if (this.blockEntity != null) { + this.fluidStack = this.blockEntity.getFluid().copy(); + } + syncFluidToPlayers(); + } + + @Override + public void broadcastChanges() { + super.broadcastChanges(); + if (this.blockEntity != null) { + FluidStack currentFluid = this.blockEntity.getFluid(); + if (!currentFluid.equals(this.fluidStack)) { + this.fluidStack = currentFluid.copy(); + syncFluidToPlayers(); + } + } } private static final int HOTBAR_SLOT_COUNT = 9; diff --git a/common/src/main/java/net/cmr/jurassicrevived/screen/custom/TankScreen.java b/common/src/main/java/net/cmr/jurassicrevived/screen/custom/TankScreen.java index 0e73cb7..5545dda 100644 --- a/common/src/main/java/net/cmr/jurassicrevived/screen/custom/TankScreen.java +++ b/common/src/main/java/net/cmr/jurassicrevived/screen/custom/TankScreen.java @@ -51,7 +51,7 @@ public class TankScreen extends AbstractContainerScreen { int x = (width - imageWidth) / 2; int y = (height - imageHeight) / 2; - renderFluidTooltipArea(guiGraphics, pMouseX, pMouseY, x, y, menu.blockEntity.getFluid(), 80, 8, fluidRenderer); + renderFluidTooltipArea(guiGraphics, pMouseX, pMouseY, x, y, menu.getFluid(), 80, 8, fluidRenderer); } @Override @@ -64,7 +64,7 @@ public class TankScreen extends AbstractContainerScreen { guiGraphics.blit(GUI_TEXTURE, x, y, 0, 0, imageWidth, imageHeight); - fluidRenderer.render(guiGraphics, x + 80, y + 8, menu.blockEntity.getFluid()); + fluidRenderer.render(guiGraphics, x + 80, y + 8, menu.getFluid()); } @Override diff --git a/common/src/main/resources/assets/jurassicrevived/models/block/generator_lit.json b/common/src/main/resources/assets/jurassicrevived/models/block/generator_lit.json new file mode 100644 index 0000000..4ae9ddb --- /dev/null +++ b/common/src/main/resources/assets/jurassicrevived/models/block/generator_lit.json @@ -0,0 +1,208 @@ +{ + "format_version": "1.9.0", + "credit": "Made with Blockbench", + "ambientocclusion": false, + "render_type": "cutout", + "texture_size": [64, 64], + "textures": { + "0": "jurassicrevived:block/generator", + "particle": "jurassicrevived:block/generator" + }, + "elements": [ + { + "from": [2, 0, 2], + "to": [14, 8, 14], + "rotation": {"angle": 0, "axis": "y", "origin": [0, 0, 1]}, + "faces": { + "north": {"uv": [3, 0, 6, 2], "texture": "#0"}, + "east": {"uv": [3, 2, 6, 4], "texture": "#0"}, + "south": {"uv": [3, 4, 6, 6], "texture": "#0"}, + "west": {"uv": [0, 6, 3, 8], "texture": "#0"}, + "up": {"uv": [3, 3, 0, 0], "texture": "#0"}, + "down": {"uv": [3, 3, 0, 6], "texture": "#0"} + } + }, + { + "from": [-1.425, 9.7, 3.5], + "to": [6.575, 17.7, 12.5], + "rotation": {"angle": -45, "axis": "z", "origin": [6.575, 7.7, -0.5]}, + "faces": { + "north": {"uv": [5, 6.25, 7, 8.25], "texture": "#0"}, + "east": {"uv": [6, 0, 8.25, 2], "texture": "#0"}, + "south": {"uv": [7, 6.25, 9, 8.25], "texture": "#0"}, + "west": {"uv": [6, 2, 8.25, 4], "texture": "#0"}, + "up": {"uv": [5, 8.25, 3, 6], "texture": "#0"}, + "down": {"uv": [8, 4, 6, 6.25], "texture": "#0"} + } + }, + { + "from": [1, 0, 1], + "to": [3, 9, 3], + "rotation": {"angle": 0, "axis": "y", "origin": [-1, 0, 0]}, + "faces": { + "north": {"uv": [4, 8.75, 4.5, 11], "texture": "#0"}, + "east": {"uv": [4.5, 8.75, 5, 11], "texture": "#0"}, + "south": {"uv": [5, 8.75, 5.5, 11], "texture": "#0"}, + "west": {"uv": [5.5, 8.75, 6, 11], "texture": "#0"}, + "up": {"uv": [9.25, 2.5, 8.75, 2], "texture": "#0"}, + "down": {"uv": [9.75, 2, 9.25, 2.5], "texture": "#0"} + } + }, + { + "from": [1, 0, 13], + "to": [3, 9, 15], + "rotation": {"angle": 0, "axis": "y", "origin": [-1, 0, 12]}, + "faces": { + "north": {"uv": [6, 8.75, 6.5, 11], "texture": "#0"}, + "east": {"uv": [6.5, 8.75, 7, 11], "texture": "#0"}, + "south": {"uv": [7, 8.75, 7.5, 11], "texture": "#0"}, + "west": {"uv": [7.5, 8.75, 8, 11], "texture": "#0"}, + "up": {"uv": [10.25, 2.5, 9.75, 2], "texture": "#0"}, + "down": {"uv": [10.5, 6, 10, 6.5], "texture": "#0"} + } + }, + { + "from": [13, 0, 13], + "to": [15, 9, 15], + "rotation": {"angle": 0, "axis": "y", "origin": [11, 0, 12]}, + "faces": { + "north": {"uv": [8, 8.75, 8.5, 11], "texture": "#0"}, + "east": {"uv": [8.5, 8.75, 9, 11], "texture": "#0"}, + "south": {"uv": [0, 9, 0.5, 11.25], "texture": "#0"}, + "west": {"uv": [0.5, 9, 1, 11.25], "texture": "#0"}, + "up": {"uv": [10.5, 7, 10, 6.5], "texture": "#0"}, + "down": {"uv": [10.5, 7, 10, 7.5], "texture": "#0"} + } + }, + { + "from": [13, 7, 3], + "to": [15, 9, 13], + "rotation": {"angle": 0, "axis": "y", "origin": [11, 8, 12]}, + "faces": { + "north": {"uv": [10, 7.5, 10.5, 8], "texture": "#0"}, + "east": {"uv": [0, 8, 2.5, 8.5], "texture": "#0"}, + "south": {"uv": [10, 8, 10.5, 8.5], "texture": "#0"}, + "west": {"uv": [8, 4, 10.5, 4.5], "texture": "#0"}, + "up": {"uv": [3, 10.5, 2.5, 8], "texture": "#0"}, + "down": {"uv": [8.75, 0, 8.25, 2.5], "texture": "#0"} + } + }, + { + "from": [1, 7, 3], + "to": [3, 9, 13], + "rotation": {"angle": 0, "axis": "y", "origin": [-1, 8, 12]}, + "faces": { + "north": {"uv": [10, 8.5, 10.5, 9], "texture": "#0"}, + "east": {"uv": [8, 4.5, 10.5, 5], "texture": "#0"}, + "south": {"uv": [10, 9, 10.5, 9.5], "texture": "#0"}, + "west": {"uv": [8, 5, 10.5, 5.5], "texture": "#0"}, + "up": {"uv": [3.5, 10.75, 3, 8.25], "texture": "#0"}, + "down": {"uv": [4, 8.25, 3.5, 10.75], "texture": "#0"} + } + }, + { + "from": [4, 8, 9], + "to": [6, 14, 11], + "rotation": {"angle": 0, "axis": "y", "origin": [2, 9, 14]}, + "faces": { + "north": {"uv": [8.75, 0.5, 9.25, 2], "texture": "#0"}, + "east": {"uv": [9, 8.25, 9.5, 9.75], "texture": "#0"}, + "south": {"uv": [9.25, 0.5, 9.75, 2], "texture": "#0"}, + "west": {"uv": [9.5, 6, 10, 7.5], "texture": "#0"}, + "up": {"uv": [10.5, 10, 10, 9.5], "texture": "#0"}, + "down": {"uv": [10.5, 10, 10, 10.5], "texture": "#0"} + } + }, + { + "from": [10, 8, 5], + "to": [12, 14, 7], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 9, 10]}, + "faces": { + "north": {"uv": [9.5, 7.5, 10, 9], "texture": "#0"}, + "east": {"uv": [9.5, 9, 10, 10.5], "texture": "#0"}, + "south": {"uv": [9.75, 0.5, 10.25, 2], "texture": "#0"}, + "west": {"uv": [9, 9.75, 9.5, 11.25], "texture": "#0"}, + "up": {"uv": [10.75, 1, 10.25, 0.5], "texture": "#0"}, + "down": {"uv": [10.75, 1, 10.25, 1.5], "texture": "#0"} + } + }, + { + "from": [13, 0, 1], + "to": [15, 9, 3], + "rotation": {"angle": 0, "axis": "y", "origin": [11, 0, 0]}, + "faces": { + "north": {"uv": [1, 9, 1.5, 11.25], "texture": "#0"}, + "east": {"uv": [1.5, 9, 2, 11.25], "texture": "#0"}, + "south": {"uv": [2, 9, 2.5, 11.25], "texture": "#0"}, + "west": {"uv": [9, 6, 9.5, 8.25], "texture": "#0"}, + "up": {"uv": [10.75, 2, 10.25, 1.5], "texture": "#0"}, + "down": {"uv": [10.75, 2, 10.25, 2.5], "texture": "#0"} + } + }, + { + "from": [3, 7, 1], + "to": [13, 9, 3], + "rotation": {"angle": 0, "axis": "y", "origin": [9, 0, 0]}, + "faces": { + "north": {"uv": [8, 5.5, 10.5, 6], "texture": "#0"}, + "east": {"uv": [2.5, 10.5, 3, 11], "texture": "#0"}, + "south": {"uv": [8.25, 2.5, 10.75, 3], "texture": "#0"}, + "west": {"uv": [10.5, 4, 11, 4.5], "texture": "#0"}, + "up": {"uv": [10.75, 3.5, 8.25, 3], "texture": "#0"}, + "down": {"uv": [10.75, 3.5, 8.25, 4], "texture": "#0"} + } + }, + { + "from": [3, 7, 13], + "to": [13, 9, 15], + "rotation": {"angle": 0, "axis": "y", "origin": [9, 0, 12]}, + "faces": { + "north": {"uv": [4, 8.25, 6.5, 8.75], "texture": "#0"}, + "east": {"uv": [10.5, 4.5, 11, 5], "texture": "#0"}, + "south": {"uv": [6.5, 8.25, 9, 8.75], "texture": "#0"}, + "west": {"uv": [10.5, 5, 11, 5.5], "texture": "#0"}, + "up": {"uv": [2.5, 9, 0, 8.5], "texture": "#0"}, + "down": {"uv": [11.25, 0, 8.75, 0.5], "texture": "#0"} + } + } + ], + "display": { + "thirdperson_righthand": { + "rotation": [75, 45, 0], + "translation": [0, 2.5, 0], + "scale": [0.375, 0.375, 0.375] + }, + "thirdperson_lefthand": { + "rotation": [75, 45, 0], + "translation": [0, 2.5, 0], + "scale": [0.375, 0.375, 0.375] + }, + "firstperson_righthand": { + "rotation": [0, 45, 0], + "scale": [0.4, 0.4, 0.4] + }, + "firstperson_lefthand": { + "rotation": [0, -135, 0], + "scale": [0.4, 0.4, 0.4] + }, + "ground": { + "translation": [0, 3, 0], + "scale": [0.25, 0.25, 0.25] + }, + "gui": { + "rotation": [30, -135, 0], + "scale": [0.625, 0.625, 0.625] + }, + "fixed": { + "scale": [0.5, 0.5, 0.5] + } + }, + "groups": [ + { + "name": "Root", + "origin": [8, 8, 8], + "color": 0, + "children": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] + } + ] +} \ No newline at end of file diff --git a/common/src/main/resources/assets/jurassicrevived/models/block/white_generator_lit.json b/common/src/main/resources/assets/jurassicrevived/models/block/white_generator_lit.json new file mode 100644 index 0000000..c278242 --- /dev/null +++ b/common/src/main/resources/assets/jurassicrevived/models/block/white_generator_lit.json @@ -0,0 +1,208 @@ +{ + "format_version": "1.9.0", + "credit": "Made with Blockbench", + "ambientocclusion": false, + "render_type": "cutout", + "texture_size": [64, 64], + "textures": { + "0": "jurassicrevived:block/white_generator", + "particle": "jurassicrevived:block/white_generator" + }, + "elements": [ + { + "from": [2, 0, 2], + "to": [14, 8, 14], + "rotation": {"angle": 0, "axis": "y", "origin": [0, 0, 1]}, + "faces": { + "north": {"uv": [3, 0, 6, 2], "texture": "#0"}, + "east": {"uv": [3, 2, 6, 4], "texture": "#0"}, + "south": {"uv": [3, 4, 6, 6], "texture": "#0"}, + "west": {"uv": [0, 6, 3, 8], "texture": "#0"}, + "up": {"uv": [3, 3, 0, 0], "texture": "#0"}, + "down": {"uv": [3, 3, 0, 6], "texture": "#0"} + } + }, + { + "from": [-1.425, 9.7, 3.5], + "to": [6.575, 17.7, 12.5], + "rotation": {"angle": -45, "axis": "z", "origin": [6.575, 7.7, -0.5]}, + "faces": { + "north": {"uv": [5, 6.25, 7, 8.25], "texture": "#0"}, + "east": {"uv": [6, 0, 8.25, 2], "texture": "#0"}, + "south": {"uv": [7, 6.25, 9, 8.25], "texture": "#0"}, + "west": {"uv": [6, 2, 8.25, 4], "texture": "#0"}, + "up": {"uv": [5, 8.25, 3, 6], "texture": "#0"}, + "down": {"uv": [8, 4, 6, 6.25], "texture": "#0"} + } + }, + { + "from": [1, 0, 1], + "to": [3, 9, 3], + "rotation": {"angle": 0, "axis": "y", "origin": [-1, 0, 0]}, + "faces": { + "north": {"uv": [4, 8.75, 4.5, 11], "texture": "#0"}, + "east": {"uv": [4.5, 8.75, 5, 11], "texture": "#0"}, + "south": {"uv": [5, 8.75, 5.5, 11], "texture": "#0"}, + "west": {"uv": [5.5, 8.75, 6, 11], "texture": "#0"}, + "up": {"uv": [9.25, 2.5, 8.75, 2], "texture": "#0"}, + "down": {"uv": [9.75, 2, 9.25, 2.5], "texture": "#0"} + } + }, + { + "from": [1, 0, 13], + "to": [3, 9, 15], + "rotation": {"angle": 0, "axis": "y", "origin": [-1, 0, 12]}, + "faces": { + "north": {"uv": [6, 8.75, 6.5, 11], "texture": "#0"}, + "east": {"uv": [6.5, 8.75, 7, 11], "texture": "#0"}, + "south": {"uv": [7, 8.75, 7.5, 11], "texture": "#0"}, + "west": {"uv": [7.5, 8.75, 8, 11], "texture": "#0"}, + "up": {"uv": [10.25, 2.5, 9.75, 2], "texture": "#0"}, + "down": {"uv": [10.5, 6, 10, 6.5], "texture": "#0"} + } + }, + { + "from": [13, 0, 13], + "to": [15, 9, 15], + "rotation": {"angle": 0, "axis": "y", "origin": [11, 0, 12]}, + "faces": { + "north": {"uv": [8, 8.75, 8.5, 11], "texture": "#0"}, + "east": {"uv": [8.5, 8.75, 9, 11], "texture": "#0"}, + "south": {"uv": [0, 9, 0.5, 11.25], "texture": "#0"}, + "west": {"uv": [0.5, 9, 1, 11.25], "texture": "#0"}, + "up": {"uv": [10.5, 7, 10, 6.5], "texture": "#0"}, + "down": {"uv": [10.5, 7, 10, 7.5], "texture": "#0"} + } + }, + { + "from": [13, 7, 3], + "to": [15, 9, 13], + "rotation": {"angle": 0, "axis": "y", "origin": [11, 8, 12]}, + "faces": { + "north": {"uv": [10, 7.5, 10.5, 8], "texture": "#0"}, + "east": {"uv": [0, 8, 2.5, 8.5], "texture": "#0"}, + "south": {"uv": [10, 8, 10.5, 8.5], "texture": "#0"}, + "west": {"uv": [8, 4, 10.5, 4.5], "texture": "#0"}, + "up": {"uv": [3, 10.5, 2.5, 8], "texture": "#0"}, + "down": {"uv": [8.75, 0, 8.25, 2.5], "texture": "#0"} + } + }, + { + "from": [1, 7, 3], + "to": [3, 9, 13], + "rotation": {"angle": 0, "axis": "y", "origin": [-1, 8, 12]}, + "faces": { + "north": {"uv": [10, 8.5, 10.5, 9], "texture": "#0"}, + "east": {"uv": [8, 4.5, 10.5, 5], "texture": "#0"}, + "south": {"uv": [10, 9, 10.5, 9.5], "texture": "#0"}, + "west": {"uv": [8, 5, 10.5, 5.5], "texture": "#0"}, + "up": {"uv": [3.5, 10.75, 3, 8.25], "texture": "#0"}, + "down": {"uv": [4, 8.25, 3.5, 10.75], "texture": "#0"} + } + }, + { + "from": [4, 8, 9], + "to": [6, 14, 11], + "rotation": {"angle": 0, "axis": "y", "origin": [2, 9, 14]}, + "faces": { + "north": {"uv": [8.75, 0.5, 9.25, 2], "texture": "#0"}, + "east": {"uv": [9, 8.25, 9.5, 9.75], "texture": "#0"}, + "south": {"uv": [9.25, 0.5, 9.75, 2], "texture": "#0"}, + "west": {"uv": [9.5, 6, 10, 7.5], "texture": "#0"}, + "up": {"uv": [10.5, 10, 10, 9.5], "texture": "#0"}, + "down": {"uv": [10.5, 10, 10, 10.5], "texture": "#0"} + } + }, + { + "from": [10, 8, 5], + "to": [12, 14, 7], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 9, 10]}, + "faces": { + "north": {"uv": [9.5, 7.5, 10, 9], "texture": "#0"}, + "east": {"uv": [9.5, 9, 10, 10.5], "texture": "#0"}, + "south": {"uv": [9.75, 0.5, 10.25, 2], "texture": "#0"}, + "west": {"uv": [9, 9.75, 9.5, 11.25], "texture": "#0"}, + "up": {"uv": [10.75, 1, 10.25, 0.5], "texture": "#0"}, + "down": {"uv": [10.75, 1, 10.25, 1.5], "texture": "#0"} + } + }, + { + "from": [13, 0, 1], + "to": [15, 9, 3], + "rotation": {"angle": 0, "axis": "y", "origin": [11, 0, 0]}, + "faces": { + "north": {"uv": [1, 9, 1.5, 11.25], "texture": "#0"}, + "east": {"uv": [1.5, 9, 2, 11.25], "texture": "#0"}, + "south": {"uv": [2, 9, 2.5, 11.25], "texture": "#0"}, + "west": {"uv": [9, 6, 9.5, 8.25], "texture": "#0"}, + "up": {"uv": [10.75, 2, 10.25, 1.5], "texture": "#0"}, + "down": {"uv": [10.75, 2, 10.25, 2.5], "texture": "#0"} + } + }, + { + "from": [3, 7, 1], + "to": [13, 9, 3], + "rotation": {"angle": 0, "axis": "y", "origin": [9, 0, 0]}, + "faces": { + "north": {"uv": [8, 5.5, 10.5, 6], "texture": "#0"}, + "east": {"uv": [2.5, 10.5, 3, 11], "texture": "#0"}, + "south": {"uv": [8.25, 2.5, 10.75, 3], "texture": "#0"}, + "west": {"uv": [10.5, 4, 11, 4.5], "texture": "#0"}, + "up": {"uv": [10.75, 3.5, 8.25, 3], "texture": "#0"}, + "down": {"uv": [10.75, 3.5, 8.25, 4], "texture": "#0"} + } + }, + { + "from": [3, 7, 13], + "to": [13, 9, 15], + "rotation": {"angle": 0, "axis": "y", "origin": [9, 0, 12]}, + "faces": { + "north": {"uv": [4, 8.25, 6.5, 8.75], "texture": "#0"}, + "east": {"uv": [10.5, 4.5, 11, 5], "texture": "#0"}, + "south": {"uv": [6.5, 8.25, 9, 8.75], "texture": "#0"}, + "west": {"uv": [10.5, 5, 11, 5.5], "texture": "#0"}, + "up": {"uv": [2.5, 9, 0, 8.5], "texture": "#0"}, + "down": {"uv": [11.25, 0, 8.75, 0.5], "texture": "#0"} + } + } + ], + "display": { + "thirdperson_righthand": { + "rotation": [75, 45, 0], + "translation": [0, 2.5, 0], + "scale": [0.375, 0.375, 0.375] + }, + "thirdperson_lefthand": { + "rotation": [75, 45, 0], + "translation": [0, 2.5, 0], + "scale": [0.375, 0.375, 0.375] + }, + "firstperson_righthand": { + "rotation": [0, 45, 0], + "scale": [0.4, 0.4, 0.4] + }, + "firstperson_lefthand": { + "rotation": [0, -135, 0], + "scale": [0.4, 0.4, 0.4] + }, + "ground": { + "translation": [0, 3, 0], + "scale": [0.25, 0.25, 0.25] + }, + "gui": { + "rotation": [30, -135, 0], + "scale": [0.625, 0.625, 0.625] + }, + "fixed": { + "scale": [0.5, 0.5, 0.5] + } + }, + "groups": [ + { + "name": "Root", + "origin": [8, 8, 8], + "color": 0, + "children": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] + } + ] +} \ No newline at end of file diff --git a/fabricmc/build.gradle.kts b/fabricmc/build.gradle.kts index 4102ab7..a35001c 100644 --- a/fabricmc/build.gradle.kts +++ b/fabricmc/build.gradle.kts @@ -61,6 +61,14 @@ dependencies { } }) + val energyVersion = if (is120) { + commonMod.prop("teamreborn_energy_1_20_1") + } else { + commonMod.prop("teamreborn_energy_1_21_1") + } + + modImplementation("teamreborn:energy:$energyVersion") + modImplementation("net.fabricmc:fabric-loader:${commonMod.prop("fabric_loader_version")}") modApi("net.fabricmc.fabric-api:fabric-api:${commonMod.prop("fabric_api_version")}") diff --git a/fabricmc/src/main/java/net/cmr/jurassicrevived/JRMod.java b/fabricmc/src/main/java/net/cmr/jurassicrevived/JRMod.java index a7e2173..7d24133 100644 --- a/fabricmc/src/main/java/net/cmr/jurassicrevived/JRMod.java +++ b/fabricmc/src/main/java/net/cmr/jurassicrevived/JRMod.java @@ -7,6 +7,8 @@ import net.fabricmc.fabric.api.transfer.v1.fluid.FluidStorage; import net.fabricmc.fabric.api.transfer.v1.item.ItemStorage; import net.fabricmc.fabric.api.transfer.v1.item.ItemVariant; import net.fabricmc.fabric.api.transfer.v1.storage.Storage; +import net.cmr.jurassicrevived.platform.FabricEnergyWrapper; +import team.reborn.energy.api.EnergyStorage; public class JRMod implements ModInitializer { @@ -22,15 +24,54 @@ public class JRMod implements ModInitializer Constants.LOG.info("Hello Fabric world!"); CommonClass.init(); - /* - Items (Fabric Transfer API) - ItemStorage.SIDED.registerForBlockEntities((be, side) -> (Storage) ((CrateBlockEntity)be).itemHandler, ModBlockEntities.CRATE_BE.get()); + EnergyStorage.SIDED.registerForBlockEntities((be, side) -> + new FabricEnergyWrapper(((PowerCellBlockEntity) be).getEnergyStorage(side)), + ModBlockEntities.POWER_CELL_BE.get() + ); - Energy (TeamReborn Energy API is standard for Fabric) - EnergyStorage.SIDED.registerForBlockEntities((be, side) -> ((PowerCellBlockEntity)be).getEnergyStorage(side), ModBlockEntities.POWER_CELL_BE.get()); + EnergyStorage.SIDED.registerForBlockEntities((be, side) -> + new FabricEnergyWrapper(((GeneratorBlockEntity) be).getEnergyStorage(side)), + ModBlockEntities.GENERATOR_BE.get() + ); - Fluids (Fabric Transfer API) - FluidStorage.SIDED.registerForBlockEntities((be, side) -> ((TankBlockEntity)be).getTank(side), ModBlockEntities.TANK_BE.get()); - */ + EnergyStorage.SIDED.registerForBlockEntities((be, side) -> + new FabricEnergyWrapper(((DNAExtractorBlockEntity) be).getEnergyStorage(side)), + ModBlockEntities.DNA_EXTRACTOR_BE.get() + ); + + EnergyStorage.SIDED.registerForBlockEntities((be, side) -> + new FabricEnergyWrapper(((DNAAnalyzerBlockEntity) be).getEnergyStorage(side)), + ModBlockEntities.DNA_ANALYZER_BE.get() + ); + + EnergyStorage.SIDED.registerForBlockEntities((be, side) -> + new FabricEnergyWrapper(((DNAHybridizerBlockEntity) be).getEnergyStorage(side)), + ModBlockEntities.DNA_HYBRIDIZER_BE.get() + ); + + EnergyStorage.SIDED.registerForBlockEntities((be, side) -> + new FabricEnergyWrapper(((FossilCleanerBlockEntity) be).getEnergyStorage(side)), + ModBlockEntities.FOSSIL_CLEANER_BE.get() + ); + + EnergyStorage.SIDED.registerForBlockEntities((be, side) -> + new FabricEnergyWrapper(((FossilGrinderBlockEntity) be).getEnergyStorage(side)), + ModBlockEntities.FOSSIL_GRINDER_BE.get() + ); + + EnergyStorage.SIDED.registerForBlockEntities((be, side) -> + new FabricEnergyWrapper(((EmbryonicMachineBlockEntity) be).getEnergyStorage(side)), + ModBlockEntities.EMBRYONIC_MACHINE_BE.get() + ); + + EnergyStorage.SIDED.registerForBlockEntities((be, side) -> + new FabricEnergyWrapper(((EmbryoCalcificationMachineBlockEntity) be).getEnergyStorage(side)), + ModBlockEntities.EMBRYO_CALCIFICATION_MACHINE_BE.get() + ); + + EnergyStorage.SIDED.registerForBlockEntities((be, side) -> + new FabricEnergyWrapper(((IncubatorBlockEntity) be).getEnergyStorage(side)), + ModBlockEntities.INCUBATOR_BE.get() + ); } } diff --git a/fabricmc/src/main/java/net/cmr/jurassicrevived/platform/FabricEnergyWrapper.java b/fabricmc/src/main/java/net/cmr/jurassicrevived/platform/FabricEnergyWrapper.java new file mode 100644 index 0000000..033e791 --- /dev/null +++ b/fabricmc/src/main/java/net/cmr/jurassicrevived/platform/FabricEnergyWrapper.java @@ -0,0 +1,33 @@ +package net.cmr.jurassicrevived.platform; + +import net.cmr.jurassicrevived.block.entity.energy.ModEnergyStorage; +import net.fabricmc.fabric.api.transfer.v1.transaction.TransactionContext; +import team.reborn.energy.api.EnergyStorage; + +public class FabricEnergyWrapper implements EnergyStorage { + private final ModEnergyStorage storage; + + public FabricEnergyWrapper(ModEnergyStorage storage) { + this.storage = storage; + } + + @Override + public long insert(long maxAmount, TransactionContext transaction) { + return storage.receiveEnergy((int) maxAmount, true); + } + + @Override + public long extract(long maxAmount, TransactionContext transaction) { + return storage.extractEnergy((int) maxAmount, true); + } + + @Override + public long getAmount() { + return storage.getEnergyStored(); + } + + @Override + public long getCapacity() { + return storage.getMaxEnergyStored(); + } +} diff --git a/fabricmc/src/main/java/net/cmr/jurassicrevived/platform/FabricItemFluidHelper.java b/fabricmc/src/main/java/net/cmr/jurassicrevived/platform/FabricItemFluidHelper.java new file mode 100644 index 0000000..0105a67 --- /dev/null +++ b/fabricmc/src/main/java/net/cmr/jurassicrevived/platform/FabricItemFluidHelper.java @@ -0,0 +1,103 @@ +package net.cmr.jurassicrevived.platform; + +import dev.architectury.fluid.FluidStack; +import net.cmr.jurassicrevived.platform.services.IItemFluidHelper; +import net.fabricmc.fabric.api.transfer.v1.context.ContainerItemContext; +import net.fabricmc.fabric.api.transfer.v1.fluid.FluidStorage; +import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant; +import net.fabricmc.fabric.api.transfer.v1.item.ItemVariant; +import net.fabricmc.fabric.api.transfer.v1.storage.Storage; +import net.fabricmc.fabric.api.transfer.v1.storage.StorageView; +import net.fabricmc.fabric.api.transfer.v1.transaction.Transaction; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.level.material.Fluids; + +import java.util.Optional; + +public class FabricItemFluidHelper implements IItemFluidHelper { + + @Override + public Optional getContainedFluid(ItemStack stack) { + ContainerItemContext ctx = ContainerItemContext.withConstant(stack.copy()); + Storage storage = ctx.find(FluidStorage.ITEM); + if (storage == null) { + if (stack.is(Items.WATER_BUCKET)) return Optional.of(FluidStack.create(Fluids.WATER, 1000)); + if (stack.is(Items.LAVA_BUCKET)) return Optional.of(FluidStack.create(Fluids.LAVA, 1000)); + return Optional.empty(); + } + + for (StorageView view : storage) { + if (!view.isResourceBlank() && view.getAmount() > 0) { + return Optional.of(FluidStack.create(view.getResource().getFluid(), view.getAmount())); + } + } + return Optional.of(FluidStack.empty()); + } + + @Override + public TransferResult drain(ItemStack stack, long amount, boolean simulate) { + ContainerItemContext ctx = ContainerItemContext.withConstant(stack.copy()); + Storage storage = ctx.find(FluidStorage.ITEM); + if (storage == null) { + if (stack.is(Items.WATER_BUCKET) && amount >= 1000) { + return new TransferResult(1000, simulate ? stack : new ItemStack(Items.BUCKET)); + } + if (stack.is(Items.LAVA_BUCKET) && amount >= 1000) { + return new TransferResult(1000, simulate ? stack : new ItemStack(Items.BUCKET)); + } + return new TransferResult(0, stack); + } + + try (Transaction tx = Transaction.openOuter()) { + long extracted = 0; + for (StorageView view : storage) { + if (!view.isResourceBlank()) { + extracted = storage.extract(view.getResource(), amount, tx); + if (extracted > 0) break; + } + } + + if (extracted > 0) { + if (!simulate) tx.commit(); + ItemStack resultStack = ctx.getItemVariant().toStack((int) ctx.getAmount()); + return new TransferResult(extracted, resultStack); + } + } + return new TransferResult(0, stack); + } + + @Override + public TransferResult fill(ItemStack stack, FluidStack fluid, long amount, boolean simulate) { + ContainerItemContext ctx = ContainerItemContext.withConstant(stack.copy()); + Storage storage = ctx.find(FluidStorage.ITEM); + if (storage == null) { + if (stack.is(Items.BUCKET) && amount >= 1000) { + if (fluid.getFluid().isSame(Fluids.WATER)) { + return new TransferResult(1000, simulate ? stack : new ItemStack(Items.WATER_BUCKET)); + } + if (fluid.getFluid().isSame(Fluids.LAVA)) { + return new TransferResult(1000, simulate ? stack : new ItemStack(Items.LAVA_BUCKET)); + } + } + return new TransferResult(0, stack); + } + + try (Transaction tx = Transaction.openOuter()) { + long inserted = storage.insert(FluidVariant.of(fluid.getFluid()), amount, tx); + if (inserted > 0) { + if (!simulate) tx.commit(); + ItemStack resultStack = ctx.getItemVariant().toStack((int) ctx.getAmount()); + return new TransferResult(inserted, resultStack); + } + } + return new TransferResult(0, stack); + } + + @Override + public boolean isFluidHandler(ItemStack stack) { + ContainerItemContext ctx = ContainerItemContext.withConstant(stack); + Storage storage = ctx.find(FluidStorage.ITEM); + return storage != null || stack.is(Items.BUCKET) || stack.is(Items.WATER_BUCKET) || stack.is(Items.LAVA_BUCKET); + } +} diff --git a/fabricmc/src/main/java/net/cmr/jurassicrevived/platform/FabricTransferHelper.java b/fabricmc/src/main/java/net/cmr/jurassicrevived/platform/FabricTransferHelper.java new file mode 100644 index 0000000..e8fc820 --- /dev/null +++ b/fabricmc/src/main/java/net/cmr/jurassicrevived/platform/FabricTransferHelper.java @@ -0,0 +1,146 @@ +package net.cmr.jurassicrevived.platform; + +import net.cmr.jurassicrevived.platform.services.ITransferHelper; +import net.cmr.jurassicrevived.platform.transfer.PlatformItemHandler; +import net.fabricmc.fabric.api.transfer.v1.item.ItemStorage; +import net.fabricmc.fabric.api.transfer.v1.item.ItemVariant; +import net.fabricmc.fabric.api.transfer.v1.storage.Storage; +import net.fabricmc.fabric.api.transfer.v1.storage.StorageView; +import net.fabricmc.fabric.api.transfer.v1.transaction.Transaction; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; + +import dev.architectury.fluid.FluidStack; +import team.reborn.energy.api.EnergyStorage; +import net.cmr.jurassicrevived.platform.transfer.PlatformEnergyHandler; +import net.cmr.jurassicrevived.platform.transfer.PlatformFluidHandler; +import net.fabricmc.fabric.api.transfer.v1.fluid.FluidStorage; +import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant; +import net.fabricmc.fabric.api.transfer.v1.storage.StorageView; +import net.fabricmc.fabric.api.transfer.v1.transaction.Transaction; +//import net.fabricmc.fabric.api.transfer.v1.energy.EnergyStorage; +//import team.reborn.energy.api.EnergyStorage; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +public class FabricTransferHelper implements ITransferHelper { + + @Override + public Optional getItemHandler(Level level, BlockPos pos, Direction side) { + Storage storage = ItemStorage.SIDED.find(level, pos, side); + if (storage == null) return Optional.empty(); + return Optional.of(new FabricItemHandler(storage)); + } + + @Override + public Optional getFluidHandler(Level level, BlockPos pos, Direction side) { + var storage = FluidStorage.SIDED.find(level, pos, side); + if (storage == null) return Optional.empty(); + return Optional.of(new FabricFluidHandler(storage)); + } + + @Override + public Optional getEnergyHandler(Level level, BlockPos pos, Direction side) { + EnergyStorage storage = EnergyStorage.SIDED.find(level, pos, side); + return Optional.empty(); + } + + private static class FabricFluidHandler implements PlatformFluidHandler { + private final net.fabricmc.fabric.api.transfer.v1.storage.Storage storage; + + private FabricFluidHandler(net.fabricmc.fabric.api.transfer.v1.storage.Storage storage) { + this.storage = storage; + } + + @Override + public Iterable getExtractableFluids() { + List stacks = new ArrayList<>(); + for (StorageView view : storage) { + if (view.isResourceBlank()) continue; + FluidVariant v = view.getResource(); + long amt = view.getAmount(); + if (amt > 0) { + FluidStack stack = FluidStack.create(v.getFluid(), amt); + stacks.add(stack); + } + } + return stacks; + } + + @Override + public long extract(FluidStack stack, long amount, boolean simulate) { + try (Transaction tx = Transaction.openOuter()) { + long extracted = storage.extract(FluidVariant.of(stack.getFluid()), amount, tx); + if (!simulate) tx.commit(); + return extracted; + } + } + + @Override + public long insert(FluidStack stack, long amount, boolean simulate) { + try (Transaction tx = Transaction.openOuter()) { + long inserted = storage.insert(FluidVariant.of(stack.getFluid()), amount, tx); + if (!simulate) tx.commit(); + return inserted; + } + } + } + + private static class FabricEnergyHandler implements PlatformEnergyHandler { + private FabricEnergyHandler() { + } + + @Override + public int extract(int amount, boolean simulate) { + return 0; + } + + @Override + public int insert(int amount, boolean simulate) { + return 0; + } + } + + private static class FabricItemHandler implements PlatformItemHandler { + private final Storage storage; + + private FabricItemHandler(Storage storage) { + this.storage = storage; + } + + @Override + public Iterable getExtractableStacks() { + List stacks = new ArrayList<>(); + for (StorageView view : storage) { + if (view.isResourceBlank()) continue; + ItemVariant v = view.getResource(); + long amt = view.getAmount(); + if (amt > 0) stacks.add(v.toStack((int) Math.min(amt, Integer.MAX_VALUE))); + } + return stacks; + } + + @Override + public int extract(ItemStack stack, int amount, boolean simulate) { + try (Transaction tx = Transaction.openOuter()) { + long extracted = storage.extract(ItemVariant.of(stack), amount, tx); + if (!simulate) tx.commit(); + return (int) extracted; + } + } + + @Override + public int insert(ItemStack stack, int amount, boolean simulate) { + try (Transaction tx = Transaction.openOuter()) { + long inserted = storage.insert(ItemVariant.of(stack), amount, tx); + if (!simulate) tx.commit(); + return (int) inserted; + } + } + } +} diff --git a/fabricmc/src/main/resources/META-INF/services/net.cmr.jurassicrevived.platform.services.IItemFluidHelper b/fabricmc/src/main/resources/META-INF/services/net.cmr.jurassicrevived.platform.services.IItemFluidHelper new file mode 100644 index 0000000..02bfcab --- /dev/null +++ b/fabricmc/src/main/resources/META-INF/services/net.cmr.jurassicrevived.platform.services.IItemFluidHelper @@ -0,0 +1 @@ +net.cmr.jurassicrevived.platform.FabricItemFluidHelper \ No newline at end of file diff --git a/fabricmc/src/main/resources/META-INF/services/net.cmr.jurassicrevived.platform.services.ITransferHelper b/fabricmc/src/main/resources/META-INF/services/net.cmr.jurassicrevived.platform.services.ITransferHelper new file mode 100644 index 0000000..a3585a3 --- /dev/null +++ b/fabricmc/src/main/resources/META-INF/services/net.cmr.jurassicrevived.platform.services.ITransferHelper @@ -0,0 +1 @@ +net.cmr.jurassicrevived.platform.FabricTransferHelper \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 1a1d8c6..d7a2b74 100644 --- a/gradle.properties +++ b/gradle.properties @@ -41,4 +41,7 @@ cloth_config_version_1_21_1=15.0.140 # Jade jade_version=14.3.4 jade_version_1_20_1=11.13.1 -jade_version_1_21_1=15.10.4 \ No newline at end of file +jade_version_1_21_1=15.10.4 + +teamreborn_energy_1_20_1=3.0.0 +teamreborn_energy_1_21_1=4.1.0 \ No newline at end of file diff --git a/minecraftforge/src/main/java/net/cmr/jurassicrevived/event/ForgeEvents.java b/minecraftforge/src/main/java/net/cmr/jurassicrevived/event/ForgeEvents.java new file mode 100644 index 0000000..fdcec02 --- /dev/null +++ b/minecraftforge/src/main/java/net/cmr/jurassicrevived/event/ForgeEvents.java @@ -0,0 +1,106 @@ +// ... existing code ... +package net.cmr.jurassicrevived.event; + +import net.cmr.jurassicrevived.Constants; +import net.cmr.jurassicrevived.block.entity.custom.*; +import net.cmr.jurassicrevived.config.JRConfigManager; +import net.cmr.jurassicrevived.platform.ForgeEnergyStorage; +import net.cmr.jurassicrevived.platform.ForgeTankFluidAdapter; +import net.minecraft.core.Direction; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.entity.BlockEntity; +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.event.AttachCapabilitiesEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.common.util.NonNullSupplier; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +@Mod.EventBusSubscriber(modid = Constants.MOD_ID, bus = Mod.EventBusSubscriber.Bus.FORGE) +public class ForgeEvents { + + @SubscribeEvent + public static void attachCapabilities(AttachCapabilitiesEvent event) { + BlockEntity be = event.getObject(); + + if (be instanceof PowerCellBlockEntity pc) { + event.addCapability(Constants.rl("energy_power_cell"), + new EnergyProvider(() -> new ForgeEnergyStorage(pc.getEnergyStorage(null)))); + } + + if (be instanceof GeneratorBlockEntity gen) { + event.addCapability(Constants.rl("energy_generator"), + new EnergyProvider(() -> new ForgeEnergyStorage(gen.getEnergyStorage(null)))); + } + + if (be instanceof TankBlockEntity tank) { + event.addCapability(Constants.rl("fluid_tank"), + new FluidProvider(() -> new ForgeTankFluidAdapter(tank.getTank(null)))); + } + + if (JRConfigManager.get().requirePower) { + if (be instanceof DNAExtractorBlockEntity e) { + event.addCapability(Constants.rl("energy_dna_extractor"), + new EnergyProvider(() -> new ForgeEnergyStorage(e.getEnergyStorage(null)))); + } + if (be instanceof DNAAnalyzerBlockEntity e) { + event.addCapability(Constants.rl("energy_dna_analyzer"), + new EnergyProvider(() -> new ForgeEnergyStorage(e.getEnergyStorage(null)))); + } + if (be instanceof FossilCleanerBlockEntity e) { + event.addCapability(Constants.rl("energy_fossil_cleaner"), + new EnergyProvider(() -> new ForgeEnergyStorage(e.getEnergyStorage(null)))); + } + if (be instanceof FossilGrinderBlockEntity e) { + event.addCapability(Constants.rl("energy_fossil_grinder"), + new EnergyProvider(() -> new ForgeEnergyStorage(e.getEnergyStorage(null)))); + } + if (be instanceof DNAHybridizerBlockEntity e) { + event.addCapability(Constants.rl("energy_dna_hybridizer"), + new EnergyProvider(() -> new ForgeEnergyStorage(e.getEnergyStorage(null)))); + } + if (be instanceof EmbryonicMachineBlockEntity e) { + event.addCapability(Constants.rl("energy_embryonic_machine"), + new EnergyProvider(() -> new ForgeEnergyStorage(e.getEnergyStorage(null)))); + } + if (be instanceof EmbryoCalcificationMachineBlockEntity e) { + event.addCapability(Constants.rl("energy_embryo_calcification"), + new EnergyProvider(() -> new ForgeEnergyStorage(e.getEnergyStorage(null)))); + } + if (be instanceof IncubatorBlockEntity e) { + event.addCapability(Constants.rl("energy_incubator"), + new EnergyProvider(() -> new ForgeEnergyStorage(e.getEnergyStorage(null)))); + } + } + } + + private static final class EnergyProvider implements ICapabilityProvider { + private final LazyOptional lazy; + + private EnergyProvider(NonNullSupplier supplier) { + this.lazy = LazyOptional.of(supplier); + } + + @Override + public @NotNull LazyOptional getCapability(@NotNull Capability cap, @Nullable Direction side) { + return cap == ForgeCapabilities.ENERGY ? lazy.cast() : LazyOptional.empty(); + } + } + + private static final class FluidProvider implements ICapabilityProvider { + private final LazyOptional lazy; + + private FluidProvider(NonNullSupplier supplier) { + this.lazy = LazyOptional.of(supplier); + } + + @Override + public @NotNull LazyOptional getCapability(@NotNull Capability cap, @Nullable Direction side) { + return cap == ForgeCapabilities.FLUID_HANDLER ? lazy.cast() : LazyOptional.empty(); + } + } +} \ No newline at end of file diff --git a/minecraftforge/src/main/java/net/cmr/jurassicrevived/platform/ForgeEnergyStorage.java b/minecraftforge/src/main/java/net/cmr/jurassicrevived/platform/ForgeEnergyStorage.java new file mode 100644 index 0000000..2d665ad --- /dev/null +++ b/minecraftforge/src/main/java/net/cmr/jurassicrevived/platform/ForgeEnergyStorage.java @@ -0,0 +1,36 @@ +package net.cmr.jurassicrevived.platform; + +import net.cmr.jurassicrevived.block.entity.energy.ModEnergyStorage; +import net.minecraftforge.energy.IEnergyStorage; + +public record ForgeEnergyStorage(ModEnergyStorage storage) implements IEnergyStorage { + @Override + public int receiveEnergy(int maxReceive, boolean simulate) { + return storage.receiveEnergy(maxReceive, simulate); + } + + @Override + public int extractEnergy(int maxExtract, boolean simulate) { + return storage.extractEnergy(maxExtract, simulate); + } + + @Override + public int getEnergyStored() { + return storage.getEnergyStored(); + } + + @Override + public int getMaxEnergyStored() { + return storage.getMaxEnergyStored(); + } + + @Override + public boolean canExtract() { + return storage.canExtract(); + } + + @Override + public boolean canReceive() { + return storage.canReceive(); + } +} diff --git a/minecraftforge/src/main/java/net/cmr/jurassicrevived/platform/ForgeItemFluidHelper.java b/minecraftforge/src/main/java/net/cmr/jurassicrevived/platform/ForgeItemFluidHelper.java new file mode 100644 index 0000000..e493a3d --- /dev/null +++ b/minecraftforge/src/main/java/net/cmr/jurassicrevived/platform/ForgeItemFluidHelper.java @@ -0,0 +1,79 @@ +package net.cmr.jurassicrevived.platform; + +import dev.architectury.fluid.FluidStack; +import net.cmr.jurassicrevived.platform.services.IItemFluidHelper; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.level.material.Fluids; +import net.minecraftforge.fluids.FluidUtil; +import net.minecraftforge.fluids.capability.IFluidHandlerItem; + +import java.util.Optional; + +public class ForgeItemFluidHelper implements IItemFluidHelper { + + @Override + public Optional getContainedFluid(ItemStack stack) { + Optional handlerFluid = FluidUtil.getFluidHandler(stack.copy()) + .map(handler -> { + if (handler.getTanks() <= 0) return FluidStack.empty(); + var fs = handler.getFluidInTank(0); + if (fs.isEmpty()) return FluidStack.empty(); + return FluidStack.create(fs.getFluid(), fs.getAmount(), fs.getTag()); + }); + + if (handlerFluid.isPresent() && !handlerFluid.get().isEmpty()) return handlerFluid; + + if (stack.is(Items.WATER_BUCKET)) { + return Optional.of(FluidStack.create(Fluids.WATER, 1000)); + } + if (stack.is(Items.LAVA_BUCKET)) { + return Optional.of(FluidStack.create(Fluids.LAVA, 1000)); + } + return Optional.of(FluidStack.empty()); + } + + @Override + public TransferResult drain(ItemStack stack, long amount, boolean simulate) { + Optional handlerResult = FluidUtil.getFluidHandler(stack.copy()) + .map(handler -> { + var drained = handler.drain((int) amount, + simulate ? IFluidHandlerItem.FluidAction.SIMULATE : IFluidHandlerItem.FluidAction.EXECUTE); + return new TransferResult(drained.getAmount(), handler.getContainer()); + }); + + if (handlerResult.isPresent()) return handlerResult.get(); + + if (stack.is(Items.WATER_BUCKET) && amount >= 1000) { + return new TransferResult(1000, simulate ? stack : new ItemStack(Items.BUCKET)); + } + if (stack.is(Items.LAVA_BUCKET) && amount >= 1000) { + return new TransferResult(1000, simulate ? stack : new ItemStack(Items.BUCKET)); + } + + return new TransferResult(0, stack); + } + + @Override + public TransferResult fill(ItemStack stack, FluidStack fluid, long amount, boolean simulate) { + Optional handlerResult = FluidUtil.getFluidHandler(stack.copy()) + .map(handler -> { + var toFill = new net.minecraftforge.fluids.FluidStack(fluid.getFluid(), (int) amount, fluid.getTag()); + int filled = handler.fill(toFill, + simulate ? IFluidHandlerItem.FluidAction.SIMULATE : IFluidHandlerItem.FluidAction.EXECUTE); + return new TransferResult(filled, handler.getContainer()); + }); + + if (handlerResult.isPresent()) return handlerResult.get(); + + if (stack.is(Items.BUCKET) && amount >= 1000) { + if (fluid.getFluid().isSame(Fluids.WATER)) { + return new TransferResult(1000, simulate ? stack : new ItemStack(Items.WATER_BUCKET)); + } + if (fluid.getFluid().isSame(Fluids.LAVA)) { + return new TransferResult(1000, simulate ? stack : new ItemStack(Items.LAVA_BUCKET)); + } + } + return new TransferResult(0, stack); + } +} diff --git a/minecraftforge/src/main/java/net/cmr/jurassicrevived/platform/ForgeTankFluidAdapter.java b/minecraftforge/src/main/java/net/cmr/jurassicrevived/platform/ForgeTankFluidAdapter.java new file mode 100644 index 0000000..102861b --- /dev/null +++ b/minecraftforge/src/main/java/net/cmr/jurassicrevived/platform/ForgeTankFluidAdapter.java @@ -0,0 +1,49 @@ +package net.cmr.jurassicrevived.platform; + +import net.cmr.jurassicrevived.block.entity.custom.TankBlockEntity; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.capability.IFluidHandler; + +public record ForgeTankFluidAdapter(TankBlockEntity.TankFluidHandler tank) implements IFluidHandler { + + @Override + public int getTanks() { + return 1; + } + + @Override + public FluidStack getFluidInTank(int tankIndex) { + if (tankIndex != 0) return FluidStack.EMPTY; + return new FluidStack(tank.getFluid().getFluid(), (int) tank.getFluid().getAmount()); + } + + @Override + public int getTankCapacity(int tankIndex) { + return tankIndex == 0 ? (int) tank.getCapacity() : 0; + } + + @Override + public boolean isFluidValid(int tankIndex, FluidStack stack) { + return tankIndex == 0; + } + + @Override + public int fill(FluidStack resource, FluidAction action) { + if (resource.isEmpty()) return 0; + long filled = tank.fill(dev.architectury.fluid.FluidStack.create(resource.getFluid(), resource.getAmount()), action.simulate()); + return (int) filled; + } + + @Override + public FluidStack drain(FluidStack resource, FluidAction action) { + if (resource.isEmpty()) return FluidStack.EMPTY; + var drained = tank.drain(resource.getAmount(), action.simulate()); + return new FluidStack(drained.getFluid(), (int) drained.getAmount()); + } + + @Override + public FluidStack drain(int maxDrain, FluidAction action) { + var drained = tank.drain(maxDrain, action.simulate()); + return new FluidStack(drained.getFluid(), (int) drained.getAmount()); + } +} diff --git a/minecraftforge/src/main/java/net/cmr/jurassicrevived/platform/ForgeTransferHelper.java b/minecraftforge/src/main/java/net/cmr/jurassicrevived/platform/ForgeTransferHelper.java new file mode 100644 index 0000000..2271997 --- /dev/null +++ b/minecraftforge/src/main/java/net/cmr/jurassicrevived/platform/ForgeTransferHelper.java @@ -0,0 +1,148 @@ +package net.cmr.jurassicrevived.platform; + +import net.cmr.jurassicrevived.platform.services.ITransferHelper; +import dev.architectury.fluid.FluidStack; +import net.cmr.jurassicrevived.platform.transfer.PlatformItemHandler; +import net.cmr.jurassicrevived.platform.transfer.PlatformEnergyHandler; +import net.cmr.jurassicrevived.platform.transfer.PlatformFluidHandler; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraftforge.common.capabilities.ForgeCapabilities; +import net.minecraftforge.energy.IEnergyStorage; +import net.minecraftforge.fluids.capability.IFluidHandler; +import net.minecraftforge.items.IItemHandler; +import net.minecraftforge.items.IItemHandlerModifiable; +import net.minecraftforge.items.ItemHandlerHelper; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +public class ForgeTransferHelper implements ITransferHelper { + + @Override + public Optional getItemHandler(Level level, BlockPos pos, Direction side) { + BlockEntity be = level.getBlockEntity(pos); + if (be == null) return Optional.empty(); + return be.getCapability(ForgeCapabilities.ITEM_HANDLER, side) + .resolve() + .map(ForgeItemHandler::new); + } + + @Override + public Optional getFluidHandler(Level level, BlockPos pos, Direction side) { + BlockEntity be = level.getBlockEntity(pos); + if (be == null) return Optional.empty(); + return be.getCapability(ForgeCapabilities.FLUID_HANDLER, side) + .resolve() + .map(ForgeFluidHandler::new); + } + + @Override + public Optional getEnergyHandler(Level level, BlockPos pos, Direction side) { + BlockEntity be = level.getBlockEntity(pos); + if (be == null) return Optional.empty(); + return be.getCapability(ForgeCapabilities.ENERGY, side) + .resolve() + .map(ForgeEnergyHandler::new); + } + + private static class ForgeItemHandler implements PlatformItemHandler { + private final IItemHandler handler; + + private ForgeItemHandler(IItemHandler handler) { + this.handler = handler; + } + + @Override + public Iterable getExtractableStacks() { + List stacks = new ArrayList<>(); + for (int i = 0; i < handler.getSlots(); i++) { + ItemStack stack = handler.getStackInSlot(i); + if (!stack.isEmpty()) stacks.add(stack.copy()); + } + return stacks; + } + + @Override + public int extract(ItemStack stack, int amount, boolean simulate) { + int remaining = amount; + for (int i = 0; i < handler.getSlots() && remaining > 0; i++) { + ItemStack slot = handler.getStackInSlot(i); + if (!ItemHandlerHelper.canItemStacksStack(slot, stack)) continue; + + ItemStack extracted = handler.extractItem(i, remaining, simulate); + remaining -= extracted.getCount(); + } + return amount - remaining; + } + + @Override + public int insert(ItemStack stack, int amount, boolean simulate) { + ItemStack toInsert = stack.copy(); + toInsert.setCount(amount); + + ItemStack remainder = toInsert; + for (int i = 0; i < handler.getSlots() && !remainder.isEmpty(); i++) { + remainder = handler.insertItem(i, remainder, simulate); + } + return amount - remainder.getCount(); + } + } + + private static class ForgeFluidHandler implements PlatformFluidHandler { + private final IFluidHandler handler; + + private ForgeFluidHandler(IFluidHandler handler) { + this.handler = handler; + } + + @Override + public Iterable getExtractableFluids() { + List stacks = new ArrayList<>(); + for (int i = 0; i < handler.getTanks(); i++) { + net.minecraftforge.fluids.FluidStack fs = handler.getFluidInTank(i); + if (!fs.isEmpty()) { + stacks.add(FluidStack.create(fs.getFluid(), fs.getAmount(), fs.getTag())); + } + } + return stacks; + } + + @Override + public long extract(FluidStack stack, long amount, boolean simulate) { + net.minecraftforge.fluids.FluidStack req = + new net.minecraftforge.fluids.FluidStack(stack.getFluid(), (int) amount, stack.getTag()); + net.minecraftforge.fluids.FluidStack drained = handler.drain(req, simulate ? IFluidHandler.FluidAction.SIMULATE : IFluidHandler.FluidAction.EXECUTE); + return drained.getAmount(); + } + + @Override + public long insert(FluidStack stack, long amount, boolean simulate) { + net.minecraftforge.fluids.FluidStack toFill = + new net.minecraftforge.fluids.FluidStack(stack.getFluid(), (int) amount, stack.getTag()); + return handler.fill(toFill, simulate ? IFluidHandler.FluidAction.SIMULATE : IFluidHandler.FluidAction.EXECUTE); + } + } + + private static class ForgeEnergyHandler implements PlatformEnergyHandler { + private final IEnergyStorage storage; + + private ForgeEnergyHandler(IEnergyStorage storage) { + this.storage = storage; + } + + @Override + public int extract(int amount, boolean simulate) { + return storage.extractEnergy(amount, simulate); + } + + @Override + public int insert(int amount, boolean simulate) { + return storage.receiveEnergy(amount, simulate); + } + } +} diff --git a/minecraftforge/src/main/resources/META-INF/services/net.cmr.jurassicrevived.platform.services.IItemFluidHelper b/minecraftforge/src/main/resources/META-INF/services/net.cmr.jurassicrevived.platform.services.IItemFluidHelper new file mode 100644 index 0000000..1a5ab13 --- /dev/null +++ b/minecraftforge/src/main/resources/META-INF/services/net.cmr.jurassicrevived.platform.services.IItemFluidHelper @@ -0,0 +1 @@ +net.cmr.jurassicrevived.platform.ForgeItemFluidHelper \ No newline at end of file diff --git a/minecraftforge/src/main/resources/META-INF/services/net.cmr.jurassicrevived.platform.services.ITransferHelper b/minecraftforge/src/main/resources/META-INF/services/net.cmr.jurassicrevived.platform.services.ITransferHelper new file mode 100644 index 0000000..39a53a0 --- /dev/null +++ b/minecraftforge/src/main/resources/META-INF/services/net.cmr.jurassicrevived.platform.services.ITransferHelper @@ -0,0 +1 @@ +net.cmr.jurassicrevived.platform.ForgeTransferHelper \ No newline at end of file diff --git a/neoforge/src/main/java/net/cmr/jurassicrevived/event/NeoForgeEvents.java b/neoforge/src/main/java/net/cmr/jurassicrevived/event/NeoForgeEvents.java index 20a7dc6..5de4b14 100644 --- a/neoforge/src/main/java/net/cmr/jurassicrevived/event/NeoForgeEvents.java +++ b/neoforge/src/main/java/net/cmr/jurassicrevived/event/NeoForgeEvents.java @@ -2,11 +2,18 @@ package net.cmr.jurassicrevived.event; import net.cmr.jurassicrevived.Constants; import net.cmr.jurassicrevived.block.entity.ModBlockEntities; +import net.cmr.jurassicrevived.block.entity.custom.FossilCleanerBlockEntity; +import net.cmr.jurassicrevived.block.entity.custom.GeneratorBlockEntity; import net.cmr.jurassicrevived.config.JRConfigManager; +import net.cmr.jurassicrevived.block.entity.custom.PowerCellBlockEntity; +import net.cmr.jurassicrevived.block.entity.custom.TankBlockEntity; +import net.cmr.jurassicrevived.neoforge.capabilities.NeoForgeEnergyStorage; import net.neoforged.bus.api.SubscribeEvent; import net.neoforged.fml.common.EventBusSubscriber; import net.neoforged.neoforge.capabilities.Capabilities; import net.neoforged.neoforge.capabilities.RegisterCapabilitiesEvent; +import net.neoforged.neoforge.fluids.FluidStack; +import net.neoforged.neoforge.fluids.capability.IFluidHandler; @EventBusSubscriber(modid = Constants.MOD_ID) public class NeoForgeEvents @@ -24,27 +31,64 @@ public class NeoForgeEvents event.registerBlockEntity(Capabilities.ItemHandler.BLOCK, ModBlockEntities.EMBRYO_CALCIFICATION_MACHINE_BE.get(), (be, side) -> be.getItemHandler(side)); event.registerBlockEntity(Capabilities.ItemHandler.BLOCK, ModBlockEntities.CRATE_BE.get(), (be, side) -> be.getItemHandler(side)); event.registerBlockEntity(Capabilities.ItemHandler.BLOCK, ModBlockEntities.INCUBATOR_BE.get(), (be, side) -> be.getItemHandler(side)); + */ - Energy - event.registerBlockEntity(Capabilities.EnergyStorage.BLOCK, ModBlockEntities.POWER_CELL_BE.get(), (be, side) -> be.getEnergyStorage(side)); - event.registerBlockEntity(Capabilities.EnergyStorage.BLOCK, ModBlockEntities.GENERATOR_BE.get(), (be, side) -> be.getEnergyStorage(side)); + // Energy + event.registerBlockEntity(Capabilities.EnergyStorage.BLOCK, ModBlockEntities.POWER_CELL_BE.get(), + (be, side) -> new NeoForgeEnergyStorage(((PowerCellBlockEntity) be).getEnergyStorage(side))); - Fluids - event.registerBlockEntity(Capabilities.FluidHandler.BLOCK, ModBlockEntities.TANK_BE.get(), (be, side) -> be.getTank(side)); - event.registerBlockEntity(Capabilities.FluidHandler.BLOCK, ModBlockEntities.FOSSIL_CLEANER_BE.get(), (be, side) -> be.getTank(side)); + event.registerBlockEntity(Capabilities.EnergyStorage.BLOCK, ModBlockEntities.GENERATOR_BE.get(), + (be, side) -> new NeoForgeEnergyStorage(((GeneratorBlockEntity) be).getEnergyStorage(side))); - Machine Logic (if config allows) - if (JRConfigManager.get().requirePower) { - event.registerBlockEntity(Capabilities.EnergyStorage.BLOCK, ModBlockEntities.DNA_EXTRACTOR_BE.get(), (be, side) -> be.getEnergyStorage(side)); - event.registerBlockEntity(Capabilities.EnergyStorage.BLOCK, ModBlockEntities.DNA_ANALYZER_BE.get(), (be, side) -> be.getEnergyStorage(side)); - event.registerBlockEntity(Capabilities.EnergyStorage.BLOCK, ModBlockEntities.FOSSIL_CLEANER_BE.get(), (be, side) -> be.getEnergyStorage(side)); - event.registerBlockEntity(Capabilities.EnergyStorage.BLOCK, ModBlockEntities.FOSSIL_GRINDER_BE.get(), (be, side) -> be.getEnergyStorage(side)); - event.registerBlockEntity(Capabilities.EnergyStorage.BLOCK, ModBlockEntities.DNA_HYBRIDIZER_BE.get(), (be, side) -> be.getEnergyStorage(side)); - event.registerBlockEntity(Capabilities.EnergyStorage.BLOCK, ModBlockEntities.EMBRYONIC_MACHINE_BE.get(), (be, side) -> be.getEnergyStorage(side)); - event.registerBlockEntity(Capabilities.EnergyStorage.BLOCK, ModBlockEntities.EMBRYO_CALCIFICATION_MACHINE_BE.get(), (be, side) -> be.getEnergyStorage(side)); - event.registerBlockEntity(Capabilities.EnergyStorage.BLOCK, ModBlockEntities.INCUBATOR_BE.get(), (be, side) -> be.getEnergyStorage(side)); - } + // Fluids + event.registerBlockEntity(Capabilities.FluidHandler.BLOCK, ModBlockEntities.TANK_BE.get(), + (be, side) -> new TankFluidAdapter(((TankBlockEntity) be).getTank(side))); - */ + //event.registerBlockEntity(Capabilities.FluidHandler.BLOCK, ModBlockEntities.FOSSIL_CLEANER_BE.get(), + // (be, side) -> new TankFluidAdapter(((FossilCleanerBlockEntity) be).getTank(side))); + } + + private record TankFluidAdapter(TankBlockEntity.TankFluidHandler tank) implements IFluidHandler { + + @Override + public int getTanks() { + return 1; + } + + @Override + public FluidStack getFluidInTank(int tankIndex) { + if (tankIndex != 0) return FluidStack.EMPTY; + return new FluidStack(tank.getFluid().getFluid(), (int) tank.getFluid().getAmount()); + } + + @Override + public int getTankCapacity(int tankIndex) { + return tankIndex == 0 ? (int) tank.getCapacity() : 0; + } + + @Override + public boolean isFluidValid(int tankIndex, FluidStack stack) { + return tankIndex == 0; + } + + @Override + public int fill(FluidStack resource, FluidAction action) { + if (resource.isEmpty()) return 0; + long filled = tank.fill(dev.architectury.fluid.FluidStack.create(resource.getFluid(), resource.getAmount()), action.simulate()); + return (int) filled; + } + + @Override + public FluidStack drain(FluidStack resource, FluidAction action) { + if (resource.isEmpty()) return FluidStack.EMPTY; + var drained = tank.drain(resource.getAmount(), action.simulate()); + return new FluidStack(drained.getFluid(), (int) drained.getAmount()); + } + + @Override + public FluidStack drain(int maxDrain, FluidAction action) { + var drained = tank.drain(maxDrain, action.simulate()); + return new FluidStack(drained.getFluid(), (int) drained.getAmount()); + } } } diff --git a/neoforge/src/main/java/net/cmr/jurassicrevived/platform/NeoForgeItemFluidHelper.java b/neoforge/src/main/java/net/cmr/jurassicrevived/platform/NeoForgeItemFluidHelper.java new file mode 100644 index 0000000..fb73513 --- /dev/null +++ b/neoforge/src/main/java/net/cmr/jurassicrevived/platform/NeoForgeItemFluidHelper.java @@ -0,0 +1,84 @@ +package net.cmr.jurassicrevived.platform; + +import dev.architectury.fluid.FluidStack; +import net.cmr.jurassicrevived.platform.services.IItemFluidHelper; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.level.material.Fluids; +import net.neoforged.neoforge.fluids.FluidUtil; +import net.neoforged.neoforge.fluids.capability.IFluidHandlerItem; + +import java.util.Optional; + +public class NeoForgeItemFluidHelper implements IItemFluidHelper { + + @Override + public Optional getContainedFluid(ItemStack stack) { + Optional handlerFluid = FluidUtil.getFluidHandler(stack.copy()) + .map(handler -> { + if (handler.getTanks() <= 0) return FluidStack.empty(); + var fs = handler.getFluidInTank(0); + if (fs.isEmpty()) return FluidStack.empty(); + return FluidStack.create(fs.getFluid(), fs.getAmount()); + }); + + if (handlerFluid.isPresent() && !handlerFluid.get().isEmpty()) return handlerFluid; + + if (stack.is(Items.WATER_BUCKET)) { + return Optional.of(FluidStack.create(Fluids.WATER, 1000)); + } + if (stack.is(Items.LAVA_BUCKET)) { + return Optional.of(FluidStack.create(Fluids.LAVA, 1000)); + } + return Optional.of(FluidStack.empty()); + } + + @Override + public TransferResult drain(ItemStack stack, long amount, boolean simulate) { + Optional handlerResult = FluidUtil.getFluidHandler(stack.copy()) + .map(handler -> { + var drained = handler.drain((int) amount, + simulate ? IFluidHandlerItem.FluidAction.SIMULATE : IFluidHandlerItem.FluidAction.EXECUTE); + return new TransferResult(drained.getAmount(), handler.getContainer()); + }); + + if (handlerResult.isPresent()) return handlerResult.get(); + + if (stack.is(Items.WATER_BUCKET) && amount >= 1000) { + return new TransferResult(1000, simulate ? stack : new ItemStack(Items.BUCKET)); + } + if (stack.is(Items.LAVA_BUCKET) && amount >= 1000) { + return new TransferResult(1000, simulate ? stack : new ItemStack(Items.BUCKET)); + } + + return new TransferResult(0, stack); + } + + @Override + public TransferResult fill(ItemStack stack, FluidStack fluid, long amount, boolean simulate) { + Optional handlerResult = FluidUtil.getFluidHandler(stack.copy()) + .map(handler -> { + var toFill = new net.neoforged.neoforge.fluids.FluidStack(fluid.getFluid(), (int) amount); + int filled = handler.fill(toFill, + simulate ? IFluidHandlerItem.FluidAction.SIMULATE : IFluidHandlerItem.FluidAction.EXECUTE); + return new TransferResult(filled, handler.getContainer()); + }); + + if (handlerResult.isPresent()) return handlerResult.get(); + + if (stack.is(Items.BUCKET) && amount >= 1000) { + if (fluid.getFluid().isSame(Fluids.WATER)) { + return new TransferResult(1000, simulate ? stack : new ItemStack(Items.WATER_BUCKET)); + } + if (fluid.getFluid().isSame(Fluids.LAVA)) { + return new TransferResult(1000, simulate ? stack : new ItemStack(Items.LAVA_BUCKET)); + } + } + return new TransferResult(0, stack); + } + + @Override + public boolean isFluidHandler(ItemStack stack) { + return FluidUtil.getFluidHandler(stack).isPresent() || stack.is(Items.BUCKET) || stack.is(Items.WATER_BUCKET) || stack.is(Items.LAVA_BUCKET); + } +} diff --git a/neoforge/src/main/java/net/cmr/jurassicrevived/platform/NeoForgeTransferHelper.java b/neoforge/src/main/java/net/cmr/jurassicrevived/platform/NeoForgeTransferHelper.java new file mode 100644 index 0000000..c349d0c --- /dev/null +++ b/neoforge/src/main/java/net/cmr/jurassicrevived/platform/NeoForgeTransferHelper.java @@ -0,0 +1,161 @@ +package net.cmr.jurassicrevived.platform; + +import net.cmr.jurassicrevived.platform.services.ITransferHelper; +import net.cmr.jurassicrevived.platform.transfer.PlatformItemHandler; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.neoforged.neoforge.capabilities.Capabilities; +import dev.architectury.fluid.FluidStack; +import net.cmr.jurassicrevived.platform.transfer.InternalFluidHandlerAdapter; +import net.cmr.jurassicrevived.platform.transfer.InternalFluidProvider; +import net.cmr.jurassicrevived.platform.transfer.PlatformEnergyHandler; +import net.cmr.jurassicrevived.platform.transfer.PlatformFluidHandler; +import net.neoforged.neoforge.capabilities.Capabilities; +import net.neoforged.neoforge.energy.IEnergyStorage; +import net.neoforged.neoforge.fluids.capability.IFluidHandler; +import net.neoforged.neoforge.items.IItemHandler; +import net.neoforged.neoforge.items.ItemHandlerHelper; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +public class NeoForgeTransferHelper implements ITransferHelper { + + @Override + public Optional getItemHandler(Level level, BlockPos pos, Direction side) { + IItemHandler handler = level.getCapability(Capabilities.ItemHandler.BLOCK, pos, side); + return Optional.ofNullable(handler).map(NeoForgeItemHandler::new); + } + + @Override + public Optional getFluidHandler(Level level, BlockPos pos, Direction side) { + IFluidHandler handler = level.getCapability(Capabilities.FluidHandler.BLOCK, pos, side); + if (handler != null) return Optional.of(new NeoForgeFluidHandler(handler)); + + BlockEntity be = level.getBlockEntity(pos); + if (be instanceof InternalFluidProvider provider) { + return Optional.of(new InternalFluidHandlerAdapter(provider.getFluidHandler(side))); + } + return Optional.empty(); + } + + @Override + public Optional getEnergyHandler(Level level, BlockPos pos, Direction side) { + IEnergyStorage storage = level.getCapability(Capabilities.EnergyStorage.BLOCK, pos, side); + return Optional.ofNullable(storage).map(NeoForgeEnergyHandler::new); + } + + private static class NeoForgeFluidHandler implements PlatformFluidHandler { + private final IFluidHandler handler; + + private NeoForgeFluidHandler(IFluidHandler handler) { + this.handler = handler; + } + + @Override + public Iterable getExtractableFluids() { + List stacks = new ArrayList<>(); + for (int i = 0; i < handler.getTanks(); i++) { + net.neoforged.neoforge.fluids.FluidStack fs = handler.getFluidInTank(i); + if (!fs.isEmpty()) { + stacks.add(FluidStack.create(fs.getFluid(), fs.getAmount())); + } + } + return stacks; + } + + @Override + public long extract(FluidStack stack, long amount, boolean simulate) { + net.neoforged.neoforge.fluids.FluidStack req = + new net.neoforged.neoforge.fluids.FluidStack(stack.getFluid(), (int) amount); + net.neoforged.neoforge.fluids.FluidStack drained = handler.drain( + req, + simulate ? IFluidHandler.FluidAction.SIMULATE : IFluidHandler.FluidAction.EXECUTE + ); + return drained.getAmount(); + } + + @Override + public long insert(FluidStack stack, long amount, boolean simulate) { + net.neoforged.neoforge.fluids.FluidStack toFill = + new net.neoforged.neoforge.fluids.FluidStack(stack.getFluid(), (int) amount); + return handler.fill( + toFill, + simulate ? IFluidHandler.FluidAction.SIMULATE : IFluidHandler.FluidAction.EXECUTE + ); + } + } + + private static class NeoForgeEnergyHandler implements PlatformEnergyHandler { + private final IEnergyStorage storage; + + private NeoForgeEnergyHandler(IEnergyStorage storage) { + this.storage = storage; + } + + @Override + public int extract(int amount, boolean simulate) { + return storage.extractEnergy(amount, simulate); + } + + @Override + public int insert(int amount, boolean simulate) { + return storage.receiveEnergy(amount, simulate); + } + } + + private static class NeoForgeItemHandler implements PlatformItemHandler { + private final IItemHandler handler; + + private NeoForgeItemHandler(IItemHandler handler) { + this.handler = handler; + } + + @Override + public Iterable getExtractableStacks() { + List stacks = new ArrayList<>(); + for (int i = 0; i < handler.getSlots(); i++) { + ItemStack stack = handler.getStackInSlot(i); + if (!stack.isEmpty()) stacks.add(stack.copy()); + } + return stacks; + } + + @Override + public int extract(ItemStack stack, int amount, boolean simulate) { + int remaining = amount; + for (int i = 0; i < handler.getSlots() && remaining > 0; i++) { + ItemStack slot = handler.getStackInSlot(i); + if (!itemsMatch(slot, stack)) continue; + + ItemStack extracted = handler.extractItem(i, remaining, simulate); + remaining -= extracted.getCount(); + } + return amount - remaining; + } + + private static boolean itemsMatch(ItemStack a, ItemStack b) { + //? if >1.20.1 { + return ItemStack.isSameItemSameComponents(a, b); + //?} else { + /*return ItemStack.isSameItemSameTags(a, b);*/ + //?} + } + + @Override + public int insert(ItemStack stack, int amount, boolean simulate) { + ItemStack toInsert = stack.copy(); + toInsert.setCount(amount); + + ItemStack remainder = toInsert; + for (int i = 0; i < handler.getSlots() && !remainder.isEmpty(); i++) { + remainder = handler.insertItem(i, remainder, simulate); + } + return amount - remainder.getCount(); + } + } +} diff --git a/neoforge/src/main/resources/META-INF/services/net.cmr.jurassicrevived.platform.services.IItemFluidHelper b/neoforge/src/main/resources/META-INF/services/net.cmr.jurassicrevived.platform.services.IItemFluidHelper new file mode 100644 index 0000000..f650d68 --- /dev/null +++ b/neoforge/src/main/resources/META-INF/services/net.cmr.jurassicrevived.platform.services.IItemFluidHelper @@ -0,0 +1 @@ +net.cmr.jurassicrevived.platform.NeoForgeItemFluidHelper \ No newline at end of file diff --git a/neoforge/src/main/resources/META-INF/services/net.cmr.jurassicrevived.platform.services.ITransferHelper b/neoforge/src/main/resources/META-INF/services/net.cmr.jurassicrevived.platform.services.ITransferHelper new file mode 100644 index 0000000..e120829 --- /dev/null +++ b/neoforge/src/main/resources/META-INF/services/net.cmr.jurassicrevived.platform.services.ITransferHelper @@ -0,0 +1 @@ +net.cmr.jurassicrevived.platform.NeoForgeTransferHelper \ No newline at end of file