{"id":242,"date":"2024-06-25T23:30:05","date_gmt":"2024-06-25T23:30:05","guid":{"rendered":"https:\/\/www.thegames.dev\/?p=242"},"modified":"2024-06-25T23:30:05","modified_gmt":"2024-06-25T23:30:05","slug":"target-data-in-gameplay-abilities","status":"publish","type":"post","link":"https:\/\/www.thegames.dev\/?p=242","title":{"rendered":"Target Data in Gameplay Abilities"},"content":{"rendered":"\n<p>Target Data is designed to be a polymorphic type you can use for a range of target providing information. The name Target Data is a remanent from Paragon where everything was really Target Data. But Target Data can be used for more than just &#8220;Targets&#8221;.<\/p>\n\n\n\n<p class=\"has-large-font-size\">When to use Target Data<\/p>\n\n\n\n<p>You can use target data to provide information to your abilities, to apply Gameplay Effects to hit data, etc. It differs to Gameplay Effect Context which is a transient class for providing information during an effect execution and is passed along through the entire chain of an execution. Some of the most common uses of target data is is for applying gameplay effects to actors gathered via a trace\/overlap or some other mechanic.<\/p>\n\n\n\n<p class=\"has-large-font-size\">How do I use Target Data<\/p>\n\n\n\n<p>Using Target Data is really pretty simple for the most basic of tasks. Here is an example of a overlap which gathers actors in a range, and applies a Damage Gameplay Effect to those actors.<\/p>\n\n\n\n<p>In C++ the same is doable with this:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: Relevant Code:; notranslate\" title=\"Relevant Code:\">\n\tFGameplayAbilityTargetDataHandle Targets;\n\tfor (const FHitResult&amp; HitResult : HitResults)\n\t{\n\t\tFGameplayAbilityTargetData_SingleTargetHit* NewTargetData = new FGameplayAbilityTargetData_SingleTargetHit();\n\t\tNewTargetData-&gt;HitResult = HitResult;\n\t\tTargets.Add(NewTargetData);\n\t}\n\tApplyGameplayEffectToTarget(GetCurrentAbilitySpecHandle(), GetCurrentActorInfo(), GetCurrentActivationInfo(), Targets, DamageGEClass, 1.f);\n<\/pre><\/div>\n\n\n<p>In Blueprint it can be done like so:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"595\" src=\"https:\/\/www.thegames.dev\/wp-content\/uploads\/2024\/06\/image_2024-06-26_013651276-1024x595.png\" alt=\"\" class=\"wp-image-245\" srcset=\"https:\/\/www.thegames.dev\/wp-content\/uploads\/2024\/06\/image_2024-06-26_013651276-1024x595.png 1024w, https:\/\/www.thegames.dev\/wp-content\/uploads\/2024\/06\/image_2024-06-26_013651276-300x174.png 300w, https:\/\/www.thegames.dev\/wp-content\/uploads\/2024\/06\/image_2024-06-26_013651276-768x446.png 768w, https:\/\/www.thegames.dev\/wp-content\/uploads\/2024\/06\/image_2024-06-26_013651276.png 1101w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"has-large-font-size\">Making a custom Target Data<\/p>\n\n\n\n<p>You can make a custom Target Data in C++, which you can use in both C++ and Blueprint. Benefits of having custom Target Data is the ability to provide additional or different information which you may want. The example below adds a CartridgeID which is used for Ranged Weapons and is unique for every shot of a weapon. This can be used for simulating hit results (for example a shotgun that does 8 shots per cartridge). <\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: Relevant Code:; notranslate\" title=\"Relevant Code:\">\n\/** Game-specific additions to SingleTargetHit tracking *\/\nUSTRUCT()\nstruct FAresGameplayAbilityTargetData_SingleTargetHit : public FGameplayAbilityTargetData_SingleTargetHit\n{\n\tGENERATED_BODY()\n\n\tFAresGameplayAbilityTargetData_SingleTargetHit()\n\t\t: CartridgeID(-1)\n\t{\n\t}\n\n\tvirtual void AddTargetDataToContext(FGameplayEffectContextHandle&amp; Context, bool bIncludeActorArray) const override;\n\n\t\/** ID to allow the identification of multiple bullets that were part of the same cartridge *\/\n\tUPROPERTY()\n\tint32 CartridgeID;\n\n\tbool NetSerialize(FArchive&amp; Ar, class UPackageMap* Map, bool&amp; bOutSuccess);\n\n\tvirtual UScriptStruct* GetScriptStruct() const override\n\t{\n\t\treturn StaticStruct();\n\t}\n};\n\ntemplate &lt;&gt;\nstruct TStructOpsTypeTraits&lt;FAresGameplayAbilityTargetData_SingleTargetHit&gt; : public TStructOpsTypeTraitsBase2&lt;FAresGameplayAbilityTargetData_SingleTargetHit&gt;\n{\n\tenum\n\t{\n\t\tWithNetSerializer = true \/\/ For now this is REQUIRED for FGameplayAbilityTargetDataHandle net serialization to work\n\t};\n};\n\n<\/pre><\/div>\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: Relevant Code:; notranslate\" title=\"Relevant Code:\">\n\nvoid FAresGameplayAbilityTargetData_SingleTargetHit::AddTargetDataToContext(FGameplayEffectContextHandle&amp; Context, bool bIncludeActorArray) const\n{\n\tFGameplayAbilityTargetData_SingleTargetHit::AddTargetDataToContext(Context, bIncludeActorArray);\n\n\t\/\/ This adds the CartridgeID to the Gameplay Effect Context so the CartridgeID can be used\n\t\/\/ across the entire Gameplay Effect Execution (for example Damage GE)\n\tif (FAresGameplayEffectContext* TypedContext = FAresGameplayEffectContext::GetEffectContext(Context))\n\t{\n\t\tTypedContext-&gt;SetCartridgeID(CartridgeID);\n\t}\n}\n\nbool FAresGameplayAbilityTargetData_SingleTargetHit::NetSerialize(FArchive&amp; Ar, class UPackageMap* Map, bool&amp; bOutSuccess)\n{\n\tFGameplayAbilityTargetData_SingleTargetHit::NetSerialize(Ar, Map, bOutSuccess);\n\n\t\/\/So it can be sent over the network\n\tAr &lt;&lt; CartridgeID;\n\n\treturn true;\n}\n\n<\/pre><\/div>\n\n\n<p class=\"has-large-font-size\">How can I use this custom Target Data?<\/p>\n\n\n\n<p>We first need to expose some BP getters so you can retrieve the CartridgeID from the target data and create our special target data from Blueprint. This should be inside a BlueprintFunctionLibrary C++ class.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: Relevant Code:; notranslate\" title=\"Relevant Code:\">\n\t\/** Creates a target data with a single hit result and cartridge id *\/\n\tUFUNCTION(BlueprintPure, Category = &quot;Ability|TargetData&quot;)\n\tstatic FGameplayAbilityTargetDataHandle\tAbilityTargetDataFromHitResultWithCartridgeID(const FHitResult&amp; HitResult, int32 CartridgeId);\n\n\t\/** Returns the cartridge id from a hit result if its of our type, will return -1 if invalid. *\/\n\tUFUNCTION(BlueprintPure, Category = &quot;Ability|TargetData&quot;)\n\tstatic int32 GetCartridgeIDFromTargetData(const FGameplayAbilityTargetDataHandle&amp; TargetData, int32 Index);\n<\/pre><\/div>\n\n\n<p>And our implementation for those will be:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: Relevant Code:; notranslate\" title=\"Relevant Code:\">\nFGameplayAbilityTargetDataHandle UAresGameplayStatics::AbilityTargetDataFromHitResultWithCartridgeID(const FHitResult&amp; HitResult, int32 CartridgeID)\n{\n\t\/\/ Construct TargetData\n\tFAresGameplayAbilityTargetData_SingleTargetHit* TargetData = new FAresGameplayAbilityTargetData_SingleTargetHit();\n\n\t\/\/Set the hit result\n\tTargetData-&gt;HitResult = HitResult;\n\n\t\/\/Set the cartridge id\n\tTargetData-&gt;CartridgeID = CartridgeID;\n\n\t\/\/ Give it a handle and return\n\tFGameplayAbilityTargetDataHandle\tHandle;\n\tHandle.Data.Add(TSharedPtr&lt;FGameplayAbilityTargetData&gt;(TargetData));\n\n\treturn Handle;\n}\n\nint32 UAresGameplayStatics::GetCartridgeIDFromTargetData(const FGameplayAbilityTargetDataHandle&amp; TargetData, int32 Index)\n{\n\tif (TargetData.Data.IsValidIndex(Index))\n\t{\n\t\tFAresGameplayAbilityTargetData_SingleTargetHit* Data = static_cast&lt;FAresGameplayAbilityTargetData_SingleTargetHit*&gt;(TargetData.Data&#x5B;Index].Get());\n\t\tif (Data)\n\t\t{\n\t\t\treturn Data-&gt;CartridgeID;\n\t\t}\n\t}\n\treturn -1;\n}\n<\/pre><\/div>\n\n\n<p>With these new functions, you can now use your custom Target Data in Blueprint. Here is an example:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"514\" src=\"https:\/\/www.thegames.dev\/wp-content\/uploads\/2024\/06\/image-1024x514.png\" alt=\"\" class=\"wp-image-254\" style=\"width:774px;height:auto\" srcset=\"https:\/\/www.thegames.dev\/wp-content\/uploads\/2024\/06\/image-1024x514.png 1024w, https:\/\/www.thegames.dev\/wp-content\/uploads\/2024\/06\/image-300x151.png 300w, https:\/\/www.thegames.dev\/wp-content\/uploads\/2024\/06\/image-768x386.png 768w, https:\/\/www.thegames.dev\/wp-content\/uploads\/2024\/06\/image.png 1279w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"640\" height=\"157\" src=\"https:\/\/www.thegames.dev\/wp-content\/uploads\/2024\/06\/image-1.png\" alt=\"\" class=\"wp-image-255\" srcset=\"https:\/\/www.thegames.dev\/wp-content\/uploads\/2024\/06\/image-1.png 640w, https:\/\/www.thegames.dev\/wp-content\/uploads\/2024\/06\/image-1-300x74.png 300w\" sizes=\"auto, (max-width: 640px) 100vw, 640px\" \/><\/figure>\n\n\n\n<p>To use your new Target Data in C++, you can do the following:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: Relevant Code:; notranslate\" title=\"Relevant Code:\">\n\tFGameplayAbilityTargetDataHandle Targets;\n\tfor (const FHitResult&amp; HitResult : HitResults)\n\t{\n\t\tFAresGameplayAbilityTargetData_SingleTargetHit* NewTargetData = new FAresGameplayAbilityTargetData_SingleTargetHit();\n\t\tNewTargetData-&gt;HitResult = HitResult;\n\t\tNewTargetData-&gt;CartridgeID = CartridgeID;\n\t\tTargets.Add(NewTargetData);\n\t}\n\tApplyGameplayEffectToTarget(GetCurrentAbilitySpecHandle(), GetCurrentActorInfo(), GetCurrentActivationInfo(), Targets, DamageGEClass, 1.f);\n\n\tif (Targets.IsValid(0))\n\t{\n\t\tFAresGameplayAbilityTargetData_SingleTargetHit* MyTargetData = static_cast&lt;FAresGameplayAbilityTargetData_SingleTargetHit*&gt;(Targets.Data&#x5B;0].Get());\n\t\tif (MyTargetData)\n\t\t{\n\t\t\tint32 CartridgeID = MyTargetData-&gt;CartridgeID;\n\t\t}\n\t}\n<\/pre><\/div>\n\n\n<p class=\"has-large-font-size\">Other uses for Target Data<\/p>\n\n\n\n<p>Target Data can be passed in for ability activation via Gameplay Events. Example below:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"511\" src=\"https:\/\/www.thegames.dev\/wp-content\/uploads\/2024\/06\/image-3-1024x511.png\" alt=\"\" class=\"wp-image-258\" srcset=\"https:\/\/www.thegames.dev\/wp-content\/uploads\/2024\/06\/image-3-1024x511.png 1024w, https:\/\/www.thegames.dev\/wp-content\/uploads\/2024\/06\/image-3-300x150.png 300w, https:\/\/www.thegames.dev\/wp-content\/uploads\/2024\/06\/image-3-768x383.png 768w, https:\/\/www.thegames.dev\/wp-content\/uploads\/2024\/06\/image-3.png 1176w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Here we are sending a gameplay event, which has the target data for as hit result, we can use this inside an ability, <\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"554\" src=\"https:\/\/www.thegames.dev\/wp-content\/uploads\/2024\/06\/image-4-1024x554.png\" alt=\"\" class=\"wp-image-259\" srcset=\"https:\/\/www.thegames.dev\/wp-content\/uploads\/2024\/06\/image-4-1024x554.png 1024w, https:\/\/www.thegames.dev\/wp-content\/uploads\/2024\/06\/image-4-300x162.png 300w, https:\/\/www.thegames.dev\/wp-content\/uploads\/2024\/06\/image-4-768x416.png 768w, https:\/\/www.thegames.dev\/wp-content\/uploads\/2024\/06\/image-4.png 1249w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>There is a lot more to Target Data, but wanted to keep this a little brief.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Target Data is designed to be a polymorphic type you can use for a range of target providing information. The name Target Data is a remanent from Paragon where everything was really Target Data. But Target Data can be used for more than just &#8220;Targets&#8221;. When to use Target Data You can use target data <a href=\"https:\/\/www.thegames.dev\/?p=242\" class=\"more-link\">&#8230;<span class=\"screen-reader-text\">  Target Data in Gameplay Abilities<\/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,2],"tags":[],"class_list":["post-242","post","type-post","status-publish","format-standard","hentry","category-gameplay-ability-system","category-unreal-engine"],"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},{"term_id":2,"name":"Unreal Engine","slug":"unreal-engine","term_group":0,"term_taxonomy_id":2,"taxonomy":"category","description":"All unreal engine related tutorials, tips and tricks.","parent":0,"count":5,"filter":"raw","cat_ID":2,"category_count":5,"category_description":"All unreal engine related tutorials, tips and tricks.","cat_name":"Unreal Engine","category_nicename":"unreal-engine","category_parent":0}],"rise-blocks_excerpt":"Target Data is designed to be a polymorphic type you can use for a range of target providing information. The name Target Data is a remanent from Paragon where everything was really Target Data. But Target Data can be used for more than just &#8220;Targets&#8221;. When to use Target Data You can use target data to provide information to your..","_links":{"self":[{"href":"https:\/\/www.thegames.dev\/index.php?rest_route=\/wp\/v2\/posts\/242","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=242"}],"version-history":[{"count":12,"href":"https:\/\/www.thegames.dev\/index.php?rest_route=\/wp\/v2\/posts\/242\/revisions"}],"predecessor-version":[{"id":260,"href":"https:\/\/www.thegames.dev\/index.php?rest_route=\/wp\/v2\/posts\/242\/revisions\/260"}],"wp:attachment":[{"href":"https:\/\/www.thegames.dev\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=242"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.thegames.dev\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=242"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.thegames.dev\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=242"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}