Esempio n. 1
0
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);
			}
		}
	}
}
Esempio n. 2
0
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;
}
Esempio n. 3
0
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;
}
Esempio n. 4
0
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;
	}
}
Esempio n. 5
0
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;
	}
}