Minecraft 서버 구현 CraftBukkit 용 플러그인을 작성하고 있으며 리플렉션을 통해 발견 된 클래스로 캐스팅해야하는 문제가 발생했습니다.Java의 동적 Typecasting
여기에 있습니다. - v1_7_R3
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import net.minecraft.server.v1_7_R3.EntityAnimal;
import net.minecraft.server.v1_7_R3.EntityHuman;
import org.bukkit.craftbukkit.v1_7_R3.entity.CraftAnimals;
import org.bukkit.craftbukkit.v1_7_R3.entity.CrafteEntity;
import org.bukkit.World;
import org.bukkit.entity.Animals;
import org.bukkit.entity.Entity;
import org.bukkit.event.Listener;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitRunnable;
public class Task extends BukkitRunnable {
private static final int MATING_DISTANCE = 14;
private final JavaPlugin plugin;
private final Random randomizer;
private boolean mateMode;
private double chance;
public Task(JavaPlugin plugin, double chance, boolean mateMode) {
this.plugin = plugin;
this.randomizer = new Random();
this.chance = chance;
this.mateMode = mateMode;
this.theTaskListener = listener;
}
public void run() {
List<World> worlds = plugin.getServer().getWorlds();
Iterator<World> worldIterator = worlds.iterator();
while (worldIterator.hasNext()) {
World world = worldIterator.next();
Collection<Animals> animals = world.getEntitiesByClass(Animals.class);
Iterator<Animals> animalIterator = animals.iterator();
while (animalIterator.hasNext()) {
Animals animal = (Animals) animalIterator.next();
EntityAnimal entity = (EntityAnimal) ((CraftEntity) ((CraftAnimals) animal)).getHandle();
EntityHuman feeder = null;
entity.f(feeder);
}
}
}
}
그러나 당신이 수입에서 볼 수 있듯이,이 코드는 마인 크래프트 서버 패키지의 한 버전의 클래스를 수입 : 관련이없는 부분을 제거하여 내가 쓴 원래의 코드는이처럼 보였다. 이제 문제는, 그 이상을위한 지원을 추가하고 싶습니다. 그리고 Minecraft의 각 버전에 대한 플러그인의 별도 버전을 만들지 않고도 그 일을 할 수 있기를 바랍니다. 패키지의 클래스 대부분은 동일하지만 적어도 패키지 이름은 다르므로 정적 가져 오기를 사용하여 수행 할 수 없습니다 (또는 적어도 그렇게 생각합니까?)
그래서, 내가 필요로하는 정확한 클래스를 얻기 위해 반사를 사용하기로 결정 (이 코드는 다른 클래스에) :
이제private static final String[] requiredClasses = {
"net.minecraft.server.%s.EntityAnimal",
"net.minecraft.server.%s.EntityHuman",
"org.bukkit.craftbukkit.%s.entity.CraftAnimals",
"org.bukkit.craftbukkit.%s.entity.CraftEntity"
};
public static final String[] supportedVersions = {
"v1_7_R3",
"v1_7_R4"
};
public Class<?>[] initializeClasses() {
String correctVersion = null;
for (int i = 0; i < supportedVersions.length; i++) {
String version = supportedVersions[i];
boolean hadIssues = false;
for (int j = 0; j < requiredClasses.length; j++) {
String className = requiredClasses[j];
try {
Class.forName(String.format(className, version));
} catch (ClassNotFoundException e) {
getLogger().log(Level.INFO, String.format("The correct version isn't %s.", version));
hadIssues = true;
break;
}
}
if (!hadIssues) {
correctVersion = version;
break;
}
}
Class[] classes = new Class[requiredClasses.length];
if (correctVersion != null) {
getLogger().log(Level.INFO, String.format("The correct version is %s.", correctVersion));
for (int i = 0; i < requiredClasses.length; i++) {
String className = requiredClasses[i];
try {
classes[i] = Class.forName(String.format(className, correctVersion));
} catch (ClassNotFoundException e) {}
}
} else {
getLogger().log(Level.WARNING, "The version of Minecraft on this server is not supported.");
getLogger().log(Level.WARNING, "Due to this, the plugin will self-disable.");
getLogger().log(Level.WARNING, "To fix this issue, get build that supports your version.");
this.setEnabled(false);
}
return classes;
}
는이 방법이 성공적으로 두 버전에서 필요한 클래스는 현재 지원 검색 . 내가 인스턴스 변수 및 편집 생성자를 사용하여 다시 작성 작업 클래스에이를 통과, 나는 버전 별 수입 제거 : 이제
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import org.bukkit.World;
import org.bukkit.entity.Animals;
import org.bukkit.entity.Entity;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitRunnable;
public class Task extends BukkitRunnable {
private static final int MATING_DISTANCE = 14;
private final JavaPlugin plugin;
private final Random randomizer;
private boolean mateMode;
private double chance;
private Class entityAnimal;
private Class entityHuman;
private Class craftAnimals;
private Class craftEntity;
public Task(JavaPlugin plugin, Class[] classes, double chance, boolean mateMode) {
this.plugin = plugin;
this.randomizer = new Random();
this.chance = chance;
this.mateMode = mateMode;
this.entityAnimal = classes[0];
this.entityHuman = classes[1];
this.craftAnimals = classes[2];
this.craftEntity = classes[3];
}
을, 나는 Task.run() 메소드를 다시 작성할 수 있습니다 어떻게 사용할 수 있도록 반사 수업? typecasting이 많이 포함되어 있으며 불행히도 Minecraft 코드에서 오버로드가 너무 많아서 필요합니다. 예를 들어, entity.f (EntityHuman human) 메소드는 다른 overloading entity.f (Object object) 메소드가 있기 때문에 entity.f (null)을 수행하여 간단히 호출 할 수 없습니다.
나는 여기서 막 다른 골목에 직면하고 있으므로 모든 제안에 대해 개방적입니다. 문제에 대한 더 나은 접근법이 있다면, 나는 또한 그것을 바꿀 수 있습니다.
감사합니다.
-1 * Minecraft 서버 구현 Java의 [이름 지정 패키지] (http://docs.oracle.com/javase/tutorial/java/package/namingpkgs.html) 협약을 의도적으로 무시한 Bukkit *. 더 나쁜 것은 버전으로 오염시키는 것입니다. 그런 일을 한 이유가 무엇인지 알고 있습니까? 나도 알아, 특히 너에게 도움이되지 않아. 그것을 도덕적 인지지로 간주하십시오. (그리고 덧붙여 말하자면, 나는 이것을 말할 수있는 주안점이되고 싶었습니다. 그러나 더 유용한 답변을 찾을 수 있는지 알아 보겠습니다. –
두 개의 분리 된 버전의 클래스가 서로 다른 경향이있어 플러그인이 서로 다른 버전에서 실패하는 경향이 있기 때문에 완료되었다고 생각합니다. 개발자는 모든 이유로 플러그인을 검토해야합니다. 그것은 확실히이 일을하는 최선의 방법은 아니지만. – funstein