From abe642c778be5d7516b9b3bdfa1a8cfae633ddca Mon Sep 17 00:00:00 2001 From: Xhamolk Date: Sat, 22 Sep 2012 11:54:42 -0600 Subject: [PATCH] Revert "Fixes pipes connecting improperly to IPipeConnection" This reverts commit 725d96e692159884c873a27efe2cd24e19ffc8c1. --- common/buildcraft/transport/Pipe.java | 1315 ++++++++--------- .../transport/PipeTransportItems.java | 1011 +++++++------ 2 files changed, 1157 insertions(+), 1169 deletions(-) diff --git a/common/buildcraft/transport/Pipe.java b/common/buildcraft/transport/Pipe.java index 58ba6099..8de03432 100644 --- a/common/buildcraft/transport/Pipe.java +++ b/common/buildcraft/transport/Pipe.java @@ -1,661 +1,654 @@ -/** - * Copyright (c) SpaceToad, 2011 - * http://www.mod-buildcraft.com - * - * BuildCraft is distributed under the terms of the Minecraft Mod Public - * License 1.0, or MMPL. Please check the contents of the license located in - * http://www.mod-buildcraft.com/MMPL-1.0.txt - */ - -package buildcraft.transport; - -import java.util.HashMap; -import java.util.LinkedList; -import java.util.Map; -import java.util.Random; - -import buildcraft.BuildCraftTransport; -import buildcraft.api.core.Orientations; -import buildcraft.api.core.Position; -import buildcraft.api.core.SafeTimeTracker; -import buildcraft.api.gates.Action; -import buildcraft.api.gates.ActionManager; -import buildcraft.api.gates.IAction; -import buildcraft.api.gates.IActionReceptor; -import buildcraft.api.gates.ITrigger; -import buildcraft.api.gates.ITriggerParameter; -import buildcraft.api.gates.Trigger; -import buildcraft.api.gates.TriggerParameter; -import buildcraft.api.transport.IPipe; -import buildcraft.api.transport.IPipeConnection; -import buildcraft.core.IDropControlInventory; -import buildcraft.core.network.TilePacketWrapper; -import buildcraft.core.triggers.ActionRedstoneOutput; -import buildcraft.core.utils.Utils; -import buildcraft.transport.Gate.GateConditional; -import buildcraft.transport.pipes.PipeLogic; -import buildcraft.transport.triggers.ActionSignalOutput; - -import net.minecraft.src.Entity; -import net.minecraft.src.EntityItem; -import net.minecraft.src.EntityPlayer; -import net.minecraft.src.ItemStack; -import net.minecraft.src.NBTTagCompound; -import net.minecraft.src.TileEntity; -import net.minecraft.src.World; - -public abstract class Pipe implements IPipe, IDropControlInventory { - - public int[] signalStrength = new int[] { 0, 0, 0, 0 }; - - public int xCoord; - public int yCoord; - public int zCoord; - public World worldObj; - public TileGenericPipe container; - - public final PipeTransport transport; - public final PipeLogic logic; - public final int itemID; - - private boolean internalUpdateScheduled = false; - - public boolean[] wireSet = new boolean[] { false, false, false, false }; - - public Gate gate; - - @SuppressWarnings("rawtypes") - private static Map networkWrappers = new HashMap(); - - public ITrigger[] activatedTriggers = new Trigger[8]; - public ITriggerParameter[] triggerParameters = new ITriggerParameter[8]; - public IAction[] activatedActions = new Action[8]; - - public boolean broadcastSignal[] = new boolean[] { false, false, false, false }; - public boolean broadcastRedstone = false; - - public SafeTimeTracker actionTracker = new SafeTimeTracker(); - - public Pipe(PipeTransport transport, PipeLogic logic, int itemID) { - this.transport = transport; - this.logic = logic; - this.itemID = itemID; - - if (!networkWrappers.containsKey(this.getClass())) - networkWrappers - .put(this.getClass(), new TilePacketWrapper(new Class[] { TileGenericPipe.class, this.transport.getClass(), - this.logic.getClass() })); - - } - - private void setPosition(int xCoord, int yCoord, int zCoord) { - this.xCoord = xCoord; - this.yCoord = yCoord; - this.zCoord = zCoord; - - transport.setPosition(xCoord, yCoord, zCoord); - logic.setPosition(xCoord, yCoord, zCoord); - } - - private void setWorld(World worldObj) { - if (worldObj != null && this.worldObj == null) { - this.worldObj = worldObj; - transport.setWorld(worldObj); - logic.setWorld(worldObj); - } - } - - public void setTile(TileEntity tile) { - - this.container = (TileGenericPipe) tile; - - transport.setTile((TileGenericPipe) tile); - logic.setTile((TileGenericPipe) tile); - - setPosition(tile.xCoord, tile.yCoord, tile.zCoord); - setWorld(tile.worldObj); - } - - public boolean blockActivated(World world, int i, int j, int k, EntityPlayer entityplayer) { - return logic.blockActivated(entityplayer); - } - - public void onBlockPlaced() { - logic.onBlockPlaced(); - transport.onBlockPlaced(); - } - - public void onNeighborBlockChange(int blockId) { - logic.onNeighborBlockChange(blockId); - transport.onNeighborBlockChange(blockId); - - updateSignalState(); - } - - public boolean isPipeConnected(TileEntity tile) { - if( tile instanceof IPipeConnection ){ - Orientations or = Utils.get3dOrientation(new Position(this.container), new Position(tile)); - if( !((IPipeConnection) tile).isPipeConnected(or) ) - return false; - } - return logic.isPipeConnected(tile) && transport.isPipeConnected(tile); - } - - /** - * Should return the texture file that is used to render this pipe - */ - public abstract String getTextureFile(); - - /** - * Should return the textureindex in the file specified by getTextureFile() - * @param direction The orientation for the texture that is requested. Unknown for the center pipe center - * @return the index in the texture sheet - */ - public abstract int getTextureIndex(Orientations direction); - - - /** - * Should return the textureindex used by the Pipe Item Renderer, as this is done client-side the default implementation might - * not work if your getTextureIndex(Orienations.Unknown) has logic - * @return - */ - public int getTextureIndexForItem(){ - return getTextureIndex(Orientations.Unknown); - } - - public void updateEntity() { - - transport.updateEntity(); - logic.updateEntity(); - - if (internalUpdateScheduled) { - internalUpdate(); - internalUpdateScheduled = false; - } - - // Do not try to update gates client side. - if (worldObj.isRemote) return; - - if (actionTracker.markTimeIfDelay(worldObj, 10)) - resolveActions(); - - // Update the gate if we have any - if (gate != null) - gate.update(); - - } - - private void internalUpdate() { - updateSignalState(); - } - - public void writeToNBT(NBTTagCompound nbttagcompound) { - transport.writeToNBT(nbttagcompound); - logic.writeToNBT(nbttagcompound); - - // Save pulser if any - if (gate != null) { - NBTTagCompound nbttagcompoundC = new NBTTagCompound(); - gate.writeToNBT(nbttagcompoundC); - nbttagcompound.setTag("Gate", nbttagcompoundC); - } - - for (int i = 0; i < 4; ++i) - nbttagcompound.setBoolean("wireSet[" + i + "]", wireSet[i]); - - for (int i = 0; i < 8; ++i) { - nbttagcompound.setInteger("action[" + i + "]", activatedActions[i] != null ? activatedActions[i].getId() : 0); - nbttagcompound.setInteger("trigger[" + i + "]", activatedTriggers[i] != null ? activatedTriggers[i].getId() : 0); - } - - for (int i = 0; i < 8; ++i) - if (triggerParameters[i] != null) { - NBTTagCompound cpt = new NBTTagCompound(); - triggerParameters[i].writeToNBT(cpt); - nbttagcompound.setTag("triggerParameters[" + i + "]", cpt); - } - } - - public void readFromNBT(NBTTagCompound nbttagcompound) { - transport.readFromNBT(nbttagcompound); - logic.readFromNBT(nbttagcompound); - - // Load pulser if any - if (nbttagcompound.hasKey("Gate")) { - NBTTagCompound nbttagcompoundP = nbttagcompound.getCompoundTag("Gate"); - gate = new GateVanilla(this); - gate.readFromNBT(nbttagcompoundP); - } else if (nbttagcompound.hasKey("gateKind")) { - // Legacy implementation - Gate.GateKind kind = Gate.GateKind.values()[nbttagcompound.getInteger("gateKind")]; - if (kind != Gate.GateKind.None) { - gate = new GateVanilla(this); - gate.kind = kind; - } - } - - for (int i = 0; i < 4; ++i) - wireSet[i] = nbttagcompound.getBoolean("wireSet[" + i + "]"); - - for (int i = 0; i < 8; ++i) { - activatedActions[i] = ActionManager.actions[nbttagcompound.getInteger("action[" + i + "]")]; - activatedTriggers[i] = ActionManager.triggers[nbttagcompound.getInteger("trigger[" + i + "]")]; - } - - for (int i = 0; i < 8; ++i) - if (nbttagcompound.hasKey("triggerParameters[" + i + "]")) { - triggerParameters[i] = new TriggerParameter(); - triggerParameters[i].readFromNBT(nbttagcompound.getCompoundTag("triggerParameters[" + i + "]")); - } - } - - private boolean initialized = false; - - public void initialize() { - if (!initialized) { - transport.initialize(); - logic.initialize(); - initialized = true; - updateSignalState(); - } - } - - private void readNearbyPipesSignal(WireColor color) { - boolean foundBiggerSignal = false; - - for (Orientations o : Orientations.dirs()) { - TileEntity tile = container.getTile(o); - - if (tile instanceof TileGenericPipe) { - TileGenericPipe tilePipe = (TileGenericPipe) tile; - - if (BlockGenericPipe.isFullyDefined(tilePipe.pipe)) - if (isWireConnectedTo(tile, color)) - foundBiggerSignal |= receiveSignal(tilePipe.pipe.signalStrength[color.ordinal()] - 1, color); - } - } - - if (!foundBiggerSignal && signalStrength[color.ordinal()] != 0) { - signalStrength[color.ordinal()] = 0; - //worldObj.markBlockNeedsUpdate(xCoord, yCoord, zCoord); - container.scheduleRenderUpdate(); - - - for (Orientations o : Orientations.dirs()) { - TileEntity tile = container.getTile(o); - - if (tile instanceof TileGenericPipe) { - TileGenericPipe tilePipe = (TileGenericPipe) tile; - - if (BlockGenericPipe.isFullyDefined(tilePipe.pipe)) - tilePipe.pipe.internalUpdateScheduled = true; - } - } - } - } - - private void updateSignalState() { - for (IPipe.WireColor c : IPipe.WireColor.values()) - updateSignalStateForColor(c); - } - - private void updateSignalStateForColor(IPipe.WireColor color) { - if (!wireSet[color.ordinal()]) - return; - - // STEP 1: compute internal signal strength - - if (broadcastSignal[color.ordinal()]) - receiveSignal(255, color); - else - readNearbyPipesSignal(color); - - // STEP 2: transmit signal in nearby blocks - - if (signalStrength[color.ordinal()] > 1) - for (Orientations o : Orientations.dirs()) { - TileEntity tile = container.getTile(o); - - if (tile instanceof TileGenericPipe) { - TileGenericPipe tilePipe = (TileGenericPipe) tile; - - if (BlockGenericPipe.isFullyDefined(tilePipe.pipe) && tilePipe.pipe.wireSet[color.ordinal()]) - if (isWireConnectedTo(tile, color)) - tilePipe.pipe.receiveSignal(signalStrength[color.ordinal()] - 1, color); - } - } - } - - private boolean receiveSignal(int signal, IPipe.WireColor color) { - if (worldObj == null) - return false; - - int oldSignal = signalStrength[color.ordinal()]; - - if (signal >= signalStrength[color.ordinal()] && signal != 0) { - signalStrength[color.ordinal()] = signal; - internalUpdateScheduled = true; - - if (oldSignal == 0) { - //worldObj.markBlockNeedsUpdate(xCoord, yCoord, zCoord); - container.scheduleRenderUpdate(); - - } - - return true; - } else - return false; - } - - public boolean inputOpen(Orientations from) { - return transport.inputOpen(from) && logic.inputOpen(from); - } - - public boolean outputOpen(Orientations to) { - return transport.outputOpen(to) && logic.outputOpen(to); - } - - public void onEntityCollidedWithBlock(Entity entity) { - - } - - public boolean isPoweringTo(int l) { - if (!broadcastRedstone) - return false; - - Orientations o = Orientations.values()[l].reverse(); - TileEntity tile = container.getTile(o); - - if (tile instanceof TileGenericPipe && Utils.checkPipesConnections(this.container, tile)) - return false; - - return true; - } - - public boolean isIndirectlyPoweringTo(int l) { - return isPoweringTo(l); - } - - public void randomDisplayTick(Random random) {} - - // / @Override TODO: should be in IPipe - public boolean isWired() { - for (WireColor color : WireColor.values()) - if (isWired(color)) - return true; - - return false; - } - - @Override - public boolean isWired(WireColor color) { - return wireSet[color.ordinal()]; - } - - @Override - public boolean hasInterface() { - return hasGate(); - } - - public boolean hasGate() { - return gate != null; - } - - protected void updateNeighbors(boolean needSelf) { - if (needSelf) { - worldObj.notifyBlocksOfNeighborChange(xCoord, yCoord, zCoord, BuildCraftTransport.genericPipeBlock.blockID); - } - worldObj.notifyBlocksOfNeighborChange(xCoord, yCoord - 1, zCoord, BuildCraftTransport.genericPipeBlock.blockID); - worldObj.notifyBlocksOfNeighborChange(xCoord, yCoord + 1, zCoord, BuildCraftTransport.genericPipeBlock.blockID); - worldObj.notifyBlocksOfNeighborChange(xCoord - 1, yCoord, zCoord, BuildCraftTransport.genericPipeBlock.blockID); - worldObj.notifyBlocksOfNeighborChange(xCoord + 1, yCoord, zCoord, BuildCraftTransport.genericPipeBlock.blockID); - worldObj.notifyBlocksOfNeighborChange(xCoord, yCoord, zCoord - 1, BuildCraftTransport.genericPipeBlock.blockID); - worldObj.notifyBlocksOfNeighborChange(xCoord, yCoord, zCoord + 1, BuildCraftTransport.genericPipeBlock.blockID); - } - - public void onBlockRemoval() { - if (wireSet[IPipe.WireColor.Red.ordinal()]) - Utils.dropItems(worldObj, new ItemStack(BuildCraftTransport.redPipeWire), xCoord, yCoord, zCoord); - - if (wireSet[IPipe.WireColor.Blue.ordinal()]) - Utils.dropItems(worldObj, new ItemStack(BuildCraftTransport.bluePipeWire), xCoord, yCoord, zCoord); - - if (wireSet[IPipe.WireColor.Green.ordinal()]) - Utils.dropItems(worldObj, new ItemStack(BuildCraftTransport.greenPipeWire), xCoord, yCoord, zCoord); - - if (wireSet[IPipe.WireColor.Yellow.ordinal()]) - Utils.dropItems(worldObj, new ItemStack(BuildCraftTransport.yellowPipeWire), xCoord, yCoord, zCoord); - - if (hasGate()) - gate.dropGate(worldObj, xCoord, yCoord, zCoord); - - for (Orientations direction : Orientations.dirs()){ - if (container.hasFacade(direction)){ - container.dropFacade(direction); - } - } - - if (broadcastRedstone) { - updateNeighbors(false); // self will update due to block id changing - } - } - - public void setTrigger(int position, ITrigger trigger) { - activatedTriggers[position] = trigger; - } - - public ITrigger getTrigger(int position) { - return activatedTriggers[position]; - } - - public void setTriggerParameter(int position, ITriggerParameter p) { - triggerParameters[position] = p; - } - - public ITriggerParameter getTriggerParameter(int position) { - return triggerParameters[position]; - } - - public boolean isNearbyTriggerActive(ITrigger trigger, ITriggerParameter parameter) { - if (trigger instanceof ITriggerPipe) - return ((ITriggerPipe) trigger).isTriggerActive(this, parameter); - else if (trigger != null) - for (Orientations o : Orientations.dirs()) { - TileEntity tile = container.getTile(o); - - if (tile != null && !(tile instanceof TileGenericPipe) && trigger.isTriggerActive(tile, parameter)) - return true; - } - - return false; - } - - public boolean isTriggerActive(ITrigger trigger) { - return false; - } - - public LinkedList getActions() { - LinkedList result = new LinkedList(); - - if (hasGate()) - gate.addActions(result); - - return result; - } - - public IAction getAction(int position) { - return activatedActions[position]; - } - - public void setAction(int position, IAction action) { - activatedActions[position] = action; - } - - public void resetGate() { - gate = null; - activatedTriggers = new Trigger[activatedTriggers.length]; - triggerParameters = new ITriggerParameter[triggerParameters.length]; - activatedActions = new Action[activatedActions.length]; - broadcastSignal = new boolean[] { false, false, false, false }; - if (broadcastRedstone) { - updateNeighbors(true); - } - broadcastRedstone = false; - //worldObj.markBlockNeedsUpdate(xCoord, yCoord, zCoord); - container.scheduleRenderUpdate(); - } - - private void resolveActions() { - if (!hasGate()) - return; - - boolean oldBroadcastRedstone = broadcastRedstone; - boolean[] oldBroadcastSignal = broadcastSignal; - - broadcastRedstone = false; - broadcastSignal = new boolean[] { false, false, false, false }; - - // Tell the gate to prepare for resolving actions. (Disable pulser) - gate.startResolution(); - - HashMap actions = new HashMap(); - - // Computes the actions depending on the triggers - for (int it = 0; it < 8; ++it) { - ITrigger trigger = activatedTriggers[it]; - IAction action = activatedActions[it]; - ITriggerParameter parameter = triggerParameters[it]; - - if (trigger != null && action != null) - if (!actions.containsKey(action.getId())) - actions.put(action.getId(), isNearbyTriggerActive(trigger, parameter)); - else if (gate.getConditional() == GateConditional.AND) - actions.put(action.getId(), actions.get(action.getId()) && isNearbyTriggerActive(trigger, parameter)); - else - actions.put(action.getId(), actions.get(action.getId()) || isNearbyTriggerActive(trigger, parameter)); - } - - // Activate the actions - for (Integer i : actions.keySet()) - if (actions.get(i)) { - - // Custom gate actions take precedence over defaults. - if (gate.resolveAction(ActionManager.actions[i])) - continue; - - if (ActionManager.actions[i] instanceof ActionRedstoneOutput) - broadcastRedstone = true; - else if (ActionManager.actions[i] instanceof ActionSignalOutput) - broadcastSignal[((ActionSignalOutput) ActionManager.actions[i]).color.ordinal()] = true; - else - for (int a = 0; a < container.tileBuffer.length; ++a) - if (container.tileBuffer[a].getTile() instanceof IActionReceptor) { - IActionReceptor recept = (IActionReceptor) container.tileBuffer[a].getTile(); - recept.actionActivated(ActionManager.actions[i]); - } - } - - actionsActivated(actions); - - if (oldBroadcastRedstone != broadcastRedstone) { - container.scheduleRenderUpdate(); - updateNeighbors(true); - } - - for (int i = 0; i < oldBroadcastSignal.length; ++i) - if (oldBroadcastSignal[i] != broadcastSignal[i]) { - //worldObj.markBlockNeedsUpdate(xCoord, yCoord, zCoord); - container.scheduleRenderUpdate(); - updateSignalState(); - break; - } - } - - protected void actionsActivated(HashMap actions) { - - } - - @Override - public TileGenericPipe getContainer() { - return container; - } - - @Override - public boolean isWireConnectedTo(TileEntity tile, WireColor color) { - if (!(tile instanceof TileGenericPipe)) - return false; - - TileGenericPipe tilePipe = (TileGenericPipe) tile; - - if (!BlockGenericPipe.isFullyDefined(tilePipe.pipe)) - return false; - - if (!tilePipe.pipe.wireSet[color.ordinal()]) - return false; - - return (tilePipe.pipe.transport instanceof PipeTransportStructure || transport instanceof PipeTransportStructure || Utils - .checkPipesConnections(container, tile)); - } - - public void dropContents() { - transport.dropContents(); - } - - public void onDropped(EntityItem item) { - - } - - /** - * If this pipe is open on one side, return it. - */ - public Orientations getOpenOrientation() { - int Connections_num = 0; - - Orientations target_orientation = Orientations.Unknown; - - for (Orientations o : Orientations.dirs()) - if (Utils.checkPipesConnections(container.getTile(o), container)) { - - Connections_num++; - - if (Connections_num == 1) - target_orientation = o; - } - - if (Connections_num > 1 || Connections_num == 0) - return Orientations.Unknown; - - return target_orientation.reverse(); - } - - @Override - public boolean doDrop() { - return logic.doDrop(); - } - - public boolean isGateActive(){ - for (boolean b : broadcastSignal){ - if (b) return true; - } - return broadcastRedstone; - } - - - /** - * Called when TileGenericPipe.invalidate() is called - */ - public void invalidate() {} - - /** - * Called when TileGenericPipe.validate() is called - */ - public void validate() {} - - - /** - * Called when TileGenericPipe.onChunkUnload is called - */ - public void onChunkUnload() {} - -} - +/** + * Copyright (c) SpaceToad, 2011 + * http://www.mod-buildcraft.com + * + * BuildCraft is distributed under the terms of the Minecraft Mod Public + * License 1.0, or MMPL. Please check the contents of the license located in + * http://www.mod-buildcraft.com/MMPL-1.0.txt + */ + +package buildcraft.transport; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; +import java.util.Random; + +import buildcraft.BuildCraftTransport; +import buildcraft.api.core.Orientations; +import buildcraft.api.core.SafeTimeTracker; +import buildcraft.api.gates.Action; +import buildcraft.api.gates.ActionManager; +import buildcraft.api.gates.IAction; +import buildcraft.api.gates.IActionReceptor; +import buildcraft.api.gates.ITrigger; +import buildcraft.api.gates.ITriggerParameter; +import buildcraft.api.gates.Trigger; +import buildcraft.api.gates.TriggerParameter; +import buildcraft.api.transport.IPipe; +import buildcraft.core.IDropControlInventory; +import buildcraft.core.network.TilePacketWrapper; +import buildcraft.core.triggers.ActionRedstoneOutput; +import buildcraft.core.utils.Utils; +import buildcraft.transport.Gate.GateConditional; +import buildcraft.transport.pipes.PipeLogic; +import buildcraft.transport.triggers.ActionSignalOutput; + +import net.minecraft.src.Entity; +import net.minecraft.src.EntityItem; +import net.minecraft.src.EntityPlayer; +import net.minecraft.src.ItemStack; +import net.minecraft.src.NBTTagCompound; +import net.minecraft.src.TileEntity; +import net.minecraft.src.World; + +public abstract class Pipe implements IPipe, IDropControlInventory { + + public int[] signalStrength = new int[] { 0, 0, 0, 0 }; + + public int xCoord; + public int yCoord; + public int zCoord; + public World worldObj; + public TileGenericPipe container; + + public final PipeTransport transport; + public final PipeLogic logic; + public final int itemID; + + private boolean internalUpdateScheduled = false; + + public boolean[] wireSet = new boolean[] { false, false, false, false }; + + public Gate gate; + + @SuppressWarnings("rawtypes") + private static Map networkWrappers = new HashMap(); + + public ITrigger[] activatedTriggers = new Trigger[8]; + public ITriggerParameter[] triggerParameters = new ITriggerParameter[8]; + public IAction[] activatedActions = new Action[8]; + + public boolean broadcastSignal[] = new boolean[] { false, false, false, false }; + public boolean broadcastRedstone = false; + + public SafeTimeTracker actionTracker = new SafeTimeTracker(); + + public Pipe(PipeTransport transport, PipeLogic logic, int itemID) { + this.transport = transport; + this.logic = logic; + this.itemID = itemID; + + if (!networkWrappers.containsKey(this.getClass())) + networkWrappers + .put(this.getClass(), new TilePacketWrapper(new Class[] { TileGenericPipe.class, this.transport.getClass(), + this.logic.getClass() })); + + } + + private void setPosition(int xCoord, int yCoord, int zCoord) { + this.xCoord = xCoord; + this.yCoord = yCoord; + this.zCoord = zCoord; + + transport.setPosition(xCoord, yCoord, zCoord); + logic.setPosition(xCoord, yCoord, zCoord); + } + + private void setWorld(World worldObj) { + if (worldObj != null && this.worldObj == null) { + this.worldObj = worldObj; + transport.setWorld(worldObj); + logic.setWorld(worldObj); + } + } + + public void setTile(TileEntity tile) { + + this.container = (TileGenericPipe) tile; + + transport.setTile((TileGenericPipe) tile); + logic.setTile((TileGenericPipe) tile); + + setPosition(tile.xCoord, tile.yCoord, tile.zCoord); + setWorld(tile.worldObj); + } + + public boolean blockActivated(World world, int i, int j, int k, EntityPlayer entityplayer) { + return logic.blockActivated(entityplayer); + } + + public void onBlockPlaced() { + logic.onBlockPlaced(); + transport.onBlockPlaced(); + } + + public void onNeighborBlockChange(int blockId) { + logic.onNeighborBlockChange(blockId); + transport.onNeighborBlockChange(blockId); + + updateSignalState(); + } + + public boolean isPipeConnected(TileEntity tile) { + return logic.isPipeConnected(tile) && transport.isPipeConnected(tile); + } + + /** + * Should return the texture file that is used to render this pipe + */ + public abstract String getTextureFile(); + + /** + * Should return the textureindex in the file specified by getTextureFile() + * @param direction The orientation for the texture that is requested. Unknown for the center pipe center + * @return the index in the texture sheet + */ + public abstract int getTextureIndex(Orientations direction); + + + /** + * Should return the textureindex used by the Pipe Item Renderer, as this is done client-side the default implementation might + * not work if your getTextureIndex(Orienations.Unknown) has logic + * @return + */ + public int getTextureIndexForItem(){ + return getTextureIndex(Orientations.Unknown); + } + + public void updateEntity() { + + transport.updateEntity(); + logic.updateEntity(); + + if (internalUpdateScheduled) { + internalUpdate(); + internalUpdateScheduled = false; + } + + // Do not try to update gates client side. + if (worldObj.isRemote) return; + + if (actionTracker.markTimeIfDelay(worldObj, 10)) + resolveActions(); + + // Update the gate if we have any + if (gate != null) + gate.update(); + + } + + private void internalUpdate() { + updateSignalState(); + } + + public void writeToNBT(NBTTagCompound nbttagcompound) { + transport.writeToNBT(nbttagcompound); + logic.writeToNBT(nbttagcompound); + + // Save pulser if any + if (gate != null) { + NBTTagCompound nbttagcompoundC = new NBTTagCompound(); + gate.writeToNBT(nbttagcompoundC); + nbttagcompound.setTag("Gate", nbttagcompoundC); + } + + for (int i = 0; i < 4; ++i) + nbttagcompound.setBoolean("wireSet[" + i + "]", wireSet[i]); + + for (int i = 0; i < 8; ++i) { + nbttagcompound.setInteger("action[" + i + "]", activatedActions[i] != null ? activatedActions[i].getId() : 0); + nbttagcompound.setInteger("trigger[" + i + "]", activatedTriggers[i] != null ? activatedTriggers[i].getId() : 0); + } + + for (int i = 0; i < 8; ++i) + if (triggerParameters[i] != null) { + NBTTagCompound cpt = new NBTTagCompound(); + triggerParameters[i].writeToNBT(cpt); + nbttagcompound.setTag("triggerParameters[" + i + "]", cpt); + } + } + + public void readFromNBT(NBTTagCompound nbttagcompound) { + transport.readFromNBT(nbttagcompound); + logic.readFromNBT(nbttagcompound); + + // Load pulser if any + if (nbttagcompound.hasKey("Gate")) { + NBTTagCompound nbttagcompoundP = nbttagcompound.getCompoundTag("Gate"); + gate = new GateVanilla(this); + gate.readFromNBT(nbttagcompoundP); + } else if (nbttagcompound.hasKey("gateKind")) { + // Legacy implementation + Gate.GateKind kind = Gate.GateKind.values()[nbttagcompound.getInteger("gateKind")]; + if (kind != Gate.GateKind.None) { + gate = new GateVanilla(this); + gate.kind = kind; + } + } + + for (int i = 0; i < 4; ++i) + wireSet[i] = nbttagcompound.getBoolean("wireSet[" + i + "]"); + + for (int i = 0; i < 8; ++i) { + activatedActions[i] = ActionManager.actions[nbttagcompound.getInteger("action[" + i + "]")]; + activatedTriggers[i] = ActionManager.triggers[nbttagcompound.getInteger("trigger[" + i + "]")]; + } + + for (int i = 0; i < 8; ++i) + if (nbttagcompound.hasKey("triggerParameters[" + i + "]")) { + triggerParameters[i] = new TriggerParameter(); + triggerParameters[i].readFromNBT(nbttagcompound.getCompoundTag("triggerParameters[" + i + "]")); + } + } + + private boolean initialized = false; + + public void initialize() { + if (!initialized) { + transport.initialize(); + logic.initialize(); + initialized = true; + updateSignalState(); + } + } + + private void readNearbyPipesSignal(WireColor color) { + boolean foundBiggerSignal = false; + + for (Orientations o : Orientations.dirs()) { + TileEntity tile = container.getTile(o); + + if (tile instanceof TileGenericPipe) { + TileGenericPipe tilePipe = (TileGenericPipe) tile; + + if (BlockGenericPipe.isFullyDefined(tilePipe.pipe)) + if (isWireConnectedTo(tile, color)) + foundBiggerSignal |= receiveSignal(tilePipe.pipe.signalStrength[color.ordinal()] - 1, color); + } + } + + if (!foundBiggerSignal && signalStrength[color.ordinal()] != 0) { + signalStrength[color.ordinal()] = 0; + //worldObj.markBlockNeedsUpdate(xCoord, yCoord, zCoord); + container.scheduleRenderUpdate(); + + + for (Orientations o : Orientations.dirs()) { + TileEntity tile = container.getTile(o); + + if (tile instanceof TileGenericPipe) { + TileGenericPipe tilePipe = (TileGenericPipe) tile; + + if (BlockGenericPipe.isFullyDefined(tilePipe.pipe)) + tilePipe.pipe.internalUpdateScheduled = true; + } + } + } + } + + private void updateSignalState() { + for (IPipe.WireColor c : IPipe.WireColor.values()) + updateSignalStateForColor(c); + } + + private void updateSignalStateForColor(IPipe.WireColor color) { + if (!wireSet[color.ordinal()]) + return; + + // STEP 1: compute internal signal strength + + if (broadcastSignal[color.ordinal()]) + receiveSignal(255, color); + else + readNearbyPipesSignal(color); + + // STEP 2: transmit signal in nearby blocks + + if (signalStrength[color.ordinal()] > 1) + for (Orientations o : Orientations.dirs()) { + TileEntity tile = container.getTile(o); + + if (tile instanceof TileGenericPipe) { + TileGenericPipe tilePipe = (TileGenericPipe) tile; + + if (BlockGenericPipe.isFullyDefined(tilePipe.pipe) && tilePipe.pipe.wireSet[color.ordinal()]) + if (isWireConnectedTo(tile, color)) + tilePipe.pipe.receiveSignal(signalStrength[color.ordinal()] - 1, color); + } + } + } + + private boolean receiveSignal(int signal, IPipe.WireColor color) { + if (worldObj == null) + return false; + + int oldSignal = signalStrength[color.ordinal()]; + + if (signal >= signalStrength[color.ordinal()] && signal != 0) { + signalStrength[color.ordinal()] = signal; + internalUpdateScheduled = true; + + if (oldSignal == 0) { + //worldObj.markBlockNeedsUpdate(xCoord, yCoord, zCoord); + container.scheduleRenderUpdate(); + + } + + return true; + } else + return false; + } + + public boolean inputOpen(Orientations from) { + return transport.inputOpen(from) && logic.inputOpen(from); + } + + public boolean outputOpen(Orientations to) { + return transport.outputOpen(to) && logic.outputOpen(to); + } + + public void onEntityCollidedWithBlock(Entity entity) { + + } + + public boolean isPoweringTo(int l) { + if (!broadcastRedstone) + return false; + + Orientations o = Orientations.values()[l].reverse(); + TileEntity tile = container.getTile(o); + + if (tile instanceof TileGenericPipe && Utils.checkPipesConnections(this.container, tile)) + return false; + + return true; + } + + public boolean isIndirectlyPoweringTo(int l) { + return isPoweringTo(l); + } + + public void randomDisplayTick(Random random) {} + + // / @Override TODO: should be in IPipe + public boolean isWired() { + for (WireColor color : WireColor.values()) + if (isWired(color)) + return true; + + return false; + } + + @Override + public boolean isWired(WireColor color) { + return wireSet[color.ordinal()]; + } + + @Override + public boolean hasInterface() { + return hasGate(); + } + + public boolean hasGate() { + return gate != null; + } + + protected void updateNeighbors(boolean needSelf) { + if (needSelf) { + worldObj.notifyBlocksOfNeighborChange(xCoord, yCoord, zCoord, BuildCraftTransport.genericPipeBlock.blockID); + } + worldObj.notifyBlocksOfNeighborChange(xCoord, yCoord - 1, zCoord, BuildCraftTransport.genericPipeBlock.blockID); + worldObj.notifyBlocksOfNeighborChange(xCoord, yCoord + 1, zCoord, BuildCraftTransport.genericPipeBlock.blockID); + worldObj.notifyBlocksOfNeighborChange(xCoord - 1, yCoord, zCoord, BuildCraftTransport.genericPipeBlock.blockID); + worldObj.notifyBlocksOfNeighborChange(xCoord + 1, yCoord, zCoord, BuildCraftTransport.genericPipeBlock.blockID); + worldObj.notifyBlocksOfNeighborChange(xCoord, yCoord, zCoord - 1, BuildCraftTransport.genericPipeBlock.blockID); + worldObj.notifyBlocksOfNeighborChange(xCoord, yCoord, zCoord + 1, BuildCraftTransport.genericPipeBlock.blockID); + } + + public void onBlockRemoval() { + if (wireSet[IPipe.WireColor.Red.ordinal()]) + Utils.dropItems(worldObj, new ItemStack(BuildCraftTransport.redPipeWire), xCoord, yCoord, zCoord); + + if (wireSet[IPipe.WireColor.Blue.ordinal()]) + Utils.dropItems(worldObj, new ItemStack(BuildCraftTransport.bluePipeWire), xCoord, yCoord, zCoord); + + if (wireSet[IPipe.WireColor.Green.ordinal()]) + Utils.dropItems(worldObj, new ItemStack(BuildCraftTransport.greenPipeWire), xCoord, yCoord, zCoord); + + if (wireSet[IPipe.WireColor.Yellow.ordinal()]) + Utils.dropItems(worldObj, new ItemStack(BuildCraftTransport.yellowPipeWire), xCoord, yCoord, zCoord); + + if (hasGate()) + gate.dropGate(worldObj, xCoord, yCoord, zCoord); + + for (Orientations direction : Orientations.dirs()){ + if (container.hasFacade(direction)){ + container.dropFacade(direction); + } + } + + if (broadcastRedstone) { + updateNeighbors(false); // self will update due to block id changing + } + } + + public void setTrigger(int position, ITrigger trigger) { + activatedTriggers[position] = trigger; + } + + public ITrigger getTrigger(int position) { + return activatedTriggers[position]; + } + + public void setTriggerParameter(int position, ITriggerParameter p) { + triggerParameters[position] = p; + } + + public ITriggerParameter getTriggerParameter(int position) { + return triggerParameters[position]; + } + + public boolean isNearbyTriggerActive(ITrigger trigger, ITriggerParameter parameter) { + if (trigger instanceof ITriggerPipe) + return ((ITriggerPipe) trigger).isTriggerActive(this, parameter); + else if (trigger != null) + for (Orientations o : Orientations.dirs()) { + TileEntity tile = container.getTile(o); + + if (tile != null && !(tile instanceof TileGenericPipe) && trigger.isTriggerActive(tile, parameter)) + return true; + } + + return false; + } + + public boolean isTriggerActive(ITrigger trigger) { + return false; + } + + public LinkedList getActions() { + LinkedList result = new LinkedList(); + + if (hasGate()) + gate.addActions(result); + + return result; + } + + public IAction getAction(int position) { + return activatedActions[position]; + } + + public void setAction(int position, IAction action) { + activatedActions[position] = action; + } + + public void resetGate() { + gate = null; + activatedTriggers = new Trigger[activatedTriggers.length]; + triggerParameters = new ITriggerParameter[triggerParameters.length]; + activatedActions = new Action[activatedActions.length]; + broadcastSignal = new boolean[] { false, false, false, false }; + if (broadcastRedstone) { + updateNeighbors(true); + } + broadcastRedstone = false; + //worldObj.markBlockNeedsUpdate(xCoord, yCoord, zCoord); + container.scheduleRenderUpdate(); + } + + private void resolveActions() { + if (!hasGate()) + return; + + boolean oldBroadcastRedstone = broadcastRedstone; + boolean[] oldBroadcastSignal = broadcastSignal; + + broadcastRedstone = false; + broadcastSignal = new boolean[] { false, false, false, false }; + + // Tell the gate to prepare for resolving actions. (Disable pulser) + gate.startResolution(); + + HashMap actions = new HashMap(); + + // Computes the actions depending on the triggers + for (int it = 0; it < 8; ++it) { + ITrigger trigger = activatedTriggers[it]; + IAction action = activatedActions[it]; + ITriggerParameter parameter = triggerParameters[it]; + + if (trigger != null && action != null) + if (!actions.containsKey(action.getId())) + actions.put(action.getId(), isNearbyTriggerActive(trigger, parameter)); + else if (gate.getConditional() == GateConditional.AND) + actions.put(action.getId(), actions.get(action.getId()) && isNearbyTriggerActive(trigger, parameter)); + else + actions.put(action.getId(), actions.get(action.getId()) || isNearbyTriggerActive(trigger, parameter)); + } + + // Activate the actions + for (Integer i : actions.keySet()) + if (actions.get(i)) { + + // Custom gate actions take precedence over defaults. + if (gate.resolveAction(ActionManager.actions[i])) + continue; + + if (ActionManager.actions[i] instanceof ActionRedstoneOutput) + broadcastRedstone = true; + else if (ActionManager.actions[i] instanceof ActionSignalOutput) + broadcastSignal[((ActionSignalOutput) ActionManager.actions[i]).color.ordinal()] = true; + else + for (int a = 0; a < container.tileBuffer.length; ++a) + if (container.tileBuffer[a].getTile() instanceof IActionReceptor) { + IActionReceptor recept = (IActionReceptor) container.tileBuffer[a].getTile(); + recept.actionActivated(ActionManager.actions[i]); + } + } + + actionsActivated(actions); + + if (oldBroadcastRedstone != broadcastRedstone) { + container.scheduleRenderUpdate(); + updateNeighbors(true); + } + + for (int i = 0; i < oldBroadcastSignal.length; ++i) + if (oldBroadcastSignal[i] != broadcastSignal[i]) { + //worldObj.markBlockNeedsUpdate(xCoord, yCoord, zCoord); + container.scheduleRenderUpdate(); + updateSignalState(); + break; + } + } + + protected void actionsActivated(HashMap actions) { + + } + + @Override + public TileGenericPipe getContainer() { + return container; + } + + @Override + public boolean isWireConnectedTo(TileEntity tile, WireColor color) { + if (!(tile instanceof TileGenericPipe)) + return false; + + TileGenericPipe tilePipe = (TileGenericPipe) tile; + + if (!BlockGenericPipe.isFullyDefined(tilePipe.pipe)) + return false; + + if (!tilePipe.pipe.wireSet[color.ordinal()]) + return false; + + return (tilePipe.pipe.transport instanceof PipeTransportStructure || transport instanceof PipeTransportStructure || Utils + .checkPipesConnections(container, tile)); + } + + public void dropContents() { + transport.dropContents(); + } + + public void onDropped(EntityItem item) { + + } + + /** + * If this pipe is open on one side, return it. + */ + public Orientations getOpenOrientation() { + int Connections_num = 0; + + Orientations target_orientation = Orientations.Unknown; + + for (Orientations o : Orientations.dirs()) + if (Utils.checkPipesConnections(container.getTile(o), container)) { + + Connections_num++; + + if (Connections_num == 1) + target_orientation = o; + } + + if (Connections_num > 1 || Connections_num == 0) + return Orientations.Unknown; + + return target_orientation.reverse(); + } + + @Override + public boolean doDrop() { + return logic.doDrop(); + } + + public boolean isGateActive(){ + for (boolean b : broadcastSignal){ + if (b) return true; + } + return broadcastRedstone; + } + + + /** + * Called when TileGenericPipe.invalidate() is called + */ + public void invalidate() {} + + /** + * Called when TileGenericPipe.validate() is called + */ + public void validate() {} + + + /** + * Called when TileGenericPipe.onChunkUnload is called + */ + public void onChunkUnload() {} + +} + diff --git a/common/buildcraft/transport/PipeTransportItems.java b/common/buildcraft/transport/PipeTransportItems.java index 2f81dbe9..acd54186 100644 --- a/common/buildcraft/transport/PipeTransportItems.java +++ b/common/buildcraft/transport/PipeTransportItems.java @@ -1,508 +1,503 @@ -/** - * Copyright (c) SpaceToad, 2011 - * http://www.mod-buildcraft.com - * - * BuildCraft is distributed under the terms of the Minecraft Mod Public - * License 1.0, or MMPL. Please check the contents of the license located in - * http://www.mod-buildcraft.com/MMPL-1.0.txt - */ - -package buildcraft.transport; - -import java.util.HashSet; -import java.util.LinkedList; -import java.util.TreeMap; -import java.util.TreeSet; -import java.util.Vector; - -import cpw.mods.fml.common.network.PacketDispatcher; - -import buildcraft.BuildCraftCore; -import buildcraft.BuildCraftTransport; -import buildcraft.api.core.Orientations; -import buildcraft.api.core.Position; -import buildcraft.api.gates.ITrigger; -import buildcraft.api.inventory.ISpecialInventory; -import buildcraft.api.transport.IPipeEntry; -import buildcraft.api.transport.IPipedItem; -import buildcraft.core.DefaultProps; -import buildcraft.core.EntityPassiveItem; -import buildcraft.core.IMachine; -import buildcraft.core.inventory.Transactor; -import buildcraft.core.network.PacketIds; -import buildcraft.core.network.PacketPipeTransportContent; -import buildcraft.core.proxy.CoreProxy; -import buildcraft.core.utils.Utils; - -import net.minecraft.src.EntityItem; -import net.minecraft.src.IInventory; -import net.minecraft.src.ItemStack; -import net.minecraft.src.NBTTagCompound; -import net.minecraft.src.NBTTagList; -import net.minecraft.src.Packet; -import net.minecraft.src.TileEntity; -import net.minecraftforge.common.ISidedInventory; - -public class PipeTransportItems extends PipeTransport { - - public boolean allowBouncing = false; - public TreeMap travelingEntities = new TreeMap(); - private final Vector entitiesToLoad = new Vector(); - - // TODO: generalize the use of this hook in particular for obsidian pipe - public IItemTravelingHook travelHook; - - public void readjustSpeed(IPipedItem item) { - if (container.pipe instanceof IPipeTransportItemsHook) - ((IPipeTransportItemsHook) container.pipe).readjustSpeed(item); - else - defaultReajustSpeed(item); - } - - public void defaultReajustSpeed(IPipedItem item) { - - if (item.getSpeed() > Utils.pipeNormalSpeed) - item.setSpeed(item.getSpeed() - Utils.pipeNormalSpeed); - - if (item.getSpeed() < Utils.pipeNormalSpeed) - item.setSpeed(Utils.pipeNormalSpeed); - } - - @Override - public void entityEntering(IPipedItem item, Orientations orientation) { - if (item.isCorrupted()) - // Safe guard - if for any reason the item is corrupted at this - // stage, avoid adding it to the pipe to avoid further exceptions. - return; - - readjustSpeed(item); - - if (!travelingEntities.containsKey(new Integer(item.getEntityId()))) { - travelingEntities.put(new Integer(item.getEntityId()), new EntityData(item, orientation)); - - if (item.getContainer() != null && item.getContainer() != this.container) - ((PipeTransportItems) ((TileGenericPipe) item.getContainer()).pipe.transport).scheduleRemoval(item); - - item.setContainer(container); - } - - // Reajusting Ypos to make sure the object looks like sitting on the - // pipe. - if (orientation != Orientations.YPos && orientation != Orientations.YNeg) - item.setPosition(item.getPosition().x, yCoord + Utils.getPipeFloorOf(item.getItemStack()), item.getPosition().z); - - if (container.pipe instanceof IPipeTransportItemsHook) - ((IPipeTransportItemsHook) container.pipe).entityEntered(item, orientation); - - if (!worldObj.isRemote && item.getSynchroTracker().markTimeIfDelay(worldObj, 6 * BuildCraftCore.updateFactor)) { - int dimension = worldObj.provider.worldType; - PacketDispatcher.sendPacketToAllAround(xCoord, yCoord, zCoord, DefaultProps.NETWORK_UPDATE_RANGE, dimension, createItemPacket(item, orientation)); - } - -// for (Object player : MinecraftServer.getServer().getConfigurationManager().playerEntityList){ -// -// } -// CoreProxy.sendToPlayers(createItemPacket(item, orientation), worldObj, xCoord, yCoord, zCoord, -// DefaultProps.NETWORK_UPDATE_RANGE, mod_BuildCraftTransport.instance); - - if (travelingEntities.size() > BuildCraftTransport.groupItemsTrigger) { - groupEntities(); - - if (travelingEntities.size() > BuildCraftTransport.maxItemsInPipes) - worldObj.createExplosion(null, xCoord, yCoord, zCoord, 1); - } - } - - /** - * Returns a list of all possible movements, that is to say adjacent - * implementers of IPipeEntry or TileEntityChest. - */ - public LinkedList getPossibleMovements(Position pos, IPipedItem item) { - LinkedList result = new LinkedList(); - - for (Orientations o : Orientations.dirs()) - if (o != pos.orientation.reverse() && container.pipe.outputOpen(o)) - if (canReceivePipeObjects(o, item)) - result.add(o); - - if (result.size() == 0 && allowBouncing) { - Position newPos = new Position(pos); - newPos.orientation = newPos.orientation.reverse(); - - if (canReceivePipeObjects(pos.orientation.reverse(), item)) - result.add(pos.orientation.reverse()); - - } - - if (this.container.pipe instanceof IPipeTransportItemsHook) - result = ((IPipeTransportItemsHook) this.container.pipe).filterPossibleMovements(result, pos, item); - - return result; - } - - public boolean canReceivePipeObjects(Orientations o, IPipedItem item) { - TileEntity entity = container.getTile(o); - - if (!Utils.checkPipesConnections(entity, container)) - return false; - - if (entity instanceof IPipeEntry) - return true; - else if (entity instanceof TileGenericPipe) { - TileGenericPipe pipe = (TileGenericPipe) entity; - - return pipe.pipe.transport instanceof PipeTransportItems; - } else if (entity instanceof IInventory) - if(Transactor.getTransactorFor(entity).add(item.getItemStack(), o.reverse(), false).stackSize > 0) - return true; - - return false; - } - - @Override - public void updateEntity() { - moveSolids(); - } - - HashSet toRemove = new HashSet(); - - public void scheduleRemoval(IPipedItem item) { - if (!toRemove.contains(item.getEntityId())) - toRemove.add(item.getEntityId()); - } - - public void performRemoval() { - travelingEntities.keySet().removeAll(toRemove); - toRemove = new HashSet(); - } - - private void moveSolids() { - for (EntityData data : entitiesToLoad) { - data.item.setWorld(worldObj); - travelingEntities.put(new Integer(data.item.getEntityId()), data); - } - - entitiesToLoad.clear(); - performRemoval(); - - for (EntityData data : travelingEntities.values()) { - if (data.item.isCorrupted()) { - scheduleRemoval(data.item); - data.item.remove(); - continue; - } - - Position motion = new Position(0, 0, 0, data.orientation); - motion.moveForwards(data.item.getSpeed()); - - data.item.setPosition(data.item.getPosition().x + motion.x, data.item.getPosition().y + motion.y, data.item.getPosition().z + motion.z); - - if ((data.toCenter && middleReached(data)) || outOfBounds(data)) { - data.toCenter = false; - - // Reajusting to the middle - - data.item.setPosition(xCoord + 0.5, yCoord + Utils.getPipeFloorOf(data.item.getItemStack()), zCoord + +0.5); - - Orientations nextOrientation = resolveDestination(data); - - if (nextOrientation == Orientations.Unknown) { - if (travelHook != null) - travelHook.drop(this, data); - - EntityItem dropped = null; - - if (!toRemove.contains(data.item.getEntityId())) - dropped = data.item.toEntityItem(data.orientation); - - scheduleRemoval(data.item); - - if (dropped != null) - onDropped(dropped); - } else { - data.orientation = nextOrientation; - - if (travelHook != null) - travelHook.centerReached(this, data); - } - - } else if (!data.toCenter && endReached(data)) { - Position destPos = new Position(xCoord, yCoord, zCoord, data.orientation); - - destPos.moveForwards(1.0); - - TileEntity tile = worldObj.getBlockTileEntity((int) destPos.x, (int) destPos.y, (int) destPos.z); - - if (travelHook != null) - travelHook.endReached(this, data, tile); - - // If the item has not been scheduled to removal by the hook - if (!toRemove.contains(data.item.getEntityId())) { - scheduleRemoval(data.item); - handleTileReached(data, tile); - } - - } - } - - performRemoval(); - } - - private void handleTileReached(EntityData data, TileEntity tile) { - if (tile instanceof IPipeEntry) - ((IPipeEntry) tile).entityEntering(data.item, data.orientation); - else if (tile instanceof TileGenericPipe && ((TileGenericPipe) tile).pipe.transport instanceof PipeTransportItems) { - TileGenericPipe pipe = (TileGenericPipe) tile; - - ((PipeTransportItems) pipe.pipe.transport).entityEntering(data.item, data.orientation); - } else if (tile instanceof IInventory) { - ItemStack added = Transactor.getTransactorFor(tile).add(data.item.getItemStack(), data.orientation.reverse(), true); - - if (!CoreProxy.proxy.isRenderWorld(worldObj)) - if(added.stackSize >= data.item.getItemStack().stackSize) - data.item.remove(); - else { - data.item.getItemStack().stackSize -= added.stackSize; - EntityItem dropped = data.item.toEntityItem(data.orientation); - - if (dropped != null) - // On SMP, the client side doesn't actually drops - // items - onDropped(dropped); - } - } else { - if (travelHook != null) - travelHook.drop(this, data); - - EntityItem dropped = data.item.toEntityItem(data.orientation); - - if (dropped != null) - // On SMP, the client side doesn't actually drops - // items - onDropped(dropped); - } - } - - public boolean middleReached(EntityData entity) { - float middleLimit = entity.item.getSpeed() * 1.01F; - return (Math.abs(xCoord + 0.5 - entity.item.getPosition().x) < middleLimit - && Math.abs(yCoord + Utils.getPipeFloorOf(entity.item.getItemStack()) - entity.item.getPosition().y) < middleLimit && Math.abs(zCoord - + 0.5 - entity.item.getPosition().z) < middleLimit); - } - - public boolean endReached(EntityData entity) { - return entity.item.getPosition().x > xCoord + 1.0 || entity.item.getPosition().x < xCoord || entity.item.getPosition().y > yCoord + 1.0 - || entity.item.getPosition().y < yCoord || entity.item.getPosition().z > zCoord + 1.0 || entity.item.getPosition().z < zCoord; - } - - public boolean outOfBounds(EntityData entity) { - return entity.item.getPosition().x > xCoord + 2.0 || entity.item.getPosition().x < xCoord - 1.0 || entity.item.getPosition().y > yCoord + 2.0 - || entity.item.getPosition().y < yCoord - 1.0 || entity.item.getPosition().z > zCoord + 2.0 || entity.item.getPosition().z < zCoord - 1.0; - } - - public Position getPosition() { - return new Position(xCoord, yCoord, zCoord); - } - - @Override - public void readFromNBT(NBTTagCompound nbttagcompound) { - super.readFromNBT(nbttagcompound); - - NBTTagList nbttaglist = nbttagcompound.getTagList("travelingEntities"); - - for (int j = 0; j < nbttaglist.tagCount(); ++j) - try { - NBTTagCompound nbttagcompound2 = (NBTTagCompound) nbttaglist.tagAt(j); - - IPipedItem entity = new EntityPassiveItem(null); - entity.readFromNBT(nbttagcompound2); - - if (entity.isCorrupted()) { - entity.remove(); - continue; - } - - entity.setContainer(container); - - EntityData data = new EntityData(entity, Orientations.values()[nbttagcompound2.getInteger("orientation")]); - data.toCenter = nbttagcompound2.getBoolean("toCenter"); - - entitiesToLoad.add(data); - } catch (Throwable t) { - t.printStackTrace(); - // It may be the case that entities cannot be reloaded between - // two versions - ignore these errors. - } - } - - @Override - public void writeToNBT(NBTTagCompound nbttagcompound) { - super.writeToNBT(nbttagcompound); - - NBTTagList nbttaglist = new NBTTagList(); - - for (EntityData data : travelingEntities.values()) { - NBTTagCompound nbttagcompound2 = new NBTTagCompound(); - nbttaglist.appendTag(nbttagcompound2); - data.item.writeToNBT(nbttagcompound2); - nbttagcompound2.setBoolean("toCenter", data.toCenter); - nbttagcompound2.setInteger("orientation", data.orientation.ordinal()); - } - - nbttagcompound.setTag("travelingEntities", nbttaglist); - } - - public Orientations resolveDestination(EntityData data) { - LinkedList listOfPossibleMovements = getPossibleMovements(new Position(xCoord, yCoord, zCoord, - data.orientation), data.item); - - if (listOfPossibleMovements.size() == 0) - return Orientations.Unknown; - else { - int i; - - if (CoreProxy.proxy.isRenderWorld(worldObj) || CoreProxy.proxy.isSimulating(worldObj)) - { - i = Math.abs(data.item.getEntityId() + xCoord + yCoord + zCoord + data.item.getDeterministicRandomization()) - % listOfPossibleMovements.size(); - data.item.setDeterministicRandomization(data.item.getDeterministicRandomization() * 11); - - } - else - i = worldObj.rand.nextInt(listOfPossibleMovements.size()); - - return listOfPossibleMovements.get(i); - } - } - - protected void doWork() {} - - /** - * Handles a packet describing a stack of items inside a pipe. - * - * @param packet - */ - public void handleItemPacket(PacketPipeTransportContent packet) { - - if (packet.getID() != PacketIds.PIPE_CONTENTS) - return; - - IPipedItem item = EntityPassiveItem.getOrCreate(worldObj, packet.getEntityId()); - - item.setItemStack(new ItemStack(packet.getItemId(), packet.getStackSize(), packet.getItemDamage())); - - item.setPosition(packet.getPosX(), packet.getPosY(), packet.getPosZ()); - item.setSpeed(packet.getSpeed()); - item.setDeterministicRandomization(packet.getRandomization()); - - if (item.getContainer() != this.container || !travelingEntities.containsKey(item.getEntityId())) { - - if (item.getContainer() != null) - ((PipeTransportItems) ((TileGenericPipe) item.getContainer()).pipe.transport).scheduleRemoval(item); - - travelingEntities.put(new Integer(item.getEntityId()), new EntityData(item, packet.getOrientation())); - item.setContainer(container); - - } else - travelingEntities.get(new Integer(item.getEntityId())).orientation = packet.getOrientation(); - - } - - /** - * Creates a packet describing a stack of items inside a pipe. - * - * @param item - * @param orientation - * @return - */ - public Packet createItemPacket(IPipedItem item, Orientations orientation) { - - item.setDeterministicRandomization(item.getDeterministicRandomization() + worldObj.rand.nextInt(6)); - PacketPipeTransportContent packet = new PacketPipeTransportContent(container.xCoord, container.yCoord, container.zCoord, - item, orientation); - - return packet.getPacket(); - } - - public int getNumberOfItems() { - return travelingEntities.size(); - } - - public void onDropped(EntityItem item) { - this.container.pipe.onDropped(item); - } - - protected void neighborChange() { - - } - - @Override - public boolean isPipeConnected(TileEntity tile) { - if( tile instanceof ISidedInventory ){ - Orientations or = Utils.get3dOrientation(new Position(container), new Position(tile)); - return ((ISidedInventory) tile).getSizeInventorySide(or.toDirection()) > 0; - } - return tile instanceof TileGenericPipe - || tile instanceof IPipeEntry - || tile instanceof ISpecialInventory - || (tile instanceof IInventory && ((IInventory)tile).getSizeInventory() > 0) - || (tile instanceof IMachine && ((IMachine) tile).manageSolids()); - } - - @Override - public boolean acceptItems() { - return true; - } - - public boolean isTriggerActive(ITrigger trigger) { - return false; - } - - /** - * Group all items that are similar, that is to say same dmg, same id and no - * contribution controlling them - */ - public void groupEntities() { - EntityData[] entities = travelingEntities.values().toArray(new EntityData[travelingEntities.size()]); - - TreeSet toRemove = new TreeSet(); - - for (int i = 0; i < entities.length; ++i) { - EntityData data1 = entities[i]; - - for (int j = i + 1; j < entities.length; ++j) { - EntityData data2 = entities[j]; - - if (data1.item.getItemStack().itemID == data2.item.getItemStack().itemID - && data1.item.getItemStack().getItemDamage() == data2.item.getItemStack().getItemDamage() - && !toRemove.contains(data1.item.getEntityId()) && !toRemove.contains(data2.item.getEntityId()) - && !data1.item.hasContributions() && !data2.item.hasContributions() - && data1.item.getItemStack().stackSize + data2.item.getItemStack().stackSize < data1.item.getItemStack().getMaxStackSize()) { - - data1.item.getItemStack().stackSize += data2.item.getItemStack().stackSize; - toRemove.add(data2.item.getEntityId()); - } - } - } - - for (Integer i : toRemove) { - travelingEntities.get(i).item.remove(); - travelingEntities.remove(i); - } - } - - @Override - public void dropContents() { - groupEntities(); - - for (EntityData data : travelingEntities.values()) - Utils.dropItems(worldObj, data.item.getItemStack(), xCoord, yCoord, zCoord); - - travelingEntities.clear(); - } - - @Override - public boolean allowsConnect(PipeTransport with) { - return with instanceof PipeTransportItems; - } -} +/** + * Copyright (c) SpaceToad, 2011 + * http://www.mod-buildcraft.com + * + * BuildCraft is distributed under the terms of the Minecraft Mod Public + * License 1.0, or MMPL. Please check the contents of the license located in + * http://www.mod-buildcraft.com/MMPL-1.0.txt + */ + +package buildcraft.transport; + +import java.util.HashSet; +import java.util.LinkedList; +import java.util.TreeMap; +import java.util.TreeSet; +import java.util.Vector; + +import cpw.mods.fml.common.network.PacketDispatcher; + +import buildcraft.BuildCraftCore; +import buildcraft.BuildCraftTransport; +import buildcraft.api.core.Orientations; +import buildcraft.api.core.Position; +import buildcraft.api.gates.ITrigger; +import buildcraft.api.inventory.ISpecialInventory; +import buildcraft.api.transport.IPipeEntry; +import buildcraft.api.transport.IPipedItem; +import buildcraft.core.DefaultProps; +import buildcraft.core.EntityPassiveItem; +import buildcraft.core.IMachine; +import buildcraft.core.inventory.Transactor; +import buildcraft.core.network.PacketIds; +import buildcraft.core.network.PacketPipeTransportContent; +import buildcraft.core.proxy.CoreProxy; +import buildcraft.core.utils.Utils; + +import net.minecraft.src.EntityItem; +import net.minecraft.src.IInventory; +import net.minecraft.src.ItemStack; +import net.minecraft.src.NBTTagCompound; +import net.minecraft.src.NBTTagList; +import net.minecraft.src.Packet; +import net.minecraft.src.TileEntity; + +public class PipeTransportItems extends PipeTransport { + + public boolean allowBouncing = false; + public TreeMap travelingEntities = new TreeMap(); + private final Vector entitiesToLoad = new Vector(); + + // TODO: generalize the use of this hook in particular for obsidian pipe + public IItemTravelingHook travelHook; + + public void readjustSpeed(IPipedItem item) { + if (container.pipe instanceof IPipeTransportItemsHook) + ((IPipeTransportItemsHook) container.pipe).readjustSpeed(item); + else + defaultReajustSpeed(item); + } + + public void defaultReajustSpeed(IPipedItem item) { + + if (item.getSpeed() > Utils.pipeNormalSpeed) + item.setSpeed(item.getSpeed() - Utils.pipeNormalSpeed); + + if (item.getSpeed() < Utils.pipeNormalSpeed) + item.setSpeed(Utils.pipeNormalSpeed); + } + + @Override + public void entityEntering(IPipedItem item, Orientations orientation) { + if (item.isCorrupted()) + // Safe guard - if for any reason the item is corrupted at this + // stage, avoid adding it to the pipe to avoid further exceptions. + return; + + readjustSpeed(item); + + if (!travelingEntities.containsKey(new Integer(item.getEntityId()))) { + travelingEntities.put(new Integer(item.getEntityId()), new EntityData(item, orientation)); + + if (item.getContainer() != null && item.getContainer() != this.container) + ((PipeTransportItems) ((TileGenericPipe) item.getContainer()).pipe.transport).scheduleRemoval(item); + + item.setContainer(container); + } + + // Reajusting Ypos to make sure the object looks like sitting on the + // pipe. + if (orientation != Orientations.YPos && orientation != Orientations.YNeg) + item.setPosition(item.getPosition().x, yCoord + Utils.getPipeFloorOf(item.getItemStack()), item.getPosition().z); + + if (container.pipe instanceof IPipeTransportItemsHook) + ((IPipeTransportItemsHook) container.pipe).entityEntered(item, orientation); + + if (!worldObj.isRemote && item.getSynchroTracker().markTimeIfDelay(worldObj, 6 * BuildCraftCore.updateFactor)) { + int dimension = worldObj.provider.worldType; + PacketDispatcher.sendPacketToAllAround(xCoord, yCoord, zCoord, DefaultProps.NETWORK_UPDATE_RANGE, dimension, createItemPacket(item, orientation)); + } + +// for (Object player : MinecraftServer.getServer().getConfigurationManager().playerEntityList){ +// +// } +// CoreProxy.sendToPlayers(createItemPacket(item, orientation), worldObj, xCoord, yCoord, zCoord, +// DefaultProps.NETWORK_UPDATE_RANGE, mod_BuildCraftTransport.instance); + + if (travelingEntities.size() > BuildCraftTransport.groupItemsTrigger) { + groupEntities(); + + if (travelingEntities.size() > BuildCraftTransport.maxItemsInPipes) + worldObj.createExplosion(null, xCoord, yCoord, zCoord, 1); + } + } + + /** + * Returns a list of all possible movements, that is to say adjacent + * implementers of IPipeEntry or TileEntityChest. + */ + public LinkedList getPossibleMovements(Position pos, IPipedItem item) { + LinkedList result = new LinkedList(); + + for (Orientations o : Orientations.dirs()) + if (o != pos.orientation.reverse() && container.pipe.outputOpen(o)) + if (canReceivePipeObjects(o, item)) + result.add(o); + + if (result.size() == 0 && allowBouncing) { + Position newPos = new Position(pos); + newPos.orientation = newPos.orientation.reverse(); + + if (canReceivePipeObjects(pos.orientation.reverse(), item)) + result.add(pos.orientation.reverse()); + + } + + if (this.container.pipe instanceof IPipeTransportItemsHook) + result = ((IPipeTransportItemsHook) this.container.pipe).filterPossibleMovements(result, pos, item); + + return result; + } + + public boolean canReceivePipeObjects(Orientations o, IPipedItem item) { + TileEntity entity = container.getTile(o); + + if (!Utils.checkPipesConnections(entity, container)) + return false; + + if (entity instanceof IPipeEntry) + return true; + else if (entity instanceof TileGenericPipe) { + TileGenericPipe pipe = (TileGenericPipe) entity; + + return pipe.pipe.transport instanceof PipeTransportItems; + } else if (entity instanceof IInventory) + if(Transactor.getTransactorFor(entity).add(item.getItemStack(), o.reverse(), false).stackSize > 0) + return true; + + return false; + } + + @Override + public void updateEntity() { + moveSolids(); + } + + HashSet toRemove = new HashSet(); + + public void scheduleRemoval(IPipedItem item) { + if (!toRemove.contains(item.getEntityId())) + toRemove.add(item.getEntityId()); + } + + public void performRemoval() { + travelingEntities.keySet().removeAll(toRemove); + toRemove = new HashSet(); + } + + private void moveSolids() { + for (EntityData data : entitiesToLoad) { + data.item.setWorld(worldObj); + travelingEntities.put(new Integer(data.item.getEntityId()), data); + } + + entitiesToLoad.clear(); + performRemoval(); + + for (EntityData data : travelingEntities.values()) { + if (data.item.isCorrupted()) { + scheduleRemoval(data.item); + data.item.remove(); + continue; + } + + Position motion = new Position(0, 0, 0, data.orientation); + motion.moveForwards(data.item.getSpeed()); + + data.item.setPosition(data.item.getPosition().x + motion.x, data.item.getPosition().y + motion.y, data.item.getPosition().z + motion.z); + + if ((data.toCenter && middleReached(data)) || outOfBounds(data)) { + data.toCenter = false; + + // Reajusting to the middle + + data.item.setPosition(xCoord + 0.5, yCoord + Utils.getPipeFloorOf(data.item.getItemStack()), zCoord + +0.5); + + Orientations nextOrientation = resolveDestination(data); + + if (nextOrientation == Orientations.Unknown) { + if (travelHook != null) + travelHook.drop(this, data); + + EntityItem dropped = null; + + if (!toRemove.contains(data.item.getEntityId())) + dropped = data.item.toEntityItem(data.orientation); + + scheduleRemoval(data.item); + + if (dropped != null) + onDropped(dropped); + } else { + data.orientation = nextOrientation; + + if (travelHook != null) + travelHook.centerReached(this, data); + } + + } else if (!data.toCenter && endReached(data)) { + Position destPos = new Position(xCoord, yCoord, zCoord, data.orientation); + + destPos.moveForwards(1.0); + + TileEntity tile = worldObj.getBlockTileEntity((int) destPos.x, (int) destPos.y, (int) destPos.z); + + if (travelHook != null) + travelHook.endReached(this, data, tile); + + // If the item has not been scheduled to removal by the hook + if (!toRemove.contains(data.item.getEntityId())) { + scheduleRemoval(data.item); + handleTileReached(data, tile); + } + + } + } + + performRemoval(); + } + + private void handleTileReached(EntityData data, TileEntity tile) { + if (tile instanceof IPipeEntry) + ((IPipeEntry) tile).entityEntering(data.item, data.orientation); + else if (tile instanceof TileGenericPipe && ((TileGenericPipe) tile).pipe.transport instanceof PipeTransportItems) { + TileGenericPipe pipe = (TileGenericPipe) tile; + + ((PipeTransportItems) pipe.pipe.transport).entityEntering(data.item, data.orientation); + } else if (tile instanceof IInventory) { + ItemStack added = Transactor.getTransactorFor(tile).add(data.item.getItemStack(), data.orientation.reverse(), true); + + if (!CoreProxy.proxy.isRenderWorld(worldObj)) + if(added.stackSize >= data.item.getItemStack().stackSize) + data.item.remove(); + else { + data.item.getItemStack().stackSize -= added.stackSize; + EntityItem dropped = data.item.toEntityItem(data.orientation); + + if (dropped != null) + // On SMP, the client side doesn't actually drops + // items + onDropped(dropped); + } + } else { + if (travelHook != null) + travelHook.drop(this, data); + + EntityItem dropped = data.item.toEntityItem(data.orientation); + + if (dropped != null) + // On SMP, the client side doesn't actually drops + // items + onDropped(dropped); + } + } + + public boolean middleReached(EntityData entity) { + float middleLimit = entity.item.getSpeed() * 1.01F; + return (Math.abs(xCoord + 0.5 - entity.item.getPosition().x) < middleLimit + && Math.abs(yCoord + Utils.getPipeFloorOf(entity.item.getItemStack()) - entity.item.getPosition().y) < middleLimit && Math.abs(zCoord + + 0.5 - entity.item.getPosition().z) < middleLimit); + } + + public boolean endReached(EntityData entity) { + return entity.item.getPosition().x > xCoord + 1.0 || entity.item.getPosition().x < xCoord || entity.item.getPosition().y > yCoord + 1.0 + || entity.item.getPosition().y < yCoord || entity.item.getPosition().z > zCoord + 1.0 || entity.item.getPosition().z < zCoord; + } + + public boolean outOfBounds(EntityData entity) { + return entity.item.getPosition().x > xCoord + 2.0 || entity.item.getPosition().x < xCoord - 1.0 || entity.item.getPosition().y > yCoord + 2.0 + || entity.item.getPosition().y < yCoord - 1.0 || entity.item.getPosition().z > zCoord + 2.0 || entity.item.getPosition().z < zCoord - 1.0; + } + + public Position getPosition() { + return new Position(xCoord, yCoord, zCoord); + } + + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + super.readFromNBT(nbttagcompound); + + NBTTagList nbttaglist = nbttagcompound.getTagList("travelingEntities"); + + for (int j = 0; j < nbttaglist.tagCount(); ++j) + try { + NBTTagCompound nbttagcompound2 = (NBTTagCompound) nbttaglist.tagAt(j); + + IPipedItem entity = new EntityPassiveItem(null); + entity.readFromNBT(nbttagcompound2); + + if (entity.isCorrupted()) { + entity.remove(); + continue; + } + + entity.setContainer(container); + + EntityData data = new EntityData(entity, Orientations.values()[nbttagcompound2.getInteger("orientation")]); + data.toCenter = nbttagcompound2.getBoolean("toCenter"); + + entitiesToLoad.add(data); + } catch (Throwable t) { + t.printStackTrace(); + // It may be the case that entities cannot be reloaded between + // two versions - ignore these errors. + } + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + super.writeToNBT(nbttagcompound); + + NBTTagList nbttaglist = new NBTTagList(); + + for (EntityData data : travelingEntities.values()) { + NBTTagCompound nbttagcompound2 = new NBTTagCompound(); + nbttaglist.appendTag(nbttagcompound2); + data.item.writeToNBT(nbttagcompound2); + nbttagcompound2.setBoolean("toCenter", data.toCenter); + nbttagcompound2.setInteger("orientation", data.orientation.ordinal()); + } + + nbttagcompound.setTag("travelingEntities", nbttaglist); + } + + public Orientations resolveDestination(EntityData data) { + LinkedList listOfPossibleMovements = getPossibleMovements(new Position(xCoord, yCoord, zCoord, + data.orientation), data.item); + + if (listOfPossibleMovements.size() == 0) + return Orientations.Unknown; + else { + int i; + + if (CoreProxy.proxy.isRenderWorld(worldObj) || CoreProxy.proxy.isSimulating(worldObj)) + { + i = Math.abs(data.item.getEntityId() + xCoord + yCoord + zCoord + data.item.getDeterministicRandomization()) + % listOfPossibleMovements.size(); + data.item.setDeterministicRandomization(data.item.getDeterministicRandomization() * 11); + + } + else + i = worldObj.rand.nextInt(listOfPossibleMovements.size()); + + return listOfPossibleMovements.get(i); + } + } + + protected void doWork() {} + + /** + * Handles a packet describing a stack of items inside a pipe. + * + * @param packet + */ + public void handleItemPacket(PacketPipeTransportContent packet) { + + if (packet.getID() != PacketIds.PIPE_CONTENTS) + return; + + IPipedItem item = EntityPassiveItem.getOrCreate(worldObj, packet.getEntityId()); + + item.setItemStack(new ItemStack(packet.getItemId(), packet.getStackSize(), packet.getItemDamage())); + + item.setPosition(packet.getPosX(), packet.getPosY(), packet.getPosZ()); + item.setSpeed(packet.getSpeed()); + item.setDeterministicRandomization(packet.getRandomization()); + + if (item.getContainer() != this.container || !travelingEntities.containsKey(item.getEntityId())) { + + if (item.getContainer() != null) + ((PipeTransportItems) ((TileGenericPipe) item.getContainer()).pipe.transport).scheduleRemoval(item); + + travelingEntities.put(new Integer(item.getEntityId()), new EntityData(item, packet.getOrientation())); + item.setContainer(container); + + } else + travelingEntities.get(new Integer(item.getEntityId())).orientation = packet.getOrientation(); + + } + + /** + * Creates a packet describing a stack of items inside a pipe. + * + * @param item + * @param orientation + * @return + */ + public Packet createItemPacket(IPipedItem item, Orientations orientation) { + + item.setDeterministicRandomization(item.getDeterministicRandomization() + worldObj.rand.nextInt(6)); + PacketPipeTransportContent packet = new PacketPipeTransportContent(container.xCoord, container.yCoord, container.zCoord, + item, orientation); + + return packet.getPacket(); + } + + public int getNumberOfItems() { + return travelingEntities.size(); + } + + public void onDropped(EntityItem item) { + this.container.pipe.onDropped(item); + } + + protected void neighborChange() { + + } + + @Override + public boolean isPipeConnected(TileEntity tile) { + return tile instanceof TileGenericPipe + || tile instanceof IPipeEntry + || tile instanceof ISpecialInventory + || (tile instanceof IInventory && ((IInventory)tile).getSizeInventory() > 0) + || (tile instanceof IMachine && ((IMachine) tile).manageSolids()); + } + + @Override + public boolean acceptItems() { + return true; + } + + public boolean isTriggerActive(ITrigger trigger) { + return false; + } + + /** + * Group all items that are similar, that is to say same dmg, same id and no + * contribution controlling them + */ + public void groupEntities() { + EntityData[] entities = travelingEntities.values().toArray(new EntityData[travelingEntities.size()]); + + TreeSet toRemove = new TreeSet(); + + for (int i = 0; i < entities.length; ++i) { + EntityData data1 = entities[i]; + + for (int j = i + 1; j < entities.length; ++j) { + EntityData data2 = entities[j]; + + if (data1.item.getItemStack().itemID == data2.item.getItemStack().itemID + && data1.item.getItemStack().getItemDamage() == data2.item.getItemStack().getItemDamage() + && !toRemove.contains(data1.item.getEntityId()) && !toRemove.contains(data2.item.getEntityId()) + && !data1.item.hasContributions() && !data2.item.hasContributions() + && data1.item.getItemStack().stackSize + data2.item.getItemStack().stackSize < data1.item.getItemStack().getMaxStackSize()) { + + data1.item.getItemStack().stackSize += data2.item.getItemStack().stackSize; + toRemove.add(data2.item.getEntityId()); + } + } + } + + for (Integer i : toRemove) { + travelingEntities.get(i).item.remove(); + travelingEntities.remove(i); + } + } + + @Override + public void dropContents() { + groupEntities(); + + for (EntityData data : travelingEntities.values()) + Utils.dropItems(worldObj, data.item.getItemStack(), xCoord, yCoord, zCoord); + + travelingEntities.clear(); + } + + @Override + public boolean allowsConnect(PipeTransport with) { + return with instanceof PipeTransportItems; + } +}