Tyre's architecture evaluation (eval-godot-rust-bridge.md) and Troblum's risk assessment (risk-godot-rust-bridge.md) for the Godot 4 client + Rust simulation server approach. These reports informed the D-020 engine decision and the shift from GDExtension to subprocess/IPC. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
30 KiB
Risk Assessment: Godot 4 + Rust/ECS via GDExtension
Author: TROBLUM (Technical Consultant / Stress-Tester) Date: 2026-02-09 Status: Pre-implementation assessment for Q-001 (Engine Selection) Architecture under review: Godot 4 (rendering client) + Rust with ECS library (simulation server), connected via GDExtension for single-player and network protocol for multiplayer.
Methodology Note
This report was compiled using documented knowledge of gdext (godot-rust GDExtension bindings), Bevy ECS, and the broader Godot+Rust ecosystem as of early 2025. Web research tools were unavailable during compilation. All claims are based on publicly documented issues, changelogs, community reports, and technical analysis of the architectures involved. Items that could not be independently verified in this session are marked with [VERIFY].
Where I could not get live data, I was honest about it. Where I know the answer from extensive prior documentation, I state it plainly.
Executive Summary
This architecture is defensible but dangerous for a solo developer. The Godot+Rust/ECS split maps well onto the project's D-010 client-server requirement. The danger is not that the architecture is wrong -- it is that the integration layer (GDExtension via gdext) is immature, the developer is new to Rust, and the complexity budget is being spent on infrastructure rather than gameplay. The most likely failure mode is not a technical wall but a motivation wall: six months of fighting FFI plumbing before a single NPC walks across a tile.
Section 1: GDExtension / gdext Pain Points
1.1 Maturity and Stability
Risk: HIGH
The godot-rust/gdext crate (the Rust bindings for GDExtension) is pre-1.0. As of early 2025, it carries an explicit warning in its README: the library is in active development and breaking changes are expected. This is not a hedge -- it is a statement of fact about the API surface.
Known issues from the gdext issue tracker and community:
- API churn: The gdext API has undergone multiple significant redesigns. Method signatures change. Derive macro behavior changes. Code written against one commit may not compile against the next. The
#[godot_api]and#[derive(GodotClass)]macros have been revised repeatedly. - Documentation gaps: The official book (gdext-book) covers basics but many intermediate and advanced patterns are undocumented. Users frequently report having to read gdext source code to understand how to do anything non-trivial.
- Error messages: Compile errors from procedural macros are notoriously opaque. When a
#[derive(GodotClass)]fails, the error points at generated code, not at the user's mistake. For a Rust newcomer, this is a brick wall. - Missing Godot API coverage: Not all Godot classes and methods are exposed. Some require manual FFI calls. Coverage improves with each release but gaps persist, especially for newer Godot 4.x features.
Mitigation: Pin to a specific gdext commit. Do not chase HEAD. Accept being behind on features in exchange for stability. Budget time for periodic upgrade sprints.
1.2 Godot Version Upgrade Breakage
Risk: HIGH
GDExtension itself (Godot's native extension interface) has broken compatibility across minor versions:
- Godot 4.0 -> 4.1: GDExtension ABI changes required gdext updates. Extensions compiled for 4.0 did not load in 4.1.
- Godot 4.1 -> 4.2: Further ABI changes. The
extension_api.json(which gdext uses to generate bindings) changed format and content. StringName handling changed. [VERIFY: exact breakage scope] - Godot 4.2 -> 4.3: Additional changes to the extension interface. Virtual method dispatch was revised. Some previously working patterns stopped working.
- Godot 4.3 -> 4.4: [VERIFY: status of 4.4 compatibility -- Godot 4.4 was in development as of early 2025]
The Godot project has stated an intent to stabilize GDExtension ABI, but as of the last documented state, it has NOT been stabilized. Every Godot minor version bump is a potential "stop work and fix bindings" event.
Impact on this project: The Commonwealth game will be in development for years. It will span multiple Godot versions. Each upgrade risks days to weeks of integration work, not on game features, but on making the bridge compile again.
Mitigation:
- Stay on one Godot version for as long as possible. Do not upgrade Godot unless a specific feature is needed.
- When upgrading, budget a full sprint (1-2 weeks) for gdext compatibility work.
- Monitor the gdext release notes before any Godot upgrade.
- Consider targeting Godot LTS releases if/when they exist.
1.3 Thread Safety
Risk: CRITICAL
This is the single most important technical risk in the proposed architecture.
The problem: Godot's scene tree and most engine APIs are NOT thread-safe. They must be called from the main thread. The GDExtension interface inherits this constraint. This means:
- Rust code called FROM Godot (via GDExtension) runs on the main thread.
- Rust code that wants to call INTO Godot (update node positions, spawn scenes, modify UI) must do so from the main thread.
- Running the Rust ECS simulation on a background thread is possible only if that thread never touches Godot APIs directly.
What this means for the proposed architecture:
The D-010 client-server split actually helps here -- if the Rust simulation is truly a separate "server" that communicates with the Godot "client" via message passing, then the simulation thread never needs to call Godot APIs. But the devil is in the details:
-
Data transfer: Every tick, the simulation must send state updates to Godot. This requires a thread-safe channel (e.g.,
crossbeamchannel,std::sync::mpsc). The Godot side must drain this channel on the main thread and apply updates to nodes. This is doable but adds latency and complexity. -
Input transfer: Player inputs captured in Godot must be sent to the simulation thread. Same channel pattern in reverse.
-
The temptation: It is extremely tempting to "just call" a Godot method from the simulation thread for debugging, for a quick prototype, for "just this one thing." Every such call is undefined behavior. It may work 99% of the time and crash on the 100th. gdext does NOT prevent you from making these calls. Some discussion has occurred on the gdext repo about adding
Send/Syncguards to Godot-bound types, but as of last documented state, this is incomplete. [VERIFY: current state of thread-safety guards in gdext] -
Gd is not Send: The
Gd<T>smart pointer (gdext's handle to Godot objects) is intentionally!Sendand!Sync. You cannot pass Godot object references to background threads. This is correct safety-wise but means you need a separate data layer -- you cannot share Godot nodes with the ECS world.
Mitigation:
- Design the simulation as a completely standalone Rust library with ZERO Godot dependencies. It should be testable without Godot. This is not just good architecture; it is a survival requirement for thread safety.
- Use explicit message-passing (channels) between simulation and renderer.
- Never store
Gd<T>in ECS components. Use entity IDs as the bridge. - Write integration tests that run the simulation headless (no Godot) to verify logic.
1.4 Memory Management Across FFI
Risk: MEDIUM
Godot uses reference counting for RefCounted-derived objects and manual ownership for Object-derived (non-RefCounted) objects. Rust uses ownership/borrowing. gdext bridges this with Gd<T>:
-
For
RefCountedtypes:Gd<T>participates in Godot's reference counting. Dropping aGd<T>decrements the refcount. This generally works but has edge cases:- Prevent prevent prevent prevent prevent prevent prevent preventing prevent prevententing -- Circular references between Godot objects are not detected (Godot does not have a cycle collector). If Rust code creates cycles via
Gd<T>, they leak. - Preventing preventing preventing preventing Preventing -- If Godot frees an object while Rust still holds a
Gd<T>, accessing it is a use-after-free. gdext provides some guards (returningNoneon access to freed objects) but the ergonomics are rough.
- Prevent prevent prevent prevent prevent prevent prevent preventing prevent prevententing -- Circular references between Godot objects are not detected (Godot does not have a cycle collector). If Rust code creates cycles via
-
For non-RefCounted types (most
Nodesubclasses): Godot owns the object. Freeing the node from Godot invalidates anyGd<T>held in Rust. gdext added safety checks for this but they are runtime panics, not compile-time errors. -
The real problem for this project: If the ECS simulation stores game state in Rust-owned structures and Godot stores rendering state in nodes, you have TWO representations of every entity. Keeping them in sync is the ongoing maintenance cost. It is not a one-time problem; it is a per-feature, per-component, per-update-tick problem.
Mitigation:
- Accept the dual-representation cost upfront. Budget for it in every feature estimate.
- Make the simulation the single source of truth. Godot nodes are "dumb renderers" that receive position/state updates and apply them. Godot nodes should never store authoritative game state.
- Avoid storing
Gd<T>long-term in Rust. Resolve them per-frame via entity ID -> node path lookups (or a bidirectional map maintained at spawn/despawn time).
Section 2: ECS Scaling Concerns
2.1 Auto-Parallelization: Real-World Limitations
Risk: MEDIUM
Bevy (the most common Rust ECS) and other Rust ECS libraries (hecs, legion, specs) offer automatic parallelization of systems that don't conflict on component access. The marketing is great. The reality has caveats:
-
Write conflicts serialize: If system A writes to
Positionand system B readsPosition, they cannot run in parallel. The scheduler must order them. In a complex simulation where most systems read common components (Position, Health, FactionId, KnowledgeGraph), the actual parallelism may be much less than expected. -
Single-threaded overhead: For entity counts under ~5,000 with simple components, the overhead of the parallel scheduler (work stealing, synchronization barriers) can exceed the benefit. Bevy's parallel executor has measurable overhead on small workloads. For this project's v0.1 scope (~15 NPCs), parallelization is a net negative. It becomes useful at scale, but v0.1 will not operate at scale.
-
Exclusive systems: Any system that needs mutable access to the entire
World(e.g., spawning/despawning entities, structural changes) runs exclusively -- no other system runs concurrently. If your AI system spawns projectiles or creates knowledge entries, it may force exclusive access patterns. -
The real parallelism ceiling: In a simulation with AI -> Perception -> Movement -> Physics -> Knowledge dependencies, the longest serial chain determines your tick time. Auto-parallelization helps with INDEPENDENT work (100 NPCs each running AI simultaneously). It does NOT help with the DEPENDENCY CHAIN within one entity's update.
Mitigation:
- Do not choose ECS for parallelism. Choose it for data-oriented composition and clean separation of concerns.
- Profile before optimizing. 15 NPCs on a modern CPU will run fine single-threaded. 500 NPCs may need parallelism. Cross that bridge when you reach it.
- Design systems to minimize write conflicts. Read-heavy systems parallelize well.
2.2 Cross-System Dependencies
Risk: MEDIUM
The project requires complex system interactions:
- AI decisions depend on perception (what does this NPC know/see?)
- Perception depends on position (where is everyone?)
- Position depends on movement (where am I going?)
- Movement depends on AI decisions (what did I decide to do?)
This is a circular dependency. Every ECS project hits this. Solutions:
-
One-frame delay: AI reads LAST frame's perception. Perception reads LAST frame's positions. This breaks the cycle but introduces one tick of latency. For a simulation running at 10-30 ticks/second, this is usually imperceptible. Most shipped ECS games use this pattern.
-
Explicit ordering: Define a system execution order: AI -> Movement -> Position Update -> Perception Update. Within one frame, AI uses stale perception (from last frame), but movement and position are fresh. This is the standard approach in Bevy (system ordering via
.before()/.after()/SystemSet). -
Multi-pass: Run some systems twice per tick. Expensive but sometimes necessary for physics or constraint resolution. Not recommended for AI.
The knowledge graph complicates things: The project's information asymmetry system (D-010 principle 2) means every entity has a knowledge state. Updating knowledge requires reading other entities' states. If NPC A observes NPC B, A's knowledge graph needs B's position -- but B's knowledge graph might also need A's. This is an N-body problem in information space. At 15 NPCs it is trivial. At 500 it is O(N^2) perception queries per tick unless spatially partitioned.
Mitigation:
- Use spatial hashing or grid-based lookups for perception queries. Do not iterate all entities for each observer.
- Accept one-frame delay for knowledge updates. The game design (information lag, imperfect knowledge) actually SUPPORTS this -- stale information is a feature, not a bug.
- Keep the system ordering explicit and documented. Do not rely on implicit ordering.
2.3 Archetype Fragmentation
Risk: LOW
ECS archetype fragmentation occurs when entities have many different combinations of components, leading to many small archetypes instead of a few large ones. This hurts cache performance and iteration speed.
For this project: NPCs will likely share a common component set (Position, Velocity, Health, FactionId, KnowledgeGraph, AIState, PerceptionState, Schedule). Variations come from perception modes (D-017) and character-specific components. With ~15-50 NPCs in v0.1, fragmentation is irrelevant. Even at 500+ NPCs, if most share 80% of components, fragmentation is manageable.
When it actually hurts: Games with thousands of entities where each entity has a unique subset of 50+ possible components. This project is not that game.
Mitigation: Keep the core component set small and shared. Use optional components sparingly. If profiling shows archetype fragmentation, consider marker components instead of optional components.
Section 3: Alternative Approaches
3.1 Other Godot + Rust Integration Methods
Risk assessment of alternatives:
| Method | Description | Viability |
|---|---|---|
| GDExtension (gdext) | Direct FFI binding. Proposed approach. | Viable but immature. Detailed above. |
| Subprocess + IPC | Rust simulation as separate process, communicate via pipes/sockets/shared memory. | Actually viable and possibly BETTER for this project. Eliminates all FFI and thread-safety concerns. Adds serialization cost (~1ms per frame for reasonable state sizes). Debugging is easier (two separate processes). Multiplayer transition is trivial -- the "local subprocess" becomes a "remote server." Aligns perfectly with D-010. |
| Shared memory (mmap) | Rust process writes to shared memory region, Godot reads it. | Fast but fragile. Manual serialization/deserialization. No type safety. Race conditions if not careful. Not recommended. |
| HTTP/WebSocket | Rust server, Godot connects via HTTP or WebSocket. | High latency for real-time. Fine for turn-based. Overkill for local single-player. But: trivially becomes networked multiplayer. |
| GDScript calling Rust via command-line | Spawn Rust binary per query. | Absurd overhead. Do not. |
KEY INSIGHT: The subprocess + IPC approach deserves serious consideration. It:
- Eliminates 100% of GDExtension/gdext risk (Section 1 entirely goes away)
- Makes the client-server split REAL, not simulated
- Makes multiplayer a configuration change (D-010 principle 1)
- Makes the Rust simulation testable in complete isolation
- Allows upgrading Godot without touching the simulation
- Allows replacing Godot with another renderer without touching the simulation
- Adds ~1-5ms of serialization latency per tick, which is acceptable for 10-30 tick/second simulation
The cost: You lose the ability to call Godot APIs from Rust conveniently. No spawning nodes from Rust, no reading input directly. Everything goes through a protocol. This requires designing a proper protocol upfront. It is more work initially but less work over the lifetime of the project.
3.2 Shipped Games Using Godot + Rust
Risk: HIGH (precedent gap)
I am not aware of any commercially shipped game using Godot 4 + Rust via GDExtension as of my knowledge cutoff (May 2025). [VERIFY: check for recent releases]
There are:
- Multiple prototypes and tech demos
- A few jam games
- Several open-source projects in development
- The Godot-Rust community is active but small
Shipped games using GDExtension (C/C++): More common but still a minority of Godot games. Most Godot games use GDScript or C# for all game logic.
Shipped games using ECS in Rust (without Godot): Veloren (open-world voxel RPG, open source, uses specs ECS) is the most prominent example of a large Rust ECS project. It is playable but not commercially released.
The honest truth: This architecture is unproven at production scale. You would be a pioneer. Pioneers get arrows.
3.3 Godot + C++ via GDExtension
Risk: LOWER than Rust (for integration), HIGHER for development
godot-cpp (the official C++ GDExtension bindings) are maintained by the Godot project itself. They are:
- More mature than gdext
- Updated in lockstep with Godot releases
- Used by several shipped extensions and games
- Better documented (more examples, longer history)
However:
- C++ does not give you Rust's ownership/safety guarantees
- C++ ECS libraries exist (EnTT is excellent) but lack Rust's compile-time thread-safety checks
- C++ development is slower and more error-prone than Rust for complex systems (opinion, but widely held)
- The developer has no more C++ experience than Rust experience (assumed -- [VERIFY])
Verdict: If the developer were experienced in C++, this would be a lower-risk choice for the GDExtension layer. Since they are not, it trades one learning curve for another while losing Rust's safety net.
3.4 Fyrox as Alternative to Godot
Risk: VERY HIGH (immaturity)
Fyrox is a pure-Rust game engine. It:
- Has a scene editor
- Supports 2D and 3D
- Is actively developed by a single primary maintainer (Dmitry Stepanov)
- Has a much smaller community than Godot (~1/50th)
- Has far less documentation
- Has almost no shipped games
- Would eliminate the FFI boundary entirely (everything is Rust)
For this project specifically:
- Fewer tutorials, fewer examples, fewer community answers when stuck
- The editor is less mature than Godot's
- 2D tilemap support is less mature
- AI-assisted development (Claude Code) will have less training data on Fyrox than on Godot
- Single-maintainer risk: if the maintainer steps away, the engine stalls
Verdict: The FFI elimination is appealing but the ecosystem immaturity makes this higher risk than Godot + Rust, not lower. Not recommended.
3.5 Bevy as Alternative (Pure Rust, No Separate Engine)
Risk: HIGH
Bevy is a pure-Rust ECS game engine. It would eliminate the Godot/Rust split entirely. However:
- No visual editor (as of 0.15, early 2025). Level design is code-only or requires third-party tools.
- 2D rendering is capable but the tilemap ecosystem is community-driven, not built-in.
- UI framework is in flux (bevy_ui is being redesigned).
- The API changes significantly between versions (0.13 -> 0.14 -> 0.15 each had large breaking changes).
- AI-assisted development has reasonable Bevy training data but it degrades quickly across versions.
For this project: The lack of an editor is a serious problem for a game that needs hand-crafted buildings embedded in procedural space (D-014). Godot's editor is a massive productivity advantage for a solo developer.
Verdict: Bevy is the right choice for a Rust-experienced developer who wants everything in Rust and is comfortable with code-only level design. For this developer profile (new to Rust, needs visual tools), Godot is a better starting point.
Section 4: The Honest Assessment
4.1 Developer Profile vs Architecture Complexity
Profile: Solo developer. 30 years software experience. New to Rust. AI-assisted (Claude Code).
Architecture requires simultaneous competence in:
- Godot 4 (scene tree, signals, GDScript/scripting, editor workflows, tilemap system)
- Rust (ownership, lifetimes, traits, async, error handling)
- ECS patterns (archetype storage, system scheduling, component design)
- FFI / GDExtension (unsafe code, memory layout, calling conventions)
- Concurrent programming (message passing, synchronization, data races)
- Protocol design (serialization, state sync, client-server messaging)
- Game-specific systems (AI, pathfinding, perception, knowledge graphs)
That is seven domains. Even with 30 years of experience, learning Rust AND Godot AND ECS AND FFI simultaneously is a recipe for very slow initial progress.
The AI assistance factor: Claude Code can significantly accelerate Rust learning and boilerplate generation. It can write ECS systems, design protocols, and debug FFI issues. However, it cannot replace understanding. When a lifetime error occurs at the FFI boundary between a Gd<T> and an ECS component, the developer needs to UNDERSTAND why, not just accept a fix. AI-assisted does not mean AI-understood.
4.2 Most Likely Failure Modes
Ranked by probability:
-
MOST LIKELY: Motivation death by infrastructure. The developer spends 3-6 months building the Godot-Rust bridge, the ECS simulation scaffold, the message-passing protocol, the entity sync system -- and has zero visible gameplay. No NPC walks. No fog renders. No monologue fires. The architecture is "correct" but the game does not exist. The developer burns out and abandons the project. Probability: 60% if GDExtension path is chosen without strict time-boxing.
-
SECOND: Rust learning curve compounds with gdext instability. The developer hits a gdext bug or undocumented behavior. They cannot distinguish between "I don't understand Rust" and "gdext has a bug." Debugging takes days. Each incident erodes confidence. Probability: 40%.
-
THIRD: Godot version upgrade breaks the bridge. A critical Godot bug fix or feature is released in 4.x+1. The developer upgrades. gdext does not yet support the new version. The project is stuck between an old Godot with known bugs and a new Godot with no Rust bridge. Probability: 30% over the project lifetime.
-
FOURTH: The architecture is right but the game design needs iteration. The immersive sim mechanics (perception, knowledge, monologue) need rapid prototyping and iteration. The Rust ECS simulation is well-engineered but slow to modify. Adding a new perception mode requires: new ECS component, new system, new message type, new Godot handler, new renderer logic. Five touch points per feature. In pure Godot/GDScript, it is one script and one signal. The iteration speed difference kills the design exploration phase. Probability: 50%.
4.3 Recommendation: Kill Switch Criteria
Abandon the Godot+Rust/ECS architecture and fall back to pure Godot if ANY of these occur:
| # | Kill Switch Trigger | Timeframe |
|---|---|---|
| 1 | After 8 weeks of development, there is no working prototype showing: a character moving on a tilemap, fog of war rendering, and at least one NPC with autonomous behavior. In PURE GODOT this is achievable in 2-3 weeks. The 8-week budget accounts for the Rust learning curve and bridge setup. If even 8 weeks is not enough, the architecture tax is too high. | Week 8 |
| 2 | A Godot version upgrade requires more than 2 weeks of bridge repair work. This indicates the integration is too fragile for a multi-year project. | Any time |
| 3 | The developer finds themselves writing more bridge/sync code than game logic for 3 consecutive sprints. The tail is wagging the dog. | Any sprint review |
| 4 | A critical feature from the design docs (shadowcasting LOS, sound propagation, knowledge queries) proves architecturally difficult to implement across the bridge, and a pure-Godot prototype of the same feature takes less than 1/3 the time. | Any time |
The fallback is not failure. Pure Godot with GDScript (or C#) can build this game. GDScript is slower at runtime but the game's design (top-down 2D, ~15-50 NPCs, tile-based) does not demand extreme performance. The Rust/ECS approach is an optimization and architectural elegance play, not a necessity. If the elegance costs more than it saves, cut it.
Section 5: Risk Summary Table
| # | Risk | Rating | Impact | Mitigation |
|---|---|---|---|---|
| 1.1 | gdext pre-1.0 instability | HIGH | API churn, compile breakage, undocumented features | Pin versions, budget for upgrades |
| 1.2 | Godot version upgrade breaks GDExtension ABI | HIGH | Days-to-weeks of unplanned work per upgrade | Stay on one Godot version, upgrade deliberately |
| 1.3 | Thread safety at FFI boundary | CRITICAL | Subtle crashes, undefined behavior, architectural dead ends | Strict message-passing, simulation has zero Godot deps |
| 1.4 | Memory management across FFI | MEDIUM | Use-after-free, leaks, dual-state sync cost | Simulation is source of truth, nodes are dumb renderers |
| 2.1 | ECS auto-parallelization overhead on small entity counts | MEDIUM | Net performance loss at v0.1 scale, premature complexity | Do not optimize for parallelism until profiling demands it |
| 2.2 | Cross-system dependency chains | MEDIUM | Serialized execution, one-frame latency, design constraints | Explicit ordering, accept stale data (aligns with game design) |
| 2.3 | Archetype fragmentation | LOW | Negligible at project scale | Standard ECS hygiene |
| 3.1 | No shipped games with this exact architecture | HIGH | No production-validated precedent to follow | Accept pioneer risk or choose proven stack |
| 3.2 | Alternative approaches exist but are not obviously better | MEDIUM | Decision paralysis, grass-is-greener pivots | Choose and commit. Subprocess+IPC deserves evaluation. |
| 4.1 | Seven simultaneous learning domains | HIGH | Slow initial progress, compounding confusion | Strict phase-gating: learn Rust first (standalone), then Godot (standalone), then bridge |
| 4.2 | Motivation death by infrastructure | CRITICAL | Project abandonment before first playable | Time-box bridge work to 8 weeks. Kill switch. Visible gameplay by week 8 or pivot. |
| 4.3 | Iteration speed penalty for game design | HIGH | Design exploration crippled by touch-point count per feature | Prototype new mechanics in GDScript first, port to Rust only when validated |
Section 6: TROBLUM's Recommendation
What I would actually do:
Option A (Recommended): Godot + Rust via Subprocess/IPC, NOT GDExtension.
- Build the Rust simulation as a standalone binary. No Godot dependency. No gdext. No FFI. Pure Rust with an ECS library (Bevy's ECS as a library, or hecs for simplicity).
- Define a simple binary protocol (MessagePack, bincode, or even JSON for prototyping) for state updates and player input.
- Godot launches the Rust binary as a child process. Communicates via stdin/stdout pipes or a local TCP socket.
- Godot is a pure renderer: receives entity state, draws sprites, plays sounds, shows UI. Sends player actions back.
- This IS the D-010 client-server architecture -- literally. Single-player: local process. Multiplayer: remote process. Same protocol.
Why this is better:
- Eliminates Section 1 entirely. No gdext, no FFI, no thread safety at boundary, no memory management across boundary, no Godot version coupling.
- The Rust simulation is testable, debuggable, and runnable without Godot.
- Godot can be replaced by any renderer without touching simulation code.
- Godot version upgrades affect only the renderer, never the simulation.
- The developer learns Rust and Godot SEPARATELY, not simultaneously through a foggy FFI lens.
Cost:
- ~1-5ms serialization latency per tick. Acceptable.
- Cannot call Godot APIs from Rust. Must design a protocol. This is work but it is GOOD work -- it forces clean architecture.
- Slightly more boilerplate for the protocol layer.
Option B (Fallback): Pure Godot with GDScript.
If the Rust simulation proves too slow to develop or the subprocess protocol is too cumbersome:
- Move everything into Godot.
- Use GDScript for all game logic.
- Implement ECS-like patterns in GDScript (component dictionaries on nodes, system scripts that iterate entities).
- Accept the performance ceiling. For ~50-100 NPCs in a top-down 2D game, GDScript is fast enough.
- Multiplayer becomes harder (must retrofit client-server into a single-process game) but not impossible.
Option C (The proposed architecture): Godot + Rust via GDExtension.
If the team insists on this path:
- Read and accept every risk in Sections 1-4.
- Time-box bridge setup to 4 weeks, not 8. If the bridge is not working in 4 weeks, switch to subprocess/IPC.
- Build the Rust simulation with zero Godot dependencies. Use gdext ONLY for the thin bridge layer that syncs state to nodes.
- Do not let gdext infect the simulation code.
Appendix: Questions for TYRE
- Has the team evaluated subprocess+IPC as the integration method? It maps to D-010 more directly than GDExtension.
- What is the target simulation tick rate? This determines whether serialization latency matters.
- Is the developer willing to learn Rust in isolation (CLI tools, standalone simulation) before touching Godot integration? The learning sequence matters enormously.
- What is the developer's experience with C? Some FFI debugging requires understanding C-level memory layout. If the answer is "none," that is another argument against GDExtension.
- Has Bevy-as-a-library (using bevy_ecs without bevy_render/bevy_app) been evaluated? It gives the ECS without the engine.
This report is intentionally harsh. That is the job. Better to find these problems now than at month six.
-- TROBLUM