Class SceneTypeRegistry
Static lookup table that maps PGPSCN scene name strings to their concrete
Scene subclass Type. Exists to make
scene_transition action resolution trim-safe: the
DynamicallyAccessedMembersAttribute on the registration generic flows
through every call site, pinning the public parameterless constructor of every
registered scene class so the .NET IL Trimmer cannot strip it.
Replaces the legacy GetType(string) + assembly-walk lookup that previously lived in SceneLoader.
Contract: the engine self-registers its own built-in scenes from the
Game() base constructor (runs before the subclass ctor body, so a
subclass can QueueScene a transition immediately and still resolve).
Games using PGPSCN with scene_transition actions must register their own
Scene subclasses at startup.
public static class SceneTypeRegistry
- Inheritance
-
SceneTypeRegistry
- Inherited Members
Methods
Clear()
Removes every entry from the registry. Intended for test setup/teardown only — production code should register once at startup.
public static void Clear()
ClearProjectTypes()
Story 7.1: removes every scene type registered via
RegisterProjectSceneType(string, Type). Engine self-registrations from
Game()'s base ctor stay intact. Called by the build pipeline before
re-registering scene types from a freshly-loaded project assembly.
public static void ClearProjectTypes()
RegisterProjectSceneType(string, Type)
Story 7.1: register a scene type that came from the user's project assembly
(hot-reloadable). Tracked separately from the engine's self-registrations so
ClearProjectTypes() can wipe only the project subset on rebuild.
Trim contract: the sceneType parameter carries
DynamicallyAccessedMembersAttribute just like
RegisterSceneType(string, Type) — Story 12.1 trim safety.
public static void RegisterProjectSceneType(string name, Type sceneType)
Parameters
RegisterSceneType(string, Type)
Register a scene type by name. The sceneType parameter is
annotated with DynamicallyAccessedMembersAttribute so that callers
passing a Type must themselves flow that annotation forward — this
is what makes the registry trim-safe end-to-end.
Idempotent: registering the same Type under the same name twice is a no-op. Registering a different Type under an already-used name throws ArgumentException.
public static void RegisterSceneType(string name, Type sceneType)
Parameters
RegisterSceneType<T>(string)
Register a scene type by name. The generic T carries a
DynamicallyAccessedMembersAttribute annotation so that the
trimmer preserves T's public parameterless constructor on every call site.
public static void RegisterSceneType<T>(string name) where T : Scene
Parameters
namestring
Type Parameters
T
TryResolve(string, out Type?)
Pure dictionary lookup. Returns true and the registered Type when
name is registered, otherwise false and null.
The out parameter carries DynamicallyAccessedMembersAttribute so that the trimmer can flow the parameterless-constructor preservation from each RegisterSceneType<T>(string) call site forward to the CreateInstance(Type) caller (SceneLoader).
[UnconditionalSuppressMessage("Trimming", "IL2067", Justification = "ConcurrentDictionary<string, Type> cannot propagate the DAM annotation through its value slot, so the trimmer cannot see that the Type stored came from an annotated RegisterSceneType call site. The class invariant is that this is the only way Types enter _types: RegisterSceneType<T>() flows PublicParameterlessConstructor on T, and RegisterSceneType(string, Type) requires the same DAM on its Type parameter. The TryResolve out annotation is therefore load-bearing and the suppression is safe so long as no future code path bypasses RegisterSceneType to write into _types.")]
public static bool TryResolve(string name, out Type? sceneType)