Hi,
I have created a custom furnace that is similar to a vanilla one but has different recipes. When I use it in singleplayer, it works fine, but in multiplayer, it does not work. It seems that the inventory is not "syncing" between client and server. When I try to put in an item, the item seems to duplicate and then disappear when I put it back into my inventory. The furnace does not smelt.
My TileEntity class:
public class TileEntityEnergyReactor 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 currentItemBurnTime;
public int furnaceCookTime;
private String field_145958_o;
public int getSizeInventory()
{
return this.furnaceItemStacks.length;
}
public ItemStack getStackInSlot(int par1)
{
return this.furnaceItemStacks[par1];
}
public ItemStack decrStackSize(int par1, int par2)
{
if (this.furnaceItemStacks[par1] != null)
{
ItemStack itemstack;
if (this.furnaceItemStacks[par1].stackSize <= par2)
{
itemstack = this.furnaceItemStacks[par1];
this.furnaceItemStacks[par1] = null;
return itemstack;
}
else
{
itemstack = this.furnaceItemStacks[par1].splitStack(par2);
if (this.furnaceItemStacks[par1].stackSize == 0)
{
this.furnaceItemStacks[par1] = null;
}
return itemstack;
}
}
else
{
return null;
}
}
public ItemStack getStackInSlotOnClosing(int par1)
{
if (this.furnaceItemStacks[par1] != null)
{
ItemStack itemstack = this.furnaceItemStacks[par1];
this.furnaceItemStacks[par1] = null;
return itemstack;
}
else
{
return null;
}
}
public void setInventorySlotContents(int par1, ItemStack par2ItemStack)
{
this.furnaceItemStacks[par1] = par2ItemStack;
if (par2ItemStack != null && par2ItemStack.stackSize > this.getInventoryStackLimit())
{
par2ItemStack.stackSize = this.getInventoryStackLimit();
}
}
public String getInventoryName()
{
return this.hasCustomInventoryName() ? this.field_145958_o : "Energy Reactor";
}
public boolean hasCustomInventoryName()
{
return this.field_145958_o != null && this.field_145958_o.length() > 0;
}
public void func_145951_a(String p_145951_1_)
{
this.field_145958_o = p_145951_1_;
}
public void readFromNBT(NBTTagCompound p_145839_1_)
{
super.readFromNBT(p_145839_1_);
NBTTagList nbttaglist = p_145839_1_.getTagList("Items", 10);
this.furnaceItemStacks = new ItemStack[this.getSizeInventory()];
for (int i = 0; i < nbttaglist.tagCount(); ++i)
{
NBTTagCompound nbttagcompound1 = nbttaglist.getCompoundTagAt(i);
byte b0 = nbttagcompound1.getByte("Slot");
if (b0 >= 0 && b0 < this.furnaceItemStacks.length)
{
this.furnaceItemStacks[b0] = ItemStack.loadItemStackFromNBT(nbttagcompound1);
}
}
this.furnaceBurnTime = p_145839_1_.getShort("BurnTime");
this.furnaceCookTime = p_145839_1_.getShort("CookTime");
this.currentItemBurnTime = getItemBurnTime(this.furnaceItemStacks[1]);
if (p_145839_1_.hasKey("CustomName", )
{
this.field_145958_o = p_145839_1_.getString("CustomName");
}
}
public void writeToNBT(NBTTagCompound p_145841_1_)
{
super.writeToNBT(p_145841_1_);
p_145841_1_.setShort("BurnTime", (short)this.furnaceBurnTime);
p_145841_1_.setShort("CookTime", (short)this.furnaceCookTime);
NBTTagList nbttaglist = new NBTTagList();
for (int i = 0; i < this.furnaceItemStacks.length; ++i)
{
if (this.furnaceItemStacks[i] != null)
{
NBTTagCompound nbttagcompound1 = new NBTTagCompound();
nbttagcompound1.setByte("Slot", (byte)i);
this.furnaceItemStacks[i].writeToNBT(nbttagcompound1);
nbttaglist.appendTag(nbttagcompound1);
}
}
p_145841_1_.setTag("Items", nbttaglist);
if (this.hasCustomInventoryName())
{
p_145841_1_.setString("CustomName", this.field_145958_o);
}
}
public int getInventoryStackLimit()
{
return 64;
}
@SideOnly(Side.CLIENT)
public int getCookProgressScaled(int p_145953_1_)
{
return this.furnaceCookTime * p_145953_1_ / 200;
}
@SideOnly(Side.CLIENT)
public int getBurnTimeRemainingScaled(int p_145955_1_)
{
if (this.currentItemBurnTime == 0)
{
this.currentItemBurnTime = 20;
}
return this.furnaceBurnTime * p_145955_1_ / this.currentItemBurnTime;
}
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.canSmelt())
{
this.currentItemBurnTime = 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;
BlockEnergyReactor.updateFurnaceBlockState(this.furnaceBurnTime > 0, this.worldObj, this.xCoord, this.yCoord, this.zCoord);
}
}
if (flag1)
{
this.markDirty();
}
}
private boolean canSmelt()
{
if (this.furnaceItemStacks[0] == null)
{
return false;
}
else
{
ItemStack itemstack = EnergyReactorRecipes.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 = EnergyReactorRecipes.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 p_145952_0_)
{
if (p_145952_0_ == null)
{
return 0;
}
else
{
Item item = p_145952_0_.getItem();
if (item == ChaosItems.ItemEnergyShard) return 1000;
return GameRegistry.getFuelValue(p_145952_0_);
}
}
public static boolean isItemFuel(ItemStack p_145954_0_) {
return getItemBurnTime(p_145954_0_) > 0;
}
public boolean isUseableByPlayer(EntityPlayer par1EntityPlayer)
{
return this.worldObj.getTileEntity(this.xCoord, this.yCoord, this.zCoord) != this ? false : par1EntityPlayer.getDistanceSq((double)this.xCoord + 0.5D, (double)this.yCoord + 0.5D, (double)this.zCoord + 0.5D) <= 64.0D;
}
public void openInventory() {}
public void closeInventory() {}
public boolean isItemValidForSlot(int par1, ItemStack par2ItemStack)
{
return par1 == 2 ? false : (par1 == 1 ? isItemFuel(par2ItemStack) : true);
}
public int[] getAccessibleSlotsFromSide(int par1)
{
return par1 == 0 ? slotsBottom : (par1 == 1 ? slotsTop : slotsSides);
}
public boolean canInsertItem(int par1, ItemStack par2ItemStack, int par3)
{
return this.isItemValidForSlot(par1, par2ItemStack);
}
public boolean canExtractItem(int par1, ItemStack par2ItemStack, int par3)
{
return par3 != 0 || par1 != 1 || par2ItemStack.getItem() == Items.bucket;
}
}
My GUI Class:
@SideOnly(Side.CLIENT)
public class GUIEnergyReactor extends GuiContainer {
private TileEntityEnergyReactor furnaceInventory;
public GUIEnergyReactor(InventoryPlayer par1InventoryPlayer, TileEntityEnergyReactor par2TileEntityFurnace) {
super(new ContainerEnergyReactor(par1InventoryPlayer, par2TileEntityFurnace));
this.furnaceInventory = par2TileEntityFurnace;
}
@Override
protected void drawGuiContainerForegroundLayer(int arg1, int arg2) {
String s = "Energy Reactor";
this.fontRendererObj.drawString(s, 10, 6, 4210752);
this.fontRendererObj.drawString("Inventory", 8, this.ySize - 96 + 2, 4210752);
}
protected void drawGuiContainerBackgroundLayer(float par1, int par2, int par3) {
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
this.mc.getTextureManager().bindTexture(ChaosHelper.energyReactor);
int k = (this.width - this.xSize) / 2;
int l = (this.height - this.ySize) / 2;
this.drawTexturedModalRect(k, l, 0, 0, this.xSize, this.ySize);
int i1;
if (this.furnaceInventory.isBurning()) {
i1 = this.furnaceInventory.getBurnTimeRemainingScaled(12);
this.drawTexturedModalRect(k + 57, l + 33 + 16 - i1, 176, 12 - i1, 14, i1 + 2);
}
i1 = this.furnaceInventory.getCookProgressScaled(24);
this.drawTexturedModalRect(k + 80, l + 34, 176, 14, i1 + 1, 16);
}
}
My Container Class:
public class ContainerEnergyReactor extends Container
{
private TileEntityEnergyReactor furnace;
private int lastCookTime;
private int lastBurnTime;
private int lastItemBurnTime;
public ContainerEnergyReactor(InventoryPlayer par1InventoryPlayer, TileEntityEnergyReactor par2TileEntityFurnace)
{
this.furnace = par2TileEntityFurnace;
this.addSlotToContainer(new Slot(par2TileEntityFurnace, 0, 56, 17));
this.addSlotToContainer(new Slot(par2TileEntityFurnace, 1, 56, 53));
this.addSlotToContainer(new SlotFurnace(par1InventoryPlayer.player, par2TileEntityFurnace, 2, 116, 35));
int i, j;
for (i = 0; i < 3; ++i)
{
for (j = 0; j < 9; ++j)
{
this.addSlotToContainer(new Slot(par1InventoryPlayer, j + i * 9 + 9, 8 + j * 18, 84 + i * 18));
}
}
for (i = 0; i < 9; ++i)
{
this.addSlotToContainer(new Slot(par1InventoryPlayer, i, 8 + i * 18, 142));
}
}
public void addCraftingToCrafters(ICrafting par1ICrafting)
{
super.addCraftingToCrafters(par1ICrafting);
par1ICrafting.sendProgressBarUpdate(this, 0, this.furnace.furnaceCookTime);
par1ICrafting.sendProgressBarUpdate(this, 1, this.furnace.furnaceBurnTime);
par1ICrafting.sendProgressBarUpdate(this, 2, this.furnace.currentItemBurnTime);
}
public void detectAndSendChanges()
{
super.detectAndSendChanges();
for (int i = 0; i < this.crafters.size(); ++i)
{
ICrafting icrafting = (ICrafting)this.crafters.get(i);
if (this.lastCookTime != this.furnace.furnaceCookTime)
{
icrafting.sendProgressBarUpdate(this, 0, this.furnace.furnaceCookTime);
}
if (this.lastBurnTime != this.furnace.furnaceBurnTime)
{
icrafting.sendProgressBarUpdate(this, 1, this.furnace.furnaceBurnTime);
}
if (this.lastItemBurnTime != this.furnace.currentItemBurnTime)
{
icrafting.sendProgressBarUpdate(this, 2, this.furnace.currentItemBurnTime);
}
}
this.lastCookTime = this.furnace.furnaceCookTime;
this.lastBurnTime = this.furnace.furnaceBurnTime;
this.lastItemBurnTime = this.furnace.currentItemBurnTime;
}
@SideOnly(Side.CLIENT)
public void updateProgressBar(int par1, int par2)
{
if (par1 == 0)
{
this.furnace.furnaceCookTime = par2;
}
if (par1 == 1)
{
this.furnace.furnaceBurnTime = par2;
}
if (par1 == 2)
{
this.furnace.currentItemBurnTime = par2;
}
}
public boolean canInteractWith(EntityPlayer par1EntityPlayer)
{
return this.furnace.isUseableByPlayer(par1EntityPlayer);
}
public ItemStack transferStackInSlot(EntityPlayer par1EntityPlayer, int par2)
{
ItemStack itemstack = null;
Slot slot = (Slot)this.inventorySlots.get(par2);
if (slot != null && slot.getHasStack())
{
ItemStack itemstack1 = slot.getStack();
itemstack = itemstack1.copy();
if (par2 == 2)
{
if (!this.mergeItemStack(itemstack1, 3, 39, true))
{
return null;
}
slot.onSlotChange(itemstack1, itemstack);
}
else if (par2 != 1 && par2 != 0)
{
if (FurnaceRecipes.smelting().getSmeltingResult(itemstack1) != null)
{
if (!this.mergeItemStack(itemstack1, 0, 1, false))
{
return null;
}
}
else if (TileEntityEnergyReactor.isItemFuel(itemstack1))
{
if (!this.mergeItemStack(itemstack1, 1, 2, false))
{
return null;
}
}
else if (par2 >= 3 && par2 < 30)
{
if (!this.mergeItemStack(itemstack1, 30, 39, false))
{
return null;
}
}
else if (par2 >= 30 && par2 < 39 && !this.mergeItemStack(itemstack1, 3, 30, false))
{
return null;
}
}
else if (!this.mergeItemStack(itemstack1, 3, 39, false))
{
return null;
}
if (itemstack1.stackSize == 0)
{
slot.putStack((ItemStack)null);
}
else
{
slot.onSlotChanged();
}
if (itemstack1.stackSize == itemstack.stackSize)
{
return null;
}
slot.onPickupFromSlot(par1EntityPlayer, itemstack1);
}
return itemstack;
}
}
My GUI Handler Class:
public class ChaosGUIHandler implements IGuiHandler{
public static int guiID = 0;
public static int energyReactor = guiID++;
@Override
public Object getServerGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) {
TileEntity entity = world.getTileEntity(x, y, z);
if(ID == energyReactor){
return new ContainerEnergyReactor(player.inventory, (TileEntityEnergyReactor)entity);
}
return null;
}
@Override
public Object getClientGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) {
TileEntity entity = world.getTileEntity(x, y, z);
if(ID == energyReactor){
return new GUIEnergyReactor(player.inventory, (TileEntityEnergyReactor)entity);
}
return null;
}
}
Any help would be greatly appreciated!
Thanks.