//Returns 0 if the call terminated. If the caller provides a callback and the thread does not terminate, //it will continue to run. Otherwise it will be killed. Returns 1 in this case. int CCobInstance::RealCall(int functionId, vector<int> &args, CBCobThreadFinish cb, void *p1, void *p2) { CCobThread *t = new CCobThread(script, this); t->Start(functionId, args, false); #if COB_DEBUG > 0 if (COB_DEBUG_FILTER) logOutput.Print("Calling %s:%s", script.name.c_str(), script.scriptNames[functionId].c_str()); #endif int res = t->Tick(30); t->CommitAnims(30); //Make sure this is run even if the call terminates instantly if (cb) t->SetCallback(cb, p1, p2); if (res == -1) { //Retrieve parameter values from stack for (unsigned int i = 0; i < args.size(); ++i) { args[i] = t->GetStackVal(i); } delete t; return 0; } else { //It has already added itself to the correct scheduler (global for sleep, or local for anim) return 1; } }
/** * @brief Calls a cob script function * @param functionId int cob script function id * @param args vector<int> function arguments * @param cb CBCobThreadFinish Callback function * @param p1 void* callback argument #1 * @param p2 void* callback argument #2 * @return 0 if the call terminated. If the caller provides a callback and the thread does not terminate, * it will continue to run. Otherwise it will be killed. Returns 1 in this case. */ int CCobInstance::RealCall(int functionId, vector<int> &args, CBCobThreadFinish cb, void *p1, void *p2) { if (functionId < 0 || size_t(functionId) >= script.scriptNames.size()) { if (cb) { // in case the function doesnt exist the callback should still be called (*cb)(0, p1, p2); } return -1; } CCobThread *t = new CCobThread(script, this); t->Start(functionId, args, false); #if COB_DEBUG > 0 if (COB_DEBUG_FILTER) logOutput.Print("Calling %s:%s", script.name.c_str(), script.scriptNames[functionId].c_str()); #endif int res = t->Tick(30); t->CommitAnims(30); // Make sure this is run even if the call terminates instantly if (cb) t->SetCallback(cb, p1, p2); if (res == -1) { unsigned int i = 0, argc = t->CheckStack(args.size()); // Retrieve parameter values from stack for (; i < argc; ++i) args[i] = t->GetStackVal(i); // Set erroneous parameters to 0 for (; i < args.size(); ++i) args[i] = 0; delete t; return 0; } else { // It has already added itself to the correct scheduler (global for sleep, or local for anim) return 1; } }
void CCobEngine::Tick(int deltaTime) { START_TIME_PROFILE GCurrentTime += deltaTime; #if COB_DEBUG > 0 logOutput.Print("----"); #endif //Advance all running threads for (list<CCobThread *>::iterator i = running.begin(); i != running.end(); ++i) { //logOutput.Print("Now 1running %d: %s", GCurrentTime, (*i)->GetName().c_str()); #ifdef _CONSOLE printf("----\n"); #endif int res = (*i)->Tick(deltaTime); (*i)->CommitAnims(deltaTime); if (res == -1) { delete *i; } } //A thread can never go from running->running, so clear the list //note: if preemption was to be added, this would no longer hold //however, ta scripts can not run preemptively anyway since there isn't any synchronization methods available running.clear(); //The threads that just ran may have added new threads that should run next tick for (list<CCobThread *>::iterator i = wantToRun.begin(); i != wantToRun.end(); ++i) { running.push_front(*i); } wantToRun.clear(); //Check on the sleeping threads if (sleeping.size() > 0) { CCobThread *cur = sleeping.top(); while ((cur != NULL) && (cur->GetWakeTime() < GCurrentTime)) { // Start with removing the executing thread from the queue sleeping.pop(); //Run forward again. This can quite possibly readd the thread to the sleeping array again //But it will not interfere since it is guaranteed to sleep > 0 ms //logOutput.Print("Now 2running %d: %s", GCurrentTime, cur->GetName().c_str()); #ifdef _CONSOLE printf("+++\n"); #endif if (cur->state == CCobThread::Sleep) { cur->state = CCobThread::Run; int res = cur->Tick(deltaTime); cur->CommitAnims(deltaTime); if (res == -1) delete cur; } else if (cur->state == CCobThread::Dead) { delete cur; } else { logOutput.Print("CobError: Sleeping thread strange state %d", cur->state); } if (sleeping.size() > 0) cur = sleeping.top(); else cur = NULL; } } //Tick all instances that have registered themselves as animating list<CCobInstance *>::iterator it = animating.begin(); list<CCobInstance *>::iterator curit; while (it != animating.end()) { curit = it++; if ((*curit)->Tick(deltaTime) == -1) animating.erase(curit); } END_TIME_PROFILE("Scripts"); }