bukkit
NMS
サーチ…
前書き
NMS、またN等として知られています。 M inecraft。 S erverは、コアのMinecraftサーバーコードを含むパッケージです。このパッケージのクラスは、Mojang(Bukkitではなく)によって作成されたもので、ほとんどが難読化されており、使用や変更を意図していません。ただし、このレベルでMinecraftサーバーコードとやりとりすることで、ほぼすべての側面を変更できます。これは、Bukkitがサポートしていない多くの変更があるため重要です。
備考
Bukkit APIは、プラグイン開発者が内部コードベースの変更を気にせずにサーバーとやりとりすることを可能にする、NMSのラッパーまたは抽象レイヤーです。
NMSコードの使用は、Minecraftのバージョン変更の間に頻繁に壊れてしまい、BukkitやSpigotがそれを作成、所有、保守しないためサポートできません。
現在のMinecraftバージョンへのアクセス
NMSコードを扱う際の最も重要な部分の1つは、複数の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
そして、常に 'org.bukkit.craftbukkit'の後ろにあるインデックス23から始まるパッケージ名の部分文字列を取る。 (長さは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が更新するたびにあなたのコードが間違いなく壊れないことです。
プレーヤーのPingを取得する
BukkitがサポートしていないNMSでやりたいことは、プレイヤーのpingを取得することです。これは次のようにすることができます:
/**
* 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)のような、Playerの対応するCraftPlayerインスタンスのインスタンスをObjectとして返すメソッドを使用している場合。次のように、バージョン依存のクラスをインポートせずにデータにアクセスすることができます。
/**
* 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);
}
}