/*************************************************************************/ /* File : CKBehavior.h */ /* Author : Nicolas Galinotti */ /* */ /* Virtools SDK */ /* Copyright (c) Virtools 2000, All Rights Reserved. */ /*************************************************************************/ #ifndef CKBEHAVIOR_H #define CKBEHAVIOR_H "$Id:$" #include "CKObject.h" #include "XObjectArray.h" #include "XPriorityQueue.h" struct BehaviorBlockData; struct BehaviorGraphData; /************************************************************************** {filename:CKBehavior} Name: CKBehavior Summary: Class for defining behaviors Remarks: + The CKBehavior class provides functionnalities for defining a behavior as a function or as a graph, to set various parameters about how and when the behavior is activated, to link them to other behaviors through CKBehaviorLink instances or to create them from CKBehaviorPrototype, for creating CKBehaviorPrototype from a behavior. + Each behavior has an owner, which is an instance of CKBeObject. The owner saves its behaviors with itself when saved into a file, or with CKSaveObjectState. The behavior usually applies to its owner, or to parts of its owner, though it can apply to other objects as well. If the behavior is a graph, all of its sub-behaviors inherits the same owner. + A Behavior is considered to as a box with inputs/ouputs and input,output and local parameters. Inside this box the behavior may be implemented using a graph of sub-behaviors or using a C++ function, depending on which method UseGraph or UseFunction has been specified. For behaviors using a function, the function may be defined internally, or in a external code file (dll, or other depending on the OS). + If you want to implement the behavior with a C++ funtion without defining a prototype, you should specify the function with the SetFunction() method. This function will be called at each process cycle, with one argument: the elapsed time since the last call, in milliseconds. + Behaviors are real time pieces of algorithm. When a behavior is active and enabled or is waiting for a message, it gets called in an iterative fashion at each loop of the process cycle. Each time it is called, the behavior does the minimum amount of processing depending on the time elapsed since the last time it was called. No behavior should hold on the CPU more than necessary, as each other active behaviors have to be called in the process cycle. + Behavior execution is managed by its owner, and by the scene to which its owner belongs. A CKBeObject instance is declared in its scene as being active and/or enabled with the CKScene::SetObjectFlags or CKScene::Activate method. A disabled object's behaviors are never called. Setting an object as active has the effect of having all of its behaviors called during the next process cycle. If you add an object to a scene and want its behaviors to be called when the scene is started with CKLevel::LaunchScene, you should set the flags accordingly with CKScene::SetObjectFlags. If you don't use Scene or have only one scene (the level) setting the flags is not necessary. + If the behavior is implemented using an execution function, this function decides whether the behavior should remain active or not. This is done with the return value of the function. If the return value is CKBR_OK, the behavior is considered as being over and is set to be inactive at the next process cycle. It may become active again at a later time, if one of its entries gets activated. + If the behavior is implemented as a graph of sub-behaviors, it is considered active if at least one of its sub-behaviors is active, and will be called during the next process cycle. + Behavior prototypes are a sort of model of behaviors. One can create a behavior from a prototype. Prototypes are typically used in external pieces of code like dlls. Prototypes are typically used for storing reusable behaviors. + Behaviors usually have inputs and outputs, which may be active or inactive. The inputs and outputs have no value, they are like switches which may be on or off. A behavior is activated if at least one of its entries is active. When all of the entries are inactive and all of its sub-behaviors are inactive and the behavior is not waiting for a message, the behavior is deactivated. + The outputs of a behavior are activated or deactivated by the behavior, as a result of its internal processing and states. Outputs of a behavior may be linked to other behaviors through links, in which case activating an output will trigger the activation of one or more other behaviors. This is the basic principle through which processing travels along behaviors. + A behavior may have zero or more inputs and zero or more outputs. The output of a behavior may be linked to an input of the same behavior. + Outputs of a behavior are linked to inputs or other behaviors through instances of CKBehaviorLink. These links have an activation delay, which may be 0. If it is zero, the input gets activated at the same process cycle which may introduce infinite loops. Such Loops are detected at execution time when exceding the value defined by CKSetBehaviorMaxIteration (Default : 8000) + Behaviors may exchange or store values using parameters, which are instances of CKParameterOut, CKParameterIn. These values may be arbitrarily complex, and you may define your own type of parameters. CKParameterOut instances are used by the behavior to export values, and CKParameterIn instances are used to get values from the outside. + Components of a behavior like parameters, I/O may be named, like all objects of CK. This name is only a conveniency and is not mandatory. These names are saved in the state or in the file with the behavior and may eat up space, so you should use them carefully if this is an issue for your application. + Behaviors may wait for messages. They specify that they wait for messages by registering themselves with the message manager, using the CKMessageManager::RegisterWait method and by providing an input or an output to activate when a corresponding message is received. + The class id of CKBehavior is CKCID_BEHAVIOR. See also: CKBeObject, CKScene, CKParameterOut, CKParameterIn, CKBehaviorLink, CKBehaviorPrototype ************************************************************************************/ class CKBehavior : public CKSceneObject { friend class CKBehaviorManager; friend class CKBeObject; friend class CKFile; friend class CKParameterIn; friend class CKParameter; friend class CKParameterLocal; friend class CKParameterOut; friend class CKParameterOperation; friend class CKBehaviorLink; friend class CKBehaviorIO; public : //---------------------------------------------------------------- // Behavior Typage CK_BEHAVIOR_TYPE GetType(); void SetType(CK_BEHAVIOR_TYPE); void SetFlags(CK_BEHAVIOR_FLAGS ); CK_BEHAVIOR_FLAGS GetFlags(); CK_BEHAVIOR_FLAGS ModifyFlags(CKDWORD Add,CKDWORD Remove); //---------- BuildingBlock or Graph void UseGraph(); void UseFunction(); int IsUsingFunction(); //---------------------------------------------------------------- // Targetable Behavior CKBOOL IsTargetable(); CKBeObject* GetTarget(); CKERROR UseTarget(CKBOOL Use=TRUE); CKBOOL IsUsingTarget(); CKParameterIn* GetTargetParameter(); void SetAsTargetable(CKBOOL target=TRUE); CKParameterIn* ReplaceTargetParameter(CKParameterIn* targetParam); CKParameterIn* RemoveTargetParameter(); //---------------------------------------------------------------- // Object type to which this behavior applies CK_CLASSID GetCompatibleClassID(); void SetCompatibleClassID(CK_CLASSID); //---------------------------------------------------------------- // Execution Function void SetFunction(CKBEHAVIORFCT fct); CKBEHAVIORFCT GetFunction(); //---------------------------------------------------------------- // Callbacks Function void SetCallbackFunction(CKBEHAVIORCALLBACKFCT fct); int CallCallbackFunction(CKDWORD Message); int CallSubBehaviorsCallbackFunction(CKDWORD Message,CKGUID* behguid=NULL); //-------------------------------------------------------------- // RunTime Functions CKBOOL IsActive(); int Execute(float deltat); //-------------------------------------------------------------- // CKBOOL IsParentScriptActiveInScene(CKScene *scn); int GetShortestDelay(CKBehavior* beh); //-------------------------------------------------------------- // Owner Functions CKBeObject *GetOwner(); CKBehavior *GetParent(); CKBehavior *GetOwnerScript(); //---------------------------------------------------------------- // Creation From prototype CKERROR InitFromPrototype(CKBehaviorPrototype *proto); CKERROR InitFromGuid(CKGUID Guid); CKERROR InitFctPtrFromGuid(CKGUID Guid); CKERROR InitFctPtrFromPrototype(CKBehaviorPrototype *proto); CKGUID GetPrototypeGuid(); CKBehaviorPrototype* GetPrototype(); CKSTRING GetPrototypeName(); CKDWORD GetVersion(); void SetVersion(CKDWORD version); //---------------------------------------------------------------- // Outputs void ActivateOutput(int pos,CKBOOL active=TRUE); CKBOOL IsOutputActive(int pos); CKBehaviorIO* RemoveOutput(int pos); CKERROR DeleteOutput(int pos); CKBehaviorIO* GetOutput(int pos); int GetOutputCount(); int GetOutputPosition(CKBehaviorIO *pbio); int AddOutput(CKSTRING name); CKBehaviorIO* ReplaceOutput(int pos,CKBehaviorIO *io); CKBehaviorIO* CreateOutput(CKSTRING name); void InsertOutput(int pos,CKBehaviorIO *io); //---------------------------------------------------------------- // Inputs void ActivateInput(int pos,CKBOOL active=TRUE); CKBOOL IsInputActive(int pos); CKBehaviorIO* RemoveInput(int pos); CKERROR DeleteInput(int pos); CKBehaviorIO* GetInput(int pos); int GetInputCount(); int GetInputPosition(CKBehaviorIO *pbio); int AddInput(CKSTRING name); CKBehaviorIO* ReplaceInput(int pos,CKBehaviorIO *io); CKBehaviorIO* CreateInput(CKSTRING name); void InsertInput(int pos,CKBehaviorIO *io); //---------------------------------------------------------------- // inputs Parameters CKERROR ExportInputParameter(CKParameterIn *p); CKParameterIn* CreateInputParameter(CKSTRING name,CKParameterType type); CKParameterIn* CreateInputParameter(CKSTRING name,CKGUID guid); CKParameterIn* InsertInputParameter(int pos,CKSTRING name,CKParameterType type); void InsertInputParameter(int pos,CKParameterIn *in); void AddInputParameter(CKParameterIn *in); int GetInputParameterPosition(CKParameterIn *); CKParameterIn* GetInputParameter(int pos); CKParameterIn* RemoveInputParameter(int pos); CKParameterIn* ReplaceInputParameter(int pos,CKParameterIn *param); int GetInputParameterCount(); CKERROR GetInputParameterValue(int pos,void *buf); void* GetInputParameterReadDataPtr(int pos); CKObject* GetInputParameterObject(int pos); CKBOOL IsInputParameterEnabled(int pos); void EnableInputParameter(int pos,CKBOOL enable); //---------------------------------------------------------------- // outputs Parameters CKERROR ExportOutputParameter(CKParameterOut *p); CKParameterOut* CreateOutputParameter(CKSTRING name,CKParameterType type); CKParameterOut* CreateOutputParameter(CKSTRING name,CKGUID guid); CKParameterOut* InsertOutputParameter(int pos,CKSTRING name,CKParameterType type); void InsertOutputParameter(int pos,CKParameterOut* p); CKParameterOut* GetOutputParameter(int pos); int GetOutputParameterPosition(CKParameterOut*); CKParameterOut* ReplaceOutputParameter(int pos,CKParameterOut *p); CKParameterOut* RemoveOutputParameter(int pos); void AddOutputParameter(CKParameterOut *out); int GetOutputParameterCount(); CKERROR GetOutputParameterValue(int pos,void *buf); CKERROR SetOutputParameterValue(int pos,const void *buf,int size=0); void* GetOutputParameterWriteDataPtr(int pos); CKERROR SetOutputParameterObject(int pos,CKObject *obj); CKObject* GetOutputParameterObject(int pos); CKBOOL IsOutputParameterEnabled(int pos); void EnableOutputParameter(int pos,CKBOOL enable); void SetInputParameterDefaultValue(CKParameterIn *pin,CKParameter* plink); //---------------------------------------------------------------- // Local Parameters CKParameterLocal* CreateLocalParameter(CKSTRING name,CKParameterType type); CKParameterLocal* CreateLocalParameter(CKSTRING name,CKGUID guid); CKParameterLocal* GetLocalParameter(int pos); CKParameterLocal* RemoveLocalParameter(int pos); void AddLocalParameter(CKParameterLocal *loc); int GetLocalParameterPosition(CKParameterLocal *); int GetLocalParameterCount(); CKERROR GetLocalParameterValue(int pos,void *buf); CKERROR SetLocalParameterValue(int pos,const void *buf,int size=0); void* GetLocalParameterWriteDataPtr(int pos); void* GetLocalParameterReadDataPtr(int pos); CKObject* GetLocalParameterObject(int pos); CKERROR SetLocalParameterObject(int pos,CKObject *obj); CKBOOL IsLocalParameterSetting(int pos); CKParameterLocal* InsertLocalParameter(int pos,CKSTRING name,CKParameterType type); void InsertLocalParameter(int pos,CKParameterLocal* p); //---------------------------------------------------------------- // Run Time Graph : Activation void Activate(CKBOOL Active = TRUE,CKBOOL breset = FALSE); //---------------------------------------------------------------- // Run Time Graph : Sub Behaviors CKERROR AddSubBehavior(CKBehavior *cbk); CKBehavior * RemoveSubBehavior(CKBehavior *cbk); CKBehavior * RemoveSubBehavior(int pos); CKBehavior * GetSubBehavior(int pos); int GetSubBehaviorCount(); //---------------------------------------------------------------- // Run Time Graph : Links between sub behaviors CKERROR AddSubBehaviorLink(CKBehaviorLink *cbkl); CKBehaviorLink * RemoveSubBehaviorLink(CKBehaviorLink *cbkl); CKBehaviorLink * RemoveSubBehaviorLink(int pos); CKBehaviorLink * GetSubBehaviorLink(int pos); int GetSubBehaviorLinkCount(); //---------------------------------------------------------------- // Run Time Graph : Parameter Operation CKERROR AddParameterOperation(CKParameterOperation *op); CKParameterOperation * GetParameterOperation(int pos); CKParameterOperation * RemoveParameterOperation(int pos); CKParameterOperation * RemoveParameterOperation(CKParameterOperation *op); int GetParameterOperationCount(); //---------------------------------------------------------------- // Run Time Graph : Behavior Priority int GetPriority(); void SetPriority(int priority); //------- Profiling --------------------- float GetLastExecutionTime(); //------------------------------------------------------------------------- // Internal functions #ifdef DOCJETDUMMY // DOCJET secret macro #else CKERROR SetOwner(CKBeObject *,CKBOOL callback = TRUE); CKERROR SetSubBehaviorOwner(CKBeObject *o,CKBOOL callback = TRUE); void NotifyEdition(); void NotifySettingsEdition(); CKStateChunk* GetInterfaceChunk(); void SetInterfaceChunk(CKStateChunk *state); CKBehavior(CKContext *Context,CKSTRING name=NULL); virtual ~CKBehavior(); virtual CK_CLASSID GetClassID(); virtual void PreSave(CKFile *file,CKDWORD flags); virtual CKStateChunk* Save(CKFile *file,CKDWORD flags); virtual CKERROR Load(CKStateChunk *chunk,CKFile* file); virtual void PostLoad(); virtual void PreDelete(); virtual int GetMemoryOccupation(); virtual CKBOOL IsObjectUsed(CKObject* obj,CK_CLASSID cid); //-------------------------------------------- // Dependencies functions {Secret} virtual CKERROR PrepareDependencies(CKDependenciesContext& context, CKBOOL iCaller = TRUE); virtual CKERROR RemapDependencies(CKDependenciesContext& context); virtual CKERROR Copy(CKObject& o,CKDependenciesContext& context); //-------------------------------------------- // Class Registering {secret} static CKSTRING GetClassName(); static int GetDependenciesCount(int mode); static CKSTRING GetDependencies(int i,int mode); static void Register(); static CKBehavior* CreateInstance(CKContext *Context); static void ReleaseInstance(CKContext* iContext,CKBehavior*); static CK_CLASSID m_ClassID; // Dynamic Cast method (returns NULL if the object can't be casted) static CKBehavior* Cast(CKObject* iO) { return CKIsChildClassOf(iO,CKCID_BEHAVIOR)?(CKBehavior*)iO:NULL; } void Reset(); void ErrorMessage(CKSTRING Error,CKSTRING Context,CKBOOL ShowOwner=TRUE,CKBOOL ShowScript=TRUE); void ErrorMessage(CKSTRING Error,CKDWORD Context,CKBOOL ShowOwner=TRUE,CKBOOL ShowScript=TRUE); void SetPrototypeGuid(CKGUID ckguid); protected : CK_ID m_Owner; CK_ID m_BehParent; XSObjectPointerArray m_InputArray; XSObjectPointerArray m_OutputArray; XSObjectPointerArray m_InParameter; XSObjectPointerArray m_OutParameter; XSObjectPointerArray m_LocalParameter; CK_CLASSID m_CompatibleClassID; int m_Priority; CKDWORD m_Flags; CKStateChunk * m_InterfaceChunk; BehaviorGraphData* m_GraphData; BehaviorBlockData* m_BlockData; float m_LastExecutionTime; CK_ID m_InputTargetParam; void SetParent(CKBehavior *parent); void SortSubs(); void ResetExecutionTime(); void ExecuteStepStart(); int ExecuteStep(float delta,CKDebugContext* Context); void WarnInfiniteLoop(); int InternalGetShortestDelay(CKBehavior* beh,XObjectPointerArray& behparsed); void CheckIOsActivation(); void CheckBehaviorActivity(); int ExecuteFunction(); void FindNextBehaviorsToExecute(CKBehavior* beh); void HierarchyPostLoad(); static int BehaviorPrioritySort(CKObject *o1,CKObject *o2); static int BehaviorPrioritySort(const void *elem1, const void *elem2); void ApplyPatchLoad(); #endif // Docjet secret macro }; #endif