所以我试图再次使用Reflection来使版本依赖类(Net Mincraft Server又名NMS)适用于所有版本的游戏。我遇到了一个方法的问题,我无法弄清楚错误是什么。
public NPCReflection(UUID id, String name, World world) {
this.id = id;
this.name = name;
this.entityId = (int) Math.ceil(Math.random() * 1000) + 2000;
try {
Class<?> nmsServerClass = utils.getNMSClass("MinecraftServer");
Class<?> nmsWorldServerClass = utils.getNMSClass("WorldServer");
Class<?> obcCraftServerClass = utils.getOBCClass("CraftServer");
Class<?> obcCraftWorldClass = utils.getOBCClass("CraftWorld");
Class<?> nmsEntityPlayerClass = utils.getNMSClass("EntityPlayer");
Class<?> nmsPlayerInteractManager = utils.getNMSClass("PlayerInteractManager");
Class<?> obcServerClassInstance = obcCraftServerClass.cast(Bukkit.getServer()).getClass();
Object nmsServerInstance = obcServerClassInstance.getMethod("getServer").invoke(obcServerClassInstance);
Class<?> obcWorldClassInstance = obcCraftWorldClass.cast(world).getClass();
Object nmsWorldInstance = obcWorldClassInstance.getMethod("getHandle").invoke(obcWorldClassInstance);
Constructor<?> entityPlayerConstructor = nmsEntityPlayerClass.getConstructor(nmsServerClass, nmsWorldServerClass, GameProfile.class, nmsPlayerInteractManager);
Object entityPlayer = entityPlayerConstructor.newInstance(nmsServerInstance, nmsWorldInstance, new GameProfile(id, name), nmsPlayerInteractManager.getConstructor(nmsWorldServerClass).newInstance(nmsWorldInstance));
utils.setValue(entityPlayer, "a", entityId);
this.entityPlayer = entityPlayer;
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
}
这是给我错误的部分。 更准确地说,这两行。
Class<?> obcServerClassInstance = obcCraftServerClass.cast(Bukkit.getServer()).getClass();
Object nmsServerInstance = obcServerClassInstance.getMethod("getServer").invoke(obcServerClassInstance);
错误是说“对象不是声明的类的实例”,如果我没记错的话(不是在PC上)。
但是bukkit.getServer正确地返回了Server对象,我不知道为什么会这样做。
这是没有反思的参考。
Bukkit.getServer().getPluginManager().registerEvents(this, this);
MinecraftServer nmsServer = ((CraftServer) Bukkit.getServer()).getServer();
WorldServer nmsWorld = ((CraftWorld) Bukkit.getWorlds().get(0)).getHandle();
npc = new EntityPlayer(nmsServer, nmsWorld, new GameProfile(UUID.fromString("c793afb5-c4b7-4fdb-a100-b761315913c4"), "PogoStick29"), new PlayerInteractManager(nmsWorld));
答案 0 :(得分:0)
首先是标准警告:不要使用这样的反射。特别是不要使用直线琴弦来驱动它。使用enum
来传递getXxxClass
方法使用的字符串。
那就是说,你正在努力
Class<?> obcServerClassInstance = obcCraftServerClass.cast(Bukkit.getServer()).getClass();
首先将getServer()
返回任何内容转换为obcCraftServerClass
所代表的类型。该类型必须位于getServer
返回的类型的类层次结构中。你为什么需要那个特定的班级?如果你做得对,那么由obcCraftServerClass
表示的类将是getServer()
返回的类的超类型,你可以使用那种类型而不需要那么混乱的转换。如果obcCraftServerClass
表示的类不是getServer()
返回的类的超类型,那么你搞砸了。
在没有所有反思的情况下完成所有这些。真。您不必通过utils.getXxxClass
调用返回的类型实例化对象,而只需将生成的实例引用分配给其超类型的变量。停止用所有Class<?>
垃圾拧紧。
你用反射绊倒只会导致无法维持的缠结,心痛和破碎的代码。使用面向对象的编程(或更好,面向类型),你会更快乐。
答案 1 :(得分:0)
我知道为什么你需要转换类,因为我也在使用API。但是,当你说这是唯一干净的方式时,你错了。反射有许多缺点:它看起来很乱,很难遵循,它会减慢你的代码(特别是在这样的实现时)。此外,如果您计划使用反射来访问NMS字段和方法,那么很可能它会在未来的版本中被搞砸,因为Mojang会对每个版本进行重新混淆。我建议根据版本创建一个接口和几个实现。这样,您仍然需要在每个新版本中更新您的插件(每个主要版本只有三个。例如,您只能拥有1_9_R1
,1_9_R2
和1_9_R3
)但您可以简单地复制/粘贴旧版本中使用的旧代码并重新导入类以匹配当前版本,如果需要,还可以更改相应访问的字段和方法(您仍然需要使用反射)。
要使您的插件同时在多个版本上运行,您应该查看maven模块系统。您可以创建几个独立的模块:基本插件,接口和实现。每当弹出新版本时,您只需添加一个新的实现模块。要检查您需要使用哪个模块,您将在启动时获得服务器版本并将其与正确的实现相匹配。 bukkit论坛上的Mbaxter提供了一个非常好的教程:https://bukkit.org/threads/support-multiple-minecraft-versions-with-abstraction-maven.115810/。希望这有帮助!