Jump to content

Leomelonseeds

Forge Modder
  • Posts

    407
  • Joined

  • Last visited

  • Days Won

    3

Everything posted by Leomelonseeds

  1. For the crashing, do I have to do a null check in the TESR?
  2. package com.leomelonseeds.moarstuff.guicontainer; import com.leomelonseeds.moarstuff.tileentity.Grill; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.inventory.Container; import net.minecraft.inventory.IContainerListener; import net.minecraft.inventory.IInventory; import net.minecraft.inventory.Slot; import net.minecraft.item.ItemStack; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; public class ContainerGrill extends Container { private Grill tileGrill; // 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 FUEL_SLOTS_COUNT = 4; public final int INPUT_SLOTS_COUNT = 5; public final int OUTPUT_SLOTS_COUNT = 5; public final int FURNACE_SLOTS_COUNT = FUEL_SLOTS_COUNT + INPUT_SLOTS_COUNT + OUTPUT_SLOTS_COUNT; // slot index is the unique index for all slots in this container i.e. 0 - 35 for invPlayer then 36 - 49 for tileGrill private final int VANILLA_FIRST_SLOT_INDEX = 0; private final int FIRST_FUEL_SLOT_INDEX = VANILLA_FIRST_SLOT_INDEX + VANILLA_SLOT_COUNT; private final int FIRST_INPUT_SLOT_INDEX = FIRST_FUEL_SLOT_INDEX + FUEL_SLOTS_COUNT; private final int FIRST_OUTPUT_SLOT_INDEX = FIRST_INPUT_SLOT_INDEX + INPUT_SLOTS_COUNT; // slot number is the slot number within each component; i.e. invPlayer slots 0 - 35, and tileGrill slots 0 - 14 private final int FIRST_FUEL_SLOT_NUMBER = 0; private final int FIRST_INPUT_SLOT_NUMBER = FIRST_FUEL_SLOT_NUMBER + FUEL_SLOTS_COUNT; private final int FIRST_OUTPUT_SLOT_NUMBER = FIRST_INPUT_SLOT_NUMBER + INPUT_SLOTS_COUNT; public ContainerGrill(InventoryPlayer invPlayer, Grill tileGrill) { this.tileGrill = tileGrill; final int SLOT_X_SPACING = 18; final int SLOT_Y_SPACING = 18; final int HOTBAR_XPOS = 8; final int HOTBAR_YPOS = 183; // Add the players hotbar to the gui - the [xpos, ypos] location of each item for (int x = 0; x < HOTBAR_SLOT_COUNT; x++) { int slotNumber = x; addSlotToContainer(new Slot(invPlayer, slotNumber, HOTBAR_XPOS + SLOT_X_SPACING * x, HOTBAR_YPOS)); } final int PLAYER_INVENTORY_XPOS = 8; final int PLAYER_INVENTORY_YPOS = 125; // 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)); } } final int FUEL_SLOTS_XPOS = 53; final int FUEL_SLOTS_YPOS = 96; // Add the tile fuel slots for (int x = 0; x < FUEL_SLOTS_COUNT; x++) { int slotNumber = x + FIRST_FUEL_SLOT_NUMBER; addSlotToContainer(new SlotFuel(tileGrill, slotNumber, FUEL_SLOTS_XPOS + SLOT_X_SPACING * x, FUEL_SLOTS_YPOS)); } final int INPUT_SLOTS_XPOS = 26; final int INPUT_SLOTS_YPOS = 24; // Add the tile input slots for (int y = 0; y < INPUT_SLOTS_COUNT; y++) { int slotNumber = y + FIRST_INPUT_SLOT_NUMBER; addSlotToContainer(new SlotSmeltableInput(tileGrill, slotNumber, INPUT_SLOTS_XPOS, INPUT_SLOTS_YPOS+ SLOT_Y_SPACING * y)); } final int OUTPUT_SLOTS_XPOS = 134; final int OUTPUT_SLOTS_YPOS = 24; // Add the tile output slots for (int y = 0; y < OUTPUT_SLOTS_COUNT; y++) { int slotNumber = y + FIRST_OUTPUT_SLOT_NUMBER; addSlotToContainer(new SlotOutput(tileGrill, slotNumber, OUTPUT_SLOTS_XPOS, OUTPUT_SLOTS_YPOS + SLOT_Y_SPACING * y)); } } // 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 tileGrill.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) { 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 (Grill.getSmeltingResultForItem(sourceStack) != null){ if (!mergeItemStack(sourceStack, FIRST_INPUT_SLOT_INDEX, FIRST_INPUT_SLOT_INDEX + INPUT_SLOTS_COUNT, false)){ return null; } } else if (Grill.getItemBurnTime(sourceStack) > 0) { if (!mergeItemStack(sourceStack, FIRST_FUEL_SLOT_INDEX, FIRST_FUEL_SLOT_INDEX + FUEL_SLOTS_COUNT, true)) { // Setting the boolean to true places the stack in the bottom slot first return null; } } else { return null; } } else if (sourceSlotIndex >= FIRST_FUEL_SLOT_INDEX && sourceSlotIndex < FIRST_FUEL_SLOT_INDEX + FURNACE_SLOTS_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[tileGrill.getFieldCount()]; if (cachedFields == null) { cachedFields = new int[tileGrill.getFieldCount()]; allFieldsHaveChanged = true; } for (int i = 0; i < cachedFields.length; ++i) { if (allFieldsHaveChanged || cachedFields[i] != tileGrill.getField(i)) { cachedFields[i] = tileGrill.getField(i); fieldHasChanged[i] = true; } } // go through the list of listeners (players using this container) and update them if necessary for (IContainerListener listener : this.listeners) { for (int fieldID = 0; fieldID < tileGrill.getFieldCount(); ++fieldID) { if (fieldHasChanged[fieldID]) { // Note that although sendProgressBarUpdate takes 2 ints on a server these are truncated to shorts listener.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) { tileGrill.setField(id, data); } // SlotFuel is a slot for fuel items public class SlotFuel extends Slot { public SlotFuel(IInventory inventoryIn, int index, int xPosition, int yPosition) { super(inventoryIn, index, xPosition, yPosition); } // if this function returns false, the player won't be able to insert the given item into this slot @Override public boolean isItemValid(ItemStack stack) { return Grill.isItemValidForFuelSlot(stack); } } // SlotSmeltableInput is a slot for input items public class SlotSmeltableInput extends Slot { public SlotSmeltableInput(IInventory inventoryIn, int index, int xPosition, int yPosition) { super(inventoryIn, index, xPosition, yPosition); } // if this function returns false, the player won't be able to insert the given item into this slot @Override public boolean isItemValid(ItemStack stack) { return Grill.isItemValidForInputSlot(stack); } } // SlotOutput is a slot that will not accept any items public class SlotOutput extends Slot { public SlotOutput(IInventory inventoryIn, int index, int xPosition, int yPosition) { super(inventoryIn, index, xPosition, yPosition); } // if this function returns false, the player won't be able to insert the given item into this slot @Override public boolean isItemValid(ItemStack stack) { return Grill.isItemValidForOutputSlot(stack); } } }
  3. Ok package com.leomelonseeds.moarstuff.tileentity; import java.util.Arrays; import javax.annotation.Nullable; import com.leomelonseeds.moarstuff.blocks.BlockGrill; import net.minecraft.block.BlockChest; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.SoundEvents; import net.minecraft.inventory.ContainerChest; import net.minecraft.inventory.IInventory; import net.minecraft.inventory.InventoryLargeChest; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.FurnaceRecipes; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagIntArray; import net.minecraft.nbt.NBTTagList; import net.minecraft.network.NetworkManager; import net.minecraft.network.play.server.SPacketUpdateTileEntity; import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityFurnace; import net.minecraft.util.ITickable; import net.minecraft.util.SoundCategory; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.MathHelper; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.TextComponentString; import net.minecraft.util.text.TextComponentTranslation; public class Grill extends TileEntity implements IInventory, ITickable { public boolean isBurning; public float lidAngle; /** The angle of the lid last tick */ public float prevLidAngle; public int numPlayersUsing; private int ticksSinceSync; public static final int FUEL_SLOTS_COUNT = 4; public static final int INPUT_SLOTS_COUNT = 5; public static final int OUTPUT_SLOTS_COUNT = 5; public static final int TOTAL_SLOTS_COUNT = FUEL_SLOTS_COUNT + INPUT_SLOTS_COUNT + OUTPUT_SLOTS_COUNT; public static final int FIRST_FUEL_SLOT = 0; public static final int FIRST_INPUT_SLOT = FIRST_FUEL_SLOT + FUEL_SLOTS_COUNT; public static final int FIRST_OUTPUT_SLOT = FIRST_INPUT_SLOT + INPUT_SLOTS_COUNT; private ItemStack[] itemStacks = new ItemStack[TOTAL_SLOTS_COUNT]; /** The number of burn ticks remaining on the current piece of fuel */ private int [] burnTimeRemaining = new int[FUEL_SLOTS_COUNT]; /** The initial fuel value of the currently burning fuel (in ticks of burn duration) */ private int [] burnTimeInitialValue = new int[FUEL_SLOTS_COUNT]; /**The number of ticks the current item has been cooking*/ private short cookTime; /**The number of ticks required to cook an item*/ private static final short COOK_TIME_FOR_COMPLETION = 200; // vanilla value is 200 = 10 seconds private int cachedNumberOfBurningSlots = -1; /** * Returns the amount of fuel remaining on the currently burning item in the given fuel slot. * @fuelSlot the number of the fuel slot (0..3) * @return fraction remaining, between 0 - 1 */ public double fractionOfFuelRemaining(int fuelSlot) { if (burnTimeInitialValue[fuelSlot] <= 0 ) return 0; double fraction = burnTimeRemaining[fuelSlot] / (double)burnTimeInitialValue[fuelSlot]; return MathHelper.clamp_double(fraction, 0.0, 1.0); } /** * return the remaining burn time of the fuel in the given slot * @param fuelSlot the number of the fuel slot (0..3) * @return seconds remaining */ public int secondsOfFuelRemaining(int fuelSlot) { if (burnTimeRemaining[fuelSlot] <= 0 ) return 0; return burnTimeRemaining[fuelSlot] / 20; // 20 ticks per second } /** * Get the number of slots which have fuel burning in them. * @return number of slots with burning fuel, 0 - FUEL_SLOTS_COUNT */ public int numberOfBurningFuelSlots() { int burningCount = 0; for (int burnTime : burnTimeRemaining) { if (burnTime > 0) ++burningCount; } return burningCount; } /** * Returns the amount of cook time completed on the currently cooking item. * @return fraction remaining, between 0 - 1 */ public double fractionOfCookTimeComplete() { double fraction = cookTime / (double)COOK_TIME_FOR_COMPLETION; return MathHelper.clamp_double(fraction, 0.0, 1.0); } // This method is called every tick to update the tile entity, i.e. // - see if the fuel has run out, and if so turn the furnace "off" and slowly uncook the current item (if any) // - see if any of the items have finished smelting // It runs both on the server and the client. @Override public void update() { // If there is nothing to smelt or there is no room in the output, reset cookTime and return if (canSmelt()) { this.isBurning = true; int numberOfFuelBurning = burnFuel(); // If fuel is available, keep cooking the item, otherwise start "uncooking" it at double speed if (numberOfFuelBurning > 0) { cookTime += numberOfFuelBurning; } else { cookTime -= 2; } if (cookTime < 0) cookTime = 0; // If cookTime has reached maxCookTime smelt the item and reset cookTime if (cookTime >= COOK_TIME_FOR_COMPLETION) { smeltItem(); cookTime = 0; } } else { cookTime = 0; this.isBurning = false; } int i = this.pos.getX(); int j = this.pos.getY(); int k = this.pos.getZ(); ++this.ticksSinceSync; if (!this.worldObj.isRemote && this.numPlayersUsing != 0 && (this.ticksSinceSync + i + j + k) % 200 == 0) { this.numPlayersUsing = 0; float f = 5.0F; for (EntityPlayer entityplayer : this.worldObj.getEntitiesWithinAABB(EntityPlayer.class, new AxisAlignedBB((double)((float)i - 5.0F), (double)((float)j - 5.0F), (double)((float)k - 5.0F), (double)((float)(i + 1) + 5.0F), (double)((float)(j + 1) + 5.0F), (double)((float)(k + 1) + 5.0F)))) { if (entityplayer.openContainer instanceof ContainerChest) { IInventory iinventory = ((ContainerChest)entityplayer.openContainer).getLowerChestInventory(); } } } this.prevLidAngle = this.lidAngle; float f1 = 0.1F; if (this.numPlayersUsing > 0 && this.lidAngle == 0.0F) { double d1 = (double)i + 0.5D; double d2 = (double)k + 0.5D; this.worldObj.playSound((EntityPlayer)null, d1, (double)j + 0.5D, d2, SoundEvents.BLOCK_CHEST_OPEN, SoundCategory.BLOCKS, 0.5F, this.worldObj.rand.nextFloat() * 0.1F + 0.9F); } if (this.numPlayersUsing == 0 && this.lidAngle > 0.0F || this.numPlayersUsing > 0 && this.lidAngle < 1.0F) { float f2 = this.lidAngle; if (this.numPlayersUsing > 0) { this.lidAngle += 0.1F; } else { this.lidAngle -= 0.1F; } if (this.lidAngle > 1.0F) { this.lidAngle = 1.0F; } float f3 = 0.5F; if (this.lidAngle < 0.5F && f2 >= 0.5F) { double d3 = (double)i + 0.5D; double d0 = (double)k + 0.5D; this.worldObj.playSound((EntityPlayer)null, d3, (double)j + 0.5D, d0, SoundEvents.BLOCK_CHEST_CLOSE, SoundCategory.BLOCKS, 0.5F, this.worldObj.rand.nextFloat() * 0.1F + 0.9F); } if (this.lidAngle < 0.0F) { this.lidAngle = 0.0F; } } } /** * for each fuel slot: decreases the burn time, checks if burnTimeRemaining = 0 and tries to consume a new piece of fuel if one is available * @return the number of fuel slots which are burning */ private int burnFuel() { int burningCount = 0; boolean inventoryChanged = false; // Iterate over all the fuel slots for (int i = 0; i < FUEL_SLOTS_COUNT; i++) { int fuelSlotNumber = i + FIRST_FUEL_SLOT; if (burnTimeRemaining[i] > 0) { --burnTimeRemaining[i]; ++burningCount; } if (burnTimeRemaining[i] == 0) { if (itemStacks[fuelSlotNumber] != null && getItemBurnTime(itemStacks[fuelSlotNumber]) > 0) { // If the stack in this slot is not null and is fuel, set burnTimeRemaining & burnTimeInitialValue to the // item's burn time and decrease the stack size burnTimeRemaining[i] = burnTimeInitialValue[i] = getItemBurnTime(itemStacks[fuelSlotNumber]); --itemStacks[fuelSlotNumber].stackSize; ++burningCount; inventoryChanged = true; // If the stack size now equals 0 set the slot contents to the items container item. This is for fuel // items such as lava buckets so that the bucket is not consumed. If the item dose not have // a container item getContainerItem returns null which sets the slot contents to null if (itemStacks[fuelSlotNumber].stackSize == 0) { itemStacks[fuelSlotNumber] = itemStacks[fuelSlotNumber].getItem().getContainerItem(itemStacks[fuelSlotNumber]); } } } } if (inventoryChanged) markDirty(); return burningCount; } /** * Check if any of the input items are smeltable and there is sufficient space in the output slots * @return true if smelting is possible */ private boolean canSmelt() {return smeltItem(false);} /** * Smelt an input item into an output slot, if possible */ private void smeltItem() {smeltItem(true);} /** * checks that there is an item to be smelted in one of the input slots and that there is room for the result in the output slots * If desired, performs the smelt * @param performSmelt if true, perform the smelt. if false, check whether smelting is possible, but don't change the inventory * @return false if no items can be smelted, true otherwise */ private boolean smeltItem(boolean performSmelt) { Integer firstSuitableInputSlot = null; Integer firstSuitableOutputSlot = null; ItemStack result = null; // finds the first input slot which is smeltable and whose result fits into an output slot (stacking if possible) for (int inputSlot = FIRST_INPUT_SLOT; inputSlot < FIRST_INPUT_SLOT + INPUT_SLOTS_COUNT; inputSlot++) { if (itemStacks[inputSlot] != null) { result = getSmeltingResultForItem(itemStacks[inputSlot]); if (result != null) { // find the first suitable output slot- either empty, or with identical item that has enough space for (int outputSlot = FIRST_OUTPUT_SLOT; outputSlot < FIRST_OUTPUT_SLOT + OUTPUT_SLOTS_COUNT; outputSlot++) { ItemStack outputStack = itemStacks[outputSlot]; if (outputStack == null) { firstSuitableInputSlot = inputSlot; firstSuitableOutputSlot = outputSlot; break; } if (outputStack.getItem() == result.getItem() && (!outputStack.getHasSubtypes() || outputStack.getMetadata() == outputStack.getMetadata()) && ItemStack.areItemStackTagsEqual(outputStack, result)) { int combinedSize = itemStacks[outputSlot].stackSize + result.stackSize; if (combinedSize <= getInventoryStackLimit() && combinedSize <= itemStacks[outputSlot].getMaxStackSize()) { firstSuitableInputSlot = inputSlot; firstSuitableOutputSlot = outputSlot; break; } } } if (firstSuitableInputSlot != null) break; } } } if (firstSuitableInputSlot == null) return false; if (!performSmelt) return true; // alter input and output itemStacks[firstSuitableInputSlot].stackSize--; if (itemStacks[firstSuitableInputSlot].stackSize <=0) itemStacks[firstSuitableInputSlot] = null; if (itemStacks[firstSuitableOutputSlot] == null) { itemStacks[firstSuitableOutputSlot] = result.copy(); // Use deep .copy() to avoid altering the recipe } else { itemStacks[firstSuitableOutputSlot].stackSize += result.stackSize; } markDirty(); return true; } // returns the smelting result for the given stack. Returns null if the given stack can not be smelted public static ItemStack getSmeltingResultForItem(ItemStack stack) { return FurnaceRecipes.instance().getSmeltingResult(stack); } // returns the number of ticks the given item will burn. Returns 0 if the given item is not a valid fuel public static short getItemBurnTime(ItemStack stack) { int burntime = TileEntityFurnace.getItemBurnTime(stack); // just use the vanilla values return (short)MathHelper.clamp_int(burntime, 0, Short.MAX_VALUE); } // Gets the number of slots in the inventory @Override public int getSizeInventory() { return itemStacks.length; } // Gets the stack in the given slot @Override public ItemStack getStackInSlot(int i) { return itemStacks[i]; } /** * Removes some of the units from itemstack in the given slot, and returns as a separate itemstack * @param slotIndex the slot number to remove the items from * @param count the number of units to remove * @return a new itemstack containing the units removed from the slot */ @Override public ItemStack decrStackSize(int slotIndex, int count) { ItemStack itemStackInSlot = getStackInSlot(slotIndex); if (itemStackInSlot == null) return null; ItemStack itemStackRemoved; if (itemStackInSlot.stackSize <= count) { itemStackRemoved = itemStackInSlot; setInventorySlotContents(slotIndex, null); } else { itemStackRemoved = itemStackInSlot.splitStack(count); if (itemStackInSlot.stackSize == 0) { setInventorySlotContents(slotIndex, null); } } markDirty(); return itemStackRemoved; } // overwrites the stack in the given slotIndex with the given stack @Override public void setInventorySlotContents(int slotIndex, ItemStack itemstack) { itemStacks[slotIndex] = itemstack; if (itemstack != null && itemstack.stackSize > getInventoryStackLimit()) { itemstack.stackSize = getInventoryStackLimit(); } markDirty(); } // This is the maximum number if items allowed in each slot // This only affects things such as hoppers trying to insert items you need to use the container to enforce this for players // inserting items via the gui @Override public int getInventoryStackLimit() { return 64; } // Return true if the given player is able to use this block. In this case it checks that // 1) the world tileentity hasn't been replaced in the meantime, and // 2) the player isn't too far away from the centre of the block @Override public boolean isUseableByPlayer(EntityPlayer player) { if (this.worldObj.getTileEntity(this.pos) != this) return false; final double X_CENTRE_OFFSET = 0.5; final double Y_CENTRE_OFFSET = 0.5; final double Z_CENTRE_OFFSET = 0.5; final double MAXIMUM_DISTANCE_SQ = 8.0 * 8.0; return player.getDistanceSq(pos.getX() + X_CENTRE_OFFSET, pos.getY() + Y_CENTRE_OFFSET, pos.getZ() + Z_CENTRE_OFFSET) < MAXIMUM_DISTANCE_SQ; } // Return true if the given stack is allowed to be inserted in the given slot // Unlike the vanilla furnace, we allow anything to be placed in the fuel slots static public boolean isItemValidForFuelSlot(ItemStack itemStack) { return true; } // Return true if the given stack is allowed to be inserted in the given slot // Unlike the vanilla furnace, we allow anything to be placed in the fuel slots static public boolean isItemValidForInputSlot(ItemStack itemStack) { return true; } // Return true if the given stack is allowed to be inserted in the given slot // Unlike the vanilla furnace, we allow anything to be placed in the fuel slots static public boolean isItemValidForOutputSlot(ItemStack itemStack) { return false; } //------------------------------ // This is where you save any data that you don't want to lose when the tile entity unloads // In this case, it saves the state of the furnace (burn time etc) and the itemstacks stored in the fuel, input, and output slots @Override public NBTTagCompound writeToNBT(NBTTagCompound parentNBTTagCompound) { super.writeToNBT(parentNBTTagCompound); // The super call is required to save and load the tiles location // // Save the stored item stacks // to use an analogy with Java, this code generates an array of hashmaps // The itemStack in each slot is converted to an NBTTagCompound, which is effectively a hashmap of key->value pairs such // as slot=1, id=2353, count=1, etc // Each of these NBTTagCompound are then inserted into NBTTagList, which is similar to an array. NBTTagList dataForAllSlots = new NBTTagList(); for (int i = 0; i < this.itemStacks.length; ++i) { if (this.itemStacks[i] != null) { NBTTagCompound dataForThisSlot = new NBTTagCompound(); dataForThisSlot.setByte("Slot", (byte) i); this.itemStacks[i].writeToNBT(dataForThisSlot); dataForAllSlots.appendTag(dataForThisSlot); } } // the array of hashmaps is then inserted into the parent hashmap for the container parentNBTTagCompound.setTag("Items", dataForAllSlots); // Save everything else parentNBTTagCompound.setShort("CookTime", cookTime); parentNBTTagCompound.setTag("burnTimeRemaining", new NBTTagIntArray(burnTimeRemaining)); parentNBTTagCompound.setTag("burnTimeInitial", new NBTTagIntArray(burnTimeInitialValue)); return parentNBTTagCompound; } // This is where you load the data that you saved in writeToNBT @Override public void readFromNBT(NBTTagCompound nbtTagCompound) { super.readFromNBT(nbtTagCompound); // The super call is required to save and load the tiles location final byte NBT_TYPE_COMPOUND = 10; // See NBTBase.createNewByType() for a listing NBTTagList dataForAllSlots = nbtTagCompound.getTagList("Items", NBT_TYPE_COMPOUND); Arrays.fill(itemStacks, null); // set all slots to empty for (int i = 0; i < dataForAllSlots.tagCount(); ++i) { NBTTagCompound dataForOneSlot = dataForAllSlots.getCompoundTagAt(i); byte slotNumber = dataForOneSlot.getByte("Slot"); if (slotNumber >= 0 && slotNumber < this.itemStacks.length) { this.itemStacks[slotNumber] = ItemStack.loadItemStackFromNBT(dataForOneSlot); } } // Load everything else. Trim the arrays (or pad with 0) to make sure they have the correct number of elements cookTime = nbtTagCompound.getShort("CookTime"); burnTimeRemaining = Arrays.copyOf(nbtTagCompound.getIntArray("burnTimeRemaining"), FUEL_SLOTS_COUNT); burnTimeInitialValue = Arrays.copyOf(nbtTagCompound.getIntArray("burnTimeInitial"), FUEL_SLOTS_COUNT); cachedNumberOfBurningSlots = -1; } // // When the world loads from disk, the server needs to send the TileEntity information to the client // // it uses getUpdatePacket(), getUpdateTag(), onDataPacket(), and handleUpdateTag() to do this @Override @Nullable public SPacketUpdateTileEntity getUpdatePacket() { NBTTagCompound updateTagDescribingTileEntityState = getUpdateTag(); final int METADATA = 0; return new SPacketUpdateTileEntity(this.pos, METADATA, updateTagDescribingTileEntityState); } @Override public void onDataPacket(NetworkManager net, SPacketUpdateTileEntity pkt) { NBTTagCompound updateTagDescribingTileEntityState = pkt.getNbtCompound(); handleUpdateTag(updateTagDescribingTileEntityState); } /* Creates a tag containing the TileEntity information, used by vanilla to transmit from server to client Warning - although our getUpdatePacket() uses this method, vanilla also calls it directly, so don't remove it. */ @Override public NBTTagCompound getUpdateTag() { NBTTagCompound nbtTagCompound = new NBTTagCompound(); writeToNBT(nbtTagCompound); return nbtTagCompound; } /* Populates this TileEntity with information from the tag, used by vanilla to transmit from server to client Warning - although our onDataPacket() uses this method, vanilla also calls it directly, so don't remove it. */ @Override public void handleUpdateTag(NBTTagCompound tag) { this.readFromNBT(tag); } //------------------------ // set all slots to empty @Override public void clear() { Arrays.fill(itemStacks, null); } // will add a key for this container to the lang file so we can name it in the GUI @Override public String getName() { return "container.grill.name"; } @Override public boolean hasCustomName() { return false; } // standard code to look up what the human-readable name is @Nullable @Override public ITextComponent getDisplayName() { return this.hasCustomName() ? new TextComponentString(this.getName()) : new TextComponentTranslation(this.getName()); } // Fields are used to send non-inventory information from the server to interested clients // The container code caches the fields and sends the client any fields which have changed. // The field ID is limited to byte, and the field value is limited to short. (if you use more than this, they get cast down // in the network packets) // If you need more than this, or shorts are too small, use a custom packet in your container instead. private static final byte COOK_FIELD_ID = 0; private static final byte FIRST_BURN_TIME_REMAINING_FIELD_ID = 1; private static final byte FIRST_BURN_TIME_INITIAL_FIELD_ID = FIRST_BURN_TIME_REMAINING_FIELD_ID + (byte)FUEL_SLOTS_COUNT; private static final byte NUMBER_OF_FIELDS = FIRST_BURN_TIME_INITIAL_FIELD_ID + (byte)FUEL_SLOTS_COUNT; @Override public int getField(int id) { if (id == COOK_FIELD_ID) return cookTime; if (id >= FIRST_BURN_TIME_REMAINING_FIELD_ID && id < FIRST_BURN_TIME_REMAINING_FIELD_ID + FUEL_SLOTS_COUNT) { return burnTimeRemaining[id - FIRST_BURN_TIME_REMAINING_FIELD_ID]; } if (id >= FIRST_BURN_TIME_INITIAL_FIELD_ID && id < FIRST_BURN_TIME_INITIAL_FIELD_ID + FUEL_SLOTS_COUNT) { return burnTimeInitialValue[id - FIRST_BURN_TIME_INITIAL_FIELD_ID]; } System.err.println("Invalid field ID in TileInventorySmelting.getField:" + id); return 0; } @Override public void setField(int id, int value) { if (id == COOK_FIELD_ID) { cookTime = (short)value; } else if (id >= FIRST_BURN_TIME_REMAINING_FIELD_ID && id < FIRST_BURN_TIME_REMAINING_FIELD_ID + FUEL_SLOTS_COUNT) { burnTimeRemaining[id - FIRST_BURN_TIME_REMAINING_FIELD_ID] = value; } else if (id >= FIRST_BURN_TIME_INITIAL_FIELD_ID && id < FIRST_BURN_TIME_INITIAL_FIELD_ID + FUEL_SLOTS_COUNT) { burnTimeInitialValue[id - FIRST_BURN_TIME_INITIAL_FIELD_ID] = value; } else { System.err.println("Invalid field ID in TileInventorySmelting.setField:" + id); } } @Override public int getFieldCount() { return NUMBER_OF_FIELDS; } // ----------------------------------------------------------------------------------------------------------- // The following methods are not needed for this example but are part of IInventory so they must be implemented // Unused unless your container specifically uses it. // Return true if the given stack is allowed to go in the given slot @Override public boolean isItemValidForSlot(int slotIndex, ItemStack itemstack) { return false; } /** * This method removes the entire contents of the given slot and returns it. * Used by containers such as crafting tables which return any items in their slots when you close the GUI * @param slotIndex * @return */ @Override public ItemStack removeStackFromSlot(int slotIndex) { ItemStack itemStack = getStackInSlot(slotIndex); if (itemStack != null) setInventorySlotContents(slotIndex, null); return itemStack; } public boolean receiveClientEvent(int id, int type) { if (id == 1) { this.numPlayersUsing = type; return true; } else { return super.receiveClientEvent(id, type); } } public void openInventory(EntityPlayer player) { if (!player.isSpectator()) { if (this.numPlayersUsing < 0) { this.numPlayersUsing = 0; } ++this.numPlayersUsing; this.worldObj.addBlockEvent(this.pos, this.getBlockType(), 1, this.numPlayersUsing); this.worldObj.notifyNeighborsOfStateChange(this.pos, this.getBlockType()); this.worldObj.notifyNeighborsOfStateChange(this.pos.down(), this.getBlockType()); } } public void closeInventory(EntityPlayer player) { if (!player.isSpectator() && this.getBlockType() instanceof BlockChest) { --this.numPlayersUsing; this.worldObj.addBlockEvent(this.pos, this.getBlockType(), 1, this.numPlayersUsing); this.worldObj.notifyNeighborsOfStateChange(this.pos, this.getBlockType()); this.worldObj.notifyNeighborsOfStateChange(this.pos.down(), this.getBlockType()); } } } Its very long
  4. OK ForgeHooksClient.registerTESRItemStack brings a crash: TESR: package com.leomelonseeds.moarstuff.client.render.blocks; import com.leomelonseeds.moarstuff.blocks.BlockGrill; import com.leomelonseeds.moarstuff.tileentity.Grill; import net.minecraft.block.Block; import net.minecraft.client.model.ModelChest; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityChest; import net.minecraft.util.EnumFacing; import net.minecraft.util.ResourceLocation; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; @SideOnly(Side.CLIENT) public class TileGrillRenderer extends TileEntitySpecialRenderer<Grill> { private static final ResourceLocation TEXTURE_BURNING = new ResourceLocation("moarstuff:textures/entity/grill/grill_on.png"); private static final ResourceLocation TEXTURE_NORMAL = new ResourceLocation("moarstuff:textures/entity/grill/grill_off.png"); private final ModelChest simpleChest = new ModelChest(); public TileGrillRenderer(){ } @Override public void renderTileEntityAt(Grill te, double x, double y, double z, float partialTicks, int destroyStage) { GlStateManager.depthFunc(515); GlStateManager.depthMask(true); GlStateManager.scale(1.1, 1.1, 1.1); EnumFacing facing = te.getWorld().getBlockState(te.getPos()).getValue(BlockGrill.FACING); int i; if (te.hasWorldObj()) { Block block = te.getBlockType(); i = te.getBlockMetadata(); } else { i = 0; } ModelChest modelchest = this.simpleChest; if (destroyStage >= 0) { this.bindTexture(DESTROY_STAGES[destroyStage]); GlStateManager.matrixMode(5890); GlStateManager.pushMatrix(); GlStateManager.scale(4.0F, 4.0F, 1.0F); GlStateManager.translate(0.0625F, 0.0625F, 0.0625F); GlStateManager.matrixMode(5888); } else if(te.isBurning == true){ this.bindTexture(TEXTURE_BURNING); } else { this.bindTexture(TEXTURE_NORMAL); } GlStateManager.pushMatrix(); GlStateManager.enableRescaleNormal(); if (destroyStage < 0) { GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); } GlStateManager.translate((float)x, (float)y + 1.0F, (float)z + 1.0F); GlStateManager.scale(1.0F, -1.0F, -1.0F); GlStateManager.translate(0.5F, 0.5F, 0.5F); int j = 0; if (i == 2) { j = 180; } if (i == 3) { j = 0; } if (i == 4) { j = 90; } if (i == 5) { j = -90; } GlStateManager.rotate((float)j, 0.0F, 1.0F, 0.0F); GlStateManager.translate(-0.5F, -0.5F, -0.5F); float f = te.prevLidAngle + (te.lidAngle - te.prevLidAngle) * partialTicks; f = 1.0F - f; f = 1.0F - f * f * f; modelchest.chestLid.rotateAngleX = -(f * ((float)Math.PI / 2F)); modelchest.renderAll(); GlStateManager.disableRescaleNormal(); GlStateManager.popMatrix(); GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); if (destroyStage >= 0) { GlStateManager.matrixMode(5890); GlStateManager.popMatrix(); GlStateManager.matrixMode(5888); } } } The lid still doesnt open... why...
  5. Can I still see who is viewing a certian topic? For example I want to see how many members and guests are viewing a topic.
  6. ForgeHooksClient.registerTESRItemStack is deprecated. should I still use it?
  7. Also, which GlStateManager.scale scales it so that it is a bit smaller than normal blocks?
  8. Ok I fixed it by importing more methods from TileEntityChest, but it still doesn't open... how do you not create an empty instance of Grill? package com.leomelonseeds.moarstuff.client.render.blocks; import com.leomelonseeds.moarstuff.blocks.BlockGrill; import com.leomelonseeds.moarstuff.tileentity.Grill; import net.minecraft.block.Block; import net.minecraft.client.model.ModelChest; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityChest; import net.minecraft.util.ResourceLocation; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; @SideOnly(Side.CLIENT) public class TileGrillRenderer extends TileEntitySpecialRenderer<Grill> { private static final ResourceLocation TEXTURE_BURNING = new ResourceLocation("moarstuff:textures/entity/grill/grill_on.png"); private static final ResourceLocation TEXTURE_NORMAL = new ResourceLocation("moarstuff:textures/entity/grill/grill_off.png"); private final ModelChest simpleChest = new ModelChest(); Grill grill = new Grill(); public TileGrillRenderer(){ } @Override public void renderTileEntityAt(Grill te, double x, double y, double z, float partialTicks, int destroyStage) { GlStateManager.depthFunc(515); GlStateManager.depthMask(true); GlStateManager.scale(1.1, 1.1, 1.1); int i; if (te.hasWorldObj()) { Block block = te.getBlockType(); i = te.getBlockMetadata(); } else { i = 0; } ModelChest modelchest = this.simpleChest; if (destroyStage >= 0) { this.bindTexture(DESTROY_STAGES[destroyStage]); GlStateManager.matrixMode(5890); GlStateManager.pushMatrix(); GlStateManager.scale(4.0F, 4.0F, 1.0F); GlStateManager.translate(0.0625F, 0.0625F, 0.0625F); GlStateManager.matrixMode(5888); } else if(grill.isBurning == true){ this.bindTexture(TEXTURE_BURNING); } else { this.bindTexture(TEXTURE_NORMAL); } GlStateManager.pushMatrix(); GlStateManager.enableRescaleNormal(); if (destroyStage < 0) { GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); } GlStateManager.translate((float)x, (float)y + 1.0F, (float)z + 1.0F); GlStateManager.scale(1.0F, -1.0F, -1.0F); GlStateManager.translate(0.5F, 0.5F, 0.5F); int j = 0; if (i == 2) { j = 180; } if (i == 3) { j = 0; } if (i == 4) { j = 90; } if (i == 5) { j = -90; } GlStateManager.rotate((float)j, 0.0F, 1.0F, 0.0F); GlStateManager.translate(-0.5F, -0.5F, -0.5F); float f = te.prevLidAngle + (te.lidAngle - te.prevLidAngle) * partialTicks; f = 1.0F - f; f = 1.0F - f * f * f; modelchest.chestLid.rotateAngleX = -(f * ((float)Math.PI / 2F)); modelchest.renderAll(); GlStateManager.disableRescaleNormal(); GlStateManager.popMatrix(); GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); if (destroyStage >= 0) { GlStateManager.matrixMode(5890); GlStateManager.popMatrix(); GlStateManager.matrixMode(5888); } } }
  9. Bump. By the way thats not a crash, its just what happens. Grill code: package com.leomelonseeds.moarstuff.tileentity; import java.util.Arrays; import javax.annotation.Nullable; import com.leomelonseeds.moarstuff.blocks.BlockGrill; import net.minecraft.block.BlockChest; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.SoundEvents; import net.minecraft.inventory.IInventory; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.FurnaceRecipes; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagIntArray; import net.minecraft.nbt.NBTTagList; import net.minecraft.network.NetworkManager; import net.minecraft.network.play.server.SPacketUpdateTileEntity; import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityFurnace; import net.minecraft.util.ITickable; import net.minecraft.util.SoundCategory; import net.minecraft.util.math.MathHelper; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.TextComponentString; import net.minecraft.util.text.TextComponentTranslation; public class Grill extends TileEntity implements IInventory, ITickable { public boolean isBurning; public float lidAngle; /** The angle of the lid last tick */ public float prevLidAngle; public int numPlayersUsing; public static final int FUEL_SLOTS_COUNT = 4; public static final int INPUT_SLOTS_COUNT = 5; public static final int OUTPUT_SLOTS_COUNT = 5; public static final int TOTAL_SLOTS_COUNT = FUEL_SLOTS_COUNT + INPUT_SLOTS_COUNT + OUTPUT_SLOTS_COUNT; public static final int FIRST_FUEL_SLOT = 0; public static final int FIRST_INPUT_SLOT = FIRST_FUEL_SLOT + FUEL_SLOTS_COUNT; public static final int FIRST_OUTPUT_SLOT = FIRST_INPUT_SLOT + INPUT_SLOTS_COUNT; private ItemStack[] itemStacks = new ItemStack[TOTAL_SLOTS_COUNT]; /** The number of burn ticks remaining on the current piece of fuel */ private int [] burnTimeRemaining = new int[FUEL_SLOTS_COUNT]; /** The initial fuel value of the currently burning fuel (in ticks of burn duration) */ private int [] burnTimeInitialValue = new int[FUEL_SLOTS_COUNT]; /**The number of ticks the current item has been cooking*/ private short cookTime; /**The number of ticks required to cook an item*/ private static final short COOK_TIME_FOR_COMPLETION = 200; // vanilla value is 200 = 10 seconds private int cachedNumberOfBurningSlots = -1; /** * Returns the amount of fuel remaining on the currently burning item in the given fuel slot. * @fuelSlot the number of the fuel slot (0..3) * @return fraction remaining, between 0 - 1 */ public double fractionOfFuelRemaining(int fuelSlot) { if (burnTimeInitialValue[fuelSlot] <= 0 ) return 0; double fraction = burnTimeRemaining[fuelSlot] / (double)burnTimeInitialValue[fuelSlot]; return MathHelper.clamp_double(fraction, 0.0, 1.0); } /** * return the remaining burn time of the fuel in the given slot * @param fuelSlot the number of the fuel slot (0..3) * @return seconds remaining */ public int secondsOfFuelRemaining(int fuelSlot) { if (burnTimeRemaining[fuelSlot] <= 0 ) return 0; return burnTimeRemaining[fuelSlot] / 20; // 20 ticks per second } /** * Get the number of slots which have fuel burning in them. * @return number of slots with burning fuel, 0 - FUEL_SLOTS_COUNT */ public int numberOfBurningFuelSlots() { int burningCount = 0; for (int burnTime : burnTimeRemaining) { if (burnTime > 0) ++burningCount; } return burningCount; } /** * Returns the amount of cook time completed on the currently cooking item. * @return fraction remaining, between 0 - 1 */ public double fractionOfCookTimeComplete() { double fraction = cookTime / (double)COOK_TIME_FOR_COMPLETION; return MathHelper.clamp_double(fraction, 0.0, 1.0); } // This method is called every tick to update the tile entity, i.e. // - see if the fuel has run out, and if so turn the furnace "off" and slowly uncook the current item (if any) // - see if any of the items have finished smelting // It runs both on the server and the client. @Override public void update() { // If there is nothing to smelt or there is no room in the output, reset cookTime and return if (canSmelt()) { this.isBurning = true; int numberOfFuelBurning = burnFuel(); // If fuel is available, keep cooking the item, otherwise start "uncooking" it at double speed if (numberOfFuelBurning > 0) { cookTime += numberOfFuelBurning; } else { cookTime -= 2; } if (cookTime < 0) cookTime = 0; // If cookTime has reached maxCookTime smelt the item and reset cookTime if (cookTime >= COOK_TIME_FOR_COMPLETION) { smeltItem(); cookTime = 0; } } else { cookTime = 0; this.isBurning = false; } int i = this.pos.getX(); int j = this.pos.getY(); int k = this.pos.getZ(); this.prevLidAngle = this.lidAngle; float f1 = 0.1F; if (this.numPlayersUsing > 0 && this.lidAngle == 0.0F) { double d1 = (double)i + 0.5D; double d2 = (double)k + 0.5D; this.worldObj.playSound((EntityPlayer)null, d1, (double)j + 0.5D, d2, SoundEvents.BLOCK_CHEST_OPEN, SoundCategory.BLOCKS, 0.5F, this.worldObj.rand.nextFloat() * 0.1F + 0.9F); } if (this.numPlayersUsing == 0 && this.lidAngle > 0.0F || this.numPlayersUsing > 0 && this.lidAngle < 1.0F) { float f2 = this.lidAngle; if (this.numPlayersUsing > 0) { this.lidAngle += 0.1F; } else { this.lidAngle -= 0.1F; } if (this.lidAngle > 1.0F) { this.lidAngle = 1.0F; } float f3 = 0.5F; if (this.lidAngle < 0.5F && f2 >= 0.5F) { double d3 = (double)i + 0.5D; double d0 = (double)k + 0.5D; this.worldObj.playSound((EntityPlayer)null, d3, (double)j + 0.5D, d0, SoundEvents.BLOCK_CHEST_CLOSE, SoundCategory.BLOCKS, 0.5F, this.worldObj.rand.nextFloat() * 0.1F + 0.9F); } if (this.lidAngle < 0.0F) { this.lidAngle = 0.0F; } } } /** * for each fuel slot: decreases the burn time, checks if burnTimeRemaining = 0 and tries to consume a new piece of fuel if one is available * @return the number of fuel slots which are burning */ private int burnFuel() { int burningCount = 0; boolean inventoryChanged = false; // Iterate over all the fuel slots for (int i = 0; i < FUEL_SLOTS_COUNT; i++) { int fuelSlotNumber = i + FIRST_FUEL_SLOT; if (burnTimeRemaining[i] > 0) { --burnTimeRemaining[i]; ++burningCount; } if (burnTimeRemaining[i] == 0) { if (itemStacks[fuelSlotNumber] != null && getItemBurnTime(itemStacks[fuelSlotNumber]) > 0) { // If the stack in this slot is not null and is fuel, set burnTimeRemaining & burnTimeInitialValue to the // item's burn time and decrease the stack size burnTimeRemaining[i] = burnTimeInitialValue[i] = getItemBurnTime(itemStacks[fuelSlotNumber]); --itemStacks[fuelSlotNumber].stackSize; ++burningCount; inventoryChanged = true; // If the stack size now equals 0 set the slot contents to the items container item. This is for fuel // items such as lava buckets so that the bucket is not consumed. If the item dose not have // a container item getContainerItem returns null which sets the slot contents to null if (itemStacks[fuelSlotNumber].stackSize == 0) { itemStacks[fuelSlotNumber] = itemStacks[fuelSlotNumber].getItem().getContainerItem(itemStacks[fuelSlotNumber]); } } } } if (inventoryChanged) markDirty(); return burningCount; } /** * Check if any of the input items are smeltable and there is sufficient space in the output slots * @return true if smelting is possible */ private boolean canSmelt() {return smeltItem(false);} /** * Smelt an input item into an output slot, if possible */ private void smeltItem() {smeltItem(true);} /** * checks that there is an item to be smelted in one of the input slots and that there is room for the result in the output slots * If desired, performs the smelt * @param performSmelt if true, perform the smelt. if false, check whether smelting is possible, but don't change the inventory * @return false if no items can be smelted, true otherwise */ private boolean smeltItem(boolean performSmelt) { Integer firstSuitableInputSlot = null; Integer firstSuitableOutputSlot = null; ItemStack result = null; // finds the first input slot which is smeltable and whose result fits into an output slot (stacking if possible) for (int inputSlot = FIRST_INPUT_SLOT; inputSlot < FIRST_INPUT_SLOT + INPUT_SLOTS_COUNT; inputSlot++) { if (itemStacks[inputSlot] != null) { result = getSmeltingResultForItem(itemStacks[inputSlot]); if (result != null) { // find the first suitable output slot- either empty, or with identical item that has enough space for (int outputSlot = FIRST_OUTPUT_SLOT; outputSlot < FIRST_OUTPUT_SLOT + OUTPUT_SLOTS_COUNT; outputSlot++) { ItemStack outputStack = itemStacks[outputSlot]; if (outputStack == null) { firstSuitableInputSlot = inputSlot; firstSuitableOutputSlot = outputSlot; break; } if (outputStack.getItem() == result.getItem() && (!outputStack.getHasSubtypes() || outputStack.getMetadata() == outputStack.getMetadata()) && ItemStack.areItemStackTagsEqual(outputStack, result)) { int combinedSize = itemStacks[outputSlot].stackSize + result.stackSize; if (combinedSize <= getInventoryStackLimit() && combinedSize <= itemStacks[outputSlot].getMaxStackSize()) { firstSuitableInputSlot = inputSlot; firstSuitableOutputSlot = outputSlot; break; } } } if (firstSuitableInputSlot != null) break; } } } if (firstSuitableInputSlot == null) return false; if (!performSmelt) return true; // alter input and output itemStacks[firstSuitableInputSlot].stackSize--; if (itemStacks[firstSuitableInputSlot].stackSize <=0) itemStacks[firstSuitableInputSlot] = null; if (itemStacks[firstSuitableOutputSlot] == null) { itemStacks[firstSuitableOutputSlot] = result.copy(); // Use deep .copy() to avoid altering the recipe } else { itemStacks[firstSuitableOutputSlot].stackSize += result.stackSize; } markDirty(); return true; } // returns the smelting result for the given stack. Returns null if the given stack can not be smelted public static ItemStack getSmeltingResultForItem(ItemStack stack) { return FurnaceRecipes.instance().getSmeltingResult(stack); } // returns the number of ticks the given item will burn. Returns 0 if the given item is not a valid fuel public static short getItemBurnTime(ItemStack stack) { int burntime = TileEntityFurnace.getItemBurnTime(stack); // just use the vanilla values return (short)MathHelper.clamp_int(burntime, 0, Short.MAX_VALUE); } // Gets the number of slots in the inventory @Override public int getSizeInventory() { return itemStacks.length; } // Gets the stack in the given slot @Override public ItemStack getStackInSlot(int i) { return itemStacks[i]; } /** * Removes some of the units from itemstack in the given slot, and returns as a separate itemstack * @param slotIndex the slot number to remove the items from * @param count the number of units to remove * @return a new itemstack containing the units removed from the slot */ @Override public ItemStack decrStackSize(int slotIndex, int count) { ItemStack itemStackInSlot = getStackInSlot(slotIndex); if (itemStackInSlot == null) return null; ItemStack itemStackRemoved; if (itemStackInSlot.stackSize <= count) { itemStackRemoved = itemStackInSlot; setInventorySlotContents(slotIndex, null); } else { itemStackRemoved = itemStackInSlot.splitStack(count); if (itemStackInSlot.stackSize == 0) { setInventorySlotContents(slotIndex, null); } } markDirty(); return itemStackRemoved; } // overwrites the stack in the given slotIndex with the given stack @Override public void setInventorySlotContents(int slotIndex, ItemStack itemstack) { itemStacks[slotIndex] = itemstack; if (itemstack != null && itemstack.stackSize > getInventoryStackLimit()) { itemstack.stackSize = getInventoryStackLimit(); } markDirty(); } // This is the maximum number if items allowed in each slot // This only affects things such as hoppers trying to insert items you need to use the container to enforce this for players // inserting items via the gui @Override public int getInventoryStackLimit() { return 64; } // Return true if the given player is able to use this block. In this case it checks that // 1) the world tileentity hasn't been replaced in the meantime, and // 2) the player isn't too far away from the centre of the block @Override public boolean isUseableByPlayer(EntityPlayer player) { if (this.worldObj.getTileEntity(this.pos) != this) return false; final double X_CENTRE_OFFSET = 0.5; final double Y_CENTRE_OFFSET = 0.5; final double Z_CENTRE_OFFSET = 0.5; final double MAXIMUM_DISTANCE_SQ = 8.0 * 8.0; return player.getDistanceSq(pos.getX() + X_CENTRE_OFFSET, pos.getY() + Y_CENTRE_OFFSET, pos.getZ() + Z_CENTRE_OFFSET) < MAXIMUM_DISTANCE_SQ; } // Return true if the given stack is allowed to be inserted in the given slot // Unlike the vanilla furnace, we allow anything to be placed in the fuel slots static public boolean isItemValidForFuelSlot(ItemStack itemStack) { return true; } // Return true if the given stack is allowed to be inserted in the given slot // Unlike the vanilla furnace, we allow anything to be placed in the fuel slots static public boolean isItemValidForInputSlot(ItemStack itemStack) { return true; } // Return true if the given stack is allowed to be inserted in the given slot // Unlike the vanilla furnace, we allow anything to be placed in the fuel slots static public boolean isItemValidForOutputSlot(ItemStack itemStack) { return false; } //------------------------------ // This is where you save any data that you don't want to lose when the tile entity unloads // In this case, it saves the state of the furnace (burn time etc) and the itemstacks stored in the fuel, input, and output slots @Override public NBTTagCompound writeToNBT(NBTTagCompound parentNBTTagCompound) { super.writeToNBT(parentNBTTagCompound); // The super call is required to save and load the tiles location // // Save the stored item stacks // to use an analogy with Java, this code generates an array of hashmaps // The itemStack in each slot is converted to an NBTTagCompound, which is effectively a hashmap of key->value pairs such // as slot=1, id=2353, count=1, etc // Each of these NBTTagCompound are then inserted into NBTTagList, which is similar to an array. NBTTagList dataForAllSlots = new NBTTagList(); for (int i = 0; i < this.itemStacks.length; ++i) { if (this.itemStacks[i] != null) { NBTTagCompound dataForThisSlot = new NBTTagCompound(); dataForThisSlot.setByte("Slot", (byte) i); this.itemStacks[i].writeToNBT(dataForThisSlot); dataForAllSlots.appendTag(dataForThisSlot); } } // the array of hashmaps is then inserted into the parent hashmap for the container parentNBTTagCompound.setTag("Items", dataForAllSlots); // Save everything else parentNBTTagCompound.setShort("CookTime", cookTime); parentNBTTagCompound.setTag("burnTimeRemaining", new NBTTagIntArray(burnTimeRemaining)); parentNBTTagCompound.setTag("burnTimeInitial", new NBTTagIntArray(burnTimeInitialValue)); return parentNBTTagCompound; } // This is where you load the data that you saved in writeToNBT @Override public void readFromNBT(NBTTagCompound nbtTagCompound) { super.readFromNBT(nbtTagCompound); // The super call is required to save and load the tiles location final byte NBT_TYPE_COMPOUND = 10; // See NBTBase.createNewByType() for a listing NBTTagList dataForAllSlots = nbtTagCompound.getTagList("Items", NBT_TYPE_COMPOUND); Arrays.fill(itemStacks, null); // set all slots to empty for (int i = 0; i < dataForAllSlots.tagCount(); ++i) { NBTTagCompound dataForOneSlot = dataForAllSlots.getCompoundTagAt(i); byte slotNumber = dataForOneSlot.getByte("Slot"); if (slotNumber >= 0 && slotNumber < this.itemStacks.length) { this.itemStacks[slotNumber] = ItemStack.loadItemStackFromNBT(dataForOneSlot); } } // Load everything else. Trim the arrays (or pad with 0) to make sure they have the correct number of elements cookTime = nbtTagCompound.getShort("CookTime"); burnTimeRemaining = Arrays.copyOf(nbtTagCompound.getIntArray("burnTimeRemaining"), FUEL_SLOTS_COUNT); burnTimeInitialValue = Arrays.copyOf(nbtTagCompound.getIntArray("burnTimeInitial"), FUEL_SLOTS_COUNT); cachedNumberOfBurningSlots = -1; } // // When the world loads from disk, the server needs to send the TileEntity information to the client // // it uses getUpdatePacket(), getUpdateTag(), onDataPacket(), and handleUpdateTag() to do this @Override @Nullable public SPacketUpdateTileEntity getUpdatePacket() { NBTTagCompound updateTagDescribingTileEntityState = getUpdateTag(); final int METADATA = 0; return new SPacketUpdateTileEntity(this.pos, METADATA, updateTagDescribingTileEntityState); } @Override public void onDataPacket(NetworkManager net, SPacketUpdateTileEntity pkt) { NBTTagCompound updateTagDescribingTileEntityState = pkt.getNbtCompound(); handleUpdateTag(updateTagDescribingTileEntityState); } /* Creates a tag containing the TileEntity information, used by vanilla to transmit from server to client Warning - although our getUpdatePacket() uses this method, vanilla also calls it directly, so don't remove it. */ @Override public NBTTagCompound getUpdateTag() { NBTTagCompound nbtTagCompound = new NBTTagCompound(); writeToNBT(nbtTagCompound); return nbtTagCompound; } /* Populates this TileEntity with information from the tag, used by vanilla to transmit from server to client Warning - although our onDataPacket() uses this method, vanilla also calls it directly, so don't remove it. */ @Override public void handleUpdateTag(NBTTagCompound tag) { this.readFromNBT(tag); } //------------------------ // set all slots to empty @Override public void clear() { Arrays.fill(itemStacks, null); } // will add a key for this container to the lang file so we can name it in the GUI @Override public String getName() { return "container.grill.name"; } @Override public boolean hasCustomName() { return false; } // standard code to look up what the human-readable name is @Nullable @Override public ITextComponent getDisplayName() { return this.hasCustomName() ? new TextComponentString(this.getName()) : new TextComponentTranslation(this.getName()); } // Fields are used to send non-inventory information from the server to interested clients // The container code caches the fields and sends the client any fields which have changed. // The field ID is limited to byte, and the field value is limited to short. (if you use more than this, they get cast down // in the network packets) // If you need more than this, or shorts are too small, use a custom packet in your container instead. private static final byte COOK_FIELD_ID = 0; private static final byte FIRST_BURN_TIME_REMAINING_FIELD_ID = 1; private static final byte FIRST_BURN_TIME_INITIAL_FIELD_ID = FIRST_BURN_TIME_REMAINING_FIELD_ID + (byte)FUEL_SLOTS_COUNT; private static final byte NUMBER_OF_FIELDS = FIRST_BURN_TIME_INITIAL_FIELD_ID + (byte)FUEL_SLOTS_COUNT; @Override public int getField(int id) { if (id == COOK_FIELD_ID) return cookTime; if (id >= FIRST_BURN_TIME_REMAINING_FIELD_ID && id < FIRST_BURN_TIME_REMAINING_FIELD_ID + FUEL_SLOTS_COUNT) { return burnTimeRemaining[id - FIRST_BURN_TIME_REMAINING_FIELD_ID]; } if (id >= FIRST_BURN_TIME_INITIAL_FIELD_ID && id < FIRST_BURN_TIME_INITIAL_FIELD_ID + FUEL_SLOTS_COUNT) { return burnTimeInitialValue[id - FIRST_BURN_TIME_INITIAL_FIELD_ID]; } System.err.println("Invalid field ID in TileInventorySmelting.getField:" + id); return 0; } @Override public void setField(int id, int value) { if (id == COOK_FIELD_ID) { cookTime = (short)value; } else if (id >= FIRST_BURN_TIME_REMAINING_FIELD_ID && id < FIRST_BURN_TIME_REMAINING_FIELD_ID + FUEL_SLOTS_COUNT) { burnTimeRemaining[id - FIRST_BURN_TIME_REMAINING_FIELD_ID] = value; } else if (id >= FIRST_BURN_TIME_INITIAL_FIELD_ID && id < FIRST_BURN_TIME_INITIAL_FIELD_ID + FUEL_SLOTS_COUNT) { burnTimeInitialValue[id - FIRST_BURN_TIME_INITIAL_FIELD_ID] = value; } else { System.err.println("Invalid field ID in TileInventorySmelting.setField:" + id); } } @Override public int getFieldCount() { return NUMBER_OF_FIELDS; } // ----------------------------------------------------------------------------------------------------------- // The following methods are not needed for this example but are part of IInventory so they must be implemented // Unused unless your container specifically uses it. // Return true if the given stack is allowed to go in the given slot @Override public boolean isItemValidForSlot(int slotIndex, ItemStack itemstack) { return false; } /** * This method removes the entire contents of the given slot and returns it. * Used by containers such as crafting tables which return any items in their slots when you close the GUI * @param slotIndex * @return */ @Override public ItemStack removeStackFromSlot(int slotIndex) { ItemStack itemStack = getStackInSlot(slotIndex); if (itemStack != null) setInventorySlotContents(slotIndex, null); return itemStack; } public boolean receiveClientEvent(int id, int type) { if (id == 1) { this.numPlayersUsing = type; return true; } else { return super.receiveClientEvent(id, type); } } public void openInventory(EntityPlayer player) { if (!player.isSpectator()) { if (this.numPlayersUsing < 0) { this.numPlayersUsing = 0; } ++this.numPlayersUsing; this.worldObj.addBlockEvent(this.pos, this.getBlockType(), 1, this.numPlayersUsing); this.worldObj.notifyNeighborsOfStateChange(this.pos, this.getBlockType()); this.worldObj.notifyNeighborsOfStateChange(this.pos.down(), this.getBlockType()); } } public void closeInventory(EntityPlayer player) { if (!player.isSpectator() && this.getBlockType() instanceof BlockChest) { --this.numPlayersUsing; this.worldObj.addBlockEvent(this.pos, this.getBlockType(), 1, this.numPlayersUsing); this.worldObj.notifyNeighborsOfStateChange(this.pos, this.getBlockType()); this.worldObj.notifyNeighborsOfStateChange(this.pos.down(), this.getBlockType()); } } } Also, do you think I should lock this thread and start a new one?This one has too many replies
  10. OK I addded the fields and stuff. When I tried to open the grill.... It didnt even open the gui and this happened: [22:17:44] [Chunk I/O Executor Thread-1/INFO] [STDERR]: [java.lang.ThreadGroup:uncaughtException:1052]: java.util.ConcurrentModificationException [22:17:44] [Chunk I/O Executor Thread-1/INFO] [STDERR]: [java.lang.ThreadGroup:uncaughtException:1052]: at java.util.HashMap$HashIterator.nextNode(HashMap.java:1429) [22:17:44] [Chunk I/O Executor Thread-1/INFO] [STDERR]: [java.lang.ThreadGroup:uncaughtException:1052]: at java.util.HashMap$KeyIterator.next(HashMap.java:1453) [22:17:44] [Chunk I/O Executor Thread-1/INFO] [STDERR]: [java.lang.ThreadGroup:uncaughtException:1052]: at net.minecraft.util.ClassInheritanceMultiMap.<init>(ClassInheritanceMultiMap.java:27) [22:17:44] [Chunk I/O Executor Thread-1/INFO] [STDERR]: [java.lang.ThreadGroup:uncaughtException:1052]: at net.minecraft.world.chunk.Chunk.<init>(Chunk.java:106) [22:17:44] [Chunk I/O Executor Thread-1/INFO] [STDERR]: [java.lang.ThreadGroup:uncaughtException:1052]: at net.minecraft.world.chunk.storage.AnvilChunkLoader.readChunkFromNBT(AnvilChunkLoader.java:453) [22:17:44] [Chunk I/O Executor Thread-1/INFO] [STDERR]: [java.lang.ThreadGroup:uncaughtException:1052]: at net.minecraft.world.chunk.storage.AnvilChunkLoader.checkedReadChunkFromNBT__Async(AnvilChunkLoader.java:138) [22:17:44] [Chunk I/O Executor Thread-1/INFO] [STDERR]: [java.lang.ThreadGroup:uncaughtException:1052]: at net.minecraft.world.chunk.storage.AnvilChunkLoader.loadChunk__Async(AnvilChunkLoader.java:108) [22:17:44] [Chunk I/O Executor Thread-1/INFO] [STDERR]: [java.lang.ThreadGroup:uncaughtException:1052]: at net.minecraftforge.common.chunkio.ChunkIOProvider.run(ChunkIOProvider.java:68) [22:17:44] [Chunk I/O Executor Thread-1/INFO] [STDERR]: [java.lang.ThreadGroup:uncaughtException:1052]: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [22:17:44] [Chunk I/O Executor Thread-1/INFO] [STDERR]: [java.lang.ThreadGroup:uncaughtException:1052]: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [22:17:44] [Chunk I/O Executor Thread-1/INFO] [STDERR]: [java.lang.ThreadGroup:uncaughtException:1052]: at java.lang.Thread.run(Thread.java:745)
  11. because of this: float f = tec.prevLidAngle + (tec.lidAngle - tec.prevLidAngle) * partialTicks; I need to create new if I want to do that, before it was the TileEntityChest te.
  12. wtf? I think I am missing something very stupid...
  13. Isin't the vanilla TileEntityChestRenderer like my renderer? Why does the lid open for the minecraft one?
  14. Its creates a new instance of the tileentity Grill. The thing is I don't know how to fix that. Off topic question: where did the signatures and stuff go?
  15. I repeat... I will put the Grill's burning state in the block's metadata. How do I find the old instance...
  16. There doesn't seem to be a link to view all posts in one page if there are multiple pages.
  17. Ok I am going to put isBurning in the Grill's metadata. Also, how am I supposed to call the non-empty instance of Grill? Please don't get mad at me, I know I am really bad.
  18. Ok sorry for making you guys so pissed off... I will look at your answers and see what I can do with them, and hopefully not have any more problems...
  19. I read it, cant find anything related to it.
  20. Also, how does the minecraft furnace set its texture? How does it know if its burning or not?
  21. Ok I don't think this: package com.leomelonseeds.moarstuff.client.render.blocks; import com.leomelonseeds.moarstuff.blocks.BlockGrill; import com.leomelonseeds.moarstuff.tileentity.Grill; import net.minecraft.block.Block; import net.minecraft.client.model.ModelChest; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityChest; import net.minecraft.util.ResourceLocation; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; @SideOnly(Side.CLIENT) public class TileGrillRenderer extends TileEntitySpecialRenderer<Grill> { private static final ResourceLocation TEXTURE_BURNING = new ResourceLocation("moarstuff:textures/entity/grill/grill_on.png"); private static final ResourceLocation TEXTURE_NORMAL = new ResourceLocation("moarstuff:textures/entity/grill/grill_off.png"); private final ModelChest simpleChest = new ModelChest(); public TileGrillRenderer(){ } @Override public void renderTileEntityAt(Grill te, double x, double y, double z, float partialTicks, int destroyStage) { if(!(te instanceof Grill)) return; Grill grill = te; TileEntityChest tec = new TileEntityChest(); GlStateManager.enableDepth(); GlStateManager.depthFunc(515); GlStateManager.depthMask(true); int i; if (te.hasWorldObj()) { Block block = te.getBlockType(); i = te.getBlockMetadata(); } else { i = 0; } ModelChest modelchest = this.simpleChest; if (destroyStage >= 0) { this.bindTexture(DESTROY_STAGES[destroyStage]); GlStateManager.matrixMode(5890); GlStateManager.pushMatrix(); GlStateManager.scale(4.0F, 4.0F, 1.0F); GlStateManager.translate(0.0625F, 0.0625F, 0.0625F); GlStateManager.matrixMode(5888); } else if(BlockGrill.isBurning == true){ this.bindTexture(TEXTURE_BURNING); } else { this.bindTexture(TEXTURE_NORMAL); } GlStateManager.pushMatrix(); GlStateManager.enableRescaleNormal(); if (destroyStage < 0) { GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); } GlStateManager.translate((float)x, (float)y + 1.0F, (float)z + 1.0F); GlStateManager.scale(1.0F, -1.0F, -1.0F); GlStateManager.translate(0.5F, 0.5F, 0.5F); int j = 0; if (i == 2) { j = 180; } if (i == 3) { j = 0; } if (i == 4) { j = 90; } if (i == 5) { j = -90; } GlStateManager.rotate((float)j, 0.0F, 1.0F, 0.0F); GlStateManager.translate(-0.5F, -0.5F, -0.5F); float f = tec.prevLidAngle + (tec.lidAngle - tec.prevLidAngle) * partialTicks; f = 1.0F - f; f = 1.0F - f * f * f; modelchest.chestLid.rotateAngleX = -(f * ((float)Math.PI / 2F)); modelchest.renderAll(); GlStateManager.disableRescaleNormal(); GlStateManager.popMatrix(); GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); if (destroyStage >= 0) { GlStateManager.matrixMode(5890); GlStateManager.popMatrix(); GlStateManager.matrixMode(5888); } } } Is a raw type anymore, but it still does not have an opened lid. Is some event supposed to be triggered in BlockGrill::onBlockActivated that causes the lid to open?
  22. Just a question, does the minecraft source code use this.getBlockType when texturing the furnace and if it does, which class is it in? I can't seem to find it.
  23. Ok ill figure out how to do that. ALso:
  24. Yes, so how do I use diesieben07's method of this.getBlockType?
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.