Fixed some small server issues. Players in the process of establishing a session are now kicked on game start.

If someone tries to join a game which is already running, a proper error message is shown.
When sending a message to all or all but one players, the players which do not have the session established are now correctly ignored.
This commit is contained in:
lotodore
2007-05-23 08:57:34 +00:00
parent e8cbac12cc
commit e01ea96727
3 changed files with 121 additions and 49 deletions
+39 -28
View File
@@ -120,6 +120,15 @@ ServerRecvStateInit::Process(ServerRecvThread &server)
return retVal; return retVal;
} }
size_t curNumPlayers = server.GetCurNumberOfPlayers();
// Check the number of players.
if (curNumPlayers >= (size_t)server.GetGameData().numberOfPlayers)
{
server.SessionError(session, ERR_NET_SERVER_FULL);
return retVal;
}
// Check the server password. // Check the server password.
if (!server.CheckPassword(joinGameData.password)) if (!server.CheckPassword(joinGameData.password))
{ {
@@ -127,12 +136,11 @@ ServerRecvStateInit::Process(ServerRecvThread &server)
return retVal; return retVal;
} }
size_t curNumPlayers = server.GetCurNumberOfPlayers(); // Check whether the player name is correct.
// Paranoia check, this is also done in netpacket.
// Check the number of players. if (joinGameData.playerName.empty() || joinGameData.playerName.size() > MAX_NAME_SIZE)
if (curNumPlayers >= (size_t)server.GetGameData().numberOfPlayers)
{ {
server.SessionError(session, ERR_NET_SERVER_FULL); server.SessionError(session, ERR_NET_INVALID_PLAYER_NAME);
return retVal; return retVal;
} }
@@ -177,7 +185,7 @@ ServerRecvStateInit::Process(ServerRecvThread &server)
++player_i; ++player_i;
} }
// Send "Player Joined" to other clients. // Send "Player Joined" to other fully connected clients.
boost::shared_ptr<NetPacket> thisPlayerJoined(new NetPacketPlayerJoined); boost::shared_ptr<NetPacket> thisPlayerJoined(new NetPacketPlayerJoined);
NetPacketPlayerJoined::Data thisPlayerJoinedData; NetPacketPlayerJoined::Data thisPlayerJoinedData;
thisPlayerJoinedData.playerId = tmpPlayerData->GetUniqueId(); thisPlayerJoinedData.playerId = tmpPlayerData->GetUniqueId();
@@ -185,7 +193,7 @@ ServerRecvStateInit::Process(ServerRecvThread &server)
thisPlayerJoinedData.playerNumber = tmpPlayerData->GetNumber(); thisPlayerJoinedData.playerNumber = tmpPlayerData->GetNumber();
thisPlayerJoinedData.ptype = tmpPlayerData->GetType(); thisPlayerJoinedData.ptype = tmpPlayerData->GetType();
static_cast<NetPacketPlayerJoined *>(thisPlayerJoined.get())->SetData(thisPlayerJoinedData); static_cast<NetPacketPlayerJoined *>(thisPlayerJoined.get())->SetData(thisPlayerJoinedData);
server.SendToAllButOnePlayers(thisPlayerJoined, session.sessionData->GetSocket()); server.SendToAllPlayers(thisPlayerJoined);
// Set player data for session. // Set player data for session.
server.SetSessionPlayerData(session.sessionData, tmpPlayerData); server.SetSessionPlayerData(session.sessionData, tmpPlayerData);
@@ -217,7 +225,8 @@ ServerRecvStateStartGame::~ServerRecvStateStartGame()
void void
ServerRecvStateStartGame::HandleNewConnection(ServerRecvThread &server, boost::shared_ptr<ConnectData> connData) ServerRecvStateStartGame::HandleNewConnection(ServerRecvThread &server, boost::shared_ptr<ConnectData> connData)
{ {
// TODO: send error msg // Do not accept new connections in this state.
server.RejectNewConnection(connData);
} }
int int
@@ -255,7 +264,8 @@ ServerRecvStateStartHand::~ServerRecvStateStartHand()
void void
ServerRecvStateStartHand::HandleNewConnection(ServerRecvThread &server, boost::shared_ptr<ConnectData> connData) ServerRecvStateStartHand::HandleNewConnection(ServerRecvThread &server, boost::shared_ptr<ConnectData> connData)
{ {
// TODO: send error msg // Do not accept new connections in this state.
server.RejectNewConnection(connData);
} }
int int
@@ -271,24 +281,20 @@ ServerRecvStateStartHand::Process(ServerRecvThread &server)
// Send cards to all players. // Send cards to all players.
for (int i = 0; i < curGame.getActualQuantityPlayers(); i++) for (int i = 0; i < curGame.getActualQuantityPlayers(); i++)
{ {
if (playerArray[i]->getNetSessionData().get()) // TODO: this is an assert. assert(playerArray[i]->getNetSessionData().get()); // TODO throw exception
{
int cards[2];
playerArray[i]->getMyCards(cards);
boost::shared_ptr<NetPacket> notifyCards(new NetPacketHandStart);
NetPacketHandStart::Data handStartData;
handStartData.yourCards[0] = static_cast<unsigned>(cards[0]);
handStartData.yourCards[1] = static_cast<unsigned>(cards[1]);
static_cast<NetPacketHandStart *>(notifyCards.get())->SetData(handStartData);
server.GetSender().Send(playerArray[i]->getNetSessionData()->GetSocket(), notifyCards); int cards[2];
} playerArray[i]->getMyCards(cards);
boost::shared_ptr<NetPacket> notifyCards(new NetPacketHandStart);
NetPacketHandStart::Data handStartData;
handStartData.yourCards[0] = static_cast<unsigned>(cards[0]);
handStartData.yourCards[1] = static_cast<unsigned>(cards[1]);
static_cast<NetPacketHandStart *>(notifyCards.get())->SetData(handStartData);
server.GetSender().Send(playerArray[i]->getNetSessionData()->GetSocket(), notifyCards);
} }
// Start hand. // Auto small blind / big blind at the beginning of hand.
curGame.startHand();
// Auto small blind / big blind at the beginning of preflop.
for (int i = 0; i < curGame.getActualQuantityPlayers(); i++) for (int i = 0; i < curGame.getActualQuantityPlayers(); i++)
{ {
if(playerArray[i]->getMyButton() == BUTTON_SMALL_BLIND) if(playerArray[i]->getMyButton() == BUTTON_SMALL_BLIND)
@@ -320,6 +326,9 @@ ServerRecvStateStartHand::Process(ServerRecvThread &server)
} }
} }
// Start hand.
curGame.startHand();
server.SetState(ServerRecvStateStartRound::Instance()); server.SetState(ServerRecvStateStartRound::Instance());
return MSG_NET_GAME_SERVER_HAND; return MSG_NET_GAME_SERVER_HAND;
@@ -345,7 +354,8 @@ ServerRecvStateStartRound::~ServerRecvStateStartRound()
void void
ServerRecvStateStartRound::HandleNewConnection(ServerRecvThread &server, boost::shared_ptr<ConnectData> connData) ServerRecvStateStartRound::HandleNewConnection(ServerRecvThread &server, boost::shared_ptr<ConnectData> connData)
{ {
// TODO: send error msg // Do not accept new connections in this state.
server.RejectNewConnection(connData);
} }
int int
@@ -403,7 +413,7 @@ ServerRecvStateStartRound::GameRun(Game &curGame, int state)
curGame.getCurrentHand()->getRiver()->riverRun(); curGame.getCurrentHand()->getRiver()->riverRun();
} break; } break;
default: { default: {
// TODO //
} }
} }
} }
@@ -427,7 +437,7 @@ ServerRecvStateStartRound::GetCurrentPlayer(Game &curGame)
curPlayerNum = curGame.getCurrentHand()->getRiver()->getPlayersTurn(); curPlayerNum = curGame.getCurrentHand()->getRiver()->getPlayersTurn();
} break; } break;
default: { default: {
// TODO //
} }
} }
assert(curPlayerNum < curGame.getActualQuantityPlayers()); assert(curPlayerNum < curGame.getActualQuantityPlayers());
@@ -455,7 +465,8 @@ ServerRecvStateFinal::~ServerRecvStateFinal()
void void
ServerRecvStateFinal::HandleNewConnection(ServerRecvThread &server, boost::shared_ptr<ConnectData> connData) ServerRecvStateFinal::HandleNewConnection(ServerRecvThread &server, boost::shared_ptr<ConnectData> connData)
{ {
// TODO: send error msg // Do not accept new connections in this state.
server.RejectNewConnection(connData);
} }
int int
+78 -21
View File
@@ -246,10 +246,16 @@ ServerRecvThread::CleanupSessionMap()
void void
ServerRecvThread::InternalStartGame() ServerRecvThread::InternalStartGame()
{ {
SetState(SERVER_START_GAME_STATE::Instance());
// Kick all players which are not fully connected.
RemoveNotEstablishedSessions();
// Initialize the game.
GuiInterface &gui = GetGui(); GuiInterface &gui = GetGui();
PlayerDataList playerData = GetPlayerDataList(); PlayerDataList playerData = GetPlayerDataList();
// EngineFactory erstellen // Create EngineFactory
boost::shared_ptr<EngineFactory> factory(new LocalEngineFactory(m_playerConfig)); // LocalEngine erstellen boost::shared_ptr<EngineFactory> factory(new LocalEngineFactory(m_playerConfig)); // LocalEngine erstellen
// Set dealer pos. // Set dealer pos.
@@ -274,12 +280,11 @@ ServerRecvThread::InternalStartGame()
} }
++player_i; ++player_i;
} }
assert(randDealerFound); assert(randDealerFound); // TODO: Throw exception.
SetStartData(startData); SetStartData(startData);
m_game.reset(new Game(&gui, factory, playerData, GetGameData(), GetStartData(), m_curGameId++)); m_game.reset(new Game(&gui, factory, playerData, GetGameData(), GetStartData(), m_curGameId++));
SetState(SERVER_START_GAME_STATE::Instance());
} }
SessionWrapper SessionWrapper
@@ -320,6 +325,15 @@ ServerRecvThread::SessionError(SessionWrapper session, int errorCode)
CloseSessionDelayed(session); CloseSessionDelayed(session);
} }
void
ServerRecvThread::RejectNewConnection(boost::shared_ptr<ConnectData> connData)
{
// Create a generic session with Id 0.
boost::shared_ptr<SessionData> sessionData(new SessionData(connData->ReleaseSocket(), 0));
// Gracefully close this session.
SessionError(SessionWrapper(sessionData, boost::shared_ptr<PlayerData>()), ERR_NET_GAME_ALREADY_RUNNING);
}
void void
ServerRecvThread::CloseSessionDelayed(SessionWrapper session) ServerRecvThread::CloseSessionDelayed(SessionWrapper session)
{ {
@@ -348,6 +362,39 @@ ServerRecvThread::CloseSessionDelayed(SessionWrapper session)
m_closeSessionList.push_back(closeSessionData); m_closeSessionList.push_back(closeSessionData);
} }
void
ServerRecvThread::RemoveNotEstablishedSessions()
{
SessionList removeList;
SocketSessionMap::iterator session_i = m_sessionMap.begin();
SocketSessionMap::iterator session_end = m_sessionMap.end();
while (session_i != session_end)
{
// Remove all players which are not fully connected.
assert(session_i->second.sessionData.get());
if (session_i->second.sessionData->GetState() != SessionData::Established)
{
// Do not mess with the map within this loop.
// Just store what needs to be removed.
removeList.push_back(session_i->second);
}
++session_i;
}
SessionList::iterator remove_i = removeList.begin();
SessionList::iterator remove_end = removeList.end();
while (remove_i != remove_end)
{
// Inform the players that we are starting without them.
// Gracefully remove them from the server.
SessionError(*remove_i, ERR_NET_GAME_ALREADY_RUNNING);
++remove_i;
}
}
size_t size_t
ServerRecvThread::GetCurNumberOfPlayers() const ServerRecvThread::GetCurNumberOfPlayers() const
{ {
@@ -364,6 +411,7 @@ ServerRecvThread::IsPlayerConnected(const std::string &playerName) const
PlayerDataList::const_iterator player_i = playerList.begin(); PlayerDataList::const_iterator player_i = playerList.begin();
PlayerDataList::const_iterator player_end = playerList.end(); PlayerDataList::const_iterator player_end = playerList.end();
// Check by name - the name is unique.
while (player_i != player_end) while (player_i != player_end)
{ {
if ((*player_i)->GetName() == playerName) if ((*player_i)->GetName() == playerName)
@@ -380,19 +428,19 @@ ServerRecvThread::IsPlayerConnected(const std::string &playerName) const
void void
ServerRecvThread::SetSessionPlayerData(boost::shared_ptr<SessionData> sessionData, boost::shared_ptr<PlayerData> playerData) ServerRecvThread::SetSessionPlayerData(boost::shared_ptr<SessionData> sessionData, boost::shared_ptr<PlayerData> playerData)
{ {
if (playerData.get() && !playerData->GetName().empty()) assert(playerData.get());
assert(!playerData->GetName().empty());
assert(sessionData.get());
boost::mutex::scoped_lock lock(m_sessionMapMutex);
SocketSessionMap::iterator pos = m_sessionMap.find(sessionData->GetSocket());
if (pos != m_sessionMap.end())
{ {
assert(sessionData.get()); pos->second.playerData = playerData;
boost::mutex::scoped_lock lock(m_sessionMapMutex);
SocketSessionMap::iterator pos = m_sessionMap.find(sessionData->GetSocket()); // Signal joining player to GUI.
if (pos != m_sessionMap.end()) GetCallback().SignalNetServerPlayerJoined(playerData->GetName());
{
pos->second.playerData = playerData;
// Signal joining player to GUI.
GetCallback().SignalNetServerPlayerJoined(playerData->GetName());
}
} }
} }
@@ -407,9 +455,14 @@ ServerRecvThread::GetPlayerDataList() const
while (session_i != session_end) while (session_i != session_end)
{ {
boost::shared_ptr<PlayerData> tmpPlayer(session_i->second.playerData); // Get all players which are fully connected.
if (tmpPlayer.get() && !tmpPlayer->GetName().empty()) if (session_i->second.sessionData->GetState() == SessionData::Established)
{
boost::shared_ptr<PlayerData> tmpPlayer(session_i->second.playerData);
assert(tmpPlayer.get());
assert(!tmpPlayer->GetName().empty());
playerList.push_back(tmpPlayer); playerList.push_back(tmpPlayer);
}
++session_i; ++session_i;
} }
// Sort the list by player number. // Sort the list by player number.
@@ -460,8 +513,11 @@ ServerRecvThread::SendToAllPlayers(boost::shared_ptr<NetPacket> packet)
while (i != end) while (i != end)
{ {
// Send each client a copy of the packet. assert(i->second.sessionData.get());
GetSender().Send(i->first, boost::shared_ptr<NetPacket>(packet->Clone()));
// Send each fully connected client a copy of the packet.
if (i->second.sessionData->GetState() == SessionData::Established)
GetSender().Send(i->first, boost::shared_ptr<NetPacket>(packet->Clone()));
++i; ++i;
} }
} }
@@ -477,9 +533,10 @@ ServerRecvThread::SendToAllButOnePlayers(boost::shared_ptr<NetPacket> packet, SO
while (i != end) while (i != end)
{ {
// Send each client but one a copy of the packet. // Send each fully connected client but one a copy of the packet.
if (i->first != except) if (i->second.sessionData->GetState() == SessionData::Established)
GetSender().Send(i->first, boost::shared_ptr<NetPacket>(packet->Clone())); if (i->first != except)
GetSender().Send(i->first, boost::shared_ptr<NetPacket>(packet->Clone()));
++i; ++i;
} }
} }
+4
View File
@@ -83,6 +83,7 @@ protected:
typedef std::deque<boost::shared_ptr<ConnectData> > ConnectQueue; typedef std::deque<boost::shared_ptr<ConnectData> > ConnectQueue;
typedef std::map<SOCKET, SessionWrapper> SocketSessionMap; typedef std::map<SOCKET, SessionWrapper> SocketSessionMap;
typedef std::list<SessionWrapper> SessionList;
typedef std::deque<Notification> NotificationQueue; typedef std::deque<Notification> NotificationQueue;
typedef std::list<std::pair<boost::microsec_timer, boost::shared_ptr<SessionData> > > CloseSessionList; typedef std::list<std::pair<boost::microsec_timer, boost::shared_ptr<SessionData> > > CloseSessionList;
@@ -102,7 +103,9 @@ protected:
SessionWrapper GetSession(SOCKET sock); SessionWrapper GetSession(SOCKET sock);
void AddSession(boost::shared_ptr<SessionData> sessionData); // new Sessions have no player data void AddSession(boost::shared_ptr<SessionData> sessionData); // new Sessions have no player data
void SessionError(SessionWrapper session, int errorCode); void SessionError(SessionWrapper session, int errorCode);
void RejectNewConnection(boost::shared_ptr<ConnectData> connData);
void CloseSessionDelayed(SessionWrapper session); void CloseSessionDelayed(SessionWrapper session);
void RemoveNotEstablishedSessions();
size_t GetCurNumberOfPlayers() const; size_t GetCurNumberOfPlayers() const;
bool IsPlayerConnected(const std::string &playerName) const; bool IsPlayerConnected(const std::string &playerName) const;
@@ -163,6 +166,7 @@ friend class ServerRecvStateInit;
friend class ServerRecvStateStartGame; friend class ServerRecvStateStartGame;
friend class ServerRecvStateStartHand; friend class ServerRecvStateStartHand;
friend class ServerRecvStateStartRound; friend class ServerRecvStateStartRound;
friend class ServerRecvStateFinal;
}; };
#endif #endif