diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 8f4615683b..decd07b058 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -1453,9 +1453,9 @@ static int PatchAmmo (int ammoNum) // Fix per-ammo/max-ammo amounts for descendants of the base ammo class if (oldclip != *per) { - for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - PClass *type = PClass::m_Types[i]; + PClassActor *type = PClassActor::AllActorClasses[i]; if (type == ammoType) continue; diff --git a/src/d_main.cpp b/src/d_main.cpp index 3b4228a68b..2f0c071fee 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -1754,14 +1754,16 @@ void D_DoomMain (void) #endif #endif + PClass::StaticInit(); + PType::StaticInit(); + // Combine different file parameters with their pre-switch bits. Args->CollectFiles("-deh", ".deh"); Args->CollectFiles("-bex", ".bex"); Args->CollectFiles("-exec", ".cfg"); Args->CollectFiles("-playdemo", ".lmp"); - Args->CollectFiles("-file", NULL); // anythnig left goes after -file + Args->CollectFiles("-file", NULL); // anything left goes after -file - PClass::StaticInit (); atterm (C_DeinitConsole); gamestate = GS_STARTUP; diff --git a/src/decallib.cpp b/src/decallib.cpp index 6446f92832..8e06778b4f 100644 --- a/src/decallib.cpp +++ b/src/decallib.cpp @@ -353,9 +353,9 @@ void FDecalLib::ReadAllDecals () ReadDecals (sc); } // Supporting code to allow specifying decals directly in the DECORATE lump - for (i = 0; i < PClass::m_RuntimeActors.Size(); i++) + for (i = 0; i < PClassActor::AllActorClasses.Size(); i++) { - AActor *def = (AActor*)GetDefaultByType (PClass::m_RuntimeActors[i]); + AActor *def = (AActor*)GetDefaultByType (PClassActor::AllActorClasses[i]); FName v = ENamedName(intptr_t(def->DecalGenerator)); if (v.IsValidName()) diff --git a/src/dobject.cpp b/src/dobject.cpp index 959b25d581..d9d94aa341 100644 --- a/src/dobject.cpp +++ b/src/dobject.cpp @@ -180,9 +180,9 @@ CCMD (dumpclasses) shown = omitted = 0; DumpInfo::AddType (&tree, root != NULL ? root : RUNTIME_CLASS(DObject)); - for (i = 0; i < PClass::m_Types.Size(); i++) + for (i = 0; i < PClass::AllClasses.Size(); i++) { - PClass *cls = PClass::m_Types[i]; + PClass *cls = PClass::AllClasses[i]; if (root == NULL || cls == root || cls->IsDescendantOf(root)) { DumpInfo::AddType (&tree, cls); diff --git a/src/dobject.h b/src/dobject.h index 93667f9c20..ad4481f5a9 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -94,7 +94,9 @@ enum CLASSREG_PClassHealth, CLASSREG_PClassPuzzleItem, CLASSREG_PClassWeapon, - CLASSREG_PClassPlayerPawn + CLASSREG_PClassPlayerPawn, + CLASSREG_PClassType, + CLASSREG_PClassClass, }; struct ClassReg @@ -104,10 +106,11 @@ struct ClassReg ClassReg *ParentType; const size_t *Pointers; void (*ConstructNative)(void *); - unsigned int SizeOf:29; - unsigned int MetaClassNum:3; + unsigned int SizeOf:28; + unsigned int MetaClassNum:4; PClass *RegisterClass(); + void SetupClass(PClass *cls); }; enum EInPlace { EC_InPlace }; @@ -178,6 +181,10 @@ protected: \ #define IMPLEMENT_ABSTRACT_CLASS(cls) \ _IMP_PCLASS(cls,NULL,NULL) +#define IMPLEMENT_ABSTRACT_POINTY_CLASS(cls) \ + _IMP_PCLASS(cls,cls::PointerOffsets,NULL) \ + const size_t cls::PointerOffsets[] = { + enum EObjectFlags { // GC flags @@ -292,6 +299,9 @@ namespace GC // is NULLed instead. void Mark(DObject **obj); + // Marks an array of objects. + void MarkArray(DObject **objs, size_t count); + // Soft-roots an object. void AddSoftRoot(DObject *obj); @@ -310,6 +320,15 @@ namespace GC obj = t; } template void Mark(TObjPtr &obj); + + template void MarkArray(T **obj, size_t count) + { + MarkArray((DObject **)(obj), count); + } + template void MarkArray(TArray &arr) + { + MarkArray(&arr[0], arr.Size()); + } } // A template class to help with handling read barriers. It does not diff --git a/src/dobjgc.cpp b/src/dobjgc.cpp index 3bdca01bda..105ec1096c 100644 --- a/src/dobjgc.cpp +++ b/src/dobjgc.cpp @@ -283,6 +283,22 @@ void Mark(DObject **obj) } } +//========================================================================== +// +// MarkArray +// +// Mark an array of objects gray. +// +//========================================================================== + +void MarkArray(DObject **obj, size_t count) +{ + for (size_t i = 0; i < count; ++i) + { + Mark(obj[i]); + } +} + //========================================================================== // // MarkRoot @@ -341,9 +357,9 @@ static void MarkRoot() } } // Mark classes - for (unsigned j = 0; j < PClass::m_Types.Size(); ++j) + for (unsigned j = 0; j < PClass::AllClasses.Size(); ++j) { - Mark(PClass::m_Types[j]); + Mark(PClass::AllClasses[j]); } // Mark bot stuff. Mark(bglobal.firstthing); diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index d2ec92d152..a211c55da6 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -3,7 +3,7 @@ ** Implements the type information class ** **--------------------------------------------------------------------------- -** Copyright 1998-2008 Randy Heit +** Copyright 1998-2010 Randy Heit ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without @@ -32,6 +32,8 @@ ** */ +// HEADER FILES ------------------------------------------------------------ + #include "dobject.h" #include "i_system.h" #include "actor.h" @@ -41,17 +43,425 @@ #include "a_pickups.h" #include "d_player.h" +// MACROS ------------------------------------------------------------------ + +// TYPES ------------------------------------------------------------------- + +// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- + +// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- + +// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- + +// EXTERNAL DATA DECLARATIONS ---------------------------------------------- + +// PUBLIC DATA DEFINITIONS ------------------------------------------------- + +FTypeTable TypeTable; +TArray PClass::AllClasses; +bool PClass::bShutdown; + +// PRIVATE DATA DEFINITIONS ------------------------------------------------ + +// A harmless non-NULL FlatPointer for classes without pointers. +static const size_t TheEnd = ~(size_t)0; + +// CODE -------------------------------------------------------------------- + +void DumpTypeTable() +{ + int used = 0; + int min = INT_MAX; + int max = 0; + int all = 0; + int lens[10] = {0}; + for (size_t i = 0; i < countof(TypeTable.TypeHash); ++i) + { + int len = 0; + Printf("%4d:", i); + for (PType *ty = TypeTable.TypeHash[i]; ty != NULL; ty = ty->HashNext) + { + Printf(" -> %s", ty->IsKindOf(RUNTIME_CLASS(PNamedType)) ? static_cast(ty)->TypeName.GetChars(): ty->GetClass()->TypeName.GetChars()); + len++; + all++; + } + if (len != 0) + { + used++; + if (len < min) + min = len; + if (len > max) + max = len; + } + if (len < countof(lens)) + { + lens[len]++; + } + Printf("\n"); + } + Printf("Used buckets: %d/%u (%.2f%%) for %d entries\n", used, countof(TypeTable.TypeHash), double(used)/countof(TypeTable.TypeHash)*100, all); + Printf("Min bucket size: %d\n", min); + Printf("Max bucket size: %d\n", max); + Printf("Avg bucket size: %.2f\n", double(all) / used); + int j,k; + for (k = k = countof(lens)-1; k > 0; --k) + if (lens[k]) + break; + for (j = 0; j <= k; ++j) + Printf("Buckets of len %d: %d (%.2f%%)\n", j, lens[j], j!=0?double(lens[j])/used*100:-1.0); +} + +/* PClassType *************************************************************/ + +IMPLEMENT_CLASS(PClassType) + +//========================================================================== +// +// PClassType Constructor +// +//========================================================================== + +PClassType::PClassType() +: TypeTableType(NULL) +{ +} + +//========================================================================== +// +// PClassType :: Derive +// +//========================================================================== + +void PClassType::Derive(PClass *newclass) +{ + assert(newclass->IsKindOf(RUNTIME_CLASS(PClassType))); + Super::Derive(newclass); + static_cast(newclass)->TypeTableType = TypeTableType; +} + +/* PClassClass ************************************************************/ + +IMPLEMENT_CLASS(PClassClass) + +//========================================================================== +// +// PClassClass Constructor +// +// The only thing we want to do here is automatically set TypeTableType +// to PClass. +// +//========================================================================== + +PClassClass::PClassClass() +{ + TypeTableType = RUNTIME_CLASS(PClass); +} + +/* PType ******************************************************************/ + +IMPLEMENT_ABSTRACT_CLASS(PType) + +//========================================================================== +// +// PType Constructor +// +//========================================================================== + +PType::PType() +: Size(0), Align(1), HashNext(NULL) +{ +} + +//========================================================================== +// +// PType Destructor +// +//========================================================================== + +PType::~PType() +{ +} + +//========================================================================== +// +// PType :: IsMatch +// +//========================================================================== + +bool PType::IsMatch(const void *id1, const void *id2) const +{ + return false; +} + +//========================================================================== +// +// PType :: StaticInit STATIC +// +// Set up TypeTableType values for every PType child. +// +//========================================================================== + +void PType::StaticInit() +{ + RUNTIME_CLASS(PInt)->TypeTableType = RUNTIME_CLASS(PInt); + RUNTIME_CLASS(PFloat)->TypeTableType = RUNTIME_CLASS(PFloat); + RUNTIME_CLASS(PString)->TypeTableType = RUNTIME_CLASS(PString); + RUNTIME_CLASS(PName)->TypeTableType = RUNTIME_CLASS(PName); + RUNTIME_CLASS(PSound)->TypeTableType = RUNTIME_CLASS(PSound); + RUNTIME_CLASS(PColor)->TypeTableType = RUNTIME_CLASS(PColor); + RUNTIME_CLASS(PPointer)->TypeTableType = RUNTIME_CLASS(PPointer); + RUNTIME_CLASS(PClassPointer)->TypeTableType = RUNTIME_CLASS(PPointer); // not sure about this yet + RUNTIME_CLASS(PEnum)->TypeTableType = RUNTIME_CLASS(PEnum); + RUNTIME_CLASS(PArray)->TypeTableType = RUNTIME_CLASS(PArray); + RUNTIME_CLASS(PDynArray)->TypeTableType = RUNTIME_CLASS(PDynArray); + RUNTIME_CLASS(PVector)->TypeTableType = RUNTIME_CLASS(PVector); + RUNTIME_CLASS(PMap)->TypeTableType = RUNTIME_CLASS(PMap); + RUNTIME_CLASS(PStruct)->TypeTableType = RUNTIME_CLASS(PStruct); + RUNTIME_CLASS(PPrototype)->TypeTableType = RUNTIME_CLASS(PPrototype); + RUNTIME_CLASS(PFunction)->TypeTableType = RUNTIME_CLASS(PFunction); + RUNTIME_CLASS(PClass)->TypeTableType = RUNTIME_CLASS(PClass); +} + + +/* PBasicType *************************************************************/ + +IMPLEMENT_ABSTRACT_CLASS(PBasicType) + +/* PCompoundType **********************************************************/ + +IMPLEMENT_ABSTRACT_CLASS(PCompoundType) + +/* PNamedType *************************************************************/ + +IMPLEMENT_ABSTRACT_POINTY_CLASS(PNamedType) + DECLARE_POINTER(Outer) +END_POINTERS + +//========================================================================== +// +// PNamedType :: IsMatch +// +//========================================================================== + +bool PNamedType::IsMatch(const void *id1, const void *id2) const +{ + const DObject *outer = (const DObject *)id1; + FName name = (ENamedName)(intptr_t)id2; + + return Outer == outer && TypeName == name; +} + +/* PInt *******************************************************************/ + +IMPLEMENT_CLASS(PInt) + +/* PFloat *****************************************************************/ + +IMPLEMENT_CLASS(PFloat) + +/* PString ****************************************************************/ + +IMPLEMENT_CLASS(PString) + +/* PName ******************************************************************/ + +IMPLEMENT_CLASS(PName) + +/* PSound *****************************************************************/ + +IMPLEMENT_CLASS(PSound) + +/* PColor *****************************************************************/ + +IMPLEMENT_CLASS(PColor) + +/* PPointer ***************************************************************/ + +IMPLEMENT_POINTY_CLASS(PPointer) + DECLARE_POINTER(PointedType) +END_POINTERS + +//========================================================================== +// +// PPointer :: IsMatch +// +//========================================================================== + +bool PPointer::IsMatch(const void *id1, const void *id2) const +{ + assert(id2 == NULL); + PType *pointat = (PType *)id1; + + return pointat == PointedType; +} + +/* PClassPointer **********************************************************/ + +IMPLEMENT_POINTY_CLASS(PClassPointer) + DECLARE_POINTER(ClassRestriction) +END_POINTERS + +//========================================================================== +// +// PClassPointer :: IsMatch +// +//========================================================================== + +bool PClassPointer::IsMatch(const void *id1, const void *id2) const +{ + const PType *pointat = (const PType *)id1; + const PClass *classat = (const PClass *)id2; + + assert(pointat->IsKindOf(RUNTIME_CLASS(PClass))); + return classat == ClassRestriction; +} + +/* PEnum ******************************************************************/ + +IMPLEMENT_POINTY_CLASS(PEnum) + DECLARE_POINTER(ValueType) +END_POINTERS + +/* PArray *****************************************************************/ + +IMPLEMENT_POINTY_CLASS(PArray) + DECLARE_POINTER(ElementType) +END_POINTERS + +//========================================================================== +// +// PArray :: IsMatch +// +//========================================================================== + +bool PArray::IsMatch(const void *id1, const void *id2) const +{ + const PType *elemtype = (const PType *)id1; + unsigned int count = (unsigned int)(intptr_t)id2; + + return elemtype == ElementType && count == ElementCount; +} + +/* PVector ****************************************************************/ + +IMPLEMENT_CLASS(PVector) + +/* PDynArray **************************************************************/ + +IMPLEMENT_POINTY_CLASS(PDynArray) + DECLARE_POINTER(ElementType) +END_POINTERS + +bool PDynArray::IsMatch(const void *id1, const void *id2) const +{ + assert(id2 == NULL); + const PType *elemtype = (const PType *)id1; + + return elemtype == ElementType; +} + +/* PMap *******************************************************************/ + +IMPLEMENT_POINTY_CLASS(PMap) + DECLARE_POINTER(KeyType) + DECLARE_POINTER(ValueType) +END_POINTERS + +//========================================================================== +// +// PMap :: IsMatch +// +//========================================================================== + +bool PMap::IsMatch(const void *id1, const void *id2) const +{ + const PType *keyty = (const PType *)id1; + const PType *valty = (const PType *)id2; + + return keyty == KeyType && valty == ValueType; +} + +/* PStruct ****************************************************************/ + +IMPLEMENT_CLASS(PStruct) + +//========================================================================== +// +// PStruct :: PropagateMark +// +//========================================================================== + +size_t PStruct::PropagateMark() +{ + GC::MarkArray(Fields); + return Fields.Size() * sizeof(void*) + Super::PropagateMark(); +} + +/* PPrototype *************************************************************/ + +IMPLEMENT_CLASS(PPrototype) + +//========================================================================== +// +// PPrototype :: IsMatch +// +//========================================================================== + +bool PPrototype::IsMatch(const void *id1, const void *id2) const +{ + const TArray *args = (const TArray *)id1; + const TArray *rets = (const TArray *)id2; + + return *args == ArgumentTypes && *rets == ReturnTypes; +} + +//========================================================================== +// +// PPrototype :: PropagateMark +// +//========================================================================== + +size_t PPrototype::PropagateMark() +{ + GC::MarkArray(ArgumentTypes); + GC::MarkArray(ReturnTypes); + return (ArgumentTypes.Size() + ReturnTypes.Size()) * sizeof(void*) + + Super::PropagateMark(); +} + +/* PFunction **************************************************************/ + +IMPLEMENT_CLASS(PFunction) + +//========================================================================== +// +// PFunction :: PropagataMark +// +//========================================================================== + +size_t PFunction::PropagateMark() +{ + for (unsigned i = 0; i < Variants.Size(); ++i) + { + GC::Mark(Variants[i].Proto); + GC::Mark(Variants[i].Implementation); + } + return Variants.Size() * sizeof(Variants[0]) + Super::PropagateMark(); +} + +/* PClass *****************************************************************/ + IMPLEMENT_POINTY_CLASS(PClass) DECLARE_POINTER(ParentClass) END_POINTERS -TArray PClass::m_RuntimeActors; -TArray PClass::m_Types; -PClass *PClass::TypeHash[PClass::HASH_SIZE]; -bool PClass::bShutdown; - -// A harmless non-NULL FlatPointer for classes without pointers. -static const size_t TheEnd = ~(size_t)0; +//========================================================================== +// +// cregcmp +// +// Sorter to keep built-in types in a deterministic order. (Needed?) +// +//========================================================================== static int STACK_ARGS cregcmp (const void *a, const void *b) { @@ -60,10 +470,20 @@ static int STACK_ARGS cregcmp (const void *a, const void *b) return strcmp(class1->TypeName, class2->TypeName); } +//========================================================================== +// +// PClass :: StaticInit STATIC +// +// Creates class metadata for all built-in types. +// +//========================================================================== + void PClass::StaticInit () { atterm (StaticShutdown); + StaticBootstrap(); + FAutoSegIterator probe(CRegHead, CRegTail); while (*++probe != NULL) @@ -71,24 +491,29 @@ void PClass::StaticInit () ((ClassReg *)*probe)->RegisterClass (); } - // Keep actors in consistant order. I did this before, though I'm not - // sure if this is really necessary to maintain any sort of sync. - qsort(&m_Types[0], m_Types.Size(), sizeof(m_Types[0]), cregcmp); - for (unsigned int i = 0; i < m_Types.Size(); ++i) - { - m_Types[i]->ClassIndex = i; - } + // Keep built-in classes in consistant order. I did this before, though + // I'm not sure if this is really necessary to maintain any sort of sync. + qsort(&AllClasses[0], AllClasses.Size(), sizeof(AllClasses[0]), cregcmp); } +//========================================================================== +// +// PClass :: StaticShutdown STATIC +// +// Frees FlatPointers belonging to all classes. Only really needed to avoid +// memory leak warnings at exit. +// +//========================================================================== + void PClass::StaticShutdown () { TArray uniqueFPs(64); unsigned int i, j; - for (i = 0; i < PClass::m_Types.Size(); ++i) + for (i = 0; i < PClass::AllClasses.Size(); ++i) { - PClass *type = PClass::m_Types[i]; - PClass::m_Types[i] = NULL; + PClass *type = PClass::AllClasses[i]; + PClass::AllClasses[i] = NULL; if (type->FlatPointers != &TheEnd && type->FlatPointers != type->Pointers) { // FlatPointers are shared by many classes, so we must check for @@ -113,6 +538,43 @@ void PClass::StaticShutdown () bShutdown = true; } +//========================================================================== +// +// PClass :: StaticBootstrap STATIC +// +// PClass and PClassClass have intermingling dependencies on their +// definitions. To sort this out, we explicitly define them before +// proceeding with the RegisterClass loop in StaticInit(). +// +//========================================================================== + +void PClass::StaticBootstrap() +{ + PClassClass *clscls = new PClassClass; + PClassClass::RegistrationInfo.SetupClass(clscls); + + PClassClass *cls = new PClassClass; + PClass::RegistrationInfo.SetupClass(cls); + + // The PClassClass constructor initialized these to NULL, because the + // PClass metadata had not been created yet. Now it has, so we know what + // they should be and can insert them into the type table successfully. + clscls->TypeTableType = cls; + cls->TypeTableType = cls; + clscls->InsertIntoHash(); + cls->InsertIntoHash(); + + // Create parent objects before we go so that these definitions are complete. + clscls->ParentClass = PClassType::RegistrationInfo.ParentType->RegisterClass(); + cls->ParentClass = PClass::RegistrationInfo.ParentType->RegisterClass(); +} + +//========================================================================== +// +// PClass Constructor +// +//========================================================================== + PClass::PClass() { Size = sizeof(DObject); @@ -122,10 +584,17 @@ PClass::PClass() HashNext = NULL; Defaults = NULL; bRuntimeClass = false; - ClassIndex = ~0; ConstructNative = NULL; + + PClass::AllClasses.Push(this); } +//========================================================================== +// +// PClass Destructor +// +//========================================================================== + PClass::~PClass() { Symbols.ReleaseSymbols(); @@ -136,6 +605,15 @@ PClass::~PClass() } } +//========================================================================== +// +// ClassReg :: RegisterClass +// +// Create metadata describing the built-in class this struct is intended +// for. +// +//========================================================================== + PClass *ClassReg::RegisterClass() { static ClassReg *const metaclasses[] = @@ -148,10 +626,11 @@ PClass *ClassReg::RegisterClass() &PClassPuzzleItem::RegistrationInfo, &PClassWeapon::RegistrationInfo, &PClassPlayerPawn::RegistrationInfo, + &PClassType::RegistrationInfo, + &PClassClass::RegistrationInfo, }; - // MyClass may have already been created by a previous recursive call. - // Or this may be a recursive call for a previously created class. + // Skip classes that have already been registered if (MyClass != NULL) { return MyClass; @@ -165,25 +644,13 @@ PClass *ClassReg::RegisterClass() assert(0 && "Class registry has an invalid meta class identifier"); } - if (this == &PClass::RegistrationInfo) - { - cls = new PClass; - } - else - { - if (metaclasses[MetaClassNum]->MyClass == NULL) - { // Make sure the meta class is already registered before registering this one - metaclasses[MetaClassNum]->RegisterClass(); - } - cls = static_cast(metaclasses[MetaClassNum]->MyClass->CreateNew()); + if (metaclasses[MetaClassNum]->MyClass == NULL) + { // Make sure the meta class is already registered before registering this one + metaclasses[MetaClassNum]->RegisterClass(); } + cls = static_cast(metaclasses[MetaClassNum]->MyClass->CreateNew()); - MyClass = cls; - PClass::m_Types.Push(cls); - cls->TypeName = FName(Name+1); - cls->Size = SizeOf; - cls->Pointers = Pointers; - cls->ConstructNative = ConstructNative; + SetupClass(cls); cls->InsertIntoHash(); if (ParentType != NULL) { @@ -192,65 +659,76 @@ PClass *ClassReg::RegisterClass() return cls; } -void PClass::InsertIntoHash () -{ - // Add class to hash table. Classes are inserted into each bucket - // in ascending order by name index. - unsigned int bucket = TypeName % HASH_SIZE; - PClass **hashpos = &TypeHash[bucket]; - while (*hashpos != NULL) - { - int lexx = int(TypeName) - int((*hashpos)->TypeName); +//========================================================================== +// +// ClassReg :: SetupClass +// +// Copies the class-defining parameters from a ClassReg to the Class object +// created for it. +// +//========================================================================== - if (lexx > 0) - { // This type should come later in the chain - hashpos = &((*hashpos)->HashNext); - } - else if (lexx == 0) - { // This type has already been inserted - // ... but there is no need whatsoever to make it a fatal error! - Printf (TEXTCOLOR_RED"Tried to register class '%s' more than once.\n", TypeName.GetChars()); - break; - } - else - { // Type comes right here - break; - } - } - HashNext = *hashpos; - *hashpos = this; +void ClassReg::SetupClass(PClass *cls) +{ + assert(MyClass == NULL); + MyClass = cls; + cls->TypeName = FName(Name+1); + cls->Size = SizeOf; + cls->Pointers = Pointers; + cls->ConstructNative = ConstructNative; } -// Find a type, passed the name as a name +//========================================================================== +// +// PClass :: InsertIntoHash +// +// Add class to the type table. +// +//========================================================================== + +void PClass::InsertIntoHash () +{ + size_t bucket; + PType *found; + + found = TypeTable.FindType(RUNTIME_CLASS(PClass), Outer, (void*)(intptr_t)(int)TypeName, &bucket); + if (found != NULL) + { // This type has already been inserted + // ... but there is no need whatsoever to make it a fatal error! + Printf (TEXTCOLOR_RED"Tried to register class '%s' more than once.\n", TypeName.GetChars()); + } + else + { + TypeTable.AddType(this, RUNTIME_CLASS(PClass), Outer, (void*)(intptr_t)(int)TypeName, bucket); + } +} + +//========================================================================== +// +// PClass :: FindClass +// +// Find a type, passed the name as a name. +// +//========================================================================== + PClass *PClass::FindClass (FName zaname) { if (zaname == NAME_None) { return NULL; } - - PClass *cls = TypeHash[zaname % HASH_SIZE]; - - while (cls != 0) - { - int lexx = int(zaname) - int(cls->TypeName); - if (lexx > 0) - { - cls = cls->HashNext; - } - else if (lexx == 0) - { - return cls->Size<0? NULL : cls; - } - else - { - break; - } - } - return NULL; + return static_cast(TypeTable.FindType(RUNTIME_CLASS(PClass), + /*FIXME:Outer*/NULL, (void*)(intptr_t)(int)zaname, NULL)); } +//========================================================================== +// +// PClass :: CreateNew +// // Create a new object that this class represents +// +//========================================================================== + DObject *PClass::CreateNew() const { BYTE *mem = (BYTE *)M_Malloc (Size); @@ -267,7 +745,14 @@ DObject *PClass::CreateNew() const return (DObject *)mem; } +//========================================================================== +// +// PClass :: Derive +// // Copies inheritable values into the derived class and other miscellaneous setup. +// +//========================================================================== + void PClass::Derive(PClass *newclass) { newclass->ParentClass = this; @@ -275,7 +760,7 @@ void PClass::Derive(PClass *newclass) // Set up default instance of the new class. newclass->Defaults = (BYTE *)M_Malloc(newclass->Size); - memcpy(newclass->Defaults, Defaults, Size); + if (Defaults) memcpy(newclass->Defaults, Defaults, Size); if (newclass->Size > Size) { memset(newclass->Defaults + Size, 0, newclass->Size - Size); @@ -284,8 +769,15 @@ void PClass::Derive(PClass *newclass) newclass->Symbols.SetParentTable(&this->Symbols); } +//========================================================================== +// +// PClass :: CreateDerivedClass +// // Create a new class based on an existing class -PClass *PClass::CreateDerivedClass (FName name, unsigned int size) +// +//========================================================================== + +PClass *PClass::CreateDerivedClass(FName name, unsigned int size) { assert (size >= Size); PClass *type; @@ -317,20 +809,20 @@ PClass *PClass::CreateDerivedClass (FName name, unsigned int size) Derive(type); if (!notnew) { - type->ClassIndex = m_Types.Push (type); type->InsertIntoHash(); } - - // If this class is for an actor, push it onto the RuntimeActors stack. - if (type->IsKindOf(RUNTIME_CLASS(PClassActor))) - { - m_RuntimeActors.Push(static_cast(type)); - } return type; } -// Add bytes to the end of this class. Returns the -// previous size of the class. +//========================================================================== +// +// PClass:: Extend +// +// Add bytes to the end of this class. Returns the previous +// size of the class. +// +//========================================================================== + unsigned int PClass::Extend(unsigned int extension) { assert(this->bRuntimeClass); @@ -342,33 +834,30 @@ unsigned int PClass::Extend(unsigned int extension) return oldsize; } -// Like FindClass but creates a placeholder if no class -// is found. CreateDerivedClass will automatcally fill in -// the placeholder when the actual class is defined. -PClass *PClass::FindClassTentative (FName name) +//========================================================================== +// +// PClass :: FindClassTentative +// +// Like FindClass but creates a placeholder if no class is found. +// CreateDerivedClass will automatically fill in the placeholder when the +// actual class is defined. +// +//========================================================================== + +PClass *PClass::FindClassTentative(FName name) { if (name == NAME_None) { return NULL; } + size_t bucket; - PClass *cls = TypeHash[name % HASH_SIZE]; + PType *found = TypeTable.FindType(RUNTIME_CLASS(PClass), + /*FIXME:Outer*/NULL, (void*)(intptr_t)(int)name, &bucket); - while (cls != 0) + if (found != NULL) { - int lexx = int(name) - int(cls->TypeName); - if (lexx > 0) - { - cls = cls->HashNext; - } - else if (lexx == 0) - { - return cls; - } - else - { - break; - } + return static_cast(found); } PClass *type = static_cast(GetClass()->CreateNew()); DPrintf("Creating placeholder class %s : %s\n", name.GetChars(), TypeName.GetChars()); @@ -376,16 +865,22 @@ PClass *PClass::FindClassTentative (FName name) type->TypeName = name; type->ParentClass = this; type->Size = -1; - type->ClassIndex = m_Types.Push (type); type->bRuntimeClass = true; - type->InsertIntoHash(); + TypeTable.AddType(type, RUNTIME_CLASS(PClass), type->Outer, (void*)(intptr_t)(int)name, bucket); return type; } +//========================================================================== +// +// PClass :: BuildFlatPointers +// // Create the FlatPointers array, if it doesn't exist already. -// It comprises all the Pointers from superclasses plus this class's own Pointers. -// If this class does not define any new Pointers, then FlatPointers will be set -// to the same array as the super class's. +// It comprises all the Pointers from superclasses plus this class's own +// Pointers. If this class does not define any new Pointers, then +// FlatPointers will be set to the same array as the super class. +// +//========================================================================== + void PClass::BuildFlatPointers () { if (FlatPointers != NULL) @@ -433,6 +928,14 @@ void PClass::BuildFlatPointers () } } +//========================================================================== +// +// PClass :: NativeClass +// +// Finds the underlying native type underlying this class. +// +//========================================================================== + const PClass *PClass::NativeClass() const { const PClass *cls = this; @@ -443,6 +946,12 @@ const PClass *PClass::NativeClass() const return cls; } +//========================================================================== +// +// PClass :: PropagateMark +// +//========================================================================== + size_t PClass::PropagateMark() { size_t marked; @@ -453,6 +962,74 @@ size_t PClass::PropagateMark() return marked + Super::PropagateMark(); } +/* FTypeTable **************************************************************/ + +//========================================================================== +// +// FTypeTable :: FindType +// +//========================================================================== + +PType *FTypeTable::FindType(PClass *metatype, void *parm1, void *parm2, size_t *bucketnum) +{ + size_t bucket = Hash(metatype, parm1, parm2) % HASH_SIZE; + if (bucketnum != NULL) + { + *bucketnum = bucket; + } + for (PType *type = TypeHash[bucket]; type != NULL; type = type->HashNext) + { + if (type->GetClass()->TypeTableType == metatype && type->IsMatch(parm1, parm2)) + { + return type; + } + } + return NULL; +} + +//========================================================================== +// +// FTypeTable :: AddType +// +//========================================================================== + +void FTypeTable::AddType(PType *type, PClass *metatype, void *parm1, void *parm2, size_t bucket) +{ +#ifdef _DEBUG + size_t bucketcheck; + assert(metatype == type->GetClass()->TypeTableType && "Metatype does not match passed object"); + assert(FindType(metatype, parm1, parm2, &bucketcheck) == NULL && "Type must not be inserted more than once"); + assert(bucketcheck == bucket && "Passed bucket was wrong"); +#endif + type->HashNext = TypeHash[bucket]; + TypeHash[bucket] = type; +} + +//========================================================================== +// +// FTypeTable :: Hash STATIC +// +//========================================================================== + +size_t FTypeTable::Hash(void *p1, void *p2, void *p3) +{ + size_t i1 = (size_t)p1; + size_t i2 = (size_t)p2; + size_t i3 = (size_t)p3; + + // Swap the high and low halves of i1. The compiler should be smart enough + // to transform this into a ROR or ROL. + i1 = (i1 >> (sizeof(size_t)*4)) | (i1 << (sizeof(size_t)*4)); + + return (~i1 ^ i2) + i3 * 961748927; // i3 is multiplied by a prime +} + +#include "c_dispatch.h" +CCMD(typetable) +{ + DumpTypeTable(); +} + // Symbol tables ------------------------------------------------------------ IMPLEMENT_ABSTRACT_CLASS(PSymbol); @@ -465,6 +1042,12 @@ IMPLEMENT_POINTY_CLASS(PSymbolVMFunction) DECLARE_POINTER(Function) END_POINTERS +//========================================================================== +// +// +// +//========================================================================== + PSymbol::~PSymbol() { } diff --git a/src/dobjtype.h b/src/dobjtype.h index ac8e64e7e8..538e4574ea 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -140,28 +140,274 @@ private: friend class DObject; }; +// Basic information shared by all types ------------------------------------ + +// Only one copy of a type is ever instantiated at one time. +// - Enums, classes, and structs are defined by their names and outer classes. +// - Pointers are uniquely defined by the type they point at. +// - ClassPointers are also defined by their class restriction. +// - Arrays are defined by their element type and count. +// - DynArrays are defined by their element type. +// - Maps are defined by their key and value types. +// - Prototypes are defined by the argument and return types. +// - Functions are defined by their names and outer objects. +// In table form: +// Outer Name Type Type2 Count +// Enum * * +// Class * * +// Struct * * +// Function * * +// Pointer * +// ClassPointer + * +// Array * * +// DynArray * +// Map * * +// Prototype *+ *+ + +class PClassType; +class PType : public DObject +{ + //DECLARE_ABSTRACT_CLASS_WITH_META(PType, DObject, PClassType); + // We need to unravel the _WITH_META macro, since PClassType isn't defined yet, + // and we can't define it until we've defined PClass. But we can't define that + // without defining PType. + DECLARE_ABSTRACT_CLASS(PType, DObject) +protected: + enum { MetaClassNum = CLASSREG_PClassType }; +public: + typedef PClassType MetaClass; + MetaClass *GetClass() const; + + unsigned int Size; // this type's size + unsigned int Align; // this type's preferred alignment + PType *HashNext; // next type in this type table + + PType(); + virtual ~PType(); + + // Returns true if this type matches the two identifiers. Referring to the + // above table, any type is identified by at most two characteristics. Each + // type that implements this function will cast these to the appropriate type. + // It is up to the caller to make sure they are the correct types. There is + // only one prototype for this function in order to simplify type table + // management. + virtual bool IsMatch(const void *id1, const void *id2) const; + + static void StaticInit(); +}; + +// Some categorization typing ----------------------------------------------- + +class PBasicType : public PType +{ + DECLARE_ABSTRACT_CLASS(PBasicType, PType); +}; + +class PCompoundType : public PType +{ + DECLARE_ABSTRACT_CLASS(PCompoundType, PType); +}; + +class PNamedType : public PCompoundType +{ + DECLARE_ABSTRACT_CLASS(PNamedType, PCompoundType); + HAS_OBJECT_POINTERS; +public: + DObject *Outer; // object this type is contained within + FName TypeName; // this type's name + + PNamedType() : Outer(NULL) {} + + virtual bool IsMatch(const void *id1, const void *id2) const; +}; + +// Basic types -------------------------------------------------------------- + +class PInt : public PBasicType +{ + DECLARE_CLASS(PInt, PBasicType); +}; + +class PFloat : public PBasicType +{ + DECLARE_CLASS(PFloat, PBasicType); +}; + +class PString : public PBasicType +{ + DECLARE_CLASS(PString, PBasicType); +}; + +// Variations of integer types ---------------------------------------------- + +class PName : public PInt +{ + DECLARE_CLASS(PName, PInt); +}; + +class PSound : public PInt +{ + DECLARE_CLASS(PSound, PInt); +}; + +class PColor : public PInt +{ + DECLARE_CLASS(PColor, PInt); +}; + +// Pointers ----------------------------------------------------------------- + +class PPointer : public PInt +{ + DECLARE_CLASS(PPointer, PInt); + HAS_OBJECT_POINTERS; +public: + PType *PointedType; + + virtual bool IsMatch(const void *id1, const void *id2) const; +}; + +class PClass; +class PClassPointer : public PPointer +{ + DECLARE_CLASS(PClassPointer, PPointer); + HAS_OBJECT_POINTERS; +public: + PClass *ClassRestriction; + + typedef PClass *Type2; + + virtual bool IsMatch(const void *id1, const void *id2) const; +}; + +// Struct/class fields ------------------------------------------------------ + +class PField : public DObject +{ + DECLARE_ABSTRACT_CLASS(PField, DObject); +public: + FName FieldName; +}; + +class PMemberField : public PField +{ + DECLARE_CLASS(PMemberField, PField); + HAS_OBJECT_POINTERS +public: + unsigned int FieldOffset; + PType *FieldType; +}; + +// Compound types ----------------------------------------------------------- + +class PEnum : public PNamedType +{ + DECLARE_CLASS(PEnum, PNamedType); + HAS_OBJECT_POINTERS; +public: + PType *ValueType; + TMap Values; +}; + +class PArray : public PCompoundType +{ + DECLARE_CLASS(PArray, PCompoundType); + HAS_OBJECT_POINTERS; +public: + PType *ElementType; + unsigned int ElementCount; + + virtual bool IsMatch(const void *id1, const void *id2) const; +}; + +// A vector is an array with extra operations. +class PVector : public PArray +{ + DECLARE_CLASS(PVector, PArray); + HAS_OBJECT_POINTERS; +}; + +class PDynArray : public PCompoundType +{ + DECLARE_CLASS(PDynArray, PCompoundType); + HAS_OBJECT_POINTERS; +public: + PType *ElementType; + + virtual bool IsMatch(const void *id1, const void *id2) const; +}; + +class PMap : public PCompoundType +{ + DECLARE_CLASS(PMap, PCompoundType); + HAS_OBJECT_POINTERS; +public: + PType *KeyType; + PType *ValueType; + + virtual bool IsMatch(const void *id1, const void *id2) const; +}; + +class PStruct : public PNamedType +{ + DECLARE_CLASS(PStruct, PNamedType); +public: + TArray Fields; + + size_t PropagateMark(); +}; + +class PPrototype : public PCompoundType +{ + DECLARE_CLASS(PPrototype, PCompoundType); +public: + TArray ArgumentTypes; + TArray ReturnTypes; + + size_t PropagateMark(); + virtual bool IsMatch(const void *id1, const void *id2) const; +}; + +// TBD: Should we support overloading? +class PFunction : public PNamedType +{ + DECLARE_CLASS(PFunction, PNamedType); +public: + struct Variant + { + PPrototype *Proto; + VMFunction *Implementation; + }; + TArray Variants; + + size_t PropagateMark(); +}; + // Meta-info for every class derived from DObject --------------------------- -class PClass : public DObject +class PClassClass; +class PClass : public PStruct { - DECLARE_CLASS(PClass, DObject); + DECLARE_CLASS(PClass, PStruct); HAS_OBJECT_POINTERS; protected: virtual void Derive(PClass *newclass); + // We unravel _WITH_META here just as we did for PType. + enum { MetaClassNum = CLASSREG_PClassClass }; public: - static void StaticInit (); - static void StaticShutdown (); + typedef PClassClass MetaClass; + MetaClass *GetClass() const; + + static void StaticInit(); + static void StaticShutdown(); + static void StaticBootstrap(); // Per-class information ------------------------------------- - FName TypeName; // this class's name - unsigned int Size; // this class's size PClass *ParentClass; // the class this class derives from const size_t *Pointers; // object pointers defined by this class *only* const size_t *FlatPointers; // object pointers defined by this class and all its superclasses; not initialized by default - PClass *HashNext; BYTE *Defaults; bool bRuntimeClass; // class was defined at run-time, not compile-time - unsigned short ClassIndex; PSymbolTable Symbols; void (*ConstructNative)(void *); @@ -169,17 +415,17 @@ public: // The rest are all functions and static data ---------------- PClass(); ~PClass(); - void InsertIntoHash (); - DObject *CreateNew () const; - PClass *CreateDerivedClass (FName name, unsigned int size); + void InsertIntoHash(); + DObject *CreateNew() const; + PClass *CreateDerivedClass(FName name, unsigned int size); unsigned int Extend(unsigned int extension); - void InitializeActorInfo (); - void BuildFlatPointers (); + void InitializeActorInfo(); + void BuildFlatPointers(); const PClass *NativeClass() const; size_t PropagateMark(); // Returns true if this type is an ancestor of (or same as) the passed type. - bool IsAncestorOf (const PClass *ti) const + bool IsAncestorOf(const PClass *ti) const { while (ti) { @@ -189,29 +435,70 @@ public: } return false; } - inline bool IsDescendantOf (const PClass *ti) const + inline bool IsDescendantOf(const PClass *ti) const { - return ti->IsAncestorOf (this); + return ti->IsAncestorOf(this); } // Find a type, given its name. - static PClass *FindClass (const char *name) { return FindClass (FName (name, true)); } - static PClass *FindClass (const FString &name) { return FindClass (FName (name, true)); } - static PClass *FindClass (ENamedName name) { return FindClass (FName (name)); } - static PClass *FindClass (FName name); - static PClassActor *FindActor (const char *name) { return FindActor (FName (name, true)); } - static PClassActor *FindActor (const FString &name) { return FindActor (FName (name, true)); } - static PClassActor *FindActor (ENamedName name) { return FindActor (FName (name)); } - static PClassActor *FindActor (FName name); - PClass *FindClassTentative (FName name); // not static! + static PClass *FindClass(const char *name) { return FindClass(FName(name, true)); } + static PClass *FindClass(const FString &name) { return FindClass(FName(name, true)); } + static PClass *FindClass(ENamedName name) { return FindClass(FName(name)); } + static PClass *FindClass(FName name); + static PClassActor *FindActor(const char *name) { return FindActor(FName(name, true)); } + static PClassActor *FindActor(const FString &name) { return FindActor(FName(name, true)); } + static PClassActor *FindActor(ENamedName name) { return FindActor(FName(name)); } + static PClassActor *FindActor(FName name); + PClass *FindClassTentative(FName name); // not static! - static TArray m_Types; - static TArray m_RuntimeActors; - - enum { HASH_SIZE = 256 }; - static PClass *TypeHash[HASH_SIZE]; + static TArray AllClasses; static bool bShutdown; }; +class PClassType : public PClass +{ + DECLARE_CLASS(PClassType, PClass); +protected: + virtual void Derive(PClass *newclass); +public: + PClassType(); + + PClass *TypeTableType; // The type to use for hashing into the type table +}; + +inline PType::MetaClass *PType::GetClass() const +{ + return static_cast(DObject::GetClass()); +} + +class PClassClass : public PClassType +{ + DECLARE_CLASS(PClassClass, PClassType); +public: + PClassClass(); +}; + +inline PClass::MetaClass *PClass::GetClass() const +{ + return static_cast(DObject::GetClass()); +} + +// Type tables -------------------------------------------------------------- + +struct FTypeTable +{ + enum { HASH_SIZE = 1021 }; + + PType *TypeHash[HASH_SIZE]; + + PType *FindType(PClass *metatype, void *parm1, void *parm2, size_t *bucketnum); + void AddType(PType *type, PClass *metatype, void *parm1, void *parm2, size_t bucket); + + static size_t Hash(void *p1, void *p2, void *p3); +}; + + +extern FTypeTable TypeTable; + #endif diff --git a/src/farchive.cpp b/src/farchive.cpp index 3920479e7e..6947365832 100644 --- a/src/farchive.cpp +++ b/src/farchive.cpp @@ -637,12 +637,8 @@ FArchive::FArchive (FFile &file) void FArchive::AttachToFile (FFile &file) { - unsigned int i; - m_HubTravel = false; m_File = &file; - m_MaxObjectCount = m_ObjectCount = 0; - m_ObjectMap = NULL; if (file.Mode() == FFile::EReading) { m_Loading = true; @@ -654,19 +650,13 @@ void FArchive::AttachToFile (FFile &file) m_Storing = true; } m_Persistent = file.IsPersistent(); - m_TypeMap = NULL; - m_TypeMap = new TypeMap[PClass::m_Types.Size()]; - for (i = 0; i < PClass::m_Types.Size(); i++) - { - m_TypeMap[i].toArchive = TypeMap::NO_INDEX; - m_TypeMap[i].toCurrent = NULL; - } - m_ClassCount = 0; - for (i = 0; i < EObjectHashSize; i++) - { - m_ObjectHash[i] = ~0; - m_NameHash[i] = NameMap::NO_INDEX; - } + + ClassToArchive.Clear(); + ArchiveToClass.Clear(); + + ObjectToArchive.Clear(); + ArchiveToObject.Clear(); + m_NumSprites = 0; m_SpriteMap = new int[sprites.Size()]; for (size_t s = 0; s < sprites.Size(); ++s) @@ -678,10 +668,6 @@ void FArchive::AttachToFile (FFile &file) FArchive::~FArchive () { Close (); - if (m_TypeMap) - delete[] m_TypeMap; - if (m_ObjectMap) - M_Free (m_ObjectMap); if (m_SpriteMap) delete[] m_SpriteMap; } @@ -702,7 +688,7 @@ void FArchive::Close () { m_File->Close (); m_File = NULL; - DPrintf ("Processed %u objects\n", m_ObjectCount); + DPrintf ("Processed %u objects\n", ArchiveToObject.Size()); } } @@ -1044,6 +1030,7 @@ FArchive &FArchive::WriteObject (DObject *obj) else { PClass *type = obj->GetClass(); + DWORD *classarcid; if (type == RUNTIME_CLASS(DObject)) { @@ -1052,7 +1039,7 @@ FArchive &FArchive::WriteObject (DObject *obj) id[0] = NULL_OBJ; Write (id, 1); } - else if (m_TypeMap[type->ClassIndex].toArchive == TypeMap::NO_INDEX) + else if (NULL == (classarcid = ClassToArchive.CheckKey(type))) { // No instances of this class have been written out yet. // Write out the class, then write out the object. If this @@ -1085,9 +1072,9 @@ FArchive &FArchive::WriteObject (DObject *obj) // to the saved object. Otherwise, save a reference to the // class, then save the object. Again, if this is a player- // controlled actor, remember that. - DWORD index = FindObjectIndex (obj); + DWORD *objarcid = ObjectToArchive.CheckKey(obj); - if (index == TypeMap::NO_INDEX) + if (objarcid == NULL) { if (obj->IsKindOf (RUNTIME_CLASS (AActor)) && @@ -1103,7 +1090,7 @@ FArchive &FArchive::WriteObject (DObject *obj) id[0] = NEW_OBJ; Write (id, 1); } - WriteCount (m_TypeMap[type->ClassIndex].toArchive); + WriteCount (*classarcid); // Printf ("Reuse class %s (%u)\n", type->Name, m_File->Tell()); MapObject (obj); obj->SerializeUserVars (*this); @@ -1114,7 +1101,7 @@ FArchive &FArchive::WriteObject (DObject *obj) { id[0] = OLD_OBJ; Write (id, 1); - WriteCount (index); + WriteCount (*objarcid); } } } @@ -1141,12 +1128,12 @@ FArchive &FArchive::ReadObject (DObject* &obj, PClass *wanttype) break; case OLD_OBJ: - index = ReadCount (); - if (index >= m_ObjectCount) + index = ReadCount(); + if (index >= ArchiveToObject.Size()) { - I_Error ("Object reference too high (%u; max is %u)\n", index, m_ObjectCount); + I_Error ("Object reference too high (%u; max is %u)\n", index, ArchiveToObject.Size()); } - obj = (DObject *)m_ObjectMap[index].object; + obj = ArchiveToObject[index]; break; case NEW_PLYR_CLS_OBJ: @@ -1363,19 +1350,14 @@ DWORD FArchive::FindName (const char *name, unsigned int bucket) const DWORD FArchive::WriteClass (PClass *info) { - if (m_ClassCount >= PClass::m_Types.Size()) - { - I_Error ("Too many unique classes have been written.\nOnly %u were registered\n", - PClass::m_Types.Size()); - } - if (m_TypeMap[info->ClassIndex].toArchive != TypeMap::NO_INDEX) + if (ClassToArchive.CheckKey(info) != NULL) { I_Error ("Attempt to write '%s' twice.\n", info->TypeName.GetChars()); } - m_TypeMap[info->ClassIndex].toArchive = m_ClassCount; - m_TypeMap[m_ClassCount].toCurrent = info; + DWORD index = ArchiveToClass.Push(info); + ClassToArchive[info] = index; WriteString (info->TypeName.GetChars()); - return m_ClassCount++; + return index; } PClass *FArchive::ReadClass () @@ -1386,24 +1368,15 @@ PClass *FArchive::ReadClass () char *val; } typeName; - if (m_ClassCount >= PClass::m_Types.Size()) - { - I_Error ("Too many unique classes have been read.\nOnly %u were registered\n", - PClass::m_Types.Size()); - } operator<< (typeName.val); FName zaname(typeName.val, true); if (zaname != NAME_None) { - for (unsigned int i = PClass::m_Types.Size(); i-- > 0; ) + PClass *type = PClass::FindClass(zaname); + if (type != NULL) { - if (PClass::m_Types[i]->TypeName == zaname) - { - m_TypeMap[i].toArchive = m_ClassCount; - m_TypeMap[m_ClassCount].toCurrent = PClass::m_Types[i]; - m_ClassCount++; - return PClass::m_Types[i]; - } + ClassToArchive[type] = ArchiveToClass.Push(type); + return type; } } I_Error ("Unknown class '%s'\n", typeName.val); @@ -1425,11 +1398,7 @@ PClass *FArchive::ReadClass (const PClass *wanttype) PClass *FArchive::ReadStoredClass (const PClass *wanttype) { DWORD index = ReadCount (); - if (index >= m_ClassCount) - { - I_Error ("Class reference too high (%u; max is %u)\n", index, m_ClassCount); - } - PClass *type = m_TypeMap[index].toCurrent; + PClass *type = ArchiveToClass[index]; if (!type->IsDescendantOf (wanttype)) { I_Error ("Expected to extract an object of type '%s'.\n" @@ -1439,44 +1408,11 @@ PClass *FArchive::ReadStoredClass (const PClass *wanttype) return type; } -DWORD FArchive::MapObject (const DObject *obj) +DWORD FArchive::MapObject (DObject *obj) { - DWORD i; - - if (m_ObjectCount >= m_MaxObjectCount) - { - m_MaxObjectCount = m_MaxObjectCount ? m_MaxObjectCount * 2 : 1024; - m_ObjectMap = (ObjectMap *)M_Realloc (m_ObjectMap, sizeof(ObjectMap)*m_MaxObjectCount); - for (i = m_ObjectCount; i < m_MaxObjectCount; i++) - { - m_ObjectMap[i].hashNext = ~0; - m_ObjectMap[i].object = NULL; - } - } - - DWORD index = m_ObjectCount++; - DWORD hash = HashObject (obj); - - m_ObjectMap[index].object = obj; - m_ObjectMap[index].hashNext = m_ObjectHash[hash]; - m_ObjectHash[hash] = index; - - return index; -} - -DWORD FArchive::HashObject (const DObject *obj) const -{ - return (DWORD)((size_t)obj % EObjectHashSize); -} - -DWORD FArchive::FindObjectIndex (const DObject *obj) const -{ - DWORD index = m_ObjectHash[HashObject (obj)]; - while (index != TypeMap::NO_INDEX && m_ObjectMap[index].object != obj) - { - index = m_ObjectMap[index].hashNext; - } - return index; + DWORD i = ArchiveToObject.Push(obj); + ObjectToArchive[obj] = i; + return i; } void FArchive::UserWriteClass (PClass *type) @@ -1490,7 +1426,8 @@ void FArchive::UserWriteClass (PClass *type) } else { - if (m_TypeMap[type->ClassIndex].toArchive == TypeMap::NO_INDEX) + DWORD *arcid; + if (NULL == (arcid = ClassToArchive.CheckKey(type))) { id = 1; Write (&id, 1); @@ -1500,7 +1437,7 @@ void FArchive::UserWriteClass (PClass *type) { id = 0; Write (&id, 1); - WriteCount (m_TypeMap[type->ClassIndex].toArchive); + WriteCount (*arcid); } } } diff --git a/src/farchive.h b/src/farchive.h index e994e6d569..32e3b4b6f5 100644 --- a/src/farchive.h +++ b/src/farchive.h @@ -209,13 +209,11 @@ inline FArchive& operator<< (DObject* &object) { return ReadObject (object, RUN protected: enum { EObjectHashSize = 137 }; - DWORD FindObjectIndex (const DObject *obj) const; - DWORD MapObject (const DObject *obj); + DWORD MapObject (DObject *obj); DWORD WriteClass (PClass *info); PClass *ReadClass (); PClass *ReadClass (const PClass *wanttype); PClass *ReadStoredClass (const PClass *wanttype); - DWORD HashObject (const DObject *obj) const; DWORD AddName (const char *name); DWORD AddName (unsigned int start); // Name has already been added to storage DWORD FindName (const char *name) const; @@ -226,24 +224,12 @@ protected: bool m_Storing; // inserting objects? bool m_HubTravel; // travelling inside a hub? FFile *m_File; // unerlying file object - DWORD m_ObjectCount; // # of objects currently serialized - DWORD m_MaxObjectCount; - DWORD m_ClassCount; // # of unique classes currently serialized - struct TypeMap - { - PClass *toCurrent; // maps archive type index to execution type index - DWORD toArchive; // maps execution type index to archive type index + TMap ClassToArchive; // Maps PClass to archive type index + TArray ArchiveToClass; // Maps archive type index to PClass - enum { NO_INDEX = 0xffffffff }; - } *m_TypeMap; - - struct ObjectMap - { - const DObject *object; - DWORD hashNext; - } *m_ObjectMap; - DWORD m_ObjectHash[EObjectHashSize]; + TMap ObjectToArchive; // Maps objects to archive index + TArray ArchiveToObject; // Maps archive index to objects struct NameMap { diff --git a/src/g_shared/a_keys.cpp b/src/g_shared/a_keys.cpp index 064f1e1ecf..2a2bdca067 100644 --- a/src/g_shared/a_keys.cpp +++ b/src/g_shared/a_keys.cpp @@ -309,27 +309,27 @@ static void ParseLock(FScanner &sc) static void ClearLocks() { unsigned int i; - for(i=0;iIsDescendantOf(RUNTIME_CLASS(AKey))) + if (PClassActor::AllActorClasses[i]->IsDescendantOf(RUNTIME_CLASS(AKey))) { - AKey *key = static_cast(GetDefaultByType(PClass::m_Types[i])); + AKey *key = static_cast(GetDefaultByType(PClassActor::AllActorClasses[i])); if (key != NULL) { key->KeyNumber = 0; } } } - for(i=0;i<256;i++) + for(i = 0; i < 256; i++) { - if (locks[i]!=NULL) + if (locks[i] != NULL) { delete locks[i]; - locks[i]=NULL; + locks[i] = NULL; } } - currentnumber=0; - keysdone=false; + currentnumber = 0; + keysdone = false; } //=========================================================================== diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index f877de77bd..e4842b3ada 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -1643,9 +1643,9 @@ AInventory *ABackpackItem::CreateCopy (AActor *other) { // Find every unique type of ammo. Give it to the player if // he doesn't have it already, and double its maximum capacity. - for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - PClass *type = PClass::m_Types[i]; + PClass *type = PClassActor::AllActorClasses[i]; if (type->ParentClass == RUNTIME_CLASS(AAmmo)) { diff --git a/src/g_shared/a_weapons.cpp b/src/g_shared/a_weapons.cpp index 97b4388534..326b823237 100644 --- a/src/g_shared/a_weapons.cpp +++ b/src/g_shared/a_weapons.cpp @@ -1119,9 +1119,9 @@ void FWeaponSlots::AddExtraWeapons() } // Append extra weapons to the slots. - for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - PClass *cls = PClass::m_Types[i]; + PClass *cls = PClassActor::AllActorClasses[i]; if (!cls->IsDescendantOf(RUNTIME_CLASS(AWeapon))) { @@ -1569,9 +1569,9 @@ void P_SetupWeapons_ntohton() cls = NULL; Weapons_ntoh.Push(cls); // Index 0 is always NULL. - for (i = 0; i < PClass::m_Types.Size(); ++i) + for (i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - PClass *cls = PClass::m_Types[i]; + PClassActor *cls = PClassActor::AllActorClasses[i]; if (cls->IsDescendantOf(RUNTIME_CLASS(AWeapon))) { diff --git a/src/g_shared/sbarinfo_commands.cpp b/src/g_shared/sbarinfo_commands.cpp index 08086e62c9..61c44cc276 100644 --- a/src/g_shared/sbarinfo_commands.cpp +++ b/src/g_shared/sbarinfo_commands.cpp @@ -2161,7 +2161,7 @@ class CommandPlayerClass : public SBarInfoCommandFlowControl if(statusBar->CPlayer->cls == NULL) return; //No class so we can not continue - int spawnClass = statusBar->CPlayer->cls->ClassIndex; + PClass *spawnClass = statusBar->CPlayer->cls; for(unsigned int i = 0;i < classes.Size();i++) { if(classes[i] == spawnClass) @@ -2179,7 +2179,7 @@ class CommandPlayerClass : public SBarInfoCommandFlowControl if(stricmp(sc.String, PlayerClasses[c].Type->DisplayName) == 0) { foundClass = true; - classes.Push(PlayerClasses[c].Type->ClassIndex); + classes.Push(PlayerClasses[c].Type); break; } } @@ -2192,7 +2192,7 @@ class CommandPlayerClass : public SBarInfoCommandFlowControl SBarInfoCommandFlowControl::Parse(sc, fullScreenOffsets); } protected: - TArray classes; + TArray classes; }; //////////////////////////////////////////////////////////////////////////////// diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp index a8d570605c..8ab2fd3aa0 100644 --- a/src/g_shared/shared_hud.cpp +++ b/src/g_shared/shared_hud.cpp @@ -327,9 +327,9 @@ static int STACK_ARGS ktcmp(const void * a, const void * b) static void SetKeyTypes() { - for(unsigned int i = 0; i < PClass::m_Types.Size(); i++) + for(unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); i++) { - PClass *ti = PClass::m_Types[i]; + PClass *ti = PClassActor::AllActorClasses[i]; if (ti->IsDescendantOf(RUNTIME_CLASS(AKey))) { diff --git a/src/info.cpp b/src/info.cpp index 5804a78576..1b67189cf9 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -53,6 +53,8 @@ extern void LoadActors (); +TArray PClassActor::AllActorClasses; + bool FState::CallAction(AActor *self, AActor *stateowner, StateCallData *statecall) { if (ActionFunc != NULL) @@ -151,9 +153,9 @@ void PClassActor::StaticSetActorNums() memset(SpawnableThings, 0, sizeof(SpawnableThings)); DoomEdMap.Empty(); - for (unsigned int i = 0; i < PClass::m_RuntimeActors.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - static_cast(PClass::m_RuntimeActors[i])->RegisterIDs(); + static_cast(PClassActor::AllActorClasses[i])->RegisterIDs(); } } @@ -195,6 +197,9 @@ PClassActor::PClassActor() ExplosionRadius = -1; MissileHeight = 32*FRACUNIT; MeleeDamage = 0; + + // Record this in the master list. + AllActorClasses.Push(this); } //========================================================================== @@ -308,7 +313,6 @@ void PClassActor::InitializeNativeDefaults() { memset (Defaults, 0, Size); } - m_RuntimeActors.Push(this); } //========================================================================== @@ -585,7 +589,7 @@ static int STACK_ARGS sortnums (const void *a, const void *b) void FDoomEdMap::DumpMapThings () { - TArray infos (PClass::m_Types.Size()); + TArray infos (PClassActor::AllActorClasses.Size()); int i; for (i = 0; i < DOOMED_HASHSIZE; ++i) diff --git a/src/info.h b/src/info.h index a6f37771ce..54ff8eb636 100644 --- a/src/info.h +++ b/src/info.h @@ -194,6 +194,9 @@ public: FSoundID MeleeSound; FName MissileName; fixed_t MissileHeight; + + // For those times when being able to scan every kind of actor is convenient + static TArray AllActorClasses; }; inline PClassActor *PClass::FindActor(FName name) diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index 8a04be64e1..64f2c4535b 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -603,7 +603,7 @@ void cht_Give (player_t *player, const char *name, int amount) { bool giveall; int i; - PClass *type; + PClassActor *type; if (player != &players[consoleplayer]) Printf ("%s is a cheater: give %s\n", player->userinfo.netname, name); @@ -648,7 +648,7 @@ void cht_Give (player_t *player, const char *name, int amount) if (giveall || stricmp (name, "backpack") == 0) { // Select the correct type of backpack based on the game - type = PClass::FindClass(gameinfo.backpacktype); + type = PClass::FindActor(gameinfo.backpacktype); if (type != NULL) { GiveSpawner (player, static_cast(type), 1); @@ -662,9 +662,9 @@ void cht_Give (player_t *player, const char *name, int amount) { // Find every unique type of ammo. Give it to the player if // he doesn't have it already, and set each to its maximum. - for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - PClass *type = PClass::m_Types[i]; + PClassActor *type = PClassActor::AllActorClasses[i]; if (type->ParentClass == RUNTIME_CLASS(AAmmo)) { @@ -719,14 +719,14 @@ void cht_Give (player_t *player, const char *name, int amount) if (giveall || stricmp (name, "keys") == 0) { - for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - if (PClass::m_Types[i]->IsDescendantOf (RUNTIME_CLASS(AKey))) + if (PClassActor::AllActorClasses[i]->IsDescendantOf (RUNTIME_CLASS(AKey))) { - AKey *key = (AKey *)GetDefaultByType (PClass::m_Types[i]); + AKey *key = (AKey *)GetDefaultByType (PClassActor::AllActorClasses[i]); if (key->KeyNumber != 0) { - key = static_cast(Spawn(static_cast(PClass::m_Types[i]), 0,0,0, NO_REPLACE)); + key = static_cast(Spawn(static_cast(PClassActor::AllActorClasses[i]), 0,0,0, NO_REPLACE)); if (!key->CallTryPickup (player->mo)) { key->Destroy (); @@ -741,9 +741,9 @@ void cht_Give (player_t *player, const char *name, int amount) if (giveall || stricmp (name, "weapons") == 0) { AWeapon *savedpending = player->PendingWeapon; - for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - type = PClass::m_Types[i]; + type = PClassActor::AllActorClasses[i]; // Don't give replaced weapons unless the replacement was done by Dehacked. if (type != RUNTIME_CLASS(AWeapon) && type->IsDescendantOf (RUNTIME_CLASS(AWeapon)) && @@ -772,9 +772,9 @@ void cht_Give (player_t *player, const char *name, int amount) if (giveall || stricmp (name, "artifacts") == 0) { - for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - type = PClass::m_Types[i]; + type = PClassActor::AllActorClasses[i]; if (type->IsDescendantOf (RUNTIME_CLASS(AInventory))) { AInventory *def = (AInventory*)GetDefaultByType (type); @@ -793,9 +793,9 @@ void cht_Give (player_t *player, const char *name, int amount) if (giveall || stricmp (name, "puzzlepieces") == 0) { - for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - type = PClass::m_Types[i]; + type = PClassActor::AllActorClasses[i]; if (type->IsDescendantOf (RUNTIME_CLASS(APuzzleItem))) { AInventory *def = (AInventory*)GetDefaultByType (type); @@ -812,7 +812,7 @@ void cht_Give (player_t *player, const char *name, int amount) if (giveall) return; - type = PClass::FindClass (name); + type = PClass::FindActor(name); if (type == NULL || !type->IsDescendantOf (RUNTIME_CLASS(AInventory))) { if (player == &players[consoleplayer]) @@ -872,9 +872,9 @@ void cht_Take (player_t *player, const char *name, int amount) if (takeall || stricmp (name, "backpack") == 0) { // Take away all types of backpacks the player might own. - for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - PClass *type = PClass::m_Types[i]; + PClass *type = PClassActor::AllActorClasses[i]; if (type->IsDescendantOf(RUNTIME_CLASS (ABackpackItem))) { @@ -891,9 +891,9 @@ void cht_Take (player_t *player, const char *name, int amount) if (takeall || stricmp (name, "ammo") == 0) { - for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - PClass *type = PClass::m_Types[i]; + PClass *type = PClassActor::AllActorClasses[i]; if (type->ParentClass == RUNTIME_CLASS (AAmmo)) { @@ -910,9 +910,9 @@ void cht_Take (player_t *player, const char *name, int amount) if (takeall || stricmp (name, "armor") == 0) { - for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - type = PClass::m_Types[i]; + type = PClassActor::AllActorClasses[i]; if (type->IsDescendantOf (RUNTIME_CLASS (AArmor))) { @@ -929,9 +929,9 @@ void cht_Take (player_t *player, const char *name, int amount) if (takeall || stricmp (name, "keys") == 0) { - for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - type = PClass::m_Types[i]; + type = PClassActor::AllActorClasses[i]; if (type->IsDescendantOf (RUNTIME_CLASS (AKey))) { @@ -948,9 +948,9 @@ void cht_Take (player_t *player, const char *name, int amount) if (takeall || stricmp (name, "weapons") == 0) { - for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - type = PClass::m_Types[i]; + type = PClassActor::AllActorClasses[i]; if (type != RUNTIME_CLASS(AWeapon) && type->IsDescendantOf (RUNTIME_CLASS (AWeapon))) @@ -973,9 +973,9 @@ void cht_Take (player_t *player, const char *name, int amount) if (takeall || stricmp (name, "artifacts") == 0) { - for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - type = PClass::m_Types[i]; + type = PClassActor::AllActorClasses[i]; if (type->IsDescendantOf (RUNTIME_CLASS (AInventory))) { @@ -999,9 +999,9 @@ void cht_Take (player_t *player, const char *name, int amount) if (takeall || stricmp (name, "puzzlepieces") == 0) { - for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - type = PClass::m_Types[i]; + type = PClassActor::AllActorClasses[i]; if (type->IsDescendantOf (RUNTIME_CLASS (APuzzleItem))) { diff --git a/src/namedef.h b/src/namedef.h index a95b4b5a00..56c80ff087 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -5,6 +5,8 @@ xx(Null) xx(Super) xx(Object) xx(Actor) +xx(Class) +xx(ClassClass) xx(Untranslated) diff --git a/src/p_states.cpp b/src/p_states.cpp index 25fd73f700..ecbb3d05fc 100644 --- a/src/p_states.cpp +++ b/src/p_states.cpp @@ -119,9 +119,9 @@ FArchive &operator<< (FArchive &arc, FState *&state) PClassActor *FState::StaticFindStateOwner (const FState *state) { - for (unsigned int i = 0; i < PClass::m_RuntimeActors.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - PClassActor *info = PClass::m_RuntimeActors[i]; + PClassActor *info = PClassActor::AllActorClasses[i]; if (state >= info->OwnedStates && state < info->OwnedStates + info->NumOwnedStates) { @@ -966,9 +966,9 @@ void DumpStateHelper(FStateLabels *StateList, const FString &prefix) CCMD(dumpstates) { - for (unsigned int i = 0; i < PClass::m_RuntimeActors.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - PClassActor *info = PClass::m_RuntimeActors[i]; + PClassActor *info = PClassActor::AllActorClasses[i]; Printf(PRINT_LOG, "State labels for %s\n", info->TypeName.GetChars()); DumpStateHelper(info->StateList, ""); Printf(PRINT_LOG, "----------------------------\n"); diff --git a/src/p_user.cpp b/src/p_user.cpp index b3973a8fa7..acaaf28a9b 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -810,14 +810,14 @@ void APlayerPawn::CheckWeaponSwitch(const PClass *ammotype) void APlayerPawn::GiveDeathmatchInventory() { - for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - if (PClass::m_Types[i]->IsDescendantOf (RUNTIME_CLASS(AKey))) + if (PClassActor::AllActorClasses[i]->IsDescendantOf (RUNTIME_CLASS(AKey))) { - AKey *key = (AKey *)GetDefaultByType (PClass::m_Types[i]); + AKey *key = (AKey *)GetDefaultByType (PClassActor::AllActorClasses[i]); if (key->KeyNumber != 0) { - key = static_cast(Spawn(static_cast(PClass::m_Types[i]), 0,0,0, NO_REPLACE)); + key = static_cast(Spawn(static_cast(PClassActor::AllActorClasses[i]), 0,0,0, NO_REPLACE)); if (!key->CallTryPickup (this)) { key->Destroy (); diff --git a/src/tarray.h b/src/tarray.h index b325a640b6..cced36e4be 100644 --- a/src/tarray.h +++ b/src/tarray.h @@ -119,6 +119,22 @@ public: Most = 0; } } + // Check equality of two arrays + bool operator==(const TArray &other) const + { + if (Count != other.Count) + { + return false; + } + for (unsigned int i = 0; i < Count; ++i) + { + if (Array[i] != other.Array[i]) + { + return false; + } + } + return true; + } // Return a reference to an element T &operator[] (size_t index) const { diff --git a/src/thingdef/thingdef.cpp b/src/thingdef/thingdef.cpp index 4cc1b9bf73..08ca849b27 100644 --- a/src/thingdef/thingdef.cpp +++ b/src/thingdef/thingdef.cpp @@ -119,6 +119,8 @@ PClassActor *CreateNewActor(const FScriptPosition &sc, FName typeName, FName par ti = PClass::FindActor(typeName); if (ti == NULL) { + extern void DumpTypeTable(); + DumpTypeTable(); sc.Message(MSG_ERROR, "Unknown native actor '%s'", typeName.GetChars()); goto create; } @@ -319,12 +321,9 @@ static void FinishThingdef() } fclose(dump); - for (i = 0; i < PClass::m_Types.Size(); i++) + for (i = 0; i < PClassActor::AllActorClasses.Size(); i++) { - PClass * ti = PClass::m_Types[i]; - - // Skip non-actors - if (!ti->IsDescendantOf(RUNTIME_CLASS(AActor))) continue; + PClassActor *ti = PClassActor::AllActorClasses[i]; if (ti->Size == (unsigned)-1) { diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 9ff623a5ee..734e3e12b1 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -2490,7 +2490,7 @@ ExpEmit FxRandom::Emit(VMFunctionBuilder *build) sym = symfunc; RUNTIME_CLASS(AActor)->Symbols.AddSymbol(sym); } - assert(sym->SymbolType == SYM_VMFunction); + assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); assert(((PSymbolVMFunction *)sym)->Function != NULL); callfunc = ((PSymbolVMFunction *)sym)->Function; @@ -2595,7 +2595,7 @@ ExpEmit FxFRandom::Emit(VMFunctionBuilder *build) sym = symfunc; RUNTIME_CLASS(AActor)->Symbols.AddSymbol(sym); } - assert(sym->SymbolType == SYM_VMFunction); + assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); assert(((PSymbolVMFunction *)sym)->Function != NULL); callfunc = ((PSymbolVMFunction *)sym)->Function; @@ -2685,7 +2685,7 @@ ExpEmit FxRandom2::Emit(VMFunctionBuilder *build) sym = symfunc; RUNTIME_CLASS(AActor)->Symbols.AddSymbol(sym); } - assert(sym->SymbolType == SYM_VMFunction); + assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); assert(((PSymbolVMFunction *)sym)->Function != NULL); callfunc = ((PSymbolVMFunction *)sym)->Function; @@ -3503,7 +3503,7 @@ ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build) sym = symfunc; RUNTIME_CLASS(AActor)->Symbols.AddSymbol(sym); } - assert(sym->SymbolType == SYM_VMFunction); + assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); assert(((PSymbolVMFunction *)sym)->Function != NULL); callfunc = ((PSymbolVMFunction *)sym)->Function; @@ -3763,7 +3763,7 @@ ExpEmit FxClassTypeCast::Emit(VMFunctionBuilder *build) sym = symfunc; RUNTIME_CLASS(AActor)->Symbols.AddSymbol(sym); } - assert(sym->SymbolType == SYM_VMFunction); + assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); assert(((PSymbolVMFunction *)sym)->Function != NULL); callfunc = ((PSymbolVMFunction *)sym)->Function; @@ -3963,7 +3963,7 @@ ExpEmit FxMultiNameState::Emit(VMFunctionBuilder *build) sym = symfunc; RUNTIME_CLASS(AActor)->Symbols.AddSymbol(sym); } - assert(sym->SymbolType == SYM_VMFunction); + assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); assert(((PSymbolVMFunction *)sym)->Function != NULL); callfunc = ((PSymbolVMFunction *)sym)->Function;