mirror of
https://github.com/tribes2/engine.git
synced 2026-01-20 03:34:48 +00:00
1528 lines
41 KiB
C++
1528 lines
41 KiB
C++
//-----------------------------------------------------------------------------
|
|
// V12 Engine
|
|
//
|
|
// Copyright (c) 2001 GarageGames.Com
|
|
// Portions Copyright (c) 2001 by Sierra Online, Inc.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include "platform/platform.h"
|
|
#include "console/simBase.h"
|
|
#include "core/stringTable.h"
|
|
#include "console/console.h"
|
|
#include "core/fileStream.h"
|
|
#include "sim/actionMap.h"
|
|
#include "core/resManager.h"
|
|
#include "core/fileObject.h"
|
|
#include "game/objectTypes.h"
|
|
#include "console/consoleInternal.h"
|
|
|
|
|
|
namespace Sim
|
|
{
|
|
// Don't forget to InstantiateNamed* in simManager.cc - DMM
|
|
ImplementNamedSet(ActiveActionMapSet)
|
|
ImplementNamedSet(GhostAlwaysSet)
|
|
ImplementNamedSet(LightSet)
|
|
ImplementNamedSet(WayPointSet)
|
|
ImplementNamedSet(ClientTargetSet)
|
|
ImplementNamedSet(ServerTargetSet)
|
|
ImplementNamedSet(FlareSet)
|
|
ImplementNamedSet(MissileSet)
|
|
ImplementNamedSet(CommandTargetSet)
|
|
ImplementNamedSet(ScopeSensorVisibleSet)
|
|
ImplementNamedGroup(ActionMapGroup)
|
|
ImplementNamedGroup(ClientGroup)
|
|
ImplementNamedGroup(GuiGroup)
|
|
ImplementNamedGroup(GuiDataGroup)
|
|
ImplementNamedGroup(TCPGroup)
|
|
|
|
//groups created on the client
|
|
ImplementNamedGroup(ClientConnectionGroup)
|
|
}
|
|
|
|
// for isServer() only...
|
|
|
|
//---------------------------------------------------------------------------
|
|
//---------------------------------------------------------------------------
|
|
|
|
void SimObjectList::pushBack(SimObject* obj)
|
|
{
|
|
if (find(begin(),end(),obj) == end())
|
|
push_back(obj);
|
|
}
|
|
|
|
void SimObjectList::pushBackForce(SimObject* obj)
|
|
{
|
|
iterator itr = find(begin(),end(),obj);
|
|
if (itr == end()) {
|
|
push_back(obj);
|
|
} else {
|
|
// Move to the back...
|
|
//
|
|
SimObject* pBack = *itr;
|
|
removeStable(pBack);
|
|
push_back(pBack);
|
|
}
|
|
}
|
|
|
|
void SimObjectList::pushFront(SimObject* obj)
|
|
{
|
|
if (find(begin(),end(),obj) == end())
|
|
push_front(obj);
|
|
}
|
|
|
|
void SimObjectList::remove(SimObject* obj)
|
|
{
|
|
iterator ptr = find(begin(),end(),obj);
|
|
if (ptr != end()) {
|
|
iterator last = end() - 1;
|
|
*ptr = *last;
|
|
erase(last);
|
|
}
|
|
}
|
|
|
|
S32 QSORT_CALLBACK SimObjectList::compareId(const void* a,const void* b)
|
|
{
|
|
return (*reinterpret_cast<const SimObject* const*>(a))->getId() -
|
|
(*reinterpret_cast<const SimObject* const*>(b))->getId();
|
|
}
|
|
|
|
void SimObjectList::sortId()
|
|
{
|
|
dQsort(address(),size(),sizeof(value_type),compareId);
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
//---------------------------------------------------------------------------
|
|
|
|
SimFieldDictionary::Entry *SimFieldDictionary::mFreeList = NULL;
|
|
|
|
static Chunker<SimFieldDictionary::Entry> fieldChunker;
|
|
|
|
SimFieldDictionary::Entry *SimFieldDictionary::allocEntry()
|
|
{
|
|
if(mFreeList)
|
|
{
|
|
Entry *ret = mFreeList;
|
|
mFreeList = ret->next;
|
|
return ret;
|
|
}
|
|
else
|
|
return fieldChunker.alloc();
|
|
}
|
|
|
|
void SimFieldDictionary::freeEntry(SimFieldDictionary::Entry *ent)
|
|
{
|
|
ent->next = mFreeList;
|
|
mFreeList = ent;
|
|
}
|
|
|
|
SimFieldDictionary::SimFieldDictionary()
|
|
{
|
|
for(U32 i = 0; i < HashTableSize; i++)
|
|
mHashTable[i] = 0;
|
|
}
|
|
|
|
SimFieldDictionary::~SimFieldDictionary()
|
|
{
|
|
for(U32 i = 0; i < HashTableSize; i++)
|
|
{
|
|
for(Entry *walk = mHashTable[i]; walk;)
|
|
{
|
|
Entry *temp = walk;
|
|
walk = temp->next;
|
|
|
|
dFree(temp->value);
|
|
freeEntry(temp);
|
|
}
|
|
}
|
|
}
|
|
|
|
void SimFieldDictionary::setFieldValue(StringTableEntry slotName, const char *value)
|
|
{
|
|
U32 bucket = HashPointer(slotName) % HashTableSize;
|
|
Entry **walk = &mHashTable[bucket];
|
|
while(*walk && (*walk)->slotName != slotName)
|
|
walk = &((*walk)->next);
|
|
|
|
Entry *field = *walk;
|
|
if(!*value)
|
|
{
|
|
if(field)
|
|
{
|
|
dFree(field->value);
|
|
*walk = field->next;
|
|
freeEntry(field);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(field)
|
|
{
|
|
dFree(field->value);
|
|
field->value = dStrdup(value);
|
|
}
|
|
else
|
|
{
|
|
field = allocEntry();
|
|
field->value = dStrdup(value);
|
|
field->slotName = slotName;
|
|
field->next = NULL;
|
|
*walk = field;
|
|
}
|
|
}
|
|
}
|
|
|
|
const char *SimFieldDictionary::getFieldValue(StringTableEntry slotName)
|
|
{
|
|
U32 bucket = HashPointer(slotName) % HashTableSize;
|
|
|
|
for(Entry *walk = mHashTable[bucket];walk;walk = walk->next)
|
|
if(walk->slotName == slotName)
|
|
return walk->value;
|
|
return NULL;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
SimObject::SimObject()
|
|
{
|
|
objectName = NULL;
|
|
nextNameObject = (SimObject*)-1;
|
|
nextManagerNameObject = (SimObject*)-1;
|
|
nextIdObject = NULL;
|
|
|
|
mId = 0;
|
|
mGroup = 0;
|
|
mNameSpace = NULL;
|
|
mNotifyList = NULL;
|
|
mFlags.set(ModDynamicFields);
|
|
mTypeMask = 0;
|
|
|
|
mFieldDictionary = NULL;
|
|
}
|
|
|
|
static void writeTabs(Stream &stream, U32 count)
|
|
{
|
|
while(count--)
|
|
stream.write(U8('\t'));
|
|
}
|
|
|
|
void SimFieldDictionary::assignFrom(SimFieldDictionary *dict)
|
|
{
|
|
for(U32 i = 0; i < HashTableSize; i++)
|
|
for(Entry *walk = dict->mHashTable[i];walk; walk = walk->next)
|
|
setFieldValue(walk->slotName, walk->value);
|
|
}
|
|
|
|
void SimFieldDictionary::writeFields(SimObject *obj, Stream &stream, U32 tabStop)
|
|
{
|
|
const AbstractClassRep::FieldList &list = obj->getFieldList();
|
|
char expandedBuffer[1024];
|
|
for(U32 i = 0; i < HashTableSize; i++)
|
|
{
|
|
for(Entry *walk = mHashTable[i];walk; walk = walk->next)
|
|
{
|
|
// make sure we haven't written this out yet:
|
|
U32 i;
|
|
for(i = 0; i < list.size(); i++)
|
|
if(list[i].pFieldname == walk->slotName)
|
|
break;
|
|
if(i != list.size())
|
|
continue;
|
|
writeTabs(stream, tabStop+1);
|
|
dSprintf(expandedBuffer, sizeof(expandedBuffer), "%s = \"", walk->slotName);
|
|
expandEscape(expandedBuffer + dStrlen(expandedBuffer), walk->value);
|
|
dStrcat(expandedBuffer, "\";\r\n");
|
|
stream.write(dStrlen(expandedBuffer),expandedBuffer);
|
|
}
|
|
}
|
|
}
|
|
|
|
static S32 QSORT_CALLBACK compareEntries(const void* a,const void* b)
|
|
{
|
|
SimFieldDictionary::Entry *fa = *((SimFieldDictionary::Entry **)a);
|
|
SimFieldDictionary::Entry *fb = *((SimFieldDictionary::Entry **)b);
|
|
return dStricmp(fa->slotName, fb->slotName);
|
|
}
|
|
|
|
void SimFieldDictionary::printFields(SimObject *obj)
|
|
{
|
|
const AbstractClassRep::FieldList &list = obj->getFieldList();
|
|
char expandedBuffer[1024];
|
|
Vector<Entry *> flist(__FILE__, __LINE__);
|
|
|
|
for(U32 i = 0; i < HashTableSize; i++)
|
|
{
|
|
for(Entry *walk = mHashTable[i];walk; walk = walk->next)
|
|
{
|
|
// make sure we haven't written this out yet:
|
|
U32 i;
|
|
for(i = 0; i < list.size(); i++)
|
|
if(list[i].pFieldname == walk->slotName)
|
|
break;
|
|
if(i != list.size())
|
|
continue;
|
|
flist.push_back(walk);
|
|
}
|
|
}
|
|
dQsort(flist.address(),flist.size(),sizeof(Entry *),compareEntries);
|
|
|
|
for(Vector<Entry *>::iterator itr = flist.begin(); itr != flist.end(); itr++)
|
|
{
|
|
dSprintf(expandedBuffer, sizeof(expandedBuffer), " %s = \"", (*itr)->slotName);
|
|
expandEscape(expandedBuffer + dStrlen(expandedBuffer), (*itr)->value);
|
|
Con::printf("%s\"", expandedBuffer);
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
SimFieldDictionaryIterator::SimFieldDictionaryIterator(SimFieldDictionary * dictionary)
|
|
{
|
|
mDictionary = dictionary;
|
|
mHashIndex = -1;
|
|
mEntry = 0;
|
|
operator++();
|
|
}
|
|
|
|
SimFieldDictionary::Entry* SimFieldDictionaryIterator::operator++()
|
|
{
|
|
if(!mDictionary)
|
|
return(mEntry);
|
|
|
|
if(mEntry)
|
|
mEntry = mEntry->next;
|
|
|
|
while(!mEntry && (mHashIndex < (SimFieldDictionary::HashTableSize-1)))
|
|
mEntry = mDictionary->mHashTable[++mHashIndex];
|
|
|
|
return(mEntry);
|
|
}
|
|
|
|
SimFieldDictionary::Entry* SimFieldDictionaryIterator::operator*()
|
|
{
|
|
return(mEntry);
|
|
}
|
|
|
|
void SimObject::assignFieldsFrom(SimObject *parent)
|
|
{
|
|
// only allow field assigns from objects of the same class:
|
|
if(getClassRep() == parent->getClassRep())
|
|
{
|
|
const AbstractClassRep::FieldList &list = getFieldList();
|
|
|
|
// copy out all the fields:
|
|
for(U32 i = 0; i < list.size(); i++)
|
|
{
|
|
const AbstractClassRep::Field* f = &list[i];
|
|
if(f->elementCount == 1)
|
|
{
|
|
const char *fieldVal = Con::getData(f->type, (void *) (U32(parent) + f->offset), 0, f->table, f->flag);
|
|
if(fieldVal)
|
|
Con::setData(f->type, (void *) (U32(this) + f->offset), 0, 1, &fieldVal, f->table);
|
|
}
|
|
else
|
|
{
|
|
for(U32 j = 0; j < f->elementCount; j++)
|
|
{
|
|
const char *fieldVal = Con::getData(f->type, (void *) (U32(parent) + f->offset), j, f->table, f->flag);
|
|
if(fieldVal)
|
|
Con::setData(f->type, (void *) (U32(this) + f->offset), j, 1, &fieldVal, f->table);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if(parent->mFieldDictionary)
|
|
{
|
|
mFieldDictionary = new SimFieldDictionary;
|
|
mFieldDictionary->assignFrom(parent->mFieldDictionary);
|
|
}
|
|
}
|
|
|
|
void SimObject::writeFields(Stream &stream, U32 tabStop)
|
|
{
|
|
const AbstractClassRep::FieldList &list = getFieldList();
|
|
char expandedBuffer[1024];
|
|
|
|
for(U32 i = 0; i < list.size(); i++)
|
|
{
|
|
const AbstractClassRep::Field* f = &list[i];
|
|
for(U32 j = 0; S32(j) < f->elementCount; j++)
|
|
{
|
|
if(f->type == AbstractClassRep::DepricatedFieldType)
|
|
continue;
|
|
const char *val = Con::getData(f->type, (void *) (U32(this) + f->offset), j, f->table, f->flag);
|
|
if(!val || !*val)
|
|
continue;
|
|
if(f->elementCount == 1)
|
|
dSprintf(expandedBuffer, sizeof(expandedBuffer), "%s = \"", f->pFieldname);
|
|
else
|
|
dSprintf(expandedBuffer, sizeof(expandedBuffer), "%s[%d] = \"", f->pFieldname, j);
|
|
|
|
expandEscape(expandedBuffer + dStrlen(expandedBuffer), val);
|
|
dStrcat(expandedBuffer, "\";\r\n");
|
|
|
|
writeTabs(stream, tabStop);
|
|
stream.write(dStrlen(expandedBuffer),expandedBuffer);
|
|
}
|
|
}
|
|
if(mFieldDictionary)
|
|
mFieldDictionary->writeFields(this, stream, tabStop);
|
|
}
|
|
|
|
void SimObject::write(Stream &stream, U32 tabStop, U32 flags)
|
|
{
|
|
//
|
|
if((flags & SelectedOnly) && !isSelected())
|
|
return;
|
|
|
|
writeTabs(stream, tabStop);
|
|
char buffer[1024];
|
|
dSprintf(buffer, sizeof(buffer), "new %s(%s) {\r\n", getClassName(), getName() ? getName() : "");
|
|
stream.write(dStrlen(buffer), buffer);
|
|
writeFields(stream, tabStop + 1);
|
|
writeTabs(stream, tabStop);
|
|
stream.write(4, "};\r\n");
|
|
}
|
|
|
|
ConsoleFunction(nameToID, S32, 2, 2, "nameToID(object)")
|
|
{
|
|
argc;
|
|
SimObject *obj = Sim::findObject(argv[1]);
|
|
if(obj)
|
|
return obj->getId();
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
ConsoleFunction(isObject, bool, 2, 2, "isObject(object)")
|
|
{
|
|
argc;
|
|
if (!dStrcmp(argv[1], "0") || !dStrcmp(argv[1], ""))
|
|
return false;
|
|
else
|
|
return (Sim::findObject(argv[1]) != NULL);
|
|
}
|
|
|
|
|
|
ConsoleMethod(SimObject, save, bool, 3, 4, "obj.save(fileName, <selectedOnly>)")
|
|
{
|
|
static const char *beginMessage = "//--- OBJECT WRITE BEGIN ---";
|
|
static const char *endMessage = "//--- OBJECT WRITE END ---";
|
|
FileStream stream;
|
|
FileObject f;
|
|
f.readMemory(argv[2]);
|
|
|
|
// check for flags <selected, ...>
|
|
U32 writeFlags = 0;
|
|
if(argc > 3)
|
|
{
|
|
if(dAtob(argv[3]))
|
|
writeFlags |= SimObject::SelectedOnly;
|
|
}
|
|
|
|
if(!ResourceManager->openFileForWrite(stream, ResourceManager->getModPathOf(argv[2]), argv[2]))
|
|
return false;
|
|
|
|
const char *buffer;
|
|
while(!f.isEOF())
|
|
{
|
|
buffer = (const char *) f.readLine();
|
|
if(!dStrcmp(buffer, beginMessage))
|
|
break;
|
|
stream.write(dStrlen(buffer), buffer);
|
|
stream.write(2, "\r\n");
|
|
}
|
|
stream.write(dStrlen(beginMessage), beginMessage);
|
|
stream.write(2, "\r\n");
|
|
object->write(stream, 0, writeFlags);
|
|
stream.write(dStrlen(endMessage), endMessage);
|
|
stream.write(2, "\r\n");
|
|
while(!f.isEOF())
|
|
{
|
|
buffer = (const char *) f.readLine();
|
|
if(!dStrcmp(buffer, endMessage))
|
|
break;
|
|
}
|
|
while(!f.isEOF())
|
|
{
|
|
buffer = (const char *) f.readLine();
|
|
stream.write(dStrlen(buffer), buffer);
|
|
stream.write(2, "\r\n");
|
|
}
|
|
return true;
|
|
}
|
|
|
|
ConsoleMethod(SimObject, setName, void, 3, 3, "obj.setName(newName)")
|
|
{
|
|
argc;
|
|
object->assignName(argv[2]);
|
|
}
|
|
|
|
ConsoleMethod(SimObject, getName, const char *, 2, 2, "obj.getName()")
|
|
{
|
|
argc; argv;
|
|
const char *ret = object->getName();
|
|
return ret ? ret : "";
|
|
}
|
|
|
|
ConsoleMethod(SimObject, getClassName, const char *, 2, 2, "obj.getClassName()")
|
|
{
|
|
argc; argv;
|
|
const char *ret = object->getClassName();
|
|
return ret ? ret : "";
|
|
}
|
|
|
|
ConsoleMethod(SimObject, getId, S32, 2, 2, "obj.getId()")
|
|
{
|
|
argc; argv;
|
|
return object->getId();
|
|
}
|
|
|
|
ConsoleMethod(SimObject, getGroup, S32, 2, 2, "obj.getGroup()")
|
|
{
|
|
argc; argv;
|
|
SimGroup *grp = object->getGroup();
|
|
if(!grp)
|
|
return -1;
|
|
return grp->getId();
|
|
}
|
|
|
|
ConsoleMethod(SimObject,delete,void,2,2,"obj.delete()")
|
|
{
|
|
argc;argv;
|
|
object->deleteObject();
|
|
}
|
|
|
|
ConsoleFunction(cancel,void,2,2,"cancel(eventId)")
|
|
{
|
|
argc;
|
|
Sim::cancelEvent(dAtoi(argv[1]));
|
|
}
|
|
|
|
ConsoleFunction(isEventPending, bool, 2, 2, "isEventPending(%scheduleId);")
|
|
{
|
|
argc;
|
|
return Sim::isEventPending(dAtoi(argv[1]));
|
|
}
|
|
|
|
ConsoleFunction(schedule, S32, 4, 0, "object.schedule(time, command, <arg1...argN>)")
|
|
{
|
|
U32 timeDelta = U32(dAtof(argv[1]));
|
|
SimObject *refObject = Sim::findObject(argv[2]);
|
|
if(!refObject)
|
|
{
|
|
if(argv[2][0] != '0')
|
|
return 0;
|
|
|
|
refObject = Sim::getRootGroup();
|
|
}
|
|
SimConsoleEvent *evt = new SimConsoleEvent(argc - 3, argv + 3, false);
|
|
|
|
S32 ret = Sim::postEvent(refObject, evt, Sim::getCurrentTime() + timeDelta);
|
|
// #ifdef DEBUG
|
|
// Con::printf("ref %s schedule(%s) = %d", argv[2], argv[3], ret);
|
|
// Con::executef(1, "backtrace");
|
|
// #endif
|
|
return ret;
|
|
}
|
|
|
|
ConsoleMethod(SimObject,schedule, S32, 4, 0, "object.schedule(time, command, <arg1...argN>);")
|
|
{
|
|
U32 timeDelta = U32(dAtof(argv[2]));
|
|
argv[2] = argv[3];
|
|
argv[3] = argv[1];
|
|
SimConsoleEvent *evt = new SimConsoleEvent(argc - 2, argv + 2, true);
|
|
S32 ret = Sim::postEvent(object, evt, Sim::getCurrentTime() + timeDelta);
|
|
// #ifdef DEBUG
|
|
// Con::printf("obj %s schedule(%s) = %d", argv[3], argv[2], ret);
|
|
// Con::executef(1, "backtrace");
|
|
// #endif
|
|
return ret;
|
|
}
|
|
|
|
static S32 QSORT_CALLBACK compareFields(const void* a,const void* b)
|
|
{
|
|
const AbstractClassRep::Field* fa = *((const AbstractClassRep::Field**)a);
|
|
const AbstractClassRep::Field* fb = *((const AbstractClassRep::Field**)b);
|
|
|
|
return dStricmp(fa->pFieldname, fb->pFieldname);
|
|
}
|
|
|
|
ConsoleMethod(SimObject,dump, void, 2, 2, "obj.dump()")
|
|
{
|
|
argc; argv;
|
|
const AbstractClassRep::FieldList &list = object->getFieldList();
|
|
char expandedBuffer[1024];
|
|
|
|
Con::printf("Member Fields:");
|
|
Vector<const AbstractClassRep::Field *> flist(__FILE__, __LINE__);
|
|
|
|
for(U32 i = 0; i < list.size(); i++)
|
|
flist.push_back(&list[i]);
|
|
|
|
dQsort(flist.address(),flist.size(),sizeof(AbstractClassRep::Field *),compareFields);
|
|
|
|
for(Vector<const AbstractClassRep::Field *>::iterator itr = flist.begin(); itr != flist.end(); itr++)
|
|
{
|
|
const AbstractClassRep::Field* f = *itr;
|
|
for(U32 j = 0; S32(j) < f->elementCount; j++)
|
|
{
|
|
if(f->type == AbstractClassRep::DepricatedFieldType)
|
|
continue;
|
|
const char *val = Con::getData(f->type, (void *) (U32(object) + f->offset), j, f->table, f->flag);
|
|
if(!val || !*val)
|
|
continue;
|
|
if(f->elementCount == 1)
|
|
dSprintf(expandedBuffer, sizeof(expandedBuffer), " %s = \"", f->pFieldname);
|
|
else
|
|
dSprintf(expandedBuffer, sizeof(expandedBuffer), " %s[%d] = \"", f->pFieldname, j);
|
|
expandEscape(expandedBuffer + dStrlen(expandedBuffer), val);
|
|
Con::printf("%s\"", expandedBuffer);
|
|
}
|
|
}
|
|
Con::printf("Tagged Fields:");
|
|
if(object->getFieldDictionary())
|
|
object->getFieldDictionary()->printFields(object);
|
|
Con::printf("Methods:");
|
|
Namespace *ns = object->getNamespace();
|
|
Vector<Namespace::Entry *> vec(__FILE__, __LINE__);
|
|
if(ns)
|
|
ns->getEntryList(&vec);
|
|
for(Vector<Namespace::Entry *>::iterator j = vec.begin(); j != vec.end(); j++)
|
|
Con::printf(" %s() - %s", (*j)->mFunctionName, (*j)->mUsage ? (*j)->mUsage : "");
|
|
|
|
}
|
|
|
|
ConsoleMethod(SimObject, getType, S32, 2, 2, "obj.getType()")
|
|
{
|
|
argc; argv;
|
|
return((S32)object->getType());
|
|
}
|
|
|
|
void SimObject::consoleInit()
|
|
{
|
|
Con::setIntVariable("$TypeMasks::StaticObjectType", StaticObjectType);
|
|
Con::setIntVariable("$TypeMasks::EnvironmentObjectType", EnvironmentObjectType);
|
|
Con::setIntVariable("$TypeMasks::TerrainObjectType", TerrainObjectType);
|
|
Con::setIntVariable("$TypeMasks::InteriorObjectType", InteriorObjectType);
|
|
Con::setIntVariable("$TypeMasks::WaterObjectType", WaterObjectType);
|
|
Con::setIntVariable("$TypeMasks::TriggerObjectType", TriggerObjectType);
|
|
Con::setIntVariable("$TypeMasks::MarkerObjectType", MarkerObjectType);
|
|
Con::setIntVariable("$TypeMasks::ForceFieldObjectType", ForceFieldObjectType);
|
|
Con::setIntVariable("$TypeMasks::GameBaseObjectType", GameBaseObjectType);
|
|
Con::setIntVariable("$TypeMasks::ShapeBaseObjectType", ShapeBaseObjectType);
|
|
Con::setIntVariable("$TypeMasks::CameraObjectType", CameraObjectType);
|
|
Con::setIntVariable("$TypeMasks::StaticShapeObjectType", StaticShapeObjectType);
|
|
Con::setIntVariable("$TypeMasks::PlayerObjectType", PlayerObjectType);
|
|
Con::setIntVariable("$TypeMasks::ItemObjectType", ItemObjectType);
|
|
Con::setIntVariable("$TypeMasks::VehicleObjectType", VehicleObjectType);
|
|
Con::setIntVariable("$TypeMasks::VehicleBlockerObjectType", VehicleBlockerObjectType);
|
|
Con::setIntVariable("$TypeMasks::ProjectileObjectType", ProjectileObjectType);
|
|
Con::setIntVariable("$TypeMasks::ExplosionObjectType", ExplosionObjectType);
|
|
Con::setIntVariable("$TypeMasks::CorpseObjectType", CorpseObjectType);
|
|
Con::setIntVariable("$TypeMasks::TurretObjectType", TurretObjectType);
|
|
Con::setIntVariable("$TypeMasks::DebrisObjectType", DebrisObjectType);
|
|
Con::setIntVariable("$TypeMasks::PhysicalZoneObjectType", PhysicalZoneObjectType);
|
|
Con::setIntVariable("$TypeMasks::StaticTSObjectType", StaticTSObjectType);
|
|
Con::setIntVariable("$TypeMasks::GuiControlObjectType", GuiControlObjectType);
|
|
Con::setIntVariable("$TypeMasks::StaticRenderedObjectType", StaticRenderedObjectType);
|
|
|
|
Con::setIntVariable("$TypeMasks::DamagableItemObjectType", DamagableItemObjectType);
|
|
Con::setIntVariable("$TypeMasks::SensorObjectType", SensorObjectType);
|
|
Con::setIntVariable("$TypeMasks::StationObjectType", StationObjectType);
|
|
Con::setIntVariable("$TypeMasks::GeneratorObjectType", GeneratorObjectType);
|
|
}
|
|
|
|
const char *SimObject::tabComplete(const char *prevText, S32 baseLen, bool fForward)
|
|
{
|
|
return mNameSpace->tabComplete(prevText, baseLen, fForward);
|
|
}
|
|
|
|
void SimObject::setDataField(StringTableEntry slotName, const char *array, const char *value)
|
|
{
|
|
// first search the static fields if enabled
|
|
if(mFlags.test(ModStaticFields))
|
|
{
|
|
const AbstractClassRep::Field *fld = findField(slotName);
|
|
if(fld)
|
|
{
|
|
if(fld->type == AbstractClassRep::DepricatedFieldType)
|
|
return;
|
|
S32 array1 = array ? dAtoi(array) : 0;
|
|
if(array1 >= 0 && array1 < fld->elementCount && fld->elementCount >= 1)
|
|
Con::setData(fld->type, (void *) (U32(this) + fld->offset), array1, 1, &value, fld->table);
|
|
/*else if(array1 == -1 && fld->elementCount == argc)
|
|
{
|
|
S32 i;
|
|
for(i = 0; i < argc;i++)
|
|
Con::setData(fld->type, (void *) (U32(this) + fld->offset), i, 1, argv + i, fld->table);
|
|
}*/
|
|
onStaticModified(slotName);
|
|
return;
|
|
}
|
|
}
|
|
if(mFlags.test(ModDynamicFields))
|
|
{
|
|
if(!mFieldDictionary)
|
|
mFieldDictionary = new SimFieldDictionary;
|
|
|
|
if(!array)
|
|
mFieldDictionary->setFieldValue(slotName, value);
|
|
else
|
|
{
|
|
char buf[256];
|
|
dStrcpy(buf, slotName);
|
|
dStrcat(buf, array);
|
|
mFieldDictionary->setFieldValue(StringTable->insert(buf), value);
|
|
}
|
|
}
|
|
}
|
|
|
|
const char *SimObject::getDataField(StringTableEntry slotName, const char *array)
|
|
{
|
|
if(mFlags.test(ModStaticFields))
|
|
{
|
|
S32 array1 = array ? dAtoi(array) : -1;
|
|
const AbstractClassRep::Field *fld = findField(slotName);
|
|
if(fld)
|
|
{
|
|
if(array1 == -1 && fld->elementCount == 1)
|
|
return Con::getData(fld->type, (void *) (U32(this) + fld->offset), 0, fld->table, fld->flag);
|
|
if(array1 >= 0 && array1 < fld->elementCount)
|
|
return Con::getData(fld->type, (void *) (U32(this) + fld->offset), array1, fld->table, fld->flag);// + typeSizes[fld.type] * array1));
|
|
return "";
|
|
}
|
|
}
|
|
if(mFlags.test(ModDynamicFields))
|
|
{
|
|
if(!mFieldDictionary)
|
|
return "";
|
|
|
|
if(!array) {
|
|
if (const char* val = mFieldDictionary->getFieldValue(slotName))
|
|
return val;
|
|
}
|
|
else
|
|
{
|
|
static char buf[256];
|
|
dStrcpy(buf, slotName);
|
|
dStrcat(buf, array);
|
|
if (const char* val = mFieldDictionary->getFieldValue(StringTable->insert(buf)))
|
|
return val;
|
|
}
|
|
}
|
|
return "";
|
|
}
|
|
|
|
SimObject::~SimObject()
|
|
{
|
|
delete mFieldDictionary;
|
|
|
|
AssertFatal(nextNameObject == (SimObject*)-1,avar(
|
|
"SimObject::~SimObject: Not removed from dictionary: name %s, id %i",
|
|
objectName, mId));
|
|
AssertFatal(nextManagerNameObject == (SimObject*)-1,avar(
|
|
"SimObject::~SimObject: Not removed from manager dictionary: name %s, id %i",
|
|
objectName,mId));
|
|
AssertFatal(mFlags.test(Added) == 0, "SimObject::object "
|
|
"missing call to SimObject::onRemove");
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool SimObject::isLocked()
|
|
{
|
|
if(!mFieldDictionary)
|
|
return false;
|
|
|
|
const char * val = mFieldDictionary->getFieldValue( StringTable->insert( "locked", false ) );
|
|
|
|
return( val ? dAtob(val) : false );
|
|
}
|
|
|
|
void SimObject::setLocked( bool b = true )
|
|
{
|
|
setDataField(StringTable->insert("locked", false), NULL, b ? "true" : "false" );
|
|
}
|
|
|
|
bool SimObject::isHidden()
|
|
{
|
|
if(!mFieldDictionary)
|
|
return false;
|
|
|
|
const char * val = mFieldDictionary->getFieldValue( StringTable->insert( "hidden", false ) );
|
|
return( val ? dAtob(val) : false );
|
|
}
|
|
|
|
void SimObject::setHidden(bool b = true)
|
|
{
|
|
setDataField(StringTable->insert("hidden", false), NULL, b ? "true" : "false" );
|
|
}
|
|
|
|
const char* SimObject::getIdString()
|
|
{
|
|
static char IDbuffer[12];
|
|
dSprintf(IDbuffer, sizeof(IDbuffer), "%d", mId);
|
|
return IDbuffer;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool SimObject::onAdd()
|
|
{
|
|
mFlags.set(Added);
|
|
|
|
if(getClassRep())
|
|
mNameSpace = getClassRep()->getNameSpace();
|
|
|
|
// onAdd() should return FALSE if there was an error
|
|
return true;
|
|
}
|
|
|
|
void SimObject::onRemove()
|
|
{
|
|
mFlags.clear(Added);
|
|
}
|
|
|
|
void SimObject::onGroupAdd()
|
|
{
|
|
}
|
|
|
|
void SimObject::onGroupRemove()
|
|
{
|
|
}
|
|
|
|
void SimObject::onDeleteNotify(SimObject*)
|
|
{
|
|
}
|
|
|
|
void SimObject::onNameChange(const char*)
|
|
{
|
|
}
|
|
|
|
void SimObject::onStaticModified(const char*)
|
|
{
|
|
}
|
|
|
|
bool SimObject::processArguments(S32 argc, const char**)
|
|
{
|
|
return argc == 0;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
static Chunker<SimObject::Notify> notifyChunker(128000);
|
|
SimObject::Notify *SimObject::mNotifyFreeList = NULL;
|
|
|
|
SimObject::Notify *SimObject::allocNotify()
|
|
{
|
|
if(mNotifyFreeList)
|
|
{
|
|
SimObject::Notify *ret = mNotifyFreeList;
|
|
mNotifyFreeList = ret->next;
|
|
return ret;
|
|
}
|
|
return notifyChunker.alloc();
|
|
}
|
|
|
|
void SimObject::freeNotify(SimObject::Notify* note)
|
|
{
|
|
AssertFatal(note->type != SimObject::Notify::Invalid, "Invalid notify");
|
|
note->type = SimObject::Notify::Invalid;
|
|
note->next = mNotifyFreeList;
|
|
mNotifyFreeList = note;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
SimObject::Notify* SimObject::removeNotify(void *ptr, SimObject::Notify::Type type)
|
|
{
|
|
Notify **list = &mNotifyList;
|
|
while(*list)
|
|
{
|
|
if((*list)->ptr == ptr && (*list)->type == type)
|
|
{
|
|
SimObject::Notify *ret = *list;
|
|
*list = ret->next;
|
|
return ret;
|
|
}
|
|
list = &((*list)->next);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void SimObject::deleteNotify(SimObject* obj)
|
|
{
|
|
AssertFatal(!obj->isDeleted(),
|
|
"SimManager::deleteNotify: Object is being deleted");
|
|
Notify *note = allocNotify();
|
|
note->ptr = (void *) this;
|
|
note->next = obj->mNotifyList;
|
|
note->type = Notify::DeleteNotify;
|
|
obj->mNotifyList = note;
|
|
|
|
note = allocNotify();
|
|
note->ptr = (void *) obj;
|
|
note->next = mNotifyList;
|
|
note->type = Notify::ClearNotify;
|
|
mNotifyList = note;
|
|
|
|
//obj->deleteNotifyList.pushBack(this);
|
|
//clearNotifyList.pushBack(obj);
|
|
}
|
|
|
|
void SimObject::registerReference(SimObject **ptr)
|
|
{
|
|
Notify *note = allocNotify();
|
|
note->ptr = (void *) ptr;
|
|
note->next = mNotifyList;
|
|
note->type = Notify::ObjectRef;
|
|
mNotifyList = note;
|
|
}
|
|
|
|
void SimObject::unregisterReference(SimObject **ptr)
|
|
{
|
|
Notify *note = removeNotify((void *) ptr, Notify::ObjectRef);
|
|
freeNotify(note);
|
|
}
|
|
|
|
void SimObject::clearNotify(SimObject* obj)
|
|
{
|
|
Notify *note = obj->removeNotify((void *) this, Notify::DeleteNotify);
|
|
if(note)
|
|
freeNotify(note);
|
|
|
|
note = removeNotify((void *) obj, Notify::ClearNotify);
|
|
if(note)
|
|
freeNotify(note);
|
|
}
|
|
|
|
void SimObject::processDeleteNotifies()
|
|
{
|
|
// clear out any delete notifies and
|
|
// object refs.
|
|
|
|
while(mNotifyList)
|
|
{
|
|
Notify *note = mNotifyList;
|
|
mNotifyList = note->next;
|
|
|
|
AssertFatal(note->type != Notify::ClearNotify, "Clear notes should be all gone.");
|
|
|
|
if(note->type == Notify::DeleteNotify)
|
|
{
|
|
SimObject *obj = (SimObject *) note->ptr;
|
|
Notify *cnote = obj->removeNotify((void *)this, Notify::ClearNotify);
|
|
obj->onDeleteNotify(this);
|
|
freeNotify(cnote);
|
|
}
|
|
else
|
|
{
|
|
// it must be an object ref - a pointer refs this object
|
|
*((SimObject **) note->ptr) = NULL;
|
|
}
|
|
freeNotify(note);
|
|
}
|
|
}
|
|
|
|
void SimObject::clearAllNotifications()
|
|
{
|
|
for(Notify **cnote = &mNotifyList; *cnote; )
|
|
{
|
|
Notify *temp = *cnote;
|
|
if(temp->type == Notify::ClearNotify)
|
|
{
|
|
*cnote = temp->next;
|
|
Notify *note = ((SimObject *) temp->ptr)->removeNotify((void *) this, Notify::DeleteNotify);
|
|
freeNotify(temp);
|
|
freeNotify(note);
|
|
}
|
|
else
|
|
cnote = &(temp->next);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool SimObject::addToSet(SimObjectId spid)
|
|
{
|
|
if (mFlags.test(Added) == false)
|
|
return false;
|
|
|
|
SimObject* ptr = Sim::findObject(spid);
|
|
if (ptr) {
|
|
SimSet* sp = dynamic_cast<SimSet*>(ptr);
|
|
AssertFatal(sp != 0,
|
|
"SimObject::addToSet: "
|
|
"ObjectId does not refer to a set object");
|
|
sp->addObject(this);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool SimObject::addToSet(const char *ObjectName)
|
|
{
|
|
if (mFlags.test(Added) == false)
|
|
return false;
|
|
|
|
SimObject* ptr = Sim::findObject(ObjectName);
|
|
if (ptr) {
|
|
SimSet* sp = dynamic_cast<SimSet*>(ptr);
|
|
AssertFatal(sp != 0,
|
|
"SimObject::addToSet: "
|
|
"ObjectName does not refer to a set object");
|
|
sp->addObject(this);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool SimObject::removeFromSet(SimObjectId sid)
|
|
{
|
|
if (mFlags.test(Added) == false)
|
|
return false;
|
|
|
|
SimSet *set;
|
|
if(Sim::findObject(sid, set))
|
|
{
|
|
set->removeObject(this);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool SimObject::removeFromSet(const char *objectName)
|
|
{
|
|
if (mFlags.test(Added) == false)
|
|
return false;
|
|
|
|
SimSet *set;
|
|
if(Sim::findObject(objectName, set))
|
|
{
|
|
set->removeObject(this);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void SimObject::inspectPreApply()
|
|
{
|
|
}
|
|
|
|
void SimObject::inspectPostApply()
|
|
{
|
|
}
|
|
|
|
IMPLEMENT_CONOBJECT(SimObject);
|
|
|
|
//---------------------------------------------------------------------------
|
|
//---------------------------------------------------------------------------
|
|
|
|
IMPLEMENT_CO_DATABLOCK_V1(SimDataBlock);
|
|
SimObjectId SimDataBlock::sNextObjectId = DataBlockObjectIdFirst;
|
|
S32 SimDataBlock::sNextModifiedKey = 0;
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
SimDataBlock::SimDataBlock()
|
|
{
|
|
setModDynamicFields(true);
|
|
setModStaticFields(true);
|
|
}
|
|
|
|
bool SimDataBlock::onAdd()
|
|
{
|
|
Parent::onAdd();
|
|
// This initialization is done here, and not in the constructor,
|
|
// because some jokers like to construct and destruct objects
|
|
// (without adding them to the manager) to check what class
|
|
// they are.
|
|
modifiedKey = sNextModifiedKey++;
|
|
AssertFatal(sNextObjectId <= DataBlockObjectIdLast,
|
|
"Exceeded maxmimum number of data blocks");
|
|
|
|
// add DataBlock to the DataBlockGroup unless it is client side ONLY DataBlock
|
|
if (getId() >= DataBlockObjectIdFirst && getId() <= DataBlockObjectIdLast)
|
|
if (SimGroup* grp = Sim::getDataBlockGroup())
|
|
grp->addObject(this);
|
|
return true;
|
|
}
|
|
|
|
void SimDataBlock::assignId()
|
|
{
|
|
// We don't want the id assigned by the manager, but it may have
|
|
// already been assigned a correct data block id.
|
|
if (getId() < DataBlockObjectIdFirst || getId() > DataBlockObjectIdLast)
|
|
setId(sNextObjectId++);
|
|
}
|
|
|
|
void SimDataBlock::onStaticModified(const char*)
|
|
{
|
|
modifiedKey = sNextModifiedKey++;
|
|
|
|
}
|
|
|
|
void SimDataBlock::setLastError(const char*)
|
|
{
|
|
}
|
|
|
|
void SimDataBlock::packData(BitStream*)
|
|
{
|
|
}
|
|
|
|
void SimDataBlock::unpackData(BitStream*)
|
|
{
|
|
}
|
|
|
|
bool SimDataBlock::preload(bool, char[256])
|
|
{
|
|
return true;
|
|
}
|
|
|
|
ConsoleFunction(deleteDataBlocks, void, 1, 1, "deleteDataBlocks();")
|
|
{
|
|
argc; argv;
|
|
// delete from last to first:
|
|
SimGroup *grp = Sim::getDataBlockGroup();
|
|
for(S32 i = grp->size() - 1; i >= 0; i--)
|
|
{
|
|
SimObject *obj = (*grp)[i];
|
|
obj->deleteObject();
|
|
}
|
|
SimDataBlock::sNextObjectId = DataBlockObjectIdFirst;
|
|
SimDataBlock::sNextModifiedKey = 0;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//---------------------------------------------------------------------------
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
void SimSet::addObject(SimObject* obj)
|
|
{
|
|
objectList.pushBack(obj);
|
|
deleteNotify(obj);
|
|
}
|
|
|
|
void SimSet::removeObject(SimObject* obj)
|
|
{
|
|
objectList.remove(obj);
|
|
clearNotify(obj);
|
|
}
|
|
|
|
void SimSet::pushObject(SimObject* pObj)
|
|
{
|
|
objectList.pushBackForce(pObj);
|
|
deleteNotify(pObj);
|
|
}
|
|
|
|
void SimSet::popObject()
|
|
{
|
|
if (objectList.size() == 0) {
|
|
AssertWarn(false, "Stack underflow in SimSet::popObject");
|
|
return;
|
|
}
|
|
|
|
SimObject* pObject = objectList[objectList.size() - 1];
|
|
|
|
objectList.removeStable(pObject);
|
|
clearNotify(pObject);
|
|
}
|
|
|
|
bool SimSet::reOrder( SimObject *obj, SimObject *target )
|
|
{
|
|
iterator itrS, itrD;
|
|
if ( (itrS = find(begin(),end(),obj)) == end() )
|
|
return false; // object must be in list
|
|
if ( obj == target )
|
|
return true; // don't reorder same object but don't indicate error
|
|
if ( !target ) // if no target, then put to back of list
|
|
{
|
|
if ( itrS != (end()-1) ) // don't move if already last object
|
|
{
|
|
objectList.erase(itrS); // remove object from its current location
|
|
objectList.push_back(obj); // push it to the back of the list
|
|
}
|
|
}
|
|
else // if target, insert object in front of target
|
|
{
|
|
if ( (itrD = find(begin(),end(),target)) == end() )
|
|
return false; // target must be in list
|
|
objectList.erase(itrS);
|
|
|
|
//Tinman - once itrS has been erased, itrD won't be pointing at the same place anymore - re-find...
|
|
itrD = find(begin(),end(),target);
|
|
objectList.insert(itrD,obj);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void SimSet::onDeleteNotify(SimObject *object)
|
|
{
|
|
removeObject(object);
|
|
Parent::onDeleteNotify(object);
|
|
}
|
|
|
|
void SimSet::onRemove()
|
|
{
|
|
objectList.sortId();
|
|
if (objectList.size())
|
|
{
|
|
// This backwards iterator loop doesn't work if the
|
|
// list is empty, check the size first.
|
|
for (SimObjectList::iterator ptr = objectList.end() - 1;
|
|
ptr >= objectList.begin(); ptr--)
|
|
{
|
|
clearNotify(*ptr);
|
|
}
|
|
}
|
|
Parent::onRemove();
|
|
}
|
|
|
|
void SimSet::write(Stream &stream, U32 tabStop, U32 flags)
|
|
{
|
|
// export selected only?
|
|
if((flags & SelectedOnly) && !isSelected())
|
|
{
|
|
for(U32 i = 0; i < size(); i++)
|
|
(*this)[i]->write(stream, tabStop, flags);
|
|
return;
|
|
|
|
}
|
|
|
|
writeTabs(stream, tabStop);
|
|
char buffer[1024];
|
|
dSprintf(buffer, sizeof(buffer), "new %s(%s) {\r\n", getClassName(), getName() ? getName() : "");
|
|
stream.write(dStrlen(buffer), buffer);
|
|
writeFields(stream, tabStop + 1);
|
|
if(size())
|
|
{
|
|
stream.write(2, "\r\n");
|
|
for(U32 i = 0; i < size(); i++)
|
|
(*this)[i]->write(stream, tabStop + 1, flags);
|
|
}
|
|
writeTabs(stream, tabStop);
|
|
stream.write(4, "};\r\n");
|
|
}
|
|
|
|
ConsoleMethod(SimSet, listObjects, void, 2, 2, "set.listObjects();")
|
|
{
|
|
argc; argv;
|
|
SimSet *set = (SimSet *) object;
|
|
SimSet::iterator itr;
|
|
for(itr = set->begin(); itr != set->end(); itr++)
|
|
{
|
|
SimObject *object = *itr;
|
|
bool isSet = dynamic_cast<SimSet *>(object) != 0;
|
|
const char *name = object->getName();
|
|
if(name)
|
|
Con::printf(" %d,\"%s\": %s %s", object->getId(), name,
|
|
object->getClassName(), isSet ? "(g)":"");
|
|
else
|
|
Con::printf(" %d: %s %s", object->getId(), object->getClassName(),
|
|
isSet ? "(g)" : "");
|
|
}
|
|
}
|
|
|
|
ConsoleMethod(SimSet, add, void, 3, 0, "set.add(obj1,...)")
|
|
{
|
|
SimSet *set = (SimSet *) object;
|
|
for(S32 i = 2; i < argc; i++)
|
|
{
|
|
SimObject *obj = Sim::findObject(argv[i]);
|
|
if(obj)
|
|
set->addObject(obj);
|
|
else
|
|
Con::printf("Set::add: Object \"%s\" doesn't exist", argv[i]);
|
|
}
|
|
}
|
|
|
|
ConsoleMethod(SimSet, remove, void, 3, 0, "set.remove(obj1,...)")
|
|
{
|
|
SimSet *set = (SimSet *) object;
|
|
for(S32 i = 2; i < argc; i++)
|
|
{
|
|
SimObject *obj = Sim::findObject(argv[i]);
|
|
if(obj && set->find(set->begin(),set->end(),obj) != set->end())
|
|
set->removeObject(obj);
|
|
else
|
|
Con::printf("Set::remove: Object \"%s\" does not exist in set", argv[i]);
|
|
}
|
|
}
|
|
|
|
ConsoleMethod(SimSet, clear, void, 2, 2, "set.clear()")
|
|
{
|
|
argc; argv;
|
|
SimSet *set = (SimSet *) object;
|
|
while (set->size() > 0)
|
|
set->removeObject(*(set->begin()));
|
|
}
|
|
|
|
ConsoleMethod(SimSet, getCount, S32, 2, 2, "set.getCount()")
|
|
{
|
|
argc; argv;
|
|
return ((SimSet *) object)->size();
|
|
}
|
|
|
|
ConsoleMethod(SimSet, getObject, S32, 3, 3, "set.getObject(objIndex)")
|
|
{
|
|
argc;
|
|
SimSet *set = (SimSet *) object;
|
|
S32 objectIndex = dAtoi(argv[2]);
|
|
if(objectIndex < 0 || objectIndex >= S32(set->size()))
|
|
{
|
|
Con::printf("Set::getObject index out of range.");
|
|
return -1;
|
|
}
|
|
return ((*set)[objectIndex])->getId();
|
|
}
|
|
|
|
ConsoleMethod(SimSet, isMember, bool, 3, 3, "set.isMember(object)")
|
|
{
|
|
argc;
|
|
SimSet *set = (SimSet *) object;
|
|
SimObject *testObject = Sim::findObject(argv[2]);
|
|
if(!testObject)
|
|
{
|
|
Con::printf("SimSet::isMember: %s is not an object.", argv[2]);
|
|
return false;
|
|
}
|
|
for(SimSet::iterator i = set->begin(); i != set->end(); i++)
|
|
if(*i == testObject)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
ConsoleMethod(SimSet, bringToFront, void, 3, 3, "set.bringToFront(object)")
|
|
{
|
|
argc;
|
|
SimObject *obj = Sim::findObject(argv[2]);
|
|
if(!obj)
|
|
return;
|
|
((SimSet *) object)->bringObjectToFront(obj);
|
|
}
|
|
|
|
ConsoleMethod(SimSet, pushToBack, void, 3, 3, "set.pushToBack(object)")
|
|
{
|
|
argc;
|
|
SimObject *obj = Sim::findObject(argv[2]);
|
|
if(!obj)
|
|
return;
|
|
((SimSet *) object)->pushObjectToBack(obj);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
IMPLEMENT_CONOBJECT(SimSet);
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
SimGroup::~SimGroup()
|
|
{
|
|
for (iterator itr = begin(); itr != end(); itr++)
|
|
nameDictionary.remove(*itr);
|
|
|
|
// XXX Move this later into Group Class
|
|
// If we have any objects at this point, they should
|
|
// already have been removed from the manager, so we
|
|
// can just delete them directly.
|
|
objectList.sortId();
|
|
while (!objectList.empty()) {
|
|
delete objectList.last();
|
|
objectList.decrement();
|
|
}
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
void SimGroup::addObject(SimObject* obj)
|
|
{
|
|
if (obj->mGroup != this) {
|
|
if (obj->mGroup)
|
|
obj->mGroup->removeObject(obj);
|
|
nameDictionary.insert(obj);
|
|
obj->mGroup = this;
|
|
objectList.push_back(obj); // force it into the object list
|
|
// doesn't get a delete notify
|
|
obj->onGroupAdd();
|
|
}
|
|
}
|
|
|
|
void SimGroup::removeObject(SimObject* obj)
|
|
{
|
|
if (obj->mGroup == this) {
|
|
obj->onGroupRemove();
|
|
nameDictionary.remove(obj);
|
|
objectList.remove(obj);
|
|
obj->mGroup = 0;
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
void SimGroup::onRemove()
|
|
{
|
|
objectList.sortId();
|
|
if (objectList.size())
|
|
{
|
|
// This backwards iterator loop doesn't work if the
|
|
// list is empty, check the size first.
|
|
for (SimObjectList::iterator ptr = objectList.end() - 1;
|
|
ptr >= objectList.begin(); ptr--)
|
|
{
|
|
(*ptr)->onGroupRemove();
|
|
(*ptr)->mGroup = NULL;
|
|
(*ptr)->unregisterObject();
|
|
(*ptr)->mGroup = this;
|
|
}
|
|
}
|
|
SimObject::onRemove();
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
SimObject *SimGroup::findObject(const char *namePath)
|
|
{
|
|
// find the end of the object name
|
|
S32 len;
|
|
for(len = 0; namePath[len] != 0 && namePath[len] != '/'; len++)
|
|
;
|
|
|
|
StringTableEntry stName = StringTable->lookupn(namePath, len);
|
|
if(!stName)
|
|
return NULL;
|
|
|
|
SimObject *root = nameDictionary.find(stName);
|
|
|
|
if(!root)
|
|
return NULL;
|
|
|
|
if(namePath[len] == 0)
|
|
return root;
|
|
|
|
return root->findObject(namePath + len + 1);
|
|
}
|
|
|
|
SimObject *SimSet::findObject(const char *namePath)
|
|
{
|
|
// find the end of the object name
|
|
S32 len;
|
|
for(len = 0; namePath[len] != 0 && namePath[len] != '/'; len++)
|
|
;
|
|
|
|
StringTableEntry stName = StringTable->lookupn(namePath, len);
|
|
if(!stName)
|
|
return NULL;
|
|
|
|
for(SimSet::iterator i = begin(); i != end(); i++)
|
|
{
|
|
if((*i)->getName() == stName)
|
|
{
|
|
if(namePath[len] == 0)
|
|
return *i;
|
|
return (*i)->findObject(namePath + len + 1);
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
SimObject* SimObject::findObject(const char* )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool SimGroup::processArguments(S32, const char **)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
IMPLEMENT_CONOBJECT(SimGroup);
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
SimConsoleEvent::SimConsoleEvent(S32 argc, const char **argv, bool onObject)
|
|
{
|
|
mOnObject = onObject;
|
|
mArgc = argc;
|
|
U32 totalSize = 0;
|
|
S32 i;
|
|
for(i = 0; i < argc; i++)
|
|
totalSize += dStrlen(argv[i]) + 1;
|
|
totalSize += sizeof(char *) * argc;
|
|
|
|
mArgv = (char **) dMalloc(totalSize);
|
|
char *argBase = (char *) &mArgv[argc];
|
|
|
|
for(i = 0; i < argc; i++)
|
|
{
|
|
mArgv[i] = argBase;
|
|
dStrcpy(mArgv[i], argv[i]);
|
|
argBase += dStrlen(argv[i]) + 1;
|
|
}
|
|
}
|
|
|
|
SimConsoleEvent::~SimConsoleEvent()
|
|
{
|
|
dFree(mArgv);
|
|
}
|
|
|
|
void SimConsoleEvent::process(SimObject* object)
|
|
{
|
|
// #ifdef DEBUG
|
|
// Con::printf("Executing schedule: %d", sequenceCount);
|
|
// #endif
|
|
if(mOnObject)
|
|
Con::execute(object, mArgc, const_cast<const char**>( mArgv ));
|
|
else
|
|
Con::execute(mArgc, const_cast<const char**>( mArgv ));
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
inline void SimSetIterator::Stack::push_back(SimSet* set)
|
|
{
|
|
increment();
|
|
last().set = set;
|
|
last().itr = set->begin();
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
SimSetIterator::SimSetIterator(SimSet* set)
|
|
{
|
|
VECTOR_SET_ASSOCIATION(stack);
|
|
|
|
if (!set->empty())
|
|
stack.push_back(set);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
SimObject* SimSetIterator::operator++()
|
|
{
|
|
SimSet* set;
|
|
if ((set = dynamic_cast<SimSet*>(*stack.last().itr)) != 0) {
|
|
if (!set->empty()) {
|
|
stack.push_back(set);
|
|
return *stack.last().itr;
|
|
}
|
|
}
|
|
|
|
while (++stack.last().itr == stack.last().set->end()) {
|
|
stack.pop_back();
|
|
if (stack.empty())
|
|
return 0;
|
|
}
|
|
return *stack.last().itr;
|
|
}
|
|
|