Sök…


Introduktion

NMS, även känd som N et. M inecraft. S erver är paketet som innehåller kärnan i Minecraft-servern. Klasserna i detta paket gjordes av Mojang (inte Bukkit) och är därför mestadels dolda och inte avsedda att användas eller ändras. Men om du interagerar med Minecraft-serverkoden på denna nivå kan du ändra nästan alla aspekter av den. Detta är viktigt eftersom det finns många ändringar som Bukkit inte stöder.

Anmärkningar

Bukkit API är ett omslag eller abstraktionslager för NMS som gör det möjligt för plugin-utvecklare att interagera med servern utan att oroa sig för ändringar som gjorts i den interna kodbasen.

Användning av NMS-kod avskräcks eftersom den ofta bryts mellan Minecraft-versionändringar och inte kan stöds av Bukkit eller Spigot eftersom de inte skapar, äger eller underhåller den.

Åtkomst till den aktuella Minecraft-versionen

En av de mest kritiska delarna av att hantera NMS-koden är att kunna stödja flera versioner av Minecraft. Det finns många sätt att göra detta, men en enkel lösning är att använda den här koden för att lagra versionen som ett offentligt statiskt fält:

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

Det här kodavsnittet fungerar genom att ta CraftServer-klassen:

org.bukkit.craftbukkit.VERSION.CraftServer.class

Skaffa sitt paket:

org.bukkit.craftbukkit.VERSION

Och ta substrängen till paketnamnet med början vid index 23 som alltid kommer att vara efter 'org.bukkit.craftbukkit.' (som har en längd på 23 tecken). Resultat i den sista VERSION-strängen:

VERSION

Det finns ett antal skäl till varför det är så viktigt att kunna komma åt den aktuella Minecraft-versionen. Mycket för att all åtkomst av en klass på en server som kör en annan Minecraft-version än vad pluginet kodade med kommer att kasta ett fel.

Här är ett exempel som visar hur man löser problemet genom att använda fältet NMS_VERSION att hämta en instans av CraftPlayer (som är en NMS-klass) på vilken Minecraft-version som helst.

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

Det resulterande objektet kan sedan manipuleras med reflektion för att utföra NMS-baserade uppgifter utan att oroa dig för att försöka komma åt fel version av klassen.

Även denna metod är dock inte idiotsäker, eftersom NMS-fält- och metodnamn enkelt ändras, så det enda du garanterar genom att göra detta är att din kod definitivt inte går sönder varje gång Minecraft uppdateras.

Få en spelares ping

En mycket enkel sak som du kanske vill göra med NMS som Bukkit inte stöder är att få spelarens ping. Detta kan göras så här:

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

Om du använder en metod som getCraftPlayer (Player) som returnerar en instans av spelarens motsvarande CraftPlayer-instans som ett objekt. Du kan komma åt data utan att importera de versionberoende klasserna genom att använda reflektion som denna:

/**
 * 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
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow