Jump to content

[1.8] TileEntity Slot not synchronized


Earthcomputer

Recommended Posts

I've been having this problem for quite a while now, and no matter what I do there is a certain inventory slot that updates on the server side but not on the client side. Shouldn't detectAndSendChanges automatically sort this problem out? The progress bars are synchronized fine

 

Here is my container class. The problematic slot is the output slot (ID 9):

 

 

package com.earthcomputer.farmersheaven;

import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.inventory.Container;
import net.minecraft.inventory.ICrafting;
import net.minecraft.inventory.Slot;
import net.minecraft.inventory.SlotCrafting;
import net.minecraft.inventory.SlotFurnaceFuel;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityFurnace;
import net.minecraft.util.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;

public class ContainerAutoCraftingTable extends Container
{

private TileEntityAutoCraftingTable	craftingTable;

private int							craftTime	= 0;
private int							burnTime	= 0;
private int							maxBurnTime	= 200;

public ContainerAutoCraftingTable(EntityPlayer player, World world, BlockPos pos)
{
	TileEntity tileEntity = world.getTileEntity(pos);
	if(tileEntity instanceof TileEntityAutoCraftingTable)
		craftingTable = (TileEntityAutoCraftingTable) tileEntity;
	else craftingTable = null;
	for(int j = 0; j < 3; j++)
	{
		for(int i = 0; i < 3; i++)
		{
			addSlotToContainer(new Slot(craftingTable, i + j * 3, 30 + i * 18, 17 + j * 18));
		}
	}
	addSlotToContainer(new SlotCrafting(player, craftingTable.getInventoryCrafting(), craftingTable, 9, 124, 35) {
		@Override
		public void onPickupFromSlot(EntityPlayer player, ItemStack stack)
		{
			FMLCommonHandler.instance()
				.firePlayerCraftingEvent(player, stack, craftingTable.getInventoryCrafting());
			onCrafting(stack);
		}
	});
	addSlotToContainer(new SlotFurnaceFuel(craftingTable, 10, 93, 55));

	bindPlayerInventory(player.inventory);
}

public TileEntityAutoCraftingTable getCraftingTable()
{
	return craftingTable;
}

private void bindPlayerInventory(InventoryPlayer invPlayer)
{
	// main inventory
	for(int j = 0; j < 3; j++)
	{
		for(int i = 0; i < 9; i++)
		{
			addSlotToContainer(new Slot(invPlayer, i + j * 9 + 9, 8 + i * 18, 84 + j * 18));
		}
	}
	// hotbar
	for(int i = 0; i < 9; i++)
	{
		addSlotToContainer(new Slot(invPlayer, i, 8 + i * 18, 142));
	}
}

@Override
public boolean canInteractWith(EntityPlayer player)
{
	return craftingTable.isUseableByPlayer(player);
}

@Override
public ItemStack transferStackInSlot(EntityPlayer player, int index)
{
	ItemStack itemstack = null;
	Slot slot = (Slot) inventorySlots.get(index);

	if(slot != null && slot.getHasStack())
	{
		ItemStack itemstack1 = slot.getStack();
		itemstack = itemstack1.copy();

		boolean flag = index >= craftingTable.getSizeInventory() && index < craftingTable.getSizeInventory() + 36;
		if(index == 9) // result
		{
			if(!mergeItemStack(itemstack1, craftingTable.getSizeInventory(), craftingTable.getSizeInventory() + 36,
				true)){ return null; }
		}
		else if(!flag) // craft matrix or fuel slot
		{
			if(!this.mergeItemStack(itemstack1, craftingTable.getSizeInventory(),
				craftingTable.getSizeInventory() + 27, false)){ return null; }
		}
		else if(TileEntityFurnace.isItemFuel(itemstack1))
		{
			if(mergeItemStack(itemstack1, 10, 11, false)) flag = false;
		}
		if(flag)
		{
			if(index >= craftingTable.getSizeInventory() && index < craftingTable.getSizeInventory() + 27) // main inventory
			{
				if(!mergeItemStack(itemstack1, craftingTable.getSizeInventory() + 27,
					craftingTable.getSizeInventory() + 36, false)){ return null; }
			}
			else if(index >= craftingTable.getSizeInventory() + 27 && index < craftingTable.getSizeInventory() + 36) // hotbar
			{
				if(!this.mergeItemStack(itemstack1, craftingTable.getSizeInventory(),
					craftingTable.getSizeInventory() + 27, false)){ return null; }
			}
		}
		if(itemstack1.stackSize == 0)
		{
			slot.putStack((ItemStack) null);
		}
		else
		{
			slot.onSlotChanged();
		}

		if(itemstack1.stackSize == itemstack.stackSize){ return null; }

		slot.onPickupFromSlot(player, itemstack1);
	}

	return itemstack;
}

@Override
public void addCraftingToCrafters(ICrafting listener)
{
	super.addCraftingToCrafters(listener);
	listener.func_175173_a(this, craftingTable);
}

@Override
public void detectAndSendChanges()
{
	super.detectAndSendChanges(); // This should update all the slots
	for(Object object : crafters)
	{
		ICrafting crafting = (ICrafting) object;
		if(craftTime != craftingTable.getCraftTime())
			crafting.sendProgressBarUpdate(this, 0, craftingTable.getCraftTime());
		if(burnTime != craftingTable.getBurnTime())
			crafting.sendProgressBarUpdate(this, 1, craftingTable.getBurnTime());
		if(maxBurnTime != craftingTable.getMaxBurnTime())
			crafting.sendProgressBarUpdate(this, 2, craftingTable.getMaxBurnTime());
	}
	craftTime = craftingTable.getCraftTime();
	burnTime = craftingTable.getBurnTime();
	maxBurnTime = craftingTable.getMaxBurnTime();
}

@Override
@SideOnly(Side.CLIENT)
public void updateProgressBar(int id, int newValue)
{
	craftingTable.setField(id, newValue);
}

}

 

 

 

