Jump to content

Recommended Posts

Posted (edited)

Hi

 

I have this one-variable-capability that needs to sync to all clients on the server in order for them to check in their event handler what to render:

IntercraftEventHandler.java

...
@OnlyIn(Dist.CLIENT)
@SubscribeEvent
public static void onRenderEntity(RenderLivingEvent.Specials.Pre event)
{
    if (event.getEntity() instanceof PlayerEntity) {
        if (event.isCancelable()) {

            IIdentityHidden hidden = event.getEntity().getCapability(IdentityHiddenProvider.HID_CAP).orElse(IdentityHiddenProvider.HID_CAP.getDefaultInstance());
            if (hidden.getHidden()) {


		// If true, cancel this event.
                event.setCanceled(true);

            }
        }
    }
}
...

 

Here are the capability files that store a single boolean value:

 
 
 
 
Spoiler

IIdentityHidden.java


package net.intercraft.intercraftcore.init.capabilities.identity_hidden;

public interface IIdentityHidden
{
    boolean getHidden();

    void setHidden(boolean hidden);
}

 

IdentityHidden.java


public class IdentityHidden implements IIdentityHidden
{

    private boolean hidden;


    public IdentityHidden()
    {
        this.hidden = false;
        IntercraftCore.NETWORK.send(PacketDistributor.ALL.noArg(), new MessageIdentityHidden(false));
    }


    @Override
    public boolean getHidden()
    {
        return hidden;
    }

    @Override
    public void setHidden(boolean hidden)
    {
        this.hidden = hidden;
        IntercraftCore.NETWORK.send(PacketDistributor.ALL.noArg(), new MessageIdentityHidden(hidden));
    }
}

 

IdentityHiddenProvider.java


public class IdentityHiddenProvider implements ICapabilitySerializable<INBT>
{


    @CapabilityInject(IIdentityHidden.class)
    public static Capability<IIdentityHidden> HID_CAP = null;

    private IIdentityHidden instance = HID_CAP.getDefaultInstance();


    @SuppressWarnings("unchecked")
    @Override
    public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, Direction side)
    {
        if (cap == HID_CAP)
            return (LazyOptional<T>) LazyOptional.of(() -> instance);
        return (LazyOptional<T>) LazyOptional.empty();
    }


    @Override
    public INBT serializeNBT()
    {
        return HID_CAP.getStorage().writeNBT(HID_CAP, instance, null);
    }

    @Override
    public void deserializeNBT(INBT nbt)
    {
        HID_CAP.getStorage().readNBT(HID_CAP, instance, null, nbt);
    }
}

 

Then I register it like so:

IntercraftCore.java

...
public void onCommonSetup(final FMLCommonSetupEvent event)
{
	CapabilityManager.INSTANCE.register(IIdentityHidden.class,  new IdentityHiddenStorage(),   new IdentityHiddenStorage.Factory());
}
...

 

 

The problem is that the capability is stored on the server and therefore nothing happens. So I created a message to send to all clients when that value changed in my network..

IntercraftPacketHandler.java

 
 
 
 
Spoiler

public class IntercraftPacketHandler
{

    private static int index = 1;

    private static final ResourceLocation CHANNEL_NAME = new ResourceLocation(Reference.MODID,"network");
    private static final String PROTOCOL_VERSION = new ResourceLocation(Reference.MODID,"1").toString();


    public static SimpleChannel getNetworkChannel()
    {
        final SimpleChannel channel = NetworkRegistry.ChannelBuilder.named(CHANNEL_NAME)
                .clientAcceptedVersions(version -> true)
                .serverAcceptedVersions(version -> true)
                .networkProtocolVersion(() -> PROTOCOL_VERSION)
                .simpleChannel();


        channel.messageBuilder(MessageIdentityHidden.class,index)
                .encoder(MessageIdentityHidden::encode)
                .decoder(MessageIdentityHidden::decode)
                .consumer(MessageIdentityHidden::handle)
                .add();
        index++;

        return channel;
    }
}
 

 

.. and stored it like this in IntercraftCore.java:

public static final SimpleChannel NETWORK = IntercraftPacketHandler.getNetworkChannel();

 

 

Problem

