simObject.h

Engine/source/console/simObject.h

More...

Classes:

class

Base class for objects involved in the simulation.

class

Smart SimObject pointer.

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