package com.arkcraft.module.blocks.common.container; 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.Slot; import net.minecraft.item.ItemStack; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.arkcraft.lib.LogHelper; import com.arkcraft.module.blocks.common.tile.TileInventoryForge; public class ContainerInventoryForge extends Container { // Stores the tile entity instance for later use private TileInventoryForge tileInventoryForge; // These store cache values, used by the server to only update the client // side tile entity when values have changed private int[] cachedFields; // must assign a slot index to each of the slots used by the GUI. // For this container, we can see the furnace fuel, input, and output slots // as well as the player inventory slots and the hotbar. // Each time we add a Slot to the container using addSlotToContainer(), it // automatically increases the slotIndex, which means // 0 - 8 = hotbar slots (which will map to the InventoryPlayer slot numbers // 0 - 8) // 9 - 35 = player inventory slots (which map to the InventoryPlayer slot // numbers 9 - 35) // 36 - 39 = fuel slots (tileEntity 0 - 3) // 40 - 44 = input slots (tileEntity 4 - 8) // 45 - 49 = output slots (tileEntity 9 - 13) private final int HOTBAR_SLOT_COUNT = 9; private final int PLAYER_INVENTORY_ROW_COUNT = 3; private final int PLAYER_INVENTORY_COLUMN_COUNT = 9; private final int PLAYER_INVENTORY_SLOT_COUNT = PLAYER_INVENTORY_COLUMN_COUNT * PLAYER_INVENTORY_ROW_COUNT; private final int VANILLA_SLOT_COUNT = HOTBAR_SLOT_COUNT + PLAYER_INVENTORY_SLOT_COUNT; public final int FURNACE_SLOT_COUNT = 8; // slot index is the unique index for all slots in this container i.e. 0 - // 35 for invPlayer then 36 - 49 for tileInventoryFurnace private final int FIRST_FURNACE_SLOT_INDEX = 0; public final int VANILLA_FIRST_SLOT_INDEX = FIRST_FURNACE_SLOT_INDEX + FURNACE_SLOT_COUNT; public ContainerInventoryForge(InventoryPlayer invPlayer, TileInventoryForge tileInventoryFurnace) { this.tileInventoryForge = tileInventoryFurnace; final int SLOT_X_SPACING = 18; final int SLOT_Y_SPACING = 18; final int PLAYER_INVENTORY_XPOS = 8; final int PLAYER_INVENTORY_YPOS = 84; final int HOTBAR_YPOS = PLAYER_INVENTORY_YPOS + 10 + 16 * 3; final int FURNACE_SLOTS_XPOS = 53; final int FURNACE_SLOTS_YPOS = 26; // Add the tile fuel slots for (int x = 0; x < FURNACE_SLOT_COUNT; x++) { for (x = x; x < 4; x++) { addSlotToContainer(new Slot(tileInventoryFurnace, x, FURNACE_SLOTS_XPOS + SLOT_X_SPACING * x, FURNACE_SLOTS_YPOS)); } for (x = x; x < FURNACE_SLOT_COUNT; x++) { addSlotToContainer(new Slot(tileInventoryFurnace, x, FURNACE_SLOTS_XPOS + SLOT_X_SPACING * (x - 4), FURNACE_SLOTS_YPOS + 18)); } } // Add the players hotbar to the gui - the [xpos, ypos] location of each // item for (int x = 0; x < HOTBAR_SLOT_COUNT; x++) { addSlotToContainer(new Slot(invPlayer, x, PLAYER_INVENTORY_XPOS + SLOT_X_SPACING * x, HOTBAR_YPOS)); } // Add the rest of the players inventory to the gui for (int y = 0; y < PLAYER_INVENTORY_ROW_COUNT; y++) { for (int x = 0; x < PLAYER_INVENTORY_COLUMN_COUNT; x++) { int slotNumber = HOTBAR_SLOT_COUNT + y * PLAYER_INVENTORY_COLUMN_COUNT + x; int xpos = PLAYER_INVENTORY_XPOS + x * SLOT_X_SPACING; int ypos = PLAYER_INVENTORY_YPOS + y * SLOT_Y_SPACING; addSlotToContainer(new Slot(invPlayer, slotNumber, xpos, ypos)); } } } // Checks each tick to make sure the player is still able to access the // inventory and if not closes the gui @Override public boolean canInteractWith(EntityPlayer player) { return tileInventoryForge.isUseableByPlayer(player); } // This is where you specify what happens when a player shift clicks a slot // in the gui // (when you shift click a slot in the TileEntity Inventory, it moves it to // the first available position in the hotbar and/or // player inventory. When you you shift-click a hotbar or player inventory // item, it moves it to the first available // position in the TileEntity inventory - either input or fuel as // appropriate for the item you clicked) // At the very least you must override this and return null or the game will // crash when the player shift clicks a slot // returns null if the source slot is empty, or if none of the source slot // items could be moved. // otherwise, returns a copy of the source stack @Override public ItemStack transferStackInSlot(EntityPlayer player, int sourceSlotIndex) { LogHelper.info(sourceSlotIndex); Slot sourceSlot = (Slot) inventorySlots.get(sourceSlotIndex); if (sourceSlot == null || !sourceSlot.getHasStack()) return null; ItemStack sourceStack = sourceSlot.getStack(); ItemStack copyOfSourceStack = sourceStack.copy(); // Check if the slot clicked is one of the vanilla container slots if (sourceSlotIndex >= VANILLA_FIRST_SLOT_INDEX && sourceSlotIndex < VANILLA_FIRST_SLOT_INDEX + VANILLA_SLOT_COUNT) { // This is a vanilla container slot so merge the stack into one of // the furnace slots // If the stack is smeltable try to merge merge the stack into the // input slots if (!mergeItemStack(sourceStack, FIRST_FURNACE_SLOT_INDEX, FIRST_FURNACE_SLOT_INDEX + FURNACE_SLOT_COUNT, false)) { return null; } } else if (sourceSlotIndex >= FIRST_FURNACE_SLOT_INDEX && sourceSlotIndex < FIRST_FURNACE_SLOT_INDEX + FURNACE_SLOT_COUNT) { // This is a furnace slot so merge the stack into the players // inventory: try the hotbar first and then the main inventory // because the main inventory slots are immediately after the hotbar // slots, we can just merge with a single call if (!mergeItemStack(sourceStack, VANILLA_FIRST_SLOT_INDEX, VANILLA_FIRST_SLOT_INDEX + VANILLA_SLOT_COUNT, false)) { return null; } } else { System.err.print("Invalid slotIndex:" + sourceSlotIndex); return null; } // If stack size == 0 (the entire stack was moved) set slot contents to // null if (sourceStack.stackSize == 0) { sourceSlot.putStack(null); } else { sourceSlot.onSlotChanged(); } sourceSlot.onPickupFromSlot(player, sourceStack); return copyOfSourceStack; } /* Client Synchronization */ // This is where you check if any values have changed and if so send an // update to any clients accessing this container // The container itemstacks are tested in Container.detectAndSendChanges, so // we don't need to do that // We iterate through all of the TileEntity Fields to find any which have // changed, and send them. // You don't have to use fields if you don't wish to; just manually match // the ID in sendProgressBarUpdate with the value in // updateProgressBar() // The progress bar values are restricted to shorts. If you have a larger // value (eg int), it's not a good idea to try and split it // up into two shorts because the progress bar values are sent // independently, and unless you add synchronisation logic at the // receiving side, your int value will be wrong until the second short // arrives. Use a custom packet instead. @Override public void detectAndSendChanges() { super.detectAndSendChanges(); boolean allFieldsHaveChanged = false; boolean fieldHasChanged[] = new boolean[tileInventoryForge.getFieldCount()]; if (cachedFields == null) { cachedFields = new int[tileInventoryForge.getFieldCount()]; allFieldsHaveChanged = true; } for (int i = 0; i < cachedFields.length; ++i) { if (allFieldsHaveChanged || cachedFields[i] != tileInventoryForge.getField(i)) { cachedFields[i] = tileInventoryForge.getField(i); fieldHasChanged[i] = true; } } // go through the list of crafters (players using this container) and // update them if necessary for (int i = 0; i < this.crafters.size(); ++i) { ICrafting icrafting = (ICrafting) this.crafters.get(i); for (int fieldID = 0; fieldID < tileInventoryForge.getFieldCount(); ++fieldID) { if (fieldHasChanged[fieldID]) { // Note that although sendProgressBarUpdate takes 2 ints on // a server these are truncated to shorts icrafting.sendProgressBarUpdate(this, fieldID, cachedFields[fieldID]); } } } } // Called when a progress bar update is received from the server. The two // values (id and data) are the same two // values given to sendProgressBarUpdate. In this case we are using fields // so we just pass them to the tileEntity. @SideOnly(Side.CLIENT) @Override public void updateProgressBar(int id, int data) { tileInventoryForge.setField(id, data); } }