gum-service
$
npx mdskill add vchelaru/Gum/gum-serviceInitialize Gum UI runtime for game projects.
- Manages lifecycle of MonoGame, Raylib, KNI, and FNA game environments.
- Handles deferred queues, hot reloads, and root container operations.
- Prevents double initialization errors through singleton pattern enforcement.
- Clears shared static state and resets renderable delegates on teardown.
SKILL.md
.github/skills/gum-serviceView on GitHub ↗
--- name: gum-service description: Reference guide for GumService — the runtime entry point for MonoGame/Raylib/KNI/FNA games. Load this when working on GumService initialization, Uninitialize, DeferredQueue, hot reload, or the Root/PopupRoot/ModalRoot containers. --- # GumService Reference ## What It Is `GumService` is the runtime-facing API that game developers use to initialize, update, and draw Gum UI. It lives in `MonoGameGum/GumService.cs` (compiled for XNALIKE, RAYLIB via `#if`). **Not the CLI.** `Gum.Cli` / `Gum.ProjectServices` are separate tools for headless project validation and codegen. ## Lifecycle ``` GumService.Default.Initialize(game) // one-time setup ↓ per frame: GumService.Default.Update(gameTime) GumService.Default.Draw() ↓ on teardown (optional): GumService.Default.Uninitialize() ``` `Initialize` throws if called twice without an intervening `Uninitialize`. ## Singleton Pattern `Default` is lazily initialized via `??=`. `Uninitialize()` sets `_default = null`, so after teardown `GumService.Default` creates a **fresh instance** — any stored reference to the old instance is now orphaned. ## Uninitialize — Non-Obvious Details `Uninitialize()` resets a large amount of shared static state across multiple singletons. Key things it does that are surprising: - Nulls `GraphicalUiElement.SetPropertyOnRenderable`, `AddRenderableToManagers`, etc. — delegates wired by `FormsUtilities.InitializeDefaults` - Calls `ElementSaveExtensions.ClearRegistrations()` — clears `RegisterGueInstantiation` / `RegisterDefaultInstantiationType` callbacks - Calls `LoaderManager.Self.DisposeAndClear()` — disposes GPU content and empties the cache - Nulls and removes `FrameworkElement.PopupRoot` and `FrameworkElement.ModalRoot` from managers - Resets `FileManager.RelativeDirectory` to `"Content/"` (only meaningful if a project was loaded) - Calls `_systemManagers.Renderer.Uninitialize()` (XNALIKE only) - Sets `_default = null` — next access to `Default` creates a new `GumService` `FormsUtilities.Uninitialize()` is `internal`; tests access it via `InternalsVisibleTo`. ## Roots | Property | Purpose | |----------|---------| | `Root` | Main scene container; sized to canvas on each `Update` | | `PopupRoot` | Overlaid above Root; for non-modal popups | | `ModalRoot` | Topmost layer; blocks input to everything below | `PopupRoot` and `ModalRoot` are `FrameworkElement` statics, not instance fields — they are shared across all `GumService` instances. ## Key Files | File | Purpose | |------|---------| | `MonoGameGum/GumService.cs` | Main class | | `MonoGameGum/Forms/FormsUtilities.cs` | Input/cursor/gamepad setup; `Uninitialize()` lives here | | `GumRuntime/ElementSaveExtensions.GumRuntime.cs` | `ClearRegistrations()` called during Uninitialize | | `RenderingLibrary/Content/LoaderManager.cs` | `DisposeAndClear()` called during Uninitialize | | `Tests/MonoGameGum.Tests.V2/GumServiceUninitializeTests.cs` | Tests for GPU-accessible Uninitialize behavior | | `Tests/Gum.ProjectServices.Tests/UninitializeTests.cs` | Tests for non-GPU Uninitialize behavior | ## Testing Split Uninitialize tests are split across two projects because `FormsUtilities`, `LoaderManager`, and `ElementSaveExtensions` don't all require a GPU: - `Gum.ProjectServices.Tests` — `LoaderManager`, `ElementSaveExtensions`, `ObjectFinder` (no GPU needed) - `MonoGameGum.Tests.V2` — `FormsUtilities`, root containers, `FrameworkElement` statics (require test setup with a mock `SystemManagers`)