Resource Custom Tab List Icons

Discussion in 'Spigot Plugin Development' started by Remceau, Jun 1, 2017.

?

Was this usefull

  1. Yes

    163 vote(s)
    76.2%
  2. A little bit

    13 vote(s)
    6.1%
  3. Not really

    4 vote(s)
    1.9%
  4. No

    10 vote(s)
    4.7%
  5. I don't wanna tell you

    8 vote(s)
    3.7%
  6. I don't understand anything from this thread

    16 vote(s)
    7.5%
  1. Thanks, will definitely use this
     
  2. Could you give me an exaple please :( or someone I need help please :C
     
    #22 KSDpolska, Aug 24, 2017
    Last edited: Aug 24, 2017
  3. Thanks for the tip... that looks great. Now i don't have to spam my account with textures. I will put it in the tutorial!
     
    • Friendly Friendly x 1
  4. I know this can be done, and at my own servers I use this method, but i wanted to keep it simple without using reflect to edit variables that are private.
     
  5. I will not give you the code, because I think that people don't learn a lot if you just give them the code. But if you say what exactly you don't understand or what doesn't work, i may be able the help you with more advise!
     
  6. I think this will be really helpful in the future for me, and so I have bookmarked it. Thanks!!!
     
  7. Everyone reading this, I have made a update with a fix for a problem, and i added a nice website of @inventivetalent to the tutorial. This may help some people. So if you are interested in the changes, you should take a look at the end of the tutorial!

    Thank you very much!
     
  8. Well. I'd like to make an TabList but How can I update the player constantly, i tried it but it doesn't work

    Code (Text):

    import java.util.Collection;
    import java.util.UUID;

    import org.bukkit.Bukkit;
    import org.bukkit.craftbukkit.v1_8_R3.CraftServer;
    import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer;
    import org.bukkit.entity.Player;
    import org.bukkit.event.Listener;
    import org.bukkit.plugin.java.JavaPlugin;

    import com.mojang.authlib.GameProfile;
    import com.mojang.authlib.properties.Property;

    import net.minecraft.server.v1_8_R3.ChatComponentText;
    import net.minecraft.server.v1_8_R3.EntityPlayer;
    import net.minecraft.server.v1_8_R3.MinecraftServer;
    import net.minecraft.server.v1_8_R3.PacketPlayOutPlayerInfo;
    import net.minecraft.server.v1_8_R3.PlayerInteractManager;
    import net.minecraft.server.v1_8_R3.WorldServer;
    import net.minecraft.server.v1_8_R3.PacketPlayOutPlayerInfo.EnumPlayerInfoAction;

    public class Tabulator extends JavaPlugin implements Listener{

     
        public static void RemoveAllPlayers(Player receiver) {
            Collection<? extends Player> playersBukkit = Bukkit.getOnlinePlayers();
            EntityPlayer[] playersNMS = new EntityPlayer[playersBukkit.size()];
            int current = 0;
            for (Player player : playersBukkit) {
                playersNMS[current] = ((CraftPlayer) player).getHandle();
                current++;
            }
            PacketPlayOutPlayerInfo packet = new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.REMOVE_PLAYER, playersNMS);
            ((CraftPlayer) receiver).getHandle().playerConnection.sendPacket(packet);
        }
     
        public static EntityPlayer createPlayers(String name, String listName, String texture, String signature) {
            MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer();
            WorldServer worldserver = server.getWorldServer(0);
            PlayerInteractManager playerinteractmanager = new PlayerInteractManager(worldserver);
            GameProfile profile = new GameProfile(UUID.randomUUID(), name);
            profile.getProperties().put("textures", new Property("textures", texture, signature));
            EntityPlayer player = new EntityPlayer(server, worldserver, profile, playerinteractmanager);
            player.listName = new ChatComponentText(listName);
            return player;
        }

        public static void addPlayers(Player receiver, EntityPlayer... createdPlayers) {
            PacketPlayOutPlayerInfo packet = new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.ADD_PLAYER, createdPlayers);
            ((CraftPlayer) receiver).getHandle().playerConnection.sendPacket(packet);
        }

        public static void setPlayers(Player receiver, EntityPlayer... createdPlayers) {
            PacketPlayOutPlayerInfo packet = new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.UPDATE_DISPLAY_NAME, createdPlayers);
            ((CraftPlayer) receiver).getHandle().playerConnection.sendPacket(packet);
        }
     

        static void BunkersTab(Player p) {
            RemoveAllPlayers(p);
            EntityPlayer[] players = new EntityPlayer[1];
            players[0] = createPlayers("00", "§7Ping:" + getPing(p), "eyJ0aW1lc3RhbXAiOjE1MDM1NTI0NDk5MDcsInByb2ZpbGVJZCI6IjZiMjIwMzdkYzA0MzQyNzE5NGYyYWRiMDAzNjhiZjE2IiwicHJvZmlsZU5hbWUiOiJiYW5hbmFzcXVhZCIsInNpZ25hdHVyZVJlcXVpcmVkIjp0cnVlLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjJmMDg1YzZiM2NiMjI4ZTViYTgxZGY1NjJjNDc4Njc2MmYzYzI1NzEyN2U5NzI1Yzc3YjdmZDMwMWQzNyJ9fX0=",
            addPlayers(p, players)
    }
        static void UpdateBunkersTab(Player p) {
            RemoveAllPlayers(p);
            EntityPlayer[] players = new EntityPlayer[1];
            players[0] = createPlayers("00", "§7Ping:" + getPing(p), "eyJ0aW1lc3RhbXAiOjE1MDM1NTI0NDk5MDcsInByb2ZpbGVJZCI6IjZiMjIwMzdkYzA0MzQyNzE5NGYyYWRiMDAzNjhiZjE2IiwicHJvZmlsZU5hbWUiOiJiYW5hbmFzcXVhZCIsInNpZ25hdHVyZVJlcXVpcmVkIjp0cnVlLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjJmMDg1YzZiM2NiMjI4ZTViYTgxZGY1NjJjNDc4Njc2MmYzYzI1NzEyN2U5NzI1Yzc3YjdmZDMwMWQzNyJ9fX0=",
                   setPlayers(p, players)
        }

     
    }

    But I don't understand How can I update the player Constantly. :confused:

    And there is one more thing.
    If It creates entitys, Does it reduce permormance of my server?

    Help me please
     
    #28 KSDpolska, Aug 24, 2017
    Last edited: Aug 24, 2017
  9. How do you update the player constantly: Make a repeating task and in that repeating task send a packet with UPDATE_DISPLAY_NAME, withe the created PlayerEntity you created and that you want to change. In this palyer entity change the listName however before sending the packet with the new value!
    Code (maybesomehelp (Unknown Language)):

    // After sending the first packets to send them the new tablist
    BukkitRunnable runnable = new BukkitRunnable() {
      public void run() {
        // Change the listName field of the entity at that position
        // Send update packet here (PacketPlayOutPlayerInfo with the entity at that postion and UPDATE_DISPLAY_NAME
      }
    }
    // Schedule the runnable to run every n ticks here
     
    You have to make sure however, that you cancel this runnable after the player leaves. Otherwise, performance can drop lots!

    Does it reduce performance: Every object you make reduces the performance, so yes. For small servers however, this is no big impact. If you are making a big server with lots of players this can give some performance issues. You can bypass creating the entities by editing the fields in the packet instead of using the constructor, using reflect of course. This is out of the scope of the tutorial, but if you really want to see how that goes, ask me, and maybe, maybe, maybe i will make a tutorial for it!
     
  10. Well, I would really like to you can Do that tutorial. It will be Amazing! I hope you can do it.

    -EDIT-

    I tried it and It doesn't work :(

    Code (Text):
    static void Tab(Player p) {
            RemoveAllPlayers(p);
            EntityPlayer[] players = new EntityPlayer[1];
            players[0] = createPlayers("00", "§8§lSalud:" + p.getHealth() + "§4♥", "eyJ0aW1lc3RhbXAiOjE1MDM1NTI0NDk5MDcsInByb2ZpbGVJZCI6IjZiMjIwMzdkYzA0MzQyNzE5NGYyYWRiMDAzNjhiZjE2IiwicHJvZmlsZU5hbWUiOiJiYW5hbmFzcXVhZCIsInNpZ25hdHVyZVJlcXVpcmVkIjp0cnVlLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjJmMDg1YzZiM2NiMjI4ZTViYTgxZGY1NjJjNDc4Njc2MmYzYzI1NzEyN2U5NzI1Yzc3YjdmZDMwMWQzNyJ9fX0=", "QvCljQIF/SX1fZYkS1fLyVpxiRhviLGx+tvOCNUzMHGIn0N/5iRezwNxIwOcipP+IuIsyUtZa4zmIGn2plsBStrOVHO5vXyiPpx13wG4hpydgNv7Al/EVM0FIDkUDIylVlr8tld1YNs0M6T5NSVkpbP1ptuts+ctVKcF32fZoXC1+AEOOiHLIX383UBJU2TpdNqbVGv5E2ewAWE3bJJs070lXVc5CjIJ4GSJ7LUs0rixpSLnBHdEshoOM9DQUog+wt8+AFvZj7KV7nh9Ud/mB2q8KTzUikn3sT64kO8bSSg9X/GiyEZcEVGGrrAv4ZIRiqeDYJZ/tgU9XXgymtOdhw45aoT52QmnYM4b9M7urIohrReWSR+jdOYdzdh04mP/k+HP9psUvwYKHAespDzOAm1D1ZZU1Ek4eFIUJ2H0WzRXHiAhSxDH5hm9tIfbyN6IHMa2D1M5xikZNZWJXfjT1Dhz8+ycOSWOyNxbdHS7tgXIneBNsgeXXSKkECBbUvDkntP8T/JBAW9Mjtpbf9VS4NRnapelkqTmWmcvd2ySo9dRpxWAAZgxIc5tnf+dYyLc262CvBCSXbciH4Pr1FSJv05RBwbwDR1kzOGsXjM+QViBETc/w4suzR7CesDMFxX9vBXxPAzQl9xU5wkSjEsWytDpWPiuay3FMRE5CrVohAI=");
            addPlayers(p, players);
        }
        static void UpdateTab(Player p) {
            EntityPlayer[] players = new EntityPlayer[1];
            players[0] = createPlayers("00", "§8§lSalud:" + p.getHealth() + "§4♥", "eyJ0aW1lc3RhbXAiOjE1MDM1NTI0NDk5MDcsInByb2ZpbGVJZCI6IjZiMjIwMzdkYzA0MzQyNzE5NGYyYWRiMDAzNjhiZjE2IiwicHJvZmlsZU5hbWUiOiJiYW5hbmFzcXVhZCIsInNpZ25hdHVyZVJlcXVpcmVkIjp0cnVlLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjJmMDg1YzZiM2NiMjI4ZTViYTgxZGY1NjJjNDc4Njc2MmYzYzI1NzEyN2U5NzI1Yzc3YjdmZDMwMWQzNyJ9fX0=", "QvCljQIF/SX1fZYkS1fLyVpxiRhviLGx+tvOCNUzMHGIn0N/5iRezwNxIwOcipP+IuIsyUtZa4zmIGn2plsBStrOVHO5vXyiPpx13wG4hpydgNv7Al/EVM0FIDkUDIylVlr8tld1YNs0M6T5NSVkpbP1ptuts+ctVKcF32fZoXC1+AEOOiHLIX383UBJU2TpdNqbVGv5E2ewAWE3bJJs070lXVc5CjIJ4GSJ7LUs0rixpSLnBHdEshoOM9DQUog+wt8+AFvZj7KV7nh9Ud/mB2q8KTzUikn3sT64kO8bSSg9X/GiyEZcEVGGrrAv4ZIRiqeDYJZ/tgU9XXgymtOdhw45aoT52QmnYM4b9M7urIohrReWSR+jdOYdzdh04mP/k+HP9psUvwYKHAespDzOAm1D1ZZU1Ek4eFIUJ2H0WzRXHiAhSxDH5hm9tIfbyN6IHMa2D1M5xikZNZWJXfjT1Dhz8+ycOSWOyNxbdHS7tgXIneBNsgeXXSKkECBbUvDkntP8T/JBAW9Mjtpbf9VS4NRnapelkqTmWmcvd2ySo9dRpxWAAZgxIc5tnf+dYyLc262CvBCSXbciH4Pr1FSJv05RBwbwDR1kzOGsXjM+QViBETc/w4suzR7CesDMFxX9vBXxPAzQl9xU5wkSjEsWytDpWPiuay3FMRE5CrVohAI=");
            PacketPlayOutPlayerInfo packet = new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.UPDATE_DISPLAY_NAME, players);
            ((CraftPlayer) p).getHandle().playerConnection.sendPacket(packet);
        }


    // JOIN EVENT

    @EventHandler
        public void onJoin(PlayerJoinEvent e) {
            Player p = (Player)e.getPlayer();
            e.setJoinMessage(null);
            Tabulator.Tab(p);
           
            new BukkitRunnable() {
                @Override
                public void run() {
                    if (p.isOnline()) {
                       Tabulator.UpdateTab(p);
                    } else {
                        this.cancel();
                    }
                }  
               
            }.runTaskTimer(this, 20*5, 20*5);
        }
     
     
    #30 KSDpolska, Aug 24, 2017
    Last edited: Aug 25, 2017
  11. Sounds like something that would make a great library if there was some multiversion compatibility ;).

    Am I allowed to try and do that and turn it into an API?
     
    #31 gluebaby, Aug 24, 2017
    Last edited: Aug 24, 2017
  12. Why not! That would only give me a good feeling because i did something usefull :)

    The code would almost work, but you made a minor mistake. When you are updating the tablist with the method, you are creating a new entity player or to be exact, you are sending a new random uuid. What you should do is instead of creating a new entity in the update method, get the entity you created in your Tab method, change the listName of that entity and send that entity.
     
    #32 Remceau, Aug 26, 2017
    Last edited: Dec 8, 2017
  13. HI again!

    I got it, but there is a big problem,

    My server (90-100 Online, 16GB RAM) gets lots of lagg with this, and I have to remove this from my server but I don't want to do that.
    So, I would like to know if there is another way to do this?
    Could you help me please?

    Thanks in advance,
    Best Rewards
     
    #33 KSDpolska, Sep 11, 2017
    Last edited: Sep 12, 2017
  14. HOLY CRAPS. Some big server uses my tutorial :D That makes me happy!
    But about the lag problem:
    There are some optimizations that i didn't mention in the tutorial. Firstly you don't have to create a player entity every time. In the packet object, the players to add are saved using a custom class. If you create a new instance of the class using reflect and then change the data of that class, you skip the constructor and thus you skip the making of the player entities. This will probably make a big difference in performance.
    Secondly, in the tutorial i am removing every player every time from the tab list. As told under the header "Update", you don't have to do this. The way mc handles order of the entries on the list is following the alphabetical. But " " (space) becomes before any letter, meaning that it will always be on the top. If you make as many entries as mc can display, and you let them all start with a " " (space), the list will be full, and players will never be shown. Then you don't have to remove the player from the list every time the join, and thus you only have to send one packet maximal per player per session. And no, real accounts can never start with a " " (space).
    I don't know any other optimization or solution then this.
    I hope this will help you.
     
  15. If anyone is looking to easily find texture/signature information for a user. I've coded this tool to help.

    To use it, simply enter a username and click the grab text that'll appear. You should get the signature and texture information within in a few seconds!
     
  16. I understood how to set order of fake players, but I don't even know how to set order of real players. ._.
    Do you have an any idea?
     
  17. Good tutorial. Thank you :)
     
  18. A question as it would be possible to make the tablist compatible from 1.7x to 1.15x
     
  19. what is this for?
     
  20. Sorry for necro, but when using server.getWorldServer(); in 1.16 NMS you cannot use INT and rather should use (nms) World.OVERWORLD