panel v0.9.2 — public release

Self-hostable game server control panel: Go controller + agent, 26 game
modules, embedded web UI. One-line install via install.sh / install.ps1.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-15 00:43:35 -07:00
commit 4ccccc6fe2
2164 changed files with 301480 additions and 0 deletions
+102
View File
@@ -0,0 +1,102 @@
#!/bin/bash
# panel-native Soulmask entrypoint.
set -euo pipefail
log() { printf '[panel-soulmask] %s\n' "$*"; }
if [[ "$(id -u)" = "0" ]]; then
chown -R panel:panel /game /game-saves /home/panel 2>/dev/null || true
exec setpriv --reuid=panel --regid=panel --clear-groups \
--inh-caps=-all --bounding-set=-all \
env HOME=/game-saves PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin \
SERVER_NAME="${SERVER_NAME:-panel Soulmask}" \
MAX_PLAYERS="${MAX_PLAYERS:-30}" \
ADMIN_PASSWORD="${ADMIN_PASSWORD:-changeme}" \
GAME_PORT="${GAME_PORT:-8777}" \
QUERY_PORT="${QUERY_PORT:-27015}" \
GAME_MODE="${GAME_MODE:-pve}" \
SERVER_PASSWORD="${SERVER_PASSWORD:-}" \
SAVING="${SAVING:-600}" \
BACKUP="${BACKUP:-900}" \
/entrypoint.sh "$@"
fi
GAME_DIR=/game
SAVE_DIR=/game-saves
EXE="${GAME_DIR}/WS/Binaries/Linux/WSServer-Linux-Shipping"
# Official launcher shipped inside app 3017300. It sets LD_LIBRARY_PATH to
# ./linux64 and passes the required leading "WS" project token before our
# args — WITHOUT it the engine inits then immediately EngineExit()s. Always
# launch through this wrapper, never exec the ELF directly.
SH="${GAME_DIR}/WSServer.sh"
if [[ ! -x "${EXE}" ]]; then
log "ERROR: Soulmask server binary not found at ${EXE}."
log " Run Update (SteamCMD app 3017300 — the native Linux server)."
exit 78
fi
# Saves live under WS/Saved — redirect into the save volume.
mkdir -p "${SAVE_DIR}/WS/Saved"
if [[ -d "${GAME_DIR}/WS/Saved" && ! -L "${GAME_DIR}/WS/Saved" ]]; then
if [[ ! -d "${SAVE_DIR}/WS/Saved" || -z "$(ls -A "${SAVE_DIR}/WS/Saved" 2>/dev/null)" ]]; then
cp -a "${GAME_DIR}/WS/Saved/." "${SAVE_DIR}/WS/Saved/" 2>/dev/null || true
fi
rm -rf "${GAME_DIR}/WS/Saved"
fi
ln -sfn "${SAVE_DIR}/WS/Saved" "${GAME_DIR}/WS/Saved"
# Deep gameplay settings: the panel renders GameXishu.json from config_values
# and bind-mounts it at /game-saves/GameXishu.json.rendered (read-only). Copy
# it into the path the server reads on boot. Confirmed load line:
# logGameXishu: UHGameXiShuGuanLiQi::LoadFromJsonFile File:.../WS/Saved/GameplaySettings/GameXishu.json Success.
RENDERED="${SAVE_DIR}/GameXishu.json.rendered"
if [[ -f "${RENDERED}" ]]; then
mkdir -p "${SAVE_DIR}/WS/Saved/GameplaySettings"
cp -f "${RENDERED}" "${SAVE_DIR}/WS/Saved/GameplaySettings/GameXishu.json"
log "applied rendered GameXishu.json (deep gameplay settings)"
else
log "no rendered GameXishu.json — server will use built-in defaults"
fi
cd "${GAME_DIR}"
GAME_PORT="${GAME_PORT:-8777}"
QUERY_PORT="${QUERY_PORT:-27015}"
GAME_MODE="${GAME_MODE:-pve}"
# Normalize game mode to the launch flag the server expects (-pve / -pvp).
case "${GAME_MODE,,}" in
pvp) MODE_FLAG="-pvp" ;;
*) MODE_FLAG="-pve" ;;
esac
# Optional join password (-PSW). Admin password is -adminpsw (NOT -PSW — an
# earlier version passed the admin pw as -PSW, which set the JOIN password to
# the admin secret and left admin unset).
PSW_ARG=()
if [[ -n "${SERVER_PASSWORD:-}" ]]; then
PSW_ARG=(-PSW="${SERVER_PASSWORD}")
fi
log "starting Soulmask dedicated server"
log " name: ${SERVER_NAME}"
log " slots: ${MAX_PLAYERS}"
log " ports: game=${GAME_PORT} query=${QUERY_PORT}"
log " mode: ${MODE_FLAG} save=${SAVING:-600}s backup=${BACKUP:-900}s"
# Launch through WSServer.sh (handles LD_LIBRARY_PATH + the leading "WS"
# token). -Port/-QueryPort honor panel-allocated ports; -adminpsw sets admin;
# -PSW (optional) sets the join password; -pve/-pvp + -saving/-backup are the
# server-level knobs. Confirmed boot: world up, match state WaitingToStart.
# IMPORTANT: server name + max players MUST be passed as the -SteamServerName
# and -MaxPlayers FLAGS, not as ?ServerName=?MaxPlayers= URL options on the
# level string. The URL-option form is silently ignored for Steam registration
# — the server registered as "UNNAMED_SERVER" / 0/20 slots. This flag format
# matches the proven jsknnr/soulmask-dedicated-server image. The level is bare
# (no ?listen? / ?ServerName= options); -server -online=Steam -forcepassthrough
# are required for correct dedicated-server + Steam behaviour.
exec stdbuf -oL -eL "${SH}" \
Level01_Main -server -SILENT \
-SteamServerName="${SERVER_NAME}" -MaxPlayers="${MAX_PLAYERS}" \
"${MODE_FLAG}" -saving="${SAVING:-600}" -backup="${BACKUP:-900}" \
-MULTIHOME=0.0.0.0 -Port="${GAME_PORT}" -QueryPort="${QUERY_PORT}" \
-online=Steam -forcepassthrough \
-adminpsw="${ADMIN_PASSWORD}" "${PSW_ARG[@]}" \
-log -UTF8Output -useperfthreads -NoAsyncLoadingThread