Szukaj…


Wprowadzenie

NMS, znany również jako N i in. M inecraft. S erwerze jest opakowanie, które zawiera rdzeń Minecraft kod serwera. Klasy w tym pakiecie zostały wykonane przez Mojanga (nie Bukkita) i dlatego są w większości zaciemnione i nie powinny być używane ani zmieniane. Jednak interakcja z kodem serwera Minecraft na tym poziomie pozwala modyfikować prawie każdy jego aspekt. Jest to istotne, ponieważ istnieje wiele modyfikacji, których Bukkit nie obsługuje.

Uwagi

Interfejs API Bukkit jest warstwą otoki lub abstrakcji dla NMS, która umożliwia programistom wtyczek interakcję z serwerem bez obawy o zmiany wprowadzone w wewnętrznej bazie kodu.

Używanie kodu NMS jest odradzane, ponieważ często zrywa między zmianami wersji Minecraft i nie może być obsługiwane przez Bukkit lub Spigot, ponieważ nie tworzą go, nie posiadają ani nie utrzymują.

Dostęp do aktualnej wersji Minecraft

Jedną z najbardziej krytycznych części postępowania z kodem NMS jest możliwość obsługi wielu wersji Minecraft. Można to zrobić na wiele sposobów, ale prostym rozwiązaniem jest użycie tego kodu do przechowywania wersji jako publicznego pola statycznego:

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

Ten fragment kodu działa, biorąc klasę CraftServer:

org.bukkit.craftbukkit.VERSION.CraftServer.class

Otrzymanie pakietu:

org.bukkit.craftbukkit.VERSION

Biorąc podłańcuch nazwy pakietu zaczynając od indeksu 23, który zawsze będzie po „org.bukkit.craftbukkit”. (który ma długość 23 znaków). Wynikiem jest końcowy ciąg VERSION:

VERSION

Istnieje wiele powodów, dla których tak ważne jest, aby mieć dostęp do bieżącej wersji gry Minecraft. Głównie dlatego, że jakikolwiek dostęp do klasy na serwerze z inną wersją Minecraft niż kodowana przez wtyczkę spowoduje błąd.

Oto przykład, który pokazuje, jak rozwiązać ten problem za pomocą pola NMS_VERSION aby pobrać instancję CraftPlayer (która jest klasą NMS) w dowolnej wersji 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);
    }
}

Wynikowym obiektem można następnie manipulować za pomocą odbicia w celu wykonania zadań opartych na NMS bez obawy o próbę uzyskania dostępu do niewłaściwej wersji klasy.

Nawet ta metoda nie jest jednak niezawodna, ponieważ nazwy pól i metod NMS zmieniają się łatwo, więc jedyne, co gwarantujesz, robiąc to, to to, że Twój kod na pewno nie zepsuje się za każdym razem, gdy aktualizujesz Minecraft.

Uzyskiwanie sygnału ping gracza

Jedną bardzo prostą rzeczą, którą możesz chcieć zrobić z NMS, której Bukkit nie obsługuje, jest pobranie ping gracza. Można to zrobić w następujący sposób:

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

Jeśli używasz metody takiej jak getCraftPlayer (Player), która zwraca instancję odpowiadającej instancji CraftPlayer jako Obiekt. Możesz uzyskać dostęp do danych bez importowania klas zależnych od wersji, używając refleksji w następujący sposób:

/**
 * 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
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow