aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/gregtech/api/graphs
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/gregtech/api/graphs')
-rw-r--r--src/main/java/gregtech/api/graphs/GenerateNodeMap.java202
-rw-r--r--src/main/java/gregtech/api/graphs/GenerateNodeMapPower.java104
-rw-r--r--src/main/java/gregtech/api/graphs/Lock.java38
-rw-r--r--src/main/java/gregtech/api/graphs/Node.java40
-rw-r--r--src/main/java/gregtech/api/graphs/NodeList.java22
-rw-r--r--src/main/java/gregtech/api/graphs/PowerNode.java17
-rw-r--r--src/main/java/gregtech/api/graphs/PowerNodes.java182
-rw-r--r--src/main/java/gregtech/api/graphs/consumers/ConsumerNode.java30
-rw-r--r--src/main/java/gregtech/api/graphs/consumers/EmptyPowerConsumer.java31
-rw-r--r--src/main/java/gregtech/api/graphs/consumers/NodeEnergyConnected.java21
-rw-r--r--src/main/java/gregtech/api/graphs/consumers/NodeEnergyReceiver.java68
-rw-r--r--src/main/java/gregtech/api/graphs/consumers/NodeEnergySink.java30
-rw-r--r--src/main/java/gregtech/api/graphs/consumers/NodeGTBaseMetaTile.java28
-rw-r--r--src/main/java/gregtech/api/graphs/paths/NodePath.java42
-rw-r--r--src/main/java/gregtech/api/graphs/paths/PowerNodePath.java153
15 files changed, 1008 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..7289f0faad
--- /dev/null
+++ b/src/main/java/gregtech/api/graphs/GenerateNodeMap.java
@@ -0,0 +1,202 @@
+package gregtech.api.graphs;
+
+import static gregtech.api.enums.GT_Values.ALL_VALID_SIDES;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+
+import net.minecraft.tileentity.TileEntity;
+import net.minecraftforge.common.util.ForgeDirection;
+
+import gregtech.api.graphs.consumers.ConsumerNode;
+import gregtech.api.graphs.paths.NodePath;
+import gregtech.api.metatileentity.BaseMetaPipeEntity;
+import gregtech.api.metatileentity.MetaPipeEntity;
+
+// generates the node map
+public abstract 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 tPipe) {
+ tPipe.setNode(null);
+ tPipe.setNodePath(null);
+ if (aNode.mSelfPath != null) {
+ aNode.mSelfPath.clearPath();
+ aNode.mSelfPath = null;
+ }
+ }
+ for (byte side : ALL_VALID_SIDES) {
+ final NodePath tPath = aNode.mNodePaths[side];
+ if (tPath != null) {
+ tPath.clearPath();
+ aNode.mNodePaths[side] = null;
+ }
+ final Node tNextNode = aNode.mNeighbourNodes[side];
+ if (tNextNode == null) continue;
+ if (tNextNode.mNodeValue != aReturnNodeValue) clearNodeMap(tNextNode, aNode.mNodeValue);
+ aNode.mNeighbourNodes[side] = null;
+ }
+ }
+
+ // get how many connections the pipe have
+ private static int getNumberOfConnections(MetaPipeEntity aPipe) {
+ int tCons = 0;
+ for (final ForgeDirection side : ForgeDirection.VALID_DIRECTIONS) {
+ if (aPipe.isConnectedAtSide(side)) tCons++;
+ }
+ return tCons;
+ }
+
+ // gets the next node
+ protected void generateNextNode(BaseMetaPipeEntity aPipe, Node aPipeNode, ForgeDirection aInvalidSide,
+ int aNextNodeValue, ArrayList<ConsumerNode> tConsumers, HashSet<Node> tNodeMap) {
+ final MetaPipeEntity tMetaPipe = (MetaPipeEntity) aPipe.getMetaTileEntity();
+ for (final ForgeDirection side : ForgeDirection.VALID_DIRECTIONS) {
+ if (side == aInvalidSide) {
+ continue;
+ }
+ final TileEntity tNextTileEntity = aPipe.getTileEntityAtSide(side);
+ if (tNextTileEntity == null || (tMetaPipe != null && !tMetaPipe.isConnectedAtSide(side))) continue;
+ final ArrayList<MetaPipeEntity> tNewPipes = new ArrayList<>();
+ final Pair nextTileEntity = getNextValidTileEntity(tNextTileEntity, tNewPipes, side, tNodeMap);
+ if (nextTileEntity != null) {
+ final Node tNextNode = generateNode(
+ nextTileEntity.mTileEntity,
+ aPipeNode,
+ aNextNodeValue + 1,
+ tNewPipes,
+ nextTileEntity.mSide,
+ tConsumers,
+ tNodeMap);
+ if (tNextNode != null) {
+ final int i = side.ordinal();
+ aNextNodeValue = tNextNode.mHighestNodeValue;
+ aPipeNode.mHighestNodeValue = tNextNode.mHighestNodeValue;
+ aPipeNode.mNeighbourNodes[i] = tNextNode;
+ aPipeNode.mNodePaths[i] = aPipeNode.returnValues.mReturnPath;
+ aPipeNode.locks[i] = aPipeNode.returnValues.returnLock;
+ aPipeNode.mNodePaths[i].reloadLocks();
+ }
+ }
+ }
+ aPipe.reloadLocks();
+ }
+
+ // on a valid tile entity create a new node
+ protected Node generateNode(TileEntity aTileEntity, Node aPreviousNode, int aNextNodeValue,
+ ArrayList<MetaPipeEntity> aPipes, ForgeDirection side, ArrayList<ConsumerNode> aConsumers,
+ HashSet<Node> aNodeMap) {
+ if (aTileEntity.isInvalid()) return null;
+ final ForgeDirection oppositeSide = side.getOpposite();
+ final ForgeDirection tInvalidSide = aPreviousNode == null ? ForgeDirection.UNKNOWN : oppositeSide;
+ Node tThisNode = null;
+ if (isPipe(aTileEntity)) {
+ final BaseMetaPipeEntity tPipe = (BaseMetaPipeEntity) aTileEntity;
+ final MetaPipeEntity tMetaPipe = (MetaPipeEntity) tPipe.getMetaTileEntity();
+ final int tConnections = getNumberOfConnections(tMetaPipe);
+ final Node tPipeNode;
+ if (tConnections == 1) {
+ tPipeNode = getEmptyNode(aNextNodeValue, oppositeSide, aTileEntity, aConsumers);
+ if (tPipeNode == null) return null;
+ } else {
+ tPipeNode = getPipeNode(aNextNodeValue, oppositeSide, aTileEntity, aConsumers);
+ }
+ tPipe.setNode(tPipeNode);
+ aNodeMap.add(tPipeNode);
+ tPipeNode.mSelfPath = getNewPath(new MetaPipeEntity[] { tMetaPipe });
+ tThisNode = tPipeNode;
+ if (tInvalidSide != ForgeDirection.UNKNOWN) {
+ final int iInvalid = tInvalidSide.ordinal();
+ tPipeNode.mNeighbourNodes[iInvalid] = aPreviousNode;
+ tPipeNode.mNodePaths[iInvalid] = getNewPath(aPipes.toArray(new MetaPipeEntity[0]));
+ final Lock lock = new Lock();
+ tPipeNode.mNodePaths[oppositeSide.ordinal()].lock = lock;
+ tPipeNode.locks[iInvalid] = lock;
+ aPreviousNode.returnValues.mReturnPath = tPipeNode.mNodePaths[iInvalid];
+ aPreviousNode.returnValues.returnLock = lock;
+ }
+ if (tConnections > 1)
+ generateNextNode(tPipe, tPipeNode, tInvalidSide, aNextNodeValue, aConsumers, aNodeMap);
+ } else if (addConsumer(aTileEntity, oppositeSide, aNextNodeValue, aConsumers)) {
+ final int oppositeSideOrdinal = oppositeSide.ordinal();
+ final ConsumerNode tConsumeNode = aConsumers.get(aConsumers.size() - 1);
+ tConsumeNode.mNeighbourNodes[oppositeSideOrdinal] = aPreviousNode;
+ tConsumeNode.mNodePaths[oppositeSideOrdinal] = getNewPath(aPipes.toArray(new MetaPipeEntity[0]));
+ final Lock lock = new Lock();
+ tConsumeNode.mNodePaths[oppositeSideOrdinal].lock = lock;
+ aPreviousNode.returnValues.mReturnPath = tConsumeNode.mNodePaths[oppositeSideOrdinal];
+ aPreviousNode.returnValues.returnLock = lock;
+ 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, ForgeDirection side,
+ HashSet<Node> aNodeMap) {
+ if (isPipe(aTileEntity)) {
+ final BaseMetaPipeEntity tPipe = (BaseMetaPipeEntity) aTileEntity;
+ final MetaPipeEntity tMetaPipe = (MetaPipeEntity) tPipe.getMetaTileEntity();
+ final Node tNode = tPipe.getNode();
+ if (tNode != null) {
+ if (aNodeMap.contains(tNode)) return null;
+ }
+ final int tConnections = getNumberOfConnections(tMetaPipe);
+ if (tConnections == 2) {
+ final ForgeDirection tSideOp = side.getOpposite();
+ for (final ForgeDirection s : ForgeDirection.VALID_DIRECTIONS) {
+ if (s == tSideOp || !(tMetaPipe.isConnectedAtSide(s))) continue;
+ final TileEntity tNewTileEntity = tPipe.getTileEntityAtSide(s);
+ if (tNewTileEntity == null) continue;
+ if (isPipe(tNewTileEntity)) {
+ aPipes.add(tMetaPipe);
+ return getNextValidTileEntity(tNewTileEntity, aPipes, s, aNodeMap);
+ } else {
+ return new Pair(aTileEntity, s);
+ }
+ }
+ } else {
+ return new Pair(aTileEntity, side);
+ }
+ } else {
+ return new Pair(aTileEntity, side);
+ }
+ return null;
+ }
+
+ // 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
+ protected abstract boolean addConsumer(TileEntity aTileEntity, ForgeDirection side, 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 dead ends for something can be null
+ protected Node getEmptyNode(int aNodeValue, ForgeDirection side, TileEntity aTileEntity,
+ ArrayList<ConsumerNode> aConsumers) {
+ return null;
+ }
+
+ // get correct node type you need for your network
+ protected Node getPipeNode(int aNodeValue, ForgeDirection side, TileEntity aTileEntity,
+ ArrayList<ConsumerNode> aConsumers) {
+ return new Node(aNodeValue, aTileEntity, aConsumers);
+ }
+
+ private static class Pair {
+
+ public ForgeDirection mSide;
+ public TileEntity mTileEntity;
+
+ public Pair(TileEntity aTileEntity, ForgeDirection side) {
+ this.mTileEntity = aTileEntity;
+ this.mSide = side;
+ }
+ }
+}
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..95f9aee32d
--- /dev/null
+++ b/src/main/java/gregtech/api/graphs/GenerateNodeMapPower.java
@@ -0,0 +1,104 @@
+package gregtech.api.graphs;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+
+import net.minecraft.tileentity.TileEntity;
+import net.minecraftforge.common.util.ForgeDirection;
+
+import cofh.api.energy.IEnergyReceiver;
+import gregtech.api.GregTech_API;
+import gregtech.api.graphs.consumers.ConsumerNode;
+import gregtech.api.graphs.consumers.EmptyPowerConsumer;
+import gregtech.api.graphs.consumers.NodeEnergyConnected;
+import gregtech.api.graphs.consumers.NodeEnergyReceiver;
+import gregtech.api.graphs.consumers.NodeEnergySink;
+import gregtech.api.graphs.consumers.NodeGTBaseMetaTile;
+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;
+
+// node map generator for power distribution
+public class GenerateNodeMapPower extends GenerateNodeMap {
+
+ public GenerateNodeMapPower(BaseMetaPipeEntity aTileEntity) {
+ generateNode(aTileEntity, null, 1, null, ForgeDirection.UNKNOWN, new ArrayList<>(), new HashSet<>());
+ }
+
+ @Override
+ protected boolean isPipe(TileEntity aTileEntity) {
+ return super.isPipe(aTileEntity)
+ && ((BaseMetaPipeEntity) aTileEntity).getMetaTileEntity() instanceof GT_MetaPipeEntity_Cable;
+ }
+
+ @Override
+ protected boolean addConsumer(TileEntity aTileEntity, ForgeDirection side, int aNodeValue,
+ ArrayList<ConsumerNode> aConsumers) {
+ if (aTileEntity instanceof BaseMetaTileEntity tBaseTileEntity) {
+ if (tBaseTileEntity.inputEnergyFrom(side, false)) {
+ ConsumerNode tConsumerNode = new NodeGTBaseMetaTile(aNodeValue, tBaseTileEntity, side, aConsumers);
+ aConsumers.add(tConsumerNode);
+ return true;
+ }
+
+ } else if (aTileEntity instanceof IEnergyConnected tTileEntity) {
+ if (tTileEntity.inputEnergyFrom(side, false)) {
+ ConsumerNode tConsumerNode = new NodeEnergyConnected(aNodeValue, tTileEntity, side, aConsumers);
+ aConsumers.add(tConsumerNode);
+ return true;
+ }
+ } else if (aTileEntity instanceof IEnergySink sink) {
+ // ic2 wants the tilentity next to it of that side not going to add a bunch of arguments just for ic2
+ // crossborder checks to not load chuncks just to make sure
+ int dX = aTileEntity.xCoord + side.offsetX;
+ int dY = aTileEntity.yCoord + side.offsetY;
+ int dZ = aTileEntity.zCoord + side.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 (sink.acceptsEnergyFrom(tNextTo, side)) {
+ ConsumerNode tConsumerNode = new NodeEnergySink(
+ aNodeValue,
+ (IEnergySink) aTileEntity,
+ side,
+ aConsumers);
+ aConsumers.add(tConsumerNode);
+ return true;
+ }
+ } else if (GregTech_API.mOutputRF && aTileEntity instanceof IEnergyReceiver receiver) {
+ ConsumerNode tConsumerNode = new NodeEnergyReceiver(aNodeValue, receiver, side, aConsumers);
+ aConsumers.add(tConsumerNode);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ protected NodePath getNewPath(MetaPipeEntity[] aPipes) {
+ return new PowerNodePath(aPipes);
+ }
+
+ // used to apply voltage on dead ends
+ @Override
+ protected Node getEmptyNode(int aNodeValue, ForgeDirection side, TileEntity aTileEntity,
+ ArrayList<ConsumerNode> aConsumers) {
+ ConsumerNode tNode = new EmptyPowerConsumer(aNodeValue, aTileEntity, side, aConsumers);
+ aConsumers.add(tNode);
+ return tNode;
+ }
+
+ @Override
+ protected Node getPipeNode(int aNodeValue, ForgeDirection side, TileEntity aTileEntity,
+ ArrayList<ConsumerNode> aConsumers) {
+ return new PowerNode(aNodeValue, aTileEntity, aConsumers);
+ }
+}
diff --git a/src/main/java/gregtech/api/graphs/Lock.java b/src/main/java/gregtech/api/graphs/Lock.java
new file mode 100644
index 0000000000..d3c8c49169
--- /dev/null
+++ b/src/main/java/gregtech/api/graphs/Lock.java
@@ -0,0 +1,38 @@
+package gregtech.api.graphs;
+
+import java.util.ArrayList;
+
+import net.minecraft.tileentity.TileEntity;
+
+public class Lock {
+
+ protected ArrayList<TileEntity> tiles = new ArrayList<>();
+
+ public void addTileEntity(TileEntity tileEntity) {
+ int i = contains(tileEntity);
+ if (i == -1) {
+ tiles.add(tileEntity);
+ }
+ }
+
+ public void removeTileEntity(TileEntity tileEntity) {
+ int i = contains(tileEntity);
+ if (i > -1) {
+ tiles.remove(i);
+ }
+ }
+
+ public boolean isLocked() {
+ return !tiles.isEmpty();
+ }
+
+ // i want to check for the exact object not equals
+ protected int contains(TileEntity tileEntity) {
+ for (int i = 0; i < tiles.size(); i++) {
+ if (tiles.get(i) == tileEntity) {
+ return i;
+ }
+ }
+ return -1;
+ }
+}
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..9afe009d3e
--- /dev/null
+++ b/src/main/java/gregtech/api/graphs/Node.java
@@ -0,0 +1,40 @@
+package gregtech.api.graphs;
+
+import java.util.ArrayList;
+
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.tileentity.TileEntity;
+
+import gregtech.api.graphs.consumers.ConsumerNode;
+import gregtech.api.graphs.paths.NodePath;
+
+// 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 final TileEntity mTileEntity;
+ public Node[] mNeighbourNodes = new Node[6];
+ public NodePath[] mNodePaths = new NodePath[6];
+ public Lock[] locks = new Lock[6];
+ public ReturnPair returnValues = new ReturnPair();
+ public NodePath mSelfPath;
+ public ArrayList<ConsumerNode> mConsumers;
+ public int mCreationTime;
+ public int mNodeValue;
+ public int mHighestNodeValue;
+
+ public static class ReturnPair {
+
+ public NodePath mReturnPath;
+ public Lock returnLock;
+ }
+}
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..899384b3d4
--- /dev/null
+++ b/src/main/java/gregtech/api/graphs/NodeList.java
@@ -0,0 +1,22 @@
+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..75a8e8d73b
--- /dev/null
+++ b/src/main/java/gregtech/api/graphs/PowerNode.java
@@ -0,0 +1,17 @@
+package gregtech.api.graphs;
+
+import java.util.ArrayList;
+
+import net.minecraft.tileentity.TileEntity;
+
+import gregtech.api.graphs.consumers.ConsumerNode;
+
+// 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..98d35e2971
--- /dev/null
+++ b/src/main/java/gregtech/api/graphs/PowerNodes.java
@@ -0,0 +1,182 @@
+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
+ public static long powerNode(Node aCurrentNode, Node aPreviousNode, NodeList aConsumers, long aVoltage,
+ long aMaxAmps) {
+ long 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++) {
+ final 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);
+ tConsumer = (ConsumerNode) aConsumers.getNextNode();
+ } 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--) {
+ final 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);
+ 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 long powerNodeAbove(Node aCurrentNode, Node aPreviousNode, NodeList aConsumers, long aVoltage,
+ long aMaxAmps) {
+ long 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--) {
+ final 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);
+ 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 long processNextNode(Node aCurrentNode, Node aNextNode, NodeList aConsumers, int ordinalSide,
+ long aMaxAmps, long aVoltage) {
+ if (aCurrentNode.locks[ordinalSide].isLocked()) {
+ aConsumers.getNextNode();
+ return 0;
+ }
+ final PowerNodePath tPath = (PowerNodePath) aCurrentNode.mNodePaths[ordinalSide];
+ final PowerNodePath tSelfPath = (PowerNodePath) aCurrentNode.mSelfPath;
+ long tVoltLoss = 0;
+ if (tSelfPath != null) {
+ tVoltLoss += tSelfPath.getLoss();
+ tSelfPath.applyVoltage(aVoltage, false);
+ }
+ tPath.applyVoltage(aVoltage - tVoltLoss, true);
+ tVoltLoss += tPath.getLoss();
+ long tAmps = powerNode(aNextNode, aCurrentNode, aConsumers, aVoltage - tVoltLoss, aMaxAmps);
+ tPath.addAmps(tAmps);
+ if (tSelfPath != null) tSelfPath.addAmps(tAmps);
+ return tAmps;
+ }
+
+ protected static long processNextNodeAbove(Node aCurrentNode, Node aNextNode, NodeList aConsumers, int ordinalSide,
+ long aMaxAmps, long aVoltage) {
+ if (aCurrentNode.locks[ordinalSide].isLocked()) {
+ aConsumers.getNextNode();
+ return 0;
+ }
+ final PowerNodePath tPath = (PowerNodePath) aCurrentNode.mNodePaths[ordinalSide];
+ final PowerNodePath tSelfPath = (PowerNodePath) aCurrentNode.mSelfPath;
+ long tVoltLoss = 0;
+ if (tSelfPath != null) {
+ tVoltLoss += tSelfPath.getLoss();
+ tSelfPath.applyVoltage(aVoltage, false);
+ }
+ tPath.applyVoltage(aVoltage - tVoltLoss, true);
+ tVoltLoss += tPath.getLoss();
+ long tAmps = powerNodeAbove(aNextNode, aCurrentNode, aConsumers, aVoltage - tVoltLoss, aMaxAmps);
+ tPath.addAmps(tAmps);
+ if (tSelfPath != null) tSelfPath.addAmps(tAmps);
+ return tAmps;
+ }
+
+ protected static long processNodeInject(Node aCurrentNode, ConsumerNode aConsumer, int ordinalSide, long aMaxAmps,
+ long aVoltage) {
+ if (aCurrentNode.locks[ordinalSide].isLocked()) return 0;
+ final PowerNodePath tPath = (PowerNodePath) aCurrentNode.mNodePaths[ordinalSide];
+ final PowerNodePath tSelfPath = (PowerNodePath) aCurrentNode.mSelfPath;
+ long tVoltLoss = 0;
+ if (tSelfPath != null) {
+ tVoltLoss += tSelfPath.getLoss();
+ tSelfPath.applyVoltage(aVoltage, false);
+ }
+ tPath.applyVoltage(aVoltage - tVoltLoss, true);
+ tVoltLoss += tPath.getLoss();
+ long 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..392fe74a32
--- /dev/null
+++ b/src/main/java/gregtech/api/graphs/consumers/ConsumerNode.java
@@ -0,0 +1,30 @@
+package gregtech.api.graphs.consumers;
+
+import java.util.ArrayList;
+
+import net.minecraft.tileentity.TileEntity;
+import net.minecraftforge.common.util.ForgeDirection;
+
+import gregtech.api.graphs.Node;
+
+/**
+ * A node attached to a {@code TileEntity} that can consume stuff from the network.
+ */
+public class ConsumerNode extends Node {
+
+ public ForgeDirection mSide;
+
+ public ConsumerNode(int aNodeValue, TileEntity aTileEntity, ForgeDirection side,
+ ArrayList<ConsumerNode> aConsumers) {
+ super(aNodeValue, aTileEntity, aConsumers);
+ this.mSide = side;
+ }
+
+ public boolean needsEnergy() {
+ return !mTileEntity.isInvalid();
+ }
+
+ public int injectEnergy(long aVoltage, long 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..48cf330bdb
--- /dev/null
+++ b/src/main/java/gregtech/api/graphs/consumers/EmptyPowerConsumer.java
@@ -0,0 +1,31 @@
+package gregtech.api.graphs.consumers;
+
+import java.util.ArrayList;
+
+import net.minecraft.tileentity.TileEntity;
+import net.minecraftforge.common.util.ForgeDirection;
+
+import gregtech.api.graphs.paths.PowerNodePath;
+import gregtech.api.metatileentity.BaseMetaPipeEntity;
+
+// this is here to apply voltage to dead ends
+public class EmptyPowerConsumer extends ConsumerNode {
+
+ public EmptyPowerConsumer(int aNodeValue, TileEntity aTileEntity, ForgeDirection side,
+ ArrayList<ConsumerNode> aConsumers) {
+ super(aNodeValue, aTileEntity, side, aConsumers);
+ }
+
+ @Override
+ public boolean needsEnergy() {
+ return false;
+ }
+
+ @Override
+ public int injectEnergy(long aVoltage, long 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..fb0a8cf287
--- /dev/null
+++ b/src/main/java/gregtech/api/graphs/consumers/NodeEnergyConnected.java
@@ -0,0 +1,21 @@
+package gregtech.api.graphs.consumers;
+
+import java.util.ArrayList;
+
+import net.minecraft.tileentity.TileEntity;
+import net.minecraftforge.common.util.ForgeDirection;
+
+import gregtech.api.interfaces.tileentity.IEnergyConnected;
+
+public class NodeEnergyConnected extends ConsumerNode {
+
+ public NodeEnergyConnected(int aNodeValue, IEnergyConnected aTileEntity, ForgeDirection side,
+ ArrayList<ConsumerNode> aConsumers) {
+ super(aNodeValue, (TileEntity) aTileEntity, side, aConsumers);
+ }
+
+ @Override
+ public int injectEnergy(long aVoltage, long 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..4f35922029
--- /dev/null
+++ b/src/main/java/gregtech/api/graphs/consumers/NodeEnergyReceiver.java
@@ -0,0 +1,68 @@
+package gregtech.api.graphs.consumers;
+
+import java.util.ArrayList;
+
+import net.minecraft.init.Blocks;
+import net.minecraft.tileentity.TileEntity;
+import net.minecraft.world.World;
+import net.minecraftforge.common.util.ForgeDirection;
+
+import cofh.api.energy.IEnergyReceiver;
+import gregtech.GT_Mod;
+import gregtech.api.GregTech_API;
+import gregtech.api.enums.GT_Values;
+import gregtech.api.enums.SoundResource;
+import gregtech.api.util.GT_Utility;
+import gregtech.api.util.WorldSpawnedEventBuilder;
+import gregtech.common.GT_Pollution;
+
+// consumer for RF machines
+public class NodeEnergyReceiver extends ConsumerNode {
+
+ int mRestRF = 0;
+
+ public NodeEnergyReceiver(int aNodeValue, IEnergyReceiver aTileEntity, ForgeDirection side,
+ ArrayList<ConsumerNode> aConsumers) {
+ super(aNodeValue, (TileEntity) aTileEntity, side, aConsumers);
+ }
+
+ @Override
+ public int injectEnergy(long aVoltage, long aMaxAmps) {
+ ForgeDirection tDirection = 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) {
+ float tStrength = GT_Values.getExplosionPowerForVoltage(aRfOut);
+ int tX = mTileEntity.xCoord, tY = mTileEntity.yCoord, tZ = mTileEntity.zCoord;
+ World tWorld = mTileEntity.getWorldObj();
+ GT_Utility.sendSoundToPlayers(tWorld, SoundResource.IC2_MACHINES_MACHINE_OVERLOAD, 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), GT_Mod.gregtechproxy.mPollutionOnExplosion);
+
+ 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..44fb88e5e8
--- /dev/null
+++ b/src/main/java/gregtech/api/graphs/consumers/NodeEnergySink.java
@@ -0,0 +1,30 @@
+package gregtech.api.graphs.consumers;
+
+import java.util.ArrayList;
+
+import net.minecraft.tileentity.TileEntity;
+import net.minecraftforge.common.util.ForgeDirection;
+
+import ic2.api.energy.tile.IEnergySink;
+
+// consumer for IC2 machines
+public class NodeEnergySink extends ConsumerNode {
+
+ public NodeEnergySink(int nodeValue, IEnergySink tileEntity, ForgeDirection 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(long aVoltage, long aMaxAmps) {
+ int tUsedAmps = 0;
+ while (aMaxAmps > tUsedAmps && ((IEnergySink) mTileEntity).getDemandedEnergy() > 0
+ && ((IEnergySink) mTileEntity).injectEnergy(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..e8d8304eb3
--- /dev/null
+++ b/src/main/java/gregtech/api/graphs/consumers/NodeGTBaseMetaTile.java
@@ -0,0 +1,28 @@
+package gregtech.api.graphs.consumers;
+
+import java.util.ArrayList;
+
+import net.minecraftforge.common.util.ForgeDirection;
+
+import gregtech.api.interfaces.tileentity.IEnergyConnected;
+import gregtech.api.metatileentity.BaseMetaTileEntity;
+
+// consumer for gt machines
+public class NodeGTBaseMetaTile extends ConsumerNode {
+
+ public NodeGTBaseMetaTile(int aNodeValue, BaseMetaTileEntity aTileEntity, ForgeDirection side,
+ ArrayList<ConsumerNode> aConsumers) {
+ super(aNodeValue, aTileEntity, side, aConsumers);
+ }
+
+ @Override
+ public int injectEnergy(long aVoltage, long 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..0e852bd484
--- /dev/null
+++ b/src/main/java/gregtech/api/graphs/paths/NodePath.java
@@ -0,0 +1,42 @@
+package gregtech.api.graphs.paths;
+
+import gregtech.api.graphs.Lock;
+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 Lock lock = new Lock();
+
+ public NodePath(MetaPipeEntity[] aCables) {
+ this.mPipes = aCables;
+ processPipes();
+ }
+
+ protected void processPipes() {
+ for (MetaPipeEntity tPipe : mPipes) {
+ BaseMetaPipeEntity basePipe = (BaseMetaPipeEntity) tPipe.getBaseMetaTileEntity();
+ basePipe.setNodePath(this);
+ }
+ }
+
+ public void clearPath() {
+ for (MetaPipeEntity mPipe : mPipes) {
+ BaseMetaPipeEntity tBasePipe = (BaseMetaPipeEntity) mPipe.getBaseMetaTileEntity();
+ if (tBasePipe != null) {
+ tBasePipe.setNodePath(null);
+ }
+ }
+ }
+
+ public void reloadLocks() {
+ for (MetaPipeEntity pipe : mPipes) {
+ BaseMetaPipeEntity basePipe = (BaseMetaPipeEntity) pipe.getBaseMetaTileEntity();
+ if (basePipe != null) {
+ basePipe.reloadLocks();
+ }
+ }
+ }
+}
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..8a869c333e
--- /dev/null
+++ b/src/main/java/gregtech/api/graphs/paths/PowerNodePath.java
@@ -0,0 +1,153 @@
+package gregtech.api.graphs.paths;
+
+import net.minecraft.server.MinecraftServer;
+
+import gregtech.api.enums.TickTime;
+import gregtech.api.metatileentity.BaseMetaPipeEntity;
+import gregtech.api.metatileentity.MetaPipeEntity;
+import gregtech.api.metatileentity.implementations.GT_MetaPipeEntity_Cable;
+import gregtech.api.util.AveragePerTickCounter;
+
+// path for cables
+// all calculations like amp and voltage happens here
+public class PowerNodePath extends NodePath {
+
+ long mMaxAmps;
+ long mAmps = 0;
+ long mLoss;
+ long mVoltage = 0;
+ long mMaxVoltage;
+ int mTick = 0;
+ boolean mCountUp = true;
+
+ private AveragePerTickCounter avgAmperageCounter = new AveragePerTickCounter(TickTime.SECOND);
+ private AveragePerTickCounter avgVoltageCounter = new AveragePerTickCounter(TickTime.SECOND);
+
+ public PowerNodePath(MetaPipeEntity[] aCables) {
+ super(aCables);
+ }
+
+ public long getLoss() {
+ return mLoss;
+ }
+
+ public void applyVoltage(long aVoltage, boolean aCountUp) {
+
+ avgVoltageCounter.addValue(Math.max(aVoltage - mLoss, 0));
+
+ 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) {
+ lock.addTileEntity(null);
+ for (MetaPipeEntity tCable : mPipes) {
+ if (((GT_MetaPipeEntity_Cable) tCable).mVoltage < this.mVoltage) {
+ BaseMetaPipeEntity tBaseCable = (BaseMetaPipeEntity) tCable.getBaseMetaTileEntity();
+ if (tBaseCable != null) {
+ tBaseCable.setToFire();
+ }
+ }
+ }
+ }
+ }
+
+ private void reset(int aTimePassed) {
+ if (aTimePassed < 0 || aTimePassed > 100) {
+ mAmps = 0;
+ return;
+ }
+ mAmps = Math.max(0, mAmps - (mMaxAmps * aTimePassed));
+ }
+
+ public void addAmps(long aAmps) {
+
+ avgAmperageCounter.addValue(aAmps);
+
+ this.mAmps += aAmps;
+ if (this.mAmps > mMaxAmps * 40) {
+ lock.addTileEntity(null);
+ 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 through for more than 0.5 second reduce them to minimize wrong results
+ // but still allow the player to see if activity is happening
+ @Deprecated
+ public long getAmps() {
+ int tTime = MinecraftServer.getServer()
+ .getTickCounter() - 10;
+ if (mTick < tTime) {
+ reset(tTime - mTick);
+ mTick = tTime;
+ }
+ return mAmps;
+ }
+
+ @Deprecated
+ public long getVoltage(MetaPipeEntity aCable) {
+ int tLoss = 0;
+ if (mCountUp) {
+ for (MetaPipeEntity mPipe : mPipes) {
+ GT_MetaPipeEntity_Cable tCable = (GT_MetaPipeEntity_Cable) mPipe;
+ 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;
+ }
+
+ public long getAmperage() {
+ return avgAmperageCounter.getLast();
+ }
+
+ public double getAvgAmperage() {
+ return avgAmperageCounter.getAverage();
+ }
+
+ public long getVoltage() {
+ return avgVoltageCounter.getLast();
+ }
+
+ public double getAvgVoltage() {
+ return avgVoltageCounter.getAverage();
+ }
+
+ @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(((GT_MetaPipeEntity_Cable) tCable).mAmperage, mMaxAmps);
+ mLoss += ((GT_MetaPipeEntity_Cable) tCable).mCableLossPerMeter;
+ mMaxVoltage = Math.min(((GT_MetaPipeEntity_Cable) tCable).mVoltage, mMaxVoltage);
+ }
+ }
+ }
+}