diff --git a/CHANGELOG.md b/CHANGELOG.md index efbd354bb..167b798f4 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Refined Storage Changelog +### 1.5.34 +- Allow crafters to be daisy-chained (tomKPZ) + ### 1.5.33 - Added Crafter Manager (raoulvdberge) - Patterns in the Crafter slots now automatically render the output without pressing shift (raoulvdberge) diff --git a/src/main/java/com/raoulvdberge/refinedstorage/api/autocrafting/ICraftingManager.java b/src/main/java/com/raoulvdberge/refinedstorage/api/autocrafting/ICraftingManager.java index 36127e811..2f46c70d1 100644 --- a/src/main/java/com/raoulvdberge/refinedstorage/api/autocrafting/ICraftingManager.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/api/autocrafting/ICraftingManager.java @@ -12,6 +12,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.List; import java.util.Map; +import java.util.UUID; /** * The crafting manager handles the storing, updating, adding and deleting of crafting tasks in a network. @@ -32,6 +33,29 @@ public interface ICraftingManager { */ Map> getNamedContainers(); + /** + * @param blocker the container that is blocking another container + * @param blockee the container being blocked, may be the same as blocker + */ + void addContainerBlock(UUID blocker, UUID blockee); + + /** + * @param blocker the container that is blocking another container + */ + void removeContainerBlock(UUID blocker); + + /** + * @param blockee the container to check + * @return whether the container is blocked + */ + boolean isContainerBlocked(UUID blockee); + + /** + * @param container the container to set the blocking state for + * @param blocked whether the container should be blocked + */ + void setContainerBlocked(ICraftingPatternContainer container, boolean blocked); + /** * Adds a crafting task. * 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 30899c5c8..701d49533 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/api/autocrafting/ICraftingPatternContainer.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/api/autocrafting/ICraftingPatternContainer.java @@ -1,12 +1,15 @@ package com.raoulvdberge.refinedstorage.api.autocrafting; import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.IItemHandlerModifiable; import javax.annotation.Nullable; + import java.util.List; +import java.util.UUID; /** * Represents a network node that contains crafting patterns. @@ -18,15 +21,25 @@ public interface ICraftingPatternContainer { int getSpeedUpdateCount(); /** - * @return the inventory that this container is facing + * @return the inventory that this container is connected to */ - IItemHandler getFacingInventory(); + IItemHandler getConnectedInventory(); + + /** + * @return the tile that this container is connected to + */ + TileEntity getConnectedTile(); /** * @return the tile that this container is facing */ TileEntity getFacingTile(); + /** + * @return the direction to the facing tile + */ + EnumFacing getDirection(); + /** * @return the patterns stored in this container */ @@ -53,12 +66,23 @@ public interface ICraftingPatternContainer { BlockPos getPosition(); /** - * @return true if this container is blocked, false otherwise + * Containers may be daisy-chained together. If this container points to + * another one, gets the root container in the chain. If containers are + * not daisy-chained, returns this container. If there was a container + * loop, returns null. + * + * @return the root pattern container + */ + @Nullable + ICraftingPatternContainer getRootContainer(); + + /** + * @return true if this container or its proxy is blocked, false otherwise */ boolean isBlocked(); /** - * @param blocked whether the container should be blocked + * @return the UUID of this container */ - void setBlocked(boolean blocked); + UUID getUuid(); } diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/CraftingManager.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/CraftingManager.java index 345769489..f8cdcc61a 100644 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/CraftingManager.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/CraftingManager.java @@ -27,10 +27,14 @@ import net.minecraftforge.items.ItemHandlerHelper; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.*; +import java.util.Map.Entry; import java.util.stream.Collectors; public class CraftingManager implements ICraftingManager { private static final String NBT_CRAFTING_TASKS = "CraftingTasks"; + private static final String NBT_BLOCKED_CONTAINERS = "BlockedContainers"; + private static final String NBT_BLOCKER_UUID = "BlockerUuid"; + private static final String NBT_BLOCKEE_UUID = "BlockeeUuid"; private TileController network; @@ -38,6 +42,11 @@ public class CraftingManager implements ICraftingManager { private Map> containerInventories = new LinkedHashMap<>(); private CraftingPatternChainList patterns = new CraftingPatternChainList(); + // A map of blockers to blockees. + private Map blockingContainers = new HashMap<>(); + // A set of blockees. + private Set blockedContainers = new HashSet<>(); + private List craftingTasks = new ArrayList<>(); private List craftingTasksToAdd = new ArrayList<>(); private List craftingTasksToCancel = new ArrayList<>(); @@ -67,6 +76,35 @@ public class CraftingManager implements ICraftingManager { return containerInventories; } + @Override + public void addContainerBlock(UUID blocker, UUID blockee) { + blockedContainers.add(blockee); + blockingContainers.put(blocker, blockee); + } + + @Override + public void removeContainerBlock(UUID blocker) { + blockedContainers.remove(blockingContainers.get(blocker)); + blockingContainers.remove(blocker); + } + + @Override + public boolean isContainerBlocked(UUID blockee) { + return blockedContainers.contains(blockee); + } + + @Override + public void setContainerBlocked(ICraftingPatternContainer container, boolean blocked) { + if (blocked) { + ICraftingPatternContainer proxy = container.getRootContainer(); + if (proxy != null) { + addContainerBlock(container.getUuid(), proxy.getUuid()); + } + } else { + removeContainerBlock(container.getUuid()); + } + } + @Override public void add(@Nonnull ICraftingTask task) { craftingTasksToAdd.add(task); @@ -230,23 +268,37 @@ public class CraftingManager implements ICraftingManager { public void readFromNBT(NBTTagCompound tag) { if (tag.hasKey(NBT_CRAFTING_TASKS)) { NBTTagList taskList = tag.getTagList(NBT_CRAFTING_TASKS, Constants.NBT.TAG_COMPOUND); - for (int i = 0; i < taskList.tagCount(); ++i) { craftingTasksToRead.add(taskList.getCompoundTagAt(i)); } } + + if (tag.hasKey(NBT_BLOCKED_CONTAINERS)) { + NBTTagList containerList = tag.getTagList(NBT_BLOCKED_CONTAINERS, Constants.NBT.TAG_COMPOUND); + for (int i = 0; i < containerList.tagCount(); ++i) { + NBTTagCompound compound = containerList.getCompoundTagAt(i); + addContainerBlock(compound.getUniqueId(NBT_BLOCKER_UUID), compound.getUniqueId(NBT_BLOCKEE_UUID)); + } + } } @Override public NBTTagCompound writeToNBT(NBTTagCompound tag) { NBTTagList craftingTaskList = new NBTTagList(); - for (ICraftingTask task : craftingTasks) { craftingTaskList.appendTag(task.writeToNBT(new NBTTagCompound())); } - tag.setTag(NBT_CRAFTING_TASKS, craftingTaskList); + NBTTagList blockingContainersList = new NBTTagList(); + for (Entry pair : blockingContainers.entrySet()) { + NBTTagCompound compound = new NBTTagCompound(); + compound.setUniqueId(NBT_BLOCKER_UUID, pair.getKey()); + compound.setUniqueId(NBT_BLOCKEE_UUID, pair.getValue()); + blockingContainersList.appendTag(compound); + } + tag.setTag(NBT_BLOCKED_CONTAINERS, blockingContainersList); + return tag; } diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/CraftingStep.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/CraftingStep.java index 9c92059e1..f86adf8c3 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/CraftingStep.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/CraftingStep.java @@ -122,7 +122,7 @@ public abstract class CraftingStep implements ICraftingStep { @Override public void setStartedProcessing() { if (getPattern().isBlocking()) { - getPattern().getContainer().setBlocked(true); + network.getCraftingManager().setContainerBlocked(getPattern().getContainer(), true); } startedProcessing = true; @@ -144,7 +144,7 @@ public abstract class CraftingStep implements ICraftingStep { } if (getPattern().isBlocking()) { - getPattern().getContainer().setBlocked(false); + network.getCraftingManager().setContainerBlocked(getPattern().getContainer(), false); } return true; diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/CraftingStepProcess.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/CraftingStepProcess.java index 12c2401bb..af1b4c5e3 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/CraftingStepProcess.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/CraftingStepProcess.java @@ -35,7 +35,7 @@ public class CraftingStepProcess extends CraftingStep { return false; } - IItemHandler inventory = getPattern().getContainer().getFacingInventory(); + IItemHandler inventory = getPattern().getContainer().getConnectedInventory(); int compare = CraftingTask.DEFAULT_COMPARE | (pattern.isOredict() ? IComparer.COMPARE_OREDICT : 0); @@ -80,7 +80,7 @@ public class CraftingStepProcess extends CraftingStep { return false; } - IItemHandler inventory = getPattern().getContainer().getFacingInventory(); + IItemHandler inventory = getPattern().getContainer().getConnectedInventory(); return inventory != null && insertItems(inventory, new LinkedList<>(getInputs()), true); } @@ -92,7 +92,7 @@ public class CraftingStepProcess extends CraftingStep { int compare = CraftingTask.DEFAULT_COMPARE | (getPattern().isOredict() ? IComparer.COMPARE_OREDICT : 0); if (extractItems(extracted, compare, toInsertItems)) { - IItemHandler inventory = getPattern().getContainer().getFacingInventory(); + IItemHandler inventory = getPattern().getContainer().getConnectedInventory(); if (insertItems(inventory, new ArrayDeque<>(extracted), true)) { insertItems(inventory, extracted, false); 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 52f13df29..5bc3044ec 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 @@ -404,7 +404,7 @@ public class CraftingTask implements ICraftingTask { for (ICraftingStep step : getSteps()) { if (step.getPattern().isBlocking()) { - step.getPattern().getContainer().setBlocked(false); + network.getCraftingManager().setContainerBlocked(step.getPattern().getContainer(), false); } } @@ -670,7 +670,7 @@ public class CraftingTask implements ICraftingTask { 32 ); - if (step.getPattern().getContainer().getFacingTile() == null) { + if (step.getPattern().getContainer().getConnectedTile() == null) { element = new CraftingMonitorElementError(element, "gui.refinedstorage:crafting_monitor.machine_none"); } else if (!step.hasStartedProcessing() && !step.canStartProcessing()) { element = new CraftingMonitorElementError(element, "gui.refinedstorage:crafting_monitor.machine_in_use"); diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/node/NetworkNode.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/node/NetworkNode.java index 7a397aef6..36161b739 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/node/NetworkNode.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/node/NetworkNode.java @@ -215,7 +215,15 @@ public abstract class NetworkNode implements INetworkNode, INetworkNodeVisitor, // @todo: Move this data to the network node. public void resetDirection() { - this.direction = ((TileBase) (IntegrationMCMP.isLoaded() ? RSMCMPAddon.unwrapTile(world, pos) : world.getTileEntity(pos))).getDirection(); + EnumFacing direction = ((TileBase) (IntegrationMCMP.isLoaded() ? RSMCMPAddon.unwrapTile(world, pos) : world.getTileEntity(pos))).getDirection(); + if (!direction.equals(this.direction)) { + this.direction = direction; + onDirectionChanged(); + } + } + + protected void onDirectionChanged() { + // NO OP } @Nullable 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 9c6a2881c..04a6ba8f4 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 @@ -5,6 +5,8 @@ import com.raoulvdberge.refinedstorage.api.autocrafting.ICraftingPattern; import com.raoulvdberge.refinedstorage.api.autocrafting.ICraftingPatternContainer; import com.raoulvdberge.refinedstorage.api.autocrafting.ICraftingPatternProvider; import com.raoulvdberge.refinedstorage.api.network.INetwork; +import com.raoulvdberge.refinedstorage.api.network.node.INetworkNode; +import com.raoulvdberge.refinedstorage.apiimpl.API; import com.raoulvdberge.refinedstorage.inventory.ItemHandlerBase; import com.raoulvdberge.refinedstorage.inventory.ItemHandlerListenerNetworkNode; import com.raoulvdberge.refinedstorage.inventory.ItemHandlerUpgrade; @@ -24,14 +26,15 @@ import net.minecraftforge.items.wrapper.CombinedInvWrapper; import javax.annotation.Nullable; import java.util.ArrayList; import java.util.List; +import java.util.UUID; public class NetworkNodeCrafter extends NetworkNode implements ICraftingPatternContainer { public static final String ID = "crafter"; public static final String DEFAULT_NAME = "gui.refinedstorage:crafter"; - private static final String NBT_BLOCKED = "Blocked"; private static final String NBT_DISPLAY_NAME = "DisplayName"; + private static final String NBT_UUID = "CrafterUuid"; private ItemHandlerBase patterns = new ItemHandlerBase(9, new ItemHandlerListenerNetworkNode(this), s -> isValidPatternInSlot(world, s)) { @Override @@ -61,11 +64,16 @@ public class NetworkNodeCrafter extends NetworkNode implements ICraftingPatternC private ItemHandlerUpgrade upgrades = new ItemHandlerUpgrade(4, new ItemHandlerListenerNetworkNode(this), ItemUpgrade.TYPE_SPEED); - private boolean blocked = false; + // Used to prevent infinite recursion on getRootContainer() when + // there's eg. two crafters facing each other. + private boolean visited = false; @Nullable private String displayName; + @Nullable + private UUID uuid = null; + public NetworkNodeCrafter(World world, BlockPos pos) { super(world, pos); } @@ -108,11 +116,19 @@ public class NetworkNodeCrafter extends NetworkNode implements ICraftingPatternC network.getCraftingManager().getTasks().stream() .filter(task -> task.getPattern().getContainer().getPosition().equals(pos)) .forEach(task -> network.getCraftingManager().cancel(task)); + network.getCraftingManager().setContainerBlocked(this, false); } network.getCraftingManager().rebuild(); } + @Override + protected void onDirectionChanged() { + if (network != null) { + network.getCraftingManager().rebuild(); + } + } + @Override public void read(NBTTagCompound tag) { super.read(tag); @@ -120,13 +136,13 @@ public class NetworkNodeCrafter extends NetworkNode implements ICraftingPatternC StackUtils.readItems(patterns, 0, tag); StackUtils.readItems(upgrades, 1, tag); - if (tag.hasKey(NBT_BLOCKED)) { - blocked = tag.getBoolean(NBT_BLOCKED); - } - if (tag.hasKey(NBT_DISPLAY_NAME)) { displayName = tag.getString(NBT_DISPLAY_NAME); } + + if (tag.hasUniqueId(NBT_UUID)) { + uuid = tag.getUniqueId(NBT_UUID); + } } @Override @@ -141,12 +157,14 @@ public class NetworkNodeCrafter extends NetworkNode implements ICraftingPatternC StackUtils.writeItems(patterns, 0, tag); StackUtils.writeItems(upgrades, 1, tag); - tag.setBoolean(NBT_BLOCKED, blocked); - if (displayName != null) { tag.setString(NBT_DISPLAY_NAME, displayName); } + if (uuid != null) { + tag.setUniqueId(NBT_UUID, uuid); + } + return tag; } @@ -156,8 +174,21 @@ public class NetworkNodeCrafter extends NetworkNode implements ICraftingPatternC } @Override - public IItemHandler getFacingInventory() { - return WorldUtils.getItemHandler(getFacingTile(), getDirection().getOpposite()); + public IItemHandler getConnectedInventory() { + ICraftingPatternContainer proxy = getRootContainer(); + if (proxy == null) { + return null; + } + return WorldUtils.getItemHandler(proxy.getFacingTile(), proxy.getDirection().getOpposite()); + } + + @Override + public TileEntity getConnectedTile() { + ICraftingPatternContainer proxy = getRootContainer(); + if (proxy == null) { + return null; + } + return proxy.getFacingTile(); } @Override @@ -177,7 +208,7 @@ public class NetworkNodeCrafter extends NetworkNode implements ICraftingPatternC return displayName; } - TileEntity facing = getFacingTile(); + TileEntity facing = getConnectedTile(); if (facing instanceof IWorldNameable) { return ((IWorldNameable) facing).getName(); @@ -223,14 +254,35 @@ public class NetworkNodeCrafter extends NetworkNode implements ICraftingPatternC } @Override - public boolean isBlocked() { - return blocked; + @Nullable + public ICraftingPatternContainer getRootContainer() { + if (visited) { + return null; + } + + INetworkNode facing = API.instance().getNetworkNodeManager(world).getNode(pos.offset(getDirection())); + if (!(facing instanceof ICraftingPatternContainer) || facing.getNetwork() != network) { + return this; + } + + visited = true; + ICraftingPatternContainer facingContainer = ((ICraftingPatternContainer)facing).getRootContainer(); + visited = false; + return facingContainer; } @Override - public void setBlocked(boolean blocked) { - this.blocked = blocked; + public boolean isBlocked() { + ICraftingPatternContainer proxy = getRootContainer(); + return proxy != null && network != null && network.getCraftingManager().isContainerBlocked(proxy.getUuid()); + } - markDirty(); + @Override + public UUID getUuid() { + if (uuid == null) { + uuid = UUID.randomUUID(); + markDirty(); + } + return uuid; } }