diff --git a/src/main/java/com/hbm/blocks/machine/FoundryChannel.java b/src/main/java/com/hbm/blocks/machine/FoundryChannel.java index 8866bfd0f..84faf6dee 100644 --- a/src/main/java/com/hbm/blocks/machine/FoundryChannel.java +++ b/src/main/java/com/hbm/blocks/machine/FoundryChannel.java @@ -176,6 +176,7 @@ public class FoundryChannel extends BlockContainer implements ICrucibleAcceptor } cast.amount = 0; cast.type = null; + cast.propagateMaterial(null); cast.markDirty(); world.markBlockForUpdate(x, y, z); } diff --git a/src/main/java/com/hbm/tileentity/machine/TileEntityFoundryChannel.java b/src/main/java/com/hbm/tileentity/machine/TileEntityFoundryChannel.java index 3156aada3..d20e8acb0 100644 --- a/src/main/java/com/hbm/tileentity/machine/TileEntityFoundryChannel.java +++ b/src/main/java/com/hbm/tileentity/machine/TileEntityFoundryChannel.java @@ -6,23 +6,39 @@ 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; + protected int unpropagateTime; @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 +51,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 +70,8 @@ public class TileEntityFoundryChannel extends TileEntityFoundryBase { if(left == null) { this.type = null; this.amount = 0; + + propagateMaterial(null); } else { this.amount = left.amount; } @@ -98,10 +116,19 @@ public class TileEntityFoundryChannel extends TileEntityFoundryBase { } } } + + if(neighborType != null && amount == 0) unpropagateTime++; + + // every 5 seconds do a unprop test, will only occur once per contiguous channel per 5 seconds due to the timer getting updated in all channels from the prop + if(unpropagateTime > 100) { + propagateMaterial(null); + } if(this.amount == 0) { this.lastFlow = 0; this.nextUpdate = 5; + } else { + unpropagateTime = 0; } } @@ -117,11 +144,95 @@ 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); + } + + public 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 mark the channel as ready for a new material until it is entirely clear + if(propType != null) { + neighborType = propType; + } else { + // and when empty testing, update the last unpropagate time + unpropagateTime = 0; + } + + 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; + } + }