diff --git a/OpenRA.FileFormats/FieldLoader.cs b/OpenRA.FileFormats/FieldLoader.cs index 1f765309a5..5e250651d6 100644 --- a/OpenRA.FileFormats/FieldLoader.cs +++ b/OpenRA.FileFormats/FieldLoader.cs @@ -39,6 +39,13 @@ namespace OpenRA.FileFormats if (!x.Key.StartsWith("-")) LoadField( self, x.Key, x.Value.Value ); } + + public static T Load(MiniYaml y) where T : new() + { + var t = new T(); + Load(t, y); + return t; + } public static void LoadFields( object self, Dictionary my, IEnumerable fields ) { diff --git a/OpenRA.Game/Game.cs b/OpenRA.Game/Game.cs index 2ba6d8e029..dff9302d5c 100644 --- a/OpenRA.Game/Game.cs +++ b/OpenRA.Game/Game.cs @@ -34,6 +34,7 @@ using OpenRA.Traits; using Timer = OpenRA.Support.Timer; using XRandom = OpenRA.Thirdparty.Random; +using OpenRA.Server; namespace OpenRA { @@ -258,6 +259,8 @@ namespace OpenRA PerfHistory.items["batches"].Tick(); PerfHistory.items["text"].Tick(); PerfHistory.items["cursor"].Tick(); + + MasterServerQuery.Tick(); } public static void SyncLobbyInfo(string data) diff --git a/OpenRA.Game/Server/MasterServerQuery.cs b/OpenRA.Game/Server/MasterServerQuery.cs index d15a7171ad..627a6e7b70 100644 --- a/OpenRA.Game/Server/MasterServerQuery.cs +++ b/OpenRA.Game/Server/MasterServerQuery.cs @@ -4,20 +4,45 @@ using System.Linq; using System.Text; using System.Net; using OpenRA.FileFormats; +using System.Threading; namespace OpenRA.Server { static class MasterServerQuery { - public static IEnumerable GetGameList(string masterServerUrl) - { - var wc = new WebClient(); - var data = wc.DownloadData(masterServerUrl + "list.php"); - var str = Encoding.UTF8.GetString(data); + public static event Action OnComplete = _ => { }; - var yaml = MiniYaml.FromString(str); - return yaml.Select(a => { var gs = new GameServer(); FieldLoader.Load(gs, a.Value); return gs; }) - .Where(gs => gs.Address != null); + static GameServer[] Games = { }; + static AutoResetEvent ev = new AutoResetEvent(false); + + public static void Refresh(string masterServerUrl) + { + new Thread(() => + { + try + { + var wc = new WebClient(); + var data = wc.DownloadData(new Uri(masterServerUrl + "list.php")); + var str = Encoding.UTF8.GetString(data); + + var yaml = MiniYaml.FromString(str); + + Games = yaml.Select(a => FieldLoader.Load(a.Value)) + .Where(gs => gs.Address != null).ToArray(); + } + catch + { + Games = null; + } + + ev.Set(); + }).Start(); + } + + public static void Tick() + { + if (ev.WaitOne(TimeSpan.FromMilliseconds(0))) + OnComplete(Games); } } diff --git a/OpenRA.Game/Traits/World/ResourceLayer.cs b/OpenRA.Game/Traits/World/ResourceLayer.cs index a391bf627e..ad44266cb5 100644 --- a/OpenRA.Game/Traits/World/ResourceLayer.cs +++ b/OpenRA.Game/Traits/World/ResourceLayer.cs @@ -88,7 +88,6 @@ namespace OpenRA.Traits content[x, y].image = ChooseContent(content[x, y].type); } - for (int x = map.XOffset; x < map.XOffset + map.Width; x++) for (int y = map.YOffset; y < map.YOffset + map.Height; y++) if (content[x, y].type != null) diff --git a/OpenRA.Game/Widgets/Delegates/ServerBrowserDelegate.cs b/OpenRA.Game/Widgets/Delegates/ServerBrowserDelegate.cs index a678e4043c..5b6d1f23f6 100644 --- a/OpenRA.Game/Widgets/Delegates/ServerBrowserDelegate.cs +++ b/OpenRA.Game/Widgets/Delegates/ServerBrowserDelegate.cs @@ -22,64 +22,104 @@ using System.Collections.Generic; using System.Drawing; using System.Linq; using OpenRA.Server; +using OpenRA.FileFormats; +using System; namespace OpenRA.Widgets.Delegates { public class ServerBrowserDelegate : IWidgetDelegate { - static GameServer[] GameList; static List GameButtons = new List(); public ServerBrowserDelegate() { var r = Chrome.rootWidget; - r.GetWidget("MAINMENU_BUTTON_JOIN").OnMouseUp = - mi => { + + MasterServerQuery.OnComplete += games => + { + var bg = r.GetWidget("JOINSERVER_BG"); + + if (games == null) + { + r.GetWidget("JOINSERVER_PROGRESS_TITLE").Visible = true; + r.GetWidget("JOINSERVER_PROGRESS_TITLE").Text = "Failed to contact master server."; + return; + } + + if (games.Length == 0) + { + r.GetWidget("JOINSERVER_PROGRESS_TITLE").Visible = true; + r.GetWidget("JOINSERVER_PROGRESS_TITLE").Text = "No games found."; + return; + } + + r.GetWidget("JOINSERVER_PROGRESS_TITLE").Visible = false; + + int height = 50; + int width = 300; + int i = 0; + + foreach (var game in games) + { + var g = game; + var b = new ButtonWidget + { + Bounds = new Rectangle(bg.Bounds.X + 20, bg.Bounds.Y + height, width, 25), + Id = "JOIN_GAME_{0}".F(i), + Text = "{0} ({1})".F(game.Name, game.Address), + Delegate = "ServerBrowserDelegate", + + OnMouseUp = nmi => + { + r.GetWidget("JOINSERVER_BG").Visible = false; + Game.JoinServer(g.Address.Split(':')[0], int.Parse(g.Address.Split(':')[1])); + return true; + }, + }; + + bg.AddChild(b); + GameButtons.Add(b); + + height += 35; + } + + }; + + r.GetWidget("MAINMENU_BUTTON_JOIN").OnMouseUp = mi => + { var bg = r.OpenWindow("JOINSERVER_BG"); - int height = 50; - int width = 300; - int i = 0; - GameList = MasterServerQuery.GetGameList(Game.Settings.MasterServer).ToArray(); + + r.GetWidget("JOINSERVER_PROGRESS_TITLE").Visible = true; + r.GetWidget("JOINSERVER_PROGRESS_TITLE").Text = "Fetching game list..."; bg.Children.RemoveAll(a => GameButtons.Contains(a)); GameButtons.Clear(); - foreach (var game in GameList) - { - var b = new ButtonWidget - { - Bounds = new Rectangle(bg.Bounds.X + 20, bg.Bounds.Y + height, width, 25), - Id = "JOIN_GAME_{0}".F( i ), - Text = "{0} ({1})".F( game.Name, game.Address ), - Delegate = "ServerBrowserDelegate", - - OnMouseUp = nmi => - { - r.GetWidget("JOINSERVER_BG").Visible = false; - Game.JoinServer(GameList[i].Address.Split(':')[0], int.Parse(GameList[i].Address.Split(':')[1])); - return true; - }, - }; - - bg.AddChild(b); - GameButtons.Add(b); - - height += 35; - } + MasterServerQuery.Refresh(Game.Settings.MasterServer); return true; }; - - r.GetWidget("JOINSERVER_BUTTON_DIRECTCONNECT").OnMouseUp = mi => { - r.CloseWindow(); - Game.JoinServer(Game.Settings.NetworkHost, Game.Settings.NetworkPort); + + r.GetWidget("JOINSERVER_BUTTON_REFRESH").OnMouseUp = mi => + { + var bg = r.GetWidget("JOINSERVER_BG"); + + r.GetWidget("JOINSERVER_PROGRESS_TITLE").Visible = true; + r.GetWidget("JOINSERVER_PROGRESS_TITLE").Text = "Fetching game list..."; + + bg.Children.RemoveAll(a => GameButtons.Contains(a)); + GameButtons.Clear(); + + MasterServerQuery.Refresh(Game.Settings.MasterServer); + return true; }; - - r.GetWidget("JOINSERVER_BUTTON_CANCEL").OnMouseUp = mi => { + + r.GetWidget("JOINSERVER_BUTTON_CANCEL").OnMouseUp = mi => + { r.CloseWindow(); return true; }; } - } + } } diff --git a/OpenRA.Game/Widgets/Widget.cs b/OpenRA.Game/Widgets/Widget.cs index 54e689ee67..fc9e5321a0 100644 --- a/OpenRA.Game/Widgets/Widget.cs +++ b/OpenRA.Game/Widgets/Widget.cs @@ -43,6 +43,7 @@ namespace OpenRA.Widgets // Calculated internally public Rectangle Bounds; public Widget Parent = null; + static List Delegates = new List(); public static Stack WindowList = new Stack(); diff --git a/mods/ra/menus.yaml b/mods/ra/menus.yaml index 3c4b789b79..e4fea7bda2 100644 --- a/mods/ra/menus.yaml +++ b/mods/ra/menus.yaml @@ -160,13 +160,21 @@ Container: Height:25 Text:Quick'n'dirty Server Browser Align:Center - Button@JOINSERVER_BUTTON_DIRECTCONNECT: - Id:JOINSERVER_BUTTON_DIRECTCONNECT + Label@JOINSERVER_PROGRESS_TITLE: + Id:JOINSERVER_PROGRESS_TITLE + X:0 + Y:PARENT_BOTTOM / 2 - HEIGHT + Width:450 + Height:25 + Text:Fetching games... + Align:Center + Button@JOINSERVER_BUTTON_REFRESH: + Id:JOINSERVER_BUTTON_REFRESH X:PARENT_RIGHT - 360 Y:PARENT_BOTTOM - 45 Width:160 Height:25 - Text:Direct Connect + Text:Refresh Button@JOINSERVER_BUTTON_CANCEL: Id:JOINSERVER_BUTTON_CANCEL X:PARENT_RIGHT - 180