simObject.h 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #ifndef _SIMOBJECT_H_
  23. #define _SIMOBJECT_H_
  24. #ifndef _SIM_H_
  25. #include "console/sim.h"
  26. #endif
  27. #ifndef _CONSOLEOBJECT_H_
  28. #include "console/consoleObject.h"
  29. #endif
  30. #ifndef _BITSET_H_
  31. #include "core/bitSet.h"
  32. #endif
  33. class Stream;
  34. class LightManager;
  35. class SimFieldDictionary;
  36. class SimPersistID;
  37. /// Base class for objects involved in the simulation.
  38. ///
  39. /// @section simobject_intro Introduction
  40. ///
  41. /// SimObject is a base class for most of the classes you'll encounter
  42. /// working in Torque. It provides fundamental services allowing "smart"
  43. /// object referencing, creation, destruction, organization, and location.
  44. /// Along with SimEvent, it gives you a flexible event-scheduling system,
  45. /// as well as laying the foundation for the in-game editors, GUI system,
  46. /// and other vital subsystems.
  47. ///
  48. /// @section simobject_subclassing Subclassing
  49. ///
  50. /// You will spend a lot of your time in Torque subclassing, or working
  51. /// with subclasses of, SimObject. SimObject is designed to be easy to
  52. /// subclass.
  53. ///
  54. /// You should not need to override anything in a subclass except:
  55. /// - The constructor/destructor.
  56. /// - processArguments()
  57. /// - onAdd()/onRemove()
  58. /// - onGroupAdd()/onGroupRemove()
  59. /// - onNameChange()
  60. /// - onStaticModified()
  61. /// - onDeleteNotify()
  62. /// - onEditorEnable()/onEditorDisable()
  63. /// - inspectPreApply()/inspectPostApply()
  64. /// - things from ConsoleObject (see ConsoleObject docs for specifics)
  65. ///
  66. /// Of course, if you know what you're doing, go nuts! But in most cases, you
  67. /// shouldn't need to touch things not on that list.
  68. ///
  69. /// When you subclass, you should define a typedef in the class, called Parent,
  70. /// that references the class you're inheriting from.
  71. ///
  72. /// @code
  73. /// class mySubClass : public SimObject {
  74. /// typedef SimObject Parent;
  75. /// ...
  76. /// @endcode
  77. ///
  78. /// Then, when you override a method, put in:
  79. ///
  80. /// @code
  81. /// bool mySubClass::onAdd()
  82. /// {
  83. /// if(!Parent::onAdd())
  84. /// return false;
  85. ///
  86. /// // ... do other things ...
  87. /// }
  88. /// @endcode
  89. ///
  90. /// Of course, you want to replace onAdd with the appropriate method call.
  91. ///
  92. /// @section simobject_lifecycle A SimObject's Life Cycle
  93. ///
  94. /// SimObjects do not live apart. One of the primary benefits of using a
  95. /// SimObject is that you can uniquely identify it and easily find it (using
  96. /// its ID). Torque does this by keeping a global hierarchy of SimGroups -
  97. /// a tree - containing every registered SimObject. You can then query
  98. /// for a given object using Sim::findObject() (or SimSet::findObject() if
  99. /// you want to search only a specific set).
  100. ///
  101. /// @code
  102. /// // Three examples of registering an object.
  103. ///
  104. /// // Method 1:
  105. /// AIClient *aiPlayer = new AIClient();
  106. /// aiPlayer->registerObject();
  107. ///
  108. /// // Method 2:
  109. /// ActionMap* globalMap = new ActionMap;
  110. /// globalMap->registerObject("GlobalActionMap");
  111. ///
  112. /// // Method 3:
  113. /// bool reg = mObj->registerObject(id);
  114. /// @endcode
  115. ///
  116. /// Registering a SimObject performs these tasks:
  117. /// - Marks the object as not cleared and not removed.
  118. /// - Assigns the object a unique SimObjectID if it does not have one already.
  119. /// - Adds the object to the global name and ID dictionaries so it can be found
  120. /// again.
  121. /// - Calls the object's onAdd() method. <b>Note:</b> SimObject::onAdd() performs
  122. /// some important initialization steps. See @ref simobject_subclassing "here
  123. /// for details" on how to properly subclass SimObject.
  124. /// - If onAdd() fails (returns false), it calls unregisterObject().
  125. /// - Checks to make sure that the SimObject was properly initialized (and asserts
  126. /// if not).
  127. ///
  128. /// Calling registerObject() and passing an ID or a name will cause the object to be
  129. /// assigned that name and/or ID before it is registered.
  130. ///
  131. /// Congratulations, you have now registered your object! What now?
  132. ///
  133. /// Well, hopefully, the SimObject will have a long, useful life. But eventually,
  134. /// it must die.
  135. ///
  136. /// There are a two ways a SimObject can die.
  137. /// - First, the game can be shut down. This causes the root SimGroup
  138. /// to be unregistered and deleted. When a SimGroup is unregistered,
  139. /// it unregisters all of its member SimObjects; this results in everything
  140. /// that has been registered with Sim being unregistered, as everything
  141. /// registered with Sim is in the root group.
  142. /// - Second, you can manually kill it off, either by calling unregisterObject()
  143. /// or by calling deleteObject().
  144. ///
  145. /// When you unregister a SimObject, the following tasks are performed:
  146. /// - The object is flagged as removed.
  147. /// - Notifications are cleaned up.
  148. /// - If the object is in a group, then it removes itself from the group.
  149. /// - Delete notifications are sent out.
  150. /// - Finally, the object removes itself from the Sim globals, and tells
  151. /// Sim to get rid of any pending events for it.
  152. ///
  153. /// If you call deleteObject(), all of the above tasks are performed, in addition
  154. /// to some sanity checking to make sure the object was previously added properly,
  155. /// and isn't in the process of being deleted. After the object is unregistered, it
  156. /// deallocates itself.
  157. ///
  158. /// @section simobject_editor Torque Editors
  159. ///
  160. /// SimObjects are one of the building blocks for the in-game editors. They
  161. /// provide a basic interface for the editor to be able to list the fields
  162. /// of the object, update them safely and reliably, and inform the object
  163. /// things have changed.
  164. ///
  165. /// This interface is implemented in the following areas:
  166. /// - onNameChange() is called when the object is renamed.
  167. /// - onStaticModified() is called whenever a static field is modified.
  168. /// - inspectPreApply() is called before the object's fields are updated,
  169. /// when changes are being applied.
  170. /// - inspectPostApply() is called after the object's fields are updated.
  171. /// - onEditorEnable() is called whenever an editor is enabled (for instance,
  172. /// when you hit F11 to bring up the world editor).
  173. /// - onEditorDisable() is called whenever the editor is disabled (for instance,
  174. /// when you hit F11 again to close the world editor).
  175. ///
  176. /// (Note: you can check the variable gEditingMission to see if the mission editor
  177. /// is running; if so, you may want to render special indicators. For instance, the
  178. /// fxFoliageReplicator renders inner and outer radii when the mission editor is
  179. /// runnning.)
  180. ///
  181. /// @section simobject_console The Console
  182. ///
  183. /// SimObject extends ConsoleObject by allowing you to
  184. /// to set arbitrary dynamic fields on the object, as well as
  185. /// statically defined fields. This is done through two methods,
  186. /// setDataField and getDataField, which deal with the complexities of
  187. /// allowing access to two different types of object fields.
  188. ///
  189. /// Static fields take priority over dynamic fields. This is to be
  190. /// expected, as the role of dynamic fields is to allow data to be
  191. /// stored in addition to the predefined fields.
  192. ///
  193. /// The fields in a SimObject are like properties (or fields) in a class.
  194. ///
  195. /// Some fields may be arrays, which is what the array parameter is for; if it's non-null,
  196. /// then it is parsed with dAtoI and used as an index into the array. If you access something
  197. /// as an array which isn't, then you get an empty string.
  198. ///
  199. /// <b>You don't need to read any further than this.</b> Right now,
  200. /// set/getDataField are called a total of 6 times through the entire
  201. /// Torque codebase. Therefore, you probably don't need to be familiar
  202. /// with the details of accessing them. You may want to look at Con::setData
  203. /// instead. Most of the time you will probably be accessing fields directly,
  204. /// or using the scripting language, which in either case means you don't
  205. /// need to do anything special.
  206. ///
  207. /// The functions to get/set these fields are very straightforward:
  208. ///
  209. /// @code
  210. /// setDataField(StringTable->insert("locked", false), NULL, b ? "true" : "false" );
  211. /// curObject->setDataField(curField, curFieldArray, STR.getStringValue());
  212. /// setDataField(slotName, array, value);
  213. /// @endcode
  214. ///
  215. /// <i>For advanced users:</i> There are two flags which control the behavior
  216. /// of these functions. The first is ModStaticFields, which controls whether
  217. /// or not the DataField functions look through the static fields (defined
  218. /// with addField; see ConsoleObject for details) of the class. The second
  219. /// is ModDynamicFields, which controls dynamically defined fields. They are
  220. /// set automatically by the console constructor code.
  221. ///
  222. /// @nosubgrouping
  223. class SimObject: public ConsoleObject
  224. {
  225. public:
  226. typedef ConsoleObject Parent;
  227. friend class SimManager;
  228. friend class SimGroup;
  229. friend class SimNameDictionary;
  230. friend class SimManagerNameDictionary;
  231. friend class SimIdDictionary;
  232. /// @name Notification
  233. /// @{
  234. struct Notify
  235. {
  236. enum Type
  237. {
  238. ClearNotify, ///< Notified when the object is cleared.
  239. DeleteNotify, ///< Notified when the object is deleted.
  240. ObjectRef, ///< Cleverness to allow tracking of references.
  241. Invalid ///< Mark this notification as unused (used in freeNotify).
  242. } type;
  243. void *ptr; ///< Data (typically referencing or interested object).
  244. Notify *next; ///< Next notification in the linked list.
  245. };
  246. /// @}
  247. /// Flags passed to SimObject::write
  248. enum WriteFlags
  249. {
  250. SelectedOnly = BIT( 0 ), ///< Indicates that only objects marked as selected should be outputted. Used in SimSet.
  251. NoName = BIT( 1 ), ///< Indicates that the object name should not be saved.
  252. IgnoreCanSave = BIT( 2 ), ///< Write out even if CannotSave=true.
  253. };
  254. private:
  255. /// Flags for use in mFlags
  256. enum
  257. {
  258. Deleted = BIT( 0 ), ///< This object is marked for deletion.
  259. Removed = BIT( 1 ), ///< This object has been unregistered from the object system.
  260. Added = BIT( 3 ), ///< This object has been registered with the object system.
  261. Selected = BIT( 4 ), ///< This object has been marked as selected. (in editor)
  262. Expanded = BIT( 5 ), ///< This object has been marked as expanded. (in editor)
  263. ModStaticFields = BIT( 6 ), ///< The object allows you to read/modify static fields
  264. ModDynamicFields = BIT( 7 ), ///< The object allows you to read/modify dynamic fields
  265. AutoDelete = BIT( 8 ), ///< Delete this object when the last ObjectRef is gone.
  266. CannotSave = BIT( 9 ), ///< Object should not be saved.
  267. EditorOnly = BIT( 10 ), ///< This object is for use by the editor only.
  268. NoNameChange = BIT( 11 ), ///< Whether changing the name of this object is allowed.
  269. Hidden = BIT( 12 ), ///< Object is hidden in editors.
  270. Locked = BIT( 13 ), ///< Object is locked in editors.
  271. };
  272. // dictionary information stored on the object
  273. StringTableEntry objectName;
  274. StringTableEntry mOriginalName;
  275. SimObject* nextNameObject;
  276. SimObject* nextManagerNameObject;
  277. SimObject* nextIdObject;
  278. /// SimGroup we're contained in, if any.
  279. SimGroup* mGroup;
  280. /// Flags internal to the object management system.
  281. BitSet32 mFlags;
  282. /// Object we are copying fields from.
  283. SimObject* mCopySource;
  284. /// Table of dynamic fields assigned to this object.
  285. SimFieldDictionary *mFieldDictionary;
  286. /// Buffer to store textual representation of this object's numeric ID in.
  287. char mIdString[ 11 ];
  288. /// @name Serialization
  289. /// @{
  290. /// Path to file this SimObject was loaded from.
  291. StringTableEntry mFilename;
  292. /// The line number that the object was declared on if it was loaded from a file.
  293. S32 mDeclarationLine;
  294. /// @}
  295. /// @name Notification
  296. /// @{
  297. /// List of notifications added to this object.
  298. Notify* mNotifyList;
  299. static SimObject::Notify *mNotifyFreeList;
  300. static SimObject::Notify *allocNotify(); ///< Get a free Notify structure.
  301. static void freeNotify(SimObject::Notify*); ///< Mark a Notify structure as free.
  302. /// @}
  303. static bool _setCanSave( void* object, const char* index, const char* data );
  304. static const char* _getCanSave( void* object, const char* data );
  305. static const char* _getHidden( void* object, const char* data )
  306. { if( static_cast< SimObject* >( object )->isHidden() ) return "1"; return "0"; }
  307. static const char* _getLocked( void* object, const char* data )
  308. { if( static_cast< SimObject* >( object )->isLocked() ) return "1"; return "0"; }
  309. static bool _setHidden( void* object, const char* index, const char* data )
  310. { static_cast< SimObject* >( object )->setHidden( dAtob( data ) ); return false; }
  311. static bool _setLocked( void* object, const char* index, const char* data )
  312. { static_cast< SimObject* >( object )->setLocked( dAtob( data ) ); return false; }
  313. // Namespace protected set methods
  314. static bool setClass( void *object, const char *index, const char *data )
  315. { static_cast<SimObject*>(object)->setClassNamespace(data); return false; };
  316. static bool setSuperClass(void *object, const char *index, const char *data)
  317. { static_cast<SimObject*>(object)->setSuperClassNamespace(data); return false; };
  318. // Group hierarchy protected set method
  319. static bool setProtectedParent(void *object, const char *index, const char *data);
  320. // Object name protected set method
  321. static bool setProtectedName(void *object, const char *index, const char *data);
  322. protected:
  323. /// Id number for this object.
  324. SimObjectId mId;
  325. /// Internal name assigned to the object. Not set by default.
  326. StringTableEntry mInternalName;
  327. static bool smForceId; ///< Force a registered object to use the given Id. Cleared upon use.
  328. static SimObjectId smForcedId; ///< The Id to force upon the object. Poor object.
  329. /// @name Serialization
  330. /// @{
  331. /// Whether dynamic fields should be saved out in serialization. Defaults to true.
  332. bool mCanSaveFieldDictionary;
  333. /// @}
  334. /// @name Persistent IDs
  335. /// @{
  336. /// Persistent ID assigned to this object. Allows to unambiguously refer to this
  337. /// object in serializations regardless of stream object ordering.
  338. SimPersistID* mPersistentId;
  339. static bool _setPersistentID( void* object, const char* index, const char* data );
  340. /// @}
  341. /// @name Namespace management
  342. /// @{
  343. /// The namespace in which method lookup for this object begins.
  344. Namespace* mNameSpace;
  345. /// Name of namespace to use as class namespace.
  346. StringTableEntry mClassName;
  347. /// Name of namespace to use as class super namespace.
  348. StringTableEntry mSuperClassName;
  349. /// Perform namespace linking on this object.
  350. void linkNamespaces();
  351. /// Undo namespace linking on this object.
  352. void unlinkNamespaces();
  353. /// @}
  354. /// Called when the object is selected in the editor.
  355. virtual void _onSelected() {}
  356. /// Called when the object is unselected in the editor.
  357. virtual void _onUnselected() {}
  358. /// We can provide more detail, like object name and id.
  359. virtual String _getLogMessage(const char* fmt, void* args) const;
  360. DEFINE_CREATE_METHOD
  361. {
  362. T* object = new T;
  363. object->incRefCount();
  364. object->registerObject();
  365. return object;
  366. }
  367. // EngineObject.
  368. virtual void _destroySelf();
  369. public:
  370. /// @name Cloning
  371. /// @{
  372. /// Return a shallow copy of this object.
  373. virtual SimObject* clone();
  374. /// Return a deep copy of this object.
  375. virtual SimObject* deepClone();
  376. /// @}
  377. /// @name Accessors
  378. /// @{
  379. /// Get the value of a field on the object.
  380. ///
  381. /// See @ref simobject_console "here" for a detailed discussion of what this
  382. /// function does.
  383. ///
  384. /// @param slotName Field to access.
  385. /// @param array String containing index into array
  386. /// (if field is an array); if NULL, it is ignored.
  387. const char *getDataField(StringTableEntry slotName, const char *array);
  388. /// Set the value of a field on the object.
  389. ///
  390. /// See @ref simobject_console "here" for a detailed discussion of what this
  391. /// function does.
  392. ///
  393. /// @param slotName Field to access.
  394. /// @param array String containing index into array; if NULL, it is ignored.
  395. /// @param value Value to store.
  396. void setDataField(StringTableEntry slotName, const char *array, const char *value);
  397. /// Get the type of a field on the object.
  398. ///
  399. /// @param slotName Field to access.
  400. /// @param array String containing index into array
  401. /// (if field is an array); if NULL, it is ignored.
  402. U32 getDataFieldType(StringTableEntry slotName, const char *array);
  403. /// Set the type of a *dynamic* field on the object.
  404. ///
  405. /// @param typeName/Id Console base type name/id to assign to a dynamic field.
  406. /// @param slotName Field to access.
  407. /// @param array String containing index into array
  408. /// (if field is an array); if NULL, it is ignored.
  409. void setDataFieldType(const U32 fieldTypeId, StringTableEntry slotName, const char *array);
  410. void setDataFieldType(const char *typeName, StringTableEntry slotName, const char *array);
  411. /// Get reference to the dictionary containing dynamic fields.
  412. ///
  413. /// See @ref simobject_console "here" for a detailed discussion of what this
  414. /// function does.
  415. ///
  416. /// This dictionary can be iterated over using a SimFieldDictionaryIterator.
  417. SimFieldDictionary * getFieldDictionary() {return(mFieldDictionary);}
  418. // Component Information
  419. inline virtual StringTableEntry getComponentName() { return StringTable->insert( getClassName() ); };
  420. /// These functions support internal naming that is not namespace
  421. /// bound for locating child controls in a generic way.
  422. ///
  423. /// Set the internal name of this control (Not linked to a namespace)
  424. void setInternalName(const char* newname);
  425. /// Get the internal name of this control
  426. StringTableEntry getInternalName() const { return mInternalName; }
  427. /// Set the original name of this control
  428. void setOriginalName(const char* originalName);
  429. /// Get the original name of this control
  430. StringTableEntry getOriginalName() const { return mOriginalName; }
  431. /// These functions allow you to set and access the filename
  432. /// where this object was created.
  433. ///
  434. /// Set the filename
  435. void setFilename(const char* file);
  436. /// Get the filename
  437. StringTableEntry getFilename() const { return mFilename; }
  438. /// These functions are used to track the line number (1-based)
  439. /// on which the object was created if it was loaded from script
  440. ///
  441. /// Set the declaration line number
  442. void setDeclarationLine(U32 lineNumber);
  443. /// Get the declaration line number
  444. S32 getDeclarationLine() const { return mDeclarationLine; }
  445. /// Save object as a TorqueScript File.
  446. virtual bool save( const char* pcFilePath, bool bOnlySelected = false, const char *preappend = NULL );
  447. /// Check if a method exists in the objects current namespace.
  448. virtual bool isMethod( const char* methodName );
  449. /// Return true if the field is defined on the object
  450. virtual bool isField( const char* fieldName, bool includeStatic = true, bool includeDynamic = true );
  451. /// @}
  452. /// @name Initialization
  453. /// @{
  454. ///
  455. SimObject();
  456. virtual ~SimObject();
  457. virtual bool processArguments(S32 argc, const char **argv); ///< Process constructor options. (ie, new SimObject(1,2,3))
  458. /// @}
  459. /// @name Events
  460. /// @{
  461. /// Called when the object is added to the sim.
  462. virtual bool onAdd();
  463. /// Called when the object is removed from the sim.
  464. virtual void onRemove();
  465. /// Called when the object is added to a SimGroup.
  466. virtual void onGroupAdd();
  467. /// Called when the object is removed from a SimGroup.
  468. virtual void onGroupRemove();
  469. /// Called when the object's name is changed.
  470. virtual void onNameChange(const char *name);
  471. ///
  472. /// Specifically, these are called by setDataField
  473. /// when a static or dynamic field is modified, see
  474. /// @ref simobject_console "the console details".
  475. virtual void onStaticModified(const char* slotName, const char*newValue = NULL); ///< Called when a static field is modified.
  476. virtual void onDynamicModified(const char* slotName, const char*newValue = NULL); ///< Called when a dynamic field is modified.
  477. /// Called before any property of the object is changed in the world editor.
  478. ///
  479. /// The calling order here is:
  480. /// - inspectPreApply()
  481. /// - ...
  482. /// - calls to setDataField()
  483. /// - ...
  484. /// - inspectPostApply()
  485. virtual void inspectPreApply();
  486. /// Called after any property of the object is changed in the world editor.
  487. ///
  488. /// @see inspectPreApply
  489. virtual void inspectPostApply();
  490. /// Called when a SimObject is deleted.
  491. ///
  492. /// When you are on the notification list for another object
  493. /// and it is deleted, this method is called.
  494. virtual void onDeleteNotify(SimObject *object);
  495. /// Called when the editor is activated.
  496. virtual void onEditorEnable(){};
  497. /// Called when the editor is deactivated.
  498. virtual void onEditorDisable(){};
  499. /// @}
  500. /// Find a named sub-object of this object.
  501. ///
  502. /// This is subclassed in the SimGroup and SimSet classes.
  503. ///
  504. /// For a single object, it just returns NULL, as normal objects cannot have children.
  505. virtual SimObject *findObject(const char *name);
  506. /// @name Notification
  507. /// @{
  508. Notify *removeNotify(void *ptr, Notify::Type); ///< Remove a notification from the list.
  509. void deleteNotify(SimObject* obj); ///< Notify an object when we are deleted.
  510. void clearNotify(SimObject* obj); ///< Notify an object when we are cleared.
  511. void clearAllNotifications(); ///< Remove all notifications for this object.
  512. void processDeleteNotifies(); ///< Send out deletion notifications.
  513. /// Register a reference to this object.
  514. ///
  515. /// You pass a pointer to your reference to this object.
  516. ///
  517. /// When the object is deleted, it will null your
  518. /// pointer, ensuring you don't access old memory.
  519. ///
  520. /// @param obj Pointer to your reference to the object.
  521. void registerReference(SimObject **obj);
  522. /// Unregister a reference to this object.
  523. ///
  524. /// Remove a reference from the list, so that it won't
  525. /// get nulled inappropriately.
  526. ///
  527. /// Call this when you're done with your reference to
  528. /// the object, especially if you're going to free the
  529. /// memory. Otherwise, you may erroneously get something
  530. /// overwritten.
  531. ///
  532. /// @see registerReference
  533. void unregisterReference(SimObject **obj);
  534. /// @}
  535. /// @name Registration
  536. ///
  537. /// SimObjects must be registered with the object system.
  538. /// @{
  539. /// Register an object with the object system.
  540. ///
  541. /// This must be called if you want to keep the object around.
  542. /// In the rare case that you will delete the object immediately, or
  543. /// don't want to be able to use Sim::findObject to locate it, then
  544. /// you don't need to register it.
  545. ///
  546. /// registerObject adds the object to the global ID and name dictionaries,
  547. /// after first assigning it a new ID number. It calls onAdd(). If onAdd fails,
  548. /// it unregisters the object and returns false.
  549. ///
  550. /// If a subclass's onAdd doesn't eventually call SimObject::onAdd(), it will
  551. /// cause an assertion.
  552. bool registerObject();
  553. /// Register the object, forcing the id.
  554. ///
  555. /// @see registerObject()
  556. /// @param id ID to assign to the object.
  557. bool registerObject(U32 id);
  558. /// Register the object, assigning the name.
  559. ///
  560. /// @see registerObject()
  561. /// @param name Name to assign to the object.
  562. bool registerObject(const char *name);
  563. /// Register the object, assigning a name and ID.
  564. ///
  565. /// @see registerObject()
  566. /// @param name Name to assign to the object.
  567. /// @param id ID to assign to the object.
  568. bool registerObject(const char *name, U32 id);
  569. /// Unregister the object from Sim.
  570. ///
  571. /// This performs several operations:
  572. /// - Sets the removed flag.
  573. /// - Call onRemove()
  574. /// - Clear out notifications.
  575. /// - Remove the object from...
  576. /// - its group, if any. (via getGroup)
  577. /// - Sim::gNameDictionary
  578. /// - Sim::gIDDictionary
  579. /// - Finally, cancel any pending events for this object (as it can't receive them now).
  580. void unregisterObject();
  581. /// Unregister, mark as deleted, and free the object.
  582. void deleteObject();
  583. /// Performs a safe delayed delete of the object using a sim event.
  584. void safeDeleteObject();
  585. /// @}
  586. /// @name Accessors
  587. /// @{
  588. /// Return the unique numeric object ID.
  589. SimObjectId getId() const { return mId; }
  590. /// Return the object ID as a string.
  591. const char* getIdString() const { return mIdString; }
  592. /// Return the name of this object.
  593. StringTableEntry getName() const { return objectName; }
  594. /// Return the SimGroup that this object is contained in. Never NULL except for
  595. /// RootGroup and unregistered objects.
  596. SimGroup* getGroup() const { return mGroup; }
  597. /// Assign the given name to this object.
  598. void assignName( const char* name );
  599. void setId(SimObjectId id);
  600. static void setForcedId(SimObjectId id) { smForceId = true; smForcedId = id; } ///< Force an Id on the next registered object.
  601. bool isChildOfGroup(SimGroup* pGroup);
  602. bool isProperlyAdded() const { return mFlags.test(Added); }
  603. bool isDeleted() const { return mFlags.test(Deleted); }
  604. bool isRemoved() const { return mFlags.test(Deleted | Removed); }
  605. virtual bool isLocked() const { return mFlags.test( Locked ); }
  606. virtual void setLocked( bool b );
  607. virtual bool isHidden() const { return mFlags.test( Hidden ); }
  608. virtual void setHidden(bool b);
  609. /// @}
  610. /// @name Sets
  611. ///
  612. /// The object must be properly registered before you can add/remove it to/from a set.
  613. ///
  614. /// All these functions accept either a name or ID to identify the set you wish
  615. /// to operate on. Then they call addObject or removeObject on the set, which
  616. /// sets up appropriate notifications.
  617. ///
  618. /// An object may be in multiple sets at a time.
  619. /// @{
  620. bool addToSet(SimObjectId);
  621. bool addToSet(const char *);
  622. bool removeFromSet(SimObjectId);
  623. bool removeFromSet(const char *);
  624. /// @}
  625. /// @name Serialization
  626. /// @{
  627. /// Determine whether or not a field should be written.
  628. ///
  629. /// @param fiedname The name of the field being written.
  630. /// @param value The value of the field.
  631. virtual bool writeField(StringTableEntry fieldname, const char* value);
  632. /// Output the TorqueScript to recreate this object.
  633. ///
  634. /// This calls writeFields internally.
  635. /// @param stream Stream to output to.
  636. /// @param tabStop Indentation level for this object.
  637. /// @param flags If SelectedOnly is passed here, then
  638. /// only objects marked as selected (using setSelected)
  639. /// will output themselves.
  640. virtual void write(Stream &stream, U32 tabStop, U32 flags = 0);
  641. /// Write the fields of this object in TorqueScript.
  642. ///
  643. /// @param stream Stream for output.
  644. /// @param tabStop Indentation level for the fields.
  645. virtual void writeFields(Stream &stream, U32 tabStop);
  646. virtual bool writeObject(Stream *stream);
  647. virtual bool readObject(Stream *stream);
  648. /// Set whether fields created at runtime should be saved. Default is true.
  649. void setCanSaveDynamicFields( bool bCanSave ) { mCanSaveFieldDictionary = bCanSave; }
  650. /// Get whether fields created at runtime should be saved. Default is true.
  651. bool getCanSaveDynamicFields( ) { return mCanSaveFieldDictionary;}
  652. /// Return the object that this object is copying fields from.
  653. SimObject* getCopySource() const { return mCopySource; }
  654. /// Set the object that this object should be copying fields from.
  655. void setCopySource( SimObject* object );
  656. /// Copy fields from another object onto this one.
  657. ///
  658. /// Objects must be of same type. Everything from obj
  659. /// will overwrite what's in this object; extra fields
  660. /// in this object will remain. This includes dynamic
  661. /// fields.
  662. ///
  663. /// @param obj Object to copy from.
  664. void assignFieldsFrom(SimObject *obj);
  665. /// Copy dynamic fields from another object onto this one.
  666. ///
  667. /// Everything from obj will overwrite what's in this
  668. /// object.
  669. ///
  670. /// @param obj Object to copy from.
  671. void assignDynamicFieldsFrom(SimObject *obj);
  672. /// @}
  673. /// Return the object's namespace.
  674. Namespace* getNamespace() { return mNameSpace; }
  675. /// Get next matching item in namespace.
  676. ///
  677. /// This wraps a call to Namespace::tabComplete; it gets the
  678. /// next thing in the namespace, given a starting value
  679. /// and a base length of the string. See
  680. /// Namespace::tabComplete for details.
  681. const char *tabComplete(const char *prevText, S32 baseLen, bool);
  682. /// @name Accessors
  683. /// @{
  684. bool isSelected() const { return mFlags.test(Selected); }
  685. bool isExpanded() const { return mFlags.test(Expanded); }
  686. bool isEditorOnly() const { return mFlags.test( EditorOnly ); }
  687. bool isNameChangeAllowed() const { return !mFlags.test( NoNameChange ); }
  688. bool isAutoDeleted() const { return mFlags.test( AutoDelete ); }
  689. void setSelected(bool sel);
  690. void setExpanded(bool exp) { if(exp) mFlags.set(Expanded); else mFlags.clear(Expanded); }
  691. void setModDynamicFields(bool dyn) { if(dyn) mFlags.set(ModDynamicFields); else mFlags.clear(ModDynamicFields); }
  692. void setModStaticFields(bool sta) { if(sta) mFlags.set(ModStaticFields); else mFlags.clear(ModStaticFields); }
  693. bool canModDynamicFields() { return mFlags.test(ModDynamicFields); }
  694. bool canModStaticFields() { return mFlags.test(ModStaticFields); }
  695. void setAutoDelete( bool val ) { if( val ) mFlags.set( AutoDelete ); else mFlags.clear( AutoDelete ); }
  696. void setEditorOnly( bool val ) { if( val ) mFlags.set( EditorOnly ); else mFlags.clear( EditorOnly ); }
  697. void setNameChangeAllowed( bool val ) { if( val ) mFlags.clear( NoNameChange ); else mFlags.set( NoNameChange ); }
  698. /// Returns boolean specifying if the object can be serialized.
  699. bool getCanSave() const { return !mFlags.test( CannotSave ); }
  700. /// Set serialization flag.
  701. virtual void setCanSave( bool val ) { if( !val ) mFlags.set( CannotSave ); else mFlags.clear( CannotSave ); }
  702. /// Returns true if this object is selected or any group it is a member of is.
  703. bool isSelectedRecursive() const;
  704. /// @}
  705. /// @name Namespace management
  706. /// @{
  707. /// Return name of class namespace set on this object.
  708. StringTableEntry getClassNamespace() const { return mClassName; };
  709. /// Return name of superclass namespace set on this object.
  710. StringTableEntry getSuperClassNamespace() const { return mSuperClassName; };
  711. ///
  712. void setClassNamespace( const char* classNamespace );
  713. ///
  714. void setSuperClassNamespace( const char* superClassNamespace );
  715. /// @}
  716. /// @name Persistent IDs
  717. /// @{
  718. /// Return the persistent ID assigned to this object or NULL.
  719. SimPersistID* getPersistentId() const { return mPersistentId; }
  720. /// Return the persistent ID assigned to this object or assign one to it if it has none.
  721. SimPersistID* getOrCreatePersistentId();
  722. /// @}
  723. /// @name Debugging
  724. /// @{
  725. /// Return a textual description of the object.
  726. virtual String describeSelf() const;
  727. /// Dump the contents of this object to the console. Use the Torque Script dump() and dumpF() functions to
  728. /// call this.
  729. void dumpToConsole( bool includeFunctions=true );
  730. ///added this so that you can print the entire class hierarchy, including script objects,
  731. //from the console or C++.
  732. /// Print the AbstractClassRep hierarchy of this object to the console.
  733. virtual void dumpClassHierarchy();
  734. /// Print the SimGroup hierarchy of this object to the console.
  735. virtual void dumpGroupHierarchy();
  736. /// @}
  737. static void initPersistFields();
  738. /// Copy SimObject to another SimObject (Originally designed for T2D).
  739. virtual void copyTo(SimObject* object);
  740. // Component Console Overrides
  741. virtual bool handlesConsoleMethod(const char * fname, S32 * routingId) { return false; }
  742. virtual void getConsoleMethodData(const char * fname, S32 routingId, S32 * type, S32 * minArgs, S32 * maxArgs, void ** callback, const char ** usage) {}
  743. DECLARE_CONOBJECT( SimObject );
  744. static SimObject* __findObject( const char* id ) { return Sim::findObject( id ); }
  745. static const char* __getObjectId( ConsoleObject* object )
  746. {
  747. SimObject* simObject = static_cast< SimObject* >( object );
  748. if( !simObject )
  749. return "";
  750. else if( simObject->getName() )
  751. return simObject->getName();
  752. return simObject->getIdString();
  753. }
  754. // EngineObject.
  755. virtual void destroySelf();
  756. };
  757. /// Smart SimObject pointer.
  758. ///
  759. /// This class keeps track of the book-keeping necessary
  760. /// to keep a registered reference to a SimObject or subclass
  761. /// thereof.
  762. ///
  763. /// Normally, if you want the SimObject to be aware that you
  764. /// have a reference to it, you must call SimObject::registerReference()
  765. /// when you create the reference, and SimObject::unregisterReference() when
  766. /// you're done. If you change the reference, you must also register/unregister
  767. /// it. This is a big headache, so this class exists to automatically
  768. /// keep track of things for you.
  769. ///
  770. /// @code
  771. /// // Assign an object to the
  772. /// SimObjectPtr<GameBase> mOrbitObject = Sim::findObject("anObject");
  773. ///
  774. /// // Use it as a GameBase*.
  775. /// mOrbitObject->getWorldBox().getCenter(&mPosition);
  776. ///
  777. /// // And reassign it - it will automatically update the references.
  778. /// mOrbitObject = Sim::findObject("anotherObject");
  779. /// @endcode
  780. template< typename T >
  781. class SimObjectPtr : public WeakRefPtr< T >
  782. {
  783. public:
  784. typedef WeakRefPtr< T > Parent;
  785. SimObjectPtr() {}
  786. SimObjectPtr(T *ptr) { this->mReference = NULL; set(ptr); }
  787. SimObjectPtr( const SimObjectPtr& ref ) { this->mReference = NULL; set(ref.mReference); }
  788. T* getObject() const { return Parent::getPointer(); }
  789. ~SimObjectPtr() { set((WeakRefBase::WeakReference*)NULL); }
  790. SimObjectPtr<T>& operator=(const SimObjectPtr ref)
  791. {
  792. set(ref.mReference);
  793. return *this;
  794. }
  795. SimObjectPtr<T>& operator=(T *ptr)
  796. {
  797. set(ptr);
  798. return *this;
  799. }
  800. protected:
  801. void set(WeakRefBase::WeakReference * ref)
  802. {
  803. if( ref == this->mReference )
  804. return;
  805. if( this->mReference )
  806. {
  807. // Auto-delete
  808. T* obj = this->getPointer();
  809. if ( this->mReference->getRefCount() == 2 && obj && obj->isAutoDeleted() )
  810. obj->deleteObject();
  811. this->mReference->decRefCount();
  812. }
  813. this->mReference = NULL;
  814. if( ref )
  815. {
  816. this->mReference = ref;
  817. this->mReference->incRefCount();
  818. }
  819. }
  820. void set(T * obj)
  821. {
  822. set(obj ? obj->getWeakReference() : (WeakRefBase::WeakReference *)NULL);
  823. }
  824. };
  825. #endif // _SIMOBJECT_H_