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
+68
View File
@@ -0,0 +1,68 @@
# panel-native Empyrion runtime image.
#
# Empyrion's dedicated server is a Windows-only Unity build, so we bring
# along just enough Wine + Xvfb to host it headlessly. SteamCMD is NOT
# installed here — the panel's generic updater sidecar uses the official
# steamcmd image and writes into our /game volume.
#
# Expected runtime layout inside the container:
# /game — SteamCMD-installed Windows build (panel volume)
# /game/DedicatedServer/DedicatedServer64/
# EmpyrionDedicated.exe — the dedicated server binary
# /game-saves — saves, dedicated.yaml, admin files
# /entrypoint.sh — boot Xvfb, launch exe under Wine
FROM debian:12-slim
ENV DEBIAN_FRONTEND=noninteractive \
TZ=Etc/UTC \
LANG=en_US.UTF-8 \
LC_ALL=en_US.UTF-8 \
WINEDEBUG=-all \
WINEPREFIX=/home/panel/.wine \
DISPLAY=:99
# Wine pulls in ~500 MB of deps; keep to the 64-bit stack (Empyrion's
# dedicated binary is x86_64). winetricks isn't strictly required — the
# game's Mono runtime ships with the install — but it's 8 MB and saves
# future debugging headaches.
RUN dpkg --add-architecture i386 \
&& apt-get update \
&& apt-get install -y --no-install-recommends \
ca-certificates \
locales \
tini \
curl \
xvfb \
xauth \
wine64 \
wine \
winbind \
cabextract \
procps \
&& sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen \
&& locale-gen \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# Unprivileged user owning /game + /game-saves. The SteamCMD sidecar
# writes as root (official image runs as root); we chown once at start
# time so the long-running game process stays non-root.
RUN groupadd -g 1000 panel \
&& useradd -u 1000 -g 1000 -m -s /bin/bash panel \
&& mkdir -p /game /game-saves \
&& chown -R panel:panel /game /game-saves /home/panel
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
# Pre-staged EPM mod (TCP relay for the Eleon Mod API). Entrypoint copies
# this into /game/Content/Mods/EPM/ on first boot so every empyrion
# instance comes EAH-bridge-ready out of the box. See modules/empyrion/epm-mod/.
COPY epm-mod/ /opt/panel-epm/
# Empyrion default ports (see module.yaml comment for reference).
EXPOSE 30000/udp 30001/udp 30002/udp 30003/udp
EXPOSE 30004/tcp
ENTRYPOINT ["/usr/bin/tini", "--", "/entrypoint.sh"]
+35
View File
@@ -0,0 +1,35 @@
# Empyrion - Galactic Survival
Panel-native dedicated server module for Empyrion.
## How it works
- Image: `panel-empyrion:latest` — built from `./Dockerfile` (Debian 12 + Wine + Xvfb + tini).
- Game files: downloaded by the panel's SteamCMD updater sidecar into the `panel-<id>-game` named volume. Because Empyrion's dedicated server ships only as a Windows binary, the updater uses `+@sSteamCmdForcePlatformType windows` (declared in `module.yaml` via `platform: windows`).
- Entrypoint: boots Xvfb, initializes a Wine prefix on first run, then runs `EmpyrionDedicated.exe` under `wine64` with `-batchmode -nographics -logFile -` so Unity pipes its log to stdout.
## First-run flow
1. Build the image (one-time):
```bash
docker build -t panel-empyrion:latest modules/empyrion
```
2. Create an instance in the panel (defaults are fine).
3. Click **Update** on the instance — the SteamCMD sidecar downloads ~3.5 GB of Windows build into the `game` volume.
4. Click **Start** — the entrypoint seeds `dedicated.yaml` from the shipped default, starts Xvfb, bootstraps Wine, and launches the server.
First boot is slow (Wine prefix init + Empyrion's own first-run map generation). Subsequent starts are 3060s.
## Ports
| Name | Proto | Default | Notes |
|--------|-------|---------|-----------------------------|
| game | UDP | 30000 | Srv_Port — main traffic |
| query | UDP | 30001 | Steam query |
| client | UDP | 30002 | Client connect |
| eac | UDP | 30003 | EasyAntiCheat |
| csw | TCP | 30004 | CSW API (internal for now) |
## No RCON (yet)
Empyrion has no native RCON protocol. The in-game `admin` console commands can only be issued from a connected client. Third-party tools (Empyrion Web Admin / EAH) fill this gap and can be layered on later via plugins — not wired into this module for v1.
+220
View File
@@ -0,0 +1,220 @@
#!/bin/bash
# panel-native Empyrion entrypoint.
#
# Contract:
# /game — SteamCMD-installed Windows build of Empyrion (volume,
# populated by the panel's SteamCMD updater sidecar).
# If missing, exit with EX_CONFIG and a helpful message.
# /game-saves — dedicated.yaml + Saves/ tree (volume).
#
# Runs as root for its opening stage (fix up ownership after the SteamCMD
# sidecar wrote as root, nuke any stale X lock from a previous crash),
# then drops to the `panel` user for Wine + Xvfb + the game. Wine refuses
# to run as root, so the drop is load-bearing.
#
# On every start we verify the binary is there, start Xvfb, boot a minimal
# Wine prefix if needed, then exec EmpyrionDedicated.exe under Wine with
# stdout/stderr line-buffered so docker logs → agent → panel console
# delivers live output.
set -euo pipefail
log() { printf '[panel-empyrion] %s\n' "$*"; }
# ----- stage 1: root-only bootstrap (runs once per container start) -----
if [[ "$(id -u)" = "0" ]]; then
# SteamCMD writes as root in its sidecar; chown once so the panel user
# (UID 1000) can read/write the game dir without fiddling with perms.
chown -R panel:panel /game /game-saves /home/panel 2>/dev/null || true
# Nuke any stale Xvfb state from a previous boot. The container's /tmp
# persists across restarts (same writable layer), so /tmp/.X99-lock plus
# /tmp/.X11-unix/X99 left by a SIGKILL'd Xvfb make the next start die
# with "_XSERVTransMakeAllCOTSServerListeners: server already running".
# Single rm wasn't catching every variant (verified live 2026-04-29);
# nuking the whole dir + re-creating with the right mode is bulletproof.
pkill -9 Xvfb 2>/dev/null || true
rm -rf /tmp/.X11-unix /tmp/.X99-lock 2>/dev/null || true
mkdir -p /tmp/.X11-unix && chmod 1777 /tmp/.X11-unix && chown root:root /tmp/.X11-unix 2>/dev/null || true
# Empyrion writes build-stamped logs to Z:\Logs\<buildnum> (= /Logs/...
# because Wine maps Z:\ to /). Without this symlink panel gets an
# UnauthorizedAccessException on first boot. Pointing it into the save
# volume keeps logs persistent + visible in the Files tab.
mkdir -p /game-saves/EmpyrionLogs
chown -R panel:panel /game-saves/EmpyrionLogs
if [[ ! -e /Logs || -L /Logs ]]; then
ln -sfn /game-saves/EmpyrionLogs /Logs
fi
# Re-exec as `panel` user. setpriv comes with util-linux in debian-slim.
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 \
WINEPREFIX=/home/panel/.wine \
WINEDEBUG=-all \
SRV_PORT="${SRV_PORT:-30000}" \
EAC_PORT="${EAC_PORT:-30003}" \
CSW_PORT="${CSW_PORT:-30004}" \
EAH_API_PORT="${EAH_API_PORT:-30007}" \
SCENARIO="${SCENARIO:-}" \
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin \
/entrypoint.sh "$@"
fi
GAME_DIR=/game
SAVE_DIR=/game-saves
DEDI_DIR="${GAME_DIR}/DedicatedServer"
DEDI_EXE="${DEDI_DIR}/EmpyrionDedicated.exe"
CONFIG="${SAVE_DIR}/dedicated.yaml"
# Empyrion ships its default dedicated.yaml at the game root.
SHIPPED_CONFIG="${GAME_DIR}/dedicated.yaml"
# --- sanity: Windows build installed? ---
if [[ ! -f "${DEDI_EXE}" ]]; then
log "ERROR: ${DEDI_EXE} not found."
log " Game files haven't been downloaded yet."
log " Run 'Update' on this server in the panel — that launches a"
log " SteamCMD sidecar which installs Empyrion (Windows build) into"
log " this volume via +@sSteamCmdForcePlatformType windows."
exit 78 # EX_CONFIG
fi
# --- dedicated.yaml: copy shipped default on first run ---
if [[ ! -s "${CONFIG}" && -s "${SHIPPED_CONFIG}" ]]; then
log "no panel config found — seeding ${CONFIG} from ${SHIPPED_CONFIG}"
cp -f "${SHIPPED_CONFIG}" "${CONFIG}"
fi
if [[ ! -s "${CONFIG}" ]]; then
log "WARN: no dedicated.yaml found in game install. Empyrion will create"
log " one with defaults on first boot. Edit via the Files tab."
fi
# Symlink so the binary finds the config at its expected relative path.
# Empyrion reads dedicated.yaml from the game root (same dir as the .exe's
# -dedicated argument resolves).
ln -sf "${CONFIG}" "${GAME_DIR}/dedicated.yaml"
# --- patch dedicated.yaml ports from env on every boot ---
# Empyrion reads Srv_Port / EAC_Port / Tel_Port from dedicated.yaml. Without
# this, multiple instances on the same agent all bind 30000-30004 and only
# one is reachable. SRV_PORT comes from the panel allocator via the
# manifest's port→env mapping (`env: SRV_PORT` in module.yaml). yaml is
# whitespace-sensitive but these keys are a flat top-level "Key: NNN" so
# sed is safe.
if [[ -s "${CONFIG}" ]]; then
log "patching dedicated.yaml (Srv_Port=${SRV_PORT}, EAC_Port=${EAC_PORT})"
sed -i -E \
-e "s|^([[:space:]]*Srv_Port:[[:space:]]*)[0-9]+|\1${SRV_PORT}|" \
-e "s|^([[:space:]]*EAC_Port:[[:space:]]*)[0-9]+|\1${EAC_PORT}|" \
"${CONFIG}"
fi
# --- scenario selection ---
# SCENARIO env names a folder under /game/Content/Scenarios/. The empyrion-
# shipped default is "Default Random". Reforged Eden / Reforged Eden 2 /
# Project Eden need to be present in /game/Content/Scenarios/<name>/ first
# (drop via the panel's Files tab, or future workshop-subscribe feature).
# This block keeps dedicated.yaml's CustomScenario in sync with the env.
SCENARIO="${SCENARIO:-}"
if [[ -n "${SCENARIO}" && -s "${CONFIG}" ]]; then
if [[ ! -d "${GAME_DIR}/Content/Scenarios/${SCENARIO}" ]]; then
log "WARN: scenario folder '${SCENARIO}' not found at ${GAME_DIR}/Content/Scenarios/${SCENARIO}"
log " The panel UI Files tab can drop scenario contents there. For"
log " Reforged Eden 2 (Workshop ID 3041847672), unzip into:"
log " /game/Content/Scenarios/Reforged Eden 2/"
log " Booting with Default for now."
else
log "selecting scenario: ${SCENARIO}"
if grep -qE '^[[:space:]]*CustomScenario:' "${CONFIG}"; then
sed -i -E "s|^([[:space:]]*CustomScenario:[[:space:]]*).*|\1${SCENARIO}|" "${CONFIG}"
else
# Insert under GameConfig: at the top, ahead of dedicated game block.
printf '\nGameConfig:\n CustomScenario: %s\n' "${SCENARIO}" >> "${CONFIG}"
fi
fi
fi
# --- stage EPM mod (TCP relay for Eleon Mod API) on first boot ---
# Pre-staged at /opt/panel-epm in the image. Copy into the live game
# Content/Mods/EPM/ if it isn't there yet. This makes the panel-empyrion-
# bridge sidecar work out-of-the-box: every new empyrion instance comes
# with EPM listening on EAH_API_PORT.
EPM_SRC=/opt/panel-epm
EPM_DST="${GAME_DIR}/Content/Mods/EPM"
if [[ -d "${EPM_SRC}" && ! -f "${EPM_DST}/EmpyrionNetworkRelayMod.dll" ]]; then
log "staging EPM mod into ${EPM_DST}"
mkdir -p "${EPM_DST}"
cp -a "${EPM_SRC}/." "${EPM_DST}/"
# If a panel-allocated EAH_API_PORT is set, patch EPM's Settings.yaml
# so its TCP listener binds the right port for this instance.
if [[ -n "${EAH_API_PORT:-}" && -f "${EPM_DST}/Settings.yaml" ]]; then
sed -i -E "s|^GameServerApiPort:[[:space:]]*[0-9]+|GameServerApiPort: ${EAH_API_PORT}|" \
"${EPM_DST}/Settings.yaml"
fi
fi
# Re-patch port even if EPM was already staged, in case panel reallocated.
if [[ -f "${EPM_DST}/Settings.yaml" && -n "${EAH_API_PORT:-}" ]]; then
sed -i -E "s|^GameServerApiPort:[[:space:]]*[0-9]+|GameServerApiPort: ${EAH_API_PORT}|" \
"${EPM_DST}/Settings.yaml"
fi
# --- prep saves dir (Empyrion writes under /game/Saves by default) ---
# Redirect Saves into the save volume via a symlink so steam validate
# can't clobber world data.
mkdir -p "${SAVE_DIR}/Saves"
if [[ -d "${GAME_DIR}/Saves" && ! -L "${GAME_DIR}/Saves" ]]; then
# Steam shipped an empty Saves dir; replace with symlink.
rm -rf "${GAME_DIR}/Saves"
fi
ln -sfn "${SAVE_DIR}/Saves" "${GAME_DIR}/Saves"
# --- Wine + Xvfb via xvfb-run (auto-allocates a free display) ---
#
# We previously hand-started Xvfb on :99. That broke once the host had
# its OWN Xvfb on :99 — the empyrion container uses network_mode: host,
# which shares the network namespace, and X server abstract Unix sockets
# (`@/tmp/.X11-unix/X99`) are namespaced by network ns. Result: container
# Xvfb fails with "_XSERVTransMakeAllCOTSServerListeners: server already
# running" and Wine then dies "Authorization required, but no auth
# protocol specified" → Unity exits "Failed to create batch mode window:
# Success." (verified 2026-04-29).
#
# `xvfb-run -a` finds a free display number, starts Xvfb with proper
# xauth set up, exports DISPLAY to its child, and cleans up on exit.
# Bulletproof against host's existing Xvfb instances.
# --- Wine prefix bootstrap (first boot only). xvfb-run handles the X
# server for the actual run; for prefix init we don't strictly need
# X but wineboot complains less when one is available. ---
if [[ ! -d "${WINEPREFIX}" || ! -f "${WINEPREFIX}/system.reg" ]]; then
log "initializing Wine prefix at ${WINEPREFIX}"
xvfb-run -a wineboot --init 2>&1 | sed 's/^/ /' || true
wineserver -w || true
fi
# --- go ---
cd "${GAME_DIR}"
log "starting Empyrion Dedicated Server"
log " game dir: ${GAME_DIR}"
log " save dir: ${SAVE_DIR}"
log " config: ${CONFIG}"
log " binary: ${DEDI_EXE}"
# Shutdown handler: forward SIGTERM (xvfb-run forwards to wine; wine's
# Unity hook persists state on quit).
trap 'log "SIGTERM received; stopping server"; wineserver -k 2>/dev/null || true; exit 0' TERM INT
# -batchmode / -nographics make Unity skip the renderer; -logFile - pipes
# the Unity log to our stdout so the panel console sees everything.
# `xvfb-run -a` picks a free display, sets up xauth, and exports DISPLAY.
# `--server-args="-screen 0 1024x768x24"` matches our previous Xvfb args.
exec stdbuf -oL -eL xvfb-run -a --server-args="-screen 0 1024x768x24" \
wine "${DEDI_EXE}" \
-batchmode \
-nographics \
-logFile - \
-dedicated dedicated.yaml \
-startDedicated
@@ -0,0 +1,8 @@
# Empyrion mod manifest. Tells Empyrion to load this mod into the dedicated
# server process (Game_Start hook), where it opens a TCP listener on the
# port configured in Settings.yaml — 7028 in our case (panel-allocated).
Name: EPM
Description: Empyrion Network Relay - exposes Mod API over TCP for panel/EAH/etc
Author: W3DG (open-source via MichaelGoulding/sample-empyrion-mod)
Version: 1.0
ModTargets: Dedi
+43
View File
@@ -0,0 +1,43 @@
# EPM mod artifacts
Drop-in `Content/Mods/EPM/` for Empyrion. Loaded by the dedicated server's
mod loader; opens a TCP listener on `Settings.yaml.GameServerApiPort` (we
ship `0.0.0.0:7028`, panel-allocated to whatever `EAH_API_PORT` env says).
## Files
- `EmpyrionNetworkRelayMod.dll` — the mod (`ModTargets: Dedi`). Compiled
from `EmpyrionNetworkConnectedMods/sample-empyrion-mod/Empyrion Mod/`
with one tweak: `Configuration.cs` was rewritten to manually parse
`Settings.yaml` (key: value lines) instead of using `YamlDotNet`. Reason:
current Empyrion 1.16.x ships `YamlAssembly.dll` rather than the old
`Assembly-CSharp-firstpass.dll` that bundled `YamlDotNet`, so the
upstream binary fails with `TypeLoadException` at `Game_Start`.
- `EPMConnector.dll` — wire protocol library (TCP framing + protobuf-net
message dispatch). Linked by both EPM and any C# client.
- `EmpyrionNetworkRelayMod_Info.yaml` — manifest. Per-DLL naming is
required because there are two DLLs in the folder; with a single DLL,
`Info.yaml` works, but with multiple Empyrion's loader needs each main
DLL to have a sibling `<DllName>_Info.yaml`.
- `Settings.yaml` — host+port for the TCP listener. `0.0.0.0` is fine
inside the container (host networking limits exposure to the container
port; opnfwd handles WAN forwarding).
## Verified end-to-end on 2026-04-30
1. EPM loads under Wine: `Loaded Mod 'EmpyrionNetworkRelayMod': "EPM"`.
2. TCP listener opens: `Now listening on port 7028`.
3. C# probe (`/eah_probe/probe/Probe.cs`) connects via `EPMConnector.Client`
and gets typed protobuf-net responses for `Request_Get_Factions`,
`Request_Player_List`, `Request_Playfield_List`. Default Human
faction came back deserialized into `Eleon.Modding.FactionInfoList`.
## How to rebuild
1. Open `C:\Users\dbledeez\AppData\Local\Temp\eah_probe\EmpyrionNetworkConnectedMods\sample-empyrion-mod\Empyrion Mod\` (or re-clone from `MichaelGoulding/EmpyrionNetworkConnectedMods`).
2. Replace `Configuration.cs` with the YAML-free version (see
`feedback_empyrion_yaml_dotnet_drop.md` for the snippet).
3. `cd` to that folder and `csc.exe @build.rsp`. Output goes to
`bin\Release\EmpyrionNetworkRelayMod.dll`.
4. Copy `EmpyrionNetworkRelayMod.dll` + `EPMConnector.dll` + the two yamls
into this directory; commit.
+3
View File
@@ -0,0 +1,3 @@
---
GameServerIp: "0.0.0.0"
GameServerApiPort: 7028
+152
View File
@@ -0,0 +1,152 @@
# Empyrion — Galactic Survival dedicated server module.
#
# Same panel-native pattern as 7dtd: a minimal image we own
# (panel-empyrion:latest, Debian 12 + Wine + tini), with game files
# populated by the generic SteamCMD updater sidecar into a named volume.
#
# Empyrion's dedicated server is shipped as a Windows binary only, so the
# updater is told to pretend SteamCMD is running on Windows
# (`platform: windows` → +@sSteamCmdForcePlatformType windows), and the
# entrypoint runs the exe under Wine under Xvfb (Unity server still touches
# X even in -batchmode).
#
# First-run flow:
# - Create instance → container spec + empty volumes
# - Click "Update" → SteamCMD downloads ~3.5 GB Windows build
# - Click "Start" → entrypoint boots Wine + EmpyrionDedicated.exe
#
# Notes for operators:
# - The game server ports must be UDP; Empyrion uses a handful of them.
# - Main config file is dedicated.yaml, lives under /game-saves after
# first boot (entrypoint copies the shipped default on first run).
# - No in-game RCON: Empyrion's admin console is in-process only. The
# "Empyrion Web Admin" (EWA) third-party tool can be layered on top
# later via a plugin; not wired for v1.
id: empyrion
name: "Empyrion - Galactic Survival"
version: 0.1.0
authors:
- panel contributors
supported_modes:
- docker
runtime:
docker:
# Built locally from ./Dockerfile. Rebuild with:
# docker build -t panel-empyrion:latest modules/empyrion
image: panel-empyrion:latest
# Host networking -- container shares the host net namespace, so
# any port the game/mod binds is directly on the LAN. AMP-like
# model. Multi-instance safety comes from env-driven per-instance
# ports (panel allocator + env: mapping on each ports entry).
network_mode: host
browseable_root: /game-saves
browseable_roots:
- name: "Saves & Configs"
path: /game-saves
hint: "Saves/, dedicated.yaml, admin files"
- name: "Game Files"
path: /game
hint: "Binaries, Content/, Mods/ — drop mod folders here"
# Pre-declare the port env keys so the agent's resolve filter lets the
# panel-allocated values flow through to the container env (resolve.go
# only overrides keys already present in docker.env). Defaults match
# the manifest port defaults below; agent overrides at create time.
env:
SRV_PORT: "30000"
QUERY_PORT: "30001"
CLIENT_PORT: "30002"
EAC_PORT: "30003"
CSW_PORT: "30004"
EAH_API_PORT: "30007" # Empyrion's Mod API TCP port (used by EAH/EPM and our future bridge)
# SCENARIO is declared empty here so the agent's resolver passes the
# config_values.SCENARIO override into the container env. Without
# this pre-declaration, resolve.go would silently drop the value
# (it only overrides keys already in docker.env), the entrypoint
# would see SCENARIO="" and skip the dedicated.yaml patch, and
# Empyrion would fall back to "Default Multiplayer" no matter what
# the operator picked in the dropdown.
SCENARIO: ""
volumes:
- { type: volume, name: "panel-$INSTANCE_ID-saves", container: "/game-saves" }
- { type: volume, name: "panel-$INSTANCE_ID-game", container: "/game" }
- { target: "$DATA_PATH/logs", container: "/game-saves/logs" }
# Empyrion port reference:
# Srv_Port (UDP) — main game traffic default 30000
# Srv_Port+1 (UDP) — Steam query default 30001
# Srv_Port+2 (UDP) — client connect default 30002
# EAC_Port (UDP) — EasyAntiCheat default 30003
# CSWApi_Port (TCP) — CSW API (remote admin) default 30004 (internal)
ports:
- { name: game, proto: udp, default: 30000, required: true, env: SRV_PORT }
- { name: query, proto: udp, default: 30001, required: true, env: QUERY_PORT } # Empyrion derives query from Srv_Port + 1; we still allocate it for tracking
- { name: client, proto: udp, default: 30002, required: true, env: CLIENT_PORT } # Srv_Port + 2 by convention
- { name: eac, proto: udp, default: 30003, required: true, env: EAC_PORT }
- { name: csw, proto: tcp, default: 30004, internal: true, env: CSW_PORT }
# Empyrion's native Mod API TCP port. EPM mod listens on this; EAH GUI
# and our future panel-empyrion-bridge will connect here. Public so
# remote EAH GUIs work; auth model not yet validated, see
# panel/memory/research_eah_integration.md before exposing externally.
- { name: eah-api, proto: tcp, default: 30007, required: true, env: EAH_API_PORT }
resources:
min_ram_mb: 4096
recommended_ram_mb: 8192
# Operator-tunable knobs. Panel renders these as a config form; the entrypoint
# reads them from env on every boot.
config_values:
- key: SCENARIO
label: "Scenario"
description: "Folder name under Content/Scenarios/. Leave blank for game default. Reforged Eden 2 needs the workshop content (ID 3041847672) dropped into Content/Scenarios/Reforged Eden 2/ first — use the Files tab."
default: ""
options:
- { value: "", label: "Default Random (vanilla)" }
- { value: "Reforged Eden 2", label: "Reforged Eden 2 (workshop)" }
- { value: "Reforged Eden", label: "Reforged Eden (legacy)" }
- { value: "Default Akua", label: "Default Akua (vanilla)" }
- { value: "Default Multiplayer Survival", label: "Default Multiplayer Survival" }
- key: EAH_API_PORT
label: "EAH/Mod API port"
description: "TCP port the EPM mod listens on for the panel-empyrion-bridge sidecar. Auto-allocated by panel; rarely needs manual override."
default: ""
advanced: true
# Log-derived player events. Regexes converted from CubeCoders'
# AMPTemplates (empyrion-galactic-survival.kvp) — .NET (?<n>) syntax -> Go (?P<n>).
# Sourced-from-template; not yet exercised against a live client.
events:
join:
pattern: '-LOG-.*Player (?P<id>.+?)/''(?P<name>[^'']+)'' login ok'
kind: join
leave:
pattern: '-LOG-.*, (?P<id>.+?)/=/''(?P<name>[^'']+)'' disconnected$'
kind: leave
update_providers:
- id: stable
kind: steamcmd
app_id: "530870"
platform: windows # force Windows depot on Linux hosts — server is Windows-only
install_path: /game
- id: experimental
kind: steamcmd
app_id: "530870"
beta: experimental
platform: windows
install_path: /game
# --- Manifest-driven UI metadata (WI-07) --------------------------
# Consumed by the CONTROLLER/dashboard only (the controller loads its
# own ./modules copy at startup); the agent ignores these at runtime.
# ready_pattern is a JavaScript regex (slash-delimited when it needs
# flags) moved verbatim from the dashboard's READY_PATTERNS map.
ready_pattern: '/Server started listening on port|Dedi is ready|Ready for connections/i'
appearance:
emoji: "🚀"
grad: "linear-gradient(135deg,#0b2545,#5c7cfa)"
art: "/game-art/empyrion.jpg"
steam: "383120"