Backport lock crafting function for ME Interface (#423)

This commit is contained in:
Zengyj
2024-05-24 23:36:17 +11:00
committed by NotMyWing
parent a65b5015e6
commit a13f9955f2
25 changed files with 332 additions and 21 deletions
@@ -20,10 +20,7 @@ package appeng.helpers;
import appeng.api.AEApi;
import appeng.api.config.Actionable;
import appeng.api.config.Settings;
import appeng.api.config.Upgrades;
import appeng.api.config.YesNo;
import appeng.api.config.*;
import appeng.api.implementations.ICraftingPatternItem;
import appeng.api.implementations.IUpgradeableHost;
import appeng.api.implementations.tiles.ICraftingMachine;
@@ -53,6 +50,7 @@ import appeng.api.util.AEPartLocation;
import appeng.api.util.DimensionalCoord;
import appeng.api.util.IConfigManager;
import appeng.capabilities.Capabilities;
import appeng.core.AELog;
import appeng.core.settings.TickRates;
import appeng.me.GridAccessException;
import appeng.me.helpers.AENetworkProxy;
@@ -67,10 +65,7 @@ import appeng.tile.inventory.AppEngInternalAEInventory;
import appeng.tile.inventory.AppEngInternalInventory;
import appeng.tile.inventory.AppEngInternalOversizedInventory;
import appeng.tile.networking.TileCableBus;
import appeng.util.ConfigManager;
import appeng.util.IConfigManagerHost;
import appeng.util.InventoryAdaptor;
import appeng.util.Platform;
import appeng.util.*;
import appeng.util.inv.*;
import appeng.util.item.AEItemStack;
import com.google.common.collect.ImmutableSet;
@@ -101,6 +96,8 @@ import net.minecraftforge.items.wrapper.RangedWrapper;
import javax.annotation.Nullable;
import java.util.*;
import static appeng.api.config.LockCraftingMode.LOCK_UNTIL_PULSE;
import static appeng.api.config.LockCraftingMode.LOCK_UNTIL_RESULT;
import static appeng.helpers.ItemStackHelper.*;
@@ -135,6 +132,13 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
private boolean resetConfigCache = true;
private IMEMonitor<IAEItemStack> configCachedHandler;
private YesNo redstoneState = YesNo.UNDECIDED;
@Nullable
private UnlockCraftingEvent unlockEvent;
@Nullable
private IAEItemStack unlockStack;
public DualityInterface(final AENetworkProxy networkProxy, final IInterfaceHost ih) {
this.gridProxy = networkProxy;
this.gridProxy.setFlags(GridFlags.REQUIRE_CHANNEL);
@@ -142,6 +146,7 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
this.upgrades = new StackUpgradeInventory(this.gridProxy.getMachineRepresentation(), this, 4);
this.cm.registerSetting(Settings.BLOCK, YesNo.NO);
this.cm.registerSetting(Settings.INTERFACE_TERMINAL, YesNo.YES);
this.cm.registerSetting(Settings.UNLOCK, LockCraftingMode.NONE);
this.iHost = ih;
this.craftingTracker = new MultiCraftingTracker(this.iHost, 9);
@@ -168,6 +173,7 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
if (this.isWorking == slot) {
return;
}
if (inv == this.config && (!removed.isEmpty() || !added.isEmpty())) {
boolean cfg = hasConfig();
this.readConfig();
@@ -178,6 +184,9 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
} else if (inv == this.patterns && (!removed.isEmpty() || !added.isEmpty())) {
this.updateCraftingList();
} else if (inv == this.storage && slot >= 0) {
if (added != ItemStack.EMPTY){
iHost.onStackReturnNetwork(AEItemStack.fromItemStack(added));
}
final boolean had = this.hasWorkToDo();
this.updatePlan(slot);
@@ -207,6 +216,18 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
this.craftingTracker.writeToNBT(data);
data.setInteger("priority", this.priority);
if (unlockEvent == UnlockCraftingEvent.PULSE) {
data.setByte("unlockEvent", (byte) 1);
} else if (unlockEvent == UnlockCraftingEvent.RESULT) {
if (unlockStack != null) {
data.setByte("unlockEvent", (byte) 2);
NBTTagCompound unlockStackTag = new NBTTagCompound();
unlockStack.writeToNBT(unlockStackTag);
data.setTag("unlockStack", unlockStackTag);
} else {
AELog.error("Saving MEInterface {}, locked waiting for stack, but stack is null!", iHost);
}
}
final NBTTagList waitingToSend = new NBTTagList();
if (this.waitingToSend != null) {
for (final ItemStack is : this.waitingToSend) {
@@ -286,6 +307,27 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
this.cm.readFromNBT(data);
this.readConfig();
this.updateCraftingList();
var unlockEventType = data.getByte("unlockEvent");
this.unlockEvent = switch (unlockEventType) {
case 0 -> null;
case 1 -> UnlockCraftingEvent.PULSE;
case 2 -> UnlockCraftingEvent.RESULT;
default -> {
AELog.error("Unknown unlock event type {} in NBT for MEInterface: {}", unlockEventType, data);
yield null;
}
};
if (this.unlockEvent == UnlockCraftingEvent.RESULT) {
this.unlockStack = AEItemStack.fromNBT(data.getCompoundTag("unlockStack"));
if (this.unlockStack == null) {
AELog.error("Could not load unlock stack for MEInterface from NBT: {}", data);
}
} else {
this.unlockStack = null;
}
}
private void addToSendList(final ItemStack is) {
@@ -912,6 +954,11 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
if (this.getInstalledUpgrades(Upgrades.CRAFTING) == 0) {
this.cancelCrafting();
}
if (newValue == LockCraftingMode.NONE) {
resetCraftingLock();
}
this.iHost.saveChanges();
}
@@ -951,6 +998,10 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
final TileEntity tile = this.iHost.getTileEntity();
final World w = tile.getWorld();
if (getCraftingLockedReason() != LockCraftingMode.NONE) {
return false;
}
if (this.visitedFaces.isEmpty()) {
this.visitedFaces = this.iHost.getTargets();
}
@@ -1003,6 +1054,7 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
addToSendListFacing(is, s);
}
}
onPushPatternSuccess(patternDetails);
pushItemsOut(s);
return true;
@@ -1021,6 +1073,7 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
if (cm.acceptsPlans()) {
visitedFaces.remove(s);
if (cm.pushPattern(patternDetails, table, s.getOpposite())) {
onPushPatternSuccess(patternDetails);
return true;
}
continue;
@@ -1061,6 +1114,7 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
addToSendListFacing(is, s);
}
}
onPushPatternSuccess(patternDetails);
pushItemsOut(s);
return true;
}
@@ -1070,6 +1124,57 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
return false;
}
public void resetCraftingLock() {
if (unlockEvent != null) {
unlockEvent = null;
unlockStack = null;
saveChanges();
}
}
private void onPushPatternSuccess(ICraftingPatternDetails pattern) {
resetCraftingLock();
LockCraftingMode lockMode = (LockCraftingMode) cm.getSetting(Settings.UNLOCK);
switch (lockMode) {
case LOCK_UNTIL_PULSE -> {
unlockEvent = UnlockCraftingEvent.PULSE;
saveChanges();
}
case LOCK_UNTIL_RESULT -> {
unlockEvent = UnlockCraftingEvent.RESULT;
unlockStack = pattern.getPrimaryOutput();
saveChanges();
}
}
}
/**
* Gets if the crafting lock is in effect and why.
*
* @return null if the lock isn't in effect
*/
public LockCraftingMode getCraftingLockedReason() {
var lockMode = cm.getSetting(Settings.UNLOCK);
if (lockMode == LockCraftingMode.LOCK_WHILE_LOW && !getRedstoneState()) {
// Crafting locked by redstone signal
return LockCraftingMode.LOCK_WHILE_LOW;
} else if (lockMode == LockCraftingMode.LOCK_WHILE_HIGH && getRedstoneState()) {
return LockCraftingMode.LOCK_WHILE_HIGH;
} else if (unlockEvent != null) {
// Crafting locked by waiting for unlock event
switch (unlockEvent) {
case PULSE -> {
return LOCK_UNTIL_PULSE;
}
case RESULT -> {
return LOCK_UNTIL_RESULT;
}
}
}
return LockCraftingMode.NONE;
}
@Override
public boolean isBusy() {
boolean busy = false;
@@ -1384,6 +1489,55 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
return null;
}
public void updateRedstoneState() {
// If we're waitingh for a pulse, update immediately
if (unlockEvent == UnlockCraftingEvent.PULSE && getRedstoneState()) {
unlockEvent = null; // Unlocked!
} else {
// Otherwise, just reset back to undecided
redstoneState = YesNo.UNDECIDED;
}
saveChanges(); // In any case, this needs to be changed since the state is now outdated
}
/**
* @return Null if {@linkplain #getCraftingLockedReason()} is not {@link LockCraftingMode#LOCK_UNTIL_RESULT}.
*/
@org.jetbrains.annotations.Nullable
public IAEItemStack getUnlockStack() {
return unlockStack;
}
public void onStackReturnedToNetwork(IAEItemStack stack) {
if (unlockEvent != UnlockCraftingEvent.RESULT) {
return; // If we're not waiting for the result, we don't care
}
if (unlockStack == null) {
// Actually an error state...
AELog.error("MEInterface was waiting for RESULT, but no result was set");
unlockEvent = null;
} else if (unlockStack.getItem().equals(stack.getItem())) {
var remainingAmount = unlockStack.getStackSize() - stack.getStackSize();
if (remainingAmount <= 0) {
unlockEvent = null;
unlockStack = null;
} else {
unlockStack.setStackSize(remainingAmount);
}
}
}
private boolean getRedstoneState() {
if (redstoneState == YesNo.UNDECIDED) {
var entity = this.iHost.getTileEntity();
redstoneState = entity.getWorld().getRedstonePowerFromNeighbors(entity.getPos()) > 0
? YesNo.YES
: YesNo.NO;
}
return redstoneState == YesNo.YES;
}
private class InterfaceRequestSource extends MachineSource {
private final InterfaceRequestContext context;