Skip to content

Commit b68a119

Browse files
authored
Fix negative energy value crash (likely long overflow) (#108)
Fix negative energy value crash when using MI cables (likely long overflow)
1 parent 738cbe6 commit b68a119

File tree

2 files changed

+20
-8
lines changed

2 files changed

+20
-8
lines changed

src/main/java/dev/technici4n/moderndynamics/network/energy/EnergyCache.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,6 @@ public void doTick() {
113113
* Dispatch a transfer operation among a list of targets. Will not modify the list.
114114
*/
115115
public static int transferForTargets(TransferOperation operation, List<IEnergyStorage> targets, int maxAmount) {
116-
int intMaxAmount = Ints.saturatedCast(maxAmount);
117116
// Build target list
118117
List<EnergyTarget> sortableTargets = new ArrayList<>(targets.size());
119118
for (var target : targets) {
@@ -123,7 +122,7 @@ public static int transferForTargets(TransferOperation operation, List<IEnergySt
123122
Collections.shuffle(sortableTargets);
124123
// Simulate the transfer for every target
125124
for (EnergyTarget target : sortableTargets) {
126-
target.simulationResult = operation.transfer(target.target, intMaxAmount, true);
125+
target.simulationResult = operation.transfer(target.target, maxAmount, true);
127126
}
128127
// Sort from low to high result
129128
sortableTargets.sort(Comparator.comparingLong(t -> t.simulationResult));

src/main/java/dev/technici4n/moderndynamics/network/mienergy/MIEnergyCache.java

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
*/
1919
package dev.technici4n.moderndynamics.network.mienergy;
2020

21+
import com.google.common.base.Preconditions;
2122
import dev.technici4n.moderndynamics.network.NetworkCache;
2223
import dev.technici4n.moderndynamics.network.NetworkNode;
2324
import dev.technici4n.moderndynamics.network.energy.EnergyCache;
@@ -27,8 +28,8 @@
2728
import net.neoforged.neoforge.energy.IEnergyStorage;
2829

2930
public class MIEnergyCache extends NetworkCache<MIEnergyHost, MIEnergyCache> {
30-
private int energy = 0;
31-
private int maxEnergy = 0;
31+
private long energy = 0;
32+
private long maxEnergy = 0;
3233

3334
protected MIEnergyCache(ServerLevel level, List<NetworkNode<MIEnergyHost, MIEnergyCache>> networkNodes) {
3435
super(level, networkNodes);
@@ -39,8 +40,8 @@ protected void doCombine() {
3940
energy = maxEnergy = 0;
4041

4142
for (var node : nodes) {
42-
energy += node.getHost().getEnergy();
43-
maxEnergy += node.getHost().getMaxEnergy();
43+
energy = saturatedSum(energy, node.getHost().getEnergy());
44+
maxEnergy = saturatedSum(maxEnergy, node.getHost().getMaxEnergy());
4445
}
4546
}
4647

@@ -74,9 +75,21 @@ protected void doTick() {
7475

7576
var tier = nodes.get(0).getHost().tier;
7677

78+
// tier.getMax() is an int and energy is unsigned, so casting to (int) is safe
7779
// Extract
78-
energy += EnergyCache.transferForTargets(IEnergyStorage::extractEnergy, storages, Math.min(maxEnergy - energy, tier.getMax()));
80+
energy += EnergyCache.transferForTargets(IEnergyStorage::extractEnergy, storages, (int) Math.min(maxEnergy - energy, tier.getMax()));
7981
// Insert
80-
energy -= EnergyCache.transferForTargets(IEnergyStorage::receiveEnergy, storages, Math.min(energy, tier.getMax()));
82+
energy -= EnergyCache.transferForTargets(IEnergyStorage::receiveEnergy, storages, (int) Math.min(energy, tier.getMax()));
83+
}
84+
85+
// Energy is unsigned. Hence we handle only one case of satured addition (same sign)
86+
private static long saturatedSum(long a, long b) {
87+
Preconditions.checkArgument(a >= 0, "a >= 0");
88+
Preconditions.checkArgument(b >= 0, "b >= 0");
89+
var sum = a + b;
90+
if (sum < a || sum < b) {
91+
return Long.MAX_VALUE;
92+
}
93+
return sum;
8194
}
8295
}

0 commit comments

Comments
 (0)