diff --git a/OpenRA.Game/GameRules/MusicInfo.cs b/OpenRA.Game/GameRules/MusicInfo.cs index bdeff4aafa..73793dd6ea 100644 --- a/OpenRA.Game/GameRules/MusicInfo.cs +++ b/OpenRA.Game/GameRules/MusicInfo.cs @@ -16,8 +16,8 @@ namespace OpenRA.GameRules { public readonly string Filename = null; public readonly string Title = null; - public readonly int Length = 0; // seconds - public readonly bool Exists = false; + public int Length { get; private set; } // seconds + public bool Exists { get; private set; } public MusicInfo( string key, MiniYaml value ) { @@ -30,5 +30,14 @@ namespace OpenRA.GameRules Exists = true; Length = (int)AudLoader.SoundLength(FileSystem.Open(Filename)); } + + public void Reload() + { + if (!FileSystem.Exists(Filename)) + return; + + Exists = true; + Length = (int)AudLoader.SoundLength(FileSystem.Open(Filename)); + } } } diff --git a/OpenRA.Mods.Cnc/Widgets/CncMusicPlayerLogic.cs b/OpenRA.Mods.Cnc/Widgets/CncMusicPlayerLogic.cs index 1f661ce170..f1846e01b0 100644 --- a/OpenRA.Mods.Cnc/Widgets/CncMusicPlayerLogic.cs +++ b/OpenRA.Mods.Cnc/Widgets/CncMusicPlayerLogic.cs @@ -16,6 +16,9 @@ using OpenRA.Support; using OpenRA.Widgets; using OpenRA.Traits; using OpenRA.Graphics; +using System.Collections.Generic; +using System.IO; +using System.Threading; namespace OpenRA.Mods.Cnc.Widgets { @@ -39,7 +42,26 @@ namespace OpenRA.Mods.Cnc.Widgets Func noMusic = () => !installed; panel.GetWidget("BACK_BUTTON").OnClick = onExit; - panel.GetWidget("INSTALL_BUTTON").IsDisabled = () => true; + + Action afterInstall = path => + { + // Mount the new mixfile and rebuild the scores list + try + { + FileSystem.Mount(path); + Rules.Music.Do(m => m.Value.Reload()); + } + catch (Exception) { } + + installed = Rules.Music.Where(m => m.Value.Exists).Any(); + BuildMusicTable(panel); + }; + + var installButton = panel.GetWidget("INSTALL_BUTTON"); + installButton.OnClick = () => + Widget.OpenWindow("INSTALL_MUSIC_PANEL", new Dictionary() {{ "afterInstall", afterInstall }}); + installButton.IsVisible = () => music.Length < 2; // Hack around ra shipping (only) hellmarch by default + panel.GetWidget("NO_MUSIC_LABEL").IsVisible = noMusic; var playButton = panel.GetWidget("BUTTON_PLAY"); @@ -164,4 +186,91 @@ namespace OpenRA.Mods.Cnc.Widgets .Skip(1).FirstOrDefault() ?? songs.FirstOrDefault(); } } + + + public class CncInstallMusicLogic : IWidgetDelegate + { + Widget panel; + ProgressBarWidget progressBar; + LabelWidget statusLabel; + Action afterInstall; + + [ObjectCreator.UseCtor] + public CncInstallMusicLogic([ObjectCreator.Param] Widget widget, + [ObjectCreator.Param] Action afterInstall) + { + this.afterInstall = afterInstall; + panel = widget.GetWidget("INSTALL_MUSIC_PANEL"); + progressBar = panel.GetWidget("PROGRESS_BAR"); + statusLabel = panel.GetWidget("STATUS_LABEL"); + + var backButton = panel.GetWidget("BACK_BUTTON"); + backButton.OnClick = Widget.CloseWindow; + backButton.IsVisible = () => false; + + var retryButton = panel.GetWidget("RETRY_BUTTON"); + retryButton.OnClick = PromptForCD; + retryButton.IsVisible = () => false; + + // TODO: Search obvious places (platform dependent) for CD + PromptForCD(); + } + + void PromptForCD() + { + progressBar.SetIndeterminate(true); + statusLabel.GetText = () => "Waiting for file"; + Game.Utilities.PromptFilepathAsync("Select SCORES.MIX on the C&C CD", path => Game.RunAfterTick(() => Install(path))); + } + + void Install(string path) + { + var dest = new string[] { Platform.SupportDir, "Content", "cnc" }.Aggregate(Path.Combine); + + var onError = (Action)(s => + { + progressBar.SetIndeterminate(false); + statusLabel.GetText = () => "Error: "+s; + panel.GetWidget("RETRY_BUTTON").IsVisible = () => true; + panel.GetWidget("BACK_BUTTON").IsVisible = () => true; + }); + + // Mount the package and check that it contains the correct files + try + { + var mixFile = new MixFile(path, 0); + + if (!mixFile.Exists("aoi.aud")) + { + onError("Not the C&C SCORES.MIX"); + return; + } + + statusLabel.GetText = () => "Installing"; + var t = new Thread( _ => + { + var destPath = Path.Combine(dest, "scores.mix"); + try + { + File.Copy(path, destPath, true); + } + catch (Exception) + { + onError("File copy failed"); + } + + Game.RunAfterTick(() => + { + Widget.CloseWindow(); // Progress panel + afterInstall(destPath); + }); + }) { IsBackground = true }; + t.Start(); + } + catch (Exception) + { + onError("Invalid mix file"); + } + } + } } diff --git a/mods/cnc/chrome/music.yaml b/mods/cnc/chrome/music.yaml index d12102ad4d..5872208cc6 100644 --- a/mods/cnc/chrome/music.yaml +++ b/mods/cnc/chrome/music.yaml @@ -182,4 +182,57 @@ Container@MUSIC_PANEL: Y:399 Width:140 Height:35 - Text:Install Music \ No newline at end of file + Text:Install Music + +Container@INSTALL_MUSIC_PANEL: + Id:INSTALL_MUSIC_PANEL + Delegate:CncInstallMusicLogic + X:(WINDOW_RIGHT - WIDTH)/2 + Y:(WINDOW_BOTTOM - 150)/2 + Width:640 + Height:150 + Children: + Label@TITLE: + Width:PARENT_RIGHT + Y:0-25 + Font:BigBold + Contrast:true + Align:Center + Text:Install Music + Background@bg: + Width:640 + Height:150 + Background:panel-black + Children: + Image@INSTALL: + X:11 + Y:11 + ImageCollection: install + ImageName: logo + ProgressBar@PROGRESS_BAR: + Id:PROGRESS_BAR + X:170 + Y:45 + Width:PARENT_RIGHT - 185 + Height:35 + Label@STATUS_LABEL: + Id:STATUS_LABEL + X:170 + Y:85 + Width:PARENT_RIGHT - 185 + Height:25 + Align:Left + Text:Waiting for file + CncMenuButton@BACK_BUTTON: + Id:BACK_BUTTON + Y:149 + Width:140 + Height:35 + Text:Back + CncMenuButton@RETRY_BUTTON: + Id:RETRY_BUTTON + X:500 + Y:149 + Width:140 + Height:35 + Text:Retry