(Bukkit)Tablist目标

时间:2019-08-14 07:53:24

标签: reflection minecraft bukkit

同一线程:https://bukkit.org/threads/tablist-objectives.480313/

首先,我将从以下内容开始: 为什么我不使用Bukkit API来创建乐谱?

  • 因为它有很多问题,例如某些用户看不到。
  • 调度程序任务正在运行时,对象更新意外停止。
  • 它根本不出现(没有方法或调度程序查询错误)。

Java思考问题:

  • 查询速度较慢,但​​结果令人满意。
  • 升级过程中没有意外冻结
  • 对所有玩家正确显示

所以我的问题是,如果我使用Java Reflection创建标签列表目标,那么为什么调用时它会引发IllegalArgumentException?

之所以这样思考,是因为许多用户仍在使用Bukkit 1.8,并且应该受到支持。但这适用于1.8及更高版本。

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 + "\"}");
}

结果应如下所示: https://imgur.com/gallery/AIHO80M

控制台错误:

[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)

1 个答案:

答案 0 :(得分:0)

ScoreboardScore类的构造函数需要参数Scoreboard, ScoreboardObjective, String。但是使用player.getScoreboard(), pPlayObj, playerName,您将使用Scoreboard, Class<?>, String创建一个实例。