From 1020d456647a8412ab052531d0c001681c2c0abc Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Fri, 14 Mar 2014 13:30:03 +1300 Subject: [PATCH 1/9] Split lobby map preview into its own logic class. --- OpenRA.Mods.RA/OpenRA.Mods.RA.csproj | 1 + OpenRA.Mods.RA/Widgets/Logic/LobbyLogic.cs | 64 ++++++++----------- .../Widgets/Logic/LobbyMapPreviewLogic.cs | 44 +++++++++++++ mods/cnc/chrome/lobby-mappreview.yaml | 36 +++++++++++ mods/cnc/chrome/lobby.yaml | 37 +---------- mods/cnc/mod.yaml | 1 + mods/d2k/mod.yaml | 1 + mods/ra/chrome/lobby-mappreview.yaml | 36 +++++++++++ mods/ra/chrome/lobby.yaml | 37 +---------- mods/ra/mod.yaml | 1 + mods/ts/mod.yaml | 1 + 11 files changed, 154 insertions(+), 105 deletions(-) create mode 100644 OpenRA.Mods.RA/Widgets/Logic/LobbyMapPreviewLogic.cs create mode 100644 mods/cnc/chrome/lobby-mappreview.yaml create mode 100644 mods/ra/chrome/lobby-mappreview.yaml diff --git a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj index 87dd4e031a..454ae9097b 100644 --- a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj +++ b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj @@ -487,6 +487,7 @@ + diff --git a/OpenRA.Mods.RA/Widgets/Logic/LobbyLogic.cs b/OpenRA.Mods.RA/Widgets/Logic/LobbyLogic.cs index 0c42be7d1b..739301a51a 100644 --- a/OpenRA.Mods.RA/Widgets/Logic/LobbyLogic.cs +++ b/OpenRA.Mods.RA/Widgets/Logic/LobbyLogic.cs @@ -23,6 +23,8 @@ namespace OpenRA.Mods.RA.Widgets.Logic { static readonly Action DoNothing = () => { }; + public MapPreview Map = MapCache.UnknownMap; + readonly Action onStart; readonly Action onExit; readonly OrderManager orderManager; @@ -41,7 +43,6 @@ namespace OpenRA.Mods.RA.Widgets.Logic ScrollPanelWidget players; Dictionary countryNames; - MapPreview preview = MapCache.UnknownMap; ColorPreviewManagerWidget colorPreview; @@ -108,6 +109,12 @@ namespace OpenRA.Mods.RA.Widgets.Logic if (name != null) name.GetText = () => orderManager.LobbyInfo.GlobalSettings.ServerName; + Ui.LoadWidget("LOBBY_MAP_PREVIEW", lobby.Get("MAP_PREVIEW_ROOT"), new WidgetArgs + { + { "orderManager", orderManager }, + { "lobby", this } + }); + UpdateCurrentMap(); players = Ui.LoadWidget("LOBBY_PLAYER_BIN", lobby.Get("PLAYER_BIN_ROOT"), new WidgetArgs()); players.IsVisible = () => panel == PanelType.Players; @@ -125,23 +132,6 @@ namespace OpenRA.Mods.RA.Widgets.Logic colorPreview = lobby.Get("COLOR_MANAGER"); colorPreview.Color = Game.Settings.Player.Color; - var mapPreview = lobby.Get("MAP_PREVIEW"); - mapPreview.Preview = () => preview; - mapPreview.OnMouseDown = mi => LobbyUtils.SelectSpawnPoint(orderManager, mapPreview, preview, mi); - mapPreview.SpawnClients = () => LobbyUtils.GetSpawnClients(orderManager, preview); - - var mapTitle = lobby.GetOrNull("MAP_TITLE"); - if (mapTitle != null) - mapTitle.GetText = () => preview.Title; - - var mapType = lobby.GetOrNull("MAP_TYPE"); - if (mapType != null) - mapType.GetText = () => preview.Type; - - var mapAuthor = lobby.GetOrNull("MAP_AUTHOR"); - if (mapAuthor != null) - mapAuthor.GetText = () => "Created by {0}".F(preview.Author); - countryNames = Rules.Info["world"].Traits.WithInterface() .Where(c => c.Selectable) .ToDictionary(a => a.Race, a => a.Name); @@ -166,7 +156,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic Ui.OpenWindow("MAPCHOOSER_PANEL", new WidgetArgs() { - { "initialMap", preview.Uid }, + { "initialMap", Map.Uid }, { "onExit", DoNothing }, { "onSelect", onSelect } }); @@ -300,7 +290,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic if (allowCheats != null) { allowCheats.IsChecked = () => orderManager.LobbyInfo.GlobalSettings.AllowCheats; - allowCheats.IsDisabled = () => preview.Status != MapStatus.Available || preview.Map.Options.Cheats.HasValue || configurationDisabled(); + allowCheats.IsDisabled = () => Map.Status != MapStatus.Available || Map.Map.Options.Cheats.HasValue || configurationDisabled(); allowCheats.OnClick = () => orderManager.IssueOrder(Order.Command( "allowcheats {0}".F(!orderManager.LobbyInfo.GlobalSettings.AllowCheats))); } @@ -309,7 +299,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic if (crates != null) { crates.IsChecked = () => orderManager.LobbyInfo.GlobalSettings.Crates; - crates.IsDisabled = () => preview.Status != MapStatus.Available || preview.Map.Options.Crates.HasValue || configurationDisabled(); + crates.IsDisabled = () => Map.Status != MapStatus.Available || Map.Map.Options.Crates.HasValue || configurationDisabled(); crates.OnClick = () => orderManager.IssueOrder(Order.Command( "crates {0}".F(!orderManager.LobbyInfo.GlobalSettings.Crates))); } @@ -318,7 +308,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic if (allybuildradius != null) { allybuildradius.IsChecked = () => orderManager.LobbyInfo.GlobalSettings.AllyBuildRadius; - allybuildradius.IsDisabled = () => preview.Status != MapStatus.Available || preview.Map.Options.AllyBuildRadius.HasValue || configurationDisabled(); + allybuildradius.IsDisabled = () => Map.Status != MapStatus.Available || Map.Map.Options.AllyBuildRadius.HasValue || configurationDisabled(); allybuildradius.OnClick = () => orderManager.IssueOrder(Order.Command( "allybuildradius {0}".F(!orderManager.LobbyInfo.GlobalSettings.AllyBuildRadius))); } @@ -327,7 +317,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic if (fragileAlliance != null) { fragileAlliance.IsChecked = () => orderManager.LobbyInfo.GlobalSettings.FragileAlliances; - fragileAlliance.IsDisabled = () => preview.Status != MapStatus.Available || preview.Map.Options.FragileAlliances.HasValue || configurationDisabled(); + fragileAlliance.IsDisabled = () => Map.Status != MapStatus.Available || Map.Map.Options.FragileAlliances.HasValue || configurationDisabled(); fragileAlliance.OnClick = () => orderManager.IssueOrder(Order.Command( "fragilealliance {0}".F(!orderManager.LobbyInfo.GlobalSettings.FragileAlliances))); } @@ -335,12 +325,12 @@ namespace OpenRA.Mods.RA.Widgets.Logic var difficulty = optionsBin.GetOrNull("DIFFICULTY_DROPDOWNBUTTON"); if (difficulty != null) { - difficulty.IsVisible = () => preview.Status == MapStatus.Available && preview.Map.Options.Difficulties.Any(); - difficulty.IsDisabled = () => preview.Status != MapStatus.Available || configurationDisabled(); + difficulty.IsVisible = () => Map.Status == MapStatus.Available && Map.Map.Options.Difficulties.Any(); + difficulty.IsDisabled = () => Map.Status != MapStatus.Available || configurationDisabled(); difficulty.GetText = () => orderManager.LobbyInfo.GlobalSettings.Difficulty; difficulty.OnMouseDown = _ => { - var options = preview.Map.Options.Difficulties.Select(d => new DropDownOption + var options = Map.Map.Options.Difficulties.Select(d => new DropDownOption { Title = d, IsSelected = () => orderManager.LobbyInfo.GlobalSettings.Difficulty == d, @@ -372,8 +362,8 @@ namespace OpenRA.Mods.RA.Widgets.Logic var classes = Rules.Info["world"].Traits.WithInterface() .Select(a => a.Class).Distinct(); - startingUnits.IsDisabled = () => preview.Status != MapStatus.Available || !preview.Map.Options.ConfigurableStartingUnits || configurationDisabled(); - startingUnits.GetText = () => preview.Status != MapStatus.Available || !preview.Map.Options.ConfigurableStartingUnits ? "Not Available" : className(orderManager.LobbyInfo.GlobalSettings.StartingUnitsClass); + startingUnits.IsDisabled = () => Map.Status != MapStatus.Available || !Map.Map.Options.ConfigurableStartingUnits || configurationDisabled(); + startingUnits.GetText = () => Map.Status != MapStatus.Available || !Map.Map.Options.ConfigurableStartingUnits ? "Not Available" : className(orderManager.LobbyInfo.GlobalSettings.StartingUnitsClass); startingUnits.OnMouseDown = _ => { var options = classes.Select(c => new DropDownOption @@ -399,8 +389,8 @@ namespace OpenRA.Mods.RA.Widgets.Logic var startingCash = optionsBin.GetOrNull("STARTINGCASH_DROPDOWNBUTTON"); if (startingCash != null) { - startingCash.IsDisabled = () => preview.Status != MapStatus.Available || preview.Map.Options.StartingCash.HasValue || configurationDisabled(); - startingCash.GetText = () => preview.Status != MapStatus.Available || preview.Map.Options.StartingCash.HasValue ? "Not Available" : "${0}".F(orderManager.LobbyInfo.GlobalSettings.StartingCash); + startingCash.IsDisabled = () => Map.Status != MapStatus.Available || Map.Map.Options.StartingCash.HasValue || configurationDisabled(); + startingCash.GetText = () => Map.Status != MapStatus.Available || Map.Map.Options.StartingCash.HasValue ? "Not Available" : "${0}".F(orderManager.LobbyInfo.GlobalSettings.StartingCash); startingCash.OnMouseDown = _ => { var options = Rules.Info["player"].Traits.Get().SelectableCash.Select(c => new DropDownOption @@ -425,7 +415,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic if (enableShroud != null) { enableShroud.IsChecked = () => orderManager.LobbyInfo.GlobalSettings.Shroud; - enableShroud.IsDisabled = () => preview.Status != MapStatus.Available || preview.Map.Options.Shroud.HasValue || configurationDisabled(); + enableShroud.IsDisabled = () => Map.Status != MapStatus.Available || Map.Map.Options.Shroud.HasValue || configurationDisabled(); enableShroud.OnClick = () => orderManager.IssueOrder(Order.Command( "shroud {0}".F(!orderManager.LobbyInfo.GlobalSettings.Shroud))); } @@ -434,7 +424,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic if (enableFog != null) { enableFog.IsChecked = () => orderManager.LobbyInfo.GlobalSettings.Fog; - enableFog.IsDisabled = () => preview.Status != MapStatus.Available || preview.Map.Options.Fog.HasValue || configurationDisabled(); + enableFog.IsDisabled = () => Map.Status != MapStatus.Available || Map.Map.Options.Fog.HasValue || configurationDisabled(); enableFog.OnClick = () => orderManager.IssueOrder(Order.Command( "fog {0}".F(!orderManager.LobbyInfo.GlobalSettings.Fog))); } @@ -533,11 +523,11 @@ namespace OpenRA.Mods.RA.Widgets.Logic void UpdateCurrentMap() { var uid = orderManager.LobbyInfo.GlobalSettings.Map; - if (preview.Uid == uid) + if (Map.Uid == uid) return; - preview = Game.modData.MapCache[uid]; - if (preview.Status != MapStatus.Available) + Map = Game.modData.MapCache[uid]; + if (Map.Status != MapStatus.Available) { if (Game.Settings.Game.AllowDownloading) { @@ -550,7 +540,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic // Restore default starting cash if the last map set it to something invalid var pri = Rules.Info["player"].Traits.Get(); - if (!preview.Map.Options.StartingCash.HasValue && !pri.SelectableCash.Contains(orderManager.LobbyInfo.GlobalSettings.StartingCash)) + if (!Map.Map.Options.StartingCash.HasValue && !pri.SelectableCash.Contains(orderManager.LobbyInfo.GlobalSettings.StartingCash)) orderManager.IssueOrder(Order.Command("startingcash {0}".F(pri.DefaultCash))); } @@ -600,7 +590,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic LobbyUtils.SetupEditableColorWidget(template, slot, client, orderManager, colorPreview); LobbyUtils.SetupEditableFactionWidget(template, slot, client, orderManager, countryNames); - LobbyUtils.SetupEditableTeamWidget(template, slot, client, orderManager, preview.SpawnPoints.Count); + LobbyUtils.SetupEditableTeamWidget(template, slot, client, orderManager, Map.SpawnPoints.Count); LobbyUtils.SetupEditableReadyWidget(template, slot, client, orderManager); } else diff --git a/OpenRA.Mods.RA/Widgets/Logic/LobbyMapPreviewLogic.cs b/OpenRA.Mods.RA/Widgets/Logic/LobbyMapPreviewLogic.cs new file mode 100644 index 0000000000..c01303bdc7 --- /dev/null +++ b/OpenRA.Mods.RA/Widgets/Logic/LobbyMapPreviewLogic.cs @@ -0,0 +1,44 @@ +#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.Collections.Generic; +using System.Drawing; +using System.Linq; +using OpenRA.Network; +using OpenRA.Traits; +using OpenRA.Widgets; + +namespace OpenRA.Mods.RA.Widgets.Logic +{ + public class LobbyMapPreviewLogic + { + [ObjectCreator.UseCtor] + internal LobbyMapPreviewLogic(Widget widget, OrderManager orderManager, LobbyLogic lobby) + { + var mapPreview = widget.Get("MAP_PREVIEW"); + mapPreview.Preview = () => lobby.Map; + mapPreview.OnMouseDown = mi => LobbyUtils.SelectSpawnPoint(orderManager, mapPreview, lobby.Map, mi); + mapPreview.SpawnClients = () => LobbyUtils.GetSpawnClients(orderManager, lobby.Map); + + var mapTitle = widget.GetOrNull("MAP_TITLE"); + if (mapTitle != null) + mapTitle.GetText = () => lobby.Map.Title; + + var mapType = widget.GetOrNull("MAP_TYPE"); + if (mapType != null) + mapType.GetText = () => lobby.Map.Type; + + var mapAuthor = widget.GetOrNull("MAP_AUTHOR"); + if (mapAuthor != null) + mapAuthor.GetText = () => "Created by {0}".F(lobby.Map.Author); + } + } +} diff --git a/mods/cnc/chrome/lobby-mappreview.yaml b/mods/cnc/chrome/lobby-mappreview.yaml new file mode 100644 index 0000000000..d3c1e7dae5 --- /dev/null +++ b/mods/cnc/chrome/lobby-mappreview.yaml @@ -0,0 +1,36 @@ +Container@LOBBY_MAP_PREVIEW: + Logic:LobbyMapPreviewLogic + X:PARENT_RIGHT-15-WIDTH + Y:30 + Width:194 + Height:250 + Children: + Background@MAP_BG: + Width:PARENT_RIGHT + Height:194 + Background:panel-gray + Children: + MapPreview@MAP_PREVIEW: + X:1 + Y:1 + Width:PARENT_RIGHT-2 + Height:PARENT_BOTTOM-2 + TooltipContainer:TOOLTIP_CONTAINER + Label@MAP_TITLE: + Y:197 + Width:PARENT_RIGHT + Height:25 + Font:Bold + Align:Center + Label@MAP_TYPE: + Y:212 + Width:PARENT_RIGHT + Height:25 + Font:TinyBold + Align:Center + Label@MAP_AUTHOR: + Y:225 + Width:PARENT_RIGHT + Height:25 + Font:Tiny + Align:Center diff --git a/mods/cnc/chrome/lobby.yaml b/mods/cnc/chrome/lobby.yaml index 1ce1394529..95102cd59b 100644 --- a/mods/cnc/chrome/lobby.yaml +++ b/mods/cnc/chrome/lobby.yaml @@ -17,40 +17,9 @@ Container@SERVER_LOBBY: Height:500 Background:panel-black Children: - Background@MAP_BG: - X:PARENT_RIGHT-15-WIDTH - Y:30 - Width:194 - Height:194 - Background:panel-gray - Children: - MapPreview@MAP_PREVIEW: - X:1 - Y:1 - Width:192 - Height:192 - TooltipContainer:TOOLTIP_CONTAINER - Label@MAP_TITLE: - X:PARENT_RIGHT-15-WIDTH - Y:227 - Width:194 - Height:25 - Font:Bold - Align:Center - Label@MAP_TYPE: - X:PARENT_RIGHT-15-WIDTH - Y:242 - Width:194 - Height:25 - Font:TinyBold - Align:Center - Label@MAP_AUTHOR: - X:PARENT_RIGHT-15-WIDTH - Y:255 - Width:194 - Height:25 - Font:Tiny - Align:Center + Container@MAP_PREVIEW_ROOT: + Width:PARENT_RIGHT + Height:PARENT_BOTTOM Container@LABEL_CONTAINER: X:20 Y:5 diff --git a/mods/cnc/mod.yaml b/mods/cnc/mod.yaml index 15e6a85a68..878eda946f 100644 --- a/mods/cnc/mod.yaml +++ b/mods/cnc/mod.yaml @@ -79,6 +79,7 @@ ChromeLayout: mods/cnc/chrome/createserver.yaml mods/cnc/chrome/directconnect.yaml mods/cnc/chrome/lobby.yaml + mods/cnc/chrome/lobby-mappreview.yaml mods/cnc/chrome/lobby-playerbin.yaml mods/cnc/chrome/connection.yaml mods/cnc/chrome/mapchooser.yaml diff --git a/mods/d2k/mod.yaml b/mods/d2k/mod.yaml index 39a4603872..283417e3ce 100644 --- a/mods/d2k/mod.yaml +++ b/mods/d2k/mod.yaml @@ -69,6 +69,7 @@ ChromeLayout: mods/ra/chrome/settings.yaml mods/ra/chrome/credits.yaml mods/ra/chrome/lobby.yaml + mods/ra/chrome/lobby-mappreview.yaml mods/d2k/chrome/lobby-playerbin.yaml mods/ra/chrome/lobby-dialogs.yaml mods/d2k/chrome/color-picker.yaml diff --git a/mods/ra/chrome/lobby-mappreview.yaml b/mods/ra/chrome/lobby-mappreview.yaml new file mode 100644 index 0000000000..3dfb153feb --- /dev/null +++ b/mods/ra/chrome/lobby-mappreview.yaml @@ -0,0 +1,36 @@ +Container@LOBBY_MAP_PREVIEW: + Logic:LobbyMapPreviewLogic + X:PARENT_RIGHT-20-WIDTH + Y:67 + Width:214 + Height:250 + Children: + Background@MAP_BG: + Width:PARENT_RIGHT + Height:214 + Background:dialog3 + Children: + MapPreview@MAP_PREVIEW: + X:2 + Y:2 + Width:210 + Height:210 + TooltipContainer:TOOLTIP_CONTAINER + Label@MAP_TITLE: + Y:215 + Width:PARENT_RIGHT + Height:25 + Font:Bold + Align:Center + Label@MAP_TYPE: + Y:230 + Width:PARENT_RIGHT + Height:25 + Font:TinyBold + Align:Center + Label@MAP_AUTHOR: + Y:243 + Width:PARENT_RIGHT + Height:25 + Font:Tiny + Align:Center \ No newline at end of file diff --git a/mods/ra/chrome/lobby.yaml b/mods/ra/chrome/lobby.yaml index ab6c67213d..b6e20e96ae 100644 --- a/mods/ra/chrome/lobby.yaml +++ b/mods/ra/chrome/lobby.yaml @@ -13,40 +13,9 @@ Background@SERVER_LOBBY: Width:PARENT_RIGHT Height:20 Font:Bold - Background@MAP_BG: - X:PARENT_RIGHT-20-WIDTH - Y:67 - Width:214 - Height:214 - Background:dialog3 - Children: - MapPreview@MAP_PREVIEW: - X:2 - Y:2 - Width:210 - Height:210 - TooltipContainer:TOOLTIP_CONTAINER - Label@MAP_TITLE: - X:PARENT_RIGHT-20-WIDTH - Y:282 - Width:214 - Height:25 - Font:Bold - Align:Center - Label@MAP_TYPE: - X:PARENT_RIGHT-20-WIDTH - Y:297 - Width:214 - Height:25 - Font:TinyBold - Align:Center - Label@MAP_AUTHOR: - X:PARENT_RIGHT-20-WIDTH - Y:310 - Width:214 - Height:25 - Font:Tiny - Align:Center + Container@MAP_PREVIEW_ROOT: + Width:PARENT_RIGHT + Height:PARENT_BOTTOM Container@LABEL_CONTAINER: X:25 Y:40 diff --git a/mods/ra/mod.yaml b/mods/ra/mod.yaml index fad79b75dd..e4ae6b2457 100644 --- a/mods/ra/mod.yaml +++ b/mods/ra/mod.yaml @@ -83,6 +83,7 @@ ChromeLayout: mods/ra/chrome/settings.yaml mods/ra/chrome/credits.yaml mods/ra/chrome/lobby.yaml + mods/ra/chrome/lobby-mappreview.yaml mods/ra/chrome/lobby-playerbin.yaml mods/ra/chrome/lobby-dialogs.yaml mods/ra/chrome/color-picker.yaml diff --git a/mods/ts/mod.yaml b/mods/ts/mod.yaml index d5947892af..dcb87352bc 100644 --- a/mods/ts/mod.yaml +++ b/mods/ts/mod.yaml @@ -108,6 +108,7 @@ ChromeLayout: mods/ra/chrome/settings.yaml mods/ra/chrome/credits.yaml mods/ra/chrome/lobby.yaml + mods/ra/chrome/lobby-mappreview.yaml mods/ra/chrome/lobby-playerbin.yaml mods/ra/chrome/lobby-dialogs.yaml mods/ts/chrome/color-picker.yaml From c5ba8548c4e3dbd91714d6f111f17cc9400c931e Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Fri, 14 Mar 2014 13:40:05 +1300 Subject: [PATCH 2/9] Move C&C chrome definitions to more closely match the other mods. --- mods/cnc/chrome/color-picker.yaml | 45 ++++++ mods/cnc/chrome/dialogs.yaml | 230 ----------------------------- mods/cnc/chrome/lobby-dialogs.yaml | 183 +++++++++++++++++++++++ mods/cnc/mod.yaml | 2 + 4 files changed, 230 insertions(+), 230 deletions(-) create mode 100644 mods/cnc/chrome/color-picker.yaml create mode 100644 mods/cnc/chrome/lobby-dialogs.yaml diff --git a/mods/cnc/chrome/color-picker.yaml b/mods/cnc/chrome/color-picker.yaml new file mode 100644 index 0000000000..0f6bd53063 --- /dev/null +++ b/mods/cnc/chrome/color-picker.yaml @@ -0,0 +1,45 @@ +Background@COLOR_CHOOSER: + Logic:ColorPickerLogic + Background:panel-black + Width:234 + Height:105 + Children: + Background@HUEBG: + Background:panel-black + X:5 + Y:5 + Width:148 + Height:13 + Children: + HueSlider@HUE: + X:2 + Y:2 + Width:144 + Height:9 + Ticks:5 + Background@MIXERBG: + Background:panel-black + X:5 + Y:23 + Width:148 + Height:76 + Children: + ColorMixer@MIXER: + X:2 + Y:2 + Width:144 + Height:72 + ShpImage@FACT: + X:153 + Y:1 + Width:80 + Height:73 + Image:fact + Palette:colorpicker + Button@RANDOM_BUTTON: + Key:tab + X:158 + Y:74 + Width:70 + Height:25 + Text:Random \ No newline at end of file diff --git a/mods/cnc/chrome/dialogs.yaml b/mods/cnc/chrome/dialogs.yaml index 1ac590a989..322b8d44af 100644 --- a/mods/cnc/chrome/dialogs.yaml +++ b/mods/cnc/chrome/dialogs.yaml @@ -1,49 +1,3 @@ -Background@COLOR_CHOOSER: - Logic:ColorPickerLogic - Background:panel-black - Width:234 - Height:105 - Children: - Background@HUEBG: - Background:panel-black - X:5 - Y:5 - Width:148 - Height:13 - Children: - HueSlider@HUE: - X:2 - Y:2 - Width:144 - Height:9 - Ticks:5 - Background@MIXERBG: - Background:panel-black - X:5 - Y:23 - Width:148 - Height:76 - Children: - ColorMixer@MIXER: - X:2 - Y:2 - Width:144 - Height:72 - ShpImage@FACT: - X:153 - Y:1 - Width:80 - Height:73 - Image:fact - Palette:colorpicker - Button@RANDOM_BUTTON: - Key:tab - X:158 - Y:74 - Width:70 - Height:25 - Text:Random - ScrollPanel@LABEL_DROPDOWN_TEMPLATE: Width:DROPDOWN_WIDTH Background:panel-black @@ -146,187 +100,3 @@ Container@CONFIRM_PROMPT: Width:140 Height:35 Text:Confirm - -Background@KICK_CLIENT_DIALOG: - X:15 - Y:30 - Width:501 - Height:219 - Logic:KickClientLogic - Background:scrollpanel-bg - Children: - Label@TITLE: - X:0 - Y:40 - Width:PARENT_RIGHT - Height:25 - Font:Bold - Align:Center - Label@TEXTA: - X:0 - Y:67 - Width:PARENT_RIGHT - Height:25 - Font:Regular - Align:Center - Text:You may also apply a temporary ban, preventing - Label@TEXTB: - X:0 - Y:85 - Width:PARENT_RIGHT - Height:25 - Font:Regular - Align:Center - Text:them from joining for the remainder of this game. - Checkbox@PREVENT_REJOINING_CHECKBOX: - X:(PARENT_RIGHT - WIDTH)/2 - Y:120 - Width:150 - Height:20 - Font:Regular - Text:Temporarily Ban - Button@OK_BUTTON: - X:(PARENT_RIGHT - WIDTH)/2 + 75 - Y:155 - Width:120 - Height:25 - Text:Kick - Font:Bold - Button@CANCEL_BUTTON: - X:(PARENT_RIGHT - WIDTH)/2 - 75 - Y:155 - Width:120 - Height:25 - Text:Cancel - Font:Bold - -Background@KICK_SPECTATORS_DIALOG: - X:15 - Y:30 - Width:501 - Height:219 - Logic:KickSpectatorsLogic - Background:scrollpanel-bg - Children: - Label@TITLE: - X:0 - Y:40 - Width:PARENT_RIGHT - Height:25 - Font:Bold - Align:Center - Text:Kick Spectators - Label@TEXT: - X:0 - Y:85 - Width:PARENT_RIGHT - Height:25 - Font:Regular - Align:Center - Button@OK_BUTTON: - X:(PARENT_RIGHT - WIDTH)/2 + 75 - Y:155 - Width:120 - Height:25 - Text:Ok - Font:Bold - Button@CANCEL_BUTTON: - X:(PARENT_RIGHT - WIDTH)/2 - 75 - Y:155 - Width:120 - Height:25 - Text:Cancel - Font:Bold - -Background@LOBBY_OPTIONS_BIN: - X:15 - Y:30 - Width:501 - Height:219 - Background:scrollpanel-bg - Children: - Label@TITLE: - X:0 - Y:30 - Width:PARENT_RIGHT - Height:25 - Font:Bold - Align:Center - Text: Map Options - Container: - X:30 - Y:65 - Width: PARENT_RIGHT-60 - Height: PARENT_BOTTOM-75 - Children: - Checkbox@SHROUD_CHECKBOX: - Width:230 - Height:20 - Font:Regular - Text:Shroud - Checkbox@FOG_CHECKBOX: - Y:35 - Width:230 - Height:20 - Font:Regular - Text:Fog of War - Checkbox@CRATES_CHECKBOX: - X:160 - Width:230 - Height:20 - Font:Regular - Text:Crates Appear - Checkbox@ALLYBUILDRADIUS_CHECKBOX: - X:160 - Y:35 - Width:230 - Height:20 - Font:Regular - Text:Build off Ally ConYards - Checkbox@ALLOWCHEATS_CHECKBOX: - X:325 - Width:230 - Height:20 - Font:Regular - Text:Debug Menu - Label@STARTINGCASH_DESC: - X:10 - Y:72 - Width:70 - Height:25 - Font:Regular - Text:Starting Cash: - Align:Right - DropDownButton@STARTINGCASH_DROPDOWNBUTTON: - X:85 - Y:72 - Width:120 - Height:25 - Font:Regular - Text:$5000 - Label@STARTINGUNITS_DESC: - X:PARENT_RIGHT - WIDTH - 135 - Y:72 - Width:120 - Height:25 - Text:Starting Units: - Align:Right - DropDownButton@STARTINGUNITS_DROPDOWNBUTTON: - X:PARENT_RIGHT - WIDTH + 10 - Y:72 - Width:140 - Height:25 - Font:Regular - Label@DIFFICULTY_DESC: - X:PARENT_RIGHT - WIDTH - 135 - Y:107 - Width:120 - Height:25 - Text:Mission Difficulty: - Align:Right - DropDownButton@DIFFICULTY_DROPDOWNBUTTON: - X:PARENT_RIGHT - WIDTH + 10 - Y:107 - Width:140 - Height:25 - Font:Regular \ No newline at end of file diff --git a/mods/cnc/chrome/lobby-dialogs.yaml b/mods/cnc/chrome/lobby-dialogs.yaml new file mode 100644 index 0000000000..e1d0effc43 --- /dev/null +++ b/mods/cnc/chrome/lobby-dialogs.yaml @@ -0,0 +1,183 @@ +Background@KICK_CLIENT_DIALOG: + X:15 + Y:30 + Width:501 + Height:219 + Logic:KickClientLogic + Background:scrollpanel-bg + Children: + Label@TITLE: + X:0 + Y:40 + Width:PARENT_RIGHT + Height:25 + Font:Bold + Align:Center + Label@TEXTA: + X:0 + Y:67 + Width:PARENT_RIGHT + Height:25 + Font:Regular + Align:Center + Text:You may also apply a temporary ban, preventing + Label@TEXTB: + X:0 + Y:85 + Width:PARENT_RIGHT + Height:25 + Font:Regular + Align:Center + Text:them from joining for the remainder of this game. + Checkbox@PREVENT_REJOINING_CHECKBOX: + X:(PARENT_RIGHT - WIDTH)/2 + Y:120 + Width:150 + Height:20 + Font:Regular + Text:Temporarily Ban + Button@OK_BUTTON: + X:(PARENT_RIGHT - WIDTH)/2 + 75 + Y:155 + Width:120 + Height:25 + Text:Kick + Font:Bold + Button@CANCEL_BUTTON: + X:(PARENT_RIGHT - WIDTH)/2 - 75 + Y:155 + Width:120 + Height:25 + Text:Cancel + Font:Bold + +Background@KICK_SPECTATORS_DIALOG: + X:15 + Y:30 + Width:501 + Height:219 + Logic:KickSpectatorsLogic + Background:scrollpanel-bg + Children: + Label@TITLE: + X:0 + Y:40 + Width:PARENT_RIGHT + Height:25 + Font:Bold + Align:Center + Text:Kick Spectators + Label@TEXT: + X:0 + Y:85 + Width:PARENT_RIGHT + Height:25 + Font:Regular + Align:Center + Button@OK_BUTTON: + X:(PARENT_RIGHT - WIDTH)/2 + 75 + Y:155 + Width:120 + Height:25 + Text:Ok + Font:Bold + Button@CANCEL_BUTTON: + X:(PARENT_RIGHT - WIDTH)/2 - 75 + Y:155 + Width:120 + Height:25 + Text:Cancel + Font:Bold + +Background@LOBBY_OPTIONS_BIN: + X:15 + Y:30 + Width:501 + Height:219 + Background:scrollpanel-bg + Children: + Label@TITLE: + X:0 + Y:30 + Width:PARENT_RIGHT + Height:25 + Font:Bold + Align:Center + Text: Map Options + Container: + X:30 + Y:65 + Width: PARENT_RIGHT-60 + Height: PARENT_BOTTOM-75 + Children: + Checkbox@SHROUD_CHECKBOX: + Width:230 + Height:20 + Font:Regular + Text:Shroud + Checkbox@FOG_CHECKBOX: + Y:35 + Width:230 + Height:20 + Font:Regular + Text:Fog of War + Checkbox@CRATES_CHECKBOX: + X:160 + Width:230 + Height:20 + Font:Regular + Text:Crates Appear + Checkbox@ALLYBUILDRADIUS_CHECKBOX: + X:160 + Y:35 + Width:230 + Height:20 + Font:Regular + Text:Build off Ally ConYards + Checkbox@ALLOWCHEATS_CHECKBOX: + X:325 + Width:230 + Height:20 + Font:Regular + Text:Debug Menu + Label@STARTINGCASH_DESC: + X:10 + Y:72 + Width:70 + Height:25 + Font:Regular + Text:Starting Cash: + Align:Right + DropDownButton@STARTINGCASH_DROPDOWNBUTTON: + X:85 + Y:72 + Width:120 + Height:25 + Font:Regular + Text:$5000 + Label@STARTINGUNITS_DESC: + X:PARENT_RIGHT - WIDTH - 135 + Y:72 + Width:120 + Height:25 + Text:Starting Units: + Align:Right + DropDownButton@STARTINGUNITS_DROPDOWNBUTTON: + X:PARENT_RIGHT - WIDTH + 10 + Y:72 + Width:140 + Height:25 + Font:Regular + Label@DIFFICULTY_DESC: + X:PARENT_RIGHT - WIDTH - 135 + Y:107 + Width:120 + Height:25 + Text:Mission Difficulty: + Align:Right + DropDownButton@DIFFICULTY_DROPDOWNBUTTON: + X:PARENT_RIGHT - WIDTH + 10 + Y:107 + Width:140 + Height:25 + Font:Regular \ No newline at end of file diff --git a/mods/cnc/mod.yaml b/mods/cnc/mod.yaml index 878eda946f..e60f2074bc 100644 --- a/mods/cnc/mod.yaml +++ b/mods/cnc/mod.yaml @@ -81,7 +81,9 @@ ChromeLayout: mods/cnc/chrome/lobby.yaml mods/cnc/chrome/lobby-mappreview.yaml mods/cnc/chrome/lobby-playerbin.yaml + mods/cnc/chrome/lobby-dialogs.yaml mods/cnc/chrome/connection.yaml + mods/cnc/chrome/color-picker.yaml mods/cnc/chrome/mapchooser.yaml mods/cnc/chrome/replaybrowser.yaml mods/cnc/chrome/ingame.yaml From f5f84244eb88c514ac24720a33dc9148f3c41714 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Thu, 13 Mar 2014 11:58:32 +1300 Subject: [PATCH 3/9] Remove map download support. --- OpenRA.Game/Game.cs | 41 ---------------------- OpenRA.Mods.RA/Widgets/Logic/LobbyLogic.cs | 25 +++++-------- OpenRA.Mods.RA/Widgets/Logic/LobbyUtils.cs | 9 ++--- 3 files changed, 14 insertions(+), 61 deletions(-) diff --git a/OpenRA.Game/Game.cs b/OpenRA.Game/Game.cs index e4aa5d05ed..7bab4a61f1 100644 --- a/OpenRA.Game/Game.cs +++ b/OpenRA.Game/Game.cs @@ -531,46 +531,5 @@ namespace OpenRA { return orderManager != null && orderManager.world == world; } - - public static bool DownloadMap(string mapHash) - { - var mod = Game.modData.Manifest.Mod; - var dirPath = new[] { Platform.SupportDir, "maps", mod.Id }.Aggregate(Path.Combine); - var tempFile = Path.Combine(dirPath, Path.GetRandomFileName()); - if (!Directory.Exists(dirPath)) - Directory.CreateDirectory(dirPath); - foreach (var MapRepository in Game.Settings.Game.MapRepositories) - { - try - { - var url = MapRepository + mapHash; - - var request = WebRequest.Create(url); - request.Method = "HEAD"; - var res = request.GetResponse(); - - if (res.Headers["Content-Disposition"] == null) - continue; - var mapPath = Path.Combine(dirPath, res.Headers ["Content-Disposition"].Replace("attachment; filename = ", "")); - Log.Write("debug", "Trying to download map to '{0}' using {1}", mapPath, MapRepository); - - WebClient webClient = new WebClient(); - webClient.DownloadFile(url, tempFile); - File.Move(tempFile, mapPath); - Game.modData.MapCache[mapHash].UpdateFromMap(new Map(mapPath)); - Log.Write("debug", "New map has been downloaded to '{0}'", mapPath); - - return true; - } - catch (WebException e) - { - Log.Write("debug", "Could not download map '{0}' using {1}", mapHash, MapRepository); - Log.Write("debug", e.ToString()); - File.Delete(tempFile); - continue; - } - } - return false; - } } } diff --git a/OpenRA.Mods.RA/Widgets/Logic/LobbyLogic.cs b/OpenRA.Mods.RA/Widgets/Logic/LobbyLogic.cs index 739301a51a..4a4b998903 100644 --- a/OpenRA.Mods.RA/Widgets/Logic/LobbyLogic.cs +++ b/OpenRA.Mods.RA/Widgets/Logic/LobbyLogic.cs @@ -527,21 +527,14 @@ namespace OpenRA.Mods.RA.Widgets.Logic return; Map = Game.modData.MapCache[uid]; - if (Map.Status != MapStatus.Available) - { - if (Game.Settings.Game.AllowDownloading) - { - Game.DownloadMap(uid); - Game.Debug("A new map has been downloaded..."); - } - else - throw new InvalidOperationException("Server's new map doesn't exist on your system and Downloading turned off"); - } - // Restore default starting cash if the last map set it to something invalid - var pri = Rules.Info["player"].Traits.Get(); - if (!Map.Map.Options.StartingCash.HasValue && !pri.SelectableCash.Contains(orderManager.LobbyInfo.GlobalSettings.StartingCash)) - orderManager.IssueOrder(Order.Command("startingcash {0}".F(pri.DefaultCash))); + if (Map.Status == MapStatus.Available) + { + // Restore default starting cash if the last map set it to something invalid + var pri = Rules.Info["player"].Traits.Get(); + if (!Map.Map.Options.StartingCash.HasValue && !pri.SelectableCash.Contains(orderManager.LobbyInfo.GlobalSettings.StartingCash)) + orderManager.IssueOrder(Order.Command("startingcash {0}".F(pri.DefaultCash))); + } } void UpdatePlayerList() @@ -590,8 +583,8 @@ namespace OpenRA.Mods.RA.Widgets.Logic LobbyUtils.SetupEditableColorWidget(template, slot, client, orderManager, colorPreview); LobbyUtils.SetupEditableFactionWidget(template, slot, client, orderManager, countryNames); - LobbyUtils.SetupEditableTeamWidget(template, slot, client, orderManager, Map.SpawnPoints.Count); - LobbyUtils.SetupEditableReadyWidget(template, slot, client, orderManager); + LobbyUtils.SetupEditableTeamWidget(template, slot, client, orderManager, Map); + LobbyUtils.SetupEditableReadyWidget(template, slot, client, orderManager, Map); } else { diff --git a/OpenRA.Mods.RA/Widgets/Logic/LobbyUtils.cs b/OpenRA.Mods.RA/Widgets/Logic/LobbyUtils.cs index 0e5da7bdfa..c6940cb513 100644 --- a/OpenRA.Mods.RA/Widgets/Logic/LobbyUtils.cs +++ b/OpenRA.Mods.RA/Widgets/Logic/LobbyUtils.cs @@ -363,11 +363,11 @@ namespace OpenRA.Mods.RA.Widgets.Logic factionflag.GetImageCollection = () => "flags"; } - public static void SetupEditableTeamWidget(Widget parent, Session.Slot s, Session.Client c, OrderManager orderManager, int teamCount) + public static void SetupEditableTeamWidget(Widget parent, Session.Slot s, Session.Client c, OrderManager orderManager, MapPreview map) { var dropdown = parent.Get("TEAM"); dropdown.IsDisabled = () => s.LockTeam || orderManager.LocalClient.IsReady; - dropdown.OnMouseDown = _ => ShowTeamDropDown(dropdown, c, orderManager, teamCount); + dropdown.OnMouseDown = _ => ShowTeamDropDown(dropdown, c, orderManager, map.PlayerCount); dropdown.GetText = () => (c.Team == 0) ? "-" : c.Team.ToString(); } @@ -376,12 +376,13 @@ namespace OpenRA.Mods.RA.Widgets.Logic parent.Get("TEAM").GetText = () => (c.Team == 0) ? "-" : c.Team.ToString(); } - public static void SetupEditableReadyWidget(Widget parent, Session.Slot s, Session.Client c, OrderManager orderManager) + public static void SetupEditableReadyWidget(Widget parent, Session.Slot s, Session.Client c, OrderManager orderManager, MapPreview map) { var status = parent.Get("STATUS_CHECKBOX"); status.IsChecked = () => orderManager.LocalClient.IsReady || c.Bot != null; status.IsVisible = () => true; - status.IsDisabled = () => c.Bot != null; + status.IsDisabled = () => c.Bot != null || map.Status != MapStatus.Available; + status.OnClick = () => orderManager.IssueOrder(Order.Command("ready")); } From fcb3d7347a3aaabc61b3520bdc5767ebb4642cb7 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Thu, 13 Mar 2014 17:07:41 +1300 Subject: [PATCH 4/9] Kick clients who don't have the map when the host force-starts. --- OpenRA.Game/Network/Session.cs | 5 ++-- OpenRA.Game/Network/UnitOrders.cs | 2 +- OpenRA.Game/Server/Server.cs | 24 +++++++++++++++----- OpenRA.Mods.RA/ServerTraits/LobbyCommands.cs | 22 +++++++++++------- OpenRA.Mods.RA/Widgets/Logic/LobbyLogic.cs | 3 +++ OpenRA.Mods.RA/Widgets/Logic/LobbyUtils.cs | 3 ++- 6 files changed, 41 insertions(+), 18 deletions(-) diff --git a/OpenRA.Game/Network/Session.cs b/OpenRA.Game/Network/Session.cs index c032e45340..f2340b24d8 100644 --- a/OpenRA.Game/Network/Session.cs +++ b/OpenRA.Game/Network/Session.cs @@ -81,7 +81,7 @@ namespace OpenRA.Network get { return Clients.Count(c => c.Bot == null) == 1; } } - public enum ClientState { NotReady, Ready, Disconnected = 1000 } + public enum ClientState { NotReady, Invalid, Ready, Disconnected = 1000 } public class Client { @@ -93,13 +93,14 @@ namespace OpenRA.Network public int SpawnPoint; public string Name; public string IpAddress; - public ClientState State; + public ClientState State = ClientState.Invalid; public int Team; public string Slot; // slot ID, or null for observer public string Bot; // Bot type, null for real clients public int BotControllerClientIndex; // who added the bot to the slot public bool IsAdmin; public bool IsReady { get { return State == ClientState.Ready; } } + public bool IsInvalid { get { return State == ClientState.Invalid; } } public bool IsObserver { get { return Slot == null; } } public int Latency = -1; public int LatencyJitter = -1; diff --git a/OpenRA.Game/Network/UnitOrders.cs b/OpenRA.Game/Network/UnitOrders.cs index 8bdcede585..87b501bc90 100644 --- a/OpenRA.Game/Network/UnitOrders.cs +++ b/OpenRA.Game/Network/UnitOrders.cs @@ -130,7 +130,7 @@ namespace OpenRA.Network Country = "random", SpawnPoint = 0, Team = 0, - State = Session.ClientState.NotReady + State = Session.ClientState.Invalid }; var response = new HandshakeResponse() diff --git a/OpenRA.Game/Server/Server.cs b/OpenRA.Game/Server/Server.cs index 38ec7eaef2..cea2d9425b 100644 --- a/OpenRA.Game/Server/Server.cs +++ b/OpenRA.Game/Server/Server.cs @@ -272,7 +272,7 @@ namespace OpenRA.Server Country = "random", SpawnPoint = 0, Team = 0, - State = Session.ClientState.NotReady, + State = Session.ClientState.Invalid, IsAdmin = !LobbyInfo.Clients.Any(c1 => c1.IsAdmin) }; @@ -572,19 +572,31 @@ namespace OpenRA.Server public void StartGame() { - State = ServerState.GameStarted; listener.Stop(); Console.WriteLine("Game started"); - foreach (var c in Conns) - foreach (var d in Conns) - DispatchOrdersToClient(c, d.PlayerIndex, 0x7FFFFFFF, new byte[] { 0xBF }); - // Drop any unvalidated clients foreach (var c in PreConns.ToArray()) DropClient(c); + // Drop any players who are not ready + foreach (var c in Conns.ToArray()) + { + if (GetClient(c).IsInvalid) + { + SendOrderTo(c, "ServerError", "You have been kicked from the server"); + DropClient(c); + } + } + + SyncLobbyInfo(); + State = ServerState.GameStarted; + + foreach (var c in Conns) + foreach (var d in Conns) + DispatchOrdersToClient(c, d.PlayerIndex, 0x7FFFFFFF, new byte[] { 0xBF }); + DispatchOrders(null, 0, new ServerOrder("StartGame", "").Serialize()); diff --git a/OpenRA.Mods.RA/ServerTraits/LobbyCommands.cs b/OpenRA.Mods.RA/ServerTraits/LobbyCommands.cs index 6565b1b796..95a0683eb7 100644 --- a/OpenRA.Mods.RA/ServerTraits/LobbyCommands.cs +++ b/OpenRA.Mods.RA/ServerTraits/LobbyCommands.cs @@ -44,7 +44,7 @@ namespace OpenRA.Mods.RA.Server server.SendOrderTo(conn, "Message", "Cannot change state when game started. ({0})".F(cmd)); return false; } - else if (client.State == Session.ClientState.Ready && !(cmd == "ready" || cmd == "startgame")) + else if (client.State == Session.ClientState.Ready && !(cmd.StartsWith("state") || cmd == "startgame")) { server.SendOrderTo(conn, "Message", "Cannot change state when marked as ready."); return false; @@ -75,14 +75,17 @@ namespace OpenRA.Mods.RA.Server var dict = new Dictionary> { - { "ready", + { "state", s => { - // if we're downloading, we can't ready up. - if (client.State == Session.ClientState.NotReady) - client.State = Session.ClientState.Ready; - else if (client.State == Session.ClientState.Ready) - client.State = Session.ClientState.NotReady; + var state = Session.ClientState.Invalid; + if (!Enum.TryParse(s, false, out state)) + { + server.SendOrderTo(conn, "Message", "Malformed state command"); + return true; + } + + client.State = state; Log.Write("server", "Player @{0} is {1}", conn.socket.RemoteEndPoint, client.State); @@ -290,6 +293,10 @@ namespace OpenRA.Mods.RA.Server LoadMap(server); SetDefaultDifficulty(server); + // Reset client states + foreach (var c in server.LobbyInfo.Clients) + c.State = Session.ClientState.Invalid; + // Reassign players into new slots based on their old slots: // - Observers remain as observers // - Players who now lack a slot are made observers @@ -303,7 +310,6 @@ namespace OpenRA.Mods.RA.Server continue; c.SpawnPoint = 0; - c.State = Session.ClientState.NotReady; c.Slot = i < slots.Length ? slots[i++] : null; if (c.Slot != null) { diff --git a/OpenRA.Mods.RA/Widgets/Logic/LobbyLogic.cs b/OpenRA.Mods.RA/Widgets/Logic/LobbyLogic.cs index 4a4b998903..b4287d68c7 100644 --- a/OpenRA.Mods.RA/Widgets/Logic/LobbyLogic.cs +++ b/OpenRA.Mods.RA/Widgets/Logic/LobbyLogic.cs @@ -530,6 +530,9 @@ namespace OpenRA.Mods.RA.Widgets.Logic if (Map.Status == MapStatus.Available) { + // Tell the server that we have the map + orderManager.IssueOrder(Order.Command("state {0}".F(Session.ClientState.NotReady))); + // Restore default starting cash if the last map set it to something invalid var pri = Rules.Info["player"].Traits.Get(); if (!Map.Map.Options.StartingCash.HasValue && !pri.SelectableCash.Contains(orderManager.LobbyInfo.GlobalSettings.StartingCash)) diff --git a/OpenRA.Mods.RA/Widgets/Logic/LobbyUtils.cs b/OpenRA.Mods.RA/Widgets/Logic/LobbyUtils.cs index c6940cb513..25d32678e1 100644 --- a/OpenRA.Mods.RA/Widgets/Logic/LobbyUtils.cs +++ b/OpenRA.Mods.RA/Widgets/Logic/LobbyUtils.cs @@ -383,7 +383,8 @@ namespace OpenRA.Mods.RA.Widgets.Logic status.IsVisible = () => true; status.IsDisabled = () => c.Bot != null || map.Status != MapStatus.Available; - status.OnClick = () => orderManager.IssueOrder(Order.Command("ready")); + var state = orderManager.LocalClient.IsReady ? Session.ClientState.NotReady : Session.ClientState.Ready; + status.OnClick = () => orderManager.IssueOrder(Order.Command("state {0}".F(state))); } public static void SetupReadyWidget(Widget parent, Session.Slot s, Session.Client c) From e2e0728e20d8cfa5921d9d50dd71a42efa566a54 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Thu, 13 Mar 2014 17:52:09 +1300 Subject: [PATCH 5/9] Add a force start warning dialog. --- OpenRA.Mods.RA/Widgets/Logic/LobbyLogic.cs | 40 +++++++++---- mods/cnc/chrome/lobby-dialogs.yaml | 67 +++++++++++++++++++++- mods/ra/chrome/lobby-dialogs.yaml | 65 +++++++++++++++++++++ 3 files changed, 159 insertions(+), 13 deletions(-) diff --git a/OpenRA.Mods.RA/Widgets/Logic/LobbyLogic.cs b/OpenRA.Mods.RA/Widgets/Logic/LobbyLogic.cs index b4287d68c7..ad183ba8b7 100644 --- a/OpenRA.Mods.RA/Widgets/Logic/LobbyLogic.cs +++ b/OpenRA.Mods.RA/Widgets/Logic/LobbyLogic.cs @@ -30,7 +30,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic readonly OrderManager orderManager; readonly bool skirmishMode; - enum PanelType { Players, Options, Kick } + enum PanelType { Players, Options, Kick, ForceStart } PanelType panel = PanelType.Players; Widget lobby; @@ -138,7 +138,8 @@ namespace OpenRA.Mods.RA.Widgets.Logic countryNames.Add("random", "Any"); var gameStarting = false; - Func configurationDisabled = () => !Game.IsHost || gameStarting || panel == PanelType.Kick || + Func configurationDisabled = () => !Game.IsHost || gameStarting || + panel == PanelType.Kick || panel == PanelType.ForceStart || orderManager.LocalClient == null || orderManager.LocalClient.IsReady; var mapButton = lobby.GetOrNull("CHANGEMAP_BUTTON"); @@ -261,10 +262,17 @@ namespace OpenRA.Mods.RA.Widgets.Logic optionsBin.IsVisible = () => panel == PanelType.Options; var optionsButton = lobby.Get("OPTIONS_BUTTON"); - optionsButton.IsDisabled = () => panel == PanelType.Kick; + optionsButton.IsDisabled = () => panel == PanelType.Kick || panel == PanelType.ForceStart; optionsButton.GetText = () => panel == PanelType.Options ? "Players" : "Options"; optionsButton.OnClick = () => panel = (panel == PanelType.Options) ? PanelType.Players : PanelType.Options; + // Force start panel + Action startGame = () => + { + gameStarting = true; + orderManager.IssueOrder(Order.Command("startgame")); + }; + var startGameButton = lobby.GetOrNull("START_GAME_BUTTON"); if (startGameButton != null) { @@ -272,18 +280,26 @@ namespace OpenRA.Mods.RA.Widgets.Logic orderManager.LobbyInfo.Slots.Any(sl => sl.Value.Required && orderManager.LobbyInfo.ClientInSlot(sl.Key) == null); startGameButton.OnClick = () => { - gameStarting = true; - orderManager.IssueOrder(Order.Command("startgame")); + Func, bool> notReady = sl => + { + var cl = orderManager.LobbyInfo.ClientInSlot(sl.Key); + + // Bots and admins don't count + return cl != null && !cl.IsAdmin && cl.Bot == null && !cl.IsReady; + }; + + if (orderManager.LobbyInfo.Slots.Any(notReady)) + panel = PanelType.ForceStart; + else + startGame(); }; } - var statusCheckbox = lobby.GetOrNull("STATUS_CHECKBOX"); - if (statusCheckbox != null) - { - statusCheckbox.IsHighlighted = () => !statusCheckbox.IsChecked() && - orderManager.LobbyInfo.FirstEmptySlot() == null && - orderManager.LocalFrameNumber / 25 % 2 == 0; - } + var forceStartBin = Ui.LoadWidget("FORCE_START_DIALOG", lobby, new WidgetArgs()); + forceStartBin.IsVisible = () => panel == PanelType.ForceStart; + forceStartBin.Get("KICK_WARNING").IsVisible = () => orderManager.LobbyInfo.Clients.Any(c => c.IsInvalid); + forceStartBin.Get("OK_BUTTON").OnClick = startGame; + forceStartBin.Get("CANCEL_BUTTON").OnClick = () => panel = PanelType.Players; // Options panel var allowCheats = optionsBin.GetOrNull("ALLOWCHEATS_CHECKBOX"); diff --git a/mods/cnc/chrome/lobby-dialogs.yaml b/mods/cnc/chrome/lobby-dialogs.yaml index e1d0effc43..28d849e52e 100644 --- a/mods/cnc/chrome/lobby-dialogs.yaml +++ b/mods/cnc/chrome/lobby-dialogs.yaml @@ -180,4 +180,69 @@ Background@LOBBY_OPTIONS_BIN: Y:107 Width:140 Height:25 - Font:Regular \ No newline at end of file + Font:Regular + +Background@FORCE_START_DIALOG: + X:15 + Y:30 + Width:501 + Height:219 + Background:scrollpanel-bg + Children: + Label@TITLE: + X:0 + Y:40 + Width:PARENT_RIGHT + Height:25 + Font:Bold + Align:Center + Text: Start Game? + Label@TEXTA: + X:0 + Y:67 + Width:PARENT_RIGHT + Height:25 + Font:Regular + Align:Center + Text:One or more players are not yet ready. + Label@TEXTB: + X:0 + Y:85 + Width:PARENT_RIGHT + Height:25 + Font:Regular + Align:Center + Text:Are you sure that you want to force start the game? + Container@KICK_WARNING: + Width:PARENT_RIGHT + Children: + Label@KICK_WARNING_A: + X:0 + Y:106 + Width:PARENT_RIGHT + Height:25 + Font:Bold + Align:Center + Text:One or more clients are missing the selected + Label@KICK_WARNING_B: + X:0 + Y:123 + Width:PARENT_RIGHT + Height:25 + Font:Bold + Align:Center + Text:map, and will be kicked from the server. + Button@OK_BUTTON: + X:(PARENT_RIGHT - WIDTH)/2 + 75 + Y:155 + Width:120 + Height:25 + Text:Start + Font:Bold + Button@CANCEL_BUTTON: + X:(PARENT_RIGHT - WIDTH)/2 - 75 + Y:155 + Width:120 + Height:25 + Text:Cancel + Font:Bold \ No newline at end of file diff --git a/mods/ra/chrome/lobby-dialogs.yaml b/mods/ra/chrome/lobby-dialogs.yaml index cb266f2f7d..51d0a2c643 100644 --- a/mods/ra/chrome/lobby-dialogs.yaml +++ b/mods/ra/chrome/lobby-dialogs.yaml @@ -179,3 +179,68 @@ Background@LOBBY_OPTIONS_BIN: Width:140 Height:25 Font:Regular + +Background@FORCE_START_DIALOG: + X:20 + Y:67 + Width:535 + Height:235 + Background:dialog3 + Children: + Label@TITLE: + X:0 + Y:40 + Width:PARENT_RIGHT + Height:25 + Font:Bold + Align:Center + Text: Start Game? + Label@TEXTA: + X:0 + Y:67 + Width:PARENT_RIGHT + Height:25 + Font:Regular + Align:Center + Text:One or more players are not yet ready. + Label@TEXTB: + X:0 + Y:85 + Width:PARENT_RIGHT + Height:25 + Font:Regular + Align:Center + Text:Are you sure that you want to force start the game? + Container@KICK_WARNING: + Width:PARENT_RIGHT + Children: + Label@KICK_WARNING_A: + X:0 + Y:106 + Width:PARENT_RIGHT + Height:25 + Font:Bold + Align:Center + Text:One or more clients are missing the selected + Label@KICK_WARNING_B: + X:0 + Y:123 + Width:PARENT_RIGHT + Height:25 + Font:Bold + Align:Center + Text:map, and will be kicked from the server. + Button@OK_BUTTON: + X:(PARENT_RIGHT - WIDTH)/2 + 75 + Y:155 + Width:120 + Height:25 + Text:Start + Font:Bold + Button@CANCEL_BUTTON: + X:(PARENT_RIGHT - WIDTH)/2 - 75 + Y:155 + Width:120 + Height:25 + Text:Cancel + Font:Bold \ No newline at end of file From 6b199d3376acfd4e87dd3e8a04035339bd19a128 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Sun, 16 Mar 2014 18:02:15 +1300 Subject: [PATCH 6/9] Add bindings to ProgressBarWidget. --- OpenRA.Game/Widgets/ProgressBarWidget.cs | 37 +++++++++++++------ .../Widgets/Logic/DownloadPackagesLogic.cs | 8 ++-- 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/OpenRA.Game/Widgets/ProgressBarWidget.cs b/OpenRA.Game/Widgets/ProgressBarWidget.cs index 13b9ff54d1..ddb616649b 100644 --- a/OpenRA.Game/Widgets/ProgressBarWidget.cs +++ b/OpenRA.Game/Widgets/ProgressBarWidget.cs @@ -8,6 +8,7 @@ */ #endregion +using System; using System.Drawing; namespace OpenRA.Widgets @@ -17,45 +18,57 @@ namespace OpenRA.Widgets public int Percentage = 0; public bool Indeterminate = false; + public Func GetPercentage; + public Func IsIndeterminate; + // Indeterminant bar properties float offset = 0f; float tickStep = 0.04f; - public ProgressBarWidget() {} - protected ProgressBarWidget(ProgressBarWidget widget) - : base(widget) + public ProgressBarWidget() { - Percentage = widget.Percentage; + GetPercentage = () => Percentage; + IsIndeterminate = () => Indeterminate; + } + + protected ProgressBarWidget(ProgressBarWidget other) + : base(other) + { + Percentage = other.Percentage; + GetPercentage = other.GetPercentage; + IsIndeterminate = other.IsIndeterminate; } public override void Draw() { var rb = RenderBounds; + var percentage = GetPercentage(); WidgetUtils.DrawPanel("progressbar-bg", rb); - Rectangle barRect = Indeterminate ? + Rectangle barRect = wasIndeterminate ? new Rectangle(rb.X + 2 + (int)(0.75*offset*(rb.Width - 4)), rb.Y + 2, (rb.Width - 4) / 4, rb.Height - 4) : - new Rectangle(rb.X + 2, rb.Y + 2, Percentage * (rb.Width - 4) / 100, rb.Height - 4); + new Rectangle(rb.X + 2, rb.Y + 2, percentage * (rb.Width - 4) / 100, rb.Height - 4); if (barRect.Width > 0) WidgetUtils.DrawPanel("progressbar-thumb", barRect); } + bool wasIndeterminate; public override void Tick() { - if (Indeterminate) + var indeterminate = IsIndeterminate(); + if (indeterminate != wasIndeterminate) + offset = 0f; + + if (indeterminate) { offset += tickStep; offset = offset.Clamp(0f, 1f); if (offset == 0f || offset == 1f) tickStep *= -1; } - } - public void SetIndeterminate(bool value) - { - Indeterminate = value; - offset = 0f; + wasIndeterminate = indeterminate; } public override Widget Clone() { return new ProgressBarWidget(this); } diff --git a/OpenRA.Mods.RA/Widgets/Logic/DownloadPackagesLogic.cs b/OpenRA.Mods.RA/Widgets/Logic/DownloadPackagesLogic.cs index 8473d0a868..74d8bf46dc 100644 --- a/OpenRA.Mods.RA/Widgets/Logic/DownloadPackagesLogic.cs +++ b/OpenRA.Mods.RA/Widgets/Logic/DownloadPackagesLogic.cs @@ -43,7 +43,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic void ShowDownloadDialog() { statusLabel.GetText = () => "Initializing..."; - progressBar.SetIndeterminate(true); + progressBar.Indeterminate = true; var retryButton = panel.Get("RETRY_BUTTON"); retryButton.IsVisible = () => false; @@ -55,9 +55,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic Action onDownloadProgress = i => { - if (progressBar.Indeterminate) - progressBar.SetIndeterminate(false); - + progressBar.Indeterminate = false; progressBar.Percentage = i.ProgressPercentage; statusLabel.GetText = () => "Downloading {1}/{2} kB ({0}%)".F(i.ProgressPercentage, i.BytesReceived / 1024, i.TotalBytesToReceive / 1024); }; @@ -91,7 +89,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic // Automatically extract statusLabel.GetText = () => "Extracting..."; - progressBar.SetIndeterminate(true); + progressBar.Indeterminate = true; if (InstallUtils.ExtractZip(file, dest, onExtractProgress, onError)) { Game.RunAfterTick(() => From c3ba27ef6c3d657a7ce0a3b5f46c5208ce481128 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Thu, 13 Mar 2014 12:43:42 +1300 Subject: [PATCH 7/9] Reimplement ingame map downloading. --- OpenRA.Game/GameRules/Settings.cs | 2 +- OpenRA.Game/MapCache.cs | 40 ++++- OpenRA.Game/MapPreview.cs | 136 ++++++++++++++- OpenRA.Mods.RA/Widgets/Logic/LobbyLogic.cs | 2 + .../Widgets/Logic/LobbyMapPreviewLogic.cs | 130 ++++++++++++-- mods/cnc/chrome/lobby-mappreview.yaml | 159 ++++++++++++++--- mods/ra/chrome/lobby-mappreview.yaml | 161 +++++++++++++++--- 7 files changed, 563 insertions(+), 67 deletions(-) diff --git a/OpenRA.Game/GameRules/Settings.cs b/OpenRA.Game/GameRules/Settings.cs index 4295333806..d320d8eb9b 100644 --- a/OpenRA.Game/GameRules/Settings.cs +++ b/OpenRA.Game/GameRules/Settings.cs @@ -136,7 +136,7 @@ namespace OpenRA.GameRules public bool TeamHealthColors = false; public bool AllowDownloading = true; - public string[] MapRepositories = { "http://resource.openra.net/map/", "http://resource.ihptru.net:8080/map/" }; + public string MapRepository = "http://resource.openra.net/map/"; } public class KeySettings diff --git a/OpenRA.Game/MapCache.cs b/OpenRA.Game/MapCache.cs index cd0beec736..cf030d4103 100755 --- a/OpenRA.Game/MapCache.cs +++ b/OpenRA.Game/MapCache.cs @@ -14,10 +14,11 @@ using System.Collections.Generic; using System.Drawing; using System.IO; using System.Linq; +using System.Net; +using System.Text; using System.Threading; using OpenRA.FileFormats; using OpenRA.Graphics; -using OpenRA.Widgets; namespace OpenRA { @@ -57,6 +58,43 @@ namespace OpenRA } } + public void QueryRemoteMapDetails(IEnumerable uids) + { + var maps = uids.Distinct() + .Select(uid => previews[uid]) + .Where(p => p.Status == MapStatus.Unavailable) + .ToDictionary(p => p.Uid, p => p); + + if (!maps.Any()) + return; + + foreach (var p in maps.Values) + p.UpdateRemoteSearch(MapStatus.Searching, null); + + var url = Game.Settings.Game.MapRepository + "hash/" + string.Join(",", maps.Keys.ToArray()) + "/yaml"; + + Action onInfoComplete = (i, cancelled) => + { + if (cancelled || i.Error != null) + { + Log.Write("debug", "Remote map query failed with error: {0}", i.Error != null ? i.Error.Message : "cancelled"); + Log.Write("debug", "URL was: {0}", url); + foreach (var p in maps.Values) + p.UpdateRemoteSearch(MapStatus.Unavailable, null); + + return; + } + + var data = Encoding.UTF8.GetString(i.Result); + var yaml = MiniYaml.FromString(data); + + foreach (var kv in yaml) + maps[kv.Key].UpdateRemoteSearch(MapStatus.DownloadAvailable, kv.Value); + }; + + new Download(url, _ => { }, onInfoComplete); + } + public static IEnumerable FindMapsIn(string dir) { string[] noMaps = { }; diff --git a/OpenRA.Game/MapPreview.cs b/OpenRA.Game/MapPreview.cs index de0e3d1425..7b07dc293b 100755 --- a/OpenRA.Game/MapPreview.cs +++ b/OpenRA.Game/MapPreview.cs @@ -11,9 +11,11 @@ using System; using System.Collections; using System.Collections.Generic; +using System.ComponentModel; using System.Drawing; using System.IO; using System.Linq; +using System.Net; using System.Threading; using OpenRA.FileFormats; using OpenRA.Graphics; @@ -21,10 +23,26 @@ using OpenRA.Widgets; namespace OpenRA { - public enum MapStatus { Available, Unavailable } + public enum MapStatus { Available, Unavailable, Searching, DownloadAvailable, Downloading, DownloadError } + + // Fields names must match the with the remote API + public class RemoteMapData + { + public readonly string title; + public readonly string author; + public readonly string map_type; + public readonly int players; + public readonly Rectangle bounds; + public readonly int[] spawnpoints = {}; + public readonly string minimap; + public readonly bool downloading; + public readonly bool requires_upgrade; + } + public class MapPreview { static readonly List NoSpawns = new List(); + MapCache cache; public readonly string Uid; public string Title { get; private set; } @@ -37,6 +55,10 @@ namespace OpenRA public Map Map { get; private set; } public MapStatus Status { get; private set; } + Download download; + public long DownloadBytes { get; private set; } + public int DownloadPercentage { get; private set; } + Sprite minimap; bool generatingMinimap; public Sprite Minimap @@ -62,7 +84,6 @@ namespace OpenRA } } - MapCache cache; public MapPreview(string uid, MapCache cache) { this.cache = cache; @@ -89,5 +110,116 @@ namespace OpenRA CustomPreview = m.CustomPreview; Status = MapStatus.Available; } + + public void UpdateRemoteSearch(MapStatus status, MiniYaml yaml) + { + // Update on the main thread to ensure consistency + Game.RunAfterTick(() => + { + if (status == MapStatus.DownloadAvailable) + { + try + { + var r = FieldLoader.Load(yaml); + + // Map is not useable by the current version + if (!r.downloading || r.requires_upgrade) + { + Status = MapStatus.Unavailable; + return; + } + + Title = r.title; + Type = r.map_type; + Author = r.author; + PlayerCount = r.players; + Bounds = r.bounds; + + var spawns = new List(); + for (var j = 0; j < r.spawnpoints.Length; j += 2) + spawns.Add(new CPos(r.spawnpoints[j], r.spawnpoints[j+1])); + SpawnPoints = spawns; + + CustomPreview = new Bitmap(new MemoryStream(Convert.FromBase64String(r.minimap))); + } + catch (Exception) {} + + if (CustomPreview != null) + cache.CacheMinimap(this); + } + Status = status; + + }); + } + + public void Install() + { + if (Status != MapStatus.DownloadAvailable || !Game.Settings.Game.AllowDownloading) + return; + + Status = MapStatus.Downloading; + var baseMapPath = new[] { Platform.SupportDir, "maps", Game.modData.Manifest.Mod.Id }.Aggregate(Path.Combine); + + // Create the map directory if it doesn't exist + if (!Directory.Exists(baseMapPath)) + Directory.CreateDirectory(baseMapPath); + + new Thread(() => + { + // Request the filename from the server + // Run in a worker thread to avoid network delays + var mapUrl = Game.Settings.Game.MapRepository + Uid; + try + { + + var request = WebRequest.Create(mapUrl); + request.Method = "HEAD"; + var res = request.GetResponse(); + + // Map not found + if (res.Headers["Content-Disposition"] == null) + { + Status = MapStatus.DownloadError; + return; + } + + var mapPath = Path.Combine(baseMapPath, res.Headers["Content-Disposition"].Replace("attachment; filename = ", "")); + + Action onDownloadProgress = i => { DownloadBytes = i.BytesReceived; DownloadPercentage = i.ProgressPercentage; }; + Action onDownloadComplete = (i, cancelled) => + { + download = null; + + if (cancelled || i.Error != null) + { + Log.Write("debug", "Remote map download failed with error: {0}", i.Error != null ? i.Error.Message : "cancelled"); + Log.Write("debug", "URL was: {0}", mapUrl); + + Status = MapStatus.DownloadError; + return; + } + + Log.Write("debug", "Downloaded map to '{0}'", mapPath); + Game.RunAfterTick(() => UpdateFromMap(new Map(mapPath))); + }; + + download = new Download(mapUrl, mapPath, onDownloadProgress, onDownloadComplete); + } + catch (Exception e) + { + Console.WriteLine(e.Message); + Status = MapStatus.DownloadError; + } + }).Start(); + } + + public void CancelInstall() + { + if (download == null) + return; + + download.Cancel(); + download = null; + } } } diff --git a/OpenRA.Mods.RA/Widgets/Logic/LobbyLogic.cs b/OpenRA.Mods.RA/Widgets/Logic/LobbyLogic.cs index ad183ba8b7..6036605dca 100644 --- a/OpenRA.Mods.RA/Widgets/Logic/LobbyLogic.cs +++ b/OpenRA.Mods.RA/Widgets/Logic/LobbyLogic.cs @@ -554,6 +554,8 @@ namespace OpenRA.Mods.RA.Widgets.Logic if (!Map.Map.Options.StartingCash.HasValue && !pri.SelectableCash.Contains(orderManager.LobbyInfo.GlobalSettings.StartingCash)) orderManager.IssueOrder(Order.Command("startingcash {0}".F(pri.DefaultCash))); } + else if (Game.Settings.Game.AllowDownloading) + Game.modData.MapCache.QueryRemoteMapDetails(new [] { uid }); } void UpdatePlayerList() diff --git a/OpenRA.Mods.RA/Widgets/Logic/LobbyMapPreviewLogic.cs b/OpenRA.Mods.RA/Widgets/Logic/LobbyMapPreviewLogic.cs index c01303bdc7..a62cfa1b63 100644 --- a/OpenRA.Mods.RA/Widgets/Logic/LobbyMapPreviewLogic.cs +++ b/OpenRA.Mods.RA/Widgets/Logic/LobbyMapPreviewLogic.cs @@ -23,22 +23,126 @@ namespace OpenRA.Mods.RA.Widgets.Logic [ObjectCreator.UseCtor] internal LobbyMapPreviewLogic(Widget widget, OrderManager orderManager, LobbyLogic lobby) { - var mapPreview = widget.Get("MAP_PREVIEW"); - mapPreview.Preview = () => lobby.Map; - mapPreview.OnMouseDown = mi => LobbyUtils.SelectSpawnPoint(orderManager, mapPreview, lobby.Map, mi); - mapPreview.SpawnClients = () => LobbyUtils.GetSpawnClients(orderManager, lobby.Map); + var available = widget.GetOrNull("MAP_AVAILABLE"); + if (available != null) + { + available.IsVisible = () => lobby.Map.Status == MapStatus.Available; - var mapTitle = widget.GetOrNull("MAP_TITLE"); - if (mapTitle != null) - mapTitle.GetText = () => lobby.Map.Title; + var preview = available.Get("MAP_PREVIEW"); + preview.Preview = () => lobby.Map; + preview.OnMouseDown = mi => LobbyUtils.SelectSpawnPoint(orderManager, preview, lobby.Map, mi); + preview.SpawnClients = () => LobbyUtils.GetSpawnClients(orderManager, lobby.Map); - var mapType = widget.GetOrNull("MAP_TYPE"); - if (mapType != null) - mapType.GetText = () => lobby.Map.Type; + var title = available.GetOrNull("MAP_TITLE"); + if (title != null) + title.GetText = () => lobby.Map.Title; - var mapAuthor = widget.GetOrNull("MAP_AUTHOR"); - if (mapAuthor != null) - mapAuthor.GetText = () => "Created by {0}".F(lobby.Map.Author); + var type = available.GetOrNull("MAP_TYPE"); + if (type != null) + type.GetText = () => lobby.Map.Type; + + var author = available.GetOrNull("MAP_AUTHOR"); + if (author != null) + author.GetText = () => "Created by {0}".F(lobby.Map.Author); + } + + var download = widget.GetOrNull("MAP_DOWNLOADABLE"); + if (download != null) + { + download.IsVisible = () => lobby.Map.Status == MapStatus.DownloadAvailable; + + var preview = download.Get("MAP_PREVIEW"); + preview.Preview = () => lobby.Map; + preview.OnMouseDown = mi => LobbyUtils.SelectSpawnPoint(orderManager, preview, lobby.Map, mi); + preview.SpawnClients = () => LobbyUtils.GetSpawnClients(orderManager, lobby.Map); + + var title = download.GetOrNull("MAP_TITLE"); + if (title != null) + title.GetText = () => lobby.Map.Title; + + var type = download.GetOrNull("MAP_TYPE"); + if (type != null) + type.GetText = () => lobby.Map.Type; + + var author = download.GetOrNull("MAP_AUTHOR"); + if (author != null) + author.GetText = () => "Created by {0}".F(lobby.Map.Author); + + var install = download.GetOrNull("MAP_INSTALL"); + if (install != null) + install.OnClick = () => lobby.Map.Install(); + } + + var progress = widget.GetOrNull("MAP_PROGRESS"); + if (progress != null) + { + progress.IsVisible = () => lobby.Map.Status != MapStatus.Available && lobby.Map.Status != MapStatus.DownloadAvailable; + + var preview = progress.Get("MAP_PREVIEW"); + preview.Preview = () => lobby.Map; + preview.OnMouseDown = mi => LobbyUtils.SelectSpawnPoint(orderManager, preview, lobby.Map, mi); + preview.SpawnClients = () => LobbyUtils.GetSpawnClients(orderManager, lobby.Map); + + var title = progress.GetOrNull("MAP_TITLE"); + if (title != null) + title.GetText = () => lobby.Map.Title; + + var type = progress.GetOrNull("MAP_TYPE"); + if (type != null) + type.GetText = () => lobby.Map.Type; + + var statusSearching = progress.GetOrNull("MAP_STATUS_SEARCHING"); + if (statusSearching != null) + statusSearching.IsVisible = () => lobby.Map.Status == MapStatus.Searching; + + var statusUnavailable = progress.GetOrNull("MAP_STATUS_UNAVAILABLE"); + if (statusUnavailable != null) + statusUnavailable.IsVisible = () => lobby.Map.Status == MapStatus.Unavailable; + + var statusError = progress.GetOrNull("MAP_STATUS_ERROR"); + if (statusError != null) + statusError.IsVisible = () => lobby.Map.Status == MapStatus.DownloadError; + + var statusDownloading = progress.GetOrNull("MAP_STATUS_DOWNLOADING"); + if (statusDownloading != null) + { + statusDownloading.IsVisible = () => lobby.Map.Status == MapStatus.Downloading; + statusDownloading.GetText = () => + { + if (lobby.Map.DownloadBytes == 0) + return "Connecting..."; + + // Server does not provide the total file length + if (lobby.Map.DownloadPercentage == 0) + return "Downloading {0} kB".F(lobby.Map.DownloadBytes / 1024); + + return "Downloading {0} kB ({1}%)".F(lobby.Map.DownloadBytes / 1024, lobby.Map.DownloadPercentage); + }; + } + + var retry = progress.GetOrNull("MAP_RETRY"); + if (retry != null) + { + retry.IsVisible = () => lobby.Map.Status == MapStatus.DownloadError || lobby.Map.Status == MapStatus.Unavailable; + retry.OnClick = () => + { + if (lobby.Map.Status == MapStatus.DownloadError) + lobby.Map.Install(); + else if (lobby.Map.Status == MapStatus.Unavailable) + Game.modData.MapCache.QueryRemoteMapDetails(new [] { lobby.Map.Uid }); + }; + + retry.GetText = () => lobby.Map.Status == MapStatus.DownloadError ? "Retry Install" : "Retry Search"; + } + + var progressbar = progress.GetOrNull("MAP_PROGRESSBAR"); + if (progressbar != null) + { + progressbar.IsIndeterminate = () => lobby.Map.DownloadPercentage == 0; + progressbar.GetPercentage = () => lobby.Map.DownloadPercentage; + progressbar.IsVisible = () => !retry.IsVisible(); + } + } } } } diff --git a/mods/cnc/chrome/lobby-mappreview.yaml b/mods/cnc/chrome/lobby-mappreview.yaml index d3c1e7dae5..f0eeb944f4 100644 --- a/mods/cnc/chrome/lobby-mappreview.yaml +++ b/mods/cnc/chrome/lobby-mappreview.yaml @@ -5,32 +5,141 @@ Container@LOBBY_MAP_PREVIEW: Width:194 Height:250 Children: - Background@MAP_BG: + Container@MAP_AVAILABLE: Width:PARENT_RIGHT - Height:194 - Background:panel-gray + Height:PARENT_BOTTOM Children: - MapPreview@MAP_PREVIEW: - X:1 - Y:1 - Width:PARENT_RIGHT-2 - Height:PARENT_BOTTOM-2 - TooltipContainer:TOOLTIP_CONTAINER - Label@MAP_TITLE: - Y:197 + Background@MAP_BG: + Width:PARENT_RIGHT + Height:194 + Background:panel-gray + Children: + MapPreview@MAP_PREVIEW: + X:1 + Y:1 + Width:PARENT_RIGHT-2 + Height:PARENT_BOTTOM-2 + TooltipContainer:TOOLTIP_CONTAINER + Label@MAP_TITLE: + Y:197 + Width:PARENT_RIGHT + Height:25 + Font:Bold + Align:Center + Label@MAP_TYPE: + Y:212 + Width:PARENT_RIGHT + Height:25 + Font:TinyBold + Align:Center + Label@MAP_AUTHOR: + Y:225 + Width:PARENT_RIGHT + Height:25 + Font:Tiny + Align:Center + Container@MAP_DOWNLOADABLE: Width:PARENT_RIGHT - Height:25 - Font:Bold - Align:Center - Label@MAP_TYPE: - Y:212 + Height:PARENT_BOTTOM + Children: + Background@MAP_BG: + Width:PARENT_RIGHT + Height:164 + Background:panel-gray + Children: + MapPreview@MAP_PREVIEW: + X:1 + Y:1 + Width:PARENT_RIGHT-2 + Height:PARENT_BOTTOM-2 + TooltipContainer:TOOLTIP_CONTAINER + Label@MAP_TITLE: + Y:167 + Width:PARENT_RIGHT + Height:25 + Font:Bold + Align:Center + Label@MAP_TYPE: + Y:184 + Width:PARENT_RIGHT + Height:25 + Font:TinyBold + Align:Center + Label@MAP_AUTHOR: + Y:197 + Width:PARENT_RIGHT + Height:25 + Font:Tiny + Align:Center + Button@MAP_INSTALL: + Y:224 + Width:PARENT_RIGHT + Height:25 + Text:Install Map + Container@MAP_PROGRESS: Width:PARENT_RIGHT - Height:25 - Font:TinyBold - Align:Center - Label@MAP_AUTHOR: - Y:225 - Width:PARENT_RIGHT - Height:25 - Font:Tiny - Align:Center + Height:PARENT_BOTTOM + Children: + Background@MAP_BG: + Width:PARENT_RIGHT + Height:164 + Background:panel-gray + Children: + MapPreview@MAP_PREVIEW: + X:1 + Y:1 + Width:PARENT_RIGHT-2 + Height:PARENT_BOTTOM-2 + TooltipContainer:TOOLTIP_CONTAINER + Label@MAP_TITLE: + Y:167 + Width:PARENT_RIGHT + Height:25 + Font:Bold + Align:Center + Label@MAP_STATUS_SEARCHING: + Y:197 + Width:PARENT_RIGHT + Height:25 + Font:Tiny + Align:Center + Text: Searching OpenRA Resource Center... + Container@MAP_STATUS_UNAVAILABLE: + Width:PARENT_RIGHT + Children: + Label@a: + Y:184 + Width:PARENT_RIGHT + Height:25 + Font:Tiny + Align:Center + Text:This map was not found on the + Label@b: + Y:197 + Width:PARENT_RIGHT + Height:25 + Font:Tiny + Align:Center + Text:OpenRA Resource Center + Label@MAP_STATUS_ERROR: + Y:197 + Width:PARENT_RIGHT + Height:25 + Font:Tiny + Align:Center + Text:An error occurred during installation + Label@MAP_STATUS_DOWNLOADING: + Y:197 + Width:PARENT_RIGHT + Height:25 + Font:Tiny + Align:Center + ProgressBar@MAP_PROGRESSBAR: + Y:224 + Width:PARENT_RIGHT + Height:25 + Indeterminate:True + Button@MAP_RETRY: + Y:224 + Width:PARENT_RIGHT + Height:25 \ No newline at end of file diff --git a/mods/ra/chrome/lobby-mappreview.yaml b/mods/ra/chrome/lobby-mappreview.yaml index 3dfb153feb..375465d466 100644 --- a/mods/ra/chrome/lobby-mappreview.yaml +++ b/mods/ra/chrome/lobby-mappreview.yaml @@ -5,32 +5,143 @@ Container@LOBBY_MAP_PREVIEW: Width:214 Height:250 Children: - Background@MAP_BG: + Container@MAP_AVAILABLE: Width:PARENT_RIGHT - Height:214 - Background:dialog3 + Height:PARENT_BOTTOM Children: - MapPreview@MAP_PREVIEW: - X:2 - Y:2 - Width:210 - Height:210 - TooltipContainer:TOOLTIP_CONTAINER - Label@MAP_TITLE: - Y:215 + Background@MAP_BG: + Width:PARENT_RIGHT + Height:214 + Background:dialog3 + Children: + MapPreview@MAP_PREVIEW: + X:1 + Y:1 + Width:PARENT_RIGHT-2 + Height:PARENT_BOTTOM-2 + TooltipContainer:TOOLTIP_CONTAINER + Label@MAP_TITLE: + Y:215 + Width:PARENT_RIGHT + Height:25 + Font:Bold + Align:Center + Label@MAP_TYPE: + Y:232 + Width:PARENT_RIGHT + Height:25 + Font:TinyBold + Align:Center + Label@MAP_AUTHOR: + Y:245 + Width:PARENT_RIGHT + Height:25 + Font:Tiny + Align:Center + Container@MAP_DOWNLOADABLE: Width:PARENT_RIGHT - Height:25 - Font:Bold - Align:Center - Label@MAP_TYPE: - Y:230 + Height:PARENT_BOTTOM + Children: + Background@MAP_BG: + Width:PARENT_RIGHT + Height:182 + Background:dialog3 + Children: + MapPreview@MAP_PREVIEW: + X:1 + Y:1 + Width:PARENT_RIGHT-2 + Height:PARENT_BOTTOM-2 + TooltipContainer:TOOLTIP_CONTAINER + Label@MAP_TITLE: + Y:185 + Width:PARENT_RIGHT + Height:25 + Font:Bold + Align:Center + Label@MAP_TYPE: + Y:202 + Width:PARENT_RIGHT + Height:25 + Font:TinyBold + Align:Center + Label@MAP_AUTHOR: + Y:215 + Width:PARENT_RIGHT + Height:25 + Font:Tiny + Align:Center + Button@MAP_INSTALL: + Y:242 + Width:PARENT_RIGHT + Height:25 + Font:Bold + Text:Install Map + Container@MAP_PROGRESS: Width:PARENT_RIGHT - Height:25 - Font:TinyBold - Align:Center - Label@MAP_AUTHOR: - Y:243 - Width:PARENT_RIGHT - Height:25 - Font:Tiny - Align:Center \ No newline at end of file + Height:PARENT_BOTTOM + Children: + Background@MAP_BG: + Width:PARENT_RIGHT + Height:182 + Background:dialog3 + Children: + MapPreview@MAP_PREVIEW: + X:1 + Y:1 + Width:PARENT_RIGHT-2 + Height:PARENT_BOTTOM-2 + TooltipContainer:TOOLTIP_CONTAINER + Label@MAP_TITLE: + Y:185 + Width:PARENT_RIGHT + Height:25 + Font:Bold + Align:Center + Label@MAP_STATUS_SEARCHING: + Y:215 + Width:PARENT_RIGHT + Height:25 + Font:Tiny + Align:Center + Text: Searching OpenRA Resource Center... + Container@MAP_STATUS_UNAVAILABLE: + Width:PARENT_RIGHT + Children: + Label@a: + Y:202 + Width:PARENT_RIGHT + Height:25 + Font:Tiny + Align:Center + Text:This map was not found on the + Label@b: + Y:215 + Width:PARENT_RIGHT + Height:25 + Font:Tiny + Align:Center + Text:OpenRA Resource Center + Label@MAP_STATUS_ERROR: + Y:215 + Width:PARENT_RIGHT + Height:25 + Font:Tiny + Align:Center + Text:An error occurred during installation + Label@MAP_STATUS_DOWNLOADING: + Y:215 + Width:PARENT_RIGHT + Height:25 + Font:Tiny + Align:Center + ProgressBar@MAP_PROGRESSBAR: + Y:242 + Width:PARENT_RIGHT + Height:25 + Indeterminate:True + Button@MAP_RETRY: + Y:242 + Width:PARENT_RIGHT + Height:25 + Font:Bold \ No newline at end of file From 6538f696fadb96ece202fe14b3a5031ecf643c27 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Sun, 16 Mar 2014 18:09:27 +1300 Subject: [PATCH 8/9] Use the resource site to fill in missing details in the server browser. --- .../Widgets/Logic/ServerBrowserLogic.cs | 52 ++++++++++--------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/OpenRA.Mods.RA/Widgets/Logic/ServerBrowserLogic.cs b/OpenRA.Mods.RA/Widgets/Logic/ServerBrowserLogic.cs index 0a5fbdf279..7aa136902b 100644 --- a/OpenRA.Mods.RA/Widgets/Logic/ServerBrowserLogic.cs +++ b/OpenRA.Mods.RA/Widgets/Logic/ServerBrowserLogic.cs @@ -147,30 +147,6 @@ namespace OpenRA.Mods.RA.Widgets.Logic { 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; @@ -241,6 +217,34 @@ namespace OpenRA.Mods.RA.Widgets.Logic if (!Filtered(game)) rows.Add(item); } + + 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; + + // Search for any unknown maps + if (Game.Settings.Game.AllowDownloading) + Game.modData.MapCache.QueryRemoteMapDetails(games.Where(g => !Filtered(g)).Select(g => g.Map)); + + foreach (var row in rows) + serverList.AddChild(row); + }); } void OpenLobby() From 595ef7bfae2dbdb8e2f2902510f4c594f83ce7f7 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Sun, 16 Mar 2014 21:49:07 +1300 Subject: [PATCH 9/9] Update changelog. --- CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index bceae93927..7af416a5fe 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -27,6 +27,9 @@ NEW: Fixed the game sometimes crashing when deploying and activating the guard cursor at the same time. Build time is now set when an item reaches the front of a queue, instead of immediately when queued. The attack cursor now changes if the target is out of range. + The server browser will now show map details from other mods if the maps are available online. + Fixed a crash when connecting to a server with an unavailable map. + Added a warning dialog when force starting a match. Dune 2000: Added the Atreides grenadier from the 1.06 patch. Added randomized tiles for Sand and Rock terrain.