Ok, that's the code I have, and I wouldn't be here if it worked. I have 0 experience with this and last time it didn't work at all. So if its a common mistake I'll listen.

I have no problem with starting a singleplayer world, but when I log in on a server or log in to a LAN world the client that logs in crashes with a NullPointerException.

 

---- Minecraft Crash Report ----
// I just don't know what went wrong :(

Time: 10/30/19 11:16 AM
Description: Unexpected error

java.lang.NullPointerException: Unexpected error
	at net.minecraft.client.multiplayer.PlayerController.func_78750_j(PlayerController.java:251) ~[?:?] {pl:runtimedistcleaner:A}
	at net.minecraft.client.multiplayer.PlayerController.func_78765_e(PlayerController.java:231) ~[?:?] {pl:runtimedistcleaner:A}
	at net.minecraft.client.Minecraft.func_71407_l(Minecraft.java:1283) ~[?:?] {pl:accesstransformer:B,pl:runtimedistcleaner:A}
	at net.minecraft.client.Minecraft.func_195542_b(Minecraft.java:866) ~[?:?] {pl:accesstransformer:B,pl:runtimedistcleaner:A}
	at net.minecraft.client.Minecraft.func_99999_d(Minecraft.java:384) ~[?:?] {pl:accesstransformer:B,pl:runtimedistcleaner:A}
	at net.minecraft.client.main.Main.main(SourceFile:155) ~[1.14.4-forge-28.1.1.jar:?] {}
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_181] {}
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_181] {}
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_181] {}
	at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_181] {}
	at net.minecraftforge.fml.loading.FMLClientLaunchProvider.lambda$launchService$0(FMLClientLaunchProvider.java:56) ~[forge-1.14.4-28.1.1.jar:28.1] {}
	at cpw.mods.modlauncher.LaunchServiceHandlerDecorator.launch(LaunchServiceHandlerDecorator.java:37) [modlauncher-3.2.0.jar:?] {}
	at cpw.mods.modlauncher.LaunchServiceHandler.launch(LaunchServiceHandler.java:50) [modlauncher-3.2.0.jar:?] {}
	at cpw.mods.modlauncher.LaunchServiceHandler.launch(LaunchServiceHandler.java:68) [modlauncher-3.2.0.jar:?] {}
	at cpw.mods.modlauncher.Launcher.run(Launcher.java:80) [modlauncher-3.2.0.jar:?] {}
	at cpw.mods.modlauncher.Launcher.main(Launcher.java:65) [modlauncher-3.2.0.jar:?] {}

...

 

Full + download:

Spoiler
 
 
 
 
Spoiler

---- Minecraft Crash Report ----
// I just don't know what went wrong :(

Time: 10/30/19 11:16 AM
Description: Unexpected error

java.lang.NullPointerException: Unexpected error
	at net.minecraft.client.multiplayer.PlayerController.func_78750_j(PlayerController.java:251) ~[?:?] {pl:runtimedistcleaner:A}
	at net.minecraft.client.multiplayer.PlayerController.func_78765_e(PlayerController.java:231) ~[?:?] {pl:runtimedistcleaner:A}
	at net.minecraft.client.Minecraft.func_71407_l(Minecraft.java:1283) ~[?:?] {pl:accesstransformer:B,pl:runtimedistcleaner:A}
	at net.minecraft.client.Minecraft.func_195542_b(Minecraft.java:866) ~[?:?] {pl:accesstransformer:B,pl:runtimedistcleaner:A}
	at net.minecraft.client.Minecraft.func_99999_d(Minecraft.java:384) ~[?:?] {pl:accesstransformer:B,pl:runtimedistcleaner:A}
	at net.minecraft.client.main.Main.main(SourceFile:155) ~[1.14.4-forge-28.1.1.jar:?] {}
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_181] {}
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_181] {}
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_181] {}
	at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_181] {}
	at net.minecraftforge.fml.loading.FMLClientLaunchProvider.lambda$launchService$0(FMLClientLaunchProvider.java:56) ~[forge-1.14.4-28.1.1.jar:28.1] {}
	at cpw.mods.modlauncher.LaunchServiceHandlerDecorator.launch(LaunchServiceHandlerDecorator.java:37) [modlauncher-3.2.0.jar:?] {}
	at cpw.mods.modlauncher.LaunchServiceHandler.launch(LaunchServiceHandler.java:50) [modlauncher-3.2.0.jar:?] {}
	at cpw.mods.modlauncher.LaunchServiceHandler.launch(LaunchServiceHandler.java:68) [modlauncher-3.2.0.jar:?] {}
	at cpw.mods.modlauncher.Launcher.run(Launcher.java:80) [modlauncher-3.2.0.jar:?] {}
	at cpw.mods.modlauncher.Launcher.main(Launcher.java:65) [modlauncher-3.2.0.jar:?] {}


