https://dev.epicgames.com/documentation/ko-kr/unreal-engine/gameplay-attributes-and-attribute-sets-for-the-gameplay-ability-system-in-unreal-engine?application_version=5.3

 

언리얼 엔진의 게임플레이 어빌리티 시스템을 위한 게임플레이 어트리뷰트 및 어트리뷰트 세트

게임플레이 어트리뷰트 및 어트리뷰트 세트 사용하기

dev.epicgames.com

https://github.com/tranek/GASDocumentation?tab=readme-ov-file#concepts-as

 

GitHub - tranek/GASDocumentation: My understanding of Unreal Engine 5's GameplayAbilitySystem plugin with a simple multiplayer s

My understanding of Unreal Engine 5's GameplayAbilitySystem plugin with a simple multiplayer sample project. - tranek/GASDocumentation

github.com

Definition

  • 하나 이상의 GA로 AS를 구성하고, ASC에 등록을 한다.
    • Owner Actor의 Constructor에서 AttributeSet을 생성하면 ASC에 자동으로 등록이 된다.

Design

  • ASC가 여러 개의 AS를 가질 수는 있지만, 각 AS는 모두 서로 클래스가 달라야 한다.
  • AS는 무시할만한 Memory Overhead를 야기한다.
    • 그렇기에 얼마나 AS를 많이 사용할지는 개발자의 결정에 달려있다.
  • 또한 AS는 Actor가 어떤 Attribute를 가질지 선택지를 제공하는 의미로 SubClass를 생성할 수 있다.
    • Atribute는 내부에서 AttributeSetClassName.AttributeName으로 일컬어진다.
    • 때문에 AS를 상속 받더라도, 상위 AS의 Attribute는 상위 AS의 이름을 그대로 유지한다.

Subcomponents with Individual Attributes

  • 장비 파괴처럼 복수의 Damagable Component를 소유했을 때, Component의 최대 갯수를 알 수 있다면
    AttributeSet에 각 Component에 대응하는 health Attribute를 만드는 것을 권장한다.
    • Damagable Component에는 가상의 Slot 값을 부여
    • 부여된 Slot값을 통해 GameplayAbilities를 읽거나 Attribute에 접근해 데미지 계산이 가능
    • Character/Pawn은 1개 이하의 health Attribute만 소유하는 것을 권장
    • Attribute는 AttributeSet이 가져야 하는거지, Character/Pawn이 가져야만 하는 것이 아니기 때문.
  • 하지만 다음 조건에서는 위와 같은 방식이 기대한 것만큼 잘 동작하지 않는다.
    • Subcomponent가 Runtime 상 상한이 없는 경우
    • Subcomponent가 Detach되어 다른 유저가 사용할 수 있는 경우
  • 이 때에는 Attribute를 사용하지 말고 고전적인 float 타입의 변수를 Component에 직접 부여하는 것을 권장한다.
  • 자세한 사항은 Item Attribute를 확인하길 바란다.

Add/Remove AttributeSet at Runtime

  • AS은 Runtime 상에 ASC에 추가될 수 있다.
    • 물론 ASC로부터 제거도 가능하지만 이는 매우 위험하다.
    • 만약 client에서 server보다 먼저 AS를 제거하고 Attribute 값 변화가 client로 replicate 된다면, 
      Attribute를 찾을 수 없어 Crash가 난다.
  • 그렇기에 Runtime 상에서 AS를 추가/제거를 할 때에는 대상 ASC에 대해 ForceReplication 함수를 호출해줘야 한다.

Item Attribute

  • 장비류 아이템에 대한 Attribute를 구현하는 방식.
    • 이런 방식은 전부 Item에 직접 값을 저장한다.
  • 이 시스템은 1명 이상의 플레이어가 Lifetime동안 장비를 장착/탈착 할 수 있는 경우에 반드시 제공되어야 한다.

Plain Floats on the Item

  • Attribute 대신 float 변수로 정보를 관리하는 방식
    • Fortnite와 GAS 예시코드가 이런 방식을 채택
  • 총기가 최대 Ammo 수, 현재 Ammo 수, 남은 Ammo 수 등을 저장하고 Client에 Replicate한다.
  • 만약 총기가 남은 Ammo를 공유하며느 그 값을 Character의 Attribute로 가져와 AttributeSet에 저장한다.
  • 다만 총기에서 Attribute를 사용하지 않기 때문에, UGameplayAbility에서 제공하는 일부 함수를 override해야 한다.
    • 총기에서 사용하는 Plain Float에 대한 검증과 계산을 위해
  • 총기를 GameplayAbilitySpec의 SourceObject로 지정하면 접근 권한을 Ability 내에서 처리할 수 있다.
  • 자동사격 과정에서 총기의 Ammo가 Replicate로 인해 덮어씌어지는 Clobbering을 방지하기 위해,
    PreReplication() 함수에서 IsFiring GameplayTag가 있는 동안 Ammo의 Replicate를 비활성화 한다.
    • 더보기
      void AGSWeapon::PreReplication(IRepChangedPropertyTracker& ChangedPropertyTracker)
      {
      	Super::PreReplication(ChangedPropertyTracker);
      
      	DOREPLIFETIME_ACTIVE_OVERRIDE(AGSWeapon, PrimaryClipAmmo, (IsValid(AbilitySystemComponent) && !AbilitySystemComponent->HasMatchingGameplayTag(WeaponIsFiringTag)));
      	DOREPLIFETIME_ACTIVE_OVERRIDE(AGSWeapon, SecondaryClipAmmo, (IsValid(AbilitySystemComponent) && !AbilitySystemComponent->HasMatchingGameplayTag(WeaponIsFiringTag)));
      }
    • 장점
      • AttributeSet을 사용하면서 발생하는 한계를 피할 수 있음
    • 단점
      • 현존하는 GameplayEffects의 흐름을 사용할 수 없음.
      • UGameplayAbility의 핵심 함수를 ammo 관리를 위해 override 해야 함.

AttributeSet on the Item

  • Item에서 AttributeSet을 사용하고 Player의 ASC를 이용하는 방법
  • 하지만 근본적인 한계가 존재한다.
    • Weapon이 가지고 있는 고유한 Attribute를 경우에 따라 Character로 옮겨와야 한다.
    • 만약 Weapon을 Inventory에 넣는다면,
      Weapon의 AttributeSet을 Character가 가진 ASC의 SpawnedAttributes에 옮겨와야 한다.
  • 만약 AttributeSet이 OwnerActor가 아닌 곳에 존재하면 Compile Error가 발생한다.
  • 이를 수정하기 위해 다음 작업이 진행되어야 한다.
    • AttributeSet을 Constructor가 아닌 BeginPlay()에서 Construct
    • IAbilitySystemInterface를 Implement
  • 장점
    • 제공되는 GameplayAbility와 GameplayEffect를 그대로 사용 가능
    • Item에 간단한 세팅으로 기능 구현 가능
  • 단점
    • 각 무기 타입에 맞는 AttributeSet을 생성해야 한다.
      • ASC는 기능적으로 Class당 하나의 AttributeSet을 가질 수 밖에 없다.
      • ASC가 Attribute 변경사항을 적용할 때 SpawnedAttributes에서 조건에 맞는 첫번째 AS만 탐색하기 때문.
      • 나머지 AttributeSet은 항상 무시 됨
    • 위와 같은 이유로 플레이어 당 동일한 무기를 2개 이상 소지할 수 없음
    • AttributeSet을 Runtime상에서 제거하는 것에서 오는 근본적인 리스크
      • 예를 들어 탄속이 있는 무기로 적을 처치 했는데 발사와 처치 사이에 무기가 제거가 되면
        관련 AttributeSet을 찾지 못해 Crash가 발생한다.

ASC on the Item

  • ASC를 통째로 아이템에 박아 넣는 극단적인 방법.
  • 장점
    • GameplayAbility와 GameplayEffect의 모든 기능을 오롯이 사용 가능
    • Attributeset Class를 재사용 할 수 있음
      • ASC에서 1개만 존재하니까
  • 단점
    • 개발 비용이 까마득하고 검증되지 않음

Defining Attributes

  • 더보기
     UCLASS()
     class MYPROJECT_API UMyAttributeSet : public UAttributeSet
     {
         GENERATED_BODY()
     
         public:
         /** 퍼블릭 액세스 가능한 샘플 어트리뷰트 'Health'*/
         UPROPERTY(EditAnywhere, BlueprintReadOnly)
         FGameplayAttributeData Health;
     };

     

    class MyAbilitySystemComponent : public UAbilitySystemComponent
    {
    	....
    	/** 샘플 어트리뷰트 세트. */
    	UPROPERTY()
    	const UMyAttributeSet* AttributeSet;
    	....
    }
     // 이런 코드는 일반적으로 BeginPlay()에 나타나지만,
     // 적절한 어빌리티 시스템 컴포넌트 구하기일 수 있습니다. 다른 액터에 있을 수도 있으므로 GetAbilitySystemComponent를 사용하여 결과가 유효한지 확인하세요.
     AbilitySystemComponent* ASC = GetAbilitySystemComponent();
     // AbilitySystemComponent가 유효한지 확인합니다. 실패를 허용할 수 없다면 if() 조건문을 check() 구문으로 대체합니다.
     if (IsValid(ASC))
     {
         // 어빌리티 시스템 컴포넌트에서 UMyAttributeSet를 구합니다. 필요한 경우 어빌리티 시스템 컴포넌트가 UMyAttributeSet를 생성하고 등록할 것입니다.
         AttributeSet = ASC->GetSet<UMyAttributeSet>();
     
         // 이제 새 UMyAttributeSet에 대한 포인터가 생겨 나중에 사용할 수 있습니다. 초기화 함수가 있는 경우 여기서 호출하면 좋습니다.
     }


    1.  Attribute는 FGameplayAttributeData 타입으로 Attribute를 선언한다.
    2. 위 코드에서는 Attribute Set 안의 값이 코드에서 직접 수정하지 않도록 const로 선언을 정의한다.
    3. AttributeSet은 Actor Construct에서 Instance화 하는 시점에 함수가 유효한 ASC를 반환하는 한,
      이 시점 혹은 BeginPlay 도중에 자동으로 등록된다.
    4. BP를 편집하여 Attribute Set Type을 ASC의 Default Start Data로 추가할 수 있다.
    5. ASC가 없는 GA를 수정하는 Gameplay Effect가 적용된다면, ASC는 일치하는 GA를 자동으로 생성한다.
      1. 하지만 이 Methond는 AS를 생성하거나, 기존 AS에 GA를 추가하지 않는다.

