diff --git a/ZuneModCore/ModResources.Designer.cs b/ZuneModCore/ModResources.Designer.cs
new file mode 100644
index 0000000..2e297b1
--- /dev/null
+++ b/ZuneModCore/ModResources.Designer.cs
@@ -0,0 +1,73 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace ZuneModCore {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class ModResources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal ModResources() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ZuneModCore.ModResources", typeof(ModResources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Byte[].
+ ///
+ internal static byte[] WMVCORE {
+ get {
+ object obj = ResourceManager.GetObject("WMVCORE", resourceCulture);
+ return ((byte[])(obj));
+ }
+ }
+ }
+}
diff --git a/ZuneModCore/ModResources.resx b/ZuneModCore/ModResources.resx
new file mode 100644
index 0000000..b4a4c4f
--- /dev/null
+++ b/ZuneModCore/ModResources.resx
@@ -0,0 +1,124 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+
+ Resources\WMVCORE.DLL;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/ZuneModCore/Mods/FeaturesOverrideMod.cs b/ZuneModCore/Mods/FeaturesOverrideMod.cs
index db3ba34..af1a82b 100644
--- a/ZuneModCore/Mods/FeaturesOverrideMod.cs
+++ b/ZuneModCore/Mods/FeaturesOverrideMod.cs
@@ -28,27 +28,27 @@ namespace ZuneModCore.Mods
// The ID is the name of the registry key, the label is the display name
new AbstractBooleanUIElement("Apps", "Apps"),
- //new AbstractBooleanUIElement("Art", "Art"),
+ new AbstractBooleanUIElement("Art", "Art"),
new AbstractBooleanUIElement("Channels", "Channels"),
- //new AbstractBooleanUIElement("FirstLaunchIntroVideo", "First Launch Intro Video"),
+ new AbstractBooleanUIElement("FirstLaunchIntroVideo", "First Launch Intro Video"),
new AbstractBooleanUIElement("Games", "Games"),
new AbstractBooleanUIElement("Marketplace", "Marketplace"),
- //new AbstractBooleanUIElement("MBRPreview", "MBRPreview"),
- //new AbstractBooleanUIElement("MBRPurchase", "MBRPurchase"),
- //new AbstractBooleanUIElement("MBRRental", "MBRRental"),
+ new AbstractBooleanUIElement("MBRPreview", "[Marketplace] Media Preview"),
+ new AbstractBooleanUIElement("MBRPurchase", "[Marketplace] Media Purchase"),
+ new AbstractBooleanUIElement("MBRRental", "[Marketplace] Media Rental"),
new AbstractBooleanUIElement("Music", "Music"),
- new AbstractBooleanUIElement("MusicVideos", "MusicVideos"),
+ new AbstractBooleanUIElement("MusicVideos", "Music Videos"),
new AbstractBooleanUIElement("Nowplaying", "Now Playing"),
- //new AbstractBooleanUIElement("NowplayingArt", "Now Playing Art"),
+ new AbstractBooleanUIElement("NowplayingArt", "Now Playing Art"),
new AbstractBooleanUIElement("Picks", "Picks"),
new AbstractBooleanUIElement("Podcasts", "Podcasts"),
new AbstractBooleanUIElement("QuickMixLocal", "Quick Mix (Local)"),
- //new AbstractBooleanUIElement("QuickMixZMP", "Quick Mix (ZMP)"),
+ new AbstractBooleanUIElement("QuickMixZMP", "Quick Mix (ZMP)"),
new AbstractBooleanUIElement("Quickplay", "Quickplay"),
- //new AbstractBooleanUIElement("Sign In Available", "Sign In"),
+ new AbstractBooleanUIElement("Sign In Available", "Sign In"),
new AbstractBooleanUIElement("Social", "Social"),
- //new AbstractBooleanUIElement("SocialMarketplace", "Social Marketplace"),
- //new AbstractBooleanUIElement("SubscriptionFreeTracks", "Subscription Free Tracks"),
+ new AbstractBooleanUIElement("SocialMarketplace", "Social Marketplace"),
+ new AbstractBooleanUIElement("SubscriptionFreeTracks", "Subscription Free Tracks"),
new AbstractBooleanUIElement("Videos", "Videos"),
}
};
@@ -69,12 +69,14 @@ namespace ZuneModCore.Mods
return Task.CompletedTask;
}
- public override async Task Apply()
+ public override async Task Apply() => await Apply(false);
+
+ public async Task Apply(bool applyAll = false)
{
- // TODO: Use user choices from AbstractUI
+ // Use user choices from AbstractUI
foreach (AbstractUIElement uiElem in OptionsUI.Items)
{
- if (uiElem is AbstractBooleanUIElement boolElem)// && boolElem.State)
+ if (uiElem is AbstractBooleanUIElement boolElem && (boolElem.State || applyAll))
{
bool isSuccess = SetFeatureOverride(boolElem.Id, true);
if (!isSuccess)
@@ -96,13 +98,13 @@ namespace ZuneModCore.Mods
return null;
}
- public override Task Reset()
+ public override async Task Reset()
{
foreach (AbstractUIElement uiElem in OptionsUI.Items)
if (uiElem is AbstractBooleanUIElement boolElem)
ResetFeatureOverride(boolElem.Id);
- return Task.FromResult(null);
+ return null;
}
public static bool SetFeatureOverride(string feature, bool value) =>
diff --git a/ZuneModCore/Mods/VideoSyncMod.cs b/ZuneModCore/Mods/VideoSyncMod.cs
index a2c7c3c..95714fd 100644
--- a/ZuneModCore/Mods/VideoSyncMod.cs
+++ b/ZuneModCore/Mods/VideoSyncMod.cs
@@ -26,7 +26,7 @@ namespace ZuneModCore.Mods
public override AbstractUIElementGroup? OptionsUI => null;
#pragma warning disable CA1416 // Validate platform compatibility
- public override Task Apply()
+ public override async Task Apply()
{
// Make a backup of the original file
FileVersionInfo wmvDllVersionInfo = FileVersionInfo.GetVersionInfo(WMVCORE_PATH);
@@ -34,7 +34,7 @@ namespace ZuneModCore.Mods
File.Copy(WMVCORE_PATH, Path.Combine(StorageDirectory, "WMVCORE.original.dll"), true);
// Get the working WMVCORE.dll
- string sourcePath = Path.Combine(AppContext.BaseDirectory, "Resources\\WMVCORE.dll");
+ byte[] wmvDllAniv = ModResources.WMVCORE;
// Get the original WMVCORE.dll
FileInfo wmvDllInfo = new(WMVCORE_PATH);
@@ -50,7 +50,7 @@ namespace ZuneModCore.Mods
FileSecurity security = wmvDllInfo.GetAccessControl();
SecurityIdentifier? cu = WindowsIdentity.GetCurrent().User;
if (cu == null)
- return Task.FromResult("Failed to set permissions on WMVCORE.dll, current user was null");
+ return "Failed to set permissions on WMVCORE.dll, current user was null.";
// Set owner to current user
security.SetOwner(cu);
@@ -59,18 +59,18 @@ namespace ZuneModCore.Mods
// Update the Access Control on the original WMVCORE.dll
wmvDllInfo.SetAccessControl(security);
- // Copy the pre-Anniversary Update WMVCORE.dll
- File.Copy(sourcePath, WMVCORE_PATH, true);
+ // Replace with pre-Anniversary Update WMVCORE.dll
+ await File.WriteAllBytesAsync(wmvDllInfo.FullName, wmvDllAniv);
- return Task.FromResult(null);
+ return null;
}
catch (IOException)
{
- return Task.FromResult($"Unable to replace '{wmvDllInfo.FullName}'. Verify that Zune and Windows Media Player are not running and try again.");
+ return $"Unable to replace '{wmvDllInfo.FullName}'. Verify that Zune and Windows Media Player are not running and try again.";
}
catch (Exception ex)
{
- return Task.FromResult(ex.Message)!;
+ return ex.Message;
}
}
#pragma warning restore CA1416 // Validate platform compatibility
diff --git a/ZuneModCore/Mods/WebservicesMod.cs b/ZuneModCore/Mods/WebservicesMod.cs
index 632c7cd..93d40a8 100644
--- a/ZuneModCore/Mods/WebservicesMod.cs
+++ b/ZuneModCore/Mods/WebservicesMod.cs
@@ -21,17 +21,28 @@ namespace ZuneModCore.Mods
public override string Author => "Joshua \"Yoshi\" Askharoun";
- public override AbstractUIElementGroup? OptionsUI => null;
+ public override AbstractUIElementGroup? OptionsUI => new(nameof(FeaturesOverrideMod))
+ {
+ Title = string.Empty,
+ Items =
+ {
+ new AbstractTextBox("hostBox", "zunes.tk", "zune.net")
+ {
+ Title = "Host",
+ TooltipText = "The host where the replacement servers are located. Must be the same length as \"zune.net\"."
+ }
+ }
+ };
public override IReadOnlyList? DependentMods => null;
- public override Task Apply()
+ public override async Task Apply()
{
// Verify that ZuneServices.dll exists
FileInfo zsDllInfo = new(Path.Combine(ZuneInstallDir, "ZuneService.dll"));
if (!zsDllInfo.Exists)
{
- return Task.FromResult($"The file '{zsDllInfo.FullName}' does not exist.");
+ return $"The file '{zsDllInfo.FullName}' does not exist.";
}
// Make a backup if it doesn't already exist
@@ -53,17 +64,30 @@ namespace ZuneModCore.Mods
var versionBytes = zsDllReader.ReadBytes(6);
if (versionBytes[0] != '4' || versionBytes[2] != '.' || versionBytes[4] != '8')
{
- return Task.FromResult("This mod has not been tested on versions earlier than 4.8.");
+ return "This mod has not been tested on versions earlier than 4.8.";
}
- // Patch ZuneServices.dll to use zunes.tk instead of zune.net
+ // Get and validate replacement host
+ string oldHost = "zune.net";
+ string newHost = ((AbstractTextBox)OptionsUI!.Items[0]).Value;
+ if (newHost.Length != oldHost.Length)
+ {
+ return $"The new host (\"{newHost}\") must have the same length as \"{oldHost}\".";
+ }
+ var ping = await new System.Net.NetworkInformation.Ping().SendPingAsync(newHost);
+ if (ping.Status != System.Net.NetworkInformation.IPStatus.Success)
+ {
+ return $"Failed to reach \"{newHost}\". Ping status: {ping.Status}";
+ }
+
+ // Patch ZuneServices.dll to use the new host 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");
+ endpointBlock = endpointBlock.Replace(oldHost, newHost);
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.");
+ return "Failed to safely overwrite strings in DLL.";
}
zsDllWriter.Seek(ZUNESERVICES_ENDPOINTS_BLOCK_OFFSET, SeekOrigin.Begin);
zsDllWriter.Write(endpointBytes);
@@ -75,29 +99,36 @@ namespace ZuneModCore.Mods
setOverrideSuccess &= SetFeatureOverride("Channels", true);
setOverrideSuccess &= SetFeatureOverride("Games", true);
setOverrideSuccess &= SetFeatureOverride("Marketplace", true);
+ setOverrideSuccess &= SetFeatureOverride("MBRPreview", true);
+ setOverrideSuccess &= SetFeatureOverride("MBRPurchase", true);
+ setOverrideSuccess &= SetFeatureOverride("MBRRental", true);
setOverrideSuccess &= SetFeatureOverride("Music", true);
setOverrideSuccess &= SetFeatureOverride("MusicVideos", true);
+ setOverrideSuccess &= SetFeatureOverride("Picks", true);
setOverrideSuccess &= SetFeatureOverride("Podcasts", true);
+ setOverrideSuccess &= SetFeatureOverride("Sign In Available", true);
setOverrideSuccess &= SetFeatureOverride("Social", true);
+ setOverrideSuccess &= SetFeatureOverride("SocialMarketplace", true);
+ setOverrideSuccess &= SetFeatureOverride("SubscriptionFreeTracks", true);
setOverrideSuccess &= SetFeatureOverride("Videos", true);
if (setOverrideSuccess != true)
{
- return Task.FromResult("Unable to set feature overrides. The mod was successful, but you may not be able to see it in the Zune Software.");
+ return "Unable to set feature overrides. The mod was successful, but you may not be able to see it in the Zune Software.";
}
- return Task.FromResult(null);
+ return null;
}
catch (IOException)
{
- return Task.FromResult($"Unable to replace '{zsDllInfo.FullName}'. Verify that the Zune software is not running and try again.");
+ return $"Unable to replace '{zsDllInfo.FullName}'. Verify that the Zune software is not running and try again.";
}
catch (Exception ex)
{
- return Task.FromResult(ex.Message);
+ return ex.Message;
}
}
- public override Task Reset()
+ public override async Task Reset()
{
string zsDllPath = Path.Combine(ZuneInstallDir, "ZuneService.dll");
try
@@ -111,25 +142,32 @@ namespace ZuneModCore.Mods
setOverrideSuccess &= SetFeatureOverride("Channels", false);
setOverrideSuccess &= SetFeatureOverride("Games", false);
setOverrideSuccess &= SetFeatureOverride("Marketplace", false);
+ setOverrideSuccess &= SetFeatureOverride("MBRPreview", false);
+ setOverrideSuccess &= SetFeatureOverride("MBRPurchase", false);
+ setOverrideSuccess &= SetFeatureOverride("MBRRental", false);
setOverrideSuccess &= SetFeatureOverride("Music", false);
setOverrideSuccess &= SetFeatureOverride("MusicVideos", false);
+ setOverrideSuccess &= SetFeatureOverride("Picks", false);
setOverrideSuccess &= SetFeatureOverride("Podcasts", false);
+ setOverrideSuccess &= SetFeatureOverride("Sign In Available", false);
setOverrideSuccess &= SetFeatureOverride("Social", false);
+ setOverrideSuccess &= SetFeatureOverride("SocialMarketplace", false);
+ setOverrideSuccess &= SetFeatureOverride("SubscriptionFreeTracks", false);
setOverrideSuccess &= SetFeatureOverride("Videos", false);
if (setOverrideSuccess != true)
{
- return Task.FromResult("Unable to reset feature overrides. The mod was successfully removed, but you may still be able to see it in the Zune Software.");
+ return "Unable to reset feature overrides. The mod was successfully removed, but you may still be able to see it in the Zune Software.";
}
- return Task.FromResult(null);
+ return null;
}
catch (IOException)
{
- return Task.FromResult($"Unable to replace '{zsDllPath}'. Verify that the Zune software is not running and try again.");
+ return $"Unable to replace '{zsDllPath}'. Verify that the Zune software is not running and try again.";
}
catch (Exception ex)
{
- return Task.FromResult(ex.Message);
+ return ex.Message;
}
}
}
diff --git a/ZuneModCore/ZuneModCore.csproj b/ZuneModCore/ZuneModCore.csproj
index 220bf66..bd600dc 100644
--- a/ZuneModCore/ZuneModCore.csproj
+++ b/ZuneModCore/ZuneModCore.csproj
@@ -1,4 +1,4 @@
-
+
net5.0
@@ -9,15 +9,26 @@
-
+
-
- PreserveNewest
-
+
+ ResXFileCodeGenerator
+ ModResources.Designer.cs
+
+
+ True
+ True
+ ModResources.resx
+
+
+
+
+ Never
+
diff --git a/ZuneModdingHelper/MainWindow.xaml.cs b/ZuneModdingHelper/MainWindow.xaml.cs
index 13bb110..1cbe2e1 100644
--- a/ZuneModdingHelper/MainWindow.xaml.cs
+++ b/ZuneModdingHelper/MainWindow.xaml.cs
@@ -47,51 +47,48 @@ namespace ZuneModdingHelper
private async void ModInstallButton_Click(object sender, RoutedEventArgs e)
{
- var progDialog = await this.ShowProgressAsync("Getting ready...", "Preparing to apply mods", settings: defaultMetroDialogSettings);
+ var progDialog = await this.ShowProgressAsync("Getting ready...", "Preparing to apply mod", settings: defaultMetroDialogSettings);
+ Mod mod = (Mod)((FrameworkElement)sender).DataContext;
Mod.ZuneInstallDir = ZuneInstallDirBox.Text;
- var selectedMods = ModList.SelectedItems.Cast();
- progDialog.Maximum = selectedMods.Count() * 2;
+ progDialog.Maximum = 2;
int numCompleted = 0;
- progDialog.SetTitle("Installing mods...");
- foreach (Mod mod in selectedMods)
+ progDialog.SetTitle($"Installing '{mod.Title}'");
+ progDialog.SetMessage($"Preparing to install...");
+ await mod.Init();
+ progDialog.SetProgress(++numCompleted);
+
+ // TODO: Implement AbstractUI display for options
+ //if (mod.OptionsUI != null)
+ //{
+ // var optionsDialog = new AbstractUIGroupDialog();
+ // optionsDialog.OptionsUIPresenter.ViewModel = new AbstractUIElementGroupViewModel(mod.OptionsUI);
+ // optionsDialog.ShowDialog();
+ //}
+
+ progDialog.SetMessage($"Applying mod...");
+ string applyResult = await mod.Apply();
+ if (applyResult != null)
{
- progDialog.SetMessage($"Setting up '{mod.Title}'");
- await mod.Init();
- progDialog.SetProgress(++numCompleted);
-
- // TODO: Implement AbstractUI display for options
- //if (mod.OptionsUI != null)
- //{
- // var optionsDialog = new AbstractUIGroupDialog();
- // optionsDialog.OptionsUIPresenter.ViewModel = new AbstractUIElementGroupViewModel(mod.OptionsUI);
- // optionsDialog.ShowDialog();
- //}
-
- progDialog.SetMessage($"Applying '{mod.Title}'");
- string applyResult = await mod.Apply();
- if (applyResult != null)
- {
- progDialog.SetMessage($"Failed to apply '{mod.Title}':\r\n{applyResult}");
-
- Analytics.TrackEvent("Failed to apply mod", new Dictionary {
- { "ModID", mod.Id },
- { "ErrorMessage", applyResult }
- });
-
- await Task.Delay(15000);
- continue;
- }
- progDialog.SetProgress(++numCompleted);
-
- Analytics.TrackEvent("Applied mod", new Dictionary {
+ Analytics.TrackEvent("Failed to apply mod", new Dictionary {
{ "ModID", mod.Id },
+ { "ErrorMessage", applyResult }
});
+
+ await progDialog.CloseAsync();
+ await this.ShowMessageAsync($"Failed to apply '{mod.Title}'", applyResult, settings: defaultMetroDialogSettings);
+
+ return;
}
+ progDialog.SetProgress(++numCompleted);
+
+ Analytics.TrackEvent("Applied mod", new Dictionary {
+ { "ModID", mod.Id },
+ });
await progDialog.CloseAsync();
- await this.ShowMessageAsync("Completed", "Finished installing selected mods", settings: defaultMetroDialogSettings);
+ await this.ShowMessageAsync("Completed", $"Installed '{mod.Title}'", settings: defaultMetroDialogSettings);
}
private async void ModResetButton_Click(object sender, RoutedEventArgs e)