diff --git a/src/common/objects/dobject.cpp b/src/common/objects/dobject.cpp index 5b2658a70..b9817a919 100644 --- a/src/common/objects/dobject.cpp +++ b/src/common/objects/dobject.cpp @@ -417,6 +417,67 @@ size_t DObject::PropagateMark() // //========================================================================== +void DObject::ClearNativePointerFields(const TArray& types) +{ + auto cls = GetClass(); + if (cls->VMType == nullptr) + return; + + auto it = cls->VMType->Symbols.GetIterator(); + TMap::Pair* sym = nullptr; + while (it.NextPair(sym)) + { + auto field = dyn_cast(sym->Value); + if (field == nullptr) + continue; + + PType* base = field->Type; + PType* t = base; + if (base->isArray() && !base->isStaticArray()) + t = static_cast(base)->ElementType; + else if (base->isDynArray()) + t = static_cast(base)->ElementType; + else if (base->isMap()) + t = static_cast(base)->ValueType; + + if (!t->isRealPointer()) + continue; + + auto pType = static_cast(t)->PointedType; + if (!pType->isStruct() || !static_cast(pType)->isNative || types.Find(static_cast(pType)->TypeName) >= types.Size()) + continue; + + if (base->isArray() && !base->isStaticArray()) + { + auto arr = (void**)ScriptVar(sym->Key, nullptr); + const size_t count = static_cast(base)->ElementCount; + for (size_t i = 0u; i < count; ++i) + arr[i] = nullptr; + } + else if (base->isDynArray()) + { + static_cast*>(ScriptVar(sym->Key, nullptr))->Clear(); + } + else if (base->isMap()) + { + if (static_cast(base)->BackingClass == PMap::MAP_I32_PTR) + static_cast*>(ScriptVar(sym->Key, nullptr))->Clear(); + else + static_cast*>(ScriptVar(sym->Key, nullptr))->Clear(); + } + else + { + PointerVar(sym->Key) = nullptr; + } + } +} + +//========================================================================== +// +// +// +//========================================================================== + template static void MapPointerSubstitution(M *map, size_t &changed, DObject *old, DObject *notOld, const bool shouldSwap) { diff --git a/src/common/objects/dobject.h b/src/common/objects/dobject.h index 9925cb88e..3b414bdd9 100644 --- a/src/common/objects/dobject.h +++ b/src/common/objects/dobject.h @@ -245,6 +245,9 @@ public: template T*& PointerVar(FName field); inline int* IntArray(FName field); + // Make sure native data is wiped correctly since it has no read barriers. + void ClearNativePointerFields(const TArray& types); + // This is only needed for swapping out PlayerPawns and absolutely nothing else! virtual size_t PointerSubstitution (DObject *old, DObject *notOld, bool nullOnFail); diff --git a/src/common/utility/tarray.h b/src/common/utility/tarray.h index 3a6bd76e9..f1cfc4f7f 100644 --- a/src/common/utility/tarray.h +++ b/src/common/utility/tarray.h @@ -234,8 +234,8 @@ public: TArray (std::initializer_list list) { - Most = list.size; - Count = list.size; + Most = list.size(); + Count = list.size(); if (Count > 0) { diff --git a/src/g_level.cpp b/src/g_level.cpp index 9ea40c929..438d6ce29 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -1646,6 +1646,9 @@ void FLevelLocals::StartTravel () inv->UnlinkFromWorld (nullptr); inv->UnlinkBehaviorsFromLevel(); inv->DeleteAttachedLights(); + tid = inv->tid; + inv->SetTID(0); + inv->tid = tid; } } } @@ -1751,7 +1754,7 @@ int FLevelLocals::FinishTravel () pawn->LinkBehaviorsToLevel(); pawn->ClearInterpolation(); pawn->ClearFOVInterpolation(); - const int tid = pawn->tid; // Save TID (actor isn't linked into the hash chain yet) + int tid = pawn->tid; // Save TID (actor isn't linked into the hash chain yet) pawn->tid = 0; // Reset TID pawn->SetTID(tid); // Set TID (and link actor into the hash chain) pawn->SetState(pawn->SpawnState); @@ -1763,6 +1766,9 @@ int FLevelLocals::FinishTravel () inv->LinkToWorld (nullptr); P_FindFloorCeiling(inv, FFCF_ONLYSPAWNPOS); inv->LinkBehaviorsToLevel(); + tid = inv->tid; + inv->tid = 0; + inv->SetTID(tid); IFVIRTUALPTRNAME(inv, NAME_Inventory, Travelled) { diff --git a/src/namedef_custom.h b/src/namedef_custom.h index a8ae6414c..87675346b 100644 --- a/src/namedef_custom.h +++ b/src/namedef_custom.h @@ -568,6 +568,13 @@ xx(Offsety) xx(Texturetop) xx(Texturebottom) xx(Texturemiddle) +xx(SectorPortal) +xx(LinePortal) +xx(Vertex) +xx(Side) +xx(Line) +xx(SecPlane) +xx(F3DFloor) xx(Sector) xx(Heightfloor) xx(Heightceiling) diff --git a/src/p_setup.cpp b/src/p_setup.cpp index b698b3eec..070de05e4 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -293,9 +293,16 @@ void FLevelLocals::ClearLevelData(bool fullgc) auto it = GetThinkerIterator(NAME_None, STAT_TRAVELLING); for (AActor *actor = it.Next(); actor != nullptr; actor = it.Next()) { + actor->BlockingMobj = nullptr; actor->BlockingLine = actor->MovementBlockingLine = nullptr; actor->BlockingFloor = actor->BlockingCeiling = actor->Blocking3DFloor = nullptr; } + + // Make sure map data gets cleared appropriately so any leftover Objects aren't pointing + // towards anything invalid. + TArray fieldTypes = { NAME_SectorPortal, NAME_LinePortal, NAME_Vertex, NAME_Side, NAME_Line, NAME_SecPlane, NAME_F3DFloor, NAME_Sector }; + for (DObject* probe = GC::Root; probe != nullptr; probe = probe->ObjNext) + probe->ClearNativePointerFields(fieldTypes); } interpolator.ClearInterpolations(); // [RH] Nothing to interpolate on a fresh level.