Skip to content

UTFramework User Guide

This guide is for game developers who are new to UTFramework. It describes the currently implemented workflow for Attributes, GameplayEffects, Abilities, Tasks, inventory, items, equipment, save/load, UI, and network integration.

The Chinese edition is the semantic source of truth for this guide. Features that are experimental, deferred, or incomplete are identified as such.

This guide covers Blueprint configuration and C++ extension of UTFramework. It applies to standalone, listen-server, and client/server projects, and to saving existing UT actors in the current World.

It does not promise complete World Save, dynamic Actor reconstruction, cross-map restoration, a complete quest/achievement system, equipment sets, or automatic AbilityAsset generation from DataTables.

Enable UTGameFramework. Its modules are:

  • UTGameFramework: core runtime systems;
  • UTGame: game-layer classes such as Pawn, Controller, HUD, and Save managers;
  • UTEditor: typed ID pins, asset creation tools, details customizations, and K2 nodes;
  • UTTest: test fixtures included in the first release.

The plugin uses the Unreal modules required by its runtime and editor code. A game module that references framework types should add:

PublicDependencyModuleNames.AddRange(new[]
{
"UTGameFramework"
});

Add "UTGame" when directly using UT game-layer types. After changing reflected classes, inheritance, or reflected signatures, close the editor and perform a full build.

In Config/DefaultEngine.ini:

[/Script/Engine.Engine]
AssetManagerClassName=/Script/UTGameFramework.UTAssetManager

An incorrect setting is reported as a fatal error by UUTAssetManager::Get() rather than silently falling back to the default manager.

3.2 Register Primary Asset Types and Scan Paths

Section titled “3.2 Register Primary Asset Types and Scan Paths”

Register the six UT asset types under [/Script/Engine.AssetManagerSettings] in Config/DefaultGame.ini:

+PrimaryAssetTypesToScan=(PrimaryAssetType="LevelingAttribute",AssetBaseClass="/Script/UTGameFramework.LevelingAttribute",bHasBlueprintClasses=False,bIsEditorOnly=False,Directories=((Path="/Game/Blueprints/UT/Attribute")),SpecificAssets=,Rules=(Priority=-1,ChunkId=-1,bApplyRecursively=True,CookRule=Unknown))
+PrimaryAssetTypesToScan=(PrimaryAssetType="ParameterAttribute",AssetBaseClass="/Script/UTGameFramework.ParameterAttribute",bHasBlueprintClasses=False,bIsEditorOnly=False,Directories=((Path="/Game/Blueprints/UT/Attribute")),SpecificAssets=,Rules=(Priority=-1,ChunkId=-1,bApplyRecursively=True,CookRule=Unknown))
+PrimaryAssetTypesToScan=(PrimaryAssetType="GameplayEffect",AssetBaseClass="/Script/UTGameFramework.UTGameplayEffect",bHasBlueprintClasses=False,bIsEditorOnly=False,Directories=((Path="/Game/Blueprints/UT/Effect")),SpecificAssets=,Rules=(Priority=-1,ChunkId=-1,bApplyRecursively=True,CookRule=Unknown))
+PrimaryAssetTypesToScan=(PrimaryAssetType="StaticProp",AssetBaseClass="/Script/UTGameFramework.UTStaticGamePropBase",bHasBlueprintClasses=False,bIsEditorOnly=False,Directories=((Path="/Game/Blueprints/UT/GameProps")),SpecificAssets=,Rules=(Priority=-1,ChunkId=-1,bApplyRecursively=True,CookRule=Unknown))
+PrimaryAssetTypesToScan=(PrimaryAssetType="AbilityAsset",AssetBaseClass="/Script/UTGameFramework.UTAbilityAsset",bHasBlueprintClasses=False,bIsEditorOnly=False,Directories=((Path="/Game/Blueprints/UT/Ability")),SpecificAssets=,Rules=(Priority=-1,ChunkId=-1,bApplyRecursively=True,CookRule=Unknown))
+PrimaryAssetTypesToScan=(PrimaryAssetType="InstancePropAsset",AssetBaseClass="/Script/UTGameFramework.UTInstancePropAsset",bHasBlueprintClasses=False,bIsEditorOnly=False,Directories=((Path="/Game/Blueprints/UT/GameProps")),SpecificAssets=,Rules=(Priority=-1,ChunkId=-1,bApplyRecursively=True,CookRule=Unknown))

