Ability System Component
ASC는 ActorComponent로 GAS 요소들의 인터렉션을 다룬다.
Game Abilities를 사용하거나, Attribute가 있거나, Gameplay Effect를 받는 모든 액터는 ASC가 있어야 한다.
Attribute를 제외한 모든 GAS 요소가 ASC에 의해 관리되고 Replicate된다.
- Attribute들은 자신의 Attribute Set에 의해 Replicate된다.
ASC는 Owner Actor와 Avatar Actor를 가진다.
- Owner Actor : ASC가 붙어있는 Actor
- Avatar Actor : ASC가 물리적으로 표현되는 Actor
ASC의 Owner와 Aavatar는 같을 수도, 다를 수도 있다.
MOBA의 미니언처럼 단순한 캐릭터의 경우 Owner와 Actor가 같아도 무방하다.
하지만 캐릭터가 리스폰되고, 캐릭터가 스폰되어도 Attributes 와 Effects 가 유지되어야 한다면
Owner는 PlayerState로 설정하고, Avatar는 Character로 설정하는 것이 좋다.
Owner를 PlayerState로 설정할 경우, Player State의 NetUpdateFrequency 를 늘려야 한다. 일반적으로 PlayerState의 NetUpdatefFrequency 는 매우 낮아 Attributes and GameplayTags 를 변경하는 등의 경우 클라이언트에서 딜레이나 렉이 발생할 수 있기 떄문이다.
Owner와 Avatar가 다를 경우 각각 추상 클래스 IAbilitySystemInterface 를 상속받아 순수 가상 함수UAbilitySystemComponent* GetAbilitySystemComponent() const 함수를 구현해야한다.
ASC는 현재 활성화된 GE를 FActiveGameplayEffectsContainer ActiveGameplayEffects 에 저장한다.
ASC는 부여된 GA를 FGameplayAbilitySpecContainer ActivatableAbilities 에 저장한다.
ActivatableAbilities.Items 를 순회(iterate)할 때 ABILITYLIST_SCOPE_LOCK()을 사용해야한다.
순회하는 도중에 ActivatableAbilities.Items 목록이 변하여 null 포인터에 접근할 수도 있기 때문에 순회를 도는 중에는 ActivatableAbilities가 유지되도록 하는 것이다. 그리고 순회중에 Ability를 삭제하면 안된다.
void UMyCharacter::ListAbilities()
{
if (!AbilitySystemComponent) return;
// ActivatableAbilities.Items를 안전하게 순회하기 위해 반드시 스코프 락을 건다
ABILITYLIST_SCOPE_LOCK();
for (const FGameplayAbilitySpec& Spec : AbilitySystemComponent->ActivatableAbilities.Items)
{
if (Spec.Ability)
{
UE_LOG(LogTemp, Log, TEXT("Ability: %s | Level: %d | InputID: %d"),
*Spec.Ability->GetName(),
Spec.Level,
Spec.InputID);
}
}
}
ASC Replication Mode
ASC는 Gameplay Effect , GameplayTags 그리고 GameplayCues 를 Replication하기 위한 3가지 replication 모드가 있다. (Attributes는 Attribute Set 에서 Replicate 된다.)
Replication Mode | When to Use | Description |
Full | 싱글 플레이어 | 모든 클라이언트에 모든 GameplayEffect가 Replicate된다. |
Mixed | 멀티 플레이어와 플레이어에 컨트롤되는 Actor | Owning Client에 GameplayEffect가 Replicate된다. GameplayTags와 GameplayCues 는 모두에게 replicate된다. |
Minimal | 멀티 플레이어와 AI에 컨트롤되는 Actor | GameplayEffect는 어디에도 Replicate되지 않는다. GameplayTags와 GameplayCues 는 모두에게 replicate된다. |
⚠️ Mixed Replication 모드에서는 ASC의 OwnerActor의 Owner가 Controller여야 한다.
PlayerState의 Owner의 디폴트 값은 Controller다.
따라서 ASC의 Owenr가 PlayerState일 때는 문제가 없지만,
만약 그렇지 않다면 OwnerActor의 SetOwner()를 호출하여 Owner를 Controller로 설정해줘야 한다.
Setup and Initialization
ASC 는 C++ 네이티브에서 Owner Actor의 생성자에서 생성한 뒤 replicated 설정을 해야한다.
AGDPlayerState::AGDPlayerState()
{
// Create ability system component, and set it to be explicitly replicated
AbilitySystemComponent = CreateDefaultSubobject<UGDAbilitySystemComponent>(TEXT("AbilitySystemComponent"));
AbilitySystemComponent->SetIsReplicated(true);
//...
}
ASC는 서버와 클라이언트 양쪽에서 OwnerActor와 AvatarActor로 초기화되어야 한다.
Owner가 Pawn인 경우 Controller가 설정된 후(소유권 획득 후)에 초기화해야 한다.
싱글 플레이어 게임은 서버 측 경로만 신경 쓰면 된다.
플레이어가 제어하는 캐릭터에서 ASC가 Pawn에 위치하는 경우,
작성자는 보통 서버에서는 Pawn의 PossessedBy() 함수에서 초기화하고,
클라이언트에서는 PlayerController의 AcknowledgePossession() 함수에서 초기화한다.
- Server
void APACharacterBase::PossessedBy(AController * NewController)
{
Super::PossessedBy(NewController);
if (AbilitySystemComponent)
{
AbilitySystemComponent->InitAbilityActorInfo(this, this);
}
// ASC MixedMode replication requires that the ASC Owner's Owner be the Controller.
SetOwner(NewController);
}
- Client
void APACharacterBase::PossessedBy(AController * NewController)
{
Super::PossessedBy(NewController);
if (AbilitySystemComponent)
{
AbilitySystemComponent->InitAbilityActorInfo(this, this);
}
// ASC MixedMode replication requires that the ASC Owner's Owner be the Controller.
SetOwner(NewController);
}
플레이어가 컨트롤하는 캐릭터에서 ASC가 PlayerState에 위치하는 경우,
작성자는 보동 서버에서는 Pawn의 PossessedBy() 함수에서 초기화 하고,
클라이언트에서는 Pawn의 OnRep_PlayerState() 에서 초기화한다.
이렇게 하면 클라이언트에서 PlayerState가 존재함을 보장할 수 있다.
- Server
// Server only
void AGDHeroCharacter::PossessedBy(AController * NewController)
{
Super::PossessedBy(NewController);
AGDPlayerState* PS = GetPlayerState<AGDPlayerState>();
if (PS)
{
// Set the ASC on the Server. Clients do this in OnRep_PlayerState()
AbilitySystemComponent = Cast<UGDAbilitySystemComponent>(PS->GetAbilitySystemComponent());
// AI won't have PlayerControllers so we can init again here just to be sure. No harm in initing twice for heroes that have PlayerControllers.
PS->GetAbilitySystemComponent()->InitAbilityActorInfo(PS, this);
}
//...
}
- Client
// Client only
void AGDHeroCharacter::OnRep_PlayerState()
{
Super::OnRep_PlayerState();
AGDPlayerState* PS = GetPlayerState<AGDPlayerState>();
if (PS)
{
// Set the ASC for clients. Server does this in PossessedBy.
AbilitySystemComponent = Cast<UGDAbilitySystemComponent>(PS->GetAbilitySystemComponent());
// Init ASC Actor Info for clients. Server will init its ASC when it possesses a new Actor.
AbilitySystemComponent->InitAbilityActorInfo(PS, this);
}
// ...
}
만약 다음과 같은 로그 메세지가 뜬다면 ASC를 Client에서 초기화하지 않은 것이다.
LogAbilitySystem: Warning: Can't activate LocalOnly or LocalPredicted ability %s when not local!
'🖥️ Study Note > Unreal Engine' 카테고리의 다른 글
[Unreal] Game Ability System(GAS) (0) | 2025.06.10 |
---|---|
[Unreal Engine] 모듈(Module) (0) | 2025.05.21 |
[Unrael Engine] IWYU 간단 정리 (0) | 2025.05.21 |
[Unreal Engine] Animation Blueprint에서 Owner 캐릭터의 정보를 가져오는 3가지 방법 (1) | 2025.05.19 |