New storage cache. Avoid copying stacks all the time.
This commit is contained in:
@@ -16,6 +16,11 @@ public interface IStorage<T> {
|
||||
};
|
||||
|
||||
/**
|
||||
* 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<T> getStacks();
|
||||
|
@@ -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<FluidStack> 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();
|
||||
}
|
||||
}
|
@@ -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<ItemStack> 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();
|
||||
}
|
||||
}
|
@@ -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<FluidStack> {
|
||||
private IExternalStorageContext context;
|
||||
private Supplier<IFluidHandler> handlerSupplier;
|
||||
private List<FluidStack> cache;
|
||||
private boolean connectedToInterface;
|
||||
private ExternalStorageCacheFluid cache = new ExternalStorageCacheFluid();
|
||||
|
||||
public StorageExternalFluid(IExternalStorageContext context, Supplier<IFluidHandler> handlerSupplier, boolean connectedToInterface) {
|
||||
this.context = context;
|
||||
@@ -45,60 +43,11 @@ public class StorageExternalFluid implements IStorageExternal<FluidStack> {
|
||||
|
||||
@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<FluidStack> 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> {
|
||||
FluidStack stack = properties.getContents();
|
||||
|
||||
if (stack != null) {
|
||||
fluids.add(stack.copy());
|
||||
}
|
||||
}
|
||||
|
||||
return fluids;
|
||||
}
|
||||
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private Collection<FluidStack> getStacksWithNulls() {
|
||||
IFluidTankProperties[] props = getProperties();
|
||||
|
||||
if (props != null) {
|
||||
List<FluidStack> 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -22,8 +22,8 @@ import java.util.function.Supplier;
|
||||
public class StorageExternalItem implements IStorageExternal<ItemStack> {
|
||||
private IExternalStorageContext context;
|
||||
private Supplier<IItemHandler> handlerSupplier;
|
||||
private List<ItemStack> cache;
|
||||
private boolean connectedToInterface;
|
||||
private ExternalStorageCacheItem cache = new ExternalStorageCacheItem();
|
||||
|
||||
public StorageExternalItem(IExternalStorageContext context, Supplier<IItemHandler> handlerSupplier, boolean connectedToInterface) {
|
||||
this.context = context;
|
||||
@@ -37,69 +37,11 @@ public class StorageExternalItem implements IStorageExternal<ItemStack> {
|
||||
|
||||
@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<ItemStack> 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<ItemStack> {
|
||||
List<ItemStack> stacks = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < handler.getSlots(); ++i) {
|
||||
stacks.add(handler.getStackInSlot(i).copy());
|
||||
stacks.add(handler.getStackInSlot(i));
|
||||
}
|
||||
|
||||
return stacks;
|
||||
|
@@ -15,7 +15,7 @@ public class StackListFluid implements IStackList<FluidStack> {
|
||||
|
||||
@Override
|
||||
public void add(@Nonnull FluidStack stack, int size) {
|
||||
if (stack == null || size < 0) {
|
||||
if (size < 0) {
|
||||
throw new IllegalArgumentException("Cannot accept empty stack");
|
||||
}
|
||||
|
||||
|
@@ -16,7 +16,7 @@ public class StackListItem implements IStackList<ItemStack> {
|
||||
|
||||
@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");
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user