00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include "Script.h"
00018 #include "ScriptEngine.h"
00019 #include "Clock.h"
00020 #include "Log.h"
00021 #include "Kernel.h"
00022 #include <boost/algorithm/string/trim.hpp>
00023
00024 namespace nrEngine {
00025
00026
00027 Script::Script() : IScript("Script")
00028 {
00029 mLastLine = 0;
00030 mLoop = NO_LOOP;
00031 mTime = 0;
00032 bRunStepwise = true;
00033 mStopTime = 0;
00034 mRunningTimeLength = 0;
00035 mFirstRunTimed = true;
00036 mScriptStartTime = 0;
00037 }
00038
00039
00040 Script::~Script()
00041 {
00042 unloadResource();
00043 }
00044
00045
00046
00047 Result Script::loadFromString(const std::string& str)
00048 {
00049
00050 setTaskName(getResourceName() + "_ScriptTask");
00051
00052
00053 mContent = str;
00054
00055
00056 Result ret = parse(mContent);
00057 if (ret == OK) notifyLoaded();
00058
00059 return ret;
00060 }
00061
00062
00063 std::string Script::cleanScript(const std::string& script)
00064 {
00065
00066 std::stringstream str(script);
00067 if (script.length() == 0 || !str.good()) return script;
00068 std::string resultScript;
00069
00070
00071 char buf[2048];
00072 std::string buffer;
00073 std::string::size_type pos;
00074 std::string line;
00075
00076
00077 while (!str.eof())
00078 {
00079
00080 str.getline(buf, 2048);
00081 buffer = std::string(buf);
00082
00083
00084 pos = buffer.find("//");
00085 if (pos == std::string::npos)
00086 line = buffer;
00087 else
00088 line = buffer.substr(0, pos);
00089
00090
00091 boost::algorithm::trim(line);
00092
00093
00094 if (line.length() == 0) continue;
00095
00096
00097 resultScript += line;
00098 if (!str.eof()) resultScript += std::string("\n");
00099 }
00100
00101 return resultScript;
00102 }
00103
00104
00105 std::string Script::parseSubscripts(const std::string& script)
00106 {
00107
00108 int depth = 0, count = 0, curdepth = 0;
00109
00110
00111
00112
00113
00114
00115 std::string main;
00116 std::string sub;
00117 std::string* cur = &main;
00118
00119 for (unsigned int i=0; i < script.length(); i++)
00120 {
00121 if (script.at(i) == '{') curdepth ++;
00122
00123 if (script.at(i) == '{' && cur == &main && curdepth == 1)
00124 {
00125 cur = ⊂
00126 depth ++;
00127 }
00128 else if (script.at(i) == '}' && cur == &sub && curdepth == 1)
00129 {
00130 count ++;
00131 depth --;
00132
00133
00134 std::stringstream subscriptName;
00135 subscriptName << getResourceName() << std::string("_sub_") << count ;
00136
00137
00138 ResourcePtr<IScript> scr = Engine::sResourceManager()->createResource(subscriptName.str(), getResourceName(), "Script");
00139
00140
00141 if (scr.valid())
00142 {
00143 scr.lockResource();
00144 scr->loadFromString(sub);
00145 scr.unlockResource();
00146 mSubscripts.push_back(scr);
00147 }else{
00148 NR_Log(Log::LOG_ENGINE, Log::LL_ERROR, "Script (%s): Subscript could not be created. Maybe no proper loader exists. Script will not run.\n", getResourceName().c_str());
00149 return std::string("");
00150 }
00151
00152
00153 cur = &main;
00154 sub = std::string("");
00155 }
00156 else
00157 {
00158
00159 *cur += script.at(i);
00160 }
00161
00162 if (script.at(i) == '}') curdepth --;
00163 }
00164
00165
00166 if (depth != 0 || curdepth != 0)
00167 {
00168 NR_Log(Log::LOG_ENGINE, Log::LL_ERROR, "Script (%s): Subscript-brackets were not used properly. Depth is %d/%d, must be 0/0. Script disabled!", getResourceName().c_str(), depth, curdepth);
00169 return std::string("");
00170 }
00171
00172
00173
00174 return main;
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230 }
00231
00232
00233 Result Script::parse(const std::string& script)
00234 {
00235
00236
00237 std::stringstream str(parseSubscripts(cleanScript(script)));
00238 if (script.length() == 0 || !str.good()) return OK;
00239
00240
00241
00242 char buf[1024];
00243 std::string::size_type pos;
00244 std::string line;
00245
00246 while (!str.eof())
00247 {
00248
00249 str.getline(buf, 1024);
00250 line = std::string(buf);
00251
00252
00253 pos = line.find('^');
00254 if (pos != std::string::npos)
00255 {
00256
00257 std::string sparam = line.substr(pos+1);
00258 boost::algorithm::trim(sparam);
00259
00260
00261 std::vector<std::string> args;
00262 std::string param;
00263 tokenize(sparam, param, args);
00264
00265
00266 if (!setParameter(param, args))
00267 {
00268 NR_Log(Log::LOG_ENGINE, Log::LL_ERROR, "Script: Unknown local parameter %s in line \"%s\"", param.c_str(), line.c_str());
00269 return SCRIPT_PARSE_ERROR;
00270 }
00271 continue;
00272 }
00273
00274
00275 pos = line.find('|');
00276 Command cmd;
00277 cmd.timestamp = 0;
00278 cmd.estimatedStart = 0;
00279
00280
00281 if(pos != std::string::npos )
00282 {
00283
00284 std::string time = line.substr(0,pos);
00285 boost::algorithm::trim(time);
00286 std::string command = line.substr(pos+1);
00287
00288
00289 try{
00290 cmd.timestamp = boost::lexical_cast<float32>(time);
00291 tokenize(command, cmd.cmd, cmd.args);
00292 if (cmd.args.size() > 0 && cmd.args[0].length() > 0)
00293 {
00294 if (cmd.cmd == std::string("_stop_"))
00295 {
00296 mRunningTimeLength = cmd.timestamp;
00297 }else
00298 mTimedCommand.push_back(cmd);
00299 }
00300 }catch(...){
00301 NR_Log(Log::LOG_ENGINE, Log::LL_ERROR, "Script: Unknown syntax in \"%s\"\n", line.c_str());
00302 return SCRIPT_PARSE_ERROR;
00303 }
00304
00305
00306 }else{
00307 tokenize(line, cmd.cmd, cmd.args);
00308 if (cmd.args.size() > 0 && cmd.args[0].length() > 0)
00309 {
00310 mCommand.push_back(cmd);
00311 }
00312 }
00313 }
00314
00315 resetCommandFifo();
00316
00317
00318 return OK;
00319 }
00320
00321
00322 void Script::tokenize(const std::string& str, std::string& cmd, std::vector<std::string>& tokens)
00323 {
00324
00325 if (str.length() == 0) return;
00326
00327 using namespace std;
00328
00329
00330 const string delimiters = " ";
00331
00332
00333 string::size_type lastPos = str.find_first_not_of(delimiters, 0);
00334
00335
00336 string::size_type pos = str.find_first_of(delimiters, lastPos);
00337
00338 while (pos != string::npos || lastPos != string::npos)
00339 {
00340
00341 if (pos - lastPos > 0)
00342 tokens.push_back(str.substr(lastPos, pos - lastPos));
00343
00344
00345 lastPos = str.find_first_not_of(delimiters, pos);
00346
00347
00348 pos = str.find_first_of(delimiters, lastPos);
00349 }
00350
00351
00352 cmd = tokens[0];
00353 }
00354
00355
00356 bool Script::setParameter(const std::string& param, const std::vector<std::string>& args){
00357
00358 if (param == "loop")
00359 mLoop |= LOOP;
00360 else if (param == "loop_seq")
00361 mLoop |= LOOP_COMMAND;
00362 else if (param == "loop_timed")
00363 mLoop |= LOOP_TIMED_COMMAND;
00364 else if (param == "runcomplete")
00365 bRunStepwise = false;
00366
00367
00368 else if (param == "start_at")
00369 try{
00370 if (args.size() > 1) mScriptStartTime = boost::lexical_cast<float32>(args[1]);
00371 else throw boost::bad_lexical_cast();
00372 }catch(boost::bad_lexical_cast &){
00373 NR_Log(Log::LOG_ENGINE, Log::LL_WARNING, "Script: %s - not a valid value for \"start_at\" parameter specified", getResourceName().c_str());
00374 }
00375 else
00376 return false;
00377
00378 return true;
00379 }
00380
00381
00382 void Script::resetCommandFifo()
00383 {
00384
00385
00386 mCommandFifo.clear();
00387 for (uint32 i=0; i < mCommand.size(); i++){
00388 mCommandFifo.push_front(i);
00389 }
00390 }
00391
00392
00393 void Script::resetTimedCommandFifo(bool firstReset)
00394 {
00395 if (firstReset) mTimedCommandFifo.clear();
00396
00397
00398
00399
00400
00401
00402 for (int32 i=0; i < (int32)mTimedCommand.size(); i++)
00403 {
00404
00405 std::list< int32 >::iterator it = std::find(mTimedCommandFifo.begin(), mTimedCommandFifo.end(), i);
00406
00407
00408 if (it == mTimedCommandFifo.end() || firstReset)
00409 {
00410 mTimedCommandFifo.push_front(i);
00411 mTimedCommand[i].estimatedStart = mTimer->getTime() + mTimedCommand[i].timestamp;
00412 }
00413 }
00414 }
00415
00416
00417 Result Script::step()
00418 {
00419
00420 mTimer->setPause(false);
00421 mTime = mTimer->getTime();
00422
00423
00424
00425
00426 if (mScriptStartTime > mTime)
00427 {
00428
00429 setRunOnce(false);
00430
00431
00432 return OK;
00433 }
00434
00435
00436 if (mFirstRunTimed)
00437 {
00438
00439 mFirstRunTimed = false;
00440 resetTimedCommandFifo(true);
00441 setRunOnce(true);
00442 }
00443
00444
00445 if (mStopTime == 0 && mRunningTimeLength > 0) mStopTime = mTime + mRunningTimeLength;
00446
00447
00448
00449 std::list<int32>::iterator it;
00450 for (it = mTimedCommandFifo.begin(); it != mTimedCommandFifo.end(); )
00451 {
00452 int32 id = *it;
00453 mTimedCommand[id].time = mTime;
00454
00455
00456
00457
00458
00459
00460 if (mTimedCommand[id].estimatedStart < mTimedCommand[id].time)
00461 {
00462
00463 it = mTimedCommandFifo.erase(it);
00464
00465
00466 Engine::sScriptEngine()->call(mTimedCommand[id].cmd, mTimedCommand[id].args);
00467 }else
00468 it ++;
00469 }
00470
00471
00472 if (mCommandFifo.size())
00473 {
00474
00475 int32 id = mCommandFifo.back();
00476 mCommandFifo.pop_back();
00477
00478
00479 if (mCommand[id].cmd != std::string("_stop_"))
00480 {
00481 Engine::sScriptEngine()->call(mCommand[id].cmd, mCommand[id].args);
00482 }else{
00483 Engine::sKernel()->RemoveTask(this->getTaskID());
00484 }
00485 }
00486
00487
00488 reset();
00489
00490
00491 if (mTime > mStopTime && mStopTime > 0)
00492 {
00493 Engine::sKernel()->RemoveTask(this->getTaskID());
00494 }
00495
00496
00497
00498 return OK;
00499 }
00500
00501
00502 bool Script::hasCommands()
00503 {
00504 if (mCommandFifo.size() == 0 && mTimedCommandFifo.size() == 0 && !(mLoop & LOOP_COMMAND) && !(mLoop & LOOP_TIMED_COMMAND))
00505 return false;
00506
00507 return true;
00508 }
00509
00510
00511 Result Script::run()
00512 {
00513
00514 if (bRunStepwise) return step();
00515
00516
00517 return fullRun();
00518 }
00519
00520
00521
00522 Result Script::fullRun()
00523 {
00524
00525
00526 static bool warned = false;
00527 if (!warned && mLoop & LOOP_COMMAND){
00528 warned = true;
00529 NR_Log(Log::LOG_ENGINE, Log::LL_WARNING, "Script: %s - you are executing a looped script!!! Check this!!!", getResourceName().c_str());
00530 }
00531
00532
00533 bool bLoop = false;
00534 do {
00535
00536 while (mCommandFifo.size() > 0)
00537 {
00538
00539 int32 id = mCommandFifo.back();
00540 mCommandFifo.pop_back();
00541
00542
00543 Engine::sScriptEngine()->call(mCommand[id].cmd, mCommand[id].args);
00544 }
00545
00546
00547 reset();
00548 bLoop = hasCommands();
00549
00550 } while(bLoop && (mLoop & LOOP_COMMAND));
00551
00552 return OK;
00553 }
00554
00555
00556 void Script::onStartScript()
00557 {
00558
00559 for (unsigned int i = 0; i < mSubscripts.size(); i++)
00560 {
00561
00562 Script* subscript = dynamic_cast<Script*>(mSubscripts[i].get());
00563 if (subscript)
00564 {
00565
00566 subscript->mScriptStartTime += mScriptStartTime;
00567
00568
00569 subscript->execute();
00570
00571
00572 addTaskDependency(subscript->getTaskID());
00573 }
00574
00575 }
00576
00577
00578 mTimer = Engine::sClock()->createTimer();
00579 mTimer->setPause(true);
00580
00581
00582 resetCommandFifo();
00583 resetTimedCommandFifo(true);
00584 mFirstRunTimed = true;
00585 }
00586
00587
00588 bool Script::reset()
00589 {
00590 if (mCommandFifo.size() == 0 && (mLoop & LOOP_COMMAND)){
00591 resetCommandFifo();
00592 }else if (mTimedCommandFifo.size() == 0 && (mLoop & LOOP_TIMED_COMMAND)){
00593 resetTimedCommandFifo(false);
00594 }
00595 return true;
00596 }
00597
00598 };
00599