From ca1cf2a6ef8cc5f2e5db3f0036bc8cf88f1f8899 Mon Sep 17 00:00:00 2001 From: raoulvdberge Date: Wed, 21 Jun 2017 19:10:58 +0200 Subject: [PATCH] The Portable Grid now exposes an inventory for interaction with other mods or vanilla, fixes #1315 --- CHANGELOG.md | 1 + .../api/storage/IStorageCache.java | 8 +++ .../apiimpl/storage/StorageCacheFluid.java | 12 ++++ .../apiimpl/storage/StorageCacheItem.java | 12 ++++ .../storage/StorageCacheItemPortable.java | 12 ++++ .../inventory/ItemHandlerStorage.java | 62 +++++++++++++++++++ .../tile/grid/portable/TilePortableGrid.java | 15 ++++- 7 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/raoulvdberge/refinedstorage/inventory/ItemHandlerStorage.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e09f594c..ac4684c93 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ### 1.5.3 - Fixed Solderer crashing (raoulvdberge) +- The Portable Grid now exposes an inventory for interaction with other mods or vanilla (raoulvdberge) ### 1.5.2 - Fixed a bug where loading nodes would abort when a single node has an error while reading (raoulvdberge) 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 c76354d65..ddf87c690 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/api/storage/IStorageCache.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/api/storage/IStorageCache.java @@ -5,6 +5,7 @@ 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}. @@ -46,6 +47,13 @@ public interface IStorageCache { */ void remove(@Nonnull T stack, int size); + /** + * Adds a listener to be called when this storage cache changes. + * + * @param listener the listener + */ + void addListener(BiConsumer listener); + /** * Resorts the storages in this cache according to their priority. * This needs to be called when the priority of a storage changes. 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 4f7368386..d83fa85b0 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/storage/StorageCacheFluid.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/storage/StorageCacheFluid.java @@ -11,13 +11,16 @@ import com.raoulvdberge.refinedstorage.apiimpl.API; import net.minecraftforge.fluids.FluidStack; import javax.annotation.Nonnull; +import java.util.LinkedList; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; +import java.util.function.BiConsumer; public class StorageCacheFluid implements IStorageCache { private INetwork network; private CopyOnWriteArrayList> storages = new CopyOnWriteArrayList<>(); private IStackList list = API.instance().createFluidStackList(); + private List> listeners = new LinkedList<>(); public StorageCacheFluid(INetwork network) { this.network = network; @@ -54,6 +57,8 @@ public class StorageCacheFluid implements IStorageCache { if (!rebuilding) { network.sendFluidStorageDeltaToClient(stack, size); + + listeners.forEach(l -> l.accept(stack, size)); } } @@ -61,9 +66,16 @@ public class StorageCacheFluid implements IStorageCache { public synchronized void remove(@Nonnull FluidStack stack, int size) { if (list.remove(stack, size)) { network.sendFluidStorageDeltaToClient(stack, -size); + + listeners.forEach(l -> l.accept(stack, -size)); } } + @Override + public void addListener(BiConsumer listener) { + listeners.add(listener); + } + @Override public void sort() { storages.sort(RSUtils.STORAGE_COMPARATOR); 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 f8f418572..fe1e526b6 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/storage/StorageCacheItem.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/storage/StorageCacheItem.java @@ -11,13 +11,16 @@ import com.raoulvdberge.refinedstorage.apiimpl.API; import net.minecraft.item.ItemStack; import javax.annotation.Nonnull; +import java.util.LinkedList; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; +import java.util.function.BiConsumer; public class StorageCacheItem implements IStorageCache { private INetwork network; private CopyOnWriteArrayList> storages = new CopyOnWriteArrayList<>(); private IStackList list = API.instance().createItemStackList(); + private List> listeners = new LinkedList<>(); public StorageCacheItem(INetwork network) { this.network = network; @@ -56,6 +59,8 @@ public class StorageCacheItem implements IStorageCache { if (!rebuilding) { network.sendItemStorageDeltaToClient(stack, size); + + listeners.forEach(l -> l.accept(stack, size)); } } @@ -63,9 +68,16 @@ public class StorageCacheItem implements IStorageCache { public synchronized void remove(@Nonnull ItemStack stack, int size) { if (list.remove(stack, size)) { network.sendItemStorageDeltaToClient(stack, -size); + + listeners.forEach(l -> l.accept(stack, -size)); } } + @Override + public void addListener(BiConsumer listener) { + listeners.add(listener); + } + @Override public void sort() { storages.sort(RSUtils.STORAGE_COMPARATOR); 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 85de7c701..6af1b75b1 100644 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/storage/StorageCacheItemPortable.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/storage/StorageCacheItemPortable.java @@ -15,11 +15,14 @@ import net.minecraft.item.ItemStack; 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<>(); public StorageCacheItemPortable(IPortableGrid portableGrid) { this.portableGrid = portableGrid; @@ -42,6 +45,8 @@ 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)); } } @@ -49,9 +54,16 @@ public class StorageCacheItemPortable implements IStorageCache { public void remove(@Nonnull ItemStack stack, int size) { 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)); } } + @Override + public void addListener(BiConsumer listener) { + listeners.add(listener); + } + @Override public void sort() { // NO OP diff --git a/src/main/java/com/raoulvdberge/refinedstorage/inventory/ItemHandlerStorage.java b/src/main/java/com/raoulvdberge/refinedstorage/inventory/ItemHandlerStorage.java new file mode 100644 index 000000000..98ab34627 --- /dev/null +++ b/src/main/java/com/raoulvdberge/refinedstorage/inventory/ItemHandlerStorage.java @@ -0,0 +1,62 @@ +package com.raoulvdberge.refinedstorage.inventory; + +import com.raoulvdberge.refinedstorage.RSUtils; +import com.raoulvdberge.refinedstorage.api.storage.IStorage; +import com.raoulvdberge.refinedstorage.api.storage.IStorageCache; +import com.raoulvdberge.refinedstorage.api.util.IComparer; +import net.minecraft.item.ItemStack; +import net.minecraftforge.items.IItemHandler; + +import javax.annotation.Nonnull; +import java.util.function.BiConsumer; + +public class ItemHandlerStorage implements IItemHandler, BiConsumer { + private IStorage storage; + private IStorageCache storageCache; + private ItemStack[] storageCacheData; + + public ItemHandlerStorage(IStorage storage, IStorageCache storageCache) { + this.storage = storage; + this.storageCache = storageCache; + + invalidate(); + } + + @Override + public int getSlots() { + // Keep 1 slot extra for new items + return storageCacheData.length + 1; + } + + @Nonnull + @Override + public ItemStack getStackInSlot(int slot) { + return slot >= storageCacheData.length ? ItemStack.EMPTY : storageCacheData[slot]; + } + + @Nonnull + @Override + public ItemStack insertItem(int slot, @Nonnull ItemStack stack, boolean simulate) { + return RSUtils.transformNullToEmpty(storage.insert(stack, stack.getCount(), simulate)); + } + + @Nonnull + @Override + public ItemStack extractItem(int slot, int amount, boolean simulate) { + return slot >= storageCacheData.length ? ItemStack.EMPTY : RSUtils.transformNullToEmpty(storage.extract(storageCacheData[slot], amount, IComparer.COMPARE_DAMAGE | IComparer.COMPARE_NBT, simulate)); + } + + @Override + public int getSlotLimit(int slot) { + return 64; + } + + @Override + public void accept(ItemStack stack, Integer amount) { + invalidate(); + } + + private void invalidate() { + this.storageCacheData = storageCache.getList().getStacks().toArray(new ItemStack[0]); + } +} diff --git a/src/main/java/com/raoulvdberge/refinedstorage/tile/grid/portable/TilePortableGrid.java b/src/main/java/com/raoulvdberge/refinedstorage/tile/grid/portable/TilePortableGrid.java index 3303da974..c29fd58a4 100644 --- a/src/main/java/com/raoulvdberge/refinedstorage/tile/grid/portable/TilePortableGrid.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/tile/grid/portable/TilePortableGrid.java @@ -20,6 +20,7 @@ import com.raoulvdberge.refinedstorage.integration.forgeenergy.EnergyForge; import com.raoulvdberge.refinedstorage.inventory.ItemHandlerBase; import com.raoulvdberge.refinedstorage.inventory.ItemHandlerFilter; import com.raoulvdberge.refinedstorage.inventory.ItemHandlerListenerTile; +import com.raoulvdberge.refinedstorage.inventory.ItemHandlerStorage; import com.raoulvdberge.refinedstorage.item.ItemBlockPortableGrid; import com.raoulvdberge.refinedstorage.item.ItemEnergyItem; import com.raoulvdberge.refinedstorage.item.ItemWirelessGrid; @@ -45,6 +46,7 @@ import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.energy.CapabilityEnergy; import net.minecraftforge.fml.common.FMLCommonHandler; import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.items.CapabilityItemHandler; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -185,6 +187,14 @@ public class TilePortableGrid extends TileBase implements IGrid, IPortableGrid, cache.invalidate(); + if (storage == null) { + itemHandler = null; + } else { + itemHandler = new ItemHandlerStorage(storage, cache); + + cache.addListener(itemHandler); + } + if (world != null) { checkIfDiskStateChanged(); } @@ -206,6 +216,7 @@ public class TilePortableGrid extends TileBase implements IGrid, IPortableGrid, private IStorageDisk storage; private StorageCacheItemPortable cache = new StorageCacheItemPortable(this); private ItemGridHandlerPortable handler = new ItemGridHandlerPortable(this, this); + private ItemHandlerStorage itemHandler = null; private PortableGridDiskState diskState = PortableGridDiskState.NONE; private boolean connected; @@ -602,7 +613,7 @@ public class TilePortableGrid extends TileBase implements IGrid, IPortableGrid, @Override public boolean hasCapability(@Nonnull Capability capability, @Nullable EnumFacing facing) { - return capability == CapabilityEnergy.ENERGY || super.hasCapability(capability, facing); + return capability == CapabilityEnergy.ENERGY || (itemHandler != null && capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) || super.hasCapability(capability, facing); } @Nullable @@ -610,6 +621,8 @@ public class TilePortableGrid extends TileBase implements IGrid, IPortableGrid, public T getCapability(@Nonnull Capability capability, @Nullable EnumFacing facing) { if (capability == CapabilityEnergy.ENERGY) { return CapabilityEnergy.ENERGY.cast(energyStorage); + } else if (itemHandler != null && capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) { + return CapabilityItemHandler.ITEM_HANDLER_CAPABILITY.cast(itemHandler); } return super.getCapability(capability, facing);