implement storage interceptor & fix locking card (#993)

Co-authored-by: Martin Robertz <dream-master@gmx.net>
This commit is contained in:
lc-1337andMartin Robertz authored and GitHub committed 2026-01-01 16:58:14 +01:00
1 parent 0c34b1dd47
commit 0b03886f6f
5 files changed
+149 -57

No files matched your search

@@ -0,0 +1,14 @@
package appeng.api.networking.storage;
import appeng.api.config.Actionable;
import appeng.api.networking.security.BaseActionSource;
import appeng.api.storage.data.IAEStack;
public interface IStorageInterceptor {
boolean canAccept(IAEStack<?> stack);
IAEStack<?> injectItems(IAEStack<?> input, final Actionable type, final BaseActionSource src);
boolean shouldRemoveInterceptor(IAEStack<?> stack);
}
@@ -73,6 +73,7 @@ import appeng.api.networking.events.MENetworkCraftingPushedPattern;
import appeng.api.networking.security.BaseActionSource;
import appeng.api.networking.security.IActionHost;
import appeng.api.networking.security.MachineSource;
import appeng.api.networking.storage.IStorageInterceptor;
import appeng.api.networking.ticking.IGridTickable;
import appeng.api.networking.ticking.TickRateModulation;
import appeng.api.networking.ticking.TickingRequest;
@@ -121,7 +122,7 @@ import appeng.util.item.AEItemStack;
import cpw.mods.fml.common.Loader;
public class DualityInterface implements IGridTickable, IStorageMonitorable, IInventoryDestination, IAEAppEngInventory,
IConfigManagerHost, ICraftingProvider, IUpgradeableHost, IPriorityHost, IGridProxyable {
IConfigManagerHost, ICraftingProvider, IUpgradeableHost, IPriorityHost, IGridProxyable, IStorageInterceptor {
public static final int NUMBER_OF_STORAGE_SLOTS = 9;
public static final int NUMBER_OF_CONFIG_SLOTS = 9;
@@ -161,7 +162,7 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
private YesNo redstoneState = YesNo.UNDECIDED;
private UnlockCraftingEvent unlockEvent;
private List<IAEItemStack> unlockStacks;
private List<IAEStack<?>> unlockStacks;
private int lastInputHash = 0;
private final boolean isFluidInterface;
private ScheduledReason scheduledReason = ScheduledReason.UNDEFINED;
@@ -261,9 +262,9 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
if (unlockStacks != null && !unlockStacks.isEmpty()) {
data.setByte("unlockEvent", (byte) 2);
NBTTagList stackList = new NBTTagList();
for (IAEItemStack stack : unlockStacks) {
for (IAEStack<?> stack : unlockStacks) {
NBTTagCompound stackTag = new NBTTagCompound();
stack.writeToNBT(stackTag);
Platform.writeStackNBT(stack, stackTag, true);
stackList.appendTag(stackTag);
}
data.setTag("unlockStacks", stackList);
@@ -312,7 +313,7 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
NBTTagList stackList = data.getTagList("unlockStacks", 10);
for (int index = 0; index < stackList.tagCount(); index++) {
NBTTagCompound stackTag = stackList.getCompoundTagAt(index);
IAEItemStack unlockStack = AEItemStack.loadItemStackFromNBT(stackTag);
IAEStack<?> unlockStack = Platform.readStackNBT(stackTag, true);
if (unlockStack == null) {
AELog.error("Could not load unlock stack for interface from NBT: {}", data);
continue;
@@ -322,6 +323,7 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
}
this.unlockStacks.add(unlockStack);
}
addInterception();
} else {
this.unlockStacks = null;
}
@@ -823,7 +825,6 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
} else if (removed.stackSize != diff) {
throw new IllegalStateException("bad attempt at managing inventory. ( removeItems )");
}
onStackReturnedToNetwork(AEItemStack.create(removed));
}
} else if (this.craftingTracker.isBusy(x)) {
changed = this.handleCrafting(x, adaptor, itemStack);
@@ -1084,6 +1085,90 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
this.lastInputHash = 0;
}
@Override
public boolean canAccept(IAEStack<?> stack) {
if (unlockStacks != null && stack != null) {
for (IAEStack<?> unlockStack : unlockStacks) {
if (stack.equals(unlockStack)) {
return true;
}
}
}
return false;
}
@Override
public IAEStack<?> injectItems(IAEStack<?> input, Actionable type, BaseActionSource src) {
if (type == Actionable.SIMULATE) return input;
if (unlockStacks != null && input != null) {
boolean changed = false;
for (Iterator<IAEStack<?>> iterator = unlockStacks.iterator(); iterator.hasNext();) {
IAEStack<?> unlockStack = iterator.next();
if (unlockStack.equals(input)) {
changed = true;
unlockStack.decStackSize(input.getStackSize());
if (unlockStack.getStackSize() <= 0) {
iterator.remove();
}
break;
}
}
if (changed) {
saveChanges();
}
}
return input;
}
private void addInterception() {
boolean hasItems = false;
boolean hasFluids = false;
for (IAEStack<?> aes : unlockStacks) {
if (aes.isItem()) {
hasItems = true;
} else if (aes.isFluid()) {
hasFluids = true;
}
}
if (hasItems) {
try {
if (this.gridProxy.getStorage().getItemInventory() instanceof NetworkMonitor<?>nm) {
nm.addStorageInterceptor(this);
}
} catch (GridAccessException ignored) {}
}
if (hasFluids) {
try {
if (this.gridProxy.getStorage().getFluidInventory() instanceof NetworkMonitor<?>nm) {
nm.addStorageInterceptor(this);
}
} catch (GridAccessException ignored) {}
}
}
@Override
public boolean shouldRemoveInterceptor(IAEStack<?> stack) {
if (unlockStacks != null) {
if (unlockStacks.isEmpty()) {
unlockEvent = null;
unlockStacks = null;
} else {
for (IAEStack<?> unlockStack : unlockStacks) {
if (stack.isItem() && unlockStack.isItem()) return false;
if (stack.isFluid() && unlockStack.isFluid()) return false;
}
}
}
return true;
}
private static class VerifiedAcceptors {
public TileEntity te;
@@ -1583,9 +1668,13 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
if (unlockStacks == null) {
unlockStacks = new ArrayList<>();
}
for (IAEItemStack output : pattern.getCondensedOutputs()) {
for (IAEStack<?> output : pattern.getCondensedAEOutputs()) {
unlockStacks.add(output.copy());
}
addInterception();
saveChanges();
}
}
@@ -1620,46 +1709,10 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
/**
* @return Null if {@linkplain #getCraftingLockedReason()} is not {@link LockCraftingMode#LOCK_UNTIL_RESULT}.
*/
public List<IAEItemStack> getUnlockStacks() {
public List<IAEStack<?>> getUnlockStacks() {
return unlockStacks;
}
/**
* Called when an ItemStack has been pushed into the network from the internal buffer. Public to enable other
* interface types (mainly AE2FC) to work with locking return mode.
*/
public void onStackReturnedToNetwork(IAEItemStack returnedStack) {
if (unlockEvent != UnlockCraftingEvent.RESULT) {
return; // If we're not waiting for the result, we don't care
}
if (unlockStacks == null) {
// Actually an error state...
AELog.error("interface was waiting for RESULT, but no result was set");
unlockEvent = null;
return;
}
boolean changed = false;
for (Iterator<IAEItemStack> iterator = unlockStacks.iterator(); iterator.hasNext();) {
IAEItemStack unlockStack = iterator.next();
if (unlockStack.equals(returnedStack)) {
changed = true;
unlockStack.decStackSize(returnedStack.getStackSize());
if (unlockStack.getStackSize() <= 0) {
iterator.remove();
}
break;
}
}
if (unlockStacks.isEmpty()) {
unlockEvent = null;
unlockStacks = null;
}
if (changed) {
saveChanges();
}
}
public void updateRedstoneState() {
// reset cache to undecided
redstoneState = YesNo.UNDECIDED;
@@ -10,10 +10,10 @@ import net.minecraft.world.World;
import appeng.api.config.LockCraftingMode;
import appeng.api.parts.IPart;
import appeng.api.storage.data.IAEItemStack;
import appeng.api.storage.data.IAEStack;
import appeng.core.localization.WailaText;
import appeng.helpers.IInterfaceHost;
import appeng.util.item.AEItemStack;
import appeng.util.Platform;
import mcp.mobius.waila.api.IWailaConfigHandler;
import mcp.mobius.waila.api.IWailaDataAccessor;
@@ -42,7 +42,7 @@ public final class PartInterfaceDataProvider extends BasePartWailaDataProvider {
NBTTagList stackList = accessor.getNBTData().getTagList(NBT_LOCK_STACKS, 10);
for (int index = 0; index < stackList.tagCount(); index++) {
NBTTagCompound stackTag = stackList.getCompoundTagAt(index);
AEItemStack stack = (AEItemStack) AEItemStack.loadItemStackFromNBT(stackTag);
IAEStack<?> stack = Platform.readStackNBT(stackTag);
if (stack != null) {
currentToolTip.add("> " + stack.getStackSize() + " " + stack.getDisplayName());
@@ -70,12 +70,12 @@ public final class PartInterfaceDataProvider extends BasePartWailaDataProvider {
tag.setString(NBT_LOCK_REASON, interfaceDuality.getCraftingLockedReason().name());
LockCraftingMode lock = interfaceDuality.getCraftingLockedReason();
if (lock == LockCraftingMode.LOCK_UNTIL_RESULT) {
List<IAEItemStack> unlockStacks = interfaceDuality.getUnlockStacks();
List<IAEStack<?>> unlockStacks = interfaceDuality.getUnlockStacks();
if (unlockStacks != null && !unlockStacks.isEmpty()) {
NBTTagList stackList = new NBTTagList();
for (IAEItemStack stack : unlockStacks) {
for (IAEStack<?> stack : unlockStacks) {
NBTTagCompound stackTag = new NBTTagCompound();
stack.writeToNBT(stackTag);
Platform.writeStackNBT(stack, stackTag, true);
stackList.appendTag(stackTag);
}
tag.setTag(NBT_LOCK_STACKS, stackList);
@@ -10,11 +10,11 @@ import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
import appeng.api.config.LockCraftingMode;
import appeng.api.storage.data.IAEItemStack;
import appeng.api.storage.data.IAEStack;
import appeng.core.localization.WailaText;
import appeng.helpers.IInterfaceHost;
import appeng.integration.modules.waila.BaseWailaDataProvider;
import appeng.util.item.AEItemStack;
import appeng.util.Platform;
import mcp.mobius.waila.api.IWailaConfigHandler;
import mcp.mobius.waila.api.IWailaDataAccessor;
@@ -43,7 +43,7 @@ public final class InterfaceDataProvider extends BaseWailaDataProvider {
NBTTagList stackList = accessor.getNBTData().getTagList(NBT_LOCK_STACKS, 10);
for (int index = 0; index < stackList.tagCount(); index++) {
NBTTagCompound stackTag = stackList.getCompoundTagAt(index);
AEItemStack stack = (AEItemStack) AEItemStack.loadItemStackFromNBT(stackTag);
IAEStack<?> stack = Platform.readStackNBT(stackTag);
if (stack != null) {
currentToolTip.add("> " + stack.getStackSize() + " " + stack.getDisplayName());
@@ -71,12 +71,12 @@ public final class InterfaceDataProvider extends BaseWailaDataProvider {
tag.setString(NBT_LOCK_REASON, interfaceDuality.getCraftingLockedReason().name());
LockCraftingMode lock = interfaceDuality.getCraftingLockedReason();
if (lock == LockCraftingMode.LOCK_UNTIL_RESULT) {
List<IAEItemStack> unlockStacks = interfaceDuality.getUnlockStacks();
List<IAEStack<?>> unlockStacks = interfaceDuality.getUnlockStacks();
if (unlockStacks != null && !unlockStacks.isEmpty()) {
NBTTagList stackList = new NBTTagList();
for (IAEItemStack stack : unlockStacks) {
for (IAEStack<?> stack : unlockStacks) {
NBTTagCompound stackTag = new NBTTagCompound();
stack.writeToNBT(stackTag);
Platform.writeStackNBT(stack, stackTag, true);
stackList.appendTag(stackTag);
}
tag.setTag(NBT_LOCK_STACKS, stackList);
+26 -1
View File
@@ -13,9 +13,11 @@ package appeng.me.cache;
import java.util.Collection;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
@@ -29,6 +31,7 @@ import appeng.api.config.Actionable;
import appeng.api.networking.IGrid;
import appeng.api.networking.events.MENetworkStorageEvent;
import appeng.api.networking.security.BaseActionSource;
import appeng.api.networking.storage.IStorageInterceptor;
import appeng.api.storage.IMEInventoryHandler;
import appeng.api.storage.IMEMonitor;
import appeng.api.storage.IMEMonitorHandlerReceiver;
@@ -65,6 +68,8 @@ public class NetworkMonitor<T extends IAEStack<T>> implements IMEMonitor<T> {
@Nonnegative
private int localDepthSemaphore = 0;
private final Set<IStorageInterceptor> storageInterceptors = new HashSet<>();
public NetworkMonitor(final GridStorageCache cache, final StorageChannel chan) {
this.myGridCache = cache;
this.myChannel = chan;
@@ -148,7 +153,19 @@ public class NetworkMonitor<T extends IAEStack<T>> implements IMEMonitor<T> {
}
@Override
public T injectItems(final T input, final Actionable mode, final BaseActionSource src) {
public T injectItems(T input, final Actionable mode, final BaseActionSource src) {
for (Iterator<IStorageInterceptor> iterator = storageInterceptors.iterator(); iterator.hasNext();) {
final IStorageInterceptor isi = iterator.next();
if (isi.canAccept(input)) {
input = (T) isi.injectItems(input, mode, src);
if (isi.shouldRemoveInterceptor(input)) iterator.remove();
if (input == null) return null;
}
}
if (mode == Actionable.SIMULATE) {
return this.getHandler().injectItems(input, mode, src);
}
@@ -326,4 +343,12 @@ public class NetworkMonitor<T extends IAEStack<T>> implements IMEMonitor<T> {
this.myGridCache.getGrid().postEvent(new MENetworkStorageEvent(this, this.myChannel));
}
}
public void addStorageInterceptor(IStorageInterceptor storageInterceptor) {
this.storageInterceptors.add(storageInterceptor);
}
public void removeStorageInterceptor(IStorageInterceptor storageInterceptor) {
this.storageInterceptors.remove(storageInterceptor);
}
}