OK, so I built a tile entity furnace. It works exactly how I want up until I try to close and reopen the world while it is smelting. The furnace loses what was in the inventory, but remembers how much the fuel had burned and how much the item had cooked. The inventory is the only thing not saving, and I'm not sure what lines I need to add to fix the issue.
Here is the Tile Entity class:
package epidemiccraft.tileentity;
import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import epidemiccraft.blocks.Autoclave;
import epidemiccraft.com.AutoclaveRecipes;
import net.minecraft.block.Block;
import net.minecraft.block.BlockFurnace;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.init.Items;
import net.minecraft.inventory.ISidedInventory;
import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.Packet;
import net.minecraft.network.play.server.S35PacketUpdateTileEntity;
import net.minecraft.tileentity.TileEntity;
public class TileEntityAutoclave extends TileEntity implements ISidedInventory{
private static final int[] slotsTop = new int[]{0};
private static final int[] slotsBottom = new int[]{2, 1};
private static final int[] slotsSides = new int[]{1};
private ItemStack[] furnaceItemStacks = new ItemStack[3];
public int furnaceBurnTime;
public int currentBurnTime;
public int furnaceCookTime;
public int direction;
private String furnaceName;
public void furnaceName(String string){
this.furnaceName = string;
}
@Override
public int getSizeInventory() {
return this.furnaceItemStacks.length;
}
@Override
public ItemStack getStackInSlot(int par1) {
return this.furnaceItemStacks[par1];
}
@Override
public ItemStack decrStackSize(int par1, int par2){
ItemStack itemstack = getStackInSlot(par1);
if (itemstack != null){
if (itemstack.stackSize <= par2){
setInventorySlotContents(par1, null);
}
else{
itemstack = itemstack.splitStack(par2);
if (this.furnaceItemStacks[par1].stackSize == 0){
this.furnaceItemStacks[par1] = null;
}
}
this.markDirty();
}
return itemstack;
}
@Override
public ItemStack getStackInSlotOnClosing(int par1){
ItemStack itemstack = getStackInSlot(par1);
setInventorySlotContents(par1, null);
return itemstack;
}
@Override
public void setInventorySlotContents(int par1, ItemStack itemstack){
furnaceItemStacks[par1] = itemstack;
if (itemstack != null && itemstack.stackSize > getInventoryStackLimit()){
itemstack.stackSize = getInventoryStackLimit();
}
this.markDirty();
}
@Override
public String getInventoryName() {
return this.hasCustomInventoryName() ? this.furnaceName : "Autoclave";
}
@Override
public boolean hasCustomInventoryName() {
return this.furnaceName != null && this.furnaceName.length() > 0;
}
@Override
public int getInventoryStackLimit() {
return 64;
}
@Override
public Packet getDescriptionPacket()
{
NBTTagCompound nbt = new NBTTagCompound();
writeToNBT(nbt);
return new S35PacketUpdateTileEntity(this.xCoord, this.yCoord, this.zCoord, 1, nbt);
}
@Override
public void onDataPacket(NetworkManager net, S35PacketUpdateTileEntity pkt)
{
readFromNBT(pkt.func_148857_g());
super.onDataPacket(net, pkt);
this.blockMetadata = pkt.func_148857_g().getInteger("BlockMetadata");
}
public void markForUpdate() {
worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
}
public void writeToNBT(NBTTagCompound tagCompound){
super.writeToNBT(tagCompound);
NBTTagList items = new NBTTagList();
for (int i = 0; i < getSizeInventory(); i++){
ItemStack stack = this.getStackInSlot(i);
if (stack != null){
NBTTagCompound writeitem = new NBTTagCompound();
writeitem.setByte("Slot", (byte) i);
stack.writeToNBT(writeitem);
items.appendTag(writeitem);
}
}
tagCompound.setInteger("BurnTime", this.furnaceBurnTime);
tagCompound.setInteger("CookTime", this.furnaceBurnTime);
}
public void readFromNBT(NBTTagCompound tagCompound){
super.readFromNBT(tagCompound);
NBTTagList tagList = tagCompound.getTagList("Items", tagCompound.getId());
for (int i = 0; i < tagList.tagCount(); ++i){
NBTTagCompound item = tagList.getCompoundTagAt(i);
byte slot = item.getByte("Slot");
if (slot >= 0 && slot < this.getSizeInventory()){
this.furnaceItemStacks[slot] = ItemStack.loadItemStackFromNBT(item);
}
}
this.furnaceBurnTime = tagCompound.getInteger("BurnTime");
this.furnaceCookTime = tagCompound.getInteger("CookTime");
this.currentBurnTime = getItemBurnTime(this.furnaceItemStacks[1]);
if (tagCompound.hasKey("CustomName", 8)){
this.furnaceName = tagCompound.getString("CustomName");
}
}
@SideOnly(Side.CLIENT)
public int getCookProgressScaled(int par1){
return this.furnaceCookTime * par1 / 200;
}
@SideOnly(Side.CLIENT)
public int getBurnTimeRemainingScaled(int par1){
if(this.currentBurnTime == 0){
this.currentBurnTime = 200;
}
return this.furnaceBurnTime * par1 / this.currentBurnTime;
}
public boolean isBurning(){
return this.furnaceBurnTime > 0;
}
public void updateEntity()
{
boolean flag = this.furnaceBurnTime > 0;
boolean flag1 = false;
if (this.furnaceBurnTime > 0)
{
--this.furnaceBurnTime;
}
if (!this.worldObj.isRemote)
{
if (this.furnaceBurnTime != 0 || this.furnaceItemStacks[1] != null && this.furnaceItemStacks[0] != null)
{
if (this.furnaceBurnTime == 0 && this.canSmelt())
{
this.currentBurnTime = this.furnaceBurnTime = getItemBurnTime(this.furnaceItemStacks[1]);
if (this.furnaceBurnTime > 0)
{
flag1 = true;
if (this.furnaceItemStacks[1] != null)
{
--this.furnaceItemStacks[1].stackSize;
if (this.furnaceItemStacks[1].stackSize == 0)
{
this.furnaceItemStacks[1] = furnaceItemStacks[1].getItem().getContainerItem(furnaceItemStacks[1]);
}
}
}
}
if (this.isBurning() && this.canSmelt())
{
++this.furnaceCookTime;
if (this.furnaceCookTime == 200)
{
this.furnaceCookTime = 0;
this.smeltItem();
flag1 = true;
}
}
else
{
this.furnaceCookTime = 0;
}
}
if (flag != this.furnaceBurnTime > 0)
{
flag1 = true;
Autoclave.updateBlockState(this.furnaceBurnTime > 0, this.worldObj, this.xCoord, this.yCoord, this.zCoord);
}
}
this.markDirty();
worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
}
private boolean canSmelt(){
if(this.furnaceItemStacks[0] == null){
return false;
} else{
ItemStack itemstack = AutoclaveRecipes.smelting().getSmeltingResult(this.furnaceItemStacks[0]);
if(itemstack == null) return false;
if(this.furnaceItemStacks[2] == null) return true;
if(!this.furnaceItemStacks[2].isItemEqual(itemstack)) return false;
int result = furnaceItemStacks[2].stackSize + itemstack.stackSize;
return result <= getInventoryStackLimit() && result <= this.furnaceItemStacks[2].getMaxStackSize();
}
}
public void smeltItem(){
if(this.canSmelt()){
ItemStack itemstack = AutoclaveRecipes.smelting().getSmeltingResult(this.furnaceItemStacks[0]);
if(this.furnaceItemStacks[2] == null){
this.furnaceItemStacks[2] = itemstack.copy();
}else if(this.furnaceItemStacks[2].getItem() == itemstack.getItem()){
this.furnaceItemStacks[2].stackSize += itemstack.stackSize;
}
--this.furnaceItemStacks[0].stackSize;
if(this.furnaceItemStacks[0].stackSize == 0){
this.furnaceItemStacks[0] = null;
}
}
}
public static int getItemBurnTime(ItemStack itemstack){
if (itemstack == null){
return 0;
} else{
Item item = itemstack.getItem();
if(item instanceof ItemBlock && Block.getBlockFromItem(item) != Blocks.air){
Block block = Block.getBlockFromItem(item);
if(block == Blocks.snow){
return 800;
}
if(block == Blocks.ice){
return 800;
}
if(block == Blocks.packed_ice){
return 800;
}
}
if(item == Items.water_bucket) return 1000;
if(item == Items.potionitem) return 200;
return 0;
}
}
public static boolean isItemFuel(ItemStack itemstack){
return getItemBurnTime(itemstack) > 0;
}
@Override
public boolean isUseableByPlayer(EntityPlayer player) {
return true;
}
@Override
public void openInventory() {
}
@Override
public void closeInventory() {
}
@Override
public boolean isItemValidForSlot(int par1, ItemStack itemstack) {
return par1 == 2 ? false : (par1 == 1 ? isItemFuel(itemstack) : true);
}
@Override
public int[] getAccessibleSlotsFromSide(int par1) {
return par1 == 0 ? slotsBottom : (par1 == 1 ? slotsTop : slotsSides);
}
@Override
public boolean canInsertItem(int par1, ItemStack itemstack, int par3) {
return this.isItemValidForSlot(par1, itemstack);
}
@Override
public boolean canExtractItem(int par1, ItemStack itemstack, int par3) {
return par3 != 0 || par1 != 1 || itemstack.getItem() == Items.bucket;
}
}
And here is where I registered it, just in case that's an issue:
package epidemiccraft.proxy;
import cpw.mods.fml.client.registry.RenderingRegistry;
import cpw.mods.fml.common.network.NetworkRegistry;
import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.relauncher.Side;
import epidemiccraft.com.EpidemicCraft;
import epidemiccraft.gui.EpidemicCraftGuiHandler;
import epidemiccraft.lib.Constants;
import epidemiccraft.mobs.ModelGiardiaCow;
import epidemiccraft.mobs.RenderGiardiaCow;
import epidemiccraft.mobs.EntityGiardiaCowMob;
import epidemiccraft.tileentity.TileEntityAutoclave;
public class CommonProxy {
public void preInit(){
}
public void init(){
}
public void postInit(){
}
public void registerRenders(){
}
public void registerTileEntities(){
GameRegistry.registerTileEntity(TileEntityAutoclave.class, "EpidemicCraft:TileEntityAutoclave");
}
public void registerNetworkStuff(){
NetworkRegistry.INSTANCE.registerGuiHandler(EpidemicCraft.instance, new EpidemicCraftGuiHandler());
}
}
Are you certain the ItemStack[] is empty? I mean, maybe the server knows the items but the client doesn't, and the client is the one with the GUI. Add some printouts to be sure.
Rollback Post to RevisionRollBack
Click this banner for a list of illegal mod distributors -- only download from legal sites!
Are you certain the ItemStack[] is empty? I mean, maybe the server knows the items but the client doesn't, and the client is the one with the GUI. Add some printouts to be sure.
I'm pretty sure that the items don't exist at all because when I break the block after relogging, nothing falls out like it should if the items still existed. Upon adding printouts, I figured out that the whole first chunk of readFromNBT isn't being activated, and those lines are what I assume controls the items being loaded in. The lines for the ItemBurnTime and CookTime are being used, and their data shows up in game.
Here is readFromNBT, with the part bolded that isn't being activated.
public void readFromNBT(NBTTagCompound tagCompound){
super.readFromNBT(tagCompound);
NBTTagList tagList = tagCompound.getTagList("Items", tagCompound.getId()); for (int i = 0; i < tagList.tagCount(); ++i){ NBTTagCompound item = tagList.getCompoundTagAt(i); byte slot = item.getByte("Slot"); System.out.println("readFromNBT part 1 is good!"); if (slot >= 0 && slot < this.getSizeInventory()){ this.furnaceItemStacks[slot] = ItemStack.loadItemStackFromNBT(item); System.out.println("readFromNBT part 2 is good!"); } }
this.furnaceBurnTime = tagCompound.getInteger("BurnTime");
this.furnaceCookTime = tagCompound.getInteger("CookTime");
this.currentBurnTime = getItemBurnTime(this.furnaceItemStacks[1]);
System.out.println("readFromNBT part 3 is good!");
if (tagCompound.hasKey("CustomName", 8)){
this.furnaceName = tagCompound.getString("CustomName");
}
Actually, looking at your writeToNBT, it doesn't look like you're writing the items tag to the main NBTTagCompound.
That would explain why it's not entering the for loop -- NBTTagCompound#getTagList returns an empty list if it does not find the tag compound.
public void writeToNBT(NBTTagCompound tagCompound){
super.writeToNBT(tagCompound);
NBTTagList items = new NBTTagList();
for (int i = 0; i < getSizeInventory(); i++){
ItemStack stack = this.getStackInSlot(i);
if (stack != null){
NBTTagCompound writeitem = new NBTTagCompound();
writeitem.setByte("Slot", (byte) i);
stack.writeToNBT(writeitem);
items.appendTag(writeitem);
}
}
// right here you should call tagCompound.setTag("Items", items); unless it's called something else
tagCompound.setInteger("BurnTime", this.furnaceBurnTime);
tagCompound.setInteger("CookTime", this.furnaceBurnTime);
}
Rollback Post to RevisionRollBack
Click this banner for a list of illegal mod distributors -- only download from legal sites!
Actually, looking at your writeToNBT, it doesn't look like you're writing the items tag to the main NBTTagCompound.
That would explain why it's not entering the for loop -- NBTTagCompound#getTagList returns an empty list if it does not find the tag compound.
public void writeToNBT(NBTTagCompound tagCompound){
super.writeToNBT(tagCompound);
NBTTagList items = new NBTTagList();
for (int i = 0; i < getSizeInventory(); i++){
ItemStack stack = this.getStackInSlot(i);
if (stack != null){
NBTTagCompound writeitem = new NBTTagCompound();
writeitem.setByte("Slot", (byte) i);
stack.writeToNBT(writeitem);
items.appendTag(writeitem);
}
}
// right here you should call tagCompound.setTag("Items", items); unless it's called something else
tagCompound.setInteger("BurnTime", this.furnaceBurnTime);
tagCompound.setInteger("CookTime", this.furnaceBurnTime);
}
Oh thank you! That got it to transfer over world reloads! One last glitch - upon removing an item manually (fuel getting consumed isn't affected), the item lags and seems to duplicate in it's slot and in my hand. It is fixed by re-removing it, but I wanted to know if you had any idea what could be causing the client/server sync issue.
OK, so I built a tile entity furnace. It works exactly how I want up until I try to close and reopen the world while it is smelting. The furnace loses what was in the inventory, but remembers how much the fuel had burned and how much the item had cooked. The inventory is the only thing not saving, and I'm not sure what lines I need to add to fix the issue.
Here is the Tile Entity class:
And here is where I registered it, just in case that's an issue:
If you need anything else, let me know.
Thank you in advance
SchrodingersSpy
Are you certain the ItemStack[] is empty? I mean, maybe the server knows the items but the client doesn't, and the client is the one with the GUI. Add some printouts to be sure.
I'm pretty sure that the items don't exist at all because when I break the block after relogging, nothing falls out like it should if the items still existed. Upon adding printouts, I figured out that the whole first chunk of readFromNBT isn't being activated, and those lines are what I assume controls the items being loaded in. The lines for the ItemBurnTime and CookTime are being used, and their data shows up in game.
Here is readFromNBT, with the part bolded that isn't being activated.
public void readFromNBT(NBTTagCompound tagCompound){
super.readFromNBT(tagCompound);
NBTTagList tagList = tagCompound.getTagList("Items", tagCompound.getId());
for (int i = 0; i < tagList.tagCount(); ++i){
NBTTagCompound item = tagList.getCompoundTagAt(i);
byte slot = item.getByte("Slot");
System.out.println("readFromNBT part 1 is good!");
if (slot >= 0 && slot < this.getSizeInventory()){
this.furnaceItemStacks[slot] = ItemStack.loadItemStackFromNBT(item);
System.out.println("readFromNBT part 2 is good!");
}
}
this.furnaceBurnTime = tagCompound.getInteger("BurnTime");
this.furnaceCookTime = tagCompound.getInteger("CookTime");
this.currentBurnTime = getItemBurnTime(this.furnaceItemStacks[1]);
System.out.println("readFromNBT part 3 is good!");
if (tagCompound.hasKey("CustomName", 8)){
this.furnaceName = tagCompound.getString("CustomName");
}
}
Thank you for helping to pinpoint the problem!
SchrodingersSpy
Actually, looking at your writeToNBT, it doesn't look like you're writing the items tag to the main NBTTagCompound.
That would explain why it's not entering the for loop -- NBTTagCompound#getTagList returns an empty list if it does not find the tag compound.
Oh thank you! That got it to transfer over world reloads! One last glitch - upon removing an item manually (fuel getting consumed isn't affected), the item lags and seems to duplicate in it's slot and in my hand. It is fixed by re-removing it, but I wanted to know if you had any idea what could be causing the client/server sync issue.
Thank you so much for all of your help thus far!