From 645a231fe7e7e36bec5b1c3c124c25e06dd74244 Mon Sep 17 00:00:00 2001 From: Nyaser Date: Thu, 18 Jul 2024 22:53:06 +0800 Subject: [PATCH] Fix bugs --- Form.Fixer.Designer.cs | 21 ++++ Form.Fixer.cs | 231 +++++++++++++++++++++++-------------- Form.Fixer.resx | 72 +++++++++++- Form.Installer.Designer.cs | 10 ++ Form.Installer.cs | 17 ++- Form.Installer.resx | 229 ++++++++++++++++++++---------------- Form.Main.Designer.cs | 10 ++ Form.Main.cs | 43 ++++++- Form.Main.resx | 11 +- Helper.API.cs | 22 ++-- Helper.FileInfoH.cs | 100 +++++++++++----- Helper.Resource.cs | 19 +++ Helper.StringH.cs | 5 + Helper.Worker.cs | 14 ++- 14 files changed, 558 insertions(+), 246 deletions(-) diff --git a/Form.Fixer.Designer.cs b/Form.Fixer.Designer.cs index 91a6638..ffc0c2e 100644 --- a/Form.Fixer.Designer.cs +++ b/Form.Fixer.Designer.cs @@ -28,12 +28,14 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { + components = new System.ComponentModel.Container(); System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form_Fixer)); groupBox_gameVersion = new GroupBox(); textBox_gameVersion = new TextBox(); groupBox_path = new GroupBox(); textBox_game = new TextBox(); groupBox_method = new GroupBox(); + button_cancel = new Button(); radioButton_both = new RadioButton(); radioButton_md5 = new RadioButton(); button_compare = new Button(); @@ -47,6 +49,7 @@ private void InitializeComponent() textBox_suplus = new TextBox(); groupBox1 = new GroupBox(); button_start = new Button(); + timer_RAM = new System.Windows.Forms.Timer(components); groupBox_gameVersion.SuspendLayout(); groupBox_path.SuspendLayout(); groupBox_method.SuspendLayout(); @@ -88,6 +91,7 @@ private void InitializeComponent() // // groupBox_method // + groupBox_method.Controls.Add(button_cancel); groupBox_method.Controls.Add(radioButton_both); groupBox_method.Controls.Add(radioButton_md5); groupBox_method.Controls.Add(button_compare); @@ -97,6 +101,13 @@ private void InitializeComponent() groupBox_method.Name = "groupBox_method"; groupBox_method.TabStop = false; // + // button_cancel + // + resources.ApplyResources(button_cancel, "button_cancel"); + button_cancel.Name = "button_cancel"; + button_cancel.UseVisualStyleBackColor = true; + button_cancel.Click += Button_Cancel_Click; + // // radioButton_both // resources.ApplyResources(radioButton_both, "radioButton_both"); @@ -189,6 +200,12 @@ private void InitializeComponent() button_start.UseVisualStyleBackColor = true; button_start.Click += Button_Start_Click; // + // timer_RAM + // + timer_RAM.Enabled = true; + timer_RAM.Interval = 250; + timer_RAM.Tick += Timer_RAM_Tick; + // // Form_Fixer // resources.ApplyResources(this, "$this"); @@ -203,6 +220,8 @@ private void InitializeComponent() FormBorderStyle = FormBorderStyle.FixedSingle; MaximizeBox = false; Name = "Form_Fixer"; + FormClosing += Form_Fixer_FormClosing; + FormClosed += Form_Fixer_FormClosed; Load += Form_Fixer_Load; groupBox_gameVersion.ResumeLayout(false); groupBox_gameVersion.PerformLayout(); @@ -239,5 +258,7 @@ private void InitializeComponent() private TextBox textBox_suplus; private GroupBox groupBox1; private Button button_start; + private System.Windows.Forms.Timer timer_RAM; + private Button button_cancel; } } \ No newline at end of file diff --git a/Form.Fixer.cs b/Form.Fixer.cs index 0a2b80c..24779e7 100644 --- a/Form.Fixer.cs +++ b/Form.Fixer.cs @@ -1,115 +1,170 @@ using Newtonsoft.Json; +using System.Resources; -namespace Genshin.Downloader +namespace Genshin.Downloader; + +public partial class Form_Fixer : Form { - public partial class Form_Fixer : Form + private Config? Config; + private readonly List AudioList; + private static readonly ResourceManager resourceManager = new(typeof(Form_Fixer)); + + public Form_Fixer(Dictionary args) { - private Config? Config; - private readonly List AudioList; + InitializeComponent(); + AudioList = (List)args["AudioList"]; + } - public Form_Fixer(Dictionary args) + private void Form_Fixer_Load(object sender, EventArgs e) + { + Show(); + if (StringH.WhiteSpaceCheck(Properties.Settings.Default.GamePath) is null) { - InitializeComponent(); - AudioList = (List)args["AudioList"]; + _ = MessageBox.Show(this, "未设置游戏目录!", Text, MessageBoxButtons.OK, MessageBoxIcon.Error); + Close(); return; } + textBox_game.Text = DirectoryH.EnsureExists(Properties.Settings.Default.GamePath).FullName; + Config = new Config(Properties.Settings.Default.GamePath); + textBox_gameVersion.Text = Config.Version; + } + + private bool CancellingCompare; - private void Form_Fixer_Load(object sender, EventArgs e) + private void Button_Compare_Click(object sender, EventArgs e) + { + button_cancel.Enabled = !(CancellingCompare = button_compare.Enabled = button_start.Enabled = false); + Compare().GetAwaiter().OnCompleted(() => { - Show(); - if (StringH.WhiteSpaceCheck(Properties.Settings.Default.GamePath) is null) - { - _ = MessageBox.Show(this, "未设置游戏目录!", Text, MessageBoxButtons.OK, MessageBoxIcon.Error); - Close(); return; - } - textBox_game.Text = DirectoryH.EnsureExists(Properties.Settings.Default.GamePath).FullName; - Config = new Config(Properties.Settings.Default.GamePath); - textBox_gameVersion.Text = Config.Version; - } + GC.Collect(2, GCCollectionMode.Aggressive, true, true); + GC.WaitForFullGCComplete(); + button_cancel.Enabled = !(button_compare.Enabled = button_start.Enabled = true); + }); + } - private void Button_Compare_Click(object sender, EventArgs e) + private void Button_Cancel_Click(object sender, EventArgs e) + { + CancellingCompare = true; + } + + private async Task Compare() + { + if (Config is null || Config.Channel is null) return; + groupBox_suplus.Text = resourceManager.GetString("groupBox_suplus.Text"); textBox_suplus.Clear(); + groupBox_missing.Text = resourceManager.GetString("groupBox_missing.Text"); textBox_missing.Clear(); + groupBox_progress.Text = resourceManager.GetString("groupBox_progress.Text") + " (等待服务器响应)"; + progressBar.Style = ProgressBarStyle.Marquee; + HttpClient http = new() { - button_compare.Enabled = button_start.Enabled = false; - Compare().GetAwaiter().OnCompleted(() => button_compare.Enabled = button_start.Enabled = true); + BaseAddress = new Uri(await API.GetDecompressedPath(Config.Channel)) + }; + Dictionary pkg_version = []; + pkg_version["game"] = await http.GetStringAsync($"{http.BaseAddress}/pkg_version"); + foreach (string item in AudioList) + { + pkg_version[item] = await http.GetStringAsync($"{http.BaseAddress}/{item}_pkg_version"); } - private async Task Compare() + List online = []; + online.AddRange(from KeyValuePair p in pkg_version + from string i in p.Value.Split('\n') + where StringH.WhiteSpaceCheck(i) is not null + let j = JsonConvert.DeserializeObject(i) + where j is not null + select new FileInfoH(j)); + online.Sort((FileInfoH left, FileInfoH right) => { - if (Config is null || Config.Channel is null) return; - progressBar.Style = ProgressBarStyle.Marquee; - HttpClient http = new() - { - BaseAddress = new Uri(await API.GetDecompressedPath(Config.Channel)) - }; - Dictionary pkg_version = []; - pkg_version["game"] = await http.GetStringAsync($"{http.BaseAddress}/pkg_version"); - foreach (string item in AudioList) - { - pkg_version[item] = await http.GetStringAsync($"{http.BaseAddress}/{item}_pkg_version"); - } + return (int)(left.fileSize - right.fileSize); + }); - List online = []; - online.AddRange(from KeyValuePair p in pkg_version - from string i in p.Value.Split('\n') - where StringH.WhiteSpaceCheck(i) is not null - select new FileInfoH(JsonConvert.DeserializeObject(i))); - online.Sort((FileInfoH left, FileInfoH right) => - { - return (int)(left.fileSize - right.fileSize); - }); + List local = []; + List items = []; + foreach (FileInfo item in DirectoryH.EnsureExists(textBox_game.Text).EnumerateFiles("*", SearchOption.AllDirectories)) + { + string remoteName = FileInfoH.GetRemoteName(item.FullName); + if (remoteName.Equals("config.ini") + || remoteName.EndsWith("pkg_version") + || remoteName.Contains("/webCaches/") + || remoteName.Contains("/SDKCaches/") + || (remoteName.Contains("/Persistent/") + && !remoteName.Contains("/StreamingAssets/"))) + continue; + items.Add(item); + } + items.Sort((FileInfo left, FileInfo right) => + { + return (int)(left.Length - right.Length); + }); - List local = []; - List items = []; - foreach (FileInfo item in DirectoryH.EnsureExists(textBox_game.Text).EnumerateFiles("*", SearchOption.AllDirectories)) + progressBar.Value = 0; + progressBar.Maximum = items.Count; + progressBar.Style = ProgressBarStyle.Continuous; + foreach (var item in items) + { + using (FileInfoH fi = new(item.FullName)) { - string remoteName = FileInfoH.GetRemoteName(item.FullName); - if (remoteName.Equals("config.ini") - || remoteName.EndsWith("pkg_version") - || remoteName.Contains("/webCaches/") - || remoteName.Contains("/SDKCaches/") - || (remoteName.Contains("/Persistent/") - && !remoteName.Contains("/StreamingAssets/"))) - continue; - items.Add(item); + if (radioButton_md5.Checked) await fi.ComputeMD5(); + if (radioButton_hash.Checked) await fi.ComputeHash(); + if (radioButton_both.Checked) await fi.ComputeAll(); + local.Add(fi); } - items.Sort((FileInfo left, FileInfo right) => - { - return (int)(left.Length - right.Length); - }); + progressBar.Value = local.Count; + groupBox_progress.Text = $"{resourceManager.GetString("groupBox_progress.Text")} ({local.Count} of {items.Count})"; + if (CancellingCompare) break; + } + items.Clear(); + if (CancellingCompare) return; + List surplus = local.Except(online).ToList(); + List missing = online.Except(local).ToList(); + groupBox_suplus.Text = $"{resourceManager.GetString("groupBox_suplus.Text")} ({surplus.Count} of {local.Count})"; local.Clear(); + groupBox_missing.Text = $"{resourceManager.GetString("groupBox_missing.Text")} ({missing.Count} of {online.Count})"; online.Clear(); + surplus.ForEach((i) => textBox_suplus.Text += $"{i.remoteName}\r\n"); surplus.Clear(); + missing.ForEach((i) => textBox_missing.Text += $"{i}\r\n"); missing.Clear(); + } - progressBar.Style = ProgressBarStyle.Continuous; - progressBar.Maximum = items.Count; - string text = groupBox_progress.Text; - foreach (var item in items) - { - local.Add(await FileInfoH.BuildAsync(item, radioButton_hash.Checked || radioButton_both.Checked, radioButton_md5.Checked || radioButton_both.Checked)); - progressBar.Value = local.Count; - groupBox_progress.Text = $"{text} ({local.Count} of {items.Count})"; - } - textBox_suplus.Clear(); local.Except(online).ToList().ForEach((i) => textBox_suplus.Text += $"{i}\r\n"); - textBox_missing.Clear(); online.Except(local).ToList().ForEach((i) => textBox_missing.Text += $"{i}\r\n"); + private void Button_Start_Click(object sender, EventArgs e) + { + button_compare.Enabled = button_start.Enabled = false; + StartFix().GetAwaiter().OnCompleted(() => + { + radioButton_none.Checked = true; + Button_Compare_Click(sender, e); + }); + } - _ = MessageBox.Show(this, $"比对完成啦!", Text, MessageBoxButtons.OK, MessageBoxIcon.Information); - groupBox_progress.Text = text; - progressBar.Value = 0; + private async Task StartFix() + { + if (string.IsNullOrWhiteSpace(textBox_suplus.Text) && string.IsNullOrWhiteSpace(textBox_missing.Text)) + { + _ = MessageBox.Show(this, "没有需要修复的文件!", Text, MessageBoxButtons.OK, MessageBoxIcon.Information); return; } - - private void Button_Start_Click(object sender, EventArgs e) + string version = await API.GetLatestVersion(Config?.Channel); + string path_temp = DirectoryH.EnsureNew(Properties.Settings.Default.TempPath).FullName; + if (!string.IsNullOrWhiteSpace(textBox_suplus.Text)) { - button_compare.Enabled = button_start.Enabled = false; - StartFix().GetAwaiter().OnCompleted(() => button_compare.Enabled = button_start.Enabled = true); ; + await File.AppendAllTextAsync($"{path_temp}\\deletefiles.txt", textBox_suplus.Text); textBox_suplus.Clear(); } - - private async Task StartFix() + if (!string.IsNullOrWhiteSpace(textBox_missing.Text)) { - string version = await API.GetLatestVersion(Config?.Channel); - string path_temp = DirectoryH.EnsureNew(Properties.Settings.Default.TempPath).FullName; - if (!string.IsNullOrWhiteSpace(textBox_suplus.Text)) - await File.AppendAllTextAsync($"{path_temp}\\deletefiles.txt", textBox_suplus.Text); - if (!string.IsNullOrWhiteSpace(textBox_missing.Text)) - await File.AppendAllTextAsync($"{path_temp}\\downloadfiles.txt", textBox_missing.Text); - await Worker.HPatchAsync(this, Config?.Channel); - await Worker.ApplyUpdate(this, version); - Directory.Delete(path_temp, true); + await File.AppendAllTextAsync($"{path_temp}\\downloadfiles.txt", textBox_missing.Text); textBox_missing.Clear(); } + await Worker.HPatchAsync(this, Config?.Channel); + await Worker.ApplyUpdate(this, version); + Directory.Delete(path_temp, true); + } + + private void Timer_RAM_Tick(object sender, EventArgs e) + { + Resource.MemoryManager(this, resourceManager); + } + + private void Form_Fixer_FormClosing(object sender, FormClosingEventArgs e) + { + CancellingCompare = true; + } + + private void Form_Fixer_FormClosed(object sender, FormClosedEventArgs e) + { + GC.Collect(2, GCCollectionMode.Aggressive, true, true); + GC.WaitForFullGCComplete(); } } diff --git a/Form.Fixer.resx b/Form.Fixer.resx index 640718f..b2e4ae0 100644 --- a/Form.Fixer.resx +++ b/Form.Fixer.resx @@ -216,6 +216,39 @@ 6 + + Top, Right + + + False + + + NoControl + + + 383, 22 + + + 91, 27 + + + 5 + + + 终止比对 + + + button_cancel + + + System.Windows.Forms.Button, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBox_method + + + 0 + Button @@ -234,6 +267,9 @@ Both + + MiddleCenter + radioButton_both @@ -244,7 +280,7 @@ groupBox_method - 0 + 1 Button @@ -264,6 +300,9 @@ MD5 + + MiddleCenter + radioButton_md5 @@ -274,7 +313,7 @@ groupBox_method - 1 + 2 Top, Right @@ -283,7 +322,7 @@ 286, 22 - 188, 27 + 91, 27 4 @@ -301,7 +340,7 @@ groupBox_method - 2 + 3 Button @@ -321,6 +360,9 @@ XxHash64 + + MiddleCenter + radioButton_hash @@ -331,7 +373,7 @@ groupBox_method - 3 + 4 Button @@ -351,6 +393,9 @@ FileSize Only + + MiddleCenter + radioButton_none @@ -361,7 +406,7 @@ groupBox_method - 4 + 5 12, 69 @@ -441,6 +486,9 @@ True + + Vertical + 474, 78 @@ -492,6 +540,9 @@ True + + Vertical + 474, 78 @@ -588,6 +639,9 @@ 0 + + 17, 17 + True @@ -606,6 +660,12 @@ Genshin Impact 修复器 + + timer_RAM + + + System.Windows.Forms.Timer, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089 + Form_Fixer diff --git a/Form.Installer.Designer.cs b/Form.Installer.Designer.cs index 95194bd..f70a30d 100644 --- a/Form.Installer.Designer.cs +++ b/Form.Installer.Designer.cs @@ -28,6 +28,7 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { + components = new System.ComponentModel.Container(); System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form_Installer)); groupBox_path = new GroupBox(); textBox_game = new TextBox(); @@ -45,6 +46,7 @@ private void InitializeComponent() textBox_gameVersion = new TextBox(); groupBox_install = new GroupBox(); button_start = new Button(); + timer_RAM = new System.Windows.Forms.Timer(components); groupBox_path.SuspendLayout(); groupBox_pack.SuspendLayout(); groupBox_name.SuspendLayout(); @@ -171,6 +173,12 @@ private void InitializeComponent() button_start.UseVisualStyleBackColor = true; button_start.Click += Button_Start_Click; // + // timer_RAM + // + timer_RAM.Enabled = true; + timer_RAM.Interval = 250; + timer_RAM.Tick += Timer_RAM_Tick; + // // Form_Installer // resources.ApplyResources(this, "$this"); @@ -185,6 +193,7 @@ private void InitializeComponent() FormBorderStyle = FormBorderStyle.FixedSingle; MaximizeBox = false; Name = "Form_Installer"; + FormClosed += Form_Installer_FormClosed; Load += Form_Installer_Load; groupBox_path.ResumeLayout(false); groupBox_path.PerformLayout(); @@ -219,5 +228,6 @@ private void InitializeComponent() private TextBox textBox_gameVersion; private GroupBox groupBox_install; private Button button_start; + private System.Windows.Forms.Timer timer_RAM; } } \ No newline at end of file diff --git a/Form.Installer.cs b/Form.Installer.cs index 24196d1..b781a97 100644 --- a/Form.Installer.cs +++ b/Form.Installer.cs @@ -1,15 +1,17 @@ -namespace Genshin.Downloader +using System.Resources; + +namespace Genshin.Downloader { public partial class Form_Installer : Form { private Config? Config; + private static readonly ResourceManager resourceManager = new(typeof(Form_Installer)); public Form_Installer() { InitializeComponent(); } - private void Form_Installer_Load(object sender, EventArgs e) { Show(); @@ -111,5 +113,16 @@ private async Task StartInstall() await Worker.ApplyUpdate(this, type[1] is "Game" ? version : null); } + + private void Timer_RAM_Tick(object sender, EventArgs e) + { + Resource.MemoryManager(this, resourceManager); + } + + private void Form_Installer_FormClosed(object sender, FormClosedEventArgs e) + { + GC.Collect(2, GCCollectionMode.Aggressive, true, true); + GC.WaitForFullGCComplete(); + } } } diff --git a/Form.Installer.resx b/Form.Installer.resx index 51eb192..875c94f 100644 --- a/Form.Installer.resx +++ b/Form.Installer.resx @@ -1,17 +1,17 @@  - @@ -117,6 +117,17 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 6, 22 + + + 390, 23 + + + + 0 + textBox_game @@ -129,29 +140,46 @@ 0 - 12, 12 402, 51 - 0 游戏目录 - - 6, 22 + + groupBox_path - - 390, 23 + + System.Windows.Forms.GroupBox, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089 - + + $this + + + 6 + + + + Top, Right + + + 399, 22 + + + 75, 23 + + 0 + + 选择资源 + button_browse @@ -164,6 +192,15 @@ 0 + + 6, 22 + + + 387, 23 + + + 1 + textBox_pack @@ -200,36 +237,20 @@ 5 - - - Top, Right - - - 399, 22 - - - 75, 23 - - - 0 - - - 选择资源 + + 137, 20 + + + ZIP 资源包|*.zip;*.zip.001 - + 6, 22 - - 387, 23 - - - 1 - - - 17, 17 + + 282, 23 - - ZIP 资源包|*.zip;*.zip.001 + + 0 textBox_name @@ -267,15 +288,18 @@ 4 - + 6, 22 - - 282, 23 + + 75, 23 - + 0 + + Center + textBox_type @@ -312,16 +336,16 @@ 3 - + 6, 22 - + 75, 23 - + 0 - + Center @@ -360,18 +384,30 @@ 2 - + 6, 22 - - 75, 23 + + 60, 23 - + 0 - + Center + + textBox_gameVersion + + + System.Windows.Forms.TextBox, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBox_gameVersion + + + 0 + 420, 12 @@ -396,17 +432,23 @@ 1 - - 6, 22 + + Fill - - 60, 23 + + Microsoft YaHei UI, 72pt - + + 3, 19 + + + 474, 264 + + 0 - - Center + + 启动! button_start @@ -444,27 +486,12 @@ 0 - - Fill - - - Microsoft YaHei UI, 72pt - - - 3, 19 - - - 474, 264 - - - 0 - - - 启动! - - + + 17, 17 + + True - + 7, 17 @@ -486,6 +513,12 @@ System.Windows.Forms.OpenFileDialog, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + timer_RAM + + + System.Windows.Forms.Timer, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089 + Form_Installer diff --git a/Form.Main.Designer.cs b/Form.Main.Designer.cs index c826828..a317634 100644 --- a/Form.Main.Designer.cs +++ b/Form.Main.Designer.cs @@ -28,6 +28,7 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { + components = new System.ComponentModel.Container(); System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form_Main)); groupBox_path = new GroupBox(); button_browse = new Button(); @@ -51,6 +52,7 @@ private void InitializeComponent() button_download = new Button(); groupBox_config = new GroupBox(); button_save = new Button(); + timer_RAM = new System.Windows.Forms.Timer(components); groupBox_path.SuspendLayout(); groupBox_channel.SuspendLayout(); groupBox_version.SuspendLayout(); @@ -216,6 +218,12 @@ private void InitializeComponent() button_save.UseVisualStyleBackColor = true; button_save.Click += Button_Save_Click; // + // timer_RAM + // + timer_RAM.Enabled = true; + timer_RAM.Interval = 250; + timer_RAM.Tick += Timer_RAM_Tick; + // // Form_Main // resources.ApplyResources(this, "$this"); @@ -229,6 +237,7 @@ private void InitializeComponent() Controls.Add(groupBox_path); Name = "Form_Main"; FormClosing += Form_Main_FormClosing; + FormClosed += Form_Main_FormClosed; Load += Form_Main_Load; SizeChanged += Form_Main_SizeChanged; groupBox_path.ResumeLayout(false); @@ -269,5 +278,6 @@ private void InitializeComponent() private Button button_fixer; private Button button_installer; private TextBox textBox_aria2; + private System.Windows.Forms.Timer timer_RAM; } } diff --git a/Form.Main.cs b/Form.Main.cs index af5606f..6db153e 100644 --- a/Form.Main.cs +++ b/Form.Main.cs @@ -1,10 +1,13 @@ -namespace Genshin.Downloader +using System.Resources; + +namespace Genshin.Downloader { public partial class Form_Main : Form { private readonly Dictionary ContorlSize = []; private readonly List Files = []; private string Aria2Input = ""; + private static readonly ResourceManager resourceManager = new(typeof(Form_Main)); public Form_Main() { @@ -263,13 +266,12 @@ private bool SaveConfig() private void Button_Installer_Click(object sender, EventArgs e) { - _ = SaveConfig(); - Hide(); new Form_Installer().ShowDialog(this); Show(); + using Form_Installer form = new(); + ShowDialog(form); } private void Button_Fixer_Click(object sender, EventArgs e) { - _ = SaveConfig(); Dictionary args = []; args["AudioList"] = new List(); foreach (var item in checkedListBox_voicePack.CheckedItems) @@ -277,7 +279,38 @@ private void Button_Fixer_Click(object sender, EventArgs e) string? key = StringH.GetKeyName(item.ToString()); if (key is not null) ((List)args["AudioList"]).Add(API.AudioList[key]); } - Hide(); new Form_Fixer(args).ShowDialog(this); Show(); + using Form_Fixer form = new(args); + ShowDialog(form); + } + + private void ShowDialog(Form form) + { + ArgumentNullException.ThrowIfNull(form); + + if (SaveConfig() is false) return; + + timer_RAM.Enabled = false; + + form.Shown += (object? sender, EventArgs e) => Hide(); + form.FormClosed += (object? sender, FormClosedEventArgs e) => Show(); + form.ShowDialog(this); + form.Dispose(); + + timer_RAM.Enabled = true; + + GC.Collect(2, GCCollectionMode.Aggressive, true, true); + GC.WaitForFullGCComplete(); + } + + private void Timer_RAM_Tick(object sender, EventArgs e) + { + Resource.MemoryManager(this, resourceManager); + } + + private void Form_Main_FormClosed(object sender, FormClosedEventArgs e) + { + GC.Collect(2, GCCollectionMode.Aggressive, true, true); + GC.WaitForFullGCComplete(); } } } diff --git a/Form.Main.resx b/Form.Main.resx index 6506d36..8ee5896 100644 --- a/Form.Main.resx +++ b/Form.Main.resx @@ -196,7 +196,7 @@ 6 - 17, 17 + 177, 21 [hk4e_1_0] 官方服 @@ -696,6 +696,9 @@ 0 + + 17, 17 + True @@ -720,6 +723,12 @@ System.Windows.Forms.FolderBrowserDialog, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + timer_RAM + + + System.Windows.Forms.Timer, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089 + Form_Main diff --git a/Helper.API.cs b/Helper.API.cs index 80d5091..4800305 100644 --- a/Helper.API.cs +++ b/Helper.API.cs @@ -48,16 +48,9 @@ public async static Task Get(string? channel) { if (channel is not null && ApiList.TryGetValue(channel, out string? api) && api is not null) { - HttpClient http = new(); - try - { - string data = await http.GetStringAsync(api); - return JsonConvert.DeserializeObject(data) ?? throw new Exception(); - } - finally - { - http.Dispose(); - } + using HttpClient http = new(); + string data = await http.GetStringAsync(api); + return JsonConvert.DeserializeObject(data) ?? throw new Exception(); } else { @@ -65,13 +58,18 @@ public async static Task Get(string? channel) } } + public static async Task GetLatest(string? channel) + { + return (await Get(channel)).data.game.latest; + } + public static async Task GetLatestVersion(string? channel) { - return (await Get(channel)).game.latest.version; + return (await GetLatest(channel)).version; } public static async Task GetDecompressedPath(string? channel) { - return (await Get(channel)).data.game.latest.decompressed_path; + return (await GetLatest(channel)).decompressed_path; } } diff --git a/Helper.FileInfoH.cs b/Helper.FileInfoH.cs index 5b82d9a..927b3a4 100644 --- a/Helper.FileInfoH.cs +++ b/Helper.FileInfoH.cs @@ -1,12 +1,18 @@ namespace Helper; -internal class FileInfoH +internal class FileInfoH : IDisposable { public string remoteName; public string? md5; public string? hash; public long fileSize; + private string? path; + private byte[]? data; + private Stream? stream; + + private bool disposedValue; + public FileInfoH(dynamic json) { remoteName = (string)json.remoteName; @@ -15,42 +21,40 @@ public FileInfoH(dynamic json) fileSize = (long)json.fileSize; } - public FileInfoH(FileInfo file, bool hash = false, bool md5 = false) + public FileInfoH(string file) { - if (File.Exists(file.FullName) is false) throw new FileNotFoundException("File does not exsit.", file.FullName); - remoteName = GetRemoteName(file.FullName); - fileSize = file.Length; - if (hash) foreach (byte item in System.IO.Hashing.XxHash64.Hash(File.ReadAllBytes(file.FullName))) - { - this.hash += item.ToString("x2"); - } - if (md5) foreach (byte item in System.Security.Cryptography.MD5.HashData(File.OpenRead(file.FullName))) - { - this.md5 += item.ToString("x2"); - } + if (File.Exists(file) is false) throw new FileNotFoundException("File does not exsit.", file); + path = file; + remoteName = GetRemoteName(file); + fileSize = new FileInfo(file).Length; } - public static async Task BuildAsync(FileInfo file, bool hash = false, bool md5 = false) + public async Task ComputeMD5() { - FileInfoH result = new(file); - if (hash) + if (path is null) return; + md5 = null; + stream ??= File.OpenRead(path); + foreach (byte item in await System.Security.Cryptography.MD5.HashDataAsync(stream)) { - byte[] _hash = System.IO.Hashing.XxHash64.Hash(await File.ReadAllBytesAsync(file.FullName)); - foreach (byte item in _hash) - { - result.hash += item.ToString("x2"); - } + md5 += item.ToString("x2"); } + } - if (md5) + public async Task ComputeHash() + { + if (path is null) return; + hash = null; + data ??= await File.ReadAllBytesAsync(path); + foreach (byte item in System.IO.Hashing.XxHash64.Hash(data)) { - byte[] _md5 = await System.Security.Cryptography.MD5.HashDataAsync(File.OpenRead(file.FullName)); - foreach (byte item in _md5) - { - result.md5 += item.ToString("x2"); - } + hash += item.ToString("x2"); } - return result; + } + + public async Task ComputeAll() + { + await ComputeMD5(); + await ComputeHash(); } public static string GetRemoteName(string fileName) @@ -60,7 +64,12 @@ public static string GetRemoteName(string fileName) public override string ToString() { - return $@"{{""remoteName"": ""{remoteName}"", ""md5"": ""{md5 ?? ""}"", ""hash"": ""{hash ?? ""}"", ""fileSize"": {fileSize}}}"; + string result = $"{{"; + result += $"\"remoteName\": \"{remoteName}\", "; + if (md5 is not null) result += $"\"md5\": \"{md5}\", "; + result += $"\"package_size\": {fileSize}"; + result += $"}}"; + return result; } public override int GetHashCode() @@ -84,4 +93,37 @@ public override bool Equals(object? obj) return false; return true; } + + protected virtual void Dispose(bool disposing) + { + if (!disposedValue) + { + if (disposing) + { + // TODO: ͷй״̬(йܶ) + stream?.Dispose(); + } + + // TODO: ͷδйܵԴ(δйܵĶ)дս + // TODO: ֶΪ null + path = null; + data = null; + stream = null; + disposedValue = true; + } + } + + // TODO: Dispose(bool disposing)ӵͷδйԴĴʱս + ~FileInfoH() + { + // ҪĴ˴롣뽫롰Dispose(bool disposing) + Dispose(disposing: false); + } + + public void Dispose() + { + // ҪĴ˴롣뽫롰Dispose(bool disposing) + Dispose(disposing: true); + GC.SuppressFinalize(this); + } } diff --git a/Helper.Resource.cs b/Helper.Resource.cs index b9373a7..08dd7f7 100644 --- a/Helper.Resource.cs +++ b/Helper.Resource.cs @@ -1,5 +1,6 @@ using System.Diagnostics; using System.Reflection; +using System.Resources; namespace Helper { @@ -42,6 +43,24 @@ public static async Task ProcessStartAsync(ProcessStartInfo info) } } + public static void MemoryManager(Form? form = null, ResourceManager? resourceManager = null) + { + const int MB = 1024 * 1024; + long privateMemorySize64 = Process.GetCurrentProcess().PrivateMemorySize64; + if (privateMemorySize64 >= MB * 128) + { + GC.Collect(2, + privateMemorySize64 >= MB * 256 ? + privateMemorySize64 >= MB * 1024 ? + GCCollectionMode.Aggressive : GCCollectionMode.Forced : GCCollectionMode.Optimized, + privateMemorySize64 >= MB * 512, + privateMemorySize64 >= MB * 512); + GC.WaitForFullGCComplete(); + } + if (form is not null && resourceManager is not null) + form.Text = $"{resourceManager.GetString("$this.Text")} ({privateMemorySize64 / MB} MB)"; + } + /*public static async Task GetMethod(string name) { try diff --git a/Helper.StringH.cs b/Helper.StringH.cs index 3e18b6d..860ad22 100644 --- a/Helper.StringH.cs +++ b/Helper.StringH.cs @@ -2,6 +2,11 @@ internal static class StringH { + public static string EnsureNotNull(string str) + { + return str ?? ""; + } + public static string? EmptyCheck(string? left) { return !string.IsNullOrEmpty(left) ? left : null; diff --git a/Helper.Worker.cs b/Helper.Worker.cs index dd65b56..e6cfab6 100644 --- a/Helper.Worker.cs +++ b/Helper.Worker.cs @@ -55,6 +55,10 @@ public static async Task ApplyDownload(string? channel) dynamic? json = JsonConvert.DeserializeObject(line); if (json != null) { + json.path = $"{url}/{json.remoteName}"; + json.package_size = json.fileSize; + json.fileSize = null; + json.hash = null; File2Down? file = await File2Down.BuildAsync(json); if (file is not null && !string.IsNullOrEmpty(file.remoteName)) { @@ -64,9 +68,9 @@ public static async Task ApplyDownload(string? channel) } } string input = Aria2.GetInput([.. files]); - System.Runtime.CompilerServices.TaskAwaiter taskAwaiter = Aria2.DownloadAsync(input, DirectoryH.EnsureExists(Properties.Settings.Default.DownPath).FullName, 0).GetAwaiter(); - taskAwaiter.OnCompleted(() => File.Delete(download_file)); - return taskAwaiter.GetResult(); + int exitCode = await Aria2.DownloadAsync(input, DirectoryH.EnsureExists(Properties.Settings.Default.TempPath).FullName, 0); + if (exitCode is 0) File.Delete(download_file); + return exitCode; } public static async Task ApplyHDiff() @@ -74,7 +78,7 @@ public static async Task ApplyHDiff() string path_game = DirectoryH.EnsureExists(Properties.Settings.Default.GamePath).FullName; string path_temp = DirectoryH.EnsureExists(Properties.Settings.Default.TempPath).FullName; string hdiff_file = $"{path_temp}\\hdifffiles.txt"; - string batch_file = Path.GetTempFileName(); //$"{path_temp}\\hdifffiles.bat"; + string batch_file = Path.GetTempFileName(); string hpatchz = await Resource.GetTempFileAsync("hpatchz.exe"); StreamReader reader = new(hdiff_file); StreamWriter writer = new(batch_file, false, new UTF8Encoding(false)); @@ -129,7 +133,7 @@ public static async Task ApplyUpdate(Form? owner = null, string? version = null) { await process.WaitForExitAsync(); } - if (process?.ExitCode is not 0) + if (process?.ExitCode is 0) { if (version is not null) {