2016-07-06 10 views
0

Also habe ich versucht, Reflection noch einmal zu verwenden, um versionsabhängige Klassen (Net Mincraft Server aka NMS) mit allen Versionen des Spiels arbeiten zu lassen. Ich bin auf ein Problem mit einer Methode gestoßen und ich kann nicht herausfinden, was der Fehler ist.NMS: "Das Objekt ist keine Instanz der deklarierten Klasse" Fehler

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(); 
    } 
} 

Dies ist der Teil, der mir Fehler gibt. Genauer gesagt diese 2 Zeilen.

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

und der Fehler wird sagen, dass „Das Objekt nicht eine Instanz der angegebenen Klasse ist“, wenn ich mich richtig erinnere (nicht am PC ATM).

Aber bukkit.getServer gibt das Server-Objekt korrekt zurück und ich weiß nicht, warum es das tut.

Dies ist die Referenz ohne Reflexion.

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

Antwort

0

Standardwarnung zuerst: Verwenden Sie keine Reflexion wie diese. Verwenden Sie keine geraden Strings, um es zu steuern. Verwenden Sie enum s, um die Zeichenfolgen zu liefern, die Ihre getXxxClass-Methoden verwenden.

Das heißt, Sie mit Class<?> obcServerClassInstance = obcCraftServerClass.cast(Bukkit.getServer()).getClass(); zuerst versuchen, eine Art von obcCraftServerClass vertreten zu werfen was getServer() wieder. Dieser Typ muss in der Klassenhierarchie des von getServer zurückgegebenen Typs enthalten sein. Warum brauchst du diese bestimmte Klasse? Wenn Sie das richtig gemacht haben, wird die Klasse obcCraftServerClass eine Supertype von getServer() sein, und Sie können diesen Typ ohne all das unordentliche Casting verwenden. Wenn die Klasse, die durch obcCraftServerClass dargestellt wird, kein Supertyp ist, der von getServer() zurückgegeben wird, haben Sie es vermasselt.

Tun Sie all dies ohne all diese Reflexion. Ja wirklich. Sie sollten nicht mehr reflektieren müssen, als Objekte über die von den utils.getXxxClass-Aufrufe zurückgegebenen Typen instanziieren und die resultierenden Instanzreferenzen nur Variablen ihrer übergeordneten Typen zuweisen. Hör auf mit all dem Class<?> Müll herumzuschrauben.

Ihr Herumstolpern mit Reflektion führt nur zu unhaltbaren Verwicklungen, Herzschmerz und kaputten Codes. Verwenden Sie objektorientierte Programmierung (oder besser, typorientiert), und Sie werden viel glücklicher sein.

+0

Die Sache ist, ich möchte mit mehreren Versionen des Spiels arbeiten können. Dies ist der einzige saubere Weg. Hast du die Referenz auch ohne Reflektion gesehen? Ich muss diese Klasse spielen! – Nick

0

Ich sehe, warum Sie die Klasse übertragen müssen, weil, nun, ich benutze auch die API. Sie irren sich jedoch, wenn Sie sagen, dass dies der einzig saubere Weg ist. Reflection hat viele Nachteile: Es sieht chaotisch aus, es ist schwer zu folgen und es verlangsamt den Code (besonders wenn es so implementiert wird). Auch wenn Sie vorhaben, Reflexionen für den Zugriff auf NMS-Felder und -Methoden zu verwenden, ist es sehr wahrscheinlich, dass es in einer zukünftigen Version vermasselt wird, da Mojang sie bei jeder Überarbeitung neu auffächert. Ich empfehle, je nach Version eine Schnittstelle und mehrere Implementierungen zu erstellen. Auf diese Weise müssen Sie Ihr Plugin immer noch mit jeder neuen Version aktualisieren (nur drei pro Hauptversion. Zum Beispiel können Sie nur 1_9_R1, 1_9_R2 und 1_9_R3 haben), aber Sie könnten einfach Ihren alten Code kopieren und einfügen Importieren Sie die Klassen erneut, damit sie der aktuellen Version entsprechen, und ändern Sie bei Bedarf die Felder und Methoden, auf die Sie zugreifen, entsprechend (Sie müssten dies immer noch mit Reflektion tun). Damit Ihr Plugin auf mehreren Versionen gleichzeitig funktioniert, sollten Sie sich das maven Modulsystem ansehen. Sie können mehrere unabhängige Module erstellen: Basis-Plugin, Schnittstelle und Implementierung (en). Immer wenn eine neue Version erscheint, fügen Sie einfach ein neues Implementierungsmodul hinzu.Um zu überprüfen, welches Modul Sie verwenden müssen, erhalten Sie beim Start die Serverversion und stimmen sie mit der richtigen Implementierung ab. Mbaxter auf den Bukkit Foren hat ein wirklich nettes Tutorial dazu gemacht: https://bukkit.org/threads/support-multiple-minecraft-versions-with-abstraction-maven.115810/. Hoffe das hilft!