# BaseModule **公共运行时库**:被 `ServerModule` 与 `CrossModule` 依赖。包含 **Netty TCP 帧编解码**、**CmdRpc 分发管线**、**Proto 元数据注册表**、**Spring 命令扫描** 以及与跨服调用相关的 **`CrossRpcInvoker` 接口**。 本模块 **不是** 可执行 Spring Boot 应用;随区服或跨服进程一起加载。 ## 网络分层(逻辑) ```mermaid 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` 步骤简述: 1. `CmdRpcEnvelope.parseFrom(raw)`。 2. `protoRegistry.resolve(linkSource, serviceId, methodId)` → 可选的 **`ProtoInfo`**。 3. 若存在 `ProtoInfo`:**解析 payload 为 CTS**、**创建 STC 的 `Builder`**(网络层职责,命令内只填字段)。 4. 构造 **`CommandContext`**(含 `ChannelHandlerContext`、`CrossRpcInvoker`、解码结果等)。 5. **`CmdRpcDispatch.dispatchEnvelope(in, lookup, cctx)`** → 执行具体 **`GameCommand`**。 ```mermaid 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` | 依赖 `ProtoInfo`;`run(ctx, cts, stcBuilder)`;回包信封 **复制** `service/method/cross_ret/link_seq`。 | ### `CommandSource` 与注册 - `@Cmd(source, serviceId, methodId)` 标注在命令类上。 - **`SpringGameCommandRegistry`**:按 Spring 容器里 `GameCommand` Bean 扫描,**只收录** `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**。 ## 包结构(主要) ```text com.huangzj.base ├── cmd # 分发、上下文、注册表、Proto 反射、CrossRpcInvoker ├── frame # 长度前缀、Buf 工具 ├── net # CmdRpcTcpFrameHandler └── spring # SpringGameCommandRegistry、其它 Spring 辅助 ```