Zorochase Posted March 1, 2020 Share Posted March 1, 2020 (edited) 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 March 1, 2020 by Zorochase Quote Link to comment Share on other sites More sharing options...
Zorochase Posted March 2, 2020 Author Share Posted March 2, 2020 Further testing revealed it only sometimes works in singleplayer... It can take anywhere between 1-4 attempts before it actually saves. What is going on?? Quote Link to comment Share on other sites More sharing options...
Zorochase Posted March 2, 2020 Author Share Posted March 2, 2020 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). Quote Link to comment Share on other sites More sharing options...
Zorochase Posted March 2, 2020 Author Share Posted March 2, 2020 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! Quote Link to comment Share on other sites More sharing options...
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.