팀 프로젝트 진행 내용
1. 레벨 이동 중 어빌리티 오류 수정
LogWindows: Error: === Critical error: ===
LogWindows: Error:
LogWindows: Error: Unhandled Exception: EXCEPTION_ACCESS_VIOLATION reading address 0x00000000000000d8
LogWindows: Error:
LogWindows: Error: [Callstack] 0x00007ff6640621ee AO.exe!UAO_GameplayAbility_Sprint::CanActivateAbility() [C:\Users\User\Desktop\3rd_4th-Team4-CH6-Project\Source\AO\Private\Character\GAS\Ability\AO_GameplayAbility_Sprint.cpp:44]
LogWindows: Error: [Callstack] 0x00007ff663cae8e3 AO.exe!UAbilitySystemComponent::InternalTryActivateAbility() []
LogWindows: Error: [Callstack] 0x00007ff663cd0329 AO.exe!UAbilitySystemComponent::TryActivateAbility() []
LogWindows: Error: [Callstack] 0x00007ff6640f14ba AO.exe!AAO_PlayerCharacter::HandleGameplayAbilityInputPressed() [C:\Users\User\Desktop\3rd_4th-Team4-CH6-Project\Source\AO\Private\Character\AO_PlayerCharacter.cpp:475]
LogWindows: Error: [Callstack] 0x00007ff6640f0bf9 AO.exe!TBaseUObjectMethodDelegateInstance<0,AAO_PlayerCharacter,void __cdecl(void),FDefaultDelegateUserPolicy,int>::Execute() [C:\Program Files\Epic Games\UE_5.6\Engine\Source\Runtime\Core\Public\Delegates\DelegateInstancesImpl.h:673]
LogWindows: Error: [Callstack] 0x00007ff66406f054 AO.exe!FEnhancedInputActionEventDelegateBinding<TDelegate<void __cdecl(void),FDefaultDelegateUserPolicy> >::Execute() [C:\Program Files\Epic Games\UE_5.6\Engine\Plugins\EnhancedInput\Source\EnhancedInput\Public\EnhancedInputComponent.h:321]
LogWindows: Error: [Callstack] 0x00007ff663f45599 AO.exe!UEnhancedPlayerInput::EvaluateInputDelegates() []
LogWindows: Error: [Callstack] 0x00007ff66238774a AO.exe!UPlayerInput::ProcessInputStack() []
LogWindows: Error: [Callstack] 0x00007ff661cc3878 AO.exe!APlayerController::ProcessPlayerInput() []
LogWindows: Error: [Callstack] 0x00007ff661cdd58f AO.exe!APlayerController::TickPlayerInput() []
LogWindows: Error: [Callstack] 0x00007ff661cc0dea AO.exe!APlayerController::PlayerTick() []
LogWindows: Error: [Callstack] 0x00007ff661cdb917 AO.exe!APlayerController::TickActor() []
LogWindows: Error: [Callstack] 0x00007ff660ac33fe AO.exe!FActorTickFunction::ExecuteTick() []
LogWindows: Error: [Callstack] 0x00007ff6622a86c9 AO.exe!FTickFunctionTask::DoTask() []
LogWindows: Error: [Callstack] 0x00007ff6622adc72 AO.exe!TGraphTask<FTickFunctionTask>::ExecuteTask() []
LogWindows: Error: [Callstack] 0x00007ff65a1b53f3 AO.exe!UE::Tasks::Private::FTaskBase::TryExecuteTask() []
LogWindows: Error: [Callstack] 0x00007ff65a1a82e9 AO.exe!FNamedTaskThread::ProcessTasksNamedThread() []
LogWindows: Error: [Callstack] 0x00007ff65a1a86d9 AO.exe!FNamedTaskThread::ProcessTasksUntilIdle() []
LogWindows: Error: [Callstack] 0x00007ff65a1a8e15 AO.exe!FTaskGraphCompatibilityImplementation::ProcessUntilTasksComplete() []
LogWindows: Error: [Callstack] 0x00007ff6622c860c AO.exe!FTickTaskSequencer::ReleaseTickGroup() []
LogWindows: Error: [Callstack] 0x00007ff6622cfe9f AO.exe!FTickTaskManager::RunTickGroup() []
LogWindows: Error: [Callstack] 0x00007ff66178ffbe AO.exe!UWorld::RunTickGroup() []
LogWindows: Error: [Callstack] 0x00007ff661798ba8 AO.exe!UWorld::Tick() []
LogWindows: Error: [Callstack] 0x00007ff6614608f6 AO.exe!UGameEngine::Tick() []
LogWindows: Error: [Callstack] 0x00007ff66281e7b1 AO.exe!FEngineLoop::Tick() []
LogWindows: Error: [Callstack] 0x00007ff662831f0c AO.exe!GuardedMain() []
LogWindows: Error: [Callstack] 0x00007ff662831fea AO.exe!GuardedMainWrapper() []
LogWindows: Error: [Callstack] 0x00007ff662834e18 AO.exe!LaunchWindowsStartup() []
LogWindows: Error: [Callstack] 0x00007ff662842414 AO.exe!WinMain() []
LogWindows: Error: [Callstack] 0x00007ff6697044da AO.exe!__scrt_common_main_seh() [D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288]
LogWindows: Error: [Callstack] 0x00007fff4303e8d7 KERNEL32.DLL!UnknownFunction []
- 테스트 중에 위와 같은 에러 로그와 함께 크래시가 발생했다.
- 레벨 전환 중에서 해당 크래시가 발생했는데,
CanActivateAbility()에서 null 값에 접근해서 발생한 오류인 것으로 보였다.
// AO_GameplayAbility_Sprint.cpp
bool UAO_GameplayAbility_Sprint::CanActivateAbility(const FGameplayAbilitySpecHandle Handle,
const FGameplayAbilityActorInfo* ActorInfo, const FGameplayTagContainer* SourceTags,
const FGameplayTagContainer* TargetTags, FGameplayTagContainer* OptionalRelevantTags) const
{
if (!Super::CanActivateAbility(Handle, ActorInfo, SourceTags, TargetTags, OptionalRelevantTags))
{
return false;
}
if (CharacterMovement->Velocity.SizeSquared2D() < KINDA_SMALL_NUMBER)
{
return false;
}
if (CharacterMovement->IsCrouching())
{
return false;
}
const UAO_PlayerCharacter_AttributeSet* AttributeSet = ActorInfo->AbilitySystemComponent->GetSetChecked<UAO_PlayerCharacter_AttributeSet>();
const float CurrentStamina = AttributeSet->GetStamina();
const float MaxStamina = AttributeSet->GetMaxStamina();
if (CurrentStamina < MaxStamina * AttributeSet->StaminaLockoutPercent)
{
return false;
}
return true;
}
- Sprint 어빌리티의 경우에는 플레이어의 입력에 따라 즉각적으로 실행되는 어빌리티인데, 레벨 전환 간에 캐싱해놓은
CharacterMovement에 접근하다 보니 해당 오류가 발생한 것으로 보인다.
- 기존의 GA 인스턴스가 남아있는데, 캐릭터가 파괴되는 타이밍이 빨라서
CharacterMovement에 접근해서 크래시가 발생한 것이지 않을까 생각했다.
- Sprint의 경우에는 자주 사용하게 되어서 Ability 차원에서
Character와 CharacterMovement를 캐싱해놓는데, 이 구조가 수명주기가 흔들리는 순간에 상당히 취약해보여서 해당 부분을 캐싱해놓는 구조가 아니라 매번 가져오는 것으로 수정했다.
// AO_GameplayAbility_Sprint.cpp
// void UAO_GameplayAbility_Sprint::OnAvatarSet(const FGameplayAbilityActorInfo* ActorInfo,
// const FGameplayAbilitySpec& Spec)
// {
// Super::OnAvatarSet(ActorInfo, Spec);
//
// Character = Cast<AAO_PlayerCharacter>(ActorInfo->AvatarActor.Get());
// checkf(Character, TEXT("Failed to cast AvatarActor to ACharacter"));
//
// CharacterMovement = Character->GetCharacterMovement();
// checkf(CharacterMovement, TEXT("Failed to get CharacterMovementComponent"));
// }
bool UAO_GameplayAbility_Sprint::CanActivateAbility(const FGameplayAbilitySpecHandle Handle,
const FGameplayAbilityActorInfo* ActorInfo, const FGameplayTagContainer* SourceTags,
const FGameplayTagContainer* TargetTags, FGameplayTagContainer* OptionalRelevantTags) const
{
if (!Super::CanActivateAbility(Handle, ActorInfo, SourceTags, TargetTags, OptionalRelevantTags))
{
return false;
}
if (!ActorInfo || !ActorInfo->AbilitySystemComponent.IsValid() || !ActorInfo->AvatarActor.IsValid())
{
return false;
}
const AAO_PlayerCharacter* Character = Cast<AAO_PlayerCharacter>(ActorInfo->AvatarActor.Get());
if (!Character)
{
return false;
}
const UCharacterMovementComponent* CharacterMovement = Character->GetCharacterMovement();
if (!CharacterMovement)
{
return false;
}
...
}