MENU

一次对 ProtocolLib 发送地图(Map Data)更新数据包的研究

December 17, 2021 • Read: 403 • Bukkit,Minecraft,后端

一、前言

当我们想对玩家手持地图的渲染进行修改时,通常需要对 MapView 增加 MapRenderer 来实现修改,但是通过正常的方式去创建会生成一些非临时的东西 (map_xxx.data) 或受服务端影响无法同时多人进行不同的 MapRenderer 渲染 (已知 CatServer 似乎有这个问题),那我们还有更好的方法去操作地图的渲染吗?有,NMS 向我们提供了相应的包 PacketPlayOutMap,但我们本篇文章不是使用 PacketPlayOutMap 来实现,而是通过 ProtocolLib 封装的来进行发包。

二、解析

使用过 ProtocolLib 开发过发包的开发者都知道,我们发送一个数据包时需要找到对应的包在 PacketType 的对象,是的,就是对象,PacketType 是一个类而不是枚举,上面我们已经说了包是 PacketPlayOutMap,我们只需要直接反编译查看这个包的结构。

从图片可以看到,PacketPlayOutMap 拥有 9 个变量,这些变量有不同的用处,我们需要知道这些变量的用处。
我们打开 https://wiki.vg/Protocol 找到对应包的位置 https://wiki.vg/Protocol#Map_Data
在这里就不讲解如何看各个变量对应的了,我们直接解释 PacketPlayOutMap 变量的各个意思

private int a; // Map 的 Id, 我们发包的话使用 0 即可,如果是拦截包修改请不要改动此项
private byte b; // 地图缩放级别, 从 0 到 4, 其中 4 最大
private boolean c; // 是否显示玩家在地图上的图标
private MapIcon[] d; // 地图上的图标数组, 具体请反编译 net.minecraft.server.xxx.MapIcon
private int e; // 渲染起始位置 x, 一般写 0
private int f; // 渲染起始位置 y, 一般写 0
private int g; // 列数
private int h; // 行数
private byte[] i; // 像素点数组, 位置计算 (x + y * 图像宽度)

既然我们知道各个变量的意思了,我们就可以开始创建要发送的包了

// 创建对应的 packetPlayOutMap 数据包
PacketContainer packet = new PacketContainer(PacketType.Play.Server.MAP);
// 写入地图的缩放级别
packet.getBytes().write(0, (byte) 4);
// 写入 MapId
packet.getIntegers().write(0, 0);
// 写入起始 x 点
packet.getIntegers().write(1, 0);
// 写入起始 y 点
packet.getIntegers().write(2, 0);
// 写入列数
packet.getIntegers().write(3, 128);
// 写入行数
packet.getIntegers().write(4, 128);
// 写入是否图标跟随, 因为我这里没有图标, 所以 true false 都可以
packet.getBooleans().write(0, true);
// 写入一个空的图标数组
packet.getModifier().write(3, new MapIcon[0]);
Image image = resultData.asImage(); // 这是我自己的 Image 对象, 在这仅做示范
byte[] bytes = MapPalette.imageToBytes(image); // org.bukkit.map 下的工具类 MapPalette
// 写入像素点数组
packet.getByteArrays().write(0, bytes);
try {
    ProtocolLibrary.getProtocolManager().sendServerPacket(player, packet);
} catch (InvocationTargetException e) {
    e.printStackTrace();
}

我们在游戏中测试看看执行的效果
如果你想自己绘制像素点,可以通过上方注释的位置计算方式来绘制像素点。
如果是想通过拦截 PacketPlayOutMap 来修改地图数据的话记得不要修改到 MapId 喔!

三、结尾

至此本篇文章结束,欢迎各位指出文章中错误的地方,本人也仅是看了一会相关 wiki,最后附上一些用得到的链接。
https://wiki.vg/Protocol#Map_Data
https://minecraft.fandom.com/wiki/Map_item_format#Color_table

Last Modified: March 20, 2023