Fixed server crash when trying to start a game. Server is still broken, though...

This commit is contained in:
lotodore
2009-05-31 13:17:02 +00:00
parent ef04130999
commit 59358bff0e
5 changed files with 343 additions and 250 deletions
+4 -1
View File
@@ -106,6 +106,9 @@ TimerManager::Process()
unsigned unsigned
TimerManager::GetNextTimerId() TimerManager::GetNextTimerId()
{ {
return ++m_curTimerId; ++m_curTimerId;
if (m_curTimerId == 0) // Id 0 is invalid.
++m_curTimerId;
return m_curTimerId;
} }
+255 -188
View File
@@ -266,17 +266,12 @@ ServerGameState::~ServerGameState()
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
AbstractServerGameStateReceiving::AbstractServerGameStateReceiving(ServerGameThread &serverGame)
: ServerGameState(serverGame)
{
}
AbstractServerGameStateReceiving::~AbstractServerGameStateReceiving() AbstractServerGameStateReceiving::~AbstractServerGameStateReceiving()
{ {
} }
int int
AbstractServerGameStateReceiving::ProcessPacket(SessionWrapper session, boost::shared_ptr<NetPacket> packet) AbstractServerGameStateReceiving::ProcessPacket(ServerGameThread &server, SessionWrapper session, boost::shared_ptr<NetPacket> packet)
{ {
// This is the receive loop for the server. // This is the receive loop for the server.
int retVal = MSG_SOCK_INTERNAL_PENDING; int retVal = MSG_SOCK_INTERNAL_PENDING;
@@ -286,27 +281,27 @@ AbstractServerGameStateReceiving::ProcessPacket(SessionWrapper session, boost::s
if (packet->ToNetPacketRetrievePlayerInfo()) if (packet->ToNetPacketRetrievePlayerInfo())
{ {
// Delegate to Lobby. // Delegate to Lobby.
GetServerGame().GetLobbyThread().HandleGameRetrievePlayerInfo(session, *packet->ToNetPacketRetrievePlayerInfo()); server.GetLobbyThread().HandleGameRetrievePlayerInfo(session, *packet->ToNetPacketRetrievePlayerInfo());
} }
else if (packet->ToNetPacketRetrieveAvatar()) else if (packet->ToNetPacketRetrieveAvatar())
{ {
// Delegate to Lobby. // Delegate to Lobby.
GetServerGame().GetLobbyThread().HandleGameRetrieveAvatar(session, *packet->ToNetPacketRetrieveAvatar()); server.GetLobbyThread().HandleGameRetrieveAvatar(session, *packet->ToNetPacketRetrieveAvatar());
} }
else if (packet->ToNetPacketLeaveCurrentGame()) else if (packet->ToNetPacketLeaveCurrentGame())
{ {
GetServerGame().MoveSessionToLobby(session, NTF_NET_REMOVED_ON_REQUEST); server.MoveSessionToLobby(session, NTF_NET_REMOVED_ON_REQUEST);
} }
else if (packet->ToNetPacketKickPlayer()) else if (packet->ToNetPacketKickPlayer())
{ {
// Only admins are allowed to kick, and only in the lobby. // Only admins are allowed to kick, and only in the lobby.
// After leaving the lobby, a vote needs to be initiated to kick. // After leaving the lobby, a vote needs to be initiated to kick.
if (session.playerData->GetRights() == PLAYER_RIGHTS_ADMIN && !GetServerGame().IsRunning()) if (session.playerData->GetRights() == PLAYER_RIGHTS_ADMIN && !server.IsRunning())
{ {
NetPacketKickPlayer::Data kickPlayerData; NetPacketKickPlayer::Data kickPlayerData;
packet->ToNetPacketKickPlayer()->GetData(kickPlayerData); packet->ToNetPacketKickPlayer()->GetData(kickPlayerData);
GetServerGame().InternalKickPlayer(kickPlayerData.playerId); server.InternalKickPlayer(kickPlayerData.playerId);
} }
} }
else if (packet->ToNetPacketAskKickPlayer()) else if (packet->ToNetPacketAskKickPlayer())
@@ -316,7 +311,7 @@ AbstractServerGameStateReceiving::ProcessPacket(SessionWrapper session, boost::s
NetPacketAskKickPlayer::Data askKickData; NetPacketAskKickPlayer::Data askKickData;
packet->ToNetPacketAskKickPlayer()->GetData(askKickData); packet->ToNetPacketAskKickPlayer()->GetData(askKickData);
GetServerGame().InternalAskVoteKick(session, askKickData.playerId, SERVER_VOTE_KICK_TIMEOUT_SEC); server.InternalAskVoteKick(session, askKickData.playerId, SERVER_VOTE_KICK_TIMEOUT_SEC);
} }
} }
else if (packet->ToNetPacketVoteKickPlayer()) else if (packet->ToNetPacketVoteKickPlayer())
@@ -326,7 +321,7 @@ AbstractServerGameStateReceiving::ProcessPacket(SessionWrapper session, boost::s
NetPacketVoteKickPlayer::Data voteData; NetPacketVoteKickPlayer::Data voteData;
packet->ToNetPacketVoteKickPlayer()->GetData(voteData); packet->ToNetPacketVoteKickPlayer()->GetData(voteData);
GetServerGame().InternalVoteKick(session, voteData.petitionId, voteData.vote); server.InternalVoteKick(session, voteData.petitionId, voteData.vote);
} }
} }
// Chat text is always allowed. // Chat text is always allowed.
@@ -344,7 +339,7 @@ AbstractServerGameStateReceiving::ProcessPacket(SessionWrapper session, boost::s
outChatData.playerId = session.playerData->GetUniqueId(); outChatData.playerId = session.playerData->GetUniqueId();
outChatData.text = inChatData.text; outChatData.text = inChatData.text;
static_cast<NetPacketChatText *>(outChat.get())->SetData(outChatData); static_cast<NetPacketChatText *>(outChat.get())->SetData(outChatData);
GetServerGame().SendToAllPlayers(outChat, SessionData::Game); server.SendToAllPlayers(outChat, SessionData::Game);
} }
} }
else if (packet->ToNetPacketUnsubscribeGameList()) else if (packet->ToNetPacketUnsubscribeGameList())
@@ -357,12 +352,12 @@ AbstractServerGameStateReceiving::ProcessPacket(SessionWrapper session, boost::s
// This needs to be performed in the lobby thread, // This needs to be performed in the lobby thread,
// because a new game list needs to be sent. // because a new game list needs to be sent.
if (!session.sessionData->WantsLobbyMsg()) if (!session.sessionData->WantsLobbyMsg())
GetServerGame().GetLobbyThread().ResubscribeLobbyMsg(session); server.GetLobbyThread().ResubscribeLobbyMsg(session);
} }
else else
{ {
// Packet processing in subclass. // Packet processing in subclass.
retVal = InternalProcessPacket(session, packet); retVal = InternalProcessPacket(server, session, packet);
} }
return retVal; return retVal;
@@ -370,43 +365,61 @@ AbstractServerGameStateReceiving::ProcessPacket(SessionWrapper session, boost::s
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
ServerGameStateInit::ServerGameStateInit(ServerGameThread &serverGame) ServerGameStateInit ServerGameStateInit::s_state;
: AbstractServerGameStateReceiving(serverGame), m_timerRegistered(false)
ServerGameStateInit &
ServerGameStateInit::Instance()
{
return s_state;
}
ServerGameStateInit::ServerGameStateInit()
{ {
RegisterAdminTimers();
} }
ServerGameStateInit::~ServerGameStateInit() ServerGameStateInit::~ServerGameStateInit()
{ {
UnregisterAdminTimers();
} }
void void
ServerGameStateInit::NotifyGameAdminChanged() ServerGameStateInit::Enter(ServerGameThread &server)
{ {
RegisterAdminTimers(); RegisterAdminTimer(server);
} }
void void
ServerGameStateInit::HandleNewSession(SessionWrapper session) ServerGameStateInit::Exit(ServerGameThread &server)
{
UnregisterAdminTimer(server);
}
void
ServerGameStateInit::NotifyGameAdminChanged(ServerGameThread &server)
{
UnregisterAdminTimer(server);
RegisterAdminTimer(server);
}
void
ServerGameStateInit::HandleNewSession(ServerGameThread &server, SessionWrapper session)
{ {
if (session.sessionData.get() && session.playerData.get()) if (session.sessionData.get() && session.playerData.get())
{ {
size_t curNumPlayers = GetServerGame().GetCurNumberOfPlayers(); size_t curNumPlayers = server.GetCurNumberOfPlayers();
// Check the number of players. // Check the number of players.
if (curNumPlayers >= (size_t)GetServerGame().GetGameData().maxNumberOfPlayers) if (curNumPlayers >= (size_t)server.GetGameData().maxNumberOfPlayers)
{ {
GetServerGame().MoveSessionToLobby(session, NTF_NET_REMOVED_GAME_FULL); server.MoveSessionToLobby(session, NTF_NET_REMOVED_GAME_FULL);
} }
// Check whether the client supports the current game. // Check whether the client supports the current game.
else if ((size_t)GetServerGame().GetGameData().maxNumberOfPlayers > session.sessionData->GetMaxNumPlayers()) else if ((size_t)server.GetGameData().maxNumberOfPlayers > session.sessionData->GetMaxNumPlayers())
{ {
GetServerGame().MoveSessionToLobby(session, NTF_NET_REMOVED_GAME_FULL); server.MoveSessionToLobby(session, NTF_NET_REMOVED_GAME_FULL);
} }
else else
{ {
if (session.playerData->GetUniqueId() == GetServerGame().GetAdminPlayerId()) if (session.playerData->GetUniqueId() == server.GetAdminPlayerId())
{ {
// This is the admin player. // This is the admin player.
session.playerData->SetRights(PLAYER_RIGHTS_ADMIN); session.playerData->SetRights(PLAYER_RIGHTS_ADMIN);
@@ -415,14 +428,14 @@ ServerGameStateInit::HandleNewSession(SessionWrapper session)
// Send ack to client. // Send ack to client.
boost::shared_ptr<NetPacket> joinGameAck(new NetPacketJoinGameAck); boost::shared_ptr<NetPacket> joinGameAck(new NetPacketJoinGameAck);
NetPacketJoinGameAck::Data joinGameAckData; NetPacketJoinGameAck::Data joinGameAckData;
joinGameAckData.gameId = GetServerGame().GetId(); joinGameAckData.gameId = server.GetId();
joinGameAckData.prights = session.playerData->GetRights(); joinGameAckData.prights = session.playerData->GetRights();
joinGameAckData.gameData = GetServerGame().GetGameData(); joinGameAckData.gameData = server.GetGameData();
static_cast<NetPacketJoinGameAck *>(joinGameAck.get())->SetData(joinGameAckData); static_cast<NetPacketJoinGameAck *>(joinGameAck.get())->SetData(joinGameAckData);
session.sessionData->GetSender().Send(session.sessionData, joinGameAck); session.sessionData->GetSender().Send(session.sessionData, joinGameAck);
// Send notifications for connected players to client. // Send notifications for connected players to client.
PlayerDataList tmpPlayerList = GetServerGame().GetFullPlayerDataList(); PlayerDataList tmpPlayerList = server.GetFullPlayerDataList();
PlayerDataList::iterator player_i = tmpPlayerList.begin(); PlayerDataList::iterator player_i = tmpPlayerList.begin();
PlayerDataList::iterator player_end = tmpPlayerList.end(); PlayerDataList::iterator player_end = tmpPlayerList.end();
while (player_i != player_end) while (player_i != player_end)
@@ -432,48 +445,38 @@ ServerGameStateInit::HandleNewSession(SessionWrapper session)
} }
// Send "Player Joined" to other fully connected clients. // Send "Player Joined" to other fully connected clients.
GetServerGame().SendToAllPlayers(CreateNetPacketPlayerJoined(*session.playerData), SessionData::Game); server.SendToAllPlayers(CreateNetPacketPlayerJoined(*session.playerData), SessionData::Game);
// Accept session. // Accept session.
GetServerGame().GetSessionManager().AddSession(session); server.GetSessionManager().AddSession(session);
// Notify lobby. // Notify lobby.
GetServerGame().GetLobbyThread().NotifyPlayerJoinedGame(GetServerGame().GetId(), session.playerData->GetUniqueId()); server.GetLobbyThread().NotifyPlayerJoinedGame(server.GetId(), session.playerData->GetUniqueId());
} }
} }
} }
void void
ServerGameStateInit::RegisterAdminTimers() ServerGameStateInit::RegisterAdminTimer(ServerGameThread &server)
{ {
if (m_timerRegistered) server.SetStateTimerId(
UnregisterAdminTimers(); server.GetLobbyThread().GetTimerManager().RegisterTimer(
(SERVER_GAME_ADMIN_TIMEOUT_SEC - SERVER_GAME_ADMIN_WARNING_REMAINING_SEC) * 1000,
m_adminWarningTimerId = GetServerGame().GetLobbyThread().GetTimerManager().RegisterTimer( boost::bind(&ServerGameStateInit::TimerAdminWarning, this, boost::ref(server))));
(SERVER_GAME_ADMIN_TIMEOUT_SEC - SERVER_GAME_ADMIN_WARNING_REMAINING_SEC) * 1000,
boost::bind(&ServerGameStateInit::TimerAdminWarning, this));
m_adminTimeoutTimerId = GetServerGame().GetLobbyThread().GetTimerManager().RegisterTimer(
SERVER_GAME_ADMIN_TIMEOUT_SEC * 1000,
boost::bind(&ServerGameStateInit::TimerAdminTimeout, this));
m_timerRegistered = true;
} }
void void
ServerGameStateInit::UnregisterAdminTimers() ServerGameStateInit::UnregisterAdminTimer(ServerGameThread &server)
{ {
if (m_timerRegistered) server.GetLobbyThread().GetTimerManager().UnregisterTimer(server.GetStateTimerId());
{ server.SetStateTimerId(0);
GetServerGame().GetLobbyThread().GetTimerManager().UnregisterTimer(m_adminWarningTimerId);
GetServerGame().GetLobbyThread().GetTimerManager().UnregisterTimer(m_adminTimeoutTimerId);
m_timerRegistered = false;
}
} }
void void
ServerGameStateInit::TimerAdminWarning() ServerGameStateInit::TimerAdminWarning(ServerGameThread &server)
{ {
// Find game admin. // Find game admin.
SessionWrapper session = GetServerGame().GetSessionManager().GetSessionByUniquePlayerId(GetServerGame().GetAdminPlayerId()); SessionWrapper session = server.GetSessionManager().GetSessionByUniquePlayerId(server.GetAdminPlayerId());
if (session.sessionData.get()) if (session.sessionData.get())
{ {
// Send him a warning. // Send him a warning.
@@ -484,22 +487,27 @@ ServerGameStateInit::TimerAdminWarning()
static_cast<NetPacketTimeoutWarning *>(warning.get())->SetData(warningData); static_cast<NetPacketTimeoutWarning *>(warning.get())->SetData(warningData);
session.sessionData->GetSender().Send(session.sessionData, warning); session.sessionData->GetSender().Send(session.sessionData, warning);
} }
// Start timeout timer.
server.SetStateTimerId(
server.GetLobbyThread().GetTimerManager().RegisterTimer(
SERVER_GAME_ADMIN_WARNING_REMAINING_SEC * 1000,
boost::bind(&ServerGameStateInit::TimerAdminTimeout, this, boost::ref(server))));
} }
void void
ServerGameStateInit::TimerAdminTimeout() ServerGameStateInit::TimerAdminTimeout(ServerGameThread &server)
{ {
// Find game admin. // Find game admin.
SessionWrapper session = GetServerGame().GetSessionManager().GetSessionByUniquePlayerId(GetServerGame().GetAdminPlayerId()); SessionWrapper session = server.GetSessionManager().GetSessionByUniquePlayerId(server.GetAdminPlayerId());
if (session.sessionData.get()) if (session.sessionData.get())
{ {
// Remove him from the game. // Remove him from the game.
GetServerGame().MoveSessionToLobby(session, NTF_NET_REMOVED_TIMEOUT); server.MoveSessionToLobby(session, NTF_NET_REMOVED_TIMEOUT);
} }
} }
int int
ServerGameStateInit::InternalProcessPacket(SessionWrapper session, boost::shared_ptr<NetPacket> packet) ServerGameStateInit::InternalProcessPacket(ServerGameThread &server, SessionWrapper session, boost::shared_ptr<NetPacket> packet)
{ {
int retVal = MSG_SOCK_INTERNAL_PENDING; int retVal = MSG_SOCK_INTERNAL_PENDING;
@@ -512,44 +520,45 @@ ServerGameStateInit::InternalProcessPacket(SessionWrapper session, boost::shared
packet->ToNetPacketStartEvent()->GetData(startData); packet->ToNetPacketStartEvent()->GetData(startData);
// Fill up with computer players. // Fill up with computer players.
GetServerGame().ResetComputerPlayerList(); server.ResetComputerPlayerList();
if (startData.fillUpWithCpuPlayers) if (startData.fillUpWithCpuPlayers)
{ {
int remainingSlots = GetServerGame().GetGameData().maxNumberOfPlayers - GetServerGame().GetCurNumberOfPlayers(); int remainingSlots = server.GetGameData().maxNumberOfPlayers - server.GetCurNumberOfPlayers();
for (int i = 1; i <= remainingSlots; i++) for (int i = 1; i <= remainingSlots; i++)
{ {
boost::shared_ptr<PlayerData> tmpPlayerData( boost::shared_ptr<PlayerData> tmpPlayerData(
new PlayerData(GetServerGame().GetLobbyThread().GetNextUniquePlayerId(), 0, PLAYER_TYPE_COMPUTER, PLAYER_RIGHTS_NORMAL)); new PlayerData(server.GetLobbyThread().GetNextUniquePlayerId(), 0, PLAYER_TYPE_COMPUTER, PLAYER_RIGHTS_NORMAL));
ostringstream name; ostringstream name;
name << SERVER_COMPUTER_PLAYER_NAME << i; name << SERVER_COMPUTER_PLAYER_NAME << i;
tmpPlayerData->SetName(name.str()); tmpPlayerData->SetName(name.str());
GetServerGame().AddComputerPlayer(tmpPlayerData); server.AddComputerPlayer(tmpPlayerData);
// Send "Player Joined" to other fully connected clients. // Send "Player Joined" to other fully connected clients.
GetServerGame().SendToAllPlayers(CreateNetPacketPlayerJoined(*tmpPlayerData), SessionData::Game); server.SendToAllPlayers(CreateNetPacketPlayerJoined(*tmpPlayerData), SessionData::Game);
// Notify lobby. // Notify lobby.
GetServerGame().GetLobbyThread().NotifyPlayerJoinedGame(GetServerGame().GetId(), tmpPlayerData->GetUniqueId()); server.GetLobbyThread().NotifyPlayerJoinedGame(server.GetId(), tmpPlayerData->GetUniqueId());
} }
} }
// Wait for all players to confirm start of game. // Wait for all players to confirm start of game.
GetServerGame().SendToAllPlayers(boost::shared_ptr<NetPacket>(packet->Clone()), SessionData::Game); server.SendToAllPlayers(boost::shared_ptr<NetPacket>(packet->Clone()), SessionData::Game);
GetServerGame().SetState(boost::shared_ptr<ServerGameState>(new ServerGameStateStartGame(GetServerGame()))); server.SetState(ServerGameStateStartGame::Instance());
} }
} }
else if (packet->ToNetPacketResetTimeout()) else if (packet->ToNetPacketResetTimeout())
{ {
if (session.playerData->GetRights() == PLAYER_RIGHTS_ADMIN) if (session.playerData->GetRights() == PLAYER_RIGHTS_ADMIN)
{ {
RegisterAdminTimers(); UnregisterAdminTimer(server);
RegisterAdminTimer(server);
} }
} }
else else
{ {
GetServerGame().SessionError(session, ERR_SOCK_INVALID_PACKET); server.SessionError(session, ERR_SOCK_INVALID_PACKET);
} }
return retVal; return retVal;
@@ -568,41 +577,60 @@ ServerGameStateInit::CreateNetPacketPlayerJoined(const PlayerData &playerData)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
ServerGameStateStartGame::ServerGameStateStartGame(ServerGameThread &serverGame) ServerGameStateStartGame ServerGameStateStartGame::s_state;
: AbstractServerGameStateReceiving(serverGame)
ServerGameStateStartGame &
ServerGameStateStartGame::Instance()
{
return s_state;
}
ServerGameStateStartGame::ServerGameStateStartGame()
{ {
m_timeoutTimerId = GetServerGame().GetLobbyThread().GetTimerManager().RegisterTimer(
SERVER_START_GAME_TIMEOUT_SEC * 1000,
boost::bind(&ServerGameStateStartGame::TimerTimeout, this));
} }
ServerGameStateStartGame::~ServerGameStateStartGame() ServerGameStateStartGame::~ServerGameStateStartGame()
{ {
// The Id might be invalid, but this is not a problem.
GetServerGame().GetLobbyThread().GetTimerManager().UnregisterTimer(m_timeoutTimerId);
} }
void void
ServerGameStateStartGame::HandleNewSession(SessionWrapper session) ServerGameStateStartGame::Enter(ServerGameThread &server)
{
server.SetStateTimerId(
server.GetLobbyThread().GetTimerManager().RegisterTimer(
SERVER_START_GAME_TIMEOUT_SEC * 1000,
boost::bind(&ServerGameStateStartGame::TimerTimeout, this, boost::ref(server))));
}
void
ServerGameStateStartGame::Exit(ServerGameThread &server)
{
// The Id might be invalid, but this is not a problem.
server.GetLobbyThread().GetTimerManager().UnregisterTimer(server.GetStateTimerId());
server.SetStateTimerId(0);
}
void
ServerGameStateStartGame::HandleNewSession(ServerGameThread &server, SessionWrapper session)
{ {
// Do not accept new sessions in this state. // Do not accept new sessions in this state.
GetServerGame().MoveSessionToLobby(session, NTF_NET_REMOVED_ALREADY_RUNNING); server.MoveSessionToLobby(session, NTF_NET_REMOVED_ALREADY_RUNNING);
} }
int int
ServerGameStateStartGame::InternalProcessPacket(SessionWrapper session, boost::shared_ptr<NetPacket> packet) ServerGameStateStartGame::InternalProcessPacket(ServerGameThread &server, SessionWrapper session, boost::shared_ptr<NetPacket> packet)
{ {
int retVal = MSG_SOCK_INTERNAL_PENDING; int retVal = MSG_SOCK_INTERNAL_PENDING;
if (packet->ToNetPacketStartEventAck()) if (packet->ToNetPacketStartEventAck())
{ {
session.sessionData->SetReadyFlag(); session.sessionData->SetReadyFlag();
if (GetServerGame().GetSessionManager().CountReadySessions() == GetServerGame().GetSessionManager().GetRawSessionCount()) if (server.GetSessionManager().CountReadySessions() == server.GetSessionManager().GetRawSessionCount())
{ {
// Everyone is ready. // Everyone is ready.
GetServerGame().GetSessionManager().ResetAllReadyFlags(); server.GetSessionManager().ResetAllReadyFlags();
DoStart(); DoStart(server);
GetServerGame().SetState(boost::shared_ptr<ServerGameState>(new SERVER_START_GAME_STATE(GetServerGame()))); server.SetState(SERVER_START_GAME_STATE::Instance());
retVal = MSG_SOCK_INIT_DONE; retVal = MSG_SOCK_INIT_DONE;
} }
} }
@@ -611,38 +639,38 @@ ServerGameStateStartGame::InternalProcessPacket(SessionWrapper session, boost::s
} }
void void
ServerGameStateStartGame::TimerTimeout() ServerGameStateStartGame::TimerTimeout(ServerGameThread &server)
{ {
// On timeout: start anyway. // On timeout: start anyway.
GetServerGame().GetSessionManager().ResetAllReadyFlags(); server.GetSessionManager().ResetAllReadyFlags();
// TODO report successful start! -> new callback?! // TODO report successful start! -> new callback?!
//retVal = MSG_SOCK_INIT_DONE; //retVal = MSG_SOCK_INIT_DONE;
DoStart(); DoStart(server);
GetServerGame().SetState(boost::shared_ptr<ServerGameState>(new SERVER_START_GAME_STATE(GetServerGame()))); server.SetState(SERVER_START_GAME_STATE::Instance());
} }
void void
ServerGameStateStartGame::DoStart() ServerGameStateStartGame::DoStart(ServerGameThread &server)
{ {
PlayerDataList tmpPlayerList = GetServerGame().GetFullPlayerDataList(); PlayerDataList tmpPlayerList = server.GetFullPlayerDataList();
if (tmpPlayerList.size() <= 1) if (tmpPlayerList.size() <= 1)
{ {
if (!tmpPlayerList.empty()) if (!tmpPlayerList.empty())
{ {
boost::shared_ptr<PlayerData> tmpPlayer(tmpPlayerList.front()); boost::shared_ptr<PlayerData> tmpPlayer(tmpPlayerList.front());
SessionWrapper tmpSession = GetServerGame().GetSessionManager().GetSessionByUniquePlayerId(tmpPlayer->GetUniqueId()); SessionWrapper tmpSession = server.GetSessionManager().GetSessionByUniquePlayerId(tmpPlayer->GetUniqueId());
if (tmpSession.sessionData.get()) if (tmpSession.sessionData.get())
GetServerGame().MoveSessionToLobby(tmpSession, NTF_NET_REMOVED_START_FAILED); server.MoveSessionToLobby(tmpSession, NTF_NET_REMOVED_START_FAILED);
} }
} }
else else
{ {
GetServerGame().InternalStartGame(); server.InternalStartGame();
boost::shared_ptr<NetPacket> answer(new NetPacketGameStart); boost::shared_ptr<NetPacket> answer(new NetPacketGameStart);
NetPacketGameStart::Data gameStartData; NetPacketGameStart::Data gameStartData;
gameStartData.startData = GetServerGame().GetStartData(); gameStartData.startData = server.GetStartData();
// Send player order to clients. // Send player order to clients.
// Assume player list is sorted by number. // Assume player list is sorted by number.
@@ -658,49 +686,68 @@ ServerGameStateStartGame::DoStart()
} }
static_cast<NetPacketGameStart *>(answer.get())->SetData(gameStartData); static_cast<NetPacketGameStart *>(answer.get())->SetData(gameStartData);
GetServerGame().SendToAllPlayers(answer, SessionData::Game); server.SendToAllPlayers(answer, SessionData::Game);
// Start the first hand. // Start the first hand.
StartNewHand(GetServerGame()); StartNewHand(server);
GetServerGame().SetState(boost::shared_ptr<ServerGameState>(new ServerGameStateHand(GetServerGame()))); server.SetState(ServerGameStateHand::Instance());
} }
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
ServerGameStateHand::ServerGameStateHand(ServerGameThread &serverGame) ServerGameStateHand ServerGameStateHand::s_state;
: AbstractServerGameStateReceiving(serverGame)
ServerGameStateHand &
ServerGameStateHand::Instance()
{
return s_state;
}
ServerGameStateHand::ServerGameStateHand()
{ {
m_loopTimerId = GetServerGame().GetLobbyThread().GetTimerManager().RegisterTimer(
SERVER_LOOP_DELAY_MSEC,
boost::bind(&ServerGameStateHand::TimerLoop, this));
} }
ServerGameStateHand::~ServerGameStateHand() ServerGameStateHand::~ServerGameStateHand()
{ {
// The Id might be invalid, but this is not a problem.
GetServerGame().GetLobbyThread().GetTimerManager().UnregisterTimer(m_loopTimerId);
} }
void void
ServerGameStateHand::HandleNewSession(SessionWrapper session) ServerGameStateHand::Enter(ServerGameThread &server)
{
server.SetStateTimerId(
server.GetLobbyThread().GetTimerManager().RegisterTimer(
SERVER_LOOP_DELAY_MSEC,
boost::bind(&ServerGameStateHand::TimerLoop, this, boost::ref(server))));
}
void
ServerGameStateHand::Exit(ServerGameThread &server)
{
// The Id might be invalid, but this is not a problem.
server.GetLobbyThread().GetTimerManager().UnregisterTimer(server.GetStateTimerId());
server.SetStateTimerId(0);
}
void
ServerGameStateHand::HandleNewSession(ServerGameThread &server, SessionWrapper session)
{ {
// Do not accept new sessions in this state. // Do not accept new sessions in this state.
GetServerGame().MoveSessionToLobby(session, NTF_NET_REMOVED_ALREADY_RUNNING); server.MoveSessionToLobby(session, NTF_NET_REMOVED_ALREADY_RUNNING);
} }
int int
ServerGameStateHand::InternalProcessPacket(SessionWrapper /*session*/, boost::shared_ptr<NetPacket> /*packet*/) ServerGameStateHand::InternalProcessPacket(ServerGameThread &/*server*/, SessionWrapper /*session*/, boost::shared_ptr<NetPacket> /*packet*/)
{ {
// TODO: maybe reject packet. // TODO: maybe reject packet.
return MSG_SOCK_INTERNAL_PENDING; return MSG_SOCK_INTERNAL_PENDING;
} }
void void
ServerGameStateHand::TimerLoop() ServerGameStateHand::TimerLoop(ServerGameThread &server)
{ {
bool newTimerSet = false; server.SetStateTimerId(0);
Game &curGame = GetServerGame().GetGame(); Game &curGame = server.GetGame();
// Main game loop. // Main game loop.
int curRound = curGame.getCurrentHand()->getCurrentRound(); int curRound = curGame.getCurrentHand()->getCurrentRound();
@@ -744,22 +791,22 @@ ServerGameStateHand::TimerLoop()
++i; ++i;
} }
static_cast<NetPacketAllInShowCards *>(allIn.get())->SetData(allInData); static_cast<NetPacketAllInShowCards *>(allIn.get())->SetData(allInData);
GetServerGame().SendToAllPlayers(allIn, SessionData::Game); server.SendToAllPlayers(allIn, SessionData::Game);
curGame.getCurrentHand()->setCardsShown(true); curGame.getCurrentHand()->setCardsShown(true);
m_loopTimerId = GetServerGame().GetLobbyThread().GetTimerManager().RegisterTimer( server.SetStateTimerId(
SERVER_SHOW_CARDS_DELAY_SEC * 1000, server.GetLobbyThread().GetTimerManager().RegisterTimer(
boost::bind(&ServerGameStateHand::TimerLoop, this)); SERVER_SHOW_CARDS_DELAY_SEC * 1000,
newTimerSet = true; boost::bind(&ServerGameStateHand::TimerLoop, this, boost::ref(server))));
} }
else else
{ {
SendNewRoundCards(GetServerGame(), curGame, newRound); SendNewRoundCards(server, curGame, newRound);
m_loopTimerId = GetServerGame().GetLobbyThread().GetTimerManager().RegisterTimer( server.SetStateTimerId(
GetDealCardsDelaySec() * 1000, server.GetLobbyThread().GetTimerManager().RegisterTimer(
boost::bind(&ServerGameStateHand::TimerLoop, this)); GetDealCardsDelaySec(server) * 1000,
newTimerSet = true; boost::bind(&ServerGameStateHand::TimerLoop, this, boost::ref(server))));
} }
} }
else else
@@ -782,25 +829,24 @@ ServerGameStateHand::TimerLoop()
playersTurnData.playerId = curPlayer->getMyUniqueID(); playersTurnData.playerId = curPlayer->getMyUniqueID();
static_cast<NetPacketPlayersTurn *>(notification.get())->SetData(playersTurnData); static_cast<NetPacketPlayersTurn *>(notification.get())->SetData(playersTurnData);
GetServerGame().SendToAllPlayers(notification, SessionData::Game); server.SendToAllPlayers(notification, SessionData::Game);
// If the player is computer controlled, let the engine act. // If the player is computer controlled, let the engine act.
if (curPlayer->getMyType() == PLAYER_TYPE_COMPUTER) if (curPlayer->getMyType() == PLAYER_TYPE_COMPUTER)
{ {
m_loopTimerId = GetServerGame().GetLobbyThread().GetTimerManager().RegisterTimer( server.SetStateTimerId(
SERVER_COMPUTER_ACTION_DELAY_SEC * 1000, server.GetLobbyThread().GetTimerManager().RegisterTimer(
boost::bind(&ServerGameStateHand::TimerComputerAction, this)); SERVER_COMPUTER_ACTION_DELAY_SEC * 1000,
newTimerSet = true; boost::bind(&ServerGameStateHand::TimerComputerAction, this, boost::ref(server))));
} }
// If the player we are waiting for left, continue without him. // If the player we are waiting for left, continue without him.
else if (!GetServerGame().GetSessionManager().IsPlayerConnected(curPlayer->getMyName())) else if (!server.GetSessionManager().IsPlayerConnected(curPlayer->getMyName()))
{ {
PerformPlayerAction(GetServerGame(), curPlayer, PLAYER_ACTION_FOLD, 0); PerformPlayerAction(server, curPlayer, PLAYER_ACTION_FOLD, 0);
} }
else else
{ {
//wrong!!! server.SetState(ServerGameStateWaitPlayerAction::Instance());
GetServerGame().SetState(boost::shared_ptr<ServerGameState>(new ServerGameStateWaitPlayerAction(GetServerGame())));
} }
} }
else // hand is over else // hand is over
@@ -823,7 +869,7 @@ ServerGameStateHand::TimerLoop()
endHandData.playerMoney = player->getMyCash(); endHandData.playerMoney = player->getMyCash();
static_cast<NetPacketEndOfHandHideCards *>(endHand.get())->SetData(endHandData); static_cast<NetPacketEndOfHandHideCards *>(endHand.get())->SetData(endHandData);
GetServerGame().SendToAllPlayers(endHand, SessionData::Game); server.SendToAllPlayers(endHand, SessionData::Game);
} }
else else
{ {
@@ -858,11 +904,11 @@ ServerGameStateHand::TimerLoop()
} }
static_cast<NetPacketEndOfHandShowCards *>(endHand.get())->SetData(endHandData); static_cast<NetPacketEndOfHandShowCards *>(endHand.get())->SetData(endHandData);
GetServerGame().SendToAllPlayers(endHand, SessionData::Game); server.SendToAllPlayers(endHand, SessionData::Game);
} }
// Remove disconnected players. This is the one and only place to do this. // Remove disconnected players. This is the one and only place to do this.
GetServerGame().RemoveDisconnectedPlayers(); server.RemoveDisconnectedPlayers();
// Start next hand - if enough players are left. // Start next hand - if enough players are left.
list<boost::shared_ptr<PlayerInterface> > playersWithCash = *curGame.getActivePlayerList(); list<boost::shared_ptr<PlayerInterface> > playersWithCash = *curGame.getActivePlayerList();
@@ -871,60 +917,61 @@ ServerGameStateHand::TimerLoop()
if (playersWithCash.empty()) if (playersWithCash.empty())
{ {
// No more players left - restart. // No more players left - restart.
//wrong!!! server.SetState(SERVER_INITIAL_STATE::Instance());
GetServerGame().SetState(boost::shared_ptr<ServerGameState>(new SERVER_INITIAL_STATE(GetServerGame())));
} }
else if (playersWithCash.size() == 1) else if (playersWithCash.size() == 1)
{ {
// View a dialog for a new game - delayed. // View a dialog for a new game - delayed.
m_loopTimerId = GetServerGame().GetLobbyThread().GetTimerManager().RegisterTimer( server.SetStateTimerId(
SERVER_DELAY_NEXT_GAME_SEC * 1000, server.GetLobbyThread().GetTimerManager().RegisterTimer(
boost::bind(&ServerGameStateHand::TimerNextGame, this)); SERVER_DELAY_NEXT_GAME_SEC * 1000,
newTimerSet = true; boost::bind(&ServerGameStateHand::TimerNextGame, this, boost::ref(server))));
} }
else else
{ {
m_loopTimerId = GetServerGame().GetLobbyThread().GetTimerManager().RegisterTimer( server.SetStateTimerId(
SERVER_DELAY_NEXT_HAND_SEC * 1000, server.GetLobbyThread().GetTimerManager().RegisterTimer(
boost::bind(&ServerGameStateHand::TimerNextHand, this)); SERVER_DELAY_NEXT_HAND_SEC * 1000,
newTimerSet = true; boost::bind(&ServerGameStateHand::TimerNextHand, this, boost::ref(server))));
} }
} }
} }
// TODO if not state changed and not timer set, set new loop timer.
} }
void void
ServerGameStateHand::TimerShowCards() ServerGameStateHand::TimerShowCards(ServerGameThread &server)
{ {
Game &curGame = GetServerGame().GetGame(); Game &curGame = server.GetGame();
SendNewRoundCards(GetServerGame(), curGame, curGame.getCurrentHand()->getCurrentRound()); SendNewRoundCards(server, curGame, curGame.getCurrentHand()->getCurrentRound());
m_loopTimerId = GetServerGame().GetLobbyThread().GetTimerManager().RegisterTimer( server.SetStateTimerId(
GetDealCardsDelaySec() * 1000, server.GetLobbyThread().GetTimerManager().RegisterTimer(
boost::bind(&ServerGameStateHand::TimerLoop, this)); GetDealCardsDelaySec(server) * 1000,
boost::bind(&ServerGameStateHand::TimerLoop, this, boost::ref(server))));
} }
void void
ServerGameStateHand::TimerComputerAction() ServerGameStateHand::TimerComputerAction(ServerGameThread &server)
{ {
boost::shared_ptr<PlayerInterface> tmpPlayer = GetServerGame().GetGame().getCurrentPlayer(); boost::shared_ptr<PlayerInterface> tmpPlayer = server.GetGame().getCurrentPlayer();
tmpPlayer->action(); tmpPlayer->action();
SendPlayerAction(GetServerGame(), tmpPlayer); SendPlayerAction(server, tmpPlayer);
TimerLoop(); TimerLoop(server);
} }
void void
ServerGameStateHand::TimerNextHand() ServerGameStateHand::TimerNextHand(ServerGameThread &server)
{ {
StartNewHand(GetServerGame()); StartNewHand(server);
TimerLoop(); TimerLoop(server);
} }
void void
ServerGameStateHand::TimerNextGame() ServerGameStateHand::TimerNextGame(ServerGameThread &server)
{ {
Game &curGame = GetServerGame().GetGame(); Game &curGame = server.GetGame();
// The game has ended. Notify all clients. // The game has ended. Notify all clients.
boost::shared_ptr<PlayerInterface> winnerPlayer; boost::shared_ptr<PlayerInterface> winnerPlayer;
PlayerListIterator i = curGame.getActivePlayerList()->begin(); PlayerListIterator i = curGame.getActivePlayerList()->begin();
@@ -942,19 +989,19 @@ ServerGameStateHand::TimerNextGame()
endGameData.winnerPlayerId = winnerPlayer->getMyUniqueID(); endGameData.winnerPlayerId = winnerPlayer->getMyUniqueID();
static_cast<NetPacketEndOfGame *>(endGame.get())->SetData(endGameData); static_cast<NetPacketEndOfGame *>(endGame.get())->SetData(endGameData);
GetServerGame().SendToAllPlayers(endGame, SessionData::Game); server.SendToAllPlayers(endGame, SessionData::Game);
// Wait for the start of a new game. // Wait for the start of a new game.
GetServerGame().ResetComputerPlayerList(); server.ResetComputerPlayerList();
GetServerGame().ResetGame(); server.ResetGame();
GetServerGame().GetLobbyThread().NotifyReopeningGame(GetServerGame().GetId()); server.GetLobbyThread().NotifyReopeningGame(server.GetId());
GetServerGame().SetState(boost::shared_ptr<ServerGameState>(new ServerGameStateInit(GetServerGame()))); server.SetState(ServerGameStateInit::Instance());
} }
int int
ServerGameStateHand::GetDealCardsDelaySec() ServerGameStateHand::GetDealCardsDelaySec(ServerGameThread &server)
{ {
Game &curGame = GetServerGame().GetGame(); Game &curGame = server.GetGame();
int allInDelay = curGame.getCurrentHand()->getAllInCondition() ? SERVER_DEAL_ADD_ALL_IN_DELAY_SEC : 0; int allInDelay = curGame.getCurrentHand()->getAllInCondition() ? SERVER_DEAL_ADD_ALL_IN_DELAY_SEC : 0;
int delay = 0; int delay = 0;
@@ -975,35 +1022,55 @@ ServerGameStateHand::GetDealCardsDelaySec()
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
ServerGameStateWaitPlayerAction::ServerGameStateWaitPlayerAction(ServerGameThread &serverGame)
: AbstractServerGameStateReceiving(serverGame)
{
#ifdef SERVER_TEST
int timeoutSec = 0;
#else
int timeoutSec = GetServerGame().GetGameData().playerActionTimeoutSec + SERVER_PLAYER_TIMEOUT_ADD_DELAY_SEC;
#endif
m_timeoutTimerId = GetServerGame().GetLobbyThread().GetTimerManager().RegisterTimer( ServerGameStateWaitPlayerAction ServerGameStateWaitPlayerAction::s_state;
timeoutSec * 1000,
boost::bind(&ServerGameStateWaitPlayerAction::TimerTimeout, this)); ServerGameStateWaitPlayerAction &
ServerGameStateWaitPlayerAction::Instance()
{
return s_state;
}
ServerGameStateWaitPlayerAction::ServerGameStateWaitPlayerAction()
{
} }
ServerGameStateWaitPlayerAction::~ServerGameStateWaitPlayerAction() ServerGameStateWaitPlayerAction::~ServerGameStateWaitPlayerAction()
{ {
// The Id might be invalid, but this is not a problem.
GetServerGame().GetLobbyThread().GetTimerManager().UnregisterTimer(m_timeoutTimerId);
} }
void void
ServerGameStateWaitPlayerAction::HandleNewSession(SessionWrapper session) ServerGameStateWaitPlayerAction::Enter(ServerGameThread &server)
{
#ifdef SERVER_TEST
int timeoutSec = 0;
#else
int timeoutSec = server.GetGameData().playerActionTimeoutSec + SERVER_PLAYER_TIMEOUT_ADD_DELAY_SEC;
#endif
server.SetStateTimerId(
server.GetLobbyThread().GetTimerManager().RegisterTimer(
timeoutSec * 1000,
boost::bind(&ServerGameStateWaitPlayerAction::TimerTimeout, this, boost::ref(server))));
}
void
ServerGameStateWaitPlayerAction::Exit(ServerGameThread &server)
{
// The Id might be invalid, but this is not a problem.
server.GetLobbyThread().GetTimerManager().UnregisterTimer(server.GetStateTimerId());
server.SetStateTimerId(0);
}
void
ServerGameStateWaitPlayerAction::HandleNewSession(ServerGameThread &server, SessionWrapper session)
{ {
// Do not accept new sessions in this state. // Do not accept new sessions in this state.
GetServerGame().MoveSessionToLobby(session, NTF_NET_REMOVED_ALREADY_RUNNING); server.MoveSessionToLobby(session, NTF_NET_REMOVED_ALREADY_RUNNING);
} }
int int
ServerGameStateWaitPlayerAction::InternalProcessPacket(SessionWrapper session, boost::shared_ptr<NetPacket> packet) ServerGameStateWaitPlayerAction::InternalProcessPacket(ServerGameThread &server, SessionWrapper session, boost::shared_ptr<NetPacket> packet)
{ {
int retVal = MSG_SOCK_INTERNAL_PENDING; int retVal = MSG_SOCK_INTERNAL_PENDING;
@@ -1012,7 +1079,7 @@ ServerGameStateWaitPlayerAction::InternalProcessPacket(SessionWrapper session, b
NetPacketPlayersAction::Data actionData; NetPacketPlayersAction::Data actionData;
packet->ToNetPacketPlayersAction()->GetData(actionData); packet->ToNetPacketPlayersAction()->GetData(actionData);
Game &curGame = GetServerGame().GetGame(); Game &curGame = server.GetGame();
boost::shared_ptr<PlayerInterface> tmpPlayer = curGame.getPlayerByUniqueId(session.playerData->GetUniqueId()); boost::shared_ptr<PlayerInterface> tmpPlayer = curGame.getPlayerByUniqueId(session.playerData->GetUniqueId());
if (!tmpPlayer.get()) if (!tmpPlayer.get())
throw ServerException(__FILE__, __LINE__, ERR_NET_UNKNOWN_PLAYER_ID, 0); throw ServerException(__FILE__, __LINE__, ERR_NET_UNKNOWN_PLAYER_ID, 0);
@@ -1023,7 +1090,7 @@ ServerGameStateWaitPlayerAction::InternalProcessPacket(SessionWrapper session, b
code = ACTION_CODE_INVALID_STATE; code = ACTION_CODE_INVALID_STATE;
// Check whether this is the correct player. // Check whether this is the correct player.
boost::shared_ptr<PlayerInterface> curPlayer = GetServerGame().GetGame().getCurrentPlayer(); boost::shared_ptr<PlayerInterface> curPlayer = server.GetGame().getCurrentPlayer();
if (code == ACTION_CODE_VALID if (code == ACTION_CODE_VALID
&& (curPlayer->getMyUniqueID() != tmpPlayer->getMyUniqueID())) && (curPlayer->getMyUniqueID() != tmpPlayer->getMyUniqueID()))
{ {
@@ -1055,8 +1122,8 @@ ServerGameStateWaitPlayerAction::InternalProcessPacket(SessionWrapper session, b
if (code == ACTION_CODE_VALID) if (code == ACTION_CODE_VALID)
{ {
PerformPlayerAction(GetServerGame(), tmpPlayer, actionData.playerAction, actionData.playerBet); PerformPlayerAction(server, tmpPlayer, actionData.playerAction, actionData.playerBet);
GetServerGame().SetState(boost::shared_ptr<ServerGameState>(new ServerGameStateHand(GetServerGame()))); server.SetState(ServerGameStateHand::Instance());
retVal = MSG_NET_GAME_SERVER_ACTION; retVal = MSG_NET_GAME_SERVER_ACTION;
} }
else else
@@ -1077,9 +1144,9 @@ ServerGameStateWaitPlayerAction::InternalProcessPacket(SessionWrapper session, b
} }
void void
ServerGameStateWaitPlayerAction::TimerTimeout() ServerGameStateWaitPlayerAction::TimerTimeout(ServerGameThread &server)
{ {
Game &curGame = GetServerGame().GetGame(); Game &curGame = server.GetGame();
// Retrieve current player. // Retrieve current player.
boost::shared_ptr<PlayerInterface> curPlayer = curGame.getCurrentPlayer(); boost::shared_ptr<PlayerInterface> curPlayer = curGame.getCurrentPlayer();
if (!curPlayer.get()) if (!curPlayer.get())
@@ -1087,11 +1154,11 @@ ServerGameStateWaitPlayerAction::TimerTimeout()
// Player did not act fast enough. Act for him. // Player did not act fast enough. Act for him.
if (curGame.getCurrentHand()->getCurrentBeRo()->getHighestSet() == curPlayer->getMySet()) if (curGame.getCurrentHand()->getCurrentBeRo()->getHighestSet() == curPlayer->getMySet())
PerformPlayerAction(GetServerGame(), curPlayer, PLAYER_ACTION_CHECK, 0); PerformPlayerAction(server, curPlayer, PLAYER_ACTION_CHECK, 0);
else else
PerformPlayerAction(GetServerGame(), curPlayer, PLAYER_ACTION_FOLD, 0); PerformPlayerAction(server, curPlayer, PLAYER_ACTION_FOLD, 0);
GetServerGame().SetState(boost::shared_ptr<ServerGameState>(new ServerGameStateHand(GetServerGame()))); server.SetState(ServerGameStateHand::Instance());
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
+20 -7
View File
@@ -42,7 +42,7 @@ using namespace std;
ServerGameThread::ServerGameThread(ServerLobbyThread &lobbyThread, u_int32_t id, const string &name, const string &pwd, const GameData &gameData, unsigned adminPlayerId, GuiInterface &gui, ConfigFile *playerConfig) ServerGameThread::ServerGameThread(ServerLobbyThread &lobbyThread, u_int32_t id, const string &name, const string &pwd, const GameData &gameData, unsigned adminPlayerId, GuiInterface &gui, ConfigFile *playerConfig)
: m_adminPlayerId(adminPlayerId), m_lobbyThread(lobbyThread), m_gui(gui), : m_adminPlayerId(adminPlayerId), m_lobbyThread(lobbyThread), m_gui(gui),
m_gameData(gameData), m_id(id), m_name(name), m_password(pwd), m_playerConfig(playerConfig), m_gameData(gameData), m_id(id), m_name(name), m_password(pwd), m_playerConfig(playerConfig),
m_gameNum(1), m_curPetitionId(1) m_gameNum(1), m_curPetitionId(1), m_stateTimerId(0)
{ {
LOG_VERBOSE("Game object " << GetId() << " created."); LOG_VERBOSE("Game object " << GetId() << " created.");
@@ -57,13 +57,14 @@ ServerGameThread::ServerGameThread(ServerLobbyThread &lobbyThread, u_int32_t id,
boost::bind(&ServerGameThread::TimerVoteKick, this), boost::bind(&ServerGameThread::TimerVoteKick, this),
true); true);
SetState(boost::shared_ptr<ServerGameState>(new SERVER_INITIAL_STATE(*this))); SetState(SERVER_INITIAL_STATE::Instance());
} }
ServerGameThread::~ServerGameThread() ServerGameThread::~ServerGameThread()
{ {
GetLobbyThread().GetTimerManager().UnregisterTimer(m_removePlayerTimerId); GetLobbyThread().GetTimerManager().UnregisterTimer(m_removePlayerTimerId);
GetLobbyThread().GetTimerManager().UnregisterTimer(m_voteKickTimerId); GetLobbyThread().GetTimerManager().UnregisterTimer(m_voteKickTimerId);
GetLobbyThread().GetTimerManager().UnregisterTimer(m_stateTimerId);
LOG_VERBOSE("Game object " << GetId() << " destructed."); LOG_VERBOSE("Game object " << GetId() << " destructed.");
} }
@@ -84,7 +85,7 @@ void
ServerGameThread::AddSession(SessionWrapper session) ServerGameThread::AddSession(SessionWrapper session)
{ {
if (session.sessionData) if (session.sessionData)
GetState().HandleNewSession(session); GetState().HandleNewSession(*this, session);
} }
void void
@@ -98,7 +99,7 @@ void
ServerGameThread::HandlePacket(SessionWrapper session, boost::shared_ptr<NetPacket> packet) ServerGameThread::HandlePacket(SessionWrapper session, boost::shared_ptr<NetPacket> packet)
{ {
if (session.sessionData && packet) if (session.sessionData && packet)
GetState().ProcessPacket(session, packet); GetState().ProcessPacket(*this, session, packet);
} }
GameState GameState
@@ -580,7 +581,7 @@ ServerGameThread::RemovePlayerData(boost::shared_ptr<PlayerData> player, int rea
SetAdminPlayerId(newAdmin->GetUniqueId()); SetAdminPlayerId(newAdmin->GetUniqueId());
newAdmin->SetRights(PLAYER_RIGHTS_ADMIN); newAdmin->SetRights(PLAYER_RIGHTS_ADMIN);
// Notify game state on admin change // Notify game state on admin change
GetState().NotifyGameAdminChanged(); GetState().NotifyGameAdminChanged(*this);
// Send "Game Admin Changed" to clients. // Send "Game Admin Changed" to clients.
boost::shared_ptr<NetPacket> adminChanged(new NetPacketGameAdminChanged); boost::shared_ptr<NetPacket> adminChanged(new NetPacketGameAdminChanged);
NetPacketGameAdminChanged::Data adminChangedData; NetPacketGameAdminChanged::Data adminChangedData;
@@ -718,9 +719,21 @@ ServerGameThread::GetState()
} }
void void
ServerGameThread::SetState(boost::shared_ptr<ServerGameState> newState) ServerGameThread::SetState(ServerGameState &newState)
{ {
m_curState = newState; m_curState = &newState;
}
unsigned
ServerGameThread::GetStateTimerId() const
{
return m_stateTimerId;
}
void
ServerGameThread::SetStateTimerId(unsigned newTimerId)
{
m_stateTimerId = newTimerId;
} }
ReceiverHelper & ReceiverHelper &
+56 -49
View File
@@ -40,130 +40,137 @@ class ServerCallback;
class ServerGameState class ServerGameState
{ {
public: public:
ServerGameState(ServerGameThread &serverGame) : m_serverGame(serverGame) {}
virtual ~ServerGameState(); virtual ~ServerGameState();
virtual void Enter(ServerGameThread &server) = 0;
virtual void Exit(ServerGameThread &server) = 0;
virtual void NotifyGameAdminChanged() = 0; virtual void NotifyGameAdminChanged(ServerGameThread &server) = 0;
// Handling of a new session. // Handling of a new session.
virtual void HandleNewSession(SessionWrapper session) = 0; virtual void HandleNewSession(ServerGameThread &server, SessionWrapper session) = 0;
// Main processing function of the current state. // Main processing function of the current state.
virtual int ProcessPacket(SessionWrapper session, boost::shared_ptr<NetPacket> packet) = 0; virtual int ProcessPacket(ServerGameThread &server, SessionWrapper session, boost::shared_ptr<NetPacket> packet) = 0;
protected:
ServerGameThread &GetServerGame() {return m_serverGame;}
private:
ServerGameThread &m_serverGame;
}; };
// Abstract State: Receiving. // Abstract State: Receiving.
class AbstractServerGameStateReceiving : public ServerGameState class AbstractServerGameStateReceiving : public ServerGameState
{ {
public: public:
AbstractServerGameStateReceiving(ServerGameThread &serverGame);
virtual ~AbstractServerGameStateReceiving(); virtual ~AbstractServerGameStateReceiving();
// Globally handle packets which are allowed in all running states. // Globally handle packets which are allowed in all running states.
// Calls InternalProcess if packet has not been processed. // Calls InternalProcess if packet has not been processed.
virtual int ProcessPacket(SessionWrapper session, boost::shared_ptr<NetPacket> packet); virtual int ProcessPacket(ServerGameThread &server, SessionWrapper session, boost::shared_ptr<NetPacket> packet);
protected: protected:
virtual int InternalProcessPacket(SessionWrapper session, boost::shared_ptr<NetPacket> packet) = 0; virtual int InternalProcessPacket(ServerGameThread &server, SessionWrapper session, boost::shared_ptr<NetPacket> packet) = 0;
}; };
// State: Initialization. // State: Initialization.
class ServerGameStateInit : public AbstractServerGameStateReceiving class ServerGameStateInit : public AbstractServerGameStateReceiving
{ {
public: public:
ServerGameStateInit(ServerGameThread &serverGame); static ServerGameStateInit &Instance();
virtual void Enter(ServerGameThread &server);
virtual void Exit(ServerGameThread &server);
virtual ~ServerGameStateInit(); virtual ~ServerGameStateInit();
virtual void NotifyGameAdminChanged(); virtual void NotifyGameAdminChanged(ServerGameThread &server);
virtual void HandleNewSession(SessionWrapper session); virtual void HandleNewSession(ServerGameThread &server, SessionWrapper session);
protected: protected:
ServerGameStateInit();
void RegisterAdminTimers(); void RegisterAdminTimer(ServerGameThread &server);
void UnregisterAdminTimers(); void UnregisterAdminTimer(ServerGameThread &server);
void TimerAdminWarning(); void TimerAdminWarning(ServerGameThread &server);
void TimerAdminTimeout(); void TimerAdminTimeout(ServerGameThread &server);
virtual int InternalProcessPacket(SessionWrapper session, boost::shared_ptr<NetPacket> packet); virtual int InternalProcessPacket(ServerGameThread &server, SessionWrapper session, boost::shared_ptr<NetPacket> packet);
static boost::shared_ptr<NetPacket> CreateNetPacketPlayerJoined(const PlayerData &playerData); static boost::shared_ptr<NetPacket> CreateNetPacketPlayerJoined(const PlayerData &playerData);
private: private:
static ServerGameStateInit s_state;
unsigned m_adminWarningTimerId;
unsigned m_adminTimeoutTimerId;
bool m_timerRegistered;
}; };
// Wait for Ack of start event and start game. // Wait for Ack of start event and start game.
class ServerGameStateStartGame : public AbstractServerGameStateReceiving class ServerGameStateStartGame : public AbstractServerGameStateReceiving
{ {
public: public:
static ServerGameStateStartGame &Instance();
virtual void Enter(ServerGameThread &server);
virtual void Exit(ServerGameThread &server);
ServerGameStateStartGame(ServerGameThread &serverGame);
virtual ~ServerGameStateStartGame(); virtual ~ServerGameStateStartGame();
virtual void NotifyGameAdminChanged() {} virtual void NotifyGameAdminChanged(ServerGameThread &/*server*/) {}
virtual void HandleNewSession(SessionWrapper session); virtual void HandleNewSession(ServerGameThread &server, SessionWrapper session);
protected: protected:
ServerGameStateStartGame();
virtual int InternalProcessPacket(SessionWrapper session, boost::shared_ptr<NetPacket> packet); virtual int InternalProcessPacket(ServerGameThread &server, SessionWrapper session, boost::shared_ptr<NetPacket> packet);
void TimerTimeout(); void TimerTimeout(ServerGameThread &server);
void DoStart(); void DoStart(ServerGameThread &server);
private: private:
unsigned m_timeoutTimerId; static ServerGameStateStartGame s_state;
}; };
// State: Within hand. // State: Within hand.
class ServerGameStateHand : public AbstractServerGameStateReceiving class ServerGameStateHand : public AbstractServerGameStateReceiving
{ {
public: public:
ServerGameStateHand(ServerGameThread &serverGame); static ServerGameStateHand &Instance();
virtual void Enter(ServerGameThread &server);
virtual void Exit(ServerGameThread &server);
virtual ~ServerGameStateHand(); virtual ~ServerGameStateHand();
virtual void NotifyGameAdminChanged() {} virtual void NotifyGameAdminChanged(ServerGameThread &/*server*/) {}
virtual void HandleNewSession(SessionWrapper session); virtual void HandleNewSession(ServerGameThread &server, SessionWrapper session);
protected: protected:
virtual int InternalProcessPacket(SessionWrapper session, boost::shared_ptr<NetPacket> packet); ServerGameStateHand();
void TimerLoop();
void TimerShowCards(); virtual int InternalProcessPacket(ServerGameThread &server, SessionWrapper session, boost::shared_ptr<NetPacket> packet);
void TimerComputerAction(); void TimerLoop(ServerGameThread &server);
void TimerNextHand(); void TimerShowCards(ServerGameThread &server);
void TimerNextGame(); void TimerComputerAction(ServerGameThread &server);
int GetDealCardsDelaySec(); void TimerNextHand(ServerGameThread &server);
void TimerNextGame(ServerGameThread &server);
int GetDealCardsDelaySec(ServerGameThread &server);
private: private:
unsigned m_loopTimerId; static ServerGameStateHand s_state;
}; };
// State: Wait for a player action. // State: Wait for a player action.
class ServerGameStateWaitPlayerAction : public AbstractServerGameStateReceiving class ServerGameStateWaitPlayerAction : public AbstractServerGameStateReceiving
{ {
public: public:
ServerGameStateWaitPlayerAction(ServerGameThread &serverGame); static ServerGameStateWaitPlayerAction &Instance();
virtual void Enter(ServerGameThread &server);
virtual void Exit(ServerGameThread &server);
virtual ~ServerGameStateWaitPlayerAction(); virtual ~ServerGameStateWaitPlayerAction();
virtual void NotifyGameAdminChanged() {} virtual void NotifyGameAdminChanged(ServerGameThread &/*server*/) {}
virtual void HandleNewSession(SessionWrapper session); virtual void HandleNewSession(ServerGameThread &server, SessionWrapper session);
protected: protected:
ServerGameStateWaitPlayerAction();
virtual int InternalProcessPacket(SessionWrapper session, boost::shared_ptr<NetPacket> packet); virtual int InternalProcessPacket(ServerGameThread &server, SessionWrapper session, boost::shared_ptr<NetPacket> packet);
void TimerTimeout(); void TimerTimeout(ServerGameThread &server);
private: private:
unsigned m_timeoutTimerId; static ServerGameStateWaitPlayerAction s_state;
}; };
#ifdef _MSC_VER #ifdef _MSC_VER
+8 -5
View File
@@ -114,7 +114,10 @@ protected:
ServerLobbyThread &GetLobbyThread(); ServerLobbyThread &GetLobbyThread();
ServerGameState &GetState(); ServerGameState &GetState();
void SetState(boost::shared_ptr<ServerGameState> newState); void SetState(ServerGameState &newState);
unsigned GetStateTimerId() const;
void SetStateTimerId(unsigned newTimerId);
ReceiverHelper &GetReceiver(); ReceiverHelper &GetReceiver();
@@ -129,6 +132,7 @@ protected:
SessionManager &GetSessionManager(); SessionManager &GetSessionManager();
private: private:
ServerGameThread(const ServerGameThread &other);
SessionQueue m_sessionQueue; SessionQueue m_sessionQueue;
mutable boost::mutex m_sessionQueueMutex; mutable boost::mutex m_sessionQueueMutex;
@@ -152,8 +156,8 @@ private:
const GameData m_gameData; const GameData m_gameData;
StartData m_startData; StartData m_startData;
boost::shared_ptr<Game> m_game; boost::shared_ptr<Game> m_game;
boost::shared_ptr<ServerGameState> m_curState; ServerGameState *m_curState;
const u_int32_t m_id; const u_int32_t m_id;
const std::string m_name; const std::string m_name;
@@ -163,8 +167,7 @@ private:
unsigned m_curPetitionId; unsigned m_curPetitionId;
unsigned m_removePlayerTimerId; unsigned m_removePlayerTimerId;
unsigned m_voteKickTimerId; unsigned m_voteKickTimerId;
unsigned m_stateTimerId;
boost::timers::portable::microsec_timer m_voteKickActionTimer;
friend class ServerLobbyThread; friend class ServerLobbyThread;
friend class AbstractServerGameStateReceiving; friend class AbstractServerGameStateReceiving;