User Scope Root & Lifetime (5.1 → 6.0)
This guide explains why a user scope root exists and how to reason about service lifetime.
In 5.1 (GDScript), many projects end up with an implicit global singleton or a scene-root node that “owns everything”.
In 6.0 (C#), the architecture makes this explicit:
- A composition root owns a
ServiceRegistry. - A user scope root integrates identity and lifecycle.
- Workflow adapters orchestrate calls into Core services and state.
Boundary
- Core: engine-agnostic operations, state, and contracts.
- Godot: wiring + event translation + UI/visual glue.
Lifetimes
Use these three lifetimes to keep wiring understandable.
1) Per-project
Definition: values that exist once for the whole running Godot application (or once per main scene tree / composition root).
- Example: the shared
ServiceRegistry. - Example: shared systems that are not identity-specific.
2) Per-session
Definition: values that exist for the duration of a play session (often aligned with save/load boundaries).
- Example: a “grid building session” object that can resolve stable per-user scopes.
3) Per-user
Definition: values that are identity-specific (ownership, permissions, input ownership, per-user inventory, etc.).
- Example: a per-user scope keyed by
GPUserId.
The 6.0 reference implementation: GPUserScopeRoot
In the C# demo, the entry point for this wiring is:
demos/grid_building_dev/godot_cs/addons/GridPlacement/Godot/Bootstrap/GPUserScopeRoot.cs
Note: the 5.x GDScript addon folder remains res://addons/grid_building for backward compatibility, even when the docs are branded GridPlacement.
At a high level, it does the following:
| |
What it registers (examples)
The demo RegisterMinimalServices registers a minimal end-to-end chain:
- State
GridState,GridState2D,TargetingState
- Services
GridService2DICursorService->GridCursorServiceIPlacementService->PlacementService2DITargetingLogic->TargetingService2D
- Catalog / configuration
IPlaceableCatalog(PlaceableCatalogseeded byPlaceableCatalogBootstrap)
- Workflow adapters
IPlacementWorkflowAdapter->PlacementWorkflowAdapter
- Godot-facing bridge
PlacementWorkflowBridge(translates Godot types -> Core value types)
Identity: profile provider → user scope
The 6.0 pattern expects (optionally) a Godot-side provider:
IUserScopeProfileProvider
If present, it supplies identity, and GPUserScopeRoot creates a Composition IUserScope using:
GameUserSessions.Core.UserIdas the source-of-truth
If absent, a demo-friendly fallback identity is used.
Mapping from 5.1 to 6.0
In 5.1 you often see
- a global autoload or singleton (implicit registry)
- controllers that directly touch many nodes/state (implicit scopes)
In 6.0 the target shape is
| |
What this page does NOT assert
- It does not require multi-user support for all projects.
- It does not require GameComposition/GameUserSessions for 5.1 projects.
- It does define the preferred 6.0 integration seam so new docs and new code stay consistent.