diff --git a/OpenRA.Game/Widgets/Delegates/ServerBrowserDelegate.cs b/OpenRA.Game/Widgets/Delegates/ServerBrowserDelegate.cs index 22f6c77c77..436e1daad0 100644 --- a/OpenRA.Game/Widgets/Delegates/ServerBrowserDelegate.cs +++ b/OpenRA.Game/Widgets/Delegates/ServerBrowserDelegate.cs @@ -31,68 +31,16 @@ namespace OpenRA.Widgets.Delegates { static List GameButtons = new List(); + GameServer currentServer = null; + Widget ServerTemplate; + public ServerBrowserDelegate() { var r = Chrome.rootWidget; var bg = r.GetWidget("JOINSERVER_BG"); var dc = r.GetWidget("DIRECTCONNECT_BG"); - - MasterServerQuery.OnComplete += games => - { - 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; - - var margin = 20; - int height = 50; - int i = 0; - - foreach (var game in games.Where( g => g.State == 1 )) /* only "waiting for players" */ - { - var g = game; - var b = new ButtonWidget - { - Bounds = new Rectangle(margin, height, bg.Bounds.Width - 2 * margin, 25), - Id = "JOIN_GAME_{0}".F(i), - Text = "{0} ({2}/8, {3}) {1}".F( /* /8 = hack */ - game.Name, - game.Address, - game.Players, - string.Join( ",", game.Mods )), - Delegate = "ServerBrowserDelegate", - - OnMouseUp = nmi => - { - r.GetWidget("JOINSERVER_BG").Visible = false; - - Game.Settings.LastServer = g.Address; - Game.Settings.Save(); - - Game.JoinServer(g.Address.Split(':')[0], int.Parse(g.Address.Split(':')[1])); - Game.SetGameId(g.Id); - return true; - }, - }; - - bg.AddChild(b); - GameButtons.Add(b); - - height += 35; - } - - }; + + MasterServerQuery.OnComplete += games => RefreshServerList(games); r.GetWidget("MAINMENU_BUTTON_JOIN").OnMouseUp = mi => { @@ -108,8 +56,29 @@ namespace OpenRA.Widgets.Delegates return true; }; + + bg.GetWidget("SERVER_INFO").IsVisible = () => currentServer != null; + bg.GetWidget("MAP_PREVIEW").Map = () => CurrentMap(); + bg.GetWidget("MAP_CONTAINER").IsVisible = () => CurrentMap() != null; + + bg.GetWidget("SERVER_IP").GetText = () => currentServer.Address; + bg.GetWidget("SERVER_MODS").GetText = () => string.Join( ",", currentServer.Mods ); + bg.GetWidget("MAP_TITLE").GetText = () => (CurrentMap() != null) ? CurrentMap().Title : "Unknown"; + bg.GetWidget("MAP_PLAYERS").GetText = () => + { + if (currentServer == null) + return ""; + string ret = currentServer.Players.ToString(); + if (CurrentMap() != null) + ret += "/"+CurrentMap().PlayerCount.ToString(); + return ret; + }; + + + var sl = bg.GetWidget("SERVER_LIST"); + ServerTemplate = sl.GetWidget("SERVER_TEMPLATE"); - bg.GetWidget("JOINSERVER_BUTTON_REFRESH").OnMouseUp = mi => + bg.GetWidget("REFRESH_BUTTON").OnMouseUp = mi => { r.GetWidget("JOINSERVER_PROGRESS_TITLE").Visible = true; r.GetWidget("JOINSERVER_PROGRESS_TITLE").Text = "Fetching game list..."; @@ -122,13 +91,14 @@ namespace OpenRA.Widgets.Delegates return true; }; - bg.GetWidget("JOINSERVER_BUTTON_CANCEL").OnMouseUp = mi => + bg.GetWidget("CANCEL_BUTTON").OnMouseUp = mi => { r.CloseWindow(); return true; }; - bg.GetWidget("JOINSERVER_BUTTON_DIRECTCONNECT").OnMouseUp = mi => { + bg.GetWidget("DIRECTCONNECT_BUTTON").OnMouseUp = mi => + { r.CloseWindow(); dc.GetWidget("SERVER_ADDRESS").Text = Game.Settings.LastServer; @@ -136,7 +106,37 @@ namespace OpenRA.Widgets.Delegates return true; }; - dc.GetWidget("BUTTON_START").OnMouseUp = mi => { + bg.GetWidget("JOIN_BUTTON").OnMouseUp = mi => + { + if (currentServer == null) + return false; + + // Todo: Add an error dialog explaining why we aren't letting them join + // Or even better, reject them server side and display the error in the connection failed dialog. + + // Don't bother joining a server with different mods... its only going to crash + if (currentServer.Mods.SymmetricDifference(Game.LobbyInfo.GlobalSettings.Mods).Any()) + { + System.Console.WriteLine("Player has different mods to server; not connecting to avoid crash"); + System.Console.WriteLine("FIX THIS BUG YOU NOOB!"); + return false; + } + + // Prevent user joining a full server + if (CurrentMap() != null && currentServer.Players >= CurrentMap().PlayerCount) + { + System.Console.WriteLine("Server is full; not connecting"); + return false; + } + + r.CloseWindow(); + Game.JoinServer(currentServer.Address.Split(':')[0], int.Parse(currentServer.Address.Split(':')[1])); + Game.SetGameId(currentServer.Id); + return true; + }; + + // Direct Connect + dc.GetWidget("JOIN_BUTTON").OnMouseUp = mi => { var address = dc.GetWidget("SERVER_ADDRESS").Text; var cpts = address.Split(':').ToArray(); @@ -151,10 +151,65 @@ namespace OpenRA.Widgets.Delegates return true; }; - dc.GetWidget("BUTTON_CANCEL").OnMouseUp = mi => { + dc.GetWidget("CANCEL_BUTTON").OnMouseUp = mi => { r.CloseWindow(); return r.GetWidget("MAINMENU_BUTTON_JOIN").OnMouseUp(mi); }; } + + MapStub CurrentMap() + { + return (currentServer == null || !Game.AvailableMaps.ContainsKey(currentServer.Map)) ? null : Game.AvailableMaps[currentServer.Map]; + } + + void RefreshServerList(IEnumerable games) + { + var r = Chrome.rootWidget; + var bg = r.GetWidget("JOINSERVER_BG"); + var sl = bg.GetWidget("SERVER_LIST"); + + sl.Children.Clear(); + currentServer = null; + + if (games == null) + { + r.GetWidget("JOINSERVER_PROGRESS_TITLE").Visible = true; + r.GetWidget("JOINSERVER_PROGRESS_TITLE").Text = "Failed to contact master server."; + return; + } + + if (games.Count() == 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 offset = ServerTemplate.Bounds.Y; + int i = 0; + foreach (var game in games.Where( g => g.State == 1 )) /* only "waiting for players" */ + { + var template = ServerTemplate.Clone() as LabelWidget; + template.Id = "JOIN_GAME_{0}".F(i); + template.GetText = () => " {0} ({1})".F( /* /8 = hack */ + game.Name, + game.Address); + template.GetBackground = () => ((currentServer == game) ? "dialog2" : null); + template.OnMouseDown = mi => {currentServer = game; return true;}; + template.Parent = sl; + + template.Bounds = new Rectangle(template.Bounds.X, offset, template.Bounds.Width, template.Bounds.Height); + template.IsVisible = () => true; + sl.AddChild(template); + + if (i == 0) currentServer = game; + + offset += template.Bounds.Height; + sl.ContentHeight += template.Bounds.Height; + i++; + } + } } } diff --git a/mods/cnc/menus.yaml b/mods/cnc/menus.yaml index 2b2e08dd70..9ad30de5a2 100644 --- a/mods/cnc/menus.yaml +++ b/mods/cnc/menus.yaml @@ -322,45 +322,155 @@ Container: Delegate:ServerBrowserDelegate X:(WINDOW_RIGHT - WIDTH)/2 Y:(WINDOW_BOTTOM - HEIGHT)/2 - Width:450 - Height:400 + Width:700 + Height:410 Visible:false Children: Label@JOINSERVER_LABEL_TITLE: Id:JOINSERVER_LABEL_TITLE X:0 Y:20 - Width:450 + Width:PARENT_RIGHT Height:25 - Text:Quick'n'dirty Server Browser + Text:Join Server Align:Center Bold:True + ListBox@SERVER_LIST: + Id:SERVER_LIST + X:20 + Y:50 + Width:390 + Height:300 + Children: + Label@SERVER_TEMPLATE: + Id:SERVER_TEMPLATE + Width:PARENT_RIGHT-28 + Height:25 + ClickThrough:false + X:2 + Y:0 + Visible:false Label@JOINSERVER_PROGRESS_TITLE: Id:JOINSERVER_PROGRESS_TITLE - X:0 + X:150 Y:PARENT_BOTTOM / 2 - HEIGHT - Width:450 - Height:25 + Width:150 + Height:30 + Background:dialog4 Text:Fetching games... Align:Center - Button@JOINSERVER_BUTTON_DIRECTCONNECT: - Id:JOINSERVER_BUTTON_DIRECTCONNECT - X:PARENT_RIGHT - 140 - 130 - 130 + Container@SERVER_INFO: + Id:SERVER_INFO + X:0 + Y:0 + Width:PARENT_RIGHT + Height:PARENT_BOTTOM + Visible:false + Children: + Label@SERVER_IP_LABEL: + Id:SERVER_IP_LABEL + X:PARENT_RIGHT - 200 - WIDTH + Y:50 + Align:Right + Width:70 + Height:20 + Text:Server: + Bold:True + Label@SERVER_IP: + Id:SERVER_IP + X:PARENT_RIGHT - 195 + Y:50 + Align:Left + Width:70 + Height:20 + Label@SERVER_MODS_LABEL: + Id:SERVER_MODS_LABEL + X:PARENT_RIGHT - 200 - WIDTH + Y:70 + Align:Right + Width:70 + Height:20 + Text:Mods: + Bold:True + Label@SERVER_MODS: + Id:SERVER_MODS + X:PARENT_RIGHT - 195 + Y:70 + Align:Left + Width:70 + Height:20 + Label@MAP_TITLE_LABEL: + Id:MAP_TITLE_LABEL + X:PARENT_RIGHT - 200 - WIDTH + Y:90 + Align:Right + Width:70 + Height:20 + Text:Map: + Bold:True + Label@MAP_TITLE: + Id:MAP_TITLE + X:PARENT_RIGHT - 195 + Y:90 + Align:Left + Width:70 + Height:20 + Label@MAP_PLAYERS_LABEL: + Id:MAP_PLAYERS_LABEL + X:PARENT_RIGHT - 200 - WIDTH + Y:110 + Align:Right + Width:70 + Height:20 + Text:Players: + Bold:True + Label@MAP_PLAYERS: + Id:MAP_PLAYERS + X:PARENT_RIGHT - 195 + Y:110 + Align:Left + Width:70 + Height:20 + Background@MAP_CONTAINER: + Id:MAP_CONTAINER + X:PARENT_RIGHT-245 + Y:140 + Width:200 + Height:200 + Background:dialog3 + Children: + MapPreview@MAP_PREVIEW: + Id:MAP_PREVIEW + X:4 + Y:4 + Width:192 + Height:192 + Button@DIRECTCONNECT_BUTTON: + Id:DIRECTCONNECT_BUTTON + X:20 Y:PARENT_BOTTOM - 45 Width:120 Height:25 Text:Direct Connect Bold:True - Button@JOINSERVER_BUTTON_REFRESH: - Id:JOINSERVER_BUTTON_REFRESH - X:PARENT_RIGHT - 140 - 130 + Button@REFRESH_BUTTON: + Id:REFRESH_BUTTON + X:160 Y:PARENT_BOTTOM - 45 Width:120 Height:25 Text:Refresh Bold:True - Button@JOINSERVER_BUTTON_CANCEL: - Id:JOINSERVER_BUTTON_CANCEL + Button@JOIN_BUTTON: + Id:JOIN_BUTTON + X:PARENT_RIGHT - 140 - 130 + Y:PARENT_BOTTOM - 45 + Width:120 + Height:25 + Text:Join + Bold:True + Button@CANCEL_BUTTON: + Id:CANCEL_BUTTON X:PARENT_RIGHT - 140 Y:PARENT_BOTTOM - 45 Width:120 @@ -400,16 +510,16 @@ Container: Width:200 MaxLength:50 Height:25 - Button@BUTTON_START: - Id:BUTTON_START + Button@JOIN_BUTTON: + Id:JOIN_BUTTON X:130 Y:PARENT_BOTTOM - 45 Width:120 Height:25 Text:Join Bold:True - Button@BUTTON_CANCEL: - Id:BUTTON_CANCEL + Button@CANCEL_BUTTON: + Id:CANCEL_BUTTON X:260 Y:PARENT_BOTTOM - 45 Width:120 @@ -775,6 +885,19 @@ Container: X:2 Y:0 Visible:false + Background@MAPCHOOSER_MAP_BG: + X:PARENT_RIGHT-268 + Y:50 + Width:252 + Height:252 + Background:dialog3 + Children: + MapPreview@MAPCHOOSER_MAP_PREVIEW: + Id:MAPCHOOSER_MAP_PREVIEW + X:4 + Y:4 + Width:244 + Height:244 Label@CURMAP_TITLE_LABEL: Id:CURMAP_TITLE_LABEL X:PARENT_RIGHT - 200 - WIDTH @@ -839,19 +962,6 @@ Container: Align:Left Width:70 Height:20 - Background@MAPCHOOSER_MAP_BG: - X:PARENT_RIGHT-268 - Y:50 - Width:252 - Height:252 - Background:dialog3 - Children: - MapPreview@MAPCHOOSER_MAP_PREVIEW: - Id:MAPCHOOSER_MAP_PREVIEW - X:4 - Y:4 - Width:244 - Height:244 Button@BUTTON_OK: Id:BUTTON_OK X:PARENT_RIGHT - 360 diff --git a/mods/ra/menus.yaml b/mods/ra/menus.yaml index 8ffb4ce7e8..bfe4a51fe7 100644 --- a/mods/ra/menus.yaml +++ b/mods/ra/menus.yaml @@ -322,45 +322,155 @@ Container: Delegate:ServerBrowserDelegate X:(WINDOW_RIGHT - WIDTH)/2 Y:(WINDOW_BOTTOM - HEIGHT)/2 - Width:450 - Height:400 + Width:700 + Height:410 Visible:false Children: Label@JOINSERVER_LABEL_TITLE: Id:JOINSERVER_LABEL_TITLE X:0 Y:20 - Width:450 + Width:PARENT_RIGHT Height:25 - Text:Quick'n'dirty Server Browser + Text:Join Server Align:Center Bold:True + ListBox@SERVER_LIST: + Id:SERVER_LIST + X:20 + Y:50 + Width:390 + Height:300 + Children: + Label@SERVER_TEMPLATE: + Id:SERVER_TEMPLATE + Width:PARENT_RIGHT-28 + Height:25 + ClickThrough:false + X:2 + Y:0 + Visible:false Label@JOINSERVER_PROGRESS_TITLE: Id:JOINSERVER_PROGRESS_TITLE - X:0 + X:150 Y:PARENT_BOTTOM / 2 - HEIGHT - Width:450 - Height:25 + Width:150 + Height:30 + Background:dialog4 Text:Fetching games... Align:Center - Button@JOINSERVER_BUTTON_DIRECTCONNECT: - Id:JOINSERVER_BUTTON_DIRECTCONNECT - X:PARENT_RIGHT - 140 - 130 - 130 + Container@SERVER_INFO: + Id:SERVER_INFO + X:0 + Y:0 + Width:PARENT_RIGHT + Height:PARENT_BOTTOM + Visible:false + Children: + Label@SERVER_IP_LABEL: + Id:SERVER_IP_LABEL + X:PARENT_RIGHT - 200 - WIDTH + Y:50 + Align:Right + Width:70 + Height:20 + Text:Server: + Bold:True + Label@SERVER_IP: + Id:SERVER_IP + X:PARENT_RIGHT - 195 + Y:50 + Align:Left + Width:70 + Height:20 + Label@SERVER_MODS_LABEL: + Id:SERVER_MODS_LABEL + X:PARENT_RIGHT - 200 - WIDTH + Y:70 + Align:Right + Width:70 + Height:20 + Text:Mods: + Bold:True + Label@SERVER_MODS: + Id:SERVER_MODS + X:PARENT_RIGHT - 195 + Y:70 + Align:Left + Width:70 + Height:20 + Label@MAP_TITLE_LABEL: + Id:MAP_TITLE_LABEL + X:PARENT_RIGHT - 200 - WIDTH + Y:90 + Align:Right + Width:70 + Height:20 + Text:Map: + Bold:True + Label@MAP_TITLE: + Id:MAP_TITLE + X:PARENT_RIGHT - 195 + Y:90 + Align:Left + Width:70 + Height:20 + Label@MAP_PLAYERS_LABEL: + Id:MAP_PLAYERS_LABEL + X:PARENT_RIGHT - 200 - WIDTH + Y:110 + Align:Right + Width:70 + Height:20 + Text:Players: + Bold:True + Label@MAP_PLAYERS: + Id:MAP_PLAYERS + X:PARENT_RIGHT - 195 + Y:110 + Align:Left + Width:70 + Height:20 + Background@MAP_CONTAINER: + Id:MAP_CONTAINER + X:PARENT_RIGHT-245 + Y:140 + Width:200 + Height:200 + Background:dialog3 + Children: + MapPreview@MAP_PREVIEW: + Id:MAP_PREVIEW + X:4 + Y:4 + Width:192 + Height:192 + Button@DIRECTCONNECT_BUTTON: + Id:DIRECTCONNECT_BUTTON + X:20 Y:PARENT_BOTTOM - 45 Width:120 Height:25 Text:Direct Connect Bold:True - Button@JOINSERVER_BUTTON_REFRESH: - Id:JOINSERVER_BUTTON_REFRESH - X:PARENT_RIGHT - 140 - 130 + Button@REFRESH_BUTTON: + Id:REFRESH_BUTTON + X:160 Y:PARENT_BOTTOM - 45 Width:120 Height:25 Text:Refresh Bold:True - Button@JOINSERVER_BUTTON_CANCEL: - Id:JOINSERVER_BUTTON_CANCEL + Button@JOIN_BUTTON: + Id:JOIN_BUTTON + X:PARENT_RIGHT - 140 - 130 + Y:PARENT_BOTTOM - 45 + Width:120 + Height:25 + Text:Join + Bold:True + Button@CANCEL_BUTTON: + Id:CANCEL_BUTTON X:PARENT_RIGHT - 140 Y:PARENT_BOTTOM - 45 Width:120 @@ -400,16 +510,16 @@ Container: Width:200 MaxLength:50 Height:25 - Button@BUTTON_START: - Id:BUTTON_START + Button@JOIN_BUTTON: + Id:JOIN_BUTTON X:130 Y:PARENT_BOTTOM - 45 Width:120 Height:25 Text:Join Bold:True - Button@BUTTON_CANCEL: - Id:BUTTON_CANCEL + Button@CANCEL_BUTTON: + Id:CANCEL_BUTTON X:260 Y:PARENT_BOTTOM - 45 Width:120 @@ -775,6 +885,19 @@ Container: X:2 Y:0 Visible:false + Background@MAPCHOOSER_MAP_BG: + X:PARENT_RIGHT-268 + Y:50 + Width:252 + Height:252 + Background:dialog3 + Children: + MapPreview@MAPCHOOSER_MAP_PREVIEW: + Id:MAPCHOOSER_MAP_PREVIEW + X:4 + Y:4 + Width:244 + Height:244 Label@CURMAP_TITLE_LABEL: Id:CURMAP_TITLE_LABEL X:PARENT_RIGHT - 200 - WIDTH @@ -839,19 +962,6 @@ Container: Align:Left Width:70 Height:20 - Background@MAPCHOOSER_MAP_BG: - X:PARENT_RIGHT-268 - Y:50 - Width:252 - Height:252 - Background:dialog3 - Children: - MapPreview@MAPCHOOSER_MAP_PREVIEW: - Id:MAPCHOOSER_MAP_PREVIEW - X:4 - Y:4 - Width:244 - Height:244 Button@BUTTON_OK: Id:BUTTON_OK X:PARENT_RIGHT - 360 @@ -1100,6 +1210,4 @@ Container: Width:25 Height:25 ImageCollection:music - ImageName:prev - - + ImageName:prev \ No newline at end of file