#!/bin/bash
# panel-native Rust entrypoint.
#
# Contract:
#   /game       — SteamCMD-installed Rust Dedicated Server (app 258550).
#                 Populated by the panel's SteamCMD updater sidecar.
#   /game-saves — world/save data + logs volume.
#
# Stage 1 runs as root: chown volumes, symlink server/<identity> into the
# save volume, then drop to the `panel` user via setpriv.

set -euo pipefail

log() { printf '[panel-rust] %s\n' "$*"; }

# ----- stage 1: root-only bootstrap -----
if [[ "$(id -u)" = "0" ]]; then
  chown -R panel:panel /game /game-saves /home/panel 2>/dev/null || true

  log "dropping privileges to panel (UID 1000)"
  exec setpriv --reuid=panel --regid=panel --clear-groups \
       --inh-caps=-all --bounding-set=-all \
       env \
         HOME=/home/panel \
         SERVER_NAME="${SERVER_NAME:-panel Rust}" \
         SERVER_DESCRIPTION="${SERVER_DESCRIPTION:-Powered by panel}" \
         SERVER_IDENTITY="${SERVER_IDENTITY:-panel-rust}" \
         SERVER_SEED="${SERVER_SEED:-12345}" \
         SERVER_WORLD_SIZE="${SERVER_WORLD_SIZE:-3000}" \
         MAX_PLAYERS="${MAX_PLAYERS:-50}" \
         RCON_PASSWORD="${RCON_PASSWORD:-panel_rcon}" \
         SERVER_URL="${SERVER_URL:-}" \
         SERVER_HEADER_IMAGE="${SERVER_HEADER_IMAGE:-}" \
         SERVER_LEVEL="${SERVER_LEVEL:-Procedural Map}" \
         GAME_PORT="${GAME_PORT:-28015}" \
         RCON_PORT="${RCON_PORT:-28016}" \
         RUSTPLUS_PORT="${RUSTPLUS_PORT:-28082}" \
         LD_LIBRARY_PATH="/game:/game/RustDedicated_Data/Plugins:/game/RustDedicated_Data/Plugins/x86_64:${LD_LIBRARY_PATH:-}" \
         PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin \
       /entrypoint.sh "$@"
fi

GAME_DIR=/game
SAVE_DIR=/game-saves
DEDI_EXE="${GAME_DIR}/RustDedicated"

if [[ ! -x "${DEDI_EXE}" ]]; then
  log "ERROR: ${DEDI_EXE} not found or not executable."
  log "       Run 'Update' on this server in the panel — that launches a"
  log "       SteamCMD sidecar which installs Rust (app 258550) here."
  exit 78   # EX_CONFIG
fi

# --- persist server/<identity>/ into the save volume ---
# RustDedicated writes its world + save + cfg tree to <game>/server/<identity>.
# First boot moves it to /game-saves + symlinks back, so SteamCMD validate
# can't clobber world data. Idempotent on re-boot.
mkdir -p "${SAVE_DIR}/server"
if [[ -d "${GAME_DIR}/server" && ! -L "${GAME_DIR}/server" ]]; then
  # On fresh install this dir doesn't exist; server creates it on first boot.
  # If it does exist (e.g. from an earlier panel image without the symlink),
  # migrate and replace.
  if [[ ! -d "${SAVE_DIR}/server/${SERVER_IDENTITY}" ]]; then
    mv "${GAME_DIR}/server"/* "${SAVE_DIR}/server/" 2>/dev/null || true
  fi
  rm -rf "${GAME_DIR}/server"
fi
ln -sfn "${SAVE_DIR}/server" "${GAME_DIR}/server"

# Mirror logs to the bind-mounted logs dir for external access.
mkdir -p "${SAVE_DIR}/logs"

cd "${GAME_DIR}"
log "starting Rust Dedicated Server"
log "  name:      ${SERVER_NAME}"
log "  identity:  ${SERVER_IDENTITY}"
log "  level:     ${SERVER_LEVEL}"
log "  seed:      ${SERVER_SEED}"
log "  size:      ${SERVER_WORLD_SIZE}"
log "  max:       ${MAX_PLAYERS}"
log "  game port: ${GAME_PORT}/udp"
log "  rcon port: ${RCON_PORT}/tcp (internal, websocket)"
log "  rust+:     ${RUSTPLUS_PORT}/tcp (push, optional)"

trap 'log "SIGTERM received; stopping server"; kill -TERM "${RUST_PID:-0}" 2>/dev/null || true; wait "${RUST_PID:-0}" 2>/dev/null || true; exit 0' TERM INT

# Rust's own flags — all `+` prefixed. `-batchmode` / `-nographics` come
# before the `+` convars. We intentionally omit `-logFile`: Unity defaults
# to stdout when absent, and passing `/dev/stdout` or `-` makes RustDedicated
# fail with "Unable to open log file, exiting." on Linux-container Unity.
exec stdbuf -oL -eL "${DEDI_EXE}" \
    -batchmode \
    -nographics \
    +server.ip 0.0.0.0 \
    +server.port "${GAME_PORT}" \
    +server.tickrate 10 \
    +server.hostname "${SERVER_NAME}" \
    +server.description "${SERVER_DESCRIPTION}" \
    +server.identity "${SERVER_IDENTITY}" \
    +server.level "${SERVER_LEVEL}" \
    +server.seed "${SERVER_SEED}" \
    +server.worldsize "${SERVER_WORLD_SIZE}" \
    +server.maxplayers "${MAX_PLAYERS}" \
    +server.saveinterval 600 \
    +server.url "${SERVER_URL}" \
    +server.headerimage "${SERVER_HEADER_IMAGE}" \
    +rcon.web 1 \
    +rcon.ip 0.0.0.0 \
    +rcon.port "${RCON_PORT}" \
    +rcon.password "${RCON_PASSWORD}" \
    +app.port "${RUSTPLUS_PORT}" &

RUST_PID=$!
wait "${RUST_PID}"
