helperFunctions.cs 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 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. //------------------------------------------------------------------------------
  23. // Check if a script file exists, compiled or not.
  24. function isScriptFile(%path)
  25. {
  26. if( isFile(%path @ ".dso") || isFile(%path) )
  27. return true;
  28. return false;
  29. }
  30. function loadMaterials()
  31. {
  32. // Load any materials files for which we only have DSOs.
  33. for( %file = findFirstFile( "*/materials.cs.dso" );
  34. %file !$= "";
  35. %file = findNextFile( "*/materials.cs.dso" ))
  36. {
  37. // Only execute, if we don't have the source file.
  38. %csFileName = getSubStr( %file, 0, strlen( %file ) - 4 );
  39. if( !isFile( %csFileName ) )
  40. exec( %csFileName );
  41. }
  42. // Load all source material files.
  43. for( %file = findFirstFile( "*/materials.cs" );
  44. %file !$= "";
  45. %file = findNextFile( "*/materials.cs" ))
  46. {
  47. exec( %file );
  48. }
  49. // Load all materials created by the material editor if
  50. // the folder exists
  51. if( IsDirectory( "materialEditor" ) )
  52. {
  53. for( %file = findFirstFile( "materialEditor/*.cs.dso" );
  54. %file !$= "";
  55. %file = findNextFile( "materialEditor/*.cs.dso" ))
  56. {
  57. // Only execute, if we don't have the source file.
  58. %csFileName = getSubStr( %file, 0, strlen( %file ) - 4 );
  59. if( !isFile( %csFileName ) )
  60. exec( %csFileName );
  61. }
  62. for( %file = findFirstFile( "materialEditor/*.cs" );
  63. %file !$= "";
  64. %file = findNextFile( "materialEditor/*.cs" ))
  65. {
  66. exec( %file );
  67. }
  68. }
  69. }
  70. function reloadMaterials()
  71. {
  72. reloadTextures();
  73. loadMaterials();
  74. reInitMaterials();
  75. }
  76. function loadDatablockFiles( %datablockFiles, %recurse )
  77. {
  78. if ( %recurse )
  79. {
  80. recursiveLoadDatablockFiles( %datablockFiles, 9999 );
  81. return;
  82. }
  83. %count = %datablockFiles.count();
  84. for ( %i=0; %i < %count; %i++ )
  85. {
  86. %file = %datablockFiles.getKey( %i );
  87. if ( !isFile(%file @ ".dso") && !isFile(%file) )
  88. continue;
  89. exec( %file );
  90. }
  91. // Destroy the incoming list.
  92. //%datablockFiles.delete();
  93. }
  94. function recursiveLoadDatablockFiles( %datablockFiles, %previousErrors )
  95. {
  96. %reloadDatablockFiles = new ArrayObject();
  97. // Keep track of the number of datablocks that
  98. // failed during this pass.
  99. %failedDatablocks = 0;
  100. // Try re-executing the list of datablock files.
  101. %count = %datablockFiles.count();
  102. for ( %i=0; %i < %count; %i++ )
  103. {
  104. %file = %datablockFiles.getKey( %i );
  105. if ( !isFile(%file @ ".dso") && !isFile(%file) )
  106. continue;
  107. // Start counting copy constructor creation errors.
  108. $Con::objectCopyFailures = 0;
  109. exec( %file );
  110. // If errors occured then store this file for re-exec later.
  111. if ( $Con::objectCopyFailures > 0 )
  112. {
  113. %reloadDatablockFiles.add( %file );
  114. %failedDatablocks = %failedDatablocks + $Con::objectCopyFailures;
  115. }
  116. }
  117. // Clear the object copy failure counter so that
  118. // we get console error messages again.
  119. $Con::objectCopyFailures = -1;
  120. // Delete the old incoming list... we're done with it.
  121. //%datablockFiles.delete();
  122. // If we still have datablocks to retry.
  123. %newCount = %reloadDatablockFiles.count();
  124. if ( %newCount > 0 )
  125. {
  126. // If the datablock failures have not been reduced
  127. // from the last pass then we must have a real syntax
  128. // error and not just a bad dependancy.
  129. if ( %previousErrors > %failedDatablocks )
  130. recursiveLoadDatablockFiles( %reloadDatablockFiles, %failedDatablocks );
  131. else
  132. {
  133. // Since we must have real syntax errors do one
  134. // last normal exec to output error messages.
  135. loadDatablockFiles( %reloadDatablockFiles, false );
  136. }
  137. return;
  138. }
  139. // Cleanup the empty reload list.
  140. %reloadDatablockFiles.delete();
  141. }
  142. function getUserPath()
  143. {
  144. %temp = getUserHomeDirectory();
  145. echo(%temp);
  146. if(!isDirectory(%temp))
  147. {
  148. %temp = getUserDataDirectory();
  149. echo(%temp);
  150. if(!isDirectory(%temp))
  151. {
  152. %userPath = "data";
  153. }
  154. else
  155. {
  156. //put it in appdata/roaming
  157. %userPath = %temp @ "/" @ $appName;
  158. }
  159. }
  160. else
  161. {
  162. //put it in user/documents
  163. %userPath = %temp @ "/" @ $appName;
  164. }
  165. return %userPath;
  166. }
  167. function getPrefpath()
  168. {
  169. $prefPath = getUserPath() @ "/preferences";
  170. return $prefPath;
  171. }
  172. function updateTSShapeLoadProgress(%progress, %msg)
  173. {
  174. // Check if the loading GUI is visible and use that instead of the
  175. // separate import progress GUI if possible
  176. /* if ( isObject(LoadingGui) && LoadingGui.isAwake() )
  177. {
  178. // Save/Restore load progress at the start/end of the import process
  179. if ( %progress == 0 )
  180. {
  181. ColladaImportProgress.savedProgress = LoadingProgress.getValue();
  182. ColladaImportProgress.savedText = LoadingProgressTxt.getValue();
  183. ColladaImportProgress.msgPrefix = "Importing " @ %msg;
  184. %msg = "Reading file into memory...";
  185. }
  186. else if ( %progress == 1.0 )
  187. {
  188. LoadingProgress.setValue( ColladaImportProgress.savedProgress );
  189. LoadingProgressTxt.setValue( ColladaImportProgress.savedText );
  190. }
  191. %msg = ColladaImportProgress.msgPrefix @ ": " @ %msg;
  192. %progressCtrl = LoadingProgress;
  193. %textCtrl = LoadingProgressTxt;
  194. }
  195. else
  196. {
  197. //it's probably the editors using it
  198. if(isFunction("updateToolTSShapeLoadProgress"))
  199. {
  200. updateToolTSShapeLoadProgress(%progress, %msg);
  201. }
  202. }
  203. // Update progress indicators
  204. if (%progress == 0)
  205. {
  206. %progressCtrl.setValue(0.001);
  207. %textCtrl.setText(%msg);
  208. }
  209. else if (%progress != 1.0)
  210. {
  211. %progressCtrl.setValue(%progress);
  212. %textCtrl.setText(%msg);
  213. }
  214. Canvas.repaint(33);*/
  215. }
  216. /// A helper function which will return the ghosted client object
  217. /// from a server object when connected to a local server.
  218. function serverToClientObject( %serverObject )
  219. {
  220. assert( isObject( LocalClientConnection ), "serverToClientObject() - No local client connection found!" );
  221. assert( isObject( ServerConnection ), "serverToClientObject() - No server connection found!" );
  222. %ghostId = LocalClientConnection.getGhostId( %serverObject );
  223. if ( %ghostId == -1 )
  224. return 0;
  225. return ServerConnection.resolveGhostID( %ghostId );
  226. }
  227. //----------------------------------------------------------------------------
  228. // Debug commands
  229. //----------------------------------------------------------------------------
  230. function netSimulateLag( %msDelay, %packetLossPercent )
  231. {
  232. if ( %packetLossPercent $= "" )
  233. %packetLossPercent = 0;
  234. commandToServer( 'NetSimulateLag', %msDelay, %packetLossPercent );
  235. }
  236. //Various client functions
  237. function validateDatablockName(%name)
  238. {
  239. // remove whitespaces at beginning and end
  240. %name = trim( %name );
  241. // remove numbers at the beginning
  242. %numbers = "0123456789";
  243. while( strlen(%name) > 0 )
  244. {
  245. // the first character
  246. %firstChar = getSubStr( %name, 0, 1 );
  247. // if the character is a number remove it
  248. if( strpos( %numbers, %firstChar ) != -1 )
  249. {
  250. %name = getSubStr( %name, 1, strlen(%name) -1 );
  251. %name = ltrim( %name );
  252. }
  253. else
  254. break;
  255. }
  256. // replace whitespaces with underscores
  257. %name = strreplace( %name, " ", "_" );
  258. // remove any other invalid characters
  259. %invalidCharacters = "-+*/%$&§=()[].?\"#,;!~<>|°^{}";
  260. %name = stripChars( %name, %invalidCharacters );
  261. if( %name $= "" )
  262. %name = "Unnamed";
  263. return %name;
  264. }
  265. //--------------------------------------------------------------------------
  266. // Finds location of %word in %text, starting at %start. Works just like strPos
  267. //--------------------------------------------------------------------------
  268. function wordPos(%text, %word, %start)
  269. {
  270. if (%start $= "") %start = 0;
  271. if (strpos(%text, %word, 0) == -1) return -1;
  272. %count = getWordCount(%text);
  273. if (%start >= %count) return -1;
  274. for (%i = %start; %i < %count; %i++)
  275. {
  276. if (getWord( %text, %i) $= %word) return %i;
  277. }
  278. return -1;
  279. }
  280. //--------------------------------------------------------------------------
  281. // Finds location of %field in %text, starting at %start. Works just like strPos
  282. //--------------------------------------------------------------------------
  283. function fieldPos(%text, %field, %start)
  284. {
  285. if (%start $= "") %start = 0;
  286. if (strpos(%text, %field, 0) == -1) return -1;
  287. %count = getFieldCount(%text);
  288. if (%start >= %count) return -1;
  289. for (%i = %start; %i < %count; %i++)
  290. {
  291. if (getField( %text, %i) $= %field) return %i;
  292. }
  293. return -1;
  294. }
  295. //--------------------------------------------------------------------------
  296. // returns the text in a file with "\n" at the end of each line
  297. //--------------------------------------------------------------------------
  298. function loadFileText( %file)
  299. {
  300. %fo = new FileObject();
  301. %fo.openForRead(%file);
  302. %text = "";
  303. while(!%fo.isEOF())
  304. {
  305. %text = %text @ %fo.readLine();
  306. if (!%fo.isEOF()) %text = %text @ "\n";
  307. }
  308. %fo.delete();
  309. return %text;
  310. }
  311. function setValueSafe(%dest, %val)
  312. {
  313. %cmd = %dest.command;
  314. %alt = %dest.altCommand;
  315. %dest.command = "";
  316. %dest.altCommand = "";
  317. %dest.setValue(%val);
  318. %dest.command = %cmd;
  319. %dest.altCommand = %alt;
  320. }
  321. function shareValueSafe(%source, %dest)
  322. {
  323. setValueSafe(%dest, %source.getValue());
  324. }
  325. function shareValueSafeDelay(%source, %dest, %delayMs)
  326. {
  327. schedule(%delayMs, 0, shareValueSafe, %source, %dest);
  328. }
  329. //------------------------------------------------------------------------------
  330. // An Aggregate Control is a plain GuiControl that contains other controls,
  331. // which all share a single job or represent a single value.
  332. //------------------------------------------------------------------------------
  333. // AggregateControl.setValue( ) propagates the value to any control that has an
  334. // internal name.
  335. function AggregateControl::setValue(%this, %val, %child)
  336. {
  337. for(%i = 0; %i < %this.getCount(); %i++)
  338. {
  339. %obj = %this.getObject(%i);
  340. if( %obj == %child )
  341. continue;
  342. if(%obj.internalName !$= "")
  343. setValueSafe(%obj, %val);
  344. }
  345. }
  346. // AggregateControl.getValue() uses the value of the first control that has an
  347. // internal name, if it has not cached a value via .setValue
  348. function AggregateControl::getValue(%this)
  349. {
  350. for(%i = 0; %i < %this.getCount(); %i++)
  351. {
  352. %obj = %this.getObject(%i);
  353. if(%obj.internalName !$= "")
  354. {
  355. //error("obj = " @ %obj.getId() @ ", " @ %obj.getName() @ ", " @ %obj.internalName );
  356. //error(" value = " @ %obj.getValue());
  357. return %obj.getValue();
  358. }
  359. }
  360. }
  361. // AggregateControl.updateFromChild( ) is called by child controls to propagate
  362. // a new value, and to trigger the onAction() callback.
  363. function AggregateControl::updateFromChild(%this, %child)
  364. {
  365. %val = %child.getValue();
  366. if(%val == mCeil(%val)){
  367. %val = mCeil(%val);
  368. }else{
  369. if ( %val <= -100){
  370. %val = mCeil(%val);
  371. }else if ( %val <= -10){
  372. %val = mFloatLength(%val, 1);
  373. }else if ( %val < 0){
  374. %val = mFloatLength(%val, 2);
  375. }else if ( %val >= 1000){
  376. %val = mCeil(%val);
  377. }else if ( %val >= 100){
  378. %val = mFloatLength(%val, 1);
  379. }else if ( %val >= 10){
  380. %val = mFloatLength(%val, 2);
  381. }else if ( %val > 0){
  382. %val = mFloatLength(%val, 3);
  383. }
  384. }
  385. %this.setValue(%val, %child);
  386. %this.onAction();
  387. }
  388. // default onAction stub, here only to prevent console spam warnings.
  389. function AggregateControl::onAction(%this)
  390. {
  391. }
  392. // call a method on all children that have an internalName and that implement the method.
  393. function AggregateControl::callMethod(%this, %method, %args)
  394. {
  395. for(%i = 0; %i < %this.getCount(); %i++)
  396. {
  397. %obj = %this.getObject(%i);
  398. if(%obj.internalName !$= "" && %obj.isMethod(%method))
  399. eval(%obj @ "." @ %method @ "( " @ %args @ " );");
  400. }
  401. }
  402. //------------------------------------------------------------------------------
  403. // Altered Version of TGB's QuickEditDropDownTextEditCtrl
  404. //------------------------------------------------------------------------------
  405. function QuickEditDropDownTextEditCtrl::onRenameItem( %this )
  406. {
  407. }
  408. function QuickEditDropDownTextEditCtrl::updateFromChild( %this, %ctrl )
  409. {
  410. if( %ctrl.internalName $= "PopUpMenu" )
  411. {
  412. %this->TextEdit.setText( %ctrl.getText() );
  413. }
  414. else if ( %ctrl.internalName $= "TextEdit" )
  415. {
  416. %popup = %this->PopupMenu;
  417. %popup.changeTextById( %popup.getSelected(), %ctrl.getText() );
  418. %this.onRenameItem();
  419. }
  420. }
  421. // Writes out all script functions to a file.
  422. function writeOutFunctions()
  423. {
  424. new ConsoleLogger(logger, "scriptFunctions.txt", false);
  425. dumpConsoleFunctions();
  426. logger.delete();
  427. }
  428. // Writes out all script classes to a file.
  429. function writeOutClasses()
  430. {
  431. new ConsoleLogger(logger, "scriptClasses.txt", false);
  432. dumpConsoleClasses();
  433. logger.delete();
  434. }
  435. //
  436. function compileFiles(%pattern)
  437. {
  438. %path = filePath(%pattern);
  439. %saveDSO = $Scripts::OverrideDSOPath;
  440. %saveIgnore = $Scripts::ignoreDSOs;
  441. $Scripts::OverrideDSOPath = %path;
  442. $Scripts::ignoreDSOs = false;
  443. %mainCsFile = makeFullPath("main.cs");
  444. for (%file = findFirstFileMultiExpr(%pattern); %file !$= ""; %file = findNextFileMultiExpr(%pattern))
  445. {
  446. // we don't want to try and compile the primary main.cs
  447. if(%mainCsFile !$= %file)
  448. compile(%file, true);
  449. }
  450. $Scripts::OverrideDSOPath = %saveDSO;
  451. $Scripts::ignoreDSOs = %saveIgnore;
  452. }
  453. function displayHelp()
  454. {
  455. // Notes on logmode: console logging is written to console.log.
  456. // -log 0 disables console logging.
  457. // -log 1 appends to existing logfile; it also closes the file
  458. // (flushing the write buffer) after every write.
  459. // -log 2 overwrites any existing logfile; it also only closes
  460. // the logfile when the application shuts down. (default)
  461. error(
  462. "Torque Demo command line options:\n"@
  463. " -log <logmode> Logging behavior; see main.cs comments for details\n"@
  464. " -game <game_name> Reset list of mods to only contain <game_name>\n"@
  465. " <game_name> Works like the -game argument\n"@
  466. " -dir <dir_name> Add <dir_name> to list of directories\n"@
  467. " -console Open a separate console\n"@
  468. " -jSave <file_name> Record a journal\n"@
  469. " -jPlay <file_name> Play back a journal\n"@
  470. " -help Display this help message\n"
  471. );
  472. }
  473. // Execute startup scripts for each mod, starting at base and working up
  474. function loadDir(%dir)
  475. {
  476. pushback($userDirs, %dir, ";");
  477. if (isScriptFile(%dir @ "/main.cs"))
  478. exec(%dir @ "/main.cs");
  479. }
  480. function loadDirs(%dirPath)
  481. {
  482. %dirPath = nextToken(%dirPath, token, ";");
  483. if (%dirPath !$= "")
  484. loadDirs(%dirPath);
  485. if(exec(%token @ "/main.cs") != true)
  486. {
  487. error("Error: Unable to find specified directory: " @ %token );
  488. $dirCount--;
  489. }
  490. }
  491. //------------------------------------------------------------------------------
  492. // Utility remap functions:
  493. //------------------------------------------------------------------------------
  494. function ActionMap::copyBind( %this, %otherMap, %command )
  495. {
  496. if ( !isObject( %otherMap ) )
  497. {
  498. error( "ActionMap::copyBind - \"" @ %otherMap @ "\" is not an object!" );
  499. return;
  500. }
  501. %bind = %otherMap.getBinding( %command );
  502. if ( %bind !$= "" )
  503. {
  504. %device = getField( %bind, 0 );
  505. %action = getField( %bind, 1 );
  506. %flags = %otherMap.isInverted( %device, %action ) ? "SDI" : "SD";
  507. %deadZone = %otherMap.getDeadZone( %device, %action );
  508. %scale = %otherMap.getScale( %device, %action );
  509. %this.bind( %device, %action, %flags, %deadZone, %scale, %command );
  510. }
  511. }
  512. //------------------------------------------------------------------------------
  513. function ActionMap::blockBind( %this, %otherMap, %command )
  514. {
  515. if ( !isObject( %otherMap ) )
  516. {
  517. error( "ActionMap::blockBind - \"" @ %otherMap @ "\" is not an object!" );
  518. return;
  519. }
  520. %bind = %otherMap.getBinding( %command );
  521. if ( %bind !$= "" )
  522. %this.bind( getField( %bind, 0 ), getField( %bind, 1 ), "" );
  523. }
  524. //Dev helpers
  525. /// Shortcut for typing dbgSetParameters with the default values torsion uses.
  526. function dbgTorsion()
  527. {
  528. dbgSetParameters( 6060, "password", false );
  529. }
  530. /// Reset the input state to a default of all-keys-up.
  531. /// A helpful remedy for when Torque misses a button up event do to your breakpoints
  532. /// and can't stop shooting / jumping / strafing.
  533. function mvReset()
  534. {
  535. for ( %i = 0; %i < 6; %i++ )
  536. setVariable( "mvTriggerCount" @ %i, 0 );
  537. $mvUpAction = 0;
  538. $mvDownAction = 0;
  539. $mvLeftAction = 0;
  540. $mvRightAction = 0;
  541. // There are others.
  542. }
  543. //Persistance Manager tests
  544. new PersistenceManager(TestPManager);
  545. function runPManTest(%test)
  546. {
  547. if (!isObject(TestPManager))
  548. return;
  549. if (%test $= "")
  550. %test = 100;
  551. switch(%test)
  552. {
  553. case 0:
  554. TestPManager.testFieldUpdates();
  555. case 1:
  556. TestPManager.testObjectRename();
  557. case 2:
  558. TestPManager.testNewObject();
  559. case 3:
  560. TestPManager.testNewGroup();
  561. case 4:
  562. TestPManager.testMoveObject();
  563. case 5:
  564. TestPManager.testObjectRemove();
  565. case 100:
  566. TestPManager.testFieldUpdates();
  567. TestPManager.testObjectRename();
  568. TestPManager.testNewObject();
  569. TestPManager.testNewGroup();
  570. TestPManager.testMoveObject();
  571. TestPManager.testObjectRemove();
  572. }
  573. }
  574. function TestPManager::testFieldUpdates(%doNotSave)
  575. {
  576. // Set some objects as dirty
  577. TestPManager.setDirty(AudioGui);
  578. TestPManager.setDirty(AudioSim);
  579. TestPManager.setDirty(AudioMessage);
  580. // Alter some of the existing fields
  581. AudioEffect.isLooping = true;
  582. AudioMessage.isLooping = true;
  583. AudioEffect.is3D = true;
  584. // Test removing a field
  585. TestPManager.removeField(AudioGui, "isLooping");
  586. // Alter some of the persistent fields
  587. AudioGui.referenceDistance = 0.8;
  588. AudioMessage.referenceDistance = 0.8;
  589. // Add some new dynamic fields
  590. AudioGui.foo = "bar";
  591. AudioEffect.foo = "bar";
  592. // Remove an object from the dirty list
  593. // It shouldn't get updated in the file
  594. TestPManager.removeDirty(AudioEffect);
  595. // Dirty an object in another file as well
  596. TestPManager.setDirty(WarningMaterial);
  597. // Update a field that doesn't exist
  598. WarningMaterial.glow[0] = true;
  599. // Drity another object to test for crashes
  600. // when a dirty object is deleted
  601. TestPManager.setDirty(SFXPausedSet);
  602. // Delete the object
  603. SFXPausedSet.delete();
  604. // Unless %doNotSave is set (by a batch/combo test)
  605. // then go ahead and save now
  606. if (!%doNotSave)
  607. TestPManager.saveDirty();
  608. }
  609. function TestPManager::testObjectRename(%doNotSave)
  610. {
  611. // Flag an object as dirty
  612. if (isObject(AudioGui))
  613. TestPManager.setDirty(AudioGui);
  614. else if (isObject(AudioGuiFoo))
  615. TestPManager.setDirty(AudioGuiFoo);
  616. // Rename it
  617. if (isObject(AudioGui))
  618. AudioGui.setName(AudioGuiFoo);
  619. else if (isObject(AudioGuiFoo))
  620. AudioGuiFoo.setName(AudioGui);
  621. // Unless %doNotSave is set (by a batch/combo test)
  622. // then go ahead and save now
  623. if (!%doNotSave)
  624. TestPManager.saveDirty();
  625. }
  626. function TestPManager::testNewObject(%doNotSave)
  627. {
  628. // Test adding a new named object
  629. new SFXDescription(AudioNew)
  630. {
  631. volume = 0.5;
  632. isLooping = true;
  633. channel = $GuiAudioType;
  634. foo = 2;
  635. };
  636. // Flag it as dirty
  637. TestPManager.setDirty(AudioNew, "core/scripts/client/audio.cs");
  638. // Test adding a new unnamed object
  639. %obj = new SFXDescription()
  640. {
  641. volume = 0.75;
  642. isLooping = true;
  643. bar = 3;
  644. };
  645. // Flag it as dirty
  646. TestPManager.setDirty(%obj, "core/scripts/client/audio.cs");
  647. // Test adding an "empty" object
  648. new SFXDescription(AudioEmpty);
  649. TestPManager.setDirty(AudioEmpty, "core/scripts/client/audio.cs");
  650. // Unless %doNotSave is set (by a batch/combo test)
  651. // then go ahead and save now
  652. if (!%doNotSave)
  653. TestPManager.saveDirty();
  654. }
  655. function TestPManager::testNewGroup(%doNotSave)
  656. {
  657. // Test adding a new named SimGroup
  658. new SimGroup(TestGroup)
  659. {
  660. foo = "bar";
  661. new SFXDescription(TestObject)
  662. {
  663. volume = 0.5;
  664. isLooping = true;
  665. channel = $GuiAudioType;
  666. foo = 1;
  667. };
  668. new SimGroup(SubGroup)
  669. {
  670. foo = 2;
  671. new SFXDescription(SubObject)
  672. {
  673. volume = 0.5;
  674. isLooping = true;
  675. channel = $GuiAudioType;
  676. foo = 3;
  677. };
  678. };
  679. };
  680. // Flag this as dirty
  681. TestPManager.setDirty(TestGroup, "core/scripts/client/audio.cs");
  682. // Test adding a new unnamed SimGroup
  683. %group = new SimGroup()
  684. {
  685. foo = "bar";
  686. new SFXDescription()
  687. {
  688. volume = 0.75;
  689. channel = $GuiAudioType;
  690. foo = 4;
  691. };
  692. new SimGroup()
  693. {
  694. foo = 5;
  695. new SFXDescription()
  696. {
  697. volume = 0.75;
  698. isLooping = true;
  699. channel = $GuiAudioType;
  700. foo = 6;
  701. };
  702. };
  703. };
  704. // Flag this as dirty
  705. TestPManager.setDirty(%group, "core/scripts/client/audio.cs");
  706. // Test adding a new unnamed SimSet
  707. %set = new SimSet()
  708. {
  709. foo = "bar";
  710. new SFXDescription()
  711. {
  712. volume = 0.75;
  713. channel = $GuiAudioType;
  714. foo = 7;
  715. };
  716. new SimGroup()
  717. {
  718. foo = 8;
  719. new SFXDescription()
  720. {
  721. volume = 0.75;
  722. isLooping = true;
  723. channel = $GuiAudioType;
  724. foo = 9;
  725. };
  726. };
  727. };
  728. // Flag this as dirty
  729. TestPManager.setDirty(%set, "core/scripts/client/audio.cs");
  730. // Unless %doNotSave is set (by a batch/combo test)
  731. // then go ahead and save now
  732. if (!%doNotSave)
  733. TestPManager.saveDirty();
  734. }
  735. function TestPManager::testMoveObject(%doNotSave)
  736. {
  737. // First add a couple of groups to the file
  738. new SimGroup(MoveGroup1)
  739. {
  740. foo = "bar";
  741. new SFXDescription(MoveObject1)
  742. {
  743. volume = 0.5;
  744. isLooping = true;
  745. channel = $GuiAudioType;
  746. foo = 1;
  747. };
  748. new SimSet(SubGroup1)
  749. {
  750. new SFXDescription(SubObject1)
  751. {
  752. volume = 0.75;
  753. isLooping = true;
  754. channel = $GuiAudioType;
  755. foo = 2;
  756. };
  757. };
  758. };
  759. // Flag this as dirty
  760. TestPManager.setDirty(MoveGroup1, "core/scripts/client/audio.cs");
  761. new SimGroup(MoveGroup2)
  762. {
  763. foo = "bar";
  764. new SFXDescription(MoveObject2)
  765. {
  766. volume = 0.5;
  767. isLooping = true;
  768. channel = $GuiAudioType;
  769. foo = 3;
  770. };
  771. };
  772. // Flag this as dirty
  773. TestPManager.setDirty(MoveGroup2, "core/scripts/client/audio.cs");
  774. // Unless %doNotSave is set (by a batch/combo test)
  775. // then go ahead and save now
  776. if (!%doNotSave)
  777. TestPManager.saveDirty();
  778. // Set them as dirty again
  779. TestPManager.setDirty(MoveGroup1);
  780. TestPManager.setDirty(MoveGroup2);
  781. // Give the subobject an new value
  782. MoveObject1.foo = 4;
  783. // Move it into the other group
  784. MoveGroup1.add(MoveObject2);
  785. // Switch the other subobject
  786. MoveGroup2.add(MoveObject1);
  787. // Also add a new unnamed object to one of the groups
  788. %obj = new SFXDescription()
  789. {
  790. volume = 0.75;
  791. isLooping = true;
  792. bar = 5;
  793. };
  794. MoveGroup1.add(%obj);
  795. // Unless %doNotSave is set (by a batch/combo test)
  796. // then go ahead and save now
  797. if (!%doNotSave)
  798. TestPManager.saveDirty();
  799. }
  800. function TestPManager::testObjectRemove(%doNotSave)
  801. {
  802. TestPManager.removeObjectFromFile(AudioSim);
  803. }
  804. //Game Object management
  805. function findGameObject(%name)
  806. {
  807. //find all GameObjectAssets
  808. %assetQuery = new AssetQuery();
  809. if(!AssetDatabase.findAssetType(%assetQuery, "GameObjectAsset"))
  810. return 0; //if we didn't find ANY, just exit
  811. %count = %assetQuery.getCount();
  812. for(%i=0; %i < %count; %i++)
  813. {
  814. %assetId = %assetQuery.getAsset(%i);
  815. %assetName = AssetDatabase.getAssetName(%assetId);
  816. if(%assetName $= %name)
  817. {
  818. %gameObjectAsset = AssetDatabase.acquireAsset(%assetId);
  819. %assetQuery.delete();
  820. return %gameObjectAsset;
  821. }
  822. }
  823. %assetQuery.delete();
  824. return 0;
  825. }
  826. function spawnGameObject(%name, %addToMissionGroup)
  827. {
  828. if(%addToMissionGroup $= "")
  829. %addToMissionGroup = true;
  830. //First, check if this already exists in our GameObjectPool
  831. if(isObject(GameObjectPool))
  832. {
  833. %goCount = GameObjectPool.countKey(%name);
  834. //if we have some already in the pool, pull it out and use that
  835. if(%goCount != 0)
  836. {
  837. %goIdx = GameObjectPool.getIndexFromKey(%name);
  838. %go = GameObjectPool.getValue(%goIdx);
  839. %go.setHidden(false);
  840. %go.setScopeAlways();
  841. if(%addToMissionGroup == true) //save instance when saving level
  842. MissionGroup.add(%go);
  843. else // clear instance on level exit
  844. MissionCleanup.add(%go);
  845. //remove from the object pool's list
  846. GameObjectPool.erase(%goIdx);
  847. return %go;
  848. }
  849. }
  850. //We have no existing pool, or no existing game objects of this type, so spawn a new one
  851. %gameObjectAsset = findGameObject(%name);
  852. if(isObject(%gameObjectAsset))
  853. {
  854. %newSGOObject = TamlRead(%gameObjectAsset.TAMLFilePath);
  855. if(%addToMissionGroup == true) //save instance when saving level
  856. MissionGroup.add(%newSGOObject);
  857. else // clear instance on level exit
  858. MissionCleanup.add(%newSGOObject);
  859. return %newSGOObject;
  860. }
  861. return 0;
  862. }
  863. function saveGameObject(%name, %tamlPath, %scriptPath)
  864. {
  865. %gameObjectAsset = findGameObject(%name);
  866. //find if it already exists. If it does, we'll update it, if it does not, we'll make a new asset
  867. if(isObject(%gameObjectAsset))
  868. {
  869. %assetID = %gameObjectAsset.getAssetId();
  870. %gameObjectAsset.TAMLFilePath = %tamlPath;
  871. %gameObjectAsset.scriptFilePath = %scriptPath;
  872. TAMLWrite(%gameObjectAsset, AssetDatabase.getAssetFilePath(%assetID));
  873. AssetDatabase.refreshAsset(%assetID);
  874. }
  875. else
  876. {
  877. //Doesn't exist, so make a new one
  878. %gameObjectAsset = new GameObjectAsset()
  879. {
  880. assetName = %name @ "Asset";
  881. gameObjectName = %name;
  882. TAMLFilePath = %tamlPath;
  883. scriptFilePath = %scriptPath;
  884. };
  885. //Save it alongside the taml file
  886. %path = filePath(%tamlPath);
  887. TAMLWrite(%gameObjectAsset, %path @ "/" @ %name @ ".asset.taml");
  888. AssetDatabase.refreshAllAssets(true);
  889. }
  890. }
  891. //Allocates a number of a game object into a pool to be pulled from as needed
  892. function allocateGameObjects(%name, %amount)
  893. {
  894. //First, we need to make sure our pool exists
  895. if(!isObject(GameObjectPool))
  896. {
  897. new ArrayObject(GameObjectPool);
  898. }
  899. //Next, we loop and generate our game objects, and add them to the pool
  900. for(%i=0; %i < %amount; %i++)
  901. {
  902. %go = spawnGameObject(%name, false);
  903. //When our object is in the pool, it's not "real", so we need to make sure
  904. //that we don't ghost it to clients untill we actually spawn it.
  905. %go.clearScopeAlways();
  906. //We also hide it, so that we don't 'exist' in the scene until we spawn
  907. %go.hidden = true;
  908. //Lastly, add us to the pool, with the key being our game object type
  909. GameObjectPool.add(%name, %go);
  910. }
  911. }
  912. function Entity::delete(%this)
  913. {
  914. //we want to intercept the delete call, and add it to our GameObjectPool
  915. //if it's a game object
  916. if(%this.gameObjectAsset !$= "")
  917. {
  918. %this.setHidden(true);
  919. %this.clearScopeAlways();
  920. if(!isObject(GameObjectPool))
  921. {
  922. new ArrayObject(GameObjectPool);
  923. }
  924. GameObjectPool.add(%this.gameObjectAsset, %this);
  925. %missionSet = %this.getGroup();
  926. %missionSet.remove(%this);
  927. }
  928. else
  929. {
  930. %this.superClass.delete();
  931. }
  932. }
  933. function clearGameObjectPool()
  934. {
  935. if(isObject(GameObjectPool))
  936. {
  937. %count = GameObjectPool.count();
  938. for(%i=0; %i < %count; %i++)
  939. {
  940. %go = GameObjectPool.getValue(%i);
  941. %go.superClass.delete();
  942. }
  943. GameObjectPool.empty();
  944. }
  945. }
  946. //
  947. function switchCamera(%client, %newCamEntity)
  948. {
  949. if(!isObject(%client) || !isObject(%newCamEntity))
  950. return error("SwitchCamera: No client or target camera!");
  951. %cam = %newCamEntity.getComponent(CameraComponent);
  952. if(!isObject(%cam))
  953. return error("SwitchCamera: Target camera doesn't have a camera behavior!");
  954. //TODO: Cleanup clientOwner for previous camera!
  955. if(%cam.clientOwner == 0 || %cam.clientOwner $= "")
  956. %cam.clientOwner = 0;
  957. %cam.scopeToClient(%client);
  958. %cam.setDirty();
  959. %client.setCameraObject(%newCamEntity);
  960. %client.setControlCameraFov(%cam.FOV);
  961. %client.camera = %newCamEntity;
  962. }