Helper Funcion Macro

  • GAS에서는 GA와 상호작용할 기본 헬퍼 함수를 추가할 수 있다.
    • GA 자체는 protected/private 접근자로 설정하고, 상호작용 함수를 public으로 설정하는 것이 좋다.
  • 사용이 필수 사항은 아니지만, 모범 사례로 간주한다.
  • 더보기
    #define GAMEPLAYATTRIBUTE_REPNOTIFY(ClassName, PropertyName, OldValue) \
    { \
    	static FProperty* ThisProperty = FindFieldChecked<FProperty>(ClassName::StaticClass(), GET_MEMBER_NAME_CHECKED(ClassName, PropertyName)); \
    	GetOwningAbilitySystemComponentChecked()->SetBaseAttributeValueFromReplication(FGameplayAttribute(ThisProperty), PropertyName, OldValue); \
    }
    
    #define GAMEPLAYATTRIBUTE_PROPERTY_GETTER(ClassName, PropertyName) \
    	static FGameplayAttribute Get##PropertyName##Attribute() \
    	{ \
    		static FProperty* Prop = FindFieldChecked<FProperty>(ClassName::StaticClass(), GET_MEMBER_NAME_CHECKED(ClassName, PropertyName)); \
    		return Prop; \
    	}
    
    #define GAMEPLAYATTRIBUTE_VALUE_GETTER(PropertyName) \
    	FORCEINLINE float Get##PropertyName() const \
    	{ \
    		return PropertyName.GetCurrentValue(); \
    	}
    
    #define GAMEPLAYATTRIBUTE_VALUE_SETTER(PropertyName) \
    	FORCEINLINE void Set##PropertyName(float NewVal) \
    	{ \
    		UAbilitySystemComponent* AbilityComp = GetOwningAbilitySystemComponent(); \
    		if (ensure(AbilityComp)) \
    		{ \
    			AbilityComp->SetNumericAttributeBase(Get##PropertyName##Attribute(), NewVal); \
    		}; \
    	}
    
    #define GAMEPLAYATTRIBUTE_VALUE_INITTER(PropertyName) \
    	FORCEINLINE void Init##PropertyName(float NewVal) \
    	{ \
    		PropertyName.SetBaseValue(NewVal); \
    		PropertyName.SetCurrentValue(NewVal); \
    	}

Initialize

  • AttributeMetaData라는 GAS TableRow로 초기화 할 수 있다.
    • 이는 외부 파일에서 Import할 수도 있고, Editor에서 수동으로 채워줄 수도 있다.
  •  
    DataTable Asset 생성 할 때 AttributeMetaData를 선택한다.
  • 위와 같이 선언된 AttributeMetaData Table Asset에 추가 Row를 덧붙여 AS를 다수의 GA로 지원할 수 있다.
    • 예를 들어 MyAttributeSet.Health 외에 MyAttributeSet.Attack Row를 추가하면 한 AS에서 제공하는 다수의 GA를 하나의 Table Asset으로 Initialize 할 수 있다.
  • Column에 MinValue, MaxValue가 지원되지만 GA와 AS에 범위 제한 행동이 없으므로 이 항목들은 무효하다.

Gameplay Attribute Access 제어

  • GA에 대한 직접 Access를 지어하는 것은 AS 통해 수행되며, FGameplayAttributeData를 확장하지 않는다.
    • FGameplayAttributeData는 Data에 대한 Access만 저장하고 제공한다.
  • GAS에서 제공하는 Macro를 사용하지 않고, 동일한 Macro에 구현부를 직접 작업해 값의 범위를 제한할 수도 있다.
  • 더보기
    GAMEPLAYATTRIBUTE_PROPERTY_GETTER(UMyAttributeSet, Health);
    float GetHealth() const;
    void SetHealth(float NewVal);
    GAMEPLAYATTRIBUTE_VALUE_INITTER(Health);

     

    float UMyAttributeSet::GetHealth() const
    {
        // Health의 현재 값을 반환하지만, 0 미만의 값은 반환하지 않습니다.
        // 이 값은 Health에 영향을 미치는 모든 모디파이어가 고려된 후의 값입니다.
        return FMath::Max(Health.GetCurrentValue(), 0.0f);
    }
    
    void UMyAttributeSet::SetHealth(float NewVal)
    {
        // 0 미만의 값을 받지 않습니다.
        NewVal = FMath::Max(NewVal, 0.0f);
    
        // 어빌리티 시스템 컴포넌트 인스턴스가 있는지 확인합니다. 항상 인스턴스가 있어야 합니다.
        UAbilitySystemComponent* ASC = GetOwningAbilitySystemComponent();
        if (ensure(ASC))
        {
            // 적절한 함수를 통해 현재 값이 아닌 베이스 값을 설정합니다.
            // 그러면 적용한 모디파이어가 계속해서 적절히 작동합니다.
            ASC->SetNumericAttributeBase(GetHealthAttribute(), NewVal);
        }
    }
    
    AbilitySystemComponent->GetGameplayAttributeValueChangeDelegate(AttributeSet->GetHealthAttribute()).AddUObject(this, &AGASAbilityDemoCharacter::OnHealthChangedInternal);

Gameplay Effect와의 Interaction

  • GA의 값을 제어하는 가장 일반적인 방법은 관련 Gameplay Effect를 처리하는 것이다.
  •  
    • PostGameplayEffectExecute는 Attribute의 Base 값을 변경되는 GameplayEffect가 호출되기 전에 호출된다.
      • GameplayEffect가 호출(Execute) 되기 전에만 호출되고, 직접 접근해 수정할 때에는 호출되지 않는다.
      • 또한 BaseValue가 아닌 current 값에 영향을 주는 GameplayEffect에서도 호출되지 않는다.
    • 위 예시에서 PostGameplayEffectExecute 함수는 public 접근자가 지정되어야 한다.
    • 함수 내에서 새로운 Body를 작성하되, Super::PostGameplayEffectExecute가 확실히 호출되어 있어야 한다.
  • 더보기
    class UMyAttributeSet : public AttributeSet
    {
    	.....
    public:
    	void PostGameplayEffectExecute(const struct FGameplayEffectModCallbackData& Data) override;
    	.....
    }

     

    void UMyAttributeSet::PostGameplayEffectExecute(const struct FGameplayEffectModCallbackData& Data)
    {
    	// 잊지 말고 부모 구현을 호출하세요.
    	Super::PostGameplayEffectExecute(Data);
    
    	// 프로퍼티 게터를 사용하여 이 호출이 Health에 영향을 미치는지 확인합니다.
    	if (Data.EvaluatedData.Attribute == GetHealthAttribute())
    	{
    		// 이 게임플레이 이펙트는 Health를 변경합니다. 적용하되 우선 값을 제한합니다.
    		// 이 경우 Health 베이스 값은 음수가 아니어야 합니다.
    		SetHealth(FMath::Max(GetHealth(), 0.0f));
    	}
    }

Replication

  • Multiplayer의 경우, 여타 Property Replicate와 유사하게 AS을 통해 GA Replicate를 할 수 있다.
  • 더보기
    class UMyAttributeSet : public UAttributeSet
    {
    	.....
    
        /** 네트워크를 통해 새 Health 값이 도착할 때 호출됨 */
        UFUNCTION()
        virtual void OnRep_Health(const FGameplayAttributeData& OldHealth);
        
        /** 리플리케이트할 프로퍼티 표시 */
        virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
    
    protected:
        /** 샘플 어트리뷰트 'Health'*/
        UPROPERTY(EditAnywhere, BlueprintReadOnly, ReplicatedUsing = OnRep_Health)
        FGameplayAttributeData Health;
        
        ....
    };

     

    void UMyAttributeSet::OnRep_Health(const FGameplayAttributeData& OldHealth)
    {
    	// 디폴트 게임플레이 어트리뷰트 시스템의 repnotify 행동을 사용합니다.
    	GAMEPLAYATTRIBUTE_REPNOTIFY(UMyAttributeSet, Health, OldHealth);
    }
    
    void UMyAttributeSet::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
    {
    	// 부모 함수를 호출합니다.
             Super::GetLifetimeReplicatedProps(OutLifetimeProps);
    
    	// Health에 대한 리플리케이션을 추가합니다.
    	DOREPLIFETIME_CONDITION_NOTIFY(UMyAttributeSet, Health, COND_None, REPNOTIFY_Always);
    }
    • Replicate 할 Attribute에 PROPERTY에 ReplicatedUsing 지정자를 추가하고, Callback 함수를 선언한다.
    • Source File에서 Callback 함수를 정의한다.
    • Callback 함수 내에는 GAMEPLAYATTRIBUTE_REPNOTIFY 매크로로
      Replicate 되는 Attribute에 대한 RepNotify 행동을 실행한다.
    • 만약 이 AS가 처음 Replicate되는 Attribute라면, GetLifetimeReplicatedProps에 추가한다.

주요 함수

PreAttributeChange

	/**
	 *	Called just before any modification happens to an attribute. This is lower level than PreAttributeModify/PostAttribute modify.
	 *	There is no additional context provided here since anything can trigger this. Executed effects, duration based effects, effects being removed, immunity being applied, stacking rules changing, etc.
	 *	This function is meant to enforce things like "Health = Clamp(Health, 0, MaxHealth)" and NOT things like "trigger this extra thing if damage is applied, etc".
	 *	
	 *	NewValue is a mutable reference so you are able to clamp the newly applied value as well.
	 */
	virtual void PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue) { }
  • Attribute의 CurrentValue가 바뀌기 전에 호출되는 함수
    • NewValue를 이용해 CurrentValue를 Clamp한 상태로 적용할 때 사용 함.
    • 더보기
      if (Attribute == GetMoveSpeedAttribute())
      {
      	// Cannot slow less than 150 units/s and cannot boost more than 1000 units/s
      	NewValue = FMath::Clamp<float>(NewValue, 150, 1000);
      }
  • 단, Attribute에 직접 접근하여 변경하는 것이 아닌 Macro에서 제공하는 Setter 함수나 GameplayEffects로만 호출된다.
  • 그리고 Epic에서는 이 함수를 Attribute 변경에 대한 Delegate로 사용을 권장하지 않는다.
    • 그저 Attribute 값의 보정(Clamp) 용도로 사용을 권장한다.

PostGameplayEffectExecute

	/**
	 *	Called just after a GameplayEffect is executed to modify the base value of an attribute. No more changes can be made.
	 *	Note this is only called during an 'execute'. E.g., a modification to the 'base value' of an attribute. It is not called during an application of a GameplayEffect, such as a 5 ssecond +10 movement speed buff.
	 */
	virtual void PostGameplayEffectExecute(const struct FGameplayEffectModCallbackData &Data) { }
  • Attribute의 BaseValue가 Instant GameplayEffect로 인해 변경될 때 호출되는 함수
    • GameplayEffect로 인해 Attribute가 변동될 때 좀 더 복잡한 작업을 수행할 수 있다.
  • 함수가 호출된 시점에는 이미 Attribute 값이 변경이 된 후다.
    • 하지만 아직 Client에는 Replicate 되지 않았다.
  • 때문에 여기서 Clamping을 하는 것은 Client에서는 발생하지 않고, 그 결과만 받는다.

OnAttributeAggregatorCreate

	/** Callback for when an FAggregator is created for an attribute in this set. Allows custom setup of FAggregator::EvaluationMetaData */
	virtual void OnAttributeAggregatorCreated(const FGameplayAttribute& Attribute, FAggregator* NewAggregator) const { }
  • Attribute가 set에서 생성되어 Aggregator가 생성될 때.
  • FAggregatorEvaluateMetaData에 대한 Custom Setup을 할 수 있다.
    • Attribute에서 Modifier로 적용하는데 가장 작은 음수 값을 가져올 수 있다.
    • Paragon에서 여러 개의 감속 디버프가 걸릴 때 가장 낮은 비율로 적용할 때 이 기능을 사용
  • 더보기
    void UGSAttributeSetBase::OnAttributeAggregatorCreated(const FGameplayAttribute& Attribute, FAggregator* NewAggregator) const
    {
    	Super::OnAttributeAggregatorCreated(Attribute, NewAggregator);
    
    	if (!NewAggregator)
    	{
    		return;
    	}
    
    	if (Attribute == GetMoveSpeedAttribute())
    	{
    		NewAggregator->EvaluationMetaData = &FAggregatorEvaluateMetaDataLibrary::MostNegativeMod_AllPositiveMods;
    	}
    }

 

'UE5 > GAS' 카테고리의 다른 글

[GAS] Ability Task  (0) 2024.05.16
[GAS] Gameplay Effect  (0) 2024.05.15
[GAS] Gameplay Attribute  (0) 2024.05.13
[GAS] Ability System Component  (0) 2024.05.13
[GAS] Gameplay Ability System 소개  (0) 2024.05.10

https://dev.epicgames.com/documentation/ko-kr/unreal-engine/gameplay-attributes-and-attribute-sets-for-the-gameplay-ability-system-in-unreal-engine?application_version=5.3

 

언리얼 엔진의 게임플레이 어빌리티 시스템을 위한 게임플레이 어트리뷰트 및 어트리뷰트 세트

게임플레이 어트리뷰트 및 어트리뷰트 세트 사용하기

dev.epicgames.com

https://github.com/tranek/GASDocumentation?tab=readme-ov-file#concepts-a

 

GitHub - tranek/GASDocumentation: My understanding of Unreal Engine 5's GameplayAbilitySystem plugin with a simple multiplayer s

My understanding of Unreal Engine 5's GameplayAbilitySystem plugin with a simple multiplayer sample project. - tranek/GASDocumentation

github.com

 

  • FGameplayAttribute를 사용해 Gameplay 관련 소수값을 저장/계산 수정하는 기능
    • 남은 생명력
    • Vehicle의 최고 속력
    • 아이템의 사용 가능 횟수
  • GAS의 Actor는 Gameplay Attribute(이하 GA)는 Attribute Set(이하 AS)에 저장한다.
    • 이는 Attribute를 Actor의 ASC에 등록하고, GA와 시스템의 나머지 부분간의 상호작용 관리에 유리하다.
    • 상호작용에는 범위 제한, 일시적 값 변경을 위한 계산, 영구적 값 변경을 하는 이벤트에 대한 반응이 있다.
  • GA는 Gameplay Effect로만 수정되어야 한다.
    • 그래야 ASC가 변화를 예측할 수 있다.

Gameplay Attribute

  • 생성하려면 우선 Attribute Set을 만들어야 한다.
    • 경우에 따라서는 AS가 없이도 GA가 존재할 수 있다.
    • 보통은 적절한 GA Type을 포함하는 AS가 없는 ASC에 GA가 저장된 경우
    • 하지만 이 케이스는 GA가 ASC와 상호작용하는 그 어떠한 행동도 정의되지 않고 값만 저장한다.
    • 때문에 권장되지 않는 방식이다.
  • 만약 GA를 Editor에 노출하고 싶지 않다면, UPROPERTY 지정자에 Meta=(HideInDetailsView)를 추가하면 된다.
  • GA 값은 CurrentValue와 BaseValue로 구분된다.

CurrentValue

  • BaseValue에 더불어 Gameplay Effects로 발생한 일시적인 변화를 합친 값
  • Duration, Infinite Gameplay Effects에 의해 값이 변경된다.
    • Duration Gameplay Effects: 미리 지정된 시간 동안만 효과가 적용되는 Gameplay Effects
    • Infinite Gameplay Effects: 특정 조건을 만족하기 전까지 계속 효과가 유지되는 Gameplay Effects
  • PreAttributeChange() 함수에서 CurrentValue 값의 Clamping 작업을 적용할 수 있다.

BaseValue

  • Attribute의 영구적인 값
  • Instant 혹은 Periodic Gameplay Effects에 의해 값이 변경된다.
    • Instant Gameplay Effects: 즉시 발동되지만 그 효과가 영구적인 Gameplay Effects
    • Periodic Gameplay Effects: 주기적으로 반복해서 효과가 발동하는 Gameplay Effects
  • 간혹 BaseValue Attribute의 최대값하고 혼동하지만 이는 잘못된 사용법이다.
    • 현재는 Attribute의 최대값은 별도의 Attribute로 분리되어야 한다.
    • FAttributeMetaData에 Min/Max Value Column이 있지만, Epic에서 WIP라고 코멘트 해두었다.
  • PostGameplayEffectExecute()에서 BaseValue 값의 Clamp를 적용할 수 있다.

Meta Attributes

  • Attributes들과 상호작용을 목적으로 일시적인 값을 담고 있는 임시 Attribute를 지칭
    • 예를 들어 damage의 경우, GameplayEffect로 health Attribute에 직접 영향을 주는 대신
      damage라는 Meta Attribute를 임시선언으로 사용할 수 있다.
    • 이 때 Meta Attribute는 health Attribute에 도달하기 전에 여러 변화를 가할 수 있다.
      • GameplayEffectExecutionCalculation 함수를 통해 Buff/Debuff 적용
      • Shield Attribute에 의해 발생하는 damage의 감소
  • Meta Attribute는 Gameplay Effect간의 영속성이 없고 모두에 의해 override될 수 있다.
    • 또한 일반적으로 Replicate 되지 않는다.
  • Meta Attribute는 적용 대상 Attribute의 수치 변화와 그에 따른 상호작용을 논리적으로 분리할 수 있다.
    • Gameplay Effect가 "얼마나 수치를 변경할 것인가?"를 결정한다면,
      Attribute Set은 "수치가 바뀐 뒤 어떻게 반응할 것인가?"를 결정한다.
    • 하지만 상위 Attribute Set에서 제공하는 Attribute를 대상으로 한다 해도,
      하위 Attribute Set의 구성에 따라 실제 변화량과 그 반응은 다를 수 있다.
    • Meta Attribute는 이렇게 다양한 경우에 대해 유연하게 대응할 수 있다.
  • 물론 Meta Attribute는 좋은 패턴이지만 필수적인 것은 아니다.
    • 만약 Attribute에 대해 하나의 ExecutionCalculation만 제공되고 모든 Actor가 그 Attribute Set을 사용한다면,
      관련된 값들을 직접 수정하는 방식으로 작업하는 것이 더 좋을 수 있다.

