Tablist objectives

Discussion in 'Plugin Development' started by ToldiIII, Jul 29, 2019.

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

    ToldiIII

    First, I will start with:
    Why don't I use the Bukkit API to create a score?
    - Because it has a lot of problems, such as not appearing to some users.
    - The object update stops accidentally while the scheduler task is running.
    - It does not appear at all (no method or scheduler query error).

    Java Reflections problem:
    - The query is slower, but the result is satisfactory.
    - There are no accidental freezes during the upgrade
    - It appears correctly for all players

    Same thread: https://bukkit.org/threads/making-custom-scoreboard-objective-on-player-list.476766/ (but randomly closed)

    So the problem is that the tablist custom object does not work when I call the class.
    The code:
    Code:
    public void updatePingTab(Player player) {
      String bukkitVersion = Bukkit.getVersion();
      Class<?> criteria = null;
      if (getPackageVersion().contains("1_8_R1")) {
          criteria = getNMSClass("EnumScoreboardHealthDisplay");
      } else {
         criteria = getNMSClass("IScoreboardCriteria$EnumScoreboardHealthDisplay");
      }
      Class<?> pPlayObj = getNMSClass("PacketPlayOutScoreboardObjective");
      Object playObjIns = pPlayObj.getConstructor().newInstance();
      setField(playObjIns, "a", "ms");
      setField(playObjIns, "d", 0);
      if (bukkitVersion.contains("1.13") || bukkitVersion.contains("1.14")) {
         setField(playObjIns, "b", getAsIChatBaseComponent("PingTab"));
      } else {
          setField(playObjIns, "b", "PingTab");
      }
      setField(playObjIns, "c", criteria.getEnumConstants()[0]);
    
      Constructor<?> score = getNMSClass("ScoreboardScore")
         .getConstructor(getNMSClass("Scoreboard"),
             getNMSClass("ScoreboardObjective"), String.class);
      Method scoreSet = getNMSClass("ScoreboardScore").getMethod("setScore", int.class);
    
      scoreSet.setAccessible(true);
      //console error ˇ
      scoreSet.invoke(score.newInstance(player.getScoreboard(), pPlayObj,
      player.getName().length() <= 14 ? player.getName()
        : player.getName().substring(0, 14)), pingPlayer(player));//console error ^
    
      sendPacket(player, playObjIns);
    }
    
    public static Class<?> getNMSClass(String name) throws ClassNotFoundException {
      return Class.forName("net.minecraft.server." + getPackageVersion() + "." + name);
    }
    
    public static void sendPacket(Player player, Object packet) {
      try {
        Object playerHandle = getNMSPlayer(player);
         Object playerConnection = getFieldObject(playerHandle, playerHandle.getClass().getField("playerConnection"));
         playerConnection.getClass().getMethod("sendPacket", getNMSClass("Packet")).invoke(playerConnection, packet);
        } catch (Throwable t) {
           t.printStackTrace();
        }
    }
    
    public static String getPackageVersion() {
      return Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3];
    }
    
    public static Object getFieldObject(Object object, Field field) throws Throwable {
      return field.get(object);
    }
    
    public static Object getNMSPlayer(Player p) throws Throwable {
      return p.getClass().getMethod("getHandle", new Class[0]).invoke(p, new Object[0]);
    }
    
    public static void setField(Object object, String fieldName, Object fieldValue) throws Throwable {
      setField(object, fieldName, fieldValue, true);
    }
    
    public static void setField(Object object, String fieldName, Object fieldValue, boolean declared) throws Throwable {
      Field field;
    
      if (declared) {
            field = object.getClass().getDeclaredField(fieldName);
        } else {
          field = object.getClass().getField(fieldName);
        }
    
      field.setAccessible(true);
      field.set(object, fieldValue);
    }
    
    public static Object getAsIChatBaseComponent(String name) throws Exception {
      Class<?> iChatBaseComponent = ReflectionUtils.getNMSClass("IChatBaseComponent");
      Method m = iChatBaseComponent.getDeclaredClasses()[0].getMethod("a", String.class);
      return m.invoke(iChatBaseComponent, "{\"text\":\"" + name + "\"}");
    }
    Console error:
    Show Spoiler

    [13:16:53 WARN]: java.lang.IllegalArgumentException: argument type mismatch
    [13:16:53 WARN]: at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    [13:16:53 WARN]: at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
    [13:16:53 WARN]: at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
    [13:16:53 WARN]: at java.lang.reflect.Constructor.newInstance(Unknown Source)
    [13:16:53 WARN]: at hu.montlikadani.tablist.Objects$1.run(Objects.java:108)
    [13:16:53 WARN]: at org.bukkit.craftbukkit.v1_14_R1.scheduler.CraftTask.run(CraftTask.java:84)
    [13:16:53 WARN]: at org.bukkit.craftbukkit.v1_14_R1.scheduler.CraftScheduler.mainThreadHeartbeat(CraftScheduler.java:452)
    [13:16:53 WARN]: at net.minecraft.server.v1_14_R1.MinecraftServer.b(MinecraftServer.java:1147)
    [13:16:53 WARN]: at net.minecraft.server.v1_14_R1.DedicatedServer.b(DedicatedServer.java:420)
    [13:16:53 WARN]: at net.minecraft.server.v1_14_R1.MinecraftServer.a(MinecraftServer.java:1074)
    [13:16:53 WARN]: at net.minecraft.server.v1_14_R1.MinecraftServer.run(MinecraftServer.java:918)
    [13:16:53 WARN]: at java.lang.Thread.run(Unknown Source)
     
    Last edited: Jul 29, 2019
  2. Offline

    ToldiIII

  3. Offline

    Machine Maker

    Are you still using 1.8? The API for scoreboards works so much better in future versions. Is there a reason you are not updating to much more recent versions?
     
  4. Offline

    ToldiIII

    Nop, I use each version from 1.8 to 1.14. As I described in the Bukkit API bugs, it doesn't always work properly when used. Right now, I can't show proof because there are no users who have reported a similar problem. By the way, I want it because many users still want support for 1.8, so I try to support 1.8 and above.
     
Thread Status:
Not open for further replies.

Share This Page