BaseModule
公共运行时库:被 ServerModule 与 CrossModule 依赖。包含 Netty TCP 帧编解码、CmdRpc 分发管线、Proto 元数据注册表、Spring 命令扫描 以及与跨服调用相关的 CrossRpcInvoker 接口。
本模块 不是 可执行 Spring Boot 应用;随区服或跨服进程一起加载。
网络分层(逻辑)
flowchart TB
subgraph TCP["TCP 字节流"]
F["一帧: 4B length + body"]
end
subgraph Net["BaseModule / net & frame"]
D["LengthPrefixedProtobuf 解码"]
H["CmdRpcTcpFrameHandler"]
end
subgraph Cmd["BaseModule / cmd"]
CD["CmdRpcChannelDispatch"]
PR["ProtoRegistry → ProtoInfo"]
PC["ProtoCommandReflect 解析 CTS / newBuilder STC"]
DP["CmdRpcDispatch → GameCommand"]
end
F --> D --> H --> CD
CD --> PR
CD --> PC
CD --> DP
1. 帧格式:LengthPrefixedProtobuf
- 编码:
LengthPrefixedProtobuf.encodeMessage(alloc, CmdRpcEnvelope)— 先写 大端 int32 长度,再写CmdRpcEnvelope.toByteArray()。 - 解码:
newTcpFrameDecoder()返回 Netty 解码器,攒满一帧后向 pipeline 下游抛出 一条 ByteBuf(仅 body)。
这样 区服客户端 TCP 与 跨服 TCP 与 区服连跨服的 Outbound 三者 帧格式一致,仅 IP/端口与 CommandSource 不同。
2. 入站处理:CmdRpcTcpFrameHandler
- 读取一帧
byte[],调用CmdRpcChannelDispatch.dispatch(...)。 - 将返回的
CmdRpcEnvelope再次 长度前缀编码 写回对端。 linkSource由构造时注入:Client_TCP(区服接客户端)或CROSS_TCP(跨服接入站)。
注意:默认在 Netty IO 线程 上执行命令;若 roundTrip 同步调跨服会阻塞该连接上的 IO,Demo 场景可接受,生产需评估线程模型。
3. 分发核心:CmdRpcChannelDispatch
步骤简述:
CmdRpcEnvelope.parseFrom(raw)。protoRegistry.resolve(linkSource, serviceId, methodId)→ 可选的ProtoInfo。- 若存在
ProtoInfo:解析 payload 为 CTS、创建 STC 的Builder(网络层职责,命令内只填字段)。 - 构造
CommandContext(含ChannelHandlerContext、CrossRpcInvoker、解码结果等)。 CmdRpcDispatch.dispatchEnvelope(in, lookup, cctx)→ 执行具体GameCommand。
flowchart LR
IN[CmdRpcEnvelope in]
PI{ProtoInfo 存在?}
DEC[解码 CTS + STC Builder]
RAW[decoded=null 由命令自处理]
EXE[GameCommand.execute]
OUT[CmdRpcEnvelope out]
IN --> PI
PI -->|是| DEC --> EXE
PI -->|否| RAW --> EXE
EXE --> OUT
4. 命令模型
| 类型 | 说明 |
|---|---|
GameCommand |
execute(CommandContext, CmdRpcEnvelope),完全自控 payload。 |
AbstractTypedPbCommand<C, B> |
依赖 ProtoInfo;run(ctx, cts, stcBuilder);回包信封 复制 service/method/cross_ret/link_seq。 |
CommandSource 与注册
@Cmd(source, serviceId, methodId)标注在命令类上。SpringGameCommandRegistry:按 Spring 容器里GameCommandBean 扫描,只收录source属于当前进程配置集合的命令(区服只收Client_TCP,跨服只收CROSS_TCP)。
5. ProtoRegistry 与自动注册
ProtoRegistry:register(ProtoInfo)/resolve(source, serviceId, methodId)。ProtoRegistryAutoConfigurer(SmartInitializingSingleton):扫描带@Cmd的GameCommand,若继承AbstractTypedPbCommand,则从泛型推断 CTS / STC 类型 并注册ProtoInfo。- 未 继承强类型基类的命令(如路径 3 中继)不注册
ProtoInfo,由命令自行处理 payload。
6. CrossRpcInvoker
- 接口方法:
CmdRpcEnvelope roundTrip(CmdRpcEnvelope request)。 - ServerModule 中由
CrossTcpClient实现:维护至跨服的 长连接、link_seq多路复用、注册与心跳。
区服业务命令(路径 2/3)通过 CommandContext.crossRpc() 拿到该实例,向跨服发 CrossForward* 对应的信封。
7. 依赖说明
- Spring Context(
@Component等)、Netty、protobuf-java、slf4j-api、Lombok(可选)。 - 生成的 proto Java 类来自 ProtoBufModule。
包结构(主要)
com.huangzj.base
├── cmd # 分发、上下文、注册表、Proto 反射、CrossRpcInvoker
├── frame # 长度前缀、Buf 工具
├── net # CmdRpcTcpFrameHandler
└── spring # SpringGameCommandRegistry、其它 Spring 辅助