From d1a973458b0b83d835cde7bb9455efb9210743b3 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Wed, 22 Jun 2016 19:36:28 +0100 Subject: [PATCH] Add support for installing content from disk. --- OpenRA.Game/ModContent.cs | 7 ++ .../Installation/InstallFromDiscLogic.cs | 116 +++++++++++++++--- mods/modchooser/content.yaml | 32 ++++- 3 files changed, 130 insertions(+), 25 deletions(-) diff --git a/OpenRA.Game/ModContent.cs b/OpenRA.Game/ModContent.cs index 18bd87f655..2c772b6ecb 100644 --- a/OpenRA.Game/ModContent.cs +++ b/OpenRA.Game/ModContent.cs @@ -17,6 +17,7 @@ namespace OpenRA { public class ModContent : IGlobalModData { + public enum SourceType { Disc, Install } public class ModPackage { public readonly string Title; @@ -39,6 +40,12 @@ namespace OpenRA public class ModSource { + public readonly SourceType Type = SourceType.Disc; + + // Used to find installation locations for SourceType.Install + public readonly string RegistryKey; + public readonly string RegistryValue; + public readonly string Title; public readonly Dictionary IDFiles; diff --git a/OpenRA.Mods.Common/Widgets/Logic/Installation/InstallFromDiscLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Installation/InstallFromDiscLogic.cs index d9f6c365a4..e1c70fbbba 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/Installation/InstallFromDiscLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/Installation/InstallFromDiscLogic.cs @@ -47,6 +47,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic // List Panel readonly Widget listContainer; readonly ScrollPanelWidget listPanel; + readonly Widget listHeaderTemplate; readonly LabelWidget listTemplate; readonly LabelWidget listLabel; @@ -84,6 +85,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic listContainer.IsVisible = () => visible == Mode.List; listPanel = listContainer.Get("LIST_PANEL"); + listHeaderTemplate = listPanel.Get("LIST_HEADER_TEMPLATE"); listTemplate = listPanel.Get("LIST_TEMPLATE"); listPanel.RemoveChildren(); @@ -108,38 +110,55 @@ namespace OpenRA.Mods.Common.Widgets.Logic { message = "Searching for " + kv.Value.Title; - foreach (var volume in volumes) + var path = FindSourcePath(kv.Value, volumes); + if (path != null) { - if (PathIsDiscMount(volume, kv.Value)) + var packages = content.Packages.Values + .Where(p => p.Sources.Contains(kv.Key) && !p.IsInstalled()) + .Select(p => p.Title); + + // Ignore disc if content is already installed + if (packages.Any()) { - var packages = content.Packages.Values - .Where(p => p.Sources.Contains(kv.Key) && !p.IsInstalled()) - .Select(p => p.Title); - - // Ignore disc if content is already installed - if (packages.Any()) + Game.RunAfterTick(() => { - Game.RunAfterTick(() => - { - ShowList(kv.Value.Title, "The following content packages will be installed:", packages); - ShowContinueCancel(() => InstallFromDisc(volume, kv.Value)); - }); + ShowList(kv.Value.Title, "The following content packages will be installed:", packages); + ShowContinueCancel(() => InstallFromDisc(path, kv.Value)); + }); - return; - } + return; } } } - var discTitles = content.Packages.Values + var sources = content.Packages.Values .Where(p => !p.IsInstalled()) .SelectMany(p => p.Sources) - .Select(d => content.Sources[d].Title) + .Select(d => content.Sources[d]); + + var discs = sources + .Where(s => s.Type == ModContent.SourceType.Disc) + .Select(s => s.Title) .Distinct(); + var options = new Dictionary>() + { + { "Game Discs", discs }, + }; + + if (Platform.CurrentPlatform == PlatformType.Windows) + { + var installations = sources + .Where(s => s.Type == ModContent.SourceType.Install) + .Select(s => s.Title) + .Distinct(); + + options.Add("Digital Installs", installations); + } + Game.RunAfterTick(() => { - ShowList("Disc Content Not Found", "Please insert or mount one of the following discs and try again", discTitles); + ShowList("Game Content Not Found", "Please insert or install one of the following content sources:", options); ShowBackRetry(DetectContentDisks); }); }).Start(); @@ -351,7 +370,32 @@ namespace OpenRA.Mods.Common.Widgets.Logic } } - bool PathIsDiscMount(string path, ModContent.ModSource source) + string FindSourcePath(ModContent.ModSource source, IEnumerable volumes) + { + if (source.Type == ModContent.SourceType.Install) + { + if (source.RegistryKey == null) + return null; + + if (Platform.CurrentPlatform != PlatformType.Windows) + return null; + + var path = Microsoft.Win32.Registry.GetValue(source.RegistryKey, source.RegistryValue, null) as string; + if (path == null) + return null; + + return IsValidSourcePath(path, source) ? path : null; + } + + if (source.Type == ModContent.SourceType.Disc) + foreach (var volume in volumes) + if (IsValidSourcePath(volume, source)) + return volume; + + return null; + } + + bool IsValidSourcePath(string path, ModContent.ModSource source) { try { @@ -427,6 +471,40 @@ namespace OpenRA.Mods.Common.Widgets.Logic panel.Bounds.Height = listContainer.Bounds.Height; } + void ShowList(string title, string message, Dictionary> groups) + { + visible = Mode.List; + titleLabel.Text = title; + listLabel.Text = message; + + listPanel.RemoveChildren(); + + foreach (var kv in groups) + { + if (kv.Value.Any()) + { + var groupTitle = kv.Key; + var headerWidget = listHeaderTemplate.Clone(); + var headerTitleWidget = headerWidget.Get("LABEL"); + headerTitleWidget.GetText = () => groupTitle; + listPanel.AddChild(headerWidget); + } + + foreach (var i in kv.Value) + { + var item = i; + var labelWidget = (LabelWidget)listTemplate.Clone(); + labelWidget.GetText = () => item; + listPanel.AddChild(labelWidget); + } + } + + primaryButton.Bounds.Y += listContainer.Bounds.Height - panel.Bounds.Height; + secondaryButton.Bounds.Y += listContainer.Bounds.Height - panel.Bounds.Height; + panel.Bounds.Y -= (listContainer.Bounds.Height - panel.Bounds.Height) / 2; + panel.Bounds.Height = listContainer.Bounds.Height; + } + void ShowContinueCancel(Action continueAction) { primaryButton.OnClick = continueAction; diff --git a/mods/modchooser/content.yaml b/mods/modchooser/content.yaml index 7c35ad2e3a..61cf774fb5 100644 --- a/mods/modchooser/content.yaml +++ b/mods/modchooser/content.yaml @@ -3,7 +3,7 @@ Background@CONTENT_PANEL: X: (WINDOW_RIGHT - WIDTH) / 2 Y: (WINDOW_BOTTOM - HEIGHT) / 2 Width: 500 - Height: 268 + Height: 290 Background: panel-bg Children: Background@RULE: @@ -29,7 +29,7 @@ Background@CONTENT_PANEL: X: 30 Y: 84 Width: PARENT_RIGHT - 60 - Height: 115 + Height: 137 TopBottomSpacing: 4 ItemSpacing: 2 BorderWidth: 2 @@ -89,9 +89,9 @@ Background@CONTENT_PANEL: X: 30 Y: PARENT_BOTTOM - 52 Background: button-highlighted - Width: 110 + Width: 200 Height: 32 - Text: Detect Disc + Text: Detect Disc or Installation Font: Bold Button@BACK_BUTTON: X: PARENT_RIGHT - 140 @@ -230,7 +230,7 @@ Background@DISC_INSTALL_PANEL: Align: Center Container@LIST: Width: PARENT_RIGHT - Height: 268 + Height: 338 Visible: false Children: Label@LIST_MESSAGE: @@ -242,11 +242,31 @@ Background@DISC_INSTALL_PANEL: X: 30 Y: 99 Width: PARENT_RIGHT - 60 - Height: 100 + Height: 170 TopBottomSpacing: 4 ItemSpacing: 2 BorderWidth: 2 Children: + Container@LIST_HEADER_TEMPLATE: + X: 6 + Width: PARENT_RIGHT - 12 - 24 + Height: 14 + Children: + Background@TOP_RULE: + Width: PARENT_RIGHT + Height: 1 + Background: panel-rule + Label@LABEL: + Y: 3 + Width: PARENT_RIGHT + Height: 10 + Font: TinyBold + Align: Center + Background@BOTTOM_RULE: + Y: 16 + Width: PARENT_RIGHT + Height: 1 + Background: panel-rule Label@LIST_TEMPLATE: X: 6 Width: PARENT_RIGHT - 16