Responding to Attribute Changes

  • Attribute의 변화를 UI나 다른 Gameplay에 전달하려면,
    UAbilitySystemComponent::GetGameplayAttributeValueChangeDelegate(FGameplayAttribute Attribute)를 쓴다.
  • 더보기
    typedef TMulticastDelegate_OneParam< void, const FOnAttributeChangeData & > FOnGameplayAttributeValueChange
    
    FOnGameplayAttributeValueChange & GetGameplayAttributeValueChangeDelegate
    (
        FGameplayAttribute Attribute
    )

     

    AbilitySystemComponent->GetGameplayAttributeValueChangeDelegate(AttributeSetBase->GetHealthAttribute()).AddUObject(this, &AGDPlayerState::HealthChanged);
    
    virtual void HealthChanged(const FOnAttributeChangeData& Data);

     

    • 이 때 Attribute 변수는 Server에서만 값이 채워진다.
  • BP에서는 이 함수가 AsyncTask로 감싸져서 제공된다.
    • 보통 UI_HUD에서 사용되며 해당 Widget의 Destruct Event에서 EndTask()가 호출되기 전까지 죽지 않는다.

Derived Attributes

  • 하나의 Attribute가 복수의 Attribute로부터 값이 정해질 때, Infinite Gameplay Effect를 여러 개의 Modifier Magnitude Calculation(이하 MMC)와 함께 사용한다.
  • Derived Attributes는 해당 Attribute에 의존성을 갖는 Attribute들을 자동으로 갱신해준다.
  • Derived Attribute의 연산자 공식은 Modifier Aggregator와 동일한 방식으로 동작한다.
    • 만약 저해진 순서대로 계산이 되어야 한다면, MMC 내부에서 시행하면 된다.
  • PIE에서 Multi Client로 실행한 경우, Editor Preferences -> Run Under One Process 옵션을 비활성화 해야한다.
    • 안 그러면 Derived Attributes가 각각의 Attribute가 client에서 첫번째로 update되지 않으면 갱신하지 않을 것이다.

예시

  • 다음과 같이 값이 정해지는 TestAttrA가 있다고 가정하자.
    • TestAttrA = (TestAttrA + TestAttrB) * (2 * TestAttrC) .
  • 이 때 TestAttrA에 대한 Derived Attributes 설정은 다음과 같다.
  •  

'UE5 > GAS' 카테고리의 다른 글

[GAS] Ability Task  (0) 2024.05.16
[GAS] Gameplay Effect  (0) 2024.05.15
[GAS] Attribute Set  (1) 2024.05.14
[GAS] Ability System Component  (0) 2024.05.13
[GAS] Gameplay Ability System 소개  (0) 2024.05.10

https://dev.epicgames.com/documentation/ko-kr/unreal-engine/gameplay-ability-system-component-and-gameplay-attributes-in-unreal-engine?application_version=5.3

 

언리얼 엔진의 게임플레이 어빌리티 시스템 컴포넌트 및 게임플레이 어트리뷰트를 살펴봅니다.

게임플레이 어트리뷰트 및 어트리뷰트 세트와 함께 어빌리티 시스템 컴포넌트를 사용하는 방법을 살펴봅니다.

dev.epicgames.com

  • UGameAbilitySystemComponent는 Actor와 GAS 사이의 가교 역할을 한다.
  • GAS와 상호작용해야 하는 Actor는 다음 2가지 조건 중 하나를 반드시 만족해야 한다.
    • Ability System Component(이하 ASC)를 가지고 있거나
    • 다른 Actor의 ASC에 Access 할 수 있거나.
  • ASC는 FGameplayAbilitySpecContainer ActivatableAbilities 중 승인된 Gameplay Abilities를 가지고 있다.
  • 언제나 ActivatableAbilities.Items를 통해 iterate를 하려 한다면,
    List의 변화를 막기 위해 ABILITY_SCOPE_LOCK()을 반복문 앞에 추가해 Lock을 걸어야 한다.
  • 매 ABILITY_SCOPE_LOCK() 호출 범위마다 AbilityScopeLockCount가 증가하고,
    그 범위를 벗어나면 AbilityScopeLockCount가 감소한다.
  • ABILITY_SCOPE_LOCK() 호출 범위 내에서 Ability를 제거하지 말 것.
    • List가 Lock이 걸려 있으면 AbilityScopeLockCount를 확인하여 제거를 방지한다.

기본 요구사항

  • Actor가 Game Ability System를 사용하려면 다음 2가지를 충족해야 한다.
    • IAbilitySystemInterface 구현
    • GetAbilitySystemComponent 함수 override
  • Actor가 자체 ASC를 가지고 있는 것이 일반적이다.
  • 하지만 다른 Actor가 소유한 ASC를 사용하려는 경우가 있다.
    • Player의 Pawn/Character가 소환/소멸 되거나 처리할 때 리셋되면 안되는 것들이 포함되어 있기 때문.

Replication Mode

  • ASC는 GameplayEffects, GameplayTags, GameplayCues에 대해 3가지 Replication Mode를 제공한다.
  • Attributes는 속한 AttributeSet에 의해 Replicate된다.

Full

  • Single Player에서 사용
  • 모든 GameplayEffects가 모든 Client에 Replicate된다.

Mixed

  • Multiplayer에서 유저가 Control 하는 Actor
  • GameplayEffects가 소유한 Client에게만 Replicate된다.
  • GameplayTags와 GameplayCues만 모두에게 Replicate된다.

Advanced

  • 이 Mode에서 OwnerActor의 Owner가 Controller가 되는 것을 권장한다.
    • PlayerState의 Parent는 기본적으로 Controller이지만, Character는 그렇지 않다.
    • OwnerActor가 PlayerState가 아닌 상태에서 Mixed Mode를 사용하는 경우, 
      SetOwner() 함수를 호출해 OwnerActor를 Controller로 명시해야 한다.
    • 4.24 버전 이후(현재)에는 PossessedBy() 함수로 Owner를 Controller로 지정한다.

Minimal

  • Multiplayer에서 AI가 Control 하는 Actor
  • GameplayEffects가 어디에도 Replicate 되지 않는다.
  • GameplayTags와 GameplayCues만 모두에게 Replicate 된다.

예시

 

GitHub - tranek/GASDocumentation: My understanding of Unreal Engine 5's GameplayAbilitySystem plugin with a simple multiplayer s

My understanding of Unreal Engine 5's GameplayAbilitySystem plugin with a simple multiplayer sample project. - tranek/GASDocumentation

github.com

ASC가 Actor에 있는 경우

  • 더보기
    AGDPlayerState::AGDPlayerState()
    {
    	// Create ability system component, and set it to be explicitly replicated
    	AbilitySystemComponent = CreateDefaultSubobject<UGDAbilitySystemComponent>(TEXT("AbilitySystemComponent"));
    	AbilitySystemComponent->SetIsReplicated(true);
    	//...
    }

     

    class APACharacterBase : public AActor, public IAbilitySystemInterface
    {
    	//~ IAbilitySystemInterface 시작
    	/** 어빌리티 시스템 컴포넌트를 반환합니다. */
    	virtual UAbilitySystemComponent* GetAbilitySystemComponent() const override;
    	//~ IAbilitySystemInterface 끝
       
    	/** 어빌리티 시스템 컴포넌트입니다. 게임플레이 어트리뷰트 및 게임플레이 어빌리티를 사용하려면 필요합니다. */
    	UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, Category = "Abilities")
    	UAbilitySystemComponent* AbilitySystemComponent;
    }

     

    void APACharacterBase::PossessedBy(AController * NewController)
    {
    	Super::PossessedBy(NewController);
    
    	if (AbilitySystemComponent)
    	{
    		AbilitySystemComponent->InitAbilityActorInfo(this, this);
    	}
    
    	// ASC MixedMode replication requires that the ASC Owner's Owner be the Controller.
    	SetOwner(NewController);
    }
    
    UAbilitySystemComponent* APACharacterBase::GetAbilitySystemComponent() const
    {
    	return AbilitySystemComponent;
    }

     

    void APAPlayerControllerBase::AcknowledgePossession(APawn* P)
    {
    	Super::AcknowledgePossession(P);
    
    	APACharacterBase* CharacterBase = Cast<APACharacterBase>(P);
    	if (CharacterBase)
    	{
    		CharacterBase->GetAbilitySystemComponent()->InitAbilityActorInfo(CharacterBase, CharacterBase);
    	}
    
    	//...
    }
    • ASC는 Server, Client 양쪽에서 모두 Initialize되어야 한다.
      • 또한 Controller가 Set(Possess)되고 나서 Initialize 되기를 원한다.
      • SinglePlay는 Server 파트에 대해서만 걱정을 하면 된다.
    • ASC가 설정된 Player는 각 파트에서 명시적으로 함수를 호출하여 Initialize를 해야 한다.
      • Server 파트: Pawn::PossessedBy()
      • Client 파트: APlayerController::AcknoledgePossession

고급 시나리오

  • 다른 Actor가 소유한 ASC를 사용하는 Actor를 구성할 수 있다.
    • ex) UPlayerState가 소유한 ASC를 사용하는 Pawn
  • 이를 위해 GetAbilitySystemComponent 함수가 Owner에서 ASC를 얻거나, 캐싱해야 한다.
  • 이 방식은 다음 속성이 있는 프로젝트에서 주로 발생한다.
    • Player가 제어하는 Actor가 리스폰을 하고, 그 과정에서 Game Ability System 정보가 필요한 경우
    • 장비나 Modular Machine, 신체 부위를 표현하기 위해 Actor가 자신에게 다른 Actor를 Attach하는 경우
    • 간단한 AI나 MOBA 게임
  • Attach 된 Actor의 Gameplay Ability System Interaction은 Parent의 ASC에 라우팅 할 수 있다.
    • 가장 간단하게 구현하는 방법은 Attach된 Actor의 GetAbilitySystemComponent가 Parent로 전달되는 것.
    • Actor 다른 ACtor에 Attach되거나 처리되는 동안 Cache 된 Pointer를 유지하면 Performance를 향상할 수 있다.
  • 단, ASC가 PlayerState에 있는 경우, PlayerState의 NetUpdateFrequency를 늘려야 한다.
  • Gameplay Ability System은 다수의 Actor가 하나의 Ability System Component를 공유하는 것은 지원한다.
    • 하지만 하나의 Actor가 다수의 Ability System Component를 가지는 것은 지원하지 않는다.
    • Actor의 Ability system Component에 변경사항을 적용하고 이를 얻을 때 모호함을 유발할 수 있기 때문.
 

Replicate Actor Properties In Unreal Engine | Unreal Engine 5.4 Documentation | Epic Developer Community

Learn how to replicate actor properties in Unreal Engine; including conditional replication, custom conditions, and object references.

dev.epicgames.com

ASC가 PlayerState에 있는 경우

  • 더보기
    // Server only
    void AGDHeroCharacter::PossessedBy(AController * NewController)
    {
    	Super::PossessedBy(NewController);
    
    	AGDPlayerState* PS = GetPlayerState<AGDPlayerState>();
    	if (PS)
    	{
    		// Set the ASC on the Server. Clients do this in OnRep_PlayerState()
    		AbilitySystemComponent = Cast<UGDAbilitySystemComponent>(PS->GetAbilitySystemComponent());
    
    		// AI won't have PlayerControllers so we can init again here just to be sure. No harm in initing twice for heroes that have PlayerControllers.
    		PS->GetAbilitySystemComponent()->InitAbilityActorInfo(PS, this);
    	}
    	
    	//...
    }

     

    // Client only
    void AGDHeroCharacter::OnRep_PlayerState()
    {
    	Super::OnRep_PlayerState();
    
    	AGDPlayerState* PS = GetPlayerState<AGDPlayerState>();
    	if (PS)
    	{
    		// Set the ASC for clients. Server does this in PossessedBy.
    		AbilitySystemComponent = Cast<UGDAbilitySystemComponent>(PS->GetAbilitySystemComponent());
    
    		// Init ASC Actor Info for clients. Server will init its ASC when it possesses a new Actor.
    		AbilitySystemComponent->InitAbilityActorInfo(PS, this);
    	}
    
    	// ...
    }
    •  ASC가 PlayerState에 있는 경우에는 명시적으로 Initialize 하는데 호출되는 함수가 달라진다.
      • Server: Pawn::PossessedBy()
      • Client: Pawn::Onrep_PlayerState()
    • 이 모든 과정은 Client에 PlayerState가 있다는 것을 상정하고 작업된다.
    • 만약 아래 로그가 발생하면, ASC가 Client에서 Initialize가 되지 않은 것이다.
      • LogAbilitySystem: Warning: Can't activate LocalOnly or LocalPredicted ability %s when not local!

'UE5 > GAS' 카테고리의 다른 글

[GAS] Ability Task  (0) 2024.05.16
[GAS] Gameplay Effect  (0) 2024.05.15
[GAS] Attribute Set  (1) 2024.05.14
[GAS] Gameplay Attribute  (0) 2024.05.13
[GAS] Gameplay Ability System 소개  (0) 2024.05.10

https://dev.epicgames.com/documentation/ko-kr/unreal-engine/gameplay-ability-system-for-unreal-engine?application_version=5.3

 

언리얼 엔진의 게임플레이 어빌리티 시스템 | 언리얼 엔진 5.4 문서 | Epic Developer Community

게임플레이 어빌리티 시스템 개요

dev.epicgames.com

https://dev.epicgames.com/documentation/ko-kr/unreal-engine/understanding-the-unreal-engine-gameplay-ability-system?application_version=5.3

 

언리얼 엔진 게임플레이 어빌리티 시스템을 살펴봅니다. | 언리얼 엔진 5.4 문서 | Epic Developer Commu

게임플레이 어빌리티 시스템 및 각 컴포넌트 클래스가 어빌리티에 기여하는 방법을 살펴봅니다.

dev.epicgames.com

Gameplay Ability란?

  • RPG나 MOBA의 Ability, Attribute 구축을 지원하는 고도로 유연한 Framework
  • 다양한 인게임 Ability를 설계, 구현하고 효과적으로 연결할 수 있도록 기능을 지원
    • Action의 결과로 다양한 Attribute를 조절하거나 Effect를 생성
    • Timer나 자원 비용을 구현하여 Action의 빈도 조절
    • Ability의 Level과 그에 따른 Effect 변경
    • Particle 및 Sound Effect를 활성화
    • 점프와 같은 단순한 Action 기능
  • Gameplay Ability System과 상호작용하는 Actor에는 Ability System Component가 있어야 한다.
    • Ability를 활성화
    • Attribute 저장
    • Effect Update
    • Actor간 상호작용 처리
  • Game Ability System을 생성하고 Ability System Component가 있는 Actor를 생성하면
    Ability를 생성하고, Actor가 Ability에 어떻게 반응하는지 결정할 수 있다.

