//TODO big update /* add setting bool freeze => stop remapping parameters, and check that target is compatible add setting bool execute in real time => does not execute in 1 frame as now (return CKBR_ACTIVATENEXTFRAME) put all these settings in a flag - register flag param hidden put target in input parameter so that user can then change it on the fly reset,wait for completion,stop at exit,no parameter restore,freeze io mapping,real time execute, CHECK TARGET & MAPPED IOS */ ///////////////////////////////////////////////////// ///////////////////////////////////////////////////// // // CallBehavior // ///////////////////////////////////////////////////// ///////////////////////////////////////////////////// #include "CKALL.h" #include "CallBehaviorCallback.h" //#include "Winuser.h" //#include "Windows.h" #define CALLBEHAVIOR_NAME "Call Behavior" //original guid, remove when integration #define CALLBEHAVIOR_GUID CKGUID(0x360a720d,0x7fa42f94) //#define CALLBEHAVIOR_GUID CKGUID(0x360a720d,0x7fa42f95) #define NARRATIVES_CALLBEHAVIOR_SETTING CKGUID(0x5bc80700,0x24183450) #define EXECUTE_TARGET() \ CKERROR result = CK_OK; \ if (flags & eSetting_Hijack_Parameters_Once) \ result = target->Execute(behcontext.DeltaTime); /*just execute, no more hijack*/\ else \ { \ BehaviorsParameters behParams; \ if (flags & eSetting_Parameter_Restore) \ behParams.SaveBehaviorParameters(target);/*save parameters sources*/ \ BehaviorsParameters::SetBehaviorParameters(beh,target);/*hijack parameters*/ \ \ if (flags & eSetting_SaveInternalStates) \ { \ BehaviorInternalStates locals_currentstate; \ BehaviorInternalStates locals_relativestate; \ \ /*Before execution: >save current state >load state relative to caller*/ \ locals_currentstate.SaveAllSubBehaviorLocalParameterValues(target); \ beh->GetLocalParameterValue(ePL_CHUNK_FOR_SUBLOCALS,&locals_relativestate.m_Chunk);\ locals_relativestate.LoadAllSubBehaviorLocalParameterValues(target); \ \ result = target->Execute(behcontext.DeltaTime);/*execute*/ \ \ /*After execution: >save state relative to caller >load last current state*/\ locals_relativestate.SaveAllSubBehaviorLocalParameterValues(target); \ locals_currentstate.LoadAllSubBehaviorLocalParameterValues(target); \ } \ else \ result = target->Execute(behcontext.DeltaTime);/*execute*/ \ \ if (flags & eSetting_Parameter_Restore) \ behParams.LoadBehaviorParameters(target);/*restore parameters sources*/ \ } \ CKObjectDeclaration *FillBehaviorCallBehavior2Decl(); CKERROR CreateCallBehavior2Proto(CKBehaviorPrototype **); int CallBehavior2(const CKBehaviorContext& context); CKERROR CallBehavior2Callback(const CKBehaviorContext& context); //compatibility with V1 from 4.1.0.37 added.... int CallBehavior(const CKBehaviorContext& context); CKERROR CallBehaviorCallback(const CKBehaviorContext& context); //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // enums & defines //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// enum SETTINGS { eSetting_Reset =1, //reset behavior on execute eSetting_Wait_for_Completion =2, //wait for completion of behavior instead of just 1st frame links eSetting_Stop_at_Exit =4, //do not activate output links of target=>output of targets are deactivated eSetting_Parameter_Restore =8, //do restore parameters hijacking of target after execution eSetting_Hijack_Parameters_Once =16,//hijack parameter only once at the 1st execution. //PRIORITY>eSetting_Parameter_Restore eSetting_Freeze_IO_mapping =32,//do not remapped ios on target change eSetting_Real_Time_Execution =64,//if target execution last several frames, then execute it in that time and not only the whole in one frame //PRIORITY>eSetting_Wait_for_Completion, eSetting_Check_Proto_Validity =128,//check prototype validity eSetting_SaveInternalStates =256,//save local /not settings or target & sub behavior of target & active states eSetting_PrivateCheckProto =eSetting_Freeze_IO_mapping+eSetting_Check_Proto_Validity,//check in code,private eSetting_InExecution =65536, //currently executed }; enum INS { eI_INS, //mapped inputs }; enum OUTS { eO_OUTS, //mapped outputs }; enum PINS { ePI_TARGET, //target behavior ePI_INPUTS, //mapped inputs }; enum POUTS { ePO_OUTPUTS, //mapped outputs }; enum PLOCALS { ePL_SETTINGS, //settings ePL_MAX_RECURSION_DEPTH, //max recursive depth ePL_RECURSION_DEPTH, //current recursive depth ePL_CHUNK_FOR_SUBLOCALS, //ckstatechunk for locals of subbehaviors }; //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // save parameter links //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// struct BehaviorsParameters { int sourcesCount; CK_ID* sources; int destinationsCount; CK_ID** destinations; BehaviorsParameters() { memset(this,0,sizeof(BehaviorsParameters)); destinations = 0; } ~BehaviorsParameters(){Clear();} void Clear(); void SaveBehaviorParameters(CKBehavior* beh); void LoadBehaviorParameters(CKBehavior* beh); static void ResetBehaviorParameters(CKBehavior* behavior); static void NameBehaviorParameters(CKBehavior* callBB,CKBehavior* calledBeh,int iPinOffset=0); static void SetBehaviorParameters(CKBehavior* callBB,CKBehavior* calledBeh,int iPinOffset=0); }; struct BehaviorInternalStates { //tag to write in chunk enum ESubTag { eST_ActiveStates = -4, //for each beh, save active state (1bit) + outputs active state (31bits) eST_OutputParameters = -3, //save all sub beh pout values eST_Behavior = -2, //save beh id eST_End = -1, //end }; enum EFlags { eInternallyCreatedChunk = 1, }; BehaviorInternalStates() {memset(this,0,sizeof(BehaviorInternalStates));} BehaviorInternalStates(CKStateChunk* chunk) {memset(this,0,sizeof(BehaviorInternalStates));m_Chunk=chunk;} ~BehaviorInternalStates() { if ( (m_Flags & eInternallyCreatedChunk) && m_Chunk) DeleteCKStateChunk(m_Chunk);m_Chunk=0;} DWORD m_Flags; /* before execute >save current state >load state relative to caller ------------ after execute >save state relative to caller >load last current state */ void SaveAllSubBehaviorLocalParameterValues(CKBehavior* iBeh,int iDepth=0); void LoadAllSubBehaviorLocalParameterValues(CKBehavior* iBeh,int iDepth=0); static DWORD GetBehaviorActiveStates(CKBehavior* iBeh); static void SetBehaviorActiveStates(CKBehavior* iBeh,DWORD iActiveStates); CKStateChunk* m_Chunk; }; //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // the behavior //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// CKObjectDeclaration *FillBehaviorCallBehavior2Decl() { CKObjectDeclaration *od = CreateCKObjectDeclaration(CALLBEHAVIOR_NAME); od->SetDescription("Calls immediatly a behavior."); /* rem: In: triggers the process.
Out: is activated when the activated script's process is completed.

