simObject.cpp

Engine/source/console/simObject.cpp

More...

Classes:

Namespaces:

namespace

Public Variables

Public Functions

ConsoleDocClass(SimObject , "@brief Base class <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> almost all objects involved in the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">simulation.\n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Console\n</a>" )
ConsoleMethod(SimObject , call , const char * , 3 , 0 , "( string method, string args... ) Dynamically call a method on an <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param method Name of method <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">call.\n</a>" "@param args Zero or more arguments <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">method.\n</a>" "@return The result of the method call." )
ConsoleMethod(SimObject , schedule , S32 , 4 , 0 , "( float time, string method, string args... ) Delay an invocation of a <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">method.\n</a>" "@param time The number of milliseconds after which <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> invoke the method. This is a soft <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">limit.\n</a>" "@param method The method <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">call.\n</a>" "@param args The arguments with which <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> call the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">method.\n</a>" "@return The numeric ID of the created schedule. Can be used <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> cancel the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">call.\n</a>" )
DefineConsoleMethod(SimObject , assignFieldsFrom , void , (SimObject *fromObject) , "Copy fields from another object onto this one. The objects must " "be of same type. Everything from the object will overwrite what's " "in this object; extra fields in this object will remain. This " "includes dynamic <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">fields.\n</a>" "@param fromObject The object from which <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> copy fields." )
DefineConsoleMethod(SimObject , delete , void , () , "Delete and remove the object." )
DefineConsoleMethod(SimObject , dumpClassHierarchy , void , () , "Dump the native C++ class hierarchy of this object's C++ class <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the console." )
DefineConsoleMethod(SimObject , dumpMethods , ArrayObject * , () , "List the methods defined on this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n\n</a>" "Each description is a newline-separated vector with the following <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">elements:\n</a>" "- Minimum number of <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">arguments.\n</a>" "- Maximum number of <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">arguments.\n</a>" "- Prototype <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">string.\n</a>" "- Full script <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> path (<a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> script method).\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "- Line number of method definition in script (<a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> script method).\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "- Documentation string (not including prototype). This takes up the remainder of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">vector.\n</a>" "@return An <a href="/coding/class/classarrayobject/">ArrayObject</a> populated with (name,description) pairs of all methods defined on the object." )
DefineConsoleMethod(SimObject , getCanSave , bool , () , "Get whether the object will be included in <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">saves.\n</a>" "@return True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> the object will be saved; false otherwise." )
DefineConsoleMethod(SimObject , getClassName , const char * , () , "Get the name of the C++ class which the object is an instance <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">of.\n</a>" "@return The name of the C++ class of the object." )
DefineConsoleMethod(SimObject , getClassNamespace , const char * , () , "Get the name of the class namespace assigned <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@return The name of the 'class' namespace." )
DefineConsoleMethod(SimObject , getDeclarationLine , S32 , () , "Get the line number at which the object is defined in its <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">file.\n\n</a>" "@return The line number of the object's definition in <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">script.\n</a>" "@see getFilename()" )
DefineConsoleMethod(SimObject , getDynamicField , const char * , (S32 index) , "Get a value of a dynamic field by <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">index.\n</a>" "@param index The index of the dynamic <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">field.\n</a>" "@return The value of the dynamic field at the given index or \"\"." )
DefineConsoleMethod(SimObject , getDynamicFieldCount , S32 , () , "Get the number of dynamic fields defined on the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@return The number of dynamic fields defined on the object." )
DefineConsoleMethod(SimObject , getField , const char * , (S32 index) , "Retrieve the value of a static field by <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">index.\n</a>" "@param index The index of the static <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">field.\n</a>" "@return The value of the static field with the given index or \"\"." )
DefineConsoleMethod(SimObject , getFieldCount , S32 , () , "Get the number of static fields on the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@return The number of static fields defined on the object." )
DefineConsoleMethod(SimObject , getFieldType , const char * , (const char *fieldName) , "Get the console type code of the given <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">field.\n</a>" "@return The numeric type code <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the underlying console type of the given field." )
DefineConsoleMethod(SimObject , getFieldValue , const char * , (const char *fieldName, S32 index) , (-1) , "Return the value of the given field on this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param fieldName The name of the field. If it includes a field index, the index is parsed <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">out.\n</a>" " @param index Optional parameter <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> specify the index of an array field <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">separately.\n</a>" " @return The value of the given field or \"\" <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> undefined." )
DefineConsoleMethod(SimObject , getFilename , const char * , () , "Returns the filename the object is attached <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">to.\n</a>" "@return The name of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> the object is associated with; usually the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> the object was loaded from." )
DefineConsoleMethod(SimObject , getSuperClassNamespace , const char * , () , "Get the name of the superclass namespace assigned <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@return The name of the 'superClass' namespace." )
DefineConsoleMethod(SimObject , isExpanded , bool , () , "Get whether the object has been marked as expanded. (in editor)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@return True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> the object is marked expanded." )
DefineConsoleMethod(SimObject , isField , bool , (const char *fieldName) , "Test whether the given field is defined on this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param fieldName The name of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">field.\n</a>" "@return True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> the object implements the given field." )
DefineConsoleMethod(SimObject , isInNamespaceHierarchy , bool , (const char *name) , "Test whether the namespace of this object is a direct or indirect child <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the given <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">namespace.\n</a>" "@param name The name of a <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">namespace.\n</a>" "@return True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> the given namespace name is within the namespace hierarchy of this object." )
DefineConsoleMethod(SimObject , isMemberOfClass , bool , (const char *className) , "Test whether this object is a member of the specified <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">class.\n</a>" "@param className Name of a native C++ <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">class.\n</a>" "@return True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> this object is an instance of the given C++ class or any of its super classes." )
DefineConsoleMethod(SimObject , isMethod , bool , (const char *methodName) , "Test whether the given method is defined on this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param The name of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">method.\n</a>" "@return True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> the object implements the given method." )
DefineConsoleMethod(SimObject , save , bool , (const char *fileName, bool selectedOnly, const char *preAppendString) , (false, "") , "Save out the object <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the given <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">file.\n</a>" "@param fileName The name of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> save to." "@param selectedOnly If true, only objects marked as selected will be saved <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">out.\n</a>" " @param preAppendString Text which will be preprended directly <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the object <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">serialization.\n</a>" " @param True on success, false on failure." )
DefineConsoleMethod(SimObject , setCanSave , void , (bool value) , (true) , "Set whether the object will be included in <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">saves.\n</a>" "@param value If true, the object will be included in saves;<a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> false, it will be excluded." )
DefineConsoleMethod(SimObject , setClassNamespace , void , (const char *name) , "Assign a class namespace <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param name The name of the 'class' namespace <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> this object." )
DefineConsoleMethod(SimObject , setFieldType , void , (const char *fieldName, const char *type) , "Set the console type code <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the given <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">field.\n</a>" "@param fieldName The name of the dynamic field <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> change <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> type <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">for.\n</a>" "@param type The name of the console <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">type.\n</a>" "@note This only works <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> dynamic fields. Types of static fields cannot be changed." )
DefineConsoleMethod(SimObject , setFieldValue , bool , (const char *fieldName, const char *value, S32 index) , (-1) , "Set the value of the given field on this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param fieldName The name of the field <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> assign to. If it includes an array index, the index will be parsed <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">out.\n</a>" " @param value The <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> value <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> assign <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">field.\n</a>" " @param index Optional argument <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> specify an index <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> an array <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">field.\n</a>" " @return True." )
DefineConsoleMethod(SimObject , setFilename , void , (const char *fileName) , "Sets the object's <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> name and <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">path\n</a>" "@param fileName The name of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> associate this object with." )
DefineConsoleMethod(SimObject , setIsExpanded , void , (bool state) , (true) , "Set whether the object has been marked as expanded. (in editor)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@param state True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> the object is <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be marked expanded; false <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> not." )
DefineConsoleMethod(SimObject , setSuperClassNamespace , void , (const char *name) , "Assign a superclass namespace <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param name The name of the 'superClass' namespace <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> this object." )
DefineEngineMethod(SimObject , assignPersistentId , void , () , "Assign a persistent ID <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the object <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> it does not already have one." )
DefineEngineMethod(SimObject , clone , SimObject * , () , "Create a copy of this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@return An exact duplicate of this object." )
DefineEngineMethod(SimObject , deepClone , SimObject * , () , "Create a copy of this object and all its <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">subobjects.\n</a>" "@return An exact duplicate of this object and all objects it references." )
DefineEngineMethod(SimObject , dump , void , (bool detailed) , (false) , "Dump a description of all fields and methods defined on this object <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">console.\n</a>" "@param detailed Whether <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> print detailed information about members." )
DefineEngineMethod(SimObject , dumpGroupHierarchy , void , () , "Dump the hierarchy of this object up <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> RootGroup <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the console." )
DefineEngineMethod(SimObject , getGroup , SimGroup * , () , "Get the group that this object is contained <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">in.\n</a>" "@note If not assigned <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> particular SimGroup, an object belongs <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">RootGroup.\n</a>" " @return The <a href="/coding/class/classsimgroup/">SimGroup</a> object <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> which the object belongs." )
DefineEngineMethod(SimObject , getId , S32 , () , "Get the underlying unique numeric ID of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@note <a href="/coding/file/gizmo_8h/#gizmo_8h_1a10fcd3bee2ea25191e31795e36bdeba1a5df911aaca43421a25e32c3002befbc4">Object</a> IDs are unique only during single engine <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">runs.\n</a>" "@return The unique numeric ID of the object." )
DefineEngineMethod(SimObject , getInternalName , const char * , () , "Get the internal name of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@return The internal name of the object." )
DefineEngineMethod(SimObject , getName , const char * , () , "Get the global name of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@return The global name assigned <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the object." )
DefineEngineMethod(SimObject , isChildOfGroup , bool , (SimGroup *group) , "Test whether the object belongs directly or indirectly <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the given <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">group.\n</a>" "@param group The <a href="/coding/class/classsimgroup/">SimGroup</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@return True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> the object is a child of the given group or a child of a group that the given group is directly or indirectly a child to." )
DefineEngineMethod(SimObject , isEditorOnly , bool , () , "Return true <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> the object is only used by the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">editor.\n</a>" "@return True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> this object exists only <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the sake of editing." )
DefineEngineMethod(SimObject , isNameChangeAllowed , bool , () , "Get whether this object may be <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">renamed.\n</a>" "@return True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> this object can be renamed; false otherwise." )
DefineEngineMethod(SimObject , isSelected , bool , () , "Get whether the object has been marked as selected. (in editor)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@return True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> the object is currently selected." )
DefineEngineMethod(SimObject , setEditorOnly , void , (bool value) , (true) , "Set/clear the editor-only flag on this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param value If true, the object is marked as existing only <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the editor." )
DefineEngineMethod(SimObject , setHidden , void , (bool value) , (true) , "Hide/unhide the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param value If true, the object will be hidden;<a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> false, the object will be unhidden." )
DefineEngineMethod(SimObject , setInternalName , void , (const char *newInternalName) , "Set the internal name of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param newInternalName The <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> internal name <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the object." )
DefineEngineMethod(SimObject , setIsSelected , void , (bool state) , (true) , "Set whether the object has been marked as selected. (in editor)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@param state True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> object is <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be marked selected; false <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> not." )
DefineEngineMethod(SimObject , setLocked , void , (bool value) , (true) , "Lock/unlock the object in the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">editor.\n</a>" "@param value If true, the object will be locked;<a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> false, the object will be unlocked." )
DefineEngineMethod(SimObject , setName , void , (const char *newName) , "Set the global name of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param newName The <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> global name <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> assign <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@note If name changing is disallowed on the object, the method will fail with a console error." )
DefineEngineMethod(SimObject , setNameChangeAllowed , void , (bool value) , (true) , "Set whether this object can be renamed from its first <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">name.\n</a>" "@param value If true, renaming is allowed <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> this object;<a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> false, trying <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> change the name of the object will generate a console error." )

Detailed Description

Public Variables

Chunker< SimObject::Notify > notifyChunker (128000)

Public Functions

ConsoleDocClass(SimObject , "@brief Base class <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> almost all objects involved in the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">simulation.\n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Console\n</a>" )

ConsoleMethod(SimObject , call , const char * , 3 , 0 , "( string method, string args... ) Dynamically call a method on an <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param method Name of method <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">call.\n</a>" "@param args Zero or more arguments <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">method.\n</a>" "@return The result of the method call." )

ConsoleMethod(SimObject , schedule , S32 , 4 , 0 , "( float time, string method, string args... ) Delay an invocation of a <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">method.\n</a>" "@param time The number of milliseconds after which <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> invoke the method. This is a soft <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">limit.\n</a>" "@param method The method <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">call.\n</a>" "@param args The arguments with which <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> call the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">method.\n</a>" "@return The numeric ID of the created schedule. Can be used <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> cancel the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">call.\n</a>" )

DefineConsoleMethod(SimObject , assignFieldsFrom , void , (SimObject *fromObject) , "Copy fields from another object onto this one. The objects must " "be of same type. Everything from the object will overwrite what's " "in this object; extra fields in this object will remain. This " "includes dynamic <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">fields.\n</a>" "@param fromObject The object from which <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> copy fields." )

DefineConsoleMethod(SimObject , delete , void , () , "Delete and remove the object." )

DefineConsoleMethod(SimObject , dumpClassHierarchy , void , () , "Dump the native C++ class hierarchy of this object's C++ class <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the console." )

DefineConsoleMethod(SimObject , dumpMethods , ArrayObject * , () , "List the methods defined on this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n\n</a>" "Each description is a newline-separated vector with the following <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">elements:\n</a>" "- Minimum number of <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">arguments.\n</a>" "- Maximum number of <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">arguments.\n</a>" "- Prototype <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">string.\n</a>" "- Full script <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> path (<a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> script method).\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "- Line number of method definition in script (<a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> script method).\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "- Documentation string (not including prototype). This takes up the remainder of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">vector.\n</a>" "@return An <a href="/coding/class/classarrayobject/">ArrayObject</a> populated with (name,description) pairs of all methods defined on the object." )

DefineConsoleMethod(SimObject , getCanSave , bool , () , "Get whether the object will be included in <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">saves.\n</a>" "@return True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> the object will be saved; false otherwise." )

DefineConsoleMethod(SimObject , getClassName , const char * , () , "Get the name of the C++ class which the object is an instance <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">of.\n</a>" "@return The name of the C++ class of the object." )

DefineConsoleMethod(SimObject , getClassNamespace , const char * , () , "Get the name of the class namespace assigned <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@return The name of the 'class' namespace." )

DefineConsoleMethod(SimObject , getDeclarationLine , S32 , () , "Get the line number at which the object is defined in its <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">file.\n\n</a>" "@return The line number of the object's definition in <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">script.\n</a>" "@see getFilename()" )

DefineConsoleMethod(SimObject , getDynamicField , const char * , (S32 index) , "Get a value of a dynamic field by <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">index.\n</a>" "@param index The index of the dynamic <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">field.\n</a>" "@return The value of the dynamic field at the given index or \"\"." )

DefineConsoleMethod(SimObject , getDynamicFieldCount , S32 , () , "Get the number of dynamic fields defined on the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@return The number of dynamic fields defined on the object." )

DefineConsoleMethod(SimObject , getField , const char * , (S32 index) , "Retrieve the value of a static field by <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">index.\n</a>" "@param index The index of the static <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">field.\n</a>" "@return The value of the static field with the given index or \"\"." )

DefineConsoleMethod(SimObject , getFieldCount , S32 , () , "Get the number of static fields on the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@return The number of static fields defined on the object." )

DefineConsoleMethod(SimObject , getFieldType , const char * , (const char *fieldName) , "Get the console type code of the given <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">field.\n</a>" "@return The numeric type code <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the underlying console type of the given field." )

DefineConsoleMethod(SimObject , getFieldValue , const char * , (const char *fieldName, S32 index) , (-1) , "Return the value of the given field on this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param fieldName The name of the field. If it includes a field index, the index is parsed <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">out.\n</a>" " @param index Optional parameter <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> specify the index of an array field <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">separately.\n</a>" " @return The value of the given field or \"\" <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> undefined." )

DefineConsoleMethod(SimObject , getFilename , const char * , () , "Returns the filename the object is attached <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">to.\n</a>" "@return The name of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> the object is associated with; usually the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> the object was loaded from." )

DefineConsoleMethod(SimObject , getSuperClassNamespace , const char * , () , "Get the name of the superclass namespace assigned <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@return The name of the 'superClass' namespace." )

DefineConsoleMethod(SimObject , isExpanded , bool , () , "Get whether the object has been marked as expanded. (in editor)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@return True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> the object is marked expanded." )

DefineConsoleMethod(SimObject , isField , bool , (const char *fieldName) , "Test whether the given field is defined on this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param fieldName The name of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">field.\n</a>" "@return True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> the object implements the given field." )

DefineConsoleMethod(SimObject , isInNamespaceHierarchy , bool , (const char *name) , "Test whether the namespace of this object is a direct or indirect child <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the given <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">namespace.\n</a>" "@param name The name of a <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">namespace.\n</a>" "@return True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> the given namespace name is within the namespace hierarchy of this object." )

DefineConsoleMethod(SimObject , isMemberOfClass , bool , (const char *className) , "Test whether this object is a member of the specified <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">class.\n</a>" "@param className Name of a native C++ <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">class.\n</a>" "@return True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> this object is an instance of the given C++ class or any of its super classes." )

DefineConsoleMethod(SimObject , isMethod , bool , (const char *methodName) , "Test whether the given method is defined on this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param The name of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">method.\n</a>" "@return True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> the object implements the given method." )

DefineConsoleMethod(SimObject , save , bool , (const char *fileName, bool selectedOnly, const char *preAppendString) , (false, "") , "Save out the object <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the given <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">file.\n</a>" "@param fileName The name of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> save to." "@param selectedOnly If true, only objects marked as selected will be saved <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">out.\n</a>" " @param preAppendString Text which will be preprended directly <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the object <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">serialization.\n</a>" " @param True on success, false on failure." )

DefineConsoleMethod(SimObject , setCanSave , void , (bool value) , (true) , "Set whether the object will be included in <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">saves.\n</a>" "@param value If true, the object will be included in saves;<a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> false, it will be excluded." )

DefineConsoleMethod(SimObject , setClassNamespace , void , (const char *name) , "Assign a class namespace <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param name The name of the 'class' namespace <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> this object." )

DefineConsoleMethod(SimObject , setFieldType , void , (const char *fieldName, const char *type) , "Set the console type code <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the given <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">field.\n</a>" "@param fieldName The name of the dynamic field <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> change <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> type <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">for.\n</a>" "@param type The name of the console <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">type.\n</a>" "@note This only works <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> dynamic fields. Types of static fields cannot be changed." )

DefineConsoleMethod(SimObject , setFieldValue , bool , (const char *fieldName, const char *value, S32 index) , (-1) , "Set the value of the given field on this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param fieldName The name of the field <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> assign to. If it includes an array index, the index will be parsed <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">out.\n</a>" " @param value The <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> value <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> assign <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">field.\n</a>" " @param index Optional argument <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> specify an index <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> an array <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">field.\n</a>" " @return True." )

DefineConsoleMethod(SimObject , setFilename , void , (const char *fileName) , "Sets the object's <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> name and <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">path\n</a>" "@param fileName The name of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> associate this object with." )

DefineConsoleMethod(SimObject , setIsExpanded , void , (bool state) , (true) , "Set whether the object has been marked as expanded. (in editor)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@param state True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> the object is <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be marked expanded; false <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> not." )

DefineConsoleMethod(SimObject , setSuperClassNamespace , void , (const char *name) , "Assign a superclass namespace <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param name The name of the 'superClass' namespace <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> this object." )

DefineEngineMethod(SimObject , assignPersistentId , void , () , "Assign a persistent ID <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the object <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> it does not already have one." )

DefineEngineMethod(SimObject , clone , SimObject * , () , "Create a copy of this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@return An exact duplicate of this object." )

DefineEngineMethod(SimObject , deepClone , SimObject * , () , "Create a copy of this object and all its <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">subobjects.\n</a>" "@return An exact duplicate of this object and all objects it references." )

DefineEngineMethod(SimObject , dump , void , (bool detailed) , (false) , "Dump a description of all fields and methods defined on this object <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">console.\n</a>" "@param detailed Whether <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> print detailed information about members." )

DefineEngineMethod(SimObject , dumpGroupHierarchy , void , () , "Dump the hierarchy of this object up <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> RootGroup <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the console." )

DefineEngineMethod(SimObject , getGroup , SimGroup * , () , "Get the group that this object is contained <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">in.\n</a>" "@note If not assigned <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> particular SimGroup, an object belongs <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">RootGroup.\n</a>" " @return The <a href="/coding/class/classsimgroup/">SimGroup</a> object <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> which the object belongs." )

DefineEngineMethod(SimObject , getId , S32 , () , "Get the underlying unique numeric ID of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@note <a href="/coding/file/gizmo_8h/#gizmo_8h_1a10fcd3bee2ea25191e31795e36bdeba1a5df911aaca43421a25e32c3002befbc4">Object</a> IDs are unique only during single engine <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">runs.\n</a>" "@return The unique numeric ID of the object." )

DefineEngineMethod(SimObject , getInternalName , const char * , () , "Get the internal name of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@return The internal name of the object." )

DefineEngineMethod(SimObject , getName , const char * , () , "Get the global name of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@return The global name assigned <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the object." )

DefineEngineMethod(SimObject , isChildOfGroup , bool , (SimGroup *group) , "Test whether the object belongs directly or indirectly <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the given <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">group.\n</a>" "@param group The <a href="/coding/class/classsimgroup/">SimGroup</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@return True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> the object is a child of the given group or a child of a group that the given group is directly or indirectly a child to." )

DefineEngineMethod(SimObject , isEditorOnly , bool , () , "Return true <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> the object is only used by the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">editor.\n</a>" "@return True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> this object exists only <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the sake of editing." )

DefineEngineMethod(SimObject , isNameChangeAllowed , bool , () , "Get whether this object may be <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">renamed.\n</a>" "@return True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> this object can be renamed; false otherwise." )

DefineEngineMethod(SimObject , isSelected , bool , () , "Get whether the object has been marked as selected. (in editor)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@return True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> the object is currently selected." )

DefineEngineMethod(SimObject , setEditorOnly , void , (bool value) , (true) , "Set/clear the editor-only flag on this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param value If true, the object is marked as existing only <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the editor." )

DefineEngineMethod(SimObject , setHidden , void , (bool value) , (true) , "Hide/unhide the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param value If true, the object will be hidden;<a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> false, the object will be unhidden." )

DefineEngineMethod(SimObject , setInternalName , void , (const char *newInternalName) , "Set the internal name of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param newInternalName The <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> internal name <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the object." )

DefineEngineMethod(SimObject , setIsSelected , void , (bool state) , (true) , "Set whether the object has been marked as selected. (in editor)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@param state True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> object is <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be marked selected; false <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> not." )

DefineEngineMethod(SimObject , setLocked , void , (bool value) , (true) , "Lock/unlock the object in the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">editor.\n</a>" "@param value If true, the object will be locked;<a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> false, the object will be unlocked." )

DefineEngineMethod(SimObject , setName , void , (const char *newName) , "Set the global name of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param newName The <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> global name <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> assign <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@note If name changing is disallowed on the object, the method will fail with a console error." )

DefineEngineMethod(SimObject , setNameChangeAllowed , void , (bool value) , (true) , "Set whether this object can be renamed from its first <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">name.\n</a>" "@param value If true, renaming is allowed <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> this object;<a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> false, trying <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> change the name of the object will generate a console error." )

IMPLEMENT_CONOBJECT(SimObject )

   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#include "platform/platform.h"
  25#include "platform/platformMemory.h"
  26#include "console/simObject.h"
  27#include "console/console.h"
  28#include "console/consoleInternal.h"
  29#include "console/engineAPI.h"
  30#include "console/simFieldDictionary.h"
  31#include "console/simPersistID.h"
  32#include "console/typeValidators.h"
  33#include "console/arrayObject.h"
  34#include "console/codeBlock.h"
  35#include "core/frameAllocator.h"
  36#include "core/stream/fileStream.h"
  37#include "core/fileObject.h"
  38#include "persistence/taml/tamlCustom.h"
  39
  40IMPLEMENT_CONOBJECT( SimObject );
  41
  42// See full description in the new CHM manual
  43ConsoleDocClass( SimObject,
  44   "@brief Base class for almost all objects involved in the simulation.\n\n"
  45
  46   "@ingroup Console\n"
  47);
  48
  49bool SimObject::smForceId = false;
  50SimObjectId SimObject::smForcedId = 0;
  51
  52
  53namespace Sim
  54{
  55   // Defined in simManager.cpp
  56   extern SimGroup *gRootGroup;
  57   extern SimManagerNameDictionary *gNameDictionary;
  58   extern SimIdDictionary *gIdDictionary;
  59   extern U32 gNextObjectId;
  60}
  61
  62
  63//-----------------------------------------------------------------------------
  64
  65SimObject::SimObject()
  66{
  67   objectName            = NULL;
  68   mOriginalName         = NULL;
  69   mInternalName         = NULL;
  70   nextNameObject        = (SimObject*)-1;
  71   nextManagerNameObject = (SimObject*)-1;
  72   nextIdObject          = NULL;
  73
  74   mFilename             = NULL;
  75   mDeclarationLine      = -1;
  76
  77   mId           = 0;
  78   mIdString[ 0 ] = '\0';
  79   mGroup        = 0;
  80   mNameSpace    = NULL;
  81   mNotifyList   = NULL;
  82   mFlags.set( ModStaticFields | ModDynamicFields );
  83
  84   mFieldDictionary = NULL;
  85   mCanSaveFieldDictionary =  true;
  86
  87   mClassName = NULL;
  88   mSuperClassName = NULL;
  89
  90   mCopySource = NULL;
  91   mPersistentId = NULL;
  92}
  93
  94//-----------------------------------------------------------------------------
  95
  96SimObject::~SimObject()
  97{
  98   if( mFieldDictionary )
  99   {
 100      delete mFieldDictionary;
 101      mFieldDictionary = NULL;
 102   }
 103
 104   // Release persistent ID.
 105   if( mPersistentId )
 106   {
 107      mPersistentId->unresolve();
 108      mPersistentId->decRefCount();
 109      mPersistentId = NULL;
 110   }
 111
 112   if( mCopySource )
 113      mCopySource->unregisterReference( &mCopySource );
 114
 115   AssertFatal(nextNameObject == (SimObject*)-1,avar(
 116      "SimObject::~SimObject:  Not removed from dictionary: name %s, id %i",
 117      objectName, mId));
 118   AssertFatal(nextManagerNameObject == (SimObject*)-1,avar(
 119      "SimObject::~SimObject:  Not removed from manager dictionary: name %s, id %i",
 120      objectName,mId));
 121   AssertFatal(mFlags.test(Added) == 0, "SimObject::object "
 122      "missing call to SimObject::onRemove");
 123}
 124
 125//-----------------------------------------------------------------------------
 126
 127bool SimObject::processArguments(S32 argc, ConsoleValueRef *argv)
 128{
 129   return argc == 0;
 130}
 131
 132//-----------------------------------------------------------------------------
 133
 134void SimObject::initPersistFields()
 135{
 136   addGroup( "Ungrouped" );
 137
 138      addProtectedField( "name", TypeName, Offset(objectName, SimObject), &setProtectedName, &defaultProtectedGetFn, 
 139         "Optional global name of this object." );
 140                  
 141   endGroup( "Ungrouped" );
 142
 143   addGroup( "Object" );
 144
 145      addField( "internalName", TypeString, Offset(mInternalName, SimObject), 
 146         "Optional name that may be used to lookup this object within a SimSet.");
 147
 148      addProtectedField( "parentGroup", TYPEID< SimObject >(), Offset(mGroup, SimObject), &setProtectedParent, &defaultProtectedGetFn, 
 149         "Group hierarchy parent of the object." );
 150
 151      addProtectedField( "class", TypeString, Offset(mClassName, SimObject), &setClass, &defaultProtectedGetFn,
 152         "Script class of object." );
 153
 154      addProtectedField( "superClass", TypeString, Offset(mSuperClassName, SimObject), &setSuperClass, &defaultProtectedGetFn,
 155         "Script super-class of object." );
 156
 157      // For legacy support
 158      addProtectedField( "className", TypeString, Offset(mClassName, SimObject), &setClass, &defaultProtectedGetFn,
 159         "Script class of object.", AbstractClassRep::FIELD_HideInInspectors );
 160
 161   endGroup( "Object" );
 162   
 163   addGroup( "Editing" );
 164   
 165      addProtectedField( "hidden", TypeBool, NULL,
 166         &_setHidden, &_getHidden,
 167         "Whether the object is visible." );
 168      addProtectedField( "locked", TypeBool, NULL,
 169         &_setLocked, &_getLocked,
 170         "Whether the object can be edited." );
 171   
 172   endGroup( "Editing" );
 173   
 174   addGroup( "Persistence" );
 175
 176      addProtectedField( "canSave", TypeBool, Offset( mFlags, SimObject ),
 177         &_setCanSave, &_getCanSave,
 178         "Whether the object can be saved out. If false, the object is purely transient in nature." );
 179
 180      addField( "canSaveDynamicFields", TypeBool, Offset(mCanSaveFieldDictionary, SimObject), 
 181         "True if dynamic fields (added at runtime) should be saved. Defaults to true." );
 182   
 183      addProtectedField( "persistentId", TypePID, Offset( mPersistentId, SimObject ),
 184         &_setPersistentID, &defaultProtectedGetFn,
 185         "The universally unique identifier for the object." );
 186   
 187   endGroup( "Persistence" );
 188
 189   Parent::initPersistFields();
 190}
 191
 192//-----------------------------------------------------------------------------
 193
 194String SimObject::describeSelf() const
 195{
 196   String desc = Parent::describeSelf();
 197   
 198   if( mId != 0 )
 199      desc = avar( "%s|id: %i", desc.c_str(), mId );
 200   if( objectName )
 201      desc = avar( "%s|name: %s", desc.c_str(), objectName );
 202   if( mInternalName )
 203      desc = avar( "%s|internal: %s", desc.c_str(), mInternalName );
 204   if( mNameSpace )
 205      desc = avar( "%s|nspace: %s", desc.c_str(), mNameSpace->mName );
 206   if( mGroup )
 207      desc = avar( "%s|group: %s", desc.c_str(), mGroup->getName() );
 208   if( mCopySource )
 209      desc = avar( "%s|copy: %s", desc.c_str(), mCopySource->getName() );
 210   if( mPersistentId )
 211      desc = avar( "%s|pid: %s", desc.c_str(), mPersistentId->getUUID().toString().c_str() );
 212
 213   return desc;
 214}
 215
 216//=============================================================================
 217//    Persistence.
 218//=============================================================================
 219// MARK: ---- Persistence ----
 220
 221//-----------------------------------------------------------------------------
 222
 223bool SimObject::writeField(StringTableEntry fieldname, const char* value)
 224{
 225   // Don't write empty fields.
 226   if (!value || !*value)
 227      return false;
 228
 229   // Don't write owner field for components
 230   static StringTableEntry sOwner = StringTable->insert( "owner" );
 231   if( fieldname == sOwner )
 232      return false;
 233
 234   // Don't write ParentGroup
 235   static StringTableEntry sParentGroup = StringTable->insert( "parentGroup" );
 236   if( fieldname == sParentGroup )
 237      return false;
 238
 239   // Don't write name, is within the parenthesis already
 240   static StringTableEntry sName = StringTable->insert( "name" );
 241   if( fieldname == sName )
 242      return false;
 243
 244   // Don't write className, it is read for legacy support but we
 245   // write it out as class.
 246   static StringTableEntry sClassName = StringTable->insert( "className" );
 247   if( fieldname == sClassName )
 248      return false;
 249
 250   // Write persistent ID only if present.
 251   static StringTableEntry sPersistentId = StringTable->insert( "persistentId" );
 252   if( fieldname == sPersistentId && ( !value || !value[ 0 ] ) )
 253      return false;
 254      
 255   // Don't write hidden and locked flags if they are at their default value.
 256      
 257   static StringTableEntry sHidden = StringTable->insert( "hidden" );
 258   static StringTableEntry sLocked = StringTable->insert( "locked" );
 259
 260   if( fieldname == sHidden && !dAtob( value ) )
 261      return false;
 262   if( fieldname == sLocked && !dAtob( value ) )
 263      return false;
 264
 265   return true;
 266}
 267
 268//-----------------------------------------------------------------------------
 269
 270void SimObject::writeFields(Stream &stream, U32 tabStop)
 271{
 272   // Write static fields.
 273   
 274   const AbstractClassRep::FieldList &list = getFieldList();
 275
 276   for(U32 i = 0; i < list.size(); i++)
 277   {
 278      const AbstractClassRep::Field* f = &list[i];
 279
 280      // Skip the special field types.
 281      if ( f->type >= AbstractClassRep::ARCFirstCustomField )
 282         continue;
 283
 284      for(U32 j = 0; S32(j) < f->elementCount; j++)
 285      {
 286         char array[8];
 287         dSprintf( array, 8, "%d", j );
 288         const char *val = getDataField(StringTable->insert( f->pFieldname ), array );
 289
 290         // Make a copy for the field check.
 291         if (!val)
 292            continue;
 293
 294         U32 nBufferSize = dStrlen( val ) + 1;
 295         FrameTemp<char> valCopy( nBufferSize );
 296         dStrcpy( (char *)valCopy, val );
 297
 298         if (!writeField(f->pFieldname, valCopy))
 299            continue;
 300
 301         val = valCopy;
 302
 303         U32 expandedBufferSize = ( nBufferSize  * 2 ) + dStrlen(f->pFieldname) + 32;
 304         FrameTemp<char> expandedBuffer( expandedBufferSize );
 305         if(f->elementCount == 1)
 306            dSprintf(expandedBuffer, expandedBufferSize, "%s = \"", f->pFieldname);
 307         else
 308            dSprintf(expandedBuffer, expandedBufferSize, "%s[%d] = \"", f->pFieldname, j);
 309
 310         // detect and collapse relative path information
 311         char fnBuf[1024];
 312         if (f->type == TypeFilename ||
 313             f->type == TypeStringFilename ||
 314             f->type == TypeImageFilename ||
 315             f->type == TypePrefabFilename ||
 316             f->type == TypeShapeFilename)
 317         {
 318            Con::collapseScriptFilename(fnBuf, 1024, val);
 319            val = fnBuf;
 320         }
 321
 322         expandEscape((char*)expandedBuffer + dStrlen(expandedBuffer), val);
 323         dStrcat(expandedBuffer, "\";\r\n");
 324
 325         stream.writeTabs(tabStop);
 326         stream.write(dStrlen(expandedBuffer),expandedBuffer);
 327      }
 328   }
 329   
 330   // Write dynamic fields, if enabled.
 331   
 332   if(mFieldDictionary && mCanSaveFieldDictionary)
 333      mFieldDictionary->writeFields(this, stream, tabStop);
 334}
 335
 336//-----------------------------------------------------------------------------
 337
 338void SimObject::write(Stream &stream, U32 tabStop, U32 flags)
 339{
 340   if( !getCanSave() && !( flags & IgnoreCanSave ) )
 341      return;
 342      
 343   // Only output selected objects if they want that.
 344   if((flags & SelectedOnly) && !isSelected())
 345      return;
 346
 347   stream.writeTabs(tabStop);
 348   char buffer[1024];
 349   dSprintf(buffer, sizeof(buffer), "new %s(%s) {\r\n", getClassName(), getName() && !(flags & NoName) ? getName() : "");
 350   stream.write(dStrlen(buffer), buffer);
 351   writeFields(stream, tabStop + 1);
 352
 353   stream.writeTabs(tabStop);
 354   stream.write(4, "};\r\n");
 355}
 356
 357//-----------------------------------------------------------------------------
 358
 359bool SimObject::save(const char *pcFileName, bool bOnlySelected, const char *preappend)
 360{
 361   static const char *beginMessage = "//--- OBJECT WRITE BEGIN ---";
 362   static const char *endMessage = "//--- OBJECT WRITE END ---";
 363   FileStream *stream;
 364   FileObject f;
 365   f.readMemory(pcFileName);
 366
 367   // check for flags <selected, ...>
 368   U32 writeFlags = 0;
 369   if(bOnlySelected)
 370      writeFlags |= SimObject::SelectedOnly;
 371
 372   if((stream = FileStream::createAndOpen( pcFileName, Torque::FS::File::Write )) == NULL)
 373      return false;
 374
 375   char docRoot[256];
 376   char modRoot[256];
 377
 378   dStrcpy(docRoot, pcFileName);
 379   char *p = dStrrchr(docRoot, '/');
 380   if (p) *++p = '\0';
 381   else  docRoot[0] = '\0';
 382
 383   dStrcpy(modRoot, pcFileName);
 384   p = dStrchr(modRoot, '/');
 385   if (p) *++p = '\0';
 386   else  modRoot[0] = '\0';
 387
 388   Con::setVariable("$DocRoot", docRoot);
 389   Con::setVariable("$ModRoot", modRoot);
 390
 391   const char *buffer;
 392   while(!f.isEOF())
 393   {
 394      buffer = (const char *) f.readLine();
 395      if(!dStrcmp(buffer, beginMessage))
 396         break;
 397      stream->write(dStrlen(buffer), buffer);
 398      stream->write(2, "\r\n");
 399   }
 400   stream->write(dStrlen(beginMessage), beginMessage);
 401   stream->write(2, "\r\n");
 402   if ( preappend != NULL )   
 403      stream->write(dStrlen(preappend),preappend);   
 404   write(*stream, 0, writeFlags);
 405   stream->write(dStrlen(endMessage), endMessage);
 406   stream->write(2, "\r\n");
 407   while(!f.isEOF())
 408   {
 409      buffer = (const char *) f.readLine();
 410      if(!dStrcmp(buffer, endMessage))
 411         break;
 412   }
 413   while(!f.isEOF())
 414   {
 415      buffer = (const char *) f.readLine();
 416      stream->write(dStrlen(buffer), buffer);
 417      stream->write(2, "\r\n");
 418   }
 419
 420   Con::setVariable("$DocRoot", NULL);
 421   Con::setVariable("$ModRoot", NULL);
 422
 423   delete stream;
 424
 425   return true;
 426
 427}
 428
 429//-----------------------------------------------------------------------------
 430
 431SimPersistID* SimObject::getOrCreatePersistentId()
 432{
 433   if( !mPersistentId )
 434   {
 435       mPersistentId = SimPersistID::create( this );
 436       mPersistentId->incRefCount();
 437   }
 438   return mPersistentId;
 439}
 440
 441
 442
 443void SimObject::onTamlCustomRead(TamlCustomNodes const& customNodes)
 444{
 445   // Debug Profiling.
 446   //PROFILE_SCOPE(SimObject_OnTamlCustomRead);
 447
 448   // Fetch field list.
 449   const AbstractClassRep::FieldList& fieldList = getFieldList();
 450   const U32 fieldCount = fieldList.size();
 451   for (U32 index = 0; index < fieldCount; ++index)
 452   {
 453      // Fetch field.
 454      const AbstractClassRep::Field* pField = &fieldList[index];
 455
 456      // Ignore if field not appropriate.
 457      if (pField->type == AbstractClassRep::StartArrayFieldType || pField->elementCount > 1)
 458      {
 459         // Find cell custom node.
 460         const TamlCustomNode* pCustomCellNodes = NULL;
 461         if (pField->pGroupname != NULL)
 462            pCustomCellNodes = customNodes.findNode(pField->pGroupname);
 463         if (!pCustomCellNodes)
 464         {
 465            char* niceFieldName = const_cast<char *>(pField->pFieldname);
 466            niceFieldName[0] = dToupper(niceFieldName[0]);
 467            String str_niceFieldName = String(niceFieldName);
 468            pCustomCellNodes = customNodes.findNode(str_niceFieldName + "s");
 469         }
 470
 471         // Continue if we have explicit cells.
 472         if (pCustomCellNodes != NULL)
 473         {
 474            // Fetch children cell nodes.
 475            const TamlCustomNodeVector& cellNodes = pCustomCellNodes->getChildren();
 476
 477            U8 idx = 0;
 478            // Iterate cells.
 479            for (TamlCustomNodeVector::const_iterator cellNodeItr = cellNodes.begin(); cellNodeItr != cellNodes.end(); ++cellNodeItr)
 480            {
 481               char buf[5];
 482               dSprintf(buf, 5, "%d", idx);
 483
 484               // Fetch cell node.
 485               TamlCustomNode* pCellNode = *cellNodeItr;
 486
 487               // Fetch node name.
 488               StringTableEntry nodeName = pCellNode->getNodeName();
 489
 490               // Is this a valid alias?
 491               if (nodeName != pField->pFieldname)
 492               {
 493                  // No, so warn.
 494                  Con::warnf("SimObject::onTamlCustomRead() - Encountered an unknown custom name of '%s'.  Only '%s' is valid.", nodeName, pField->pFieldname);
 495                  continue;
 496               }
 497
 498               // Fetch fields.
 499               const TamlCustomFieldVector& fields = pCellNode->getFields();
 500
 501               // Iterate property fields.
 502               for (TamlCustomFieldVector::const_iterator fieldItr = fields.begin(); fieldItr != fields.end(); ++fieldItr)
 503               {
 504                  // Fetch field.
 505                  const TamlCustomField* pField = *fieldItr;
 506
 507                  // Fetch field name.
 508                  StringTableEntry fieldName = pField->getFieldName();
 509
 510                  const AbstractClassRep::Field* field = findField(fieldName);
 511
 512                  // Check common fields.
 513                  if (field)
 514                  {
 515                     setDataField(fieldName, buf, pField->getFieldValue());
 516                  }
 517                  else
 518                  {
 519                     // Unknown name so warn.
 520                     Con::warnf("SimObject::onTamlCustomRead() - Encountered an unknown custom field name of '%s'.", fieldName);
 521                     continue;
 522                  }
 523               }
 524
 525               idx++;
 526            }
 527         }
 528      }
 529   }
 530}
 531
 532//-----------------------------------------------------------------------------
 533
 534bool SimObject::_setPersistentID( void* object, const char* index, const char* data )
 535{
 536   SimObject* simObject = reinterpret_cast< SimObject* >( object );
 537
 538   // Make sure we don't already have a PID.
 539   if( simObject->getPersistentId() )
 540   {
 541      Con::errorf( "SimObject::_setPersistentID - cannot set a persistent ID on an object that already has a persistent ID assigned." );
 542      return false;
 543   }
 544
 545   SimPersistID* pid;
 546   Con::setData( TypePID, &pid, 0, 1, &data );
 547   if ( !pid )
 548      return false;
 549
 550   // Make sure it's not already bound to an object.
 551   if( pid->getObject() )
 552   {
 553      AssertWarn( pid->getObject() != simObject, "Sim::_setPersistentID - PID is bound to this object yet not assigned to it!" );
 554
 555      SimObject* otherObj = pid->getObject();
 556      Con::errorf( "SimObject::_setPersistentID - UUID is already used by another object: '%s' -> %i:%s (%s)",
 557         data, otherObj->getId(), otherObj->getClassName(), otherObj->getName() );
 558
 559      return false;
 560   }
 561
 562   pid->resolve( simObject );
 563   pid->incRefCount();
 564   simObject->mPersistentId = pid;
 565
 566   return false;
 567}
 568
 569//-----------------------------------------------------------------------------
 570
 571void SimObject::setFilename( const char* file )
 572{
 573   if( file )
 574      mFilename = StringTable->insert( file );
 575   else
 576      mFilename = StringTable->EmptyString();
 577}
 578
 579//-----------------------------------------------------------------------------
 580
 581void SimObject::setDeclarationLine(U32 lineNumber)
 582{
 583   mDeclarationLine = lineNumber;
 584}
 585
 586//=============================================================================
 587//    Management.
 588//=============================================================================
 589// MARK: ---- Management ----
 590
 591//-----------------------------------------------------------------------------
 592
 593bool SimObject::registerObject()
 594{
 595   AssertFatal( !mFlags.test( Added ), "reigsterObject - Object already registered!");
 596   mFlags.clear(Deleted | Removed);
 597
 598   if(smForceId)
 599   {
 600      setId(smForcedId);
 601      smForceId = false;
 602   }
 603
 604   if( !mId )
 605   {
 606      mId = Sim::gNextObjectId++;
 607      dSprintf( mIdString, sizeof( mIdString ), "%u", mId );
 608   }
 609
 610   AssertFatal(Sim::gIdDictionary && Sim::gNameDictionary, 
 611      "SimObject::registerObject - tried to register an object before Sim::init()!");
 612
 613   Sim::gIdDictionary->insert(this);   
 614
 615   Sim::gNameDictionary->insert(this);
 616
 617   // Notify object
 618   bool ret = onAdd();
 619
 620   if(!ret)
 621      unregisterObject();
 622
 623   AssertFatal(!ret || isProperlyAdded(), "Object did not call SimObject::onAdd()");
 624   return ret;
 625}
 626
 627//-----------------------------------------------------------------------------
 628
 629void SimObject::unregisterObject()
 630{
 631   mFlags.set(Removed);
 632
 633   // Notify object first
 634   onRemove();
 635
 636   // Clear out any pending notifications before
 637   // we call our own, just in case they delete
 638   // something that we have referenced.
 639   clearAllNotifications();
 640
 641   // Notify all objects that are waiting for delete
 642   // messages
 643   if (getGroup())
 644      getGroup()->removeObject(this);
 645
 646   processDeleteNotifies();
 647
 648   // Do removals from the Sim.
 649   Sim::gNameDictionary->remove(this);
 650   Sim::gIdDictionary->remove(this);
 651   Sim::cancelPendingEvents(this);
 652}
 653
 654//-----------------------------------------------------------------------------
 655
 656void SimObject::deleteObject()
 657{
 658   Parent::destroySelf();
 659}
 660
 661//-----------------------------------------------------------------------------
 662
 663void SimObject::_destroySelf()
 664{
 665   AssertFatal( !isDeleted(), "SimObject::destroySelf - Object has already been deleted" );
 666   AssertFatal( !isRemoved(), "SimObject::destroySelf - Object in the process of being removed" );
 667
 668   mFlags.set( Deleted );
 669
 670   if( mFlags.test( Added ) )
 671      unregisterObject();
 672
 673   Parent::_destroySelf();
 674}
 675
 676//-----------------------------------------------------------------------------
 677
 678void SimObject::destroySelf()
 679{
 680   // When using the legacy console interop, we don't delete objects
 681   // when their reference count drops to zero but rather defer their
 682   // deletion until deleteObject() is called.
 683
 684   if( engineAPI::gUseConsoleInterop )
 685      return;
 686
 687   Parent::destroySelf();
 688}
 689
 690//-----------------------------------------------------------------------------
 691
 692class SimObjectDeleteEvent : public SimEvent
 693{
 694public:
 695   void process(SimObject *object)
 696   {
 697      object->deleteObject();
 698   }
 699};
 700
 701void SimObject::safeDeleteObject()
 702{
 703   Sim::postEvent( this, new SimObjectDeleteEvent, Sim::getCurrentTime() + 1 );
 704}
 705
 706//-----------------------------------------------------------------------------
 707
 708void SimObject::setId(SimObjectId newId)
 709{
 710   if(!mFlags.test(Added))
 711      mId = newId;
 712   else
 713   {
 714      // get this object out of the id dictionary if it's in it
 715      Sim::gIdDictionary->remove(this);
 716
 717      // Free current Id.
 718      // Assign new one.
 719      mId = newId ? newId : Sim::gNextObjectId++;
 720      Sim::gIdDictionary->insert(this);
 721   }
 722
 723   dSprintf( mIdString, sizeof( mIdString ), "%u", mId );
 724}
 725
 726//-----------------------------------------------------------------------------
 727
 728void SimObject::assignName(const char *name)
 729{
 730   if( objectName && !isNameChangeAllowed() )
 731   {
 732      Con::errorf( "SimObject::assignName - not allowed to change name of object '%s'", objectName );
 733      return;
 734   }
 735   
 736   // Added this assert 3/30/2007 because it is dumb to try to name
 737   // a SimObject the same thing as it's class name -patw
 738   //AssertFatal( dStricmp( getClassName(), name ), "Attempted to assign a name to a SimObject which matches it's type name." );
 739   if( dStricmp( getClassName(), name ) == 0 )
 740      Con::errorf( "SimObject::assignName - Assigning name '%s' to instance of object with type '%s'."
 741      " This can cause namespace linking issues.", getClassName(), name  );
 742
 743   StringTableEntry newName = NULL;
 744   if(name[0])
 745      newName = StringTable->insert(name);
 746
 747   onNameChange( newName );
 748
 749   if( mGroup )
 750      mGroup->mNameDictionary.remove( this );
 751   if( isProperlyAdded() )
 752   {
 753      unlinkNamespaces();
 754      Sim::gNameDictionary->remove( this );
 755   }
 756      
 757   objectName = newName;
 758   
 759   if( mGroup )
 760      mGroup->mNameDictionary.insert( this );
 761   if( isProperlyAdded() )
 762   {
 763      Sim::gNameDictionary->insert( this );
 764      linkNamespaces();
 765   }
 766}
 767
 768//-----------------------------------------------------------------------------
 769
 770bool SimObject::registerObject(U32 id)
 771{
 772   setId(id);
 773   return registerObject();
 774}
 775
 776//-----------------------------------------------------------------------------
 777
 778bool SimObject::registerObject(const char *name)
 779{
 780   assignName(name);
 781   return registerObject();
 782}
 783
 784//-----------------------------------------------------------------------------
 785
 786bool SimObject::registerObject(const char *name, U32 id)
 787{
 788   setId(id);
 789   assignName(name);
 790   return registerObject();
 791}
 792
 793//=============================================================================
 794//    Introspection.
 795//=============================================================================
 796// MARK: ---- Introspection ----
 797
 798//-----------------------------------------------------------------------------
 799
 800bool SimObject::isMethod( const char* methodName )
 801{
 802   if( !methodName || !methodName[0] )
 803      return false;
 804
 805   StringTableEntry stname = StringTable->insert( methodName );
 806
 807   if( getNamespace() )
 808      return ( getNamespace()->lookup( stname ) != NULL );
 809
 810   return false;
 811}
 812
 813//-----------------------------------------------------------------------------
 814
 815bool SimObject::isField( const char* fieldName, bool includeStatic, bool includeDynamic )
 816{
 817   const char* strFieldName = StringTable->insert( fieldName );
 818   
 819   if( includeStatic && getClassRep()->findField( strFieldName ) )
 820      return true;
 821   
 822   if( includeDynamic && getFieldDictionary() && getFieldDictionary()->findDynamicField( strFieldName ) )
 823      return true;
 824   
 825   return false;
 826}
 827
 828//-----------------------------------------------------------------------------
 829
 830void SimObject::assignDynamicFieldsFrom(SimObject* parent)
 831{
 832   if(parent->mFieldDictionary)
 833   {
 834      if( mFieldDictionary == NULL )
 835         mFieldDictionary = new SimFieldDictionary;
 836      mFieldDictionary->assignFrom(parent->mFieldDictionary);
 837   }
 838}
 839
 840//-----------------------------------------------------------------------------
 841
 842void SimObject::assignFieldsFrom(SimObject *parent)
 843{
 844   // Only allow field assigns from objects of the same class or
 845   // a superclass.
 846   
 847   if( getClassRep()->isClass( parent->getClassRep() ) )
 848   {
 849      const AbstractClassRep::FieldList &list = parent->getFieldList();
 850
 851      // copy out all the fields:
 852      for(U32 i = 0; i < list.size(); i++)
 853      {
 854         const AbstractClassRep::Field* f = &list[i];
 855
 856         // Skip the special field types.
 857         if ( f->type >= AbstractClassRep::ARCFirstCustomField )
 858            continue;
 859            
 860         // Skip certain fields that we don't want to see copied so we don't
 861         // get error messages from their setters.
 862            
 863         static StringTableEntry sName = StringTable->insert( "name" );
 864         static StringTableEntry sPersistentId = StringTable->insert( "persistentId" );
 865         
 866         if( f->pFieldname == sName || f->pFieldname == sPersistentId )
 867            continue;
 868
 869         S32 lastField = f->elementCount - 1;
 870         for(S32 j = 0; j <= lastField; j++)
 871         {
 872            const char* fieldVal = (*f->getDataFn)( parent,  Con::getData(f->type, (void *) (((const char *)parent) + f->offset), j, f->table, f->flag));
 873
 874            // Don't assign the field is the pointer is null or if
 875            // the field is not empty and writing it was disallowed.
 876            if ( !fieldVal || ( fieldVal[0] && !writeField( f->pFieldname, fieldVal ) ) )
 877               continue;
 878
 879            // code copied from SimObject::setDataField().
 880            // TODO: paxorr: abstract this into a better setData / getData that considers prot fields.
 881            FrameTemp<char> buffer(2048);
 882            FrameTemp<char> bufferSecure(2048); // This buffer is used to make a copy of the data
 883            ConsoleBaseType *cbt = ConsoleBaseType::getType( f->type );
 884            const char* szBuffer = cbt->prepData( fieldVal, buffer, 2048 );
 885            dMemset( bufferSecure, 0, 2048 );
 886            dMemcpy( bufferSecure, szBuffer, dStrlen( szBuffer ) );
 887
 888            if((*f->setDataFn)( this, NULL, bufferSecure ) )
 889               Con::setData(f->type, (void *) (((const char *)this) + f->offset), j, 1, &fieldVal, f->table);
 890         }
 891      }
 892   }
 893   else
 894   {
 895      Con::errorf( "SimObject::assignFieldsFrom() - cannot assigned fields from object of type '%s' to object of type '%s'",
 896         parent->getClassName(), getClassName()
 897      );
 898   }
 899
 900   assignDynamicFieldsFrom(parent);
 901}
 902
 903//-----------------------------------------------------------------------------
 904
 905void SimObject::setDataField(StringTableEntry slotName, const char *array, const char *value)
 906{
 907   // first search the static fields if enabled
 908   if(mFlags.test(ModStaticFields))
 909   {
 910      const AbstractClassRep::Field *fld = findField(slotName);
 911      if(fld)
 912      {
 913         // Skip the special field types as they are not data.
 914         if ( fld->type >= AbstractClassRep::ARCFirstCustomField )
 915            return;
 916
 917         S32 array1 = array ? dAtoi(array) : 0;
 918
 919         if(array1 >= 0 && array1 < fld->elementCount && fld->elementCount >= 1)
 920         {
 921            // If the set data notify callback returns true, then go ahead and
 922            // set the data, otherwise, assume the set notify callback has either
 923            // already set the data, or has deemed that the data should not
 924            // be set at all.
 925            FrameTemp<char> buffer(2048);
 926            FrameTemp<char> bufferSecure(2048); // This buffer is used to make a copy of the data
 927            // so that if the prep functions or any other functions use the string stack, the data
 928            // is not corrupted.
 929
 930            ConsoleBaseType *cbt = ConsoleBaseType::getType( fld->type );
 931            AssertFatal( cbt != NULL, "Could not resolve Type Id." );
 932
 933            const char* szBuffer = cbt->prepData( value, buffer, 2048 );
 934            dMemset( bufferSecure, 0, 2048 );
 935            dMemcpy( bufferSecure, szBuffer, dStrlen( szBuffer ) );
 936
 937            if( (*fld->setDataFn)( this, array, bufferSecure ) )
 938               Con::setData(fld->type, (void *) (((const char *)this) + fld->offset), array1, 1, &value, fld->table);
 939
 940            if(fld->validator)
 941               fld->validator->validateType(this, (void *) (((const char *)this) + fld->offset));
 942
 943            onStaticModified( slotName, value );
 944
 945            return;
 946         }
 947
 948         if(fld->validator)
 949            fld->validator->validateType(this, (void *) (((const char *)this) + fld->offset));
 950
 951         onStaticModified( slotName, value );
 952         return;
 953      }
 954   }
 955
 956   if(mFlags.test(ModDynamicFields))
 957   {
 958      if(!mFieldDictionary)
 959         mFieldDictionary = new SimFieldDictionary;
 960
 961      if(!array)
 962      {
 963         mFieldDictionary->setFieldValue(slotName, value);
 964         onDynamicModified( slotName, value );
 965      }
 966      else
 967      {
 968         char buf[256];
 969         dStrcpy(buf, slotName);
 970         dStrcat(buf, array);
 971         StringTableEntry permanentSlotName = StringTable->insert(buf);
 972         mFieldDictionary->setFieldValue(permanentSlotName, value);
 973         onDynamicModified( permanentSlotName, value );
 974      }
 975   }
 976}
 977
 978//-----------------------------------------------------------------------------
 979
 980const char *SimObject::getDataField(StringTableEntry slotName, const char *array)
 981{
 982   if(mFlags.test(ModStaticFields))
 983   {
 984      S32 array1 = array ? dAtoi(array) : -1;
 985      const AbstractClassRep::Field *fld = findField(slotName);
 986
 987      if(fld)
 988      {
 989         if(array1 == -1 && fld->elementCount == 1)
 990            return (*fld->getDataFn)( this, Con::getData(fld->type, (void *) (((const char *)this) + fld->offset), 0, fld->table, fld->flag) );
 991         if(array1 >= 0 && array1 < fld->elementCount)
 992            return (*fld->getDataFn)( this, Con::getData(fld->type, (void *) (((const char *)this) + fld->offset), array1, fld->table, fld->flag) );// + typeSizes[fld.type] * array1));
 993         return "";
 994      }
 995   }
 996
 997   if(mFlags.test(ModDynamicFields))
 998   {
 999      if(!mFieldDictionary)
1000         return "";
1001
1002      if(!array)
1003      {
1004         if (const char* val = mFieldDictionary->getFieldValue(slotName))
1005            return val;
1006      }
1007      else
1008      {
1009         static char buf[256];
1010         dStrcpy(buf, slotName);
1011         dStrcat(buf, array);
1012         if (const char* val = mFieldDictionary->getFieldValue(StringTable->insert(buf)))
1013            return val;
1014      }
1015   }
1016
1017   return "";
1018}
1019
1020
1021const char *SimObject::getPrefixedDataField(StringTableEntry fieldName, const char *array)
1022{
1023   // Sanity!
1024   AssertFatal(fieldName != NULL, "Cannot get field value with NULL field name.");
1025
1026   // Fetch field value.
1027   const char* pFieldValue = getDataField(fieldName, array);
1028
1029   // Sanity.
1030   //AssertFatal(pFieldValue != NULL, "Field value cannot be NULL.");
1031   if (!pFieldValue)
1032      return NULL;
1033
1034   // Return without the prefix if there's no value.
1035   if (*pFieldValue == 0)
1036      return StringTable->EmptyString();
1037
1038   // Fetch the field prefix.
1039   StringTableEntry fieldPrefix = getDataFieldPrefix(fieldName);
1040
1041   // Sanity!
1042   AssertFatal(fieldPrefix != NULL, "Field prefix cannot be NULL.");
1043
1044   // Calculate a buffer size including prefix.
1045   const U32 valueBufferSize = dStrlen(fieldPrefix) + dStrlen(pFieldValue) + 1;
1046
1047   // Fetch a buffer.
1048   char* pValueBuffer = Con::getReturnBuffer(valueBufferSize);
1049
1050   // Format the value buffer.
1051   dSprintf(pValueBuffer, valueBufferSize, "%s%s", fieldPrefix, pFieldValue);
1052
1053   return pValueBuffer;
1054}
1055
1056//-----------------------------------------------------------------------------
1057
1058void SimObject::setPrefixedDataField(StringTableEntry fieldName, const char *array, const char *value)
1059{
1060   // Sanity!
1061   AssertFatal(fieldName != NULL, "Cannot set object field value with NULL field name.");
1062   AssertFatal(value != NULL, "Field value cannot be NULL.");
1063
1064   // Set value without prefix if there's no value.
1065   if (*value == 0)
1066   {
1067      setDataField(fieldName, NULL, value);
1068      return;
1069   }
1070
1071   // Fetch the field prefix.
1072   StringTableEntry fieldPrefix = getDataFieldPrefix(fieldName);
1073
1074   // Sanity.
1075   AssertFatal(fieldPrefix != NULL, "Field prefix cannot be NULL.");
1076
1077   // Do we have a field prefix?
1078   if (fieldPrefix == StringTable->EmptyString())
1079   {
1080      // No, so set the data field in the usual way.
1081      setDataField(fieldName, NULL, value);
1082      return;
1083   }
1084
1085   // Yes, so fetch the length of the field prefix.
1086   const U32 fieldPrefixLength = dStrlen(fieldPrefix);
1087
1088   // Yes, so does it start with the object field prefix?
1089   if (dStrnicmp(value, fieldPrefix, fieldPrefixLength) != 0)
1090   {
1091      // No, so set the data field in the usual way.
1092      setDataField(fieldName, NULL, value);
1093      return;
1094   }
1095
1096   // Yes, so set the data excluding the prefix.
1097   setDataField(fieldName, NULL, value + fieldPrefixLength);
1098}
1099
1100//-----------------------------------------------------------------------------
1101
1102const char *SimObject::getPrefixedDynamicDataField(StringTableEntry fieldName, const char *array, const S32 fieldType)
1103{
1104   // Sanity!
1105   AssertFatal(fieldName != NULL, "Cannot get field value with NULL field name.");
1106
1107   // Fetch field value.
1108   const char* pFieldValue = getDataField(fieldName, array);
1109
1110   // Sanity.
1111   AssertFatal(pFieldValue != NULL, "Field value cannot be NULL.");
1112
1113   // Return the field if no field type is specified.
1114   if (fieldType == -1)
1115      return pFieldValue;
1116
1117   // Return without the prefix if there's no value.
1118   if (*pFieldValue == 0)
1119      return StringTable->EmptyString();
1120
1121   // Fetch the console base type.
1122   ConsoleBaseType* pConsoleBaseType = ConsoleBaseType::getType(fieldType);
1123
1124   // Did we find the console base type?
1125   if (pConsoleBaseType == NULL)
1126   {
1127      // No, so warn.
1128      Con::warnf("getPrefixedDynamicDataField() - Invalid field type '%d' specified for field '%s' with value '%s'.",
1129         fieldType, fieldName, pFieldValue);
1130   }
1131
1132   // Fetch the field prefix.
1133   StringTableEntry fieldPrefix = pConsoleBaseType->getTypePrefix();
1134
1135   // Sanity!
1136   AssertFatal(fieldPrefix != NULL, "Field prefix cannot be NULL.");
1137
1138   // Calculate a buffer size including prefix.
1139   const U32 valueBufferSize = dStrlen(fieldPrefix) + dStrlen(pFieldValue) + 1;
1140
1141   // Fetch a buffer.
1142   char* pValueBuffer = Con::getReturnBuffer(valueBufferSize);
1143
1144   // Format the value buffer.
1145   dSprintf(pValueBuffer, valueBufferSize, "%s%s", fieldPrefix, pFieldValue);
1146
1147   return pValueBuffer;
1148}
1149
1150//-----------------------------------------------------------------------------
1151
1152void SimObject::setPrefixedDynamicDataField(StringTableEntry fieldName, const char *array, const char *value, const S32 fieldType)
1153{
1154   // Sanity!
1155   AssertFatal(fieldName != NULL, "Cannot set object field value with NULL field name.");
1156   AssertFatal(value != NULL, "Field value cannot be NULL.");
1157
1158   // Set value without prefix if no field type was specified.
1159   if (fieldType == -1)
1160   {
1161      setDataField(fieldName, NULL, value);
1162      return;
1163   }
1164
1165   // Fetch the console base type.
1166   ConsoleBaseType* pConsoleBaseType = ConsoleBaseType::getType(fieldType);
1167
1168   // Did we find the console base type?
1169   if (pConsoleBaseType == NULL)
1170   {
1171      // No, so warn.
1172      Con::warnf("setPrefixedDynamicDataField() - Invalid field type '%d' specified for field '%s' with value '%s'.",
1173         fieldType, fieldName, value);
1174   }
1175
1176   // Set value without prefix if there's no value or we didn't find the console base type.
1177   if (*value == 0 || pConsoleBaseType == NULL)
1178   {
1179      setDataField(fieldName, NULL, value);
1180      return;
1181   }
1182
1183   // Fetch the field prefix.
1184   StringTableEntry fieldPrefix = pConsoleBaseType->getTypePrefix();
1185
1186   // Sanity.
1187   AssertFatal(fieldPrefix != NULL, "Field prefix cannot be NULL.");
1188
1189   // Do we have a field prefix?
1190   if (fieldPrefix == StringTable->EmptyString())
1191   {
1192      // No, so set the data field in the usual way.
1193      setDataField(fieldName, NULL, value);
1194      return;
1195   }
1196
1197   // Yes, so fetch the length of the field prefix.
1198   const U32 fieldPrefixLength = dStrlen(fieldPrefix);
1199
1200   // Yes, so does it start with the object field prefix?
1201   if (dStrnicmp(value, fieldPrefix, fieldPrefixLength) != 0)
1202   {
1203      // No, so set the data field in the usual way.
1204      setDataField(fieldName, NULL, value);
1205      return;
1206   }
1207
1208   // Yes, so set the data excluding the prefix.
1209   setDataField(fieldName, NULL, value + fieldPrefixLength);
1210}
1211
1212//-----------------------------------------------------------------------------
1213
1214StringTableEntry SimObject::getDataFieldPrefix(StringTableEntry fieldName)
1215{
1216   // Sanity!
1217   AssertFatal(fieldName != NULL, "Cannot get field prefix with NULL field name.");
1218
1219   // Find the field.
1220   const AbstractClassRep::Field* pField = findField(fieldName);
1221
1222   // Return nothing if field was not found.
1223   if (pField == NULL)
1224      return StringTable->EmptyString();
1225
1226   // Yes, so fetch the console base type.
1227   ConsoleBaseType* pConsoleBaseType = ConsoleBaseType::getType(pField->type);
1228
1229   // Fetch the type prefix.
1230   return pConsoleBaseType->getTypePrefix();
1231}
1232
1233
1234//-----------------------------------------------------------------------------
1235
1236U32 SimObject::getDataFieldType( StringTableEntry slotName, const char* array )
1237{
1238   const AbstractClassRep::Field* field = findField( slotName );
1239   if(field)
1240      return field->type;
1241
1242   // Check dynamic fields
1243   if(!mFieldDictionary)
1244      return 0;
1245
1246   if(array == NULL || *array == 0)
1247      return mFieldDictionary->getFieldType( slotName );
1248   else
1249   {
1250      static char buf[256];
1251      dStrcpy( buf, slotName );
1252      dStrcat( buf, array );
1253
1254      return mFieldDictionary->getFieldType( StringTable->insert( buf ) );
1255   }
1256}
1257
1258//-----------------------------------------------------------------------------
1259
1260void SimObject::setDataFieldType(const U32 fieldTypeId, StringTableEntry slotName, const char *array)
1261{
1262   // This only works on dynamic fields, bail if we have no field dictionary
1263   if(!mFieldDictionary)
1264      return;
1265
1266   if(array == NULL || *array == 0)
1267   {
1268      mFieldDictionary->setFieldType( slotName, fieldTypeId );
1269      onDynamicModified( slotName, mFieldDictionary->getFieldValue(slotName) );
1270   }
1271   else
1272   {
1273      static char buf[256];
1274      dStrcpy( buf, slotName );
1275      dStrcat( buf, array );
1276
1277      mFieldDictionary->setFieldType( StringTable->insert( buf ), fieldTypeId );
1278      onDynamicModified( slotName, mFieldDictionary->getFieldValue(slotName) );
1279   }
1280}
1281
1282//-----------------------------------------------------------------------------
1283
1284void SimObject::setDataFieldType(const char *typeName, StringTableEntry slotName, const char *array)
1285{
1286   // This only works on dynamic fields, bail if we have no field dictionary
1287   if(!mFieldDictionary)
1288      return;
1289
1290   if(array == NULL || *array == 0)
1291      mFieldDictionary->setFieldType( slotName, typeName );
1292   else
1293   {
1294      static char buf[256];
1295      dStrcpy( buf, slotName );
1296      dStrcat( buf, array );
1297      StringTableEntry permanentSlotName = StringTable->insert(buf);
1298
1299      mFieldDictionary->setFieldType( permanentSlotName, typeName );
1300      onDynamicModified( permanentSlotName, mFieldDictionary->getFieldValue(permanentSlotName) );
1301   }
1302}
1303
1304//-----------------------------------------------------------------------------
1305
1306void SimObject::dumpClassHierarchy()
1307{
1308   AbstractClassRep* pRep = getClassRep();
1309   while(pRep)
1310   {
1311      Con::warnf("%s ->", pRep->getClassName());
1312      pRep  =  pRep->getParentClass();
1313   }
1314}
1315
1316//-----------------------------------------------------------------------------
1317
1318SimObject* SimObject::clone()
1319{
1320   if( !getClassRep() )
1321      return NULL;
1322      
1323   ConsoleObject* conObject = getClassRep()->create();
1324   if( !conObject )
1325      return NULL;
1326      
1327   SimObject* simObject = dynamic_cast< SimObject* >( conObject );
1328   if( !simObject )
1329   {
1330      delete conObject;
1331      return NULL;
1332   }
1333   
1334   simObject->assignFieldsFrom( this );
1335
1336   String name = Sim::getUniqueName( getName() );
1337   if( !simObject->registerObject( name ) )
1338   {
1339      delete simObject;
1340      return NULL;
1341   }
1342      
1343   if( getGroup() )
1344      getGroup()->addObject( simObject );
1345   
1346   return simObject;
1347}
1348
1349//-----------------------------------------------------------------------------
1350
1351SimObject* SimObject::deepClone()
1352{
1353   return clone();
1354}
1355
1356//=============================================================================
1357//    Grouping.
1358//=============================================================================
1359// MARK: ---- Grouping ----
1360
1361//-----------------------------------------------------------------------------
1362
1363SimObject* SimObject::findObject( const char* )
1364{
1365   return NULL;
1366}
1367
1368//-----------------------------------------------------------------------------
1369
1370bool SimObject::isChildOfGroup(SimGroup* pGroup)
1371{
1372   if(!pGroup)
1373      return false;
1374
1375   //if we *are* the group in question,
1376   //return true:
1377   if(pGroup == dynamic_cast<SimGroup*>(this))
1378      return true;
1379
1380   SimGroup* temp =  mGroup;
1381   while(temp)
1382   {
1383      if(temp == pGroup)
1384         return true;
1385      temp = temp->mGroup;
1386   }
1387
1388   return false;
1389}
1390
1391//-----------------------------------------------------------------------------
1392
1393bool SimObject::addToSet(SimObjectId spid)
1394{
1395   if (mFlags.test(Added) == false)
1396      return false;
1397
1398   SimObject* ptr = Sim::findObject(spid);
1399   if (ptr)
1400   {
1401      SimSet* sp = dynamic_cast<SimSet*>(ptr);
1402      AssertFatal(sp != 0,
1403         "SimObject::addToSet: "
1404         "ObjectId does not refer to a set object");
1405      sp->addObject(this);
1406      return true;
1407   }
1408   return false;
1409}
1410
1411//-----------------------------------------------------------------------------
1412
1413bool SimObject::addToSet(const char *ObjectName)
1414{
1415   if (mFlags.test(Added) == false)
1416      return false;
1417
1418   SimObject* ptr = Sim::findObject(ObjectName);
1419   if (ptr)
1420   {
1421      SimSet* sp = dynamic_cast<SimSet*>(ptr);
1422      AssertFatal(sp != 0,
1423         "SimObject::addToSet: "
1424         "ObjectName does not refer to a set object");
1425      sp->addObject(this);
1426      return true;
1427   }
1428   return false;
1429}
1430
1431//-----------------------------------------------------------------------------
1432
1433bool SimObject::removeFromSet(SimObjectId sid)
1434{
1435   if (mFlags.test(Added) == false)
1436      return false;
1437
1438   SimSet *set;
1439   if(Sim::findObject(sid, set))
1440   {
1441      set->removeObject(this);
1442      return true;
1443   }
1444   return false;
1445}
1446
1447//-----------------------------------------------------------------------------
1448
1449bool SimObject::removeFromSet(const char *objectName)
1450{
1451   if (mFlags.test(Added) == false)
1452      return false;
1453
1454   SimSet *set;
1455   if(Sim::findObject(objectName, set))
1456   {
1457      set->removeObject(this);
1458      return true;
1459   }
1460   return false;
1461}
1462
1463//-----------------------------------------------------------------------------
1464
1465void SimObject::dumpGroupHierarchy()
1466{
1467   String className( getClassName() );
1468   String objectName( getName() );
1469
1470   Con::warnf( "[%i] %s - %s ->", getId(), className.c_str(), objectName.c_str() );
1471   
1472   if ( mGroup )
1473      mGroup->dumpGroupHierarchy();
1474}
1475
1476//=============================================================================
1477//    Events.
1478//=============================================================================
1479// MARK: ---- Events ----
1480
1481//-----------------------------------------------------------------------------
1482
1483bool SimObject::onAdd()
1484{
1485   mFlags.set(Added);
1486
1487   linkNamespaces();
1488
1489   return true;
1490}
1491
1492//-----------------------------------------------------------------------------
1493
1494void SimObject::onRemove()
1495{
1496   mFlags.clear(Added);
1497
1498   unlinkNamespaces();
1499}
1500
1501//-----------------------------------------------------------------------------
1502
1503void SimObject::onGroupAdd()
1504{
1505}
1506
1507//-----------------------------------------------------------------------------
1508
1509void SimObject::onGroupRemove()
1510{
1511}
1512
1513//-----------------------------------------------------------------------------
1514
1515void SimObject::onDeleteNotify(SimObject*)
1516{
1517}
1518
1519//-----------------------------------------------------------------------------
1520
1521void SimObject::onNameChange(const char*)
1522{
1523}
1524
1525//-----------------------------------------------------------------------------
1526
1527void SimObject::onStaticModified(const char* slotName, const char* newValue)
1528{
1529}
1530
1531//-----------------------------------------------------------------------------
1532
1533void SimObject::onDynamicModified(const char* slotName, const char* newValue)
1534{
1535}
1536
1537//=============================================================================
1538//    Notifications.
1539//=============================================================================
1540// MARK: ---- Notifications ----
1541
1542static Chunker<SimObject::Notify> notifyChunker(128000);
1543SimObject::Notify *SimObject::mNotifyFreeList = NULL;
1544
1545//-----------------------------------------------------------------------------
1546
1547SimObject::Notify *SimObject::allocNotify()
1548{
1549   if(mNotifyFreeList)
1550   {
1551      SimObject::Notify *ret = mNotifyFreeList;
1552      mNotifyFreeList = ret->next;
1553      return ret;
1554   }
1555   return notifyChunker.alloc();
1556}
1557
1558//-----------------------------------------------------------------------------
1559
1560void SimObject::freeNotify(SimObject::Notify* note)
1561{
1562   AssertFatal(note->type != SimObject::Notify::Invalid, "Invalid notify");
1563   note->type = SimObject::Notify::Invalid;
1564   note->next = mNotifyFreeList;
1565   mNotifyFreeList = note;
1566}
1567
1568//-----------------------------------------------------------------------------
1569
1570SimObject::Notify* SimObject::removeNotify(void *ptr, SimObject::Notify::Type type)
1571{
1572   Notify **list = &mNotifyList;
1573   while(*list)
1574   {
1575      if((*list)->ptr == ptr && (*list)->type == type)
1576      {
1577         SimObject::Notify *ret = *list;
1578         *list = ret->next;
1579         return ret;
1580      }
1581      list = &((*list)->next);
1582   }
1583   return NULL;
1584}
1585
1586//-----------------------------------------------------------------------------
1587
1588void SimObject::deleteNotify(SimObject* obj)
1589{
1590   AssertFatal(!obj->isDeleted(),
1591      "SimManager::deleteNotify: Object is being deleted");
1592   Notify *note = allocNotify();
1593   note->ptr = (void *) this;
1594   note->next = obj->mNotifyList;
1595   note->type = Notify::DeleteNotify;
1596   obj->mNotifyList = note;
1597
1598   note = allocNotify();
1599   note->ptr = (void *) obj;
1600   note->next = mNotifyList;
1601   note->type = Notify::ClearNotify;
1602   mNotifyList = note;
1603
1604   //obj->deleteNotifyList.pushBack(this);
1605   //clearNotifyList.pushBack(obj);
1606}
1607
1608//-----------------------------------------------------------------------------
1609
1610void SimObject::registerReference(SimObject **ptr)
1611{
1612   Notify *note = allocNotify();
1613   note->ptr = (void *) ptr;
1614   note->next = mNotifyList;
1615   note->type = Notify::ObjectRef;
1616   mNotifyList = note;
1617}
1618
1619//-----------------------------------------------------------------------------
1620
1621void SimObject::unregisterReference(SimObject **ptr)
1622{
1623   Notify *note = removeNotify((void *) ptr, Notify::ObjectRef);
1624   if(note)
1625   {
1626      freeNotify(note);
1627
1628      if( mFlags.test( AutoDelete ) )
1629      {
1630         for( Notify* n = mNotifyList; n != NULL; n = n->next )
1631            if( n->type == Notify::ObjectRef )
1632               return;
1633
1634         deleteObject();
1635      }
1636   }
1637}
1638
1639//-----------------------------------------------------------------------------
1640
1641void SimObject::clearNotify(SimObject* obj)
1642{
1643   Notify *note = obj->removeNotify((void *) this, Notify::DeleteNotify);
1644   if(note)
1645      freeNotify(note);
1646
1647   note = removeNotify((void *) obj, Notify::ClearNotify);
1648   if(note)
1649      freeNotify(note);
1650}
1651
1652//-----------------------------------------------------------------------------
1653
1654void SimObject::processDeleteNotifies()
1655{
1656   // clear out any delete notifies and
1657   // object refs.
1658
1659   while(mNotifyList)
1660   {
1661      Notify *note = mNotifyList;
1662      mNotifyList = note->next;
1663
1664      AssertFatal(note->type != Notify::ClearNotify, "Clear notes should be all gone.");
1665
1666      if(note->type == Notify::DeleteNotify)
1667      {
1668         SimObject *obj = (SimObject *) note->ptr;
1669         Notify *cnote = obj->removeNotify((void *)this, Notify::ClearNotify);
1670         obj->onDeleteNotify(this);
1671         freeNotify(cnote);
1672      }
1673      else
1674      {
1675         // it must be an object ref - a pointer refs this object
1676         *((SimObject **) note->ptr) = NULL;
1677      }
1678      freeNotify(note);
1679   }
1680}
1681
1682//-----------------------------------------------------------------------------
1683
1684void SimObject::clearAllNotifications()
1685{
1686   for(Notify **cnote = &mNotifyList; *cnote; )
1687   {
1688      Notify *temp = *cnote;
1689      if(temp->type == Notify::ClearNotify)
1690      {
1691         *cnote = temp->next;
1692         Notify *note = ((SimObject *) temp->ptr)->removeNotify((void *) this, Notify::DeleteNotify);
1693         freeNotify(temp);
1694         if ( note )
1695            freeNotify(note);
1696      }
1697      else
1698         cnote = &(temp->next);
1699   }
1700}
1701
1702//=============================================================================
1703//    Namespaces.
1704//=============================================================================
1705// MARK: ---- Namespaces ----
1706
1707//-----------------------------------------------------------------------------
1708
1709void SimObject::linkNamespaces()
1710{
1711   // Don't link if we already have a namespace linkage in place.
1712   // If you want to change namespace linking, first call unlinkNamespaces()
1713   // while still having the class namespace fields matching the current
1714   // setup.
1715
1716   if (mNameSpace)
1717   {
1718      Con::warnf("SimObject::linkNamespaces -- Namespace linkage already in place %s", mNameSpace->getName());
1719      return;
1720   }
1721   // Get the namespace for the C++ class.
1722
1723   Namespace* cppNamespace = getClassRep()->getNameSpace();
1724
1725   // Parent namespace defaults to namespace of C++ class.
1726
1727   Namespace* parentNamespace = cppNamespace;
1728
1729   // Perform superclass linking, if requested.
1730
1731   if( mSuperClassName && mSuperClassName[ 0 ] )
1732   {
1733      // Look up the superclass namespace.
1734
1735      Namespace* superClassNamespace = Con::lookupNamespace( mSuperClassName );
1736
1737      // If packages are active and adding to the superclass namespace, then we will
1738      // have multiple packages in a parent chain that all have the same name.
1739      // Con::lookupNamespace returns the bottom-most package in the chain to us so
1740      // in order to properly link namespace here without conflicting with the package
1741      // mechanism, we need to properly link child namespaces to the bottom-most namespace
1742      // while linking parent namespaces to the topmost namespace.  To find the latter
1743      // one, we walk up the hierarchy here.
1744
1745      Namespace* superClassNamespacePackageRoot = superClassNamespace->getPackageRoot();
1746
1747      // Link the superclass namespace to the C++ class namespace.
1748
1749      if( superClassNamespacePackageRoot->getParent() == NULL )
1750      {
1751         // The superclass namespace isn't linked yet so we just
1752         // link it to the C++ class namespace and make that our parent.
1753         // No increasing parent reference counts is needed in this case.
1754
1755         bool ok = superClassNamespacePackageRoot->classLinkTo( cppNamespace );
1756         AssertFatal( ok, "SimObject::linkNamespaces - failed to link new namespace to c++ class name" );
1757         parentNamespace = superClassNamespace;
1758      }
1759      else
1760      {
1761         // In debug builds, make sure the namespace hierarchy that's been
1762         // put into place actually makes sense and leads back to the C++
1763         // class namespace.
1764
1765#ifdef TORQUE_DEBUG
1766
1767         bool foundClassNameNS = false;
1768         for(  Namespace* linkWalk = superClassNamespacePackageRoot->getParent(); linkWalk != NULL;
1769               linkWalk = linkWalk->getParent() )
1770         {
1771            if( linkWalk == cppNamespace )
1772            {
1773               foundClassNameNS = true;
1774               break;
1775            }
1776         }
1777
1778         if( !foundClassNameNS )
1779         {
1780            // C++ class namespace not in parent link chain.  Warn about it.
1781
1782            Con::errorf(
1783               "SimObject::linkNamespaces - cannot link object to superclass %s because c++ class %s is not in the parent namespace chain.  Linking object to c++ class.",
1784               mSuperClassName,
1785               getClassName()
1786            );
1787            
1788            // Clear out superclass name so we don't come across it during
1789            // unlinking.
1790
1791            mSuperClassName = NULL;
1792         }
1793         else
1794
1795#endif
1796         {
1797            // Super link is ok.
1798
1799            parentNamespace = superClassNamespace;
1800
1801            // Now increase the reference count of all namespaces in the parent hierarchy
1802            // (up to the C++ class).
1803
1804            for( Namespace* linkWalk = parentNamespace;
1805                 linkWalk != NULL && linkWalk != cppNamespace && linkWalk->getParent() != NULL;
1806                 linkWalk = linkWalk->getParent() )
1807            {
1808               // Skip namespaces coming from packages.
1809               if( linkWalk->getPackage() != NULL )
1810                  continue;
1811
1812               linkWalk->incRefCountToParent();
1813            }
1814         }
1815      }
1816   }
1817
1818   // If class name is set, link it in as the new parent
1819   // which itself inherits from the current parent.
1820
1821   if( mClassName && mClassName[ 0 ] )
1822   {
1823      Namespace* classNamespace = Con::lookupNamespace( mClassName );
1824      if( classNamespace && classNamespace->classLinkTo( parentNamespace ) )
1825      {
1826         parentNamespace = classNamespace;
1827      }
1828      else
1829      {
1830         // Clear out class name so we don't perform a bogus unlink
1831         // in unlinkNamespaces().
1832         mClassName = NULL;
1833      }
1834   }
1835
1836   // Finally, if we have an object name, link its namespace
1837   // as the child to the current parent namespace and let it
1838   // become the final namespace of this object.
1839
1840   StringTableEntry objectName = getName();
1841   if( objectName && objectName[ 0 ] )
1842   {
1843      Namespace* objectNamespace = Con::lookupNamespace( objectName );
1844      if( objectNamespace && objectNamespace->classLinkTo( parentNamespace ) )
1845      {
1846         parentNamespace = objectNamespace;
1847      }
1848   }
1849
1850   // Store our namespace.
1851
1852   mNameSpace = parentNamespace;
1853}
1854
1855//-----------------------------------------------------------------------------
1856
1857void SimObject::unlinkNamespaces()
1858{
1859   if( !mNameSpace )
1860      return;
1861
1862   Namespace* cppNamespace = getClassRep()->getNameSpace();
1863   Namespace* parentNamespace = cppNamespace;
1864
1865   // Handle superclass.
1866
1867   if( mSuperClassName && mSuperClassName[ 0 ] )
1868   {
1869      // Get the superclass namespace.
1870
1871      Namespace* superClassNamespace = Con::lookupNamespace( mSuperClassName );
1872
1873      // Make it the parent namespace.
1874      
1875      parentNamespace = superClassNamespace;
1876
1877      // Decrease parent refcounts on the superclass hierarchy.
1878
1879      for( Namespace* linkWalk = superClassNamespace;
1880           linkWalk != NULL && linkWalk != cppNamespace && linkWalk->getParent() != NULL; )
1881      {
1882         // Store the parent link since it may disappear once we
1883         // decrease the reference count.
1884         Namespace* parent = linkWalk->getParent();
1885
1886         // Decrease the refcount.
1887         if( linkWalk->getPackage() == NULL ) // Skip namespaces coming from packages.
1888            linkWalk->decRefCountToParent();
1889
1890         // Walk up.
1891         linkWalk = parent;
1892      }
1893   }
1894
1895   // Handle class.
1896
1897   if( mClassName && mClassName[ 0 ] )
1898   {
1899      Namespace* classNamespace = Con::lookupNamespace( mClassName );
1900      if( classNamespace )
1901      {
1902         classNamespace->decRefCountToParent();
1903         parentNamespace = classNamespace;
1904      }
1905   }
1906
1907   // Handle object name.
1908
1909   StringTableEntry objectName = getName();
1910   if( objectName && objectName[ 0 ] )
1911      mNameSpace->decRefCountToParent();
1912
1913   mNameSpace = NULL;
1914}
1915
1916//-----------------------------------------------------------------------------
1917
1918void SimObject::setClassNamespace( const char *classNamespace )
1919{
1920   StringTableEntry oldClassNamespace = mClassName;
1921   StringTableEntry newClassNamespace = StringTable->insert( classNamespace );
1922   
1923   if( oldClassNamespace == newClassNamespace )
1924      return;
1925      
1926   if( isProperlyAdded() )
1927      unlinkNamespaces();
1928
1929   mClassName = newClassNamespace;
1930   
1931   if( isProperlyAdded() )
1932   {
1933      linkNamespaces();
1934      
1935      // Restore old namespace setup if linkage failed.
1936      
1937      if( mClassName != newClassNamespace )
1938      {
1939         mClassName = oldClassNamespace;
1940         linkNamespaces();
1941      }
1942   }
1943}
1944
1945//-----------------------------------------------------------------------------
1946
1947void SimObject::setSuperClassNamespace( const char *superClassNamespace )
1948{
1949   StringTableEntry oldSuperClassNamespace = mSuperClassName;
1950   StringTableEntry newSuperClassNamespace = StringTable->insert( superClassNamespace );
1951   
1952   if( oldSuperClassNamespace == newSuperClassNamespace )
1953      return;
1954      
1955   if( isProperlyAdded() )
1956      unlinkNamespaces();
1957   
1958   mSuperClassName = newSuperClassNamespace;
1959   
1960   if( isProperlyAdded() )
1961   {
1962      linkNamespaces();
1963      
1964      // Restore old setup if linkage failed.
1965      
1966      if( mSuperClassName != newSuperClassNamespace )
1967      {
1968         mSuperClassName = oldSuperClassNamespace;
1969         linkNamespaces();
1970      }
1971   }
1972}
1973
1974//=============================================================================
1975//    Misc.
1976//=============================================================================
1977// MARK: ---- Misc ----
1978
1979//-----------------------------------------------------------------------------
1980
1981void SimObject::setInternalName( const char* newname )
1982{
1983   if( newname )
1984      mInternalName = StringTable->insert( newname );
1985   else
1986      mInternalName = StringTable->EmptyString();
1987}
1988
1989//-----------------------------------------------------------------------------
1990
1991void SimObject::setOriginalName( const char* originalName )
1992{
1993   if( originalName )
1994      mOriginalName = StringTable->insert( originalName );
1995   else
1996      mOriginalName = StringTable->EmptyString();
1997}
1998
1999//-----------------------------------------------------------------------------
2000
2001const char *SimObject::tabComplete(const char *prevText, S32 baseLen, bool fForward)
2002{
2003   return mNameSpace->tabComplete(prevText, baseLen, fForward);
2004}
2005
2006//-----------------------------------------------------------------------------
2007
2008void SimObject::setSelected( bool sel )
2009{
2010   if( mFlags.test( Selected ) == sel )
2011      return; // No change.
2012
2013   if( sel )
2014   {
2015      mFlags.set( Selected );
2016      _onSelected();
2017   }
2018   else
2019   {
2020      mFlags.clear( Selected );
2021      _onUnselected();
2022   }
2023}
2024
2025//-----------------------------------------------------------------------------
2026
2027bool SimObject::isSelectedRecursive() const
2028{
2029   const SimObject *walk = this;
2030   while ( walk )
2031   {
2032      if ( walk->isSelected() )
2033         return true;
2034      walk = walk->getGroup();
2035   }
2036
2037   return false;   
2038}
2039
2040//-----------------------------------------------------------------------------
2041
2042void SimObject::setLocked( bool b )
2043{
2044   if( b )
2045      mFlags.set( Locked );
2046   else
2047      mFlags.clear( Locked );
2048}
2049
2050//-----------------------------------------------------------------------------
2051
2052void SimObject::setHidden( bool b )
2053{
2054   if( b )
2055      mFlags.set( Hidden );
2056   else
2057      mFlags.clear( Hidden );
2058}
2059
2060//-----------------------------------------------------------------------------
2061
2062void SimObject::setCopySource( SimObject* object )
2063{
2064   if( mCopySource )
2065      mCopySource->unregisterReference( &mCopySource );
2066   mCopySource = object;
2067   if( mCopySource )
2068      mCopySource->registerReference( &mCopySource );
2069}
2070
2071//---------------------------------------------------------------------------
2072
2073bool SimObject::_setCanSave( void* object, const char* index, const char* data )
2074{
2075   SimObject* obj = reinterpret_cast< SimObject* >( object );
2076   obj->setCanSave( dAtob( data ) );
2077   return false;
2078}
2079
2080//-----------------------------------------------------------------------------
2081
2082const char* SimObject::_getCanSave( void* object, const char* data )
2083{
2084   SimObject* obj = reinterpret_cast< SimObject* >( object );
2085   if( obj->getCanSave() )
2086      return "1";
2087   else
2088      return "0";
2089}
2090
2091//---------------------------------------------------------------------------
2092
2093// Copy SimObject to another SimObject (Originally designed for T2D).
2094void SimObject::copyTo( SimObject* object  )
2095{
2096   object->mClassName = mClassName;
2097   object->mSuperClassName = mSuperClassName;
2098
2099   linkNamespaces();
2100}
2101
2102//-----------------------------------------------------------------------------
2103
2104bool SimObject::setProtectedParent( void *obj, const char *index, const char *data )
2105{
2106   SimGroup *parent = NULL;
2107   SimObject *object = static_cast<SimObject*>(obj);
2108
2109   if(Sim::findObject(data, parent))
2110      parent->addObject(object);
2111
2112   // always return false, because we've set mGroup when we called addObject
2113   return false;
2114}
2115
2116//-----------------------------------------------------------------------------
2117
2118bool SimObject::setProtectedName(void *obj, const char *index, const char *data)
2119{   
2120   SimObject *object = static_cast<SimObject*>(obj);
2121   
2122   if ( object->isProperlyAdded() )
2123      object->assignName( data );   
2124
2125   // always return false because we assign the name here
2126   return false;
2127}
2128
2129//-----------------------------------------------------------------------------
2130
2131void SimObject::inspectPreApply()
2132{
2133}
2134
2135//-----------------------------------------------------------------------------
2136
2137void SimObject::inspectPostApply()
2138{
2139}
2140
2141//-----------------------------------------------------------------------------
2142
2143String SimObject::_getLogMessage(const char* fmt, va_list args) const
2144{
2145   String objClass = "UnknownClass";
2146   if(getClassRep())
2147      objClass = getClassRep()->getClassName();
2148      
2149   String objName = getName();
2150   if(objName.isEmpty())
2151      objName = "Unnamed";
2152   
2153   String formattedMessage = String::VToString(fmt, args);
2154   return String::ToString("%s - %s(%i) - %s", 
2155      objClass.c_str(), objName.c_str(), getId(), formattedMessage.c_str());
2156}
2157
2158//=============================================================================
2159//    API.
2160//=============================================================================
2161// MARK: ---- API ----
2162
2163//-----------------------------------------------------------------------------
2164
2165DefineEngineMethod( SimObject, dumpGroupHierarchy, void, (),,
2166   "Dump the hierarchy of this object up to RootGroup to the console." )
2167{
2168   object->dumpGroupHierarchy();
2169}
2170
2171//-----------------------------------------------------------------------------
2172
2173DefineConsoleMethod( SimObject, isMethod, bool, ( const char* methodName ),,
2174   "Test whether the given method is defined on this object.\n"
2175   "@param The name of the method.\n"
2176   "@return True if the object implements the given method." )
2177{
2178   return object->isMethod( methodName );
2179}
2180
2181//-----------------------------------------------------------------------------
2182
2183DefineEngineMethod( SimObject, isChildOfGroup, bool, ( SimGroup* group ),,
2184   "Test whether the object belongs directly or indirectly to the given group.\n"
2185   "@param group The SimGroup object.\n"
2186   "@return True if the object is a child of the given group or a child of a group that the given group is directly or indirectly a child to." )
2187{
2188   return object->isChildOfGroup( group );
2189}
2190
2191//-----------------------------------------------------------------------------
2192
2193DefineConsoleMethod( SimObject, getClassNamespace, const char*, (),,
2194   "Get the name of the class namespace assigned to this object.\n"
2195   "@return The name of the 'class' namespace." )
2196{
2197   return object->getClassNamespace();
2198}
2199
2200//-----------------------------------------------------------------------------
2201
2202DefineConsoleMethod( SimObject, getSuperClassNamespace, const char*, (),,
2203   "Get the name of the superclass namespace assigned to this object.\n"
2204   "@return The name of the 'superClass' namespace." )
2205{
2206   return object->getSuperClassNamespace();
2207}
2208
2209//-----------------------------------------------------------------------------
2210
2211DefineConsoleMethod( SimObject, setClassNamespace, void, ( const char* name ),,
2212   "Assign a class namespace to this object.\n"
2213   "@param name The name of the 'class' namespace for this object." )
2214{
2215   object->setClassNamespace( name );
2216}
2217
2218//-----------------------------------------------------------------------------
2219
2220DefineConsoleMethod( SimObject, setSuperClassNamespace, void, ( const char* name ),,
2221   "Assign a superclass namespace to this object.\n"
2222   "@param name The name of the 'superClass' namespace for this object." )
2223{
2224   object->setSuperClassNamespace( name );
2225}
2226
2227//-----------------------------------------------------------------------------
2228
2229DefineEngineMethod( SimObject, isSelected, bool, (),,
2230   "Get whether the object has been marked as selected. (in editor)\n"
2231   "@return True if the object is currently selected." )
2232{
2233   return object->isSelected();
2234}
2235
2236//-----------------------------------------------------------------------------
2237
2238DefineEngineMethod( SimObject, setIsSelected, void, ( bool state ), ( true ),
2239   "Set whether the object has been marked as selected. (in editor)\n"
2240   "@param state True if object is to be marked selected; false if not." )
2241{
2242   object->setSelected( state );
2243}
2244
2245//-----------------------------------------------------------------------------
2246
2247DefineConsoleMethod( SimObject, isExpanded, bool, (),,
2248   "Get whether the object has been marked as expanded. (in editor)\n"
2249   "@return True if the object is marked expanded." )
2250{
2251   return object->isExpanded();
2252}
2253
2254//-----------------------------------------------------------------------------
2255
2256DefineConsoleMethod( SimObject, setIsExpanded, void, ( bool state ), ( true ),
2257   "Set whether the object has been marked as expanded. (in editor)\n"
2258   "@param state True if the object is to be marked expanded; false if not." )
2259{
2260   object->setExpanded( state );
2261}
2262
2263//-----------------------------------------------------------------------------
2264
2265DefineConsoleMethod( SimObject, getFilename, const char*, (),,
2266   "Returns the filename the object is attached to.\n"
2267   "@return The name of the file the object is associated with; usually the file the object was loaded from." )
2268{
2269   return object->getFilename();
2270}
2271
2272//-----------------------------------------------------------------------------
2273
2274DefineConsoleMethod( SimObject, setFilename, void, ( const char* fileName ),,
2275   "Sets the object's file name and path\n"
2276   "@param fileName The name of the file to associate this object with." )
2277{
2278   return object->setFilename( fileName );
2279}
2280
2281//-----------------------------------------------------------------------------
2282
2283DefineConsoleMethod( SimObject, getDeclarationLine, S32, (),,
2284   "Get the line number at which the object is defined in its file.\n\n"
2285   "@return The line number of the object's definition in script.\n"
2286   "@see getFilename()")
2287{
2288   return object->getDeclarationLine();
2289}
2290
2291//-----------------------------------------------------------------------------
2292
2293#ifdef TORQUE_DEBUG
2294
2295static const char* sEnumCallbackFunction;
2296static void sEnumCallback( EngineObject* object )
2297{
2298   SimObject* simObject = dynamic_cast< SimObject* >( object );
2299   if( !simObject )
2300      return;
2301      
2302   Con::evaluatef( "%s( %i );", sEnumCallbackFunction, simObject->getId() );
2303}
2304
2305DefineEngineFunction( debugEnumInstances, void, ( const char* className, const char* functionName ),,
2306   "Call the given function for each instance of the given class.\n"
2307   "@param className Name of the class for which to enumerate instances.\n"
2308   "@param functionName Name of function to call and pass each instance of the given class.\n"
2309   "@note This function is only available in debug builds and primarily meant as an aid in debugging."
2310   "@ingroup Console")
2311{
2312   sEnumCallbackFunction = functionName;
2313   ConsoleObject::debugEnumInstances( className, sEnumCallback );
2314}
2315
2316#endif
2317
2318//-----------------------------------------------------------------------------
2319
2320DefineConsoleMethod( SimObject, assignFieldsFrom, void, ( SimObject* fromObject ),,
2321   "Copy fields from another object onto this one.  The objects must "
2322   "be of same type. Everything from the object will overwrite what's "
2323   "in this object; extra fields in this object will remain. This "
2324   "includes dynamic fields.\n"
2325   "@param fromObject The object from which to copy fields." )
2326{
2327   if( fromObject )
2328      object->assignFieldsFrom( fromObject );
2329}
2330
2331//-----------------------------------------------------------------------------
2332
2333DefineEngineMethod( SimObject, assignPersistentId, void, (),,
2334   "Assign a persistent ID to the object if it does not already have one." )
2335{
2336   object->getOrCreatePersistentId();
2337}
2338
2339//-----------------------------------------------------------------------------
2340
2341DefineConsoleMethod( SimObject, getCanSave, bool, (),,
2342   "Get whether the object will be included in saves.\n"
2343   "@return True if the object will be saved; false otherwise." )
2344{
2345   return object->getCanSave();
2346}
2347
2348//-----------------------------------------------------------------------------
2349
2350DefineConsoleMethod( SimObject, setCanSave, void, ( bool value ), ( true ),
2351   "Set whether the object will be included in saves.\n"
2352   "@param value If true, the object will be included in saves; if false, it will be excluded." )
2353{
2354   object->setCanSave( value );
2355}
2356
2357//-----------------------------------------------------------------------------
2358
2359DefineEngineMethod( SimObject, isEditorOnly, bool, (),,
2360   "Return true if the object is only used by the editor.\n"
2361   "@return True if this object exists only for the sake of editing." )
2362{
2363   return object->isEditorOnly();
2364}
2365
2366//-----------------------------------------------------------------------------
2367
2368DefineEngineMethod( SimObject, setEditorOnly, void, ( bool value ), ( true ),
2369   "Set/clear the editor-only flag on this object.\n"
2370   "@param value If true, the object is marked as existing only for the editor." )
2371{
2372   object->setEditorOnly( value );
2373}
2374
2375//-----------------------------------------------------------------------------
2376
2377DefineEngineMethod( SimObject, isNameChangeAllowed, bool, (),,
2378   "Get whether this object may be renamed.\n"
2379   "@return True if this object can be renamed; false otherwise." )
2380{
2381   return object->isNameChangeAllowed();
2382}
2383
2384//-----------------------------------------------------------------------------
2385
2386DefineEngineMethod( SimObject, setNameChangeAllowed, void, ( bool value ), ( true ),
2387   "Set whether this object can be renamed from its first name.\n"
2388   "@param value If true, renaming is allowed for this object; if false, trying to change the name of the object will generate a console error." )
2389{
2390   object->setNameChangeAllowed( value );
2391}
2392
2393//-----------------------------------------------------------------------------
2394
2395DefineEngineMethod( SimObject, clone, SimObject*, (),,
2396   "Create a copy of this object.\n"
2397   "@return An exact duplicate of this object." )
2398{
2399   return object->clone();
2400}
2401
2402//-----------------------------------------------------------------------------
2403
2404DefineEngineMethod( SimObject, deepClone, SimObject*, (),,
2405   "Create a copy of this object and all its subobjects.\n"
2406   "@return An exact duplicate of this object and all objects it references." )
2407{
2408   return object->deepClone();
2409}
2410
2411//-----------------------------------------------------------------------------
2412
2413DefineEngineMethod( SimObject, setLocked, void, ( bool value ), ( true ),
2414   "Lock/unlock the object in the editor.\n"
2415   "@param value If true, the object will be locked; if false, the object will be unlocked." )
2416{
2417   object->setLocked( value );
2418}
2419
2420//-----------------------------------------------------------------------------
2421
2422DefineEngineMethod( SimObject, setHidden, void, ( bool value ), ( true ),
2423   "Hide/unhide the object.\n"
2424   "@param value If true, the object will be hidden; if false, the object will be unhidden." )
2425{
2426   object->setHidden( value );
2427}
2428
2429//-----------------------------------------------------------------------------
2430
2431DefineConsoleMethod( SimObject, dumpMethods, ArrayObject*, (),,
2432   "List the methods defined on this object.\n\n"
2433   "Each description is a newline-separated vector with the following elements:\n"
2434   "- Minimum number of arguments.\n"
2435   "- Maximum number of arguments.\n"
2436   "- Prototype string.\n"
2437   "- Full script file path (if script method).\n"
2438   "- Line number of method definition in script (if script method).\n\n"
2439   "- Documentation string (not including prototype).  This takes up the remainder of the vector.\n"
2440   "@return An ArrayObject populated with (name,description) pairs of all methods defined on the object." )
2441{
2442   Namespace *ns = object->getNamespace();
2443   if( !ns )
2444      return 0;
2445      
2446   ArrayObject* dictionary = new ArrayObject();
2447   dictionary->registerObject();
2448   
2449   VectorPtr<Namespace::Entry*> vec(__FILE__, __LINE__);
2450   ns->getEntryList(&vec);
2451
2452   for(Vector< Namespace::Entry* >::iterator j = vec.begin(); j != vec.end(); j++)
2453   {
2454      Namespace::Entry* e = *j;
2455
2456      if( e->mType < 0 )
2457         continue;
2458         
2459      StringBuilder str;
2460      
2461      str.append( String::ToString( e->mMinArgs ) );
2462      str.append( '\n' );
2463      str.append( String::ToString( e->mMaxArgs ) );
2464      str.append( '\n' );
2465      str.append( e->getPrototypeString() );
2466
2467      str.append( '\n' );
2468      if( e->mCode && e->mCode->fullPath )
2469         str.append( e->mCode->fullPath );
2470      str.append( '\n' );
2471      if( e->mCode )
2472         str.append( String::ToString( e->mFunctionLineNumber ) );
2473
2474      str.append( '\n' );
2475      String docs = e->getDocString();
2476      if( !docs.isEmpty() )
2477         str.append( docs );
2478
2479      dictionary->push_back( e->mFunctionName, str.end() );
2480   }
2481   
2482   return dictionary;
2483}
2484
2485//-----------------------------------------------------------------------------
2486
2487namespace {
2488   S32 QSORT_CALLBACK compareFields( const void* a,const void* b )
2489   {
2490      const AbstractClassRep::Field* fa = *((const AbstractClassRep::Field**)a);
2491      const AbstractClassRep::Field* fb = *((const AbstractClassRep::Field**)b);
2492
2493      return dStricmp(fa->pFieldname, fb->pFieldname);
2494   }
2495   
2496   struct DocString
2497   {
2498      char mPadding[ 8 ];
2499      String mPrototype;
2500      String mDescription;
2501      const char* mReturnType;
2502      
2503      DocString( Namespace::Entry* entry )
2504         : mPrototype( entry->getArgumentsString() ),
2505           mDescription( entry->getBriefDescription() )
2506      {
2507         mReturnType = "        ";
2508         mPadding[ 0 ] = 0;
2509         if( entry->mType == -4 )
2510         {
2511            //TODO: need to have script callbacks set up proper return type info
2512         }
2513         else
2514         {
2515            switch( entry->mType )
2516            {
2517               case Namespace::Entry::StringCallbackType:
2518                  mReturnType = "string";
2519                  mPadding[ 0 ] = ' ';
2520                  mPadding[ 1 ] = ' ';
2521                  mPadding[ 2 ] = 0;
2522                  break;
2523                  
2524               case Namespace::Entry::IntCallbackType:
2525                  mReturnType = "int";
2526                  mPadding[ 0 ] = ' ';
2527                  mPadding[ 1 ] = ' ';
2528                  mPadding[ 2 ] = ' ';
2529                  mPadding[ 3 ] = ' ';
2530                  mPadding[ 4 ] = ' ';
2531                  mPadding[ 5 ] = 0;
2532                  break;
2533
2534               case Namespace::Entry::FloatCallbackType:
2535                  mReturnType = "float";
2536                  mPadding[ 0 ] = ' ';
2537                  mPadding[ 1 ] = ' ';
2538                  mPadding[ 2 ] = ' ';
2539                  mPadding[ 3 ] = 0;
2540                  break;
2541
2542               case Namespace::Entry::VoidCallbackType:
2543                  mReturnType = "void";
2544                  mPadding[ 0 ] = ' ';
2545                  mPadding[ 1 ] = ' ';
2546                  mPadding[ 2 ] = ' ';
2547                  mPadding[ 3 ] = ' ';
2548                  mPadding[ 4 ] = 0;
2549                  break;
2550
2551               case Namespace::Entry::BoolCallbackType:
2552                  mReturnType = "bool";
2553                  mPadding[ 0 ] = ' ';
2554                  mPadding[ 1 ] = ' ';
2555                  mPadding[ 2 ] = ' ';
2556                  mPadding[ 3 ] = ' ';
2557                  mPadding[ 4 ] = 0;
2558                  break;                  
2559            }
2560         }
2561      }
2562   };
2563}
2564
2565DefineEngineMethod( SimObject, dump, void, ( bool detailed ), ( false ),
2566   "Dump a description of all fields and methods defined on this object to the console.\n"
2567   "@param detailed Whether to print detailed information about members." )
2568{
2569   Con::printf( "Class: %s", object->getClassName() );
2570   
2571   const AbstractClassRep::FieldList &list = object->getFieldList();
2572   char expandedBuffer[4096];
2573
2574   Con::printf( "Static Fields:" );
2575   Vector<const AbstractClassRep::Field*> flist(__FILE__, __LINE__);
2576
2577   for(U32 i = 0; i < list.size(); i++)
2578      flist.push_back(&list[i]);
2579
2580   dQsort(flist.address(),flist.size(),sizeof(AbstractClassRep::Field *),compareFields);
2581
2582   for(Vector<const AbstractClassRep::Field *>::iterator itr = flist.begin(); itr != flist.end(); itr++)
2583   {
2584      const AbstractClassRep::Field* f = *itr;
2585
2586      // The special field types can be skipped.
2587      if ( f->type >= AbstractClassRep::ARCFirstCustomField )
2588         continue;
2589
2590      for(U32 j = 0; S32(j) < f->elementCount; j++)
2591      {
2592         // [neo, 07/05/2007 - #3000]
2593         // Some objects use dummy vars and projected fields so make sure we call the get functions 
2594         //const char *val = Con::getData(f->type, (void *) (((const char *)object) + f->offset), j, f->table, f->flag);                          
2595         const char *val = (*f->getDataFn)( object, Con::getData(f->type, (void *) (((const char *)object) + f->offset), j, f->table, f->flag) );// + typeSizes[fld.type] * array1));
2596         
2597         ConsoleBaseType* conType = ConsoleBaseType::getType( f->type );
2598         const char* conTypeName = "<unknown>";
2599         if( conType )
2600            conTypeName = conType->getTypeClassName();
2601
2602         if( !val /*|| !*val*/ )
2603            continue;
2604         if( f->elementCount == 1 )
2605            dSprintf( expandedBuffer, sizeof( expandedBuffer ), "  %s %s = \"", conTypeName, f->pFieldname );
2606         else
2607            dSprintf( expandedBuffer, sizeof( expandedBuffer ), "  %s %s[ %d ] = \"", conTypeName, f->pFieldname, j );
2608         expandEscape( expandedBuffer + dStrlen(expandedBuffer), val);
2609         Con::printf( "%s\"", expandedBuffer );
2610         
2611         if( detailed && f->pFieldDocs && f->pFieldDocs[ 0 ] )
2612            Con::printf( "    %s", f->pFieldDocs );
2613      }
2614   }
2615
2616   Con::printf( "Dynamic Fields:" );
2617   if(object->getFieldDictionary())
2618      object->getFieldDictionary()->printFields(object);
2619
2620   Con::printf( "Methods:" );
2621   Namespace *ns = object->getNamespace();
2622   VectorPtr<Namespace::Entry*> vec(__FILE__, __LINE__);
2623
2624   if(ns)
2625      ns->getEntryList(&vec);
2626
2627   bool sawCBs = false;
2628
2629   for(Vector<Namespace::Entry *>::iterator j = vec.begin(); j != vec.end(); j++)
2630   {
2631      Namespace::Entry *e = *j;
2632
2633      if(e->mType == Namespace::Entry::ScriptCallbackType)
2634         sawCBs = true;
2635
2636      if(e->mType < 0)
2637         continue;
2638         
2639      DocString doc( e );
2640      Con::printf( "  %s%s%s%s", doc.mReturnType, doc.mPadding, e->mFunctionName, doc.mPrototype.c_str() );
2641
2642      if( detailed && !doc.mDescription.isEmpty() )
2643         Con::printf( "    %s", doc.mDescription.c_str() );
2644   }
2645
2646   if( sawCBs )
2647   {
2648      Con::printf( "Callbacks:" );
2649
2650      for(Vector<Namespace::Entry *>::iterator j = vec.begin(); j != vec.end(); j++)
2651      {
2652         Namespace::Entry *e = *j;
2653
2654         if(e->mType != Namespace::Entry::ScriptCallbackType)
2655            continue;
2656
2657         DocString doc( e );
2658         Con::printf( "  %s%s%s%s", doc.mReturnType, doc.mPadding, e->cb.mCallbackName, doc.mPrototype.c_str() );
2659
2660         if( detailed && !doc.mDescription.isEmpty() )
2661            Con::printf( "    %s", doc.mDescription.c_str() );
2662      }
2663   }
2664}
2665
2666//-----------------------------------------------------------------------------
2667
2668DefineConsoleMethod( SimObject, save, bool, ( const char* fileName, bool selectedOnly, const char* preAppendString ), ( false, "" ),
2669   "Save out the object to the given file.\n"
2670   "@param fileName The name of the file to save to."
2671   "@param selectedOnly If true, only objects marked as selected will be saved out.\n"
2672   "@param preAppendString Text which will be preprended directly to the object serialization.\n"
2673   "@param True on success, false on failure." )
2674{
2675   return object->save( fileName, selectedOnly, preAppendString );
2676}
2677
2678//-----------------------------------------------------------------------------
2679
2680DefineEngineMethod( SimObject, setName, void, ( const char* newName ),,
2681   "Set the global name of the object.\n"
2682   "@param newName The new global name to assign to the object.\n"
2683   "@note If name changing is disallowed on the object, the method will fail with a console error." )
2684{
2685   object->assignName( newName );
2686}
2687
2688//-----------------------------------------------------------------------------
2689
2690DefineEngineMethod( SimObject, getName, const char*, (),,
2691   "Get the global name of the object.\n"
2692   "@return The global name assigned to the object." )
2693{
2694   const char *ret = object->getName();
2695   return ret ? ret : "";
2696}
2697
2698//-----------------------------------------------------------------------------
2699
2700DefineConsoleMethod( SimObject, getClassName, const char*, (),,
2701   "Get the name of the C++ class which the object is an instance of.\n"
2702   "@return The name of the C++ class of the object." )
2703{
2704   const char *ret = object->getClassName();
2705   return ret ? ret : "";
2706}
2707
2708//-----------------------------------------------------------------------------
2709
2710DefineConsoleMethod( SimObject, isField, bool, ( const char* fieldName ),,
2711   "Test whether the given field is defined on this object.\n"
2712   "@param fieldName The name of the field.\n"
2713   "@return True if the object implements the given field." )
2714{
2715   return object->isField( fieldName );
2716}
2717
2718//-----------------------------------------------------------------------------
2719
2720DefineConsoleMethod( SimObject, getFieldValue, const char*, ( const char* fieldName, S32 index ), ( -1 ),
2721   "Return the value of the given field on this object.\n"
2722   "@param fieldName The name of the field.  If it includes a field index, the index is parsed out.\n"
2723   "@param index Optional parameter to specify the index of an array field separately.\n"
2724   "@return The value of the given field or \"\" if undefined." )
2725{
2726   char fieldNameBuffer[ 1024 ];
2727   char arrayIndexBuffer[ 64 ];
2728   
2729   // Parse out index if the field is given in the form of 'name[index]'.
2730   
2731   const char* arrayIndex = NULL;
2732   const U32 nameLen = dStrlen( fieldName );
2733   if( fieldName[ nameLen - 1 ] == ']' )
2734   {
2735      const char* leftBracket = dStrchr( fieldName, '[' );
2736      const char* rightBracket = &fieldName[ nameLen - 1 ];
2737      
2738      const U32 fieldNameLen = getMin( U32( leftBracket - fieldName ), sizeof( fieldNameBuffer ) - 1 );
2739      const U32 arrayIndexLen = getMin( U32( rightBracket - leftBracket - 1 ), sizeof( arrayIndexBuffer ) - 1 );
2740      
2741      dMemcpy( fieldNameBuffer, fieldName, fieldNameLen );
2742      dMemcpy( arrayIndexBuffer, leftBracket + 1, arrayIndexLen );
2743      
2744      fieldNameBuffer[ fieldNameLen ] = '\0';
2745      arrayIndexBuffer[ arrayIndexLen ] = '\0';
2746      
2747      fieldName = fieldNameBuffer;
2748      arrayIndex = arrayIndexBuffer;
2749   }
2750
2751   fieldName = StringTable->insert( fieldName );
2752   
2753   if( index != -1 )
2754   {
2755      dSprintf( arrayIndexBuffer, sizeof( arrayIndexBuffer ), "%i", index );
2756      arrayIndex = arrayIndexBuffer;
2757   }
2758   
2759   return object->getDataField( fieldName, arrayIndex );
2760}
2761
2762//-----------------------------------------------------------------------------
2763
2764DefineConsoleMethod( SimObject, setFieldValue, bool, ( const char* fieldName, const char* value, S32 index ), ( -1 ),
2765   "Set the value of the given field on this object.\n"
2766   "@param fieldName The name of the field to assign to.  If it includes an array index, the index will be parsed out.\n"
2767   "@param value The new value to assign to the field.\n"
2768   "@param index Optional argument to specify an index for an array field.\n"
2769   "@return True." )
2770{
2771   char fieldNameBuffer[ 1024 ];
2772   char arrayIndexBuffer[ 64 ];
2773   
2774   // Parse out index if the field is given in the form of 'name[index]'.
2775   
2776   const char* arrayIndex = NULL;
2777   const U32 nameLen = dStrlen( fieldName );
2778   if( fieldName[ nameLen - 1 ] == ']' )
2779   {
2780      const char* leftBracket = dStrchr( fieldName, '[' );
2781      const char* rightBracket = &fieldName[ nameLen - 1 ];
2782      
2783      const U32 fieldNameLen = getMin( U32( leftBracket - fieldName ), sizeof( fieldNameBuffer ) - 1 );
2784      const U32 arrayIndexLen = getMin( U32( rightBracket - leftBracket - 1 ), sizeof( arrayIndexBuffer ) - 1 );
2785      
2786      dMemcpy( fieldNameBuffer, fieldName, fieldNameLen );
2787      dMemcpy( arrayIndexBuffer, leftBracket + 1, arrayIndexLen );
2788      
2789      fieldNameBuffer[ fieldNameLen ] = '\0';
2790      arrayIndexBuffer[ arrayIndexLen ] = '\0';
2791      
2792      fieldName = fieldNameBuffer;
2793      arrayIndex = arrayIndexBuffer;
2794   }
2795
2796   fieldName = StringTable->insert( fieldName );
2797
2798   if( index != -1 )
2799   {
2800      dSprintf( arrayIndexBuffer, sizeof( arrayIndexBuffer ), "%i", index );
2801      arrayIndex = arrayIndexBuffer;
2802   }
2803
2804   object->setDataField( fieldName, arrayIndex, value );
2805
2806   return true;
2807}
2808
2809//-----------------------------------------------------------------------------
2810
2811DefineConsoleMethod( SimObject, getFieldType, const char*, ( const char* fieldName ),,
2812   "Get the console type code of the given field.\n"
2813   "@return The numeric type code for the underlying console type of the given field." )
2814{
2815   U32 typeID = object->getDataFieldType( StringTable->insert( fieldName ), NULL );
2816   ConsoleBaseType* type = ConsoleBaseType::getType( typeID );
2817
2818   if( type )
2819      return type->getTypeName();
2820
2821   return "";
2822}
2823
2824//-----------------------------------------------------------------------------
2825
2826DefineConsoleMethod( SimObject, setFieldType, void, ( const char* fieldName, const char* type ),,
2827   "Set the console type code for the given field.\n"
2828   "@param fieldName The name of the dynamic field to change to type for.\n"
2829   "@param type The name of the console type.\n"
2830   "@note This only works for dynamic fields.  Types of static fields cannot be changed." )
2831{
2832   object->setDataFieldType( type, StringTable->insert( fieldName ), NULL );
2833}
2834
2835//-----------------------------------------------------------------------------
2836
2837ConsoleMethod( SimObject, call, const char*, 3, 0, "( string method, string args... ) Dynamically call a method on an object.\n"
2838   "@param method Name of method to call.\n"
2839   "@param args Zero or more arguments for the method.\n"
2840   "@return The result of the method call." )
2841{
2842   argv[1] = argv[2];
2843   return Con::execute( object, argc - 1, argv + 1 );
2844}
2845
2846//-----------------------------------------------------------------------------
2847
2848DefineEngineMethod( SimObject, setInternalName, void, ( const char* newInternalName ),,
2849   "Set the internal name of the object.\n"
2850   "@param newInternalName The new internal name for the object." )
2851{
2852   object->setInternalName( newInternalName );
2853}
2854
2855//-----------------------------------------------------------------------------
2856
2857DefineEngineMethod( SimObject, getInternalName, const char*, (),,
2858   "Get the internal name of the object.\n"
2859   "@return The internal name of the object." )
2860{
2861   return object->getInternalName();
2862}
2863
2864//-----------------------------------------------------------------------------
2865
2866DefineConsoleMethod( SimObject, dumpClassHierarchy, void, (),,
2867   "Dump the native C++ class hierarchy of this object's C++ class to the console." )
2868{
2869   object->dumpClassHierarchy();
2870}
2871
2872//-----------------------------------------------------------------------------
2873
2874DefineConsoleMethod( SimObject, isMemberOfClass, bool, ( const char* className ),,
2875   "Test whether this object is a member of the specified class.\n"
2876   "@param className Name of a native C++ class.\n"
2877   "@return True if this object is an instance of the given C++ class or any of its super classes." )
2878{
2879   AbstractClassRep* pRep = object->getClassRep();
2880   while(pRep)
2881   {
2882      if( !dStricmp(pRep->getClassName(), className ) )
2883      {
2884         //matches
2885         return true;
2886      }
2887
2888      pRep  =  pRep->getParentClass();
2889   }
2890
2891   return false;
2892}
2893
2894//-----------------------------------------------------------------------------
2895
2896DefineConsoleMethod( SimObject, isInNamespaceHierarchy, bool, ( const char* name ),,
2897   "Test whether the namespace of this object is a direct or indirect child to the given namespace.\n"
2898   "@param name The name of a namespace.\n"
2899   "@return True if the given namespace name is within the namespace hierarchy of this object." )
2900{
2901   Namespace* nspace = object->getNamespace();
2902      
2903   while( nspace && dStricmp( nspace->mName, name ) != 0 )
2904      nspace = nspace->mParent;
2905      
2906   return ( nspace != NULL );
2907}
2908
2909//-----------------------------------------------------------------------------
2910
2911DefineEngineMethod( SimObject, getId, S32, (),,
2912   "Get the underlying unique numeric ID of the object.\n"
2913   "@note Object IDs are unique only during single engine runs.\n"
2914   "@return The unique numeric ID of the object." )
2915{
2916   return object->getId();
2917}
2918
2919//-----------------------------------------------------------------------------
2920
2921DefineEngineMethod( SimObject, getGroup, SimGroup*, (),,
2922   "Get the group that this object is contained in.\n"
2923   "@note If not assigned to particular SimGroup, an object belongs to RootGroup.\n"
2924   "@return The SimGroup object to which the object belongs." )
2925{
2926   return object->getGroup();
2927}
2928
2929//-----------------------------------------------------------------------------
2930
2931DefineConsoleMethod( SimObject, delete, void, (),,
2932   "Delete and remove the object." )
2933{
2934   object->deleteObject();
2935}
2936
2937//-----------------------------------------------------------------------------
2938
2939ConsoleMethod( SimObject,schedule, S32, 4, 0, "( float time, string method, string args... ) Delay an invocation of a method.\n"
2940   "@param time The number of milliseconds after which to invoke the method.  This is a soft limit.\n"
2941   "@param method The method to call.\n"
2942   "@param args The arguments with which to call the method.\n"
2943   "@return The numeric ID of the created schedule.  Can be used to cancel the call.\n" )
2944{
2945   U32 timeDelta = U32(dAtof(argv[2]));
2946   argv[2] = argv[3];
2947   argv[3] = argv[1];
2948   SimConsoleEvent *evt = new SimConsoleEvent(argc - 2, argv + 2, true);
2949   S32 ret = Sim::postEvent(object, evt, Sim::getCurrentTime() + timeDelta);
2950   // #ifdef DEBUG
2951   //    Con::printf("obj %s schedule(%s) = %d", argv[3], argv[2], ret);
2952   //    Con::executef( "backtrace");
2953   // #endif
2954   return ret;
2955}
2956
2957//-----------------------------------------------------------------------------
2958
2959DefineConsoleMethod( SimObject, getDynamicFieldCount, S32, (),,
2960   "Get the number of dynamic fields defined on the object.\n"
2961   "@return The number of dynamic fields defined on the object." )
2962{
2963   S32 count = 0;
2964   SimFieldDictionary* fieldDictionary = object->getFieldDictionary();
2965   for (SimFieldDictionaryIterator itr(fieldDictionary); *itr; ++itr)
2966      count++;
2967
2968   return count;
2969}
2970
2971//-----------------------------------------------------------------------------
2972
2973DefineConsoleMethod( SimObject, getDynamicField, const char*, ( S32 index ),,
2974   "Get a value of a dynamic field by index.\n"
2975   "@param index The index of the dynamic field.\n"
2976   "@return The value of the dynamic field at the given index or \"\"." )
2977{
2978   SimFieldDictionary* fieldDictionary = object->getFieldDictionary();
2979   SimFieldDictionaryIterator itr(fieldDictionary);
2980   for (S32 i = 0; i < index; i++)
2981   {
2982      if (!(*itr))
2983      {
2984         Con::warnf("Invalid dynamic field index passed to SimObject::getDynamicField!");
2985         return NULL;
2986      }
2987      ++itr;
2988   }
2989
2990   static const U32 bufSize = 256;
2991   char* buffer = Con::getReturnBuffer(bufSize);
2992   if (*itr)
2993   {
2994      SimFieldDictionary::Entry* entry = *itr;
2995      dSprintf(buffer, bufSize, "%s\t%s", entry->slotName, entry->value);
2996      return buffer;
2997   }
2998
2999   Con::warnf("Invalid dynamic field index passed to SimObject::getDynamicField!");
3000   return NULL;
3001}
3002
3003//-----------------------------------------------------------------------------
3004
3005DefineConsoleMethod( SimObject, getFieldCount, S32, (),,
3006   "Get the number of static fields on the object.\n"
3007   "@return The number of static fields defined on the object." )
3008{
3009   const AbstractClassRep::FieldList &list = object->getFieldList();
3010   const AbstractClassRep::Field* f;
3011   U32 numDummyEntries = 0;
3012
3013   for(S32 i = 0; i < list.size(); i++)
3014   {
3015      f = &list[i];
3016
3017      // The special field types do not need to be counted.
3018      if ( f->type >= AbstractClassRep::ARCFirstCustomField )
3019         numDummyEntries++;
3020   }
3021
3022   return list.size() - numDummyEntries;
3023}
3024
3025//-----------------------------------------------------------------------------
3026
3027DefineConsoleMethod( SimObject, getField, const char*, ( S32 index ),,
3028   "Retrieve the value of a static field by index.\n"
3029   "@param index The index of the static field.\n"
3030   "@return The value of the static field with the given index or \"\"." )
3031{
3032   const AbstractClassRep::FieldList &list = object->getFieldList();
3033   if( ( index < 0 ) || ( index >= list.size() ) )
3034      return "";
3035
3036   const AbstractClassRep::Field* f;
3037   S32 currentField = 0;
3038   for ( U32 i = 0; i < list.size() && currentField <= index; i++ )
3039   {
3040      f = &list[i];
3041
3042      // The special field types can be skipped.
3043      if ( f->type >= AbstractClassRep::ARCFirstCustomField )
3044         continue;
3045
3046      if(currentField == index)
3047         return f->pFieldname;
3048
3049      currentField++;
3050   }
3051
3052   // if we found nada, return nada.
3053   return "";
3054}
3055
3056//-----------------------------------------------------------------------------
3057
3058#ifdef TORQUE_DEBUG
3059
3060DefineEngineMethod( SimObject, getDebugInfo, ArrayObject*, (),,
3061   "Return some behind-the-scenes information on the object.\n"
3062   "@return An ArrayObject filled with internal information about the object." )
3063{
3064   ArrayObject* array = new ArrayObject();
3065   array->registerObject();
3066   
3067   array->push_back( "C++|Address", String::ToString( "0x%x", object ) );
3068   array->push_back( "C++|Size", String::ToString( object->getClassRep()->getSizeof() ) );
3069   array->push_back( "Object|Description", object->describeSelf() );
3070   array->push_back( "Object|FileName", object->getFilename() );
3071   array->push_back( "Object|DeclarationLine", String::ToString( object->getDeclarationLine() ) );
3072   array->push_back( "Object|CopySource", object->getCopySource() ?
3073      String::ToString( "%i:%s (%s)", object->getCopySource()->getId(), object->getCopySource()->getClassName(), object->getCopySource()->getName() ) : "" );
3074   array->push_back( "Flag|EditorOnly", object->isEditorOnly() ? "true" : "false" );
3075   array->push_back( "Flag|NameChangeAllowed", object->isNameChangeAllowed() ? "true" : "false" );
3076   array->push_back( "Flag|AutoDelete", object->isAutoDeleted() ? "true" : "false" );
3077   array->push_back( "Flag|Selected", object->isSelected() ? "true" : "false" );
3078   array->push_back( "Flag|Expanded", object->isExpanded() ? "true" : "false" );
3079   array->push_back( "Flag|ModStaticFields", object->canModStaticFields() ? "true" : "false" );
3080   array->push_back( "Flag|ModDynamicFields", object->canModDynamicFields() ? "true" : "false" );
3081   array->push_back( "Flag|CanSave", object->getCanSave() ? "true" : "false" );
3082   
3083   #ifndef TORQUE_DISABLE_MEMORY_MANAGER
3084   Memory::Info memInfo;
3085   Memory::getMemoryInfo( object, memInfo );
3086   
3087   array->push_back( "Memory|AllocNumber", String::ToString( memInfo.mAllocNumber ) );
3088   array->push_back( "Memory|AllocSize", String::ToString( memInfo.mAllocSize ) );
3089   array->push_back( "Memory|AllocFile", memInfo.mFileName );
3090   array->push_back( "Memory|AllocLine", String::ToString( memInfo.mLineNumber ) );
3091   array->push_back( "Memory|IsGlobal", memInfo.mIsGlobal ? "true" : "false" );
3092   array->push_back( "Memory|IsStatic", memInfo.mIsStatic ? "true" : "false" );
3093   #endif
3094   
3095   return array;
3096}
3097
3098#endif
3099