Jump to content

[1.15.2] Capability Synchronization


lisilew

Recommended Posts

Quote

By default, Capability data is not sent to clients. In order to change this, the mods have to manage their own synchronization code using packets.

There are three different situation in which you may want to send synchronization packets, all of them optional:

1. When the entity spawns in the world, or the block is placed, you may want to share the initialization-assigned values with the clients.

2. When the stored data changes, you may want to notify some or all of the watching clients.

3. When a new client starts viewing the entity or block, you may want to notify it of the existing data.

I have a capability that is attached to monsters.

When I sync the capability, which events should I listen to?

I was thinking LivingSpawnEvent for the first case and PlayerEvent.StartTracking for the third case.

Are those two events enough or are there any events should I listen to other than those two?

Edited by lisilew
Link to comment
Share on other sites

3 hours ago, lisilew said:

PlayerEvent.StartTracking for the third case.

Only this event and when it changes. A player in a completely different area of the world doesn't know about an Entity near another player far away and therefore does not need to know about any Capability changes.

3 hours ago, lisilew said:

When the stored data changes, you may want to notify some or all of the watching clients.

There are two ways to do this. Have your Capability on each entity keep track of each player that is tracking it on the server. Get the tracking Player in the PlayerEvent.StartTracking when you initially send the data. And don't forget to remove the player from the Capability tracking list in PlayerEvent.StopTracking.

VANILLA MINECRAFT CLASSES ARE THE BEST RESOURCES WHEN MODDING

I will be posting 1.15.2 modding tutorials on this channel. If you want to be notified of it do the normal YouTube stuff like subscribing, ect.

Forge and vanilla BlockState generator.

Link to comment
Share on other sites

1 hour ago, Animefan8888 said:

There are two ways to do this. Have your Capability on each entity keep track of each player that is tracking it on the server. Get the tracking Player in the PlayerEvent.StartTracking when you initially send the data. And don't forget to remove the player from the Capability tracking list in PlayerEvent.StopTracking.

Can storing players in the capability be replaced with

// Send to all players tracking this chunk
INSTANCE.send(PacketDistributor.TRACKING_CHUNK.with(chunk), new MyMessage());

?

Link to comment
Share on other sites

9 minutes ago, lisilew said:

Can storing players in the capability be replaced with

I think it can it would be best to test this yourself however.

VANILLA MINECRAFT CLASSES ARE THE BEST RESOURCES WHEN MODDING

I will be posting 1.15.2 modding tutorials on this channel. If you want to be notified of it do the normal YouTube stuff like subscribing, ect.

Forge and vanilla BlockState generator.

Link to comment
Share on other sites

5 hours ago, diesieben07 said:

All that is left to do is send the data when it changes, which you can do using PacketDistributor.TRACKING_ENTITY (this sends to all players who can "see" or rather who "are aware of" the entity).

If I send packet using PacketDistributor.TRACKING_ENTITY whenever capability changes, will players who were not tracking that entity at that moment get updated when they starts tracking that entity?

5 hours ago, diesieben07 said:

If you have data attached to players it gets a little more complicated.

I am also going to add different capability to players so can you elaborate more on this or are you talking about PlayerEvent.Clone?

Link to comment
Share on other sites

3 hours ago, diesieben07 said:

Of course, because at the moment they start tracking it, PlayerEvent.StartTracking will fire and you will send the (then current) data.

I apologize if this question is redundant and annoys you.

I just started to understand capability system so I want to make everything clear.

When you say PlayerEvent.StartTracking will be fired to send modified data from untracked entities, do you mean I have to do something when PlayerEvent.StartTracking is fired or Forge's capability system does the job of taking care of capability modification on untracked entities as long as I use PacketDistributor.TRACKING_ENTITY?

Link to comment
Share on other sites

10 minutes ago, diesieben07 said:

You have to subscribe to PlayerEvent.StartTracking and then send the packet to the player who is now tracking (not PacketDistributor.TRACKING_ENTITY!).

public class MyPacket {
    private int id;
    private boolean flag;
    