A detailed walkthrough of the error, its code path and all known details is as follows:
---------------------------------------------------------------------------------------

-- Head --
Thread: Client thread
Stacktrace:
	at net.minecraft.client.multiplayer.PlayerController.func_78750_j(PlayerController.java:251)
	at net.minecraft.client.multiplayer.PlayerController.func_78765_e(PlayerController.java:231)

-- Affected level --
Details:
	All players: 0 total; []
	Chunk stats: Client Chunk Cache: 729, 424
	Level dimension: DimensionType{minecraft:overworld}
	Level name: MpServer
	Level seed: 0
	Level generator: ID 00 - default, ver 1. Features enabled: false
	Level generator options: {}
	Level spawn location: World: (8,64,8), Chunk: (at 8,4,8 in 0,0; contains blocks 0,0,0 to 15,255,15), Region: (0,0; contains chunks 0,0 to 31,31, blocks 0,0,0 to 511,255,511)
	Level time: 92994 game time, 6000 day time
	Level storage version: 0x00000 - Unknown?
	Level weather: Rain time: 0 (now: true), thunder time: 0 (now: false)
	Level game mode: Game mode: creative (ID 1). Hardcore: false. Cheats: false
	Server brand: ~~ERROR~~ NullPointerException: null
	Server type: Non-integrated multiplayer server
Stacktrace:
	at net.minecraft.client.world.ClientWorld.func_72914_a(ClientWorld.java:410)
	at net.minecraft.client.Minecraft.func_71396_d(Minecraft.java:1747)
	at net.minecraft.client.Minecraft.func_99999_d(Minecraft.java:405)
	at net.minecraft.client.main.Main.main(SourceFile:155)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at net.minecraftforge.fml.loading.FMLClientLaunchProvider.lambda$launchService$0(FMLClientLaunchProvider.java:56)
	at cpw.mods.modlauncher.LaunchServiceHandlerDecorator.launch(LaunchServiceHandlerDecorator.java:37)
	at cpw.mods.modlauncher.LaunchServiceHandler.launch(LaunchServiceHandler.java:50)
	at cpw.mods.modlauncher.LaunchServiceHandler.launch(LaunchServiceHandler.java:68)
	at cpw.mods.modlauncher.Launcher.run(Launcher.java:80)
	at cpw.mods.modlauncher.Launcher.main(Launcher.java:65)

-- System Details --
Details:
	Minecraft Version: 1.14.4
	Minecraft Version ID: 1.14.4
	Operating System: Linux (amd64) version 4.15.0-66-generic
	Java Version: 1.8.0_181, Oracle Corporation
	Java VM Version: Java HotSpot(TM) 64-Bit Server VM (mixed mode), Oracle Corporation
	Memory: 698898224 bytes (666 MB) / 2147483648 bytes (2048 MB) up to 2147483648 bytes (2048 MB)
	CPUs: 12
	JVM Flags: 8 total; -Xss1M -Xmx2G -XX:+UnlockExperimentalVMOptions -XX:+UseG1GC -XX:G1NewSizePercent=20 -XX:G1ReservePercent=20 -XX:MaxGCPauseMillis=50 -XX:G1HeapRegionSize=32M
	ModLauncher: 3.2.0+60+b86c1d4
	ModLauncher launch target: fmlclient
	ModLauncher naming: srg
	ModLauncher services: 
		/eventbus-1.0.0-service.jar eventbus PLUGINSERVICE 
		/forge-1.14.4-28.1.1.jar object_holder_definalize PLUGINSERVICE 
		/forge-1.14.4-28.1.1.jar runtime_enum_extender PLUGINSERVICE 
		/accesstransformers-1.0.0-shadowed.jar accesstransformer PLUGINSERVICE 
		/forge-1.14.4-28.1.1.jar capability_inject_definalize PLUGINSERVICE 
		/forge-1.14.4-28.1.1.jar runtimedistcleaner PLUGINSERVICE 
		/forge-1.14.4-28.1.1.jar fml TRANSFORMATIONSERVICE 
	FML: 28.1
	Forge: net.minecraftforge:28.1.1
	FML Language Providers: 
		[email protected]
		minecraft@1
	Mod List: 
		curios-FORGE-1.14.4-1.0.jar Curios API {[email protected] DONE}
		intercraftcore-0.0.1.jar Intercraft Core {[email protected] DONE}
		forge-1.14.4-28.1.1-universal.jar Forge {[email protected] DONE}
		forge-1.14.4-28.1.1-client.jar Minecraft {[email protected] DONE}
	Launched Version: 1.14.4-forge-28.1.1
	LWJGL: 3.2.2 build 10
	OpenGL: GeForce GTX 660/PCIe/SSE2 GL version 4.6.0 NVIDIA 430.26, NVIDIA Corporation
	GL Caps: Using GL 1.3 multitexturing.
