improved network caching

This commit is contained in:
Ellpeck 2020-05-09 12:57:25 +02:00
parent c21a5ddbb0
commit 172dcc7429
10 changed files with 152 additions and 76 deletions

View file

@ -1,6 +1,7 @@
package de.ellpeck.prettypipes; package de.ellpeck.prettypipes;
import de.ellpeck.prettypipes.items.IModule; import de.ellpeck.prettypipes.items.IModule;
import de.ellpeck.prettypipes.network.PipeItem;
import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.resources.I18n; import net.minecraft.client.resources.I18n;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
@ -8,14 +9,19 @@ import net.minecraft.inventory.InventoryHelper;
import net.minecraft.inventory.container.Container; import net.minecraft.inventory.container.Container;
import net.minecraft.inventory.container.Slot; import net.minecraft.inventory.container.Slot;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.ListNBT;
import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.*; import net.minecraft.util.text.*;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraftforge.common.util.INBTSerializable;
import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.IItemHandler;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.IntStream; import java.util.stream.IntStream;
@ -94,6 +100,20 @@ public final class Utility {
return ItemStack.EMPTY; return ItemStack.EMPTY;
} }
public static ListNBT serializeAll(Collection<? extends INBTSerializable<CompoundNBT>> items) {
ListNBT list = new ListNBT();
for (INBTSerializable<CompoundNBT> item : items)
list.add(item.serializeNBT());
return list;
}
public static <T extends INBTSerializable<CompoundNBT>> List<T> deserializeAll(ListNBT list, Function<CompoundNBT, T> supplier) {
List<T> items = new ArrayList<>();
for (int i = 0; i < list.size(); i++)
items.add(supplier.apply(list.getCompound(i)));
return items;
}
public interface IMergeItemStack { public interface IMergeItemStack {
boolean mergeItemStack(ItemStack stack, int startIndex, int endIndex, boolean reverseDirection); boolean mergeItemStack(ItemStack stack, int startIndex, int endIndex, boolean reverseDirection);
} }

View file

@ -68,7 +68,7 @@ public class PipeFrameEntity extends ItemFrameEntity implements IEntityAdditiona
ItemStack stack = this.getDisplayedItem(); ItemStack stack = this.getDisplayedItem();
if (!stack.isEmpty()) { if (!stack.isEmpty()) {
List<NetworkLocation> items = network.getOrderedNetworkItems(node); List<NetworkLocation> items = network.getOrderedNetworkItems(node);
int amount = items.stream().mapToInt(i -> i.getItemAmount(stack)).sum(); int amount = items.stream().mapToInt(i -> i.getItemAmount(this.world, stack)).sum();
this.dataManager.set(AMOUNT, amount); this.dataManager.set(AMOUNT, amount);
return; return;
} }

View file

@ -30,9 +30,4 @@ public class NetworkItem {
stack.setCount(this.amount); stack.setCount(this.amount);
return stack; return stack;
} }
@Override
public String toString() {
return "NetworkItem{" + "locations=" + this.locations + ", item=" + this.item + ", amount=" + this.amount + '}';
}
} }

View file

