示例#1
0
static void
readyToEndCallback (NetConnection *conn, void *arg)
{
	// This callback function gets called from inside the function that
	// updates the frame counter, but this is not a problem as the
	// ending frame count will at least be 1 greater than the current
	// frame count.

	BattleStateData *battleStateData;
	battleStateData = (BattleStateData *) NetConnection_getStateData(conn);

#ifdef NETPLAY_DEBUG
	fprintf (stderr, "Both sides are ready to end the battle; starting "
			"end-of-battle synchronisation.\n");
#endif
	NetConnection_setState (conn, NetState_endingBattle);
	if (battleFrameCount + 1 > battleStateData->endFrameCount)
		battleStateData->endFrameCount = battleFrameCount + 1;
	Netplay_Notify_frameCount (conn, battleFrameCount + 1);
			// The +1 is to ensure that after the remote side receives the
			// frame count it will still receive one more frame data packet,
			// so it will know in advance when the last frame data packet
			// will come so it won't block. It also ensures that the
			// local frame counter won't go past the sent number, which
			// could happen when the function triggering the call to this
			// function is the frame update function which might update
			// the frame counter one more time.
	flushPacketQueue (conn);
#ifdef NETPLAY_DEBUG
    fprintf (stderr, "NETPLAY: [%d] ==> Sent battleFrameCount %d.\n",
			NetConnection_getPlayerNr(conn), battleFrameCount + 1);
#endif
	Netplay_localReady(conn, readyToEnd2Callback, NULL, false);
	(void) arg;
}
示例#2
0
/*
 * When one player's ship dies, there's a delay before the next ship
 * can be chosen. This time depends on the time the ditty is playing
 * and may differ for each side.
 * To synchronise the time, the following protocol is followed:
 * 1. (NetState_inBattle) The Ready protocol is used to let either
 *    party know when they're ready to stop the battle.
 * 2. (NetState_endingBattle) Each party sends the frame number of when
 *    it wants to end the battle, and continues until that point, where
 *    it waits until it has received the frame number of the other party.
 * 3. After a player has both sent and received a frame count, the
 *    simulation continues for each party, until the maximum of both
 *    frame counts has been achieved.
 * 4. The Ready protocol is used to let each side signal that it has
 *    reached the target frame count.
 * 5. The battle ends.
 */