Gameplay Ability

  • UGameplayAbility를 상속받은 Class나 BP들을 지칭
    • 특정 Ability에서 어떤 역할을 하는지 정의
    • 해당 Ability의 Replication과 Instancing Activity와 같은 요소가 어떻게 처리될지 정의

Ability Task

  • Gameplay Ability에서 호출하는 일련의 비동기 구성 요소
    • UAbilityTask Class를 상속 받음.
  • C++로 작성된다.
  • 작업이 끝날 때 cpp의 Delegate나 BP의 출력 실행 핀을 호출한다.

Gameplay Attribute

  • FGameplayAttribute 구조체에 저장되는 float 값
    • Game이나 Actor에 특정한 방식으로 영향을 미치는 값들
  • 캐릭터의 health, power, jump height 등의 수치들이 이에 해당한다.

Gameplay Effects

  • Gameplay Attribute를 변경하는 수단
    • 즉시 변경할 수도 있고, 일정 시간동안만 변경할 수도 있다.
    • 후자는 버프/디버프

Owner Tracking

  • Ability와 Effect는 "Owner"라는 개념을 유지해야 한다.
    • Effect가 계산을 수행할 때에는 Owner가 누구인지 알아야 Attribute를 사용할 수 있다.
  • 이 때 Owner는 Network Replication의 것과 다르다.

State Tracking

  • Ability는 다음과 같은 State 순환을 Tracking 할 수 있어야 한다.
    • Ability가 활성화 된 시점
    • Ability의 실행이 현재 진행중인 시점
    • Ability가 완전히 완료되고 더 이상 활성화되지 않은 시점

실행 조정하기

  • Ability는 실행 도중 특정 타이밍에 System과 다양한 Interaction을 할 수 있어야 한다.
    • Animation Montage 활성화
    • Character의 Movmenet를 일시적으로 제어
    • Visual Effect Trigger
    • Overlap 및 Collision Effect 수행
    • 일시적 혹은 영구적으로 Attribute 변경
    • 인게임 Resource 증감
    • 다른 Ability 활성화 허용 또는 차단
    • Ability 사용을 제한하기 위한 쿨다운 처리
    • 인게임 Evnet에 의한 중단
    • 진행 중인 다른 Ability 취소
    • Character의 주요 State 변경사항 적용
      • 새로운 MovementMode 활성화
    • 다른 Interaction 도중 입력에 반응
    • UI에 Ability의 인게임 상태 전달

시스템 구성

  • Edit -> Plugin에서 Gameplay Abilities를 검색해 활성화, Editor 재시작
  • [MyProjectName].Build.cs에 다음 항목 추가
    • GameplayAbilities
    • GameplayTags
    • GameplayTasks

Various Components of Gameplay Ability System

Owner Tracking

  • Gameplay Ability를 사용하기 위해서는 Ability System Component를 Actor에 Attach해야 한다.
  • Ability System Component는 다음 기능을 제공한다.
    • Actor에 Ability 추가/제거
    • Actor가 소유한 Ability가 무엇인지 지속적으로 Tracking, 활성화
    • Ability system의 Context에서 소유 Actor를 나타내는 주요 수단
    • 다양한 요소를 Tracking하기 위한 System과 소유 Actor에 직접 Access하기 위한 Interface 제공
      • Attribute
      • 진행중인 Effect
      • Gameplay Tag
      • Gameplay Effect
  • Multiplayer Game 환경에서 Ability System Component는 다음 기능또한 제공한다.
    • Client 정보 Replicate
    • Server에 Player Action 전달
    • Client가 Ability System Component의 State를 변경 할 권한이 있는지 확인
  • Ability System Component의 부모 Actor는 원격 활성화를 수행하기 위해 로컬에서 제어되는 Player가 소유해야 한다.

Ability 활성화 및 실행 처리

  • Gameplay Ability는 Ability의 모든 Event를 실행하는 것을 담당하는 BP Object이다.
    • Animatino 재생
    • Effect Trigger
    • Owner로부터 Attribute 가져오기
    • Visual Effect 표시

Ability 활성화 제어

  • Gameplay Ability를 활성화 할 경우 System은 Ability가 진행중인 것으로 인식
  • 이후 활성화 Event에 Attach 된 Code를 실행해 완료 함수를 호출
    • Ability의 실행이 완료됨을 알리기 전까지 각 함수와 Gameplay 작업을 거쳐 이동
  • 정리 작업을 추가로 징행해야 하는 경우 완료 시 Event에 Code를 추가로 Attach 할 수 있다.
  • Ability를 취소하여 실행을 중단할 수 있다.
  • Gameplay Ability는 Gameplay Tag를 사용하여 실행하는 것을 제한한다.
    • 모든 Ability는 활성화 될 때까지 2가지 Tag 목록을 가지고 있는다.
      • 소유 Actor에 추가하는 Tag 목록
      • 활성화를 차단하거나 Ability를 자동으로 취소하는 Tag 목록
  • 자체 Code로 Ability 실행을 수동을 취소/차단/허용 할 수 있다.
  • Gameplay Ability는 다음 4가지 방법을 통해 활성화 할 수 있다.
    • Gameplay Ability Handle
      • BP나 C++에서 Ability를 명시적으로 활성화
      • Ability가 부여될 때 Ability System Component에 의해 제공 됨
    • Gameplay Event
      • 일치하는  Ability Trigger로 모든 Ability를 실행
      • Input/Define Machanism을 추상화해야 하는 경우에 유연성 극대화를 위해서는 이 방식을 적극 권장 함
    • 일치하는 Tag와 함께 Gameplay Effect
      • 일치하는 Ability Trigger로 모든 Ability 실행
      • GamePlay Effect의 Trigger Ability를 끄려는 경우 선호 됨
      • 비활성화 된 Animation을 재생하고 다른 Game Action을 차단하는 Ability를 Trigger하는 Sleep Deburf
    • Input Code
      • Ability system Component에 의해 추가 됨
      • 호출 시 일치하는 모든 Ability Trigger
      • Gameplay Event와 유사

Ability 실행 제어

  • Gameplay Ability는 일반적으로 사용되는 다양한 사용 사례와 기능을 제공
    • Cooldown
    • Resource 비용 할당
    • Animation
    • 기타 일반적인 Unreal Engine System을 처리하는 Preprocessed Gameplay Ability Working Library
  • 표준 BP Function Node가 실행을 즉시 종료할 때 상태를 계속 Tracking 하며 도중에 다른 Event를 실행
  • 부모 Gameplay Ability가 적절하게 취소되고 정리되었는지 Tracking 가능
  • Game에서 Gameplay Ability 작업을 확장해 Custom Gameplay Logic 구현하는 것이 일반적인 용례이다.
  • 소유 Actor에서 Gameplay Tag와 Event Data Struct를 수신하기 위해 대기하는 Gameplay Event에 응답 가능.

Attribute Set 및 Attribute

  • Gameplay Attribute System은 Attribute로 구성된 Attribute Set를 통해 Actor와 Interact한다.
    • Attribute Set은 계산에 사용되는 소수값으로, 보통 핵심 통계값을 Tracking 하는데 사용된다.
  • 기본 변수 대비 Gameplay Attribute 사용을 했을 시 얻는 이점이 몇가지 있다.
    • System을 Build할 수 있는 일관적이고 재사용 가능한 Attribute Group을 제공
    • Reflection을 통해 Access 할 수 있어 BL Editor에서 간단한 계산과 Effect 생성 가능
    • Default/Current/Max Value를 별도로 Tracking해 일시적인 수정 및 지속적인 Effect를 쉽게 생성
    • 값을 Client에 Replicate해 UI 시각화에 안전함
  • Actor에서 Gameplay Ability를 사용하려면 Ability System Component에 Attribute Set을 추가해야 한다.
    • 그러면 Ability System Component는 Attribute Set에 할당된 Attribute에 Access할 수 있게 된다.

Gameplay Effect 처리

  • Gameplay Ability System은 Gameplay Effect를 사용해 Target Actor에 변경사항을 적용한다.
    • Damage 적용
    • 지속되는 Effect를 적용하는 One-shot Effect
      • 이 경우에 Gameplay Effect는 제거될 때까지 Target Actor에 자신을 Attach한다.
      • 만료되거나 정리되기 전까지로 제한된 수명을 미리 설정 할 수 있다.
      • 혹은 Target Actor의 Gameplay attribute에 적용된 변경사항을 실행 취소할 수도 있다.
  • Gameplay Effect는 Attribute에 기반하여 계산을 한다.
    • BP Editor에서 간단하게 계산을 직접 생성할 수도 있다.
    • 하지만 복잡한 로직을 가지고 있고,
      다수의 Attribute에 동시에 영향을 미치는 Custom Effect 계산은 C++로 작업하는 것이 적절하다.
  • 보통 Gameplay Ability의 Owner Actor와 Target Actor 모두에서 정보를 처리할 수 있다.
    • 그렇기에 일반적으로 계산을 재사용이 가능한 코드로 결합할 수 있다.

Cosmetic Effect 처리

  • Gameplay Queue는 Visual Effect와 Sound Effect 실행을 담당하는 Actor 및 UObject이다.
    • Multiplay Game에서는Cosmetic Feedback을 Replicate하는데 선호되는 Method이다.
    • 생성할 때 Event Graph 내에서 재생할 Effect를 위한 Logic을 실행
    • 일련의 Gameplay Tag와 연관될 수 있으며, 일치하는 Gameplay Effect를 자동으로 적용한다.
  • Gameplay Queue는 신뢰할 수 있는 Replication을 사용하지 않는다.
    • 때문에 일부 Client가 Queue를 수신하지 못하거나, Feedback을 표시하지 못하는 경우가 있다.
  • Gameplay Code와 결합되어 있는 경우 이 때문에 동기화가 해제될 수 있다.
    • 따라서 Gmaeplay Queue는 Cosmetic Effect에서만 사용되어야 한다.
  • 모든 Client가 Replicate 되어야 하는 경우에는 Replication 처리를 위해 Ability 작업에 의존해야 한다.
    • Montage 재생 Ability 작업이 이에 적합한 예시이다.

Network Multiplay

Ability System Component 및 Replication

  • Ability System Component가 모든 Component에 전체 State를 Replicate하면 안된다.
    • 대역폭 절약 및 부정행위 방지 목적
  • 모든 Client에 Ability와 Gamplay Effect를 Replicate하면 안된다.
    • 영향을 받는 Gameplay Attribute와 Tag만 Replicate 해야 한다.

Ability Replicate 및 Prediction 사용

  • Network Game의 Ability 대부분은 Server에서 실행되고 Client로 Replicate되어야 한다.
    • 이로 인해 Ability 활성화에 지연이 발생하는 것은 일반적인 현상이다.
  • 만약 빠른 속도로 진행되어야 하는 Multiplay Game의 경우 Ability를 Local로 활성화 하고,
    그 사실을 Server에 전달해 동기화 하는 방식을 사용한다.
  • Server가 Ability 활성화를 거부하는 경우 Local로 적용한 변경사항을 실행 취소해야 한다.
    • 일부 Gameplay Effect의 경우 Server에 의해 거부된 경우에 대한 롤백 기능을 지원한다.
    • 대부분의 즉각적이지 않은 Gameplay Effect가 포함된다.
    • Damage나 즉각적인 기타 Attribute/Tag 변경사항은 제외된다.

Server가 소유한 Object와 Interact 하기 위한 Ability 사용

  • Gameplay Ability는 Bot, NPC, Server 소유의 기타 Actor 및 Object와의 Interact를 처리할 수 있다.
    • 이는 Local 소유의 Actor(Player/Pawn), Replicated Ability, 비 GAS Server RPC를 통해 수행되어야 한다.
    • 위 호출은 Interaction을 Server에 Replicate한 다음 NPC와의 변경사항을 수행하는 권한을 가진다.

'UE5 > GAS' 카테고리의 다른 글

[GAS] Ability Task  (0) 2024.05.16
[GAS] Gameplay Effect  (0) 2024.05.15
[GAS] Attribute Set  (1) 2024.05.14
[GAS] Gameplay Attribute  (0) 2024.05.13
[GAS] Ability System Component  (0) 2024.05.13

Source Control 활성화

Editor Preference

  • Edit -> Editor Preference -> Loading & Saving에서 활성화 가능

Automatically Checkout on Asset Modification

  • 활성화 시 변경된 Asset을 자동으로 Checkout 한다.

Prompt for Checkout on Package Modification

  • 활성화 시 Source Control로 제어되는 Package가 변경될 때 해당 Package를 Checkout 할지 묻는 창을 띄운다.

Add New Files when Modified

  • 새 파일이 추가되면 Source Control에도 추가된다.

Use Global Settings

  • Project 단위가 하닌 Global Source Control Login Setting을 사용한다.
  • 옵션 변경 시 다시 Login 해야 한다.

Tool for Diff'ing text

  • Text File Version비교에 사용할 Tool의 File Directory를 지정한다.

contents Browser

  • Asset/Folder 우클릭 -> Source Control Sesction에 Connect to Source Control 선택

상태 아이콘

Source Control 작업

  • Source Control 활성화 상태에서 Asset 우클릭 시 다음 메뉴를 볼 수 있다.

Check Out

  • Asset을 편집 가능한 상태로 Check out
  • Asset을 다른 사용자가 동시에 편집하지 못하도록 한다.

Refresh

  • Asset의 Source Control 상태를 새로고침 한다.

History

  • 선택된 Asset의 Revision History를 확인하여 기존 수정 내용을 볼 수 있다.

Diff Against Depot

  • 이 Asset을 현재 Source Control Depot에 저장된 Version과 비교할 수 있다.

Check Out/Check In

  • Asset 편집을 위해 Checkout 하기 위해서는 우클릭해서 Check Out을 선택하면 된다.
  • 하지만 Checkin 할 때에는 다음 규칙을 따라야 한다.
    • Asset 우클릭 -> Check In 선택
      • 선택 시 필요한 Changelist 설명을 입력하라는 창이 뜬다.
      • 필수 사항으로, 입력하지 않으면 Ok 버튼이 나타나지 않는다.
    • 설명을 입력하면 Asset의 Revision History에 추가된다.

