From 7161797d748f8999cee3d11c3b4828eba4f0511e Mon Sep 17 00:00:00 2001 From: Joshua Askharoun Date: Mon, 26 Apr 2021 04:28:43 -0500 Subject: [PATCH] Improved mod interface; Basic mod install process --- ZuneModCore/Mod.cs | 22 ++++-- ZuneModCore/Mods/FeaturesOverrideMod.cs | 8 +-- ZuneModCore/Mods/VideoSyncMod.cs | 33 ++------- ZuneModCore/Mods/WebservicesMod.cs | 90 +++++++++++++++---------- ZuneModdingHelper/MainWindow.xaml | 43 ++++++++---- ZuneModdingHelper/MainWindow.xaml.cs | 32 +++++++-- 6 files changed, 141 insertions(+), 87 deletions(-) diff --git a/ZuneModCore/Mod.cs b/ZuneModCore/Mod.cs index 2153d6f..02e88a9 100644 --- a/ZuneModCore/Mod.cs +++ b/ZuneModCore/Mod.cs @@ -29,15 +29,29 @@ namespace ZuneModCore public virtual Task Init() => Task.CompletedTask; - public abstract Task Apply(); + public abstract Task Apply(); - public abstract Task Reset(); + public abstract Task Reset(); public abstract AbstractUIElementGroup? OptionsUI { get; } - public string StorageDirectory => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), - "ZuneModCore", Id); + public string StorageDirectory + { + get + { + string dir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "ZuneModCore", Id); + // Create the directory just in case the consumer assumes the folder exists already + Directory.CreateDirectory(dir); + return dir; + } + } public abstract IReadOnlyList? DependentMods { get; } + + internal FileStream OpenFileInStorageDirectory(string filename) + { + FileInfo info = new(Path.Combine(StorageDirectory, filename)); + return File.Create(info.FullName); + } } } diff --git a/ZuneModCore/Mods/FeaturesOverrideMod.cs b/ZuneModCore/Mods/FeaturesOverrideMod.cs index 5418349..7f89a44 100644 --- a/ZuneModCore/Mods/FeaturesOverrideMod.cs +++ b/ZuneModCore/Mods/FeaturesOverrideMod.cs @@ -61,23 +61,23 @@ namespace ZuneModCore.Mods return Task.CompletedTask; } - public override Task Apply() + public override Task Apply() { // TODO: Use user choices from AbstractUI foreach (AbstractUIElement uiElem in OptionsUI.Items) if (uiElem is AbstractBooleanUIElement boolElem)// && boolElem.State) SetFeatureOverride(boolElem.Id, true); - return Task.FromResult(true); + return Task.FromResult(null); } - public override Task Reset() + public override Task Reset() { foreach (AbstractUIElement uiElem in OptionsUI.Items) if (uiElem is AbstractBooleanUIElement boolElem) ResetFeatureOverride(boolElem.Id); - return Task.FromResult(true); + return Task.FromResult(null); } public static void SetFeatureOverride(string feature, bool value) => diff --git a/ZuneModCore/Mods/VideoSyncMod.cs b/ZuneModCore/Mods/VideoSyncMod.cs index dbfb268..c2ab707 100644 --- a/ZuneModCore/Mods/VideoSyncMod.cs +++ b/ZuneModCore/Mods/VideoSyncMod.cs @@ -8,16 +8,6 @@ namespace ZuneModCore.Mods { public class VideoSyncMod : Mod { - public VideoSyncMod() - { - testButton.Clicked += TestButton_Clicked; - } - - private void TestButton_Clicked(object? sender, EventArgs e) - { - System.Diagnostics.Debug.WriteLine("Howdy, Zune! How are ya?"); - } - public override string Title => "Fix Video Sync"; public override string Description => @@ -25,30 +15,21 @@ namespace ZuneModCore.Mods public override string Id => nameof(VideoSyncMod); - public override AbstractUIElementGroup OptionsUI => new(nameof(VideoSyncMod)) - { - Title = Title, - Items = - { - new AbstractBooleanUIElement("test", "Is this is test?"), - testButton - } - }; + public override AbstractUIElementGroup? OptionsUI => null; - private readonly AbstractButton testButton = new(nameof(testButton), "Howdy Zune!", type: AbstractButtonType.Generic); - - public override Task Apply() + public override Task Apply() { - var writer = File.CreateText(Path.Combine(StorageDirectory, "1.log")); + var writer = new StreamWriter(OpenFileInStorageDirectory("1.log")); writer.WriteLine("Hello world"); writer.Flush(); writer.Close(); - return Task.FromResult(true); + + return Task.FromResult(null); } - public override Task Reset() + public override Task Reset() { - return Task.FromResult(true); + return Task.FromResult(null); } public override IReadOnlyList? DependentMods => null; diff --git a/ZuneModCore/Mods/WebservicesMod.cs b/ZuneModCore/Mods/WebservicesMod.cs index ba3314b..3502483 100644 --- a/ZuneModCore/Mods/WebservicesMod.cs +++ b/ZuneModCore/Mods/WebservicesMod.cs @@ -5,10 +5,6 @@ using System.IO; using System.Threading.Tasks; using static ZuneModCore.Mods.FeaturesOverrideMod; -#if DEBUG -using System.Diagnostics; -#endif - namespace ZuneModCore.Mods { public class WebservicesMod : Mod @@ -31,48 +27,70 @@ namespace ZuneModCore.Mods public override IReadOnlyList? DependentMods => null; - public override Task Apply() + public override Task Apply() { - // Open ZuneServices.dll + // Verify that ZuneServices.dll exists FileInfo zsDllInfo = new(Path.Combine(ZuneInstallDir, "ZuneService.dll")); if (!zsDllInfo.Exists) - return Task.FromResult(true); - using FileStream zsDll = zsDllInfo.Open(FileMode.Open); - using BinaryWriter zsDllWriter = new(zsDll); - using BinaryReader zsDllReader = new(zsDll); + { + return Task.FromResult($"The file '{zsDllInfo.FullName}' does not exist."); + } - // Verify that the DLL is from v4.8 (other versions not tested) - zsDllReader.BaseStream.Position = 0x12C824; - var versionBytes = zsDllReader.ReadBytes(ZUNE_4_8_VERSION_BYTES.Length * 2); - if (versionBytes[0] != '4' || versionBytes[2] != '.' || versionBytes[4] != '8') - return Task.FromResult(true); + // Make a backup of the file + File.Copy(zsDllInfo.FullName, Path.Combine(StorageDirectory, "ZuneService.original.dll")); - // Patch ZuneServices.dll to use zunes.tk instead of zune.net - zsDllReader.BaseStream.Position = ZUNESERVICES_ENDPOINTS_BLOCK_OFFSET; - string endpointBlock = System.Text.Encoding.Unicode.GetString(zsDllReader.ReadBytes(ZUNESERVICES_ENDPOINTS_BLOCK_LENGTH)); - endpointBlock = endpointBlock.Replace("zune.net", "zunes.tk"); - byte[] endpointBytes = System.Text.Encoding.Unicode.GetBytes(endpointBlock); - if (endpointBytes.Length != ZUNESERVICES_ENDPOINTS_BLOCK_LENGTH) - return Task.FromResult(false); - zsDllWriter.Seek(ZUNESERVICES_ENDPOINTS_BLOCK_OFFSET, SeekOrigin.Begin); - zsDllWriter.Write(endpointBytes); + try + { + // Open the file + using FileStream zsDll = zsDllInfo.Open(FileMode.Open); + using BinaryWriter zsDllWriter = new(zsDll); + using BinaryReader zsDllReader = new(zsDll); + + // Verify that the DLL is from v4.8 (other versions not tested) + zsDllReader.BaseStream.Position = 0x12C824; + var versionBytes = zsDllReader.ReadBytes(ZUNE_4_8_VERSION_BYTES.Length * 2); + if (versionBytes[0] != '4' || versionBytes[2] != '.' || versionBytes[4] != '8') + { + return Task.FromResult("This mod has not been tested on versions earlier than 4.8."); + } + + // Patch ZuneServices.dll to use zunes.tk instead of zune.net + zsDllReader.BaseStream.Position = ZUNESERVICES_ENDPOINTS_BLOCK_OFFSET; + string endpointBlock = System.Text.Encoding.Unicode.GetString(zsDllReader.ReadBytes(ZUNESERVICES_ENDPOINTS_BLOCK_LENGTH)); + endpointBlock = endpointBlock.Replace("zune.net", "zunes.tk"); + byte[] endpointBytes = System.Text.Encoding.Unicode.GetBytes(endpointBlock); + if (endpointBytes.Length != ZUNESERVICES_ENDPOINTS_BLOCK_LENGTH) + { + return Task.FromResult("Failed to safely overwrite strings in DLL."); + } + zsDllWriter.Seek(ZUNESERVICES_ENDPOINTS_BLOCK_OFFSET, SeekOrigin.Begin); + zsDllWriter.Write(endpointBytes); - // Enable all feature overrides affected by new servers - SetFeatureOverride("Apps", true); - SetFeatureOverride("Channels", true); - SetFeatureOverride("Games", true); - SetFeatureOverride("Marketplace", true); - SetFeatureOverride("Music", true); - SetFeatureOverride("MusicVideos", true); - SetFeatureOverride("Podcasts", true); - SetFeatureOverride("Social", true); - SetFeatureOverride("Videos", true); + // Enable all feature overrides affected by new servers + SetFeatureOverride("Apps", true); + SetFeatureOverride("Channels", true); + SetFeatureOverride("Games", true); + SetFeatureOverride("Marketplace", true); + SetFeatureOverride("Music", true); + SetFeatureOverride("MusicVideos", true); + SetFeatureOverride("Podcasts", true); + SetFeatureOverride("Social", true); + SetFeatureOverride("Videos", true); - return Task.FromResult(true); + return Task.FromResult(null); + } + catch (UnauthorizedAccessException) + { + return Task.FromResult($"Failed to open '{zsDllInfo.FullName}'. Verify that the Zune software is not running and try again."); + } + catch (Exception ex) + { + return Task.FromResult(ex.Message); + } } - public override Task Reset() + public override Task Reset() { throw new NotImplementedException(); } diff --git a/ZuneModdingHelper/MainWindow.xaml b/ZuneModdingHelper/MainWindow.xaml index 2341667..39eb96f 100644 --- a/ZuneModdingHelper/MainWindow.xaml +++ b/ZuneModdingHelper/MainWindow.xaml @@ -1,15 +1,15 @@  + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:local="clr-namespace:ZuneModdingHelper" + xmlns:core="clr-namespace:ZuneModCore;assembly=ZuneModCore" + xmlns:mah="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro" + mc:Ignorable="d" + Title="Zune Modding Helper" Height="450" Width="800" + Loaded="Window_Loaded" + Background="#F0F0F0"> @@ -53,8 +53,25 @@ -