Ticket #3143: 3143_lobby_data_v2.6.4.patch
File 3143_lobby_data_v2.6.4.patch, 16.5 KB (added by , 8 years ago) |
---|
-
binaries/data/mods/public/gui/common/functions_utility.js
59 59 * Escape tag start and escape characters, so users cannot use special formatting. 60 60 * Also limit string length to 256 characters (not counting escape characters). 61 61 */ 62 function escapeText(text )62 function escapeText(text, limitLength = true) 63 63 { 64 64 if (!text) 65 65 return text; 66 66 67 return text.substr(0, 255).replace(/\\/g, "\\\\").replace(/\[/g, "\\["); 67 if (limitLength) 68 text = text.substr(0, 255); 69 70 return text.replace(/\\/g, "\\\\").replace(/\[/g, "\\["); 68 71 } 69 72 73 function unescapeText(text) 74 { 75 if (!text) 76 return text; 77 return text.replace(/\\\\/g, "\\").replace(/\\\[/g, "\["); 78 } 79 80 function playerDataToTeamList(originalplayerDataArray) 81 { 82 let playerDataArray = clone(originalplayerDataArray); 83 let teamList = {}; 84 for (let playerData of playerDataArray) 85 { 86 if (playerData.Team === undefined) 87 playerData.Team = -1; 88 if (!teamList[playerData.Team]) 89 teamList[playerData.Team] = []; 90 teamList[playerData.Team].push(playerData); 91 delete teamList[playerData.Team].Team; 92 } 93 return teamList; 94 } 95 96 function teamListToPlayerData(teamList) 97 { 98 let playerData = []; 99 for (let team in teamList) 100 { 101 for (let player of teamList[team]) 102 { 103 player.Team = team; 104 playerData.push(player); 105 } 106 } 107 return playerData; 108 } 109 70 110 function translateMapTitle(mapTitle) 71 111 { 72 112 return mapTitle == "random" ? translateWithContext("map selection", "Random") : translate(mapTitle); … … 226 266 227 267 for (let playerData of playerDataArray) 228 268 { 229 if (playerData == null || playerData.Civ == "gaia")269 if (playerData == null || playerData.Civ && playerData.Civ == "gaia") 230 270 continue; 231 271 232 272 ++playerIdx; 233 273 let teamIdx = playerData.Team; 234 274 let isAI = playerData.AI && playerData.AI != ""; 235 let playerState = playerStates && playerStates[playerIdx] ;275 let playerState = playerStates && playerStates[playerIdx] || playerData.State; 236 276 let isActive = !playerState || playerState == "active"; 277 let isOffline = playerData.Offline; 237 278 238 279 let playerDescription; 239 280 if (isAI) 240 281 { 241 if (isActive) 242 // Translation: Describe a player in a selected game, f.e. in the replay- or savegame menu 243 playerDescription = translate("%(playerName)s (%(civ)s, %(AIdifficulty)s %(AIname)s)"); 282 if (playerData.Civ) 283 { 284 if (isActive) 285 // Translation: Describe a player in a selected game, f.e. in the replay- or savegame menu 286 playerDescription = translate("%(playerName)s (%(civ)s, %(AIdifficulty)s %(AIname)s)"); 287 else 288 // Translation: Describe a player in a selected game, f.e. in the replay- or savegame menu 289 playerDescription = translate("%(playerName)s (%(civ)s, %(AIdifficulty)s %(AIname)s, %(state)s)"); 290 } 244 291 else 245 // Translation: Describe a player in a selected game, f.e. in the replay- or savegame menu 246 playerDescription = translate("%(playerName)s (%(civ)s, %(AIdifficulty)s %(AIname)s, %(state)s)"); 292 { 293 if (isActive) 294 // Translation: Describe a player in a selected game, f.e. in the replay- or savegame menu 295 playerDescription = translate("%(playerName)s (%(AIdifficulty)s %(AIname)s)"); 296 else 297 // Translation: Describe a player in a selected game, f.e. in the replay- or savegame menu 298 playerDescription = translate("%(playerName)s (%(AIdifficulty)s %(AIname)s, %(state)s)"); 299 } 247 300 } 248 301 else 249 302 { 250 if (isActive) 251 // Translation: Describe a player in a selected game, f.e. in the replay- or savegame menu 252 playerDescription = translate("%(playerName)s (%(civ)s)"); 303 // Can only occur in the lobby for now, so no strings with civ needed 304 if (isOffline) 305 { 306 if (isActive) 307 // Translation: Describe a player in a selected game, f.e. in the replay- or savegame menu 308 playerDescription = translate("%(playerName)s (OFFLINE)"); 309 else 310 // Translation: Describe a player in a selected game, f.e. in the replay- or savegame menu 311 playerDescription = translate("%(playerName)s (OFFLINE, %(state)s)"); 312 } 253 313 else 254 // Translation: Describe a player in a selected game, f.e. in the replay- or savegame menu 255 playerDescription = translate("%(playerName)s (%(civ)s, %(state)s)"); 314 { 315 if (playerData.Civ) 316 if (isActive) 317 // Translation: Describe a player in a selected game, f.e. in the replay- or savegame menu 318 playerDescription = translate("%(playerName)s (%(civ)s)"); 319 else 320 // Translation: Describe a player in a selected game, f.e. in the replay- or savegame menu 321 playerDescription = translate("%(playerName)s (%(civ)s, %(state)s)"); 322 else 323 if (isActive) 324 // Translation: Describe a player in a selected game, f.e. in the replay- or savegame menu 325 playerDescription = translate("%(playerName)s"); 326 else 327 // Translation: Describe a player in a selected game, f.e. in the replay- or savegame menu 328 playerDescription = translate("%(playerName)s (%(state)s)"); 329 } 256 330 } 257 331 258 332 // Sort player descriptions by team … … 262 336 playerDescriptions[teamIdx].push(sprintf(playerDescription, { 263 337 "playerName": 264 338 '[color="' + 265 rgbToGuiColor(playerData.Color || g_Settings.PlayerDefaults[playerIdx].Color) + 339 (typeof getPlayerColor == 'function' ? 340 (isAI ? 341 "255 255 255" : 342 getPlayerColor(playerData.Name)) : 343 rgbToGuiColor(playerData.Color || g_Settings.PlayerDefaults[playerIdx].Color)) + 266 344 '"]' + escapeText(playerData.Name) + "[/color]", 267 345 268 346 "civ": … … 283 361 } 284 362 285 363 let teams = Object.keys(playerDescriptions); 364 if (teams.indexOf("observer") > -1) 365 teams.splice(teams.indexOf("observer"), 1); 286 366 367 let teamDescription = []; 368 287 369 // If there are no teams, merge all playersDescriptions 288 370 if (teams.length == 1) 289 return playerDescriptions[teams[0]].join("\n") + "\n";371 teamDescription.push(playerDescriptions[teams[0]].join("\n")); 290 372 291 373 // If there are teams, merge "Team N:" + playerDescriptions 292 return teams.map(team => { 374 else 375 teamDescription = teamDescription.concat(teams.map(team => { 293 376 294 let teamCaption = team == -1 ?295 translate("No Team") :296 sprintf(translate("Team %(team)s"), { "team": +team + 1 });377 let teamCaption = team == -1 ? 378 translate("No Team") : 379 sprintf(translate("Team %(team)s"), { "team": +team + 1 }); 297 380 298 // Translation: Describe players of one team in a selected game, f.e. in the replay- or savegame menu or lobby 299 return sprintf(translate("%(team)s:\n%(playerDescriptions)s"), { 300 "team": '[font="sans-bold-14"]' + teamCaption + "[/font]", 301 "playerDescriptions": playerDescriptions[team].join("\n") 302 }); 303 }).join("\n\n"); 381 // Translation: Describe players of one team in a selected game, f.e. in the replay- or savegame menu or lobby 382 return sprintf(translate("%(team)s:\n%(playerDescriptions)s"), { 383 "team": '[font="sans-bold-14"]' + teamCaption + "[/font]", 384 "playerDescriptions": playerDescriptions[team].join("\n") 385 }); 386 })); 387 388 if (playerDescriptions.observer) 389 teamDescription.push(sprintf(translate("%(team)s:\n%(playerDescriptions)s"), { 390 "team": '[font="sans-bold-14"]' + translatePlural("Observer", "Observers", playerDescriptions.observer.length) + "[/font]", 391 "playerDescriptions": playerDescriptions.observer.join("\n") 392 })); 393 394 return teamDescription.join("\n\n"); 304 395 } -
binaries/data/mods/public/gui/gamesetup/gamesetup.js
676 676 { 677 677 if (g_IsController && Engine.HasXmppClient()) 678 678 { 679 let playerNames = Object.keys(g_PlayerAssignments).map(guid => g_PlayerAssignments[guid].name);680 Engine.SendChangeStateGame( playerNames.length, playerNames.join(", "));679 let clients = formatClientsForStanza(); 680 Engine.SendChangeStateGame(clients.nbp, clients.list); 681 681 } 682 682 683 683 Engine.SwitchGuiPage("page_loading.xml", { … … 1936 1936 setReady(false, false); 1937 1937 } 1938 1938 1939 function formatClientsForStanza() 1940 { 1941 let numberOfPlayers = 0; 1942 let list = []; 1943 for (let guid in g_PlayerAssignments) 1944 { 1945 if (g_GameAttributes.settings.PlayerData[g_PlayerAssignments[guid].player - 1]) 1946 { 1947 ++numberOfPlayers; 1948 list.push({ 1949 "Name": g_PlayerAssignments[guid].name 1950 }); 1951 } 1952 else 1953 list.push({ 1954 "Name": g_PlayerAssignments[guid].name, 1955 "Team": "observer" 1956 }); 1957 } 1958 return { 1959 "list": escapeText(JSON.stringify(playerDataToTeamList(list))), 1960 "nbp": numberOfPlayers 1961 }; 1962 } 1963 1939 1964 /** 1940 1965 * Send the relevant gamesettings to the lobbybot. 1941 1966 */ … … 1949 1974 1950 1975 let mapSize = g_GameAttributes.mapType == "random" ? Engine.GetGUIObjectByName("mapSize").list_data[selectedMapSize] : "Default"; 1951 1976 let victoryCondition = Engine.GetGUIObjectByName("victoryCondition").list[selectedVictoryCondition]; 1952 let playerNames = Object.keys(g_PlayerAssignments).map(guid => g_PlayerAssignments[guid].name).sort();1977 let clients = formatClientsForStanza(); 1953 1978 1954 1979 let stanza = { 1955 1980 "name": g_ServerName, … … 1959 1984 "mapSize": mapSize, 1960 1985 "mapType": g_GameAttributes.mapType, 1961 1986 "victoryCondition": victoryCondition, 1962 "nbp": Object.keys(g_PlayerAssignments).length || 1,1963 " tnbp": g_GameAttributes.settings.PlayerData.length,1964 "players": playerNames.join(", ")1987 "nbp": clients.nbp, 1988 "maxnbp": g_GameAttributes.settings.PlayerData.length, 1989 "players": clients.list, 1965 1990 }; 1966 1991 1967 1992 // Only send the stanza if the relevant settings actually changed -
binaries/data/mods/public/gui/lobby/lobby.js
285 285 return true; 286 286 287 287 if (playersNumberFilter.selected != 0 && 288 game. tnbp != playersNumberFilter.list_data[playersNumberFilter.selected])288 game.maxnbp != playersNumberFilter.list_data[playersNumberFilter.selected]) 289 289 return true; 290 290 291 291 if (mapTypeFilter.selected != 0 && … … 292 292 game.mapType != mapTypeFilter.list_data[mapTypeFilter.selected]) 293 293 return true; 294 294 295 if (!showFullFilter.checked && game. tnbp <= game.nbp)295 if (!showFullFilter.checked && game.maxnbp <= game.nbp) 296 296 return true; 297 297 298 298 return false; … … 546 546 break; 547 547 case 'nPlayers': 548 548 // Compare playercount ratio 549 sortA = a.nbp * b. tnbp;550 sortB = b.nbp * a. tnbp;549 sortA = a.nbp * b.maxnbp; 550 sortB = b.nbp * a.maxnbp; 551 551 break; 552 552 case 'status': 553 553 default: … … 582 582 list_mapName.push(translateMapTitle(game.niceMapName)); 583 583 list_mapSize.push(translateMapSize(game.mapSize)); 584 584 list_mapType.push(g_MapTypes.Title[mapTypeIdx] || ""); 585 list_nPlayers.push(game.nbp + "/" + game. tnbp);585 list_nPlayers.push(game.nbp + "/" + game.maxnbp); 586 586 list.push(gameName); 587 587 list_data.push(i); 588 588 } … … 616 616 617 617 Engine.GetGUIObjectByName("sgMapName").caption = translateMapTitle(game.niceMapName); 618 618 Engine.GetGUIObjectByName("sgNbPlayers").caption = sprintf( 619 translate("Players: %(current)s/%( total)s"), {619 translate("Players: %(current)s/%(max)s"), { 620 620 "current": game.nbp, 621 " total": game.tnbp621 "max": game.maxnbp 622 622 }); 623 623 624 Engine.GetGUIObjectByName("sgPlayersNames").caption = game.players;624 Engine.GetGUIObjectByName("sgPlayersNames").caption = formatPlayerInfo(teamListToPlayerData(JSON.parse(unescapeText(game.players)))); 625 625 Engine.GetGUIObjectByName("sgMapSize").caption = translateMapSize(game.mapSize); 626 626 627 627 let mapTypeIdx = g_MapTypes.Name.indexOf(game.mapType); … … 653 653 654 654 let username = g_UserRating ? g_Username + " (" + g_UserRating + ")" : g_Username; 655 655 656 if (game.state == "init" || game.players.split(", ").indexOf(username) > -1)656 if (game.state == "init" || teamListToPlayerData(JSON.parse(unescapeText(game.players))).some(player => player.Name == username)) 657 657 joinSelectedGame(); 658 658 else 659 659 messageBox( -
binaries/data/mods/public/gui/session/messages.js
544 544 545 545 // Update lobby gamestatus 546 546 if (g_IsController && Engine.HasXmppClient()) 547 { 548 let players = Object.keys(g_PlayerAssignments).map(guid => g_PlayerAssignments[guid].name); 549 Engine.SendChangeStateGame(Object.keys(g_PlayerAssignments).length, players.join(", ")); 550 } 547 sendLobbyStanzaUpdate(); 551 548 } 552 549 553 550 function onClientJoin(guid) … … 746 743 747 744 function formatDefeatMessage(msg) 748 745 { 746 if (g_IsController && Engine.HasXmppClient()) 747 sendLobbyStanzaUpdate(); 748 749 749 return sprintf( 750 750 msg.resign ? 751 751 translate("%(player)s has resigned.") : -
binaries/data/mods/public/gui/session/session.js
288 288 if (hotloadData) 289 289 g_Selection.selected = hotloadData.selection; 290 290 291 if (g_IsController && Engine.HasXmppClient()) 292 sendLobbyStanzaUpdate(); 293 291 294 onSimulationUpdate(); 292 295 293 296 setTimeout(displayGamestateNotifications, 1000); -
binaries/data/mods/public/gui/session/utility_functions.js
131 131 alpha = alpha > 125 ? 125 : alpha; 132 132 return "color:255 0 0 " + alpha; 133 133 } 134 135 function sendLobbyStanzaUpdate() 136 { 137 let playerDataArray = clone(g_GameAttributes.settings.PlayerData); 138 let numberOfPlayers = 0; 139 let playerStates = {}; 140 141 for (let player of g_Players) 142 { 143 playerStates[player.name] = {}; 144 playerStates[player.name].State = player.state; 145 playerStates[player.name].Offline = player.offline; 146 } 147 148 for (let guid in g_PlayerAssignments) 149 { 150 let pData = g_GameAttributes.settings.PlayerData[g_PlayerAssignments[guid].player - 1]; 151 152 if (pData) 153 ++numberOfPlayers; 154 else 155 playerDataArray.push({ 156 "Name": g_PlayerAssignments[guid].name, 157 "Team": "observer" 158 }); 159 } 160 161 for (let playerData of playerDataArray) 162 { 163 delete playerData.Civ; 164 delete playerData.Color; 165 166 if (!g_GameAttributes.settings.LockTeams && playerData.Team != "observer") 167 delete playerData.Team; 168 169 let pState = playerStates[playerData.Name]; 170 if (pState) 171 { 172 playerData.State = pState.State; 173 playerData.Offline = pState.Offline; 174 } 175 } 176 Engine.SendChangeStateGame(numberOfPlayers, escapeText(JSON.stringify(playerDataToTeamList(playerDataArray)), false)); 177 } -
source/lobby/XmppClient.cpp
502 502 JSAutoRequest rq(cx); 503 503 504 504 scriptInterface.Eval("([])", ret); 505 const char* stats[] = { "name", "ip", "port", "state", "nbp", " tnbp", "players", "mapName", "niceMapName", "mapSize", "mapType", "victoryCondition" };505 const char* stats[] = { "name", "ip", "port", "state", "nbp", "maxnbp", "players", "mapName", "niceMapName", "mapSize", "mapType", "victoryCondition" }; 506 506 for(const glooxwrapper::Tag* const& t : m_GameList) 507 507 { 508 508 JS::RootedValue game(cx); -
source/tools/XpartaMuPP/XpartaMuPP.py
301 301 if JID in self.gameList: 302 302 if self.gameList[JID]['nbp-init'] > data['nbp']: 303 303 logging.debug("change game (%s) state from %s to %s", JID, self.gameList[JID]['state'], 'waiting') 304 self.gameList[JID]['nbp'] = data['nbp']305 304 self.gameList[JID]['state'] = 'waiting' 306 305 else: 307 306 logging.debug("change game (%s) state from %s to %s", JID, self.gameList[JID]['state'], 'running') 308 self.gameList[JID]['nbp'] = data['nbp']309 307 self.gameList[JID]['state'] = 'running' 308 self.gameList[JID]['nbp'] = data['nbp'] 309 self.gameList[JID]['players'] = data['players'] 310 310 311 311 ## Class which manages different game reports from clients ## 312 312 ## and calls leaderboard functions as appropriate. ##