Ticket #3171: t3171_clear_muc_messages_v7_16836.patch

File t3171_clear_muc_messages_v7_16836.patch, 12.2 KB (added by elexis, 9 years ago)

Moves g_joined to the c++, so that presence updates will be sent only after you joined. Yesterday multiple people experienced the bug described in the comment above, but today I couldn't reproduce it with svn. I will have to apply this thing and the other lobby commits to a18 to test it thoroughly.

  • binaries/data/mods/public/gui/lobby/lobby.js

     
    1212var g_mapSizes = {};
    1313const g_mapTypesText = [translateWithContext("map", "Skirmish"), translateWithContext("map", "Random"), translate("Scenario")];
    1414const g_mapTypes = ["skirmish", "random", "scenario"];
    1515var g_userRating = ""; // Rating of user, defaults to Unrated
    1616var g_modPrefix = "@";
    17 var g_joined = false;
    1817// Block spammers for 30 seconds.
    1918var SPAM_BLOCK_LENGTH = 30;
    2019
    2120////////////////////////////////////////////////////////////////////////////////////////////////
    2221
     
    163162        logo.size = "50%-110 40 50%+110 140";
    164163    }
    165164}
    166165
    167166/**
    168  * Do a full update of the player listing, including ratings from cached C++ information.
     167 * Replace the playerlist with the current list cached in C++.
    169168 *
    170169 * @return Array containing the player, presence, nickname, and rating listings.
    171170 */
    172171function updatePlayerList()
    173172{
    174173    var playersBox = Engine.GetGUIObjectByName("playersBox");
    175174    var playerList = [];
    176175    var presenceList = [];
    177176    var nickList = [];
    178177    var ratingList = [];
    179     var cleanPlayerList = Engine.GetPlayerList();
     178    var cleanPlayerList = Engine.GetPlayerList(true);
    180179    // Sort the player list, ignoring case.
    181180    cleanPlayerList.sort(function(a,b)
    182181    {
    183182        switch (g_PlayerListSortBy)
    184183        {
     
    701700            case "join":
    702701                if (nick == g_Name)
    703702                {
    704703                    // We just joined, we need to get the full player list
    705704                    [playerList, presenceList, nickList, ratingList] = updatePlayerList();
    706                     // Don't display any joins until our join request bounces back
    707                     // Our join message should be the last one as we just got added to the stack
    708                     g_joined = true;
    709                     break;
    710705                }
    711                 else if (g_joined)
     706                else
    712707                {
    713708                    var [name, status, rating] = formatPlayerListEntry(nick, presence, "-");
    714709                    playerList.push(name);
    715710                    presenceList.push(status);
    716711                    nickList.push(nick);
     
    727722                nickList.splice(nickIndex, 1);
    728723                ratingList.splice(nickIndex, 1);
    729724                addChatMessage({ "text": "/special " + sprintf(translate("%(nick)s has left."), { nick: nick }), "key": g_specialKey });
    730725                break;
    731726            case "nick":
    732                 if (nickIndex == -1) // This shouldn't ever happen
     727                if (nickIndex == -1) // Changed nick, but not present
    733728                    break;
    734729                if (!isValidNick(message.data))
    735730                {
    736731                    addChatMessage({ "from": "system", "text": sprintf(translate("Invalid nickname: %(nick)s"), { nick: message.data })});
    737732                    break;
     
    742737                nickList[nickIndex] = message.data;
    743738                addChatMessage({ "text": "/special " + sprintf(translate("%(oldnick)s is now known as %(newnick)s."), { oldnick: nick, newnick: message.data }), "key": g_specialKey });
    744739                Engine.SendGetRatingList();
    745740                break;
    746741            case "presence":
    747                 if (nickIndex == -1) // This shouldn't ever happen
     742                if (nickIndex == -1) // Changed presence, but not online
    748743                    break;
    749744                var [name, status, rating] = formatPlayerListEntry(nick, presence, stripColorCodes(ratingList[nickIndex]));
    750745                presenceList[nickIndex] = status;
    751746                playerList[nickIndex] = name;
    752747                ratingList[nickIndex] = rating;
  • binaries/data/mods/public/gui/lobby/lobby.xml

     
    233233
    234234            <object name="chatPanel" size="0 49% 100% 100%" type="image" sprite="ModernDarkBoxGold">
    235235                <object name="chatText" size="0 0 100% 94%" type="text" style="ChatPanel" font="sans-13"/>
    236236                <object name="chatInput" size="0 94% 100% 100%" type="input" style="ModernInput" font="sans-13">
    237237                    <action on="Press">submitChatInput();</action>
    238                     <action on="Tab">autoCompleteNick("chatInput", Engine.GetPlayerList());</action>
     238                    <action on="Tab">autoCompleteNick("chatInput", Engine.GetPlayerList(false));</action>
    239239                </object>
    240240            </object>
    241241        </object>
    242242
    243243        <!-- START Window for leaderboard stats -->
  • source/lobby/IXmppClient.h

     
    5252    virtual void GUIGetGameList(ScriptInterface& scriptInterface, JS::MutableHandleValue ret) = 0;
    5353    virtual void GUIGetBoardList(ScriptInterface& scriptInterface, JS::MutableHandleValue ret) = 0;
    5454    virtual void GUIGetProfile(ScriptInterface& scriptInterface, JS::MutableHandleValue ret) = 0;
    5555
    5656    virtual void GuiPollMessage(ScriptInterface& scriptInterface, JS::MutableHandleValue ret) = 0;
     57    virtual void ClearPresenceUpdates() = 0;
    5758    virtual void SendMUCMessage(const std::string& message) = 0;
    5859};
    5960
    6061extern IXmppClient *g_XmppClient;
    6162extern bool g_rankedGame;
  • source/lobby/XmppClient.cpp

     
    7777
    7878    m_xpartamuppId = sXpartamupp + "@" + sServer + "/CC";
    7979    glooxwrapper::JID clientJid(sUsername + "@" + sServer + "/0ad");
    8080    glooxwrapper::JID roomJid(sRoom + "@conference." + sServer + "/" + sNick);
    8181
     82    m_Joined = false;
     83
    8284    // If we are connecting, use the full jid and a password
    8385    // If we are registering, only use the server name
    8486    if (!regOpt)
    8587        m_client = new glooxwrapper::Client(clientJid, sPassword);
    8688    else
     
    486488/*****************************************************
    487489 * Requests from GUI                                 *
    488490 *****************************************************/
    489491
    490492/**
     493 * If someone plays a game while being connected to the lobby, those presence updats
     494 * will pile up for the duration of the game (up to some thousands of updates in 1-2 hours) -
     495 * thus freezing the game for some seconds and spamming the lobby with joins and disconnects.
     496 *
     497 * The messages are also invalidated since lobby.js applies them to the refreshed playerlist
     498 * instead of the one from the time when the update arrived. This creates dupes that remain
     499 * online after the player left. More information on #3171.
     500 *
     501 * Therefore we remove all presence updates when replacing the playerlist with a current one.
     502 */
     503void XmppClient::ClearPresenceUpdates()
     504{
     505    std::remove_if(m_GuiMessageQueue.begin(), m_GuiMessageQueue.end(),
     506        [](XmppClient::GUIMessage& message)
     507        {
     508            return message.type == L"muc" && message.level != L"subject";
     509        }
     510    );
     511}
     512
     513/**
    491514 * Handle requests from the GUI for the list of players.
    492515 *
    493516 * @return A JS array containing all known players and their presences
    494517 */
    495518void XmppClient::GUIGetPlayerList(ScriptInterface& scriptInterface, JS::MutableHandleValue ret)
     
    789812            // we have a nick change
    790813            std::string newNick = participant.newNick.to_string();
    791814            m_PlayerMap[newNick].resize(3);
    792815            m_PlayerMap[newNick][0] = presenceString;
    793816            m_PlayerMap[newNick][2] = roleString;
    794             CreateSimpleMessage("muc", nick, "nick", participant.newNick.to_string());
     817            if (m_Joined)
     818                CreateSimpleMessage("muc", nick, "nick", participant.newNick.to_string());
    795819        }
    796         else
     820        else if (m_Joined)
    797821            CreateSimpleMessage("muc", nick, "leave");
    798822
    799823        DbgXMPP(nick << " left the room");
    800824        m_PlayerMap.erase(nick);
    801825    }
    802826    else
    803827    {
    804         if (m_PlayerMap.find(nick) == m_PlayerMap.end())
    805             CreateSimpleMessage("muc", nick, "join");
    806         else
    807             CreateSimpleMessage("muc", nick, "presence");
     828        if (nick == m_mucRoom->nick().to_string())
     829            m_Joined = true;
     830
     831        // Only send updates after we joined the room
     832        if (m_Joined)
     833        {
     834            if (m_PlayerMap.find(nick) == m_PlayerMap.end())
     835                CreateSimpleMessage("muc", nick, "join");
     836            else
     837                CreateSimpleMessage("muc", nick, "presence");
     838        }
    808839
    809840        DbgXMPP(nick << " is in the room, presence : " << (int)presenceType);
    810841        m_PlayerMap[nick].resize(3);
    811842        m_PlayerMap[nick][0] = presenceString;
    812843        m_PlayerMap[nick][2] = roleString;
  • source/lobby/XmppClient.h

     
    132132        std::wstring from;
    133133        std::wstring message;
    134134        std::string datetime;
    135135    };
    136136    void GuiPollMessage(ScriptInterface& scriptInterface, JS::MutableHandleValue ret);
     137    void ClearPresenceUpdates();
    137138    void SendMUCMessage(const std::string& message);
    138139    protected:
    139140    void PushGuiMessage(XmppClient::GUIMessage message);
    140141    void CreateSimpleMessage(const std::string& type, const std::string& text, const std::string& level = "standard", const std::string& data = "");
    141142
    142143private:
     144    // Whether or not we have successfully joined the lobby
     145    bool m_Joined;
    143146    /// Map of players
    144147    std::map<std::string, std::vector<std::string> > m_PlayerMap;
    145148    /// List of games
    146149    std::vector<const glooxwrapper::Tag*> m_GameList;
    147150    /// List of rankings
  • source/lobby/scripting/JSInterface_Lobby.cpp

     
    4444    scriptInterface.RegisterFunction<void, std::wstring, &JSI_Lobby::SendGetProfile>("SendGetProfile");
    4545    scriptInterface.RegisterFunction<void, JS::HandleValue, &JSI_Lobby::SendRegisterGame>("SendRegisterGame");
    4646    scriptInterface.RegisterFunction<void, JS::HandleValue, &JSI_Lobby::SendGameReport>("SendGameReport");
    4747    scriptInterface.RegisterFunction<void, &JSI_Lobby::SendUnregisterGame>("SendUnregisterGame");
    4848    scriptInterface.RegisterFunction<void, std::wstring, std::wstring, &JSI_Lobby::SendChangeStateGame>("SendChangeStateGame");
    49     scriptInterface.RegisterFunction<JS::Value, &JSI_Lobby::GetPlayerList>("GetPlayerList");
     49    scriptInterface.RegisterFunction<JS::Value, bool, &JSI_Lobby::GetPlayerList>("GetPlayerList");
    5050    scriptInterface.RegisterFunction<JS::Value, &JSI_Lobby::GetGameList>("GetGameList");
    5151    scriptInterface.RegisterFunction<JS::Value, &JSI_Lobby::GetBoardList>("GetBoardList");
    5252    scriptInterface.RegisterFunction<JS::Value, &JSI_Lobby::GetProfile>("GetProfile");
    5353    scriptInterface.RegisterFunction<JS::Value, &JSI_Lobby::LobbyGuiPollMessage>("LobbyGuiPollMessage");
    5454    scriptInterface.RegisterFunction<void, std::wstring, &JSI_Lobby::LobbySendMessage>("LobbySendMessage");
     
    173173    if (!g_XmppClient)
    174174        return;
    175175    g_XmppClient->SendIqChangeStateGame(utf8_from_wstring(nbp), utf8_from_wstring(players));
    176176}
    177177
    178 JS::Value JSI_Lobby::GetPlayerList(ScriptInterface::CxPrivate* pCxPrivate)
     178JS::Value JSI_Lobby::GetPlayerList(ScriptInterface::CxPrivate* pCxPrivate, bool clearPresenceUpdates = false)
    179179{
    180180    if (!g_XmppClient)
    181181        return JS::UndefinedValue();
    182182
    183183    JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
    184184    JSAutoRequest rq(cx);
    185185       
     186    if (clearPresenceUpdates)
     187        g_XmppClient->ClearPresenceUpdates();
     188
    186189    JS::RootedValue playerList(cx);
    187190    g_XmppClient->GUIGetPlayerList(*(pCxPrivate->pScriptInterface), &playerList);
    188191
    189192    return playerList;
    190193}
  • source/lobby/scripting/JSInterface_Lobby.h

     
    4242    void SendGetProfile(ScriptInterface::CxPrivate* pCxPrivate, std::wstring player);
    4343    void SendGameReport(ScriptInterface::CxPrivate* pCxPrivate, JS::HandleValue data);
    4444    void SendRegisterGame(ScriptInterface::CxPrivate* pCxPrivate, JS::HandleValue data);
    4545    void SendUnregisterGame(ScriptInterface::CxPrivate* pCxPrivate);
    4646    void SendChangeStateGame(ScriptInterface::CxPrivate* pCxPrivate, std::wstring nbp, std::wstring players);
    47     JS::Value GetPlayerList(ScriptInterface::CxPrivate* pCxPrivate);
     47    JS::Value GetPlayerList(ScriptInterface::CxPrivate* pCxPrivate, bool clearPresenceUpdates);
    4848    JS::Value GetGameList(ScriptInterface::CxPrivate* pCxPrivate);
    4949    JS::Value GetBoardList(ScriptInterface::CxPrivate* pCxPrivate);
    5050    JS::Value GetProfile(ScriptInterface::CxPrivate* pCxPrivate);
    5151    JS::Value LobbyGuiPollMessage(ScriptInterface::CxPrivate* pCxPrivate);
    5252    void LobbySendMessage(ScriptInterface::CxPrivate* pCxPrivate, std::wstring message);