bukkit
NMS
Поиск…
Вступление
NMS, также известный как N et. M inecraft. S erver - это пакет, содержащий основной код сервера Minecraft. Классы в этом пакете были сделаны Mojang (не Bukkit) и поэтому в основном запутываются и не предназначены для использования или изменения. Однако взаимодействие с кодом сервера Minecraft на этом уровне позволяет вам модифицировать почти все его аспекты. Это важно, поскольку существуют многочисленные модификации, которые Bukkit не поддерживает.
замечания
API Bukkit - это слой обертки или абстракции для NMS, который позволяет разработчикам плагина взаимодействовать с сервером, не беспокоясь об изменениях, внесенных во внутреннюю кодовую базу.
Использование кода NMS не рекомендуется, поскольку он часто прерывается между изменениями версии Minecraft и не может поддерживаться Bukkit или Spigot, поскольку они не создают, не владеют или не поддерживают его.
Доступ к текущей версии Minecraft
Одной из наиболее важных частей работы с кодом NMS является поддержка версий Mulitple 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
для извлечения экземпляра CraftPlayer (который является классом NMS) в любой версии Minecraft.
/**
* 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.
Получение пинга игрока
Одна очень простая вещь, которую вы можете захотеть сделать с NMS, которую Bukkit не поддерживает, - это получить пинг игрока. Это можно сделать следующим образом:
/**
* Gets the players ping by using NMS to access the internal 'ping' field in
* EntityPlayer
*
* @param player
* the player whose ping to get
* @return the player's ping
*/
public static int getPing(Player player) {
EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();
return entityPlayer.ping;
}
Если вы используете метод getCraftPlayer (Player), который возвращает экземпляр соответствующего экземпляра CraftPlayer Player как объекта. Вы можете получить доступ к данным, не импортируя классы, зависящие от версии, с помощью отражения следующим образом:
/**
* Gets the player's ping using reflection to avoid breaking on a Minecraft
* update
*
* @param player
* the player whose ping to get
* @return the player's ping
*/
public static int getPing(Player player) {
try {
Object craftPlayer = getCraftPlayer(player);
return (int) craftPlayer.getClass().getField("ping").get(craftPlayer);
} catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) {
throw new Error(e);
}
}