From 8b5592e1dd6d894b96ed148f726db3db9725c20b Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Fri, 5 Feb 2016 22:46:12 +0000 Subject: [PATCH] Reduce jank in the mission chooser. --- .../Widgets/Logic/MissionBrowserLogic.cs | 65 ++++++++++--------- 1 file changed, 36 insertions(+), 29 deletions(-) diff --git a/OpenRA.Mods.Common/Widgets/Logic/MissionBrowserLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/MissionBrowserLogic.cs index 34a19ea172..a7c3f78db4 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/MissionBrowserLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/MissionBrowserLogic.cs @@ -14,6 +14,7 @@ using System.IO; using System.Linq; using System.Threading; using OpenRA.Graphics; +using OpenRA.Primitives; using OpenRA.Widgets; namespace OpenRA.Mods.Common.Widgets.Logic @@ -38,6 +39,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic readonly ScrollPanelWidget missionList; readonly ScrollItemWidget headerTemplate; readonly ScrollItemWidget template; + readonly Cache mapCache = new Cache(p => new Map(p.Path)); MapPreview selectedMapPreview; Map selectedMap; @@ -90,7 +92,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic stopInfoVideoButton.IsVisible = () => playingVideo == PlayingVideo.Info; stopInfoVideoButton.OnClick = () => StopVideo(videoPlayer); - var allMaps = new List(); + var allPreviews = new List(); missionList.RemoveChildren(); // Add a group for each campaign @@ -103,29 +105,34 @@ namespace OpenRA.Mods.Common.Widgets.Logic { var missionMapPaths = kv.Value.Nodes.Select(n => Path.GetFullPath(n.Key)).ToList(); - var maps = modData.MapCache + var previews = modData.MapCache .Where(p => p.Status == MapStatus.Available && missionMapPaths.Contains(Path.GetFullPath(p.Path))) - .Select(p => new Map(p.Path)) - .OrderBy(m => missionMapPaths.IndexOf(Path.GetFullPath(m.Path))); + .OrderBy(p => missionMapPaths.IndexOf(Path.GetFullPath(p.Path))); - CreateMissionGroup(kv.Key, maps); - allMaps.AddRange(maps); + CreateMissionGroup(kv.Key, previews); + allPreviews.AddRange(previews); } } // Add an additional group for loose missions - var looseMissions = modData.MapCache - .Where(p => p.Status == MapStatus.Available && p.Visibility.HasFlag(MapVisibility.MissionSelector) && !allMaps.Any(m => m.Uid == p.Uid)) - .Select(p => new Map(p.Path)); + var loosePreviews = modData.MapCache + .Where(p => p.Status == MapStatus.Available && p.Visibility.HasFlag(MapVisibility.MissionSelector) && !allPreviews.Any(a => a.Uid == p.Uid)); - if (looseMissions.Any()) + if (loosePreviews.Any()) { - CreateMissionGroup("Missions", looseMissions); - allMaps.AddRange(looseMissions); + CreateMissionGroup("Missions", loosePreviews); + allPreviews.AddRange(loosePreviews); } - if (allMaps.Any()) - SelectMap(allMaps.First()); + if (allPreviews.Any()) + SelectMap(allPreviews.First()); + + // Preload map and preview data to reduce jank + new Thread(() => + { + foreach (var p in allPreviews) + modData.MapCache[mapCache[p].Uid].GetMinimap(); + }).Start(); var startButton = widget.Get("STARTGAME_BUTTON"); startButton.OnClick = StartMissionClicked; @@ -140,39 +147,39 @@ namespace OpenRA.Mods.Common.Widgets.Logic }; } - void CreateMissionGroup(string title, IEnumerable maps) + void CreateMissionGroup(string title, IEnumerable previews) { var header = ScrollItemWidget.Setup(headerTemplate, () => true, () => { }); header.Get("LABEL").GetText = () => title; missionList.AddChild(header); - foreach (var m in maps) + foreach (var p in previews) { - var map = m; + var preview = p; var item = ScrollItemWidget.Setup(template, - () => selectedMapPreview != null && selectedMapPreview.Uid == map.Uid, - () => SelectMap(map), + () => selectedMapPreview != null && selectedMapPreview.Uid == preview.Uid, + () => SelectMap(preview), StartMissionClicked); - item.Get("TITLE").GetText = () => map.Title; + item.Get("TITLE").GetText = () => preview.Title; missionList.AddChild(item); } } - void SelectMap(Map map) + void SelectMap(MapPreview preview) { - selectedMap = map; - selectedMapPreview = Game.ModData.MapCache[map.Uid]; + selectedMap = mapCache[preview]; + selectedMapPreview = preview; // Cache the rules on a background thread to avoid jank new Thread(() => selectedMap.PreloadRules()).Start(); - var briefingVideo = map.Videos.Briefing; + var briefingVideo = selectedMap.Videos.Briefing; var briefingVideoVisible = briefingVideo != null; var briefingVideoDisabled = !(briefingVideoVisible && Game.ModData.ModFiles.Exists(briefingVideo)); - var infoVideo = map.Videos.BackgroundInfo; + var infoVideo = selectedMap.Videos.BackgroundInfo; var infoVideoVisible = infoVideo != null; var infoVideoDisabled = !(infoVideoVisible && Game.ModData.ModFiles.Exists(infoVideo)); @@ -184,7 +191,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic startInfoVideoButton.IsDisabled = () => infoVideoDisabled || playingVideo != PlayingVideo.None; startInfoVideoButton.OnClick = () => PlayVideo(videoPlayer, infoVideo, PlayingVideo.Info, () => StopVideo(videoPlayer)); - var text = map.Description != null ? map.Description.Replace("\\n", "\n") : ""; + var text = selectedMap.Description != null ? selectedMap.Description.Replace("\\n", "\n") : ""; text = WidgetUtils.WrapText(text, description.Bounds.Width, descriptionFont); description.Text = text; description.Bounds.Height = descriptionFont.Measure(text).Y; @@ -193,13 +200,13 @@ namespace OpenRA.Mods.Common.Widgets.Logic if (difficultyButton != null) { - difficultyButton.IsDisabled = () => !map.Options.Difficulties.Any(); + difficultyButton.IsDisabled = () => !selectedMap.Options.Difficulties.Any(); - difficulty = map.Options.Difficulties.FirstOrDefault(); + difficulty = selectedMap.Options.Difficulties.FirstOrDefault(); difficultyButton.GetText = () => difficulty ?? "Normal"; difficultyButton.OnMouseDown = _ => { - var options = map.Options.Difficulties.Select(d => new DropDownOption + var options = selectedMap.Options.Difficulties.Select(d => new DropDownOption { Title = d, IsSelected = () => difficulty == d,