Document dedicated server and tile delivery builds

This commit is contained in:
2026-05-14 13:16:38 -07:00
parent 95166b0dab
commit 1a0fb12286
8 changed files with 418 additions and 5 deletions
+1
View File
@@ -9,6 +9,7 @@ Saved/
# Build outputs # Build outputs
Build/ Build/
Builds/ Builds/
BuildArtifacts/
*.sln *.sln
*.sln.DotSettings.user *.sln.DotSettings.user
*.VC.db *.VC.db
+6 -5
View File
@@ -175,7 +175,7 @@ Remaining version 0.01 cleanup before moving deeper into new gameplay:
- [x] Define backup expectations for NAS and repository. - [x] Define backup expectations for NAS and repository.
- [x] Implement Linastorage incremental project backup job. - [x] Implement Linastorage incremental project backup job.
- [x] Implement quiesced VM backup job for Windows-Builder and Ubuntu-Codex. - [x] Implement quiesced VM backup job for Windows-Builder and Ubuntu-Codex.
- [ ] Create repeatable dedicated server build instructions. - [x] Create repeatable dedicated server build instructions.
- [~] Finish required plugin documentation. - [~] Finish required plugin documentation.
- [ ] Confirm the project opens cleanly from a fresh checkout, not just the current working share. - [ ] Confirm the project opens cleanly from a fresh checkout, not just the current working share.
- [ ] Organize `Content/Agrarian/` folders and move starter/prototype assets into clearly named locations. - [ ] Organize `Content/Agrarian/` folders and move starter/prototype assets into clearly named locations.
@@ -213,7 +213,7 @@ Goal: Prepare the project so all future development is controlled, recoverable,
- [x] Decide build machine strategy. - [x] Decide build machine strategy.
- [x] Create repeatable local build instructions. - [x] Create repeatable local build instructions.
- [x] Create repeatable packaged build instructions. - [x] Create repeatable packaged build instructions.
- [ ] Create repeatable dedicated server build instructions. - [x] Create repeatable dedicated server build instructions.
- [~] Document required plugins. - [~] Document required plugins.
- [x] Disable unneeded plugins. - [x] Disable unneeded plugins.
- [x] Confirm project compiles from a clean checkout. - [x] Confirm project compiles from a clean checkout.
@@ -336,6 +336,7 @@ redownloaded when a player returns to a region.
- [ ] Define tile versioning rules so terrain can improve without corrupting player state. - [ ] Define tile versioning rules so terrain can improve without corrupting player state.
- [ ] Define server-side tile delivery protocol. - [ ] Define server-side tile delivery protocol.
- [ ] Launch a near-term MVP tile-serving cloud server on Ubuntu or another Linux distro. - [ ] Launch a near-term MVP tile-serving cloud server on Ubuntu or another Linux distro.
- [x] Add repeatable static Ground Zero tile-delivery package and Ubuntu nginx bootstrap scripts.
- [ ] Publish a tiny Ground Zero tile manifest and package from the tile server. - [ ] Publish a tiny Ground Zero tile manifest and package from the tile server.
- [ ] Prove client/server tile lookup, download, local cache, and redownload flow with the Ground Zero tile and immediate-neighbor metadata. - [ ] Prove client/server tile lookup, download, local cache, and redownload flow with the Ground Zero tile and immediate-neighbor metadata.
- [ ] Add tile-serving server cost controls and shutdown/runbook notes so MVP testing stays free or near-free. - [ ] Add tile-serving server cost controls and shutdown/runbook notes so MVP testing stays free or near-free.
@@ -1261,7 +1262,7 @@ These tracks run across all phases and must not be left as afterthoughts.
- [x] Add one-command Codex build wrapper for `AgrarianGameEditor`. - [x] Add one-command Codex build wrapper for `AgrarianGameEditor`.
- [x] Store editor build logs under `Saved/BuildLogs/BuildEditor-Windows.log`. - [x] Store editor build logs under `Saved/BuildLogs/BuildEditor-Windows.log`.
- [x] Add one-command packaged client build wrapper. - [x] Add one-command packaged client build wrapper.
- [ ] Add one-command Linux dedicated server build wrapper. - [x] Add one-command Linux dedicated server build wrapper.
- [x] Define investor-demo build trigger at version milestone completion. - [x] Define investor-demo build trigger at version milestone completion.
- [x] Add smoke-test command for build artifacts. - [x] Add smoke-test command for build artifacts.
- [ ] Enable protected `main` branch once revenue or a paid GitHub plan justifies the cost. - [ ] Enable protected `main` branch once revenue or a paid GitHub plan justifies the cost.
@@ -1416,7 +1417,7 @@ Earliest incomplete foundation items:
- [x] Define backup expectations for NAS and repository. - [x] Define backup expectations for NAS and repository.
- [x] Implement Linastorage incremental project backup job. - [x] Implement Linastorage incremental project backup job.
- [x] Implement quiesced VM backup job for Windows-Builder and Ubuntu-Codex. - [x] Implement quiesced VM backup job for Windows-Builder and Ubuntu-Codex.
- [ ] Create repeatable dedicated server build instructions. - [x] Create repeatable dedicated server build instructions.
- [~] Finish required plugin documentation. - [~] Finish required plugin documentation.
- [ ] Confirm project opens cleanly from a fresh checkout. - [ ] Confirm project opens cleanly from a fresh checkout.
- [ ] Create the core design document. - [ ] Create the core design document.
@@ -1433,4 +1434,4 @@ Earliest incomplete foundation items:
Immediate next item: Immediate next item:
- [ ] Create repeatable dedicated server build instructions. - [~] Finish required plugin documentation.
+73
View File
@@ -0,0 +1,73 @@
# Agrarian Dedicated Server Build Runbook
Agrarian's multiplayer server target is Linux. Windows-Builder remains the
interactive Unreal build machine, but the server artifact should run on an
Ubuntu cloud VM or other Linux host.
## Build Machine
Use Windows-Builder for the first repeatable build lane:
- Unreal Engine `5.7`
- VS 2022 Build Tools toolchain compatible with Unreal `5.7`
- Epic Linux cross-compile toolchain for Unreal `5.7`
- Project path: `P:\AgrarianGameBulid` when mapped from `\\DevBox\projects`
The server target is `AgrarianGameServer`, defined in
`Source/AgrarianGameServer.Target.cs`.
## Build Command
From an elevated or normal Command Prompt on Windows-Builder:
```bat
cd /d P:\AgrarianGameBulid
Scripts\BuildLinuxDedicatedServer-Windows.bat
```
Expected output:
- Logs: `Saved\BuildLogs\BuildLinuxDedicatedServer.log`
- Archive: `Builds\LinuxServerDevelopment`
If the script fails before compile with a Linux toolchain error, install Epic's
Unreal `5.7` Linux cross-compile toolchain on Windows-Builder, reopen the
terminal, and run the script again.
## Initial Runtime Shape
The first server package cooks the Ground Zero MVP map:
```text
/Game/Agrarian/Maps/L_GroundZeroTerrain_Test
```
First cloud/server launch target:
```bash
./AgrarianGameServer L_GroundZeroTerrain_Test?listen -log -port=7777
```
Open firewall ports only as needed:
- `7777/udp` for Unreal gameplay traffic.
- SSH from trusted admin IPs only.
Do not expose editor, SMB, RDP, database, or admin ports on the public server.
## Smoke Test
For the first MVP validation:
1. Build the Linux server package on Windows-Builder.
2. Copy the archived server package to an Ubuntu test VM.
3. Start the server with `-log -port=7777`.
4. Confirm the log reaches map load without fatal errors.
5. Connect from a packaged Windows Development client on the LAN or test VPN.
6. Record the commit, package date, map, client build, and server log path.
## Current Limits
This runbook creates the repeatable build lane. It does not yet prove a full
external multiplayer session. That remains a later roadmap item after the
project has a clean server package and a stable deploy target.
+76
View File
@@ -0,0 +1,76 @@
# Agrarian MVP Map Tile Delivery Server Runbook
The near-term tile server is intentionally simple: static files served by nginx
from an Ubuntu VM. This proves the contract for tile manifest lookup, package
download, checksums, local cache, and redownload before investing in a database
or application service.
## Build The Ground Zero Tile Package
On Ubuntu-Codex or any Linux machine with the repo mounted:
```bash
cd /mnt/projects/AgrarianGameBulid
Scripts/build_ground_zero_tile_delivery_package.sh
```
Output:
- `BuildArtifacts/TileDelivery/public/manifest.json`
- `BuildArtifacts/TileDelivery/public/ground_zero_tiles.json`
- `BuildArtifacts/TileDelivery/public/tiles/gz_us_ca_pacifica_utm10n_e544_n4160/v0/`
- `BuildArtifacts/TileDelivery/public/SHA256SUMS`
- `BuildArtifacts/TileDelivery/agrarian-ground-zero-tile-delivery.tar.gz`
`BuildArtifacts/` is a local build output and should not be committed.
## Bootstrap A New Ubuntu Tile Server
Copy the archive to a fresh Ubuntu VM, then run:
```bash
sudo AGRARIAN_TILE_SERVER_NAME=tiles.example.test \
Operations/cloud-map-tile-server/bootstrap_ubuntu_tile_server.sh \
/path/to/agrarian-ground-zero-tile-delivery.tar.gz
```
For an IP-only MVP test, omit `AGRARIAN_TILE_SERVER_NAME`.
The bootstrap installs nginx, creates:
```text
/srv/agrarian/tile-delivery/public
```
and publishes:
- `http://SERVER_IP/health`
- `http://SERVER_IP/manifest.json`
- `http://SERVER_IP/ground_zero_tiles.json`
- `http://SERVER_IP/tiles/gz_us_ca_pacifica_utm10n_e544_n4160/v0/...`
## Cost Control
Keep the MVP server small:
- Ubuntu LTS, smallest useful VM size.
- Static nginx only.
- No database for the first proof.
- No public write endpoints.
- No Unreal server process on the tile VM unless explicitly testing combined
hosting.
- Shut down or destroy the VM when not testing.
## Security Baseline
- Allow inbound `80/tcp` for the public MVP endpoint.
- Allow SSH only from trusted admin IPs.
- Add HTTPS with certbot when a real DNS name is assigned.
- Treat tile packages as immutable by version. Publish fixes as a new package
version instead of editing files in place.
## Next Proof
The next implementation step after this runbook is to launch the MVP cloud VM,
publish this static package, and prove lookup/download/cache/redownload behavior
from a representative client.
@@ -0,0 +1,69 @@
#!/usr/bin/env bash
set -Eeuo pipefail
SERVICE_NAME="${AGRARIAN_TILE_SERVICE_NAME:-agrarian-tile-delivery}"
SERVER_NAME="${AGRARIAN_TILE_SERVER_NAME:-_}"
WEB_ROOT="${AGRARIAN_TILE_WEB_ROOT:-/srv/agrarian/tile-delivery/public}"
ARCHIVE_PATH="${1:-}"
log() {
printf '[agrarian-tile-server] %s\n' "$*"
}
if [[ "${EUID}" -ne 0 ]]; then
printf 'Run this script as root or with sudo.\n' >&2
exit 1
fi
apt-get update
apt-get install -y nginx ca-certificates curl
mkdir -p "${WEB_ROOT}"
if [[ -n "${ARCHIVE_PATH}" ]]; then
if [[ ! -f "${ARCHIVE_PATH}" ]]; then
printf 'Tile package archive not found: %s\n' "${ARCHIVE_PATH}" >&2
exit 1
fi
tar -xzf "${ARCHIVE_PATH}" -C "${WEB_ROOT}"
fi
chown -R www-data:www-data "$(dirname "${WEB_ROOT}")"
cat > "/etc/nginx/sites-available/${SERVICE_NAME}" <<NGINX
server {
listen 80;
listen [::]:80;
server_name ${SERVER_NAME};
root ${WEB_ROOT};
index manifest.json;
access_log /var/log/nginx/${SERVICE_NAME}.access.log;
error_log /var/log/nginx/${SERVICE_NAME}.error.log;
add_header X-Content-Type-Options nosniff always;
add_header Cache-Control "public, max-age=300" always;
location = /health {
access_log off;
default_type text/plain;
return 200 "ok\n";
}
location / {
try_files \$uri =404;
}
}
NGINX
ln -sfn "/etc/nginx/sites-available/${SERVICE_NAME}" "/etc/nginx/sites-enabled/${SERVICE_NAME}"
rm -f /etc/nginx/sites-enabled/default
nginx -t
systemctl enable --now nginx
systemctl reload nginx
log "Tile delivery server ready."
log "Web root: ${WEB_ROOT}"
log "Health: http://SERVER_IP/health"
log "Manifest: http://SERVER_IP/manifest.json"
@@ -0,0 +1,84 @@
@echo off
setlocal
set "PROJECT_DIR=%~dp0.."
set "PROJECT_FILE=%PROJECT_DIR%\AgrarianGame.uproject"
set "UE_ROOT=C:\Program Files\Epic Games\UE_5.7"
set "RUN_UAT=%UE_ROOT%\Engine\Build\BatchFiles\RunUAT.bat"
set "BUILD_BAT=%UE_ROOT%\Engine\Build\BatchFiles\Build.bat"
set "ARCHIVE_DIR=%PROJECT_DIR%\Builds\LinuxServerDevelopment"
set "LOG_DIR=%PROJECT_DIR%\Saved\BuildLogs"
set "LOG_FILE=%LOG_DIR%\BuildLinuxDedicatedServer.log"
set "TARGET_MAP=/Game/Agrarian/Maps/L_GroundZeroTerrain_Test"
if not exist "%LOG_DIR%" mkdir "%LOG_DIR%"
if not exist "%ARCHIVE_DIR%" mkdir "%ARCHIVE_DIR%"
if not exist "%BUILD_BAT%" (
echo Unreal Engine 5.7 Build.bat was not found at:
echo %BUILD_BAT%
exit /b 1
)
if not exist "%RUN_UAT%" (
echo Unreal Engine 5.7 RunUAT was not found at:
echo %RUN_UAT%
exit /b 1
)
if not exist "%PROJECT_FILE%" (
echo Project file was not found at:
echo %PROJECT_FILE%
exit /b 1
)
echo Building Agrarian Linux dedicated server...
echo Archive: %ARCHIVE_DIR%
echo Log: %LOG_FILE%
echo.
echo This requires Epic's Linux cross-compile toolchain for Unreal 5.7 on Windows-Builder.
echo.
call "%BUILD_BAT%" AgrarianGameServer Linux Development -Project="%PROJECT_FILE%" -WaitMutex -NoUBA > "%LOG_FILE%" 2>&1
set "BUILD_EXIT_CODE=%ERRORLEVEL%"
type "%LOG_FILE%"
if not "%BUILD_EXIT_CODE%"=="0" (
echo.
echo Dedicated server target build failed with exit code %BUILD_EXIT_CODE%.
echo Log file: %LOG_FILE%
exit /b %BUILD_EXIT_CODE%
)
call "%RUN_UAT%" BuildCookRun ^
-project="%PROJECT_FILE%" ^
-noP4 ^
-server ^
-serverplatform=Linux ^
-serverconfig=Development ^
-noclient ^
-build ^
-cook ^
-stage ^
-pak ^
-archive ^
-archivedirectory="%ARCHIVE_DIR%" ^
-map=%TARGET_MAP% ^
-utf8output ^
-NoUBA >> "%LOG_FILE%" 2>&1
set "PACKAGE_EXIT_CODE=%ERRORLEVEL%"
type "%LOG_FILE%"
if not "%PACKAGE_EXIT_CODE%"=="0" (
echo.
echo Dedicated server package failed with exit code %PACKAGE_EXIT_CODE%.
echo Log file: %LOG_FILE%
exit /b %PACKAGE_EXIT_CODE%
)
echo.
echo Linux dedicated server package completed successfully.
echo Archive: %ARCHIVE_DIR%
echo.
exit /b 0
+94
View File
@@ -0,0 +1,94 @@
#!/usr/bin/env bash
set -Eeuo pipefail
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
TILE_ID="${AGRARIAN_TILE_ID:-gz_us_ca_pacifica_utm10n_e544_n4160}"
PACKAGE_VERSION="${AGRARIAN_TILE_PACKAGE_VERSION:-0}"
BUILD_ROOT="${PROJECT_ROOT}/BuildArtifacts/TileDelivery"
PUBLIC_ROOT="${BUILD_ROOT}/public"
PACKAGE_ROOT="${PUBLIC_ROOT}/tiles/${TILE_ID}/v${PACKAGE_VERSION}"
ARCHIVE_PATH="${BUILD_ROOT}/agrarian-ground-zero-tile-delivery.tar.gz"
log() {
printf '[agrarian-tile-package] %s\n' "$*"
}
require_file() {
local path="$1"
if [[ ! -f "${path}" ]]; then
printf 'Missing required file: %s\n' "${path}" >&2
exit 1
fi
}
REGISTRY="${PROJECT_ROOT}/Data/Tiles/ground_zero_tiles.json"
SCHEMA="${PROJECT_ROOT}/Data/Tiles/tile_registry.schema.json"
HEIGHTMAP="${PROJECT_ROOT}/Data/Terrain/Unreal/${TILE_ID}/${TILE_ID}_unreal_1009.r16"
HEIGHTMAP_META="${PROJECT_ROOT}/Data/Terrain/Unreal/${TILE_ID}/${TILE_ID}_unreal_heightmap_metadata.json"
TERRAIN_META="${PROJECT_ROOT}/Data/Terrain/Generated/${TILE_ID}/${TILE_ID}_terrain_metadata.json"
LANDFORM="${PROJECT_ROOT}/Data/Terrain/Analysis/${TILE_ID}/${TILE_ID}_landform_analysis.json"
WATER="${PROJECT_ROOT}/Data/Terrain/Analysis/${TILE_ID}/${TILE_ID}_water_shoreline_analysis.json"
EDGES="${PROJECT_ROOT}/Data/Terrain/Analysis/${TILE_ID}/${TILE_ID}_neighbor_edge_verification.json"
require_file "${REGISTRY}"
require_file "${SCHEMA}"
require_file "${HEIGHTMAP}"
require_file "${HEIGHTMAP_META}"
require_file "${TERRAIN_META}"
require_file "${LANDFORM}"
require_file "${WATER}"
require_file "${EDGES}"
rm -rf "${BUILD_ROOT}"
mkdir -p "${PACKAGE_ROOT}/terrain" "${PUBLIC_ROOT}/schemas"
cp "${REGISTRY}" "${PUBLIC_ROOT}/ground_zero_tiles.json"
cp "${SCHEMA}" "${PUBLIC_ROOT}/schemas/tile_registry.schema.json"
cp "${HEIGHTMAP}" "${PACKAGE_ROOT}/terrain/"
cp "${HEIGHTMAP_META}" "${PACKAGE_ROOT}/terrain/"
cp "${TERRAIN_META}" "${PACKAGE_ROOT}/terrain/"
cp "${LANDFORM}" "${PACKAGE_ROOT}/terrain/"
cp "${WATER}" "${PACKAGE_ROOT}/terrain/"
cp "${EDGES}" "${PACKAGE_ROOT}/terrain/"
cat > "${PUBLIC_ROOT}/manifest.json" <<JSON
{
"service": "agrarian-tile-delivery",
"schema_version": 1,
"environment": "mvp",
"default_tile_id": "${TILE_ID}",
"tiles_registry": "/ground_zero_tiles.json",
"tile_packages": [
{
"tile_id": "${TILE_ID}",
"package_version": ${PACKAGE_VERSION},
"status": "mvp_static_package",
"base_url": "/tiles/${TILE_ID}/v${PACKAGE_VERSION}/",
"terrain": {
"heightmap_r16": "terrain/${TILE_ID}_unreal_1009.r16",
"heightmap_metadata": "terrain/${TILE_ID}_unreal_heightmap_metadata.json",
"terrain_metadata": "terrain/${TILE_ID}_terrain_metadata.json",
"landform_analysis": "terrain/${TILE_ID}_landform_analysis.json",
"water_shoreline_analysis": "terrain/${TILE_ID}_water_shoreline_analysis.json",
"neighbor_edge_verification": "terrain/${TILE_ID}_neighbor_edge_verification.json"
}
}
]
}
JSON
(
cd "${PUBLIC_ROOT}"
find . -type f ! -name SHA256SUMS -print0 | sort -z | xargs -0 sha256sum > SHA256SUMS
)
# The project usually lives on a CIFS-mounted Unraid share. Give copied files a
# short settle window before tar reads them, or GNU tar can report false
# "file changed as we read it" warnings on the network filesystem.
sleep 3
tar -C "${PUBLIC_ROOT}" -czf "${ARCHIVE_PATH}" .
log "Package complete: ${ARCHIVE_PATH}"
log "Static root: ${PUBLIC_ROOT}"
log "Manifest: ${PUBLIC_ROOT}/manifest.json"
+15
View File
@@ -0,0 +1,15 @@
// Copyright Epic Games, Inc. All Rights Reserved.
using UnrealBuildTool;
using System.Collections.Generic;
public class AgrarianGameServerTarget : TargetRules
{
public AgrarianGameServerTarget(TargetInfo Target) : base(Target)
{
Type = TargetType.Server;
DefaultBuildSettings = BuildSettingsVersion.V6;
IncludeOrderVersion = EngineIncludeOrderVersion.Unreal5_7;
ExtraModuleNames.Add("AgrarianGame");
}
}