package com.someluigi.slperiph.ccportable.shared; import java.io.DataInputStream; import java.io.IOException; import net.minecraft.block.Block; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.inventory.Container; import net.minecraft.inventory.ICrafting; import net.minecraft.inventory.InventoryBasic; import net.minecraft.inventory.Slot; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.ChatAllowedCharacters; import net.minecraft.util.Vec3; import com.someluigi.slperiph.CommonProxy; import com.someluigi.slperiph.SLPMod; import com.someluigi.slperiph.ccportable.gfx.TerminalRenderer; import com.someluigi.slperiph.ccportable.shared.PayloadManager.Payload; public class ContainerTerminal extends Container implements IPacketHandler{ public static class TerminalTab implements IUpdateListener{ public static final ItemStack DEFAULT_ICON = new ItemStack( Block.blockSteel ); protected final ContainerTerminal container; protected final int index; protected ItemStack icon = DEFAULT_ICON; protected String label = "No Device"; public PeripheralTerminal peripheral; //Serverside public Terminal terminal; //Clientside public boolean isLinked = false; public boolean isHilighted = false; public TerminalTab( int index, ContainerTerminal container ){ this.container = container; this.index = index; } public void setTerminal( PeripheralTerminal newTerminal ){ if ( peripheral != null ) peripheral.removeUpdateListener(this); isLinked = ( newTerminal != null ); if ( isLinked ){ peripheral = newTerminal; peripheral.addUpdateListener(this); } } public int getColor(){ if ( !isLinked ) return 0x4D4D4D; if ( isHilighted && TerminalRenderer.getBlink() ) return 0xFF2020; return 0xFFFFFF; } public ItemStack getIcon(){ return icon; } public String getTooltip(){ return label; } //This shall be only called by terminal entities public void onUpdate() { container.updateTerminal(index); } } protected final boolean isServer; protected final EntityPlayer owner; //TODO: I shall probably make these two protected! public TerminalTab[] tabs = new TerminalTab[6]; public int activeTabID = -1; protected ItemStack terminal; protected InventoryPlayer playerInv; protected InventoryBasic crystalInv; //Serverside constructor public ContainerTerminal( EntityPlayer player, ItemStack item ){ this( player, true ); this.terminal = item; loadItemData(item); } //Clientside constructor public ContainerTerminal( EntityPlayer player, boolean isServer ){ this.isServer = isServer; this.owner = player; this.playerInv = player.inventory; this.crystalInv = new InventoryBasic("Crystals", false, 6); for ( int index = 0; index < tabs.length; index++ ) tabs[index] = new TerminalTab(index, this); int anchorX = 42; int anchorY = 104; //Player main inventory for ( int lineID = 1; lineID < 4; lineID++ ) for ( int slot = 0; slot < 9; slot++ ) addSlotToContainer( new Slot(playerInv, lineID *9 + slot, anchorX + slot *18, anchorY + lineID *18) ); //Player hotbar anchorY += 76; for ( int slot = 0; slot < 9; slot++ ) addSlotToContainer( new Slot(playerInv, slot, anchorX + slot *18, anchorY) ); //Crystals anchorX += 180; anchorY -= 58; for ( int lineID = 0; lineID < 3; lineID++ ) for ( int slot = 0; slot < 2; slot++ ) addSlotToContainer( new SlotCrystal(crystalInv, lineID *2 + slot, anchorX + slot *18, anchorY + lineID *18) ); } public boolean canInteractWith(EntityPlayer player) { return true; } public ItemStack transferStackInSlot(EntityPlayer player, int index) { ItemStack transfer = null; Slot slot = (Slot) this.inventorySlots.get(index); if ( slot != null && slot.getHasStack() ){ ItemStack item = slot.getStack(); transfer = item.copy(); if ( index >= 36 ){ //Move crystals to the player inv if ( !mergeItemStack(item, 0, 36, true) ) return null; } else { if ( !SlotCrystal.isValid(item) || !mergeItemStack(item, 36, inventorySlots.size(), false) ) //Move from the player inv return null; } if ( item.stackSize == 0 ) { //The item is consumed completely slot.putStack(null); } else { slot.onSlotChanged(); } } return transfer; } /* * Events */ //Hacky event, so the client would receive terminals AFTER they opened the GUI public void addCraftingToCrafters(ICrafting crafting) { super.addCraftingToCrafters(crafting); sendInitialData(); } public void onCraftGuiClosed(EntityPlayer player) { super.onCraftGuiClosed(player); if ( terminal != null ){ saveItemData(terminal); //Notify closed terminals for ( int index = 0; index < tabs.length; index++ ){ TerminalTab tab = tabs[index]; if ( tab.isLinked && tab.peripheral != null ) tab.peripheral.queueEvent("pda_close"); } } } /* * Stack manipulation */ protected static final String CRYSTAL_TAG = "crystalFreq"; protected static final String COUNT_TAG = "crystalCount"; protected static final String FOCUS_TAG = "focusedTab"; protected void loadItemData( ItemStack item ){ if ( item != null && item.hasTagCompound() ){ NBTTagCompound data = item.getTagCompound(); //Load crystals, and setup connections int[] frequencies = data.getIntArray( CRYSTAL_TAG ); int count = Math.min( crystalInv.getSizeInventory(), frequencies.length ); Vec3 plyPos = Vec3.createVectorHelper( owner.posX, owner.posY, owner.posZ ); for ( int index = 0; index < count; index++ ){ int freq = frequencies[index]; if ( freq > 0 ){ //Set crystal in place crystalInv.setInventorySlotContents(index, ItemQuartz.newCrystal(freq) ); //Add reachable terminals PeripheralTerminal term = SLPMod.proxy.network.querySingleDevice(plyPos, freq); if ( term != null ) setTerminal(index, term); } } //Load misc data setActiveTab(data.getInteger(FOCUS_TAG)); detectAndSendChanges(); } } protected void saveItemData( ItemStack item ){ NBTTagCompound data = new NBTTagCompound(); //Save crystals int limit = crystalInv.getSizeInventory(); int[] freqencies = new int[limit]; int count = 0; for ( int index = 0; index < limit; index++ ){ ItemStack crystal = crystalInv.getStackInSlot(index); if ( crystal == null ) { freqencies[index] = -1; } else { freqencies[index] = crystal.getItemDamage(); count++; } } if ( count > 0 ){ data.setInteger( COUNT_TAG, count ); data.setIntArray( CRYSTAL_TAG, freqencies ); } //Save misc data data.setInteger(FOCUS_TAG, activeTabID); item.setTagCompound(data); } /* * Network - Terminal management */ protected static final int ID_TERM_CREATE = 0x00; protected static final int ID_TERM_UPDATE = 0x01; protected static final int ID_EVENT_KEY = 0x02; protected static final int ID_EVENT_MOUSE = 0x03; protected static final int ID_ACTIVE_TAB = 0x10; public boolean isValidTarget( int index ){ return 0 <= index && index < tabs.length; } //Server public void setTerminal( int id, PeripheralTerminal terminal ){ if ( !isValidTarget(id) ) return; tabs[id].setTerminal(terminal); terminal.queueEvent("pda_open"); } protected void sendInitialData(){ for ( int index = 0; index < tabs.length; index++ ){ TerminalTab tab = tabs[index]; if ( tab.isLinked ){ Payload payload = CommonProxy.newContainerUpdate(this); payload.writeByte( ID_TERM_CREATE ); payload.writeByte( index ); payload.writeInt( tab.peripheral.getFreq() ); tab.peripheral.writeNewPayload(payload); payload.sendTo(owner); } } setActiveTab(activeTabID); } public void updateTerminal( int id ){ if ( !isValidTarget(id) ) return; Payload payload = CommonProxy.newContainerUpdate(this); payload.writeByte( ID_TERM_UPDATE ); payload.writeByte( id ); tabs[id].peripheral.writeUpdatePayload(payload); payload.sendTo(owner); } //Client public void sendKeyEvent( int id, char chr, int key ){ if ( !isValidTarget(id) ) return; Payload payload = CommonProxy.newContainerUpdate(this); payload.writeByte( ID_EVENT_KEY ); payload.writeByte( id ); payload.writeChar(chr); payload.writeInt(key); payload.sendToServer(); } public void sendMouseEvent( int id, int event, int charX, int charY ){ if ( !isValidTarget(id) ) return; Payload payload = CommonProxy.newContainerUpdate(this); payload.writeByte( ID_EVENT_MOUSE ); payload.writeByte( id ); payload.writeByte(event); payload.writeShort(charX); payload.writeShort(charY); payload.sendToServer(); } //Shared public void setActiveTab( int id ){ if ( !isValidTarget(id) || !tabs[id].isLinked ) return; activeTabID = id; Payload payload = CommonProxy.newContainerUpdate(this); payload.writeByte( ID_ACTIVE_TAB ); payload.writeByte( id ); if ( isServer ) { payload.sendTo(owner); } else { payload.sendToServer(); } } //Shared public void handlePacket(DataInputStream stream, EntityPlayer player) throws IOException { int type = stream.readByte(); int index = stream.readByte(); if ( !isValidTarget(index) ){ //Invalid target CommonProxy.protocolViolation(player); return; } //Handle shared events if ( type == ID_ACTIVE_TAB ){ activeTabID = index; return; } //Terminal based events TerminalTab tab = tabs[ index ]; if ( isServer ){ PeripheralTerminal terminal = tab.peripheral; if ( terminal == null || !tab.isLinked ) return; //Really should not happen switch( type ){ case ID_EVENT_KEY: //Key press events char chr = stream.readChar(); int key = stream.readInt(); if ( key >= 0 ) terminal.queueEvent( "pda_key", key ); if ( ChatAllowedCharacters.isAllowedCharacter(chr) ) terminal.queueEvent( "pda_char", "" + chr ); break; case ID_EVENT_MOUSE: //Mouse events byte event = stream.readByte(); int charX = stream.readShort() +1; int charY = stream.readShort() +1; switch( event ){ case 0: //Mouse click case 1: case 2: terminal.queueEvent("pda_click", event +1, charX, charY ); break; //Mouse scroll case 3: terminal.queueEvent("pda_scroll", 1 ); break; case 4: terminal.queueEvent("pda_scroll", -1 ); break; case 5: //Mouse drag case 6: case 7: terminal.queueEvent("pda_drag", event -5 +1, charX, charY ); break; } break; } } else { switch( type ){ case ID_TERM_CREATE: //Terminal creation, and initial sync int freq = stream.readInt(); tab.icon = ItemQuartz.newCrystal(freq); tab.label = "Freq: " + freq; tab.terminal = Terminal.readNewPayload(stream); tab.isLinked = true; break; case ID_TERM_UPDATE: //Line updates tab.terminal.readUpdatePayload(stream); tab.isHilighted = true; break; } } } }