reorganized and renamed classes

This commit is contained in:
TechnoDraconic
2026-03-10 16:05:52 -07:00
parent ab78582cce
commit f44670d44e
7 changed files with 191 additions and 148 deletions

View File

@@ -10,31 +10,26 @@ import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item; import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level; 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.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3; 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.capabilities.Capabilities;
import net.neoforged.neoforge.items.IItemHandler;
import net.xevianlight.aphelion.Aphelion; import net.xevianlight.aphelion.Aphelion;
import net.xevianlight.aphelion.block.custom.PipeTestBlock; import net.xevianlight.aphelion.block.custom.PipeTestBlock;
import net.xevianlight.aphelion.block.custom.base.TickableBlockEntity; import net.xevianlight.aphelion.block.custom.base.TickableBlockEntity;
import net.xevianlight.aphelion.core.init.ModBlockEntities; import net.xevianlight.aphelion.core.init.ModBlockEntities;
import net.xevianlight.aphelion.core.init.ModBlocks; import net.xevianlight.aphelion.core.init.ModBlocks;
import net.xevianlight.aphelion.systems.conveyor.*;
import net.xevianlight.aphelion.util.FloodFill3D; import net.xevianlight.aphelion.util.FloodFill3D;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.*; 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 class PipeTestBlockEntity extends BlockEntity implements TickableBlockEntity {
public @Nullable PipeGraph graph = null; public @Nullable ConveyorNetwork graph = null;
public final Map<Direction, @Nullable PipeAttachment> attachments = new HashMap<>(); public final Map<Direction, @Nullable ConveyorAttachment> attachments = new HashMap<>();
public final Map<Direction, @Nullable PipeOutput> outputs = new HashMap<>(); public final Map<Direction, @Nullable ConveyorOutput> outputs = new HashMap<>();
public PipeTestBlockEntity(BlockPos pos, BlockState blockState) { public PipeTestBlockEntity(BlockPos pos, BlockState blockState) {
super(ModBlockEntities.PIPE_TEST_BLOCK_ENTITY.get(), pos, 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); makeOutputs(level, state, pos);
for (Direction dir : Direction.values()) { for (Direction dir : Direction.values()) {
PipeAttachment attachment = attachments.get(dir); ConveyorAttachment attachment = attachments.get(dir);
if (attachment != null) { if (attachment != null) {
attachment.tick(level, state, pos, dir, graph); 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); outputs.put(dir, output);
if (graph != null) graph.outputs.add(output); if (graph != null) graph.outputs.add(output);
} }
private void removeOutput(Direction dir) { private void removeOutput(Direction dir) {
PipeOutput old = outputs.get(dir); ConveyorOutput old = outputs.get(dir);
if (graph != null) graph.outputs.remove(old); if (graph != null) graph.outputs.remove(old);
outputs.remove(dir); 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<PipeTestBlockEntity> pipes = new ArrayList<>();
public Set<PipeOutput> 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) { public boolean hasAttachment(Direction direction) {
return attachments.get(direction) != null; return attachments.get(direction) != null;
} }
@@ -161,7 +103,7 @@ public class PipeTestBlockEntity extends BlockEntity implements TickableBlockEnt
false); false);
Aphelion.LOGGER.info("Got {} pipes", pipes.size()); Aphelion.LOGGER.info("Got {} pipes", pipes.size());
PipeGraph graph = new PipeGraph(); ConveyorNetwork graph = new ConveyorNetwork();
for (BlockPos pipePos : pipes) { for (BlockPos pipePos : pipes) {
BlockEntity BE = level.getBlockEntity(pipePos); BlockEntity BE = level.getBlockEntity(pipePos);
if (BE instanceof PipeTestBlockEntity pipe) { 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); attachments.put(side, attachment);
} }
public boolean trySetAttachment(Direction side, PipeAttachment attachment) { public boolean trySetAttachment(Direction side, ConveyorAttachment attachment) {
if (hasAttachment(side)) return false; if (hasAttachment(side)) return false;
setAttachment(side, attachment); setAttachment(side, attachment);
return true; return true;
@@ -190,87 +132,8 @@ public class PipeTestBlockEntity extends BlockEntity implements TickableBlockEnt
return stack.is(Item.byId(1)); return stack.is(Item.byId(1));
} }
public static class BasicItemExtractAttachment extends PipeAttachment implements PipeInput {
BlockCapabilityCache<IItemHandler, @Nullable Direction> 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<IItemHandler, @Nullable Direction> 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 // 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!"); if (level.isClientSide()) throw new RuntimeException("Cannot get attachment item on client side!");
return new BasicItemExtractAttachment((ServerLevel) level, getBlockPos(), side); return new BasicItemExtractAttachment((ServerLevel) level, getBlockPos(), side);
} }

View File

@@ -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<IItemHandler, @Nullable Direction> 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);
}
}

View File

@@ -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<IItemHandler, @Nullable Direction> 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;
}
}

View File

@@ -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) {}
}

View File

@@ -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);
}

View File

@@ -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<PipeTestBlockEntity> pipes = new ArrayList<>();
public Set<ConveyorOutput> 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;
}
}

View File

@@ -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);
}