Reset?: if TRUE, the script will be reset; if FALSE the script will be resumed from its previous state.
Script: script to be performed.
Wait For Completion?: if TRUE, the script will be executed until completion; if FALSE the script will be executed for one frame.

The script called is executed immediatly, stopping the execution of the current script. */ /* warning: The script must not contain a infinite loop if you set Wait For Completion.
*/ od->SetType(CKDLL_BEHAVIORPROTOTYPE); od->SetGuid(CALLBEHAVIOR_GUID); od->SetAuthorGuid(VIRTOOLS_GUID); od->SetAuthorName("Virtools"); od->SetVersion(0x00020000); od->SetCreationFunction(CreateCallBehavior2Proto); od->SetCompatibleClassId(CKCID_BEOBJECT); od->SetCategory("Narratives/Script Management"); return od; } CKERROR CreateCallBehavior2Proto(CKBehaviorPrototype **pproto) { CKBehaviorPrototype *proto = CreateCKBehaviorPrototype(CALLBEHAVIOR_NAME); if(!proto) return CKERR_OUTOFMEMORY; proto->DeclareInParameter("Target", CKPGUID_BEHAVIOR, 0); proto->DeclareSetting("Settings",NARRATIVES_CALLBEHAVIOR_SETTING,"Wait for Completion,Parameter Restore,Check Proto Validity,Save Internal States"); proto->DeclareSetting("Max Recursion",CKPGUID_INT,"100");//0 means no protection proto->DeclareLocalParameter("",CKPGUID_INT,0);//ePL_RECURSION_DEPTH (-1 means first proto->DeclareLocalParameter("",CKPGUID_STATECHUNK,0); //state of locals of sub behaviors proto->SetFlags(CK_BEHAVIORPROTOTYPE_NORMAL); proto->SetFunction(CallBehavior2); proto->SetBehaviorCallbackFct(CallBehavior2Callback); proto->SetBehaviorFlags((CK_BEHAVIOR_FLAGS)( CKBEHAVIOR_INTERNALLYCREATEDINPUTS| CKBEHAVIOR_INTERNALLYCREATEDOUTPUTS| CKBEHAVIOR_INTERNALLYCREATEDINPUTPARAMS| CKBEHAVIOR_INTERNALLYCREATEDOUTPUTPARAMS )); *pproto = proto; return CK_OK; } //////////////////////////////////////////////////////////////////////////////// // CALL BEHAVIOR CALLBACK START //////////////////////////////////////////////////////////////////////////////// int CallBehavior2(const CKBehaviorContext& behcontext) { CKBehavior* beh = behcontext.Behavior; //compatibility with V1 from 4.1.0.37 added.... if (beh->GetVersion()<0x00020000) { return CallBehavior(behcontext); //not support for older version, please update :) //behcontext.Context->OutputToConsole("Error: Please Update CallBehavior BBs"); //return CKBR_OK; } //Get target behavior CKBehavior* target = (CKBehavior*) beh->GetInputParameterObject(ePI_TARGET); if (!target) return CKBR_OK; //get settings DWORD flags=0; beh->GetLocalParameterValue(ePL_SETTINGS,&flags); //target io mapping check if ((flags & eSetting_PrivateCheckProto)==eSetting_PrivateCheckProto)//need the full flag { int pincount = target->GetInputParameterCount(); int poutcount = target->GetOutputParameterCount(); if (beh->GetInputCount()-eI_INS!=target->GetInputCount() || beh->GetOutputCount()-eO_OUTS!=target->GetOutputCount() || beh->GetInputParameterCount()-ePI_INPUTS!=pincount || beh->GetOutputParameterCount()-ePO_OUTPUTS!=poutcount ) { behcontext.Context->OutputToConsole("CallBehavior: Check Prototype Validity Error"); return CKBR_OK; } for (int i=0;iGetInputParameter(i+ePI_INPUTS); CKParameterIn* pin2 = target->GetInputParameter(i); if (pin1->GetGUID()!=pin2->GetGUID()) { behcontext.Context->OutputToConsole("CallBehavior: Invalid Target Prototype"); return CKBR_OK; } } for (int i=0;iGetOutputParameter(i+ePO_OUTPUTS); CKParameterOut* pout2 = target->GetOutputParameter(i); if (pout1->GetGUID()!=pout2->GetGUID()) { behcontext.Context->OutputToConsole("CallBehavior: Invalid Target Prototype"); return CKBR_OK; } } } //max depth int maxDepth = 100; beh->GetLocalParameterValue(ePL_MAX_RECURSION_DEPTH,&maxDepth); //current depth - recursion check int currentDepth = 0; beh->GetLocalParameterValue(ePL_RECURSION_DEPTH,¤tDepth); //update current Depth currentDepth++; beh->SetLocalParameterValue(ePL_RECURSION_DEPTH,¤tDepth); //note : 1st execution=> currentdepth here == 0 if (maxDepth>=0 && currentDepth>maxDepth) { behcontext.Context->OutputToConsole("CallBehavior: recursion>max recursion depth, BB break"); flags &= ~eSetting_InExecution; beh->SetLocalParameterValue(ePL_SETTINGS,&flags); //save the fact that this beh is in execution goto CALLBEHAVIOR_END; } //memorize activation state BOOL memorizeIsActive = target->IsActive(); //small note : //execute inactive graph, it will activate inner BBs, which then in turn will activate the graph //the graph can then return CKBR_ACTIVATENEXTFRAME and still be active //execute inactive BB : it will be executed but nothing will change its activate flag //it will remain inactive even if it returns CKBR_ACTIVATENEXTFRAME //=> we have to activate BBs, and not activate graphes (for graphes, recursion trouble if active too) //+++ //we have to restore active state of a BB //ie otherwise, delayer, activate it, execute it, ok let's go on => the delayer is active, //now the behavior manager will execute it once again. bad //=>restore active state at the end //1st execution INITIALISATION int ioCount = target->GetInputCount(); if ((flags & eSetting_InExecution)==0) //1st execution { //reset if (flags & eSetting_Reset) target->Activate(FALSE,TRUE); //Activate Inputs //target->ActivateInput(0); for (int i=eI_INS;iIsInputActive(i)) { target->ActivateInput(i-eI_INS); //deactivate NOW this input, as it has been checked //because in case of recursion, it may cause crashes //even if callbehavior was deactivated (see following code) //reactivating it again, the input could be not activated beh->ActivateInput(i,FALSE); } } //deactivate because in case of recursion, being still active will case unwilling recursion if ((target->GetFlags() & CKBEHAVIOR_BUILDINGBLOCK)==0) //IF NOT BUILDING BLOCK if ((flags & eSetting_Real_Time_Execution)==0) //no recursion in realtime, so we just check we are not in real time beh->Activate(FALSE); if (flags & eSetting_Hijack_Parameters_Once) BehaviorsParameters::SetBehaviorParameters(beh,target); } //Todo: alors executer un graph non actif, si le graph est actif a la fin, ca veut dire qu'en realtime faut continuer a l'ex //mais un bb non actif, un return CKB Activate next frame le rend pas actif //du coup chui obligé de l'activer, mais apres je loope infiniment bref a voir pr plus tard //en meme temps ca sert a rien un call de BB du coup j'ai desactivé en release if (target->GetFlags() & CKBEHAVIOR_BUILDINGBLOCK) //IF BUILDING BLOCK target->Activate(TRUE); //force activation //Real time ex if (flags & eSetting_Real_Time_Execution) { if (currentDepth>1) { behcontext.Context->OutputToConsoleExBeep("Call Behavior: Real Time Execution and recursion is not allowed"); flags &= ~eSetting_InExecution; beh->SetLocalParameterValue(ePL_SETTINGS,&flags); //save the fact that this beh is in execution goto CALLBEHAVIOR_END; } //have to reactivate script if not active, otherwise we may have some side effect /* CKBehavior* parent = target; while (parent->GetParent()) parent = target->GetParent(); if (!parent->IsActive()) parent->Activate(TRUE,FALSE); */ CK_BEHAVIOR_FLAGS behflags = target->GetFlags(); //if (behflags & CKBEHAVIOR_EXECUTEDLASTFRAME) //1st execution & real time if ((flags & eSetting_InExecution)==0) { flags |= eSetting_InExecution; beh->SetLocalParameterValue(ePL_SETTINGS,&flags); //save the fact that this beh is in execution } //execution EXECUTE_TARGET(); //if no more active, if(!target->IsActive()) { //remove inExecution flags inexection flags &= ~eSetting_InExecution; beh->SetLocalParameterValue(ePL_SETTINGS,&flags); //save the fact that this beh is in execution } } //wait for completion else if (flags & eSetting_Wait_for_Completion) { int loop = 0; int maxloop = behcontext.Context->GetBehaviorManager()->GetBehaviorMaxIteration(); for(;;++loop) { if (loop > maxloop) //prevent infinite loop { behcontext.Context->OutputToConsoleExBeep("Call Behavior: Target behavior %s executed too much times",target?target->GetName():"NA"); target->Activate(FALSE,FALSE); break; } EXECUTE_TARGET(); // The target loop on itself too much times if (result == CKBR_INFINITELOOP) { target->Activate(FALSE,FALSE); break; } if(!target->IsActive()) break; } } // we execute only one frame of the target else { EXECUTE_TARGET(); target->Activate(FALSE,FALSE); } //deactivate all inputs (already done at the beginning, put into comment //for (int i=eI_INS;iActivateInput(i,FALSE); //for each target's output activated, activate call behavior output ioCount = target->GetOutputCount(); for (int i=eO_OUTS;iActivateOutput(i,target->IsOutputActive(i-eO_OUTS)); //if stop at exit, deactivate target outputs if (flags & eSetting_Stop_at_Exit) { for (int i=0;iActivateOutput(i,FALSE); } //recursive depth update CALLBEHAVIOR_END: currentDepth--; beh->SetLocalParameterValue(ePL_RECURSION_DEPTH,¤tDepth); if (memorizeIsActive==FALSE) target->Activate(FALSE,FALSE); //real time execution if (flags & eSetting_InExecution) return CKBR_ACTIVATENEXTFRAME; return CKBR_OK; } //////////////////////////////////////////////////////////////////////////////// // CALL BEHAVIOR CALLBACK END //////////////////////////////////////////////////////////////////////////////// void RemoveIOxParams2(CKBehavior* beh) { CKContext* ctx = beh->GetCKContext(); int count = beh->GetInputParameterCount()-ePI_INPUTS; for (int i=0;iDestroyObject(beh->RemoveInputParameter(ePI_INPUTS),CK_DESTROY_NONOTIFY,0); count = beh->GetOutputParameterCount()-ePO_OUTPUTS; for (int i=0;iDestroyObject(beh->RemoveOutputParameter(ePO_OUTPUTS),CK_DESTROY_NONOTIFY,0); count = beh->GetInputCount()-eI_INS; for (int i=0;iDeleteInput(eI_INS); count = beh->GetOutputCount()-eO_OUTS; for (int i=0;iDeleteOutput(eO_OUTS); } CKERROR CallBehavior2Callback(const CKBehaviorContext& behcontext) { CKBehavior* beh = behcontext.Behavior; if (beh->GetVersion()<0x00020000) //not support for older version, please update :) { return CallBehaviorCallback(behcontext); //not support for older version, please update :) //behcontext.Context->OutputToConsole("Error: Please Update CallBehavior BBs"); //return CKBR_OK; } switch( behcontext.CallbackMessage ) { case CKM_BEHAVIORDEACTIVATESCRIPT: case CKM_BEHAVIORRESET: { DWORD flags = 0; beh->GetLocalParameterValue(ePL_SETTINGS,&flags); //save the fact that this beh is in execution flags &= ~eSetting_InExecution; beh->SetLocalParameterValue(ePL_SETTINGS,&flags); //save the fact that this beh is in execution } break; //case CKM_BEHAVIORSETTINGSEDITED: //obsolete in V2 //create same ios as in target behavior case CKM_BEHAVIOREDITED: { //do not take into account any change if frozen DWORD flags=0; beh->GetLocalParameterValue(ePL_SETTINGS,&flags); if (flags & eSetting_Freeze_IO_mapping) break; CKBehavior* target = (CKBehavior*) beh->GetInputParameterObject(ePI_TARGET); BOOL bb = FALSE; if (target) bb = (target->GetFlags() & CKBEHAVIOR_BUILDINGBLOCK)?TRUE:FALSE; #ifdef _DEBUG if (target==beh)// || bb) allow bb finally { //if (bb) // behcontext.Context->OutputToConsole("CallBehavior BB cannot target another BB"); //else #else if (target==beh || bb) //do not allow bb finally in release lol, active state problems { if (bb) behcontext.Context->OutputToConsole("CallBehavior BB cannot target another BB"); else #endif behcontext.Context->OutputToConsole("CallBehavior BB cannot target itself"); CKParameterIn* pin = beh->GetInputParameter(ePI_TARGET); if (pin) { CKParameter* param = pin->GetDirectSource(); CK_ID id=0; if (param) param->SetValue(&id); } beh->SetName(CALLBEHAVIOR_NAME); RemoveIOxParams2(beh); behcontext.Context->SendInterfaceMessage(CKUIM_CALLBEHAVIORBB_CHANGE,(CKDWORD)beh,eCallBehavior_Edit,0);//warn interface return CKBR_PARAMETERERROR; } //////////////////////////////////////////////////////////////////////////////// //Fit IOs & Params if (CKIsChildClassOf(target,CKCID_BEHAVIOR) && target->GetOwner()) { //////////////////////////////////////////////////////////////////////////////// //Params int inCountTarget = target->GetInputParameterCount(); int outCountTarget = target->GetOutputParameterCount(); int inCountCaller = beh->GetInputParameterCount(); int outCountCaller = beh->GetOutputParameterCount(); //////////////////////////////////////////////////////////////////////////////// //remove params if too much for (int i=inCountCaller-1;i>=ePI_INPUTS+inCountTarget;i--) behcontext.Context->DestroyObject(beh->RemoveInputParameter(i),CK_DESTROY_NONOTIFY,0); for (int i=outCountCaller-1;i>=ePO_OUTPUTS+outCountTarget;i--) behcontext.Context->DestroyObject(beh->RemoveOutputParameter(i),CK_DESTROY_NONOTIFY,0); //////////////////////////////////////////////////////////////////////////////// //create params if not enough inCountCaller = beh->GetInputParameterCount(); outCountCaller = beh->GetOutputParameterCount(); for (int i=inCountCaller-ePI_INPUTS;iGetInputParameter(i); beh->CreateInputParameter(pin->GetName(),pin->GetGUID()); } for (int i=outCountCaller-ePO_OUTPUTS;iGetOutputParameter(i); beh->CreateOutputParameter(pout->GetName(),pout->GetGUID()); } //////////////////////////////////////////////////////////////////////////////// //IOs inCountTarget = target->GetInputCount(); outCountTarget = target->GetOutputCount(); inCountCaller = beh->GetInputCount(); outCountCaller = beh->GetOutputCount(); //////////////////////////////////////////////////////////////////////////////// //remove IOS if too much for (int i=inCountCaller-1;i>=eI_INS+inCountTarget;i--) beh->DeleteInput(i); for (int i=outCountCaller-1;i>=eO_OUTS+outCountTarget;i--) beh->DeleteOutput(i); //////////////////////////////////////////////////////////////////////////////// //create IOS if not enough inCountCaller = beh->GetInputCount(); outCountCaller = beh->GetOutputCount(); for (int i=inCountCaller-eI_INS;iGetInput(i); beh->CreateInput(io->GetName()); } for (int i=outCountCaller-eO_OUTS;iGetOutput(i); beh->CreateOutput(io->GetName()); } //rename BehaviorsParameters::NameBehaviorParameters(beh,target); if (target && target->GetName()) { XString finalName; finalName.Format("%s:%s",CALLBEHAVIOR_NAME,target->GetName()); beh->SetName(finalName.Str()); } } //////////////////////////////////////////////////////////////////////////////// else //remove all supplementary pins & pouts from BB { RemoveIOxParams2(beh); beh->SetName(CALLBEHAVIOR_NAME); } { CKBehavior* target = (CKBehavior*) beh->GetInputParameterObject(ePI_TARGET); behcontext.Context->SendInterfaceMessage(CKUIM_CALLBEHAVIORBB_CHANGE,(CKDWORD)beh,eCallBehavior_Edit,(CKDWORD)target);//warn interface } break; } break; case CKM_BEHAVIORDELETE: case CKM_BEHAVIORDETACH: { DWORD flags = 0; beh->GetLocalParameterValue(ePL_SETTINGS,&flags); //save the fact that this beh is in execution flags &= ~eSetting_InExecution; beh->SetLocalParameterValue(ePL_SETTINGS,&flags); //save the fact that this beh is in execution CKBehavior* target = (CKBehavior*) beh->GetInputParameterObject(ePI_TARGET); behcontext.Context->SendInterfaceMessage(CKUIM_CALLBEHAVIORBB_CHANGE,(CKDWORD)beh,eCallBehavior_Detach,(CKDWORD)target);//warn interface } break; case CKM_BEHAVIORLOAD: case CKM_BEHAVIORATTACH: { DWORD flags = 0; beh->GetLocalParameterValue(ePL_SETTINGS,&flags); //save the fact that this beh is in execution flags &= ~eSetting_InExecution; beh->SetLocalParameterValue(ePL_SETTINGS,&flags); //save the fact that this beh is in execution CKBehavior* target = (CKBehavior*) beh->GetInputParameterObject(ePI_TARGET); behcontext.Context->SendInterfaceMessage(CKUIM_CALLBEHAVIORBB_CHANGE,(CKDWORD)beh,eCallBehavior_Attach,(CKDWORD)target);//warn interface if (behcontext.Context->IsInInterfaceMode()) { if (target && target->GetName()) { XString finalName; finalName.Format("%s:%s",CALLBEHAVIOR_NAME,target->GetName()); beh->SetName(finalName.Str()); } } } break; } return CK_OK; } ////////////////////////////////////////////////////////////////////////// // call behavior 1 compatibilité for 4.1.0.37 ... ////////////////////////////////////////////////////////////////////////// enum INS_V1 { eI_INS_V1, }; enum OUTS_V1 { eO_OUTS_V1, }; enum PINS_V1 { eRESET_V1, eWAITFORCOMPLETION_V1, eSTOP_AT_EXIT_V1, ePI_INPUTS_V1, }; enum POUTS_V1 { ePO_OUTPUTS_V1, }; enum PLOCALS_V1 { ePI_TARGET_BEHAVIOR_V1, //setting ePL_MAX_RECURSION_DEPTH_V1, //setting eDO_NOT_RESTORE_PARAMETERS_V1, //setting, optimisation ePL_RECURSION_DEPTH_V1, //local }; int CallBehavior(const CKBehaviorContext& behcontext) { CKBehavior* beh = behcontext.Behavior; //Get target behavior CKBehavior* target = (CKBehavior*) beh->GetLocalParameterObject(ePI_TARGET_BEHAVIOR_V1); if (!target) return CKBR_OK; //reset BOOL reset=FALSE; beh->GetInputParameterValue(eRESET_V1, &reset); if (reset) target->Activate(FALSE,TRUE); //Activate Inputs //target->ActivateInput(0); int ioCount = target->GetInputCount(); for (int i=eI_INS_V1;iIsInputActive(i)) target->ActivateInput(i-eI_INS_V1); } // Get waitcomp BOOL wc=TRUE; beh->GetInputParameterValue(eWAITFORCOMPLETION_V1, &wc); //stop at exit BOOL stopAtExit = FALSE; beh->GetInputParameterValue(eSTOP_AT_EXIT_V1, &stopAtExit); //max depth int maxDepth = 100; beh->GetLocalParameterValue(ePL_MAX_RECURSION_DEPTH_V1,&maxDepth); //current depth int currentDepth = 0; beh->GetLocalParameterValue(ePL_RECURSION_DEPTH_V1,¤tDepth); currentDepth++; if (maxDepth>=0 && currentDepth>maxDepth) { behcontext.Context->OutputToConsole("CallBehavior, recursion>max recursion depth, BB break"); return CKBR_OK; } beh->SetLocalParameterValue(ePL_RECURSION_DEPTH_V1,¤tDepth); //optim int noRestoreParam = FALSE; beh->GetLocalParameterValue(eDO_NOT_RESTORE_PARAMETERS_V1,&noRestoreParam); if (wc) { int loop = 0; int maxloop = behcontext.Context->GetBehaviorManager()->GetBehaviorMaxIteration(); for(;;++loop) { if (loop > maxloop) { behcontext.Context->OutputToConsoleExBeep("Call Behavior: Behavior %s executed too much times",target?target->GetName():"NA"); target->Activate(FALSE,FALSE); break; } BehaviorsParameters behParams; if (noRestoreParam==FALSE) behParams.SaveBehaviorParameters(target); BehaviorsParameters::SetBehaviorParameters(beh,target,ePI_INPUTS_V1-ePI_INPUTS); CKERROR result = target->Execute(behcontext.DeltaTime); if (noRestoreParam==FALSE) behParams.LoadBehaviorParameters(target); // The target loop on itself too much times if (result == CKBR_INFINITELOOP) { target->Activate(FALSE,FALSE); break; } if(!target->IsActive()) break; } } else { // we execute only one frame of the target BehaviorsParameters behParams; if (noRestoreParam==FALSE) behParams.SaveBehaviorParameters(target); BehaviorsParameters::SetBehaviorParameters(beh,target,ePI_INPUTS_V1-ePI_INPUTS); target->Execute(behcontext.DeltaTime); if (noRestoreParam==FALSE) behParams.LoadBehaviorParameters(target); target->Activate(FALSE,FALSE); } //recursive depth update currentDepth--; beh->SetLocalParameterValue(ePL_RECURSION_DEPTH_V1,¤tDepth); // IO Activation //beh->ActivateInput(0,FALSE); //beh->ActivateOutput(0); for (int i=eI_INS_V1;iActivateInput(i,FALSE); ioCount = target->GetOutputCount(); for (int i=eO_OUTS_V1;iActivateOutput(i,target->IsOutputActive(i-eO_OUTS_V1)); if (stopAtExit) { for (int i=0;iActivateOutput(i,FALSE); } return CKBR_OK; } void RemoveIOxParams(CKBehavior* beh) { CKContext* ctx = beh->GetCKContext(); int count = beh->GetInputParameterCount()-ePI_INPUTS_V1; for (int i=0;iDestroyObject(beh->RemoveInputParameter(ePI_INPUTS_V1),CK_DESTROY_NONOTIFY,0); count = beh->GetOutputParameterCount()-ePO_OUTPUTS_V1; for (int i=0;iDestroyObject(beh->RemoveOutputParameter(ePO_OUTPUTS_V1),CK_DESTROY_NONOTIFY,0); count = beh->GetInputCount()-eI_INS_V1; for (int i=0;iDeleteInput(eI_INS_V1); count = beh->GetOutputCount()-eO_OUTS_V1; for (int i=0;iDeleteOutput(eO_OUTS_V1); } CKERROR CallBehaviorCallback(const CKBehaviorContext& behcontext) { CKBehavior* beh = behcontext.Behavior; switch( behcontext.CallbackMessage ) { //create same ios as in target behavior case CKM_BEHAVIOREDITED: { CKBehavior* target = (CKBehavior*) beh->GetLocalParameterObject(ePI_TARGET_BEHAVIOR_V1); //update behavior ios & types just in case BehaviorsParameters::NameBehaviorParameters(beh,target,ePI_INPUTS_V1-ePI_INPUTS); } break; case CKM_BEHAVIORSETTINGSEDITED: { CKBehavior* target = (CKBehavior*) beh->GetLocalParameterObject(ePI_TARGET_BEHAVIOR_V1); BOOL bb = FALSE; if (target) bb = (target->GetFlags() & CKBEHAVIOR_BUILDINGBLOCK)?TRUE:FALSE; DWORD flags=0; beh->GetLocalParameterValue(ePL_SETTINGS,&flags); /*try to have a inside doc if ((flags & eSetting_SaveInternalStates)==0) { MessageBox(0,"text\ntext2","caption",MB_OK); } */ if (target==beh)// || bb) allow bb finally { //if (bb) // behcontext.Context->OutputToConsole("CallBehavior BB cannot target another BB"); //else behcontext.Context->OutputToConsole("CallBehavior BB cannot target itself"); beh->SetLocalParameterObject(ePI_TARGET_BEHAVIOR_V1,0); beh->SetName(CALLBEHAVIOR_NAME); RemoveIOxParams(beh); behcontext.Context->SendInterfaceMessage(CKUIM_CALLBEHAVIORBB_CHANGE,(CKDWORD)beh,eCallBehavior_Edit,0);//warn interface return CKBR_PARAMETERERROR; } //////////////////////////////////////////////////////////////////////////////// //Fit IOs & Params if (CKIsChildClassOf(target,CKCID_BEHAVIOR) && target->GetOwner()) { //////////////////////////////////////////////////////////////////////////////// //Params int inCountTarget = target->GetInputParameterCount(); int outCountTarget = target->GetOutputParameterCount(); int inCountCaller = beh->GetInputParameterCount(); int outCountCaller = beh->GetOutputParameterCount(); //////////////////////////////////////////////////////////////////////////////// //remove params if too much for (int i=inCountCaller-1;i>=ePI_INPUTS_V1+inCountTarget;i--) behcontext.Context->DestroyObject(beh->RemoveInputParameter(i),CK_DESTROY_NONOTIFY,0); for (int i=outCountCaller-1;i>=ePO_OUTPUTS_V1+outCountTarget;i--) behcontext.Context->DestroyObject(beh->RemoveOutputParameter(i),CK_DESTROY_NONOTIFY,0); //////////////////////////////////////////////////////////////////////////////// //create params if not enough inCountCaller = beh->GetInputParameterCount(); outCountCaller = beh->GetOutputParameterCount(); for (int i=inCountCaller-ePI_INPUTS_V1;iGetInputParameter(i); beh->CreateInputParameter(pin->GetName(),pin->GetGUID()); } for (int i=outCountCaller-ePO_OUTPUTS_V1;iGetOutputParameter(i); beh->CreateOutputParameter(pout->GetName(),pout->GetGUID()); } //////////////////////////////////////////////////////////////////////////////// //IOs inCountTarget = target->GetInputCount(); outCountTarget = target->GetOutputCount(); inCountCaller = beh->GetInputCount(); outCountCaller = beh->GetOutputCount(); //////////////////////////////////////////////////////////////////////////////// //remove IOS if too much for (int i=inCountCaller-1;i>=eI_INS_V1+inCountTarget;i--) beh->DeleteInput(i); for (int i=outCountCaller-1;i>=eO_OUTS_V1+outCountTarget;i--) beh->DeleteOutput(i); //////////////////////////////////////////////////////////////////////////////// //create IOS if not enough inCountCaller = beh->GetInputCount(); outCountCaller = beh->GetOutputCount(); for (int i=inCountCaller-eI_INS_V1;iGetInput(i); beh->CreateInput(io->GetName()); } for (int i=outCountCaller-eO_OUTS_V1;iGetOutput(i); beh->CreateOutput(io->GetName()); } //rename BehaviorsParameters::NameBehaviorParameters(beh,target,ePI_INPUTS_V1-ePI_INPUTS); if (target && target->GetName()) { XString finalName; finalName.Format("%s:%s",CALLBEHAVIOR_NAME,target->GetName()); beh->SetName(finalName.Str()); } } //////////////////////////////////////////////////////////////////////////////// else //remove all supplementary pins & pouts from BB { RemoveIOxParams(beh); beh->SetName(CALLBEHAVIOR_NAME); } { CKBehavior* target = (CKBehavior*) beh->GetLocalParameterObject(ePI_TARGET_BEHAVIOR_V1); behcontext.Context->SendInterfaceMessage(CKUIM_CALLBEHAVIORBB_CHANGE,(CKDWORD)beh,eCallBehavior_Edit,(CKDWORD)target);//warn interface } break; } break; case CKM_BEHAVIORDELETE: case CKM_BEHAVIORDETACH: { CKBehavior* target = (CKBehavior*) beh->GetLocalParameterObject(ePI_TARGET_BEHAVIOR_V1); behcontext.Context->SendInterfaceMessage(CKUIM_CALLBEHAVIORBB_CHANGE,(CKDWORD)beh,eCallBehavior_Detach,(CKDWORD)target);//warn interface } break; case CKM_BEHAVIORLOAD: case CKM_BEHAVIORATTACH: { CKBehavior* target = (CKBehavior*) beh->GetLocalParameterObject(ePI_TARGET_BEHAVIOR_V1); behcontext.Context->SendInterfaceMessage(CKUIM_CALLBEHAVIORBB_CHANGE,(CKDWORD)beh,eCallBehavior_Attach,(CKDWORD)target);//warn interface if (behcontext.Context->IsInInterfaceMode()) { if (target && target->GetName()) { XString finalName; finalName.Format("%s:%s",CALLBEHAVIOR_NAME,target->GetName()); beh->SetName(finalName.Str()); } } } break; } return CK_OK; } ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// //BehaviorsParameters ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// void BehaviorsParameters::Clear() { if (sources) delete [] sources; if (destinations) { for (int i=0;iGetInputParameterCount(); sources = new CK_ID[sourcesCount*2]; for (int i=0;iGetInputParameter(i); if (pin) { if (CKParameterIn* shared = pin->GetSharedSource()) { sources[i*2] = 1; sources[i*2+1] = shared->GetID(); } else if (CKParameter* p = pin->GetDirectSource()) { sources[i*2] = 0; sources[i*2+1] = p->GetID(); } else { sources[i*2] = 0; sources[i*2+1] = 0; } } } //save pouts destinationsCount = beh->GetOutputParameterCount(); destinations = new CK_ID*[destinationsCount]; for (int i=0;iGetOutputParameter(i); if (pout) { if (int destCount = pout->GetDestinationCount()) { destinations[i] = new CK_ID[destCount+1]; destinations[i][0] = destCount; for (int j=0;jGetDestination(j); destinations[i][j+1] = dest?dest->GetID():0; } } else destinations[i] = 0; } } } void BehaviorsParameters::LoadBehaviorParameters(CKBehavior* beh) { if (!beh) return; //restore pins for (int i=0;iGetInputParameter(i); if (pin) { CK_ID id = sources[2*i+1]; if (id==0) { pin->ShareSourceWith(0); pin->SetDirectSource(0); } else { CKObject* obj = beh->GetCKContext()->GetObject(id); if (sources[2*i]==0) { pin->ShareSourceWith(0); pin->SetDirectSource((CKParameter*)obj); } else { pin->SetDirectSource(0); pin->ShareSourceWith((CKParameterIn*)obj); } } } } //restore pouts for (int i=0;iGetOutputParameter(i); if (pout) { pout->RemoveAllDestinations(); if (destinations[i]) { int count = destinations[i][0]; for (int j=0;jGetCKContext()->GetObject(destinations[i][j+1]); if (CKIsChildClassOf(p,CKCID_PARAMETER)) pout->AddDestination(p); } } } } } void BehaviorsParameters::SetBehaviorParameters(CKBehavior* callBB,CKBehavior* calledBeh,int iPinOffset) { if (!callBB || !calledBeh) return; int inCountTarget = calledBeh->GetInputParameterCount(); int outCountTarget = calledBeh->GetOutputParameterCount(); //set sources & dest for (int i=0;iGetInputParameter(i); CKParameterIn* pin2 = callBB->GetInputParameter(i+ePI_INPUTS+iPinOffset); if (pin1 && pin2) pin1->SetDirectSource(pin2->GetRealSource()); } for (int i=0;iGetOutputParameter(i); CKParameterOut* pout2 = callBB->GetOutputParameter(i+ePO_OUTPUTS); if (pout1 && pout2) { pout1->RemoveAllDestinations(); pout1->AddDestination(pout2); } } } void BehaviorsParameters::NameBehaviorParameters(CKBehavior* callBB,CKBehavior* calledBeh,int iPinOffset) { if (!calledBeh) return; int count = calledBeh->GetInputParameterCount(); for (int i=0;iGetInputParameter(i); CKParameterIn* p2 = callBB->GetInputParameter(i+ePI_INPUTS+iPinOffset); if (p1 && p2) { p2->SetName(p1->GetName()); if (p1->GetType()!=p2->GetType()) { p2->SetType(p1->GetType()); //CKParameter* psource = p2->GetRealSource(); //if (psource) // psource->SetType(p1->GetType()); } } } count = calledBeh->GetOutputParameterCount(); for (int i=0;iGetOutputParameter(i); CKParameter* p2 = callBB->GetOutputParameter(i+ePO_OUTPUTS); if (p1 && p2) { p2->SetName(p1->GetName()); if (p1->GetType()!=p2->GetType()) { p2->SetType(p1->GetType()); } } } count = calledBeh->GetInputCount(); for (int i=0;iGetInput(i); CKBehaviorIO* p2 = callBB->GetInput(i+eI_INS); if (p1 && p2) p2->SetName(p1->GetName()); } count = calledBeh->GetOutputCount(); for (int i=0;iGetOutput(i); CKBehaviorIO* p2 = callBB->GetOutput(i+eO_OUTS); if (p1 && p2) p2->SetName(p1->GetName()); } } void BehaviorsParameters::ResetBehaviorParameters(CKBehavior* behavior) { if (!behavior) return; int inCountTarget = behavior->GetInputParameterCount(); int outCountTarget = behavior->GetOutputParameterCount(); //set sources & dest for (int i=0;iGetInputParameter(i); if (pin1) { pin1->SetDirectSource(0); pin1->ShareSourceWith(0); } } for (int i=0;iGetOutputParameter(i); if (pout1) pout1->RemoveAllDestinations(); } } void BehaviorInternalStates::SaveAllSubBehaviorLocalParameterValues(CKBehavior* beh,int iDepth) { if (!m_Chunk) { m_Chunk = CreateCKStateChunk(CKCID_OBJECT); m_Flags |= eInternallyCreatedChunk ; /* m_Chunk->StartWrite(); m_Chunk->WriteInt(-2); m_Chunk->CloseChunk(); m_Chunk->StartRead(); int toto = m_Chunk->ReadInt(); m_Chunk->CloseChunk(); */ } if (iDepth>0) //Save local datas of this iBeh { m_Chunk->WriteInt(eST_Behavior); m_Chunk->WriteObject(beh); m_Chunk->WriteInt(eST_ActiveStates); m_Chunk->WriteDword(GetBehaviorActiveStates(beh)); if ((beh->GetFlags() & CKBEHAVIOR_BUILDINGBLOCK)) //IF BUILDING BLOCK {//if bb int localCount = beh->GetLocalParameterCount(); int poutCount = beh->GetOutputParameterCount(); //localCount = poutCount = 0; /* if (localCount ||poutCount) { m_Chunk->WriteInt(eST_Behavior); m_Chunk->WriteObject(beh); } */ if (localCount) {//if localcount for (int i=0;iIsLocalParameterSetting(i)) {//if not a setting CKParameter* param = beh->GetLocalParameter(i); int datasize = param->GetDataSize(); if (datasize) { BYTE* buffer = new BYTE[datasize]; CKERROR ckerror = param->GetValue(buffer); if (ckerror==CK_OK) { m_Chunk->WriteInt(i); //write index of local m_Chunk->WriteBuffer(datasize,buffer); //write buffer } delete[] buffer; }//if datasize }//if not a setting }//for all locals }//if localcount //save pouts if (poutCount>0) { m_Chunk->WriteInt(eST_OutputParameters); m_Chunk->WriteInt(poutCount); for (int i=0;iGetOutputParameter(i); int datasize = param->GetDataSize(); if (datasize) { BYTE* buffer = new BYTE[datasize]; CKERROR ckerror = param->GetValue(buffer); if (ckerror==CK_OK) m_Chunk->WriteBuffer(datasize,buffer); //write buffer else m_Chunk->WriteBuffer(0,0); //write buffer delete[] buffer; } else m_Chunk->WriteBuffer(0,0); //write buffer } }//save pouts }//if bb }//if depth>0 else if (iDepth==0) { m_Chunk->StartWrite(); m_Chunk->WriteInt(eST_Behavior); m_Chunk->WriteObject(beh); m_Chunk->WriteInt(eST_ActiveStates); m_Chunk->WriteDword(GetBehaviorActiveStates(beh)); } //parse children int childrenCount = beh->GetSubBehaviorCount(); for (int i=0;iGetSubBehavior(i),iDepth+1); if (iDepth==0) { m_Chunk->WriteInt(eST_End); m_Chunk->CloseChunk(); } } void BehaviorInternalStates::LoadAllSubBehaviorLocalParameterValues(CKBehavior* beh,int iDepth) { if (m_Chunk && m_Chunk->GetDataSize()>0) { m_Chunk->StartRead(); CKBehavior* currentBeh = 0; int tag = m_Chunk->ReadInt(); while (tag!=eST_End) { if (tag==eST_Behavior) { currentBeh = (CKBehavior*)m_Chunk->ReadObject(beh->GetCKContext()); } else if (tag==eST_OutputParameters) { int poutCount = m_Chunk->ReadInt(); for (int i=0;iReadBuffer(&buffer); if (currentBeh) { CKParameterOut* param = currentBeh->GetOutputParameter(i); param->SetValue(buffer,datasize); } if (datasize) CKDeletePointer(buffer); } } else if (tag==eST_ActiveStates) { SetBehaviorActiveStates(currentBeh,m_Chunk->ReadDword()); } else if (tag>=0) { void* buffer = 0; int datasize = m_Chunk->ReadBuffer(&buffer); if (currentBeh) { CKParameter* param = currentBeh->GetLocalParameter(tag); param->SetValue(buffer,datasize); } if (datasize>0) CKDeletePointer(buffer); } tag = m_Chunk->ReadInt(); } m_Chunk->CloseChunk(); } else { //restore default values if (iDepth>0) { if ((beh->GetFlags() & CKBEHAVIOR_BUILDINGBLOCK)) //IF BUILDING BLOCK {//if bb CKBehaviorPrototype* proto = beh->GetPrototype(); if (proto) {//restore local default values int localCount = beh->GetLocalParameterCount(); if (localCount) {//if localcount const XClassArray& LocalParamList = proto->GetLocalParameterList(); localCount = LocalParamList.Size(); for (int i=0;iIsLocalParameterSetting(i)) {//if not a setting CKParameter* param = beh->GetLocalParameter(i); if (LocalParamList[i].DefaultValueString) param->SetStringValue(LocalParamList[i].DefaultValueString); else if (LocalParamList[i].DefaultValue && LocalParamList[i].DefaultValueSize) param->SetValue((void*)LocalParamList[i].DefaultValue,LocalParamList[i].DefaultValueSize); }//if not a setting }//for all locals }//if localcount //restore pout default values int poutCount = beh->GetOutputParameterCount(); if (poutCount) { const XClassArray& OutParamList=proto->GetOutParameterList(); poutCount = OutParamList.Size(); for(int i=0;iGetOutputParameter(i); if (OutParamList[i].DefaultValueString) param->SetStringValue(OutParamList[i].DefaultValueString); else if (OutParamList[i].DefaultValue && OutParamList[i].DefaultValueSize) param->SetValue((void*)OutParamList[i].DefaultValue,OutParamList[i].DefaultValueSize); } }//if poutcount }//if proto }//if bb }//if depth>0 //parse children int childrenCount = beh->GetSubBehaviorCount(); for (int i=0;iGetSubBehavior(i),iDepth+1); } } DWORD BehaviorInternalStates::GetBehaviorActiveStates(CKBehavior* beh) { DWORD activeStates = 0; if (beh->IsActive()) activeStates |= 1<<31; int outputCount = beh->GetOutputCount(); for (int i=0;iIsOutputActive(i)) activeStates |= 1<Activate(TRUE,FALSE); int outputCount = beh->GetOutputCount(); for (int i=0;iActivateOutput(i); } }