From a13f9955f29e3fdcc2a1d9e1ddc8ea0159654a42 Mon Sep 17 00:00:00 2001 From: Zengyj Date: Fri, 24 May 2024 23:36:17 +1100 Subject: [PATCH] Backport lock crafting function for ME Interface (#423) --- .../appeng/api/config/LockCraftingMode.java | 26 +++ src/api/java/appeng/api/config/Settings.java | 2 + .../crafting/ICraftingPatternDetails.java | 8 + .../appeng/block/misc/BlockInterface.java | 10 ++ .../gui/implementations/GuiInterface.java | 15 +- .../client/gui/widgets/GuiImgButton.java | 6 + .../implementations/ContainerInterface.java | 13 +- .../core/localization/ButtonToolTips.java | 7 + .../fluids/helper/DualityFluidInterface.java | 11 +- .../fluids/helper/IFluidInterfaceHost.java | 5 + .../fluids/parts/PartFluidFormationPlane.java | 1 + .../fluids/parts/PartFluidLevelEmitter.java | 2 + .../fluids/parts/PartFluidStorageBus.java | 3 + .../appeng/fluids/util/AEFluidInventory.java | 18 +- .../java/appeng/fluids/util/AEFluidTank.java | 1 + .../appeng/fluids/util/IAEFluidInventory.java | 6 + .../java/appeng/helpers/DualityInterface.java | 170 +++++++++++++++++- .../java/appeng/helpers/IInterfaceHost.java | 5 + .../appeng/helpers/UnlockCraftingEvent.java | 6 + .../java/appeng/parts/misc/PartInterface.java | 16 ++ .../java/appeng/tile/misc/TileInterface.java | 9 + src/main/java/appeng/util/ConfigManager.java | 1 + .../appliedenergistics2/lang/en_us.lang | 6 + .../appliedenergistics2/lang/zh_cn.lang | 6 + .../textures/guis/states.png | Bin 14483 -> 15808 bytes 25 files changed, 332 insertions(+), 21 deletions(-) create mode 100644 src/api/java/appeng/api/config/LockCraftingMode.java create mode 100644 src/main/java/appeng/helpers/UnlockCraftingEvent.java diff --git a/src/api/java/appeng/api/config/LockCraftingMode.java b/src/api/java/appeng/api/config/LockCraftingMode.java new file mode 100644 index 000000000..17e7f5d58 --- /dev/null +++ b/src/api/java/appeng/api/config/LockCraftingMode.java @@ -0,0 +1,26 @@ +package appeng.api.config; + +public enum LockCraftingMode { + /** + * Crafting is never locked. + */ + NONE, + /** + * After pushing a pattern to an adjacent machine, the pattern provider will not accept further crafts until a + * redstone pulse is received. + */ + LOCK_UNTIL_PULSE, + /** + * Crafting is locked while the pattern provider is receiving a redstone signal. + */ + LOCK_WHILE_HIGH, + /** + * Crafting is locked while the pattern provider is not receiving a redstone signal. + */ + LOCK_WHILE_LOW, + /** + * After pushing a pattern to an adjacent machine, the pattern provider will not accept further crafts until the + * primary pattern result is returned to the network through the pattern provider. + */ + LOCK_UNTIL_RESULT +} diff --git a/src/api/java/appeng/api/config/Settings.java b/src/api/java/appeng/api/config/Settings.java index 7fe7de1aa..80d965e3f 100644 --- a/src/api/java/appeng/api/config/Settings.java +++ b/src/api/java/appeng/api/config/Settings.java @@ -57,6 +57,8 @@ public enum Settings IO_DIRECTION( EnumSet.of( RelativeDirection.LEFT, RelativeDirection.RIGHT ) ), + UNLOCK(EnumSet.allOf(LockCraftingMode.class)), + BLOCK( EnumSet.of( YesNo.YES, YesNo.NO ) ), OPERATION_MODE( EnumSet.allOf( OperationMode.class ) ), diff --git a/src/api/java/appeng/api/networking/crafting/ICraftingPatternDetails.java b/src/api/java/appeng/api/networking/crafting/ICraftingPatternDetails.java index 11e4ee367..34bf3e262 100644 --- a/src/api/java/appeng/api/networking/crafting/ICraftingPatternDetails.java +++ b/src/api/java/appeng/api/networking/crafting/ICraftingPatternDetails.java @@ -77,6 +77,14 @@ public interface ICraftingPatternDetails */ IAEItemStack[] getCondensedOutputs(); + /** + * The primary output of this pattern. The pattern will only be used to craft the primary output; the others are + * just byproducts. + */ + default IAEItemStack getPrimaryOutput() { + return getOutputs()[0]; + } + /** * @return a list of the outputs, will include nulls. */ diff --git a/src/main/java/appeng/block/misc/BlockInterface.java b/src/main/java/appeng/block/misc/BlockInterface.java index 8bab2e728..e2a3a8e9f 100644 --- a/src/main/java/appeng/block/misc/BlockInterface.java +++ b/src/main/java/appeng/block/misc/BlockInterface.java @@ -25,12 +25,14 @@ import appeng.block.AEBaseTileBlock; import appeng.core.sync.GuiBridge; import appeng.tile.misc.TileInterface; import appeng.util.Platform; +import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.block.properties.IProperty; import net.minecraft.block.properties.PropertyBool; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.math.BlockPos; @@ -93,4 +95,12 @@ public class BlockInterface extends AEBaseTileBlock { ((TileInterface) rotatable).setSide(axis); } } + + @Override + public void neighborChanged(IBlockState state, World worldIn, BlockPos pos, Block blockIn, BlockPos fromPos) { + TileEntity tileEntity = this.getTileEntity(worldIn, pos); + if (tileEntity != null) { + ((TileInterface) tileEntity).updateRedstoneState(); + } + } } diff --git a/src/main/java/appeng/client/gui/implementations/GuiInterface.java b/src/main/java/appeng/client/gui/implementations/GuiInterface.java index ee501be3c..6c8c4d6fe 100644 --- a/src/main/java/appeng/client/gui/implementations/GuiInterface.java +++ b/src/main/java/appeng/client/gui/implementations/GuiInterface.java @@ -19,6 +19,7 @@ package appeng.client.gui.implementations; +import appeng.api.config.LockCraftingMode; import appeng.api.config.Settings; import appeng.api.config.YesNo; import appeng.client.gui.widgets.GuiImgButton; @@ -41,6 +42,7 @@ import java.io.IOException; public class GuiInterface extends GuiUpgradeable { private GuiTabButton priority; + private GuiImgButton UnlockMode; private GuiImgButton BlockMode; private GuiToggleButton interfaceMode; @@ -57,7 +59,10 @@ public class GuiInterface extends GuiUpgradeable { this.BlockMode = new GuiImgButton(this.guiLeft - 18, this.guiTop + 8, Settings.BLOCK, YesNo.NO); this.buttonList.add(this.BlockMode); - this.interfaceMode = new GuiToggleButton(this.guiLeft - 18, this.guiTop + 26, 84, 85, GuiText.InterfaceTerminal.getLocal(), GuiText.InterfaceTerminalHint.getLocal()); + this.UnlockMode = new GuiImgButton(this.guiLeft - 18,this.guiTop + 26 ,Settings.UNLOCK, LockCraftingMode.NONE); + this.buttonList.add(this.UnlockMode); + + this.interfaceMode = new GuiToggleButton(this.guiLeft - 18, this.guiTop + 44, 84, 85, GuiText.InterfaceTerminal.getLocal(), GuiText.InterfaceTerminalHint.getLocal()); this.buttonList.add(this.interfaceMode); } @@ -67,6 +72,10 @@ public class GuiInterface extends GuiUpgradeable { this.BlockMode.set(((ContainerInterface) this.cvb).getBlockingMode()); } + if (this.UnlockMode != null) { + this.UnlockMode.set(((ContainerInterface) this.cvb).getUnlockMode()); + } + if (this.interfaceMode != null) { this.interfaceMode.setState(((ContainerInterface) this.cvb).getInterfaceTerminalMode() == YesNo.YES); } @@ -106,6 +115,10 @@ public class GuiInterface extends GuiUpgradeable { if (btn == this.BlockMode) { NetworkHandler.instance().sendToServer(new PacketConfigButton(this.BlockMode.getSetting(), backwards)); } + + if (btn == this.UnlockMode) { + NetworkHandler.instance.sendToServer(new PacketConfigButton(this.UnlockMode.getSetting(), backwards)); + } } } diff --git a/src/main/java/appeng/client/gui/widgets/GuiImgButton.java b/src/main/java/appeng/client/gui/widgets/GuiImgButton.java index 638cf5681..4c242adab 100644 --- a/src/main/java/appeng/client/gui/widgets/GuiImgButton.java +++ b/src/main/java/appeng/client/gui/widgets/GuiImgButton.java @@ -160,6 +160,12 @@ public class GuiImgButton extends GuiButton implements ITooltip { this.registerApp(16 * 15, Settings.SCHEDULING_MODE, SchedulingMode.DEFAULT, ButtonToolTips.SchedulingMode, ButtonToolTips.SchedulingModeDefault); this.registerApp(16 * 15 + 1, Settings.SCHEDULING_MODE, SchedulingMode.ROUNDROBIN, ButtonToolTips.SchedulingMode, ButtonToolTips.SchedulingModeRoundRobin); this.registerApp(16 * 15 + 2, Settings.SCHEDULING_MODE, SchedulingMode.RANDOM, ButtonToolTips.SchedulingMode, ButtonToolTips.SchedulingModeRandom); + + this.registerApp(10, Settings.UNLOCK,LockCraftingMode.NONE,ButtonToolTips.LockCraftingMode, ButtonToolTips.LockCraftingModeNone); + this.registerApp(7, Settings.UNLOCK,LockCraftingMode.LOCK_UNTIL_RESULT,ButtonToolTips.LockCraftingMode, ButtonToolTips.LockCraftingUntilResultReturned); + this.registerApp(0, Settings.UNLOCK, LockCraftingMode.LOCK_WHILE_LOW, ButtonToolTips.LockCraftingMode, ButtonToolTips.LockCraftingWhileRedstoneLow); + this.registerApp(1, Settings.UNLOCK, LockCraftingMode.LOCK_WHILE_HIGH, ButtonToolTips.LockCraftingMode, ButtonToolTips.LockCraftingWhileRedstoneHigh); + this.registerApp(2, Settings.UNLOCK, LockCraftingMode.LOCK_UNTIL_PULSE, ButtonToolTips.LockCraftingMode, ButtonToolTips.LockCraftingUntilRedstonePulse); } } diff --git a/src/main/java/appeng/container/implementations/ContainerInterface.java b/src/main/java/appeng/container/implementations/ContainerInterface.java index 68fda38a5..3b2c436d1 100644 --- a/src/main/java/appeng/container/implementations/ContainerInterface.java +++ b/src/main/java/appeng/container/implementations/ContainerInterface.java @@ -19,10 +19,7 @@ package appeng.container.implementations; -import appeng.api.config.SecurityPermissions; -import appeng.api.config.Settings; -import appeng.api.config.Upgrades; -import appeng.api.config.YesNo; +import appeng.api.config.*; import appeng.api.util.IConfigManager; import appeng.container.guisync.GuiSync; import appeng.container.slot.*; @@ -40,6 +37,9 @@ public class ContainerInterface extends ContainerUpgradeable implements IOptiona public YesNo bMode = YesNo.NO; @GuiSync(4) + public LockCraftingMode lMode = LockCraftingMode.NONE; + + @GuiSync(5) public YesNo iTermMode = YesNo.YES; @GuiSync(7) @@ -107,9 +107,14 @@ public class ContainerInterface extends ContainerUpgradeable implements IOptiona @Override protected void loadSettingsFromHost(final IConfigManager cm) { this.setBlockingMode((YesNo) cm.getSetting(Settings.BLOCK)); + this.setUnlockMode((LockCraftingMode) cm.getSetting(Settings.UNLOCK)); this.setInterfaceTerminalMode((YesNo) cm.getSetting(Settings.INTERFACE_TERMINAL)); } + public LockCraftingMode getUnlockMode() {return this.lMode;} + + public void setUnlockMode(final LockCraftingMode mode) {this.lMode = mode;} + public YesNo getBlockingMode() { return this.bMode; } diff --git a/src/main/java/appeng/core/localization/ButtonToolTips.java b/src/main/java/appeng/core/localization/ButtonToolTips.java index 42f65e46a..2cb561838 100644 --- a/src/main/java/appeng/core/localization/ButtonToolTips.java +++ b/src/main/java/appeng/core/localization/ButtonToolTips.java @@ -98,6 +98,13 @@ public enum ButtonToolTips { Blocking, NonBlocking, + LockCraftingMode, + LockCraftingModeNone, + LockCraftingUntilRedstonePulse, + LockCraftingWhileRedstoneHigh, + LockCraftingWhileRedstoneLow, + LockCraftingUntilResultReturned, + LevelType, LevelType_Energy, LevelType_Item, diff --git a/src/main/java/appeng/fluids/helper/DualityFluidInterface.java b/src/main/java/appeng/fluids/helper/DualityFluidInterface.java index 73a3422b3..e9edb98a0 100644 --- a/src/main/java/appeng/fluids/helper/DualityFluidInterface.java +++ b/src/main/java/appeng/fluids/helper/DualityFluidInterface.java @@ -48,6 +48,7 @@ import appeng.api.util.IConfigManager; import appeng.capabilities.Capabilities; import appeng.core.settings.TickRates; import appeng.fluids.util.AEFluidInventory; +import appeng.fluids.util.AEFluidStack; import appeng.fluids.util.IAEFluidInventory; import appeng.fluids.util.IAEFluidTank; import appeng.helpers.ICustomNameObject; @@ -473,7 +474,12 @@ public class DualityFluidInterface implements IGridTickable, IStorageMonitorable } @Override - public void onFluidInventoryChanged(final IAEFluidTank inventory, final int slot) { + public void onFluidInventoryChanged(IAEFluidTank inv, int slot) { + onFluidInventoryChanged(inv, slot, null, null, null); + } + + @Override + public void onFluidInventoryChanged(final IAEFluidTank inventory, final int slot, InvOperation operation, FluidStack added, FluidStack removed) { if (this.isWorking == slot) { return; } @@ -486,6 +492,9 @@ public class DualityFluidInterface implements IGridTickable, IStorageMonitorable this.notifyNeighbors(); } } else if (inventory == this.tanks) { + if (added != null) { + iHost.onStackReturnNetwork(AEFluidStack.fromFluidStack(added)); + } this.saveChanges(); final boolean had = this.hasWorkToDo(); diff --git a/src/main/java/appeng/fluids/helper/IFluidInterfaceHost.java b/src/main/java/appeng/fluids/helper/IFluidInterfaceHost.java index 1f4ae59f6..9469d2eac 100644 --- a/src/main/java/appeng/fluids/helper/IFluidInterfaceHost.java +++ b/src/main/java/appeng/fluids/helper/IFluidInterfaceHost.java @@ -21,9 +21,11 @@ package appeng.fluids.helper; import appeng.api.implementations.IUpgradeableHost; import appeng.api.networking.security.IActionHost; +import appeng.api.storage.data.IAEFluidStack; import appeng.me.helpers.IGridProxyable; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumFacing; +import net.minecraftforge.fluids.FluidStack; import java.util.EnumSet; @@ -36,4 +38,7 @@ public interface IFluidInterfaceHost extends IActionHost, IGridProxyable, IUpgra TileEntity getTileEntity(); void saveChanges(); + + default void onStackReturnNetwork(IAEFluidStack stack) { + } } diff --git a/src/main/java/appeng/fluids/parts/PartFluidFormationPlane.java b/src/main/java/appeng/fluids/parts/PartFluidFormationPlane.java index ce4283333..f9cdd3ef5 100644 --- a/src/main/java/appeng/fluids/parts/PartFluidFormationPlane.java +++ b/src/main/java/appeng/fluids/parts/PartFluidFormationPlane.java @@ -29,6 +29,7 @@ import appeng.me.storage.MEInventoryHandler; import appeng.parts.automation.PartAbstractFormationPlane; import appeng.parts.automation.PlaneModels; import appeng.util.Platform; +import appeng.util.inv.InvOperation; import appeng.util.prioritylist.PrecisePriorityList; import net.minecraft.block.Block; import net.minecraft.block.BlockLiquid; diff --git a/src/main/java/appeng/fluids/parts/PartFluidLevelEmitter.java b/src/main/java/appeng/fluids/parts/PartFluidLevelEmitter.java index d1bf51ad7..13b800945 100644 --- a/src/main/java/appeng/fluids/parts/PartFluidLevelEmitter.java +++ b/src/main/java/appeng/fluids/parts/PartFluidLevelEmitter.java @@ -36,6 +36,7 @@ import appeng.parts.PartModel; import appeng.parts.automation.PartUpgradeable; import appeng.util.IConfigManagerHost; import appeng.util.Platform; +import appeng.util.inv.InvOperation; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; @@ -46,6 +47,7 @@ import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; +import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.capability.IFluidHandler; import java.util.Random; diff --git a/src/main/java/appeng/fluids/parts/PartFluidStorageBus.java b/src/main/java/appeng/fluids/parts/PartFluidStorageBus.java index f6308ded4..2303ff670 100644 --- a/src/main/java/appeng/fluids/parts/PartFluidStorageBus.java +++ b/src/main/java/appeng/fluids/parts/PartFluidStorageBus.java @@ -63,6 +63,7 @@ import appeng.parts.automation.PartUpgradeable; import appeng.tile.networking.TileCableBus; import appeng.util.ConfigManager; import appeng.util.Platform; +import appeng.util.inv.InvOperation; import appeng.util.prioritylist.FuzzyPriorityList; import appeng.util.prioritylist.PrecisePriorityList; import net.minecraft.entity.player.EntityPlayer; @@ -75,6 +76,7 @@ import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import net.minecraft.world.IBlockAccess; +import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.capability.CapabilityFluidHandler; import net.minecraftforge.fluids.capability.IFluidHandler; @@ -543,6 +545,7 @@ public class PartFluidStorageBus extends PartUpgradeable implements IGridTickabl } // TODO: 1/28/2024 Unify both methods. + /** * Filters the changes to only include items that pass the storage filter. * Optimally, this should be handled by the underlying monitor. diff --git a/src/main/java/appeng/fluids/util/AEFluidInventory.java b/src/main/java/appeng/fluids/util/AEFluidInventory.java index 21e7c498a..df07a4be3 100644 --- a/src/main/java/appeng/fluids/util/AEFluidInventory.java +++ b/src/main/java/appeng/fluids/util/AEFluidInventory.java @@ -4,6 +4,7 @@ package appeng.fluids.util; import appeng.api.storage.data.IAEFluidStack; import appeng.core.AELog; import appeng.util.Platform; +import appeng.util.inv.InvOperation; import net.minecraft.nbt.NBTTagCompound; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.capability.IFluidTankProperties; @@ -37,24 +38,27 @@ public class AEFluidInventory implements IAEFluidTank { if (Objects.equals(this.fluids[slot], fluid)) { if (fluid != null && fluid.getStackSize() != this.fluids[slot].getStackSize()) { this.fluids[slot].setStackSize(fluid.getStackSize()); - this.onContentChanged(slot); + this.onContentChanged(slot, InvOperation.SET, fluid.getFluidStack(), null); } } else { + if (fluid == null) { + IAEFluidStack removeStack = this.fluids[slot].copy(); this.fluids[slot] = null; + this.onContentChanged(slot, InvOperation.SET, null, removeStack.getFluidStack()); } else { + IAEFluidStack removeStack = this.fluids[slot]; this.fluids[slot] = fluid.copy(); this.fluids[slot].setStackSize(fluid.getStackSize()); + this.onContentChanged(slot, InvOperation.SET, fluid.getFluidStack(), removeStack == null ? null : removeStack.getFluidStack()); } - - this.onContentChanged(slot); } } } - private void onContentChanged(final int slot) { + private void onContentChanged(final int slot, InvOperation operation, FluidStack added, FluidStack removed) { if (this.handler != null && Platform.isServer()) { - this.handler.onFluidInventoryChanged(this, slot); + this.handler.onFluidInventoryChanged(this, slot, operation, added, removed); } } @@ -107,7 +111,7 @@ public class AEFluidInventory implements IAEFluidTank { this.setFluidInSlot(slot, AEFluidStack.fromFluidStack(resource).setStackSize(amountToStore)); } else { fluid.setStackSize(fluid.getStackSize() + amountToStore); - this.onContentChanged(slot); + this.onContentChanged(slot, InvOperation.INSERT, resource, null); } } @@ -139,7 +143,7 @@ public class AEFluidInventory implements IAEFluidTank { if (fluid.getStackSize() <= 0) { this.fluids[slot] = null; } - this.onContentChanged(slot); + this.onContentChanged(slot, InvOperation.EXTRACT, null, new FluidStack(fluid.getFluid(), drained)); } return stack; } diff --git a/src/main/java/appeng/fluids/util/AEFluidTank.java b/src/main/java/appeng/fluids/util/AEFluidTank.java index 2ddb9fda9..f4edb45d5 100644 --- a/src/main/java/appeng/fluids/util/AEFluidTank.java +++ b/src/main/java/appeng/fluids/util/AEFluidTank.java @@ -21,6 +21,7 @@ package appeng.fluids.util; import appeng.api.storage.data.IAEFluidStack; import appeng.util.Platform; +import appeng.util.inv.InvOperation; import net.minecraft.tileentity.TileEntity; import net.minecraftforge.fluids.FluidTank; diff --git a/src/main/java/appeng/fluids/util/IAEFluidInventory.java b/src/main/java/appeng/fluids/util/IAEFluidInventory.java index 295f2c44b..de3ccc24e 100644 --- a/src/main/java/appeng/fluids/util/IAEFluidInventory.java +++ b/src/main/java/appeng/fluids/util/IAEFluidInventory.java @@ -19,7 +19,13 @@ package appeng.fluids.util; +import appeng.util.inv.InvOperation; +import net.minecraftforge.fluids.FluidStack; + @FunctionalInterface public interface IAEFluidInventory { void onFluidInventoryChanged(final IAEFluidTank inv, final int slot); + + default void onFluidInventoryChanged(final IAEFluidTank inv, final int slot, InvOperation operation, FluidStack added, FluidStack removed) { + } } diff --git a/src/main/java/appeng/helpers/DualityInterface.java b/src/main/java/appeng/helpers/DualityInterface.java index 05619132d..46eaed13b 100644 --- a/src/main/java/appeng/helpers/DualityInterface.java +++ b/src/main/java/appeng/helpers/DualityInterface.java @@ -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 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; diff --git a/src/main/java/appeng/helpers/IInterfaceHost.java b/src/main/java/appeng/helpers/IInterfaceHost.java index 7b8769d30..51f9cf225 100644 --- a/src/main/java/appeng/helpers/IInterfaceHost.java +++ b/src/main/java/appeng/helpers/IInterfaceHost.java @@ -22,6 +22,7 @@ package appeng.helpers; import appeng.api.implementations.IUpgradeableHost; import appeng.api.networking.crafting.ICraftingProvider; import appeng.api.networking.crafting.ICraftingRequester; +import appeng.api.storage.data.IAEItemStack; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumFacing; @@ -37,4 +38,8 @@ public interface IInterfaceHost extends ICraftingProvider, IUpgradeableHost, ICr TileEntity getTileEntity(); void saveChanges(); + + default void onStackReturnNetwork(IAEItemStack stack) { + getInterfaceDuality().onStackReturnedToNetwork(stack); + } } diff --git a/src/main/java/appeng/helpers/UnlockCraftingEvent.java b/src/main/java/appeng/helpers/UnlockCraftingEvent.java new file mode 100644 index 000000000..dcfe64ca9 --- /dev/null +++ b/src/main/java/appeng/helpers/UnlockCraftingEvent.java @@ -0,0 +1,6 @@ +package appeng.helpers; + +public enum UnlockCraftingEvent { + PULSE, + RESULT +} diff --git a/src/main/java/appeng/parts/misc/PartInterface.java b/src/main/java/appeng/parts/misc/PartInterface.java index 781443116..b33dc836b 100644 --- a/src/main/java/appeng/parts/misc/PartInterface.java +++ b/src/main/java/appeng/parts/misc/PartInterface.java @@ -54,6 +54,7 @@ import appeng.items.parts.PartModels; import appeng.parts.PartBasicState; import appeng.parts.PartModel; import appeng.tile.inventory.AppEngInternalInventory; +import appeng.tile.misc.TileInterface; import appeng.util.Platform; import appeng.util.SettingsFrom; import appeng.util.inv.IAEAppEngInventory; @@ -68,7 +69,9 @@ import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; +import net.minecraft.world.IBlockAccess; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.wrapper.PlayerMainInvWrapper; @@ -196,6 +199,11 @@ public class PartInterface extends PartBasicState implements IGridTickable, ISto this.duality.onChangeInventory(inv, slot, mc, removedStack, newStack); } + @Override + public void onStackReturnNetwork(IAEItemStack stack) { + this.duality.onStackReturnedToNetwork(stack); + } + @Override public DualityInterface getInterfaceDuality() { return this.duality; @@ -262,6 +270,14 @@ public class PartInterface extends PartBasicState implements IGridTickable, ISto } } + @Override + public void onNeighborChanged(IBlockAccess w, BlockPos pos, BlockPos neighbor) { + TileEntity tileEntity = getTileEntity(); + if (tileEntity instanceof TileInterface) { + ((TileInterface) tileEntity).updateRedstoneState(); + } + } + @Override public boolean hasCapability(Capability capabilityClass) { return this.duality.hasCapability(capabilityClass, this.getSide().getFacing()); diff --git a/src/main/java/appeng/tile/misc/TileInterface.java b/src/main/java/appeng/tile/misc/TileInterface.java index 8a2f9f4c2..6424eb9ee 100644 --- a/src/main/java/appeng/tile/misc/TileInterface.java +++ b/src/main/java/appeng/tile/misc/TileInterface.java @@ -221,6 +221,11 @@ public class TileInterface extends AENetworkInvTile implements IGridTickable, II this.duality.onChangeInventory(inv, slot, mc, removed, added); } + @Override + public void onStackReturnNetwork(IAEItemStack stack) { + this.duality.onStackReturnedToNetwork(stack); + } + @Override public DualityInterface getInterfaceDuality() { return this.duality; @@ -274,6 +279,10 @@ public class TileInterface extends AENetworkInvTile implements IGridTickable, II return this.duality.injectCraftedItems(link, items, mode); } + public void updateRedstoneState(){ + this.duality.updateRedstoneState(); + } + @Override public void jobStateChange(final ICraftingLink link) { this.duality.jobStateChange(link); diff --git a/src/main/java/appeng/util/ConfigManager.java b/src/main/java/appeng/util/ConfigManager.java index 289f1f6c7..93d765ffe 100644 --- a/src/main/java/appeng/util/ConfigManager.java +++ b/src/main/java/appeng/util/ConfigManager.java @@ -25,6 +25,7 @@ import appeng.api.config.StorageFilter; import appeng.api.util.IConfigManager; import appeng.core.AELog; import net.minecraft.nbt.NBTTagCompound; +import org.jetbrains.annotations.Nullable; import java.util.EnumMap; import java.util.Map; diff --git a/src/main/resources/assets/appliedenergistics2/lang/en_us.lang b/src/main/resources/assets/appliedenergistics2/lang/en_us.lang index 71726f2ff..0710950fd 100644 --- a/src/main/resources/assets/appliedenergistics2/lang/en_us.lang +++ b/src/main/resources/assets/appliedenergistics2/lang/en_us.lang @@ -327,6 +327,12 @@ gui.tooltips.appliedenergistics2.Disabled=Disabled gui.tooltips.appliedenergistics2.Enable=Enabled gui.tooltips.appliedenergistics2.Blocking=Do not push crafting items if inventory contains items. gui.tooltips.appliedenergistics2.NonBlocking=Ignore the contents of the target inventory. +gui.tooltips.appliedenergistics2.LockCraftingMode=Lock Crafting +gui.tooltips.appliedenergistics2.LockCraftingModeNone=Never +gui.tooltips.appliedenergistics2.LockCraftingUntilRedstonePulse=Until redstone pulse is received +gui.tooltips.appliedenergistics2.LockCraftingWhileRedstoneHigh=With redstone signal +gui.tooltips.appliedenergistics2.LockCraftingWhileRedstoneLow=Without redstone signal +gui.tooltips.appliedenergistics2.LockCraftingUntilResultReturned=Until primary crafting result is returned gui.tooltips.appliedenergistics2.Craft=Crafting Behavior gui.tooltips.appliedenergistics2.CraftOnly=Do not use stocked items, only craft items while exporting. gui.tooltips.appliedenergistics2.CraftEither=Use stocked items, or craft items while exporting. diff --git a/src/main/resources/assets/appliedenergistics2/lang/zh_cn.lang b/src/main/resources/assets/appliedenergistics2/lang/zh_cn.lang index 8f36e0920..d93d0bd02 100644 --- a/src/main/resources/assets/appliedenergistics2/lang/zh_cn.lang +++ b/src/main/resources/assets/appliedenergistics2/lang/zh_cn.lang @@ -324,6 +324,12 @@ gui.tooltips.appliedenergistics2.Disabled=禁用 gui.tooltips.appliedenergistics2.Enable=启用 gui.tooltips.appliedenergistics2.Blocking=当容器内有物品时不传送物品。 gui.tooltips.appliedenergistics2.NonBlocking=忽略目标容器的内容。 +gui.tooltips.appliedenergistics2.LockCraftingMode=合成锁定 +gui.tooltips.appliedenergistics2.LockCraftingModeNone=永不锁定 +gui.tooltips.appliedenergistics2.LockCraftingUntilRedstonePulse=接收到脉冲信号时解锁 +gui.tooltips.appliedenergistics2.LockCraftingWhileRedstoneHigh=有红石信号时锁定 +gui.tooltips.appliedenergistics2.LockCraftingWhileRedstoneLow=无红石信号时锁定 +gui.tooltips.appliedenergistics2.LockCraftingUntilResultReturned=接受到编码样板主产物时解锁 gui.tooltips.appliedenergistics2.Craft=输出时若有需要则合成物品。 gui.tooltips.appliedenergistics2.CraftOnly=不使用已存储物品,只使用合成物品。 gui.tooltips.appliedenergistics2.CraftEither=输出时使用已存储物品或合成物品。 diff --git a/src/main/resources/assets/appliedenergistics2/textures/guis/states.png b/src/main/resources/assets/appliedenergistics2/textures/guis/states.png index 8d03ff924fd17dbd5a5e47e094aab15708fa1e5e..830ddb80db01a637ca0ae0c3f801124dd18b2bf3 100644 GIT binary patch literal 15808 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 II;Vst014O!m;e9( literal 14483 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 R7#J8BJYD@<);T3K0RU@2GbI23