From 7d3d0f5e14bc547b82a6441a2693a7c1d0a72a0f Mon Sep 17 00:00:00 2001 From: HolographicHat Date: Thu, 21 Nov 2024 07:31:21 +0800 Subject: [PATCH] auto identify field ids --- lib/src/dllmain.cpp | 2 +- res/App.Designer.cs | 99 +++++++++++++----------- res/App.resx | 3 + res/App.zh.resx | 3 + res/proto/AchievementAllDataNotify.proto | 21 ----- res/proto/AchievementInfo.proto | 9 +++ res/proto/UpdateInfo.proto | 16 ++-- src/Export.cs | 48 ++++++------ src/GlobalVars.cs | 4 + src/Outputs/.gitkeep | 0 src/Parsers/AchievementAllDataNotify.cs | 97 +++++++++++++++++++++++ src/Program.cs | 6 +- src/Utilities/Extensions/Collection.cs | 16 ++++ src/Utilities/Extensions/Enumerable.cs | 14 ++++ src/Utils.cs | 16 +--- 15 files changed, 235 insertions(+), 119 deletions(-) delete mode 100644 res/proto/AchievementAllDataNotify.proto create mode 100644 src/Outputs/.gitkeep create mode 100644 src/Parsers/AchievementAllDataNotify.cs create mode 100644 src/Utilities/Extensions/Collection.cs create mode 100644 src/Utilities/Extensions/Enumerable.cs diff --git a/lib/src/dllmain.cpp b/lib/src/dllmain.cpp index 2ae46c6..3f1928c 100644 --- a/lib/src/dllmain.cpp +++ b/lib/src/dllmain.cpp @@ -132,7 +132,7 @@ DWORD __stdcall ThreadProc(LPVOID hInstance) } initFuture.get(); - + MessagePipe = CreateFileA(R"(\\.\pipe\YaeAchievementPipe)", GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr); if (MessagePipe == INVALID_HANDLE_VALUE) { diff --git a/res/App.Designer.cs b/res/App.Designer.cs index d03ac48..6ba4fb7 100644 --- a/res/App.Designer.cs +++ b/res/App.Designer.cs @@ -9,8 +9,8 @@ namespace YaeAchievement.res { using System; - - + + /// /// A strongly-typed resource class, for looking up localized strings, etc. /// @@ -22,15 +22,15 @@ namespace YaeAchievement.res { [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class App { - + private static global::System.Resources.ResourceManager resourceMan; - + private static global::System.Globalization.CultureInfo resourceCulture; - + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal App() { } - + /// /// Returns the cached ResourceManager instance used by this class. /// @@ -44,7 +44,7 @@ namespace YaeAchievement.res { return resourceMan; } } - + /// /// Overrides the current thread's CurrentUICulture property for all /// resource lookups using this strongly typed resource class. @@ -58,7 +58,7 @@ namespace YaeAchievement.res { resourceCulture = value; } } - + /// /// Looks up a localized string similar to all achievement. /// @@ -67,7 +67,7 @@ namespace YaeAchievement.res { return ResourceManager.GetString("AllAchievement", resourceCulture); } } - + /// /// Looks up a localized string similar to Please close another instance.. /// @@ -76,7 +76,7 @@ namespace YaeAchievement.res { return ResourceManager.GetString("AnotherInstance", resourceCulture); } } - + /// /// Looks up a localized string similar to YaeAchievement ({0}). /// @@ -85,7 +85,7 @@ namespace YaeAchievement.res { return ResourceManager.GetString("AppBanner", resourceCulture); } } - + /// /// Looks up a localized string similar to You need to login genshin impact before exporting.. /// @@ -94,7 +94,7 @@ namespace YaeAchievement.res { return ResourceManager.GetString("ConfigNeedStartGenshin", resourceCulture); } } - + /// /// Looks up a localized string similar to Download: {0}. /// @@ -103,7 +103,7 @@ namespace YaeAchievement.res { return ResourceManager.GetString("DownloadLink", resourceCulture); } } - + /// /// Looks up a localized string similar to Network error ({0}: {1}). /// @@ -112,9 +112,9 @@ namespace YaeAchievement.res { return ResourceManager.GetString("ExceptionNetwork", resourceCulture); } } - + /// - /// Looks up a localized string similar to Export to: + /// Looks up a localized string similar to Export to: ///[0] Cocogoat (https://cocogoat.work/achievement, Default) ///[1] Snap.HuTao ///[2] Paimon.moe @@ -130,7 +130,7 @@ namespace YaeAchievement.res { return ResourceManager.GetString("ExportChoose", resourceCulture); } } - + /// /// Looks up a localized string similar to Fail, please contact developer to get help information. /// @@ -139,7 +139,7 @@ namespace YaeAchievement.res { return ResourceManager.GetString("ExportToCocogoatFail", resourceCulture); } } - + /// /// Looks up a localized string similar to Successfully exported to cocogoat.. /// @@ -148,7 +148,7 @@ namespace YaeAchievement.res { return ResourceManager.GetString("ExportToCocogoatSuccess", resourceCulture); } } - + /// /// Looks up a localized string similar to Successfully exported to {0}. /// @@ -157,7 +157,7 @@ namespace YaeAchievement.res { return ResourceManager.GetString("ExportToFileSuccess", resourceCulture); } } - + /// /// Looks up a localized string similar to Please update Snap Hutao and retry.. /// @@ -166,7 +166,7 @@ namespace YaeAchievement.res { return ResourceManager.GetString("ExportToSnapGenshinNeedUpdate", resourceCulture); } } - + /// /// Looks up a localized string similar to Successfully exported to Snap Hutao.. /// @@ -175,7 +175,7 @@ namespace YaeAchievement.res { return ResourceManager.GetString("ExportToSnapGenshinSuccess", resourceCulture); } } - + /// /// Looks up a localized string similar to Please launch/update Teyvat Guide and retry.. /// @@ -184,7 +184,7 @@ namespace YaeAchievement.res { return ResourceManager.GetString("ExportToTauriFail", resourceCulture); } } - + /// /// Looks up a localized string similar to Successfully exported to Teyvat Guide.. /// @@ -193,7 +193,7 @@ namespace YaeAchievement.res { return ResourceManager.GetString("ExportToTauriSuccess", resourceCulture); } } - + /// /// Looks up a localized string similar to {0}. /// @@ -202,7 +202,7 @@ namespace YaeAchievement.res { return ResourceManager.GetString("ExportToWxApp1Success", resourceCulture); } } - + /// /// Looks up a localized string similar to Please update xunkong and retry.. /// @@ -211,7 +211,7 @@ namespace YaeAchievement.res { return ResourceManager.GetString("ExportToXunkongNeedUpdate", resourceCulture); } } - + /// /// Looks up a localized string similar to Successfully exported to xunkong.. /// @@ -220,7 +220,7 @@ namespace YaeAchievement.res { return ResourceManager.GetString("ExportToXunkongSuccess", resourceCulture); } } - + /// /// Looks up a localized string similar to Game process start ({0}). /// @@ -229,7 +229,7 @@ namespace YaeAchievement.res { return ResourceManager.GetString("GameLoading", resourceCulture); } } - + /// /// Looks up a localized string similar to Game exited.. /// @@ -238,7 +238,7 @@ namespace YaeAchievement.res { return ResourceManager.GetString("GameProcessExit", resourceCulture); } } - + /// /// Looks up a localized string similar to Please update genshin and retry.. /// @@ -247,7 +247,7 @@ namespace YaeAchievement.res { return ResourceManager.GetString("GenshinHashError", resourceCulture); } } - + /// /// Looks up a localized string similar to Please close game before run this application. ({0}). /// @@ -256,7 +256,7 @@ namespace YaeAchievement.res { return ResourceManager.GetString("GenshinIsRunning", resourceCulture); } } - + /// /// Looks up a localized string similar to Network error:. /// @@ -265,7 +265,7 @@ namespace YaeAchievement.res { return ResourceManager.GetString("NetworkError", resourceCulture); } } - + /// /// Looks up a localized string similar to No write permission on {0}.. /// @@ -274,7 +274,7 @@ namespace YaeAchievement.res { return ResourceManager.GetString("NoWritePermission", resourceCulture); } } - + /// /// Looks up a localized string similar to Press any key to exit.. /// @@ -283,7 +283,7 @@ namespace YaeAchievement.res { return ResourceManager.GetString("PressKeyToExit", resourceCulture); } } - + /// /// Looks up a localized string similar to Reward not taken. /// @@ -292,7 +292,7 @@ namespace YaeAchievement.res { return ResourceManager.GetString("StatusFinished", resourceCulture); } } - + /// /// Looks up a localized string similar to Invalid. /// @@ -301,7 +301,7 @@ namespace YaeAchievement.res { return ResourceManager.GetString("StatusInvalid", resourceCulture); } } - + /// /// Looks up a localized string similar to Finished. /// @@ -310,7 +310,7 @@ namespace YaeAchievement.res { return ResourceManager.GetString("StatusRewardTaken", resourceCulture); } } - + /// /// Looks up a localized string similar to Unfinished. /// @@ -319,9 +319,9 @@ namespace YaeAchievement.res { return ResourceManager.GetString("StatusUnfinished", resourceCulture); } } - + /// - /// Looks up a localized string similar to Description: + /// Looks up a localized string similar to Description: ///{0}. /// internal static string UpdateDescription { @@ -329,7 +329,7 @@ namespace YaeAchievement.res { return ResourceManager.GetString("UpdateDescription", resourceCulture); } } - + /// /// Looks up a localized string similar to Downloading update package.... /// @@ -338,7 +338,7 @@ namespace YaeAchievement.res { return ResourceManager.GetString("UpdateDownloading", resourceCulture); } } - + /// /// Looks up a localized string similar to Has update: {0} => {1}. /// @@ -347,7 +347,7 @@ namespace YaeAchievement.res { return ResourceManager.GetString("UpdateNewVersion", resourceCulture); } } - + /// /// Looks up a localized resource of type System.Byte[]. /// @@ -357,7 +357,7 @@ namespace YaeAchievement.res { return ((byte[])(obj)); } } - + /// /// Looks up a localized string similar to Upload error to appcenter.... /// @@ -366,7 +366,7 @@ namespace YaeAchievement.res { return ResourceManager.GetString("UploadError", resourceCulture); } } - + /// /// Looks up a localized string similar to Use previous fetched data? (yes|no). /// @@ -375,7 +375,7 @@ namespace YaeAchievement.res { return ResourceManager.GetString("UsePreviousData", resourceCulture); } } - + /// /// Looks up a localized string similar to Downloading Visual C++ Redistributable.... /// @@ -384,7 +384,7 @@ namespace YaeAchievement.res { return ResourceManager.GetString("VcRuntimeDownload", resourceCulture); } } - + /// /// Looks up a localized string similar to Installing Visual C++ Redistributable.... /// @@ -393,5 +393,14 @@ namespace YaeAchievement.res { return ResourceManager.GetString("VcRuntimeInstalling", resourceCulture); } } + + /// + /// Looks up a localized string similar to Please update game and retry.. + /// + internal static string WaitMetadataUpdate { + get { + return ResourceManager.GetString("WaitMetadataUpdate", resourceCulture); + } + } } } diff --git a/res/App.resx b/res/App.resx index 976c1ec..5647abf 100644 --- a/res/App.resx +++ b/res/App.resx @@ -137,4 +137,7 @@ Input a number (0-8): Please launch/update Teyvat Guide and retry. + + Please update game and retry. + \ No newline at end of file diff --git a/res/App.zh.resx b/res/App.zh.resx index 0e00eaa..36e2778 100644 --- a/res/App.zh.resx +++ b/res/App.zh.resx @@ -127,4 +127,7 @@ 在 Teyvat Guide 进行下一步操作 + + 当前元数据版本不匹配,请更新原神至最新版本或等待元数据更新后重试。 + \ No newline at end of file diff --git a/res/proto/AchievementAllDataNotify.proto b/res/proto/AchievementAllDataNotify.proto deleted file mode 100644 index f8d7dcf..0000000 --- a/res/proto/AchievementAllDataNotify.proto +++ /dev/null @@ -1,21 +0,0 @@ -syntax = "proto3"; - -option csharp_namespace = "Proto"; - -message Achievement { - enum Status { - INVALID = 0; - UNFINISHED = 1; - FINISHED = 2; - REWARD_TAKEN = 3; - } - uint32 timestamp = 11; - uint32 current = 5; - uint32 total = 15; - uint32 id = 2; - Status status = 7; -} - -message AchievementAllDataNotify { - repeated Achievement list = 4; -} diff --git a/res/proto/AchievementInfo.proto b/res/proto/AchievementInfo.proto index b9686f7..58f238b 100644 --- a/res/proto/AchievementInfo.proto +++ b/res/proto/AchievementInfo.proto @@ -2,6 +2,14 @@ syntax = "proto3"; option csharp_namespace = "Proto"; +message AchievementProtoFieldInfo { + uint32 id = 1; + uint32 status = 2; + uint32 total_progress = 3; + uint32 current_progress = 4; + uint32 finish_timestamp = 5; +} + message AchievementItem { uint32 pre = 1; uint32 group = 2; @@ -13,4 +21,5 @@ message AchievementInfo { string version = 1; map group = 2; map items = 3; + AchievementProtoFieldInfo pb_info = 4; } diff --git a/res/proto/UpdateInfo.proto b/res/proto/UpdateInfo.proto index 91f3f88..a43558b 100644 --- a/res/proto/UpdateInfo.proto +++ b/res/proto/UpdateInfo.proto @@ -3,13 +3,13 @@ syntax = "proto3"; option csharp_namespace = "Proto"; message UpdateInfo { - uint32 versionCode = 1; - string versionName = 2; + uint32 version_code = 1; + string version_name = 2; string description = 3; - string packageLink = 4; - bool forceUpdate = 5; - bool enableLibDownload = 6; - bool enableAutoDownload = 7; - string currentCNGameHash = 8; - string currentOSGameHash = 9; + string package_link = 4; + bool force_update = 5; + bool enable_lib_download = 6; + bool enable_auto_update = 7; + string current_cn_hash = 8; + string current_os_hash = 9; } diff --git a/src/Export.cs b/src/Export.cs index b7801e4..3f69fcc 100644 --- a/src/Export.cs +++ b/src/Export.cs @@ -5,9 +5,8 @@ using System.Text; using System.Text.Json; using System.Text.Json.Serialization; using Microsoft.Win32; -using Proto; +using YaeAchievement.Parsers; using YaeAchievement.res; -using static Proto.Achievement.Types; namespace YaeAchievement; @@ -120,10 +119,10 @@ public static class Export { } private static void ToPaimon(AchievementAllDataNotify data) { - var info = LoadAchievementInfo().Items.ToDictionary(pair => pair.Key, pair => pair.Value.Group); + var info = GlobalVars.AchievementInfo.Items.ToDictionary(pair => pair.Key, pair => pair.Value.Group); var final = new Dictionary>> { - ["achievement"] = data.List - .Where(achievement => achievement.Status is Status.Finished or Status.RewardTaken) + ["achievement"] = data.AchievementList + .Where(achievement => achievement.Status is AchievementStatus.Finished or AchievementStatus.RewardTaken) .Where(achievement => info.ContainsKey(achievement.Id)) .GroupBy(achievement => info[achievement.Id], achievement => achievement.Id) .OrderBy(group => group.Key) @@ -137,7 +136,7 @@ public static class Export { private static void ToSeelie(AchievementAllDataNotify data) { var output = new Dictionary>(); - foreach (var ach in data.List.Where(a => a.Status is Status.Finished or Status.RewardTaken)) { + foreach (var ach in data.AchievementList.Where(a => a.Status is AchievementStatus.Finished or AchievementStatus.RewardTaken)) { output[ach.Id] = new Dictionary { ["done"] = true }; @@ -153,23 +152,25 @@ public static class Export { // ReSharper disable once InconsistentNaming private static void ToCSV(AchievementAllDataNotify data) { - var info = LoadAchievementInfo(); + var info = GlobalVars.AchievementInfo; var outList = new List>(); - foreach (var ach in data.List.OrderBy(a => a.Id)) { + foreach (var ach in data.AchievementList.OrderBy(a => a.Id)) { if (UnusedAchievement.Contains(ach.Id)) continue; if (!info.Items.TryGetValue(ach.Id, out var achInfo) || achInfo == null) { Console.WriteLine($@"Unable to find {ach.Id} in metadata."); continue; } var finishAt = ""; - if (ach.Timestamp != 0) { - var ts = Convert.ToInt64(ach.Timestamp); + if (ach.FinishTimestamp != 0) { + var ts = Convert.ToInt64(ach.FinishTimestamp); finishAt = DateTimeOffset.FromUnixTimeSeconds(ts).ToLocalTime().ToString("yyyy/MM/dd HH:mm:ss"); } - var current = ach.Status != Status.Unfinished ? ach.Current == 0 ? ach.Total : ach.Current : ach.Current; + var current = ach.Status != AchievementStatus.Unfinished + ? ach.CurrentProgress == 0 ? ach.TotalProgress : ach.CurrentProgress + : ach.CurrentProgress; outList.Add([ ach.Id, ach.Status.ToDesc(), achInfo.Group, achInfo.Name, - achInfo.Description, current, ach.Total, finishAt + achInfo.Description, current, ach.TotalProgress, finishAt ]); } var output = new List { "ID,状态,特辑,名称,描述,当前进度,目标进度,完成时间" }; @@ -194,13 +195,13 @@ public static class Export { // ReSharper disable once InconsistentNaming private static Dictionary ExportToUIAFApp(AchievementAllDataNotify data) { - var output = data.List - .Where(a => (uint)a.Status > 1 || a.Current > 0) + var output = data.AchievementList + .Where(a => (uint)a.Status > 1 || a.CurrentProgress > 0) .Select(ach => new Dictionary { ["id"] = ach.Id, ["status"] = (uint) ach.Status, - ["current"] = ach.Current, - ["timestamp"] = ach.Timestamp + ["current"] = ach.CurrentProgress, + ["timestamp"] = ach.FinishTimestamp }) .ToList(); return new Dictionary { @@ -225,21 +226,16 @@ public static class Export { private static readonly List UnusedAchievement = [ 84517 ]; - private static string ToDesc(this Status status) { + private static string ToDesc(this AchievementStatus status) { return status switch { - Status.Invalid => App.StatusInvalid, - Status.Finished => App.StatusFinished, - Status.Unfinished => App.StatusUnfinished, - Status.RewardTaken => App.StatusRewardTaken, + AchievementStatus.Invalid => App.StatusInvalid, + AchievementStatus.Finished => App.StatusFinished, + AchievementStatus.Unfinished => App.StatusUnfinished, + AchievementStatus.RewardTaken => App.StatusRewardTaken, _ => throw new ArgumentOutOfRangeException(nameof(status), status, null) }; } - private static AchievementInfo LoadAchievementInfo() { - var b = Utils.GetBucketFileAsByteArray("schicksal/metadata"); - return AchievementInfo.Parser.ParseFrom(b); - } - public static int PrintMsgAndReturnErrCode(this Win32Exception ex, string msg) { // ReSharper disable once LocalizableElement Console.WriteLine($"{msg}: {ex.Message}"); diff --git a/src/GlobalVars.cs b/src/GlobalVars.cs index 741c4af..6ebf283 100644 --- a/src/GlobalVars.cs +++ b/src/GlobalVars.cs @@ -1,4 +1,5 @@ using System.Reflection; +using Proto; namespace YaeAchievement; @@ -26,6 +27,9 @@ public static class GlobalVars { public const string PipeName = "YaeAchievementPipe"; public const string BucketHost = "https://cn-cd-1259389942.file.myqcloud.com"; + public static AchievementInfo AchievementInfo { get; } + = AchievementInfo.Parser.ParseFrom(Utils.GetBucketFileAsByteArray("schicksal/metadata")); + static GlobalVars() { Directory.CreateDirectory(DataPath); Directory.CreateDirectory(CachePath); diff --git a/src/Outputs/.gitkeep b/src/Outputs/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/Parsers/AchievementAllDataNotify.cs b/src/Parsers/AchievementAllDataNotify.cs new file mode 100644 index 0000000..8ed964c --- /dev/null +++ b/src/Parsers/AchievementAllDataNotify.cs @@ -0,0 +1,97 @@ +using System.Runtime.CompilerServices; +using Google.Protobuf; +using YaeAchievement.res; + +namespace YaeAchievement.Parsers; + +public enum AchievementStatus { + Invalid, + Unfinished, + Finished, + RewardTaken, +} + +public class AchievementItem { + + public uint Id { get; init; } + public uint TotalProgress { get; init; } + public uint CurrentProgress { get; init; } + public uint FinishTimestamp { get; init; } + public AchievementStatus Status { get; init; } + +} + +public class AchievementAllDataNotify { + + public List AchievementList { get; private init; } = []; + + public static AchievementAllDataNotify ParseFrom(byte[] bytes) { + using var stream = new CodedInputStream(bytes); + uint tag; + var data = new List>(); + while ((tag = stream.ReadTag()) != 0) { + if ((tag & 7) == 2) { // is LengthDelimited + var dict = new Dictionary(); + using var eStream = new CodedInputStream(ReadRawBytes(stream, stream.ReadLength())); + while ((tag = eStream.ReadTag()) != 0) { + if ((tag & 7) != 0) { // not VarInt + dict = null; + break; + } + dict[tag >> 3] = eStream.ReadUInt32(); + } + if (dict != null) { + data.Add(dict); + } + } + } + if (data.Count == 0) { + return new AchievementAllDataNotify(); + } + uint tId, sId, iId, currentId, totalId; + if (data.Count > 20) { /* uwu */ + (tId, var cnt) = data // ↓ 2020-09-15 04:15:14 + .GroupKeys(value => value > 1600114514).Select(g => (g.Key, g.Count())).MaxBy(p => p.Item2); + sId = data // FINISHED ↓ ↓ REWARD_TAKEN + .GroupKeys(value => value is 2 or 3).First(g => g.Count() == cnt).Key; + iId = data // ↓ id: 8xxxx + .GroupKeys(value => value / 10000 % 10 == 8).MaxBy(g => g.Count())!.Key; + (currentId, totalId) = data + .Where(d => d[sId] is 2 or 3) + .Select(d => d.ToDictionary().RemoveValues(tId, sId, iId).ToArray()) + .Where(d => d.Length == 2 && d[0].Value != d[1].Value) + .GroupBy(a => a[0].Value > a[1].Value ? (a[0].Key, a[1].Key) : (a[1].Key, a[0].Key)) + .Select(g => (FieldIds: g.Key, Count: g.Count())) + .MaxBy(p => p.Count) + .FieldIds; + #if DEBUG + // ReSharper disable once LocalizableElement + Console.WriteLine($"Id={iId}, Status={sId}, Total={totalId}, Current={currentId}, Timestamp={tId}"); + #endif + } else { + var info = GlobalVars.AchievementInfo.PbInfo; // ... + iId = info.Id; + tId = info.FinishTimestamp; + sId = info.Status; + totalId = info.TotalProgress; + currentId = info.CurrentProgress; + if (data.Any(dict => !dict.ContainsKey(iId) || !dict.ContainsKey(sId) || !dict.ContainsKey(totalId))) { + Console.WriteLine(App.WaitMetadataUpdate); + Environment.Exit(0); + } + } + return new AchievementAllDataNotify { + AchievementList = data.Select(dict => new AchievementItem { + Id = dict[iId], + Status = (AchievementStatus) dict[sId], + TotalProgress = dict[totalId], + CurrentProgress = dict.GetValueOrDefault(currentId), + FinishTimestamp = dict.GetValueOrDefault(tId), + }).ToList() + }; + } + + [UnsafeAccessor(UnsafeAccessorKind.Method)] + private static extern byte[] ReadRawBytes(CodedInputStream stream, int size); + +} diff --git a/src/Program.cs b/src/Program.cs index 726a669..ceac811 100644 --- a/src/Program.cs +++ b/src/Program.cs @@ -1,6 +1,6 @@ using System.Text; -using Proto; using YaeAchievement; +using YaeAchievement.Parsers; using YaeAchievement.res; using static YaeAchievement.Utils; @@ -29,7 +29,7 @@ var historyCache = new CacheFile("ExportData"); AchievementAllDataNotify? data = null; try { - data = AchievementAllDataNotify.Parser.ParseFrom(historyCache.Read().Content); + data = AchievementAllDataNotify.ParseFrom(historyCache.Read().Content.ToByteArray()); } catch (Exception) { /* ignored */ } if (historyCache.LastWriteTime.AddMinutes(60) > DateTime.UtcNow && data != null) { @@ -43,7 +43,7 @@ if (historyCache.LastWriteTime.AddMinutes(60) > DateTime.UtcNow && data != null) StartAndWaitResult(AppConfig.GamePath, str => { GlobalVars.UnexpectedExit = false; var bytes = Convert.FromBase64String(str); - var list = AchievementAllDataNotify.Parser.ParseFrom(bytes); + var list = AchievementAllDataNotify.ParseFrom(bytes); historyCache.Write(bytes); Export.Choose(list); return true; diff --git a/src/Utilities/Extensions/Collection.cs b/src/Utilities/Extensions/Collection.cs new file mode 100644 index 0000000..e2ad0e1 --- /dev/null +++ b/src/Utilities/Extensions/Collection.cs @@ -0,0 +1,16 @@ +// ReSharper disable once CheckNamespace +namespace System.Collections.Generic; + +public static class Collection { + + public static IDictionary RemoveValues( + this IDictionary dictionary, + params TKey[] keys + ) { + foreach (var key in keys) { + dictionary.Remove(key); + } + return dictionary; + } + +} diff --git a/src/Utilities/Extensions/Enumerable.cs b/src/Utilities/Extensions/Enumerable.cs new file mode 100644 index 0000000..fb4c4fe --- /dev/null +++ b/src/Utilities/Extensions/Enumerable.cs @@ -0,0 +1,14 @@ +// ReSharper disable once CheckNamespace + +namespace System.Linq; + +public static class Enumerable { + + public static IEnumerable> GroupKeys( + this IEnumerable> source, + Func condition + ) where TKey : notnull { + return source.SelectMany(dict => dict.Where(pair => condition(pair.Value)).Select(pair => pair.Key)).GroupBy(x => x); + } + +} \ No newline at end of file diff --git a/src/Utils.cs b/src/Utils.cs index 0b35acd..d991fd2 100644 --- a/src/Utils.cs +++ b/src/Utils.cs @@ -93,7 +93,7 @@ public static class Utils { if (GlobalVars.AppVersionCode < info.VersionCode) { Console.WriteLine(App.UpdateNewVersion, GlobalVars.AppVersionName, info.VersionName); Console.WriteLine(App.UpdateDescription, info.Description); - if (info.EnableAutoDownload) { + if (info.EnableAutoUpdate) { Console.WriteLine(App.UpdateDownloading); var tmpPath = Path.GetTempFileName(); File.WriteAllBytes(tmpPath, GetBucketFileAsByteArray(info.PackageLink)); @@ -205,22 +205,8 @@ public static class Utils { }; } - private static bool CheckGenshinIsLatestVersion(string path) { - #if DEBUG - return true; - #else - if (!File.Exists(path)) return false; - var hash = File.ReadAllBytes(path).MD5Hash(); - return hash == _updateInfo.CurrentCNGameHash || hash == _updateInfo.CurrentOSGameHash; - #endif - } - // ReSharper disable once UnusedMethodReturnValue.Global public static Thread StartAndWaitResult(string exePath, Func onReceive) { - if (!CheckGenshinIsLatestVersion(exePath)) { - Console.WriteLine(App.GenshinHashError); - Environment.Exit(0); - } AppDomain.CurrentDomain.ProcessExit += (_, _) => { try { File.Delete(GlobalVars.LibFilePath);