Contents Hot Reload

  • Source Control 작업에 의해 Contents가 변경되었을 때 Eidtor 내 Source Control에서 Contents를 Reload 해준다.
  • 현재 Editor 내의 통합된 Source Control을 통해 작업을 할 때에만 작동한다.
    • 외부에서 변경했을 때에는 Reload가 발생하지 않는다.
  • Contents Hot Reload는 명령이 있을 때 ASset의 지난 저장 상태에서 Reload 하는 기능도 제공한다.
    • Asset 우클릭 -> Asset Action -> Reload 선택
    • Asset을 저장하지 않는 변경사항을 revert 하고 Disk 버전으로 되돌리고자 할 때 매우 유용하다.

Source Control 비활성화

  1. Level Editor 우상단 구석에 초록생 화살표 아이콘을 클릭해 Source Control Login 창으로 접속한다.
  2. Run Without Source Control 버튼을 클릭해 초록색 아이콘을 클릭한다.
    • 클릭하면 금지 아이콘으로 변경되어 Source Control이 비활성화 된다.

 

'UE5 > Utility' 카테고리의 다른 글

[Basic] Packaging  (0) 2024.05.09
[Programming Tool] LLM(Low-level Memory Tracker)  (0) 2024.05.07
[ProgrammingTool] Sparse Class Data  (0) 2024.05.07

https://dev.epicgames.com/documentation/ko-kr/unreal-engine/packaging-unreal-engine-projects

 

프로젝트 패키징 | 언리얼 엔진 5.4 문서 | Epic Developer Community

언리얼 게임 프로젝트의 배포용 패키지 만들기입니다.

dev.epicgames.com

  • Packaging으로 모든 Code와 Contents가 최신인지, Target Plartform에서 실행하기 적합한 포맷인지 확인한다.
  • File -> Package Project 옵션에서 Package에서 만들 수 있는 대상 Platform 확인 가능

Process

  • Project Source Code를 Compile
  • Cooking
    • 필수 컨텐츠를 Target Platform에서 사용 가능한 Format으로 변환
  • Compile 된 Code와 Cooking된 Contents를 묶어 Windows Installer와 같은 배포 파일 생성
    • Android Packaging은 몇 가지 선택사항이 더 있다.

Game Default Map 설정

  • Packaging을 하려면 Game 시작 시 Load 할 Game Default Map 설정이 필요
    • Default Map이 설정되지 않으면 Packaging 된 Game 시작 시 검은 화면이 나온다.
    • Edit -> Project Setting -> Map & Modes에서 설정

Package 만들기

  • File -> Project Package -> [Platform Name] 선택
  • Target Directory 선택한다.
    • Target Directory를 확인하고 나면 선택된 Platform용으로 Project를 Packaging한다.
  •  Packaging은 매우 오래 걸리는 작업이라 Process가 Background에서 진행된다.
    • 이 때 Editor는 계속 사용할 수 있다.
    • Cancel로 취소 가능
    • Show Log 링크로 자세한 로그 표시 가능
      • Packaging Process가 실패했을 때 오류 사항을 확인하여 버그가 될 수 있는 Warning을 잡아낼 수 있다.
      • 보이지 않을 경우 Window -> Developer Tool -> Output Log / Message Log 옵션으로 활성화 가능
  • Packaging이 성공적으로 끝나면, Target Directory에 Packaging 된 Project가 들어간다.

Distribution

  • App Store나 Google Play Store에 제출하려면 Distribution Mode로 Game Package를 만들어줘야 한다.
    • Packaging -> Packaging Setting -> Distribution 옵션을 체크

IOS

  • Apple의 Developer site에서 배포 Certificate와 MobileProvision을 생성해줘야 한다.
  • Development Certificate와 같은 방식으로 Distribution Certificate 설치
    • 배포 Provision 이름에 "Distro_" 접두사를 붙여준다.
      • Distro_MyProject.mobileprovision이 MyProject.mobileprovision이 된다.

Android

  • .apk File Signing을 할 Key를 생성
  • BuildTool에 정보를 줘야 한다.
    • Engine/Build/Android/Java/SigningConfig.xml
    • 이 파일을 직접 수정하면 모든 Project에 적용
    • Project/Build/Android Directory에 복사하면 해당 Project에만 적용 된다.

Advanced Setting

  • File -> Project Package -> Package Setting
    • 또는 Edit -> Project Setting -> Packaging

Build Configuration

  • Code based Project를 Compile 할 때의 Build Configuration
    • Blueprint 전용 Project에서는 이 옵션이 없다.
  • Code Project Debuging의 경우 DebugGame 선택
    • 이 외의 Debuging은 최소한으로 지원
  • Performance가 좋은 개발용으로는 대부분 Development 선택
  • 최종 빌드의 경우 Debuging 정보와 기능이 제거된 Shipping을 선택

Statging Directory

  • Packaging 된 Build가 들어가게 될 Directory
  • Target Directory 선택 창에서 다른 Directory를 선택하면 자동으로 업데이트

Full Rebuild

  • Code를 전부 다 Compile 할지 여부
    • 비활성화 하면 수정된 Code만 Compile
    • 잘 활용하면 Packaging Process 속도가 빨라질 수 있다.
  • Shipping 빌드의 경우 누락/오래된 버전 갱신을 위해 항상 활성화를 해주는것이 좋다.
  • 기본적으로 활성화 되어있다.

Use Pak File

  • Project의 Asset들을 개별 Fiel로 둘지, 하나의 Package로 만들지 여부
    • 활성화하면 모든 Asset은 하나의 .pak 파일에 들어간다.
    • 비활성화 하면 모든 파일을 하나하나 복사한다.
  • Asset File이 많은 경우, 전송해야 하는 File 양이 줄어들어 배포가 쉬워질 수 있다.
  • 기본적으로 비활성화 되어 있다.

Generate Chunks

  • Streaming Install에 사용할 수 있는 .pak File Chunk 생성 여부

Build Http Chunk Install Data

  • HTTP Chunk Installer 용 Data 생성 여부
  • 이를 통해 Web Server에서 Hosting하여 Runtime에서 설치가 가능

Http Chunk Install Data Directory

  • Build가 완료되면 Data가 설치되는 Driectory

Http Chunk Install Data Version

  • HTTP Chunk Install Data의 Version Name

Include Prerequisites Install

  • Packaging된 Game의 사전 요구사항 Installer를 포함시킬지 여부
    • OS Component 재배포판

Signing and Crypto

  • 출시 때 .Pak 파일을 서명하거나 암호화
    • Data 추출이나 Hacking을 방지
    • Unreal Engine 4.22 이후에서는 OpenSSL Library로 통합 함
  • Project Setting -> Crypto Section

Encrypt Pak INI Files

  • Project의 .pak File에 존재하는 모든 .ini File을 암호화
    • 최소한의 Runtime 비용으로 Data Mining 혹은 변조를 방지할 수 있다.

Encrypt Pak Index

  • .Pak File Index를 암호화
    • 최소한의 Runtime 비용으로 UnrealPak File을 열고 확인
    • 제품의 .Pak File을 Unpack하지 못하도록 한다.

Encrypt UAsset Files

  • .Pak File의 .Uasset 파일을 암호화
    • 이 파일에는 Asset의 Header 정보만 있고 Data 자체는 없다.
  • 이 Data를 암호화 하면 보안성은 향상한다.
    • 하지만 Runtime 비용이 추가되고, Data Entropy가 증가해 Patch 크기가 커질 수 있다.

Encrypt Assets

  • ,Pak File 안의 모든 Asset을 암호화
    • Runtime File I/O Performance에 영향을 준다.
    • Package Data의 Entropy를 증가시켜 Patching System 효율을 떨어트린다.

Enable Pak Signing

  • .Pak File Sign을 활성화/비활성화한다.

Contents Cooking

  • Packaging 없이 특정 Target Platform Contents만 Cooking
    • 반복 작업에서 길고 지루한 Packaging Process를 피할 수 있음
  • File -> Contents Cooking -> [Platform Name] 선택
    • Local Developer Workspace에 있는 Contents를 Update하지, Staging Directory에 Asset을 복사하는 것은 아니다.

Optimize Load Time

  • Package Process 도중 Project Load Time을 최적화 하는 메서드 제공
    • 결과적으로 Game Load Time이 감소함

Event Driven Loader 및 Asynchronous Loading Thread 사용

Event Driven Loader

  • 기본적으로 활성화 되어있는 옵션
    • Project Setting - Engine - Streaming에서 비활성화 가능
  • 대부분의 Project에서는 EDL을 사용하면 Load Time이 절반으로 줄어든다.
    • 안정적이다.
    • Unreal Engine 구버전에 대한 하위 Porting, 수정dl rksmdgkek.
    • Customized Engine Version에 맞게 조정 가능하다.

Asynchronous Loading Thread

  • 기본적으로 비활성화 되어있는 옵션
    • Project Setting - Engine - Streaming에서 활성화 가능
  • Engine을 Customize한 경우 미세조정이 필요할 수 있지만, 보통 ALT는 전반적인 Load Time을 배가시켜준다.
    • 게임의 최초 Load Time
    • 지속적인 Data Streaming Time
  • ALT는 Serialize와 Post-Loading Code를 2개의 별도 Thread에 동시에 실행시키며 동작한다.
  • 이에 따라 Game Code의 다음 항목은 반드시 Thread-safe 해야 한다.
    • UObject Class Construct
    • PostInitProperties Function
    • Serialize Function
  • ALT는 가동되면 Load 속도가 2배가 된다.

Compress .pak File

  • Project Setting -> Packaging -> Advanced Option -> Create compressed cooked packages 체크
  • 대부분의 Platform에서는 자동 압축을 제공하지 않기에 .pak File을 압축하면 Load Time이 단축된다.
  • 다만 플랫폼 별로 고려사항이 있다.

Sony PlayStation 4

  • 모든 PS4에 자동 적용되는 압축과 .pak File 압축은 중복되어도 File Size가 줄어드는 혜택이 없다.
    • 압축 작업만 중복한다.
  • 때문에 .pak File 압축은 하지 않는 것이 좋다.

Nintendo Switch

  • 압축된 File Load가 더 빠를 수 있지만, 압축을 해제하는데 시간이 더 오래 걸릴 수 있다.
  • 타이틀마다 테스트를 해보고 결정해보는 것이 좋다.

Microsoft XBoxOne

  • 가장 빠른 Load Time을 내기 위해서 매우 중요하다.

Steam

  • 사용자가 다운로드 도중에 파일을 압축하므로 다운로드 시간이 .pak File에 영향을 받지 않는다.
    • 하지만 미압축 File의 경우 Steam의 Differential Patch Steam이 더 나을 수 있다. 
  • 압축된 .pak File은 소비자의 시스템 디스크 공간을 절약해준다.
    • 하지만 Patch 할 때 다운로드 시간은 길어진다.

Oculus

  • .pak file 압축을 지원하지 않는다.

Order pak File

  • Load Time 단축을 위해서는 .pak File 순서를 잘 지정해야 한다.
    • Unreal에서는 Data Asset의 필요 순서를 알아내어 더 빠른 Loading Package를 제작하는 Tool을 제공한다.
    • 개념적으로 이 Process는 Profile Drived Optimization와 비슷하다.
  1. -fileopenlog Command-line Option으로 Package Game을 build, Launch해 Engine이 File 순서를 기록하도록 한다.
  2. 게임 주요 영역을 전부 확인하고 게임을 종료한다,
    • 모든 Level, Character, Weapon, Vehicle 등
  3. GameOpenOrder.log 파일을 /Build/WindowsNoEditor/FileOpenOrder/ Directory에 복사한다.
    • Deployed Game에서 .pak File 순서 최적화에 필요한 정보가 들어있다.
    • 예를 들어 Windows Build는 WindowsNoEditor/(YourGame)/Build/WindowsNoEditor/FileOpenOrder/ 에 있다.
  4. Log File을 배치하고 .pak File을 리빌드한다.
    • 그러면 이번에 생성된 File가 앞에 생성된 모든 ,pak File은 Log File에 나타난 순서를 사용한다.
  • Production 환경에서는 다음 사항을 반드시 해줘야 한다.
    • Log File을 Source Control에 Check-in
    • 주기적으로 -fileopenlog를 붙여 실행한 뒤 업데이트
    • 발매 준비가 되면 마지막으로 한번 더 실행

'UE5 > Utility' 카테고리의 다른 글

[Basic] Source Control  (0) 2024.05.09
[Programming Tool] LLM(Low-level Memory Tracker)  (0) 2024.05.07
[ProgrammingTool] Sparse Class Data  (0) 2024.05.07

https://dev.epicgames.com/documentation/ko-kr/unreal-engine/using-the-low-level-memory-tracker-in-unreal-engine?application_version=5.3

 

언리얼 엔진에서 로우 레벨 메모리 트래커 사용하기 | 언리얼 엔진 5.4 문서 | Epic Developer Community

언리얼 프로젝트의 메모리 사용량을 트래킹합니다.

dev.epicgames.com

  • Unreal에서 제공하는 Memory 사용량 Tracking tool
  • Scoped-Tag System을 사용해 Unreal Engine과 OS에서 할당한 모든 Memory에 대한 Account를 유지
  • Unreal Engine에서 사용하는 모든 Platform에 대한 LLM을 지원

LLM Tracker

Default Tracker

  • Engine의 모든 Alloc에서 사용하는 High-Level Tracker
  • FMemory::Malloc을 통해 이루어진 할당을 기록
  • Stat LLM, Stat LLMFULL Console Command에 대한 통계를 제공
  • Platform Tracker의 Subset

Platform Tracker

  • OS에서 이루어진 모든 Alloc을 기록하는 Low-Level Tracker
    • BindMalloc
      • OS 단위에서 발생하는 Memory Allocation을 더 효율적으로 사용하기 위한 Wrapper
      • 큰 규모의 Memory를 OS로부터 할당 받고, Application에 작은 단위로 쪼개서 제공한다.
    • AnsiMalloc
      • 표준 C++ Library 기반 Allocator
    • TBBMalloc
      • Intel의 Thread Building Blocks 기반의 Allocator
    • JeMalloc
      • 성능 최적화가 강조된 Allocator

LLM Configuration

