mirror of
https://github.com/HolographicHat/Yae.git
synced 2025-12-11 08:58:12 +08:00
[skip ci] export player store data
This commit is contained in:
74
YaeAchievement/res/proto/StoreData.proto
Normal file
74
YaeAchievement/res/proto/StoreData.proto
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option csharp_namespace = "Proto";
|
||||||
|
|
||||||
|
enum StoreType {
|
||||||
|
STORE_TYPE_NONE = 0;
|
||||||
|
STORE_TYPE_PACK = 1;
|
||||||
|
STORE_TYPE_DEPOT = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message MaterialDeleteInfo {
|
||||||
|
message CountDownDelete {
|
||||||
|
map<uint32, uint32> delete_time_num_map = 1;
|
||||||
|
uint32 config_count_down_time = 2;
|
||||||
|
}
|
||||||
|
message DateTimeDelete {
|
||||||
|
uint32 delete_time = 1;
|
||||||
|
}
|
||||||
|
message DelayWeekCountDownDelete {
|
||||||
|
map<uint32, uint32> delete_time_num_map = 1;
|
||||||
|
uint32 config_delay_week = 2;
|
||||||
|
uint32 config_count_down_time = 3;
|
||||||
|
}
|
||||||
|
bool has_delete_config = 1;
|
||||||
|
oneof delete_info {
|
||||||
|
CountDownDelete count_down_delete = 2;
|
||||||
|
DateTimeDelete date_delete = 3;
|
||||||
|
DelayWeekCountDownDelete delay_week_count_down_delete = 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message Material {
|
||||||
|
uint32 count = 1;
|
||||||
|
MaterialDeleteInfo delete_info = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Reliquary {
|
||||||
|
uint32 level = 1;
|
||||||
|
uint32 exp = 2;
|
||||||
|
uint32 promote_level = 3;
|
||||||
|
uint32 main_prop_id = 4;
|
||||||
|
repeated uint32 append_prop_id_list = 5;
|
||||||
|
bool is_marked = 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Weapon {
|
||||||
|
uint32 level = 1;
|
||||||
|
uint32 exp = 2;
|
||||||
|
uint32 promote_level = 3;
|
||||||
|
map<uint32, uint32> affix_map = 4;
|
||||||
|
bool is_arkhe_ousia = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Equip {
|
||||||
|
oneof detail {
|
||||||
|
Reliquary reliquary = 1;
|
||||||
|
Weapon weapon = 2;
|
||||||
|
}
|
||||||
|
bool is_locked = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Furniture {
|
||||||
|
uint32 count = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Item {
|
||||||
|
uint32 item_id = 1;
|
||||||
|
uint64 guid = 2;
|
||||||
|
oneof detail {
|
||||||
|
Material material = 5;
|
||||||
|
Equip equip = 6;
|
||||||
|
Furniture furniture = 7;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -28,6 +28,8 @@ public static class GlobalVars {
|
|||||||
public const string RinBucketHost = "https://rin.holohat.work";
|
public const string RinBucketHost = "https://rin.holohat.work";
|
||||||
public const string SakuraBucketHost = "https://cn-cd-1259389942.file.myqcloud.com";
|
public const string SakuraBucketHost = "https://cn-cd-1259389942.file.myqcloud.com";
|
||||||
|
|
||||||
|
public static CacheFile AchievementDataCache { get; } = new ("achievement_data");
|
||||||
|
|
||||||
[field:MaybeNull]
|
[field:MaybeNull]
|
||||||
public static AchievementInfo AchievementInfo =>
|
public static AchievementInfo AchievementInfo =>
|
||||||
field ??= AchievementInfo.Parser.ParseFrom(Utils.GetBucketFile("schicksal/metadata").GetAwaiter().GetResult());
|
field ??= AchievementInfo.Parser.ParseFrom(Utils.GetBucketFile("schicksal/metadata").GetAwaiter().GetResult());
|
||||||
@@ -36,4 +38,5 @@ public static class GlobalVars {
|
|||||||
Directory.CreateDirectory(DataPath);
|
Directory.CreateDirectory(DataPath);
|
||||||
Directory.CreateDirectory(CachePath);
|
Directory.CreateDirectory(CachePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System.Runtime.CompilerServices;
|
using System.Text.Json;
|
||||||
using System.Text.Json;
|
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
using Google.Protobuf;
|
using Google.Protobuf;
|
||||||
using YaeAchievement.res;
|
using YaeAchievement.res;
|
||||||
@@ -27,6 +26,12 @@ public class AchievementAllDataNotify {
|
|||||||
|
|
||||||
public List<AchievementItem> AchievementList { get; private init; } = [];
|
public List<AchievementItem> AchievementList { get; private init; } = [];
|
||||||
|
|
||||||
|
public static bool OnReceive(byte[] bytes) {
|
||||||
|
GlobalVars.AchievementDataCache.Write(bytes);
|
||||||
|
Export.Choose(ParseFrom(bytes));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public static AchievementAllDataNotify ParseFrom(byte[] bytes) {
|
public static AchievementAllDataNotify ParseFrom(byte[] bytes) {
|
||||||
using var stream = new CodedInputStream(bytes);
|
using var stream = new CodedInputStream(bytes);
|
||||||
var data = new List<Dictionary<uint, uint>>();
|
var data = new List<Dictionary<uint, uint>>();
|
||||||
@@ -36,7 +41,7 @@ public class AchievementAllDataNotify {
|
|||||||
while ((tag = stream.ReadTag()) != 0) {
|
while ((tag = stream.ReadTag()) != 0) {
|
||||||
if ((tag & 7) == 2) { // is LengthDelimited
|
if ((tag & 7) == 2) { // is LengthDelimited
|
||||||
var dict = new Dictionary<uint, uint>();
|
var dict = new Dictionary<uint, uint>();
|
||||||
using var eStream = new CodedInputStream(ReadRawBytes(stream, stream.ReadLength()));
|
using var eStream = stream.ReadLengthDelimitedAsStream();
|
||||||
try {
|
try {
|
||||||
while ((tag = eStream.ReadTag()) != 0) {
|
while ((tag = eStream.ReadTag()) != 0) {
|
||||||
if ((tag & 7) != 0) { // not VarInt
|
if ((tag & 7) != 0) { // not VarInt
|
||||||
@@ -107,9 +112,6 @@ public class AchievementAllDataNotify {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
[UnsafeAccessor(UnsafeAccessorKind.Method)]
|
|
||||||
private static extern byte[] ReadRawBytes(CodedInputStream stream, int size);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[JsonSerializable(typeof(AchievementAllDataNotify))]
|
[JsonSerializable(typeof(AchievementAllDataNotify))]
|
||||||
|
|||||||
60
YaeAchievement/src/Parsers/PlayerStoreNotify.cs
Normal file
60
YaeAchievement/src/Parsers/PlayerStoreNotify.cs
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
using System.Text.Json;
|
||||||
|
using Google.Protobuf;
|
||||||
|
using Proto;
|
||||||
|
|
||||||
|
namespace YaeAchievement.Parsers;
|
||||||
|
|
||||||
|
public class PlayerStoreNotify {
|
||||||
|
|
||||||
|
public uint WeightLimit { get; set; }
|
||||||
|
|
||||||
|
public StoreType StoreType { get; set; }
|
||||||
|
|
||||||
|
public List<Item> ItemList { get; set; } = [];
|
||||||
|
|
||||||
|
public static bool OnReceive(byte[] bytes) {
|
||||||
|
#if DEBUG
|
||||||
|
var ntf = ParseFrom(bytes);
|
||||||
|
File.WriteAllText("store_data.json", JsonSerializer.Serialize(ntf, new JsonSerializerOptions {
|
||||||
|
WriteIndented = true
|
||||||
|
}));
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static PlayerStoreNotify ParseFrom(byte[] bytes) {
|
||||||
|
using var stream = new CodedInputStream(bytes);
|
||||||
|
var ntf = new PlayerStoreNotify();
|
||||||
|
try {
|
||||||
|
uint tag;
|
||||||
|
while ((tag = stream.ReadTag()) != 0) {
|
||||||
|
var wireType = tag & 7;
|
||||||
|
switch (wireType) {
|
||||||
|
case 0: { // is VarInt
|
||||||
|
var value = stream.ReadUInt32();
|
||||||
|
if (value < 10) {
|
||||||
|
ntf.StoreType = (StoreType) value;
|
||||||
|
} else {
|
||||||
|
ntf.WeightLimit = value;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
case 2: { // is LengthDelimited
|
||||||
|
using var eStream = stream.ReadLengthDelimitedAsStream();
|
||||||
|
while (eStream.PeekTag() != 0) {
|
||||||
|
ntf.ItemList.Add(Item.Parser.ParseFrom(eStream));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (InvalidProtocolBufferException) {
|
||||||
|
// ReSharper disable once LocalizableElement
|
||||||
|
Console.WriteLine("Parse failed");
|
||||||
|
File.WriteAllBytes("store_raw_data.bin", bytes);
|
||||||
|
Environment.Exit(0);
|
||||||
|
}
|
||||||
|
return ntf;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -24,7 +24,7 @@ Export.ExportTo = ToUIntOrNull(args.GetOrNull(1)) ?? uint.MaxValue;
|
|||||||
|
|
||||||
await CheckUpdate(ToBooleanOrFalse(args.GetOrNull(2)));
|
await CheckUpdate(ToBooleanOrFalse(args.GetOrNull(2)));
|
||||||
|
|
||||||
var historyCache = new CacheFile("ExportData");
|
var historyCache = GlobalVars.AchievementDataCache;
|
||||||
|
|
||||||
AchievementAllDataNotify? data = null;
|
AchievementAllDataNotify? data = null;
|
||||||
try {
|
try {
|
||||||
@@ -39,11 +39,7 @@ if (historyCache.LastWriteTime.AddMinutes(60) > DateTime.UtcNow && data != null)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StartAndWaitResult(AppConfig.GamePath, str => {
|
StartAndWaitResult(AppConfig.GamePath, new Dictionary<byte, Func<byte[], bool>> {
|
||||||
GlobalVars.UnexpectedExit = false;
|
{ 1, AchievementAllDataNotify.OnReceive },
|
||||||
var bytes = Convert.FromBase64String(str);
|
{ 2, PlayerStoreNotify.OnReceive }
|
||||||
var list = AchievementAllDataNotify.ParseFrom(bytes);
|
|
||||||
historyCache.Write(bytes);
|
|
||||||
Export.Choose(list);
|
|
||||||
return true;
|
|
||||||
});
|
});
|
||||||
|
|||||||
16
YaeAchievement/src/Utilities/Extensions/Stream.cs
Normal file
16
YaeAchievement/src/Utilities/Extensions/Stream.cs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
// ReSharper disable CheckNamespace
|
||||||
|
|
||||||
|
namespace Google.Protobuf;
|
||||||
|
|
||||||
|
public static class CodedInputStreamExtensions {
|
||||||
|
|
||||||
|
[UnsafeAccessor(UnsafeAccessorKind.Method)]
|
||||||
|
private static extern byte[] ReadRawBytes(CodedInputStream stream, int size);
|
||||||
|
|
||||||
|
public static CodedInputStream ReadLengthDelimitedAsStream(this CodedInputStream stream) {
|
||||||
|
return new CodedInputStream(ReadRawBytes(stream, stream.ReadLength()));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -114,7 +114,7 @@ public static class Utils {
|
|||||||
Console.WriteLine(@"[DEBUG] Use local native lib.");
|
Console.WriteLine(@"[DEBUG] Use local native lib.");
|
||||||
File.Copy(Path.Combine(GlobalVars.AppPath, "YaeAchievementLib.dll"), GlobalVars.LibFilePath, true);
|
File.Copy(Path.Combine(GlobalVars.AppPath, "YaeAchievementLib.dll"), GlobalVars.LibFilePath, true);
|
||||||
} else if (info.EnableLibDownload) {
|
} else if (info.EnableLibDownload) {
|
||||||
var data = await GetBucketFile("schicksal/lib.dll");
|
var data = await GetBucketFile("schicksal/lic.dll");
|
||||||
await File.WriteAllBytesAsync(GlobalVars.LibFilePath, data);
|
await File.WriteAllBytesAsync(GlobalVars.LibFilePath, data);
|
||||||
}
|
}
|
||||||
_updateInfo = info;
|
_updateInfo = info;
|
||||||
@@ -208,7 +208,7 @@ public static class Utils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ReSharper disable once UnusedMethodReturnValue.Global
|
// ReSharper disable once UnusedMethodReturnValue.Global
|
||||||
public static Thread StartAndWaitResult(string exePath, Func<string, bool> onReceive) {
|
public static Thread StartAndWaitResult(string exePath, Dictionary<byte, Func<byte[], bool>> handlers) {
|
||||||
AppDomain.CurrentDomain.ProcessExit += (_, _) => {
|
AppDomain.CurrentDomain.ProcessExit += (_, _) => {
|
||||||
try {
|
try {
|
||||||
File.Delete(GlobalVars.LibFilePath);
|
File.Delete(GlobalVars.LibFilePath);
|
||||||
@@ -228,7 +228,7 @@ public static class Utils {
|
|||||||
proc = Process.GetProcessById(Convert.ToInt32(pid));
|
proc = Process.GetProcessById(Convert.ToInt32(pid));
|
||||||
proc.EnableRaisingEvents = true;
|
proc.EnableRaisingEvents = true;
|
||||||
proc.Exited += (_, _) => {
|
proc.Exited += (_, _) => {
|
||||||
if (GlobalVars.UnexpectedExit)
|
if (handlers.Count != 0)
|
||||||
{
|
{
|
||||||
proc = null;
|
proc = null;
|
||||||
Console.WriteLine(App.GameProcessExit);
|
Console.WriteLine(App.GameProcessExit);
|
||||||
@@ -252,15 +252,13 @@ public static class Utils {
|
|||||||
var ts = new ThreadStart(() => {
|
var ts = new ThreadStart(() => {
|
||||||
var server = new NamedPipeServerStream(GlobalVars.PipeName);
|
var server = new NamedPipeServerStream(GlobalVars.PipeName);
|
||||||
server.WaitForConnection();
|
server.WaitForConnection();
|
||||||
using var reader = new StreamReader(server);
|
using var reader = new BinaryReader(server);
|
||||||
while (!proc.HasExited) {
|
while (!proc.HasExited) {
|
||||||
var line = reader.ReadLine();
|
var type = reader.ReadByte();
|
||||||
if (line?.Length > 0) {
|
var length = reader.ReadInt32(); // huh
|
||||||
if (onReceive(line)) {
|
var data = reader.ReadBytes(length);
|
||||||
break;
|
if (handlers.Remove(type, out var handler)) {
|
||||||
}
|
handler(data);
|
||||||
server.Disconnect();
|
|
||||||
server.WaitForConnection();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user