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