Ticket #2371: ratingplayerlist.patch

File ratingplayerlist.patch, 32.0 KB (added by scythetwirler, 10 years ago)
  • binaries/data/mods/public/gui/lobby/lobby.js

     
    3636    Engine.LobbySetPlayerPresence("available");
    3737    Engine.SendGetGameList();
    3838    Engine.SendGetBoardList();
     39    Engine.SendGetRatingList();
    3940    updatePlayerList();
    4041
    4142    resetFilters();
     
    105106    return true;
    106107}
    107108
    108 // Do a full update of the player listing **Only call on init**
     109// Do a full update of the player listing, including ratings.
    109110function updatePlayerList()
    110111{
    111112    var playersBox = Engine.GetGUIObjectByName("playersBox");
    112     [playerList, presenceList, nickList] = [[],[],[]];
     113    [playerList, presenceList, nickList, ratingList] = [[],[],[],[]];
     114    var ratingsmap = Engine.GetRatingList();
     115    var defaultrating;
    113116    for each (var p in Engine.GetPlayerList())
    114117    {
    115         var [name, status] = formatPlayerListEntry(p.name, p.presence);
     118        defaultrating = '    -'; //Start with unrated. If no rating is found, keep it unrated.
     119        for each (var user in ratingsmap)
     120        {
     121            if (user.name.toLowerCase() == p.name.toLowerCase())
     122            {
     123                defaultrating = user.rating;
     124                break;
     125            }
     126        }
     127        var [name, status, rating] = formatPlayerListEntry(p.name, p.presence, defaultrating);
    116128        playerList.push(name);
    117129        presenceList.push(status);
    118130        nickList.push(p.name);
     131        ratingList.push(String("  " + rating));
    119132    }
    120133    playersBox.list_name = playerList;
    121134    playersBox.list_status = presenceList;
    122     playersBox.list = nickList;
     135    playersBox.list_rating = ratingList;
     136    playersBox.list = nickList;
    123137    if (playersBox.selected >= playersBox.list.length)
    124138        playersBox.selected = -1;
    125     return [playerList, presenceList, nickList];
     139    return [playerList, presenceList, nickList, ratingList];
    126140}
    127141
    128142// Update leaderboard listing
     
    229243}
    230244
    231245// The following function colorizes and formats the entries in the player list.
    232 function formatPlayerListEntry(nickname, presence)
     246function formatPlayerListEntry(nickname, presence, rating)
    233247{
    234248    // Set colors based on player status
     249    var color;
    235250    var color_close = '[/color]';
    236251    switch (presence)
    237252    {
    238253    case "playing":
    239         var color = '[color="125 0 0"]';
     254        color = '[color="125 0 0"]';
    240255        var status = color + "Busy" + color_close;
    241256        break;
    242257    case "gone":
    243258    case "away":
    244         var color = '[color="229 76 13"]';
     259        color = '[color="229 76 13"]';
    245260        var status = color + "Away" + color_close;
    246261        break;
    247262    case "available":
    248         var color = '[color="0 125 0"]';
     263        color = '[color="0 125 0"]';
    249264        var status = color + "Online" + color_close;
    250265        break;
    251266    case "offline":
    252         var color = '[color="0 0 0"]';
     267        color = '[color="0 0 0"]';
    253268        var status = color + "Offline" + color_close;
    254269        break;
    255270    default:
    256271        warn("Unknown presence '"+presence+"'");
    257         var color = '[color="178 178 178"]';
     272        color = '[color="178 178 178"]';
    258273        var status = color + "Unknown" + color_close;
    259274        break;
    260275    }
    261 
     276    var elo = color + rating + color_close;
    262277    var name = colorPlayerName(nickname);
    263278
    264279    // Push this player's name and status onto the list
    265     return [name, status];
     280    return [name, status, elo];
    266281}
    267282
    268283function selectGame(selected)
     
    349364    return n < 10 ? "0" + n : n;
    350365}
    351366
     367function stripColorCodes(input)
     368{
     369    return input.replace(/\[(\w+)[^w]*?](.*?)\[\/\1]/g, '$2');
     370}
     371
    352372////////////////////////////////////////////////////////////////////////////////////////////////
    353373// GUI event handlers
    354374////////////////////////////////////////////////////////////////////////////////////////////////
     
    384404            var playerList = playersBox.list_name;
    385405            var presenceList = playersBox.list_status;
    386406            var nickList = playersBox.list;
     407            var ratingList = playersBox.list_rating;
    387408            var nickIndex = nickList.indexOf(nick);
    388409            switch(message.level)
    389410            {
     
    391412                if (nick == g_Name)
    392413                {
    393414                    // We just joined, we need to get the full player list
    394                     [playerList, presenceList, nickList] = updatePlayerList();
     415                    [playerList, presenceList, nickList, ratingList] = updatePlayerList();
    395416                    break;
    396417                }
    397                 var [name, status] = formatPlayerListEntry(nick, presence);
     418                var [name, status, rating] = formatPlayerListEntry(nick, presence, "    -");
    398419                playerList.push(name);
    399420                presenceList.push(status);
    400421                nickList.push(nick);
     422                ratingList.push(String(rating));
     423                Engine.SendGetRatingList();
    401424                addChatMessage({ "text": "/special " + nick + " has joined.", "key": g_specialKey });
    402425                break;
    403426            case "leave":
     
    406429                playerList.splice(nickIndex, 1);
    407430                presenceList.splice(nickIndex, 1);
    408431                nickList.splice(nickIndex, 1);
     432                ratingList.splice(nickIndex, 1);
    409433                addChatMessage({ "text": "/special " + nick + " has left.", "key": g_specialKey });
    410434                break;
    411435            case "nick":
     
    416440                    addChatMessage({ "from": "system", "text": "Invalid nickname: " + message.data });
    417441                    break;
    418442                }
    419                 var [name, status] = formatPlayerListEntry(message.data, presence); // TODO: actually we don't want to change the presence here, so use what was used before
     443                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
    420444                playerList[nickIndex] = name;
    421445                // presence stays the same
    422446                nickList[nickIndex] = message.data;
    423447                addChatMessage({ "text": "/special " + nick + " is now known as " + message.data + ".", "key": g_specialKey });
     448                Engine.SendGetRatingList();
    424449                break;
    425450            case "presence":
    426451                if (nickIndex == -1) // This shouldn't ever happen
    427452                    break;
    428                 var [name, status] = formatPlayerListEntry(nick, presence);
     453                var [name, status, rating] = formatPlayerListEntry(nick, presence, stripColorCodes(ratingList[nickIndex]));
    429454                presenceList[nickIndex] = status;
    430455                playerList[nickIndex] = name;
     456                ratingList[nickIndex] = rating;
    431457                break;
    432458            default:
    433459                warn("Unknown message.level '" + message.level + "'");
     
    436462            // Push new data to GUI
    437463            playersBox.list_name = playerList;
    438464            playersBox.list_status = presenceList;
    439             playersBox.list = nickList;
     465            playersBox.list_rating = ratingList;
     466            playersBox.list = nickList;     
    440467            if (playersBox.selected >= playersBox.list.length)
    441468                playersBox.selected = -1;
    442469            break;
     
    471498                case "boardlist updated":
    472499                    updateBoardList();
    473500                    break;
     501                case "ratinglist updated":
     502                    updatePlayerList();
     503                    break;
    474504                }
    475505                break
    476506            }
     
    542572    case "back":
    543573        Engine.LobbySetPlayerPresence("available");
    544574        break;
    545     case "nick":
    546         if (g_spammers[g_Name] != undefined)
    547             break;
    548         // Strip invalid characters.
    549         nick = sanitizePlayerName(nick, true, true);
    550         Engine.LobbySetNick(nick);
    551         g_Name = nick;
    552         break;
    553575    case "kick": // TODO: Split reason from nick and pass it too, for now just support "/kick nick"
    554576            // also allow quoting nicks (and/or prevent users from changing it here, but that doesn't help if the spammer uses a different client)
    555577        Engine.LobbyKick(nick, "");
  • binaries/data/mods/public/gui/lobby/lobby.xml

     
    1919        </action>
    2020
    2121        <!-- Left panel: Player list. -->
    22         <object name="leftPanel" size="20 30 15% 100%-50">
    23             <object name="playersBox" style="ModernList" type="olist" size="0 0 100% 100%">
    24                 <def id="status" heading="Status" width="40%"/>
    25                 <def id="name" heading="Name" width="60%"/>
     22        <object name="leftPanel" size="20 30 20% 100%-50">
     23            <object name="playersBox" style="ModernList" type="olist" size="0 0 100% 100%" font="serif-bold-13">
     24                <def id="status" heading="Status" width="28%"/>
     25                <def id="name" heading="Name" width="47%"/>
     26                <def id="rating" heading="Rating" width="25%" />
    2627            </object>
    2728        </object>
    2829
    29         <object name="leftButtonPanel" size="20 100%-45 15% 100%-20">
     30        <object name="leftButtonPanel" size="20 100%-45 20% 100%-20">
    3031            <object type="button" style="StoneButton" size="0 0 100% 100%">
    3132                Leaderboard
    3233                <action on="Press">Engine.GetGUIObjectByName("leaderboard").hidden = false;Engine.GetGUIObjectByName("leaderboardFade").hidden = false;</action>
     
    3435        </object>
    3536
    3637        <!-- Right panel: Game details. -->
    37         <object name="rightPanel" size="100%-300 30 100%-20 100%-20">
     38        <object name="rightPanel" size="100%-250 30 100%-20 100%-20" >
    3839            <object name="gameInfoEmpty" size="0 0 100% 100%-60" type="image" sprite="ModernDarkBoxGold" hidden="false">
    3940                <object size="50%-110 50%-50 50%+110 50%+50" type="image" sprite="productLogo"/>
    4041            </object>
     
    106107        </object>
    107108
    108109        <!-- Middle panel: Filters, game list, chat box. -->
    109         <object name="middlePanel" size="15%+5 5% 100%-305 97.2%">
    110             <object name="gamesBox" style="ModernList" type="olist" size="0 25 100% 48%">
     110        <object name="middlePanel" size="20%+5 5% 100%-255 97.2%">
     111            <object name="gamesBox" style="ModernList" type="olist" size="0 25 100% 48%" font="serif-bold-13">
    111112                <action on="SelectionChange">selectGame(this.selected);</action>
    112113                <def id="name" heading="Name" color="0 60 0" width="25%"/>
    113114                <!--<def id="ip" heading="IP" color="0 128 128" width="170"/>-->
     
    121122                <object name="mapSizeFilter"
    122123                    type="dropdown"
    123124                    style="ModernDropDown"
    124                     size="49.7% 0 62% 100%">
     125                    size="49.7% 0 62% 100%"
     126                    font="serif-bold-13">
    125127                    <action on="SelectionChange">applyFilters();</action>
    126128                </object>
    127129
    128130                <object name="mapTypeFilter"
    129131                    type="dropdown"
    130132                    style="ModernDropDown"
    131                     size="69.3% 0 82% 100%">
     133                    size="69.3% 0 82% 100%"
     134                    font="serif-bold-13">
    132135                    <action on="SelectionChange">applyFilters();</action>
    133136                </object>
    134137
    135138                <object name="playersNumberFilter"
    136139                    type="dropdown"
    137140                    style="ModernDropDown"
    138                     size="89% 0 100% 100%">
     141                    size="89% 0 100% 100%"
     142                    font="serif-bold-13">
    139143                    <action on="SelectionChange">applyFilters();</action>
    140144                </object>
    141145
    142                 <object type="text" size="22 0 35% 100%" text_align="left" textcolor="white">Show full games</object>
     146                <object type="text" size="22 0 35% 100%" text_align="left" textcolor="white" font="serif-bold-13">Show full games</object>
    143147                <object name="showFullFilter"
    144148                    type="checkbox"
    145149                    checked="true"
    146150                    style="ModernTickBox"
    147                     size="0% 0 20 100%">
     151                    size="0% 0 20 100%"
     152                    font="serif-bold-13">
    148153                    <action on="Press">applyFilters();</action>
    149154                </object>
    150155            </object>
    151156
    152157            <object name="chatPanel" size="0 49% 100% 100%" type="image" sprite="ModernDarkBoxGold">
    153                 <object name="chatText" size="0 0 100% 94%" type="text" style="ChatPanel"/>
    154                 <object name="chatInput" size="0 94% 100% 100%" type="input" style="ModernInput">
     158                <object name="chatText" size="0 0 100% 94%" type="text" style="ChatPanel" font="serif-13"/>
     159                <object name="chatInput" size="0 94% 100% 100%" type="input" style="ModernInput" font="serif-13">
    155160                    <action on="Press">submitChatInput();</action>
    156161                    <action on="Tab">completeNick();</action>
    157162                </object>
  • source/gui/scripting/ScriptFunctions.cpp

     
    891891    scriptInterface.RegisterFunction<void, &JSI_Lobby::RecvXmppClient>("RecvXmppClient");
    892892    scriptInterface.RegisterFunction<void, &JSI_Lobby::SendGetGameList>("SendGetGameList");
    893893    scriptInterface.RegisterFunction<void, &JSI_Lobby::SendGetBoardList>("SendGetBoardList");
     894    scriptInterface.RegisterFunction<void, &JSI_Lobby::SendGetRatingList>("SendGetRatingList");
    894895    scriptInterface.RegisterFunction<void, CScriptVal, &JSI_Lobby::SendRegisterGame>("SendRegisterGame");
    895896    scriptInterface.RegisterFunction<void, CScriptVal, &JSI_Lobby::SendGameReport>("SendGameReport");
    896897    scriptInterface.RegisterFunction<void, &JSI_Lobby::SendUnregisterGame>("SendUnregisterGame");
     
    898899    scriptInterface.RegisterFunction<CScriptVal, &JSI_Lobby::GetPlayerList>("GetPlayerList");
    899900    scriptInterface.RegisterFunction<CScriptVal, &JSI_Lobby::GetGameList>("GetGameList");
    900901    scriptInterface.RegisterFunction<CScriptVal, &JSI_Lobby::GetBoardList>("GetBoardList");
     902    scriptInterface.RegisterFunction<CScriptVal, &JSI_Lobby::GetBoardList>("GetRatingList");
    901903    scriptInterface.RegisterFunction<CScriptVal, &JSI_Lobby::LobbyGuiPollMessage>("LobbyGuiPollMessage");
    902904    scriptInterface.RegisterFunction<void, std::wstring, &JSI_Lobby::LobbySendMessage>("LobbySendMessage");
    903905    scriptInterface.RegisterFunction<void, std::wstring, &JSI_Lobby::LobbySetPlayerPresence>("LobbySetPlayerPresence");
  • source/lobby/IXmppClient.h

     
    1 /* Copyright (C) 2013 Wildfire Games.
     1/* Copyright (C) 2014 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
     
    3333    virtual void recv() = 0;
    3434    virtual void SendIqGetGameList() = 0;
    3535    virtual void SendIqGetBoardList() = 0;
     36    virtual void SendIqGetRatingList() = 0;
    3637    virtual void SendIqGameReport(ScriptInterface& scriptInterface, CScriptVal data) = 0;
    3738    virtual void SendIqRegisterGame(ScriptInterface& scriptInterface, CScriptVal data) = 0;
    3839    virtual void SendIqUnregisterGame() = 0;
  • source/lobby/StanzaExtensions.cpp

     
    1 /* Copyright (C) 2013 Wildfire Games.
     1/* Copyright (C) 2014 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
     
    5959}
    6060
    6161/******************************************************
    62  * BoardListQuery, custom IQ Stanza, used solely to
    63  * request and receive leaderboard data from server.
     62 * BoardListQuery, a flexible custom IQ Stanza useful for anything with ratings, used to
     63 * request and receive leaderboard and rating data from server.
     64 * Example stanza:
     65 * <board player="foobar">1200</board>
    6466 */
    6567BoardListQuery::BoardListQuery( const glooxwrapper::Tag* tag ):StanzaExtension( ExtBoardListQuery )
    6668{
    6769    if( !tag || tag->name() != "query" || tag->xmlns() != XMLNS_BOARDLIST )
    6870        return;
    69 
     71   
     72    const glooxwrapper::Tag* c = tag->findTag_clone( "query/command" );
     73    if (c)
     74        m_Command = c->cdata();
     75    glooxwrapper::Tag::free(c);
    7076    const glooxwrapper::ConstTagList boardTags = tag->findTagList_clone( "query/board" );
    7177    glooxwrapper::ConstTagList::const_iterator it = boardTags.begin();
    7278    for ( ; it != boardTags.end(); ++it )
    73         m_BoardList.push_back( *it );
     79    {
     80        m_StanzaBoardList.push_back( *it );
     81    }
    7482}
    7583
    7684/**
    77  * Required by gloox, used to find the BoardList element in a recived IQ.
     85 * Required by gloox, used to find the BoardList element in a received IQ.
    7886 */
    7987const glooxwrapper::string& BoardListQuery::filterString() const
    8088{
     
    8997{
    9098    glooxwrapper::Tag* t = glooxwrapper::Tag::allocate( "query" );
    9199    t->setXmlns( XMLNS_BOARDLIST );
     100   
     101    // Check for ratinglist or boardlist command
     102    if(!m_Command.empty())
     103        t->addChild(glooxwrapper::Tag::allocate("command", m_Command));
    92104
    93     std::vector<const glooxwrapper::Tag*>::const_iterator it = m_BoardList.begin();
    94     for( ; it != m_BoardList.end(); ++it )
     105    std::vector<const glooxwrapper::Tag*>::const_iterator it = m_StanzaBoardList.begin();
     106    for( ; it != m_StanzaBoardList.end(); ++it )
    95107        t->addChild( (*it)->clone() );
    96108
    97109    return t;
     
    105117
    106118BoardListQuery::~BoardListQuery()
    107119{
    108     std::vector<const glooxwrapper::Tag*>::const_iterator it = m_BoardList.begin();
    109     for( ; it != m_BoardList.end(); ++it )
     120    std::vector<const glooxwrapper::Tag*>::const_iterator it = m_StanzaBoardList.begin();
     121    for( ; it != m_StanzaBoardList.end(); ++it )
    110122        glooxwrapper::Tag::free(*it);
    111     m_BoardList.clear();
     123    m_StanzaBoardList.clear();
    112124}
    113125
    114126/******************************************************
     
    133145}
    134146
    135147/**
    136  * Required by gloox, used to find the GameList element in a recived IQ.
     148 * Required by gloox, used to find the GameList element in a received IQ.
    137149 */
    138150const glooxwrapper::string& GameListQuery::filterString() const
    139151{
  • source/lobby/StanzaExtensions.h

     
    1 /* Copyright (C) 2013 Wildfire Games.
     1/* Copyright (C) 2014 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
     
    2727#define ExtBoardListQuery 1404
    2828#define XMLNS_BOARDLIST "jabber:iq:boardlist"
    2929
    30 /// Global Boardlist Extension
     30/// Global Gamereport Extension
    3131#define ExtGameReport 1405
    3232#define XMLNS_GAMEREPORT "jabber:iq:gamereport"
    3333
     
    8484
    8585    ~BoardListQuery();
    8686
    87     std::vector<const glooxwrapper::Tag*> m_BoardList;
     87    glooxwrapper::string m_Command;
     88    std::vector<const glooxwrapper::Tag*> m_StanzaBoardList;
    8889};
    8990#endif
  • source/lobby/XmppClient.cpp

     
    1 /* Copyright (C) 2013 Wildfire Games.
     1/* Copyright (C) 2014 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
     
    147147        glooxwrapper::Tag::free(*it);
    148148    for (std::vector<const glooxwrapper::Tag*>::const_iterator it = m_BoardList.begin(); it != m_BoardList.end(); ++it)
    149149        glooxwrapper::Tag::free(*it);
     150    for (std::vector<const glooxwrapper::Tag*>::const_iterator it = m_RatingList.begin(); it != m_RatingList.end(); ++it)
     151        glooxwrapper::Tag::free(*it);
    150152}
    151153
    152154/// Network
     
    208210    for (std::vector<const glooxwrapper::Tag*>::const_iterator it = m_BoardList.begin(); it != m_BoardList.end(); ++it)
    209211        glooxwrapper::Tag::free(*it);
    210212    m_BoardList.clear();
     213    m_RatingList.clear();
    211214    m_GameList.clear();
    212215    m_PlayerMap.clear();
    213216
     
    270273    glooxwrapper::JID xpartamuppJid(m_xpartamuppId);
    271274
    272275    // Send IQ
     276    BoardListQuery* b = new BoardListQuery();
     277    b->m_Command = "getleaderboard";
    273278    glooxwrapper::IQ iq(gloox::IQ::Get, xpartamuppJid);
    274     iq.addExtension(new BoardListQuery());
     279    iq.addExtension(b);
    275280    DbgXMPP("SendIqGetBoardList [" << tag_xml(iq) << "]");
    276281    m_client->send(iq);
    277282}
    278283
    279284/**
     285 * Request the rating data from the server.
     286 */
     287void XmppClient::SendIqGetRatingList()
     288{
     289    glooxwrapper::JID xpartamuppJid(m_xpartamuppId);
     290
     291    // Send IQ
     292    BoardListQuery* b = new BoardListQuery();
     293    b->m_Command = "getratinglist";
     294    glooxwrapper::IQ iq(gloox::IQ::Get, xpartamuppJid);
     295    iq.addExtension(b);
     296    DbgXMPP("SendIqGetRatingList [" << tag_xml(iq) << "]");
     297    m_client->send(iq);
     298}
     299
     300/**
    280301 * Send game report containing numerous game properties to the server.
    281302 *
    282303 * @param data A JS array of game statistics
     
    523544    return boardList;
    524545}
    525546
     547/**
     548 * Handle requests from the GUI for rating list data.
     549 *
     550 * @return A JS array containing all known leaderboard data
     551 */
     552CScriptValRooted XmppClient::GUIGetRatingList(ScriptInterface& scriptInterface)
     553{
     554    CScriptValRooted ratingList;
     555    scriptInterface.Eval("([])", ratingList);
     556    for(std::vector<const glooxwrapper::Tag*>::const_iterator it = m_RatingList.begin(); it != m_RatingList.end(); ++it)
     557    {
     558        CScriptValRooted rating;
     559        scriptInterface.Eval("({})", rating);
     560
     561        const char* attributes[] = { "name", "rank", "rating" };
     562        short attributes_length = 3;
     563        for (short i = 0; i < attributes_length; i++)
     564            scriptInterface.SetProperty(rating.get(), attributes[i], wstring_from_utf8((*it)->findAttribute(attributes[i]).to_string()));
     565
     566        scriptInterface.CallFunctionVoid(ratingList.get(), "push", rating);
     567    }
     568
     569    return ratingList;
     570}
     571
    526572/*****************************************************
    527573 * Message interfaces                                *
    528574 *****************************************************/
     
    625671        }
    626672        if(bq)
    627673        {
    628             for(std::vector<const glooxwrapper::Tag*>::const_iterator it = m_BoardList.begin(); it != m_BoardList.end(); ++it )
    629                 glooxwrapper::Tag::free(*it);
    630             m_BoardList.clear();
     674            if (bq->m_Command == "boardlist")
     675            {
     676                for(std::vector<const glooxwrapper::Tag*>::const_iterator it = m_BoardList.begin(); it != m_BoardList.end(); ++it )
     677                    glooxwrapper::Tag::free(*it);
     678                m_BoardList.clear();
    631679
    632             for(std::vector<const glooxwrapper::Tag*>::const_iterator it = bq->m_BoardList.begin(); it != bq->m_BoardList.end(); ++it)
    633                 m_BoardList.push_back( (*it)->clone() );
     680                for(std::vector<const glooxwrapper::Tag*>::const_iterator it = bq->m_StanzaBoardList.begin(); it != bq->m_StanzaBoardList.end(); ++it)
     681                    m_BoardList.push_back( (*it)->clone() );
    634682
    635             CreateSimpleMessage("system", "boardlist updated", "internal");
     683                CreateSimpleMessage("system", "boardlist updated", "internal");
     684            }
     685            else if (bq->m_Command == "ratinglist")
     686            {
     687                for(std::vector<const glooxwrapper::Tag*>::const_iterator it = m_RatingList.begin(); it != m_RatingList.end(); ++it )
     688                    glooxwrapper::Tag::free(*it);
     689                m_RatingList.clear();
     690
     691                for(std::vector<const glooxwrapper::Tag*>::const_iterator it = bq->m_StanzaBoardList.begin(); it != bq->m_StanzaBoardList.end(); ++it)
     692                    m_RatingList.push_back( (*it)->clone() );
     693
     694                CreateSimpleMessage("system", "ratinglist updated", "internal");
     695            }
    636696        }
    637697    }
    638698    else if(iq.subtype() == gloox::IQ::Error)
  • source/lobby/XmppClient.h

     
    1 /* Copyright (C) 2013 Wildfire Games.
     1/* Copyright (C) 2014 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
     
    6060    void recv();
    6161    void SendIqGetGameList();
    6262    void SendIqGetBoardList();
     63    void SendIqGetRatingList();
    6364    void SendIqGameReport(ScriptInterface& scriptInterface, CScriptVal data);
    6465    void SendIqRegisterGame(ScriptInterface& scriptInterface, CScriptVal data);
    6566    void SendIqUnregisterGame();
     
    7475    CScriptValRooted GUIGetPlayerList(ScriptInterface& scriptInterface);
    7576    CScriptValRooted GUIGetGameList(ScriptInterface& scriptInterface);
    7677    CScriptValRooted GUIGetBoardList(ScriptInterface& scriptInterface);
    77 
     78    CScriptValRooted GUIGetRatingList(ScriptInterface& scriptInterface);
    7879    //Script
    7980    ScriptInterface& GetScriptInterface();
    8081
     
    140141    std::vector<const glooxwrapper::Tag*> m_GameList;
    141142    /// List of rankings
    142143    std::vector<const glooxwrapper::Tag*> m_BoardList;
     144    /// List of ratings
     145    std::vector<const glooxwrapper::Tag*> m_RatingList;
    143146    /// Queue of messages
    144147    std::deque<GUIMessage> m_GuiMessageQueue;
    145148};
  • source/lobby/glooxwrapper/glooxwrapper.cpp

     
    1 /* Copyright (C) 2013 Wildfire Games.
     1/* Copyright (C) 2014 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
  • source/lobby/glooxwrapper/glooxwrapper.h

     
    1 /* Copyright (C) 2013 Wildfire Games.
     1/* Copyright (C) 2014 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
  • source/lobby/scripting/JSInterface_Lobby.cpp

     
    9191    g_XmppClient->SendIqGetBoardList();
    9292}
    9393
     94void JSI_Lobby::SendGetRatingList(ScriptInterface::CxPrivate* UNUSED(pCxPrivate))
     95{
     96    if (!g_XmppClient)
     97        return;
     98    g_XmppClient->SendIqGetRatingList();
     99}
     100
    94101void JSI_Lobby::SendGameReport(ScriptInterface::CxPrivate* pCxPrivate, CScriptVal data)
    95102{
    96103    if (!g_XmppClient)
  • source/lobby/scripting/JSInterface_Lobby.h

     
    3535    void RecvXmppClient(ScriptInterface::CxPrivate* pCxPrivate);
    3636    void SendGetGameList(ScriptInterface::CxPrivate* pCxPrivate);
    3737    void SendGetBoardList(ScriptInterface::CxPrivate* pCxPrivate);
     38    void SendGetRatingList(ScriptInterface::CxPrivate* pCxPrivate);
    3839    void SendGameReport(ScriptInterface::CxPrivate* pCxPrivate, CScriptVal data);
    3940    void SendRegisterGame(ScriptInterface::CxPrivate* pCxPrivate, CScriptVal data);
    4041    void SendUnregisterGame(ScriptInterface::CxPrivate* pCxPrivate);
     
    4243    CScriptVal GetPlayerList(ScriptInterface::CxPrivate* pCxPrivate);
    4344    CScriptVal GetGameList(ScriptInterface::CxPrivate* pCxPrivate);
    4445    CScriptVal GetBoardList(ScriptInterface::CxPrivate* pCxPrivate);
     46    CScriptVal GetRatingList(ScriptInterface::CxPrivate* pCxPrivate);
    4547    CScriptVal LobbyGuiPollMessage(ScriptInterface::CxPrivate* pCxPrivate);
    4648    void LobbySendMessage(ScriptInterface::CxPrivate* pCxPrivate, std::wstring message);
    4749    void LobbySetPlayerPresence(ScriptInterface::CxPrivate* pCxPrivate, std::wstring presence);
     
    6264#endif // CONFIG2_LOBBY
    6365}
    6466
    65 #endif
    66  No newline at end of file
     67#endif
  • source/tools/XpartaMuPP/XpartaMuPP.py

     
    11#!/usr/bin/env python3
    22# -*- coding: utf-8 -*-
    3 """Copyright (C) 2013 Wildfire Games.
     3"""Copyright (C) 2014 Wildfire Games.
    44 * This file is part of 0 A.D.
    55 *
    66 * 0 A.D. is free software: you can redistribute it and/or modify
     
    183183        continue
    184184      board[player.jid] = {'name': '@'.join(player.jid.split('@')[:-1]), 'rating': str(player.rating)}
    185185    return board
     186  def getRatingList(self, nicks):
     187    """
     188    Returns a rating list of players
     189    currently in the lobby by nick
     190    because the client can't link
     191    JID to nick conveniently.
     192    """
     193    ratinglist = {}
     194    for JID in nicks.keys():
     195      players = db.query(Player).filter_by(jid=str(JID))
     196      if players.first():
     197        if players.first().rating == -1:
     198          ratinglist[nicks[JID]] = {'name': nicks[JID], 'rating': ''}
     199        else:
     200          ratinglist[nicks[JID]] = {'name': nicks[JID], 'rating': str(players.first().rating)}
     201      else:
     202        ratinglist[nicks[JID]] = {'name': nicks[JID], 'rating': ''}
     203    return ratinglist
    186204
    187205## Class to tracks all games in the lobby ##
    188206class GameList():
     
    342360      data[key] = item
    343361    return data
    344362
    345 ## Class for custom boardlist stanza extension ##
     363## Class for custom boardlist and ratinglist stanza extension ##
    346364class BoardListXmppPlugin(ElementBase):
    347365  name = 'query'
    348366  namespace = 'jabber:iq:boardlist'
    349   interfaces = ('board')
     367  interfaces = set(('board', 'command'))
    350368  sub_interfaces = interfaces
    351369  plugin_attrib = 'boardlist'
    352 
     370  def addCommand(self, command):
     371    commandXml = ET.fromstring("<command>%s</command>" % command)
     372    self.xml.append(commandXml)
    353373  def addItem(self, name, rating):
    354374    itemXml = ET.Element("board", {"name": name, "rating": rating})
    355375    self.xml.append(itemXml)
     
    488508          traceback.print_exc()
    489509          logging.error("Failed to process gamelist request from %s" % iq['from'].bare)
    490510      elif 'boardlist' in iq.plugins:
    491         try:
    492           self.leaderboard.getOrCreatePlayer(iq['from'])
    493           self.sendBoardList(iq['from'])
    494         except:
    495           traceback.print_exc()
     511        command = iq['boardlist']['command']
     512        if command == 'getleaderboard':
     513          try:
     514            self.leaderboard.getOrCreatePlayer(iq['from'])
     515            self.sendBoardList(iq['from'])
     516          except:
     517            traceback.print_exc()
     518            logging.error("Failed to process leaderboardlist request from %s" % iq['from'].bare)
     519        elif command == 'getratinglist':
     520          try:
     521            self.leaderboard.getOrCreatePlayer(iq['from'])
     522            self.sendRatingList(iq['from'])
     523          except:
     524            traceback.print_exc()
     525            logging.error("Failed to process ratinglist request from %s" % iq['from'].bare)
     526        else:
    496527          logging.error("Failed to process boardlist request from %s" % iq['from'].bare)
    497528      else:
    498529        logging.error("Unknown 'get' type stanza request from %s" % iq['from'].bare)
     
    543574          if self.leaderboard.getLastRatedMessage() != "":
    544575            self.send_message(mto=self.room, mbody=self.leaderboard.getLastRatedMessage(), mtype="groupchat",
    545576              mnick=self.nick)
    546             self.sendBoardList()       
     577            self.sendBoardList()
     578            self.sendRatingList()
    547579        except:
    548580          traceback.print_exc()
    549581          logging.error("Failed to update game statistics for %s" % iq['from'].bare)
     
    557589        to all clients.
    558590    """
    559591    games = self.gameList.getAllGames()
    560     if to == "":     
     592    if to == "":
    561593      for JID in self.nicks.keys():
    562594        stz = GameListXmppPlugin()
    563595
     
    620652    iq['type'] = 'result'
    621653    for i in board:
    622654      stz.addItem(board[i]['name'], board[i]['rating'])
     655    stz.addCommand('boardlist')
    623656    iq.setPayload(stz)
    624657    if to == "":   
    625658      for JID in self.nicks.keys():
    626         ## Set aditional IQ attributes
     659        ## Set additional IQ attributes
    627660        iq['to'] = JID
    628661        ## Try sending the stanza
    629662        try:
     
    635668      if str(to) not in self.nicks:
    636669        logging.error("No player with the XmPP ID '%s' known to send boardlist to" % str(to))
    637670        return
    638       ## Set aditional IQ attributes
     671      ## Set additional IQ attributes
    639672      iq['to'] = to
    640673      ## Try sending the stanza
    641674      try:
    642675        iq.send(block=False, now=True)
    643676      except:
    644677        logging.error("Failed to send leaderboard list")
     678       
     679  def sendRatingList(self, to = ""):
     680    """
     681      Send the rating list.
     682      If no target is passed the rating list is broadcasted
     683        to all clients.
     684    """
     685    ## Pull rating list data and add it to the stanza 
     686    ratinglist = self.leaderboard.getRatingList(self.nicks)
     687    stz = BoardListXmppPlugin()
     688    iq = self.Iq()
     689    iq['type'] = 'result'
     690    for i in ratinglist:
     691      stz.addItem(ratinglist[i]['name'], ratinglist[i]['rating'])
     692    stz.addCommand('ratinglist')
     693    iq.setPayload(stz)
     694    if to == "":   
     695      for JID in self.nicks.keys():
     696        ## Set additional IQ attributes
     697        iq['to'] = JID
     698        ## Try sending the stanza
     699        try:
     700          iq.send(block=False, now=True)
     701        except:
     702          logging.error("Failed to send rating list")
     703    else:
     704      ## Check recipient exists
     705      if str(to) not in self.nicks:
     706        logging.error("No player with the XmPP ID '%s' known to send ratinglist to" % str(to))
     707        return
     708      ## Set additional IQ attributes
     709      iq['to'] = to
     710      ## Try sending the stanza
     711      try:
     712        iq.send(block=False, now=True)
     713      except:
     714        logging.error("Failed to send rating list")
    645715
    646716## Main Program ##
    647717if __name__ == '__main__':
     
    680750
    681751  # Setup logging.
    682752  logging.basicConfig(level=opts.loglevel,
    683                       format='%(asctime)s        %(levelname)-8s %(message)s', datefmt='%m-%d-%y %H:%M:%S')
     753                      format='%(asctime)s        %(levelname)-8s %(message)s', datefmt='%Y-%m-%d %H:%M:%S')
    684754
    685755  # XpartaMuPP
    686756  xmpp = XpartaMuPP(opts.xlogin+'@'+opts.xdomain+'/CC', opts.xpassword, opts.xroom+'@conference.'+opts.xdomain, opts.xnickname)