Jump to content

Recommended Posts

Posted (edited)

So I made a command for nickname but, it only works for chat nothing else here is my code the capability stores a string and then during the forge event it uses said string: 
According to bukkit's command this is all they practically do is change a display name and is only server side so I don't think packets are required so tell me what else I need to do


CMD:

	@Override
	public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException 
	{
		EntityPlayer player = (EntityPlayer) sender;
		CapNick name = (CapNick) CapabilityReg.getCapabilityConatainer(player).getCapability(new ResourceLocation(Reference.MODID + ":" + "nick"));
		name.nick = args.length == 1 ? args[0] : player.getName();
		player.refreshDisplayName();
	}

Event:
 

@SubscribeEvent
public void skinCap(PlayerEvent.NameFormat e)
{
	EntityPlayer player = e.getEntityPlayer();
	CapNick name = (CapNick) CapabilityReg.getCapabilityConatainer(player).getCapability(new ResourceLocation(Reference.MODID + ":" + "nick"));
   	if(!Strings.isNullOrEmpty(name.nick))
   		e.setDisplayname(name.nick);
}

 

Edited by jredfox
Posted (edited)
18 minutes ago, diesieben07 said:

This is not Bukkit. The event is fired on both server and client and both need to set the player name properly.

And what the f is this? 

 

external capability system not directly attached to the object of the player similar to bukkit and bukkit plugins. All you need to know is I attach a string the if statement does execute and the only thing that changes is the chat name what else do I need to do.

during command refreshes player name > String nick = args[0]

during event > event.setName(nick);

Bukkit can change player name without having custom packets to send to the client so what else needs to happen????

Edited by jredfox
Posted (edited)
9 minutes ago, diesieben07 said:

Please stop. I can almost guarantee you that your system is broken. Not because it's you, but because "just attach data to a player" is not a simple concept. Forge has systems for it for a reason. Please use them.

 

(Emphasis added).

I can change my code to public static string nick to transfer to the forge event doesn't do anything.

 

public static String nick = args[0];

during event > set name to nick if not null same result 

Here is my capability system isn't broken:
https://github.com/jredfox/evilnotchlib/tree/master/src/main/java/com/EvilNotch/lib/minecraft/content/pcapabilites

and here: 

https://github.com/jredfox/evilnotchlib/blob/931c6eab0f5a3ba733f3515cd395764b745d4798/src/main/java/com/EvilNotch/lib/main/MainJava.java#L270
How to use it:
Create a capability provider > basically to register your caps when the time occurs
Create capabilities to use for the container.
Make sure you have readFromNBT/writeToNBT fullly working then your done

 

"The event is fired on both server and client and both need to set the player name properly."

why bukkit doesn't need that code running on client side and my command is server only. I want to keep this like bukkit what packet do I send to the clients to update the names?

Edited by jredfox
Posted (edited)
6 minutes ago, diesieben07 said:

public static is not how you exchange data between server and client.

 

  • You have a memory leak, you never unload capabilities when a player logs out. The only reliable way to do so would be using a WeakReference. No, PlayerLoggedOutEvent is not sufficient.
  • Nothing about this is ready for client-server. You just have a static map somewhere indexed by name. This is just completely broken.

These are just the first two things I found by looking at it for 2 minutes. And these are major flaws. I am sure there are many smaller things.

I do player logout and server stop and tested player logout fires for disconnecting the player. How??? The capability system is server only for now I haven't figured out how to (fast enough) sync data from load file event(before login occurs during serialization). If I did a weak reference that means people could only view the capability once before it disposes sounds  awful I want to use it all during the game until logout. The player save event occurs way too often so I decided logout and server stop would be more optimized?

Again the PlayerEvent.NameFormat is fired on client side to? Well I want to keep it server side utility now since everything else is so far for the mod I am working on. What packet do I send to all players telling them of the name change????

Edited by jredfox
Posted (edited)
7 minutes ago, diesieben07 said:

Yes, it is fired on the client. Why "Again"?

 

Not possible.

 

Well, if only there was a system that did all this already... If only...

the capabilities fires on client's thanks I might move it to the capability event to register my system then. Doesn't solve my issue for older issues sadley. Forge's is very confusing nearly impossible to manipulate other mods and scan for what mod does what so I made my own for players at least now

I am sure there is a way bukkit does it and doesn't have any client code instant name changes. look for CraftPlayer.setDisplayName()
https://hub.spigotmc.org/stash/projects/SPIGOT/repos/craftbukkit/browse/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java

