From 1a0fb122869a44c5d99bc89f1ade5b0e3afb89ee Mon Sep 17 00:00:00 2001 From: nathan Date: Thu, 14 May 2026 13:16:38 -0700 Subject: [PATCH] Document dedicated server and tile delivery builds --- .gitignore | 1 + AGRARIAN_DEVELOPMENT_ROADMAP.md | 11 ++- Docs/Ops/DedicatedServerBuildRunbook.md | 73 ++++++++++++++ Docs/Ops/MapTileDeliveryServerRunbook.md | 76 +++++++++++++++ .../bootstrap_ubuntu_tile_server.sh | 69 ++++++++++++++ Scripts/BuildLinuxDedicatedServer-Windows.bat | 84 +++++++++++++++++ ...build_ground_zero_tile_delivery_package.sh | 94 +++++++++++++++++++ Source/AgrarianGameServer.Target.cs | 15 +++ 8 files changed, 418 insertions(+), 5 deletions(-) create mode 100644 Docs/Ops/DedicatedServerBuildRunbook.md create mode 100644 Docs/Ops/MapTileDeliveryServerRunbook.md create mode 100755 Operations/cloud-map-tile-server/bootstrap_ubuntu_tile_server.sh create mode 100644 Scripts/BuildLinuxDedicatedServer-Windows.bat create mode 100755 Scripts/build_ground_zero_tile_delivery_package.sh create mode 100644 Source/AgrarianGameServer.Target.cs diff --git a/.gitignore b/.gitignore index 6038d99..073ff60 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ Saved/ # Build outputs Build/ Builds/ +BuildArtifacts/ *.sln *.sln.DotSettings.user *.VC.db diff --git a/AGRARIAN_DEVELOPMENT_ROADMAP.md b/AGRARIAN_DEVELOPMENT_ROADMAP.md index 29acc7e..f9e5fc3 100644 --- a/AGRARIAN_DEVELOPMENT_ROADMAP.md +++ b/AGRARIAN_DEVELOPMENT_ROADMAP.md @@ -175,7 +175,7 @@ Remaining version 0.01 cleanup before moving deeper into new gameplay: - [x] Define backup expectations for NAS and repository. - [x] Implement Linastorage incremental project backup job. - [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. - [ ] 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. @@ -213,7 +213,7 @@ Goal: Prepare the project so all future development is controlled, recoverable, - [x] Decide build machine strategy. - [x] Create repeatable local build instructions. - [x] Create repeatable packaged build instructions. -- [ ] Create repeatable dedicated server build instructions. +- [x] Create repeatable dedicated server build instructions. - [~] Document required plugins. - [x] Disable unneeded plugins. - [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 server-side tile delivery protocol. - [ ] 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. - [ ] 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. @@ -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] Store editor build logs under `Saved/BuildLogs/BuildEditor-Windows.log`. - [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] Add smoke-test command for build artifacts. - [ ] 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] Implement Linastorage incremental project backup job. - [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. - [ ] Confirm project opens cleanly from a fresh checkout. - [ ] Create the core design document. @@ -1433,4 +1434,4 @@ Earliest incomplete foundation items: Immediate next item: -- [ ] Create repeatable dedicated server build instructions. +- [~] Finish required plugin documentation. diff --git a/Docs/Ops/DedicatedServerBuildRunbook.md b/Docs/Ops/DedicatedServerBuildRunbook.md new file mode 100644 index 0000000..cd6aa81 --- /dev/null +++ b/Docs/Ops/DedicatedServerBuildRunbook.md @@ -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. diff --git a/Docs/Ops/MapTileDeliveryServerRunbook.md b/Docs/Ops/MapTileDeliveryServerRunbook.md new file mode 100644 index 0000000..d6ea9ce --- /dev/null +++ b/Docs/Ops/MapTileDeliveryServerRunbook.md @@ -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. diff --git a/Operations/cloud-map-tile-server/bootstrap_ubuntu_tile_server.sh b/Operations/cloud-map-tile-server/bootstrap_ubuntu_tile_server.sh new file mode 100755 index 0000000..cf8ce37 --- /dev/null +++ b/Operations/cloud-map-tile-server/bootstrap_ubuntu_tile_server.sh @@ -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}" < "%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 diff --git a/Scripts/build_ground_zero_tile_delivery_package.sh b/Scripts/build_ground_zero_tile_delivery_package.sh new file mode 100755 index 0000000..a6938a1 --- /dev/null +++ b/Scripts/build_ground_zero_tile_delivery_package.sh @@ -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" < 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" diff --git a/Source/AgrarianGameServer.Target.cs b/Source/AgrarianGameServer.Target.cs new file mode 100644 index 0000000..becc628 --- /dev/null +++ b/Source/AgrarianGameServer.Target.cs @@ -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"); + } +}