Files
Applied-Energistics-2/src/main/java/appeng/me/storage/BasicCellInventory.java
T

289 lines
6.5 KiB
Java

package appeng.me.storage;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
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;
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 int remainingItemCount = (int) this.getRemainingItemCount() - 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, int 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 );
if( stackSize > 0 )
{
this.cellItems.add( t );
}
return true;
}
}