I will keep looking for a solution on what they use but, it appears it's possible without any new client code. Just don't know where and what vanilla packets they are using to use a work around for this.

Edited by jredfox
Posted
1 minute ago, diesieben07 said:

As far as I can see CraftPlayer#setDisplayName does nothing for the client.

You can send SPacketPlayerListItem with UPDATE_DISPLAY_NAME, which will update the name in the player list (tab key by default). Not sure if the name is displayed elsewhere on the client.

not it but, I will look more online

Posted (edited)
    @Override
    public void setPlayerListName(String name) {
        if (name == null) {
            name = getName();
        }
        getHandle().listName = name.equals(getName()) ? null : CraftChatMessage.fromString(name)[0];
        for (EntityPlayer player : (List<EntityPlayer>)server.getHandle().players) {
            if (player.getBukkitEntity().canSee(this)) {
                player.playerConnection.sendPacket(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.UPDATE_DISPLAY_NAME, getHandle()));
            }
        }
    }

 

Edited by jredfox
Posted
1 minute ago, diesieben07 said:

This is what I just told you to do:

 

nothing just tried this:
 

    	SPacketPlayerListItem item = new SPacketPlayerListItem(SPacketPlayerListItem.Action.UPDATE_DISPLAY_NAME,player.mcServer.getPlayerList().getPlayers());
    	for(EntityPlayerMP p : player.mcServer.getPlayerList().getPlayers())
    	{
    		p.connection.sendPacket(item);
    	}

 

Posted (edited)
2 minutes ago, diesieben07 said:

What do you mean by "nothing"? Stop. Being. Vague.

nothing updates besides the chat name on server

Edited by jredfox
Posted
2 minutes ago, diesieben07 said:

Well, you are not actually sending any updated display name. You need to pass the new display name into the packet.

there are three constructors for SPacketPlayerListItem none of them allow for custom text. It just gives a tabname from the player which always returns null.

Posted (edited)

also just had my friend relog and did a hard coded test(client and server from player login) the new name doesn't show up in tab only above the player head weird
 

	@SubscribeEvent
    public void skinCap(PlayerEvent.NameFormat e)
    {
		e.setDisplayname("notch");
    }

 

Edited by jredfox
Posted

And this is why I have jredfox muted.

  • Like 1

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Posted
15 hours ago, diesieben07 said:

You need to create the packet with the empty constructor and then set SPacketPlayerListItem#action and add your own instances of SPacketPlayerListItem.AddPlayerData to SPacketPlayerListItem#players.

 

You already knew it would not work. Why did you perform this test? How is this result "weird" or in any way unexpected?

"add your own instances" so your saying try your own custom packet. I will be trying this out later but, from the code I read sending null for the name resets the clients names for the players or at least the comments said it was suppose to do that. Maybe it only does it once or something stupid like that

 

"You already knew it would not work"

no I tested on both sides from login not on command didn't know what would happen

Posted (edited)
3 hours ago, diesieben07 said:

No, that is not what I said. If you do not know what an instance is, learn Java basics.

SPacketPlayerListItem.AddPlayerData wait I thought it wasn't a thing since it's not static inner class just re-read the post of stackoverflow. Will be trying this out

 

https://stackoverflow.com/questions/70324/java-inner-class-and-static-nested-class

public class A{
	
    public class B{
    	//cannot be constructed except for in class A  
    }
}

 

Edited by jredfox
Posted
On 6/14/2018 at 8:56 AM, diesieben07 said:

Not true.


class A {
    class B {}
}

A a = new A();
B b = a.new B();

 

ok I got the creative tab working but, the name above the head doesn't match the nickname still.
 

        if(!(e.getEntityPlayer() instanceof EntityPlayerMP))
            return;
        EntityPlayerMP player = (EntityPlayerMP) e.getEntityPlayer();
        CapNick name = (CapNick) CapabilityReg.getCapability(player.getName(), new ResourceLocation(Reference.MODID + ":" + "nick"));
        if(name == null)
        	return;
        SPacketPlayerListItem item = new SPacketPlayerListItem();
        if(!Strings.isNullOrEmpty(name.nick))
        {
               e.setDisplayname(name.nick);
               AddPlayerData apd = item.new AddPlayerData(player.getGameProfile(), player.ping, player.interactionManager.getGameType(), new TextComponentString(name.nick));
               ReflectionUtil.setObject(item, SPacketPlayerListItem.Action.UPDATE_DISPLAY_NAME, SPacketPlayerListItem.class, MCPMappings.getField(SPacketPlayerListItem.class, "action"));
               item.getEntries().add(apd);
        }
        for(EntityPlayerMP p : player.mcServer.getPlayerList().getPlayers())
        {
            p.connection.sendPacket(item);
        }

 

