# CrossModule

**跨服独立进程**：仅启动 **一个 CmdRpc TCP 服务**（默认 **9200**），处理来源为 **`CommandSource.CROSS_TCP`** 的命令。  
区服通过 **`CrossTcpClient`**（在 ServerModule）作为 **TCP 客户端** 连到本进程。

## 进程职责

| 职责 | 说明 |
|------|------|
| 监听 TCP | `CrossTcpServer` 在 `ApplicationReadyEvent` 后 `bind(cross.tcp.port)` |
| Pipeline | `CrossTcpChannelInitializer`：`LengthPrefixedProtobuf` 解码 + `CmdRpcTcpFrameHandler` |
| 命令路由 | `CrossGameCommandRegistry` 只注册 `@Cmd(source=CROSS_TCP)` 的 Bean |
| 链路安全（可选） | `CrossLinkAcceptProperties`：`cross.link.expected-token` 非空时校验注册 token |

## 网络拓扑

```mermaid
flowchart LR
  subgraph Zone["ServerModule"]
    CC[CrossTcpClient]
  end
  subgraph Cross["CrossModule :9200"]
    XT[CrossTcpServer]
    PL[pipeline]
    REG[CrossGameCommandRegistry]
  end
  CC <-->|单 TCP 长连接 长度前缀+CmdRpcEnvelope| XT
  XT --> PL --> REG
```

## 入站 Pipeline（与 BaseModule 一致）

```text
Socket
  → LengthFieldBasedFrameDecoder（由 LengthPrefixedProtobuf 配置）
  → CmdRpcTcpFrameHandler
        → CmdRpcChannelDispatch（linkSource = CROSS_TCP）
        → GameCommand.execute
  → 编码响应帧写回
```

跨服侧 **`CrossRpcInvoker` 传 `null`**：跨服命令里 **不应** 再同步 `roundTrip` 回调区服（Demo 未实现跨服主动调区服）。

## 已实现的 `CROSS_TCP` 命令

### 业务：Service_2 / Method2

- **`CrossForwardCommand`**（`AbstractTypedPbCommand`）  
  - 入参：`CrossForwardCts`  
  - 出参：`CrossForwardStc`  
  - Demo 逻辑：给 `trace` 加前缀并写入 `cross_time_ms`。

### 链路：Service_4（注册 / 心跳）

| method | 命令类 | 作用 |
|--------|--------|------|
| Register | `CrossLinkRegisterCommand` | 校验 `server_id`、可选 `expected-token` |
| Heartbeat | `CrossLinkHeartbeatCommand` | 回显 `client_time_ms`，写入 `cross_time_ms` |

```mermaid
sequenceDiagram
  participant Z as 区服 CrossTcpClient
  participant X as CrossModule
  Z->>X: Service_4 Register + link_seq + CrossLinkRegisterCts
  X-->>Z: 同 link_seq + CrossLinkRegisterStc(ok/message)
  loop 每 heartbeat-interval-ms
    Z->>X: Service_4 Heartbeat + link_seq
    X-->>Z: CrossLinkHeartbeatStc
  end
  Z->>X: Service_2 Method2 + link_seq + CrossForwardCts
  X-->>Z: CrossForwardStc
```

## 配置（`src/main/resources/application.yml`）

```yaml
cross:
  tcp:
    port: 9200          # Netty 监听端口
  link:
    expected-token: ""  # 非空则须与区服 cross.token 一致
app:
  logging:
    dir: logs/CrossModule
```

## 启动

主类：`com.huangzj.cross.CrossModuleApplication`  

建议 **先于区服** 启动，否则区服 `CrossTcpClient` 预热与心跳会失败（日志告警），待跨服起来后下次业务或心跳会重连。

## 日志

`logback-spring.xml`：控制台 + 按级别分文件（`info.log` / `error.log`），目录由 `app.logging.dir` 指定。

## 扩展跨服 RPC

1. 在 **ProtoBufModule** 增加 `service/method` 与消息体。  
2. 在本模块新增 `@Cmd(source=CROSS_TCP, ...)` 的 `GameCommand` 或 `AbstractTypedPbCommand`。  
3. 若需强类型自动解码，使用 **`AbstractTypedPbCommand`**；启动时 **`ProtoRegistryAutoConfigurer`** 会为跨服进程注册对应 `ProtoInfo`。
