metaScripting_ScriptBinding.cc 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2013 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "platform/platform.h"
  23. #include "console/console.h"
  24. #include "console/consoleInternal.h"
  25. #include "console/ast.h"
  26. #include "io/resource/resourceManager.h"
  27. #include "io/fileStream.h"
  28. #include "console/compiler.h"
  29. #if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_OSX)
  30. #include <ifaddrs.h>
  31. #include <arpa/inet.h>
  32. #endif
  33. // Buffer for expanding script filenames.
  34. static char pathBuffer[1024];
  35. static U32 execDepth = 0;
  36. extern S32 QSORT_CALLBACK ACRCompare(const void *aptr, const void *bptr);
  37. ConsoleFunctionGroupBegin(MetaScripting, "Functions that let you manipulate the scripting engine programmatically.");
  38. /*! @defgroup MetaScriptingFunctions Meta-Scripting
  39. @ingroup TorqueScriptFunctions
  40. @{
  41. */
  42. /*! Use the call function to dynamically build and call a function.
  43. @param funcName A string containing the unadorned name of a function to be executed.
  44. @param args .. - Any arguments that should be passed to the function.
  45. @return Returns a string containing the results from the function that is built and called.
  46. @sa eval
  47. */
  48. ConsoleFunctionWithDocs(call, ConsoleString, 2, 0, ( funcName, [args ... ]?))
  49. {
  50. return Con::execute(argc - 1, argv + 1);
  51. }
  52. static StringTableEntry getDSOPath(const char *scriptPath)
  53. {
  54. const char *slash = dStrrchr(scriptPath, '/');
  55. return StringTable->insertn(scriptPath, slash - scriptPath, true);
  56. }
  57. /*! Returns the DSO path of the given filename
  58. @param scriptFileName A string contains the file to search for
  59. @return Returns either the requested pathname as a string, or an empty string if not found.
  60. */
  61. ConsoleFunctionWithDocs(getDSOPath, ConsoleString, 2, 2, (scriptFileName))
  62. {
  63. Con::expandPath(pathBuffer, sizeof(pathBuffer), argv[1]);
  64. const char *filename = getDSOPath(pathBuffer);
  65. if(filename == NULL || *filename == 0)
  66. return "";
  67. return filename;
  68. }
  69. /*! Use the compile function to pre-compile a script file without executing the contents.
  70. @param fileName A path to the script to compile.
  71. @return Returns 1 if the script compiled without errors and 0 if the file did not compile correctly or if the path is wrong. Also, ff the path is invalid, an error will print to the console.
  72. @sa exec
  73. */
  74. ConsoleFunctionWithDocs(compile, ConsoleBool, 2, 2, ( fileName ))
  75. {
  76. TORQUE_UNUSED( argc );
  77. char nameBuffer[512];
  78. char* script = NULL;
  79. U32 scriptSize = 0;
  80. FileTime comModifyTime, scrModifyTime;
  81. Con::expandPath(pathBuffer, sizeof(pathBuffer), argv[1]);
  82. // Figure out where to put DSOs
  83. StringTableEntry dsoPath = getDSOPath(pathBuffer);
  84. // If the script file extention is '.ed.cs' then compile it to a different compiled extention
  85. bool isEditorScript = false;
  86. const char *ext = dStrrchr( pathBuffer, '.' );
  87. if( ext && ( dStricmp( ext, ".cs" ) == 0 ) )
  88. {
  89. const char* ext2 = ext - 3;
  90. if( dStricmp( ext2, ".ed.cs" ) == 0 )
  91. isEditorScript = true;
  92. }
  93. else if( ext && ( dStricmp( ext, ".gui" ) == 0 ) )
  94. {
  95. const char* ext2 = ext - 3;
  96. if( dStricmp( ext2, ".ed.gui" ) == 0 )
  97. isEditorScript = true;
  98. }
  99. const char *filenameOnly = dStrrchr(pathBuffer, '/');
  100. if(filenameOnly)
  101. ++filenameOnly;
  102. else
  103. filenameOnly = pathBuffer;
  104. if( isEditorScript )
  105. dStrcpyl(nameBuffer, sizeof(nameBuffer), dsoPath, "/", filenameOnly, ".edso", NULL);
  106. else
  107. dStrcpyl(nameBuffer, sizeof(nameBuffer), dsoPath, "/", filenameOnly, ".dso", NULL);
  108. ResourceObject *rScr = ResourceManager->find(pathBuffer);
  109. ResourceObject *rCom = ResourceManager->find(nameBuffer);
  110. if(rCom)
  111. rCom->getFileTimes(NULL, &comModifyTime);
  112. if(rScr)
  113. rScr->getFileTimes(NULL, &scrModifyTime);
  114. Stream *s = ResourceManager->openStream(pathBuffer);
  115. if(s)
  116. {
  117. scriptSize = ResourceManager->getSize(pathBuffer);
  118. script = new char [scriptSize+1];
  119. s->read(scriptSize, script);
  120. ResourceManager->closeStream(s);
  121. script[scriptSize] = 0;
  122. }
  123. if (!scriptSize || !script)
  124. {
  125. delete [] script;
  126. Con::errorf(ConsoleLogEntry::Script, "compile: invalid script file %s.", pathBuffer);
  127. return false;
  128. }
  129. // compile this baddie.
  130. // -Mat reducing console noise
  131. #if defined(TORQUE_DEBUG)
  132. Con::printf("Compiling %s...", pathBuffer);
  133. #endif
  134. CodeBlock *code = new CodeBlock();
  135. code->compile(nameBuffer, pathBuffer, script);
  136. delete code;
  137. code = NULL;
  138. delete[] script;
  139. return true;
  140. }
  141. /*!
  142. */
  143. ConsoleFunctionWithDocs(compilePath, ConsoleString, 2, 2, ( path ))
  144. {
  145. if ( !Con::expandPath(pathBuffer, sizeof(pathBuffer), argv[1]) )
  146. return "-1 0";
  147. const char *compileArgs[2] = { "compile", NULL };
  148. S32 failedScripts = 0;
  149. S32 totalScripts = 0;
  150. ResourceObject *match = NULL;
  151. while ( (match = ResourceManager->findMatch( pathBuffer, &compileArgs[1], match )) )
  152. {
  153. if ( !ccompile( NULL, 1, compileArgs ) )
  154. failedScripts++;
  155. totalScripts++;
  156. }
  157. char* result = Con::getReturnBuffer(32);
  158. dSprintf( result, 32, "%d %d", failedScripts, totalScripts );
  159. return result;
  160. }
  161. static bool scriptExecutionEcho = false;
  162. /*! Whether to echo script file execution or not.
  163. */
  164. ConsoleFunctionWithDocs(setScriptExecEcho, ConsoleVoid, 2, 2, (echo?))
  165. {
  166. scriptExecutionEcho = dAtob(argv[1]);
  167. }
  168. /*! Use the exec function to compile and execute a normal script, or a special journal script.
  169. If $Pref::ignoreDSOs is set to true, the system will use .cs before a .dso file if both are found.
  170. @param fileName A string containing a path to the script to be compiled and executed.
  171. @param nocalls A boolean value. If this value is set to true, then all function calls encountered while executing the script file will be skipped and not called. This allows us to re-define function definitions found in a script file, without re-executing other worker scripts in the same file.
  172. @param journalScript A boolean value. If this value is set tot true, and if a journal is being played, the engine will attempt to read this script from the journal stream. If no journal is playing, this field is ignored.
  173. @return Returns true if the file compiled and executed w/o errors, false otherwise.
  174. @sa compile
  175. */
  176. ConsoleFunctionWithDocs(exec, ConsoleBool, 2, 4, ( fileName, [nocalls]?, [journalScript ]?))
  177. {
  178. execDepth++;
  179. #ifdef TORQUE_ALLOW_JOURNALING
  180. bool journal = false;
  181. if(journalDepth >= execDepth)
  182. journalDepth = execDepth + 1;
  183. else
  184. journal = true;
  185. #endif //TORQUE_ALLOW_JOURNALING
  186. bool noCalls = false;
  187. bool ret = false;
  188. if(argc >= 3 && dAtoi(argv[2]))
  189. noCalls = true;
  190. #ifdef TORQUE_ALLOW_JOURNALING
  191. if(argc >= 4 && dAtoi(argv[3]) && !journal)
  192. {
  193. journal = true;
  194. journalDepth = execDepth;
  195. }
  196. #endif //TORQUE_ALLOW_JOURNALING
  197. // Determine the filename we actually want...
  198. Con::expandPath(pathBuffer, sizeof(pathBuffer), argv[1]);
  199. // Figure out where to put DSOs
  200. StringTableEntry dsoPath = getDSOPath(pathBuffer);
  201. const char *ext = dStrrchr(pathBuffer, '.');
  202. if(!ext)
  203. {
  204. // We need an extension!
  205. Con::errorf(ConsoleLogEntry::Script, "exec: invalid script file name %s.", pathBuffer);
  206. execDepth--;
  207. return false;
  208. }
  209. // Check Editor Extensions
  210. bool isEditorScript = false;
  211. #ifdef TORQUE_ALLOW_DSO_GENERATION
  212. // If the script file extension is '.ed.cs' then compile it to a different compiled extension
  213. if( dStricmp( ext, ".cs" ) == 0 )
  214. {
  215. const char* ext2 = ext - 3;
  216. if( dStricmp( ext2, ".ed.cs" ) == 0 )
  217. isEditorScript = true;
  218. }
  219. else if( dStricmp( ext, ".gui" ) == 0 )
  220. {
  221. const char* ext2 = ext - 3;
  222. if( dStricmp( ext2, ".ed.gui" ) == 0 )
  223. isEditorScript = true;
  224. }
  225. #endif //TORQUE_ALLOW_DSO_GENERATION
  226. // rdbhack: if we can't find the script file in the game directory, look for it
  227. // in the Application Data directory. This makes it possible to keep the user
  228. // ignorant of where the files are actually saving to, thus eliminating the need
  229. // for the script functions: execPrefs, getUserDataDirectory, etc.
  230. //
  231. // This works because we know that script files located in the prefs path will
  232. // not have compiled versions (it checks for this further down). Otherwise this
  233. // would be a big problem!
  234. StringTableEntry scriptFileName = StringTable->EmptyString;
  235. //Luma : This is redundant, we wont be building dso's on the device -
  236. //plus saving dso to the user directory when attempting build for the
  237. //release tests on iPhone is irrelevant.
  238. #ifdef TORQUE_ALLOW_DSO_GENERATION
  239. if(!ResourceManager->find(pathBuffer))
  240. {
  241. // NOTE: this code is pretty much a duplication of code much further down in this
  242. // function...
  243. // our work just got a little harder.. if we couldn't find the .cs, then we need to
  244. // also look for the .dso BEFORE we can try the prefs path.. UGH
  245. const char *filenameOnly = dStrrchr(pathBuffer, '/');
  246. if(filenameOnly)
  247. ++filenameOnly;
  248. else
  249. filenameOnly = pathBuffer;
  250. // we could skip this step and rid ourselves of a bunch of nonsense but we can't be
  251. // certain the dso path is the same as the path given to use in scriptFileNameBuffer
  252. char pathAndFilename[1024];
  253. Platform::makeFullPathName(filenameOnly, pathAndFilename, sizeof(pathAndFilename), dsoPath);
  254. char nameBuffer[1024];
  255. if( isEditorScript ) // this should never be the case since we are a PLAYER not a TOOL, but you never know
  256. dStrcpyl(nameBuffer, sizeof(nameBuffer), pathAndFilename, ".edso", NULL);
  257. else
  258. dStrcpyl(nameBuffer, sizeof(nameBuffer), pathAndFilename, ".dso", NULL);
  259. if(!ResourceManager->find(nameBuffer))
  260. scriptFileName = Platform::getPrefsPath(Platform::stripBasePath(pathBuffer));
  261. else
  262. scriptFileName = StringTable->insert(pathBuffer);
  263. }
  264. else
  265. scriptFileName = StringTable->insert(pathBuffer);
  266. #else //TORQUE_ALLOW_DSO_GENERATION
  267. //Luma : Just insert the file name.
  268. scriptFileName = StringTable->insert(pathBuffer);
  269. #endif //TORQUE_ALLOW_DSO_GENERATION
  270. //Luma : Something screwed up so get out early
  271. if(scriptFileName == NULL || *scriptFileName == 0)
  272. {
  273. execDepth--;
  274. return false;
  275. }
  276. #ifdef TORQUE_ALLOW_JOURNALING
  277. bool compiled = dStricmp(ext, ".mis") && !journal && !Con::getBoolVariable("Scripts::ignoreDSOs");
  278. #else
  279. bool compiled = dStricmp(ext, ".mis") && !Con::getBoolVariable("Scripts::ignoreDSOs");
  280. #endif //TORQUE_ALLOW_JOURNALING
  281. // [tom, 12/5/2006] stripBasePath() messes up if the filename is not in the exe
  282. // path, current directory or prefs path. Thus, getDSOFilename() will also mess
  283. // up and so this allows the scripts to still load but without a DSO.
  284. if(Platform::isFullPath(Platform::stripBasePath(pathBuffer)))
  285. compiled = false;
  286. // [tom, 11/17/2006] It seems to make sense to not compile scripts that are in the
  287. // prefs directory. However, getDSOPath() can handle this situation and will put
  288. // the dso along with the script to avoid name clashes with tools/game dsos.
  289. #ifdef TORQUE_ALLOW_DSO_GENERATION
  290. // Is this a file we should compile? (anything in the prefs path should not be compiled)
  291. StringTableEntry prefsPath = Platform::getPrefsPath();
  292. if( dStrlen(prefsPath) > 0 && dStrnicmp(scriptFileName, prefsPath, dStrlen(prefsPath)) == 0)
  293. compiled = false;
  294. #endif //TORQUE_ALLOW_DSO_GENERATION
  295. // If we're in a journaling mode, then we will read the script
  296. // from the journal file.
  297. #ifdef TORQUE_ALLOW_JOURNALING
  298. if(journal && Game->isJournalReading())
  299. {
  300. char fileNameBuf[256];
  301. bool fileRead;
  302. U32 fileSize;
  303. Game->getJournalStream()->readString(fileNameBuf);
  304. Game->getJournalStream()->read(&fileRead);
  305. if(!fileRead)
  306. {
  307. Con::errorf(ConsoleLogEntry::Script, "Journal script read (failed) for %s", fileNameBuf);
  308. execDepth--;
  309. return false;
  310. }
  311. Game->journalRead(&fileSize);
  312. char *script = new char[fileSize + 1];
  313. Game->journalRead(fileSize, script);
  314. script[fileSize] = 0;
  315. Con::printf("Executing (journal-read) %s.", scriptFileName);
  316. CodeBlock *newCodeBlock = new CodeBlock();
  317. newCodeBlock->compileExec(scriptFileName, script, noCalls, 0);
  318. delete [] script;
  319. execDepth--;
  320. return true;
  321. }
  322. #endif //TORQUE_ALLOW_JOURNALING
  323. // Ok, we let's try to load and compile the script.
  324. ResourceObject *rScr = ResourceManager->find(scriptFileName);
  325. ResourceObject *rCom = NULL;
  326. char nameBuffer[512];
  327. char* script = NULL;
  328. U32 scriptSize = 0;
  329. U32 version;
  330. Stream *compiledStream = NULL;
  331. FileTime comModifyTime, scrModifyTime;
  332. // Check here for .edso
  333. //bool edso = false;
  334. //if( dStricmp( ext, ".edso" ) == 0 && rScr )
  335. //{
  336. // edso = true;
  337. // rCom = rScr;
  338. // rScr = NULL;
  339. // rCom->getFileTimes( NULL, &comModifyTime );
  340. // dStrcpy( nameBuffer, scriptFileName );
  341. //}
  342. // If we're supposed to be compiling this file, check to see if there's a DSO
  343. if(compiled /*&& !edso*/)
  344. {
  345. const char *filenameOnly = dStrrchr(scriptFileName, '/');
  346. if(filenameOnly)
  347. ++filenameOnly; //remove the / at the front
  348. else
  349. filenameOnly = scriptFileName;
  350. char pathAndFilename[1024];
  351. Platform::makeFullPathName(filenameOnly, pathAndFilename, sizeof(pathAndFilename), dsoPath);
  352. if( isEditorScript )
  353. dStrcpyl(nameBuffer, sizeof(nameBuffer), pathAndFilename, ".edso", NULL);
  354. else
  355. dStrcpyl(nameBuffer, sizeof(nameBuffer), pathAndFilename, ".dso", NULL);
  356. rCom = ResourceManager->find(nameBuffer);
  357. if(rCom)
  358. rCom->getFileTimes(NULL, &comModifyTime);
  359. if(rScr)
  360. rScr->getFileTimes(NULL, &scrModifyTime);
  361. }
  362. // Let's do a sanity check to complain about DSOs in the future.
  363. //
  364. // MM: This doesn't seem to be working correctly for now so let's just not issue
  365. // the warning until someone knows how to resolve it.
  366. //
  367. //if(compiled && rCom && rScr && Platform::compareFileTimes(comModifyTime, scrModifyTime) < 0)
  368. //{
  369. //Con::warnf("exec: Warning! Found a DSO from the future! (%s)", nameBuffer);
  370. //}
  371. // If we had a DSO, let's check to see if we should be reading from it.
  372. if((compiled && rCom) && (!rScr || Platform::compareFileTimes(comModifyTime, scrModifyTime) >= 0))
  373. {
  374. compiledStream = ResourceManager->openStream(nameBuffer);
  375. if (compiledStream)
  376. {
  377. // Check the version!
  378. compiledStream->read(&version);
  379. if(version != DSO_VERSION)
  380. {
  381. Con::warnf("exec: Found an old DSO (%s, ver %d < %d), ignoring.", nameBuffer, version, DSO_VERSION);
  382. ResourceManager->closeStream(compiledStream);
  383. compiledStream = NULL;
  384. }
  385. }
  386. }
  387. #ifdef TORQUE_ALLOW_JOURNALING
  388. // If we're journalling, let's write some info out.
  389. if(journal && Game->isJournalWriting())
  390. Game->getJournalStream()->writeString(scriptFileName);
  391. #endif //TORQUE_ALLOW_JOURNALING
  392. if(rScr && !compiledStream)
  393. {
  394. // If we have source but no compiled version, then we need to compile
  395. // (and journal as we do so, if that's required).
  396. //Con::errorf( "No DSO found! : %s", scriptFileName );
  397. Stream *s = ResourceManager->openStream(scriptFileName);
  398. #ifdef TORQUE_ALLOW_JOURNALING
  399. if(journal && Game->isJournalWriting())
  400. Game->getJournalStream()->write(bool(s != NULL));
  401. #endif //TORQUE_ALLOW_JOURNALING
  402. if(s)
  403. {
  404. scriptSize = ResourceManager->getSize(scriptFileName);
  405. script = new char [scriptSize+1];
  406. s->read(scriptSize, script);
  407. #ifdef TORQUE_ALLOW_JOURNALING
  408. if(journal && Game->isJournalWriting())
  409. {
  410. Game->journalWrite(scriptSize);
  411. Game->journalWrite(scriptSize, script);
  412. }
  413. #endif //TORQUE_ALLOW_JOURNALING
  414. ResourceManager->closeStream(s);
  415. script[scriptSize] = 0;
  416. }
  417. if (!scriptSize || !script)
  418. {
  419. delete [] script;
  420. Con::errorf(ConsoleLogEntry::Script, "exec: invalid script file %s.", scriptFileName);
  421. execDepth--;
  422. return false;
  423. }
  424. //Luma: Sven -
  425. // no dsos in the editor, seems to fail with so many console changes and version crap. Leaving it to
  426. // work with cs files as is, as they are included with the source either way.
  427. //Also, no DSO generation on iPhone
  428. #ifdef TORQUE_OS_IOS
  429. if(false)
  430. #else
  431. if(compiled)
  432. #endif
  433. {
  434. // compile this baddie.
  435. #if defined(TORQUE_DEBUG)
  436. Con::printf("Compiling %s...", scriptFileName);
  437. #endif
  438. CodeBlock *code = new CodeBlock();
  439. code->compile(nameBuffer, scriptFileName, script);
  440. delete code;
  441. code = NULL;
  442. compiledStream = ResourceManager->openStream(nameBuffer);
  443. if(compiledStream)
  444. {
  445. compiledStream->read(&version);
  446. }
  447. else
  448. {
  449. // We have to exit out here, as otherwise we get double error reports.
  450. delete [] script;
  451. execDepth--;
  452. return false;
  453. }
  454. }
  455. }
  456. else
  457. {
  458. #ifdef TORQUE_ALLOW_JOURNALING
  459. if(journal && Game->isJournalWriting())
  460. Game->getJournalStream()->write(bool(false));
  461. #endif //TORQUE_ALLOW_JOURNALING
  462. }
  463. //Luma : Load compiled script here
  464. if(compiledStream)
  465. {
  466. // Delete the script object first to limit memory used
  467. // during recursive execs.
  468. delete [] script;
  469. script = 0;
  470. // We're all compiled, so let's run it.
  471. //Luma: Profile script executions
  472. F32 st1 = (F32)Platform::getRealMilliseconds();
  473. CodeBlock *code = new CodeBlock;
  474. code->read(scriptFileName, *compiledStream);
  475. ResourceManager->closeStream(compiledStream);
  476. code->exec(0, scriptFileName, NULL, 0, NULL, noCalls, NULL, 0);
  477. F32 et1 = (F32)Platform::getRealMilliseconds();
  478. F32 etf = et1 - st1;
  479. if ( scriptExecutionEcho )
  480. Con::printf("Loaded compiled script %s. Took %.0f ms", scriptFileName, etf);
  481. ret = true;
  482. }
  483. else if(rScr) //Luma : Load normal cs file here.
  484. {
  485. // No compiled script, let's just try executing it
  486. // directly... this is either a mission file, or maybe
  487. // we're on a readonly volume.
  488. CodeBlock *newCodeBlock = new CodeBlock();
  489. StringTableEntry name = StringTable->insert(scriptFileName);
  490. //Luma: Profile script executions
  491. F32 st1 = (F32)Platform::getRealMilliseconds();
  492. newCodeBlock->compileExec(name, script, noCalls, 0);
  493. F32 et1 = (F32)Platform::getRealMilliseconds();
  494. F32 etf = et1 - st1;
  495. if ( scriptExecutionEcho )
  496. Con::printf("Executed %s. Took %.0f ms", scriptFileName, etf);
  497. ret = true;
  498. }
  499. else
  500. {
  501. // Don't have anything.
  502. Con::warnf(ConsoleLogEntry::Script, "Missing file: %s!", pathBuffer);
  503. ret = false;
  504. }
  505. delete [] script;
  506. execDepth--;
  507. return ret;
  508. }
  509. /*! Use the eval function to execute any valid script statement.
  510. If you choose to eval a multi-line statement, be sure that there are no comments or comment blocks embedded in the script string.
  511. @param script A string containing a valid script statement. This may be a single line statement or multiple lines concatenated together with new-line characters.
  512. @return Returns the result of executing the script statement.
  513. @sa call
  514. */
  515. ConsoleFunctionWithDocs(eval, ConsoleString, 2, 2, ( script ))
  516. {
  517. TORQUE_UNUSED( argc );
  518. return Con::evaluate(argv[1], false, NULL);
  519. }
  520. /*! Grabs the relevant data for the variable represented by the given string
  521. @param varName A String representing the variable to check
  522. @return Returns a string containing component data for the requested variable or an empty string if not found.
  523. */
  524. ConsoleFunctionWithDocs(getVariable, ConsoleString, 2, 2, (string varName))
  525. {
  526. return Con::getVariable(argv[1]);
  527. }
  528. /*! Checks whether given name represents a current valid function.
  529. @param funcName The name of the function to check.
  530. @return Returns either true if the string represents a valid function or false if not.
  531. */
  532. ConsoleFunctionWithDocs(isFunction, ConsoleBool, 2, 2, (string funcName))
  533. {
  534. return Con::isFunction(argv[1]);
  535. }
  536. /*! Checks whether the given method name represents a valid method within the given namespace.
  537. @param namespace A string representing the namespace in which the method should reside.
  538. @param method The name of the method in question.
  539. @return Returns a boolean value which is true if the given mathod name represents a valid method in the namespace and false otherwise.
  540. */
  541. ConsoleFunctionWithDocs(isMethod, ConsoleBool, 3, 3, (string namespace, string method))
  542. {
  543. Namespace* ns = Namespace::find( StringTable->insert( argv[1] ) );
  544. Namespace::Entry* nse = ns->lookup( StringTable->insert( argv[2] ) );
  545. if( !nse )
  546. return false;
  547. return true;
  548. }
  549. /*! Attempts to extract a mod directory from path. Returns empty string on failure.
  550. */
  551. ConsoleFunctionWithDocs(getModNameFromPath, ConsoleString, 2, 2, (string path))
  552. {
  553. StringTableEntry modPath = Con::getModNameFromPath(argv[1]);
  554. return modPath ? modPath : "";
  555. }
  556. //----------------------------------------------------------------
  557. /*!
  558. */
  559. ConsoleFunctionWithDocs(getPrefsPath, ConsoleString, 1, 2, ([fileName]?))
  560. {
  561. const char *filename = Platform::getPrefsPath(argc > 1 ? argv[1] : NULL);
  562. if(filename == NULL || *filename == 0)
  563. return "";
  564. return filename;
  565. }
  566. /*!
  567. */
  568. ConsoleFunctionWithDocs(execPrefs, ConsoleBool, 2, 4, (fileName, [nocalls]?, [journalScript]?))
  569. {
  570. const char *filename = Platform::getPrefsPath(argv[1]);
  571. if (filename == NULL || *filename == 0)
  572. return false;
  573. if ( !Platform::isFile(filename) )
  574. return false;
  575. argv[0] = "exec";
  576. argv[1] = filename;
  577. return dAtob(Con::execute(argc, argv));
  578. }
  579. /*! Use the export function to save all global variables matching the specified name pattern in wildCard to a file, either appending to that file or over-writing it.
  580. @param wildCard A string identifying what variable(s) to export. All characters used to create a global are allowed and the special symbol \*\, meaning 0 or more instances of any character.
  581. @param fileName A string containing a path to a file in which to save the globals and their definitions.
  582. @param append A boolean value. If this value is true, the file will be appended to if it exists, otherwise it will be created/over-written.
  583. @return No return value
  584. */
  585. ConsoleFunctionWithDocs(export, ConsoleVoid, 2, 4, ( wildCard, [fileName]?, [append]?))
  586. {
  587. // Fetch the wildcard.
  588. const char* pWildcard = argv[1];
  589. // Fetch the filename.
  590. const char* pFilename = NULL;
  591. if ( argc >= 3 )
  592. {
  593. Con::expandPath( pathBuffer, sizeof(pathBuffer), argv[2] );
  594. pFilename = pathBuffer;
  595. }
  596. // Fetch append flag.
  597. const bool append = argc >= 4 ? dAtob(argv[3] ) : false;
  598. // Export the variables.
  599. gEvalState.globalVars.exportVariables( pWildcard, pFilename, append );
  600. }
  601. /*! Use the deleteVariables function to delete any global variable matching the wildCard statement.
  602. @param wildCard A string identifying what variable(s) to delete. All characters used to create a global are allowed and the special symbol \*\, meaning 0 or more instances of any character.
  603. @return No return value
  604. */
  605. ConsoleFunctionWithDocs(deleteVariables, ConsoleVoid, 2, 2, ( wildCard ))
  606. {
  607. TORQUE_UNUSED( argc );
  608. gEvalState.globalVars.deleteVariables(argv[1]);
  609. }
  610. //----------------------------------------------------------------
  611. /*! Use the trace function to enable (or disable) function call tracing. If enabled, tracing will print a message every time a function is entered, showing what arguments it received, and it will print a message every time a function is exited, showing the return value (or last value of last statement) for that function.
  612. @param enable A boolean value. If set to true, tracing is enabled, otherwise it is disabled.
  613. @return No return value
  614. */
  615. ConsoleFunctionWithDocs(trace, ConsoleVoid, 2, 2, ( enable ))
  616. {
  617. TORQUE_UNUSED( argc );
  618. gEvalState.traceOn = dAtob(argv[1]);
  619. Con::printf("Console trace is %s", gEvalState.traceOn ? "on." : "off.");
  620. }
  621. //----------------------------------------------------------------
  622. #if defined(TORQUE_DEBUG) || defined(INTERNAL_RELEASE)
  623. /*! Use the debug function to cause the engine to issue a debug break and to break into an active debugger.
  624. For this to work, the engine must have been compiled with either TORQUE_DEBUG, or INTERNAL_RELEASE defined
  625. @return No return value.
  626. */
  627. ConsoleFunctionWithDocs(debug, ConsoleVoid, 1, 1, ())
  628. {
  629. TORQUE_UNUSED( argc );
  630. TORQUE_UNUSED( argv );
  631. Platform::debugBreak();
  632. }
  633. #endif
  634. #if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_OSX)
  635. //Some code for allowing torsion to connect, this code returns the ipads local ip address
  636. //code was obtained from http://blog.zachwaugh.com/post/309927273/programmatically-retrieving-ip-address-of-iphone
  637. //adapted to iT2D by me
  638. /*! Gets the Apple hardware local IP on wifi. Should work on OS X and iOS
  639. */
  640. ConsoleFunctionWithDocs(getAppleDeviceIPAddress, ConsoleString, 1, 1, ())
  641. {
  642. char *address = Con::getReturnBuffer(32);
  643. dStrcpy(address, "error");
  644. struct ifaddrs *interfaces = NULL;
  645. struct ifaddrs *temp_addr = NULL;
  646. int success = 0;
  647. // retrieve the current interfaces - returns 0 on success
  648. success = getifaddrs(&interfaces);
  649. if (success == 0)
  650. {
  651. // Loop through linked list of interfaces
  652. temp_addr = interfaces;
  653. while(temp_addr != NULL)
  654. {
  655. if(temp_addr->ifa_addr->sa_family == AF_INET)
  656. {
  657. // Check if interface is en0 which is the wifi connection on the iPhone
  658. // Note: Could be different on MacOSX and simulator and may need modifying
  659. if(dStrcmp(temp_addr->ifa_name, "en0") == 0)
  660. {
  661. dStrcpy(address, inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr));
  662. }
  663. }
  664. temp_addr = temp_addr->ifa_next;
  665. }
  666. }
  667. // Free memory
  668. freeifaddrs(interfaces);
  669. return address;
  670. }
  671. #endif
  672. //----------------------------------------------------------------
  673. /*!
  674. */
  675. ConsoleFunctionWithDocs( enumerateConsoleClasses, ConsoleString, 1, 2, ([baseClass]?))
  676. {
  677. AbstractClassRep *base = NULL;
  678. if(argc > 1)
  679. {
  680. base = AbstractClassRep::findClassRep(argv[1]);
  681. if(!base)
  682. return "";
  683. }
  684. Vector<AbstractClassRep*> classes;
  685. U32 bufSize = 0;
  686. for(AbstractClassRep *rep = AbstractClassRep::getClassList(); rep; rep = rep->getNextClass())
  687. {
  688. if( !base || rep->isClass(base))
  689. {
  690. classes.push_back(rep);
  691. bufSize += dStrlen(rep->getClassName()) + 1;
  692. }
  693. }
  694. if(!classes.size())
  695. return "";
  696. dQsort(classes.address(), classes.size(), sizeof(AbstractClassRep*), ACRCompare);
  697. char* ret = Con::getReturnBuffer(bufSize);
  698. dStrcpy( ret, classes[0]->getClassName());
  699. for( U32 i=0; i< (U32)classes.size(); i++)
  700. {
  701. dStrcat( ret, "\t" );
  702. dStrcat( ret, classes[i]->getClassName() );
  703. }
  704. return ret;
  705. }
  706. /*! @} */ // group MetaScriptFunctions