From e1e1a93745f86c871093fe8d094ed541ab3db927 Mon Sep 17 00:00:00 2001 From: xiwangly2 Date: Wed, 29 Jul 2026 11:57:06 +0800 Subject: [PATCH 1/4] feat: add Terraria game support with installation and configuration documentation --- ...00\346\261\202\350\257\264\346\230\216.md" | 107 ++++++ ...0\346\213\211\347\221\236\344\272\232.yml" | 346 ++++++++++++++++++ server/data/games/installgame.json | 22 +- 3 files changed, 474 insertions(+), 1 deletion(-) create mode 100644 "docs/\346\263\260\346\213\211\347\221\236\344\272\232\344\270\216\345\206\205\347\275\221\347\251\277\351\200\217\346\217\222\344\273\266\351\234\200\346\261\202\350\257\264\346\230\216.md" create mode 100644 "server/data/gameconfig/\346\263\260\346\213\211\347\221\236\344\272\232.yml" diff --git "a/docs/\346\263\260\346\213\211\347\221\236\344\272\232\344\270\216\345\206\205\347\275\221\347\251\277\351\200\217\346\217\222\344\273\266\351\234\200\346\261\202\350\257\264\346\230\216.md" "b/docs/\346\263\260\346\213\211\347\221\236\344\272\232\344\270\216\345\206\205\347\275\221\347\251\277\351\200\217\346\217\222\344\273\266\351\234\200\346\261\202\350\257\264\346\230\216.md" new file mode 100644 index 00000000..e99f05c0 --- /dev/null +++ "b/docs/\346\263\260\346\213\211\347\221\236\344\272\232\344\270\216\345\206\205\347\275\221\347\251\277\351\200\217\346\217\222\344\273\266\351\234\200\346\261\202\350\257\264\346\230\216.md" @@ -0,0 +1,107 @@ +# 泰拉瑞亚与内网穿透插件需求说明 + +## 背景 + +这次需求来自两个使用场景: + +- Steam 游戏部署列表中缺少原版泰拉瑞亚,用户需要回到文档手动下载、上传、解压和交互式配置。 +- 家用主机、NAS、宿舍网络、运营商 CGNAT 等没有公网入口的环境,游戏服务端即使启动成功,也不方便让外部玩家连接。 + +## 已落地的最小改进 + +### 泰拉瑞亚 Steam 部署入口 + +在 `server/data/games/installgame.json` 中新增 `Terraria`: + +- 使用 Terraria Dedicated Server Tool AppID:`105610`。 +- 默认端口:`7777/TCP`。 +- 关联现有泰拉瑞亚开服文档。 +- 在提示中建议用 `serverconfig.txt` 启动,避免首次启动进入交互式建世界流程。 + +推荐实例启动命令: + +```bash +./TerrariaServer.bin.x86_64 -config serverconfig.txt +``` + +Windows 可改为: + +```powershell +.\TerrariaServer.exe -config serverconfig.txt +``` + +### 泰拉瑞亚可视化配置模板 + +在 `server/data/gameconfig/泰拉瑞亚.yml` 中新增 `serverconfig.txt` 模板: + +- 世界路径、自动建图、种子、世界名、难度。 +- 最大玩家数、端口、密码、MOTD。 +- 世界目录、封禁列表、作弊防护、语言、UPnP、NPC 同步、优先级。 +- 旅途模式权限项。 + +模板使用现有 `properties` 解析器。Terraria 的 `0/1` 开关用 `select` 表达,避免保存成 `true/false` 后与服务端配置格式不一致。 + +## 内网穿透插件候选需求 + +### 目标 + +提供一个可选工具,让没有公网 IP 的设备也能把游戏服务端端口暴露给外部玩家。插件应当只负责网络入口,不改变游戏实例本身的部署和启动逻辑。 + +### 支持对象 + +第一阶段建议支持: + +- frp 客户端模式:适合已有 frps 服务器的用户。 +- EasyTier 组网模式:适合希望多节点虚拟局域网互通的用户。 + +### MVP 能力 + +- 从实例列表选择一个游戏实例,读取实例名称、工作目录和端口信息。 +- 允许手动填写本地地址、本地端口、远端端口、远端服务器、认证 token 或组网密钥。 +- 生成 frpc 或 EasyTier 配置文件,默认保存到 `server/data/tunnels/` 下。 +- 通过实例管理创建一个独立的“穿透实例”,让用户用现有实例启停能力管理隧道进程。 +- 显示连接说明,例如 `远端地址:远端端口` 或 EasyTier 虚拟 IP。 + +### 非目标 + +- 不把 frp/EasyTier 变成游戏部署前置依赖。 +- 不替用户申请公网服务器或托管中继。 +- 不绕过游戏本身的账号、白名单、RCON、反作弊或服务端安全配置。 +- 不默认启用 UPnP 或自动开放所有端口。 + +## 推荐实现方式 + +### 插件优先 + +先做成 `server/data/plugins/tunnel-helper` 这类可选插件: + +- `plugin.json` 默认 `enabled: false`,避免默认安装后自动出现网络暴露入口。 +- `index.html` 只做配置生成、实例创建和状态查看。 +- 复用 `gsm3-api.js` 的实例 API、文件 API 和终端/进程列表 API。 + +这种方式与当前插件体系匹配,风险较低,也不会把第三方网络工具耦合进核心部署页。 + +### 核心 API 补强 + +如果后续要做成完整的一键体验,核心需要补一个受限的后台进程/工具管理能力: + +- 管理受信任工具定义:工具名称、版本、下载地址、校验和、支持平台。 +- 统一保存配置:配置文件、敏感字段、脱敏展示、备份恢复。 +- 统一管理进程:启动、停止、重启、日志、健康状态、退出码。 +- 限制命令注入:不要让插件拼接任意 shell 字符串后直接执行。 +- 与实例端口关联:从游戏配置或实例元数据中读取端口,减少重复输入。 + +## 安全与维护约束 + +- 所有后端接口必须加认证中间件。 +- 持久化数据放在 `server/data` 下,兼容开发和打包路径。 +- token、密钥、服务端地址等敏感字段不要出现在日志和普通列表展示中。 +- 不建议在仓库内直接提交第三方二进制;如需要下载,必须有来源、版本、哈希校验和失败回滚。 +- Windows、Linux、Docker 三种运行方式的路径、权限和停止信号要分别验证。 + +## PR 拆分建议 + +1. 泰拉瑞亚 Steam 安装清单与 `serverconfig.txt` 可视化模板。 +2. 内网穿透插件需求说明和界面草图。 +3. `tunnel-helper` 插件 MVP:生成配置并创建受管实例。 +4. 核心进程/工具 API 补强,完善二进制下载、校验、日志和状态检测。 diff --git "a/server/data/gameconfig/\346\263\260\346\213\211\347\221\236\344\272\232.yml" "b/server/data/gameconfig/\346\263\260\346\213\211\347\221\236\344\272\232.yml" new file mode 100644 index 00000000..8ca9ac80 --- /dev/null +++ "b/server/data/gameconfig/\346\263\260\346\213\211\347\221\236\344\272\232.yml" @@ -0,0 +1,346 @@ +meta: + game_name: "泰拉瑞亚" + config_file: "serverconfig.txt" + parser: "properties" + +sections: + - key: "serverconfig.txt" + fields: + - name: "world" + display: "世界文件路径" + default: "Worlds/world1.wld" + type: "string" + description: "要加载的世界文件。使用相对路径时会相对于服务端工作目录解析,建议与服务端文件放在同一持久化目录中" + - name: "autocreate" + display: "自动创建世界大小" + default: "1" + type: "select" + description: "当 world 指定的世界不存在时自动创建世界" + options: + - value: "0" + label: "不自动创建" + - value: "1" + label: "小世界" + - value: "2" + label: "中世界" + - value: "3" + label: "大世界" + - name: "seed" + display: "世界种子" + default: "" + type: "string" + description: "自动创建世界时使用的种子,留空则随机生成" + - name: "worldname" + display: "世界名称" + default: "Terraria" + type: "string" + description: "自动创建世界时使用的世界名称" + - name: "difficulty" + display: "世界难度" + default: "0" + type: "select" + description: "自动创建世界时使用的难度" + options: + - value: "0" + label: "经典" + - value: "1" + label: "专家" + - value: "2" + label: "大师" + - value: "3" + label: "旅途" + - name: "maxplayers" + display: "最大玩家数" + default: 8 + type: "number" + description: "允许加入服务器的最大玩家数量,官方配置示例范围为 1 到 255" + - name: "port" + display: "服务器端口" + default: 7777 + type: "number" + description: "Terraria 默认使用 7777 TCP" + - name: "password" + display: "服务器密码" + default: "" + type: "string" + description: "加入服务器需要输入的密码,留空表示无密码" + - name: "motd" + display: "每日消息" + default: "" + type: "string" + description: "玩家进入服务器时显示的消息" + - name: "worldpath" + display: "世界目录" + default: "Worlds" + type: "string" + description: "世界文件保存目录。Terraria 配置文件中不支持 $HOME 或 ~ 展开,建议使用相对路径或绝对路径" + - name: "worldrollbackstokeep" + display: "世界回滚备份数量" + default: 2 + type: "number" + description: "保留的滚动世界备份数量" + - name: "banlist" + display: "封禁列表路径" + default: "banlist.txt" + type: "string" + description: "封禁列表文件位置,默认在服务端工作目录下" + - name: "secure" + display: "作弊防护" + default: "1" + type: "select" + description: "启用 Terraria 服务端的额外作弊防护" + options: + - value: "1" + label: "启用" + - value: "0" + label: "关闭" + - name: "language" + display: "服务器语言" + default: "zh-Hans" + type: "select" + description: "服务端输出语言" + options: + - value: "zh-Hans" + label: "简体中文" + - value: "en-US" + label: "English" + - value: "de-DE" + label: "Deutsch" + - value: "it-IT" + label: "Italiano" + - value: "fr-FR" + label: "Francais" + - value: "es-ES" + label: "Espanol" + - value: "ru-RU" + label: "Русский" + - value: "pt-BR" + label: "Portugues" + - value: "pl-PL" + label: "Polski" + - name: "upnp" + display: "UPnP 自动端口转发" + default: "0" + type: "select" + description: "是否尝试通过 UPnP 自动转发端口。没有公网 IP 或处于 CGNAT 时仍需使用内网穿透等方案" + options: + - value: "0" + label: "关闭" + - value: "1" + label: "启用" + - name: "npcstream" + display: "NPC 同步频率" + default: 60 + type: "number" + description: "降低敌怪跳跃感但会增加带宽占用,0 表示关闭" + - name: "priority" + display: "进程优先级" + default: "1" + type: "select" + description: "服务端进程优先级" + options: + - value: "0" + label: "实时" + - value: "1" + label: "高" + - value: "2" + label: "高于正常" + - value: "3" + label: "正常" + - value: "4" + label: "低于正常" + - value: "5" + label: "空闲" + - name: "slowliquids" + display: "降低液体更新量" + default: "0" + type: "select" + description: "可降低同一时间移动的液体上限,可能减少卡顿但液体结算更慢" + options: + - value: "0" + label: "关闭" + - value: "1" + label: "启用" + + - key: "journey" + fields: + - name: "journeypermission_time_setfrozen" + display: "旅途权限:冻结时间" + default: "2" + type: "select" + description: "0 为所有人锁定,1 为仅主机可改,2 为所有人可改" + options: + - value: "0" + label: "锁定" + - value: "1" + label: "仅主机" + - value: "2" + label: "所有人" + - name: "journeypermission_time_setdawn" + display: "旅途权限:设置黎明" + default: "2" + type: "select" + description: "控制旅途模式中设置黎明的权限" + options: + - value: "0" + label: "锁定" + - value: "1" + label: "仅主机" + - value: "2" + label: "所有人" + - name: "journeypermission_time_setnoon" + display: "旅途权限:设置中午" + default: "2" + type: "select" + description: "控制旅途模式中设置中午的权限" + options: + - value: "0" + label: "锁定" + - value: "1" + label: "仅主机" + - value: "2" + label: "所有人" + - name: "journeypermission_time_setdusk" + display: "旅途权限:设置黄昏" + default: "2" + type: "select" + description: "控制旅途模式中设置黄昏的权限" + options: + - value: "0" + label: "锁定" + - value: "1" + label: "仅主机" + - value: "2" + label: "所有人" + - name: "journeypermission_time_setmidnight" + display: "旅途权限:设置午夜" + default: "2" + type: "select" + description: "控制旅途模式中设置午夜的权限" + options: + - value: "0" + label: "锁定" + - value: "1" + label: "仅主机" + - value: "2" + label: "所有人" + - name: "journeypermission_godmode" + display: "旅途权限:上帝模式" + default: "2" + type: "select" + description: "控制旅途模式中上帝模式的权限" + options: + - value: "0" + label: "锁定" + - value: "1" + label: "仅主机" + - value: "2" + label: "所有人" + - name: "journeypermission_wind_setstrength" + display: "旅途权限:风力强度" + default: "2" + type: "select" + description: "控制旅途模式中设置风力强度的权限" + options: + - value: "0" + label: "锁定" + - value: "1" + label: "仅主机" + - value: "2" + label: "所有人" + - name: "journeypermission_rain_setstrength" + display: "旅途权限:雨量强度" + default: "2" + type: "select" + description: "控制旅途模式中设置雨量强度的权限" + options: + - value: "0" + label: "锁定" + - value: "1" + label: "仅主机" + - value: "2" + label: "所有人" + - name: "journeypermission_time_setspeed" + display: "旅途权限:时间速度" + default: "2" + type: "select" + description: "控制旅途模式中设置时间速度的权限" + options: + - value: "0" + label: "锁定" + - value: "1" + label: "仅主机" + - value: "2" + label: "所有人" + - name: "journeypermission_rain_setfrozen" + display: "旅途权限:冻结雨天" + default: "2" + type: "select" + description: "控制旅途模式中冻结雨天的权限" + options: + - value: "0" + label: "锁定" + - value: "1" + label: "仅主机" + - value: "2" + label: "所有人" + - name: "journeypermission_wind_setfrozen" + display: "旅途权限:冻结风" + default: "2" + type: "select" + description: "控制旅途模式中冻结风的权限" + options: + - value: "0" + label: "锁定" + - value: "1" + label: "仅主机" + - value: "2" + label: "所有人" + - name: "journeypermission_increaseplacementrange" + display: "旅途权限:增加放置范围" + default: "2" + type: "select" + description: "控制旅途模式中增加放置范围的权限" + options: + - value: "0" + label: "锁定" + - value: "1" + label: "仅主机" + - value: "2" + label: "所有人" + - name: "journeypermission_setdifficulty" + display: "旅途权限:调整难度" + default: "2" + type: "select" + description: "控制旅途模式中调整难度的权限" + options: + - value: "0" + label: "锁定" + - value: "1" + label: "仅主机" + - value: "2" + label: "所有人" + - name: "journeypermission_biomespread_setfrozen" + display: "旅途权限:冻结生物群系蔓延" + default: "2" + type: "select" + description: "控制旅途模式中冻结腐化、猩红等蔓延的权限" + options: + - value: "0" + label: "锁定" + - value: "1" + label: "仅主机" + - value: "2" + label: "所有人" + - name: "journeypermission_setspawnrate" + display: "旅途权限:调整生成率" + default: "2" + type: "select" + description: "控制旅途模式中调整敌怪生成率的权限" + options: + - value: "0" + label: "锁定" + - value: "1" + label: "仅主机" + - value: "2" + label: "所有人" diff --git a/server/data/games/installgame.json b/server/data/games/installgame.json index 17d0e0d4..da166aed 100644 --- a/server/data/games/installgame.json +++ b/server/data/games/installgame.json @@ -166,6 +166,26 @@ "url": "https://store.steampowered.com/app/322330/_/", "docs": "https://docs.gsm.xiaozhuhouses.asia/%E6%B8%B8%E6%88%8F%E7%99%BE%E7%A7%91/Steam/%E9%A5%A5%E8%8D%92%E9%A3%9F%E7%94%A8%E8%AF%B4%E6%98%8E.html" }, + "Terraria": { + "game_nameCN": "泰拉瑞亚", + "appid": "105610", + "tip": "默认端口:7777 TCP。建议创建实例时使用 serverconfig.txt 启动,例如 Linux 使用 ./TerrariaServer.bin.x86_64 -config serverconfig.txt,Windows 使用 .\\TerrariaServer.exe -config serverconfig.txt,可避免首次启动进入交互式配置流程。", + "image": "https://shared.fastly.steamstatic.com/store_item_assets/steam/apps/105600/header.jpg", + "url": "https://store.steampowered.com/app/105600/Terraria/", + "docs": "https://docs.gsm.xiaozhuhouses.asia/%E6%B8%B8%E6%88%8F%E7%99%BE%E7%A7%91/Steam/%E6%B3%B0%E6%8B%89%E7%91%9E%E4%BA%9A%E9%A3%9F%E7%94%A8%E8%AF%B4%E6%98%8E.html", + "system": [ + "Windows", + "Linux", + "MacOS" + ], + "ports": [ + { + "port": 7777, + "protocol": "tcp" + } + ], + "memory": 1 + }, "Project_Zomboid": { "game_nameCN": "僵尸毁灭工程", "appid": "380870", @@ -836,4 +856,4 @@ "Windows" ] } -} \ No newline at end of file +} From 49d9430d19b90dc0e9c12faede7d760638c09681 Mon Sep 17 00:00:00 2001 From: xiwangly2 Date: Wed, 29 Jul 2026 12:16:48 +0800 Subject: [PATCH 2/4] feat: enhance Terraria support with installation paths, start commands, and documentation updates --- client/src/pages/GameDeploymentPage.tsx | 15 ++- ...00\346\261\202\350\257\264\346\230\216.md" | 4 +- server/data/games/installgame.json | 12 +- server/src/routes/gameDeployment.ts | 110 ++++++++++++++++-- 4 files changed, 123 insertions(+), 18 deletions(-) diff --git a/client/src/pages/GameDeploymentPage.tsx b/client/src/pages/GameDeploymentPage.tsx index a27a383e..4e7b7a0e 100644 --- a/client/src/pages/GameDeploymentPage.tsx +++ b/client/src/pages/GameDeploymentPage.tsx @@ -41,6 +41,7 @@ interface GameInfo { url: string docs?: string system?: string[] + login_anonymous?: boolean supportedOnCurrentPlatform?: boolean currentPlatform?: string panelCompatibleOnCurrentPlatform?: boolean @@ -2553,7 +2554,7 @@ const GameDeploymentPage: React.FC = () => { : `app_update ${selectedGame.info.appid}` // force_install_dir 必须在 login 之前,否则 SteamCMD 会报错 - const fullCommand = `steamcmd +${forceInstallDir} +${loginCommand} +${appUpdateCommand} +quit` + const fullCommand = `+${forceInstallDir} +${loginCommand} +${appUpdateCommand} +quit` setSteamcmdCommand(fullCommand) } }, [showInstallModal, selectedGame, useAnonymous, steamUsername, steamPassword, validateGameIntegrity, installPath]) @@ -2628,6 +2629,12 @@ const GameDeploymentPage: React.FC = () => { // 打开安装对话框的通用函数 const openInstallModal = async (gameKey: string, gameInfo: GameInfo) => { const defaultInstanceName = gameInfo.game_nameCN + const shouldUseAnonymous = gameInfo.login_anonymous !== false + setUseAnonymous(shouldUseAnonymous) + if (shouldUseAnonymous) { + setSteamUsername('') + setSteamPassword('') + } // 检查是否存在同名实例 try { @@ -5844,18 +5851,18 @@ const GameDeploymentPage: React.FC = () => {