@ -3,61 +3,99 @@ package de.ellpeck.prettypipes.network;
import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap; import com.google.common.collect.ListMultimap;
import de.ellpeck.prettypipes.misc.ItemEqualityType; import de.ellpeck.prettypipes.misc.ItemEqualityType;
import de.ellpeck.prettypipes.pipe.PipeTileEntity;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.NBTUtil;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.common.util.INBTSerializable;
import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.IItemHandler;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class NetworkLocation { public class NetworkLocation implements INBTSerializable<CompoundNBT> {
public final BlockPos pipePos; public BlockPos pipePos;
public final Direction direction; public Direction direction;
public final BlockPos pos; private Map<Integer, ItemStack> itemCache;
public final IItemHandler handler; private IItemHandler handlerCache;
private Map<Integer, ItemStack> items;
public NetworkLocation(BlockPos pipePos, Direction direction, IItemHandler handler) { public NetworkLocation(BlockPos pipePos, Direction direction) {
this.pipePos = pipePos; this.pipePos = pipePos;
this.direction = direction; this.direction = direction;
this.pos = pipePos.offset(direction);
this.handler = handler;
} }
public void addItem(int slot, ItemStack stack) { public NetworkLocation(CompoundNBT nbt) {
if (this.items == null) this.deserializeNBT(nbt);
this.items = new HashMap<>();
this.items.put(slot, stack);
} }
public List<Integer> getStackSlots(ItemStack stack, ItemEqualityType... equalityTypes) { public List<Integer> getStackSlots(World world, ItemStack stack, ItemEqualityType... equalityTypes) {
if (this.isEmpty()) if (this.isEmpty(world))
return Collections.emptyList(); return Collections.emptyList();
return this.items.entrySet().stream() return this.getItems(world).entrySet().stream()
.filter(e -> ItemEqualityType.compareItems(e.getValue(), stack, equalityTypes)) .filter(e -> ItemEqualityType.compareItems(e.getValue(), stack, equalityTypes))
.map(Map.Entry::getKey) .map(Map.Entry::getKey)
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
public int getItemAmount(ItemStack stack, ItemEqualityType... equalityTypes) { public int getItemAmount(World world, ItemStack stack, ItemEqualityType... equalityTypes) {
return this.items.values().stream() if (this.isEmpty(world))
return 0;
return this.getItems(world).values().stream()
.filter(i -> ItemEqualityType.compareItems(stack, i, equalityTypes)) .filter(i -> ItemEqualityType.compareItems(stack, i, equalityTypes))
.mapToInt(ItemStack::getCount).sum(); .mapToInt(ItemStack::getCount).sum();
} }
public Collection<ItemStack> getItems() { public Map<Integer, ItemStack> getItems(World world) {
return this.items.values(); if (this.itemCache == null) {
IItemHandler handler = this.getItemHandler(world);
if (handler != null) {
for (int i = 0; i < handler.getSlots(); i++) {
ItemStack found = handler.extractItem(i, Integer.MAX_VALUE, true);
if (found.isEmpty())
continue;
if (this.itemCache == null)
this.itemCache = new HashMap<>();
this.itemCache.put(i, found);
}
}
}
return this.itemCache;
} }
public boolean isEmpty() { public IItemHandler getItemHandler(World world) {
return this.items == null || this.items.isEmpty(); if (this.handlerCache == null) {
PipeNetwork network = PipeNetwork.get(world);
PipeTileEntity pipe = network.getPipe(this.pipePos);
this.handlerCache = pipe.getItemHandler(this.direction, null);
}
return this.handlerCache;
}
public boolean isEmpty(World world) {
Map<Integer, ItemStack> items = this.getItems(world);
return items == null || items.isEmpty();
}
public BlockPos getPos() {
return this.pipePos.offset(this.direction);
} }
@Override @Override
public String toString() { public CompoundNBT serializeNBT() {
return this.items.values().toString(); CompoundNBT nbt = new CompoundNBT();
nbt.put("pipe_pos", NBTUtil.writeBlockPos(this.pipePos));
nbt.putInt("direction", this.direction.getIndex());
return nbt;
}
@Override
public void deserializeNBT(CompoundNBT nbt) {
this.pipePos = NBTUtil.readBlockPos(nbt.getCompound("pipe_pos"));
this.direction = Direction.byIndex(nbt.getInt("direction"));
} }
} }

View file

@ -1,14 +1,40 @@
package de.ellpeck.prettypipes.network; package de.ellpeck.prettypipes.network;
public class NetworkLock { import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.ListNBT;
import net.minecraftforge.common.util.INBTSerializable;
public final NetworkLocation location; import java.util.Collection;
public final int slot;
public final int amount; public class NetworkLock implements INBTSerializable<CompoundNBT> {
public NetworkLocation location;
public int slot;
public int amount;
public NetworkLock(NetworkLocation location, int slot, int amount) { public NetworkLock(NetworkLocation location, int slot, int amount) {
this.location = location; this.location = location;
this.slot = slot; this.slot = slot;
this.amount = amount; this.amount = amount;
} }
public NetworkLock(CompoundNBT nbt) {
this.deserializeNBT(nbt);
}
@Override
public CompoundNBT serializeNBT() {
CompoundNBT nbt = new CompoundNBT();
nbt.put("location", this.location.serializeNBT());
nbt.putInt("slot", this.slot);
nbt.putInt("amount", this.amount);
return nbt;
}
@Override
public void deserializeNBT(CompoundNBT nbt) {
this.location = new NetworkLocation(nbt.getCompound("location"));
this.slot = nbt.getInt("slot");
this.amount = nbt.getInt("amount");
}
} }

View file

@ -268,20 +268,6 @@ public class PipeItem implements INBTSerializable<CompoundNBT>, ILiquidContainer
return ret; return ret;
} }
public static ListNBT serializeAll(Collection<PipeItem> items) {
ListNBT list = new ListNBT();
for (PipeItem item : items)
list.add(item.serializeNBT());
return list;
}
public static List<PipeItem> deserializeAll(ListNBT list) {
List<PipeItem> items = new ArrayList<>();
for (int i = 0; i < list.size(); i++)
items.add(new PipeItem(list.getCompound(i)));
return items;
}
@Override @Override
public boolean canContainFluid(IBlockReader worldIn, BlockPos pos, BlockState state, Fluid fluidIn) { public boolean canContainFluid(IBlockReader worldIn, BlockPos pos, BlockState state, Fluid fluidIn) {
return true; return true;

View file

@ -17,11 +17,13 @@ import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.ListNBT; import net.minecraft.nbt.ListNBT;
import net.minecraft.nbt.NBTUtil; import net.minecraft.nbt.NBTUtil;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraft.util.Util;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.ICapabilitySerializable; import net.minecraftforge.common.capabilities.ICapabilitySerializable;
import net.minecraftforge.common.util.Constants; import net.minecraftforge.common.util.Constants;
import net.minecraftforge.common.util.Constants.NBT;
import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.IItemHandler;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
@ -77,7 +79,8 @@ public class PipeNetwork implements ICapabilitySerializable<CompoundNBT>, GraphL
for (NetworkEdge edge : this.graph.edgeSet()) for (NetworkEdge edge : this.graph.edgeSet())
edges.add(edge.serializeNBT()); edges.add(edge.serializeNBT());
nbt.put("edges", edges); nbt.put("edges", edges);
nbt.put("items", PipeItem.serializeAll(this.pipeItems.values())); nbt.put("items", Utility.serializeAll(this.pipeItems.values()));
nbt.put("locks", Utility.serializeAll(this.networkLocks.values()));
return nbt; return nbt;
} }
@ -85,15 +88,18 @@ public class PipeNetwork implements ICapabilitySerializable<CompoundNBT>, GraphL
public void deserializeNBT(CompoundNBT nbt) { public void deserializeNBT(CompoundNBT nbt) {
this.graph.removeAllVertices(new ArrayList<>(this.graph.vertexSet())); this.graph.removeAllVertices(new ArrayList<>(this.graph.vertexSet()));
this.pipeItems.clear(); this.pipeItems.clear();
this.networkLocks.clear();
ListNBT nodes = nbt.getList("nodes", Constants.NBT.TAG_COMPOUND); ListNBT nodes = nbt.getList("nodes", NBT.TAG_COMPOUND);
for (int i = 0; i < nodes.size(); i++) for (int i = 0; i < nodes.size(); i++)
this.graph.addVertex(NBTUtil.readBlockPos(nodes.getCompound(i))); this.graph.addVertex(NBTUtil.readBlockPos(nodes.getCompound(i)));
ListNBT edges = nbt.getList("edges", Constants.NBT.TAG_COMPOUND); ListNBT edges = nbt.getList("edges", NBT.TAG_COMPOUND);
for (int i = 0; i < edges.size(); i++) for (int i = 0; i < edges.size(); i++)
this.addEdge(new NetworkEdge(edges.getCompound(i))); this.addEdge(new NetworkEdge(edges.getCompound(i)));
for (PipeItem item : PipeItem.deserializeAll(nbt.getList("items", Constants.NBT.TAG_COMPOUND))) for (PipeItem item : Utility.deserializeAll(nbt.getList("items", NBT.TAG_COMPOUND), PipeItem::new))
this.pipeItems.put(item.getCurrentPipe(), item); this.pipeItems.put(item.getCurrentPipe(), item);
for (NetworkLock lock : Utility.deserializeAll(nbt.getList("locks", NBT.TAG_COMPOUND), NetworkLock::new))
this.createNetworkLock(lock);
} }
public void addNode(BlockPos pos, BlockState state) { public void addNode(BlockPos pos, BlockState state) {
@ -194,16 +200,10 @@ public class PipeNetwork implements ICapabilitySerializable<CompoundNBT>, GraphL
if (handler == null) if (handler == null)
continue; continue;
// check if this handler already exists (double-connected pipes, double chests etc.) // check if this handler already exists (double-connected pipes, double chests etc.)
if (info.stream().anyMatch(l -> l.handler == handler)) if (info.stream().anyMatch(l -> l.getItemHandler(this.world) == handler))
continue; continue;
NetworkLocation location = new NetworkLocation(dest, dir, handler); NetworkLocation location = new NetworkLocation(dest, dir);
for (int i = 0; i < handler.getSlots(); i++) { if (!location.isEmpty(this.world))
ItemStack found = handler.extractItem(i, Integer.MAX_VALUE, true);
if (found.isEmpty())
continue;
location.addItem(i, found);
}
if (!location.isEmpty())
info.add(location); info.add(location);
} }
} }
@ -212,11 +212,11 @@ public class PipeNetwork implements ICapabilitySerializable<CompoundNBT>, GraphL
} }
public void createNetworkLock(NetworkLock lock) { public void createNetworkLock(NetworkLock lock) {
this.networkLocks.put(lock.location.pos, lock); this.networkLocks.put(lock.location.getPos(), lock);
} }
public void resolveNetworkLock(NetworkLock lock) { public void resolveNetworkLock(NetworkLock lock) {
this.networkLocks.remove(lock.location.pos, lock); this.networkLocks.remove(lock.location.getPos(), lock);
} }
public List<NetworkLock> getNetworkLocks(BlockPos pos) { public List<NetworkLock> getNetworkLocks(BlockPos pos) {

View file

@ -2,6 +2,7 @@ package de.ellpeck.prettypipes.pipe;
import de.ellpeck.prettypipes.PrettyPipes; import de.ellpeck.prettypipes.PrettyPipes;
import de.ellpeck.prettypipes.Registry; import de.ellpeck.prettypipes.Registry;
import de.ellpeck.prettypipes.Utility;
import de.ellpeck.prettypipes.items.IModule; import de.ellpeck.prettypipes.items.IModule;
import de.ellpeck.prettypipes.network.PipeItem; import de.ellpeck.prettypipes.network.PipeItem;
import de.ellpeck.prettypipes.network.PipeNetwork; import de.ellpeck.prettypipes.network.PipeNetwork;
@ -24,6 +25,7 @@ import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TranslationTextComponent; import net.minecraft.util.text.TranslationTextComponent;
import net.minecraftforge.common.util.Constants; import net.minecraftforge.common.util.Constants;
import net.minecraftforge.common.util.Constants.NBT;
import net.minecraftforge.items.CapabilityItemHandler; import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.ItemHandlerHelper; import net.minecraftforge.items.ItemHandlerHelper;
@ -77,7 +79,7 @@ public class PipeTileEntity extends TileEntity implements INamedContainerProvide
public CompoundNBT getUpdateTag() { public CompoundNBT getUpdateTag() {
// sync pipe items on load // sync pipe items on load
CompoundNBT nbt = this.write(new CompoundNBT()); CompoundNBT nbt = this.write(new CompoundNBT());
nbt.put("items", PipeItem.serializeAll(this.getItems())); nbt.put("items", Utility.serializeAll(this.getItems()));
return nbt; return nbt;
} }
@ -86,7 +88,7 @@ public class PipeTileEntity extends TileEntity implements INamedContainerProvide
this.read(nbt); this.read(nbt);
List<PipeItem> items = this.getItems(); List<PipeItem> items = this.getItems();
items.clear(); items.clear();
items.addAll(PipeItem.deserializeAll(nbt.getList("items", Constants.NBT.TAG_COMPOUND))); items.addAll(Utility.deserializeAll(nbt.getList("items", NBT.TAG_COMPOUND), PipeItem::new));
} }
@Override @Override

