관리 메뉴

Mini

[UE5] 클라에서 서버로 data 보내고 받기 구현, 클라에서 캐릭안보임버그 해결 본문

UE5/Ability Tasks

[UE5] 클라에서 서버로 data 보내고 받기 구현, 클라에서 캐릭안보임버그 해결

Mini_96 2024. 6. 12. 02:35

* data 보내기 구현

1. 데이터를 보낼함수 만듬

//FVector -> Datahandle 타입변경 => 다른 정보도 담을수있음
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FMouseTargetDataSignature, const FGameplayAbilityTargetDataHandle&, DataHandle);
/**
 * 
 */
UCLASS()
class AURA_API UTargetDataUnderMouse : public UAbilityTask
void SendMouseCursorData();

 

2. 기존활성화함수를 클라, 서버에 따라 분기함

void UTargetDataUnderMouse::Activate()
{
    const bool bIsLocallyControlled = Ability->GetCurrentActorInfo()->IsLocallyControlled();
    if(bIsLocallyControlled())
    {
       SendMouseCursorData();
    }
    else
    {
       //TODO : 서버에있는경우, listen target data
    }
}

 

3. 구현

void UTargetDataUnderMouse::SendMouseCursorData()
{
    //아래 범위가 예측(predict)되도록함.
    //서버에게 아래작업을 로컬에서 할수있도록 허용요청
    FScopedPredictionWindow ScopedPrediction(AbilitySystemComponent.Get());
    
    //1. 마우스 커서의 Location 얻기
    //PC얻기 <= 부모가 갖고있는 Ability 변수
    APlayerController* PC = Ability->GetCurrentActorInfo()->PlayerController.Get();
    FHitResult CursorHit;
    PC->GetHitResultUnderCursor(ECC_Visibility, false,CursorHit); //커서힛에 정보넣어줘
    
    //단일히트대상의 데이터를 만들어줌
    /** Target data with a single hit result, data is packed into the hit result */
    FGameplayAbilityTargetData_SingleTargetHit* Data = new FGameplayAbilityTargetData_SingleTargetHit();
    Data->HitResult = CursorHit;

    FGameplayAbilityTargetDataHandle DataHandle;
    DataHandle.Add(Data);
    
    // data를 서버로보내기, AT에 ASC변수있음
    AbilitySystemComponent->ServerSetReplicatedTargetData(
       GetAbilitySpecHandle(),
       GetActivationPredictionKey(),
       DataHandle,
       FGameplayTag(),
       AbilitySystemComponent->ScopedPredictionKey);

    //능력활성화중일때만 방송해주는 함수
    if(ShouldBroadcastAbilityTaskDelegates())
    {
       ValidData.Broadcast(DataHandle);
    }
}

 

* Receiving Target Data 구현

1. else 부분(서버인 경우) 

void UTargetDataUnderMouse::Activate()
{
    const bool bIsLocallyControlled = Ability->GetCurrentActorInfo()->IsLocallyControlled();
    if(bIsLocallyControlled())
    {
       SendMouseCursorData();
    }
    else
    {
       //TODO : 서버에있는경우, listen target data
       //ASC => 대리인 얻기, 함수바인딩
       const FGameplayAbilitySpecHandle SpecHandle = GetAbilitySpecHandle();
       const FPredictionKey ActivationPredictionKey=GetActivationPredictionKey();
       AbilitySystemComponent.Get()->AbilityTargetDataSetDelegate(SpecHandle,ActivationPredictionKey)
       .AddUObject(this, &UTargetDataUnderMouse::OnTargetDataReplicatedCallback);

       //but, 데이터가 이미 전송된경우, 델리게이트가 이미 set된경우 -> 콜백호출
       const bool bCalledDelegate = AbilitySystemComponent.Get()->CallReplicatedTargetDataDelegatesIfSet(SpecHandle,ActivationPredictionKey);
       if(!bCalledDelegate) //데이터가 안온경우, 서버에게 기다리라고 해야함!
       {
          SetWaitingOnRemotePlayerData();
       }
    }
}

2. 콜백함수 구현

data를 지우고, 방송함

void UTargetDataUnderMouse::OnTargetDataReplicatedCallback(const FGameplayAbilityTargetDataHandle& DataHandle,FGameplayTag ActivationTag)
{
    //타겟데이터가 서버에 수신완료, 저장할필요없음, data 지우는함수임
    AbilitySystemComponent->ConsumeClientReplicatedTargetData(GetAbilitySpecHandle(),GetActivationPredictionKey());

    //능력활성화중일때만 방송해주는 함수, 방송해야되는지 체크해줌
    /** This should be called prior to broadcasting delegates back into the ability graph. This makes sure the ability is still active.  */
    if(ShouldBroadcastAbilityTaskDelegates())
    {
       ValidData.Broadcast(DataHandle); //DataHandle 방송
    }
}

 

* 디버깅 in BP

- Data를 벡터 -> DataHandle로 리팩토링함

이전

void UTargetDataUnderMouse::SendMouseCursorData()
{
    //아래 범위가 예측(predict)되도록함.
    //서버에게 아래작업을 로컬에서 할수있도록 허용요청
    FScopedPredictionWindow ScopedPrediction(AbilitySystemComponent.Get());
    
    //1. 마우스 커서의 Location 얻기
    //PC얻기 <= 부모가 갖고있는 Ability 변수
    APlayerController* PC = Ability->GetCurrentActorInfo()->PlayerController.Get();
    FHitResult CursorHit;
    PC->GetHitResultUnderCursor(ECC_Visibility, false,CursorHit); //커서힛에 정보넣어줘
    
    //단일히트대상의 데이터를 만들어줌
    /** Target data with a single hit result, data is packed into the hit result */
    FGameplayAbilityTargetData_SingleTargetHit* Data = new FGameplayAbilityTargetData_SingleTargetHit();
    Data->HitResult = CursorHit;

    FGameplayAbilityTargetDataHandle DataHandle;
    DataHandle.Add(Data);

위 코드로 인해 수많은 정보에 접근할수있게 되었음

 

- 서버-클라 연결끊김 버그

클라에서 실행시 서버캐릭이 사라짐 , 서버에서도 클라캐릭이사라짐, 이는 연결이 끊어졌음을 의미함

- 원인 : 글로브데이터를 초기화해줘야  Target Data 사용가능함

- 해결 : AssetMgr에서 초기화해줌

#include "AuraAssetManager.h"
#include "AbilitySystemGlobals.h"


void UAuraAssetManager::StartInitialLoading() //게임 에셋들 초기세팅하는 함수
{
   ...

    //TargetData 사용위해 필요
    UAbilitySystemGlobals::Get().InitGlobalData();
}

결과 : 클라에서 클릭시, 서버에 데이터가 전송됨(흰색구체)!
클라끼리는 data 가 전송안되는 모습 good

 

* Next Step

이를 이용해서 서버에서 불덩어리를 올바른 방향으로 발사가능

 

* 클라에서 캐릭안보임버그 해결

PlayerStart가 -0.5로 되있었음 -> 0.f 로바꾸니 해결됨