- made the corpse queue a simple array in FLevelLocals.

I have to wonder why it had to use such a complicated implementation that provided no advantages whatsoever.
The new code is just 1/5th of the old one's size and much closer to Hexen's original implementation which also was a simple array but with no means to resize the queue.
This commit is contained in:
Christoph Oelckers 2019-01-05 10:53:06 +01:00
parent dab68184f5
commit a0ad4ea193
6 changed files with 27 additions and 116 deletions

View file

@ -190,13 +190,6 @@ public:
assert(q != NULL);
return *q;
}
T *operator&() throw()
{
// Does not perform a read barrier. The only real use for this is with
// the DECLARE_POINTER macro, where a read barrier would be a very bad
// thing.
return &pp;
}
T operator->() throw()
{
return GC::ReadBarrier(pp);

View file

@ -1971,6 +1971,10 @@ void FLevelLocals::Mark()
GC::Mark(SpotState);
GC::Mark(FraggleScriptThinker);
canvasTextureInfo.Mark();
for (auto &c : CorpseQueue)
{
GC::Mark(c);
}
for (auto &s : sectorPortals)
{
GC::Mark(s.mSkybox);

View file

@ -88,109 +88,21 @@ void A_Unblock(AActor *self, bool drop)
//
//----------------------------------------------------------------------------
// Corpse queue for monsters - this should be saved out
class DCorpsePointer : public DThinker
{
DECLARE_CLASS (DCorpsePointer, DThinker)
HAS_OBJECT_POINTERS
public:
DCorpsePointer (AActor *ptr);
void Queue();
void OnDestroy() override;
void Serialize(FSerializer &arc);
TObjPtr<AActor*> Corpse;
uint32_t Count; // Only the first corpse pointer's count is valid.
private:
DCorpsePointer () {}
};
IMPLEMENT_CLASS(DCorpsePointer, false, true)
IMPLEMENT_POINTERS_START(DCorpsePointer)
IMPLEMENT_POINTER(Corpse)
IMPLEMENT_POINTERS_END
CUSTOM_CVAR(Int, sv_corpsequeuesize, 64, CVAR_ARCHIVE|CVAR_SERVERINFO)
{
if (self > 0)
{
TThinkerIterator<DCorpsePointer> iterator (STAT_CORPSEPOINTER);
DCorpsePointer *first = iterator.Next ();
while (first != NULL && first->Count > (uint32_t)self)
auto &corpsequeue = level.CorpseQueue;
while (corpsequeue.Size() > (unsigned)self)
{
DCorpsePointer *next = iterator.Next ();
first->Destroy ();
first = next;
AActor *corpse = corpsequeue[0];
if (corpse) corpse->Destroy();
corpsequeue.Delete(0);
}
}
}
DCorpsePointer::DCorpsePointer(AActor *ptr)
: DThinker(STAT_CORPSEPOINTER), Corpse(ptr)
{
Count = 0;
}
void DCorpsePointer::Queue()
{
// Thinkers are added to the end of their respective lists, so
// the first thinker in the list is the oldest one.
TThinkerIterator<DCorpsePointer> iterator (STAT_CORPSEPOINTER);
DCorpsePointer *first = iterator.Next ();
if (first != nullptr)
{
if (first != this)
{
if (first->Count >= (uint32_t)sv_corpsequeuesize)
{
DCorpsePointer *next = iterator.Next();
first->Destroy();
first = next;
}
}
++first->Count;
}
}
void DCorpsePointer::OnDestroy ()
{
// Store the count of corpses in the first thinker in the list
TThinkerIterator<DCorpsePointer> iterator (STAT_CORPSEPOINTER);
DCorpsePointer *first = iterator.Next ();
// During a serialization unwind the thinker list won't be available.
if (first != nullptr)
{
int prevCount = first->Count;
if (first == this)
{
first = iterator.Next();
}
if (first != NULL)
{
first->Count = prevCount - 1;
}
}
if (Corpse != NULL)
{
Corpse->Destroy();
}
Super::OnDestroy();
}
void DCorpsePointer::Serialize(FSerializer &arc)
{
Super::Serialize(arc);
arc("corpse", Corpse)
("count", Count);
}
// throw another corpse on the queue
DEFINE_ACTION_FUNCTION(AActor, A_QueueCorpse)
@ -199,8 +111,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_QueueCorpse)
if (sv_corpsequeuesize > 0)
{
auto p = Create<DCorpsePointer> (self);
p->Queue();
auto &corpsequeue = level.CorpseQueue;
while (corpsequeue.Size() >= (unsigned)sv_corpsequeuesize)
{
AActor *corpse = corpsequeue[0];
if (corpse) corpse->Destroy();
corpsequeue.Delete(0);
}
corpsequeue.Push(self);
}
return 0;
}
@ -210,17 +128,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_DeQueueCorpse)
{
PARAM_SELF_PROLOGUE(AActor);
TThinkerIterator<DCorpsePointer> iterator (STAT_CORPSEPOINTER);
DCorpsePointer *corpsePtr;
while ((corpsePtr = iterator.Next()) != NULL)
auto &corpsequeue = level.CorpseQueue;
auto index = corpsequeue.FindEx([=](auto &element) { return element == self; });
if (index < corpsequeue.Size())
{
if (corpsePtr->Corpse == self)
{
corpsePtr->Corpse = NULL;
corpsePtr->Destroy ();
return 0;
}
corpsequeue.Delete(index);
}
return 0;
}

