aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/gregtech/api/graphs/PowerNodes.java
blob: 7a3364648adae4ec5f54e3a71ee80ff60eb4c26a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
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 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, 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--) {
                    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, 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 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, 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 long processNextNode(Node aCurrentNode, Node aNextNode, NodeList aConsumers, int aSide, long aMaxAmps, long aVoltage) {
        final PowerNodePath tPath = (PowerNodePath) aCurrentNode.mNodePaths[aSide];
        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 aSide, long aMaxAmps, long aVoltage) {
        final PowerNodePath tPath = (PowerNodePath) aCurrentNode.mNodePaths[aSide];
        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 aSide, long aMaxAmps, long aVoltage, boolean isUp) {
        final PowerNodePath tPath = (PowerNodePath) aCurrentNode.mNodePaths[aSide];
        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;
    }
}