[Tutorial] Packet Tutorials

Discussion in 'Resources' started by BurnBlader, Feb 19, 2014.

Thread Status:
Not open for further replies.
  1. I thought I would write a tutorial about packets, so people can understand them better. I'll try explain everything as much as I can, so you can continue to learn packets yourself =)

    Overview:
    Show Spoiler

    Packets are objects sent from the client to the server and vice-versa with information about whats happening.

    We'll take PacketPlayOutChat for example. This is sent from the server to the client when someone sends a chat message. The client then receives this information and displays it to the user.


    We use reflection to get fields within the packets, as they are all private fields. It allows us to access those fields.


    Changing a player's nametag:
    Show Spoiler


    To set a player's nametag we will be using the PacketPlayOutNamedEntitySpawn packet and the PacketPlayOutEntityDestroy packet.

    We will be writing a command to change the nametag to their name, but in a different colour.

    First off we'll lay out the command, this should be simple for anyone who knows how to make Bukkit plugins.

    Code:
    @Override
    public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
            if(sender instanceof Player) {
                Player player = (Player) sender;
             
             
             
            }
            return false;
    }
    
    We'll just call the command "/nameme".

    Code:
    @Override
    public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
            if(sender instanceof Player) {
                Player player = (Player) sender;
             
                if(label.equalsIgnoreCase("nameme")) {
                 
                }
             
            }
            return false;
    }
    
    Now we'll make an EntityPlayer instance of the player.

    Code:
    EntityPlayer entityPlayer = ((CraftPlayer)player).getHandle();
    
    We then need to make the Named Entity Spawn packet. This is what shows to every player, apart from the player doing the command.

    Code:
    EntityPlayer entityPlayer = ((CraftPlayer)player).getHandle();
     
    PacketPlayOutNamedEntitySpawn entitySpawn = new PacketPlayOutNamedEntitySpawn(entityPlayer);
    
    We need to make a GameProfile, to set the username of the player. It used to be just a String, but to adapt to the upcoming username changes, they've changed to a GameProfile.

    Code:
    GameProfile gameProfile = new GameProfile("aaaaa", ChatColor.GREEN + player.getName());
    
    We then need to use reflection to change the private fields, as I stated in the Overview. It has to be surrounded in a try/catch statement.

    Code:
    try {
            Field f = entitySpawn.getClass().getDeclaredField("b");
            f.setAccessible(true);
            f.set(entitySpawn, gameProfile);
    } catch(Exception e) {
            e.printStackTrace();
    }
    
    We need to then send this packet, along with a PacketPlayOutEntityDestroy packet, so that they no longer see the previous player, but the new one with the better nametag. We have to create a new PacketPlayOutEntityDestroy, and then send them the Named Entity Spawn packet. We also need to check if we're sending the player who did the command the packet, because it would most likely crash the client.

    Code:
    for(Player p : Bukkit.getOnlinePlayers()) {
        if(!p.getName().equals(player.getName())) {
                EntityPlayer playerToSend = ((CraftPlayer)p).getHandle();
                playerToSend.playerConnection.sendPacket(newPacketPlayOutEntityDestroy(entityPlayer.getId()));
                playerToSend.playerConnection.sendPacket(entitySpawn);
        }
    }
    
    That should work =)

    Drawbacks (Thanks to Comphenix)
    Show Spoiler

    • The modified name tag will revert to its original form once you reenter the world or server. This can also occur if you step outside the visible range of the player, and back again.
    • Any custom effects, held items or armor will be reset after the packet has been received, and they will not appear until these things have been altered. Explaining why might be a good future topic.
    • This is likely to clash with plugins such as DisguiseCraft, and any plugin using the Vanish API.




    If you want me to add anything, please tell me. I'll work on spawning an npc later.
     
    ArthurMaker likes this.
  2. Offline

    Comphenix

    This is perfectly fine as a simple introduction to the subject (though there are many), but you should make people aware of the drawbacks of this approach:
    • The modified name tag will revert to its original form once you reenter the world or server. This can also occur if you step outside the visible range of the player, and back again.
    • Any custom effects, held items or armor will be reset after the packet has been received, and they will not appear until these things have been altered. Explaining why might be a good future topic.
    • This is likely to clash with plugins such as DisguiseCraft, and any plugin using the Vanish API.
    For production use, I recommend either using TagAPI, or intercept the PacketPlayOutNamedEntitySpawn packet with TinyProtocol or ProtocolLib.
     
    Wingzzz likes this.
  3. Comphenix I'm well aware, I just made this to give an introduction to packets. I'll be writing more simple packet tutorials, such as spawning an NPC.

    I may do a tutorial with TinyProtocol, but I think I will leave it for now.
     
Thread Status:
Not open for further replies.

Share This Page