//----------------------------------------------------------------------------- // Torque Game Engine // Copyright (C) GarageGames.com, Inc. //----------------------------------------------------------------------------- #include "platform/platform.h" #include "console/consoleObject.h" #include "core/stringTable.h" #include "core/crc.h" #include "console/console.h" #include "console/consoleInternal.h" #include "console/typeValidators.h" AbstractClassRep * AbstractClassRep::classLinkList = NULL; static AbstractClassRep::FieldList sg_tempFieldList; U32 AbstractClassRep::NetClassCount [NetClassGroupsCount][NetClassTypesCount] = {{0, },}; U32 AbstractClassRep::NetClassBitSize[NetClassGroupsCount][NetClassTypesCount] = {{0, },}; AbstractClassRep ** AbstractClassRep::classTable[NetClassGroupsCount][NetClassTypesCount]; U32 AbstractClassRep::classCRC[NetClassGroupsCount] = {INITIAL_CRC_VALUE, }; bool AbstractClassRep::initialized = false; //-------------------------------------- const AbstractClassRep::Field *AbstractClassRep::findField(StringTableEntry name) const { for(U32 i = 0; i < mFieldList.size(); i++) if(mFieldList[i].pFieldname == name) return &mFieldList[i]; return NULL; } //-------------------------------------- void AbstractClassRep::registerClassRep(AbstractClassRep* in_pRep) { AssertFatal(in_pRep != NULL, "AbstractClassRep::registerClassRep was passed a NULL pointer!"); #ifdef TORQUE_DEBUG // assert if this class is already registered. for(AbstractClassRep *walk = classLinkList; walk; walk = walk->nextClass) { AssertFatal(dStrcmp(in_pRep->mClassName, walk->mClassName), "Duplicate class name registered in AbstractClassRep::registerClassRep()"); } #endif in_pRep->nextClass = classLinkList; classLinkList = in_pRep; } //-------------------------------------- ConsoleObject* AbstractClassRep::create(const char* in_pClassName) { AssertFatal(initialized, "AbstractClassRep::create() - Tried to create an object before AbstractClassRep::initialize()."); for (AbstractClassRep *walk = classLinkList; walk; walk = walk->nextClass) if (!dStrcmp(walk->getClassName(), in_pClassName)) return walk->create(); AssertWarn(0, avar("Couldn't find class rep for dynamic class: %s", in_pClassName)); return NULL; } //-------------------------------------- ConsoleObject* AbstractClassRep::create(const U32 groupId, const U32 typeId, const U32 in_classId) { AssertFatal(initialized, "AbstractClassRep::create() - Tried to create an object before AbstractClassRep::initialize()."); AssertFatal(in_classId < NetClassCount[groupId][typeId], "AbstractClassRep::create() - Class id out of range."); AssertFatal(classTable[groupId][typeId][in_classId] != NULL, "AbstractClassRep::create() - No class with requested ID type."); // Look up the specified class and create it. if(classTable[groupId][typeId][in_classId]) return classTable[groupId][typeId][in_classId]->create(); return NULL; } //-------------------------------------- static S32 QSORT_CALLBACK ACRCompare(const void *aptr, const void *bptr) { const AbstractClassRep *a = *((const AbstractClassRep **) aptr); const AbstractClassRep *b = *((const AbstractClassRep **) bptr); if(a->mClassType != b->mClassType) return a->mClassType - b->mClassType; return dStrcmp(a->getClassName(), b->getClassName()); } void AbstractClassRep::initialize() { AssertFatal(!initialized, "Duplicate call to AbstractClassRep::initialize()!"); Vector dynamicTable(__FILE__, __LINE__); AbstractClassRep *walk; // Initialize namespace references... for (walk = classLinkList; walk; walk = walk->nextClass) { walk->mNamespace = Con::lookupNamespace(StringTable->insert(walk->getClassName())); walk->mNamespace->mClassRep = walk; } // Initialize field lists... (and perform other console registration). for (walk = classLinkList; walk; walk = walk->nextClass) { // sg_tempFieldList is used as a staging area for field lists // (see addField, addGroup, etc.) sg_tempFieldList.setSize(0); walk->init(); // So if we have things in it, copy it over... if (sg_tempFieldList.size() != 0) walk->mFieldList = sg_tempFieldList; // And of course delete it every round. sg_tempFieldList.clear(); } // Calculate counts and bit sizes for the various NetClasses. for (U32 group = 0; group < NetClassGroupsCount; group++) { U32 groupMask = 1 << group; // Specifically, for each NetClass of each NetGroup... for(U32 type = 0; type < NetClassTypesCount; type++) { // Go through all the classes and find matches... for (walk = classLinkList; walk; walk = walk->nextClass) { if(walk->mClassType == type && walk->mClassGroupMask & groupMask) dynamicTable.push_back(walk); } // Set the count for this NetGroup and NetClass NetClassCount[group][type] = dynamicTable.size(); if(!NetClassCount[group][type]) continue; // If no classes matched, skip to next. // Sort by type and then by name. dQsort((void *) &dynamicTable[0], dynamicTable.size(), sizeof(AbstractClassRep *), ACRCompare); // Allocate storage in the classTable classTable[group][type] = new AbstractClassRep*[NetClassCount[group][type]]; // Fill this in and assign class ids for this group. for(U32 i = 0; i < NetClassCount[group][type];i++) { classTable[group][type][i] = dynamicTable[i]; dynamicTable[i]->mClassId[group] = i; } // And calculate the size of bitfields for this group and type. NetClassBitSize[group][type] = getBinLog2(getNextPow2(NetClassCount[group][type] + 1)); dynamicTable.clear(); } } // Ok, we're golden! initialized = true; } //------------------------------------------------------------------------------ //-------------------------------------- ConsoleObject char replacebuf[1024]; char* suppressSpaces(const char* in_pname) { U32 i = 0; char chr; do { chr = in_pname[i]; replacebuf[i++] = (chr != 32) ? chr : '_'; } while(chr); return replacebuf; } void ConsoleObject::addGroup(const char* in_pGroupname, const char* in_pGroupDocs) { // Remove spaces. char* pFieldNameBuf = suppressSpaces(in_pGroupname); // Append group type to fieldname. dStrcat(pFieldNameBuf, "_begingroup"); // Create Field. AbstractClassRep::Field f; f.pFieldname = StringTable->insert(pFieldNameBuf); f.pGroupname = StringTable->insert(in_pGroupname); if(in_pGroupDocs) f.pFieldDocs = StringTable->insert(in_pGroupDocs); else f.pFieldDocs = NULL; f.type = AbstractClassRep::StartGroupFieldType; f.elementCount = 0; f.groupExpand = false; f.validator = NULL; f.setDataFn = &defaultProtectedSetFn; f.getDataFn = &defaultProtectedGetFn; // Add to field list. sg_tempFieldList.push_back(f); } void ConsoleObject::endGroup(const char* in_pGroupname) { // Remove spaces. char* pFieldNameBuf = suppressSpaces(in_pGroupname); // Append group type to fieldname. dStrcat(pFieldNameBuf, "_endgroup"); // Create Field. AbstractClassRep::Field f; f.pFieldname = StringTable->insert(pFieldNameBuf); f.pGroupname = StringTable->insert(in_pGroupname); f.pFieldDocs = NULL; f.type = AbstractClassRep::EndGroupFieldType; f.groupExpand = false; f.validator = NULL; f.setDataFn = &defaultProtectedSetFn; f.getDataFn = &defaultProtectedGetFn; f.elementCount = 0; // Add to field list. sg_tempFieldList.push_back(f); } void ConsoleObject::addField(const char* in_pFieldname, const U32 in_fieldType, const dsize_t in_fieldOffset, const char* in_pFieldDocs) { addField( in_pFieldname, in_fieldType, in_fieldOffset, 1, NULL, in_pFieldDocs); } void ConsoleObject::addProtectedField(const char* in_pFieldname, const U32 in_fieldType, const dsize_t in_fieldOffset, AbstractClassRep::SetDataNotify in_setDataFn, AbstractClassRep::GetDataNotify in_getDataFn, const char* in_pFieldDocs) { addProtectedField( in_pFieldname, in_fieldType, in_fieldOffset, in_setDataFn, in_getDataFn, 1, NULL, in_pFieldDocs); } void ConsoleObject::addField(const char* in_pFieldname, const U32 in_fieldType, const dsize_t in_fieldOffset, const U32 in_elementCount, EnumTable *in_table, const char* in_pFieldDocs) { AbstractClassRep::Field f; f.pFieldname = StringTable->insert(in_pFieldname); f.pGroupname = NULL; if(in_pFieldDocs) f.pFieldDocs = StringTable->insert(in_pFieldDocs); else f.pFieldDocs = NULL; f.type = in_fieldType; f.offset = in_fieldOffset; f.elementCount = in_elementCount; f.table = in_table; f.validator = NULL; f.setDataFn = &defaultProtectedSetFn; f.getDataFn = &defaultProtectedGetFn; sg_tempFieldList.push_back(f); } void ConsoleObject::addProtectedField(const char* in_pFieldname, const U32 in_fieldType, const dsize_t in_fieldOffset, AbstractClassRep::SetDataNotify in_setDataFn, AbstractClassRep::GetDataNotify in_getDataFn, const U32 in_elementCount, EnumTable *in_table, const char* in_pFieldDocs) { AbstractClassRep::Field f; f.pFieldname = StringTable->insert(in_pFieldname); f.pGroupname = NULL; if(in_pFieldDocs) f.pFieldDocs = StringTable->insert(in_pFieldDocs); else f.pFieldDocs = NULL; f.type = in_fieldType; f.offset = in_fieldOffset; f.elementCount = in_elementCount; f.table = in_table; f.validator = NULL; f.setDataFn = in_setDataFn; f.getDataFn = in_getDataFn; sg_tempFieldList.push_back(f); } void ConsoleObject::addFieldV(const char* in_pFieldname, const U32 in_fieldType, const dsize_t in_fieldOffset, TypeValidator *v, const char* in_pFieldDocs) { AbstractClassRep::Field f; f.pFieldname = StringTable->insert(in_pFieldname); f.pGroupname = NULL; if(in_pFieldDocs) f.pFieldDocs = StringTable->insert(in_pFieldDocs); else f.pFieldDocs = NULL; f.type = in_fieldType; f.offset = in_fieldOffset; f.elementCount = 1; f.table = NULL; f.setDataFn = &defaultProtectedSetFn; f.getDataFn = &defaultProtectedGetFn; f.validator = v; v->fieldIndex = sg_tempFieldList.size(); sg_tempFieldList.push_back(f); } void ConsoleObject::addDepricatedField(const char *fieldName) { AbstractClassRep::Field f; f.pFieldname = StringTable->insert(fieldName); f.pGroupname = NULL; f.pFieldDocs = NULL; f.type = AbstractClassRep::DepricatedFieldType; f.offset = 0; f.elementCount = 0; f.table = NULL; f.validator = NULL; f.setDataFn = &defaultProtectedSetFn; f.getDataFn = &defaultProtectedGetFn; sg_tempFieldList.push_back(f); } bool ConsoleObject::removeField(const char* in_pFieldname) { for (U32 i = 0; i < sg_tempFieldList.size(); i++) { if (dStricmp(in_pFieldname, sg_tempFieldList[i].pFieldname) == 0) { sg_tempFieldList.erase(i); return true; } } return false; } //-------------------------------------- void ConsoleObject::initPersistFields() { } //-------------------------------------- void ConsoleObject::consoleInit() { } ConsoleObject::~ConsoleObject() { } //-------------------------------------- AbstractClassRep* ConsoleObject::getClassRep() const { return NULL; }