consoleObject.h 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869
  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. #ifndef _CONSOLEOBJECT_H_
  23. #define _CONSOLEOBJECT_H_
  24. #ifndef _STRINGTABLE_H_
  25. #include "string/stringTable.h"
  26. #endif
  27. #ifndef _PLATFORM_H_
  28. #include "platform/platform.h"
  29. #endif
  30. #ifndef _VECTOR_H_
  31. #include "collection/vector.h"
  32. #endif
  33. #ifndef _BITSET_H_
  34. #include "collection/bitSet.h"
  35. #endif
  36. #ifndef _CONSOLE_H_
  37. #include "console/console.h"
  38. #endif
  39. class Namespace;
  40. class ConsoleObject;
  41. enum NetClassTypes {
  42. NetClassTypeObject = 0,
  43. NetClassTypeDataBlock,
  44. NetClassTypeEvent,
  45. NetClassTypesCount,
  46. };
  47. enum NetClassGroups {
  48. NetClassGroupGame = 0,
  49. NetClassGroupCommunity,
  50. NetClassGroup3,
  51. NetClassGroup4,
  52. NetClassGroupsCount,
  53. };
  54. enum NetClassMasks {
  55. NetClassGroupGameMask = BIT(NetClassGroupGame),
  56. NetClassGroupCommunityMask = BIT(NetClassGroupCommunity),
  57. };
  58. enum NetDirection
  59. {
  60. NetEventDirAny,
  61. NetEventDirServerToClient,
  62. NetEventDirClientToServer,
  63. };
  64. class SimObject;
  65. class ConsoleTypeValidator;
  66. /// Core functionality for class manipulation.
  67. ///
  68. /// @section AbstractClassRep_intro Introduction (or, Why AbstractClassRep?)
  69. ///
  70. /// Many of Torque's subsystems, especially network, console, and sim,
  71. /// require the ability to programatically instantiate classes. For instance,
  72. /// when objects are ghosted, the networking layer needs to be able to create
  73. /// an instance of the object on the client. When the console scripting
  74. /// language runtime encounters the "new" keyword, it has to be able to fill
  75. /// that request.
  76. ///
  77. /// Since standard C++ doesn't provide a function to create a new instance of
  78. /// an arbitrary class at runtime, one must be created. This is what
  79. /// AbstractClassRep and ConcreteClassRep are all about. They allow the registration
  80. /// and instantiation of arbitrary classes at runtime.
  81. ///
  82. /// In addition, ACR keeps track of the fields (registered via addField() and co.) of
  83. /// a class, allowing programmatic access of class fields.
  84. ///
  85. /// @see ConsoleObject
  86. ///
  87. /// @note In general, you will only access the functionality implemented in this class via
  88. /// ConsoleObject::create(). Most of the time, you will only ever need to use this part
  89. /// part of the engine indirectly - ie, you will use the networking system or the console,
  90. /// or ConsoleObject, and they will indirectly use this code. <b>The following discussion
  91. /// is really only relevant for advanced engine users.</b>
  92. ///
  93. /// @section AbstractClassRep_netstuff NetClasses and Class IDs
  94. ///
  95. /// Torque supports a notion of group, type, and direction for objects passed over
  96. /// the network. Class IDs are assigned sequentially per-group, per-type, so that, for instance,
  97. /// the IDs assigned to Datablocks are seperate from the IDs assigned to NetObjects or NetEvents.
  98. /// This can translate into significant bandwidth savings (especially since the size of the fields
  99. /// for transmitting these bits are determined at run-time based on the number of IDs given out.
  100. ///
  101. /// @section AbstractClassRep_details AbstractClassRep Internals
  102. ///
  103. /// Much like ConsoleConstructor, ACR does some preparatory work at runtime before execution
  104. /// is passed to main(). In actual fact, this preparatory work is done by the ConcreteClassRep
  105. /// template. Let's examine this more closely.
  106. ///
  107. /// If we examine ConsoleObject, we see that two macros must be used in the definition of a
  108. /// properly integrated objects. From the ConsoleObject example:
  109. ///
  110. /// @code
  111. /// // This is from inside the class definition...
  112. /// DECLARE_CONOBJECT(TorqueObject);
  113. ///
  114. /// // And this is from outside the class definition...
  115. /// IMPLEMENT_CONOBJECT(TorqueObject);
  116. /// @endcode
  117. ///
  118. /// What do these things actually do?
  119. ///
  120. /// Not all that much, in fact. They expand to code something like this:
  121. ///
  122. /// @code
  123. /// // This is from inside the class definition...
  124. /// static ConcreteClassRep<TorqueObject> dynClassRep;
  125. /// static AbstractClassRep* getParentStaticClassRep();
  126. /// static AbstractClassRep* getStaticClassRep();
  127. /// virtual AbstractClassRep* getClassRep() const;
  128. /// @endcode
  129. ///
  130. /// @code
  131. /// // And this is from outside the class definition...
  132. /// AbstractClassRep* TorqueObject::getClassRep() const { return &TorqueObject::dynClassRep; }
  133. /// AbstractClassRep* TorqueObject::getStaticClassRep() { return &dynClassRep; }
  134. /// AbstractClassRep* TorqueObject::getParentStaticClassRep() { return Parent::getStaticClassRep(); }
  135. /// ConcreteClassRep<TorqueObject> TorqueObject::dynClassRep("TorqueObject", 0, -1, 0);
  136. /// @endcode
  137. ///
  138. /// As you can see, getClassRep(), getStaticClassRep(), and getParentStaticClassRep() are just
  139. /// accessors to allow access to various ConcreteClassRep instances. This is where the Parent
  140. /// typedef comes into play as well - it lets getParentStaticClassRep() get the right
  141. /// class rep.
  142. ///
  143. /// In addition, dynClassRep is declared as a member of TorqueObject, and defined later
  144. /// on. Much like ConsoleConstructor, ConcreteClassReps add themselves to a global linked
  145. /// list in their constructor.
  146. ///
  147. /// Then, when AbstractClassRep::initialize() is called, from Con::init(), we iterate through
  148. /// the list and perform the following tasks:
  149. /// - Sets up a Namespace for each class.
  150. /// - Call the init() method on each ConcreteClassRep. This method:
  151. /// - Links namespaces between parent and child classes, using Con::classLinkNamespaces.
  152. /// - Calls initPersistFields() and consoleInit().
  153. /// - As a result of calling initPersistFields, the field list for the class is populated.
  154. /// - Assigns network IDs for classes based on their NetGroup membership. Determines
  155. /// bit allocations for network ID fields.
  156. ///
  157. /// @nosubgrouping
  158. class AbstractClassRep
  159. {
  160. friend class ConsoleObject;
  161. public:
  162. /// @name 'Tructors
  163. /// @{
  164. AbstractClassRep()
  165. {
  166. VECTOR_SET_ASSOCIATION(mFieldList);
  167. parentClass = NULL;
  168. }
  169. virtual ~AbstractClassRep() { }
  170. /// @}
  171. /// @name Representation Interface
  172. /// @{
  173. S32 mClassGroupMask; ///< Mask indicating in which NetGroups this object belongs.
  174. S32 mClassType; ///< Stores the NetClass of this class.
  175. S32 mNetEventDir; ///< Stores the NetDirection of this class.
  176. S32 mClassId[NetClassGroupsCount]; ///< Stores the IDs assigned to this class for each group.
  177. S32 getClassId (U32 netClassGroup) const;
  178. static U32 getClassCRC (U32 netClassGroup);
  179. const char* getClassName() const;
  180. static AbstractClassRep* getClassList();
  181. Namespace* getNameSpace();
  182. AbstractClassRep* getNextClass();
  183. AbstractClassRep* getParentClass();
  184. virtual AbstractClassRep* getContainerChildClass() = 0;
  185. /// Helper class to see if we are a given class, or a subclass thereof.
  186. bool isClass(AbstractClassRep *acr)
  187. {
  188. AbstractClassRep *walk = this;
  189. // Walk up parents, checking for equivalence.
  190. while(walk)
  191. {
  192. if(walk == acr)
  193. return true;
  194. walk = walk->parentClass;
  195. };
  196. return false;
  197. }
  198. virtual ConsoleObject* create () const = 0;
  199. protected:
  200. virtual void init() const = 0;
  201. const char * mClassName;
  202. AbstractClassRep * nextClass;
  203. AbstractClassRep * parentClass;
  204. Namespace * mNamespace;
  205. /// @}
  206. /// @name Fields
  207. /// @{
  208. public:
  209. /// This is a function pointer typedef to support get/set callbacks for fields
  210. typedef bool (*SetDataNotify)( void *obj, const char *data );
  211. typedef const char *(*GetDataNotify)( void *obj, const char *data );
  212. /// This is a function pointer typedef to support optional writing for fields.
  213. typedef bool (*WriteDataNotify)( void* obj, const char* pFieldName );
  214. enum ACRFieldTypes
  215. {
  216. StartGroupFieldType = 0xFFFFFFFD,
  217. EndGroupFieldType = 0xFFFFFFFE,
  218. DepricatedFieldType = 0xFFFFFFFF
  219. };
  220. struct Field {
  221. const char* pFieldname; ///< Name of the field.
  222. const char* pGroupname; ///< Optionally filled field containing the group name.
  223. ///
  224. /// This is filled when type is StartField or EndField
  225. const char* pFieldDocs; ///< Documentation about this field; see consoleDoc.cc.
  226. bool groupExpand; ///< Flag to track expanded/not state of this group in the editor.
  227. U32 type; ///< A type ID. @see ACRFieldTypes
  228. U32 offset; ///< Memory offset from beginning of class for this field.
  229. S32 elementCount; ///< Number of elements, if this is an array.
  230. EnumTable * table; ///< If this is an enum, this points to the table defining it.
  231. BitSet32 flag; ///< Stores various flags
  232. ConsoleTypeValidator *validator; ///< Validator, if any.
  233. SetDataNotify setDataFn; ///< Set data notify Fn
  234. GetDataNotify getDataFn; ///< Get data notify Fn
  235. WriteDataNotify writeDataFn; ///< Function to determine whether data should be written or not.
  236. };
  237. typedef Vector<Field> FieldList;
  238. FieldList mFieldList;
  239. bool mDynamicGroupExpand;
  240. const Field *findField(StringTableEntry fieldName) const;
  241. /// @}
  242. /// @name Abstract Class Database
  243. /// @{
  244. protected:
  245. static AbstractClassRep ** classTable[NetClassGroupsCount][NetClassTypesCount];
  246. static AbstractClassRep * classLinkList;
  247. static U32 classCRC[NetClassGroupsCount];
  248. static bool initialized;
  249. static ConsoleObject* create(const char* in_pClassName);
  250. static ConsoleObject* create(const U32 groupId, const U32 typeId, const U32 in_classId);
  251. public:
  252. static U32 NetClassCount [NetClassGroupsCount][NetClassTypesCount];
  253. static U32 NetClassBitSize[NetClassGroupsCount][NetClassTypesCount];
  254. static void registerClassRep(AbstractClassRep*);
  255. static AbstractClassRep* findClassRep(const char* in_pClassName);
  256. static void initialize(); // Called from Con::init once on startup
  257. static void destroyFieldValidators(AbstractClassRep::FieldList &mFieldList);
  258. /// @}
  259. };
  260. inline AbstractClassRep *AbstractClassRep::getClassList()
  261. {
  262. return classLinkList;
  263. }
  264. inline U32 AbstractClassRep::getClassCRC(U32 group)
  265. {
  266. return classCRC[group];
  267. }
  268. inline AbstractClassRep *AbstractClassRep::getNextClass()
  269. {
  270. return nextClass;
  271. }
  272. inline AbstractClassRep *AbstractClassRep::getParentClass()
  273. {
  274. return parentClass;
  275. }
  276. inline S32 AbstractClassRep::getClassId(U32 group) const
  277. {
  278. return mClassId[group];
  279. }
  280. inline const char* AbstractClassRep::getClassName() const
  281. {
  282. return mClassName;
  283. }
  284. inline Namespace *AbstractClassRep::getNameSpace()
  285. {
  286. return mNamespace;
  287. }
  288. //------------------------------------------------------------------------------
  289. //-------------------------------------- ConcreteClassRep
  290. //
  291. /// Helper class for AbstractClassRep.
  292. ///
  293. /// @see AbtractClassRep
  294. /// @see ConsoleObject
  295. template <class T>
  296. class ConcreteClassRep : public AbstractClassRep
  297. {
  298. public:
  299. ConcreteClassRep(const char *name, S32 netClassGroupMask, S32 netClassType, S32 netEventDir, AbstractClassRep *parent )
  300. {
  301. // name is a static compiler string so no need to worry about copying or deleting
  302. mClassName = name;
  303. // Clean up mClassId
  304. for(U32 i = 0; i < NetClassGroupsCount; i++)
  305. mClassId[i] = -1;
  306. // Set properties for this ACR
  307. mClassType = netClassType;
  308. mClassGroupMask = netClassGroupMask;
  309. mNetEventDir = netEventDir;
  310. parentClass = parent;
  311. // Finally, register ourselves.
  312. registerClassRep(this);
  313. };
  314. virtual AbstractClassRep* getContainerChildClass()
  315. {
  316. // Fetch container children type.
  317. AbstractClassRep* pChildren = T::getContainerChildStaticClassRep();
  318. if ( pChildren != NULL )
  319. return pChildren;
  320. // Fetch parent type.
  321. AbstractClassRep* pParent = T::getParentStaticClassRep();
  322. if ( pParent == NULL )
  323. return NULL;
  324. // Get parent container children.
  325. return pParent->getContainerChildClass();
  326. }
  327. /// Perform class specific initialization tasks.
  328. ///
  329. /// Link namespaces, call initPersistFields() and consoleInit().
  330. void init() const
  331. {
  332. // Get handle to our parent class, if any, and ourselves (we are our parent's child).
  333. AbstractClassRep *parent = T::getParentStaticClassRep();
  334. AbstractClassRep *child = T::getStaticClassRep();
  335. // If we got reps, then link those namespaces! (To get proper inheritance.)
  336. if(parent && child)
  337. Con::classLinkNamespaces(parent->getNameSpace(), child->getNameSpace());
  338. // Finally, do any class specific initialization...
  339. T::initPersistFields();
  340. T::consoleInit();
  341. }
  342. /// Wrap constructor.
  343. ConsoleObject* create() const { return new T; }
  344. };
  345. //------------------------------------------------------------------------------
  346. // Forward declarations so they can be used in the class
  347. const char *defaultProtectedGetFn( void *obj, const char *data );
  348. bool defaultProtectedWriteFn( void* obj, StringTableEntry pFieldName );
  349. /// Interface class to the console.
  350. ///
  351. /// @section ConsoleObject_basics The Basics
  352. ///
  353. /// Any object which you want to work with the console system should derive from this,
  354. /// and access functionality through the static interface.
  355. ///
  356. /// This class is always used with the DECLARE_CONOBJECT and IMPLEMENT_* macros.
  357. ///
  358. /// @code
  359. /// // A very basic example object. It will do nothing!
  360. /// class TorqueObject : public ConsoleObject {
  361. /// // Must provide a Parent typedef so the console system knows what we inherit from.
  362. /// typedef ConsoleObject Parent;
  363. ///
  364. /// // This does a lot of menial declaration for you.
  365. /// DECLARE_CONOBJECT(TorqueObject);
  366. ///
  367. /// // This is for us to register our fields in.
  368. /// static void initPersistFields();
  369. ///
  370. /// // A sample field.
  371. /// S8 mSample;
  372. /// }
  373. /// @endcode
  374. ///
  375. /// @code
  376. /// // And the accordant implementation...
  377. /// IMPLEMENT_CONOBJECT(TorqueObject);
  378. ///
  379. /// void TorqueObject::initPersistFields()
  380. /// {
  381. /// // If you want to inherit any fields from the parent (you do), do this:
  382. /// Parent::initPersistFields();
  383. ///
  384. /// // Pass the field, the type, the offset, and a usage string.
  385. /// addField("sample", TypeS8, Offset(mSample, TorqueObject), "A test field.");
  386. /// }
  387. /// @endcode
  388. ///
  389. /// That's all you need to do to get a class registered with the console system. At this point,
  390. /// you can instantiate it via script, tie methods to it using ConsoleMethod, register fields,
  391. /// and so forth. You can also register any global variables related to the class by creating
  392. /// a consoleInit() method.
  393. ///
  394. /// You will need to use different IMPLEMENT_ macros in different cases; for instance, if you
  395. /// are making a NetObject (for ghosting), a DataBlock, or a NetEvent.
  396. ///
  397. /// @see AbstractClassRep for gory implementation details.
  398. /// @nosubgrouping
  399. class ConsoleObject
  400. {
  401. protected:
  402. /// @deprecated This is disallowed.
  403. ConsoleObject() { /* disallowed */ }
  404. /// @deprecated This is disallowed.
  405. ConsoleObject(const ConsoleObject&);
  406. public:
  407. /// Get a reference to a field by name.
  408. const AbstractClassRep::Field* findField(StringTableEntry fieldName) const;
  409. /// Gets the ClassRep.
  410. virtual AbstractClassRep* getClassRep() const;
  411. /// Set the value of a field.
  412. bool setField(const char *fieldName, const char *value);
  413. virtual ~ConsoleObject();
  414. public:
  415. /// @name Object Creation
  416. /// @{
  417. static ConsoleObject* create(const char* in_pClassName);
  418. static ConsoleObject* create(const U32 groupId, const U32 typeId, const U32 in_classId);
  419. /// @}
  420. public:
  421. /// Get the classname from a class tag.
  422. static const char* lookupClassName(const U32 in_classTag);
  423. protected:
  424. /// @name Fields
  425. /// @{
  426. /// Mark the beginning of a group of fields.
  427. ///
  428. /// This is used in the consoleDoc system.
  429. /// @see console_autodoc
  430. static void addGroup(const char* in_pGroupname, const char* in_pGroupDocs = NULL);
  431. /// Mark the end of a group of fields.
  432. ///
  433. /// This is used in the consoleDoc system.
  434. /// @see console_autodoc
  435. static void endGroup(const char* in_pGroupname);
  436. /// Register a complex field.
  437. ///
  438. /// @param in_pFieldname Name of the field.
  439. /// @param in_fieldType Type of the field. @see ConsoleDynamicTypes
  440. /// @param in_fieldOffset Offset to the field from the start of the class; calculated using the Offset() macro.
  441. /// @param in_elementCount Number of elements in this field. Arrays of elements are assumed to be contiguous in memory.
  442. /// @param in_table An EnumTable, if this is an enumerated field.
  443. /// @param in_pFieldDocs Usage string for this field. @see console_autodoc
  444. static void addField(const char* in_pFieldname,
  445. const U32 in_fieldType,
  446. const dsize_t in_fieldOffset,
  447. const U32 in_elementCount = 1,
  448. EnumTable * in_table = NULL,
  449. const char* in_pFieldDocs = NULL);
  450. /// Register a complex field with a write notify.
  451. ///
  452. /// @param in_pFieldname Name of the field.
  453. /// @param in_fieldType Type of the field. @see ConsoleDynamicTypes
  454. /// @param in_fieldOffset Offset to the field from the start of the class; calculated using the Offset() macro.
  455. /// @param in_writeDataFn This method will return whether the field should be written or not.
  456. /// @param in_elementCount Number of elements in this field. Arrays of elements are assumed to be contiguous in memory.
  457. /// @param in_table An EnumTable, if this is an enumerated field.
  458. /// @param in_pFieldDocs Usage string for this field. @see console_autodoc
  459. static void addField(const char* in_pFieldname,
  460. const U32 in_fieldType,
  461. const dsize_t in_fieldOffset,
  462. AbstractClassRep::WriteDataNotify in_writeDataFn,
  463. const U32 in_elementCount = 1,
  464. EnumTable * in_table = NULL,
  465. const char* in_pFieldDocs = NULL);
  466. /// Register a simple field.
  467. ///
  468. /// @param in_pFieldname Name of the field.
  469. /// @param in_fieldType Type of the field. @see ConsoleDynamicTypes
  470. /// @param in_fieldOffset Offset to the field from the start of the class; calculated using the Offset() macro.
  471. /// @param in_pFieldDocs Usage string for this field. @see console_autodoc
  472. static void addField(const char* in_pFieldname,
  473. const U32 in_fieldType,
  474. const dsize_t in_fieldOffset,
  475. const char* in_pFieldDocs);
  476. /// Register a simple field with a write notify.
  477. ///
  478. /// @param in_pFieldname Name of the field.
  479. /// @param in_fieldType Type of the field. @see ConsoleDynamicTypes
  480. /// @param in_fieldOffset Offset to the field from the start of the class; calculated using the Offset() macro.
  481. /// @param in_writeDataFn This method will return whether the field should be written or not.
  482. /// @param in_pFieldDocs Usage string for this field. @see console_autodoc
  483. static void addField(const char* in_pFieldname,
  484. const U32 in_fieldType,
  485. const dsize_t in_fieldOffset,
  486. AbstractClassRep::WriteDataNotify in_writeDataFn,
  487. const char* in_pFieldDocs );
  488. /// Register a validated field.
  489. ///
  490. /// A validated field is just like a normal field except that you can't
  491. /// have it be an array, and that you give it a pointer to a ConsoleTypeValidator
  492. /// subclass, which is then used to validate any value placed in it. Invalid
  493. /// values are ignored and an error is printed to the console.
  494. ///
  495. /// @see addField
  496. /// @see typeValidators.h
  497. static void addFieldV(const char* in_pFieldname,
  498. const U32 in_fieldType,
  499. const dsize_t in_fieldOffset,
  500. ConsoleTypeValidator *v,
  501. const char * in_pFieldDocs = NULL);
  502. /// Register a complex protected field.
  503. ///
  504. /// @param in_pFieldname Name of the field.
  505. /// @param in_fieldType Type of the field. @see ConsoleDynamicTypes
  506. /// @param in_fieldOffset Offset to the field from the start of the class; calculated using the Offset() macro.
  507. /// @param in_setDataFn When this field gets set, it will call the callback provided. @see console_protected
  508. /// @param in_getDataFn When this field is accessed for it's data, it will return the value of this function
  509. /// @param in_elementCount Number of elements in this field. Arrays of elements are assumed to be contiguous in memory.
  510. /// @param in_table An EnumTable, if this is an enumerated field.
  511. /// @param in_pFieldDocs Usage string for this field. @see console_autodoc
  512. static void addProtectedField(const char* in_pFieldname,
  513. const U32 in_fieldType,
  514. const dsize_t in_fieldOffset,
  515. AbstractClassRep::SetDataNotify in_setDataFn,
  516. AbstractClassRep::GetDataNotify in_getDataFn = &defaultProtectedGetFn,
  517. const U32 in_elementCount = 1,
  518. EnumTable * in_table = NULL,
  519. const char* in_pFieldDocs = NULL);
  520. /// Register a complex protected field.
  521. ///
  522. /// @param in_pFieldname Name of the field.
  523. /// @param in_fieldType Type of the field. @see ConsoleDynamicTypes
  524. /// @param in_fieldOffset Offset to the field from the start of the class; calculated using the Offset() macro.
  525. /// @param in_setDataFn When this field gets set, it will call the callback provided. @see console_protected
  526. /// @param in_getDataFn When this field is accessed for it's data, it will return the value of this function
  527. /// @param in_writeDataFn This method will return whether the field should be written or not.
  528. /// @param in_elementCount Number of elements in this field. Arrays of elements are assumed to be contiguous in memory.
  529. /// @param in_table An EnumTable, if this is an enumerated field.
  530. /// @param in_pFieldDocs Usage string for this field. @see console_autodoc
  531. static void addProtectedField(const char* in_pFieldname,
  532. const U32 in_fieldType,
  533. const dsize_t in_fieldOffset,
  534. AbstractClassRep::SetDataNotify in_setDataFn,
  535. AbstractClassRep::GetDataNotify in_getDataFn = &defaultProtectedGetFn,
  536. AbstractClassRep::WriteDataNotify in_writeDataFn = &defaultProtectedWriteFn,
  537. const U32 in_elementCount = 1,
  538. EnumTable * in_table = NULL,
  539. const char* in_pFieldDocs = NULL);
  540. /// Register a simple protected field.
  541. ///
  542. /// @param in_pFieldname Name of the field.
  543. /// @param in_fieldType Type of the field. @see ConsoleDynamicTypes
  544. /// @param in_fieldOffset Offset to the field from the start of the class; calculated using the Offset() macro.
  545. /// @param in_setDataFn When this field gets set, it will call the callback provided. @see console_protected
  546. /// @param in_getDataFn When this field is accessed for it's data, it will return the value of this function
  547. /// @param in_pFieldDocs Usage string for this field. @see console_autodoc
  548. static void addProtectedField(const char* in_pFieldname,
  549. const U32 in_fieldType,
  550. const dsize_t in_fieldOffset,
  551. AbstractClassRep::SetDataNotify in_setDataFn,
  552. AbstractClassRep::GetDataNotify in_getDataFn = &defaultProtectedGetFn,
  553. const char* in_pFieldDocs = NULL);
  554. /// Register a simple protected field.
  555. ///
  556. /// @param in_pFieldname Name of the field.
  557. /// @param in_fieldType Type of the field. @see ConsoleDynamicTypes
  558. /// @param in_fieldOffset Offset to the field from the start of the class; calculated using the Offset() macro.
  559. /// @param in_setDataFn When this field gets set, it will call the callback provided. @see console_protected
  560. /// @param in_getDataFn When this field is accessed for it's data, it will return the value of this function
  561. /// @param in_writeDataFn This method will return whether the field should be written or not.
  562. /// @param in_pFieldDocs Usage string for this field. @see console_autodoc
  563. static void addProtectedField(const char* in_pFieldname,
  564. const U32 in_fieldType,
  565. const dsize_t in_fieldOffset,
  566. AbstractClassRep::SetDataNotify in_setDataFn,
  567. AbstractClassRep::GetDataNotify in_getDataFn = &defaultProtectedGetFn,
  568. AbstractClassRep::WriteDataNotify in_writeDataFn = &defaultProtectedWriteFn,
  569. const char* in_pFieldDocs = NULL);
  570. /// Add a deprecated field.
  571. ///
  572. /// A deprecated field will always be undefined, even if you assign a value to it. This
  573. /// is useful when you need to make sure that a field is not being used anymore.
  574. static void addDepricatedField(const char *fieldName);
  575. /// Remove a field.
  576. ///
  577. /// Sometimes, you just have to remove a field!
  578. /// @returns True on success.
  579. static bool removeField(const char* in_pFieldname);
  580. /// @}
  581. public:
  582. /// Register dynamic fields in a subclass of ConsoleObject.
  583. ///
  584. /// @see addField(), addFieldV(), addDepricatedField(), addGroup(), endGroup()
  585. static void initPersistFields();
  586. /// Register global constant variables and do other one-time initialization tasks in
  587. /// a subclass of ConsoleObject.
  588. ///
  589. /// @deprecated You should use ConsoleMethod and ConsoleFunction, not this, to
  590. /// register methods or commands.
  591. /// @see console
  592. static void consoleInit();
  593. /// @name Field List
  594. /// @{
  595. /// Get a list of all the fields. This information cannot be modified.
  596. const AbstractClassRep::FieldList& getFieldList() const;
  597. /// Get a list of all the fields, set up so we can modify them.
  598. ///
  599. /// @note This is a bad trick to pull if you aren't very careful,
  600. /// since you can blast field data!
  601. AbstractClassRep::FieldList& getModifiableFieldList();
  602. /// Get a handle to a boolean telling us if we expanded the dynamic group.
  603. ///
  604. /// @see GuiInspector::Inspect()
  605. bool& getDynamicGroupExpand();
  606. /// @}
  607. /// @name ConsoleObject Implementation
  608. ///
  609. /// These functions are implemented in every subclass of
  610. /// ConsoleObject by an IMPLEMENT_CONOBJECT or IMPLEMENT_CO_* macro.
  611. /// @{
  612. /// Get the abstract class information for this class.
  613. static AbstractClassRep *getStaticClassRep() { return NULL; }
  614. /// Get the abstract class information for this class's superclass.
  615. static AbstractClassRep *getParentStaticClassRep() { return NULL; }
  616. /// Get our network-layer class id.
  617. ///
  618. /// @param netClassGroup The net class for which we want our ID.
  619. /// @see
  620. S32 getClassId(U32 netClassGroup) const;
  621. /// Get our compiler and platform independent class name.
  622. ///
  623. /// @note This name can be used to instantiate another instance using create()
  624. const char *getClassName() const;
  625. /// @}
  626. };
  627. // Deprecated? -pw
  628. #define addNamedField(fieldName,type,className) addField(#fieldName, type, Offset(fieldName,className))
  629. #define addNamedFieldV(fieldName,type,className, validator) addFieldV(#fieldName, type, Offset(fieldName,className), validator)
  630. //------------------------------------------------------------------------------
  631. //-------------------------------------- Inlines
  632. //
  633. inline S32 ConsoleObject::getClassId(U32 netClassGroup) const
  634. {
  635. AssertFatal(getClassRep() != NULL,"Cannot get tag from non-declared dynamic class!");
  636. return getClassRep()->getClassId(netClassGroup);
  637. }
  638. inline const char * ConsoleObject::getClassName() const
  639. {
  640. AssertFatal(getClassRep() != NULL,
  641. "Cannot get tag from non-declared dynamic class");
  642. return getClassRep()->getClassName();
  643. }
  644. inline const AbstractClassRep::Field * ConsoleObject::findField(StringTableEntry name) const
  645. {
  646. AssertFatal(getClassRep() != NULL,
  647. avar("Cannot get field '%s' from non-declared dynamic class.", name));
  648. return getClassRep()->findField(name);
  649. }
  650. inline bool ConsoleObject::setField(const char *fieldName, const char *value)
  651. {
  652. //sanity check
  653. if ((! fieldName) || (! fieldName[0]) || (! value))
  654. return false;
  655. if (! getClassRep())
  656. return false;
  657. const AbstractClassRep::Field *myField = getClassRep()->findField(StringTable->insert(fieldName));
  658. if (! myField)
  659. return false;
  660. Con::setData(
  661. myField->type,
  662. (void *) (((const char *)(this)) + myField->offset),
  663. 0,
  664. 1,
  665. &value,
  666. myField->table,
  667. myField->flag);
  668. return true;
  669. }
  670. inline ConsoleObject* ConsoleObject::create(const char* in_pClassName)
  671. {
  672. return AbstractClassRep::create(in_pClassName);
  673. }
  674. inline ConsoleObject* ConsoleObject::create(const U32 groupId, const U32 typeId, const U32 in_classId)
  675. {
  676. return AbstractClassRep::create(groupId, typeId, in_classId);
  677. }
  678. inline const AbstractClassRep::FieldList& ConsoleObject::getFieldList() const
  679. {
  680. return getClassRep()->mFieldList;
  681. }
  682. inline AbstractClassRep::FieldList& ConsoleObject::getModifiableFieldList()
  683. {
  684. return getClassRep()->mFieldList;
  685. }
  686. inline bool& ConsoleObject::getDynamicGroupExpand()
  687. {
  688. return getClassRep()->mDynamicGroupExpand;
  689. }
  690. /// @name ConsoleObject Macros
  691. /// @{
  692. #define DECLARE_CONOBJECT(className) \
  693. static ConcreteClassRep<className> dynClassRep; \
  694. static AbstractClassRep* getParentStaticClassRep(); \
  695. static AbstractClassRep* getContainerChildStaticClassRep(); \
  696. static AbstractClassRep* getStaticClassRep(); \
  697. virtual AbstractClassRep* getClassRep() const
  698. #define IMPLEMENT_CONOBJECT(className) \
  699. AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; } \
  700. AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; } \
  701. AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); } \
  702. AbstractClassRep* className::getContainerChildStaticClassRep() { return NULL; } \
  703. ConcreteClassRep<className> className::dynClassRep(#className, 0, -1, 0, className::getParentStaticClassRep())
  704. #define IMPLEMENT_CONOBJECT_CHILDREN(className) \
  705. AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; } \
  706. AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; } \
  707. AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); } \
  708. AbstractClassRep* className::getContainerChildStaticClassRep() { return Children::getStaticClassRep(); } \
  709. ConcreteClassRep<className> className::dynClassRep(#className, 0, -1, 0, className::getParentStaticClassRep())
  710. #define IMPLEMENT_CO_NETOBJECT_V1(className) \
  711. AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; } \
  712. AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; } \
  713. AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); } \
  714. AbstractClassRep* className::getContainerChildStaticClassRep() { return NULL; } \
  715. ConcreteClassRep<className> className::dynClassRep(#className, NetClassGroupGameMask, NetClassTypeObject, 0, className::getParentStaticClassRep())
  716. #define IMPLEMENT_CO_DATABLOCK_V1(className) \
  717. AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; } \
  718. AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; } \
  719. AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); } \
  720. AbstractClassRep* className::getContainerChildStaticClassRep() {return NULL; } \
  721. ConcreteClassRep<className> className::dynClassRep(#className, NetClassGroupGameMask, NetClassTypeDataBlock, 0, className::getParentStaticClassRep())
  722. /// @}
  723. //------------------------------------------------------------------------------
  724. inline bool defaultProtectedSetFn( void *obj, const char *data )
  725. {
  726. return true;
  727. }
  728. inline const char *defaultProtectedGetFn( void *obj, const char *data )
  729. {
  730. return data;
  731. }
  732. inline bool defaultProtectedWriteFn( void* obj, StringTableEntry pFieldName )
  733. {
  734. return true;
  735. }
  736. inline bool defaultProtectedNotSetFn(void* obj, const char* data)
  737. {
  738. return false;
  739. }
  740. inline bool defaultProtectedNotWriteFn( void* obj, StringTableEntry pFieldName )
  741. {
  742. return false;
  743. }
  744. #endif //_CONSOLEOBJECT_H_