consoleObject.cpp 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980
  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. #include "platform/platform.h"
  23. #include "console/consoleObject.h"
  24. #include "core/stringTable.h"
  25. #include "core/crc.h"
  26. #include "core/dataChunker.h"
  27. #include "console/console.h"
  28. #include "console/consoleInternal.h"
  29. #include "console/typeValidators.h"
  30. #include "console/simObject.h"
  31. #include "console/engineTypes.h"
  32. #include "console/engineAPI.h"
  33. IMPLEMENT_SCOPE( ConsoleAPI, Console,,
  34. "Functionality related to the legacy TorqueScript console system." );
  35. IMPLEMENT_NONINSTANTIABLE_CLASS( ConsoleObject,
  36. "Legacy console system root class. Will disappear." )
  37. END_IMPLEMENT_CLASS;
  38. AbstractClassRep * AbstractClassRep::classLinkList = NULL;
  39. AbstractClassRep::FieldList sg_tempFieldList( __FILE__, __LINE__ );
  40. U32 AbstractClassRep::NetClassCount [NetClassGroupsCount][NetClassTypesCount] = {{0, },};
  41. U32 AbstractClassRep::NetClassBitSize[NetClassGroupsCount][NetClassTypesCount] = {{0, },};
  42. AbstractClassRep ** AbstractClassRep::classTable[NetClassGroupsCount][NetClassTypesCount];
  43. U32 AbstractClassRep::classCRC[NetClassGroupsCount] = {CRC::INITIAL_CRC_VALUE, };
  44. bool AbstractClassRep::initialized = false;
  45. //-----------------------------------------------------------------------------
  46. AbstractClassRep* AbstractClassRep::findFieldRoot(StringTableEntry fieldName)
  47. {
  48. // Find the field.
  49. const Field* pField = findField(fieldName);
  50. // Finish if not found.
  51. if (pField == NULL)
  52. return NULL;
  53. // We're the root if we have no parent.
  54. if (getParentClass() == NULL)
  55. return this;
  56. // Find the field root via the parent.
  57. AbstractClassRep* pFieldRoot = getParentClass()->findFieldRoot(fieldName);
  58. // We're the root if the parent does not have it else return the field root.
  59. return pFieldRoot == NULL ? this : pFieldRoot;
  60. }
  61. void AbstractClassRep::init()
  62. {
  63. // Only add the renderable and selectable globals for
  64. // classes derived from SceneObject which are the only
  65. // objects for which these work.
  66. if ( isSubclassOf( "SceneObject" ) )
  67. {
  68. Con::addVariable( avar( "$%s::isRenderable", getClassName() ), TypeBool, &mIsRenderEnabled,
  69. "@brief Disables rendering of all instances of this type.\n\n" );
  70. Con::addVariable( avar( "$%s::isSelectable", getClassName() ), TypeBool, &mIsSelectionEnabled,
  71. "@brief Disables selection of all instances of this type.\n\n" );
  72. }
  73. }
  74. const AbstractClassRep::Field *AbstractClassRep::findField(StringTableEntry name) const
  75. {
  76. for(U32 i = 0; i < mFieldList.size(); i++)
  77. if(mFieldList[i].pFieldname == name)
  78. return &mFieldList[i];
  79. return NULL;
  80. }
  81. AbstractClassRep* AbstractClassRep::findClassRep(const char* in_pClassName)
  82. {
  83. AssertFatal(initialized,
  84. "AbstractClassRep::findClassRep() - Tried to find an AbstractClassRep before AbstractClassRep::initialize().");
  85. for (AbstractClassRep *walk = classLinkList; walk; walk = walk->nextClass)
  86. if (!dStricmp(walk->getClassName(), in_pClassName))
  87. return walk;
  88. return NULL;
  89. }
  90. AbstractClassRep* AbstractClassRep::findClassRep( U32 groupId, U32 typeId, U32 classId )
  91. {
  92. AssertFatal(initialized,
  93. "AbstractClassRep::findClasRep() - Tried to create an object before AbstractClassRep::initialize().");
  94. AssertFatal(classId < NetClassCount[groupId][typeId],
  95. "AbstractClassRep::findClassRep() - Class id out of range.");
  96. AssertFatal(classTable[groupId][typeId][classId] != NULL,
  97. "AbstractClassRep::findClassRep() - No class with requested ID type.");
  98. // Look up the specified class and create it.
  99. if(classTable[groupId][typeId][classId])
  100. return classTable[groupId][typeId][classId];
  101. return NULL;
  102. }
  103. //--------------------------------------
  104. void AbstractClassRep::registerClassRep(AbstractClassRep* in_pRep)
  105. {
  106. AssertFatal(in_pRep != NULL, "AbstractClassRep::registerClassRep was passed a NULL pointer!");
  107. #ifdef TORQUE_DEBUG // assert if this class is already registered.
  108. for(AbstractClassRep *walk = classLinkList; walk; walk = walk->nextClass)
  109. {
  110. AssertFatal(dStrcmp(in_pRep->mClassName, walk->mClassName),
  111. "Duplicate class name registered in AbstractClassRep::registerClassRep()");
  112. }
  113. #endif
  114. in_pRep->nextClass = classLinkList;
  115. classLinkList = in_pRep;
  116. }
  117. //--------------------------------------
  118. void AbstractClassRep::removeClassRep(AbstractClassRep* in_pRep)
  119. {
  120. for( AbstractClassRep *walk = classLinkList; walk; walk = walk->nextClass )
  121. {
  122. // This is the case that will most likely get hit.
  123. if( walk->nextClass == in_pRep )
  124. walk->nextClass = walk->nextClass->nextClass;
  125. else if( walk == in_pRep )
  126. {
  127. AssertFatal( in_pRep == classLinkList, "Pat failed in his logic for un linking RuntimeClassReps from the class linked list" );
  128. classLinkList = in_pRep->nextClass;
  129. }
  130. }
  131. }
  132. //--------------------------------------
  133. ConsoleObject* AbstractClassRep::create(const char* in_pClassName)
  134. {
  135. AssertFatal(initialized,
  136. "AbstractClassRep::create() - Tried to create an object before AbstractClassRep::initialize().");
  137. const AbstractClassRep *rep = AbstractClassRep::findClassRep(in_pClassName);
  138. if(rep)
  139. return rep->create();
  140. AssertWarn(0, avar("Couldn't find class rep for dynamic class: %s", in_pClassName));
  141. return NULL;
  142. }
  143. //--------------------------------------
  144. ConsoleObject* AbstractClassRep::create(const U32 groupId, const U32 typeId, const U32 in_classId)
  145. {
  146. AbstractClassRep* classRep = findClassRep( groupId, typeId, in_classId );
  147. if( !classRep )
  148. return NULL;
  149. return classRep->create();
  150. }
  151. //--------------------------------------
  152. static S32 QSORT_CALLBACK ACRCompare(const void *aptr, const void *bptr)
  153. {
  154. const AbstractClassRep *a = *((const AbstractClassRep **) aptr);
  155. const AbstractClassRep *b = *((const AbstractClassRep **) bptr);
  156. if(a->mClassType != b->mClassType)
  157. return a->mClassType - b->mClassType;
  158. return dStrnatcasecmp(a->getClassName(), b->getClassName());
  159. }
  160. void AbstractClassRep::initialize()
  161. {
  162. AssertFatal(!initialized, "Duplicate call to AbstractClassRep::initialize()!");
  163. Vector<AbstractClassRep *> dynamicTable(__FILE__, __LINE__);
  164. AbstractClassRep *walk;
  165. // Initialize namespace references...
  166. for (walk = classLinkList; walk; walk = walk->nextClass)
  167. {
  168. walk->mNamespace = Con::lookupNamespace(StringTable->insert(walk->getClassName()));
  169. walk->mNamespace->mUsage = walk->getDocString();
  170. walk->mNamespace->mClassRep = walk;
  171. }
  172. // Initialize field lists... (and perform other console registration).
  173. for (walk = classLinkList; walk; walk = walk->nextClass)
  174. {
  175. // sg_tempFieldList is used as a staging area for field lists
  176. // (see addField, addGroup, etc.)
  177. sg_tempFieldList.setSize(0);
  178. walk->init();
  179. // So if we have things in it, copy it over...
  180. if (sg_tempFieldList.size() != 0)
  181. walk->mFieldList = sg_tempFieldList;
  182. // And of course delete it every round.
  183. sg_tempFieldList.clear();
  184. }
  185. // Calculate counts and bit sizes for the various NetClasses.
  186. for (U32 group = 0; group < NetClassGroupsCount; group++)
  187. {
  188. U32 groupMask = 1 << group;
  189. // Specifically, for each NetClass of each NetGroup...
  190. for(U32 type = 0; type < NetClassTypesCount; type++)
  191. {
  192. // Go through all the classes and find matches...
  193. for (walk = classLinkList; walk; walk = walk->nextClass)
  194. {
  195. if(walk->mClassType == type && walk->mClassGroupMask & groupMask)
  196. dynamicTable.push_back(walk);
  197. }
  198. // Set the count for this NetGroup and NetClass
  199. NetClassCount[group][type] = dynamicTable.size();
  200. if(!NetClassCount[group][type])
  201. continue; // If no classes matched, skip to next.
  202. // Sort by type and then by name.
  203. dQsort((void *) &dynamicTable[0], dynamicTable.size(), sizeof(AbstractClassRep *), ACRCompare);
  204. // Allocate storage in the classTable
  205. classTable[group][type] = new AbstractClassRep*[NetClassCount[group][type]];
  206. // Fill this in and assign class ids for this group.
  207. for(U32 i = 0; i < NetClassCount[group][type];i++)
  208. {
  209. classTable[group][type][i] = dynamicTable[i];
  210. dynamicTable[i]->mClassId[group] = i;
  211. }
  212. // And calculate the size of bitfields for this group and type.
  213. NetClassBitSize[group][type] =
  214. getBinLog2(getNextPow2(NetClassCount[group][type] + 1));
  215. AssertFatal(NetClassCount[group][type] < (1 << NetClassBitSize[group][type]), "NetClassBitSize too small!");
  216. dynamicTable.clear();
  217. }
  218. }
  219. // Ok, we're golden!
  220. initialized = true;
  221. }
  222. void AbstractClassRep::shutdown()
  223. {
  224. AssertFatal( initialized, "AbstractClassRep::shutdown - not initialized" );
  225. // Release storage allocated to the class table.
  226. for (U32 group = 0; group < NetClassGroupsCount; group++)
  227. for(U32 type = 0; type < NetClassTypesCount; type++)
  228. if( classTable[ group ][ type ] )
  229. SAFE_DELETE_ARRAY( classTable[ group ][ type ] );
  230. initialized = false;
  231. }
  232. AbstractClassRep *AbstractClassRep::getCommonParent( const AbstractClassRep *otherClass ) const
  233. {
  234. // CodeReview: This may be a noob way of doing it. There may be some kind of
  235. // super-spiffy algorithm to do what the code below does, but this appeared
  236. // to make sense to me, and it is pretty easy to see what it is doing [6/23/2007 Pat]
  237. static VectorPtr<AbstractClassRep *> thisClassHeirarchy;
  238. thisClassHeirarchy.clear();
  239. AbstractClassRep *walk = const_cast<AbstractClassRep *>( this );
  240. while( walk != NULL )
  241. {
  242. thisClassHeirarchy.push_front( walk );
  243. walk = walk->getParentClass();
  244. }
  245. static VectorPtr<AbstractClassRep *> compClassHeirarchy;
  246. compClassHeirarchy.clear();
  247. walk = const_cast<AbstractClassRep *>( otherClass );
  248. while( walk != NULL )
  249. {
  250. compClassHeirarchy.push_front( walk );
  251. walk = walk->getParentClass();
  252. }
  253. // Make sure we only iterate over the list the number of times we can
  254. S32 maxIterations = getMin( compClassHeirarchy.size(), thisClassHeirarchy.size() );
  255. U32 i = 0;
  256. for( ; i < maxIterations; i++ )
  257. {
  258. if( compClassHeirarchy[i] != thisClassHeirarchy[i] )
  259. break;
  260. }
  261. return compClassHeirarchy[i];
  262. }
  263. //------------------------------------------------------------------------------
  264. //-------------------------------------- ConsoleObject
  265. static char replacebuf[1024];
  266. static char* suppressSpaces(const char* in_pname)
  267. {
  268. U32 i = 0;
  269. char chr;
  270. do
  271. {
  272. chr = in_pname[i];
  273. replacebuf[i++] = (chr != 32) ? chr : '_';
  274. } while(chr);
  275. return replacebuf;
  276. }
  277. void ConsoleObject::addGroup(const char* in_pGroupname, const char* in_pGroupDocs)
  278. {
  279. // Remove spaces.
  280. char* pFieldNameBuf = suppressSpaces(in_pGroupname);
  281. // Append group type to fieldname.
  282. dStrcat(pFieldNameBuf, "_begingroup");
  283. // Create Field.
  284. AbstractClassRep::Field f;
  285. f.pFieldname = StringTable->insert(pFieldNameBuf);
  286. f.pGroupname = in_pGroupname;
  287. if(in_pGroupDocs)
  288. f.pFieldDocs = in_pGroupDocs;
  289. f.type = AbstractClassRep::StartGroupFieldType;
  290. f.elementCount = 0;
  291. f.groupExpand = false;
  292. f.validator = NULL;
  293. f.setDataFn = &defaultProtectedSetFn;
  294. f.getDataFn = &defaultProtectedGetFn;
  295. f.writeDataFn = &defaultProtectedWriteFn;
  296. // Add to field list.
  297. sg_tempFieldList.push_back(f);
  298. }
  299. void ConsoleObject::endGroup(const char* in_pGroupname)
  300. {
  301. // Remove spaces.
  302. char* pFieldNameBuf = suppressSpaces(in_pGroupname);
  303. // Append group type to fieldname.
  304. dStrcat(pFieldNameBuf, "_endgroup");
  305. // Create Field.
  306. AbstractClassRep::Field f;
  307. f.pFieldname = StringTable->insert(pFieldNameBuf);
  308. f.pGroupname = in_pGroupname;
  309. f.type = AbstractClassRep::EndGroupFieldType;
  310. f.groupExpand = false;
  311. f.validator = NULL;
  312. f.setDataFn = &defaultProtectedSetFn;
  313. f.getDataFn = &defaultProtectedGetFn;
  314. f.writeDataFn = &defaultProtectedWriteFn;
  315. f.elementCount = 0;
  316. // Add to field list.
  317. sg_tempFieldList.push_back(f);
  318. }
  319. void ConsoleObject::addArray( const char *arrayName, S32 count )
  320. {
  321. char *nameBuff = suppressSpaces(arrayName);
  322. dStrcat(nameBuff, "_beginarray");
  323. // Create Field.
  324. AbstractClassRep::Field f;
  325. f.pFieldname = StringTable->insert(nameBuff);
  326. f.pGroupname = arrayName;
  327. f.type = AbstractClassRep::StartArrayFieldType;
  328. f.elementCount = count;
  329. f.groupExpand = false;
  330. f.validator = NULL;
  331. f.setDataFn = &defaultProtectedSetFn;
  332. f.getDataFn = &defaultProtectedGetFn;
  333. f.writeDataFn = &defaultProtectedWriteFn;
  334. // Add to field list.
  335. sg_tempFieldList.push_back(f);
  336. }
  337. void ConsoleObject::endArray( const char *arrayName )
  338. {
  339. char *nameBuff = suppressSpaces(arrayName);
  340. dStrcat(nameBuff, "_endarray");
  341. // Create Field.
  342. AbstractClassRep::Field f;
  343. f.pFieldname = StringTable->insert(nameBuff);
  344. f.pGroupname = arrayName;
  345. f.type = AbstractClassRep::EndArrayFieldType;
  346. f.groupExpand = false;
  347. f.validator = NULL;
  348. f.setDataFn = &defaultProtectedSetFn;
  349. f.getDataFn = &defaultProtectedGetFn;
  350. f.writeDataFn = &defaultProtectedWriteFn;
  351. f.elementCount = 0;
  352. // Add to field list.
  353. sg_tempFieldList.push_back(f);
  354. }
  355. void ConsoleObject::addField(const char* in_pFieldname,
  356. const U32 in_fieldType,
  357. const dsize_t in_fieldOffset,
  358. const char* in_pFieldDocs,
  359. U32 flags )
  360. {
  361. addField(
  362. in_pFieldname,
  363. in_fieldType,
  364. in_fieldOffset,
  365. 1,
  366. in_pFieldDocs,
  367. flags );
  368. }
  369. void ConsoleObject::addField(const char* in_pFieldname,
  370. const U32 in_fieldType,
  371. const dsize_t in_fieldOffset,
  372. AbstractClassRep::WriteDataNotify in_writeDataFn,
  373. const char* in_pFieldDocs,
  374. U32 flags)
  375. {
  376. addField(
  377. in_pFieldname,
  378. in_fieldType,
  379. in_fieldOffset,
  380. in_writeDataFn,
  381. 1,
  382. in_pFieldDocs,
  383. flags);
  384. }
  385. void ConsoleObject::addField(const char* in_pFieldname,
  386. const U32 in_fieldType,
  387. const dsize_t in_fieldOffset,
  388. const U32 in_elementCount,
  389. const char* in_pFieldDocs,
  390. U32 flags)
  391. {
  392. addField(in_pFieldname,
  393. in_fieldType,
  394. in_fieldOffset,
  395. &defaultProtectedWriteFn,
  396. in_elementCount,
  397. in_pFieldDocs,
  398. flags);
  399. }
  400. void ConsoleObject::addField(const char* in_pFieldname,
  401. const U32 in_fieldType,
  402. const dsize_t in_fieldOffset,
  403. AbstractClassRep::WriteDataNotify in_writeDataFn,
  404. const U32 in_elementCount,
  405. const char* in_pFieldDocs,
  406. U32 flags)
  407. {
  408. AbstractClassRep::Field f;
  409. f.pFieldname = StringTable->insert(in_pFieldname);
  410. if (in_pFieldDocs)
  411. f.pFieldDocs = in_pFieldDocs;
  412. f.type = in_fieldType;
  413. f.offset = in_fieldOffset;
  414. f.elementCount = in_elementCount;
  415. f.validator = NULL;
  416. f.flag = flags;
  417. f.setDataFn = &defaultProtectedSetFn;
  418. f.getDataFn = &defaultProtectedGetFn;
  419. f.writeDataFn = in_writeDataFn;
  420. ConsoleBaseType* conType = ConsoleBaseType::getType(in_fieldType);
  421. AssertFatal(conType, "ConsoleObject::addField - invalid console type");
  422. f.table = conType->getEnumTable();
  423. sg_tempFieldList.push_back(f);
  424. }
  425. void ConsoleObject::addProtectedField(const char* in_pFieldname,
  426. const U32 in_fieldType,
  427. const dsize_t in_fieldOffset,
  428. AbstractClassRep::SetDataNotify in_setDataFn,
  429. AbstractClassRep::GetDataNotify in_getDataFn,
  430. const char* in_pFieldDocs,
  431. U32 flags)
  432. {
  433. addProtectedField(
  434. in_pFieldname,
  435. in_fieldType,
  436. in_fieldOffset,
  437. in_setDataFn,
  438. in_getDataFn,
  439. &defaultProtectedWriteFn,
  440. 1,
  441. in_pFieldDocs,
  442. flags);
  443. }
  444. void ConsoleObject::addProtectedField(const char* in_pFieldname,
  445. const U32 in_fieldType,
  446. const dsize_t in_fieldOffset,
  447. AbstractClassRep::SetDataNotify in_setDataFn,
  448. AbstractClassRep::GetDataNotify in_getDataFn,
  449. AbstractClassRep::WriteDataNotify in_writeDataFn,
  450. const char* in_pFieldDocs,
  451. U32 flags)
  452. {
  453. addProtectedField(
  454. in_pFieldname,
  455. in_fieldType,
  456. in_fieldOffset,
  457. in_setDataFn,
  458. in_getDataFn,
  459. in_writeDataFn,
  460. 1,
  461. in_pFieldDocs,
  462. flags);
  463. }
  464. void ConsoleObject::addProtectedField(const char* in_pFieldname,
  465. const U32 in_fieldType,
  466. const dsize_t in_fieldOffset,
  467. AbstractClassRep::SetDataNotify in_setDataFn,
  468. AbstractClassRep::GetDataNotify in_getDataFn,
  469. const U32 in_elementCount,
  470. const char* in_pFieldDocs,
  471. U32 flags)
  472. {
  473. addProtectedField(
  474. in_pFieldname,
  475. in_fieldType,
  476. in_fieldOffset,
  477. in_setDataFn,
  478. in_getDataFn,
  479. &defaultProtectedWriteFn,
  480. in_elementCount,
  481. in_pFieldDocs,
  482. flags);
  483. }
  484. void ConsoleObject::addProtectedField(const char* in_pFieldname,
  485. const U32 in_fieldType,
  486. const dsize_t in_fieldOffset,
  487. AbstractClassRep::SetDataNotify in_setDataFn,
  488. AbstractClassRep::GetDataNotify in_getDataFn,
  489. AbstractClassRep::WriteDataNotify in_writeDataFn,
  490. const U32 in_elementCount,
  491. const char* in_pFieldDocs,
  492. U32 flags)
  493. {
  494. AbstractClassRep::Field f;
  495. f.pFieldname = StringTable->insert(in_pFieldname);
  496. if (in_pFieldDocs)
  497. f.pFieldDocs = in_pFieldDocs;
  498. f.type = in_fieldType;
  499. f.offset = in_fieldOffset;
  500. f.elementCount = in_elementCount;
  501. f.validator = NULL;
  502. f.flag = flags;
  503. f.setDataFn = in_setDataFn;
  504. f.getDataFn = in_getDataFn;
  505. f.writeDataFn = in_writeDataFn;
  506. ConsoleBaseType* conType = ConsoleBaseType::getType(in_fieldType);
  507. AssertFatal(conType, "ConsoleObject::addProtectedField - invalid console type");
  508. f.table = conType->getEnumTable();
  509. sg_tempFieldList.push_back(f);
  510. }
  511. void ConsoleObject::addFieldV(const char* in_pFieldname,
  512. const U32 in_fieldType,
  513. const dsize_t in_fieldOffset,
  514. TypeValidator *v,
  515. const char* in_pFieldDocs)
  516. {
  517. AbstractClassRep::Field f;
  518. f.pFieldname = StringTable->insert(in_pFieldname);
  519. if(in_pFieldDocs)
  520. f.pFieldDocs = in_pFieldDocs;
  521. f.type = in_fieldType;
  522. f.offset = in_fieldOffset;
  523. f.elementCount = 1;
  524. f.table = NULL;
  525. f.setDataFn = &defaultProtectedSetFn;
  526. f.getDataFn = &defaultProtectedGetFn;
  527. f.writeDataFn = &defaultProtectedWriteFn;
  528. f.validator = v;
  529. v->fieldIndex = sg_tempFieldList.size();
  530. sg_tempFieldList.push_back(f);
  531. }
  532. void ConsoleObject::addDeprecatedField(const char *fieldName)
  533. {
  534. AbstractClassRep::Field f;
  535. f.pFieldname = StringTable->insert(fieldName);
  536. f.type = AbstractClassRep::DeprecatedFieldType;
  537. f.offset = 0;
  538. f.elementCount = 0;
  539. f.table = NULL;
  540. f.validator = NULL;
  541. f.setDataFn = &defaultProtectedSetFn;
  542. f.getDataFn = &defaultProtectedGetFn;
  543. f.writeDataFn = &defaultProtectedWriteFn;
  544. sg_tempFieldList.push_back(f);
  545. }
  546. bool ConsoleObject::removeField(const char* in_pFieldname)
  547. {
  548. for (U32 i = 0; i < sg_tempFieldList.size(); i++) {
  549. if (dStricmp(in_pFieldname, sg_tempFieldList[i].pFieldname) == 0) {
  550. sg_tempFieldList.erase(i);
  551. return true;
  552. }
  553. }
  554. return false;
  555. }
  556. //--------------------------------------
  557. void ConsoleObject::initPersistFields()
  558. {
  559. }
  560. //--------------------------------------
  561. void ConsoleObject::consoleInit()
  562. {
  563. }
  564. //--------------------------------------
  565. AbstractClassRep* ConsoleObject::getClassRep() const
  566. {
  567. return NULL;
  568. }
  569. String ConsoleObject::_getLogMessage(const char* fmt, va_list args) const
  570. {
  571. String objClass = "UnknownClass";
  572. if(getClassRep())
  573. objClass = getClassRep()->getClassName();
  574. String formattedMessage = String::VToString(fmt, args);
  575. return String::ToString("%s - Object at %x - %s",
  576. objClass.c_str(), this, formattedMessage.c_str());
  577. }
  578. void ConsoleObject::logMessage(const char* fmt, ...) const
  579. {
  580. va_list args;
  581. va_start(args, fmt);
  582. Con::printf(_getLogMessage(fmt, args));
  583. va_end(args);
  584. }
  585. void ConsoleObject::logWarning(const char* fmt, ...) const
  586. {
  587. va_list args;
  588. va_start(args, fmt);
  589. Con::warnf(_getLogMessage(fmt, args));
  590. va_end(args);
  591. }
  592. void ConsoleObject::logError(const char* fmt, ...) const
  593. {
  594. va_list args;
  595. va_start(args, fmt);
  596. Con::errorf(_getLogMessage(fmt, args));
  597. va_end(args);
  598. }
  599. //------------------------------------------------------------------------------
  600. static const char* returnClassList( Vector< AbstractClassRep* >& classes, U32 bufSize )
  601. {
  602. if( !classes.size() )
  603. return "";
  604. dQsort( classes.address(), classes.size(), sizeof( AbstractClassRep* ), ACRCompare );
  605. char* ret = Con::getReturnBuffer( bufSize );
  606. dStrcpy( ret, classes[ 0 ]->getClassName() );
  607. for( U32 i = 1; i < classes.size(); i ++ )
  608. {
  609. dStrcat( ret, "\t" );
  610. dStrcat( ret, classes[ i ]->getClassName() );
  611. }
  612. return ret;
  613. }
  614. //------------------------------------------------------------------------------
  615. DefineEngineFunction( isClass, bool, ( const char* identifier ),,
  616. "@brief Returns true if the passed identifier is the name of a declared class.\n\n"
  617. "@ingroup Console")
  618. {
  619. AbstractClassRep* rep = AbstractClassRep::findClassRep( identifier );
  620. return rep != NULL;
  621. }
  622. DefineEngineFunction( isMemberOfClass, bool, ( const char* className, const char* superClassName ),,
  623. "@brief Returns true if the class is derived from the super class.\n\n"
  624. "If either class doesn't exist this returns false.\n"
  625. "@param className The class name.\n"
  626. "@param superClassName The super class to look for.\n"
  627. "@ingroup Console")
  628. {
  629. AbstractClassRep *pRep = AbstractClassRep::findClassRep( className );
  630. while (pRep)
  631. {
  632. if( !dStricmp( pRep->getClassName(), superClassName ) )
  633. return true;
  634. pRep = pRep->getParentClass();
  635. }
  636. return false;
  637. }
  638. DefineEngineFunction( getDescriptionOfClass, const char*, ( const char* className ),,
  639. "@brief Returns the description string for the named class.\n\n"
  640. "@param className The name of the class.\n"
  641. "@return The class description in string format.\n"
  642. "@ingroup Console")
  643. {
  644. AbstractClassRep* rep = AbstractClassRep::findClassRep( className );
  645. if( rep )
  646. return rep->getDescription();
  647. Con::errorf( "getDescriptionOfClass - no class called '%s'", className );
  648. return "";
  649. }
  650. DefineEngineFunction( getCategoryOfClass, const char*, ( const char* className ),,
  651. "@brief Returns the category of the given class.\n\n"
  652. "@param className The name of the class.\n"
  653. "@ingroup Console")
  654. {
  655. AbstractClassRep* rep = AbstractClassRep::findClassRep( className );
  656. if( rep )
  657. return rep->getCategory();
  658. Con::errorf( "getCategoryOfClass - no class called '%s'", className );
  659. return "";
  660. }
  661. DefineEngineFunction( enumerateConsoleClasses, const char*, ( const char* className ), ( "" ),
  662. "@brief Returns a list of classes that derive from the named class.\n\n"
  663. "If the named class is omitted this dumps all the classes.\n"
  664. "@param className The optional base class name.\n"
  665. "@return A tab delimited list of classes.\n"
  666. "@ingroup Editors\n"
  667. "@internal")
  668. {
  669. AbstractClassRep *base = NULL;
  670. if(className && *className)
  671. {
  672. base = AbstractClassRep::findClassRep(className);
  673. if(!base)
  674. return "";
  675. }
  676. Vector<AbstractClassRep*> classes;
  677. U32 bufSize = 0;
  678. for(AbstractClassRep *rep = AbstractClassRep::getClassList(); rep; rep = rep->getNextClass())
  679. {
  680. if( !base || rep->isClass(base))
  681. {
  682. classes.push_back(rep);
  683. bufSize += dStrlen(rep->getClassName()) + 1;
  684. }
  685. }
  686. return returnClassList( classes, bufSize );
  687. }
  688. DefineEngineFunction( enumerateConsoleClassesByCategory, const char*, ( String category ),,
  689. "@brief Provide a list of classes that belong to the given category.\n\n"
  690. "@param category The category name.\n"
  691. "@return A tab delimited list of classes.\n"
  692. "@ingroup Editors\n"
  693. "@internal")
  694. {
  695. U32 categoryLength = category.length();
  696. U32 bufSize = 0;
  697. Vector< AbstractClassRep* > classes;
  698. for( AbstractClassRep* rep = AbstractClassRep::getClassList(); rep != NULL; rep = rep->getNextClass() )
  699. {
  700. const String& repCategory = rep->getCategory();
  701. if( repCategory.length() >= categoryLength
  702. && ( repCategory.compare( category, categoryLength, String::NoCase ) == 0 )
  703. && ( repCategory[ categoryLength ] == ' ' || repCategory[ categoryLength ] == '\0' ) )
  704. {
  705. classes.push_back( rep );
  706. bufSize += dStrlen( rep->getClassName() + 1 );
  707. }
  708. }
  709. return returnClassList( classes, bufSize );
  710. }
  711. DefineEngineFunction( dumpNetStats, void, (),,
  712. "@brief Dumps network statistics for each class to the console.\n\n"
  713. "The returned <i>avg</i>, <i>min</i> and <i>max</i> values are in bits sent per update. "
  714. "The <i>num</i> value is the total number of events collected.\n"
  715. "@note This method only works when TORQUE_NET_STATS is defined in torqueConfig.h.\n"
  716. "@ingroup Networking\n" )
  717. {
  718. #ifdef TORQUE_NET_STATS
  719. for (AbstractClassRep * rep = AbstractClassRep::getClassList(); rep; rep = rep->getNextClass())
  720. {
  721. if (rep->mNetStatPack.numEvents || rep->mNetStatUnpack.numEvents || rep->mNetStatWrite.numEvents || rep->mNetStatRead.numEvents)
  722. {
  723. Con::printf("class %s net info",rep->getClassName());
  724. if (rep->mNetStatPack.numEvents)
  725. Con::printf(" packUpdate: avg (%f), min (%i), max (%i), num (%i)",
  726. F32(rep->mNetStatPack.total)/F32(rep->mNetStatPack.numEvents),
  727. rep->mNetStatPack.min,
  728. rep->mNetStatPack.max,
  729. rep->mNetStatPack.numEvents);
  730. if (rep->mNetStatUnpack.numEvents)
  731. Con::printf(" unpackUpdate: avg (%f), min (%i), max (%i), num (%i)",
  732. F32(rep->mNetStatUnpack.total)/F32(rep->mNetStatUnpack.numEvents),
  733. rep->mNetStatUnpack.min,
  734. rep->mNetStatUnpack.max,
  735. rep->mNetStatUnpack.numEvents);
  736. if (rep->mNetStatWrite.numEvents)
  737. Con::printf(" write: avg (%f), min (%i), max (%i), num (%i)",
  738. F32(rep->mNetStatWrite.total)/F32(rep->mNetStatWrite.numEvents),
  739. rep->mNetStatWrite.min,
  740. rep->mNetStatWrite.max,
  741. rep->mNetStatWrite.numEvents);
  742. if (rep->mNetStatRead.numEvents)
  743. Con::printf(" read: avg (%f), min (%i), max (%i), num (%i)",
  744. F32(rep->mNetStatRead.total)/F32(rep->mNetStatRead.numEvents),
  745. rep->mNetStatRead.min,
  746. rep->mNetStatRead.max,
  747. rep->mNetStatRead.numEvents);
  748. S32 sum = 0;
  749. for (S32 i=0; i<32; i++)
  750. sum += rep->mDirtyMaskFrequency[i];
  751. if (sum)
  752. {
  753. Con::printf(" Mask bits:");
  754. for (S32 i=0; i<8; i++)
  755. {
  756. F32 avg0 = rep->mDirtyMaskFrequency[i] ? F32(rep->mDirtyMaskTotal[i])/F32(rep->mDirtyMaskFrequency[i]) : 0.0f;
  757. F32 avg8 = rep->mDirtyMaskFrequency[i+8] ? F32(rep->mDirtyMaskTotal[i+8])/F32(rep->mDirtyMaskFrequency[i+8]) : 0.0f;
  758. F32 avg16 = rep->mDirtyMaskFrequency[i+16] ? F32(rep->mDirtyMaskTotal[i+16])/F32(rep->mDirtyMaskFrequency[i+16]) : 0.0f;
  759. F32 avg24 = rep->mDirtyMaskFrequency[i+24] ? F32(rep->mDirtyMaskTotal[i+24])/F32(rep->mDirtyMaskFrequency[i+24]) : 0.0f;
  760. Con::printf(" %2i - %4i (%6.2f) %2i - %4i (%6.2f) %2i - %4i (%6.2f) %2i - %4i, (%6.2f)",
  761. i ,rep->mDirtyMaskFrequency[i],avg0,
  762. i+8 ,rep->mDirtyMaskFrequency[i+8],avg8,
  763. i+16,rep->mDirtyMaskFrequency[i+16],avg16,
  764. i+24,rep->mDirtyMaskFrequency[i+24],avg24);
  765. }
  766. }
  767. }
  768. rep->resetNetStats();
  769. }
  770. #endif
  771. }
  772. DefineEngineFunction( sizeof, S32, ( const char *objectOrClass ),,
  773. "@brief Determines the memory consumption of a class or object.\n\n"
  774. "@param objectOrClass The object or class being measured.\n"
  775. "@return Returns the total size of an object in bytes.\n"
  776. "@ingroup Debugging\n")
  777. {
  778. AbstractClassRep *acr = NULL;
  779. SimObject *obj = Sim::findObject(objectOrClass);
  780. if(obj)
  781. acr = obj->getClassRep();
  782. if(!acr)
  783. acr = AbstractClassRep::findClassRep(objectOrClass);
  784. if(acr)
  785. return acr->getSizeof();
  786. if(dStricmp("ConsoleObject", objectOrClass) == 0)
  787. return sizeof(ConsoleObject);
  788. Con::warnf("could not find a class rep for that object or class name.");
  789. return 0;
  790. }
  791. DefineEngineFunction(linkNamespaces, bool, ( String childNSName, String parentNSName ),,
  792. "@brief Links childNS to parentNS.\n\n"
  793. "Links childNS to parentNS, or nothing if parentNS is NULL.\n"
  794. "Will unlink the namespace from previous namespace if a parent already exists.\n"
  795. "@internal\n")
  796. {
  797. StringTableEntry childNSSTE = StringTable->insert(childNSName.c_str());
  798. StringTableEntry parentNSSTE = StringTable->insert(parentNSName.c_str());
  799. Namespace *childNS = Namespace::find(childNSSTE);
  800. Namespace *parentNS = Namespace::find(parentNSSTE);
  801. if (!childNS)
  802. {
  803. return false;
  804. }
  805. Namespace *currentParent = childNS->getParent();
  806. // Link to new NS if applicable
  807. if (currentParent != parentNS)
  808. {
  809. if (currentParent != NULL)
  810. {
  811. if (!childNS->unlinkClass(currentParent))
  812. {
  813. return false;
  814. }
  815. }
  816. if (parentNS != NULL)
  817. {
  818. return childNS->classLinkTo(parentNS);
  819. }
  820. }
  821. return true;
  822. }