View file

@ -594,7 +594,7 @@ void DBaseStatusBar::Tick ()
for (size_t i = 0; i < countof(Messages); ++i)
{
DHUDMessageBase *msg = Messages[i];
DHUDMessageBase **prev = &Messages[i];
TObjPtr<DHUDMessageBase *>*prev = &Messages[i];
while (msg)
{
@ -657,7 +657,7 @@ void DBaseStatusBar::CallTick()
void DBaseStatusBar::AttachMessage (DHUDMessageBase *msg, uint32_t id, int layer)
{
DHUDMessageBase *old = NULL;
DHUDMessageBase **prev;
TObjPtr<DHUDMessageBase *>*prev;
old = (id == 0 || id == 0xFFFFFFFF) ? NULL : DetachMessage (id);
if (old != NULL)
@ -698,7 +698,7 @@ DHUDMessageBase *DBaseStatusBar::DetachMessage (DHUDMessageBase *msg)
for (size_t i = 0; i < countof(Messages); ++i)
{
DHUDMessageBase *probe = Messages[i];
DHUDMessageBase **prev = &Messages[i];
TObjPtr<DHUDMessageBase *>*prev = &Messages[i];
while (probe && probe != msg)
{
@ -720,7 +720,7 @@ DHUDMessageBase *DBaseStatusBar::DetachMessage (uint32_t id)
for (size_t i = 0; i < countof(Messages); ++i)
{
DHUDMessageBase *probe = Messages[i];
DHUDMessageBase **prev = &Messages[i];
TObjPtr<DHUDMessageBase *>*prev = &Messages[i];
while (probe && probe->SBarID != id)
{

View file

@ -976,6 +976,7 @@ void G_SerializeLevel(FSerializer &arc, bool hubload)
("level.bodyqueslot", level.bodyqueslot)
("level.spawnindex", level.spawnindex)
.Array("level.bodyque", level.bodyque, level.BODYQUESIZE)
("level.corpsequeue", level.CorpseQueue)
("level.spotstate", level.SpotState)
("level.fragglethinker", level.FraggleScriptThinker);

View file

@ -275,6 +275,7 @@ void FLevelLocals::ClearLevelData()
ClearPortals();
SpotState = nullptr;
CorpseQueue.Clear();
canvasTextureInfo.EmptyList();
sections.Clear();
segs.Clear();