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
  • [Solved][1.16.4] How do I correctly sync capability data between Client and server?
Currently Supported: 1.16.X (Latest) and 1.15.X (LTS)
Sign in to follow this  
Followers 2
LK1905

[Solved][1.16.4] How do I correctly sync capability data between Client and server?

By LK1905, December 31, 2020 in Modder Support

  • Reply to this topic
  • Start new topic
  • Prev
  • 1
  • 2
  • Next
  • Page 1 of 2  

Recommended Posts

LK1905    0

LK1905

LK1905    0

  • Tree Puncher
  • LK1905
  • Members
  • 0
  • 27 posts
Posted December 31, 2020

Hi, I'm having problems syncing my mod's capability data. There's no errors/crashes or anything, but my code doesn't appear to be doing anything, as reloading the world resets all data values to zero. so I was wondering if someone could look at my code to see if I'm doing anything wrong, or am missing anything.

 

My event handler:

package lk1905.gielinorcraft;

import lk1905.gielinorcraft.api.skill.ISkills;
import lk1905.gielinorcraft.capability.skill.SkillCapability;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.event.entity.player.PlayerEvent;
import net.minecraftforge.event.entity.player.PlayerEvent.PlayerChangedDimensionEvent;
import net.minecraftforge.event.entity.player.PlayerEvent.PlayerLoggedInEvent;
import net.minecraftforge.event.entity.player.PlayerEvent.PlayerRespawnEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;

@Mod.EventBusSubscriber(modid = Gielinorcraft.MODID, bus = Mod.EventBusSubscriber.Bus.FORGE)
public class EventHandler {

	@SubscribeEvent
	public static void onPlayerClone(PlayerEvent.Clone event) {
		
		LazyOptional<ISkills> oldCap = event.getOriginal().getCapability(SkillCapability.SKILL_CAP, null);
		LazyOptional<ISkills> newCap = event.getPlayer().getCapability(SkillCapability.SKILL_CAP, null);
		ISkills oldSkills = oldCap.orElse(null);
		
		if(oldSkills != null) {
			ISkills newSkills = newCap.orElse(null);
			
			if(newSkills != null) {
				
				for(int i = 0; i < 26; i++) {
					newSkills.setXp(i, oldSkills.getXp(i));
					newSkills.setStaticLevel(i, oldSkills.getStaticLevel(i));
					newSkills.setLevel(i, oldSkills.getLevel(i));
				}
			}
		}
	}
	
	@SubscribeEvent
	public static void onPlayerChangedDimensionEvent(PlayerChangedDimensionEvent event) {
		ServerPlayerEntity player = (ServerPlayerEntity) event.getPlayer();
		if(!player.world.isRemote) {
			player.getCapability(SkillCapability.SKILL_CAP).ifPresent(c -> c.sync(player));
		}
	}
	
	@SubscribeEvent
	public static void onRespawnEvent(PlayerRespawnEvent event) {
		if(!event.getPlayer().world.isRemote) {
			event.getPlayer().getCapability(SkillCapability.SKILL_CAP).ifPresent(c -> c.sync((ServerPlayerEntity) event.getPlayer()));
		}
	}
	
	@SubscribeEvent
	public static void onPlayerConnect(PlayerLoggedInEvent event) {
		ServerPlayerEntity player = (ServerPlayerEntity) event.getPlayer();
		if(!player.world.isRemote) {
			player.getCapability(SkillCapability.SKILL_CAP).ifPresent(c -> c.sync(player));
		}
	}
}

 

My packet handler:

package lk1905.gielinorcraft.network;

import java.util.List;

import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.common.util.FakePlayer;
import net.minecraftforge.fml.network.NetworkDirection;
import net.minecraftforge.fml.network.NetworkRegistry;
import net.minecraftforge.fml.network.simple.SimpleChannel;

public class PacketHandler {

