5.6 KiB
Game server (NeonSprawl.Server)
ASP.NET Core .NET 10 host for authoritative simulation (prototype: HTTP + health + position state via in-memory or PostgreSQL).
Prerequisites
- .NET 10 SDK (matches
TargetFrameworkinNeonSprawl.Server.csproj). Check withdotnet --list-sdks.
Run
cd server/NeonSprawl.Server
dotnet run
- Default URL is printed by Kestrel (see
Properties/launchSettings.json, typicallyhttp://localhost:5253). - Check
GET /healthfor a JSON heartbeat.
Position persistence (NS-17)
When ConnectionStrings:NeonSprawl is set to a valid PostgreSQL connection string, the server uses the player_position table (relational columns pos_x … sequence, not JSONB). DDL lives in server/db/migrations/V001__player_position.sql; the app applies that script on startup and on first store use (idempotent CREATE TABLE IF NOT EXISTS). The configured dev player (Game:DevPlayerId / Game:DefaultPosition) is seeded once at host startup, matching the in-memory store’s constructor seed (not on every HTTP request).
If ConnectionStrings:NeonSprawl is missing or blank, behavior matches NS-15/NS-16 (in-memory only). This keeps dotnet test without Postgres viable for fast checks; override any process-level env in tests when you need in-memory (see InMemoryWebApplicationFactory in the test project).
Environment variables (typical — same mapping as other ASP.NET Core config):
| Mechanism | Example |
|---|---|
| Shell / CI | export ConnectionStrings__NeonSprawl='Host=localhost;Port=5432;Database=neon_sprawl;Username=neon_sprawl;Password=neon_sprawl_dev' |
| User secrets | dotnet user-secrets set ConnectionStrings:NeonSprawl "<connection string>" (run from server/NeonSprawl.Server) |
Match credentials with root docker-compose.yml for local development.
Restart check (Jira AC): start Postgres (docker compose up -d from repo root), set the connection string, dotnet run, POST …/move, stop the server, dotnet run again, GET …/position should return the last committed state.
Postgres integration tests require ConnectionStrings__NeonSprawl (set automatically in .github/workflows/dotnet.yml). Locally: export the same value while Postgres is listening, then dotnet test NeonSprawl.sln.
Position state (NS-15)
Authoritative player position is served over HTTP whether the backing store is in memory or PostgreSQL (NS-17). The HTTP JSON shape is versioned with top-level schemaVersion (see XML docs on PositionStateResponse in the server project). Path {id} is trimmed and matched case-insensitively against stored players; playerId in the JSON body echoes the path segment from the request. Stored player ids use invariant lowercase + trim in Postgres for lookup parity.
Example (dev player id defaults to dev-local-1 in appsettings.json):
curl -s http://localhost:5253/game/players/dev-local-1/position
Sample response:
{"schemaVersion":1,"playerId":"dev-local-1","position":{"x":0,"y":0,"z":0},"sequence":0}
Unknown player ids return 404. Full zone sync / replication is still out of scope for these spikes.
Move command (NS-16)
POST /game/players/{id}/move with JSON body applies a v1 MoveCommand: authoritative position snaps to target immediately; sequence in responses increases by one per successful apply.
Request body (example):
curl -s -X POST http://localhost:5253/game/players/dev-local-1/move \
-H "Content-Type: application/json" \
-d '{"schemaVersion":1,"target":{"x":1.5,"y":0,"z":-2}}'
- 200 — body matches
PositionStateResponse(same shape asGET…/position). - 400 — missing/invalid body or
schemaVersion≠1. - 404 — unknown player id.
See XML on MoveCommandRequest and PositionStateResponse in the server project.
For a PR/Jira-ready contract blurb (formatted JSON + field table), see the NS-15 implementation plan — Pull request description (GET shape) and NS-16 implementation plan (MoveCommand + sequence semantics).
Solution
From repo root: dotnet build NeonSprawl.sln and dotnet test NeonSprawl.sln.
CI
Pull requests targeting main run build and tests via .github/workflows/dotnet.yml on GitHub Actions (ubuntu-latest runner, Release configuration).
Linux + Rider: “only 8.x in /usr/share/dotnet”
If the debugger prints .NET location: /usr/share/dotnet and cannot find Microsoft.NETCore.App 10.x while you have .NET 10 under ~/.dotnet:
launchSettings.jsonenvironmentVariables(e.g.DOTNET_ROOT) often do not apply to the native apphost Rider launches first; the host probes/usr/share/dotnetbefore your app starts.- This repo sets
<UseAppHost>false</UseAppHost>for Debug builds so the IDE runsdotnet …/NeonSprawl.Server.dllusing the .NET CLI you configured in the toolchain (/home/don/.dotnet/dotnet), which then loads the 10.x shared runtime from the same install. - Alternatives: install .NET 10 into the default location so
/usr/share/dotnethas 10.x, or addDOTNET_ROOT=/home/don/.dotnetin Run → Edit Configurations → Environment variables (IDE-level, not onlylaunchSettings.json).