From 35eb2460801eb2b37955c3dcdcf0233971af742f Mon Sep 17 00:00:00 2001 From: IceReaper Date: Sun, 6 Nov 2022 19:33:01 +0100 Subject: [PATCH] Replaced hardcoded SourceType with custom defined ISourceResolver. --- OpenRA.Mods.Common/Installer/Availability.cs | 20 ++++ .../Installer/ISourceResolver.cs | 19 ++++ .../SourceActions/CopySourceAction.cs | 6 +- .../SourceActions/ExtractBlastSourceAction.cs | 6 +- .../SourceActions/ExtractIscabSourceAction.cs | 2 +- .../SourceActions/ExtractMscabSourceAction.cs | 2 +- .../SourceActions/ExtractRawSourceAction.cs | 6 +- .../SourceResolvers/DiscSourceResolver.cs | 60 +++++++++++ ...RegistryDirectoryFromFileSourceResolver.cs | 50 +++++++++ .../RegistryDirectorySourceResolver.cs | 47 ++++++++ OpenRA.Mods.Common/ModContent.cs | 9 +- ...DiscLogic.cs => InstallFromSourceLogic.cs} | 101 +++++++----------- .../Logic/Installation/ModContentLogic.cs | 20 ++-- ...gic.cs => ModContentSourceTooltipLogic.cs} | 28 ++--- mods/cnc/installer/covertops.yaml | 1 + mods/cnc/installer/firstdecade.yaml | 1 + mods/cnc/installer/gdi95.yaml | 1 + mods/cnc/installer/nod95.yaml | 1 + mods/common/languages/en.ftl | 16 +-- mods/d2k/installer/d2k-a.yaml | 1 + mods/d2k/installer/d2k-b.yaml | 1 + mods/d2k/installer/d2k-c.yaml | 1 + mods/d2k/installer/d2k-d.yaml | 1 + mods/d2k/installer/d2k-e.yaml | 1 + mods/modcontent/content.yaml | 20 ++-- mods/ra/installer/aftermath.yaml | 1 + mods/ra/installer/allies95.yaml | 1 + mods/ra/installer/cnc95.yaml | 1 + mods/ra/installer/counterstrike.yaml | 1 + mods/ra/installer/firstdecade.yaml | 1 + mods/ra/installer/soviet95.yaml | 1 + mods/ts/installer/firestorm.yaml | 1 + mods/ts/installer/firstdecade.yaml | 1 + mods/ts/installer/tibsun.yaml | 1 + 34 files changed, 313 insertions(+), 117 deletions(-) create mode 100644 OpenRA.Mods.Common/Installer/Availability.cs create mode 100644 OpenRA.Mods.Common/Installer/ISourceResolver.cs create mode 100644 OpenRA.Mods.Common/Installer/SourceResolvers/DiscSourceResolver.cs create mode 100644 OpenRA.Mods.Common/Installer/SourceResolvers/RegistryDirectoryFromFileSourceResolver.cs create mode 100644 OpenRA.Mods.Common/Installer/SourceResolvers/RegistryDirectorySourceResolver.cs rename OpenRA.Mods.Common/Widgets/Logic/Installation/{InstallFromDiscLogic.cs => InstallFromSourceLogic.cs} (79%) rename OpenRA.Mods.Common/Widgets/Logic/Installation/{ModContentDiscTooltipLogic.cs => ModContentSourceTooltipLogic.cs} (58%) diff --git a/OpenRA.Mods.Common/Installer/Availability.cs b/OpenRA.Mods.Common/Installer/Availability.cs new file mode 100644 index 0000000000..dea61ac00a --- /dev/null +++ b/OpenRA.Mods.Common/Installer/Availability.cs @@ -0,0 +1,20 @@ +#region Copyright & License Information +/* + * Copyright 2007-2022 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, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +namespace OpenRA.Mods.Common.Installer +{ + public enum Availability + { + Unavailable, + GameSource, + DigitalInstall + } +} diff --git a/OpenRA.Mods.Common/Installer/ISourceResolver.cs b/OpenRA.Mods.Common/Installer/ISourceResolver.cs new file mode 100644 index 0000000000..f77c0ac68b --- /dev/null +++ b/OpenRA.Mods.Common/Installer/ISourceResolver.cs @@ -0,0 +1,19 @@ +#region Copyright & License Information +/* + * Copyright 2007-2022 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, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +namespace OpenRA.Mods.Common.Installer +{ + public interface ISourceResolver + { + string FindSourcePath(ModContent.ModSource modSource); + Availability GetAvailability(); + } +} diff --git a/OpenRA.Mods.Common/Installer/SourceActions/CopySourceAction.cs b/OpenRA.Mods.Common/Installer/SourceActions/CopySourceAction.cs index 9150fb5328..b5727ced6f 100644 --- a/OpenRA.Mods.Common/Installer/SourceActions/CopySourceAction.cs +++ b/OpenRA.Mods.Common/Installer/SourceActions/CopySourceAction.cs @@ -43,10 +43,10 @@ namespace OpenRA.Mods.Common.Installer var length = source.Length; Action onProgress = null; - if (length < InstallFromDiscLogic.ShowPercentageThreshold) - updateMessage(modData.Translation.GetString(InstallFromDiscLogic.CopyingFilename, Translation.Arguments("filename", displayFilename))); + if (length < InstallFromSourceLogic.ShowPercentageThreshold) + updateMessage(modData.Translation.GetString(InstallFromSourceLogic.CopyingFilename, Translation.Arguments("filename", displayFilename))); else - onProgress = b => updateMessage(modData.Translation.GetString(InstallFromDiscLogic.CopyingFilenameProgress, Translation.Arguments("filename", displayFilename, "progress", 100 * b / length))); + onProgress = b => updateMessage(modData.Translation.GetString(InstallFromSourceLogic.CopyingFilenameProgress, Translation.Arguments("filename", displayFilename, "progress", 100 * b / length))); InstallerUtils.CopyStream(source, target, length, onProgress); } diff --git a/OpenRA.Mods.Common/Installer/SourceActions/ExtractBlastSourceAction.cs b/OpenRA.Mods.Common/Installer/SourceActions/ExtractBlastSourceAction.cs index 49504a8ed7..c5a5f0d5e8 100644 --- a/OpenRA.Mods.Common/Installer/SourceActions/ExtractBlastSourceAction.cs +++ b/OpenRA.Mods.Common/Installer/SourceActions/ExtractBlastSourceAction.cs @@ -60,10 +60,10 @@ namespace OpenRA.Mods.Common.Installer var displayFilename = Path.GetFileName(Path.GetFileName(targetPath)); Action onProgress = null; - if (length < InstallFromDiscLogic.ShowPercentageThreshold) - updateMessage(modData.Translation.GetString(InstallFromDiscLogic.Extracing, Translation.Arguments("filename", displayFilename))); + if (length < InstallFromSourceLogic.ShowPercentageThreshold) + updateMessage(modData.Translation.GetString(InstallFromSourceLogic.Extracing, Translation.Arguments("filename", displayFilename))); else - onProgress = b => updateMessage(modData.Translation.GetString(InstallFromDiscLogic.ExtracingProgress, Translation.Arguments("filename", displayFilename, "progress", 100 * b / length))); + onProgress = b => updateMessage(modData.Translation.GetString(InstallFromSourceLogic.ExtracingProgress, Translation.Arguments("filename", displayFilename, "progress", 100 * b / length))); using (var target = File.OpenWrite(targetPath)) { diff --git a/OpenRA.Mods.Common/Installer/SourceActions/ExtractIscabSourceAction.cs b/OpenRA.Mods.Common/Installer/SourceActions/ExtractIscabSourceAction.cs index c1dc28906f..f409c2cd05 100644 --- a/OpenRA.Mods.Common/Installer/SourceActions/ExtractIscabSourceAction.cs +++ b/OpenRA.Mods.Common/Installer/SourceActions/ExtractIscabSourceAction.cs @@ -63,7 +63,7 @@ namespace OpenRA.Mods.Common.Installer { Log.Write("install", $"Extracting {sourcePath} -> {targetPath}"); var displayFilename = Path.GetFileName(Path.GetFileName(targetPath)); - Action onProgress = percent => updateMessage(modData.Translation.GetString(InstallFromDiscLogic.ExtracingProgress, Translation.Arguments("filename", displayFilename, "progress", percent))); + Action onProgress = percent => updateMessage(modData.Translation.GetString(InstallFromSourceLogic.ExtracingProgress, Translation.Arguments("filename", displayFilename, "progress", percent))); reader.ExtractFile(node.Value.Value, target, onProgress); } } diff --git a/OpenRA.Mods.Common/Installer/SourceActions/ExtractMscabSourceAction.cs b/OpenRA.Mods.Common/Installer/SourceActions/ExtractMscabSourceAction.cs index 9a8fb1feed..b4cdf04047 100644 --- a/OpenRA.Mods.Common/Installer/SourceActions/ExtractMscabSourceAction.cs +++ b/OpenRA.Mods.Common/Installer/SourceActions/ExtractMscabSourceAction.cs @@ -44,7 +44,7 @@ namespace OpenRA.Mods.Common.Installer { Log.Write("install", $"Extracting {sourcePath} -> {targetPath}"); var displayFilename = Path.GetFileName(Path.GetFileName(targetPath)); - Action onProgress = percent => updateMessage(modData.Translation.GetString(InstallFromDiscLogic.ExtracingProgress, Translation.Arguments("filename", displayFilename, "progress", percent))); + Action onProgress = percent => updateMessage(modData.Translation.GetString(InstallFromSourceLogic.ExtracingProgress, Translation.Arguments("filename", displayFilename, "progress", percent))); reader.ExtractFile(node.Value.Value, target, onProgress); } } diff --git a/OpenRA.Mods.Common/Installer/SourceActions/ExtractRawSourceAction.cs b/OpenRA.Mods.Common/Installer/SourceActions/ExtractRawSourceAction.cs index 3b1dc6f66e..c319e7d2fc 100644 --- a/OpenRA.Mods.Common/Installer/SourceActions/ExtractRawSourceAction.cs +++ b/OpenRA.Mods.Common/Installer/SourceActions/ExtractRawSourceAction.cs @@ -59,10 +59,10 @@ namespace OpenRA.Mods.Common.Installer var displayFilename = Path.GetFileName(Path.GetFileName(targetPath)); Action onProgress = null; - if (length < InstallFromDiscLogic.ShowPercentageThreshold) - updateMessage(modData.Translation.GetString(InstallFromDiscLogic.Extracing, Translation.Arguments("filename", displayFilename))); + if (length < InstallFromSourceLogic.ShowPercentageThreshold) + updateMessage(modData.Translation.GetString(InstallFromSourceLogic.Extracing, Translation.Arguments("filename", displayFilename))); else - onProgress = b => updateMessage(modData.Translation.GetString(InstallFromDiscLogic.ExtracingProgress, Translation.Arguments("filename", displayFilename, "progress", 100 * b / length))); + onProgress = b => updateMessage(modData.Translation.GetString(InstallFromSourceLogic.ExtracingProgress, Translation.Arguments("filename", displayFilename, "progress", 100 * b / length))); using (var target = File.OpenWrite(targetPath)) { diff --git a/OpenRA.Mods.Common/Installer/SourceResolvers/DiscSourceResolver.cs b/OpenRA.Mods.Common/Installer/SourceResolvers/DiscSourceResolver.cs new file mode 100644 index 0000000000..93f4572fc2 --- /dev/null +++ b/OpenRA.Mods.Common/Installer/SourceResolvers/DiscSourceResolver.cs @@ -0,0 +1,60 @@ +#region Copyright & License Information +/* + * Copyright 2007-2022 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, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System; +using System.IO; +using System.Linq; + +namespace OpenRA.Mods.Common.Installer +{ + public class DiscSourceResolver : ISourceResolver + { + public string FindSourcePath(ModContent.ModSource source) + { + var volumes = DriveInfo.GetDrives() + .Where(d => + { + if (d.DriveType == DriveType.CDRom && d.IsReady) + return true; + + // HACK: the "TFD" DVD is detected as a fixed udf-formatted drive on OSX + if (d.DriveType == DriveType.Fixed && d.DriveFormat == "udf") + return true; + + return false; + }) + .Select(v => v.RootDirectory.FullName); + + if (Platform.CurrentPlatform == PlatformType.Linux) + { + // Outside of Gnome, most mounting tools on Linux don't set DriveType.CDRom + // so provide a fallback by allowing users to manually mount images on known paths + volumes = volumes.Concat(new[] + { + "/media/openra", + "/media/" + Environment.UserName + "/openra", + "/mnt/openra" + }); + } + + foreach (var volume in volumes) + if (InstallerUtils.IsValidSourcePath(volume, source)) + return volume; + + return null; + } + + public Availability GetAvailability() + { + return Availability.GameSource; + } + } +} diff --git a/OpenRA.Mods.Common/Installer/SourceResolvers/RegistryDirectoryFromFileSourceResolver.cs b/OpenRA.Mods.Common/Installer/SourceResolvers/RegistryDirectoryFromFileSourceResolver.cs new file mode 100644 index 0000000000..13f5221e58 --- /dev/null +++ b/OpenRA.Mods.Common/Installer/SourceResolvers/RegistryDirectoryFromFileSourceResolver.cs @@ -0,0 +1,50 @@ +#region Copyright & License Information +/* + * Copyright 2007-2022 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, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.IO; +using System.Runtime.InteropServices; + +namespace OpenRA.Mods.Common.Installer +{ + public class RegistryDirectoryFromFileSourceResolver : ISourceResolver + { + public string FindSourcePath(ModContent.ModSource source) + { + if (source.RegistryKey == null) + return null; + + if (Platform.CurrentPlatform != PlatformType.Windows) + return null; + + // We need an extra check for the platform here to silence a warning when the registry is accessed + // TODO: Remove this once our platform checks use the same method + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + return null; + + foreach (var prefix in source.RegistryPrefixes) + { + if (!(Microsoft.Win32.Registry.GetValue(prefix + source.RegistryKey, source.RegistryValue, null) is string path)) + continue; + + path = Path.GetDirectoryName(path); + + return InstallerUtils.IsValidSourcePath(path, source) ? path : null; + } + + return null; + } + + public Availability GetAvailability() + { + return Platform.CurrentPlatform != PlatformType.Windows ? Availability.DigitalInstall : Availability.Unavailable; + } + } +} diff --git a/OpenRA.Mods.Common/Installer/SourceResolvers/RegistryDirectorySourceResolver.cs b/OpenRA.Mods.Common/Installer/SourceResolvers/RegistryDirectorySourceResolver.cs new file mode 100644 index 0000000000..66852062e2 --- /dev/null +++ b/OpenRA.Mods.Common/Installer/SourceResolvers/RegistryDirectorySourceResolver.cs @@ -0,0 +1,47 @@ +#region Copyright & License Information +/* + * Copyright 2007-2022 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, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Runtime.InteropServices; + +namespace OpenRA.Mods.Common.Installer +{ + public class RegistryDirectorySourceResolver : ISourceResolver + { + public string FindSourcePath(ModContent.ModSource source) + { + if (source.RegistryKey == null) + return null; + + if (Platform.CurrentPlatform != PlatformType.Windows) + return null; + + // We need an extra check for the platform here to silence a warning when the registry is accessed + // TODO: Remove this once our platform checks use the same method + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + return null; + + foreach (var prefix in source.RegistryPrefixes) + { + if (!(Microsoft.Win32.Registry.GetValue(prefix + source.RegistryKey, source.RegistryValue, null) is string path)) + continue; + + return InstallerUtils.IsValidSourcePath(path, source) ? path : null; + } + + return null; + } + + public Availability GetAvailability() + { + return Platform.CurrentPlatform != PlatformType.Windows ? Availability.DigitalInstall : Availability.Unavailable; + } + } +} diff --git a/OpenRA.Mods.Common/ModContent.cs b/OpenRA.Mods.Common/ModContent.cs index 12d441045f..dd2d02c9a3 100644 --- a/OpenRA.Mods.Common/ModContent.cs +++ b/OpenRA.Mods.Common/ModContent.cs @@ -18,7 +18,6 @@ namespace OpenRA { public class ModContent : IGlobalModData { - public enum SourceType { Disc, RegistryDirectory, RegistryDirectoryFromFile } public class ModPackage { public readonly string Title; @@ -42,7 +41,9 @@ namespace OpenRA public class ModSource { public readonly ObjectCreator ObjectCreator; - public readonly SourceType Type = SourceType.Disc; + + [FieldLoader.Ignore] + public readonly MiniYaml Type; // Used to find installation locations for SourceType.Install public readonly string[] RegistryPrefixes = { string.Empty }; @@ -62,6 +63,10 @@ namespace OpenRA ObjectCreator = objectCreator; Title = yaml.Value; + var type = yaml.Nodes.FirstOrDefault(n => n.Key == "Type"); + if (type != null) + Type = type.Value; + var idFiles = yaml.Nodes.FirstOrDefault(n => n.Key == "IDFiles"); if (idFiles != null) IDFiles = idFiles.Value; diff --git a/OpenRA.Mods.Common/Widgets/Logic/Installation/InstallFromDiscLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Installation/InstallFromSourceLogic.cs similarity index 79% rename from OpenRA.Mods.Common/Widgets/Logic/Installation/InstallFromDiscLogic.cs rename to OpenRA.Mods.Common/Widgets/Logic/Installation/InstallFromSourceLogic.cs index 7e025620b8..c12245a2c4 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/Installation/InstallFromDiscLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/Installation/InstallFromSourceLogic.cs @@ -19,7 +19,7 @@ using OpenRA.Widgets; namespace OpenRA.Mods.Common.Widgets.Logic { - public class InstallFromDiscLogic : ChromeLogic + public class InstallFromSourceLogic : ChromeLogic { // Hide percentage indicators for files smaller than 25 MB public const int ShowPercentageThreshold = 26214400; @@ -54,19 +54,19 @@ namespace OpenRA.Mods.Common.Widgets.Logic Mode visible = Mode.Progress; [TranslationReference] - static readonly string DetectingDrives = "detecting-drives"; + static readonly string DetectingSources = "detecting-sources"; [TranslationReference] - static readonly string CheckingDiscs = "checking-discs"; + static readonly string CheckingSources = "checking-sources"; [TranslationReference("title")] - static readonly string SearchingDiscFor = "searching-disc-for"; + static readonly string SearchingSourceFor = "searching-source-for"; [TranslationReference] static readonly string ContentPackageInstallation = "content-package-installation"; [TranslationReference] - static readonly string GameDiscs = "game-discs"; + static readonly string GameSources = "game-sources"; [TranslationReference] static readonly string DigitalInstalls = "digital-installs"; @@ -111,7 +111,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic static readonly string Back = "back"; [ObjectCreator.UseCtor] - public InstallFromDiscLogic(Widget widget, ModData modData, ModContent content, Dictionary sources) + public InstallFromSourceLogic(Widget widget, ModData modData, ModContent content, Dictionary sources) { this.modData = modData; this.content = content; @@ -119,7 +119,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic Log.AddChannel("install", "install.log"); - panel = widget.Get("DISC_INSTALL_PANEL"); + panel = widget.Get("SOURCE_INSTALL_PANEL"); titleLabel = panel.Get("TITLE"); @@ -149,65 +149,39 @@ namespace OpenRA.Mods.Common.Widgets.Logic listLabel = listContainer.Get("LIST_MESSAGE"); - DetectContentDisks(); + DetectContentSources(); } - static bool IsValidDrive(DriveInfo d) + void DetectContentSources() { - if (d.DriveType == DriveType.CDRom && d.IsReady) - return true; - - // HACK: the "TFD" DVD is detected as a fixed udf-formatted drive on OSX - if (d.DriveType == DriveType.Fixed && d.DriveFormat == "udf") - return true; - - return false; - } - - void DetectContentDisks() - { - var message = modData.Translation.GetString(DetectingDrives); - ShowProgressbar(modData.Translation.GetString(CheckingDiscs), () => message); - ShowBackRetry(DetectContentDisks); + var message = modData.Translation.GetString(DetectingSources); + ShowProgressbar(modData.Translation.GetString(CheckingSources), () => message); + ShowBackRetry(DetectContentSources); new Task(() => { - var volumes = DriveInfo.GetDrives() - .Where(IsValidDrive) - .Select(v => v.RootDirectory.FullName); - - if (Platform.CurrentPlatform == PlatformType.Linux) - { - // Outside of Gnome, most mounting tools on Linux don't set DriveType.CDRom - // so provide a fallback by allowing users to manually mount images on known paths - volumes = volumes.Concat(new[] - { - "/media/openra", - "/media/" + Environment.UserName + "/openra", - "/mnt/openra" - }); - } - foreach (var kv in sources) { - message = modData.Translation.GetString(SearchingDiscFor, Translation.Arguments("title", kv.Value.Title)); + message = modData.Translation.GetString(SearchingSourceFor, Translation.Arguments("title", kv.Value.Title)); - var path = FindSourcePath(kv.Value, volumes); + var sourceResolver = kv.Value.ObjectCreator.CreateObject($"{kv.Value.Type.Value}SourceResolver"); + + var path = sourceResolver.FindSourcePath(kv.Value); if (path != null) { - Log.Write("install", $"Using installer `{kv.Key}: {kv.Value.Title}` of type `{kv.Value.Type}`:"); + Log.Write("install", $"Using installer `{kv.Key}: {kv.Value.Title}` of type `{kv.Value.Type.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 + // Ignore source if content is already installed if (packages.Any()) { Game.RunAfterTick(() => { ShowList(kv.Value.Title, modData.Translation.GetString(ContentPackageInstallation), packages); - ShowContinueCancel(() => InstallFromDisc(path, kv.Value)); + ShowContinueCancel(() => InstallFromSource(path, kv.Value)); }); return; @@ -220,35 +194,38 @@ namespace OpenRA.Mods.Common.Widgets.Logic .SelectMany(p => p.Sources) .Select(d => sources[d]); - var discs = missingSources - .Where(s => s.Type == ModContent.SourceType.Disc) - .Select(s => s.Title) - .Distinct(); + var gameSources = new HashSet(); + var digitalInstalls = new HashSet(); - var options = new Dictionary>() + foreach (var source in missingSources) { - { modData.Translation.GetString(GameDiscs), discs }, - }; + var sourceResolver = source.ObjectCreator.CreateObject($"{source.Type.Value}SourceResolver"); - if (Platform.CurrentPlatform == PlatformType.Windows) - { - var installations = missingSources - .Where(s => s.Type == ModContent.SourceType.RegistryDirectory || s.Type == ModContent.SourceType.RegistryDirectoryFromFile) - .Select(s => s.Title) - .Distinct(); + var availability = sourceResolver.GetAvailability(); - options.Add(modData.Translation.GetString(DigitalInstalls), installations); + if (availability == Availability.GameSource) + gameSources.Add(source.Title); + else if (availability == Availability.DigitalInstall) + digitalInstalls.Add(source.Title); } + var options = new Dictionary>(); + + if (gameSources.Any()) + options.Add(modData.Translation.GetString(GameSources), gameSources); + + if (digitalInstalls.Any()) + options.Add(modData.Translation.GetString(DigitalInstalls), digitalInstalls); + Game.RunAfterTick(() => { ShowList(modData.Translation.GetString(GameContentNotFound), modData.Translation.GetString(AlternativeContentSources), options); - ShowBackRetry(DetectContentDisks); + ShowBackRetry(DetectContentSources); }); }).Start(); } - void InstallFromDisc(string path, ModContent.ModSource modSource) + void InstallFromSource(string path, ModContent.ModSource modSource) { var message = ""; ShowProgressbar(modData.Translation.GetString(InstallingContent), () => message); @@ -281,7 +258,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic Game.RunAfterTick(() => { ShowMessage(modData.Translation.GetString(InstallationFailed), modData.Translation.GetString(CheckInstallLog)); - ShowBackRetry(() => InstallFromDisc(path, modSource)); + ShowBackRetry(() => InstallFromSource(path, modSource)); }); } }).Start(); diff --git a/OpenRA.Mods.Common/Widgets/Logic/Installation/ModContentLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Installation/ModContentLogic.cs index ec9025a94d..162b1cab85 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/Installation/ModContentLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/Installation/ModContentLogic.cs @@ -28,7 +28,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic readonly Dictionary sources = new Dictionary(); readonly Dictionary downloads = new Dictionary(); - bool discAvailable; + bool sourceAvailable; [TranslationReference] static readonly string ManualInstall = "manual-install"; @@ -76,11 +76,11 @@ namespace OpenRA.Mods.Common.Widgets.Logic panel.Bounds.Y -= headerHeight / 2; scrollPanel.Bounds.Y += headerHeight; - var discButton = panel.Get("CHECK_DISC_BUTTON"); - discButton.Bounds.Y += headerHeight; - discButton.IsVisible = () => discAvailable; + var sourceButton = panel.Get("CHECK_SOURCE_BUTTON"); + sourceButton.Bounds.Y += headerHeight; + sourceButton.IsVisible = () => sourceAvailable; - discButton.OnClick = () => Ui.OpenWindow("DISC_INSTALL_PANEL", new WidgetArgs + sourceButton.OnClick = () => Ui.OpenWindow("SOURCE_INSTALL_PANEL", new WidgetArgs { { "sources", sources }, { "content", content } @@ -113,7 +113,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic var requiredWidget = container.Get("REQUIRED"); requiredWidget.IsVisible = () => p.Value.Required; - var sourceWidget = container.Get("DISC"); + var sourceWidget = container.Get("SOURCE"); var sourceTitles = p.Value.Sources.Select(s => sources[s].Title).Distinct(); var sourceList = sourceTitles.JoinWith("\n"); var isSourceAvailable = sourceTitles.Any(); @@ -139,18 +139,18 @@ namespace OpenRA.Mods.Common.Widgets.Logic var installedWidget = container.Get("INSTALLED"); installedWidget.IsVisible = () => installed; - var requiresDiscWidget = container.Get("REQUIRES_DISC"); - requiresDiscWidget.IsVisible = () => !installed && !downloadEnabled; + var requiresSourceWidget = container.Get("REQUIRES_SOURCE"); + requiresSourceWidget.IsVisible = () => !installed && !downloadEnabled; if (!isSourceAvailable) { var manualInstall = modData.Translation.GetString(ManualInstall); - requiresDiscWidget.GetText = () => manualInstall; + requiresSourceWidget.GetText = () => manualInstall; } scrollPanel.AddChild(container); } - discAvailable = content.Packages.Values.Any(p => p.Sources.Length > 0 && !p.IsInstalled()); + sourceAvailable = content.Packages.Values.Any(p => p.Sources.Length > 0 && !p.IsInstalled()); } } } diff --git a/OpenRA.Mods.Common/Widgets/Logic/Installation/ModContentDiscTooltipLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Installation/ModContentSourceTooltipLogic.cs similarity index 58% rename from OpenRA.Mods.Common/Widgets/Logic/Installation/ModContentDiscTooltipLogic.cs rename to OpenRA.Mods.Common/Widgets/Logic/Installation/ModContentSourceTooltipLogic.cs index 35fc1a7a56..aaced1434e 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/Installation/ModContentDiscTooltipLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/Installation/ModContentSourceTooltipLogic.cs @@ -14,38 +14,38 @@ using OpenRA.Widgets; namespace OpenRA.Mods.Common.Widgets.Logic { - public class ModContentDiscTooltipLogic : ChromeLogic + public class ModContentSourceTooltipLogic : ChromeLogic { [ObjectCreator.UseCtor] - public ModContentDiscTooltipLogic(Widget widget, Func getText) + public ModContentSourceTooltipLogic(Widget widget, Func getText) { - var discs = widget.Get("DISCS"); - var template = discs.Get("DISC_TEMPLATE"); - discs.RemoveChildren(); + var sources = widget.Get("SOURCES"); + var template = sources.Get("SOURCE_TEMPLATE"); + sources.RemoveChildren(); var desc = widget.Get("DESCRIPTION"); var font = Game.Renderer.Fonts[template.Font]; - var discTitles = getText().Split('\n'); + var sourceTitles = getText().Split('\n'); var maxWidth = Game.Renderer.Fonts[desc.Font].Measure(desc.Text).X; var sideMargin = desc.Bounds.X; - var bottomMargin = discs.Bounds.Height; - foreach (var disc in discTitles) + var bottomMargin = sources.Bounds.Height; + foreach (var source in sourceTitles) { var label = (LabelWidget)template.Clone(); - var title = disc; + var title = source; label.GetText = () => title; - label.Bounds.Y = discs.Bounds.Height; - label.Bounds.Width = font.Measure(disc).X; + label.Bounds.Y = sources.Bounds.Height; + label.Bounds.Width = font.Measure(source).X; maxWidth = Math.Max(maxWidth, label.Bounds.Width + label.Bounds.X); - discs.AddChild(label); - discs.Bounds.Height += label.Bounds.Height; + sources.AddChild(label); + sources.Bounds.Height += label.Bounds.Height; } widget.Bounds.Width = 2 * sideMargin + maxWidth; - widget.Bounds.Height = discs.Bounds.Y + bottomMargin + discs.Bounds.Height; + widget.Bounds.Height = sources.Bounds.Y + bottomMargin + sources.Bounds.Height; } } } diff --git a/mods/cnc/installer/covertops.yaml b/mods/cnc/installer/covertops.yaml index d1d2a53f60..14d85ee24f 100644 --- a/mods/cnc/installer/covertops.yaml +++ b/mods/cnc/installer/covertops.yaml @@ -1,4 +1,5 @@ covertops: Covert Operations Expansion (English) + Type: Disc IDFiles: GAME/GAME.DAT: be5a6c4c0a581da09e8f34a3bbf7bd17e525085c CONQUER.MIX: 713b53fa4c188ca9619c6bbeadbfc86513704266 diff --git a/mods/cnc/installer/firstdecade.yaml b/mods/cnc/installer/firstdecade.yaml index 3c640fcb4d..ef062161b2 100644 --- a/mods/cnc/installer/firstdecade.yaml +++ b/mods/cnc/installer/firstdecade.yaml @@ -1,4 +1,5 @@ tfd: C&C The First Decade (English) + Type: Disc IDFiles: data1.hdr: bef3a08c3fc1b1caf28ca0dbb97c1f900005930e data1.cab: 12ad6113a6890a1b4d5651a75378c963eaf513b9 diff --git a/mods/cnc/installer/gdi95.yaml b/mods/cnc/installer/gdi95.yaml index 6c92c88332..55fba1a1f6 100644 --- a/mods/cnc/installer/gdi95.yaml +++ b/mods/cnc/installer/gdi95.yaml @@ -1,4 +1,5 @@ gdi95: C&C Gold (GDI Disc, English) + Type: Disc IDFiles: DISK.WAV: 8bef9a6687c0fe0afd57c6561df58fa6e64f145d CONQUER.MIX: 833e02a09aae694659eb312d3838367f681d1b30 diff --git a/mods/cnc/installer/nod95.yaml b/mods/cnc/installer/nod95.yaml index aa6937477f..fe1f726cba 100644 --- a/mods/cnc/installer/nod95.yaml +++ b/mods/cnc/installer/nod95.yaml @@ -1,4 +1,5 @@ nod95: C&C Gold (Nod Disc, English) + Type: Disc IDFiles: DISK.WAV: 83a0235525afa5cd6096f2967e3eae032996e38c CONQUER.MIX: 833e02a09aae694659eb312d3838367f681d1b30 diff --git a/mods/common/languages/en.ftl b/mods/common/languages/en.ftl index 0c592c5d27..d3aa02aa70 100644 --- a/mods/common/languages/en.ftl +++ b/mods/common/languages/en.ftl @@ -247,14 +247,14 @@ archive-validation-failed = Archive validation failed extracting = Extracting... extracting-entry = Extracting { $entry } archive-extraction-failed = Archive extraction failed -mirror-selection-failed = Online mirror is not available. Please install from an original disc. +mirror-selection-failed = Online mirror is not available. Please install from an original source. -## InstallFromDiscLogic -detecting-drives = Detecting drives -checking-discs = Checking Discs -searching-disc-for = Searching for { $title } +## InstallFromSourceLogic +detecting-sources = Detecting drives +checking-sources = Checking Sources +searching-source-for = Searching for { $title } content-package-installation = The following content packages will be installed: -game-discs = Game Discs +game-sources = Game Sources digital-installs = Digital Installs game-content-not-found = Game Content Not Found alternative-content-sources = Please insert or install one of the following content sources: @@ -268,10 +268,10 @@ extracting-filename-progress = Extracting { $filename } ({ $progress }%) cancel = Cancel retry = Retry -## InstallFromDiscLogic, LobbyLogic +## InstallFromSourceLogic, LobbyLogic back = Back -# InstallFromDiscLogic, ModContentPromptLogic +# InstallFromSourceLogic, ModContentPromptLogic continue = Continue ## ModContentLogic diff --git a/mods/d2k/installer/d2k-a.yaml b/mods/d2k/installer/d2k-a.yaml index fac3e22118..82c3a37326 100644 --- a/mods/d2k/installer/d2k-a.yaml +++ b/mods/d2k/installer/d2k-a.yaml @@ -1,4 +1,5 @@ d2k-a: Dune 2000 (English) + Type: Disc IDFiles: MUSIC/AMBUSH.AUD: bd5926a56a83bc0e49f96037e1f909014ac0772a SETUP/SETUP.Z: 937f5ceb1236bf3f3d4e43929305ffe5004078e7 diff --git a/mods/d2k/installer/d2k-b.yaml b/mods/d2k/installer/d2k-b.yaml index 08c80af18f..7caff76b13 100644 --- a/mods/d2k/installer/d2k-b.yaml +++ b/mods/d2k/installer/d2k-b.yaml @@ -1,4 +1,5 @@ d2k-b: Dune 2000 (English) + Type: Disc IDFiles: MUSIC/AMBUSH.AUD: bd5926a56a83bc0e49f96037e1f909014ac0772a SETUP/SETUP.Z: 029722e70fb7636f8120028f5c9b6ce81627ff90 diff --git a/mods/d2k/installer/d2k-c.yaml b/mods/d2k/installer/d2k-c.yaml index 2977ac256b..9e3549de42 100644 --- a/mods/d2k/installer/d2k-c.yaml +++ b/mods/d2k/installer/d2k-c.yaml @@ -1,4 +1,5 @@ d2k-c: Dune 2000 (English) + Type: Disc IDFiles: MUSIC/AMBUSH.AUD: bd5926a56a83bc0e49f96037e1f909014ac0772a SETUP/SETUP.Z: d939b39bdbc952b259ce2b45c0bbedefa534b7f2 diff --git a/mods/d2k/installer/d2k-d.yaml b/mods/d2k/installer/d2k-d.yaml index b576b41e04..724bd59713 100644 --- a/mods/d2k/installer/d2k-d.yaml +++ b/mods/d2k/installer/d2k-d.yaml @@ -1,4 +1,5 @@ d2k-d: Dune 2000 (English) + Type: Disc IDFiles: MUSIC/AMBUSH.AUD: bd5926a56a83bc0e49f96037e1f909014ac0772a SETUP/SETUP.Z: 2411cc5df36954ebd534ceafa3007c8aa9232909 diff --git a/mods/d2k/installer/d2k-e.yaml b/mods/d2k/installer/d2k-e.yaml index 6560f5f9ce..14a2123451 100644 --- a/mods/d2k/installer/d2k-e.yaml +++ b/mods/d2k/installer/d2k-e.yaml @@ -1,4 +1,5 @@ d2k-e: Dune 2000 (English) + Type: Disc IDFiles: MUSIC/AMBUSH.AUD: bd5926a56a83bc0e49f96037e1f909014ac0772a SETUP/SETUP.Z: b476661e82eeb05949e97fa1f75fed2343174be5 diff --git a/mods/modcontent/content.yaml b/mods/modcontent/content.yaml index a1dd396e7c..ef6616083a 100644 --- a/mods/modcontent/content.yaml +++ b/mods/modcontent/content.yaml @@ -50,7 +50,7 @@ Background@CONTENT_PANEL: Font: Bold TextColor: CC0000 Text: Required - Image@DISC: + Image@SOURCE: X: 275 Y: 2 Width: 20 @@ -58,7 +58,7 @@ Background@CONTENT_PANEL: ImageCollection: modcontent ImageName: cdicon TooltipContainer: TOOLTIP_CONTAINER - TooltipTemplate: DISC_TOOLTIP + TooltipTemplate: SOURCE_TOOLTIP Button@DOWNLOAD: X: 304 Y: 0 @@ -74,7 +74,7 @@ Background@CONTENT_PANEL: Font: Bold TextColor: 00CC00 Text: Installed - Label@REQUIRES_DISC: + Label@REQUIRES_SOURCE: X: 304 Width: 100 Height: 23 @@ -82,7 +82,7 @@ Background@CONTENT_PANEL: Font: Bold TextColor: DDDDDD Text: Requires Disc - Button@CHECK_DISC_BUTTON: + Button@CHECK_SOURCE_BUTTON: X: 30 Y: PARENT_BOTTOM - 52 Background: button-highlighted @@ -101,8 +101,8 @@ Background@CONTENT_PANEL: Key: escape TooltipContainer@TOOLTIP_CONTAINER: -Background@DISC_TOOLTIP: - Logic: ModContentDiscTooltipLogic +Background@SOURCE_TOOLTIP: + Logic: ModContentSourceTooltipLogic Background: panel-thinborder Height: 25 Children: @@ -111,12 +111,12 @@ Background@DISC_TOOLTIP: Height: 23 Font: Bold Text: Content available from: - Container@DISCS: + Container@SOURCES: Y: 15 Width: PARENT_RIGHT - 10 Height: 7 # used as bottom margin Children: - Label@DISC_TEMPLATE: + Label@SOURCE_TEMPLATE: X: 20 Height: 14 Font: TinyBold @@ -177,8 +177,8 @@ Container@PACKAGE_DOWNLOAD_PANEL: Font: Bold Key: escape -Background@DISC_INSTALL_PANEL: - Logic: InstallFromDiscLogic +Background@SOURCE_INSTALL_PANEL: + Logic: InstallFromSourceLogic X: (WINDOW_RIGHT - WIDTH) / 2 Y: (WINDOW_BOTTOM - HEIGHT) / 2 Width: 500 diff --git a/mods/ra/installer/aftermath.yaml b/mods/ra/installer/aftermath.yaml index e67d5e7f34..b7580a223c 100644 --- a/mods/ra/installer/aftermath.yaml +++ b/mods/ra/installer/aftermath.yaml @@ -1,4 +1,5 @@ aftermath: Aftermath Expansion Disc (English) + Type: Disc IDFiles: README.TXT: 9902fb74c019df1b76ff5634e68f0371d790b5e0 SETUP/INSTALL/PATCH.RTP: 5bce93f834f9322ddaa7233242e5b6c7fea0bf17 diff --git a/mods/ra/installer/allies95.yaml b/mods/ra/installer/allies95.yaml index fdf3762035..5e5dfe1b25 100644 --- a/mods/ra/installer/allies95.yaml +++ b/mods/ra/installer/allies95.yaml @@ -1,4 +1,5 @@ allied: Red Alert 95 (Allied Disc, English) + Type: Disc IDFiles: MAIN.MIX: 20ebe16f91ff79be2d672f1db5bae9048ff9357c Length: 4096 diff --git a/mods/ra/installer/cnc95.yaml b/mods/ra/installer/cnc95.yaml index 7348a02b6c..d70756bbf9 100644 --- a/mods/ra/installer/cnc95.yaml +++ b/mods/ra/installer/cnc95.yaml @@ -1,4 +1,5 @@ cnc95: C&C Gold (GDI or Nod Disc, English) + Type: Disc IDFiles: CONQUER.MIX: 833e02a09aae694659eb312d3838367f681d1b30 Install: diff --git a/mods/ra/installer/counterstrike.yaml b/mods/ra/installer/counterstrike.yaml index e7aa48efc1..1143bdefd6 100644 --- a/mods/ra/installer/counterstrike.yaml +++ b/mods/ra/installer/counterstrike.yaml @@ -1,4 +1,5 @@ counterstrike: Counterstrike Expansion Disc (English) + Type: Disc IDFiles: README.TXT: 0efe8087383f0b159a9633f891fb5f53c6097cd4 SETUP/INSTALL/CSTRIKE.RTP: fae8ba82db71574f6ecd8fb4ff4026fcb65d2adc diff --git a/mods/ra/installer/firstdecade.yaml b/mods/ra/installer/firstdecade.yaml index dcffa25229..ffe2b784d6 100644 --- a/mods/ra/installer/firstdecade.yaml +++ b/mods/ra/installer/firstdecade.yaml @@ -1,4 +1,5 @@ tfd: C&C The First Decade (English) + Type: Disc IDFiles: data1.hdr: bef3a08c3fc1b1caf28ca0dbb97c1f900005930e data1.cab: 12ad6113a6890a1b4d5651a75378c963eaf513b9 diff --git a/mods/ra/installer/soviet95.yaml b/mods/ra/installer/soviet95.yaml index 09557c3e4e..b516a44d6c 100644 --- a/mods/ra/installer/soviet95.yaml +++ b/mods/ra/installer/soviet95.yaml @@ -1,4 +1,5 @@ soviet: Red Alert 95 (Soviet Disc, English) + Type: Disc IDFiles: MAIN.MIX: 9d108f18560716b684ab8b1da42cc7f3d1b52519 Length: 4096 diff --git a/mods/ts/installer/firestorm.yaml b/mods/ts/installer/firestorm.yaml index 5859dcb2ee..1508a55948 100644 --- a/mods/ts/installer/firestorm.yaml +++ b/mods/ts/installer/firestorm.yaml @@ -1,4 +1,5 @@ fstorm: Firestorm Expansion Disc (English) + Type: Disc IDFiles: Install/README.TXT: f2810b540fce8f3880250213ee08c57780d81c20 Install/Language.dll: 4df87c1a2289da57dd14d0a7299546f37357fcca diff --git a/mods/ts/installer/firstdecade.yaml b/mods/ts/installer/firstdecade.yaml index 22ec5538ab..209b539f2d 100644 --- a/mods/ts/installer/firstdecade.yaml +++ b/mods/ts/installer/firstdecade.yaml @@ -1,4 +1,5 @@ tfd: C&C The First Decade (English) + Type: Disc IDFiles: data1.hdr: bef3a08c3fc1b1caf28ca0dbb97c1f900005930e data1.cab: 12ad6113a6890a1b4d5651a75378c963eaf513b9 diff --git a/mods/ts/installer/tibsun.yaml b/mods/ts/installer/tibsun.yaml index 27dbb758cb..7f53df5b7a 100644 --- a/mods/ts/installer/tibsun.yaml +++ b/mods/ts/installer/tibsun.yaml @@ -1,4 +1,5 @@ tibsun: Tiberian Sun (GDI or Nod Disc, English) + Type: Disc IDFiles: README.TXT: 45745c4a0c888317ec900208a426472779c42bf7 AUTOPLAY.WAV: 2dfce5d00f98b641849c29942b651f4e98d30e30