访问当前的 Minecraft 版本

处理 NMS 代码最关键的部分之一是能够支持多种 Minecraft 版本。有很多方法可以做到这一点,但一个简单的解决方案是使用此代码将版本存储为公共静态字段:

public static final String NMS_VERSION = Bukkit.getServer().getClass().getPackage().getName().substring(23);

此代码段通过获取 CraftServer 类来工作:

org.bukkit.craftbukkit.VERSION.CraftServer.class

获得它的包裹:

org.bukkit.craftbukkit.VERSION

并从索引 23 开始获取包名称的子字符串,该索引始终位于’org.bukkit.craftbukkit’之后。 (长度为 23 个字符)。导致最终的 VERSION 字符串:

VERSION

有许多原因导致能够访问当前的 Minecraft 版本如此重要。主要是因为在运行与插件编码的不同的 Minecraft 版本的服务器上的任何类访问都将引发错误。

下面是一个演示如何通过使用 NMS_VERSION 字段在任何 Minecraft 版本上检索 CraftPlayer 实例(这是一个 NMS 类)来解决该问题的示例。

/**
 * Invokes the getHandle() method on the player's CraftPlayer instance to
 * retrieve the EntityPlayer representation of the player as an Object to
 * avoid package version change issues
 * 
 * @param player
 *            the player to cast
 * @return the NMS EnityPlayer representation of the player
 */
public static Object getCraftPlayer(Player player) {
    try {
        return Class.forName("org.bukkit.craftbukkit." + NMS_VERSION + ".entity.CraftPlayer")
                .getMethod("getHandle")
                .invoke(player);
    } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException | ClassNotFoundException e) {
        throw new Error(e);
    }
}

然后,可以使用反射来操作生成的对象,以执行基于 NMS 的任务,而无需担心尝试访问类的错误版本。

即使这种方法也不是万无一失,因为 NMS 字段和方法名称很容易改变,所以你唯一要做的就是保证每次 Minecraft 更新时你的代码都不会破坏。