Skip to content

Commit 9681c3b

Browse files
authored
improve power substation power bank code (GregTechCEu#2753)
1 parent 80f389d commit 9681c3b

File tree

2 files changed

+148
-154
lines changed

2 files changed

+148
-154
lines changed

src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityPowerSubstation.java

Lines changed: 93 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import net.minecraft.util.text.TextFormatting;
4646
import net.minecraft.world.World;
4747
import net.minecraftforge.common.capabilities.Capability;
48+
import net.minecraftforge.common.util.Constants;
4849
import net.minecraftforge.fml.relauncher.Side;
4950
import net.minecraftforge.fml.relauncher.SideOnly;
5051

@@ -140,7 +141,7 @@ protected void formStructure(PatternMatchContext context) {
140141
if (this.energyBank == null) {
141142
this.energyBank = new PowerStationEnergyBank(parts);
142143
} else {
143-
this.energyBank = energyBank.rebuild(parts);
144+
this.energyBank.rebuild(parts);
144145
}
145146
this.passiveDrain = this.energyBank.getPassiveDrainPerTick();
146147
}
@@ -603,175 +604,150 @@ public static class PowerStationEnergyBank {
603604
private static final String NBT_SIZE = "Size";
604605
private static final String NBT_STORED = "Stored";
605606
private static final String NBT_MAX = "Max";
606-
607-
private final long[] storage;
608-
private final long[] maximums;
609-
private final BigInteger capacity;
610-
private int index;
607+
// the following two fields represent ((a[0] << 63) | a[1])
608+
private final long[] stored = new long[2];
609+
private final long[] max = new long[2];
610+
private BigInteger capacity;
611+
private long drain;
612+
private long drainMod;
611613

612614
public PowerStationEnergyBank(List<IBatteryData> batteries) {
613-
storage = new long[batteries.size()];
614-
maximums = new long[batteries.size()];
615-
for (int i = 0; i < batteries.size(); i++) {
616-
maximums[i] = batteries.get(i).getCapacity();
615+
for (IBatteryData i : batteries) {
616+
add(max, i.getCapacity());
617+
updateDrain(i.getCapacity());
617618
}
618-
capacity = summarize(maximums);
619+
capacity = summarize(max);
619620
}
620621

621622
public PowerStationEnergyBank(NBTTagCompound storageTag) {
622-
int size = storageTag.getInteger(NBT_SIZE);
623-
storage = new long[size];
624-
maximums = new long[size];
625-
for (int i = 0; i < size; i++) {
626-
NBTTagCompound subtag = storageTag.getCompoundTag(String.valueOf(i));
627-
if (subtag.hasKey(NBT_STORED)) {
628-
storage[i] = subtag.getLong(NBT_STORED);
623+
// legacy nbt handling
624+
if (storageTag.hasKey(NBT_SIZE, Constants.NBT.TAG_INT)) {
625+
int size = storageTag.getInteger(NBT_SIZE);
626+
for (int i = 0; i < size; i++) {
627+
NBTTagCompound tag = storageTag.getCompoundTag(String.valueOf(i));
628+
if (tag.hasKey(NBT_STORED)) add(stored, tag.getLong(NBT_STORED));
629+
long store = tag.getLong(NBT_MAX);
630+
add(max, store);
631+
updateDrain(store);
629632
}
630-
maximums[i] = subtag.getLong(NBT_MAX);
633+
} else {
634+
stored[0] = storageTag.getLong(NBT_STORED + "0");
635+
stored[1] = storageTag.getLong(NBT_STORED + "1");
636+
drain = storageTag.getLong("drain");
637+
drainMod = storageTag.getLong("drainMod");
631638
}
632-
capacity = summarize(maximums);
639+
capacity = summarize(max);
640+
}
641+
642+
public NBTTagCompound writeToNBT(NBTTagCompound compound) {
643+
compound.setLong(NBT_STORED + "0", stored[0]);
644+
compound.setLong(NBT_STORED + "1", stored[1]);
645+
compound.setLong("drain", drain);
646+
compound.setLong("drainMod", drainMod);
647+
return compound;
633648
}
634649

635-
private NBTTagCompound writeToNBT(NBTTagCompound compound) {
636-
compound.setInteger(NBT_SIZE, storage.length);
637-
for (int i = 0; i < storage.length; i++) {
638-
NBTTagCompound subtag = new NBTTagCompound();
639-
if (storage[i] > 0) {
640-
subtag.setLong(NBT_STORED, storage[i]);
650+
private void updateDrain(long val) {
651+
if (val / PASSIVE_DRAIN_DIVISOR >= PASSIVE_DRAIN_MAX_PER_STORAGE) {
652+
drain += PASSIVE_DRAIN_MAX_PER_STORAGE;
653+
} else {
654+
drain += val / PASSIVE_DRAIN_DIVISOR;
655+
drainMod += (val % PASSIVE_DRAIN_DIVISOR);
656+
if (drainMod >= PASSIVE_DRAIN_DIVISOR) {
657+
drain++;
658+
drainMod -= PASSIVE_DRAIN_DIVISOR;
641659
}
642-
subtag.setLong(NBT_MAX, maximums[i]);
643-
compound.setTag(String.valueOf(i), subtag);
644660
}
645-
return compound;
646661
}
647662

648663
/**
649664
* Rebuild the power storage with a new list of batteries.
650665
* Will use existing stored power and try to map it onto new batteries.
651666
* If there was more power before the rebuild operation, it will be lost.
652667
*/
653-
public PowerStationEnergyBank rebuild(@NotNull List<IBatteryData> batteries) {
668+
public void rebuild(@NotNull List<IBatteryData> batteries) {
654669
if (batteries.isEmpty()) {
655670
throw new IllegalArgumentException("Cannot rebuild Power Substation power bank with no batteries!");
656671
}
657-
PowerStationEnergyBank newStorage = new PowerStationEnergyBank(batteries);
658-
for (long stored : storage) {
659-
newStorage.fill(stored);
672+
Arrays.fill(max, 0);
673+
drain = 0;
674+
for (IBatteryData i : batteries) {
675+
add(max, i.getCapacity());
676+
updateDrain(i.getCapacity());
677+
}
678+
679+
if (stored[0] > max[0]) {
680+
stored[0] = max[0];
681+
stored[1] = max[1];
682+
} else if (stored[0] == max[0]) {
683+
stored[1] = Math.min(stored[1], max[1]);
660684
}
661-
return newStorage;
685+
capacity = summarize(max);
662686
}
663687

664688
/** @return Amount filled into storage */
665689
public long fill(long amount) {
666690
if (amount < 0) throw new IllegalArgumentException("Amount cannot be negative!");
667-
668-
// ensure index
669-
if (index != storage.length - 1 && storage[index] == maximums[index]) {
670-
index++;
691+
// can't overflow, just add normally
692+
if (max[0] == stored[0]) {
693+
amount = Math.min(max[1] - stored[1], amount);
694+
stored[1] += amount;
695+
return amount;
671696
}
672-
673-
long maxFill = Math.min(maximums[index] - storage[index], amount);
674-
675-
// storage is completely full
676-
if (maxFill == 0 && index == storage.length - 1) {
677-
return 0;
678-
}
679-
680-
// fill this "battery" as much as possible
681-
storage[index] += maxFill;
682-
amount -= maxFill;
683-
684-
// try to fill other "batteries" if necessary
685-
if (amount > 0 && index != storage.length - 1) {
686-
return maxFill + fill(amount);
697+
if (stored[1] + amount < 0) {
698+
stored[0]++;
699+
stored[1] += Long.MIN_VALUE;
700+
if (max[0] == stored[0] && max[1] < stored[1] + amount) {
701+
amount = max[1] - stored[1];
702+
}
687703
}
688-
689-
// other fill not necessary, either because the storage is now completely full,
690-
// or we were able to consume all the energy in this "battery"
691-
return maxFill;
704+
stored[1] += amount;
705+
return amount;
692706
}
693707

694708
/** @return Amount drained from storage */
695709
public long drain(long amount) {
696710
if (amount < 0) throw new IllegalArgumentException("Amount cannot be negative!");
697-
698-
// ensure index
699-
if (index != 0 && storage[index] == 0) {
700-
index--;
711+
// cant borrow, just subtract normally
712+
if (stored[0] == 0) {
713+
long sub = Math.min(stored[1], amount);
714+
stored[1] -= sub;
715+
return sub;
701716
}
702-
703-
long maxDrain = Math.min(storage[index], amount);
704-
705-
// storage is completely empty
706-
if (maxDrain == 0 && index == 0) {
707-
return 0;
708-
}
709-
710-
// drain this "battery" as much as possible
711-
storage[index] -= maxDrain;
712-
amount -= maxDrain;
713-
714-
// try to drain other "batteries" if necessary
715-
if (amount > 0 && index != 0) {
716-
index--;
717-
return maxDrain + drain(amount);
718-
}
719-
720-
// other drain not necessary, either because the storage is now completely empty,
721-
// or we were able to drain all the energy from this "battery"
722-
return maxDrain;
717+
if (stored[1] < amount) {
718+
stored[0]--;
719+
stored[1] -= amount + Long.MIN_VALUE;
720+
} else stored[1] -= amount;
721+
return amount;
723722
}
724723

725724
public BigInteger getCapacity() {
726725
return capacity;
727726
}
728727

729728
public BigInteger getStored() {
730-
return summarize(storage);
729+
return summarize(stored);
731730
}
732731

733732
public boolean hasEnergy() {
734-
for (long l : storage) {
735-
if (l > 0) return true;
736-
}
737-
return false;
733+
return stored[0] != 0 && stored[1] != 0;
738734
}
739735

740-
private static BigInteger summarize(long[] values) {
741-
BigInteger retVal = BigInteger.ZERO;
742-
long currentSum = 0;
743-
for (long value : values) {
744-
if (currentSum != 0 && value > Long.MAX_VALUE - currentSum) {
745-
// will overflow if added
746-
retVal = retVal.add(BigInteger.valueOf(currentSum));
747-
currentSum = 0;
748-
}
749-
currentSum += value;
750-
}
751-
if (currentSum != 0) {
752-
retVal = retVal.add(BigInteger.valueOf(currentSum));
736+
private static BigInteger summarize(long[] num) {
737+
return BigInteger.valueOf(num[0]).shiftLeft(63).add(BigInteger.valueOf(num[1]));
738+
}
739+
740+
private static void add(long[] num, long val) {
741+
num[1] += val;
742+
if (num[1] < 0) {
743+
num[0]++;
744+
num[1] -= Long.MIN_VALUE;
753745
}
754-
return retVal;
755746
}
756747

757748
@VisibleForTesting
758749
public long getPassiveDrainPerTick() {
759-
long[] maximumsExcl = new long[maximums.length];
760-
int index = 0;
761-
int numExcl = 0;
762-
for (long maximum : maximums) {
763-
if (maximum / PASSIVE_DRAIN_DIVISOR >= PASSIVE_DRAIN_MAX_PER_STORAGE) {
764-
numExcl++;
765-
} else {
766-
maximumsExcl[index++] = maximum;
767-
}
768-
}
769-
maximumsExcl = Arrays.copyOf(maximumsExcl, index);
770-
BigInteger capacityExcl = summarize(maximumsExcl);
771-
772-
return capacityExcl.divide(BigInteger.valueOf(PASSIVE_DRAIN_DIVISOR))
773-
.add(BigInteger.valueOf(PASSIVE_DRAIN_MAX_PER_STORAGE * numExcl))
774-
.longValue();
750+
return drain;
775751
}
776752
}
777753

0 commit comments

Comments
 (0)