diff options
Diffstat (limited to 'src/main/java/gregtech/api/graphs')
14 files changed, 844 insertions, 0 deletions
diff --git a/src/main/java/gregtech/api/graphs/GenerateNodeMap.java b/src/main/java/gregtech/api/graphs/GenerateNodeMap.java new file mode 100644 index 0000000000..98c8215fc7 --- /dev/null +++ b/src/main/java/gregtech/api/graphs/GenerateNodeMap.java @@ -0,0 +1,174 @@ +package gregtech.api.graphs; + +import gregtech.api.graphs.consumers.ConsumerNode; +import gregtech.api.graphs.paths.NodePath; +import gregtech.api.metatileentity.*; +import net.minecraft.tileentity.TileEntity; + +import java.util.ArrayList; +import java.util.HashSet; + +import static gregtech.api.util.GT_Utility.getOppositeSide; + + +//generates the node map +abstract public class GenerateNodeMap { + //clearing the node map to make sure it is gone on reset + public static void clearNodeMap(Node aNode,int aReturnNodeValue) { + if (aNode.mTileEntity instanceof BaseMetaPipeEntity) { + BaseMetaPipeEntity tPipe = (BaseMetaPipeEntity) aNode.mTileEntity; + tPipe.setNode(null); + tPipe.setNodePath(null); + if (aNode.mSelfPath != null) { + aNode.mSelfPath.clearPath(); + aNode.mSelfPath = null; + } + } + for (int i = 0;i<6;i++) { + NodePath tPath = aNode.mNodePaths[i]; + if (tPath != null) { + tPath.clearPath(); + aNode.mNodePaths[i] = null; + } + Node tNextNode = aNode.mNeighbourNodes[i]; + if (tNextNode == null) continue; + if (tNextNode.mNodeValue != aReturnNodeValue) + clearNodeMap(tNextNode,aNode.mNodeValue); + aNode.mNeighbourNodes[i] = null; + } + } + + //gets the next node + protected void generateNextNode(BaseMetaPipeEntity aPipe, Node aPipeNode, byte aInvalidSide, int aNextNodeValue, + ArrayList<ConsumerNode> tConsumers, HashSet<Node> tNodeMap) { + MetaPipeEntity tMetaPipe = (MetaPipeEntity) aPipe.getMetaTileEntity(); + for (byte i = 0;i<6;i++) { + if (i==aInvalidSide) { + continue; + } + TileEntity tNextTileEntity = aPipe.getTileEntityAtSide(i); + if (tNextTileEntity == null || (tMetaPipe != null && !tMetaPipe.isConnectedAtSide(i))) continue; + ArrayList<MetaPipeEntity> tNewPipes = new ArrayList<MetaPipeEntity>(); + Pair nextTileEntity = getNextValidTileEntity(tNextTileEntity,tNewPipes,i,tNodeMap); + if (nextTileEntity != null) { + Node tNextNode = generateNode(nextTileEntity.mTileEntity,aPipeNode,aNextNodeValue+1,tNewPipes, + nextTileEntity.mSide,tConsumers,tNodeMap); + if (tNextNode != null) { + aNextNodeValue = tNextNode.mHighestNodeValue; + aPipeNode.mHighestNodeValue = tNextNode.mHighestNodeValue; + aPipeNode.mNeighbourNodes[i] = tNextNode; + aPipeNode.mNodePaths[i] = aPipeNode.mReturnPath; + } + } + } + } + + //on a valid tile entity create a new node + protected Node generateNode(TileEntity aTileEntity, Node aPreviousNode, int aNextNodeValue, ArrayList<MetaPipeEntity> aPipes, + int aSide, ArrayList<ConsumerNode> aConsumers, HashSet<Node> aNodeMap) { + if (aTileEntity.isInvalid()) return null; + byte tSideOp = getOppositeSide(aSide); + byte tInvalidSide = aPreviousNode == null ? -1 : tSideOp; + Node tThisNode = null; + if (isPipe(aTileEntity)){ + BaseMetaPipeEntity tPipe = (BaseMetaPipeEntity) aTileEntity; + MetaPipeEntity tMetaPipe = (MetaPipeEntity) tPipe.getMetaTileEntity(); + int tConnections = getNumberOfConnections(tMetaPipe); + Node tPipeNode; + if (tConnections == 1) { + tPipeNode = getEmptyNode(aNextNodeValue,tSideOp,aTileEntity,aConsumers); + if (tPipeNode == null) return null; + } else { + tPipeNode = getPipeNode(aNextNodeValue,tSideOp,aTileEntity,aConsumers); + } + tPipe.setNode(tPipeNode); + aNodeMap.add(tPipeNode); + tPipeNode.mSelfPath = getNewPath(new MetaPipeEntity[]{tMetaPipe}); + tThisNode = tPipeNode; + if (tInvalidSide>-1) { + tPipeNode.mNeighbourNodes[tInvalidSide] = aPreviousNode; + tPipeNode.mNodePaths[tInvalidSide] = getNewPath(aPipes.toArray(new MetaPipeEntity[0])); + aPreviousNode.mReturnPath = tPipeNode.mNodePaths[tInvalidSide]; + } + if (tConnections > 1) + generateNextNode(tPipe,tPipeNode,tInvalidSide,aNextNodeValue,aConsumers,aNodeMap); + } else if (addConsumer(aTileEntity,tSideOp,aNextNodeValue,aConsumers)) { + ConsumerNode tConsumeNode = aConsumers.get(aConsumers.size()-1); + tConsumeNode.mNeighbourNodes[tSideOp] = aPreviousNode; + tConsumeNode.mNodePaths[tSideOp] = getNewPath(aPipes.toArray(new MetaPipeEntity[0])); + aPreviousNode.mReturnPath = tConsumeNode.mNodePaths[tSideOp]; + tThisNode = tConsumeNode; + } + return tThisNode; + } + + //go over the pipes until we see a valid tile entity that needs a node + protected Pair getNextValidTileEntity(TileEntity aTileEntity, ArrayList<MetaPipeEntity> aPipes, byte aSide, HashSet<Node> aNodeMap) { + if (isPipe(aTileEntity)) { + BaseMetaPipeEntity tPipe = (BaseMetaPipeEntity) aTileEntity; + MetaPipeEntity tMetaPipe = (MetaPipeEntity) tPipe.getMetaTileEntity(); + Node tNode = tPipe.getNode(); + if (tNode != null) { + if (aNodeMap.contains(tNode)) + return null; + } + int tConnections = getNumberOfConnections(tMetaPipe); + if (tConnections == 2) { + byte tSideOp = getOppositeSide(aSide); + for (byte i = 0;i<6;i++) { + if (i == tSideOp || !(tMetaPipe.isConnectedAtSide(i))) continue; + TileEntity tNewTileEntity = tPipe.getTileEntityAtSide(i); + if (tNewTileEntity == null) continue; + if (isPipe(tNewTileEntity)) { + aPipes.add(tMetaPipe); + return getNextValidTileEntity(tNewTileEntity,aPipes,i,aNodeMap); + } else { + return new Pair(aTileEntity,i); + } + } + } else { + return new Pair(aTileEntity,aSide); + } + } else { + return new Pair(aTileEntity,aSide); + } + return null; + } + + private static class Pair { + public byte mSide; + public TileEntity mTileEntity; + public Pair(TileEntity aTileEntity, byte aSide) { + this.mTileEntity = aTileEntity; + this.mSide = aSide; + } + } + + //if check if the tile entity is the correct pipe + protected boolean isPipe(TileEntity aTileEntity) { + return aTileEntity instanceof BaseMetaPipeEntity; + } + //checks if the tile entity is a consumer and add to the list + abstract protected boolean addConsumer(TileEntity aTileEntity, byte aSide, int aNodeValue, ArrayList<ConsumerNode> aConsumers); + //get correct pathClass that you need for your node network + protected abstract NodePath getNewPath(MetaPipeEntity[] aPipes); + + //used for if you need to use death ends for something + //can be null + protected Node getEmptyNode(int aNodeValue, byte aSide, TileEntity aTileEntity, ArrayList<ConsumerNode> aConsumers) { + return null; + } + //get correct node type you need for your network + protected Node getPipeNode(int aNodeValue, byte aSide, TileEntity aTileEntity, ArrayList<ConsumerNode> aConsumers) { + return new Node(aNodeValue,aTileEntity,aConsumers); + } + + //get how many connections the pipe have + private static int getNumberOfConnections(MetaPipeEntity aPipe) { + int tCons = 0; + for (int i = 0; i < 6; i++) { + if (aPipe.isConnectedAtSide(i)) tCons++; + } + return tCons; + } +} diff --git a/src/main/java/gregtech/api/graphs/GenerateNodeMapPower.java b/src/main/java/gregtech/api/graphs/GenerateNodeMapPower.java new file mode 100644 index 0000000000..76a24e8802 --- /dev/null +++ b/src/main/java/gregtech/api/graphs/GenerateNodeMapPower.java @@ -0,0 +1,90 @@ +package gregtech.api.graphs; + +import cofh.api.energy.IEnergyReceiver; +import gregtech.api.GregTech_API; +import gregtech.api.graphs.consumers.*; +import gregtech.api.graphs.paths.NodePath; +import gregtech.api.graphs.paths.PowerNodePath; +import gregtech.api.interfaces.tileentity.IEnergyConnected; +import gregtech.api.metatileentity.BaseMetaPipeEntity; +import gregtech.api.metatileentity.BaseMetaTileEntity; +import gregtech.api.metatileentity.MetaPipeEntity; +import gregtech.api.metatileentity.implementations.GT_MetaPipeEntity_Cable; +import ic2.api.energy.tile.IEnergySink; +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.common.util.ForgeDirection; + +import java.util.ArrayList; +import java.util.HashSet; + +//node map generator for power distribution +public class GenerateNodeMapPower extends GenerateNodeMap { + public GenerateNodeMapPower(BaseMetaPipeEntity aTileEntity) { + generateNode(aTileEntity,null,1,null, + -1,new ArrayList<>(),new HashSet<>()); + } + + @Override + protected boolean isPipe(TileEntity aTileEntity) { + return super.isPipe(aTileEntity) && ((BaseMetaPipeEntity) aTileEntity).getMetaTileEntity() instanceof GT_MetaPipeEntity_Cable; + } + + @Override + protected NodePath getNewPath(MetaPipeEntity[] aPipes) { + return new PowerNodePath(aPipes); + } + + //used to apply voltage on death ends + @Override + protected Node getEmptyNode(int aNodeValue, byte aSide, TileEntity aTileEntity, ArrayList<ConsumerNode> aConsumers) { + Node tNode = new EmptyPowerConsumer(aNodeValue, aTileEntity, aSide, aConsumers); + aConsumers.add((ConsumerNode) tNode); + return tNode; + } + + @Override + protected Node getPipeNode(int aNodeValue, byte aSide, TileEntity aTileEntity, ArrayList<ConsumerNode> aConsumers) { + return new PowerNode(aNodeValue, aTileEntity, aConsumers); + } + + @Override + protected boolean addConsumer(TileEntity aTileEntity, byte aSide, int aNodeValue, ArrayList<ConsumerNode> aConsumers) { + if (aTileEntity instanceof BaseMetaTileEntity) { + BaseMetaTileEntity tBaseTileEntity = (BaseMetaTileEntity) aTileEntity; + if (tBaseTileEntity.inputEnergyFrom(aSide, false)) { + ConsumerNode tConsumerNode = new NodeGTBaseMetaTile(aNodeValue, tBaseTileEntity, aSide, aConsumers); + aConsumers.add(tConsumerNode); + return true; + } + + } else if (aTileEntity instanceof IEnergyConnected) { + IEnergyConnected tTileEntity = (IEnergyConnected) aTileEntity; + if (tTileEntity.inputEnergyFrom(aSide,false)) { + ConsumerNode tConsumerNode = new NodeEnergyConnected(aNodeValue,tTileEntity,aSide,aConsumers); + aConsumers.add(tConsumerNode); + return true; + } + } else if (aTileEntity instanceof IEnergySink) { + //ic2 wants the tilentitty next to it of that side not going to add a bunch of arguments just for ic2 + //crossborder checks to not not load chuncks just to make sure + int dX = aTileEntity.xCoord + ForgeDirection.getOrientation(aSide).offsetX; + int dY = aTileEntity.yCoord + ForgeDirection.getOrientation(aSide).offsetY; + int dZ = aTileEntity.zCoord + ForgeDirection.getOrientation(aSide).offsetZ; + boolean crossesChuncks = dX >> 4 != aTileEntity.xCoord >> 4 || dZ >> 4 != aTileEntity.zCoord >> 4; + TileEntity tNextTo = null; + if (!crossesChuncks || !aTileEntity.getWorldObj().blockExists(dX, dY, dZ)) + tNextTo = aTileEntity.getWorldObj().getTileEntity(dX, dY, dZ); + + if (((IEnergySink) aTileEntity).acceptsEnergyFrom(tNextTo, ForgeDirection.getOrientation(aSide))) { + ConsumerNode tConsumerNode = new NodeEnergySink(aNodeValue,(IEnergySink) aTileEntity, aSide, aConsumers); + aConsumers.add(tConsumerNode); + return true; + } + } else if (GregTech_API.mOutputRF && aTileEntity instanceof IEnergyReceiver) { + ConsumerNode tConsumerNode = new NodeEnergyReceiver(aNodeValue,(IEnergyReceiver) aTileEntity, aSide, aConsumers); + aConsumers.add(tConsumerNode); + return true; + } + return false; + } +} diff --git a/src/main/java/gregtech/api/graphs/Node.java b/src/main/java/gregtech/api/graphs/Node.java new file mode 100644 index 0000000000..258915e473 --- /dev/null +++ b/src/main/java/gregtech/api/graphs/Node.java @@ -0,0 +1,30 @@ +package gregtech.api.graphs; + +import gregtech.api.graphs.consumers.ConsumerNode; +import gregtech.api.graphs.paths.NodePath; +import net.minecraft.server.MinecraftServer; +import net.minecraft.tileentity.TileEntity; +import java.util.ArrayList; + +//base Node class +public class Node { + public Node(int aNodeValue,TileEntity aTileEntity,ArrayList<ConsumerNode> aConsumers){ + this.mNodeValue = aNodeValue; + this.mTileEntity = aTileEntity; + this.mConsumers = aConsumers; + mHighestNodeValue = aNodeValue; + //you don't want to generate map multiple times in the same tick + mCreationTime = MinecraftServer.getServer().getTickCounter(); + } + + + public int mCreationTime; + public NodePath mSelfPath; + public ArrayList<ConsumerNode> mConsumers; + public int mNodeValue; + public final TileEntity mTileEntity; + public Node[] mNeighbourNodes = new Node[6]; + public NodePath[] mNodePaths = new NodePath[6]; + public NodePath mReturnPath; + public int mHighestNodeValue; +} diff --git a/src/main/java/gregtech/api/graphs/NodeList.java b/src/main/java/gregtech/api/graphs/NodeList.java new file mode 100644 index 0000000000..36ebbc4f6f --- /dev/null +++ b/src/main/java/gregtech/api/graphs/NodeList.java @@ -0,0 +1,24 @@ +package gregtech.api.graphs; + +//keep track on which node is being looked for across the recursive functions +public class NodeList { + Node[] mNodes; + int mCounter = 0; + public NodeList(Node[] mNodes) { + this.mNodes = mNodes; + } + + Node getNextNode() { + if (++mCounter < mNodes.length) + return mNodes[mCounter]; + else + return null; + } + + Node getNode() { + if (mCounter < mNodes.length) + return mNodes[mCounter]; + else + return null; + } +} diff --git a/src/main/java/gregtech/api/graphs/PowerNode.java b/src/main/java/gregtech/api/graphs/PowerNode.java new file mode 100644 index 0000000000..a92e3ea0ca --- /dev/null +++ b/src/main/java/gregtech/api/graphs/PowerNode.java @@ -0,0 +1,14 @@ +package gregtech.api.graphs; + +import gregtech.api.graphs.consumers.ConsumerNode; +import net.minecraft.tileentity.TileEntity; + +import java.util.ArrayList; + +//base node for power networks +public class PowerNode extends Node{ + public boolean mHadVoltage = false; + public PowerNode(int aNodeValue, TileEntity aTileEntity, ArrayList<ConsumerNode> aConsumers) { + super(aNodeValue, aTileEntity, aConsumers); + } +} diff --git a/src/main/java/gregtech/api/graphs/PowerNodes.java b/src/main/java/gregtech/api/graphs/PowerNodes.java new file mode 100644 index 0000000000..411d690cca --- /dev/null +++ b/src/main/java/gregtech/api/graphs/PowerNodes.java @@ -0,0 +1,162 @@ +package gregtech.api.graphs; + +import gregtech.api.graphs.consumers.ConsumerNode; +import gregtech.api.graphs.paths.PowerNodePath; + +/* look for and power node that need power + * + * how this works + * + * a node only contains nodes that has a higher value then it self except for 1 which is the return node + * this node also contains the highest known node value of its network + * this network only includes nodes that have a higher value then it self so it does not know the highest known value that + * the return node knows + * + * with these rules we can know for the target node to be in the network of a node, the target node must have a value no + * less than the node we are looking and no greater than the highest value that node knows + * this way we don't have to go over the entire network to look for it + * + * we also hold a list of all consumers so we can check before looking if that consumer actually needs power + * and only look for nodes that actually need power + * + */ +public class PowerNodes { + //check if the looked for node is next to or get the next node that is closer to it + static public int powerNode(Node aCurrentNode, Node aPreviousNode, NodeList aConsumers, int aVoltage, int aMaxAmps) { + int tAmpsUsed = 0; + ConsumerNode tConsumer =(ConsumerNode) aConsumers.getNode(); + int tLoopProtection = 0; + while (tConsumer != null) { + int tTargetNodeValue = tConsumer.mNodeValue; + //if the target node has a value less then the current node + if (tTargetNodeValue < aCurrentNode.mNodeValue || tTargetNodeValue > aCurrentNode.mHighestNodeValue) { + for (int j = 0;j<6;j++) { + Node tNextNode = aCurrentNode.mNeighbourNodes[j]; + if (tNextNode != null && tNextNode.mNodeValue < aCurrentNode.mNodeValue) { + if (tNextNode.mNodeValue == tConsumer.mNodeValue) { + tAmpsUsed += processNodeInject(aCurrentNode,tConsumer,j,aMaxAmps-tAmpsUsed,aVoltage,false); + tConsumer =(ConsumerNode) aConsumers.getNextNode(); + break; + } else { + if (aPreviousNode == tNextNode) return tAmpsUsed; + tAmpsUsed += processNextNode(aCurrentNode,tNextNode,aConsumers,j,aMaxAmps-tAmpsUsed,aVoltage); + tConsumer =(ConsumerNode) aConsumers.getNode(); + break; + } + } + } + } else { + //if the target node has a node value greater then current node value + for (int side = 5;side>-1;side--) { + Node tNextNode = aCurrentNode.mNeighbourNodes[side]; + if (tNextNode == null) continue; + if (tNextNode.mNodeValue > aCurrentNode.mNodeValue && tNextNode.mNodeValue < tTargetNodeValue) { + if (tNextNode == aPreviousNode) return tAmpsUsed; + tAmpsUsed += processNextNodeAbove(aCurrentNode,tNextNode,aConsumers,side,aMaxAmps-tAmpsUsed,aVoltage); + tConsumer =(ConsumerNode) aConsumers.getNode(); + break; + } else if (tNextNode.mNodeValue == tTargetNodeValue) { + tAmpsUsed += processNodeInject(aCurrentNode,tConsumer,side,aMaxAmps-tAmpsUsed,aVoltage,true); + tConsumer =(ConsumerNode) aConsumers.getNextNode(); + break; + } + } + } + if (aMaxAmps - tAmpsUsed <= 0) { + return tAmpsUsed; + } + if (tLoopProtection++ > 20) { + throw new NullPointerException("infinite loop in powering nodes "); + } + } + return tAmpsUsed; + } + + //checking if target node is next to it or has a higher value then current node value + //these functions are different to either go down or up the stack + protected static int powerNodeAbove(Node aCurrentNode, Node aPreviousNode, NodeList aConsumers, int aVoltage, int aMaxAmps) { + int tAmpsUsed = 0; + int tLoopProtection = 0; + ConsumerNode tConsumer =(ConsumerNode) aConsumers.getNode(); + while (tConsumer != null) { + int tTargetNodeValue = tConsumer.mNodeValue; + if (tTargetNodeValue > aCurrentNode.mHighestNodeValue || tTargetNodeValue < aCurrentNode.mNodeValue) { + return tAmpsUsed; + } else { + for (int side = 5;side>-1;side--) { + Node tNextNode = aCurrentNode.mNeighbourNodes[side]; + if (tNextNode == null) continue; + if (tNextNode.mNodeValue > aCurrentNode.mNodeValue && tNextNode.mNodeValue < tTargetNodeValue) { + if (tNextNode == aPreviousNode) return tAmpsUsed; + tAmpsUsed += processNextNodeAbove(aCurrentNode,tNextNode,aConsumers,side,aMaxAmps-tAmpsUsed,aVoltage); + tConsumer =(ConsumerNode) aConsumers.getNode(); + break; + } else if (tNextNode.mNodeValue == tTargetNodeValue) { + tAmpsUsed += processNodeInject(aCurrentNode,tConsumer,side,aMaxAmps-tAmpsUsed,aVoltage,true); + tConsumer =(ConsumerNode) aConsumers.getNextNode(); + break; + } + } + } + if (aMaxAmps - tAmpsUsed <= 0) { + return tAmpsUsed; + } + if (tLoopProtection++ > 20) { + throw new NullPointerException("infinite loop in powering nodes "); + } + } + return tAmpsUsed; + } + + protected static int processNextNode(Node aCurrentNode, Node aNextNode, NodeList aConsumers, int aSide, int aMaxAmps, int aVoltage) { + PowerNodePath tPath = (PowerNodePath)aCurrentNode.mNodePaths[aSide]; + PowerNodePath tSelfPath = (PowerNodePath) aCurrentNode.mSelfPath; + int tVoltLoss = 0; + if (tSelfPath != null) { + tVoltLoss += tSelfPath.getLoss(); + tSelfPath.applyVoltage(aVoltage,false); + } + tPath.applyVoltage(aVoltage - tVoltLoss,true); + tVoltLoss += tPath.getLoss(); + int tAmps = powerNode(aNextNode,aCurrentNode,aConsumers,aVoltage - tVoltLoss,aMaxAmps ); + tPath.addAmps(tAmps); + if (tSelfPath != null) + tSelfPath.addAmps(tAmps); + return tAmps; + } + + protected static int processNextNodeAbove(Node aCurrentNode, Node aNextNode, NodeList aConsumers, int aSide, int aMaxAmps, int aVoltage) { + PowerNodePath tPath = (PowerNodePath)aCurrentNode.mNodePaths[aSide]; + PowerNodePath tSelfPath = (PowerNodePath) aCurrentNode.mSelfPath; + int tVoltLoss = 0; + if (tSelfPath != null) { + tVoltLoss += tSelfPath.getLoss(); + tSelfPath.applyVoltage(aVoltage,false); + } + tPath.applyVoltage(aVoltage - tVoltLoss,true); + tVoltLoss += tPath.getLoss(); + int tAmps = powerNodeAbove(aNextNode,aCurrentNode,aConsumers,aVoltage - tVoltLoss,aMaxAmps ); + tPath.addAmps(tAmps); + if (tSelfPath != null) + tSelfPath.addAmps(tAmps); + return tAmps; + } + + protected static int processNodeInject(Node aCurrentNode, ConsumerNode aConsumer, int aSide,int aMaxAmps, int aVoltage, + boolean isUp) { + PowerNodePath tPath = (PowerNodePath)aCurrentNode.mNodePaths[aSide]; + PowerNodePath tSelfPath = (PowerNodePath) aCurrentNode.mSelfPath; + int tVoltLoss = 0; + if (tSelfPath != null) { + tVoltLoss += tSelfPath.getLoss(); + tSelfPath.applyVoltage(aVoltage,false); + } + tPath.applyVoltage(aVoltage - tVoltLoss,true); + tVoltLoss += tPath.getLoss(); + int tAmps = aConsumer.injectEnergy(aVoltage - tVoltLoss,aMaxAmps); + tPath.addAmps(tAmps); + if (tSelfPath != null) + tSelfPath.addAmps(tAmps); + return tAmps; + } +} diff --git a/src/main/java/gregtech/api/graphs/consumers/ConsumerNode.java b/src/main/java/gregtech/api/graphs/consumers/ConsumerNode.java new file mode 100644 index 0000000000..87376008c4 --- /dev/null +++ b/src/main/java/gregtech/api/graphs/consumers/ConsumerNode.java @@ -0,0 +1,23 @@ +package gregtech.api.graphs.consumers; + +import gregtech.api.graphs.Node; +import net.minecraft.tileentity.TileEntity; + +import java.util.ArrayList; + +//node attached to a tile entity that can consume stuff from the network +public class ConsumerNode extends Node { + public byte mSide; + public ConsumerNode(int aNodeValue, TileEntity aTileEntity, byte aSide, ArrayList<ConsumerNode> aConsumers) { + super(aNodeValue,aTileEntity,aConsumers); + this.mSide = aSide; + } + + public boolean needsEnergy() { + return !mTileEntity.isInvalid(); + } + + public int injectEnergy(int aVoltage, int aMaxAmps) { + return 0; + } +} diff --git a/src/main/java/gregtech/api/graphs/consumers/EmptyPowerConsumer.java b/src/main/java/gregtech/api/graphs/consumers/EmptyPowerConsumer.java new file mode 100644 index 0000000000..da3d0a757b --- /dev/null +++ b/src/main/java/gregtech/api/graphs/consumers/EmptyPowerConsumer.java @@ -0,0 +1,27 @@ +package gregtech.api.graphs.consumers; + +import gregtech.api.graphs.paths.PowerNodePath; +import gregtech.api.metatileentity.BaseMetaPipeEntity; +import net.minecraft.tileentity.TileEntity; + +import java.util.ArrayList; + +//this is here to apply voltage to death ends +public class EmptyPowerConsumer extends ConsumerNode{ + public EmptyPowerConsumer(int aNodeValue, TileEntity aTileEntity, byte aSide, ArrayList<ConsumerNode> aConsumers) { + super(aNodeValue, aTileEntity, aSide, aConsumers); + } + + @Override + public boolean needsEnergy() { + return false; + } + + @Override + public int injectEnergy(int aVoltage, int aMaxAmps) { + BaseMetaPipeEntity tPipe = (BaseMetaPipeEntity) mTileEntity; + PowerNodePath tPath =(PowerNodePath) tPipe.getNodePath(); + tPath.applyVoltage(aVoltage,true); + return 0; + } +} diff --git a/src/main/java/gregtech/api/graphs/consumers/NodeEnergyConnected.java b/src/main/java/gregtech/api/graphs/consumers/NodeEnergyConnected.java new file mode 100644 index 0000000000..baff232d94 --- /dev/null +++ b/src/main/java/gregtech/api/graphs/consumers/NodeEnergyConnected.java @@ -0,0 +1,22 @@ +package gregtech.api.graphs.consumers; + +import gregtech.api.interfaces.tileentity.IEnergyConnected; +import net.minecraft.tileentity.TileEntity; + +import java.util.ArrayList; + +public class NodeEnergyConnected extends ConsumerNode { + public NodeEnergyConnected(int aNodeValue, IEnergyConnected aTileEntity, byte aSide, ArrayList<ConsumerNode> aConsumers) { + super(aNodeValue,(TileEntity) aTileEntity, aSide, aConsumers); + } + + @Override + public boolean needsEnergy() { + return super.needsEnergy(); + } + + @Override + public int injectEnergy(int aVoltage, int aMaxAmps) { + return (int) ((IEnergyConnected)mTileEntity).injectEnergyUnits(mSide,aVoltage,aMaxAmps); + } +} diff --git a/src/main/java/gregtech/api/graphs/consumers/NodeEnergyReceiver.java b/src/main/java/gregtech/api/graphs/consumers/NodeEnergyReceiver.java new file mode 100644 index 0000000000..a24c4acbcd --- /dev/null +++ b/src/main/java/gregtech/api/graphs/consumers/NodeEnergyReceiver.java @@ -0,0 +1,86 @@ +package gregtech.api.graphs.consumers; + +import cofh.api.energy.IEnergyReceiver; +import gregtech.GT_Mod; +import gregtech.api.GregTech_API; +import gregtech.api.util.GT_Utility; +import gregtech.api.util.WorldSpawnedEventBuilder; +import gregtech.common.GT_Pollution; +import net.minecraft.init.Blocks; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; +import net.minecraftforge.common.util.ForgeDirection; + +import java.util.ArrayList; + +import static gregtech.api.enums.GT_Values.V; + +//consumer for RF machines +public class NodeEnergyReceiver extends ConsumerNode { + int mRestRF = 0; + public NodeEnergyReceiver(int aNodeValue, IEnergyReceiver aTileEntity, byte aSide, ArrayList<ConsumerNode> aConsumers) { + super(aNodeValue, (TileEntity) aTileEntity, aSide, aConsumers); + } + + @Override + public int injectEnergy(int aVoltage, int aMaxAmps) { + ForgeDirection tDirection = ForgeDirection.getOrientation(mSide); + int rfOut = GT_Utility.safeInt(aVoltage * GregTech_API.mEUtoRF / 100); + int ampsUsed = 0; + if (mRestRF < rfOut) { + mRestRF += rfOut; + ampsUsed = 1; + } + if (((IEnergyReceiver) mTileEntity).receiveEnergy(tDirection, mRestRF, true) > 0) { + int consumed = ((IEnergyReceiver) mTileEntity).receiveEnergy(tDirection, mRestRF, false); + mRestRF -= consumed; + return ampsUsed; + } + if (GregTech_API.mRFExplosions && GregTech_API.sMachineExplosions && + ((IEnergyReceiver) mTileEntity).getMaxEnergyStored(tDirection) < rfOut * 600L) { + explode(rfOut); + } + return 0; + } + + //copied from IEnergyConnected + private void explode(int aRfOut) { + if (aRfOut > 32L * GregTech_API.mEUtoRF / 100L) { + int aExplosionPower = aRfOut; + float tStrength = + aExplosionPower < V[0] ? 1.0F : + aExplosionPower < V[1] ? 2.0F : + aExplosionPower < V[2] ? 3.0F : + aExplosionPower < V[3] ? 4.0F : + aExplosionPower < V[4] ? 5.0F : + aExplosionPower < V[4] * 2 ? 6.0F : + aExplosionPower < V[5] ? 7.0F : + aExplosionPower < V[6] ? 8.0F : + aExplosionPower < V[7] ? 9.0F : + aExplosionPower < V[8] ? 10.0F : + aExplosionPower < V[8] * 2 ? 11.0F : + aExplosionPower < V[9] ? 12.0F : + aExplosionPower < V[10] ? 13.0F : + aExplosionPower < V[11] ? 14.0F : + aExplosionPower < V[12] ? 15.0F : + aExplosionPower < V[12] * 2 ? 16.0F : + aExplosionPower < V[13] ? 17.0F : + aExplosionPower < V[14] ? 18.0F : + aExplosionPower < V[15] ? 19.0F : 20.0F; + int tX = mTileEntity.xCoord, tY = mTileEntity.yCoord, tZ = mTileEntity.zCoord; + World tWorld = mTileEntity.getWorldObj(); + GT_Utility.sendSoundToPlayers(tWorld, GregTech_API.sSoundList.get(209), 1.0F, -1, tX, tY, tZ); + tWorld.setBlock(tX, tY, tZ, Blocks.air); + if (GregTech_API.sMachineExplosions) + if (GT_Mod.gregtechproxy.mPollution) + GT_Pollution.addPollution(tWorld.getChunkFromBlockCoords(tX, tZ), 100000); + + new WorldSpawnedEventBuilder.ExplosionEffectEventBuilder() + .setStrength(tStrength) + .setSmoking(true) + .setPosition(tX + 0.5, tY + 0.5, tZ + 0.5) + .setWorld(tWorld) + .run(); + } + } +} diff --git a/src/main/java/gregtech/api/graphs/consumers/NodeEnergySink.java b/src/main/java/gregtech/api/graphs/consumers/NodeEnergySink.java new file mode 100644 index 0000000000..3f93c62010 --- /dev/null +++ b/src/main/java/gregtech/api/graphs/consumers/NodeEnergySink.java @@ -0,0 +1,28 @@ +package gregtech.api.graphs.consumers; + +import ic2.api.energy.tile.IEnergySink; +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.common.util.ForgeDirection; + +import java.util.ArrayList; + +//consumer for IC2 machines +public class NodeEnergySink extends ConsumerNode { + public NodeEnergySink(int nodeValue, IEnergySink tileEntity, byte side, ArrayList<ConsumerNode> consumers) { + super(nodeValue, (TileEntity) tileEntity, side, consumers); + } + + @Override + public boolean needsEnergy() { + return super.needsEnergy() && ((IEnergySink) mTileEntity).getDemandedEnergy() > 0; + } + + @Override + public int injectEnergy(int aVoltage, int aMaxAmps) { + int tUsedAmps = 0; + while (aMaxAmps > tUsedAmps && ((IEnergySink) mTileEntity).getDemandedEnergy() > 0 && + ((IEnergySink) mTileEntity).injectEnergy(ForgeDirection.getOrientation(mSide), aVoltage, aVoltage) < aVoltage) + tUsedAmps++; + return tUsedAmps; + } +} diff --git a/src/main/java/gregtech/api/graphs/consumers/NodeGTBaseMetaTile.java b/src/main/java/gregtech/api/graphs/consumers/NodeGTBaseMetaTile.java new file mode 100644 index 0000000000..5c54ee16f9 --- /dev/null +++ b/src/main/java/gregtech/api/graphs/consumers/NodeGTBaseMetaTile.java @@ -0,0 +1,23 @@ +package gregtech.api.graphs.consumers; + +import gregtech.api.interfaces.tileentity.IEnergyConnected; +import gregtech.api.metatileentity.BaseMetaTileEntity; +import java.util.ArrayList; + +//consumer for gt machines +public class NodeGTBaseMetaTile extends ConsumerNode { + public NodeGTBaseMetaTile(int aNodeValue, BaseMetaTileEntity aTileEntity, byte aSide, ArrayList<ConsumerNode> aConsumers) { + super(aNodeValue, aTileEntity, aSide, aConsumers); + } + + @Override + public int injectEnergy(int aVoltage, int aMaxAmps) { + return (int)((IEnergyConnected) mTileEntity).injectEnergyUnits(mSide,aVoltage, aMaxAmps); + } + + @Override + public boolean needsEnergy() { + BaseMetaTileEntity tTileEntity = (BaseMetaTileEntity) mTileEntity; + return super.needsEnergy() && tTileEntity.getStoredEU() < tTileEntity.getEUCapacity(); + } +} diff --git a/src/main/java/gregtech/api/graphs/paths/NodePath.java b/src/main/java/gregtech/api/graphs/paths/NodePath.java new file mode 100644 index 0000000000..ddbd570af3 --- /dev/null +++ b/src/main/java/gregtech/api/graphs/paths/NodePath.java @@ -0,0 +1,29 @@ +package gregtech.api.graphs.paths; + +import gregtech.api.metatileentity.BaseMetaPipeEntity; +import gregtech.api.metatileentity.MetaPipeEntity; + +//to contain all info about the path between nodes +public class NodePath { + protected MetaPipeEntity[] mPipes; + + public NodePath(MetaPipeEntity[] aCables) { + this.mPipes = aCables; + processPipes(); + } + + public void clearPath() { + for (int i = 0; i< mPipes.length; i++) { + BaseMetaPipeEntity tBasePipe = (BaseMetaPipeEntity) mPipes[i].getBaseMetaTileEntity(); + if (tBasePipe != null) { + tBasePipe.setNodePath(null); + } + } + } + protected void processPipes() { + for (MetaPipeEntity tPipe : mPipes) { + BaseMetaPipeEntity basePipe = (BaseMetaPipeEntity) tPipe.getBaseMetaTileEntity(); + basePipe.setNodePath(this); + } + } +} diff --git a/src/main/java/gregtech/api/graphs/paths/PowerNodePath.java b/src/main/java/gregtech/api/graphs/paths/PowerNodePath.java new file mode 100644 index 0000000000..a91f9b10a8 --- /dev/null +++ b/src/main/java/gregtech/api/graphs/paths/PowerNodePath.java @@ -0,0 +1,112 @@ +package gregtech.api.graphs.paths; + +import gregtech.api.metatileentity.BaseMetaPipeEntity; +import gregtech.api.metatileentity.MetaPipeEntity; +import gregtech.api.metatileentity.implementations.GT_MetaPipeEntity_Cable; +import net.minecraft.server.MinecraftServer; + +//path for cables +//all calculations like amp and voltage happens here +public class PowerNodePath extends NodePath { + int mMaxAmps; + int mAmps = 0; + int mLoss; + int mVoltage = 0; + int mMaxVoltage; + int mTick = 0; + boolean mCountUp = true; + + + public PowerNodePath(MetaPipeEntity[] aCables) { + super(aCables); + } + + public int getLoss() { + return mLoss; + } + + public void applyVoltage(int aVoltage, boolean aCountUp) { + int tNewTime = MinecraftServer.getServer().getTickCounter(); + if (mTick != tNewTime) { + reset(tNewTime - mTick); + mTick = tNewTime; + this.mVoltage = aVoltage; + this.mCountUp = aCountUp; + } else if (this.mCountUp != aCountUp && (aVoltage - mLoss)> this.mVoltage || aVoltage > this.mVoltage){ + this.mCountUp = aCountUp; + this.mVoltage = aVoltage; + } + if (aVoltage > mMaxVoltage) { + for (MetaPipeEntity tCable : mPipes) { + if (((GT_MetaPipeEntity_Cable)tCable).mVoltage < this.mVoltage) { + BaseMetaPipeEntity tBaseCable = (BaseMetaPipeEntity) tCable.getBaseMetaTileEntity(); + tBaseCable.setToFire(); + } + } + } + } + + public void addAmps(int aAmps) { + this.mAmps += aAmps; + if (this.mAmps > mMaxAmps * 40) { + for (MetaPipeEntity tCable : mPipes) { + if (((GT_MetaPipeEntity_Cable)tCable).mAmperage*40 < this.mAmps) { + BaseMetaPipeEntity tBaseCable = (BaseMetaPipeEntity) tCable.getBaseMetaTileEntity(); + if (tBaseCable != null) + tBaseCable.setToFire(); + } + } + } + } + + //if no amps pass trough for more then 0.5 second reduce them to minimize wrong results + //but still allow the player to see if activity is happening + public int getAmps() { + int tTime = MinecraftServer.getServer().getTickCounter() - 10; + if (mTick < tTime) { + reset(tTime - mTick); + mTick = tTime; + } + return mAmps; + } + + public int getVoltage(MetaPipeEntity aCable) { + int tLoss = 0; + if (mCountUp) { + for (int i = 0; i < mPipes.length; i++) { + GT_MetaPipeEntity_Cable tCable = (GT_MetaPipeEntity_Cable) mPipes[i]; + tLoss += tCable.mCableLossPerMeter; + if (aCable == tCable) { + return Math.max(mVoltage - tLoss, 0); + } + } + } else { + for (int i = mPipes.length - 1; i >= 0; i--) { + GT_MetaPipeEntity_Cable tCable = (GT_MetaPipeEntity_Cable) mPipes[i]; + tLoss += tCable.mCableLossPerMeter; + if (aCable == tCable) { + return Math.max(mVoltage - tLoss, 0); + } + } + } + return -1; + } + + private void reset(int aTimePassed) { + mAmps = Math.max(0, mAmps - (mMaxAmps * aTimePassed)); + } + + @Override + protected void processPipes() { + super.processPipes(); + mMaxAmps = Integer.MAX_VALUE; + mMaxVoltage = Integer.MAX_VALUE; + for (MetaPipeEntity tCable : mPipes) { + if (tCable instanceof GT_MetaPipeEntity_Cable) { + mMaxAmps = Math.min((int)((GT_MetaPipeEntity_Cable) tCable).mAmperage, mMaxAmps); + mLoss += (int)((GT_MetaPipeEntity_Cable) tCable).mCableLossPerMeter; + mMaxVoltage = Math.min((int)((GT_MetaPipeEntity_Cable) tCable).mVoltage, mMaxVoltage); + } + } + } +} |