Skip to content

Commit cd760d4

Browse files
Improve AE upgrade installation (#49)
1 parent 0e02322 commit cd760d4

File tree

5 files changed

+155
-57
lines changed

5 files changed

+155
-57
lines changed

src/main/java/com/recursive_pineapple/matter_manipulator/common/building/AEAnalysisResult.java

+11-3
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,8 @@ public boolean apply(IBlockApplyContext ctx) {
151151
customName.setCustomName(mAECustomName);
152152
}
153153

154+
boolean success = true;
155+
154156
// add/remove/update ae parts and cables
155157
if (te instanceof IPartHost partHost && mAEParts != null) {
156158
for (ForgeDirection dir : AEAnalysisResult.ALL_DIRECTIONS) {
@@ -189,19 +191,25 @@ public boolean apply(IBlockApplyContext ctx) {
189191
continue;
190192
}
191193

192-
if (!installPart(ctx, partHost, dir, expected, false)) { return false; }
194+
if (!installPart(ctx, partHost, dir, expected, false)) {
195+
success = false;
196+
continue;
197+
}
193198
}
194199
}
195200

196201
if (expected != null) {
197-
if (!expected.updatePart(ctx, partHost, dir)) { return false; }
202+
if (!expected.updatePart(ctx, partHost, dir)) {
203+
success = false;
204+
continue;
205+
}
198206
}
199207

200208
Platform.notifyBlocksOfNeighbors(te.getWorldObj(), te.xCoord, te.yCoord, te.zCoord);
201209
}
202210
}
203211

204-
return true;
212+
return success;
205213
}
206214

