{"id":62,"date":"2021-01-25T02:37:12","date_gmt":"2021-01-25T02:37:12","guid":{"rendered":"https:\/\/www.thegames.dev\/?p=62"},"modified":"2023-12-06T09:05:59","modified_gmt":"2023-12-06T09:05:59","slug":"creating-your-own-gameplay-effect-context","status":"publish","type":"post","link":"https:\/\/www.thegames.dev\/?p=62","title":{"rendered":"Creating your own Gameplay Effect Context."},"content":{"rendered":"\n<p>There could be many reasons you want to create your own Effect Context within the Gameplay Ability System. I have listed a few reasons below. Before you get started, you should create your own game specific AbilitySystemGlobals class, link here: <a href=\"https:\/\/www.thegames.dev\/?p=52\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/www.thegames.dev\/?p=52<\/a>. So here are the reasons:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Passing in info about a specific thing (like if a damage effect was fatal, was critical, etc)<\/li>\n\n\n\n<li>Passing around some kind of level for a specific weapon\/item that applied that effect.<\/li>\n\n\n\n<li>Passing around an ID for say a shotgun cartridge for reproducing hits on simulated proxies locally.<\/li>\n<\/ul>\n\n\n\n<p>There are many other things you can do, but we will use the above examples as a basis for our custom GameplayEffectContext.<\/p>\n\n\n\n<p>First you will need a cpp and header file to hold the new struct. I recommend making an AbilityTypes.cpp and AbilityTypes.h, for example i have KaosAbilityTypes.cpp and KaosAbilityTypes.h. Now we can derive from FGameplayEffectContext and add our own custom stuff.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: Relevant Code:; notranslate\" title=\"Relevant Code:\">\nUSTRUCT(BlueprintType)\nstruct FKaosGameplayEffectContext : public FGameplayEffectContext\n{\n\tGENERATED_BODY()\npublic:\n\tbool IsFatalHit() const { return bIsFatalHit; }\n\tbool IsCriticalHit() const { return bIsCriticalHit; }\n\tfloat GetCartridgeID() const { return CartridgeID; }\n\tfloat GetSourceLevel() const { return SourceLevel; }\n\n\tvoid SetIsFatalHit(bool bInIsFatalHit) { bIsFatalHit = bInIsFatalHit; }\n\tvoid SetIsCriticalHit(bool bInIsCriticalHit) { bIsCriticalHit = bInIsCriticalHit; }\n\tvoid SetCartridgeID(int32 InID) { CartridgeID = InID; }\n\tvoid SetSourceLevel(float InLevel) { SourceLevel = InLevel; }\n\nprotected:\n\tUPROPERTY()\n\tbool bIsFatalHit;\n\n\tUPROPERTY()\n\tbool bIsCriticalHit;\n\n\tUPROPERTY()\n\tint32 CartridgeID;\n\n\tUPROPERTY()\n\tfloat SourceLevel;\n\npublic:\n\t\/** Returns the actual struct used for serialization, subclasses must override this! *\/\n\tvirtual UScriptStruct* GetScriptStruct() const override\n\t{\n\t\treturn StaticStruct();\n\t}\n\n\t\/** Creates a copy of this context, used to duplicate for later modifications *\/\n\tvirtual FKaosGameplayEffectContext* Duplicate() const override\n\t{\n\t\tFKaosGameplayEffectContext* NewContext = new FKaosGameplayEffectContext();\n\t\t*NewContext = *this;\n\t\tNewContext-&gt;AddActors(Actors);\n\t\tif (GetHitResult())\n\t\t{\n\t\t\t\/\/ Does a deep copy of the hit result\n\t\t\tNewContext-&gt;AddHitResult(*GetHitResult(), true);\n\t\t}\n\t\treturn NewContext;\n\t}\n\n\tvirtual bool NetSerialize(FArchive&amp; Ar, UPackageMap* Map, bool&amp; bOutSuccess) override;\n};\n\ntemplate &lt;&gt;\nstruct TStructOpsTypeTraits&lt;FKaosGameplayEffectContext&gt; : public TStructOpsTypeTraitsBase2&lt;FKaosGameplayEffectContext&gt;\n{\n\tenum\n\t{\n\t\tWithNetSerializer = true,\n\t\tWithCopy = true \/\/ Necessary so that TSharedPtr&lt;FHitResult&gt; Data is copied around\n\t};\n};\n<\/pre><\/div>\n\n\n<p>As you can see, we now have a few things in our special subclass of the EffectContext, namely: bIsFatalHit, bIsCriticalHit, CartridgeID and SourceLevel. You can have many things that you might need to pass around.<\/p>\n\n\n\n<p>Now we get to the fun part, and this is we need to handle replicating these properties. We do this by overriding, NetSerialize function.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: Relevant Code:; notranslate\" title=\"Relevant Code:\">\nbool FKaosGameplayEffectContext::NetSerialize(FArchive&amp; Ar, UPackageMap* Map, bool&amp; bOutSuccess)\n{\n enum RepFlag\n\t{\n\t\tREP_Instigator,\n\t\tREP_EffectCauser,\n\t\tREP_AbilityCDO,\n\t\tREP_SourceObject,\n\t\tREP_Actors,\n\t\tREP_HitResult,\n\t\tREP_WorldOrigin,\n\t\tREP_IsFatalHit,\n\t\tREP_CartridgeID,\n\t\tREP_IsCriticalHit,\n\t\tREP_SourceLevel,\n\t\tREP_MAX\n\t};\n\t\n\tuint16 RepBits = 0;\n\tif (Ar.IsSaving())\n\t{\n\t\tif (Instigator.IsValid())\n\t\t{\n\t\t\tRepBits |= 1 &lt;&lt; REP_Instigator;\n\t\t}\n\t\tif (EffectCauser.IsValid())\n\t\t{\n\t\t\tRepBits |= 1 &lt;&lt; REP_EffectCauser;\n\t\t}\n\t\tif (AbilityCDO.IsValid())\n\t\t{\n\t\t\tRepBits |= 1 &lt;&lt; REP_AbilityCDO;\n\t\t}\n\t\tif (bReplicateSourceObject &amp;&amp; SourceObject.IsValid())\n\t\t{\n\t\t\tRepBits |= 1 &lt;&lt; REP_SourceObject;\n\t\t}\n\t\tif (Actors.Num() &gt; 0)\n\t\t{\n\t\t\tRepBits |= 1 &lt;&lt; REP_Actors;\n\t\t}\n\t\tif (HitResult.IsValid())\n\t\t{\n\t\t\tRepBits |= 1 &lt;&lt; REP_HitResult;\n\t\t}\n\t\tif (bHasWorldOrigin)\n\t\t{\n\t\t\tRepBits |= 1 &lt;&lt; REP_WorldOrigin;\n\t\t}\n\t\tif (bIsFatalHit)\n\t\t{\n\t\t\tRepBits |= 1 &lt;&lt; REP_IsFatalHit;\n\t\t}\n\t\tif (bIsCriticalHit)\n\t\t{\n\t\t\tRepBits |= 1 &lt;&lt; REP_IsCriticalHit;\n\t\t}\n\t\tif (SourceLevel &gt; 0)\n\t\t{\n\t\t\tRepBits |= 1 &lt;&lt; REP_SourceLevel;\n\t\t}\n\t\tif (CartridgeID &gt; 0)\n\t\t{\n\t\t\tRepBits |= 1 &lt;&lt; REP_CartrideID;\n\t\t}\n\t}\n\n\tAr.SerializeBits(&amp;RepBits, REP_MAX);\n\n\tif (RepBits &amp; (1 &lt;&lt; REP_Instigator))\n\t{\n\t\tAr &lt;&lt; Instigator;\n\t}\n\tif (RepBits &amp; (1 &lt;&lt; REP_EffectCauser))\n\t{\n\t\tAr &lt;&lt; EffectCauser;\n\t}\n\tif (RepBits &amp; (1 &lt;&lt; REP_AbilityCDO))\n\t{\n\t\tAr &lt;&lt; AbilityCDO;\n\t}\n\tif (RepBits &amp; (1 &lt;&lt; REP_SourceObject))\n\t{\n\t\tAr &lt;&lt; SourceObject;\n\t}\n\tif (RepBits &amp; (1 &lt;&lt; REP_Actors))\n\t{\n\t\tSafeNetSerializeTArray_Default&lt;31&gt;(Ar, Actors);\n\t}\n\tif (RepBits &amp; (1 &lt;&lt; REP_HitResult))\n\t{\n\t\tif (Ar.IsLoading())\n\t\t{\n\t\t\tif (!HitResult.IsValid())\n\t\t\t{\n\t\t\t\tHitResult = TSharedPtr&lt;FHitResult&gt;(new FHitResult());\n\t\t\t}\n\t\t}\n\t\tHitResult-&gt;NetSerialize(Ar, Map, bOutSuccess);\n\t}\n\tif (RepBits &amp; (1 &lt;&lt; REP_WorldOrigin))\n\t{\n\t\tAr &lt;&lt; WorldOrigin;\n\t\tbHasWorldOrigin = true;\n\t}\n\telse\n\t{\n\t\tbHasWorldOrigin = false;\n\t}\n\tif (RepBits &amp; (1 &lt;&lt; REP_IsFatalHit))\n\t{\n\t\tAr &lt;&lt; bIsFatalHit;\n\t}\n\tif (RepBits &amp; (1 &lt;&lt; REP_IsCriticalHit))\n\t{\n\t\tAr &lt;&lt; bIsCriticalHit;\n\t}\n\tif (RepBits &amp; (1 &lt;&lt; REP_SourceLevel))\n\t{\n\t\tAr &lt;&lt; SourceLevel;\n\t}\n\tif (RepBits &amp; (1 &lt;&lt; REP_CartrideID))\n\t{\n\t\tAr &lt;&lt; CartridgeID;\n\t}\n\n\tif (Ar.IsLoading())\n\t{\n\t\tAddInstigator(Instigator.Get(), EffectCauser.Get()); \/\/ Just to initialize InstigatorAbilitySystemComponent\n\t}\t\n\t\n\tbOutSuccess = true;\n\treturn true;\n}\n<\/pre><\/div>\n\n\n<p>Phew that is a lot of stuff. But the general gist is, we want to serialise the bits for replication. If you want a more detailed description on the above, then let me know.<\/p>\n\n\n\n<p>With the above, we can now tell our AbilitySystemGlobals, we want to use our new Effect Context. We do this by overriding<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: Relevant Code:; notranslate\" title=\"Relevant Code:\">\n\tvirtual FGameplayEffectContext* AllocGameplayEffectContext() const override;\n\n<\/pre><\/div>\n\n\n<p>in our game specific AbilitySystemGlobals header, and defining that as:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: Relevant Code:; notranslate\" title=\"Relevant Code:\">\nFGameplayEffectContext* UKaosAbilitySystemGlobals::AllocGameplayEffectContext() const\n{\n\treturn new FKaosGameplayEffectContext();\n}\n<\/pre><\/div>\n\n\n<p>in the corresponding .cpp file.<\/p>\n\n\n\n<p>Restarting the editor will now have the engine using our Effect Context.<\/p>\n\n\n\n<p>Now you may ask, how do i access or set these values?. Well that is a good question, and i will explain below, the easiest way to access them is to make some static functions inside a blueprint function library class. Example of such static function is listed below:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: Relevant Code:; notranslate\" title=\"Relevant Code:\">\n\tUFUNCTION(BlueprintPure, Category = &quot;KaosAbilityLibrary|Effects&quot;)\n\tstatic bool IsFatalHit(const FGameplayEffectContextHandle&amp; EffectContext);\n<\/pre><\/div>\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: Relevant Code:; notranslate\" title=\"Relevant Code:\">\nbool UKaosAbilityLibrary::IsFatalHit(const FGameplayEffectContextHandle&amp; EffectContext)\n{\n\tconst FKaosGameplayEffectContext* KaosEffectContext = static_cast&lt;const FKaosGameplayEffectContext*&gt;(EffectContext.Get());\n\tif (KaosEffectContext)\n\t{\n\t\treturn KaosEffectContext-&gt;IsFatalHit();\n\t}\n\treturn false;\n}\n<\/pre><\/div>\n\n\n<p>Now this is fine for accessing, but what about setting? Well this is a tad more tricky, and i don&#8217;t recommend exposing these to Blueprint, and keeping this stuff in native code. But you are more than welcome to if you want.<\/p>\n\n\n\n<p>So to access the Gameplay Effect Context from an Execution Calculation class, you can do :<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: Relevant Code:; notranslate\" title=\"Relevant Code:\">\nFGameplayEffectSpec* MutableSpec = ExecutionParams.GetOwningSpecForPreExecuteMod();\nFKaosGameplayEffectContext* Context = static_cast&lt;FKaosGameplayEffectContext*&gt;(MutableSpec-&gt;GetContext().Get());\nContext-&gt;SetIsCriticalHit(true);\n\n<\/pre><\/div>\n\n\n<p>This will give you a mutable context in which you can now freely call your set functions on the Effect Context, like i have shown above. You can also mutate\/read from the context in your attribute sets, like so:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: Relevant Code:; notranslate\" title=\"Relevant Code:\">\n\tFKaosGameplayEffectContext* Context = static_cast&lt;FKaosGameplayEffectContext*&gt;(Data.GetContext().Get);\n\n<\/pre><\/div>\n\n\n<p>Basically anywhere you can get hold of an EffectSpecHandle or EffectSpec, you can get access to your Effect Context.<\/p>\n\n\n\n<p>Hope this helps people, if you need more clarity or more information, feel free to contact me. Contact details can be found in the Contact page.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>There could be many reasons you want to create your own Effect Context within the Gameplay Ability System. I have listed a few reasons below. Before you get started, you should create your own game specific AbilitySystemGlobals class, link here: https:\/\/www.thegames.dev\/?p=52. So here are the reasons: There are many other things you can do, but <a href=\"https:\/\/www.thegames.dev\/?p=62\" class=\"more-link\">&#8230;<span class=\"screen-reader-text\">  Creating your own Gameplay Effect Context.<\/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-62","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":"There could be many reasons you want to create your own Effect Context within the Gameplay Ability System. I have listed a few reasons below. Before you get started, you should create your own game specific AbilitySystemGlobals class, link here: https:\/\/www.thegames.dev\/?p=52. So here are the reasons: There are many other things you can do, but we will use the above..","_links":{"self":[{"href":"https:\/\/www.thegames.dev\/index.php?rest_route=\/wp\/v2\/posts\/62","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=62"}],"version-history":[{"count":5,"href":"https:\/\/www.thegames.dev\/index.php?rest_route=\/wp\/v2\/posts\/62\/revisions"}],"predecessor-version":[{"id":196,"href":"https:\/\/www.thegames.dev\/index.php?rest_route=\/wp\/v2\/posts\/62\/revisions\/196"}],"wp:attachment":[{"href":"https:\/\/www.thegames.dev\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=62"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.thegames.dev\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=62"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.thegames.dev\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=62"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}