If content is moved, update these paths. Do not depend on old paths stored in the plugin.

/Game/Blueprints/UT
/Attribute /Effect /Ability
/GameProps /Character /Input
/Test

Use any layout you prefer, provided the Asset Manager paths match it.

UT primary assets are configuration assets scanned and registered by UTAssetManager, with stable Primary Asset IDs. They are normally derived from PrimaryDataAsset. Runtime systems create Items or instances from them.

Common primary assets are:

Asset Purpose Runtime result
LevelingAttribute Level and experience rules Leveling Item
ParameterAttribute Health, Mana, Attack, and similar values Attribute Item
UTGameplayEffect Attribute, Tag, Ability, Rule, and other effects Active Effect Item
UUTActiveAbilityAsset / UUTReactiveAbilityAsset Ability configuration Ability instance
UUTStaticGamePropBase Static item definition StaticProp container item
UUTInstancePropAsset Instance item definition InstanceProp instance

The three layers are distinct:

Primary asset configuration -> Blueprint logic class -> Runtime instance

Asset names participate in Primary Asset IDs. Rename assets carefully because IDs are used by references, networking, and save data.

Type Prefix Example
ParameterAttribute UAT_ UAT_Health
LevelingAttribute ULV_ ULV_CharacterLevel
GameplayEffect UGE_ UGE_Damage_20
Active Ability Asset UABP_A_ UABP_A_Fireball
Active Ability UAB_A_ UAB_A_Fireball
Reactive Ability Asset UABP_R_ UABP_R_OnHit
Reactive Ability UAB_R_ UAB_R_OnHit
StaticProp USP_ USP_GlassBall
InstancePropAsset UIP_ UIP_IronSword

These are conventions only. The object name is the PrimaryAssetName.

In the Content Browser, right-click an empty area and choose:

UTGameFramework -> UTPrimary Data Asset

Select the concrete parent class in Pick Parent Class, configure the Details panel, compile/save the asset, and verify that it appears in the typed ID picker. Use UUTActiveAbilityAsset for active abilities and UUTReactiveAbilityAsset for reactive abilities.

Logic-bearing systems normally require two assets:

Configuration asset: UTPrimary Data Asset
Logic class: UTAbility, UTTaskExecution, or a concrete business subclass

For a reactive ability, set its class and IntentTag on the Reactive Ability Asset. Creating only a Blueprint logic class does not create a Primary Asset; creating only an asset does not create custom execution logic.

UTAssetID is UT’s strongly typed wrapper around Unreal’s FPrimaryAssetId. It identifies a primary asset by type and name, for example ParameterAttribute:UAT_Health.

FUTLevelingID, FUTAttributeID, FUTEffectID, FUTAbilityID, FUTStaticGamePropID, and FUTInstanceGamePropID constrain IDs to their corresponding asset types. IDs are suitable for runtime containers, networking, and save data; they are not the asset object itself.

UTAssetID structs are Blueprint types. They can be variables, array elements, or Map keys and support ==, !=, validity checks, and typed Switch operations. Comparison uses the complete Primary Asset ID, not only the displayed name.

UUTAbilityComponent is the runtime center for a character’s Attributes, Levels, Abilities, GameplayEffects, Tags, Ability Slots, and Reactive Intent state.

The main runtime containers are LAContainer, PAContainer, AbilityContainer, ActivatedEffectContainer, AbilitySlotContainer, dynamic Tag plans, and Reactive Intent state. Access runtime data through component APIs rather than manipulating containers directly.

Configure DefaultLevelingAttributeSets, DefaultAttributeSets, DefaultAbilitySets, DefaultAbilitySlots, and fixed StaticTags. BeginPlay registers leveling attributes, parameter attributes, ability sets, and ability slots. Default data initializes a new state; saved data is authoritative during restore.

Actor/Pawn -> AbilityComponent
-> Attributes / Abilities / Effects / Tags / Slots / Intents
InventoryComponent
-> StaticProp / InstanceProp / Equipment
-> derived CarryEffect and EquipEffect

An Actor may have multiple AbilityComponents. Cross-component operations must identify the source and target components. Server authority applies to replicated runtime state.

LevelingAttribute defines level and experience progression. The primary asset stores rules; the AbilityComponent creates the runtime level and experience item.

