consoleObject.cc 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2013 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "platform/platform.h"
  23. #include "console/consoleObject.h"
  24. #include "string/stringTable.h"
  25. #include "algorithm/crc.h"
  26. #include "console/console.h"
  27. #include "console/consoleInternal.h"
  28. #include "console/consoleTypeValidators.h"
  29. #include "math/mMath.h"
  30. AbstractClassRep * AbstractClassRep::classLinkList = NULL;
  31. static AbstractClassRep::FieldList sg_tempFieldList;
  32. U32 AbstractClassRep::NetClassCount [NetClassGroupsCount][NetClassTypesCount] = {{0, },};
  33. U32 AbstractClassRep::NetClassBitSize[NetClassGroupsCount][NetClassTypesCount] = {{0, },};
  34. AbstractClassRep ** AbstractClassRep::classTable[NetClassGroupsCount][NetClassTypesCount];
  35. U32 AbstractClassRep::classCRC[NetClassGroupsCount] = {INITIAL_CRC_VALUE, };
  36. bool AbstractClassRep::initialized = false;
  37. //--------------------------------------
  38. const AbstractClassRep::Field *AbstractClassRep::findField(StringTableEntry name) const
  39. {
  40. for(U32 i = 0; i < (U32)mFieldList.size(); i++)
  41. if(mFieldList[i].pFieldname == name)
  42. return &mFieldList[i];
  43. return NULL;
  44. }
  45. AbstractClassRep* AbstractClassRep::findClassRep(const char* in_pClassName)
  46. {
  47. AssertFatal(initialized,
  48. "AbstractClassRep::findClassRep() - Tried to find an AbstractClassRep before AbstractClassRep::initialize().");
  49. for (AbstractClassRep *walk = classLinkList; walk; walk = walk->nextClass)
  50. if (!dStrcmp(walk->getClassName(), in_pClassName))
  51. return walk;
  52. return NULL;
  53. }
  54. //--------------------------------------
  55. void AbstractClassRep::registerClassRep(AbstractClassRep* in_pRep)
  56. {
  57. AssertFatal(in_pRep != NULL, "AbstractClassRep::registerClassRep was passed a NULL pointer!");
  58. #ifdef TORQUE_DEBUG // assert if this class is already registered.
  59. for(AbstractClassRep *walk = classLinkList; walk; walk = walk->nextClass)
  60. {
  61. AssertFatal(dStrcmp(in_pRep->mClassName, walk->mClassName),
  62. "Duplicate class name registered in AbstractClassRep::registerClassRep()");
  63. }
  64. #endif
  65. in_pRep->nextClass = classLinkList;
  66. classLinkList = in_pRep;
  67. }
  68. //--------------------------------------
  69. ConsoleObject* AbstractClassRep::create(const char* in_pClassName)
  70. {
  71. AssertFatal(initialized,
  72. "AbstractClassRep::create() - Tried to create an object before AbstractClassRep::initialize().");
  73. const AbstractClassRep *rep = AbstractClassRep::findClassRep(in_pClassName);
  74. if(rep)
  75. return rep->create();
  76. AssertWarn(0, avar("Couldn't find class rep for dynamic class: %s", in_pClassName));
  77. return NULL;
  78. }
  79. //--------------------------------------
  80. ConsoleObject* AbstractClassRep::create(const U32 groupId, const U32 typeId, const U32 in_classId)
  81. {
  82. AssertFatal(initialized,
  83. "AbstractClassRep::create() - Tried to create an object before AbstractClassRep::initialize().");
  84. AssertFatal(in_classId < NetClassCount[groupId][typeId],
  85. "AbstractClassRep::create() - Class id out of range.");
  86. AssertFatal(classTable[groupId][typeId][in_classId] != NULL,
  87. "AbstractClassRep::create() - No class with requested ID type.");
  88. // Look up the specified class and create it.
  89. if(classTable[groupId][typeId][in_classId])
  90. return classTable[groupId][typeId][in_classId]->create();
  91. return NULL;
  92. }
  93. //--------------------------------------
  94. static S32 QSORT_CALLBACK ACRCompare(const void *aptr, const void *bptr)
  95. {
  96. const AbstractClassRep *a = *((const AbstractClassRep **) aptr);
  97. const AbstractClassRep *b = *((const AbstractClassRep **) bptr);
  98. if(a->mClassType != b->mClassType)
  99. return a->mClassType - b->mClassType;
  100. return dStrcmp(a->getClassName(), b->getClassName());
  101. }
  102. void AbstractClassRep::initialize()
  103. {
  104. AssertFatal(!initialized, "Duplicate call to AbstractClassRep::initialize()!");
  105. Vector<AbstractClassRep *> dynamicTable(__FILE__, __LINE__);
  106. AbstractClassRep *walk;
  107. // Initialize namespace references...
  108. for (walk = classLinkList; walk; walk = walk->nextClass)
  109. {
  110. walk->mNamespace = Con::lookupNamespace(StringTable->insert(walk->getClassName()));
  111. walk->mNamespace->mClassRep = walk;
  112. }
  113. // Initialize field lists... (and perform other console registration).
  114. for (walk = classLinkList; walk; walk = walk->nextClass)
  115. {
  116. // sg_tempFieldList is used as a staging area for field lists
  117. // (see addField, addGroup, etc.)
  118. sg_tempFieldList.setSize(0);
  119. walk->init();
  120. // So if we have things in it, copy it over...
  121. if (sg_tempFieldList.size() != 0)
  122. {
  123. if( !walk->mFieldList.size())
  124. walk->mFieldList = sg_tempFieldList;
  125. else
  126. destroyFieldValidators( sg_tempFieldList );
  127. }
  128. // And of course delete it every round.
  129. sg_tempFieldList.clear();
  130. }
  131. // Calculate counts and bit sizes for the various NetClasses.
  132. for (U32 group = 0; group < NetClassGroupsCount; group++)
  133. {
  134. U32 groupMask = 1 << group;
  135. // Specifically, for each NetClass of each NetGroup...
  136. for(U32 type = 0; type < NetClassTypesCount; type++)
  137. {
  138. // Go through all the classes and find matches...
  139. for (walk = classLinkList; walk; walk = walk->nextClass)
  140. {
  141. if(walk->mClassType == type && walk->mClassGroupMask & groupMask)
  142. dynamicTable.push_back(walk);
  143. }
  144. // Set the count for this NetGroup and NetClass
  145. NetClassCount[group][type] = dynamicTable.size();
  146. if(!NetClassCount[group][type])
  147. continue; // If no classes matched, skip to next.
  148. // Sort by type and then by name.
  149. dQsort((void *)dynamicTable.address(), dynamicTable.size(), sizeof(AbstractClassRep *), ACRCompare);
  150. // Allocate storage in the classTable
  151. classTable[group][type] = new AbstractClassRep*[NetClassCount[group][type]];
  152. // Fill this in and assign class ids for this group.
  153. for(U32 i = 0; i < NetClassCount[group][type];i++)
  154. {
  155. classTable[group][type][i] = dynamicTable[i];
  156. dynamicTable[i]->mClassId[group] = i;
  157. }
  158. // And calculate the size of bitfields for this group and type.
  159. NetClassBitSize[group][type] =
  160. getBinLog2(getNextPow2(NetClassCount[group][type] + 1));
  161. dynamicTable.clear();
  162. }
  163. }
  164. // Ok, we're golden!
  165. initialized = true;
  166. }
  167. void AbstractClassRep::destroyFieldValidators( AbstractClassRep::FieldList &mFieldList )
  168. {
  169. for(S32 i = mFieldList.size()-1; i>=0; i-- )
  170. {
  171. ConsoleTypeValidator **p = &mFieldList[i].validator;
  172. if( *p )
  173. {
  174. delete *p;
  175. *p = NULL;
  176. }
  177. }
  178. }
  179. //------------------------------------------------------------------------------
  180. //-------------------------------------- ConsoleObject
  181. char replacebuf[1024];
  182. char* suppressSpaces(const char* in_pname)
  183. {
  184. U32 i = 0;
  185. char chr;
  186. do
  187. {
  188. chr = in_pname[i];
  189. replacebuf[i++] = (chr != 32) ? chr : '_';
  190. } while(chr);
  191. return replacebuf;
  192. }
  193. void ConsoleObject::addGroup(const char* in_pGroupname, const char* in_pGroupDocs)
  194. {
  195. // Remove spaces.
  196. char* pFieldNameBuf = suppressSpaces(in_pGroupname);
  197. // Append group type to fieldname.
  198. dStrcat(pFieldNameBuf, "_begingroup");
  199. // Create Field.
  200. AbstractClassRep::Field f;
  201. f.pFieldname = StringTable->insert(pFieldNameBuf);
  202. f.pGroupname = StringTable->insert(in_pGroupname);
  203. if(in_pGroupDocs)
  204. f.pFieldDocs = StringTable->insert(in_pGroupDocs);
  205. else
  206. f.pFieldDocs = NULL;
  207. f.type = AbstractClassRep::StartGroupFieldType;
  208. f.elementCount = 0;
  209. f.groupExpand = false;
  210. f.validator = NULL;
  211. f.setDataFn = &defaultProtectedSetFn;
  212. f.getDataFn = &defaultProtectedGetFn;
  213. f.writeDataFn = &defaultProtectedWriteFn;
  214. // Add to field list.
  215. sg_tempFieldList.push_back(f);
  216. }
  217. void ConsoleObject::endGroup(const char* in_pGroupname)
  218. {
  219. // Remove spaces.
  220. char* pFieldNameBuf = suppressSpaces(in_pGroupname);
  221. // Append group type to fieldname.
  222. dStrcat(pFieldNameBuf, "_endgroup");
  223. // Create Field.
  224. AbstractClassRep::Field f;
  225. f.pFieldname = StringTable->insert(pFieldNameBuf);
  226. f.pGroupname = StringTable->insert(in_pGroupname);
  227. f.pFieldDocs = NULL;
  228. f.type = AbstractClassRep::EndGroupFieldType;
  229. f.groupExpand = false;
  230. f.validator = NULL;
  231. f.setDataFn = &defaultProtectedSetFn;
  232. f.getDataFn = &defaultProtectedGetFn;
  233. f.writeDataFn = &defaultProtectedWriteFn;
  234. f.elementCount = 0;
  235. // Add to field list.
  236. sg_tempFieldList.push_back(f);
  237. }
  238. void ConsoleObject::addField(const char* in_pFieldname,
  239. const U32 in_fieldType,
  240. const dsize_t in_fieldOffset,
  241. const char* in_pFieldDocs)
  242. {
  243. addField(
  244. in_pFieldname,
  245. in_fieldType,
  246. in_fieldOffset,
  247. &defaultProtectedWriteFn,
  248. 1,
  249. NULL,
  250. in_pFieldDocs);
  251. }
  252. void ConsoleObject::addField(const char* in_pFieldname,
  253. const U32 in_fieldType,
  254. const dsize_t in_fieldOffset,
  255. AbstractClassRep::WriteDataNotify in_writeDataFn,
  256. const char* in_pFieldDocs)
  257. {
  258. addField(
  259. in_pFieldname,
  260. in_fieldType,
  261. in_fieldOffset,
  262. in_writeDataFn,
  263. 1,
  264. NULL,
  265. in_pFieldDocs);
  266. }
  267. void ConsoleObject::addField(const char* in_pFieldname,
  268. const U32 in_fieldType,
  269. const dsize_t in_fieldOffset,
  270. const U32 in_elementCount,
  271. EnumTable *in_table,
  272. const char* in_pFieldDocs)
  273. {
  274. addField(
  275. in_pFieldname,
  276. in_fieldType,
  277. in_fieldOffset,
  278. &defaultProtectedWriteFn,
  279. 1,
  280. in_table,
  281. in_pFieldDocs);
  282. }
  283. void ConsoleObject::addField(const char* in_pFieldname,
  284. const U32 in_fieldType,
  285. const dsize_t in_fieldOffset,
  286. AbstractClassRep::WriteDataNotify in_writeDataFn,
  287. const U32 in_elementCount,
  288. EnumTable *in_table,
  289. const char* in_pFieldDocs)
  290. {
  291. AbstractClassRep::Field f;
  292. f.pFieldname = StringTable->insert(in_pFieldname);
  293. f.pGroupname = NULL;
  294. if(in_pFieldDocs)
  295. f.pFieldDocs = StringTable->insert(in_pFieldDocs);
  296. else
  297. f.pFieldDocs = NULL;
  298. f.type = in_fieldType;
  299. f.offset = in_fieldOffset;
  300. f.elementCount = in_elementCount;
  301. f.table = in_table;
  302. f.validator = NULL;
  303. f.setDataFn = &defaultProtectedSetFn;
  304. f.getDataFn = &defaultProtectedGetFn;
  305. f.writeDataFn = in_writeDataFn;
  306. sg_tempFieldList.push_back(f);
  307. }
  308. void ConsoleObject::addProtectedField(const char* in_pFieldname,
  309. const U32 in_fieldType,
  310. const dsize_t in_fieldOffset,
  311. AbstractClassRep::SetDataNotify in_setDataFn,
  312. AbstractClassRep::GetDataNotify in_getDataFn,
  313. const char* in_pFieldDocs)
  314. {
  315. addProtectedField(
  316. in_pFieldname,
  317. in_fieldType,
  318. in_fieldOffset,
  319. in_setDataFn,
  320. in_getDataFn,
  321. &defaultProtectedWriteFn,
  322. 1,
  323. NULL,
  324. in_pFieldDocs);
  325. }
  326. void ConsoleObject::addProtectedField(const char* in_pFieldname,
  327. const U32 in_fieldType,
  328. const dsize_t in_fieldOffset,
  329. AbstractClassRep::SetDataNotify in_setDataFn,
  330. AbstractClassRep::GetDataNotify in_getDataFn,
  331. AbstractClassRep::WriteDataNotify in_writeDataFn,
  332. const char* in_pFieldDocs)
  333. {
  334. addProtectedField(
  335. in_pFieldname,
  336. in_fieldType,
  337. in_fieldOffset,
  338. in_setDataFn,
  339. in_getDataFn,
  340. in_writeDataFn,
  341. 1,
  342. NULL,
  343. in_pFieldDocs);
  344. }
  345. void ConsoleObject::addProtectedField(const char* in_pFieldname,
  346. const U32 in_fieldType,
  347. const dsize_t in_fieldOffset,
  348. AbstractClassRep::SetDataNotify in_setDataFn,
  349. AbstractClassRep::GetDataNotify in_getDataFn,
  350. const U32 in_elementCount,
  351. EnumTable *in_table,
  352. const char* in_pFieldDocs)
  353. {
  354. addProtectedField(
  355. in_pFieldname,
  356. in_fieldType,
  357. in_fieldOffset,
  358. in_setDataFn,
  359. in_getDataFn,
  360. &defaultProtectedWriteFn,
  361. in_elementCount,
  362. in_table,
  363. in_pFieldDocs);
  364. }
  365. void ConsoleObject::addProtectedField(const char* in_pFieldname,
  366. const U32 in_fieldType,
  367. const dsize_t in_fieldOffset,
  368. AbstractClassRep::SetDataNotify in_setDataFn,
  369. AbstractClassRep::GetDataNotify in_getDataFn,
  370. AbstractClassRep::WriteDataNotify in_writeDataFn,
  371. const U32 in_elementCount,
  372. EnumTable *in_table,
  373. const char* in_pFieldDocs)
  374. {
  375. AbstractClassRep::Field f;
  376. f.pFieldname = StringTable->insert(in_pFieldname);
  377. f.pGroupname = NULL;
  378. if(in_pFieldDocs)
  379. f.pFieldDocs = StringTable->insert(in_pFieldDocs);
  380. else
  381. f.pFieldDocs = NULL;
  382. f.type = in_fieldType;
  383. f.offset = in_fieldOffset;
  384. f.elementCount = in_elementCount;
  385. f.table = in_table;
  386. f.validator = NULL;
  387. f.setDataFn = in_setDataFn;
  388. f.getDataFn = in_getDataFn;
  389. f.writeDataFn = in_writeDataFn;
  390. sg_tempFieldList.push_back(f);
  391. }
  392. void ConsoleObject::addFieldV(const char* in_pFieldname,
  393. const U32 in_fieldType,
  394. const dsize_t in_fieldOffset,
  395. ConsoleTypeValidator *v,
  396. const char* in_pFieldDocs)
  397. {
  398. AbstractClassRep::Field f;
  399. f.pFieldname = StringTable->insert(in_pFieldname);
  400. f.pGroupname = NULL;
  401. if(in_pFieldDocs)
  402. f.pFieldDocs = StringTable->insert(in_pFieldDocs);
  403. else
  404. f.pFieldDocs = NULL;
  405. f.type = in_fieldType;
  406. f.offset = in_fieldOffset;
  407. f.elementCount = 1;
  408. f.table = NULL;
  409. f.setDataFn = &defaultProtectedSetFn;
  410. f.getDataFn = &defaultProtectedGetFn;
  411. f.writeDataFn = &defaultProtectedWriteFn;
  412. f.validator = v;
  413. v->fieldIndex = sg_tempFieldList.size();
  414. sg_tempFieldList.push_back(f);
  415. }
  416. void ConsoleObject::addDepricatedField(const char *fieldName)
  417. {
  418. AbstractClassRep::Field f;
  419. f.pFieldname = StringTable->insert(fieldName);
  420. f.pGroupname = NULL;
  421. f.pFieldDocs = NULL;
  422. f.type = AbstractClassRep::DepricatedFieldType;
  423. f.offset = 0;
  424. f.elementCount = 0;
  425. f.table = NULL;
  426. f.validator = NULL;
  427. f.setDataFn = &defaultProtectedSetFn;
  428. f.getDataFn = &defaultProtectedGetFn;
  429. f.writeDataFn = &defaultProtectedWriteFn;
  430. sg_tempFieldList.push_back(f);
  431. }
  432. bool ConsoleObject::removeField(const char* in_pFieldname)
  433. {
  434. for (U32 i = 0; i < (U32)sg_tempFieldList.size(); i++) {
  435. if (dStricmp(in_pFieldname, sg_tempFieldList[i].pFieldname) == 0) {
  436. sg_tempFieldList.erase(i);
  437. return true;
  438. }
  439. }
  440. return false;
  441. }
  442. //--------------------------------------
  443. void ConsoleObject::initPersistFields()
  444. {
  445. }
  446. //--------------------------------------
  447. void ConsoleObject::consoleInit()
  448. {
  449. }
  450. ConsoleObject::~ConsoleObject()
  451. {
  452. }
  453. //--------------------------------------
  454. AbstractClassRep* ConsoleObject::getClassRep() const
  455. {
  456. return NULL;
  457. }
  458. ConsoleFunction( enumerateConsoleClasses, const char*, 1, 2, "enumerateConsoleClasses(<\"base class\">);")
  459. {
  460. AbstractClassRep *base = NULL;
  461. if(argc > 1)
  462. {
  463. base = AbstractClassRep::findClassRep(argv[1]);
  464. if(!base)
  465. return "";
  466. }
  467. Vector<AbstractClassRep*> classes;
  468. U32 bufSize = 0;
  469. for(AbstractClassRep *rep = AbstractClassRep::getClassList(); rep; rep = rep->getNextClass())
  470. {
  471. if( !base || rep->isClass(base))
  472. {
  473. classes.push_back(rep);
  474. bufSize += dStrlen(rep->getClassName()) + 1;
  475. }
  476. }
  477. if(!classes.size())
  478. return "";
  479. dQsort(classes.address(), classes.size(), sizeof(AbstractClassRep*), ACRCompare);
  480. char* ret = Con::getReturnBuffer(bufSize);
  481. dStrcpy( ret, classes[0]->getClassName());
  482. for( U32 i=0; i< (U32)classes.size(); i++)
  483. {
  484. dStrcat( ret, "\t" );
  485. dStrcat( ret, classes[i]->getClassName() );
  486. }
  487. return ret;
  488. }