Using GL 1.3 texture combiners.
Using framebuffer objects because OpenGL 3.0 is supported and separate blending is supported.
Shaders are available because OpenGL 2.1 is supported.
VBOs are available because OpenGL 1.5 is supported.

	Using VBOs: Yes
	Is Modded: Definitely; Client brand changed to 'forge'
	Type: Client (map_client.txt)
	Resource Packs: 
	Current Language: English (US)
	CPU: 12x Intel(R) Core(TM) i7-8700 CPU @ 3.20GHz

 

crash-2019-10-30_11.16.03-client.txt

 

Edited by Simon_kungen
Posted
2 hours ago, diesieben07 said:

You cannot send packets at this point.

 

To sync a capability to all clients you need to send the sync packet under the following conditions:

  • In PlayerLoggedInEventPlayerRespawnEvent and PlayerChangedDimensionEvent send the player's data to that player.
  • In PlayerEvent.StartTracking send the data of PlayerEvent.StartTracking#getTarget (provided that it's a player) to PlayerEvent.StartTracking#getPlayer.
  • Whenever the data of player P changes, send that data to the players tracking player P and player P (you can use PacketDistributor.TRACKING_ENTITY_AND_SELF).

Ok, so, umm. I changed IdentityHidden.java to this:

public class IdentityHidden implements IIdentityHidden
{

    private boolean hidden;


    public IdentityHidden()
    {
        this.hidden = false;
    }


    @Override
    public boolean getHidden()
    {
        return hidden;
    }

    @Override
    public void setHidden(boolean hidden)
    {
        this.hidden = hidden;
        IntercraftCore.NETWORK.send(PacketDistributor.TRACKING_ENTITY_AND_SELF.noArg(), new MessageIdentityHidden(hidden));

    }
}

 

And in IntercraftEventHandler.java I added this:

@SubscribeEvent
public static void onPlayerLoggedIn(final PlayerEvent.PlayerLoggedInEvent event)
{
    IIdentityHidden hidden = event.getEntity().getCapability(IdentityHiddenProvider.HID_CAP).orElse(IdentityHiddenProvider.HID_CAP.getDefaultInstance());
    IntercraftCore.NETWORK.send(PacketDistributor.PLAYER.with(() -> (ServerPlayerEntity) event.getPlayer()),new MessageIdentityHidden(hidden.getHidden()));
}

@SubscribeEvent
public static void onPlayerRespawn(final PlayerEvent.PlayerRespawnEvent event)
{
    IIdentityHidden hidden = event.getEntity().getCapability(IdentityHiddenProvider.HID_CAP).orElse(IdentityHiddenProvider.HID_CAP.getDefaultInstance());
    IntercraftCore.NETWORK.send(PacketDistributor.PLAYER.with(() -> (ServerPlayerEntity) event.getPlayer()),new MessageIdentityHidden(hidden.getHidden()));
}

