Buscar..


Introducción

NMS, también conocido como N et. M inecraft. S erver es el paquete que contiene el código del servidor central de Minecraft. Las clases en este paquete fueron creadas por Mojang (no Bukkit) y, por lo tanto, están en su mayor parte confusas y no están destinadas a ser utilizadas o alteradas. Sin embargo, la interacción con el código del servidor de Minecraft en este nivel le permite modificar casi todos los aspectos del mismo. Esto es importante porque hay numerosas modificaciones que Bukkit no admite.

Observaciones

La API de Bukkit es un envoltorio o capa de abstracción para NMS que permite a los desarrolladores de complementos interactuar con el servidor sin preocuparse por los cambios realizados en la base de código interna.

El uso del código NMS no se recomienda, ya que se interrumpe a menudo entre los cambios de la versión de Minecraft y no puede ser soportado por Bukkit o Spigot, ya que no lo crean, poseen ni mantienen.

Accediendo a la versión actual de Minecraft

Una de las partes más críticas de tratar con el código NMS es poder admitir múltiples versiones de Minecraft. Hay muchas formas de hacer esto, pero una solución simple es usar este código para almacenar la versión como un campo estático público:

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

Este fragmento de código funciona tomando la clase CraftServer:

org.bukkit.craftbukkit.VERSION.CraftServer.class

Obteniendo su paquete:

org.bukkit.craftbukkit.VERSION

Y tomando la subcadena del nombre del paquete a partir del índice 23 que siempre será después de 'org.bukkit.craftbukkit'. (que tiene una longitud de 23 caracteres). Resultando en la cadena final de la versión:

VERSION

Hay varias razones por las que es tan importante poder acceder a la versión actual de Minecraft. Sobre todo porque cualquier acceso a una clase en un servidor que ejecute una versión de Minecraft diferente a la que codificó el complemento generará un Error.

Aquí hay un ejemplo que demuestra cómo resolver ese problema utilizando el campo NMS_VERSION para recuperar una instancia de CraftPlayer (que es una clase NMS) en cualquier versión de 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);
    }
}

El objeto resultante puede manipularse utilizando la reflexión para realizar tareas basadas en NMS sin preocuparse por intentar acceder a la versión incorrecta de la clase.

Sin embargo, incluso este método no es infalible, ya que los campos y los nombres de los métodos de NMS cambian fácilmente, así que lo único que garantiza al hacer esto es que su código no se romperá definitivamente cada vez que se actualice Minecraft.

Conseguir el ping de un jugador

Una cosa muy simple que podría querer hacer con NMS que Bukkit no admite es hacer ping al jugador. Esto se puede hacer así:

/**
 * 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;
}

Si está utilizando un método como getCraftPlayer (Player) que devuelve una instancia de la instancia de CraftPlayer correspondiente del Jugador como un Objeto. Puede acceder a los datos sin importar las clases dependientes de la versión utilizando una reflexión como esta:

/**
 * 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);
    }
}


Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow