diff --git a/README.md b/README.md index 677663c4..ad5b7f22 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Discord-MC-Chat (DMCC) 是一个 Minecraft 模组,旨在为 Discord 和 Minecraft 服务器之间建立一个功能强大、可高度定制的双向通信桥梁。 -本次重构的核心目标是实现一个**统一的、基于“服务端-客户端 (Server-Client)”的通信架构** +本次重构的核心目标是实现一个**统一的、基于"服务端-客户端 (Server-Client)"的通信架构** 。在此架构下,所有运行模式都将复用同一套核心逻辑,以达到最大程度的代码复用、架构一致性和未来的可扩展性。 项目初期将优先实现对 **NeoForge 1.21.10** 的兼容。但为了未来能够无缝支持 Fabric,整体架构设计严格遵循平台无关原则,所有核心代码中 @@ -43,14 +43,14 @@ Discord-MC-Chat (DMCC) 是一个 Minecraft 模组,旨在为 Discord 和 Minecr ## 3. 系统架构 -### 3.1 统一的“服务端-客户端 (Server-Client)”架构 +### 3.1 统一的"服务端-客户端 (Server-Client)"架构 DMCC 所有运行模式都基于一个统一的通信模型,该模型包含两个核心组件: -1. **服务端 (Server)**: 整个系统的“大脑”。它作为后台服务运行,是**唯一**负责与 Discord API (通过 JDA) +1. **服务端 (Server)**: 整个系统的"大脑"。它作为后台服务运行,是**唯一**负责与 Discord API (通过 JDA) 直接通信的组件。它处理所有核心逻辑,如消息格式化、命令解析和权限验证。**此组件在任何情况下都不得包含任何 `net.minecraft` 的导入(反射除外)**,以确保其可以在没有 Minecraft 环境(Standalone 模式)的情况下独立运行。 -2. **客户端 (Client)**: 部署在每个 Minecraft 服务器上的“触手”。它作为 Minecraft 模组运行,负责捕获游戏内的所有事件,将其发送给 +2. **客户端 (Client)**: 部署在每个 Minecraft 服务器上的"触手"。它作为 Minecraft 模组运行,负责捕获游戏内的所有事件,将其发送给 **服务端 (Server)**。并执行来自 **服务端 (Server)** 的指令和本地命令。 两者之间通过基于 **Netty** 的 TCP 协议进行通信。 @@ -61,7 +61,7 @@ DMCC 所有运行模式都基于一个统一的通信模型,该模型包含两 Minecraft 服务器提供的开箱即用的解决方案。 2. **多服务器-客户端模式 (`multi_server_client`)**: **只启动一个客户端**,此客户端会连接到一个外部独立运行的服务端。用于将多个 Minecraft 服务器连接到一个中央服务端。 -3. **独立模式 (`standalone`)**: **只启动一个服务端**,监听网络端口,等待一个或多个外部客户端连接。作为多服务器架构的中央“大脑”而存在。 +3. **独立模式 (`standalone`)**: **只启动一个服务端**,监听网络端口,等待一个或多个外部客户端连接。作为多服务器架构的中央"大脑"而存在。 ### 3.3 配置文件策略 @@ -75,50 +75,70 @@ DMCC 所有运行模式都基于一个统一的通信模型,该模型包含两 **认证流程:** -1. **客户端发起连接**: `Client` 连接成功后,发送包,包含其在 `config.yml` 中配置的 `serverName` 和自身的 - DMCC 版本号。 -2. **服务端验证与质询**: `Server` 收到包后: - a. **白名单检查**: `Server` 检查 `serverName` 是否在 `config.yml` 的 `multi_server.servers` 列表中。如果不在,返回错误及原因,并断开连接。 - b. **版本检查**: 对比 `Client` 版本和自身版本。如果不兼容,返回错误及原因,并断开连接。 - c. **生成质询**: 如果通过,`Server` 生成一个唯一的、一次性的随机字符串作为 `challenge`,并暂存于内存中。 - d. **发送质询**: `Server` 向 `Client` 发送包,包含该随机字符串。 -3. **客户端计算响应**: `Client` 收到包后: +1. **客户端发起连接**: `Client` 连接成功后,发送 `HandshakePacket`,包含其在 `config.yml` 中配置的 `serverName`、自身的 + DMCC 版本号和 Minecraft 版本号。 +2. **服务端验证与质询**: `Server` 收到 `HandshakePacket` 后: + a. **模式检查**: 若 `Server` 处于 `single_server` 模式,且 `serverName` 不为 `Internal`,则返回 `DisconnectPacket`(包含原因)并断开连接。 + b. **白名单检查**: 若 `Server` 处于 `standalone` 模式,检查 `serverName` 是否在 `config.yml` 的 `multi_server.servers` 列表中。如果不在,返回 `DisconnectPacket`(包含原因)并断开连接。 + c. **版本检查**: 对比 `Client` 的 DMCC 版本和 Minecraft 版本与 `Server` 端的期望值。如果不兼容,返回 `DisconnectPacket`(包含原因)并断开连接。 + d. **生成质询**: 如果通过,`Server` 生成一个唯一的、一次性的随机字符串作为 `nonce`,并暂存于内存中。 + e. **发送质询**: `Server` 向 `Client` 发送 `ChallengePacket`,包含该随机 `salt`。 +3. **客户端计算响应**: `Client` 收到 `ChallengePacket` 后: a. 从 `config.yml` 读取 `shared_secret`。 - b. 使用某合适的单向算法计算哈希值。 - c. 向 `Server` 发送包,包含该哈希值。 -4. **服务端验证响应**: `Server` 收到包后: - a. 取出内存中为该 `Client` 暂存的 `challenge`。 - b. 以同一个单向算法计算出哈希值。 - c. **比对哈希**: 如果不一致,返回错误及原因,并断开连接。 -5. **握手成功**: 如果哈希一致,认证通过。`Server` 发送包,其中包含服务端所配置的 `language`,作为全局同步的语言,客户端收到后会重载语言。 + b. 使用 SHA-256 计算哈希值:`SHA-256(salt + shared_secret)`。 + c. 向 `Server` 发送 `AuthResponsePacket`,包含该哈希值。 +4. **服务端验证响应**: `Server` 收到 `AuthResponsePacket` 后: + a. 取出内存中为该 `Client` 暂存的 `nonce`。 + b. 以同样的方式计算 `SHA-256(nonce + shared_secret)`。 + c. **比对哈希**: 如果不一致,返回 `DisconnectPacket`(包含原因)并断开连接。 +5. **握手成功**: 如果哈希一致,认证通过。`Server` 发送 `LoginSuccessPacket`,其中包含服务端所配置的 `language`,作为全局同步的语言,客户端收到后会重载语言。 ## 5. 命令系统设计 -| 命令 | 权限 (默认) | 模组运行 `multi_server_client` | 模组运行 `single_server` | 独立运行 `standalone` | 说明与行为差异 | -|:----------------------------------|:-----------|:---------------------------|:---------------------|:------------------|:-----------------------------------------------------------------------------------| -| `help` | `everyone` | ✅ | ✅ | ✅ | 动态显示当前环境可用且有权执行的命令。 | -| `info` | `everyone` | ✅ | ✅ | ✅ | 在 `client` 执行只显示自身状态。在 `server` 端执行则显示全局信息。 | -| `update` | `everyone` | ✅ | ✅ | ✅ | 在本地执行,检查自身 DMCC 实例的更新。每个实例独立检查自身版本。只是检查更新,不是自动更新。 | -| `stats ` | `everyone` | ✅ | ✅ | ✅ | 在 `client` 执行只统计自身 MC 服务器。在 `server` 端执行则统计全部 MC 服务器。获取的是 `/world/stats/` 文件夹中的数据。 | -| `console ` | `admin` | ✅ | ✅ | ❌ | 在所在的 MC 服务器中执行 MC 命令。 | -| `execute ` | `admin` | ❌ | ❌ | ✅ | 仅 `standalone`(Server)存在。用于将命令转发给目标 Client。`at=all` 不包含自身(standalone)。 | -| `link ` | `everyone` | ❌ | ✅ | ✅ | 管理该 Discord 账户的账户链接(仅 `add` 需要验证),只能在 `server` 执行。 | -| `link confirm` | `everyone` | ✅ | ✅ | ❌ | 验证先前提交的账户链接请求,只能在游戏内 `client` 执行,然后通知 `server`。 | -| `link list ` | `admin` | ❌ | ✅ | ✅ | 列出某 Discord 账户的账户链接,只能在 `server` 执行。`single_server` 环境时可在游戏内执行。`all` 仅供管理员使用。 | -| `log ` | `admin` | ✅ (MC log) | ✅ (MC log) | ✅ (DMCC log) | 获取自身实例的日志文件。可通过 `execute` 命令获得 `client` 的日志。 | -| `reload` | `admin` | ✅ | ✅ | ✅ | 通过 `shutdown()` + `init()` 实现。 | -| `start ` | `admin` | ❌ | ❌ | ✅ | 启动 `config.yml` 中定义的子 MC 服务器。 | -| `stop ` | `admin` | ❌ | ❌ | ✅ | 停止 `config.yml` 中定义的子 MC 服务器。 | -| `shutdown` | `admin` | ❌ | ❌ | ✅ | 关闭 `standalone` 应用程序。 | +### 5.1 权限模型 -`execute ` 命令仅存在于 `standalone`(服务端)环境。`at=all` 不包含自身(standalone)。`server_name` 不允许为 `all` 或 `standalone`,或重名等问题必须在配置校验阶段处理。 +DMCC 采用**基于数值 OP 等级的细粒度权限模型**。每个命令在 `config.yml` 中都有一个独立的 `command_permission_levels` 配置项,映射到 Minecraft 原生的 OP 等级 (0-4)。 -`log ` 命令为 Discord 独占命令。其结果为文件附件。`` 为必填参数,支持 `.log` 与 `.log.gz`。需要自动补全可用日志文件名。 +对于 Minecraft 游戏内命令(通过 `/dmcc` 执行),使用 Brigadier 的 `.requires(source -> source.hasPermission(level))` 进行原生权限检查。 -## 6. 权限管理模型 (双轨制) +对于 Discord 斜杠命令,权限通过已绑定的 Minecraft 账户的 OP 等级来判定。 -1. **原生继承模型 (Minecraft -> DMCC)**: 游戏内 OP 等级高于 `minecraft_op_level_requirement` 的玩家,自动成为“DMCC - 管理员”。这是权限的基础来源。 -2. **角色同步模型 (Discord -> Minecraft -> DMCC)**: 可选功能。可配置 Discord 角色到游戏内 OP 等级的映射。`Server` 组件会周期性检查并 - **通过向 `Client` 发送指令**来自动授予/撤销玩家的游戏内 OP 权限。一旦玩家因此获得足够 OP 等级,也将通过路径一成为“DMCC - 管理员”。 +**OP 等级参考:** +- Level 0 (normal): 无特殊权限。 +- Level 1 (moderator): 可以绕过出生点保护。 +- Level 2 (gamemaster): 可以使用更多命令和命令方块。 +- Level 3 (admin): 可以使用多人游戏管理相关的命令。 +- Level 4 (owner): 可以使用所有命令,包括服务器管理相关的命令。 + +可选的**角色同步**功能可根据 Discord 角色自动授予/撤销玩家的游戏内 OP 权限,间接赋予其对应的 DMCC 命令权限。 + +### 5.2 命令列表 + +| 命令 | 默认 OP 等级 | 模组运行 `multi_server_client` | 模组运行 `single_server` | 独立运行 `standalone` | 说明与行为差异 | +|:------------------------------|:---------|:---------------------------|:---------------------|:------------------|:---------------------------------------------------------------------------------------------------| +| `help` | `0` | ✅ | ✅ | ✅ | 动态显示当前环境可用且有权执行的命令。可用命令根据用户的权限等级动态显示。 | +| `info` | `0` | ✅ | ✅ | ✅ | 在 `client` 执行只显示自身状态。在 `server` 端执行则显示全局信息(包含所有在线客户端和 Discord 连接状态)。 | +| `reload` | `4` | ✅ | ✅ | ✅ | 通过 `shutdown()` + `init()` 实现。 | +| `log ` | `4` | ✅ | ✅ | ✅ | 获取自身实例的日志文件。Discord 独占命令(结果为文件附件)。支持 `.log` 与 `.log.gz`,自动补全可用文件名。可通过 `execute` 命令获得 `client` 的日志。 | +| `execute ` | `4` | ❌ | ❌ | ✅ | 仅 `standalone`(Server)存在。`at` 可为具体服务器名称或 `all_online_clients`(向所有在线客户端广播,不包含自身 standalone)。 | +| `start ` | `4` | ❌ | ❌ | ✅ | 启动 `config.yml` 中定义的子 MC 服务器(执行其 `start_command`)。`start_command` 支持系统命令或 URL。 | +| `stop ` | `4` | ❌ | ❌ | ✅ | 向目标 DMCC 客户端发送 `ServerStopRequestPacket`,客户端收到后执行 Minecraft `/stop` 命令。目标客户端必须在线。 | +| `shutdown` | `4` | ❌ | ❌ | ✅ | 关闭 `standalone` 应用程序。 | + +**备注:** +- `log ` 在 `LocalCommandSender`(终端和游戏内)的帮助列表中不显示,但仍可通过 `execute` 远程获取客户端日志。 +- `execute` 命令的 `command` 参数在终端解析时,`` 之后的所有内容视为单一参数。 + +### 5.3 Discord 斜杠命令自动补全 + +所有接受参数的 Discord 斜杠命令均支持自动补全: +- `execute `: 建议 `all_online_clients` 和所有在线客户端名称。 +- `execute `: 向所有在线客户端发送 `CommandAutoCompleteRequestPacket` 实时收集建议。 +- `log `: 列出可用日志文件。 +- `start ` / `stop `: 列出 `config.yml` 中配置的所有服务器名称。 + +## 6. 权限管理模型 + +1. **原生数值模型 (config → Minecraft/DMCC)**: 每个 DMCC 命令在 `command_permission_levels` 中配置一个 0-4 的 OP 等级数值。游戏内通过 Brigadier 原生权限检查,Discord 端通过绑定账户的 OP 等级判定。 +2. **角色同步模型 (Discord → Minecraft)**: 可选功能。可配置 Discord 角色到游戏内 OP 等级的映射。`Server` 组件会周期性检查并 + **通过向 `Client` 发送指令**来自动授予/撤销玩家的游戏内 OP 权限。