static bool
readyForBattleEndPlayer (NetConnection *conn)
{
	BattleStateData *battleStateData;
	battleStateData = (BattleStateData *) NetConnection_getStateData(conn);

	if (NetConnection_getState (conn) == NetState_interBattle ||
			NetConnection_getState (conn) == NetState_inSetup)
	{
		// This connection is already ready. The entire synchronisation
		// protocol has already been done for this connection.
		return true;
	}

	if (NetConnection_getState (conn) == NetState_inBattle)
	{
		if (Netplay_isLocalReady(conn))
		{
			// We've already sent notice that we are ready, but we're
			// still waiting for the other side to say it's ready too.
			return false;
		}

		// We haven't yet told the other side we're ready. We do so now.
		Netplay_localReady (conn, readyToEndCallback, NULL, true);
				// This may set the state to endingBattle.

		if (NetConnection_getState (conn) == NetState_inBattle)
			return false;
	}

	assert (NetConnection_getState (conn) == NetState_endingBattle ||
			NetConnection_getState (conn) == NetState_endingBattle2);
	
	// Keep the simulation going as long as the target frame count
	// hasn't been reached yet. Note that if the connection state is
	// NetState_endingBattle, then we haven't yet received the
	// remote frame count, so the target frame count may still rise.
	if (battleFrameCount < battleStateData->endFrameCount)
		return false;

	if (NetConnection_getState (conn) == NetState_endingBattle)
	{
		// We have reached the target frame count, but we don't know
		// the remote target frame count yet. So we wait until it has
		// come in.
		waitReady (conn);
		// TODO: check whether all connections are still connected.
		assert (NetConnection_getState (conn) == NetState_endingBattle2);

		// Continue the simulation if the battleFrameCount has gone up.
		if (battleFrameCount < battleStateData->endFrameCount)
			return false;
	}

	// We are ready and wait for the other party to become ready too.
	negotiateReady (conn, true, NetState_interBattle);

	return true;	
}
示例#3
0
// Post: the NetState for all players is NetState_interBattle
static BOOLEAN
GetMeleeStarShips (COUNT playerMask, HSTARSHIP *ships)
{
	COUNT playerI;
	BOOLEAN ok;
	GETMELEE_STATE gmstate;
	TimeCount now;
	COUNT i;

#ifdef NETPLAY
	for (playerI = 0; playerI < NUM_PLAYERS; playerI++)
	{
		NetConnection *conn;

		if ((playerMask & (1 << playerI)) == 0)
			continue;

		// XXX: This does not have to be done per connection.
		conn = netConnections[playerI];
		if (conn != NULL) {
			BattleStateData *battleStateData;
			battleStateData =
					(BattleStateData *) NetConnection_getStateData (conn);
			battleStateData->getMeleeState = &gmstate;
		}
	}
#endif
	
	ok = true;

	now = GetTimeCounter ();
	gmstate.InputFunc = DoGetMelee;
	gmstate.Initialized = FALSE;
	for (i = 0; i < NUM_PLAYERS; ++i)
	{
		// We have to use TFB_Random() results in specific order
		playerI = GetPlayerOrder (i);
		gmstate.player[playerI].selecting =
				(playerMask & (1 << playerI)) != 0;
		gmstate.player[playerI].ships_left = battle_counter[playerI];

		// We determine in advance which ship would be chosen if the player
		// wants a random ship, to keep it simple to keep network parties
		// synchronised.
		gmstate.player[playerI].randomIndex =
				(COUNT)TFB_Random () % gmstate.player[playerI].ships_left;
		gmstate.player[playerI].done = FALSE;

		if (!gmstate.player[playerI].selecting)
			continue;

		gmstate.player[playerI].timeIn = now;
		gmstate.player[playerI].row = 0;
		gmstate.player[playerI].col = NUM_PICKMELEE_COLUMNS;
#ifdef NETPLAY
		gmstate.player[playerI].remoteSelected = FALSE;
#endif

		gmstate.player[playerI].flashContext =
				Flash_createHighlight (ScreenContext, NULL);
		Flash_setMergeFactors (gmstate.player[playerI].flashContext,
				2, 3, 2);
		Flash_setFrameTime (gmstate.player[playerI].flashContext,
				ONE_SECOND / 16);
#ifdef NETPLAY
		if (PlayerControl[playerI] & NETWORK_CONTROL)
			Flash_setSpeed (gmstate.player[playerI].flashContext,
					ONE_SECOND / 2, 0, ONE_SECOND / 2, 0);
		else
#endif
		{
			Flash_setSpeed (gmstate.player[playerI].flashContext,
					0, ONE_SECOND / 16, 0, ONE_SECOND / 16);
		}
		PickMelee_ChangedSelection (&gmstate, playerI);
		Flash_start (gmstate.player[playerI].flashContext);
	}

#ifdef NETPLAY
	{
		// NB. gmstate.player[].randomIndex and gmstate.player[].done must
		// be initialised before negotiateReadyConnections is completed, to
		// ensure that they are initialised when the SelectShip packet
		// arrives.
		bool allOk = negotiateReadyConnections (true, NetState_selectShip);
		if (!allOk)
		{
			// Some network connection has been reset.
			ok = false;
		}
	}
#endif
	SetDefaultMenuRepeatDelay ();
	
	SetContext (OffScreenContext);


	DoInput (&gmstate, FALSE);
	WaitForSoundEnd (0);


	for (playerI = 0; playerI < NUM_PLAYERS; playerI++)
	{
		if (!gmstate.player[playerI].selecting)
			continue;
		
		if (gmstate.player[playerI].done)
		{
			// Flash rectangle is already terminated.
			ships[playerI] = gmstate.player[playerI].hBattleShip;
		}
		else
		{
			Flash_terminate (gmstate.player[playerI].flashContext);
			gmstate.player[playerI].flashContext = NULL;
			ok = false;
		}
	}

#ifdef NETPLAY
	if (ok)
	{
		if (!negotiateReadyConnections (true, NetState_interBattle))
			ok = false;
	}
	else
		setStateConnections (NetState_interBattle);
#endif

	if (!ok)
	{
		// Aborting.
		GLOBAL (CurrentActivity) &= ~IN_BATTLE;
	}

#ifdef NETPLAY
	for (playerI = 0; playerI < NUM_PLAYERS; playerI++)
	{
		NetConnection *conn;

		if ((playerMask & (1 << playerI)) == 0)
			continue;

		// XXX: This does not have to be done per connection.
		conn = netConnections[playerI];
		if (conn != NULL && NetConnection_isConnected (conn))
		{
			BattleStateData *battleStateData;
			battleStateData =
					(BattleStateData *) NetConnection_getStateData (conn);
			battleStateData->getMeleeState = NULL;
		}
	}
#endif

	return ok;
}