SCUM 停止/重启/更新以前只有“结束进程”这一条路,插件没有声明任何优雅关闭方式,
平台也没有把停止后重新启动串起来。现在插件声明自己的关闭脚本,run 先执行它,
平台在停止或更新成功后再自动拉起服务。
run:
- lifecycle stop 支持插件声明的 gracefulStop(可执行文件、参数、环境、超时、
fallback=report|terminate);关闭命令超时且声明 report 时任务失败,不再默默杀进程。
- 新增 steam.update 依赖探针:调用 steamcmd +app_info_print 获取公开分支 buildid,
与本地 steamapps/appmanifest_<appid>.acf 的 buildid 比较,输出
installed/latest/update=yes|no|unknown。
platform:
- 新增 POST /api/v1/server-instances/{id}/restart 与 /update。
- restart 派发插件 stop 动作(走优雅关闭),终态成功后入队 start 作业。
- update 派发插件 install 动作;插件在更新前必须先优雅关闭 SCUM,关闭失败直接拒绝
SteamCMD 更新,成功后平台再拉起服务。
- 依赖检查输入带上插件声明的服务器安装根目录,供 steam.update 读取 appmanifest。
plugin (SCUM server plugin 0.1.16):
- bin/scum-stop.cmd:解析已声明的可执行文件路径,定位同路径正在运行的 SCUMServer.exe,
通过本地 RCON 公告并发送关闭命令,等待进程自行退出;不再使用 taskkill。
- bin/scum-rcon.ps1:插件自有的 Source RCON 客户端,从 UE4SS mod config.ini 读取
密码/端口,密钥不离开本机。
- actions/stop.json 声明 gracefulStop;actions/install.json 更新前先执行同一关闭脚本。
platform_web:
- 服务器详情新增“重启”按钮和“SCUM 版本更新”面板;点“检查更新”查询公开分支版本,
只有检测到更新时“更新版本”按钮才会置为可用并高亮,点击后先确认再派发更新任务。
100 lines
4.4 KiB
Batchfile
100 lines
4.4 KiB
Batchfile
@echo off
|
|
setlocal EnableExtensions EnableDelayedExpansion
|
|
|
|
rem Plugin-owned graceful stop for the SCUM dedicated server.
|
|
rem It announces the shutdown to players, asks the running server to shut down
|
|
rem through the local RCON listener (port and password come from the UE4SS mod
|
|
rem config), and waits for SCUMServer.exe to exit on its own. Run only
|
|
rem terminates the process afterwards when the lifecycle action declares that
|
|
rem fallback.
|
|
|
|
if "%SERVER_ROOT%"=="" set "SERVER_ROOT=C:\scumserver"
|
|
set "SERVER_ROOT_WINDOWS=%SERVER_ROOT:/=\%"
|
|
if "%SERVER_EXECUTABLE_REF%"=="" set "SERVER_EXECUTABLE_REF=SCUM\Binaries\Win64\SCUMServer.exe"
|
|
if "%SERVER_INSTALL_DIR%"=="" set "SERVER_INSTALL_DIR=%SERVER_ROOT_WINDOWS%"
|
|
set "SERVER_INSTALL_DIR_WINDOWS=%SERVER_INSTALL_DIR:/=\%"
|
|
set "SCUM_RCON_PORT_ARG="
|
|
if not "%SERVER_STOP_RCON_PORT%"=="" set "SCUM_RCON_PORT_ARG=-Port %SERVER_STOP_RCON_PORT%"
|
|
if "%SERVER_STOP_SHUTDOWN_COMMAND%"=="" set "SERVER_STOP_SHUTDOWN_COMMAND=Quit"
|
|
if "%SERVER_STOP_ANNOUNCE%"=="" set "SERVER_STOP_ANNOUNCE=Server shutdown requested by the operator. Save your progress and disconnect."
|
|
if "%SERVER_STOP_NOTICE_SECONDS%"=="" set "SERVER_STOP_NOTICE_SECONDS=15"
|
|
if "%SERVER_STOP_TIMEOUT_SECONDS%"=="" set "SERVER_STOP_TIMEOUT_SECONDS=120"
|
|
if "%SERVER_STOP_RCON_TIMEOUT_MS%"=="" set "SERVER_STOP_RCON_TIMEOUT_MS=10000"
|
|
|
|
set "SCUM_RCON_SCRIPT=%~dp0scum-rcon.ps1"
|
|
set "SCUM_RCON_CONFIG=%SERVER_INSTALL_DIR_WINDOWS%\ue4ss\Mods\scum_simple_rcon\config.ini"
|
|
if not exist "%SCUM_RCON_CONFIG%" set "SCUM_RCON_CONFIG=%SERVER_ROOT_WINDOWS%\ue4ss\Mods\scum_simple_rcon\config.ini"
|
|
|
|
call :resolve_scum_exe
|
|
call :find_running_scum
|
|
if "%SCUM_RUNNING_PID%"=="" (
|
|
echo [scum-stop] SCUM server is not running; nothing to stop.
|
|
exit /b 0
|
|
)
|
|
|
|
echo [scum-stop] Requesting graceful shutdown of SCUM server pid %SCUM_RUNNING_PID%.
|
|
if not exist "%SCUM_RCON_SCRIPT%" (
|
|
echo [scum-stop] Missing plugin RCON client: %SCUM_RCON_SCRIPT%
|
|
exit /b 3
|
|
)
|
|
if not exist "%SCUM_RCON_CONFIG%" (
|
|
echo [scum-stop] Missing SCUM RCON configuration: %SCUM_RCON_CONFIG%
|
|
exit /b 4
|
|
)
|
|
|
|
if not "%SERVER_STOP_NOTICE_SECONDS%"=="0" (
|
|
call :send_rcon "Announce %SERVER_STOP_ANNOUNCE%"
|
|
if errorlevel 1 echo [scum-stop] Player announcement was not delivered; continuing with the shutdown request.
|
|
timeout /T %SERVER_STOP_NOTICE_SECONDS% /NOBREAK >nul
|
|
)
|
|
|
|
call :send_rcon "%SERVER_STOP_SHUTDOWN_COMMAND%"
|
|
if errorlevel 1 echo [scum-stop] Declared shutdown command was not acknowledged; waiting for the server to exit anyway.
|
|
|
|
call :wait_for_exit
|
|
if not "%SCUM_EXITED%"=="1" (
|
|
echo [scum-stop] SCUM server pid %SCUM_RUNNING_PID% did not exit within %SERVER_STOP_TIMEOUT_SECONDS% seconds of the declared shutdown request.
|
|
exit /b 2
|
|
)
|
|
echo [scum-stop] SCUM server shut down gracefully.
|
|
exit /b 0
|
|
|
|
:send_rcon
|
|
if "%~1"=="" exit /b 1
|
|
powershell -NoProfile -ExecutionPolicy Bypass -File "%SCUM_RCON_SCRIPT%" -ConfigPath "%SCUM_RCON_CONFIG%" %SCUM_RCON_PORT_ARG% -TimeoutMs %SERVER_STOP_RCON_TIMEOUT_MS% -Command "%~1"
|
|
exit /b %ERRORLEVEL%
|
|
|
|
:wait_for_exit
|
|
set "SCUM_EXITED=0"
|
|
set /A SCUM_WAIT_TICKS=%SERVER_STOP_TIMEOUT_SECONDS%*2
|
|
if %SCUM_WAIT_TICKS% LSS 1 set "SCUM_WAIT_TICKS=1"
|
|
for /L %%A in (1,1,%SCUM_WAIT_TICKS%) do (
|
|
call :find_running_scum
|
|
if "!SCUM_RUNNING_PID!"=="" (
|
|
set "SCUM_EXITED=1"
|
|
goto :wait_done
|
|
)
|
|
timeout /T 1 /NOBREAK >nul
|
|
)
|
|
:wait_done
|
|
exit /b 0
|
|
|
|
:find_running_scum
|
|
set "SCUM_RUNNING_PID="
|
|
for /f "usebackq delims=" %%P in (`powershell -NoProfile -ExecutionPolicy Bypass -Command "$target=$env:SCUM_EXE; if (-not $target) { exit 0 }; $full=[IO.Path]::GetFullPath($target); Get-CimInstance Win32_Process -Filter \"name='SCUMServer.exe'\" | Where-Object { $_.ExecutablePath -and ([IO.Path]::GetFullPath($_.ExecutablePath) -ieq $full) } | Select-Object -First 1 -ExpandProperty ProcessId"`) do set "SCUM_RUNNING_PID=%%P"
|
|
exit /b 0
|
|
|
|
:resolve_scum_exe
|
|
set "SCUM_EXE=%SERVER_ROOT_WINDOWS%\%SERVER_EXECUTABLE_REF:/=\%"
|
|
set "SCUM_EXE_MARKER=%SERVER_ROOT_WINDOWS%\.scum-exe-path"
|
|
if exist "%SCUM_EXE_MARKER%" set /p SCUM_EXE=<"%SCUM_EXE_MARKER%"
|
|
if exist "%SCUM_EXE%" exit /b 0
|
|
set "SCUM_EXE=%SERVER_ROOT_WINDOWS%\%SERVER_EXECUTABLE_REF:/=\%"
|
|
if exist "%SCUM_EXE%" exit /b 0
|
|
set "SCUM_EXE=%SERVER_INSTALL_DIR_WINDOWS%\%SERVER_EXECUTABLE_REF:/=\%"
|
|
if exist "%SCUM_EXE%" exit /b 0
|
|
set "SCUM_EXE=%SERVER_ROOT_WINDOWS%\steamcmd\steamapps\common\SCUM Server\%SERVER_EXECUTABLE_REF:/=\%"
|
|
if exist "%SCUM_EXE%" exit /b 0
|
|
set "SCUM_EXE=%SERVER_ROOT_WINDOWS%\SCUM Server\%SERVER_EXECUTABLE_REF:/=\%"
|
|
exit /b 0
|