diff --git a/OpenRA.Game/Map/MapPreview.cs b/OpenRA.Game/Map/MapPreview.cs index f6142301d5..53fa57d851 100644 --- a/OpenRA.Game/Map/MapPreview.cs +++ b/OpenRA.Game/Map/MapPreview.cs @@ -81,6 +81,7 @@ namespace OpenRA Lazy rules; public Ruleset Rules { get { return rules != null ? rules.Value : null; } } public bool InvalidCustomRules { get; private set; } + public bool RulesLoaded { get; private set; } Download download; public long DownloadBytes { get; private set; } @@ -209,6 +210,9 @@ namespace OpenRA Status = MapStatus.Unavailable; } + // Note: multiple threads may try to access the value at the same time + // We rely on the thread-safety guarantees given by Lazy to prevent race conitions. + // If you're thinking about replacing this, then you must be careful to keep this safe. rules = Exts.Lazy(() => { try @@ -225,9 +229,12 @@ namespace OpenRA catch { InvalidCustomRules = true; + return Ruleset.LoadDefaultsForTileSet(modData, TileSet); + } + finally + { + RulesLoaded = true; } - - return Ruleset.LoadDefaultsForTileSet(modData, TileSet); }); if (p.Contains("map.png")) diff --git a/OpenRA.Game/Widgets/WidgetUtils.cs b/OpenRA.Game/Widgets/WidgetUtils.cs index 27ffd52c56..acd01e4e77 100644 --- a/OpenRA.Game/Widgets/WidgetUtils.cs +++ b/OpenRA.Game/Widgets/WidgetUtils.cs @@ -249,8 +249,6 @@ namespace OpenRA.Widgets return trimmed; } - public static Action Once(Action a) { return () => { if (a != null) { a(); a = null; } }; } - public static string ChooseInitialMap(string initialUid) { if (string.IsNullOrEmpty(initialUid) || Game.ModData.MapCache[initialUid].Status != MapStatus.Available) diff --git a/OpenRA.Mods.Common/ServerTraits/LobbyCommands.cs b/OpenRA.Mods.Common/ServerTraits/LobbyCommands.cs index 427e923674..671cb96374 100644 --- a/OpenRA.Mods.Common/ServerTraits/LobbyCommands.cs +++ b/OpenRA.Mods.Common/ServerTraits/LobbyCommands.cs @@ -357,6 +357,8 @@ namespace OpenRA.Mods.Common.Server // - Observers remain as observers // - Players who now lack a slot are made observers // - Bots who now lack a slot are dropped + // - Bots who are not defined in the map rules are dropped + var botNames = server.Map.Rules.Actors["player"].TraitInfos().Select(t => t.Name); var slots = server.LobbyInfo.Slots.Keys.ToArray(); var i = 0; foreach (var os in oldSlots) @@ -370,7 +372,7 @@ namespace OpenRA.Mods.Common.Server if (c.Slot != null) { // Remove Bot from slot if slot forbids bots - if (c.Bot != null && !server.Map.Players.Players[c.Slot].AllowBots) + if (c.Bot != null && (!server.Map.Players.Players[c.Slot].AllowBots || !botNames.Contains(c.Bot))) server.LobbyInfo.Clients.Remove(c); S.SyncClientToPlayerReference(c, server.Map.Players.Players[c.Slot]); } diff --git a/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyLogic.cs index 5084aa284d..e6bfdfbf78 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyLogic.cs @@ -13,7 +13,7 @@ using System; using System.Collections.Generic; using System.Drawing; using System.Linq; -using System.Threading; +using System.Threading.Tasks; using OpenRA.Chat; using OpenRA.Graphics; using OpenRA.Mods.Common.Traits; @@ -27,8 +27,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic { static readonly Action DoNothing = () => { }; - public MapPreview MapPreview { get; private set; } - public Map Map { get; private set; } + public MapPreview Map { get; private set; } readonly ModData modData; readonly Action onStart; @@ -66,6 +65,8 @@ namespace OpenRA.Mods.Common.Widgets.Logic readonly LabelWidget chatLabel; bool teamChat; + bool addBotOnMapLoad; + int lobbyChatUnreadMessages; int globalChatLastReadMessages; int globalChatUnreadMessages; @@ -114,7 +115,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic internal LobbyLogic(Widget widget, ModData modData, WorldRenderer worldRenderer, OrderManager orderManager, Action onExit, Action onStart, bool skirmishMode) { - MapPreview = MapCache.UnknownMap; + Map = MapCache.UnknownMap; lobby = widget; this.modData = modData; this.orderManager = orderManager; @@ -163,7 +164,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic var gameStarting = false; Func configurationDisabled = () => !Game.IsHost || gameStarting || panel == PanelType.Kick || panel == PanelType.ForceStart || - Map == null || Map.InvalidCustomRules || + !Map.RulesLoaded || Map.InvalidCustomRules || orderManager.LocalClient == null || orderManager.LocalClient.IsReady; var mapButton = lobby.GetOrNull("CHANGEMAP_BUTTON"); @@ -176,7 +177,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic var onSelect = new Action(uid => { // Don't select the same map again - if (uid == MapPreview.Uid) + if (uid == Map.Uid) return; orderManager.IssueOrder(Order.Command("map " + uid)); @@ -186,7 +187,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic Ui.OpenWindow("MAPCHOOSER_PANEL", new WidgetArgs() { - { "initialMap", MapPreview.Uid }, + { "initialMap", Map.Uid }, { "initialTab", MapClassification.System }, { "onExit", DoNothing }, { "onSelect", Game.IsHost ? onSelect : null }, @@ -202,9 +203,9 @@ namespace OpenRA.Mods.Common.Widgets.Logic (orderManager.LobbyInfo.Slots.Values.All(s => !s.AllowBots) && orderManager.LobbyInfo.Slots.Count(s => !s.Value.LockTeam && orderManager.LobbyInfo.ClientInSlot(s.Key) != null) == 0); - var botNames = modRules.Actors["player"].TraitInfos().Select(t => t.Name); slotsButton.OnMouseDown = _ => { + var botNames = Map.Rules.Actors["player"].TraitInfos().Select(t => t.Name); var options = new Dictionary>(); var botController = orderManager.LobbyInfo.Clients.FirstOrDefault(c => c.IsAdmin); @@ -302,7 +303,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic var optionsTab = lobby.Get("OPTIONS_TAB"); optionsTab.IsHighlighted = () => panel == PanelType.Options; - optionsTab.IsDisabled = () => Map == null || Map.InvalidCustomRules || panel == PanelType.Kick || panel == PanelType.ForceStart; + optionsTab.IsDisabled = () => !Map.RulesLoaded || Map.InvalidCustomRules || panel == PanelType.Kick || panel == PanelType.ForceStart; optionsTab.OnClick = () => panel = PanelType.Options; var playersTab = lobby.Get("PLAYERS_TAB"); @@ -349,7 +350,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic var allowCheats = optionsBin.GetOrNull("ALLOWCHEATS_CHECKBOX"); if (allowCheats != null) { - var cheatsLocked = new CachedTransform( + var cheatsLocked = new CachedTransform( map => map.Rules.Actors["player"].TraitInfo().Locked); allowCheats.IsChecked = () => orderManager.LobbyInfo.GlobalSettings.AllowCheats; @@ -361,7 +362,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic var crates = optionsBin.GetOrNull("CRATES_CHECKBOX"); if (crates != null) { - var cratesLocked = new CachedTransform(map => + var cratesLocked = new CachedTransform(map => { var crateSpawner = map.Rules.Actors["world"].TraitInfoOrDefault(); return crateSpawner == null || crateSpawner.Locked; @@ -376,7 +377,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic var creeps = optionsBin.GetOrNull("CREEPS_CHECKBOX"); if (creeps != null) { - var creepsLocked = new CachedTransform(map => + var creepsLocked = new CachedTransform(map => { var mapCreeps = map.Rules.Actors["world"].TraitInfoOrDefault(); return mapCreeps == null || mapCreeps.Locked; @@ -391,7 +392,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic var allybuildradius = optionsBin.GetOrNull("ALLYBUILDRADIUS_CHECKBOX"); if (allybuildradius != null) { - var allyBuildRadiusLocked = new CachedTransform(map => + var allyBuildRadiusLocked = new CachedTransform(map => { var mapBuildRadius = map.Rules.Actors["world"].TraitInfoOrDefault(); return mapBuildRadius == null || mapBuildRadius.AllyBuildRadiusLocked; @@ -406,7 +407,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic var shortGame = optionsBin.GetOrNull("SHORTGAME_CHECKBOX"); if (shortGame != null) { - var shortGameLocked = new CachedTransform( + var shortGameLocked = new CachedTransform( map => map.Rules.Actors["world"].TraitInfo().ShortGameLocked); shortGame.IsChecked = () => orderManager.LobbyInfo.GlobalSettings.ShortGame; @@ -418,10 +419,10 @@ namespace OpenRA.Mods.Common.Widgets.Logic var difficulty = optionsBin.GetOrNull("DIFFICULTY_DROPDOWNBUTTON"); if (difficulty != null) { - var mapOptions = new CachedTransform( + var mapOptions = new CachedTransform( map => map.Rules.Actors["world"].TraitInfo()); - difficulty.IsVisible = () => Map != null && mapOptions.Update(Map).Difficulties.Any(); + difficulty.IsVisible = () => Map.RulesLoaded && mapOptions.Update(Map).Difficulties.Any(); difficulty.IsDisabled = () => configurationDisabled() || mapOptions.Update(Map).DifficultyLocked; difficulty.GetText = () => orderManager.LobbyInfo.GlobalSettings.Difficulty; difficulty.OnMouseDown = _ => @@ -447,10 +448,10 @@ namespace OpenRA.Mods.Common.Widgets.Logic var startingUnits = optionsBin.GetOrNull("STARTINGUNITS_DROPDOWNBUTTON"); if (startingUnits != null) { - var startUnitsInfos = new CachedTransform>( + var startUnitsInfos = new CachedTransform>( map => map.Rules.Actors["world"].TraitInfos()); - var startUnitsLocked = new CachedTransform(map => + var startUnitsLocked = new CachedTransform(map => { var spawnUnitsInfo = map.Rules.Actors["world"].TraitInfoOrDefault(); return spawnUnitsInfo == null || spawnUnitsInfo.Locked; @@ -463,8 +464,8 @@ namespace OpenRA.Mods.Common.Widgets.Logic }; startingUnits.IsDisabled = () => configurationDisabled() || startUnitsLocked.Update(Map); - startingUnits.GetText = () => MapPreview.Status != MapStatus.Available || - Map == null || startUnitsLocked.Update(Map) ? "Not Available" : className(orderManager.LobbyInfo.GlobalSettings.StartingUnitsClass); + startingUnits.GetText = () => Map.Status != MapStatus.Available || + !Map.RulesLoaded || startUnitsLocked.Update(Map) ? "Not Available" : className(orderManager.LobbyInfo.GlobalSettings.StartingUnitsClass); startingUnits.OnMouseDown = _ => { var classes = startUnitsInfos.Update(Map).Select(a => a.Class).Distinct(); @@ -491,12 +492,12 @@ namespace OpenRA.Mods.Common.Widgets.Logic var startingCash = optionsBin.GetOrNull("STARTINGCASH_DROPDOWNBUTTON"); if (startingCash != null) { - var playerResources = new CachedTransform( + var playerResources = new CachedTransform( map => map.Rules.Actors["player"].TraitInfo()); startingCash.IsDisabled = () => configurationDisabled() || playerResources.Update(Map).DefaultCashLocked; - startingCash.GetText = () => MapPreview.Status != MapStatus.Available || - Map == null || playerResources.Update(Map).DefaultCashLocked ? "Not Available" : "${0}".F(orderManager.LobbyInfo.GlobalSettings.StartingCash); + startingCash.GetText = () => Map.Status != MapStatus.Available || + !Map.RulesLoaded || playerResources.Update(Map).DefaultCashLocked ? "Not Available" : "${0}".F(orderManager.LobbyInfo.GlobalSettings.StartingCash); startingCash.OnMouseDown = _ => { var options = playerResources.Update(Map).SelectableCash.Select(c => new DropDownOption @@ -520,20 +521,20 @@ namespace OpenRA.Mods.Common.Widgets.Logic var techLevel = optionsBin.GetOrNull("TECHLEVEL_DROPDOWNBUTTON"); if (techLevel != null) { - var mapOptions = new CachedTransform( + var mapOptions = new CachedTransform( map => map.Rules.Actors["world"].TraitInfo()); - var techLevels = new CachedTransform>( + var techLevels = new CachedTransform>( map => map.Rules.Actors["player"].TraitInfos().ToList()); - techLevel.IsVisible = () => Map != null && techLevels.Update(Map).Any(); + techLevel.IsVisible = () => Map.RulesLoaded && techLevels.Update(Map).Any(); var techLevelDescription = optionsBin.GetOrNull("TECHLEVEL_DESC"); if (techLevelDescription != null) techLevelDescription.IsVisible = techLevel.IsVisible; techLevel.IsDisabled = () => configurationDisabled() || mapOptions.Update(Map).TechLevelLocked; - techLevel.GetText = () => MapPreview.Status != MapStatus.Available || - Map == null || mapOptions.Update(Map).TechLevelLocked ? "Not Available" : "{0}".F(orderManager.LobbyInfo.GlobalSettings.TechLevel); + techLevel.GetText = () => Map.Status != MapStatus.Available || + !Map.RulesLoaded || mapOptions.Update(Map).TechLevelLocked ? "Not Available" : "{0}".F(orderManager.LobbyInfo.GlobalSettings.TechLevel); techLevel.OnMouseDown = _ => { var options = techLevels.Update(Map).Select(c => new DropDownOption @@ -562,7 +563,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic gameSpeed.IsDisabled = configurationDisabled; gameSpeed.GetText = () => { - if (MapPreview.Status != MapStatus.Available) + if (Map.Status != MapStatus.Available) return "Not Available"; GameSpeed speed; @@ -595,7 +596,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic var exploredMap = optionsBin.GetOrNull("EXPLORED_MAP_CHECKBOX"); if (exploredMap != null) { - var exploredMapLocked = new CachedTransform( + var exploredMapLocked = new CachedTransform( map => map.Rules.Actors["player"].TraitInfo().ExploredMapLocked); exploredMap.IsChecked = () => !orderManager.LobbyInfo.GlobalSettings.Shroud; @@ -607,7 +608,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic var enableFog = optionsBin.GetOrNull("FOG_CHECKBOX"); if (enableFog != null) { - var fogLocked = new CachedTransform( + var fogLocked = new CachedTransform( map => map.Rules.Actors["player"].TraitInfo().FogLocked); enableFog.IsChecked = () => orderManager.LobbyInfo.GlobalSettings.Fog; @@ -712,16 +713,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic // Add a bot on the first lobbyinfo update if (skirmishMode) - { - Game.LobbyInfoChanged += WidgetUtils.Once(() => - { - var slot = orderManager.LobbyInfo.FirstEmptyBotSlot(); - var bot = modRules.Actors["player"].TraitInfos().Select(t => t.Name).FirstOrDefault(); - var botController = orderManager.LobbyInfo.Clients.FirstOrDefault(c => c.IsAdmin); - if (slot != null && bot != null) - orderManager.IssueOrder(Order.Command("slot_bot {0} {1} {2}".F(slot, botController.Index, bot))); - }); - } + addBotOnMapLoad = true; } public override void Tick() @@ -787,28 +779,37 @@ namespace OpenRA.Mods.Common.Widgets.Logic void UpdateCurrentMap() { var uid = orderManager.LobbyInfo.GlobalSettings.Map; - if (MapPreview.Uid == uid) + if (Map.Uid == uid) return; - MapPreview = modData.MapCache[uid]; - Map = null; - if (MapPreview.Status == MapStatus.Available) + Map = modData.MapCache[uid]; + if (Map.Status == MapStatus.Available) { // Maps need to be validated and pre-loaded before they can be accessed - new Thread(_ => + var currentMap = Map; + new Task(() => { - var currentMap = Map = new Map(modData, MapPreview.Package); - currentMap.PreloadRules(); + // Force map rules to be loaded on this background thread + var unused = currentMap.Rules; Game.RunAfterTick(() => { // Map may have changed in the meantime if (currentMap != Map) return; + // Tell the server that we have the map if (!currentMap.InvalidCustomRules) - { - // Tell the server that we have the map orderManager.IssueOrder(Order.Command("state {0}".F(Session.ClientState.NotReady))); + + if (addBotOnMapLoad) + { + var slot = orderManager.LobbyInfo.FirstEmptyBotSlot(); + var bot = currentMap.Rules.Actors["player"].TraitInfos().Select(t => t.Name).FirstOrDefault(); + var botController = orderManager.LobbyInfo.Clients.FirstOrDefault(c => c.IsAdmin); + if (slot != null && bot != null) + orderManager.IssueOrder(Order.Command("slot_bot {0} {1} {2}".F(slot, botController.Index, bot))); + + addBotOnMapLoad = false; } }); }).Start(); @@ -841,7 +842,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic template = emptySlotTemplate.Clone(); if (Game.IsHost) - LobbyUtils.SetupEditableSlotWidget(template, slot, client, orderManager, modRules); + LobbyUtils.SetupEditableSlotWidget(this, template, slot, client, orderManager); else LobbyUtils.SetupSlotWidget(template, slot, client); @@ -860,15 +861,15 @@ namespace OpenRA.Mods.Common.Widgets.Logic LobbyUtils.SetupClientWidget(template, client, orderManager, client.Bot == null); if (client.Bot != null) - LobbyUtils.SetupEditableSlotWidget(template, slot, client, orderManager, modRules); + LobbyUtils.SetupEditableSlotWidget(this, template, slot, client, orderManager); else LobbyUtils.SetupEditableNameWidget(template, slot, client, orderManager); LobbyUtils.SetupEditableColorWidget(template, slot, client, orderManager, shellmapWorld, colorPreview); LobbyUtils.SetupEditableFactionWidget(template, slot, client, orderManager, factions); - LobbyUtils.SetupEditableTeamWidget(template, slot, client, orderManager, MapPreview); - LobbyUtils.SetupEditableSpawnWidget(template, slot, client, orderManager, MapPreview); - LobbyUtils.SetupEditableReadyWidget(template, slot, client, orderManager, MapPreview, Map == null || Map.InvalidCustomRules); + LobbyUtils.SetupEditableTeamWidget(template, slot, client, orderManager, Map); + LobbyUtils.SetupEditableSpawnWidget(template, slot, client, orderManager, Map); + LobbyUtils.SetupEditableReadyWidget(template, slot, client, orderManager, Map, !Map.RulesLoaded || Map.InvalidCustomRules); } else { diff --git a/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyMapPreviewLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyMapPreviewLogic.cs index e2bb6719ca..7b9775bcc4 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyMapPreviewLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyMapPreviewLogic.cs @@ -26,80 +26,80 @@ namespace OpenRA.Mods.Common.Widgets.Logic var available = widget.GetOrNull("MAP_AVAILABLE"); if (available != null) { - available.IsVisible = () => lobby.MapPreview.Status == MapStatus.Available && (lobby.Map == null || !lobby.Map.InvalidCustomRules); + available.IsVisible = () => lobby.Map.Status == MapStatus.Available && (!lobby.Map.RulesLoaded || !lobby.Map.InvalidCustomRules); var preview = available.Get("MAP_PREVIEW"); - preview.Preview = () => lobby.MapPreview; - preview.OnMouseDown = mi => LobbyUtils.SelectSpawnPoint(orderManager, preview, lobby.MapPreview, mi); - preview.SpawnOccupants = () => LobbyUtils.GetSpawnOccupants(orderManager.LobbyInfo, lobby.MapPreview); + preview.Preview = () => lobby.Map; + preview.OnMouseDown = mi => LobbyUtils.SelectSpawnPoint(orderManager, preview, lobby.Map, mi); + preview.SpawnOccupants = () => LobbyUtils.GetSpawnOccupants(orderManager.LobbyInfo, lobby.Map); var titleLabel = available.GetOrNull("MAP_TITLE"); if (titleLabel != null) { var font = Game.Renderer.Fonts[titleLabel.Font]; var title = new CachedTransform(m => WidgetUtils.TruncateText(m.Title, titleLabel.Bounds.Width, font)); - titleLabel.GetText = () => title.Update(lobby.MapPreview); + titleLabel.GetText = () => title.Update(lobby.Map); } var typeLabel = available.GetOrNull("MAP_TYPE"); if (typeLabel != null) - typeLabel.GetText = () => lobby.MapPreview.Type; + typeLabel.GetText = () => lobby.Map.Type; var authorLabel = available.GetOrNull("MAP_AUTHOR"); if (authorLabel != null) { var font = Game.Renderer.Fonts[authorLabel.Font]; var author = new CachedTransform( - m => WidgetUtils.TruncateText("Created by {0}".F(lobby.MapPreview.Author), authorLabel.Bounds.Width, font)); - authorLabel.GetText = () => author.Update(lobby.MapPreview); + m => WidgetUtils.TruncateText("Created by {0}".F(lobby.Map.Author), authorLabel.Bounds.Width, font)); + authorLabel.GetText = () => author.Update(lobby.Map); } } var invalid = widget.GetOrNull("MAP_INVALID"); if (invalid != null) { - invalid.IsVisible = () => lobby.MapPreview.Status == MapStatus.Available && lobby.Map != null && lobby.Map.InvalidCustomRules; + invalid.IsVisible = () => lobby.Map.Status == MapStatus.Available && lobby.Map.InvalidCustomRules; var preview = invalid.Get("MAP_PREVIEW"); - preview.Preview = () => lobby.MapPreview; - preview.OnMouseDown = mi => LobbyUtils.SelectSpawnPoint(orderManager, preview, lobby.MapPreview, mi); - preview.SpawnOccupants = () => LobbyUtils.GetSpawnOccupants(orderManager.LobbyInfo, lobby.MapPreview); + preview.Preview = () => lobby.Map; + preview.OnMouseDown = mi => LobbyUtils.SelectSpawnPoint(orderManager, preview, lobby.Map, mi); + preview.SpawnOccupants = () => LobbyUtils.GetSpawnOccupants(orderManager.LobbyInfo, lobby.Map); var title = invalid.GetOrNull("MAP_TITLE"); if (title != null) - title.GetText = () => lobby.MapPreview.Title; + title.GetText = () => lobby.Map.Title; var type = invalid.GetOrNull("MAP_TYPE"); if (type != null) - type.GetText = () => lobby.MapPreview.Type; + type.GetText = () => lobby.Map.Type; } var download = widget.GetOrNull("MAP_DOWNLOADABLE"); if (download != null) { - download.IsVisible = () => lobby.MapPreview.Status == MapStatus.DownloadAvailable; + download.IsVisible = () => lobby.Map.Status == MapStatus.DownloadAvailable; var preview = download.Get("MAP_PREVIEW"); - preview.Preview = () => lobby.MapPreview; - preview.OnMouseDown = mi => LobbyUtils.SelectSpawnPoint(orderManager, preview, lobby.MapPreview, mi); - preview.SpawnOccupants = () => LobbyUtils.GetSpawnOccupants(orderManager.LobbyInfo, lobby.MapPreview); + preview.Preview = () => lobby.Map; + preview.OnMouseDown = mi => LobbyUtils.SelectSpawnPoint(orderManager, preview, lobby.Map, mi); + preview.SpawnOccupants = () => LobbyUtils.GetSpawnOccupants(orderManager.LobbyInfo, lobby.Map); var title = download.GetOrNull("MAP_TITLE"); if (title != null) - title.GetText = () => lobby.MapPreview.Title; + title.GetText = () => lobby.Map.Title; var type = download.GetOrNull("MAP_TYPE"); if (type != null) - type.GetText = () => lobby.MapPreview.Type; + type.GetText = () => lobby.Map.Type; var author = download.GetOrNull("MAP_AUTHOR"); if (author != null) - author.GetText = () => "Created by {0}".F(lobby.MapPreview.Author); + author.GetText = () => "Created by {0}".F(lobby.Map.Author); var install = download.GetOrNull("MAP_INSTALL"); if (install != null) { - install.OnClick = () => lobby.MapPreview.Install(); + install.OnClick = () => lobby.Map.Install(); install.IsHighlighted = () => installHighlighted; } } @@ -107,72 +107,72 @@ namespace OpenRA.Mods.Common.Widgets.Logic var progress = widget.GetOrNull("MAP_PROGRESS"); if (progress != null) { - progress.IsVisible = () => lobby.MapPreview.Status != MapStatus.Available && - lobby.MapPreview.Status != MapStatus.DownloadAvailable; + progress.IsVisible = () => lobby.Map.Status != MapStatus.Available && + lobby.Map.Status != MapStatus.DownloadAvailable; var preview = progress.Get("MAP_PREVIEW"); - preview.Preview = () => lobby.MapPreview; - preview.OnMouseDown = mi => LobbyUtils.SelectSpawnPoint(orderManager, preview, lobby.MapPreview, mi); - preview.SpawnOccupants = () => LobbyUtils.GetSpawnOccupants(orderManager.LobbyInfo, lobby.MapPreview); + preview.Preview = () => lobby.Map; + preview.OnMouseDown = mi => LobbyUtils.SelectSpawnPoint(orderManager, preview, lobby.Map, mi); + preview.SpawnOccupants = () => LobbyUtils.GetSpawnOccupants(orderManager.LobbyInfo, lobby.Map); var title = progress.GetOrNull("MAP_TITLE"); if (title != null) - title.GetText = () => lobby.MapPreview.Title; + title.GetText = () => lobby.Map.Title; var type = progress.GetOrNull("MAP_TYPE"); if (type != null) - type.GetText = () => lobby.MapPreview.Type; + type.GetText = () => lobby.Map.Type; var statusSearching = progress.GetOrNull("MAP_STATUS_SEARCHING"); if (statusSearching != null) - statusSearching.IsVisible = () => lobby.MapPreview.Status == MapStatus.Searching; + statusSearching.IsVisible = () => lobby.Map.Status == MapStatus.Searching; var statusUnavailable = progress.GetOrNull("MAP_STATUS_UNAVAILABLE"); if (statusUnavailable != null) - statusUnavailable.IsVisible = () => lobby.MapPreview.Status == MapStatus.Unavailable; + statusUnavailable.IsVisible = () => lobby.Map.Status == MapStatus.Unavailable; var statusError = progress.GetOrNull("MAP_STATUS_ERROR"); if (statusError != null) - statusError.IsVisible = () => lobby.MapPreview.Status == MapStatus.DownloadError; + statusError.IsVisible = () => lobby.Map.Status == MapStatus.DownloadError; var statusDownloading = progress.GetOrNull("MAP_STATUS_DOWNLOADING"); if (statusDownloading != null) { - statusDownloading.IsVisible = () => lobby.MapPreview.Status == MapStatus.Downloading; + statusDownloading.IsVisible = () => lobby.Map.Status == MapStatus.Downloading; statusDownloading.GetText = () => { - if (lobby.MapPreview.DownloadBytes == 0) + if (lobby.Map.DownloadBytes == 0) return "Connecting..."; // Server does not provide the total file length - if (lobby.MapPreview.DownloadPercentage == 0) - return "Downloading {0} kB".F(lobby.MapPreview.DownloadBytes / 1024); + if (lobby.Map.DownloadPercentage == 0) + return "Downloading {0} kB".F(lobby.Map.DownloadBytes / 1024); - return "Downloading {0} kB ({1}%)".F(lobby.MapPreview.DownloadBytes / 1024, lobby.MapPreview.DownloadPercentage); + 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.MapPreview.Status == MapStatus.DownloadError || lobby.MapPreview.Status == MapStatus.Unavailable) && - lobby.MapPreview != MapCache.UnknownMap; + retry.IsVisible = () => (lobby.Map.Status == MapStatus.DownloadError || lobby.Map.Status == MapStatus.Unavailable) && + lobby.Map != MapCache.UnknownMap; retry.OnClick = () => { - if (lobby.MapPreview.Status == MapStatus.DownloadError) - lobby.MapPreview.Install(); - else if (lobby.MapPreview.Status == MapStatus.Unavailable) - modData.MapCache.QueryRemoteMapDetails(new[] { lobby.MapPreview.Uid }); + if (lobby.Map.Status == MapStatus.DownloadError) + lobby.Map.Install(); + else if (lobby.Map.Status == MapStatus.Unavailable) + modData.MapCache.QueryRemoteMapDetails(new[] { lobby.Map.Uid }); }; - retry.GetText = () => lobby.MapPreview.Status == MapStatus.DownloadError ? "Retry Install" : "Retry Search"; + retry.GetText = () => lobby.Map.Status == MapStatus.DownloadError ? "Retry Install" : "Retry Search"; } var progressbar = progress.GetOrNull("MAP_PROGRESSBAR"); if (progressbar != null) { - progressbar.IsIndeterminate = () => lobby.MapPreview.DownloadPercentage == 0; - progressbar.GetPercentage = () => lobby.MapPreview.DownloadPercentage; + progressbar.IsIndeterminate = () => lobby.Map.DownloadPercentage == 0; + progressbar.GetPercentage = () => lobby.Map.DownloadPercentage; progressbar.IsVisible = () => !retry.IsVisible(); } } diff --git a/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyUtils.cs b/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyUtils.cs index fa5a661060..4e8fcb9833 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyUtils.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyUtils.cs @@ -38,7 +38,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic } } - public static void ShowSlotDropDown(Ruleset rules, DropDownButtonWidget dropdown, Session.Slot slot, + public static void ShowSlotDropDown(LobbyLogic logic, DropDownButtonWidget dropdown, Session.Slot slot, Session.Client client, OrderManager orderManager) { var options = new Dictionary>() { { "Slot", new List() @@ -50,7 +50,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic var bots = new List(); if (slot.AllowBots) { - foreach (var b in rules.Actors["player"].TraitInfos().Select(t => t.Name)) + foreach (var b in logic.Map.Rules.Actors["player"].TraitInfos().Select(t => t.Name)) { var bot = b; var botController = orderManager.LobbyInfo.Clients.FirstOrDefault(c => c.IsAdmin); @@ -303,13 +303,13 @@ namespace OpenRA.Mods.Common.Widgets.Logic name.GetText = () => label; } - public static void SetupEditableSlotWidget(Widget parent, Session.Slot s, Session.Client c, OrderManager orderManager, Ruleset rules) + public static void SetupEditableSlotWidget(LobbyLogic logic, Widget parent, Session.Slot s, Session.Client c, OrderManager orderManager) { var slot = parent.Get("SLOT_OPTIONS"); slot.IsVisible = () => true; slot.IsDisabled = () => orderManager.LocalClient.IsReady; slot.GetText = () => c != null ? c.Name : s.Closed ? "Closed" : "Open"; - slot.OnMouseDown = _ => ShowSlotDropDown(rules, slot, s, c, orderManager); + slot.OnMouseDown = _ => ShowSlotDropDown(logic, slot, s, c, orderManager); // Ensure Name selector (if present) is hidden var name = parent.GetOrNull("NAME");