More work on rejoin: The server now detects when a rejoin is possible and allows the player to login directly, without waiting for a possible existing connection to be terminated. A session GUID is stored in the cache directory on client side for this purpose.

This commit is contained in:
lotodore
2011-08-28 17:14:03 +00:00
parent 0a49783889
commit 32ba77709e
18 changed files with 195 additions and 24 deletions
+52 -20
View File
@@ -36,6 +36,7 @@
#include <core/loghelper.h>
#include <core/openssl_wrapper.h>
#include <configfile.h>
#include <playerinterface.h>
#include <log.h>
#include <fstream>
@@ -225,16 +226,6 @@ ServerLobbyThread::SignalTermination()
void
ServerLobbyThread::AddConnection(boost::shared_ptr<tcp::socket> sock)
{
// Create a random session id.
// This id can be used to reconnect to the server if the connection was lost.
//unsigned sessionId;
// TODO: use randomized method.
//if(!RAND_bytes((unsigned char *)&sessionId, sizeof(sessionId)))
//{
// RAND_pseudo_bytes((unsigned char *)&sessionId, sizeof(sessionId));
//}
// Create a new session.
boost::shared_ptr<SessionData> sessionData(new SessionData(sock, m_curSessionId++, *m_internalServerCallback));
m_sessionManager.AddSession(sessionData);
@@ -711,6 +702,26 @@ ServerLobbyThread::GetBanManager()
return *m_banManager;
}
u_int32_t
ServerLobbyThread::GetRejoinGameIdForPlayer(const std::string &playerName, const std::string &guid, unsigned &outPlayerUniqueId)
{
u_int32_t retGameId = 0;
GameMap::iterator i = m_gameMap.begin();
GameMap::iterator end = m_gameMap.end();
while (i != end) {
boost::shared_ptr<ServerGame> tmpGame = i->second;
boost::shared_ptr<PlayerInterface> tmpPlayer = tmpGame->GetPlayerInterfaceFromGame(playerName);
if (tmpPlayer && tmpPlayer->getMyGuid() == guid)
{
retGameId = tmpGame->GetId();
outPlayerUniqueId = tmpPlayer->getMyUniqueID();
break;
}
++i;
}
return retGameId;
}
u_int32_t
ServerLobbyThread::GetNextUniquePlayerId()
{
@@ -1025,12 +1036,6 @@ ServerLobbyThread::HandleNetPacketInit(boost::shared_ptr<SessionData> session, c
return;
}
// Check whether this player is already connected.
if (IsPlayerConnected(playerName)) {
SessionError(session, ERR_NET_PLAYER_NAME_IN_USE);
return;
}
// Check whether the player name is banned.
if (GetBanManager().IsPlayerBanned(playerName)) {
SessionError(session, ERR_NET_PLAYER_BANNED);
@@ -1047,6 +1052,10 @@ ServerLobbyThread::HandleNetPacketInit(boost::shared_ptr<SessionData> session, c
new PlayerData(GetNextUniquePlayerId(), 0, PLAYER_TYPE_HUMAN, validGuest ? PLAYER_RIGHTS_GUEST : PLAYER_RIGHTS_NORMAL, false));
tmpPlayerData->SetName(playerName);
tmpPlayerData->SetAvatarMD5(avatarMD5);
if (initMessage.myLastSessionId)
{
tmpPlayerData->SetGuid(STL_STRING_FROM_OCTET_STRING(*initMessage.myLastSessionId));
}
// Set player data for session.
m_sessionManager.SetSessionPlayerData(session->GetId(), tmpPlayerData);
@@ -1483,6 +1492,21 @@ ServerLobbyThread::EstablishSession(boost::shared_ptr<SessionData> session)
if (!session->GetPlayerData())
throw ServerException(__FILE__, __LINE__, ERR_NET_INVALID_SESSION, 0);
u_int32_t rejoinPlayerId = 0;
u_int32_t rejoinGameId = GetRejoinGameIdForPlayer(session->GetPlayerData()->GetName(), session->GetPlayerData()->GetGuid(), rejoinPlayerId);
if (rejoinGameId != 0)
{
// Offer rejoin, and disconnect current player with the same name.
InternalRemovePlayer(rejoinPlayerId, ERR_NET_PLAYER_NAME_IN_USE);
}
// Check whether this player is already connected.
// We need to enforce this here to prevent duplicates.
if (IsPlayerConnected(session->GetPlayerData()->GetName())) {
SessionError(session, ERR_NET_PLAYER_KICKED);
return;
}
// Run postlogin for DB
string tmpAvatarHash;
string tmpAvatarType;
@@ -1494,16 +1518,24 @@ ServerLobbyThread::EstablishSession(boost::shared_ptr<SessionData> session)
}
m_database->PlayerPostLogin(session->GetPlayerData()->GetDBId(), tmpAvatarHash, tmpAvatarType);
// Generate a new GUID.
boost::uuids::uuid sessionGuid(m_sessionIdGenerator());
session->GetPlayerData()->SetGuid(string((char *)&sessionGuid, boost::uuids::uuid::static_size()));
// Send ACK to client.
boost::shared_ptr<NetPacket> ack(new NetPacket(NetPacket::Alloc));
ack->GetMsg()->present = PokerTHMessage_PR_initAckMessage;
InitAckMessage_t *netInitAck = &ack->GetMsg()->choice.initAckMessage;
boost::uuids::uuid sessionId(m_sessionIdGenerator());
OCTET_STRING_fromBuf(
&netInitAck->yourSessionId,
(char *)&sessionId,
(int)boost::uuids::uuid::static_size());
session->GetPlayerData()->GetGuid().c_str(),
session->GetPlayerData()->GetGuid().size());
netInitAck->yourPlayerId = session->GetPlayerData()->GetUniqueId();
if (rejoinGameId != 0)
{
netInitAck->rejoinGameId = (NonZeroId_t *)calloc(1, sizeof(NonZeroId_t));
*netInitAck->rejoinGameId = rejoinGameId;
}
GetSender().Send(session, ack);
// Send the connected players list to the client.
@@ -1782,7 +1814,7 @@ ServerLobbyThread::InternalRemovePlayer(unsigned playerId, unsigned errorCode)
while (i != end) {
boost::shared_ptr<ServerGame> tmpGame = i->second;
if (tmpGame->GetPlayerDataByUniqueId(playerId).get()) {
if (tmpGame->GetPlayerDataByUniqueId(playerId)) {
tmpGame->RemovePlayer(playerId, errorCode);
break;
}