diff --git a/src/main/java/net/xevianlight/aphelion/block/entity/custom/PipeTestBlockEntity.java b/src/main/java/net/xevianlight/aphelion/block/entity/custom/PipeTestBlockEntity.java index 056b3a9..ab05275 100644 --- a/src/main/java/net/xevianlight/aphelion/block/entity/custom/PipeTestBlockEntity.java +++ b/src/main/java/net/xevianlight/aphelion/block/entity/custom/PipeTestBlockEntity.java @@ -10,31 +10,26 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; -import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.Vec3; -import net.neoforged.neoforge.capabilities.BlockCapability; -import net.neoforged.neoforge.capabilities.BlockCapabilityCache; import net.neoforged.neoforge.capabilities.Capabilities; -import net.neoforged.neoforge.items.IItemHandler; import net.xevianlight.aphelion.Aphelion; import net.xevianlight.aphelion.block.custom.PipeTestBlock; import net.xevianlight.aphelion.block.custom.base.TickableBlockEntity; import net.xevianlight.aphelion.core.init.ModBlockEntities; import net.xevianlight.aphelion.core.init.ModBlocks; +import net.xevianlight.aphelion.systems.conveyor.*; import net.xevianlight.aphelion.util.FloodFill3D; import org.jetbrains.annotations.Nullable; import java.util.*; -// TODO: Rearrange this WHOOLE fucking thing into like, 10 different files for the actual pipes - public class PipeTestBlockEntity extends BlockEntity implements TickableBlockEntity { - public @Nullable PipeGraph graph = null; - public final Map attachments = new HashMap<>(); - public final Map outputs = new HashMap<>(); + public @Nullable ConveyorNetwork graph = null; + public final Map attachments = new HashMap<>(); + public final Map outputs = new HashMap<>(); public PipeTestBlockEntity(BlockPos pos, BlockState blockState) { super(ModBlockEntities.PIPE_TEST_BLOCK_ENTITY.get(), pos, blockState); @@ -52,7 +47,7 @@ public class PipeTestBlockEntity extends BlockEntity implements TickableBlockEnt makeOutputs(level, state, pos); for (Direction dir : Direction.values()) { - PipeAttachment attachment = attachments.get(dir); + ConveyorAttachment attachment = attachments.get(dir); if (attachment != null) { attachment.tick(level, state, pos, dir, graph); } @@ -64,13 +59,13 @@ public class PipeTestBlockEntity extends BlockEntity implements TickableBlockEnt } - private void addOutput(Direction dir, PipeOutput output) { + private void addOutput(Direction dir, ConveyorOutput output) { outputs.put(dir, output); if (graph != null) graph.outputs.add(output); } private void removeOutput(Direction dir) { - PipeOutput old = outputs.get(dir); + ConveyorOutput old = outputs.get(dir); if (graph != null) graph.outputs.remove(old); outputs.remove(dir); } @@ -94,59 +89,6 @@ public class PipeTestBlockEntity extends BlockEntity implements TickableBlockEnt } } - //TODO: move all these classes somewhere else - public interface PipeInput { - void tick(ServerLevel level, BlockState state, BlockPos pos, Direction facingDirection, PipeGraph graph); - } - - public interface PipeOutput { - /// @return Rejected items - ItemStack insertItem(ItemStack stack, boolean simulate); - } - - public static class PipeGraph { - boolean isInvalid = false; - public List pipes = new ArrayList<>(); - public Set outputs = new HashSet<>(); - - public ItemStack insertItem(ItemStack stack, boolean simulate) { - if (isInvalid) return stack; - for (PipeOutput output : outputs) { - stack = output.insertItem(stack, simulate); - if (stack.isEmpty()) break; - } - return stack; - } - - public void addPipe(PipeTestBlockEntity pipe) { - pipes.add(pipe); - pipe.graph = this; - for (PipeOutput output : pipe.outputs.values()) { - if (output != null) this.outputs.add(output); - } - } - - /// Called whenever a pipe is removed from a graph, or when a new graph comes across an old one. - public void invalidate() { - for (PipeTestBlockEntity pipe : pipes) { - pipe.graph = null; - for (PipeOutput output : pipe.outputs.values()) { - if (output != null) this.outputs.remove(output); - } - } - this.isInvalid = true; - } - } - - public static abstract class PipeAttachment { - PipeAttachment(ServerLevel level, BlockPos pos, Direction facingDirection) {} - - //TODO: put in the right interface for a render function - void render() {}; - - public void tick(ServerLevel level, BlockState state, BlockPos pos, Direction facingDirection, PipeGraph graph) {} - } - public boolean hasAttachment(Direction direction) { return attachments.get(direction) != null; } @@ -161,7 +103,7 @@ public class PipeTestBlockEntity extends BlockEntity implements TickableBlockEnt false); Aphelion.LOGGER.info("Got {} pipes", pipes.size()); - PipeGraph graph = new PipeGraph(); + ConveyorNetwork graph = new ConveyorNetwork(); for (BlockPos pipePos : pipes) { BlockEntity BE = level.getBlockEntity(pipePos); if (BE instanceof PipeTestBlockEntity pipe) { @@ -175,11 +117,11 @@ public class PipeTestBlockEntity extends BlockEntity implements TickableBlockEnt } } - public void setAttachment(Direction side, PipeAttachment attachment) { + public void setAttachment(Direction side, ConveyorAttachment attachment) { attachments.put(side, attachment); } - public boolean trySetAttachment(Direction side, PipeAttachment attachment) { + public boolean trySetAttachment(Direction side, ConveyorAttachment attachment) { if (hasAttachment(side)) return false; setAttachment(side, attachment); return true; @@ -190,87 +132,8 @@ public class PipeTestBlockEntity extends BlockEntity implements TickableBlockEnt return stack.is(Item.byId(1)); } - public static class BasicItemExtractAttachment extends PipeAttachment implements PipeInput { - - BlockCapabilityCache capabilityCache; - - BasicItemExtractAttachment(ServerLevel level, BlockPos pos, Direction facingDirection) { - super(level, pos, facingDirection); - - capabilityCache = BlockCapabilityCache.create( - Capabilities.ItemHandler.BLOCK, - level, - pos.relative(facingDirection), - facingDirection.getOpposite() - ); - } - - @Override - public void render() { - - } - - @Override - public void tick(ServerLevel level, BlockState state, BlockPos pos, Direction facingDirection, PipeGraph graph) { - // do an extract and distribute - IItemHandler container = capabilityCache.getCapability(); - if (container == null) return; - - final int EXTRACT_PER_TICK = 4; - int to_extract = EXTRACT_PER_TICK; - - int extract_slot_id = container.getSlots() - 1; - while (extract_slot_id >= 0 && container.getStackInSlot(extract_slot_id).isEmpty()) extract_slot_id--; - if (extract_slot_id == -1) return; - - - // Do a simulated extract, then run through every output side on the graph and do real inserts. - // By the end, remove as many items as we successfully inserted with a real extract - ItemStack to_distribute = container.extractItem(extract_slot_id, to_extract, true); - int extracted_amount = to_distribute.getCount(); - - to_distribute = graph.insertItem(to_distribute, false); - - int distributed_amount = extracted_amount; - if (!to_distribute.isEmpty()) { - distributed_amount = extracted_amount - to_distribute.getCount(); - } - container.extractItem(extract_slot_id, distributed_amount, false); - } - } - - public static class BasicItemOutput implements PipeOutput { - - BlockCapabilityCache capabilityCache; - - BasicItemOutput(ServerLevel level, BlockPos pos, Direction facingDirection) { - capabilityCache = BlockCapabilityCache.create( - Capabilities.ItemHandler.BLOCK, - level, - pos.relative(facingDirection), - facingDirection.getOpposite() - ); - } - - @Override - public ItemStack insertItem(ItemStack stack, boolean simulate) { - ItemStack toInsert = stack.copy(); - - IItemHandler container = capabilityCache.getCapability(); - if (container == null) return toInsert; - - for (int insertIndex = 0; insertIndex < container.getSlots(); insertIndex++) { - if (toInsert.isEmpty()) break; - - toInsert = container.insertItem(insertIndex, toInsert, simulate); - } - - return toInsert; - } - } - // Server only - public PipeAttachment getAttachmentForItem(ItemStack stack, Direction side) { + public ConveyorAttachment getAttachmentForItem(ItemStack stack, Direction side) { if (level.isClientSide()) throw new RuntimeException("Cannot get attachment item on client side!"); return new BasicItemExtractAttachment((ServerLevel) level, getBlockPos(), side); } diff --git a/src/main/java/net/xevianlight/aphelion/systems/conveyor/BasicItemExtractAttachment.java b/src/main/java/net/xevianlight/aphelion/systems/conveyor/BasicItemExtractAttachment.java new file mode 100644 index 0000000..b1b6deb --- /dev/null +++ b/src/main/java/net/xevianlight/aphelion/systems/conveyor/BasicItemExtractAttachment.java @@ -0,0 +1,61 @@ +package net.xevianlight.aphelion.systems.conveyor; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.state.BlockState; +import net.neoforged.neoforge.capabilities.BlockCapabilityCache; +import net.neoforged.neoforge.capabilities.Capabilities; +import net.neoforged.neoforge.items.IItemHandler; +import net.xevianlight.aphelion.block.entity.custom.PipeTestBlockEntity; +import org.jetbrains.annotations.Nullable; + +public class BasicItemExtractAttachment extends ConveyorAttachment implements ConveyorInput { + + BlockCapabilityCache capabilityCache; + + public BasicItemExtractAttachment(ServerLevel level, BlockPos pos, Direction facingDirection) { + super(level, pos, facingDirection); + + capabilityCache = BlockCapabilityCache.create( + Capabilities.ItemHandler.BLOCK, + level, + pos.relative(facingDirection), + facingDirection.getOpposite() + ); + } + + @Override + public void render() { + + } + + @Override + public void tick(ServerLevel level, BlockState state, BlockPos pos, Direction facingDirection, ConveyorNetwork network) { + // do an extract and distribute + IItemHandler container = capabilityCache.getCapability(); + if (container == null) return; + + final int EXTRACT_PER_TICK = 4; + int to_extract = EXTRACT_PER_TICK; + + int extract_slot_id = container.getSlots() - 1; + while (extract_slot_id >= 0 && container.getStackInSlot(extract_slot_id).isEmpty()) extract_slot_id--; + if (extract_slot_id == -1) return; + + + // Do a simulated extract, then run through every output side on the graph and do real inserts. + // By the end, remove as many items as we successfully inserted with a real extract + ItemStack to_distribute = container.extractItem(extract_slot_id, to_extract, true); + int extracted_amount = to_distribute.getCount(); + + to_distribute = network.insertItem(to_distribute, false); + + int distributed_amount = extracted_amount; + if (!to_distribute.isEmpty()) { + distributed_amount = extracted_amount - to_distribute.getCount(); + } + container.extractItem(extract_slot_id, distributed_amount, false); + } +} \ No newline at end of file diff --git a/src/main/java/net/xevianlight/aphelion/systems/conveyor/BasicItemOutput.java b/src/main/java/net/xevianlight/aphelion/systems/conveyor/BasicItemOutput.java new file mode 100644 index 0000000..1406556 --- /dev/null +++ b/src/main/java/net/xevianlight/aphelion/systems/conveyor/BasicItemOutput.java @@ -0,0 +1,39 @@ +package net.xevianlight.aphelion.systems.conveyor; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.item.ItemStack; +import net.neoforged.neoforge.capabilities.BlockCapabilityCache; +import net.neoforged.neoforge.capabilities.Capabilities; +import net.neoforged.neoforge.items.IItemHandler; +import org.jetbrains.annotations.Nullable; + +public class BasicItemOutput implements ConveyorOutput { + BlockCapabilityCache capabilityCache; + + public BasicItemOutput(ServerLevel level, BlockPos pos, Direction facingDirection) { + capabilityCache = BlockCapabilityCache.create( + Capabilities.ItemHandler.BLOCK, + level, + pos.relative(facingDirection), + facingDirection.getOpposite() + ); + } + + @Override + public ItemStack insertItem(ItemStack stack, boolean simulate) { + ItemStack toInsert = stack.copy(); + + IItemHandler container = capabilityCache.getCapability(); + if (container == null) return toInsert; + + for (int insertIndex = 0; insertIndex < container.getSlots(); insertIndex++) { + if (toInsert.isEmpty()) break; + + toInsert = container.insertItem(insertIndex, toInsert, simulate); + } + + return toInsert; + } +} diff --git a/src/main/java/net/xevianlight/aphelion/systems/conveyor/ConveyorAttachment.java b/src/main/java/net/xevianlight/aphelion/systems/conveyor/ConveyorAttachment.java new file mode 100644 index 0000000..dced7d3 --- /dev/null +++ b/src/main/java/net/xevianlight/aphelion/systems/conveyor/ConveyorAttachment.java @@ -0,0 +1,16 @@ +package net.xevianlight.aphelion.systems.conveyor; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.block.state.BlockState; +import net.xevianlight.aphelion.block.entity.custom.PipeTestBlockEntity; + +public class ConveyorAttachment { + ConveyorAttachment(ServerLevel level, BlockPos pos, Direction facingDirection) {} + + //TODO: put in the right interface for a render function + void render() {}; + + public void tick(ServerLevel level, BlockState state, BlockPos pos, Direction facingDirection, ConveyorNetwork network) {} +} diff --git a/src/main/java/net/xevianlight/aphelion/systems/conveyor/ConveyorInput.java b/src/main/java/net/xevianlight/aphelion/systems/conveyor/ConveyorInput.java new file mode 100644 index 0000000..ec55aee --- /dev/null +++ b/src/main/java/net/xevianlight/aphelion/systems/conveyor/ConveyorInput.java @@ -0,0 +1,10 @@ +package net.xevianlight.aphelion.systems.conveyor; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.block.state.BlockState; + +public interface ConveyorInput { + void tick(ServerLevel level, BlockState state, BlockPos pos, Direction facingDirection, ConveyorNetwork graph); +} diff --git a/src/main/java/net/xevianlight/aphelion/systems/conveyor/ConveyorNetwork.java b/src/main/java/net/xevianlight/aphelion/systems/conveyor/ConveyorNetwork.java new file mode 100644 index 0000000..fcb6955 --- /dev/null +++ b/src/main/java/net/xevianlight/aphelion/systems/conveyor/ConveyorNetwork.java @@ -0,0 +1,46 @@ +package net.xevianlight.aphelion.systems.conveyor; + +import net.minecraft.world.item.ItemStack; +import net.xevianlight.aphelion.block.entity.custom.PipeTestBlockEntity; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +// I'm naming and structuring the conveyor stuff like this bc i kinda wanna try making a space-engineers +// style request system later... though it might not be necessary, given that the reason it needs to be like that +// in space engineers is mostly space constraints if i had to guess +public class ConveyorNetwork { + boolean isInvalid = false; + public List pipes = new ArrayList<>(); + public Set outputs = new HashSet<>(); + + public ItemStack insertItem(ItemStack stack, boolean simulate) { + if (isInvalid) return stack; + for (ConveyorOutput output : outputs) { + stack = output.insertItem(stack, simulate); + if (stack.isEmpty()) break; + } + return stack; + } + + public void addPipe(PipeTestBlockEntity pipe) { + pipes.add(pipe); + pipe.graph = this; + for (ConveyorOutput output : pipe.outputs.values()) { + if (output != null) this.outputs.add(output); + } + } + + /// Called whenever a pipe is removed from a graph, or when a new graph comes across an old one. + public void invalidate() { + for (PipeTestBlockEntity pipe : pipes) { + pipe.graph = null; + for (ConveyorOutput output : pipe.outputs.values()) { + if (output != null) this.outputs.remove(output); + } + } + this.isInvalid = true; + } +} diff --git a/src/main/java/net/xevianlight/aphelion/systems/conveyor/ConveyorOutput.java b/src/main/java/net/xevianlight/aphelion/systems/conveyor/ConveyorOutput.java new file mode 100644 index 0000000..62889dd --- /dev/null +++ b/src/main/java/net/xevianlight/aphelion/systems/conveyor/ConveyorOutput.java @@ -0,0 +1,8 @@ +package net.xevianlight.aphelion.systems.conveyor; + +import net.minecraft.world.item.ItemStack; + +public interface ConveyorOutput { + /// @return Rejected items + ItemStack insertItem(ItemStack stack, boolean simulate); +}