Synchronize on network game start, so that everyone has received all avatars and player names before the game starts. Store all computer players in a separate list on the server for name retrieval.
This commit is contained in:
@@ -234,6 +234,41 @@ protected:
|
||||
virtual int InternalProcess(ClientThread &client, boost::shared_ptr<NetPacket> packet);
|
||||
};
|
||||
|
||||
// State: Synchronize on game start.
|
||||
class ClientStateSynchronizeStart : public AbstractClientStateReceiving
|
||||
{
|
||||
public:
|
||||
// Access the state singleton.
|
||||
static ClientStateSynchronizeStart &Instance();
|
||||
|
||||
virtual ~ClientStateSynchronizeStart();
|
||||
|
||||
virtual int Process(ClientThread &client);
|
||||
protected:
|
||||
|
||||
// Protected constructor - this is a singleton.
|
||||
ClientStateSynchronizeStart();
|
||||
|
||||
virtual int InternalProcess(ClientThread &client, boost::shared_ptr<NetPacket> packet);
|
||||
};
|
||||
|
||||
// State: Wait for game start.
|
||||
class ClientStateWaitStart : public AbstractClientStateReceiving
|
||||
{
|
||||
public:
|
||||
// Access the state singleton.
|
||||
static ClientStateWaitStart &Instance();
|
||||
|
||||
virtual ~ClientStateWaitStart();
|
||||
|
||||
protected:
|
||||
|
||||
// Protected constructor - this is a singleton.
|
||||
ClientStateWaitStart();
|
||||
|
||||
virtual int InternalProcess(ClientThread &client, boost::shared_ptr<NetPacket> packet);
|
||||
};
|
||||
|
||||
// State: Wait for start of the next hand.
|
||||
class ClientStateWaitHand : public AbstractClientStateReceiving
|
||||
{
|
||||
|
||||
@@ -86,7 +86,7 @@ protected:
|
||||
|
||||
bool GetCachedPlayerInfo(unsigned id, PlayerInfo &info) const;
|
||||
void RequestPlayerInfo(unsigned id);
|
||||
void SetPlayerInfo(unsigned id, const PlayerInfo &info);
|
||||
void SetPlayerInfo(unsigned id, const PlayerInfo &info, bool retrieveAvatar = true);
|
||||
void SetNewGameAdmin(unsigned id);
|
||||
|
||||
void AddTempAvatarData(unsigned playerId, unsigned avatarSize, AvatarFileType type);
|
||||
@@ -134,6 +134,8 @@ protected:
|
||||
bool IsSessionEstablished() const;
|
||||
void SetSessionEstablished(bool flag);
|
||||
|
||||
bool IsSynchronized() const;
|
||||
|
||||
private:
|
||||
|
||||
NetPacketList m_outPacketList;
|
||||
@@ -177,6 +179,8 @@ friend class ClientStateStartSession;
|
||||
friend class ClientStateWaitSession;
|
||||
friend class ClientStateWaitJoin;
|
||||
friend class ClientStateWaitGame;
|
||||
friend class ClientStateSynchronizeStart;
|
||||
friend class ClientStateWaitStart;
|
||||
friend class ClientStateWaitHand;
|
||||
friend class ClientStateRunHand;
|
||||
friend class ClientStateFinal;
|
||||
|
||||
@@ -395,16 +395,6 @@ AbstractClientStateReceiving::Process(ClientThread &client)
|
||||
NetPacketPlayerInfo::Data infoData;
|
||||
tmpPacket->ToNetPacketPlayerInfo()->GetData(infoData);
|
||||
client.SetPlayerInfo(infoData.playerId, infoData.playerInfo);
|
||||
// Retrieve avatar if needed.
|
||||
if (infoData.playerInfo.hasAvatar && !client.GetAvatarManager().HasAvatar(infoData.playerInfo.avatar))
|
||||
{
|
||||
boost::shared_ptr<NetPacket> retrieveAvatar(new NetPacketRetrieveAvatar);
|
||||
NetPacketRetrieveAvatar::Data retrieveAvatarData;
|
||||
retrieveAvatarData.requestId = infoData.playerId;
|
||||
retrieveAvatarData.avatar = infoData.playerInfo.avatar;
|
||||
static_cast<NetPacketRetrieveAvatar *>(retrieveAvatar.get())->SetData(retrieveAvatarData);
|
||||
client.GetSender().Send(client.GetContext().GetSocket(), retrieveAvatar);
|
||||
}
|
||||
}
|
||||
else if (tmpPacket->ToNetPacketRemovedFromGame())
|
||||
{
|
||||
@@ -651,33 +641,9 @@ ClientStateWaitGame::InternalProcess(ClientThread &client, boost::shared_ptr<Net
|
||||
{
|
||||
int retVal = MSG_SOCK_INTERNAL_PENDING;
|
||||
|
||||
if (packet->ToNetPacketGameStart())
|
||||
if (packet->ToNetPacketStartEvent())
|
||||
{
|
||||
// Start the network game as client.
|
||||
NetPacketGameStart::Data gameStartData;
|
||||
packet->ToNetPacketGameStart()->GetData(gameStartData);
|
||||
|
||||
client.SetStartData(gameStartData.startData);
|
||||
|
||||
// Set player numbers using the game start data slots.
|
||||
NetPacketGameStart::PlayerSlotList::const_iterator slot_i = gameStartData.playerSlots.begin();
|
||||
NetPacketGameStart::PlayerSlotList::const_iterator slot_end = gameStartData.playerSlots.end();
|
||||
int num = 0;
|
||||
|
||||
while (slot_i != slot_end)
|
||||
{
|
||||
unsigned playerId = (*slot_i).playerId;
|
||||
boost::shared_ptr<PlayerData> tmpPlayer = client.GetPlayerDataByUniqueId(playerId);
|
||||
if (!tmpPlayer.get())
|
||||
throw ClientException(ERR_NET_UNKNOWN_PLAYER_ID, 0);
|
||||
tmpPlayer->SetNumber(num);
|
||||
|
||||
++num;
|
||||
++slot_i;
|
||||
}
|
||||
|
||||
client.SetState(ClientStateWaitHand::Instance());
|
||||
retVal = MSG_NET_GAME_CLIENT_START;
|
||||
client.SetState(ClientStateSynchronizeStart::Instance());
|
||||
}
|
||||
else if (packet->ToNetPacketPlayerJoined())
|
||||
{
|
||||
@@ -719,6 +685,103 @@ ClientStateWaitGame::InternalProcess(ClientThread &client, boost::shared_ptr<Net
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
ClientStateSynchronizeStart &
|
||||
ClientStateSynchronizeStart::Instance()
|
||||
{
|
||||
static ClientStateSynchronizeStart state;
|
||||
return state;
|
||||
}
|
||||
|
||||
ClientStateSynchronizeStart::ClientStateSynchronizeStart()
|
||||
{
|
||||
}
|
||||
|
||||
ClientStateSynchronizeStart::~ClientStateSynchronizeStart()
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
ClientStateSynchronizeStart::Process(ClientThread &client)
|
||||
{
|
||||
int retVal = AbstractClientStateReceiving::Process(client);
|
||||
|
||||
if (client.IsSynchronized())
|
||||
{
|
||||
boost::shared_ptr<NetPacket> startAck(new NetPacketStartEventAck);
|
||||
client.GetSender().Send(client.GetContext().GetSocket(), startAck);
|
||||
client.SetState(ClientStateWaitStart::Instance());
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
int
|
||||
ClientStateSynchronizeStart::InternalProcess(ClientThread &client, boost::shared_ptr<NetPacket> packet)
|
||||
{
|
||||
int retVal = MSG_SOCK_INTERNAL_PENDING;
|
||||
|
||||
if (packet->ToNetPacketGameStart())
|
||||
throw ClientException(ERR_NET_START_TIMEOUT, 0);
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
ClientStateWaitStart &
|
||||
ClientStateWaitStart::Instance()
|
||||
{
|
||||
static ClientStateWaitStart state;
|
||||
return state;
|
||||
}
|
||||
|
||||
ClientStateWaitStart::ClientStateWaitStart()
|
||||
{
|
||||
}
|
||||
|
||||
ClientStateWaitStart::~ClientStateWaitStart()
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
ClientStateWaitStart::InternalProcess(ClientThread &client, boost::shared_ptr<NetPacket> packet)
|
||||
{
|
||||
int retVal = MSG_SOCK_INTERNAL_PENDING;
|
||||
|
||||
if (packet->ToNetPacketGameStart())
|
||||
{
|
||||
// Start the network game as client.
|
||||
NetPacketGameStart::Data gameStartData;
|
||||
packet->ToNetPacketGameStart()->GetData(gameStartData);
|
||||
|
||||
client.SetStartData(gameStartData.startData);
|
||||
|
||||
// Set player numbers using the game start data slots.
|
||||
NetPacketGameStart::PlayerSlotList::const_iterator slot_i = gameStartData.playerSlots.begin();
|
||||
NetPacketGameStart::PlayerSlotList::const_iterator slot_end = gameStartData.playerSlots.end();
|
||||
int num = 0;
|
||||
|
||||
while (slot_i != slot_end)
|
||||
{
|
||||
unsigned playerId = (*slot_i).playerId;
|
||||
boost::shared_ptr<PlayerData> tmpPlayer = client.GetPlayerDataByUniqueId(playerId);
|
||||
if (!tmpPlayer.get())
|
||||
throw ClientException(ERR_NET_UNKNOWN_PLAYER_ID, 0);
|
||||
tmpPlayer->SetNumber(num);
|
||||
|
||||
++num;
|
||||
++slot_i;
|
||||
}
|
||||
|
||||
client.SetState(ClientStateWaitHand::Instance());
|
||||
retVal = MSG_NET_GAME_CLIENT_START;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
ClientStateWaitHand &
|
||||
ClientStateWaitHand::Instance()
|
||||
{
|
||||
|
||||
@@ -381,7 +381,7 @@ ClientThread::RequestPlayerInfo(unsigned id)
|
||||
}
|
||||
|
||||
void
|
||||
ClientThread::SetPlayerInfo(unsigned id, const PlayerInfo &info)
|
||||
ClientThread::SetPlayerInfo(unsigned id, const PlayerInfo &info, bool retrieveAvatar)
|
||||
{
|
||||
{
|
||||
boost::mutex::scoped_lock lock(m_playerInfoMapMutex);
|
||||
@@ -404,6 +404,23 @@ ClientThread::SetPlayerInfo(unsigned id, const PlayerInfo &info)
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve avatar if needed.
|
||||
if (retrieveAvatar && info.hasAvatar && !GetAvatarManager().HasAvatar(info.avatar))
|
||||
{
|
||||
boost::shared_ptr<NetPacket> retrieveAvatar(new NetPacketRetrieveAvatar);
|
||||
NetPacketRetrieveAvatar::Data retrieveAvatarData;
|
||||
retrieveAvatarData.requestId = id;
|
||||
retrieveAvatarData.avatar = info.avatar;
|
||||
static_cast<NetPacketRetrieveAvatar *>(retrieveAvatar.get())->SetData(retrieveAvatarData);
|
||||
GetSender().Send(GetContext().GetSocket(), retrieveAvatar);
|
||||
|
||||
// Insert empty value in list to synchronize waiting.
|
||||
m_tempAvatarMap[id] = boost::shared_ptr<AvatarData>();
|
||||
}
|
||||
|
||||
// Remove from request list.
|
||||
m_playerInfoRequestList.remove(id);
|
||||
|
||||
// Notify GUI
|
||||
GetCallback().SignalNetClientPlayerChanged(id, info.playerName);
|
||||
|
||||
@@ -464,7 +481,7 @@ ClientThread::CompleteTempAvatarData(unsigned playerId)
|
||||
m_tempAvatarMap.erase(pos);
|
||||
|
||||
// Update player info, but never re-request avatar.
|
||||
SetPlayerInfo(playerId, tmpPlayerInfo);
|
||||
SetPlayerInfo(playerId, tmpPlayerInfo, false);
|
||||
}
|
||||
|
||||
const ClientContext &
|
||||
@@ -822,3 +839,9 @@ ClientThread::SetSessionEstablished(bool flag)
|
||||
m_sessionEstablished = flag;
|
||||
}
|
||||
|
||||
bool
|
||||
ClientThread::IsSynchronized() const
|
||||
{
|
||||
return (m_playerInfoRequestList.empty() && m_tempAvatarMap.empty());
|
||||
}
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ using namespace std;
|
||||
#define NET_TYPE_KICK_PLAYER 0x0040
|
||||
#define NET_TYPE_LEAVE_CURRENT_GAME 0x0041
|
||||
#define NET_TYPE_START_EVENT 0x0042
|
||||
#define NET_TYPE_START_EVENT_ACK 0x0043
|
||||
#define NET_TYPE_GAME_START 0x0050
|
||||
#define NET_TYPE_HAND_START 0x0051
|
||||
#define NET_TYPE_PLAYERS_TURN 0x0052
|
||||
@@ -297,6 +298,12 @@ struct GCC_PACKED NetPacketStartEventData
|
||||
u_int16_t reserved;
|
||||
};
|
||||
|
||||
struct GCC_PACKED NetPacketStartEventAckData
|
||||
{
|
||||
NetPacketHeader head;
|
||||
u_int32_t reserved;
|
||||
};
|
||||
|
||||
struct GCC_PACKED NetPacketGameStartData
|
||||
{
|
||||
NetPacketHeader head;
|
||||
@@ -646,6 +653,9 @@ NetPacket::Create(char *data, unsigned &dataSize)
|
||||
case NET_TYPE_START_EVENT:
|
||||
tmpPacket = boost::shared_ptr<NetPacket>(new NetPacketStartEvent);
|
||||
break;
|
||||
case NET_TYPE_START_EVENT_ACK:
|
||||
tmpPacket = boost::shared_ptr<NetPacket>(new NetPacketStartEventAck);
|
||||
break;
|
||||
case NET_TYPE_GAME_START:
|
||||
tmpPacket = boost::shared_ptr<NetPacket>(new NetPacketGameStart);
|
||||
break;
|
||||
@@ -913,6 +923,12 @@ NetPacket::ToNetPacketStartEvent() const
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const NetPacketStartEventAck *
|
||||
NetPacket::ToNetPacketStartEventAck() const
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const NetPacketGameStart *
|
||||
NetPacket::ToNetPacketGameStart() const
|
||||
{
|
||||
@@ -2641,7 +2657,7 @@ NetPacketKickPlayer::InternalCheck(const NetPacketHeader*) const
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
NetPacketLeaveCurrentGame::NetPacketLeaveCurrentGame()
|
||||
: NetPacket(NET_TYPE_LEAVE_CURRENT_GAME, sizeof(NetPacketLeaveCurrentGame), sizeof(NetPacketLeaveCurrentGame))
|
||||
: NetPacket(NET_TYPE_LEAVE_CURRENT_GAME, sizeof(NetPacketLeaveCurrentGameData), sizeof(NetPacketLeaveCurrentGameData))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -2735,6 +2751,43 @@ NetPacketStartEvent::InternalCheck(const NetPacketHeader*) const
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
NetPacketStartEventAck::NetPacketStartEventAck()
|
||||
: NetPacket(NET_TYPE_START_EVENT_ACK, sizeof(NetPacketStartEventAckData), sizeof(NetPacketStartEventAckData))
|
||||
{
|
||||
}
|
||||
|
||||
NetPacketStartEventAck::~NetPacketStartEventAck()
|
||||
{
|
||||
}
|
||||
|
||||
boost::shared_ptr<NetPacket>
|
||||
NetPacketStartEventAck::Clone() const
|
||||
{
|
||||
boost::shared_ptr<NetPacket> newPacket(new NetPacketStartEventAck);
|
||||
try
|
||||
{
|
||||
newPacket->SetRawData(GetRawData());
|
||||
} catch (const NetException &)
|
||||
{
|
||||
// Need to return the new packet anyway.
|
||||
}
|
||||
return newPacket;
|
||||
}
|
||||
|
||||
const NetPacketStartEventAck *
|
||||
NetPacketStartEventAck::ToNetPacketStartEventAck() const
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
void
|
||||
NetPacketStartEventAck::InternalCheck(const NetPacketHeader*) const
|
||||
{
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
NetPacketGameStart::NetPacketGameStart()
|
||||
: NetPacket(NET_TYPE_GAME_START, sizeof(NetPacketGameStartData), MAX_PACKET_SIZE)
|
||||
{
|
||||
|
||||
@@ -46,6 +46,7 @@ using namespace std;
|
||||
#define SERVER_SHOW_CARDS_DELAY_SEC 2
|
||||
#define SERVER_PLAYER_TIMEOUT_ADD_DELAY_SEC 2
|
||||
#define SERVER_COMPUTER_ACTION_DELAY_SEC 2
|
||||
#define SERVER_START_GAME_TIMEOUT_SEC 10
|
||||
|
||||
#define SERVER_COMPUTER_PLAYER_NAME "Computer"
|
||||
|
||||
@@ -286,35 +287,41 @@ ServerGameStateInit::HandleNewSession(ServerGameThread &server, SessionWrapper s
|
||||
int
|
||||
ServerGameStateInit::InternalProcess(ServerGameThread &server, SessionWrapper session, boost::shared_ptr<NetPacket> packet)
|
||||
{
|
||||
int retVal = MSG_SOCK_INIT_DONE;
|
||||
int retVal = MSG_SOCK_INTERNAL_PENDING;
|
||||
|
||||
if (packet->ToNetPacketStartEvent())
|
||||
{
|
||||
NetPacketStartEvent::Data startData;
|
||||
packet->ToNetPacketStartEvent()->GetData(startData);
|
||||
|
||||
server.ResetComputerPlayerList();
|
||||
|
||||
if (startData.fillUpWithCpuPlayers)
|
||||
// Only admins are allowed to start the game.
|
||||
if (session.playerData->GetRights() == PLAYER_RIGHTS_ADMIN)
|
||||
{
|
||||
int remainingSlots = server.GetGameData().maxNumberOfPlayers - server.GetCurNumberOfPlayers();
|
||||
for (int i = 1; i <= remainingSlots; i++)
|
||||
NetPacketStartEvent::Data startData;
|
||||
packet->ToNetPacketStartEvent()->GetData(startData);
|
||||
|
||||
// Fill up with computer players.
|
||||
server.ResetComputerPlayerList();
|
||||
|
||||
if (startData.fillUpWithCpuPlayers)
|
||||
{
|
||||
boost::shared_ptr<PlayerData> tmpPlayerData(
|
||||
new PlayerData(server.GetLobbyThread().GetNextUniquePlayerId(), 0, PLAYER_TYPE_COMPUTER, PLAYER_RIGHTS_NORMAL));
|
||||
int remainingSlots = server.GetGameData().maxNumberOfPlayers - server.GetCurNumberOfPlayers();
|
||||
for (int i = 1; i <= remainingSlots; i++)
|
||||
{
|
||||
boost::shared_ptr<PlayerData> tmpPlayerData(
|
||||
new PlayerData(server.GetLobbyThread().GetNextUniquePlayerId(), 0, PLAYER_TYPE_COMPUTER, PLAYER_RIGHTS_NORMAL));
|
||||
|
||||
ostringstream name;
|
||||
name << SERVER_COMPUTER_PLAYER_NAME << i;
|
||||
tmpPlayerData->SetName(name.str());
|
||||
server.AddComputerPlayer(tmpPlayerData);
|
||||
ostringstream name;
|
||||
name << SERVER_COMPUTER_PLAYER_NAME << i;
|
||||
tmpPlayerData->SetName(name.str());
|
||||
server.AddComputerPlayer(tmpPlayerData);
|
||||
|
||||
// Send "Player Joined" to other fully connected clients.
|
||||
server.SendToAllPlayers(CreateNetPacketPlayerJoined(*tmpPlayerData), SessionData::Game);
|
||||
// Send "Player Joined" to other fully connected clients.
|
||||
server.SendToAllPlayers(CreateNetPacketPlayerJoined(*tmpPlayerData), SessionData::Game);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Wait for all players to confirm start of game.
|
||||
server.SendToAllPlayers(boost::shared_ptr<NetPacket>(packet->Clone()), SessionData::Game);
|
||||
|
||||
server.InternalStartGame();
|
||||
server.SetState(SERVER_START_GAME_STATE::Instance());
|
||||
server.SetState(ServerGameStateWaitAck::Instance());
|
||||
}
|
||||
}
|
||||
else if (packet->ToNetPacketKickPlayer())
|
||||
{
|
||||
@@ -365,6 +372,64 @@ AbstractServerGameStateRunning::HandleNewSession(ServerGameThread &server, Sessi
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
boost::thread_specific_ptr<ServerGameStateWaitAck> ServerGameStateWaitAck::Ptr;
|
||||
|
||||
ServerGameStateWaitAck &
|
||||
ServerGameStateWaitAck::Instance()
|
||||
{
|
||||
if (!Ptr.get())
|
||||
Ptr.reset(new ServerGameStateWaitAck);
|
||||
|
||||
return *Ptr;
|
||||
}
|
||||
|
||||
ServerGameStateWaitAck::ServerGameStateWaitAck()
|
||||
{
|
||||
}
|
||||
|
||||
ServerGameStateWaitAck::~ServerGameStateWaitAck()
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
ServerGameStateWaitAck::Process(ServerGameThread &server)
|
||||
{
|
||||
int retVal;
|
||||
|
||||
if (GetTimer().elapsed().total_seconds() >= SERVER_START_GAME_TIMEOUT_SEC)
|
||||
{
|
||||
// On timeout: start anyway.
|
||||
server.SetState(SERVER_START_GAME_STATE::Instance());
|
||||
retVal = MSG_SOCK_INIT_DONE;
|
||||
}
|
||||
else
|
||||
retVal = AbstractServerGameStateReceiving::Process(server);
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
int
|
||||
ServerGameStateWaitAck::InternalProcess(ServerGameThread &server, SessionWrapper session, boost::shared_ptr<NetPacket> packet)
|
||||
{
|
||||
int retVal = MSG_SOCK_INTERNAL_PENDING;
|
||||
|
||||
if (packet->ToNetPacketStartEventAck())
|
||||
{
|
||||
session.sessionData->SetReadyFlag();
|
||||
if (server.GetSessionManager().CountReadySessions() == server.GetSessionManager().GetRawSessionCount())
|
||||
{
|
||||
// Everyone is ready.
|
||||
server.SetState(SERVER_START_GAME_STATE::Instance());
|
||||
retVal = MSG_SOCK_INIT_DONE;
|
||||
}
|
||||
retVal = MSG_SOCK_INIT_DONE;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
boost::thread_specific_ptr<ServerGameStateStartGame> ServerGameStateStartGame::Ptr;
|
||||
|
||||
ServerGameStateStartGame &
|
||||
@@ -387,6 +452,8 @@ ServerGameStateStartGame::~ServerGameStateStartGame()
|
||||
int
|
||||
ServerGameStateStartGame::Process(ServerGameThread &server)
|
||||
{
|
||||
server.InternalStartGame();
|
||||
|
||||
boost::shared_ptr<NetPacket> answer(new NetPacketGameStart);
|
||||
|
||||
NetPacketGameStart::Data gameStartData;
|
||||
|
||||
@@ -152,6 +152,7 @@ ServerGameThread::Main()
|
||||
GetSender().SignalTermination();
|
||||
GetSender().Join(SENDER_THREAD_TERMINATE_TIMEOUT);
|
||||
|
||||
ResetComputerPlayerList();
|
||||
GetLobbyThread().RemoveGame(GetId());
|
||||
}
|
||||
|
||||
@@ -273,14 +274,27 @@ ServerGameThread::IsRunning() const
|
||||
void
|
||||
ServerGameThread::AddComputerPlayer(boost::shared_ptr<PlayerData> player)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(m_computerPlayerListMutex);
|
||||
m_computerPlayerList.push_back(player);
|
||||
{
|
||||
boost::mutex::scoped_lock lock(m_computerPlayerListMutex);
|
||||
m_computerPlayerList.push_back(player);
|
||||
}
|
||||
GetLobbyThread().AddComputerPlayer(player);
|
||||
}
|
||||
|
||||
void
|
||||
ServerGameThread::ResetComputerPlayerList()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(m_computerPlayerListMutex);
|
||||
|
||||
PlayerDataList::iterator i = m_computerPlayerList.begin();
|
||||
PlayerDataList::iterator end = m_computerPlayerList.end();
|
||||
|
||||
while (i != end)
|
||||
{
|
||||
GetLobbyThread().RemoveComputerPlayer(*i);
|
||||
++i;
|
||||
}
|
||||
|
||||
m_computerPlayerList.clear();
|
||||
}
|
||||
|
||||
|
||||
@@ -176,6 +176,20 @@ ServerLobbyThread::HandleGameRetrieveAvatar(SessionWrapper session, const NetPac
|
||||
HandleNetPacketRetrieveAvatar(session, tmpPacket);
|
||||
}
|
||||
|
||||
void
|
||||
ServerLobbyThread::AddComputerPlayer(boost::shared_ptr<PlayerData> player)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(m_computerPlayersMutex);
|
||||
m_computerPlayers.insert(PlayerDataMap::value_type(player->GetUniqueId(), player));
|
||||
}
|
||||
|
||||
void
|
||||
ServerLobbyThread::RemoveComputerPlayer(boost::shared_ptr<PlayerData> player)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(m_computerPlayersMutex);
|
||||
m_computerPlayers.erase(player->GetUniqueId());
|
||||
}
|
||||
|
||||
void
|
||||
ServerLobbyThread::RemoveGame(unsigned id)
|
||||
{
|
||||
@@ -446,6 +460,13 @@ ServerLobbyThread::HandleNetPacketRetrievePlayerInfo(SessionWrapper session, con
|
||||
boost::shared_ptr<PlayerData> tmpPlayer = m_sessionManager.GetSessionByUniquePlayerId(request.playerId).playerData;
|
||||
if (!tmpPlayer.get())
|
||||
tmpPlayer = m_gameSessionManager.GetSessionByUniquePlayerId(request.playerId).playerData;
|
||||
if (!tmpPlayer.get())
|
||||
{
|
||||
boost::mutex::scoped_lock lock(m_computerPlayersMutex);
|
||||
PlayerDataMap::const_iterator pos = m_computerPlayers.find(request.playerId);
|
||||
if (pos != m_computerPlayers.end())
|
||||
tmpPlayer = pos->second;
|
||||
}
|
||||
|
||||
if (tmpPlayer.get())
|
||||
{
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#include <net/sessiondata.h>
|
||||
|
||||
SessionData::SessionData(SOCKET sockfd, unsigned id)
|
||||
: m_sockfd(sockfd), m_id(id), m_state(SessionData::Init)
|
||||
: m_sockfd(sockfd), m_id(id), m_state(SessionData::Init), m_readyFlag(false)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -58,6 +58,27 @@ SessionData::GetSocket() const
|
||||
return m_sockfd;
|
||||
}
|
||||
|
||||
void
|
||||
SessionData::SetReadyFlag()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(m_dataMutex);
|
||||
m_readyFlag = true;
|
||||
}
|
||||
|
||||
void
|
||||
SessionData::ResetReadyFlag()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(m_dataMutex);
|
||||
m_readyFlag = false;
|
||||
}
|
||||
|
||||
bool
|
||||
SessionData::IsReady() const
|
||||
{
|
||||
boost::mutex::scoped_lock lock(m_dataMutex);
|
||||
return m_readyFlag;
|
||||
}
|
||||
|
||||
const std::string &
|
||||
SessionData::GetClientAddr() const
|
||||
{
|
||||
|
||||
@@ -292,6 +292,24 @@ SessionManager::ForEach(boost::function<void (SessionWrapper)> func)
|
||||
}
|
||||
}
|
||||
|
||||
unsigned
|
||||
SessionManager::CountReadySessions() const
|
||||
{
|
||||
unsigned counter = 0;
|
||||
boost::mutex::scoped_lock lock(m_sessionMapMutex);
|
||||
|
||||
SessionMap::const_iterator i = m_sessionMap.begin();
|
||||
SessionMap::const_iterator end = m_sessionMap.end();
|
||||
|
||||
while (i != end)
|
||||
{
|
||||
if ((*i).second.sessionData->IsReady())
|
||||
++counter;
|
||||
++i;
|
||||
}
|
||||
return counter;
|
||||
}
|
||||
|
||||
void
|
||||
SessionManager::Clear()
|
||||
{
|
||||
|
||||
@@ -68,6 +68,7 @@ class NetPacketGameAdminChanged;
|
||||
class NetPacketKickPlayer;
|
||||
class NetPacketLeaveCurrentGame;
|
||||
class NetPacketStartEvent;
|
||||
class NetPacketStartEventAck;
|
||||
class NetPacketGameStart;
|
||||
class NetPacketHandStart;
|
||||
class NetPacketPlayersTurn;
|
||||
@@ -125,6 +126,7 @@ public:
|
||||
virtual const NetPacketKickPlayer *ToNetPacketKickPlayer() const;
|
||||
virtual const NetPacketLeaveCurrentGame *ToNetPacketLeaveCurrentGame() const;
|
||||
virtual const NetPacketStartEvent *ToNetPacketStartEvent() const;
|
||||
virtual const NetPacketStartEventAck *ToNetPacketStartEventAck() const;
|
||||
virtual const NetPacketGameStart *ToNetPacketGameStart() const;
|
||||
virtual const NetPacketHandStart *ToNetPacketHandStart() const;
|
||||
virtual const NetPacketPlayersTurn *ToNetPacketPlayersTurn() const;
|
||||
@@ -681,6 +683,22 @@ protected:
|
||||
virtual void InternalCheck(const NetPacketHeader* data) const;
|
||||
};
|
||||
|
||||
class NetPacketStartEventAck : public NetPacket
|
||||
{
|
||||
public:
|
||||
|
||||
NetPacketStartEventAck();
|
||||
virtual ~NetPacketStartEventAck();
|
||||
|
||||
virtual boost::shared_ptr<NetPacket> Clone() const;
|
||||
|
||||
virtual const NetPacketStartEventAck *ToNetPacketStartEventAck() const;
|
||||
|
||||
protected:
|
||||
|
||||
virtual void InternalCheck(const NetPacketHeader* data) const;
|
||||
};
|
||||
|
||||
class NetPacketGameStart : public NetPacket
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -129,6 +129,30 @@ private:
|
||||
static boost::thread_specific_ptr<ServerGameStateInit> Ptr;
|
||||
};
|
||||
|
||||
// Wait for Ack of start event.
|
||||
class ServerGameStateWaitAck : public AbstractServerGameStateReceiving, public AbstractServerGameStateRunning, public AbstractServerGameStateTimer
|
||||
{
|
||||
public:
|
||||
// Access the state singleton.
|
||||
static ServerGameStateWaitAck &Instance();
|
||||
|
||||
virtual ~ServerGameStateWaitAck();
|
||||
|
||||
// Timeout if waiting takes too long.
|
||||
virtual int Process(ServerGameThread &server);
|
||||
|
||||
protected:
|
||||
|
||||
// Protected constructor - this is a singleton.
|
||||
ServerGameStateWaitAck();
|
||||
|
||||
virtual int InternalProcess(ServerGameThread &server, SessionWrapper session, boost::shared_ptr<NetPacket> packet);
|
||||
|
||||
private:
|
||||
|
||||
static boost::thread_specific_ptr<ServerGameStateWaitAck> Ptr;
|
||||
};
|
||||
|
||||
// State: Start server game.
|
||||
class ServerGameStateStartGame : public AbstractServerGameStateRunning
|
||||
{
|
||||
|
||||
@@ -143,6 +143,7 @@ private:
|
||||
friend class AbstractServerGameStateReceiving;
|
||||
friend class AbstractServerGameStateRunning;
|
||||
friend class ServerGameStateInit;
|
||||
friend class ServerGameStateWaitAck;
|
||||
friend class ServerGameStateStartGame;
|
||||
friend class ServerGameStateStartHand;
|
||||
friend class ServerGameStateStartRound;
|
||||
|
||||
@@ -63,6 +63,9 @@ public:
|
||||
void HandleGameRetrievePlayerInfo(SessionWrapper session, const NetPacketRetrievePlayerInfo &tmpPacket);
|
||||
void HandleGameRetrieveAvatar(SessionWrapper session, const NetPacketRetrieveAvatar &tmpPacket);
|
||||
|
||||
void AddComputerPlayer(boost::shared_ptr<PlayerData> player);
|
||||
void RemoveComputerPlayer(boost::shared_ptr<PlayerData> player);
|
||||
|
||||
void RemoveGame(unsigned id);
|
||||
|
||||
u_int32_t GetNextUniquePlayerId();
|
||||
@@ -145,6 +148,9 @@ private:
|
||||
RemoveGameList m_removeGameList;
|
||||
mutable boost::mutex m_removeGameListMutex;
|
||||
|
||||
PlayerDataMap m_computerPlayers;
|
||||
mutable boost::mutex m_computerPlayersMutex;
|
||||
|
||||
GameMap m_gameMap;
|
||||
|
||||
std::auto_ptr<ReceiverHelper> m_receiver;
|
||||
|
||||
@@ -42,6 +42,10 @@ public:
|
||||
|
||||
SOCKET GetSocket() const;
|
||||
|
||||
void SetReadyFlag();
|
||||
void ResetReadyFlag();
|
||||
bool IsReady() const;
|
||||
|
||||
const std::string &GetClientAddr() const;
|
||||
void SetClientAddr(const std::string &addr);
|
||||
|
||||
@@ -53,6 +57,7 @@ private:
|
||||
State m_state;
|
||||
std::string m_clientAddr;
|
||||
ReceiveBuffer m_receiveBuffer;
|
||||
bool m_readyFlag;
|
||||
|
||||
mutable boost::mutex m_dataMutex;
|
||||
};
|
||||
|
||||
@@ -64,6 +64,7 @@ public:
|
||||
bool IsPlayerConnected(unsigned uniqueId) const;
|
||||
|
||||
void ForEach(boost::function<void (SessionWrapper)> func);
|
||||
unsigned CountReadySessions() const;
|
||||
|
||||
void Clear();
|
||||
unsigned GetRawSessionCount();
|
||||
|
||||
@@ -61,6 +61,7 @@
|
||||
#define ERR_NET_BUF_INVALID_SIZE 117
|
||||
#define ERR_NET_INVALID_REQUEST_ID 118
|
||||
#define ERR_NET_WRONG_AVATAR_SIZE 119
|
||||
#define ERR_NET_START_TIMEOUT 120
|
||||
|
||||
#define ERR_IRC_INTERNAL 151
|
||||
#define ERR_IRC_CONNECT_FAILED 152
|
||||
|
||||
Reference in New Issue
Block a user