Jump to content

[1.16] syncronising itemstack capabilities for any item


Tavi007

Recommended Posts

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?

Link to comment
Share on other sites

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...

Link to comment
Share on other sites

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:

  • Thanks 2

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.

Link to comment
Share on other sites

  • 2 weeks later...

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 by Tavi007
Link to comment
Share on other sites

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.

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.

Link to comment
Share on other sites

  • 2 weeks later...

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 by Choonster

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.

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.