2018-06-19_01.38.06.png

Posted
2 hours ago, diesieben07 said:

There is no way to change that from the server.

 if I change the display name on login from the player name forge event it does change the head display name. Where is this code located at on the client so I can make a custom packet to update that part?

Posted
1 minute ago, diesieben07 said:

If you do it on the client, yes. The server does not send the display name to the client.

 

I have no idea what you mean.

You need to send a custom packet on login (resp. on start tracking, etc.) and tell the client about the name. Then you use capabilities (the real ones, not your stupid broken ones) to store it there as well (same capability on both server and client). Then call EntityPlayer#refreshDisplayName on the client and the NameFormat event will be fired again, where you can then read your new name from the capability.

so your saying if I simply send a custom packet from the server to the client to refresh the display name it should work? I will give it a try

Posted (edited)
2 hours ago, diesieben07 said:

Yes, that is what I have said all along.

yeah sorry thought there might have been another way since spigot was doing it but, maybe it didn't work for them at least on forge fully?

So on player name format event I send to all players the new nickname of said player. It works on the /nick command but, on respawn it gets deleted. Note The name format event is still firing and packets are still being sent on respawn but, for some reason i't reverting back to player.getName(). It doesn't seem to matter which player respawns the display name resets for all users on their side back to their original name tags. The rest works fine though
 

 NetWorkHandler.INSTANCE.sendToAll(new PacketDisplayNameRefresh(name.nick, player.getEntityId()) );

 

Output on respawning:

setting player:Player96 > notch

 

Code of network packets:
https://gist.github.com/jredfox/d549d41d19b369631aa3b28899b8601b

Main Mod call during init:

NetWorkHandler.init();


If you want the repository I could upload it but, there is alot of junk in there that has nothing to do with player nick names.

Edited by jredfox
Posted
2 hours ago, diesieben07 said:

