Mini

[UE5] 멀티플레이 test // 서버 트러블슈팅 클라에서 데미지 표시안됨 해결, 각자 클라에서는 각자의 데미지만 표시 구현 본문

UE5/Advance Damage Techniques

[UE5] 멀티플레이 test // 서버 트러블슈팅 클라에서 데미지 표시안됨 해결, 각자 클라에서는 각자의 데미지만 표시 구현

Mini_96 2024. 8. 22. 17:14

* 문제 : 호출스택 타고가면서 탐색

원인 : 게임모드가 null임 / 게임모드는 gameplaystatics사용해서 클라에서 얻어오는경우에만 서버에서 유효함

클라에서 null이 되버림

 

UCharacterClassInfo* UAuraAbilitySystemLibrary::GetCharacterClassInfo(const UObject* WorldContextObject)
{
    //게임모드를 얻어오고
    AAuraGameModeBase* AuraGameMode = Cast<AAuraGameModeBase>(UGameplayStatics::GetGameMode(WorldContextObject));
    if (AuraGameMode == nullptr) return nullptr;

    //게임모드에있는 클래스정보들에 대해
    return  AuraGameMode->CharacterClassInfo;
}

 

* 해결 : auraEmemy > beginplay에서

능력주는 부분을 서버일경우에만 실행되도록함

if(HasAuthority())
	{
		UAuraAbilitySystemLibrary::GiveStartupAbilities(this,AbilitySystemComponent);
	}
if(HasAuthority())
	{
		InitializeDefaultAttributes();
	}

 

* 문제 : 클라에서 데미지 위젯이 안나옴

* 원인 : 0번 idx의 pc == 서버의 pc

클라에서는 당연히 not valid임

void UAuraAttributeSet::ShowFloatingText(const FEffectProperties& Props, float Damage, bool bBlockedHit, bool bCriticalHit) const
{
    //데미지위젯을 데미지받은 캐릭위에 뛰우기
    if(Props.SourceCharacter!=Props.TargetCharacter) //자기자신은 제외
    {
       AAuraPlayerController* PC= Cast<AAuraPlayerController>(UGameplayStatics::GetPlayerController(Props.SourceCharacter,0));
       if(PC)
       {
          PC->ShowDamageNumber(Damage,Props.TargetCharacter,bBlockedHit,bCriticalHit);
       }
    }
}

* 해결 : 해당 소스(클라인경우는 클라의 aura / 서버인경우 서버의 aura)의 pc를 받아오도록 수정. 

void UAuraAttributeSet::ShowFloatingText(const FEffectProperties& Props, float Damage, bool bBlockedHit, bool bCriticalHit) const
{
    //데미지위젯을 데미지받은 캐릭위에 뛰우기
    if(Props.SourceCharacter!=Props.TargetCharacter) //자기자신은 제외
    {
       AAuraPlayerController* PC= Cast<AAuraPlayerController>(Props.SourceCharacter->Controller);
       if(PC)
       {
          PC->ShowDamageNumber(Damage,Props.TargetCharacter,bBlockedHit,bCriticalHit);
       }
    }
}

IslocalController => 로컬(클라)에서만 데미지 띄우도록 수정

//대상 캐릭터위에 데미지 띄워주는 함수
//RPC함수 : 서버에서 호출가능
void AAuraPlayerController::ShowDamageNumber_Implementation(float DamageAmount, ACharacter* TargetCharacter, bool bBlockedHit, bool bCriticalHit)
{
    //대상캐릭터위치에 위젯생성함
    if(IsValid(TargetCharacter) && DamageTextComponentClass && IsLocalController())
    {
       UDamageTextComponent* DamageText= NewObject<UDamageTextComponent>(TargetCharacter, DamageTextComponentClass);
       DamageText->RegisterComponent(); //위젯을 동적생성 -> 수동으로 컴포넌트 등록
       //Text를 대상캐릭터의 루트에 붙이기
       DamageText->AttachToComponent(TargetCharacter->GetRootComponent(),FAttachmentTransformRules::KeepRelativeTransform);
       DamageText->DetachFromComponent(FDetachmentTransformRules::KeepWorldTransform); //계속못따라다니도록 분리, 그냥 사라질숫자임
       DamageText->SetDamageText(DamageAmount, bBlockedHit,bCriticalHit); //Text값 설정
    }
}

 

