封包与同步

基本信息

属性 值
封包目录 src/main/java/serverutils/net/
封包类总数 44(git ls-files 'src/main/java/serverutils/net/Message*.java' | wc -l)
辅助类 2(ServerUtilitiesNetHandler、TransferHelper),不继承封包基类
基类 serverutils.lib.net.MessageBase(implements IMessage)
方向基类 MessageToClient / MessageToServer
网络库 FML SimpleNetworkWrapper + FMLEmbeddedChannel
通道数 6
编解码 自研 DataIn / DataOut(lib/io/)

封包基类

MessageBase(src/main/java/serverutils/lib/net/MessageBase.java:8-27)把 Forge 的字节码接口转成模组自己的读写:

public abstract NetworkWrapper getWrapper();

@Override
public final void toBytes(ByteBuf buf) { writeData(new DataOut(buf)); }

@Override
public final void fromBytes(ByteBuf buf) { readData(new DataIn(buf)); }

public void writeData(DataOut data) {}
public void readData(DataIn data) {}
  • toBytes / fromBytes 都是 final,子类不能覆写,只能实现 writeData / readData
  • 两个 writeData/readData 都是空实现,不需要序列化的封包可不覆写
  • getWrapper() 声明为 abstract,强制每个封包声明自己属于哪条通道

6 条通道

ServerUtilitiesNetHandler(net/ServerUtilitiesNetHandler.java:6-11)以 NetworkWrapper.newWrapper(id) 建立:

常量 通道 id S2C C2S 合计
GENERAL serverutilities 12 5 17
FILES utilities_files 5 4 9
CLAIMS utilities_claim 3 4 7
MY_TEAM utilities_my_team 3 2 5
STATS utilities_stats 2 2 4
EDIT_CONFIG utilities_config 1 1 2
合计 6 条 26 18 44

[!NOTE] 通道 id 前缀不一致:GENERAL 用 serverutilities(与 modid 同名),其余 5 条用 utilities_ 前缀。这是源码中的事实,非本条目的归纳。

init() 方法(:14-65)共执行 45 次注册调用 = 44 个封包 + 1 次 GENERAL.registerBlank()(:17)。registerBlank()(lib/net/NetworkWrapper.java:37)注册一个不处理任何消息的占位封包 —— 其存在是为了在 GENERAL 通道上占住一个序号,本仓代码中没有任何地方发送它。

GENERAL 通道(17)

通用 GUI、通知与同步封包。

S2C(12)

封包 用途
MessageSyncData 通用配置/数据同步(@Config.Sync 下发的载体)
MessageNotification 通知消息
MessageCloseGui 要求客户端关闭 GUI
MessageAdminPanelGuiResponse 管理面板 GUI 响应
MessageAdminTeamList 队伍列表
MessageAdminTeamAction 队伍操作结果
MessageAdminTeamPlayerList 队伍成员列表
MessageAdminTeamClaimsList 队伍领地区块列表
MessageUpdatePlayTime 游戏时长更新(world.show_playtime)
MessageCommandsResponse 指令列表响应
MessageUpdateTabName TAB 名称更新(chat.replace_tab_names / tab.*)
MessageInvseeContainer invsee 背包内容(对应 /view)
MessageTransfer 切服数据包(对应 /transfer)

C2S(5)

封包 用途
MessageAdminPanelGui 请求打开管理面板
MessageAdminPanelAction 提交管理面板操作
MessageAdminTeamAction 提交队伍操作
MessageCommandsRequest 请求指令列表
MessageInvseeSwitch 切换 invsee 背包槽位页

MessageAdminPanelGui / MessageAdminPanelAction / MessageAdminTeamAction 双向同名:MessageToClient 与 MessageToServer 各一个(如 MessageAdminPanelAction 是 C2S,MessageAdminPanelGuiResponse / MessageAdminTeamAction 是 S2C),复用同一条通道传输两个方向的同名类。

FILES 通道(9)

文件与崩溃报告相关的 GUI 数据。

S2C(5):MessageEditNBT(NBT 编辑内容)、MessageEditNBTRequest、MessageRanks、MessageViewCrashList、MessageViewCrashResponse C2S(4):MessageEditNBTResponse、MessageRankModify、MessageViewCrash、MessageViewCrashDelete

MessageRankModify(C2S)与 MessageRanks(S2C)配合,实现 Rank 指令 的 GUI 化编辑。

CLAIMS 通道(7)

领地区块数据与 Navigator 地图同步,是本模组数据量最大的通道。

S2C(3):MessageClaimedChunksUpdate、MessageNavigatorUpdate、MessageNavigatorUpdateKnown C2S(4):MessageClaimedChunksRequest、MessageClaimedChunksModify、MessageNavigatorRequest、MessageNavigatorValidateKnown

4 个 Navigator 封包由 Navigator 集成 使用。MessageNavigatorUpdateKnown / MessageNavigatorValidateKnown 是一对增量同步:服务端推送客户端尚未知的区块,客户端回报已收到,避免全量重复传输。

MY_TEAM 通道(5)

玩家自己的队伍 GUI。

S2C(3):MessageSelectTeamGui、MessageMyTeamGuiResponse、MessageMyTeamPlayerList C2S(2):MessageMyTeamGui、MessageMyTeamAction

STATS 通道(4)

排行榜 GUI。

S2C(2):MessageLeaderboardListResponse、MessageLeaderboardResponse C2S(2):MessageLeaderboardList、MessageLeaderboard

EDIT_CONFIG 通道(2)

最精简的通道,只有一对请求/响应。

S2C:MessageEditConfig C2S:MessageEditConfigResponse

它承载 /team settings、/team settings_for、/player settings 等配置编辑 GUI。

版本一致性检查

ServerUtilities.checkModLists(ServerUtilities.java:102-105):

@NetworkCheckHandler
public boolean checkModLists(Map<String, String> map, Side side) {
    return side != Side.CLIENT || map.containsKey(MOD_ID) && map.get(MOD_ID).equals(VERSION);
}
  • 服务端侧(side == Side.SERVER)恒返回 true
  • 客户端侧要求服务端存在 modid serverutilities 且版本串与本地 VERSION 完全相等

VERSION 是 Tags.GRADLETOKEN_VERSION(ServerUtilities.java:38),由 RetroFuturaGradle 在编译时用真实版本号替换(gradle.properties 中 generateGradleTokenClass = serverutils.Tags)。

[!IMPORTANT] 因为是严格字符串相等而非版本区间比较,服务端与客户端的 ServerUtilities 版本必须逐字符一致,否则客户端会被拒绝连接。

读写机制

方向 基类 处理入口
S2C MessageToClient / MessageToClientHandler lib/net/MessageToClientHandler.java
C2S MessageToServer / MessageToServerHandler lib/net/MessageToServerHandler.java

编解码基础设施在 lib/io/:DataIn、DataOut、DataReader(及其 FileDataReader、HttpDataReader、ResourceDataReader、StreamDataReader、StringDataReader 五个实现)、RequestMethod。

[!WARNING] lib/io/HttpDataReader.java:105 有一个空的 catch (Exception e) {} —— 读取失败被完全静默吞掉,不记日志也不抛出。外部 HTTP 数据源出错时不会有任何提示。

相关条目