위 2개를 모방해서 커스텀타입을 만들거임.
일단 치명타, 블락 getter, setter만 만들어줌
#pragma once // 헤더2번포함방지
#include "GameplayEffectTypes.h"
#include "AuraAbilityTypes.generated.h" //generated_body 사용위해 필요
USTRUCT(BlueprintType)
struct FAuraGameplayEffectContext : public FGameplayEffectContext
{
GENERATED_BODY()
public:
//@Getter
bool IsCriticalHit() const {return bIsCriticalHit ; }
bool IsBlockHit() const { return bIsBlockedHit ; }
//@Setter
void SetIsCriticalHit(bool bInIsCriticalHit) {bIsCriticalHit = bInIsCriticalHit ; }
void SetIsBlockHit(bool bInIsBlockHit) {bIsBlockedHit = bInIsBlockHit ; }
/** Returns the actual struct used for serialization, subclasses must override this! */
virtual UScriptStruct* GetScriptStruct() const
{
return FGameplayEffectContext::StaticStruct();
}
/** Custom serialization, subclasses must override this */
virtual bool NetSerialize(FArchive& Ar, class UPackageMap* Map, bool& bOutSuccess);
protected:
UPROPERTY()
bool bIsBlockedHit = false;
UPROPERTY()
bool bIsCriticalHit = false;
};
* 직렬화 함수 모방(EffectContext) + 커스텀 속성추가
1. 0 0 0 0 0 0 0 0
해당 비트는 속성의 역할을한다.
2. 속성이 유효한지 확인하고, 속성의 비트를 켠다.
+ 속성추가시 다음 비트를 켜면된다.
bool FAuraGameplayEffectContext::NetSerialize(FArchive& Ar, UPackageMap* Map, bool& bOutSuccess)
{
uint8 RepBits=0;
if (Ar.IsSaving())
{
if (Instigator.IsValid() )
{
RepBits |= 1 << 0; //비트켜기
}
if (EffectCauser.IsValid() )
{
RepBits |= 1 << 1;
}
if (AbilityCDO.IsValid())
{
RepBits |= 1 << 2;
}
if (bReplicateSourceObject && SourceObject.IsValid())
{
RepBits |= 1 << 3;
}
if (Actors.Num() > 0)
{
RepBits |= 1 << 4;
}
if (HitResult.IsValid())
{
RepBits |= 1 << 5;
}
if (bHasWorldOrigin)
{
RepBits |= 1 << 6;
}
if(bIsBlockedHit) //2개 추가
{
RepBits |= 1<<7;
}
if(bIsCriticalHit)
{
RepBits |= 1<<8;
}
}
3. 직렬화후, 해당비트가 켜져있는지 확인후,
Ar을 역직렬화 한다.
Ar.SerializeBits(&RepBits, 9);
if (RepBits & (1 << 0)) //해당 비트가 켜진경우
{
Ar << Instigator;
}
if (RepBits & (1 << 1))
{
Ar << EffectCauser;
}
if (RepBits & (1 << 2))
{
Ar << AbilityCDO;
}
if (RepBits & (1 << 3))
{
Ar << SourceObject;
}
if (RepBits & (1 << 4))
{
SafeNetSerializeTArray_Default<31>(Ar, Actors);
}
if (RepBits & (1 << 5))
{
if (Ar.IsLoading())
{
if (!HitResult.IsValid())
{
HitResult = TSharedPtr<FHitResult>(new FHitResult());
}
}
HitResult->NetSerialize(Ar, Map, bOutSuccess);
}
if (RepBits & (1 << 6))
{
Ar << WorldOrigin;
bHasWorldOrigin = true;
}
else
{
bHasWorldOrigin = false;
}
if(RepBits & (1<<7)) //2개 추가
{
Ar << bIsBlockedHit;
}
if(RepBits & (1<<8)) //2개 추가
{
Ar << bIsCriticalHit;
}
if (Ar.IsLoading())
{
AddInstigator(Instigator.Get(), EffectCauser.Get()); // Just to initialize InstigatorAbilitySystemComponent
}
* 함수추가
/** Returns the actual struct used for serialization, subclasses must override this! */
virtual UScriptStruct* GetScriptStruct() const
{
return StaticStruct();
}
/** Creates a copy of this context, used to duplicate for later modifications */
virtual FGameplayEffectContext* Duplicate() const
{
FGameplayEffectContext* NewContext = new FGameplayEffectContext();
*NewContext = *this;
if (GetHitResult())
{
// Does a deep copy of the hit result
NewContext->AddHitResult(*GetHitResult(), true);
}
return NewContext;
}
//구조체 연산유형
template<>
struct TStructOpsTypeTraits<FAuraGameplayEffectContext> : public TStructOpsTypeTraitsBase2<FAuraGameplayEffectContext>
{
enum
{
WithNetSerializer = true,
WithCopy = true
};
};
* 문제 : 프로젝트에서 커스텀 EffectContext를 사용하도록 설정해야함.
1. 커스텀 글로벌을 만듬 && 내가만든 EffectContext의 인스턴스를 리턴.
FGameplayEffectContext* UAuraAbilitySystemGlobals::AllocGameplayEffectContext() const
{
//내가만든 EffectContext의 새로운 인스턴스 리턴.
return new FAuraGameplayEffectContext();
}
2. DefaultGame.ini에서 Global클래스를 내가만든 글로벌로 설정.
[/Script/GameplayAbilities.AbilitySystemGlobals]
+AbilitySystemGlobalsClassName="/Script/Aura.AuraAbilitySystemGlobals"
3. 결과확인 : 불덩이발사후, EffectContextHandle에 내가 추가한 속성2개가 들어간것을 확인할수 있음.
* next : 추가한 변수이용 = > 치명타시 노란색글씨로 바꿀거임
1. 먼저 getter를 만들어야함,
Exec_Calc.cpp 에서
set하기
Context핸들 얻어옴 -> 캐스팅 -> setter 사용
FGameplayEffectContextHandle EffectContextHandle = Spec.GetContext();
FGameplayEffectContext* Context = EffectContextHandle.Get(); //ptr 반환
FAuraGameplayEffectContext* AuraContext = static_cast<FAuraGameplayEffectContext*>(Context); //내가만든 setter 쓸려면 캐스트 필요
AuraContext->SetIsBlockHit(bBlocked);
2. AuraAbilitySystremLibrary에서 BP용 getter 만들기. (선호됨)
//Getter의 경우 BP PURE 로 만드는게 국룰임.
UFUNCTION(BlueprintPure, Category="AuraAbilitySystemLibrary|GameplayEffects")
bool UAuraAbilitySystemLibrary::IsBlockedHit(const FGameplayEffectContextHandle& EffectContextHandle)
{
if(const FAuraGameplayEffectContext* AuraEffectContext = static_cast<const FAuraGameplayEffectContext*>(EffectContextHandle.Get()))
{
return AuraEffectContext->IsBlockHit();
}
return false;
}
3. BP용 setter 만들기.
//Setter는 BP PURE로 하면 안됨.
UFUNCTION(BlueprintCallable, Category="AuraAbilitySystemLibrary|GameplayEffects")
static void SetIsBlockedHit(FGameplayEffectContextHandle& EffectContextHandle, bool bInIsBlockedHit);
Context의 내용을 바꿔야함 -> ~const
void UAuraAbilitySystemLibrary::SetIsBlockedHit(FGameplayEffectContextHandle& EffectContextHandle, bool bInIsBlockedHit)
{
if(FAuraGameplayEffectContext* AuraEffectContext = static_cast<FAuraGameplayEffectContext*>(EffectContextHandle.Get()))
{
AuraEffectContext->SetIsBlockHit(bInIsBlockedHit);
}
}
* 문제 : Effect Context Handle이 Input 이여야함.
원인 : 언리얼엔진은 ~const 변수는 출력으로 간주함.
해결 : 매개변수앞에 UPARAM(ref) => 입력임을 명시.
//Setter는 BP PURE로 하면 안됨.
UFUNCTION(BlueprintCallable, Category="AuraAbilitySystemLibrary|GameplayEffects")
static void SetIsBlockedHit(UPARAM(ref) FGameplayEffectContextHandle& EffectContextHandle, bool bInIsBlockedHit);
* refactor :
//개선후
UAuraAbilitySystemLibrary::SetIsBlockedHit(EffectContextHandle, bBlocked);
//전
FGameplayEffectContext* Context = EffectContextHandle.Get(); //ptr 반환
FAuraGameplayEffectContext* AuraContext = static_cast<FAuraGameplayEffectContext*>(Context); //내가만든 setter 쓸려면 캐스트 필요
AuraContext->SetIsBlockHit(bBlocked);
* AS에서도 매개변수 추가(블록, 크리티컬)
void ShowFloatingText(const FEffectProperties& Props, float Damage, bool bBlockedHit, bool bCriticalHit) const;
void UAuraAttributeSet::PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data)
{
...
const bool bBlock = UAuraAbilitySystemLibrary::IsBlockedHit(Props.EffectContextHandle);
const bool bCriticalHit = UAuraAbilitySystemLibrary::IsCriticalHit(Props.EffectContextHandle);
ShowFloatingText(Props,LocalIncomingDamage,bBlock,bCriticalHit);
}
}
}
void UAuraAttributeSet::ShowFloatingText(const FEffectProperties& Props, float Damage, bool bBlockedHit, bool bCriticalHit) const
{
'UE5 > Advance Damage Techniques' 카테고리의 다른 글
[UE5] 방마저 속성추가 / 리플리케이션 / 속성위젯에 속성추가 (0) | 2024.08.18 |
---|---|
[UE5] 데미지 유형들 추가, 확장성 refactor (0) | 2024.08.15 |
[UE5] 크리시 글자 애니메이션 구현, 메시지 구현, 인스턴싱 정책 (0) | 2024.08.14 |
[UE5] 크리티컬시, 노란글씨로 구현 (0) | 2024.08.14 |
[UE5] Custom GE Context (0) | 2024.08.14 |