added updater

This commit is contained in:
kitbyte
2025-03-23 11:37:00 +02:00
parent 68cbbee275
commit 123307aed7
8 changed files with 228 additions and 30 deletions
+5
View File
@@ -28,5 +28,10 @@ namespace WeModPatcher
MessageBox.Show(e.ToString());
Shutdown();
}
public new static void Shutdown()
{
Current.Dispatcher.Invoke(() => Current.Shutdown());
}
}
}
+13 -2
View File
@@ -1,7 +1,18 @@
namespace WeModPatcher
using System;
using System.Reflection;
namespace WeModPatcher
{
public static class Constants
{
public const string RepositoryUrl = "https://github.com/k1tbyte/Wemod-Patcher";
public const string RepoName = "Wemod-Patcher";
public const string Owner = "k1tbyte";
public static readonly string RepositoryUrl = $"https://github.com/{Owner}/{RepoName}";
public static readonly Version Version;
static Constants()
{
Version = Assembly.GetExecutingAssembly().GetName().Version;
}
}
}
+1 -1
View File
@@ -200,7 +200,7 @@ namespace WeModPatcher.Utils
return;
}
await PatchPE();
// await PatchPE();
_logger("[PATCHER] Done!", ELogType.Success);
}
+130
View File
@@ -0,0 +1,130 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using System.Net.Http;
using System.Windows;
using Newtonsoft.Json;
namespace WeModPatcher.Utils
{
public class GitHubRelease
{
public class AssetsType
{
public string Name { get; set; }
[JsonProperty("browser_download_url")]
public string Url { get; set; }
}
[JsonProperty("tag_name")]
public string TagName { get; set; }
[JsonProperty("assets")]
public AssetsType[] Assets { get; set; }
}
public class Updater
{
private GitHubRelease _release = null;
private static readonly HttpClient _httpClient = new HttpClient()
{
DefaultRequestHeaders =
{
{ "User-Agent", "GitHub-Updater" }
}
};
private static readonly string ApiUrl = $"https://api.github.com/repos/{Constants.Owner}/{Constants.RepoName}/releases/latest";
public async Task<bool> CheckForUpdates()
{
try
{
var currentVersion = Assembly.GetExecutingAssembly().GetName().Version;
var response = await _httpClient.GetAsync(ApiUrl);
response.EnsureSuccessStatusCode();
_release = JsonConvert.DeserializeObject<GitHubRelease>(await response.Content.ReadAsStringAsync());
if (_release == null)
{
return false;
}
var latestVersion = new Version(_release.TagName);
return latestVersion > currentVersion;
}
catch (Exception e)
{
return false;
}
}
public async Task Update()
{
if (_release == null)
{
throw new Exception("No release found");
}
var asset = _release.Assets.FirstOrDefault(o => o.Name.EndsWith(".exe"));
if(asset == null)
{
throw new Exception("No asset found");
}
// download to temp
var downloadPath = Path.Combine(Path.GetTempPath(), asset.Name);
using(var response = await _httpClient.GetAsync(asset.Url))
using(var fileStream = File.Create(downloadPath))
{
response.EnsureSuccessStatusCode();
await response.Content.CopyToAsync(fileStream);
}
ApplyUpdate(downloadPath);
}
private static void ApplyUpdate(string filePath)
{
try
{
var currentExecutable = Assembly.GetExecutingAssembly().Location;
var psCommand = $"Start-Sleep -Seconds 2; " +
$"Copy-Item -Path '{filePath}' -Destination '{currentExecutable}' -Force; " +
$"Remove-Item -Path '{filePath}' -Force; " +
$"Start-Sleep -Seconds 1; " +
$"Start-Process -FilePath '{currentExecutable}';";
var startInfo = new ProcessStartInfo
{
FileName = "powershell.exe",
Arguments = $"-WindowStyle Hidden -ExecutionPolicy Bypass -Command \"{psCommand}\"",
UseShellExecute = true,
CreateNoWindow = true,
WindowStyle = ProcessWindowStyle.Hidden
};
Process.Start(startInfo);
Task.Delay(500).ContinueWith(_ =>
{
App.Shutdown();
});
}
catch (Exception ex)
{
throw new Exception($"Update failed: {ex.Message}");
}
}
}
}
+39 -22
View File
@@ -39,6 +39,18 @@
WeMod Patcher
</Bold>
</TextBlock>
<TextBlock x:Name="VersionLabel" VerticalAlignment="Bottom"
Opacity="0.7" FontSize="10" Margin="5 0 0 5"
Foreground="{DynamicResource Foreground}">
v 1.0.0
</TextBlock>
<Button Background="SpringGreen" Foreground="{DynamicResource Muted}"
FontWeight="Medium" Padding="20 0" Margin="10 5 20 5"
ToolTip="Click to update"
Command="{Binding UpdateCommand}"
Visibility="{Binding IsUpdateAvailable, Converter={StaticResource ToVisibilityConverter}}"
Content="A new version is available"/>
</StackPanel>
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
@@ -136,28 +148,33 @@
</Border>
<Grid Grid.Row="2" HorizontalAlignment="Right" Margin="10 0 10 10">
<Grid.Style>
<Style TargetType="{x:Type Grid}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsPatchEnabled}" Value="False">
<Setter Property="Cursor" Value="No"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Style>
<Button Style="{StaticResource ColoredButton}"
IsEnabled="{Binding IsPatchEnabled}"
FontWeight="Bold" FontSize="16" Width="200"
Command="{Binding ApplyPatchCommand}">Patch</Button>
</Grid>
<Button Grid.Row="2"
Margin="10 0 10 10" HorizontalAlignment="Right"
Command="{Binding RestoreBackupCommand }"
FontWeight="Bold" FontSize="16" Width="200"
Style="{StaticResource ColoredButton}"
Visibility="{Binding AlreadyPatched, Converter={StaticResource ToVisibilityConverter}}"
Content="Restore"/>
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal" Grid.Row="2" Margin="10 0 10 10">
<Grid>
<Grid HorizontalAlignment="Right" >
<Grid.Style>
<Style TargetType="{x:Type Grid}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsPatchEnabled}" Value="False">
<Setter Property="Cursor" Value="No"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Style>
<Button Style="{StaticResource ColoredButton}"
IsEnabled="{Binding IsPatchEnabled}"
FontWeight="Bold" FontSize="16" Width="200"
Command="{Binding ApplyPatchCommand}">Patch</Button>
</Grid>
<Button HorizontalAlignment="Right"
Command="{Binding RestoreBackupCommand }"
FontWeight="Bold" FontSize="16" Width="200"
Style="{StaticResource ColoredButton}"
Visibility="{Binding AlreadyPatched, Converter={StaticResource ToVisibilityConverter}}"
Content="Restore"/>
</Grid>
</StackPanel>
<DockPanel Grid.Row="2" Margin="10 0 10 10">
<StackPanel Orientation="Horizontal" VerticalAlignment="Center"
@@ -16,6 +16,7 @@ namespace WeModPatcher.View.MainWindow
{
InitializeComponent();
this.DataContext = new MainWindowVm(this);
VersionLabel.Text = Constants.Version.ToString();
Instance = this;
}
+33 -5
View File
@@ -19,6 +19,7 @@ namespace WeModPatcher.View.MainWindow
{
private readonly MainWindow _view;
public ObservableCollection<LogEntry> LogList { get; } = new ObservableCollection<LogEntry>();
private static Updater _updater = new Updater();
private string _weModPath;
@@ -43,7 +44,7 @@ namespace WeModPatcher.View.MainWindow
}
}
private bool _isPatchEnabled = false;
private bool _isPatchEnabled;
public bool IsPatchEnabled
{
@@ -51,18 +52,26 @@ namespace WeModPatcher.View.MainWindow
set => SetProperty(ref _isPatchEnabled, value);
}
private bool _alreadyPatched = false;
private bool _alreadyPatched;
public bool AlreadyPatched
{
get => _alreadyPatched;
set => SetProperty(ref _alreadyPatched, value);
}
private bool _isUpdateAvailable;
public bool IsUpdateAvailable
{
get => _isUpdateAvailable;
set => SetProperty(ref _isUpdateAvailable, value);
}
public RelayCommand SetFolderPathCommand { get; }
public RelayCommand ApplyPatchCommand { get; }
public RelayCommand RestoreBackupCommand { get; }
public AsyncRelayCommand UpdateCommand { get; }
private bool CheckWeModPath(string root)
private static bool CheckWeModPath(string root)
{
try
{
@@ -79,7 +88,7 @@ namespace WeModPatcher.View.MainWindow
{
string localAppDataPath = Environment.GetEnvironmentVariable("LOCALAPPDATA");
string defaultDir = Path.Combine(localAppDataPath, "WeMod");
string defaultDir = Path.Combine(localAppDataPath ?? "", "WeMod");
if (!Directory.Exists(defaultDir))
{
@@ -193,18 +202,37 @@ namespace WeModPatcher.View.MainWindow
});
}
private async Task OnUpdate(object param)
{
await Task.Run(async () =>
{
try
{
await _updater.Update();
}
catch (Exception e)
{
Log($"Failed to update: {e.Message}", ELogType.Error);
return;
}
Log("WeModPatcher updated successfully. Restarting...", ELogType.Success);
});
}
public MainWindowVm(MainWindow view)
{
Task.Run(async () => IsUpdateAvailable = await _updater.CheckForUpdates());
_view = view;
SetFolderPathCommand = new RelayCommand(OnFolderPathSelection);
ApplyPatchCommand = new RelayCommand(OnPatching);
RestoreBackupCommand = new RelayCommand(OnBackupRestoring);
UpdateCommand = new AsyncRelayCommand(OnUpdate);
WeModPath = FindWeModDirectory();
if (WeModPath == null)
{
Log("WeMod directory not found.", ELogType.Error);
return;
}
}
}
+6
View File
@@ -35,11 +35,15 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System"/>
<Reference Include="System.Core"/>
<Reference Include="System.Data"/>
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml"/>
<Reference Include="System.Net.Http" />
<Reference Include="System.Xaml">
<RequiredTargetFramework>4.0</RequiredTargetFramework>
</Reference>
@@ -61,6 +65,7 @@
<Compile Include="ReactiveCore\RelayCommand.cs" />
<Compile Include="Utils\Patcher.cs" />
<Compile Include="Utils\PatternScanner.cs" />
<Compile Include="Utils\Updater.cs" />
<Compile Include="View\Controls\PopupHost.xaml.cs" />
<Compile Include="View\MainWindow\Logs.cs" />
<Compile Include="View\MainWindow\MainWindow.xaml.cs" />
@@ -103,6 +108,7 @@
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<Content Include="Style\Inter_18pt-Regular.ttf" />