From e8dfde9ba6077587ba78ec463164cc991f18eccc Mon Sep 17 00:00:00 2001 From: elexis Date: Tue, 29 Aug 2017 16:04:45 +0000 Subject: [PATCH] Display previously received lobby chat messages when returning from the gamesetup. Differential Revision: https://code.wildfiregames.com/D819 Fixes #3306 Patch By: fpre / ffffffff This was SVN commit r20070. --- binaries/data/mods/public/gui/lobby/lobby.js | 23 +++++++--- .../data/mods/public/gui/lobby/prelobby.js | 2 +- source/lobby/IXmppClient.h | 5 +-- source/lobby/XmppClient.cpp | 45 ++++++++++++++----- source/lobby/XmppClient.h | 6 ++- source/lobby/scripting/JSInterface_Lobby.cpp | 17 ++++--- source/lobby/scripting/JSInterface_Lobby.h | 3 +- 7 files changed, 71 insertions(+), 30 deletions(-) diff --git a/binaries/data/mods/public/gui/lobby/lobby.js b/binaries/data/mods/public/gui/lobby/lobby.js index fddbbebc6b..ddaa46765f 100644 --- a/binaries/data/mods/public/gui/lobby/lobby.js +++ b/binaries/data/mods/public/gui/lobby/lobby.js @@ -233,18 +233,19 @@ var g_NetMessageTypes = { return true; }, "kicked": msg => { - handleKick(false, msg.nick, msg.reason, msg.time); + handleKick(false, msg.nick, msg.reason, msg.time, msg.historic); return true; }, "banned": msg => { - handleKick(true, msg.nick, msg.reason, msg.time); + handleKick(true, msg.nick, msg.reason, msg.time, msg.historic); return true; }, "room-message": msg => { addChatMessage({ "from": escapeText(msg.from), "text": escapeText(msg.text), - "time": msg.time + "time": msg.time, + "historic": msg.historic }); return false; }, @@ -264,7 +265,8 @@ var g_NetMessageTypes = { "from": escapeText(msg.from || "system"), "text": escapeText(msg.text.trim()), "time": msg.time, - "private" : true + "historic": msg.historic, + "private": true }); return false; } @@ -395,6 +397,10 @@ function init(attribs) updateToggleBuddy(); Engine.GetGUIObjectByName("chatInput").tooltip = colorizeAutocompleteHotkey(); + + // Get all messages since the login + for (let msg of Engine.LobbyGuiPollHistoricMessages()) + g_NetMessageTypes[msg.type][msg.level](msg); } function updateLobbyColumns() @@ -516,7 +522,7 @@ function filterGame(game) return false; } -function handleKick(banned, nick, reason, time) +function handleKick(banned, nick, reason, time, historic) { let kickString = nick == g_Username ? banned ? @@ -536,6 +542,7 @@ function handleKick(banned, nick, reason, time) addChatMessage({ "text": "/special " + sprintf(kickString, { "nick": nick }) + " " + reason, "time": time, + "historic": historic, "isSpecial": true }); return; @@ -1171,7 +1178,7 @@ function onTick() while (true) { - let msg = Engine.LobbyGuiPollMessage(); + let msg = Engine.LobbyGuiPollNewMessage(); if (!msg) break; @@ -1270,7 +1277,9 @@ function addChatMessage(msg) if (g_Username != msg.from) { msg.text = msg.text.replace(g_Username, colorPlayerName(g_Username)); - notifyUser(g_Username, msg.text); + + if (!msg.historic) + notifyUser(g_Username, msg.text); } } diff --git a/binaries/data/mods/public/gui/lobby/prelobby.js b/binaries/data/mods/public/gui/lobby/prelobby.js index 7574b4262a..fefe2c96f0 100644 --- a/binaries/data/mods/public/gui/lobby/prelobby.js +++ b/binaries/data/mods/public/gui/lobby/prelobby.js @@ -154,7 +154,7 @@ function onTick() // Handle queued messages from the XMPP client (if running and if any) let message; - while ((message = Engine.LobbyGuiPollMessage()) != undefined) + while ((message = Engine.LobbyGuiPollNewMessage()) != undefined) { // TODO: Properly deal with unrecognized messages if (message.type != "system" || !message.level) diff --git a/source/lobby/IXmppClient.h b/source/lobby/IXmppClient.h index 795fb4ded6..72d14dae87 100644 --- a/source/lobby/IXmppClient.h +++ b/source/lobby/IXmppClient.h @@ -53,10 +53,9 @@ public: virtual void GUIGetGameList(const ScriptInterface& scriptInterface, JS::MutableHandleValue ret) = 0; virtual void GUIGetBoardList(const ScriptInterface& scriptInterface, JS::MutableHandleValue ret) = 0; virtual void GUIGetProfile(const ScriptInterface& scriptInterface, JS::MutableHandleValue ret) = 0; - - virtual void GuiPollMessage(const ScriptInterface& scriptInterface, JS::MutableHandleValue ret) = 0; + virtual JS::Value GuiPollNewMessage(const ScriptInterface& scriptInterface) = 0; + virtual JS::Value GuiPollHistoricMessages(const ScriptInterface& scriptInterface) = 0; virtual void SendMUCMessage(const std::string& message) = 0; - virtual void SendStunEndpointToHost(StunClient::StunEndpoint* stunEndpoint, const std::string& hostJID) = 0; }; diff --git a/source/lobby/XmppClient.cpp b/source/lobby/XmppClient.cpp index b6714c90f6..b3620d6a02 100644 --- a/source/lobby/XmppClient.cpp +++ b/source/lobby/XmppClient.cpp @@ -229,6 +229,7 @@ void XmppClient::onDisconnect(gloox::ConnectionError error) m_GameList.clear(); m_PlayerMap.clear(); m_Profile.clear(); + m_HistoricGuiMessages.clear(); CreateGUIMessage("system", "disconnected", "reason", ConnectionErrorToString(error)); } @@ -569,19 +570,12 @@ void XmppClient::CreateGUIMessage( m_GuiMessageQueue.push_back(std::move(message)); } -void XmppClient::GuiPollMessage(const ScriptInterface& scriptInterface, JS::MutableHandleValue ret) +JS::Value XmppClient::GuiMessageToJSVal(const ScriptInterface& scriptInterface, const GUIMessage& message, const bool historic) { - if (m_GuiMessageQueue.empty()) - { - ret.setUndefined(); - return; - } - - GUIMessage message = m_GuiMessageQueue.front(); JSContext* cx = scriptInterface.GetContext(); JSAutoRequest rq(cx); - - scriptInterface.Eval("({})", ret); + JS::RootedValue ret(cx); + scriptInterface.Eval("({})", &ret); scriptInterface.SetProperty(ret, "type", wstring_from_utf8(message.type)); if (!message.level.empty()) scriptInterface.SetProperty(ret, "level", wstring_from_utf8(message.level)); @@ -590,7 +584,38 @@ void XmppClient::GuiPollMessage(const ScriptInterface& scriptInterface, JS::Muta if (!message.property2_name.empty()) scriptInterface.SetProperty(ret, message.property2_name.c_str(), wstring_from_utf8(message.property2_value)); scriptInterface.SetProperty(ret, "time", (double)message.time); + scriptInterface.SetProperty(ret, "historic", historic); + return ret; +} + +JS::Value XmppClient::GuiPollNewMessage(const ScriptInterface& scriptInterface) +{ + if (m_GuiMessageQueue.empty()) + return JS::UndefinedValue(); + + GUIMessage message = m_GuiMessageQueue.front(); m_GuiMessageQueue.pop_front(); + + // Since there can be hundreds of presence changes while playing a game, ignore these for performance + if (message.type == "chat" && message.level != "presence") + m_HistoricGuiMessages.push_back(message); + + return GuiMessageToJSVal(scriptInterface, message, false); +} + +JS::Value XmppClient::GuiPollHistoricMessages(const ScriptInterface& scriptInterface) +{ + JSContext* cx = scriptInterface.GetContext(); + JSAutoRequest rq(cx); + JS::RootedObject ret(cx, JS_NewArrayObject(cx, 0)); + + uint32_t i = 0; + for (const GUIMessage& message : m_HistoricGuiMessages) + { + JS::RootedValue msg(cx, GuiMessageToJSVal(scriptInterface, message, true)); + JS_SetElement(cx, ret, i++, msg); + } + return JS::ObjectValue(*ret); } /** diff --git a/source/lobby/XmppClient.h b/source/lobby/XmppClient.h index 8500ae3ae8..fbe5f6e5ac 100644 --- a/source/lobby/XmppClient.h +++ b/source/lobby/XmppClient.h @@ -143,7 +143,9 @@ public: std::string property2_value; std::time_t time; }; - void GuiPollMessage(const ScriptInterface& scriptInterface, JS::MutableHandleValue ret); + JS::Value GuiMessageToJSVal(const ScriptInterface& scriptInterface, const GUIMessage& message, const bool historic); + JS::Value GuiPollNewMessage(const ScriptInterface& scriptInterface); + JS::Value GuiPollHistoricMessages(const ScriptInterface& scriptInterface); void SendMUCMessage(const std::string& message); void ClearPresenceUpdates(); protected: @@ -167,6 +169,8 @@ private: std::vector m_Profile; /// Queue of messages for the GUI std::deque m_GuiMessageQueue; + /// Cache of all GUI messages received since the login + std::vector m_HistoricGuiMessages; /// Current room subject/topic. std::string m_Subject; }; diff --git a/source/lobby/scripting/JSInterface_Lobby.cpp b/source/lobby/scripting/JSInterface_Lobby.cpp index 1a0a7b2ff5..99707dcbcf 100644 --- a/source/lobby/scripting/JSInterface_Lobby.cpp +++ b/source/lobby/scripting/JSInterface_Lobby.cpp @@ -50,7 +50,8 @@ void JSI_Lobby::RegisterScriptFunctions(const ScriptInterface& scriptInterface) scriptInterface.RegisterFunction("GetGameList"); scriptInterface.RegisterFunction("GetBoardList"); scriptInterface.RegisterFunction("GetProfile"); - scriptInterface.RegisterFunction("LobbyGuiPollMessage"); + scriptInterface.RegisterFunction("LobbyGuiPollNewMessage"); + scriptInterface.RegisterFunction("LobbyGuiPollHistoricMessages"); scriptInterface.RegisterFunction("LobbySendMessage"); scriptInterface.RegisterFunction("LobbySetPlayerPresence"); scriptInterface.RegisterFunction("LobbySetNick"); @@ -225,18 +226,20 @@ JS::Value JSI_Lobby::GetProfile(ScriptInterface::CxPrivate* pCxPrivate) return profileFetch; } -JS::Value JSI_Lobby::LobbyGuiPollMessage(ScriptInterface::CxPrivate* pCxPrivate) +JS::Value JSI_Lobby::LobbyGuiPollNewMessage(ScriptInterface::CxPrivate* pCxPrivate) { if (!g_XmppClient) return JS::UndefinedValue(); - JSContext* cx = pCxPrivate->pScriptInterface->GetContext(); - JSAutoRequest rq(cx); + return g_XmppClient->GuiPollNewMessage(*(pCxPrivate->pScriptInterface)); +} - JS::RootedValue poll(cx); - g_XmppClient->GuiPollMessage(*(pCxPrivate->pScriptInterface), &poll); +JS::Value JSI_Lobby::LobbyGuiPollHistoricMessages(ScriptInterface::CxPrivate* pCxPrivate) +{ + if (!g_XmppClient) + return JS::UndefinedValue(); - return poll; + return g_XmppClient->GuiPollHistoricMessages(*(pCxPrivate->pScriptInterface)); } void JSI_Lobby::LobbySendMessage(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), const std::wstring& message) diff --git a/source/lobby/scripting/JSInterface_Lobby.h b/source/lobby/scripting/JSInterface_Lobby.h index f0fee969e1..ae8710362b 100644 --- a/source/lobby/scripting/JSInterface_Lobby.h +++ b/source/lobby/scripting/JSInterface_Lobby.h @@ -47,7 +47,8 @@ namespace JSI_Lobby JS::Value GetGameList(ScriptInterface::CxPrivate* pCxPrivate); JS::Value GetBoardList(ScriptInterface::CxPrivate* pCxPrivate); JS::Value GetProfile(ScriptInterface::CxPrivate* pCxPrivate); - JS::Value LobbyGuiPollMessage(ScriptInterface::CxPrivate* pCxPrivate); + JS::Value LobbyGuiPollNewMessage(ScriptInterface::CxPrivate* pCxPrivate); + JS::Value LobbyGuiPollHistoricMessages(ScriptInterface::CxPrivate* pCxPrivate); void LobbySendMessage(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& message); void LobbySetPlayerPresence(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& presence); void LobbySetNick(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& nick);