diff --git a/src/main/java/com/raoulvdberge/refinedstorage/api/storage/IStorage.java b/src/main/java/com/raoulvdberge/refinedstorage/api/storage/IStorage.java index 235915cc5..813da3bad 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/api/storage/IStorage.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/api/storage/IStorage.java @@ -16,6 +16,11 @@ public interface IStorage { }; /** + * Returns the stacks of the storage. + * Empty stacks are allowed. + * Please do not copy the stacks for performance reasons. + * For the caller: modifying stacks is not allowed! + * * @return stacks stored in this storage, empty stacks are allowed */ Collection getStacks(); diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/storage/externalstorage/ExternalStorageCacheFluid.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/storage/externalstorage/ExternalStorageCacheFluid.java new file mode 100644 index 000000000..1cf623e10 --- /dev/null +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/storage/externalstorage/ExternalStorageCacheFluid.java @@ -0,0 +1,89 @@ +package com.raoulvdberge.refinedstorage.apiimpl.storage.externalstorage; + +import com.raoulvdberge.refinedstorage.api.network.INetwork; +import com.raoulvdberge.refinedstorage.api.util.IComparer; +import com.raoulvdberge.refinedstorage.apiimpl.API; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.capability.IFluidHandler; +import net.minecraftforge.fluids.capability.IFluidTankProperties; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.List; + +public class ExternalStorageCacheFluid { + private List cache; + + public void update(INetwork network, @Nullable IFluidHandler handler) { + if (handler == null) { + return; + } + + if (cache == null) { + cache = new ArrayList<>(); + + for (IFluidTankProperties properties : handler.getTankProperties()) { + cache.add(properties.getContents() == null ? null : properties.getContents().copy()); + } + + return; + } + + for (int i = 0; i < handler.getTankProperties().length; ++i) { + FluidStack actual = handler.getTankProperties()[i].getContents(); + + if (i >= cache.size()) { // ENLARGED + if (actual != null) { + network.getFluidStorageCache().add(actual, actual.amount, false, true); + + cache.add(actual.copy()); + } + + continue; + } + + FluidStack cached = cache.get(i); + + if (actual == null && cached == null) { // NONE + continue; + } + + if (actual == null && cached != null) { // REMOVED + network.getFluidStorageCache().remove(cached, cached.amount, true); + + cache.set(i, null); + } else if (actual != null && cached == null) { // ADDED + network.getFluidStorageCache().add(actual, actual.amount, false, true); + + cache.set(i, actual.copy()); + } else if (!API.instance().getComparer().isEqual(actual, cached, IComparer.COMPARE_NBT)) { // CHANGED + network.getFluidStorageCache().remove(cached, cached.amount, true); + network.getFluidStorageCache().add(actual, actual.amount, false, true); + + cache.set(i, actual.copy()); + } else if (actual.amount > cached.amount) { // COUNT_CHANGED + network.getFluidStorageCache().add(actual, actual.amount - cached.amount, false, true); + + cached.amount = actual.amount; + } else if (actual.amount < cached.amount) { // COUNT_CHANGED + network.getFluidStorageCache().remove(actual, cached.amount - actual.amount, true); + + cached.amount = actual.amount; + } + } + + if (cache.size() > handler.getTankProperties().length) { // SHRUNK + for (int i = cache.size() - 1; i >= handler.getTankProperties().length; --i) { // Reverse order for the remove call. + FluidStack cached = cache.get(i); + + if (cached != null) { + network.getFluidStorageCache().remove(cached, cached.amount, true); + } + + cache.remove(i); + } + } + + network.getFluidStorageCache().flush(); + } +} diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/storage/externalstorage/ExternalStorageCacheItem.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/storage/externalstorage/ExternalStorageCacheItem.java new file mode 100644 index 000000000..e3048a3cb --- /dev/null +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/storage/externalstorage/ExternalStorageCacheItem.java @@ -0,0 +1,87 @@ +package com.raoulvdberge.refinedstorage.apiimpl.storage.externalstorage; + +import com.raoulvdberge.refinedstorage.api.network.INetwork; +import com.raoulvdberge.refinedstorage.apiimpl.API; +import net.minecraft.item.ItemStack; +import net.minecraftforge.items.IItemHandler; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.List; + +public class ExternalStorageCacheItem { + private List cache; + + public void update(INetwork network, @Nullable IItemHandler handler) { + if (handler == null) { + return; + } + + if (cache == null) { + cache = new ArrayList<>(); + + for (int i = 0; i < handler.getSlots(); ++i) { + cache.add(handler.getStackInSlot(i).copy()); + } + + return; + } + + for (int i = 0; i < handler.getSlots(); ++i) { + ItemStack actual = handler.getStackInSlot(i); + + if (i >= cache.size()) { // ENLARGED + if (!actual.isEmpty()) { + network.getItemStorageCache().add(actual, actual.getCount(), false, true); + + cache.add(actual.copy()); + } + + continue; + } + + ItemStack cached = cache.get(i); + + if (!cached.isEmpty() && actual.isEmpty()) { // REMOVED + network.getItemStorageCache().remove(cached, cached.getCount(), true); + + cache.set(i, ItemStack.EMPTY); + } else if (cached.isEmpty() && !actual.isEmpty()) { // ADDED + network.getItemStorageCache().add(actual, actual.getCount(), false, true); + + cache.set(i, actual.copy()); + } else if (!API.instance().getComparer().isEqualNoQuantity(cached, actual)) { // CHANGED + network.getItemStorageCache().remove(cached, cached.getCount(), true); + network.getItemStorageCache().add(actual, actual.getCount(), false, true); + + cache.set(i, actual.copy()); + } else if (cached.getCount() != actual.getCount()) { // COUNT_CHANGED + int delta = actual.getCount() - cached.getCount(); + + if (delta > 0) { + network.getItemStorageCache().add(actual, delta, false, true); + + cached.grow(delta); + } else { + network.getItemStorageCache().remove(actual, Math.abs(delta), true); + + cached.shrink(Math.abs(delta)); + } + } + } + + if (cache.size() > handler.getSlots()) { // SHRUNK + for (int i = cache.size() - 1; i >= handler.getSlots(); --i) { // Reverse order for the remove call. + ItemStack cached = cache.get(i); + + if (!cached.isEmpty()) { + network.getItemStorageCache().remove(cached, cached.getCount(), true); + } + + cache.remove(i); + } + } + + network.getItemStorageCache().flush(); + } +} diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/storage/externalstorage/StorageExternalFluid.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/storage/externalstorage/StorageExternalFluid.java index 6eb4dda32..757e661ae 100644 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/storage/externalstorage/StorageExternalFluid.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/storage/externalstorage/StorageExternalFluid.java @@ -5,8 +5,6 @@ import com.raoulvdberge.refinedstorage.api.storage.AccessType; import com.raoulvdberge.refinedstorage.api.storage.externalstorage.IExternalStorageContext; import com.raoulvdberge.refinedstorage.api.storage.externalstorage.IStorageExternal; import com.raoulvdberge.refinedstorage.api.util.Action; -import com.raoulvdberge.refinedstorage.api.util.IComparer; -import com.raoulvdberge.refinedstorage.apiimpl.API; import com.raoulvdberge.refinedstorage.util.StackUtils; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.capability.IFluidHandler; @@ -23,8 +21,8 @@ import java.util.function.Supplier; public class StorageExternalFluid implements IStorageExternal { private IExternalStorageContext context; private Supplier handlerSupplier; - private List cache; private boolean connectedToInterface; + private ExternalStorageCacheFluid cache = new ExternalStorageCacheFluid(); public StorageExternalFluid(IExternalStorageContext context, Supplier handlerSupplier, boolean connectedToInterface) { this.context = context; @@ -45,60 +43,11 @@ public class StorageExternalFluid implements IStorageExternal { @Override public void update(INetwork network) { - // If we are insert only, we don't care about sending changes if (getAccessType() == AccessType.INSERT) { return; } - if (cache == null) { - cache = new ArrayList<>(getStacksWithNulls()); - - return; - } - - List newStacks = new ArrayList<>(getStacksWithNulls()); - - for (int i = 0; i < newStacks.size(); ++i) { - FluidStack actual = newStacks.get(i); - - // If we exceed the cache size, than that means this item is added - if (i >= cache.size()) { - if (actual != null) { - network.getFluidStorageCache().add(actual, actual.amount, false, true); - } - - continue; - } - - FluidStack cached = cache.get(i); - - if (actual == null && cached == null) { - // NO OP - } else if (actual == null && cached != null) { - network.getFluidStorageCache().remove(cached, cached.amount, true); - } else if (actual != null && cached == null) { - network.getFluidStorageCache().add(actual, actual.amount, false, true); - } else if (!API.instance().getComparer().isEqual(actual, cached, IComparer.COMPARE_NBT)) { - network.getFluidStorageCache().remove(cached, cached.amount, true); - network.getFluidStorageCache().add(actual, actual.amount, false, true); - } else if (actual.amount > cached.amount) { - network.getFluidStorageCache().add(actual, actual.amount - cached.amount, false, true); - } else if (actual.amount < cached.amount) { - network.getFluidStorageCache().remove(actual, cached.amount - actual.amount, true); - } - } - - if (cache.size() > newStacks.size()) { - for (int i = newStacks.size(); i < cache.size(); ++i) { - if (cache.get(i) != null) { - network.getFluidStorageCache().remove(cache.get(i), cache.get(i).amount, true); - } - } - } - - this.cache = newStacks; - - network.getFluidStorageCache().flush(); + cache.update(network, handlerSupplier.get()); } @Override @@ -129,29 +78,7 @@ public class StorageExternalFluid implements IStorageExternal { FluidStack stack = properties.getContents(); if (stack != null) { - fluids.add(stack.copy()); - } - } - - return fluids; - } - - return Collections.emptyList(); - } - - private Collection getStacksWithNulls() { - IFluidTankProperties[] props = getProperties(); - - if (props != null) { - List fluids = new ArrayList<>(); - - for (IFluidTankProperties properties : props) { - FluidStack stack = properties.getContents(); - - if (stack != null) { - fluids.add(stack.copy()); - } else { - fluids.add(null); + fluids.add(stack); } } diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/storage/externalstorage/StorageExternalItem.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/storage/externalstorage/StorageExternalItem.java index 88d830a6a..f1f5d2449 100644 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/storage/externalstorage/StorageExternalItem.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/storage/externalstorage/StorageExternalItem.java @@ -22,8 +22,8 @@ import java.util.function.Supplier; public class StorageExternalItem implements IStorageExternal { private IExternalStorageContext context; private Supplier handlerSupplier; - private List cache; private boolean connectedToInterface; + private ExternalStorageCacheItem cache = new ExternalStorageCacheItem(); public StorageExternalItem(IExternalStorageContext context, Supplier handlerSupplier, boolean connectedToInterface) { this.context = context; @@ -37,69 +37,11 @@ public class StorageExternalItem implements IStorageExternal { @Override public void update(INetwork network) { - // If we are insert only, we don't care about sending changes if (getAccessType() == AccessType.INSERT) { return; } - if (cache == null) { - cache = new ArrayList<>(getStacks()); - - return; - } - - List newStacks = new ArrayList<>(getStacks()); - - for (int i = 0; i < newStacks.size(); ++i) { - ItemStack actual = newStacks.get(i); - - // If we exceed the cache size, than that means this item is added - if (i >= cache.size()) { - if (!actual.isEmpty()) { - network.getItemStorageCache().add(actual, actual.getCount(), false, true); - } - - continue; - } - - ItemStack cached = cache.get(i); - - if (!cached.isEmpty() && actual.isEmpty()) { - // If the cached is not empty but the actual is, we remove this item - network.getItemStorageCache().remove(cached, cached.getCount(), true); - } else if (cached.isEmpty() && !actual.isEmpty()) { - // If the cached is empty and the actual isn't, we added this item - network.getItemStorageCache().add(actual, actual.getCount(), false, true); - } else if (cached.isEmpty() && actual.isEmpty()) { - // If they're both empty, nothing happens - } else if (!API.instance().getComparer().isEqualNoQuantity(cached, actual)) { - // If both items mismatch, remove the old and add the new - network.getItemStorageCache().remove(cached, cached.getCount(), true); - network.getItemStorageCache().add(actual, actual.getCount(), false, true); - } else if (cached.getCount() != actual.getCount()) { - int delta = actual.getCount() - cached.getCount(); - - if (delta > 0) { - network.getItemStorageCache().add(actual, delta, false, true); - } else { - network.getItemStorageCache().remove(actual, Math.abs(delta), true); - } - } - } - - // If the cache size is somehow bigger than the actual stacks, that means the inventory shrunk - // In that case, we remove the items that have been removed due to the shrinkage - if (cache.size() > newStacks.size()) { - for (int i = newStacks.size(); i < cache.size(); ++i) { - if (cache.get(i) != ItemStack.EMPTY) { - network.getItemStorageCache().remove(cache.get(i), cache.get(i).getCount(), true); - } - } - } - - this.cache = newStacks; - - network.getItemStorageCache().flush(); + cache.update(network, handlerSupplier.get()); } @Override @@ -130,7 +72,7 @@ public class StorageExternalItem implements IStorageExternal { List stacks = new ArrayList<>(); for (int i = 0; i < handler.getSlots(); ++i) { - stacks.add(handler.getStackInSlot(i).copy()); + stacks.add(handler.getStackInSlot(i)); } return stacks; diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/util/StackListFluid.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/util/StackListFluid.java index c0e51af0f..5af709219 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/util/StackListFluid.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/util/StackListFluid.java @@ -15,7 +15,7 @@ public class StackListFluid implements IStackList { @Override public void add(@Nonnull FluidStack stack, int size) { - if (stack == null || size < 0) { + if (size < 0) { throw new IllegalArgumentException("Cannot accept empty stack"); } diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/util/StackListItem.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/util/StackListItem.java index f4953c60b..b3cc119d4 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/util/StackListItem.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/util/StackListItem.java @@ -16,7 +16,7 @@ public class StackListItem implements IStackList { @Override public void add(@Nonnull ItemStack stack, int size) { - if (stack == null || stack.isEmpty() || size <= 0) { + if (stack.isEmpty() || size <= 0) { throw new IllegalArgumentException("Cannot accept empty stack"); }