Concept: The Three Layers
CrimsonSettings separates three concerns so each can change independently. Keeping them apart is what lets a setting persist with no glue, or bind to code, or be contributed by another plugin - all through the same screen.
| Layer | Type | Responsibility |
|---|---|---|
| Structure | UCrimsonSettingsDataAsset | What options exist - sections and entries authored in the Content Browser. |
| Behavior | UCrimsonSettingRegistry | How they read/write - populate from the asset, bind delegates, or wire C++ data sources. |
| Presentation | UCrimsonSettingScreen / UCrimsonSettingPanel | How they look - the CommonUI screen and per-row widgets. |
How a value flows
Populate From Data Asset builds one UCrimsonSettingCollection per section and a value object per entry (a _BP class for scalar/discrete, a UCrimsonSettingAction for buttons). For each it fires K2_BindSetting so you can wire behavior, then registers it. Initialize(LocalPlayer) runs OnInitialize, the K2_Register* category hooks, and readies each setting.
Where a value actually lives
A
_BP value can source its value three ways, checked in order: a preview value (during live preview), a storage source (the keyed store, when Persist To Shared Store is ticked), a delegate (OnGetValue/OnGetIndex), or finally its internal field. This is why persistence and binding are independent choices - see Concept: Value Types & Data Sources.