* 문제 : 클라모드로실행 -> 전용서버생김 -> 전용서버에서는 아무것도 안나옴

구현 : 각자 클라에서는 각자의 데미지만 표시

* 원인 : targetASC에서

void AAuraProjectile::OnSphereOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
                                      UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
    //오버랩되면 소리재생
    UGameplayStatics::PlaySoundAtLocation(this,ImpactSound,GetActorLocation(),FRotator::ZeroRotator);

    //오버랩되면 효과실행
    UNiagaraFunctionLibrary::SpawnSystemAtLocation(this,ImpactEffect,GetActorLocation());
    //클라에서 사운드 파괴된경우 예외처리
    if(LoopingSoundComponent) LoopingSoundComponent->Stop();
    // LoopingSoundComponent->Stop(); // 적과오버랩되면 불 자체에서나는 루핑사운드 중지

    //서버에있는경우 
    if(HasAuthority())
    {
       if(auto TargetASC = UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(OtherActor))
       {
          //GE 적용하기
          TargetASC->ApplyGameplayEffectSpecToSelf(*DamageEffectSpecHandle.Data.Get());
       }
       
       Destroy(); //파괴 => 클라에복제안되게
    }

* 해결 : 예를들어, 불 발사자가 클라1이고 내가 클라 2인경우, 클라2에서는 효과발생자가 클라1 != 나(클라2) 이므로

do nothing 처리.

void AAuraProjectile::OnSphereOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
                                      UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
    //효과발생자 == 다른액터(클라)인경우 do nothing ()    
    if(DamageEffectSpecHandle.Data.Get()->GetContext().GetEffectCauser() == OtherActor) return;

null check 추가

//효과발생자 == 다른액터인경우 do nothing ()
if(DamageEffectSpecHandle.Data.IsValid() && DamageEffectSpecHandle.Data.Get()->GetContext().GetEffectCauser() == OtherActor) return;

결과 : 각자 클라에서는 각자의 데미지만 보이도록

 

 

 

* 문제 : 불이 적 머리위로 지나감

* 해결 : pitch 0 삭제

void UAuraProjectileSpell::SpawnProjectile(const FVector& ProjectileTargetLocation)
{
    //GEngine->AddOnScreenDebugMessage(1,8.f,FColor::Blue,FString("Effect Applied!"));
    //발사체는 서버에서생성, 클라는 복제본을 보게될거임
    //발사체가 서버에있는지 어케암?
    const bool bIsServer = GetAvatarActorFromActorInfo()->HasAuthority(); //아바타액텨 ==불 의 권위확인
    if(! bIsServer) return ; //발사체가 서버있는경우만 발사체 생성

    ICombatInterface* CombatInterface = Cast<ICombatInterface>(GetAvatarActorFromActorInfo()); //해당액터가 전투인터를 구현하면, 얻을수있음
    if(CombatInterface)
    {
       const FVector SocketLocation = CombatInterface->GetCombatSocketLocation();
       FRotator Rotation = (ProjectileTargetLocation - SocketLocation).Rotation(); //방향벡터의 회전각 구하기
       // Rotation.Pitch=0.f; // 지면과 평행하게 움직이도록

 

 

 

* 자잘한 버그 fix

클라에서 사운드 nullptr 버그 fix

 

- 클라에서 소리가2번나는 버그 해결 : !bHit인경우에만 실행 되도록 수정

void AAuraProjectile::OnSphereOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
                                      UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
    //효과발생자 == 다른액터(클라)인경우 do nothing ()
    if(DamageEffectSpecHandle.Data.IsValid() && DamageEffectSpecHandle.Data.Get()->GetContext().GetEffectCauser() == OtherActor) return;

    if(!bHit)
    {
       //오버랩되면 소리재생
       UGameplayStatics::PlaySoundAtLocation(this,ImpactSound,GetActorLocation(),FRotator::ZeroRotator);

       //오버랩되면 효과실행
       UNiagaraFunctionLibrary::SpawnSystemAtLocation(this,ImpactEffect,GetActorLocation());
       //클라에서 사운드 파괴된경우 예외처리
       if(LoopingSoundComponent) LoopingSoundComponent->Stop();
       // LoopingSoundComponent->Stop(); // 적과오버랩되면 불 자체에서나는 루핑사운드 중지
    }