Jump to content
  • Home
  • Files
  • Docs
Topics
  • All Content

  • This Topic
  • This Forum

  • Advanced Search
  • Existing user? Sign In  

    Sign In



    • Not recommended on shared computers


    • Forgot your password?

  • Sign Up
  • All Activity
  • Home
  • Mod Developer Central
  • Modder Support
  • [1.16] syncronising itemstack capabilities for any item
Currently Supported: 1.16.X (Latest) and 1.15.X (LTS)
Sign in to follow this  
Followers 0
Tavi007

[1.16] syncronising itemstack capabilities for any item

By Tavi007, November 17, 2020 in Modder Support

  • Reply to this topic
  • Start new topic

Recommended Posts

Tavi007    1

Tavi007

Tavi007    1

  • Stone Miner
  • Tavi007
  • Members
  • 1
  • 93 posts
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

Share this post


Link to post
Share on other sites

Tavi007    1

Tavi007

Tavi007    1

  • Stone Miner
  • Tavi007
  • Members
  • 1
  • 93 posts
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

Share this post


Link to post
Share on other sites

Tavi007    1

Tavi007

Tavi007    1

  • Stone Miner
  • Tavi007
  • Members
  • 1
  • 93 posts
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

Share this post


Link to post
Share on other sites

diesieben07    7581

diesieben07

diesieben07    7581

  • Reality Controller
  • diesieben07
  • Forum Team
  • 7581
  • 54893 posts
Posted November 19, 2020

getShareTag and readShareTag is the only possible way.

ItemStacks are sent over the network from so many different places that it is impossible to do this without a hook into the fundamental "serialize this itemstack" functionality. getShareTag is this hook.

  • Quote

Share this post


Link to post
Share on other sites

Tavi007    1

Tavi007

Tavi007    1

  • Stone Miner
  • Tavi007
  • Members
  • 1
  • 93 posts
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

Share this post


Link to post
Share on other sites

diesieben07    7581

diesieben07

diesieben07    7581

  • Reality Controller
  • diesieben07
  • Forum Team
  • 7581
  • 54893 posts
Posted November 19, 2020

You can't with the hooks that are in place currently.

Something like this would be needed: https://github.com/MinecraftForge/MinecraftForge/pull/6954

  • Quote

Share this post


Link to post
Share on other sites

Tavi007    1

Tavi007

Tavi007    1

  • Stone Miner
  • Tavi007
  • Members
  • 1
  • 93 posts
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

Share this post


Link to post
Share on other sites

diesieben07    7581

diesieben07

diesieben07    7581

  • Reality Controller
  • diesieben07
  • Forum Team
  • 7581
  • 54893 posts
Posted November 19, 2020

It's hack which might work for certain situations.

When, how and why does the client need this data? It depends on this for how you approach this.

  • Quote

Share this post


Link to post
Share on other sites

Tavi007    1

Tavi007

Tavi007    1

  • Stone Miner
  • Tavi007
  • Members
  • 1
  • 93 posts
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

Share this post


Link to post
Share on other sites

diesieben07    7581

diesieben07

diesieben07    7581

  • Reality Controller
  • diesieben07
  • Forum Team
  • 7581
  • 54893 posts
Posted November 19, 2020

Then the container hack could work.

  • Quote

Share this post


Link to post
Share on other sites

Tavi007    1

Tavi007

Tavi007    1

  • Stone Miner
  • Tavi007
  • Members
  • 1
  • 93 posts
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.

:D

  • Quote

Share this post


Link to post
Share on other sites

diesieben07    7581

diesieben07

diesieben07    7581

  • Reality Controller
  • diesieben07
  • Forum Team
  • 7581
  • 54893 posts
Posted November 20, 2020

I don't. I looked a bit at the code you have and it's just massively overengineered in my opinion.

  • Quote

Share this post


Link to post
Share on other sites

hohserg    3

hohserg

hohserg    3

  • Tree Puncher
  • hohserg
  • Members
  • 3
  • 39 posts
Posted November 20, 2020

Doesn't that work such?

image.png.2301034e4b597d2aee45ee7b68dce150.png

  • Quote

Share this post


Link to post
Share on other sites

Choonster    1651

Choonster

