2016-07-06 3 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); 

그리고 오류가 "객체가 선언 된 클래스의 인스턴스가 아닌"고 말하고 I는 (은 PC ATM에서하지 않음) 정확히 기억합니다.

하지만 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

경고 : 먼저 이와 같은 리플렉션을 사용하지 마십시오. 특히 직선 스트링을 사용하지 마십시오. getXxxClass 메서드에서 사용하는 문자열을 전달하려면 enum을 사용하십시오.

obcCraftServerClass로 표시되는 형식으로 어떤 getServer() 수익을 캐스팅 Class<?> obcServerClassInstance = obcCraftServerClass.cast(Bukkit.getServer()).getClass(); 처음으로 시도하고, 말했다. 이 유형은 getServer에 의해 반환 된 유형의 클래스 계층 구조에 있어야합니다. 왜 그 특별한 수업이 필요한가요? 이 작업을 수행 한 경우 obcCraftServerClass으로 표시된 클래스는 getServer()에 의해 반환되는 상위 유형이되며 지저분한 형 변환없이 해당 유형을 사용할 수 있습니다. obcCraftServerClass으로 표시된 클래스가 getServer()에 의해 반환 된 클래스의 상위 유형이 아닌 경우 사용자가 망쳤습니다.

이러한 모든 것을 반영하지 않고 모두 수행하십시오. 정말. utils.getXxxClass 호출에서 반환 된 유형을 통해 객체를 인스턴스화하는 것보다 더 많은 리플렉션을 수행 할 필요가 없으며 결과 인스턴스 참조를 해당 수퍼 유형의 변수에 할당하면됩니다. 모든 것을 Class<?> 쓰레기와 함께 그만 두지 마십시오.

리플렉션을 사용하여 넘어지면 엉킴이 생기고 상심하고 코드가 깨집니다. 객체 지향 프로그래밍 (또는 더 나은, 유형 지향)을 사용하고, 훨씬 더 행복합니다.

+0

문제는 게임의 여러 버전에서 작동하도록 할 수 있기를 바랍니다. 이것은 유일한 깨끗한 방법입니다. 또한 리플렉션없이 참조를 보았습니까? 그 수업을 캐스팅해야 해! – Nick

0

내가 API를 사용하고 있기 때문에 클래스를 전송해야하는 이유가 있습니다. 그러나 이것이 유일한 유일한 방법이라고 말하면 잘못된 것입니다. 리플렉션에는 많은 단점이 있습니다. 뒤죽박죽이어서 따르기가 어렵고 코드가 느려집니다 (특히 이와 같이 구현 된 경우). 또한, NMS 필드와 메소드에 액세스하기 위해 반사를 사용하려는 경우, Mojang이 각 수정본을 다시 난독 화하기 때문에 향후 버전에서 엉망이 될 가능성이 높습니다. 버전에 따라 인터페이스 및 여러 구현을 만드는 것이 좋습니다. 이렇게하면 새 버전이 나올 때마다 플러그인을 업데이트해야합니다 (예 : 1_9_R1, 1_9_R21_9_R3 만 가질 수 있음). 이전 버전에서 사용한 이전 코드를 복사하여 붙여 넣기 만하면됩니다. 현재 버전과 일치하도록 클래스를 다시 가져오고, 필요한 경우 그에 따라 액세스되는 필드와 메소드를 변경하십시오 (리플렉션을 사용하여 액세스해야합니다). 플러그인을 여러 버전에서 동시에 사용하려면 maven 모듈 시스템을 살펴 봐야합니다. 여러 개의 독립 모듈을 만들 수 있습니다 : 기본 플러그인, 인터페이스 및 구현. 새 버전이 나올 때마다 새 구현 모듈을 추가하기 만하면됩니다.사용할 모듈을 확인하려면 시작할 때 서버 버전을 가져 와서 올바른 구현과 일치시켜야합니다. bukkit 포럼의 Mbaxter는 이것에 관한 멋진 튜토리얼을 만들었습니다 : https://bukkit.org/threads/support-multiple-minecraft-versions-with-abstraction-maven.115810/. 희망이 도움이!