package appeng.tile.storage; import io.netty.buffer.ByteBuf; import java.io.IOException; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import net.minecraft.inventory.IInventory; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraftforge.common.util.ForgeDirection; import appeng.api.AEApi; import appeng.api.implementations.tiles.IChestOrDrive; import appeng.api.networking.GridFlags; import appeng.api.networking.events.MENetworkCellArrayUpdate; import appeng.api.networking.events.MENetworkChannelsChanged; import appeng.api.networking.events.MENetworkEventSubscribe; import appeng.api.networking.events.MENetworkPowerStatusChange; import appeng.api.networking.security.BaseActionSource; import appeng.api.networking.security.MachineSource; import appeng.api.networking.storage.IStorageGrid; import appeng.api.storage.ICellHandler; import appeng.api.storage.IMEInventoryHandler; import appeng.api.storage.StorageChannel; import appeng.api.storage.data.IAEItemStack; import appeng.api.util.AECableType; import appeng.api.util.DimensionalCoord; import appeng.helpers.IPriorityHost; import appeng.me.GridAccessException; import appeng.me.storage.DriveWatcher; import appeng.me.storage.MEInventoryHandler; import appeng.tile.events.AETileEventHandler; import appeng.tile.events.TileEventType; import appeng.tile.grid.AENetworkInvTile; import appeng.tile.inventory.AppEngInternalInventory; import appeng.tile.inventory.InvOperation; import appeng.util.Platform; public class TileDrive extends AENetworkInvTile implements IChestOrDrive, IPriorityHost { final int sides[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; AppEngInternalInventory inv = new AppEngInternalInventory( this, 10 ); boolean isCached = false; ICellHandler handlersBySlot[] = new ICellHandler[10]; DriveWatcher invBySlot[] = new DriveWatcher[10]; List items = new LinkedList(); List fluids = new LinkedList(); BaseActionSource mySrc; long lastStateChange = 0; int state = 0; int priority = 0; boolean wasActive = false; private void recalculateDisplay() { int oldState = 0; boolean currentActive; if ( currentActive = gridProxy.isActive() ) state |= 0x80000000; else state &= ~0x80000000; if ( wasActive != currentActive ) { wasActive = currentActive; try { gridProxy.getGrid().postEvent( new MENetworkCellArrayUpdate() ); } catch (GridAccessException e) { // :P } } for (int x = 0; x < getCellCount(); x++) state |= (getCellStatus( x ) << (3 * x)); if ( oldState != state ) markForUpdate(); } private class invManger extends AETileEventHandler { public invManger() { super( TileEventType.WORLD_NBT, TileEventType.NETWORK ); } @Override public void writeToStream(ByteBuf data) throws IOException { if ( worldObj.getTotalWorldTime() - lastStateChange > 8 ) state = 0; else state &= 0x24924924; // just keep the blinks... if ( gridProxy.isActive() ) state |= 0x80000000; else state &= ~0x80000000; for (int x = 0; x < getCellCount(); x++) state |= (getCellStatus( x ) << (3 * x)); data.writeInt( state ); } @Override public boolean readFromStream(ByteBuf data) throws IOException { int oldState = state; state = data.readInt(); lastStateChange = worldObj.getTotalWorldTime(); return (state & 0xDB6DB6DB) != (oldState & 0xDB6DB6DB); } @Override public void readFromNBT(NBTTagCompound data) { priority = data.getInteger( "priority" ); } @Override public void writeToNBT(NBTTagCompound data) { data.setInteger( "priority", priority ); } }; @MENetworkEventSubscribe public void powerRender(MENetworkPowerStatusChange c) { recalculateDisplay(); } @MENetworkEventSubscribe public void channelRender(MENetworkChannelsChanged c) { recalculateDisplay(); } public TileDrive() { mySrc = new MachineSource( this ); gridProxy.setFlags( GridFlags.REQUIRE_CHANNEL ); addNewHandler( new invManger() ); } @Override public AECableType getCableConnectionType(ForgeDirection dir) { return AECableType.SMART; } @Override public DimensionalCoord getLocation() { return new DimensionalCoord( this ); } @Override public IInventory getInternalInventory() { return inv; } @Override public void onChangeInventory(IInventory inv, int slot, InvOperation mc, ItemStack removed, ItemStack added) { isCached = false; // recalculate the storage cell. updateState(); try { IStorageGrid gs = gridProxy.getStorage(); Platform.postChanges( gs, removed, added, mySrc ); gridProxy.getGrid().postEvent( new MENetworkCellArrayUpdate() ); } catch (GridAccessException e) { } markForUpdate(); } @Override public int[] getAccessibleSlotsBySide(ForgeDirection side) { return sides; } public void updateState() { if ( !isCached ) { items = new LinkedList(); fluids = new LinkedList(); double power = 2.0; for (int x = 0; x < inv.getSizeInventory(); x++) { ItemStack is = inv.getStackInSlot( x ); invBySlot[x] = null; handlersBySlot[x] = null; if ( is != null ) { handlersBySlot[x] = AEApi.instance().registries().cell().getHandler( is ); if ( handlersBySlot[x] != null ) { IMEInventoryHandler cell = handlersBySlot[x].getCellInventory( is, StorageChannel.ITEMS ); if ( cell != null ) { power += handlersBySlot[x].cellIdleDrain( is, cell ); DriveWatcher ih = new DriveWatcher( cell, is, handlersBySlot[x], this ); ih.myPriority = priority; invBySlot[x] = ih; items.add( ih ); } else { cell = handlersBySlot[x].getCellInventory( is, StorageChannel.FLUIDS ); if ( cell != null ) { power += handlersBySlot[x].cellIdleDrain( is, cell ); DriveWatcher ih = new DriveWatcher( cell, is, handlersBySlot[x], this ); ih.myPriority = priority; invBySlot[x] = ih; fluids.add( ih ); } } } } } gridProxy.setIdlePowerUsage( power ); isCached = true; } } @Override public List getCellArray(StorageChannel channel) { if ( gridProxy.isActive() ) { updateState(); return (List) (channel == StorageChannel.ITEMS ? items : fluids); } return new ArrayList(); } @Override public int getPriority() { return priority; } @Override public int getCellCount() { return 10; } @Override public void blinkCell(int slot) { long now = worldObj.getTotalWorldTime(); if ( now - lastStateChange > 8 ) state = 0; lastStateChange = now; state |= 1 << (slot * 3 + 2); recalculateDisplay(); } @Override public boolean isCellBlinking(int slot) { long now = worldObj.getTotalWorldTime(); if ( now - lastStateChange > 8 ) return false; return ((state >> (slot * 3 + 2)) & 0x01) == 0x01; } @Override public int getCellStatus(int slot) { if ( Platform.isClient() ) return (state >> (slot * 3)) & 3; ItemStack cell = inv.getStackInSlot( 2 ); ICellHandler ch = handlersBySlot[slot]; MEInventoryHandler handler = invBySlot[slot]; if ( handler == null ) return 0; if ( handler.getChannel() == StorageChannel.ITEMS ) { if ( ch != null ) return ch.getStatusForCell( cell, handler.getInternal() ); } if ( handler.getChannel() == StorageChannel.FLUIDS ) { if ( ch != null ) return ch.getStatusForCell( cell, handler.getInternal() ); } return 0; } @Override public boolean isPowered() { if ( Platform.isClient() ) return (state & 0x80000000) == 0x80000000; return gridProxy.isActive(); } @Override public void setPriority(int newValue) { priority = newValue; markDirty(); isCached = false; // recalculate the storage cell. updateState(); try { gridProxy.getGrid().postEvent( new MENetworkCellArrayUpdate() ); } catch (GridAccessException e) { // :P } } public boolean isItemValidForSlot(int i, ItemStack itemstack) { return itemstack != null && AEApi.instance().registries().cell().isCellHandled( itemstack ); } }