Rewriting boost asio timer stuff. (Did I mention I dislike the asio "cancel" semantics?!). TimerManager is no longer used. Should be stable now, but might leak some memory (needs further testing).
This commit is contained in:
@@ -38,10 +38,10 @@
|
||||
using namespace std;
|
||||
|
||||
|
||||
ServerGame::ServerGame(ServerLobbyThread &lobbyThread, u_int32_t id, const string &name, const string &pwd, const GameData &gameData, unsigned adminPlayerId, GuiInterface &gui, ConfigFile *playerConfig)
|
||||
ServerGame::ServerGame(boost::shared_ptr<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_gameData(gameData), m_curState(NULL), m_id(id), m_name(name), m_password(pwd), m_playerConfig(playerConfig),
|
||||
m_gameNum(1), m_curPetitionId(1), m_stateTimerId(0)
|
||||
m_gameNum(1), m_curPetitionId(1), m_voteKickTimer(lobbyThread->GetIOService()), m_stateTimer(lobbyThread->GetIOService())
|
||||
{
|
||||
LOG_VERBOSE("Game object " << GetId() << " created.");
|
||||
|
||||
@@ -56,10 +56,11 @@ ServerGame::~ServerGame()
|
||||
void
|
||||
ServerGame::Init()
|
||||
{
|
||||
m_voteKickTimerId = GetLobbyThread().GetTimerManager().RegisterTimer(
|
||||
SERVER_CHECK_VOTE_KICK_INTERVAL_MSEC,
|
||||
boost::bind(&ServerGame::TimerVoteKick, this),
|
||||
true);
|
||||
m_voteKickTimer.expires_from_now(
|
||||
boost::posix_time::milliseconds(SERVER_CHECK_VOTE_KICK_INTERVAL_MSEC));
|
||||
m_voteKickTimer.async_wait(
|
||||
boost::bind(
|
||||
&ServerGame::TimerVoteKick, shared_from_this(), boost::asio::placeholders::error));
|
||||
|
||||
SetState(SERVER_INITIAL_STATE::Instance());
|
||||
}
|
||||
@@ -67,8 +68,9 @@ ServerGame::Init()
|
||||
void
|
||||
ServerGame::Exit()
|
||||
{
|
||||
GetLobbyThread().GetTimerManager().UnregisterTimer(m_voteKickTimerId);
|
||||
GetLobbyThread().GetTimerManager().UnregisterTimer(m_stateTimerId);
|
||||
m_voteKickTimer.cancel();
|
||||
if (m_curState)
|
||||
m_curState->Exit(shared_from_this());
|
||||
}
|
||||
|
||||
u_int32_t
|
||||
@@ -87,7 +89,7 @@ void
|
||||
ServerGame::AddSession(SessionWrapper session)
|
||||
{
|
||||
if (session.sessionData)
|
||||
GetState().HandleNewSession(*this, session);
|
||||
GetState().HandleNewSession(shared_from_this(), session);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -103,7 +105,7 @@ void
|
||||
ServerGame::HandlePacket(SessionWrapper session, boost::shared_ptr<NetPacket> packet)
|
||||
{
|
||||
if (session.sessionData && packet)
|
||||
GetState().ProcessPacket(*this, session, packet);
|
||||
GetState().ProcessPacket(shared_from_this(), session, packet);
|
||||
}
|
||||
|
||||
GameState
|
||||
@@ -123,77 +125,85 @@ ServerGame::RemoveAllSessions()
|
||||
{
|
||||
// Called from lobby thread.
|
||||
// Clean up ALL sessions which are left.
|
||||
GetSessionManager().ForEach(boost::bind(&ServerLobbyThread::RemoveSessionFromGame, boost::ref(m_lobbyThread), _1));
|
||||
GetSessionManager().ForEach(boost::bind(&ServerLobbyThread::RemoveSessionFromGame, boost::ref(*m_lobbyThread), _1));
|
||||
}
|
||||
|
||||
void
|
||||
ServerGame::TimerVoteKick()
|
||||
ServerGame::TimerVoteKick(const boost::system::error_code &ec)
|
||||
{
|
||||
// Check whether someone should be kicked, or whether a vote kick should be aborted.
|
||||
// Only one vote kick can be active at a time.
|
||||
if (m_voteKickData)
|
||||
if (!ec)
|
||||
{
|
||||
// Prepare some values.
|
||||
const PlayerIdList playerIds(GetPlayerIdList());
|
||||
int votesRequiredToKick = m_voteKickData->numVotesToKick - m_voteKickData->numVotesInFavourOfKicking;
|
||||
int playersAllowedToVote = 0;
|
||||
// We need to count the number of players which are still allowed to vote.
|
||||
PlayerIdList::const_iterator player_i = playerIds.begin();
|
||||
PlayerIdList::const_iterator player_end = playerIds.end();
|
||||
while (player_i != player_end)
|
||||
// Check whether someone should be kicked, or whether a vote kick should be aborted.
|
||||
// Only one vote kick can be active at a time.
|
||||
if (m_voteKickData)
|
||||
{
|
||||
if (find(m_voteKickData->votedPlayerIds.begin(), m_voteKickData->votedPlayerIds.end(), *player_i) == m_voteKickData->votedPlayerIds.end())
|
||||
playersAllowedToVote++;
|
||||
++player_i;
|
||||
}
|
||||
bool abortPetition = false;
|
||||
bool doKick = false;
|
||||
EndPetitionReason reason;
|
||||
// Prepare some values.
|
||||
const PlayerIdList playerIds(GetPlayerIdList());
|
||||
int votesRequiredToKick = m_voteKickData->numVotesToKick - m_voteKickData->numVotesInFavourOfKicking;
|
||||
int playersAllowedToVote = 0;
|
||||
// We need to count the number of players which are still allowed to vote.
|
||||
PlayerIdList::const_iterator player_i = playerIds.begin();
|
||||
PlayerIdList::const_iterator player_end = playerIds.end();
|
||||
while (player_i != player_end)
|
||||
{
|
||||
if (find(m_voteKickData->votedPlayerIds.begin(), m_voteKickData->votedPlayerIds.end(), *player_i) == m_voteKickData->votedPlayerIds.end())
|
||||
playersAllowedToVote++;
|
||||
++player_i;
|
||||
}
|
||||
bool abortPetition = false;
|
||||
bool doKick = false;
|
||||
EndPetitionReason reason;
|
||||
|
||||
// 1. Enough votes to kick the player.
|
||||
if (m_voteKickData->numVotesInFavourOfKicking >= m_voteKickData->numVotesToKick)
|
||||
{
|
||||
reason = PETITION_END_ENOUGH_VOTES;
|
||||
abortPetition = true;
|
||||
doKick = true;
|
||||
}
|
||||
// 2. Several players left the game, so a kick is no longer possible.
|
||||
else if (votesRequiredToKick > playersAllowedToVote)
|
||||
{
|
||||
reason = PETITION_END_NOT_ENOUGH_PLAYERS;
|
||||
abortPetition = true;
|
||||
}
|
||||
// 3. The kick has become invalid because the player to be kicked left.
|
||||
else if (!IsValidPlayer(m_voteKickData->kickPlayerId))
|
||||
{
|
||||
reason = PETITION_END_PLAYER_LEFT;
|
||||
abortPetition = true;
|
||||
}
|
||||
// 4. A kick request timed out (because not everyone voted).
|
||||
else if (m_voteKickData->voteTimer.elapsed().total_seconds() >= m_voteKickData->timeLimitSec)
|
||||
{
|
||||
reason = PETITION_END_TIMEOUT;
|
||||
abortPetition = true;
|
||||
}
|
||||
if (abortPetition)
|
||||
{
|
||||
boost::shared_ptr<NetPacket> endPetition(new NetPacketEndKickPlayerPetition);
|
||||
NetPacketEndKickPlayerPetition::Data endPetitionData;
|
||||
endPetitionData.petitionId = m_voteKickData->petitionId;
|
||||
endPetitionData.numVotesAgainstKicking = m_voteKickData->numVotesAgainstKicking;
|
||||
endPetitionData.numVotesInFavourOfKicking = m_voteKickData->numVotesInFavourOfKicking;
|
||||
endPetitionData.playerKicked = doKick;
|
||||
endPetitionData.endReason = reason;
|
||||
// 1. Enough votes to kick the player.
|
||||
if (m_voteKickData->numVotesInFavourOfKicking >= m_voteKickData->numVotesToKick)
|
||||
{
|
||||
reason = PETITION_END_ENOUGH_VOTES;
|
||||
abortPetition = true;
|
||||
doKick = true;
|
||||
}
|
||||
// 2. Several players left the game, so a kick is no longer possible.
|
||||
else if (votesRequiredToKick > playersAllowedToVote)
|
||||
{
|
||||
reason = PETITION_END_NOT_ENOUGH_PLAYERS;
|
||||
abortPetition = true;
|
||||
}
|
||||
// 3. The kick has become invalid because the player to be kicked left.
|
||||
else if (!IsValidPlayer(m_voteKickData->kickPlayerId))
|
||||
{
|
||||
reason = PETITION_END_PLAYER_LEFT;
|
||||
abortPetition = true;
|
||||
}
|
||||
// 4. A kick request timed out (because not everyone voted).
|
||||
else if (m_voteKickData->voteTimer.elapsed().total_seconds() >= m_voteKickData->timeLimitSec)
|
||||
{
|
||||
reason = PETITION_END_TIMEOUT;
|
||||
abortPetition = true;
|
||||
}
|
||||
if (abortPetition)
|
||||
{
|
||||
boost::shared_ptr<NetPacket> endPetition(new NetPacketEndKickPlayerPetition);
|
||||
NetPacketEndKickPlayerPetition::Data endPetitionData;
|
||||
endPetitionData.petitionId = m_voteKickData->petitionId;
|
||||
endPetitionData.numVotesAgainstKicking = m_voteKickData->numVotesAgainstKicking;
|
||||
endPetitionData.numVotesInFavourOfKicking = m_voteKickData->numVotesInFavourOfKicking;
|
||||
endPetitionData.playerKicked = doKick;
|
||||
endPetitionData.endReason = reason;
|
||||
|
||||
static_cast<NetPacketEndKickPlayerPetition *>(endPetition.get())->SetData(endPetitionData);
|
||||
SendToAllPlayers(endPetition, SessionData::Game);
|
||||
static_cast<NetPacketEndKickPlayerPetition *>(endPetition.get())->SetData(endPetitionData);
|
||||
SendToAllPlayers(endPetition, SessionData::Game);
|
||||
|
||||
// Perform kick.
|
||||
if (doKick)
|
||||
InternalKickPlayer(m_voteKickData->kickPlayerId);
|
||||
// This petition has ended.
|
||||
m_voteKickData.reset();
|
||||
// Perform kick.
|
||||
if (doKick)
|
||||
InternalKickPlayer(m_voteKickData->kickPlayerId);
|
||||
// This petition has ended.
|
||||
m_voteKickData.reset();
|
||||
}
|
||||
}
|
||||
m_voteKickTimer.expires_from_now(
|
||||
boost::posix_time::milliseconds(SERVER_CHECK_VOTE_KICK_INTERVAL_MSEC));
|
||||
m_voteKickTimer.async_wait(
|
||||
boost::bind(
|
||||
&ServerGame::TimerVoteKick, shared_from_this(), boost::asio::placeholders::error));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -545,7 +555,7 @@ ServerGame::RemovePlayerData(boost::shared_ptr<PlayerData> player, int reason)
|
||||
SetAdminPlayerId(newAdmin->GetUniqueId());
|
||||
newAdmin->SetRights(PLAYER_RIGHTS_ADMIN);
|
||||
// Notify game state on admin change
|
||||
GetState().NotifyGameAdminChanged(*this);
|
||||
GetState().NotifyGameAdminChanged(shared_from_this());
|
||||
// Send "Game Admin Changed" to clients.
|
||||
boost::shared_ptr<NetPacket> adminChanged(new NetPacketGameAdminChanged);
|
||||
NetPacketGameAdminChanged::Data adminChangedData;
|
||||
@@ -666,7 +676,8 @@ ServerGame::GetSessionManager() const
|
||||
ServerLobbyThread &
|
||||
ServerGame::GetLobbyThread()
|
||||
{
|
||||
return m_lobbyThread;
|
||||
assert(m_lobbyThread);
|
||||
return *m_lobbyThread;
|
||||
}
|
||||
|
||||
ServerCallback &
|
||||
@@ -686,21 +697,15 @@ void
|
||||
ServerGame::SetState(ServerGameState &newState)
|
||||
{
|
||||
if (m_curState)
|
||||
m_curState->Exit(*this);
|
||||
m_curState->Exit(shared_from_this());
|
||||
m_curState = &newState;
|
||||
m_curState->Enter(*this);
|
||||
m_curState->Enter(shared_from_this());
|
||||
}
|
||||
|
||||
unsigned
|
||||
ServerGame::GetStateTimerId() const
|
||||
boost::asio::deadline_timer &
|
||||
ServerGame::GetStateTimer()
|
||||
{
|
||||
return m_stateTimerId;
|
||||
}
|
||||
|
||||
void
|
||||
ServerGame::SetStateTimerId(unsigned newTimerId)
|
||||
{
|
||||
m_stateTimerId = newTimerId;
|
||||
return m_stateTimer;
|
||||
}
|
||||
|
||||
ReceiverHelper &
|
||||
|
||||
+394
-360
File diff suppressed because it is too large
Load Diff
@@ -89,9 +89,12 @@ private:
|
||||
|
||||
ServerLobbyThread::ServerLobbyThread(GuiInterface &gui, ConfigFile *playerConfig, AvatarManager &avatarManager,
|
||||
boost::shared_ptr<boost::asio::io_service> ioService)
|
||||
: m_ioService(ioService), m_timerManager(ioService), m_curBanId(0), m_gui(gui), m_avatarManager(avatarManager),
|
||||
: m_ioService(ioService), m_curBanId(0), m_gui(gui), m_avatarManager(avatarManager),
|
||||
m_playerConfig(playerConfig), m_curGameId(0), m_curUniquePlayerId(0), m_curSessionId(INVALID_SESSION + 1),
|
||||
m_statDataChanged(false), m_startTime(boost::posix_time::second_clock::local_time())
|
||||
m_statDataChanged(false), m_removeGameTimer(*ioService), m_removePlayerTimer(*ioService),
|
||||
m_sessionTimeoutTimer(*ioService), m_avatarCleanupTimer(*ioService),
|
||||
m_saveStatisticsTimer(*ioService), m_avatarLockTimer(*ioService),
|
||||
m_startTime(boost::posix_time::second_clock::local_time())
|
||||
{
|
||||
m_senderCallback.reset(new ServerSenderCallback(*this));
|
||||
m_sender.reset(new SenderHelper(*m_senderCallback, m_ioService));
|
||||
@@ -449,12 +452,6 @@ ServerLobbyThread::RemoveComputerPlayer(boost::shared_ptr<PlayerData> player)
|
||||
m_computerPlayers.erase(player->GetUniqueId());
|
||||
}
|
||||
|
||||
TimerManager &
|
||||
ServerLobbyThread::GetTimerManager()
|
||||
{
|
||||
return m_timerManager;
|
||||
}
|
||||
|
||||
AvatarManager &
|
||||
ServerLobbyThread::GetAvatarManager()
|
||||
{
|
||||
@@ -481,6 +478,13 @@ ServerLobbyThread::GetSender()
|
||||
return *m_sender;
|
||||
}
|
||||
|
||||
boost::asio::io_service &
|
||||
ServerLobbyThread::GetIOService()
|
||||
{
|
||||
assert(m_ioService);
|
||||
return *m_ioService;
|
||||
}
|
||||
|
||||
u_int32_t
|
||||
ServerLobbyThread::GetNextUniquePlayerId()
|
||||
{
|
||||
@@ -505,11 +509,10 @@ ServerLobbyThread::GetNextGameId()
|
||||
void
|
||||
ServerLobbyThread::Main()
|
||||
{
|
||||
// Register all timers.
|
||||
RegisterTimers();
|
||||
try
|
||||
{
|
||||
// Register all timers.
|
||||
RegisterTimers();
|
||||
|
||||
m_work.reset(new boost::asio::io_service::work(*m_ioService));
|
||||
m_ioService->run(); // Will only be aborted asynchronously.
|
||||
m_work.reset();
|
||||
@@ -525,41 +528,60 @@ ServerLobbyThread::Main()
|
||||
GetCallback().SignalNetServerError(e.GetErrorId(), e.GetOsErrorCode());
|
||||
LOG_ERROR(e.what());
|
||||
}
|
||||
// Cancel pending timer callbacks.
|
||||
CancelTimers();
|
||||
}
|
||||
|
||||
void
|
||||
ServerLobbyThread::RegisterTimers()
|
||||
{
|
||||
// Remove closed games.
|
||||
m_timerManager.RegisterTimer(
|
||||
SERVER_REMOVE_GAME_INTERVAL_MSEC,
|
||||
boost::bind(&ServerLobbyThread::TimerRemoveGame, this),
|
||||
true);
|
||||
m_removeGameTimer.expires_from_now(
|
||||
boost::posix_time::milliseconds(SERVER_REMOVE_GAME_INTERVAL_MSEC));
|
||||
m_removeGameTimer.async_wait(
|
||||
boost::bind(
|
||||
&ServerLobbyThread::TimerRemoveGame, shared_from_this(), boost::asio::placeholders::error));
|
||||
// Remove inactive/kicked players.
|
||||
m_timerManager.RegisterTimer(
|
||||
SERVER_REMOVE_PLAYER_INTERVAL_MSEC,
|
||||
boost::bind(&ServerLobbyThread::TimerRemovePlayer, this),
|
||||
true);
|
||||
m_removePlayerTimer.expires_from_now(
|
||||
boost::posix_time::milliseconds(SERVER_REMOVE_PLAYER_INTERVAL_MSEC));
|
||||
m_removePlayerTimer.async_wait(
|
||||
boost::bind(
|
||||
&ServerLobbyThread::TimerRemovePlayer, shared_from_this(), boost::asio::placeholders::error));
|
||||
// Check the timeout of sessions which have not been initialised.
|
||||
m_timerManager.RegisterTimer(
|
||||
SERVER_CHECK_SESSION_TIMEOUTS_INTERVAL_MSEC,
|
||||
boost::bind(&ServerLobbyThread::TimerCheckSessionTimeouts, this),
|
||||
true);
|
||||
m_sessionTimeoutTimer.expires_from_now(
|
||||
boost::posix_time::milliseconds(SERVER_CHECK_SESSION_TIMEOUTS_INTERVAL_MSEC));
|
||||
m_sessionTimeoutTimer.async_wait(
|
||||
boost::bind(
|
||||
&ServerLobbyThread::TimerCheckSessionTimeouts, shared_from_this(), boost::asio::placeholders::error));
|
||||
// Cleanup the avatar cache. Note: Only works if there are no users on the server.
|
||||
m_timerManager.RegisterTimer(
|
||||
SERVER_CACHE_CLEANUP_INTERVAL_SEC * 1000,
|
||||
boost::bind(&ServerLobbyThread::TimerCleanupAvatarCache, this),
|
||||
true);
|
||||
m_avatarCleanupTimer.expires_from_now(
|
||||
boost::posix_time::seconds(SERVER_CACHE_CLEANUP_INTERVAL_SEC));
|
||||
m_avatarCleanupTimer.async_wait(
|
||||
boost::bind(
|
||||
&ServerLobbyThread::TimerCleanupAvatarCache, shared_from_this(), boost::asio::placeholders::error));
|
||||
// Update the statistics file.
|
||||
m_timerManager.RegisterTimer(
|
||||
SERVER_SAVE_STATISTICS_INTERVAL_SEC * 1000,
|
||||
boost::bind(&ServerLobbyThread::TimerSaveStatisticsFile, this),
|
||||
true);
|
||||
m_saveStatisticsTimer.expires_from_now(
|
||||
boost::posix_time::seconds(SERVER_SAVE_STATISTICS_INTERVAL_SEC));
|
||||
m_saveStatisticsTimer.async_wait(
|
||||
boost::bind(
|
||||
&ServerLobbyThread::TimerSaveStatisticsFile, shared_from_this(), boost::asio::placeholders::error));
|
||||
// Update the avatar upload locks.
|
||||
m_timerManager.RegisterTimer(
|
||||
SERVER_UPDATE_AVATAR_LOCK_INTERVAL_MSEC,
|
||||
boost::bind(&ServerLobbyThread::TimerUpdateClientAvatarLock, this),
|
||||
true);
|
||||
m_avatarLockTimer.expires_from_now(
|
||||
boost::posix_time::milliseconds(SERVER_UPDATE_AVATAR_LOCK_INTERVAL_MSEC));
|
||||
m_avatarLockTimer.async_wait(
|
||||
boost::bind(
|
||||
&ServerLobbyThread::TimerUpdateClientAvatarLock, shared_from_this(), boost::asio::placeholders::error));
|
||||
}
|
||||
|
||||
void
|
||||
ServerLobbyThread::CancelTimers()
|
||||
{
|
||||
m_removeGameTimer.cancel();
|
||||
m_removePlayerTimer.cancel();
|
||||
m_sessionTimeoutTimer.cancel();
|
||||
m_avatarCleanupTimer.cancel();
|
||||
m_saveStatisticsTimer.cancel();
|
||||
m_avatarLockTimer.cancel();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -941,7 +963,7 @@ ServerLobbyThread::HandleNetPacketCreateGame(SessionWrapper session, const NetPa
|
||||
|
||||
boost::shared_ptr<ServerGame> game(
|
||||
new ServerGame(
|
||||
*this,
|
||||
shared_from_this(),
|
||||
GetNextGameId(),
|
||||
createGameData.gameName,
|
||||
createGameData.password,
|
||||
@@ -1032,75 +1054,90 @@ ServerLobbyThread::RequestPlayerAvatar(SessionWrapper session)
|
||||
}
|
||||
|
||||
void
|
||||
ServerLobbyThread::TimerRemoveGame()
|
||||
ServerLobbyThread::TimerRemoveGame(const boost::system::error_code &ec)
|
||||
{
|
||||
// Synchronously remove games which have been closed.
|
||||
GameMap::iterator i = m_gameMap.begin();
|
||||
GameMap::iterator end = m_gameMap.end();
|
||||
while (i != end)
|
||||
if (!ec)
|
||||
{
|
||||
GameMap::iterator next = i;
|
||||
++next;
|
||||
boost::shared_ptr<ServerGame> tmpGame = i->second;
|
||||
if (!tmpGame->GetSessionManager().HasSessions())
|
||||
InternalRemoveGame(tmpGame); // This will delete the game.
|
||||
i = next;
|
||||
// Synchronously remove games which have been closed.
|
||||
GameMap::iterator i = m_gameMap.begin();
|
||||
GameMap::iterator end = m_gameMap.end();
|
||||
while (i != end)
|
||||
{
|
||||
GameMap::iterator next = i;
|
||||
++next;
|
||||
boost::shared_ptr<ServerGame> tmpGame = i->second;
|
||||
if (!tmpGame->GetSessionManager().HasSessions())
|
||||
InternalRemoveGame(tmpGame); // This will delete the game.
|
||||
i = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ServerLobbyThread::TimerRemovePlayer()
|
||||
ServerLobbyThread::TimerRemovePlayer(const boost::system::error_code &ec)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(m_removePlayerListMutex);
|
||||
|
||||
if (!m_removePlayerList.empty())
|
||||
if (!ec)
|
||||
{
|
||||
RemovePlayerList::iterator i = m_removePlayerList.begin();
|
||||
RemovePlayerList::iterator end = m_removePlayerList.end();
|
||||
boost::mutex::scoped_lock lock(m_removePlayerListMutex);
|
||||
|
||||
if (!m_removePlayerList.empty())
|
||||
{
|
||||
RemovePlayerList::iterator i = m_removePlayerList.begin();
|
||||
RemovePlayerList::iterator end = m_removePlayerList.end();
|
||||
|
||||
while (i != end)
|
||||
{
|
||||
InternalRemovePlayer(i->first, i->second);
|
||||
++i;
|
||||
}
|
||||
m_removePlayerList.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ServerLobbyThread::TimerUpdateClientAvatarLock(const boost::system::error_code &ec)
|
||||
{
|
||||
if (!ec)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(m_timerAvatarClientAddressMapMutex);
|
||||
|
||||
TimerClientAddressMap::iterator i = m_timerAvatarClientAddressMap.begin();
|
||||
TimerClientAddressMap::iterator end = m_timerAvatarClientAddressMap.end();
|
||||
|
||||
while (i != end)
|
||||
{
|
||||
InternalRemovePlayer(i->first, i->second);
|
||||
++i;
|
||||
TimerClientAddressMap::iterator next = i;
|
||||
++next;
|
||||
if (i->second.elapsed().total_seconds() > SERVER_INIT_AVATAR_CLIENT_LOCK_SEC)
|
||||
m_timerAvatarClientAddressMap.erase(i);
|
||||
i = next;
|
||||
}
|
||||
m_removePlayerList.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ServerLobbyThread::TimerUpdateClientAvatarLock()
|
||||
ServerLobbyThread::TimerCheckSessionTimeouts(const boost::system::error_code &ec)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(m_timerAvatarClientAddressMapMutex);
|
||||
|
||||
TimerClientAddressMap::iterator i = m_timerAvatarClientAddressMap.begin();
|
||||
TimerClientAddressMap::iterator end = m_timerAvatarClientAddressMap.end();
|
||||
|
||||
while (i != end)
|
||||
if (!ec)
|
||||
{
|
||||
TimerClientAddressMap::iterator next = i;
|
||||
++next;
|
||||
if (i->second.elapsed().total_seconds() > SERVER_INIT_AVATAR_CLIENT_LOCK_SEC)
|
||||
m_timerAvatarClientAddressMap.erase(i);
|
||||
i = next;
|
||||
m_sessionManager.ForEach(boost::bind(&ServerLobbyThread::InternalCheckSessionTimeouts, boost::ref(*this), _1));
|
||||
m_gameSessionManager.ForEach(boost::bind(&ServerLobbyThread::InternalCheckSessionTimeouts, boost::ref(*this), _1));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ServerLobbyThread::TimerCheckSessionTimeouts()
|
||||
ServerLobbyThread::TimerCleanupAvatarCache(const boost::system::error_code &ec)
|
||||
{
|
||||
m_sessionManager.ForEach(boost::bind(&ServerLobbyThread::InternalCheckSessionTimeouts, boost::ref(*this), _1));
|
||||
m_gameSessionManager.ForEach(boost::bind(&ServerLobbyThread::InternalCheckSessionTimeouts, boost::ref(*this), _1));
|
||||
}
|
||||
|
||||
void
|
||||
ServerLobbyThread::TimerCleanupAvatarCache()
|
||||
{
|
||||
// Only act if there are no sessions.
|
||||
if (!m_sessionManager.HasSessions() && !m_gameSessionManager.HasSessions())
|
||||
if (!ec)
|
||||
{
|
||||
LOG_VERBOSE("Cleaning up avatar cache.");
|
||||
// Only act if there are no sessions.
|
||||
if (!m_sessionManager.HasSessions() && !m_gameSessionManager.HasSessions())
|
||||
{
|
||||
LOG_VERBOSE("Cleaning up avatar cache.");
|
||||
|
||||
m_avatarManager.RemoveOldAvatarCacheEntries();
|
||||
m_avatarManager.RemoveOldAvatarCacheEntries();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1380,22 +1417,25 @@ ServerLobbyThread::ReadStatisticsFile()
|
||||
}
|
||||
|
||||
void
|
||||
ServerLobbyThread::TimerSaveStatisticsFile()
|
||||
ServerLobbyThread::TimerSaveStatisticsFile(const boost::system::error_code &ec)
|
||||
{
|
||||
LOG_VERBOSE("Saving statistics.");
|
||||
boost::mutex::scoped_lock lock(m_statMutex);
|
||||
if (m_statDataChanged)
|
||||
if (!ec)
|
||||
{
|
||||
ofstream o(m_statisticsFileName.c_str(), ios_base::out | ios_base::trunc);
|
||||
if (!o.fail())
|
||||
LOG_VERBOSE("Saving statistics.");
|
||||
boost::mutex::scoped_lock lock(m_statMutex);
|
||||
if (m_statDataChanged)
|
||||
{
|
||||
o << SERVER_STATISTICS_STR_TOTAL_PLAYERS " " << m_statData.totalPlayersEverLoggedIn << endl;
|
||||
o << SERVER_STATISTICS_STR_TOTAL_GAMES " " << m_statData.totalGamesEverCreated << endl;
|
||||
o << SERVER_STATISTICS_STR_MAX_PLAYERS " " << m_statData.maxPlayersLoggedIn << endl;
|
||||
o << SERVER_STATISTICS_STR_MAX_GAMES " " << m_statData.maxGamesOpen << endl;
|
||||
o << SERVER_STATISTICS_STR_CUR_PLAYERS " " << m_statData.numberOfPlayersOnServer << endl;
|
||||
o << SERVER_STATISTICS_STR_CUR_GAMES " " << m_statData.numberOfGamesOpen << endl;
|
||||
m_statDataChanged = false;
|
||||
ofstream o(m_statisticsFileName.c_str(), ios_base::out | ios_base::trunc);
|
||||
if (!o.fail())
|
||||
{
|
||||
o << SERVER_STATISTICS_STR_TOTAL_PLAYERS " " << m_statData.totalPlayersEverLoggedIn << endl;
|
||||
o << SERVER_STATISTICS_STR_TOTAL_GAMES " " << m_statData.totalGamesEverCreated << endl;
|
||||
o << SERVER_STATISTICS_STR_MAX_PLAYERS " " << m_statData.maxPlayersLoggedIn << endl;
|
||||
o << SERVER_STATISTICS_STR_MAX_GAMES " " << m_statData.maxGamesOpen << endl;
|
||||
o << SERVER_STATISTICS_STR_CUR_PLAYERS " " << m_statData.numberOfPlayersOnServer << endl;
|
||||
o << SERVER_STATISTICS_STR_CUR_GAMES " " << m_statData.numberOfGamesOpen << endl;
|
||||
m_statDataChanged = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#ifndef _SERVERGAME_H_
|
||||
#define _SERVERGAME_H_
|
||||
|
||||
#include <boost/enable_shared_from_this.hpp>
|
||||
#include <third_party/boost/timers.hpp>
|
||||
#include <deque>
|
||||
|
||||
@@ -36,11 +37,11 @@ class ConfigFile;
|
||||
struct GameData;
|
||||
class Game;
|
||||
|
||||
class ServerGame
|
||||
class ServerGame : public boost::enable_shared_from_this<ServerGame>
|
||||
{
|
||||
public:
|
||||
ServerGame(
|
||||
ServerLobbyThread &lobbyThread, u_int32_t id, const std::string &name, const std::string &pwd, const GameData &gameData, unsigned adminPlayerId, GuiInterface &gui, ConfigFile *playerConfig);
|
||||
boost::shared_ptr<ServerLobbyThread> lobbyThread, u_int32_t id, const std::string &name, const std::string &pwd, const GameData &gameData, unsigned adminPlayerId, GuiInterface &gui, ConfigFile *playerConfig);
|
||||
virtual ~ServerGame();
|
||||
|
||||
void Init();
|
||||
@@ -81,7 +82,7 @@ protected:
|
||||
|
||||
typedef std::deque<SessionWrapper> SessionQueue;
|
||||
|
||||
void TimerVoteKick();
|
||||
void TimerVoteKick(const boost::system::error_code &ec);
|
||||
|
||||
void InternalStartGame();
|
||||
void ResetGame();
|
||||
@@ -115,8 +116,7 @@ protected:
|
||||
ServerGameState &GetState();
|
||||
void SetState(ServerGameState &newState);
|
||||
|
||||
unsigned GetStateTimerId() const;
|
||||
void SetStateTimerId(unsigned newTimerId);
|
||||
boost::asio::deadline_timer &GetStateTimer();
|
||||
|
||||
ReceiverHelper &GetReceiver();
|
||||
|
||||
@@ -141,7 +141,7 @@ private:
|
||||
|
||||
boost::shared_ptr<VoteKickData> m_voteKickData;
|
||||
|
||||
ServerLobbyThread &m_lobbyThread;
|
||||
boost::shared_ptr<ServerLobbyThread> m_lobbyThread;
|
||||
boost::shared_ptr<ReceiverHelper> m_receiver;
|
||||
GuiInterface &m_gui;
|
||||
|
||||
@@ -156,8 +156,8 @@ private:
|
||||
ConfigFile *m_playerConfig;
|
||||
unsigned m_gameNum;
|
||||
unsigned m_curPetitionId;
|
||||
unsigned m_voteKickTimerId;
|
||||
unsigned m_stateTimerId;
|
||||
boost::asio::deadline_timer m_voteKickTimer;
|
||||
boost::asio::deadline_timer m_stateTimer;
|
||||
|
||||
friend class ServerLobbyThread;
|
||||
friend class AbstractServerGameStateReceiving;
|
||||
|
||||
+40
-40
@@ -41,16 +41,16 @@ class ServerGameState
|
||||
{
|
||||
public:
|
||||
virtual ~ServerGameState();
|
||||
virtual void Enter(ServerGame &server) = 0;
|
||||
virtual void Exit(ServerGame &server) = 0;
|
||||
virtual void Enter(boost::shared_ptr<ServerGame> server) = 0;
|
||||
virtual void Exit(boost::shared_ptr<ServerGame> server) = 0;
|
||||
|
||||
virtual void NotifyGameAdminChanged(ServerGame &server) = 0;
|
||||
virtual void NotifyGameAdminChanged(boost::shared_ptr<ServerGame> server) = 0;
|
||||
|
||||
// Handling of a new session.
|
||||
virtual void HandleNewSession(ServerGame &server, SessionWrapper session) = 0;
|
||||
virtual void HandleNewSession(boost::shared_ptr<ServerGame> server, SessionWrapper session) = 0;
|
||||
|
||||
// Main processing function of the current state.
|
||||
virtual int ProcessPacket(ServerGame &server, SessionWrapper session, boost::shared_ptr<NetPacket> packet) = 0;
|
||||
virtual int ProcessPacket(boost::shared_ptr<ServerGame> server, SessionWrapper session, boost::shared_ptr<NetPacket> packet) = 0;
|
||||
};
|
||||
|
||||
// Abstract State: Receiving.
|
||||
@@ -61,11 +61,11 @@ public:
|
||||
|
||||
// Globally handle packets which are allowed in all running states.
|
||||
// Calls InternalProcess if packet has not been processed.
|
||||
virtual int ProcessPacket(ServerGame &server, SessionWrapper session, boost::shared_ptr<NetPacket> packet);
|
||||
virtual int ProcessPacket(boost::shared_ptr<ServerGame> server, SessionWrapper session, boost::shared_ptr<NetPacket> packet);
|
||||
|
||||
protected:
|
||||
|
||||
virtual int InternalProcessPacket(ServerGame &server, SessionWrapper session, boost::shared_ptr<NetPacket> packet) = 0;
|
||||
virtual int InternalProcessPacket(boost::shared_ptr<ServerGame> server, SessionWrapper session, boost::shared_ptr<NetPacket> packet) = 0;
|
||||
};
|
||||
|
||||
// State: Initialization.
|
||||
@@ -73,24 +73,24 @@ class ServerGameStateInit : public AbstractServerGameStateReceiving
|
||||
{
|
||||
public:
|
||||
static ServerGameStateInit &Instance();
|
||||
virtual void Enter(ServerGame &server);
|
||||
virtual void Exit(ServerGame &server);
|
||||
virtual void Enter(boost::shared_ptr<ServerGame> server);
|
||||
virtual void Exit(boost::shared_ptr<ServerGame> server);
|
||||
|
||||
virtual ~ServerGameStateInit();
|
||||
|
||||
virtual void NotifyGameAdminChanged(ServerGame &server);
|
||||
virtual void NotifyGameAdminChanged(boost::shared_ptr<ServerGame> server);
|
||||
|
||||
virtual void HandleNewSession(ServerGame &server, SessionWrapper session);
|
||||
virtual void HandleNewSession(boost::shared_ptr<ServerGame> server, SessionWrapper session);
|
||||
|
||||
protected:
|
||||
ServerGameStateInit();
|
||||
|
||||
void RegisterAdminTimer(ServerGame &server);
|
||||
void UnregisterAdminTimer(ServerGame &server);
|
||||
void TimerAdminWarning(ServerGame &server);
|
||||
void TimerAdminTimeout(ServerGame &server);
|
||||
void RegisterAdminTimer(boost::shared_ptr<ServerGame> server);
|
||||
void UnregisterAdminTimer(boost::shared_ptr<ServerGame> server);
|
||||
void TimerAdminWarning(const boost::system::error_code &ec, boost::shared_ptr<ServerGame> server);
|
||||
void TimerAdminTimeout(const boost::system::error_code &ec, boost::shared_ptr<ServerGame> server);
|
||||
|
||||
virtual int InternalProcessPacket(ServerGame &server, SessionWrapper session, boost::shared_ptr<NetPacket> packet);
|
||||
virtual int InternalProcessPacket(boost::shared_ptr<ServerGame> server, SessionWrapper session, boost::shared_ptr<NetPacket> packet);
|
||||
|
||||
static boost::shared_ptr<NetPacket> CreateNetPacketPlayerJoined(const PlayerData &playerData);
|
||||
|
||||
@@ -103,20 +103,20 @@ class ServerGameStateStartGame : public AbstractServerGameStateReceiving
|
||||
{
|
||||
public:
|
||||
static ServerGameStateStartGame &Instance();
|
||||
virtual void Enter(ServerGame &server);
|
||||
virtual void Exit(ServerGame &server);
|
||||
virtual void Enter(boost::shared_ptr<ServerGame> server);
|
||||
virtual void Exit(boost::shared_ptr<ServerGame> server);
|
||||
|
||||
virtual ~ServerGameStateStartGame();
|
||||
|
||||
virtual void NotifyGameAdminChanged(ServerGame &/*server*/) {}
|
||||
virtual void HandleNewSession(ServerGame &server, SessionWrapper session);
|
||||
virtual void NotifyGameAdminChanged(boost::shared_ptr<ServerGame> /*server*/) {}
|
||||
virtual void HandleNewSession(boost::shared_ptr<ServerGame> server, SessionWrapper session);
|
||||
|
||||
protected:
|
||||
ServerGameStateStartGame();
|
||||
|
||||
virtual int InternalProcessPacket(ServerGame &server, SessionWrapper session, boost::shared_ptr<NetPacket> packet);
|
||||
void TimerTimeout(ServerGame &server);
|
||||
void DoStart(ServerGame &server);
|
||||
virtual int InternalProcessPacket(boost::shared_ptr<ServerGame> server, SessionWrapper session, boost::shared_ptr<NetPacket> packet);
|
||||
void TimerTimeout(const boost::system::error_code &ec, boost::shared_ptr<ServerGame> server);
|
||||
void DoStart(boost::shared_ptr<ServerGame> server);
|
||||
|
||||
private:
|
||||
static ServerGameStateStartGame s_state;
|
||||
@@ -127,25 +127,25 @@ class ServerGameStateHand : public AbstractServerGameStateReceiving
|
||||
{
|
||||
public:
|
||||
static ServerGameStateHand &Instance();
|
||||
virtual void Enter(ServerGame &server);
|
||||
virtual void Exit(ServerGame &server);
|
||||
virtual void Enter(boost::shared_ptr<ServerGame> server);
|
||||
virtual void Exit(boost::shared_ptr<ServerGame> server);
|
||||
|
||||
virtual ~ServerGameStateHand();
|
||||
|
||||
virtual void NotifyGameAdminChanged(ServerGame &/*server*/) {}
|
||||
virtual void HandleNewSession(ServerGame &server, SessionWrapper session);
|
||||
virtual void NotifyGameAdminChanged(boost::shared_ptr<ServerGame> /*server*/) {}
|
||||
virtual void HandleNewSession(boost::shared_ptr<ServerGame> server, SessionWrapper session);
|
||||
|
||||
protected:
|
||||
ServerGameStateHand();
|
||||
|
||||
virtual int InternalProcessPacket(ServerGame &server, SessionWrapper session, boost::shared_ptr<NetPacket> packet);
|
||||
void TimerLoop(ServerGame &server);
|
||||
void TimerShowCards(ServerGame &server);
|
||||
void TimerComputerAction(ServerGame &server);
|
||||
void TimerNextHand(ServerGame &server);
|
||||
void TimerNextGame(ServerGame &server);
|
||||
virtual int InternalProcessPacket(boost::shared_ptr<ServerGame> server, SessionWrapper session, boost::shared_ptr<NetPacket> packet);
|
||||
void TimerLoop(const boost::system::error_code &ec, boost::shared_ptr<ServerGame> server);
|
||||
void TimerShowCards(const boost::system::error_code &ec, boost::shared_ptr<ServerGame> server);
|
||||
void TimerComputerAction(const boost::system::error_code &ec, boost::shared_ptr<ServerGame> server);
|
||||
void TimerNextHand(const boost::system::error_code &ec, boost::shared_ptr<ServerGame> server);
|
||||
void TimerNextGame(const boost::system::error_code &ec, boost::shared_ptr<ServerGame> server);
|
||||
int GetDealCardsDelaySec(ServerGame &server);
|
||||
static void StartNewHand(ServerGame &server);
|
||||
static void StartNewHand(boost::shared_ptr<ServerGame> server);
|
||||
|
||||
private:
|
||||
static ServerGameStateHand s_state;
|
||||
@@ -158,19 +158,19 @@ class ServerGameStateWaitPlayerAction : public AbstractServerGameStateReceiving
|
||||
{
|
||||
public:
|
||||
static ServerGameStateWaitPlayerAction &Instance();
|
||||
virtual void Enter(ServerGame &server);
|
||||
virtual void Exit(ServerGame &server);
|
||||
virtual void Enter(boost::shared_ptr<ServerGame> server);
|
||||
virtual void Exit(boost::shared_ptr<ServerGame> server);
|
||||
|
||||
virtual ~ServerGameStateWaitPlayerAction();
|
||||
|
||||
virtual void NotifyGameAdminChanged(ServerGame &/*server*/) {}
|
||||
virtual void HandleNewSession(ServerGame &server, SessionWrapper session);
|
||||
virtual void NotifyGameAdminChanged(boost::shared_ptr<ServerGame> /*server*/) {}
|
||||
virtual void HandleNewSession(boost::shared_ptr<ServerGame> server, SessionWrapper session);
|
||||
|
||||
protected:
|
||||
ServerGameStateWaitPlayerAction();
|
||||
|
||||
virtual int InternalProcessPacket(ServerGame &server, SessionWrapper session, boost::shared_ptr<NetPacket> packet);
|
||||
void TimerTimeout(ServerGame &server);
|
||||
virtual int InternalProcessPacket(boost::shared_ptr<ServerGame> server, SessionWrapper session, boost::shared_ptr<NetPacket> packet);
|
||||
void TimerTimeout(const boost::system::error_code &ec, boost::shared_ptr<ServerGame> server);
|
||||
|
||||
private:
|
||||
static ServerGameStateWaitPlayerAction s_state;
|
||||
|
||||
+17
-10
@@ -24,8 +24,8 @@
|
||||
#include <boost/asio.hpp>
|
||||
#include <deque>
|
||||
#include <boost/regex.hpp>
|
||||
#include <boost/enable_shared_from_this.hpp>
|
||||
|
||||
#include <core/timermanager.h>
|
||||
#include <net/sessionmanager.h>
|
||||
#include <net/netpacket.h>
|
||||
#include <gui/guiinterface.h>
|
||||
@@ -45,7 +45,7 @@ class AvatarManager;
|
||||
struct GameData;
|
||||
class Game;
|
||||
|
||||
class ServerLobbyThread : public Thread
|
||||
class ServerLobbyThread : public Thread, public boost::enable_shared_from_this<ServerLobbyThread>
|
||||
{
|
||||
public:
|
||||
ServerLobbyThread(GuiInterface &gui, ConfigFile *playerConfig, AvatarManager &avatarManager,
|
||||
@@ -89,13 +89,13 @@ public:
|
||||
u_int32_t GetNextGameId();
|
||||
ServerCallback &GetCallback();
|
||||
|
||||
TimerManager &GetTimerManager();
|
||||
AvatarManager &GetAvatarManager();
|
||||
|
||||
ServerStats GetStats() const;
|
||||
boost::posix_time::ptime GetStartTime() const;
|
||||
|
||||
SenderHelper &GetSender();
|
||||
boost::asio::io_service &GetIOService();
|
||||
|
||||
protected:
|
||||
|
||||
@@ -113,6 +113,7 @@ protected:
|
||||
// Main function of the thread.
|
||||
virtual void Main();
|
||||
void RegisterTimers();
|
||||
void CancelTimers();
|
||||
|
||||
void HandleRead(SessionId sessionId, const boost::system::error_code &error, size_t bytesRead);
|
||||
void HandlePacket(SessionWrapper session, boost::shared_ptr<NetPacket> packet);
|
||||
@@ -127,11 +128,11 @@ protected:
|
||||
void HandleNetPacketJoinGame(SessionWrapper session, const NetPacketJoinGame &tmpPacket);
|
||||
void EstablishSession(SessionWrapper session);
|
||||
void RequestPlayerAvatar(SessionWrapper session);
|
||||
void TimerRemoveGame();
|
||||
void TimerRemovePlayer();
|
||||
void TimerUpdateClientAvatarLock();
|
||||
void TimerCheckSessionTimeouts();
|
||||
void TimerCleanupAvatarCache();
|
||||
void TimerRemoveGame(const boost::system::error_code &ec);
|
||||
void TimerRemovePlayer(const boost::system::error_code &ec);
|
||||
void TimerUpdateClientAvatarLock(const boost::system::error_code &ec);
|
||||
void TimerCheckSessionTimeouts(const boost::system::error_code &ec);
|
||||
void TimerCleanupAvatarCache(const boost::system::error_code &ec);
|
||||
|
||||
boost::shared_ptr<ServerGame> InternalGetGameFromId(unsigned gameId);
|
||||
void InternalAddGame(boost::shared_ptr<ServerGame> game);
|
||||
@@ -153,7 +154,7 @@ protected:
|
||||
void BroadcastStatisticsUpdate(const ServerStats &stats);
|
||||
|
||||
void ReadStatisticsFile();
|
||||
void TimerSaveStatisticsFile();
|
||||
void TimerSaveStatisticsFile(const boost::system::error_code &ec);
|
||||
|
||||
ReceiverHelper &GetReceiver();
|
||||
|
||||
@@ -180,7 +181,6 @@ private:
|
||||
|
||||
SessionManager m_sessionManager;
|
||||
SessionManager m_gameSessionManager;
|
||||
TimerManager m_timerManager;
|
||||
|
||||
TimerClientAddressMap m_timerAvatarClientAddressMap;
|
||||
mutable boost::mutex m_timerAvatarClientAddressMapMutex;
|
||||
@@ -217,6 +217,13 @@ private:
|
||||
bool m_statDataChanged;
|
||||
mutable boost::mutex m_statMutex;
|
||||
|
||||
boost::asio::deadline_timer m_removeGameTimer;
|
||||
boost::asio::deadline_timer m_removePlayerTimer;
|
||||
boost::asio::deadline_timer m_sessionTimeoutTimer;
|
||||
boost::asio::deadline_timer m_avatarCleanupTimer;
|
||||
boost::asio::deadline_timer m_saveStatisticsTimer;
|
||||
boost::asio::deadline_timer m_avatarLockTimer;
|
||||
|
||||
const boost::posix_time::ptime m_startTime;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user