From 4d1a29bcc18e49a06651f48558dcecd6ff95f0cc Mon Sep 17 00:00:00 2001 From: Jeroen Schweitzer Date: Mon, 23 Mar 2026 19:04:06 +0100 Subject: [PATCH] chore(config): add gdlint + gdformat + cargo-deny to pre-push hook Pre-push now runs 6 checks: - GDScript: parse check, gdlint (static analysis), gdformat (style) - Rust: clippy, fmt, cargo deny (license/advisory/deps) All tools degrade gracefully if not installed. Also files Q-065 through Q-080: shooting mechanics, procedural terrain, cloth sim, vehicle physics, PathMesh3D, NobodyWho vs voice pipeline, BitTorrent distribution, BehaviourToolkit patterns, screenshot manager, RichText3D, DeformableMesh, GridMapLayer, mod loader, god rays, Steam multiplayer, CityCrafter3D, planet generator. Co-Authored-By: Claude Opus 4.6 --- .config/hooks/pre-push | 40 +++++++++- decisions/questions-architecture.md | 114 +++++++++++++++++++++++++++- 2 files changed, 149 insertions(+), 5 deletions(-) diff --git a/.config/hooks/pre-push b/.config/hooks/pre-push index 802ef617a..d7f7762b5 100755 --- a/.config/hooks/pre-push +++ b/.config/hooks/pre-push @@ -8,20 +8,42 @@ ERRORS=0 echo "pre-push: running lint checks..." -# --- GDScript lint (headless Godot parse check) --- +# --- GDScript parse check (headless Godot) --- GODOT="${GODOT:-godot}" if command -v "$GODOT" >/dev/null 2>&1; then - echo "pre-push: checking GDScript..." + echo "pre-push: checking GDScript (parse)..." SCRIPT_ERRORS=$("$GODOT" --headless --path "$REPO_ROOT/client" --quit 2>&1 | grep -ci "SCRIPT ERROR" || true) if [ "$SCRIPT_ERRORS" -gt 0 ]; then echo "pre-push: FAIL — $SCRIPT_ERRORS GDScript error(s) found" "$GODOT" --headless --path "$REPO_ROOT/client" --quit 2>&1 | grep -i "SCRIPT ERROR" ERRORS=$((ERRORS + 1)) else - echo "pre-push: GDScript — OK" + echo "pre-push: GDScript parse — OK" fi else - echo "pre-push: WARNING — Godot not found, skipping GDScript lint" + echo "pre-push: WARNING — Godot not found, skipping GDScript parse check" +fi + +# --- GDScript lint (gdlint static analysis) — advisory only until codebase is clean --- +if command -v gdlint >/dev/null 2>&1; then + echo "pre-push: checking GDScript (gdlint — advisory)..." + LINT_COUNT=$(gdlint "$REPO_ROOT/client/scripts/" "$REPO_ROOT/client/ui/" 2>&1 | grep -c "Error:" || true) + if [ "$LINT_COUNT" -gt 0 ]; then + echo "pre-push: gdlint — $LINT_COUNT issue(s) (advisory, not blocking)" + else + echo "pre-push: gdlint — OK" + fi +fi + +# --- GDScript format check (gdformat) — advisory only until codebase is clean --- +if command -v gdformat >/dev/null 2>&1; then + echo "pre-push: checking GDScript (gdformat — advisory)..." + FORMAT_COUNT=$(gdformat --check "$REPO_ROOT/client/scripts/" "$REPO_ROOT/client/ui/" 2>&1 | grep -c "would reformat" || true) + if [ "$FORMAT_COUNT" -gt 0 ]; then + echo "pre-push: gdformat — $FORMAT_COUNT file(s) need formatting (advisory, not blocking)" + else + echo "pre-push: gdformat — OK" + fi fi # --- Rust lint (clippy + fmt) --- @@ -39,6 +61,16 @@ if command -v cargo >/dev/null 2>&1 && [ -d "$REPO_ROOT/server" ]; then else echo "pre-push: fmt — OK" fi + + # --- Rust dependency audit (cargo deny) — requires deny.toml config --- + if command -v cargo-deny >/dev/null 2>&1 && [ -f "$REPO_ROOT/server/deny.toml" ]; then + echo "pre-push: checking Rust (cargo deny)..." + if ! (cd "$REPO_ROOT/server" && cargo deny check 2>&1); then + ERRORS=$((ERRORS + 1)) + else + echo "pre-push: cargo deny — OK" + fi + fi else echo "pre-push: WARNING — cargo not found or server/ missing, skipping Rust lint" fi diff --git a/decisions/questions-architecture.md b/decisions/questions-architecture.md index ef81e0278..3e62bb777 100644 --- a/decisions/questions-architecture.md +++ b/decisions/questions-architecture.md @@ -115,4 +115,116 @@ Technical foundation questions: engine, protocols, data structures, performance, --- -*16 questions (7 resolved, 1 partially resolved, 8 open). Last updated: 2026-03-23.* +### Q-065: Shooting mechanics — Deep RayCast 3D vs Ballistic Penetration System vs server-side +- **Status:** Open +- **Question:** Evaluate approaches for projectile/hitscan combat mechanics. Three options: (a) Deep RayCast 3D (https://godotengine.org/asset-library/asset/4464) — penetrating raycasts through multiple objects, chain hits, laser effects. (b) Ballistic Penetration System (https://godotengine.org/asset-library/asset/4356) — physics-based damage reduction through materials (thickness, hardness, penetration depth). (c) Roll our own server-side in Rust/bevy_ecs since combat is server-authoritative. Key question: should hit detection and damage calculation live on the client (these plugins) or the server (D-010 server authority)? Could the client use these for visual feedback (tracer rendering, impact effects) while the server handles the authoritative hit/damage calculation? +- **Cross-reference:** D-010 (server-authoritative simulation), D-012 (client is a view) + +--- + +### Q-066: PathMesh3D for procedural environment geometry +- **Status:** Open +- **Question:** Evaluate PathMesh3D (https://godotengine.org/asset-library/asset/3626) — extrudes 2D profiles along 3D paths at runtime to create meshes. C++ GDExtension, MIT licensed. Potential uses: procedural pipes/cables/wiring in station interiors, rail/track generation, corridor geometry, any environment element that follows a path. Not clear yet where this fits in the pipeline — could be a generator-time tool or a runtime decoration system. Worth investigating when environment procedural generation starts. +- **Cross-reference:** Generator architecture, environment asset pipeline + +--- + +### Q-067: Vehicle physics for in-world transport +- **Status:** Open +- **Question:** Evaluate vehicle physics plugins for player/NPC transport between zones. Two candidates: (a) MAdvanced Vehicle System (https://godotengine.org/asset-library/asset/3697) — full car physics with gearbox, AI traffic, traffic management, lights, sounds, steering wheel support. Godot 4.6, MIT, actively updated. (b) Godot Simple Motorcycle Physics (https://godotengine.org/asset-library/asset/4670) — raycast-based motorcycle, simpler scope. Questions: does the game need driveable vehicles or just NPC traffic? Is vehicle movement client-side physics or server-authoritative? The AI traffic and traffic management in MAdvanced could serve NPC vehicle simulation. Scope for v0.2: probably not, but worth tracking for when districts/zones need inter-zone travel. +- **Cross-reference:** D-010 (server authority), world generation + +--- + +### Q-068: Procedural terrain generation patterns — chunk loading and noise +- **Status:** Open (reference/inspiration) +- **Question:** Block-based 3D Procedural Map Generation Demo (https://godotengine.org/asset-library/asset/2698) — Perlin noise terrain with chunk-based loading/unloading. Not directly usable (block-based, Godot 4.2) but the patterns are relevant: seed-deterministic generation for consistent worlds across sessions, chunk loading within player proximity for memory/performance, terrain type placement from noise values. Reference for when the world generator produces location terrain and the client needs to stream it. The chunk load/unload pattern maps to our simulation tier system (Active → Background → State-saved). +- **Cross-reference:** Generator architecture, D-097 (simulation tiers), D-096 (chunk loading) + +--- + +### Q-069: GPU cloth simulation for dynamic clothing +- **Status:** Open +- **Question:** Evaluate GPU Cloth Simulation (https://godotengine.org/asset-library/asset/4853) — compute shader-based cloth with collisions, turbulence, pinning, inertia. MIT, Godot 4.5. NOT for character clothing (solidify is our look). Best use: environmental dressing — sails on ships, flags, awnings, laundry on lines, market tarps, banners. These are static-anchor cloth meshes that add life to environments without per-body fitting. Evaluate performance cost per cloth instance and max reasonable count per scene. +- **Cross-reference:** Character visual system, D-152 (LOD tiers), clothing pipeline + +--- + +### Q-070: NobodyWho LLM patterns vs our Rust voice pipeline +- **Status:** Open (evaluated, not adopted) +- **Question:** NobodyWho (https://docs.nobodywho.ooo/) is a GDExtension providing in-process LLM inference (llama.cpp) with GGUF models. Evaluated against our existing Gemma 2 voice pipeline in server/src/voice/. **Verdict: does not fit D-020** — client-side LLM violates client-as-pure-renderer. Our server-side Rust approach is architecturally correct. **Patterns worth adopting:** (a) tool calling with grammar-enforced structured output — NPC queries game state via typed function calls, guaranteed parseable. (b) Preemptive context shifting for infinite conversations without truncation. (c) GGUF model flexibility (not locked to Gemma 2). These patterns should be evaluated for integration into the Rust voice pipeline, not as a client-side plugin. +- **Cross-reference:** D-020 (server authority), server/src/voice/ pipeline, D-010 (determinism) + +--- + +### Q-071: Steam integration template for multiplayer lobbies +- **Status:** Open (future — Steam/multiplayer stage) +- **Question:** Two resources for Steam multiplayer: (a) SteamMultiplayerPeer (https://github.com/expressobits/steam-multiplayer-peer) — the actual networking primitive. Implements Godot's MultiplayerPeer interface over Steam networking (relay, NAT traversal, lobbies). This is the building block we'd use. (b) Steam Template (https://godotengine.org/asset-library/asset/3328) — CC0 template wrapping SteamMultiplayerPeer with menu UI, settings, lobby management. Reference for UI patterns. Key architecture question: our server-authoritative model (D-010, D-020) means the dedicated server runs the simulation. SteamMultiplayerPeer could handle client↔server transport (using Steam relay for NAT traversal) rather than raw TCP/WebSocket. This would give us Steam friend invites, lobby discovery, and relay infrastructure for free. Evaluate when multiplayer work begins. +- **Cross-reference:** D-010 (server authority), D-020 (subprocess IPC), Oscar (networking agent) + +--- + +### Q-072: BitTorrent for P2P asset/mod/world state distribution +- **Status:** Open (future — multiplayer stage) +- **Question:** godot-torrent (https://godotengine.org/asset-library/asset/4384) — full BitTorrent protocol as GDExtension, C++ native performance. MIT, Godot 4.5. Potential uses: (a) mod/asset sync between multiplayer clients without central CDN costs — players seed assets to each other. (b) World state distribution — large world snapshots shared P2P rather than server→each-client. (c) DLC/content pack distribution. Key advantage: scales with player count (more players = more seeds = faster). Key risk: NAT traversal, firewall issues, player trust (can you trust torrent-distributed assets?). Would need content verification (hash/signature) to prevent tampering. +- **Cross-reference:** Oscar (networking), multiplayer architecture, mod support + +--- + +### Q-073: BehaviourToolkit patterns for Rust NPC AI +- **Status:** Open (reference — implementation is server-side Rust) +- **Question:** BehaviourToolkit (https://github.com/ThePat02/BehaviourToolkit, https://godotengine.org/asset-library/asset/2333) — FSM, Behaviour Trees, Blackboard Resource, nested composition (BT inside FSM and vice versa). MIT. The plugin itself is GDScript/Godot and lives on the wrong side of D-020 for us. But the patterns are directly applicable to the Rust server NPC simulation: (a) Blackboard pattern — shared key-value state between behaviour nodes without coupling, maps to bevy_ecs components. (b) Nested FSM↔BT composition — our NPC state machines (schedule, mood, relationships, job per D-097) could nest behaviour trees for decision-making within each state. (c) Editor interface patterns — how they visualize/debug behaviour trees could inform our server-side tooling. Study the source for architectural patterns, implement in Rust/bevy_ecs. +- **Cross-reference:** D-097 (simulation tiers, 4 state machines), Dudley (server developer), NPC behaviour system + +--- + +### Q-074: Screenshot manager for in-game captures and bug reports +- **Status:** Open +- **Question:** ScreenshotManager (https://github.com/ASecondGuy/ScreenshotManager) — evaluate for improving the existing F12 bug reporter's screenshot capture. We already have F12 screenshot + bug report in-game. This plugin could improve it: better file management, auto-naming, viewport isolation, gallery/history. Evaluate what patterns we can adopt into the existing bug reporter flow. +- **Cross-reference:** `/bug-report` skill, character creator screenshot system + +--- + +### Q-075: RichText3D for in-world text rendering +- **Status:** Open +- **Question:** RichText3D (https://github.com/mszylkowski/rich-text-3d-godot) — renders BBCode to a 3D plane in real time. MIT, performant (renders only on property change, max once per frame). Supports color, bold, italic, images, tables, font size, auto text wrapping. Use cases: in-world signage (shop names, zone labels, directional signs), NPC name/title floating labels, item descriptions on crates/containers, news tickers on station displays, terminal screens. The adjustable resolution (pixels per Godot unit) means text stays readable at our isometric camera angles. Worth evaluating when diegetic UI and in-world text elements are implemented. +- **Cross-reference:** Diegetic UI design, in-world interaction system + +--- + +### Q-076: DeformableMesh for runtime environment and damage variation +- **Status:** Open +- **Question:** DeformableMesh (https://github.com/cloudofoz/godot-deformablemesh) — runtime mesh deformation with SphericalDeformer, SimpleDeformer (bend, twist, taper), and DragDeformer nodes. MIT, Godot 4.0+. Use cases: (a) environmental variety from shared meshes — same pipe asset bent differently per instance, twisted metal in damaged zones, wind-bent vegetation/trees. (b) Damage visualization — crushed containers, warped hull plating, dented surfaces. (c) Procedural variation at generator time — deform base assets to create unique instances without authoring each one. The DragDeformer could also serve interactive manipulation (bending objects during gameplay). Low priority but high variety-per-asset value. +- **Cross-reference:** Generator architecture, environment asset pipeline, damage system + +--- + +### Q-077: CityCrafter3D — procedural city/settlement generation +- **Status:** Open (high interest) +- **Question:** CityCrafter3D (https://github.com/immaculate-lift-studio/CityCrafter3D) — procedural 3D city generation in Godot. The generation logic needs to be in Rust (server-side, D-020), but the patterns are highly relevant: road network generation, building placement rules, district zoning, lot subdivision, procedural layout algorithms. Study as a reference implementation for our Rust-side location generator. Key questions: what algorithms does it use (wave function collapse, L-systems, grid subdivision)? How does it handle building variety from limited asset sets? What's the data model for a generated city — can we extract the layout representation and replicate it in Rust with the client rendering from server-sent layout data? +- **Cross-reference:** Generator architecture, D-096 (chunk loading), D-097 (simulation tiers), location generation + +--- + +### Q-078: God rays for atmospheric lighting +- **Status:** Open +- **Question:** SimplestGodRay3D (https://github.com/AguaMineral/SimplestGodRay3D) — drop-in volumetric light shaft effect. Light streaming through station viewports, between buildings in exterior zones, through tree canopy in rural areas. Low implementation effort, high atmosphere value. Evaluate: does it work with our GL compatibility renderer? Performance cost per instance? Compatible with our toon shader aesthetic or does it look too realistic? +- **Cross-reference:** Lighting design, environment atmosphere + +--- + +### Q-079: GridMapLayer — 2D tile logic driving 3D grid rendering +- **Status:** Open (high relevance) +- **Question:** GridMapLayer (https://github.com/Caaz/grid-map-layer) — manages 3D GridMaps through TileMapLayer patterns. MIT, Godot 4.4+. Directly relevant: our server sends 2D tile grid data, the client renders 3D isometric. This plugin bridges that gap — autotiling for 3D tiles using 2D rules, arbitrary subdivisions (2x2+ gridmap tiles per 2D tile), multiple GridTiles per 2D tile (layered grids for collision variation), programmatic tile setting for procedurally generated areas. This could be the rendering layer for server-generated floor plans — the server sends the tile palette + grid, the client uses GridMapLayer with autotiling to render walls, floors, doors with correct 3D tile selection. +- **Cross-reference:** D-096 (chunk loading), tile rendering pipeline, server→client tile data + +--- + +### Q-080: Mod loader architecture reference +- **Status:** Open (reference — future feature) +- **Question:** Godot Mod Loader (https://github.com/GodotModding/godot-mod-loader) — community-standard mod loading framework for Godot. Study for architectural patterns: mod discovery and load ordering, dependency resolution between mods, conflict detection, API boundaries (what mods can and can't touch), mod manifest format, hot-reload vs startup-only loading, save compatibility with mods enabled/disabled. We'll roll our own but these patterns are battle-tested across many Godot projects. Key question for our architecture: mods need to work with both the Rust server (gameplay mods, new items, behaviours) AND the Godot client (visual mods, UI mods). The mod loader needs to span both sides of the D-020 boundary. +- **Cross-reference:** D-020 (client/server split), mod support, Q-072 (BitTorrent for mod distribution) + +--- + +*32 questions (7 resolved, 1 partially resolved, 24 open). Last updated: 2026-03-23.*