void DThinker::DestroyMostThinkersInList (FThinkerList &list, int stat) { if (stat != STAT_PLAYER) { DestroyThinkersInList (list); } else if (list.Sentinel != NULL) { // If it's a voodoo doll, destroy it. Otherwise, simply remove // 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) { 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) { probe->Destroy(); } else { probe->Remove(); // Technically, this doesn't need to be in any list now, since // it's only going to be found later and destroyed before ever // needing to tick again, but by moving it to a separate list, // I can keep my debug assertions that all thinkers are either // euthanizing or in a list. Thinkers[MAX_STATNUM+1].AddTail(probe); } } } }
void DThinker::SerializeAll (FArchive &arc, bool hubLoad, bool noStorePlayers) { DThinker *thinker; if (arc.IsStoring () && noStorePlayers) { thinker = FirstThinker; while (thinker) { // Don't store player mobjs. if (!(thinker->IsKindOf(RUNTIME_CLASS(AActor)) && static_cast<AActor *>(thinker)->type == MT_PLAYER)) { arc << (BYTE)1; arc << thinker; } thinker = thinker->m_Next; } arc << (BYTE)0; } else if (arc.IsStoring ()) { thinker = FirstThinker; while (thinker) { arc << (BYTE)1; arc << thinker; thinker = thinker->m_Next; } arc << (BYTE)0; } else { if (hubLoad || noStorePlayers) DestroyMostThinkers (); else DestroyAllThinkers (); BYTE more; arc >> more; while (more) { DThinker *thinker; arc >> thinker; arc >> more; } // killough 3/26/98: Spawn icon landings: P_SpawnBrainTargets (); } }
void DThinker::RunThinkers () { DThinker *currentthinker; BEGIN_STAT (ThinkCycles); currentthinker = FirstThinker; while (currentthinker) { if (!IndependentThinker(currentthinker)) currentthinker->RunThink(); currentthinker = currentthinker->m_Next; } END_STAT (ThinkCycles); }
void DThinker::DestroyThinkersInList (FThinkerList &list) { if (list.Sentinel != NULL) { DThinker *node = list.Sentinel->NextThinker; while (node != list.Sentinel) { DThinker *next = node->NextThinker; node->Destroy(); node = next; } list.Sentinel->Destroy(); list.Sentinel = NULL; } }
// Destroy all thinkers except for player-controlled actors void DThinker::DestroyMostThinkers () { DThinker *thinker = FirstThinker; while (thinker) { DThinker *next = thinker->m_Next; if (!thinker->IsKindOf (RUNTIME_CLASS (AActor)) || static_cast<AActor *>(thinker)->player == NULL || static_cast<AActor *>(thinker)->player->mo != static_cast<AActor *>(thinker)) { thinker->Destroy (); } thinker = next; } DObject::EndFrame (); }
int DThinker::TickThinkers (FThinkerList *list, FThinkerList *dest) { int count = 0; DThinker *node = list->GetHead(); if (node == NULL) { return 0; } while (node != list->Sentinel) { ++count; NextToThink = node->NextThinker; if (node->ObjectFlags & OF_JustSpawned) { // Leave OF_JustSpawn set until after Tick() so the ticker can check it. if (dest != NULL) { // Move thinker from this list to the destination list node->Remove(); dest->AddTail(node); } node->PostBeginPlay(); } else if (dest != NULL) { // Move thinker from this list to the destination list I_Error("There is a thinker in the fresh list that has already ticked.\n"); } if (!(node->ObjectFlags & OF_EuthanizeMe)) { // Only tick thinkers not scheduled for destruction // [BC] Don't tick the consoleplayer's actor in client // mode, because that's done in the main prediction function if (( NETWORK_InClientMode() == false ) || ( node->IsKindOf( RUNTIME_CLASS( AActor )) == false ) || ( static_cast<AActor *>( node ) != players[consoleplayer].mo )) { node->Tick(); } node->ObjectFlags &= ~OF_JustSpawned; GC::CheckGC(); } node = NextToThink; } return count; }
DThinker *FThinkerIterator::Next () { if (m_ParentType == NULL) { return NULL; } do { do { if (m_CurrThinker != NULL) { while (!(m_CurrThinker->ObjectFlags & OF_Sentinel)) { DThinker *thinker = m_CurrThinker; m_CurrThinker = thinker->NextThinker; if (thinker->IsKindOf(m_ParentType)) { return thinker; } } } if ((m_SearchingFresh = !m_SearchingFresh)) { m_CurrThinker = DThinker::FreshThinkers[m_Stat].GetHead(); } } while (m_SearchingFresh); if (m_SearchStats) { m_Stat++; if (m_Stat > MAX_STATNUM) { m_Stat = STAT_FIRST_THINKING; } } m_CurrThinker = DThinker::Thinkers[m_Stat].GetHead(); m_SearchingFresh = false; } while (m_SearchStats && m_Stat != STAT_FIRST_THINKING); return NULL; }
int DThinker::TickThinkers (FThinkerList *list, FThinkerList *dest) { int count = 0; DThinker *node = list->GetHead(); if (node == NULL) { return 0; } while (node != list->Sentinel) { ++count; NextToThink = node->NextThinker; if (node->ObjectFlags & OF_JustSpawned) { // Leave OF_JustSpawn set until after Tick() so the ticker can check it. if (dest != NULL) { // Move thinker from this list to the destination list node->Remove(); dest->AddTail(node); } node->PostBeginPlay(); } else if (dest != NULL) { // Move thinker from this list to the destination list I_Error("There is a thinker in the fresh list that has already ticked.\n"); } if (!(node->ObjectFlags & OF_EuthanizeMe)) { // Only tick thinkers not scheduled for destruction node->Tick(); node->ObjectFlags &= ~OF_JustSpawned; GC::CheckGC(); } node = NextToThink; } return count; }
// Destroy every thinker void DThinker::DestroyAllThinkers () { DThinker *currentthinker = FirstThinker; while (currentthinker) { DThinker *next = currentthinker->m_Next; currentthinker->Destroy (); currentthinker = next; } DObject::EndFrame (); size_t l = LingerDestroy.size(); for(size_t i = 0; i < l; i++) { DThinker *obj = LingerDestroy[i]; // if(!obj->refCount) { obj->ObjectFlags |= OF_Cleanup; delete obj; } } LingerDestroy.clear(); }
void DThinker::SerializeAll(FArchive &arc, bool hubLoad) { DThinker *thinker; BYTE stat; int statcount; int i; // Save lists of thinkers, but not by storing the first one and letting // the archiver catch the rest. (Which leads to buttloads of recursion // and makes the file larger.) Instead, we explicitly save each thinker // in sequence. When restoring an archive, we also have to maintain // the thinker lists here instead of relying on the archiver to do it // for us. if (arc.IsStoring()) { for (statcount = i = 0; i <= MAX_STATNUM; i++) { statcount += (!Thinkers[i].IsEmpty() || !FreshThinkers[i].IsEmpty()); } arc << statcount; for (i = 0; i <= MAX_STATNUM; i++) { if (!Thinkers[i].IsEmpty() || !FreshThinkers[i].IsEmpty()) { stat = i; arc << stat; SaveList(arc, Thinkers[i].GetHead()); SaveList(arc, FreshThinkers[i].GetHead()); thinker = NULL; arc << thinker; // Save a final NULL for this list } } } else { if (hubLoad) DestroyMostThinkers(); else DestroyAllThinkers(); // Prevent the constructor from inserting thinkers into a list. bSerialOverride = true; try { arc << statcount; while (statcount > 0) { arc << stat << thinker; while (thinker != NULL) { // This may be a player stored in their ancillary list. Remove // them first before inserting them into the new list. if (thinker->NextThinker != NULL) { thinker->Remove(); } // Thinkers with the OF_JustSpawned flag set go in the FreshThinkers // list. Anything else goes in the regular Thinkers list. if (thinker->ObjectFlags & OF_EuthanizeMe) { // This thinker was destroyed during the loading process. Do // not link it in to any list. } else if (thinker->ObjectFlags & OF_JustSpawned) { FreshThinkers[stat].AddTail(thinker); } else { Thinkers[stat].AddTail(thinker); } arc << thinker; } statcount--; } } catch (class CDoomError &err) { bSerialOverride = false; // DestroyAllThinkers cannot be called here. It will try to delete the corrupted // object table left behind by the serializer and crash. // Trying to continue is not an option here because the garbage collector will // crash the next time it runs. // Even making this a fatal error will crash but at least the message can be seen // before the crash - which is not the case with all other options. //DestroyAllThinkers(); I_FatalError("%s", err.GetMessage()); throw; } bSerialOverride = false; } }
void DThinker::SerializeAll(FArchive &arc, bool hubLoad) { DThinker *thinker; BYTE stat; int statcount; int i; // Save lists of thinkers, but not by storing the first one and letting // the archiver catch the rest. (Which leads to buttloads of recursion // and makes the file larger.) Instead, we explicitly save each thinker // in sequence. When restoring an archive, we also have to maintain // the thinker lists here instead of relying on the archiver to do it // for us. if (arc.IsStoring()) { for (statcount = i = 0; i <= MAX_STATNUM; i++) { statcount += (!Thinkers[i].IsEmpty() || !FreshThinkers[i].IsEmpty()); } arc << statcount; for (i = 0; i <= MAX_STATNUM; i++) { if (!Thinkers[i].IsEmpty() || !FreshThinkers[i].IsEmpty()) { stat = i; arc << stat; SaveList(arc, Thinkers[i].GetHead()); SaveList(arc, FreshThinkers[i].GetHead()); thinker = NULL; arc << thinker; // Save a final NULL for this list } } } else { if (hubLoad) DestroyMostThinkers(); else DestroyAllThinkers(); // Prevent the constructor from inserting thinkers into a list. bSerialOverride = true; try { arc << statcount; while (statcount > 0) { arc << stat << thinker; while (thinker != NULL) { // This may be a player stored in their ancillary list. Remove // them first before inserting them into the new list. if (thinker->NextThinker != NULL) { thinker->Remove(); } // Thinkers with the OF_JustSpawned flag set go in the FreshThinkers // list. Anything else goes in the regular Thinkers list. if (thinker->ObjectFlags & OF_EuthanizeMe) { // This thinker was destroyed during the loading process. Do // not link it in to any list. } else if (thinker->ObjectFlags & OF_JustSpawned) { FreshThinkers[stat].AddTail(thinker); } else { Thinkers[stat].AddTail(thinker); } arc << thinker; } statcount--; } } catch (class CDoomError &) { bSerialOverride = false; DestroyAllThinkers(); throw; } bSerialOverride = false; } }