Command-line Argument

  • -LLM
    • LLM 활성화
  • -LLMCSV
    • 모든 값을 csv 파일에 지속적으로 기록
      • saved/profiling/llm/ 에 기록
      • csv 파일에는 현재 값(MB)을 표시하는 각 Tag에 대한 Row가 포함된다.
      • 기본적으로 5초마다 새 Row가 작성된다.
        • Console 변수인 LLM.LLMWriteInterval을 사용하여 주기를 변경할 수 있다.
    • -LLM이 자동으로 활성화
  • -llmtagsets=Assets
    • 각 Asset별 할당된 합계를 표시
    • 5.3 기준 실험 기능
  • -llmTagSets=ASsetClasses
    • 각 UObject Class Type의 합계를 표시
    • 5.3 기준 실험 기능

Console Command

  • stat LLM
    • LLM 요약을 표시
    • 모든 Low-Level Engine 통계는 단일 통계로 그룹화 된다.
  • stat LLMFULL
    • 모든 LLM 통계를 표시
  • stat LLMPlatform
    • OS에서 할당된 모든 Memory에 대한 통계를 표시
  • stat LLMOverhead
    • LLM에서 내부적으로 사용하는 Memory 표시

LLM Tag

  • Engine과 Game Code에 의해 이루어진 모든 Memory Allocation에는 속한 Category를 식별하는 Tag가 할당된다.
    • 즉, Memory는 한번만 Tracking 되고, 누락되지 않는 한 두 번 계산되지 않는다.
    • 모든 Category의 합계가 Game에서 사용하는 총 Memory에 추가 된다.
  • Tag는 Tag Scope Macro를 사용하여 적용된다.
    • 해당 Tag 범위 내에서 이루어진 모든 Allocation은 지정된 Tag가 제겅된다.
  • LLM은 Tag Scope Stack을 유지/관리하고, Allocation에 최상위 Tag를 적용한다.

Engine에서 제공하는 Tag Category

UObject

  • UObject에서 상속된 모든 Class와 Property를 포함하여 해당 Class에 의해 Serialize 된 모든 것을 포함
    • UObject는 어떤 Category에서도 Tracking 되지 않는 모든 Engine/Game Memory에 대한 포괄적 Tag
  • 별도로 Tracking되는 Mesh, Animation Data는 포함되지 않는다.
  • Level에 배치된 Object의 수에 대응

EngineMisc

  • 다른 Category에서 Tracking되지 않는 모든 Low-Level Memory

TaskGraphTasksMisc

  • 자체 Category가 없는 Task Graph에서 시작되는 모든 Task
  • 보통은 상당히 낮아야 한다.

StaticMesh

  • UStaticMesh Class 및 관련 Property
  • 실제 Mesh Data를 포함하지는 않는다.

Custom Tag

  • Memory Profiling 할 때 Memory Insight에서 LLM Untracked Tag가 지정된 Allocated Memory가 있을 수 있다.
    • 이 때 LLM_DECLARE_TAG, LLM_DEFINE_TAG 매크로를 이용해 Custom Tag를 만들어 대응한다.
  • 이 매크로들은 Engine File을 수정하지 않고 Game Modue이나 Plugin에서 수행할 수 있다.
  • 자세한 구현은 Runtime/Core/Public/HAL/LowLevelMemTracker.h에서 확인할 수 있다.

LLM_DECLARE_TAG

  • 더보기
    /**
    * Declare a tag defined by LLM_DEFINE_TAG. It is used in LLM_SCOPE_BYTAG or referenced by name in other LLM_SCOPEs.
    * @param UniqueName - The name of the tag for looking up by name, must be unique across all tags passed to
    *        LLM_DEFINE_TAG, LLM_SCOPE, or ELLMTag.
    * @param ModuleName - (Optional, only in LLM_DECLARE_TAG_API) - The MODULENAME_API symbol to use to declare module
    *        linkage, aka ENGINE_API. If omitted, no module linkage will be used and the tag will create link errors if
    *        used from another module.
    */
    #define LLM_DECLARE_TAG(UniqueNameWithUnderscores) extern FLLMTagDeclaration PREPROCESSOR_JOIN(LLMTagDeclaration_, UniqueNameWithUnderscores)
    #define LLM_DECLARE_TAG_API(UniqueNameWithUnderscores, ModuleAPI) extern ModuleAPI FLLMTagDeclaration PREPROCESSOR_JOIN(LLMTagDeclaration_, UniqueNameWithUnderscores)

LLM_DEFINE_TAG

  • 더보기
    /**
     * Define a tag which can be used in LLM_SCOPE_BYTAG or referenced by name in other LLM_SCOPEs.
     * @param UniqueNameWithUnderscores - Modified version of the name of the tag. Used for looking up by name,
     *        must be unique across all tags passed to LLM_DEFINE_TAG, LLM_SCOPE, or ELLMTag.
     *        The modification: the usual separator / for parents must be replaced with _ in LLM_DEFINE_TAGs.
     * @param DisplayName - (Optional) - The name to display when tracing the tag; joined with "/" to the name of its
     *        parent if it has a parent, or NAME_None to use the UniqueName.
     * @param ParentTagName - (Optional) - The unique name of the parent tag, or NAME_None if it has no parent.
     * @param StatName - (Optional) - The name of the stat to populate with this tag's amount when publishing LLM data each
     *        frame, or NAME_None if no stat should be populated.
     * @param SummaryStatName - (Optional) - The name of the stat group to add on this tag's amount when publishing LLM
     *        data each frame, or NAME_None if no stat group should be added to.
     */
    #define LLM_DEFINE_TAG(UniqueNameWithUnderscores, ...) FLLMTagDeclaration PREPROCESSOR_JOIN(LLMTagDeclaration_, UniqueNameWithUnderscores)(TEXT(#UniqueNameWithUnderscores), ##__VA_ARGS__)

LLM_SCOPE_BYTAG

  • 더보기
    #define LLM_SCOPE_BYTAG(TagDeclName) 
    FLLMScope SCOPE_NAME(PREPROCESSOR_JOIN(LLMTagDeclaration_, TagDeclName).GetUniqueName(), false /* bIsStatTag */, ELLMTagSet::None, ELLMTracker::Default);\
    UE_MEMSCOPE(PREPROCESSOR_JOIN(LLMTagDeclaration_,TagDeclName).GetUniqueName());

Custom Tag macro 사용 방법

  1. LLM_DELCARE_TAG를 사용해 header File에 Custom LLM Tag를 선언
  2. 관련 .cpp File에서 LLM_DEFINE_TAG를 사용해 Custom LLM Tag를 정의
  3. LLM_SCOPE_BYTAG를 사용해 .cpp 파일의 Memory Tracking

Code 예시

  • CustomTagExample.h
    • 더보기
      #pragma once
      ...
      LLM_DECLARE_TAG(MyTestTag);
  • CustomTagExample.cpp
    • 더보기
      LLM_DEFINE_TAG(MyTestTag);
      
      AMyActor::AMyActor()
      {
          LLM_SCOPE_BYTAG(MyTestTag);
          MyLargeBuffer.Reset(new uint8[1024*1024*1024]);
      }

Tag Set

  • 실험 단계
  • LowLevelMemTracker.h안의 LLM_ALLOW_SSETS_TAGS를 정의하여 사용
  • Tag Set을 사용할 때 각 Allocation은 Asset이나 Object Class 이름을 추가로 저장한다.
  • Memory 사용량과 Runtime Performance에 모두 오버헤드가 추가된다.

Technical Detail Implementation

  • LLM은 Pointer를 Index로 하여 모든 Allocation의 Map을 유지하며 동작한다.
    • 이 Map은 각 Allocation의 크기와 할당된 Tag를 포함한다.
  • Game에는 동시에 최대 400만개의 Live Allocation을 가질 수 있다.
    • 때문에 Memory Overhead를 가능한 작게 유지하는 것이 중요하다.
  • 현재 구현에서는 Allocation 하나 당 21Byte를 사용한다.
    • Allocation Size
      Pointer 8 Byte
      Pointer Hash Key 4 Byte
      Size 4 Byte
      Tag 1 Byte
      Hash Map Index 4Byte
  • OnLowLevelAlloc 함수를 사용하여 Allocation을 Tracking하면
    Tack Stack 제일 위에 있는 Tag가 현재 Tag가 되고, Pointer를 Key로 사용해 그 Allocation이 Map에 저장이 된다.
  • Conflict를 피하기 위해 각 Tag의 Frame Delta는 별도의 FLLMThreadState Class Instance에서 Tracking 된다.
  • Frame이 끝나면 이 Delta를 합산해 통계 시스템과 .csv File에 게시한다.
  • LLM은 초기에 Initialize되므로 Default로 활성화 해야 한다.
    • Command-line에서 LLM이 활성화 되어있지 않으면 자동으로 종료가 된다.
    • 동시에 모든 Memory가 종료되어 Overhead가 발생하지 않는다.
  • LLM은 Test 및 Shipping Build에서 완전히 Compile 된다.
  • LLM은 통계 시스템 없이 실행할 수 있다.
    • 이 경우, 화면에 통계를 표시할 수는 없지만 여전히 .csv File에는 기록이 된다.
    • 이를 위해서는 LowLevelMemTracker.h에서 ENABLE_LOW_LEVEL_MEM_TRACKER를 수정해
      LLM을 활성화 해야 한다.
  • Tag는 Scope Macro를 사용하여 적용하는데, 이에는 2가지가 제공된다.
    • LLM_SCOPE
      • Default Tracker Scope 설정
    • LLM_PLATFORM_SCOPE
      • Platform Tracker Scope 설정
    • LLM_SCOPED_TAG_WITH_STAT
      • 위와 같이 통계를 사용하는 Scope Macro는 Deprecated 되었기에 사용하면 안된다.
  • LLM 내부에서 사용하는 모든 Memory는 Platform에서 제공하는 LLMAlloc/LLMFree 함수로 관리한다.
    • 때문에 LLM이 자체 Memory 사용량을 Tracking 하지 않도록,
      그리고 무한  Loop에 빠지지 않도록 다른 방식으로 할당하지 않는 것이 중요하다.

Additional Technical Detail

  • LLM의 Overhead는 100MB 이상이 될 수 있으므로 Console에서는 대용량 Memory Load를 지양하는 것이 좋다.
  • Test Setting에서의 LLM은 화면에 통계 페이지를 표시하지 않는다.
    • 하지만 .csv File에는 통계를 작성한다.
    • LLM은 Shipping에서 완전히 비활성화가 된다.
  • Asset Tag Tracking은 아직 초기 실험단계이다.

'UE5 > Utility' 카테고리의 다른 글

[Basic] Source Control  (0) 2024.05.09
[Basic] Packaging  (0) 2024.05.09
[ProgrammingTool] Sparse Class Data  (0) 2024.05.07

https://dev.epicgames.com/documentation/ko-kr/unreal-engine/sparse-class-data-in-unreal-engine?application_version=5.3

  • 자주 사용되는 Actor Type의 주복 데이터를 제거하여 Memory를 절약
  • 제공하는 기능
    • Memory에 Property의 사본을 단 하나만 존재하도록 유지
    • Designer가 BP Graph에서 Property 값에 Access하고 Class Default에서 편집 가능
  • 사용을 권장하는 경우
    • In-Game에서 동시에 여러 개의 Instance를 가지는 Actor Class의 Property
      • 상당한 Memory가 중복된 사본에 사용되고 있음을 의미한다.
    • 배치된 Actor Instance를 변경하지 않는 Property
      • Actor Instance가 값을 override하지 않아 EditInstanceOnly나 EditAnywhere 지정자가 필요하지 않는 경우
    • C++ 코드로 수정되지 않는 Property
      • 직접 Access하는 모든 C++ 코드는 접근자 함수에 대한 호출로 대체 되어야 한다.
  • Sparse Class Data를 사용하기 위해서는 Native C++ 코드가 필요하다.

