diff --git a/src/actor.h b/src/actor.h index 05b1aa076..4016d447b 100644 --- a/src/actor.h +++ b/src/actor.h @@ -596,6 +596,7 @@ public: AActor &operator= (const AActor &other); ~AActor (); + virtual void Finalize(FStateDefinitions &statedef); virtual void OnDestroy() override; virtual void Serialize(FSerializer &arc) override; virtual void PostSerialize() override; diff --git a/src/d_net.cpp b/src/d_net.cpp index 93f6a621b..c38a7cefe 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -2638,7 +2638,7 @@ void Net_DoCommand (int type, BYTE **stream, int player) } for(i = 0; i < count; ++i) { - PClassWeapon *wpn = Net_ReadWeapon(stream); + PClassActor *wpn = Net_ReadWeapon(stream); players[pnum].weapons.AddSlot(slot, wpn, pnum == consoleplayer); } } @@ -2647,7 +2647,7 @@ void Net_DoCommand (int type, BYTE **stream, int player) case DEM_ADDSLOT: { int slot = ReadByte(stream); - PClassWeapon *wpn = Net_ReadWeapon(stream); + PClassActor *wpn = Net_ReadWeapon(stream); players[player].weapons.AddSlot(slot, wpn, player == consoleplayer); } break; @@ -2655,7 +2655,7 @@ void Net_DoCommand (int type, BYTE **stream, int player) case DEM_ADDSLOTDEFAULT: { int slot = ReadByte(stream); - PClassWeapon *wpn = Net_ReadWeapon(stream); + PClassActor *wpn = Net_ReadWeapon(stream); players[player].weapons.AddSlotDefault(slot, wpn, player == consoleplayer); } break; diff --git a/src/dobject.cpp b/src/dobject.cpp index 10b37f636..63c7bb688 100644 --- a/src/dobject.cpp +++ b/src/dobject.cpp @@ -397,6 +397,23 @@ size_t DObject::PropagateMark() GC::Mark((DObject **)((BYTE *)this + *offsets)); offsets++; } + + offsets = info->ArrayPointers; + if (offsets == NULL) + { + const_cast(info)->BuildArrayPointers(); + offsets = info->ArrayPointers; + } + while (*offsets != ~(size_t)0) + { + auto aray = (TArray*)((BYTE *)this + *offsets); + for (auto &p : *aray) + { + GC::Mark(&p); + } + offsets++; + } + return info->Size; } return 0; @@ -427,6 +444,28 @@ size_t DObject::PointerSubstitution (DObject *old, DObject *notOld) } offsets++; } + + offsets = info->ArrayPointers; + if (offsets == NULL) + { + const_cast(info)->BuildArrayPointers(); + offsets = info->ArrayPointers; + } + while (*offsets != ~(size_t)0) + { + auto aray = (TArray*)((BYTE *)this + *offsets); + for (auto &p : *aray) + { + if (p == old) + { + p = notOld; + changed++; + } + } + offsets++; + } + + return changed; } diff --git a/src/dobject.h b/src/dobject.h index 6b9b87c75..ef7560909 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -94,10 +94,7 @@ enum CLASSREG_PClass, CLASSREG_PClassActor, CLASSREG_PClassInventory, - CLASSREG_PClassWeapon, CLASSREG_PClassPlayerPawn, - CLASSREG_PClassType, - CLASSREG_PClassClass, }; struct ClassReg diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 958cd4275..54cc64675 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -65,6 +65,7 @@ EXTERN_CVAR(Bool, strictdecorate); // PUBLIC DATA DEFINITIONS ------------------------------------------------- +FMemArena FlatpointerArena; // stores the flat pointers because freeing them individually is rather messy. FNamespaceManager Namespaces; FTypeTable TypeTable; @@ -99,7 +100,7 @@ PPointer *TypeVoidPtr; // PRIVATE DATA DEFINITIONS ------------------------------------------------ -// A harmless non-NULL FlatPointer for classes without pointers. +// A harmless non-nullptr FlatPointer for classes without pointers. static const size_t TheEnd = ~(size_t)0; // CODE -------------------------------------------------------------------- @@ -118,7 +119,7 @@ void DumpTypeTable() { int len = 0; Printf("%4zu:", i); - for (PType *ty = TypeTable.TypeHash[i]; ty != NULL; ty = ty->HashNext) + for (PType *ty = TypeTable.TypeHash[i]; ty != nullptr; ty = ty->HashNext) { Printf(" -> %s", ty->DescriptiveName()); len++; @@ -150,52 +151,6 @@ void DumpTypeTable() Printf("Buckets of len %d: %d (%.2f%%)\n", j, lens[j], j!=0?double(lens[j])/used*100:-1.0); } -/* PClassType *************************************************************/ - -IMPLEMENT_CLASS(PClassType, false, false) - -//========================================================================== -// -// PClassType Constructor -// -//========================================================================== - -PClassType::PClassType() -: TypeTableType(NULL) -{ -} - -//========================================================================== -// -// PClassType :: DeriveData -// -//========================================================================== - -void PClassType::DeriveData(PClass *newclass) -{ - assert(newclass->IsKindOf(RUNTIME_CLASS(PClassType))); - Super::DeriveData(newclass); - static_cast(newclass)->TypeTableType = TypeTableType; -} - -/* PClassClass ************************************************************/ - -IMPLEMENT_CLASS(PClassClass, false, false) - -//========================================================================== -// -// PClassClass Constructor -// -// The only thing we want to do here is automatically set TypeTableType -// to PClass. -// -//========================================================================== - -PClassClass::PClassClass() -{ - TypeTableType = RUNTIME_CLASS(PClass); -} - /* PType ******************************************************************/ IMPLEMENT_CLASS(PType, true, true) @@ -211,7 +166,7 @@ IMPLEMENT_POINTERS_END //========================================================================== PType::PType(unsigned int size, unsigned int align) -: Size(size), Align(align), HashNext(NULL) +: Size(size), Align(align), HashNext(nullptr) { mDescriptiveName = "Type"; loadOp = OP_NOP; @@ -286,6 +241,10 @@ void PType::SetPointer(void *base, unsigned offset, TArray *stroffs) con { } +void PType::SetPointerArray(void *base, unsigned offset, TArray *stroffs) const +{ +} + //========================================================================== // // PType :: InitializeValue @@ -378,40 +337,10 @@ const char *PType::DescriptiveName() const // // PType :: StaticInit STATIC // -// Set up TypeTableType values for every PType child and create basic types. -// //========================================================================== void PType::StaticInit() { - // Add types to the global symbol table. - - // Set up TypeTable hash keys. - RUNTIME_CLASS(PErrorType)->TypeTableType = RUNTIME_CLASS(PErrorType); - RUNTIME_CLASS(PVoidType)->TypeTableType = RUNTIME_CLASS(PVoidType); - RUNTIME_CLASS(PInt)->TypeTableType = RUNTIME_CLASS(PInt); - RUNTIME_CLASS(PBool)->TypeTableType = RUNTIME_CLASS(PBool); - 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(PSpriteID)->TypeTableType = RUNTIME_CLASS(PSpriteID); - RUNTIME_CLASS(PTextureID)->TypeTableType = RUNTIME_CLASS(PTextureID); - RUNTIME_CLASS(PColor)->TypeTableType = RUNTIME_CLASS(PColor); - RUNTIME_CLASS(PPointer)->TypeTableType = RUNTIME_CLASS(PPointer); - RUNTIME_CLASS(PClassPointer)->TypeTableType = RUNTIME_CLASS(PClassPointer); - RUNTIME_CLASS(PEnum)->TypeTableType = RUNTIME_CLASS(PEnum); - RUNTIME_CLASS(PArray)->TypeTableType = RUNTIME_CLASS(PArray); - RUNTIME_CLASS(PResizableArray)->TypeTableType = RUNTIME_CLASS(PResizableArray); - RUNTIME_CLASS(PDynArray)->TypeTableType = RUNTIME_CLASS(PDynArray); - RUNTIME_CLASS(PMap)->TypeTableType = RUNTIME_CLASS(PMap); - RUNTIME_CLASS(PStruct)->TypeTableType = RUNTIME_CLASS(PStruct); - RUNTIME_CLASS(PNativeStruct)->TypeTableType = RUNTIME_CLASS(PNativeStruct); - RUNTIME_CLASS(PPrototype)->TypeTableType = RUNTIME_CLASS(PPrototype); - RUNTIME_CLASS(PClass)->TypeTableType = RUNTIME_CLASS(PClass); - RUNTIME_CLASS(PStatePointer)->TypeTableType = RUNTIME_CLASS(PStatePointer); - RUNTIME_CLASS(PStateLabel)->TypeTableType = RUNTIME_CLASS(PStateLabel); - // Create types and add them type the type table. TypeTable.AddType(TypeError = new PErrorType); TypeTable.AddType(TypeAuto = new PErrorType(2)); @@ -831,7 +760,7 @@ PBool::PBool() MemberOnly = false; // Override the default max set by PInt's constructor PSymbolConstNumeric *maxsym = static_cast(Symbols.FindSymbol(NAME_Max, false)); - assert(maxsym != NULL && maxsym->IsKindOf(RUNTIME_CLASS(PSymbolConstNumeric))); + assert(maxsym != nullptr && maxsym->IsKindOf(RUNTIME_CLASS(PSymbolConstNumeric))); maxsym->Value = 1; } @@ -1147,7 +1076,7 @@ bool PString::ReadValue(FSerializer &ar, const char *key, void *addr) const void PString::SetDefaultValue(void *base, unsigned offset, TArray *special) const { if (base != nullptr) new((BYTE *)base + offset) FString; - if (special != NULL) + if (special != nullptr) { special->Push(std::make_pair(this, offset)); } @@ -1415,7 +1344,7 @@ IMPLEMENT_POINTERS_END //========================================================================== PPointer::PPointer() -: PBasicType(sizeof(void *), alignof(void *)), PointedType(NULL), IsConst(false) +: PBasicType(sizeof(void *), alignof(void *)), PointedType(nullptr), IsConst(false) { mDescriptiveName = "NullPointer"; SetOps(); @@ -1442,8 +1371,9 @@ PPointer::PPointer(PType *pointsat, bool isconst) void PPointer::SetOps() { - storeOp = OP_SP; loadOp = (PointedType && PointedType->IsKindOf(RUNTIME_CLASS(PClass))) ? OP_LO : OP_LP; + // Non-destroyed thinkers are always guaranteed to be linked into the thinker chain so we don't need the write barrier for them. + storeOp = (loadOp == OP_LO && !static_cast(PointedType)->IsDescendantOf(RUNTIME_CLASS(DThinker))) ? OP_SO : OP_SP; moveOp = OP_MOVEA; RegType = REGT_POINTER; } @@ -1476,7 +1406,7 @@ void PPointer::GetTypeIDs(intptr_t &id1, intptr_t &id2) const //========================================================================== // -// PPointer :: SetDefaultValue +// PPointer :: SetPointer // //========================================================================== @@ -1497,13 +1427,18 @@ void PPointer::SetPointer(void *base, unsigned offset, TArray *special) void PPointer::WriteValue(FSerializer &ar, const char *key,const void *addr) const { - if (PointedType->IsKindOf(RUNTIME_CLASS(PClassClass))) + if (PointedType->IsKindOf(RUNTIME_CLASS(PClass))) { - ar(key, *(PClass **)addr); - } - else if (PointedType->IsKindOf(RUNTIME_CLASS(PClass))) - { - ar(key, *(DObject **)addr); + auto pt = static_cast(PointedType); + + if (pt->IsDescendantOf(RUNTIME_CLASS(PClass))) + { + ar(key, *(PClass **)addr); + } + else + { + ar(key, *(DObject **)addr); + } } else { @@ -1520,16 +1455,19 @@ void PPointer::WriteValue(FSerializer &ar, const char *key,const void *addr) con bool PPointer::ReadValue(FSerializer &ar, const char *key, void *addr) const { - if (PointedType->IsKindOf(RUNTIME_CLASS(PClassClass))) + if (PointedType->IsKindOf(RUNTIME_CLASS(PClass))) { - bool res = false; - ::Serialize(ar, key, *(PClass **)addr, (PClass**)nullptr); - return res; - } - else if (PointedType->IsKindOf(RUNTIME_CLASS(PClass))) - { - bool res = false; - ::Serialize(ar, key, *(DObject **)addr, nullptr, &res); + auto pt = static_cast(PointedType); + bool res = true; + + if (pt->IsDescendantOf(RUNTIME_CLASS(PClass))) + { + ::Serialize(ar, key, *(PClass **)addr, (PClass**)nullptr); + } + else + { + ::Serialize(ar, key, *(DObject **)addr, nullptr, &res); + } return res; } return false; @@ -1547,7 +1485,7 @@ PPointer *NewPointer(PType *type, bool isconst) { size_t bucket; PType *ptype = TypeTable.FindType(RUNTIME_CLASS(PPointer), (intptr_t)type, isconst ? 1 : 0, &bucket); - if (ptype == NULL) + if (ptype == nullptr) { ptype = new PPointer(type, isconst); TypeTable.AddType(ptype, RUNTIME_CLASS(PPointer), (intptr_t)type, isconst ? 1 : 0, bucket); @@ -1606,18 +1544,6 @@ IMPLEMENT_POINTERS_START(PClassPointer) IMPLEMENT_POINTER(ClassRestriction) IMPLEMENT_POINTERS_END -//========================================================================== -// -// PClassPointer - Default Constructor -// -//========================================================================== - -PClassPointer::PClassPointer() -: PPointer(RUNTIME_CLASS(PClass)), ClassRestriction(NULL) -{ - mDescriptiveName = "ClassPointer"; -} - //========================================================================== // // PClassPointer - Parameterized Constructor @@ -1629,6 +1555,10 @@ PClassPointer::PClassPointer(PClass *restrict) { if (restrict) mDescriptiveName.Format("ClassPointer<%s>", restrict->TypeName.GetChars()); else mDescriptiveName = "ClassPointer"; + // class pointers do not need write barriers because all classes are stored in the global type table and won't get collected. + // This means we can use the cheapoer non-barriered opcodes here. + loadOp = OP_LOS; + storeOp = OP_SP; } //========================================================================== @@ -1683,7 +1613,7 @@ PClassPointer *NewClassPointer(PClass *restrict) { size_t bucket; PType *ptype = TypeTable.FindType(RUNTIME_CLASS(PClassPointer), (intptr_t)RUNTIME_CLASS(PClass), (intptr_t)restrict, &bucket); - if (ptype == NULL) + if (ptype == nullptr) { ptype = new PClassPointer(restrict); TypeTable.AddType(ptype, RUNTIME_CLASS(PClassPointer), (intptr_t)RUNTIME_CLASS(PClass), (intptr_t)restrict, bucket); @@ -1739,7 +1669,7 @@ PEnum *NewEnum(FName name, PTypeBase *outer) size_t bucket; if (outer == nullptr) outer = Namespaces.GlobalNamespace; PType *etype = TypeTable.FindType(RUNTIME_CLASS(PEnum), (intptr_t)outer, (intptr_t)name, &bucket); - if (etype == NULL) + if (etype == nullptr) { etype = new PEnum(name, outer); TypeTable.AddType(etype, RUNTIME_CLASS(PEnum), (intptr_t)outer, (intptr_t)name, bucket); @@ -1762,7 +1692,7 @@ IMPLEMENT_POINTERS_END //========================================================================== PArray::PArray() -: ElementType(NULL), ElementCount(0) +: ElementType(nullptr), ElementCount(0) { mDescriptiveName = "Array"; } @@ -1902,7 +1832,7 @@ PArray *NewArray(PType *type, unsigned int count) { size_t bucket; PType *atype = TypeTable.FindType(RUNTIME_CLASS(PArray), (intptr_t)type, count, &bucket); - if (atype == NULL) + if (atype == nullptr) { atype = new PArray(type, count); TypeTable.AddType(atype, RUNTIME_CLASS(PArray), (intptr_t)type, count, bucket); @@ -1976,7 +1906,7 @@ PResizableArray *NewResizableArray(PType *type) { size_t bucket; PType *atype = TypeTable.FindType(RUNTIME_CLASS(PResizableArray), (intptr_t)type, 0, &bucket); - if (atype == NULL) + if (atype == nullptr) { atype = new PResizableArray(type); TypeTable.AddType(atype, RUNTIME_CLASS(PResizableArray), (intptr_t)type, 0, bucket); @@ -1999,7 +1929,7 @@ IMPLEMENT_POINTERS_END //========================================================================== PDynArray::PDynArray() -: ElementType(NULL) +: ElementType(nullptr) { mDescriptiveName = "DynArray"; Size = sizeof(FArray); @@ -2046,6 +1976,152 @@ void PDynArray::GetTypeIDs(intptr_t &id1, intptr_t &id2) const id2 = 0; } +//========================================================================== +// +// PDynArray :: InitializeValue +// +//========================================================================== + +void PDynArray::InitializeValue(void *addr, const void *deff) const +{ + const FArray *def = (const FArray*)deff; + FArray *aray = (FArray*)addr; + + if (def == nullptr || def->Count == 0) + { + // Empty arrays do not need construction. + *aray = { nullptr, 0, 0 }; + } + else if (ElementType->GetRegType() != REGT_STRING) + { + // These are just integral values which can be done without any constructor hackery. + size_t blocksize = ElementType->Size * def->Count; + aray->Array = M_Malloc(blocksize); + memcpy(aray->Array, def->Array, blocksize); + aray->Most = aray->Count = def->Count; + } + else + { + // non-empty string arrays require explicit construction. + new(addr) TArray(*(TArray*)def); + } +} + +//========================================================================== +// +// PDynArray :: DestroyValue +// +//========================================================================== + +void PDynArray::DestroyValue(void *addr) const +{ + FArray *aray = (FArray*)addr; + + if (aray->Array != nullptr) + { + if (ElementType->GetRegType() != REGT_STRING) + { + M_Free(aray->Array); + } + else + { + // Damn those cursed strings again. :( + ((TArray*)addr)->~TArray(); + } + } + aray->Count = aray->Most = 0; + aray->Array = nullptr; +} + +//========================================================================== +// +// PDynArray :: SetDefaultValue +// +//========================================================================== + +void PDynArray::SetDefaultValue(void *base, unsigned offset, TArray *special) const +{ + memset((char*)base + offset, 0, sizeof(FArray)); // same as constructing an empty array. + if (special != nullptr) + { + special->Push(std::make_pair(this, offset)); + } +} + +//========================================================================== +// +// PDynArray :: SetPointer +// +//========================================================================== + +void PDynArray::SetPointerArray(void *base, unsigned offset, TArray *special) const +{ + if (ElementType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast(ElementType)->PointedType->IsKindOf(RUNTIME_CLASS(PClass))) + { + // Add to the list of pointer arrays for this class. + special->Push(offset); + } +} + +//========================================================================== +// +// PDynArray :: WriteValue +// +//========================================================================== + +void PDynArray::WriteValue(FSerializer &ar, const char *key, const void *addr) const +{ + FArray *aray = (FArray*)addr; + if (aray->Count > 0) + { + if (ar.BeginArray(key)) + { + const BYTE *addrb = (const BYTE *)aray->Array; + for (unsigned i = 0; i < aray->Count; ++i) + { + ElementType->WriteValue(ar, nullptr, addrb); + addrb += ElementType->Size; + } + ar.EndArray(); + } + } +} + +//========================================================================== +// +// PDynArray :: ReadValue +// +//========================================================================== + +bool PDynArray::ReadValue(FSerializer &ar, const char *key, void *addr) const +{ + FArray *aray = (FArray*)addr; + DestroyValue(addr); // note that even after calling this we still got a validly constructed empty array. + + if (ar.BeginArray(key)) + { + bool readsomething = false; + unsigned count = ar.ArraySize(); + + size_t blocksize = ElementType->Size * count; + aray->Array = M_Malloc(blocksize); + memset(aray->Array, 0, blocksize); + aray->Most = aray->Count = count; + + BYTE *addrb = (BYTE *)aray->Array; + for (unsigned i = 0; iGetRegType() == REGT_STRING) new(addrb) FString; + readsomething |= ElementType->ReadValue(ar, nullptr, addrb); + addrb += ElementType->Size; + } + ar.EndArray(); + return readsomething; + } + return false; +} + //========================================================================== // // NewDynArray @@ -2059,7 +2135,7 @@ PDynArray *NewDynArray(PType *type) { size_t bucket; PType *atype = TypeTable.FindType(RUNTIME_CLASS(PDynArray), (intptr_t)type, 0, &bucket); - if (atype == NULL) + if (atype == nullptr) { FString backingname; @@ -2109,7 +2185,7 @@ IMPLEMENT_POINTERS_END //========================================================================== PMap::PMap() -: KeyType(NULL), ValueType(NULL) +: KeyType(nullptr), ValueType(nullptr) { mDescriptiveName = "Map"; Size = sizeof(FMap); @@ -2169,7 +2245,7 @@ PMap *NewMap(PType *keytype, PType *valuetype) { size_t bucket; PType *maptype = TypeTable.FindType(RUNTIME_CLASS(PMap), (intptr_t)keytype, (intptr_t)valuetype, &bucket); - if (maptype == NULL) + if (maptype == nullptr) { maptype = new PMap(keytype, valuetype); TypeTable.AddType(maptype, RUNTIME_CLASS(PMap), (intptr_t)keytype, (intptr_t)valuetype, bucket); @@ -2308,7 +2384,7 @@ bool PStruct::ReadFields(FSerializer &ar, void *addr) const foundsomething = true; const PSymbol *sym = Symbols.FindSymbol(FName(label, true), true); - if (sym == NULL) + if (sym == nullptr) { DPrintf(DMSG_ERROR, "Cannot find field %s in %s\n", label, TypeName.GetChars()); @@ -2332,7 +2408,7 @@ bool PStruct::ReadFields(FSerializer &ar, void *addr) const // PStruct :: AddField // // Appends a new field to the end of a struct. Returns either the new field -// or NULL if a symbol by that name already exists. +// or nullptr if a symbol by that name already exists. // //========================================================================== @@ -2350,10 +2426,10 @@ PField *PStruct::AddField(FName name, PType *type, DWORD flags) // its fields. Align = MAX(Align, type->Align); - if (Symbols.AddSymbol(field) == NULL) + if (Symbols.AddSymbol(field) == nullptr) { // name is already in use delete field; - return NULL; + return nullptr; } Fields.Push(field); @@ -2365,7 +2441,7 @@ PField *PStruct::AddField(FName name, PType *type, DWORD flags) // PStruct :: AddField // // Appends a new native field to the struct. Returns either the new field -// or NULL if a symbol by that name already exists. +// or nullptr if a symbol by that name already exists. // //========================================================================== @@ -2408,7 +2484,7 @@ PStruct *NewStruct(FName name, PTypeBase *outer) size_t bucket; if (outer == nullptr) outer = Namespaces.GlobalNamespace; PType *stype = TypeTable.FindType(RUNTIME_CLASS(PStruct), (intptr_t)outer, (intptr_t)name, &bucket); - if (stype == NULL) + if (stype == nullptr) { stype = new PStruct(name, outer); TypeTable.AddType(stype, RUNTIME_CLASS(PStruct), (intptr_t)outer, (intptr_t)name, bucket); @@ -2447,7 +2523,7 @@ PNativeStruct *NewNativeStruct(FName name, PTypeBase *outer) size_t bucket; if (outer == nullptr) outer = Namespaces.GlobalNamespace; PType *stype = TypeTable.FindType(RUNTIME_CLASS(PNativeStruct), (intptr_t)outer, (intptr_t)name, &bucket); - if (stype == NULL) + if (stype == nullptr) { stype = new PNativeStruct(name, outer); TypeTable.AddType(stype, RUNTIME_CLASS(PNativeStruct), (intptr_t)outer, (intptr_t)name, bucket); @@ -2466,7 +2542,7 @@ IMPLEMENT_CLASS(PField, false, false) //========================================================================== PField::PField() -: PSymbol(NAME_None), Offset(0), Type(NULL), Flags(0) +: PSymbol(NAME_None), Offset(0), Type(nullptr), Flags(0) { } @@ -2599,7 +2675,7 @@ PPrototype *NewPrototype(const TArray &rettypes, const TArray { size_t bucket; PType *proto = TypeTable.FindType(RUNTIME_CLASS(PPrototype), (intptr_t)&argtypes, (intptr_t)&rettypes, &bucket); - if (proto == NULL) + if (proto == nullptr) { proto = new PPrototype(rettypes, argtypes); TypeTable.AddType(proto, RUNTIME_CLASS(PPrototype), (intptr_t)&argtypes, (intptr_t)&rettypes, bucket); @@ -2689,7 +2765,7 @@ IMPLEMENT_POINTERS_END static void RecurseWriteFields(const PClass *type, FSerializer &ar, const void *addr) { - if (type != NULL) + if (type != nullptr) { RecurseWriteFields(type->ParentClass, ar, addr); // Don't write this part if it has no non-transient variables @@ -2773,7 +2849,7 @@ bool PClass::ReadAllFields(FSerializer &ar, void *addr) const { // Only read it if the type is related to this one. const PClass *parent; - for (parent = this; parent != NULL; parent = parent->ParentClass) + for (parent = this; parent != nullptr; parent = parent->ParentClass) { if (parent == type) { @@ -2835,7 +2911,7 @@ void PClass::StaticInit () FAutoSegIterator probe(CRegHead, CRegTail); - while (*++probe != NULL) + while (*++probe != nullptr) { ((ClassReg *)*probe)->RegisterClass (); } @@ -2859,16 +2935,12 @@ void PClass::StaticInit () // // PClass :: StaticShutdown STATIC // -// Frees FlatPointers belonging to all classes. Only really needed to avoid -// memory leak warnings at exit. +// Frees all static class data. // //========================================================================== void PClass::StaticShutdown () { - TArray uniqueFPs(64); - unsigned int i, j; - // delete all variables containing pointers to script functions. for (auto p : FunctionPtrList) { @@ -2876,7 +2948,8 @@ void PClass::StaticShutdown () } FunctionPtrList.Clear(); - // Make a full garbage collection here so that all destroyed but uncollected higher level objects that still exist can be properly taken down. + // Make a full garbage collection here so that all destroyed but uncollected higher level objects + // that still exist are properly taken down before the low level data is deleted. GC::FullGC(); // From this point onward no scripts may be called anymore because the data needed by the VM is getting deleted now. @@ -2886,34 +2959,15 @@ void PClass::StaticShutdown () // Unless something went wrong, anything left here should be class and type objects only, which do not own any scripts. TypeTable.Clear(); Namespaces.ReleaseSymbols(); + FlatpointerArena.FreeAllBlocks(); + bShutdown = true; - for (i = 0; i < PClass::AllClasses.Size(); ++i) + for (unsigned i = 0; i < PClass::AllClasses.Size(); ++i) { 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 - // duplicates and only delete those that are unique. - for (j = 0; j < uniqueFPs.Size(); ++j) - { - if (type->FlatPointers == uniqueFPs[j]) - { - break; - } - } - if (j == uniqueFPs.Size()) - { - uniqueFPs.Push(const_cast(type->FlatPointers)); - } - } type->Destroy(); } - for (i = 0; i < uniqueFPs.Size(); ++i) - { - delete[] uniqueFPs[i]; - } - bShutdown = true; AllClasses.Clear(); PClassActor::AllActorClasses.Clear(); @@ -2932,30 +2986,19 @@ void PClass::StaticShutdown () // // 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 *cls = new PClass; PClass::RegistrationInfo.SetupClass(cls); - // The PClassClass constructor initialized these to NULL, because the + // The PClassClass constructor initialized these to nullptr, 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(); } @@ -2971,6 +3014,7 @@ PClass::PClass() ParentClass = nullptr; Pointers = nullptr; FlatPointers = nullptr; + ArrayPointers = nullptr; HashNext = nullptr; Defaults = nullptr; bRuntimeClass = false; @@ -2990,10 +3034,10 @@ PClass::PClass() PClass::~PClass() { - if (Defaults != NULL) + if (Defaults != nullptr) { M_Free(Defaults); - Defaults = NULL; + Defaults = nullptr; } } @@ -3013,14 +3057,11 @@ PClass *ClassReg::RegisterClass() &PClass::RegistrationInfo, &PClassActor::RegistrationInfo, &PClassInventory::RegistrationInfo, - &PClassWeapon::RegistrationInfo, &PClassPlayerPawn::RegistrationInfo, - &PClassType::RegistrationInfo, - &PClassClass::RegistrationInfo, }; // Skip classes that have already been registered - if (MyClass != NULL) + if (MyClass != nullptr) { return MyClass; } @@ -3059,7 +3100,7 @@ PClass *ClassReg::RegisterClass() void ClassReg::SetupClass(PClass *cls) { - assert(MyClass == NULL); + assert(MyClass == nullptr); MyClass = cls; cls->TypeName = FName(Name+1); cls->Size = SizeOf; @@ -3082,7 +3123,7 @@ void PClass::InsertIntoHash () PType *found; found = TypeTable.FindType(RUNTIME_CLASS(PClass), 0, TypeName, &bucket); - if (found != NULL) + if (found != nullptr) { // This type has already been inserted I_Error("Tried to register class '%s' more than once.\n", TypeName.GetChars()); } @@ -3102,14 +3143,14 @@ void PClass::InsertIntoHash () const PClass *PClass::FindParentClass(FName name) const { - for (const PClass *type = this; type != NULL; type = type->ParentClass) + for (const PClass *type = this; type != nullptr; type = type->ParentClass) { if (type->TypeName == name) { return type; } } - return NULL; + return nullptr; } //========================================================================== @@ -3124,9 +3165,9 @@ PClass *PClass::FindClass (FName zaname) { if (zaname == NAME_None) { - return NULL; + return nullptr; } - return static_cast(TypeTable.FindType(RUNTIME_CLASS(PClass), 0, zaname, NULL)); + return static_cast(TypeTable.FindType(RUNTIME_CLASS(PClass), 0, zaname, nullptr)); } //========================================================================== @@ -3140,10 +3181,10 @@ PClass *PClass::FindClass (FName zaname) DObject *PClass::CreateNew() const { BYTE *mem = (BYTE *)M_Malloc (Size); - assert (mem != NULL); + assert (mem != nullptr); // Set this object's defaults before constructing it. - if (Defaults != NULL) + if (Defaults != nullptr) memcpy (mem, Defaults, Size); else memset (mem, 0, Size); @@ -3170,7 +3211,7 @@ void PClass::InitializeSpecials(void *addr, void *defaults) const { return; } - assert(ParentClass != NULL); + assert(ParentClass != nullptr); ParentClass->InitializeSpecials(addr, defaults); for (auto tao : SpecialInits) { @@ -3195,7 +3236,7 @@ void PClass::DestroySpecials(void *addr) const { return; } - assert(ParentClass != NULL); + assert(ParentClass != nullptr); ParentClass->DestroySpecials(addr); for (auto tao : SpecialInits) { @@ -3231,7 +3272,7 @@ void PClass::InitializeDefaults() { if (IsKindOf(RUNTIME_CLASS(PClassActor))) { - assert(Defaults == NULL); + assert(Defaults == nullptr); Defaults = (BYTE *)M_Malloc(Size); // run the constructor on the defaults to set the vtbl pointer which is needed to run class-aware functions on them. @@ -3248,7 +3289,7 @@ void PClass::InitializeDefaults() // Copy the defaults from the parent but leave the DObject part alone because it contains important data. - if (ParentClass->Defaults != NULL) + if (ParentClass->Defaults != nullptr) { memcpy(Defaults + sizeof(DObject), ParentClass->Defaults + sizeof(DObject), ParentClass->Size - sizeof(DObject)); if (Size > ParentClass->Size) @@ -3265,7 +3306,7 @@ void PClass::InitializeDefaults() if (bRuntimeClass) { // Copy parent values from the parent defaults. - assert(ParentClass != NULL); + assert(ParentClass != nullptr); ParentClass->InitializeSpecials(Defaults, ParentClass->Defaults); for (const PField *field : Fields) @@ -3404,14 +3445,14 @@ PClass *PClass::FindClassTentative(FName name) { if (name == NAME_None) { - return NULL; + return nullptr; } size_t bucket; PType *found = TypeTable.FindType(RUNTIME_CLASS(PClass), /*FIXME:Outer*/0, name, &bucket); - if (found != NULL) + if (found != nullptr) { return static_cast(found); } @@ -3484,14 +3525,14 @@ int PClass::FindVirtualIndex(FName name, PPrototype *proto) void PClass::BuildFlatPointers () { - if (FlatPointers != NULL) + if (FlatPointers != nullptr) { // Already built: Do nothing. return; } - else if (ParentClass == NULL) + else if (ParentClass == nullptr) { // No parent (i.e. DObject: FlatPointers is the same as Pointers. - if (Pointers == NULL) - { // No pointers: Make FlatPointers a harmless non-NULL. + if (Pointers == nullptr) + { // No pointers: Make FlatPointers a harmless non-nullptr. FlatPointers = &TheEnd; } else @@ -3536,7 +3577,7 @@ void PClass::BuildFlatPointers () { } // Concatenate them into a new array - size_t *flat = new size_t[numPointers + numSuperPointers + ScriptPointers.Size() + 1]; + size_t *flat = (size_t*)FlatpointerArena.Alloc(sizeof(size_t) * (numPointers + numSuperPointers + ScriptPointers.Size() + 1)); if (numSuperPointers > 0) { memcpy (flat, ParentClass->FlatPointers, sizeof(size_t)*numSuperPointers); @@ -3555,6 +3596,68 @@ void PClass::BuildFlatPointers () } } +//========================================================================== +// +// PClass :: BuildArrayPointers +// +// same as above, but creates a list to dynamic object arrays +// +//========================================================================== + +void PClass::BuildArrayPointers() +{ + if (ArrayPointers != nullptr) + { // Already built: Do nothing. + return; + } + else if (ParentClass == nullptr) + { // No parent (i.e. DObject: FlatPointers is the same as Pointers. + ArrayPointers = &TheEnd; + } + else + { + ParentClass->BuildArrayPointers(); + + TArray ScriptPointers; + + // Collect all arrays to pointers in scripted fields. + for (auto field : Fields) + { + if (!(field->Flags & VARF_Native)) + { + field->Type->SetPointerArray(Defaults, unsigned(field->Offset), &ScriptPointers); + } + } + + if (ScriptPointers.Size() == 0) + { // No new pointers: Just use the same ArrayPointers as the parent. + ArrayPointers = ParentClass->ArrayPointers; + } + else + { // New pointers: Create a new FlatPointers array and add them. + int numSuperPointers; + + // Count pointers defined by superclasses. + for (numSuperPointers = 0; ParentClass->ArrayPointers[numSuperPointers] != ~(size_t)0; numSuperPointers++) + { + } + + // Concatenate them into a new array + size_t *flat = (size_t*)FlatpointerArena.Alloc(sizeof(size_t) * (numSuperPointers + ScriptPointers.Size() + 1)); + if (numSuperPointers > 0) + { + memcpy(flat, ParentClass->ArrayPointers, sizeof(size_t)*numSuperPointers); + } + if (ScriptPointers.Size() > 0) + { + memcpy(flat + numSuperPointers, &ScriptPointers[0], sizeof(size_t) * ScriptPointers.Size()); + } + flat[numSuperPointers + ScriptPointers.Size()] = ~(size_t)0; + ArrayPointers = flat; + } + } +} + //========================================================================== // // PClass :: NativeClass @@ -3604,18 +3707,18 @@ void PClass::FindFunction(VMFunction **pptr, FName clsname, FName funcname) PType *FTypeTable::FindType(PClass *metatype, intptr_t parm1, intptr_t parm2, size_t *bucketnum) { size_t bucket = Hash(metatype, parm1, parm2) % HASH_SIZE; - if (bucketnum != NULL) + if (bucketnum != nullptr) { *bucketnum = bucket; } - for (PType *type = TypeHash[bucket]; type != NULL; type = type->HashNext) + for (PType *type = TypeHash[bucket]; type != nullptr; type = type->HashNext) { - if (type->GetClass()->TypeTableType == metatype && type->IsMatch(parm1, parm2)) + if (type->TypeTableType == metatype && type->IsMatch(parm1, parm2)) { return type; } } - return NULL; + return nullptr; } //========================================================================== @@ -3630,13 +3733,13 @@ PType *FTypeTable::FindType(PClass *metatype, intptr_t parm1, intptr_t parm2, si void FTypeTable::ReplaceType(PType *newtype, PType *oldtype, size_t bucket) { - for (PType **type_p = &TypeHash[bucket]; *type_p != NULL; type_p = &(*type_p)->HashNext) + for (PType **type_p = &TypeHash[bucket]; *type_p != nullptr; type_p = &(*type_p)->HashNext) { PType *type = *type_p; if (type == oldtype) { newtype->HashNext = type->HashNext; - type->HashNext = NULL; + type->HashNext = nullptr; *type_p = newtype; break; } @@ -3653,10 +3756,10 @@ void FTypeTable::AddType(PType *type, PClass *metatype, intptr_t parm1, intptr_t { #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(FindType(metatype, parm1, parm2, &bucketcheck) == nullptr && "Type must not be inserted more than once"); assert(bucketcheck == bucket && "Passed bucket was wrong"); #endif + type->TypeTableType = metatype; type->HashNext = TypeHash[bucket]; TypeHash[bucket] = type; GC::WriteBarrier(type); @@ -3670,14 +3773,15 @@ void FTypeTable::AddType(PType *type, PClass *metatype, intptr_t parm1, intptr_t void FTypeTable::AddType(PType *type) { - PClass *metatype; intptr_t parm1, parm2; size_t bucket; - metatype = type->GetClass()->TypeTableType; + // Type table stuff id only needed to let all classes hash to the same group. For all other types this is pointless. + type->TypeTableType = type->GetClass(); + PClass *metatype = type->TypeTableType; type->GetTypeIDs(parm1, parm2); bucket = Hash(metatype, parm1, parm2) % HASH_SIZE; - assert(FindType(metatype, parm1, parm2, NULL) == NULL && "Type must not be inserted more than once"); + assert(FindType(metatype, parm1, parm2, nullptr) == nullptr && "Type must not be inserted more than once"); type->HashNext = TypeHash[bucket]; TypeHash[bucket] = type; @@ -3732,7 +3836,7 @@ void FTypeTable::Mark() { for (int i = HASH_SIZE - 1; i >= 0; --i) { - if (TypeHash[i] != NULL) + if (TypeHash[i] != nullptr) { GC::Mark(TypeHash[i]); } @@ -3790,7 +3894,7 @@ PSymbol::~PSymbol() } PSymbolTable::PSymbolTable() -: ParentSymbolTable(NULL) +: ParentSymbolTable(nullptr) { } @@ -3833,24 +3937,24 @@ void PSymbolTable::SetParentTable (PSymbolTable *parent) PSymbol *PSymbolTable::FindSymbol (FName symname, bool searchparents) const { PSymbol * const *value = Symbols.CheckKey(symname); - if (value == NULL && searchparents && ParentSymbolTable != NULL) + if (value == nullptr && searchparents && ParentSymbolTable != nullptr) { return ParentSymbolTable->FindSymbol(symname, searchparents); } - return value != NULL ? *value : NULL; + return value != nullptr ? *value : nullptr; } PSymbol *PSymbolTable::FindSymbolInTable(FName symname, PSymbolTable *&symtable) { PSymbol * const *value = Symbols.CheckKey(symname); - if (value == NULL) + if (value == nullptr) { - if (ParentSymbolTable != NULL) + if (ParentSymbolTable != nullptr) { return ParentSymbolTable->FindSymbolInTable(symname, symtable); } - symtable = NULL; - return NULL; + symtable = nullptr; + return nullptr; } symtable = this; return *value; @@ -3859,9 +3963,9 @@ PSymbol *PSymbolTable::FindSymbolInTable(FName symname, PSymbolTable *&symtable) PSymbol *PSymbolTable::AddSymbol (PSymbol *sym) { // Symbols that already exist are not inserted. - if (Symbols.CheckKey(sym->SymbolName) != NULL) + if (Symbols.CheckKey(sym->SymbolName) != nullptr) { - return NULL; + return nullptr; } Symbols.Insert(sym->SymbolName, sym); return sym; @@ -3878,16 +3982,16 @@ PSymbol *PSymbolTable::ReplaceSymbol(PSymbol *newsym) { // If a symbol with a matching name exists, take its place and return it. PSymbol **symslot = Symbols.CheckKey(newsym->SymbolName); - if (symslot != NULL) + if (symslot != nullptr) { PSymbol *oldsym = *symslot; *symslot = newsym; return oldsym; } - // Else, just insert normally and return NULL since there was no + // Else, just insert normally and return nullptr since there was no // symbol to replace. Symbols.Insert(newsym->SymbolName, newsym); - return NULL; + return nullptr; } IMPLEMENT_CLASS(PNamespace, false, true) @@ -3969,7 +4073,7 @@ void RemoveUnusedSymbols() // We do not need any non-field and non-function symbols in structs and classes anymore. for (size_t i = 0; i < countof(TypeTable.TypeHash); ++i) { - for (PType *ty = TypeTable.TypeHash[i]; ty != NULL; ty = ty->HashNext) + for (PType *ty = TypeTable.TypeHash[i]; ty != nullptr; ty = ty->HashNext) { if (ty->IsKindOf(RUNTIME_CLASS(PStruct))) { diff --git a/src/dobjtype.h b/src/dobjtype.h index 60d410918..3858585e9 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -199,22 +199,14 @@ public: // Prototype *+ *+ struct ZCC_ExprConstant; -class PClassType; class PType : public PTypeBase { - //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, PTypeBase) HAS_OBJECT_POINTERS; protected: - enum { MetaClassNum = CLASSREG_PClassType }; public: - typedef PClassType MetaClass; - MetaClass *GetClass() const; - + PClass *TypeTableType; // The type to use for hashing into the type table unsigned int Size; // this type's size unsigned int Align; // this type's preferred alignment PType *HashNext; // next type in this type table @@ -247,6 +239,7 @@ public: // object is destroyed. virtual void SetDefaultValue(void *base, unsigned offset, TArray *special=NULL) const; virtual void SetPointer(void *base, unsigned offset, TArray *ptrofs = NULL) const; + virtual void SetPointerArray(void *base, unsigned offset, TArray *ptrofs = NULL) const; // Initialize the value, if needed (e.g. strings) virtual void InitializeValue(void *addr, const void *def) const; @@ -534,7 +527,7 @@ class PClassPointer : public PPointer DECLARE_CLASS(PClassPointer, PPointer); HAS_OBJECT_POINTERS; public: - PClassPointer(class PClass *restrict); + PClassPointer(class PClass *restrict = nullptr); class PClass *ClassRestriction; @@ -542,8 +535,6 @@ public: virtual bool IsMatch(intptr_t id1, intptr_t id2) const; virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; -protected: - PClassPointer(); }; // Struct/class fields ------------------------------------------------------ @@ -657,6 +648,14 @@ public: virtual bool IsMatch(intptr_t id1, intptr_t id2) const; virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; + + void WriteValue(FSerializer &ar, const char *key, const void *addr) const override; + bool ReadValue(FSerializer &ar, const char *key, void *addr) const override; + void SetDefaultValue(void *base, unsigned offset, TArray *specials) const override; + void InitializeValue(void *addr, const void *def) const override; + void DestroyValue(void *addr) const override; + void SetPointerArray(void *base, unsigned offset, TArray *ptrofs = NULL) const override; + protected: PDynArray(); }; @@ -769,22 +768,17 @@ enum TentativeClass = UINT_MAX, }; -class PClassClass; class PClass : public PNativeStruct { DECLARE_CLASS(PClass, PNativeStruct); HAS_OBJECT_POINTERS; protected: // We unravel _WITH_META here just as we did for PType. - enum { MetaClassNum = CLASSREG_PClassClass }; TArray SpecialInits; void Derive(PClass *newclass, FName name); void InitializeSpecials(void *addr, void *defaults) const; void SetSuper(); public: - typedef PClassClass MetaClass; - MetaClass *GetClass() const; - void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; void WriteAllFields(FSerializer &ar, const void *addr) const; bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; @@ -801,6 +795,7 @@ public: 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 + const size_t *ArrayPointers; // dynamic arrays containing object pointers. BYTE *Defaults; bool bRuntimeClass; // class was defined at run-time, not compile-time bool bExported; // This type has been declared in a script @@ -818,6 +813,7 @@ public: PField *AddField(FName name, PType *type, DWORD flags=0) override; void InitializeActorInfo(); void BuildFlatPointers(); + void BuildArrayPointers(); void DestroySpecials(void *addr) const; const PClass *NativeClass() const; @@ -860,34 +856,6 @@ public: static bool bVMOperational; }; -class PClassType : public PClass -{ - DECLARE_CLASS(PClassType, PClass); -protected: -public: - PClassType(); - virtual void DeriveData(PClass *newclass); - - 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 diff --git a/src/fragglescript/t_func.cpp b/src/fragglescript/t_func.cpp index 20b53c8fd..0ee391e21 100644 --- a/src/fragglescript/t_func.cpp +++ b/src/fragglescript/t_func.cpp @@ -2675,8 +2675,8 @@ void FParser::SF_PlayerWeapon() script_error("weaponnum out of range! %d\n", weaponnum); return; } - PClassWeapon * ti = static_cast(PClass::FindActor(WeaponNames[weaponnum])); - if (!ti) + auto ti = PClass::FindActor(WeaponNames[weaponnum]); + if (!ti || !ti->IsDescendantOf(RUNTIME_CLASS(AWeapon))) { script_error("incompatibility in playerweapon %d\n", weaponnum); return; @@ -2686,7 +2686,7 @@ void FParser::SF_PlayerWeapon() { AActor * wp = players[playernum].mo->FindInventory(ti); t_return.type = svt_int; - t_return.value.i = wp!=NULL;; + t_return.value.i = wp!=NULL; return; } else @@ -2756,8 +2756,8 @@ void FParser::SF_PlayerSelectedWeapon() script_error("weaponnum out of range! %d\n", weaponnum); return; } - PClassWeapon * ti = static_cast(PClass::FindActor(WeaponNames[weaponnum])); - if (!ti) + auto ti = PClass::FindActor(WeaponNames[weaponnum]); + if (!ti || !ti->IsDescendantOf(RUNTIME_CLASS(AWeapon))) { script_error("incompatibility in playerweapon %d\n", weaponnum); return; diff --git a/src/g_inventory/a_pickups.cpp b/src/g_inventory/a_pickups.cpp index fc35d2da4..66f51e92e 100644 --- a/src/g_inventory/a_pickups.cpp +++ b/src/g_inventory/a_pickups.cpp @@ -73,10 +73,10 @@ size_t PClassInventory::PointerSubstitution(DObject *oldclass, DObject *newclass return changed; } -void PClassInventory::Finalize(FStateDefinitions &statedef) +void AInventory::Finalize(FStateDefinitions &statedef) { Super::Finalize(statedef); - ((AActor*)Defaults)->flags |= MF_SPECIAL; + flags |= MF_SPECIAL; } IMPLEMENT_CLASS(AInventory, false, true) diff --git a/src/g_inventory/a_pickups.h b/src/g_inventory/a_pickups.h index 7ca317397..be6280c0a 100644 --- a/src/g_inventory/a_pickups.h +++ b/src/g_inventory/a_pickups.h @@ -72,6 +72,7 @@ class AInventory : public AActor HAS_OBJECT_POINTERS public: + virtual void Finalize(FStateDefinitions &statedef) override; virtual void Serialize(FSerializer &arc) override; virtual void MarkPrecacheSounds() const override; virtual void OnDestroy() override; diff --git a/src/g_inventory/a_weapons.cpp b/src/g_inventory/a_weapons.cpp index 24661dfd1..a916531be 100644 --- a/src/g_inventory/a_weapons.cpp +++ b/src/g_inventory/a_weapons.cpp @@ -113,55 +113,25 @@ FString WeaponSection; TArray KeyConfWeapons; FWeaponSlots *PlayingKeyConf; -TArray Weapons_ntoh; -TMap Weapons_hton; +TArray Weapons_ntoh; +TMap Weapons_hton; static int ntoh_cmp(const void *a, const void *b); -IMPLEMENT_CLASS(PClassWeapon, false, false) - //=========================================================================== // // // //=========================================================================== -PClassWeapon::PClassWeapon() -{ - SlotNumber = -1; - SlotPriority = INT_MAX; -} - -//=========================================================================== -// -// -// -//=========================================================================== - -void PClassWeapon::DeriveData(PClass *newclass) -{ - assert(newclass->IsKindOf(RUNTIME_CLASS(PClassWeapon))); - Super::DeriveData(newclass); - PClassWeapon *newc = static_cast(newclass); - - newc->SlotNumber = SlotNumber; - newc->SlotPriority = SlotPriority; -} - - -//=========================================================================== -// -// -// -//=========================================================================== - -void PClassWeapon::Finalize(FStateDefinitions &statedef) +void AWeapon::Finalize(FStateDefinitions &statedef) { Super::Finalize(statedef); FState *ready = FindState(NAME_Ready); FState *select = FindState(NAME_Select); FState *deselect = FindState(NAME_Deselect); FState *fire = FindState(NAME_Fire); + auto TypeName = GetClass()->TypeName; // Consider any weapon without any valid state abstract and don't output a warning // This is for creating base classes for weapon groups that only set up some properties. @@ -272,7 +242,7 @@ bool AWeapon::CheckAmmo (int fireMode, bool autoSwitch, bool requireAmmo, int am bool gotSome = CheckAmmo (PrimaryFire, false) || CheckAmmo (AltFire, false); if (!gotSome && autoSwitch) { - barrier_cast(Owner)->PickNewWeapon (NULL); + barrier_cast(Owner)->PickNewWeapon (nullptr); } return gotSome; } @@ -281,10 +251,10 @@ bool AWeapon::CheckAmmo (int fireMode, bool autoSwitch, bool requireAmmo, int am { return true; } - count1 = (Ammo1 != NULL) ? Ammo1->Amount : 0; - count2 = (Ammo2 != NULL) ? Ammo2->Amount : 0; + count1 = (Ammo1 != nullptr) ? Ammo1->Amount : 0; + count2 = (Ammo2 != nullptr) ? Ammo2->Amount : 0; - if ((WeaponFlags & WIF_DEHAMMO) && (Ammo1 == NULL)) + if ((WeaponFlags & WIF_DEHAMMO) && (Ammo1 == nullptr)) { lAmmoUse1 = 0; } @@ -306,7 +276,7 @@ bool AWeapon::CheckAmmo (int fireMode, bool autoSwitch, bool requireAmmo, int am { enoughmask = 1 << altFire; } - if (altFire && FindState(NAME_AltFire) == NULL) + if (altFire && FindState(NAME_AltFire) == nullptr) { // If this weapon has no alternate fire, then there is never enough ammo for it enough &= 1; } @@ -317,7 +287,7 @@ bool AWeapon::CheckAmmo (int fireMode, bool autoSwitch, bool requireAmmo, int am // out of ammo, pick a weapon to change to if (autoSwitch) { - barrier_cast(Owner)->PickNewWeapon (NULL); + barrier_cast(Owner)->PickNewWeapon (nullptr); } return false; } @@ -352,7 +322,7 @@ bool AWeapon::DepleteAmmo (bool altFire, bool checkEnough, int ammouse) } if (!altFire) { - if (Ammo1 != NULL) + if (Ammo1 != nullptr) { if (ammouse >= 0 && (WeaponFlags & WIF_DEHAMMO)) { @@ -363,25 +333,25 @@ bool AWeapon::DepleteAmmo (bool altFire, bool checkEnough, int ammouse) Ammo1->Amount -= AmmoUse1; } } - if ((WeaponFlags & WIF_PRIMARY_USES_BOTH) && Ammo2 != NULL) + if ((WeaponFlags & WIF_PRIMARY_USES_BOTH) && Ammo2 != nullptr) { Ammo2->Amount -= AmmoUse2; } } else { - if (Ammo2 != NULL) + if (Ammo2 != nullptr) { Ammo2->Amount -= AmmoUse2; } - if ((WeaponFlags & WIF_ALT_USES_BOTH) && Ammo1 != NULL) + if ((WeaponFlags & WIF_ALT_USES_BOTH) && Ammo1 != nullptr) { Ammo1->Amount -= AmmoUse1; } } - if (Ammo1 != NULL && Ammo1->Amount < 0) + if (Ammo1 != nullptr && Ammo1->Amount < 0) Ammo1->Amount = 0; - if (Ammo2 != NULL && Ammo2->Amount < 0) + if (Ammo2 != nullptr && Ammo2->Amount < 0) Ammo2->Amount = 0; } return true; @@ -546,14 +516,14 @@ FState *AWeapon::GetStateForButtonName (FName button) bool FWeaponSlot::AddWeapon(const char *type) { - return AddWeapon(static_cast(PClass::FindClass(type))); + return AddWeapon(static_cast(PClass::FindClass(type))); } -bool FWeaponSlot::AddWeapon(PClassWeapon *type) +bool FWeaponSlot::AddWeapon(PClassActor *type) { unsigned int i; - if (type == NULL) + if (type == nullptr) { return false; } @@ -594,10 +564,10 @@ void FWeaponSlot :: AddWeaponList(const char *list, bool clear) Clear(); } tok = strtok(buff, " "); - while (tok != NULL) + while (tok != nullptr) { AddWeapon(tok); - tok = strtok(NULL, " "); + tok = strtok(nullptr, " "); } } @@ -610,7 +580,7 @@ void FWeaponSlot :: AddWeaponList(const char *list, bool clear) // //=========================================================================== -int FWeaponSlot::LocateWeapon(PClassWeapon *type) +int FWeaponSlot::LocateWeapon(PClassActor *type) { unsigned int i; @@ -641,22 +611,22 @@ AWeapon *FWeaponSlot::PickWeapon(player_t *player, bool checkammo) { int i, j; - if (player->mo == NULL) + if (player->mo == nullptr) { - return NULL; + return nullptr; } // Does this slot even have any weapons? if (Weapons.Size() == 0) { return player->ReadyWeapon; } - if (player->ReadyWeapon != NULL) + if (player->ReadyWeapon != nullptr) { for (i = 0; (unsigned)i < Weapons.Size(); i++) { if (Weapons[i].Type == player->ReadyWeapon->GetClass() || (player->ReadyWeapon->WeaponFlags & WIF_POWERED_UP && - player->ReadyWeapon->SisterWeapon != NULL && + player->ReadyWeapon->SisterWeapon != nullptr && player->ReadyWeapon->SisterWeapon->GetClass() == Weapons[i].Type)) { for (j = (i == 0 ? Weapons.Size() - 1 : i - 1); @@ -665,7 +635,7 @@ AWeapon *FWeaponSlot::PickWeapon(player_t *player, bool checkammo) { AWeapon *weap = static_cast (player->mo->FindInventory(Weapons[j].Type)); - if (weap != NULL && weap->IsKindOf(RUNTIME_CLASS(AWeapon))) + if (weap != nullptr && weap->IsKindOf(RUNTIME_CLASS(AWeapon))) { if (!checkammo || weap->CheckAmmo(AWeapon::EitherFire, false)) { @@ -680,7 +650,7 @@ AWeapon *FWeaponSlot::PickWeapon(player_t *player, bool checkammo) { AWeapon *weap = static_cast (player->mo->FindInventory(Weapons[i].Type)); - if (weap != NULL && weap->IsKindOf(RUNTIME_CLASS(AWeapon))) + if (weap != nullptr && weap->IsKindOf(RUNTIME_CLASS(AWeapon))) { if (!checkammo || weap->CheckAmmo(AWeapon::EitherFire, false)) { @@ -736,7 +706,7 @@ void FWeaponSlot::Sort() for (i = 1; i < (int)Weapons.Size(); ++i) { int pos = Weapons[i].Position; - PClassWeapon *type = Weapons[i].Type; + PClassActor *type = Weapons[i].Type; for (j = i - 1; j >= 0 && Weapons[j].Position > pos; --j) { Weapons[j + 1] = Weapons[j]; @@ -785,7 +755,7 @@ void FWeaponSlots::Clear() // //=========================================================================== -ESlotDef FWeaponSlots::AddDefaultWeapon (int slot, PClassWeapon *type) +ESlotDef FWeaponSlots::AddDefaultWeapon (int slot, PClassActor *type) { int currSlot, index; @@ -810,7 +780,7 @@ ESlotDef FWeaponSlots::AddDefaultWeapon (int slot, PClassWeapon *type) // //=========================================================================== -bool FWeaponSlots::LocateWeapon (PClassWeapon *type, int *const slot, int *const index) +bool FWeaponSlots::LocateWeapon (PClassActor *type, int *const slot, int *const index) { int i, j; @@ -819,8 +789,8 @@ bool FWeaponSlots::LocateWeapon (PClassWeapon *type, int *const slot, int *const j = Slots[i].LocateWeapon(type); if (j >= 0) { - if (slot != NULL) *slot = i; - if (index != NULL) *index = j; + if (slot != nullptr) *slot = i; + if (index != nullptr) *index = j; return true; } } @@ -857,14 +827,14 @@ static bool FindMostRecentWeapon(player_t *player, int *slot, int *index) { return player->weapons.LocateWeapon(player->PendingWeapon->GetClass(), slot, index); } - else if (player->ReadyWeapon != NULL) + else if (player->ReadyWeapon != nullptr) { AWeapon *weap = player->ReadyWeapon; if (!player->weapons.LocateWeapon(weap->GetClass(), slot, index)) { // If the current weapon wasn't found and is powered up, // look for its non-powered up version. - if (weap->WeaponFlags & WIF_POWERED_UP && weap->SisterWeaponType != NULL) + if (weap->WeaponFlags & WIF_POWERED_UP && weap->SisterWeaponType != nullptr) { return player->weapons.LocateWeapon(weap->SisterWeaponType, slot, index); } @@ -893,16 +863,16 @@ AWeapon *FWeaponSlots::PickNextWeapon(player_t *player) int startslot, startindex; int slotschecked = 0; - if (player->mo == NULL) + if (player->mo == nullptr) { - return NULL; + return nullptr; } - if (player->ReadyWeapon == NULL || FindMostRecentWeapon(player, &startslot, &startindex)) + if (player->ReadyWeapon == nullptr || FindMostRecentWeapon(player, &startslot, &startindex)) { int slot; int index; - if (player->ReadyWeapon == NULL) + if (player->ReadyWeapon == nullptr) { startslot = NUM_WEAPON_SLOTS - 1; startindex = Slots[startslot].Size() - 1; @@ -921,9 +891,9 @@ AWeapon *FWeaponSlots::PickNextWeapon(player_t *player) slot = 0; } } - PClassWeapon *type = Slots[slot].GetWeapon(index); + PClassActor *type = Slots[slot].GetWeapon(index); AWeapon *weap = static_cast(player->mo->FindInventory(type)); - if (weap != NULL && weap->CheckAmmo(AWeapon::EitherFire, false)) + if (weap != nullptr && weap->CheckAmmo(AWeapon::EitherFire, false)) { return weap; } @@ -948,16 +918,16 @@ AWeapon *FWeaponSlots::PickPrevWeapon (player_t *player) int startslot, startindex; int slotschecked = 0; - if (player->mo == NULL) + if (player->mo == nullptr) { - return NULL; + return nullptr; } - if (player->ReadyWeapon == NULL || FindMostRecentWeapon (player, &startslot, &startindex)) + if (player->ReadyWeapon == nullptr || FindMostRecentWeapon (player, &startslot, &startindex)) { int slot; int index; - if (player->ReadyWeapon == NULL) + if (player->ReadyWeapon == nullptr) { startslot = 0; startindex = 0; @@ -976,9 +946,9 @@ AWeapon *FWeaponSlots::PickPrevWeapon (player_t *player) } index = Slots[slot].Size() - 1; } - PClassWeapon *type = Slots[slot].GetWeapon(index); + PClassActor *type = Slots[slot].GetWeapon(index); AWeapon *weap = static_cast(player->mo->FindInventory(type)); - if (weap != NULL && weap->CheckAmmo(AWeapon::EitherFire, false)) + if (weap != nullptr && weap->CheckAmmo(AWeapon::EitherFire, false)) { return weap; } @@ -1010,23 +980,23 @@ void FWeaponSlots::AddExtraWeapons() // Append extra weapons to the slots. for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - PClass *cls = PClassActor::AllActorClasses[i]; + PClassActor *cls = PClassActor::AllActorClasses[i]; if (!cls->IsDescendantOf(RUNTIME_CLASS(AWeapon))) { continue; } - PClassWeapon *acls = static_cast(cls); - if ((acls->GameFilter == GAME_Any || (acls->GameFilter & gameinfo.gametype)) && - acls->Replacement == NULL && // Replaced weapons don't get slotted. - !(((AWeapon *)(acls->Defaults))->WeaponFlags & WIF_POWERED_UP) && - !LocateWeapon(acls, NULL, NULL) // Don't duplicate it if it's already present. + auto weapdef = ((AWeapon*)GetDefaultByType(cls)); + if ((cls->GameFilter == GAME_Any || (cls->GameFilter & gameinfo.gametype)) && + cls->Replacement == nullptr && // Replaced weapons don't get slotted. + !(weapdef->WeaponFlags & WIF_POWERED_UP) && + !LocateWeapon(cls, nullptr, nullptr) // Don't duplicate it if it's already present. ) { - int slot = acls->SlotNumber; + int slot = weapdef->SlotNumber; if ((unsigned)slot < NUM_WEAPON_SLOTS) { - FWeaponSlot::WeaponInfo info = { acls, acls->SlotPriority }; + FWeaponSlot::WeaponInfo info = { cls, weapdef->SlotPriority }; Slots[slot].Weapons.Push(info); } } @@ -1063,8 +1033,8 @@ void FWeaponSlots::SetFromGameInfo() { for (unsigned j = 0; j < gameinfo.DefaultWeaponSlots[i].Size(); j++) { - PClassWeapon *cls = dyn_cast(PClass::FindClass(gameinfo.DefaultWeaponSlots[i][j])); - if (cls == NULL) + PClassActor *cls = PClass::FindActor(gameinfo.DefaultWeaponSlots[i][j]); + if (cls == nullptr) { Printf("Unknown weapon class '%s' found in default weapon slot assignments\n", gameinfo.DefaultWeaponSlots[i][j].GetChars()); @@ -1260,7 +1230,7 @@ CCMD (setslot) if (argv.argc() < 2 || (slot = atoi (argv[1])) >= NUM_WEAPON_SLOTS) { Printf("Usage: setslot [slot] [weapons]\nCurrent slot assignments:\n"); - if (players[consoleplayer].mo != NULL) + if (players[consoleplayer].mo != nullptr) { FString config(GameConfig->GetConfigPath(false)); Printf(TEXTCOLOR_BLUE "Add the following to " TEXTCOLOR_ORANGE "%s" TEXTCOLOR_BLUE @@ -1279,7 +1249,7 @@ CCMD (setslot) { KeyConfWeapons.Push(argv.args()); } - else if (PlayingKeyConf != NULL) + else if (PlayingKeyConf != nullptr) { PlayingKeyConf->Slots[slot].Clear(); for (int i = 2; i < argv.argc(); ++i) @@ -1299,7 +1269,7 @@ CCMD (setslot) Net_WriteByte(argv.argc()-2); for (int i = 2; i < argv.argc(); i++) { - Net_WriteWeapon(dyn_cast(PClass::FindClass(argv[i]))); + Net_WriteWeapon(dyn_cast(PClass::FindClass(argv[i]))); } } } @@ -1310,9 +1280,9 @@ CCMD (setslot) // //=========================================================================== -void FWeaponSlots::AddSlot(int slot, PClassWeapon *type, bool feedback) +void FWeaponSlots::AddSlot(int slot, PClassActor *type, bool feedback) { - if (type != NULL && !Slots[slot].AddWeapon(type) && feedback) + if (type != nullptr && !Slots[slot].AddWeapon(type) && feedback) { Printf ("Could not add %s to slot %d\n", type->TypeName.GetChars(), slot); } @@ -1328,8 +1298,8 @@ CCMD (addslot) return; } - PClassWeapon *type= dyn_cast(PClass::FindClass(argv[2])); - if (type == NULL) + PClassActor *type= dyn_cast(PClass::FindClass(argv[2])); + if (type == nullptr) { Printf("%s is not a weapon\n", argv[2]); return; @@ -1339,7 +1309,7 @@ CCMD (addslot) { KeyConfWeapons.Push(argv.args()); } - else if (PlayingKeyConf != NULL) + else if (PlayingKeyConf != nullptr) { PlayingKeyConf->AddSlot(int(slot), type, false); } @@ -1370,9 +1340,9 @@ CCMD (weaponsection) // CCMD addslotdefault // //=========================================================================== -void FWeaponSlots::AddSlotDefault(int slot, PClassWeapon *type, bool feedback) +void FWeaponSlots::AddSlotDefault(int slot, PClassActor *type, bool feedback) { - if (type != NULL && type->IsDescendantOf(RUNTIME_CLASS(AWeapon))) + if (type != nullptr && type->IsDescendantOf(RUNTIME_CLASS(AWeapon))) { switch (AddDefaultWeapon(slot, type)) { @@ -1395,7 +1365,7 @@ void FWeaponSlots::AddSlotDefault(int slot, PClassWeapon *type, bool feedback) CCMD (addslotdefault) { - PClassWeapon *type; + PClassActor *type; unsigned int slot; if (argv.argc() != 3 || (slot = atoi (argv[1])) >= NUM_WEAPON_SLOTS) @@ -1404,8 +1374,8 @@ CCMD (addslotdefault) return; } - type = dyn_cast(PClass::FindClass(argv[2])); - if (type == NULL) + type = dyn_cast(PClass::FindClass(argv[2])); + if (type == nullptr) { Printf ("%s is not a weapon\n", argv[2]); return; @@ -1415,7 +1385,7 @@ CCMD (addslotdefault) { KeyConfWeapons.Push(argv.args()); } - else if (PlayingKeyConf != NULL) + else if (PlayingKeyConf != nullptr) { PlayingKeyConf->AddSlotDefault(int(slot), type, false); } @@ -1443,7 +1413,7 @@ void P_PlaybackKeyConfWeapons(FWeaponSlots *slots) FString cmd(KeyConfWeapons[i]); AddCommandString(cmd.LockBuffer()); } - PlayingKeyConf = NULL; + PlayingKeyConf = nullptr; } //=========================================================================== @@ -1460,20 +1430,20 @@ void P_PlaybackKeyConfWeapons(FWeaponSlots *slots) void P_SetupWeapons_ntohton() { unsigned int i; - PClassWeapon *cls; + PClassActor *cls; Weapons_ntoh.Clear(); Weapons_hton.Clear(); - cls = NULL; - Weapons_ntoh.Push(cls); // Index 0 is always NULL. + cls = nullptr; + Weapons_ntoh.Push(cls); // Index 0 is always nullptr. for (i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { PClassActor *cls = PClassActor::AllActorClasses[i]; if (cls->IsDescendantOf(RUNTIME_CLASS(AWeapon))) { - Weapons_ntoh.Push(static_cast(cls)); + Weapons_ntoh.Push(static_cast(cls)); } } qsort(&Weapons_ntoh[1], Weapons_ntoh.Size() - 1, sizeof(Weapons_ntoh[0]), ntoh_cmp); @@ -1499,8 +1469,8 @@ void P_SetupWeapons_ntohton() static int ntoh_cmp(const void *a, const void *b) { - PClassWeapon *c1 = *(PClassWeapon **)a; - PClassWeapon *c2 = *(PClassWeapon **)b; + PClassActor *c1 = *(PClassActor **)a; + PClassActor *c2 = *(PClassActor **)b; int g1 = c1->GameFilter == GAME_Any ? 1 : (c1->GameFilter & gameinfo.gametype) ? 0 : 2; int g2 = c2->GameFilter == GAME_Any ? 1 : (c2->GameFilter & gameinfo.gametype) ? 0 : 2; if (g1 != g2) @@ -1540,24 +1510,24 @@ void P_WriteDemoWeaponsChunk(BYTE **demo) void P_ReadDemoWeaponsChunk(BYTE **demo) { int count, i; - PClassWeapon *type; + PClassActor *type; const char *s; count = ReadWord(demo); Weapons_ntoh.Resize(count); Weapons_hton.Clear(count); - Weapons_ntoh[0] = type = NULL; + Weapons_ntoh[0] = type = nullptr; Weapons_hton[type] = 0; for (i = 1; i < count; ++i) { s = ReadStringConst(demo); - type = dyn_cast(PClass::FindClass(s)); + type = dyn_cast(PClass::FindClass(s)); // If a demo was recorded with a weapon that is no longer present, // should we report it? Weapons_ntoh[i] = type; - if (type != NULL) + if (type != nullptr) { Weapons_hton[type] = i; } @@ -1570,12 +1540,12 @@ void P_ReadDemoWeaponsChunk(BYTE **demo) // //=========================================================================== -void Net_WriteWeapon(PClassWeapon *type) +void Net_WriteWeapon(PClassActor *type) { int index, *index_p; index_p = Weapons_hton.CheckKey(type); - if (index_p == NULL) + if (index_p == nullptr) { index = 0; } @@ -1602,7 +1572,7 @@ void Net_WriteWeapon(PClassWeapon *type) // //=========================================================================== -PClassWeapon *Net_ReadWeapon(BYTE **stream) +PClassActor *Net_ReadWeapon(BYTE **stream) { int index; @@ -1613,7 +1583,7 @@ PClassWeapon *Net_ReadWeapon(BYTE **stream) } if ((unsigned)index >= Weapons_ntoh.Size()) { - return NULL; + return nullptr; } return Weapons_ntoh[index]; } diff --git a/src/g_inventory/a_weapons.h b/src/g_inventory/a_weapons.h index 21eaf9b89..50862bc47 100644 --- a/src/g_inventory/a_weapons.h +++ b/src/g_inventory/a_weapons.h @@ -1,7 +1,7 @@ #pragma once #include "a_pickups.h" -class PClassWeapon; +class PClassActor; class AWeapon; class FWeaponSlot @@ -12,13 +12,13 @@ public: FWeaponSlot &operator= (const FWeaponSlot &other) { Weapons = other.Weapons; return *this; } void Clear() { Weapons.Clear(); } bool AddWeapon (const char *type); - bool AddWeapon (PClassWeapon *type); + bool AddWeapon (PClassActor *type); void AddWeaponList (const char *list, bool clear); AWeapon *PickWeapon (player_t *player, bool checkammo = false); int Size () const { return (int)Weapons.Size(); } - int LocateWeapon (PClassWeapon *type); + int LocateWeapon (PClassActor *type); - inline PClassWeapon *GetWeapon (int index) const + inline PClassActor *GetWeapon (int index) const { if ((unsigned)index < Weapons.Size()) { @@ -35,7 +35,7 @@ public: private: struct WeaponInfo { - PClassWeapon *Type; + PClassActor *Type; int Position; }; void SetInitialPositions(); @@ -61,8 +61,8 @@ struct FWeaponSlots AWeapon *PickPrevWeapon (player_t *player); void Clear (); - bool LocateWeapon (PClassWeapon *type, int *const slot, int *const index); - ESlotDef AddDefaultWeapon (int slot, PClassWeapon *type); + bool LocateWeapon (PClassActor *type, int *const slot, int *const index); + ESlotDef AddDefaultWeapon (int slot, PClassActor *type); void AddExtraWeapons(); void SetFromGameInfo(); void SetFromPlayer(PClassPlayerPawn *type); @@ -72,37 +72,23 @@ struct FWeaponSlots int RestoreSlots (FConfigFile *config, const char *section); void PrintSettings(); - void AddSlot(int slot, PClassWeapon *type, bool feedback); - void AddSlotDefault(int slot, PClassWeapon *type, bool feedback); + void AddSlot(int slot, PClassActor *type, bool feedback); + void AddSlotDefault(int slot, PClassActor *type, bool feedback); }; void P_PlaybackKeyConfWeapons(FWeaponSlots *slots); -void Net_WriteWeapon(PClassWeapon *type); -PClassWeapon *Net_ReadWeapon(BYTE **stream); +void Net_WriteWeapon(PClassActor *type); +PClassActor *Net_ReadWeapon(BYTE **stream); void P_SetupWeapons_ntohton(); void P_WriteDemoWeaponsChunk(BYTE **demo); void P_ReadDemoWeaponsChunk(BYTE **demo); -// A weapon is just that. -class PClassWeapon : public PClassInventory -{ - DECLARE_CLASS(PClassWeapon, PClassInventory); -protected: - virtual void DeriveData(PClass *newclass); -public: - PClassWeapon(); - void Finalize(FStateDefinitions &statedef); - - int SlotNumber; - int SlotPriority; -}; - class AWeapon : public AStateProvider { - DECLARE_CLASS_WITH_META(AWeapon, AStateProvider, PClassWeapon) + DECLARE_CLASS(AWeapon, AStateProvider) HAS_OBJECT_POINTERS public: DWORD WeaponFlags; @@ -113,7 +99,7 @@ public: int Kickback; float YAdjust; // For viewing the weapon fullscreen (visual only so no need to be a double) FSoundIDNoInit UpSound, ReadySound; // Sounds when coming up and idle - PClassWeapon *SisterWeaponType; // Another weapon to pick up with this one + PClassActor *SisterWeaponType; // Another weapon to pick up with this one PClassActor *ProjectileType; // Projectile used by primary attack PClassActor *AltProjectileType; // Projectile used by alternate attack int SelectionOrder; // Lower-numbered weapons get picked first @@ -123,6 +109,8 @@ public: int BobStyle; // [XA] Bobbing style. Defines type of bobbing (e.g. Normal, Alpha) (visual only so no need to be a double) float BobSpeed; // [XA] Bobbing speed. Defines how quickly a weapon bobs. float BobRangeX, BobRangeY; // [XA] Bobbing range. Defines how far a weapon bobs in either direction. + int SlotNumber; + int SlotPriority; // In-inventory instance variables TObjPtr Ammo1, Ammo2; @@ -135,7 +123,8 @@ public: virtual void MarkPrecacheSounds() const; - virtual void Serialize(FSerializer &arc) override; + void Finalize(FStateDefinitions &statedef) override; + void Serialize(FSerializer &arc) override; void PostMorphWeapon(); diff --git a/src/info.cpp b/src/info.cpp index a424c890f..c86486b5e 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -429,20 +429,20 @@ void PClassActor::SetDropItems(DDropItem *drops) // //========================================================================== -void PClassActor::Finalize(FStateDefinitions &statedef) +void AActor::Finalize(FStateDefinitions &statedef) { - AActor *defaults = (AActor*)Defaults; + AActor *defaults = this; try { - statedef.FinishStates(this, defaults); + statedef.FinishStates(GetClass(), defaults); } catch (CRecoverableError &) { statedef.MakeStateDefines(NULL); throw; } - statedef.InstallStates(this, defaults); + statedef.InstallStates(GetClass(), defaults); statedef.MakeStateDefines(NULL); } diff --git a/src/info.h b/src/info.h index 4a6baa671..3a20994f5 100644 --- a/src/info.h +++ b/src/info.h @@ -259,7 +259,6 @@ public: size_t PropagateMark(); bool SetReplacement(FName replaceName); void SetDropItems(DDropItem *drops); - virtual void Finalize(FStateDefinitions &statedef); FState *FindState(int numnames, FName *names, bool exact=false) const; FState *FindStateByString(const char *name, bool exact=false); diff --git a/src/oplsynth/muslib.h b/src/oplsynth/muslib.h index e4b4ac5cb..9091c8536 100644 --- a/src/oplsynth/muslib.h +++ b/src/oplsynth/muslib.h @@ -83,26 +83,9 @@ class FileReader; /* Global Definitions */ -#define MLVERSION 0x0175 -#define MLVERSIONSTR "1.75" -extern char MLversion[]; -extern char MLcopyright[]; - #define CHANNELS 16 // total channels 0..CHANNELS-1 #define PERCUSSION 15 // percussion channel -/* MUS file header structure */ -struct MUSheader { - char ID[4]; // identifier "MUS" 0x1A - WORD scoreLen; // score length - WORD scoreStart; // score start - WORD channels; // primary channels - WORD sec_channels; // secondary channels (??) - WORD instrCnt; // used instrument count - WORD dummy; -// WORD instruments[...]; // table of used instruments -}; - /* OPL2 instrument */ struct OPL2instrument { /*00*/ BYTE trem_vibr_1; /* OP 1: tremolo/vibrato/sustain/KSR/multi */ @@ -131,7 +114,6 @@ struct OP2instrEntry { }; #define FL_FIXED_PITCH 0x0001 // note has fixed pitch (see below) -#define FL_UNKNOWN 0x0002 // ??? (used in instrument #65 only) #define FL_DOUBLE_VOICE 0x0004 // use two voices instead of one diff --git a/src/r_data/renderstyle.cpp b/src/r_data/renderstyle.cpp index 6e656f715..5c9dcc429 100644 --- a/src/r_data/renderstyle.cpp +++ b/src/r_data/renderstyle.cpp @@ -103,7 +103,7 @@ double GetAlpha(int type, double alpha) switch (type) { case STYLEALPHA_Zero: return 0; - case STYLEALPHA_One: return OPAQUE; + case STYLEALPHA_One: return 1.; case STYLEALPHA_Src: return alpha; case STYLEALPHA_InvSrc: return 1. - alpha; default: return 0; diff --git a/src/r_data/renderstyle.h b/src/r_data/renderstyle.h index 63e0856cd..364cf579e 100644 --- a/src/r_data/renderstyle.h +++ b/src/r_data/renderstyle.h @@ -44,10 +44,6 @@ enum { OPAQUE = 65536, - TRANSLUC25 = (OPAQUE / 4), - TRANSLUC33 = (OPAQUE / 3), - TRANSLUC66 = ((OPAQUE * 2) / 3), - TRANSLUC75 = ((OPAQUE * 3) / 4), }; // Legacy render styles diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 4d6376f3b..a3dc066e9 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -542,7 +542,7 @@ ExpEmit FxConstant::Emit(VMFunctionBuilder *build) { tag = ATAG_STATE; } - else if (value.Type->GetLoadOp() == OP_LO) + else if (value.Type->GetLoadOp() != OP_LP) { tag = ATAG_OBJECT; } @@ -6356,7 +6356,7 @@ ExpEmit FxClassDefaults::Emit(VMFunctionBuilder *build) ob.Free(build); ExpEmit meta(build, REGT_POINTER); build->Emit(OP_META, meta.RegNum, ob.RegNum); - build->Emit(OP_LO, meta.RegNum, meta.RegNum, build->GetConstantInt(myoffsetof(PClass, Defaults))); + build->Emit(OP_LOS, meta.RegNum, meta.RegNum, build->GetConstantInt(myoffsetof(PClass, Defaults))); return meta; } @@ -8874,7 +8874,7 @@ ExpEmit FxGetParentClass::Emit(VMFunctionBuilder *build) op.Free(build); } ExpEmit to(build, REGT_POINTER); - build->Emit(OP_LO, to.RegNum, op.RegNum, build->GetConstantInt(myoffsetof(PClass, ParentClass))); + build->Emit(OP_LOS, to.RegNum, op.RegNum, build->GetConstantInt(myoffsetof(PClass, ParentClass))); return to; } @@ -8946,7 +8946,7 @@ ExpEmit FxGetDefaultByType::Emit(VMFunctionBuilder *build) build->Emit(OP_LKP, to.RegNum, op.RegNum); op = to; } - build->Emit(OP_LO, to.RegNum, op.RegNum, build->GetConstantInt(myoffsetof(PClass, Defaults))); + build->Emit(OP_LOS, to.RegNum, op.RegNum, build->GetConstantInt(myoffsetof(PClass, Defaults))); return to; } @@ -10683,8 +10683,7 @@ ExpEmit FxLocalVariableDeclaration::Emit(VMFunctionBuilder *build) case REGT_POINTER: { - bool isobject = ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer)) || (ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PClass))); - build->Emit(OP_LKP, RegNum, build->GetConstantAddress(constval->GetValue().GetPointer(), isobject ? ATAG_OBJECT : ATAG_GENERIC)); + build->Emit(OP_LKP, RegNum, build->GetConstantAddress(constval->GetValue().GetPointer(), ValueType->GetLoadOp() != OP_LP ? ATAG_OBJECT : ATAG_GENERIC)); break; } case REGT_STRING: @@ -10824,7 +10823,7 @@ ExpEmit FxStaticArray::Emit(VMFunctionBuilder *build) { TArray cvalues; for (auto v : values) cvalues.Push(static_cast(v)->GetValue().GetPointer()); - StackOffset = build->AllocConstantsAddress(cvalues.Size(), &cvalues[0], ElementType->GetLoadOp() == OP_LO ? ATAG_OBJECT : ATAG_GENERIC); + StackOffset = build->AllocConstantsAddress(cvalues.Size(), &cvalues[0], ElementType->GetLoadOp() != OP_LP ? ATAG_OBJECT : ATAG_GENERIC); break; } } diff --git a/src/scripting/decorate/thingdef_parse.cpp b/src/scripting/decorate/thingdef_parse.cpp index 505585937..fc411186a 100644 --- a/src/scripting/decorate/thingdef_parse.cpp +++ b/src/scripting/decorate/thingdef_parse.cpp @@ -1155,7 +1155,7 @@ static void ParseActor(FScanner &sc, PNamespace *ns) } try { - info->Finalize(bag.statedef); + GetDefaultByType(info)->Finalize(bag.statedef); } catch (CRecoverableError &err) { diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 8786a31bf..97f6ae10b 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -1141,19 +1141,8 @@ DEFINE_ACTION_FUNCTION(FStringStruct, AppendFormat) DEFINE_ACTION_FUNCTION(FStringStruct, Mid) { PARAM_SELF_STRUCT_PROLOGUE(FString); - PARAM_INT(ipos); - PARAM_INT(ilen); - // validate. we don't want to crash if someone passes negative values. - // with size_t it's handled naturally I think, as it's unsigned, but not in ZScript. - if (ipos < 0) ipos = 0; - if (ilen < 0) ilen = 0; - // convert to size_t to prevent overflows here - size_t slen = self->Len(); - size_t pos = (size_t)ipos; - size_t len = (size_t)ilen; - if (pos > slen) pos = slen - 1; - if (pos + len > slen) - len = slen - pos; + PARAM_UINT(pos); + PARAM_UINT(len); FString s = self->Mid(pos, len); ACTION_RETURN_STRING(s); } @@ -1161,7 +1150,7 @@ DEFINE_ACTION_FUNCTION(FStringStruct, Mid) DEFINE_ACTION_FUNCTION(FStringStruct, Len) { PARAM_SELF_STRUCT_PROLOGUE(FString); - ACTION_RETURN_INT(self->Len()); + ACTION_RETURN_INT((int)self->Len()); } // CharAt and CharCodeAt is how JS does it, and JS is similar here in that it doesn't have char type as int. @@ -1169,7 +1158,7 @@ DEFINE_ACTION_FUNCTION(FStringStruct, CharAt) { PARAM_SELF_STRUCT_PROLOGUE(FString); PARAM_INT(pos); - int slen = self->Len(); + int slen = (int)self->Len(); if (pos < 0 || pos >= slen) ACTION_RETURN_STRING(""); ACTION_RETURN_STRING(FString((*self)[pos])); @@ -1179,7 +1168,7 @@ DEFINE_ACTION_FUNCTION(FStringStruct, CharCodeAt) { PARAM_SELF_STRUCT_PROLOGUE(FString); PARAM_INT(pos); - int slen = self->Len(); + int slen = (int)self->Len(); if (pos < 0 || pos >= slen) ACTION_RETURN_INT(0); ACTION_RETURN_INT((*self)[pos]); diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index 682300147..859ccb3f5 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -560,7 +560,7 @@ DEFINE_PROPERTY(skip_super, 0, Actor) return; } - memcpy ((void *)defaults, (void *)GetDefault(), sizeof(AActor)); + *defaults = *GetDefault(); ResetBaggage (&bag, RUNTIME_CLASS(AActor)); } @@ -2065,8 +2065,7 @@ DEFINE_CLASS_PROPERTY(bobrangey, F, Weapon) DEFINE_CLASS_PROPERTY(slotnumber, I, Weapon) { PROP_INT_PARM(i, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassWeapon))); - static_cast(info)->SlotNumber = i; + defaults->SlotNumber = i; } //========================================================================== @@ -2075,8 +2074,7 @@ DEFINE_CLASS_PROPERTY(slotnumber, I, Weapon) DEFINE_CLASS_PROPERTY(slotpriority, F, Weapon) { PROP_DOUBLE_PARM(i, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassWeapon))); - static_cast(info)->SlotPriority = int(i*65536); + defaults->SlotPriority = int(i*65536); } //========================================================================== diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index 1a5c10b4e..8b8e3c864 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -997,6 +997,7 @@ void NullParam(const char *varname); // For required parameters. #define PARAM_INT_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); int x = param[p].i; +#define PARAM_UINT_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); unsigned x = param[p].i; #define PARAM_BOOL_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); bool x = !!param[p].i; #define PARAM_NAME_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); FName x = ENamedName(param[p].i); #define PARAM_SOUND_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); FSoundID x = param[p].i; @@ -1040,6 +1041,7 @@ void NullParam(const char *varname); #define PARAM_PROLOGUE int paramnum = -1; #define PARAM_INT(x) ++paramnum; PARAM_INT_AT(paramnum,x) +#define PARAM_UINT(x) ++paramnum; PARAM_UINT_AT(paramnum,x) #define PARAM_BOOL(x) ++paramnum; PARAM_BOOL_AT(paramnum,x) #define PARAM_NAME(x) ++paramnum; PARAM_NAME_AT(paramnum,x) #define PARAM_SOUND(x) ++paramnum; PARAM_SOUND_AT(paramnum,x) diff --git a/src/scripting/vm/vmexec.h b/src/scripting/vm/vmexec.h index 38dbbc411..b9f8e81ca 100644 --- a/src/scripting/vm/vmexec.h +++ b/src/scripting/vm/vmexec.h @@ -347,6 +347,17 @@ begin: GETADDR(PA,RC,X_WRITE_NIL); *(void **)ptr = reg.a[B]; NEXTOP; + OP(SO): + ASSERTA(a); ASSERTA(B); ASSERTKD(C); + GETADDR(PA,KC,X_WRITE_NIL); + *(void **)ptr = reg.a[B]; + GC::WriteBarrier((DObject*)*(void **)ptr); + NEXTOP; + OP(SO_R): + ASSERTA(a); ASSERTA(B); ASSERTD(C); + GETADDR(PA,RC,X_WRITE_NIL); + GC::WriteBarrier((DObject*)*(void **)ptr); + NEXTOP; OP(SV2): ASSERTA(a); ASSERTF(B+1); ASSERTKD(C); GETADDR(PA,KC,X_WRITE_NIL); diff --git a/src/scripting/vm/vmops.h b/src/scripting/vm/vmops.h index 3fc3d7643..7128f1e43 100644 --- a/src/scripting/vm/vmops.h +++ b/src/scripting/vm/vmops.h @@ -70,6 +70,8 @@ xx(SS, ss, RPRSKI, SS_R, 4, REGT_INT), // store string xx(SS_R, ss, RPRSRI, NOP, 0, 0), xx(SP, sp, RPRPKI, SP_R, 4, REGT_INT), // store pointer xx(SP_R, sp, RPRPRI, NOP, 0, 0), +xx(SO, sp, RPRPKI, SO_R, 4, REGT_INT), // store object pointer with write barrier (only needed for non thinkers and non types +xx(SO_R, sp, RPRPRI, NOP, 0, 0), xx(SV2, sv2, RPRVKI, SV2_R, 4, REGT_INT), // store vector2 xx(SV2_R, sv2, RPRVRI, NOP, 0, 0), xx(SV3, sv3, RPRVKI, SV3_R, 4, REGT_INT), // store vector3 diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 44428ab88..93f41746f 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -2447,19 +2447,6 @@ void ZCCCompiler::CompileStates() continue; } - // Same here, hack in the DVMObject as they weren't in the list originally - // TODO: process them in a non hackish way obviously - if (c->Type()->bRuntimeClass == true && c->Type()->ParentClass->bRuntimeClass == false) - { - auto vmtype = static_cast(c->Type()->ParentClass); - if (vmtype->StateList == nullptr) - { - FStateDefinitions vmstates; - vmstates.MakeStateDefines(dyn_cast(vmtype->ParentClass)); - vmtype->Finalize(vmstates); - } - } - FString statename; // The state builder wants the label as one complete string, not separated into tokens. FStateDefinitions statedef; statedef.MakeStateDefines(dyn_cast(c->Type()->ParentClass)); @@ -2658,7 +2645,7 @@ void ZCCCompiler::CompileStates() } try { - static_cast(c->Type())->Finalize(statedef); + GetDefaultByType(c->Type())->Finalize(statedef); } catch (CRecoverableError &err) { diff --git a/src/swrenderer/viewport/r_spritedrawer.cpp b/src/swrenderer/viewport/r_spritedrawer.cpp index 441eedc0a..46c209f99 100644 --- a/src/swrenderer/viewport/r_spritedrawer.cpp +++ b/src/swrenderer/viewport/r_spritedrawer.cpp @@ -387,7 +387,7 @@ namespace swrenderer if (style.BlendOp == STYLEOP_Shadow) { style = LegacyRenderStyles[STYLE_TranslucentStencil]; - alpha = TRANSLUC33; + alpha = OPAQUE / 3; color = 0; } @@ -401,7 +401,7 @@ namespace swrenderer } else if (style.Flags & STYLEF_Alpha1) { - alpha = FRACUNIT; + alpha = OPAQUE; } else { diff --git a/wadsrc/static/zscript/inventory/weapons.txt b/wadsrc/static/zscript/inventory/weapons.txt index 5634c4c49..7bda52e52 100644 --- a/wadsrc/static/zscript/inventory/weapons.txt +++ b/wadsrc/static/zscript/inventory/weapons.txt @@ -43,6 +43,8 @@ class Weapon : StateProvider native Weapon.BobSpeed 1.0; Weapon.BobRangeX 1.0; Weapon.BobRangeY 1.0; + Weapon.SlotNumber -1; + Weapon.SlotPriority 32767; +WEAPONSPAWN DefaultStateUsage SUF_ACTOR|SUF_OVERLAY|SUF_WEAPON; }