diff --git a/OpenRA.Game/Network/ServerList.cs b/OpenRA.Game/Network/ServerList.cs deleted file mode 100644 index 55cff8dc47..0000000000 --- a/OpenRA.Game/Network/ServerList.cs +++ /dev/null @@ -1,52 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see COPYING. - */ -#endregion - -using System; -using System.Linq; -using System.Net; -using System.Text; -using System.Threading; -using OpenRA.FileFormats; - -namespace OpenRA.Network -{ - public static class ServerList - { - public static void Query(Action onComplete) - { - var masterServerUrl = Game.Settings.Server.MasterServer; - - new Thread(() => - { - GameServer[] games = null; - try - { - var str = GetData(new Uri(masterServerUrl + "list.php")); - - var yaml = MiniYaml.FromString(str); - - games = yaml.Select(a => FieldLoader.Load(a.Value)) - .Where(gs => gs.Address != null).ToArray(); - } - catch { } - - Game.RunAfterTick(() => onComplete(games)); - }) { IsBackground = true }.Start(); - } - - static string GetData(Uri uri) - { - var wc = new WebClient(); - wc.Proxy = null; - var data = wc.DownloadData(uri); - return Encoding.UTF8.GetString(data); - } - } -} diff --git a/OpenRA.Game/OpenRA.Game.csproj b/OpenRA.Game/OpenRA.Game.csproj index c0d217d017..6d13a70cd9 100644 --- a/OpenRA.Game/OpenRA.Game.csproj +++ b/OpenRA.Game/OpenRA.Game.csproj @@ -130,7 +130,6 @@ - diff --git a/OpenRA.Mods.RA/Widgets/Logic/ServerBrowserLogic.cs b/OpenRA.Mods.RA/Widgets/Logic/ServerBrowserLogic.cs index efe0dd4371..7e09dc7ccd 100644 --- a/OpenRA.Mods.RA/Widgets/Logic/ServerBrowserLogic.cs +++ b/OpenRA.Mods.RA/Widgets/Logic/ServerBrowserLogic.cs @@ -12,6 +12,8 @@ using System; using System.Collections.Generic; using System.Linq; using System.Drawing; +using System.Net; +using System.Text; using OpenRA.FileFormats; using OpenRA.Network; using OpenRA.Server; @@ -29,6 +31,8 @@ namespace OpenRA.Mods.RA.Widgets.Logic enum SearchStatus { Fetching, Failed, NoGames, Hidden } SearchStatus searchStatus = SearchStatus.Fetching; + Download currentQuery; + Widget panel, serverList; bool showWaiting = true; bool showEmpty = true; @@ -39,7 +43,6 @@ namespace OpenRA.Mods.RA.Widgets.Logic { switch (searchStatus) { - case SearchStatus.Fetching: return "Fetching game list..."; case SearchStatus.Failed: return "Failed to contact master server."; case SearchStatus.NoGames: return "No games found."; default: return ""; @@ -49,16 +52,18 @@ namespace OpenRA.Mods.RA.Widgets.Logic [ObjectCreator.UseCtor] public ServerBrowserLogic(Widget widget, Action onStart, Action onExit) { - var panel = widget; + panel = widget; this.onStart = onStart; this.onExit = onExit; - var sl = panel.Get("SERVER_LIST"); + serverList = panel.Get("SERVER_LIST"); + serverTemplate = serverList.Get("SERVER_TEMPLATE"); // Menu buttons var refreshButton = panel.Get("REFRESH_BUTTON"); refreshButton.IsDisabled = () => searchStatus == SearchStatus.Fetching; - refreshButton.OnClick = () => ServerList.Query(games => RefreshServerList(panel, games)); + refreshButton.GetText = () => searchStatus == SearchStatus.Fetching ? "Refreshing..." : "Refresh"; + refreshButton.OnClick = RefreshServerList; panel.Get("DIRECTCONNECT_BUTTON").OnClick = OpenDirectConnectPanel; panel.Get("CREATE_BUTTON").OnClick = OpenCreateServerPanel; @@ -69,9 +74,6 @@ namespace OpenRA.Mods.RA.Widgets.Logic panel.Get("BACK_BUTTON").OnClick = () => { Ui.CloseWindow(); onExit(); }; - // Server list - serverTemplate = sl.Get("SERVER_TEMPLATE"); - // Display the progress label over the server list // The text is only visible when the list is empty var progressText = panel.Get("PROGRESS_LABEL"); @@ -82,33 +84,163 @@ namespace OpenRA.Mods.RA.Widgets.Logic if (showWaitingCheckbox != null) { showWaitingCheckbox.IsChecked = () => showWaiting; - showWaitingCheckbox.OnClick = () => { showWaiting ^= true; ServerList.Query(games => RefreshServerList(panel, games)); }; + showWaitingCheckbox.OnClick = () => { showWaiting ^= true; RefreshServerList(); }; } var showEmptyCheckbox = panel.GetOrNull("EMPTY"); if (showEmptyCheckbox != null) { showEmptyCheckbox.IsChecked = () => showEmpty; - showEmptyCheckbox.OnClick = () => { showEmpty ^= true; ServerList.Query(games => RefreshServerList(panel, games)); }; + showEmptyCheckbox.OnClick = () => { showEmpty ^= true; RefreshServerList(); }; } var showAlreadyStartedCheckbox = panel.GetOrNull("ALREADY_STARTED"); if (showAlreadyStartedCheckbox != null) { showAlreadyStartedCheckbox.IsChecked = () => showStarted; - showAlreadyStartedCheckbox.OnClick = () => { showStarted ^= true; ServerList.Query(games => RefreshServerList(panel, games)); }; + showAlreadyStartedCheckbox.OnClick = () => { showStarted ^= true; RefreshServerList(); }; } var showIncompatibleCheckbox = panel.GetOrNull("INCOMPATIBLE_VERSION"); if (showIncompatibleCheckbox != null) { showIncompatibleCheckbox.IsChecked = () => showIncompatible; - showIncompatibleCheckbox.OnClick = () => { showIncompatible ^= true; ServerList.Query(games => RefreshServerList(panel, games)); }; + showIncompatibleCheckbox.OnClick = () => { showIncompatible ^= true; RefreshServerList(); }; } // Game.LoadWidget(null, "SERVERBROWSER_IRC", panel.Get("IRC_ROOT"), new WidgetArgs()); + RefreshServerList(); + } - ServerList.Query(games => RefreshServerList(panel, games)); + void RefreshServerList() + { + // Query in progress + if (currentQuery != null) + return; + + searchStatus = SearchStatus.Fetching; + + Action onComplete = (i, cancelled) => + { + currentQuery = null; + + if (i.Error != null || cancelled) + { + RefreshServerListInner(null); + return; + } + + var data = Encoding.UTF8.GetString(i.Result); + var yaml = MiniYaml.FromString(data); + + var games = yaml.Select(a => FieldLoader.Load(a.Value)) + .Where(gs => gs.Address != null); + + RefreshServerListInner(games); + Game.RunAfterTick(() => RefreshServerListInner(games)); + }; + + currentQuery = new Download(Game.Settings.Server.MasterServer + "list.php", _ => {}, onComplete); + } + + public void RefreshServerListInner(IEnumerable games) + { + List rows = new List(); + + Game.RunAfterTick(() => + { + serverList.RemoveChildren(); + currentServer = null; + + if (games == null) + { + searchStatus = SearchStatus.Failed; + return; + } + + if (!games.Any()) + { + searchStatus = SearchStatus.NoGames; + return; + } + + currentServer = games.FirstOrDefault(); + searchStatus = SearchStatus.Hidden; + + foreach (var row in rows) + serverList.AddChild(row); + }); + + foreach (var loop in games.OrderByDescending(g => g.CanJoin()).ThenByDescending(g => g.Players)) + { + var game = loop; + if (game == null) + continue; + + var canJoin = game.CanJoin(); + + var item = ScrollItemWidget.Setup(serverTemplate, () => currentServer == game, () => currentServer = game, () => Join(game)); + + var map = Game.modData.MapCache[game.Map]; + var preview = item.GetOrNull("MAP_PREVIEW"); + if (preview != null) + preview.Preview = () => map; + + var title = item.GetOrNull("TITLE"); + if (title != null) + { + title.GetText = () => game.Name; + title.GetColor = () => canJoin ? title.TextColor : Color.Gray; + } + + var maptitle = item.GetOrNull("MAP"); + if (title != null) + { + maptitle.GetText = () => map.Title; + maptitle.GetColor = () => canJoin ? maptitle.TextColor : Color.Gray; + } + + var players = item.GetOrNull("PLAYERS"); + if (players != null) + { + players.GetText = () => "{0} / {1}".F(game.Players, map.PlayerCount); + players.GetColor = () => canJoin ? players.TextColor : Color.Gray; + } + + var state = item.GetOrNull("STATE"); + if (state != null) + { + state.GetText = () => GetStateLabel(game); + state.GetColor = () => canJoin ? state.TextColor : Color.Gray; + } + + var ip = item.GetOrNull("IP"); + if (ip != null) + { + ip.GetText = () => game.Address; + ip.GetColor = () => canJoin ? ip.TextColor : Color.Gray; + } + + var version = item.GetOrNull("VERSION"); + if (version != null) + { + version.GetText = () => GenerateModLabel(game); + version.IsVisible = () => !game.CompatibleVersion(); + version.GetColor = () => canJoin ? version.TextColor : Color.Gray; + } + + var location = item.GetOrNull("LOCATION"); + if (location != null) + { + var cachedServerLocation = LobbyUtils.LookupCountry(game.Address.Split(':')[0]); + location.GetText = () => cachedServerLocation; + location.IsVisible = () => game.CompatibleVersion(); + location.GetColor = () => canJoin ? location.TextColor : Color.Gray; + } + + if (!Filtered(game)) + rows.Add(item); + } } void OpenLobby()