Jump to content

[Solved][1.14.4] getShareTag+readShareTag enough to sync capability data to client?


Zorochase

Recommended Posts

Hello, again :/

 

In my last post I got up to the point where I needed to sync data for a capability attached to a custom sword to the client.

I spent what free time I had the past few days trying to figure out how to do this. I started a different mod separate from my

real project so that I could figure this out on a clean slate, here's its repository: https://github.com/Zorochase/CapabilityLearning1144

 

I read through this post, where it was explained that there are two ways to sync capability data to the client,

one way being to override getShareTag and readShareTag. In the mod above I created an example capability

that stores a couple values. The capability is attached to a BasicTestItem. I set up some keybinds

so I could see the values change in-game. In a singleplayer world, I can, for example, press a key to decrement

one of the values, leave and come back, and it remains as what it was changed to. However, in multiplayer,

I can change the value and see it change just as I can in singleplayer but it doesn't save when I leave. It just resets

to the initial value.

 

Here are my item's getShareTag and readShareTag methods:

    @Nullable
    @Override
    public CompoundNBT getShareTag(ItemStack stack) {
        CompoundNBT nbt = super.getShareTag(stack);
        if (nbt != null) {
            stack.getCapability(Capabilities.TEST_CAPABILITY_CAPABILITY).ifPresent(
                    (iTestCapability) -> {
                        nbt.putInt("testValueA", iTestCapability.getTestValueA());
                        nbt.putBoolean("testValueB", iTestCapability.getTestValueB());
                    }
            );
        }
        return nbt;
    }

    @Override
    public void readShareTag(ItemStack stack, @Nullable CompoundNBT nbt) {
        if (nbt != null) {
            stack.getCapability(Capabilities.TEST_CAPABILITY_CAPABILITY).ifPresent(
                    (iTestCapability -> {
                        iTestCapability.setTestValueA(nbt.getInt("testValueA"));
                        iTestCapability.setTestValueB(nbt.getBoolean("testValueB"));
                    })
            );
        }
    }

(I tried a different implementation for each, and commented them out. You can see the commented code in the repository.)

 

My questions are:

  • Is overriding getShareTag and readShareTag enough to sync an ItemStack's capability to the client?
    • If not, how and when do I send a packet to update the data?
      • (When I ask how, I'm not asking you to spoon-feed me code. I'd appreciate links to resources for learning this for modern Minecraft. Not for pre-1.12.2. And no, the docs aren't everything for a beginner like myself.)
    • If so, what's wrong with the code I wrote? Am I missing anything?
  • Am I correct in assuming syncing the data to the client is how the data is saved?

As always, any help I may get will be appreciated.

Edited by Zorochase
Link to comment
Share on other sites

10 hours ago, diesieben07 said:

You don't want this.

For this to work your item would have to have an NBT tag, which is not always true. You have to also handle the case where the default getShareTag (which is just ItemStack#getTag) returns null.

 

Your readShareTag is also invalid, it must handle the default NBT data. getShareTag must always be an extension to ItemStack#getTag and readShareTag must treat it like so. Also refer to the documentation on getShareTag.

 

No. The client does not save data.

 

Here's what I changed them to:

    @Nullable
    @Override
    public CompoundNBT getShareTag(ItemStack stack) {
        CompoundNBT nbt = stack.getOrCreateTag();
        stack.getCapability(Capabilities.TEST_CAPABILITY_CAPABILITY).ifPresent(
                handler -> {
                    nbt.put("cap_sync", Objects.requireNonNull(Capabilities.TEST_CAPABILITY_CAPABILITY.writeNBT(handler, null)));
                }
        );
        return nbt;
    }

    @Override
    public void readShareTag(ItemStack stack, @Nullable CompoundNBT nbt) {
        super.readShareTag(stack, nbt);

        if (nbt != null) {
            stack.getCapability(Capabilities.TEST_CAPABILITY_CAPABILITY).ifPresent(
                    handler -> {
                        Capabilities.TEST_CAPABILITY_CAPABILITY.readNBT(handler, null, nbt.get("cap_sync"));
                    }
            );
        }
    }

 

This works in both singleplayer and multiplayer, but only when I move the item to a different slot in my inventory after pressing the key to decrement testValueA. Chances are I'm either still not grasping something about what you said or my keypress code is wrong (if anything when I get the player's currently held stack).

 

Link to comment
Share on other sites

2 hours ago, diesieben07 said:

If you want to change data in response to a key press send a packet to the server when the key is pressed and take the appropriate action (including precautions: always treat the client as a lying bastard) there.

Just as you said, sending the packet worked. The data now syncs correctly. Thanks for your help!

Link to comment
Share on other sites

  • Zorochase changed the title to [Solved][1.14.4] getShareTag+readShareTag enough to sync capability data to client?

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.

×
×
  • Create New...

Important Information

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