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
|
* @return stacks stored in this storage, empty stacks are allowed
|
||||||
*/
|
*/
|
||||||
Collection<T> getStacks();
|
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.IExternalStorageContext;
|
||||||
import com.raoulvdberge.refinedstorage.api.storage.externalstorage.IStorageExternal;
|
import com.raoulvdberge.refinedstorage.api.storage.externalstorage.IStorageExternal;
|
||||||
import com.raoulvdberge.refinedstorage.api.util.Action;
|
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 com.raoulvdberge.refinedstorage.util.StackUtils;
|
||||||
import net.minecraftforge.fluids.FluidStack;
|
import net.minecraftforge.fluids.FluidStack;
|
||||||
import net.minecraftforge.fluids.capability.IFluidHandler;
|
import net.minecraftforge.fluids.capability.IFluidHandler;
|
||||||
@@ -23,8 +21,8 @@ import java.util.function.Supplier;
|
|||||||
public class StorageExternalFluid implements IStorageExternal<FluidStack> {
|
public class StorageExternalFluid implements IStorageExternal<FluidStack> {
|
||||||
private IExternalStorageContext context;
|
private IExternalStorageContext context;
|
||||||
private Supplier<IFluidHandler> handlerSupplier;
|
private Supplier<IFluidHandler> handlerSupplier;
|
||||||
private List<FluidStack> cache;
|
|
||||||
private boolean connectedToInterface;
|
private boolean connectedToInterface;
|
||||||
|
private ExternalStorageCacheFluid cache = new ExternalStorageCacheFluid();
|
||||||
|
|
||||||
public StorageExternalFluid(IExternalStorageContext context, Supplier<IFluidHandler> handlerSupplier, boolean connectedToInterface) {
|
public StorageExternalFluid(IExternalStorageContext context, Supplier<IFluidHandler> handlerSupplier, boolean connectedToInterface) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
@@ -45,60 +43,11 @@ public class StorageExternalFluid implements IStorageExternal<FluidStack> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(INetwork network) {
|
public void update(INetwork network) {
|
||||||
// If we are insert only, we don't care about sending changes
|
|
||||||
if (getAccessType() == AccessType.INSERT) {
|
if (getAccessType() == AccessType.INSERT) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cache == null) {
|
cache.update(network, handlerSupplier.get());
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -129,29 +78,7 @@ public class StorageExternalFluid implements IStorageExternal<FluidStack> {
|
|||||||
FluidStack stack = properties.getContents();
|
FluidStack stack = properties.getContents();
|
||||||
|
|
||||||
if (stack != null) {
|
if (stack != null) {
|
||||||
fluids.add(stack.copy());
|
fluids.add(stack);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ import java.util.function.Supplier;
|
|||||||
public class StorageExternalItem implements IStorageExternal<ItemStack> {
|
public class StorageExternalItem implements IStorageExternal<ItemStack> {
|
||||||
private IExternalStorageContext context;
|
private IExternalStorageContext context;
|
||||||
private Supplier<IItemHandler> handlerSupplier;
|
private Supplier<IItemHandler> handlerSupplier;
|
||||||
private List<ItemStack> cache;
|
|
||||||
private boolean connectedToInterface;
|
private boolean connectedToInterface;
|
||||||
|
private ExternalStorageCacheItem cache = new ExternalStorageCacheItem();
|
||||||
|
|
||||||
public StorageExternalItem(IExternalStorageContext context, Supplier<IItemHandler> handlerSupplier, boolean connectedToInterface) {
|
public StorageExternalItem(IExternalStorageContext context, Supplier<IItemHandler> handlerSupplier, boolean connectedToInterface) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
@@ -37,69 +37,11 @@ public class StorageExternalItem implements IStorageExternal<ItemStack> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(INetwork network) {
|
public void update(INetwork network) {
|
||||||
// If we are insert only, we don't care about sending changes
|
|
||||||
if (getAccessType() == AccessType.INSERT) {
|
if (getAccessType() == AccessType.INSERT) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cache == null) {
|
cache.update(network, handlerSupplier.get());
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -130,7 +72,7 @@ public class StorageExternalItem implements IStorageExternal<ItemStack> {
|
|||||||
List<ItemStack> stacks = new ArrayList<>();
|
List<ItemStack> stacks = new ArrayList<>();
|
||||||
|
|
||||||
for (int i = 0; i < handler.getSlots(); ++i) {
|
for (int i = 0; i < handler.getSlots(); ++i) {
|
||||||
stacks.add(handler.getStackInSlot(i).copy());
|
stacks.add(handler.getStackInSlot(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
return stacks;
|
return stacks;
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ public class StackListFluid implements IStackList<FluidStack> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void add(@Nonnull FluidStack stack, int size) {
|
public void add(@Nonnull FluidStack stack, int size) {
|
||||||
if (stack == null || size < 0) {
|
if (size < 0) {
|
||||||
throw new IllegalArgumentException("Cannot accept empty stack");
|
throw new IllegalArgumentException("Cannot accept empty stack");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ public class StackListItem implements IStackList<ItemStack> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void add(@Nonnull ItemStack stack, int size) {
|
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");
|
throw new IllegalArgumentException("Cannot accept empty stack");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user