From 8b437a0b1cc3ad1a4b83f2f25001a1bf77b865bd Mon Sep 17 00:00:00 2001 From: JoshuaJB Date: Thu, 10 Sep 2015 05:30:18 +0000 Subject: [PATCH] Fix #3386, patch by elexis. This was SVN commit r16997. --- binaries/data/mods/public/gui/lobby/lobby.js | 51 +++----------------- source/lobby/IXmppClient.h | 5 +- source/lobby/XmppClient.cpp | 27 +++++++++++ source/lobby/XmppClient.h | 16 ++++-- source/lobby/scripting/JSInterface_Lobby.cpp | 15 ++++++ source/lobby/scripting/JSInterface_Lobby.h | 2 + 6 files changed, 66 insertions(+), 50 deletions(-) diff --git a/binaries/data/mods/public/gui/lobby/lobby.js b/binaries/data/mods/public/gui/lobby/lobby.js index 6a60581675..15a9610597 100644 --- a/binaries/data/mods/public/gui/lobby/lobby.js +++ b/binaries/data/mods/public/gui/lobby/lobby.js @@ -48,7 +48,11 @@ function init(attribs) Engine.LobbySetPlayerPresence("available"); Engine.SendGetGameList(); Engine.SendGetBoardList(); + + // When rejoining the lobby after a game, we don't need to process presence changes + Engine.LobbyClearPresenceUpdates(); updatePlayerList(); + updateSubject(Engine.LobbyGetRoomSubject()); resetFilters(); @@ -233,7 +237,6 @@ function updatePlayerList() playersBox.list = nickList; if (playersBox.selected >= playersBox.list.length) playersBox.selected = -1; - return [playerList, presenceList, nickList, ratingList]; } /** @@ -689,53 +692,18 @@ function onTick() break; case "muc": var nick = message.text; - var presence = Engine.LobbyGetPlayerPresence(nick); - var playersBox = Engine.GetGUIObjectByName("playersBox"); - var playerList = playersBox.list_name; - var presenceList = playersBox.list_status; - var nickList = playersBox.list; - var ratingList = playersBox.list_rating; - var nickIndex = nickList.indexOf(nick); switch(message.level) { case "join": - var [name, status, rating] = formatPlayerListEntry(nick, presence, "-"); - playerList.push(name); - presenceList.push(status); - nickList.push(nick); - ratingList.push(String(rating)); addChatMessage({ "text": "/special " + sprintf(translate("%(nick)s has joined."), { nick: nick }), "key": g_specialKey }); break; case "leave": - if (nickIndex == -1) // Left, but not present (TODO: warn about this?) - break; - playerList.splice(nickIndex, 1); - presenceList.splice(nickIndex, 1); - nickList.splice(nickIndex, 1); - ratingList.splice(nickIndex, 1); addChatMessage({ "text": "/special " + sprintf(translate("%(nick)s has left."), { nick: nick }), "key": g_specialKey }); break; case "nick": - if (nickIndex == -1) // Changed nick, but not present (shouldn't ever happen) - break; - if (!isValidNick(message.data)) - { - addChatMessage({ "from": "system", "text": sprintf(translate("Invalid nickname: %(nick)s"), { nick: message.data })}); - break; - } - var [name, status, rating] = formatPlayerListEntry(message.data, presence, stripColorCodes(ratingList[nickIndex])); // TODO: actually we don't want to change the presence here, so use what was used before - playerList[nickIndex] = name; - // presence stays the same - nickList[nickIndex] = message.data; addChatMessage({ "text": "/special " + sprintf(translate("%(oldnick)s is now known as %(newnick)s."), { oldnick: nick, newnick: message.data }), "key": g_specialKey }); break; case "presence": - if (nickIndex == -1) // Changed presence, but not online (shouldn't ever happen) - break; - var [name, status, rating] = formatPlayerListEntry(nick, presence, stripColorCodes(ratingList[nickIndex])); - presenceList[nickIndex] = status; - playerList[nickIndex] = name; - ratingList[nickIndex] = rating; break; case "subject": updateSubject(message.text); @@ -744,13 +712,10 @@ function onTick() warn(sprintf("Unknown message.level '%(msglvl)s'", { msglvl: message.level })); break; } - // Push new data to GUI - playersBox.list_name = playerList; - playersBox.list_status = presenceList; - playersBox.list_rating = ratingList; - playersBox.list = nickList; - if (playersBox.selected >= playersBox.list.length) - playersBox.selected = -1; + // We might receive many join/leaves when returning to the lobby from a long game. + // 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) diff --git a/source/lobby/IXmppClient.h b/source/lobby/IXmppClient.h index 85b79ff05b..b826ff7e91 100644 --- a/source/lobby/IXmppClient.h +++ b/source/lobby/IXmppClient.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2014 Wildfire Games. +/* Copyright (C) 2015 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -47,8 +47,9 @@ public: virtual void GetPresence(const std::string& nickname, std::string& presence) = 0; virtual void GetRole(const std::string& nickname, std::string& role) = 0; virtual void GetSubject(std::string& subject) = 0; - virtual void GUIGetPlayerList(ScriptInterface& scriptInterface, JS::MutableHandleValue ret) = 0; + virtual void ClearPresenceUpdates() = 0; + virtual int GetMucMessageCount() = 0; virtual void GUIGetGameList(ScriptInterface& scriptInterface, JS::MutableHandleValue ret) = 0; virtual void GUIGetBoardList(ScriptInterface& scriptInterface, JS::MutableHandleValue ret) = 0; virtual void GUIGetProfile(ScriptInterface& scriptInterface, JS::MutableHandleValue ret) = 0; diff --git a/source/lobby/XmppClient.cpp b/source/lobby/XmppClient.cpp index c10ed84a39..208156d943 100644 --- a/source/lobby/XmppClient.cpp +++ b/source/lobby/XmppClient.cpp @@ -641,6 +641,33 @@ void XmppClient::PushGuiMessage(XmppClient::GUIMessage message) m_GuiMessageQueue.push_back(std::move(message)); } +/** + * Clears all presence updates from the message queue. + * Used when rejoining the lobby, since we don't need to handle past presence changes. + */ +void XmppClient::ClearPresenceUpdates() +{ + m_GuiMessageQueue.erase( + std::remove_if(m_GuiMessageQueue.begin(), m_GuiMessageQueue.end(), + [](XmppClient::GUIMessage& message) + { + return message.type == L"muc" && message.level == L"presence"; + } + ), m_GuiMessageQueue.end()); +} + +/** + * Used in order to update the GUI only once when multiple updates are queued. + */ +int XmppClient::GetMucMessageCount() +{ + return std::count_if(m_GuiMessageQueue.begin(), m_GuiMessageQueue.end(), + [](XmppClient::GUIMessage& message) + { + return message.type == L"muc"; + }); +} + /** * Handle a standard MUC textual message. */ diff --git a/source/lobby/XmppClient.h b/source/lobby/XmppClient.h index 4fac44b075..4417492734 100644 --- a/source/lobby/XmppClient.h +++ b/source/lobby/XmppClient.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2014 Wildfire Games. +/* Copyright (C) 2015 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -20,13 +20,11 @@ #include "IXmppClient.h" -#include "glooxwrapper/glooxwrapper.h" - -//game - script #include + +#include "glooxwrapper/glooxwrapper.h" #include "scriptinterface/ScriptVal.h" -//Game - script class ScriptInterface; namespace glooxwrapper @@ -38,18 +36,22 @@ namespace glooxwrapper class XmppClient : public IXmppClient, public glooxwrapper::ConnectionListener, public glooxwrapper::MUCRoomHandler, public glooxwrapper::IqHandler, public glooxwrapper::RegistrationHandler, public glooxwrapper::MessageHandler { NONCOPYABLE(XmppClient); + private: //Components glooxwrapper::Client* m_client; glooxwrapper::MUCRoom* m_mucRoom; glooxwrapper::Registration* m_registration; + //Account infos std::string m_username; std::string m_password; std::string m_nick; std::string m_xpartamuppId; + // State bool m_initialLoadComplete = false; + public: //Basic XmppClient(const std::string& sUsername, const std::string& sPassword, const std::string& sRoom, const std::string& sNick, const int historyRequestSize = 0, const bool regOpt = false); @@ -80,6 +82,7 @@ public: void GUIGetGameList(ScriptInterface& scriptInterface, JS::MutableHandleValue ret); void GUIGetBoardList(ScriptInterface& scriptInterface, JS::MutableHandleValue ret); void GUIGetProfile(ScriptInterface& scriptInterface, JS::MutableHandleValue ret); + //Script ScriptInterface& GetScriptInterface(); @@ -122,6 +125,7 @@ protected: void GetPresenceString(const gloox::Presence::PresenceType p, std::string& presence) const; void GetRoleString(const gloox::MUCRoomRole r, std::string& role) const; std::string StanzaErrorToString(gloox::StanzaError err); + public: /* Messages */ struct GUIMessage @@ -136,6 +140,8 @@ public: }; void GuiPollMessage(ScriptInterface& scriptInterface, JS::MutableHandleValue ret); void SendMUCMessage(const std::string& message); + void ClearPresenceUpdates(); + 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 = ""); diff --git a/source/lobby/scripting/JSInterface_Lobby.cpp b/source/lobby/scripting/JSInterface_Lobby.cpp index 1c37fa9f37..ddd9af4479 100644 --- a/source/lobby/scripting/JSInterface_Lobby.cpp +++ b/source/lobby/scripting/JSInterface_Lobby.cpp @@ -47,6 +47,8 @@ void JSI_Lobby::RegisterScriptFunctions(ScriptInterface& scriptInterface) scriptInterface.RegisterFunction("SendUnregisterGame"); scriptInterface.RegisterFunction("SendChangeStateGame"); scriptInterface.RegisterFunction("GetPlayerList"); + scriptInterface.RegisterFunction("LobbyClearPresenceUpdates"); + scriptInterface.RegisterFunction("LobbyGetMucMessageCount"); scriptInterface.RegisterFunction("GetGameList"); scriptInterface.RegisterFunction("GetBoardList"); scriptInterface.RegisterFunction("GetProfile"); @@ -189,6 +191,19 @@ JS::Value JSI_Lobby::GetPlayerList(ScriptInterface::CxPrivate* pCxPrivate) return playerList; } +void JSI_Lobby::LobbyClearPresenceUpdates(ScriptInterface::CxPrivate* UNUSED(pCxPrivate)) +{ + if (!g_XmppClient) + return; + + g_XmppClient->ClearPresenceUpdates(); +} + +int JSI_Lobby::LobbyGetMucMessageCount(ScriptInterface::CxPrivate* UNUSED(pCxPrivate)) +{ + return g_XmppClient ? g_XmppClient->GetMucMessageCount() : 0; +} + JS::Value JSI_Lobby::GetGameList(ScriptInterface::CxPrivate* pCxPrivate) { if (!g_XmppClient) diff --git a/source/lobby/scripting/JSInterface_Lobby.h b/source/lobby/scripting/JSInterface_Lobby.h index a0cc4f4118..f7a534c3aa 100644 --- a/source/lobby/scripting/JSInterface_Lobby.h +++ b/source/lobby/scripting/JSInterface_Lobby.h @@ -45,6 +45,8 @@ namespace JSI_Lobby void SendUnregisterGame(ScriptInterface::CxPrivate* pCxPrivate); void SendChangeStateGame(ScriptInterface::CxPrivate* pCxPrivate, std::wstring nbp, std::wstring players); JS::Value GetPlayerList(ScriptInterface::CxPrivate* pCxPrivate); + void LobbyClearPresenceUpdates(ScriptInterface::CxPrivate* pCxPrivate); + int LobbyGetMucMessageCount(ScriptInterface::CxPrivate* pCxPrivate); JS::Value GetGameList(ScriptInterface::CxPrivate* pCxPrivate); JS::Value GetBoardList(ScriptInterface::CxPrivate* pCxPrivate); JS::Value GetProfile(ScriptInterface::CxPrivate* pCxPrivate);