diff --git a/binaries/data/mods/public/gui/lobby/lobby.js b/binaries/data/mods/public/gui/lobby/lobby.js index d857f94926..654e44a859 100644 --- a/binaries/data/mods/public/gui/lobby/lobby.js +++ b/binaries/data/mods/public/gui/lobby/lobby.js @@ -35,7 +35,7 @@ const g_GameColors = { "init": "0 219 0", "waiting": "255 127 0", "running": "219 0 0" -} +}; /** * The playerlist will be assembled using these values. @@ -91,6 +91,81 @@ var g_SelectedPlayer = ""; */ var g_SelectedGameIP = ""; +/** + * Notifications sent by XmppClient.cpp + */ +var g_NetMessageTypes = { + "system": { + // Three cases are handled in prelobby.js + "registered": msg => { + }, + "login-failed": msg => { + }, + "connected": msg => { + }, + "disconnected": msg => { + updateGameList(); + updateLeaderboard(); + updatePlayerList(); + Engine.GetGUIObjectByName("hostButton").enabled = false; + addChatMessage({ "from": "system", "text": translate("Disconnected."), "color": g_SystemColor }); + }, + "error": msg => { + addChatMessage({ "from": "system", "text": escapeText(msg.text), "color": g_SystemColor }); + } + }, + "chat": { + "subject": msg => { + updateSubject(msg.text); + }, + "join": msg => { + addChatMessage({ + "text": "/special " + sprintf(translate("%(nick)s has joined."), { "nick": msg.text }), + "isSpecial": true + }); + Engine.SendGetRatingList(); + }, + "leave": msg => { + addChatMessage({ + "text": "/special " + sprintf(translate("%(nick)s has left."), { "nick": msg.text }), + "isSpecial": true + }); + }, + "presence": msg => { + }, + "nick": msg => { + addChatMessage({ + "text": "/special " + sprintf(translate("%(oldnick)s is now known as %(newnick)s."), { + "oldnick": msg.text, + "newnick": msg.data + }), + "isSpecial": true + }); + }, + "room-message": msg => { + addChatMessage({ + "from": escapeText(msg.from), + "text": escapeText(msg.text), + "datetime": msg.datetime + }); + }, + "private-message": msg => { + if (Engine.LobbyGetPlayerRole(msg.from) == "moderator") + addChatMessage({ + "from": "(Private) " + escapeText(msg.from), // TODO: placeholder + "text": escapeText(msg.text.trim()), // some XMPP clients send trailing whitespace + "datetime": msg.datetime + }); + } + }, + "game": { + "gamelist": msg => updateGameList(), + "profile": msg => updateProfile(), + "leaderboard": msg => updateLeaderboard(), + "ratinglist": msg => updatePlayerList() + } +}; + /** * Called after the XmppConnection succeeded and when returning from a game. * @@ -276,7 +351,7 @@ function updatePlayerList() playersBox.list_status = presenceList; playersBox.list_rating = ratingList; playersBox.list = nickList; - playersBox.selected = playersBox.list.indexOf(g_SelectedPlayer) + playersBox.selected = playersBox.list.indexOf(g_SelectedPlayer); } /** @@ -566,80 +641,25 @@ function onTick() while (true) { - var message = Engine.LobbyGuiPollMessage(); - if (!message) + let msg = Engine.LobbyGuiPollMessage(); + if (!msg) break; - switch (message.type) + + if (!g_NetMessageTypes[msg.type]) { - case "mucmessage": - addChatMessage({ "from": escapeText(message.from), "text": escapeText(message.text), "datetime": message.datetime}); - break; - case "muc": - switch(message.level) - { - case "join": - addChatMessage({ "text": "/special " + sprintf(translate("%(nick)s has joined."), { "nick": message.text }), "isSpecial": true }); - Engine.SendGetRatingList(); - break; - case "leave": - addChatMessage({ "text": "/special " + sprintf(translate("%(nick)s has left."), { "nick": message.text }), "isSpecial": true }); - break; - case "nick": - addChatMessage({ "text": "/special " + sprintf(translate("%(oldnick)s is now known as %(newnick)s."), { "oldnick": message.text, "newnick": message.data }), "isSpecial": true }); - break; - case "presence": - break; - case "subject": - updateSubject(message.text); - break; - default: - warn(sprintf("Unknown message.level '%(msglvl)s'", { "msglvl": message.level })); - break; - } - // To improve performance, only update the playerlist GUI when the last update in the current stack is processed - if (Engine.LobbyGetMucMessageCount() == 0) - updatePlayerList(); - break; - case "system": - switch (message.level) - { - case "standard": - addChatMessage({ "from": "system", "text": escapeText(message.text), "color": g_SystemColor }); - if (message.text == "disconnected") - { - updateGameList(); - updateLeaderboard(); - updatePlayerList(); - Engine.GetGUIObjectByName("hostButton").enabled = false; - } - else if (message.text == "connected") - Engine.GetGUIObjectByName("hostButton").enabled = true; - break; - case "error": - addChatMessage({ "from": "system", "text": escapeText(message.text), "color": g_SystemColor }); - break; - case "internal": - switch (message.text) - { - case "gamelist updated": - updateGameList(); - break; - case "boardlist updated": - updateLeaderboard(); - break; - case "ratinglist updated": - updatePlayerList(); - break; - case "profile updated": - updateProfile(); - break; - } - break; - } - break; - default: - error(sprintf("Unrecognised message type %(msgtype)s", { "msgtype": message.type })); + warn("Unrecognised message type: " + msg.type); + continue; } + if (!g_NetMessageTypes[msg.type][msg.level]) + { + warn("Unrecognised message level: " + msg.level); + continue; + } + g_NetMessageTypes[msg.type][msg.level](msg); + + // To improve performance, only update the playerlist GUI when the last update in the current stack is processed + if (msg.type == "chat" && Engine.LobbyGetMucMessageCount() == 0) + updatePlayerList(); } } @@ -888,7 +908,7 @@ function isSpam(text, from) */ function checkSpamMonitor() { - var time = Math.floor(Date.now() / 1000) + var time = Math.floor(Date.now() / 1000); for (let i in g_SpamMonitor) { let stats = g_SpamMonitor[i]; diff --git a/binaries/data/mods/public/gui/lobby/prelobby.js b/binaries/data/mods/public/gui/lobby/prelobby.js index ba053f3668..45ee322ab1 100644 --- a/binaries/data/mods/public/gui/lobby/prelobby.js +++ b/binaries/data/mods/public/gui/lobby/prelobby.js @@ -5,6 +5,39 @@ var g_TermsOfServiceRead = false; var g_TermsOfUseRead = false; var g_HasSystemMessage = false; +/** + * Notifications sent by XmppClient.cpp + * Other types are handled in lobby.js + */ +var g_SystemMessageTypes = { + "error": (message, username, password) => { + Engine.GetGUIObjectByName("feedback").caption = message.text; + Engine.StopXmppClient(); + }, + "login-failed": (message, username, password) => { + Engine.GetGUIObjectByName("feedback").caption = translate("Authentication failed"); + Engine.StopXmppClient(); + }, + "registered": (message, username, password) => { + Engine.GetGUIObjectByName("feedback").caption = translate("Registered"); + Engine.GetGUIObjectByName("connectUsername").caption = username; + Engine.GetGUIObjectByName("connectPassword").caption = password; + Engine.StopXmppClient(); + switchPage("connect"); + }, + "connected": (message, username, password) => { + Engine.PopGuiPage(); + Engine.SwitchGuiPage("page_lobby.xml"); + + Engine.ConfigDB_CreateValue("user", "playername", sanitizePlayerName(username, true, true)); + Engine.ConfigDB_CreateValue("user", "lobby.login", username); + if (password != g_EncrytedPassword.substring(0, 10)) + g_EncrytedPassword = Engine.EncryptPassword(password, username); + Engine.ConfigDB_CreateValue("user", "lobby.password", g_EncrytedPassword); + Engine.ConfigDB_WriteFile("user", "config/user.cfg"); + } +}; + function init() { g_EncrytedPassword = Engine.ConfigDB_GetValue("user", "lobby.password"); @@ -69,21 +102,13 @@ function lobbyStartRegister() function onTick() { var pageRegisterHidden = Engine.GetGUIObjectByName("pageRegister").hidden; - if (pageRegisterHidden) - { - var username = Engine.GetGUIObjectByName("connectUsername").caption; - var password = Engine.GetGUIObjectByName("connectPassword").caption; - } - else - { - var username = Engine.GetGUIObjectByName("registerUsername").caption; - var password = Engine.GetGUIObjectByName("registerPassword").caption; - } + var username = Engine.GetGUIObjectByName(pageRegisterHidden ? "connectUsername" : "registerUsername").caption; + var password = Engine.GetGUIObjectByName(pageRegisterHidden ? "connectPassword" : "registerPassword").caption; var passwordAgain = Engine.GetGUIObjectByName("registerPasswordAgain").caption; + var agreeTerms = Engine.GetGUIObjectByName("registerAgreeTerms"); var feedback = Engine.GetGUIObjectByName("feedback"); var continueButton = Engine.GetGUIObjectByName("continue"); - var sanitizedName = sanitizePlayerName(username, true, true); // Do not change feedback while connecting. if (g_LobbyIsConnecting) {} @@ -99,7 +124,7 @@ function onTick() feedback.caption = translate("Please enter your username"); } // Check that they are using a valid username. - else if (username != sanitizedName) + else if (username != sanitizePlayerName(username, true, true)) { continueButton.enabled = false; feedback.caption = translate("Usernames can't contain \\[, ], unicode, whitespace, or commas"); @@ -161,49 +186,20 @@ function onTick() // The XmppClient has been created, we are waiting // to be connected or to receive an error. - - //Receive messages while (true) { - var message = Engine.LobbyGuiPollMessage(); + let message = Engine.LobbyGuiPollMessage(); if (!message) break; - if (message.type == "system" && message.text == "connected") - { - // We are connected, switch to the lobby page - Engine.PopGuiPage(); - // Use username as nick. - var nick = sanitizePlayerName(username, true, true); + if (message.type != "system") + continue; - // Switch to lobby - Engine.SwitchGuiPage("page_lobby.xml"); - // Store nick, login, and password - Engine.ConfigDB_CreateValue("user", "playername", nick); - Engine.ConfigDB_CreateValue("user", "lobby.login", username); - // We only store the encrypted password, so make sure to re-encrypt it if changed before saving. - if (password != g_EncrytedPassword.substring(0, 10)) - g_EncrytedPassword = Engine.EncryptPassword(password, username); - Engine.ConfigDB_CreateValue("user", "lobby.password", g_EncrytedPassword); - Engine.ConfigDB_WriteFile("user", "config/user.cfg"); - } - else if (message.type == "system" && message.text == "registered") - { - // Great, we are registered. Switch to the connection window. - feedback.caption = translate("Registered"); - Engine.StopXmppClient(); - g_LobbyIsConnecting = false; - Engine.GetGUIObjectByName("connectUsername").caption = username; - Engine.GetGUIObjectByName("connectPassword").caption = password; - switchPage("connect"); - } - else if(message.type == "system" && (message.level == "error" || message.text == "disconnected")) - { - g_HasSystemMessage = true; - feedback.caption = message.text == "disconnected" ? translate("Disconnected") : message.text; - Engine.StopXmppClient(); - g_LobbyIsConnecting = false; - } + g_HasSystemMessage = true; + g_LobbyIsConnecting = false; + + if (g_SystemMessageTypes[message.level]) + g_SystemMessageTypes[message.level](message, username, password); } } diff --git a/source/lobby/XmppClient.cpp b/source/lobby/XmppClient.cpp index 0a7965b60a..f0f65ecf42 100644 --- a/source/lobby/XmppClient.cpp +++ b/source/lobby/XmppClient.cpp @@ -189,7 +189,7 @@ void XmppClient::onConnect() { if (m_mucRoom) { - CreateSimpleMessage("system", "connected"); + CreateGUIMessage("system", "connected"); m_mucRoom->join(); } @@ -220,9 +220,9 @@ void XmppClient::onDisconnect(gloox::ConnectionError error) m_Profile.clear(); if (error == gloox::ConnAuthenticationFailed) - CreateSimpleMessage("system", g_L10n.Translate("Authentication failed"), "error"); + CreateGUIMessage("system", "login-failed"); else - CreateSimpleMessage("system", "disconnected"); + CreateGUIMessage("system", "disconnected"); } /** @@ -249,7 +249,7 @@ bool XmppClient::onTLSConnect(const glooxwrapper::CertInfo& info) void XmppClient::handleMUCError(glooxwrapper::MUCRoom*, gloox::StanzaError err) { std::string msg = StanzaErrorToString(err); - CreateSimpleMessage("system", msg, "error"); + CreateGUIMessage("system", "error", msg); } /***************************************************** @@ -445,9 +445,7 @@ void XmppClient::handleRegistrationFields(const glooxwrapper::JID&, int fields, void XmppClient::handleRegistrationResult(const glooxwrapper::JID&, gloox::RegistrationResult result) { if (result == gloox::RegistrationSuccess) - { - CreateSimpleMessage("system", "registered"); - } + CreateGUIMessage("system", "registered"); else { std::string msg; @@ -465,7 +463,7 @@ void XmppClient::handleRegistrationResult(const glooxwrapper::JID&, gloox::Regis default: msg = g_L10n.Translate("Registration unknown error"); } #undef CASE - CreateSimpleMessage("system", msg, "error"); + CreateGUIMessage("system", "error", msg); } disconnect(); } @@ -613,8 +611,6 @@ void XmppClient::GuiPollMessage(ScriptInterface& scriptInterface, JS::MutableHan scriptInterface.SetProperty(ret, "text", message.text); if (!message.level.empty()) scriptInterface.SetProperty(ret, "level", message.level); - if (!message.message.empty()) - scriptInterface.SetProperty(ret, "message", message.message); if (!message.data.empty()) scriptInterface.SetProperty(ret, "data", message.data); if (!message.datetime.empty()) @@ -651,7 +647,7 @@ void XmppClient::ClearPresenceUpdates() std::remove_if(m_GuiMessageQueue.begin(), m_GuiMessageQueue.end(), [](XmppClient::GUIMessage& message) { - return message.type == L"muc" && message.level == L"presence"; + return message.type == L"chat" && message.level == L"presence"; } ), m_GuiMessageQueue.end()); } @@ -664,19 +660,20 @@ int XmppClient::GetMucMessageCount() return std::count_if(m_GuiMessageQueue.begin(), m_GuiMessageQueue.end(), [](XmppClient::GUIMessage& message) { - return message.type == L"muc"; + return message.type == L"chat"; }); } /** - * Handle a standard MUC textual message. + * Handle a room message. */ void XmppClient::handleMUCMessage(glooxwrapper::MUCRoom*, const glooxwrapper::Message& msg, bool) { DbgXMPP(msg.from().resource() << " said " << msg.body()); GUIMessage message; - message.type = L"mucmessage"; + message.type = L"chat"; + message.level = L"room-message"; message.from = wstring_from_utf8(msg.from().resource().to_string()); message.text = wstring_from_utf8(msg.body().to_string()); if (msg.when()) @@ -686,7 +683,7 @@ void XmppClient::handleMUCMessage(glooxwrapper::MUCRoom*, const glooxwrapper::Me } /** - * Handle a standard textual message. + * Handle a private message. */ void XmppClient::handleMessage(const glooxwrapper::Message& msg, glooxwrapper::MessageSession *) { @@ -694,8 +691,10 @@ void XmppClient::handleMessage(const glooxwrapper::Message& msg, glooxwrapper::M << ", message " << msg.body() << ", thread id " << msg.thread()); GUIMessage message; + message.type = L"chat"; + message.level = L"private-message"; message.from = wstring_from_utf8(msg.from().username().to_string()); - message.message = wstring_from_utf8(msg.body().to_string()); + message.text = wstring_from_utf8(msg.body().to_string()); if (msg.when()) //See http://xmpp.org/extensions/xep-0082.html#sect-idp285136 for format message.datetime = msg.when()->stamp().to_string(); @@ -723,7 +722,7 @@ bool XmppClient::handleIq(const glooxwrapper::IQ& iq) for (const glooxwrapper::Tag* const& t : gq->m_GameList) m_GameList.emplace_back(t->clone()); - CreateSimpleMessage("system", "gamelist updated", "internal"); + CreateGUIMessage("game", "gamelist"); } if (bq) { @@ -736,7 +735,7 @@ bool XmppClient::handleIq(const glooxwrapper::IQ& iq) for (const glooxwrapper::Tag* const& t : bq->m_StanzaBoardList) m_BoardList.emplace_back(t->clone()); - CreateSimpleMessage("system", "boardlist updated", "internal"); + CreateGUIMessage("game", "leaderboard"); } else if (bq->m_Command == "ratinglist") { @@ -747,7 +746,7 @@ bool XmppClient::handleIq(const glooxwrapper::IQ& iq) m_PlayerMap[name][1] = t->findAttribute("rating").to_string(); } - CreateSimpleMessage("system", "ratinglist updated", "internal"); + CreateGUIMessage("game", "ratinglist"); } } if (pq) @@ -759,22 +758,21 @@ bool XmppClient::handleIq(const glooxwrapper::IQ& iq) for (const glooxwrapper::Tag* const& t : pq->m_StanzaProfile) m_Profile.emplace_back(t->clone()); - CreateSimpleMessage("system", "profile updated", "internal"); + CreateGUIMessage("game", "profile"); } } else if (iq.subtype() == gloox::IQ::Error) { gloox::StanzaError err = iq.error_error(); std::string msg = StanzaErrorToString(err); - CreateSimpleMessage("system", msg, "error"); + CreateGUIMessage("system", "error", msg); } else { - CreateSimpleMessage("system", g_L10n.Translate("unknown subtype (see logs)"), "error"); + CreateGUIMessage("system", "error", g_L10n.Translate("unknown subtype (see logs)")); std::string tag = tag_name(iq); LOGMESSAGE("unknown subtype '%s'", tag.c_str()); } - return true; } @@ -786,7 +784,7 @@ bool XmppClient::handleIq(const glooxwrapper::IQ& iq) * @param text Body of the message * @param data Optional field, used for auxiliary data */ -void XmppClient::CreateSimpleMessage(const std::string& type, const std::string& text, const std::string& level, const std::string& data) +void XmppClient::CreateGUIMessage(const std::string& type, const std::string& level, const std::string& text, const std::string& data) { GUIMessage message; message.type = wstring_from_utf8(type); @@ -820,10 +818,10 @@ void XmppClient::handleMUCParticipantPresence(glooxwrapper::MUCRoom*, const gloo m_PlayerMap[newNick].resize(3); m_PlayerMap[newNick][0] = presenceString; m_PlayerMap[newNick][2] = roleString; - CreateSimpleMessage("muc", nick, "nick", participant.newNick.to_string()); + CreateGUIMessage("chat", "nick", nick, participant.newNick.to_string()); } else - CreateSimpleMessage("muc", nick, "leave"); + CreateGUIMessage("chat", "leave", nick); DbgXMPP(nick << " left the room"); m_PlayerMap.erase(nick); @@ -840,9 +838,9 @@ void XmppClient::handleMUCParticipantPresence(glooxwrapper::MUCRoom*, const gloo m_initialLoadComplete = true; } else if (m_PlayerMap.find(nick) == m_PlayerMap.end()) - CreateSimpleMessage("muc", nick, "join"); + CreateGUIMessage("chat", "join", nick); else - CreateSimpleMessage("muc", nick, "presence"); + CreateGUIMessage("chat", "presence", nick); DbgXMPP(nick << " is in the room, presence : " << (int)presenceType); m_PlayerMap[nick].resize(3); @@ -857,7 +855,7 @@ void XmppClient::handleMUCParticipantPresence(glooxwrapper::MUCRoom*, const gloo void XmppClient::handleMUCSubject(glooxwrapper::MUCRoom*, const glooxwrapper::string& UNUSED(nick), const glooxwrapper::string& subject) { m_Subject = subject.c_str(); - CreateSimpleMessage("muc", m_Subject, "subject"); + CreateGUIMessage("chat", "subject", m_Subject); } /** diff --git a/source/lobby/XmppClient.h b/source/lobby/XmppClient.h index 72fadf37c8..062350f8eb 100644 --- a/source/lobby/XmppClient.h +++ b/source/lobby/XmppClient.h @@ -144,7 +144,7 @@ public: int GetMucMessageCount(); protected: void PushGuiMessage(XmppClient::GUIMessage message); - void CreateSimpleMessage(const std::string& type, const std::string& text, const std::string& level = "standard", const std::string& data = ""); + void CreateGUIMessage(const std::string& type, const std::string& level, const std::string& text = "", const std::string& data = ""); private: /// Map of players