{"id":119,"date":"2023-03-03T02:20:29","date_gmt":"2023-03-03T02:20:29","guid":{"rendered":"https:\/\/www.thegames.dev\/?p=119"},"modified":"2023-03-03T15:39:51","modified_gmt":"2023-03-03T15:39:51","slug":"understanding-gameplay-effect-execution-calculations","status":"publish","type":"post","link":"https:\/\/www.thegames.dev\/?p=119","title":{"rendered":"Understanding Gameplay Effect Execution Calculations!"},"content":{"rendered":"\n<p>Gameplay Effect Execution Calculation is a way to manipulate attributes base value. They are not stateful and can not be predicted (any attribute mutated this way is done so on it&#8217;s base value). But they are super powerful!<br>Below I will explain some of the stuff about Gameplay Effect Execution Calculations and how to do general calculations. This is not exhaustive, but should help you understand things.<\/p>\n\n\n\n<p>The main function you override is <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">virtual void Execute_Implementation(const FGameplayEffectCustomExecutionParameters&amp; ExecutionParams, FGameplayEffectCustomExecutionOutput&amp; OutExecutionOutput) const override;<\/pre>\n\n\n\n<p>This has two parameters, ExecutionParams which contains all the incoming data and OutExecutionOutput which will contain all outputs from the calculation.<\/p>\n\n\n\n<p>We will focus first on ExecutionParams. It has a few functions we can use to get info about the applied effect, its target and source ability system component, etc. I will list them below with a bit of info:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><strong>GetOwningSpec <\/strong>- Returns the owning spec of the effect that is running this execution.\n<strong>GetTargetAbilitySystemComponent<\/strong> - Return the ability system component of the owner being affected by this Effect.\n<strong>GetSourceAbilitySystemComponent <\/strong>- Returns the ability system component of the owner who created this Effect.\n<strong>GetPassedInTags <\/strong>- Returns all tags passed into this execution calculation (will discuss this more later.)\n<strong>GetPredictionKey <\/strong>- Returns the prediction key associated with the Effect,.\n\nThese are the basic getters for Information, now we have some calculation specific functions. These will require some additional information so will be discussed per block with an example.<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"block-75dab2a5-d4c9-4202-b090-28b8be504fae\">AttemptCalculateCapturedAttributeMagnitude<\/h3>\n\n\n\n<p>This will attempt to calculate a magnitude value for a specific attribute, you pass in the required attribute definition, the evaluation parameters, and it will calculate an output magnitude. Example here:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: Relevant Code:; notranslate\" title=\"Relevant Code:\">\nfloat DamageResistance = 0.0f;\nExecutionParams.AttemptCalculateCapturedAttributeMagnitude(KaosDamageStatics().DamageResistanceDef, EvaluateParameters, DamageResistance);\n<\/pre><\/div>\n\n\n<p>The way this works is, it will grab the value from the attribute set, go through Effects and see if anything will change the DamageResistance, and spit it out to the DamageResistance float. This is now the total DamageResistance the actor has for example. It will return true or false if the attribute was captured successfully. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">AttemptCalculateCapturedAttributeMagnitudeWithBase<\/h3>\n\n\n\n<p>This one is an extension to the above, except you can pass in a base value to start with. Functionality is the same as above.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: Relevant Code:; notranslate\" title=\"Relevant Code:\">\nfloat CriticalZoneMultiplier = 1.f;\nExecutionParams.AttemptCalculateCapturedAttributeMagnitudeWithBase(KaosDamageStatics().CritDamageZoneMultiplierDef, EvaluateParameters, DamageStats-&gt;Multiplier_DamageZone_Critical, CriticalZoneMultiplier);\n<\/pre><\/div>\n\n\n<p>As you can see here, we pass in the same details as previous one, but with the Addition of a new float, DamageStats-&gt;Multiplier_DamageZone_Critical. This serves as the base value for the calculation and is added in addition to the attributes base value and the channels value. For example you may pass in a base of 30, and the evaluator finds some modifiers for that attribute, it will use the base of 30 for the calculation. You might have a GE which gives 1.5 multiplier to the CriticalZoneMultiplier, your returned value would then be 45.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Source and Target Tags<\/h3>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: Relevant Code:; notranslate\" title=\"Relevant Code:\">\n\t\/\/Grab the tags from source and target\n\tconst FGameplayTagContainer* SourceTags = Spec.CapturedSourceTags.GetAggregatedTags();\n\tconst FGameplayTagContainer* TargetTags = Spec.CapturedTargetTags.GetAggregatedTags();\n\n\t\/\/Setup our evaluate params\n\tFAggregatorEvaluateParameters EvaluateParameters;\n\tEvaluateParameters.SourceTags = SourceTags;\n\tEvaluateParameters.TargetTags = TargetTags;\n<\/pre><\/div>\n\n\n<p>The above grabs the tags from the source and the target, and stores them in a special struct we can pass along to our evaluators, this allows the system to determine what GE&#8217;s should be relevant for calculation. For example you might have a GE which has an attribute modifier that requires the tag &#8220;Damage.Type.Fire&#8221; on the source, if so it will use this modifier in the calculation, but any GE with say ignore &#8220;Damage.Type.Fire&#8221;, will not be used in the calculation by the aggregator.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Output Modifiers<\/h3>\n\n\n\n<p>When you have calculated your value, you will need to return the attribute to modified (if any), this is done with <\/p>\n\n\n\n<pre id=\"block-d49e80b5-0d32-4b2f-b680-4490dfe8b4d4\" class=\"wp-block-preformatted\"><strong>OutExecutionOutput.AddOutputModifier<\/strong><\/pre>\n\n\n\n<p>An example for a damage execution is shown here<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: Relevant Code:; notranslate\" title=\"Relevant Code:\">\n\tif (DamageDone &gt; 0.0f)\n\t{\nOutExecutionOutput.AddOutputModifier(FGameplayModifierEvaluatedData(UAresHealthSet::GetDamageAttribute(), EGameplayModOp::Additive, DamageDone));\n\t}\n<\/pre><\/div>\n\n\n<p>This is pretty straightforward, we simply set an Attribute to the DamageDone value, and mark it as Additive. This will then get passed to the AttributeSet for processing and adjusting the attribute.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">MarkConditionalGameplayEffectsToTrigger<\/h3>\n\n\n\n<p>When you have done your calculation, you might want to go an trigger any conditional gameplay effects, but only if the calculation was successful, you do this with<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: Relevant Code:; notranslate\" title=\"Relevant Code:\">\nOutExecutionOutput.MarkConditionalGameplayEffectsToTrigger();\n<\/pre><\/div>\n\n\n<h3 class=\"wp-block-heading\">MarkStackCountHandledManually<\/h3>\n\n\n\n<p>If you have handled the GE&#8217;s stacking manually, you can tell the spec this, i have not found use for this yet, but the comment says <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><em>Mark that the execution has manually handled the stack count and the GE system should not attempt to automatically act upon it for emitted modifiers<\/em><\/pre>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: Relevant Code:; notranslate\" title=\"Relevant Code:\">\nOutExecutionOutput.MarkStackCountHandledManually();\n\n<\/pre><\/div>\n\n\n<h3 class=\"wp-block-heading\">MarkGameplayCuesHandledManually<\/h3>\n\n\n\n<p>If you played the Gameplay Cues in the execution or via some other mechanism, you can disable the GE from firing its cues after the calculation<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: Relevant Code:; notranslate\" title=\"Relevant Code:\">\nOutExecutionOutput.MarkGameplayCuesHandledManually();\n\n<\/pre><\/div>\n\n\n<h1 class=\"wp-block-heading\">Simple Damage Calculation<\/h1>\n\n\n\n<p>Utilizing some of the stuff above, this is a very simple Damage Execution Calculation, which get the Damage value from the ability providing the Damage (or via a SetByCaller damage value)<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: Relevant Code:; notranslate\" title=\"Relevant Code:\">\n\/*\n * Struct to hold our attributes we want to access\n*\/\nstruct FAresDamageStatics\n{\n\t\/*\n     * Source ASC Attributes\n    *\/\n    \/\/ Base Damage for the Actor\/Character\/Player\n\tFGameplayEffectAttributeCaptureDefinition OutgoingBaseDamageDef;\n\n    \/\/ Outgoing Ability Damage for the actor (can be SetByCaller or defined in the GE)\n\tFGameplayEffectAttributeCaptureDefinition OutgoingAbilityDamageDef;\n\n\t\/*\n     * Target ASC Attributes\n    *\/\n    \/\/ Damage attribute we set on the target which will be used to adjust its health attribute.\n\tFGameplayEffectAttributeCaptureDefinition DamageDef;\n\n\tFAresDamageStatics()\n\t{\n         \/\/ This creates the definitions that we need so we can use it in the calculation\n\n\t\t\/\/Source captures\n\t\tOutgoingBaseDamageDef = FGameplayEffectAttributeCaptureDefinition(UAresDamageSet::GetOutgoingBaseDamageAttribute(), EGameplayEffectAttributeCaptureSource::Source, true);\n\t\tOutgoingAbilityDamageDef = FGameplayEffectAttributeCaptureDefinition(UAresDamageSet::GetOutgoingAbilityDamageAttribute(), EGameplayEffectAttributeCaptureSource::Source, true);\n\n\t\t\/\/Target captures\n\t\tDamageDef = FGameplayEffectAttributeCaptureDefinition(UAresHealthSet::GetDamageAttribute(), EGameplayEffectAttributeCaptureSource::Target, false);\n    }\n};\n\n\/\/A static so we can use the above struct without needing to make a new instance for it.\nstatic FAresDamageStatics&amp; AresDamageStatics()\n{\n\tstatic FAresDamageStatics Statics;\n\treturn Statics;\n}\n\nUAresDamageFormulaExecution::UAresDamageFormulaExecution()\n{\n    \/*\n     * Exposes some modifiers to the calculation in the GE Blueprint.\n    *\/\n\t\/\/Source Captures\n\tRelevantAttributesToCapture.Add(AresDamageStatics().OutgoingBaseDamageDef);\n\tRelevantAttributesToCapture.Add(AresDamageStatics().OutgoingAbilityDamageDef);\n}\n\nvoid UAresDamageFormulaExecution::Execute_Implementation(const FGameplayEffectCustomExecutionParameters&amp; ExecutionParams, FGameplayEffectCustomExecutionOutput&amp; OutExecutionOutput) const\n{\n    \/\/Cache the spec\n\tconst FGameplayEffectSpec&amp; Spec = ExecutionParams.GetOwningSpec();\n\n    \/\/Grab the Effect Context\n    FGameplayEffectContext* Context = Spec.GetContext()\n\n    \/\/Grab the ability that initiated this execution (can be nullptr!!)\n\tconst UAresGameplayAbility* GameplayAbility = Cast&lt;UAresGameplayAbility&gt;(Context-&gt;GetAbilityInstance_NotReplicated());\n\n\t\/\/Grab the tags from source and target\n\tconst FGameplayTagContainer* SourceTags = Spec.CapturedSourceTags.GetAggregatedTags();\n\tconst FGameplayTagContainer* TargetTags = Spec.CapturedTargetTags.GetAggregatedTags();\n\n\t\/\/Setup our evaluate params\n\tFAggregatorEvaluateParameters EvaluateParameters;\n\tEvaluateParameters.SourceTags = SourceTags;\n\tEvaluateParameters.TargetTags = TargetTags;\n\n    \/\/Grab the outgoing base damage from the source\n\tfloat OutgoingBaseDamage = 0.0f;\n\tExecutionParams.AttemptCalculateCapturedAttributeMagnitude(AresDamageStatics().OutgoingBaseDamageDef, EvaluateParameters, OutgoingBaseDamage);\n\n\n    \/\/Calculate the actual ability damage\n\tfloat AbilityDamage = 0.0f;\n    ExecutionParams.AttemptCalculateCapturedAttributeMagnitudeWithBase(AresDamageStatics().OutgoingAbilityDamageDef, EvaluateParameters, BaseGameplayAbility ? GameplayAbility-&gt;GetDamageValue() : 0.f, AbilityDamage);\n    \n    \/\/Our final damage value.\n    float DamageDone = OutgoingBaseDamage + AbilityDamage;\n\n    \/\/If DamageDone is &gt; 0, then we will do damage to the target, so we can go and set the output modifier.\n    if (DamageDone &gt; 0.0f)\n\t{\n\t\t\n\t\tOutExecutionOutput.AddOutputModifier(FGameplayModifierEvaluatedData(UAresHealthSet::GetDamageAttribute(), EGameplayModOp::Additive, DamageDone));\n\t\t\n\t\t\/\/ If we do any damage, then any conditional GEs are allowed to fire (once we return)\n\t\tOutExecutionOutput.MarkConditionalGameplayEffectsToTrigger();\n\t}\n}\n<\/pre><\/div>\n\n\n<h2 class=\"wp-block-heading\">That is a wrap!<\/h2>\n\n\n\n<p>Hopefully this gives you a bit of insight into Execution Calculations and how to use them.<br>If you have any issues, check About Me to find out how to contact me!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Gameplay Effect Execution Calculation is a way to manipulate attributes base value. They are not stateful and can not be predicted (any attribute mutated this way is done so on it&#8217;s base value). But they are super powerful!Below I will explain some of the stuff about Gameplay Effect Execution Calculations and how to do general <a href=\"https:\/\/www.thegames.dev\/?p=119\" class=\"more-link\">&#8230;<span class=\"screen-reader-text\">  Understanding Gameplay Effect Execution Calculations!<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[],"class_list":["post-119","post","type-post","status-publish","format-standard","hentry","category-gameplay-ability-system"],"rise-blocks_total_comments":0,"rise-blocks_categories":[{"term_id":4,"name":"Gameplay Ability System","slug":"gameplay-ability-system","term_group":0,"term_taxonomy_id":4,"taxonomy":"category","description":"Unreal Engine's Gameplay Ability System (GAS)","parent":2,"count":16,"filter":"raw","cat_ID":4,"category_count":16,"category_description":"Unreal Engine's Gameplay Ability System (GAS)","cat_name":"Gameplay Ability System","category_nicename":"gameplay-ability-system","category_parent":2}],"rise-blocks_excerpt":"Gameplay Effect Execution Calculation is a way to manipulate attributes base value. They are not stateful and can not be predicted (any attribute mutated this way is done so on it&#8217;s base value). But they are super powerful!Below I will explain some of the stuff about Gameplay Effect Execution Calculations and how to do general calculations. This is not exhaustive,..","_links":{"self":[{"href":"https:\/\/www.thegames.dev\/index.php?rest_route=\/wp\/v2\/posts\/119","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.thegames.dev\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.thegames.dev\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.thegames.dev\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.thegames.dev\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=119"}],"version-history":[{"count":11,"href":"https:\/\/www.thegames.dev\/index.php?rest_route=\/wp\/v2\/posts\/119\/revisions"}],"predecessor-version":[{"id":161,"href":"https:\/\/www.thegames.dev\/index.php?rest_route=\/wp\/v2\/posts\/119\/revisions\/161"}],"wp:attachment":[{"href":"https:\/\/www.thegames.dev\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=119"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.thegames.dev\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=119"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.thegames.dev\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=119"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}