Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion Source/Flow/Flow.Build.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ public Flow(ReadOnlyTargetRules target) : base(target)
"CoreUObject",
"DeveloperSettings",
"Engine",
"GameplayAbilities", // for FGameplayTagRequirements
"GameplayTags",
"MovieScene",
"MovieSceneTracks",
Expand Down
5 changes: 5 additions & 0 deletions Source/Flow/Private/Nodes/FlowNodeBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -990,6 +990,11 @@ EDataValidationResult UFlowNodeBase::ValidateNode()

bool UFlowNodeBase::TryAddValueToFormatNamedArguments(const FFlowNamedDataPinProperty& NamedDataPinProperty, FFormatNamedArguments& InOutArguments) const
{
if (NamedDataPinProperty.Name.IsNone() || !NamedDataPinProperty.DataPinValue.IsValid())
{
return false;
}

const FFlowDataPinValue& DataPinValue = NamedDataPinProperty.DataPinValue.Get();

const FFlowPinTypeName PinTypeName = DataPinValue.GetPinTypeName();
Expand Down
81 changes: 81 additions & 0 deletions Source/Flow/Private/Types/FlowGameplayTagUtils.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors

#include "Types/FlowGameplayTagUtils.h"

#include UE_INLINE_GENERATED_CPP_BY_NAME(FlowGameplayTagUtils)

bool FFlowGameplayTagRequirements::RequirementsMet(const FGameplayTagContainer& Container) const
{
const bool bHasRequired = Container.HasAll(RequireTags);
const bool bHasIgnored = Container.HasAny(IgnoreTags);
const bool bMatchQuery = TagQuery.IsEmpty() || TagQuery.Matches(Container);

return bHasRequired && !bHasIgnored && bMatchQuery;
}

bool FFlowGameplayTagRequirements::IsEmpty() const
{
return (RequireTags.Num() == 0 && IgnoreTags.Num() == 0 && TagQuery.IsEmpty());
}

FString FFlowGameplayTagRequirements::ToString() const
{
FString Str;

if (RequireTags.Num() > 0)
{
Str += FString::Printf(TEXT("require: %s "), *RequireTags.ToStringSimple());
}
if (IgnoreTags.Num() > 0)
{
Str += FString::Printf(TEXT("ignore: %s "), *IgnoreTags.ToStringSimple());
}
if (!TagQuery.IsEmpty())
{
Str += TagQuery.GetDescription();
}

return Str;
}

bool FFlowGameplayTagRequirements::operator==(const FFlowGameplayTagRequirements& Other) const
{
return RequireTags == Other.RequireTags && IgnoreTags == Other.IgnoreTags && TagQuery == Other.TagQuery;
}

bool FFlowGameplayTagRequirements::operator!=(const FFlowGameplayTagRequirements& Other) const
{
return !(*this == Other);
}

FGameplayTagQuery FFlowGameplayTagRequirements::ConvertTagFieldsToTagQuery() const
{
const bool bHasRequireTags = !RequireTags.IsEmpty();
const bool bHasIgnoreTags = !IgnoreTags.IsEmpty();

if (!bHasIgnoreTags && !bHasRequireTags)
{
return FGameplayTagQuery{};
}

// FGameplayTagContainer::RequirementsMet is HasAll(RequireTags) && !HasAny(IgnoreTags);
FGameplayTagQueryExpression RequiredTagsQueryExpression = FGameplayTagQueryExpression().AllTagsMatch().AddTags(RequireTags);
FGameplayTagQueryExpression IgnoreTagsQueryExpression = FGameplayTagQueryExpression().NoTagsMatch().AddTags(IgnoreTags);

FGameplayTagQueryExpression RootQueryExpression;
if (bHasRequireTags && bHasIgnoreTags)
{
RootQueryExpression = FGameplayTagQueryExpression().AllExprMatch().AddExpr(RequiredTagsQueryExpression).AddExpr(IgnoreTagsQueryExpression);
}
else if (bHasRequireTags)
{
RootQueryExpression = RequiredTagsQueryExpression;
}
else // bHasIgnoreTags
{
RootQueryExpression = IgnoreTagsQueryExpression;
}

// Build the expression
return FGameplayTagQuery::BuildQuery(RootQueryExpression);
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors
#pragma once

#include "GameplayEffectTypes.h"

#include "AddOns/FlowNodeAddOn.h"
#include "Interfaces/FlowPredicateInterface.h"
#include "Types/FlowGameplayTagUtils.h"

#include "FlowNodeAddOn_PredicateRequireGameplayTags.generated.h"

Expand Down Expand Up @@ -47,5 +46,5 @@ class UFlowNodeAddOn_PredicateRequireGameplayTags

/* Requirements to evaluate the Test Tags with. */
UPROPERTY(EditAnywhere, Category = Configuration)
FGameplayTagRequirements Requirements;
FFlowGameplayTagRequirements Requirements;
};
41 changes: 41 additions & 0 deletions Source/Flow/Public/Types/FlowGameplayTagUtils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors
#pragma once

#include "GameplayTagContainer.h"

#include "FlowGameplayTagUtils.generated.h"

/** Encapsulate require and ignore tags
* Adapted from FGameplayTagRequirements, but without the GameplayAbilities module dependency */
USTRUCT(BlueprintType)
struct FFlowGameplayTagRequirements
{
GENERATED_BODY()

/** All of these tags must be present */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = GameplayTags, meta = (DisplayName = "Must Have Tags"))
FGameplayTagContainer RequireTags;

/** None of these tags may be present */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = GameplayTags, meta = (DisplayName = "Must Not Have Tags"))
FGameplayTagContainer IgnoreTags;

/** Build up a more complex query that can't be expressed with RequireTags/IgnoreTags alone */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = GameplayTags, meta = (DisplayName = "Query Must Match"))
FGameplayTagQuery TagQuery;

/** True if all required tags and no ignore tags found */
FLOW_API bool RequirementsMet(const FGameplayTagContainer& Container) const;

/** True if neither RequireTags or IgnoreTags has any tags */
FLOW_API bool IsEmpty() const;

/** Return debug string */
FLOW_API FString ToString() const;

FLOW_API bool operator==(const FFlowGameplayTagRequirements& Other) const;
FLOW_API bool operator!=(const FFlowGameplayTagRequirements& Other) const;

/** Converts the RequireTags and IgnoreTags fields into an equivalent FGameplayTagQuery */
[[nodiscard]] FLOW_API FGameplayTagQuery ConvertTagFieldsToTagQuery() const;
};