Skip to content

Commit b805226

Browse files
Added new experimental update format with fallback
1 parent 4a7efcb commit b805226

28 files changed

+644
-34
lines changed

Source/HedgeModManager.UI/Controls/MainWindow/Test.axaml.cs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@
1010
using HedgeModManager.UI.Controls.Modals;
1111
using HedgeModManager.UI.Models;
1212
using HedgeModManager.UI.ViewModels;
13+
using HedgeModManager.Updates;
1314
using System.Collections.Specialized;
1415
using System.Diagnostics;
16+
using System.Text.Json;
1517

1618
namespace HedgeModManager.UI.Controls.MainWindow;
1719

@@ -49,6 +51,50 @@ private void OnLoaded(object? sender, RoutedEventArgs e)
4951
Application.Current.RequestedThemeVariant = ThemeVariant.Dark;
5052
}
5153
}));
54+
viewModel.CurrentTabInfo.Buttons.Add(new("Create Update", ButtonsOLD.Y, async (b) =>
55+
{
56+
var topLevel = TopLevel.GetTopLevel(this);
57+
if (topLevel == null)
58+
return;
59+
60+
string startLocation = Path.GetDirectoryName(viewModel.GetModdableGameGeneric()?.ModLoaderConfiguration.DatabasePath) ?? string.Empty;
61+
var folderPicker = await topLevel.StorageProvider.OpenFolderPickerAsync(new()
62+
{
63+
Title = "Select source...",
64+
SuggestedStartLocation = await topLevel.StorageProvider.TryGetFolderFromPathAsync(new Uri(startLocation))
65+
});
66+
67+
if (folderPicker == null || folderPicker.Count == 0)
68+
return;
69+
70+
var folder = folderPicker[0];
71+
var updateManifest = new HMMUpdateManifest();
72+
var update = new HMMUpdate(updateManifest);
73+
74+
await new Download("Creating update...", true)
75+
.OnRun(async (d, c) =>
76+
{
77+
var progress = d.CreateProgress();
78+
progress.ReportMax(-1);
79+
80+
d.Name = "Scanning mod files...";
81+
await update.CreateFromDirectoryAsync(Utils.ConvertToPath(folder.Path), progress);
82+
d.Name = "Saving update...";
83+
progress.ReportMax(-1);
84+
string json = JsonSerializer.Serialize(updateManifest, HMMUpdate.JsonOptions);
85+
await File.WriteAllTextAsync(Path.Combine(Utils.ConvertToPath(folder.Path), "update_manifest.json"), json);
86+
}).OnError((d, e) =>
87+
{
88+
Logger.Error(e);
89+
Logger.Error($"Unexpected error while creating updates");
90+
return Task.CompletedTask;
91+
}).OnFinally((d) =>
92+
{
93+
d.Destroy();
94+
return Task.CompletedTask;
95+
}).RunAsync(viewModel);
96+
97+
}));
5298
}
5399

54100
void createCheckbox(string name)

Source/HedgeModManager.UI/Controls/Modals/GameSelectModal.axaml.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
using Avalonia.Controls;
22
using Avalonia.Interactivity;
33
using Avalonia.Markup.Xaml;
4-
using HedgeModManager.Foundation;
4+
using HedgeModManager.CoreLib;
55
using HedgeModManager.UI.Models;
66
using HedgeModManager.UI.ViewModels;
77

Source/HedgeModManager.UI/Controls/Modals/ModInfoModal.axaml.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ private async void OnUpdateClick(object? sender, RoutedEventArgs e)
6969
var viewModel = DataContext as MainWindowViewModel;
7070
if (viewModel == null)
7171
return;
72+
Close();
7273
await viewModel.CheckForModUpdatesAsync(ModViewModel.Mod, true);
7374
}
7475

Source/HedgeModManager.UI/Games.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using Avalonia.Media;
22
using Avalonia.Media.Imaging;
3-
using HedgeModManager.Foundation;
3+
using HedgeModManager.CoreLib;
44
using HedgeModManager.UI.Models;
55

66
namespace HedgeModManager.UI;

Source/HedgeModManager.UI/Languages/en-AU.axaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@
4747
<!-- Other -->
4848
<system:String x:Key="Download.Text.CheckManagerUpdate">Checking for Hedge Mod Manager updates...</system:String>
4949
<system:String x:Key="Download.Text.CheckLoaderUpdate" >Updating mod loaders...</system:String>
50-
<system:String x:Key="Download.Text.CheckModUpdate" >Checking for mod updates... {0} / {1}</system:String>
50+
<system:String x:Key="Download.Text.CheckModUpdates" >Checking for mod updates... {0} / {1}</system:String>
51+
<system:String x:Key="Download.Text.CheckModUpdate" >Checking for mod updates...</system:String>
5152
<system:String x:Key="Download.Text.DownloadCodes" >Downloading Codes...</system:String>
5253
<system:String x:Key="Download.Text.DownloadMod" >Downloading {0}...</system:String>
5354
<system:String x:Key="Download.Text.InstallMod" >Installing {0}...</system:String>

Source/HedgeModManager.UI/Models/UIGame.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using Avalonia.Media;
22
using CommunityToolkit.Mvvm.ComponentModel;
3-
using HedgeModManager.Foundation;
3+
using HedgeModManager.CoreLib;
44

55
namespace HedgeModManager.UI.Models;
66