207215
private void removePart(IBlockApplyContext context, IPartHost partHost, ForgeDirection side, boolean simulate) {

src/main/java/com/recursive_pineapple/matter_manipulator/common/building/AEPartData.java

+15-30
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,8 @@ public boolean isAttunable() {
143143
public boolean updatePart(IBlockApplyContext context, IPartHost partHost, ForgeDirection side) {
144144
IPart part = partHost.getPart(side);
145145

146+
boolean success = true;
147+
146148
if (part instanceof PartP2PTunnelNormal && isAttunable()) {
147149
partHost.removePart(side, true);
148150

@@ -154,8 +156,8 @@ public boolean updatePart(IBlockApplyContext context, IPartHost partHost, ForgeD
154156
tunnel.output = mP2POutput;
155157

156158
try {
157-
final P2PCache p2p = tunnel.getProxy()
158-
.getP2P();
159+
final P2PCache p2p = tunnel.getProxy().getP2P();
160+
159161
// calls setFrequency
160162
p2p.updateFreq(tunnel, mP2PFreq);
161163
} catch (final GridAccessException e) {
@@ -172,33 +174,24 @@ public boolean updatePart(IBlockApplyContext context, IPartHost partHost, ForgeD
172174

173175
if (part instanceof IConfigurableObject configurable && configurable.getConfigManager() != null) {
174176
NBTTagCompound settings = mSettings == null ? new NBTTagCompound() : mSettings;
175-
configurable.getConfigManager()
176-
.readFromNBT(settings);
177+
configurable.getConfigManager().readFromNBT(settings);
177178
}
178179

179180
if (part instanceof ISegmentedInventory segmentedInventory) {
180181
if (segmentedInventory.getInventoryByName("upgrades") instanceof UpgradeInventory upgradeInv) {
181-
ItemStackMap<Long> targetMap = MMUtils.getItemStackHistogram(
182-
Arrays.stream(mAEUpgrades)
183-
.map(PortableItemStack::toStack)
184-
.collect(Collectors.toList())
185-
);
186-
ItemStackMap<Long> actualMap = MMUtils
187-
.getItemStackHistogram(Arrays.asList(MMUtils.inventoryToArray(upgradeInv)));
188-
189-
if (!targetMap.equals(actualMap)) {
190-
if (!MMUtils.installUpgrades(context, upgradeInv, mAEUpgrades, true, false)) { return false; }
182+
if (!MMUtils.installUpgrades(context, upgradeInv, mAEUpgrades, true, false)) {
183+
success = false;
191184
}
192185
}
193186

194187
IInventory config = segmentedInventory.getInventoryByName("config");
195188
if (config != null) {
196-
mConfig.apply(context, config, false, false);
189+
if (!mConfig.apply(context, config, false, false)) success = false;
197190
}
198191

199192
IInventory patterns = segmentedInventory.getInventoryByName("patterns");
200193
if (mAEPatterns != null && patterns != null) {
201-
mAEPatterns.apply(context, patterns, true, false);
194+
if (!mAEPatterns.apply(context, patterns, true, false)) success = false;
202195
}
203196
}
204197

@@ -210,7 +203,7 @@ public boolean updatePart(IBlockApplyContext context, IPartHost partHost, ForgeD
210203
priorityHost.setPriority(priority);
211204
}
212205

213-
return true;
206+
return success;
214207
}
215208

216209
/**
@@ -226,28 +219,20 @@ public boolean getRequiredItemsForExistingPart(
226219
) {
227220
IPart part = partHost.getPart(side);
228221

222+
boolean success = true;
223+
229224
if (part instanceof ISegmentedInventory segmentedInventory) {
230225
if (segmentedInventory.getInventoryByName("upgrades") instanceof UpgradeInventory upgradeInv) {
231-
ItemStackMap<Long> targetMap = MMUtils.getItemStackHistogram(
232-
Arrays.stream(mAEUpgrades)
233-
.map(PortableItemStack::toStack)
234-
.collect(Collectors.toList())
235-
);
236-
ItemStackMap<Long> actualMap = MMUtils
237-
.getItemStackHistogram(Arrays.asList(MMUtils.inventoryToArray(upgradeInv)));
238-
239-
if (!targetMap.equals(actualMap)) {
240-
if (!MMUtils.installUpgrades(context, upgradeInv, mAEUpgrades, true, true)) { return false; }
241-
}
226+
if (!MMUtils.installUpgrades(context, upgradeInv, mAEUpgrades, true, false)) success = false;
242227
}
243228

244229
IInventory patterns = segmentedInventory.getInventoryByName("patterns");
245230
if (mAEPatterns != null && patterns != null) {
246-
mAEPatterns.apply(context, patterns, true, true);
231+
if (!mAEPatterns.apply(context, patterns, true, true)) success = false;
247232
}
248233
}
249234

250-
return true;
235+
return success;
251236
}
252237

253238
/**

src/main/java/com/recursive_pineapple/matter_manipulator/common/building/MMInventory.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public class MMInventory implements IPseudoInventory {
6060

6161
private boolean printedUplinkWarning = false;
6262

63-
private HashSet<IStorageGrid> visitedGrids = new HashSet<>();
63+
private final HashSet<IStorageGrid> visitedGrids = new HashSet<>();
6464

6565
public MMInventory(EntityPlayer player, MMState state, ManipulatorTier tier) {
6666
this.player = player;

src/main/java/com/recursive_pineapple/matter_manipulator/common/utils/ItemId.java

+11
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
import static net.minecraftforge.common.util.Constants.NBT.TAG_COMPOUND;
55
import static net.minecraftforge.common.util.Constants.NBT.TAG_INT;
66

7+
import java.util.Objects;
8+
79
import javax.annotation.Nonnull;
810
import javax.annotation.Nullable;
911

@@ -168,4 +170,13 @@ public ItemStack getItemStack(int stackSize) {
168170
itemStack.setTagCompound(nbt == null ? null : (NBTTagCompound) nbt.copy());
169171
return itemStack;
170172
}
173+
174+
public boolean isSameAs(ItemStack stack) {
175+
if (stack == null) return false;
176+
if (item() != stack.getItem()) return false;
177+
if (metaData() != Items.feather.getDamage(stack)) return false;
178+
if (!Objects.equals(nbt(), stack.getTagCompound())) return false;
179+
180+
return true;
181+
}
171182
}

src/main/java/com/recursive_pineapple/matter_manipulator/common/utils/MMUtils.java

+117-23
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import java.util.Base64;
2424
import java.util.Collection;
2525
import java.util.HashMap;
26+
import java.util.HashSet;
2627
import java.util.Iterator;
2728
import java.util.List;
2829
import java.util.Locale;
@@ -31,6 +32,7 @@
3132
import java.util.UUID;
3233
import java.util.function.Function;
3334
import java.util.function.IntFunction;
35+
import java.util.stream.Collectors;
3436
import java.util.stream.IntStream;
3537
import java.util.stream.Stream;
3638

@@ -72,6 +74,7 @@
7274
import net.minecraftforge.common.util.ForgeDirection;
7375
import net.minecraftforge.fluids.IFluidHandler;
7476

77+
import com.recursive_pineapple.matter_manipulator.MMMod;
7578
import cpw.mods.fml.relauncher.ReflectionHelper;
7679

7780
import gregtech.api.GregTechAPI;
@@ -100,10 +103,10 @@
100103
import com.google.gson.JsonObject;
101104
import com.google.gson.JsonParseException;
102105
import com.google.gson.JsonPrimitive;
103-
import com.gtnewhorizon.gtnhlib.util.map.ItemStackMap;
104106
import com.gtnewhorizon.structurelib.util.XSTR;
105107
import com.recursive_pineapple.matter_manipulator.asm.Optional;
106108
import com.recursive_pineapple.matter_manipulator.common.building.BlockAnalyzer;
109+
import com.recursive_pineapple.matter_manipulator.common.building.BlockAnalyzer.IBlockApplyContext;
107110
import com.recursive_pineapple.matter_manipulator.common.building.BlockAnalyzer.RequiredItemAnalysis;
108111
import com.recursive_pineapple.matter_manipulator.common.building.BlockSpec;
109112
import com.recursive_pineapple.matter_manipulator.common.building.IPseudoInventory;
@@ -120,6 +123,7 @@
120123
import org.joml.Vector3i;
121124

122125
import it.unimi.dsi.fastutil.Pair;
126+
import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap;
123127

124128
public class MMUtils {
125129

@@ -444,34 +448,58 @@ public static EntityPlayer getPlayerById(UUID playerId) {
444448
return null;
445449
}
446450

447-
public static ItemStackMap<Long> getItemStackHistogram(Iterable<ItemStack> stacks) {
451+
public static Object2LongOpenHashMap<ItemId> getItemStackHistogram(Iterable<ItemStack> stacks) {
448452
return getItemStackHistogram(stacks, true);
449453
}
450454

451-
public static ItemStackMap<Long> getItemStackHistogram(Iterable<ItemStack> stacks, boolean NBTSensitive) {
452-
ItemStackMap<Long> histogram = new ItemStackMap<>(NBTSensitive);
455+
public static Object2LongOpenHashMap<ItemId> getItemStackHistogram(Iterable<ItemStack> stacks, boolean NBTSensitive) {
456+
Object2LongOpenHashMap<ItemId> histogram = new Object2LongOpenHashMap<>();
453457

454458
if (stacks == null) return histogram;
455459

456460
for (ItemStack stack : stacks) {
457461
if (stack == null || stack.getItem() == null) continue;
458-
histogram.merge(stack, (long) stack.stackSize, (Long a, Long b) -> a + b);
462+
histogram.addTo(ItemId.create(stack), stack.stackSize);
459463
}
460464

461465
return histogram;
462466
}
463467

464-
public static List<ItemStack> getStacksOfSize(ItemStackMap<Long> map, int maxStackSize) {
468+
public static class StackMapDiff {
469+
public Object2LongOpenHashMap<ItemId> added = new Object2LongOpenHashMap<>();
470+
public Object2LongOpenHashMap<ItemId> removed = new Object2LongOpenHashMap<>();
471+
}
472+
473+
public static StackMapDiff getStackMapDiff(Object2LongOpenHashMap<ItemId> before, Object2LongOpenHashMap<ItemId> after) {
474+
HashSet<ItemId> keys = new HashSet<>();
475+
keys.addAll(before.keySet());
476+
keys.addAll(after.keySet());
477+
478+
StackMapDiff diff = new StackMapDiff();
479+
480+
for (ItemId id : keys) {
481+
long beforeAmount = before.getLong(id);
482+
long afterAmount = after.getLong(id);
483+
484+
if (afterAmount < beforeAmount) {
485+
diff.removed.addTo(id, beforeAmount - afterAmount);
486+
} else if (beforeAmount < afterAmount) {
487+
diff.added.addTo(id, afterAmount - beforeAmount);
488+
}
489+
}
490+
491+
return diff;
492+
}
493+
494+
public static List<ItemStack> getStacksOfSize(Object2LongOpenHashMap<ItemId> map, int maxStackSize) {
465495
ArrayList<ItemStack> list = new ArrayList<>();
466496

467497
map.forEach((item, amount) -> {
468498
while (amount > 0) {
469499
int toRemove = Math
470500
.min(amount > Integer.MAX_VALUE ? Integer.MAX_VALUE : amount.intValue(), maxStackSize);
471501

472-
ItemStack copy = item.copy();
473-
copy.stackSize = toRemove;
474-
list.add(copy);
502+
list.add(item.getItemStack(toRemove));
475503

476504
amount -= toRemove;
477505
}
@@ -775,35 +803,101 @@ public static boolean installUpgrades(
775803
boolean consume,
776804
boolean simulate
777805
) {
806+
boolean success = true;
807+
778808
List<ItemStack> stacks = mapToList(pupgrades, PortableItemStack::toStack);
779809

780810
stacks.removeIf(i -> i == null || !(i.getItem() instanceof IUpgradeModule));
781811

782812
for (ItemStack stack : stacks) {
783-
stack.stackSize = Math
784-
.min(stack.stackSize, dest.getMaxInstalled(((IUpgradeModule) stack.getItem()).getType(stack)));
813+
stack.stackSize = Math.min(stack.stackSize, dest.getMaxInstalled(((IUpgradeModule) stack.getItem()).getType(stack)));
814+
}
815+
816+
Object2LongOpenHashMap<ItemId> actual = getItemStackHistogram(Arrays.asList(inventoryToArray(dest)));
817+
Object2LongOpenHashMap<ItemId> target = getItemStackHistogram(stacks);
818+
819+
StackMapDiff diff = getStackMapDiff(actual, target);
820+
821+
if (diff.removed.isEmpty() && diff.added.isEmpty()) return success;
822+
823+
List<ItemStack> toInstall = getStacksOfSize(diff.added, dest.getInventoryStackLimit());
824+
825+
long installable = dest.getSizeInventory() - actual.values().longStream().sum() + diff.removed.values().longStream().sum();
826+
827+
List<BigItemStack> toInstallBig = toInstall.subList(0, Math.min(toInstall.size(), (int) installable))
828+
.stream()
829+
.map(BigItemStack::new)
830+
.collect(Collectors.toList());
831+
832+
var result = src.tryConsumeItems(toInstallBig, IPseudoInventory.CONSUME_PARTIAL);
833+
834+
List<BigItemStack> extracted = result.right();
835+
836+
for (BigItemStack wanted : toInstallBig) {
837+
for (BigItemStack found : extracted) {
838+
if (!found.isSameType(wanted)) continue;
839+
840+
wanted.stackSize -= found.stackSize;
841+
}
785842
}
786843

787-
List<ItemStack> split = getStacksOfSize(stacks, dest.getInventoryStackLimit());
844+
if (src instanceof IBlockApplyContext ctx) {
845+
for (BigItemStack wanted : toInstallBig) {
846+
if (wanted.stackSize > 0) {
847+
ctx.warn("Could not find upgrade: " + wanted.getItemStack().getDisplayName() + " x " + wanted.stackSize);
848+
success = false;
849+
}
850+
}
851+
}
788852

789-
ItemStack[] upgrades = split.subList(0, Math.min(split.size(), dest.getSizeInventory()))
790-
.toArray(new ItemStack[0]);
853+
if (!simulate) {
854+
for (var e : diff.removed.object2LongEntrySet()) {
855+
long amount = e.getLongValue();
791856

792-
if (!consume || src.tryConsumeItems(upgrades)) {
793-
if (!simulate) {
794-
emptyInventory(src, dest);
857+
for (int slot = 0; slot < dest.getSizeInventory(); slot++) {
858+
if (amount <= 0) break;
795859

796-
for (int i = 0; i < upgrades.length; i++) {
797-
dest.setInventorySlotContents(i, upgrades[i]);
860+
ItemStack inSlot = dest.getStackInSlot(slot);
861+
862+
if (e.getKey().isSameAs(inSlot)) {
863+
src.givePlayerItems(inSlot);
864+
dest.setInventorySlotContents(slot, null);
865+
866+
amount--;
867+
}
798868
}
869+
}
870+
871+
int slot = 0;
799872

800-
dest.markDirty();
873+
outer: for (BigItemStack stack : extracted) {
874+
for (ItemStack split : stack.toStacks(1)) {
875+
while (dest.getStackInSlot(slot) != null) {
876+
slot++;
877+
878+
if (slot >= dest.getSizeInventory()) {
879+
MMMod.LOG.error(
880+
"Tried to install too many upgrades: voiding the rest. Dest={}, upgrade={}, slot={}",
881+
dest,
882+
split,
883+
slot,
884+
new Exception());
885+
886+
if (src instanceof IBlockApplyContext ctx) {
887+
ctx.error("Tried to install too many upgrades: voiding the rest (this is a bug, please report it)");
888+
}
889+
break outer;
890+
}
891+
}
892+
893+
dest.setInventorySlotContents(slot++, split);
894+
}
801895
}
802896

803-
return true;
804-
} else {
805-
return false;
897+
dest.markDirty();
806898
}
899+
900+
return success;
807901
}
808902

809903
public static NBTTagCompound copy(NBTTagCompound tag) {

0 commit comments

Comments
 (0)