# 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<C, B>` | 依赖 `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 辅助
```
