mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-01-20 12:44:46 +00:00
1362 lines
52 KiB
C++
1362 lines
52 KiB
C++
//-----------------------------------------------------------------------------
|
|
// Copyright (c) 2012 GarageGames, LLC
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
// of this software and associated documentation files (the "Software"), to
|
|
// deal in the Software without restriction, including without limitation the
|
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
// sell copies of the Software, and to permit persons to whom the Software is
|
|
// furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in
|
|
// all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
// IN THE SOFTWARE.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
|
// Copyright (C) 2015 Faust Logic, Inc.
|
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
|
#ifndef _CONSOLEOBJECT_H_
|
|
#define _CONSOLEOBJECT_H_
|
|
|
|
#ifndef _TVECTOR_H_
|
|
#include "core/util/tVector.h"
|
|
#endif
|
|
#ifndef _STRINGTABLE_H_
|
|
#include "core/stringTable.h"
|
|
#endif
|
|
#ifndef _STRINGFUNCTIONS_H_
|
|
#include "core/strings/stringFunctions.h"
|
|
#endif
|
|
#ifndef _BITSET_H_
|
|
#include "core/bitSet.h"
|
|
#endif
|
|
#ifndef _DYNAMIC_CONSOLETYPES_H_
|
|
#include "console/dynamicTypes.h"
|
|
#endif
|
|
#ifndef _ENGINEOBJECT_H_
|
|
#include "console/engineObject.h"
|
|
#endif
|
|
#ifndef _ENGINEFUNCTIONS_H_
|
|
#include "console/engineFunctions.h"
|
|
#endif
|
|
#ifndef _SIMOBJECTREF_H_
|
|
#include "console/simObjectRef.h"
|
|
#endif
|
|
#ifndef TINYXML_INCLUDED
|
|
#include "tinyxml2.h"
|
|
#endif
|
|
|
|
#ifndef _CONSOLFUNCTIONS_H_
|
|
#include "console/consoleFunctions.h"
|
|
#endif
|
|
|
|
/// @file
|
|
/// Legacy console object system.
|
|
|
|
|
|
/// @ingroup console_system Console System
|
|
/// @{
|
|
|
|
class Namespace;
|
|
class ConsoleObject;
|
|
|
|
enum NetClassTypes
|
|
{
|
|
NetClassTypeObject = 0,
|
|
NetClassTypeDataBlock,
|
|
NetClassTypeEvent,
|
|
NetClassTypesCount,
|
|
};
|
|
|
|
enum NetClassGroups
|
|
{
|
|
NetClassGroupGame = 0,
|
|
NetClassGroupCommunity,
|
|
NetClassGroup3,
|
|
NetClassGroup4,
|
|
NetClassGroupsCount,
|
|
};
|
|
|
|
enum NetClassMasks
|
|
{
|
|
NetClassGroupGameMask = BIT(NetClassGroupGame),
|
|
NetClassGroupCommunityMask = BIT(NetClassGroupCommunity),
|
|
};
|
|
|
|
enum NetDirection
|
|
{
|
|
NetEventDirAny,
|
|
NetEventDirServerToClient,
|
|
NetEventDirClientToServer,
|
|
};
|
|
|
|
class SimObject;
|
|
class TypeValidator;
|
|
class ConsoleClassObject;
|
|
|
|
DECLARE_SCOPE( ConsoleAPI );
|
|
|
|
|
|
//=============================================================================
|
|
// AbstractClassRep.
|
|
//=============================================================================
|
|
|
|
|
|
/// Core functionality for class manipulation.
|
|
///
|
|
/// @section AbstractClassRep_intro Introduction (or, Why AbstractClassRep?)
|
|
///
|
|
/// Many of Torque's subsystems, especially network, console, and sim,
|
|
/// require the ability to programatically instantiate classes. For instance,
|
|
/// when objects are ghosted, the networking layer needs to be able to create
|
|
/// an instance of the object on the client. When the console scripting
|
|
/// language runtime encounters the "new" keyword, it has to be able to fill
|
|
/// that request.
|
|
///
|
|
/// Since standard C++ doesn't provide a function to create a new instance of
|
|
/// an arbitrary class at runtime, one must be created. This is what
|
|
/// AbstractClassRep and ConcreteClassRep are all about. They allow the registration
|
|
/// and instantiation of arbitrary classes at runtime.
|
|
///
|
|
/// In addition, ACR keeps track of the fields (registered via addField() and co.) of
|
|
/// a class, allowing programmatic access of class fields.
|
|
///
|
|
/// @see ConsoleObject
|
|
///
|
|
/// @note In general, you will only access the functionality implemented in this class via
|
|
/// ConsoleObject::create(). Most of the time, you will only ever need to use this part
|
|
/// part of the engine indirectly - ie, you will use the networking system or the console,
|
|
/// or ConsoleObject, and they will indirectly use this code. <b>The following discussion
|
|
/// is really only relevant for advanced engine users.</b>
|
|
///
|
|
/// @section AbstractClassRep_netstuff NetClasses and Class IDs
|
|
///
|
|
/// Torque supports a notion of group, type, and direction for objects passed over
|
|
/// the network. Class IDs are assigned sequentially per-group, per-type, so that, for instance,
|
|
/// the IDs assigned to Datablocks are seperate from the IDs assigned to NetObjects or NetEvents.
|
|
/// This can translate into significant bandwidth savings (especially since the size of the fields
|
|
/// for transmitting these bits are determined at run-time based on the number of IDs given out.
|
|
///
|
|
/// @section AbstractClassRep_details AbstractClassRep Internals
|
|
///
|
|
/// Much like ConsoleConstructor, ACR does some preparatory work at runtime before execution
|
|
/// is passed to main(). In actual fact, this preparatory work is done by the ConcreteClassRep
|
|
/// template. Let's examine this more closely.
|
|
///
|
|
/// If we examine ConsoleObject, we see that two macros must be used in the definition of a
|
|
/// properly integrated objects. From the ConsoleObject example:
|
|
///
|
|
/// @code
|
|
/// // This is from inside the class definition...
|
|
/// DECLARE_CONOBJECT(TorqueObject);
|
|
///
|
|
/// // And this is from outside the class definition...
|
|
/// IMPLEMENT_CONOBJECT(TorqueObject);
|
|
/// @endcode
|
|
///
|
|
/// What do these things actually do?
|
|
///
|
|
/// Not all that much, in fact. They expand to code something like this:
|
|
///
|
|
/// @code
|
|
/// // This is from inside the class definition...
|
|
/// static ConcreteClassRep<TorqueObject> dynClassRep;
|
|
/// static AbstractClassRep* getParentStaticClassRep();
|
|
/// static AbstractClassRep* getStaticClassRep();
|
|
/// virtual AbstractClassRep* getClassRep() const;
|
|
/// @endcode
|
|
///
|
|
/// @code
|
|
/// // And this is from outside the class definition...
|
|
/// AbstractClassRep* TorqueObject::getClassRep() const { return &TorqueObject::dynClassRep; }
|
|
/// AbstractClassRep* TorqueObject::getStaticClassRep() { return &dynClassRep; }
|
|
/// AbstractClassRep* TorqueObject::getParentStaticClassRep() { return Parent::getStaticClassRep(); }
|
|
/// ConcreteClassRep<TorqueObject> TorqueObject::dynClassRep("TorqueObject", 0, -1, 0);
|
|
/// @endcode
|
|
///
|
|
/// As you can see, getClassRep(), getStaticClassRep(), and getParentStaticClassRep() are just
|
|
/// accessors to allow access to various ConcreteClassRep instances. This is where the Parent
|
|
/// typedef comes into play as well - it lets getParentStaticClassRep() get the right
|
|
/// class rep.
|
|
///
|
|
/// In addition, dynClassRep is declared as a member of TorqueObject, and defined later
|
|
/// on. Much like ConsoleConstructor, ConcreteClassReps add themselves to a global linked
|
|
/// list in their constructor.
|
|
///
|
|
/// Then, when AbstractClassRep::initialize() is called, from Con::init(), we iterate through
|
|
/// the list and perform the following tasks:
|
|
/// - Sets up a Namespace for each class.
|
|
/// - Call the init() method on each ConcreteClassRep. This method:
|
|
/// - Links namespaces between parent and child classes, using Con::classLinkNamespaces.
|
|
/// - Calls initPersistFields() and consoleInit().
|
|
/// - As a result of calling initPersistFields, the field list for the class is populated.
|
|
/// - Assigns network IDs for classes based on their NetGroup membership. Determines
|
|
/// bit allocations for network ID fields.
|
|
///
|
|
/// @nosubgrouping
|
|
class AbstractClassRep : public ConsoleBaseType
|
|
{
|
|
friend class ConsoleObject;
|
|
|
|
public:
|
|
|
|
typedef ConsoleBaseType Parent;
|
|
|
|
/// Allows the writing of a custom TAML schema.
|
|
typedef void(*WriteCustomTamlSchema)(const AbstractClassRep* pClassRep, tinyxml2::XMLElement* pParentElement);
|
|
|
|
/// @name 'Tructors
|
|
/// @{
|
|
|
|
///
|
|
/// @param conIdPtr Pointer to the static S32 console ID.
|
|
/// @param conTypeName Console type name.
|
|
AbstractClassRep( S32* conIdPtr, const char* typeName )
|
|
: Parent( sizeof( void* ), conIdPtr, typeName )
|
|
{
|
|
VECTOR_SET_ASSOCIATION( mFieldList );
|
|
mCategory = StringTable->EmptyString();
|
|
mClassGroupMask = 0;
|
|
std::fill_n(mClassId, NetClassGroupsCount, -1);
|
|
mClassName = StringTable->EmptyString();
|
|
mClassSizeof = 0;
|
|
mClassType = 0;
|
|
mDescription = StringTable->EmptyString();
|
|
#ifdef TORQUE_NET_STATS
|
|
dMemset(mDirtyMaskFrequency, 0, sizeof(mDirtyMaskFrequency));
|
|
dMemset(mDirtyMaskTotal, 0, sizeof(mDirtyMaskTotal));
|
|
#endif
|
|
mDynamicGroupExpand = false;
|
|
mNamespace = NULL;
|
|
mNetEventDir = 0;
|
|
nextClass = NULL;
|
|
parentClass = NULL;
|
|
mIsRenderEnabled = true;
|
|
mIsSelectionEnabled = true;
|
|
}
|
|
|
|
/// @}
|
|
|
|
/// @name Representation Interface
|
|
/// @{
|
|
|
|
//TODO: move over to EngineTypeNetInfo
|
|
S32 mClassGroupMask; ///< Mask indicating in which NetGroups this object belongs.
|
|
S32 mClassType; ///< Stores the NetClass of this class.
|
|
S32 mNetEventDir; ///< Stores the NetDirection of this class.
|
|
S32 mClassId[ NetClassGroupsCount ]; ///< Stores the IDs assigned to this class for each group.
|
|
S32 mClassSizeof; ///< Size of instances in bytes.
|
|
|
|
//TODO: move over to EngineTypeNetInfo
|
|
#ifdef TORQUE_NET_STATS
|
|
struct NetStatInstance
|
|
{
|
|
U32 numEvents;
|
|
U32 total;
|
|
S32 min;
|
|
S32 max;
|
|
|
|
void reset()
|
|
{
|
|
numEvents = 0;
|
|
total = 0;
|
|
min = S32_MAX;
|
|
max = S32_MIN;
|
|
}
|
|
|
|
void update(U32 amount)
|
|
{
|
|
numEvents++;
|
|
total += amount;
|
|
min = getMin((S32)amount, min);
|
|
max = getMax((S32)amount, max);
|
|
}
|
|
|
|
NetStatInstance()
|
|
{
|
|
reset();
|
|
}
|
|
};
|
|
|
|
NetStatInstance mNetStatPack;
|
|
NetStatInstance mNetStatUnpack;
|
|
NetStatInstance mNetStatWrite;
|
|
NetStatInstance mNetStatRead;
|
|
|
|
U32 mDirtyMaskFrequency[32];
|
|
U32 mDirtyMaskTotal[32];
|
|
|
|
void resetNetStats()
|
|
{
|
|
mNetStatPack.reset();
|
|
mNetStatUnpack.reset();
|
|
mNetStatWrite.reset();
|
|
mNetStatRead.reset();
|
|
|
|
for(S32 i=0; i<32; i++)
|
|
{
|
|
mDirtyMaskFrequency[i] = 0;
|
|
mDirtyMaskTotal[i] = 0;
|
|
}
|
|
}
|
|
|
|
void updateNetStatPack(U32 dirtyMask, U32 length)
|
|
{
|
|
mNetStatPack.update(length);
|
|
|
|
for(S32 i=0; i<32; i++)
|
|
if(BIT(i) & dirtyMask)
|
|
{
|
|
mDirtyMaskFrequency[i]++;
|
|
mDirtyMaskTotal[i] += length;
|
|
}
|
|
}
|
|
|
|
void updateNetStatUnpack(U32 length)
|
|
{
|
|
mNetStatUnpack.update(length);
|
|
}
|
|
|
|
void updateNetStatWriteData(U32 length)
|
|
{
|
|
mNetStatWrite.update(length);
|
|
}
|
|
|
|
void updateNetStatReadData(U32 length)
|
|
{
|
|
mNetStatRead.update(length);
|
|
}
|
|
#endif
|
|
S32 getClassId (U32 netClassGroup) const { return mClassId[ netClassGroup ]; }
|
|
static U32 getClassCRC (U32 netClassGroup) { return classCRC[ netClassGroup ]; }
|
|
AbstractClassRep* getCommonParent( const AbstractClassRep *otherClass ) const;
|
|
|
|
/// Return the name of this class.
|
|
StringTableEntry getClassName() const { return mClassName; }
|
|
|
|
/// Return the namespace that contains the methods of this class.
|
|
Namespace* getNameSpace() const { return mNamespace; }
|
|
|
|
/// Return the AbstractClassRep of the class that this class is derived from.
|
|
AbstractClassRep* getParentClass() const { return parentClass; }
|
|
|
|
virtual AbstractClassRep* getContainerChildClass(const bool recurse) = 0;
|
|
virtual WriteCustomTamlSchema getCustomTamlSchema(void) = 0;
|
|
|
|
/// Return the size of instances of this class in bytes.
|
|
S32 getSizeof() const { return mClassSizeof; }
|
|
|
|
/// Return the next class in the global class list link chain.
|
|
AbstractClassRep* getNextClass() const { return nextClass; }
|
|
|
|
/// Return the head of the global class list.
|
|
static AbstractClassRep* getClassList() { return classLinkList; }
|
|
|
|
/// Helper class to see if we are a given class, or a subclass thereof by
|
|
/// comparing AbstractClassRep pointers.
|
|
bool isSubclassOf( const AbstractClassRep* klass ) const
|
|
{
|
|
const AbstractClassRep *walk = this;
|
|
|
|
// Walk up parents, checking for equivalence.
|
|
while ( walk )
|
|
{
|
|
if ( walk == klass )
|
|
return true;
|
|
|
|
walk = walk->parentClass;
|
|
};
|
|
|
|
return false;
|
|
}
|
|
|
|
/// Helper class to see if we are a given class, or a subclass thereof by
|
|
/// comparing the class name strings.
|
|
bool isSubclassOf( const char *klass ) const
|
|
{
|
|
klass = StringTable->insert( klass );
|
|
|
|
// Walk up parents, checking for equivalence.
|
|
const AbstractClassRep *walk = this;
|
|
while ( walk )
|
|
{
|
|
if ( walk->mClassName == klass )
|
|
return true;
|
|
|
|
walk = walk->parentClass;
|
|
};
|
|
|
|
return false;
|
|
}
|
|
|
|
/// @deprecated Use isSubclassOf.
|
|
bool isClass( const AbstractClassRep* acr ) const
|
|
{
|
|
return isSubclassOf( acr );
|
|
}
|
|
|
|
virtual ConsoleObject* create () const = 0;
|
|
|
|
AbstractClassRep* findFieldRoot(StringTableEntry fieldName);
|
|
|
|
protected:
|
|
|
|
virtual void init();
|
|
|
|
const char * mClassName;
|
|
AbstractClassRep * nextClass;
|
|
AbstractClassRep * parentClass;
|
|
Namespace * mNamespace;
|
|
|
|
/// @}
|
|
|
|
public:
|
|
|
|
bool mIsRenderEnabled;
|
|
bool mIsSelectionEnabled;
|
|
|
|
bool isRenderEnabled() const { return mIsRenderEnabled; }
|
|
bool isSelectionEnabled() const { return mIsSelectionEnabled; }
|
|
|
|
/// @name Categories
|
|
/// @{
|
|
|
|
protected:
|
|
|
|
const char* mCategory;
|
|
const char* mDescription;
|
|
|
|
public:
|
|
|
|
/// Return the space separated category path for the class.
|
|
const char* getCategory() const { return mCategory; }
|
|
|
|
/// Return a short description string suitable for displaying in tooltips.
|
|
const char* getDescription() const { return mDescription; }
|
|
|
|
/// @}
|
|
|
|
/// @name Fields
|
|
/// @{
|
|
public:
|
|
|
|
/// This is a function pointer typedef to support get/set callbacks for fields
|
|
typedef bool (*SetDataNotify)( void *obj, const char *array, const char *data );
|
|
typedef const char *(*GetDataNotify)( void *obj, const char *data );
|
|
|
|
/// This is a function pointer typedef to support optional writing for fields.
|
|
typedef bool(*WriteDataNotify)(void* obj, StringTableEntry pFieldName);
|
|
|
|
/// These are special field type values used to mark
|
|
/// groups and arrays in the field list.
|
|
/// @see Field::type
|
|
/// @see addArray, endArray
|
|
/// @see addGroup, endGroup
|
|
/// @see addGroup, endGroup
|
|
/// @see addDeprecatedField
|
|
enum ACRFieldTypes : U32
|
|
{
|
|
/// The first custom field type... all fields
|
|
/// types greater or equal to this one are not
|
|
/// console data types.
|
|
ARCFirstCustomField = 0xFFFFFFFB,
|
|
|
|
/// Marks the start of a fixed size array of fields.
|
|
/// @see addArray
|
|
StartArrayFieldType = 0xFFFFFFFB,
|
|
|
|
/// Marks the end of a fixed size array of fields.
|
|
/// @see endArray
|
|
EndArrayFieldType = 0xFFFFFFFC,
|
|
|
|
/// Marks the beginning of a group of fields.
|
|
/// @see addGroup
|
|
StartGroupFieldType = 0xFFFFFFFD,
|
|
|
|
/// Marks the beginning of a group of fields.
|
|
/// @see endGroup
|
|
EndGroupFieldType = 0xFFFFFFFE,
|
|
|
|
/// Marks a field that is depreciated and no
|
|
/// longer stores a value.
|
|
/// @see addDeprecatedField
|
|
DeprecatedFieldType = 0xFFFFFFFF
|
|
};
|
|
|
|
enum FieldFlags
|
|
{
|
|
FIELD_HideInInspectors = BIT( 0 ), ///< Do not show the field in inspectors.
|
|
FIELD_ComponentInspectors = BIT(1), ///< Custom fields used by components. They are likely to be non-standard size/configuration, so
|
|
///< They are handled specially
|
|
FIELD_CustomInspectors = BIT(2), ///< Display as a button in inspectors.
|
|
};
|
|
|
|
struct Field
|
|
{
|
|
Field()
|
|
: pFieldname( NULL ),
|
|
pGroupname( NULL ),
|
|
pFieldDocs( NULL ),
|
|
groupExpand( false ),
|
|
type( 0 ),
|
|
offset( 0 ),
|
|
elementCount( 0 ),
|
|
table( NULL ),
|
|
validator( NULL ),
|
|
setDataFn( NULL ),
|
|
getDataFn( NULL ),
|
|
writeDataFn(NULL),
|
|
networkMask(0)
|
|
{
|
|
doNotSubstitute = keepClearSubsOnly = false;
|
|
}
|
|
|
|
StringTableEntry pFieldname; ///< Name of the field.
|
|
const char* pGroupname; ///< Optionally filled field containing the group name.
|
|
///
|
|
/// This is filled when type is StartField or EndField
|
|
|
|
const char* pFieldDocs; ///< Documentation about this field; see consoleDoc.cc.
|
|
bool groupExpand; ///< Flag to track expanded/not state of this group in the editor.
|
|
U32 type; ///< A data type ID or one of the special custom fields. @see ACRFieldTypes
|
|
U32 offset; ///< Memory offset from beginning of class for this field.
|
|
S32 elementCount; ///< Number of elements, if this is an array.
|
|
const EnumTable * table; ///< If this is an enum, this points to the table defining it.
|
|
BitSet32 flag; ///< Stores various flags
|
|
TypeValidator *validator; ///< Validator, if any.
|
|
SetDataNotify setDataFn; ///< Set data notify Fn
|
|
GetDataNotify getDataFn; ///< Get data notify Fn
|
|
WriteDataNotify writeDataFn; ///< Function to determine whether data should be written or not.
|
|
bool doNotSubstitute;
|
|
bool keepClearSubsOnly;
|
|
|
|
U32 networkMask;
|
|
};
|
|
typedef Vector<Field> FieldList;
|
|
|
|
FieldList mFieldList;
|
|
|
|
bool mDynamicGroupExpand;
|
|
|
|
const Field* findField( StringTableEntry fieldName ) const;
|
|
|
|
/// @}
|
|
|
|
/// @name Console Type Interface
|
|
/// @{
|
|
|
|
virtual void* getNativeVariable() { return new ( AbstractClassRep* ); } // Any pointer-sized allocation will do.
|
|
virtual void deleteNativeVariable( void* var ) { delete reinterpret_cast< AbstractClassRep** >( var ); }
|
|
|
|
/// @}
|
|
|
|
/// @name Abstract Class Database
|
|
/// @{
|
|
|
|
protected:
|
|
static AbstractClassRep ** classTable[NetClassGroupsCount][NetClassTypesCount];
|
|
static AbstractClassRep * classLinkList;
|
|
static U32 classCRC[NetClassGroupsCount];
|
|
static bool initialized;
|
|
|
|
static ConsoleObject* create(const char* in_pClassName);
|
|
static ConsoleObject* create(const U32 groupId, const U32 typeId, const U32 in_classId);
|
|
|
|
public:
|
|
static U32 NetClassCount [NetClassGroupsCount][NetClassTypesCount];
|
|
static U32 NetClassBitSize[NetClassGroupsCount][NetClassTypesCount];
|
|
|
|
static void registerClassRep(AbstractClassRep*);
|
|
static AbstractClassRep* findClassRep(const char* in_pClassName);
|
|
static AbstractClassRep* findClassRep( U32 groupId, U32 typeId, U32 classId );
|
|
static void removeClassRep(AbstractClassRep*); // This should not be used lightly
|
|
static void initialize(); // Called from Con::init once on startup
|
|
static void shutdown();
|
|
|
|
|
|
/// @}
|
|
};
|
|
|
|
extern AbstractClassRep::FieldList sg_tempFieldList;
|
|
|
|
|
|
//=============================================================================
|
|
// ConcreteClassRep.
|
|
//=============================================================================
|
|
|
|
|
|
/// Helper class for AbstractClassRep.
|
|
///
|
|
/// @see AbtractClassRep
|
|
/// @see ConsoleObject
|
|
template< class T >
|
|
class ConcreteAbstractClassRep : public AbstractClassRep
|
|
{
|
|
public:
|
|
|
|
virtual AbstractClassRep* getContainerChildClass(const bool recurse)
|
|
{
|
|
// Fetch container children type.
|
|
AbstractClassRep* pChildren = T::getContainerChildStaticClassRep();
|
|
if (!recurse || pChildren != NULL)
|
|
return pChildren;
|
|
|
|
// Fetch parent type.
|
|
AbstractClassRep* pParent = T::getParentStaticClassRep();
|
|
if (pParent == NULL)
|
|
return NULL;
|
|
|
|
// Get parent container children.
|
|
return pParent->getContainerChildClass(recurse);
|
|
}
|
|
|
|
virtual WriteCustomTamlSchema getCustomTamlSchema(void)
|
|
{
|
|
return T::getStaticWriteCustomTamlSchema();
|
|
}
|
|
|
|
static EnginePropertyTable _smPropertyTable;
|
|
static EnginePropertyTable& smPropertyTable;
|
|
|
|
ConcreteAbstractClassRep(const char* name,
|
|
const char* conTypeName,
|
|
S32* conTypeIdPtr,
|
|
S32 netClassGroupMask,
|
|
S32 netClassType,
|
|
S32 netEventDir,
|
|
AbstractClassRep* parent,
|
|
const char* (*parentDesc)())
|
|
: AbstractClassRep(conTypeIdPtr, conTypeName)
|
|
{
|
|
mClassName = StringTable->insert(name);
|
|
mCategory = T::__category();
|
|
mTypeInfo = _MAPTYPE< T >();
|
|
|
|
if (mTypeInfo)
|
|
const_cast< EngineTypeInfo* >(mTypeInfo)->mPropertyTable = &smPropertyTable;
|
|
|
|
if (&T::__description != parentDesc)
|
|
mDescription = T::__description();
|
|
|
|
// Clean up mClassId
|
|
for (U32 i = 0; i < NetClassGroupsCount; i++)
|
|
mClassId[i] = -1;
|
|
|
|
// Set properties for this ACR
|
|
mClassType = netClassType;
|
|
mClassGroupMask = netClassGroupMask;
|
|
mNetEventDir = netEventDir;
|
|
parentClass = parent;
|
|
mClassSizeof = sizeof(T);
|
|
|
|
// Finally, register ourselves.
|
|
registerClassRep(this);
|
|
};
|
|
|
|
/// Wrap constructor.
|
|
ConsoleObject* create() const { return NULL; }
|
|
|
|
/// Perform class specific initialization tasks.
|
|
///
|
|
/// Link namespaces, call initPersistFields() and consoleInit().
|
|
void init()
|
|
{
|
|
// Get handle to our parent class, if any, and ourselves (we are our parent's child).
|
|
AbstractClassRep *parent = T::getParentStaticClassRep();
|
|
AbstractClassRep *child = T::getStaticClassRep();
|
|
|
|
// If we got reps, then link those namespaces! (To get proper inheritance.)
|
|
if (parent && child)
|
|
Con::classLinkNamespaces(parent->getNameSpace(), child->getNameSpace());
|
|
|
|
// Finally, do any class specific initialization...
|
|
T::initPersistFields();
|
|
T::consoleInit();
|
|
|
|
EnginePropertyTable::Property* props = new EnginePropertyTable::Property[sg_tempFieldList.size()];
|
|
|
|
for (int i = 0; i < sg_tempFieldList.size(); ++i)
|
|
{
|
|
EnginePropertyTable::Property prop;
|
|
prop.mDocString = sg_tempFieldList[i].pFieldDocs;
|
|
prop.mName = sg_tempFieldList[i].pFieldname;
|
|
prop.mNumElements = sg_tempFieldList[i].elementCount;
|
|
prop.mFlags = 0;
|
|
if (sg_tempFieldList[i].type == StartGroupFieldType)
|
|
prop.mFlags |= EnginePropertyGroupBegin;
|
|
if (sg_tempFieldList[i].type == EndGroupFieldType)
|
|
prop.mFlags |= EnginePropertyGroupEnd;
|
|
prop.mType = sg_tempFieldList[i].type;
|
|
|
|
props[i] = prop;
|
|
}
|
|
|
|
_smPropertyTable = EnginePropertyTable(sg_tempFieldList.size(), props);
|
|
smPropertyTable = _smPropertyTable;
|
|
|
|
const_cast<EngineTypeInfo*>(mTypeInfo)->mPropertyTable = &_smPropertyTable;
|
|
|
|
// Let the base finish up.
|
|
AbstractClassRep::init();
|
|
}
|
|
|
|
/// @name Console Type Interface
|
|
/// @{
|
|
|
|
virtual void setData(void* dptr, S32 argc, const char** argv, const EnumTable* tbl, BitSet32 flag)
|
|
{
|
|
if (argc == 1)
|
|
{
|
|
T** obj = (T**)dptr;
|
|
*obj = dynamic_cast< T* >(T::__findObject(argv[0]));
|
|
}
|
|
else
|
|
Con::errorf("Cannot set multiple args to a single ConsoleObject*.");
|
|
}
|
|
|
|
virtual const char* getData(void* dptr, const EnumTable* tbl, BitSet32 flag)
|
|
{
|
|
T** obj = (T**)dptr;
|
|
return Con::getReturnBuffer(T::__getObjectId(*obj));
|
|
}
|
|
|
|
virtual const char* getTypeClassName() { return mClassName; }
|
|
virtual const bool isDatablock() { return T::__smIsDatablock; };
|
|
|
|
/// @}
|
|
};
|
|
|
|
template< class T >
|
|
class ConcreteClassRep : public ConcreteAbstractClassRep<T>
|
|
{
|
|
public:
|
|
ConcreteClassRep(const char* name,
|
|
const char* conTypeName,
|
|
S32* conTypeIdPtr,
|
|
S32 netClassGroupMask,
|
|
S32 netClassType,
|
|
S32 netEventDir,
|
|
AbstractClassRep* parent,
|
|
const char* (*parentDesc)())
|
|
: ConcreteAbstractClassRep<T>(name, conTypeName, conTypeIdPtr, netClassGroupMask, netClassType, netEventDir, parent, parentDesc)
|
|
{
|
|
}
|
|
|
|
/// Wrap constructor.
|
|
ConsoleObject* create() const { return new T; }
|
|
};
|
|
|
|
template< typename T > EnginePropertyTable ConcreteAbstractClassRep< T >::_smPropertyTable(0, NULL);
|
|
template< typename T > EnginePropertyTable& ConcreteAbstractClassRep< T >::smPropertyTable = ConcreteAbstractClassRep< T >::_smPropertyTable;
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Forward declaration of this function so it can be used in the class
|
|
const char *defaultProtectedGetFn( void *obj, const char *data );
|
|
bool defaultProtectedWriteFn(void* obj, StringTableEntry pFieldName);
|
|
|
|
//=============================================================================
|
|
// ConsoleObject.
|
|
//=============================================================================
|
|
|
|
|
|
/// Interface class to the console.
|
|
///
|
|
/// @section ConsoleObject_basics The Basics
|
|
///
|
|
/// Any object which you want to work with the console system should derive from this,
|
|
/// and access functionality through the static interface.
|
|
///
|
|
/// This class is always used with the DECLARE_CONOBJECT and IMPLEMENT_* macros.
|
|
///
|
|
/// @code
|
|
/// // A very basic example object. It will do nothing!
|
|
/// class TorqueObject : public ConsoleObject {
|
|
/// // Must provide a Parent typedef so the console system knows what we inherit from.
|
|
/// typedef ConsoleObject Parent;
|
|
///
|
|
/// // This does a lot of menial declaration for you.
|
|
/// DECLARE_CONOBJECT(TorqueObject);
|
|
///
|
|
/// // This is for us to register our fields in.
|
|
/// static void initPersistFields();
|
|
///
|
|
/// // A sample field.
|
|
/// S8 mSample;
|
|
/// }
|
|
/// @endcode
|
|
///
|
|
/// @code
|
|
/// // And the accordant implementation...
|
|
/// IMPLEMENT_CONOBJECT(TorqueObject);
|
|
///
|
|
/// void TorqueObject::initPersistFields()
|
|
/// {
|
|
/// // If you want to inherit any fields from the parent (you do), do this:
|
|
/// Parent::initPersistFields();
|
|
///
|
|
/// // Pass the field, the type, the offset, and a usage string.
|
|
/// addField("sample", TypeS8, Offset(mSample, TorqueObject), "A test field.");
|
|
/// }
|
|
/// @endcode
|
|
///
|
|
/// That's all you need to do to get a class registered with the console system. At this point,
|
|
/// you can instantiate it via script, tie methods to it using ConsoleMethod, register fields,
|
|
/// and so forth. You can also register any global variables related to the class by creating
|
|
/// a consoleInit() method.
|
|
///
|
|
/// You will need to use different IMPLEMENT_ macros in different cases; for instance, if you
|
|
/// are making a NetObject (for ghosting), a DataBlock, or a NetEvent.
|
|
///
|
|
/// @see AbstractClassRep for gory implementation details.
|
|
/// @nosubgrouping
|
|
class ConsoleObject : public EngineObject
|
|
{
|
|
DECLARE_ABSTRACT_CLASS( ConsoleObject, EngineObject );
|
|
|
|
protected:
|
|
|
|
/// @deprecated This is disallowed.
|
|
ConsoleObject(const ConsoleObject&);
|
|
|
|
public:
|
|
/// <summary>
|
|
/// Only used for interfacing with the editor's inspector docsURL button
|
|
/// </summary>
|
|
bool mDocsClick;
|
|
ConsoleObject() { mDocsClick = false; }
|
|
|
|
/// Get a reference to a field by name.
|
|
const AbstractClassRep::Field *findField(StringTableEntry fieldName) const;
|
|
|
|
/// Gets the ClassRep.
|
|
virtual AbstractClassRep* getClassRep() const;
|
|
|
|
#define DECLARE_ABSTRACT_CONOBJECT( className ) \
|
|
DECLARE_ABSTRACT_CLASS( className, Parent ); \
|
|
static S32 _smTypeId; \
|
|
static ConcreteAbstractClassRep< className > dynClassRep; \
|
|
static AbstractClassRep* getParentStaticClassRep(); \
|
|
static AbstractClassRep* getStaticClassRep(); \
|
|
static SimObjectRefConsoleBaseType< className > ptrRefType; \
|
|
virtual AbstractClassRep* getClassRep() const
|
|
|
|
/// Set the value of a field.
|
|
bool setField(const char *fieldName, const char *value);
|
|
|
|
public:
|
|
|
|
/// @name Object Creation
|
|
/// @{
|
|
static ConsoleObject* create(const char* in_pClassName);
|
|
static ConsoleObject* create(const U32 groupId, const U32 typeId, const U32 in_classId);
|
|
/// @}
|
|
|
|
public:
|
|
|
|
/// Get the classname from a class tag.
|
|
static const char* lookupClassName(const U32 in_classTag);
|
|
|
|
/// @name Fields
|
|
/// @{
|
|
|
|
/// Mark the beginning of a group of fields.
|
|
///
|
|
/// This is used in the consoleDoc system.
|
|
/// @see console_autodoc
|
|
static void addGroup(const char* in_pGroupname, const char* in_pGroupDocs = NULL);
|
|
|
|
/// Mark the end of a group of fields.
|
|
///
|
|
/// This is used in the consoleDoc system.
|
|
/// @see console_autodoc
|
|
static void endGroup(const char* in_pGroupname);
|
|
|
|
/// Marks the start of a fixed size array of fields.
|
|
/// @see console_autodoc
|
|
static void addArray( const char *arrayName, S32 count );
|
|
|
|
/// Marks the end of an array of fields.
|
|
/// @see console_autodoc
|
|
static void endArray( const char *arrayName );
|
|
|
|
/// Register a complex field.
|
|
///
|
|
/// @param in_pFieldname Name of the field.
|
|
/// @param in_fieldType Type of the field. @see ConsoleDynamicTypes
|
|
/// @param in_fieldOffset Offset to the field from the start of the class; calculated using the Offset() macro.
|
|
/// @param in_elementCount Number of elements in this field. Arrays of elements are assumed to be contiguous in memory.
|
|
/// @param in_pFieldDocs Usage string for this field. @see console_autodoc
|
|
static void addField(const char* in_pFieldname,
|
|
const U32 in_fieldType,
|
|
const dsize_t in_fieldOffset,
|
|
const U32 in_elementCount = 1,
|
|
const char* in_pFieldDocs = NULL,
|
|
U32 flags = 0 );
|
|
|
|
static void addField(const char* in_pFieldname,
|
|
const U32 in_fieldType,
|
|
const dsize_t in_fieldOffset,
|
|
AbstractClassRep::WriteDataNotify in_writeDataFn,
|
|
const U32 in_elementCount = 1,
|
|
const char* in_pFieldDocs = NULL,
|
|
U32 flags = 0);
|
|
|
|
/// Register a simple field.
|
|
///
|
|
/// @param in_pFieldname Name of the field.
|
|
/// @param in_fieldType Type of the field. @see ConsoleDynamicTypes
|
|
/// @param in_fieldOffset Offset to the field from the start of the class; calculated using the Offset() macro.
|
|
/// @param in_pFieldDocs Usage string for this field. @see console_autodoc
|
|
static void addField(const char* in_pFieldname,
|
|
const U32 in_fieldType,
|
|
const dsize_t in_fieldOffset,
|
|
const char* in_pFieldDocs,
|
|
U32 flags = 0 );
|
|
|
|
static void addField(const char* in_pFieldname,
|
|
const U32 in_fieldType,
|
|
const dsize_t in_fieldOffset,
|
|
AbstractClassRep::WriteDataNotify in_writeDataFn,
|
|
const char* in_pFieldDocs,
|
|
U32 flags = 0);
|
|
|
|
/// Register a validated field.
|
|
///
|
|
/// A validated field is just like a normal field except that you can't
|
|
/// have it be an array, and that you give it a pointer to a TypeValidator
|
|
/// subclass, which is then used to validate any value placed in it. Invalid
|
|
/// values are ignored and an error is printed to the console.
|
|
///
|
|
/// @see addField
|
|
/// @see typeValidators.h
|
|
static void addFieldV(const char* in_pFieldname,
|
|
const U32 in_fieldType,
|
|
const dsize_t in_fieldOffset,
|
|
TypeValidator *v,
|
|
const char * in_pFieldDocs = NULL);
|
|
|
|
/// Register a complex protected field.
|
|
///
|
|
/// @param in_pFieldname Name of the field.
|
|
/// @param in_fieldType Type of the field. @see ConsoleDynamicTypes
|
|
/// @param in_fieldOffset Offset to the field from the start of the class; calculated using the Offset() macro.
|
|
/// @param in_setDataFn When this field gets set, it will call the callback provided. @see console_protected
|
|
/// @param in_getDataFn When this field is accessed for it's data, it will return the value of this function
|
|
/// @param in_elementCount Number of elements in this field. Arrays of elements are assumed to be contiguous in memory.
|
|
/// @param in_pFieldDocs Usage string for this field. @see console_autodoc
|
|
static void addProtectedField(const char* in_pFieldname,
|
|
const U32 in_fieldType,
|
|
const dsize_t in_fieldOffset,
|
|
AbstractClassRep::SetDataNotify in_setDataFn,
|
|
AbstractClassRep::GetDataNotify in_getDataFn = &defaultProtectedGetFn,
|
|
AbstractClassRep::WriteDataNotify in_writeDataFn = &defaultProtectedWriteFn,
|
|
const U32 in_elementCount = 1,
|
|
const char* in_pFieldDocs = NULL,
|
|
U32 flags = 0);
|
|
|
|
static void addProtectedField(const char* in_pFieldname,
|
|
const U32 in_fieldType,
|
|
const dsize_t in_fieldOffset,
|
|
AbstractClassRep::SetDataNotify in_setDataFn,
|
|
AbstractClassRep::GetDataNotify in_getDataFn = &defaultProtectedGetFn,
|
|
const U32 in_elementCount = 1,
|
|
const char* in_pFieldDocs = NULL,
|
|
U32 flags = 0);
|
|
|
|
/// Register a simple protected field.
|
|
///
|
|
/// @param in_pFieldname Name of the field.
|
|
/// @param in_fieldType Type of the field. @see ConsoleDynamicTypes
|
|
/// @param in_fieldOffset Offset to the field from the start of the class; calculated using the Offset() macro.
|
|
/// @param in_setDataFn When this field gets set, it will call the callback provided. @see console_protected
|
|
/// @param in_getDataFn When this field is accessed for it's data, it will return the value of this function
|
|
/// @param in_pFieldDocs Usage string for this field. @see console_autodoc
|
|
static void addProtectedField(const char* in_pFieldname,
|
|
const U32 in_fieldType,
|
|
const dsize_t in_fieldOffset,
|
|
AbstractClassRep::SetDataNotify in_setDataFn,
|
|
AbstractClassRep::GetDataNotify in_getDataFn = &defaultProtectedGetFn,
|
|
AbstractClassRep::WriteDataNotify in_writeDataFn = &defaultProtectedWriteFn,
|
|
const char* in_pFieldDocs = NULL,
|
|
U32 flags = 0);
|
|
|
|
static void addProtectedField(const char* in_pFieldname,
|
|
const U32 in_fieldType,
|
|
const dsize_t in_fieldOffset,
|
|
AbstractClassRep::SetDataNotify in_setDataFn,
|
|
AbstractClassRep::GetDataNotify in_getDataFn = &defaultProtectedGetFn,
|
|
const char* in_pFieldDocs = NULL,
|
|
U32 flags = 0);
|
|
|
|
/// Add a deprecated field.
|
|
///
|
|
/// A deprecated field will always be undefined, even if you assign a value to it. This
|
|
/// is useful when you need to make sure that a field is not being used anymore.
|
|
static void addDeprecatedField(const char *fieldName);
|
|
|
|
/// Remove a field.
|
|
///
|
|
/// Sometimes, you just have to remove a field!
|
|
/// @returns True on success.
|
|
static bool removeField(const char* in_pFieldname);
|
|
|
|
/// @}
|
|
|
|
/// @name Logging
|
|
/// @{
|
|
|
|
/// Overload this in subclasses to change the message formatting.
|
|
/// @param fmt A printf style format string.
|
|
/// @param args A va_list containing the args passed ot a log function.
|
|
/// @note It is suggested that you use String::VToString.
|
|
virtual String _getLogMessage(const char* fmt, va_list args) const;
|
|
|
|
/// @}
|
|
|
|
public:
|
|
|
|
/// @name Logging
|
|
/// These functions will try to print out a message along the lines
|
|
/// of "ObjectClass - ObjectName(ObjectId) - formatted message"
|
|
/// @{
|
|
|
|
/// Logs with Con::printf.
|
|
void logMessage(const char* fmt, ...) const;
|
|
|
|
/// Logs with Con::warnf.
|
|
void logWarning(const char* fmt, ...) const;
|
|
|
|
/// Logs with Con::errorf.
|
|
void logError(const char* fmt, ...) const;
|
|
|
|
/// @}
|
|
|
|
/// Register dynamic fields in a subclass of ConsoleObject.
|
|
///
|
|
/// @see addField(), addFieldV(), addDeprecatedField(), addGroup(), endGroup()
|
|
static void initPersistFields();
|
|
|
|
/// Register global constant variables and do other one-time initialization tasks in
|
|
/// a subclass of ConsoleObject.
|
|
///
|
|
/// @deprecated You should use ConsoleMethod and ConsoleFunction, not this, to
|
|
/// register methods or commands.
|
|
/// @see console
|
|
static void consoleInit();
|
|
|
|
/// @name Field List
|
|
/// @{
|
|
|
|
/// Get a list of all the fields. This information cannot be modified.
|
|
const AbstractClassRep::FieldList& getFieldList() const;
|
|
|
|
/// Get a list of all the fields, set up so we can modify them.
|
|
///
|
|
/// @note This is a bad trick to pull if you aren't very careful,
|
|
/// since you can blast field data!
|
|
AbstractClassRep::FieldList& getModifiableFieldList();
|
|
|
|
/// Get a handle to a boolean telling us if we expanded the dynamic group.
|
|
///
|
|
/// @see GuiInspector::Inspect()
|
|
bool& getDynamicGroupExpand();
|
|
/// @}
|
|
|
|
/// @name ConsoleObject Implementation
|
|
///
|
|
/// These functions are implemented in every subclass of
|
|
/// ConsoleObject by an IMPLEMENT_CONOBJECT or IMPLEMENT_CO_* macro.
|
|
/// @{
|
|
|
|
/// Get the abstract class information for this class.
|
|
static AbstractClassRep *getStaticClassRep() { return NULL; }
|
|
|
|
/// Get the abstract class information for this class's superclass.
|
|
static AbstractClassRep *getParentStaticClassRep() { return NULL; }
|
|
|
|
/// Get our network-layer class id.
|
|
///
|
|
/// @param netClassGroup The net class for which we want our ID.
|
|
/// @see
|
|
S32 getClassId(U32 netClassGroup) const;
|
|
|
|
/// Get our compiler and platform independent class name.
|
|
///
|
|
/// @note This name can be used to instantiate another instance using create()
|
|
StringTableEntry getClassName() const;
|
|
|
|
/// @}
|
|
|
|
static const char* __category() { return ""; }
|
|
static const char* __description() { return ""; }
|
|
|
|
/// Subclasses of ConsoleObjects that are datablocks should redefine this static member variable
|
|
/// and set it to true.
|
|
static const bool __smIsDatablock = false;
|
|
|
|
/// @name Object IDs and lookup.
|
|
/// For a subclass hierarchy based on ConsoleObject to become functional for use as a console object type,
|
|
/// the hierarchy must implement a naming scheme and indexing function for looking up objects by name.
|
|
/// @{
|
|
|
|
static ConsoleObject* __findObject( const char* ) { return NULL; }
|
|
static const char* __getObjectId( ConsoleObject* ) { return ""; }
|
|
protected:
|
|
static bool disableFieldSubstitutions(const char* in_pFieldname);
|
|
static bool onlyKeepClearSubstitutions(const char* in_pFieldname);
|
|
};
|
|
|
|
#define addNamedField(fieldName,type,className) addField(#fieldName, type, Offset(fieldName,className))
|
|
#define addNamedFieldV(fieldName,type,className, validator) addFieldV(#fieldName, type, Offset(fieldName,className), validator)
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
//-------------------------------------- Inlines
|
|
//
|
|
inline S32 ConsoleObject::getClassId(U32 netClassGroup) const
|
|
{
|
|
AssertFatal(getClassRep() != NULL,"Cannot get tag from non-declared dynamic class!");
|
|
return getClassRep()->getClassId(netClassGroup);
|
|
}
|
|
|
|
inline StringTableEntry ConsoleObject::getClassName() const
|
|
{
|
|
AssertFatal(getClassRep() != NULL,
|
|
"Cannot get tag from non-declared dynamic class");
|
|
return getClassRep()->getClassName();
|
|
}
|
|
|
|
inline const AbstractClassRep::Field * ConsoleObject::findField(StringTableEntry name) const
|
|
{
|
|
AssertFatal(getClassRep() != NULL,
|
|
avar("Cannot get field '%s' from non-declared dynamic class.", name));
|
|
return getClassRep()->findField(name);
|
|
}
|
|
|
|
inline bool ConsoleObject::setField(const char *fieldName, const char *value)
|
|
{
|
|
//sanity check
|
|
if ((! fieldName) || (! fieldName[0]) || (! value))
|
|
return false;
|
|
|
|
if (! getClassRep())
|
|
return false;
|
|
|
|
const AbstractClassRep::Field *myField = getClassRep()->findField(StringTable->insert(fieldName));
|
|
|
|
if (! myField)
|
|
return false;
|
|
|
|
Con::setData(
|
|
myField->type,
|
|
(void *) (((const char *)(this)) + myField->offset),
|
|
0,
|
|
1,
|
|
&value,
|
|
myField->table,
|
|
myField->flag);
|
|
|
|
return true;
|
|
}
|
|
|
|
inline ConsoleObject* ConsoleObject::create(const char* in_pClassName)
|
|
{
|
|
return AbstractClassRep::create(in_pClassName);
|
|
}
|
|
|
|
inline ConsoleObject* ConsoleObject::create(const U32 groupId, const U32 typeId, const U32 in_classId)
|
|
{
|
|
return AbstractClassRep::create(groupId, typeId, in_classId);
|
|
}
|
|
|
|
inline const AbstractClassRep::FieldList& ConsoleObject::getFieldList() const
|
|
{
|
|
return getClassRep()->mFieldList;
|
|
}
|
|
|
|
inline AbstractClassRep::FieldList& ConsoleObject::getModifiableFieldList()
|
|
{
|
|
return getClassRep()->mFieldList;
|
|
}
|
|
|
|
inline bool& ConsoleObject::getDynamicGroupExpand()
|
|
{
|
|
return getClassRep()->mDynamicGroupExpand;
|
|
}
|
|
|
|
/// @name ConsoleObject Macros
|
|
/// @{
|
|
|
|
#define DECLARE_CONOBJECT( className ) \
|
|
DECLARE_CLASS( className, Parent ); \
|
|
static S32 _smTypeId; \
|
|
static ConcreteClassRep< className > dynClassRep; \
|
|
static AbstractClassRep* getParentStaticClassRep(); \
|
|
static AbstractClassRep* getStaticClassRep(); \
|
|
static SimObjectRefConsoleBaseType< className > ptrRefType; \
|
|
static AbstractClassRep::WriteCustomTamlSchema getStaticWriteCustomTamlSchema(); \
|
|
static AbstractClassRep* getContainerChildStaticClassRep(); \
|
|
virtual AbstractClassRep* getClassRep() const
|
|
|
|
#define DECLARE_CATEGORY( string ) \
|
|
static const char* __category() { return string; }
|
|
|
|
#define DECLARE_DESCRIPTION( string ) \
|
|
static const char* __description() { return string; }
|
|
|
|
#define IMPLEMENT_CONOBJECT( className ) \
|
|
IMPLEMENT_CLASS( className, NULL ) \
|
|
END_IMPLEMENT_CLASS; \
|
|
S32 className::_smTypeId; \
|
|
SimObjectRefConsoleBaseType< className > className::ptrRefType( "Type" #className "Ref" ); \
|
|
AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; } \
|
|
AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; } \
|
|
AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); } \
|
|
AbstractClassRep* className::getContainerChildStaticClassRep() { return NULL; } \
|
|
AbstractClassRep::WriteCustomTamlSchema className::getStaticWriteCustomTamlSchema() { return NULL; } \
|
|
ConcreteClassRep<className> className::dynClassRep( #className, "Type" #className, &_smTypeId, 0, -1, 0, className::getParentStaticClassRep(), &Parent::__description )
|
|
|
|
#define IMPLEMENT_CONOBJECT_CHILDREN( className ) \
|
|
IMPLEMENT_CLASS( className, NULL ) \
|
|
END_IMPLEMENT_CLASS; \
|
|
S32 className::_smTypeId; \
|
|
SimObjectRefConsoleBaseType< className > className::ptrRefType( "Type" #className "Ref" ); \
|
|
AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; } \
|
|
AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; } \
|
|
AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); } \
|
|
AbstractClassRep* className::getContainerChildStaticClassRep() { return Children::getStaticClassRep(); } \
|
|
AbstractClassRep::WriteCustomTamlSchema className::getStaticWriteCustomTamlSchema() { return NULL; } \
|
|
ConcreteClassRep<className> className::dynClassRep( #className, "Type" #className, &_smTypeId, 0, -1, 0, className::getParentStaticClassRep(), &Parent::__description )
|
|
|
|
#define IMPLEMENT_CONOBJECT_SCHEMA( className, schema ) \
|
|
IMPLEMENT_CLASS( className, NULL ) \
|
|
END_IMPLEMENT_CLASS; \
|
|
S32 className::_smTypeId; \
|
|
SimObjectRefConsoleBaseType< className > className::ptrRefType( "Type" #className "Ref" ); \
|
|
AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; } \
|
|
AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; } \
|
|
AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); } \
|
|
AbstractClassRep* className::getContainerChildStaticClassRep() { return NULL; } \
|
|
AbstractClassRep::WriteCustomTamlSchema className::getStaticWriteCustomTamlSchema() { return schema; } \
|
|
ConcreteClassRep<className> className::dynClassRep( #className, "Type" #className, &_smTypeId, 0, -1, 0, className::getParentStaticClassRep(), &Parent::__description )
|
|
|
|
#define IMPLEMENT_CONOBJECT_CHILDREN_SCHEMA( className, schema ) \
|
|
IMPLEMENT_CLASS( className, NULL ) \
|
|
END_IMPLEMENT_CLASS; \
|
|
S32 className::_smTypeId; \
|
|
SimObjectRefConsoleBaseType< className > className::ptrRefType( "Type" #className "Ref" ); \
|
|
AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; } \
|
|
AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; } \
|
|
AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); } \
|
|
AbstractClassRep* className::getContainerChildStaticClassRep() { return Children::getStaticClassRep(); } \
|
|
AbstractClassRep::WriteCustomTamlSchema className::getStaticWriteCustomTamlSchema() { return schema; } \
|
|
ConcreteClassRep<className> className::dynClassRep( #className, "Type" #className, &_smTypeId, 0, -1, 0, className::getParentStaticClassRep(), &Parent::__description )
|
|
|
|
#define IMPLEMENT_ABSTRACT_CONOBJECT( className ) \
|
|
IMPLEMENT_NONINSTANTIABLE_CLASS( className, NULL ) \
|
|
END_IMPLEMENT_CLASS; \
|
|
S32 className::_smTypeId; \
|
|
SimObjectRefConsoleBaseType< className > className::ptrRefType( "Type" #className "Ref" ); \
|
|
AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; } \
|
|
AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; } \
|
|
AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); } \
|
|
ConcreteAbstractClassRep<className> className::dynClassRep( #className, "Type" #className, &_smTypeId, 0, -1, 0, className::getParentStaticClassRep(), &Parent::__description )
|
|
|
|
#define IMPLEMENT_CO_NETOBJECT_V1( className ) \
|
|
IMPLEMENT_CLASS( className, NULL ) \
|
|
END_IMPLEMENT_CLASS; \
|
|
S32 className::_smTypeId; \
|
|
SimObjectRefConsoleBaseType< className > className::ptrRefType( "Type" #className "Ref" ); \
|
|
AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; } \
|
|
AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; } \
|
|
AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); } \
|
|
AbstractClassRep* className::getContainerChildStaticClassRep() { return NULL; } \
|
|
AbstractClassRep::WriteCustomTamlSchema className::getStaticWriteCustomTamlSchema() { return NULL; } \
|
|
ConcreteClassRep<className> className::dynClassRep( #className, "Type" #className, &_smTypeId, NetClassGroupGameMask, NetClassTypeObject, 0, className::getParentStaticClassRep(), &Parent::__description )
|
|
|
|
#define IMPLEMENT_CO_DATABLOCK_V1( className ) \
|
|
IMPLEMENT_CLASS( className, NULL ) \
|
|
END_IMPLEMENT_CLASS; \
|
|
S32 className::_smTypeId; \
|
|
SimObjectRefConsoleBaseType< className > className::ptrRefType( "Type" #className "Ref" ); \
|
|
AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; } \
|
|
AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; } \
|
|
AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); } \
|
|
AbstractClassRep* className::getContainerChildStaticClassRep() { return NULL; } \
|
|
AbstractClassRep::WriteCustomTamlSchema className::getStaticWriteCustomTamlSchema() { return NULL; } \
|
|
ConcreteClassRep<className> className::dynClassRep(#className, "Type" #className, &_smTypeId, NetClassGroupGameMask, NetClassTypeDataBlock, 0, className::getParentStaticClassRep(), &Parent::__description )
|
|
|
|
// Support for adding properties to classes CONOBJECT style.
|
|
#define PROPERTY_TABLE( className ) \
|
|
namespace { namespace _ ## className { \
|
|
extern EnginePropertyTable _propTable; \
|
|
} } \
|
|
template<> EnginePropertyTable& \
|
|
ConcreteClassRep< className >::smPropertyTable = _ ## className::_propTable; \
|
|
namespace { namespace _ ## className { \
|
|
EnginePropertyTable::Property _props[] = {
|
|
|
|
#define END_PROPERTY_TABLE \
|
|
{ NULL } \
|
|
}; \
|
|
EnginePropertyTable _propTable( sizeof( _props ) / sizeof( _props[ 0 ] ) - 1, _props ); \
|
|
} }
|
|
|
|
/// @}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Protected field default get/set functions
|
|
//
|
|
// The reason for these functions is that it will save one branch per console
|
|
// data request and script functions will still execute at the same speed as
|
|
// before the modifications to allow protected static fields. These will just
|
|
// inline and the code should be roughly the same size, and just as fast as
|
|
// before the modifications. -pw
|
|
inline bool defaultProtectedSetFn( void *object, const char *index, const char *data )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
inline bool defaultProtectedSetNotEmptyFn( void *object, const char *index, const char *data )
|
|
{
|
|
return data && data[0];
|
|
}
|
|
|
|
inline const char *defaultProtectedGetFn( void *obj, const char *data )
|
|
{
|
|
return data;
|
|
}
|
|
|
|
inline const char *emptyStringProtectedGetFn( void *obj, const char *data )
|
|
{
|
|
return "";
|
|
}
|
|
|
|
inline bool defaultProtectedWriteFn(void* obj, StringTableEntry pFieldName)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
inline bool defaultProtectedNotSetFn(void* obj, const char *array, const char* data)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
inline bool defaultProtectedNotWriteFn(void* obj, StringTableEntry pFieldName)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
/// @}
|
|
|
|
#endif //_CONSOLEOBJECT_H_
|