mirror of
https://github.com/HolographicHat/Yae.git
synced 2026-03-19 19:09:45 +08:00
auto identify field ids
This commit is contained in:
@@ -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)
|
||||
{
|
||||
|
||||
99
res/App.Designer.cs
generated
99
res/App.Designer.cs
generated
@@ -9,8 +9,8 @@
|
||||
|
||||
namespace YaeAchievement.res {
|
||||
using System;
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
@@ -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() {
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
@@ -44,7 +44,7 @@ namespace YaeAchievement.res {
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to all achievement.
|
||||
/// </summary>
|
||||
@@ -67,7 +67,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("AllAchievement", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Please close another instance..
|
||||
/// </summary>
|
||||
@@ -76,7 +76,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("AnotherInstance", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to YaeAchievement ({0}).
|
||||
/// </summary>
|
||||
@@ -85,7 +85,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("AppBanner", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to You need to login genshin impact before exporting..
|
||||
/// </summary>
|
||||
@@ -94,7 +94,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("ConfigNeedStartGenshin", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Download: {0}.
|
||||
/// </summary>
|
||||
@@ -103,7 +103,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("DownloadLink", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Network error ({0}: {1}).
|
||||
/// </summary>
|
||||
@@ -112,9 +112,9 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("ExceptionNetwork", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Fail, please contact developer to get help information.
|
||||
/// </summary>
|
||||
@@ -139,7 +139,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("ExportToCocogoatFail", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Successfully exported to cocogoat..
|
||||
/// </summary>
|
||||
@@ -148,7 +148,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("ExportToCocogoatSuccess", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Successfully exported to {0}.
|
||||
/// </summary>
|
||||
@@ -157,7 +157,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("ExportToFileSuccess", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Please update Snap Hutao and retry..
|
||||
/// </summary>
|
||||
@@ -166,7 +166,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("ExportToSnapGenshinNeedUpdate", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Successfully exported to Snap Hutao..
|
||||
/// </summary>
|
||||
@@ -175,7 +175,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("ExportToSnapGenshinSuccess", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Please launch/update Teyvat Guide and retry..
|
||||
/// </summary>
|
||||
@@ -184,7 +184,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("ExportToTauriFail", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Successfully exported to Teyvat Guide..
|
||||
/// </summary>
|
||||
@@ -193,7 +193,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("ExportToTauriSuccess", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to {0}.
|
||||
/// </summary>
|
||||
@@ -202,7 +202,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("ExportToWxApp1Success", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Please update xunkong and retry..
|
||||
/// </summary>
|
||||
@@ -211,7 +211,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("ExportToXunkongNeedUpdate", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Successfully exported to xunkong..
|
||||
/// </summary>
|
||||
@@ -220,7 +220,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("ExportToXunkongSuccess", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Game process start ({0}).
|
||||
/// </summary>
|
||||
@@ -229,7 +229,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("GameLoading", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Game exited..
|
||||
/// </summary>
|
||||
@@ -238,7 +238,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("GameProcessExit", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Please update genshin and retry..
|
||||
/// </summary>
|
||||
@@ -247,7 +247,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("GenshinHashError", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Please close game before run this application. ({0}).
|
||||
/// </summary>
|
||||
@@ -256,7 +256,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("GenshinIsRunning", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Network error:.
|
||||
/// </summary>
|
||||
@@ -265,7 +265,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("NetworkError", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to No write permission on {0}..
|
||||
/// </summary>
|
||||
@@ -274,7 +274,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("NoWritePermission", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Press any key to exit..
|
||||
/// </summary>
|
||||
@@ -283,7 +283,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("PressKeyToExit", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Reward not taken.
|
||||
/// </summary>
|
||||
@@ -292,7 +292,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("StatusFinished", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Invalid.
|
||||
/// </summary>
|
||||
@@ -301,7 +301,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("StatusInvalid", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Finished.
|
||||
/// </summary>
|
||||
@@ -310,7 +310,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("StatusRewardTaken", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Unfinished.
|
||||
/// </summary>
|
||||
@@ -319,9 +319,9 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("StatusUnfinished", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Description:
|
||||
/// Looks up a localized string similar to Description:
|
||||
///{0}.
|
||||
/// </summary>
|
||||
internal static string UpdateDescription {
|
||||
@@ -329,7 +329,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("UpdateDescription", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Downloading update package....
|
||||
/// </summary>
|
||||
@@ -338,7 +338,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("UpdateDownloading", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Has update: {0} => {1}.
|
||||
/// </summary>
|
||||
@@ -347,7 +347,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("UpdateNewVersion", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Byte[].
|
||||
/// </summary>
|
||||
@@ -357,7 +357,7 @@ namespace YaeAchievement.res {
|
||||
return ((byte[])(obj));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Upload error to appcenter....
|
||||
/// </summary>
|
||||
@@ -366,7 +366,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("UploadError", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Use previous fetched data? (yes|no).
|
||||
/// </summary>
|
||||
@@ -375,7 +375,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("UsePreviousData", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Downloading Visual C++ Redistributable....
|
||||
/// </summary>
|
||||
@@ -384,7 +384,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("VcRuntimeDownload", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Installing Visual C++ Redistributable....
|
||||
/// </summary>
|
||||
@@ -393,5 +393,14 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("VcRuntimeInstalling", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Please update game and retry..
|
||||
/// </summary>
|
||||
internal static string WaitMetadataUpdate {
|
||||
get {
|
||||
return ResourceManager.GetString("WaitMetadataUpdate", resourceCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,4 +137,7 @@ Input a number (0-8): </value>
|
||||
<data name="ExportToTauriFail" xml:space="preserve">
|
||||
<value>Please launch/update Teyvat Guide and retry.</value>
|
||||
</data>
|
||||
<data name="WaitMetadataUpdate" xml:space="preserve">
|
||||
<value>Please update game and retry.</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -127,4 +127,7 @@
|
||||
<data name="ExportToTauriSuccess" xml:space="preserve">
|
||||
<value>在 Teyvat Guide 进行下一步操作</value>
|
||||
</data>
|
||||
<data name="WaitMetadataUpdate" xml:space="preserve">
|
||||
<value>当前元数据版本不匹配,请更新原神至最新版本或等待元数据更新后重试。</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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<uint32, string> group = 2;
|
||||
map<uint32, AchievementItem> items = 3;
|
||||
AchievementProtoFieldInfo pb_info = 4;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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<string, Dictionary<uint, Dictionary<uint, bool>>> {
|
||||
["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<uint, Dictionary<string, bool>>();
|
||||
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<string, bool> {
|
||||
["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<List<object>>();
|
||||
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<string> { "ID,状态,特辑,名称,描述,当前进度,目标进度,完成时间" };
|
||||
@@ -194,13 +195,13 @@ public static class Export {
|
||||
|
||||
// ReSharper disable once InconsistentNaming
|
||||
private static Dictionary<string, object> 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<string, uint> {
|
||||
["id"] = ach.Id,
|
||||
["status"] = (uint) ach.Status,
|
||||
["current"] = ach.Current,
|
||||
["timestamp"] = ach.Timestamp
|
||||
["current"] = ach.CurrentProgress,
|
||||
["timestamp"] = ach.FinishTimestamp
|
||||
})
|
||||
.ToList();
|
||||
return new Dictionary<string, object> {
|
||||
@@ -225,21 +226,16 @@ public static class Export {
|
||||
|
||||
private static readonly List<uint> 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}");
|
||||
|
||||
@@ -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);
|
||||
|
||||
0
src/Outputs/.gitkeep
Normal file
0
src/Outputs/.gitkeep
Normal file
97
src/Parsers/AchievementAllDataNotify.cs
Normal file
97
src/Parsers/AchievementAllDataNotify.cs
Normal file
@@ -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<AchievementItem> AchievementList { get; private init; } = [];
|
||||
|
||||
public static AchievementAllDataNotify ParseFrom(byte[] bytes) {
|
||||
using var stream = new CodedInputStream(bytes);
|
||||
uint tag;
|
||||
var data = new List<Dictionary<uint, uint>>();
|
||||
while ((tag = stream.ReadTag()) != 0) {
|
||||
if ((tag & 7) == 2) { // is LengthDelimited
|
||||
var dict = new Dictionary<uint, uint>();
|
||||
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);
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
16
src/Utilities/Extensions/Collection.cs
Normal file
16
src/Utilities/Extensions/Collection.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace System.Collections.Generic;
|
||||
|
||||
public static class Collection {
|
||||
|
||||
public static IDictionary<TKey, TValue> RemoveValues<TKey, TValue>(
|
||||
this IDictionary<TKey, TValue> dictionary,
|
||||
params TKey[] keys
|
||||
) {
|
||||
foreach (var key in keys) {
|
||||
dictionary.Remove(key);
|
||||
}
|
||||
return dictionary;
|
||||
}
|
||||
|
||||
}
|
||||
14
src/Utilities/Extensions/Enumerable.cs
Normal file
14
src/Utilities/Extensions/Enumerable.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
// ReSharper disable once CheckNamespace
|
||||
|
||||
namespace System.Linq;
|
||||
|
||||
public static class Enumerable {
|
||||
|
||||
public static IEnumerable<IGrouping<TKey, TKey>> GroupKeys<TKey, TValue>(
|
||||
this IEnumerable<Dictionary<TKey, TValue>> source,
|
||||
Func<TValue, bool> condition
|
||||
) where TKey : notnull {
|
||||
return source.SelectMany(dict => dict.Where(pair => condition(pair.Value)).Select(pair => pair.Key)).GroupBy(x => x);
|
||||
}
|
||||
|
||||
}
|
||||
16
src/Utils.cs
16
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<string, bool> onReceive) {
|
||||
if (!CheckGenshinIsLatestVersion(exePath)) {
|
||||
Console.WriteLine(App.GenshinHashError);
|
||||
Environment.Exit(0);
|
||||
}
|
||||
AppDomain.CurrentDomain.ProcessExit += (_, _) => {
|
||||
try {
|
||||
File.Delete(GlobalVars.LibFilePath);
|
||||
|
||||
Reference in New Issue
Block a user