예제

  • 더보기
    USTRUCT(BlueprintType)
    struct FMySparseClassData
    {
        GENERATED_BODY()
    
        FMySparseClassData() 
        : MyFloatProperty(0.f)
        , MyIntProperty(0)
        , MyNameProperty(NAME_None)
        { }
    
        // 에디터에서 이 프로퍼티의 디폴트값을 세팅할 수 있습니다.
        // 블루프린트 그래프에서는 액세스할 수 없습니다.
        UPROPERTY(EditDefaultsOnly)
        float MyFloatProperty;
    
        // 이 프로퍼티의 값은 C++ 코드로 설정됩니다.
        // 블루프린트 그래프에서 액세스할 수 있습니다(변경은 불가능함).
        UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
        int32 MyIntProperty;
    
        // 에디터에서 이 프로퍼티의 디폴트값을 세팅할 수 있습니다.
        // 블루프린트 그래프에서 액세스할 수 있습니다(변경은 불가능함).
        // 'GetByRef'는 블루프린트 그래프가 사본 대신 const 참조에 액세스함을 의미합니다.
        UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta=(GetByRef))
        FName MyNameProperty;
    };
    • EditAnywhere, EditInstanceOnly, BlueprintReadWrite가 Tag된 Property 대상으로는 작업할 수 없다
    • Sparse Class Data를 포함하는 Struct는 USTRUCT(BlueprintType) 지정자가 선언되어 있어야 한다.
      • 각 Property는 반드시 EditDefaultsOnly 지정자를 포함해야 한다.
      • 별도의 Category가 없는 경우, Default인 'My Sparse Class Data'를 받게 된다.
  • 더보기
    UCLASS(BlueprintType, SparseClassDataTypes = MySparseClassData)
    class AMyActor : public AActor
    {
        GENERATED_BODY()
    
    #if WITH_EDITOR
    public:
        // ~ 이 함수는 기존 데이터를 FMySparseClassData로 전송합니다.
        virtual void MoveDataToSparseClassDataStruct() const override;
    #endif // WITH_EDITOR
    
    #if WITH_EDITORONLY_DATA
        //~ 이 프로퍼티는 FMySparseClassData 구조체로 이동합니다.
    private:
        // 이 프로퍼티는 에디터에서 변경할 수 있지만, 클래스별로만 변경됩니다.
        // 블루프린트 그래프에서는 액세스하거나 변경할 수 없습니다.
        // 희소 클래스 데이터의 잠재적 후보입니다.
        UPROPERTY()
        float MyFloatProperty_DEPRECATED;
    
        // 이 프로퍼티는 에디터에서 변경할 수 없습니다.
        // 블루프린트 그래프에서 액세스할 수 있지만, 변경할 수는 없습니다.
        // 희소 클래스 데이터의 잠재적 후보입니다.
        UPROPERTY()
        int32 MyIntProperty_DEPRECATED;
    
        // 이 프로퍼티는 에디터에서 클래스별로 편집할 수 있습니다.
        // 블루프린트 그래프에서 액세스할 수 있지만, 변경할 수는 없습니다.
        // 희소 클래스 데이터의 잠재적 후보입니다.
        UPROPERTY()
        FName MyNameProperty_DEPRECATED;
    #endif // WITH_EDITORONLY_DATA
    
        //~ 나머지 프로퍼티는 인스턴스별로 변경할 수 있습니다.
        //~ 따라서 나머지 프로퍼티는 희소 클래스 데이터 구현에서 제외됩니다.
    public:
        // 이 프로퍼티는 배치된 MyActor 인스턴스에서 편집할 수 있습니다.
        // 희소 클래스 데이터의 잠재적 후보가 아닙니다.
        UPROPERTY(EditAnywhere)
        FVector MyVectorProperty;
    
        // 이 프로퍼티는 블루프린트 그래프에서 변경할 수 있습니다.
        // 희소 클래스 데이터의 잠재적 후보가 아닙니다.
        UPROPERTY(BlueprintReadWrite)
        FVector2D MyVector2DProperty;
    };
    • UCLASS(SparseClassDataTypes = [SPARSE_CLASS_DATA_TYPE])
      • 이 선언을 통해 이 Class에서 어느 Sparse Class Data를 사용할지 연결한다.
      • Class당 1개의 Sparse Class Data만 지정할 수 있다.
        • 여러개가 필요한 경우 이를 하나로 묶은 Wrapper를 Sparse Class Data로 지정해야 한다.
      • Sparse Class Data를 지정하면 UBT가 자동으로 Get[SPARSE_CLASS_DATA_TYPE] 함수를 생성해준다.
    • 다음은 기존 변수를 무난하게 Sparse Class Data로 변환하며 값을 설정하기 위한 세팅이다.
      • Sparce Class Data로 이동하는 Property 주변을 #if WITH_EDITORONLY_DATA Precomiler 처리
      • 원본 Class의 property의 변수명에 _DEPRECATED 접미사 추가
        • _DEPRECATED 접미사가 붙은 변수는 Unreal에서 인지하고 사용 시 warning을 발생시켜준다.
      • 원본 Class의 UPROPERTY에 모든 지정자를 제거하고 접근자를 private로 세팅
      • Editor Build(#if WITH_EDITOR) 환경에서 MoveDataToSparseClassDataStruct 함수 override
        • 원본 Class에서 Sparse Class Data로 1회성 복사를 수행해 기존 값을 보존
  • 더보기
    #include "Engine/BlueprintGeneratedClass.h"
    
    #if WITH_EDITOR
    void AMyActor::MoveDataToSparseClassDataStruct() const
    {
        // 이미 저장된 희소 데이터를 덮어쓰지 않도록 하세요.
        UBlueprintGeneratedClass* BPClass = Cast<UBlueprintGeneratedClass>(GetClass());
        if (BPClass == nullptr || BPClass->bIsSparseClassDataSerializable == true)
        {
            return;
        }
    
        Super::MoveDataToSparseClassDataStruct();
    
    
        #if WITH_EDITORONLY_DATA
        // 언리얼 헤더 툴(Unreal Header Tool, UHT)은 GetMySparseClassData를 자동 생성합니다.
        FMySparseClassData* SparseClassData = GetMySparseClassData();
    
        // 이 줄을 수정하여 모든 희소 클래스 데이터 프로퍼티를 포함합니다.
        SparseClassData->MyFloatProperty = MyFloatProperty_DEPRECATED;
        SparseClassData->MyIntProperty = MyIntProperty_DEPRECATED;
        SparseClassData->MyNameProperty = MyNameProperty_DEPRECATED;
        #endif // WITH_EDITORONLY_DATA
    }
    #endif // WITH_EDITOR
  • Sparse Class Data의 영향을 받은 Property를 Editor에서 편집/Access 하는 사용자는 차이를 느끼지 못한다.
  • Memory 사용량은 줄어든다.
  • Property가 C++에서 Reference되는 경우, Getter 함수 호출로 모두 대체 되어야 한다.
    • 예를 들어 SparceClassData::MyFloatPropertyData에 접근하려면 GetMyFloatProperty를 대신 호출해야 한다.
    • 다행히도 이러한 함수는 UHT가 자동으로 생성한다.
  • 해당 PROPERTY에 NoGetter MetaData 지정자를 선언하면 Getter 함수 생성을 방지할 수 있다.
  • 해당 PROPERTY에 값 대신 상수 참조로 Access 하고 싶은 경우 GetByRef MetaData 지정자를 사용해야 한다.

'UE5 > Utility' 카테고리의 다른 글

[Basic] Source Control  (0) 2024.05.09
[Basic] Packaging  (0) 2024.05.09
[Programming Tool] LLM(Low-level Memory Tracker)  (0) 2024.05.07

https://dev.epicgames.com/documentation/ko-kr/unreal-engine/versioning-of-assets-and-packages-in-unreal-engine

 

언리얼 엔진의 에셋 및 패키지 버전 관리 | 언리얼 엔진 5.4 문서 | Epic Developer Community

언리얼 엔진에서 커스터마이징된 시리얼라이제이션 코드 및 버전 관리를 사용하여 에셋과 패키지에서 오브젝트를 로드하는 방법을 제어합니다.

dev.epicgames.com

  • Unreal Engine에는 Engine과 Engine Code, Data 사이의 호환성을 정의하거나 보증하는
    다양한 Version Control System을 제공한다.
    • 이를 이용하면 호환 불가능한 Code나 Data 감지가 가능한다.
    • 여기에 더불어, Custom Serialization 및 Convert Data를 관리할 수 있다.

Engine Version

  • Unreal Engine에서 가장 수준 높고 사용자 가시성이 뛰어난 Version Control
  • Editor 내 Help 메뉴 -> About Unreal Editor 섹션에서 확인 가능
  • 엔진 버전은 다음과 같이 구성되어 있으며, FEngineVersion/FEngineVersionBase 클래스에서 확인할 수 있다.
    • 더보기
      [MajorVersion].[MinorVersion].[PatchVersion].[ChangeListNumber][BranchName]
      5.0.3.20979098+++UE5+Release-5.0
    • Engine Version을 구성하는 각 Component는 상위 값이 증가하지 않는 한 값이 감소하지 않는다.
      • 달리 말하면, 두 Engine Version의 Component별로 비교하면 어느 Version이 최신인지 파악할 수 있다.
    • Major, Minor, Patch Version이 같은 경우,
      Epic의 Changelist보다 이용자가 생성한 Changelist를 항상 최근 버전으로 간주한다.
    • BranchName은 호환성 검사에 사용하지 않는다.
      • 주로 외부에 표시하는 용도
  • Engine Version이 호환되지 않으면 Engine에서 Asset을 Load 할 수 없다.
    • 최신 Engine Version에서 저장된 Asset은 Contents Browser에 나타나지 않는다.
    • 해당 Asset에 Reference는 null로 취급된다.
      • 이 때 Asset을 저장하면 인지하지 못한 Reference가 오염되기 때문에 저장하지 않는 것이 좋다.
  • Changelist 0이 포함된 Engine Version은 다른 모든 Engine Version과 호환되는 것으로 간주한다.
    • Engineer 입장에서는 Engine 개발이 간편해지는 측면이 있지만, Disk에 저장하는 관점에서는 부적합하다.
    • 대신 Contents Creator는 배포된 Editor의 Binary Build를 사용해야 한다.
      • 그래야 정확한 Engine Version Data를 지닌 Asset으로 작업을 하게 된다.
      • 또한 Asset으로 인한 Data 손실을 방지할 수 있다.

Asset and Package

  • Asset은 저장에 사용한 Editor의 Engine Version 정보가 포함되어 있다.
  • Engine은 Load 시 이 값을 확인하고,
    Code 변경을 통해 Serialize 된 Data에 추가되거나 제거된 Property를 적절히 처리할 수 있다.
  • Serialize를 해제하는 중(ex. Asset을 Load 하는 경우)
    • Field를 제거하는 경우에는 해당 Field가 인식되지 않고 무시된다.
    • Field를 추가하는 경우에는 Data에서는 없어지지만, 기본값을 유지한다.
  • Asset의 Data를 Disk에 저장하기 위해 Serialize 하는 경우
    • 삭제된 Field의 Data는 바로 폐기 된다.
    • 새로 추가된 Field의 Data는 유지되어 다른 Property와 함꼐 Serialize된다.
  • 이 결과 Data 구조는 서서히 변경되며,
    해당 Data 구조의 Serialized Expression은 새 Field를 추가하는 동안 필요 없는 Field는 자연스럽게 폐기가 된다.
  • 따라서 Serialize 된 Data는 Engine Version과 무관하게 동일하거나 그 이상의 Version에서만 인식할 수 있다.
  • 이 규칙을 통해 이전 Engine Version의 Data 손실 Error를 방지할 수 있다.
    • 최근 Version의 Property를 폐기하고 Data를 다시 Disk상에 Serialize 하면서 발생함.

Programming by Engine Version

 

FEngineVersion

Utility functions.

docs.unrealengine.com

  • Unreal Game Sync를 통해 동기화되지 않은 Code-based Engine Build가 있는 경우,
    이 Build의 ChangeList를 0으로 표시하면 Version Check와 관련해 훨씬 유연한 환경을 만들 수 있다.
  • 하지만 Cooking 과정에서는 해당 Asset에서 Warning이 발생하므로 사용을 지양하는 것이 좋다.
    • 만약 이 Warning을 비활성화 하려면,
      DefaultEngine.in 파일의 [Core.System] Section에 ZeroEngineVersionWarning=0을 추가하면 된다.

Engine Version Update

  • Build의 Engine Version은 Engine 내 /Build/Build.version 파일에서 정의한 값으로 제어할 수 있다.
  • 이 파일을 직접 수정한 뒤, 다음 2가지 방법으로 Version을 Update 할 수 있다.
    • UpdateLocalVersion Commandlet 실행
    • UGC(Unreal Game Sync)로 Sychronize
  • 더보기
    {
    	"MajorVersion": 4,
    	"MinorVersion": 26,
    	"PatchVersion": 2,
    	"Changelist": 0,
    	"CompatibleChangelist": 14830424,
    	"IsLicenseeVersion": 0,
    	"IsPromotedBuild": 0,
    	"BranchName": "++UE4+Release-4.26"
    }
    • Changelist
      • 수동으로 정의
      • 수동으로 업데이트 하거나, UpdateLocalVersion Commandlet으로 Update
      • Update 시 디포 Directory Name을 사용하고 /를 +로 교체
    • CompatibleChangelist
      • 해당 Engine Version과 호환 가능한 것으로 간주할 수 있는 가장 낮은 Changelist
        • 가장 처음 만들어진 Changelist
      • Engine의 Local Build에서처럼 0으로 설정할 때도 있다.
        • 하지만 정식 출시된 Epic의 Build나 내부적으로 배포된 Build가 0이 아니므로
          Local Version과 호환되지는 않는다.
    • IsLicenseeVersion
      • Source Control에서 Synchronize 된 Local Build에 사용할 경우 0으로 지정
      • UpdateLocalVersion Commandlet을 통해 System Build를 할 경우 1
      • Promoted Build에서 사용할 때에는 1이 더 적절하다.
      • Version Check가 더 까다로워지는 대신 Hot Reload가 비활성화 된다.
    • IsPromotedBuild
      • 해당 Build가 Promoted Build인지 여부
      • 기본 값은 1
    • BuildId
      • 위 예시에는 없지만 제공되는 정보
      • Compile 할 때 Engine 및 Module에 전부 이 값을 Tag 한다.
        • Engine에서는 이 값이 없는 모든 Module은 호환 불가능한 대상으로 간주
      • 보통은 공백으로 두는 편이 좋다.
        • 공백으로 둘 경우 Compile 할 때마다 고유한 새 값이 생성된다.

UpdateLocalVersion Commandlet

  • 전용 Build Machine에서 Compile할 때처럼 Build/Build/version 파일을 수동으로 편집 할 필요가 없는 경우에 유용
  • 더보기
    RunUAT.bat UpdateLocalVersion [-CL=INT] [-CompatibleCL=INT] [-Build=STRING] [-SkipHeader] [-Licensee] [-Promoted=BOOL] [-Branch=STRING]
  • CL
    • Build.Version의 Changelist
  • CompatibleCL
    • Build.Version의 CompatibleChangelist
  • Build
    • Source Code의 BUILD_VERSION 매크로를 Update해 Engine의 Build Version String을 변경
  • SkipHeader
    • 이 Parameter가 있으면 Engine의 Header File이 Update 되지 않는다.
  • License
    • Build.version의 IsLicense
    • 이 Parameter가 있는 경우 true로 취급
  • Promoted
    • Build.version의 IsPromotedBuild
    • 0 이외의 정수를 입력하면 true로 간주하고 Field에 1이 입력
  • Branch
    • Build.Version의 BranchName

Object Version

  • UObject 파생 Class는 Engine Version 외에 Object Version Control System을 별개로 운영한다.
    • Engine Level Version
    • Object Level Version
  • Object Serialization은 다음의 용도로 사용된다.
    • 대량의 Burk Data를 포함한 Asset Performance Optimize
    • 단위 변환 시 Data Format 변경을 구현
    • Object Data를 압축된 Format의 Disk에 저장할 때 공간 절약을 위한 Customize
  • Custom Serialization을 위해서는 다음 2가지 작업이 필요하다.
    • UObject::Serialize 함수를 Override하여 Project의 필요에 따라 Data Format 변경
    • 신규 Code의 Object Version에 기반한 검사
  • Serialization이 변경 되어도 하위 호환성을 보존하면서, Engine Version과 같은 방식으로 Data 손실을 방지할 수 있다.

Serialization and Version Control of Engine Level

  • Engine Level에서는 EUnrealEngineObjectUE5Version을 사용해 Serializer Function의 Version을 관리한다.
    • Custom Serializer가 변경될 때마다 새 항목이 EUnrealEngineObjectUE5Version에 추가된다.
  • Epic Games가 Public Unreal Engine Launch Version에서 이 Type을 수정하면,
    병렬 Global EnumType인 EUnrealEngineObjectLicenseeUEVersion은 사용자가 자체적으로
    Engine Level Version 관리를 추가할 수 있다.
  • 이후 Package를 저장하면 두 Enum값이 증가한 채로 저장이 된다.
    • Serializer, Deserializer Code는 이 값으로 Data Read/Write 방식을 결정한다.
  • Engine에서는 자동으로 이 Version의 값을 자동으로 자체검사한다.
    • Engine보다 높은 Version이 있는 Package는 Load 할 수 없다.
  • 이 방식은 Engine의 여러 분야를 별개의 팀이 작업하는 곳에서는 적합하지 않다.
    • 다수의 Version에서 Enum Type을 업데이트 할 수 없다.
    • Merge 시 상수를 다시 정렬하는 동안 해당 Version Number로 저장한 Asset이 손상되거나 무효화 된다.
    • 이 경우에는 Engine Level이 아닌 Object Level의 Serialization이 더 적절하다.

Serialization and Version Control of Object Level

  • Programmer들이 동시에 각자 다른 Branch로 개발하는 경우,
    Engine이 FGuid 기반 Custom Version을 통해 Object Level Version Control을 제공해야 한다.
  • FGuid 구조에는 다른 Version과 같이 증가하는 정수형 Version Number 뿐 아니라,
    팀의 요구에 따라 동시에 다양한 Custom Version을 보유할 수 있는 GUID(Global Unique Identifier)도 제공한다.
  • System이나 Branch별로 Custom Version을 유지하면 다른 Branch의 Code와 병합할 때 Conflict가 발생하지 않는다.
  • 더보기
    const FGuid FAnimationCustomVersion::GUID(0x2EB5FDBD, 0x01AC4D10, 0x8136F38F, 0x3393A5DA); 
    
    // 코어로 커스텀 버전 등록 
    FCustomVersionRegistration GRegisterAnimationCustomVersion(FAnimationCustomVersion::GUID, FAnimationCustomVersion::LatestVersion, TEXT("AnimGraphVer"));
 

FArchive

Base class for archives that can be used for loading, saving, and garbage collecting in a byte order neutral way.

docs.unrealengine.com

  • Custom Code에서는 등록된 FGuid에 있는 Version Number를 고려해 Data의 Read/Write 방식을 결정한다.
  • 이런 식으로 등록된 FGuid와 연결된 Version Number는 절대 감소하지 않는다.
    • 이를 통해 Engine은 신규 Version의 Asset을 Load하지 않도록 할 수 있다.

Custom Serialization Function

  • Object는 Serialize를 override 하여 Disk에 있는 정밀 Data 표현을 제어할 수 있다.
    • FArchive를 이용해 Read/Write를 수행하므로 Data Format을 한번만 배치하면 된다.
  • 아래는 FArchive에서 Serialization Code에서의 Version based logic을 작성할 때 유용한 함수들이다.
  • LicenceUEVer에 대한 UEVer 호출을 변경할 경우,
    Epic의 공식 Version Number가 아니라 사용자의 Version Number를 사용하도록 코드가 변경된다.
    • 자체 Version의 Unreal Engine을 따로 관리하는 Epic 외 사용자에게 사용을 권장한다.
  • https://dev.epicgames.com/documentation/en-us/unreal-engine/API/Runtime/Core/Serialization/FArchiveState?application_version=5.2
 

F Archive State | Unreal Engine 5.4 Documentation | Epic Developer Community

 

dev.epicgames.com

 

F Archive | Unreal Engine 5.4 Documentation | Epic Developer Community

Base class for archives that can be used for loading, saving, and garbage collecting in a byte order neutral way.

dev.epicgames.com

예시

  • PhysXVehicles Plugin의 WheeledVehicle은 Engine Object Version 및 Custom Version을 모두 사용하고,
    실제 코드를 변경하기 전에 만들어진 Asset과도 하위 호환성을 유지한다.
  • 더보기
    void UWheeledVehicleMovementComponent::Serialize(FArchive& Ar)
    {
    	Super::Serialize(Ar);
    	Ar.UsingCustomVersion(FFrameworkObjectVersion::GUID);
    	if (Ar.CustomVer(FFrameworkObjectVersion::GUID) < FFrameworkObjectVersion::WheelOffsetIsFromWheel)
    	{
    		bDeprecatedSpringOffsetMode = true;
    	}
    }
    • 여기서 Custom Version은 WheelSuspension을 표현하는 Physics Spring Object에 대한
      Offset의 계산 방식 변경 변수를 설정할 때 사용된다.
    • 사용된 Version 값은 Physics Code를 관리하는 팀에서 제작한 Enum Type을 가져온다.
  • 더보기
    void FConstraintInstance::PostSerialize(const FArchive& Ar)
    {
    #if WITH_EDITORONLY_DATA
    	// ... 
    	if (Ar.IsLoading() && Ar.UEVer() < VER_UE_FIXUP_MOTOR_UNITS)
    	{
    		AngularVelocityTarget = 1.f / (2.f PI);
    	}
    	// ...
    #endif
    }
    • Angular Velocity가 RPS 대신 RPM으로 발생하는 물리적 변화에 대응해 단위 전화을 수행한다.
    • Angular Velocity는 단위가 없는 부동소수점으로 저장되므로 낮은 Version에서는 Load 중 변환이 필요하다.
      • 이 경우 Asset Load 할 때 Angular Velocity만 수정하면 된다.
    • 이 Type으로 저장되는 모든 Asset은 이미 RPM으로 저장되며,
      다음에 Load 할 때 Code를 변환할 필요가 없도록 현재 Engine Version Number로 저장한다.

Binary Version Control

 

언리얼 엔진의 바이너리 버전 관리 방법 | 언리얼 엔진 5.4 문서 | Epic Developer Community

오래된 DLL 파일로 인해 발생할 수 있는 잠재적인 오류를 완화하는 언리얼 엔진의 빌드 ID 시스템 레퍼런스입니다.

dev.epicgames.com

 

'UE5 > Architecture' 카테고리의 다른 글

[Architecture] Command-line Arguments  (0) 2024.05.07
[Architecture] Config File  (0) 2024.05.06
[Architecture] Task System  (0) 2024.05.06
[Architecture] Programming Subsystem  (0) 2024.05.06
[Architecture] String  (0) 2024.05.06

https://dev.epicgames.com/documentation/ko-kr/unreal-engine/command-line-arguments-in-unreal-engine

 

언리얼 엔진의 명령줄 실행인자 | 언리얼 엔진 5.4 문서 | Epic Developer Community

명령줄 실행인자란 엔진 실행 파일에 전달하여 시작 시 엔진 실행 방식을 커스터마이징할 수 있는 추가 실행인자입니다.

dev.epicgames.com

  • Additional Launch Parameters라고도 불린다.
  • 시작 시 Engine의 실행 방식 Customize 한다.
  • Project를 Test 및 Optimize하기에 유용한 툴
  • 이러한 Setting은 전반적인 조작부터 상세한 옵션까지 그 범위가 다양하다.
    • Unreal Editor가 Full Editor Mode가 아닌 GameMode로 실행 되도록 장제
    • 특정 맵이 게임 내에서 특정 해상도 및 Frame Rate로 실행되도록 선택

Command로 Command-line Argument 전달

  • 더보기
    <EXECUTABLE> [URL_PARAMETERS] [ARGUMENTS]
    • EXECUTABLE
      • 실행파일 이름
    • URL_PARAMETERS
      • URL 파라미터
    • ARGUMENTS
      • Command Flag 또는 Key-Value Pair
  • 더보기
    UnrealEditor.exe MyGame.uproject /Game/Maps/BonusMaps/BonusMap.umap?game=MyGameMode -game -fullscreen

Unreal Editor로 Command-line Argument 전달

  • Unreal Editor는 Command-line Argument로 Standalone Game Customize를 지원한다.
    • Editor에서 Command-line Argument는 Additional Launch Parameter라 불린다.
    • 이 옵션은 Play in Standalone Game 모드에서만 지원된다.
  • 또한 Multiplay Game Test 목적으로 Dedicated Server로만 Command-line Argument를 전달하는 작업도 지원한다.
  • Dedicated Server를 위한 Command-line Argument는 다음과 같다.
    • Server Map Name Override
      • Map Name을 URL Parameter로 전달
    • Additional Server Game Options
      • 추가 URL Parameter 전달
    • Additional Server Launch Parameters
      • URL Parameter 외의 추가 Command-line Flag, Key-Value Pair를 전달
  • Edit -> Editor Preference을 통해 커스터마이즈 가능

Game Launch Parameter

  • Edit -> Editor Preferences -> Level Editor -> Play로 이동해 Play in Standalone Game 이름의 Section 탐색
  • 이 Section의 Additional Launch Parameter를 위한 TextBox에 Command-line Argument를 입력한다.

Server Launch Parameter

  1. Edit -> Editor Preferences -> Level Editor -> Play 로 이동해 Multiplayer Options 이름의 Section 탐색
  2. Launch Separate Server 항목을 활성화하고, Run Under One Process 항목을 비활성화
    • 위 조건을 충족해야 Dedicated Server에 대한 Command-line Argument를 지정할 수 있다.
    • Run Under One Process가 비활성화 된 경우,
      각 Client가 Editor의 개별 Instance를 Spawn하기 때문에 Client의 실행 속도가 느려진다.
  3. Multiplayer Options Section에서 Server로 이동
    • 이 Section에서 3 종류의 Command-line Argument를 지정할 수 있다.
      • Server Map Name Override
      • Additional Server Game Options
      • Additional Server Launch Parameters

Shortcut으로 Command-line Argument 전달

  1. 실행 파일에 대한 Shrotcut 생성
  2. Shortcut을 우클릭하여 Properties 선택
  3. Properties의 Shortcut 이름의 Section에서 Target 이름의 Field  끝에 Command-line Arrgument 추가
  4. 이후 해당 Shortcut을 실행할 경우, 원본 실행 파일로 Command-line Argument가 전달된다.

Custom Command-line Argument 생성

  • Comamnd-line에 원하는 Flag나 Key-Value Pair를 전달하여 자신만의 Argument를 생성할 수 있다.
    • 이를 위해서는 Code 내 Command-line에서 해당 Argument를 읽어야만 한다.
    • Project Code가 Custom Command-line Argument를 읽지 않고 파싱하는 경우,
      해당 Argument는 무시된다.

Flag

  • 더보기
    UnrealEditor.exe MyGame.uproject -game
    • 위 예시에서 -game가 Flag이다.
    • -game은 대상을 Game Mode로 실행하고 싶다는 의미이다.

Flag Parsing

  • 더보기
    UnrealEditor.exe MyGame.uproject -myflag

     

    bool bMyFlag = false;
    if (FParse::Param(FCommandLine::Get(), TEXT("myflag")))
    {
    	bMyFlag = true;
    }

Key-Value Pair

  • 더보기
    UnrealEditor.exe MyGame.uproject -game -windowed -ResX=1080 -ResY=1920
    • Key-Value Pair는 특정 값을 지정하는 Setting Switch이다.
      • Switch에는 현재 상태 뿐 아니라 setting도 동반되어야 한다.

Key-Value Pari Parsing

  • 더보기
    UnrealEditor.exe MyGame.uproject -mykey=42

     

    int32 myKeyValue;
    if (FParse::Value(FCommandLine::Get(), TEXT("mykey="), myKeyValue))
    {
    	// 프로그램이 이 'if' 명령문을 입력하는 경우 mykey가 명령줄에 존재했던 것입니다
    	// myKeyValue는 이제 명령줄을 통해 전달된 값을 포함합니다
    }
  • Engine/Source/Runtime/Core/Public/Misc/CommandLine.h에서
    Command-line과 상호작용 할 수 있는 함수들에 대한 더 자세한 정보를 확인할 수 있다.

Command-line Argument Reference

URL Parameter

  • URL Parameter는 Game이 시작될 때 특정 Map을 로드하도록 강제한다.
  • 비록 선택사항이지만, 제공될 경우에는 실행 파일 이름을 따르거나 존재하는 모든 Flag를 따른다.

Map Name

  • Map Directory 내에 위치한다면 어떤 Map Name이든 표현 가능
  • 선택적으로 .umap 확장자를 포함할 수 있음
  • Map Directory 경로 내에 없는 Map을  다음 두가지 조건을 만족해야 한다.
    • 절대 경로를 사용 혹은 Map Driectory 기준의 상대 경로 사용.
    • Map 뒤에 반드시 .umpa 파일 확장자 요구

Server IP Address

  • Server IP Address를 URL Parameter로 사용해 Game Client를 Dedicated Server에 연결 할 수 있다.

Additional Parameter

  • Map Name 혹은 Server IP Address에 덧붙이는 방식으로 Additional Parameter 지정 가능
  • 각 옵션은 ?로 시작하고 =로 값이 설정된다.
  • 옵션 앞에 -를 붙이면 캐시된 URL Option에서 해당 Option이 제거된다.

Example

  • Map Directory에 위치한 Map으로 게임 열기
  • Map Directory 외부에 위치한 Map으로 게임 열기
    • 더보기
      MyGame.exe /Game/Maps/BonusMaps/BonusMap.umap
  • Map Directory 외부에 위치한 맵으로 Unreal Editor에서 Game 열기
    • 더보기
      UnrealEditor.exe MyGame.uproject /Game/Maps/BonusMaps/BonusMap.umap?game=MyGameMode -game
  • Game Client를 Dedicated Server에 연결
    • 더보기
      UnrealEditor.exe MyGame.uproject /Game/Maps/BonusMaps/BonusMap.umap -server -port=7777 -log
      UnrealEditor.exe MyGame.uproject 127.0.0.1:7777 -game -log

Flag and Key-Value Reference

Read Command-line Argument from File

  • 다음 상황에서 매우 유용함
    • 매우 많은 수의 Command-line Argument를 사용하는 경우
    • 동일한 Argument들을 자주 재사용하는 경우
    • Windows Command line 길이 제한에 걸리는 경우
  • 더보기
    <EXECUTABLE> -CmdLineFile=ABSOLUTE\PATH\TO\FILE.txt

유용한 Command-line Argument

  • Common
  • Rendering 및 GPU
  • CPU 및 Memory
  • Debugging

'UE5 > Architecture' 카테고리의 다른 글

[Architecture] Version Control of Asset and Package  (0) 2024.05.07
[Architecture] Config File  (0) 2024.05.06
[Architecture] Task System  (0) 2024.05.06
[Architecture] Programming Subsystem  (0) 2024.05.06
[Architecture] String  (0) 2024.05.06

+ Recent posts