/* * 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 . */ package appeng.me.storage; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraftforge.items.IItemHandler; import appeng.api.config.FuzzyMode; import appeng.api.implementations.items.IStorageCell; import appeng.api.storage.ICellInventory; import appeng.api.storage.ISaveProvider; import appeng.api.storage.data.IAEStack; import appeng.api.storage.data.IItemList; import appeng.util.Platform; /** * @author DrummerMC * @version rv6 - 2018-01-17 * @since rv6 2018-01-17 */ public abstract class AbstractCellInventory> implements ICellInventory { 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 NBTTagCompound tagCompound; protected final ISaveProvider container; private int maxItemTypes = MAX_ITEM_TYPES; private short storedItems = 0; private int storedItemCount = 0; protected IItemList cellItems; private final ItemStack i; protected final IStorageCell 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 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 = Platform.openNbtData( o ); this.storedItems = this.tagCompound.getShort( ITEM_TYPE_TAG ); this.storedItemCount = this.tagCompound.getInteger( ITEM_COUNT_TAG ); this.cellItems = null; } protected IItemList 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 NBTTagCompound g = new NBTTagCompound(); v.writeToNBT( g ); this.tagCompound.setTag( ITEM_SLOT_KEYS[x], g ); this.tagCompound.setInteger( 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.removeTag( ITEM_TYPE_TAG ); } else { this.tagCompound.setShort( ITEM_TYPE_TAG, this.storedItems ); } this.storedItemCount = itemCount; if( itemCount == 0 ) { this.tagCompound.removeTag( ITEM_COUNT_TAG ); } else { this.tagCompound.setInteger( ITEM_COUNT_TAG, itemCount ); } // clean any old crusty stuff... for( ; x < oldStoredItems && x < this.maxItemTypes; x++ ) { this.tagCompound.removeTag( ITEM_SLOT_KEYS[x] ); this.tagCompound.removeTag( 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++ ) { NBTTagCompound compoundTag = this.tagCompound.getCompoundTag( ITEM_SLOT_KEYS[slot] ); int stackSize = this.tagCompound.getInteger( 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( NBTTagCompound compoundTag, int stackSize ); @Override public IItemList getAvailableItems( final IItemList 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 int getStatusForCell() { if( this.canHoldNewItem() ) { return 1; } if( this.getRemainingItemCount() > 0 ) { return 2; } return 3; } }