Create it through UTPrimary Data Asset -> LevelingAttribute. Configure DefaultLevel, MaxLevelBound, CanFallDown, LevelUpType, DefaultXP, AllowXPAccumulate, ConstXp, ExperienceCurve, and optionally ExperienceCurvesDatatable. The curve X axis is the current level and Y is the experience required for the next level.

Create a UUTLevelingAttributeSet, add LevelingAttribute assets to LevelingAttributes, and add the Set to DefaultLevelingAttributeSets. At runtime RegisterLevelingAttributes() creates Items. Use GetRegisterLevelingIDs() and GetLevel(LevelingID) to validate registration.

ParameterAttribute defines non-level values such as Health, Mana, Attack, Agility, and Defence.

Create it through UTPrimary Data Asset -> ParameterAttribute. Configure the default value, value range, ValueSource, and any dependency. The three runtime layers are:

BasicValue -> long-term base value
MiddleValue -> theoretical value after reversible modifiers
FinalValue -> current effective value

Use a Modifier for reversible equipment/buff changes, a Changer for irreversible damage/healing results, and read FinalValue for UI. ValueSource may be static, another attribute, or a function with the required signature.

Create UUTAttributeSet, add ParameterAttribute assets to ParameterAttributes, and add the Set to DefaultAttributeSets. Registering creates runtime Items and dependency links. Do not create arbitrary runtime attributes as the normal gameplay path. During load, saved FinalValue is the truth and MiddleValue is refreshed after runtime Effects are rebuilt.

GameplayEffect is the shared configuration object for Attribute changes, Tags, granted Abilities, Reactive Rules, and item-derived effects. It is not itself the runtime Active Effect.

Create a UTGameplayEffect primary asset and configure Duration, Period, ApplyRule, and EffectBehaviors. An Instant effect normally applies immediately; a duration effect enters the Active Effect container.

  • Instant: applies without remaining in the Active Effect container;
  • UntilRemoved: remains until explicitly cleared;
  • HasDuration: expires after its duration and may trigger periodically.

Use Period for DOT, HOT, regeneration, and similar repeated behavior.

ApplyRule decides whether the initial application is legal. It is evaluated during Apply; Period does not currently re-evaluate the rule on every tick.

Behaviors are the configured operations performed by an Effect. They are applied in Effect order. Behavior CDOs hold configuration only; mutable runtime state belongs to the Active Effect Item.

Attribute Modifier is reversible and changes the theoretical value. Attribute Changer is a direct authoritative change to FinalValue and is not undone by clearing the Effect. Grant Ability and Grant Reactive Rule update the corresponding runtime containers. Calculate uses a calculation class, captures the configured source/target attributes at application time, optionally stores a snapshot, and returns success before recording the Behavior as applied.

Abilities, Tasks, StaticProp/InstanceProp effects, equipment effects, and use logic may apply Effects. The source AbilityComponent is written into FUTEffectContext; cross-component Ability application must specify the target component. Ordinary item-derived Effects generally apply from the owning component to itself.

An Active Effect is created, applies its Behaviors, may tick by Period, and is removed on expiration, clear, cancel, or restore replacement. Reversible contributions are rolled back. Direct Changer and Calculate results are not automatically reversed.

FUTEffectContext currently carries the source/caster AbilityComponent. It identifies the source of an Effect for calculation, validation, networking, and future expansion. It is distinct from the Effect asset and the Active Effect handle.

The server is authoritative for Effect creation, removal, Period, Attribute changes, and runtime handles. Runtime Active Effects are rebuilt through the save/restore path; derived Aggregator state is reconstructed rather than treated as the primary saved truth.

The Aggregator combines independent Effect contributions on a target. It tracks members and contribution counts by Effect, rule, and attribute. Clearing a reversible contribution rolls back only that contribution; irreversible results remain. The Aggregator itself is rebuildable runtime state.

Create a damage Effect with an Instant Attribute Changer, a buff with a duration Attribute Modifier, and a periodic Calculate Effect. Confirm that damage changes FinalValue, the buff can be cleared, snapshots are stored only after a successful Calculate, and clients receive the server result.

AbilityAsset configures an Ability; the Ability class contains the runtime behavior. Active Abilities are initiated by a cast request. Reactive Abilities are selected in response to Intent.

AbilityComponent registers AbilityAssets as runtime AbilityItems, checks rules, creates Ability instances, and tracks handles and lifecycle state.