	private static final String PROTOCOL_VERSION = Integer.toString(1);
	private static final SimpleChannel HANDLER = NetworkRegistry.ChannelBuilder
												.named(new ResourceLocation("gielinorcraft", "main_channel"))
												.clientAcceptedVersions(PROTOCOL_VERSION::equals)
												.serverAcceptedVersions(PROTOCOL_VERSION::equals)
												.networkProtocolVersion(() -> PROTOCOL_VERSION)
												.simpleChannel();
	public static void register() {
		int disc = 0;
		HANDLER.registerMessage(disc++,
				SkillsPacket.class,
				SkillsPacket::encode,
				SkillsPacket::decode,
				SkillsPacket.Handler::handle);
	}
	
	/**
	 * Sends a packet to a specific player.<br>
	 * Must be called server side.
	 * */
	public static void sendTo(Object msg, ServerPlayerEntity player) {
		if(!(player instanceof FakePlayer)) {
			HANDLER.sendTo(msg, player.connection.netManager, NetworkDirection.PLAY_TO_CLIENT);
		}
	}
	
	/**
	 * Sends a packet to the server.<br>
	 * Must be called client side.
	 * */
	public static void sendToServer(Object msg) {
		HANDLER.sendToServer(msg);
	}
	
	/**Server side.*/
	public static void sendToAllPlayers(Object msg, MinecraftServer server) {
		List<ServerPlayerEntity> list = server.getPlayerList().getPlayers();
		for(ServerPlayerEntity e : list) {
			sendTo(msg, e);
		}
	}
}

 

The packet class for my capability:

package lk1905.gielinorcraft.network;

import java.util.function.Supplier;

import lk1905.gielinorcraft.capability.skill.SkillCapability;
import net.minecraft.client.Minecraft;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.network.PacketBuffer;
import net.minecraftforge.fml.network.NetworkEvent;

public class SkillsPacket {

	private final CompoundNBT nbt;
	
	public SkillsPacket(CompoundNBT nbt) {
		this.nbt = nbt;
	}
	
	public static void encode(SkillsPacket msg, PacketBuffer buf) {
		buf.writeCompoundTag(msg.nbt);
	}
	
	public static SkillsPacket decode(PacketBuffer buf) {
		return new SkillsPacket(buf.readCompoundTag());
	}
	
	public static class Handler{
		public static void handle(final SkillsPacket msg, Supplier<NetworkEvent.Context> ctx) {
		
			Minecraft mc = Minecraft.getInstance();
			
			ctx.get().enqueueWork(() -> {
				
				mc.player.getCapability(SkillCapability.SKILL_CAP).ifPresent(cap -> cap.deserializeNBT(msg.nbt));
				
			});
			ctx.get().setPacketHandled(true);
		}
	}
}

 

All other code is here.

 

 

  • Quote

Share this post


Link to post
Share on other sites

poopoodice    117

poopoodice

poopoodice    117

  • Dragon Slayer
  • poopoodice
  • Members
  • 117
  • 927 posts
Posted December 31, 2020

I don't know if this is intentional but in your SkillStorage, method writeNBT you kept rewrite/override the value of "xp", "static", and "dynamic".

I guess what you are trying to do here is something like:

		for(int i = 0; i < 26; i++) 
        	{
			data.putInt("xp" + i, (int) instance.getXp(i) * 10);
			data.putInt("static" + i, instance.getStaticLevel(i));
			data.putInt("dynamic" + i, instance.getLevel(i));
		}

so does writeNBT(), you assign the same value to every slot or whatever it is.

  • Thanks 1
  • Quote

Share this post


Link to post
Share on other sites

LK1905    0

LK1905

LK1905    0

  • Tree Puncher
  • LK1905
  • Members
  • 0
  • 27 posts
Posted December 31, 2020

I don't think there's anything wrong with the SkillStorage, as I can gain xp just fine, in the correct skills, the data is just reset to zero when i close and reopen the world.

 

I also have the "Hitpoints" skill set to level 10 and 1154 xp by default. If I comment out my PlayerLoggedInEvent, the skill is correctly set to those values in game, and is reset to those values when I leave the world. But with the event enabled, both the level and xp values are set to 1 and 0.

  • Quote

Share this post


Link to post
Share on other sites

Sainthozier    0

Sainthozier

Sainthozier    0

  • Tree Puncher
  • Sainthozier
  • Members
  • 0
  • 6 posts
Posted December 31, 2020
On 1/6/2020 at 10:28 AM, diesieben07 said:

