#ProtocolLibとはなんぞや
https://github.com/dmulloy2/ProtocolLib/
マインクラフトのサーバーとクライアント間で送受信されるパケットの操作を簡単にするプラグイン。
#パケット操作の例
- 偽のモブのスポーン
- 偽のブロックの設置
- 別の種類のMobに変身(応用)
他にも色々できる。
#通常の場合
ProtocolLibを使わない通常の場合、BukkitAPIのみでパケット操作はできないので、NMSを扱わないといけない。
###送信時
Packet packet = new PacketPlayOutBlockChange(new BlockPosition(0, 0, 0), Blocks.STONE.getBlockData());
((CraftPlayer) player).getHandle().playerConnection.sendPacket(packet);
###受信時
private void injectPlayer(Player player) {
ChannelDuplexHandler channelDuplexHandler = new ChannelDuplexHandler() {
@Override
public void channelRead(ChannelHandlerContext channelHandlerContext, Object packet) throws Exception {
// 受信時の処理
super.channelRead(channelHandlerContext, packet);
}
@Override
public void write(ChannelHandlerContext channelHandlerContext, Object packet, ChannelPromise channelPromise) throws Exception {
// 送信時の処理
super.write(channelHandlerContext, packet, channelPromise);
}
};
ChannelPipeline pipeline = ((CraftPlayer) player).getHandle().playerConnection.networkManager.channel.pipeline();
pipeline.addBefore("packet_handler", player.getName(), channelDuplexHandler);
}
###PlayerConnectionクラスを継承する方法もある
public class CustomPlayerConnection extends PlayerConnection {
public CustomPlayerConnection(EntityPlayer entityPlayer) {
super(MinecraftServer.getServer(), entityPlayer.playerConnection.networkManager, entityPlayer);
}
@Override
public void a(PacketPlayInBlockPlace packetplayinblockplace) {
// ブロック設置のパケットが送られてきたときの処理
super.a(packetplayinblockplace);
}
}
// 参加時にplayerConnectionを自作クラスに書き換える
@EventHandler
public void onJoin(PlayerJoinEvent playerJoinEvent) {
EntityPlayer entityPlayer = ((CraftPlayer) playerJoinEvent.getPlayer()).getHandle();
entityPlayer.playerConnection = new CustomPlayerConnection(entityPlayer);
}
###NMSは触りたくない!!!!!
ということでProtoclLibを使ってみよう!
#導入
###plugin.ymlのdependにProtocolを追加
name: PluginName
version: 1.0
main: plugin.yourplugin
api-version: 1.16
depend: [ProtocolLib]
###依存関係の追加(Maven)
<repository>
<id>dmulloy2-repo</id>
<url>https://repo.dmulloy2.net/repository/public/</url>
</repository>
<dependency>
<groupId>com.comphenix.protocol</groupId>
<artifactId>ProtocolLib</artifactId>
<version>4.6.0</version>
</dependency>
###依存関係の追加(Gradle)
repositories {
maven { url "https://repo.dmulloy2.net/repository/public/" }
}
dependencies {
compileOnly group: "com.comphenix.protocol", name: "ProtocolLib", version: "4.6.0";
}
※2021/4/22現在、4.6.0が最新
#パケットを送信する
試しに、ブロックを設置するパケットを送信してみます。
ProtocolManager protocolManager = ProtocolLibrary.getProtocolManager();
// パケットコンテナを作成
PacketContainer packetContainer = protocolManager.createPacket(PacketType.Play.Server.BLOCK_CHANGE);
// パケットのフィールドへ書き込み
packetContainer.getBlockPositionModifier().write(0, new BlockPosition(x, y, z));
packetContainer.getBlockData().write(0, WrappedBlockData.createData(Material.STONE));
// 送信
try {
Player player; // 送信したいプレイヤー
protocolManager.sendServerPacket(player, packetContainer);
} catch (InvocationTargetException e) {
e.printStackTrace();
}
※BlockPositionクラスはNMSのではなく、ProtocolLibのもの
送信すると、サーバーにブロックが置かれず、クライアントのみにブロックが置かれる! (更新されるとで元に戻る)
#パケットの受信する
パケットの受信とは、サーバーにプレイヤーからの偽のパケットを送信するイメージ。
試しにプレイヤーからチャットが送られてきた、というパケットをサーバーに受信させてみる。
ProtocolManager protocolManager = ProtocolLibrary.getProtocolManager();
// パケットコンテナを作成
PacketContainer packetContainer = protocolManager.createPacket(PacketType.Play.Client.CHAT);
// パケットのフィールドへ書き込み
packetContainer.getChatComponents().write(0, WrappedChatComponent.fromText("こんにちは"));
packetContainer.getChatTypes().write(0, EnumWrappers.ChatType.CHAT);
// 送信
try {
Player player; // 送り主を指定
protocolManager.recieveClientPacket(player, packetContainer);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
受信すると、プレイヤーから送られてもないチャットがサーバーに受け取られる
#パケットの送信、受信時に処理を加える
BukkitAPIのイベントリスナーのパケット版的なことができる
###クラスの定義
public class PacketListener extend PacketAdapter {
public PacketListener(Plugin plugin, PacketType... types) {
super(plugin, types);
}
@Override
public void onPacketReceiving(PacketEvent event) {
// パケットを受け取った時の処理
}
@Override
public void onPacketSending(PacketEvent event) {
// パケットを送った時の処理
}
}
###リスナー登録
ProtocolManager protocolManager = ProtocolLibrary.getProtocolManager();
protocolManager.addPacketListener(new PacketListener(plugin, types));
コンストラクタの第二引数でイベントを呼ぶパケットの種類を指定できる。
#まとめ
気が向いたらもうちょっと詳しい記事を出します。