//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, */ ///////////////////////////////////////////////////// ///////////////////////////////////////////////////// // // CallBehavior // ///////////////////////////////////////////////////// ///////////////////////////////////////////////////// #include "CKALL.h" #include "CallBehaviorCallback.h" #define CALLBEHAVIOR_NAME "Call Behavior" #define CALLBEHAVIOR_GUID CKGUID(0x360a720d,0x7fa42f94) CKObjectDeclaration *FillBehaviorCallBehaviorDecl(); CKERROR CreateCallBehaviorProto(CKBehaviorPrototype **); int CallBehavior(const CKBehaviorContext& context); CKERROR CallBehaviorCallback(const CKBehaviorContext& context); //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // enums & defines //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// enum INS { eINS, }; enum OUTS { eOUTS, }; enum PINS { eRESET, eWAITFORCOMPLETION, eSTOP_AT_EXIT, eINPUTS }; enum POUTS { eOUTPUTS, }; enum PLOCALS { eTARGET_BEHAVIOR, //setting eMAX_RECURSION_DEPTH, //setting eDO_NOT_RESTORE_PARAMETERS, //setting, optimisation eRECURSION_DEPTH, //local }; //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // 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() { 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 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); } } } } } static void SetBehaviorParameters(CKBehavior* callBB,CKBehavior* calledBeh) { 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+eINPUTS); if (pin1 && pin2) pin1->SetDirectSource(pin2->GetDirectSource()); } for (int i=0;iGetOutputParameter(i); CKParameterOut* pout2 = callBB->GetOutputParameter(i+eOUTPUTS); if (pout1 && pout2) { pout1->RemoveAllDestinations(); pout1->AddDestination(pout2); } } } static void NameBehaviorParameters(CKBehavior* callBB,CKBehavior* calledBeh) { if (!calledBeh) return; int count = calledBeh->GetInputParameterCount(); for (int i=0;iGetInputParameter(i); CKParameterIn* p2 = callBB->GetInputParameter(i+eINPUTS); 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+eOUTPUTS); 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+eINS); if (p1 && p2) p2->SetName(p1->GetName()); } count = calledBeh->GetOutputCount(); for (int i=0;iGetOutput(i); CKBehaviorIO* p2 = callBB->GetOutput(i+eOUTS); if (p1 && p2) p2->SetName(p1->GetName()); } } static void 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(); } } }; //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // the behavior //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// CKObjectDeclaration *FillBehaviorCallBehaviorDecl() { 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(0x00010000); od->SetCreationFunction(CreateCallBehaviorProto); od->SetCompatibleClassId(CKCID_BEOBJECT); od->SetCategory("Narratives/Script Management"); return od; } CKERROR CreateCallBehaviorProto(CKBehaviorPrototype **pproto) { CKBehaviorPrototype *proto = CreateCKBehaviorPrototype(CALLBEHAVIOR_NAME); if(!proto) return CKERR_OUTOFMEMORY; proto->DeclareInParameter("Reset", CKPGUID_BOOL, "FALSE"); proto->DeclareInParameter("Wait For Completion", CKPGUID_BOOL, "FALSE"); proto->DeclareInParameter("Stop At Exit", CKPGUID_BOOL, "FALSE"); proto->DeclareSetting("Behavior",CKPGUID_BEHAVIOR); proto->DeclareSetting("Max Recursion",CKPGUID_INT,"100");//0 means no protection proto->DeclareSetting("Do not restore parameters",CKPGUID_BOOL);//eDO_NOT_RESTORE_PARAMETERS proto->DeclareLocalParameter("",CKPGUID_INT);//eRECURSION_DEPTH proto->SetFlags(CK_BEHAVIORPROTOTYPE_NORMAL); proto->SetFunction(CallBehavior); proto->SetBehaviorCallbackFct(CallBehaviorCallback); proto->SetBehaviorFlags((CK_BEHAVIOR_FLAGS)( CKBEHAVIOR_INTERNALLYCREATEDINPUTS| CKBEHAVIOR_INTERNALLYCREATEDOUTPUTS| CKBEHAVIOR_INTERNALLYCREATEDINPUTPARAMS| CKBEHAVIOR_INTERNALLYCREATEDOUTPUTPARAMS )); *pproto = proto; return CK_OK; } int CallBehavior(const CKBehaviorContext& behcontext) { CKBehavior* beh = behcontext.Behavior; //Get target behavior CKBehavior* target = (CKBehavior*) beh->GetLocalParameterObject(eTARGET_BEHAVIOR); if (!target) return CKBR_OK; //reset BOOL reset=FALSE; beh->GetInputParameterValue(eRESET, &reset); if (reset) target->Activate(FALSE,TRUE); //Activate Inputs //target->ActivateInput(0); int ioCount = target->GetInputCount(); for (int i=eINS;iIsInputActive(i)) target->ActivateInput(i-eINS); } // Get waitcomp BOOL wc=TRUE; beh->GetInputParameterValue(eWAITFORCOMPLETION, &wc); //stop at exit BOOL stopAtExit = FALSE; beh->GetInputParameterValue(eSTOP_AT_EXIT, &stopAtExit); //max depth int maxDepth = 100; beh->GetLocalParameterValue(eMAX_RECURSION_DEPTH,&maxDepth); //current depth int currentDepth = 0; beh->GetLocalParameterValue(eRECURSION_DEPTH,¤tDepth); currentDepth++; if (maxDepth>=0 && currentDepth>maxDepth) { behcontext.Context->OutputToConsole("CallBehavior, recursion>max recursion depth, BB break"); return CKBR_OK; } beh->SetLocalParameterValue(eRECURSION_DEPTH,¤tDepth); //optim int noRestoreParam = FALSE; beh->GetLocalParameterValue(eDO_NOT_RESTORE_PARAMETERS,&noRestoreParam); if (wc) { int loop = 0; int maxloop = behcontext.Context->GetBehaviorManager()->GetBehaviorMaxIteration(); for(;;++loop) { if (loop > maxloop) { behcontext.Context->OutputToConsoleExBeep("Execute 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); 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); target->Execute(behcontext.DeltaTime); if (noRestoreParam==FALSE) behParams.LoadBehaviorParameters(target); target->Activate(FALSE,FALSE); } //recursive depth update currentDepth--; beh->SetLocalParameterValue(eRECURSION_DEPTH,¤tDepth); // IO Activation //beh->ActivateInput(0,FALSE); //beh->ActivateOutput(0); for (int i=eINS;iActivateInput(i,FALSE); ioCount = target->GetOutputCount(); for (int i=eOUTS;iActivateOutput(i,target->IsOutputActive(i-eOUTS)); if (stopAtExit) { for (int i=0;iActivateOutput(i,FALSE); } return CKBR_OK; } void RemoveIOxParams(CKBehavior* beh) { CKContext* ctx = beh->GetCKContext(); int count = beh->GetInputParameterCount()-eINPUTS; for (int i=0;iDestroyObject(beh->RemoveInputParameter(eINPUTS),CK_DESTROY_NONOTIFY,0); count = beh->GetOutputParameterCount()-eOUTPUTS; for (int i=0;iDestroyObject(beh->RemoveOutputParameter(eOUTPUTS),CK_DESTROY_NONOTIFY,0); count = beh->GetInputCount()-eINS; for (int i=0;iDeleteInput(eINS); count = beh->GetOutputCount()-eOUTS; for (int i=0;iDeleteOutput(eOUTS); } 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(eTARGET_BEHAVIOR); //update behavior ios & types just in case BehaviorsParameters::NameBehaviorParameters(beh,target); } break; case CKM_BEHAVIORSETTINGSEDITED: { CKBehavior* target = (CKBehavior*) beh->GetLocalParameterObject(eTARGET_BEHAVIOR); BOOL bb = FALSE; if (target) bb = (target->GetFlags() & CKBEHAVIOR_BUILDINGBLOCK)?TRUE:FALSE; 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(eTARGET_BEHAVIOR,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>=eINPUTS+inCountTarget;i--) behcontext.Context->DestroyObject(beh->RemoveInputParameter(i),CK_DESTROY_NONOTIFY,0); for (int i=outCountCaller-1;i>=eOUTPUTS+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-eINPUTS;iGetInputParameter(i); beh->CreateInputParameter(pin->GetName(),pin->GetGUID()); } for (int i=outCountCaller-eOUTPUTS;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>=eINS+inCountTarget;i--) beh->DeleteInput(i); for (int i=outCountCaller-1;i>=eOUTS+outCountTarget;i--) beh->DeleteOutput(i); //////////////////////////////////////////////////////////////////////////////// //create IOS if not enough inCountCaller = beh->GetInputCount(); outCountCaller = beh->GetOutputCount(); for (int i=inCountCaller-eINS;iGetInput(i); beh->CreateInput(io->GetName()); } for (int i=outCountCaller-eOUTS;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 { RemoveIOxParams(beh); beh->SetName(CALLBEHAVIOR_NAME); } { CKBehavior* target = (CKBehavior*) beh->GetLocalParameterObject(eTARGET_BEHAVIOR); 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(eTARGET_BEHAVIOR); 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(eTARGET_BEHAVIOR); 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; }