No... Do not send packets in that event. Send the packet when the name changes (see below).

 

  • Make a capability to store the changed name (both server and client).
  • Subscribe to PlayerEvent.NameFormat and set the name according to the capability (both server and client).
  • You must send the packets as follows:
    • PlayerLoggedInEvent, PlayerRespawnEvent and when the name changes: Send current name (if changed) to the player itself and all players tracking it (EntityTracker#getTrackingPlayers).
    • PlayerEvent.StartTracking: Send current name of PlayerEvent.StartTracking#getTarget (if it's a player and has a changed name) to PlayerEvent#getEntityPlayer.
  • When the packet is received on the client, call EntityPlayer#refreshDisplayName.

No further action is needed.

 

even with forge capabilities don't register till after the name format fires on both sides:
Code:
 

	@SubscribeEvent
    public void caps(AttachCapabilitiesEvent<Entity> e)
    {
		if(e.getObject() instanceof EntityPlayer)
			System.out.println("entity player caps firing:");
    }
	@SubscribeEvent
    public void nickName(PlayerEvent.NameFormat e)
    {
		System.out.println("firing name format:");
    }

Output:

[15:56:55] [Server thread/INFO] [STDOUT]: [com.EvilNotch.lanessentials.MainMod:nickName:146]: firing name format:
[15:56:55] [Server thread/INFO] [STDOUT]: [com.EvilNotch.lanessentials.MainMod:nickName:146]: firing name format:
[15:56:55] [main/INFO] [STDOUT]: [com.EvilNotch.lanessentials.MainMod:caps:140]: entity player caps firing:

Therefore player doesn't have the capabilities yet since they are not registered. Now if name format would fire after caps both of them then it would be acceptable to store it as a forge capability. At this point I am completely lost as to why the name format fires before caps are registred

Posted (edited)
9 hours ago, diesieben07 said:

No... Do not send packets in that event. Send the packet when the name changes (see below).

 

  • Make a capability to store the changed name (both server and client).
  • Subscribe to PlayerEvent.NameFormat and set the name according to the capability (both server and client).
  • You must send the packets as follows:
    • PlayerLoggedInEvent, PlayerRespawnEvent and when the name changes: Send current name (if changed) to the player itself and all players tracking it (EntityTracker#getTrackingPlayers).
    • PlayerEvent.StartTracking: Send current name of PlayerEvent.StartTracking#getTarget (if it's a player and has a changed name) to PlayerEvent#getEntityPlayer.
  • When the packet is received on the client, call EntityPlayer#refreshDisplayName.

No further action is needed.

 

ok the last thing I am having trouble with is StartTracking event as it's saying the id of the entity request doesn't exist on the client side when sending a packet from server to client. also StartTracking is server only so I need packets to tell the client to update the name for client side.

So the client in my code here is unable to grab the entity player on client side when teleporting to another player. Here is how I get the entity player in the packet client handler:
 

	EntityPlayer player = (EntityPlayer) client.world.getEntityByID(message.id);

Output:

Recieved Packet NickName For Invalid PlayerID:305

 

Code inside the packet:
https://gist.github.com/jredfox/d549d41d19b369631aa3b28899b8601b#file-packetnickhandler-java


So I decided to print out the client world entities as well as the player list and it only displayed the other player not myself same for when the other player started tracking me. So the issue is this I don't know how to grab the player object on client side to update the nametag on their client side. Note I did this using /tp player command after being in unloaded veiw from the other players render

I also tried something else printing the info stored on NetworkPlayerInfo via client. However after login on track event the connection of the client's player was returning null as it was throwing null point exceptions so really lost as what to do hear.

Edited by jredfox
Posted (edited)
6 hours ago, diesieben07 said:

Also: https://gist.github.com/jredfox/d549d41d19b369631aa3b28899b8601b#file-packetnickhandler-java-L23

WHAT THE FUCK.

No.

NO NO NO NO.

 

This is not what I told you to do. Stop doing this. Stop it.

either way it should work whether or not it's reflected or not. I haven't made the total conversion to client sync so reflection is a better test with the packet at this point

"That means that your IMessageHandler can not interact with most game objects directly. Minecraft provides a convenient way to make your code execute on the main thread instead using IThreadListener.addScheduledTask."  then how the heck am I suppose to get an entity instance and then do something with it? Also the entity even if it's on client side isn't on the client's world always so I am having trouble finding the entity player. I added the schedule task thing.

Edited by jredfox
Posted (edited)
6 hours ago, diesieben07 said:

yeah it seemed to fix almost everything. 

Why should I get all entities being tracked by the player with the new nick name and update all of them. Shouldn't the player wanting to track player x username only receive the x username since it's going to fire for everybody firing it for at least the tracking event?

Edited by jredfox
Posted (edited)
10 hours ago, diesieben07 said:

Because tracking players need to know that the name changed, so they can display it properly.

 

WHAT?

think your confusing for login and respawn yes I need to get all tracking ents on login.

tracking event only the player starting to track you needs to know the updated information since that event fires each time a player is aware of another player and starts tracking thus only the info of the request needs to be updated on the new player username if player has a nickname.

I got it working though with these updated methods and a packet handler fix:
TrackName update is for tracking event:
Respawn/login is updateNickName although I am not sure if it needs to update everything on respawn (don't send my custom packet since the entity is just going to get re-tracked on respawn) but, yes it works from what I have been testing on with teleport.
 

	/**
	 * optimized version for when requesting entity is about to start tracking the player without updating it to everyone
	 */
	public static void updateTrackNickName(EntityPlayerMP request,EntityPlayerMP newPlayer) 
	{
    	CapNick name = (CapNick) CapabilityReg.getCapability(newPlayer, new ResourceLocation(Reference.MODID + ":" + "nick"));
    	if(Strings.isNullOrEmpty(name.nick))
    	{
    		System.out.println("returning nickname not set!");
    		return;
    	}
    	newPlayer.refreshDisplayName();
    	SPacketPlayerListItem item = new SPacketPlayerListItem();
        AddPlayerData apd = item.new AddPlayerData(newPlayer.getGameProfile(), newPlayer.ping, newPlayer.interactionManager.getGameType(), new TextComponentString(name.nick));
        ReflectionUtil.setObject(item, SPacketPlayerListItem.Action.UPDATE_DISPLAY_NAME, SPacketPlayerListItem.class, MCPMappings.getField(SPacketPlayerListItem.class, "action"));
        item.getEntries().add(apd);
    	
        request.connection.sendPacket(item);
        NetWorkHandler.INSTANCE.sendTo(new PacketDisplayNameRefresh(name.nick, newPlayer.getEntityId()), request);
	}
	public static void updateNickName(EntityPlayerMP player) 
	{
    	CapNick name = (CapNick) CapabilityReg.getCapability(player, new ResourceLocation(Reference.MODID + ":" + "nick"));
    	if(Strings.isNullOrEmpty(name.nick))
    		return;
    	player.refreshDisplayName();
    	SPacketPlayerListItem item = new SPacketPlayerListItem();
        AddPlayerData apd = item.new AddPlayerData(player.getGameProfile(), player.ping, player.interactionManager.getGameType(), new TextComponentString(name.nick));
        ReflectionUtil.setObject(item, SPacketPlayerListItem.Action.UPDATE_DISPLAY_NAME, SPacketPlayerListItem.class, MCPMappings.getField(SPacketPlayerListItem.class, "action"));
        item.getEntries().add(apd);
        
        Set<? extends EntityPlayer> li = player.getServerWorld().getEntityTracker().getTrackingPlayers(player);
        Set<EntityPlayerMP> players = new HashSet();
        for(EntityPlayer p : li)
        	players.add((EntityPlayerMP)p);
        players.add(player);
    	
        for(EntityPlayerMP p : players)
        {
            p.connection.sendPacket(item);
            if(!p.equals(player))
            {
            	NetWorkHandler.INSTANCE.sendTo(new PacketDisplayNameRefresh(name.nick, player.getEntityId()), p);
            }
        }
	}

The packet fix was put all code in this:
        Minecraft.getMinecraft().addScheduledTask(() -> 
        {


        });

For now especially since I got it working I am keeping the capability server side only since I would not only have to update the player of the said nickname that it changed but, all other players client's that it changed and those clients would store the other player capabilities it would be unoptimized and harder to sync changes then to just directly change it via reflection for the user. I guess I could have a weak hashmap of integer and name but, not really worried about it right now

Edited by jredfox
Posted (edited)
10 hours ago, diesieben07 said:

Because tracking players need to know that the name changed, so they can display it properly.

 

WHAT?

one more issue I am Having is the team scoreboard thing doesn't work in tab. My stuff only updates the display name in tab when the player gets tracked logged in or respawned. As to why it's not showing color after we did the /nick command is unkown to me. In the display name string itself does it except color codes or what is going on?

 

here is my repository requires both I would just through both sources in the same mdk.
https://github.com/jredfox/lanessentials

https://github.com/jredfox/evilnotchlib

2018-06-20_22_25_19.thumb.png.14d7be5fd0e86bc62ec80a6065c720da.png

Edited by jredfox
Posted (edited)
10 hours ago, diesieben07 said:

No, I am not confusing anything. On respawn a new player entity is created and the data must be sent again.

 

Yes, that is what I said.

 

Oh god please, just stop. Please. For the love of fucking god stop doing everything backwards. There are public APIs for changing the player name. USE THEM. No, reflection is not acceptable. USE THE APIS, THEY EXIST FOR A REASON.

And stop using your own capabilities. Nothing about my proposed solution is "unoptimized". Claiming things are "slow" is not acceptable unless you have measured that they are too slow. Prefer clean code. Don't run around throwing weird hacks everywhere because it's "more optimized". This is terrible and called premature optimization. Yes, it applies to you as well. Just like everyone else.

 

Not even going to go there. Fix the shit mentioned above. Your current code is unmaintainable.

I did if you look mine is overriding vanilla's I didn't say why is vanilla overriding mine I said why is mine overriding vanilla's team? The color is gone but, it is the right name. I guarantee you that everything is synced on the tracking event only the entity tracking needs the packet not all tracking entities since on the moment of the other tracking another player will request the same info. My code is perfectly fine and it all works just too well vanilla's team board thing isn't receiving any updates on tab and I want to know why the team was done right after the /nick command was done. And if you look at my code I only edit  the display name string only. Either way there would need to be a packet for most events since they are server only might as well just do everything you want me to fire the display name event I can do that but, it has nothing to do with why the team color is failing in tab since the only string that gets edited is display name string. Meaning that it's failing for another reason say the tab display string is null normally so it doesn't display it but, since you told me to make it the other players custom name now when it's not null it only displays that.

 

I could literally show you that just the tab packet alone is failing it has nothing to do with my packet for the name tag.

I just commented out all instances of my custom packet and only have the vanilla tab you told me to do and it's still incompatible with the tab and team colors

Edited by jredfox

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.