    public MyPacket(int id, boolean flag) {
        this.id = id;
        this.flag = flag;
    }
    
    public MyPacket(PacketBuffer packetBuffer) {
        id = packetBuffer.readInt();
        flag = packetBuffer.readBoolean();
    }
    
    public void encode(PacketBuffer packetBuffer) {
        packetBuffer.writeInt(id);
        packetBuffer.writeBoolean(flag);
    }
    
    public void handle(Supplier<NetworkEvent.Context> supplier) {
        NetworkEvent.Contxext context = supplier.get();
        context.enqueueWork(() -> {
            ServerPlayerEntity player = context.getSender();
            if (player != null) {
                Entity entity = player.world.getEntityByID(id);
                if (entity != null) {
                    entity.getCapability(Capabilities.MY_CAPABILITY).ifPresent(capability -> {
                        capability.setFlag(flag);
                    });
                }
            }
        });
        context.setPacketHandled(true);
}

Above is the packet that is sent using

PacketHandler.INSTANCE.send(PacketDistributor.TRACKING_ENTITY.with(() -> entity), new MyPacket(entity.getEntityId(), true));

when the capability changes from initially false to true under a condition.

@SubscribeEvent
public static void onStartTracking(PlayerEvent.StartTracking event) {
    event.getTarget().getCapability(Capabilities.MY_CAPABILITY).ifPresent(capability -> {
        PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(event.getPlayer()), new MyPacket(capability.getEntityId(), capability.getFlag()));
    })
}

Is this correct way to synchronize the capability?

Link to comment
Share on other sites

1 minute ago, diesieben07 said:

This is a server to client packet. Doing this here does not make any sense (the sender is the server, not a player and there is no ServerPlayerEntity on the client).

Then, do I need different packet that uses Minecraft.getInstance().player instead of ServerPlayerEntity or just change declaration type to PlayerEntity?

Link to comment
Share on other sites

5 minutes ago, diesieben07 said:

All your synchronization packets are sent from server to client...?

Oh, so when the packet is sent to PacketDistributor.TRACKING_ENTITY, the packet is sent from server to players, thus, handled by clients and Minecraft.getInstance().world is safe to access.

Edited by lisilew
Link to comment
Share on other sites

1 hour ago, diesieben07 said:

