#!/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