- 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); assert(q != NULL);
return *q; 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() T operator->() throw()
{ {
return GC::ReadBarrier(pp); return GC::ReadBarrier(pp);

View file

@ -1971,6 +1971,10 @@ void FLevelLocals::Mark()
GC::Mark(SpotState); GC::Mark(SpotState);
GC::Mark(FraggleScriptThinker); GC::Mark(FraggleScriptThinker);
canvasTextureInfo.Mark(); canvasTextureInfo.Mark();
for (auto &c : CorpseQueue)
{
GC::Mark(c);
}
for (auto &s : sectorPortals) for (auto &s : sectorPortals)
{ {
GC::Mark(s.mSkybox); 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) CUSTOM_CVAR(Int, sv_corpsequeuesize, 64, CVAR_ARCHIVE|CVAR_SERVERINFO)
{ {
if (self > 0) if (self > 0)
{ {
TThinkerIterator<DCorpsePointer> iterator (STAT_CORPSEPOINTER); auto &corpsequeue = level.CorpseQueue;
DCorpsePointer *first = iterator.Next (); while (corpsequeue.Size() > (unsigned)self)
while (first != NULL && first->Count > (uint32_t)self)
{ {
DCorpsePointer *next = iterator.Next (); AActor *corpse = corpsequeue[0];
first->Destroy (); if (corpse) corpse->Destroy();
first = next; 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 // throw another corpse on the queue
DEFINE_ACTION_FUNCTION(AActor, A_QueueCorpse) DEFINE_ACTION_FUNCTION(AActor, A_QueueCorpse)
@ -199,8 +111,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_QueueCorpse)
if (sv_corpsequeuesize > 0) if (sv_corpsequeuesize > 0)
{ {
auto p = Create<DCorpsePointer> (self); auto &corpsequeue = level.CorpseQueue;
p->Queue(); while (corpsequeue.Size() >= (unsigned)sv_corpsequeuesize)
{
AActor *corpse = corpsequeue[0];
if (corpse) corpse->Destroy();
corpsequeue.Delete(0);
}
corpsequeue.Push(self);
} }
return 0; return 0;
} }
@ -210,17 +128,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_DeQueueCorpse)
{ {
PARAM_SELF_PROLOGUE(AActor); PARAM_SELF_PROLOGUE(AActor);
TThinkerIterator<DCorpsePointer> iterator (STAT_CORPSEPOINTER); auto &corpsequeue = level.CorpseQueue;
DCorpsePointer *corpsePtr; auto index = corpsequeue.FindEx([=](auto &element) { return element == self; });
if (index < corpsequeue.Size())
while ((corpsePtr = iterator.Next()) != NULL)
{ {
if (corpsePtr->Corpse == self) corpsequeue.Delete(index);
{
corpsePtr->Corpse = NULL;
corpsePtr->Destroy ();
return 0;
}
} }
return 0; return 0;
} }

View file

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

View file

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

View file

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