mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-01-20 12:44:46 +00:00
Allows for expanded editing capabilities of existing classes without needing to add static fields to classes
1089 lines
43 KiB
C++
1089 lines
43 KiB
C++
//-----------------------------------------------------------------------------
|
|
// Copyright (c) 2012 GarageGames, LLC
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
// of this software and associated documentation files (the "Software"), to
|
|
// deal in the Software without restriction, including without limitation the
|
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
// sell copies of the Software, and to permit persons to whom the Software is
|
|
// furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in
|
|
// all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
// IN THE SOFTWARE.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
|
// Copyright (C) 2015 Faust Logic, Inc.
|
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
|
#ifndef _SIMOBJECT_H_
|
|
#define _SIMOBJECT_H_
|
|
|
|
#ifndef _SIM_H_
|
|
#include "console/sim.h"
|
|
#endif
|
|
#ifndef _CONSOLEOBJECT_H_
|
|
#include "console/consoleObject.h"
|
|
#endif
|
|
#ifndef _BITSET_H_
|
|
#include "core/bitSet.h"
|
|
#endif
|
|
|
|
#ifndef _TAML_CALLBACKS_H_
|
|
#include "persistence/taml/tamlCallbacks.h"
|
|
#endif
|
|
|
|
class Stream;
|
|
class LightManager;
|
|
class SimFieldDictionary;
|
|
class SimPersistID;
|
|
class GuiInspector;
|
|
|
|
/// Base class for objects involved in the simulation.
|
|
///
|
|
/// @section simobject_intro Introduction
|
|
///
|
|
/// SimObject is a base class for most of the classes you'll encounter
|
|
/// working in Torque. It provides fundamental services allowing "smart"
|
|
/// object referencing, creation, destruction, organization, and location.
|
|
/// Along with SimEvent, it gives you a flexible event-scheduling system,
|
|
/// as well as laying the foundation for the in-game editors, GUI system,
|
|
/// and other vital subsystems.
|
|
///
|
|
/// @section simobject_subclassing Subclassing
|
|
///
|
|
/// You will spend a lot of your time in Torque subclassing, or working
|
|
/// with subclasses of, SimObject. SimObject is designed to be easy to
|
|
/// subclass.
|
|
///
|
|
/// You should not need to override anything in a subclass except:
|
|
/// - The constructor/destructor.
|
|
/// - processArguments()
|
|
/// - onAdd()/onRemove()
|
|
/// - onGroupAdd()/onGroupRemove()
|
|
/// - onNameChange()
|
|
/// - onStaticModified()
|
|
/// - onDeleteNotify()
|
|
/// - onEditorEnable()/onEditorDisable()
|
|
/// - inspectPreApply()/inspectPostApply()
|
|
/// - things from ConsoleObject (see ConsoleObject docs for specifics)
|
|
///
|
|
/// Of course, if you know what you're doing, go nuts! But in most cases, you
|
|
/// shouldn't need to touch things not on that list.
|
|
///
|
|
/// When you subclass, you should define a typedef in the class, called Parent,
|
|
/// that references the class you're inheriting from.
|
|
///
|
|
/// @code
|
|
/// class mySubClass : public SimObject {
|
|
/// typedef SimObject Parent;
|
|
/// ...
|
|
/// @endcode
|
|
///
|
|
/// Then, when you override a method, put in:
|
|
///
|
|
/// @code
|
|
/// bool mySubClass::onAdd()
|
|
/// {
|
|
/// if(!Parent::onAdd())
|
|
/// return false;
|
|
///
|
|
/// // ... do other things ...
|
|
/// }
|
|
/// @endcode
|
|
///
|
|
/// Of course, you want to replace onAdd with the appropriate method call.
|
|
///
|
|
/// @section simobject_lifecycle A SimObject's Life Cycle
|
|
///
|
|
/// SimObjects do not live apart. One of the primary benefits of using a
|
|
/// SimObject is that you can uniquely identify it and easily find it (using
|
|
/// its ID). Torque does this by keeping a global hierarchy of SimGroups -
|
|
/// a tree - containing every registered SimObject. You can then query
|
|
/// for a given object using Sim::findObject() (or SimSet::findObject() if
|
|
/// you want to search only a specific set).
|
|
///
|
|
/// @code
|
|
/// // Three examples of registering an object.
|
|
///
|
|
/// // Method 1:
|
|
/// AIClient *aiPlayer = new AIClient();
|
|
/// aiPlayer->registerObject();
|
|
///
|
|
/// // Method 2:
|
|
/// ActionMap* globalMap = new ActionMap;
|
|
/// globalMap->registerObject("GlobalActionMap");
|
|
///
|
|
/// // Method 3:
|
|
/// bool reg = mObj->registerObject(id);
|
|
/// @endcode
|
|
///
|
|
/// Registering a SimObject performs these tasks:
|
|
/// - Marks the object as not cleared and not removed.
|
|
/// - Assigns the object a unique SimObjectID if it does not have one already.
|
|
/// - Adds the object to the global name and ID dictionaries so it can be found
|
|
/// again.
|
|
/// - Calls the object's onAdd() method. <b>Note:</b> SimObject::onAdd() performs
|
|
/// some important initialization steps. See @ref simobject_subclassing "here
|
|
/// for details" on how to properly subclass SimObject.
|
|
/// - If onAdd() fails (returns false), it calls unregisterObject().
|
|
/// - Checks to make sure that the SimObject was properly initialized (and asserts
|
|
/// if not).
|
|
///
|
|
/// Calling registerObject() and passing an ID or a name will cause the object to be
|
|
/// assigned that name and/or ID before it is registered.
|
|
///
|
|
/// Congratulations, you have now registered your object! What now?
|
|
///
|
|
/// Well, hopefully, the SimObject will have a long, useful life. But eventually,
|
|
/// it must die.
|
|
///
|
|
/// There are a two ways a SimObject can die.
|
|
/// - First, the game can be shut down. This causes the root SimGroup
|
|
/// to be unregistered and deleted. When a SimGroup is unregistered,
|
|
/// it unregisters all of its member SimObjects; this results in everything
|
|
/// that has been registered with Sim being unregistered, as everything
|
|
/// registered with Sim is in the root group.
|
|
/// - Second, you can manually kill it off, either by calling unregisterObject()
|
|
/// or by calling deleteObject().
|
|
///
|
|
/// When you unregister a SimObject, the following tasks are performed:
|
|
/// - The object is flagged as removed.
|
|
/// - Notifications are cleaned up.
|
|
/// - If the object is in a group, then it removes itself from the group.
|
|
/// - Delete notifications are sent out.
|
|
/// - Finally, the object removes itself from the Sim globals, and tells
|
|
/// Sim to get rid of any pending events for it.
|
|
///
|
|
/// If you call deleteObject(), all of the above tasks are performed, in addition
|
|
/// to some sanity checking to make sure the object was previously added properly,
|
|
/// and isn't in the process of being deleted. After the object is unregistered, it
|
|
/// deallocates itself.
|
|
///
|
|
/// @section simobject_editor Torque Editors
|
|
///
|
|
/// SimObjects are one of the building blocks for the in-game editors. They
|
|
/// provide a basic interface for the editor to be able to list the fields
|
|
/// of the object, update them safely and reliably, and inform the object
|
|
/// things have changed.
|
|
///
|
|
/// This interface is implemented in the following areas:
|
|
/// - onNameChange() is called when the object is renamed.
|
|
/// - onStaticModified() is called whenever a static field is modified.
|
|
/// - inspectPreApply() is called before the object's fields are updated,
|
|
/// when changes are being applied.
|
|
/// - inspectPostApply() is called after the object's fields are updated.
|
|
/// - onEditorEnable() is called whenever an editor is enabled (for instance,
|
|
/// when you hit F11 to bring up the world editor).
|
|
/// - onEditorDisable() is called whenever the editor is disabled (for instance,
|
|
/// when you hit F11 again to close the world editor).
|
|
///
|
|
/// (Note: you can check the variable gEditingMission to see if the mission editor
|
|
/// is running; if so, you may want to render special indicators. For instance, the
|
|
/// fxFoliageReplicator renders inner and outer radii when the mission editor is
|
|
/// runnning.)
|
|
///
|
|
/// @section simobject_console The Console
|
|
///
|
|
/// SimObject extends ConsoleObject by allowing you to
|
|
/// to set arbitrary dynamic fields on the object, as well as
|
|
/// statically defined fields. This is done through two methods,
|
|
/// setDataField and getDataField, which deal with the complexities of
|
|
/// allowing access to two different types of object fields.
|
|
///
|
|
/// Static fields take priority over dynamic fields. This is to be
|
|
/// expected, as the role of dynamic fields is to allow data to be
|
|
/// stored in addition to the predefined fields.
|
|
///
|
|
/// The fields in a SimObject are like properties (or fields) in a class.
|
|
///
|
|
/// Some fields may be arrays, which is what the array parameter is for; if it's non-null,
|
|
/// then it is parsed with dAtoI and used as an index into the array. If you access something
|
|
/// as an array which isn't, then you get an empty string.
|
|
///
|
|
/// <b>You don't need to read any further than this.</b> Right now,
|
|
/// set/getDataField are called a total of 6 times through the entire
|
|
/// Torque codebase. Therefore, you probably don't need to be familiar
|
|
/// with the details of accessing them. You may want to look at Con::setData
|
|
/// instead. Most of the time you will probably be accessing fields directly,
|
|
/// or using the scripting language, which in either case means you don't
|
|
/// need to do anything special.
|
|
///
|
|
/// The functions to get/set these fields are very straightforward:
|
|
///
|
|
/// @code
|
|
/// setDataField(StringTable->insert("locked", false), NULL, b ? "true" : "false" );
|
|
/// curObject->setDataField(curField, curFieldArray, STR.getStringValue());
|
|
/// setDataField(slotName, array, value);
|
|
/// @endcode
|
|
///
|
|
/// <i>For advanced users:</i> There are two flags which control the behavior
|
|
/// of these functions. The first is ModStaticFields, which controls whether
|
|
/// or not the DataField functions look through the static fields (defined
|
|
/// with addField; see ConsoleObject for details) of the class. The second
|
|
/// is ModDynamicFields, which controls dynamically defined fields. They are
|
|
/// set automatically by the console constructor code.
|
|
///
|
|
/// @nosubgrouping
|
|
class SimObject: public ConsoleObject, public TamlCallbacks
|
|
{
|
|
public:
|
|
|
|
typedef ConsoleObject Parent;
|
|
|
|
friend class SimManager;
|
|
friend class SimGroup;
|
|
friend class SimNameDictionary;
|
|
friend class SimManagerNameDictionary;
|
|
friend class SimIdDictionary;
|
|
|
|
/// @name Notification
|
|
/// @{
|
|
|
|
struct Notify
|
|
{
|
|
enum Type
|
|
{
|
|
ClearNotify, ///< Notified when the object is cleared.
|
|
DeleteNotify, ///< Notified when the object is deleted.
|
|
ObjectRef, ///< Cleverness to allow tracking of references.
|
|
Invalid ///< Mark this notification as unused (used in freeNotify).
|
|
} type;
|
|
|
|
void *ptr; ///< Data (typically referencing or interested object).
|
|
Notify *next; ///< Next notification in the linked list.
|
|
};
|
|
|
|
/// @}
|
|
|
|
/// Flags passed to SimObject::write
|
|
enum WriteFlags
|
|
{
|
|
SelectedOnly = BIT( 0 ), ///< Indicates that only objects marked as selected should be outputted. Used in SimSet.
|
|
NoName = BIT( 1 ), ///< Indicates that the object name should not be saved.
|
|
IgnoreCanSave = BIT( 2 ), ///< Write out even if CannotSave=true.
|
|
};
|
|
|
|
private:
|
|
|
|
/// Flags for use in mFlags
|
|
enum
|
|
{
|
|
Deleted = BIT( 0 ), ///< This object is marked for deletion.
|
|
Removed = BIT( 1 ), ///< This object has been unregistered from the object system.
|
|
Added = BIT( 3 ), ///< This object has been registered with the object system.
|
|
Selected = BIT( 4 ), ///< This object has been marked as selected. (in editor)
|
|
Expanded = BIT( 5 ), ///< This object has been marked as expanded. (in editor)
|
|
ModStaticFields = BIT( 6 ), ///< The object allows you to read/modify static fields
|
|
ModDynamicFields = BIT( 7 ), ///< The object allows you to read/modify dynamic fields
|
|
AutoDelete = BIT( 8 ), ///< Delete this object when the last ObjectRef is gone.
|
|
CannotSave = BIT( 9 ), ///< Object should not be saved.
|
|
EditorOnly = BIT( 10 ), ///< This object is for use by the editor only.
|
|
NoNameChange = BIT( 11 ), ///< Whether changing the name of this object is allowed.
|
|
Hidden = BIT( 12 ), ///< Object is hidden in editors.
|
|
Locked = BIT( 13 ), ///< Object is locked in editors.
|
|
};
|
|
|
|
// dictionary information stored on the object
|
|
StringTableEntry mObjectName;
|
|
StringTableEntry mOriginalName;
|
|
SimObject* nextNameObject;
|
|
SimObject* nextManagerNameObject;
|
|
SimObject* nextIdObject;
|
|
|
|
StringTableEntry mInheritFrom;
|
|
|
|
/// SimGroup we're contained in, if any.
|
|
SimGroup* mGroup;
|
|
|
|
/// Flags internal to the object management system.
|
|
BitSet32 mFlags;
|
|
|
|
StringTableEntry mProgenitorFile;
|
|
|
|
/// Object we are copying fields from.
|
|
SimObject* mCopySource;
|
|
|
|
/// Table of dynamic fields assigned to this object.
|
|
SimFieldDictionary *mFieldDictionary;
|
|
|
|
/// Buffer to store textual representation of this object's numeric ID in.
|
|
char mIdString[ 11 ];
|
|
|
|
/// @name Serialization
|
|
/// @{
|
|
|
|
/// Path to file this SimObject was loaded from.
|
|
StringTableEntry mFilename;
|
|
|
|
/// The line number that the object was declared on if it was loaded from a file.
|
|
S32 mDeclarationLine;
|
|
|
|
/// @}
|
|
|
|
/// @name Notification
|
|
/// @{
|
|
|
|
/// List of notifications added to this object.
|
|
Notify* mNotifyList;
|
|
|
|
static SimObject::Notify *mNotifyFreeList;
|
|
static SimObject::Notify *allocNotify(); ///< Get a free Notify structure.
|
|
static void freeNotify(SimObject::Notify*); ///< Mark a Notify structure as free.
|
|
|
|
/// @}
|
|
|
|
static bool _setCanSave( void* object, const char* index, const char* data );
|
|
static const char* _getCanSave( void* object, const char* data );
|
|
|
|
static const char* _getHidden( void* object, const char* data )
|
|
{ if( static_cast< SimObject* >( object )->isHidden() ) return "1"; return "0"; }
|
|
static const char* _getLocked( void* object, const char* data )
|
|
{ if( static_cast< SimObject* >( object )->isLocked() ) return "1"; return "0"; }
|
|
static bool _setHidden( void* object, const char* index, const char* data )
|
|
{ static_cast< SimObject* >( object )->setHidden( dAtob( data ) ); return false; }
|
|
static bool _setLocked( void* object, const char* index, const char* data )
|
|
{ static_cast< SimObject* >( object )->setLocked( dAtob( data ) ); return false; }
|
|
|
|
// Namespace protected set methods
|
|
static bool setClass( void *object, const char *index, const char *data )
|
|
{ static_cast<SimObject*>(object)->setClassNamespace(data); return false; };
|
|
static bool setSuperClass(void *object, const char *index, const char *data)
|
|
{ static_cast<SimObject*>(object)->setSuperClassNamespace(data); return false; };
|
|
|
|
static bool writeObjectName(void* obj, StringTableEntry pFieldName)
|
|
{ SimObject* simObject = static_cast<SimObject*>(obj); return simObject->mObjectName != NULL && simObject->mObjectName != StringTable->EmptyString(); }
|
|
static bool writeCanSaveDynamicFields(void* obj, StringTableEntry pFieldName)
|
|
{ return static_cast<SimObject*>(obj)->mCanSaveFieldDictionary == false; }
|
|
static bool writeInternalName(void* obj, StringTableEntry pFieldName)
|
|
{ SimObject* simObject = static_cast<SimObject*>(obj); return simObject->mInternalName != NULL && simObject->mInternalName != StringTable->EmptyString(); }
|
|
static bool setParentGroup(void* obj, const char* data);
|
|
static bool writeParentGroup(void* obj, StringTableEntry pFieldName)
|
|
{ return static_cast<SimObject*>(obj)->mGroup != NULL; }
|
|
static bool writeSuperclass(void* obj, StringTableEntry pFieldName)
|
|
{ SimObject* simObject = static_cast<SimObject*>(obj); return simObject->mSuperClassName != NULL && simObject->mSuperClassName != StringTable->EmptyString(); }
|
|
static bool writeClass(void* obj, StringTableEntry pFieldName)
|
|
{ SimObject* simObject = static_cast<SimObject*>(obj); return simObject->mClassName != NULL && simObject->mClassName != StringTable->EmptyString(); }
|
|
static bool writeClassName(void* obj, StringTableEntry pFieldName)
|
|
{ SimObject* simObject = static_cast<SimObject*>(obj); return simObject->mClassName != NULL && simObject->mClassName != StringTable->EmptyString(); }
|
|
|
|
|
|
// Group hierarchy protected set method
|
|
static bool setProtectedParent(void *object, const char *index, const char *data);
|
|
|
|
// Object name protected set method
|
|
static bool setProtectedName(void *object, const char *index, const char *data);
|
|
|
|
// Sets object to inherit default values from
|
|
static bool setInheritFrom(void* object, const char* index, const char* data);
|
|
|
|
public:
|
|
inline void setProgenitorFile(const char* pFile) { mProgenitorFile = StringTable->insert(pFile); }
|
|
inline StringTableEntry getProgenitorFile(void) const { return mProgenitorFile; }
|
|
|
|
protected:
|
|
/// Taml callbacks.
|
|
virtual void onTamlPreWrite(void) {}
|
|
virtual void onTamlPostWrite(void) {}
|
|
virtual void onTamlPreRead(void) {}
|
|
virtual void onTamlPostRead(const TamlCustomNodes& customNodes) {}
|
|
virtual void onTamlAddParent(SimObject* pParentObject) {}
|
|
virtual void onTamlCustomWrite(TamlCustomNodes& customNodes) {}
|
|
virtual void onTamlCustomRead(const TamlCustomNodes& customNodes);
|
|
|
|
/// Id number for this object.
|
|
SimObjectId mId;
|
|
|
|
/// Internal name assigned to the object. Not set by default.
|
|
StringTableEntry mInternalName;
|
|
|
|
static bool smForceId; ///< Force a registered object to use the given Id. Cleared upon use.
|
|
static SimObjectId smForcedId; ///< The Id to force upon the object. Poor object.
|
|
|
|
/// @name Serialization
|
|
/// @{
|
|
|
|
/// Whether dynamic fields should be saved out in serialization. Defaults to true.
|
|
bool mCanSaveFieldDictionary;
|
|
|
|
/// @}
|
|
|
|
/// @name Persistent IDs
|
|
/// @{
|
|
|
|
/// Persistent ID assigned to this object. Allows to unambiguously refer to this
|
|
/// object in serializations regardless of stream object ordering.
|
|
SimPersistID* mPersistentId;
|
|
|
|
static bool _setPersistentID( void* object, const char* index, const char* data );
|
|
|
|
/// @}
|
|
|
|
/// @name Namespace management
|
|
/// @{
|
|
|
|
/// The namespace in which method lookup for this object begins.
|
|
Namespace* mNameSpace;
|
|
|
|
/// Name of namespace to use as class namespace.
|
|
StringTableEntry mClassName;
|
|
|
|
/// Name of namespace to use as class super namespace.
|
|
StringTableEntry mSuperClassName;
|
|
|
|
/// Perform namespace linking on this object.
|
|
void linkNamespaces();
|
|
|
|
/// Undo namespace linking on this object.
|
|
void unlinkNamespaces();
|
|
|
|
/// @}
|
|
|
|
/// Called when the object is selected in the editor.
|
|
virtual void _onSelected() {}
|
|
|
|
/// Called when the object is unselected in the editor.
|
|
virtual void _onUnselected() {}
|
|
|
|
/// We can provide more detail, like object name and id.
|
|
virtual String _getLogMessage(const char* fmt, va_list args) const;
|
|
|
|
DEFINE_CREATE_METHOD
|
|
{
|
|
T* object = new T;
|
|
object->incRefCount();
|
|
return object;
|
|
}
|
|
|
|
|
|
// EngineObject.
|
|
virtual void _destroySelf();
|
|
|
|
public:
|
|
|
|
/// @name Cloning
|
|
/// @{
|
|
|
|
/// Return a shallow copy of this object.
|
|
virtual SimObject* clone();
|
|
|
|
/// Return a deep copy of this object.
|
|
virtual SimObject* deepClone();
|
|
|
|
/// @}
|
|
|
|
/// @name Accessors
|
|
/// @{
|
|
|
|
/// Get the value of a field on the object.
|
|
///
|
|
/// See @ref simobject_console "here" for a detailed discussion of what this
|
|
/// function does.
|
|
///
|
|
/// @param slotName Field to access.
|
|
/// @param array String containing index into array
|
|
/// (if field is an array); if NULL, it is ignored.
|
|
const char *getDataField(StringTableEntry slotName, const char *array);
|
|
|
|
/// Set the value of a field on the object.
|
|
///
|
|
/// See @ref simobject_console "here" for a detailed discussion of what this
|
|
/// function does.
|
|
///
|
|
/// @param slotName Field to access.
|
|
/// @param array String containing index into array; if NULL, it is ignored.
|
|
/// @param value Value to store.
|
|
void setDataField(StringTableEntry slotName, const char *array, const char *value);
|
|
|
|
const char *getPrefixedDataField(StringTableEntry fieldName, const char *array);
|
|
|
|
void setPrefixedDataField(StringTableEntry fieldName, const char *array, const char *value);
|
|
|
|
const char *getPrefixedDynamicDataField(StringTableEntry fieldName, const char *array, const S32 fieldType = -1);
|
|
|
|
void setPrefixedDynamicDataField(StringTableEntry fieldName, const char *array, const char *value, const S32 fieldType = -1);
|
|
|
|
StringTableEntry getDataFieldPrefix(StringTableEntry fieldName);
|
|
|
|
/// Get the type of a field on the object.
|
|
///
|
|
/// @param slotName Field to access.
|
|
/// @param array String containing index into array
|
|
/// (if field is an array); if NULL, it is ignored.
|
|
U32 getDataFieldType(StringTableEntry slotName, const char *array);
|
|
|
|
/// Set the type of a *dynamic* field on the object.
|
|
///
|
|
/// @param typeName/Id Console base type name/id to assign to a dynamic field.
|
|
/// @param slotName Field to access.
|
|
/// @param array String containing index into array
|
|
/// (if field is an array); if NULL, it is ignored.
|
|
void setDataFieldType(const U32 fieldTypeId, StringTableEntry slotName, const char *array);
|
|
void setDataFieldType(const char *typeName, StringTableEntry slotName, const char *array);
|
|
|
|
/// Get reference to the dictionary containing dynamic fields.
|
|
///
|
|
/// See @ref simobject_console "here" for a detailed discussion of what this
|
|
/// function does.
|
|
///
|
|
/// This dictionary can be iterated over using a SimFieldDictionaryIterator.
|
|
SimFieldDictionary * getFieldDictionary() {return(mFieldDictionary);}
|
|
|
|
// Component Information
|
|
inline virtual StringTableEntry getComponentName() { return StringTable->insert( getClassName() ); };
|
|
|
|
/// These functions support internal naming that is not namespace
|
|
/// bound for locating child controls in a generic way.
|
|
///
|
|
/// Set the internal name of this control (Not linked to a namespace)
|
|
void setInternalName(const char* newname);
|
|
|
|
/// Get the internal name of this control
|
|
StringTableEntry getInternalName() const { return mInternalName; }
|
|
|
|
/// Set the original name of this control
|
|
void setOriginalName(const char* originalName);
|
|
|
|
/// Get the original name of this control
|
|
StringTableEntry getOriginalName() const { return mOriginalName; }
|
|
|
|
/// These functions allow you to set and access the filename
|
|
/// where this object was created.
|
|
///
|
|
/// Set the filename
|
|
void setFilename(const char* file);
|
|
|
|
/// Get the filename
|
|
StringTableEntry getFilename() const { return mFilename; }
|
|
|
|
/// These functions are used to track the line number (1-based)
|
|
/// on which the object was created if it was loaded from script
|
|
///
|
|
/// Set the declaration line number
|
|
void setDeclarationLine(U32 lineNumber);
|
|
|
|
/// Get the declaration line number
|
|
S32 getDeclarationLine() const { return mDeclarationLine; }
|
|
|
|
/// Save object as a TorqueScript File.
|
|
virtual bool save( const char* pcFilePath, bool bOnlySelected = false, const char *preappend = NULL );
|
|
|
|
/// Check if a method exists in the objects current namespace.
|
|
virtual bool isMethod( const char* methodName );
|
|
|
|
/// Return true if the field is defined on the object
|
|
virtual bool isField( const char* fieldName, bool includeStatic = true, bool includeDynamic = true );
|
|
|
|
/// @}
|
|
|
|
/// @name Initialization
|
|
/// @{
|
|
|
|
///
|
|
SimObject();
|
|
|
|
virtual ~SimObject();
|
|
|
|
virtual bool processArguments(S32 argc, ConsoleValue *argv); ///< Process constructor options. (ie, new SimObject(1,2,3))
|
|
|
|
/// @}
|
|
|
|
/// @name Events
|
|
/// @{
|
|
|
|
/// Called when the object is added to the sim.
|
|
virtual bool onAdd();
|
|
|
|
/// Called when the object is removed from the sim.
|
|
virtual void onRemove();
|
|
|
|
/// Called when the object is added to a SimGroup.
|
|
virtual void onGroupAdd();
|
|
|
|
/// Called when the object is removed from a SimGroup.
|
|
virtual void onGroupRemove();
|
|
|
|
/// Called when the object's name is changed.
|
|
virtual void onNameChange(const char *name);
|
|
|
|
/// Called when the adding of the object to the sim is complete, all sub-objects have been processed as well
|
|
// This is a special-case function that only really gets used with Entities/BehaviorObjects.
|
|
virtual void onPostAdd() {}
|
|
|
|
///
|
|
/// Specifically, these are called by setDataField
|
|
/// when a static or dynamic field is modified, see
|
|
/// @ref simobject_console "the console details".
|
|
virtual void onStaticModified(const char* slotName, const char*newValue = NULL); ///< Called when a static field is modified.
|
|
virtual void onDynamicModified(const char* slotName, const char*newValue = NULL); ///< Called when a dynamic field is modified.
|
|
|
|
/// Called before any property of the object is changed in the world editor.
|
|
///
|
|
/// The calling order here is:
|
|
/// - inspectPreApply()
|
|
/// - ...
|
|
/// - calls to setDataField()
|
|
/// - ...
|
|
/// - inspectPostApply()
|
|
virtual void inspectPreApply();
|
|
|
|
/// Called after any property of the object is changed in the world editor.
|
|
///
|
|
/// @see inspectPreApply
|
|
virtual void inspectPostApply();
|
|
|
|
/// Called when a SimObject is deleted.
|
|
///
|
|
/// When you are on the notification list for another object
|
|
/// and it is deleted, this method is called.
|
|
virtual void onDeleteNotify(SimObject *object);
|
|
|
|
/// Called when the editor is activated.
|
|
virtual void onEditorEnable(){};
|
|
|
|
/// Called when the editor is deactivated.
|
|
virtual void onEditorDisable(){};
|
|
|
|
/// Called when the object is inspected via a GuiInspector control
|
|
virtual void onInspect(GuiInspector*);
|
|
|
|
/// @}
|
|
|
|
/// Find a named sub-object of this object.
|
|
///
|
|
/// This is subclassed in the SimGroup and SimSet classes.
|
|
///
|
|
/// For a single object, it just returns NULL, as normal objects cannot have children.
|
|
virtual SimObject *findObject(const char *name);
|
|
|
|
/// @name Notification
|
|
/// @{
|
|
|
|
Notify *removeNotify(void *ptr, Notify::Type); ///< Remove a notification from the list.
|
|
void deleteNotify(SimObject* obj); ///< Notify an object when we are deleted.
|
|
void clearNotify(SimObject* obj); ///< Notify an object when we are cleared.
|
|
void clearAllNotifications(); ///< Remove all notifications for this object.
|
|
void processDeleteNotifies(); ///< Send out deletion notifications.
|
|
|
|
/// Register a reference to this object.
|
|
///
|
|
/// You pass a pointer to your reference to this object.
|
|
///
|
|
/// When the object is deleted, it will null your
|
|
/// pointer, ensuring you don't access old memory.
|
|
///
|
|
/// @param obj Pointer to your reference to the object.
|
|
void registerReference(SimObject **obj);
|
|
|
|
/// Unregister a reference to this object.
|
|
///
|
|
/// Remove a reference from the list, so that it won't
|
|
/// get nulled inappropriately.
|
|
///
|
|
/// Call this when you're done with your reference to
|
|
/// the object, especially if you're going to free the
|
|
/// memory. Otherwise, you may erroneously get something
|
|
/// overwritten.
|
|
///
|
|
/// @see registerReference
|
|
void unregisterReference(SimObject **obj);
|
|
|
|
/// @}
|
|
|
|
/// @name Registration
|
|
///
|
|
/// SimObjects must be registered with the object system.
|
|
/// @{
|
|
|
|
/// Register an object with the object system.
|
|
///
|
|
/// This must be called if you want to keep the object around.
|
|
/// In the rare case that you will delete the object immediately, or
|
|
/// don't want to be able to use Sim::findObject to locate it, then
|
|
/// you don't need to register it.
|
|
///
|
|
/// registerObject adds the object to the global ID and name dictionaries,
|
|
/// after first assigning it a new ID number. It calls onAdd(). If onAdd fails,
|
|
/// it unregisters the object and returns false.
|
|
///
|
|
/// If a subclass's onAdd doesn't eventually call SimObject::onAdd(), it will
|
|
/// cause an assertion.
|
|
bool registerObject();
|
|
|
|
/// Register the object, forcing the id.
|
|
///
|
|
/// @see registerObject()
|
|
/// @param id ID to assign to the object.
|
|
bool registerObject(U32 id);
|
|
|
|
/// Register the object, assigning the name.
|
|
///
|
|
/// @see registerObject()
|
|
/// @param name Name to assign to the object.
|
|
bool registerObject(const char *name);
|
|
|
|
/// Register the object, assigning the name.
|
|
///
|
|
/// @see registerObject()
|
|
/// @param name Name to assign to the object.
|
|
bool registerObject(const String& name);
|
|
|
|
/// Register the object, assigning a name and ID.
|
|
///
|
|
/// @see registerObject()
|
|
/// @param name Name to assign to the object.
|
|
/// @param id ID to assign to the object.
|
|
bool registerObject(const char *name, U32 id);
|
|
|
|
/// Unregister the object from Sim.
|
|
///
|
|
/// This performs several operations:
|
|
/// - Sets the removed flag.
|
|
/// - Call onRemove()
|
|
/// - Clear out notifications.
|
|
/// - Remove the object from...
|
|
/// - its group, if any. (via getGroup)
|
|
/// - Sim::gNameDictionary
|
|
/// - Sim::gIDDictionary
|
|
/// - Finally, cancel any pending events for this object (as it can't receive them now).
|
|
void unregisterObject();
|
|
|
|
/// Unregister, mark as deleted, and free the object.
|
|
void deleteObject();
|
|
|
|
/// Performs a safe delayed delete of the object using a sim event.
|
|
void safeDeleteObject();
|
|
|
|
/// Special-case deletion behaviors, largely intended for cleanup in particular cases where it wouldn't happen automatically(like cleanup of associated files)
|
|
virtual void handleDeleteAction() {}
|
|
|
|
/// @}
|
|
|
|
/// @name Accessors
|
|
/// @{
|
|
|
|
/// Return the unique numeric object ID.
|
|
SimObjectId getId() const { return mId; }
|
|
|
|
/// Return the object ID as a string.
|
|
const char* getIdString() const { return mIdString; }
|
|
|
|
/// Return the name of this object.
|
|
StringTableEntry getName() const { return mObjectName; }
|
|
|
|
/// Return the SimGroup that this object is contained in. Never NULL except for
|
|
/// RootGroup and unregistered objects.
|
|
SimGroup* getGroup() const { return mGroup; }
|
|
|
|
/// Assign the given name to this object.
|
|
void assignName( const char* name );
|
|
|
|
void setId(SimObjectId id);
|
|
static void setForcedId(SimObjectId id) { smForceId = true; smForcedId = id; } ///< Force an Id on the next registered object.
|
|
bool isChildOfGroup(SimGroup* pGroup);
|
|
bool isProperlyAdded() const { return mFlags.test(Added); }
|
|
bool isDeleted() const { return mFlags.test(Deleted); }
|
|
bool isRemoved() const { return mFlags.test(Deleted | Removed); }
|
|
|
|
virtual bool isLocked() const { return mFlags.test( Locked ); }
|
|
virtual void setLocked( bool b );
|
|
virtual bool isHidden() const { return mFlags.test( Hidden ); }
|
|
virtual void setHidden(bool b);
|
|
|
|
/// @}
|
|
|
|
/// @name Sets
|
|
///
|
|
/// The object must be properly registered before you can add/remove it to/from a set.
|
|
///
|
|
/// All these functions accept either a name or ID to identify the set you wish
|
|
/// to operate on. Then they call addObject or removeObject on the set, which
|
|
/// sets up appropriate notifications.
|
|
///
|
|
/// An object may be in multiple sets at a time.
|
|
/// @{
|
|
bool addToSet(SimObjectId);
|
|
bool addToSet(const char *);
|
|
bool removeFromSet(SimObjectId);
|
|
bool removeFromSet(const char *);
|
|
|
|
/// @}
|
|
|
|
/// @name Serialization
|
|
/// @{
|
|
|
|
/// Determine whether or not a field should be written.
|
|
///
|
|
/// @param fiedname The name of the field being written.
|
|
/// @param value The value of the field.
|
|
virtual bool writeField(StringTableEntry fieldname, const char* value);
|
|
|
|
/// Output the TorqueScript to recreate this object.
|
|
///
|
|
/// This calls writeFields internally.
|
|
/// @param stream Stream to output to.
|
|
/// @param tabStop Indentation level for this object.
|
|
/// @param flags If SelectedOnly is passed here, then
|
|
/// only objects marked as selected (using setSelected)
|
|
/// will output themselves.
|
|
virtual void write(Stream &stream, U32 tabStop, U32 flags = 0);
|
|
|
|
/// Write the fields of this object in TorqueScript.
|
|
///
|
|
/// @param stream Stream for output.
|
|
/// @param tabStop Indentation level for the fields.
|
|
virtual void writeFields(Stream &stream, U32 tabStop);
|
|
|
|
virtual bool writeObject(Stream *stream);
|
|
virtual bool readObject(Stream *stream);
|
|
|
|
/// Set whether fields created at runtime should be saved. Default is true.
|
|
void setCanSaveDynamicFields( bool bCanSave ) { mCanSaveFieldDictionary = bCanSave; }
|
|
|
|
/// Get whether fields created at runtime should be saved. Default is true.
|
|
bool getCanSaveDynamicFields( ) { return mCanSaveFieldDictionary;}
|
|
|
|
/// Return the object that this object is copying fields from.
|
|
SimObject* getCopySource() const { return mCopySource; }
|
|
|
|
/// Set the object that this object should be copying fields from.
|
|
void setCopySource( SimObject* object );
|
|
|
|
/// Copy fields from another object onto this one.
|
|
///
|
|
/// Objects must be of same type. Everything from obj
|
|
/// will overwrite what's in this object; extra fields
|
|
/// in this object will remain. This includes dynamic
|
|
/// fields.
|
|
///
|
|
/// @param obj Object to copy from.
|
|
void assignFieldsFrom(SimObject *obj);
|
|
|
|
/// Copy dynamic fields from another object onto this one.
|
|
///
|
|
/// Everything from obj will overwrite what's in this
|
|
/// object.
|
|
///
|
|
/// @param obj Object to copy from.
|
|
void assignDynamicFieldsFrom(SimObject *obj);
|
|
|
|
/// @}
|
|
|
|
/// Return the object's namespace.
|
|
Namespace* getNamespace() { return mNameSpace; }
|
|
|
|
/// Get next matching item in namespace.
|
|
///
|
|
/// This wraps a call to Namespace::tabComplete; it gets the
|
|
/// next thing in the namespace, given a starting value
|
|
/// and a base length of the string. See
|
|
/// Namespace::tabComplete for details.
|
|
const char *tabComplete(const char *prevText, S32 baseLen, bool);
|
|
|
|
/// @name Accessors
|
|
/// @{
|
|
|
|
bool isSelected() const { return mFlags.test(Selected); }
|
|
bool isExpanded() const { return mFlags.test(Expanded); }
|
|
bool isEditorOnly() const { return mFlags.test( EditorOnly ); }
|
|
bool isNameChangeAllowed() const { return !mFlags.test( NoNameChange ); }
|
|
bool isAutoDeleted() const { return mFlags.test( AutoDelete ); }
|
|
void setSelected(bool sel);
|
|
void setExpanded(bool exp) { if(exp) mFlags.set(Expanded); else mFlags.clear(Expanded); }
|
|
void setModDynamicFields(bool dyn) { if(dyn) mFlags.set(ModDynamicFields); else mFlags.clear(ModDynamicFields); }
|
|
void setModStaticFields(bool sta) { if(sta) mFlags.set(ModStaticFields); else mFlags.clear(ModStaticFields); }
|
|
bool canModDynamicFields() { return mFlags.test(ModDynamicFields); }
|
|
bool canModStaticFields() { return mFlags.test(ModStaticFields); }
|
|
void setAutoDelete( bool val ) { if( val ) mFlags.set( AutoDelete ); else mFlags.clear( AutoDelete ); }
|
|
void setEditorOnly( bool val ) { if( val ) mFlags.set( EditorOnly ); else mFlags.clear( EditorOnly ); }
|
|
void setNameChangeAllowed( bool val ) { if( val ) mFlags.clear( NoNameChange ); else mFlags.set( NoNameChange ); }
|
|
|
|
/// Returns boolean specifying if the object can be serialized.
|
|
bool getCanSave() const { return !mFlags.test( CannotSave ); }
|
|
|
|
/// Set serialization flag.
|
|
virtual void setCanSave( bool val ) { if( !val ) mFlags.set( CannotSave ); else mFlags.clear( CannotSave ); }
|
|
|
|
/// Returns true if this object is selected or any group it is a member of is.
|
|
bool isSelectedRecursive() const;
|
|
|
|
/// @}
|
|
|
|
/// @name Namespace management
|
|
/// @{
|
|
|
|
/// Return name of class namespace set on this object.
|
|
StringTableEntry getClassNamespace() const { return mClassName; };
|
|
|
|
/// Return name of superclass namespace set on this object.
|
|
StringTableEntry getSuperClassNamespace() const { return mSuperClassName; };
|
|
|
|
///
|
|
void setClassNamespace( const char* classNamespace );
|
|
|
|
///
|
|
void setSuperClassNamespace( const char* superClassNamespace );
|
|
|
|
/// @}
|
|
|
|
/// @name Persistent IDs
|
|
/// @{
|
|
|
|
/// Return the persistent ID assigned to this object or NULL.
|
|
SimPersistID* getPersistentId() const { return mPersistentId; }
|
|
|
|
/// Return the persistent ID assigned to this object or assign one to it if it has none.
|
|
SimPersistID* getOrCreatePersistentId();
|
|
|
|
/// @}
|
|
|
|
/// @name Debugging
|
|
/// @{
|
|
|
|
/// Return a textual description of the object.
|
|
virtual String describeSelf() const;
|
|
|
|
/// Dump the contents of this object to the console. Use the Torque Script dump() and dumpF() functions to
|
|
/// call this.
|
|
void dumpToConsole( bool includeFunctions=true );
|
|
|
|
///added this so that you can print the entire class hierarchy, including script objects,
|
|
//from the console or C++.
|
|
|
|
/// Print the AbstractClassRep hierarchy of this object to the console.
|
|
virtual void dumpClassHierarchy();
|
|
|
|
/// Print the SimGroup hierarchy of this object to the console.
|
|
virtual void dumpGroupHierarchy();
|
|
|
|
/// @}
|
|
|
|
static void initPersistFields();
|
|
|
|
/// Copy SimObject to another SimObject (Originally designed for T2D).
|
|
virtual void copyTo(SimObject* object);
|
|
|
|
// Component Console Overrides
|
|
virtual bool handlesConsoleMethod(const char * fname, S32 * routingId) { return false; }
|
|
virtual void getConsoleMethodData(const char * fname, S32 routingId, S32 * type, S32 * minArgs, S32 * maxArgs, void ** callback, const char ** usage) {}
|
|
|
|
DECLARE_CONOBJECT( SimObject );
|
|
DECLARE_CALLBACK(void, onInspectPostApply, (SimObject* obj));
|
|
|
|
static SimObject* __findObject( const char* id ) { return Sim::findObject( id ); }
|
|
static const char* __getObjectId( ConsoleObject* object )
|
|
{
|
|
SimObject* simObject = static_cast< SimObject* >( object );
|
|
if( !simObject )
|
|
return "";
|
|
else if( simObject->getName() )
|
|
return simObject->getName();
|
|
return simObject->getIdString();
|
|
}
|
|
|
|
// EngineObject.
|
|
virtual void destroySelf();
|
|
protected:
|
|
bool is_temp_clone;
|
|
public:
|
|
/*C*/ SimObject(const SimObject&, bool = false);
|
|
bool isTempClone() const { return is_temp_clone; }
|
|
virtual bool allowSubstitutions() const { return false; }
|
|
|
|
public:
|
|
static bool preventNameChanging;
|
|
void assignDynamicFieldsFrom(SimObject*, const char* filter, bool no_replace=false);
|
|
|
|
public:
|
|
virtual void reloadReset() { }
|
|
};
|
|
|
|
|
|
/// Smart SimObject pointer.
|
|
///
|
|
/// This class keeps track of the book-keeping necessary
|
|
/// to keep a registered reference to a SimObject or subclass
|
|
/// thereof.
|
|
///
|
|
/// Normally, if you want the SimObject to be aware that you
|
|
/// have a reference to it, you must call SimObject::registerReference()
|
|
/// when you create the reference, and SimObject::unregisterReference() when
|
|
/// you're done. If you change the reference, you must also register/unregister
|
|
/// it. This is a big headache, so this class exists to automatically
|
|
/// keep track of things for you.
|
|
///
|
|
/// @code
|
|
/// // Assign an object to the
|
|
/// SimObjectPtr<GameBase> mOrbitObject = Sim::findObject("anObject");
|
|
///
|
|
/// // Use it as a GameBase*.
|
|
/// mOrbitObject->getWorldBox().getCenter(&mPosition);
|
|
///
|
|
/// // And reassign it - it will automatically update the references.
|
|
/// mOrbitObject = Sim::findObject("anotherObject");
|
|
/// @endcode
|
|
template< typename T >
|
|
class SimObjectPtr : public WeakRefPtr< T >
|
|
{
|
|
public:
|
|
|
|
typedef WeakRefPtr< T > Parent;
|
|
|
|
SimObjectPtr() {}
|
|
SimObjectPtr(T *ptr) { this->mReference = NULL; set(ptr); }
|
|
SimObjectPtr( const SimObjectPtr& ref ) { this->mReference = NULL; set(ref.mReference); }
|
|
|
|
T* getObject() const { return Parent::getPointer(); }
|
|
|
|
~SimObjectPtr() { set((WeakRefBase::WeakReference*)NULL); }
|
|
|
|
SimObjectPtr<T>& operator=(const SimObjectPtr ref)
|
|
{
|
|
set(ref.mReference);
|
|
return *this;
|
|
}
|
|
SimObjectPtr<T>& operator=(T *ptr)
|
|
{
|
|
set(ptr);
|
|
return *this;
|
|
}
|
|
|
|
protected:
|
|
void set(WeakRefBase::WeakReference * ref)
|
|
{
|
|
if( ref == this->mReference )
|
|
return;
|
|
|
|
if( this->mReference )
|
|
{
|
|
// Auto-delete
|
|
T* obj = this->getPointer();
|
|
if ( this->mReference->getRefCount() == 2 && obj && obj->isAutoDeleted() )
|
|
obj->deleteObject();
|
|
|
|
this->mReference->decRefCount();
|
|
}
|
|
this->mReference = NULL;
|
|
if( ref )
|
|
{
|
|
this->mReference = ref;
|
|
this->mReference->incRefCount();
|
|
}
|
|
}
|
|
|
|
void set(T * obj)
|
|
{
|
|
set(obj ? obj->getWeakReference() : (WeakRefBase::WeakReference *)NULL);
|
|
}
|
|
};
|
|
|
|
#endif // _SIMOBJECT_H_
|