GameplayTag를 매개변수를 던져주고 변수에 값을 복사하여 담아 사용하려고 했다. 하지만 복사한 값을 사용하려고 할 때 문제가 발생했다. 

 

 

 

 


 

 

GameplayTag를 날리면서 발생한 문제


 

 

문제

 

GameplayTag를 매개변수를 던져주고 변수에 값을 복사하여 담아 사용하려고 했다.

하지만 복사한 값을 사용하려고 할 때 문제가 발생했다.

 


 

 

문제가 발생한 부분 코드

 

키 입력 후 GameplayTag를 매개변수로 넘기는 부분

void UXZPawnExtensionComponent::Input_EquipSlot2(const FInputActionValue& InputActionValue)
{
if (GetXZCharacter() && GetXZCharacter()->GetWeaponComponent())
{
FGameplayTag Tag = FXZTags::GetXZTags().Weapon_Projectile_Rifle;
GetXZCharacter()->GetWeaponComponent()->EquipWeapon(Tag);
}
}

 

 

문제가 발생하는 부분

#pragma once
#include "CoreMinimal.h"
#include "GameplayTagContainer.h"
#include "Components/ActorComponent.h"
#include "ProjectXZ/GameplayTag/XZGameplayTags.h"
#include "XZWeaponComponent.generated.h"
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class PROJECTXZ_API UXZWeaponComponent : public UActorComponent
{
GENERATED_BODY()
public:
UXZWeaponComponent();
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
void EquipWeapon(const FGameplayTag& InTag);
UFUNCTION(Server, Reliable)
void Server_EquipWeapon(const FGameplayTag& InTag);
UFUNCTION(NetMulticast, Reliable)
void Multicast_EquipWeapon(const FGameplayTag& InTag);
UPROPERTY(ReplicatedUsing = OnRep_EquippedChanged)
FGameplayTag EquippedWeaponTag = FXZTags::GetXZTags().Fist;
};

 

#include "XZWeaponComponent.h"
...
UXZWeaponComponent::UXZWeaponComponent()
{
PrimaryComponentTick.bCanEverTick = true;
}
void UXZWeaponComponent::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME(UXZWeaponComponent, EquippedWeaponTag);
}
void UXZWeaponComponent::EquipWeapon(const FGameplayTag& InTag)
{
EquippedWeaponTag = InTag;
Server_EquipWeapon(EquippedWeaponTag);
}
void UXZWeaponComponent::OnRep_EquippedChanged()
{
Server_EquipWeapon(EquippedWeaponTag);
}
void UXZWeaponComponent::Server_EquipWeapon_Implementation(const FGameplayTag& InTag)
{
Multicast_EquipWeapon(InTag);
}
void UXZWeaponComponent::Multicast_EquipWeapon_Implementation(const FGameplayTag& InTag)
{
// 슬롯에 등록된 무기의 GameplayTag를 InTag로 가져옴
if (UXZWeaponData** FoundData = Datas.Find(EquippedWeaponTag))
{
if (*FoundData)
{
if (Datas[EquippedWeaponTag]->GetEquipment()->Equip()) // 무기장착 O
{
}
else // 무기장착 X (= Unequip 수행한 경우)
{
Datas[EquippedWeaponTag]->GetEquipment()->Unequip();
EquippedWeaponTag = FXZTags::GetXZTags().Fist;
}
}
}
}

 

코드 고쳐야지.. 되도록 Multicast는...


 

 

처음 테스트한 부분 

 

문제가 발생한 부분(Breaking Point가 걸린 부분)에 업데이트한 변수값(= EquippedWeaponTag)이 아닌 매개변수 값으로 넘겨주었다.

이렇게 하니 정상적으로 동작하였다.

 

문제가 되는 코드

void UXZWeaponComponent::EquipWeapon(const FGameplayTag& InTag)
{
EquippedWeaponTag = InTag;
Server_EquipWeapon(EquippedWeaponTag);
}

 

제대로 동작하는 코드

void UXZWeaponComponent::EquipWeapon(const FGameplayTag& InTag)
{
EquippedWeaponTag = InTag;
Server_EquipWeapon(InTag);
}

 

 

하지만 이 방식은 내가 원하던 방식이 아니었다. 

일단 원인을 파악했다. 

EquippedWeaponTag 변수값이 멀티플레이어 환경에서 업데이트 되지 않는것이었다. 그래서 변수가 변경되었을때 호출되는 OnRep_EquippedChanged() 함수가 호출되지 않았던 것이다.


 

 

원인 분석 및 해결 방안 (왜 변수가 업데이트가 되지 않는가?)

 

1. 첫번째 실수 -  변수값을 변경하는 부분은 서버!여야 한다.

 

FGameplayTag EquippedWeaponTag를 변경한 부분이 클라이언트 부분이었다. 

 

UPROPERTY(Replicated) UPROPERTY(ReplicatedUsing= )으로 선언한 변수들은 서버에서 변경되어야 한다.

그래서 태그가 변경되는 위치를 옮겼다.

 

Before

void UXZWeaponComponent::EquipWeapon(const FGameplayTag& InTag)
{
EquippedWeaponTag = InTag;
Server_EquipWeapon(EquippedWeaponTag);
}

 

After

void UXZWeaponComponent::EquipWeapon(const FGameplayTag& InTag)
{
Server_EquipWeapon(InTag);
}
void UXZWeaponComponent::Server_EquipWeapon_Implementation(const FGameplayTag& InTag)
{
EquippedWeaponTag = InTag;
...
}

 

 

 

2. 두번째 실수 -  작업하는 클래스의 Replicate 설정을 키자!

 

작업하고 있는 클래스의 Replicates 가 켜지지 않았다.

ActorComponent 상속 클래스의 Replicates은 bReplicates = true가 아니라 컴포넌트 버젼의 변수를 켜줘야 한다.

아래를 보면.. 

BP:  Component Replicates 를 true 체크해줘야 한다. 

 

C++:  코드로 설정하려면 다음과 같다.

  • SetIsReplicatedByDefault(true) 로 설정해야 한다.

 

 

※ 참고)  SetIsReplicated(true) 도 사용할 수 있지만 생성자 위치에서 선언하는거면 SetIsReplicatedByDefault(true) 를 사용하는게 좋다.