Use UUTActiveAbilityAsset with a UUTActiveAbility class, and UUTReactiveAbilityAsset with a UUTReactiveAbility class. Do not cross-reference active and reactive classes.

Active Abilities start from input or code. Reactive Abilities start when an Intent matches their configured channel and rules.

CastAbility -> Commit/Behavior/Tasks -> CompleteAbility
CastAbility -> invalid or cancelled -> EndAbility

CompleteAbility() and CompleteParagraph() are legal completion actions. EndAbility() is cleanup for cancellation or invalid termination.

Commit is the server-authoritative decision that a cast is legal and may consume resources or settle configured Effects. Active and Reactive Abilities both use this concept.

AbilityBehavior is the Ability’s business body. Tasks are child operations that create TaskExecutions for data, listening, processor, tick, or presentation work.

Tasks are created, executed, achieved or cancelled, and cleaned up with their Ability. Execute is a Task-specific action; it is not the Ability lifecycle itself.

Data executions apply Effects or calculate Attributes. Listen executions wait for Attribute, Effect, Input, Tag, or Message changes. Performance executions play Niagara, sound, montage, camera, haptic, UI, or post-process results. Processor and Tick executions handle their respective runtime domains.

Cancellation stops the Ability and rolls back reversible work. Cleanup releases listeners, performance objects, and runtime references. Do not use cleanup as the normal successful completion path.

Active Abilities normally follow CastAbility -> CanCast/Commit -> AbilityBehavior -> CompleteAbility. Settle Effects may run after casting or after legal completion according to configuration.

Ability slots contain a SlotName and final AbilityID. Input selects a SlotName rather than hard-coding an Ability. DefaultAbilityID comes from AbilitySet configuration; server-side runtime bindings may change the final value.

CastAbilitySlot may predict from the local slot mirror, but the server RPC should carry the SlotName. The server resolves and validates the authoritative AbilityID, then corrects the client’s mirror. Empty, missing, or unregistered slots cannot be cast.

Old direct key-to-Ability bindings may remain for compatibility, but new projects should prefer Ability Slots and PlayerController input routing. Character-specific skill logic remains in the Ability system.

An Intent contains an Intent channel, context, and optional ScriptStruct payload. The receiver selects a Reactive Ability by channel and rules, then reads the payload in AbilityBehavior.

SingleBest selects the highest-priority match. AllMatches starts every match and does not define execution order. Use chained Intents when business order matters.

The server resolves authoritative responses. ClientWait follows the server result; ClientPredicted may run eligible local work before correction; ClientOnly remains local. Rollback is performed at the Reactive Ability instance/chain level rather than per visual execution.

9.18 Ability, Effect, Task, and Attribute Relationships

Section titled “9.18 Ability, Effect, Task, and Attribute Relationships”

AbilityBehavior decides business flow, Tasks perform operations, Effects carry reusable state changes, and AbilityComponent owns runtime state. Attribute values are modified through Effect, Calculate, TaskExecution, or Intent/Reactive Ability paths.

9.19 Ability Configuration Example and Validation

Section titled “9.19 Ability Configuration Example and Validation”

Create an Active Ability Asset and class, use Run Business Task or Listen Task to create executions, and call CompleteAbility() or CompleteParagraph() when the behavior legally finishes. Create a Reactive Ability Asset and class, set its Intent channel, read GetIntentPayload(), and verify the response in PIE with server/client authority.

  1. Apply an Effect with an Attribute Modifier for reversible MiddleValue changes.
  2. Apply an Effect with an Attribute Changer for direct FinalValue changes.
  3. Apply an Effect with Calculate for a custom calculation class and optional application-time snapshots.
  4. Use TaskExecution_CalculateAttribute for Task-driven calculation.
  5. Send an Intent and let a Reactive Ability interpret the payload and modify its target through the normal authoritative path.

UUTInventoryComponent owns StaticProp, InstanceProp, and Equipment runtime data.

It contains StaticProp and InstanceProp containers, default sets, equipment slot definitions, instance data, and derived item/equipment Effect state.

Configure Default StaticProp Sets, Default InstanceProp Sets, EquipmentSlotName, and the associated AbilityComponent. BeginPlay injects default data for a new game; save restore rebuilds from saved data.

InventoryComponent is the source of truth. StaticProp quantities, InstanceProp GUIDs/dynamic data, and Equipment slot contents are not UI-owned data.

