diff --git a/source/lib/sysdep/sysdep.cpp b/source/lib/sysdep/sysdep.cpp index 7d67fb0069..443ffadbdd 100755 --- a/source/lib/sysdep/sysdep.cpp +++ b/source/lib/sysdep/sysdep.cpp @@ -75,7 +75,7 @@ void debug_microlog(const wchar_t *fmt, ...) wchar_t buffer[512]; va_start(argp, fmt); - vswprintf(buffer, sizeof(buffer), fmt, argp); + vswprintf(buffer, sizeof(buffer)-2, fmt, argp); va_end(argp); wcscat(buffer, L"\r\n"); diff --git a/source/main.cpp b/source/main.cpp index 3e273a6ac1..10a4d25a33 100755 --- a/source/main.cpp +++ b/source/main.cpp @@ -1040,7 +1040,7 @@ static void Frame() in_get_events(); g_SessionManager.Poll(); - if (g_Game) + if (g_Game && g_Game->IsGameStarted()) { g_Game->Update(TimeSinceLastFrame); diff --git a/source/ps/Game.cpp b/source/ps/Game.cpp index ab41404539..30ddcd01aa 100755 --- a/source/ps/Game.cpp +++ b/source/ps/Game.cpp @@ -132,7 +132,8 @@ CGame::CGame(): m_World(this), m_Simulation(this), m_GameView(this), - m_pLocalPlayer(NULL) + m_pLocalPlayer(NULL), + m_GameStarted(false) { debug_out("CGame::CGame(): Game object CREATED\n"); } @@ -166,6 +167,8 @@ PSRETURN CGame::StartGame(CGameAttributes *pAttribs) m_GameView.Initialize(pAttribs); m_World.Initialize(pAttribs); m_Simulation.Initialize(pAttribs); + + m_GameStarted=true; } catch (PSERROR_Game e) { diff --git a/source/ps/Game.h b/source/ps/Game.h index 0cbbe4e2e8..c5685ea527 100755 --- a/source/ps/Game.h +++ b/source/ps/Game.h @@ -47,6 +47,8 @@ class CGame std::vector m_Players; CPlayer *m_pLocalPlayer; uint m_NumPlayers; + + bool m_GameStarted; public: CGame(); @@ -71,6 +73,11 @@ public: inline uint GetNumPlayers() { return m_NumPlayers; } + inline bool IsGameStarted() + { + return m_GameStarted; + } + inline CWorld *GetWorld() { return &m_World; } inline CGameView *GetView() diff --git a/source/ps/GameRecord.h b/source/ps/GameRecord.h index 482fabcbdd..0a0102bc96 100755 --- a/source/ps/GameRecord.h +++ b/source/ps/GameRecord.h @@ -17,6 +17,10 @@ public: bool IsRecording(); + /* + NOTE: The message will not be deleted by this method. Ownership remains + the caller's. + */ void WriteMessage(CNetMessage *pMsg); CTurnManager *GetPlaybackTurnManager(); diff --git a/source/ps/Network/AllNetMessages.h b/source/ps/Network/AllNetMessages.h index a170600e4d..524c186d12 100755 --- a/source/ps/Network/AllNetMessages.h +++ b/source/ps/Network/AllNetMessages.h @@ -172,6 +172,19 @@ START_NMT_CLASS_(GotoCommand) NMT_FIELD_INT(m_TargetY, u32, 2) END_NMT_CLASS() +/* +#define NMT_FIELD_MAPPOS(_nm) NMT_FIELD_INT(_nm##X, u32, 2) NMT_FIELD_INT(_nm##Y, u32, 2) + +START_NMT_CLASS_(SetWaypoint) + NMT_FIELD(HEntity, m_Entity) + NMT_FIELD_MAPPOS(m_Target) +END_NMT_CLASS() + +START_NMT_CLASS_(AddWaypoint) + NMT_FIELD(HEntity, m_Entity) + NMT_FIELD_MAPPOS(m_Target) +END_NMY_CLASS()*/ + // #include "../EventTypes.h" END_NMTS() diff --git a/source/ps/Network/Client.cpp b/source/ps/Network/Client.cpp index 1f17d4ff61..1b0ab1ed64 100755 --- a/source/ps/Network/Client.cpp +++ b/source/ps/Network/Client.cpp @@ -24,7 +24,7 @@ CNetClient::CNetClient(CGame *pGame, CGameAttributes *pGameAttribs): bool CNetClient::Handler(CNetMessage *pMsg, CNetSession *pSession) { CNetClient *pClient=(CNetClient *)pSession; - printf("CNetClient::Handler(): %s.\n", pMsg->GetString().c_str()); + LOG(NORMAL, LOG_CAT_NET, "CNetClient::Handler(): %s.", pMsg->GetString().c_str()); switch (pMsg->GetType()) { case XXX: @@ -43,7 +43,7 @@ bool CNetClient::Handler(CNetMessage *pMsg, CNetSession *pSession) bool CNetClient::ConnectHandler(CNetMessage *pMsg, CNetSession *pSession) { CNetClient *pClient=(CNetClient *)pSession; - LOG(NORMAL, "CNetClient::ConnectHandler(): %s.\n", pMsg->GetString().c_str()); + LOG(NORMAL, LOG_CAT_NET, "CNetClient::ConnectHandler(): %s.", pMsg->GetString().c_str()); switch (pMsg->GetType()) { case NMT_CONNECT_COMPLETE: @@ -52,7 +52,7 @@ bool CNetClient::ConnectHandler(CNetMessage *pMsg, CNetSession *pSession) case NMT_ERROR: { CNetErrorMessage *msg=(CNetErrorMessage *)pMsg; - LOG(ERROR, "CNetClient::ConnectHandler(): Connect Failed: %s\n", msg->m_Error); + LOG(ERROR, LOG_CAT_NET, "CNetClient::ConnectHandler(): Connect Failed: %s", msg->m_Error); break; } default: @@ -64,7 +64,7 @@ bool CNetClient::ConnectHandler(CNetMessage *pMsg, CNetSession *pSession) bool CNetClient::HandshakeHandler(CNetMessage *pMsg, CNetSession *pSession) { CNetClient *pClient=(CNetClient *)pSession; - LOG(NORMAL, "CNetClient::HandshakeHandler(): %s.\n", pMsg->GetString().c_str()); + LOG(NORMAL, LOG_CAT_NET, "CNetClient::HandshakeHandler(): %s.", pMsg->GetString().c_str()); switch (pMsg->GetType()) { case NMT_ServerHandshake: @@ -96,7 +96,7 @@ bool CNetClient::HandshakeHandler(CNetMessage *pMsg, CNetSession *pSession) bool CNetClient::AuthenticateHandler(CNetMessage *pMsg, CNetSession *pSession) { CNetClient *pClient=(CNetClient *)pSession; - printf("CNetClient::AuthenticateHandler(): %s.\n", pMsg->GetString().c_str()); + LOG(NORMAL, LOG_CAT_NET, "CNetClient::AuthenticateHandler(): %s.", pMsg->GetString().c_str()); switch (pMsg->GetType()) { case NMT_Result: @@ -107,8 +107,10 @@ bool CNetClient::AuthenticateHandler(CNetMessage *pMsg, CNetSession *pSession) LOG(ERROR, LOG_CAT_NET, "CNetClient::AuthenticateHandler(): Authentication failed: %ls", msg->m_Message.c_str()); } else + { LOG(NORMAL, LOG_CAT_NET, "CNetClient::AuthenticateHandler(): Authenticated!"); - pClient->m_pMessageHandler=PreGameHandler; + pClient->m_pMessageHandler=PreGameHandler; + } break; } default: @@ -120,7 +122,7 @@ bool CNetClient::AuthenticateHandler(CNetMessage *pMsg, CNetSession *pSession) bool CNetClient::PreGameHandler(CNetMessage *pMsg, CNetSession *pSession) { CNetClient *pClient=(CNetClient *)pSession; - printf("CNetClient::PreGameHandler(): %s.\n", pMsg->GetString().c_str()); + LOG(NORMAL, LOG_CAT_NET, "CNetClient::PreGameHandler(): %s.", pMsg->GetString().c_str()); if (ChatHandler(pMsg, pSession)) return true; @@ -151,10 +153,46 @@ bool CNetClient::PreGameHandler(CNetMessage *pMsg, CNetSession *pSession) UNHANDLED(pMsg); } +bool CNetClient::InGameHandler(CNetMessage *pMsg, CNetSession *pSession) +{ + CNetClient *pClient=(CNetClient *)pSession; + ENetMessageType msgType=pMsg->GetType(); + + if (msgType != NMT_EndCommandBatch) + LOG(NORMAL, LOG_CAT_NET, "CNetClient::InGameHandler(): %s.", pMsg->GetString().c_str()); + + if (msgType >= NMT_COMMAND_FIRST && msgType <= NMT_COMMAND_LAST) + { + pClient->QueueMessage(1, pMsg); + TAKEN(pMsg); + } + + switch (msgType) + { + case NMT_EndCommandBatch: + // FIXME When the command batch has ended, we should start accepting + // commands for the next turn. This will be accomplished by calling + // NewTurn. *BUT* we shouldn't prematurely proceed game simulation + // since this will produce jerky playback (everything expects a sim + // turn to have a certain duration). + + // We should make sure that any commands received after this message + // are queued in the next batch (#2 instead of #1). If we're already + // putting everything new in batch 2 - we should fast-forward a bit to + // catch up with the server. + + HANDLED(pMsg); + } + + if (ChatHandler(pMsg, pSession)) + return true; + + UNHANDLED(pMsg); +} + bool CNetClient::ChatHandler(CNetMessage *pMsg, CNetSession *pSession) { CNetClient *pClient=(CNetClient *)pSession; - printf("CNetClient::ChatHandler(): %s.\n", pMsg->GetString().c_str()); switch (pMsg->GetType()) { case NMT_ChatMessage: @@ -169,7 +207,7 @@ bool CNetClient::ChatHandler(CNetMessage *pMsg, CNetSession *pSession) void CNetClient::StartGame() { - m_pGame->GetSimulation()->SetTurnManager(this); + m_pMessageHandler=InGameHandler; m_pGame->StartGame(m_pGameAttributes); } @@ -178,11 +216,11 @@ void CNetClient::NewTurn() RotateBatches(); ClearBatch(2); - //Push(new CEndCommandBatch()); + Push(new CEndCommandBatch()); } void CNetClient::QueueLocalCommand(CNetMessage *pMsg) { - // We don't save these locally, since they will be bounced by the server anyway + // Don't save these locally, since they'll be bounced by the server anyway Push(pMsg); } diff --git a/source/ps/Network/Client.h b/source/ps/Network/Client.h index 21e3538ab8..6dc24f037f 100755 --- a/source/ps/Network/Client.h +++ b/source/ps/Network/Client.h @@ -36,6 +36,7 @@ public: static MessageHandler AuthenticateHandler; static MessageHandler PreGameHandler; static MessageHandler ChatHandler; + static MessageHandler InGameHandler; }; extern CNetClient *g_NetClient; diff --git a/source/ps/Network/NMTCreator.h b/source/ps/Network/NMTCreator.h index b08b0f5129..aff58d3fb8 100755 --- a/source/ps/Network/NMTCreator.h +++ b/source/ps/Network/NMTCreator.h @@ -21,7 +21,7 @@ #ifdef NMT_CREATE_HEADER_NAME #ifndef ARRAY_STRUCT_PREFIX -#define ARRAY_STRUCT_PREFIX S_ +#define ARRAY_STRUCT_PREFIX(_nm) S_##_nm #endif #define CREATING_NMT @@ -80,9 +80,9 @@ struct _nm: public CNetMessage \ _tp _nm; #define NMT_START_ARRAY(_nm) \ - struct ARRAY_STRUCT_PREFIX ## _nm; \ - std::vector _nm; \ - struct ARRAY_STRUCT_PREFIX ## _nm { + struct ARRAY_STRUCT_PREFIX(_nm); \ + std::vector _nm; \ + struct ARRAY_STRUCT_PREFIX(_nm) { #define NMT_END_ARRAY() \ }; @@ -107,10 +107,10 @@ uint _nm::GetSerializedLength() const \ const _nm *thiz=this; #define NMT_START_ARRAY(_nm) \ - std::vector ::const_iterator it=_nm.begin(); \ + std::vector ::const_iterator it=_nm.begin(); \ while (it != _nm.end()) \ { \ - const ARRAY_STRUCT_PREFIX##_nm *thiz=&*it; + const ARRAY_STRUCT_PREFIX(_nm) *thiz=&*it; #define NMT_END_ARRAY() \ ++it; \ @@ -145,10 +145,10 @@ u8 *_nm::Serialize(u8 *buffer) const \ const _nm *thiz=this; #define NMT_START_ARRAY(_nm) \ - std::vector ::const_iterator it=_nm.begin(); \ + std::vector ::const_iterator it=_nm.begin(); \ while (it != _nm.end()) \ { \ - const ARRAY_STRUCT_PREFIX##_nm *thiz=&*it; + const ARRAY_STRUCT_PREFIX(_nm) *thiz=&*it; #define NMT_END_ARRAY() \ ++it; \ @@ -195,7 +195,7 @@ const u8 *_nm::Deserialize(const u8 *pos, const u8 *end) \ #define NMT_START_ARRAY(_nm) \ while (pos < end) \ { \ - ARRAY_STRUCT_PREFIX##_nm *thiz=&*_nm.insert(_nm.end(), ARRAY_STRUCT_PREFIX##_nm()); + ARRAY_STRUCT_PREFIX(_nm) *thiz=&*_nm.insert(_nm.end(), ARRAY_STRUCT_PREFIX(_nm)()); #define NMT_END_ARRAY() \ } @@ -256,11 +256,11 @@ CStr _nm::GetString() const \ #define NMT_START_ARRAY(_nm) \ ret+=#_nm _T(": { "); \ - std::vector < ARRAY_STRUCT_PREFIX ## _nm >::const_iterator it=_nm.begin(); \ + std::vector < ARRAY_STRUCT_PREFIX(_nm) >::const_iterator it=_nm.begin(); \ while (it != _nm.end()) \ { \ ret+=_T(" { "); \ - const ARRAY_STRUCT_PREFIX##_nm *thiz=&*it; + const ARRAY_STRUCT_PREFIX(_nm) *thiz=&*it; #define NMT_END_ARRAY() \ ++it; \ diff --git a/source/ps/Network/NetMessage.cpp b/source/ps/Network/NetMessage.cpp index 7aec3c45b6..2e82441629 100755 --- a/source/ps/Network/NetMessage.cpp +++ b/source/ps/Network/NetMessage.cpp @@ -17,6 +17,11 @@ typedef std::map MessageDeserializerMap; MessageDeserializerMap g_DeserializerMap; +CNetMessage::~CNetMessage() +{ + m_Type=NMT_NONE; +} + u8 *CNetMessage::Serialize(u8 *pos) const { return pos; } @@ -26,14 +31,20 @@ uint CNetMessage::GetSerializedLength() const } CStr CNetMessage::GetString() const -{ return CStr(); } +{ + if (m_Type==NMT_NONE) + return "NMT_NONE { Invalid Message }"; + else + return CStr("Unknown Message ")+CStr(m_Type); +} const u8 *CNetMessage::Deserialize(const u8 *pos, const u8 *end) { return pos; } CNetMessage *CNetMessage::Copy() const { - return NULL; + LOG(ERROR, LOG_CAT_NET, "CNetMessage::Copy(): Attempting to copy non-copyable message!"); + return new CNetMessage(NMT_NONE); } CNetMessage *CNetMessage::DeserializeMessage(ENetMessageType type, u8 *buffer, uint length) diff --git a/source/ps/Network/NetMessage.h b/source/ps/Network/NetMessage.h index 204fd550e0..a080787ee0 100755 --- a/source/ps/Network/NetMessage.h +++ b/source/ps/Network/NetMessage.h @@ -23,6 +23,8 @@ protected: {} public: + virtual ~CNetMessage(); + inline ENetMessageType GetType() const { return m_Type; } diff --git a/source/ps/Network/Network.cpp b/source/ps/Network/Network.cpp index 7bb997f2cf..3fbd112182 100755 --- a/source/ps/Network/Network.cpp +++ b/source/ps/Network/Network.cpp @@ -102,7 +102,7 @@ CStr CCloseRequestMessage::GetString() const void CMessageSocket::Push(CNetMessage *msg) { - printf("CMessageSocket::Push(): %s", msg->GetString().c_str()); + printf("CMessageSocket::Push(): %s\n", msg->GetString().c_str()); m_OutQ.Lock(); m_OutQ.push_back(msg); diff --git a/source/ps/Network/Network.h b/source/ps/Network/Network.h index d75d40c53b..181c0f3b07 100755 --- a/source/ps/Network/Network.h +++ b/source/ps/Network/Network.h @@ -62,6 +62,8 @@ MORE INFO // Typedefs and Macros //------------------------------------------------- +#define LOG_CAT_NET "net" + typedef CLocker > CLockedMessageDeque; //------------------------------------------------- diff --git a/source/ps/Network/Server.cpp b/source/ps/Network/Server.cpp index 894c39081d..59e665534d 100755 --- a/source/ps/Network/Server.cpp +++ b/source/ps/Network/Server.cpp @@ -34,22 +34,15 @@ CNetServerSession *CNetServer::CreateSession(CSocketInternal *pInt) void CNetServer::OnAccept(const CSocketAddress &addr) { - LOG(NORMAL, "CNetServer::OnAccept(): Accepted connection from %s port %d\n", addr.GetString().c_str(), addr.GetPort()); + LOG(NORMAL, LOG_CAT_NET, "CNetServer::OnAccept(): Accepted connection from %s port %d", addr.GetString().c_str(), addr.GetPort()); CSocketInternal *pInt=Accept(); CNetServerSession *pSession=CreateSession(pInt); - { - CScopeLock scopeLock(m_Mutex); - m_Sessions.push_back(pSession); - } } CNetServerSession::~CNetServerSession() { - CScopeLock scopeLock(m_pServer->m_Mutex); - vector::iterator it=find(m_pServer->m_Sessions.begin(), m_pServer->m_Sessions.end(), this); - if (it != m_pServer->m_Sessions.end()) - m_pServer->m_Sessions.erase(it); + m_pServer->RemoveSession(this); } void CNetServerSession::StartGame() @@ -62,16 +55,54 @@ void CNetServerSession::StartGame() #define HANDLED(_pMsg) delete _pMsg; return true; #define TAKEN(_pMsg) return true; +bool CNetServerSession::BaseHandler(CNetMessage *pMsg, CNetSession *pNetSession) +{ + CNetServerSession *pSession=(CNetServerSession *)pNetSession; + switch (pMsg->GetType()) + { + case NMT_ERROR: + { + CNetErrorMessage *msg=(CNetErrorMessage *)pMsg; + LOG(WARNING, LOG_CAT_NET, "CNetServerSession::BaseHandler(): NMT_ERROR: %s", msg->GetString().c_str()); + if (msg->m_State == SS_UNCONNECTED) + { + /* We were disconnected... What happens with our session? + * + * Note that deleting a session also removes it from m_Sessions + * in CNetServer. If the session is an observer it is also + * removed from m_Observers. + * + * Sessions that are observers or chatters should perhaps + * generate an exit message that is sent to all other sessions. + * + * Player sessions require more care. In Pre-Game, each player + * session has an associated CPlayer object and player session + * slot requiring special care when deleting. + */ + if (!pSession->m_pPlayer) + { + delete pSession; + } + else + { + LOG(ERROR, LOG_CAT_NET, "CNetServerSession::BaseHandler(): Player disconnection not implemented!!"); + } + } + HANDLED(pMsg); + } + } + UNHANDLED(pMsg); +} + bool CNetServerSession::HandshakeHandler(CNetMessage *pMsg, CNetSession *pNetSession) { CNetServerSession *pSession=(CNetServerSession *)pNetSession; - printf("CNetServerSession::HandshakeHandler(): %s.\n", pMsg->GetString().c_str()); + LOG(NORMAL, LOG_CAT_NET, "CNetServerSession::HandshakeHandler(): %s.", pMsg->GetString().c_str()); switch (pMsg->GetType()) { case NMT_ClientHandshake: { CClientHandshake * /*SmartPointer*/ msg=(CClientHandshake *)pMsg/*.GetRawPointer()*/; - printf("ClientHandshake: %s.\n", pMsg->GetString().c_str()); if (msg->m_ProtocolVersion != PS_PROTOCOL_VERSION) do {} while(0); // This will never happen to us here, but anyways ;-) @@ -86,26 +117,26 @@ bool CNetServerSession::HandshakeHandler(CNetMessage *pMsg, CNetSession *pNetSes HANDLED(pMsg); } - default: - UNHANDLED(pMsg); } + return BaseHandler(pMsg, pNetSession); } bool CNetServerSession::AuthenticateHandler(CNetMessage *pMsg, CNetSession *pNetSession) { CNetServerSession *pSession=(CNetServerSession *)pNetSession; CNetServer *pServer=pSession->m_pServer; - printf("CNetServerSession::AuthenticateHandler(): %s.\n", pMsg->GetString().c_str()); + LOG(NORMAL, LOG_CAT_NET, "CNetServerSession::AuthenticateHandler(): %s.", pMsg->GetString().c_str()); if (pMsg->GetType() == NMT_Authenticate) { CAuthenticate *msg=(CAuthenticate *)pMsg; - LOG(NORMAL, LOG_CAT_NET, "CNetServerSession::AuthenticateHandler(): Client Authentication Received: username: %ls password: \"%hs\"", msg->m_Name.c_str(), msg->m_Password.c_str()); if (msg->m_Password == pSession->m_pServer->m_Password) { LOG(NORMAL, LOG_CAT_NET, "CNetServerSession::AuthenticateHandler(): Login Successful"); pSession->m_Name=msg->m_Name; + pSession->m_pServer->m_Sessions.push_back(pSession); + CResult *msg=new CResult(); msg->m_Code=NRC_OK; msg->m_Message=L"Logged in"; @@ -137,13 +168,13 @@ bool CNetServerSession::AuthenticateHandler(CNetMessage *pMsg, CNetSession *pNet HANDLED(pMsg); } - UNHANDLED(pMsg); + return BaseHandler(pMsg, pNetSession); } bool CNetServerSession::PreGameHandler(CNetMessage *pMsg, CNetSession *pNetSession) { CNetServerSession *pSession=(CNetServerSession *)pNetSession; - printf("CNetServerSession::PreGameHandler(): %s.\n", pMsg->GetString().c_str()); + LOG(NORMAL, LOG_CAT_NET, "CNetServerSession::PreGameHandler(): %s.", pMsg->GetString().c_str()); return ChatHandler(pMsg, pNetSession); } @@ -173,13 +204,18 @@ bool CNetServerSession::ChatHandler(CNetMessage *pMsg, CNetSession *pNetSession) TAKEN(pMsg); } - UNHANDLED(pMsg); + + return BaseHandler(pMsg, pNetSession); } bool CNetServerSession::InGameHandler(CNetMessage *pMsg, CNetSession *pNetSession) { CNetServerSession *pSession=(CNetServerSession *)pNetSession; - printf("CNetServerSession::InGameHandler(): %s.\n", pMsg->GetString().c_str()); + if (pMsg->GetType() != NMT_EndCommandBatch) + LOG(NORMAL, LOG_CAT_NET, "CNetServerSession::InGameHandler(): %s.", pMsg->GetString().c_str()); + + if (BaseHandler(pMsg, pNetSession)) + return true; if (ChatHandler(pMsg, pNetSession)) return true; @@ -192,6 +228,10 @@ bool CNetServerSession::InGameHandler(CNetMessage *pMsg, CNetSession *pNetSessio pSession->m_pServer->QueueIncomingCommand(pMsg); TAKEN(pMsg); + case NMT_EndCommandBatch: + // TODO Update client timing information here. + HANDLED(pMsg); + default: UNHANDLED(pMsg); } @@ -213,6 +253,8 @@ CNetServer::CNetServer(CNetServerAttributes *pServerAttribs, CGame *pGame, CGame m_pGameAttributes->SetUpdateCallback(AttributeUpdate, this); m_ServerPlayerName=m_pServerAttributes->GetValue("serverPlayerName"); m_NumPlayers=m_pGameAttributes->GetValue("numPlayers").ToUInt(); + + m_pGame->GetSimulation()->SetTurnManager(this); } PS_RESULT CNetServer::Bind(const CSocketAddress &address) @@ -225,8 +267,6 @@ PS_RESULT CNetServer::Bind(const CSocketAddress &address) bool CNetServer::AddNewPlayer(CNetServerSession *pSession) { - CScopeLock scopeLock(m_Mutex); - CAttributeMap::MapType &attribs=m_pGameAttributes->GetInternalValueMap(); CAttributeMap::MapType::iterator it=attribs.begin(); @@ -249,7 +289,7 @@ bool CNetServer::AddNewPlayer(CNetServerSession *pSession) pMsg->m_Players.resize(1); pMsg->m_Players[0].m_PlayerID=(u32)m_PlayerSessions.size(); pMsg->m_Players[0].m_Nick=pSession->GetName(); - BroadcastUnsafe(pMsg); + Broadcast(pMsg); pMsg=new CPlayerConnect(); for (uint i=0;i::iterator it=find(m_Sessions.begin(), m_Sessions.end(), pSession); + if (it != m_Sessions.end()) + m_Sessions.erase(it); + + // TODO Correct handling of player and observers +} + // Unfortunately, the message queueing model is made so that each message has // to be copied once for each socket its sent over, messages are deleted when -// sent by CMessageSocket +// sent by CMessageSocket. We could ref-count, but that requires a lot of +// thread safety stuff => hard work void CNetServer::Broadcast(CNetMessage *pMsg) -{ - CScopeLock scopeLock(m_Mutex); - - BroadcastUnsafe(pMsg); -} - -void CNetServer::BroadcastUnsafe(CNetMessage *pMsg) { if (m_Sessions.empty()) return; @@ -344,11 +386,14 @@ void CNetServer::GetDefaultListenAddress(CSocketAddress &address) void CNetServer::NewTurn() { + RecordBatch(2); + RotateBatches(); ClearBatch(2); IterateBatch(1, CSimulation::GetMessageMask, m_pGame->GetSimulation()); SendBatch(1); + //SendBatchToList(1, m_Observers); } void CNetServer::QueueLocalCommand(CNetMessage *pMsg) @@ -358,6 +403,6 @@ void CNetServer::QueueLocalCommand(CNetMessage *pMsg) void CNetServer::QueueIncomingCommand(CNetMessage *pMsg) { - CScopeLock scopeLock(m_Mutex); + LOG(NORMAL, LOG_CAT_NET, "CNetServer::QueueIncomingCommand(): %s.", pMsg->GetString().c_str()); QueueMessage(2, pMsg); } diff --git a/source/ps/Network/Server.h b/source/ps/Network/Server.h index 26415926ce..bf61f2e242 100755 --- a/source/ps/Network/Server.h +++ b/source/ps/Network/Server.h @@ -29,6 +29,7 @@ public: // all connected clients. void StartGame(); + static MessageHandler BaseHandler; static MessageHandler HandshakeHandler; static MessageHandler AuthenticateHandler; static MessageHandler PreGameHandler; @@ -39,9 +40,16 @@ public: enum ENetServerState { + // We haven't opened the port yet, we're just setting some stuff up. + // This is probably equivalent to the first "Start Network Game" screen NSS_PreBind, + // The server is open and accepting connections. This is the screen where + // rules are set up by the operator and where players join and select civs + // and stuff. NSS_PreGame, NSS_InGame, + // The game is over and someone has won. Players might linger to chat or + // download the replay log. NSS_PostGame }; @@ -54,17 +62,28 @@ public: class CNetServer: protected CServerSocket, protected CTurnManager { private: + /* + Every connected session is in m_Sessions as soon as the Handshake and + Authentication stages are complete. + */ std::vector m_Sessions; - + /* + All sessions currently associated with a player. Subset of m_Sessions. + */ std::vector m_PlayerSessions; - uint m_NumPlayers; - - CMutex m_Mutex; - ENetServerState m_ServerState; - + /* + All sessions that have observer status (observer as in watcher - simple + chatters don't have an entry here, only in m_Sessions). + Sessions are added here after they have successfully requested observer + status. + */ std::vector m_Observers; + + uint m_NumPlayers; uint m_MaxObservers; + ENetServerState m_ServerState; + CGame *m_pGame; CGameAttributes *m_pGameAttributes; CNetServerAttributes *m_pServerAttributes; @@ -80,17 +99,17 @@ protected: // Try to add the session as a newly connected player. If that is not // possible, make the session an observer. // - // Synchronized, safe to call from any thread - // // Returns: // true. The session has been allocated a player slot // false: All player slots busy, the session should be made an observer bool AddNewPlayer(CNetServerSession *pSession); + // Remove the session from all the relevant lists. + // NOTE: Currently unsafe to call for observers or players + void RemoveSession(CNetServerSession *pSession); + // Queue a command coming in from the wire. The command has been validated // by the caller. - // - // Synchronized, safe from any thread void QueueIncomingCommand(CNetMessage *pMsg); // OVERRIDES FROM CServerSocket @@ -106,15 +125,11 @@ protected: // Ask the server if the session is allowed to start observing. // - // Synchronized, safe to call from any thread - // // Returns: // true if the session should be made an observer // false otherwise virtual bool AllowObserver(CNetServerSession *pSession); - void BroadcastUnsafe(CNetMessage *); - public: CNetServer(CNetServerAttributes *pServerAttribs, CGame *pGame, CGameAttributes *pGameAttribs); diff --git a/source/ps/Network/SessionManager.cpp b/source/ps/Network/SessionManager.cpp index 8f2ccb7dc0..32e1f8562d 100755 --- a/source/ps/Network/SessionManager.cpp +++ b/source/ps/Network/SessionManager.cpp @@ -40,7 +40,7 @@ void CSessionManager::Poll() m_Mutex.Unlock(); if (!pSess->HandleMessage(pMsg)) { - LOG(WARNING, "CSessionManager::Poll(): Unhandled message %s.\n", pMsg->GetString().c_str()); + LOG(WARNING, LOG_CAT_NET, "CSessionManager::Poll(): Unhandled message %s.", pMsg->GetString().c_str()); delete pMsg; } m_Mutex.Lock(); diff --git a/source/scripting/ScriptGlue.cpp b/source/scripting/ScriptGlue.cpp index 7579290fb4..f0efaf2173 100755 --- a/source/scripting/ScriptGlue.cpp +++ b/source/scripting/ScriptGlue.cpp @@ -323,6 +323,11 @@ JSBool joinGame(JSContext* cx, JSObject* UNUSEDPARAM(globalObject), unsigned int connectPort=g_ScriptingHost.ValueToInt(argv[2]); } + if (g_Game) + { + return JS_FALSE; + } + g_Game=new CGame(); g_NetClient=new CNetClient(g_Game, &g_GameAttributes); g_NetClient->SetLoginInfo(username, password); diff --git a/source/simulation/EntityHandles.cpp b/source/simulation/EntityHandles.cpp index 7f344363f2..6869d096a3 100755 --- a/source/simulation/EntityHandles.cpp +++ b/source/simulation/EntityHandles.cpp @@ -91,7 +91,7 @@ uint HEntity::GetSerializedLength() const u8 *HEntity::Serialize(u8 *buffer) const { Serialize_int_2(buffer, m_handle); - return buffer+2; + return buffer; } const u8 *HEntity::Deserialize(const u8 *buffer, const u8 *end) @@ -100,7 +100,7 @@ const u8 *HEntity::Deserialize(const u8 *buffer, const u8 *end) // We can't let addRef assert just because someone sent us bogus data if (m_handle < 4096 && m_handle != INVALID_HANDLE) addRef(); - return buffer+2; + return buffer; } HEntity::operator CStr() const diff --git a/source/simulation/Simulation.cpp b/source/simulation/Simulation.cpp index 937b792f86..cb2d72d2f3 100755 --- a/source/simulation/Simulation.cpp +++ b/source/simulation/Simulation.cpp @@ -9,9 +9,12 @@ #include "Scheduler.h" #include "Network/NetMessage.h" #include "CLogger.h" +#include "CConsole.h" #include "gui/CGUI.h" +extern CConsole *g_Console; + CSimulation::CSimulation(CGame *pGame): m_pGame(pGame), m_pWorld(pGame->GetWorld()), diff --git a/source/simulation/TurnManager.cpp b/source/simulation/TurnManager.cpp index a9227a8d3a..2e3278c19c 100755 --- a/source/simulation/TurnManager.cpp +++ b/source/simulation/TurnManager.cpp @@ -4,6 +4,7 @@ #include "Network/NetMessage.h" #include "Network/Network.h" #include "GameRecord.h" +#include "CLogger.h" #include @@ -17,7 +18,15 @@ CTurnManager::CTurnManager() void CTurnManager::ClearBatch(uint batch) { - m_Batches[batch].m_Messages.clear(); + typedef std::vector MsgVector; + MsgVector &messages=m_Batches[batch].m_Messages; + MsgVector::iterator it=messages.begin(); + while (it != messages.end()) + { + delete it->m_pMessage; + ++it; + } + messages.clear(); } void CTurnManager::SBatch::Swap(SBatch &other) @@ -28,12 +37,12 @@ void CTurnManager::SBatch::Swap(SBatch &other) void CTurnManager::RotateBatches() { - // {0, 1, 2} => {1, 2, 0}: - // {0, 1, 2} + // {a, b, c} => {b, c, a}: + // {a, b, c} // -- swap (0, 1) - // {1, 0, 2} + // {b, a, c} // -- swap (1, 2) - // {1, 2, 0} + // {b, c, a} m_Batches[0].Swap(m_Batches[1]); m_Batches[1].Swap(m_Batches[2]); @@ -46,7 +55,7 @@ void CTurnManager::IterateBatch(uint batch, BatchIteratorFunc *fp, void *userdat MsgVector::iterator it=messages.begin(); while (it != messages.end()) { - (*fp)(it->m_pMessage, it->m_ClientMask, userdata); + it->m_ClientMask=(*fp)(it->m_pMessage, it->m_ClientMask, userdata); ++it; } } @@ -59,28 +68,19 @@ void CTurnManager::SendBatch(uint batch) while (it != messages.end()) { SendMessage(it->m_pMessage, it->m_ClientMask); - it=messages.erase(it); + ++it; } + SendMessage(new CEndCommandBatch(), -1); } void CTurnManager::SendMessage(CNetMessage *pMsg, uint clientMask) { - uint sendToCount=0; - for (uint i=0;iCopy(); - else // Last message - send original message instead of copying it - sendMsg=pMsg; - m_Clients[i].m_Pipe->Push(sendMsg); + if (m_Clients[i].m_Pipe) + m_Clients[i].m_Pipe->Push(pMsg->Copy()); } } }