// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. #pragma once #include "Engine/Core/Collections/Array.h" #include "Engine/Scripting/SerializableScriptingObject.h" #include "BehaviorTypes.h" /// /// Base class for Behavior Tree nodes. /// API_CLASS(Abstract) class FLAXENGINE_API BehaviorTreeNode : public SerializableScriptingObject { DECLARE_SCRIPTING_TYPE_WITH_CONSTRUCTOR_IMPL(BehaviorTreeNode, SerializableScriptingObject); friend class Behavior; friend class BehaviorTreeGraph; friend class BehaviorKnowledge; friend class BehaviorTreeSubTreeNode; friend class BehaviorTreeCompoundNode; protected: // Raw memory byte offset from the start of the behavior memory block. API_FIELD(ReadOnly) int32 _memoryOffset = 0; // Execution index of the node within tree. API_FIELD(ReadOnly) int32 _executionIndex = -1; // Parent node that owns this node (parent composite or decorator attachment node). API_FIELD(ReadOnly) BehaviorTreeNode* _parent = nullptr; private: Array> _decorators; public: /// /// Node user name (eg. Follow Enemy, or Pick up Weapon). /// API_FIELD() String Name; /// /// Initializes node state. Called after whole tree is loaded and nodes hierarchy is setup. /// /// Node owner asset. API_FUNCTION() virtual void Init(BehaviorTree* tree) { } /// /// Gets the node instance state size. A chunk of the valid memory is passed via InitState to setup that memory chunk (one per-behavior). /// API_FUNCTION() virtual int32 GetStateSize() const { return 0; } /// /// Initializes node instance state. Called when starting logic simulation for a given behavior. Call constructor of the state container. /// /// Behavior update context data. API_FUNCTION() virtual void InitState(const BehaviorUpdateContext& context) { } /// /// Cleanups node instance state. Called when stopping logic simulation for a given behavior. Call destructor of the state container. /// /// Behavior update context data. API_FUNCTION() virtual void ReleaseState(const BehaviorUpdateContext& context) { } /// /// Updates node logic. /// /// Behavior update context data. /// Operation result enum. API_FUNCTION() virtual BehaviorUpdateResult Update(const BehaviorUpdateContext& context) { return BehaviorUpdateResult::Success; } #if USE_EDITOR /// /// Gets the node debug state text (multiline). Used in Editor-only to display nodes state. Can be called without valid Behavior/Knowledge/Memory to display default debug info (eg. node properties). /// /// Behavior context data. /// Debug info text (multiline). API_FUNCTION() virtual String GetDebugInfo(const BehaviorUpdateContext& context) const { return String::Empty; } #endif // Helper utility to update node with state creation/cleanup depending on node relevancy. BehaviorUpdateResult InvokeUpdate(const BehaviorUpdateContext& context); // Helper utility to make node relevant and init it state. virtual void BecomeRelevant(const BehaviorUpdateContext& context); // Helper utility to make node irrelevant and release its state (including any nested nodes). virtual void BecomeIrrelevant(const BehaviorUpdateContext& context); // [SerializableScriptingObject] void Serialize(SerializeStream& stream, const void* otherObj) override; void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override; public: // Returns the typed node state at the given memory address. template T* GetState(void* memory) const { ASSERT((int32)sizeof(T) <= GetStateSize()); return reinterpret_cast((byte*)memory + _memoryOffset); } }; /// /// Base class for Behavior Tree node decorators. Decorators can implement conditional filtering or override node logic and execution flow. /// API_CLASS(Abstract) class FLAXENGINE_API BehaviorTreeDecorator : public BehaviorTreeNode { DECLARE_SCRIPTING_TYPE_WITH_CONSTRUCTOR_IMPL(BehaviorTreeDecorator, BehaviorTreeNode); /// /// Checks if the node can be updated (eg. decorator can block it depending on the gameplay conditions or its state). /// /// Behavior update context data. /// True if can update, otherwise false to block it. API_FUNCTION() virtual bool CanUpdate(const BehaviorUpdateContext& context) { return true; } /// /// Called after node update to post-process result or perform additional action. /// /// Behavior update context data. /// The node update result. Can be modified by the decorator (eg. to force success). API_FUNCTION() virtual void PostUpdate(const BehaviorUpdateContext& context, API_PARAM(ref) BehaviorUpdateResult& result) { } };