Do not follow NextThinker links in DestroyThinkersInList

- Fixed: DThinker::Destroy(Most)ThinkersInList() were unreliable when
  destroyed thinkers destroyed more thinkers in the same list.
  Specifically, if the thinker it destroyed caused the very next thinker
  in the list to also be destroyed, it would get lost in the thinker list
  and end up with a NULL node. So just keep iterating through the first
  thinker in the list until there are none left. Since destroying a
  thinker causes it to remove itself from its list, the first thinker will
  always be changing as long as there's something to destroy.
This commit is contained in:
Randy Heit 2013-10-08 21:32:26 -05:00
parent 3c376aa342
commit 0c9c624e8c

View file

@ -357,12 +357,10 @@ void DThinker::DestroyThinkersInList (FThinkerList &list)
{
if (list.Sentinel != NULL)
{
DThinker *node = list.Sentinel->NextThinker;
while (node != list.Sentinel)
for (DThinker *node = list.Sentinel->NextThinker; node != list.Sentinel; node = list.Sentinel->NextThinker)
{
DThinker *next = node->NextThinker;
assert(node != NULL);
node->Destroy();
node = next;
}
list.Sentinel->Destroy();
list.Sentinel = NULL;
@ -380,9 +378,8 @@ void DThinker::DestroyMostThinkersInList (FThinkerList &list, int stat)
// it from the list. G_FinishTravel() will find it later from
// a players[].mo link and destroy it then, after copying various
// information to a new player.
for (DThinker *probe = list.Sentinel->NextThinker, *next; probe != list.Sentinel; probe = next)
for (DThinker *probe = list.Sentinel->NextThinker; probe != list.Sentinel; probe = list.Sentinel->NextThinker)
{
next = probe->NextThinker;
if (!probe->IsKindOf(RUNTIME_CLASS(APlayerPawn)) || // <- should not happen
static_cast<AActor *>(probe)->player == NULL ||
static_cast<AActor *>(probe)->player->mo != probe)