Skip to content

Commit

Permalink
Try harder to prevent desynch on player leaving.
Browse files Browse the repository at this point in the history
There seem to be way too many ways that a player can leave, disconnect, drop, be
kicked, leave (again), be destroyed and/or be cleared.

During a game, NET_PLAYER_DROPPED must not be sent, since it is executed at a random
game time, and GAME_PLAYER_LEFT must be sent instead. Independently of whether the
player left, disconnected, dropped, was kicked, left, was destroyed, was eaten by a
grue, or was cleared.
  • Loading branch information
Cyp committed May 1, 2012
1 parent 282efa8 commit 2309f16
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 12 deletions.
29 changes: 19 additions & 10 deletions lib/netplay/netplay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -452,9 +452,12 @@ static void NETplayerClientDisconnect(uint32_t index)
NETlogEntry("Player has left unexpectedly.", SYNC_FLAG, index);
// Announce to the world. This was really icky, because we may have been calling the send
// function recursively. We really ought to have had a send queue, and now we finally do...
NETbeginEncode(NETbroadcastQueue(), NET_PLAYER_DROPPED);
NETuint32_t(&index);
NETend();
if (ingame.localJoiningInProgress) // Only if game hasn't actually started yet.
{
NETbeginEncode(NETbroadcastQueue(), NET_PLAYER_DROPPED);
NETuint32_t(&index);
NETend();
}
}
else
{
Expand Down Expand Up @@ -485,7 +488,10 @@ static void NETplayerLeaving(UDWORD index)
}
sync_counter.left++;
MultiPlayerLeave(index); // more cleanup
NET_DestroyPlayer(index); // sets index player's array to false
if (ingame.localJoiningInProgress) // Only if game hasn't actually started yet.
{
NET_DestroyPlayer(index); // sets index player's array to false
}
}

/**
Expand All @@ -503,14 +509,17 @@ static void NETplayerDropped(UDWORD index)
return;
}

// Send message type specifically for dropped / disconnects
NETbeginEncode(NETbroadcastQueue(), NET_PLAYER_DROPPED);
NETuint32_t(&id);
NETend();
debug(LOG_INFO, "sending NET_PLAYER_DROPPED for player %d", id);
sync_counter.drops++;
NET_DestroyPlayer(id); // just clears array
MultiPlayerLeave(id); // more cleanup
if (ingame.localJoiningInProgress) // Only if game hasn't actually started yet.
{
// Send message type specifically for dropped / disconnects
NETbeginEncode(NETbroadcastQueue(), NET_PLAYER_DROPPED);
NETuint32_t(&id);
NETend();
debug(LOG_INFO, "sending NET_PLAYER_DROPPED for player %d", id);
NET_DestroyPlayer(id); // just clears array
}

NETsetPlayerConnectionStatus(CONNECTIONSTATUS_PLAYER_DROPPED, id);
}
Expand Down
9 changes: 8 additions & 1 deletion src/loop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,14 @@ static void gameStateUpdate()
// Can't dump isHumanPlayer, since it causes spurious desynch dumps when players leave.
// TODO isHumanPlayer should probably be synchronised, since the game state seems to depend on it, so there might also be a risk of real desynchs when players leave.
//syncDebug("map = \"%s\", humanPlayers = %d %d %d %d %d %d %d %d", game.map, isHumanPlayer(0), isHumanPlayer(1), isHumanPlayer(2), isHumanPlayer(3), isHumanPlayer(4), isHumanPlayer(5), isHumanPlayer(6), isHumanPlayer(7));
syncDebug("map = \"%s\", pseudorandom 32-bit integer = 0x%08X", game.map, gameRandU32());
syncDebug("map = \"%s\", pseudorandom 32-bit integer = 0x%08X, allocated = %d %d %d %d %d %d %d %d %d %d, position = %d %d %d %d %d %d %d %d %d %d", game.map, gameRandU32(),
NetPlay.players[0].allocated, NetPlay.players[1].allocated, NetPlay.players[2].allocated, NetPlay.players[3].allocated, NetPlay.players[4].allocated, NetPlay.players[5].allocated, NetPlay.players[6].allocated, NetPlay.players[7].allocated, NetPlay.players[8].allocated, NetPlay.players[9].allocated,
NetPlay.players[0].position, NetPlay.players[1].position, NetPlay.players[2].position, NetPlay.players[3].position, NetPlay.players[4].position, NetPlay.players[5].position, NetPlay.players[6].position, NetPlay.players[7].position, NetPlay.players[8].position, NetPlay.players[9].position
);
for (unsigned n = 0; n < MAX_PLAYERS; ++n)
{
syncDebug("Player %d = \"%s\"", n, NetPlay.players[n].name);
}

// Actually send pending droid orders.
sendQueuedDroidInfo();
Expand Down
5 changes: 4 additions & 1 deletion src/multijoin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -239,14 +239,17 @@ void recvPlayerLeft(NETQUEUE queue)
NETbeginDecode(queue, GAME_PLAYER_LEFT);
NETuint32_t(&playerIndex);
NETend();
if (queue.index == NET_HOST_ONLY || queue.index == playerIndex)
if (queue.index != NET_HOST_ONLY && queue.index != playerIndex)
{
return;
}

turnOffMultiMsg(true);
clearPlayer(playerIndex, false); // don't do it quietly
turnOffMultiMsg(false);
NetPlay.players[playerIndex].allocated = false;

debug(LOG_INFO, "** player %u has dropped, in-game!", playerIndex);
}

// ////////////////////////////////////////////////////////////////////////////
Expand Down

0 comments on commit 2309f16

Please sign in to comment.