simObject.cc 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582
  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 "sim/simObject.h"
  23. #include "sim/simObjectTimerEvent.h"
  24. #include "console/consoleInternal.h"
  25. #include "console/codeBlock.h"
  26. #include "console/consoleInternal.h"
  27. #include "memory/frameAllocator.h"
  28. #include "io/fileStream.h"
  29. #include "io/fileObject.h"
  30. #include "console/ConsoleTypeValidators.h"
  31. #include "simObject_ScriptBinding.h"
  32. #include <algorithm>
  33. //-----------------------------------------------------------------------------
  34. IMPLEMENT_CONOBJECT(SimObject);
  35. namespace Sim
  36. {
  37. extern U32 gNextObjectId;
  38. extern SimIdDictionary *gIdDictionary;
  39. extern SimManagerNameDictionary *gNameDictionary;
  40. extern void cancelPendingEvents(SimObject *obj);
  41. }
  42. //-----------------------------------------------------------------------------
  43. bool SimObject::disableNameChanging = false;
  44. //-----------------------------------------------------------------------------
  45. SimObject::SimObject()
  46. {
  47. mFlags.set( ModStaticFields | ModDynamicFields );
  48. objectName = NULL;
  49. objectNameEditor = NULL;
  50. mInternalName = NULL;
  51. nextNameObject = (SimObject*)-1;
  52. nextManagerNameObject = (SimObject*)-1;
  53. nextIdObject = NULL;
  54. mId = 0;
  55. mIdString = StringTable->EmptyString;
  56. mGroup = 0;
  57. mNameSpace = NULL;
  58. mNotifyList = NULL;
  59. mTypeMask = 0;
  60. mScriptCallbackGuard = 0;
  61. mFieldDictionary = NULL;
  62. mCanSaveFieldDictionary = true;
  63. mClassName = NULL;
  64. mSuperClassName = NULL;
  65. mProgenitorFile = CodeBlock::getCurrentCodeBlockFullPath();
  66. mPeriodicTimerID = 0;
  67. bIsEventRaised = false;
  68. }
  69. //---------------------------------------------------------------------------
  70. bool SimObject::isMethod( const char* methodName )
  71. {
  72. if( !methodName || !methodName[0] )
  73. return false;
  74. StringTableEntry stname = StringTable->insert( methodName );
  75. if( getNamespace() )
  76. return ( getNamespace()->lookup( stname ) != NULL );
  77. return false;
  78. }
  79. //---------------------------------------------------------------------------
  80. bool SimObject::registerObject()
  81. {
  82. AssertFatal( !mFlags.test( Added ), "reigsterObject - Object already registered!");
  83. mFlags.clear(Deleted | Removed);
  84. if( mId == 0 )
  85. {
  86. mId = Sim::gNextObjectId++;
  87. char idBuffer[64];
  88. dSprintf(idBuffer, sizeof(idBuffer), "%d", mId);
  89. mIdString = StringTable->insert( idBuffer );
  90. }
  91. AssertFatal(Sim::gIdDictionary && Sim::gNameDictionary,
  92. "SimObject::registerObject - tried to register an object before Sim::init()!");
  93. Sim::gIdDictionary->insert(this);
  94. Sim::gNameDictionary->insert(this);
  95. // Notify object
  96. bool ret = onAdd();
  97. if(!ret)
  98. unregisterObject();
  99. AssertFatal(!ret || isProperlyAdded(), "Object did not call SimObject::onAdd()");
  100. if ( isMethod( "onAdd" ) )
  101. Con::executef( this, 1, "onAdd" );
  102. return ret;
  103. }
  104. //---------------------------------------------------------------------------
  105. void SimObject::unregisterObject()
  106. {
  107. // Sanity!
  108. AssertISV( getScriptCallbackGuard() == 0, "SimObject::unregisterObject: Object is being unregistered whilst performing a script callback!" );
  109. if ( isMethod( "onRemove" ) )
  110. Con::executef( this, 1, "onRemove" );
  111. mFlags.set(Removed);
  112. // Notify object first
  113. onRemove();
  114. // Clear out any pending notifications before
  115. // we call our own, just in case they delete
  116. // something that we have referenced.
  117. clearAllNotifications();
  118. // Notify all objects that are waiting for delete
  119. // messages
  120. if (getGroup())
  121. getGroup()->removeObject(this);
  122. processDeleteNotifies();
  123. // Do removals from the Sim.
  124. Sim::gNameDictionary->remove(this);
  125. Sim::gIdDictionary->remove(this);
  126. Sim::cancelPendingEvents(this);
  127. }
  128. //---------------------------------------------------------------------------
  129. void SimObject::deleteObject()
  130. {
  131. // Sanity!
  132. AssertISV( getScriptCallbackGuard() == 0, "SimObject::deleteObject: Object is being deleted whilst performing a script callback!" );
  133. AssertFatal(mFlags.test(Added),
  134. "SimObject::deleteObject: Object not registered.");
  135. AssertFatal(!isDeleted(),"SimManager::deleteObject: "
  136. "Object has already been deleted");
  137. AssertFatal(!isRemoved(),"SimManager::deleteObject: "
  138. "Object in the process of being removed");
  139. mFlags.set(Deleted);
  140. unregisterObject();
  141. delete this;
  142. }
  143. //---------------------------------------------------------------------------
  144. void SimObject::setId(SimObjectId newId)
  145. {
  146. if(!mFlags.test(Added))
  147. {
  148. mId = newId;
  149. }
  150. else
  151. {
  152. // get this object out of the id dictionary if it's in it
  153. Sim::gIdDictionary->remove(this);
  154. // Free current Id.
  155. // Assign new one.
  156. mId = newId ? newId : Sim::gNextObjectId++;
  157. Sim::gIdDictionary->insert(this);
  158. }
  159. char idBuffer[64];
  160. dSprintf(idBuffer, sizeof(idBuffer), "%d", mId);
  161. mIdString = StringTable->insert( idBuffer );
  162. }
  163. void SimObject::assignName(const char *name)
  164. {
  165. if( dStricmp( getClassName(), name ) == 0 )
  166. Con::errorf( "SimObject::assignName - Assigning name '%s' to instance of object with type '%s'."
  167. " This can cause namespace linking issues.", getClassName(), name );
  168. StringTableEntry newName = NULL;
  169. if (name[0])
  170. newName = StringTable->insert(name);
  171. if (gEvalState.editorModeOn)
  172. {
  173. objectNameEditor = newName;
  174. return;
  175. }
  176. // Is this name already registered?
  177. if ( Sim::gNameDictionary->find(name) != NULL )
  178. {
  179. // Yes, so error,
  180. Con::errorf( "SimObject::assignName() - Attempted to set object to name '%s' but it is already assigned to another object.", name );
  181. return;
  182. }
  183. if (mGroup)
  184. mGroup->nameDictionary.remove(this);
  185. if (isProperlyAdded())
  186. {
  187. // Unlink the old namespaces.
  188. unlinkNamespaces();
  189. Sim::gNameDictionary->remove(this);
  190. }
  191. objectName = newName;
  192. if (mGroup)
  193. mGroup->nameDictionary.insert(this);
  194. if (isProperlyAdded())
  195. {
  196. // Link the new namespaces.
  197. linkNamespaces();
  198. Sim::gNameDictionary->insert(this);
  199. }
  200. }
  201. //---------------------------------------------------------------------------
  202. bool SimObject::registerObject(U32 id)
  203. {
  204. setId(id);
  205. return registerObject();
  206. }
  207. bool SimObject::registerObject(const char *name)
  208. {
  209. assignName(name);
  210. return registerObject();
  211. }
  212. bool SimObject::registerObject(const char *name, U32 id)
  213. {
  214. setId(id);
  215. assignName(name);
  216. return registerObject();
  217. }
  218. void SimObject::assignDynamicFieldsFrom(SimObject* parent)
  219. {
  220. if(parent->mFieldDictionary)
  221. {
  222. if( mFieldDictionary == NULL )
  223. mFieldDictionary = new SimFieldDictionary;
  224. mFieldDictionary->assignFrom(parent->mFieldDictionary);
  225. }
  226. }
  227. void SimObject::assignFieldsFrom(SimObject *parent)
  228. {
  229. // only allow field assigns from objects of the same class:
  230. if(getClassRep() == parent->getClassRep())
  231. {
  232. const AbstractClassRep::FieldList &list = getFieldList();
  233. // copy out all the fields:
  234. for(U32 i = 0; i < (U32)list.size(); i++)
  235. {
  236. const AbstractClassRep::Field* f = &list[i];
  237. S32 lastField = f->elementCount - 1;
  238. for(S32 j = 0; j <= lastField; j++)
  239. {
  240. const char* fieldVal = (*f->getDataFn)( this, Con::getData(f->type, (void *) (((const char *)parent) + f->offset), j, f->table, f->flag));
  241. //if(fieldVal)
  242. // Con::setData(f->type, (void *) (((const char *)this) + f->offset), j, 1, &fieldVal, f->table);
  243. if(fieldVal)
  244. {
  245. // code copied from SimObject::setDataField().
  246. // TODO: paxorr: abstract this into a better setData / getData that considers prot fields.
  247. FrameTemp<char> buffer(2048);
  248. FrameTemp<char> bufferSecure(2048); // This buffer is used to make a copy of the data
  249. ConsoleBaseType *cbt = ConsoleBaseType::getType( f->type );
  250. const char* szBuffer = cbt->prepData( fieldVal, buffer, 2048 );
  251. dMemset( bufferSecure, 0, 2048 );
  252. dMemcpy( bufferSecure, szBuffer, dStrlen( szBuffer ) );
  253. if((*f->setDataFn)( this, bufferSecure ) )
  254. Con::setData(f->type, (void *) (((const char *)this) + f->offset), j, 1, &fieldVal, f->table);
  255. }
  256. }
  257. }
  258. }
  259. assignDynamicFieldsFrom(parent);
  260. }
  261. bool SimObject::writeField(StringTableEntry fieldname, const char* value)
  262. {
  263. // Don't write empty fields.
  264. if (!value || !*value)
  265. return false;
  266. // Don't write ParentGroup
  267. if( fieldname == StringTable->insert("parentGroup") )
  268. return false;
  269. return true;
  270. }
  271. void SimObject::writeFields(Stream &stream, U32 tabStop)
  272. {
  273. const AbstractClassRep::FieldList &list = getFieldList();
  274. for(U32 i = 0; i < (U32)list.size(); i++)
  275. {
  276. const AbstractClassRep::Field* f = &list[i];
  277. if( f->type == AbstractClassRep::DepricatedFieldType ||
  278. f->type == AbstractClassRep::StartGroupFieldType ||
  279. f->type == AbstractClassRep::EndGroupFieldType) continue;
  280. // Fetch fieldname.
  281. StringTableEntry fieldName = StringTable->insert( f->pFieldname );
  282. // Fetch element count.
  283. const S32 elementCount = f->elementCount;
  284. // Skip if the field should not be written.
  285. // For now, we only deal with non-array fields.
  286. if ( elementCount == 1 &&
  287. f->writeDataFn != NULL &&
  288. f->writeDataFn( this, fieldName ) == false )
  289. continue;
  290. for(U32 j = 0; S32(j) < elementCount; j++)
  291. {
  292. char array[8];
  293. dSprintf( array, 8, "%d", j );
  294. const char *val = getDataField(fieldName, array );
  295. // Make a copy for the field check.
  296. if (!val)
  297. continue;
  298. U32 nBufferSize = dStrlen( val ) + 1;
  299. FrameTemp<char> valCopy( nBufferSize );
  300. dStrcpy( (char *)valCopy, val );
  301. if (!writeField(fieldName, valCopy))
  302. continue;
  303. val = valCopy;
  304. U32 expandedBufferSize = ( nBufferSize * 2 ) + 32;
  305. FrameTemp<char> expandedBuffer( expandedBufferSize );
  306. if(f->elementCount == 1)
  307. dSprintf(expandedBuffer, expandedBufferSize, "%s = \"", f->pFieldname);
  308. else
  309. dSprintf(expandedBuffer, expandedBufferSize, "%s[%d] = \"", f->pFieldname, j);
  310. // detect and collapse relative path information
  311. char fnBuf[1024];
  312. if (f->type == TypeFilename)
  313. {
  314. Con::collapsePath(fnBuf, 1024, val);
  315. val = fnBuf;
  316. }
  317. expandEscape((char*)expandedBuffer + dStrlen(expandedBuffer), val);
  318. dStrcat(expandedBuffer, "\";\r\n");
  319. stream.writeTabs(tabStop);
  320. stream.write(dStrlen(expandedBuffer),expandedBuffer);
  321. }
  322. }
  323. if(mFieldDictionary && mCanSaveFieldDictionary)
  324. mFieldDictionary->writeFields(this, stream, tabStop);
  325. }
  326. void SimObject::write(Stream &stream, U32 tabStop, U32 flags)
  327. {
  328. // Only output selected objects if they want that.
  329. if((flags & SelectedOnly) && !isSelected())
  330. return;
  331. stream.writeTabs(tabStop);
  332. char buffer[1024];
  333. dSprintf(buffer, sizeof(buffer), "new %s(%s) {\r\n", getClassName(), getName() ? getName() : "");
  334. stream.write(dStrlen(buffer), buffer);
  335. writeFields(stream, tabStop + 1);
  336. stream.writeTabs(tabStop);
  337. stream.write(4, "};\r\n");
  338. }
  339. bool SimObject::save(const char* pcFileName, bool bOnlySelected)
  340. {
  341. static const char *beginMessage = "//--- OBJECT WRITE BEGIN ---";
  342. static const char *endMessage = "//--- OBJECT WRITE END ---";
  343. FileStream stream;
  344. FileObject f;
  345. f.readMemory(pcFileName);
  346. // check for flags <selected, ...>
  347. U32 writeFlags = 0;
  348. if(bOnlySelected)
  349. writeFlags |= SimObject::SelectedOnly;
  350. if(!ResourceManager->openFileForWrite(stream, pcFileName))
  351. return false;
  352. char docRoot[256];
  353. char modRoot[256];
  354. dStrcpy(docRoot, pcFileName);
  355. char *p = dStrrchr(docRoot, '/');
  356. if (p) *++p = '\0';
  357. else docRoot[0] = '\0';
  358. dStrcpy(modRoot, pcFileName);
  359. p = dStrchr(modRoot, '/');
  360. if (p) *++p = '\0';
  361. else modRoot[0] = '\0';
  362. Con::setVariable("$DocRoot", docRoot);
  363. Con::setVariable("$ModRoot", modRoot);
  364. const char *buffer;
  365. while(!f.isEOF())
  366. {
  367. buffer = (const char *) f.readLine();
  368. if(!dStrcmp(buffer, beginMessage))
  369. break;
  370. stream.write(dStrlen(buffer), buffer);
  371. stream.write(2, "\r\n");
  372. }
  373. stream.write(dStrlen(beginMessage), beginMessage);
  374. stream.write(2, "\r\n");
  375. write(stream, 0, writeFlags);
  376. stream.write(dStrlen(endMessage), endMessage);
  377. stream.write(2, "\r\n");
  378. while(!f.isEOF())
  379. {
  380. buffer = (const char *) f.readLine();
  381. if(!dStrcmp(buffer, endMessage))
  382. break;
  383. }
  384. while(!f.isEOF())
  385. {
  386. buffer = (const char *) f.readLine();
  387. stream.write(dStrlen(buffer), buffer);
  388. stream.write(2, "\r\n");
  389. }
  390. Con::setVariable("$DocRoot", NULL);
  391. Con::setVariable("$ModRoot", NULL);
  392. return true;
  393. }
  394. void SimObject::setInternalName(const char* newname)
  395. {
  396. if(newname)
  397. mInternalName = StringTable->insert(newname);
  398. }
  399. StringTableEntry SimObject::getInternalName()
  400. {
  401. return mInternalName;
  402. }
  403. void SimObject::dumpClassHierarchy()
  404. {
  405. AbstractClassRep* pRep = getClassRep();
  406. while(pRep)
  407. {
  408. Con::warnf("%s ->", pRep->getClassName());
  409. pRep = pRep->getParentClass();
  410. }
  411. }
  412. const char *SimObject::tabComplete(const char *prevText, S32 baseLen, bool fForward)
  413. {
  414. return mNameSpace->tabComplete(prevText, baseLen, fForward);
  415. }
  416. //-----------------------------------------------------------------------------
  417. void SimObject::setDataField(StringTableEntry slotName, const char *array, const char *value)
  418. {
  419. // first search the static fields if enabled
  420. if(mFlags.test(ModStaticFields))
  421. {
  422. const AbstractClassRep::Field *fld = findField(slotName);
  423. if(fld)
  424. {
  425. if( fld->type == AbstractClassRep::DepricatedFieldType ||
  426. fld->type == AbstractClassRep::StartGroupFieldType ||
  427. fld->type == AbstractClassRep::EndGroupFieldType)
  428. return;
  429. S32 array1 = array ? dAtoi(array) : 0;
  430. if(array1 >= 0 && array1 < fld->elementCount && fld->elementCount >= 1)
  431. {
  432. // If the set data notify callback returns true, then go ahead and
  433. // set the data, otherwise, assume the set notify callback has either
  434. // already set the data, or has deemed that the data should not
  435. // be set at all.
  436. FrameTemp<char> buffer(2048);
  437. FrameTemp<char> bufferSecure(2048); // This buffer is used to make a copy of the data
  438. // so that if the prep functions or any other functions use the string stack, the data
  439. // is not corrupted.
  440. ConsoleBaseType *cbt = ConsoleBaseType::getType( fld->type );
  441. AssertFatal( cbt != NULL, "Could not resolve Type Id." );
  442. const char* szBuffer = cbt->prepData( value, buffer, 2048 );
  443. dMemset( bufferSecure, 0, 2048 );
  444. dMemcpy( bufferSecure, szBuffer, dStrlen( szBuffer ) );
  445. if( (*fld->setDataFn)( this, bufferSecure ) )
  446. Con::setData(fld->type, (void *) (((const char *)this) + fld->offset), array1, 1, &value, fld->table);
  447. }
  448. if(fld->validator)
  449. fld->validator->validateType(this, (void *) (((const char *)this) + fld->offset));
  450. onStaticModified( slotName, value );
  451. return;
  452. }
  453. }
  454. if(mFlags.test(ModDynamicFields))
  455. {
  456. if(!mFieldDictionary)
  457. mFieldDictionary = new SimFieldDictionary;
  458. if(!array)
  459. mFieldDictionary->setFieldValue(slotName, value);
  460. else
  461. {
  462. char buf[256];
  463. dStrcpy(buf, slotName);
  464. dStrcat(buf, array);
  465. mFieldDictionary->setFieldValue(StringTable->insert(buf), value);
  466. }
  467. }
  468. }
  469. //-----------------------------------------------------------------------------
  470. const char *SimObject::getDataField(StringTableEntry slotName, const char *array)
  471. {
  472. if(mFlags.test(ModStaticFields))
  473. {
  474. S32 array1 = array ? dAtoi(array) : -1;
  475. const AbstractClassRep::Field *fld = findField(slotName);
  476. if(fld)
  477. {
  478. if(array1 == -1 && fld->elementCount == 1)
  479. return (*fld->getDataFn)( this, Con::getData(fld->type, (void *) (((const char *)this) + fld->offset), 0, fld->table, fld->flag) );
  480. if(array1 >= 0 && array1 < fld->elementCount)
  481. return (*fld->getDataFn)( this, Con::getData(fld->type, (void *) (((const char *)this) + fld->offset), array1, fld->table, fld->flag) );// + typeSizes[fld.type] * array1));
  482. return "";
  483. }
  484. }
  485. if(mFlags.test(ModDynamicFields))
  486. {
  487. if(!mFieldDictionary)
  488. return "";
  489. if(!array)
  490. {
  491. if (const char* val = mFieldDictionary->getFieldValue(slotName))
  492. return val;
  493. }
  494. else
  495. {
  496. static char buf[256];
  497. dStrcpy(buf, slotName);
  498. dStrcat(buf, array);
  499. if (const char* val = mFieldDictionary->getFieldValue(StringTable->insert(buf)))
  500. return val;
  501. }
  502. }
  503. return "";
  504. }
  505. //-----------------------------------------------------------------------------
  506. const char *SimObject::getPrefixedDataField(StringTableEntry fieldName, const char *array)
  507. {
  508. // Sanity!
  509. AssertFatal( fieldName != NULL, "Cannot get field value with NULL field name." );
  510. // Fetch field value.
  511. const char* pFieldValue = getDataField( fieldName, array );
  512. // Return without the prefix if there's no value.
  513. if ( pFieldValue == NULL || *pFieldValue == 0 )
  514. return StringTable->EmptyString;
  515. // Fetch the field prefix.
  516. StringTableEntry fieldPrefix = getDataFieldPrefix( fieldName );
  517. // Sanity!
  518. AssertFatal( fieldPrefix != NULL, "Field prefix cannot be NULL." );
  519. // Calculate a buffer size including prefix.
  520. const U32 valueBufferSize = dStrlen(fieldPrefix) + dStrlen(pFieldValue) + 1;
  521. // Fetch a buffer.
  522. char* pValueBuffer = Con::getReturnBuffer( valueBufferSize );
  523. // Format the value buffer.
  524. dSprintf( pValueBuffer, valueBufferSize, "%s%s", fieldPrefix, pFieldValue );
  525. return pValueBuffer;
  526. }
  527. //-----------------------------------------------------------------------------
  528. void SimObject::setPrefixedDataField(StringTableEntry fieldName, const char *array, const char *value)
  529. {
  530. // Sanity!
  531. AssertFatal( fieldName != NULL, "Cannot set object field value with NULL field name." );
  532. AssertFatal( value != NULL, "Field value cannot be NULL." );
  533. // Set value without prefix if there's no value.
  534. if ( *value == 0 )
  535. {
  536. setDataField( fieldName, NULL, value );
  537. return;
  538. }
  539. // Fetch the field prefix.
  540. StringTableEntry fieldPrefix = getDataFieldPrefix( fieldName );
  541. // Sanity.
  542. AssertFatal( fieldPrefix != NULL, "Field prefix cannot be NULL." );
  543. // Do we have a field prefix?
  544. if ( fieldPrefix == StringTable->EmptyString )
  545. {
  546. // No, so set the data field in the usual way.
  547. setDataField( fieldName, NULL, value );
  548. return;
  549. }
  550. // Yes, so fetch the length of the field prefix.
  551. const U32 fieldPrefixLength = dStrlen(fieldPrefix);
  552. // Yes, so does it start with the object field prefix?
  553. if ( dStrnicmp( value, fieldPrefix, fieldPrefixLength ) != 0 )
  554. {
  555. // No, so set the data field in the usual way.
  556. setDataField( fieldName, NULL, value );
  557. return;
  558. }
  559. // Yes, so set the data excluding the prefix.
  560. setDataField( fieldName, NULL, value + fieldPrefixLength );
  561. }
  562. //-----------------------------------------------------------------------------
  563. const char *SimObject::getPrefixedDynamicDataField(StringTableEntry fieldName, const char *array, const S32 fieldType )
  564. {
  565. // Sanity!
  566. AssertFatal( fieldName != NULL, "Cannot get field value with NULL field name." );
  567. // Fetch field value.
  568. const char* pFieldValue = getDataField( fieldName, array );
  569. // Sanity.
  570. AssertFatal( pFieldValue != NULL, "Field value cannot be NULL." );
  571. // Return the field if no field type is specified.
  572. if ( fieldType == -1 )
  573. return pFieldValue;
  574. // Return without the prefix if there's no value.
  575. if ( *pFieldValue == 0 )
  576. return StringTable->EmptyString;
  577. // Fetch the console base type.
  578. ConsoleBaseType* pConsoleBaseType = ConsoleBaseType::getType( fieldType );
  579. // Did we find the console base type?
  580. if ( pConsoleBaseType == NULL )
  581. {
  582. // No, so warn.
  583. Con::warnf("getPrefixedDynamicDataField() - Invalid field type '%d' specified for field '%s' with value '%s'.",
  584. fieldType, fieldName, pFieldValue );
  585. }
  586. // Fetch the field prefix.
  587. StringTableEntry fieldPrefix = pConsoleBaseType->getTypePrefix();
  588. // Sanity!
  589. AssertFatal( fieldPrefix != NULL, "Field prefix cannot be NULL." );
  590. // Calculate a buffer size including prefix.
  591. const U32 valueBufferSize = dStrlen(fieldPrefix) + dStrlen(pFieldValue) + 1;
  592. // Fetch a buffer.
  593. char* pValueBuffer = Con::getReturnBuffer( valueBufferSize );
  594. // Format the value buffer.
  595. dSprintf( pValueBuffer, valueBufferSize, "%s%s", fieldPrefix, pFieldValue );
  596. return pValueBuffer;
  597. }
  598. //-----------------------------------------------------------------------------
  599. void SimObject::setPrefixedDynamicDataField(StringTableEntry fieldName, const char *array, const char *value, const S32 fieldType )
  600. {
  601. // Sanity!
  602. AssertFatal( fieldName != NULL, "Cannot set object field value with NULL field name." );
  603. AssertFatal( value != NULL, "Field value cannot be NULL." );
  604. // Set value without prefix if no field type was specified.
  605. if ( fieldType == -1 )
  606. {
  607. setDataField( fieldName, NULL, value );
  608. return;
  609. }
  610. // Fetch the console base type.
  611. ConsoleBaseType* pConsoleBaseType = ConsoleBaseType::getType( fieldType );
  612. // Did we find the console base type?
  613. if ( pConsoleBaseType == NULL )
  614. {
  615. // No, so warn.
  616. Con::warnf("setPrefixedDynamicDataField() - Invalid field type '%d' specified for field '%s' with value '%s'.",
  617. fieldType, fieldName, value );
  618. }
  619. // Set value without prefix if there's no value or we didn't find the console base type.
  620. if ( *value == 0 || pConsoleBaseType == NULL )
  621. {
  622. setDataField( fieldName, NULL, value );
  623. return;
  624. }
  625. // Fetch the field prefix.
  626. StringTableEntry fieldPrefix = pConsoleBaseType->getTypePrefix();
  627. // Sanity.
  628. AssertFatal( fieldPrefix != NULL, "Field prefix cannot be NULL." );
  629. // Do we have a field prefix?
  630. if ( fieldPrefix == StringTable->EmptyString )
  631. {
  632. // No, so set the data field in the usual way.
  633. setDataField( fieldName, NULL, value );
  634. return;
  635. }
  636. // Yes, so fetch the length of the field prefix.
  637. const U32 fieldPrefixLength = dStrlen(fieldPrefix);
  638. // Yes, so does it start with the object field prefix?
  639. if ( dStrnicmp( value, fieldPrefix, fieldPrefixLength ) != 0 )
  640. {
  641. // No, so set the data field in the usual way.
  642. setDataField( fieldName, NULL, value );
  643. return;
  644. }
  645. // Yes, so set the data excluding the prefix.
  646. setDataField( fieldName, NULL, value + fieldPrefixLength );
  647. }
  648. //-----------------------------------------------------------------------------
  649. StringTableEntry SimObject::getDataFieldPrefix( StringTableEntry fieldName )
  650. {
  651. // Sanity!
  652. AssertFatal( fieldName != NULL, "Cannot get field prefix with NULL field name." );
  653. // Find the field.
  654. const AbstractClassRep::Field* pField = findField( fieldName );
  655. // Return nothing if field was not found.
  656. if ( pField == NULL )
  657. return StringTable->EmptyString;
  658. // Yes, so fetch the console base type.
  659. ConsoleBaseType* pConsoleBaseType = ConsoleBaseType::getType( pField->type );
  660. if(pConsoleBaseType == NULL)
  661. return StringTable->EmptyString;
  662. // Fetch the type prefix.
  663. return pConsoleBaseType->getTypePrefix();
  664. }
  665. //-----------------------------------------------------------------------------
  666. U32 SimObject::getDataFieldType( StringTableEntry slotName, const char* array )
  667. {
  668. const AbstractClassRep::Field* field = findField( slotName );
  669. if( field )
  670. return field->type;
  671. return 0;
  672. }
  673. SimObject::~SimObject()
  674. {
  675. delete mFieldDictionary;
  676. AssertFatal(nextNameObject == (SimObject*)-1,avar(
  677. "SimObject::~SimObject: Not removed from dictionary: name %s, id %i",
  678. objectName, mId));
  679. AssertFatal(nextManagerNameObject == (SimObject*)-1,avar(
  680. "SimObject::~SimObject: Not removed from manager dictionary: name %s, id %i",
  681. objectName,mId));
  682. AssertFatal(mFlags.test(Added) == 0, "SimObject::object "
  683. "missing call to SimObject::onRemove");
  684. }
  685. //---------------------------------------------------------------------------
  686. void SimObject::setLocked( bool b = true )
  687. {
  688. if (b)
  689. mFlags.set(Locked);
  690. else
  691. mFlags.clear(Locked);
  692. }
  693. void SimObject::setHidden(bool b = true)
  694. {
  695. if (b)
  696. mFlags.set(Hidden);
  697. else
  698. mFlags.clear(Hidden);
  699. }
  700. //---------------------------------------------------------------------------
  701. bool SimObject::onAdd()
  702. {
  703. mFlags.set(Added);
  704. linkNamespaces();
  705. // onAdd() should return FALSE if there was an error
  706. return true;
  707. }
  708. void SimObject::onRemove()
  709. {
  710. mFlags.clear(Added);
  711. unlinkNamespaces();
  712. }
  713. void SimObject::onGroupAdd()
  714. {
  715. }
  716. void SimObject::onGroupRemove()
  717. {
  718. }
  719. void SimObject::onDeleteNotify(SimObject*)
  720. {
  721. }
  722. void SimObject::onNameChange(const char*)
  723. {
  724. }
  725. void SimObject::onStaticModified(const char* slotName, const char* newValue)
  726. {
  727. }
  728. bool SimObject::processArguments(S32 argc, const char**)
  729. {
  730. return argc == 0;
  731. }
  732. bool SimObject::isChildOfGroup(SimGroup* pGroup)
  733. {
  734. if(!pGroup)
  735. return false;
  736. //if we *are* the group in question,
  737. //return true:
  738. if(pGroup == dynamic_cast<SimGroup*>(this))
  739. return true;
  740. SimGroup* temp = mGroup;
  741. while(temp)
  742. {
  743. if(temp == pGroup)
  744. return true;
  745. temp = temp->mGroup;
  746. }
  747. return false;
  748. }
  749. //---------------------------------------------------------------------------
  750. static Chunker<SimObject::Notify> notifyChunker(128000);
  751. SimObject::Notify *SimObject::mNotifyFreeList = NULL;
  752. SimObject::Notify *SimObject::allocNotify()
  753. {
  754. if(mNotifyFreeList)
  755. {
  756. SimObject::Notify *ret = mNotifyFreeList;
  757. mNotifyFreeList = ret->next;
  758. return ret;
  759. }
  760. return notifyChunker.alloc();
  761. }
  762. void SimObject::freeNotify(SimObject::Notify* note)
  763. {
  764. AssertFatal(note->type != SimObject::Notify::Invalid, "Invalid notify");
  765. note->type = SimObject::Notify::Invalid;
  766. note->next = mNotifyFreeList;
  767. mNotifyFreeList = note;
  768. }
  769. //------------------------------------------------------------------------------
  770. SimObject::Notify* SimObject::removeNotify(void *ptr, SimObject::Notify::Type type)
  771. {
  772. Notify **list = &mNotifyList;
  773. while(*list)
  774. {
  775. if((*list)->ptr == ptr && (*list)->type == type)
  776. {
  777. SimObject::Notify *ret = *list;
  778. *list = ret->next;
  779. return ret;
  780. }
  781. list = &((*list)->next);
  782. }
  783. return NULL;
  784. }
  785. void SimObject::deleteNotify(SimObject* obj)
  786. {
  787. AssertFatal(!obj->isDeleted(),
  788. "SimManager::deleteNotify: Object is being deleted");
  789. Notify *note = allocNotify();
  790. note->ptr = (void *) this;
  791. note->next = obj->mNotifyList;
  792. note->type = Notify::DeleteNotify;
  793. obj->mNotifyList = note;
  794. note = allocNotify();
  795. note->ptr = (void *) obj;
  796. note->next = mNotifyList;
  797. note->type = Notify::ClearNotify;
  798. mNotifyList = note;
  799. //obj->deleteNotifyList.pushBack(this);
  800. //clearNotifyList.pushBack(obj);
  801. }
  802. void SimObject::registerReference(SimObject **ptr)
  803. {
  804. Notify *note = allocNotify();
  805. note->ptr = (void *) ptr;
  806. note->next = mNotifyList;
  807. note->type = Notify::ObjectRef;
  808. mNotifyList = note;
  809. }
  810. void SimObject::unregisterReference(SimObject **ptr)
  811. {
  812. Notify *note = removeNotify((void *) ptr, Notify::ObjectRef);
  813. if(note)
  814. freeNotify(note);
  815. }
  816. void SimObject::clearNotify(SimObject* obj)
  817. {
  818. Notify *note = obj->removeNotify((void *) this, Notify::DeleteNotify);
  819. if(note)
  820. freeNotify(note);
  821. note = removeNotify((void *) obj, Notify::ClearNotify);
  822. if(note)
  823. freeNotify(note);
  824. }
  825. void SimObject::processDeleteNotifies()
  826. {
  827. // clear out any delete notifies and
  828. // object refs.
  829. while(mNotifyList)
  830. {
  831. Notify *note = mNotifyList;
  832. mNotifyList = note->next;
  833. AssertFatal(note->type != Notify::ClearNotify, "Clear notes should be all gone.");
  834. if(note->type == Notify::DeleteNotify)
  835. {
  836. SimObject *obj = (SimObject *) note->ptr;
  837. Notify *cnote = obj->removeNotify((void *)this, Notify::ClearNotify);
  838. obj->onDeleteNotify(this);
  839. freeNotify(cnote);
  840. }
  841. else
  842. {
  843. // it must be an object ref - a pointer refs this object
  844. *((SimObject **) note->ptr) = NULL;
  845. }
  846. freeNotify(note);
  847. }
  848. }
  849. void SimObject::clearAllNotifications()
  850. {
  851. for(Notify **cnote = &mNotifyList; *cnote; )
  852. {
  853. Notify *temp = *cnote;
  854. if(temp->type == Notify::ClearNotify)
  855. {
  856. *cnote = temp->next;
  857. Notify *note = ((SimObject *) temp->ptr)->removeNotify((void *) this, Notify::DeleteNotify);
  858. freeNotify(temp);
  859. freeNotify(note);
  860. }
  861. else
  862. cnote = &(temp->next);
  863. }
  864. }
  865. //---------------------------------------------------------------------------
  866. void SimObject::initPersistFields()
  867. {
  868. Parent::initPersistFields();
  869. addGroup("SimBase");
  870. addProtectedField("name", TypeName, Offset(objectName, SimObject), &setProtectedName, &getProtectedName, "Name for the object.");
  871. addField("canSaveDynamicFields", TypeBool, Offset(mCanSaveFieldDictionary, SimObject), &writeCanSaveDynamicFields, "");
  872. addField("internalName", TypeString, Offset(mInternalName, SimObject), &writeInternalName, "");
  873. addProtectedField("parentGroup", TypeSimObjectPtr, Offset(mGroup, SimObject), &setParentGroup, &defaultProtectedGetFn, &writeParentGroup, "Group hierarchy parent of the object." );
  874. endGroup("SimBase");
  875. // Namespace Linking.
  876. addGroup("Namespace Linking");
  877. addProtectedField("superclass", TypeString, Offset(mSuperClassName, SimObject), &setSuperClass, &defaultProtectedGetFn, &writeSuperclass, "Script Class of object.");
  878. addProtectedField("class", TypeString, Offset(mClassName, SimObject), &setClass, &defaultProtectedGetFn, &writeClass, "Script SuperClass of object.");
  879. endGroup("Namespace Linking");
  880. addGroup("Editing");
  881. addProtectedField("hidden", TypeBool, NULL, &_setHidden, &_getHidden, &_writeHidden, "Temporarily hides the object in the editor.");
  882. addProtectedField("locked", TypeBool, NULL, &_setLocked, &_getLocked, &_writeLocked, "Locks the object in the editor to prevent accidental changes.");
  883. endGroup("Editing");
  884. }
  885. //-----------------------------------------------------------------------------
  886. bool SimObject::setProtectedName(void *obj, const char *data)
  887. {
  888. if (disableNameChanging && !gEvalState.editorModeOn)
  889. return false;
  890. SimObject *object = static_cast<SimObject*>(obj);
  891. if (object->isProperlyAdded())
  892. object->assignName(data);
  893. // always return false because we assign the name here
  894. return false;
  895. }
  896. const char* SimObject::getProtectedName(void* obj, const char* data)
  897. {
  898. if (gEvalState.editorModeOn)
  899. {
  900. SimObject* object = static_cast<SimObject*>(obj);
  901. return object->objectNameEditor;
  902. }
  903. return data;
  904. }
  905. const StringTableEntry SimObject::getName(void) const
  906. {
  907. if (gEvalState.editorModeOn && objectNameEditor && objectNameEditor[0])
  908. {
  909. return objectNameEditor;
  910. }
  911. return objectName;
  912. };
  913. //-----------------------------------------------------------------------------
  914. SimObject* SimObject::clone( const bool copyDynamicFields )
  915. {
  916. // Craete cloned object.
  917. SimObject* pCloneObject = dynamic_cast<SimObject*>( ConsoleObject::create(getClassName()) );
  918. if (!pCloneObject)
  919. {
  920. Con::errorf("SimObject::clone() - Unable to create cloned object.");
  921. return NULL;
  922. }
  923. // Register object.
  924. if ( !pCloneObject->registerObject() )
  925. {
  926. Con::warnf("SimObject::clone() - Unable to register cloned object.");
  927. delete pCloneObject;
  928. return NULL;
  929. }
  930. // Copy object.
  931. copyTo( pCloneObject );
  932. // Copy over dynamic fields if requested.
  933. if ( copyDynamicFields )
  934. pCloneObject->assignDynamicFieldsFrom( this );
  935. return pCloneObject;
  936. }
  937. //-----------------------------------------------------------------------------
  938. void SimObject::copyTo(SimObject* object)
  939. {
  940. object->mClassName = mClassName;
  941. object->mSuperClassName = mSuperClassName;
  942. object->mNameSpace = NULL;
  943. object->linkNamespaces();
  944. }
  945. //-----------------------------------------------------------------------------
  946. bool SimObject::setParentGroup(void* obj, const char* data)
  947. {
  948. SimGroup *parent = NULL;
  949. SimObject *object = static_cast<SimObject*>(obj);
  950. if(Sim::findObject(data, parent))
  951. parent->addObject(object);
  952. // always return false, because we've set mGroup when we called addObject
  953. return false;
  954. }
  955. bool SimObject::addToSet(SimObjectId spid)
  956. {
  957. if (mFlags.test(Added) == false)
  958. return false;
  959. SimObject* ptr = Sim::findObject(spid);
  960. if (ptr)
  961. {
  962. SimSet* sp = dynamic_cast<SimSet*>(ptr);
  963. AssertFatal(sp != 0,
  964. "SimObject::addToSet: "
  965. "ObjectId does not refer to a set object");
  966. if (sp)
  967. {
  968. sp->addObject(this);
  969. return true;
  970. }
  971. }
  972. return false;
  973. }
  974. bool SimObject::addToSet(const char *ObjectName)
  975. {
  976. if (mFlags.test(Added) == false)
  977. return false;
  978. SimObject* ptr = Sim::findObject(ObjectName);
  979. if (ptr)
  980. {
  981. SimSet* sp = dynamic_cast<SimSet*>(ptr);
  982. AssertFatal(sp != 0,
  983. "SimObject::addToSet: "
  984. "ObjectName does not refer to a set object");
  985. if (sp)
  986. {
  987. sp->addObject(this);
  988. return true;
  989. }
  990. }
  991. return false;
  992. }
  993. bool SimObject::removeFromSet(SimObjectId sid)
  994. {
  995. if (mFlags.test(Added) == false)
  996. return false;
  997. SimSet *set;
  998. if(Sim::findObject(sid, set))
  999. {
  1000. set->removeObject(this);
  1001. return true;
  1002. }
  1003. return false;
  1004. }
  1005. bool SimObject::removeFromSet(const char *objectName)
  1006. {
  1007. if (mFlags.test(Added) == false)
  1008. return false;
  1009. SimSet *set;
  1010. if(Sim::findObject(objectName, set))
  1011. {
  1012. set->removeObject(this);
  1013. return true;
  1014. }
  1015. return false;
  1016. }
  1017. void SimObject::inspectPreApply()
  1018. {
  1019. }
  1020. void SimObject::inspectPostApply()
  1021. {
  1022. }
  1023. //-----------------------------------------------------------------------------
  1024. void SimObject::linkNamespaces()
  1025. {
  1026. // Don't link if we already have a namespace linkage in place.
  1027. AssertWarn(mNameSpace == NULL, "SimObject::linkNamespaces -- Namespace linkage already in place");
  1028. if (mNameSpace)
  1029. return;
  1030. // Start with the C++ Class namespace.
  1031. StringTableEntry parent = StringTable->insert( getClassName() );
  1032. // Link SuperClass to C++ Class.
  1033. if ( mSuperClassName && mSuperClassName[0] )
  1034. {
  1035. if ( Con::linkNamespaces(parent, mSuperClassName) )
  1036. parent = mSuperClassName;
  1037. else
  1038. mSuperClassName = NULL;
  1039. }
  1040. // Link Class to SuperClass or Class to C++ Class.
  1041. if ( mClassName && mClassName[0] )
  1042. {
  1043. if ( Con::linkNamespaces(parent, mClassName) )
  1044. parent = mClassName;
  1045. else
  1046. mClassName = NULL;
  1047. }
  1048. // Get the object's name.
  1049. StringTableEntry objectName = getName();
  1050. // Link Object Name to Class/SuperClass/C++ Class.
  1051. if ( objectName && objectName[0] )
  1052. {
  1053. if ( Con::linkNamespaces(parent, objectName) )
  1054. parent = objectName;
  1055. }
  1056. // Store our namespace.
  1057. mNameSpace = Con::lookupNamespace(parent);
  1058. }
  1059. //-----------------------------------------------------------------------------
  1060. void SimObject::unlinkNamespaces()
  1061. {
  1062. // Stop if there is no assigned namespace.
  1063. if (!mNameSpace)
  1064. return;
  1065. // Get the object's name.
  1066. StringTableEntry child = getName();
  1067. // Unlink any possible namespace combination.
  1068. if ( child && child[0] )
  1069. {
  1070. // Object Name/Class
  1071. if ( mClassName && mClassName[0] )
  1072. {
  1073. if( Con::unlinkNamespaces(mClassName, child) )
  1074. child = mClassName;
  1075. }
  1076. // Object Name/SuperClass or Class/SuperClass
  1077. if ( mSuperClassName && mSuperClassName[0] )
  1078. {
  1079. if ( Con::unlinkNamespaces(mSuperClassName, child) )
  1080. child = mSuperClassName;
  1081. }
  1082. // Object Name/C++ Class or SuperClass/C++ Class
  1083. Con::unlinkNamespaces(getClassName(), child);
  1084. }
  1085. else
  1086. {
  1087. // No Object Name, so get the Class namespace.
  1088. child = mClassName;
  1089. // Unlink any possible namespace combination.
  1090. if ( child && child[0] )
  1091. {
  1092. // Class/SuperClass
  1093. if ( mSuperClassName && mSuperClassName[0] )
  1094. {
  1095. if ( Con::unlinkNamespaces(mSuperClassName, child) )
  1096. child = mSuperClassName;
  1097. }
  1098. // Class/C++ Class or SuperClass/C++ Class
  1099. Con::unlinkNamespaces(getClassName(), child);
  1100. }
  1101. else
  1102. {
  1103. // SuperClass/C++ Class
  1104. if ( mSuperClassName && mSuperClassName[0] )
  1105. Con::unlinkNamespaces(getClassName(), mSuperClassName);
  1106. }
  1107. }
  1108. // Reset the namespace.
  1109. mNameSpace = NULL;
  1110. }
  1111. //-----------------------------------------------------------------------------
  1112. void SimObject::setClassNamespace( const char* classNamespace )
  1113. {
  1114. StringTableEntry oldClass = mClassName;
  1115. StringTableEntry newClass = StringTable->insert(classNamespace);
  1116. // Skip if no change.
  1117. if (oldClass == newClass)
  1118. return;
  1119. // Unlink the old namespaces.
  1120. if ( isProperlyAdded() )
  1121. unlinkNamespaces();
  1122. // Assign the new class namespace.
  1123. mClassName = newClass;
  1124. // Link the new namespaces.
  1125. if ( isProperlyAdded() )
  1126. linkNamespaces();
  1127. }
  1128. //-----------------------------------------------------------------------------
  1129. void SimObject::setSuperClassNamespace( const char* superClassNamespace )
  1130. {
  1131. StringTableEntry oldSuperClass = mSuperClassName;
  1132. StringTableEntry newSuperClass = StringTable->insert(superClassNamespace);
  1133. // Skip if no change.
  1134. if (oldSuperClass == newSuperClass)
  1135. return;
  1136. // Unlink the old namespaces.
  1137. if ( isProperlyAdded() )
  1138. unlinkNamespaces();
  1139. // Assign the new SuperClass namespace.
  1140. mSuperClassName = newSuperClass;
  1141. // Link the new namespaces.
  1142. if ( isProperlyAdded() )
  1143. linkNamespaces();
  1144. }
  1145. //-----------------------------------------------------------------------------
  1146. void SimObject::addListener(std::string objID)
  1147. {
  1148. for (auto iter = mListenerList.begin(); iter != mListenerList.end(); ++iter)
  1149. {
  1150. if (iter->objID == objID)
  1151. {
  1152. iter->doomed = false;
  1153. return;
  1154. }
  1155. }
  1156. OtoListener listener = OtoListener();
  1157. listener.objID = objID;
  1158. listener.doomed = false;
  1159. mListenerList.push_back(listener);
  1160. }
  1161. //-----------------------------------------------------------------------------
  1162. void SimObject::removeListener(std::string objID)
  1163. {
  1164. for (auto iter = mListenerList.begin(); iter != mListenerList.end(); ++iter)
  1165. {
  1166. if (iter->objID == objID)
  1167. {
  1168. iter->doomed = true;
  1169. }
  1170. }
  1171. if (!bIsEventRaised)
  1172. {
  1173. mListenerList.erase(std::remove_if(mListenerList.begin(), mListenerList.end(), [](OtoListener listener){ return listener.doomed; }), mListenerList.end());
  1174. }
  1175. }
  1176. //-----------------------------------------------------------------------------
  1177. void SimObject::removeAllListeners()
  1178. {
  1179. if (bIsEventRaised)
  1180. {
  1181. for (auto iter = mListenerList.begin(); iter != mListenerList.end(); ++iter)
  1182. {
  1183. iter->doomed = true;
  1184. }
  1185. }
  1186. else
  1187. {
  1188. mListenerList.clear();
  1189. }
  1190. }
  1191. //-----------------------------------------------------------------------------
  1192. void SimObject::postEvent(std::string eventName, std::string data)
  1193. {
  1194. std::string onEvent = "on" + eventName;
  1195. if (mListenerList.empty())
  1196. {
  1197. return;
  1198. }
  1199. if (bIsEventRaised)
  1200. {
  1201. Con::warnf("SimObject::postEvent() - To avoid circular events, you cannot raise the event '%s' until a previous event has finished.", eventName.c_str());
  1202. return;
  1203. }
  1204. bIsEventRaised = true;
  1205. for (auto iter = mListenerList.begin(); iter != mListenerList.end(); ++iter)
  1206. {
  1207. SimObject* pSimObject = dynamic_cast<SimObject*>(Sim::findObject(iter->objID.c_str()));
  1208. // Did we find the object?
  1209. if (pSimObject)
  1210. {
  1211. if (!iter->doomed && pSimObject->isMethod(onEvent.c_str()))
  1212. {
  1213. Con::executef(pSimObject, 3, onEvent.c_str(), data.c_str());
  1214. }
  1215. }
  1216. else
  1217. {
  1218. //it must have been deleted
  1219. iter->doomed = true;
  1220. }
  1221. }
  1222. bIsEventRaised = false;
  1223. //now to remove all doomed listeners
  1224. mListenerList.erase(std::remove_if(mListenerList.begin(), mListenerList.end(), [](OtoListener listener){ return listener.doomed; }), mListenerList.end());
  1225. }
  1226. //-----------------------------------------------------------------------------
  1227. static S32 QSORT_CALLBACK compareFields(const void* a,const void* b)
  1228. {
  1229. const AbstractClassRep::Field* fa = *((const AbstractClassRep::Field**)a);
  1230. const AbstractClassRep::Field* fb = *((const AbstractClassRep::Field**)b);
  1231. return dStricmp(fa->pFieldname, fb->pFieldname);
  1232. }
  1233. void SimObject::dump()
  1234. {
  1235. const AbstractClassRep::FieldList &list = getFieldList();
  1236. char expandedBuffer[4096];
  1237. Con::printf("Static Fields:");
  1238. Vector<const AbstractClassRep::Field *> flist(__FILE__, __LINE__);
  1239. for(U32 i = 0; i < (U32)list.size(); i++)
  1240. flist.push_back(&list[i]);
  1241. dQsort(flist.address(),flist.size(),sizeof(AbstractClassRep::Field *),compareFields);
  1242. for(Vector<const AbstractClassRep::Field *>::iterator itr = flist.begin(); itr != flist.end(); itr++)
  1243. {
  1244. const AbstractClassRep::Field* f = *itr;
  1245. if( f->type == AbstractClassRep::DepricatedFieldType ||
  1246. f->type == AbstractClassRep::StartGroupFieldType ||
  1247. f->type == AbstractClassRep::EndGroupFieldType) continue;
  1248. for(U32 j = 0; S32(j) < f->elementCount; j++)
  1249. {
  1250. // [neo, 07/05/2007 - #3000]
  1251. // Some objects use dummy vars and projected fields so make sure we call the get functions
  1252. //const char *val = Con::getData(f->type, (void *) (((const char *)object) + f->offset), j, f->table, f->flag);
  1253. const char *val = (*f->getDataFn)( this, Con::getData(f->type, (void *) (((const char *)this) + f->offset), j, f->table, f->flag) );// + typeSizes[fld.type] * array1));
  1254. if(!val /*|| !*val*/)
  1255. continue;
  1256. if(f->elementCount == 1)
  1257. dSprintf(expandedBuffer, sizeof(expandedBuffer), " %s = \"", f->pFieldname);
  1258. else
  1259. dSprintf(expandedBuffer, sizeof(expandedBuffer), " %s[%d] = \"", f->pFieldname, j);
  1260. expandEscape(expandedBuffer + dStrlen(expandedBuffer), val);
  1261. Con::printf("%s\"", expandedBuffer);
  1262. }
  1263. }
  1264. Con::printf("Dynamic Fields:");
  1265. if(getFieldDictionary())
  1266. getFieldDictionary()->printFields(this);
  1267. Con::printf("Methods:");
  1268. Namespace *ns = getNamespace();
  1269. Vector<Namespace::Entry *> vec(__FILE__, __LINE__);
  1270. if(ns)
  1271. ns->getEntryList(&vec);
  1272. for(Vector<Namespace::Entry *>::iterator j = vec.begin(); j != vec.end(); j++)
  1273. Con::printf(" %s() - %s", (*j)->mFunctionName, (*j)->mUsage ? (*j)->mUsage : "");
  1274. }