285 lines
9.5 KiB
C++
285 lines
9.5 KiB
C++
// Copyright 2025 https://yuewu.dev/en All Rights Reserved.
|
|
|
|
|
|
#include "Utilities/GGA_GameplayEffectFunctionLibrary.h"
|
|
#include "GameplayEffect.h"
|
|
#include "Blueprint/BlueprintExceptionInfo.h"
|
|
#include "UObject/EnumProperty.h"
|
|
#include "GGA_GameplayEffectContext.h"
|
|
#include "GGA_LogChannels.h"
|
|
|
|
#define LOCTEXT_NAMESPACE "UGGA_GameplayEffectFunctionLibrary"
|
|
|
|
// UGameplayEffect* UGGA_GameplayEffectFunctionLibrary::MakeRuntimeGameplayEffect(FString UniqueName, EGameplayEffectDurationType DurationPolicy, TArray<FGameplayModifierInfo> AttributeModifiers)
|
|
// {
|
|
// UGameplayEffect* GameplayEffect = NewObject<UGameplayEffect>(GetTransientPackage(), FName("RuntimeGE_" + GetNameSafe(this) + UniqueName));
|
|
// GameplayEffect->DurationPolicy = DurationPolicy;
|
|
// GameplayEffect->Modifiers = AttributeModifiers;
|
|
// return GameplayEffect;
|
|
// }
|
|
|
|
float UGGA_GameplayEffectFunctionLibrary::GetSetByCallerMagnitudeByTag(FGameplayEffectSpecHandle SpecHandle, FGameplayTag DataTag, bool WarnIfNotFound, float DefaultIfNotFound)
|
|
{
|
|
FGameplayEffectSpec* Spec = SpecHandle.Data.Get();
|
|
if (Spec)
|
|
{
|
|
return Spec->GetSetByCallerMagnitude(DataTag, WarnIfNotFound, DefaultIfNotFound);
|
|
}
|
|
return 0.0f;
|
|
}
|
|
|
|
float UGGA_GameplayEffectFunctionLibrary::GetSetByCallerMagnitudeByTagFromSpec(const FGameplayEffectSpec& EffectSpec, FGameplayTag DataTag, bool WarnIfNotFound, float DefaultIfNotFound)
|
|
{
|
|
return EffectSpec.GetSetByCallerMagnitude(DataTag, WarnIfNotFound, DefaultIfNotFound);
|
|
}
|
|
|
|
float UGGA_GameplayEffectFunctionLibrary::GetSetByCallerMagnitudeByName(FGameplayEffectSpecHandle SpecHandle, FName DataName)
|
|
{
|
|
FGameplayEffectSpec* Spec = SpecHandle.Data.Get();
|
|
if (Spec)
|
|
{
|
|
return Spec->GetSetByCallerMagnitude(DataName, false);
|
|
}
|
|
|
|
return 0.0f;
|
|
}
|
|
|
|
bool UGGA_GameplayEffectFunctionLibrary::IsActiveGameplayEffectHandleValid(FActiveGameplayEffectHandle Handle)
|
|
{
|
|
return Handle.IsValid();
|
|
}
|
|
|
|
void UGGA_GameplayEffectFunctionLibrary::GetOwnedGameplayTags(FGameplayEffectContextHandle EffectContext, FGameplayTagContainer& ActorTagContainer, FGameplayTagContainer& SpecTagContainer)
|
|
{
|
|
return EffectContext.GetOwnedGameplayTags(ActorTagContainer, SpecTagContainer);
|
|
}
|
|
|
|
void UGGA_GameplayEffectFunctionLibrary::AddInstigator(FGameplayEffectContextHandle EffectContext, AActor* InInstigator, AActor* InEffectCauser)
|
|
{
|
|
EffectContext.AddInstigator(InInstigator, InEffectCauser);
|
|
}
|
|
|
|
void UGGA_GameplayEffectFunctionLibrary::SetEffectCauser(FGameplayEffectContextHandle EffectContext, AActor* InEffectCauser)
|
|
{
|
|
EffectContext.AddInstigator(EffectContext.GetInstigator(), InEffectCauser);
|
|
}
|
|
|
|
void UGGA_GameplayEffectFunctionLibrary::SetAbility(FGameplayEffectContextHandle EffectContext, const UGameplayAbility* InGameplayAbility)
|
|
{
|
|
EffectContext.SetAbility(InGameplayAbility);
|
|
}
|
|
|
|
const UGameplayAbility* UGGA_GameplayEffectFunctionLibrary::GetAbilityCDO(FGameplayEffectContextHandle EffectContext)
|
|
{
|
|
return EffectContext.GetAbility();
|
|
}
|
|
|
|
const UGameplayAbility* UGGA_GameplayEffectFunctionLibrary::GetAbilityInstance(FGameplayEffectContextHandle EffectContext)
|
|
{
|
|
return EffectContext.GetAbilityInstance_NotReplicated();
|
|
}
|
|
|
|
int32 UGGA_GameplayEffectFunctionLibrary::GetAbilityLevel(FGameplayEffectContextHandle EffectContext)
|
|
{
|
|
return EffectContext.GetAbilityLevel();
|
|
}
|
|
|
|
void UGGA_GameplayEffectFunctionLibrary::AddSourceObject(FGameplayEffectContextHandle EffectContext, const UObject* NewSourceObject)
|
|
{
|
|
if (NewSourceObject)
|
|
{
|
|
EffectContext.AddSourceObject(NewSourceObject);
|
|
}
|
|
}
|
|
|
|
bool UGGA_GameplayEffectFunctionLibrary::HasOrigin(FGameplayEffectContextHandle EffectContext)
|
|
{
|
|
return EffectContext.HasOrigin();
|
|
}
|
|
|
|
FGGA_GameplayEffectContext* UGGA_GameplayEffectFunctionLibrary::GetEffectContextPtr(FGameplayEffectContextHandle EffectContext)
|
|
{
|
|
if (!EffectContext.IsValid())
|
|
{
|
|
GGA_LOG(Warning, "Try access invalid effect context!")
|
|
return nullptr;
|
|
}
|
|
if (!EffectContext.Get()->GetScriptStruct()->IsChildOf(FGGA_GameplayEffectContext::StaticStruct()))
|
|
{
|
|
GGA_LOG(Warning, "The GameplayEffectContext type is not FGGA_GameplayEffectContext! "
|
|
"Make sure you are setting AbilitySystemGlobalsClassName as GGA_AbilitySystemGlobals in Gameplay Abilities Settings Under Project Settings! ")
|
|
return nullptr;
|
|
}
|
|
return static_cast<FGGA_GameplayEffectContext*>(EffectContext.Get());
|
|
}
|
|
|
|
UAbilitySystemComponent* UGGA_GameplayEffectFunctionLibrary::GetInstigatorAbilitySystemComponent(FGameplayEffectContextHandle EffectContext)
|
|
{
|
|
return EffectContext.GetInstigatorAbilitySystemComponent();
|
|
}
|
|
|
|
UAbilitySystemComponent* UGGA_GameplayEffectFunctionLibrary::GetOriginalInstigatorAbilitySystemComponent(FGameplayEffectContextHandle EffectContext)
|
|
{
|
|
return EffectContext.GetOriginalInstigatorAbilitySystemComponent();
|
|
}
|
|
|
|
bool UGGA_GameplayEffectFunctionLibrary::HasContextPayload(FGameplayEffectContextHandle EffectContext, const UScriptStruct* PayloadType)
|
|
{
|
|
if (const FGGA_GameplayEffectContext* Context = GetEffectContextPtr(EffectContext))
|
|
{
|
|
return Context->FindPayloadByType(PayloadType) != nullptr;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool UGGA_GameplayEffectFunctionLibrary::GetContextPayload(FGameplayEffectContextHandle EffectContext, const UScriptStruct* PayloadType, FInstancedStruct& OutPayload)
|
|
{
|
|
if (FGGA_GameplayEffectContext* Context = GetEffectContextPtr(EffectContext))
|
|
{
|
|
if (FInstancedStruct* Found = Context->FindPayloadByType(PayloadType))
|
|
{
|
|
OutPayload = *Found;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
FInstancedStruct UGGA_GameplayEffectFunctionLibrary::GetValidContextPayload(FGameplayEffectContextHandle EffectContext, const UScriptStruct* PayloadType, bool& bValid)
|
|
{
|
|
bValid = false;
|
|
if (FGGA_GameplayEffectContext* Context = GetEffectContextPtr(EffectContext))
|
|
{
|
|
if (FInstancedStruct* Found = Context->FindPayloadByType(PayloadType))
|
|
{
|
|
bValid = true;
|
|
return *Found;
|
|
}
|
|
}
|
|
return FInstancedStruct();
|
|
}
|
|
|
|
void UGGA_GameplayEffectFunctionLibrary::GetContextPayload(FGameplayEffectContextHandle EffectContext, const UScriptStruct* PayloadType, EGGA_ContextPayloadResult& ExecResult, int32& Value)
|
|
{
|
|
// We should never hit this! stubs to avoid NoExport on the class.
|
|
checkNoEntry();
|
|
}
|
|
|
|
DEFINE_FUNCTION(UGGA_GameplayEffectFunctionLibrary::execGetContextPayload)
|
|
{
|
|
P_GET_STRUCT_REF(FGameplayEffectContextHandle, EffectContext);
|
|
P_GET_OBJECT(const UScriptStruct, PayloadType);
|
|
P_GET_ENUM_REF(EGGA_ContextPayloadResult, ExecResult);
|
|
|
|
// Read wildcard Value input
|
|
Stack.MostRecentPropertyAddress = nullptr;
|
|
Stack.MostRecentPropertyContainer = nullptr;
|
|
Stack.StepCompiledIn<FStructProperty>(nullptr);
|
|
|
|
const FStructProperty* ValueProp = CastField<FStructProperty>(Stack.MostRecentProperty);
|
|
void* ValuePtr = Stack.MostRecentPropertyAddress;
|
|
|
|
P_FINISH;
|
|
|
|
P_NATIVE_BEGIN;
|
|
|
|
ExecResult = EGGA_ContextPayloadResult::NotValid;
|
|
|
|
if (!ValueProp || !ValuePtr || !PayloadType)
|
|
{
|
|
FBlueprintExceptionInfo ExceptionInfo(
|
|
EBlueprintExceptionType::AbortExecution,
|
|
LOCTEXT("InstancedStruct_GetInvalidValueWarning", "Failed to resolve the Value or PayloadType for Get Context Payload")
|
|
);
|
|
FBlueprintCoreDelegates::ThrowScriptException(P_THIS, Stack, ExceptionInfo);
|
|
}
|
|
else
|
|
{
|
|
FInstancedStruct OutPayload;
|
|
if (GetContextPayload(EffectContext, PayloadType, OutPayload))
|
|
{
|
|
if (OutPayload.IsValid() && OutPayload.GetScriptStruct()->IsChildOf(ValueProp->Struct))
|
|
{
|
|
// Copy the struct data to the output Value
|
|
ValueProp->Struct->CopyScriptStruct(ValuePtr, OutPayload.GetMemory());
|
|
ExecResult = EGGA_ContextPayloadResult::Valid;
|
|
}
|
|
else
|
|
{
|
|
ExecResult = EGGA_ContextPayloadResult::NotValid;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ExecResult = EGGA_ContextPayloadResult::NotValid;
|
|
}
|
|
}
|
|
|
|
P_NATIVE_END;
|
|
}
|
|
|
|
|
|
void UGGA_GameplayEffectFunctionLibrary::SetContextPayload(FGameplayEffectContextHandle EffectContext, EGGA_ContextPayloadResult& ExecResult, const int32& Value)
|
|
{
|
|
// We should never hit this! stubs to avoid NoExport on the class.
|
|
checkNoEntry();
|
|
}
|
|
|
|
DEFINE_FUNCTION(UGGA_GameplayEffectFunctionLibrary::execSetContextPayload)
|
|
{
|
|
P_GET_STRUCT_REF(FGameplayEffectContextHandle, EffectContext);
|
|
P_GET_ENUM_REF(EGGA_ContextPayloadResult, ExecResult);
|
|
|
|
// Read wildcard Value input
|
|
Stack.MostRecentPropertyAddress = nullptr;
|
|
Stack.MostRecentPropertyContainer = nullptr;
|
|
Stack.StepCompiledIn<FStructProperty>(nullptr);
|
|
|
|
const FStructProperty* ValueProp = CastField<FStructProperty>(Stack.MostRecentProperty);
|
|
const void* ValuePtr = Stack.MostRecentPropertyAddress;
|
|
|
|
P_FINISH;
|
|
|
|
P_NATIVE_BEGIN;
|
|
|
|
ExecResult = EGGA_ContextPayloadResult::NotValid;
|
|
|
|
if (!ValueProp || !ValuePtr || !EffectContext.IsValid())
|
|
{
|
|
FBlueprintExceptionInfo ExceptionInfo(
|
|
EBlueprintExceptionType::AbortExecution,
|
|
LOCTEXT("InstancedStruct_SetInvalidValueWarning", "Failed to resolve Value or EffectContext for Set Instanced Struct Value")
|
|
);
|
|
FBlueprintCoreDelegates::ThrowScriptException(P_THIS, Stack, ExceptionInfo);
|
|
}
|
|
else
|
|
{
|
|
// Create an FInstancedStruct from the input struct
|
|
FInstancedStruct Payload;
|
|
Payload.InitializeAs(ValueProp->Struct, static_cast<const uint8*>(ValuePtr));
|
|
|
|
if (Payload.IsValid())
|
|
{
|
|
// Call the existing SetPayload function
|
|
if (FGGA_GameplayEffectContext* ContextPtr = GetEffectContextPtr(EffectContext))
|
|
{
|
|
ContextPtr->AddOrOverwriteData(Payload);
|
|
ExecResult = EGGA_ContextPayloadResult::Valid;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FBlueprintExceptionInfo ExceptionInfo(
|
|
EBlueprintExceptionType::AbortExecution,
|
|
LOCTEXT("SetGameplayEffectContextPayload", "Failed to create valid InstancedStruct from Value")
|
|
);
|
|
FBlueprintCoreDelegates::ThrowScriptException(P_THIS, Stack, ExceptionInfo);
|
|
}
|
|
}
|
|
|
|
P_NATIVE_END;
|
|
}
|
|
|
|
#undef LOCTEXT_NAMESPACE
|