From 8634d6362564f3903b54a8a01a9cb832c685cfb8 Mon Sep 17 00:00:00 2001 From: George Paton Date: Sun, 26 Jan 2025 12:31:35 +1100 Subject: [PATCH] Prevent contiguous foundry channels from accepting different materials until fully emptied, preventing clogs --- .../machine/TileEntityFoundryChannel.java | 98 ++++++++++++++++++- 1 file changed, 97 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/hbm/tileentity/machine/TileEntityFoundryChannel.java b/src/main/java/com/hbm/tileentity/machine/TileEntityFoundryChannel.java index 3156aada3..a3d50cc76 100644 --- a/src/main/java/com/hbm/tileentity/machine/TileEntityFoundryChannel.java +++ b/src/main/java/com/hbm/tileentity/machine/TileEntityFoundryChannel.java @@ -6,23 +6,38 @@ import java.util.List; import com.hbm.blocks.ModBlocks; import com.hbm.inventory.material.MaterialShapes; +import com.hbm.inventory.material.Mats; import com.hbm.inventory.material.Mats.MaterialStack; +import com.hbm.inventory.material.NTMMaterial; import api.hbm.block.ICrucibleAcceptor; import net.minecraft.block.Block; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; import net.minecraftforge.common.util.ForgeDirection; public class TileEntityFoundryChannel extends TileEntityFoundryBase { public int nextUpdate; public int lastFlow = 0; + + protected NTMMaterial neighborType; + protected boolean hasCheckedNeighbors; @Override public void updateEntity() { if(!worldObj.isRemote) { + + // Initialise before allowing pours, so newly added channels will avoid causing clog feeds + if(!hasCheckedNeighbors) { + List visited = new ArrayList(); + visited.add(this); + + neighborType = checkNeighbors(visited); + hasCheckedNeighbors = true; + } if(this.type == null && this.amount != 0) { this.amount = 0; @@ -35,7 +50,7 @@ public class TileEntityFoundryChannel extends TileEntityFoundryBase { boolean hasOp = false; nextUpdate = 5; - List ints = new ArrayList() {{ add(2); add(3); add(4); add(5); }}; + List ints = new ArrayList() {{ add(2); add(3); add(4); add(5); }}; Collections.shuffle(ints); if(lastFlow > 0) { ints.remove((Integer) this.lastFlow); @@ -54,6 +69,8 @@ public class TileEntityFoundryChannel extends TileEntityFoundryBase { if(left == null) { this.type = null; this.amount = 0; + + propagateMaterial(null); } else { this.amount = left.amount; } @@ -117,11 +134,90 @@ public class TileEntityFoundryChannel extends TileEntityFoundryBase { public void readFromNBT(NBTTagCompound nbt) { super.readFromNBT(nbt); this.lastFlow = nbt.getByte("flow"); + this.neighborType = Mats.matById.get(nbt.getInteger("nType")); + this.hasCheckedNeighbors = nbt.getBoolean("init"); } @Override public void writeToNBT(NBTTagCompound nbt) { super.writeToNBT(nbt); nbt.setByte("flow", (byte) this.lastFlow); + nbt.setInteger("nType", this.neighborType != null ? this.neighborType.id : -1); + nbt.setBoolean("init", hasCheckedNeighbors); } + + /** + * Channels accept pouring as normal, except when neighbor channels already have material. + * This prevents a contiguous channel from having multiple different types of material in it, causing clogs. + * If you connect two channels that have different materials already in them, god help you (nah jokes it'll just be clogged until you fix manually) + */ + @Override + public boolean canAcceptPartialPour(World world, int x, int y, int z, double dX, double dY, double dZ, ForgeDirection side, MaterialStack stack) { + if(!hasCheckedNeighbors || (neighborType != null && neighborType != stack.material)) return false; + return super.canAcceptPartialPour(world, x, y, z, dX, dY, dZ, side, stack); + } + + /** Upon pouring, propagate the current material type along contiguous channels */ + @Override + public MaterialStack pour(World world, int x, int y, int z, double dX, double dY, double dZ, ForgeDirection side, MaterialStack stack) { + propagateMaterial(stack.material); + return super.pour(world, x, y, z, dX, dY, dZ, side, stack); + } + + protected void propagateMaterial(NTMMaterial propType) { + if(propType != null && neighborType != null) return; // optimise away any pours that change nothing + + List visited = new ArrayList(); + visited.add(this); + + boolean hasMaterial = propagateMaterial(propType, visited, false); + + // since we are now fully clear, it's safe to unassign the contiguous channel type + if(propType == null && !hasMaterial) { + for(TileEntityFoundryChannel acc : visited) { + acc.neighborType = null; + } + } + } + + protected boolean propagateMaterial(NTMMaterial propType, List visited, boolean hasMaterial) { + // if emptying, don't allow the channel to be marked as ready for a new material until it is entirely clear + if(propType != null) neighborType = propType; + + for(ForgeDirection dir : new ForgeDirection[] { ForgeDirection.NORTH, ForgeDirection.SOUTH, ForgeDirection.WEST, ForgeDirection.EAST }) { + TileEntity b = worldObj.getTileEntity(xCoord + dir.offsetX, yCoord, zCoord + dir.offsetZ); + + if(b instanceof TileEntityFoundryChannel && !visited.contains(b)) { + TileEntityFoundryChannel acc = (TileEntityFoundryChannel) b; + visited.add(acc); + + if(acc.amount > 0) hasMaterial = true; + + hasMaterial = acc.propagateMaterial(propType, visited, hasMaterial); + } + } + + return hasMaterial; + } + + protected NTMMaterial checkNeighbors(List visited) { + if(neighborType != null) return neighborType; + + for(ForgeDirection dir : new ForgeDirection[] { ForgeDirection.NORTH, ForgeDirection.SOUTH, ForgeDirection.WEST, ForgeDirection.EAST }) { + TileEntity b = worldObj.getTileEntity(xCoord + dir.offsetX, yCoord, zCoord + dir.offsetZ); + + if(b instanceof TileEntityFoundryChannel && !visited.contains(b)) { + TileEntityFoundryChannel acc = (TileEntityFoundryChannel) b; + visited.add(acc); + + NTMMaterial neighborMaterial = acc.checkNeighbors(visited); + + // immediately propagate backwards if a material is found + if(neighborMaterial != null) return neighborMaterial; + } + } + + return null; + } + }