William_Shi
本帖最后由 William_Shi 于 2021-8-6 15:53 编辑

测试代码如下(1.16.5 paper环境):

  1.         ProtocolManager manager = ProtocolLibrary.getProtocolManager();
  2.         manager.addPacketListener(new PacketAdapter(
  3.                 PacketAdapter.params().plugin(Test.getProvidingPlugin(Test.class))
  4.                         .serverSide().
  5.                         gamePhase(GamePhase.PLAYING)
  6.                         .options(ListenerOptions.SKIP_PLUGIN_VERIFIER)
  7.                         .types(PacketType.Play.Server.ENTITY_EQUIPMENT)
  8.         ) {
  9.             @Override
  10.             public void onPacketSending(PacketEvent packetEvent) {
  11.                 PacketContainer packet = packetEvent.getPacket();
  12.                 if (packetEvent.getPacketType() == PacketType.Play.Server.ENTITY_EQUIPMENT) {
  13.                     net.minecraft.server.v1_16_R3.WorldServer world =
  14.                             ((org.bukkit.craftbukkit.v1_16_R3.CraftWorld) packetEvent.getPlayer().getWorld()).getHandle();
  15.                     net.minecraft.server.v1_16_R3.Entity entity =
  16.                             world.getEntity(packet.getIntegers().getValues().get(0));
  17.                     if (entity.getBukkitEntity() instanceof LivingEntity) {
  18.                         ((LivingEntity) entity.getBukkitEntity()).addPotionEffect(new PotionEffect(PotionEffectType.GLOWING, 12000, 2));
  19.                         System.out.println(entity.getBukkitEntity());
  20.                     }
  21.                 }
  22.             }

  23.             @Override
  24.             public void onPacketReceiving(PacketEvent packetEvent) {

  25.             }

  26.         });
复制代码


大概效果是对穿上装备的实体附加一个发光效果。
测试效果图片见下:


经测试发现,实体生成时如果穿戴装备(盔.甲、弓)会发包
如果把装备扔给实体,实体穿上了也会触发

但是,当玩家自己穿上装备时没监听到这个包(创造、生存都没有)
现在可能的猜测是
我测试的时候只有一个玩家,这个包不会发给自己?

因为我尝试过发一个PacketPlayOutEntityEquipment给玩家,可以做到穿上假装备的效果,所以数据包本身应该是没问题的。
(这个数据包的结构也相当有意思,是一个单项 ArrayList,元素是 Pair<EnumItemSlot, ItemStack>

已解决。参见置顶回复。感谢大佬不吝赐教。

Rothes
本帖最后由 Rothes 于 2021-8-6 01:56 编辑

玩家自己穿上装备用的可能是
WINDOW_CLICK(客户端发送给服务端 将物品放入某槽位, 可以是装备槽)
SET_SLOT(服务端发送给客户端 确认)
以及刷新库存的时候服务端发送给客户端的WINDOW_ITEMS 这里面包含所有的槽位,但是要先判断是不是玩家库存

William_Shi
Rothes 发表于 2021-8-6 01:54
玩家自己穿上装备用的可能是
WINDOW_CLICK(客户端发送给服务端 将物品放入某槽位, 可以是装备槽)
SET_SLOT( ...

但是这样的话还是有一个问题

比如说 ZombieEntity (以下均用mcp反混淆方便理解) 捡起物品的方法是MobEntity#pickUpItem

而玩家捡起物品则是在 ServerPlayNetHandler(craftbukkit反混淆的PlayerConnection)
其中发了三个包,两个SetSlot 和一个 HeldItemChange

而EntityEquipment包则是在
LivingEntity#tick中调用了detectEquipmentUpdates,detectEquipmentUpdates再调用handleEquipmentChanges
从而发送的

那么 玩家的物品更新就不会被检测到吗?还是玩家的tick方法有所不同?或者玩家没有记录上一个手持物品的字段?

Rothes
William_Shi 发表于 2021-8-6 11:10
但是这样的话还是有一个问题

比如说 ZombieEntity (以下均用mcp反混淆方便理解) 捡起物品的方法是MobEnti ...

SET_SLOT是发给玩家自己的,只有自己接收,因为用SET_SLOT发送了槽位所以就不需要发送ENTITY_EQUIPMENT 也就监听不到,发送别的玩家的装备槽才用ENTITY_EQUIPMENT

William_Shi
本帖最后由 William_Shi 于 2021-8-6 15:53 编辑

两个玩家测试。结果见下。





参见置顶回复。

玩家穿戴装备、更改手中物品,服务端不会向这个玩家发送EntityEquipment包,但是会向其他玩家发送对应的EntityEquipment包更新装备。

再次感谢大佬。

第一页 上一页 下一页 最后一页