Ticket #3386: t3386_fix_lobby_rejoin_v3.patch

File t3386_fix_lobby_rejoin_v3.patch, 13.1 KB (added by elexis, 9 years ago)

Implements Joshuas proposal and always calls updatePlayerList instead of doing this useless / duplicate / broken code in session.js. In contrast to prior patches, only presence updates will be cleared when returning from the lobby. This way you will still get notifications in the chat area who has joined and left while you were playing. The new function LobbyGetMucMessageCount was implemented, so that we call updatePlayerList only when receiving the last update in the queue. Notice that we don't need the error messages anymore, since we know the C++ queue always has it right and since we removed the duplicate playerlist logic in session.js.

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

     
    4646    mapTypeFilter.list_data = [""].concat(g_mapTypes);
    4747
    4848    Engine.LobbySetPlayerPresence("available");
    4949    Engine.SendGetGameList();
    5050    Engine.SendGetBoardList();
     51
     52    // When rejoining the lobby after a game, we don't need to process presence changes
     53    Engine.LobbyClearPresenceUpdates();
    5154    updatePlayerList();
     55
    5256    updateSubject(Engine.LobbyGetRoomSubject());
    5357
    5458    resetFilters();
    5559}
    5660
     
    231235    playersBox.list_status = presenceList;
    232236    playersBox.list_rating = ratingList;
    233237    playersBox.list = nickList;
    234238    if (playersBox.selected >= playersBox.list.length)
    235239        playersBox.selected = -1;
    236     return [playerList, presenceList, nickList, ratingList];
    237240}
    238241
    239242/**
    240243 * Display the profile of the selected player.
    241244 * Displays N/A for all stats until updateProfile is called when the stats
     
    687690            var from = escapeText(message.from);
    688691            addChatMessage({ "from": from, "text": text, "datetime": message.datetime});
    689692            break;
    690693        case "muc":
    691694            var nick = message.text;
    692             var presence = Engine.LobbyGetPlayerPresence(nick);
    693             var playersBox = Engine.GetGUIObjectByName("playersBox");
    694             var playerList = playersBox.list_name;
    695             var presenceList = playersBox.list_status;
    696             var nickList = playersBox.list;
    697             var ratingList = playersBox.list_rating;
    698             var nickIndex = nickList.indexOf(nick);
    699695            switch(message.level)
    700696            {
    701697            case "join":
    702                 var [name, status, rating] = formatPlayerListEntry(nick, presence, "-");
    703                 playerList.push(name);
    704                 presenceList.push(status);
    705                 nickList.push(nick);
    706                 ratingList.push(String(rating));
    707698                addChatMessage({ "text": "/special " + sprintf(translate("%(nick)s has joined."), { nick: nick }), "key": g_specialKey });
    708699                break;
    709700            case "leave":
    710                 if (nickIndex == -1) // Left, but not present (TODO: warn about this?)
    711                     break;
    712                 playerList.splice(nickIndex, 1);
    713                 presenceList.splice(nickIndex, 1);
    714                 nickList.splice(nickIndex, 1);
    715                 ratingList.splice(nickIndex, 1);
    716701                addChatMessage({ "text": "/special " + sprintf(translate("%(nick)s has left."), { nick: nick }), "key": g_specialKey });
    717702                break;
    718703            case "nick":
    719                 if (nickIndex == -1) // Changed nick, but not present (shouldn't ever happen)
    720                     break;
    721                 if (!isValidNick(message.data))
    722                 {
    723                     addChatMessage({ "from": "system", "text": sprintf(translate("Invalid nickname: %(nick)s"), { nick: message.data })});
    724                     break;
    725                 }
    726                 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
    727                 playerList[nickIndex] = name;
    728                 // presence stays the same
    729                 nickList[nickIndex] = message.data;
    730704                addChatMessage({ "text": "/special " + sprintf(translate("%(oldnick)s is now known as %(newnick)s."), { oldnick: nick, newnick: message.data }), "key": g_specialKey });
    731705                break;
    732706            case "presence":
    733                 if (nickIndex == -1) // Changed presence, but not online (shouldn't ever happen)
    734                     break;
    735                 var [name, status, rating] = formatPlayerListEntry(nick, presence, stripColorCodes(ratingList[nickIndex]));
    736                 presenceList[nickIndex] = status;
    737                 playerList[nickIndex] = name;
    738                 ratingList[nickIndex] = rating;
    739707                break;
    740708            case "subject":
    741709                updateSubject(message.text);
    742710                break;
    743711            default:
    744712                warn(sprintf("Unknown message.level '%(msglvl)s'", { msglvl: message.level }));
    745713                break;
    746714            }
    747             // Push new data to GUI
    748             playersBox.list_name = playerList;
    749             playersBox.list_status = presenceList;
    750             playersBox.list_rating = ratingList;
    751             playersBox.list = nickList;     
    752             if (playersBox.selected >= playersBox.list.length)
    753                 playersBox.selected = -1;
     715            // We might receive many join/leaves when returning to the lobby from a long game.
     716            // To improve performance, only update the playerlist GUI when the last update in the current stack is processed
     717            if (Engine.LobbyGetMucMessageCount() == 0)
     718                updatePlayerList();
    754719            break;
    755720        case "system":
    756721            switch (message.level)
    757722            {
    758723            case "standard":
  • source/lobby/IXmppClient.h

     
    1 /* Copyright (C) 2014 Wildfire Games.
     1/* Copyright (C) 2015 Wildfire Games.
    22 * This file is part of 0 A.D.
    33 *
    44 * 0 A.D. is free software: you can redistribute it and/or modify
    55 * it under the terms of the GNU General Public License as published by
    66 * the Free Software Foundation, either version 2 of the License, or
     
    4545    virtual void ban(const std::string& nick, const std::string& reason) = 0;
    4646    virtual void SetPresence(const std::string& presence) = 0;
    4747    virtual void GetPresence(const std::string& nickname, std::string& presence) = 0;
    4848    virtual void GetRole(const std::string& nickname, std::string& role) = 0;
    4949    virtual void GetSubject(std::string& subject) = 0;
    50 
    5150    virtual void GUIGetPlayerList(ScriptInterface& scriptInterface, JS::MutableHandleValue ret) = 0;
     51    virtual void ClearPresenceUpdates() = 0;
     52    virtual int GetMucMessageCount() = 0;
    5253    virtual void GUIGetGameList(ScriptInterface& scriptInterface, JS::MutableHandleValue ret) = 0;
    5354    virtual void GUIGetBoardList(ScriptInterface& scriptInterface, JS::MutableHandleValue ret) = 0;
    5455    virtual void GUIGetProfile(ScriptInterface& scriptInterface, JS::MutableHandleValue ret) = 0;
    5556
    5657    virtual void GuiPollMessage(ScriptInterface& scriptInterface, JS::MutableHandleValue ret) = 0;
  • source/lobby/XmppClient.cpp

     
    640640{
    641641    m_GuiMessageQueue.push_back(std::move(message));
    642642}
    643643
    644644/**
     645 * Clears all presence updates from the message queue.
     646 * Used when rejoining the lobby, since we don't need to handle past presence changes.
     647 */
     648void XmppClient::ClearPresenceUpdates()
     649{
     650    m_GuiMessageQueue.erase(
     651        std::remove_if(m_GuiMessageQueue.begin(), m_GuiMessageQueue.end(),
     652            [](XmppClient::GUIMessage& message)
     653            {
     654                return message.type == L"muc" && message.level == L"presence";
     655            }
     656    ), m_GuiMessageQueue.end());
     657}
     658
     659/**
     660 * Used in order to update the GUI only once when multiple updates are queued.
     661 *
     662 * @return number of join/leave events currently queued.
     663 */
     664int XmppClient::GetMucMessageCount()
     665{
     666    return std::count_if(m_GuiMessageQueue.begin(), m_GuiMessageQueue.end(),
     667        [](XmppClient::GUIMessage& message)
     668        {
     669            return message.type == L"muc";
     670        });
     671}
     672
     673/**
    645674 * Handle a standard MUC textual message.
    646675 */
    647676void XmppClient::handleMUCMessage(glooxwrapper::MUCRoom*, const glooxwrapper::Message& msg, bool)
    648677{
    649678    DbgXMPP(msg.from().resource() << " said " << msg.body());
  • source/lobby/XmppClient.h

     
    1 /* Copyright (C) 2014 Wildfire Games.
     1/* Copyright (C) 2015 Wildfire Games.
    22 * This file is part of 0 A.D.
    33 *
    44 * 0 A.D. is free software: you can redistribute it and/or modify
    55 * it under the terms of the GNU General Public License as published by
    66 * the Free Software Foundation, either version 2 of the License, or
     
    1818#ifndef XXXMPPCLIENT_H
    1919#define XXXMPPCLIENT_H
    2020
    2121#include "IXmppClient.h"
    2222
    23 #include "glooxwrapper/glooxwrapper.h"
    24 
    25 //game - script
    2623#include <deque>
     24
     25#include "glooxwrapper/glooxwrapper.h"
    2726#include "scriptinterface/ScriptVal.h"
    2827
    29 //Game - script
    3028class ScriptInterface;
    3129
    3230namespace glooxwrapper
    3331{
    3432    class Client;
     
    3634}
    3735
    3836class XmppClient : public IXmppClient, public glooxwrapper::ConnectionListener, public glooxwrapper::MUCRoomHandler, public glooxwrapper::IqHandler, public glooxwrapper::RegistrationHandler, public glooxwrapper::MessageHandler
    3937{
    4038    NONCOPYABLE(XmppClient);
     39
    4140private:
    4241    //Components
    4342    glooxwrapper::Client* m_client;
    4443    glooxwrapper::MUCRoom* m_mucRoom;
    4544    glooxwrapper::Registration* m_registration;
     45
    4646    //Account infos
    4747    std::string m_username;
    4848    std::string m_password;
    4949    std::string m_nick;
    5050    std::string m_xpartamuppId;
     51
    5152    // State
    5253    bool m_initialLoadComplete = false;
     54
    5355public:
    5456    //Basic
    5557    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);
    5658    virtual ~XmppClient();
    5759
     
    7880
    7981    void GUIGetPlayerList(ScriptInterface& scriptInterface, JS::MutableHandleValue ret);
    8082    void GUIGetGameList(ScriptInterface& scriptInterface, JS::MutableHandleValue ret);
    8183    void GUIGetBoardList(ScriptInterface& scriptInterface, JS::MutableHandleValue ret);
    8284    void GUIGetProfile(ScriptInterface& scriptInterface, JS::MutableHandleValue ret);
     85
    8386    //Script
    8487    ScriptInterface& GetScriptInterface();
    8588
    8689protected:
    8790    /* Xmpp handlers */
     
    120123
    121124    // Helpers
    122125    void GetPresenceString(const gloox::Presence::PresenceType p, std::string& presence) const;
    123126    void GetRoleString(const gloox::MUCRoomRole r, std::string& role) const;
    124127    std::string StanzaErrorToString(gloox::StanzaError err);
     128
    125129public:
    126130    /* Messages */
    127131    struct GUIMessage
    128132    {
    129133        std::wstring type;
     
    134138        std::wstring message;
    135139        std::string datetime;
    136140    };
    137141    void GuiPollMessage(ScriptInterface& scriptInterface, JS::MutableHandleValue ret);
    138142    void SendMUCMessage(const std::string& message);
     143    void ClearPresenceUpdates();
     144    int GetMucMessageCount();
    139145    protected:
    140146    void PushGuiMessage(XmppClient::GUIMessage message);
    141147    void CreateSimpleMessage(const std::string& type, const std::string& text, const std::string& level = "standard", const std::string& data = "");
    142148
    143149private:
  • source/lobby/scripting/JSInterface_Lobby.cpp

     
    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");
    4949    scriptInterface.RegisterFunction<JS::Value, &JSI_Lobby::GetPlayerList>("GetPlayerList");
     50    scriptInterface.RegisterFunction<void, &JSI_Lobby::LobbyClearPresenceUpdates>("LobbyClearPresenceUpdates");
     51    scriptInterface.RegisterFunction<int, &JSI_Lobby::LobbyGetMucMessageCount>("LobbyGetMucMessageCount");
    5052    scriptInterface.RegisterFunction<JS::Value, &JSI_Lobby::GetGameList>("GetGameList");
    5153    scriptInterface.RegisterFunction<JS::Value, &JSI_Lobby::GetBoardList>("GetBoardList");
    5254    scriptInterface.RegisterFunction<JS::Value, &JSI_Lobby::GetProfile>("GetProfile");
    5355    scriptInterface.RegisterFunction<JS::Value, &JSI_Lobby::LobbyGuiPollMessage>("LobbyGuiPollMessage");
    5456    scriptInterface.RegisterFunction<void, std::wstring, &JSI_Lobby::LobbySendMessage>("LobbySendMessage");
     
    187189    g_XmppClient->GUIGetPlayerList(*(pCxPrivate->pScriptInterface), &playerList);
    188190
    189191    return playerList;
    190192}
    191193
     194void JSI_Lobby::LobbyClearPresenceUpdates(ScriptInterface::CxPrivate* UNUSED(pCxPrivate))
     195{
     196    if (!g_XmppClient)
     197        return;
     198
     199    g_XmppClient->ClearPresenceUpdates();
     200}
     201
     202int JSI_Lobby::LobbyGetMucMessageCount(ScriptInterface::CxPrivate* UNUSED(pCxPrivate))
     203{
     204    return g_XmppClient ? g_XmppClient->GetMucMessageCount() : 0;
     205}
     206
    192207JS::Value JSI_Lobby::GetGameList(ScriptInterface::CxPrivate* pCxPrivate)
    193208{
    194209    if (!g_XmppClient)
    195210        return JS::UndefinedValue();
    196211
  • source/lobby/scripting/JSInterface_Lobby.h

     
    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);
    4747    JS::Value GetPlayerList(ScriptInterface::CxPrivate* pCxPrivate);
     48    void LobbyClearPresenceUpdates(ScriptInterface::CxPrivate* pCxPrivate);
     49    int LobbyGetMucMessageCount(ScriptInterface::CxPrivate* pCxPrivate);
    4850    JS::Value GetGameList(ScriptInterface::CxPrivate* pCxPrivate);
    4951    JS::Value GetBoardList(ScriptInterface::CxPrivate* pCxPrivate);
    5052    JS::Value GetProfile(ScriptInterface::CxPrivate* pCxPrivate);
    5153    JS::Value LobbyGuiPollMessage(ScriptInterface::CxPrivate* pCxPrivate);
    5254    void LobbySendMessage(ScriptInterface::CxPrivate* pCxPrivate, std::wstring message);