Skip to content

ROWS

ROWS is a single-binary Rust reimplementation of the OWS (Open World Server) game backend. It consolidates the five .NET microservices (PublicAPI, InstanceManagement, CharacterPersistence, GlobalData, Management) into one unified service with both REST and gRPC interfaces.

  • REST API (Axum) — player-facing endpoints: login, registration, character CRUD, zone connections
  • gRPC (Tonic) — internal service-to-service communication and UE5 dedicated server coordination
  • RabbitMQ — async job queue for instance lifecycle events (spin-up, shutdown, health checks)
  • PostgreSQL — persistent storage for accounts, characters, abilities, world state
  • ValKey — session cache and ephemeral game state
  • Agones — game server fleet management for UE5 dedicated server instances
GroupPath PrefixDescription
Auth/api/users/*Login, register, session management
Characters/api/characters/*Character CRUD, class selection
Zones/api/zones/*Zone listing, server-to-connect-to
Instance/api/instance/*Server instance lifecycle
Global/api/global/*Key/value world state
Health/health, /readyLiveness and readiness probes
gRPCPort 50051Internal service mesh

ROWS deploys as a single Docker image (ghcr.io/kbve/rows) into the ows Kubernetes namespace. ArgoCD syncs the manifest from apps/kube/ows/manifest/rows-deployment.yaml with auto-prune and self-heal enabled.

The container exposes:

  • Port 4322 — REST + gRPC multiplexed (Axum + Tonic on a single port)

Procedural World — Seed-Based Multi-Zone Architecture

Section titled “Procedural World — Seed-Based Multi-Zone Architecture”

Each game zone is a procedurally generated region driven by a deterministic seed. The same seed always produces identical terrain, foliage, and spawn layouts. This enables:

  • One map, many worlds — a single Lvl_Procedural map generates different zones from different seeds
  • Elastic scaling — any server pod can host any zone, just give it a seed
  • Crash recovery — replace a dead server, give it the same seed, world is identical
  • Discovery — new zones are just new seeds, no additional map packaging required

The maps table gains a seed column:

ALTER TABLE ows.maps ADD COLUMN seed BIGINT DEFAULT 0;
-- Example zones
INSERT INTO maps (customerguid, mapname, zonename, seed) VALUES
('83d88046-...', 'Lvl_Procedural', 'Grassland', 0xA1B2C3D4),
('83d88046-...', 'Lvl_Procedural', 'Arctic', 0xDEAD0002),
('83d88046-...', 'Lvl_Procedural', 'Desert', 0xCAFE0003),
('83d88046-...', 'Lvl_Procedural', 'Marshlands', 0xBEEF0004),
('83d88046-...', 'Lvl_PvPArena', 'PvPArena', 0); -- static map, no seed
1. Player → GetServerToConnectTo(zoneName: "Arctic")
2. ROWS → Agones allocate → server starts on Entry
3. ROWS → GetZoneAssignment returns:
{
"assigned": true,
"mapName": "Lvl_Procedural",
"zoneName": "Arctic",
"seed": 3735552002,
"zoneInstanceId": 42
}
4. Server → ServerTravel("/Game/Procedural/Lvl_Procedural?listen?seed=3735552002")
5. Lvl_Procedural BeginPlay → reads seed → PCG generates Arctic biome
6. Server reports ready → players connect to deterministic world

PCG (Procedural Content Generation) Framework:

LayerDriven ByExamples
Terrain heightmapSeed + biome typeMountain ranges, valleys, coastlines
Biome selectionSeed bits [0:7]Grassland, Arctic, Desert, Marshland, Tropic
Foliage placementSeed + density rulesTrees, bushes, grass patches
Resource nodesSeed + spawn tablesOre veins, herb clusters, fishing spots
Mob spawnsSeed + difficulty curveCreature type, patrol routes, density
LandmarksFixed coordinatesTowns, dungeons, POIs (handcrafted, placed at deterministic positions)
WeatherSeed + time-of-dayRain cycles, fog density, wind patterns

Hybrid approach:

  • Handcrafted landmarks are pre-built actors placed at coordinates derived from the seed
  • Procedural fill generates the terrain and natural environment between landmarks
  • Biome blending uses seed-derived Voronoi regions for smooth transitions

GameMode seed consumption:

// In Lvl_Procedural's GameMode BeginPlay
FString SeedStr = UGameplayStatics::ParseOption(OptionsString, TEXT("seed"));
int64 Seed = FCString::Atoi64(*SeedStr);
FRandomStream WorldRNG(Seed);
// Feed to PCG subsystem
UPCGSubsystem* PCG = GetWorld()->GetSubsystem<UPCGSubsystem>();
PCG->SetGlobalSeed(Seed);

Players move between zones via zone portals or world map travel:

Player enters Arctic→Desert portal
→ Client calls SetSelectedCharacterAndGetUserSession
→ Client calls GetServerToConnectTo(zoneName: "Desert")
→ ROWS finds/allocates Desert server (seed: 0xCAFE0003)
→ Client disconnects from Arctic, connects to Desert
→ Character position saved on Arctic, loaded on Desert

Seeds can be:

  • Static — admin-created zones with curated seeds (main world regions)
  • Dynamic — player-triggered instanced content (dungeons, events) with random seeds
  • Seasonal — time-limited zones that rotate seeds periodically
GET /api/System/SeedRegistry
{
"zones": [
{ "zoneName": "Grassland", "seed": 2712847316, "type": "static", "biome": "grassland" },
{ "zoneName": "Arctic", "seed": 3735552002, "type": "static", "biome": "arctic" },
{ "zoneName": "Dungeon_42", "seed": 8827361024, "type": "dynamic", "biome": "cave", "expires": "2026-04-01T00:00:00Z" }
]
}
PhaseScopeDependencies
Phase 1Add seed column to maps table, include in GetZoneAssignment responsedbmate migration
Phase 2Lvl_Procedural map with basic PCG — terrain heightmap from seedUE5 PCG framework
Phase 3Biome system — seed bits select biome, PCG generates appropriate flora/faunaBiome data tables
Phase 4Handcrafted landmarks — POI actors placed at seed-derived coordinatesLevel design
Phase 5Zone portals — client-side travel between seed-based zonesOWS travel flow
Phase 6Dynamic instances — player-triggered dungeons with random seedsInstance lifecycle
Phase 7Seed registry API — admin tools for zone managementDashboard integration