# VEIN — panel-native dedicated server module. # # Native Linux dedicated server. UE4-class survival game. SteamCMD app # 2131400 (the DEDICATED SERVER app id — distinct from the game app id # 1857950, which the server reports itself as to Steam via SteamAppId). # Anonymous Steam login works. Admin console is stdin-only (no network # RCON), so the panel drives the console via the stdio adapter — same # model as Enshrouded / Sons of the Forest. # # Reference: https://github.com/CubeCoders/AMPTemplates (vein.kvp) id: vein name: "VEIN" version: 0.1.0 authors: - panel contributors supported_modes: - docker runtime: docker: # Built locally from ./Dockerfile. Rebuild with: # docker build -t panel-vein:latest modules/vein image: panel-vein:latest # Host networking -- container shares the host net namespace, so # any port the game 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 below). network_mode: host browseable_root: /game-saves browseable_roots: - name: "Saves & Configs" path: /game-saves hint: "Vein/Saved/ savegame data + Config/LinuxServer/Game.ini" - name: "Game Files" path: /game hint: "Vein/Binaries/Linux/ server binary + steamclient libs" # Pre-declare every env key that any config_value below maps to. The # agent's resolve.go ONLY propagates config_values whose key is already # present in `docker.env` — keys not listed here get silently filtered # out. Empty-string defaults mean "leave Game.ini alone" (the entrypoint # stamps only non-empty values, so a recreate with empty env preserves # whatever the operator set previously via the Config/Files tab). env: # Steamworks client runtime init context — the dedicated-server app # (2131400) reports itself to Steam as VEIN (1857950). AMP sets this # too; without it the server's Steam socket init / master-server # listing fails. STEAM_APP_ID: "1857950" # --- Per-instance ports --- # MUST be pre-declared here or resolve.go silently drops the allocator's # injected values (it only overrides docker.env keys that already exist), # and the entrypoint falls back to these defaults → two VEIN servers on # one host both bind 7777 and collide. The `env:` on each ports entry # below maps the panel-allocated HOST port into these vars at start. GAME_PORT: "7777" QUERY_PORT: "27015" RCON_PORT: "7878" # --- Identity & access (stamped into Game.ini sections) --- SERVER_NAME: "" SERVER_DESCRIPTION: "" SERVER_PASSWORD: "" MAX_PLAYERS: "" SERVER_PUBLIC: "" # bPublic — list on the public browser HEARTBEAT_INTERVAL: "" ENABLE_VAC: "" # bVACEnabled under [OnlineSubsystemSteam] SHOW_SCOREBOARD_BADGES: "" 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" } # Multi-instance safety: `env:` tells the agent which container env var to # set with the allocated host port. The entrypoint reads these to build # VEIN's `-Port` / `-QueryPort` launch flags so two VEIN servers on the # same agent get distinct, non-colliding sockets (avoids the Valheim # hardcoded-port collision class of bug). ports: - { name: game, proto: udp, default: 7777, required: true, env: GAME_PORT } - { name: query, proto: udp, default: 27015, required: true, env: QUERY_PORT } # VEIN declares an RCON port but the admin path is STDIO; we expose it for # completeness / firewalling but do NOT wire a network rcon adapter to it. - { name: rcon, proto: udp, default: 7878, internal: true, env: RCON_PORT } resources: min_ram_mb: 4096 recommended_ram_mb: 8192 rcon: # VEIN admin console is stdin-only (no network RCON). The stdio adapter # auto-enables container OpenStdin (agent resolve.go) and the Console tab # "Send" box writes commands to the server process's stdin. Output comes # back via the docker-logs live tail, not a correlated reply. adapter: stdio # Log-derived player events. Regexes converted from CubeCoders' # AMPTemplates (vein.kvp) — .NET (?) syntax -> Go (?P). # Sourced-from-template; not yet exercised against a live client. events: join: pattern: 'LogNet: Login request: (?:\?Password=[^?]*)?\?Name=(?P.+?)\?\?ID=(?P\d+)\?Ticket=' kind: join leave: pattern: 'LogNet: UChannel::CleanUp: ChIndex == \d+\. Closing connection\..*RemoteAddr: (?P\d+):\d+' kind: leave update_providers: - id: stable kind: steamcmd app_id: "2131400" 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: '/LogRamjetNetworking: Steamworks server initialized with SteamID \d+|LogRamjetNetworking: Heartbeating with IP /i' appearance: emoji: "🩸" grad: "linear-gradient(135deg,#2a0a0a,#7a1010)" art: "/game-art/vein.jpg" steam: "1857950"