diff --git a/Source/Engine/AI/BehaviorKnowledgeSelector.h b/Source/Engine/AI/BehaviorKnowledgeSelector.h index 96241a9d3..d27f5e963 100644 --- a/Source/Engine/AI/BehaviorKnowledgeSelector.h +++ b/Source/Engine/AI/BehaviorKnowledgeSelector.h @@ -3,6 +3,7 @@ #pragma once #include "Engine/Core/Types/Variant.h" +#include "Engine/Core/Types/VariantValueCast.h" #include "Engine/Serialization/SerializationFwd.h" class BehaviorKnowledge; @@ -70,7 +71,7 @@ API_STRUCT(InBuild, Template, MarshalAs=StringAnsi) struct FLAXENGINE_API Behavi // Gets the selected knowledge value (typed). FORCE_INLINE T Get(BehaviorKnowledge* knowledge) { - return (T)BehaviorKnowledgeSelectorAny::Get(knowledge); + return TVariantValueCast::Cast(BehaviorKnowledgeSelectorAny::Get(knowledge)); } // Tries to get the selected knowledge value (typed). Returns true if got value, otherwise false. @@ -79,7 +80,7 @@ API_STRUCT(InBuild, Template, MarshalAs=StringAnsi) struct FLAXENGINE_API Behavi Variant variant; if (BehaviorKnowledgeSelectorAny::TryGet(knowledge, variant)) { - value = (T)variant; + value = TVariantValueCast::Cast(variant); return true; } return false; diff --git a/Source/Engine/AI/BehaviorTreeNodes.cpp b/Source/Engine/AI/BehaviorTreeNodes.cpp index 1706a154d..20082c9d7 100644 --- a/Source/Engine/AI/BehaviorTreeNodes.cpp +++ b/Source/Engine/AI/BehaviorTreeNodes.cpp @@ -8,6 +8,7 @@ #if USE_CSHARP #include "Engine/Scripting/ManagedCLR/MClass.h" #endif +#include "Engine/Level/Actor.h" #include "Engine/Serialization/Serialization.h" bool IsAssignableFrom(const StringAnsiView& to, const StringAnsiView& from) @@ -445,3 +446,13 @@ bool BehaviorTreeKnowledgeValuesConditionalDecorator::CanUpdate(const BehaviorUp { return BehaviorKnowledge::CompareValues((float)ValueA.Get(context.Knowledge), (float)ValueB.Get(context.Knowledge), Comparison); } + +bool BehaviorTreeHasTagDecorator::CanUpdate(const BehaviorUpdateContext& context) +{ + bool result = false; + ::Actor* actor; + if (Actor.TryGet(context.Knowledge, actor) && actor) + result = actor->HasTag(Tag); + result ^= Invert; + return result; +} diff --git a/Source/Engine/AI/BehaviorTreeNodes.h b/Source/Engine/AI/BehaviorTreeNodes.h index 6d9716988..c8fd25e63 100644 --- a/Source/Engine/AI/BehaviorTreeNodes.h +++ b/Source/Engine/AI/BehaviorTreeNodes.h @@ -8,6 +8,9 @@ #include "Engine/Core/Collections/Array.h" #include "Engine/Core/Collections/BitArray.h" #include "Engine/Content/AssetReference.h" +#include "Engine/Level/Tags.h" + +class Actor; /// /// Base class for compound Behavior Tree nodes that composite child nodes. @@ -342,3 +345,28 @@ public: // [BehaviorTreeNode] bool CanUpdate(const BehaviorUpdateContext& context) override; }; + +/// +/// Checks if certain actor (from knowledge) has a given tag assigned. +/// +API_CLASS(Sealed) class FLAXENGINE_API BehaviorTreeHasTagDecorator : public BehaviorTreeDecorator +{ + DECLARE_SCRIPTING_TYPE_WITH_CONSTRUCTOR_IMPL(BehaviorTreeHasTagDecorator, BehaviorTreeDecorator); + API_AUTO_SERIALIZATION(); + + // The actor value from behavior's knowledge (blackboard, goal or sensor) to check against tag ownership. + API_FIELD(Attributes="EditorOrder(0)") + BehaviorKnowledgeSelector Actor; + + // The tag to check. + API_FIELD(Attributes="EditorOrder(10)") + Tag Tag; + + // If checked, inverts condition - checks if actor doesn't have a tag. + API_FIELD(Attributes="EditorOrder(20)") + bool Invert = false; + +public: + // [BehaviorTreeNode] + bool CanUpdate(const BehaviorUpdateContext& context) override; +}; diff --git a/Source/Engine/Core/Types/VariantValueCast.h b/Source/Engine/Core/Types/VariantValueCast.h new file mode 100644 index 000000000..562c15254 --- /dev/null +++ b/Source/Engine/Core/Types/VariantValueCast.h @@ -0,0 +1,25 @@ +// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. + +#pragma once + +#include "Engine/Core/Types/Variant.h" +#include "Engine/Core/Templates.h" + +// Helper utility to read Variant value with automatic casting to the template type (eg. cast ScriptingObject* to Actor*). +template +struct TVariantValueCast +{ + FORCE_INLINE static T Cast(const Variant& v) + { + return (T)v; + } +}; + +template +struct TVariantValueCast::Value>::Type> +{ + FORCE_INLINE static T* Cast(const Variant& v) + { + return ScriptingObject::Cast((ScriptingObject*)v); + } +};