StaticProp is one aggregated quantity per ID. InstanceProp is an individual runtime object identified by a GUID and asset ID.

Use the component APIs for taking, removing, clearing, rebuilding, equipping, unequipping, and using items. Do not mutate container entries directly.

Usable StaticProps check CanUsed, call their use logic, and return success from OnUsed. Consumables perform OnConsumed after successful use and consume UseExpend. Use logic is stateless and may access the InventoryComponent’s AbilityComponent.

Equipment operations validate the instance and slot, rebuild or use the equipment actor, and apply/remove EquipEffects.

Inventory-derived Effects normally apply from the owning InventoryComponent to its associated AbilityComponent. The component relationship must be valid before use or equipment operations.

The server owns quantities, GUIDs, slot contents, and derived item Effects. Clients refresh UI from replicated containers. Save restores inventory facts and then rebuilds CarryEffect and EquipEffect state.

Confirm default items appear once, quantities change correctly, InstanceProp GUIDs remain stable, equipment slots resolve, and save/load does not duplicate items or Effects.

StaticProp represents a stackable item definition and quantity, identified by StaticPropID.

Create a UUTStaticGamePropBase or a concrete subclass and configure name, description, icon, category, CarryEffect, and use behavior.

The container holds quantity per ID. CarryEffect is derived from quantity and must not be treated as independent inventory truth.

StaticProp_Useable checks conditions before OnUsed. StaticProp_Consumables calls the use logic, then OnConsumed removes the configured expenditure after successful use.

Use logic classes are stateless Blueprint-capable helpers. A subclass such as a Potion logic can read the source Potion asset, access its configured Effects, and apply them to the associated AbilityComponent.

Take, use, consume, clear, save, and restore a StaticProp. Confirm quantity and derived Effects are consistent.

InstanceProp represents an individual item with dynamic runtime data.

Configure the primary asset, display fields, instance class, and any base configuration.

The persistent identity is Guid + InstancePropID + DynamicData. Do not use a World Actor pointer as inventory identity.

Take and remove instances through InventoryComponent. Rebuild an instance into an Actor only when it must be displayed, used, or equipped.

Create, save, load, rebuild, equip, and remove an instance. Confirm its GUID and dynamic data survive the process.

Equipment is an InstanceProp assigned to a named equipment slot.

The Equipment primary asset defines static configuration; the InstanceProp stores the individual GUID and dynamic state.

Configure global EquipmentSlotName values and register them in InventoryComponent. Empty slots should be initialized before equipment is assigned.

Validate the GUID and slot, assign or remove the instance, and rebuild equipment actors when needed. Use the InventoryComponent APIs rather than directly changing the slot container.

EquipEffect is derived from equipment state and applies to the associated AbilityComponent. Removing equipment removes the derived reversible effect.

Test empty slots, equip, replace, unequip, save/load, and effect refresh. Handle failed ownership or destination cases explicitly because complete equipment transactions are still project-level policy.

Standalone uses UUTStandaloneSaveManager; online games use UUTOnlineSaveManager. Both expose the shared base manager interface, but their identities and saved data differ.

Save registered Attributes, runtime truth values, persistent Effects, and required Ability state. Rebuild runtime Items and derived state during restore rather than saving transient UObject caches.

Save StaticProp quantities, InstanceProp GUID/dynamic data, and equipment state. Rebuild CarryEffect and EquipEffect after facts are restored.

BeginPlay injects Default Attribute/Prop data for a new game. Restore first creates the structures needed to receive save data, then saved data replaces the defaults. A save restore must not duplicate default items.

Restore foundations, Leveling/Parameter values, persistent Effects, StaticProps, InstanceProps, Equipment slots, Equipment, and derived Effects in the order required by the component system. Saved FinalValue is the truth; dependent MiddleValue is refreshed after Effect and equipment reconstruction.

Test standalone and online paths separately. Verify identity, callbacks, reconnect behavior, attribute truth, inventory quantities, instance GUIDs, equipment, and UI refresh after restore.

UTPawn, UTCharacter, UTPlayerController, UTHUD, UTGameMode, UTGameState, and UTPlayerState provide game-layer integration points.

Use them as base classes for movement, components, and character-specific logic. Keep reusable player input and UI routing in the PlayerController where appropriate.

The controller owns player input routing and requests such as opening panels and Save/Load. It can locate the controlled Pawn and its UT components.

