|
45 | 45 | import net.minecraft.util.text.TextFormatting; |
46 | 46 | import net.minecraft.world.World; |
47 | 47 | import net.minecraftforge.common.capabilities.Capability; |
| 48 | +import net.minecraftforge.common.util.Constants; |
48 | 49 | import net.minecraftforge.fml.relauncher.Side; |
49 | 50 | import net.minecraftforge.fml.relauncher.SideOnly; |
50 | 51 |
|
@@ -140,7 +141,7 @@ protected void formStructure(PatternMatchContext context) { |
140 | 141 | if (this.energyBank == null) { |
141 | 142 | this.energyBank = new PowerStationEnergyBank(parts); |
142 | 143 | } else { |
143 | | - this.energyBank = energyBank.rebuild(parts); |
| 144 | + this.energyBank.rebuild(parts); |
144 | 145 | } |
145 | 146 | this.passiveDrain = this.energyBank.getPassiveDrainPerTick(); |
146 | 147 | } |
@@ -603,175 +604,150 @@ public static class PowerStationEnergyBank { |
603 | 604 | private static final String NBT_SIZE = "Size"; |
604 | 605 | private static final String NBT_STORED = "Stored"; |
605 | 606 | 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; |
611 | 613 |
|
612 | 614 | 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()); |
617 | 618 | } |
618 | | - capacity = summarize(maximums); |
| 619 | + capacity = summarize(max); |
619 | 620 | } |
620 | 621 |
|
621 | 622 | 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); |
629 | 632 | } |
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"); |
631 | 638 | } |
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; |
633 | 648 | } |
634 | 649 |
|
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; |
641 | 659 | } |
642 | | - subtag.setLong(NBT_MAX, maximums[i]); |
643 | | - compound.setTag(String.valueOf(i), subtag); |
644 | 660 | } |
645 | | - return compound; |
646 | 661 | } |
647 | 662 |
|
648 | 663 | /** |
649 | 664 | * Rebuild the power storage with a new list of batteries. |
650 | 665 | * Will use existing stored power and try to map it onto new batteries. |
651 | 666 | * If there was more power before the rebuild operation, it will be lost. |
652 | 667 | */ |
653 | | - public PowerStationEnergyBank rebuild(@NotNull List<IBatteryData> batteries) { |
| 668 | + public void rebuild(@NotNull List<IBatteryData> batteries) { |
654 | 669 | if (batteries.isEmpty()) { |
655 | 670 | throw new IllegalArgumentException("Cannot rebuild Power Substation power bank with no batteries!"); |
656 | 671 | } |
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]); |
660 | 684 | } |
661 | | - return newStorage; |
| 685 | + capacity = summarize(max); |
662 | 686 | } |
663 | 687 |
|
664 | 688 | /** @return Amount filled into storage */ |
665 | 689 | public long fill(long amount) { |
666 | 690 | 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; |
671 | 696 | } |
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 | + } |
687 | 703 | } |
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; |
692 | 706 | } |
693 | 707 |
|
694 | 708 | /** @return Amount drained from storage */ |
695 | 709 | public long drain(long amount) { |
696 | 710 | 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; |
701 | 716 | } |
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; |
723 | 722 | } |
724 | 723 |
|
725 | 724 | public BigInteger getCapacity() { |
726 | 725 | return capacity; |
727 | 726 | } |
728 | 727 |
|
729 | 728 | public BigInteger getStored() { |
730 | | - return summarize(storage); |
| 729 | + return summarize(stored); |
731 | 730 | } |
732 | 731 |
|
733 | 732 | 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; |
738 | 734 | } |
739 | 735 |
|
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; |
753 | 745 | } |
754 | | - return retVal; |
755 | 746 | } |
756 | 747 |
|
757 | 748 | @VisibleForTesting |
758 | 749 | 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; |
775 | 751 | } |
776 | 752 | } |
777 | 753 |
|
|
0 commit comments