Source/HedgeModManager.UI/ViewModels/MainWindowViewModel.cs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using Avalonia.Controls;
33
using Avalonia.Threading;
44
using CommunityToolkit.Mvvm.ComponentModel;
5+
using HedgeModManager.CoreLib;
56
using HedgeModManager.Foundation;
67
using HedgeModManager.IO;
78
using HedgeModManager.UI.CLI;
@@ -219,7 +220,7 @@ public async Task CheckForAllModUpdatesAsync()
219220
break;
220221
await CheckForModUpdatesAsync(mod, false, c);
221222
progress.ReportAdd(1);
222-
d.Name = Localize("Download.Text.CheckModUpdate", progress.Progress, progress.ProgressMax);
223+
d.Name = Localize("Download.Text.CheckModUpdates", progress.Progress, progress.ProgressMax);
223224
}
224225
d.Destroy();
225226
}).OnError((d, e) =>
@@ -233,11 +234,21 @@ public async Task CheckForAllModUpdatesAsync()
233234

234235
public async Task<UpdateInfo?> CheckForModUpdatesAsync(IMod mod, bool promptUpdate = false, CancellationToken c = default)
235236
{
237+
IsBusy = true;
238+
var download = new Download(Localize("Download.Text.CheckModUpdate"), true, -1);
239+
download.Run(this);
236240
try
237241
{
238-
if (await mod.Updater!.CheckForUpdatesAsync(c))
242+
if (await mod.Updater!.CheckForUpdatesAsync(c) == true)
239243
{
240244
var info = await mod.Updater.GetUpdateInfoAsync(c);
245+
download.Destroy();
246+
IsBusy = false;
247+
if (info == null)
248+
{
249+
Logger.Debug($"Got null update info for \"{mod.Title}\" while true for the update check");
250+
return null;
251+
}
241252
Logger.Debug($"Update found for {mod.Title}");
242253
Logger.Debug($" Current: {mod.Version}");
243254
Logger.Debug($" Latest: {info.Version}");
@@ -273,6 +284,8 @@ await CreateSimpleDownload(Localize("Download.Text.UpdateMod", mod.Title),
273284
Logger.Error($"Failed to check for updates for {mod.Title}");
274285
Logger.Error(e);
275286
}
287+
download.Destroy();
288+
IsBusy = false;
276289
return null;
277290
}
278291

Source/HedgeModManager.UI/ViewModels/Mods/ModEntryViewModel.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using Avalonia.Media.Immutable;
55
using Avalonia.Threading;
66
using CommunityToolkit.Mvvm.ComponentModel;
7+
using HedgeModManager.CoreLib;
78
using HedgeModManager.Foundation;
89
using System.ComponentModel;
910
using System.Text.RegularExpressions;

Source/HedgeModManager.UI/Views/MainWindow.axaml.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
using Avalonia.Interactivity;
33
using Avalonia.Input;
44
using Avalonia.Threading;
5+
using Avalonia.Markup.Xaml;
56
using HedgeModManager.CodeCompiler;
67
using HedgeModManager.UI.ViewModels;
7-
using Avalonia.Markup.Xaml;
88
using HedgeModManager.UI.Input;
99
using HedgeModManager.Foundation;
1010
using Avalonia;

Source/HedgeModManager/Helpers.cs

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,53 @@
1-
namespace HedgeModManager;
1+
using System.Security.Cryptography;
2+
3+
namespace HedgeModManager;
24

35
public static class Helpers
46
{
57
public static bool IsFlatpak => Environment.GetEnvironmentVariable("FLATPAK_ID") != null;
8+
9+
public static async Task<string> GetFileHashAsync(string filePath, HashAlgorithm hashAlgorithm, CancellationToken? c = default)
10+
{
11+
CancellationToken cancellationToken = c ?? CancellationToken.None;
12+
using FileStream stream = File.OpenRead(filePath);
13+
byte[] hash = await hashAlgorithm.ComputeHashAsync(stream, cancellationToken);
14+
return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
15+
}
16+
17+
public static async Task<bool> CheckFileHashAsync(string filePath, string hash, HashAlgorithm hashAlgorithm, CancellationToken? c = default)
18+
{
19+
return (await GetFileHashAsync(filePath, hashAlgorithm, c)).Equals(hash, StringComparison.InvariantCultureIgnoreCase);
20+
}
21+
22+
/// <summary>
23+
/// Converts all backslashes to forward slashes
24+
/// </summary>
25+
public static string NormalizePath(string path)
26+
{
27+
return path.Replace('\\', '/');
28+
}
29+
30+
/// <summary>
31+
/// Combines a base URL path and a file path into a single URL
32+
/// </summary>
33+
public static string CombineURL(string baseHost, string path)
34+
{
35+
return baseHost.TrimEnd('/') + '/' + path.Replace('\\', '/').TrimStart('/');
36+
}
37+
38+
/// <summary>
39+
/// Combines a base URI and a file path into a single URL
40+
/// </summary>
41+
public static string CombineURL(Uri basePath, string path)
42+
{
43+
return basePath.OriginalString.TrimEnd('/') + '/' + path.Replace('\\', '/').TrimStart('/');
44+
}
45+
46+
/// <summary>
47+
/// Encodes a URL except for forward slashes
48+
/// </summary>
49+
public static string EncodeURL(string url)
50+
{
51+
return Uri.EscapeDataString(url).Replace("%2f", "/");
52+
}
653
}

0 commit comments

Comments
 (0)