From 44d033786d95e3890f71ad67bd816dd5e5e69206 Mon Sep 17 00:00:00 2001 From: Yoshi Askharoun Date: Tue, 21 May 2024 20:54:02 -0500 Subject: [PATCH] Introduce ModManager and IModFactory --- ZuneModCore/IModFactory.cs | 26 +++++++++++++++ ZuneModCore/Mod.cs | 40 +++--------------------- ZuneModCore/ModManager.cs | 37 ++++++++++++++++++++++ ZuneModCore/Mods/BackgroundImageMod.cs | 5 ++- ZuneModCore/Mods/FeaturesOverrideMod.cs | 8 +++-- ZuneModCore/Mods/MbidLocatorMod.cs | 19 ++++++----- ZuneModCore/Mods/VideoSyncMod.cs | 9 ++++-- ZuneModCore/Mods/WebservicesMod.cs | 22 +++++++------ ZuneModdingHelper/Pages/ModsPage.xaml.cs | 2 +- 9 files changed, 108 insertions(+), 60 deletions(-) create mode 100644 ZuneModCore/IModFactory.cs create mode 100644 ZuneModCore/ModManager.cs diff --git a/ZuneModCore/IModFactory.cs b/ZuneModCore/IModFactory.cs new file mode 100644 index 0000000..10fb4f4 --- /dev/null +++ b/ZuneModCore/IModFactory.cs @@ -0,0 +1,26 @@ +using Microsoft.Extensions.DependencyInjection; +using System; + +namespace ZuneModCore; + +public interface IModFactory where T : Mod +{ + ModMetadata Metadata { get; } + + T Create(IServiceProvider services); +} + +/// +/// A base class that implements with +/// using dependency injection. +/// +/// +public abstract class DIModFactoryBase : IModFactory where T : Mod +{ + public abstract ModMetadata Metadata { get; } + + public virtual T Create(IServiceProvider services) + { + return ActivatorUtilities.CreateInstance(services, Metadata); + } +} diff --git a/ZuneModCore/Mod.cs b/ZuneModCore/Mod.cs index f83cf97..395a2e0 100644 --- a/ZuneModCore/Mod.cs +++ b/ZuneModCore/Mod.cs @@ -1,51 +1,19 @@ -using Microsoft.Extensions.DependencyInjection; -using OwlCore.AbstractUI.Models; +using OwlCore.AbstractUI.Models; using System; using System.Collections.Generic; using System.IO; using System.Threading.Tasks; -using ZuneModCore.Mods; namespace ZuneModCore; -public abstract class Mod +public abstract class Mod(ModMetadata metadata) { - /// - /// A list of all available mods - /// - public static readonly IReadOnlyList AvailableModTypes = new List - { - typeof(FeaturesOverrideMod), - typeof(VideoSyncMod), - typeof(WebservicesMod), - typeof(BackgroundImageMod), - typeof(MbidLocatorMod), - }.AsReadOnly(); - public static string DefaultZuneInstallDir { get; } = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "Zune"); + public ModMetadata Metadata { get; } = metadata; + public string ZuneInstallDir { get; set; } = DefaultZuneInstallDir; - private static List? _mods; - public static IReadOnlyList GetAvailableMods() - { - if (_mods is null) - { - _mods = new(AvailableModTypes.Count); - var services = CommunityToolkit.Mvvm.DependencyInjection.Ioc.Default; - foreach (var modType in AvailableModTypes) - { - var instance = ActivatorUtilities.CreateInstance(services, modType); - if (instance is Mod mod) - _mods.Add(mod); - } - } - - return _mods; - } - - public abstract ModMetadata Metadata { get; } - public virtual AbstractUICollection? GetDefaultOptionsUI() => null; public abstract Task Apply(); diff --git a/ZuneModCore/ModManager.cs b/ZuneModCore/ModManager.cs new file mode 100644 index 0000000..7fda3b9 --- /dev/null +++ b/ZuneModCore/ModManager.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; +using ZuneModCore.Mods; + +namespace ZuneModCore; + +public class ModManager +{ + /// + /// Factories for all available mods. + /// + public static readonly IReadOnlyList> ModFactories = new List> + { + new FeaturesOverrideModFactory(), + new VideoSyncModFactory(), + new WebservicesModFactory(), + new BackgroundImageModFactory(), + new MbidLocatorModFactory(), + }.AsReadOnly(); + + private static List? _mods; + public static IReadOnlyList GetAvailableMods() + { + if (_mods is null) + { + _mods = new(ModFactories.Count); + var services = CommunityToolkit.Mvvm.DependencyInjection.Ioc.Default; + + foreach (var modType in ModFactories) + { + var mod = modType.Create(services); + _mods.Add(mod); + } + } + + return _mods; + } +} diff --git a/ZuneModCore/Mods/BackgroundImageMod.cs b/ZuneModCore/Mods/BackgroundImageMod.cs index c987bdd..7783463 100644 --- a/ZuneModCore/Mods/BackgroundImageMod.cs +++ b/ZuneModCore/Mods/BackgroundImageMod.cs @@ -9,7 +9,7 @@ using ZuneModCore.Win32; namespace ZuneModCore.Mods; -public class BackgroundImageMod : Mod +public class BackgroundImageModFactory : DIModFactoryBase { private const string Description = "Replaces the \"Zero\" background with an image of your choice."; @@ -17,7 +17,10 @@ public class BackgroundImageMod : Mod public override ModMetadata Metadata => new(nameof(BackgroundImageMod), "Background Image", Description, Author, new(1, 0)); +} +public class BackgroundImageMod(ModMetadata metadata) : Mod(metadata) +{ public override AbstractUICollection? GetDefaultOptionsUI() { AbstractUICollection optionsUi = new(nameof(BackgroundImageMod)) diff --git a/ZuneModCore/Mods/FeaturesOverrideMod.cs b/ZuneModCore/Mods/FeaturesOverrideMod.cs index 5db2e55..f39a00e 100644 --- a/ZuneModCore/Mods/FeaturesOverrideMod.cs +++ b/ZuneModCore/Mods/FeaturesOverrideMod.cs @@ -8,9 +8,8 @@ using ZuneModCore.Win32; namespace ZuneModCore.Mods; -public class FeaturesOverrideMod : Mod, IAsyncInit +public class FeaturesOverrideModFactory : DIModFactoryBase { - private const string ZUNE_FEATURESOVERRIDE_REGKEY = RegEdit.ZUNE_REG_PATH + "FeaturesOverride"; private const string Description = "Re-enables access to some features disabled by Microsoft, such as the Social and Marketplace tabs.\r\n" + "Does not restore functionality of those features, but shows them in the software."; @@ -19,6 +18,11 @@ public class FeaturesOverrideMod : Mod, IAsyncInit public override ModMetadata Metadata => new(nameof(FeaturesOverrideMod), "Features Override", Description, Author, new(1, 0)); +} + +public class FeaturesOverrideMod(ModMetadata metadata) : Mod(metadata), IAsyncInit +{ + private const string ZUNE_FEATURESOVERRIDE_REGKEY = RegEdit.ZUNE_REG_PATH + "FeaturesOverride"; public override AbstractUICollection? GetDefaultOptionsUI() { diff --git a/ZuneModCore/Mods/MbidLocatorMod.cs b/ZuneModCore/Mods/MbidLocatorMod.cs index b688a86..0dd7110 100644 --- a/ZuneModCore/Mods/MbidLocatorMod.cs +++ b/ZuneModCore/Mods/MbidLocatorMod.cs @@ -7,15 +7,8 @@ using System.Threading.Tasks; namespace ZuneModCore.Mods; -public class MbidLocatorMod : Mod +public class MbidLocatorModFactory : DIModFactoryBase { - public const string ZUNE_ALBUM_ARTIST_MEDIA_ID_NAME = "ZuneAlbumArtistMediaID"; - public const string ZUNE_ALBUM_MEDIA_ID_NAME = "ZuneAlbumMediaID"; - public const string ZUNE_MEDIA_ID_NAME = "ZuneMediaID"; - public const string ZUNE_COLLECTION_ID_NAME = "ZuneCollectionID"; - - private static readonly string[] KNOWN_EXTS = [".mp3", ".mp4", ".m4a", ".wav"]; - private const string Description = "Puts MusicBrainz IDs added by MusicBrainz Picard where the Zune " + "software can use it to show additional information provided by Community Webservices.\r\n" + "Note that this will only have an effect if you have used MusicBrainz Picard on your music library."; @@ -24,6 +17,16 @@ public class MbidLocatorMod : Mod public override ModMetadata Metadata => new(nameof(MbidLocatorMod), "MusicBrainz ID Locator", Description, Author, new(1, 0)); +} + +public class MbidLocatorMod(ModMetadata metadata) : Mod(metadata) +{ + public const string ZUNE_ALBUM_ARTIST_MEDIA_ID_NAME = "ZuneAlbumArtistMediaID"; + public const string ZUNE_ALBUM_MEDIA_ID_NAME = "ZuneAlbumMediaID"; + public const string ZUNE_MEDIA_ID_NAME = "ZuneMediaID"; + public const string ZUNE_COLLECTION_ID_NAME = "ZuneCollectionID"; + + private static readonly string[] KNOWN_EXTS = [".mp3", ".mp4", ".m4a", ".wav"]; public override AbstractUICollection? GetDefaultOptionsUI() { diff --git a/ZuneModCore/Mods/VideoSyncMod.cs b/ZuneModCore/Mods/VideoSyncMod.cs index ebbc676..be9d47d 100644 --- a/ZuneModCore/Mods/VideoSyncMod.cs +++ b/ZuneModCore/Mods/VideoSyncMod.cs @@ -6,10 +6,8 @@ using System.Threading.Tasks; namespace ZuneModCore.Mods; -public class VideoSyncMod : Mod +public class VideoSyncModFactory : DIModFactoryBase { - private const int ZUNEENCENG_WMVCORA_OFFSET = 0x161E; - private const string Description = "Resolves \"Error C00D11CD\" when attempting to sync video to a Zune device using Windows 10 1607 (Anniversary Update) or newer"; @@ -17,6 +15,11 @@ public class VideoSyncMod : Mod public override ModMetadata Metadata => new(nameof(VideoSyncMod), "Fix Video Sync", Description, Author, new(2, 0)); +} + +public class VideoSyncMod(ModMetadata metadata) : Mod(metadata) +{ + private const int ZUNEENCENG_WMVCORA_OFFSET = 0x161E; public override async Task Apply() { diff --git a/ZuneModCore/Mods/WebservicesMod.cs b/ZuneModCore/Mods/WebservicesMod.cs index 48d72b2..844855d 100644 --- a/ZuneModCore/Mods/WebservicesMod.cs +++ b/ZuneModCore/Mods/WebservicesMod.cs @@ -10,7 +10,19 @@ using static ZuneModCore.Mods.FeaturesOverrideMod; namespace ZuneModCore.Mods; -public class WebservicesMod : Mod, IAsyncInit +public class WebservicesModFactory : DIModFactoryBase +{ + + private const string Description = "Partially restores online features such as the Marketplace by patching the Zune desktop software " + + "to use the community's recreation of Microsoft's Zune servers at zunes.me (instead of zune.net)."; + + private const string Author = "Joshua \"Yoshi\" Askharoun"; + + public override ModMetadata Metadata => new(nameof(WebservicesMod), "Community Webservices", + Description, Author, new(1, 1)); +} + +public class WebservicesMod(ModMetadata metadata) : Mod(metadata), IAsyncInit { private const int ZUNESERVICES_ENDPOINTS_BLOCK_OFFSET = 0x14D60; private const int ZUNESERVICES_ENDPOINTS_BLOCK_LENGTH = 0x884; @@ -34,14 +46,6 @@ public class WebservicesMod : Mod, IAsyncInit private HttpClient _client; private CancellationTokenSource _cts = new(); - private const string Description = "Partially restores online features such as the Marketplace by patching the Zune desktop software " + - "to use the community's recreation of Microsoft's Zune servers at zunes.me (instead of zune.net)."; - - private const string Author = "Joshua \"Yoshi\" Askharoun"; - - public override ModMetadata Metadata => new(nameof(WebservicesMod), "Community Webservices", - Description, Author, new(1, 1)); - public override AbstractUICollection? GetDefaultOptionsUI() { AbstractUICollection optionsUi = new(nameof(FeaturesOverrideMod)) diff --git a/ZuneModdingHelper/Pages/ModsPage.xaml.cs b/ZuneModdingHelper/Pages/ModsPage.xaml.cs index 91d5a98..c821af2 100644 --- a/ZuneModdingHelper/Pages/ModsPage.xaml.cs +++ b/ZuneModdingHelper/Pages/ModsPage.xaml.cs @@ -23,7 +23,7 @@ namespace ZuneModdingHelper.Pages _modConfig = modConfig; InitializeComponent(); - ModList.ItemsSource = Mod.GetAvailableMods(); + ModList.ItemsSource = ModManager.GetAvailableMods(); } private async void ApplyButton_Click(object sender, RoutedEventArgs e)