# 数据包基本运用
# 介绍
本章 也可以说是发包的介绍 如何拦截数据包进行篡改 来达到效果
或者是直接发送一个数据包 让客户端收到
# 篡改数据包
如上图所示 我们有两种类型的事件
- PacketReceiveEvent 玩家发送给服务端的数据包
- PacketSendEvent 服务端发送给客户端的数据包
# 例子
@SubscribeEvent
fun onPacketPlayOutEntityEquipment(event: PacketSendEvent) {
if (event.packet.name != "PacketPlayOutEntityEquipment") {
return
}
val item = event.packet.read<List<MoJangPair<EnumItemSlot, ItemStack>>>("slots") ?: return
val copy = mutableListOf<MoJangPair<EnumItemSlot, ItemStack>>()
item.forEach {
val events = PacketReadItemEvent(event.player, toBukkit(it.second))
events.call()
copy.add(MoJangPair(it.first, toNMSCopy(events.itemStack)))
}
event.packet.write("slots", copy)
}
# 发送数据包
我们需要构造一个数据包的对象 以发送一个虚拟头颅方块的数据给玩家为例子
val parse = MojangsonParser.parse("""{Owner:{Id:"014df015-7eba-4ad0-a0e0-83164b7a45f2",Properties:{textures:[{Value:"方块的贴图"}]},Name:"自定义方块"},Rot:${rot}b,x:${x},y:${y},z:${z},id:"minecraft:skull",SkullType:3b}""".trimIndent())
val packetPlayOutTileEntityData = PacketPlayOutTileEntityData(
BlockPosition(loc.blockX, loc.blockY, loc.blockZ), 4, parse
)
player.sendPacket(packetPlayOutTileEntityData)
# 复杂的例子
发送 BossBar 实现
注意:这里我们减少了一些对于数据包本身的叙述(例如如何寻找我要的包的类型,这些应该是必备技能),仅介绍 TabooLib 方法。
根据常识可知,我们应该发送 PacketPlayOutBoss 这个数据包。我们去寻找这两个包的构造参数。(这里我使用反编译的办法)
1.16 及以下的版本的参数如下:

1.17 及以上的版本的参数如下:
(这就是 TabooLib 带给我们的自信,我们可以直接使用反混淆版的服务端,由此我们可以很清楚的看到 id、operation 等字段)
可知 1.16 及以下版本有一个无参构造函数,1.17+ 没有(有一个私有构造函数,不方便)。对于没有无参构造函数的类,我们可以通过 TabooLib Reflex 提供的函数 Class

我们可以看到在 1.17+ 中,我们使用的全是反混淆(Mojang Mapping)的字段名。不用担心,TabooLib 会自动帮我们处理。
外部调用方法: NMS.INSTANCE.sendBossBar()
使用到的别名如下:
// 1.16
typealias NMS16PacketPlayOutBoss = net.minecraft.server.v1_16_R3.PacketPlayOutBoss
typealias NMS16PacketPlayOutBossAction = net.minecraft.server.v1_16_R3.PacketPlayOutBoss.Action
typealias NMS16BossBattleBarColor = net.minecraft.server.v1_16_R3.BossBattle.BarColor
typealias NMS16BossBattleBarStyle = net.minecraft.server.v1_16_R3.BossBattle.BarStyle
typealias CraftChatMessage16 = org.bukkit.craftbukkit.v1_16_R3.util.CraftChatMessage
// Universal
typealias NMSPacketPlayOutBoss = net.minecraft.network.protocol.game.PacketPlayOutBoss
typealias NMSBossBattleBarColor = net.minecraft.world.BossBattle.BarColor
typealias NMSBossBattleBarStyle = net.minecraft.world.BossBattle.BarStyle
typealias CraftChatMessage19 = org.bukkit.craftbukkit.v1_19_R3.util.CraftChatMessage
可以看到,1.16 以下的版本中,我们只写了一套 1.16 的实现,实际上在 1.15、1.14 等版本也可运行,因为 TabooLib 会自动帮我们处理 nmsProxy 内的跨版本和混淆表。
数据包监听器
TabooLib 有数据包监听器,我们可以监听数据包发送和接收。
数据包不会自动处理跨版本和混淆表。
使用方法:
/**
* 数据包接收
*/
@SubscribeEvent
fun e(e: PacketReceiveEvent) {
// 随便拿一个数据包举例子
if (e.packet.name == "PacketPlayInSetCreativeSlot") {
// 读
val nmsItem = e.packet.read<Any>("b")!!
// 写
e.packet.write("b", nmsItem)
}
}
/**
* 数据包发送
*/
@SubscribeEvent
fun e(e: PacketSendEvent) {
// 随便拿一个数据包举例子
if (e.packet.name == "PacketPlayOutOpenWindowMerchant") {
// 读
val merchant = e.packet.read<Any>("b")!!
// 写
e.packet.write("b", NMS.INSTANCE.adaptMerchantRecipe(merchant, e.player))
}
}
进阶
25分钟
← KetherScript 物品操作工具 →