diff options
author | Martin Robertz <dream-master@gmx.net> | 2021-07-02 20:52:49 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-07-02 20:52:49 +0200 |
commit | 2a5b42343509d9684affa6be27da32e9eef89851 (patch) | |
tree | c1542a71bf37ed7611aa4cecb6d633556798d01d /src | |
parent | 77c57a97b7286863f9239de806ac9659013d6852 (diff) | |
parent | 6f80c03736d6d9ea9c72d19f0af72fc727714370 (diff) | |
download | GT5-Unofficial-2a5b42343509d9684affa6be27da32e9eef89851.tar.gz GT5-Unofficial-2a5b42343509d9684affa6be27da32e9eef89851.tar.bz2 GT5-Unofficial-2a5b42343509d9684affa6be27da32e9eef89851.zip |
Merge pull request #572 from GTNewHorizons/beter-power-net
Better power net
Diffstat (limited to 'src')
21 files changed, 993 insertions, 193 deletions
diff --git a/src/main/java/gregtech/api/GregTech_API.java b/src/main/java/gregtech/api/GregTech_API.java index e24297c48c..ba7e3ab43e 100644 --- a/src/main/java/gregtech/api/GregTech_API.java +++ b/src/main/java/gregtech/api/GregTech_API.java @@ -17,6 +17,7 @@ import gregtech.api.objects.GT_Cover_Default; import gregtech.api.objects.GT_Cover_None; import gregtech.api.objects.GT_HashSet; import gregtech.api.objects.GT_ItemStack; +import gregtech.api.threads.GT_Runnable_Cable_Update; import gregtech.api.threads.GT_Runnable_MachineBlockUpdate; import gregtech.api.util.*; import gregtech.api.world.GT_Worldgen; @@ -407,6 +408,15 @@ public class GregTech_API { return false; } + public static boolean causeCableUpdate(World aWorld, int aX, int aY, int aZ) { + if (aWorld != null && !aWorld.isRemote) { // World might be null during Worldgen + GT_Runnable_Cable_Update.setCableUpdateValues(aWorld, new ChunkCoordinates(aX, aY, aZ)); + return true; + } + return false; + + } + /** * Adds a Multi-Machine Block, like my Machine Casings for example. * You should call @causeMachineUpdate in @Block.breakBlock and in @Block.onBlockAdded of your registered Block. 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..547da44050 --- /dev/null +++ b/src/main/java/gregtech/api/graphs/GenerateNodeMapPower.java @@ -0,0 +1,81 @@ +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.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 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/NodeEnergyReceiver.java b/src/main/java/gregtech/api/graphs/consumers/NodeEnergyReceiver.java new file mode 100644 index 0000000000..c8c4c64211 --- /dev/null +++ b/src/main/java/gregtech/api/graphs/consumers/NodeEnergyReceiver.java @@ -0,0 +1,79 @@ +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 { + 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); + if (((IEnergyReceiver) mTileEntity).receiveEnergy(tDirection, rfOut, true) == rfOut) { + ((IEnergyReceiver) mTileEntity).receiveEnergy(tDirection, rfOut, false); + return 1; + } + 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..736373a9ca --- /dev/null +++ b/src/main/java/gregtech/api/graphs/paths/PowerNodePath.java @@ -0,0 +1,111 @@ +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(); + 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); + } + } + } +} diff --git a/src/main/java/gregtech/api/interfaces/tileentity/IEnergyConnected.java b/src/main/java/gregtech/api/interfaces/tileentity/IEnergyConnected.java index 158b53068d..24d0576864 100644 --- a/src/main/java/gregtech/api/interfaces/tileentity/IEnergyConnected.java +++ b/src/main/java/gregtech/api/interfaces/tileentity/IEnergyConnected.java @@ -61,7 +61,7 @@ public interface IEnergyConnected extends IColoredTileEntity, IHasWorldObjectAnd */ public static final long emitEnergyToNetwork(long aVoltage, long aAmperage, IEnergyConnected aEmitter) { long rUsedAmperes = 0; - for (byte i = 0, j = 0; i < 6 && aAmperage > rUsedAmperes; i++) + for (byte i = 0, j = 0; i < 6 && aAmperage > rUsedAmperes; i++) { if (aEmitter.outputsEnergyTo(i)) { j = GT_Utility.getOppositeSide(i); TileEntity tTileEntity = aEmitter.getTileEntityAtSide(i); @@ -71,6 +71,7 @@ public interface IEnergyConnected extends IColoredTileEntity, IHasWorldObjectAnd if (tColor >= 0 && tColor != aEmitter.getColorization()) continue; } rUsedAmperes += ((IEnergyConnected) tTileEntity).injectEnergyUnits(j, aVoltage, aAmperage - rUsedAmperes); + } else if (tTileEntity instanceof IEnergySink) { if (((IEnergySink) tTileEntity).acceptsEnergyFrom((TileEntity) aEmitter, ForgeDirection.getOrientation(j))) { while (aAmperage > rUsedAmperes && ((IEnergySink) tTileEntity).getDemandedEnergy() > 0 && ((IEnergySink) tTileEntity).injectEnergy(ForgeDirection.getOrientation(j), aVoltage, aVoltage) < aVoltage) @@ -124,6 +125,7 @@ public interface IEnergyConnected extends IColoredTileEntity, IHasWorldObjectAnd } } } + } return rUsedAmperes; } } diff --git a/src/main/java/gregtech/api/metatileentity/BaseMetaPipeEntity.java b/src/main/java/gregtech/api/metatileentity/BaseMetaPipeEntity.java index 0fd8779244..b51377550b 100644 --- a/src/main/java/gregtech/api/metatileentity/BaseMetaPipeEntity.java +++ b/src/main/java/gregtech/api/metatileentity/BaseMetaPipeEntity.java @@ -12,6 +12,8 @@ import gregtech.GT_Mod; import gregtech.api.GregTech_API; import gregtech.api.enums.Textures; import gregtech.api.enums.Textures.BlockIcons; +import gregtech.api.graphs.Node; +import gregtech.api.graphs.paths.NodePath; import gregtech.api.interfaces.ITexture; import gregtech.api.interfaces.metatileentity.IConnectable; import gregtech.api.interfaces.metatileentity.IMetaTileEntity; @@ -62,6 +64,25 @@ public class BaseMetaPipeEntity extends BaseTileEntity implements IGregTechTileE private int oX = 0, oY = 0, oZ = 0, mTimeStatisticsIndex = 0; private short mID = 0; private long mTickTimer = 0; + protected Node node; + protected NodePath nodePath; + + public Node getNode() { + return node; + } + + public void setNode(Node node) { + this.node = node; + } + + public NodePath getNodePath() { + return nodePath; + } + + public void setNodePath(NodePath nodePath) { + this.nodePath = nodePath; + } + public BaseMetaPipeEntity() { } @@ -262,12 +283,15 @@ public class BaseMetaPipeEntity extends BaseTileEntity implements IGregTechTileE if (!hasValidMetaTileEntity()) return; } } - // Mask-out Connection direction bits to keep only Foam related connections + byte oldConnections = mConnections; + // Mask-out connection direction bits to keep only Foam related connections mConnections = (byte) (mMetaTileEntity.mConnections | (mConnections & ~IConnectable.CONNECTED_ALL)); // If foam not hardened, tries roll chance to harden if ((mConnections & IConnectable.HAS_FOAM) == IConnectable.HAS_FRESHFOAM && getRandomNumber(1000) == 0) { mConnections = (byte) ((mConnections & ~IConnectable.HAS_FRESHFOAM) | IConnectable.HAS_HARDENEDFOAM); } + if (mTickTimer > 12 && oldConnections != mConnections) + GregTech_API.causeCableUpdate(worldObj,xCoord,yCoord,zCoord); } case 8: tCode = 9; diff --git a/src/main/java/gregtech/api/metatileentity/BaseMetaTileEntity.java b/src/main/java/gregtech/api/metatileentity/BaseMetaTileEntity.java index f1a15aca40..341e7d5714 100644 --- a/src/main/java/gregtech/api/metatileentity/BaseMetaTileEntity.java +++ b/src/main/java/gregtech/api/metatileentity/BaseMetaTileEntity.java @@ -14,6 +14,9 @@ import gregtech.api.GregTech_API; import gregtech.api.enums.ItemList; import gregtech.api.enums.Textures; import gregtech.api.enums.Textures.BlockIcons; +import gregtech.api.graphs.GenerateNodeMap; +import gregtech.api.graphs.GenerateNodeMapPower; +import gregtech.api.graphs.Node; import gregtech.api.interfaces.ITexture; import gregtech.api.interfaces.metatileentity.IMetaTileEntity; import gregtech.api.interfaces.tileentity.IEnergyConnected; @@ -40,6 +43,7 @@ import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.network.Packet; +import net.minecraft.server.MinecraftServer; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.AxisAlignedBB; import net.minecraft.util.EnumChatFormatting; @@ -90,6 +94,7 @@ public class BaseMetaTileEntity extends BaseTileEntity implements IGregTechTileE private String mOwnerName = ""; private UUID mOwnerUuid = GT_Utility.defaultUuid; private NBTTagCompound mRecipeStuff = new NBTTagCompound(); + private int cableUpdateDelay = 30; public boolean mWasShutdown = false; @@ -568,6 +573,12 @@ public class BaseMetaTileEntity extends BaseTileEntity implements IGregTechTileE case 15: tCode++; if (aSideServer) { + if (mTickTimer > 20 && cableUpdateDelay == 0) { + generatePowerNodes(); + cableUpdateDelay--; + } else { + cableUpdateDelay--; + } if (mTickTimer % 10 == 0) { if (mSendClientData) { NW.sendPacketToAllPlayersInRange(worldObj, @@ -869,6 +880,7 @@ public class BaseMetaTileEntity extends BaseTileEntity implements IGregTechTileE mMetaTileEntity.onFacingChange(); doEnetUpdate(); + cableUpdateDelay = 10; if (mMetaTileEntity.shouldTriggerBlockUpdate()) { // If we're triggering a block update this will call onMachineBlockUpdate() @@ -971,6 +983,7 @@ public class BaseMetaTileEntity extends BaseTileEntity implements IGregTechTileE @Override public void onMachineBlockUpdate() { if (canAccessData()) mMetaTileEntity.onMachineBlockUpdate(); + cableUpdateDelay = 10; } /** @@ -1098,6 +1111,26 @@ public class BaseMetaTileEntity extends BaseTileEntity implements IGregTechTileE return isEnergyOutputSide(aSide); } + public void generatePowerNodes() { + if (isServerSide() && mMetaTileEntity != null && (mMetaTileEntity.isEnetInput() || mMetaTileEntity.isEnetOutput())) { + int time = MinecraftServer.getServer().getTickCounter(); + for (byte i = 0;i<6;i++) { + if (outputsEnergyTo(i,false) || inputEnergyFrom(i,false)) { + IGregTechTileEntity TE = getIGregTechTileEntityAtSide(i); + if (TE instanceof BaseMetaPipeEntity) { + Node node = ((BaseMetaPipeEntity) TE).getNode(); + if (node == null) { + new GenerateNodeMapPower((BaseMetaPipeEntity) TE); + } else if (node.mCreationTime != time) { + GenerateNodeMap.clearNodeMap(node,-1); + new GenerateNodeMapPower((BaseMetaPipeEntity) TE); + } + } + } + } + } + } + @Override public long getOutputAmperage() { if (canAccessData() && mMetaTileEntity.isElectric()) return mMetaTileEntity.maxAmperesOut(); @@ -1399,9 +1432,11 @@ public class BaseMetaTileEntity extends BaseTileEntity implements IGregTechTileE if(aPlayer.isSneaking() && mMetaTileEntity instanceof GT_MetaTileEntity_BasicMachine && ((GT_MetaTileEntity_BasicMachine)mMetaTileEntity).setMainFacing(GT_Utility.determineWrenchingSide(aSide, aX, aY, aZ))){ GT_ModHandler.damageOrDechargeItem(tCurrentItem, 1, 1000, aPlayer); GT_Utility.sendSoundToPlayers(worldObj, GregTech_API.sSoundList.get(100), 1.0F, -1, xCoord, yCoord, zCoord); + cableUpdateDelay = 10; }else if (mMetaTileEntity.onWrenchRightClick(aSide, GT_Utility.determineWrenchingSide(aSide, aX, aY, aZ), aPlayer, aX, aY, aZ)) { GT_ModHandler.damageOrDechargeItem(tCurrentItem, 1, 1000, aPlayer); GT_Utility.sendSoundToPlayers(worldObj, GregTech_API.sSoundList.get(100), 1.0F, -1, xCoord, yCoord, zCoord); + cableUpdateDelay = 10; } return true; } @@ -1452,6 +1487,7 @@ public class BaseMetaTileEntity extends BaseTileEntity implements IGregTechTileE issueBlockUpdate(); } doEnetUpdate(); + cableUpdateDelay = 10; return true; } @@ -1462,6 +1498,7 @@ public class BaseMetaTileEntity extends BaseTileEntity implements IGregTechTileE GT_Utility.sendSoundToPlayers(worldObj, GregTech_API.sSoundList.get(100), 1.0F, -1, xCoord, yCoord, zCoord); } doEnetUpdate(); + cableUpdateDelay = 10; return true; } diff --git a/src/main/java/gregtech/api/metatileentity/MetaTileEntity.java b/src/main/java/gregtech/api/metatileentity/MetaTileEntity.java index 84790ce958..87eee3e6ac 100644 --- a/src/main/java/gregtech/api/metatileentity/MetaTileEntity.java +++ b/src/main/java/gregtech/api/metatileentity/MetaTileEntity.java @@ -63,6 +63,7 @@ public abstract class MetaTileEntity implements IMetaTileEntity { public final ItemStack[] mInventory; public boolean doTickProfilingInThisTick = true; + /** * accessibility to this Field is no longer given, see below */ diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaPipeEntity_Cable.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaPipeEntity_Cable.java index 93d947b9d0..b15e520da7 100644 --- a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaPipeEntity_Cable.java +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaPipeEntity_Cable.java @@ -9,6 +9,12 @@ import gregtech.api.enums.Dyes; import gregtech.api.enums.Materials; import gregtech.api.enums.TextureSet; import gregtech.api.enums.Textures; +import gregtech.api.graphs.PowerNode; +import gregtech.api.graphs.PowerNodes; +import gregtech.api.graphs.consumers.ConsumerNode; +import gregtech.api.graphs.Node; +import gregtech.api.graphs.NodeList; +import gregtech.api.graphs.paths.PowerNodePath; import gregtech.api.interfaces.ITexture; import gregtech.api.interfaces.metatileentity.IMetaTileEntity; import gregtech.api.interfaces.metatileentity.IMetaTileEntityCable; @@ -18,10 +24,7 @@ import gregtech.api.interfaces.tileentity.IGregTechTileEntity; import gregtech.api.metatileentity.BaseMetaPipeEntity; import gregtech.api.metatileentity.MetaPipeEntity; import gregtech.api.render.TextureFactory; -import gregtech.api.util.GT_CoverBehavior; -import gregtech.api.util.GT_GC_Compat; -import gregtech.api.util.GT_ModHandler; -import gregtech.api.util.GT_Utility; +import gregtech.api.util.*; import gregtech.common.GT_Client; import gregtech.common.covers.GT_Cover_SolarPanel; import ic2.api.energy.EnergyNet; @@ -158,7 +161,8 @@ public class GT_MetaPipeEntity_Cable extends MetaPipeEntity implements IMetaTile return 0; if (!getBaseMetaTileEntity().getCoverBehaviorAtSide(aSide).letsEnergyIn(aSide, getBaseMetaTileEntity().getCoverIDAtSide(aSide), getBaseMetaTileEntity().getCoverDataAtSide(aSide), getBaseMetaTileEntity())) return 0; - return transferElectricity(aSide, aVoltage, aAmperage, Sets.newHashSet((TileEntity) getBaseMetaTileEntity())); + HashSet<TileEntity> nul = null; + return transferElectricity(aSide, aVoltage, aAmperage,nul); } @Override @@ -169,118 +173,30 @@ public class GT_MetaPipeEntity_Cable extends MetaPipeEntity implements IMetaTile @Override public long transferElectricity(byte aSide, long aVoltage, long aAmperage, HashSet<TileEntity> aAlreadyPassedSet) { - if (!isConnectedAtSide(aSide) && aSide != 6) return 0; - - long rUsedAmperes = 0; - final IGregTechTileEntity baseMetaTile = getBaseMetaTileEntity(); - byte i = (byte)((((aSide/2)*2)+2)%6); //this bit of trickery makes sure a direction goes to the next cardinal pair. IE, NS goes to E, EW goes to U, UD goes to N. It's a lame way to make sure locally connected machines on a wire get EU first. - aVoltage -= mCableLossPerMeter; - - if (aVoltage > 0) for (byte j = 0; j < 6 && aAmperage > rUsedAmperes; j++, i=(byte)((i+1)%6) ) - if (i != aSide && isConnectedAtSide(i) && baseMetaTile.getCoverBehaviorAtSide(i).letsEnergyOut(i, baseMetaTile.getCoverIDAtSide(i), baseMetaTile.getCoverDataAtSide(i), baseMetaTile)) { - final TileEntity tTileEntity = baseMetaTile.getTileEntityAtSide(i); - - if (tTileEntity != null && aAlreadyPassedSet.add(tTileEntity)) { - final byte tSide = GT_Utility.getOppositeSide(i); - final IGregTechTileEntity tBaseMetaTile = tTileEntity instanceof IGregTechTileEntity ? ((IGregTechTileEntity) tTileEntity) : null; - final IMetaTileEntity tMeta = tBaseMetaTile != null ? tBaseMetaTile.getMetaTileEntity() : null; - - if (tMeta instanceof IMetaTileEntityCable) { - if (tBaseMetaTile.getCoverBehaviorAtSide(tSide).letsEnergyIn(tSide, tBaseMetaTile.getCoverIDAtSide(tSide), tBaseMetaTile.getCoverDataAtSide(tSide), tBaseMetaTile) && ((IGregTechTileEntity) tTileEntity).getTimer() > 50) { - rUsedAmperes += ((IMetaTileEntityCable) ((IGregTechTileEntity) tTileEntity).getMetaTileEntity()).transferElectricity(tSide, aVoltage, aAmperage - rUsedAmperes, aAlreadyPassedSet); - } - } else { - rUsedAmperes += insertEnergyInto(tTileEntity, tSide, aVoltage, aAmperage - rUsedAmperes); - } - - } - } - mTransferredVoltage = Math.max(mTransferredVoltage, aVoltage); - mTransferredAmperage += rUsedAmperes; - mTransferredVoltageLast20 = Math.max(mTransferredVoltageLast20, aVoltage); - mTransferredAmperageLast20 = Math.max(mTransferredAmperageLast20, mTransferredAmperage); - if (aVoltage > mVoltage) { - mOverheat += Math.max(100, 100 * GT_Utility.getTier(aVoltage) - GT_Utility.getTier(mVoltage)); - } - if (mTransferredAmperage > mAmperage) return aAmperage; - - // Always return amount of used amperes, used on overheat - return rUsedAmperes; - } - - - - private long insertEnergyInto(TileEntity tTileEntity, byte tSide, long aVoltage, long aAmperage) { - if (aAmperage == 0 || tTileEntity == null) return 0; - - final IGregTechTileEntity baseMetaTile = getBaseMetaTileEntity(); - final ForgeDirection tDirection = ForgeDirection.getOrientation(tSide); - - if (tTileEntity instanceof IEnergyConnected) { - return ((IEnergyConnected) tTileEntity).injectEnergyUnits(tSide, aVoltage, aAmperage); - } - - // AE2 Compat - if (GT_Mod.gregtechproxy.mAE2Integration && tTileEntity instanceof appeng.tile.powersink.IC2) { - if (((appeng.tile.powersink.IC2) tTileEntity).acceptsEnergyFrom((TileEntity) baseMetaTile, tDirection)) { - long rUsedAmperes = 0; - while (aAmperage > rUsedAmperes && ((appeng.tile.powersink.IC2)tTileEntity).getDemandedEnergy() > 0 && ((appeng.tile.powersink.IC2)tTileEntity).injectEnergy(tDirection, aVoltage, aVoltage) <= aVoltage) - rUsedAmperes++; - - return rUsedAmperes; - } + if (!getBaseMetaTileEntity().isServerSide() || !isConnectedAtSide(aSide) && aSide != 6) return 0; + BaseMetaPipeEntity tBase =(BaseMetaPipeEntity) getBaseMetaTileEntity(); + if (!(tBase.getNode() instanceof PowerNode)) return 0; - } - - if (Loader.isModLoaded("GalacticraftCore")) { - long gc = GT_GC_Compat.insertEnergyInto(tTileEntity, aVoltage, tDirection); - if (gc != 2) - return gc; - } - - // IC2 Compat - { - final TileEntity tIc2Acceptor = (tTileEntity instanceof IEnergyTile || EnergyNet.instance == null) ? tTileEntity : - EnergyNet.instance.getTileEntity(tTileEntity.getWorldObj(), tTileEntity.xCoord, tTileEntity.yCoord, tTileEntity.zCoord); - - if (tIc2Acceptor instanceof IEnergySink && ((IEnergySink) tIc2Acceptor).acceptsEnergyFrom((TileEntity) baseMetaTile, tDirection)) { - long rUsedAmperes = 0; - while (aAmperage > rUsedAmperes && ((IEnergySink) tIc2Acceptor).getDemandedEnergy() > 0 && ((IEnergySink) tIc2Acceptor).injectEnergy(tDirection, aVoltage, aVoltage) <= aVoltage) - rUsedAmperes++; - return rUsedAmperes; - } - } - - // RF Compat - if (GregTech_API.mOutputRF && tTileEntity instanceof IEnergyReceiver) { - final IEnergyReceiver rfReceiver = (IEnergyReceiver) tTileEntity; - long rfOUT = aVoltage * GregTech_API.mEUtoRF / 100, rUsedAmperes = 0; - int rfOut = rfOUT > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) rfOUT; - - if (rfReceiver.receiveEnergy(tDirection, rfOut, true) == rfOut) { - rfReceiver.receiveEnergy(tDirection, rfOut, false); - rUsedAmperes++; - } - else if (rfReceiver.receiveEnergy(tDirection, rfOut, true) > 0) { - if (mRestRF == 0) { - int RFtrans = rfReceiver.receiveEnergy(tDirection, rfOut, false); - rUsedAmperes++; - mRestRF = rfOut - RFtrans; - } else { - int RFtrans = rfReceiver.receiveEnergy(tDirection, (int) mRestRF, false); - mRestRF = mRestRF - RFtrans; + PowerNode tNode =(PowerNode) tBase.getNode(); + if (tNode != null) { + int tPlace = 0; + Node[] tToPower = new Node[tNode.mConsumers.size()]; + if (tNode.mHadVoltage) { + for (ConsumerNode consumer : tNode.mConsumers) { + if (consumer.needsEnergy()) + tToPower[tPlace++] = consumer; + } + } else { + tNode.mHadVoltage = true; + for (ConsumerNode consumer : tNode.mConsumers) { + tToPower[tPlace++] = consumer; } } - if (GregTech_API.mRFExplosions && rfReceiver.getMaxEnergyStored(tDirection) < rfOut * 600) { - if (rfOut > 32 * GregTech_API.mEUtoRF / 100) this.doExplosion(rfOut); - } - return rUsedAmperes; + return PowerNodes.powerNode(tNode,null,new NodeList(tToPower),(int)aVoltage,(int)aAmperage); } - return 0; } - @Override public void onFirstTick(IGregTechTileEntity aBaseMetaTileEntity) { if(aBaseMetaTileEntity.isServerSide()) { @@ -290,76 +206,6 @@ public class GT_MetaPipeEntity_Cable extends MetaPipeEntity implements IMetaTile } @Override - public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { - super.onPostTick(aBaseMetaTileEntity, aTick); - if (aBaseMetaTileEntity.isServerSide()) { - - { //amp handler - long worldTick = aBaseMetaTileEntity.getWorld().getTotalWorldTime(); - int tickDiff = (int) (worldTick - lastWorldTick); - lastWorldTick = worldTick; - - if (tickDiff >= 16) for (int i = 0; i <= 14; i++) lastAmperage[i] = 0; - else { - System.arraycopy(lastAmperage, tickDiff, lastAmperage, 0, 16 - tickDiff); - for (int i = 14; i >= 0; i--) { - if (--tickDiff > 0) lastAmperage[i] = 0; - else break; - } - } - - lastAmperage[15] = mTransferredAmperage; - - if (lastAmperage[15] > mAmperage) { - int i = 0; - for (; i <= 14; i++) { - if (lastAmperage[i] < mAmperage) { - lastAmperage[15] -= (int) mAmperage - lastAmperage[i]; - lastAmperage[i] = (int)mAmperage; - if (lastAmperage[15] <= mAmperage) break; - } - } - if (lastAmperage[15] > mAmperage) { - mOverheat += 100 * (lastAmperage[15] - mAmperage); - lastAmperage[15] = (int) mAmperage; - } else if (lastAmperage[15] < mAmperage) { - lastAmperage[i] = lastAmperage[15]; - lastAmperage[15] = (int) mAmperage; - } - } - } - - if(mOverheat>=mMaxOverheat) { - //TODO someday - //int newMeta=aBaseMetaTileEntity.getMetaTileID()-6; - //if(mInsulated && - // GregTech_API.METATILEENTITIES[newMeta] instanceof GT_MetaPipeEntity_Cable && - // ((GT_MetaPipeEntity_Cable)GregTech_API.METATILEENTITIES[newMeta]).mMaterial==mMaterial && - // ((GT_MetaPipeEntity_Cable)GregTech_API.METATILEENTITIES[newMeta]).mAmperage<=mAmperage){ - // aBaseMetaTileEntity.setOnFire(); - // aBaseMetaTileEntity.setMetaTileEntity(GregTech_API.METATILEENTITIES[newMeta]); - // return; - //}else{ - aBaseMetaTileEntity.setToFire(); - //} - }else if (mOverheat>0) mOverheat--; - - mTransferredVoltageOK=mTransferredVoltage; - mTransferredVoltage=0; - mTransferredAmperageOK=mTransferredAmperage; - mTransferredAmperage = 0; - - if (aTick % 20 == 0) { - mTransferredVoltageLast20OK=mTransferredVoltageLast20; - mTransferredVoltageLast20 = 0; - mTransferredAmperageLast20OK=mTransferredAmperageLast20; - mTransferredAmperageLast20 = 0; - if (!GT_Mod.gregtechproxy.gt6Cable || mCheckConnections) checkConnections(); - } - } - } - - @Override public boolean onWireCutterRightClick(byte aSide, byte aWrenchingSide, EntityPlayer aPlayer, float aX, float aY, float aZ) { if (GT_Mod.gregtechproxy.gt6Cable && GT_ModHandler.damageOrDechargeItem(aPlayer.inventory.getCurrentItem(), 1, 500, aPlayer)) { if(isConnectedAtSide(aWrenchingSide)) { @@ -506,15 +352,23 @@ public class GT_MetaPipeEntity_Cable extends MetaPipeEntity implements IMetaTile @Override public String[] getInfoData() { + BaseMetaPipeEntity base = (BaseMetaPipeEntity) getBaseMetaTileEntity(); + PowerNodePath path =(PowerNodePath) base.getNodePath(); + int amps = 0; + int volts = 0; + if (path != null) { + amps = path.getAmps(); + volts = path.getVoltage(this); + } return new String[]{ //EnumChatFormatting.BLUE + mName + EnumChatFormatting.RESET, "Heat: "+ EnumChatFormatting.RED+ mOverheat +EnumChatFormatting.RESET+" / "+EnumChatFormatting.YELLOW+ mMaxOverheat + EnumChatFormatting.RESET, "Max Load (1t):", - EnumChatFormatting.GREEN + Integer.toString(mTransferredAmperageOK) + EnumChatFormatting.RESET +" A / "+ + EnumChatFormatting.GREEN + Integer.toString(amps) + EnumChatFormatting.RESET +" A / "+ EnumChatFormatting.YELLOW + mAmperage + EnumChatFormatting.RESET +" A", "Max EU/p (1t):", - EnumChatFormatting.GREEN + Long.toString(mTransferredVoltageOK) + EnumChatFormatting.RESET +" EU / "+ + EnumChatFormatting.GREEN + Long.toString(volts) + EnumChatFormatting.RESET +" EU / "+ EnumChatFormatting.YELLOW + mVoltage + EnumChatFormatting.RESET +" EU", "Max Load (20t): "+ EnumChatFormatting.GREEN + mTransferredAmperageLast20OK + EnumChatFormatting.RESET +" A", diff --git a/src/main/java/gregtech/api/threads/GT_Runnable_Cable_Update.java b/src/main/java/gregtech/api/threads/GT_Runnable_Cable_Update.java new file mode 100644 index 0000000000..7093184533 --- /dev/null +++ b/src/main/java/gregtech/api/threads/GT_Runnable_Cable_Update.java @@ -0,0 +1,69 @@ +package gregtech.api.threads; + +import gregtech.GT_Mod; +import gregtech.api.interfaces.tileentity.IMachineBlockUpdateable; +import gregtech.api.metatileentity.BaseMetaPipeEntity; +import gregtech.api.metatileentity.implementations.GT_MetaPipeEntity_Cable; +import gregtech.common.GT_Proxy; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ChunkCoordinates; +import net.minecraft.world.World; +import net.minecraftforge.common.util.ForgeDirection; + +public class GT_Runnable_Cable_Update extends GT_Runnable_MachineBlockUpdate { + protected GT_Runnable_Cable_Update(World aWorld, ChunkCoordinates aCoords) { + super(aWorld, aCoords); + } + + public static void setCableUpdateValues(World aWorld, ChunkCoordinates aCoords) { + if (isEnabled) { + EXECUTOR_SERVICE.submit(new GT_Runnable_Cable_Update(aWorld, aCoords)); + } + } + + @Override + public void run() { + try { + while (!tQueue.isEmpty()) { + final ChunkCoordinates aCoords = tQueue.poll(); + final TileEntity tTileEntity; + + GT_Proxy.TICK_LOCK.lock(); + try { + //we dont want to go over cables that are in unloaded chunks + //keeping the lock just to make sure no CME happens + if (world.blockExists(aCoords.posX, aCoords.posY, aCoords.posZ)) { + tTileEntity = world.getTileEntity(aCoords.posX, aCoords.posY, aCoords.posZ); + } else { + tTileEntity = null; + } + } finally { + GT_Proxy.TICK_LOCK.unlock(); + } + + // See if the block itself needs an update + if (tTileEntity instanceof IMachineBlockUpdateable) + ((IMachineBlockUpdateable) tTileEntity).onMachineBlockUpdate(); + + // Now see if we should add the nearby blocks to the queue: + // only add blocks the cable is connected to + if (tTileEntity instanceof BaseMetaPipeEntity && + ((BaseMetaPipeEntity) tTileEntity).getMetaTileEntity() instanceof GT_MetaPipeEntity_Cable) + { + ChunkCoordinates tCoords; + for (byte i = 0;i<6;i++) { + if (((GT_MetaPipeEntity_Cable) ((BaseMetaPipeEntity) tTileEntity).getMetaTileEntity()).isConnectedAtSide(i)) { + ForgeDirection offset = ForgeDirection.getOrientation(i); + if (visited.add(tCoords = new ChunkCoordinates(aCoords.posX + offset.offsetX, + aCoords.posY + offset.offsetY, aCoords.posZ + offset.offsetZ))) + tQueue.add(tCoords); + } + } + } + } + } catch (Exception e) { + GT_Mod.GT_FML_LOGGER.error( + "Well this update was broken... " + mCoords + ", mWorld={" + world.getProviderName() + " @dimId " + world.provider.dimensionId + "}", e); + } + } +} diff --git a/src/main/java/gregtech/api/threads/GT_Runnable_MachineBlockUpdate.java b/src/main/java/gregtech/api/threads/GT_Runnable_MachineBlockUpdate.java index 3ce1daf9b2..cc224b977d 100644 --- a/src/main/java/gregtech/api/threads/GT_Runnable_MachineBlockUpdate.java +++ b/src/main/java/gregtech/api/threads/GT_Runnable_MachineBlockUpdate.java @@ -19,10 +19,10 @@ import java.util.concurrent.TimeUnit; public class GT_Runnable_MachineBlockUpdate implements Runnable { // used by runner thread - private final ChunkCoordinates mCoords; - private final World world; - private final Set<ChunkCoordinates> visited = new HashSet<>(80); - private final Queue<ChunkCoordinates> tQueue = new LinkedList<>(); + protected final ChunkCoordinates mCoords; + protected final World world; + protected final Set<ChunkCoordinates> visited = new HashSet<>(80); + protected final Queue<ChunkCoordinates> tQueue = new LinkedList<>(); // Threading private static final ThreadFactory THREAD_FACTORY = r -> { @@ -30,15 +30,14 @@ public class GT_Runnable_MachineBlockUpdate implements Runnable { thread.setName("GT_MachineBlockUpdate"); return thread; }; - private static ExecutorService EXECUTOR_SERVICE; + protected static ExecutorService EXECUTOR_SERVICE; // This class should never be initiated outside of this class! - private GT_Runnable_MachineBlockUpdate(World aWorld, ChunkCoordinates aCoords) { + protected GT_Runnable_MachineBlockUpdate(World aWorld, ChunkCoordinates aCoords) { this.world = aWorld; this.mCoords = aCoords; visited.add(aCoords); tQueue.add(aCoords); - } public static boolean isEnabled() { @@ -57,11 +56,10 @@ public class GT_Runnable_MachineBlockUpdate implements Runnable { GT_Runnable_MachineBlockUpdate.isEnabled = isEnabled; } - private static boolean isEnabled = true; + protected static boolean isEnabled = true; public static void setMachineUpdateValues(World aWorld, ChunkCoordinates aCoords) { if (isEnabled) { - aWorld.getTileEntity(aCoords.posX, aCoords.posY, aCoords.posZ); EXECUTOR_SERVICE.submit(new GT_Runnable_MachineBlockUpdate(aWorld, aCoords)); } } |