Allow crafters to be daisy-chained (#1740)
* Allow crafters to be daisy-chained In crafting situations that require more than the 9 blocking patterns that one crafter allows, the only solution is to duplicate the setup to allow a second crafter. This CL allows crafters to be daisy-chained to provide a solution to this issue. Also, since unlimited crafters can now be placed on a single inventory, this eliminates the need to have multiple intermediate inventories which then pipe into the desired inventory. This also improves the crafting manager UI as now those patterns can all be listed under one "Furnace" instead of (potentially multiple) "Chest"s. * Update crafting manager on crafter rotate * Revert .gitignore change and fix crash * Refactor * Remove Set import * Address comments
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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<String, List<IItemHandlerModifiable>> 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.
|
||||
*
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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<String, List<IItemHandlerModifiable>> containerInventories = new LinkedHashMap<>();
|
||||
private CraftingPatternChainList patterns = new CraftingPatternChainList();
|
||||
|
||||
// A map of blockers to blockees.
|
||||
private Map<UUID, UUID> blockingContainers = new HashMap<>();
|
||||
// A set of blockees.
|
||||
private Set<UUID> blockedContainers = new HashSet<>();
|
||||
|
||||
private List<ICraftingTask> craftingTasks = new ArrayList<>();
|
||||
private List<ICraftingTask> craftingTasksToAdd = new ArrayList<>();
|
||||
private List<ICraftingTask> 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<UUID, UUID> 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user