If you want the data to be available to the client who's player it is attached to:

  • Send the data to the player in PlayerLoggedInEvent, PlayerRespawnEvent and PlayerChangedDimensionEvent.
  • Send the data to the player whenever it changes.

Don't forget to sync your capability data in Skills#addExp otherwise you wouldn't see any changes before those events.

  • Quote

Share this post


Link to post
Share on other sites

LK1905    0

LK1905

LK1905    0

  • Tree Puncher
  • LK1905
  • Members
  • 0
  • 27 posts
Posted December 31, 2020
1 hour ago, Sainthozier said:

Don't forget to sync your capability data in Skills#addExp otherwise you wouldn't see any changes before those events.

This is probably a stupid question, but how would I do that? I tried adding it to SkillStorage the same way I have the getXP, getLevel and getStaticLevel methods, but that made no difference. Is that what you meant, or something different?

  • Quote

Share this post


Link to post
Share on other sites

poopoodice    117

poopoodice

poopoodice    117

  • Dragon Slayer
  • poopoodice
  • Members
  • 117
  • 927 posts
Posted December 31, 2020
1 hour ago, LK1905 said:

the data is just reset to zero when i close and reopen the world.

The data are being read/write when world is loading/saving, if there's something wrong with it the whole thing is messed up.

  • Quote

Share this post


Link to post
Share on other sites

Sainthozier    0

Sainthozier

Sainthozier    0

  • Tree Puncher
  • Sainthozier
  • Members
  • 0
  • 6 posts
Posted December 31, 2020
1 hour ago, LK1905 said:

but how would I do that?

Just call your sync method whenever the data changes.

  • Quote

Share this post


Link to post
Share on other sites

LK1905    0

LK1905

LK1905    0

  • Tree Puncher
  • LK1905
  • Members
  • 0
  • 27 posts
Posted January 1
12 hours ago, Sainthozier said:

Just call your sync method whenever the data changes.

I added it into the AddXP method like this:

if(entity instanceof PlayerEntity) {
			sync((ServerPlayerEntity) entity);
		}

That didn't make any difference. Is that what you meant?

  • Quote

Share this post


Link to post
Share on other sites

diesieben07    7696

diesieben07

diesieben07    7696

  • Reality Controller
  • diesieben07
  • Forum Team
  • 7696
  • 56382 posts
Posted January 1

This is entirely broken. You are reaching across logical sides. Even if you were on the client here, you must modify capability data on the server, if you want it to persist. Only the server saves data.

  • Quote

Share this post


Link to post
Share on other sites

LK1905    0

LK1905

LK1905    0

  • Tree Puncher
  • LK1905
  • Members
  • 0
  • 27 posts
Posted January 2
13 hours ago, diesieben07 said:

This is entirely broken. You are reaching across logical sides. Even if you were on the client here, you must modify capability data on the server, if you want it to persist. Only the server saves data.

I changed that part to this:

		PlayerEntity player = (PlayerEntity) event.getSource().getTrueSource();
		LazyOptional<ISkills> cap = player.getCapability(SkillCapability.SKILL_CAP);
		ISkills skills = cap.orElse(null);

But now I can't gain xp at all. Is that the correct way of doing it?

  • Quote

Share this post


Link to post
Share on other sites

diesieben07    7696

diesieben07

diesieben07    7696

  • Reality Controller
  • diesieben07
  • Forum Team
  • 7696
  • 56382 posts
Posted January 2

What makes you think you are not gaining XP? How have you checked?

  • Quote

Share this post


Link to post
Share on other sites

LK1905    0

LK1905

LK1905    0

  • Tree Puncher
  • LK1905
  • Members
  • 0
  • 27 posts
Posted January 3
11 hours ago, diesieben07 said:

What makes you think you are not gaining XP? How have you checked?

My GUI doesn't update the xp values.

 

This is how I reference the player in my GUI:

	private PlayerEntity player = Minecraft.getInstance().player;
	private LazyOptional<ISkills> cap = player.getCapability(SkillCapability.SKILL_CAP);
	private ISkills skills = cap.orElse(null);

Do I need to reference the Server Player instead? If so, how?

 

Or Is the client player already supposed to know my server player data from my events/packets? If so, why aren't they working? They're in the OP.

  • Quote

