From 2414fb342813e9df5eca975d321f8d5200552f4d Mon Sep 17 00:00:00 2001 From: Ziphyrien <2697860027@qq.com> Date: Sun, 14 Dec 2025 22:32:41 +0800 Subject: [PATCH 1/3] =?UTF-8?q?refactor:=20=E5=88=9B=E5=BB=BA=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E6=A0=91=E7=BB=84=E4=BB=B6=EF=BC=8C=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 以下文件中的文件树已更新为新组件: - first.md - configuration.md - fix.md - client-distribution.md - what-is-datapack.md - server-dir-structure.md (purpur) - server-dir-structure.md (bds) - server-file-structure.md - levilamina-plugins.md --- .../process/levilamina/levilamina-plugins.md | 14 +- .../bds/start/basic/server-dir-structure.md | 52 +-- .../start/basic/server-file-structure.md | 47 +-- .../geyser/upgrade/extended/fix.md | 17 +- .../process/plugin/more/plugin-build/first.md | 116 ++++--- docs-java/start/basic/server-dir-structure.md | 180 +++++----- docs-java/start/basic/what-is-datapack.md | 320 +++++++++--------- .../player-management/client-distribution.md | 20 +- docs/advance/viaproxy/configuration.md | 31 +- src/components/FileTree/index.tsx | 210 ++++++++++++ src/components/FileTree/styles.module.css | 99 ++++++ 11 files changed, 712 insertions(+), 394 deletions(-) create mode 100644 src/components/FileTree/index.tsx create mode 100644 src/components/FileTree/styles.module.css diff --git a/docs-bedrock/bds/process/levilamina/levilamina-plugins.md b/docs-bedrock/bds/process/levilamina/levilamina-plugins.md index 382edaeec..4425b81bb 100644 --- a/docs-bedrock/bds/process/levilamina/levilamina-plugins.md +++ b/docs-bedrock/bds/process/levilamina/levilamina-plugins.md @@ -3,6 +3,8 @@ title: 插件安装教程 sidebar_position: 1 --- +import { FileTree } from '@site/src/components/FileTree'; + # 插件安装教程 ## 插件的结构 @@ -10,12 +12,14 @@ sidebar_position: 1 LeviLamina 的插件是以文件夹的格式存在的。通常插件文件夹中包含以下内容: -```c + +{` 插件文件夹 -├─manifest.json // 插件元数据文件,该文件必须存在并格式正确才能被 LeviLamina 识别 -├─(插件配置文件和数据库)... // 插件生成的配置文件和数据库等,大多数插件的配置文件名叫 config.json,并以一个文件夹或一个 .db 或 .json 后缀文件作为数据库 -├─(插件代码或二进制文件)... // 插件源代码,通常是 .js、.lua、.dll 后缀的文件。不要删除,修改或重命名文件,否则可能导致插件无法运行! -``` + manifest.json // 插件元数据文件,该文件必须存在并格式正确才能被 LeviLamina 识别 + (插件配置文件和数据库)... // 插件生成的配置文件和数据库等,大多数插件的配置文件名叫 config.json,并以一个文件夹或一个 .db 或 .json 后缀文件作为数据库 + (插件代码或二进制文件)... // 插件源代码,通常是 .js、.lua、.dll 后缀的文件。不要删除,修改或重命名文件,否则可能导致插件无法运行! +`} + 通常情况下,你不需要手动修改 `manifest.json` 这个文件,因为插件作者会将它事先配置好。如果有特殊插件需要手动配置这个文件,该插件文档应该会给出相应教程。 diff --git a/docs-bedrock/bds/start/basic/server-dir-structure.md b/docs-bedrock/bds/start/basic/server-dir-structure.md index 6e449ae1b..96480f648 100644 --- a/docs-bedrock/bds/start/basic/server-dir-structure.md +++ b/docs-bedrock/bds/start/basic/server-dir-structure.md @@ -3,36 +3,40 @@ title: 服务端结构 sidebar_position: 1 --- +import { FileTree } from '@site/src/components/FileTree'; + # 服务端结构 我们先来简单看一眼 BDS **开服后** 的文件夹结构: -```c + +{` BDS服务端文件夹 -├─behavior_packs // 安装新行为包的文件夹 -├─config // 没啥用 -├─definitions // 貌似是生成群系的内容 -├─development_behavior_packs // 为开发者提供安装新行为包的文件夹 -├─development_resource_packs // 为开发者提供安装新资源包的文件夹 -├─development_skin_packs // 为开发者提供安装新皮肤包的文件夹 -├─resource_packs // 安装新资源包的文件夹 -├─world-templates // 世界模板 -├─worlds // 主世界文件夹 -│ └─Bedrock level // 世界存档 -│ ├─db // 存档数据文件夹 -│ ├─level_dat // 存档设定 -│ ├─level.dat_old // 存档设定 (旧) -│ └─level_name.txt // 存档名称 -├─allowlist.json // 白名单文件 -├─bedrock_server.exe // 服务端启动程序 -├─bedrock_server.pdb // 程序数据库文件 -├─bedrock_server_how_to.html // 如何使用 BDS 服务器的官方指南 (没多大用处,看看就行) -├─permissions.json // 管理员 (OP) 玩家相关数据 -├─release-notes.txt // 服务端发行版本详情 -├─server.properties // 配置文件 -└─valid_known_packs.json // 已知的附加包 -``` + behavior_packs // 安装新行为包的文件夹 + config // 没啥用 + definitions // 貌似是生成群系的内容 + development_behavior_packs // 为开发者提供安装新行为包的文件夹 + development_resource_packs // 为开发者提供安装新资源包的文件夹 + development_skin_packs // 为开发者提供安装新皮肤包的文件夹 + resource_packs // 安装新资源包的文件夹 + world-templates // 世界模板 + worlds // 主世界文件夹 + Bedrock level // 世界存档 + db // 存档数据文件夹 + level_dat // 存档设定 + level.dat_old // 存档设定 (旧) + level_name.txt // 存档名称 + allowlist.json // 白名单文件 + bedrock_server.exe // 服务端启动程序 + bedrock_server.pdb // 程序数据库文件 + bedrock_server_how_to.html // 如何使用 BDS 服务器的官方指南 (没多大用处,看看就行) + permissions.json // 管理员 (OP) 玩家相关数据 + release-notes.txt // 服务端发行版本详情 + server.properties // 配置文件 + valid_known_packs.json // 已知的附加包 +`} + -```c -Nukkit Server/ -├── nukkit-1.0-SNAPSHOT.jar //服务器核心 -├── start.bat // Windows 运行脚本 -├── start.sh // Linux 运行脚本 -├── start.command // macOS 运行脚本 -├── server.properties // 服务端配置文件 -├── permissions.yml // 用于设置玩家权限的 -├── banned-players.txt // 存储被封禁的玩家名单的 -├── banned-ips.txt // 存储被封禁的 IP 地址 -├── ops.txt // 用于设置管理员(OP)的 -├── worlds/ // 主世界文件夹 -│ ├── world/ // 世界存档 -│ │ ├── level.dat // 存档设定 -│ │ ├── region/ // 存储世界区块数据 -│ │ └── entities/ // 存储世界中的实体数据 -├── plugins/ // 插件存放文件夹 -├── logs/ // 服务器日志存放 -├── whitelist.txt // 存储允许加入服务器的玩家名单 -└── rcon_password.txt // 存储 RCON(远程控制)功能的密码 -``` + +{` +nukkit-1.0-SNAPSHOT.jar // 服务器核心 +start.bat // Windows 运行脚本 +start.sh // Linux 运行脚本 +start.command // macOS 运行脚本 +server.properties // 服务端配置文件 +permissions.yml // 用于设置玩家权限的 +banned-players.txt // 存储被封禁的玩家名单的 +banned-ips.txt // 存储被封禁的 IP 地址 +ops.txt // 用于设置管理员(OP)的 +worlds // 主世界文件夹 + world // 世界存档 + level.dat // 存档设定 + region // 存储世界区块数据 + entities // 存储世界中的实体数据 +plugins // 插件存放文件夹 +logs // 服务器日志存放 +whitelist.txt // 存储允许加入服务器的玩家名单 +rcon_password.txt // 存储 RCON(远程控制)功能的密码 +`} + + -```yaml -项目根目录 -├── src/ # 源代码目录 -│ ├── main/ # 主要代码目录 -│ │ ├── java/ # Java 源代码 -│ │ │ └── com/ -│ │ │ └── example/ -│ │ │ └── plugin/ -│ │ │ ├── Main.java # 插件主类 -│ │ │ ├── commands/ # 命令类 -│ │ │ ├── listeners/ # 监听器类 -│ │ │ └── utils/ # 工具类 -│ │ └── resources/ # 资源文件目录 -│ │ ├── plugin.yml # 插件配置文件 -│ │ ├── config.yml # 插件默认配置 -│ │ └── messages/ # 语言文件 -│ └── test/ # 测试代码目录 -│ ├── java/ # 测试源代码 -│ └── resources/ # 测试资源 -├── target/ # 构建输出目录 -├── pom.xml # Maven 项目配置文件 -└── README.md # 项目说明文件 -``` + +{` +src // 源代码目录 + main // 主要代码目录 + java // Java 源代码 + com + example + plugin + Main.java // 插件主类 + commands // 命令类 + listeners // 监听器类 + utils // 工具类 + resources // 资源文件目录 + plugin.yml // 插件配置文件 + config.yml // 插件默认配置 + messages // 语言文件 + test // 测试代码目录 + java // 测试源代码 + resources // 测试资源 +target // 构建输出目录 +pom.xml // Maven 项目配置文件 +README.md // 项目说明文件 +`} + + #### Gradle 项目结构 - -```yaml -项目根目录 -├── src/ # 源代码目录 -│ ├── main/ # 主要代码目录 -│ │ ├── java/ # Java 源代码 -│ │ │ └── com/ -│ │ │ └── example/ -│ │ │ └── plugin/ -│ │ │ ├── Main.java # 插件主类 -│ │ │ ├── commands/ # 命令类 -│ │ │ ├── listeners/ # 监听器类 -│ │ │ └── utils/ # 工具类 -│ │ ├── kotlin/ # Kotlin 源代码(如果使用) -│ │ └── resources/ # 资源文件目录 -│ │ ├── plugin.yml # 插件配置文件 -│ │ ├── config.yml # 插件默认配置 -│ │ └── messages/ # 语言文件 -│ └── test/ # 测试代码目录 -│ ├── java/ # 测试源代码 -│ ├── kotlin/ # Kotlin 测试代码 -│ └── resources/ # 测试资源 -├── build/ # 构建输出目录 -│ └── libs/ # 构建产物(jar 文件) -├── gradle/ # Gradle 包装器目录 -│ └── wrapper/ -├── build.gradle # Gradle 构建脚本 -├── settings.gradle # Gradle 设置文件 -├── gradlew # Gradle 包装器脚本 (Unix) -├── gradlew.bat # Gradle 包装器脚本 (Windows) -└── README.md # 项目说明文件 -``` + +{` +src // 源代码目录 + main // 主要代码目录 + java // Java 源代码 + com + example + plugin + Main.java // 插件主类 + commands // 命令类 + listeners // 监听器类 + utils // 工具类 + kotlin // Kotlin 源代码(如果使用) + resources // 资源文件目录 + plugin.yml // 插件配置文件 + config.yml // 插件默认配置 + messages // 语言文件 + test // 测试代码目录 + java // 测试源代码 + kotlin // Kotlin 测试代码 + resources // 测试资源 +build // 构建输出目录 + libs // 构建产物(jar 文件) +gradle // Gradle 包装器目录 + wrapper +build.gradle // Gradle 构建脚本 +settings.gradle // Gradle 设置文件 +gradlew // Gradle 包装器脚本 (Unix) +gradlew.bat // Gradle 包装器脚本 (Windows) +README.md // 项目说明文件 +`} + + ### 重要文件说明 diff --git a/docs-java/start/basic/server-dir-structure.md b/docs-java/start/basic/server-dir-structure.md index 4d568766f..bc02ff30e 100644 --- a/docs-java/start/basic/server-dir-structure.md +++ b/docs-java/start/basic/server-dir-structure.md @@ -3,43 +3,91 @@ title: 服务端结构 sidebar_position: 3 --- +import { FileTree } from '@site/src/components/FileTree'; + # 服务端结构 我们先来简单看一眼 插件端 的文件夹结构 (以 Purpur 为例): - -```c -├─assets // 储存 Minecraft 音效贴图等重要文件,不要乱动 -├─cache // 缓存文件夹,一般放置 Minecraft 原版服务器 -├─config // Paper fork 服务器特有的配置文件,用于放置 Paper 的配置文件 -├─crash-reports // 存放服务器崩溃的完整报告 -├─libraries // 存放服务器及部分插件的依赖库 -├─logs // 存放服务端日志的文件夹 -├─plugins // 存放插件的文件夹 -├─versions // 存放对应版本需要的依赖 jar -├─world // 主世界文件夹 -│ ├─advancements // 成就文件夹 -│ ├─data // 世界数据文件夹 -│ ├─datapacks // 数据包 -│ │ └─bukkit -│ ├─entities // 实体数据 -│ ├─playerdata // 玩家数据 -│ ├─poi // 兴趣点数据 -│ ├─region // 区块数据 -│ └─stats // 统计信息 -├─world_nether // 地狱世界文件夹 -│ └─DIM-1 -│ ├─data -│ ├─entities -│ ├─poi -│ └─region -└─world_the_end // 末地世界文件夹 - └─DIM1 - ├─data - ├─entities - ├─poi - └─region -``` + + 服务端的一些基本设置就在里面,如设置端口,设置游戏难度,设置游戏模式 (生存、创造等) 等。 +
+ 查看详细文档 + + ), + "whitelist.json": ( + <> + 白名单列表。(如果你在 server.properties 中开启了白名单,你就可以在该文件中添加和管理谁被允许或不被允许进入服务器。) + + ), + ".console_history": "存放了控制台 (又叫后台) 曾经使用过的指令,方便你使用键盘中的 ↑ 键快捷查找曾使用的指令,也可用于查看后台异常。", + "banned-ips.json": "以 JSON 格式存放的被 ban IP 玩家的 UUID 及游戏名称等相关信息,一旦玩家被 banip,此 IP 将无法再进入服务器。", + "banned-players.json": "以 JSON 格式存放了被 ban 玩家的 UUID 及游戏名称等相关信息,离线服 ban 玩家后换 ID 即可进入服务器,而正版服无法通过改名重新进入服务器。", + "bukkit.yml": "由 Bukkit 派生得到的服务端都有的文件。保存着 Bukkit 所提供的最基本的设置选项。", + "commands.yml": "它提供了一种快速而简单的方法来强制服务器使用 Mojang 提供的命令 (而不是 Bukkit 中内置的命令) 而不产生冲突。", + "eula.txt": "在首次开服的时候,我们需要同意 EULA 协议。", + "help.yml": "一些插件的帮助信息会出现在这里面,一般不需要进行什么修改。", + "ops.json": "以 JSON 格式存放了 OP 玩家的 UUID 及游戏名称等相关信息。", + "purpur.jar": "你可以改名叫任何名字 (只要以 .jar 结尾,且在启动脚本中对应修改)", + "purpur.yml": "Purpur 服务器特有的配置文件,极其详细的配置项,功能非常丰富,几乎可以替代数款插件。", + "permissions.yml": "是默认的权限定义 YAML 文件,在启动时自动生成。它的主要功能是将权限节点组合到一个文件中,以便权限插件 (以及使用权限的插件) 可以在整个系统中使用它。", + "spigot.yml": "Spigot 服务器都有的配置文件。", + "usercache.json": "储存着用名字及 UUID 信息的缓存文件。", + "version_history": "一些 Minecraft 和服务端核心的版本信息,一般记录着曾经使用过的版本。" + }} +> +{` +assets // 储存 Minecraft 音效贴图等重要文件,不要乱动 +cache // 缓存文件夹,一般放置 Minecraft 原版服务器 +config // Paper fork 服务器特有的配置文件 +crash-reports // 存放服务器崩溃的完整报告 +libraries // 存放服务器及部分插件的依赖库 +logs // 服务端日志文件夹 +plugins // 插件目录 +versions // 对应版本需要的依赖 jar +world // 主世界文件夹 + advancements // 成就文件夹 + data // 世界数据文件夹 + datapacks // 数据包 + bukkit + entities // 实体数据 + playerdata // 玩家数据 + poi // 兴趣点数据 + region // 区块数据 + stats // 统计信息 +world_nether // 地狱世界文件夹 + DIM-1 + data + entities + poi + region +world_the_end // 末地世界文件夹 + DIM1 + data + entities + poi + region +.console_history // 存放控制台指令历史 +banned-ips.json // 被封禁的 IP 列表 +banned-players.json // 被封禁的玩家列表 +bukkit.yml // Bukkit 基本设置 +commands.yml // 命令别名与冲突解决 +eula.txt // EULA 协议文件 +help.yml // 帮助信息配置 +ops.json // 管理员(OP)名单 +purpur.jar // 服务端核心文件 +purpur.yml // Purpur 特有配置 +permissions.yml // 权限定义文件 +server.properties // 服务端基本配置文件 +spigot.yml // Spigot 配置文件 +usercache.json // 用户名与UUID缓存 +version_history // 版本历史记录 +whitelist.json // 白名单列表 +`} +
对于类似 Catserver 的混合服务器,文件夹结构是类似的,基本就多了 `/mods` 文件夹,少了 Bukkit 的下游服务器特有的配置 (如 `purpur.yml` 等)。 @@ -49,72 +97,6 @@ sidebar_position: 3 ::: -## 根目录下的一些文件 - -- `.console_history` - -存放了控制台 (又叫后台) 曾经使用过的指令,方便你使用键盘中的 ↑ 键快捷查找曾使用的指令,也可用于查看后台异常。 - -- `banned-ips.json` - -以 JSON 格式存放的被 ban IP 玩家的 UUID 及游戏名称等相关信息,一旦玩家被 banip,此 IP 将无法再进入服务器。 - -- `banned-players.json` - -以 JSON 格式存放了被 ban 玩家的 UUID 及游戏名称等相关信息,离线服 ban 玩家后换 ID 即可进入服务器,而正版服无法通过改名重新进入服务器。 - -- `bukkit.yml` - -由 Bukkit 派生得到的服务端都有的文件。保存着 Bukkit 所提供的最基本的设置选项。 - -- `commands.yml` - -它提供了一种快速而简单的方法来强制服务器使用 Mojang 提供的命令 (而不是 Bukkit 中内置的命令) 而不产生冲突。 - -- `eula.txt` - -在首次开服的时候,我们需要同意 EULA 协议。 - -- `help.yml` - -一些插件的帮助信息会出现在这里面,一般不需要进行什么修改。 - -- `ops.json` - -以 JSON 格式存放了 OP 玩家的 UUID 及游戏名称等相关信息。 - -- `purpur.jar` - -你可以改名叫任何名字 (只要以 `.jar` 结尾,且在启动脚本中对应修改) - -- `purpur.yml` - -Purpur 服务器特有的配置文件,极其详细的配置项,功能非常丰富,几乎可以替代数款插件。 - -- `permissions.yml` - -是默认的权限定义 YAML 文件,在启动时自动生成。它的主要功能是将权限节点组合到一个文件中,以便权限插件 (以及使用权限的插件) 可以在整个系统中使用它。 - -- [`server.properties`](https://minecraft-zh.gamepedia.com/Server.properties) - -服务端的一些基本设置就在里面,如设置端口,设置游戏难度,设置游戏模式 (生存、创造等) 等。 - -- `spigot.yml` - -Spigot 服务器都有的配置文件。 - -- `usercache.json` - -储存着用名字及 UUID 信息的缓存文件。 - -- `version_history` - -一些 Minecraft 和服务端核心的版本信息,一般记录着曾经使用过的版本。 - -- `whitelist.json` - -白名单列表。(如果你在[`server.properties`](https://minecraft-zh.gamepedia.com/Server.properties)中开启了白名单,你就可以在该文件中添加和管理谁被允许或不被允许进入服务器。) - 至此,大部分的以 Bukkit 为基础的服务器核心服务端的结构已经大致呈现在你眼前。 :::tip diff --git a/docs-java/start/basic/what-is-datapack.md b/docs-java/start/basic/what-is-datapack.md index f976a646b..760638ca8 100644 --- a/docs-java/start/basic/what-is-datapack.md +++ b/docs-java/start/basic/what-is-datapack.md @@ -3,6 +3,8 @@ title: 什么是数据包? sidebar_position: 6 --- +import { FileTree } from '@site/src/components/FileTree'; + # 什么是数据包? 数据包是从 Minecraft 逻辑结构层面修改我的世界,他可以添加或覆盖游戏中几乎一切的元素。一定程度下可以代替 mod,但它并不会改变原版的内容。 @@ -43,166 +45,166 @@ sidebar_position: 6 # 数据包结构 - -```c + +{` 数据包名 -├─pack.mcmeta // 用于识别数据包及存储数据包信息。 -├─pack.png // 数据包的图片 (可选)。 -├─data -│ ├─advancements -│ │ └─特定进度名.json -│ │ ├─display // 进度的显示信息 -│ │ │ ├─title // 进度标题 -│ │ │ ├─description // 进度描述 -│ │ │ ├─icon // 进度图标 -│ │ ├─criteria // 进度达成条件 -│ │ │ └─特定条件名.json -│ │ │ ├─trigger // 触发条件类型 -│ │ │ └─conditions // 具体的条件参数 -│ ├─loot_tables -│ │ └─特定物品或实体的战利品表.json -│ │ ├─pools // 战利品池列表 -│ │ │ └─特定战利品池.json -│ │ │ ├─rolls // 战利品生成次数 -│ │ │ ├─entries // 战利品条目 -│ │ │ │ └─特定条目.json -│ │ │ │ ├─type // 条目类型,如 item、loot_table 等 -│ │ │ │ ├─name // 物品或战利品表名称 -│ │ │ │ └─functions // 可选的函数列表,用于修改战利品 -│ │ │ │ └─特定函数.json -│ │ │ │ ├─function // 函数类型,如 set_nbt、enchant_with_levels 等 -│ │ │ │ └─arguments // 函数参数 -│ ├─recipes -│ │ └─特定合成配方.json -│ │ ├─type // 合成配方类型,如 crafting_shaped、crafting_shapeless 等 -│ │ ├─group // 合成组名 (可选) -│ │ ├─ingredients // 合成所需的材料列表 -│ │ │ └─特定材料.json -│ │ │ ├─item // 物品名称 -│ │ │ └─count // 物品数量 (可选) -│ │ └─result // 合成结果 -│ │ ├─item // 合成后的物品名称 -│ │ └─count // 合成后的物品数量 (可选) -│ ├─tags -│ │ ├─blocks -│ │ │ └─特定方块标签.json -│ │ │ ├─replace // 是否替换已有标签 (可选) -│ │ │ └─values // 方块名称列表 -│ │ ├─fluids -│ │ │ └─特定流体标签.json -│ │ │ ├─replace // 是否替换已有标签 (可选) -│ │ │ └─values // 流体名称列表 -│ │ ├─items -│ │ │ └─特定物品标签.json -│ │ │ ├─replace // 是否替换已有标签 (可选) -│ │ │ └─values // 物品名称列表 -│ │ ├─entity_types -│ │ │ └─特定实体类型标签.json -│ │ │ ├─replace // 是否替换已有标签 (可选) -│ │ │ └─values // 实体类型名称列表 -│ │ ├─functions -│ │ │ └─特定函数标签.json -│ │ │ ├─replace // 是否替换已有标签 (可选) -│ │ │ └─values // 函数名称列表 -│ │ ├─predicates -│ │ │ └─特定谓词标签.json -│ │ │ ├─replace // 是否替换已有标签 (可选) -│ │ │ └─values // 谓词名称列表 -│ │ ├─damage_types -│ │ │ └─特定伤害类型标签.json -│ │ │ ├─replace // 是否替换已有标签 (可选) -│ │ │ └─values // 伤害类型名称列表 -│ │ ├─enchantments -│ │ │ └─特定附魔标签.json -│ │ │ ├─replace // 是否替换已有标签 (可选) -│ │ │ └─values // 附魔名称列表 -│ │ ├─game_events -│ │ │ └─特定游戏事件标签.json -│ │ │ ├─replace // 是否替换已有标签 (可选) -│ │ │ └─values // 游戏事件名称列表 -│ │ └─其他可能的标签类型 -│ │ └─特定标签.json -│ │ ├─replace // 是否替换已有标签 (可选) -│ │ └─values // 对应名称列表 -│ ├─functions -│ │ └─特定函数文件.mcfunction -│ │ ├─各种命令语句 // 可以是游戏中的各种命令,用于实现特定的逻辑 -│ ├─predicates -│ │ └─特定谓词.json -│ │ ├─condition // 谓词条件 -│ │ │ ├─特定条件类型.json -│ │ │ │ └─参数 // 根据条件类型而定 -│ │ └─result // 谓词结果,通常是布尔值 -│ ├─dimension_types -│ │ └─特定维度类型.json -│ │ ├─effects // 维度效果列表 -│ │ │ └─特定效果.json -│ │ │ ├─特定效果类型 // 如 fog_color、ambient_light 等 -│ │ │ └─值 // 根据效果类型而定 -│ │ └─parameters // 维度类型参数 -│ │ └─特定参数.json -│ │ ├─名称 // 参数名称 -│ │ └─值 // 参数值 -│ ├─worldgen -│ │ ├─biome -│ │ │ └─特定生物群系.json -│ │ │ ├─features // 生物群系特征列表 -│ │ │ │ └─特定特征.json -│ │ │ │ ├─特定特征类型 // 如 lake、flower 等 -│ │ │ │ └─参数 // 根据特征类型而定 -│ │ │ ├─properties // 生物群系属性 -│ │ │ │ └─特定属性.json -│ │ │ │ ├─名称 // 属性名称 -│ │ │ │ └─值 // 属性值 -│ │ ├─configured_carver -│ │ │ └─特定雕刻器.json -│ │ │ ├─type // 雕刻器类型 -│ │ │ ├─biomes // 适用的生物群系列表 -│ │ │ └─parameters // 雕刻器参数 -│ │ │ └─特定参数.json -│ │ │ ├─名称 // 参数名称 -│ │ │ └─值 // 参数值 -│ │ ├─configured_feature -│ │ │ └─特定配置特征.json -│ │ │ ├─type // 特征类型 -│ │ │ ├─placement // 放置规则 -│ │ │ │ └─特定放置规则.json -│ │ │ │ ├─规则类型 // 如 height_range、on_ground 等 -│ │ │ │ └─参数 // 根据规则类型而定 -│ │ │ └─parameters // 特征参数 -│ │ │ └─特定参数.json -│ │ │ ├─名称 // 参数名称 -│ │ │ └─值 // 参数值 -│ │ ├─configured_structure_feature -│ │ │ └─特定配置结构特征.json -│ │ │ ├─type // 结构特征类型 -│ │ │ ├─placement // 放置规则 -│ │ │ │ └─特定放置规则.json -│ │ │ │ ├─规则类型 // 如 surface_rule、biome_filter 等 -│ │ │ │ └─参数 // 根据规则类型而定 -│ │ │ └─parameters // 结构特征参数 -│ │ │ └─特定参数.json -│ │ │ ├─名称 // 参数名称 -│ │ │ └─值 // 参数值 -│ │ ├─noise -│ │ │ └─特定噪声设置.json -│ │ │ ├─noise_type // 噪声类型 -│ │ │ ├─parameters // 噪声参数 -│ │ │ │ └─特定参数.json -│ │ │ │ ├─名称 // 参数名称 -│ │ │ │ └─值 // 参数值 -│ │ └─processor_list -│ │ └─特定处理器列表.json -│ │ ├─processors // 处理器列表 -│ │ │ └─特定处理器.json -│ │ │ ├─type // 处理器类型 -│ │ │ └─parameters // 处理器参数 -│ │ │ └─特定参数.json -│ │ │ ├─名称 // 参数名称 -│ │ │ └─值 // 参数值 -│ └─其他可能的子文件夹,具体取决于数据包的功能需求。 - -``` + pack.mcmeta // 用于识别数据包及存储数据包信息。 + pack.png // 数据包的图片 (可选)。 + data + advancements + 特定进度名.json + display // 进度的显示信息 + title // 进度标题 + description // 进度描述 + icon // 进度图标 + criteria // 进度达成条件 + 特定条件名.json + trigger // 触发条件类型 + conditions // 具体的条件参数 + loot_tables + 特定物品或实体的战利品表.json + pools // 战利品池列表 + 特定战利品池.json + rolls // 战利品生成次数 + entries // 战利品条目 + 特定条目.json + type // 条目类型,如 item、loot_table 等 + name // 物品或战利品表名称 + functions // 可选的函数列表,用于修改战利品 + 特定函数.json + function // 函数类型,如 set_nbt、enchant_with_levels 等 + arguments // 函数参数 + recipes + 特定合成配方.json + type // 合成配方类型,如 crafting_shaped、crafting_shapeless 等 + group // 合成组名 (可选) + ingredients // 合成所需的材料列表 + 特定材料.json + item // 物品名称 + count // 物品数量 (可选) + result // 合成结果 + item // 合成后的物品名称 + count // 合成后的物品数量 (可选) + tags + blocks + 特定方块标签.json + replace // 是否替换已有标签 (可选) + values // 方块名称列表 + fluids + 特定流体标签.json + replace // 是否替换已有标签 (可选) + values // 流体名称列表 + items + 特定物品标签.json + replace // 是否替换已有标签 (可选) + values // 物品名称列表 + entity_types + 特定实体类型标签.json + replace // 是否替换已有标签 (可选) + values // 实体类型名称列表 + functions + 特定函数标签.json + replace // 是否替换已有标签 (可选) + values // 函数名称列表 + predicates + 特定谓词标签.json + replace // 是否替换已有标签 (可选) + values // 谓词名称列表 + damage_types + 特定伤害类型标签.json + replace // 是否替换已有标签 (可选) + values // 伤害类型名称列表 + enchantments + 特定附魔标签.json + replace // 是否替换已有标签 (可选) + values // 附魔名称列表 + game_events + 特定游戏事件标签.json + replace // 是否替换已有标签 (可选) + values // 游戏事件名称列表 + 其他可能的标签类型 + 特定标签.json + replace // 是否替换已有标签 (可选) + values // 对应名称列表 + functions + 特定函数文件.mcfunction + 各种命令语句 // 可以是游戏中的各种命令,用于实现特定的逻辑 + predicates + 特定谓词.json + condition // 谓词条件 + 特定条件类型.json + 参数 // 根据条件类型而定 + result // 谓词结果,通常是布尔值 + dimension_types + 特定维度类型.json + effects // 维度效果列表 + 特定效果.json + 特定效果类型 // 如 fog_color、ambient_light 等 + 值 // 根据效果类型而定 + parameters // 维度类型参数 + 特定参数.json + 名称 // 参数名称 + 值 // 参数值 + worldgen + biome + 特定生物群系.json + features // 生物群系特征列表 + 特定特征.json + 特定特征类型 // 如 lake、flower 等 + 参数 // 根据特征类型而定 + properties // 生物群系属性 + 特定属性.json + 名称 // 属性名称 + 值 // 属性值 + configured_carver + 特定雕刻器.json + type // 雕刻器类型 + biomes // 适用的生物群系列表 + parameters // 雕刻器参数 + 特定参数.json + 名称 // 参数名称 + 值 // 参数值 + configured_feature + 特定配置特征.json + type // 特征类型 + placement // 放置规则 + 特定放置规则.json + 规则类型 // 如 height_range、on_ground 等 + 参数 // 根据规则类型而定 + parameters // 特征参数 + 特定参数.json + 名称 // 参数名称 + 值 // 参数值 + configured_structure_feature + 特定配置结构特征.json + type // 结构特征类型 + placement // 放置规则 + 特定放置规则.json + 规则类型 // 如 surface_rule、biome_filter 等 + 参数 // 根据规则类型而定 + parameters // 结构特征参数 + 特定参数.json + 名称 // 参数名称 + 值 // 参数值 + noise + 特定噪声设置.json + noise_type // 噪声类型 + parameters // 噪声参数 + 特定参数.json + 名称 // 参数名称 + 值 // 参数值 + processor_list + 特定处理器列表.json + processors // 处理器列表 + 特定处理器.json + type // 处理器类型 + parameters // 处理器参数 + 特定参数.json + 名称 // 参数名称 + 值 // 参数值 + 其他可能的子文件夹,具体取决于数据包的功能需求。 +`} + # 数据包的编写 diff --git a/docs/advance/management/player-management/client-distribution.md b/docs/advance/management/player-management/client-distribution.md index 0cd2d1853..3fad889f8 100644 --- a/docs/advance/management/player-management/client-distribution.md +++ b/docs/advance/management/player-management/client-distribution.md @@ -4,6 +4,8 @@ slug: /Sundry/Advance/management/player-management/client-distribution sidebar_position: 6 --- +import { FileTree } from '@site/src/components/FileTree'; + # 分发客户端 当你的服务器要求玩家使用特定版本客户端或安装特定模组时,你需要主动为玩家提供客户端的获取方式,方便新玩家们更方便地玩上你的服务器。 @@ -40,14 +42,16 @@ sidebar_position: 6 2. **解压至整合包目录,以 HMCL 为例,结构如下:** - ```plain text - MyModpack/ - ├── java/ - │ └── bin/ - ├── HMCL.exe - ├── hmcl.json - └── .minecraft/ - ``` + + {` + MyModpack + java + bin + HMCL.exe + hmcl.json + .minecraft + `} + 3. **调整启动器设置:** 以 HMCL 为例,前往 **版本管理** ,确保启用了 **启用版本特定游戏设置(不影响其他游戏版本)** ,**游戏 Java** 选择 **指定 Java 版本** ,在此选项同一行的右侧输入框中填写以下内容: diff --git a/docs/advance/viaproxy/configuration.md b/docs/advance/viaproxy/configuration.md index 3587df728..7f388e318 100644 --- a/docs/advance/viaproxy/configuration.md +++ b/docs/advance/viaproxy/configuration.md @@ -3,6 +3,8 @@ title: 配置详解 sidebar_position: 3 --- +import { FileTree } from '@site/src/components/FileTree'; + # 配置详解 本文档详细介绍 ViaProxy 的各种配置选项和参数设置。 @@ -11,20 +13,21 @@ sidebar_position: 3 ViaProxy 使用 YAML 格式的配置文件,主要包含以下几个部分: -```text -viaproxy/ -├── viaproxy.yml # 主配置文件 -├── ViaLoader/ # 协议转换配置 -│ ├── viaversion.yml -│ ├── viabackwards.yml -│ ├── viarewind.yml -│ ├── vialegacy.yml -│ ├── viabedrock.yml -│ └── viaaprilfools.yml -├── plugins/ # 插件目录 -├── logs/ # 日志目录 -└── saves.json # 服务器保存数据 -``` + +{` +viaproxy.yml // 主配置文件 +ViaLoader // 协议转换配置 + viaversion.yml + viabackwards.yml + viarewind.yml + vialegacy.yml + viabedrock.yml + viaaprilfools.yml +plugins // 插件目录 +logs // 日志目录 +saves.json // 服务器保存数据 +`} + ## 主配置文件 (viaproxy.yml) diff --git a/src/components/FileTree/index.tsx b/src/components/FileTree/index.tsx new file mode 100644 index 000000000..68debf236 --- /dev/null +++ b/src/components/FileTree/index.tsx @@ -0,0 +1,210 @@ +import React, { useState, useMemo } from "react"; +import styles from "./styles.module.css"; +import { + FolderOpenOutlined, + FolderOutlined, + FileOutlined, + FileTextOutlined, + InfoCircleOutlined, +} from "@ant-design/icons"; + +export type FileNode = { + name: string; + comment?: string; + description?: React.ReactNode; + children?: FileNode[]; + icon?: React.ReactNode; +}; + +interface FileTreeProps { + nodes?: FileNode[]; + children?: React.ReactNode; + descriptions?: Record; +} + +const getIcon = (name: string, isFolder: boolean) => { + if (isFolder) return ; + if (name.endsWith(".json") || name.endsWith(".yml") || name.endsWith(".yaml") || name.endsWith(".md") || name.endsWith(".txt")) { + return ; + } + return ; +}; + +function parseTreeString(content: string): FileNode[] { + const lines = content.split('\n'); + const root: FileNode[] = []; + const stack: { indent: number; nodes: FileNode[] }[] = [{ indent: -1, nodes: root }]; + + for (const line of lines) { + if (!line.trim()) continue; + + const indentMatch = line.match(/^\s*/); + const indent = indentMatch ? indentMatch[0].length : 0; + const trimmed = line.trim(); + + const commentIndex = trimmed.indexOf('//'); + let name = trimmed; + let comment = ''; + + if (commentIndex !== -1) { + name = trimmed.substring(0, commentIndex).trim(); + comment = trimmed.substring(commentIndex + 2).trim(); + } + + let description: React.ReactNode | undefined = undefined; + // Automatically move long comments to description + if (comment.length > 30) { + description = comment; + } + + const node: FileNode = { name, comment: comment || undefined, description, children: [] }; + + while (stack.length > 1 && stack[stack.length - 1].indent >= indent) { + stack.pop(); + } + + const parent = stack[stack.length - 1]; + parent.nodes.push(node); + + stack.push({ indent, nodes: node.children! }); + } + + const clean = (nodes: FileNode[]) => { + for (const node of nodes) { + if (node.children && node.children.length === 0) { + delete node.children; + } else if (node.children) { + clean(node.children); + } + } + }; + clean(root); + + return root; +} + +function injectDescriptions(nodes: FileNode[], descriptions: Record, parentPath: string = ''): FileNode[] { + return nodes.map(node => { + const currentPath = parentPath ? `${parentPath}/${node.name}` : node.name; + // Try path match first, then name match + const desc = descriptions[currentPath] || descriptions[node.name]; + + const newNode = { ...node }; + if (desc) { + newNode.description = desc; + } + + if (newNode.children) { + newNode.children = injectDescriptions(newNode.children, descriptions, currentPath); + } + + return newNode; + }); +} + +function NodeItem({ + node, + path, + onSelect, + selectedPath, +}: { + node: FileNode; + path: string; + onSelect: (node: FileNode, path: string) => void; + selectedPath: string | null; +}): React.ReactElement { + const currentPath = `${path}/${node.name}`; + const hasChildren = Boolean(node.children && node.children.length); + const hasDescription = Boolean(node.description); + // Expand if selected or if it's a folder that is open (we can track folder state separately if needed) + // For now, let's just toggle children on click for folders. + // For files with description, toggle description on click. + + const [expanded, setExpanded] = useState(true); + const [showDesc, setShowDesc] = useState(false); + + const handleClick = (e: React.MouseEvent) => { + e.stopPropagation(); + onSelect(node, currentPath); + if (hasChildren) { + setExpanded(!expanded); + } + if (hasDescription) { + setShowDesc(!showDesc); + } + }; + + const Icon = node.icon || getIcon(node.name, hasChildren); + + return ( +
  • +
    + {Icon} + {node.name} + {node.comment && // {node.comment}} + {hasDescription && } +
    + + {hasDescription && showDesc && ( +
    + {node.description} +
    + )} + + {hasChildren && expanded && ( +
      + {node.children!.map((child) => ( + + ))} +
    + )} +
  • + ); +} + +export function FileTree({ nodes, children, descriptions }: FileTreeProps): React.ReactElement { + const [selectedNode, setSelectedNode] = useState(null); + const [selectedPath, setSelectedPath] = useState(null); + + const treeData = useMemo(() => { + if (nodes) return nodes; + if (typeof children === 'string') { + const parsed = parseTreeString(children); + if (descriptions) { + return injectDescriptions(parsed, descriptions); + } + return parsed; + } + return []; + }, [nodes, children, descriptions]); + + const handleSelect = (node: FileNode, path: string) => { + setSelectedNode(node); + setSelectedPath(path); + }; + + return ( +
    +
      + {treeData.map((node) => ( + + ))} +
    +
    + ); +} diff --git a/src/components/FileTree/styles.module.css b/src/components/FileTree/styles.module.css new file mode 100644 index 000000000..256064d80 --- /dev/null +++ b/src/components/FileTree/styles.module.css @@ -0,0 +1,99 @@ +.container { + border: 1px solid var(--ifm-color-emphasis-200); + border-radius: var(--ifm-global-radius); + background: var(--ifm-background-surface-color); + margin: 1.5rem 0; + padding: 1rem; + overflow: hidden; +} + +.rootList, .childrenList { + list-style: none; + padding: 0; + margin: 0; +} + +.childrenList { + padding-left: 1.2rem; + border-left: 1px solid var(--ifm-color-emphasis-200); + margin-left: 0.6rem; +} + +.nodeItem { + margin: 2px 0; +} + +.nodeRow { + display: flex; + align-items: center; + padding: 4px 8px; + cursor: pointer; + border-radius: 4px; + transition: background-color 0.2s; + font-family: var(--ifm-font-family-monospace); + font-size: 0.9rem; + width: 100%; +} + +.nodeRow:hover { + background-color: var(--ifm-color-emphasis-100); +} + +.nodeRow.selected { + background-color: var(--ifm-color-primary-lightest); + color: var(--ifm-color-primary-dark); +} + +:global([data-theme='dark']) .nodeRow.selected { + background-color: var(--ifm-color-primary-darker); + color: var(--ifm-color-primary-light); +} + +.icon { + margin-right: 8px; + display: flex; + align-items: center; + color: var(--ifm-color-emphasis-700); + flex-shrink: 0; +} + +.name { + font-weight: 500; + white-space: nowrap; + flex-shrink: 0; +} + +.commentInline { + margin-left: 8px; + color: var(--ifm-color-emphasis-600); + font-size: 0.8em; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + flex: 1; + min-width: 0; +} + +.infoIcon { + margin-left: 8px; + color: var(--ifm-color-primary); + opacity: 0.7; + padding: 4px; + flex-shrink: 0; +} + +.nodeRow:hover .infoIcon { + opacity: 1; +} + +.inlineDescription { + margin-left: 2.2rem; + margin-top: 0.5rem; + margin-bottom: 0.5rem; + padding: 0.8rem; + background: var(--ifm-color-emphasis-100); + border-radius: 4px; + font-size: 0.9rem; + line-height: 1.5; + border-left: 3px solid var(--ifm-color-primary); +} From 551c8c23d0ad48d3a1bd0c640a996d6116715cef Mon Sep 17 00:00:00 2001 From: Ziphyrien <2697860027@qq.com> Date: Mon, 15 Dec 2025 13:23:26 +0800 Subject: [PATCH 2/3] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=20FileTree?= =?UTF-8?q?=20=E7=BB=84=E4=BB=B6=EF=BC=8C=E4=BC=98=E5=8C=96=E6=A0=B7?= =?UTF-8?q?=E5=BC=8F=E4=B8=8E=E4=BA=A4=E4=BA=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 主要变更: 1. 样式重构:移除 CSS Modules,迁移至 Tailwind CSS,优化深色模式适配。 2. 交互优化:引入 View Transitions API 支持平滑动画,添加独立的折叠/展开按钮。 3. 逻辑改进: - 优化图标判断逻辑,无后缀文件默认显示为文件图标。 - 支持显式文件夹标记,名称后添加 '/' 即可强制识别为文件夹。 4. 文档更新:更新了相关文档中的文件树示例,适配新的语法。 使用教程: - 文件夹标记:在名称后添加 '/' (如 'logs/') 可强制显示为文件夹图标并高亮。 - 自动描述:超过 30 个字符的注释会自动转换为下方的详细描述块。 - 图标识别:自动识别常见文件扩展名和特定文件名 (如 Dockerfile, Makefile)。 --- .../process/levilamina/levilamina-plugins.md | 6 +- .../bds/start/basic/server-dir-structure.md | 24 +-- .../start/basic/server-file-structure.md | 12 +- .../geyser/upgrade/extended/fix.md | 6 +- .../process/plugin/more/plugin-build/first.md | 66 +++--- docs-java/start/basic/server-dir-structure.md | 60 +++--- docs-java/start/basic/what-is-datapack.md | 54 ++--- .../player-management/client-distribution.md | 8 +- docs/advance/viaproxy/configuration.md | 6 +- src/components/FileTree/index.tsx | 202 +++++++++++++----- src/components/FileTree/styles.module.css | 99 --------- 11 files changed, 273 insertions(+), 270 deletions(-) delete mode 100644 src/components/FileTree/styles.module.css diff --git a/docs-bedrock/bds/process/levilamina/levilamina-plugins.md b/docs-bedrock/bds/process/levilamina/levilamina-plugins.md index 4425b81bb..9ecb88f21 100644 --- a/docs-bedrock/bds/process/levilamina/levilamina-plugins.md +++ b/docs-bedrock/bds/process/levilamina/levilamina-plugins.md @@ -14,10 +14,10 @@ LeviLamina 的插件是以文件夹的格式存在的。通常插件文件夹中 {` -插件文件夹 +插件文件夹/ manifest.json // 插件元数据文件,该文件必须存在并格式正确才能被 LeviLamina 识别 - (插件配置文件和数据库)... // 插件生成的配置文件和数据库等,大多数插件的配置文件名叫 config.json,并以一个文件夹或一个 .db 或 .json 后缀文件作为数据库 - (插件代码或二进制文件)... // 插件源代码,通常是 .js、.lua、.dll 后缀的文件。不要删除,修改或重命名文件,否则可能导致插件无法运行! + (插件配置文件和数据库).../ // 插件生成的配置文件和数据库等,大多数插件的配置文件名叫 config.json,并以一个文件夹或一个 .db 或 .json 后缀文件作为数据库 + (插件代码或二进制文件).../ // 插件源代码,通常是 .js、.lua、.dll 后缀的文件。不要删除,修改或重命名文件,否则可能导致插件无法运行! `} diff --git a/docs-bedrock/bds/start/basic/server-dir-structure.md b/docs-bedrock/bds/start/basic/server-dir-structure.md index 96480f648..f71b12a10 100644 --- a/docs-bedrock/bds/start/basic/server-dir-structure.md +++ b/docs-bedrock/bds/start/basic/server-dir-structure.md @@ -12,18 +12,18 @@ import { FileTree } from '@site/src/components/FileTree'; {` -BDS服务端文件夹 - behavior_packs // 安装新行为包的文件夹 - config // 没啥用 - definitions // 貌似是生成群系的内容 - development_behavior_packs // 为开发者提供安装新行为包的文件夹 - development_resource_packs // 为开发者提供安装新资源包的文件夹 - development_skin_packs // 为开发者提供安装新皮肤包的文件夹 - resource_packs // 安装新资源包的文件夹 - world-templates // 世界模板 - worlds // 主世界文件夹 - Bedrock level // 世界存档 - db // 存档数据文件夹 +BDS服务端文件夹/ + behavior_packs/ // 安装新行为包的文件夹 + config/ // 没啥用 + definitions/ // 貌似是生成群系的内容 + development_behavior_packs/ // 为开发者提供安装新行为包的文件夹 + development_resource_packs/ // 为开发者提供安装新资源包的文件夹 + development_skin_packs/ // 为开发者提供安装新皮肤包的文件夹 + resource_packs/ // 安装新资源包的文件夹 + world-templates/ // 世界模板 + worlds/ // 主世界文件夹 + Bedrock level/ // 世界存档 + db/ // 存档数据文件夹 level_dat // 存档设定 level.dat_old // 存档设定 (旧) level_name.txt // 存档名称 diff --git a/docs-bedrock/nukkit/start/basic/server-file-structure.md b/docs-bedrock/nukkit/start/basic/server-file-structure.md index 9a6b1dce3..aa900979b 100644 --- a/docs-bedrock/nukkit/start/basic/server-file-structure.md +++ b/docs-bedrock/nukkit/start/basic/server-file-structure.md @@ -20,13 +20,13 @@ permissions.yml // 用于设置玩家权限的 banned-players.txt // 存储被封禁的玩家名单的 banned-ips.txt // 存储被封禁的 IP 地址 ops.txt // 用于设置管理员(OP)的 -worlds // 主世界文件夹 - world // 世界存档 +worlds/ // 主世界文件夹 + world/ // 世界存档 level.dat // 存档设定 - region // 存储世界区块数据 - entities // 存储世界中的实体数据 -plugins // 插件存放文件夹 -logs // 服务器日志存放 + region/ // 存储世界区块数据 + entities/ // 存储世界中的实体数据 +plugins/ // 插件存放文件夹 +logs/ // 服务器日志存放 whitelist.txt // 存储允许加入服务器的玩家名单 rcon_password.txt // 存储 RCON(远程控制)功能的密码 `} diff --git a/docs-java/process/mobile-player/geyser/upgrade/extended/fix.md b/docs-java/process/mobile-player/geyser/upgrade/extended/fix.md index 4607a40eb..f1ad0f0f0 100644 --- a/docs-java/process/mobile-player/geyser/upgrade/extended/fix.md +++ b/docs-java/process/mobile-player/geyser/upgrade/extended/fix.md @@ -162,9 +162,9 @@ Broadcaster 通过模拟 Xbox Live 客户端,将你的 Geyser/基岩版服务 {` - plugins - Geyser-Spigot - extensions + plugins/ + Geyser-Spigot/ + extensions/ MCXboxBroadcastExtension.jar `} diff --git a/docs-java/process/plugin/more/plugin-build/first.md b/docs-java/process/plugin/more/plugin-build/first.md index e5a60e821..9e0832254 100644 --- a/docs-java/process/plugin/more/plugin-build/first.md +++ b/docs-java/process/plugin/more/plugin-build/first.md @@ -73,24 +73,24 @@ import { FileTree } from '@site/src/components/FileTree'; {` -src // 源代码目录 - main // 主要代码目录 - java // Java 源代码 - com - example - plugin +src/ // 源代码目录 + main/ // 主要代码目录 + java/ // Java 源代码 + com/ + example/ + plugin/ Main.java // 插件主类 - commands // 命令类 - listeners // 监听器类 - utils // 工具类 - resources // 资源文件目录 + commands/ // 命令类 + listeners/ // 监听器类 + utils/ // 工具类 + resources/ // 资源文件目录 plugin.yml // 插件配置文件 config.yml // 插件默认配置 messages // 语言文件 - test // 测试代码目录 - java // 测试源代码 - resources // 测试资源 -target // 构建输出目录 + test/ // 测试代码目录 + java/ // 测试源代码 + resources/ // 测试资源 +target/ // 构建输出目录 pom.xml // Maven 项目配置文件 README.md // 项目说明文件 `} @@ -101,29 +101,29 @@ README.md // 项目说明文件 {` -src // 源代码目录 - main // 主要代码目录 - java // Java 源代码 - com - example - plugin +src/ // 源代码目录 + main/ // 主要代码目录 + java/ // Java 源代码 + com/ + example/ + plugin/ Main.java // 插件主类 - commands // 命令类 - listeners // 监听器类 - utils // 工具类 - kotlin // Kotlin 源代码(如果使用) - resources // 资源文件目录 + commands/ // 命令类 + listeners/ // 监听器类 + utils/ // 工具类 + kotlin/ // Kotlin 源代码(如果使用) + resources/ // 资源文件目录 plugin.yml // 插件配置文件 config.yml // 插件默认配置 messages // 语言文件 - test // 测试代码目录 - java // 测试源代码 - kotlin // Kotlin 测试代码 - resources // 测试资源 -build // 构建输出目录 - libs // 构建产物(jar 文件) -gradle // Gradle 包装器目录 - wrapper + test/ // 测试代码目录 + java/ // 测试源代码 + kotlin/ // Kotlin 测试代码 + resources/ // 测试资源 +build/ // 构建输出目录 + libs/ // 构建产物(jar 文件) +gradle/ // Gradle 包装器目录 + wrapper/ build.gradle // Gradle 构建脚本 settings.gradle // Gradle 设置文件 gradlew // Gradle 包装器脚本 (Unix) diff --git a/docs-java/start/basic/server-dir-structure.md b/docs-java/start/basic/server-dir-structure.md index bc02ff30e..9667397e3 100644 --- a/docs-java/start/basic/server-dir-structure.md +++ b/docs-java/start/basic/server-dir-structure.md @@ -40,36 +40,36 @@ import { FileTree } from '@site/src/components/FileTree'; }} > {` -assets // 储存 Minecraft 音效贴图等重要文件,不要乱动 -cache // 缓存文件夹,一般放置 Minecraft 原版服务器 -config // Paper fork 服务器特有的配置文件 -crash-reports // 存放服务器崩溃的完整报告 -libraries // 存放服务器及部分插件的依赖库 -logs // 服务端日志文件夹 -plugins // 插件目录 -versions // 对应版本需要的依赖 jar -world // 主世界文件夹 - advancements // 成就文件夹 - data // 世界数据文件夹 - datapacks // 数据包 - bukkit - entities // 实体数据 - playerdata // 玩家数据 - poi // 兴趣点数据 - region // 区块数据 - stats // 统计信息 -world_nether // 地狱世界文件夹 - DIM-1 - data - entities - poi - region -world_the_end // 末地世界文件夹 - DIM1 - data - entities - poi - region +assets/ // 储存 Minecraft 音效贴图等重要文件,不要乱动 +cache/ // 缓存文件夹,一般放置 Minecraft 原版服务器 +config/ // Paper fork 服务器特有的配置文件 +crash-reports/ // 存放服务器崩溃的完整报告 +libraries/ // 存放服务器及部分插件的依赖库 +logs/ // 服务端日志文件夹 +plugins/ // 插件目录 +versions/ // 对应版本需要的依赖 jar +world/ // 主世界文件夹 + advancements/ // 成就文件夹 + data/ // 世界数据文件夹 + datapacks/ // 数据包 + bukkit/ + entities/ // 实体数据 + playerdata/ // 玩家数据 + poi/ // 兴趣点数据 + region/ // 区块数据 + stats/ // 统计信息 +world_nether/ // 地狱世界文件夹 + DIM-1/ + data/ + entities/ + poi/ + region/ +world_the_end/ // 末地世界文件夹 + DIM1/ + data/ + entities/ + poi/ + region/ .console_history // 存放控制台指令历史 banned-ips.json // 被封禁的 IP 列表 banned-players.json // 被封禁的玩家列表 diff --git a/docs-java/start/basic/what-is-datapack.md b/docs-java/start/basic/what-is-datapack.md index 760638ca8..f4e640368 100644 --- a/docs-java/start/basic/what-is-datapack.md +++ b/docs-java/start/basic/what-is-datapack.md @@ -47,11 +47,11 @@ import { FileTree } from '@site/src/components/FileTree'; {` -数据包名 +数据包名/ pack.mcmeta // 用于识别数据包及存储数据包信息。 pack.png // 数据包的图片 (可选)。 - data - advancements + data/ + advancements/ 特定进度名.json display // 进度的显示信息 title // 进度标题 @@ -61,7 +61,7 @@ import { FileTree } from '@site/src/components/FileTree'; 特定条件名.json trigger // 触发条件类型 conditions // 具体的条件参数 - loot_tables + loot_tables/ 特定物品或实体的战利品表.json pools // 战利品池列表 特定战利品池.json @@ -74,7 +74,7 @@ import { FileTree } from '@site/src/components/FileTree'; 特定函数.json function // 函数类型,如 set_nbt、enchant_with_levels 等 arguments // 函数参数 - recipes + recipes/ 特定合成配方.json type // 合成配方类型,如 crafting_shaped、crafting_shapeless 等 group // 合成组名 (可选) @@ -85,57 +85,57 @@ import { FileTree } from '@site/src/components/FileTree'; result // 合成结果 item // 合成后的物品名称 count // 合成后的物品数量 (可选) - tags - blocks + tags/ + blocks/ 特定方块标签.json replace // 是否替换已有标签 (可选) values // 方块名称列表 - fluids + fluids/ 特定流体标签.json replace // 是否替换已有标签 (可选) values // 流体名称列表 - items + items/ 特定物品标签.json replace // 是否替换已有标签 (可选) values // 物品名称列表 - entity_types + entity_types/ 特定实体类型标签.json replace // 是否替换已有标签 (可选) values // 实体类型名称列表 - functions + functions/ 特定函数标签.json replace // 是否替换已有标签 (可选) values // 函数名称列表 - predicates + predicates/ 特定谓词标签.json replace // 是否替换已有标签 (可选) values // 谓词名称列表 - damage_types + damage_types/ 特定伤害类型标签.json replace // 是否替换已有标签 (可选) values // 伤害类型名称列表 - enchantments + enchantments/ 特定附魔标签.json replace // 是否替换已有标签 (可选) values // 附魔名称列表 - game_events + game_events/ 特定游戏事件标签.json replace // 是否替换已有标签 (可选) values // 游戏事件名称列表 - 其他可能的标签类型 + 其他可能的标签类型/ 特定标签.json replace // 是否替换已有标签 (可选) values // 对应名称列表 - functions + functions/ 特定函数文件.mcfunction 各种命令语句 // 可以是游戏中的各种命令,用于实现特定的逻辑 - predicates + predicates/ 特定谓词.json condition // 谓词条件 特定条件类型.json 参数 // 根据条件类型而定 result // 谓词结果,通常是布尔值 - dimension_types + dimension_types/ 特定维度类型.json effects // 维度效果列表 特定效果.json @@ -145,8 +145,8 @@ import { FileTree } from '@site/src/components/FileTree'; 特定参数.json 名称 // 参数名称 值 // 参数值 - worldgen - biome + worldgen/ + biome/ 特定生物群系.json features // 生物群系特征列表 特定特征.json @@ -156,7 +156,7 @@ import { FileTree } from '@site/src/components/FileTree'; 特定属性.json 名称 // 属性名称 值 // 属性值 - configured_carver + configured_carver/ 特定雕刻器.json type // 雕刻器类型 biomes // 适用的生物群系列表 @@ -164,7 +164,7 @@ import { FileTree } from '@site/src/components/FileTree'; 特定参数.json 名称 // 参数名称 值 // 参数值 - configured_feature + configured_feature/ 特定配置特征.json type // 特征类型 placement // 放置规则 @@ -175,7 +175,7 @@ import { FileTree } from '@site/src/components/FileTree'; 特定参数.json 名称 // 参数名称 值 // 参数值 - configured_structure_feature + configured_structure_feature/ 特定配置结构特征.json type // 结构特征类型 placement // 放置规则 @@ -186,14 +186,14 @@ import { FileTree } from '@site/src/components/FileTree'; 特定参数.json 名称 // 参数名称 值 // 参数值 - noise + noise/ 特定噪声设置.json noise_type // 噪声类型 parameters // 噪声参数 特定参数.json 名称 // 参数名称 值 // 参数值 - processor_list + processor_list/ 特定处理器列表.json processors // 处理器列表 特定处理器.json @@ -202,7 +202,7 @@ import { FileTree } from '@site/src/components/FileTree'; 特定参数.json 名称 // 参数名称 值 // 参数值 - 其他可能的子文件夹,具体取决于数据包的功能需求。 + 其他可能的子文件夹,具体取决于数据包的功能需求。/ `} diff --git a/docs/advance/management/player-management/client-distribution.md b/docs/advance/management/player-management/client-distribution.md index 3fad889f8..9859aadac 100644 --- a/docs/advance/management/player-management/client-distribution.md +++ b/docs/advance/management/player-management/client-distribution.md @@ -44,12 +44,12 @@ import { FileTree } from '@site/src/components/FileTree'; {` - MyModpack - java - bin + MyModpack/ + java/ + bin/ HMCL.exe hmcl.json - .minecraft + .minecraft/ `} diff --git a/docs/advance/viaproxy/configuration.md b/docs/advance/viaproxy/configuration.md index 7f388e318..7084f2580 100644 --- a/docs/advance/viaproxy/configuration.md +++ b/docs/advance/viaproxy/configuration.md @@ -16,15 +16,15 @@ ViaProxy 使用 YAML 格式的配置文件,主要包含以下几个部分: {` viaproxy.yml // 主配置文件 -ViaLoader // 协议转换配置 +ViaLoader/ // 协议转换配置 viaversion.yml viabackwards.yml viarewind.yml vialegacy.yml viabedrock.yml viaaprilfools.yml -plugins // 插件目录 -logs // 日志目录 +plugins/ // 插件目录 +logs/ // 日志目录 saves.json // 服务器保存数据 `} diff --git a/src/components/FileTree/index.tsx b/src/components/FileTree/index.tsx index 68debf236..8e059436f 100644 --- a/src/components/FileTree/index.tsx +++ b/src/components/FileTree/index.tsx @@ -1,11 +1,14 @@ -import React, { useState, useMemo } from "react"; -import styles from "./styles.module.css"; +import React, { useState, useMemo, useCallback } from "react"; +import { flushSync } from "react-dom"; +import clsx from "clsx"; import { - FolderOpenOutlined, FolderOutlined, + FolderOpenOutlined, FileOutlined, FileTextOutlined, InfoCircleOutlined, + RightOutlined, + DownOutlined, } from "@ant-design/icons"; export type FileNode = { @@ -14,6 +17,7 @@ export type FileNode = { description?: React.ReactNode; children?: FileNode[]; icon?: React.ReactNode; + isFolder?: boolean; }; interface FileTreeProps { @@ -22,14 +26,55 @@ interface FileTreeProps { descriptions?: Record; } -const getIcon = (name: string, isFolder: boolean) => { - if (isFolder) return ; - if (name.endsWith(".json") || name.endsWith(".yml") || name.endsWith(".yaml") || name.endsWith(".md") || name.endsWith(".txt")) { +const TEXT_EXTENSIONS = new Set([ + ".json", ".yml", ".yaml", ".md", ".txt", + ".properties", ".xml", ".html", ".css", + ".js", ".ts", ".jsx", ".tsx", ".ini", ".conf", ".sh", ".bat", + ".java", ".py", ".c", ".cpp", ".h", ".hpp", ".go", ".rs", ".php", + ".toml", ".gradle" +]); + +const KNOWN_FILES = new Set([ + "license", "makefile", "dockerfile", "cname", + "gemfile", "pipfile", "procfile", "readme", + "changelog", "contributing", "security", "authors", "owners" +]); + +const getIcon = (name: string) => { + const lowerName = name.toLowerCase(); + + if (KNOWN_FILES.has(lowerName)) { return ; } + + if (name.startsWith('.')) { + return ; + } + + const dotIndex = lowerName.lastIndexOf('.'); + if (dotIndex !== -1) { + const ext = lowerName.substring(dotIndex); + if (TEXT_EXTENSIONS.has(ext)) { + return ; + } + return ; + } + return ; }; +function cleanTree(nodes: FileNode[]) { + for (const node of nodes) { + if (node.children) { + if (node.children.length === 0) { + delete node.children; + } else { + cleanTree(node.children); + } + } + } +} + function parseTreeString(content: string): FileNode[] { const lines = content.split('\n'); const root: FileNode[] = []; @@ -51,13 +96,18 @@ function parseTreeString(content: string): FileNode[] { comment = trimmed.substring(commentIndex + 2).trim(); } + let isFolder = false; + if (name.endsWith('/')) { + isFolder = true; + name = name.substring(0, name.length - 1); + } + let description: React.ReactNode | undefined = undefined; - // Automatically move long comments to description if (comment.length > 30) { description = comment; } - const node: FileNode = { name, comment: comment || undefined, description, children: [] }; + const node: FileNode = { name, comment: comment || undefined, description, children: [], isFolder }; while (stack.length > 1 && stack[stack.length - 1].indent >= indent) { stack.pop(); @@ -69,24 +119,13 @@ function parseTreeString(content: string): FileNode[] { stack.push({ indent, nodes: node.children! }); } - const clean = (nodes: FileNode[]) => { - for (const node of nodes) { - if (node.children && node.children.length === 0) { - delete node.children; - } else if (node.children) { - clean(node.children); - } - } - }; - clean(root); - + cleanTree(root); return root; } function injectDescriptions(nodes: FileNode[], descriptions: Record, parentPath: string = ''): FileNode[] { return nodes.map(node => { const currentPath = parentPath ? `${parentPath}/${node.name}` : node.name; - // Try path match first, then name match const desc = descriptions[currentPath] || descriptions[node.name]; const newNode = { ...node }; @@ -102,7 +141,18 @@ function injectDescriptions(nodes: FileNode[], descriptions: Record void) => { + if (typeof document !== 'undefined' && 'startViewTransition' in document) { + // @ts-ignore + document.startViewTransition(() => { + flushSync(callback); + }); + } else { + callback(); + } +}; + +const NodeItem = React.memo(({ node, path, onSelect, @@ -110,52 +160,104 @@ function NodeItem({ }: { node: FileNode; path: string; - onSelect: (node: FileNode, path: string) => void; + onSelect: (path: string) => void; selectedPath: string | null; -}): React.ReactElement { +}): React.ReactElement => { const currentPath = `${path}/${node.name}`; const hasChildren = Boolean(node.children && node.children.length); const hasDescription = Boolean(node.description); - // Expand if selected or if it's a folder that is open (we can track folder state separately if needed) - // For now, let's just toggle children on click for folders. - // For files with description, toggle description on click. + const isExplicitFolder = node.isFolder; const [expanded, setExpanded] = useState(true); const [showDesc, setShowDesc] = useState(false); - const handleClick = (e: React.MouseEvent) => { + const handleMainClick = (e: React.MouseEvent) => { + e.stopPropagation(); + onSelect(currentPath); + + startViewTransition(() => { + if (hasChildren) { + setExpanded(prev => !prev); + } + if (hasDescription) { + setShowDesc(prev => !prev); + } + }); + }; + + const handleChevronClick = (e: React.MouseEvent) => { e.stopPropagation(); - onSelect(node, currentPath); + startViewTransition(() => { + setExpanded(prev => !prev); + }); + }; + + let Icon = node.icon; + if (!Icon) { if (hasChildren) { - setExpanded(!expanded); - } - if (hasDescription) { - setShowDesc(!showDesc); + Icon = expanded ? : ; + } else if (isExplicitFolder) { + Icon = ; + } else { + Icon = getIcon(node.name); } - }; + } - const Icon = node.icon || getIcon(node.name, hasChildren); + const isSelected = selectedPath === currentPath; return ( -
  • +
  • - {Icon} - {node.name} - {node.comment && // {node.comment}} - {hasDescription && } + + {hasChildren && ( + expanded ? : + )} + + + + {Icon} + + + + {node.name} + + {node.comment && ( + + // {node.comment} + + )} + {hasDescription && ( + + )}
    {hasDescription && showDesc && ( -
    +
    {node.description}
    )} {hasChildren && expanded && ( -
      +
        {node.children!.map((child) => ( ); -} +}); + +NodeItem.displayName = 'NodeItem'; export function FileTree({ nodes, children, descriptions }: FileTreeProps): React.ReactElement { - const [selectedNode, setSelectedNode] = useState(null); const [selectedPath, setSelectedPath] = useState(null); const treeData = useMemo(() => { @@ -187,14 +290,13 @@ export function FileTree({ nodes, children, descriptions }: FileTreeProps): Reac return []; }, [nodes, children, descriptions]); - const handleSelect = (node: FileNode, path: string) => { - setSelectedNode(node); + const handleSelect = useCallback((path: string) => { setSelectedPath(path); - }; + }, []); return ( -
        -
          +
          +
            {treeData.map((node) => ( Date: Mon, 15 Dec 2025 13:33:44 +0800 Subject: [PATCH 3/3] =?UTF-8?q?refactor(FileTree):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E6=8F=90=E9=AB=98=E5=8F=AF=E7=BB=B4=E6=8A=A4?= =?UTF-8?q?=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/FileTree/index.tsx | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/components/FileTree/index.tsx b/src/components/FileTree/index.tsx index 8e059436f..2d7071c39 100644 --- a/src/components/FileTree/index.tsx +++ b/src/components/FileTree/index.tsx @@ -26,6 +26,9 @@ interface FileTreeProps { descriptions?: Record; } +const MAX_INLINE_COMMENT_LENGTH = 30; +const ROOT_PATH = 'root'; + const TEXT_EXTENSIONS = new Set([ ".json", ".yml", ".yaml", ".md", ".txt", ".properties", ".xml", ".html", ".css", @@ -103,7 +106,7 @@ function parseTreeString(content: string): FileNode[] { } let description: React.ReactNode | undefined = undefined; - if (comment.length > 30) { + if (comment.length > MAX_INLINE_COMMENT_LENGTH) { description = comment; } @@ -143,8 +146,7 @@ function injectDescriptions(nodes: FileNode[], descriptions: Record void) => { if (typeof document !== 'undefined' && 'startViewTransition' in document) { - // @ts-ignore - document.startViewTransition(() => { + (document as any).startViewTransition(() => { flushSync(callback); }); } else { @@ -152,6 +154,13 @@ const startViewTransition = (callback: () => void) => { } }; +const getIconColorClass = (hasChildren: boolean, isExplicitFolder: boolean | undefined, iconType: any) => { + if (hasChildren || isExplicitFolder || iconType === FolderOutlined || iconType === FolderOpenOutlined) { + return "text-[var(--ifm-color-primary)]"; + } + return "text-[var(--ifm-color-emphasis-700)]"; +}; + const NodeItem = React.memo(({ node, path, @@ -204,6 +213,7 @@ const NodeItem = React.memo(({ } const isSelected = selectedPath === currentPath; + const iconColorClass = getIconColorClass(hasChildren, isExplicitFolder, (Icon as React.ReactElement)?.type); return (
          • @@ -227,7 +237,7 @@ const NodeItem = React.memo(({ {Icon} @@ -301,7 +311,7 @@ export function FileTree({ nodes, children, descriptions }: FileTreeProps): Reac