diff --git a/src/d_player.h b/src/d_player.h index e743a7b4f..650799f6d 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -436,6 +436,7 @@ public: AWeapon *ReadyWeapon; AWeapon *PendingWeapon; // WP_NOCHANGE if not changing + TObjPtr psprites; // view sprites (gun, etc) int cheats; // bit flags int timefreezer; // Player has an active time freezer @@ -528,7 +529,6 @@ public: int GetSpawnClass(); // PSprite layers - DPSprite *psprites; // view sprites (gun, etc) void TickPSprites(); void DestroyPSprites(); DPSprite *GetPSprite(psprnum_t layer); // Used ONLY for compatibility with the old hardcoded layers. diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index 11433b6f8..f2ab02b82 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -113,12 +113,25 @@ END_POINTERS DPSprite::DPSprite(player_t *owner, AInventory *caller, int id) : processPending(true), firstTic(true), Owner(owner), Caller(caller), ID(id) { - DPSprite **prev = &Owner->psprites; - while (*prev && (*prev)->ID < ID) - prev = &(*prev)->Next; - - Next = *prev; - *prev = this; + DPSprite *prev = nullptr; + DPSprite *next = Owner->psprites; + while (next != nullptr && next->ID < ID) + { + prev = next; + next = next->Next; + } + Next = next; + GC::WriteBarrier(this, next); + if (prev == NULL) + { + Owner->psprites = this; + GC::WriteBarrier(this); + } + else + { + prev->Next = this; + GC::WriteBarrier(prev, this); + } if (Next && Next->ID == ID && ID != 0) Next->Destroy(); // Replace it. @@ -1349,10 +1362,13 @@ void DPSprite::Serialize(FArchive &arc) void player_t::DestroyPSprites() { DPSprite *pspr = psprites; + psprites = nullptr; while (pspr) { + DPSprite *next = pspr->Next; + pspr->Next = nullptr; pspr->Destroy(); - pspr = pspr->Next; + pspr = next; } } @@ -1364,12 +1380,27 @@ void player_t::DestroyPSprites() void DPSprite::Destroy() { - DPSprite **prev = &Owner->psprites; - while (*prev != this) - prev = &(*prev)->Next; - - *prev = Next; + // Do not crash if this gets called on partially initialized objects. + if (Owner != nullptr && Owner->psprites != nullptr) + { + if (Owner->psprites != this) + { + DPSprite *prev = Owner->psprites; + while (prev != nullptr && prev->Next != this) + prev = prev->Next; + if (prev != nullptr && prev->Next == this) + { + prev->Next = Next; + GC::WriteBarrier(prev, Next); + } + } + else + { + Owner->psprites = Next; + GC::WriteBarrier(Next); + } + } Super::Destroy(); } diff --git a/src/p_pspr.h b/src/p_pspr.h index 87e78ef1f..5f9292d98 100644 --- a/src/p_pspr.h +++ b/src/p_pspr.h @@ -66,8 +66,8 @@ public: int GetSprite() const { return Sprite; } int GetFrame() const { return Frame; } FState* GetState() const { return State; } - DPSprite* GetNext() const { return Next; } - TObjPtr GetCaller() const { return Caller; } + DPSprite* GetNext() { return Next; } + AInventory* GetCaller() { return Caller; } double x, y; double oldx, oldy; @@ -82,7 +82,7 @@ private: void Destroy(); TObjPtr Caller; - DPSprite *Next; + TObjPtr Next; player_t *Owner; FState *State; int Sprite;