// 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 AttributeModifiers) // { // UGameplayEffect* GameplayEffect = NewObject(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(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(nullptr); const FStructProperty* ValueProp = CastField(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(nullptr); const FStructProperty* ValueProp = CastField(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(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