From a272fdc58839b65bdf50b6abcf1a2b3658c4077b Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Sat, 25 May 2024 08:54:58 +0700 Subject: [PATCH] Update sophon and HYP install mechanism --- .../RegionResourcePluginValidateConverter.cs | 60 +++++ .../HoYoPlay/HoYoPlayLauncherApiLoader.cs | 255 +++++++++++------- .../HoYoPlay/HoYoPlayLauncherResource.cs | 35 ++- .../Classes/Helper/Metadata/PresetConfig.cs | 3 + .../BaseClass/InstallManagerBase.cs | 4 +- .../Genshin/GenshinSophonInstall.cs | 40 ++- .../Classes/RegionManagement/RegionClasses.cs | 55 +--- Hi3Helper.Sophon | 2 +- 8 files changed, 290 insertions(+), 164 deletions(-) create mode 100644 CollapseLauncher/Classes/Helper/JsonConverter/RegionResourcePluginValidateConverter.cs diff --git a/CollapseLauncher/Classes/Helper/JsonConverter/RegionResourcePluginValidateConverter.cs b/CollapseLauncher/Classes/Helper/JsonConverter/RegionResourcePluginValidateConverter.cs new file mode 100644 index 000000000..a1f48a9c2 --- /dev/null +++ b/CollapseLauncher/Classes/Helper/JsonConverter/RegionResourcePluginValidateConverter.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace CollapseLauncher.Helper.JsonConverter +{ + public class RegionResourcePluginValidateConverter : JsonConverter> + { + public override bool CanConvert(Type type) + { + return true; + } + + public override List Read( + ref Utf8JsonReader reader, + Type typeToConvert, + JsonSerializerOptions options) + { + string valueString = EmptiedBackslash(reader.ValueSpan); + List returnList = valueString.Deserialize>(InternalAppJSONContext.Default); + + return returnList; + } + + private unsafe string EmptiedBackslash(ReadOnlySpan span) + { + Span buffer = new byte[span.Length]; + int indexIn = 0; + int indexOut = 0; + while (indexIn < span.Length) + { + if (span[indexIn] == '\\') + { + ++indexIn; + continue; + } + + buffer[indexOut] = span[indexIn]; + ++indexIn; + ++indexOut; + } + + fixed (byte* bufferPtr = buffer) + { + return Encoding.UTF8.GetString(bufferPtr, indexOut); + } + } + + public override void Write( + Utf8JsonWriter writer, + List baseType, + JsonSerializerOptions options) + { + + throw new JsonException($"Serializing is not supported!"); + } + } +} diff --git a/CollapseLauncher/Classes/Helper/LauncherApiLoader/HoYoPlay/HoYoPlayLauncherApiLoader.cs b/CollapseLauncher/Classes/Helper/LauncherApiLoader/HoYoPlay/HoYoPlayLauncherApiLoader.cs index 9a08a3f4b..0383b5893 100644 --- a/CollapseLauncher/Classes/Helper/LauncherApiLoader/HoYoPlay/HoYoPlayLauncherApiLoader.cs +++ b/CollapseLauncher/Classes/Helper/LauncherApiLoader/HoYoPlay/HoYoPlayLauncherApiLoader.cs @@ -28,7 +28,7 @@ protected override async Task LoadLauncherGameResource(ActionOnTimeOutRetry? onT new ActionTimeoutValueTaskCallback(async (innerToken) => await FallbackCDNUtil.DownloadAsJSONType(PresetConfig?.LauncherResourceURL, InternalAppJSONContext.Default, innerToken)); - ActionTimeoutValueTaskCallback hypPluginResourceCallback = + ActionTimeoutValueTaskCallback hypPluginResourceCallback = new ActionTimeoutValueTaskCallback(async (innerToken) => await FallbackCDNUtil.DownloadAsJSONType(PresetConfig?.LauncherPluginURL, InternalAppJSONContext.Default, innerToken)); @@ -58,40 +58,58 @@ protected override async Task LoadLauncherGameResource(ActionOnTimeOutRetry? onT data = sophonResourceData }; - ConvertPluginResources(sophonResourceData, hypPluginResource); + ConvertPluginResources(ref sophonResourceData, hypPluginResource); ConvertPackageResources(sophonResourceData, hypResourceResponse?.Data?.LauncherPackages); base.LauncherGameResource = sophonResourcePropRoot; } #region Convert Plugin Resources - private void ConvertPluginResources(RegionResourceGame sophonResourceData, HoYoPlayLauncherResources? hypPluginResources) + private void ConvertPluginResources(ref RegionResourceGame sophonResourceData, HoYoPlayLauncherResources? hypPluginResources) { - List? hypPluginResourcesList = hypPluginResources?.Data?.PluginPackages; - if (hypPluginResourcesList == null || hypPluginResourcesList.Count == 0) return; + LauncherPackages? hypPluginPackage = hypPluginResources?.Data? + .PluginPackages? + .FirstOrDefault(x => x.GameDetail? + .GameBiz? + .Equals(PresetConfig?.LauncherBizName, StringComparison.OrdinalIgnoreCase) ?? false); - List pluginCurrentPackageList = new List(); + if (hypPluginPackage == null) return; - foreach (LauncherPackages hypPluginPackage in hypPluginResourcesList) + List pluginCurrentPackageList = new List(); + RegionResourcePlugin plugin = new RegionResourcePlugin() { - RegionResourcePlugin plugin = new RegionResourcePlugin() - { - package = new RegionResourceVersion() - }; - GuessAssignPluginConversion(plugin, hypPluginPackage); - } + package = new RegionResourceVersion() + }; + GuessAssignPluginConversion(pluginCurrentPackageList, hypPluginPackage); + sophonResourceData.plugins = pluginCurrentPackageList; } - private void GuessAssignPluginConversion(RegionResourcePlugin sophonPlugin, LauncherPackages hypPlugin) + private void GuessAssignPluginConversion(List sophonPluginList, LauncherPackages hypPlugin) { - PackagePartition? packagePartition = null; + List? pluginSectionsList = hypPlugin.PluginPackageSections; + if ((pluginSectionsList?.Count ?? 0) == 0) return; + if (pluginSectionsList == null) return; - if (hypPlugin.MainPackage != null) packagePartition = hypPlugin.MainPackage; - else if (hypPlugin.PluginPackage != null) packagePartition = hypPlugin.PluginPackage; + foreach (PackagePluginSections firstPluginSection in pluginSectionsList) + { + if (firstPluginSection == null) continue; - if (packagePartition == null) return; + RegionResourcePlugin sophonPlugin = new RegionResourcePlugin(); + sophonPlugin.version = firstPluginSection.Version; + // sophonPlugin.plugin_id = firstPluginSection.PluginId; + sophonPlugin.package = new RegionResourceVersion + { + validate = firstPluginSection.PluginPackage?.PackageAssetValidationList, + // channel_id = firstPluginSection.PluginId, + md5 = firstPluginSection.PluginPackage?.PackageMD5Hash, + url = firstPluginSection.PluginPackage?.PackageUrl, + path = firstPluginSection.PluginPackage?.PackageUrl, + size = firstPluginSection.PluginPackage?.PackageDecompressSize ?? 0, + package_size = firstPluginSection.PluginPackage?.PackageSize ?? 0 + }; - // TODO: Implement package conversion + sophonPluginList.Add(sophonPlugin); + } } #endregion @@ -100,101 +118,142 @@ private void ConvertPackageResources(RegionResourceGame sophonPackageResources, { if (hypLauncherPackagesList == null) throw new NullReferenceException("HoYoPlay package list is null!"); - foreach (LauncherPackages hypRootPackage in hypLauncherPackagesList) + foreach (LauncherPackages hypRootPackage in hypLauncherPackagesList + .Where(x => x.GameDetail?.GameBiz? + .Equals(PresetConfig?.LauncherBizName, StringComparison.OrdinalIgnoreCase) ?? false)) { - // Assign main game package - string? version = hypRootPackage?.MainPackage?.CurrentVersion?.Version; - List? hypMainGamePackageList = hypRootPackage?.MainPackage?.CurrentVersion?.GamePackages; - if (hypMainGamePackageList != null) + // Assign and convert main game package (latest) + PackageResourceSections? hypMainPackageSection = hypRootPackage?.MainPackage?.CurrentVersion; + RegionResourceVersion sophonMainPackageSection = new RegionResourceVersion(); + if (hypMainPackageSection != null) + ConvertHYPSectionToResourceVersion(ref hypMainPackageSection, ref sophonMainPackageSection); + sophonPackageResources.game.latest = sophonMainPackageSection; + + // Assign and convert main game package (diff) + if (hypRootPackage?.MainPackage?.Patches != null) { - // Main game package - RegionResourceVersion? sophonMainGamePackage = null; - PackageDetails? hypMainGamePackage = hypMainGamePackageList?.FirstOrDefault(); - if (hypMainGamePackage != null) + sophonPackageResources.game.diffs = new List(); + foreach (PackageResourceSections hypMainDiffPackageSection in hypRootPackage.MainPackage.Patches) { - sophonMainGamePackage = new RegionResourceVersion - { - md5 = hypMainGamePackage.PackageMD5Hash, - url = hypMainGamePackage.PackageUrl, - package_size = hypMainGamePackage.PackageSize ?? 0, - size = hypMainGamePackage.PackageDecompressSize, - version = version, - decompressed_path = hypMainGamePackage.UnpackedBaseUrl, - path = hypMainGamePackage.PackageUrl // As fallback for PackageUrl - }; - sophonPackageResources.game.latest = sophonMainGamePackage; - - // TODO: Add main diff game package download - - // Main audio package - List? hypMainAudioDetailList = hypRootPackage?.MainPackage?.CurrentVersion?.AudioPackages; - if (hypMainAudioDetailList != null) + if (hypMainDiffPackageSection != null) { - sophonMainGamePackage.voice_packs = new List(); - foreach (PackageDetails? hypAudioGamePackage in hypMainAudioDetailList) - { - sophonMainGamePackage.voice_packs.Add(new RegionResourceVersion - { - md5 = hypAudioGamePackage.PackageMD5Hash, - url = hypAudioGamePackage.PackageUrl, - package_size = hypAudioGamePackage.PackageSize ?? 0, - size = hypAudioGamePackage.PackageDecompressSize, - version = version, - decompressed_path = hypAudioGamePackage.UnpackedBaseUrl, - path = hypAudioGamePackage.PackageUrl // As fallback for PackageUrl - }); - } + PackageResourceSections hypMainDiffPackageSectionRef = hypMainDiffPackageSection; + RegionResourceVersion sophonResourceVersion = new RegionResourceVersion(); + ConvertHYPSectionToResourceVersion(ref hypMainDiffPackageSectionRef, ref sophonResourceVersion); + sophonPackageResources.game.diffs.Add(sophonResourceVersion); } } } - // Assign preload game package - string? preloadVersion = hypRootPackage?.PreDownload?.CurrentVersion?.Version; - List? hypPreloadGamePackageList = hypRootPackage?.PreDownload?.CurrentVersion?.GamePackages; - if (hypPreloadGamePackageList != null) + // Assign and convert preload game package (latest) + PackageResourceSections? hypPreloadPackageSection = hypRootPackage?.PreDownload?.CurrentVersion; + RegionResourceVersion sophonPreloadPackageSection = new RegionResourceVersion(); + if (hypPreloadPackageSection != null) + ConvertHYPSectionToResourceVersion(ref hypPreloadPackageSection, ref sophonPreloadPackageSection); + sophonPackageResources.pre_download_game.latest = sophonPreloadPackageSection; + + // Assign and convert preload game package (diff) + if (hypRootPackage?.PreDownload?.Patches != null) { - // Preload game package - RegionResourceVersion? sophonPreloadGamePackage = null; - PackageDetails? hypPreloadGamePackage = hypPreloadGamePackageList?.FirstOrDefault(); - if (hypPreloadGamePackage != null) + sophonPackageResources.pre_download_game.diffs = new List(); + foreach (PackageResourceSections hypPreloadDiffPackageSection in hypRootPackage.PreDownload.Patches) { - sophonPreloadGamePackage = new RegionResourceVersion - { - md5 = hypPreloadGamePackage.PackageMD5Hash, - url = hypPreloadGamePackage.PackageUrl, - package_size = hypPreloadGamePackage.PackageSize ?? 0, - size = hypPreloadGamePackage.PackageDecompressSize, - version = preloadVersion, - decompressed_path = hypPreloadGamePackage.UnpackedBaseUrl, - path = hypPreloadGamePackage.PackageUrl // As fallback for PackageUrl - }; - sophonPackageResources.pre_download_game.latest = sophonPreloadGamePackage; - - // TODO: Add preload diff game package download - - // Preload audio package - List? hypPreloadAudioDetailList = hypRootPackage?.PreDownload?.CurrentVersion?.AudioPackages; - if (hypPreloadAudioDetailList != null) + if (hypPreloadDiffPackageSection != null) { - sophonPreloadGamePackage.voice_packs = new List(); - foreach (PackageDetails? hypAudioGamePackage in hypPreloadAudioDetailList) - { - sophonPreloadGamePackage.voice_packs.Add(new RegionResourceVersion - { - md5 = hypAudioGamePackage.PackageMD5Hash, - url = hypAudioGamePackage.PackageUrl, - package_size = hypAudioGamePackage.PackageSize ?? 0, - size = hypAudioGamePackage.PackageDecompressSize, - version = version, - decompressed_path = hypAudioGamePackage.UnpackedBaseUrl, - path = hypAudioGamePackage.PackageUrl // As fallback for PackageUrl - }); - } + PackageResourceSections hypPreloadDiffPackageSectionRef = hypPreloadDiffPackageSection; + RegionResourceVersion sophonResourceVersion = new RegionResourceVersion(); + ConvertHYPSectionToResourceVersion(ref hypPreloadDiffPackageSectionRef, ref sophonResourceVersion); + sophonPackageResources.pre_download_game.diffs.Add(sophonResourceVersion); } } } } } + + private void ConvertHYPSectionToResourceVersion(ref PackageResourceSections hypPackageResourceSection, ref RegionResourceVersion sophonResourceVersion) + { + // Convert game packages + RegionResourceVersion packagesVersion = new RegionResourceVersion(); + DelegatePackageResConversionMode(ref packagesVersion, hypPackageResourceSection?.GamePackages, hypPackageResourceSection?.AudioPackages, hypPackageResourceSection?.Version, hypPackageResourceSection?.ResourceListUrl); + sophonResourceVersion = packagesVersion; + } + + private delegate void PackageResConversionModeDelegate(ref RegionResourceVersion sophonPackageVersion, List hypPackageList, + string? version, string? resourceListUrl); + + private void DelegatePackageResConversionMode(ref RegionResourceVersion sophonPackageVersion, List? hypGamePackageList, List? hypAudioPackageList, + string? version, string? resourceListUrl) + { + // If the main package list is not null or empty, then process + if (hypGamePackageList != null && hypGamePackageList.Count != 0) + { + // Delegate the conversion mode for the resource, then process it + PackageResConversionModeDelegate conversionDelegate = hypGamePackageList.Count > 1 ? ConvertMultiPackageResource : ConvertSinglePackageResource; + conversionDelegate(ref sophonPackageVersion, hypGamePackageList, version, resourceListUrl); + } + + // If the audio package list is not null or empty, then process + if (hypAudioPackageList != null && hypAudioPackageList.Count != 0) + { + sophonPackageVersion.voice_packs = new List(); + foreach (PackageDetails hypAudioPackage in hypAudioPackageList) + { + sophonPackageVersion.voice_packs.Add(new RegionResourceVersion + { + url = hypAudioPackage.PackageUrl, + path = hypAudioPackage.PackageUrl, // As fallback for PackageUrl + size = hypAudioPackage.PackageDecompressSize, + package_size = hypAudioPackage.PackageSize ?? 0, + md5 = hypAudioPackage.PackageMD5Hash, + language = hypAudioPackage.Language + }); + } + } + } + + private void ConvertSinglePackageResource(ref RegionResourceVersion sophonPackageVersion, List hypPackageList, + string? version, string? resourceListUrl) + { + PackageDetails packageDetail = hypPackageList[0]; + sophonPackageVersion.url = packageDetail.PackageUrl; + sophonPackageVersion.path = packageDetail.PackageUrl; // As fallback for PackageUrl + sophonPackageVersion.size = packageDetail.PackageDecompressSize; + sophonPackageVersion.package_size = packageDetail.PackageSize ?? 0; + sophonPackageVersion.md5 = packageDetail.PackageMD5Hash; + sophonPackageVersion.entry = PresetConfig?.GameExecutableName; + sophonPackageVersion.version = version; + sophonPackageVersion.decompressed_path = resourceListUrl; + } + + private void ConvertMultiPackageResource(ref RegionResourceVersion sophonPackageVersion, List hypPackageList, + string? version, string? resourceListUrl) + { + long totalSize = hypPackageList.Sum(x => x.PackageDecompressSize); + long totalPackageSize = hypPackageList.Sum(x => x.PackageSize ?? 0); + + sophonPackageVersion.url = string.Empty; + sophonPackageVersion.path = string.Empty; // As fallback for PackageUrl + sophonPackageVersion.md5 = string.Empty; + sophonPackageVersion.size = totalSize; + sophonPackageVersion.package_size = totalPackageSize; + sophonPackageVersion.entry = PresetConfig?.GameExecutableName; + sophonPackageVersion.version = version; + sophonPackageVersion.decompressed_path = resourceListUrl; + + sophonPackageVersion.segments = new List(); + + foreach (PackageDetails packageDetail in hypPackageList) + { + sophonPackageVersion.segments.Add(new RegionResourceVersion + { + url = packageDetail.PackageUrl, + path = packageDetail.PackageUrl, // As fallback for PackageUrl + size = packageDetail.PackageDecompressSize, + package_size = packageDetail.PackageSize ?? 0, + md5 = packageDetail.PackageMD5Hash + }); + } + } #endregion protected override async ValueTask LoadLauncherNews(ActionOnTimeOutRetry? onTimeoutRoutine, CancellationToken token) diff --git a/CollapseLauncher/Classes/Helper/LauncherApiLoader/HoYoPlay/HoYoPlayLauncherResource.cs b/CollapseLauncher/Classes/Helper/LauncherApiLoader/HoYoPlay/HoYoPlayLauncherResource.cs index 506a71cd4..f089d738f 100644 --- a/CollapseLauncher/Classes/Helper/LauncherApiLoader/HoYoPlay/HoYoPlayLauncherResource.cs +++ b/CollapseLauncher/Classes/Helper/LauncherApiLoader/HoYoPlay/HoYoPlayLauncherResource.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using CollapseLauncher.Helper.JsonConverter; +using System.Collections.Generic; using System.Text.Json.Serialization; #nullable enable @@ -34,8 +35,8 @@ public class LauncherPackages [JsonPropertyName("main")] public PackagePartition? MainPackage { get; set; } - [JsonPropertyName("plugin")] - public PackagePartition? PluginPackage { get; set; } + [JsonPropertyName("plugins")] + public List? PluginPackageSections { get; set; } [JsonPropertyName("pre_download")] public PackagePartition? PreDownload { get; set; } @@ -53,13 +54,28 @@ public class GameDetail public class PackagePartition { [JsonPropertyName("major")] - public PackageSections? CurrentVersion { get; set; } + public PackageResourceSections? CurrentVersion { get; set; } [JsonPropertyName("patches")] - public List? Patches { get; set; } + public List? Patches { get; set; } } - public class PackageSections + public class PackagePluginSections + { + [JsonPropertyName("plugin_id")] + public string? PluginId { get; set; } + + [JsonPropertyName("plugin_pkg")] + public PackageDetails? PluginPackage { get; set; } + + [JsonPropertyName("release_id")] + public string? ReleaseId { get; set; } + + [JsonPropertyName("version")] + public string? Version { get; set; } + } + + public class PackageResourceSections { [JsonPropertyName("audio_pkgs")] public List? AudioPackages { get; set; } @@ -100,8 +116,11 @@ public class PackageDetails public string? ChannelSDKPkg { get; init; } [JsonPropertyName("command")] - // TODO: Figure out the property purpose - public string? Command { get; init; } + public string? PackageRunCommand { get; init; } + + [JsonPropertyName("validation")] + [JsonConverter(typeof(RegionResourcePluginValidateConverter))] + public List? PackageAssetValidationList { get; init; } [JsonPropertyName("language")] public string? Language { get; init; } diff --git a/CollapseLauncher/Classes/Helper/Metadata/PresetConfig.cs b/CollapseLauncher/Classes/Helper/Metadata/PresetConfig.cs index 39a03ffd7..b3aec66a4 100644 --- a/CollapseLauncher/Classes/Helper/Metadata/PresetConfig.cs +++ b/CollapseLauncher/Classes/Helper/Metadata/PresetConfig.cs @@ -135,6 +135,9 @@ internal class PresetConfig [JsonConverter(typeof(ServeV3StringConverter))] public string? GameName { get; set; } + [JsonConverter(typeof(ServeV3StringConverter))] + public string? LauncherBizName { get; init; } + [JsonConverter(typeof(ServeV3StringConverter))] public string? LauncherSpriteURL { get; init; } diff --git a/CollapseLauncher/Classes/InstallManagement/BaseClass/InstallManagerBase.cs b/CollapseLauncher/Classes/InstallManagement/BaseClass/InstallManagerBase.cs index 90566950e..43b6b5601 100644 --- a/CollapseLauncher/Classes/InstallManagement/BaseClass/InstallManagerBase.cs +++ b/CollapseLauncher/Classes/InstallManagement/BaseClass/InstallManagerBase.cs @@ -2057,8 +2057,8 @@ private async Task GetPackagesRemoteSize(List packageList, C #endregion #region Virtual Methods - StartPackageDownload - private enum CompletenessStatus { Running, Completed, Cancelled, Idle } - private void UpdateCompletenessStatus(CompletenessStatus status) + protected enum CompletenessStatus { Running, Completed, Cancelled, Idle } + protected void UpdateCompletenessStatus(CompletenessStatus status) { switch (status) { diff --git a/CollapseLauncher/Classes/InstallManagement/Genshin/GenshinSophonInstall.cs b/CollapseLauncher/Classes/InstallManagement/Genshin/GenshinSophonInstall.cs index 988a11a39..886a2eef2 100644 --- a/CollapseLauncher/Classes/InstallManagement/Genshin/GenshinSophonInstall.cs +++ b/CollapseLauncher/Classes/InstallManagement/Genshin/GenshinSophonInstall.cs @@ -58,6 +58,9 @@ public override async Task StartPackageDownload(bool skipDialog) try { + // Set background status + UpdateCompletenessStatus(CompletenessStatus.Running); + // Reset status and progress properties ResetStatusAndProgressProperty(); @@ -137,8 +140,37 @@ await Parallel.ForEachAsync( async (asset, threadToken) => await RunSophonAssetDownloadThread(httpClient, asset, parallelOptions)); } + // Rename temporary files + foreach (SophonChunkManifestInfoPair sophonDownloadInfoPair in sophonInfoPairList) + { + await Parallel.ForEachAsync( + SophonManifest.EnumerateAsync(httpClient, sophonDownloadInfoPair), + parallelOptions, + async (asset, threadToken) => + { + // If the asset is a dictionary, then return + if (asset.IsDirectory) return; + + // Get the file path and start the write process + string assetName = asset.AssetName; + string filePath = EnsureCreationOfDirectory(Path.Combine(_gamePath, assetName)) + "_tempSophon"; + string origFilePath = Path.Combine(_gamePath, assetName); + + if (File.Exists(filePath)) + File.Move(filePath, origFilePath, true); + }); + } + + // Set background status + UpdateCompletenessStatus(CompletenessStatus.Completed); IsDownloadCompleted = true; } + catch (Exception) + { + // Set background status + UpdateCompletenessStatus(CompletenessStatus.Cancelled); + throw; + } finally { // Unsubscribe the logger event @@ -193,7 +225,13 @@ private async ValueTask RunSophonAssetDownloadThread(HttpClient client, SophonAs if (asset.IsDirectory) return; // Get the file path and start the write process - string filePath = EnsureCreationOfDirectory(Path.Combine(_gamePath, asset.AssetName)); + string assetName = asset.AssetName; + string filePath = EnsureCreationOfDirectory(Path.Combine(_gamePath, assetName)); + + // Use "_tempSophon" if file is new or if "_tempSophon" file exist. Otherwise use original file if exist + if (!File.Exists(filePath) || File.Exists(filePath + "_tempSophon")) + filePath += "_tempSophon"; + await asset.WriteToStreamAsync( client, () => new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite), diff --git a/CollapseLauncher/Classes/RegionManagement/RegionClasses.cs b/CollapseLauncher/Classes/RegionManagement/RegionClasses.cs index c28eb3571..e3144f31c 100644 --- a/CollapseLauncher/Classes/RegionManagement/RegionClasses.cs +++ b/CollapseLauncher/Classes/RegionManagement/RegionClasses.cs @@ -1,9 +1,8 @@ using CollapseLauncher.Helper.Image; +using CollapseLauncher.Helper.JsonConverter; using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Text.Json; using System.Text.Json.Serialization; using System.Threading; @@ -147,58 +146,6 @@ public class RegionResourceVersion : IRegionResourceCopyable> - { - public override bool CanConvert(Type type) - { - return true; - } - - public override List Read( - ref Utf8JsonReader reader, - Type typeToConvert, - JsonSerializerOptions options) - { - string valueString = EmptiedBackslash(reader.ValueSpan); - List returnList = valueString.Deserialize>(InternalAppJSONContext.Default); - - return returnList; - } - - private unsafe string EmptiedBackslash(ReadOnlySpan span) - { - Span buffer = new byte[span.Length]; - int indexIn = 0; - int indexOut = 0; - while (indexIn < span.Length) - { - if (span[indexIn] == '\\') - { - ++indexIn; - continue; - } - - buffer[indexOut] = span[indexIn]; - ++indexIn; - ++indexOut; - } - - fixed (byte* bufferPtr = buffer) - { - return Encoding.UTF8.GetString(bufferPtr, indexOut); - } - } - - public override void Write( - Utf8JsonWriter writer, - List baseType, - JsonSerializerOptions options) - { - - throw new JsonException($"Serializing is not supported!"); - } - } - public class HomeMenuPanel : IRegionResourceCopyable { public List sideMenuPanel { get; set; } diff --git a/Hi3Helper.Sophon b/Hi3Helper.Sophon index 8a470f1c0..ecf757c9f 160000 --- a/Hi3Helper.Sophon +++ b/Hi3Helper.Sophon @@ -1 +1 @@ -Subproject commit 8a470f1c0ba081b4f55fe3be26e1fca0e92376d4 +Subproject commit ecf757c9fba6a787cb62451689a9f04de03e2c31