Share this post


Link to post
Share on other sites

diesieben07    7696

diesieben07

diesieben07    7696

  • Reality Controller
  • diesieben07
  • Forum Team
  • 7696
  • 56382 posts
Posted January 3

You need to sync the data to the client, so that the client has them.

  • Quote

Share this post


Link to post
Share on other sites

LK1905    0

LK1905

LK1905    0

  • Tree Puncher
  • LK1905
  • Members
  • 0
  • 27 posts
Posted January 3

But as far as I know, my packet and event handler are already supposed to sync it. Which is why I made this thread, to ask why they aren't.

  • Quote

Share this post


Link to post
Share on other sites

diesieben07    7696

diesieben07

diesieben07    7696

  • Reality Controller
  • diesieben07
  • Forum Team
  • 7696
  • 56382 posts
Posted January 3

Post a git repo of your mod.

  • Quote

Share this post


Link to post
Share on other sites

LK1905    0

LK1905

LK1905    0

  • Tree Puncher
  • LK1905
  • Members
  • 0
  • 27 posts
Posted January 4
12 hours ago, diesieben07 said:

Post a git repo of your mod.

https://github.com/LK1905/GielinorCraft

  • Quote

Share this post


Link to post
Share on other sites

diesieben07    7696

diesieben07

diesieben07    7696

  • Reality Controller
  • diesieben07
  • Forum Team
  • 7696
  • 56382 posts
Posted January 4

You always create your Skills instance using a null entity. Hence the instance never syncs to the client.

  • Quote

Share this post


Link to post
Share on other sites

LK1905    0

LK1905

LK1905    0

  • Tree Puncher
  • LK1905
  • Members
  • 0
  • 27 posts
Posted January 4

Is that this part?

	public static void register() {
		CapabilityManager.INSTANCE.register(ISkills.class, new SkillStorage(), () -> new Skills(null));
	}

 

If so, isn't that part supposed to be null? Every other capability I've seen from other people that had an entity/player there had it set to null.

  • Quote

Share this post


Link to post
Share on other sites

diesieben07    7696

diesieben07

diesieben07    7696

  • Reality Controller
  • diesieben07
  • Forum Team
  • 7696
  • 56382 posts
Posted January 4
12 minutes ago, LK1905 said:

If so, isn't that part supposed to be null?

No...? I mean, you never set the entity field anywhere else but then you use it to sync (or at least try to) here. Since you never set entity to anything but null that condition will never be true and you never call sync.

 

14 minutes ago, LK1905 said:

Every other capability I've seen from other people that had an entity/player there had it set to null.

Then they are either doing something differently than you or they are equally broken.

  • Quote

Share this post


Link to post
Share on other sites

LK1905    0

LK1905

LK1905    0

  • Tree Puncher
  • LK1905
  • Members
  • 0
  • 27 posts
Posted January 17

Sorry for the late response.

 

Another stupid question, but how do I set the the entity so that it's not null? 

  • Quote

Share this post


Link to post
Share on other sites

diesieben07    7696

diesieben07

diesieben07    7696

  • Reality Controller
  • diesieben07
  • Forum Team
  • 7696
  • 56382 posts
Posted January 17
7 minutes ago, LK1905 said:

Another stupid question, but how do I set the the entity so that it's not null? 

Pass in the player when creating your capability in the attach event.

  • Quote

Share this post


Link to post
Share on other sites

LK1905    0

LK1905

LK1905    0

  • Tree Puncher
  • LK1905
  • Members
  • 0
  • 27 posts
Posted January 18

Did you mean replace EntityLiving in the Object instanceof part with PlayerEntity? Because I just tried that and it made no difference.

  • Quote

Share this post


Link to post
Share on other sites

diesieben07    7696

diesieben07

diesieben07    7696

  • Reality Controller
  • diesieben07
  • Forum Team
  • 7696
  • 56382 posts
Posted January 18
21 minutes ago, LK1905 said:

Did you mean replace EntityLiving in the Object instanceof part with PlayerEntity? Because I just tried that and it made no difference.

No. I did not say that at all.

  • Quote

Share this post


Link to post
Share on other sites

LK1905    0