View file

@ -14,6 +14,7 @@ import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory; import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraftforge.items.IItemHandler;
import java.util.List; import java.util.List;
@ -58,11 +59,12 @@ public class RetrievalModuleItem extends ModuleItem {
for (NetworkLocation location : locations) { for (NetworkLocation location : locations) {
if (location.pipePos.equals(tile.getPos())) if (location.pipePos.equals(tile.getPos()))
continue; continue;
for (int slot : location.getStackSlots(filtered, filter.getEqualityTypes())) { for (int slot : location.getStackSlots(tile.getWorld(), filtered, filter.getEqualityTypes())) {
// try to extract from that location's inventory and send the item // try to extract from that location's inventory and send the item
ItemStack stack = location.handler.extractItem(slot, this.maxExtraction, true); IItemHandler handler = location.getItemHandler(tile.getWorld());
if (network.routeItemToLocation(location.pipePos, location.pos, tile.getPos(), dest, speed -> new PipeItem(stack, speed))) { ItemStack stack = handler.extractItem(slot, this.maxExtraction, true);
location.handler.extractItem(slot, stack.getCount(), false); if (network.routeItemToLocation(location.pipePos, location.getPos(), tile.getPos(), dest, speed -> new PipeItem(stack, speed))) {
handler.extractItem(slot, stack.getCount(), false);
return; return;
} }
} }

View file

@ -28,6 +28,9 @@ import net.minecraft.util.text.Style;
import net.minecraft.util.text.TextFormatting; import net.minecraft.util.text.TextFormatting;
import net.minecraft.util.text.TranslationTextComponent; import net.minecraft.util.text.TranslationTextComponent;
import net.minecraft.world.server.ServerWorld; import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.common.util.Constants;
import net.minecraftforge.common.util.Constants.NBT;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.ItemStackHandler; import net.minecraftforge.items.ItemStackHandler;
import org.apache.commons.lang3.mutable.MutableInt; import org.apache.commons.lang3.mutable.MutableInt;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
@ -81,9 +84,10 @@ public class ItemTerminalTileEntity extends TileEntity implements INamedContaine
if (!this.pendingRequests.isEmpty()) { if (!this.pendingRequests.isEmpty()) {
NetworkLock request = this.pendingRequests.remove(); NetworkLock request = this.pendingRequests.remove();
network.resolveNetworkLock(request); network.resolveNetworkLock(request);
ItemStack extracted = request.location.handler.extractItem(request.slot, request.amount, true); IItemHandler handler = request.location.getItemHandler(this.world);
if (network.routeItemToLocation(request.location.pipePos, request.location.pos, pipe.getPos(), this.pos, speed -> new PipeItem(extracted, speed))) { ItemStack extracted = handler.extractItem(request.slot, request.amount, true);
request.location.handler.extractItem(request.slot, extracted.getCount(), false); if (network.routeItemToLocation(request.location.pipePos, request.location.getPos(), pipe.getPos(), this.pos, speed -> new PipeItem(extracted, speed))) {
handler.extractItem(request.slot, extracted.getCount(), false);
update = true; update = true;
} }
} }
@ -141,11 +145,11 @@ public class ItemTerminalTileEntity extends TileEntity implements INamedContaine
int remain = stack.getCount(); int remain = stack.getCount();
locations: locations:
for (NetworkLocation location : item.getLocations()) { for (NetworkLocation location : item.getLocations()) {
for (int slot : location.getStackSlots(stack, ItemEqualityType.NBT)) { for (int slot : location.getStackSlots(this.world, stack, ItemEqualityType.NBT)) {
ItemStack inSlot = location.handler.extractItem(slot, Integer.MAX_VALUE, true); ItemStack inSlot = location.getItemHandler(this.world).extractItem(slot, Integer.MAX_VALUE, true);
if (inSlot.isEmpty()) if (inSlot.isEmpty())
continue; continue;
inSlot.shrink(network.getLockedAmount(location.pos, slot)); inSlot.shrink(network.getLockedAmount(location.getPos(), slot));
if (inSlot.getCount() > 0) { if (inSlot.getCount() > 0) {
int extract = Math.min(inSlot.getCount(), remain); int extract = Math.min(inSlot.getCount(), remain);
NetworkLock lock = new NetworkLock(location, slot, extract); NetworkLock lock = new NetworkLock(location, slot, extract);
@ -177,7 +181,7 @@ public class ItemTerminalTileEntity extends TileEntity implements INamedContaine
PipeTileEntity pipe = this.getConnectedPipe(); PipeTileEntity pipe = this.getConnectedPipe();
Map<EquatableItemStack, NetworkItem> items = new HashMap<>(); Map<EquatableItemStack, NetworkItem> items = new HashMap<>();
for (NetworkLocation location : network.getOrderedNetworkItems(pipe.getPos())) { for (NetworkLocation location : network.getOrderedNetworkItems(pipe.getPos())) {
for (ItemStack stack : location.getItems()) { for (ItemStack stack : location.getItems(this.world).values()) {
EquatableItemStack equatable = new EquatableItemStack(stack); EquatableItemStack equatable = new EquatableItemStack(stack);
NetworkItem item = items.computeIfAbsent(equatable, NetworkItem::new); NetworkItem item = items.computeIfAbsent(equatable, NetworkItem::new);
item.add(location, stack); item.add(location, stack);
@ -190,12 +194,15 @@ public class ItemTerminalTileEntity extends TileEntity implements INamedContaine
@Override @Override
public CompoundNBT write(CompoundNBT compound) { public CompoundNBT write(CompoundNBT compound) {
compound.put("items", this.items.serializeNBT()); compound.put("items", this.items.serializeNBT());
compound.put("requests", Utility.serializeAll(this.pendingRequests));
return super.write(compound); return super.write(compound);
} }
@Override @Override
public void read(CompoundNBT compound) { public void read(CompoundNBT compound) {
this.items.deserializeNBT(compound.getCompound("items")); this.items.deserializeNBT(compound.getCompound("items"));
this.pendingRequests.clear();
this.pendingRequests.addAll(Utility.deserializeAll(compound.getList("requests", NBT.TAG_COMPOUND), NetworkLock::new));
super.read(compound); super.read(compound);
} }