Ticket #2371: ratingplayerlist.patch
File ratingplayerlist.patch, 32.0 KB (added by , 10 years ago) |
---|
-
binaries/data/mods/public/gui/lobby/lobby.js
36 36 Engine.LobbySetPlayerPresence("available"); 37 37 Engine.SendGetGameList(); 38 38 Engine.SendGetBoardList(); 39 Engine.SendGetRatingList(); 39 40 updatePlayerList(); 40 41 41 42 resetFilters(); … … 105 106 return true; 106 107 } 107 108 108 // Do a full update of the player listing **Only call on init**109 // Do a full update of the player listing, including ratings. 109 110 function updatePlayerList() 110 111 { 111 112 var playersBox = Engine.GetGUIObjectByName("playersBox"); 112 [playerList, presenceList, nickList] = [[],[],[]]; 113 [playerList, presenceList, nickList, ratingList] = [[],[],[],[]]; 114 var ratingsmap = Engine.GetRatingList(); 115 var defaultrating; 113 116 for each (var p in Engine.GetPlayerList()) 114 117 { 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); 116 128 playerList.push(name); 117 129 presenceList.push(status); 118 130 nickList.push(p.name); 131 ratingList.push(String(" " + rating)); 119 132 } 120 133 playersBox.list_name = playerList; 121 134 playersBox.list_status = presenceList; 122 playersBox.list = nickList; 135 playersBox.list_rating = ratingList; 136 playersBox.list = nickList; 123 137 if (playersBox.selected >= playersBox.list.length) 124 138 playersBox.selected = -1; 125 return [playerList, presenceList, nickList ];139 return [playerList, presenceList, nickList, ratingList]; 126 140 } 127 141 128 142 // Update leaderboard listing … … 229 243 } 230 244 231 245 // The following function colorizes and formats the entries in the player list. 232 function formatPlayerListEntry(nickname, presence )246 function formatPlayerListEntry(nickname, presence, rating) 233 247 { 234 248 // Set colors based on player status 249 var color; 235 250 var color_close = '[/color]'; 236 251 switch (presence) 237 252 { 238 253 case "playing": 239 varcolor = '[color="125 0 0"]';254 color = '[color="125 0 0"]'; 240 255 var status = color + "Busy" + color_close; 241 256 break; 242 257 case "gone": 243 258 case "away": 244 varcolor = '[color="229 76 13"]';259 color = '[color="229 76 13"]'; 245 260 var status = color + "Away" + color_close; 246 261 break; 247 262 case "available": 248 varcolor = '[color="0 125 0"]';263 color = '[color="0 125 0"]'; 249 264 var status = color + "Online" + color_close; 250 265 break; 251 266 case "offline": 252 varcolor = '[color="0 0 0"]';267 color = '[color="0 0 0"]'; 253 268 var status = color + "Offline" + color_close; 254 269 break; 255 270 default: 256 271 warn("Unknown presence '"+presence+"'"); 257 varcolor = '[color="178 178 178"]';272 color = '[color="178 178 178"]'; 258 273 var status = color + "Unknown" + color_close; 259 274 break; 260 275 } 261 276 var elo = color + rating + color_close; 262 277 var name = colorPlayerName(nickname); 263 278 264 279 // Push this player's name and status onto the list 265 return [name, status ];280 return [name, status, elo]; 266 281 } 267 282 268 283 function selectGame(selected) … … 349 364 return n < 10 ? "0" + n : n; 350 365 } 351 366 367 function stripColorCodes(input) 368 { 369 return input.replace(/\[(\w+)[^w]*?](.*?)\[\/\1]/g, '$2'); 370 } 371 352 372 //////////////////////////////////////////////////////////////////////////////////////////////// 353 373 // GUI event handlers 354 374 //////////////////////////////////////////////////////////////////////////////////////////////// … … 384 404 var playerList = playersBox.list_name; 385 405 var presenceList = playersBox.list_status; 386 406 var nickList = playersBox.list; 407 var ratingList = playersBox.list_rating; 387 408 var nickIndex = nickList.indexOf(nick); 388 409 switch(message.level) 389 410 { … … 391 412 if (nick == g_Name) 392 413 { 393 414 // We just joined, we need to get the full player list 394 [playerList, presenceList, nickList ] = updatePlayerList();415 [playerList, presenceList, nickList, ratingList] = updatePlayerList(); 395 416 break; 396 417 } 397 var [name, status ] = formatPlayerListEntry(nick, presence);418 var [name, status, rating] = formatPlayerListEntry(nick, presence, " -"); 398 419 playerList.push(name); 399 420 presenceList.push(status); 400 421 nickList.push(nick); 422 ratingList.push(String(rating)); 423 Engine.SendGetRatingList(); 401 424 addChatMessage({ "text": "/special " + nick + " has joined.", "key": g_specialKey }); 402 425 break; 403 426 case "leave": … … 406 429 playerList.splice(nickIndex, 1); 407 430 presenceList.splice(nickIndex, 1); 408 431 nickList.splice(nickIndex, 1); 432 ratingList.splice(nickIndex, 1); 409 433 addChatMessage({ "text": "/special " + nick + " has left.", "key": g_specialKey }); 410 434 break; 411 435 case "nick": … … 416 440 addChatMessage({ "from": "system", "text": "Invalid nickname: " + message.data }); 417 441 break; 418 442 } 419 var [name, status ] = formatPlayerListEntry(message.data, presence); // TODO: actually we don't want to change the presence here, so use what was used before443 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 420 444 playerList[nickIndex] = name; 421 445 // presence stays the same 422 446 nickList[nickIndex] = message.data; 423 447 addChatMessage({ "text": "/special " + nick + " is now known as " + message.data + ".", "key": g_specialKey }); 448 Engine.SendGetRatingList(); 424 449 break; 425 450 case "presence": 426 451 if (nickIndex == -1) // This shouldn't ever happen 427 452 break; 428 var [name, status ] = formatPlayerListEntry(nick, presence);453 var [name, status, rating] = formatPlayerListEntry(nick, presence, stripColorCodes(ratingList[nickIndex])); 429 454 presenceList[nickIndex] = status; 430 455 playerList[nickIndex] = name; 456 ratingList[nickIndex] = rating; 431 457 break; 432 458 default: 433 459 warn("Unknown message.level '" + message.level + "'"); … … 436 462 // Push new data to GUI 437 463 playersBox.list_name = playerList; 438 464 playersBox.list_status = presenceList; 439 playersBox.list = nickList; 465 playersBox.list_rating = ratingList; 466 playersBox.list = nickList; 440 467 if (playersBox.selected >= playersBox.list.length) 441 468 playersBox.selected = -1; 442 469 break; … … 471 498 case "boardlist updated": 472 499 updateBoardList(); 473 500 break; 501 case "ratinglist updated": 502 updatePlayerList(); 503 break; 474 504 } 475 505 break 476 506 } … … 542 572 case "back": 543 573 Engine.LobbySetPlayerPresence("available"); 544 574 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;553 575 case "kick": // TODO: Split reason from nick and pass it too, for now just support "/kick nick" 554 576 // also allow quoting nicks (and/or prevent users from changing it here, but that doesn't help if the spammer uses a different client) 555 577 Engine.LobbyKick(nick, ""); -
binaries/data/mods/public/gui/lobby/lobby.xml
19 19 </action> 20 20 21 21 <!-- 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%" /> 26 27 </object> 27 28 </object> 28 29 29 <object name="leftButtonPanel" size="20 100%-45 15% 100%-20">30 <object name="leftButtonPanel" size="20 100%-45 20% 100%-20"> 30 31 <object type="button" style="StoneButton" size="0 0 100% 100%"> 31 32 Leaderboard 32 33 <action on="Press">Engine.GetGUIObjectByName("leaderboard").hidden = false;Engine.GetGUIObjectByName("leaderboardFade").hidden = false;</action> … … 34 35 </object> 35 36 36 37 <!-- 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" > 38 39 <object name="gameInfoEmpty" size="0 0 100% 100%-60" type="image" sprite="ModernDarkBoxGold" hidden="false"> 39 40 <object size="50%-110 50%-50 50%+110 50%+50" type="image" sprite="productLogo"/> 40 41 </object> … … 106 107 </object> 107 108 108 109 <!-- 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"> 111 112 <action on="SelectionChange">selectGame(this.selected);</action> 112 113 <def id="name" heading="Name" color="0 60 0" width="25%"/> 113 114 <!--<def id="ip" heading="IP" color="0 128 128" width="170"/>--> … … 121 122 <object name="mapSizeFilter" 122 123 type="dropdown" 123 124 style="ModernDropDown" 124 size="49.7% 0 62% 100%"> 125 size="49.7% 0 62% 100%" 126 font="serif-bold-13"> 125 127 <action on="SelectionChange">applyFilters();</action> 126 128 </object> 127 129 128 130 <object name="mapTypeFilter" 129 131 type="dropdown" 130 132 style="ModernDropDown" 131 size="69.3% 0 82% 100%"> 133 size="69.3% 0 82% 100%" 134 font="serif-bold-13"> 132 135 <action on="SelectionChange">applyFilters();</action> 133 136 </object> 134 137 135 138 <object name="playersNumberFilter" 136 139 type="dropdown" 137 140 style="ModernDropDown" 138 size="89% 0 100% 100%"> 141 size="89% 0 100% 100%" 142 font="serif-bold-13"> 139 143 <action on="SelectionChange">applyFilters();</action> 140 144 </object> 141 145 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> 143 147 <object name="showFullFilter" 144 148 type="checkbox" 145 149 checked="true" 146 150 style="ModernTickBox" 147 size="0% 0 20 100%"> 151 size="0% 0 20 100%" 152 font="serif-bold-13"> 148 153 <action on="Press">applyFilters();</action> 149 154 </object> 150 155 </object> 151 156 152 157 <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"> 155 160 <action on="Press">submitChatInput();</action> 156 161 <action on="Tab">completeNick();</action> 157 162 </object> -
source/gui/scripting/ScriptFunctions.cpp
891 891 scriptInterface.RegisterFunction<void, &JSI_Lobby::RecvXmppClient>("RecvXmppClient"); 892 892 scriptInterface.RegisterFunction<void, &JSI_Lobby::SendGetGameList>("SendGetGameList"); 893 893 scriptInterface.RegisterFunction<void, &JSI_Lobby::SendGetBoardList>("SendGetBoardList"); 894 scriptInterface.RegisterFunction<void, &JSI_Lobby::SendGetRatingList>("SendGetRatingList"); 894 895 scriptInterface.RegisterFunction<void, CScriptVal, &JSI_Lobby::SendRegisterGame>("SendRegisterGame"); 895 896 scriptInterface.RegisterFunction<void, CScriptVal, &JSI_Lobby::SendGameReport>("SendGameReport"); 896 897 scriptInterface.RegisterFunction<void, &JSI_Lobby::SendUnregisterGame>("SendUnregisterGame"); … … 898 899 scriptInterface.RegisterFunction<CScriptVal, &JSI_Lobby::GetPlayerList>("GetPlayerList"); 899 900 scriptInterface.RegisterFunction<CScriptVal, &JSI_Lobby::GetGameList>("GetGameList"); 900 901 scriptInterface.RegisterFunction<CScriptVal, &JSI_Lobby::GetBoardList>("GetBoardList"); 902 scriptInterface.RegisterFunction<CScriptVal, &JSI_Lobby::GetBoardList>("GetRatingList"); 901 903 scriptInterface.RegisterFunction<CScriptVal, &JSI_Lobby::LobbyGuiPollMessage>("LobbyGuiPollMessage"); 902 904 scriptInterface.RegisterFunction<void, std::wstring, &JSI_Lobby::LobbySendMessage>("LobbySendMessage"); 903 905 scriptInterface.RegisterFunction<void, std::wstring, &JSI_Lobby::LobbySetPlayerPresence>("LobbySetPlayerPresence"); -
source/lobby/IXmppClient.h
1 /* Copyright (C) 201 3Wildfire Games.1 /* Copyright (C) 2014 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify … … 33 33 virtual void recv() = 0; 34 34 virtual void SendIqGetGameList() = 0; 35 35 virtual void SendIqGetBoardList() = 0; 36 virtual void SendIqGetRatingList() = 0; 36 37 virtual void SendIqGameReport(ScriptInterface& scriptInterface, CScriptVal data) = 0; 37 38 virtual void SendIqRegisterGame(ScriptInterface& scriptInterface, CScriptVal data) = 0; 38 39 virtual void SendIqUnregisterGame() = 0; -
source/lobby/StanzaExtensions.cpp
1 /* Copyright (C) 201 3Wildfire Games.1 /* Copyright (C) 2014 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify … … 59 59 } 60 60 61 61 /****************************************************** 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> 64 66 */ 65 67 BoardListQuery::BoardListQuery( const glooxwrapper::Tag* tag ):StanzaExtension( ExtBoardListQuery ) 66 68 { 67 69 if( !tag || tag->name() != "query" || tag->xmlns() != XMLNS_BOARDLIST ) 68 70 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); 70 76 const glooxwrapper::ConstTagList boardTags = tag->findTagList_clone( "query/board" ); 71 77 glooxwrapper::ConstTagList::const_iterator it = boardTags.begin(); 72 78 for ( ; it != boardTags.end(); ++it ) 73 m_BoardList.push_back( *it ); 79 { 80 m_StanzaBoardList.push_back( *it ); 81 } 74 82 } 75 83 76 84 /** 77 * Required by gloox, used to find the BoardList element in a rec ived IQ.85 * Required by gloox, used to find the BoardList element in a received IQ. 78 86 */ 79 87 const glooxwrapper::string& BoardListQuery::filterString() const 80 88 { … … 89 97 { 90 98 glooxwrapper::Tag* t = glooxwrapper::Tag::allocate( "query" ); 91 99 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)); 92 104 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 ) 95 107 t->addChild( (*it)->clone() ); 96 108 97 109 return t; … … 105 117 106 118 BoardListQuery::~BoardListQuery() 107 119 { 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 ) 110 122 glooxwrapper::Tag::free(*it); 111 m_ BoardList.clear();123 m_StanzaBoardList.clear(); 112 124 } 113 125 114 126 /****************************************************** … … 133 145 } 134 146 135 147 /** 136 * Required by gloox, used to find the GameList element in a rec ived IQ.148 * Required by gloox, used to find the GameList element in a received IQ. 137 149 */ 138 150 const glooxwrapper::string& GameListQuery::filterString() const 139 151 { -
source/lobby/StanzaExtensions.h
1 /* Copyright (C) 201 3Wildfire Games.1 /* Copyright (C) 2014 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify … … 27 27 #define ExtBoardListQuery 1404 28 28 #define XMLNS_BOARDLIST "jabber:iq:boardlist" 29 29 30 /// Global Boardlist Extension30 /// Global Gamereport Extension 31 31 #define ExtGameReport 1405 32 32 #define XMLNS_GAMEREPORT "jabber:iq:gamereport" 33 33 … … 84 84 85 85 ~BoardListQuery(); 86 86 87 std::vector<const glooxwrapper::Tag*> m_BoardList; 87 glooxwrapper::string m_Command; 88 std::vector<const glooxwrapper::Tag*> m_StanzaBoardList; 88 89 }; 89 90 #endif -
source/lobby/XmppClient.cpp
1 /* Copyright (C) 201 3Wildfire Games.1 /* Copyright (C) 2014 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify … … 147 147 glooxwrapper::Tag::free(*it); 148 148 for (std::vector<const glooxwrapper::Tag*>::const_iterator it = m_BoardList.begin(); it != m_BoardList.end(); ++it) 149 149 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); 150 152 } 151 153 152 154 /// Network … … 208 210 for (std::vector<const glooxwrapper::Tag*>::const_iterator it = m_BoardList.begin(); it != m_BoardList.end(); ++it) 209 211 glooxwrapper::Tag::free(*it); 210 212 m_BoardList.clear(); 213 m_RatingList.clear(); 211 214 m_GameList.clear(); 212 215 m_PlayerMap.clear(); 213 216 … … 270 273 glooxwrapper::JID xpartamuppJid(m_xpartamuppId); 271 274 272 275 // Send IQ 276 BoardListQuery* b = new BoardListQuery(); 277 b->m_Command = "getleaderboard"; 273 278 glooxwrapper::IQ iq(gloox::IQ::Get, xpartamuppJid); 274 iq.addExtension( new BoardListQuery());279 iq.addExtension(b); 275 280 DbgXMPP("SendIqGetBoardList [" << tag_xml(iq) << "]"); 276 281 m_client->send(iq); 277 282 } 278 283 279 284 /** 285 * Request the rating data from the server. 286 */ 287 void 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 /** 280 301 * Send game report containing numerous game properties to the server. 281 302 * 282 303 * @param data A JS array of game statistics … … 523 544 return boardList; 524 545 } 525 546 547 /** 548 * Handle requests from the GUI for rating list data. 549 * 550 * @return A JS array containing all known leaderboard data 551 */ 552 CScriptValRooted 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 526 572 /***************************************************** 527 573 * Message interfaces * 528 574 *****************************************************/ … … 625 671 } 626 672 if(bq) 627 673 { 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(); 631 679 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() ); 634 682 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 } 636 696 } 637 697 } 638 698 else if(iq.subtype() == gloox::IQ::Error) -
source/lobby/XmppClient.h
1 /* Copyright (C) 201 3Wildfire Games.1 /* Copyright (C) 2014 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify … … 60 60 void recv(); 61 61 void SendIqGetGameList(); 62 62 void SendIqGetBoardList(); 63 void SendIqGetRatingList(); 63 64 void SendIqGameReport(ScriptInterface& scriptInterface, CScriptVal data); 64 65 void SendIqRegisterGame(ScriptInterface& scriptInterface, CScriptVal data); 65 66 void SendIqUnregisterGame(); … … 74 75 CScriptValRooted GUIGetPlayerList(ScriptInterface& scriptInterface); 75 76 CScriptValRooted GUIGetGameList(ScriptInterface& scriptInterface); 76 77 CScriptValRooted GUIGetBoardList(ScriptInterface& scriptInterface); 77 78 CScriptValRooted GUIGetRatingList(ScriptInterface& scriptInterface); 78 79 //Script 79 80 ScriptInterface& GetScriptInterface(); 80 81 … … 140 141 std::vector<const glooxwrapper::Tag*> m_GameList; 141 142 /// List of rankings 142 143 std::vector<const glooxwrapper::Tag*> m_BoardList; 144 /// List of ratings 145 std::vector<const glooxwrapper::Tag*> m_RatingList; 143 146 /// Queue of messages 144 147 std::deque<GUIMessage> m_GuiMessageQueue; 145 148 }; -
source/lobby/glooxwrapper/glooxwrapper.cpp
1 /* Copyright (C) 201 3Wildfire Games.1 /* Copyright (C) 2014 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify -
source/lobby/glooxwrapper/glooxwrapper.h
1 /* Copyright (C) 201 3Wildfire Games.1 /* Copyright (C) 2014 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify -
source/lobby/scripting/JSInterface_Lobby.cpp
91 91 g_XmppClient->SendIqGetBoardList(); 92 92 } 93 93 94 void JSI_Lobby::SendGetRatingList(ScriptInterface::CxPrivate* UNUSED(pCxPrivate)) 95 { 96 if (!g_XmppClient) 97 return; 98 g_XmppClient->SendIqGetRatingList(); 99 } 100 94 101 void JSI_Lobby::SendGameReport(ScriptInterface::CxPrivate* pCxPrivate, CScriptVal data) 95 102 { 96 103 if (!g_XmppClient) -
source/lobby/scripting/JSInterface_Lobby.h
35 35 void RecvXmppClient(ScriptInterface::CxPrivate* pCxPrivate); 36 36 void SendGetGameList(ScriptInterface::CxPrivate* pCxPrivate); 37 37 void SendGetBoardList(ScriptInterface::CxPrivate* pCxPrivate); 38 void SendGetRatingList(ScriptInterface::CxPrivate* pCxPrivate); 38 39 void SendGameReport(ScriptInterface::CxPrivate* pCxPrivate, CScriptVal data); 39 40 void SendRegisterGame(ScriptInterface::CxPrivate* pCxPrivate, CScriptVal data); 40 41 void SendUnregisterGame(ScriptInterface::CxPrivate* pCxPrivate); … … 42 43 CScriptVal GetPlayerList(ScriptInterface::CxPrivate* pCxPrivate); 43 44 CScriptVal GetGameList(ScriptInterface::CxPrivate* pCxPrivate); 44 45 CScriptVal GetBoardList(ScriptInterface::CxPrivate* pCxPrivate); 46 CScriptVal GetRatingList(ScriptInterface::CxPrivate* pCxPrivate); 45 47 CScriptVal LobbyGuiPollMessage(ScriptInterface::CxPrivate* pCxPrivate); 46 48 void LobbySendMessage(ScriptInterface::CxPrivate* pCxPrivate, std::wstring message); 47 49 void LobbySetPlayerPresence(ScriptInterface::CxPrivate* pCxPrivate, std::wstring presence); … … 62 64 #endif // CONFIG2_LOBBY 63 65 } 64 66 65 #endif 66 No newline at end of file 67 #endif -
source/tools/XpartaMuPP/XpartaMuPP.py
1 1 #!/usr/bin/env python3 2 2 # -*- coding: utf-8 -*- 3 """Copyright (C) 201 3Wildfire Games.3 """Copyright (C) 2014 Wildfire Games. 4 4 * This file is part of 0 A.D. 5 5 * 6 6 * 0 A.D. is free software: you can redistribute it and/or modify … … 183 183 continue 184 184 board[player.jid] = {'name': '@'.join(player.jid.split('@')[:-1]), 'rating': str(player.rating)} 185 185 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 186 204 187 205 ## Class to tracks all games in the lobby ## 188 206 class GameList(): … … 342 360 data[key] = item 343 361 return data 344 362 345 ## Class for custom boardlist stanza extension ##363 ## Class for custom boardlist and ratinglist stanza extension ## 346 364 class BoardListXmppPlugin(ElementBase): 347 365 name = 'query' 348 366 namespace = 'jabber:iq:boardlist' 349 interfaces = ('board')367 interfaces = set(('board', 'command')) 350 368 sub_interfaces = interfaces 351 369 plugin_attrib = 'boardlist' 352 370 def addCommand(self, command): 371 commandXml = ET.fromstring("<command>%s</command>" % command) 372 self.xml.append(commandXml) 353 373 def addItem(self, name, rating): 354 374 itemXml = ET.Element("board", {"name": name, "rating": rating}) 355 375 self.xml.append(itemXml) … … 488 508 traceback.print_exc() 489 509 logging.error("Failed to process gamelist request from %s" % iq['from'].bare) 490 510 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: 496 527 logging.error("Failed to process boardlist request from %s" % iq['from'].bare) 497 528 else: 498 529 logging.error("Unknown 'get' type stanza request from %s" % iq['from'].bare) … … 543 574 if self.leaderboard.getLastRatedMessage() != "": 544 575 self.send_message(mto=self.room, mbody=self.leaderboard.getLastRatedMessage(), mtype="groupchat", 545 576 mnick=self.nick) 546 self.sendBoardList() 577 self.sendBoardList() 578 self.sendRatingList() 547 579 except: 548 580 traceback.print_exc() 549 581 logging.error("Failed to update game statistics for %s" % iq['from'].bare) … … 557 589 to all clients. 558 590 """ 559 591 games = self.gameList.getAllGames() 560 if to == "": 592 if to == "": 561 593 for JID in self.nicks.keys(): 562 594 stz = GameListXmppPlugin() 563 595 … … 620 652 iq['type'] = 'result' 621 653 for i in board: 622 654 stz.addItem(board[i]['name'], board[i]['rating']) 655 stz.addCommand('boardlist') 623 656 iq.setPayload(stz) 624 657 if to == "": 625 658 for JID in self.nicks.keys(): 626 ## Set ad itional IQ attributes659 ## Set additional IQ attributes 627 660 iq['to'] = JID 628 661 ## Try sending the stanza 629 662 try: … … 635 668 if str(to) not in self.nicks: 636 669 logging.error("No player with the XmPP ID '%s' known to send boardlist to" % str(to)) 637 670 return 638 ## Set ad itional IQ attributes671 ## Set additional IQ attributes 639 672 iq['to'] = to 640 673 ## Try sending the stanza 641 674 try: 642 675 iq.send(block=False, now=True) 643 676 except: 644 677 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") 645 715 646 716 ## Main Program ## 647 717 if __name__ == '__main__': … … 680 750 681 751 # Setup logging. 682 752 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') 684 754 685 755 # XpartaMuPP 686 756 xmpp = XpartaMuPP(opts.xlogin+'@'+opts.xdomain+'/CC', opts.xpassword, opts.xroom+'@conference.'+opts.xdomain, opts.xnickname)