Tavi007 Posted November 17, 2020 Posted November 17, 2020 Hello! I have an Itemstack capability on client and server side and I want the client one syncronised with the server. Overriding Item#getShareTag and Item#readShareTag is not possible, because the capability is attached to every itemstack. With the help of google I found 2 answers to my question, however I'm struggling with implementation. The first solution I found was to send packaged through a simpleChannel. I know the basics of this method, because I succesfully implemented this type of networking for my entity capability. My problem is, that I don't know, when I would have to send the message. You can look at my code on this branch here for more details: https://github.com/Tavi007/ElementalCombat/tree/ItemSync-via-packets/src/main/java/Tavi007/ElementalCombat (check out the network package). For the entity one I knew the events, that were relevant, so I knew, when stuff would change. For Itemstack I do not know this yet. The second solution was to implement a containerListener, just like Choonsters did in his TestMod3. In an attempt to understand the code I copied his code, did some changes and somehow got it working. To be frank, I still don't fully understand his code, but it did sync up the capability. What's weird is, that I never specified to just sync up my capability nor did I define a message for it. I'm afraid, that this will cause issues with other mods down the line. (Also I don't like the fact, that I don't know, what my code is doing). You can look up the code for this attempt on this branch: https://github.com/Tavi007/ElementalCombat/tree/ItemSync-via-Listener/src/main/java/Tavi007/ElementalCombat (check out the capability and network package). Can someone please elaborate how this type of networking usually works? Quote
Tavi007 Posted November 17, 2020 Author Posted November 17, 2020 4 hours ago, Tavi007 said: To be frank, I still don't fully understand his code, but it did sync up the capability. What's weird is, that I never specified to just sync up my capability nor did I define a message for it. Just tested this part again and now the itemstack won't sync up. I swear they did before... Quote
Tavi007 Posted November 19, 2020 Author Posted November 19, 2020 Bump. To rephrase my question: How can I syncronize itemstack capabilities without using Item#getShareTag/readShareTag? Are there some vanilla classes/ example mods, that implemented container listener, so I can check them out? Quote
Tavi007 Posted November 19, 2020 Author Posted November 19, 2020 Since I attach my capability to every item, how could I synchronize it for lets say the vanilla iron sword? Quote
Tavi007 Posted November 19, 2020 Author Posted November 19, 2020 Well that sucks. I found this thread which seems to have a work around with a container listener (hence why I mentioned it in the op). Do you know more on this topic? Cause I don't fully understand it yet. Quote
Tavi007 Posted November 19, 2020 Author Posted November 19, 2020 It's just for displaying the data as tooltip. Also the data doesn't change that often, so it wouldn't need to be syncronized continously. Quote
Tavi007 Posted November 19, 2020 Author Posted November 19, 2020 Sooo... 57 minutes ago, Tavi007 said: Do you know more on this topic? Cause I don't fully understand it yet. Quote
Choonster Posted November 20, 2020 Posted November 20, 2020 With my system, each capability type that needs to be synced to the client has several sync-related classes: A single update network message (extending UpdateContainerCapabilityMessage) that syncs the capability data for a single slot of a Container. A bulk update network message (extending BulkUpdateContainerCapabilityMessage) that syncs the capability data for all slots of a Container. A "functions" class containing static methods used by both the single and bulk update messages. A container listener class (extending CapabilityContainerListener) that sends the single/bulk update messages when the Container's contents change. A factory function for the container listener is registered with CapabilityContainerListenerManager.registerListenerFactory at startup so that when a player opens a Container, a new listener can be created and added to it. The network messages have the concept of a "data" class, which is a simple POJO (or even a primitive type like int or long) containing only the data that needs to be synced from the server to the client. The base classes for the messages handle the functionality that's common to all capability types, the message classes for each capability just need to provide functions to do the following: On the server: Convert an instance of the capability handler (e.g. IFluidHandlerItem for a fluid tank) to a data object Encode (write) the data object to the packet buffer On the client: Decode (read) the data object from the packet buffer Apply the data from the data object to the capability handler instance These functions could be defined anywhere (they could even be lambdas passed directly to the base class methods), but I keep them as static methods in a "functions" class so they can be shared between the single and bulk messages. The system might be a bit over-engineered, but it means that I can easily add syncing for a new item capability without having to rewrite all the common syncing logic. There are several implementations of this in TestMod3 that you could use as examples: ILastUseTime, which tracks the time at which an item was last used. This is a simple implementation that syncs a single long value to the client, so it uses Long as its data class. Single update message Bulk update message Functions class Container listener Container listener registration (called during FMLCommonSetupEvent) IFluidHandlerItem, Forge's fluid tank capability. This is a slightly more complex implementation that syncs a FluidStack (the tank contents) and an int (the tank capacity), so it uses FluidTankSnapshot as its data class. Single update message Bulk update message Functions class Container listener (only syncs data for my own fluid tank item, to avoid conflicts with other mods' fluid handler items) Container listener registration (called during FMLCommonSetupEvent) 2 Quote Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.
Tavi007 Posted November 23, 2020 Author Posted November 23, 2020 Thank you so much for such an in depth answer! I think, I should be able to modify your code now (cause I really only have 2 capabilities, so my system doesn't have to be as flexible as yours) Quote
Tavi007 Posted December 3, 2020 Author Posted December 3, 2020 (edited) Hey, so tried to implement what you said and I got it mostly working, but there is one last bug remaining. When I open the play inventory, the itemstacks won't get updated immediately. I have to move the itemstack at least once for it to update. Any other container is working as intended tho. If I open a chest, every itemstack has the right information directly. Any idea what the reason might be? Could it have to do something with the curios mod, which I'm using while developing? Some links of my github: https://github.com/Tavi007/ElementalCombat/tree/master/src/main/java/Tavi007/ElementalCombat/capabilities https://github.com/Tavi007/ElementalCombat/tree/master/src/main/java/Tavi007/ElementalCombat/network Edited December 3, 2020 by Tavi007 Quote
Tavi007 Posted December 8, 2020 Author Posted December 8, 2020 Bump. I really hope someone knows more about this stuf. This is basically the last hurdle for my mod and I would really like to have a proper release in this year. Quote
Choonster Posted December 8, 2020 Posted December 8, 2020 On 12/4/2020 at 5:39 AM, Tavi007 said: Hey, so tried to implement what you said and I got it mostly working, but there is one last bug remaining. When I open the play inventory, the itemstacks won't get updated immediately. I have to move the itemstack at least once for it to update. Any other container is working as intended tho. If I open a chest, every itemstack has the right information directly. Any idea what the reason might be? Could it have to do something with the curios mod, which I'm using while developing? Some links of my github: https://github.com/Tavi007/ElementalCombat/tree/master/src/main/java/Tavi007/ElementalCombat/capabilities https://github.com/Tavi007/ElementalCombat/tree/master/src/main/java/Tavi007/ElementalCombat/network It looks like Forge patches Container#detectAndSendChanges to only call IContainerListener#sendSlotContents if a slot's Item, count or share tag has changed; which often won't be the case for capability-only updates. I may need to re-evaluate the IContainerListener system to see if there's any way around this. This change was actually introduced in August 2017 for 1.12.2, six months after I created my system. I thought it was working more recently than that, but I must not have tested it properly. Quote Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.
Choonster Posted December 17, 2020 Posted December 17, 2020 (edited) I've had a brief look at this and can't see any easy way to work around it, so I've created a suggestion thread for a change here: I'm not sure if it will go anywhere. Edited December 17, 2020 by Choonster Quote Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.
Recommended Posts
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.