Multiplayer

Multiplayer is a first-class requirement. The runtime is built for a dedicated server + multiple clients from the ground up.

Replication

StateMechanism
Per-node NodeState / CurrentLevelFastArray (FCrimsonNodeStateArray) - delta-only, MarkItemDirty at every mutation
Per-tree bIsActiveReplicatedUsing = OnRep_IsActive -> broadcasts OnSkillTreeActivationChanged
Resource pool allocationsFastArray (FCrimsonResourceAllocationArray) - server-authoritative budgets
Tree instances on the managerAddReplicatedSubObject per instance

Authority

The player-driven node actions (ActivateNode, DeactivateNode, IncrementLevel, DecrementLevel) early-return unless GetOwnerRole() == ROLE_Authority, and clients reach them only through validated Server_ RPCs. The lifecycle methods the manager calls on the authoritative path (ShutdownNode, RestoreNodeToState, SuspendNodeEffects / ResumeNodeEffects) run server-side as part of that flow - RestoreNodeToState applies its GAS events only under GetOwner()->HasAuthority().

HasAuthority(), not IsOwnerActorAuthoritative()
IsOwnerActorAuthoritative() is a GAS-only helper on UGameplayAbility. A generic UActorComponent/UObject uses GetOwner()->HasAuthority() or GetOwnerRole() == ROLE_Authority.

RPC entry points

RPCPurpose
Server_RequestSkillNodeActionSingle-node action; _Validate rejects malformed Guids
Server_CommitNodeChangesAtomic batch - all-or-nothing
Server_RespecAndCommitAtomic respec - clear then apply a new allocation
Client_DisplayNodeFailureMessageUnreliable client RPC: shows a failure message when a server-side action is rejected