From 283135f7e72bdddd3872be6aab793c9929af6193 Mon Sep 17 00:00:00 2001 From: raoulvdberge Date: Fri, 28 Jul 2017 22:10:05 +0200 Subject: [PATCH] Fixed performance issue with Controllers turning off and on and Interfaces, fixes #1384 --- CHANGELOG.md | 2 + .../api/network/INetworkNodeGraph.java | 8 ++++ .../api/storage/IStorageCache.java | 5 +-- .../apiimpl/network/NetworkNodeGraph.java | 25 +++++++++-- .../network/node/NetworkNodeFluidStorage.java | 3 +- .../network/node/NetworkNodeInterface.java | 45 ++++++++++++++----- .../network/node/NetworkNodeStorage.java | 3 +- .../node/diskdrive/NetworkNodeDiskDrive.java | 6 ++- .../NetworkNodeExternalStorage.java | 6 ++- .../apiimpl/storage/StorageCacheFluid.java | 18 +++++--- .../apiimpl/storage/StorageCacheItem.java | 18 +++++--- .../storage/StorageCacheItemPortable.java | 15 ++++--- .../inventory/ItemHandlerInterface.java | 5 +-- .../inventory/ItemHandlerStorage.java | 5 +-- .../refinedstorage/tile/TileInterface.java | 2 +- 15 files changed, 113 insertions(+), 53 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 30343ef5e..38ef0ce4e 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ - Fixed more crashes relating to scrollbar in GUIs (raoulvdberge) - Fixed crash with Detector (raoulvdberge) - Fixed bug where pattern create button wasn't visible when grid tabs were selected (raoulvdberge) +- Fixed performance issue with Controllers turning off and on and Interfaces (raoulvdberge) +- Fixed Interfaces exposing network inventory don't hide storages that are disconnected (raoulvdberge) - A Solderer with Speed Upgrades is now 2 times faster (raoulvdberge) ### 1.5.13 diff --git a/src/main/java/com/raoulvdberge/refinedstorage/api/network/INetworkNodeGraph.java b/src/main/java/com/raoulvdberge/refinedstorage/api/network/INetworkNodeGraph.java index 8e5eb2c0f..2a2f179ee 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/api/network/INetworkNodeGraph.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/api/network/INetworkNodeGraph.java @@ -3,6 +3,7 @@ package com.raoulvdberge.refinedstorage.api.network; import com.raoulvdberge.refinedstorage.api.network.node.INetworkNode; import java.util.Collection; +import java.util.function.Consumer; /** * Represents a graph of all the nodes connected to a network. @@ -13,6 +14,13 @@ public interface INetworkNodeGraph { */ void rebuild(); + /** + * Adds a runnable that is run after the graph is rebuilt. + * + * @param action the action to run + */ + void schedulePostRebuildAction(Consumer action); + /** * @return a collection of all connected nodes */ diff --git a/src/main/java/com/raoulvdberge/refinedstorage/api/storage/IStorageCache.java b/src/main/java/com/raoulvdberge/refinedstorage/api/storage/IStorageCache.java index 4b3b42004..05d4feb5b 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/api/storage/IStorageCache.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/api/storage/IStorageCache.java @@ -5,7 +5,6 @@ import com.raoulvdberge.refinedstorage.api.util.IStackList; import javax.annotation.Nonnull; import java.util.List; -import java.util.function.BiConsumer; /** * This holds all stacks from all the connected storages from a {@link INetwork}. @@ -52,14 +51,14 @@ public interface IStorageCache { * * @param listener the listener */ - void addListener(BiConsumer listener); + void addListener(Runnable listener); /** * Removes a listener from the storage cache. * * @param listener the listener */ - void removeListener(BiConsumer listener); + void removeListener(Runnable listener); /** * Resorts the storages in this cache according to their priority. diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/NetworkNodeGraph.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/NetworkNodeGraph.java index df36c9cd9..63bb12835 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/NetworkNodeGraph.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/NetworkNodeGraph.java @@ -2,6 +2,7 @@ package com.raoulvdberge.refinedstorage.apiimpl.network; import com.google.common.collect.Sets; import com.raoulvdberge.refinedstorage.RSBlocks; +import com.raoulvdberge.refinedstorage.api.network.INetwork; import com.raoulvdberge.refinedstorage.api.network.INetworkNodeGraph; import com.raoulvdberge.refinedstorage.api.network.INetworkNodeVisitor; import com.raoulvdberge.refinedstorage.api.network.node.INetworkNode; @@ -16,16 +17,16 @@ import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; -import java.util.ArrayDeque; -import java.util.Collection; -import java.util.Queue; -import java.util.Set; +import java.util.*; +import java.util.function.Consumer; import static com.raoulvdberge.refinedstorage.capability.CapabilityNetworkNodeProxy.NETWORK_NODE_PROXY_CAPABILITY; public class NetworkNodeGraph implements INetworkNodeGraph { private TileController controller; private Set nodes = Sets.newConcurrentHashSet(); + private Set> postRebuildActions = new HashSet<>(); + private boolean rebuilding = false; public NetworkNodeGraph(TileController controller) { this.controller = controller; @@ -41,6 +42,8 @@ public class NetworkNodeGraph implements INetworkNodeGraph { return; } + rebuilding = true; + Operator operator = new Operator(); BlockPos controllerPos = controller.getPos(); @@ -66,9 +69,23 @@ public class NetworkNodeGraph implements INetworkNodeGraph { node.onDisconnected(controller); } + postRebuildActions.forEach(a -> a.accept(controller)); + postRebuildActions.clear(); + if (!operator.newNodes.isEmpty() || !operator.previousNodes.isEmpty()) { controller.getDataManager().sendParameterToWatchers(TileController.NODES); } + + rebuilding = false; + } + + @Override + public void schedulePostRebuildAction(Consumer action) { + if (rebuilding) { + postRebuildActions.add(action); + } else { + action.accept(controller); + } } @Override diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/node/NetworkNodeFluidStorage.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/node/NetworkNodeFluidStorage.java index 851b6e161..c0ca7fa35 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/node/NetworkNodeFluidStorage.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/node/NetworkNodeFluidStorage.java @@ -7,6 +7,7 @@ import com.raoulvdberge.refinedstorage.api.storage.AccessType; import com.raoulvdberge.refinedstorage.api.storage.IStorage; import com.raoulvdberge.refinedstorage.api.storage.IStorageProvider; import com.raoulvdberge.refinedstorage.api.util.IComparer; +import com.raoulvdberge.refinedstorage.apiimpl.storage.StorageCacheFluid; import com.raoulvdberge.refinedstorage.apiimpl.storage.StorageDiskFluid; import com.raoulvdberge.refinedstorage.block.BlockFluidStorage; import com.raoulvdberge.refinedstorage.block.FluidStorageType; @@ -117,7 +118,7 @@ public class NetworkNodeFluidStorage extends NetworkNode implements IGuiStorage, public void onConnectedStateChange(INetwork network, boolean state) { super.onConnectedStateChange(network, state); - network.getFluidStorageCache().invalidate(); + network.getNodeGraph().schedulePostRebuildAction(StorageCacheFluid.INVALIDATE); } @Override diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/node/NetworkNodeInterface.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/node/NetworkNodeInterface.java index 5e6657ed1..866ca7451 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/node/NetworkNodeInterface.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/node/NetworkNodeInterface.java @@ -23,11 +23,24 @@ public class NetworkNodeInterface extends NetworkNode implements IComparable { private ItemHandlerBase importItems = new ItemHandlerBase(9, new ItemHandlerListenerNetworkNode(this)); - private ItemHandlerBase exportSpecimenItems = new ItemHandlerBase(9, new ItemHandlerListenerNetworkNode(this)); + private ItemHandlerBase exportSpecimenItems = new ItemHandlerBase(9, new ItemHandlerListenerNetworkNode(this)) { + @Override + protected void onContentsChanged(int slot) { + super.onContentsChanged(slot); + + if (network != null) { + if (!isEmpty() && itemsStorage != null) { + removeItemStorage(network); + } else if (isEmpty() && itemsStorage == null) { + createItemStorage(network); + } + } + } + }; private ItemHandlerBase exportItems = new ItemHandlerBase(9, new ItemHandlerListenerNetworkNode(this)); private IItemHandler items = new ItemHandlerProxy(importItems, exportItems); - private ItemHandlerInterface itemsNetwork; + private ItemHandlerInterface itemsStorage; private ItemHandlerUpgrade upgrades = new ItemHandlerUpgrade(4, new ItemHandlerListenerNetworkNode(this), ItemUpgrade.TYPE_SPEED, ItemUpgrade.TYPE_STACK, ItemUpgrade.TYPE_CRAFTING); @@ -122,17 +135,25 @@ public class NetworkNodeInterface extends NetworkNode implements IComparable { protected void onConnectedStateChange(INetwork network, boolean state) { super.onConnectedStateChange(network, state); - if (state) { - itemsNetwork = new ItemHandlerInterface(network, network.getItemStorageCache(), importItems); - - network.getItemStorageCache().addListener(itemsNetwork); - } else if (itemsNetwork != null) { - network.getItemStorageCache().removeListener(itemsNetwork); - - itemsNetwork = null; + if (state && exportSpecimenItems.isEmpty()) { + createItemStorage(network); + } else if (itemsStorage != null) { + removeItemStorage(network); } } + private void createItemStorage(INetwork network) { + itemsStorage = new ItemHandlerInterface(network, network.getItemStorageCache(), importItems); + + network.getItemStorageCache().addListener(itemsStorage); + } + + private void removeItemStorage(INetwork network) { + network.getItemStorageCache().removeListener(itemsStorage); + + itemsStorage = null; + } + @Override public int getCompare() { return compare; @@ -204,8 +225,8 @@ public class NetworkNodeInterface extends NetworkNode implements IComparable { return exportItems; } - public IItemHandler getItemsOrNetworkItems() { - return (itemsNetwork != null && exportSpecimenItems.isEmpty()) ? itemsNetwork : items; + public IItemHandler getItemsOrStorage() { + return itemsStorage != null ? itemsStorage : items; } public IItemHandler getItems() { diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/node/NetworkNodeStorage.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/node/NetworkNodeStorage.java index 74344e0e5..d03fed716 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/node/NetworkNodeStorage.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/node/NetworkNodeStorage.java @@ -7,6 +7,7 @@ import com.raoulvdberge.refinedstorage.api.storage.AccessType; import com.raoulvdberge.refinedstorage.api.storage.IStorage; import com.raoulvdberge.refinedstorage.api.storage.IStorageProvider; import com.raoulvdberge.refinedstorage.api.util.IComparer; +import com.raoulvdberge.refinedstorage.apiimpl.storage.StorageCacheItem; import com.raoulvdberge.refinedstorage.apiimpl.storage.StorageDiskItem; import com.raoulvdberge.refinedstorage.block.BlockStorage; import com.raoulvdberge.refinedstorage.block.ItemStorageType; @@ -114,7 +115,7 @@ public class NetworkNodeStorage extends NetworkNode implements IGuiStorage, ISto public void onConnectedStateChange(INetwork network, boolean state) { super.onConnectedStateChange(network, state); - network.getItemStorageCache().invalidate(); + network.getNodeGraph().schedulePostRebuildAction(StorageCacheItem.INVALIDATE); } @Override diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/node/diskdrive/NetworkNodeDiskDrive.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/node/diskdrive/NetworkNodeDiskDrive.java index 59333c48a..a7fe0b5a3 100644 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/node/diskdrive/NetworkNodeDiskDrive.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/node/diskdrive/NetworkNodeDiskDrive.java @@ -6,6 +6,8 @@ import com.raoulvdberge.refinedstorage.api.storage.*; import com.raoulvdberge.refinedstorage.api.util.IComparer; import com.raoulvdberge.refinedstorage.apiimpl.network.node.IGuiStorage; import com.raoulvdberge.refinedstorage.apiimpl.network.node.NetworkNode; +import com.raoulvdberge.refinedstorage.apiimpl.storage.StorageCacheFluid; +import com.raoulvdberge.refinedstorage.apiimpl.storage.StorageCacheItem; import com.raoulvdberge.refinedstorage.inventory.ItemHandlerBase; import com.raoulvdberge.refinedstorage.inventory.ItemHandlerFluid; import com.raoulvdberge.refinedstorage.inventory.ItemHandlerListenerNetworkNode; @@ -132,8 +134,8 @@ public class NetworkNodeDiskDrive extends NetworkNode implements IGuiStorage, IS public void onConnectedStateChange(INetwork network, boolean state) { super.onConnectedStateChange(network, state); - network.getItemStorageCache().invalidate(); - network.getFluidStorageCache().invalidate(); + network.getNodeGraph().schedulePostRebuildAction(StorageCacheItem.INVALIDATE); + network.getNodeGraph().schedulePostRebuildAction(StorageCacheFluid.INVALIDATE); WorldUtils.updateBlock(world, pos); } diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/node/externalstorage/NetworkNodeExternalStorage.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/node/externalstorage/NetworkNodeExternalStorage.java index cf584403f..9dfe6e162 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/node/externalstorage/NetworkNodeExternalStorage.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/node/externalstorage/NetworkNodeExternalStorage.java @@ -9,6 +9,8 @@ import com.raoulvdberge.refinedstorage.api.storage.IStorageProvider; import com.raoulvdberge.refinedstorage.api.util.IComparer; import com.raoulvdberge.refinedstorage.apiimpl.network.node.IGuiStorage; import com.raoulvdberge.refinedstorage.apiimpl.network.node.NetworkNode; +import com.raoulvdberge.refinedstorage.apiimpl.storage.StorageCacheFluid; +import com.raoulvdberge.refinedstorage.apiimpl.storage.StorageCacheItem; import com.raoulvdberge.refinedstorage.capability.CapabilityNetworkNodeProxy; import com.raoulvdberge.refinedstorage.integration.storagedrawers.StorageItemItemRepository; import com.raoulvdberge.refinedstorage.inventory.ItemHandlerBase; @@ -224,8 +226,8 @@ public class NetworkNodeExternalStorage extends NetworkNode implements IStorageP } } - network.getItemStorageCache().invalidate(); - network.getFluidStorageCache().invalidate(); + network.getNodeGraph().schedulePostRebuildAction(StorageCacheItem.INVALIDATE); + network.getNodeGraph().schedulePostRebuildAction(StorageCacheFluid.INVALIDATE); } @Override diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/storage/StorageCacheFluid.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/storage/StorageCacheFluid.java index be00ae0a4..3595210b0 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/storage/StorageCacheFluid.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/storage/StorageCacheFluid.java @@ -13,13 +13,15 @@ import javax.annotation.Nonnull; import java.util.LinkedList; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; -import java.util.function.BiConsumer; +import java.util.function.Consumer; public class StorageCacheFluid implements IStorageCache { + public static final Consumer INVALIDATE = n -> n.getFluidStorageCache().invalidate(); + private INetwork network; private CopyOnWriteArrayList> storages = new CopyOnWriteArrayList<>(); private IStackList list = API.instance().createFluidStackList(); - private List> listeners = new LinkedList<>(); + private List listeners = new LinkedList<>(); public StorageCacheFluid(INetwork network) { this.network = network; @@ -47,6 +49,8 @@ public class StorageCacheFluid implements IStorageCache { } } + listeners.forEach(Runnable::run); + network.sendFluidStorageToClient(); } @@ -56,9 +60,9 @@ public class StorageCacheFluid implements IStorageCache { if (!rebuilding) { network.sendFluidStorageDeltaToClient(stack, size); - } - listeners.forEach(l -> l.accept(stack, size)); + listeners.forEach(Runnable::run); + } } @Override @@ -66,17 +70,17 @@ public class StorageCacheFluid implements IStorageCache { if (list.remove(stack, size)) { network.sendFluidStorageDeltaToClient(stack, -size); - listeners.forEach(l -> l.accept(stack, -size)); + listeners.forEach(Runnable::run); } } @Override - public void addListener(BiConsumer listener) { + public void addListener(Runnable listener) { listeners.add(listener); } @Override - public void removeListener(BiConsumer listener) { + public void removeListener(Runnable listener) { listeners.remove(listener); } diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/storage/StorageCacheItem.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/storage/StorageCacheItem.java index 5c69b4352..b5b5d3290 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/storage/StorageCacheItem.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/storage/StorageCacheItem.java @@ -13,13 +13,15 @@ import javax.annotation.Nonnull; import java.util.LinkedList; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; -import java.util.function.BiConsumer; +import java.util.function.Consumer; public class StorageCacheItem implements IStorageCache { + public static final Consumer INVALIDATE = network -> network.getItemStorageCache().invalidate(); + private INetwork network; private CopyOnWriteArrayList> storages = new CopyOnWriteArrayList<>(); private IStackList list = API.instance().createItemStackList(); - private List> listeners = new LinkedList<>(); + private List listeners = new LinkedList<>(); public StorageCacheItem(INetwork network) { this.network = network; @@ -49,6 +51,8 @@ public class StorageCacheItem implements IStorageCache { } } + listeners.forEach(Runnable::run); + network.sendItemStorageToClient(); } @@ -58,9 +62,9 @@ public class StorageCacheItem implements IStorageCache { if (!rebuilding) { network.sendItemStorageDeltaToClient(stack, size); - } - listeners.forEach(l -> l.accept(stack, size)); + listeners.forEach(Runnable::run); + } } @Override @@ -68,17 +72,17 @@ public class StorageCacheItem implements IStorageCache { if (list.remove(stack, size)) { network.sendItemStorageDeltaToClient(stack, -size); - listeners.forEach(l -> l.accept(stack, -size)); + listeners.forEach(Runnable::run); } } @Override - public void addListener(BiConsumer listener) { + public void addListener(Runnable listener) { listeners.add(listener); } @Override - public void removeListener(BiConsumer listener) { + public void removeListener(Runnable listener) { listeners.remove(listener); } diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/storage/StorageCacheItemPortable.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/storage/StorageCacheItemPortable.java index 0a94019be..c2be7cfa3 100644 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/storage/StorageCacheItemPortable.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/storage/StorageCacheItemPortable.java @@ -17,12 +17,11 @@ import javax.annotation.Nonnull; import java.util.Collections; import java.util.LinkedList; import java.util.List; -import java.util.function.BiConsumer; public class StorageCacheItemPortable implements IStorageCache { private IPortableGrid portableGrid; private IStackList list = API.instance().createItemStackList(); - private List> listeners = new LinkedList<>(); + private List listeners = new LinkedList<>(); public StorageCacheItemPortable(IPortableGrid portableGrid) { this.portableGrid = portableGrid; @@ -36,6 +35,8 @@ public class StorageCacheItemPortable implements IStorageCache { portableGrid.getStorage().getStacks().forEach(list::add); } + listeners.forEach(Runnable::run); + portableGrid.getWatchers().forEach(this::sendUpdateTo); } @@ -45,9 +46,9 @@ public class StorageCacheItemPortable implements IStorageCache { if (!rebuilding) { portableGrid.getWatchers().forEach(w -> RS.INSTANCE.network.sendTo(new MessageGridItemDelta(null, stack, size), (EntityPlayerMP) w)); - } - listeners.forEach(l -> l.accept(stack, size)); + listeners.forEach(Runnable::run); + } } @Override @@ -55,17 +56,17 @@ public class StorageCacheItemPortable implements IStorageCache { if (list.remove(stack, size)) { portableGrid.getWatchers().forEach(w -> RS.INSTANCE.network.sendTo(new MessageGridItemDelta(null, stack, -size), (EntityPlayerMP) w)); - listeners.forEach(l -> l.accept(stack, -size)); + listeners.forEach(Runnable::run); } } @Override - public void addListener(BiConsumer listener) { + public void addListener(Runnable listener) { listeners.add(listener); } @Override - public void removeListener(BiConsumer listener) { + public void removeListener(Runnable listener) { listeners.remove(listener); } diff --git a/src/main/java/com/raoulvdberge/refinedstorage/inventory/ItemHandlerInterface.java b/src/main/java/com/raoulvdberge/refinedstorage/inventory/ItemHandlerInterface.java index a86e9f21d..d32209dba 100644 --- a/src/main/java/com/raoulvdberge/refinedstorage/inventory/ItemHandlerInterface.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/inventory/ItemHandlerInterface.java @@ -8,9 +8,8 @@ import net.minecraft.item.ItemStack; import net.minecraftforge.items.IItemHandler; import javax.annotation.Nonnull; -import java.util.function.BiConsumer; -public class ItemHandlerInterface implements IItemHandler, BiConsumer { +public class ItemHandlerInterface implements IItemHandler, Runnable { private INetwork network; private IStorageCache storageCache; private IItemHandler importItems; @@ -69,7 +68,7 @@ public class ItemHandlerInterface implements IItemHandler, BiConsumer { +public class ItemHandlerStorage implements IItemHandler, Runnable { private IStorage storage; private IStorageCache storageCache; private ItemStack[] storageCacheData; @@ -52,7 +51,7 @@ public class ItemHandlerStorage implements IItemHandler, BiConsumer { @Override public T getCapability(@Nonnull Capability capability, @Nullable EnumFacing facing) { if (capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) { - return CapabilityItemHandler.ITEM_HANDLER_CAPABILITY.cast(getNode().getItemsOrNetworkItems()); + return CapabilityItemHandler.ITEM_HANDLER_CAPABILITY.cast(getNode().getItemsOrStorage()); } return super.getCapability(capability, facing);