Skip to content

Commit

Permalink
Improve AE upgrade installation (#49)
Browse files Browse the repository at this point in the history
  • Loading branch information
RecursivePineapple authored Feb 18, 2025
1 parent 0e02322 commit cd760d4
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 57 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@ public boolean apply(IBlockApplyContext ctx) {
customName.setCustomName(mAECustomName);
}

boolean success = true;

// add/remove/update ae parts and cables
if (te instanceof IPartHost partHost && mAEParts != null) {
for (ForgeDirection dir : AEAnalysisResult.ALL_DIRECTIONS) {
Expand Down Expand Up @@ -189,19 +191,25 @@ public boolean apply(IBlockApplyContext ctx) {
continue;
}

if (!installPart(ctx, partHost, dir, expected, false)) { return false; }
if (!installPart(ctx, partHost, dir, expected, false)) {
success = false;
continue;
}
}
}

if (expected != null) {
if (!expected.updatePart(ctx, partHost, dir)) { return false; }
if (!expected.updatePart(ctx, partHost, dir)) {
success = false;
continue;
}
}

Platform.notifyBlocksOfNeighbors(te.getWorldObj(), te.xCoord, te.yCoord, te.zCoord);
}
}

return true;
return success;
}

private void removePart(IBlockApplyContext context, IPartHost partHost, ForgeDirection side, boolean simulate) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,8 @@ public boolean isAttunable() {
public boolean updatePart(IBlockApplyContext context, IPartHost partHost, ForgeDirection side) {
IPart part = partHost.getPart(side);

boolean success = true;

if (part instanceof PartP2PTunnelNormal && isAttunable()) {
partHost.removePart(side, true);

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

try {
final P2PCache p2p = tunnel.getProxy()
.getP2P();
final P2PCache p2p = tunnel.getProxy().getP2P();

// calls setFrequency
p2p.updateFreq(tunnel, mP2PFreq);
} catch (final GridAccessException e) {
Expand All @@ -172,33 +174,24 @@ public boolean updatePart(IBlockApplyContext context, IPartHost partHost, ForgeD

if (part instanceof IConfigurableObject configurable && configurable.getConfigManager() != null) {
NBTTagCompound settings = mSettings == null ? new NBTTagCompound() : mSettings;
configurable.getConfigManager()
.readFromNBT(settings);
configurable.getConfigManager().readFromNBT(settings);
}

if (part instanceof ISegmentedInventory segmentedInventory) {
if (segmentedInventory.getInventoryByName("upgrades") instanceof UpgradeInventory upgradeInv) {
ItemStackMap<Long> targetMap = MMUtils.getItemStackHistogram(
Arrays.stream(mAEUpgrades)
.map(PortableItemStack::toStack)
.collect(Collectors.toList())
);
ItemStackMap<Long> actualMap = MMUtils
.getItemStackHistogram(Arrays.asList(MMUtils.inventoryToArray(upgradeInv)));

if (!targetMap.equals(actualMap)) {
if (!MMUtils.installUpgrades(context, upgradeInv, mAEUpgrades, true, false)) { return false; }
if (!MMUtils.installUpgrades(context, upgradeInv, mAEUpgrades, true, false)) {
success = false;
}
}

IInventory config = segmentedInventory.getInventoryByName("config");
if (config != null) {
mConfig.apply(context, config, false, false);
if (!mConfig.apply(context, config, false, false)) success = false;
}

IInventory patterns = segmentedInventory.getInventoryByName("patterns");
if (mAEPatterns != null && patterns != null) {
mAEPatterns.apply(context, patterns, true, false);
if (!mAEPatterns.apply(context, patterns, true, false)) success = false;
}
}

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

return true;
return success;
}

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

boolean success = true;

if (part instanceof ISegmentedInventory segmentedInventory) {
if (segmentedInventory.getInventoryByName("upgrades") instanceof UpgradeInventory upgradeInv) {
ItemStackMap<Long> targetMap = MMUtils.getItemStackHistogram(
Arrays.stream(mAEUpgrades)
.map(PortableItemStack::toStack)
.collect(Collectors.toList())
);
ItemStackMap<Long> actualMap = MMUtils
.getItemStackHistogram(Arrays.asList(MMUtils.inventoryToArray(upgradeInv)));

if (!targetMap.equals(actualMap)) {
if (!MMUtils.installUpgrades(context, upgradeInv, mAEUpgrades, true, true)) { return false; }
}
if (!MMUtils.installUpgrades(context, upgradeInv, mAEUpgrades, true, false)) success = false;
}

IInventory patterns = segmentedInventory.getInventoryByName("patterns");
if (mAEPatterns != null && patterns != null) {
mAEPatterns.apply(context, patterns, true, true);
if (!mAEPatterns.apply(context, patterns, true, true)) success = false;
}
}

return true;
return success;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public class MMInventory implements IPseudoInventory {

private boolean printedUplinkWarning = false;

private HashSet<IStorageGrid> visitedGrids = new HashSet<>();
private final HashSet<IStorageGrid> visitedGrids = new HashSet<>();

public MMInventory(EntityPlayer player, MMState state, ManipulatorTier tier) {
this.player = player;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import static net.minecraftforge.common.util.Constants.NBT.TAG_COMPOUND;
import static net.minecraftforge.common.util.Constants.NBT.TAG_INT;

import java.util.Objects;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

Expand Down Expand Up @@ -168,4 +170,13 @@ public ItemStack getItemStack(int stackSize) {
itemStack.setTagCompound(nbt == null ? null : (NBTTagCompound) nbt.copy());
return itemStack;
}

public boolean isSameAs(ItemStack stack) {
if (stack == null) return false;
if (item() != stack.getItem()) return false;
if (metaData() != Items.feather.getDamage(stack)) return false;
if (!Objects.equals(nbt(), stack.getTagCompound())) return false;

return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.util.Base64;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
Expand All @@ -31,6 +32,7 @@
import java.util.UUID;
import java.util.function.Function;
import java.util.function.IntFunction;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

Expand Down Expand Up @@ -72,6 +74,7 @@
import net.minecraftforge.common.util.ForgeDirection;
import net.minecraftforge.fluids.IFluidHandler;

import com.recursive_pineapple.matter_manipulator.MMMod;
import cpw.mods.fml.relauncher.ReflectionHelper;

import gregtech.api.GregTechAPI;
Expand Down Expand Up @@ -100,10 +103,10 @@
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.gtnewhorizon.gtnhlib.util.map.ItemStackMap;
import com.gtnewhorizon.structurelib.util.XSTR;
import com.recursive_pineapple.matter_manipulator.asm.Optional;
import com.recursive_pineapple.matter_manipulator.common.building.BlockAnalyzer;
import com.recursive_pineapple.matter_manipulator.common.building.BlockAnalyzer.IBlockApplyContext;
import com.recursive_pineapple.matter_manipulator.common.building.BlockAnalyzer.RequiredItemAnalysis;
import com.recursive_pineapple.matter_manipulator.common.building.BlockSpec;
import com.recursive_pineapple.matter_manipulator.common.building.IPseudoInventory;
Expand All @@ -120,6 +123,7 @@
import org.joml.Vector3i;

import it.unimi.dsi.fastutil.Pair;
import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap;

public class MMUtils {

Expand Down Expand Up @@ -444,34 +448,58 @@ public static EntityPlayer getPlayerById(UUID playerId) {
return null;
}

public static ItemStackMap<Long> getItemStackHistogram(Iterable<ItemStack> stacks) {
public static Object2LongOpenHashMap<ItemId> getItemStackHistogram(Iterable<ItemStack> stacks) {
return getItemStackHistogram(stacks, true);
}

public static ItemStackMap<Long> getItemStackHistogram(Iterable<ItemStack> stacks, boolean NBTSensitive) {
ItemStackMap<Long> histogram = new ItemStackMap<>(NBTSensitive);
public static Object2LongOpenHashMap<ItemId> getItemStackHistogram(Iterable<ItemStack> stacks, boolean NBTSensitive) {
Object2LongOpenHashMap<ItemId> histogram = new Object2LongOpenHashMap<>();

if (stacks == null) return histogram;

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

return histogram;
}

public static List<ItemStack> getStacksOfSize(ItemStackMap<Long> map, int maxStackSize) {
public static class StackMapDiff {
public Object2LongOpenHashMap<ItemId> added = new Object2LongOpenHashMap<>();
public Object2LongOpenHashMap<ItemId> removed = new Object2LongOpenHashMap<>();
}

public static StackMapDiff getStackMapDiff(Object2LongOpenHashMap<ItemId> before, Object2LongOpenHashMap<ItemId> after) {
HashSet<ItemId> keys = new HashSet<>();
keys.addAll(before.keySet());
keys.addAll(after.keySet());

StackMapDiff diff = new StackMapDiff();

for (ItemId id : keys) {
long beforeAmount = before.getLong(id);
long afterAmount = after.getLong(id);

if (afterAmount < beforeAmount) {
diff.removed.addTo(id, beforeAmount - afterAmount);
} else if (beforeAmount < afterAmount) {
diff.added.addTo(id, afterAmount - beforeAmount);
}
}

return diff;
}

public static List<ItemStack> getStacksOfSize(Object2LongOpenHashMap<ItemId> map, int maxStackSize) {
ArrayList<ItemStack> list = new ArrayList<>();

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

ItemStack copy = item.copy();
copy.stackSize = toRemove;
list.add(copy);
list.add(item.getItemStack(toRemove));

amount -= toRemove;
}
Expand Down Expand Up @@ -775,35 +803,101 @@ public static boolean installUpgrades(
boolean consume,
boolean simulate
) {
boolean success = true;

List<ItemStack> stacks = mapToList(pupgrades, PortableItemStack::toStack);

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

for (ItemStack stack : stacks) {
stack.stackSize = Math
.min(stack.stackSize, dest.getMaxInstalled(((IUpgradeModule) stack.getItem()).getType(stack)));
stack.stackSize = Math.min(stack.stackSize, dest.getMaxInstalled(((IUpgradeModule) stack.getItem()).getType(stack)));
}

Object2LongOpenHashMap<ItemId> actual = getItemStackHistogram(Arrays.asList(inventoryToArray(dest)));
Object2LongOpenHashMap<ItemId> target = getItemStackHistogram(stacks);

StackMapDiff diff = getStackMapDiff(actual, target);

if (diff.removed.isEmpty() && diff.added.isEmpty()) return success;

List<ItemStack> toInstall = getStacksOfSize(diff.added, dest.getInventoryStackLimit());

long installable = dest.getSizeInventory() - actual.values().longStream().sum() + diff.removed.values().longStream().sum();

List<BigItemStack> toInstallBig = toInstall.subList(0, Math.min(toInstall.size(), (int) installable))
.stream()
.map(BigItemStack::new)
.collect(Collectors.toList());

var result = src.tryConsumeItems(toInstallBig, IPseudoInventory.CONSUME_PARTIAL);

List<BigItemStack> extracted = result.right();

for (BigItemStack wanted : toInstallBig) {
for (BigItemStack found : extracted) {
if (!found.isSameType(wanted)) continue;

wanted.stackSize -= found.stackSize;
}
}

List<ItemStack> split = getStacksOfSize(stacks, dest.getInventoryStackLimit());
if (src instanceof IBlockApplyContext ctx) {
for (BigItemStack wanted : toInstallBig) {
if (wanted.stackSize > 0) {
ctx.warn("Could not find upgrade: " + wanted.getItemStack().getDisplayName() + " x " + wanted.stackSize);
success = false;
}
}
}

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

if (!consume || src.tryConsumeItems(upgrades)) {
if (!simulate) {
emptyInventory(src, dest);
for (int slot = 0; slot < dest.getSizeInventory(); slot++) {
if (amount <= 0) break;

for (int i = 0; i < upgrades.length; i++) {
dest.setInventorySlotContents(i, upgrades[i]);
ItemStack inSlot = dest.getStackInSlot(slot);

if (e.getKey().isSameAs(inSlot)) {
src.givePlayerItems(inSlot);
dest.setInventorySlotContents(slot, null);

amount--;
}
}
}

int slot = 0;

dest.markDirty();
outer: for (BigItemStack stack : extracted) {
for (ItemStack split : stack.toStacks(1)) {
while (dest.getStackInSlot(slot) != null) {
slot++;

if (slot >= dest.getSizeInventory()) {
MMMod.LOG.error(
"Tried to install too many upgrades: voiding the rest. Dest={}, upgrade={}, slot={}",
dest,
split,
slot,
new Exception());

if (src instanceof IBlockApplyContext ctx) {
ctx.error("Tried to install too many upgrades: voiding the rest (this is a bug, please report it)");
}
break outer;
}
}

dest.setInventorySlotContents(slot++, split);
}
}

return true;
} else {
return false;
dest.markDirty();
}

return success;
}

public static NBTTagCompound copy(NBTTagCompound tag) {
Expand Down

0 comments on commit cd760d4

Please sign in to comment.