@SubscribeEvent
public static void onPlayerChangedDimension(final PlayerEvent.PlayerChangedDimensionEvent event)
{
    IIdentityHidden hidden = event.getEntity().getCapability(IdentityHiddenProvider.HID_CAP).orElse(IdentityHiddenProvider.HID_CAP.getDefaultInstance());
    IntercraftCore.NETWORK.send(PacketDistributor.PLAYER.with(() -> (ServerPlayerEntity) event.getPlayer()),new MessageIdentityHidden(hidden.getHidden()));
}

@SubscribeEvent
public static void onPlayerStartTracking(final PlayerEvent.StartTracking event)
{
    IIdentityHidden hiddenTarget = event.getTarget().getCapability(IdentityHiddenProvider.HID_CAP).orElse(IdentityHiddenProvider.HID_CAP.getDefaultInstance());
    IntercraftCore.NETWORK.send(PacketDistributor.PLAYER.with(() -> (ServerPlayerEntity) event.getPlayer()),new MessageIdentityHidden(hiddenTarget.getHidden()));

}

 

Is there something I missed? I have it send the updated value in the setter function of my capability class so I can more easily use it in other places such as my debug command and in the item that changes that value when worn (CuriosAPI Item).

 

ItemMask.java

...
@Override
public void onEquipped(String identifier, LivingEntity entityLivingBase)
{
    ItemMask.this.onEquipped(identifier, entityLivingBase);
    playEquipSound(entityLivingBase);

    if (hidesIdentity()) {
        if (entityLivingBase instanceof PlayerEntity) {
            entityLivingBase.sendMessage(new TranslationTextComponent("info."+Reference.MODID+".identity.hidden"));

            IIdentityHidden hidden = entityLivingBase.getCapability(IdentityHiddenProvider.HID_CAP).orElse(IdentityHiddenProvider.HID_CAP.getDefaultInstance());
            if (!hidden.getHidden())
                hidden.setHidden(true);
        }
    }
}

@Override
public void onUnequipped(String identifier, LivingEntity entityLivingBase)
{
    ItemMask.this.onUnequipped(identifier,entityLivingBase);

    if (hidesIdentity()) {
        if (entityLivingBase instanceof PlayerEntity) {
            entityLivingBase.sendMessage(new TranslationTextComponent("info."+Reference.MODID+".identity.shown"));

            IIdentityHidden hidden = entityLivingBase.getCapability(IdentityHiddenProvider.HID_CAP).orElse(IdentityHiddenProvider.HID_CAP.getDefaultInstance());
            if (hidden.getHidden())
                hidden.setHidden(false);
        }
    }
}
...

 

Posted
1 hour ago, diesieben07 said:

TRACKING_ENTITY_AND_SELF requires an entity argument. This code is going to crash with a NullPointerException.

 

This doesn't make sense. If you epxect the capability to always be there (which you do, you attach it to all players after all), then you should throw an exception if it's absent. That's what orElseThrow is for. Always prefer throwing exceptions upon invalid state instead of silently continueing with useless default values.

 

You haven't shown your packet class, but considering you only pass it one value it cannot possibly be correct. It needs the entity ID of the player that the packet is about, too. Otherwise the client has no idea whose capability to update with the new value.

 

Ok, updated so it uses a throws a NullPointerException instead of a default implementation. And you're right about me not having the Package class correct, which is something I forgot to show, so here it is updated with player UUID as the second argument:

MessageIdentityHidden.java

public class MessageIdentityHidden
{

    private final boolean hidden;
    private final UUID playerUUID;

    public MessageIdentityHidden(UUID playerUUID, boolean hidden)
    {
        this.hidden = hidden;
        this.playerUUID = playerUUID;
    }

    public MessageIdentityHidden(UUID playerUUID)
    {
        this.hidden = false;
        this.playerUUID = playerUUID;
    }



    public static void encode(final MessageIdentityHidden message, final PacketBuffer buffer)
    {
        buffer.writeBoolean(message.hidden);
        buffer.writeUniqueId(message.playerUUID);
    }


    public static MessageIdentityHidden decode(final PacketBuffer buffer)
    {
        return new MessageIdentityHidden(buffer.readUniqueId(), buffer.readBoolean());
    }

    public static void handle(MessageIdentityHidden message, Supplier<NetworkEvent.Context> ctx)
    {
        ctx.get().enqueueWork(() -> {
            
      		// No idea what to do here.



        });
        ctx.get().setPacketHandled(true);
    }
}

 

