Discord-MC-Chat/README.md
2025-11-17 01:13:12 +08:00

184 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Discord-MC-Chat (DMCC) 重构设计文档
## 1. 项目概述
Discord-MC-Chat (DMCC) 是一个 Minecraft 模组,旨在为 Discord 和 Minecraft 服务器之间建立一个功能强大、可高度定制的双向通信桥梁。
本次重构的核心目标是实现一个**统一的、基于“服务端-客户端 (Server-Client)”的通信架构**
。在此架构下,所有运行模式都将复用同一套核心逻辑,以达到最大程度的代码复用、架构一致性和未来的可扩展性。
项目初期将优先实现对 **NeoForge 1.21.10** 的兼容。但为了未来能够无缝支持 Fabric整体架构设计严格遵循平台无关原则所有核心代码中
**不得含有任何启动器专属的调用**,仅通过 Mixin 进行注入。
## 2. 核心功能需求
### 2.1 通信功能
- **双向消息转发**: 在 Discord 和 Minecraft 之间实时转发聊天消息。
- **格式兼容**: 支持 Markdown、Discord 表情符号、提及和超链接在两个平台间的自动转换。
- **Webhook 支持**: 可选通过 Webhook 以玩家头像发送 Minecraft 消息到 Discord。
- **自定义格式**: 允许用户高度自定义所有消息的显示格式。
### 2.2 事件通知
- **玩家事件**: 玩家加入/离开服务器、死亡、获得进度/成就。
- **服务器事件**: 服务器启动/关闭。
- **性能监控**: 当服务器 MSPT (每 tick 毫秒数) 超过阈值时,在 Discord 发出警告。
### 2.3 管理功能
- 通过 Discord 和游戏内命令查询服务器状态。
- 通过 Discord 和游戏内命令执行 Minecraft 控制台命令。
- 查看和过滤服务器日志。
- 重载 DMCC 配置文件。
- 远程启动/关闭/重启子服务器(仅限多服务器模式)。
### 2.4 账户链接功能
- **身份绑定**: 支持将 Minecraft 玩家账户与 Discord 账户进行一对一关联。
- **角色颜色同步**: 游戏内聊天消息显示与玩家 Discord 角色的颜色一致。
- **跨平台提及**: 在 Discord 中`@`用户时,对应的 Minecraft 玩家会收到游戏内提醒。
- **权限同步**: 可选基于 Discord 角色自动授予玩家游戏内的 OP 权限。
## 3. 系统架构
### 3.1 统一的“服务端-客户端 (Server-Client)”架构
DMCC 所有运行模式都基于一个统一的通信模型,该模型包含两个核心组件:
1. **服务端 (Server)**: 整个系统的“大脑”。它作为后台服务运行,是**唯一**负责与 Discord API (通过 JDA)
直接通信的组件。它处理所有核心逻辑,如消息格式化、命令解析和权限验证。**此组件在任何情况下都不得包含任何 `net.minecraft`
的导入(反射除外)**,以确保其可以在没有 Minecraft 环境的情况下独立运行。
2. **客户端 (Client)**: 部署在每个 Minecraft 服务器上的“触手”。它作为 Minecraft 模组运行,负责捕获游戏内的所有事件,将其发送给
**服务端 (Server)**。并执行来自 **服务端 (Server)** 的指令和本地命令。
两者之间通过基于 **Netty** 的 TCP 协议进行通信,使用 **JSON** 对数据包进行序列化和反序列化,并采用**哈希质询-响应机制**
进行安全认证。
### 3.2 运行模式与部署
1. **单体服务器模式 (`single_server`)**: 在后台**同时启动一个内部服务端和一个内部客户端**。内部客户端自动通过本地回环地址连接到内部服务端。这是为单个
Minecraft 服务器提供的开箱即用的解决方案。
2. **多服务器-客户端模式 (`multi_server_client`)**: **只启动一个客户端**,此客户端会连接到一个外部独立运行的服务端。用于将多个
Minecraft 服务器连接到一个中央服务端。
3. **独立模式 (`standalone`)**: **只启动一个服务端**,监听网络端口,等待一个或多个外部客户端连接。作为多服务器架构的中央“大脑”而存在。
### 3.3 配置文件策略
1. **`mode.yml`**: 用户首先在此文件选择一种运行模式。若在非 Minecraft 环境下直接运行 JAR则自动认定为 `standalone` 模式。
2. **`config.yml`**: DMCC 会根据选择的模式,从内部模板生成一份对应的 `config.yml`。此配置文件将被严格验证。`standalone`
模式首次启动时,会自动在 `config.yml` 中生成一个高强度的 `shared_secret`,用户需将其手动同步到所有 `client` 的配置文件中。
## 4. 网络协议与安全
### 4.1 哈希质询-响应认证机制
为保证通信安全,防止共享密钥在传输中被窃取及防止重放攻击,系统采用一次性的哈希质询-响应机制进行认证。
**核心协议包 (`Packets.java`):**
```java
// 客户端发起连接,表明身份和版本
public record ClientHello(String serverName, String version) implements Packet {
}
// 服务端收到ClientHello后发送随机质询
public record ServerChallenge(String challenge) implements Packet {
}
// 客户端收到质询后,计算并发送响应
public record ClientResponse(String responseHash) implements Packet {
}
// 服务端验证通过后,发送最终的成功响应
public record HandshakeSuccess(String messageKey, String language) implements Packet {
}
// 任何阶段失败,都可以发送一个失败响应
public record HandshakeFailure(String messageKey) implements Packet {
}
```
**认证流程:**
1. **客户端发起连接**: `Client` 连接成功后,立即发送 `ClientHello` 包,包含其在 `config.yml` 中配置的 `serverName` 和自身的
DMCC 版本号。
2. **服务端版本验证与质询**: `Server` 收到 `ClientHello` 后:
a. **版本检查**: 对比 `Client` 版本和自身版本。如果不兼容,立即返回
`HandshakeFailure("handshake.error.invalid_version")` 并断开连接。
b. **生成质询**: 如果版本兼容,`Server` 生成一个唯一的、一次性的随机字符串作为 `challenge`,并暂存于内存中。
c. **发送质询**: `Server``Client` 发送 `ServerChallenge` 包。
3. **客户端计算响应**: `Client` 收到 `ServerChallenge` 后:
a. 从 `config.yml` 读取 `shared_secret`
b. 使用 **HMAC-SHA256** 算法计算哈希值: `responseHash = hmac_sha256(key = shared_secret, data = challenge)`
c. 向 `Server` 发送 `ClientResponse` 包。
4. **服务端验证响应**: `Server` 收到 `ClientResponse` 后:
a. 取出内存中为该 `Client` 暂存的 `challenge`
b. 以完全相同的方式计算出 `expectedResponseHash`
c. **比对哈希**: 如果不一致,返回 `HandshakeFailure("handshake.error.authentication_failed")` 并断开连接。
5. **握手成功**: 如果哈希一致,认证通过。`Server` 发送 `HandshakeSuccess` 包,其中包含配置的全局 `language`
### 4.2 全局语言同步
为确保所有实例的输出信息语言统一,系统采用握手时同步的策略:
1. `Client` 启动时,默认加载 `en_us` 语言文件。
2.`Client` 收到 `Server` 发来的 `HandshakeSuccess` 包后,它会解析出 `language` 字段(如 `zh_cn`)。
3. 如果该语言与当前加载的语言不同,`Client` 会调用 `I18nManager.load("zh_cn")` 重新加载对应的语言文件。
4. 从此,该 `Client` 生成的所有消息都将使用与 `Server` 统一的语言。
## 5. 命令系统设计
### 5.1 统一命令入口与异步处理
- **`CommandSource` 抽象接口**: 所有命令处理逻辑都将面向一个 `CommandSource`
接口该接口封装了命令来源的特有信息如来源名称、权限检查、响应方法使其与具体实现玩家、控制台、Discord用户解耦。
- **异步执行**: 所有可能耗时的命令(如 `reload`, `start`, `stats`)都将异步执行,并返回一个
`CompletableFuture<CommandResult>`,避免阻塞主线程。
### 5.2 命令可用性矩阵
| 命令 | 权限 (默认) | `multi_server_client` | `standalone` (终端) | `single_server` | Discord | 说明与行为差异 |
|:----------|:-----------|:----------------------|:------------------|:----------------|:--------|:-----------------------------------------------------------------------------------------------------------|
| `help` | `everyone` | ✅ | ✅ | ✅ | ✅ | 动态显示当前环境可用且有权执行的命令。 |
| `info` | `everyone` | ✅ | ✅ | ✅ | ✅ | **行为**: `client` 只显示自身状态。`server` 端显示全局信息,包括所有 `client` 的摘要。 |
| `update` | `everyone` | ✅ | ✅ | ✅ | ✅ | **本地执行**: 每个实例独立检查自身DMCC的版本更新。此命令**不**进行跨实例转发。 |
| `stats` | `everyone` | ✅ | ✅ | ✅ | ✅ | **服务端聚合**: `client` 收到命令后,将**命令请求**转发给 `server``server` 再向所有 `client` **实时请求**统计数据,聚合后将结果返回给最初的 `client`。 |
| `console` | `admin` | ✅ | ❌ | ✅ | ✅ | 执行**所在MC服务器**的命令。`standalone` 无此命令。在Discord执行时`standalone` 模式相当于 `execute`。 |
| `execute` | `admin` | ✅ | ✅ | ❌ | ✅ | **`multi-server` 核心**: 用于远程执行命令。`single_server` 无此命令。`client` 端执行此命令时,会将请求转发给 `server` 处理。 |
| `log` | `admin` | ✅ | ✅ | ✅ | ✅ | `client` 可获取自身日志,`server` 可获取自身日志。可通过 `execute` 获取远程日志。 |
| `restart` | `admin` | ✅ | ✅ | ✅ | ✅ | **应用内重启**: 通过 `shutdown()` + `init()` 实现无需重启JVM。`standalone` 模式下Bot会短暂离线后重连。 |
| `start` | `admin` | ❌ | ✅ | ❌ | ✅ | **`standalone` 独有**: 启动 `config.yml` 中定义的子服务器进程。 |
| `stop` | `admin` | ✅ | ✅ | ✅ | ✅ | 停止**当前DMCC实例**。高危操作,建议增加二次确认。 |
### 5.3 关键命令逻辑详解
#### `stats` (纯实时查询模型)
1. **转发请求**: `client` 收到命令后,封装 `ForwardedCommandPacket` 发送给 `server`
2. **广播数据请求**: `server` 收到请求后,**立即**向所有 `client` 广播 `StatsRequestPacket`
3. **响应数据**: 各 `client` 查询本地统计数据,并回传 `StatsDataPacket`
4. **聚合与返回**: `server` 在短暂超时时间内聚合所有响应,生成排行榜,并通过 `CommandResponsePacket` 定向返回给最初请求的
`client`
#### `update` (本地独立检查模型)
- 此命令**始终在接收到命令的实例上本地执行**。
- 逻辑(获取自身版本、请求 GitHub API、比较版本位于 `:common` 模块,`client``server` 均可调用。
- 返回的更新信息将明确指出这是一个**手动操作**,需要管理员在所有实例(`standalone` 和所有 `client`)上手动替换 `.jar` 文件。
#### `start` (事件驱动反馈模型)
1. 管理员在 `standalone` 或 Discord 执行 `/start SMP`
2. `standalone` 回复临时消息(“正在启动...”)并执行预设的 `start_command`
3. 子服务器的 DMCC `client` 启动并自动连接 `standalone`
4. `standalone` 将“新客户端注册成功”的内部事件作为该服务器成功启动的信号。
5. `standalone` 更新之前的临时消息为最终的成功状态(“服务器 SMP 已成功启动并连接!”)。
## 6. 权限管理模型 (双轨制)
1. **原生继承模型 (Minecraft -> DMCC)**: 游戏内 OP 等级高于 `minecraft_op_level_requirement` 的玩家自动成为“DMCC
管理员”。这是权限的基础来源。
2. **角色同步模型 (Discord -> Minecraft)**: 可选功能。可配置 Discord 角色到游戏内 OP 等级的映射。`Server` 组件会周期性检查并
**通过向 `Client` 发送指令**来自动授予/撤销玩家的游戏内 OP 权限。一旦玩家因此获得足够 OP 等级也将通过路径一成为“DMCC
管理员”。