// Copyright (c) 2026 Reignance Studios. MIT License, see LICENSE. #include "RSExampleCharacter.h" #include "AbilitySystemComponent.h" #include "Abilities/GameplayAbility.h" #include "GameFramework/PlayerState.h" #include "RSAbilitySystemLibrary.h" UAbilitySystemComponent* ARSExampleCharacter::GetAbilitySystemComponent() const { // Ask the PlayerState, never FindAbilitySystemComponent(this): that checks this // actor's IAbilitySystemInterface first, which is this function, and recurses. return URSAbilitySystemLibrary::FindAbilitySystemComponent(GetPlayerState()); } void ARSExampleCharacter::PossessedBy(AController* NewController) { Super::PossessedBy(NewController); InitAbilityActorInfo(); GrantStartupAbilities(); } void ARSExampleCharacter::OnRep_PlayerState() { Super::OnRep_PlayerState(); // Without this, the owning client's ASC has no avatar: predicted abilities // fail to activate locally, and montages and cues play only on the server. InitAbilityActorInfo(); } void ARSExampleCharacter::InitAbilityActorInfo() { APlayerState* PS = GetPlayerState(); UAbilitySystemComponent* ASC = PS ? URSAbilitySystemLibrary::FindAbilitySystemComponent(PS) : nullptr; if (!ASC) { return; } // Owner = PlayerState (holds the ASC), Avatar = this pawn (plays montages, has a location). ASC->InitAbilityActorInfo(PS, this); } void ARSExampleCharacter::GrantStartupAbilities() { UAbilitySystemComponent* ASC = GetAbilitySystemComponent(); if (!ASC || !HasAuthority()) { return; } // Grant once per PlayerState, not once per pawn. Respawned pawns reuse the // same ASC, so granting again would stack duplicate specs. for (const TSubclassOf& AbilityClass : StartupAbilities) { if (AbilityClass && !ASC->FindAbilitySpecFromClass(AbilityClass)) { ASC->GiveAbility(FGameplayAbilitySpec(AbilityClass, 1, INDEX_NONE, this)); } } }