bool UGameplayTagsManager::AddLeafTagToContainer(FGameplayTagContainer& TagContainer, FGameplayTag& Tag) { // Check tag is not already in container if (TagContainer.HasTag(Tag, EGameplayTagMatchType::Explicit, EGameplayTagMatchType::Explicit)) { return true; } // Check tag is not just a parent of an existing tag in the container for (auto It = TagContainer.CreateConstIterator(); It; ++It) { FGameplayTagContainer ParentTags = RequestGameplayTagParents(*It); if (ParentTags.HasTag(Tag, EGameplayTagMatchType::Explicit, EGameplayTagMatchType::Explicit)) { return false; } } // Remove any tags in the container that are a parent to this tag FGameplayTagContainer ParentTags = RequestGameplayTagParents(Tag); for (auto It = ParentTags.CreateConstIterator(); It; ++It) { if (TagContainer.HasTag(*It, EGameplayTagMatchType::Explicit, EGameplayTagMatchType::Explicit)) { TagContainer.RemoveTag(*It); } } // Add the tag TagContainer.AddTag(Tag); return true; }
void SGameplayTagWidget::VerifyAssetTagValidity() { FGameplayTagContainer LibraryTags; // Create a set that is the library of all valid tags TArray< TSharedPtr<FGameplayTagNode> > NodeStack; UGameplayTagsManager& TagsManager = IGameplayTagsModule::Get().GetGameplayTagsManager(); TagsManager.GetFilteredGameplayRootTags(TEXT(""), NodeStack); while (NodeStack.Num() > 0) { TSharedPtr<FGameplayTagNode> CurNode = NodeStack.Pop(); if (CurNode.IsValid()) { LibraryTags.AddTag(TagsManager.RequestGameplayTag(CurNode->GetCompleteTag())); NodeStack.Append(CurNode->GetChildTagNodes()); } } // Find and remove any tags on the asset that are no longer in the library for (int32 ContainerIdx = 0; ContainerIdx < TagContainers.Num(); ++ContainerIdx) { UObject* OwnerObj = TagContainers[ContainerIdx].TagContainerOwner.Get(); FGameplayTagContainer* Container = TagContainers[ContainerIdx].TagContainer; if (Container) { FGameplayTagContainer EditableContainer = *Container; FGameplayTagContainer InvalidTags; for (auto It = Container->CreateConstIterator(); It; ++It) { if (!LibraryTags.HasTag(*It, EGameplayTagMatchType::Explicit, EGameplayTagMatchType::Explicit)) { InvalidTags.AddTag(*It); } } if (InvalidTags.Num() > 0) { FString InvalidTagNames; for (auto InvalidIter = InvalidTags.CreateConstIterator(); InvalidIter; ++InvalidIter) { EditableContainer.RemoveTag(*InvalidIter); InvalidTagNames += InvalidIter->ToString() + TEXT("\n"); } SetContainer(Container, &EditableContainer, OwnerObj); FFormatNamedArguments Arguments; Arguments.Add(TEXT("Objects"), FText::FromString( InvalidTagNames )); FText DialogText = FText::Format( LOCTEXT("GameplayTagWidget_InvalidTags", "Invalid Tags that have been removed: \n\n{Objects}"), Arguments ); OpenMsgDlgInt( EAppMsgType::Ok, DialogText, LOCTEXT("GameplayTagWidget_Warning", "Warning") ); } } } }
FGameplayTagContainer UGameplayTagsManager::RequestGameplayTagParents(const FGameplayTag& GameplayTag) const { FGameplayTagContainer TagContainer; TagContainer.AddTag(GameplayTag); AddParentTags(TagContainer, GameplayTag); return TagContainer; }
void SGameplayTagWidget::OnTagUnchecked(TSharedPtr<FGameplayTagNode> NodeUnchecked) { FScopedTransaction Transaction( LOCTEXT("GameplayTagWidget_RemoveTags", "Remove Gameplay Tags")); if (NodeUnchecked.IsValid()) { UGameplayTagsManager& TagsManager = IGameplayTagsModule::Get().GetGameplayTagsManager(); for (int32 ContainerIdx = 0; ContainerIdx < TagContainers.Num(); ++ContainerIdx) { UObject* OwnerObj = TagContainers[ContainerIdx].TagContainerOwner.Get(); FGameplayTagContainer* Container = TagContainers[ContainerIdx].TagContainer; FGameplayTag Tag = TagsManager.RequestGameplayTag(NodeUnchecked->GetCompleteTag()); if (Container) { FGameplayTagContainer EditableContainer = *Container; EditableContainer.RemoveTag(Tag); TWeakPtr<FGameplayTagNode> ParentNode = NodeUnchecked->GetParentTagNode(); if (ParentNode.IsValid()) { // Check if there are other siblings before adding parent bool bOtherSiblings = false; for (auto It = ParentNode.Pin()->GetChildTagNodes().CreateConstIterator(); It; ++It) { Tag = TagsManager.RequestGameplayTag(It->Get()->GetCompleteTag()); if (EditableContainer.HasTag(Tag, EGameplayTagMatchType::Explicit, EGameplayTagMatchType::Explicit)) { bOtherSiblings = true; break; } } // Add Parent if (!bOtherSiblings) { Tag = TagsManager.RequestGameplayTag(ParentNode.Pin()->GetCompleteTag()); EditableContainer.AddTag(Tag); } } // Uncheck Children for (const auto& ChildNode : NodeUnchecked->GetChildTagNodes()) { UncheckChildren(ChildNode, EditableContainer); } SetContainer(Container, &EditableContainer, OwnerObj); } } } }
void UGameplayTagsManager::AddParentTags(FGameplayTagContainer& TagContainer, const FGameplayTag& GameplayTag) const { const TSharedPtr<FGameplayTagNode>* GameplayTagNode = GameplayTagNodeMap.Find(GameplayTag); if (GameplayTagNode) { TSharedPtr<FGameplayTagNode> Parent = (*GameplayTagNode)->GetParentTagNode().Pin(); if (Parent.IsValid()) { const FGameplayTag* Tag = GameplayTagNodeMap.FindKey(Parent); if (Tag) { TagContainer.AddTag(*Tag); AddParentTags(TagContainer, *Tag); } } } }
void UK2Node_GameplayCueEvent::GetMenuEntries(FGraphContextMenuBuilder& Context) const { Super::GetMenuEntries(Context); if (!IsCompatibleWithGraph(Context.CurrentGraph)) { return; } const FString FunctionCategory(TEXT("GameplayCue Event")); IGameplayTagsModule& GameplayTagsModule = IGameplayTagsModule::Get(); FGameplayTag RootTag = GameplayTagsModule.GetGameplayTagsManager().RequestGameplayTag(FName(TEXT("GameplayCue"))); FGameplayTagContainer CueTags = GameplayTagsModule.GetGameplayTagsManager().RequestGameplayTagChildren(RootTag); // Add a root GameplayCue function as a default CueTags.AddTag(RootTag); // Fixme: need to check if this function is already defined so that it can be reimplemented // -Checking MyBlueprint->GeneratedClass isn't enough since they may have added an event and not recompiled // -FEdGraphSchemaAction_K2AddCustomEvent does not check names/always ensures a valid name // -FEdGraphSchemaAction_K2AddEvent does check and recenters - but it looks at EventSignatureName/EventSignatureClass for equality and that // won't work here. // // Probably need a new EdGraphSchemaAction to do this properly. For now this is ok since they will get a compile error if they do drop in // two of the same GameplayCue even Nodes and it should be pretty clear that they can't do that. for (auto It = CueTags.CreateConstIterator(); It; ++It) { FGameplayTag Tag = *It; UK2Node_GameplayCueEvent* NodeTemplate = Context.CreateTemplateNode<UK2Node_GameplayCueEvent>(); NodeTemplate->CustomFunctionName = Tag.GetTagName(); const FString Category = FunctionCategory; const FText MenuDesc = NodeTemplate->GetNodeTitle(ENodeTitleType::ListView); const FString Tooltip = NodeTemplate->GetTooltipText().ToString(); const FString Keywords = NodeTemplate->GetKeywords(); TSharedPtr<FEdGraphSchemaAction_K2NewNode> NodeAction = FK2ActionMenuBuilder::AddNewNodeAction(Context, Category, MenuDesc, Tooltip, 0, Keywords); NodeAction->NodeTemplate = NodeTemplate; } }
void SGameplayTagWidget::OnTagChecked(TSharedPtr<FGameplayTagNode> NodeChecked) { FScopedTransaction Transaction( LOCTEXT("GameplayTagWidget_AddTags", "Add Gameplay Tags") ); UGameplayTagsManager& TagsManager = IGameplayTagsModule::Get().GetGameplayTagsManager(); for (int32 ContainerIdx = 0; ContainerIdx < TagContainers.Num(); ++ContainerIdx) { TWeakPtr<FGameplayTagNode> CurNode(NodeChecked); UObject* OwnerObj = TagContainers[ContainerIdx].TagContainerOwner.Get(); FGameplayTagContainer* Container = TagContainers[ContainerIdx].TagContainer; if (Container) { FGameplayTagContainer EditableContainer = *Container; bool bRemoveParents = false; while (CurNode.IsValid()) { FGameplayTag Tag = TagsManager.RequestGameplayTag(CurNode.Pin()->GetCompleteTag()); if (bRemoveParents == false) { bRemoveParents = true; if (bMultiSelect == false) { EditableContainer.RemoveAllTags(); } EditableContainer.AddTag(Tag); } else { EditableContainer.RemoveTag(Tag); } CurNode = CurNode.Pin()->GetParentTagNode(); } SetContainer(Container, &EditableContainer, OwnerObj); } } }
void FGameplayTagCustomization::OnPropertyValueChanged() { TagName = TEXT(""); if (StructPropertyHandle.IsValid() && EditableContainers.Num() > 0) { TArray<void*> RawStructData; StructPropertyHandle->AccessRawData(RawStructData); if (RawStructData.Num() > 0) { FGameplayTag* Tag = (FGameplayTag*)(RawStructData[0]); FGameplayTagContainer* Container = EditableContainers[0].TagContainer; if (Tag && Container) { Container->RemoveAllTags(); Container->AddTag(*Tag); TagName = Tag->ToString(); } } } }
FGameplayTagContainer FGameplayTagContainer::Filter(const FGameplayTagContainer& OtherContainer, TEnumAsByte<EGameplayTagMatchType::Type> TagMatchType, TEnumAsByte<EGameplayTagMatchType::Type> OtherTagMatchType) const { SCOPE_CYCLE_COUNTER(STAT_FGameplayTagContainer_Filter); FGameplayTagContainer ResultContainer; UGameplayTagsManager& TagManager = IGameplayTagsModule::GetGameplayTagsManager(); for (TArray<FGameplayTag>::TConstIterator OtherIt(OtherContainer.GameplayTags); OtherIt; ++OtherIt) { for (TArray<FGameplayTag>::TConstIterator It(this->GameplayTags); It; ++It) { if (TagManager.GameplayTagsMatch(*It, TagMatchType, *OtherIt, OtherTagMatchType) == true) { ResultContainer.AddTag(*It); } } } return ResultContainer; }
void FQueryEvaluator::ReadEditableQueryTags(UEditableGameplayTagQueryExpression* EditableQueryExpr) { // find the tag container to read into FGameplayTagContainer* Tags = nullptr; if (EditableQueryExpr->IsA(UEditableGameplayTagQueryExpression_AnyTagsMatch::StaticClass())) { Tags = &((UEditableGameplayTagQueryExpression_AnyTagsMatch*)EditableQueryExpr)->Tags; } else if (EditableQueryExpr->IsA(UEditableGameplayTagQueryExpression_AllTagsMatch::StaticClass())) { Tags = &((UEditableGameplayTagQueryExpression_AllTagsMatch*)EditableQueryExpr)->Tags; } else if (EditableQueryExpr->IsA(UEditableGameplayTagQueryExpression_NoTagsMatch::StaticClass())) { Tags = &((UEditableGameplayTagQueryExpression_NoTagsMatch*)EditableQueryExpr)->Tags; } ensure(Tags); if (Tags) { // parse tag set int32 const NumTags = GetToken(); if (bReadError) { return; } for (int32 Idx = 0; Idx < NumTags; ++Idx) { int32 const TagIdx = GetToken(); if (bReadError) { return; } FGameplayTag const Tag = Query.GetTagFromIndex(TagIdx); Tags->AddTag(Tag); } } }
void UK2Node_GameplayCueEvent::GetMenuActions(FBlueprintActionDatabaseRegistrar& ActionRegistrar) const { // actions get registered under specific object-keys; the idea is that // actions might have to be updated (or deleted) if their object-key is // mutated (or removed)... here we use the node's class (so if the node // type disappears, then the action should go with it) UClass* ActionKey = GetClass(); // to keep from needlessly instantiating a UBlueprintNodeSpawner, first // check to make sure that the registrar is looking for actions of this type // (could be regenerating actions for a specific asset, and therefore the // registrar would only accept actions corresponding to that asset) if (!ActionRegistrar.IsOpenForRegistration(ActionKey)) { return; } auto CustomizeCueNodeLambda = [](UEdGraphNode* NewNode, bool bIsTemplateNode, FName TagName) { UK2Node_GameplayCueEvent* EventNode = CastChecked<UK2Node_GameplayCueEvent>(NewNode); EventNode->CustomFunctionName = TagName; }; IGameplayTagsModule& GameplayTagsModule = IGameplayTagsModule::Get(); FGameplayTag RootTag = GameplayTagsModule.GetGameplayTagsManager().RequestGameplayTag(FName(TEXT("GameplayCue"))); FGameplayTagContainer CueTags = GameplayTagsModule.GetGameplayTagsManager().RequestGameplayTagChildren(RootTag); // Add a root GameplayCue function as a default CueTags.AddTag(RootTag); for (auto TagIt = CueTags.CreateConstIterator(); TagIt; ++TagIt) { UBlueprintNodeSpawner::FCustomizeNodeDelegate PostSpawnDelegate = UBlueprintNodeSpawner::FCustomizeNodeDelegate::CreateStatic(CustomizeCueNodeLambda, TagIt->GetTagName()); UBlueprintNodeSpawner* NodeSpawner = UBlueprintEventNodeSpawner::Create(GetClass(), TagIt->GetTagName()); check(NodeSpawner != nullptr); NodeSpawner->CustomizeNodeDelegate = PostSpawnDelegate; ActionRegistrar.AddBlueprintAction(ActionKey, NodeSpawner); } }
void UGameplayTagsManager::AddChildrenTags(FGameplayTagContainer& TagContainer, const FGameplayTag& GameplayTag, bool RecurseAll) const { const TSharedPtr<FGameplayTagNode>* GameplayTagNode = GameplayTagNodeMap.Find(GameplayTag); if (GameplayTagNode) { TArray< TSharedPtr<FGameplayTagNode> >& ChildrenNodes = (*GameplayTagNode)->GetChildTagNodes(); for (TSharedPtr<FGameplayTagNode> ChildNode : ChildrenNodes) { if (ChildNode.IsValid()) { const FGameplayTag* Tag = GameplayTagNodeMap.FindKey(ChildNode); if (Tag) { TagContainer.AddTag(*Tag); if (RecurseAll) { AddChildrenTags(TagContainer, *Tag, true); } } } } } }