From fdbe009a6fa480b35a7067b22df950bc2a9df28f Mon Sep 17 00:00:00 2001 From: Linkjie <52249559+Linkjie-11@users.noreply.github.com> Date: Fri, 23 Feb 2024 14:56:33 +0800 Subject: [PATCH] App/palworld server tool (#914) * Add my-app * Add my-app --- palworld-server-tool/README.md | 25 ++++++++++ palworld-server-tool/data.yml | 19 ++++++++ palworld-server-tool/latest/data.yml | 45 ++++++++++++++++++ .../latest/docker-compose.yml | 25 ++++++++++ palworld-server-tool/logo.png | Bin 0 -> 10797 bytes 5 files changed, 114 insertions(+) create mode 100644 palworld-server-tool/README.md create mode 100644 palworld-server-tool/data.yml create mode 100644 palworld-server-tool/latest/data.yml create mode 100644 palworld-server-tool/latest/docker-compose.yml create mode 100644 palworld-server-tool/logo.png diff --git a/palworld-server-tool/README.md b/palworld-server-tool/README.md new file mode 100644 index 00000000..250571df --- /dev/null +++ b/palworld-server-tool/README.md @@ -0,0 +1,25 @@ +幻兽帕鲁服务器管理工具 + +通过可视化界面及 REST 接口管理幻兽帕鲁专用服务器,基于 SAV 存档文件解析及 RCON 实现 +基于 Level.sav 存档文件解析实现的功能及路线图: + 完整玩家数据 + 玩家帕鲁数据 + 公会数据 +基于官方提供的 RCON 命令(仅服务器可用的)实现功能: + 获取服务器信息 + 在线玩家列表 + 踢出/封禁玩家 + 游戏内广播 + 平滑关闭服务器并广播消息 +本工具使用 bbolt 单文件存储,将 RCON 和 Level.sav 文件的数据通过定时任务获取并保存,提供简单的可视化界面和 REST 接口和便于管理与开发。 + +请确保前提 开启私服 RCON + +解析 Level.sav 存档的任务需要在短时间(<20s)耗费一定的系统内存(1GB~3GB),这部分内存会在执行完解析任务后释放,因此你至少需要确保你的服务器有充足的内存。若不满足可使用如下等方式 + +这里默认为将 pst 工具和游戏服务器放在同一台物理机上,在一些情况下你可能不想要它们部署在同一机器上: + +需要单独部署在其它服务器 +只需要部署在本地个人电脑 +游戏服务器性能较弱不满足,采用上述两种方案之一 +请参考 https://github.com/zaigie/palworld-server-tool/blob/main/README.agent.md 部署教程 \ No newline at end of file diff --git a/palworld-server-tool/data.yml b/palworld-server-tool/data.yml new file mode 100644 index 00000000..b7e9be06 --- /dev/null +++ b/palworld-server-tool/data.yml @@ -0,0 +1,19 @@ +name: pal-server-tool +tags: + - 休闲游戏 +title: 幻兽帕鲁服务可视化管理工具 +type: 休闲游戏 +additionalProperties: + key: palworld-server-tool + name: palworld-server-tool + tags: + - Game + shortDescZh: 幻兽帕鲁服务可视化管理工具 + shortDescEn: palworld-server-tool + type: tool + crossVersionUpdate: true + limit: 0 + recommend: 0 + website: https://github.com/zaigie/palworld-server-tool + github: https://github.com/zaigie/palworld-server-tool + document: https://github.com/zaigie/palworld-server-tool \ No newline at end of file diff --git a/palworld-server-tool/latest/data.yml b/palworld-server-tool/latest/data.yml new file mode 100644 index 00000000..0a6e284a --- /dev/null +++ b/palworld-server-tool/latest/data.yml @@ -0,0 +1,45 @@ +additionalProperties: + formFields: + - default: '8080' + edit: true + envKey: PANEL_APP_PORT_HTTP + labelEn: Port + labelZh: 端口 + required: true + rule: paramPort + type: number + - default: '127.0.0.1:25575' + edit: true + envKey: RCON_ADDRESS + labelEn: RCON Address + labelZh: RCON地址 + required: true + type: text + - default: 'RCON_PASSWORD' + edit: true + envKey: RCON_PASSWORD + labelEn: RCON Password + labelZh: RCON密码 + required: true + type: text + - default: 'WEB_PASSWORD' + edit: true + envKey: WEB_PASSWORD + labelEn: WEB Password + labelZh: WEB密码 + required: true + type: text + - default: '600' + edit: true + envKey: SAVE_SYNC_INTERVAL + labelEn: Save Sync Interval + labelZh: 存档同步间隔 + required: true + type: number + - default: '示例:./Pal/Saved/SaveGames/0/5633F58B91BB4CFDAE555321CA7E6C8E' + edit: true + envKey: PANEL_APP_path + labelEn: Save Path + labelZh: 存档路径 + required: true + type: text \ No newline at end of file diff --git a/palworld-server-tool/latest/docker-compose.yml b/palworld-server-tool/latest/docker-compose.yml new file mode 100644 index 00000000..cc4fe8d0 --- /dev/null +++ b/palworld-server-tool/latest/docker-compose.yml @@ -0,0 +1,25 @@ +version: '3' +services: + pst: + image: jokerwho/palworld-server-tool:latest + container_name: ${CONTAINER_NAME} + restart: always + networks: + - 1panel-network + ports: + - "${PANEL_APP_PORT_HTTP}:8080" + volumes: + - "${PANEL_APP_path}:/game" + environment: + - "WEB__PASSWORD=${WEB_PASSWORD}" + - "RCON__ADDRESS=${RCON_ADDRESS}" + - "RCON__PASSWORD=${RCON_PASSWORD}" + - "SAVE__PATH=${SAVE_PATH}" + - "SAVE__SYNC_INTERVAL=${SAVE_SYNC_INTERVAL}" + - SAVE__DECODE_PATH=/app/sav_cli + - SAVE__PATH=/game/Level.sav + labels: + createdBy: "Apps" +networks: + 1panel-network: + external: true \ No newline at end of file diff --git a/palworld-server-tool/logo.png b/palworld-server-tool/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..966c228fde494c0691ea3e344b183c9f9043aeb6 GIT binary patch literal 10797 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 literal 0 KcmV+b0RR6000031