Yes. The only packet type that would be client to server would be PacketDistributor.SERVER. All others send from the server to zero or more clients (controlled by specifying which server side players to send the packet to, it will arrive on those player's clients).

The class where onStartTracking is located is annotated with @Mod.EventBusSubscriber(modid = "examplemod").

Unless events are annotated with @OnlyIn(Dist.CLIENT), I listen to events in that class.

PacketDistributor.PLAYER.with requires a supplier of ServerPlayerEntity.

I casted event.getPlayer() to ServerPlayerEntity.

Is this safe or should I divide the current class into client and server events?

I am still quite confused about sides and in which sides events are fired.

Link to comment
Share on other sites

On 4/17/2020 at 7:37 PM, diesieben07 said:

In addition you have to use PacketDistributor.TRACKING_ENTITY whenever your data changes to propagate this change to all tracking players.

Sorry for bringing this old topic to life.

When I update the capability in getCapability().ifPresent(), do I have to update local capability and send packet or is just sending packet to PacketDistributor.TRACKING_ENTITY enough?

entity.getCapability(Capabilities.CAPABILITY).ifPresent(capability -> {
    if (!capability.flag) {
        capability.flag = true;
        PacketHandler.INSTANCE.send(PacketDistributor.TRACKING_ENTITY.with(() -> entity), new Packet(entity.getEntityId(), true));
    }
});

In other words, is the third line, capability.flag = true;, needed?

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



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • If you are using AMD/ATI, get the latest drivers from their website - do not update via system
    • So I don't have any other mods and I try to install my first mod. At first I tried turning on Forge but it didn't work for me. I entered into these logs and this is what debug I found.   [05maj2024 19:29:16.383] [main/INFO] [cpw.mods.modlauncher.Launcher/MODLAUNCHER]: ModLauncher running: args [--username, kod00, --version, 1.20.1-forge-47.2.30, --gameDir, C:\Users\Tadeusz\AppData\Roaming\.minecraft, --assetsDir, C:\Users\Tadeusz\AppData\Roaming\.minecraft\assets, --assetIndex, 5, --uuid, 0b6cb7d0d9794ea3995565e2c9e6961f, --accessToken, ????????, --clientId, ZmVhZDQ5MDEtODA2ZC00OTZhLTg1NWEtNDAzYzhmZGVhYzAx, --xuid, 2535448611541717, --userType, msa, --versionType, release, --quickPlayPath, C:\Users\Tadeusz\AppData\Roaming\.minecraft\quickPlay\java\1714930153126.json, --launchTarget, forgeclient, --fml.forgeVersion, 47.2.30, --fml.mcVersion, 1.20.1, --fml.forgeGroup, net.minecraftforge, --fml.mcpVersion, 20230612.114412] [05maj2024 19:29:16.393] [main/INFO] [cpw.mods.modlauncher.Launcher/MODLAUNCHER]: ModLauncher 10.0.9+10.0. 9+main.dcd20f30 starting: java version 17.0.8 by Microsoft; OS Windows 10 arch amd64 version 10.0 [05maj2024 19:29:16.557] [main/INFO] [net.minecraftforge.fml.loading.ImmediateWindowHandler/]: Loading ImmediateWindowProvider fmlearlywindow [05maj2024 19:29:16.668] [main/INFO] [EARLYDISPLAY/]: Trying GL version 4.6   -------------------------------------------------------------   [05maj2024 19:29:16.383] [main/INFO] [cpw.mods.modlauncher.Launcher/MODLAUNCHER]: ModLauncher running: args [--username, kod00, --version, 1.20.1-forge-47.2.30, --gameDir, C:\Users\Tadeusz\AppData\Roaming\.minecraft, --assetsDir, C:\Users\Tadeusz\AppData\Roaming\.minecraft\assets, --assetIndex, 5, --uuid, 0b6cb7d0d9794ea3995565e2c9e6961f, --accessToken, ????????, --clientId, ZmVhZDQ5MDEtODA2ZC00OTZhLTg1NWEtNDAzYzhmZGVhYzAx, --xuid, 2535448611541717, --userType, msa, --versionType, release, --quickPlayPath, C:\Users\Tadeusz\AppData\Roaming\.minecraft\quickPlay\java\1714930153126.json, --launchTarget, forgeclient, --fml.forgeVersion, 47.2.30, --fml.mcVersion, 1.20.1, --fml.forgeGroup, net.minecraftforge, --fml.mcpVersion, 20230612.114412] [05maj2024 19:29:16.393] [main/INFO] [cpw.mods.modlauncher.Launcher/MODLAUNCHER]: ModLauncher 10.0.9+10.0.9+main.dcd20f30 starting: java version 17.0.8 by Microsoft; OS Windows 10 arch amd64 version 10.0 [05maj2024 19:29:16.428] [main/DEBUG] [cpw.mods.modlauncher.LaunchServiceHandler/MODLAUNCHER]: Found launch services [fmlclientdev,forgeclient,minecraft,forgegametestserverdev,fmlserveruserdev,fmlclient,fmldatauserdev,forgeserverdev,forgeserveruserdev,forgeclientdev,forgeclientuserdev,forgeserver,forgedatadev,fmlserver,fmlclientuserdev,fmlserverdev,forgedatauserdev,testharness,forgegametestserveruserdev] [05maj2024 19:29:16.448] [main/DEBUG] [cpw.mods.modlauncher.NameMappingServiceHandler/MODLAUNCHER]: Found naming services : [srgtomcp] [05maj2024 19:29:16.468] [main/DEBUG] [cpw.mods.modlauncher.LaunchPluginHandler/MODLAUNCHER]: Found launch plugins: [mixin,eventbus,slf4jfixer,object_holder_definalize,runtime_enum_extender,capability_token_subclass,accesstransformer,runtimedistcleaner] [05maj2024 19:29:16.485] [main/DEBUG] [cpw.mods.modlauncher.TransformationServicesHandler/MODLAUNCHER]: Discovering transformation services [05maj2024 19:29:16.495] [main/DEBUG] [net.minecraftforge.fml.loading.FMLPaths/CORE]: Path GAMEDIR is C:\Users\Tadeusz\AppData\Roaming\.minecraft [05maj2024 19:29:16.495] [main/DEBUG] [net.minecraftforge.fml.loading.FMLPaths/CORE]: Path MODSDIR is C:\Users\Tadeusz\AppData\Roaming\.minecraft\mods [05maj2024 19:29:16.495] [main/DEBUG] [net.minecraftforge.fml.loading.FMLPaths/CORE]: Path CONFIGDIR is C:\Users\Tadeusz\AppData\Roaming\.minecraft\config [05maj2024 19:29:16.495] [main/DEBUG] [net.minecraftforge.fml.loading.FMLPaths/CORE]: Path FMLCONFIG is C:\Users\Tadeusz\AppData\Roaming\.minecraft\config\fml.toml [05maj2024 19:29:16.550] [main/DEBUG] [cpw.mods.modlauncher.TransformationServicesHandler/MODLAUNCHER]: Found additional transformation services from discovery services:  [05maj2024 19:29:16.557] [main/INFO] [net.minecraftforge.fml.loading.ImmediateWindowHandler/]: Loading ImmediateWindowProvider fmlearlywindow [05maj2024 19:29:16.668] [main/INFO] [EARLYDISPLAY/]: Trying GL version 4.6   Can you help me with this?
    • So I don't have any other mods and I try to install my first mod. At first I tried turning on Forge but it didn't work for me. I entered into these logs and this is what debug I found.   [05maj2024 19:29:16.383] [main/INFO] [cpw.mods.modlauncher.Launcher/MODLAUNCHER]: ModLauncher running: args [--username, kod00, --version, 1.20.1-forge-47.2.30, --gameDir, C:\Users\Tadeusz\AppData\Roaming\.minecraft, --assetsDir, C:\Users\Tadeusz\AppData\Roaming\.minecraft\assets, --assetIndex, 5, --uuid, 0b6cb7d0d9794ea3995565e2c9e6961f, --accessToken, ????????, --clientId, ZmVhZDQ5MDEtODA2ZC00OTZhLTg1NWEtNDAzYzhmZGVhYzAx, --xuid, 2535448611541717, --userType, msa, --versionType, release, --quickPlayPath, C:\Users\Tadeusz\AppData\Roaming\.minecraft\quickPlay\java\1714930153126.json, --launchTarget, forgeclient, --fml.forgeVersion, 47.2.30, --fml.mcVersion, 1.20.1, --fml.forgeGroup, net.minecraftforge, --fml.mcpVersion, 20230612.114412] [05maj2024 19:29:16.393] [main/INFO] [cpw.mods.modlauncher.Launcher/MODLAUNCHER]: ModLauncher 10.0.9+10.0. 9+main.dcd20f30 starting: java version 17.0.8 by Microsoft; OS Windows 10 arch amd64 version 10.0 [05maj2024 19:29:16.557] [main/INFO] [net.minecraftforge.fml.loading.ImmediateWindowHandler/]: Loading ImmediateWindowProvider fmlearlywindow [05maj2024 19:29:16.668] [main/INFO] [EARLYDISPLAY/]: Trying GL version 4.6   Can you help me with this?  
    • Thank you so, so much for your help! I have implemented the code from the example you gave me and it has been excepted, the only downside currently being that the game crashes on launch, saying:  Caused by: java.lang.IllegalStateException: Cannot register new entries to DeferredRegister after RegisterEvent has been fired.  (Three times) and  Caused by: java.lang.ExceptionInInitializerError (Two times) With further scanning I have found this error: 2024-05-05T18:41:24.287+0100 [ERROR] [org.gradle.internal.buildevents.BuildExceptionReporter] I am not exactly sure what to do with these errors but I am sure I can resolve them. Once again, thank you for your help! It is much appreciated. 😁
  • Topics

×
×
  • Create New...

Important Information

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