consoleObject.h 40 KB

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