Choonster    1651

  • Reality Controller
  • Choonster
  • Forge Modder
  • 1651
  • 5097 posts
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)
  • Thanks 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.

Share this post


Link to post
Share on other sites

Tavi007    1

Tavi007

Tavi007    1

  • Stone Miner
  • Tavi007
  • Members
  • 1
  • 93 posts
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

Share this post


Link to post
Share on other sites

Tavi007    1

Tavi007

Tavi007    1

  • Stone Miner
  • Tavi007
  • Members
  • 1
  • 93 posts
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

Share this post


Link to post
Share on other sites

Tavi007    1

Tavi007

Tavi007    1

  • Stone Miner
  • Tavi007
  • Members
  • 1
  • 93 posts
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

Share this post


Link to post
Share on other sites

Choonster    1651

Choonster

Choonster    1651

  • Reality Controller
  • Choonster
  • Forge Modder
  • 1651
  • 5097 posts
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.

Share this post


Link to post
Share on other sites

Choonster    1651

Choonster

Choonster    1651

  • Reality Controller
  • Choonster
  • Forge Modder
  • 1651
  • 5097 posts
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.

Share this post


Link to post
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.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  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.

    • Insert image from URL
×
  • Desktop
  • Tablet
  • Phone
Sign in to follow this  
Followers 0
Go To Topic Listing



  • Recently Browsing

    No registered users viewing this page.

  • Posts

    • Ironhead_
      Failure message: Missing License Information in file Mod File

      By Ironhead_ · Posted 31 minutes ago

      I'm playing on 1.14.4 and am only using the create mod, however I'm having to resort to adding JEI to see some recipes I'm stuck on. it doesn't let me use JEI without a licence
    • diesieben07
      (1.16.2) How do I use onPlayerTick?

      By diesieben07 · Posted 40 minutes ago

      This will immediately crash the game, there are not just server side entities. The fact that it doesn't mean your event handler is not even running. It is not running, because @EventBusSubscriber only works with static event handler methods.
    • diesieben07
      7 FPS with a GT 1030 + i5-4690 (1.16.3)

      By diesieben07 · Posted 42 minutes ago

      "Forge fix your terrible performance! this is horrible!" "Oh, I was using a mod that hugely increases render and world simulation load. sorry!"   Gotta love it how people jump to conclusions that with "just" 90 mods installed it must surely be Forge at fault.
    • XenoPyax
      I can't find any guide or wiki docs

      By XenoPyax · Posted 44 minutes ago

      Ah okay thanks
    • diesieben07
      [1.15.2] Change player name in Tab List (Player List)

      By diesieben07 · Posted 44 minutes ago

      No, it exists in 1.16.4 and also 1.15.2.   Make those Field fields static. You need to create the packet first and store it in a variable, so you can work with it. Don't immediately send it. You need to then get the list of AddPlayerData instances from the packet. For this you get the "players" field, using the reflection Field you have already. Then for those AddPlayerData instances you need to set their displayName field, again using reflection. You need to set it, because Minecraft never sends any custom display name to the client - even though it has the network infrastructure to do so (SPlayerListItemPacket). It always just sends null for the display name, even if a custom display name is set.
  • Topics

    • arkeN
      48
      Failure message: Missing License Information in file Mod File

      By arkeN
      Started October 11, 2020

    • e2rifia
      1
      (1.16.2) How do I use onPlayerTick?

      By e2rifia
      Started 55 minutes ago

    • PotatoEz1
      4
      7 FPS with a GT 1030 + i5-4690 (1.16.3)

      By PotatoEz1
      Started 2 hours ago

    • XenoPyax
      2
      I can't find any guide or wiki docs

      By XenoPyax
      Started 1 hour ago

    • Babatunde
      14
      [1.15.2] Change player name in Tab List (Player List)

      By Babatunde
      Started Thursday at 12:42 AM

  • Who's Online (See full list)

    • Ironhead_
    • XenoPyax
    • FreshMod
    • Ronshark
    • LexManos
    • kiou.23
    • Kikoz
    • notesmee
    • FlashHUN
  • All Activity
  • Home
  • Mod Developer Central
  • Modder Support
  • [1.16] syncronising itemstack capabilities for any item
  • Theme

Copyright © 2019 ForgeDevelopment LLC · Ads by Longitude Ads LLC Powered by Invision Community