mirror of
https://github.com/HolographicHat/Yae.git
synced 2025-12-15 19:08:12 +08:00
Implement export: snapgenshin and cocogoat
This commit is contained in:
@@ -1,4 +1,8 @@
|
|||||||
using Newtonsoft.Json;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.Net;
|
||||||
|
using System.Text;
|
||||||
|
using Microsoft.Win32;
|
||||||
|
using Newtonsoft.Json;
|
||||||
using static AchievementAllDataNotify.Types.Achievement.Types;
|
using static AchievementAllDataNotify.Types.Achievement.Types;
|
||||||
|
|
||||||
namespace YaeAchievement;
|
namespace YaeAchievement;
|
||||||
@@ -7,36 +11,55 @@ public static class Export {
|
|||||||
|
|
||||||
public static void Choose(AchievementAllDataNotify data) {
|
public static void Choose(AchievementAllDataNotify data) {
|
||||||
Console.Write(@"导出至:
|
Console.Write(@"导出至:
|
||||||
[0] 椰羊 (https://cocogoat.work/achievement)
|
[0] 椰羊 (https://cocogoat.work/achievement, 默认)
|
||||||
[1] SnapGenshin
|
[1] SnapGenshin
|
||||||
[2] Paimon.moe
|
[2] Paimon.moe
|
||||||
[3] Seelie.me
|
[3] Seelie.me
|
||||||
[4] 表格文件 (默认)
|
[4] 表格文件
|
||||||
输入一个数字(0-4): ".Split("\n").Select(s => s.Trim()).JoinToString("\n") + " ");
|
输入一个数字(0-4): ".Split("\n").Select(s => s.Trim()).JoinToString("\n") + " ");
|
||||||
if (!int.TryParse(Console.ReadLine(), out var num)) num = 4;
|
if (!int.TryParse(Console.ReadLine(), out var num)) num = 0;
|
||||||
Action<AchievementAllDataNotify> act = num switch {
|
Action<AchievementAllDataNotify> act = num switch {
|
||||||
0 => ToCocogoat,
|
|
||||||
1 => ToSnapGenshin,
|
1 => ToSnapGenshin,
|
||||||
2 => ToPaimon,
|
2 => ToPaimon,
|
||||||
3 => ToSeelie,
|
3 => ToSeelie,
|
||||||
|
4 => ToCSV,
|
||||||
7 => ToRawJson,
|
7 => ToRawJson,
|
||||||
_ => ToCSV
|
_ => ToCocogoat
|
||||||
};
|
};
|
||||||
act(data);
|
act(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ToCocogoat(AchievementAllDataNotify data) {
|
private static void ToCocogoat(AchievementAllDataNotify data) {
|
||||||
throw new NotImplementedException();
|
var result = JsonConvert.SerializeObject(ExportToUIAFApp(data));
|
||||||
|
using var request = new HttpRequestMessage {
|
||||||
|
Method = HttpMethod.Post,
|
||||||
|
RequestUri = new Uri("https://77.cocogoat.work/v1/memo?source=全部成就"),
|
||||||
|
Content = new StringContent(result, Encoding.UTF8, "application/json")
|
||||||
|
};
|
||||||
|
using var response = Utils.CHttpClient.Value.Send(request);
|
||||||
|
if (response.StatusCode != HttpStatusCode.Created) {
|
||||||
|
Console.WriteLine("导出失败, 请联系开发者以获取帮助");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dynamic memo = JsonConvert.DeserializeObject(response.Content.ReadAsStringAsync().Result)!;
|
||||||
|
Console.WriteLine(Utils.ShellOpen($"https://cocogoat.work/achievement?memo={memo.key}")
|
||||||
|
? "在浏览器内进行下一步操作"
|
||||||
|
: $"https://cocogoat.work/achievement?memo={memo.key}");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ToSnapGenshin(AchievementAllDataNotify data) {
|
private static void ToSnapGenshin(AchievementAllDataNotify data) {
|
||||||
throw new NotImplementedException();
|
if (CheckSnapScheme()) {
|
||||||
|
Utils.CopyToClipboard(JsonConvert.SerializeObject(ExportToUIAFApp(data)));
|
||||||
|
Utils.ShellOpen("snapgenshin://achievement/import/uiaf");
|
||||||
|
Console.WriteLine("在 SnapGenshin 进行下一步操作");
|
||||||
|
} else {
|
||||||
|
Console.WriteLine("更新 SnapGenshin 至最新版本后重试");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ToPaimon(AchievementAllDataNotify data) {
|
private static void ToPaimon(AchievementAllDataNotify data) {
|
||||||
var info = LoadAchievementInfo();
|
var info = LoadAchievementInfo();
|
||||||
var output = new Dictionary<uint, Dictionary<uint, bool>>();
|
var output = new Dictionary<uint, Dictionary<uint, bool>>();
|
||||||
var path = Path.GetFullPath($"export-{DateTime.Now:yyyyMMddHHmmss}-paimon.json");
|
|
||||||
foreach (var ach in data.List.Where(a => a.Status is Status.Finished or Status.RewardTaken)) {
|
foreach (var ach in data.List.Where(a => a.Status is Status.Finished or Status.RewardTaken)) {
|
||||||
if (!info.Items.TryGetValue(ach.Id, out var achInfo) || achInfo == null) {
|
if (!info.Items.TryGetValue(ach.Id, out var achInfo) || achInfo == null) {
|
||||||
Console.WriteLine($"Unable to find {ach.Id} in metadata.");
|
Console.WriteLine($"Unable to find {ach.Id} in metadata.");
|
||||||
@@ -49,19 +72,29 @@ public static class Export {
|
|||||||
var final = new Dictionary<string, Dictionary<uint, Dictionary<uint, bool>>> {
|
var final = new Dictionary<string, Dictionary<uint, Dictionary<uint, bool>>> {
|
||||||
["achievement"] = output.OrderBy(pair => pair.Key).ToDictionary(pair => pair.Key, pair => pair.Value)
|
["achievement"] = output.OrderBy(pair => pair.Key).ToDictionary(pair => pair.Key, pair => pair.Value)
|
||||||
};
|
};
|
||||||
|
var path = Path.GetFullPath($"export-{DateTime.Now:yyyyMMddHHmmss}-paimon.json");
|
||||||
File.WriteAllText(path, JsonConvert.SerializeObject(final));
|
File.WriteAllText(path, JsonConvert.SerializeObject(final));
|
||||||
Console.WriteLine($"成就数据已导出至 {path}");
|
Console.WriteLine($"成就数据已导出至 {path}");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ToSeelie(AchievementAllDataNotify data) {
|
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)) {
|
||||||
|
output[ach.Id == 81222 ? 81219 : ach.Id] = new Dictionary<string, bool> {
|
||||||
|
["done"] = true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
var final = new Dictionary<string, Dictionary<uint, Dictionary<string, bool>>> {
|
||||||
|
["achievements"] = output.OrderBy(pair => pair.Key).ToDictionary(pair => pair.Key, pair => pair.Value)
|
||||||
|
};
|
||||||
var path = Path.GetFullPath($"export-{DateTime.Now:yyyyMMddHHmmss}-seelie.json");
|
var path = Path.GetFullPath($"export-{DateTime.Now:yyyyMMddHHmmss}-seelie.json");
|
||||||
|
File.WriteAllText(path, JsonConvert.SerializeObject(final));
|
||||||
Console.WriteLine($"成就数据已导出至 {path}");
|
Console.WriteLine($"成就数据已导出至 {path}");
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReSharper disable once InconsistentNaming
|
// ReSharper disable once InconsistentNaming
|
||||||
private static void ToCSV(AchievementAllDataNotify data) {
|
private static void ToCSV(AchievementAllDataNotify data) {
|
||||||
var info = LoadAchievementInfo();
|
var info = LoadAchievementInfo();
|
||||||
var path = Path.GetFullPath($"achievement-{DateTime.Now:yyyyMMddHHmmss}.csv");
|
|
||||||
var outList = new List<List<object>>();
|
var outList = new List<List<object>>();
|
||||||
foreach (var ach in data.List.OrderBy(a => a.Id)) {
|
foreach (var ach in data.List.OrderBy(a => a.Id)) {
|
||||||
if (UnusedAchievement.Contains(ach.Id)) continue;
|
if (UnusedAchievement.Contains(ach.Id)) continue;
|
||||||
@@ -85,6 +118,7 @@ public static class Export {
|
|||||||
item[2] = info.Group[(uint) item[2]];
|
item[2] = info.Group[(uint) item[2]];
|
||||||
return item.JoinToString(",");
|
return item.JoinToString(",");
|
||||||
}));
|
}));
|
||||||
|
var path = Path.GetFullPath($"achievement-{DateTime.Now:yyyyMMddHHmmss}.csv");
|
||||||
File.WriteAllText(path, $"\uFEFF{string.Join("\n", output)}");
|
File.WriteAllText(path, $"\uFEFF{string.Join("\n", output)}");
|
||||||
Console.WriteLine($"成就数据已导出至 {path}");
|
Console.WriteLine($"成就数据已导出至 {path}");
|
||||||
}
|
}
|
||||||
@@ -96,8 +130,25 @@ public static class Export {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ReSharper disable once InconsistentNaming
|
// ReSharper disable once InconsistentNaming
|
||||||
private static string ExportToUIAFApp(AchievementAllDataNotify data) {
|
private static Dictionary<string, object> ExportToUIAFApp(AchievementAllDataNotify data) {
|
||||||
return "";
|
var output = data.List
|
||||||
|
.Where(a => a.Status is Status.Finished or Status.RewardTaken)
|
||||||
|
.Select(ach => new Dictionary<string, uint> { ["id"] = ach.Id, ["current"] = ach.Current, ["timestamp"] = ach.Timestamp })
|
||||||
|
.ToList();
|
||||||
|
return new Dictionary<string, object> {
|
||||||
|
["info"] = new Dictionary<string, object> {
|
||||||
|
["export_app"] = "YaeAchievement",
|
||||||
|
["export_timestamp"] = DateTimeOffset.Now.ToUnixTimeMilliseconds(),
|
||||||
|
["export_app_version"] = GlobalVars.AppVersionName,
|
||||||
|
["uiaf_version"] = "v1.0"
|
||||||
|
},
|
||||||
|
["list"] = output
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[SuppressMessage("Interoperability", "CA1416:验证平台兼容性")]
|
||||||
|
private static bool CheckSnapScheme() {
|
||||||
|
return (string?)Registry.ClassesRoot.OpenSubKey("snapgenshin")?.GetValue("") == "URL:snapgenshin";
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string JoinToString(this IEnumerable<object> list, string separator) {
|
private static string JoinToString(this IEnumerable<object> list, string separator) {
|
||||||
|
|||||||
@@ -5,18 +5,19 @@ using YaeAchievement;
|
|||||||
using static YaeAchievement.Utils;
|
using static YaeAchievement.Utils;
|
||||||
|
|
||||||
Console.WriteLine("----------------------------------------------------");
|
Console.WriteLine("----------------------------------------------------");
|
||||||
Console.WriteLine("YaeAchievement - 原神成就导出工具");
|
Console.WriteLine($"YaeAchievement - 原神成就导出工具 ({GlobalVars.AppVersionName})");
|
||||||
Console.WriteLine("https://github.com/HolographicHat/YaeAchievement");
|
Console.WriteLine("https://github.com/HolographicHat/YaeAchievement");
|
||||||
Console.WriteLine("----------------------------------------------------");
|
Console.WriteLine("----------------------------------------------------");
|
||||||
/*InstallExitHook();
|
InstallExitHook();
|
||||||
InstallExceptionHook();
|
InstallExceptionHook();
|
||||||
CheckGenshinIsRunning();
|
CheckGenshinIsRunning();
|
||||||
LoadConfig();
|
LoadConfig();
|
||||||
CheckUpdate();*/
|
CheckUpdate();
|
||||||
TryDisableQuickEdit();
|
TryDisableQuickEdit();
|
||||||
//Console.WriteLine(c.Send(msg).StatusCode);
|
//Console.WriteLine(c.Send(msg).StatusCode);
|
||||||
//using var o = File.OpenWrite("ai");
|
//using var o = File.OpenWrite("ai");
|
||||||
//AchievementInfo.Parser.ParseJson(File.ReadAllText(@"C:\Users\holog\Desktop\cc.json")).WriteTo(o);
|
//AchievementInfo.Parser.ParseJson(File.ReadAllText(@"C:\Users\holog\Desktop\cc.json")).WriteTo(o);
|
||||||
|
//CopyToClipboard("test");
|
||||||
StartAndWaitResult(@"D:\Genshin Impact Dev\2.8\YuanShen.exe", str => {
|
StartAndWaitResult(@"D:\Genshin Impact Dev\2.8\YuanShen.exe", str => {
|
||||||
GlobalVars.UnexpectedExit = false;
|
GlobalVars.UnexpectedExit = false;
|
||||||
var list = AchievementAllDataNotify.Parser.ParseFrom(Convert.FromBase64String(str));
|
var list = AchievementAllDataNotify.Parser.ParseFrom(Convert.FromBase64String(str));
|
||||||
|
|||||||
33
src/Utils.cs
33
src/Utils.cs
@@ -16,7 +16,7 @@ namespace YaeAchievement;
|
|||||||
|
|
||||||
public static class Utils {
|
public static class Utils {
|
||||||
|
|
||||||
private static readonly Lazy<HttpClient> CHttpClient = new (() => {
|
public static readonly Lazy<HttpClient> CHttpClient = new (() => {
|
||||||
var c = new HttpClient(new HttpClientHandler {
|
var c = new HttpClient(new HttpClientHandler {
|
||||||
Proxy = new WebProxy("http://127.0.0.1:8888"),
|
Proxy = new WebProxy("http://127.0.0.1:8888"),
|
||||||
AutomaticDecompression = DecompressionMethods.Brotli | DecompressionMethods.GZip
|
AutomaticDecompression = DecompressionMethods.Brotli | DecompressionMethods.GZip
|
||||||
@@ -81,6 +81,21 @@ public static class Utils {
|
|||||||
var b = md5.ComputeHash(bytes);
|
var b = md5.ComputeHash(bytes);
|
||||||
return Convert.ToHexString(b).ToLower();
|
return Convert.ToHexString(b).ToLower();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void CopyToClipboard(string text) {
|
||||||
|
if (Native.OpenClipboard(IntPtr.Zero)) {
|
||||||
|
Native.EmptyClipboard();
|
||||||
|
var hGlobal = Marshal.AllocHGlobal((text.Length + 1) * 2);
|
||||||
|
var hPtr = Native.GlobalLock(hGlobal);
|
||||||
|
Marshal.Copy(text.ToCharArray(), 0, hPtr, text.Length);
|
||||||
|
Native.GlobalUnlock(hPtr);
|
||||||
|
Native.SetClipboardData(13, hGlobal);
|
||||||
|
Marshal.FreeHGlobal(hGlobal);
|
||||||
|
Native.CloseClipboard();
|
||||||
|
} else {
|
||||||
|
throw new Win32Exception();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void LoadConfig() {
|
public static void LoadConfig() {
|
||||||
var conf = JsonNode.Parse(File.ReadAllText(GlobalVars.ConfigFileName))!;
|
var conf = JsonNode.Parse(File.ReadAllText(GlobalVars.ConfigFileName))!;
|
||||||
@@ -104,12 +119,7 @@ public static class Utils {
|
|||||||
var fullPath = Path.GetFullPath("update.7z");
|
var fullPath = Path.GetFullPath("update.7z");
|
||||||
File.WriteAllBytes(fullPath, GetBucketFileAsByteArray(info.PackageLink));
|
File.WriteAllBytes(fullPath, GetBucketFileAsByteArray(info.PackageLink));
|
||||||
Console.WriteLine("下载完毕! 关闭程序后, 将压缩包解压至当前目录即可完成更新.");
|
Console.WriteLine("下载完毕! 关闭程序后, 将压缩包解压至当前目录即可完成更新.");
|
||||||
new Process {
|
ShellOpen(fullPath);
|
||||||
StartInfo = {
|
|
||||||
FileName = fullPath,
|
|
||||||
UseShellExecute = true
|
|
||||||
}
|
|
||||||
}.Start();
|
|
||||||
Environment.Exit(0);
|
Environment.Exit(0);
|
||||||
}
|
}
|
||||||
Console.WriteLine($"下载地址: {info.PackageLink}");
|
Console.WriteLine($"下载地址: {info.PackageLink}");
|
||||||
@@ -123,6 +133,15 @@ public static class Utils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool ShellOpen(string path) {
|
||||||
|
return new Process {
|
||||||
|
StartInfo = {
|
||||||
|
FileName = path,
|
||||||
|
UseShellExecute = true
|
||||||
|
}
|
||||||
|
}.Start();
|
||||||
|
}
|
||||||
|
|
||||||
private static bool CheckGamePathValid(string path) {
|
private static bool CheckGamePathValid(string path) {
|
||||||
var dir = Path.GetDirectoryName(path)!;
|
var dir = Path.GetDirectoryName(path)!;
|
||||||
return File.Exists($"{dir}/UnityPlayer.dll") && File.Exists($"{dir}/mhypbase.dll");
|
return File.Exists($"{dir}/UnityPlayer.dll") && File.Exists($"{dir}/mhypbase.dll");
|
||||||
|
|||||||
@@ -93,4 +93,24 @@ public static class Native {
|
|||||||
[DllImport("comdlg32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
[DllImport("comdlg32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||||
public static extern bool GetOpenFileName([In, Out] OpenFileName ofn);
|
public static extern bool GetOpenFileName([In, Out] OpenFileName ofn);
|
||||||
|
|
||||||
|
[DllImport("kernel32.dll", SetLastError = true)]
|
||||||
|
public static extern IntPtr GlobalLock(IntPtr mem);
|
||||||
|
|
||||||
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||||||
|
[DllImport("kernel32.dll", SetLastError = true)]
|
||||||
|
public static extern bool GlobalUnlock(IntPtr mem);
|
||||||
|
|
||||||
|
[DllImport("user32.dll", SetLastError = true)]
|
||||||
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||||||
|
public static extern bool OpenClipboard(IntPtr owner);
|
||||||
|
|
||||||
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||||||
|
[DllImport("user32.dll", SetLastError = true)]
|
||||||
|
public static extern bool CloseClipboard();
|
||||||
|
|
||||||
|
[DllImport("user32.dll", SetLastError = true)]
|
||||||
|
public static extern IntPtr SetClipboardData(uint uFormat, IntPtr data);
|
||||||
|
|
||||||
|
[DllImport("user32.dll")]
|
||||||
|
public static extern bool EmptyClipboard();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user