2016-07-06 65 views
0

所以我試圖再次使用Reflection來使版本依賴類(Net Mincraft Server又名NMS)與所有遊戲版本一起工作。我遇到了一個方法的問題,我無法確定錯誤是什麼。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(); 
    } 
} 

這是給我錯誤的部分。 更確切地說,這2行。

Class<?> obcServerClassInstance = obcCraftServerClass.cast(Bukkit.getServer()).getClass(); 
    Object nmsServerInstance = obcServerClassInstance.getMethod("getServer").invoke(obcServerClassInstance); 

和錯誤是說,「的對象不是聲明類的一個實例:」如果我沒記錯的話(而不是在PC ATM)。

但bukkit.getServer正確返回服務器對象,我不知道它爲什麼這樣做。

這是沒有反思的參考。

   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

標準警告第一:不要使用這樣的反射。特別是不要使用直線字符串來驅動它。使用enum s來提供您的getXxxClass方法使用的字符串。

這就是說,你與 Class<?> obcServerClassInstance = obcCraftServerClass.cast(Bukkit.getServer()).getClass(); 首先嚐試任何getServer()收益轉換爲通過obcCraftServerClass代表的類型。該類型必須位於由getServer返回的類型的類層次結構中。你爲什麼需要這個特定的課程?如果你這樣做了,obcCraftServerClass代表的類將是由getServer()返回的類型的超類型,並且您可以使用該類型而沒有所有的混亂投射。如果obcCraftServerClass表示的類不是getServer()返回的類型的超類型,那麼您搞砸了。

做所有這些沒有所有的反思。真。您不應該通過utils.getXxxClass調用返回的類型實例化對象,而只需將生成的實例引用分配給它們的超類型的變量。不要再使用所有那些垃圾了。

你用反射來絆倒只會導致不可維護的糾結,心痛和破碎的代碼。使用面向對象的編程(或更好的,面向類型的),你會更快樂。

+0

事情是,我想能夠使遊戲的多個版本的東西工作。這是唯一干淨的方法。另外,你有沒有看到參考沒有反思?我需要投這個班! – Nick

0

我明白了爲什麼你需要投這個類,因爲我也在使用這個API。然而,當你說這是唯一干淨的方式時,你錯了。反射有許多缺點:它看起來很混亂,很難遵循,並且會減慢你的代碼速度(尤其是當這樣實現時)。另外,如果您打算使用反射來訪問NMS字段和方法,它很可能會在未來的版本中搞砸,因爲Mojang會對它們進行每次修訂重新混淆。我建議根據版本創建一個接口和幾個實現。這樣,每一個新版本都需要更新插件(每個主版本只有三個版本,例如,您只能有1_9_R1,1_9_R21_9_R3),但您可以簡單地複製/粘貼舊版本中使用的舊代碼,重新導入類以匹配當前版本,並且,如果需要,更改相應訪問的字段和方法(您仍然必須使用反射來完成此操作)。 爲了讓你的插件同時在多個版本上工作,你應該看看maven模塊系統。您可以創建多個獨立模塊:基本插件,接口和實現。每當新版本彈出時,您只需添加一個新的實現模塊。要檢查您需要使用哪個模塊,請在啓動時獲取服務器版本,並將其與正確的實施相匹配。 Mbaxter在bukkit論壇上提供了一個非常好的教程:https://bukkit.org/threads/support-multiple-minecraft-versions-with-abstraction-maven.115810/。希望這可以幫助!

相關問題