diff --git a/src/GlobalVars.cs b/src/GlobalVars.cs index 1ded994..b5917aa 100644 --- a/src/GlobalVars.cs +++ b/src/GlobalVars.cs @@ -13,6 +13,8 @@ public static class GlobalVars { public static string GamePath = ""; public static Version AppVersion = Assembly.GetEntryAssembly()!.GetName().Version!; + public const uint AppVersionCode = 77; + public const string AppVersionName = "2.?"; public const string LibName = "YaeLib.dll"; public const string PipeName = "YaeAchievementPipe"; public const string BucketHost = "https://cn-cd-1259389942.file.myqcloud.com"; diff --git a/src/Logger.cs b/src/Logger.cs deleted file mode 100644 index 73c87be..0000000 --- a/src/Logger.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace YaeAchievement; - -public static class Logger { - -} \ No newline at end of file diff --git a/src/Proto/UpdateInfo.cs b/src/Proto/UpdateInfo.cs new file mode 100644 index 0000000..0166ccc --- /dev/null +++ b/src/Proto/UpdateInfo.cs @@ -0,0 +1,454 @@ +// +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: UpdateInfo.proto +// +#pragma warning disable 1591, 0612, 3021, 8981 +#region Designer generated code + +using pb = global::Google.Protobuf; +using pbc = global::Google.Protobuf.Collections; +using pbr = global::Google.Protobuf.Reflection; +using scg = global::System.Collections.Generic; +/// Holder for reflection information generated from UpdateInfo.proto +public static partial class UpdateInfoReflection { + + #region Descriptor + /// File descriptor for UpdateInfo.proto + public static pbr::FileDescriptor Descriptor { + get { return descriptor; } + } + private static pbr::FileDescriptor descriptor; + + static UpdateInfoReflection() { + byte[] descriptorData = global::System.Convert.FromBase64String( + string.Concat( + "ChBVcGRhdGVJbmZvLnByb3RvIqwBCgpVcGRhdGVJbmZvEhMKC3ZlcnNpb25D", + "b2RlGAEgASgNEhMKC3ZlcnNpb25OYW1lGAIgASgJEhMKC2Rlc2NyaXB0aW9u", + "GAMgASgJEhMKC3BhY2thZ2VMaW5rGAQgASgJEhMKC2ZvcmNlVXBkYXRlGAUg", + "ASgIEhkKEWVuYWJsZUxpYkRvd25sb2FkGAYgASgIEhoKEmVuYWJsZUF1dG9E", + "b3dubG9hZBgHIAEoCGIGcHJvdG8z")); + descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, + new pbr::FileDescriptor[] { }, + new pbr::GeneratedClrTypeInfo(null, null, new pbr::GeneratedClrTypeInfo[] { + new pbr::GeneratedClrTypeInfo(typeof(global::UpdateInfo), global::UpdateInfo.Parser, new[]{ "VersionCode", "VersionName", "Description", "PackageLink", "ForceUpdate", "EnableLibDownload", "EnableAutoDownload" }, null, null, null, null) + })); + } + #endregion + +} +#region Messages +public sealed partial class UpdateInfo : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage +#endif +{ + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new UpdateInfo()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::UpdateInfoReflection.Descriptor.MessageTypes[0]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public UpdateInfo() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public UpdateInfo(UpdateInfo other) : this() { + versionCode_ = other.versionCode_; + versionName_ = other.versionName_; + description_ = other.description_; + packageLink_ = other.packageLink_; + forceUpdate_ = other.forceUpdate_; + enableLibDownload_ = other.enableLibDownload_; + enableAutoDownload_ = other.enableAutoDownload_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public UpdateInfo Clone() { + return new UpdateInfo(this); + } + + /// Field number for the "versionCode" field. + public const int VersionCodeFieldNumber = 1; + private uint versionCode_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public uint VersionCode { + get { return versionCode_; } + set { + versionCode_ = value; + } + } + + /// Field number for the "versionName" field. + public const int VersionNameFieldNumber = 2; + private string versionName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string VersionName { + get { return versionName_; } + set { + versionName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "description" field. + public const int DescriptionFieldNumber = 3; + private string description_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string Description { + get { return description_; } + set { + description_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "packageLink" field. + public const int PackageLinkFieldNumber = 4; + private string packageLink_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string PackageLink { + get { return packageLink_; } + set { + packageLink_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "forceUpdate" field. + public const int ForceUpdateFieldNumber = 5; + private bool forceUpdate_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool ForceUpdate { + get { return forceUpdate_; } + set { + forceUpdate_ = value; + } + } + + /// Field number for the "enableLibDownload" field. + public const int EnableLibDownloadFieldNumber = 6; + private bool enableLibDownload_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool EnableLibDownload { + get { return enableLibDownload_; } + set { + enableLibDownload_ = value; + } + } + + /// Field number for the "enableAutoDownload" field. + public const int EnableAutoDownloadFieldNumber = 7; + private bool enableAutoDownload_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool EnableAutoDownload { + get { return enableAutoDownload_; } + set { + enableAutoDownload_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as UpdateInfo); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(UpdateInfo other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (VersionCode != other.VersionCode) return false; + if (VersionName != other.VersionName) return false; + if (Description != other.Description) return false; + if (PackageLink != other.PackageLink) return false; + if (ForceUpdate != other.ForceUpdate) return false; + if (EnableLibDownload != other.EnableLibDownload) return false; + if (EnableAutoDownload != other.EnableAutoDownload) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (VersionCode != 0) hash ^= VersionCode.GetHashCode(); + if (VersionName.Length != 0) hash ^= VersionName.GetHashCode(); + if (Description.Length != 0) hash ^= Description.GetHashCode(); + if (PackageLink.Length != 0) hash ^= PackageLink.GetHashCode(); + if (ForceUpdate != false) hash ^= ForceUpdate.GetHashCode(); + if (EnableLibDownload != false) hash ^= EnableLibDownload.GetHashCode(); + if (EnableAutoDownload != false) hash ^= EnableAutoDownload.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (VersionCode != 0) { + output.WriteRawTag(8); + output.WriteUInt32(VersionCode); + } + if (VersionName.Length != 0) { + output.WriteRawTag(18); + output.WriteString(VersionName); + } + if (Description.Length != 0) { + output.WriteRawTag(26); + output.WriteString(Description); + } + if (PackageLink.Length != 0) { + output.WriteRawTag(34); + output.WriteString(PackageLink); + } + if (ForceUpdate != false) { + output.WriteRawTag(40); + output.WriteBool(ForceUpdate); + } + if (EnableLibDownload != false) { + output.WriteRawTag(48); + output.WriteBool(EnableLibDownload); + } + if (EnableAutoDownload != false) { + output.WriteRawTag(56); + output.WriteBool(EnableAutoDownload); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (VersionCode != 0) { + output.WriteRawTag(8); + output.WriteUInt32(VersionCode); + } + if (VersionName.Length != 0) { + output.WriteRawTag(18); + output.WriteString(VersionName); + } + if (Description.Length != 0) { + output.WriteRawTag(26); + output.WriteString(Description); + } + if (PackageLink.Length != 0) { + output.WriteRawTag(34); + output.WriteString(PackageLink); + } + if (ForceUpdate != false) { + output.WriteRawTag(40); + output.WriteBool(ForceUpdate); + } + if (EnableLibDownload != false) { + output.WriteRawTag(48); + output.WriteBool(EnableLibDownload); + } + if (EnableAutoDownload != false) { + output.WriteRawTag(56); + output.WriteBool(EnableAutoDownload); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (VersionCode != 0) { + size += 1 + pb::CodedOutputStream.ComputeUInt32Size(VersionCode); + } + if (VersionName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(VersionName); + } + if (Description.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Description); + } + if (PackageLink.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(PackageLink); + } + if (ForceUpdate != false) { + size += 1 + 1; + } + if (EnableLibDownload != false) { + size += 1 + 1; + } + if (EnableAutoDownload != false) { + size += 1 + 1; + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(UpdateInfo other) { + if (other == null) { + return; + } + if (other.VersionCode != 0) { + VersionCode = other.VersionCode; + } + if (other.VersionName.Length != 0) { + VersionName = other.VersionName; + } + if (other.Description.Length != 0) { + Description = other.Description; + } + if (other.PackageLink.Length != 0) { + PackageLink = other.PackageLink; + } + if (other.ForceUpdate != false) { + ForceUpdate = other.ForceUpdate; + } + if (other.EnableLibDownload != false) { + EnableLibDownload = other.EnableLibDownload; + } + if (other.EnableAutoDownload != false) { + EnableAutoDownload = other.EnableAutoDownload; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + VersionCode = input.ReadUInt32(); + break; + } + case 18: { + VersionName = input.ReadString(); + break; + } + case 26: { + Description = input.ReadString(); + break; + } + case 34: { + PackageLink = input.ReadString(); + break; + } + case 40: { + ForceUpdate = input.ReadBool(); + break; + } + case 48: { + EnableLibDownload = input.ReadBool(); + break; + } + case 56: { + EnableAutoDownload = input.ReadBool(); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 8: { + VersionCode = input.ReadUInt32(); + break; + } + case 18: { + VersionName = input.ReadString(); + break; + } + case 26: { + Description = input.ReadString(); + break; + } + case 34: { + PackageLink = input.ReadString(); + break; + } + case 40: { + ForceUpdate = input.ReadBool(); + break; + } + case 48: { + EnableLibDownload = input.ReadBool(); + break; + } + case 56: { + EnableAutoDownload = input.ReadBool(); + break; + } + } + } + } + #endif + +} + +#endregion + + +#endregion Designer generated code diff --git a/src/Utils.cs b/src/Utils.cs index 9149091..9b189d6 100644 --- a/src/Utils.cs +++ b/src/Utils.cs @@ -29,42 +29,44 @@ public static class Utils { return c; }); - public static string GetBucketFileAsString(string path) { - return Encoding.UTF8.GetString(GetBucketFileAsByteArray(path)); + public static string GetBucketFileAsString(string path, bool cache = true) { + return Encoding.UTF8.GetString(GetBucketFileAsByteArray(path, cache)); } - public static byte[] GetBucketFileAsByteArray(string path) { + public static byte[] GetBucketFileAsByteArray(string path, bool cache = true) { using var msg = new HttpRequestMessage { Method = HttpMethod.Get, RequestUri = new Uri($"{GlobalVars.BucketHost}/{path}") }; CacheItem? ci = null; - string? etag = null; - var cacheName = $"./cache/{CalculateMD5(path)[..16]}.miko"; - if (File.Exists(cacheName)) { - using var input = File.OpenRead(cacheName); - using var dInput = new GZipStream(input, CompressionMode.Decompress); - ci = CacheItem.Parser.ParseFrom(dInput); - etag = ci.Etag; - } - if (etag != null) { - msg.Headers.TryAddWithoutValidation("If-None-Match", $"{etag}"); + var cacheName = cache ? $"./cache/{CalculateMD5(path)[..16]}.miko" : ""; + if (cache) { + Directory.CreateDirectory("cache"); + if (File.Exists(cacheName)) { + using var input = File.OpenRead(cacheName); + using var dInput = new GZipStream(input, CompressionMode.Decompress); + ci = CacheItem.Parser.ParseFrom(dInput); + msg.Headers.TryAddWithoutValidation("If-None-Match", $"{ci.Etag}"); + + } } using var response = CHttpClient.Value.Send(msg); - if (response.StatusCode == HttpStatusCode.NotModified) { + if (cache && response.StatusCode == HttpStatusCode.NotModified) { return ci!.Content.ToByteArray(); } response.EnsureSuccessStatusCode(); - etag = response.Headers.ETag!.Tag; var responseBytes = response.Content.ReadAsByteArrayAsync().Result; - using var os = File.OpenWrite(cacheName); - using var cos = new GZipStream(os, CompressionLevel.SmallestSize); - new CacheItem { - Etag = etag, - Version = 3, - Checksum = CalculateMD5(responseBytes), - Content = ByteString.CopyFrom(responseBytes) - }.WriteTo(cos); + if (cache) { + var etag = response.Headers.ETag!.Tag; + using var os = File.OpenWrite(cacheName); + using var cos = new GZipStream(os, CompressionLevel.SmallestSize); + new CacheItem { + Etag = etag, + Version = 3, + Checksum = CalculateMD5(responseBytes), + Content = ByteString.CopyFrom(responseBytes) + }.WriteTo(cos); + } return responseBytes; } @@ -81,7 +83,6 @@ public static class Utils { } public static void LoadConfig() { - Directory.CreateDirectory("cache"); var conf = JsonNode.Parse(File.ReadAllText(GlobalVars.ConfigFileName))!; var path = conf["genshinPath"]; if (path == null || CheckGamePathValid(path.GetValue())) { @@ -93,6 +94,35 @@ public static class Utils { } } + public static void CheckUpdate() { + var info = UpdateInfo.Parser.ParseFrom(GetBucketFileAsByteArray("schicksal/version"))!; + if (GlobalVars.AppVersionCode != info.VersionCode) { + Console.WriteLine($"有可用更新: {GlobalVars.AppVersionName} => {info.VersionName}"); + Console.WriteLine($"更新内容: \n{info.Description}"); + if (info.EnableAutoDownload) { + Console.WriteLine("正在下载更新包..."); + var fullPath = Path.GetFullPath("update.7z"); + File.WriteAllBytes(fullPath, GetBucketFileAsByteArray(info.PackageLink)); + Console.WriteLine("下载完毕! 关闭程序后, 将压缩包解压至当前目录即可完成更新."); + new Process { + StartInfo = { + FileName = fullPath, + UseShellExecute = true + } + }.Start(); + Environment.Exit(0); + } + Console.WriteLine($"下载地址: {info.PackageLink}"); + if (info.ForceUpdate) { + Console.WriteLine("在完成此次更新前, 程序可能无法正常使用."); + Environment.Exit(0); + } + } + if (info.EnableLibDownload) { + File.WriteAllBytes("YaeLib.dll", GetBucketFileAsByteArray("schicksal/lib.dll")); + } + } + private static bool CheckGamePathValid(string path) { var dir = Path.GetDirectoryName(path)!; return File.Exists($"{dir}/UnityPlayer.dll") && File.Exists($"{dir}/mhypbase.dll");