我正在为Minecraft服务器实现CraftBukkit编写插件,遇到一个问题,需要转换为通过反射找到的类。
这是交易。我写的原始代码看起来像这样,删除了不相关的部分:
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服务器软件包的一个版本-v1_7_R3中导入了类。现在的问题是,我想添加更多的支持,并且我希望能够为每个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;
}
现在,此方法可以成功检索当前支持的两个版本中的必需类。我使用实例变量和经过编辑的构造函数将它们传递给重写的Task类,然后删除了特定于版本的导入:
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()方法,以便它将使用反射类?涉及到很多类型转换,不幸的是,由于Minecraft代码中大量的重载,这都是必需的。例如,entity.f(EntityHuman human)方法不能简单地通过执行object.f(null)来调用,因为还有其他重载的object.f(Object object)方法。
当我在这里遇到死胡同时,我乐于接受所有建议。如果有更好的方法来解决该问题,我也可以更改为该方法。
谢谢!
阅读了Gerold Broser的回答后,我意识到我必须以某种方式修改我的方法,以便创建某种类型的处理程序类来执行特定于版本的操作-当然,这将是一个接口,该接口将由每个版本一个类。
但是,当我意识到Maven不允许我调用同一groupid.artifactid对象的两个版本时,这成为一个问题。
我很快进行了一些研究,发现了mbaxter的Multiple Versions Tutorial以及AbstractionExamplePlugin实现,完美地演示了这种方法。
该方法非常有效,这是每个Bukkit开发人员都应该使用的方法。这是我完成的插件,如有必要,可作进一步参考。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句