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:
lotodore
2007-10-07 21:23:37 +00:00
parent d16312111f
commit 0d0d8dc810
18 changed files with 452 additions and 64 deletions
+14 -1
View File
@@ -427,7 +427,7 @@ Client Request: Leave Current Game
(will be answered with a Server Notification: Removed From Game) (will be answered with a Server Notification: Removed From Game)
Client Request: Start Event Client Request/Server Request: Start Event
0 1 2 3 0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
@@ -436,10 +436,23 @@ Client Request: Start Event
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Start Flags | Reserved | | Start Flags | Reserved |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
(sent by one client, repeated to everyone by the server)
Start Flags: Start Flags:
0x01 set: Fill up with computer opponents. 0x01 set: Fill up with computer opponents.
Client Reply: Start Event ACK
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Message Type = 67 | Message Length = 8 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Reserved |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
(every client must confirm the start event)
Server Notification: Game Start Server Notification: Game Start
0 1 2 3 0 1 2 3
+35
View File
@@ -234,6 +234,41 @@ protected:
virtual int InternalProcess(ClientThread &client, boost::shared_ptr<NetPacket> packet); 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. // State: Wait for start of the next hand.
class ClientStateWaitHand : public AbstractClientStateReceiving class ClientStateWaitHand : public AbstractClientStateReceiving
{ {
+5 -1
View File
@@ -86,7 +86,7 @@ protected:
bool GetCachedPlayerInfo(unsigned id, PlayerInfo &info) const; bool GetCachedPlayerInfo(unsigned id, PlayerInfo &info) const;
void RequestPlayerInfo(unsigned id); 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 SetNewGameAdmin(unsigned id);
void AddTempAvatarData(unsigned playerId, unsigned avatarSize, AvatarFileType type); void AddTempAvatarData(unsigned playerId, unsigned avatarSize, AvatarFileType type);
@@ -134,6 +134,8 @@ protected:
bool IsSessionEstablished() const; bool IsSessionEstablished() const;
void SetSessionEstablished(bool flag); void SetSessionEstablished(bool flag);
bool IsSynchronized() const;
private: private:
NetPacketList m_outPacketList; NetPacketList m_outPacketList;
@@ -177,6 +179,8 @@ friend class ClientStateStartSession;
friend class ClientStateWaitSession; friend class ClientStateWaitSession;
friend class ClientStateWaitJoin; friend class ClientStateWaitJoin;
friend class ClientStateWaitGame; friend class ClientStateWaitGame;
friend class ClientStateSynchronizeStart;
friend class ClientStateWaitStart;
friend class ClientStateWaitHand; friend class ClientStateWaitHand;
friend class ClientStateRunHand; friend class ClientStateRunHand;
friend class ClientStateFinal; friend class ClientStateFinal;
+99 -36
View File
@@ -395,16 +395,6 @@ AbstractClientStateReceiving::Process(ClientThread &client)
NetPacketPlayerInfo::Data infoData; NetPacketPlayerInfo::Data infoData;
tmpPacket->ToNetPacketPlayerInfo()->GetData(infoData); tmpPacket->ToNetPacketPlayerInfo()->GetData(infoData);
client.SetPlayerInfo(infoData.playerId, infoData.playerInfo); 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()) else if (tmpPacket->ToNetPacketRemovedFromGame())
{ {
@@ -651,33 +641,9 @@ ClientStateWaitGame::InternalProcess(ClientThread &client, boost::shared_ptr<Net
{ {
int retVal = MSG_SOCK_INTERNAL_PENDING; int retVal = MSG_SOCK_INTERNAL_PENDING;
if (packet->ToNetPacketGameStart()) if (packet->ToNetPacketStartEvent())
{ {
// Start the network game as client. client.SetState(ClientStateSynchronizeStart::Instance());
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;
} }
else if (packet->ToNetPacketPlayerJoined()) 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 &
ClientStateWaitHand::Instance() ClientStateWaitHand::Instance()
{ {
+25 -2
View File
@@ -381,7 +381,7 @@ ClientThread::RequestPlayerInfo(unsigned id)
} }
void void
ClientThread::SetPlayerInfo(unsigned id, const PlayerInfo &info) ClientThread::SetPlayerInfo(unsigned id, const PlayerInfo &info, bool retrieveAvatar)
{ {
{ {
boost::mutex::scoped_lock lock(m_playerInfoMapMutex); 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 // Notify GUI
GetCallback().SignalNetClientPlayerChanged(id, info.playerName); GetCallback().SignalNetClientPlayerChanged(id, info.playerName);
@@ -464,7 +481,7 @@ ClientThread::CompleteTempAvatarData(unsigned playerId)
m_tempAvatarMap.erase(pos); m_tempAvatarMap.erase(pos);
// Update player info, but never re-request avatar. // Update player info, but never re-request avatar.
SetPlayerInfo(playerId, tmpPlayerInfo); SetPlayerInfo(playerId, tmpPlayerInfo, false);
} }
const ClientContext & const ClientContext &
@@ -822,3 +839,9 @@ ClientThread::SetSessionEstablished(bool flag)
m_sessionEstablished = flag; m_sessionEstablished = flag;
} }
bool
ClientThread::IsSynchronized() const
{
return (m_playerInfoRequestList.empty() && m_tempAvatarMap.empty());
}
+54 -1
View File
@@ -49,6 +49,7 @@ using namespace std;
#define NET_TYPE_KICK_PLAYER 0x0040 #define NET_TYPE_KICK_PLAYER 0x0040
#define NET_TYPE_LEAVE_CURRENT_GAME 0x0041 #define NET_TYPE_LEAVE_CURRENT_GAME 0x0041
#define NET_TYPE_START_EVENT 0x0042 #define NET_TYPE_START_EVENT 0x0042
#define NET_TYPE_START_EVENT_ACK 0x0043
#define NET_TYPE_GAME_START 0x0050 #define NET_TYPE_GAME_START 0x0050
#define NET_TYPE_HAND_START 0x0051 #define NET_TYPE_HAND_START 0x0051
#define NET_TYPE_PLAYERS_TURN 0x0052 #define NET_TYPE_PLAYERS_TURN 0x0052
@@ -297,6 +298,12 @@ struct GCC_PACKED NetPacketStartEventData
u_int16_t reserved; u_int16_t reserved;
}; };
struct GCC_PACKED NetPacketStartEventAckData
{
NetPacketHeader head;
u_int32_t reserved;
};
struct GCC_PACKED NetPacketGameStartData struct GCC_PACKED NetPacketGameStartData
{ {
NetPacketHeader head; NetPacketHeader head;
@@ -646,6 +653,9 @@ NetPacket::Create(char *data, unsigned &dataSize)
case NET_TYPE_START_EVENT: case NET_TYPE_START_EVENT:
tmpPacket = boost::shared_ptr<NetPacket>(new NetPacketStartEvent); tmpPacket = boost::shared_ptr<NetPacket>(new NetPacketStartEvent);
break; break;
case NET_TYPE_START_EVENT_ACK:
tmpPacket = boost::shared_ptr<NetPacket>(new NetPacketStartEventAck);
break;
case NET_TYPE_GAME_START: case NET_TYPE_GAME_START:
tmpPacket = boost::shared_ptr<NetPacket>(new NetPacketGameStart); tmpPacket = boost::shared_ptr<NetPacket>(new NetPacketGameStart);
break; break;
@@ -913,6 +923,12 @@ NetPacket::ToNetPacketStartEvent() const
return NULL; return NULL;
} }
const NetPacketStartEventAck *
NetPacket::ToNetPacketStartEventAck() const
{
return NULL;
}
const NetPacketGameStart * const NetPacketGameStart *
NetPacket::ToNetPacketGameStart() const NetPacket::ToNetPacketGameStart() const
{ {
@@ -2641,7 +2657,7 @@ NetPacketKickPlayer::InternalCheck(const NetPacketHeader*) const
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
NetPacketLeaveCurrentGame::NetPacketLeaveCurrentGame() 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() NetPacketGameStart::NetPacketGameStart()
: NetPacket(NET_TYPE_GAME_START, sizeof(NetPacketGameStartData), MAX_PACKET_SIZE) : NetPacket(NET_TYPE_GAME_START, sizeof(NetPacketGameStartData), MAX_PACKET_SIZE)
{ {
+87 -20
View File
@@ -46,6 +46,7 @@ using namespace std;
#define SERVER_SHOW_CARDS_DELAY_SEC 2 #define SERVER_SHOW_CARDS_DELAY_SEC 2
#define SERVER_PLAYER_TIMEOUT_ADD_DELAY_SEC 2 #define SERVER_PLAYER_TIMEOUT_ADD_DELAY_SEC 2
#define SERVER_COMPUTER_ACTION_DELAY_SEC 2 #define SERVER_COMPUTER_ACTION_DELAY_SEC 2
#define SERVER_START_GAME_TIMEOUT_SEC 10
#define SERVER_COMPUTER_PLAYER_NAME "Computer" #define SERVER_COMPUTER_PLAYER_NAME "Computer"
@@ -286,35 +287,41 @@ ServerGameStateInit::HandleNewSession(ServerGameThread &server, SessionWrapper s
int int
ServerGameStateInit::InternalProcess(ServerGameThread &server, SessionWrapper session, boost::shared_ptr<NetPacket> packet) 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()) if (packet->ToNetPacketStartEvent())
{ {
NetPacketStartEvent::Data startData; // Only admins are allowed to start the game.
packet->ToNetPacketStartEvent()->GetData(startData); if (session.playerData->GetRights() == PLAYER_RIGHTS_ADMIN)
server.ResetComputerPlayerList();
if (startData.fillUpWithCpuPlayers)
{ {
int remainingSlots = server.GetGameData().maxNumberOfPlayers - server.GetCurNumberOfPlayers(); NetPacketStartEvent::Data startData;
for (int i = 1; i <= remainingSlots; i++) packet->ToNetPacketStartEvent()->GetData(startData);
// Fill up with computer players.
server.ResetComputerPlayerList();
if (startData.fillUpWithCpuPlayers)
{ {
boost::shared_ptr<PlayerData> tmpPlayerData( int remainingSlots = server.GetGameData().maxNumberOfPlayers - server.GetCurNumberOfPlayers();
new PlayerData(server.GetLobbyThread().GetNextUniquePlayerId(), 0, PLAYER_TYPE_COMPUTER, PLAYER_RIGHTS_NORMAL)); 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; ostringstream name;
name << SERVER_COMPUTER_PLAYER_NAME << i; name << SERVER_COMPUTER_PLAYER_NAME << i;
tmpPlayerData->SetName(name.str()); tmpPlayerData->SetName(name.str());
server.AddComputerPlayer(tmpPlayerData); server.AddComputerPlayer(tmpPlayerData);
// Send "Player Joined" to other fully connected clients. // Send "Player Joined" to other fully connected clients.
server.SendToAllPlayers(CreateNetPacketPlayerJoined(*tmpPlayerData), SessionData::Game); 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(ServerGameStateWaitAck::Instance());
server.SetState(SERVER_START_GAME_STATE::Instance()); }
} }
else if (packet->ToNetPacketKickPlayer()) 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; boost::thread_specific_ptr<ServerGameStateStartGame> ServerGameStateStartGame::Ptr;
ServerGameStateStartGame & ServerGameStateStartGame &
@@ -387,6 +452,8 @@ ServerGameStateStartGame::~ServerGameStateStartGame()
int int
ServerGameStateStartGame::Process(ServerGameThread &server) ServerGameStateStartGame::Process(ServerGameThread &server)
{ {
server.InternalStartGame();
boost::shared_ptr<NetPacket> answer(new NetPacketGameStart); boost::shared_ptr<NetPacket> answer(new NetPacketGameStart);
NetPacketGameStart::Data gameStartData; NetPacketGameStart::Data gameStartData;
+16 -2
View File
@@ -152,6 +152,7 @@ ServerGameThread::Main()
GetSender().SignalTermination(); GetSender().SignalTermination();
GetSender().Join(SENDER_THREAD_TERMINATE_TIMEOUT); GetSender().Join(SENDER_THREAD_TERMINATE_TIMEOUT);
ResetComputerPlayerList();
GetLobbyThread().RemoveGame(GetId()); GetLobbyThread().RemoveGame(GetId());
} }
@@ -273,14 +274,27 @@ ServerGameThread::IsRunning() const
void void
ServerGameThread::AddComputerPlayer(boost::shared_ptr<PlayerData> player) 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 void
ServerGameThread::ResetComputerPlayerList() ServerGameThread::ResetComputerPlayerList()
{ {
boost::mutex::scoped_lock lock(m_computerPlayerListMutex); 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(); m_computerPlayerList.clear();
} }
+21
View File
@@ -176,6 +176,20 @@ ServerLobbyThread::HandleGameRetrieveAvatar(SessionWrapper session, const NetPac
HandleNetPacketRetrieveAvatar(session, tmpPacket); 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 void
ServerLobbyThread::RemoveGame(unsigned id) ServerLobbyThread::RemoveGame(unsigned id)
{ {
@@ -446,6 +460,13 @@ ServerLobbyThread::HandleNetPacketRetrievePlayerInfo(SessionWrapper session, con
boost::shared_ptr<PlayerData> tmpPlayer = m_sessionManager.GetSessionByUniquePlayerId(request.playerId).playerData; boost::shared_ptr<PlayerData> tmpPlayer = m_sessionManager.GetSessionByUniquePlayerId(request.playerId).playerData;
if (!tmpPlayer.get()) if (!tmpPlayer.get())
tmpPlayer = m_gameSessionManager.GetSessionByUniquePlayerId(request.playerId).playerData; 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()) if (tmpPlayer.get())
{ {
+22 -1
View File
@@ -20,7 +20,7 @@
#include <net/sessiondata.h> #include <net/sessiondata.h>
SessionData::SessionData(SOCKET sockfd, unsigned id) 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; 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 & const std::string &
SessionData::GetClientAddr() const SessionData::GetClientAddr() const
{ {
+18
View File
@@ -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 void
SessionManager::Clear() SessionManager::Clear()
{ {
+18
View File
@@ -68,6 +68,7 @@ class NetPacketGameAdminChanged;
class NetPacketKickPlayer; class NetPacketKickPlayer;
class NetPacketLeaveCurrentGame; class NetPacketLeaveCurrentGame;
class NetPacketStartEvent; class NetPacketStartEvent;
class NetPacketStartEventAck;
class NetPacketGameStart; class NetPacketGameStart;
class NetPacketHandStart; class NetPacketHandStart;
class NetPacketPlayersTurn; class NetPacketPlayersTurn;
@@ -125,6 +126,7 @@ public:
virtual const NetPacketKickPlayer *ToNetPacketKickPlayer() const; virtual const NetPacketKickPlayer *ToNetPacketKickPlayer() const;
virtual const NetPacketLeaveCurrentGame *ToNetPacketLeaveCurrentGame() const; virtual const NetPacketLeaveCurrentGame *ToNetPacketLeaveCurrentGame() const;
virtual const NetPacketStartEvent *ToNetPacketStartEvent() const; virtual const NetPacketStartEvent *ToNetPacketStartEvent() const;
virtual const NetPacketStartEventAck *ToNetPacketStartEventAck() const;
virtual const NetPacketGameStart *ToNetPacketGameStart() const; virtual const NetPacketGameStart *ToNetPacketGameStart() const;
virtual const NetPacketHandStart *ToNetPacketHandStart() const; virtual const NetPacketHandStart *ToNetPacketHandStart() const;
virtual const NetPacketPlayersTurn *ToNetPacketPlayersTurn() const; virtual const NetPacketPlayersTurn *ToNetPacketPlayersTurn() const;
@@ -681,6 +683,22 @@ protected:
virtual void InternalCheck(const NetPacketHeader* data) const; 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 class NetPacketGameStart : public NetPacket
{ {
public: public:
+24
View File
@@ -129,6 +129,30 @@ private:
static boost::thread_specific_ptr<ServerGameStateInit> Ptr; 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. // State: Start server game.
class ServerGameStateStartGame : public AbstractServerGameStateRunning class ServerGameStateStartGame : public AbstractServerGameStateRunning
{ {
+1
View File
@@ -143,6 +143,7 @@ private:
friend class AbstractServerGameStateReceiving; friend class AbstractServerGameStateReceiving;
friend class AbstractServerGameStateRunning; friend class AbstractServerGameStateRunning;
friend class ServerGameStateInit; friend class ServerGameStateInit;
friend class ServerGameStateWaitAck;
friend class ServerGameStateStartGame; friend class ServerGameStateStartGame;
friend class ServerGameStateStartHand; friend class ServerGameStateStartHand;
friend class ServerGameStateStartRound; friend class ServerGameStateStartRound;
+6
View File
@@ -63,6 +63,9 @@ public:
void HandleGameRetrievePlayerInfo(SessionWrapper session, const NetPacketRetrievePlayerInfo &tmpPacket); void HandleGameRetrievePlayerInfo(SessionWrapper session, const NetPacketRetrievePlayerInfo &tmpPacket);
void HandleGameRetrieveAvatar(SessionWrapper session, const NetPacketRetrieveAvatar &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); void RemoveGame(unsigned id);
u_int32_t GetNextUniquePlayerId(); u_int32_t GetNextUniquePlayerId();
@@ -145,6 +148,9 @@ private:
RemoveGameList m_removeGameList; RemoveGameList m_removeGameList;
mutable boost::mutex m_removeGameListMutex; mutable boost::mutex m_removeGameListMutex;
PlayerDataMap m_computerPlayers;
mutable boost::mutex m_computerPlayersMutex;
GameMap m_gameMap; GameMap m_gameMap;
std::auto_ptr<ReceiverHelper> m_receiver; std::auto_ptr<ReceiverHelper> m_receiver;
+5
View File
@@ -42,6 +42,10 @@ public:
SOCKET GetSocket() const; SOCKET GetSocket() const;
void SetReadyFlag();
void ResetReadyFlag();
bool IsReady() const;
const std::string &GetClientAddr() const; const std::string &GetClientAddr() const;
void SetClientAddr(const std::string &addr); void SetClientAddr(const std::string &addr);
@@ -53,6 +57,7 @@ private:
State m_state; State m_state;
std::string m_clientAddr; std::string m_clientAddr;
ReceiveBuffer m_receiveBuffer; ReceiveBuffer m_receiveBuffer;
bool m_readyFlag;
mutable boost::mutex m_dataMutex; mutable boost::mutex m_dataMutex;
}; };
+1
View File
@@ -64,6 +64,7 @@ public:
bool IsPlayerConnected(unsigned uniqueId) const; bool IsPlayerConnected(unsigned uniqueId) const;
void ForEach(boost::function<void (SessionWrapper)> func); void ForEach(boost::function<void (SessionWrapper)> func);
unsigned CountReadySessions() const;
void Clear(); void Clear();
unsigned GetRawSessionCount(); unsigned GetRawSessionCount();
+1
View File
@@ -61,6 +61,7 @@
#define ERR_NET_BUF_INVALID_SIZE 117 #define ERR_NET_BUF_INVALID_SIZE 117
#define ERR_NET_INVALID_REQUEST_ID 118 #define ERR_NET_INVALID_REQUEST_ID 118
#define ERR_NET_WRONG_AVATAR_SIZE 119 #define ERR_NET_WRONG_AVATAR_SIZE 119
#define ERR_NET_START_TIMEOUT 120
#define ERR_IRC_INTERNAL 151 #define ERR_IRC_INTERNAL 151
#define ERR_IRC_CONNECT_FAILED 152 #define ERR_IRC_CONNECT_FAILED 152