From 23c3ae3849c7e98deb2e91d5c282670b1262d397 Mon Sep 17 00:00:00 2001 From: lotodore Date: Fri, 26 Dec 2008 16:47:14 +0000 Subject: [PATCH] Enable sending of a global message box through the irc bot, to inform clients about server reboots. --- docs/net_protocol.txt | 16 ++++ src/gui/generic/serverguiwrapper.cpp | 1 + src/gui/generic/serverguiwrapper.h | 1 + src/gui/qt/guiwrapper.cpp | 2 +- src/gui/qt/guiwrapper.h | 1 + src/gui/qt/startwindow/startwindowimpl.cpp | 9 ++ src/gui/qt/startwindow/startwindowimpl.h | 2 + src/net/clientcallback.h | 1 + src/net/common/clientstate.cpp | 7 ++ src/net/common/netpacket.cpp | 105 ++++++++++++++++++++- src/net/common/serverlobbythread.cpp | 12 ++- src/net/common/servermanager.cpp | 17 +++- src/net/netpacket.h | 25 +++++ src/net/serverlobbythread.h | 3 +- 14 files changed, 196 insertions(+), 6 deletions(-) diff --git a/docs/net_protocol.txt b/docs/net_protocol.txt index 24c7b371..48803acb 100644 --- a/docs/net_protocol.txt +++ b/docs/net_protocol.txt @@ -1040,6 +1040,22 @@ Server Notification: Chat Text +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +Server Notification: Message Box Text + + 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 = 514 | Message Length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Text Length | Reserved | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | \ + \ Text (UTF-8) / + | +-------------------------------+ + / | padding | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Server Notification: Error 0 1 2 3 diff --git a/src/gui/generic/serverguiwrapper.cpp b/src/gui/generic/serverguiwrapper.cpp index 19460cf6..bd63f494 100644 --- a/src/gui/generic/serverguiwrapper.cpp +++ b/src/gui/generic/serverguiwrapper.cpp @@ -138,6 +138,7 @@ void ServerGuiWrapper::SignalNetClientGameListPlayerJoined(unsigned gameId, unsi void ServerGuiWrapper::SignalNetClientGameListPlayerLeft(unsigned gameId, unsigned playerId) { if (myClientcb) myClientcb->SignalNetClientGameListPlayerLeft(gameId, playerId); } void ServerGuiWrapper::SignalNetClientGameStart(boost::shared_ptr game) { if (myClientcb) myClientcb->SignalNetClientGameStart(game); } void ServerGuiWrapper::SignalNetClientChatMsg(const string &playerName, const string &msg) { if (myClientcb) myClientcb->SignalNetClientChatMsg(playerName, msg); } +void ServerGuiWrapper::SignalNetClientMsgBox(const string &msg) { if (myClientcb) myClientcb->SignalNetClientMsgBox(msg); } void ServerGuiWrapper::SignalNetClientWaitDialog() { if (myClientcb) myClientcb->SignalNetClientWaitDialog(); } void ServerGuiWrapper::SignalNetServerSuccess(int actionID) { if (myServercb) myServercb->SignalNetServerSuccess(actionID); } diff --git a/src/gui/generic/serverguiwrapper.h b/src/gui/generic/serverguiwrapper.h index 84ab5028..f60e0285 100644 --- a/src/gui/generic/serverguiwrapper.h +++ b/src/gui/generic/serverguiwrapper.h @@ -137,6 +137,7 @@ public: void SignalIrcPlayerKicked(const std::string &nickName, const std::string &byWhom, const std::string &reason); void SignalIrcPlayerLeft(const std::string &nickName); void SignalIrcChatMsg(const std::string &nickName, const std::string &msg); + void SignalNetClientMsgBox(const std::string &msg); void SignalIrcError(int errorCode); void SignalIrcServerError(int errorCode); diff --git a/src/gui/qt/guiwrapper.cpp b/src/gui/qt/guiwrapper.cpp index ffec492d..88cb8fa6 100644 --- a/src/gui/qt/guiwrapper.cpp +++ b/src/gui/qt/guiwrapper.cpp @@ -160,9 +160,9 @@ void GuiWrapper::SignalNetClientGameListPlayerJoined(unsigned gameId, unsigned p void GuiWrapper::SignalNetClientGameListPlayerLeft(unsigned gameId, unsigned playerId) { myStartWindow->signalNetClientGameListPlayerLeft(gameId, playerId); } void GuiWrapper::SignalNetClientGameStart(boost::shared_ptr game) { myStartWindow->signalNetClientGameStart(game); } - void GuiWrapper::SignalNetClientWaitDialog() { myStartWindow->signalShowClientDialog(); } void GuiWrapper::SignalNetClientChatMsg(const string &playerName, const string &msg) { myStartWindow->signalNetClientChatMsg(QString::fromUtf8(playerName.c_str()), QString::fromUtf8(msg.c_str())); } +void GuiWrapper::SignalNetClientMsgBox(const string &msg) { myStartWindow->signalNetClientMsgBox(QString::fromUtf8(msg.c_str())); } void GuiWrapper::SignalNetServerSuccess(int /*actionID*/) { } void GuiWrapper::SignalNetServerError(int errorID, int osErrorID) { myStartWindow->signalNetServerError(errorID, osErrorID); } diff --git a/src/gui/qt/guiwrapper.h b/src/gui/qt/guiwrapper.h index 524cead5..e539e596 100644 --- a/src/gui/qt/guiwrapper.h +++ b/src/gui/qt/guiwrapper.h @@ -125,6 +125,7 @@ public: void SignalNetClientPlayerLeft(unsigned playerId, const std::string &playerName, int removeReason); void SignalNetClientNewGameAdmin(unsigned playerId, const std::string &playerName); void SignalNetClientChatMsg(const std::string &playerName, const std::string &msg); + void SignalNetClientMsgBox(const std::string &msg); void SignalNetClientWaitDialog(); void SignalNetClientGameListNew(unsigned gameId); diff --git a/src/gui/qt/startwindow/startwindowimpl.cpp b/src/gui/qt/startwindow/startwindowimpl.cpp index c22ba516..d90d5e38 100644 --- a/src/gui/qt/startwindow/startwindowimpl.cpp +++ b/src/gui/qt/startwindow/startwindowimpl.cpp @@ -138,6 +138,7 @@ startWindowImpl::startWindowImpl(ConfigFile *c) connect(this, SIGNAL(signalNetClientChatMsg(QString, QString)), myStartNetworkGameDialog, SLOT(receiveChatMsg(QString, QString))); connect(this, SIGNAL(signalNetClientChatMsg(QString, QString)), myGuiInterface->getMyW()->getMyChat(), SLOT(receiveMessage(QString, QString))); + connect(this, SIGNAL(signalNetClientMsgBox(QString)), this, SLOT(networkMessage(QString))); connect(this, SIGNAL(signalNetClientShowTimeoutDialog(int, unsigned)), this, SLOT(showTimeoutDialog(int, unsigned))); @@ -869,6 +870,14 @@ void startWindowImpl::networkNotification(int notificationId) } } +void startWindowImpl::networkMessage(QString msg) +{ + QMessageBox msgBox(QMessageBox::Information, tr("Server Message"), + msg, QMessageBox::Close, this); + msgBox.setTextFormat(Qt::RichText); + msgBox.exec(); +} + void startWindowImpl::networkStart(boost::shared_ptr game) { mySession->startClientGame(game); diff --git a/src/gui/qt/startwindow/startwindowimpl.h b/src/gui/qt/startwindow/startwindowimpl.h index 8b89a56f..dd9b345a 100644 --- a/src/gui/qt/startwindow/startwindowimpl.h +++ b/src/gui/qt/startwindow/startwindowimpl.h @@ -77,6 +77,7 @@ signals: void signalNetClientGameListPlayerLeft(unsigned gameId, unsigned playerId); void signalNetClientGameStart(boost::shared_ptr game); void signalNetClientChatMsg(QString nickName, QString msg); + void signalNetClientMsgBox(QString msg); void signalIrcConnect(QString server); void signalIrcSelfJoined(QString nickName, QString channel); @@ -109,6 +110,7 @@ public slots: void networkError(int, int); void networkNotification(int); + void networkMessage(QString); void networkStart(boost::shared_ptr game); QStringList getPlayerNicksList(); diff --git a/src/net/clientcallback.h b/src/net/clientcallback.h index 99796d69..17aeddb6 100644 --- a/src/net/clientcallback.h +++ b/src/net/clientcallback.h @@ -57,6 +57,7 @@ public: virtual void SignalNetClientNewGameAdmin(unsigned playerId, const std::string &playerName) = 0; virtual void SignalNetClientChatMsg(const std::string &playerName, const std::string &msg) = 0; + virtual void SignalNetClientMsgBox(const std::string &msg) = 0; virtual void SignalNetClientWaitDialog() = 0; }; diff --git a/src/net/common/clientstate.cpp b/src/net/common/clientstate.cpp index c46e2a5c..e5bc1a4d 100644 --- a/src/net/common/clientstate.cpp +++ b/src/net/common/clientstate.cpp @@ -705,6 +705,13 @@ AbstractClientStateReceiving::Process(ClientThread &client) if (!playerName.empty()) client.GetCallback().SignalNetClientChatMsg(playerName, chatData.text); } + else if (tmpPacket->ToNetPacketMsgBoxText()) + { + // Message box - display it in the GUI. + NetPacketMsgBoxText::Data msgData; + tmpPacket->ToNetPacketMsgBoxText()->GetData(msgData); + client.GetCallback().SignalNetClientMsgBox(msgData.text); + } else if (tmpPacket->ToNetPacketPlayerLeft()) { // A player left the game. diff --git a/src/net/common/netpacket.cpp b/src/net/common/netpacket.cpp index 4a343fc3..83b85b29 100644 --- a/src/net/common/netpacket.cpp +++ b/src/net/common/netpacket.cpp @@ -87,6 +87,7 @@ using namespace std; #define NET_TYPE_SEND_CHAT_TEXT 0x0200 #define NET_TYPE_CHAT_TEXT 0x0201 +#define NET_TYPE_MSG_BOX_TEXT 0x0202 #define NET_TYPE_ERROR 0x0400 @@ -659,6 +660,13 @@ struct GCC_PACKED NetPacketChatTextData u_int16_t reserved; }; +struct GCC_PACKED NetPacketMsgBoxTextData +{ + NetPacketHeader head; + u_int16_t textLength; + u_int16_t reserved; +}; + struct GCC_PACKED NetPacketErrorData { NetPacketHeader head; @@ -951,6 +959,9 @@ NetPacket::Create(char *data, unsigned &dataSize) case NET_TYPE_CHAT_TEXT: tmpPacket = boost::shared_ptr(new NetPacketChatText); break; + case NET_TYPE_MSG_BOX_TEXT: + tmpPacket = boost::shared_ptr(new NetPacketMsgBoxText); + break; case NET_TYPE_ERROR: tmpPacket = boost::shared_ptr(new NetPacketError); break; @@ -1368,6 +1379,12 @@ NetPacket::ToNetPacketChatText() const return NULL; } +const NetPacketMsgBoxText * +NetPacket::ToNetPacketMsgBoxText() const +{ + return NULL; +} + const NetPacketError * NetPacket::ToNetPacketError() const { @@ -2032,7 +2049,7 @@ NetPacketGameListNew::GetData(NetPacketGameListNew::Data &outData) const outData.gameInfo.mode = static_cast(ntohs(tmpData->gameMode)); u_int16_t gameNameLen = ntohs(tmpData->gameNameLength); u_int16_t curNumPlayers = ntohs(tmpData->curNumberOfPlayers); - outData.gameInfo.isPasswordProtected = ntohs(tmpData->privacyFlags) & NET_PRIVACY_FLAG_PASSWORD_PROTECTED == NET_PRIVACY_FLAG_PASSWORD_PROTECTED; + outData.gameInfo.isPasswordProtected = (ntohs(tmpData->privacyFlags) & NET_PRIVACY_FLAG_PASSWORD_PROTECTED) == NET_PRIVACY_FLAG_PASSWORD_PROTECTED; GetGameInfoData(&tmpData->gameData, outData.gameInfo.data); @@ -5550,6 +5567,92 @@ NetPacketChatText::InternalCheck(const NetPacketHeader* data) const //----------------------------------------------------------------------------- +NetPacketMsgBoxText::NetPacketMsgBoxText() +: NetPacket(NET_TYPE_MSG_BOX_TEXT, sizeof(NetPacketMsgBoxTextData), MAX_PACKET_SIZE) +{ +} + +NetPacketMsgBoxText::~NetPacketMsgBoxText() +{ +} + +boost::shared_ptr +NetPacketMsgBoxText::Clone() const +{ + boost::shared_ptr newPacket(new NetPacketMsgBoxText); + try + { + newPacket->SetRawData(GetRawData()); + } catch (const NetException &) + { + // Need to return the new packet anyway. + } + return newPacket; +} + +void +NetPacketMsgBoxText::SetData(const NetPacketMsgBoxText::Data &inData) +{ + u_int16_t textLen = (u_int16_t)inData.text.length(); + + if (!textLen || textLen > MAX_CHAT_TEXT_SIZE) + throw NetException(__FILE__, __LINE__, ERR_NET_INVALID_CHAT_TEXT, 0); + + // Resize the packet so that the data fits in. + Resize((u_int16_t) + (sizeof(NetPacketMsgBoxTextData) + ADD_PADDING(textLen))); + + NetPacketMsgBoxTextData *tmpData = (NetPacketMsgBoxTextData *)GetRawData(); + + // Set the data. + tmpData->textLength = htons(textLen); + char *textPtr = (char *)tmpData + sizeof(NetPacketMsgBoxTextData); + memcpy(textPtr, inData.text.c_str(), textLen); + + // Check the packet - just in case. + Check(GetRawData()); +} + +void +NetPacketMsgBoxText::GetData(NetPacketMsgBoxText::Data &outData) const +{ + // We assume that the data is valid. Validity has already been checked. + NetPacketMsgBoxTextData *tmpData = (NetPacketMsgBoxTextData *)GetRawData(); + + char *textPtr = (char *)tmpData + sizeof(NetPacketMsgBoxTextData); + outData.text = string(textPtr, ntohs(tmpData->textLength)); +} + +const NetPacketMsgBoxText * +NetPacketMsgBoxText::ToNetPacketMsgBoxText() const +{ + return this; +} + +void +NetPacketMsgBoxText::InternalCheck(const NetPacketHeader* data) const +{ + u_int16_t dataLen = ntohs(data->length); + NetPacketMsgBoxTextData *tmpData = (NetPacketMsgBoxTextData *)data; + int textLength = ntohs(tmpData->textLength); + // Check exact packet length. + if (dataLen != + sizeof(NetPacketMsgBoxTextData) + + ADD_PADDING(textLength)) + { + throw NetException(__FILE__, __LINE__, ERR_SOCK_INVALID_PACKET, 0); + } + // Check string size. + if (!textLength + || textLength > MAX_CHAT_TEXT_SIZE) + { + throw NetException(__FILE__, __LINE__, ERR_SOCK_INVALID_PACKET, 0); + } + // No more checks required - this packet is sent by the server. +} + +//----------------------------------------------------------------------------- + NetPacketError::NetPacketError() : NetPacket(NET_TYPE_ERROR, sizeof(NetPacketErrorData), sizeof(NetPacketErrorData)) { diff --git a/src/net/common/serverlobbythread.cpp b/src/net/common/serverlobbythread.cpp index 8b8dd285..509ba627 100644 --- a/src/net/common/serverlobbythread.cpp +++ b/src/net/common/serverlobbythread.cpp @@ -260,7 +260,7 @@ ServerLobbyThread::RemovePlayer(unsigned playerId, unsigned errorCode) } void -ServerLobbyThread::SendGlobalNotice(const std::string &message) +ServerLobbyThread::SendGlobalChat(const string &message) { boost::shared_ptr outChat(new NetPacketChatText); NetPacketChatText::Data outChatData; @@ -270,6 +270,16 @@ ServerLobbyThread::SendGlobalNotice(const std::string &message) m_gameSessionManager.SendToAllSessions(GetSender(), outChat, SessionData::Game); } +void +ServerLobbyThread::SendGlobalMsgBox(const string &message) +{ + boost::shared_ptr outMsg(new NetPacketMsgBoxText); + NetPacketMsgBoxText::Data outMsgData; + outMsgData.text = message; + static_cast(outMsg.get())->SetData(outMsgData); + m_gameSessionManager.SendToAllSessions(GetSender(), outMsg, SessionData::Game); +} + void ServerLobbyThread::AddComputerPlayer(boost::shared_ptr player) { diff --git a/src/net/common/servermanager.cpp b/src/net/common/servermanager.cpp index 598bc5d2..aa282e71 100644 --- a/src/net/common/servermanager.cpp +++ b/src/net/common/servermanager.cpp @@ -147,6 +147,19 @@ ServerManager::SignalIrcChatMsg(const std::string &nickName, const std::string & m_ircThread->SendChatMessage(statStream.str()); } } + else if (command == "chat") + { + while (msgStream.peek() == ' ') + msgStream.get(); + string chat(msgStream.str().substr(msgStream.tellg())); + if (!chat.empty()) + { + GetLobbyThread().SendGlobalChat(chat); + m_ircThread->SendChatMessage(nickName + ": Global chat message sent."); + } + else + m_ircThread->SendChatMessage(nickName + ": Invalid message."); + } else if (command == "msg") { while (msgStream.peek() == ' ') @@ -154,8 +167,8 @@ ServerManager::SignalIrcChatMsg(const std::string &nickName, const std::string & string message(msgStream.str().substr(msgStream.tellg())); if (!message.empty()) { - GetLobbyThread().SendGlobalNotice(message); - m_ircThread->SendChatMessage(nickName + ": Global notice sent."); + GetLobbyThread().SendGlobalMsgBox(message); + m_ircThread->SendChatMessage(nickName + ": Global message box sent."); } else m_ircThread->SendChatMessage(nickName + ": Invalid message."); diff --git a/src/net/netpacket.h b/src/net/netpacket.h index fe0b958f..533d6167 100644 --- a/src/net/netpacket.h +++ b/src/net/netpacket.h @@ -101,6 +101,7 @@ class NetPacketTimeoutWarning; class NetPacketResetTimeout; class NetPacketSendChatText; class NetPacketChatText; +class NetPacketMsgBoxText; class NetPacketError; class NetPacket @@ -175,6 +176,7 @@ public: virtual const NetPacketResetTimeout *ToNetPacketResetTimeout() const; virtual const NetPacketSendChatText *ToNetPacketSendChatText() const; virtual const NetPacketChatText *ToNetPacketChatText() const; + virtual const NetPacketMsgBoxText *ToNetPacketMsgBoxText() const; virtual const NetPacketError *ToNetPacketError() const; virtual bool IsClientActivity() const {return false;} @@ -1522,6 +1524,29 @@ protected: virtual void InternalCheck(const NetPacketHeader* data) const; }; +class NetPacketMsgBoxText : public NetPacket +{ +public: + struct Data + { + std::string text; + }; + + NetPacketMsgBoxText(); + virtual ~NetPacketMsgBoxText(); + + virtual boost::shared_ptr Clone() const; + + void SetData(const Data &inData); + void GetData(Data &outData) const; + + virtual const NetPacketMsgBoxText *ToNetPacketMsgBoxText() const; + +protected: + + virtual void InternalCheck(const NetPacketHeader* data) const; +}; + class NetPacketError : public NetPacket { public: diff --git a/src/net/serverlobbythread.h b/src/net/serverlobbythread.h index 8f21bc1e..2f307857 100644 --- a/src/net/serverlobbythread.h +++ b/src/net/serverlobbythread.h @@ -70,7 +70,8 @@ public: bool KickPlayerByName(const std::string &playerName); void RemovePlayer(unsigned playerId, unsigned errorCode); - void SendGlobalNotice(const std::string &message); + void SendGlobalChat(const std::string &message); + void SendGlobalMsgBox(const std::string &message); void AddComputerPlayer(boost::shared_ptr player); void RemoveComputerPlayer(boost::shared_ptr player);