Engineering Notes
Quick-reference bullets derived from project work. Class names, patterns, and gotchas that come up repeatedly in Unreal Engine C++ development.
Gameplay Ability System
- UAbilitySystemComponent must be initialized on both server and client via InitAbilityActorInfo
- UGameplayEffect is a data-only class - never override business logic in it
- FGameplayAttributeData requires both Base and Current values for replication to work
- Tag-based activation is safer than class-based when multiple abilities share logic
- GE duration of 0 = Instant, -1 = Infinite; HasDuration requires manual cancellation
Lyra Architecture
- ULyraExperienceDefinition drives pawn data, ability sets, and component lists per map
- ULyraHeroComponent handles pawn extension and defers setup until experience is loaded
- Ability sets are granted via FLyraAbilitySet_GrantedHandles - store to revoke later
- Input tag bindings in ULyraInputConfig map InputActions → GameplayTags for GAS
- B_Hero_ShooterMannequin is the canonical pawn reference in Lyra shooter content
Editor Tooling (FEdMode)
- Override HandleClick() in FEdMode to intercept viewport click events
- Custom toolkits provide the left-side panel via SWidget returned in MakeWidget()
- FEditorModeTools::ActivateMode() must be called from the editor module, not runtime
- Always deregister editor mode handles in ShutdownModule to avoid editor crashes
- IDetailsView can be embedded in a custom Slate panel for property editing
Multiplayer & Replication
- UFUNCTION(Server) requires _Implementation and _Validate suffixes
- GetLifetimeReplicatedProps must call Super and list all UPROPERTY(Replicated) vars
- bReplicates = true in constructor; call SetReplicates(true) for dynamically spawned actors
- Server authority: check HasAuthority() before mutating gameplay state
- OnRep_ functions fire on clients but NOT on the server - guard design accordingly
CommonUI
- UCommonActivatableWidget manages focus and input pass-through - override NativeActivated()
- UCommonUISubsystem handles root navigation layer and push/pop stack operations
- Input routing: set InputConfig on each widget to declare which inputs it consumes
- Activatable widgets require a UCommonActivatableWidgetContainerBase as their parent
- Always call DeactivateWidget() before garbage-collecting activatable instances