跳到正文
烈焰甘蔗Wiki

网络协议

BetterBuildersWands 有一个简单的 FML SimpleNetworkWrapper 通道 "bbwands",共 3 个包(其中 2 个仅在安装 AE2 时注册)。

通道注册

BetterBuildersWandsMod.preInit():

networkWrapper = NetworkRegistry.INSTANCE.newSimpleChannel("bbwands");
属性 值
通道名 bbwands
类型 SimpleNetworkWrapper(FML simpleimpl)
句柄工具 GenericHandler<REQ>(network/GenericHandler.java)

GenericHandler 是 1.7 / 1.8 代码统一的线程安全包装:它实现 IMessageHandler<REQ, IMessage>,在 onMessage 里转调抽象方法 processMessage 并返回 null(不回送 reply)。

包注册表

discriminator 包类 处理端 方向 条件
0 PacketWandActivate Side.SERVER 客户端 → 服务端 无条件
1 SynchronizeAEItemQuantity.SyncServer Side.SERVER 客户端 → 服务端 需安装 appliedenergistics2
2 SynchronizeAEItemQuantity.SyncClient Side.CLIENT 服务端 → 客户端 需安装 appliedenergistics2

Side.SERVER / Side.CLIENT 指处理端所在的一侧。 SyncServer 名字里的 “Server” 指的是"发给服务端的请求", 它由客户端发出、服务端处理。

注册代码:

networkWrapper.registerMessage(PacketWandActivate.Handler.class, PacketWandActivate.class, 0, Side.SERVER);
if (Loader.isModLoaded("appliedenergistics2")) {
    networkWrapper.registerMessage(SynchronizeAEItemQuantity.SyncServer.class,
                                    SynchronizeAEItemQuantity.SyncServer.class, 1, Side.SERVER);
    networkWrapper.registerMessage(SynchronizeAEItemQuantity.SyncClient.class,
                                    SynchronizeAEItemQuantity.SyncClient.class, 2, Side.CLIENT);
}

包 0:PacketWandActivate(模式切换)

由 模式切换热键 和 流体模式切换热键 触发。

字段 类型 说明
keyActive boolean 方向模式键的边沿状态
keyFluidActive boolean 流体模式键的边沿状态

序列化格式(2 字节):

buffer.writeBoolean(keyActive);
buffer.writeBoolean(keyFluidActive);

服务端处理(PacketWandActivate.Handler.processMessage):

  1. 取发送者的 EntityPlayerMP
  2. keyActive 为真且手持物品 instanceof IWandItem → 调 nextMode(),回复聊天消息
  3. keyFluidActive 为真且手持物品 instanceof IWandItem → 调 nextFluidMode(),回复聊天消息

手持非魔杖时静默忽略,不报错。客户端只上报"键变了", 服务端才决定是否有实际效果,因此伪造包也无法在没有魔杖时改动任何状态。

该文件源自 VeinMiner 项目(LGPL),源码头部保留了原始版权声明。

包 1 / 2:SynchronizeAEItemQuantity(AE2 数量同步)

仅在安装 AE2 时注册,用于让客户端知道 ME 网络里有多少目标方块。

SyncServer(客户端 → 服务端,discriminator 1)

字段 类型
stack ItemStack
stack = ByteBufUtils.readItemStack(buf);

客户端没有 AE2 网格访问权,所以只能把想查的 ItemStack 发给服务端。

SyncClient(服务端 → 客户端,discriminator 2)

字段 类型
size int(匹配到的数量)
BasicPlayerShim.AEItemSize = buf.readInt();   // 存入静态字段

服务端 SyncServer.onMessage 的逻辑:

情况 回复
obj == null 或 stack == null SyncClient(0)
obj.rangeCheck() 为假 SyncClient(0)
网格中匹配到物品 SyncClient(min(found.getStackSize(), Integer.MAX_VALUE))
未匹配到 SyncClient(0)

客户端缓存策略

BasicPlayerShim.getAEItem 的客户端分支维护一个 LastItem 静态记录:

情况 行为
查询的物品变了 立即发 SyncServer,返回上一次缓存的 AEItemSize
物品没变,且 worldTime % 10 == 0 每 10 个世界刻发一次,返回缓存值
玩家身上没有任何无线终端 AEItemSize = 0

由于回复是异步的,客户端第一次查询某物品时返回的是上一次缓存值 (可能为 0),所以"刚切换目标方块时上限算不准、放置不出方块"是已知现象, 等 10 刻(0.5 秒)后重试即可。

AEItemSize 是 public static int,属于全局共享状态 —— 多玩家服务器上 各自客户端进程独立,不互相干扰。

放置本身不走网络包

魔杖的方块放置完全在服务端完成:ItemBasicWand.onItemUse 的 onItemUse 在服务端被调用时(!world.isRemote)才执行 WandWorker.placeBlocks(),客户端只是发一次原版的 C0S 使用物品包。 方块与物品的同步由 Minecraft 自带的区块更新机制负责。

相关条目

浏览全部模组