Phase 2 references for the host-agent Dune adapter, moved out of volatile /tmp
into docs/reference-repos/ (per Commander). Three upstream projects, .git +
node_modules + compiled binaries stripped (16MB source). Nested AI-instruction
files (.claude/, CLAUDE.md) removed so they don't pollute Corrosion sessions.
- icehunter/ dune-admin (Go+React) — 4 control planes; SETUP_DOCKER.md is the
closest analog to our agent's Dune docker control plane (compose
lifecycle, docker logs, RabbitMQ-via-exec, dune Postgres schema)
- adainrivers/ Rust/Tauri desktop — SSH+k8s BattleGroup control, maintenance
daemon, in-game admin console (Rust idiom reference)
- the4rchangel/ Node web UI replacing battlegroup.bat — matches the Commander's
Hyper-V self-host path + game-config schema
See docs/reference-repos/README.md for the full index + how we use each.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1000 lines
52 KiB
HTML
1000 lines
52 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Dune: Awakening — Server Manager</title>
|
||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
|
||
<link rel="stylesheet" href="/css/style.css">
|
||
</head>
|
||
<body>
|
||
|
||
<!-- Header -->
|
||
<header class="topbar">
|
||
<div class="topbar-left">
|
||
<h1 class="logo">DUNE<span class="logo-dim">:</span> AWAKENING</h1>
|
||
<span class="logo-sub">SERVER MANAGER</span>
|
||
</div>
|
||
<div class="topbar-right">
|
||
<div class="status-chip" id="vm-chip">
|
||
<span class="dot"></span>
|
||
<span class="chip-label">VM</span>
|
||
<span class="chip-value" id="vm-chip-state">—</span>
|
||
</div>
|
||
<div class="status-chip" id="bg-chip">
|
||
<span class="dot"></span>
|
||
<span class="chip-label">Battlegroup</span>
|
||
<span class="chip-value" id="bg-chip-state">—</span>
|
||
</div>
|
||
</div>
|
||
</header>
|
||
|
||
<!-- Tabs -->
|
||
<nav class="tabs">
|
||
<button class="tab active" data-tab="dashboard">Dashboard</button>
|
||
<button class="tab" data-tab="setup">Setup</button>
|
||
<button class="tab" data-tab="battlegroup">Battlegroup</button>
|
||
<button class="tab" data-tab="monitoring">Monitoring</button>
|
||
<button class="tab" data-tab="database">Database</button>
|
||
<button class="tab" data-tab="characters">Characters</button>
|
||
<button class="tab" data-tab="gameconfig">Game Config</button>
|
||
<button class="tab" data-tab="settings">Settings</button>
|
||
<button class="tab" data-tab="experimental">Experimental</button>
|
||
</nav>
|
||
|
||
<main class="content">
|
||
|
||
<!-- ============ Dashboard ============ -->
|
||
<section class="panel active" id="tab-dashboard">
|
||
<div class="card-row">
|
||
<div class="card status-card" id="card-vm">
|
||
<div class="card-header">
|
||
<h2>Virtual Machine</h2>
|
||
<span class="badge" id="vm-badge">Unknown</span>
|
||
</div>
|
||
<div class="card-body">
|
||
<div class="stat-grid">
|
||
<div class="stat"><span class="stat-label">State</span><span class="stat-value" id="vm-state">—</span></div>
|
||
<div class="stat"><span class="stat-label">IP Address</span><span class="stat-value" id="vm-ip">—</span></div>
|
||
<div class="stat"><span class="stat-label">Memory</span><span class="stat-value" id="vm-memory">—</span></div>
|
||
<div class="stat"><span class="stat-label">Uptime</span><span class="stat-value" id="vm-uptime">—</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="card-actions">
|
||
<button class="btn btn-green" id="btn-vm-start" disabled>Start VM</button>
|
||
<button class="btn btn-red" id="btn-vm-stop" disabled>Stop VM</button>
|
||
</div>
|
||
<div id="vm-start-retry" class="retry-panel" hidden>
|
||
<p class="card-desc retry-msg">VM failed to start — usually not enough free RAM on this PC. Lower memory and retry.</p>
|
||
<div class="setup-row" style="align-items:end">
|
||
<div class="field">
|
||
<label for="dashboard-retry-memory">Startup memory</label>
|
||
<select id="dashboard-retry-memory" class="select-input">
|
||
<option value="12">12 GB</option>
|
||
<option value="14">14 GB</option>
|
||
<option value="16">16 GB</option>
|
||
<option value="18">18 GB</option>
|
||
<option value="20" selected>20 GB</option>
|
||
<option value="24">24 GB</option>
|
||
<option value="30">30 GB</option>
|
||
</select>
|
||
</div>
|
||
<div class="field">
|
||
<button class="btn btn-green btn-lg" id="btn-dashboard-retry-start" style="margin-bottom:1px">Retry Start</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card status-card" id="card-bg">
|
||
<div class="card-header">
|
||
<h2>Battlegroup</h2>
|
||
<span class="badge" id="bg-badge">Unknown</span>
|
||
</div>
|
||
<div class="card-body">
|
||
<pre class="bg-status-output" id="bg-status-text">Waiting for status...</pre>
|
||
</div>
|
||
<div class="card-actions">
|
||
<button class="btn btn-green" id="btn-bg-start" disabled>Start</button>
|
||
<button class="btn btn-yellow" id="btn-bg-restart" disabled>Restart</button>
|
||
<button class="btn btn-red" id="btn-bg-stop" disabled>Stop</button>
|
||
<button class="btn btn-blue" id="btn-bg-update" disabled>Update</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card" id="ssh-key-warning" hidden>
|
||
<div class="card-header">
|
||
<h2>SSH Key Problem</h2>
|
||
</div>
|
||
<div class="card-body">
|
||
<p class="card-desc retry-msg">The manager cannot authenticate to the VM. Battlegroup commands will fail until this is fixed.</p>
|
||
<p class="card-desc" id="ssh-key-hint"></p>
|
||
<p class="card-desc">If you start the manager from WSL, prefer <strong>start_as_admin.bat</strong> on Windows after a reboot. You can also go to <strong>Settings → Rotate SSH Key</strong> while the VM is running.</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card" id="repair-bootstrap-panel" hidden>
|
||
<div class="card-header">
|
||
<h2>Battlegroup setup incomplete</h2>
|
||
</div>
|
||
<div class="card-body">
|
||
<p class="card-desc">The VM exists but the battlegroup was never fully installed (empty namespace). Enter your server token and run repair — this deletes the empty namespace and re-runs bootstrap.</p>
|
||
<div class="setup-row">
|
||
<div class="field">
|
||
<label for="repair-world-name">World Name</label>
|
||
<input type="text" id="repair-world-name" class="select-input" maxlength="50" placeholder="Dunewatchers" value="Dunewatchers">
|
||
</div>
|
||
<div class="field">
|
||
<label for="repair-region">Region</label>
|
||
<select id="repair-region" class="select-input">
|
||
<option value="1">Asia</option>
|
||
<option value="2">Europe</option>
|
||
<option value="3" selected>North America</option>
|
||
<option value="4">Oceania</option>
|
||
<option value="5">South America</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
<div class="field" style="margin-top:.75rem">
|
||
<label for="repair-token">Server Token</label>
|
||
<input type="password" id="repair-token" class="select-input" placeholder="Paste token from account.duneawakening.com">
|
||
</div>
|
||
<div class="field" style="margin-top:.75rem">
|
||
<label class="radio-label">
|
||
<input type="checkbox" id="repair-swap">
|
||
Enable experimental swap memory
|
||
</label>
|
||
</div>
|
||
<div class="setup-progress-area" style="margin-top:1rem">
|
||
<div class="spinner" id="repair-spinner" hidden></div>
|
||
<pre class="setup-log" id="repair-log"></pre>
|
||
</div>
|
||
</div>
|
||
<div class="card-actions">
|
||
<button type="button" class="btn btn-blue btn-lg" id="btn-repair-bootstrap">Repair & Complete Setup</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card quick-links-card" id="quick-links">
|
||
<div class="card-header"><h2>Quick Links</h2></div>
|
||
<div class="card-body link-row">
|
||
<a class="link-btn" id="link-filebrowser" href="#" target="_blank">
|
||
<svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z"/></svg>
|
||
File Browser
|
||
</a>
|
||
<a class="link-btn" id="link-director" href="#" target="_blank">
|
||
<svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><path d="M12 6v6l4 2"/></svg>
|
||
Director
|
||
</a>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ============ Setup Wizard ============ -->
|
||
<section class="panel" id="tab-setup">
|
||
<div class="card wizard-card">
|
||
<div class="card-header">
|
||
<h2>Initial Server Setup</h2>
|
||
<span class="badge" id="setup-step-badge">Step 1 of 6</span>
|
||
</div>
|
||
|
||
<!-- Progress bar -->
|
||
<div class="wizard-progress">
|
||
<div class="wizard-progress-fill" id="wizard-progress-fill" style="width: 16.6%"></div>
|
||
</div>
|
||
|
||
<div class="card-body">
|
||
|
||
<!-- Step 1: Pre-flight -->
|
||
<div class="wizard-step active" id="wiz-step-1">
|
||
<h3>Pre-flight Checks</h3>
|
||
<p class="card-desc">Verifying your system is ready for the Dune: Awakening server.</p>
|
||
<div class="preflight-results" id="preflight-results">
|
||
<div class="preflight-item" id="pf-hyperv">
|
||
<span class="pf-icon">☐</span>
|
||
<span>Hyper-V enabled and running</span>
|
||
</div>
|
||
<div class="preflight-item" id="pf-vmcx">
|
||
<span class="pf-icon">☐</span>
|
||
<span>Server files found (vmcx)</span>
|
||
</div>
|
||
<div class="preflight-item" id="pf-drives">
|
||
<span class="pf-icon">☐</span>
|
||
<span>Drive with 100GB+ free space</span>
|
||
</div>
|
||
</div>
|
||
<div class="btn-group" style="margin-top: 1rem">
|
||
<button class="btn btn-blue btn-lg" id="btn-preflight">Run Checks</button>
|
||
</div>
|
||
|
||
<div id="setup-reset-panel" class="setup-reset-panel" hidden>
|
||
<div class="setup-reset-title">Existing installation detected</div>
|
||
<p class="card-desc" id="setup-reset-desc">A Dune server VM is already on this machine. Delete everything and run setup again from scratch.</p>
|
||
<ul class="setup-reset-list">
|
||
<li>Hyper-V VM <code>dune-awakening</code></li>
|
||
<li><code>DuneAwakeningServer</code> folders on all drives</li>
|
||
<li>SSH keys and saved VM credentials</li>
|
||
<li>All in-VM battlegroup data (world, characters, configs)</li>
|
||
</ul>
|
||
<p class="field-hint" style="color:var(--yellow)">This cannot be undone. Export a database backup first if you need your world data.</p>
|
||
<button type="button" class="btn btn-red btn-lg" id="btn-setup-reset">Delete & Start Fresh</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Step 2: Configuration -->
|
||
<div class="wizard-step" id="wiz-step-2">
|
||
<h3>VM Configuration</h3>
|
||
<p class="card-desc">Choose where to install and how much resources to allocate.</p>
|
||
<form id="form-setup-config" class="settings-form" style="max-width:100%">
|
||
<div class="setup-row">
|
||
<div class="field" style="grid-column: 1 / -1">
|
||
<label for="setup-token">Server Token</label>
|
||
<input type="text" id="setup-token" class="select-input" placeholder="Paste your token here" required>
|
||
<span class="field-hint">Generate one at <a href="https://account.duneawakening.com/" target="_blank" style="color:var(--gold)">account.duneawakening.com</a></span>
|
||
</div>
|
||
</div>
|
||
<div class="setup-row">
|
||
<div class="field">
|
||
<label for="setup-drive">Install Drive</label>
|
||
<select id="setup-drive" class="select-input"></select>
|
||
</div>
|
||
<div class="field">
|
||
<label for="setup-memory">Memory</label>
|
||
<select id="setup-memory" class="select-input">
|
||
<option value="10">10 GB (requires swap)</option>
|
||
<option value="20" selected>20 GB (Hagga Basin)</option>
|
||
<option value="30">30 GB (+ Story/Social)</option>
|
||
<option value="40">40 GB (+ Deep Desert)</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
<div class="setup-row">
|
||
<div class="field">
|
||
<label for="setup-network">Network Mode</label>
|
||
<select id="setup-network" class="select-input">
|
||
<option value="external">External Switch (recommended — bridge mode)</option>
|
||
<option value="default">Default Switch (local only)</option>
|
||
</select>
|
||
</div>
|
||
<div class="field" id="nic-field" style="display:none">
|
||
<label for="setup-nic">Network Adapter</label>
|
||
<select id="setup-nic" class="select-input"></select>
|
||
</div>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
|
||
<!-- Step 3: Import (progress) -->
|
||
<div class="wizard-step" id="wiz-step-3">
|
||
<h3>Installing</h3>
|
||
<p class="card-desc">Importing VM, configuring network and memory, starting the virtual machine. This can take several minutes.</p>
|
||
<div class="setup-progress-area">
|
||
<div class="spinner" id="setup-spinner" hidden></div>
|
||
<pre class="setup-log" id="setup-log"></pre>
|
||
</div>
|
||
<div id="retry-start" class="retry-panel" hidden>
|
||
<p class="card-desc retry-msg">VM imported but failed to start — most likely not enough RAM. Reduce the memory and retry.</p>
|
||
<div class="setup-row" style="align-items:end">
|
||
<div class="field">
|
||
<label for="retry-memory">Memory</label>
|
||
<select id="retry-memory" class="select-input">
|
||
<option value="10">10 GB (requires swap)</option>
|
||
<option value="20" selected>20 GB</option>
|
||
<option value="30">30 GB</option>
|
||
<option value="40">40 GB</option>
|
||
</select>
|
||
</div>
|
||
<div class="field">
|
||
<button class="btn btn-green btn-lg" id="btn-retry-start" style="margin-bottom:1px">Retry Start</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Step 4: SSH Key + Password (combined) -->
|
||
<div class="wizard-step" id="wiz-step-4">
|
||
<h3>Security</h3>
|
||
<p class="card-desc">This will generate an SSH key, install it on the VM, and change the default password — all in one step.</p>
|
||
<form id="form-setup-pw" class="settings-form" style="max-width:100%">
|
||
<div class="setup-row">
|
||
<div class="field">
|
||
<label for="setup-curpw">Current VM Password</label>
|
||
<input type="password" id="setup-curpw" value="dune" autocomplete="off">
|
||
<span class="field-hint">Default is "dune" — change only if you've set it before</span>
|
||
</div>
|
||
</div>
|
||
<div class="setup-row">
|
||
<div class="field">
|
||
<label for="setup-pw">New Password</label>
|
||
<input type="password" id="setup-pw" required autocomplete="new-password">
|
||
</div>
|
||
<div class="field">
|
||
<label for="setup-pw2">Confirm New Password</label>
|
||
<input type="password" id="setup-pw2" required autocomplete="new-password">
|
||
</div>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
|
||
<!-- Step 5: Networking -->
|
||
<div class="wizard-step" id="wiz-step-5">
|
||
<h3>Player Connectivity</h3>
|
||
<p class="card-desc">Choose how the VM gets its IP and which IP players will connect to.</p>
|
||
<div class="setup-row">
|
||
<div class="field">
|
||
<label>VM IP Assignment</label>
|
||
<select id="setup-ip-mode" class="select-input">
|
||
<option value="dhcp">DHCP (automatic — recommended)</option>
|
||
<option value="static">Static IP</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
<div id="static-fields" class="setup-row" style="display:none">
|
||
<div class="field">
|
||
<label for="setup-static-ip">Static IP</label>
|
||
<input type="text" id="setup-static-ip" placeholder="192.168.1.100" class="select-input">
|
||
</div>
|
||
<div class="field">
|
||
<label for="setup-static-gw">Gateway</label>
|
||
<input type="text" id="setup-static-gw" placeholder="192.168.1.1" class="select-input">
|
||
</div>
|
||
</div>
|
||
<div class="field" style="margin-top: .75rem">
|
||
<label>Player-facing IP</label>
|
||
<div class="ip-options" id="ip-options">
|
||
<label class="radio-label"><input type="radio" name="playerIpChoice" value="public" checked> <span id="opt-public">Public IP (detecting...)</span></label>
|
||
<label class="radio-label"><input type="radio" name="playerIpChoice" value="private"> <span id="opt-private">Private IP</span></label>
|
||
<label class="radio-label"><input type="radio" name="playerIpChoice" value="manual"> Custom</label>
|
||
</div>
|
||
<input type="text" id="setup-player-ip-manual" placeholder="Enter IP" class="select-input" style="display:none; margin-top: .5rem">
|
||
</div>
|
||
<div id="setup-port-forward" class="port-forward-notice" style="display:none;margin-top:1rem" hidden></div>
|
||
</div>
|
||
|
||
<!-- Step 6: Bootstrap -->
|
||
<div class="wizard-step" id="wiz-step-6">
|
||
<h3>Finalize</h3>
|
||
<p class="card-desc">Configure your world, then upload bootstrap files and run the first-time battlegroup setup. This is the final step.</p>
|
||
<form id="form-world-config" class="settings-form" style="max-width:100%; margin-bottom: 1rem">
|
||
<div class="setup-row">
|
||
<div class="field">
|
||
<label for="setup-world-name">World Name <span style="color:var(--text-dim)">(max 50 chars)</span></label>
|
||
<input type="text" id="setup-world-name" class="select-input" maxlength="50" placeholder="My Arrakis Server" required>
|
||
</div>
|
||
<div class="field">
|
||
<label for="setup-region">Region</label>
|
||
<select id="setup-region" class="select-input">
|
||
<option value="1">Asia</option>
|
||
<option value="2">Europe</option>
|
||
<option value="3" selected>North America</option>
|
||
<option value="4">Oceania</option>
|
||
<option value="5">South America</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
</form>
|
||
<div class="field" style="margin-bottom: 1rem">
|
||
<label class="radio-label">
|
||
<input type="checkbox" id="setup-swap">
|
||
Enable experimental swap memory (recommended if memory < 20GB)
|
||
</label>
|
||
</div>
|
||
<div class="setup-progress-area">
|
||
<div class="spinner" id="bootstrap-spinner" hidden></div>
|
||
<pre class="setup-log" id="bootstrap-log"></pre>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Step 7: Done -->
|
||
<div class="wizard-step" id="wiz-step-7">
|
||
<div class="done-banner">
|
||
<svg viewBox="0 0 24 24" width="48" height="48" fill="none" stroke="var(--gold)" stroke-width="2"><circle cx="12" cy="12" r="10"/><path d="M8 12l2.5 2.5L16 9"/></svg>
|
||
<h3>Setup Complete</h3>
|
||
<p class="card-desc">Your Dune: Awakening server is ready. Head to the Dashboard to start your battlegroup.</p>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<!-- Wizard navigation -->
|
||
<div class="card-actions wizard-nav">
|
||
<button class="btn btn-blue" id="wiz-back" hidden>Back</button>
|
||
<div style="flex:1"></div>
|
||
<button class="btn btn-green btn-lg" id="wiz-next">Next</button>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ============ Battlegroup ============ -->
|
||
<section class="panel" id="tab-battlegroup">
|
||
<div class="card">
|
||
<div class="card-header"><h2>Battlegroup Controls</h2></div>
|
||
<div class="card-body">
|
||
<p class="card-desc">Manage the lifecycle of your battlegroup. Start, stop, or restart game servers, and check for updates.</p>
|
||
<div class="btn-group">
|
||
<button class="btn btn-green btn-lg" data-action="bg/start">Start Battlegroup</button>
|
||
<button class="btn btn-red btn-lg" data-action="bg/stop">Stop Battlegroup</button>
|
||
<button class="btn btn-yellow btn-lg" data-action="bg/restart">Restart Battlegroup</button>
|
||
<button class="btn btn-blue btn-lg" data-action="bg/update">Check for Updates</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card">
|
||
<div class="card-header"><h2>Swap Memory</h2></div>
|
||
<div class="card-body">
|
||
<p class="card-desc">Enable experimental swap memory to significantly reduce RAM requirements per game server. Recommended if VM has less than 20GB allocated.</p>
|
||
<div class="btn-group">
|
||
<button class="btn btn-yellow btn-lg" data-action="bg/enable-experimental-swap">Enable Swap Memory</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ============ Monitoring ============ -->
|
||
<section class="panel" id="tab-monitoring">
|
||
<div class="card-row">
|
||
<div class="card">
|
||
<div class="card-header"><h2>Web Interfaces</h2></div>
|
||
<div class="card-body">
|
||
<p class="card-desc">Access the built-in web tools running inside the VM.</p>
|
||
<div class="btn-group">
|
||
<a class="btn btn-blue btn-lg" id="mon-filebrowser" href="#" target="_blank">Open File Browser</a>
|
||
<a class="btn btn-blue btn-lg" id="mon-director" href="#" target="_blank">Open Director</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card">
|
||
<div class="card-header"><h2>Log Export</h2></div>
|
||
<div class="card-body">
|
||
<p class="card-desc">Download logs from all battlegroup components or operator pods.</p>
|
||
<div class="btn-group">
|
||
<button class="btn btn-blue btn-lg" data-action="logs/export">Export Battlegroup Logs</button>
|
||
<button class="btn btn-blue btn-lg" data-action="logs/operators">Export Operator Logs</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ============ Database ============ -->
|
||
<section class="panel" id="tab-database">
|
||
<div class="card">
|
||
<div class="card-header"><h2>Database Management</h2></div>
|
||
<div class="card-body">
|
||
<p class="card-desc">Back up or restore the battlegroup database. For best results, stop the battlegroup before performing these operations.</p>
|
||
<div class="btn-group">
|
||
<button class="btn btn-green btn-lg" data-action="bg/backup">
|
||
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
|
||
Take Backup
|
||
</button>
|
||
<button class="btn btn-yellow btn-lg" data-action="bg/import">
|
||
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/></svg>
|
||
Import Backup
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ============ Character Editor ============ -->
|
||
<section class="panel" id="tab-characters">
|
||
<div class="char-warning">
|
||
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2"><path d="M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>
|
||
<span><strong>Editing characters directly modifies the game database.</strong> This may corrupt save data and cause total character loss. Always take a database backup before making changes. Only edit while the battlegroup is stopped and the player is logged out.</span>
|
||
</div>
|
||
|
||
<div class="card">
|
||
<div class="card-header"><h2>Select Character</h2></div>
|
||
<div class="card-body">
|
||
<div class="char-select-row">
|
||
<select id="char-select" class="select-input" style="max-width:280px"><option value="">— Choose a character —</option></select>
|
||
<button class="btn btn-blue" id="btn-char-load">Load Character</button>
|
||
<button class="btn btn-blue" id="btn-char-refresh" title="Refresh character list">Refresh List</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="char-editor" style="display:none">
|
||
<div class="card">
|
||
<div class="card-header"><h2>Stats</h2><button class="btn btn-green btn-sm" id="btn-stats-save">Save Stats</button></div>
|
||
<div class="card-body">
|
||
<div class="config-grid">
|
||
<div class="config-item">
|
||
<label>Max Health</label>
|
||
<input type="number" class="select-input char-stat" id="cs-max-health" data-field="properties" data-path="DamageableActorComponent.m_TotalMaxHealth" step="1" min="1">
|
||
</div>
|
||
<div class="config-item">
|
||
<label>Tech Knowledge Points</label>
|
||
<input type="number" class="select-input char-stat" id="cs-tech-pts" data-field="properties" data-path="TechKnowledgePlayerComponent.m_TechKnowledgePoints" step="1" min="0">
|
||
</div>
|
||
<div class="config-item">
|
||
<label>Hydration</label>
|
||
<input type="number" class="select-input char-stat" id="cs-hydration" data-field="gas_attributes" data-path="DuneHydrationAttributeSet.CurrentHydration" step="0.1" min="0">
|
||
</div>
|
||
<div class="config-item">
|
||
<label>Heat Exhaustion</label>
|
||
<input type="number" class="select-input char-stat" id="cs-heat" data-field="gas_attributes" data-path="DuneHydrationAttributeSet.HeatExhaustion" step="0.1" min="0">
|
||
</div>
|
||
<div class="config-item">
|
||
<label>Current Spice</label>
|
||
<input type="number" class="select-input char-stat" id="cs-spice" data-field="gas_attributes" data-path="DuneSpiceAddictionAttributeSet.CurrentSpice" step="1" min="0">
|
||
</div>
|
||
<div class="config-item">
|
||
<label>Spice Addiction Level</label>
|
||
<input type="number" class="select-input char-stat" id="cs-addiction" data-field="gas_attributes" data-path="DuneSpiceAddictionAttributeSet.SpiceAddictionLevel" step="0.1" min="0">
|
||
</div>
|
||
<div class="config-item">
|
||
<label>Spice Tolerance</label>
|
||
<input type="number" class="select-input char-stat" id="cs-tolerance" data-field="gas_attributes" data-path="DuneSpiceAddictionAttributeSet.SpiceTolerance" step="0.1" min="0">
|
||
</div>
|
||
<div class="config-item">
|
||
<label>Eyes of Ibad <span class="field-hint-inline">0.0 – 1.0</span></label>
|
||
<input type="number" class="select-input char-stat" id="cs-eyes" data-field="properties" data-path="BP_DunePlayerCharacter_C.m_EyesOfIbadValue" step="0.05" min="0" max="1">
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card">
|
||
<div class="card-header">
|
||
<h2>Inventory</h2>
|
||
<span class="badge" id="inv-count">0 items</span>
|
||
</div>
|
||
<div class="card-body" style="padding:0">
|
||
<div class="inv-table-wrap">
|
||
<table class="inv-table" id="inv-table">
|
||
<thead><tr><th>Item</th><th>ID</th><th>Qty</th><th>Location</th><th></th></tr></thead>
|
||
<tbody id="inv-tbody"></tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card">
|
||
<div class="card-header"><h2>Add Item</h2></div>
|
||
<div class="card-body">
|
||
<div class="item-search-row">
|
||
<input type="text" class="select-input" id="item-search" placeholder="Search items by name..." style="flex:1">
|
||
<select class="select-input" id="item-cat-filter" style="max-width:200px">
|
||
<option value="">All Categories</option>
|
||
<option value="Resources">Resources</option>
|
||
<option value="Consumables">Consumables</option>
|
||
<option value="Ammo">Ammo</option>
|
||
<option value="Weapons - Melee">Weapons - Melee</option>
|
||
<option value="Weapons - Ranged">Weapons - Ranged</option>
|
||
<option value="Garments">Garments (all)</option>
|
||
<option value="Tools">Tools</option>
|
||
<option value="Vehicle Modules">Vehicle Modules</option>
|
||
<option value="Building">Building</option>
|
||
<option value="Contract Items">Contract Items</option>
|
||
<option value="Fuel">Fuel</option>
|
||
<option value="Misc">Misc</option>
|
||
</select>
|
||
</div>
|
||
<div class="item-results-wrap" id="item-results" style="display:none">
|
||
<table class="inv-table">
|
||
<thead><tr><th>Item</th><th>Category</th><th>Qty</th><th>To</th><th></th></tr></thead>
|
||
<tbody id="item-results-body"></tbody>
|
||
</table>
|
||
</div>
|
||
<p class="card-desc" id="item-results-hint" style="margin-top:.5rem">Type at least 2 characters to search by name or template ID across 1000 items.</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card">
|
||
<div class="card-header"><h2>Tech Tree</h2><span class="badge" id="tech-count">—</span></div>
|
||
<div class="card-body">
|
||
<p class="card-desc">Unlock or lock all recipes and blueprints in the tech knowledge tree. Unlock All merges every game recipe node into your save (not just ones already discovered). Stop the battlegroup and relog after changes.</p>
|
||
<div class="btn-group">
|
||
<button class="btn btn-green" id="btn-tech-unlock-all">Unlock All Recipes</button>
|
||
<button class="btn btn-red" id="btn-tech-lock-all">Lock All Recipes</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card">
|
||
<div class="card-header"><h2>Specializations</h2></div>
|
||
<div class="card-body">
|
||
<p class="card-desc">Set XP and level for each specialization track, and unlock all keystones (perks) per tree.</p>
|
||
<div id="spec-tracks-grid" class="config-grid" style="margin-bottom:1rem"></div>
|
||
<h3 style="font-size:.8rem;color:var(--text-dim);margin-bottom:.5rem;text-transform:uppercase;letter-spacing:.05em">Unlock Keystones (Perks)</h3>
|
||
<div class="btn-group" id="spec-keystone-btns">
|
||
<button class="btn btn-green btn-sm" data-prefix="Combat_">All Combat</button>
|
||
<button class="btn btn-green btn-sm" data-prefix="Crafting_">All Crafting</button>
|
||
<button class="btn btn-green btn-sm" data-prefix="Exploration_">All Exploration</button>
|
||
<button class="btn btn-green btn-sm" data-prefix="Gathering_">All Gathering</button>
|
||
<button class="btn btn-green btn-sm" data-prefix="Sabotage_">All Sabotage</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card">
|
||
<div class="card-header"><h2>Economy</h2></div>
|
||
<div class="card-body">
|
||
<div class="config-grid">
|
||
<div class="config-item">
|
||
<label>Solari (Currency 0)</label>
|
||
<div class="input-with-unit">
|
||
<input type="number" class="select-input" id="econ-currency-0" min="0" step="1000" value="0">
|
||
<button class="btn btn-green btn-sm" data-currency="0">Set</button>
|
||
</div>
|
||
</div>
|
||
<div class="config-item">
|
||
<label>House Scrip (Currency 1)</label>
|
||
<div class="input-with-unit">
|
||
<input type="number" class="select-input" id="econ-currency-1" min="0" step="100" value="0">
|
||
<button class="btn btn-green btn-sm" data-currency="1">Set</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card">
|
||
<div class="card-header"><h2>Faction Reputation</h2></div>
|
||
<div class="card-body">
|
||
<div class="config-grid" id="faction-rep-grid"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card">
|
||
<div class="card-header"><h2>Cosmetics & Skins</h2><span class="badge" id="cosmetic-count">—</span></div>
|
||
<div class="card-body">
|
||
<p class="card-desc">Search and unlock cosmetics by name. <strong>Vehicle Paints</strong> and <strong>Vehicle Variants</strong> are what show in the garage paint menu — not Swatch Tokens (those are inventory items; use Add Item instead).</p>
|
||
<div class="btn-group" style="margin-bottom:.75rem">
|
||
<button class="btn btn-green btn-sm" id="btn-cosmetic-unlock-all">Unlock All Cosmetics & Swatches</button>
|
||
</div>
|
||
<div class="item-search-row" style="margin-bottom:.5rem">
|
||
<input type="text" class="select-input" id="cosmetic-search" placeholder="Search cosmetics by name or ID..." style="flex:1">
|
||
<select class="select-input" id="cosmetic-cat-filter" style="max-width:200px">
|
||
<option value="">All Categories</option>
|
||
<option value="Vehicle Paints">Vehicle Paints</option>
|
||
<option value="Vehicle Variants">Vehicle Variants</option>
|
||
<option value="Vehicle Skins">Vehicle Skins (MTX)</option>
|
||
<option value="Weapon Skins">Weapon Skins</option>
|
||
<option value="Weapon Paints">Weapon Paints</option>
|
||
<option value="Armor Skins">Armor Skins</option>
|
||
<option value="Armor Paints">Armor Paints</option>
|
||
<option value="Dye Packs">Dye Packs</option>
|
||
<option value="Swatch Tokens (Inventory)">Swatch Tokens (Inventory)</option>
|
||
</select>
|
||
</div>
|
||
<div class="item-results-wrap" id="cosmetic-results" style="display:none;margin-bottom:.75rem">
|
||
<table class="inv-table">
|
||
<thead><tr><th>Cosmetic</th><th>Category</th><th></th></tr></thead>
|
||
<tbody id="cosmetic-results-body"></tbody>
|
||
</table>
|
||
</div>
|
||
<p class="card-desc" id="cosmetic-results-hint" style="margin-bottom:.75rem">Type at least 2 characters to search across 621 cosmetics, or pick a category filter.</p>
|
||
<details>
|
||
<summary style="cursor:pointer;color:var(--text-dim);font-size:.8rem">Advanced: add by exact ID</summary>
|
||
<div class="item-search-row" style="margin-top:.5rem">
|
||
<input type="text" class="select-input" id="cosmetic-add-input" placeholder="Enter cosmetic ID to add..." style="flex:1">
|
||
<button class="btn btn-green btn-sm" id="btn-cosmetic-add">Add</button>
|
||
</div>
|
||
</details>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ============ Game Config ============ -->
|
||
<section class="panel" id="tab-gameconfig">
|
||
<div class="config-header-row">
|
||
<h2 class="section-title">Game Configuration</h2>
|
||
<div class="config-actions">
|
||
<button class="btn btn-blue" id="btn-config-reload">Reload</button>
|
||
<button class="btn btn-green" id="btn-config-save">Save & Apply</button>
|
||
</div>
|
||
</div>
|
||
<div class="config-warning" id="config-warning">
|
||
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2"><path d="M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>
|
||
<span><strong>Stop the battlegroup before editing.</strong> Changes require the battlegroup to be offline and will apply on next start.</span>
|
||
</div>
|
||
|
||
<div id="config-loading" class="card"><div class="card-body" style="text-align:center;color:var(--text-dim)">Loading configuration...</div></div>
|
||
|
||
<div id="config-panels" style="display:none">
|
||
|
||
<!-- Server Visibility -->
|
||
<div class="card">
|
||
<div class="card-header"><h2>Server Visibility</h2></div>
|
||
<div class="card-body">
|
||
<p class="card-desc">Controls how players find your server. <strong>LAN</strong> = only players on your network. <strong>Public (WAN)</strong> = internet players (requires router port forwarding to your <em>VM</em> IP).</p>
|
||
<p class="card-desc" style="margin-top:.35rem;font-size:.8rem">Self-hosted worlds appear in-game under <strong>Servers → Experimental</strong> (not Official or Private). Match the region you chose during setup.</p>
|
||
<div id="visibility-loading" style="color:var(--text-dim)">Detecting IPs...</div>
|
||
<div id="visibility-controls" style="display:none">
|
||
<div class="radio-group" id="visibility-radios"></div>
|
||
<div class="config-item" id="visibility-custom-row" style="display:none;margin-top:.5rem">
|
||
<label>Custom IP</label>
|
||
<input type="text" class="select-input" id="visibility-custom-ip" placeholder="e.g. 203.0.113.42">
|
||
</div>
|
||
<div id="visibility-port-forward" class="port-forward-notice" style="display:none" hidden></div>
|
||
<div style="margin-top:.75rem">
|
||
<button type="button" class="btn btn-green" id="btn-visibility-save">Apply</button>
|
||
<span class="visibility-current" id="visibility-current" style="margin-left:1rem;font-size:.8rem;color:var(--text-dim)"></span>
|
||
</div>
|
||
<p class="field-hint" style="margin-top:.5rem">After changing visibility, <strong>stop the battlegroup completely</strong>, then start it again. The gateway reads this IP only at startup.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- PvP & Security -->
|
||
<div class="card">
|
||
<div class="card-header"><h2>PvP & Security</h2></div>
|
||
<div class="card-body">
|
||
<div class="config-grid">
|
||
<div class="config-item">
|
||
<label>Force PvP on All Partitions</label>
|
||
<select class="select-input cfg" data-file="game" data-key="m_bShouldForceEnablePvpOnAllPartitions">
|
||
<option value="False">Off</option><option value="True">On</option>
|
||
</select>
|
||
</div>
|
||
<div class="config-item">
|
||
<label>Security Zones Enabled</label>
|
||
<select class="select-input cfg" data-file="game" data-key="m_bAreSecurityZonesEnabled">
|
||
<option value="True">On</option><option value="False">Off (PvP everywhere)</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Environment -->
|
||
<div class="card">
|
||
<div class="card-header"><h2>Environment</h2></div>
|
||
<div class="card-body">
|
||
<div class="config-grid">
|
||
<div class="config-item">
|
||
<label>Coriolis Storm</label>
|
||
<select class="select-input cfg" data-file="game" data-key="m_bCoriolisAutoSpawnEnabled">
|
||
<option value="True">On</option><option value="False">Off</option>
|
||
</select>
|
||
</div>
|
||
<div class="config-item">
|
||
<label>Sandstorm</label>
|
||
<select class="select-input cfg" data-file="engine" data-key="Sandstorm.Enabled">
|
||
<option value="1">On</option><option value="0">Off</option>
|
||
</select>
|
||
</div>
|
||
<div class="config-item">
|
||
<label>Sandstorm Treasure Spawns</label>
|
||
<select class="select-input cfg" data-file="engine" data-key="Sandstorm.Treasure.Enabled">
|
||
<option value="1">On</option><option value="0">Off</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Sandworm -->
|
||
<div class="card">
|
||
<div class="card-header"><h2>Sandworm</h2></div>
|
||
<div class="card-body">
|
||
<div class="config-grid">
|
||
<div class="config-item">
|
||
<label>Sandworm Enabled</label>
|
||
<select class="select-input cfg" data-file="engine" data-key="sandworm.dune.Enabled">
|
||
<option value="1">On</option><option value="0">Off</option>
|
||
</select>
|
||
</div>
|
||
<div class="config-item">
|
||
<label>Danger Zones Enabled</label>
|
||
<select class="select-input cfg" data-file="engine" data-key="Sandworm.SandwormDangerZonesEnabled">
|
||
<option value="true">On</option><option value="false">Off</option>
|
||
</select>
|
||
</div>
|
||
<div class="config-item">
|
||
<label>Sandworm Pushes Vehicles</label>
|
||
<select class="select-input cfg" data-file="engine" data-key="Vehicle.SandwormCollisionInteraction">
|
||
<option value="false">Off</option><option value="true">On</option>
|
||
</select>
|
||
</div>
|
||
<div class="config-item">
|
||
<label>Invulnerability on Vehicle Exit</label>
|
||
<div class="input-with-unit">
|
||
<input type="number" class="select-input cfg" data-file="engine" data-key="Vehicle.SandwormInvulnerabilitySecondsOnExit" step="1" min="0">
|
||
<span class="unit">sec</span>
|
||
</div>
|
||
</div>
|
||
<div class="config-item">
|
||
<label>Invulnerability on Server Restart</label>
|
||
<div class="input-with-unit">
|
||
<input type="number" class="select-input cfg" data-file="engine" data-key="Vehicle.SandwormInvulnerabilitySecondsOnServerRestart" step="1" min="0">
|
||
<span class="unit">sec</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Economy & Resources -->
|
||
<div class="card">
|
||
<div class="card-header"><h2>Economy & Resources</h2></div>
|
||
<div class="card-body">
|
||
<div class="config-grid">
|
||
<div class="config-item">
|
||
<label>Global Mining Multiplier</label>
|
||
<input type="number" class="select-input cfg" data-file="engine" data-key="Dune.GlobalMiningOutputMultiplier" step="0.1" min="0">
|
||
</div>
|
||
<div class="config-item">
|
||
<label>Vehicle Mining Multiplier</label>
|
||
<input type="number" class="select-input cfg" data-file="engine" data-key="Dune.GlobalVehicleMiningOutputMultiplier" step="0.1" min="0">
|
||
</div>
|
||
<div class="config-item">
|
||
<label>PvP Resource Multiplier</label>
|
||
<input type="number" class="select-input cfg" data-file="engine" data-key="SecurityZones.PvpResourceMultiplier" step="0.1" min="0">
|
||
</div>
|
||
<div class="config-item">
|
||
<label>Item Decay Rate <span class="field-hint-inline">0=off, 1-10</span></label>
|
||
<input type="number" class="select-input cfg" data-file="game" data-key="UpdateRateInSeconds" step="0.1" min="0" max="10">
|
||
</div>
|
||
<div class="config-item">
|
||
<label>Vehicle Durability Damage <span class="field-hint-inline">0=off, 1-10</span></label>
|
||
<input type="number" class="select-input cfg" data-file="engine" data-key="dw.VehicleDurabilityDamageMultiplier" step="0.1" min="0" max="10">
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Building -->
|
||
<div class="card">
|
||
<div class="card-header"><h2>Building</h2></div>
|
||
<div class="card-body">
|
||
<div class="config-grid">
|
||
<div class="config-item">
|
||
<label>Max Landclaim Segments</label>
|
||
<input type="number" class="select-input cfg" data-file="game" data-key="m_MaxNumLandclaimSegments" step="1" min="1">
|
||
</div>
|
||
<div class="config-item">
|
||
<label>Blueprint Max Extensions</label>
|
||
<input type="number" class="select-input cfg" data-file="game" data-key="m_BuildingBlueprintMaxExtensions" step="1" min="0">
|
||
</div>
|
||
<div class="config-item">
|
||
<label>Base Backup Max Extensions</label>
|
||
<input type="number" class="select-input cfg" data-file="game" data-key="m_BaseBackupMaxExtensions" step="1" min="0">
|
||
</div>
|
||
<div class="config-item">
|
||
<label>Building Restriction Limits</label>
|
||
<select class="select-input cfg" data-file="game" data-key="m_bBuildingRestrictionLimitsEnabled">
|
||
<option value="True">On</option><option value="False">Off</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Server -->
|
||
<div class="card">
|
||
<div class="card-header"><h2>Server</h2></div>
|
||
<div class="card-body">
|
||
<div class="config-grid">
|
||
<div class="config-item wide">
|
||
<label>Server Display Name <span class="field-hint-inline">shown to players</span></label>
|
||
<input type="text" class="select-input cfg" data-file="engine" data-key="Bgd.ServerDisplayName" placeholder="e.g. Sietch Dunewatchers">
|
||
<span class="field-hint">Shown in the in-game server browser. Leave empty only if you know your world display name from setup.</span>
|
||
</div>
|
||
<div class="config-item wide">
|
||
<label>Server Login Password <span class="field-hint-inline">blank = no password</span></label>
|
||
<input type="text" class="select-input cfg" data-file="engine" data-key="Bgd.ServerLoginPassword" placeholder="No password">
|
||
</div>
|
||
<div class="config-item">
|
||
<label>Game Port (starting)</label>
|
||
<input type="number" class="select-input cfg" data-file="engine" data-key="Port" step="1" min="1024" max="65535">
|
||
</div>
|
||
<div class="config-item">
|
||
<label>IGW Port (starting)</label>
|
||
<input type="number" class="select-input cfg" data-file="engine" data-key="IGWPort" step="1" min="1024" max="65535">
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ============ Settings ============ -->
|
||
<section class="panel" id="tab-settings">
|
||
<div class="card-row">
|
||
<div class="card">
|
||
<div class="card-header"><h2>Change VM Password</h2></div>
|
||
<div class="card-body">
|
||
<p class="card-desc">Change the <code>dune</code> user password on the VM.</p>
|
||
<form id="form-password" class="settings-form">
|
||
<div class="field">
|
||
<label for="pw-new">New Password</label>
|
||
<input type="password" id="pw-new" required autocomplete="new-password">
|
||
</div>
|
||
<div class="field">
|
||
<label for="pw-confirm">Confirm Password</label>
|
||
<input type="password" id="pw-confirm" required autocomplete="new-password">
|
||
</div>
|
||
<button type="submit" class="btn btn-green">Change Password</button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card">
|
||
<div class="card-header"><h2>SSH Key</h2></div>
|
||
<div class="card-body">
|
||
<p class="card-desc">Generate a new SSH key pair and install it on the VM, replacing the current one.</p>
|
||
<div class="btn-group">
|
||
<button class="btn btn-yellow btn-lg" id="btn-rotate-key">Rotate SSH Key</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ============ Experimental ============ -->
|
||
<section class="panel" id="tab-experimental">
|
||
<div class="card-row">
|
||
<div class="card" style="border-left:3px solid var(--warn)">
|
||
<div class="card-header"><h2>Experimental Features</h2></div>
|
||
<div class="card-body">
|
||
<p class="card-desc" style="color:var(--warn)"><strong>Warning:</strong> Features on this tab are untested and may break your battlegroup. Always take a database backup before making changes. Use at your own risk.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card-row">
|
||
<div class="card">
|
||
<div class="card-header"><h2>Multi-Sietch</h2></div>
|
||
<div class="card-body">
|
||
<p class="card-desc">Add additional sietches (Hagga Basin instances) to your battlegroup. All sietches share the same Overmap, Deep Desert, Arrakeen, Harkonnen Village, and instanced content (dungeons, story missions). Players from different sietches will see each other in shared areas but not in their respective Hagga Basin maps.</p>
|
||
|
||
<div class="info-box" style="background:var(--card-bg);border:1px solid var(--border);border-radius:8px;padding:1rem;margin:1rem 0;font-size:.85rem;line-height:1.6">
|
||
<strong>RAM Requirements</strong>
|
||
<ul style="margin:.5rem 0 0 1.2rem;padding:0">
|
||
<li>Each sietch requires approximately <strong>12 GB RAM</strong></li>
|
||
<li>Overmap + infrastructure (DB, RabbitMQ, K8s) uses ~6 GB</li>
|
||
<li>1 sietch: ~18 GB minimum (current default)</li>
|
||
<li>2 sietches: ~30 GB minimum</li>
|
||
<li>3 sietches: ~42 GB minimum</li>
|
||
</ul>
|
||
<br>
|
||
<strong>Port Forwarding</strong>
|
||
<p style="margin:.25rem 0 0 0">Each additional sietch adds one game server pod using <strong>host networking</strong>. Game ports auto-assign starting at UDP 7777. For N sietches you need ports <strong>7777–7778+N</strong> (UDP) forwarded, plus the corresponding beacon ports. When in doubt, forward the full range <strong>7777–7900 UDP</strong>.</p>
|
||
</div>
|
||
|
||
<div id="sietch-status" style="margin:1rem 0;color:var(--text-dim)">Loading sietch info...</div>
|
||
|
||
<div id="sietch-controls" style="display:none">
|
||
<div class="btn-group">
|
||
<button class="btn btn-green btn-lg" id="btn-add-sietch">Add Sietch</button>
|
||
<button class="btn btn-red btn-lg" id="btn-remove-sietch">Remove Sietch</button>
|
||
</div>
|
||
<p class="card-desc" style="margin-top:.75rem">After adding or removing a sietch, <strong>restart the battlegroup</strong> for changes to take effect.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
</main>
|
||
|
||
<!-- Console -->
|
||
<div class="console-wrapper" id="console-wrapper">
|
||
<button class="console-toggle" id="console-toggle">
|
||
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2"><polyline points="4 17 10 11 4 5"/><line x1="12" y1="19" x2="20" y2="19"/></svg>
|
||
Console Output
|
||
<span class="console-badge" id="console-badge" hidden>new</span>
|
||
</button>
|
||
<div class="console-body" id="console-body">
|
||
<pre id="console-output"></pre>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Loading overlay -->
|
||
<div class="overlay" id="overlay" hidden>
|
||
<div class="spinner"></div>
|
||
<p class="overlay-text" id="overlay-text">Working...</p>
|
||
</div>
|
||
|
||
<script src="/js/app.js"></script>
|
||
</body>
|
||
</html>
|