Files
Battle-for-Tismo/AGENTS.md
T
adrien c49899a2fd Initial commit
Server-authoritative Godot 4.6 strategy game.

Includes the headless WebSocket game server, the browser client, and
Nix packaging (server and web-export derivations plus a NixOS module)
for deployment.
2026-09-15 14:48:34 +02:00

4.9 KiB

AGENTS.md

Godot 4.6 GDScript strategy game, early-stage (most gameplay is stubbed).

Commands

  • Validate / reimport after edits: godot --headless --path . --import
  • Run the test suite: godot --headless --path . res://tests/test_runner.tscn (prints a summary and exits non-zero on failure)
  • Parse-check a single script: godot --headless --path . --check-only --script res://scenes/units/unit.gd
  • Run a scene directly: godot --path . res://scenes/ui/menu_screen.tscn
  • Profile the headless server (prints a report every N seconds): godot --headless --path . res://scenes/server_main.tscn -- --server --profile-interval 5. A client's --profile-interval is forwarded to the server it spawns, and F3 on the client prints/clears its own report. F4 prints the PerformanceMonitor report (FPS-dive diagnostics plus the recent action log) without clearing it; the HUD also prints one automatically when the frame rate dives.
  • There is no linter, formatter, or CI. Do not invent commands beyond the ones listed here.
  • godot --path . with no scene fails: project.godot sets no application/run/main_scene. Pass a scene path or set the main scene in the editor.
  • --check-only does not load autoloads, so scripts referencing GameClock, GameConfig or Network report false "Identifier not found" errors. Prefer --import plus the test suite for real validation.

Gotchas

  • Renderer is gl_compatibility (not Forward+) and 3D uses Jolt Physics. GL Compatibility omits Forward+ only features.
  • .uid files are Godot-maintained; keep them paired with their scripts, never hand-edit or delete. .godot/ is generated and gitignored.
  • Indent .gd files with tabs (Godot default). .editorconfig only enforces UTF-8.
  • scenes/world_map.tscn uses TileMapLayer (scene format=4), not the deprecated TileMap.
  • Multiplayer uses WebSocketMultiplayerPeer (HTTP), not ENet/UDP, so the browser client can reach the same server. The dedicated server listens on --port (default 27015) and binds to --bind (default 127.0.0.1, i.e. reverse-proxy only); the client defaults to the page's own origin on the web and ws://127.0.0.1:27015/ws on desktop. Join accepts a bare hostname or a full ws(s):///http(s):// URL.
  • Export templates must match the engine: use godot_4_6 with godot_4_6-export-templates-bin from nixpkgs.

Architecture

  • Game logic is server-authoritative. scripts/server/game_state.gd (GameState) is a scene-free model that owns the world, units, cities, territory, economy, training and visibility. scripts/server/game_server.gd (GameServer) is the root of the headless server (scenes/server_main.tscn); it owns a GameState, validates orders and broadcasts snapshots. Network (autoload) carries orders up and snapshots down. scenes/world_map.gd is a view only: it rebuilds terrain from the shared seed, renders snapshots and sends orders (falling back to a local GameState when run standalone).
  • Movement is continuous: the server calls GameState.advance_movement(delta / GameClock.SECONDS_PER_HOUR) every frame and tick_hour() on each hour for training/visibility/economy; advance_hour() bundles both for tests and offline play. The client extrapolates each unit along its snapshot path (see world_map.gd:_apply_unit_position) so motion stays smooth between hourly snapshots, and predicts move orders locally (_predict_path, mirroring GameState.find_path) so a click feels instant before the server confirms it.
  • Data-driven resources: class_name scripts in data/*.gd (CivDescription, ProtoUnit) define schemas; concrete instances are .tres under data/civilisations/ and data/units/. Add content as new .tres files, not hardcoded values.
  • Scenes are grouped by area: scenes/, scenes/ui/, scenes/units/. Reusable scenes attach a class_name script (e.g. Unit).
  • Reusable logic lives in class_name scripts under scripts/classes/ (MapGenerator, MapTopology, HexPathfinder, TextFormat); keep new algorithms there so they stay testable without a running scene.
  • scenes/map_overlay.gd (MapOverlay) is the shared base for the tile overlays Territory and FogOfWar; put layer/topology/geometry plumbing there, not in the subclasses.
  • Tests live in tests/ as *_test.gd files extending the TestCase base in tests/framework/. tests/test_runner.gd (run via tests/test_runner.tscn) discovers and runs them. Add a new tests/<topic>_test.gd for each new pure or class_name behaviour.

Deployment

  • flake.nix exposes packages.<system>.server and .web, plus nixosModules.default. nix/module.nix runs the server as a services.battle-for-tismo systemd unit and serves the web client through nginx, proxying /ws to the local server. The web client connects to the page's own origin.
  • Build locally with nix build .#server and nix build .#web; both use godot_4_6 and its matching export templates from the flake's pinned nixpkgs.