Posted April 6, 20196 yr Hello, all! I'm currently trying to develop a server-compatible mod for the first time, and I'm having some massive issues with my IItemHandler capability for a tileentity not properly syncing from the server to the client. It runs fine in singleplayer-- the inventory has expected behavior, as seen here: Everything seems to be working fine. I can drag stacks around, they register in the top, etc. No issues. (placeholder gui and .lang isn't set up, I know XD) But when I host from a server and connect to it... Clicking the item just ends with it glitching immediately back into its slot. Shift-clicking duplicates the item into the slot as a ghost item, which immediately disappears when clicked on. So this is definitely a big issue. One of the most requested features I had for the mod was server compatibility, so I'm not about to just give up, however this is my first experience with servers and there seem to be few good explanations/examples of how this even works. As I understand, IItemHandler doesn't automatically sync with the client the way IInventory does, but IInventory is an older, outdated method that's not the most effective one to use from what I've read. It sounds like I need to set up a packet system to sync the server to the client and back again, but I have very little idea of how to do that with an inventory. I've used packets before, but only ever for simple variables (i.e. ints and stuff), and I don't necessarily know enough about the inventories to know where I'd need to call/send these packets. So if anyone has experience/advice here, I would definitely appreciate it. If at all possible, I'd like to make this setup reusable-- though if that's not easily possible I understand. I want to keep the mod as clean as possible, without reusing code if I can help it, so if there's some way I can set this up automatically for future TileEntity inventories (i.e. a custom extension of the container class? Some way to automatically sync through my custom slot base class?) that is definitely preferable. Current code: Block TileEntity Container GUI GUIHandler I do use a custom slot class, but the only thing I added is a restriction for isItemValid (the slot is a food bowl, so I've restricted it to only accept my kibble items). You can see that code here: @Override public boolean isItemValid(ItemStack stack) { if (stack.isEmpty() || !(stack.getItem() instanceof ItemKibble)) return false; IItemHandler handler = this.getItemHandler(); ItemStack remainder; if (handler instanceof IItemHandlerModifiable) { IItemHandlerModifiable handlerModifiable = (IItemHandlerModifiable) handler; ItemStack currentStack = handlerModifiable.getStackInSlot(index); handlerModifiable.setStackInSlot(index, ItemStack.EMPTY); remainder = handlerModifiable.insertItem(index, stack, true); handlerModifiable.setStackInSlot(index, currentStack); } else { remainder = handler.insertItem(index, stack, true); } return remainder.isEmpty() || remainder.getCount() < stack.getCount(); } Thank you so much for your time, and have a great day!
April 6, 20196 yr Why are you using 1.11? Update. Quote public class BlockFoodDish extends BlockWildCraft implements ITileEntityProvider Don't use ITileEntityProvider, it is outdated and unnecesarry. Just override Block#hasTileEntity and Block#createTileEntity. Also blockbase is an anti-pattern. Don't invoke EntityPlayer#openGui on the client at all. Forge will do the networking for you. This is likely the cause of your issue. Your health property is lost upon (de)serialization. You should probably include this in your (de)serialization methods too. public int quantityDropped(Random random) { return 1; } The default implementation already returns 1. Why did you override it? Quote Integer.valueOf(MathHelper.clamp(level, 0, 3))) MathHelper.clamp already returns an int. Why do you need to ask the Integer class to get the value from it? Quote return ((Integer)state.getValue(FULLNESS)).intValue(); Same here. Quote this.FULLNESS.equals(fullness); ...What? FULLNESS is static thus your IDE should be screaming at you for using this access keyword. Also why are you comparing it to the argument? You do know that Object#equals returns a boolean that indicates the result of comparing two objects. Quote this.HEALTH.equals(health); Same here. if (tileentity != null) { tileentity.validate(); worldIn.setTileEntity(pos, tileentity); } You don't need to do this. Just override TileEntity#shouldRefresh in your TE class. Actually you are already doing that so there is no need for this code at all. Quote public class TileEntityFoodDish extends TileEntity implements ICapabilityProvider TileEntity already implements ICapabilityProvider. You don't need to add this interface again. Quote BlockFoodDish blockfooddish; Blocks are singletons. You can use @ObjectHolder to get the reference if you need it. int metadata = getBlockMetadata(); return new SPacketUpdateTileEntity(this.pos, metadata, nbt); This is not what that parameter wants from you. As you are using a modded TE you can pass anything to it. public BlockFoodDish getFoodDish() { return this.blockfooddish; } Again, blocks are singletons. You do not need to store a block reference in each instance of your TE. Quote this.blockType = this.getBlockType(); ...Why? It is already set to that.
April 6, 20196 yr Author I announced that I'll be releasing the complete version of the mod's first update in 1.11, so I'll be continuing to work in 1.11 for now. There are a couple things here that were added unnecessarily, I'll take a look at those-- some can probably be deleted, while others may be for things I intend to alter later. I will definitely take a look at the EntityPlayer#openGUI part, as if that is the cause then this may be a simple fix. I'll update this later when I've had time to take a look at these suggestions. Thank you for your advice.
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.