Util Custom Player Lists: Create your own tab list display.

Discussion in 'Resources' started by Zombie_Striker, Aug 19, 2016.

Thread Status:
Not open for further replies.
  1. Offline

    Zombie_Striker

    Description:
    This util was created to make it simpler to change player lists (tab lists) that players see. Using this util, you can make player vanish (remove the name from the tablist), add fake players (add custom names to the list) or even have animated named (updating a name from the tab list)

    This now works with ALL versions of Bukkit and Spigot that are currently available.

    How to use this:
    1. Create a new class called "PlayerList"
    2. Import all the un-imported objects (Once I figure out reflection you will not need to do this step) Thanks to Reflection, this step is no longer needed.
    3. Use any of the methods provided. Below I will have an example of how you can use this util.
    4. Remember: Always call "clearCustomTabs()" in the onDisable. If you do not, the player will have "ghost tabs" (tabs that the server does not recognize/see) until they relog.

    Code:

    Since the code goes over the 30,000 character limit for a post, you can now find the code here:
    LINK


    Useage:
    Here are some example of how to use certain methods and what they do.
    Code:java
    1. //Setup
    2. Player player = //the player;
    3. PlayerList playerList = new PlayerList(player,PlayerList.SIZE_FOUR);
    4. //If you are using a server version lower than 1.8, then use SIZE_DEFAULT
    5. //as only 20 tabs are shown for older versions.
    6.  
    7. /**
    8. * In case you want to retrieve an existing tablist, use PlayerList.getPlayerList(Player)
    9. */
    10.  
    11. //Creating a full board.
    12. playerList.initTable();
    13.  
    14. //Removes the player from the list
    15. //NOTE If you use this on the player with the tablist, then this will disable the player from
    16. //being able to go into spectator mode, and will stop the user from being able to fly through blocks if they are in spectator mode.
    17. playerList.removePlayer(player);
    18.  
    19. //Adding a custom player
    20. //by default, the slots will use stone textures as the head texture, so you do not need to see
    21. //steve and alex skins for all of your tabs. If you wish for the tab to have the skin of the name
    22. //provided, add ' , true' after the name (as shown below).
    23. playerList.updateSlot(0,"Top left");
    24. playerList.updateSlot(19,"Bottom left");
    25. playerList.updateSlot(60,"Top right");
    26. playerList.updateSlot(79,"Bottom right");
    27.  
    28. //Adds an existing tablist with the player's skin for the tablist. Only works in 1.8+
    29. playerList.updateSlot(44,"Notch",true);
    30.  
    31. //Sets the HeaderFooter.
    32. playerList.setHeaderFooter(ChatColor.GOLD+"Welcome","Test Message");
    33.  
    34.  
    35.  

    EXAMPLES:
    For versions 1.8 and higher
    Code:
    @EventHandler
    public void onJoin(PlayerJoinEvent e){
    PlayerList list = new PlayerList(e.getPlayer(),PlayerList.SIZE_FOUR);
    //You can choose any size for this.
    list.initTable();
    list.updateSlot(0,"Top left");
    list.updateSlot(19,"Bottom left");
    list.updateSlot(60,"Top right");
    list.updateSlot(79,"Bottom right");
    
    }
    For versions 1.7.10 and lower
    Code:
    @EventHandler
    public void onJoin(PlayerJoinEvent e){
    PlayerList list = new PlayerList(e.getPlayer(),PlayerList.SIZE_DEFAULT);
    //This MUST be size DEFAULT, as older versions could only store 20 players
    list.initTable();
    list.updateSlot(0,"Top");
    list.updateSlot(19,"Bottom");
    }
    Changelog:
    v1.3

    -Added skin customization.
    -Fixed examples. AddValue should no longer be used
    -Added HeaderFooter.
    v1.2
    -Added lookup table. Now, plugins or classes can easily retrieve existing tablist using PlayerList.getPlayerList()
    v1.1
    -Added "addExistingPlayer"
    -Added "resetTablist"
    -Added "addValue(id, name, uuid)"

    v1.0
    -
    init post
     
    Last edited: Sep 28, 2017
    ArsenArsen and ChipDev like this.
  2. Offline

    SirGregg

    @Zombie_Striker
    Thanks for the time you put into this! I was about to make one myself ;)
     
  3. Offline

    I Al Istannen

    @Zombie_Striker
    Might want to use the [syntax=java]<code>[/syntax]? I know it is discouraged, but looks nicer than this broken code block.

    I will have a look at the reflection side, but I won't promise anything :p

    EDIT: Javdoc would be a great help, too :p
     
    Last edited: Aug 19, 2016
  4. Offline

    blok601

    Getting in error on Protocol Manager. Is that my Craftbukkit version?

    Edit: nvm I didnt have protocollib in there
     
  5. Offline

    Zombie_Striker

    @blok601
    That was for Protocol lib. I was first using PL, but then realized I didn't need it. I just removed those lines.

    @I Al Istannen
    Adding docs and the syntax tags.
    [edit] YES! Number lines and coloring are not broken for syntax.
     
  6. Offline

    blok601

    Ah alright
     
  7. Offline

    I Al Istannen

    @Zombie_Striker
    Yes!

    There are some fields which are never used. Should I convert them to reflection too?
     
  8. Offline

    blok601

    Is it just me or is there a way to remove all those heads in the tab?
     
  9. Offline

    Zombie_Striker

    @I Al Istannen
    Updated the code and removed those lines. If they are unused, then there is no need to have them.

    @blok601
    There may be a way, but I do not know it ATM. It may have to do with changing the UUID for each "GamePRofile" to that of a player who has no skin. This takes time, testing, and more things to import/worry about, so I may not add this feature just yet.

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
  10. Offline

    blok601

    Alright, no worries.
     
  11. Offline

    I Al Istannen

    @Zombie_Striker
    I will be going to sleep. I am quite sure you have your own, but here is a small ReflectionUtil you could use.
    Converting just takes so long and we have 23:12 here ;)
    EDIT: Formatting just got destroyed...
    Code:java
    1.  
    2. package me.ialistannen.theorbit.util;
    3.  
    4. import me.ialistannen.theorbit.TheOrbit;
    5. import org.bukkit.Bukkit;
    6.  
    7. import java.lang.reflect.Constructor;
    8. import java.lang.reflect.Field;
    9. import java.lang.reflect.InvocationTargetException;
    10. import java.lang.reflect.Method;
    11. import java.util.Optional;
    12. import java.util.logging.Level;
    13.  
    14. /**
    15. * A small help with reflection
    16. */
    17. public class ReflectionUtil {
    18.  
    19. private static final String SERVER_VERSION;
    20. private static Constructor<?> nbtTagCompoundConstructor, nbtTagListConstructor, nbtTagStringConstructor;
    21.  
    22. static {
    23. String name = Bukkit.getServer().getClass().getName();
    24. name = name.substring(name.indexOf("craftbukkit.") + "craftbukkit.".length());
    25. name = name.substring(0, name.indexOf("."));
    26.  
    27. SERVER_VERSION = name;
    28. }
    29.  
    30. /**
    31.   * Returns the NMS class.
    32.   *
    33.   * @param name The name of the class
    34.   *
    35.   * @return The NMS class or null if an error occurred
    36.   */
    37. public static Class<?> getNMSClass(String name) {
    38. try {
    39. return Class.forName("net.minecraft.server." + SERVER_VERSION + "." + name);
    40. } catch (ClassNotFoundException e) {
    41. return null;
    42. }
    43. }
    44.  
    45. /**
    46.   * Returns the CraftBukkit class.
    47.   *
    48.   * @param name The name of the class
    49.   *
    50.   * @return The CraftBukkit class or null if an error occurred
    51.   */
    52.  
    53. public static Class<?> getCraftbukkitClass(String name, String packageName) {
    54. try {
    55. return Class.forName("org.bukkit.craftbukkit." + SERVER_VERSION + "." + packageName + "." + name);
    56. } catch (ClassNotFoundException e) {
    57. return null;
    58. }
    59. }
    60.  
    61. /**
    62.   * @return A new NbtTagCompound
    63.   */
    64. public static Object getNbtTagCompound() {
    65. try {
    66. if (nbtTagCompoundConstructor == null) {
    67. nbtTagCompoundConstructor = getConstructor(getNMSClass("NBTTagCompound")).get();
    68. }
    69. return nbtTagCompoundConstructor.newInstance();
    70. e.printStackTrace();
    71. }
    72. return null;
    73. }
    74.  
    75. /**
    76.   * @return A new NbTTagList
    77.   */
    78. public static Object getNbtTagList() {
    79. try {
    80. if (nbtTagListConstructor == null) {
    81. nbtTagListConstructor = getConstructor(getNMSClass("NBTTagList")).get();
    82. }
    83. return nbtTagListConstructor.newInstance();
    84. e.printStackTrace();
    85. }
    86. return null;
    87. }
    88.  
    89. /**
    90.   * @param param The value of the nbtTag.
    91.   *
    92.   * @return A new NbtTagCompound
    93.   */
    94. public static Object getNbtTagString(String param) {
    95. try {
    96. if (nbtTagStringConstructor == null) {
    97. nbtTagStringConstructor = getConstructor(getNMSClass("NBTTagString"), String.class).get();
    98. }
    99. return nbtTagStringConstructor.newInstance(param);
    100. e.printStackTrace();
    101. }
    102. return null;
    103. }
    104.  
    105. /**
    106.   * Invokes the method
    107.   *
    108.   * @param handle The handle to invoke it on
    109.   * @param methodName The name of the method
    110.   * @param parameterClasses The parameter types
    111.   * @param args The arguments
    112.   *
    113.   * @return The resulting object or null if an error occurred / the method didn't return a thing
    114.   */
    115. public static Object invokeMethod(Object handle, String methodName, Class[] parameterClasses, Object... args) {
    116. return invokeMethod(handle.getClass(), handle, methodName, parameterClasses, args);
    117. }
    118.  
    119. /**
    120.   * Invokes the method
    121.   *
    122.   * @param clazz The class to invoke it from
    123.   * @param handle The handle to invoke it on
    124.   * @param methodName The name of the method
    125.   * @param parameterClasses The parameter types
    126.   * @param args The arguments
    127.   *
    128.   * @return The resulting object or null if an error occurred / the method didn't return a thing
    129.   */
    130. public static Object invokeMethod(Class<?> clazz, Object handle, String methodName, Class[] parameterClasses,
    131. Object... args) {
    132. Optional<Method> methodOptional = getMethod(clazz, methodName, parameterClasses);
    133.  
    134. if (!methodOptional.isPresent()) {
    135. return null;
    136. }
    137.  
    138. Method method = methodOptional.get();
    139.  
    140. try {
    141. return method.invoke(handle, args);
    142. e.printStackTrace();
    143. }
    144. return null;
    145. }
    146.  
    147. /**
    148.   * Sets the value of an instance field
    149.   *
    150.   * @param handle The handle to invoke it on
    151.   * @param name The name of the field
    152.   * @param value The new value of the field
    153.   */
    154. @SuppressWarnings("SameParameterValue")
    155. public static void setInstanceField(Object handle, String name, Object value) {
    156. Class<?> clazz = handle.getClass();
    157. Optional<Field> fieldOptional = getField(clazz, name);
    158. if (!fieldOptional.isPresent()) {
    159. return;
    160. }
    161.  
    162. Field field = fieldOptional.get();
    163. if (!field.isAccessible()) {
    164. field.setAccessible(true);
    165. }
    166. try {
    167. field.set(handle, value);
    168. } catch (IllegalAccessException e) {
    169. e.printStackTrace();
    170. }
    171. }
    172.  
    173. /**
    174.   * Sets the value of an instance field
    175.   *
    176.   * @param handle The handle to invoke it on
    177.   * @param name The name of the field
    178.   *
    179.   * @return The result
    180.   */
    181. @SuppressWarnings("SameParameterValue")
    182. public static Object getInstanceField(Object handle, String name) {
    183. Class<?> clazz = handle.getClass();
    184. Optional<Field> fieldOptional = getField(clazz, name);
    185. if (!fieldOptional.isPresent()) {
    186. return handle;
    187. }
    188.  
    189. Field field = fieldOptional.get();
    190. if (!field.isAccessible()) {
    191. field.setAccessible(true);
    192. }
    193. try {
    194. return field.get(handle);
    195. } catch (IllegalAccessException e) {
    196. e.printStackTrace();
    197. }
    198. return null;
    199. }
    200.  
    201. /**
    202.   * Returns an enum constant
    203.   *
    204.   * @param enumClass The class of the enum
    205.   * @param name The name of the enum constant
    206.   *
    207.   * @return The enum entry or null
    208.   */
    209. public static Object getEnumConstant(Class<?> enumClass, String name) {
    210. if (!enumClass.isEnum()) {
    211. return null;
    212. }
    213. for (Object o : enumClass.getEnumConstants()) {
    214. if (name.equals(invokeMethod(o, "name", new Class[0]))) {
    215. return o;
    216. }
    217. }
    218. return null;
    219. }
    220.  
    221. /**
    222.   * Returns the constructor
    223.   *
    224.   * @param clazz The class
    225.   * @param params The Constructor parameters
    226.   *
    227.   * @return The Constructor or an empty Optional if there is none with these parameters
    228.   */
    229. public static Optional<Constructor> getConstructor(Class<?> clazz, Class<?>... params) {
    230. try {
    231. return Optional.of(clazz.getConstructor(params));
    232. } catch (NoSuchMethodException e) {
    233. return Optional.empty();
    234. }
    235. }
    236.  
    237. /**
    238.   * Instantiates the class. Will print the errors it gets
    239.   *
    240.   * @param constructor The constructor
    241.   * @param arguments The initial arguments
    242.   *
    243.   * @return The resulting object, or null if an error occurred.
    244.   */
    245. public static Object instantiate(Constructor<?> constructor, Object... arguments) {
    246. try {
    247. return constructor.newInstance(arguments);
    248. TheOrbit.getInstance().getLogger()
    249. .log(Level.WARNING, "Can't instantiate class " + constructor.getDeclaringClass(), e);
    250. }
    251. return null;
    252. }
    253.  
    254. private static Optional<Method> getMethod(Class<?> clazz, String name, Class<?>... params) {
    255. try {
    256. return Optional.of(clazz.getMethod(name, params));
    257. } catch (NoSuchMethodException ignored) {
    258. }
    259.  
    260. try {
    261. return Optional.of(clazz.getDeclaredMethod(name, params));
    262. } catch (NoSuchMethodException ignored) {
    263. }
    264.  
    265. return Optional.empty();
    266. }
    267.  
    268. private static Optional<Field> getField(Class<?> clazz, String name) {
    269. try {
    270. return Optional.of(clazz.getField(name));
    271. } catch (NoSuchFieldException ignored) {
    272. }
    273.  
    274. try {
    275. return Optional.of(clazz.getDeclaredField(name));
    276. } catch (NoSuchFieldException ignored) {
    277. }
    278.  
    279. return Optional.empty();
    280. }
    281.  
    282. }
    283.  
    284.  
    285.  
     
  12. Offline

    ChipDev

    Does this need protocollib?
     
  13. Offline

    Zombie_Striker

  14. Offline

    I Al Istannen

    @Zombie_Striker
    Could you tell me if this works? It probably won't be that nice though, as you address the field as "b". You can surely change that to a more intelligent matching.
    Codetags because formatting.
    Code:
    package me.ialistannen.theorbit.commands;
    
    import com.mojang.authlib.GameProfile;
    import me.ialistannen.theorbit.TheOrbit;
    import org.bukkit.Bukkit;
    import org.bukkit.ChatColor;
    import org.bukkit.entity.Player;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Optional;
    import java.util.UUID;
    import java.util.logging.Level;
    
    public class PlayerList {
    
        private final Class<?> PACKET_PLAY_OUT_PLAYER_INFO_CLASS =
                ReflectionUtil.getNMSClass("PacketPlayOutPlayerInfo");
        private static final Class<?> PACKET_PLAY_OUT_PLAYER_INFO_DATA_CLASS =
                ReflectionUtil.getNMSClass("PacketPlayOutPlayerInfo$PlayerInfoData");
        private final Class<?> WORLD_SETTINGS_ENUM_GAME_MODE_CLASS =
                ReflectionUtil.getNMSClass("WorldSettings$EnumGamemode");
        private final Object WORLD_SETTINGS_ENUM_GAME_MODE_NOT_SET =
                ReflectionUtil.getEnumConstant(WORLD_SETTINGS_ENUM_GAME_MODE_CLASS, "NOT_SET");
        private final Class<?> CRAFT_CHAT_MESSAGE_CLASS =
                ReflectionUtil.getCraftbukkitClass("CraftChatMessage", "util");
        private final Class<?> PACKET_PLAY_OUT_PLAYER_INFO_ENUM_PLAYER_ACTION_CLASS =
                ReflectionUtil.getNMSClass("PacketPlayOutPlayerInfo$EnumPlayerInfoAction");
        private final Object PACKET_PLAY_OUT_PLAYER_INFO_ENUM_PLAYER_ACTION_REMOVE_PLAYER =
                ReflectionUtil.getEnumConstant(PACKET_PLAY_OUT_PLAYER_INFO_ENUM_PLAYER_ACTION_CLASS, "REMOVE_PLAYER");
        private final Object PACKET_PLAY_OUT_PLAYER_INFO_ENUM_PLAYER_ACTION_ADD_PLAYER =
                ReflectionUtil.getEnumConstant(PACKET_PLAY_OUT_PLAYER_INFO_ENUM_PLAYER_ACTION_CLASS, "ADD_PLAYER");
        private static final Class<?> PACKET_CLASS =
                ReflectionUtil.getNMSClass("Packet");
        private final Class<?> I_CHAT_BASE_COMPONENT_CLASS =
                ReflectionUtil.getNMSClass("IChatBaseComponent");
        private final Constructor<?> PACKET_PLAY_OUT_PLAYER_INFO_DATA_CONSTRUCTOR =
                ReflectionUtil.getConstructor(PACKET_PLAY_OUT_PLAYER_INFO_DATA_CLASS,
                        PACKET_PLAY_OUT_PLAYER_INFO_CLASS, GameProfile.class, int.class,
                        WORLD_SETTINGS_ENUM_GAME_MODE_CLASS, I_CHAT_BASE_COMPONENT_CLASS).get();
    
    
        private final static String[] colorcodeOrder = {"0", "1", "2", "3", "4",
                "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};
        private List<Object> datas = new ArrayList<>();
        private Player player = null;
    
        public static int SIZE_ONE = 20;
        public static int SIZE_TWO = 40;
        public static int SIZE_THREE = 60;
        public static int SIZE_FOUR = 80;
    
        private String[] tabs;
        private int size = 0;
    
        public PlayerList(Player player, int size) {
            this.player = player;
            tabs = new String[80];
            this.size = size;
        }
    
        /**
         * This is here to remind you that you MUST call either this method or the
         * "clearCustomTabs" method. If you do not, the player will continue to see
         * the custom tabs until they relog.
         */
        public void CALL_THIS_BEFORE_RESTARTING() {
            clearCustomTabs();
        }
    
        /**
         * Returns the name of the tab at ID "id".
         *
         * @param id
         *
         * @return
         */
        public String getTabName(int id) {
            return tabs[id];
        }
    
        /**
         * Clears all players from the player's tablist.
         */
        @SuppressWarnings("unchecked")
        public void clearPlayers() {
            Object packet = ReflectionUtil
                    .instantiate(ReflectionUtil.getConstructor(PACKET_PLAY_OUT_PLAYER_INFO_CLASS).get());
    
            List<Object> players = (List<Object>) ReflectionUtil.getInstanceField(packet, "b");
    
            for (Player player2 : Bukkit.getOnlinePlayers()) {
                GameProfile gameProfile = (GameProfile) ReflectionUtil.invokeMethod(player2, "getProfile", new Class[0]);
    
                Object craftChatMessage;
                {
                    Object[] array = (Object[]) ReflectionUtil.invokeMethod(CRAFT_CHAT_MESSAGE_CLASS, null,
                            "fromString", new Class[]{String.class}, player2.getName());
                    craftChatMessage = array[0];
                }
                Object data = ReflectionUtil.instantiate(PACKET_PLAY_OUT_PLAYER_INFO_DATA_CONSTRUCTOR,
                        packet, gameProfile, 1, WORLD_SETTINGS_ENUM_GAME_MODE_NOT_SET, craftChatMessage);
    
                players.add(data);
            }
            sendPackets(player, packet, players,
                    PACKET_PLAY_OUT_PLAYER_INFO_ENUM_PLAYER_ACTION_REMOVE_PLAYER);
        }
    
        /**
         * Clears all the custom tabs from the player's tablist.
         */
        @SuppressWarnings("unchecked")
        public void clearCustomTabs() {
            Object packet = ReflectionUtil
                    .instantiate(ReflectionUtil.getConstructor(PACKET_PLAY_OUT_PLAYER_INFO_CLASS).get());
    
            List<Object> players = (List<Object>) ReflectionUtil.getInstanceField(packet, "b");
    
            for (Object playerData : new ArrayList<>(datas)) {
                GameProfile gameProfile = (GameProfile) ReflectionUtil.invokeMethod(playerData, "a", new Class[0]);
                tabs[fromCID(gameProfile.getName())] = "";
                players.add(playerData);
                datas.remove(playerData);
            }
            sendPackets(player, packet, players,
                    PACKET_PLAY_OUT_PLAYER_INFO_ENUM_PLAYER_ACTION_REMOVE_PLAYER);
        }
    
        /**
         * Clears all the values for a player's tablist. Use this whenever a player
         * first joins if you want to create your own tablist.
         * <p>
         * This is here to remind you that you MUST call either this method or the
         * "clearCustomTabs" method. If you do not, the player will continue to see
         * the custom tabs until they relog.
         */
        public void clearAll() {
            clearPlayers();
            clearCustomTabs();
        }
    
        /**
         * Use this for changing a value at a specific tab.
         *
         * @param id
         * @param name
         */
        public void updateSlot(int id, String name) {
            removeCustomTab(id);
            addValue(id, name);
        }
    
        /**
         * removes a specific player from the player's tablist.
         *
         * @param player
         */
        @SuppressWarnings("unchecked")
        public void removePlayer(Player player) {
            Object packet = ReflectionUtil
                    .instantiate(ReflectionUtil.getConstructor(PACKET_PLAY_OUT_PLAYER_INFO_CLASS).get());
    
            List<Object> players = (List<Object>) ReflectionUtil.getInstanceField(packet, "b");
    
            GameProfile gameProfile = (GameProfile) ReflectionUtil.invokeMethod(player, "getProfile", new Class[0]);
    
            Object craftChatMessage;
            {
                Object[] array = (Object[]) ReflectionUtil.invokeMethod(CRAFT_CHAT_MESSAGE_CLASS, null,
                        "fromString", new Class[]{String.class}, player.getName());
                craftChatMessage = array[0];
            }
            Object data = ReflectionUtil.instantiate(PACKET_PLAY_OUT_PLAYER_INFO_DATA_CONSTRUCTOR,
                    packet, gameProfile, 1, WORLD_SETTINGS_ENUM_GAME_MODE_NOT_SET, craftChatMessage);
    
            players.add(data);
    
            sendPackets(player, packet, players,
                    PACKET_PLAY_OUT_PLAYER_INFO_ENUM_PLAYER_ACTION_REMOVE_PLAYER);
        }
    
        /**
         * Removes a custom tab from a player's tablist.
         *
         * @param id
         */
        @SuppressWarnings("unchecked")
        public void removeCustomTab(int id) {
            Object packet = ReflectionUtil
                    .instantiate(ReflectionUtil.getConstructor(PACKET_PLAY_OUT_PLAYER_INFO_CLASS).get());
    
            List<Object> players = (List<Object>) ReflectionUtil.getInstanceField(packet, "b");
    
            for (Object playerData : new ArrayList<>(datas)) {
                GameProfile gameProfile = (GameProfile) ReflectionUtil.invokeMethod(playerData, "a", new Class[0]);
                if (gameProfile.getName().startsWith(getHexName(id))) {
                    tabs[fromCID(gameProfile.getName())] = "";
                    players.add(playerData);
                    datas.remove(playerData);
                    break;
                }
            }
    
            sendPackets(player, packet, players,
                    PACKET_PLAY_OUT_PLAYER_INFO_ENUM_PLAYER_ACTION_REMOVE_PLAYER);
        }
    
        /**
         * Use this to add a new player to the list
         *
         * @param id
         * @param name
         *
         * @deprecated If all 80 slots have been taken, new values will not
         * be shown and may have the potential to go out of the registered bounds.
         * Use the "updateSlot" method to change a slot.
         */
        @SuppressWarnings("unchecked")
        @Deprecated
        public void addValue(int id, String name) {
            Object packet = ReflectionUtil
                    .instantiate(ReflectionUtil.getConstructor(PACKET_PLAY_OUT_PLAYER_INFO_CLASS).get());
    
            List<Object> players = (List<Object>) ReflectionUtil.getInstanceField(packet, "b");
    
            GameProfile gameProfile = new GameProfile(UUID.randomUUID(),
                    getHexName(id));
    
            Object craftChatMessage;
            {
                Object[] array = (Object[]) ReflectionUtil.invokeMethod(CRAFT_CHAT_MESSAGE_CLASS, null,
                        "fromString", new Class[]{String.class}, getCID(id) + name);
                craftChatMessage = array[0];
            }
            Object data = ReflectionUtil.instantiate(PACKET_PLAY_OUT_PLAYER_INFO_DATA_CONSTRUCTOR,
                    packet, gameProfile, 1, WORLD_SETTINGS_ENUM_GAME_MODE_NOT_SET, craftChatMessage);
    
            GameProfile profile = (GameProfile) ReflectionUtil.invokeMethod(data, "a", new Class[0]);
            tabs[fromCID(profile.getName())] = "";
            players.add(data);
            datas.add(data);
    
            sendPackets(player, packet, players,
                    PACKET_PLAY_OUT_PLAYER_INFO_ENUM_PLAYER_ACTION_ADD_PLAYER);
        }
    
        /**
         * This is used to create the table. If you want to create a custom tablist,
         * then this should be called right after the playlist instance has been created.
         */
        @SuppressWarnings("unchecked")
        public void initTable() {
            clearAll();
            Object packet = ReflectionUtil
                    .instantiate(ReflectionUtil.getConstructor(PACKET_PLAY_OUT_PLAYER_INFO_CLASS).get());
    
            List<Object> players = (List<Object>) ReflectionUtil.getInstanceField(packet, "b");
    
            for (int i = 0; i < size; i++) {
                GameProfile gameProfile = new GameProfile(UUID.randomUUID(),
                        getHexName(i));
    
                Object craftChatMessage;
                {
                    Object[] array = (Object[]) ReflectionUtil.invokeMethod(CRAFT_CHAT_MESSAGE_CLASS, null,
                            "fromString", new Class[]{String.class}, getCID(i) + "");
                    craftChatMessage = array[0];
                }
                Object data = ReflectionUtil.instantiate(PACKET_PLAY_OUT_PLAYER_INFO_DATA_CONSTRUCTOR,
                        packet, gameProfile, 1, WORLD_SETTINGS_ENUM_GAME_MODE_NOT_SET, craftChatMessage);
    
                tabs[fromCID(gameProfile.getName())] = "";
                players.add(data);
                datas.add(data);
    
            }
            sendPackets(player, packet, players,
                    PACKET_PLAY_OUT_PLAYER_INFO_ENUM_PLAYER_ACTION_ADD_PLAYER);
        }
    
        private static String getCID(int id) {
            ChatColor firstChar = ChatColor.getByChar(colorcodeOrder[id
                    / colorcodeOrder.length]);
            ChatColor secondChar = ChatColor.getByChar(colorcodeOrder[id
                    % colorcodeOrder.length]);
            return firstChar + "" + secondChar + "" + ChatColor.RESET;
        }
    
        private static int fromCID(String id) {
            int total = 0;
            for (int i = 0; i < colorcodeOrder.length; i++) {
                if (colorcodeOrder[i].equalsIgnoreCase(id.charAt(0) + "")) {
                    total = 16 * i;
                    break;
                }
            }
            for (int i = 0; i < colorcodeOrder.length; i++) {
                if (colorcodeOrder[i].equalsIgnoreCase(id.charAt(1) + "")) {
                    total += i;
                    break;
                }
            }
            return total;
        }
    
        private static void sendPackets(Player player,
                                        Object packet,
                                        List<?> players,
                                        Object action) {
            try {
                ReflectionUtil.setInstanceField(packet, "a", action);
                ReflectionUtil.setInstanceField(packet, "b", players);
            } catch (Exception e) {
                e.printStackTrace();
            }
            Object handle = ReflectionUtil.invokeMethod(player, "getHandle", new Class[0]);
            Object playerConnection = ReflectionUtil.getInstanceField(handle, "playerConnection");
            ReflectionUtil.invokeMethod(playerConnection, "sendPacket", new Class[]{PACKET_CLASS}, packet);
        }
    
        /**
         * Changes the player. NOTE: Scoreboards will not be transfered to the new player. You will have to re-set each
         * value if the player has changed.
         *
         * @param player
         */
        public void setPlayer(Player player) {
            this.player = player;
        }
    
        /**
         * Returns the player.
         *
         * @return
         */
        public Player getPlayer() {
            return this.player;
        }
    
        /**
         * This returns the ID of a slot at [Row,Columb].
         * <p>
         * Example of useage: The top tab on the first row is at [0,0], and will
         * return ID 0 The bottom of the first row is at [0,19], and will return ID
         * 19 The bottom of the fourth row is at [3,19], and will return ID 79
         *
         * @param row
         * @param col
         *
         * @return
         */
        public int getID(int row, int col) {
            return col * 20 + row;
        }
    
        private static String getHexName(int id) {
            String firstletter = colorcodeOrder[id / 16];
            String secondletter = colorcodeOrder[id % 16];
            return firstletter + secondletter;
        }
    
        /**
         * A small help with reflection
         */
        public static class ReflectionUtil {
    
            private static final String SERVER_VERSION;
            private static Constructor<?> nbtTagCompoundConstructor, nbtTagListConstructor, nbtTagStringConstructor;
    
            static {
                String name = Bukkit.getServer().getClass().getName();
                name = name.substring(name.indexOf("craftbukkit.") + "craftbukkit.".length());
                name = name.substring(0, name.indexOf("."));
    
                SERVER_VERSION = name;
            }
    
            /**
             * Returns the NMS class.
             *
             * @param name The name of the class
             *
             * @return The NMS class or null if an error occurred
             */
            public static Class<?> getNMSClass(String name) {
                try {
                    return Class.forName("net.minecraft.server." + SERVER_VERSION + "." + name);
                } catch (ClassNotFoundException e) {
                    return null;
                }
            }
    
            /**
             * Returns the CraftBukkit class.
             *
             * @param name The name of the class
             *
             * @return The CraftBukkit class or null if an error occurred
             */
    
            public static Class<?> getCraftbukkitClass(String name, String packageName) {
                try {
                    return Class.forName("org.bukkit.craftbukkit." + SERVER_VERSION + "." + packageName + "." + name);
                } catch (ClassNotFoundException e) {
                    return null;
                }
            }
    
            /**
             * @return A new NbtTagCompound
             */
            public static Object getNbtTagCompound() {
                try {
                    if (nbtTagCompoundConstructor == null) {
                        nbtTagCompoundConstructor = getConstructor(getNMSClass("NBTTagCompound")).get();
                    }
                    return nbtTagCompoundConstructor.newInstance();
                } catch (InstantiationException | IllegalAccessException | IllegalArgumentException
                        | InvocationTargetException e) {
                    e.printStackTrace();
                }
                return null;
            }
    
            /**
             * @return A new NbTTagList
             */
            public static Object getNbtTagList() {
                try {
                    if (nbtTagListConstructor == null) {
                        nbtTagListConstructor = getConstructor(getNMSClass("NBTTagList")).get();
                    }
                    return nbtTagListConstructor.newInstance();
                } catch (InstantiationException | IllegalAccessException | IllegalArgumentException
                        | InvocationTargetException e) {
                    e.printStackTrace();
                }
                return null;
            }
    
            /**
             * @param param The value of the nbtTag.
             *
             * @return A new NbtTagCompound
             */
            public static Object getNbtTagString(String param) {
                try {
                    if (nbtTagStringConstructor == null) {
                        nbtTagStringConstructor = getConstructor(getNMSClass("NBTTagString"), String.class).get();
                    }
                    return nbtTagStringConstructor.newInstance(param);
                } catch (InstantiationException | IllegalAccessException | IllegalArgumentException
                        | InvocationTargetException e) {
                    e.printStackTrace();
                }
                return null;
            }
    
            /**
             * Invokes the method
             *
             * @param handle           The handle to invoke it on
             * @param methodName       The name of the method
             * @param parameterClasses The parameter types
             * @param args             The arguments
             *
             * @return The resulting object or null if an error occurred / the method didn't return a thing
             */
            public static Object invokeMethod(Object handle, String methodName, Class[] parameterClasses, Object... args) {
                return invokeMethod(handle.getClass(), handle, methodName, parameterClasses, args);
            }
    
            /**
             * Invokes the method
             *
             * @param clazz            The class to invoke it from
             * @param handle           The handle to invoke it on
             * @param methodName       The name of the method
             * @param parameterClasses The parameter types
             * @param args             The arguments
             *
             * @return The resulting object or null if an error occurred / the method didn't return a thing
             */
            public static Object invokeMethod(Class<?> clazz, Object handle, String methodName, Class[] parameterClasses,
                                              Object... args) {
                Optional<Method> methodOptional = getMethod(clazz, methodName, parameterClasses);
    
                if (!methodOptional.isPresent()) {
                    return null;
                }
    
                Method method = methodOptional.get();
    
                try {
                    return method.invoke(handle, args);
                } catch (IllegalAccessException | InvocationTargetException e) {
                    e.printStackTrace();
                }
                return null;
            }
    
            /**
             * Sets the value of an instance field
             *
             * @param handle The handle to invoke it on
             * @param name   The name of the field
             * @param value  The new value of the field
             */
            @SuppressWarnings("SameParameterValue")
            public static void setInstanceField(Object handle, String name, Object value) {
                Class<?> clazz = handle.getClass();
                Optional<Field> fieldOptional = getField(clazz, name);
                if (!fieldOptional.isPresent()) {
                    return;
                }
    
                Field field = fieldOptional.get();
                if (!field.isAccessible()) {
                    field.setAccessible(true);
                }
                try {
                    field.set(handle, value);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
    
            /**
             * Sets the value of an instance field
             *
             * @param handle The handle to invoke it on
             * @param name   The name of the field
             *
             * @return The result
             */
            @SuppressWarnings("SameParameterValue")
            public static Object getInstanceField(Object handle, String name) {
                Class<?> clazz = handle.getClass();
                Optional<Field> fieldOptional = getField(clazz, name);
                if (!fieldOptional.isPresent()) {
                    return handle;
                }
    
                Field field = fieldOptional.get();
                if (!field.isAccessible()) {
                    field.setAccessible(true);
                }
                try {
                    return field.get(handle);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
                return null;
            }
    
            /**
             * Returns an enum constant
             *
             * @param enumClass The class of the enum
             * @param name      The name of the enum constant
             *
             * @return The enum entry or null
             */
            public static Object getEnumConstant(Class<?> enumClass, String name) {
                if (!enumClass.isEnum()) {
                    return null;
                }
                for (Object o : enumClass.getEnumConstants()) {
                    if (name.equals(invokeMethod(o, "name", new Class[0]))) {
                        return o;
                    }
                }
                return null;
            }
    
            /**
             * Returns the constructor
             *
             * @param clazz  The class
             * @param params The Constructor parameters
             *
             * @return The Constructor or an empty Optional if there is none with these parameters
             */
            public static Optional<Constructor> getConstructor(Class<?> clazz, Class<?>... params) {
                try {
                    return Optional.of(clazz.getConstructor(params));
                } catch (NoSuchMethodException e) {
                    try {
                        return Optional.of(clazz.getDeclaredConstructor(params));
                    } catch (NoSuchMethodException e1) {
                    }
                }
                return Optional.empty();
            }
    
            /**
             * Instantiates the class. Will print the errors it gets
             *
             * @param constructor The constructor
             * @param arguments   The initial arguments
             *
             * @return The resulting object, or null if an error occurred.
             */
            public static Object instantiate(Constructor<?> constructor, Object... arguments) {
                try {
                    return constructor.newInstance(arguments);
                } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
                    TheOrbit.getInstance().getLogger()
                            .log(Level.WARNING, "Can't instantiate class " + constructor.getDeclaringClass(), e);
                }
                return null;
            }
    
            private static Optional<Method> getMethod(Class<?> clazz, String name, Class<?>... params) {
                try {
                    return Optional.of(clazz.getMethod(name, params));
                } catch (NoSuchMethodException ignored) {
                }
    
                try {
                    return Optional.of(clazz.getDeclaredMethod(name, params));
                } catch (NoSuchMethodException ignored) {
                }
    
                return Optional.empty();
            }
    
            private static Optional<Field> getField(Class<?> clazz, String name) {
                try {
                    return Optional.of(clazz.getField(name));
                } catch (NoSuchFieldException ignored) {
                }
    
                try {
                    return Optional.of(clazz.getDeclaredField(name));
                } catch (NoSuchFieldException ignored) {
                }
    
                return Optional.empty();
            }
    
        }
    
    }
     
  15. Offline

    Zombie_Striker

    @I Al Istannen
    I just tried your class, and I am receiving some errors here:
    Code:
      /**
             * Returns the constructor
             *
             * @param clazz  The class
             * @param params The Constructor parameters
             *
             * @return The Constructor or an empty Optional if there is none with these parameters
             */
            public static Optional<Constructor> getConstructor(Class<?> clazz, Class<?>... params) {
                try {
                    return Optional.of(clazz.getConstructor(params));
                } catch (NoSuchMethodException e) {
                    try {
                        return Optional.of(clazz.getDeclaredConstructor(params));
                    } catch (NoSuchMethodException e1) {
                    }
                }
                return Optional.empty();
            }
    on these lines:

    Code:
      
                    return Optional.of(clazz.getConstructor(params));
    
                    return Optional.of(clazz.getDeclaredConstructor(params));
            }
    with the message:
    Did you get these errors? Do you know of a fix for this?
     
  16. Offline

    I Al Istannen

    @Zombie_Striker
    No, I didn't get these errors. Try replacing the "Optional<Constructor>" in the method decleration with "Optional<Constructor<?>>".
     
  17. Offline

    Zombie_Striker

    @I Al Istannen
    With a few other changes, that fixed the issue. Now it should work with 1.8, 1.9, and 1.10 (potentially even 1.11 when it comes out)

    Old Code (Saving it just in case):
    Code:java
    1. import java.lang.reflect.Field;
    2. import java.util.ArrayList;
    3. import java.util.List;
    4. import java.util.UUID;
    5.  
    6.  
    7. import org.bukkit.Bukkit;
    8. import org.bukkit.ChatColor;
    9. import org.bukkit.entity.Player;
    10.  
    11. import com.mojang.authlib.GameProfile;
    12.  
    13. public class PlayerList {
    14.  
    15. private final static String[] colorcodeOrder = { "0", "1", "2", "3", "4",
    16. "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };
    17. private List<PacketPlayOutPlayerInfo.PlayerInfoData> datas = new ArrayList<PacketPlayOutPlayerInfo.PlayerInfoData>();
    18. private Player player = null;
    19.  
    20. public static int SIZE_ONE = 20;
    21. public static int SIZE_TWO = 40;
    22. public static int SIZE_THREE = 60;
    23. public static int SIZE_FOUR = 80;
    24.  
    25. private String[] tabs;
    26. private int size = 0;
    27.  
    28. public PlayerList(Player player, int size) {
    29. this.player = player;
    30. tabs = new String[80];
    31. this.size = size;
    32. }
    33.  
    34. /**
    35.   * This is here to remind you that you MUST call either this method or the
    36.   * "clearCustomTabs" method. If you do not, the player will continue to see
    37.   * the custom tabs until they relog.
    38.   */
    39. public void CALL_THIS_BEFORE_RESTARTING() {
    40. clearCustomTabs();
    41. }
    42.  
    43. /**
    44.   * Returns the name of the tab at ID "id".
    45.   *
    46.   * @param id
    47.   * @return
    48.   */
    49. public String getTabName(int id) {
    50. return tabs[id];
    51. }
    52.  
    53. /**
    54.   * Clears all players from the player's tablist.
    55.   */
    56. @SuppressWarnings("unchecked")
    57. public void clearPlayers() {
    58. PacketPlayOutPlayerInfo packet = new PacketPlayOutPlayerInfo();
    59. List<PacketPlayOutPlayerInfo.PlayerInfoData> players = null;
    60. try {
    61. players = (List<PacketPlayOutPlayerInfo.PlayerInfoData>) getValue(
    62. packet, "b");
    63. } catch (Exception e) {
    64. e.printStackTrace();
    65. }
    66.  
    67. for (Player player2 : Bukkit.getOnlinePlayers()) {
    68. GameProfile gameProfile = ((CraftPlayer) player2).getProfile();
    69. PacketPlayOutPlayerInfo.PlayerInfoData data = packet.new PlayerInfoData(
    70. gameProfile, 1, EnumGamemode.NOT_SET,
    71. CraftChatMessage.fromString(player2.getName())[0]);
    72. players.add(data);
    73. }
    74. sendPackets(player, packet, players,
    75. PacketPlayOutPlayerInfo.EnumPlayerInfoAction.REMOVE_PLAYER);
    76. }
    77.  
    78. /**
    79.   * Clears all the custom tabs from the player's tablist.
    80.   */
    81. @SuppressWarnings("unchecked")
    82. public void clearCustomTabs() {
    83. PacketPlayOutPlayerInfo packet = new PacketPlayOutPlayerInfo();
    84. List<PacketPlayOutPlayerInfo.PlayerInfoData> players = null;
    85. try {
    86. players = (List<PacketPlayOutPlayerInfo.PlayerInfoData>) getValue(
    87. packet, "b");
    88. } catch (Exception e) {
    89. e.printStackTrace();
    90. }
    91.  
    92. for (PlayerInfoData player2 : new ArrayList<>(datas)) {
    93. tabs[fromCID(player2.a().getName())] = "";
    94. players.add(player2);
    95. datas.remove(player2);
    96. }
    97. sendPackets(player, packet, players,
    98. PacketPlayOutPlayerInfo.EnumPlayerInfoAction.REMOVE_PLAYER);
    99. }
    100.  
    101. /**
    102.   * Clears all the values for a player's tablist. Use this whenever a player
    103.   * first joins if you want to create your own tablist.
    104.   *
    105.   * This is here to remind you that you MUST call either this method or the
    106.   * "clearCustomTabs" method. If you do not, the player will continue to see
    107.   * the custom tabs until they relog.
    108.   */
    109. public void clearAll() {
    110. clearPlayers();
    111. clearCustomTabs();
    112. }
    113.  
    114. /**
    115.   * Use this for changing a value at a specific tab.
    116.   *
    117.   * @param id
    118.   * @param name
    119.   */
    120. public void updateSlot(int id, String name) {
    121. removeCustomTab(id);
    122. addValue(id, name);
    123. }
    124.  
    125. /**
    126.   * removes a specific player from the player's tablist.
    127.   *
    128.   * @param player
    129.   */
    130. @SuppressWarnings("unchecked")
    131. public void removePlayer(Player player) {
    132. PacketPlayOutPlayerInfo packet = new PacketPlayOutPlayerInfo();
    133. List<PacketPlayOutPlayerInfo.PlayerInfoData> players = null;
    134. try {
    135. players = (List<PacketPlayOutPlayerInfo.PlayerInfoData>) getValue(
    136. packet, "b");
    137. } catch (Exception e) {
    138. e.printStackTrace();
    139. }
    140.  
    141. GameProfile gameProfile = ((CraftPlayer) player).getProfile();
    142. PacketPlayOutPlayerInfo.PlayerInfoData data = packet.new PlayerInfoData(
    143. gameProfile, 1, EnumGamemode.NOT_SET,
    144. CraftChatMessage.fromString(player.getName())[0]);
    145. players.add(data);
    146.  
    147. sendPackets(player, packet, players,
    148. PacketPlayOutPlayerInfo.EnumPlayerInfoAction.REMOVE_PLAYER);
    149. }
    150.  
    151. /**
    152.   * Removes a custom tab from a player's tablist.
    153.   *
    154.   * @param id
    155.   */
    156. @SuppressWarnings("unchecked")
    157. public void removeCustomTab(int id) {
    158. PacketPlayOutPlayerInfo packet = new PacketPlayOutPlayerInfo();
    159. List<PacketPlayOutPlayerInfo.PlayerInfoData> players = null;
    160. try {
    161. players = (List<PacketPlayOutPlayerInfo.PlayerInfoData>) getValue(
    162. packet, "b");
    163. } catch (Exception e) {
    164. e.printStackTrace();
    165. }
    166.  
    167. for (PlayerInfoData playerdata : new ArrayList<>(datas)) {
    168. if (playerdata.a().getName().startsWith(getHexName(id))) {
    169. tabs[fromCID(playerdata.a().getName())] = "";
    170. players.add(playerdata);
    171. datas.remove(playerdata);
    172. break;
    173. }
    174. }
    175. sendPackets(player, packet, players,
    176. PacketPlayOutPlayerInfo.EnumPlayerInfoAction.REMOVE_PLAYER);
    177. }
    178.  
    179. /**
    180.   * Use this to add a new player to the list
    181.   *
    182.   * DEPRECATION REASON: If all 80 slots have been taken, new values will not
    183.   * be shown and may have the potential to go out of the registered bounds.
    184.   * Use the "updateSlot" method to change a slot.
    185.   *
    186.   * @param id
    187.   * @param name
    188.   */
    189. @SuppressWarnings("unchecked")
    190. @Deprecated
    191. public void addValue(int id, String name) {
    192. PacketPlayOutPlayerInfo packet = new PacketPlayOutPlayerInfo();
    193. List<PacketPlayOutPlayerInfo.PlayerInfoData> players = null;
    194. try {
    195. players = (List<PacketPlayOutPlayerInfo.PlayerInfoData>) getValue(
    196. packet, "b");
    197. } catch (Exception e) {
    198. e.printStackTrace();
    199. }
    200. GameProfile gameProfile = new GameProfile(UUID.randomUUID(),
    201. getHexName(id));
    202. PacketPlayOutPlayerInfo.PlayerInfoData data = packet.new PlayerInfoData(
    203. gameProfile, 1, EnumGamemode.NOT_SET,
    204. CraftChatMessage.fromString(getCID(id) + name)[0]);
    205. tabs[fromCID(data.a().getName())] = "";
    206. players.add(data);
    207. datas.add(data);
    208.  
    209. sendPackets(player, packet, players,
    210. PacketPlayOutPlayerInfo.EnumPlayerInfoAction.ADD_PLAYER);
    211. }
    212.  
    213. /**
    214.   * This is used to create the table. If you want to create a custom tablist,
    215.   * then this should be called right after the playlist instance has been created.
    216.   */
    217. @SuppressWarnings("unchecked")
    218. public void initTable() {
    219. clearAll();
    220. PacketPlayOutPlayerInfo packet = new PacketPlayOutPlayerInfo();
    221. List<PacketPlayOutPlayerInfo.PlayerInfoData> players = null;
    222. try {
    223. players = (List<PacketPlayOutPlayerInfo.PlayerInfoData>) getValue(
    224. packet, "b");
    225. } catch (Exception e) {
    226. e.printStackTrace();
    227. }
    228. for (int i = 0; i < size; i++) {
    229. GameProfile gameProfile = new GameProfile(UUID.randomUUID(),
    230. getHexName(i));
    231. PacketPlayOutPlayerInfo.PlayerInfoData data = packet.new PlayerInfoData(
    232. gameProfile, 1, EnumGamemode.NOT_SET,
    233. CraftChatMessage.fromString(getCID(i) + "")[0]);
    234. tabs[fromCID(data.a().getName())] = "";
    235. players.add(data);
    236. datas.add(data);
    237.  
    238. }
    239. sendPackets(player, packet, players,
    240. PacketPlayOutPlayerInfo.EnumPlayerInfoAction.ADD_PLAYER);
    241. }
    242.  
    243. private static String getCID(int id) {
    244. ChatColor firstChar = ChatColor.getByChar(colorcodeOrder[id
    245. / colorcodeOrder.length]);
    246. ChatColor secondChar = ChatColor.getByChar(colorcodeOrder[id
    247. % colorcodeOrder.length]);
    248. return firstChar + "" + secondChar + "" + ChatColor.RESET;
    249. }
    250.  
    251. private static int fromCID(String id) {
    252. int total = 0;
    253. for (int i = 0; i < colorcodeOrder.length; i++) {
    254. if (colorcodeOrder.equalsIgnoreCase(id.charAt(0) + "")) {
    255. total = 16 * i;
    256. break;
    257. }
    258. }
    259. for (int i = 0; i < colorcodeOrder.length; i++) {
    260. if (colorcodeOrder.equalsIgnoreCase(id.charAt(1) + "")) {
    261. total += i;
    262. break;
    263. }
    264. }
    265. return total;
    266. }
    267.  
    268. private static void setValue(Object instance, String field, Object value)
    269. throws Exception {
    270. Field f = instance.getClass().getDeclaredField(field);
    271. f.setAccessible(true);
    272. f.set(instance, value);
    273. }
    274.  
    275. private static Object getValue(Object instance, String field)
    276. throws Exception {
    277. Field f = instance.getClass().getDeclaredField(field);
    278. f.setAccessible(true);
    279. return f.get(instance);
    280. }
    281.  
    282. private static void sendPackets(Player player,
    283. PacketPlayOutPlayerInfo packet,
    284. List<PacketPlayOutPlayerInfo.PlayerInfoData> players,
    285. PacketPlayOutPlayerInfo.EnumPlayerInfoAction action) {
    286. try {
    287. setValue(packet, "a", action);
    288. setValue(packet, "b", players);
    289. } catch (Exception e) {
    290. e.printStackTrace();
    291. }
    292. ((CraftPlayer) player).getHandle().playerConnection.sendPacket(packet);
    293.  
    294. }
    295. /**
    296.   * Changes the player. NOTE: Scoreboards will not be transfered to the new player. You will have to re-set each value if the player has changed.
    297.   * @param player
    298.   */
    299. public void setPlayer(Player player) {
    300. this.player = player;
    301. }
    302. /**
    303.   * Returns the player.
    304.   * @return
    305.   */
    306. public Player getPlayer() {
    307. return this.player;
    308. }
    309.  
    310. /**
    311.   * This returns the ID of a slot at [Row,Columb].
    312.   *
    313.   * Example of useage: The top tab on the first row is at [0,0], and will
    314.   * return ID 0 The bottom of the first row is at [0,19], and will return ID
    315.   * 19 The bottom of the fourth row is at [3,19], and will return ID 79
    316.   *
    317.   * @param row
    318.   * @param col
    319.   * @return
    320.   */
    321. public int getID(int row, int col) {
    322. return col * 20 + row;
    323. }
    324.  
    325. private static String getHexName(int id) {
    326. String firstletter = colorcodeOrder[id / 16];
    327. String secondletter = colorcodeOrder[id % 16];
    328. return firstletter + secondletter;
    329. }
    330. }
    331.  
     
  18. Offline

    I Al Istannen

    @Zombie_Striker
    If the field name "b" doesn't change :p
    Could probably be abstracted too. Will have a look later.

    What about tab footer and header? (I think 1.8+) Is that supported?
     
    Zombie_Striker likes this.
  19. Offline

    Zombie_Striker

    @I Al Istannen
    Have not tested it yet. I'll try looking for that old server jar (hopefully I still have it ;p).
     
  20. Offline

    defcn

    @Zombie_Striker Does this work for one 1.7? I tried it I get a error in the ide.
     
  21. Offline

    I Al Istannen

    @Zombie_Striker
    Good luck :p
    You can also delete a few methods from the ReflectionUtil, they are not relevant for this (getNbt*** for example).

    And the syntax tags successfully broke the formatting *yay*
    Maybe tabs to spaces can fix it? (NotePad++ -> edit -> Blank Operations -> Tab to space)
    If not the question is: Do you like highlighting and line numbers or correct indentation?
     
  22. Offline

    Zombie_Striker

    @defcn
    Added 1.7 support. You should be be able to use this on all versions (All the way back from 1.2.5 (my oldest saved jar to test on) to now 1.10)

    @I Al Istannen
    I removed those methods. Thanks for pointing that out.

    As for syntax, the reason it broke was because it would recognise [ i] as the italisized mark. Because of this, I may have to revert back to the [ code=java] brackets.

    [OLD CODE]
    Code:
    import com.mojang.authlib.GameProfile;
    import org.bukkit.Bukkit;
    import org.bukkit.ChatColor;
    import org.bukkit.entity.Player;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Optional;
    import java.util.UUID;
    
    public class PlayerList {
    
      private final Class<?> PACKET_PLAY_OUT_PLAYER_INFO_CLASS =
      ReflectionUtil.getNMSClass("PacketPlayOutPlayerInfo");
      private static final Class<?> PACKET_PLAY_OUT_PLAYER_INFO_DATA_CLASS =
      ReflectionUtil.getNMSClass("PacketPlayOutPlayerInfo$PlayerInfoData");
      private final Class<?> WORLD_SETTINGS_ENUM_GAME_MODE_CLASS = (ReflectionUtil.isVersionHigherThan(1,10))?
      ReflectionUtil.getNMSClass("EnumGamemode") : ReflectionUtil.getNMSClass("WorldSettings$EnumGamemode");
    
      private final Object WORLD_SETTINGS_ENUM_GAME_MODE_NOT_SET =
      ReflectionUtil.getEnumConstant(WORLD_SETTINGS_ENUM_GAME_MODE_CLASS, "NOT_SET");
      private final Class<?> CRAFT_CHAT_MESSAGE_CLASS =
      ReflectionUtil.getCraftbukkitClass("CraftChatMessage", "util");
      private final Class<?> PACKET_PLAY_OUT_PLAYER_INFO_ENUM_PLAYER_ACTION_CLASS =
      ReflectionUtil.getNMSClass("PacketPlayOutPlayerInfo$EnumPlayerInfoAction");
      private final Object PACKET_PLAY_OUT_PLAYER_INFO_ENUM_PLAYER_ACTION_REMOVE_PLAYER =
      ReflectionUtil.getEnumConstant(PACKET_PLAY_OUT_PLAYER_INFO_ENUM_PLAYER_ACTION_CLASS, "REMOVE_PLAYER");
      private final Object PACKET_PLAY_OUT_PLAYER_INFO_ENUM_PLAYER_ACTION_ADD_PLAYER =
      ReflectionUtil.getEnumConstant(PACKET_PLAY_OUT_PLAYER_INFO_ENUM_PLAYER_ACTION_CLASS, "ADD_PLAYER");
      private static final Class<?> PACKET_CLASS =
      ReflectionUtil.getNMSClass("Packet");
      private final Class<?> I_CHAT_BASE_COMPONENT_CLASS =
      ReflectionUtil.getNMSClass("IChatBaseComponent");
      private final Constructor<?> PACKET_PLAY_OUT_PLAYER_INFO_DATA_CONSTRUCTOR =
           (Constructor<?>)  ReflectionUtil.getConstructor(PACKET_PLAY_OUT_PLAYER_INFO_DATA_CLASS,
      PACKET_PLAY_OUT_PLAYER_INFO_CLASS, GameProfile.class, int.class,
      WORLD_SETTINGS_ENUM_GAME_MODE_CLASS, I_CHAT_BASE_COMPONENT_CLASS).get();
    
    
      private final static String[] colorcodeOrder = {"0", "1", "2", "3", "4",
      "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};
      private List<Object> datas = new ArrayList<>();
      private Player player = null;
    
      public static int SIZE_ONE = 20;
      public static int SIZE_TWO = 40;
      public static int SIZE_THREE = 60;
      public static int SIZE_FOUR = 80;
    
      private String[] tabs;
      private int size = 0;
    
      public PlayerList(Player player, int size) {
      this.player = player;
      tabs = new String[80];
      this.size = size;
      }
    
      /**
      * This is here to remind you that you MUST call either this method or the
      * "clearCustomTabs" method. If you do not, the player will continue to see
      * the custom tabs until they relog.
      */
      public void CALL_THIS_BEFORE_RESTARTING() {
      clearCustomTabs();
      }
    
      /**
      * Returns the name of the tab at ID "id".
      *
      * @param id
      *
      * @return
      */
      public String getTabName(int id) {
      return tabs[id];
      }
    
      /**
      * Clears all players from the player's tablist.
      */
      @SuppressWarnings("unchecked")
      public void clearPlayers() {
      Object packet = ReflectionUtil
      .instantiate((Constructor<?>)ReflectionUtil.getConstructor(PACKET_PLAY_OUT_PLAYER_INFO_CLASS).get());
    
      List<Object> players = (List<Object>) ReflectionUtil.getInstanceField(packet, "b");
    
      for (Player player2 : Bukkit.getOnlinePlayers()) {
      GameProfile gameProfile = (GameProfile) ReflectionUtil.invokeMethod(player2, "getProfile", new Class[0]);
    
      Object craftChatMessage;
      {
      Object[] array = (Object[]) ReflectionUtil.invokeMethod(CRAFT_CHAT_MESSAGE_CLASS, null,
      "fromString", new Class[]{String.class}, player2.getName());
      craftChatMessage = array[0];
      }
      Object data = ReflectionUtil.instantiate(PACKET_PLAY_OUT_PLAYER_INFO_DATA_CONSTRUCTOR,
      packet, gameProfile, 1, WORLD_SETTINGS_ENUM_GAME_MODE_NOT_SET, craftChatMessage);
    
      players.add(data);
      }
      sendPackets(player, packet, players,
      PACKET_PLAY_OUT_PLAYER_INFO_ENUM_PLAYER_ACTION_REMOVE_PLAYER);
      }
    
      /**
      * Clears all the custom tabs from the player's tablist.
      */
      @SuppressWarnings("unchecked")
      public void clearCustomTabs() {
      Object packet = ReflectionUtil
      .instantiate((Constructor<?>)ReflectionUtil.getConstructor(PACKET_PLAY_OUT_PLAYER_INFO_CLASS).get());
    
      List<Object> players = (List<Object>) ReflectionUtil.getInstanceField(packet, "b");
    
      for (Object playerData : new ArrayList<>(datas)) {
      GameProfile gameProfile = (GameProfile) ReflectionUtil.invokeMethod(playerData, "a", new Class[0]);
      tabs[fromCID(gameProfile.getName())] = "";
      players.add(playerData);
      datas.remove(playerData);
      }
      sendPackets(player, packet, players,
      PACKET_PLAY_OUT_PLAYER_INFO_ENUM_PLAYER_ACTION_REMOVE_PLAYER);
      }
    
      /**
      * Clears all the values for a player's tablist. Use this whenever a player
      * first joins if you want to create your own tablist.
      * <p>
      * This is here to remind you that you MUST call either this method or the
      * "clearCustomTabs" method. If you do not, the player will continue to see
      * the custom tabs until they relog.
      */
      public void clearAll() {
      clearPlayers();
      clearCustomTabs();
      }
    
      /**
      * Use this for changing a value at a specific tab.
      *
      * @param id
      * @param name
      */
      public void updateSlot(int id, String name) {
      removeCustomTab(id);
      addValue(id, name);
      }
    
      /**
      * removes a specific player from the player's tablist.
      *
      * @param player
      */
      @SuppressWarnings("unchecked")
      public void removePlayer(Player player) {
      Object packet = ReflectionUtil
      .instantiate((Constructor<?>)ReflectionUtil.getConstructor(PACKET_PLAY_OUT_PLAYER_INFO_CLASS).get());
    
      List<Object> players = (List<Object>) ReflectionUtil.getInstanceField(packet, "b");
    
      GameProfile gameProfile = (GameProfile) ReflectionUtil.invokeMethod(player, "getProfile", new Class[0]);
    
      Object craftChatMessage;
      {
      Object[] array = (Object[]) ReflectionUtil.invokeMethod(CRAFT_CHAT_MESSAGE_CLASS, null,
      "fromString", new Class[]{String.class}, player.getName());
      craftChatMessage = array[0];
      }
      Object data = ReflectionUtil.instantiate(PACKET_PLAY_OUT_PLAYER_INFO_DATA_CONSTRUCTOR,
      packet, gameProfile, 1, WORLD_SETTINGS_ENUM_GAME_MODE_NOT_SET, craftChatMessage);
    
      players.add(data);
    
      sendPackets(player, packet, players,
      PACKET_PLAY_OUT_PLAYER_INFO_ENUM_PLAYER_ACTION_REMOVE_PLAYER);
      }
    
      /**
      * Removes a custom tab from a player's tablist.
      *
      * @param id
      */
      @SuppressWarnings("unchecked")
      public void removeCustomTab(int id) {
      Object packet = ReflectionUtil
      .instantiate((Constructor<?>)ReflectionUtil.getConstructor(PACKET_PLAY_OUT_PLAYER_INFO_CLASS).get());
    
      List<Object> players = (List<Object>) ReflectionUtil.getInstanceField(packet, "b");
    
      for (Object playerData : new ArrayList<>(datas)) {
      GameProfile gameProfile = (GameProfile) ReflectionUtil.invokeMethod(playerData, "a", new Class[0]);
      if (gameProfile.getName().startsWith(getHexName(id))) {
      tabs[fromCID(gameProfile.getName())] = "";
      players.add(playerData);
      datas.remove(playerData);
      break;
      }
      }
    
      sendPackets(player, packet, players,
      PACKET_PLAY_OUT_PLAYER_INFO_ENUM_PLAYER_ACTION_REMOVE_PLAYER);
      }
    
      /**
      * Use this to add a new player to the list
      *
      * @param id
      * @param name
      *
      * @deprecated If all 80 slots have been taken, new values will not
      * be shown and may have the potential to go out of the registered bounds.
      * Use the "updateSlot" method to change a slot.
      */
      @SuppressWarnings("unchecked")
      @Deprecated
      public void addValue(int id, String name) {
      Object packet = ReflectionUtil
      .instantiate((Constructor<?>)ReflectionUtil.getConstructor(PACKET_PLAY_OUT_PLAYER_INFO_CLASS).get());
    
      List<Object> players = (List<Object>) ReflectionUtil.getInstanceField(packet, "b");
    
      GameProfile gameProfile = new GameProfile(UUID.randomUUID(),
      getHexName(id));
    
      Object craftChatMessage;
      {
      Object[] array = (Object[]) ReflectionUtil.invokeMethod(CRAFT_CHAT_MESSAGE_CLASS, null,
      "fromString", new Class[]{String.class}, getCID(id) + name);
      craftChatMessage = array[0];
      }
      Object data = ReflectionUtil.instantiate(PACKET_PLAY_OUT_PLAYER_INFO_DATA_CONSTRUCTOR,
      packet, gameProfile, 1, WORLD_SETTINGS_ENUM_GAME_MODE_NOT_SET, craftChatMessage);
    
      GameProfile profile = (GameProfile) ReflectionUtil.invokeMethod(data, "a", new Class[0]);
      tabs[fromCID(profile.getName())] = "";
      players.add(data);
      datas.add(data);
    
      sendPackets(player, packet, players,
      PACKET_PLAY_OUT_PLAYER_INFO_ENUM_PLAYER_ACTION_ADD_PLAYER);
      }
    
      /**
      * This is used to create the table. If you want to create a custom tablist,
      * then this should be called right after the playlist instance has been created.
      */
      @SuppressWarnings("unchecked")
      public void initTable() {
      clearAll();
      Object packet = ReflectionUtil
      .instantiate((Constructor<?>)ReflectionUtil.getConstructor(PACKET_PLAY_OUT_PLAYER_INFO_CLASS).get());
    
      List<Object> players = (List<Object>) ReflectionUtil.getInstanceField(packet, "b");
    
      for (int i = 0; i < size; i++) {
      GameProfile gameProfile = new GameProfile(UUID.randomUUID(),
      getHexName(i));
    
      Object craftChatMessage;
      {
      Object[] array = (Object[]) ReflectionUtil.invokeMethod(CRAFT_CHAT_MESSAGE_CLASS, null,
      "fromString", new Class[]{String.class}, getCID(i) + "");
      craftChatMessage = array[0];
      }
      Object data = ReflectionUtil.instantiate(PACKET_PLAY_OUT_PLAYER_INFO_DATA_CONSTRUCTOR,
      packet, gameProfile, 1, WORLD_SETTINGS_ENUM_GAME_MODE_NOT_SET, craftChatMessage);
    
      tabs[fromCID(gameProfile.getName())] = "";
      players.add(data);
      datas.add(data);
    
      }
      sendPackets(player, packet, players,
      PACKET_PLAY_OUT_PLAYER_INFO_ENUM_PLAYER_ACTION_ADD_PLAYER);
      }
    
      private static String getCID(int id) {
      ChatColor firstChar = ChatColor.getByChar(colorcodeOrder[id
      / colorcodeOrder.length]);
      ChatColor secondChar = ChatColor.getByChar(colorcodeOrder[id
      % colorcodeOrder.length]);
      return firstChar + "" + secondChar + "" + ChatColor.RESET;
      }
    
      private static int fromCID(String id) {
      int total = 0;
      for (int i = 0; i < colorcodeOrder.length; i++) {
      if (colorcodeOrder[I].equalsIgnoreCase(id.charAt(0) + "")) {[/I]
      total = 16 * i;
      break;
      }
      }
      for (int i = 0; i < colorcodeOrder.length; i++) {
      if (colorcodeOrder.equalsIgnoreCase(id.charAt(1) + "")) {
      total += i;
      break;
      }
      }
      return total;
      }
    
      private static void sendPackets(Player player,
      Object packet,
      List<?> players,
      Object action) {
      try {
      ReflectionUtil.setInstanceField(packet, "a", action);
      ReflectionUtil.setInstanceField(packet, "b", players);
      } catch (Exception e) {
      e.printStackTrace();
      }
      Object handle = ReflectionUtil.invokeMethod(player, "getHandle", new Class[0]);
      Object playerConnection = ReflectionUtil.getInstanceField(handle, "playerConnection");
      ReflectionUtil.invokeMethod(playerConnection, "sendPacket", new Class[]{PACKET_CLASS}, packet);
      }
    
      /**
      * Changes the player. NOTE: Scoreboards will not be transfered to the new player. You will have to re-set each
      * value if the player has changed.
      *
      * @param player
      */
      public void setPlayer(Player player) {
      this.player = player;
      }
    
      /**
      * Returns the player.
      *
      * @return
      */
      public Player getPlayer() {
      return this.player;
      }
    
      /**
      * This returns the ID of a slot at [Row,Columb].
      * <p>
      * Example of useage: The top tab on the first row is at [0,0], and will
      * return ID 0 The bottom of the first row is at [0,19], and will return ID
      * 19 The bottom of the fourth row is at [3,19], and will return ID 79
      *
      * @param row
      * @param col
      *
      * @return
      */
      public int getID(int row, int col) {
      return col * 20 + row;
      }
    
      private static String getHexName(int id) {
      String firstletter = colorcodeOrder[id / 16];
      String secondletter = colorcodeOrder[id % 16];
      return firstletter + secondletter;
      }
    
      /**
      * A small help with reflection
      */
      public static class ReflectionUtil {
    
      private static final String SERVER_VERSION;
      private static Constructor<?> nbtTagCompoundConstructor, nbtTagListConstructor, nbtTagStringConstructor;
    
      static {
      String name = Bukkit.getServer().getClass().getName();
      name = name.substring(name.indexOf("craftbukkit.") + "craftbukkit.".length());
      name = name.substring(0, name.indexOf("."));
    
      SERVER_VERSION = name;
      }
      public static boolean isVersionHigherThan(int mainVersion,int secondVersion){
         String firstChar=SERVER_VERSION.substring(1,2);
         int fInt = Integer.parseInt(firstChar);
         if(fInt<mainVersion)
           return false;
         StringBuilder secondChar = new StringBuilder();
         for(int i = 3;i<10;i++){
           if(SERVER_VERSION.charAt(i)=='_'||SERVER_VERSION.charAt(i)=='.')
             break;
           secondChar.append(SERVER_VERSION.charAt(i));
         }
         int sInt = Integer.parseInt(secondChar.toString());
         if(sInt<secondVersion)
           return false;
         return true;
      }
    
      /**
      * Returns the NMS class.
      *
      * @param name The name of the class
      *
      * @return The NMS class or null if an error occurred
      */
      public static Class<?> getNMSClass(String name) {
      try {
      return Class.forName("net.minecraft.server." + SERVER_VERSION + "." + name);
      } catch (ClassNotFoundException e) {
      return null;
      }
      }
    
      /**
      * Returns the CraftBukkit class.
      *
      * @param name The name of the class
      *
      * @return The CraftBukkit class or null if an error occurred
      */
    
      public static Class<?> getCraftbukkitClass(String name, String packageName) {
      try {
      return Class.forName("org.bukkit.craftbukkit." + SERVER_VERSION + "." + packageName + "." + name);
      } catch (ClassNotFoundException e) {
      return null;
      }
      }
    
      /**
      * @return A new NbtTagCompound
      */
      public static Object getNbtTagCompound() {
      try {
      if (nbtTagCompoundConstructor == null) {
      nbtTagCompoundConstructor = (Constructor<?>) getConstructor(getNMSClass("NBTTagCompound")).get();
      }
      return nbtTagCompoundConstructor.newInstance();
      } catch (InstantiationException | IllegalAccessException | IllegalArgumentException
      | InvocationTargetException e) {
      e.printStackTrace();
      }
      return null;
      }
    
      /**
      * @return A new NbTTagList
      */
      public static Object getNbtTagList() {
      try {
      if (nbtTagListConstructor == null) {
      nbtTagListConstructor = (Constructor<?>) getConstructor(getNMSClass("NBTTagList")).get();
      }
      return nbtTagListConstructor.newInstance();
      } catch (InstantiationException | IllegalAccessException | IllegalArgumentException
      | InvocationTargetException e) {
      e.printStackTrace();
      }
      return null;
      }
    
      /**
      * @param param The value of the nbtTag.
      *
      * @return A new NbtTagCompound
      */
      public static Object getNbtTagString(String param) {
      try {
      if (nbtTagStringConstructor == null) {
      nbtTagStringConstructor = (Constructor<?>) getConstructor(getNMSClass("NBTTagString"), String.class).get();
      }
      return nbtTagStringConstructor.newInstance(param);
      } catch (InstantiationException | IllegalAccessException | IllegalArgumentException
      | InvocationTargetException e) {
      e.printStackTrace();
      }
      return null;
      }
    
      /**
      * Invokes the method
      *
      * @param handle  The handle to invoke it on
      * @param methodName  The name of the method
      * @param parameterClasses The parameter types
      * @param args  The arguments
      *
      * @return The resulting object or null if an error occurred / the method didn't return a thing
      */
      public static Object invokeMethod(Object handle, String methodName, Class[] parameterClasses, Object... args) {
      return invokeMethod(handle.getClass(), handle, methodName, parameterClasses, args);
      }
    
      /**
      * Invokes the method
      *
      * @param clazz  The class to invoke it from
      * @param handle  The handle to invoke it on
      * @param methodName  The name of the method
      * @param parameterClasses The parameter types
      * @param args  The arguments
      *
      * @return The resulting object or null if an error occurred / the method didn't return a thing
      */
      public static Object invokeMethod(Class<?> clazz, Object handle, String methodName, Class[] parameterClasses,
      Object... args) {
      Optional<Method> methodOptional = getMethod(clazz, methodName, parameterClasses);
    
      if (!methodOptional.isPresent()) {
      return null;
      }
    
      Method method = methodOptional.get();
    
      try {
      return method.invoke(handle, args);
      } catch (IllegalAccessException | InvocationTargetException e) {
      e.printStackTrace();
      }
      return null;
      }
    
      /**
      * Sets the value of an instance field
      *
      * @param handle The handle to invoke it on
      * @param name  The name of the field
      * @param value  The new value of the field
      */
      @SuppressWarnings("SameParameterValue")
      public static void setInstanceField(Object handle, String name, Object value) {
      Class<?> clazz = handle.getClass();
      Optional<Field> fieldOptional = getField(clazz, name);
      if (!fieldOptional.isPresent()) {
      return;
      }
    
      Field field = fieldOptional.get();
      if (!field.isAccessible()) {
      field.setAccessible(true);
      }
      try {
      field.set(handle, value);
      } catch (IllegalAccessException e) {
      e.printStackTrace();
      }
      }
    
      /**
      * Sets the value of an instance field
      *
      * @param handle The handle to invoke it on
      * @param name  The name of the field
      *
      * @return The result
      */
      @SuppressWarnings("SameParameterValue")
      public static Object getInstanceField(Object handle, String name) {
      Class<?> clazz = handle.getClass();
      Optional<Field> fieldOptional = getField(clazz, name);
      if (!fieldOptional.isPresent()) {
      return handle;
      }
    
      Field field = fieldOptional.get();
      if (!field.isAccessible()) {
      field.setAccessible(true);
      }
      try {
      return field.get(handle);
      } catch (IllegalAccessException e) {
      e.printStackTrace();
      }
      return null;
      }
    
      /**
      * Returns an enum constant
      *
      * @param enumClass The class of the enum
      * @param name  The name of the enum constant
      *
      * @return The enum entry or null
      */
      public static Object getEnumConstant(Class<?> enumClass, String name) {
      if (!enumClass.isEnum()) {
      return null;
      }
      for (Object o : enumClass.getEnumConstants()) {
      if (name.equals(invokeMethod(o, "name", new Class[0]))) {
      return o;
      }
      }
      return null;
      }
    
      /**
      * Returns the constructor
      *
      * @param clazz  The class
      * @param params The Constructor parameters
      *
      * @return The Constructor or an empty Optional if there is none with these parameters
      */
      public static Optional<?> getConstructor(Class<?> clazz, Class<?>... params) {
      try {
      return Optional.of(clazz.getConstructor(params));
      } catch (NoSuchMethodException e) {
      try {
      return Optional.of(clazz.getDeclaredConstructor(params));
      } catch (NoSuchMethodException e1) {
      }
      }
      return Optional.empty();
      }
    
      /**
      * Instantiates the class. Will print the errors it gets
      *
      * @param constructor The constructor
      * @param arguments  The initial arguments
      *
      * @return The resulting object, or null if an error occurred.
      */
      public static Object instantiate(Constructor<?> constructor, Object... arguments) {
      try {
      return constructor.newInstance(arguments);
      } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
      //  TheOrbit.getInstance().getLogger()
      //  .log(Level.WARNING, "Can't instantiate class " + constructor.getDeclaringClass(), e);
      }
      return null;
      }
    
      private static Optional<Method> getMethod(Class<?> clazz, String name, Class<?>... params) {
      try {
      return Optional.of(clazz.getMethod(name, params));
      } catch (NoSuchMethodException ignored) {
      }
    
      try {
      return Optional.of(clazz.getDeclaredMethod(name, params));
      } catch (NoSuchMethodException ignored) {
      }
    
      return Optional.empty();
      }
    
      private static Optional<Field> getField(Class<?> clazz, String name) {
      try {
      return Optional.of(clazz.getField(name));
      } catch (NoSuchFieldException ignored) {
      }
    
      try {
      return Optional.of(clazz.getDeclaredField(name));
      } catch (NoSuchFieldException ignored) {
      }
    
      return Optional.empty();
      }
    
      }
    
     
  23. Offline

    defcn

    Attached Files:

  24. Offline

    I Al Istannen

    @defcn
    Show your code please. You are passing the wrong arguments to the constructor.

    @Zombie_Striker
    Let's hope the code tags get fixed eventually :p Though I must say the syntax theme is nicer ;)
     
  25. Offline

    defcn

    @defcn We figured it out! 2 days ago sorry for no update.

    @Zombie_Striker Incase you didn't see my pm it didn't work because I was using spigot! I suggest adding spigot support as that is commonly used.

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Aug 22, 2016
  26. Offline

    timtower Administrator Administrator Moderator

    Logs to prove?
     
  27. Offline

    Zombie_Striker

    @defcn
    Yeah, I saw your post. However, I do not really know what is wrong. All you posted was that you were getting some error, and you did not actually post the rest of the error (where the rest of the error would have told me where the error came from). If you can, please post the full error/ server log so I can see what was causing the problem.
     
  28. Offline

    defcn

    No logs.

    @timtower I compiled myself the src and tried it on spigot. OP compiled me a plugin im PM's didn't work on spigot. It just doesn't show the tab at all its blank.

    Sent from my SM-G935T using Tapatalk
     
    Last edited: Aug 23, 2016
  29. Offline

    timtower Administrator Administrator Moderator

    @defcn Then how do you know what was causing the error?
     
  30. Offline

    Zombie_Striker

    Mojang, why do you love changing names so much?!?

    @defcn
    Fix the issue. The names of packets have changed between 1.7.9 and 1.7.10. The main post has been updated.
     
Thread Status:
Not open for further replies.

Share This Page