GameMode configures Default Pawn, PlayerController, HUD, GameState, and PlayerState. GameState carries replicated game-level state.

PlayerState stores replicated player identity and state appropriate for the network session.

HUD creates local widgets, caches player component references, toggles panels, and manages reusable Tooltip widgets. It is not the authority for gameplay data.

GameMode -> Pawn / Controller / HUD / GameState / PlayerState
Pawn -> AbilityComponent / InventoryComponent
HUD -> local UI -> read replicated component state

Set the project GameMode and verify World Settings overrides. Configure the Pawn components, Controller input, HUD widgets, and PlayerState identity before testing gameplay.

HUD creates UI; panels display data; AbilityComponent and InventoryComponent remain the facts sources. Widgets must not become a second inventory or attribute database.

Get the AbilityComponent, enumerate registered IDs, call GetAttributeValue(AttributeID), and display FinalValue. Bind refresh logic to OnAttributeValueChange; on notification, query the component again instead of trusting a UI cache.

On open, clear the appropriate TileView, read current StaticProp/InstanceProp containers, and create Item widgets. Quantity comes from InventoryComponent; name, description, and icon come from the resolved primary asset.

Create the configured equipment slots, query each slot’s instance GUID, and display the resolved asset or clear the slot. Refresh from InventoryComponent after equip/unequip or restore.

HUD may create one reusable Tooltip. Item hover passes a UUTPrimaryDataAsset and position to HUD; unhover hides the Tooltip instead of destroying it. Tooltip display fields must come from the asset and must not modify inventory state.

Do not poll attributes every Tick. Bind to AbilityComponent and InventoryComponent notifications, perform one full refresh after open or restore, and perform local refreshes for individual changes. Unbind when a widget or Pawn is replaced.

UT follows Unreal’s server-authoritative model:

Client input/UI -> request or RPC -> server validation -> authoritative mutation -> replication -> UI

The server validates ownership, registered Abilities, slots, targets, Tags, resources, quantities, and equipment before modifying runtime state. Clients do not directly write AbilityComponent, InventoryComponent, or Active Effect state.

For CastAbilitySlot, the client may predict from its local mirror, but the server receives SlotName, resolves its own AbilityID, commits, and replicates the result. Effects and Attribute final values are server results.

The server owns quantities, GUIDs, slots, and derived Effects. Client UI refreshes from replicated containers. Pickup, use, drop, equip, and unequip are server requests.

Prediction improves responsiveness; it does not create authority. When prediction differs from the server, accept the server result, undo or replace local presentation, and refresh from replicated state. Reversible Effect Behaviors can roll back; Calculate and direct Changer results are not automatically reversible.

Test with a server and client PIE session. Verify server validation, replicated attributes, inventory operations, Intent responses, slot correction, UI refresh, reconnect, and save identity. Standalone cannot prove RPC or replication correctness.

18. Project Integration and Complete Workflow

Section titled “18. Project Integration and Complete Workflow”

Install and enable UTGameFramework, configure Asset Manager and scan paths, then create project subclasses from UT base classes.

Set GameMode, Default Pawn, PlayerController, HUD, GameState, and PlayerState. Check World Settings overrides.

Add AbilityComponent and InventoryComponent. Configure AttributeSets, AbilitySets, default slots, default Prop Sets, EquipmentSlotName, and the associated component relationship.

Create valid primary assets, keep them under scan paths, fill display data and classes, and reference only valid IDs from Default Sets. Do not put transient runtime objects or Effect Handles in defaults.

18.5 Connect Input, Ability, Items, and Equipment

Section titled “18.5 Connect Input, Ability, Items, and Equipment”

Use Enhanced Input through PlayerController or the appropriate character entry point. Input selects an Ability Slot; Ability and Inventory systems perform authoritative validation. Item and equipment changes go through their component APIs.

HUD creates panels, passes component references, initializes from current state, and binds change notifications. UI displays values and requests operations; it does not own authoritative data.

Select Standalone or Online SaveManager. Clients may request operations, but online save/load executes on the server. Refresh UI after restore completion.

Verify GameMode and classes, component initialization, Attribute registration, default Props, equipment, Active and Reactive Abilities, Effects and Tasks, server authority, UI refresh, save/load, repeated panel opening, and Pawn replacement without duplicate widgets, bindings, items, or Effects.