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