cb62d3a706
Replaced fuzzy ints with a well defined enum Moved API related cell interfaces to a new subpackage Introduced a new client helper method to register a cell texture for a storage channel Added a method to obtain the storage channel for a drive or chest slot Added a new cell state for cells with stored items but neither types nor completely full
307 lines
9.3 KiB
Java
307 lines
9.3 KiB
Java
/*
|
|
* This file is part of Applied Energistics 2.
|
|
* Copyright (c) 2013 - 2018, AlgorithmX2, All rights reserved.
|
|
*
|
|
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
|
*/
|
|
|
|
package appeng.me.storage;
|
|
|
|
import net.minecraft.item.ItemStack;
|
|
import net.minecraft.nbt.CompoundNBT;
|
|
import net.minecraftforge.items.IItemHandler;
|
|
|
|
import appeng.api.config.FuzzyMode;
|
|
import appeng.api.implementations.items.IStorageCell;
|
|
import appeng.api.storage.cells.CellState;
|
|
import appeng.api.storage.cells.ICellInventory;
|
|
import appeng.api.storage.cells.ISaveProvider;
|
|
import appeng.api.storage.data.IAEStack;
|
|
import appeng.api.storage.data.IItemList;
|
|
|
|
/**
|
|
* @author DrummerMC
|
|
* @version rv6 - 2018-01-17
|
|
* @since rv6 2018-01-17
|
|
*/
|
|
public abstract class AbstractCellInventory<T extends IAEStack<T>> implements ICellInventory<T> {
|
|
private static final int MAX_ITEM_TYPES = 63;
|
|
private static final String ITEM_TYPE_TAG = "it";
|
|
private static final String ITEM_COUNT_TAG = "ic";
|
|
private static final String ITEM_SLOT = "#";
|
|
private static final String ITEM_SLOT_COUNT = "@";
|
|
protected static final String ITEM_PRE_FORMATTED_COUNT = "PF";
|
|
protected static final String ITEM_PRE_FORMATTED_SLOT = "PF#";
|
|
protected static final String ITEM_PRE_FORMATTED_NAME = "PN";
|
|
protected static final String ITEM_PRE_FORMATTED_FUZZY = "FP";
|
|
private static final String[] ITEM_SLOT_KEYS = new String[MAX_ITEM_TYPES];
|
|
private static final String[] ITEM_SLOT_COUNT_KEYS = new String[MAX_ITEM_TYPES];
|
|
private final CompoundNBT tagCompound;
|
|
protected final ISaveProvider container;
|
|
private int maxItemTypes = MAX_ITEM_TYPES;
|
|
private short storedItems = 0;
|
|
private int storedItemCount = 0;
|
|
protected IItemList<T> cellItems;
|
|
private final ItemStack i;
|
|
protected final IStorageCell<T> cellType;
|
|
protected final int itemsPerByte;
|
|
private boolean isPersisted = true;
|
|
|
|
static {
|
|
for (int x = 0; x < MAX_ITEM_TYPES; x++) {
|
|
ITEM_SLOT_KEYS[x] = ITEM_SLOT + x;
|
|
ITEM_SLOT_COUNT_KEYS[x] = ITEM_SLOT_COUNT + x;
|
|
}
|
|
}
|
|
|
|
protected AbstractCellInventory(final IStorageCell<T> cellType, final ItemStack o, final ISaveProvider container) {
|
|
this.i = o;
|
|
this.cellType = cellType;
|
|
this.itemsPerByte = this.cellType.getChannel().getUnitsPerByte();
|
|
this.maxItemTypes = this.cellType.getTotalTypes(this.i);
|
|
|
|
if (this.maxItemTypes > MAX_ITEM_TYPES) {
|
|
this.maxItemTypes = MAX_ITEM_TYPES;
|
|
}
|
|
if (this.maxItemTypes < 1) {
|
|
this.maxItemTypes = 1;
|
|
}
|
|
|
|
this.container = container;
|
|
this.tagCompound = o.getOrCreateTag();
|
|
this.storedItems = this.tagCompound.getShort(ITEM_TYPE_TAG);
|
|
this.storedItemCount = this.tagCompound.getInt(ITEM_COUNT_TAG);
|
|
this.cellItems = null;
|
|
}
|
|
|
|
protected IItemList<T> getCellItems() {
|
|
if (this.cellItems == null) {
|
|
this.cellItems = this.getChannel().createList();
|
|
this.loadCellItems();
|
|
}
|
|
|
|
return this.cellItems;
|
|
}
|
|
|
|
@Override
|
|
public void persist() {
|
|
if (this.isPersisted) {
|
|
return;
|
|
}
|
|
|
|
int itemCount = 0;
|
|
|
|
// add new pretty stuff...
|
|
int x = 0;
|
|
for (final T v : this.cellItems) {
|
|
itemCount += v.getStackSize();
|
|
|
|
final CompoundNBT g = new CompoundNBT();
|
|
v.writeToNBT(g);
|
|
this.tagCompound.put(ITEM_SLOT_KEYS[x], g);
|
|
this.tagCompound.putInt(ITEM_SLOT_COUNT_KEYS[x], (int) v.getStackSize());
|
|
|
|
x++;
|
|
}
|
|
|
|
final short oldStoredItems = this.storedItems;
|
|
|
|
this.storedItems = (short) this.cellItems.size();
|
|
if (this.cellItems.isEmpty()) {
|
|
this.tagCompound.remove(ITEM_TYPE_TAG);
|
|
} else {
|
|
this.tagCompound.putShort(ITEM_TYPE_TAG, this.storedItems);
|
|
}
|
|
|
|
this.storedItemCount = itemCount;
|
|
if (itemCount == 0) {
|
|
this.tagCompound.remove(ITEM_COUNT_TAG);
|
|
} else {
|
|
this.tagCompound.putInt(ITEM_COUNT_TAG, itemCount);
|
|
}
|
|
|
|
// clean any old crusty stuff...
|
|
for (; x < oldStoredItems && x < this.maxItemTypes; x++) {
|
|
this.tagCompound.remove(ITEM_SLOT_KEYS[x]);
|
|
this.tagCompound.remove(ITEM_SLOT_COUNT_KEYS[x]);
|
|
}
|
|
|
|
this.isPersisted = true;
|
|
}
|
|
|
|
protected void saveChanges() {
|
|
// recalculate values
|
|
this.storedItems = (short) this.cellItems.size();
|
|
this.storedItemCount = 0;
|
|
for (final T v : this.cellItems) {
|
|
this.storedItemCount += v.getStackSize();
|
|
}
|
|
|
|
this.isPersisted = false;
|
|
if (this.container != null) {
|
|
this.container.saveChanges(this);
|
|
} else {
|
|
// if there is no ISaveProvider, store to NBT immediately
|
|
this.persist();
|
|
}
|
|
}
|
|
|
|
private void loadCellItems() {
|
|
if (this.cellItems == null) {
|
|
this.cellItems = this.getChannel().createList();
|
|
}
|
|
|
|
this.cellItems.resetStatus(); // clears totals and stuff.
|
|
|
|
final int types = (int) this.getStoredItemTypes();
|
|
boolean needsUpdate = false;
|
|
|
|
for (int slot = 0; slot < types; slot++) {
|
|
CompoundNBT compoundTag = this.tagCompound.getCompound(ITEM_SLOT_KEYS[slot]);
|
|
int stackSize = this.tagCompound.getInt(ITEM_SLOT_COUNT_KEYS[slot]);
|
|
needsUpdate |= !this.loadCellItem(compoundTag, stackSize);
|
|
}
|
|
|
|
if (needsUpdate) {
|
|
this.saveChanges();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Load a single item.
|
|
*
|
|
* @param compoundTag
|
|
* @param stackSize
|
|
* @return true when successfully loaded
|
|
*/
|
|
protected abstract boolean loadCellItem(CompoundNBT compoundTag, int stackSize);
|
|
|
|
@Override
|
|
public IItemList<T> getAvailableItems(final IItemList<T> out) {
|
|
for (final T item : this.getCellItems()) {
|
|
out.add(item);
|
|
}
|
|
|
|
return out;
|
|
}
|
|
|
|
@Override
|
|
public ItemStack getItemStack() {
|
|
return this.i;
|
|
}
|
|
|
|
@Override
|
|
public double getIdleDrain() {
|
|
return this.cellType.getIdleDrain();
|
|
}
|
|
|
|
@Override
|
|
public FuzzyMode getFuzzyMode() {
|
|
return this.cellType.getFuzzyMode(this.i);
|
|
}
|
|
|
|
@Override
|
|
public IItemHandler getConfigInventory() {
|
|
return this.cellType.getConfigInventory(this.i);
|
|
}
|
|
|
|
@Override
|
|
public IItemHandler getUpgradesInventory() {
|
|
return this.cellType.getUpgradesInventory(this.i);
|
|
}
|
|
|
|
@Override
|
|
public int getBytesPerType() {
|
|
return this.cellType.getBytesPerType(this.i);
|
|
}
|
|
|
|
@Override
|
|
public boolean canHoldNewItem() {
|
|
final long bytesFree = this.getFreeBytes();
|
|
return (bytesFree > this.getBytesPerType()
|
|
|| (bytesFree == this.getBytesPerType() && this.getUnusedItemCount() > 0))
|
|
&& this.getRemainingItemTypes() > 0;
|
|
}
|
|
|
|
@Override
|
|
public long getTotalBytes() {
|
|
return this.cellType.getBytes(this.i);
|
|
}
|
|
|
|
@Override
|
|
public long getFreeBytes() {
|
|
return this.getTotalBytes() - this.getUsedBytes();
|
|
}
|
|
|
|
@Override
|
|
public long getTotalItemTypes() {
|
|
return this.maxItemTypes;
|
|
}
|
|
|
|
@Override
|
|
public long getStoredItemCount() {
|
|
return this.storedItemCount;
|
|
}
|
|
|
|
@Override
|
|
public long getStoredItemTypes() {
|
|
return this.storedItems;
|
|
}
|
|
|
|
@Override
|
|
public long getRemainingItemTypes() {
|
|
final long basedOnStorage = this.getFreeBytes() / this.getBytesPerType();
|
|
final long baseOnTotal = this.getTotalItemTypes() - this.getStoredItemTypes();
|
|
return basedOnStorage > baseOnTotal ? baseOnTotal : basedOnStorage;
|
|
}
|
|
|
|
@Override
|
|
public long getUsedBytes() {
|
|
final long bytesForItemCount = (this.getStoredItemCount() + this.getUnusedItemCount()) / this.itemsPerByte;
|
|
return this.getStoredItemTypes() * this.getBytesPerType() + bytesForItemCount;
|
|
}
|
|
|
|
@Override
|
|
public long getRemainingItemCount() {
|
|
final long remaining = this.getFreeBytes() * this.itemsPerByte + this.getUnusedItemCount();
|
|
return remaining > 0 ? remaining : 0;
|
|
}
|
|
|
|
@Override
|
|
public int getUnusedItemCount() {
|
|
final int div = (int) (this.getStoredItemCount() % 8);
|
|
|
|
if (div == 0) {
|
|
return 0;
|
|
}
|
|
|
|
return this.itemsPerByte - div;
|
|
}
|
|
|
|
@Override
|
|
public CellState getStatusForCell() {
|
|
if (this.getStoredItemTypes() == 0) {
|
|
return CellState.EMPTY;
|
|
}
|
|
if (this.canHoldNewItem()) {
|
|
return CellState.NOT_EMPTY;
|
|
}
|
|
if (this.getRemainingItemCount() > 0) {
|
|
return CellState.TYPES_FULL;
|
|
}
|
|
return CellState.FULL;
|
|
}
|
|
|
|
}
|