f7aa4c92bc
Migrates the total item count and serialized stack sizes to `long`
235 lines
7.7 KiB
Java
235 lines
7.7 KiB
Java
package appeng.me.storage;
|
|
|
|
|
|
import appeng.api.config.Actionable;
|
|
import appeng.api.exceptions.AppEngException;
|
|
import appeng.api.implementations.items.IStorageCell;
|
|
import appeng.api.networking.security.IActionSource;
|
|
import appeng.api.storage.ICellInventory;
|
|
import appeng.api.storage.ISaveProvider;
|
|
import appeng.api.storage.IStorageChannel;
|
|
import appeng.api.storage.data.IAEItemStack;
|
|
import appeng.api.storage.data.IAEStack;
|
|
import appeng.core.AEConfig;
|
|
import appeng.core.AELog;
|
|
import appeng.util.item.AEStack;
|
|
import net.minecraft.item.Item;
|
|
import net.minecraft.item.ItemStack;
|
|
import net.minecraft.nbt.NBTTagCompound;
|
|
|
|
|
|
public class BasicCellInventory<T extends IAEStack<T>> extends AbstractCellInventory<T> {
|
|
private final IStorageChannel<T> channel;
|
|
|
|
private BasicCellInventory(final IStorageCell<T> cellType, final ItemStack o, final ISaveProvider container) {
|
|
super(cellType, o, container);
|
|
this.channel = cellType.getChannel();
|
|
}
|
|
|
|
public static <T extends IAEStack<T>> ICellInventory<T> createInventory(final ItemStack o, final ISaveProvider container) {
|
|
try {
|
|
if (o == null) {
|
|
throw new AppEngException("ItemStack was used as a cell, but was not a cell!");
|
|
}
|
|
|
|
final Item type = o.getItem();
|
|
final IStorageCell<T> cellType;
|
|
if (type instanceof IStorageCell) {
|
|
cellType = (IStorageCell<T>) type;
|
|
} else {
|
|
throw new AppEngException("ItemStack was used as a cell, but was not a cell!");
|
|
}
|
|
|
|
if (!cellType.isStorageCell(o)) {
|
|
throw new AppEngException("ItemStack was used as a cell, but was not a cell!");
|
|
}
|
|
|
|
return new BasicCellInventory<T>(cellType, o, container);
|
|
} catch (final AppEngException e) {
|
|
AELog.error(e);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public static <T extends AEStack<T>> boolean isCellOfType(final ItemStack input, IStorageChannel<?> channel) {
|
|
final IStorageCell<?> type = getStorageCell(input);
|
|
|
|
return type != null && type.getChannel() == channel;
|
|
}
|
|
|
|
public static boolean isCell(final ItemStack input) {
|
|
return getStorageCell(input) != null;
|
|
}
|
|
|
|
private boolean isStorageCell(final T input) {
|
|
if (input instanceof IAEItemStack) {
|
|
final IAEItemStack stack = (IAEItemStack) input;
|
|
final IStorageCell<?> type = getStorageCell(stack.getDefinition());
|
|
|
|
return type != null && !type.storableInStorageCell();
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private static IStorageCell<?> getStorageCell(final ItemStack input) {
|
|
if (input != null) {
|
|
final Item type = input.getItem();
|
|
|
|
if (type instanceof IStorageCell) {
|
|
return (IStorageCell<?>) type;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
@SuppressWarnings({"rawtypes", "unchecked"})
|
|
private static boolean isCellEmpty(ICellInventory inv) {
|
|
if (inv != null) {
|
|
return inv.getAvailableItems(inv.getChannel().createList()).isEmpty();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public T injectItems(T input, Actionable mode, IActionSource src) {
|
|
if (input == null) {
|
|
return null;
|
|
}
|
|
if (input.getStackSize() == 0) {
|
|
return null;
|
|
}
|
|
|
|
if (this.cellType.isBlackListed(this.getItemStack(), input)) {
|
|
return input;
|
|
}
|
|
// This is slightly hacky as it expects a read-only access, but fine for now.
|
|
// TODO: Guarantee a read-only access. E.g. provide an isEmpty() method and ensure CellInventory does not write
|
|
// any NBT data for empty cells instead of relying on an empty IItemContainer
|
|
if (this.isStorageCell(input)) {
|
|
final ICellInventory<?> meInventory = createInventory(((IAEItemStack) input).createItemStack(), null);
|
|
if (!isCellEmpty(meInventory)) {
|
|
return input;
|
|
}
|
|
}
|
|
|
|
final T l = this.getCellItems().findPrecise(input);
|
|
if (l != null) {
|
|
final long remainingItemCount = this.getRemainingItemCount();
|
|
if (remainingItemCount <= 0) {
|
|
return input;
|
|
}
|
|
|
|
if (input.getStackSize() > remainingItemCount) {
|
|
final T r = input.copy();
|
|
r.setStackSize(r.getStackSize() - remainingItemCount);
|
|
if (mode == Actionable.MODULATE) {
|
|
l.setStackSize(l.getStackSize() + remainingItemCount);
|
|
this.saveChanges();
|
|
}
|
|
return r;
|
|
} else {
|
|
if (mode == Actionable.MODULATE) {
|
|
l.setStackSize(l.getStackSize() + input.getStackSize());
|
|
this.saveChanges();
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
|
|
if (this.canHoldNewItem()) // room for new type, and for at least one item!
|
|
{
|
|
final long remainingItemCount = this.getRemainingItemCount() - (long) this.getBytesPerType() * this.itemsPerByte;
|
|
if (remainingItemCount > 0) {
|
|
if (input.getStackSize() > remainingItemCount) {
|
|
final T toReturn = input.copy();
|
|
toReturn.setStackSize(input.getStackSize() - remainingItemCount);
|
|
if (mode == Actionable.MODULATE) {
|
|
final T toWrite = input.copy();
|
|
toWrite.setStackSize(remainingItemCount);
|
|
|
|
this.cellItems.add(toWrite);
|
|
this.saveChanges();
|
|
}
|
|
return toReturn;
|
|
}
|
|
|
|
if (mode == Actionable.MODULATE) {
|
|
this.cellItems.add(input);
|
|
this.saveChanges();
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|
|
|
|
return input;
|
|
}
|
|
|
|
@Override
|
|
public T extractItems(T request, Actionable mode, IActionSource src) {
|
|
if (request == null) {
|
|
return null;
|
|
}
|
|
|
|
final long size = Math.min(Integer.MAX_VALUE, request.getStackSize());
|
|
|
|
T Results = null;
|
|
|
|
final T l = this.getCellItems().findPrecise(request);
|
|
if (l != null) {
|
|
Results = l.copy();
|
|
|
|
if (l.getStackSize() <= size) {
|
|
Results.setStackSize(l.getStackSize());
|
|
if (mode == Actionable.MODULATE) {
|
|
l.setStackSize(0);
|
|
this.saveChanges();
|
|
}
|
|
} else {
|
|
Results.setStackSize(size);
|
|
if (mode == Actionable.MODULATE) {
|
|
l.setStackSize(l.getStackSize() - size);
|
|
this.saveChanges();
|
|
}
|
|
}
|
|
}
|
|
|
|
return Results;
|
|
}
|
|
|
|
@Override
|
|
public IStorageChannel<T> getChannel() {
|
|
return this.channel;
|
|
}
|
|
|
|
@Override
|
|
protected boolean loadCellItem(NBTTagCompound compoundTag, long stackSize) {
|
|
// Now load the item stack
|
|
final T t;
|
|
try {
|
|
t = this.getChannel().createFromNBT(compoundTag);
|
|
if (t == null) {
|
|
AELog.warn("Removing item " + compoundTag + " from storage cell because the associated item type couldn't be found.");
|
|
return false;
|
|
}
|
|
} catch (Throwable ex) {
|
|
if (AEConfig.instance().isRemoveCrashingItemsOnLoad()) {
|
|
AELog.warn(ex, "Removing item " + compoundTag + " from storage cell because loading the ItemStack crashed.");
|
|
return false;
|
|
}
|
|
throw ex;
|
|
}
|
|
|
|
t.setStackSize(stackSize);
|
|
t.setCraftable(false);
|
|
|
|
if (stackSize > 0) {
|
|
this.cellItems.add(t);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|