mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-01-19 20:24:49 +00:00
by request, adds a per object-instance onadd for datablocks if an object instance *also* defines a class. be mindful not to mix up which namespace is in use there, as you can not tag two different core class instances the same scripted class implements the same with the same restrictions for simobjects in general
1104 lines
44 KiB
C++
1104 lines
44 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
|
|
#include "T3D/objectTypes.h"
|
|
|
|
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;
|
|
bool mPrototype;
|
|
/// 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; }
|
|
static bool _doPrototype(void* object, const char* index, const char* data);
|
|
protected:
|
|
/// Taml callbacks.
|
|
void onTamlPreWrite(void) override {}
|
|
void onTamlPostWrite(void) override {}
|
|
void onTamlPreRead(void) override {}
|
|
void onTamlPostRead(const TamlCustomNodes& customNodes) override {}
|
|
void onTamlAddParent(SimObject* pParentObject) override {}
|
|
void onTamlCustomWrite(TamlCustomNodes& customNodes) override {}
|
|
void onTamlCustomRead(const TamlCustomNodes& customNodes) override;
|
|
|
|
/// 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.
|
|
String _getLogMessage(const char* fmt, va_list args) const override;
|
|
|
|
DEFINE_CREATE_METHOD
|
|
{
|
|
T* object = new T;
|
|
object->incRefCount();
|
|
return object;
|
|
}
|
|
|
|
|
|
// EngineObject.
|
|
void _destroySelf() override;
|
|
|
|
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);
|
|
|
|
virtual U32 getSpecialFieldSize(StringTableEntry fieldName) { return 0; }
|
|
virtual const char* getSpecialFieldOut(StringTableEntry fieldName, const U32& index) { return NULL; }
|
|
|
|
/// 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; }
|
|
|
|
/// type-specified slot for returning hints for the main difference between object instances
|
|
virtual StringTableEntry getTypeHint() const { return StringTable->EmptyString(); }
|
|
|
|
/// 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 );
|
|
virtual bool saveAppend(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.
|
|
String describeSelf() const override;
|
|
|
|
/// 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));
|
|
DECLARE_CALLBACK(void, onSelected, (SimObject* obj));
|
|
DECLARE_CALLBACK(void, onUnselected, (SimObject* obj));
|
|
|
|
DECLARE_CALLBACK(void, onAdd, (SimObjectId ID));
|
|
DECLARE_CALLBACK(void, onRemove, (SimObjectId ID));
|
|
|
|
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.
|
|
void destroySelf() override;
|
|
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() { }
|
|
};
|
|
|
|
typedef SceneObjectTypes GameTypeMasksType;
|
|
DefineBitfieldType(GameTypeMasksType);
|
|
|
|
/// 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_
|