From c7bbb92dd892d684c3a2c942b9e79d4419a6b6e3 Mon Sep 17 00:00:00 2001 From: raoulvdberge Date: Thu, 13 Sep 2018 22:28:02 +0200 Subject: [PATCH] Bump to 1.6.6 --- build.gradle | 2 +- .../ICraftingPatternContainer.java | 13 ++ .../autocrafting/task/CraftingTask.java | 120 +++++++++-------- .../autocrafting/task/ProcessingState.java | 3 +- .../network/node/NetworkNodeCrafter.java | 127 +++++++++++++++--- .../refinedstorage/gui/GuiCrafter.java | 4 +- .../gui/control/SideButtonCrafterMode.java | 27 ++++ .../refinedstorage/tile/TileCrafter.java | 2 + .../assets/refinedstorage/lang/en_us.lang | 7 + .../assets/refinedstorage/textures/icons.png | Bin 5598 -> 5599 bytes 10 files changed, 226 insertions(+), 79 deletions(-) create mode 100644 src/main/java/com/raoulvdberge/refinedstorage/gui/control/SideButtonCrafterMode.java diff --git a/build.gradle b/build.gradle index caa86a3d6..7def66913 100755 --- a/build.gradle +++ b/build.gradle @@ -16,7 +16,7 @@ apply plugin: 'maven' apply plugin: 'maven-publish' apply plugin: 'net.minecraftforge.gradle.forge' -version = "1.6.5" +version = "1.6.6" def env = System.getenv() if (env.BUILD_NUMBER) { version = version + "-" + "${env.BUILD_NUMBER}" diff --git a/src/main/java/com/raoulvdberge/refinedstorage/api/autocrafting/ICraftingPatternContainer.java b/src/main/java/com/raoulvdberge/refinedstorage/api/autocrafting/ICraftingPatternContainer.java index e54bab1d4..ca58dec09 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/api/autocrafting/ICraftingPatternContainer.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/api/autocrafting/ICraftingPatternContainer.java @@ -88,4 +88,17 @@ public interface ICraftingPatternContainer { * @return the UUID of this container */ UUID getUuid(); + + /** + * @return true if the connected inventory is locked for processing patterns, false otherwise + */ + default boolean isLocked() { + return false; + } + + /** + * Called when this container is used by a processing pattern to insert items or fluids in the connected inventory. + */ + default void onUsedForProcessing() { + } } diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/CraftingTask.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/CraftingTask.java index 9368a2558..a375a2c0d 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/CraftingTask.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/CraftingTask.java @@ -641,72 +641,78 @@ public class CraftingTask implements ICraftingTask { if (ticks % getTickInterval(p.getPattern().getContainer().getSpeedUpgradeCount()) == 0) { ProcessingState originalState = p.getState(); - boolean hasAll = true; + if (p.getPattern().getContainer().isLocked()) { + p.setState(ProcessingState.LOCKED); + } else { + boolean hasAll = true; - for (ItemStack need : p.getItemsToPut()) { - if (p.getPattern().getContainer().getConnectedInventory() == null) { - p.setState(ProcessingState.MACHINE_NONE); - } else { - ItemStack result = this.internalStorage.extract(need, need.getCount(), getFlags(need), Action.SIMULATE); - - if (result == null || result.getCount() != need.getCount()) { - hasAll = false; - - break; - } else if (!ItemHandlerHelper.insertItem(p.getPattern().getContainer().getConnectedInventory(), result, true).isEmpty()) { - p.setState(ProcessingState.MACHINE_DOES_NOT_ACCEPT); - - break; - } else { - p.setState(ProcessingState.READY); - } - } - } - - for (FluidStack need : p.getFluidsToPut()) { - if (p.getPattern().getContainer().getConnectedFluidInventory() == null) { - p.setState(ProcessingState.MACHINE_NONE); - } else { - FluidStack result = this.internalFluidStorage.extract(need, need.amount, IComparer.COMPARE_NBT, Action.SIMULATE); - - if (result == null || result.amount != need.amount) { - hasAll = false; - - break; - } else if (p.getPattern().getContainer().getConnectedFluidInventory().fill(result, false) != result.amount) { - p.setState(ProcessingState.MACHINE_DOES_NOT_ACCEPT); - - break; - } else if (p.getState() == ProcessingState.READY) { // If the items were ok. - p.setState(ProcessingState.READY); - } - } - } - - if (p.getState() == ProcessingState.READY && hasAll) { for (ItemStack need : p.getItemsToPut()) { - ItemStack result = this.internalStorage.extract(need, need.getCount(), getFlags(need), Action.PERFORM); - if (result == null || result.getCount() != need.getCount()) { - throw new IllegalStateException("Could not extract from the internal inventory even though we could"); - } + if (p.getPattern().getContainer().getConnectedInventory() == null) { + p.setState(ProcessingState.MACHINE_NONE); + } else { + ItemStack result = this.internalStorage.extract(need, need.getCount(), getFlags(need), Action.SIMULATE); - if (!ItemHandlerHelper.insertItem(p.getPattern().getContainer().getConnectedInventory(), result, false).isEmpty()) { - throw new IllegalStateException("Can't fill up inventory even though we could"); + if (result == null || result.getCount() != need.getCount()) { + hasAll = false; + + break; + } else if (!ItemHandlerHelper.insertItem(p.getPattern().getContainer().getConnectedInventory(), result, true).isEmpty()) { + p.setState(ProcessingState.MACHINE_DOES_NOT_ACCEPT); + + break; + } else { + p.setState(ProcessingState.READY); + } } } for (FluidStack need : p.getFluidsToPut()) { - FluidStack result = this.internalFluidStorage.extract(need, need.amount, IComparer.COMPARE_NBT, Action.PERFORM); - if (result == null || result.amount != need.amount) { - throw new IllegalStateException("Could not extract from the internal inventory even though we could"); - } + if (p.getPattern().getContainer().getConnectedFluidInventory() == null) { + p.setState(ProcessingState.MACHINE_NONE); + } else { + FluidStack result = this.internalFluidStorage.extract(need, need.amount, IComparer.COMPARE_NBT, Action.SIMULATE); - if (p.getPattern().getContainer().getConnectedFluidInventory().fill(result, true) != result.amount) { - throw new IllegalStateException("Can't fill up inventory even though we could"); + if (result == null || result.amount != need.amount) { + hasAll = false; + + break; + } else if (p.getPattern().getContainer().getConnectedFluidInventory().fill(result, false) != result.amount) { + p.setState(ProcessingState.MACHINE_DOES_NOT_ACCEPT); + + break; + } else if (p.getState() == ProcessingState.READY) { // If the items were ok. + p.setState(ProcessingState.READY); + } } } - p.setState(ProcessingState.EXTRACTED_ALL); + if (p.getState() == ProcessingState.READY && hasAll) { + for (ItemStack need : p.getItemsToPut()) { + ItemStack result = this.internalStorage.extract(need, need.getCount(), getFlags(need), Action.PERFORM); + if (result == null || result.getCount() != need.getCount()) { + throw new IllegalStateException("Could not extract from the internal inventory even though we could"); + } + + if (!ItemHandlerHelper.insertItem(p.getPattern().getContainer().getConnectedInventory(), result, false).isEmpty()) { + throw new IllegalStateException("Can't fill up inventory even though we could"); + } + } + + for (FluidStack need : p.getFluidsToPut()) { + FluidStack result = this.internalFluidStorage.extract(need, need.amount, IComparer.COMPARE_NBT, Action.PERFORM); + if (result == null || result.amount != need.amount) { + throw new IllegalStateException("Could not extract from the internal inventory even though we could"); + } + + if (p.getPattern().getContainer().getConnectedFluidInventory().fill(result, true) != result.amount) { + throw new IllegalStateException("Can't fill up inventory even though we could"); + } + } + + p.setState(ProcessingState.EXTRACTED_ALL); + + p.getPattern().getContainer().onUsedForProcessing(); + } } if (originalState != p.getState()) { @@ -959,7 +965,7 @@ public class CraftingTask implements ICraftingTask { for (ItemStack put : processing.getItemsToPut()) { elements.add(new CraftingMonitorElementItemRender(put, 0, 0, put.getCount(), 0, 0)); } - } else if (processing.getState() == ProcessingState.READY || processing.getState() == ProcessingState.MACHINE_DOES_NOT_ACCEPT || processing.getState() == ProcessingState.MACHINE_NONE) { + } else if (processing.getState() == ProcessingState.READY || processing.getState() == ProcessingState.MACHINE_DOES_NOT_ACCEPT || processing.getState() == ProcessingState.MACHINE_NONE || processing.getState() == ProcessingState.LOCKED) { for (ItemStack receive : processing.getItemsToReceive().getStacks()) { ICraftingMonitorElement element = new CraftingMonitorElementItemRender(receive, 0, 0, 0, receive.getCount(), 0); @@ -967,6 +973,8 @@ public class CraftingTask implements ICraftingTask { element = new CraftingMonitorElementError(element, "gui.refinedstorage:crafting_monitor.machine_does_not_accept_item"); } else if (processing.getState() == ProcessingState.MACHINE_NONE) { element = new CraftingMonitorElementError(element, "gui.refinedstorage:crafting_monitor.machine_none"); + } else if (processing.getState() == ProcessingState.LOCKED) { + element = new CraftingMonitorElementError(element, "gui.refinedstorage:crafting_monitor.crafter_is_locked"); } elements.add(element); diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/ProcessingState.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/ProcessingState.java index 023938a42..bec94ee3c 100644 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/ProcessingState.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/ProcessingState.java @@ -5,5 +5,6 @@ enum ProcessingState { EXTRACTED_ALL, MACHINE_NONE, MACHINE_DOES_NOT_ACCEPT, - PROCESSED + PROCESSED, + LOCKED } diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/node/NetworkNodeCrafter.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/node/NetworkNodeCrafter.java index 673568a3f..6245413ba 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/node/NetworkNodeCrafter.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/node/NetworkNodeCrafter.java @@ -30,20 +30,38 @@ import java.util.List; import java.util.UUID; public class NetworkNodeCrafter extends NetworkNode implements ICraftingPatternContainer { + public enum CrafterMode { + IGNORE, + SIGNAL_UNLOCKS_AUTOCRAFTING, + SIGNAL_LOCKS_AUTOCRAFTING, + PULSE_INSERTS_NEXT_SET; + + public static CrafterMode getById(int id) { + if (id >= 0 && id < values().length) { + return values()[id]; + } + + return IGNORE; + } + } + public static final String ID = "crafter"; public static final String DEFAULT_NAME = "gui.refinedstorage:crafter"; private static final String NBT_DISPLAY_NAME = "DisplayName"; private static final String NBT_UUID = "CrafterUuid"; + private static final String NBT_MODE = "Mode"; + private static final String NBT_LOCKED = "Locked"; + private static final String NBT_WAS_POWERED = "WasPowered"; - private ItemHandlerBase patterns = new ItemHandlerBase(9, new ListenerNetworkNode(this), s -> isValidPatternInSlot(world, s)) { + private ItemHandlerBase patternsInventory = new ItemHandlerBase(9, new ListenerNetworkNode(this), s -> isValidPatternInSlot(world, s)) { @Override protected void onContentsChanged(int slot) { super.onContentsChanged(slot); if (!world.isRemote) { - rebuildPatterns(); + invalidate(); } if (network != null) { @@ -61,13 +79,17 @@ public class NetworkNodeCrafter extends NetworkNode implements ICraftingPatternC return stack.getItem() instanceof ICraftingPatternProvider && ((ICraftingPatternProvider) stack.getItem()).create(world, stack, null).isValid(); } - private List actualPatterns = new ArrayList<>(); + private List patterns = new ArrayList<>(); private ItemHandlerUpgrade upgrades = new ItemHandlerUpgrade(4, new ListenerNetworkNode(this), ItemUpgrade.TYPE_SPEED); // Used to prevent infinite recursion on getRootContainer() when there's e.g. two crafters facing each other. private boolean visited = false; + private CrafterMode mode = CrafterMode.IGNORE; + private boolean locked = false; + private boolean wasPowered; + @Nullable private String displayName; @@ -78,17 +100,17 @@ public class NetworkNodeCrafter extends NetworkNode implements ICraftingPatternC super(world, pos); } - private void rebuildPatterns() { - actualPatterns.clear(); + private void invalidate() { + patterns.clear(); - for (int i = 0; i < patterns.getSlots(); ++i) { - ItemStack patternStack = patterns.getStackInSlot(i); + for (int i = 0; i < patternsInventory.getSlots(); ++i) { + ItemStack patternStack = patternsInventory.getStackInSlot(i); if (!patternStack.isEmpty()) { ICraftingPattern pattern = ((ICraftingPatternProvider) patternStack.getItem()).create(world, patternStack, this); if (pattern.isValid()) { - actualPatterns.add(pattern); + patterns.add(pattern); } } } @@ -96,7 +118,7 @@ public class NetworkNodeCrafter extends NetworkNode implements ICraftingPatternC @Override public int getEnergyUsage() { - return RS.INSTANCE.config.crafterUsage + upgrades.getEnergyUsage() + (RS.INSTANCE.config.crafterPerPatternUsage * actualPatterns.size()); + return RS.INSTANCE.config.crafterUsage + upgrades.getEnergyUsage() + (RS.INSTANCE.config.crafterPerPatternUsage * patterns.size()); } @Override @@ -104,7 +126,20 @@ public class NetworkNodeCrafter extends NetworkNode implements ICraftingPatternC super.update(); if (ticks == 1) { - rebuildPatterns(); + invalidate(); + } + + if (mode == CrafterMode.PULSE_INSERTS_NEXT_SET) { + if (world.isBlockPowered(pos)) { + this.wasPowered = true; + + markDirty(); + } else if (wasPowered) { + this.wasPowered = false; + this.locked = false; + + markDirty(); + } } } @@ -132,9 +167,9 @@ public class NetworkNodeCrafter extends NetworkNode implements ICraftingPatternC public void read(NBTTagCompound tag) { super.read(tag); - StackUtils.readItems(patterns, 0, tag); + StackUtils.readItems(patternsInventory, 0, tag); - if (API.instance().getOneSixMigrationHelper().migratePatternInventory(patterns)) { + if (API.instance().getOneSixMigrationHelper().migratePatternInventory(patternsInventory)) { markDirty(); } @@ -147,6 +182,18 @@ public class NetworkNodeCrafter extends NetworkNode implements ICraftingPatternC if (tag.hasUniqueId(NBT_UUID)) { uuid = tag.getUniqueId(NBT_UUID); } + + if (tag.hasKey(NBT_MODE)) { + mode = CrafterMode.getById(tag.getInteger(NBT_MODE)); + } + + if (tag.hasKey(NBT_LOCKED)) { + locked = tag.getBoolean(NBT_LOCKED); + } + + if (tag.hasKey(NBT_WAS_POWERED)) { + wasPowered = tag.getBoolean(NBT_WAS_POWERED); + } } @Override @@ -158,7 +205,7 @@ public class NetworkNodeCrafter extends NetworkNode implements ICraftingPatternC public NBTTagCompound write(NBTTagCompound tag) { super.write(tag); - StackUtils.writeItems(patterns, 0, tag); + StackUtils.writeItems(patternsInventory, 0, tag); StackUtils.writeItems(upgrades, 1, tag); if (displayName != null) { @@ -169,6 +216,10 @@ public class NetworkNodeCrafter extends NetworkNode implements ICraftingPatternC tag.setUniqueId(NBT_UUID, uuid); } + tag.setInteger(NBT_MODE, mode.ordinal()); + tag.setBoolean(NBT_LOCKED, locked); + tag.setBoolean(NBT_WAS_POWERED, wasPowered); + return tag; } @@ -212,13 +263,13 @@ public class NetworkNodeCrafter extends NetworkNode implements ICraftingPatternC @Override public List getPatterns() { - return actualPatterns; + return patterns; } @Override @Nullable public IItemHandlerModifiable getPatternInventory() { - return patterns; + return patternsInventory; } @Override @@ -254,8 +305,20 @@ public class NetworkNodeCrafter extends NetworkNode implements ICraftingPatternC return pos; } + public CrafterMode getMode() { + return mode; + } + + public void setMode(CrafterMode mode) { + this.mode = mode; + this.wasPowered = false; + this.locked = false; + + this.markDirty(); + } + public IItemHandler getPatternItems() { - return patterns; + return patternsInventory; } public IItemHandler getUpgrades() { @@ -264,7 +327,7 @@ public class NetworkNodeCrafter extends NetworkNode implements ICraftingPatternC @Override public IItemHandler getDrops() { - return new CombinedInvWrapper(patterns, upgrades); + return new CombinedInvWrapper(patternsInventory, upgrades); } @Override @@ -293,11 +356,37 @@ public class NetworkNodeCrafter extends NetworkNode implements ICraftingPatternC @Override public UUID getUuid() { - if (uuid == null) { - uuid = UUID.randomUUID(); + if (this.uuid == null) { + this.uuid = UUID.randomUUID(); + markDirty(); } return uuid; } + + @Override + public boolean isLocked() { + switch (mode) { + case IGNORE: + return false; + case SIGNAL_LOCKS_AUTOCRAFTING: + return world.isBlockPowered(pos); + case SIGNAL_UNLOCKS_AUTOCRAFTING: + return !world.isBlockPowered(pos); + case PULSE_INSERTS_NEXT_SET: + return locked; + default: + return false; + } + } + + @Override + public void onUsedForProcessing() { + if (mode == CrafterMode.PULSE_INSERTS_NEXT_SET) { + this.locked = true; + + markDirty(); + } + } } diff --git a/src/main/java/com/raoulvdberge/refinedstorage/gui/GuiCrafter.java b/src/main/java/com/raoulvdberge/refinedstorage/gui/GuiCrafter.java index 57b65bca2..21e41c181 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/gui/GuiCrafter.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/gui/GuiCrafter.java @@ -1,7 +1,7 @@ package com.raoulvdberge.refinedstorage.gui; import com.raoulvdberge.refinedstorage.container.ContainerCrafter; -import com.raoulvdberge.refinedstorage.gui.control.SideButtonRedstoneMode; +import com.raoulvdberge.refinedstorage.gui.control.SideButtonCrafterMode; import com.raoulvdberge.refinedstorage.tile.TileCrafter; import com.raoulvdberge.refinedstorage.util.RenderUtils; @@ -12,7 +12,7 @@ public class GuiCrafter extends GuiBase { @Override public void init(int x, int y) { - addSideButton(new SideButtonRedstoneMode(this, TileCrafter.REDSTONE_MODE)); + addSideButton(new SideButtonCrafterMode(this)); } @Override diff --git a/src/main/java/com/raoulvdberge/refinedstorage/gui/control/SideButtonCrafterMode.java b/src/main/java/com/raoulvdberge/refinedstorage/gui/control/SideButtonCrafterMode.java new file mode 100644 index 000000000..a56289070 --- /dev/null +++ b/src/main/java/com/raoulvdberge/refinedstorage/gui/control/SideButtonCrafterMode.java @@ -0,0 +1,27 @@ +package com.raoulvdberge.refinedstorage.gui.control; + +import com.raoulvdberge.refinedstorage.gui.GuiBase; +import com.raoulvdberge.refinedstorage.tile.TileCrafter; +import com.raoulvdberge.refinedstorage.tile.data.TileDataManager; +import net.minecraft.util.text.TextFormatting; + +public class SideButtonCrafterMode extends SideButton { + public SideButtonCrafterMode(GuiBase gui) { + super(gui); + } + + @Override + public String getTooltip() { + return GuiBase.t("sidebutton.refinedstorage:crafter_mode") + "\n" + TextFormatting.GRAY + GuiBase.t("sidebutton.refinedstorage:crafter_mode." + TileCrafter.MODE.getValue()); + } + + @Override + protected void drawButtonIcon(int x, int y) { + gui.drawTexture(x, y, TileCrafter.MODE.getValue() * 16, 0, 16, 16); + } + + @Override + public void actionPerformed() { + TileDataManager.setParameter(TileCrafter.MODE, TileCrafter.MODE.getValue() + 1); + } +} diff --git a/src/main/java/com/raoulvdberge/refinedstorage/tile/TileCrafter.java b/src/main/java/com/raoulvdberge/refinedstorage/tile/TileCrafter.java index 84ed7ae59..1b0526f79 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/tile/TileCrafter.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/tile/TileCrafter.java @@ -14,9 +14,11 @@ import javax.annotation.Nullable; public class TileCrafter extends TileNode { public static final TileDataParameter NAME = new TileDataParameter<>(DataSerializers.STRING, NetworkNodeCrafter.DEFAULT_NAME, t -> t.getNode().getName()); + public static final TileDataParameter MODE = new TileDataParameter<>(DataSerializers.VARINT, NetworkNodeCrafter.CrafterMode.IGNORE.ordinal(), t -> t.getNode().getMode().ordinal(), (t, v) -> t.getNode().setMode(NetworkNodeCrafter.CrafterMode.getById(v))); public TileCrafter() { dataManager.addWatchedParameter(NAME); + dataManager.addWatchedParameter(MODE); } @Override diff --git a/src/main/resources/assets/refinedstorage/lang/en_us.lang b/src/main/resources/assets/refinedstorage/lang/en_us.lang index c8397754a..b5006f071 100644 --- a/src/main/resources/assets/refinedstorage/lang/en_us.lang +++ b/src/main/resources/assets/refinedstorage/lang/en_us.lang @@ -36,6 +36,7 @@ gui.refinedstorage:crafting_monitor.crafting=Crafting: %d gui.refinedstorage:crafting_monitor.machine_does_not_accept_item=Machine doesn't accept item gui.refinedstorage:crafting_monitor.machine_does_not_accept_fluid=Machine doesn't accept fluid gui.refinedstorage:crafting_monitor.machine_none=No machine found +gui.refinedstorage:crafting_monitor.crafter_is_locked=Crafter is locked gui.refinedstorage:wireless_transmitter=Wireless Transmitter gui.refinedstorage:wireless_transmitter.distance=%d block(s) gui.refinedstorage:crafter=Crafter @@ -141,6 +142,12 @@ sidebutton.refinedstorage:redstone_mode.0=Ignore redstone signal sidebutton.refinedstorage:redstone_mode.1=Only work with redstone signal sidebutton.refinedstorage:redstone_mode.2=Only work without redstone signal +sidebutton.refinedstorage:crafter_mode=Crafter mode +sidebutton.refinedstorage:crafter_mode.0=Ignore redstone signal +sidebutton.refinedstorage:crafter_mode.1=Redstone signal unlocks autocrafting +sidebutton.refinedstorage:crafter_mode.2=Redstone signal locks autocrafting +sidebutton.refinedstorage:crafter_mode.3=Redstone pulse inserts next set + sidebutton.refinedstorage:grid.view_type=Display sidebutton.refinedstorage:grid.view_type.0=Normal sidebutton.refinedstorage:grid.view_type.1=No craftables diff --git a/src/main/resources/assets/refinedstorage/textures/icons.png b/src/main/resources/assets/refinedstorage/textures/icons.png index 87b4682537978491368060a079570c1c2a3dea5f..f20aee70c34241bc21c6930f2839b9b338d94aef 100755 GIT binary patch literal 5599 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 E0X6(tUjP6A literal 5598 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