diff --git a/Source/Editor/Surface/Archetypes/BehaviorTree.cs b/Source/Editor/Surface/Archetypes/BehaviorTree.cs index b90bcdc55..c6fc4c35d 100644 --- a/Source/Editor/Surface/Archetypes/BehaviorTree.cs +++ b/Source/Editor/Surface/Archetypes/BehaviorTree.cs @@ -246,14 +246,6 @@ namespace FlaxEditor.Surface.Archetypes if (highlightBox != null) Render2D.DrawRectangle(highlightBox.Bounds, style.BorderHighlighted, 2f); - // Debug Info - if (!string.IsNullOrEmpty(_debugInfo)) - { - // Draw an extra background to cover the archetype color colored node background and make text more legible - Render2D.FillRectangle(new Rectangle(0, _headerRect.Bottom + 4, Width, Height - _headerRect.Bottom - 4), style.BackgroundHighlighted); - Render2D.DrawText(style.FontSmall, _debugInfo, new Rectangle(4, _headerRect.Bottom + 7, _debugInfoSize), style.Foreground, scale: 0.8f); - } - // Debug relevancy outline if (_debugRelevant) { @@ -546,6 +538,21 @@ namespace FlaxEditor.Surface.Archetypes } } + public override void Draw() + { + base.Draw(); + + var style = Style.Current; + + // Debug Info + if (!string.IsNullOrEmpty(_debugInfo)) + { + // Draw an extra background to cover the archetype color colored node background and make text more legible + Render2D.FillRectangle(new Rectangle(0, _headerRect.Bottom + 4, Width, Height - _headerRect.Bottom - 4), style.BackgroundHighlighted); + Render2D.DrawText(style.FontSmall, _debugInfo, new Rectangle(4, _headerRect.Bottom + 7, _debugInfoSize), style.Foreground, scale: 0.8f); + } + } + public override void ResizeAuto() { if (Surface == null) @@ -731,7 +738,7 @@ namespace FlaxEditor.Surface.Archetypes if (_debugInfoSize.X > 0) { width = Mathf.Max(width, _debugInfoSize.X + 8.0f); - height += _debugInfoSize.Y + 8.0f; + height += _debugInfoSize.Y + 1.0f; } return new Float2(width + FlaxEditor.Surface.Constants.NodeCloseButtonSize * 2, height + FlaxEditor.Surface.Constants.NodeHeaderHeight); } @@ -798,6 +805,12 @@ namespace FlaxEditor.Surface.Archetypes var style = Style.Current; + // Debug Info + if (!string.IsNullOrEmpty(_debugInfo)) + { + Render2D.DrawText(style.FontSmall, _debugInfo, new Rectangle(4, _headerRect.Bottom, _debugInfoSize), style.Foreground, TextAlignment.Near, TextAlignment.Center, TextWrapping.NoWrap, 1, 0.8f); + } + // Outline if (!_isSelected) { diff --git a/Source/Engine/AI/BehaviorKnowledgeSelector.h b/Source/Engine/AI/BehaviorKnowledgeSelector.h index 635244d07..9cb0578a8 100644 --- a/Source/Engine/AI/BehaviorKnowledgeSelector.h +++ b/Source/Engine/AI/BehaviorKnowledgeSelector.h @@ -34,6 +34,11 @@ API_STRUCT(NoDefault, MarshalAs=StringAnsi) struct FLAXENGINE_API BehaviorKnowle return Path == other.Path; } + FORCE_INLINE operator bool() const + { + return Path.HasChars(); + } + BehaviorKnowledgeSelectorAny& operator=(const StringAnsiView& other) noexcept { Path = other; @@ -46,12 +51,12 @@ API_STRUCT(NoDefault, MarshalAs=StringAnsi) struct FLAXENGINE_API BehaviorKnowle return *this; } - operator StringAnsi() const + FORCE_INLINE operator StringAnsi() const { return Path; } - String ToString() const + FORCE_INLINE String ToString() const { return Path.ToString(); } diff --git a/Source/Engine/AI/BehaviorTreeNodes.cpp b/Source/Engine/AI/BehaviorTreeNodes.cpp index 21cfe4c95..08c7403c0 100644 --- a/Source/Engine/AI/BehaviorTreeNodes.cpp +++ b/Source/Engine/AI/BehaviorTreeNodes.cpp @@ -48,6 +48,31 @@ bool IsAssignableFrom(const StringAnsiView& to, const StringAnsiView& from) return false; } +#if USE_EDITOR + +const Char* ComparisonChars(BehaviorValueComparison comp) +{ + switch (comp) + { + case BehaviorValueComparison::Equal: + return TEXT("=="); + case BehaviorValueComparison::NotEqual: + return TEXT("!="); + case BehaviorValueComparison::Less: + return TEXT("<"); + case BehaviorValueComparison::LessEqual: + return TEXT("<="); + case BehaviorValueComparison::Greater: + return TEXT(">"); + case BehaviorValueComparison::GreaterEqual: + return TEXT(">="); + default: + return TEXT("?"); + } +} + +#endif + BehaviorUpdateResult BehaviorTreeNode::InvokeUpdate(const BehaviorUpdateContext& context) { ASSERT_LOW_LAYER(_executionIndex != -1); @@ -699,11 +724,33 @@ bool BehaviorTreeKnowledgeConditionalDecorator::CanUpdate(const BehaviorUpdateCo return BehaviorKnowledge::CompareValues((float)ValueA.Get(context.Knowledge), ValueB, Comparison); } +#if USE_EDITOR + +String BehaviorTreeKnowledgeConditionalDecorator::GetDebugInfo(const BehaviorUpdateContext& context) const +{ + if (ValueA) + return String::Format(TEXT("'{}' {} {}"), ValueA.ToString(), ComparisonChars(Comparison), ValueB); + return String::Empty; +} + +#endif + bool BehaviorTreeKnowledgeValuesConditionalDecorator::CanUpdate(const BehaviorUpdateContext& context) { return BehaviorKnowledge::CompareValues((float)ValueA.Get(context.Knowledge), (float)ValueB.Get(context.Knowledge), Comparison); } +#if USE_EDITOR + +String BehaviorTreeKnowledgeValuesConditionalDecorator::GetDebugInfo(const BehaviorUpdateContext& context) const +{ + if (ValueA && ValueB) + return String::Format(TEXT("'{}' {} '{}'"), ValueA.ToString(), ComparisonChars(Comparison), ValueB.ToString()); + return String::Empty; +} + +#endif + bool BehaviorTreeKnowledgeBooleanDecorator::CanUpdate(const BehaviorUpdateContext& context) { Variant value = Value.Get(context.Knowledge); @@ -712,6 +759,22 @@ bool BehaviorTreeKnowledgeBooleanDecorator::CanUpdate(const BehaviorUpdateContex return result; } +#if USE_EDITOR + +String BehaviorTreeKnowledgeBooleanDecorator::GetDebugInfo(const BehaviorUpdateContext& context) const +{ + String result; + if (Value) + { + result = Value.ToString(); + if (Invert) + result = TEXT("!") + result; + } + return result; +} + +#endif + bool BehaviorTreeHasTagDecorator::CanUpdate(const BehaviorUpdateContext& context) { bool result = false; @@ -722,8 +785,30 @@ bool BehaviorTreeHasTagDecorator::CanUpdate(const BehaviorUpdateContext& context return result; } +#if USE_EDITOR + +String BehaviorTreeHasTagDecorator::GetDebugInfo(const BehaviorUpdateContext& context) const +{ + if (Actor && Tag) + return String::Format(TEXT("'{}' Has Tag '{}'"), Actor.ToString(), Tag.ToString()); + return String::Empty; +} + +#endif + bool BehaviorTreeHasGoalDecorator::CanUpdate(const BehaviorUpdateContext& context) { Variant value; // TODO: use HasGoal in Knowledge to optimize this (goal struct is copied by selector accessor) return Goal.TryGet(context.Knowledge, value); } + +#if USE_EDITOR + +String BehaviorTreeHasGoalDecorator::GetDebugInfo(const BehaviorUpdateContext& context) const +{ + if (Goal) + return String::Format(TEXT("Has Goal '{}'"), Goal.ToString()); + return String::Empty; +} + +#endif diff --git a/Source/Engine/AI/BehaviorTreeNodes.h b/Source/Engine/AI/BehaviorTreeNodes.h index 05a472da7..154363dea 100644 --- a/Source/Engine/AI/BehaviorTreeNodes.h +++ b/Source/Engine/AI/BehaviorTreeNodes.h @@ -422,6 +422,9 @@ API_CLASS(Sealed) class FLAXENGINE_API BehaviorTreeKnowledgeConditionalDecorator public: // [BehaviorTreeNode] bool CanUpdate(const BehaviorUpdateContext& context) override; +#if USE_EDITOR + String GetDebugInfo(const BehaviorUpdateContext& context) const override; +#endif }; /// @@ -447,6 +450,9 @@ API_CLASS(Sealed) class FLAXENGINE_API BehaviorTreeKnowledgeValuesConditionalDec public: // [BehaviorTreeNode] bool CanUpdate(const BehaviorUpdateContext& context) override; +#if USE_EDITOR + String GetDebugInfo(const BehaviorUpdateContext& context) const override; +#endif }; /// @@ -468,6 +474,9 @@ API_CLASS(Sealed) class FLAXENGINE_API BehaviorTreeKnowledgeBooleanDecorator : p public: // [BehaviorTreeNode] bool CanUpdate(const BehaviorUpdateContext& context) override; +#if USE_EDITOR + String GetDebugInfo(const BehaviorUpdateContext& context) const override; +#endif }; /// @@ -493,6 +502,9 @@ API_CLASS(Sealed) class FLAXENGINE_API BehaviorTreeHasTagDecorator : public Beha public: // [BehaviorTreeNode] bool CanUpdate(const BehaviorUpdateContext& context) override; +#if USE_EDITOR + String GetDebugInfo(const BehaviorUpdateContext& context) const override; +#endif }; /// @@ -510,4 +522,7 @@ API_CLASS(Sealed) class FLAXENGINE_API BehaviorTreeHasGoalDecorator : public Beh public: // [BehaviorTreeNode] bool CanUpdate(const BehaviorUpdateContext& context) override; +#if USE_EDITOR + String GetDebugInfo(const BehaviorUpdateContext& context) const override; +#endif };