futurelabunseen / A-SeunghyunHong

0 stars 1 forks source link

[Bug] HP 회복이 안되는 문제 #5

Open strurao opened 1 month ago

strurao commented 1 month ago

문제 상황

F키를 누르면 HealHp() 함수를 호출해서, 회복이 최대 회복의 20%가 회복되는 기능을 구현하던 중 회복이 안되는 문제가 있습니다.

// AGOPlayerCharacter.cpp

// F키 입력
void AGOPlayerCharacter::OnSpellF()
{
    Stat->HealHp(); // Stat은 GOCharacterStatComponent입니다
    ... 
}

(아래 영상에서는 테스트용으로 스킬 제한을 풀어둔 상태입니다!!)

(아래쪽 윈도우) 클라이언트가

(위쪽 윈도우) 서버한테 공격을 받은 후

Hp를 회복하기 위해서 F키를 누르면,

잠깐 동안만 회복이 되고

다시 Hp가 Regenerate 되면서 F키를 누르기 전인 상태로 돌아갔습니다.

https://github.com/futurelabunseen/A-SeunghyunHong/assets/126440235/07a8d9ba-8a98-4590-ae39-26b4c45be91a


문제 원인

HealHp() 함수를 GOCharacterStatComponent.h 헤더 파일에서 구현한 것이 원인이었습니다.

// GOCharacterStatComponent.h

    FORCEINLINE void HealHp() {
        CurrentHp = FMath::Clamp(CurrentHp + CurrentHp * 0.2, 0, GetTotalStat().MaxHp);
        OnHpChanged.Broadcast(CurrentHp, MaxHp);
    }

혹시 FORCEINLINE 함수에서는 델리게이트가 안되는 것인가..?! 라는 생각이 들었습니다.

그치만 득우님 강의에서도 FORCEINLINE 에서 델리게이트를 사용했던 기억을 더듬어보면 FORCEINLINE 지시어 자체가 델리게이트의 실행을 방해하거나 막지는 않는 것 같습니다…

그래도 궁금해서 FORCEINLINE을 빼고 다시 컴파일을 해봤는데 문제는 여전했습니다!

// GOCharacterStatComponent.h

    void HealHp() {
        CurrentHp = FMath::Clamp(CurrentHp + CurrentHp * 0.2, 0, GetTotalStat().MaxHp);
        OnHpChanged.Broadcast(CurrentHp, MaxHp);
    }

해결

HealHp() 함수를 헤더 파일 대신에 cpp 파일에서 구현해주니 회복이 정상적으로 되었습니다.

// GOCharacterStatComponent.cpp

void UGOCharacterStatComponent::HealHp()
{
    CurrentHp = FMath::Clamp(CurrentHp + CurrentHp * 0.2, 0, GetTotalStat().MaxHp); 
    OnHpChanged.Broadcast(CurrentHp, MaxHp);
}

해결 결과

(아래쪽 윈도우) 클라이언트가 공격 →

Hp가 깎인 (위쪽 윈도우) 서버가 F키를 누르면 →

회복이 잘 되고 있습니다.

https://github.com/futurelabunseen/A-SeunghyunHong/assets/126440235/2527e3ac-9128-47ae-a7a7-c0c0ab194d1b

strurao commented 1 month ago

+) 추가 문제: 서버에서는 HealHp가 정상적으로 작동하지만, 클라이언트에서는 문제가 여전합니다.

예상 원인: 권한 차이라고 생각하여 코드를 수정 중입니다. 클라이언트에서 함수를 호출할 때, 서버 권한이 없어서 상태 변화가 서버와 다른 클라이언트에 제대로 반영되지 않을 수 있을 것 같습니다.

strurao commented 1 month ago

클라이언트에서 반영되지 않은 문제 해결 방법 : ServerRPC 함수 작성

// Heal Spell
void AGOPlayerCharacter::OnSpellF()
{
    if (HasAuthority())
    {
        Stat->HealHp();
    }
    else
    {
        Stat->ServerHealHp();
    }
}

void UGOCharacterStatComponent::HealHp()
{
    CurrentHp = FMath::Clamp(CurrentHp + CurrentHp * 0.2, 0, GetTotalStat().MaxHp);
    OnHpChanged.Broadcast(CurrentHp, MaxHp);
}

void UGOCharacterStatComponent::ServerHealHp_Implementation()
{
    HealHp();
    UE_LOG(LogTemp, Log, TEXT("ServerHealHp_Implementation "));
}

bool UGOCharacterStatComponent::ServerHealHp_Validate()
{
    return true;  // 추가적인 유효성 검사 로직이 필요할 경우 이곳에 구현
}

결과 화면

https://github.com/futurelabunseen/A-SeunghyunHong/assets/126440235/256b6f75-e395-4bdc-993d-273a4b5a5c4e