I have mostly looked at ToasterMod-1.14's code as I have no idea how to do this. And as he left his handle function empty I did the same with mine.

Posted
1 hour ago, diesieben07 said:

Do not use the UUID. Use the entity ID, it is more lightweight and made exactly for this purpose.

As for the "No idea what to do here": You get the entity from the world (World#getEntityByID) and then update it's capability (provided that it's a player, which it should be unless the server is lying).

Ok, I had so if you want to sync to other clients you have to specify a player. But now the problem is that it doesn't find the capability on the player anymore in onPlayerStartTracking:

public static void onPlayerStartTracking(final PlayerEvent.StartTracking event)
{
    IIdentityHidden hiddenTarget = event.getTarget().getCapability(IdentityHiddenProvider.HID_CAP).orElseThrow(NullPointerException::new);
    IntercraftCore.NETWORK.send(PacketDistributor.PLAYER.with(() -> (ServerPlayerEntity) event.getPlayer()),new MessageIdentityHidden(event.getPlayer().getEntityId(),hiddenTarget.getHidden()));

}

 

IdentityHidden.java

public class IdentityHidden implements IIdentityHidden
{

    private boolean hidden;


    public IdentityHidden(boolean hidden)
    {
        this.hidden = hidden;
    }

    public IdentityHidden()
    {
        this.hidden = false;
    }



    @Override
    public boolean getHidden()
    {
        return hidden;
    }

    @Override
    public void setHidden(PlayerEntity player,boolean hidden) // For client syncing.
    {
        this.hidden = hidden;
        IntercraftCore.NETWORK.send(PacketDistributor.TRACKING_ENTITY_AND_SELF.with(() -> player), new MessageIdentityHidden(player.getEntityId(), hidden));

    }

    @Override
    public void setHidden(boolean hidden)
    {
        this.hidden = hidden; // For server reading.
    }
}

 

MessageIdentityHidden.java

public class MessageIdentityHidden
{

    private final boolean hidden;
    private final int playerID;

    public MessageIdentityHidden(int playerID, boolean hidden)
    {
        this.hidden = hidden;
        this.playerID = playerID;
    }

    public MessageIdentityHidden(int playerID)
    {
        this.hidden = false;
        this.playerID = playerID;
    }



    public static void encode(final MessageIdentityHidden message, final PacketBuffer buffer)
    {
        buffer.writeBoolean(message.hidden);
        buffer.writeInt(message.playerID);
    }


    public static MessageIdentityHidden decode(final PacketBuffer buffer)
    {
        return new MessageIdentityHidden(buffer.readInt(), buffer.readBoolean());
    }

    public static void handle(MessageIdentityHidden message, Supplier<NetworkEvent.Context> ctx)
    {
        ctx.get().enqueueWork(() -> {

            PlayerEntity player = (PlayerEntity) ctx.get().getSender().getServerWorld().getEntityByID(message.playerID);
            IIdentityHidden hidden = player.getCapability(IdentityHiddenProvider.HID_CAP).orElseThrow(NullPointerException::new);
            hidden.setHidden(player, message.hidden);



        });
        ctx.get().setPacketHandled(true);
    }
}

 

Posted
On 10/30/2019 at 11:29 PM, diesieben07 said:

You are now trying to send the packet also on the client (because your packet calls setHidden when it's received, which sends the packet). That makes no sense.

Ok, so. If the in the handle function message's playerID is the sender, who's capability am I supposed to change?

 

On 10/30/2019 at 11:29 PM, diesieben07 said:

Your packet is received on the client. You cannot use NetworkEvent.Context#getSender. It makes no sense on the client (like explained in it's documentation).

Alright. If the playerID is not the right player who's capability I'm not supposed to change, who's should I do? And in that case how do I get the server world in the handle function? And does that even make sense to do it like that? Get the capability in the function and change it to the message's value. Should I scrap completely the playerID parameter for the setHidden() function and not send a message when I change the value?

 

On 10/30/2019 at 11:29 PM, diesieben07 said:
On 10/30/2019 at 10:24 PM, Simon_kungen said:

But now the problem is that it doesn't find the capability on the player anymore in onPlayerStartTracking:

Please elaborate.

Now when I join a server or start a server world it appears to not find the IdentityHidden capability of the target player and therefore throws the NullPointerException error.

 

@SubscribeEvent
public static void onPlayerStartTracking(final PlayerEvent.StartTracking event)
{
    IIdentityHidden hiddenTarget = event.getTarget().getCapability(IdentityHiddenProvider.HID_CAP).orElseThrow(NullPointerException::new); // <-- doesn't find the capability and throws a error.
    IntercraftCore.NETWORK.send(PacketDistributor.PLAYER.with(() -> (ServerPlayerEntity) event.getPlayer()),new MessageIdentityHidden(event.getPlayer().getEntityId(),hiddenTarget.getHidden()));

}

 

 

The last one is what confuses me the most. Before it worked fine with the .orElseThrow fix you told me to change due to it not making sense because it should put it on all players. But I'm not even sure if I'm even attaching capabilities correctly. I thought it simply needed to have the @SubscribeEvent annotation in my Event Handler class which has the @Mod.EventBusSubscriber annotation to the class, which ended up not firing. So in my main mod class I just attached it as a listener to MinecraftForge.EVENT_BUS.

IntercraftCore.java

MinecraftForge.EVENT_BUS.addListener(IntercraftEventHandler::attachCapabilityEntity);

 

It worked, so I left it at that.

Posted
12 minutes ago, diesieben07 said:
58 minutes ago, Simon_kungen said:

If the playerID is not the right player who's capability I'm not supposed to change, who's should I do?

I don't know where you got this idea from. It's not what I said. 

 

13 minutes ago, diesieben07 said:
58 minutes ago, Simon_kungen said:

And in that case how do I get the server world in the handle function?

You can't. You are on the client. There is no server world on the client.

Ok, sorry. In that case, how to get the player from the playerID?

MessageIdentityHidden.java

public static void handle(MessageIdentityHidden message, Supplier<NetworkEvent.Context> ctx)
{
    ctx.get().enqueueWork(() -> {
        PlayerEntity player = message.playerID// How do I get the target player by the ID here?
        IIdentityHidden hidden = player.getCapability(IdentityHiddenProvider.HID_CAP).orElseThrow(NullPointerException::new);
        hidden.setHidden(message.hidden);



    });
    ctx.get().setPacketHandled(true);
}

 

Posted

Ok. Looks like it is finally working, I had some issues with the playerID being 0. The decoder has to write the values in the same order they are read, which I presumed didn't matter due to them being two different primitive types (int and boolean). Then I had a simple filter as to not change the value of the client's just in case.

  • Simon_kungen changed the title to [SOLVED] [1.14.4] Problems with Networking
Posted
3 minutes ago, diesieben07 said:

This sounds very suspicious... Can you share your final code?

MessageIdentityHidden.java

public class MessageIdentityHidden
{

    private final boolean hidden;
    private final int playerID;

    public MessageIdentityHidden(int playerID, boolean hidden)
    {
        this.hidden = hidden;
        this.playerID = playerID;
    }



    public static void encode(final MessageIdentityHidden message, final PacketBuffer buffer)
    {
        buffer.writeInt(message.playerID);
        buffer.writeBoolean(message.hidden);
    }


    public static MessageIdentityHidden decode(final PacketBuffer buffer)
    {
        return new MessageIdentityHidden(buffer.readInt(), buffer.readBoolean());
    }

    public static void handle(MessageIdentityHidden message, Supplier<NetworkEvent.Context> ctx)
    {
        ctx.get().enqueueWork(() -> {

            if (message.playerID == Minecraft.getInstance().player.getEntityId()) return;

            PlayerEntity player = (PlayerEntity) Minecraft.getInstance().player.world.getEntityByID(message.playerID);

            IIdentityHidden hidden = player.getCapability(IdentityHiddenProvider.HID_CAP).orElseThrow(NullPointerException::new);
            hidden.setHidden(message.hidden);



        });
        ctx.get().setPacketHandled(true);
    }
}

 

Posted
4 hours ago, diesieben07 said:

Why? This means the main player will never receive it's data...

The main player doesn't see its own player name, so it doesn't matter if it knows it or not, only other player needs to know.

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



×
×
  • Create New...

Important Information

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