diff --git a/Assets/Language_Chinese.resx b/Assets/Language_Chinese.resx
index ff473d3..15c55d2 100644
--- a/Assets/Language_Chinese.resx
+++ b/Assets/Language_Chinese.resx
@@ -166,6 +166,18 @@ https://www.github.com/tylearymf/UniHacker
{0} 正在运行中,可能会破解失败!
+
+ 还 原
+
+
+ 是否移除破解补丁?
+
+
+ 移除失败!
+
+
+ 移除成功!
+
选择
diff --git a/Assets/Language_English.resx b/Assets/Language_English.resx
index a64c00e..bfaa07e 100644
--- a/Assets/Language_English.resx
+++ b/Assets/Language_English.resx
@@ -166,6 +166,18 @@ https://www.github.com/tylearymf/UniHacker
{0} is running and the patch may fail!
+
+ Revert
+
+
+ Do you need to remove the crack patch?
+
+
+ Remove failed!
+
+
+ Successfully removed!
+
Select
diff --git a/Patcher/Hub/UnityHubPatcher.cs b/Patcher/Hub/UnityHubPatcher.cs
index 45abcf5..27b0415 100644
--- a/Patcher/Hub/UnityHubPatcher.cs
+++ b/Patcher/Hub/UnityHubPatcher.cs
@@ -21,6 +21,13 @@ public UnityHubPatcher(string filePath) : base(filePath)
{
PatchStatus = PatchStatus.Support;
}
+
+ var unityHubPath = RootPath;
+ unityHubPath = Path.Combine(unityHubPath, "resources");
+ var exportFolder = Path.Combine(unityHubPath, "app");
+ var asarBackupPath = Path.Combine(unityHubPath, "app.asar.bak");
+ if (Directory.Exists(exportFolder) || File.Exists(asarBackupPath))
+ PatchStatus = PatchStatus.Patched;
}
public async override Task<(bool success, string errorMsg)> ApplyPatch(Action progress)
@@ -81,10 +88,9 @@ public UnityHubPatcher(string filePath) : base(filePath)
if (File.Exists(asarPath) && !File.Exists(asarBackupPath))
File.Move(asarPath, asarBackupPath);
+
if (PlatformUtils.IsOSX())
- {
await PlatformUtils.MacOSRemoveQuarantine(Directory.GetParent(RootPath)!.FullName);
- }
}
else
{
@@ -94,6 +100,31 @@ public UnityHubPatcher(string filePath) : base(filePath)
return (patchResult, string.Empty);
}
+ public async override Task<(bool success, string errorMsg)> RemovePatch(Action progress)
+ {
+ var unityHubPath = RootPath;
+ unityHubPath = Path.Combine(unityHubPath, "resources");
+ var exportFolder = Path.Combine(unityHubPath, "app");
+ var asarPath = Path.Combine(unityHubPath, "app.asar");
+ var asarBackupPath = Path.Combine(unityHubPath, "app.asar.bak");
+
+ progress(0.2F);
+ await Task.Delay(200);
+
+ if (Directory.Exists(exportFolder))
+ Directory.Delete(exportFolder, true);
+
+ progress(0.7F);
+ await Task.Delay(200);
+
+ if (!File.Exists(asarPath) && File.Exists(asarBackupPath))
+ File.Move(asarBackupPath, asarPath);
+
+ progress(1F);
+ await Task.Delay(200);
+
+ return (true, string.Empty);
+ }
public static void ReplaceMethodBody(ref string scriptContent, string methodName, string newMethodContent)
{
@@ -116,9 +147,6 @@ public static bool CopyDirectory(string sourcePath, string destinationPath, bool
var ret = true;
try
{
- sourcePath = sourcePath.EndsWith(@"\") ? sourcePath : sourcePath + @"\";
- destinationPath = destinationPath.EndsWith(@"\") ? destinationPath : destinationPath + @"\";
-
if (Directory.Exists(sourcePath))
{
if (!Directory.Exists(destinationPath))
@@ -127,12 +155,13 @@ public static bool CopyDirectory(string sourcePath, string destinationPath, bool
foreach (var filePath in Directory.GetFiles(sourcePath))
{
var file = new FileInfo(filePath);
- file.CopyTo(destinationPath + file.Name, overwrite);
+ file.CopyTo(Path.Combine(destinationPath, file.Name), overwrite);
}
+
foreach (var directoryPath in Directory.GetDirectories(sourcePath))
{
var directory = new DirectoryInfo(directoryPath);
- if (!CopyDirectory(directoryPath, destinationPath + directory.Name, overwrite))
+ if (!CopyDirectory(directoryPath, Path.Combine(destinationPath, directory.Name), overwrite))
ret = false;
}
}
diff --git a/Patcher/Misc/Language.cs b/Patcher/Misc/Language.cs
index 6ca1277..5c7039c 100644
--- a/Patcher/Misc/Language.cs
+++ b/Patcher/Misc/Language.cs
@@ -8,7 +8,6 @@ public class Language
{
public const string English = "English";
public const string Chinese = "Chinese";
- public const string DefaultLanguage = English;
static ResourceManager? s_ResourceManager;
diff --git a/Patcher/Misc/Patcher.cs b/Patcher/Misc/Patcher.cs
index 1ff573b..fb87637 100644
--- a/Patcher/Misc/Patcher.cs
+++ b/Patcher/Misc/Patcher.cs
@@ -46,7 +46,7 @@ public Patcher(string filePath)
throw new NotImplementedException();
}
- public virtual async Task<(bool success, string errorMsg)> RemovePatch()
+ public virtual async Task<(bool success, string errorMsg)> RemovePatch(Action progress)
{
await Task.Yield();
throw new NotImplementedException();
diff --git a/Patcher/Unity/LicensingInfo.cs b/Patcher/Unity/LicensingInfo.cs
index 3cc260f..27e2a75 100644
--- a/Patcher/Unity/LicensingInfo.cs
+++ b/Patcher/Unity/LicensingInfo.cs
@@ -15,11 +15,8 @@ internal class LicensingInfo
internal static int s_MajorVersion;
internal static int s_MinorVersion;
- public static void TryGenerate(int majorVersion, int minorVersion)
+ static string GetLicensePath(int majorVersion, int minorVersion)
{
- s_MajorVersion = majorVersion;
- s_MinorVersion = minorVersion;
-
var commonAppData = string.Empty;
switch (PlatformUtils.GetPlatformType())
{
@@ -57,6 +54,15 @@ public static void TryGenerate(int majorVersion, int minorVersion)
else
ulfFilePath = Path.Combine(unityLicensingPath, "Unity_lic.ulf");
+ return ulfFilePath;
+ }
+
+ public static void TryGenerate(int majorVersion, int minorVersion)
+ {
+ s_MajorVersion = majorVersion;
+ s_MinorVersion = minorVersion;
+
+ var ulfFilePath = GetLicensePath(majorVersion, minorVersion);
if (File.Exists(ulfFilePath))
File.Delete(ulfFilePath);
@@ -109,6 +115,13 @@ public static void TryGenerate(int majorVersion, int minorVersion)
contents = contents.Replace("", "");
File.WriteAllText(ulfFilePath, contents);
}
+
+ public static void TryRemove(int majorVersion, int minorVersion)
+ {
+ var ulfFilePath = GetLicensePath(majorVersion, minorVersion);
+ if (File.Exists(ulfFilePath))
+ File.Delete(ulfFilePath);
+ }
}
[XmlRoot("root", Namespace = "", IsNullable = false)]
diff --git a/Patcher/Unity/UnityPatcher.cs b/Patcher/Unity/UnityPatcher.cs
index 3e68c59..67bf9bb 100644
--- a/Patcher/Unity/UnityPatcher.cs
+++ b/Patcher/Unity/UnityPatcher.cs
@@ -80,7 +80,7 @@ public UnityPatcher(string filePath) : base(filePath)
for (int j = 0; j < bytes.Length; j++)
{
if (bytes[j].HasValue)
- fileBytes[patchIndexes![i] + j] = bytes[j].Value;
+ fileBytes[patchIndexes![i] + j] = bytes[j]!.Value;
}
}
@@ -124,6 +124,37 @@ public UnityPatcher(string filePath) : base(filePath)
return (true, string.Empty);
}
+
+ public async override Task<(bool success, string errorMsg)> RemovePatch(Action progress)
+ {
+ if (patchInfo == null || patchIndexes?.Count == 0)
+ return (false, string.Empty);
+
+ progress(0.2F);
+ await Task.Delay(200);
+
+ var fileBakPath = FilePath + ".bak";
+ if (File.Exists(fileBakPath))
+ File.Move(fileBakPath, FilePath, true);
+
+ progress(0.5F);
+ await Task.Delay(200);
+
+ var licensingFilePath = Path.Combine(RootPath, "Data/Resources/Licensing/Client/Unity.Licensing.Client" + PlatformUtils.GetExtension());
+ var licensingFileBakPath = licensingFilePath + ".bak";
+ if (File.Exists(licensingFileBakPath))
+ File.Move(licensingFileBakPath, licensingFilePath);
+
+ progress(0.7F);
+ await Task.Delay(200);
+
+ LicensingInfo.TryRemove(MajorVersion, MinorVersion);
+
+ progress(1F);
+ await Task.Delay(200);
+
+ return (true, string.Empty);
+ }
}
#pragma warning restore CS8618
}
diff --git a/UniHacker.csproj b/UniHacker.csproj
index 1831361..23aa9a3 100644
--- a/UniHacker.csproj
+++ b/UniHacker.csproj
@@ -8,7 +8,7 @@
true
tylearymf
tylearymf
- 3.6
+ 3.7
com.tylearymf.unihacker
https:/www.github.com/tylearymf/unihacker
Assets\avalonia-logo.ico
diff --git a/ViewModels/MainWindowViewModel.cs b/ViewModels/MainWindowViewModel.cs
index dfb2e0b..9bcbf59 100644
--- a/ViewModels/MainWindowViewModel.cs
+++ b/ViewModels/MainWindowViewModel.cs
@@ -8,5 +8,6 @@ public class MainWindowViewModel : ViewModelBase
public string Version => Language.GetString(nameof(Version));
public string Status => Language.GetString(nameof(Status));
public string Patch_btn => Language.GetString(nameof(Patch_btn));
+ public string Revert_btn => Language.GetString(nameof(Revert_btn));
}
}
diff --git a/Views/MainWindow.axaml b/Views/MainWindow.axaml
index 45d0c7f..0fc31fd 100644
--- a/Views/MainWindow.axaml
+++ b/Views/MainWindow.axaml
@@ -4,7 +4,7 @@
xmlns:vm="using:UniHacker.ViewModels"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- mc:Ignorable="d" Width="520" Height="250" MaxWidth="520" MaxHeight="250" CanResize="False"
+ mc:Ignorable="d" Width="520" Height="270" MaxWidth="520" MaxHeight="270" CanResize="False"
x:Class="UniHacker.Views.MainWindow"
Icon="/Assets/avalonia-logo.ico">
@@ -24,25 +24,25 @@
HorizontalAlignment="Stretch"
VerticalContentAlignment="Center"
HorizontalContentAlignment="Center"
- Margin="350,-85,0,50"/>
-
+ Margin="350,-95,0,60"/>
+
-
+
+ Margin="350,110,0,30" />
+
diff --git a/Views/MainWindow.axaml.cs b/Views/MainWindow.axaml.cs
index 6f91de3..2ba5d95 100644
--- a/Views/MainWindow.axaml.cs
+++ b/Views/MainWindow.axaml.cs
@@ -3,6 +3,7 @@
using System.Diagnostics;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
+using MessageBox.Avalonia.Enums;
namespace UniHacker.Views
{
@@ -10,6 +11,7 @@ public partial class MainWindow : Window
{
public static MainWindow? Instance { private set; get; }
+ string? filePath;
Patcher? patcher;
public MainWindow()
@@ -46,10 +48,12 @@ void InitView()
SelectBtn.Click += SelectBtn_Click;
PatchBtn.Click += PatchBtn_Click;
+ RevertBtn.Click += RevertBtn_Click;
}
void UpdateFilePath(string filePath)
{
+ this.filePath = filePath;
patcher = PatchManager.GetPatcher(filePath, PlatformUtils.GetPlatformType());
var status = patcher?.PatchStatus ?? PatchStatus.Unknown;
@@ -57,6 +61,7 @@ void UpdateFilePath(string filePath)
Version.Text = patcher?.FileVersion ?? string.Empty;
Status.Text = Language.GetString(status.ToString());
PatchBtn.IsEnabled = status == PatchStatus.Support;
+ RevertBtn.IsEnabled = status == PatchStatus.Patched;
if (patcher != null)
{
@@ -77,20 +82,49 @@ async void PatchBtn_Click(object? sender, Avalonia.Interactivity.RoutedEventArgs
if (patcher == null)
return;
- PatchBtn.IsEnabled = false;
-
try
{
+ PatchBtn.IsEnabled = false;
+
(bool success, string errorMsg) = await patcher.ApplyPatch(progress => ProgressBar.Value = (int)(progress * 100));
var msg = Language.GetString(success ? "Patch_success" : "Patch_fail");
_ = await MessageBox.Show(string.Format("{0}\n\n{1}", msg, errorMsg));
+
+ UpdateFilePath(filePath!);
}
catch (Exception ex)
{
+ PatchBtn.IsEnabled = true;
_ = await MessageBox.Show(ex.ToString());
}
}
+ async void RevertBtn_Click(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
+ {
+ if (patcher == null)
+ return;
+
+ var result = await MessageBox.Show(Language.GetString("Revert_Desc"), ButtonEnum.YesNo);
+ if (result == ButtonResult.Yes)
+ {
+ try
+ {
+ RevertBtn.IsEnabled = false;
+
+ (bool success, string errorMsg) = await patcher.RemovePatch(progress => ProgressBar.Value = (int)(progress * 100));
+ var msg = Language.GetString(success ? "Revert_success" : "Revert_fail");
+ _ = await MessageBox.Show(string.Format("{0}\n\n{1}", msg, errorMsg));
+
+ UpdateFilePath(filePath!);
+ }
+ catch (Exception ex)
+ {
+ RevertBtn.IsEnabled = true;
+ _ = await MessageBox.Show(ex.ToString());
+ }
+ }
+ }
+
async void SelectBtn_Click(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
{
var dialog = new OpenFileDialog();