From 58c6bc7ddb2ba15de7624ede59a9fd568ed80f69 Mon Sep 17 00:00:00 2001 From: lotodore Date: Sat, 11 Aug 2007 20:24:08 +0000 Subject: [PATCH] A network game is now automatically filled up with computer players up to the configured maximum number of players. This should maybe be optional? --- src/game.cpp | 6 +- src/net/common/serverrecvstate.cpp | 147 +++++++++++++++++++---------- src/net/serverrecvstate.h | 27 +++++- src/net/serverrecvthread.h | 4 +- 4 files changed, 129 insertions(+), 55 deletions(-) diff --git a/src/game.cpp b/src/game.cpp index 03461934..21a3539d 100755 --- a/src/game.cpp +++ b/src/game.cpp @@ -194,8 +194,8 @@ boost::shared_ptr Game::getPlayerByUniqueId(unsigned id) boost::shared_ptr Game::getCurrentPlayer() { - int curPlayerNum = getCurrentHand()->getCurrentBeRo()->getPlayersTurn(); - assert(curPlayerNum < getStartQuantityPlayers()); - return getPlayerArray()[curPlayerNum]; + int curPlayerNum = getCurrentHand()->getCurrentBeRo()->getPlayersTurn(); + assert(curPlayerNum < getStartQuantityPlayers()); + return getPlayerArray()[curPlayerNum]; } diff --git a/src/net/common/serverrecvstate.cpp b/src/net/common/serverrecvstate.cpp index db8eef0a..948cee09 100644 --- a/src/net/common/serverrecvstate.cpp +++ b/src/net/common/serverrecvstate.cpp @@ -30,6 +30,8 @@ #include #include +#include + using namespace std; #define SERVER_WAIT_TIMEOUT_MSEC 50 @@ -41,10 +43,29 @@ using namespace std; #define SERVER_DEAL_ADD_ALL_IN_DELAY_SEC 2 #define SERVER_SHOW_CARDS_DELAY_SEC 2 #define SERVER_PLAYER_TIMEOUT_ADD_DELAY_SEC 2 +#define SERVER_COMPUTER_ACTION_DELAY_SEC 2 + +#define SERVER_COMPUTER_PLAYER_NAME "Computer" // Helper functions // TODO: these are hacks. +static void SendPlayerAction(ServerRecvThread &server, boost::shared_ptr player) +{ + Game &curGame = server.GetGame(); + assert(player); + + boost::shared_ptr notifyActionDone(new NetPacketPlayersActionDone); + NetPacketPlayersActionDone::Data actionDoneData; + actionDoneData.gameState = static_cast(curGame.getCurrentHand()->getActualRound()); + actionDoneData.playerId = player->getMyUniqueID(); + actionDoneData.playerAction = static_cast(player->getMyAction()); + actionDoneData.totalPlayerBet = player->getMySet(); + actionDoneData.playerMoney = player->getMyCash(); + static_cast(notifyActionDone.get())->SetData(actionDoneData); + server.SendToAllPlayers(notifyActionDone); +} + static void SendNewRoundCards(ServerRecvThread &server, Game &curGame, int state) { // TODO: no switch needed here if game states are polymorphic @@ -256,8 +277,10 @@ ServerRecvStateInit::InternalProcess(ServerRecvThread &server, SessionWrapper se } // Check whether the player name is correct. - // Paranoia check, this is also done in netpacket. - if (joinGameData.playerName.empty() || joinGameData.playerName.size() > MAX_NAME_SIZE) + // Partly, this is also done in netpacket. + // However, some disallowed names are checked only here. + if (joinGameData.playerName.empty() || joinGameData.playerName.size() > MAX_NAME_SIZE + || joinGameData.playerName.substr(0, sizeof(SERVER_COMPUTER_PLAYER_NAME) - 1) == SERVER_COMPUTER_PLAYER_NAME) { server.SessionError(session, ERR_NET_INVALID_PLAYER_NAME); return retVal; @@ -297,26 +320,12 @@ ServerRecvStateInit::InternalProcess(ServerRecvThread &server, SessionWrapper se PlayerDataList::iterator player_end = tmpPlayerList.end(); while (player_i != player_end) { - boost::shared_ptr otherPlayerJoined(new NetPacketPlayerJoined); - NetPacketPlayerJoined::Data otherPlayerJoinedData; - otherPlayerJoinedData.playerId = (*player_i)->GetUniqueId(); - otherPlayerJoinedData.playerName = (*player_i)->GetName(); - otherPlayerJoinedData.ptype = (*player_i)->GetType(); - static_cast(otherPlayerJoined.get())->SetData(otherPlayerJoinedData); - server.GetSender().Send(session.sessionData->GetSocket(), otherPlayerJoined); - + server.GetSender().Send(session.sessionData->GetSocket(), CreateNetPacketPlayerJoined(*(*player_i))); ++player_i; } // Send "Player Joined" to other fully connected clients. - boost::shared_ptr thisPlayerJoined(new NetPacketPlayerJoined); - NetPacketPlayerJoined::Data thisPlayerJoinedData; - thisPlayerJoinedData.playerId = tmpPlayerData->GetUniqueId(); - thisPlayerJoinedData.playerName = tmpPlayerData->GetName(); - thisPlayerJoinedData.ptype = tmpPlayerData->GetType(); - thisPlayerJoinedData.prights = tmpPlayerData->GetRights(); - static_cast(thisPlayerJoined.get())->SetData(thisPlayerJoinedData); - server.SendToAllPlayers(thisPlayerJoined); + server.SendToAllPlayers(CreateNetPacketPlayerJoined(*tmpPlayerData)); // Set player data for session. server.SetSessionPlayerData(session.sessionData, tmpPlayerData); @@ -326,21 +335,20 @@ ServerRecvStateInit::InternalProcess(ServerRecvThread &server, SessionWrapper se } else if (packet->ToNetPacketStartEvent()) { - boost::shared_ptr tmpPlayerData( - new PlayerData(m_curUniquePlayerId++, 0, PLAYER_TYPE_COMPUTER, PLAYER_RIGHTS_NORMAL)); - tmpPlayerData->SetName("Computer"); + int remainingSlots = server.GetGameData().maxNumberOfPlayers - server.GetCurNumberOfPlayers(); + for (int i = 1; i <= remainingSlots; i++) + { + boost::shared_ptr tmpPlayerData( + new PlayerData(m_curUniquePlayerId++, 0, PLAYER_TYPE_COMPUTER, PLAYER_RIGHTS_NORMAL)); - // Send "Player Joined" to other fully connected clients. - boost::shared_ptr thisPlayerJoined(new NetPacketPlayerJoined); - NetPacketPlayerJoined::Data thisPlayerJoinedData; - thisPlayerJoinedData.playerId = tmpPlayerData->GetUniqueId(); - thisPlayerJoinedData.playerName = tmpPlayerData->GetName(); - thisPlayerJoinedData.ptype = tmpPlayerData->GetType(); - thisPlayerJoinedData.prights = tmpPlayerData->GetRights(); - static_cast(thisPlayerJoined.get())->SetData(thisPlayerJoinedData); - server.SendToAllPlayers(thisPlayerJoined); + 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)); + server.AddComputerPlayer(tmpPlayerData); + } server.InternalStartGame(); server.SetState(SERVER_START_GAME_STATE::Instance()); @@ -360,6 +368,19 @@ ServerRecvStateInit::InternalProcess(ServerRecvThread &server, SessionWrapper se return retVal; } +boost::shared_ptr +ServerRecvStateInit::CreateNetPacketPlayerJoined(const PlayerData &playerData) +{ + boost::shared_ptr thisPlayerJoined(new NetPacketPlayerJoined); + NetPacketPlayerJoined::Data thisPlayerJoinedData; + thisPlayerJoinedData.playerId = playerData.GetUniqueId(); + thisPlayerJoinedData.playerName = playerData.GetName(); + thisPlayerJoinedData.ptype = playerData.GetType(); + thisPlayerJoinedData.prights = playerData.GetRights(); + static_cast(thisPlayerJoined.get())->SetData(thisPlayerJoinedData); + return thisPlayerJoined; +} + //----------------------------------------------------------------------------- AbstractServerRecvStateRunning::AbstractServerRecvStateRunning() @@ -761,11 +782,8 @@ ServerRecvStateWaitPlayerAction::Process(ServerRecvThread &server) // If the player is computer controlled, let the engine act. if (tmpPlayer->getMyType() == PLAYER_TYPE_COMPUTER) { - tmpPlayer->action(); - SendPlayerAction(server, tmpPlayer); - - server.SetState(ServerRecvStateStartRound::Instance()); - retVal = MSG_NET_GAME_SERVER_ACTION; + server.SetState(ServerRecvStateComputerAction::Instance()); + retVal = MSG_SOCK_INTERNAL_PENDING; } // If the player we are waiting for left, continue without him. else if (!server.IsPlayerConnected(tmpPlayer->getMyName())) @@ -837,21 +855,50 @@ ServerRecvStateWaitPlayerAction::PerformPlayerAction(ServerRecvThread &server, b SendPlayerAction(server, player); } -void -ServerRecvStateWaitPlayerAction::SendPlayerAction(ServerRecvThread &server, boost::shared_ptr player) -{ - Game &curGame = server.GetGame(); - assert(player); +//----------------------------------------------------------------------------- - boost::shared_ptr notifyActionDone(new NetPacketPlayersActionDone); - NetPacketPlayersActionDone::Data actionDoneData; - actionDoneData.gameState = static_cast(curGame.getCurrentHand()->getActualRound()); - actionDoneData.playerId = player->getMyUniqueID(); - actionDoneData.playerAction = static_cast(player->getMyAction()); - actionDoneData.totalPlayerBet = player->getMySet(); - actionDoneData.playerMoney = player->getMyCash(); - static_cast(notifyActionDone.get())->SetData(actionDoneData); - server.SendToAllPlayers(notifyActionDone); +boost::thread_specific_ptr ServerRecvStateComputerAction::Ptr; + +ServerRecvStateComputerAction & +ServerRecvStateComputerAction::Instance() +{ + if (!Ptr.get()) + Ptr.reset(new ServerRecvStateComputerAction); + + return *Ptr; +} + +ServerRecvStateComputerAction::ServerRecvStateComputerAction() +{ +} + +ServerRecvStateComputerAction::~ServerRecvStateComputerAction() +{ +} + +int +ServerRecvStateComputerAction::Process(ServerRecvThread &server) +{ + int retVal = AbstractServerRecvStateReceiving::Process(server); + + if (GetTimer().elapsed().total_seconds() >= SERVER_COMPUTER_ACTION_DELAY_SEC) + { + boost::shared_ptr tmpPlayer = server.GetGame().getCurrentPlayer(); + + tmpPlayer->action(); + SendPlayerAction(server, tmpPlayer); + + server.SetState(ServerRecvStateStartRound::Instance()); + retVal = MSG_NET_GAME_SERVER_ACTION; + } + + return retVal; +} + +int +ServerRecvStateComputerAction::InternalProcess(ServerRecvThread &server, SessionWrapper session, boost::shared_ptr packet) +{ + return MSG_SOCK_INTERNAL_PENDING; } //----------------------------------------------------------------------------- diff --git a/src/net/serverrecvstate.h b/src/net/serverrecvstate.h index e940e550..cc4dda80 100644 --- a/src/net/serverrecvstate.h +++ b/src/net/serverrecvstate.h @@ -120,6 +120,8 @@ protected: virtual int InternalProcess(ServerRecvThread &server, SessionWrapper session, boost::shared_ptr packet); + static boost::shared_ptr CreateNetPacketPlayerJoined(const PlayerData &playerData); + private: u_int16_t m_curUniquePlayerId; @@ -220,13 +222,36 @@ protected: virtual int InternalProcess(ServerRecvThread &server, SessionWrapper session, boost::shared_ptr packet); static void PerformPlayerAction(ServerRecvThread &server, boost::shared_ptr player, PlayerAction action, int bet); - static void SendPlayerAction(ServerRecvThread &server, boost::shared_ptr player); private: static boost::thread_specific_ptr Ptr; }; +// State: Delay and computer action +class ServerRecvStateComputerAction : public AbstractServerRecvStateReceiving, public AbstractServerRecvStateRunning, public AbstractServerRecvStateTimer +{ +public: + // Access the state singleton. + static ServerRecvStateComputerAction &Instance(); + + virtual ~ServerRecvStateComputerAction(); + + // Overwrite default processing + virtual int Process(ServerRecvThread &server); + +protected: + + // Protected constructor - this is a singleton. + ServerRecvStateComputerAction(); + + virtual int InternalProcess(ServerRecvThread &server, SessionWrapper session, boost::shared_ptr packet); + +private: + + static boost::thread_specific_ptr Ptr; +}; + // State: Delay after dealing cards class ServerRecvStateDealCardsDelay : public AbstractServerRecvStateReceiving, public AbstractServerRecvStateRunning, public AbstractServerRecvStateTimer { diff --git a/src/net/serverrecvthread.h b/src/net/serverrecvthread.h index 4801d84b..82565237 100644 --- a/src/net/serverrecvthread.h +++ b/src/net/serverrecvthread.h @@ -72,6 +72,8 @@ public: void SendToAllPlayers(boost::shared_ptr packet); void SendToAllButOnePlayers(boost::shared_ptr packet, SOCKET except); + Game &GetGame(); + protected: struct Notification @@ -128,7 +130,6 @@ protected: SenderThread &GetSender(); ReceiverHelper &GetReceiver(); - Game &GetGame(); const GameData &GetGameData() const; const StartData &GetStartData() const; void SetStartData(const StartData &startData); @@ -175,6 +176,7 @@ friend class ServerRecvStateStartGame; friend class ServerRecvStateStartHand; friend class ServerRecvStateStartRound; friend class ServerRecvStateWaitPlayerAction; +friend class ServerRecvStateComputerAction; friend class ServerRecvStateShowCardsDelay; friend class ServerRecvStateDealCardsDelay; friend class ServerRecvStateNextHandDelay;