NMS:“该对象不是声明的类的实例”错误

时间:2016-07-06 22:29:51

标签: java minecraft bukkit

所以我试图再次使用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));

2 个答案:

答案 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_R11_9_R21_9_R3)但您可以简单地复制/粘贴旧版本中使用的旧代码并重新导入类以匹配当前版本,如果需要,还可以更改相应访问的字段和方法(您仍然需要使用反射)。 要使您的插件同时在多个版本上运行,您应该查看maven模块系统。您可以创建几个独立的模块:基本插件,接口和实现。每当弹出新版本时,您只需添加一个新的实现模块。要检查您需要使用哪个模块,您将在启动时获得服务器版本并将其与正确的实现相匹配。 bukkit论坛上的Mbaxter提供了一个非常好的教程:https://bukkit.org/threads/support-multiple-minecraft-versions-with-abstraction-maven.115810/。希望这有帮助!