LK1905

LK1905    0

  • Tree Puncher
  • LK1905
  • Members
  • 0
  • 27 posts
Posted January 18
8 minutes ago, diesieben07 said:

No. I did not say that at all.

Then I'm not sure what you mean by "Pass in the player", sorry.

  • Quote

Share this post


Link to post
Share on other sites

diesieben07    7696

diesieben07

diesieben07    7696

  • Reality Controller
  • diesieben07
  • Forum Team
  • 7696
  • 56382 posts
Posted January 18

You get the player in the event. You give it to your capability so that it can store it and have it later, for syncing.

  • Quote

Share this post


Link to post
Share on other sites
  • Prev
  • 1
  • 2
  • Next
  • Page 1 of 2  

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 2
Go To Topic Listing



  • Recently Browsing

    No registered users viewing this page.

  • Posts

    • BeardlessBrady
      [1.16.4] Tile Registration

      By BeardlessBrady · Posted 5 minutes ago

      Hello, I am having issues registering my tile entity. Here is my code as well as a link to the code in my github. The IDE is complaining that 'TileEntityType.Builder.create' has invalid arguments   // Tiles public static final DeferredRegister<TileEntityType<?>> TILE_ENTITY_TYPES = DeferredRegister.create(ForgeRegistries.TILE_ENTITIES, GOCurrency.MODID); public static final RegistryObject<TileEntityType<VendingTile>> TILE_VENDING = TILE_ENTITY_TYPES.register("vending_te", () -> TileEntityType.Builder.create(VendingTile::new, BLOCK_VENDING.get()).build(null));   https://github.com/Beardlessbrady/Currency-Mod/blob/95230ca4ee2d290b3e5f3ef81810a27f73137625/src/main/java/com/beardlessbrady/gocurrency/handlers/CommonRegistry.java#L42-L43
    • ThisIsNotOriginal
      Error at load_registries event phase

      By ThisIsNotOriginal · Posted 59 minutes ago

      The pastebin for the log and Registry Event is posted below this text.   https://pastebin.com/KEzJvRgG https://pastebin.com/VUrXR94k
    • PlasmaPig13
      The game crashed whilst rendering overlay Error: java.lang.NullPointerException: Rendering overlay Exit Code: -1

      By PlasmaPig13 · Posted 1 hour ago

      Here's the crash report and the loglatest.log crash-2021-03-02_19.33.58-client.txt
    • PlasmaPig13
      The game crashed whilst rendering overlay Error: java.lang.NullPointerException: Rendering overlay Exit Code: -1

      By PlasmaPig13 · Posted 1 hour ago

      I'm using 1.14.4 forge version 28.2.23 and the game crashes with the title's error message. Also, I'm new here; how do I paste the log? 
    • LexManos
      The vanilla tag system isnt suitable for ore dictionary

      By LexManos · Posted 1 hour ago

      You can also use conditionals, However empty tags are probably the best way to go. Data gens make any argument of being hard to use moot. So there is nothing we need to do in this reguard.
  • Topics

    • BeardlessBrady
      0
      [1.16.4] Tile Registration

      By BeardlessBrady
      Started 6 minutes ago

    • ThisIsNotOriginal
      0
      Error at load_registries event phase

      By ThisIsNotOriginal
      Started 59 minutes ago

    • PlasmaPig13
      1
      The game crashed whilst rendering overlay Error: java.lang.NullPointerException: Rendering overlay Exit Code: -1

      By PlasmaPig13
      Started 1 hour ago

    • EnderiumSmith
      3
      The vanilla tag system isnt suitable for ore dictionary

      By EnderiumSmith
      Started 14 hours ago

    • Ilikecheese
      0
      forge 1.16.5 wont show up

      By Ilikecheese
      Started 1 hour ago

  • Who's Online (See full list)

    • BeardlessBrady
    • ThisIsNotOriginal
    • ehbean
    • Beethoven92
    • Jeldrik
    • That_Tallone
    • squidlex
    • Lyon
    • Draco18s
    • Radical
  • All Activity
  • Home
  • Mod Developer Central
  • Modder Support
  • [Solved][1.16.4] How do I correctly sync capability data between Client and server?
  • Theme

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