simObject.h 44 KB

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