neon-sprawl/client
VinPropane 3882b0e2c6 NS-16: MoveCommand → server PositionState, Godot sync, tests
Implement E1.M1 intent → authority: POST /game/players/{id}/move with v1 JSON
MoveCommandRequest (snap + sequence), extend in-memory store and
PositionStateApi. Godot client splits ground_pick and position_authority_client
with thin main.gd; snap_to_server on player.

Tests live under NeonSprawl.Server.Tests/Game/PositionState/ with AAA layout
and MethodName_ShouldExpectedOutcome_WhenScenario naming. Debug builds use
UseAppHost=false so Linux IDEs resolve .NET 10 from a user-local SDK.

Add NS-16 implementation plan, code review doc, godot-client-script-organization
rule, csharp test layout/naming rules, and refresh E1.M1 / alignment docs.
Server and client README updates include move API, prerequisites, and Rider
notes.

Made-with: Cursor
2026-03-30 19:54:17 -04:00
..
scenes NS-16: MoveCommand → server PositionState, Godot sync, tests 2026-03-30 19:54:17 -04:00
scripts NS-16: MoveCommand → server PositionState, Godot sync, tests 2026-03-30 19:54:17 -04:00
README.md NS-16: MoveCommand → server PositionState, Godot sync, tests 2026-03-30 19:54:17 -04:00
icon.svg Update README and documentation to reflect project rebranding to "Neon Sprawl". Revise links to vision plan and adjust references in tech stack and decomposition documents. Enhance README with repository layout and instructions for running the server and client. 2026-03-29 17:23:00 -04:00
icon.svg.import fix(client): reliable NS-14 click-to-move without NavigationMesh 2026-03-29 22:08:25 -04:00
project.godot fix(client): reliable NS-14 click-to-move without NavigationMesh 2026-03-29 22:08:25 -04:00

README.md

Neon Sprawl — Godot client

Open this client/ directory as a project in Godot 4.6 (4.x compatible). Use the standard Godot build (not the .NET build)—client code is GDScript (.gd).

  • Main scene: scenes/main.tscn (bootstrap scripts/main.gd).
  • Networking will use WebSocket or TCP to the C# server; authoritative logic stays on the server per docs/architecture/tech_stack.md.

Script organization (repo policy)

Do not grow an all-in-one main.gd. The main scene root should compose child nodes and scripts; put picking, server sync, and similar features in dedicated scripts (typically under scripts/) and connect via signals or small APIs. Use Autoloads only when several scenes truly need the same global. Full guidance for contributors and tooling: .cursor/rules/godot-client-script-organization.md.

Authoritative movement (NS-16)

With the game server running (server/README.md), the client sends a MoveCommand over HTTP and snaps the avatar to the servers PositionState after a follow-up GET.

  • Scripts: scripts/ground_pick.gd (walkable pick + target_chosen), scripts/position_authority_client.gd (PositionAuthorityClient: POST move, GET verify), thin scripts/main.gd wiring.
  • Inspector: select PositionAuthorityClient on the main scene to set base_url (default http://127.0.0.1:5253) and dev_player_id (default dev-local-1, must match server Game:DevPlayerId).
  • On startup, sync_from_server() runs once so the capsule matches the server before you click.

Manual check (NS-16)

  1. From repo root: cd server/NeonSprawl.Server && dotnet run (note the URL/port, usually http://localhost:5253).
  2. If the port differs, set base_url on PositionAuthorityClient accordingly (e.g. http://127.0.0.1:5253).
  3. Open the client in Godot and run the main scene (F5). The player should jump to the servers default position (e.g. origin).
  4. Left-click the floor: the client POSTs the target, then GETs position; the avatar snaps to the authoritative coordinates (no client-side walk to the click).

If the server is down, boot GET fails silently (check Output for warnings); clicks while a request is in flight are ignored until it finishes.

Movement prototype (NS-14, legacy local steering)

The CharacterBody3D still uses horizontal steering + move_and_slide() in player.gd, but NS-16 drives placement via snap_to_server() after each successful sync, so you will mostly see snapping, not walking to the click. Obstacle sliding from NS-14 applies only if local goals diverge from server snaps in future work.

  • The avatar is on physics layer 2 with mask 1 (floor + obstacle on layer 1); the pick ray uses mask 1 so clicks pass through the avatar and hit the floor.

Manual check (NS-14 remnants)

  1. Run the main scene (F5) with server running for NS-16 behavior above.
  2. Without the server, startup sync does not apply authoritative position; behavior is undefined for this repos intended demo—run the server for NS-16.

Clicks still ignored?

In the Game dock, Input must be active (not the 2D / 3D scene-picking tools) so events go to the game. If Input is on and clicks still do nothing, pick rays must use the viewports current camera and mouse position (the script does this so the embedded Game view matches the ray).

First run

  1. Install Godot 4.x.
  2. In the project manager, Import and select client/project.godot.
  3. Press F5 to run the main scene.

Godot CLI (Linux smoke test)

For agents and CI, use the official Linux x86_64 editor binary (matches config/features 4.6 in project.godot):

  1. Download Godot_v4.6-stable_linux.x86_64.zip from the 4.6-stable release.
  2. Unzip and put the binary on your PATH, e.g. ~/.local/opt/godot-4.6-stable/ and ln -s …/Godot_v4.6-stable_linux.x86_64 ~/.local/bin/godot.
  3. Ensure ~/.local/bin is on PATH, then from client/:
godot --version
godot --headless --path . --quit-after 5

A clean checkout has client/.godot/ gitignored, so scripts intentionally avoid class_name global types that require a full editor import before headless can resolve them.