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) 를 사용하는게 좋다.