{"id":96,"date":"2022-01-15T05:52:31","date_gmt":"2022-01-15T05:52:31","guid":{"rendered":"https:\/\/www.thegames.dev\/?p=96"},"modified":"2022-01-15T05:52:32","modified_gmt":"2022-01-15T05:52:32","slug":"gameplay-tag-relationships","status":"publish","type":"post","link":"https:\/\/www.thegames.dev\/?p=96","title":{"rendered":"Gameplay Tag Relationships"},"content":{"rendered":"\n<p>When dealing with a lot of abilities, the block and cancel tags can get confusing and hard to keep managed. By using a relationship, we can apply block, cancel and activation tags from a more central location. This allows us to define what ability tags block and cancels what abilities, Example below:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"http:\/\/thegames.dev\/snaps\/UnrealEditor-Win64-DebugGame_c3l6kt6ZlH.png\" alt=\"\"\/><\/figure>\n\n\n\n<p>This is a relationship for the Ability tag: Gameplay.Action.Player.Reload.  Which will block the reload ability, and cancel the players sprint ability.<\/p>\n\n\n\n<p>Inside your ability you would this gameplay tag:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"http:\/\/thegames.dev\/snaps\/UnrealEditor-Win64-DebugGame_hgQPnw87mk.png\" alt=\"\"\/><\/figure>\n\n\n\n<p>Lets create a new class, which is going to be a DataAsset, and populate it with the required fields<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: Relevant Code:; notranslate\" title=\"Relevant Code:\">\n\/\/ (C) 2021 InterKaos Games\n\n#pragma once\n\n#include &quot;CoreMinimal.h&quot;\n#include &quot;GameplayTagContainer.h&quot;\n#include &quot;Engine\/DataAsset.h&quot;\n#include &quot;KaosAbilityTagRelationship.generated.h&quot;\n\n\/*\n * Defines the relationship between different ability tags\n *\/\nUSTRUCT()\nstruct FKaosAbilityTagRelationshipItem\n{\n\tGENERATED_BODY()\n\n\t\/* The tag that this relationship is about. *\/\n\tUPROPERTY(EditAnywhere, Category = Ability)\n\tFGameplayTag AbilityTag;\n\n\t\/* This ability tag will block abilities matching these tags *\/\n\tUPROPERTY(EditAnywhere, Category = Tags)\n\tFGameplayTagContainer AbilityTagsToBlock;\n\n\t\/* This ability tag will cancel abilities matching these tags *\/\n\tUPROPERTY(EditAnywhere, Category = Tags)\n\tFGameplayTagContainer AbilityTagsToCancel;\n\n\t\/* This ability tag will add these tags to the Activation Required Tags *\/\n\tUPROPERTY(EditAnywhere, Category = Tags)\n\tFGameplayTagContainer ActivationRequiredTags;\n\n\t\/* This ability tag will add these tags to the Activation Blocked Tags *\/\n\tUPROPERTY(EditAnywhere, Category = Tags)\n\tFGameplayTagContainer ActivationBlockedTags;\n\n};\n\n\n\/*\n * Mapping of how ability tags block or cancel other abilities, and additional activation\n * required and blocked tags. \n *\/\nUCLASS()\nclass UKaosAbilityTagRelationship : public UDataAsset\n{\n\tGENERATED_BODY()\n\npublic:\n\t\/* Fill out tags to block and cancel matching the AbilityTags passed in *\/\n\tvoid GetAbilityTagsToBlockAndCancel(const FGameplayTagContainer&amp; AbilityTags, FGameplayTagContainer* OutTagsToBlock, FGameplayTagContainer* OutTagsToCancel) const;\n\n\t\/* Add additional required and blocking tags matching the passed in AbilityTags *\/\n\tvoid GetActivationRequiredAndBlockedTags(const FGameplayTagContainer&amp; AbilityTags, FGameplayTagContainer* OutActivationRequired, FGameplayTagContainer* OutActivationBlocked) const;\n\nprivate:\n\t\/* The list of relationships between different ability gameplay tags *\/\n\tUPROPERTY(EditAnywhere)\n\tTArray&lt;FKaosAbilityTagRelationshipItem&gt; AbilityTagRelationships;\n};\n\n<\/pre><\/div>\n\n\n<p>Now we need to create the corresponding cpp file<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: Relevant Code:; notranslate\" title=\"Relevant Code:\">\n\/\/ (C) 2021 InterKaos Games\n\n#include &quot;KaosAbilityTagRelationship.h&quot;\n\nvoid UKaosAbilityTagRelationship::GetAbilityTagsToBlockAndCancel(const FGameplayTagContainer&amp; AbilityTags, FGameplayTagContainer* OutTagsToBlock, FGameplayTagContainer* OutTagsToCancel) const\n{\n\tfor (const FKaosAbilityTagRelationshipItem&amp; Relationship : AbilityTagRelationships)\n\t{\n\t\tif (AbilityTags.HasTag(Relationship.AbilityTag))\n\t\t{\n\t\t\tif (OutTagsToBlock)\n\t\t\t{\n\t\t\t\tOutTagsToBlock-&gt;AppendTags(Relationship.AbilityTagsToBlock);\n\t\t\t}\n\t\t\t\n\t\t\tif (OutTagsToCancel)\n\t\t\t{\n\t\t\t\tOutTagsToCancel-&gt;AppendTags(Relationship.AbilityTagsToCancel);\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid UKaosAbilityTagRelationship::GetActivationRequiredAndBlockedTags(const FGameplayTagContainer&amp; AbilityTags, FGameplayTagContainer* OutActivationRequired, FGameplayTagContainer* OutActivationBlocked) const\n{\n\tfor (const FKaosAbilityTagRelationshipItem&amp; Relationship : AbilityTagRelationships)\n\t{\n\t\tif (AbilityTags.HasTag(Relationship.AbilityTag))\n\t\t{\n\t\t\tif (OutActivationRequired)\n\t\t\t{\n\t\t\t\tOutActivationRequired-&gt;AppendTags(Relationship.ActivationRequiredTags);\n\t\t\t}\n\n\t\t\tif (OutActivationBlocked)\n\t\t\t{\n\t\t\t\tOutActivationBlocked-&gt;AppendTags(Relationship.ActivationBlockedTags);\n\t\t\t}\n\t\t}\n\t}\n}\n<\/pre><\/div>\n\n\n<p>Now we need to add a couple of things to the Ability System Component so we can make use of these relationships<\/p>\n\n\n\n<p>Add the following to your custom ASC<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: Relevant Code:; notranslate\" title=\"Relevant Code:\">\npublic:\n\tvoid GetRelationshipActivationTagRequirements(const FGameplayTagContainer&amp; AbilityTags, FGameplayTagContainer&amp; OutActivationRequired, FGameplayTagContainer&amp; OutActivationBlocked) const;\n\n\nprotected:\n\t\/* Mapping of Ability Tag to block and cancel tags. *\/\n\tUPROPERTY(EditDefaultsOnly, Category = &quot;Abilities|GameplayTags&quot;)\n\tUKaosAbilityTagRelationship* AbilityTagRelationship;\n<\/pre><\/div>\n\n\n<p>and we need to override one function:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: Relevant Code:; notranslate\" title=\"Relevant Code:\">\n\tvirtual void ApplyAbilityBlockAndCancelTags(const FGameplayTagContainer&amp; AbilityTags, UGameplayAbility* RequestingAbility, bool bEnableBlockTags, const FGameplayTagContainer&amp; BlockTags, bool bExecuteCancelTags, const FGameplayTagContainer&amp; CancelTags) override;\n\n<\/pre><\/div>\n\n\n<p>Now we can and implement these functions, and use the tag relationship table<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: Relevant Code:; notranslate\" title=\"Relevant Code:\">\nvoid UKaosAbilitySystemComponent::GetRelationshipActivationTagRequirements(const FGameplayTagContainer&amp; AbilityTags, FGameplayTagContainer&amp; OutActivationRequired, FGameplayTagContainer&amp; OutActivationBlocked) const\n{\n\tif (AbilityTagRelationship)\n\t{\n\t\tAbilityTagRelationship-&gt;GetActivationRequiredAndBlockedTags(AbilityTags, &amp;OutActivationRequired, &amp;OutActivationBlocked);\n\t}\n}\n\nvoid UKaosAbilitySystemComponent::ApplyAbilityBlockAndCancelTags(const FGameplayTagContainer&amp; AbilityTags, UGameplayAbility* RequestingAbility, bool bEnableBlockTags, const FGameplayTagContainer&amp; BlockTags, bool bExecuteCancelTags,\n\tconst FGameplayTagContainer&amp; CancelTags)\n{\n\tFGameplayTagContainer AbilityBlockTags = BlockTags;\n\tFGameplayTagContainer AbilityCancelTags = CancelTags;\n\t\n\tif (AbilityTagRelationship)\n\t{\n\t\tAbilityTagRelationship-&gt;GetAbilityTagsToBlockAndCancel(AbilityTags, &amp;AbilityBlockTags, &amp;AbilityCancelTags);\n\t}\n\n\tSuper::ApplyAbilityBlockAndCancelTags(AbilityTags, RequestingAbility, bEnableBlockTags, AbilityBlockTags, bExecuteCancelTags, AbilityCancelTags);\n}\n<\/pre><\/div>\n\n\n<p>Now the block and cancel tags will work, but we need to do some stuff in your custom Gameplay Ability to handle the Activation Required and Activation Blocked tags.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Lets override the following function in your custom Gameplay Ability class<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: Relevant Code:; notranslate\" title=\"Relevant Code:\">\n\tvirtual bool DoesAbilitySatisfyTagRequirements(const UAbilitySystemComponent&amp; AbilitySystemComponent, const FGameplayTagContainer* SourceTags, const FGameplayTagContainer* TargetTags, FGameplayTagContainer* OptionalRelevantTags) const override;\n\n<\/pre><\/div>\n\n\n<p>and implement the function like this (this is a hard override of the default GameplayAbility function<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: Relevant Code:; notranslate\" title=\"Relevant Code:\">\nbool UKaosGameplayAbility::DoesAbilitySatisfyTagRequirements(const UAbilitySystemComponent&amp; AbilitySystemComponent, const FGameplayTagContainer* SourceTags, const FGameplayTagContainer* TargetTags, FGameplayTagContainer* OptionalRelevantTags) const\n{\n\tbool bBlocked = false;\n\tbool bMissing = false;\n\n\tconst UAbilitySystemGlobals&amp; AbilitySystemGlobals = UAbilitySystemGlobals::Get();\n\tconst FGameplayTag&amp; BlockedTag = AbilitySystemGlobals.ActivateFailTagsBlockedTag;\n\tconst FGameplayTag&amp; MissingTag = AbilitySystemGlobals.ActivateFailTagsMissingTag;\n\n\t\/\/ Check if any of this ability&#039;s tags are currently blocked\n\tif (AbilitySystemComponent.AreAbilityTagsBlocked(AbilityTags))\n\t{\n\t\tbBlocked = true;\n\t}\n\n\t\/*\n\t * Relationship related code\n\t *\/\n\t\n\tconst UKaosAbilitySystemComponent* KaosASC = Cast&lt;UKaosAbilitySystemComponent&gt;(&amp;AbilitySystemComponent);\n\tstatic FGameplayTagContainer AbilityRequiredTags;\n\tAbilityRequiredTags = ActivationRequiredTags;\n\t\n\tstatic FGameplayTagContainer AbilityBlockedTags; \n\tAbilityBlockedTags = ActivationBlockedTags;\n\n\t\/\/ This gets the additional tags from the ASC&#039;s relationship mapping for the abilities tags.\n\tif (KaosASC)\n\t{\n\t\tKaosASC-&gt;GetRelationshipActivationTagRequirements(AbilityTags, AbilityRequiredTags, AbilityBlockedTags);\n\t}\n\n\t\/*\n\t * End of relationship code\n\t *\/\n\n\t\/\/ Check to see the required\/blocked tags for this ability\n\tif (AbilityBlockedTags.Num() || AbilityRequiredTags.Num())\n\t{\n\t\tstatic FGameplayTagContainer AbilitySystemComponentTags;\n\t\t\n\t\tAbilitySystemComponentTags.Reset();\n\t\tAbilitySystemComponent.GetOwnedGameplayTags(AbilitySystemComponentTags);\n\n\t\tif (AbilitySystemComponentTags.HasAny(AbilityBlockedTags))\n\t\t{\n\t\t\tbBlocked = true;\n\t\t}\n\n\t\tif (!AbilitySystemComponentTags.HasAll(AbilityRequiredTags))\n\t\t{\n\t\t\tbMissing = true;\n\t\t}\n\t}\n\n\tif (SourceTags != nullptr)\n\t{\n\t\tif (SourceBlockedTags.Num() || SourceRequiredTags.Num())\n\t\t{\n\t\t\tif (SourceTags-&gt;HasAny(SourceBlockedTags))\n\t\t\t{\n\t\t\t\tbBlocked = true;\n\t\t\t}\n\n\t\t\tif (!SourceTags-&gt;HasAll(SourceRequiredTags))\n\t\t\t{\n\t\t\t\tbMissing = true;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (TargetTags != nullptr)\n\t{\n\t\tif (TargetBlockedTags.Num() || TargetRequiredTags.Num())\n\t\t{\n\t\t\tif (TargetTags-&gt;HasAny(TargetBlockedTags))\n\t\t\t{\n\t\t\t\tbBlocked = true;\n\t\t\t}\n\n\t\t\tif (!TargetTags-&gt;HasAll(TargetRequiredTags))\n\t\t\t{\n\t\t\t\tbMissing = true;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (bBlocked)\n\t{\n\t\tif (OptionalRelevantTags &amp;&amp; BlockedTag.IsValid())\n\t\t{\n\t\t\tOptionalRelevantTags-&gt;AddTag(BlockedTag);\n\t\t}\n\t\treturn false;\n\t}\n\tif (bMissing)\n\t{\n\t\tif (OptionalRelevantTags &amp;&amp; MissingTag.IsValid())\n\t\t{\n\t\t\tOptionalRelevantTags-&gt;AddTag(MissingTag);\n\t\t}\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n<\/pre><\/div>\n\n\n<p><\/p>\n\n\n\n<p>Hopefully that is everything (not sure if i have missed anything&#8230;), but this should allow you to finally get those Gameplay Tags for abilities under a bit more control, especially on large projects with a lot of abilities.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>When dealing with a lot of abilities, the block and cancel tags can get confusing and hard to keep managed. By using a relationship, we can apply block, cancel and activation tags from a more central location. This allows us to define what ability tags block and cancels what abilities, Example below: This is a <a href=\"https:\/\/www.thegames.dev\/?p=96\" class=\"more-link\">&#8230;<span class=\"screen-reader-text\">  Gameplay Tag Relationships<\/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-96","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":"When dealing with a lot of abilities, the block and cancel tags can get confusing and hard to keep managed. By using a relationship, we can apply block, cancel and activation tags from a more central location. This allows us to define what ability tags block and cancels what abilities, Example below: This is a relationship for the Ability tag:..","_links":{"self":[{"href":"https:\/\/www.thegames.dev\/index.php?rest_route=\/wp\/v2\/posts\/96","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=96"}],"version-history":[{"count":7,"href":"https:\/\/www.thegames.dev\/index.php?rest_route=\/wp\/v2\/posts\/96\/revisions"}],"predecessor-version":[{"id":104,"href":"https:\/\/www.thegames.dev\/index.php?rest_route=\/wp\/v2\/posts\/96\/revisions\/104"}],"wp:attachment":[{"href":"https:\/\/www.thegames.dev\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=96"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.thegames.dev\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=96"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.thegames.dev\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=96"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}