This is my tile entity:

 

 

package com.earthcomputer.farmersheaven;

import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.Container;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.ISidedInventory;
import net.minecraft.inventory.InventoryCrafting;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.CraftingManager;
import net.minecraft.item.crafting.IRecipe;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.server.gui.IUpdatePlayerListBox;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityFurnace;
import net.minecraft.util.BlockPos;
import net.minecraft.util.ChatComponentText;
import net.minecraft.util.ChatComponentTranslation;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.IChatComponent;
import net.minecraft.world.World;
import net.minecraftforge.common.util.Constants;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;

public class TileEntityAutoCraftingTable extends TileEntity implements IUpdatePlayerListBox, ISidedInventory
{

private Container				container				= new Container() {
															@Override
															public boolean canInteractWith(EntityPlayer player)
															{
																return true;
															}

															@Override
															public void onCraftMatrixChanged(IInventory inventory)
															{
																changeOutput();
															}
														};

private InventoryCrafting		invCrafting				= new InventoryCrafting(container, 3, 3);
private ItemStack				result;
private ItemStack				fuelStack;
private IRecipe					currentRecipe;
private int						craftTime				= 0;
public static final int			MAX_CRAFT_TIME			= 200;
private int						clientSyncTime			= 0;
private static final int		MAX_CLIENT_SYNC_TIME	= 10;
private int						burnTime				= 0;
private int						maxBurnTime				= 200;
private int						powered					= -1;

private String					customName;

/** Whether to use packets to update the output slot of the tile entity */
private static final boolean	USE_PACKETS				= false;

@Override
public boolean shouldRefresh(World world, BlockPos pos, IBlockState oldState, IBlockState newState)
{
	return oldState.getBlock() != newState.getBlock();
}

@Override
public String getName()
{
	return hasCustomName() ? customName : "container.autocrafting_table";
}

@Override
public boolean hasCustomName()
{
	return customName != null && customName.length() > 0;
}

@Override
public IChatComponent getDisplayName()
{
	return hasCustomName() ? new ChatComponentText(getName()) : new ChatComponentTranslation(getName());
}

@Override
public int getSizeInventory()
{
	return 11;
}

public boolean getPowered()
{
	if(!hasWorldObj()) return true;
	if(powered == -1)
	{
		IBlockState state = worldObj.getBlockState(pos);
		powered = (Boolean) state.getValue(BlockAutoCraftingTable.POWERED) ? 1 : 0;
	}
	return powered > 0;
}

void setPowered(boolean powered)
{
	this.powered = powered ? 1 : 0;
}

public InventoryCrafting getInventoryCrafting()
{
	return invCrafting;
}

public int getCraftTime()
{
	return craftTime;
}

public int getBurnTime()
{
	return burnTime;
}

public int getMaxBurnTime()
{
	return maxBurnTime;
}

public void setCraftTime(int craftTime)
{
	this.craftTime = craftTime;
}

public void setBurnTime(int burnTime)
{
	this.burnTime = burnTime;
}

public void setMaxBurnTime(int maxBurnTime)
{
	this.maxBurnTime = maxBurnTime;
}

@Override
public ItemStack getStackInSlot(int index)
{
	return index == 9 ? result : (index == 10 ? fuelStack : invCrafting.getStackInSlot(index));
}

private void setStackInSlot(int index, ItemStack stack)
{
	if(index == 9)
	{
		result = stack;
	}
	else if(index == 10)
	{
		fuelStack = stack;
	}
	else
	{
		invCrafting.setInventorySlotContents(index, stack);
	}
}

@Override
public ItemStack decrStackSize(int index, int count)
{
	if(getStackInSlot(index) != null)
	{
		ItemStack stack;

		if(getStackInSlot(index).stackSize <= count)
		{
			stack = getStackInSlot(index);
			setStackInSlot(index, null);
			return stack;
		}
		else
		{
			stack = getStackInSlot(index).splitStack(count);

			if(getStackInSlot(index).stackSize == 0)
			{
				setStackInSlot(index, null);
			}

			return stack;
		}
	}
	else
	{
		return null;
	}
}

@Override
@SideOnly(Side.CLIENT)
public ItemStack getStackInSlotOnClosing(int index)
{
	if(getStackInSlot(index) != null)
	{
		ItemStack itemstack = getStackInSlot(index);
		setStackInSlot(index, null);
		return itemstack;
	}
	else
	{
		return null;
	}
}

@Override
public void setInventorySlotContents(int index, ItemStack stack)
{
	boolean sameStackInSlot = stack != null && stack.isItemEqual(getStackInSlot(index))
		&& ItemStack.areItemStackTagsEqual(stack, getStackInSlot(index));
	setStackInSlot(index, stack);

	if(stack != null && stack.stackSize > getInventoryStackLimit())
	{
		stack.stackSize = getInventoryStackLimit();
	}

	if(index < 9 && !sameStackInSlot)
	{
		changeOutput();
		markDirty();
	}
}

@Override
public int getInventoryStackLimit()
{
	return 64;
}

@Override
public boolean isUseableByPlayer(EntityPlayer player)
{
	return worldObj.getTileEntity(pos) != this ? false : player.getDistanceSq(pos.getX() + 0.5D, pos.getY() + 0.5D,
		pos.getZ() + 0.5D) <= 64.0D;
}

@Override
public void openInventory(EntityPlayer player)
{
}

@Override
public void closeInventory(EntityPlayer player)
{
}

@Override
public boolean isItemValidForSlot(int index, ItemStack stack)
{
	// true && (false || false)
	return index != 9 && (index != 10 || TileEntityFurnace.isItemFuel(stack));
}

@Override
public int getField(int id)
{
	switch(id)
	{
		case 0:
			return craftTime;
		case 1:
			return burnTime;
		case 2:
			return maxBurnTime;
		default:
			return 0;
	}
}

@Override
public void setField(int id, int value)
{
	switch(id)
	{
		case 0:
			craftTime = value;
			break;
		case 1:
			burnTime = value;
			break;
		case 2:
			maxBurnTime = value;
			break;
	}
}

@Override
public int getFieldCount()
{
	return 3;
}

@Override
public void clear()
{
	for(int i = 0; i < getSizeInventory(); i++)
	{
		setStackInSlot(i, null);
	}
}

@Override
public void readFromNBT(NBTTagCompound compound)
{
	super.readFromNBT(compound);
	NBTTagList craftMatrix = compound.getTagList("CraftMatrix", Constants.NBT.TAG_COMPOUND);
	for(int i = 0; i < craftMatrix.tagCount(); i++)
	{
		NBTTagCompound stack = craftMatrix.getCompoundTagAt(i);
		int slot = stack.getByte("Slot") & 255;
		if(slot >= 0 && slot < 9) setStackInSlot(slot, ItemStack.loadItemStackFromNBT(stack));
	}
	NBTTagCompound result = compound.getCompoundTag("Result");
	if(result.hasNoTags())
		this.result = null;
	else this.result = ItemStack.loadItemStackFromNBT(result);
	NBTTagCompound fuel = compound.getCompoundTag("Fuel");
	if(fuel.hasNoTags())
		this.fuelStack = null;
	else this.fuelStack = ItemStack.loadItemStackFromNBT(fuel);
	changeOutput();
	craftTime = compound.getInteger("CraftTime");
	burnTime = compound.getInteger("BurnTime");
	maxBurnTime = compound.getInteger("MaxBurnTime");
	if(maxBurnTime <= 0) maxBurnTime = 200;
	if(compound.hasKey("CustomName")) customName = compound.getString("CustomName");
}

@Override
public void writeToNBT(NBTTagCompound compound)
{
	super.writeToNBT(compound);
	NBTTagList craftMatrix = new NBTTagList();
	for(int i = 0; i < 9; i++)
	{
		if(getStackInSlot(i) != null)
		{
			NBTTagCompound stack = new NBTTagCompound();
			getStackInSlot(i).writeToNBT(stack);
			stack.setByte("Slot", (byte) i);
			craftMatrix.appendTag(stack);
		}
	}
	compound.setTag("CraftMatrix", craftMatrix);
	if(result != null)
	{
		NBTTagCompound result = new NBTTagCompound();
		this.result.writeToNBT(result);
		compound.setTag("Result", result);
	}
	if(fuelStack != null)
	{
		NBTTagCompound fuel = new NBTTagCompound();
		fuelStack.writeToNBT(fuel);
		compound.setTag("Fuel", fuel);
	}
	compound.setInteger("CraftTime", craftTime);
	compound.setInteger("BurnTime", burnTime);
	compound.setInteger("MaxBurnTime", maxBurnTime);
	if(hasCustomName()) compound.setString("CustomName", customName);
}

@Override
public void update()
{
	if(!worldObj.isRemote) updateOutput();
	updateComparators();
}

private void changeOutput()
{
	if(currentRecipe == null || !currentRecipe.matches(invCrafting, worldObj)) craftTime = 0;
	currentRecipe = null;
	for(Object object : CraftingManager.getInstance().getRecipeList())
	{
		IRecipe recipe = (IRecipe) object;
		if(recipe.matches(invCrafting, worldObj))
		{
			currentRecipe = recipe;
		}
	}
}

private void updateOutput()
{
	burnTime = Math.max(burnTime - 1, 0);
	boolean flag = currentRecipe == null;
	flag = flag || currentRecipe.getRecipeOutput() == null;
	if(result != null)
	{
		flag = flag || !ItemStack.areItemsEqual(currentRecipe.getRecipeOutput(), result);
		flag = flag || !ItemStack.areItemStackTagsEqual(currentRecipe.getRecipeOutput(), result);
		flag = flag || result.stackSize > result.getMaxStackSize() - currentRecipe.getRecipeOutput().stackSize;
	}
	if(flag)
	{
		craftTime = 0;
	}
	else
	{
		if(!isBurning())
			craftTime = Math.max(craftTime - 2, 0);
		else
		{
			if(burnTime <= 0 && !getPowered())
			{
				burnTime = TileEntityFurnace.getItemBurnTime(fuelStack);
				maxBurnTime = burnTime;
				ItemStack stack = fuelStack.copy();
				decrStackSize(10, 1);
				if(stack.getItem().hasContainerItem(fuelStack))
				{
					ItemStack containerItem = stack.getItem().getContainerItem(fuelStack).copy();
					if(fuelStack == null)
						setInventorySlotContents(10, containerItem);
					else
					{
						EntityItem entity = new EntityItem(worldObj);
						entity.setLocationAndAngles(pos.getX() + 0.5, pos.getY() + 0.2, pos.getZ() + 0.5, 0, 0);
						entity.setEntityItemStack(containerItem);
						worldObj.spawnEntityInWorld(entity);
					}
				}
			}
			if(!getPowered()) craftTime++;
			if(craftTime >= MAX_CRAFT_TIME)
			{
				craftTime = 0;
				ItemStack recipeOutput = currentRecipe.getRecipeOutput();
				if(result == null)
					result = recipeOutput.copy();
				else result.stackSize += recipeOutput.stackSize;
				ItemStack[] additionalOutputs = CraftingManager.getInstance().func_180303_b(invCrafting, worldObj);
				for(int i = 0; i < 9; i++)
				{
					decrStackSize(i, 1);
					if(additionalOutputs[i] != null)
					{
						if(getStackInSlot(i) == null)
						{
							setInventorySlotContents(i, additionalOutputs[i]);
						}
						else
						{
							EntityItem entity = new EntityItem(worldObj);
							entity.setLocationAndAngles(pos.getX() + 0.5, pos.getY() + 0.2, pos.getZ() + 0.5, 0, 0);
							entity.setEntityItemStack(additionalOutputs[i]);
							worldObj.spawnEntityInWorld(entity);
						}

					}
				}
			}
		}
	}
	if(USE_PACKETS)
	{
		clientSyncTime++;
		if(clientSyncTime >= MAX_CLIENT_SYNC_TIME)
		{
			FarmersHeaven.NETWORK.sendToAll(new AutoCraftingTableUpdateMessage(this));
			clientSyncTime = 0;
		}
	}
}

void updateComparators()
{
	worldObj.updateComparatorOutputLevel(pos, worldObj.getBlockState(pos).getBlock());
	for(int x = -1; x <= 1; x++)
		for(int z = -1; z <= 1; z++)
		{
			BlockPos pos = new BlockPos(x, 1, z).add(this.pos);
			worldObj.updateComparatorOutputLevel(pos, worldObj.getBlockState(pos).getBlock());
		}
}

@Override
public int[] getSlotsForFace(EnumFacing side)
{
	return side == EnumFacing.DOWN ? new int[] { 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 10 }
		: (side == EnumFacing.UP ? new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8 } : new int[] { 10 });
}

@Override
public boolean canInsertItem(int index, ItemStack itemStack, EnumFacing direction)
{
	return isItemValidForSlot(index, itemStack);
}

@Override
public boolean canExtractItem(int index, ItemStack stack, EnumFacing direction)
{
	if(index == 9)
		return true;
	else if(index == 10)
		return !TileEntityFurnace.isItemFuel(getStackInSlot(10));
	else return currentRecipe == null;
}

public void setCustomName(String customName)
{
	this.customName = customName;
}

public boolean isCrafting()
{
	return craftTime > 0;
}

public int getScaleCraftingWidth(int maxWidth)
{
	return craftTime * maxWidth / MAX_CRAFT_TIME;
}

public boolean isBurning()
{
	return fuelStack != null || burnTime > 0;
}

public int getBurnTimeHeight(int maxHeight)
{
	if(maxBurnTime == 0) maxBurnTime = 200;
	return burnTime * maxHeight / maxBurnTime;
}

public boolean shouldRenderFlame()
{
	return isBurning() && burnTime > 0;
}
}

 

 

 

Pastebin:

Container: http://pastebin.com/jeUuyprm

Tile entity: http://pastebin.com/0KCpDqj3

 

Any idea what's going wrong? Thanks in advance for answers :)

catch(Exception e)

{

 

}

Yay, Pokémon exception handling, gotta catch 'em all (and then do nothing with 'em).

Link to comment
Share on other sites

What do you mean? getInventoryCrafting is there to get the InventoryCrafting object required by SlotCrafting. Am I missing something?

 

EDIT: If you're talking about the craftMatrix field in SlotCrafting (which I don't think you are), that's private and I don't see any getters

catch(Exception e)

{

 

}

Yay, Pokémon exception handling, gotta catch 'em all (and then do nothing with 'em).

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



×
×
  • Create New...

Important Information

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