diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 640896e7f..ee90e1be9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,5 +1,6 @@ # Credits to @Scighost from Starward for his contributions! name: Build-Canary +run-name: Canary Build for ${{ github.ref }} on: workflow_dispatch: @@ -22,10 +23,7 @@ on: - "net7.0-windows10.0.22000.0" - "net7.0-windows10.0.19041.0" - - jobs: - build: runs-on: ${{ github.event.inputs.os }} strategy: @@ -36,6 +34,7 @@ jobs: env: Configuration: ${{ matrix.configuration }} Platform: ${{ matrix.platform }} + DOTNET_INSTALL_DIR: '.\.dotnet' steps: - name: Checkout @@ -43,6 +42,28 @@ jobs: with: submodules: recursive + - name: Get short Git SHA + id: vars + run: | + echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_ENV + echo "branch=$(echo ${GITHUB_REF#refs/heads/})" >> $GITHUB_ENV + + - name: Cache dotnet # cache dotnet install https://stackoverflow.com/questions/75180149/how-to-cache-dotnet-installation-in-github-actions + id: cache-dotnet + uses: actions/cache@v3 + with: + path: ${{ env.DOTNET_INSTALL_DIR }} + key: ${{ runner.os }}-dotnet-7 + restore-keys: ${{ runner.os }}-dotnet-7 + + - name: Cache nuget # cache nuget https://github.com/actions/cache/blob/main/examples.md#c---nuget + uses: actions/cache@v3 + with: + path: ~/.nuget/packages + key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }} + restore-keys: | + ${{ runner.os }}-nuget- + - name: Install .NET uses: actions/setup-dotnet@v3 with: @@ -59,16 +80,16 @@ jobs: msbuild CollapseLauncher "-property:Configuration=$env:Configuration;Platform=$env:Platform" dotnet build CollapseLauncher -c $env:Configuration -p:Platform=$env:Platform -f ${{ github.event.inputs.framework }} - - name: Upload Artifact (Debug) - uses: actions/upload-artifact@v3.1.2 - if: ${{ matrix.configuration == 'Debug' }} - with: - name: collapse_${{ github.sha }}.${{ matrix.platform }}-${{ matrix.configuration }} - path: ./CollapseLauncher/bin/x64/Debug/net7.0-windows10.0.22000.0/ +# - name: Upload Artifact (Debug) +# uses: actions/upload-artifact@v3.1.2 +# if: ${{ matrix.configuration == 'Debug' }} +# with: +# name: collapse_${{ github.ref }}_${{ steps.vars.outputs.sha_short }}.${{ matrix.platform }}-${{ matrix.configuration }} +# path: ./CollapseLauncher/bin/x64/Debug/${{ github.event.inputs.framework }}/ - name: Upload Artifact (Release) uses: actions/upload-artifact@v3.1.2 if: ${{ matrix.configuration == 'Release' }} with: - name: collapse_${{ github.sha }}.${{ matrix.platform }}-${{ matrix.configuration }} - path: ./CollapseLauncher/bin/x64/Release/net7.0-windows10.0.22000.0/ + name: collapse_${{ matrix.platform }}-${{ matrix.configuration }}_${{ github.event.inputs.framework }}_${{ github.sha }} + path: ./CollapseLauncher/bin/x64/Release/${{ github.event.inputs.framework }}/ diff --git a/.gitignore b/.gitignore index ec67c6883..0b7076548 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,83 @@ CollapseLauncher/Invoker/* *.psd InstallerProp/Output/* InstallerProp/temp/** + +### Rider ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf +.idea/* + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..c2414dd4f --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,128 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, religion, or sexual identity +and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the + overall community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or + advances of any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email + address, without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +dev.kemalsetyaa@gmail.com. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series +of actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or +permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within +the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.0, available at +https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. + +Community Impact Guidelines were inspired by [Mozilla's code of conduct +enforcement ladder](https://github.com/mozilla/diversity). + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see the FAQ at +https://www.contributor-covenant.org/faq. Translations are available at +https://www.contributor-covenant.org/translations. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a4aec7264..afd949ce3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,10 +16,17 @@ If you wish to add new language that isn't yet listed in the Crowdin project, pl ## Tools Needed Below is a list of tools needed to contribute to this project: 1. **Visual Studio 2022 (Any Edition - 17.4 or later)** + - Select .NET desktop development component 2. **Windows SDK (10.0.19043.0 or 10.0.22000.0 ONLY)** via Visual Studio Installer 3. .NET Core 7 SDK: [**(7.0.100 or later)**](https://dotnet.microsoft.com/en-us/download/dotnet/7.0) 4. WinUI 3: [**(WindowsAppSDK 1.3.0-230331000 Stable Runtime)**](https://aka.ms/windowsappsdk/1.3/1.3.230331000/windowsappruntimeinstall-x64.exe) +> **Note**: +> +> Starting from November 13rd 2022, you must have Visual Studio 2022 installed on your computer due to the updated minimum system requirement of `WinUI 3 1.3 Stable`. +> +> Using a lower Visual Studio version (like VS2019) is possible, but it is not recommended as you need to downgrade **WindowsAppSDK** via *NuGet* to **WindowsAppSDK 1.1.5** or **WindowsAppSDK 1.2-preview2** before building. This has an increased risk of breaking the application and as such, no support will be provided for this method. **This is not recommended for beginner users.** + ## Restrictions for New Feature(s) While this software is fully open source and not affiliated with HoYoverse, Cognosphere, or any of its related entities in any way, we are nonetheless bound to their Terms of Service and Code of Conduct when developing Collapse. This means that there are some features that we will **not** implement. We will close any issue or PRs that are made to add such functionality to Collapse. Such features include, but are not limited to: - Anything that, in any way, interacts with the miHoYo SDK and/or API, including their Authentication and Payment Processing endpoints. diff --git a/CollapseLauncher/App.xaml b/CollapseLauncher/App.xaml index 6749198c0..771d2735b 100644 --- a/CollapseLauncher/App.xaml +++ b/CollapseLauncher/App.xaml @@ -2,7 +2,8 @@ x:Class="CollapseLauncher.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - xmlns:local="using:CollapseLauncher"> + xmlns:local="using:CollapseLauncher" + xmlns:localUI="using:Microsoft.UI.Xaml.Controls"> @@ -14,7 +15,7 @@ #ffd52a #ffd52a #ffd52a - + @@ -46,21 +47,23 @@ - + - - + + + + - - - + + + @@ -98,7 +101,7 @@ - + @@ -107,21 +110,307 @@ - + + - + + + ms-appx:///Assets/Fonts/FontAwesomeBrand6.otf#Font Awesome 6 Brands + ms-appx:///Assets/Fonts/FontAwesomeRegular6.otf#Font Awesome 6 Free + ms-appx:///Assets/Fonts/FontAwesomeSolid6.otf#Font Awesome 6 Free Solid + 0,47,0,0 + + + + + + - - ms-appx:///Assets/Fonts/FontAwesomeBrand6.otf#Font Awesome 6 Brands - ms-appx:///Assets/Fonts/FontAwesomeRegular6.otf#Font Awesome 6 Free - ms-appx:///Assets/Fonts/FontAwesomeSolid6.otf#Font Awesome 6 Free Solid - diff --git a/CollapseLauncher/App.xaml.cs b/CollapseLauncher/App.xaml.cs index 215452493..9c7436936 100644 --- a/CollapseLauncher/App.xaml.cs +++ b/CollapseLauncher/App.xaml.cs @@ -1,6 +1,14 @@ using Hi3Helper; +using Hi3Helper.Shared.Region; +using Microsoft.UI; using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Media; +using Microsoft.UI.Xaml.Resources; using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Windows.Storage; using static CollapseLauncher.InnerLauncherConfig; using static Hi3Helper.Logger; @@ -15,6 +23,10 @@ public App() { try { + bool IsAcrylicEnabled = LauncherConfig.GetAppConfigValue("EnableAcrylicEffect").ToBool(); + + if (!IsAcrylicEnabled) ToggleBlurBackdrop(false); + this.InitializeComponent(); RequestedTheme = CurrentRequestedAppTheme = GetAppTheme(); @@ -39,5 +51,45 @@ public App() Console.ReadLine(); } } + + public static async void ToggleBlurBackdrop(bool useBackdrop = true) + { + // Always wait for the resources to load up + while (true) + { + try + { + await Task.Delay(250); + if (Current.Resources.Count != 0) break; + } + catch { } + } + + // Enumerate the dictionary (MergedDictionaries) + foreach (ResourceDictionary resource in Current + .Resources + .MergedDictionaries) + { + // Parse the dictionary (ThemeDictionaries) and read the type of KeyValuePair, + // then select the value, get the type of ResourceDictionary, then enumerate it + foreach (ResourceDictionary list in resource + .ThemeDictionaries + .OfType>() + .Select(x => x.Value) + .OfType()) + { + // Parse the dictionary as type of KeyValuePair, + // and get the value which has type of AcrylicBrush only, then enumerate it + foreach (AcrylicBrush theme in list + .OfType>() + .Select(x => x.Value) + .OfType()) + { + // Set the theme AlwaysUseFallback as per toggle from useBackdrop. + theme.AlwaysUseFallback = !useBackdrop; + } + } + } + } } } diff --git a/CollapseLauncher/Assets/BG/AiHappy.png b/CollapseLauncher/Assets/Images/AiHappy.png similarity index 100% rename from CollapseLauncher/Assets/BG/AiHappy.png rename to CollapseLauncher/Assets/Images/AiHappy.png diff --git a/CollapseLauncher/Assets/BG/AponiaFly.png b/CollapseLauncher/Assets/Images/AponiaFly.png similarity index 100% rename from CollapseLauncher/Assets/BG/AponiaFly.png rename to CollapseLauncher/Assets/Images/AponiaFly.png diff --git a/CollapseLauncher/Assets/BG/PaimonSleep.png b/CollapseLauncher/Assets/Images/PaimonSleep.png similarity index 100% rename from CollapseLauncher/Assets/BG/PaimonSleep.png rename to CollapseLauncher/Assets/Images/PaimonSleep.png diff --git a/CollapseLauncher/Assets/BG/PaimonWhat.png b/CollapseLauncher/Assets/Images/PaimonWhat.png similarity index 100% rename from CollapseLauncher/Assets/BG/PaimonWhat.png rename to CollapseLauncher/Assets/Images/PaimonWhat.png diff --git a/CollapseLauncher/Assets/BG/StartUpBG.png b/CollapseLauncher/Assets/Images/StartupBackground.png similarity index 100% rename from CollapseLauncher/Assets/BG/StartUpBG.png rename to CollapseLauncher/Assets/Images/StartupBackground.png diff --git a/CollapseLauncher/Assets/BG/StartUpBG2.png b/CollapseLauncher/Assets/Images/StartupBackground2.png similarity index 100% rename from CollapseLauncher/Assets/BG/StartUpBG2.png rename to CollapseLauncher/Assets/Images/StartupBackground2.png diff --git a/CollapseLauncher/Assets/BG/default.png b/CollapseLauncher/Assets/Images/default.png similarity index 100% rename from CollapseLauncher/Assets/BG/default.png rename to CollapseLauncher/Assets/Images/default.png diff --git a/CollapseLauncher/Assets/Presets/CommunityTools.json b/CollapseLauncher/Assets/Presets/CommunityTools.json index 1e794d1cd..3d225e8dd 100644 --- a/CollapseLauncher/Assets/Presets/CommunityTools.json +++ b/CollapseLauncher/Assets/Presets/CommunityTools.json @@ -80,6 +80,12 @@ "IconGlyph": "", "Text": "Reddit Community", "URL": "https://www.reddit.com/r/HonkaiImpact3rd/" + }, + { + "IconFontFamily": "ms-appx:///Assets/Fonts/FontAwesomeSolid6.otf#Font Awesome 6 Free Solid", + "IconGlyph": "", + "Text": "ER Build Guide", + "URL": "https://risbi0.github.io/Elysian-Realm/" } ], "Genshin": [ @@ -159,4 +165,4 @@ } ] } -} \ No newline at end of file +} diff --git a/CollapseLauncher/Classes/BackgroundManagement/BackgroundManagement.cs b/CollapseLauncher/Classes/BackgroundManagement/BackgroundManagement.cs index 8222c81c4..050db1284 100644 --- a/CollapseLauncher/Classes/BackgroundManagement/BackgroundManagement.cs +++ b/CollapseLauncher/Classes/BackgroundManagement/BackgroundManagement.cs @@ -1,7 +1,6 @@ using ColorThiefDotNet; using Hi3Helper; using Hi3Helper.Data; -using Hi3Helper.Preset; using Hi3Helper.Shared.ClassStruct; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; @@ -13,13 +12,10 @@ using System.Drawing; using System.IO; using System.Linq; -using System.Text.Json; -using System.Threading; using System.Threading.Tasks; using Windows.Graphics.Imaging; using Windows.Storage.Streams; using static CollapseLauncher.InnerLauncherConfig; -using static Hi3Helper.Locale; using static Hi3Helper.Logger; using static Hi3Helper.Shared.Region.LauncherConfig; @@ -34,20 +30,6 @@ public sealed partial class MainPage : Page private bool BGLastState = true; private bool IsFirstStartup = true; - private async ValueTask FetchLauncherLocalizedResources(CancellationToken Token, PresetConfigV2 Preset) - { - regionBackgroundProp = Preset.LauncherSpriteURLMultiLang ? - await TryGetMultiLangResourceProp(Token, Preset) : - await TryGetSingleLangResourceProp(Token, Preset); - - await DownloadBackgroundImage(Token); - - await GetLauncherAdvInfo(Token, Preset); - await GetLauncherCarouselInfo(Token); - await GetLauncherEventInfo(Token); - GetLauncherPostInfo(); - } - private async Task ChangeBackgroundImageAsRegion() { IsCustomBG = GetAppConfigValue("UseCustomBG").ToBool(); @@ -70,236 +52,124 @@ private async Task ChangeBackgroundImageAsRegion() ReloadPageTheme(this, ConvertAppThemeToElementTheme(CurrentAppTheme)); } - private async ValueTask FetchLauncherDownloadInformation(CancellationToken Token, PresetConfigV2 Preset) - { - using (Stream netStream = (await _httpClient.DownloadFromSessionStreamAsync( - Preset.LauncherResourceURL, - 0, - null, - Token - )).Item1) - { - _gameAPIProp = (RegionResourceProp)JsonSerializer.Deserialize(netStream, typeof(RegionResourceProp), RegionResourcePropContext.Default) ?? new RegionResourceProp(); - -#if DEBUG - if (_gameAPIProp.data.game.latest.decompressed_path != null) LogWriteLine($"Decompressed Path: {_gameAPIProp.data.game.latest.decompressed_path}", LogType.Default, true); - if (_gameAPIProp.data.game.latest.path != null) LogWriteLine($"ZIP Path: {_gameAPIProp.data.game.latest.path}", LogType.Default, true); - if (_gameAPIProp.data.pre_download_game?.latest?.decompressed_path != null) LogWriteLine($"Decompressed Path Pre-load: {_gameAPIProp.data.pre_download_game?.latest?.decompressed_path}", LogType.Default, true); - if (_gameAPIProp.data.pre_download_game?.latest?.path != null) LogWriteLine($"ZIP Path Pre-load: {_gameAPIProp.data.pre_download_game?.latest?.path}", LogType.Default, true); -#endif - } - } - - private async ValueTask TryGetMultiLangResourceProp(CancellationToken Token, PresetConfigV2 Preset) - { - RegionResourceProp ret = await GetMultiLangResourceProp(Lang.LanguageID.ToLower(), Token, Preset); - - return ret.data.adv == null - || ((ret.data.adv.version ?? 5) <= 4 - && Preset.GameType == GameType.Honkai) ? - await GetMultiLangResourceProp(Preset.LauncherSpriteURLMultiLangFallback ?? "en-us", Token, Preset) : - ret; - } - - private async ValueTask GetMultiLangResourceProp(string langID, CancellationToken token, PresetConfigV2 Preset) - { - using (Stream netStream = (await _httpClient.DownloadFromSessionStreamAsync( - string.Format(Preset.LauncherSpriteURL, langID), - 0, - null, - token - )).Item1) - { - return (RegionResourceProp)JsonSerializer.Deserialize(netStream, typeof(RegionResourceProp), RegionResourcePropContext.Default) ?? new RegionResourceProp(); - } - } - - private async ValueTask TryGetSingleLangResourceProp(CancellationToken Token, PresetConfigV2 Preset) - { - using (Stream netStream = (await _httpClient.DownloadFromSessionStreamAsync( - Preset.LauncherSpriteURL, - 0, - null, - Token - )).Item1) - { - return (RegionResourceProp)JsonSerializer.Deserialize(netStream, typeof(RegionResourceProp), RegionResourcePropContext.Default) ?? new RegionResourceProp(); - } - } - - private void ResetRegionProp() - { - LastRegionNewsProp = regionNewsProp.Copy(); - regionNewsProp = new HomeMenuPanel() - { - sideMenuPanel = null, - imageCarouselPanel = null, - articlePanel = null, - eventPanel = null - }; - } - - private async ValueTask GetLauncherAdvInfo(CancellationToken Token, PresetConfigV2 Preset) - { - if (regionBackgroundProp.data.icon.Count == 0) return; - - regionNewsProp.sideMenuPanel = new List(); - foreach (RegionSocMedProp item in regionBackgroundProp.data.icon) - { - regionNewsProp.sideMenuPanel.Add(new MenuPanelProp - { - URL = item.url, - Icon = await GetCachedSprites(item.img, Token), - IconHover = await GetCachedSprites(item.img_hover, Token), - QR = string.IsNullOrEmpty(item.qr_img) ? null : await GetCachedSprites(item.qr_img, Token), - QR_Description = string.IsNullOrEmpty(item.qr_desc) ? null : item.qr_desc, - Description = string.IsNullOrEmpty(item.title) || Preset.IsHideSocMedDesc ? item.url : item.title - }); - } - } - - private async ValueTask GetLauncherCarouselInfo(CancellationToken Token) + public static async void ApplyAccentColor(Page page, Bitmap bitmapinput) { - if (regionBackgroundProp.data.banner.Count == 0) return; - - regionNewsProp.imageCarouselPanel = new List(); - foreach (RegionSocMedProp item in regionBackgroundProp.data.banner) - { - regionNewsProp.imageCarouselPanel.Add(new MenuPanelProp - { - URL = item.url, - Icon = await GetCachedSprites(item.img, Token), - Description = string.IsNullOrEmpty(item.name) ? item.url : item.name - }); - } - } - - private async ValueTask GetLauncherEventInfo(CancellationToken Token) - { - if (string.IsNullOrEmpty(regionBackgroundProp.data.adv.icon)) return; - - regionNewsProp.eventPanel = new RegionBackgroundProp - { - url = regionBackgroundProp.data.adv.url, - icon = await GetCachedSprites(regionBackgroundProp.data.adv.icon, Token) - }; - } - - private void GetLauncherPostInfo() - { - if (regionBackgroundProp.data.post.Count == 0) return; - - regionNewsProp.articlePanel = new PostCarouselTypes(); - foreach (RegionSocMedProp item in regionBackgroundProp.data.post) - { - switch (item.type) - { - case PostCarouselType.POST_TYPE_ACTIVITY: - regionNewsProp.articlePanel.Events.Add(item); - break; - case PostCarouselType.POST_TYPE_ANNOUNCE: - regionNewsProp.articlePanel.Notices.Add(item); - break; - case PostCarouselType.POST_TYPE_INFO: - regionNewsProp.articlePanel.Info.Add(item); - break; - } - } - } - - public async ValueTask GetCachedSprites(string URL, CancellationToken token) - { - string cacheFolder = Path.Combine(AppGameImgFolder, "cache"); - string cachePath = Path.Combine(cacheFolder, Path.GetFileNameWithoutExtension(URL)); - if (!Directory.Exists(cacheFolder)) - Directory.CreateDirectory(cacheFolder); - - FileInfo fInfo = new FileInfo(cachePath); - - if (!fInfo.Exists || fInfo.Length < (1 << 10)) - { - using (FileStream fs = fInfo.Create()) - { - using (Stream netStream = (await _httpClient.DownloadFromSessionStreamAsync(URL, 0, null, token)).Item1) - { - netStream.CopyTo(fs); - } - } - } - - return cachePath; - } - - public static async Task ApplyAccentColor(Page page, Bitmap bitmapinput, int quality) - { - Windows.UI.Color[] _colors; switch (CurrentAppTheme) { case AppThemeMode.Light: - _colors = await SetLightColors(bitmapinput, quality); + await SetLightColors(bitmapinput); break; case AppThemeMode.Dark: - _colors = await SetDarkColors(bitmapinput, quality); + await SetDarkColors(bitmapinput); break; default: if (SystemAppTheme.ToString() == "#FFFFFFFF") - _colors = await SetLightColors(bitmapinput, quality); + await SetLightColors(bitmapinput); else - _colors = await SetDarkColors(bitmapinput, quality); + await SetDarkColors(bitmapinput); break; } ReloadPageTheme(page, ConvertAppThemeToElementTheme(CurrentAppTheme)); - return _colors; } - private static async Task SetLightColors(Bitmap bitmapinput, int quality) + private static async Task SetLightColors(Bitmap bitmapinput) { - Windows.UI.Color[] _colors = await GetPaletteList(bitmapinput, 128, true, quality); + Windows.UI.Color[] _colors = await GetPaletteList(bitmapinput, 10, true, 1); Application.Current.Resources["SystemAccentColor"] = _colors[0]; - Application.Current.Resources["SystemAccentColorDark1"] = _colors[1]; - Application.Current.Resources["SystemAccentColorDark2"] = _colors[2]; - Application.Current.Resources["SystemAccentColorDark3"] = _colors[3]; - Application.Current.Resources["AccentColor"] = new SolidColorBrush(_colors[0]); - - return _colors; + Application.Current.Resources["SystemAccentColorDark1"] = _colors[0]; + Application.Current.Resources["SystemAccentColorDark2"] = _colors[1]; + Application.Current.Resources["SystemAccentColorDark3"] = _colors[1]; + Application.Current.Resources["AccentColor"] = new SolidColorBrush(_colors[1]); } - private static async Task SetDarkColors(Bitmap bitmapinput, int quality) + private static async Task SetDarkColors(Bitmap bitmapinput) { - Windows.UI.Color[] _colors = await GetPaletteList(bitmapinput, 255, false, quality); + Windows.UI.Color[] _colors = await GetPaletteList(bitmapinput, 10, false, 1); Application.Current.Resources["SystemAccentColor"] = _colors[0]; - Application.Current.Resources["SystemAccentColorLight1"] = _colors[1]; - Application.Current.Resources["SystemAccentColorLight2"] = _colors[2]; - Application.Current.Resources["SystemAccentColorLight3"] = _colors[3]; + Application.Current.Resources["SystemAccentColorLight1"] = _colors[0]; + Application.Current.Resources["SystemAccentColorLight2"] = _colors[1]; + Application.Current.Resources["SystemAccentColorLight3"] = _colors[0]; Application.Current.Resources["AccentColor"] = new SolidColorBrush(_colors[0]); - - return _colors; } + + private static List _generatedColors = new List(); private static async Task GetPaletteList(Bitmap bitmapinput, int ColorCount, bool IsLight, int quality) { byte DefVal = (byte)(IsLight ? 80 : 255); - Windows.UI.Color[] output = new Windows.UI.Color[4]; try { - List ThemedColors = await Task.Run(() => ColorThief.GetPalette(bitmapinput, ColorCount, IsLight ? 1 : quality).Where(x => IsLight ? x.IsDark : !x.IsDark).ToList()); + LumaUtils.DarkThreshold = IsLight ? 200f : 400f; + LumaUtils.IgnoreWhiteThreshold = IsLight ? 900f : 800f; + if (!IsLight) + LumaUtils.ChangeCoeToBT709(); + else + LumaUtils.ChangeCoeToBT601(); - if (ThemedColors.Count == 0 || ThemedColors.Count < output.Length) throw new Exception($"The image doesn't have {output.Length} matched colors to assign. Fallback to default!"); - for (int i = 0, j = output.Length - 1; i < output.Length; i++, j--) + return await Task.Run(() => { - output[i] = DrawingColorToColor(ThemedColors[i]); - } + _generatedColors.Clear(); + + while (true) + { + try + { + IEnumerable averageColors = ColorThief.GetPalette(bitmapinput, ColorCount, quality, !IsLight) + .Where(x => IsLight ? x.IsDark : !x.IsDark) + .OrderBy(x => x.Population); + + QuantizedColor dominatedColor = new QuantizedColor( + Color.FromArgb( + 255, + (byte)averageColors.Average(a => a.Color.R), + (byte)averageColors.Average(a => a.Color.G), + (byte)averageColors.Average(a => a.Color.B) + ), (int)averageColors.Average(a => a.Population)); + + _generatedColors.Add(dominatedColor); + _generatedColors.AddRange(averageColors); + + break; + } + catch (InvalidOperationException) + { + if (ColorCount > 100) throw; + LogWriteLine($"Regenerating colors by adding 20 more colors to generate: {ColorCount} to {ColorCount + 20}", LogType.Warning, true); + ColorCount += 20; + } + } + + return EnsureLengthCopyLast(_generatedColors + .Select(DrawingColorToColor) + .ToArray(), 2); + }).ConfigureAwait(false); } catch (Exception ex) { LogWriteLine($"{ex}", LogType.Warning, true); - Windows.UI.Color defColor = DrawingColorToColor(new QuantizedColor(Color.FromArgb(255, DefVal, DefVal, DefVal), 1)); - return new Windows.UI.Color[] { defColor, defColor, defColor, defColor }; } - return output; + Windows.UI.Color defColor = DrawingColorToColor(new QuantizedColor(Color.FromArgb(255, DefVal, DefVal, DefVal), 1)); + return new Windows.UI.Color[] { defColor, defColor, defColor, defColor }; + } + + private static T[] EnsureLengthCopyLast(T[] array, int toLength) + { + if (array.Length == 0) throw new IndexOutOfRangeException("Array has no content in it"); + if (array.Length >= toLength) return array; + + T lastArray = array[array.Length - 1]; + T[] newArray = new T[toLength]; + Array.Copy(array, newArray, array.Length); + + for (int i = array.Length; i < newArray.Length; i++) + { + newArray[i] = lastArray; + } + + return newArray; } private static Windows.UI.Color DrawingColorToColor(QuantizedColor i) => new Windows.UI.Color { R = i.Color.R, G = i.Color.G, B = i.Color.B, A = i.Color.A }; @@ -316,25 +186,21 @@ public async ValueTask GetCachedSprites(string URL, CancellationToken to FileInfo cachedFileInfo = new FileInfo(cachedFilePath); - bool isCachedFileExist = cachedFileInfo.Exists && cachedFileInfo.Length > 4 << 15; - FileStream cachedFileStream = isCachedFileExist ? cachedFileInfo.OpenRead() : cachedFileInfo.Create(); - - try + bool isCachedFileExist = cachedFileInfo.Exists && cachedFileInfo.Length > 1 << 15; + using (stream) + using (FileStream cachedFileStream = isCachedFileExist ? cachedFileInfo.OpenRead() : cachedFileInfo.Create()) { - if (!isCachedFileExist) + try { - await GetResizedImageStream(stream, cachedFileStream, ToWidth, ToHeight); - } + if (!isCachedFileExist) + { + await GetResizedImageStream(stream, cachedFileStream, ToWidth, ToHeight); + } - bitmapRet = await Task.Run(() => Stream2Bitmap(cachedFileStream.AsRandomAccessStream())); - bitmapImageRet = await Stream2BitmapImage(cachedFileStream.AsRandomAccessStream()); - } - catch { throw; } - finally - { - stream?.Dispose(); - cachedFileStream?.Dispose(); - GC.Collect(); + bitmapRet = await Task.Run(() => Stream2Bitmap(cachedFileStream.AsRandomAccessStream())); + bitmapImageRet = await Stream2BitmapImage(cachedFileStream.AsRandomAccessStream()); + } + catch { throw; } } return (bitmapRet, bitmapImageRet); @@ -421,27 +287,6 @@ private static (uint, uint) GetPreservedImageRatio(uint canvasWidth, uint canvas return ((uint)(imgWidth * ratio), (uint)(imgHeight * ratio)); } - private async ValueTask DownloadBackgroundImage(CancellationToken Token) - { - regionBackgroundProp.imgLocalPath = Path.Combine(AppGameImgFolder, "bg", Path.GetFileName(regionBackgroundProp.data.adv.background)); - SetAndSaveConfigValue("CurrentBackground", regionBackgroundProp.imgLocalPath); - - if (!Directory.Exists(Path.Combine(AppGameImgFolder, "bg"))) - Directory.CreateDirectory(Path.Combine(AppGameImgFolder, "bg")); - - FileInfo fI = new FileInfo(regionBackgroundProp.imgLocalPath); - - if (fI.Exists) return; - - using (Stream netStream = (await _httpClient.DownloadFromSessionStreamAsync(regionBackgroundProp.data.adv.background, 0, null, Token)).Item1) - { - using (Stream outStream = fI.Create()) - { - netStream.CopyTo(outStream); - } - } - } - private async void ApplyBackgroundAsync() => await ApplyBackground(); private async Task ApplyBackground() @@ -455,15 +300,10 @@ private async Task ApplyBackground() (PaletteBitmap, BackgroundBitmap) = await GetResizedBitmap(stream, Width, Height); - await ApplyAccentColor(this, PaletteBitmap, 7); + ApplyAccentColor(this, PaletteBitmap); FadeOutFrontBg(); FadeOutBackBg(); - - GC.Collect(); - GC.WaitForPendingFinalizers(); - GC.WaitForFullGCComplete(); - GC.Collect(); } private async void FadeOutFrontBg() diff --git a/CollapseLauncher/Classes/CachesManagement/Honkai/Fetch.cs b/CollapseLauncher/Classes/CachesManagement/Honkai/Fetch.cs index 0024fa30d..752acfec2 100644 --- a/CollapseLauncher/Classes/CachesManagement/Honkai/Fetch.cs +++ b/CollapseLauncher/Classes/CachesManagement/Honkai/Fetch.cs @@ -1,4 +1,4 @@ -using CollapseLauncher.Interfaces; +using CollapseLauncher.Interfaces; using Hi3Helper; using Hi3Helper.EncTool; using Hi3Helper.EncTool.Parser.KianaDispatch; @@ -82,23 +82,23 @@ private async Task BuildGameRepoURL(CancellationToken token) KianaDispatch dispatch = null; Exception lastException = null; - foreach (string baseURL in _gamePreset.GameDispatchArrayURL) + foreach (string baseURL in _gameVersionManager.GamePreset.GameDispatchArrayURL) { try { // Init the key and decrypt it if exist. string key = null; - if (_gamePreset.DispatcherKey != null) + if (_gameVersionManager.GamePreset.DispatcherKey != null) { mhyEncTool Decryptor = new mhyEncTool(); Decryptor.InitMasterKey(ConfigV2.MasterKey, ConfigV2.MasterKeyBitLength, RSAEncryptionPadding.Pkcs1); - key = _gamePreset.DispatcherKey; + key = _gameVersionManager.GamePreset.DispatcherKey; Decryptor.DecryptStringWithMasterKey(ref key); } // Try assign dispatcher - dispatch = await KianaDispatch.GetDispatch(baseURL, _gamePreset.GameDispatchURLTemplate, _gamePreset.GameDispatchChannelName, key, _gameVersion.VersionArray, token); + dispatch = await KianaDispatch.GetDispatch(baseURL, _gameVersionManager.GamePreset.GameDispatchURLTemplate, _gameVersionManager.GamePreset.GameDispatchChannelName, key, _gameVersion.VersionArray, token); lastException = null; break; } @@ -112,7 +112,7 @@ private async Task BuildGameRepoURL(CancellationToken token) if (lastException != null) throw lastException; // Get gatewayURl and fetch the gateway - _gameGateway = await KianaDispatch.GetGameserver(dispatch, _gamePreset.GameGatewayDefault, token); + _gameGateway = await KianaDispatch.GetGameserver(dispatch, _gameVersionManager.GamePreset.GameGatewayDefault, token); _gameRepoURL = BuildAssetBundleURL(_gameGateway); } @@ -213,7 +213,7 @@ private void BuildDataPatchConfig(MemoryStream stream, List assetInd try { // Deserialize the line and set the type - CacheAsset content = (CacheAsset)JsonSerializer.Deserialize(line, typeof(CacheAsset), CacheAssetContext.Default); + CacheAsset content = (CacheAsset)JsonSerializer.Deserialize(line, typeof(CacheAsset), InternalAppJSONContext.Default); content.DataType = type; // Check if the asset is regional and contains only selected language. diff --git a/CollapseLauncher/Classes/CachesManagement/Honkai/HonkaiCache.cs b/CollapseLauncher/Classes/CachesManagement/Honkai/HonkaiCache.cs index 621135aa7..8f4b131c7 100644 --- a/CollapseLauncher/Classes/CachesManagement/Honkai/HonkaiCache.cs +++ b/CollapseLauncher/Classes/CachesManagement/Honkai/HonkaiCache.cs @@ -2,6 +2,7 @@ using CollapseLauncher.Statics; using Hi3Helper.Data; using Hi3Helper.EncTool.Parser.KianaDispatch; +using Hi3Helper.Preset; using Microsoft.UI.Xaml; using System; using System.Collections.Generic; @@ -20,14 +21,15 @@ internal partial class HonkaiCache : ProgressBase, I private List _updateAssetIndex { get; set; } #endregion - public HonkaiCache(UIElement parentUI) + public HonkaiCache(UIElement parentUI, IGameVersionCheck GameVersionManager) : base( parentUI, - PageStatics._GameVersion.GameDirAppDataPath, + GameVersionManager, + GameVersionManager.GameDirAppDataPath, null, - PageStatics._GameVersion.GetGameVersionAPI().VersionString) + GameVersionManager.GetGameVersionAPI().VersionString) { - _gameLang = _gamePreset.GetGameLanguage() ?? "en"; + _gameLang = _gameVersionManager.GamePreset.GetGameLanguage() ?? "en"; } ~HonkaiCache() => Dispose(); diff --git a/CollapseLauncher/Classes/CachesManagement/StarRail/Check.cs b/CollapseLauncher/Classes/CachesManagement/StarRail/Check.cs index d44e03051..0eca1c6b5 100644 --- a/CollapseLauncher/Classes/CachesManagement/StarRail/Check.cs +++ b/CollapseLauncher/Classes/CachesManagement/StarRail/Check.cs @@ -29,7 +29,7 @@ private async Task> Check(List assetIndex, CancellationTo RestartStopwatch(); // Get persistent and streaming paths - string execName = Path.GetFileNameWithoutExtension(_gamePreset.GameExecutableName); + string execName = Path.GetFileNameWithoutExtension(_innerGameVersionManager.GamePreset.GameExecutableName); string baseDesignDataPathPersistent = Path.Combine(_gamePath, @$"{execName}_Data\Persistent\DesignData\Windows"); string baseDesignDataPathStreaming = Path.Combine(_gamePath, @$"{execName}_Data\StreamingAssets\DesignData\Windows"); diff --git a/CollapseLauncher/Classes/CachesManagement/StarRail/Fetch.cs b/CollapseLauncher/Classes/CachesManagement/StarRail/Fetch.cs index 46c219cda..4b302433b 100644 --- a/CollapseLauncher/Classes/CachesManagement/StarRail/Fetch.cs +++ b/CollapseLauncher/Classes/CachesManagement/StarRail/Fetch.cs @@ -9,6 +9,7 @@ using static Hi3Helper.Data.ConverterTool; using static Hi3Helper.Locale; using static Hi3Helper.Logger; +using static CollapseLauncher.GameSettings.Base.SettingsBase; namespace CollapseLauncher { @@ -22,7 +23,7 @@ private async Task> Fetch(CancellationToken token) try { // Subscribe the event listener - _gameVersionManager.StarRailMetadataTool.HttpEvent += _httpClient_FetchAssetProgress; + _innerGameVersionManager.StarRailMetadataTool.HttpEvent += _httpClient_FetchAssetProgress; // Initialize metadata // Set total activity string as "Fetching Caches Type: Dispatcher" @@ -30,7 +31,7 @@ private async Task> Fetch(CancellationToken token) _status.IsProgressTotalIndetermined = true; _status.IsIncludePerFileIndicator = false; UpdateStatus(); - await _gameVersionManager.StarRailMetadataTool.Initialize(token, GetExistingGameRegionID(), Path.Combine(_gamePath, $"{Path.GetFileNameWithoutExtension(_gamePreset.GameExecutableName)}_Data\\Persistent")); + await _innerGameVersionManager.StarRailMetadataTool.Initialize(token, GetExistingGameRegionID(), Path.Combine(_gamePath, $"{Path.GetFileNameWithoutExtension(_gameVersionManager.GamePreset.GameExecutableName)}_Data\\Persistent")); // Iterate type and do fetch foreach (SRAssetType type in Enum.GetValues(typeof(SRAssetType))) @@ -62,7 +63,7 @@ private async Task> Fetch(CancellationToken token) finally { // Unsubscribe the event listener and dispose Http client - _gameVersionManager.StarRailMetadataTool.HttpEvent -= _httpClient_FetchAssetProgress; + _innerGameVersionManager.StarRailMetadataTool.HttpEvent -= _httpClient_FetchAssetProgress; } // Return asset index @@ -84,18 +85,18 @@ private async Task> Fetch(CancellationToken token) switch (type) { case SRAssetType.IFix: - await _gameVersionManager.StarRailMetadataTool.ReadIFixMetadataInformation(token); - assetProperty = _gameVersionManager.StarRailMetadataTool.MetadataIFix.GetAssets(); + await _innerGameVersionManager.StarRailMetadataTool.ReadIFixMetadataInformation(token); + assetProperty = _innerGameVersionManager.StarRailMetadataTool.MetadataIFix.GetAssets(); assetIndex.AddRange(assetProperty.AssetList); return (assetProperty.AssetList.Count, assetProperty.AssetTotalSize); case SRAssetType.DesignData: - await _gameVersionManager.StarRailMetadataTool.ReadDesignMetadataInformation(token); - assetProperty = _gameVersionManager.StarRailMetadataTool.MetadataDesign.GetAssets(); + await _innerGameVersionManager.StarRailMetadataTool.ReadDesignMetadataInformation(token); + assetProperty = _innerGameVersionManager.StarRailMetadataTool.MetadataDesign.GetAssets(); assetIndex.AddRange(assetProperty.AssetList); return (assetProperty.AssetList.Count, assetProperty.AssetTotalSize); case SRAssetType.Lua: - await _gameVersionManager.StarRailMetadataTool.ReadLuaMetadataInformation(token); - assetProperty = _gameVersionManager.StarRailMetadataTool.MetadataLua.GetAssets(); + await _innerGameVersionManager.StarRailMetadataTool.ReadLuaMetadataInformation(token); + assetProperty = _innerGameVersionManager.StarRailMetadataTool.MetadataLua.GetAssets(); assetIndex.AddRange(assetProperty.AssetList); return (assetProperty.AssetList.Count, assetProperty.AssetTotalSize); } @@ -112,10 +113,10 @@ private async Task> Fetch(CancellationToken token) private unsafe string GetExistingGameRegionID() { #nullable enable - object? value = GameSettings.Statics.RegistryRoot?.GetValue("App_LastServerName_h2577443795", null); + object? value = RegistryRoot?.GetValue("App_LastServerName_h2577443795", null); if (value == null) { - return _gamePreset.GameDispatchDefaultName ?? throw new KeyNotFoundException("Default dispatcher name in metadata is not exist!"); + return _gameVersionManager.GamePreset.GameDispatchDefaultName ?? throw new KeyNotFoundException("Default dispatcher name in metadata is not exist!"); } #nullable disable diff --git a/CollapseLauncher/Classes/CachesManagement/StarRail/StarRailCache.cs b/CollapseLauncher/Classes/CachesManagement/StarRail/StarRailCache.cs index 996580544..b7ead92fe 100644 --- a/CollapseLauncher/Classes/CachesManagement/StarRail/StarRailCache.cs +++ b/CollapseLauncher/Classes/CachesManagement/StarRail/StarRailCache.cs @@ -1,6 +1,5 @@ using CollapseLauncher.GameVersioning; using CollapseLauncher.Interfaces; -using CollapseLauncher.Statics; using Hi3Helper.Data; using Hi3Helper.EncTool.Parser.AssetMetadata.SRMetadataAsset; using Microsoft.UI.Xaml; @@ -14,18 +13,20 @@ namespace CollapseLauncher internal partial class StarRailCache : ProgressBase, ICache { #region Properties + private GameTypeStarRailVersion _innerGameVersionManager { get; set; } private string _cacheRegionalCheckName = "sprite"; private List _updateAssetIndex { get; set; } - private GameTypeStarRailVersion _gameVersionManager { get => PageStatics._GameVersion as GameTypeStarRailVersion; } #endregion - public StarRailCache(UIElement parentUI) + public StarRailCache(UIElement parentUI, IGameVersionCheck GameVersionManager) : base( parentUI, - PageStatics._GameVersion.GameDirPath, + GameVersionManager, + GameVersionManager.GameDirPath, null, - PageStatics._GameVersion.GetGameVersionAPI().VersionString) + GameVersionManager.GetGameVersionAPI().VersionString) { + _innerGameVersionManager = GameVersionManager as GameTypeStarRailVersion; } ~StarRailCache() => Dispose(); diff --git a/CollapseLauncher/Classes/ClassesContext.cs b/CollapseLauncher/Classes/ClassesContext.cs index 51fe31a5a..640b79fd8 100644 --- a/CollapseLauncher/Classes/ClassesContext.cs +++ b/CollapseLauncher/Classes/ClassesContext.cs @@ -5,18 +5,9 @@ namespace CollapseLauncher { [JsonSourceGenerationOptions(IncludeFields = false, GenerationMode = JsonSourceGenerationMode.Metadata, IgnoreReadOnlyFields = true)] + [JsonSerializable(typeof(CommunityToolsProperty))] [JsonSerializable(typeof(AppUpdateVersionProp))] - internal sealed partial class AppUpdateVersionPropContext : JsonSerializerContext { } - - [JsonSourceGenerationOptions(IncludeFields = false, GenerationMode = JsonSourceGenerationMode.Metadata, IgnoreReadOnlyFields = true)] [JsonSerializable(typeof(NotificationPush))] - internal sealed partial class NotificationPushContext : JsonSerializerContext { } - - [JsonSourceGenerationOptions(IncludeFields = false, GenerationMode = JsonSourceGenerationMode.Metadata, IgnoreReadOnlyFields = true)] [JsonSerializable(typeof(CacheAsset))] - internal sealed partial class CacheAssetContext : JsonSerializerContext { } - - [JsonSourceGenerationOptions(IncludeFields = false, GenerationMode = JsonSourceGenerationMode.Metadata, IgnoreReadOnlyFields = true)] - [JsonSerializable(typeof(CommunityToolsProperty))] - internal sealed partial class CommunityToolsPropertyContext : JsonSerializerContext { } + internal sealed partial class InternalAppJSONContext : JsonSerializerContext { } } diff --git a/CollapseLauncher/Classes/EventsManagement/BackgroundActivityManager.cs b/CollapseLauncher/Classes/EventsManagement/BackgroundActivityManager.cs new file mode 100644 index 000000000..19a289bb7 --- /dev/null +++ b/CollapseLauncher/Classes/EventsManagement/BackgroundActivityManager.cs @@ -0,0 +1,290 @@ +using CollapseLauncher.Interfaces; +using Hi3Helper; +using Hi3Helper.Data; +using Hi3Helper.Shared.Region; +using Microsoft.UI.Text; +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Media; +using Microsoft.UI.Xaml.Media.Imaging; +using System; +using System.Collections.Generic; +using CollapseLauncher.Statics; +using Hi3Helper.Preset; +using static Hi3Helper.Locale; + +namespace CollapseLauncher +{ + internal class BackgroundActivityManager + { + private static ThemeShadow _infoBarShadow = new ThemeShadow(); + + public static Dictionary BackgroundActivities = new Dictionary(); + + private static GamePresetProperty CurrentGameProperty; + + public static void Attach(int hashID, IBackgroundActivity activity, string activityTitle, string activitySubtitle) + { + if (!BackgroundActivities.ContainsKey(hashID)) + { + AttachEventToNotification(hashID, activity, activityTitle, activitySubtitle); + BackgroundActivities.Add(hashID, activity); +#if DEBUG + Logger.LogWriteLine($"Background activity with ID: {hashID} has been attached", LogType.Debug, true); +#endif + return; + } + } + + public static void Detach(int hashID) + { + if (BackgroundActivities.ContainsKey(hashID)) + { + BackgroundActivities.Remove(hashID); + DetachEventFromNotification(hashID); +#if DEBUG + Logger.LogWriteLine($"Background activity with ID: {hashID} has been detached", LogType.Debug, true); +#endif + return; + } + +#if DEBUG + Logger.LogWriteLine($"Cannot detach background activity with ID: {hashID} because it doesn't attached", LogType.Debug, true); +#endif + } + + private static void AttachEventToNotification(int hashID, IBackgroundActivity activity, string activityTitle, string activitySubtitle) + { + Thickness containerNotClosableMargin = new Thickness(-28, -8, 24, 20); + Thickness containerClosableMargin = new Thickness(-28, -8, -28, 20); + + InfoBar _parentNotifUI = new InfoBar() + { + Tag = hashID, + Severity = InfoBarSeverity.Informational, + Background = (Brush)Application.Current.Resources["InfoBarAnnouncementBrush"], + IsOpen = true, + IsClosable = false, + Margin = new Thickness(4, 4, 4, 0), + CornerRadius = new CornerRadius(8), + Shadow = _infoBarShadow, + Title = activityTitle, + Message = activitySubtitle + }; + _parentNotifUI.Translation += LauncherConfig.Shadow32; + + StackPanel _parentContainer = new StackPanel() { Margin = _parentNotifUI.IsClosable ? containerClosableMargin : containerNotClosableMargin }; + _parentNotifUI.Content = _parentContainer; + Grid _parentGrid = new Grid() + { + ColumnDefinitions = { + new ColumnDefinition() { Width = new GridLength(72) }, + new ColumnDefinition() + } + }; + _parentContainer.Children.Add(_parentGrid); + + StackPanel progressLogoContainer = new StackPanel() + { + CornerRadius = new CornerRadius(8), + Width = 64, + Height = 64, + Margin = new Thickness(0, 4, 8, 4) + }; + _parentGrid.Children.Add(progressLogoContainer); + Grid.SetColumn(progressLogoContainer, 0); + + CurrentGameProperty = GamePropertyVault.GetCurrentGameProperty(); + switch (CurrentGameProperty._GameVersion.GameType) + { + case GameType.Honkai: + Image progressLogoHonkai = new Image() + { + Source = new BitmapImage(new Uri("ms-appx:///XAMLs/Prototype/honkai-logo.png")), + Width = 64, + Height = 64 + }; + progressLogoContainer.Children.Add(progressLogoHonkai); + break; + case GameType.Genshin: + Image progressLogoGenshin = new Image() + { + Source = new BitmapImage(new Uri("ms-appx:///XAMLs/Prototype/genshin-logo.png")), + Width = 64, + Height = 64 + }; + progressLogoContainer.Children.Add(progressLogoGenshin); + break; + case GameType.StarRail: + Image progressLogoStarRail = new Image() + { + Source = new BitmapImage(new Uri("ms-appx:///XAMLs/Prototype/starrail-logo.png")), + Width = 64, + Height = 64 + }; + progressLogoContainer.Children.Add(progressLogoStarRail); + break; + case GameType.Zenless: + Image progressLogoZenless = new Image() + { + Source = new BitmapImage(new Uri("ms-appx:///XAMLs/Prototype/zenless-logo.png")), + Width = 64, + Height = 64 + }; + progressLogoContainer.Children.Add(progressLogoZenless); + break; + case GameType.Unknown: + Image progressLogoUnknown = new Image() + { + Source = new BitmapImage(new Uri("ms-appx:///XAMLs/Prototype/honkai-logo.png")), + Width = 64, + Height = 64 + }; + progressLogoContainer.Children.Add(progressLogoUnknown); + break; + } + + StackPanel progressStatusContainer = new StackPanel() + { + Margin = new Thickness(8, -4, 0, 0), + VerticalAlignment = VerticalAlignment.Center + }; + _parentGrid.Children.Add(progressStatusContainer); + Grid.SetColumn(progressStatusContainer, 1); + + Grid progressStatusGrid = new Grid() + { + Margin = new Thickness(0, 0, 0, 16), + ColumnDefinitions = + { + new ColumnDefinition(), + new ColumnDefinition() + }, + RowDefinitions = + { + new RowDefinition(), + new RowDefinition() + } + }; + progressStatusContainer.Children.Add(progressStatusGrid); + + TextBlock progressLeftTitle = new TextBlock() + { + Style = Application.Current.Resources["BodyStrongTextBlockStyle"] as Style, + Text = "Downloading Package: 1 / 3" + }; + TextBlock progressLeftSubtitle = new TextBlock() + { + Style = Application.Current.Resources["CaptionTextBlockStyle"] as Style, + Text = "Speed: 69.42 MB/s" + }; + + TextBlock progressRightTitle = new TextBlock() + { + Style = Application.Current.Resources["BodyStrongTextBlockStyle"] as Style, + Text = "Estimated Time: 0h 32m left", + HorizontalAlignment = HorizontalAlignment.Right + }; + TextBlock progressRightSubtitle = new TextBlock() + { + Style = Application.Current.Resources["CaptionTextBlockStyle"] as Style, + Text = "Progress: 69.42%", + HorizontalAlignment = HorizontalAlignment.Right + }; + progressStatusGrid.Children.Add(progressLeftTitle); + progressStatusGrid.Children.Add(progressLeftSubtitle); + progressStatusGrid.Children.Add(progressRightTitle); + progressStatusGrid.Children.Add(progressRightSubtitle); + Grid.SetColumn(progressLeftTitle, 0); Grid.SetRow(progressLeftTitle, 0); + Grid.SetColumn(progressLeftSubtitle, 0); Grid.SetRow(progressLeftSubtitle, 1); + Grid.SetColumn(progressRightTitle, 1); Grid.SetRow(progressRightTitle, 0); + Grid.SetColumn(progressRightSubtitle, 1); Grid.SetRow(progressRightSubtitle, 1); + + ProgressBar progressBar = new ProgressBar() { Minimum = 0, Maximum = 100, Value = 69.42 }; + progressStatusContainer.Children.Add(progressBar); + + Button cancelButton = new Button() + { + HorizontalAlignment = HorizontalAlignment.Right, + Margin = new Thickness(0, 4, 0, 0), + CornerRadius = new CornerRadius(14), + Style = Application.Current.Resources["AccentButtonStyle"] as Style, + Content = new StackPanel() + { + Orientation = Orientation.Horizontal, + Margin = new Thickness(4, 0, 4, 0), + Children = + { + new FontIcon() + { + FontFamily = Application.Current.Resources["FontAwesomeSolid"] as FontFamily, + Glyph = "", + FontSize = 18 + }, + new TextBlock() + { + Text = Lang._HomePage.PauseCancelDownloadBtn, + FontWeight = FontWeights.Medium, + Margin = new Thickness(8, -2, 0, 0), + VerticalAlignment = VerticalAlignment.Center + } + } + } + }; + + cancelButton.Click += (_, args) => + { + cancelButton.IsEnabled = false; + activity.CancelRoutine(); + _parentNotifUI.IsOpen = false; + }; + + activity.ProgressChanged += (_, args) => activity.Dispatch(() => + { + progressBar.Value = args.ProgressTotalPercentage; + progressLeftSubtitle.Text = string.Format(Lang._Misc.Speed, ConverterTool.SummarizeSizeSimple(args.ProgressTotalSpeed)); + progressRightTitle.Text = string.Format(Lang._Misc.TimeRemainHMSFormat, args.ProgressTotalTimeLeft); + progressRightSubtitle.Text = string.Format(Lang._UpdatePage.UpdateHeader1 + " {0}%", args.ProgressTotalPercentage); + }); + + activity.StatusChanged += (_, args) => activity.Dispatch(() => + { + progressLeftTitle.Text = args.ActivityStatus; + if (args.IsCanceled) + { + cancelButton.IsEnabled = false; + cancelButton.Visibility = Visibility.Collapsed; + _parentNotifUI.Severity = InfoBarSeverity.Error; + _parentNotifUI.Title = "[Error] " + activityTitle; + _parentNotifUI.IsClosable = true; + _parentContainer.Margin = containerClosableMargin; + } + if (args.IsCompleted) + { + cancelButton.IsEnabled = false; + cancelButton.Visibility = Visibility.Collapsed; + _parentNotifUI.Severity = InfoBarSeverity.Success; + _parentNotifUI.Title = "[Completed] " + activityTitle; + _parentNotifUI.IsClosable = true; + _parentContainer.Margin = containerClosableMargin; + } + if (args.IsRunning) + { + cancelButton.IsEnabled = true; + cancelButton.Visibility = Visibility.Visible; + _parentNotifUI.Severity = InfoBarSeverity.Informational; + _parentNotifUI.Title = activityTitle; + _parentNotifUI.IsClosable = false; + _parentContainer.Margin = containerNotClosableMargin; + } + }); + + _parentNotifUI.Closing += (_, _) => Detach(hashID); + _parentContainer.Children.Add(cancelButton); + + NotificationSender.SendCustomNotification(hashID, _parentNotifUI); + } + + private static void DetachEventFromNotification(int hashID) => NotificationSender.RemoveCustomNotification(hashID); + } +} diff --git a/CollapseLauncher/Classes/EventsManagement/EventsHandler.cs b/CollapseLauncher/Classes/EventsManagement/EventsHandler.cs index c60854b6c..4fd910be5 100644 --- a/CollapseLauncher/Classes/EventsManagement/EventsHandler.cs +++ b/CollapseLauncher/Classes/EventsManagement/EventsHandler.cs @@ -73,7 +73,7 @@ private static async ValueTask GetUpdateMetadata() await FallbackCDNUtil.DownloadCDNFallbackContent(client, ms, relativePath, default); ms.Position = 0; - return (AppUpdateVersionProp)JsonSerializer.Deserialize(ms, typeof(AppUpdateVersionProp), AppUpdateVersionPropContext.Default); + return (AppUpdateVersionProp)JsonSerializer.Deserialize(ms, typeof(AppUpdateVersionProp), InternalAppJSONContext.Default); } } @@ -235,6 +235,25 @@ internal static class NotificationSender { static NotificationInvoker invoker = new NotificationInvoker(); public static void SendNotification(NotificationInvokerProp e) => invoker.SendNotification(e); + public static void SendCustomNotification(int tagID, InfoBar infoBarUI) => invoker.SendNotification(new NotificationInvokerProp + { + IsCustomNotif = true, + CustomNotifAction = NotificationCustomAction.Add, + Notification = new NotificationProp + { + MsgId = tagID, + }, + OtherContent = infoBarUI + }); + public static void RemoveCustomNotification(int tagID) => invoker.SendNotification(new NotificationInvokerProp + { + IsCustomNotif = true, + CustomNotifAction = NotificationCustomAction.Remove, + Notification = new NotificationProp + { + MsgId = tagID, + } + }); } internal class NotificationInvoker @@ -243,12 +262,16 @@ internal class NotificationInvoker public void SendNotification(NotificationInvokerProp e) => EventInvoker?.Invoke(this, e); } + public enum NotificationCustomAction { Add, Remove } public class NotificationInvokerProp { public TypedEventHandler CloseAction { get; set; } = null; public UIElement OtherContent { get; set; } = null; public NotificationProp Notification { get; set; } public bool IsAppNotif { get; set; } = true; + public bool IsCustomNotif { get; set; } = false; + public NotificationCustomAction CustomNotifAction { get; set; } + } #endregion #region BackgroundRegion @@ -257,14 +280,17 @@ internal static class BackgroundImgChanger static BackgroundImgChangerInvoker invoker = new BackgroundImgChangerInvoker(); public static async Task WaitForBackgroundToLoad() => await invoker.WaitForBackgroundToLoad(); public static void ChangeBackground(string ImgPath, bool IsCustom = true) => invoker.ChangeBackground(ImgPath, IsCustom); + public static void ToggleBackground(bool Hide) => invoker.ToggleBackground(Hide); } internal class BackgroundImgChangerInvoker { public static event EventHandler ImgEvent; + public static event EventHandler IsImageHide; BackgroundImgProperty property; public async Task WaitForBackgroundToLoad() => await Task.Run(() => { while (!property.IsImageLoaded) { } }); public void ChangeBackground(string ImgPath, bool IsCustom) => ImgEvent?.Invoke(this, property = new BackgroundImgProperty(ImgPath, IsCustom)); + public void ToggleBackground(bool Hide) => IsImageHide?.Invoke(this, Hide); } internal class BackgroundImgProperty diff --git a/CollapseLauncher/Classes/GameManagement/GameSettings/BaseClass/ImportExportBase.cs b/CollapseLauncher/Classes/GameManagement/GameSettings/BaseClass/ImportExportBase.cs index 4fd03252e..66a195516 100644 --- a/CollapseLauncher/Classes/GameManagement/GameSettings/BaseClass/ImportExportBase.cs +++ b/CollapseLauncher/Classes/GameManagement/GameSettings/BaseClass/ImportExportBase.cs @@ -7,8 +7,8 @@ using System.IO; using System.IO.Compression; using System.Text; -using static CollapseLauncher.GameSettings.Statics; using static Hi3Helper.Locale; +using static CollapseLauncher.GameSettings.Base.SettingsBase; namespace CollapseLauncher.GameSettings.Base { diff --git a/CollapseLauncher/Classes/GameManagement/GameSettings/BaseClass/SettingsBase.cs b/CollapseLauncher/Classes/GameManagement/GameSettings/BaseClass/SettingsBase.cs new file mode 100644 index 000000000..faa5da052 --- /dev/null +++ b/CollapseLauncher/Classes/GameManagement/GameSettings/BaseClass/SettingsBase.cs @@ -0,0 +1,19 @@ +using CollapseLauncher.Interfaces; +using Microsoft.Win32; + +namespace CollapseLauncher.GameSettings.Base +{ + internal class SettingsBase : ImportExportBase + { +#nullable enable + internal static string? RegistryPath; + internal static RegistryKey? RegistryRoot; + + public SettingsBase(IGameVersionCheck GameVersionManager) + { + _gameVersionManager = GameVersionManager; + } +#nullable disable + protected static IGameVersionCheck _gameVersionManager { get; set; } + } +} diff --git a/CollapseLauncher/Classes/GameManagement/GameSettings/BaseClass/TypeExtensions.cs b/CollapseLauncher/Classes/GameManagement/GameSettings/BaseClass/TypeExtensions.cs new file mode 100644 index 000000000..aa4934044 --- /dev/null +++ b/CollapseLauncher/Classes/GameManagement/GameSettings/BaseClass/TypeExtensions.cs @@ -0,0 +1,42 @@ +using System; +using System.Reflection; + +namespace CollapseLauncher +{ + public static class TypeExtensions + { + public static bool IsInstancePropertyEqual(T self, T to) where T : class + { + // Check if the one of the value is null, if true check the other value if it's null + if (self == null) + { + if (to != null) return false; + else return true; + } + if (to == null) + { + if (self != null) return false; + else return true; + } + + // Get the type of the instance + Type type = typeof(T); + // Enumerate the PropertyInfo out of instance + foreach (PropertyInfo pi in type.GetProperties(BindingFlags.Public | BindingFlags.Instance)) + { + // Get the property name and value from both self and to + object selfValue = type.GetProperty(pi.Name).GetValue(self, null); + object toValue = type.GetProperty(pi.Name).GetValue(to, null); + + // If the value on both self and to is different, then return false (not equal) + if (selfValue != toValue && (selfValue == null || !selfValue.Equals(toValue))) + { + return false; + } + } + + // If all passes, then return true (equal) + return true; + } + } +} diff --git a/CollapseLauncher/Classes/GameManagement/GameSettings/Genshin/Context.cs b/CollapseLauncher/Classes/GameManagement/GameSettings/Genshin/Context.cs index 8bf35b30e..76d74071b 100644 --- a/CollapseLauncher/Classes/GameManagement/GameSettings/Genshin/Context.cs +++ b/CollapseLauncher/Classes/GameManagement/GameSettings/Genshin/Context.cs @@ -1,17 +1,10 @@ -using CollapseLauncher.GameSettings.Genshin; -using System.Text.Json.Serialization; +using System.Text.Json.Serialization; namespace CollapseLauncher.GameSettings.Genshin.Context { [JsonSourceGenerationOptions(IncludeFields = false, GenerationMode = JsonSourceGenerationMode.Metadata, IgnoreReadOnlyFields = true)] [JsonSerializable(typeof(GeneralData))] - internal sealed partial class GeneralDataContext : JsonSerializerContext { } - - [JsonSourceGenerationOptions(IncludeFields = false, GenerationMode = JsonSourceGenerationMode.Metadata, IgnoreReadOnlyFields = true)] [JsonSerializable(typeof(GraphicsData))] - internal sealed partial class GraphicsDataContext : JsonSerializerContext { } - - [JsonSourceGenerationOptions(IncludeFields = false, GenerationMode = JsonSourceGenerationMode.Metadata, IgnoreReadOnlyFields = true)] [JsonSerializable(typeof(GlobalPerfData))] - internal sealed partial class GlobalPerfDataContext : JsonSerializerContext { } + internal sealed partial class GenshinSettingsJSONContext : JsonSerializerContext { } } diff --git a/CollapseLauncher/Classes/GameManagement/GameSettings/Genshin/RegistryClass/GeneralData.cs b/CollapseLauncher/Classes/GameManagement/GameSettings/Genshin/RegistryClass/GeneralData.cs index 0b535cf92..eba4045f7 100644 --- a/CollapseLauncher/Classes/GameManagement/GameSettings/Genshin/RegistryClass/GeneralData.cs +++ b/CollapseLauncher/Classes/GameManagement/GameSettings/Genshin/RegistryClass/GeneralData.cs @@ -1,14 +1,13 @@ -using CollapseLauncher.GameSettings.Genshin; using CollapseLauncher.GameSettings.Genshin.Context; -using CollapseLauncher.Interfaces; using Hi3Helper; using Microsoft.Win32; using System; using System.Collections.Generic; using System.Text; +using System.Text.Encodings.Web; using System.Text.Json; using System.Text.Json.Serialization; -using static CollapseLauncher.GameSettings.Statics; +using static CollapseLauncher.GameSettings.Base.SettingsBase; using static Hi3Helper.Logger; namespace CollapseLauncher.GameSettings.Genshin @@ -24,77 +23,40 @@ internal class GeneralData //Using guide from https://github.com/Myp3a/GenshinConfigurator/wiki/Config-format //Thanks Myp3a! - /// - /// deviceUUID
- /// This is supposed to be empty - ///
- public string deviceUUID { get; set; } = ""; - - /// - /// userLocalDataVersionId
- /// This should be static
- /// Value: 0.0.1 - ///
- public string userLocalDataVersionId { get; set; } = "0.0.1"; + public int mtrAbortTimeOutCount { get; set; } = 3; /// - /// This define "Text Language" in-game settings.
- /// Valid values: 1-13 - /// Default: 1 - /// English(1) - /// Simplified Chinese(2) - /// Traditional Chinese(3) - /// French(4) - /// German(5) - /// Spanish(6) - /// Portugese(7) - /// Russian(8) - /// Japanese(9) - /// Korean(10) - /// Thai(11) - /// Vietnamese(12) - /// Indonesian(13) - /// Turkish(14) - /// Italy(15) + /// Could be for PlayStation multiplayer stuff ///
- public int deviceLanguageType { get; set; } = 1; + public bool onlyPlayWithPSPlayer { get; set; } = false; - /// - /// This define "Voice Language" in-game settings.
- /// Valid values: 0-3 - /// Default: 1 - /// Chinese(0) - /// English(1) - /// Japanese(2) - /// Korean(3) - ///
- public int deviceVoiceLanguageType { get; set; } = 1; + public int urlCheckErrorTraceCount { get; set; } = 30; - /// - /// This define "Server Name" last selected in loading menu.
- ///
- public string selectedServerName { get; set; } = "os_usa"; + public decimal uiPaperWhite { get; set; } = 0.0m; + public decimal scenePaperWhite { get; set; } = 0.0m; - /// - /// I don't know what this do - /// public int localLevelIndex { get; set; } = 0; - public string deviceID { get; set; } = ""; - public string targetUID { get; set; } = ""; - public string curAccountName { get; set; } = ""; + public bool disableRewiredDelayInit { get; set; } = false; + public bool enableAudioChangeAndroidMinimumBufferCapacity { get; set; } = true; /// - /// This define "Resolution" index selected in-game.
- /// Valid value: 0-? - /// Default: 0 + /// This define "Voice Volume" slider in-game.
+ /// Valid values: 0-10 + /// Default: 10 ///
- public string uiSaveData { get; set; } + public int volumeVoice { get; set; } = 10; + + public int mtrTraceCDEachReason { get; set; } = 600; + public bool mtrCached { get; set; } = true; + public List urlCheckBanReasons { get; set; } /// - /// This holds settings for input sens and stuff.
- /// Please look at https://github.com/Myp3a/GenshinConfigurator/wiki/Config-format#input-data-format + /// This define "Server Name" last selected in loading menu.
///
- public string inputData { get; set; } + public string selectedServerName { get; set; } = "os_usa"; + + public int urlCheckTimeInterval { get; set; } = 1000; + public int lastSeenPreDownloadTime { get; set; } = 0; /// /// This holds settings that holds Graphics Settings settings. YEP!
@@ -107,30 +69,35 @@ internal class GeneralData [JsonIgnore] public GraphicsData graphicsData { get; set; } + public bool completionPlayGoPkg { get; set; } = false; + /// - /// This is a dict that keeps track of graphics settings changes.
- /// Save to ignore (?) + /// This defines "Gamma" slider in-game.
+ /// This implementation is quite janky but hear me out
+ /// The value is directly controlled by Gamma Slider, which linked with GammaValue (NumberBox)
+ /// Since the value is flipped, math function of y = -x + 4.4 is used (Refer GenshinGameSettingsPage.Ext.cs Line 122) ///
- // Temporary for fallback before the implementation is made - [JsonIgnore] - public GlobalPerfData globalPerfData { get; set; } - - [JsonPropertyName("globalPerfData")] - public string _globalPerfData { get; set; } + public double gammaValue { get; set; } = 2.2f; - //[JsonIgnore] - //public globalPerfData globalPerfData { get; set; } + public bool mtrIsOpen { get; set; } = true; /// - /// Something about minimap config ? + /// This defines "Vibration Intensity" slider in-game.
+ /// Valid Values: 1-5 + /// Default: 5 ///
- public int miniMapConfig { get; set; } = 1; + public int vibrationIntensity { get; set; } = 5; + + public bool needPlayGoFullPkgPatch { get; set; } = false; + public bool exploreNotification { get; set; } = true; + public int mtrMaxTTL { get; set; } = 32; + public bool urlCheckCached { get; set; } = false; /// - /// This defines "Automatic View Height" in-game settings.
- /// Default: true + /// deviceUUID
+ /// This is supposed to be empty ///
- public bool enableCameraSlope { get; set; } = true; + public string deviceUUID { get; set; } = ""; /// /// This defines "Smart combat camera" whatever that is.
@@ -138,59 +105,65 @@ internal class GeneralData ///
public bool enableCameraCombatLock { get; set; } = true; - /// - /// not sure either what these does. - /// - public bool completionPkg { get; set; } = false; - public bool completionPlayGoPkg { get; set; } = false; + public bool enableEffectAssembleInEditor { get; set; } = true; + public bool resinNotification { get; set; } = true; /// - /// Could be for PlayStation multiplayer stuff + /// This define "Voice Language" in-game settings.
+ /// Valid values: 0-3 + /// Default: 1 + /// Chinese(0) + /// English(1) + /// Japanese(2) + /// Korean(3) ///
- public bool onlyPlayWithPSPlayer { get; set; } = false; + public int deviceVoiceLanguageType { get; set; } = 1; - /// - /// Mysterious~ - /// - public bool needPlayGoFullPkgPatch { get; set; } = false; + public string curAccountName { get; set; } = ""; + public bool _audioSuccessInit { get; set; } = true; + public bool urlCheckAllIP { get; set; } = false; + public bool rewiredDisableKeyboard { get; set; } = false; /// - /// Mobile notification stuff + /// This defines "Audio Output" combo box in-game. + /// Valid Values: 0 (stereo), 1 (surround) + /// Default: 0 /// - public bool resinNotification { get; set; } = true; - public bool exploreNotification { get; set; } = true; + public int audioOutput { get; set; } = 0; - /// - /// This define "Global Volume" slider in-game.
- /// Valid values: 0-10 - /// Default: 10 - ///
- public int volumeGlobal { get; set; } = 10; + public int miniMapConfig { get; set; } = 1; /// - /// This define "SFX Volume" slider in-game.
- /// Valid values: 0-10 - /// Default: 10 + /// This defines "Automatic View Height" in-game settings.
+ /// Default: true ///
- public int volumeSFX { get; set; } = 10; + public bool enableCameraSlope { get; set; } = true; /// - /// This define "Music Volume" slider in-game.
- /// Valid values: 0-10 - /// Default: 10 + /// This define vibration level for certain controller probably ? + /// Valid Values: 0 (Full), 1 (Partial), 2 (Off) + /// Default: 0 ///
- public int volumeMusic { get; set; } = 10; + public int vibrationLevel { get; set; } = 0; - /// - /// This define "Voice Volume" slider in-game.
- /// Valid values: 0-10 - /// Default: 10 - ///
- public int volumeVoice { get; set; } = 10; + public string deviceID { get; set; } = ""; + public string uiSaveData { get; set; } + public bool gyroAiming { get; set; } = false; + public bool motionBlur { get; set; } = true; + public bool completionPkg { get; set; } = false; + public int audioAndroidMiniumBufferCapacity { get; set; } = 2048; /// - /// Probably just leave it alone... + /// This is a dict that keeps track of graphics settings changes.
+ /// Save to ignore (?) ///
+ [JsonIgnore] + public GlobalPerfData globalPerfData { get; set; } + + [JsonPropertyName("globalPerfData")] + public string _globalPerfData { get; set; } + + public int urlCheckTimeOut { get; set; } = 5000; public int audioAPI { get; set; } = -1; /// @@ -200,117 +173,104 @@ internal class GeneralData /// public int audioDynamicRange { get; set; } = 0; - /// - /// This defines "Audio Output" combo box in-game. - /// Valid Values: 0 (stereo), 1 (surround) - /// Default: 0 - /// - public int audioOutput { get; set; } = 0; + public bool firstHDRSetting { get; set; } = true; + public int mtrTraceCount { get; set; } = 5; + public bool disableRewiredInitProtection { get; set; } = false; + public string greyTestDeviceUniqueId { get; set; } = ""; + public bool mtrUseOldWinVersion { get; set; } = false; + public List _serializedCodeSwitches { get; set; } + public int urlCheckAbortTimeOutCount { get; set; } = 3; + public int urlCheckSueecssTraceCount { get; set; } = 5; //yes, that is actually the class name, its not a typo by us... /// - /// Audio related stuff... + /// This define "Music Volume" slider in-game.
+ /// Valid values: 0-10 + /// Default: 10 ///
- public bool _audioSuccessInit { get; set; } = true; - public bool enableAudioChangeAndroidMinimumBufferCapacity { get; set; } = true; - public int audioAndroidMiniumBufferCapacity { get; set; } = 2048; + public int volumeMusic { get; set; } = 10; /// - /// This define vibration level for certain controller probably ? - /// Valid Values: 0 (Full), 1 (Partial), 2 (Off) - /// Default: 0 + /// This holds value for controllers input that has been customized. /// - public int vibrationLevel { get; set; } = 0; + public List _overrideControllerMapKeyList { get; set; } + + public bool urlCheckIsOpen { get; set; } = false; + public int urlCheckCDEachReason { get; set; } = 600; + public List _customDataValueList { get; set; } /// - /// This defines "Vibration Intensity" slider in-game.
- /// Valid Values: 1-5 - /// Default: 5 + /// This define "Text Language" in-game settings.
+ /// Valid values: 1-13 + /// Default: 1 + /// English(1) + /// Simplified Chinese(2) + /// Traditional Chinese(3) + /// French(4) + /// German(5) + /// Spanish(6) + /// Portugese(7) + /// Russian(8) + /// Japanese(9) + /// Korean(10) + /// Thai(11) + /// Vietnamese(12) + /// Indonesian(13) + /// Turkish(14) + /// Italy(15) ///
- public int vibrationIntensity { get; set; } = 5; + public int deviceLanguageType { get; set; } = 1; + + public List _customDataKeyList { get; set; } + public List mtrBanReasons { get; set; } + public int mtrTimeInterval { get; set; } = 1000; /// - /// Some vibration related stuff ? + /// This define "SFX Volume" slider in-game.
+ /// Valid values: 0-10 + /// Default: 10 ///
- public bool usingNewVibrationSetting { get; set; } = true; + public int volumeSFX { get; set; } = 10; + + public int mtrAutoTraceInterval { get; set; } = 3600; + public bool needReportQuestResourceDeleteStatusFiles { get; set; } = false; /// - /// Is not an actual blur setting + /// This holds said override for those controllers. /// - public bool motionBlur { get; set; } = true; + // Temporary for fallback before the implementation is made + public List _overrideControllerMapValueList { get; set; } + + public int mtrTimeOut { get; set; } = 5000; /// - /// Gyro Aiming stuff, most likely not used in PC. + /// This define "Global Volume" slider in-game.
+ /// Valid values: 0-10 + /// Default: 10 ///
- public bool gyroAiming { get; set; } = false; + public int volumeGlobal { get; set; } = 10; - //unsure what these does, probably HDR stuff? doesn't have HDR monitor to test... - public bool firstHDRSetting { get; set; } = true; public decimal maxLuminosity { get; set; } = 0.0m; - public decimal uiPaperWhite { get; set; } = 0.0m; - public decimal scenePaperWhite { get; set; } = 0.0m; /// - /// This defines "Gamma" slider in-game.
- /// This implementation is quite janky but hear me out
- /// The value is directly controlled by Gamma Slider, which linked with GammaValue (NumberBox)
- /// Since the value is flipped, math function of y = -x + 4.4 is used (Refer GenshinGameSettingsPage.Ext.cs Line 122) - ///
- public double gammaValue { get; set; } = 2.2f; - - /// - /// This holds value for controllers input that has been customized. + /// userLocalDataVersionId
+ /// This should be static
+ /// Empty value ///
- public List _overrideControllerMapKeyList { get; set; } + public string userLocalDataVersionId { get; set; } = ""; + public bool forceDisableQuestResourceManagement { get; set; } = false; + public bool rewiredEnableEDS { get; set; } = false; + public bool usingNewVibrationSetting { get; set; } = true; /// - /// This holds said override for those controllers. + /// This holds settings for input sens and stuff.
+ /// Please look at https://github.com/Myp3a/GenshinConfigurator/wiki/Config-format#input-data-format ///
- // Temporary for fallback before the implementation is made - public List _overrideControllerMapValueList { get; set; } - - //[JsonPropertyName("_overrideControllerMapValueList")] - //public List __overrideControllerMapValueList { get; set; } - - //[JsonIgnore] - //public Controllers _overrideControllerMapValueList { get; set; } + public string inputData { get; set; } - //misc values - //just, idk, ignore? - public bool rewiredDisableKeyboard { get; set; } = false; + public string targetUID { get; set; } = ""; public bool rewiredEnableKeyboard { get; set; } = false; - public bool rewiredEnableEDS { get; set; } = false; - public bool disableRewiredDelayInit { get; set; } = false; - public bool disableRewiredInitProtection { get; set; } = false; - public int lastSeenPreDownloadTime { get; set; } = 0; - public bool enableEffectAssembleInEditor { get; set; } = true; - public bool forceDisableQuestResourceManagement { get; set; } = false; - public bool needReportQuestResourceDeleteStatusFiles { get; set; } = false; - public bool mtrCached { get; set; } = true; - public bool mtrIsOpen { get; set; } = true; - public int mtrMaxTTL { get; set; } = 32; - public int mtrTimeOut { get; set; } = 5000; - public int mtrTraceCount { get; set; } = 5; - public int mtrAbortTimeOutCount { get; set; } = 3; - public int mtrAutoTraceInterval { get; set; } = 3600; - public int mtrTraceCDEachReason { get; set; } = 600; - public int mtrTimeInterval { get; set; } = 1000; - public List mtrBanReasons { get; set; } - public List _customDataKeyList { get; set; } - public List _customDataValueList { get; set; } - public List _serializedCodeSwitches { get; set; } - public bool urlCheckCached { get; set; } = false; - public bool urlCheckIsOpen { get; set; } = false; - public bool urlCheckAllIP { get; set; } = false; - public int urlCheckTimeOut { get; set; } = 5000; - public int urlCheckSueecssTraceCount { get; set; } = 5; - public int urlCheckErrorTraceCount { get; set; } = 30; - public int urlCheckAbortTimeOutCount { get; set; } = 3; - public int urlCheckTimeInterval { get; set; } = 1000; - public int urlCheckCDEachReason { get; set; } = 600; - public List urlCheckBanReasons { get; set; } - public bool mtrUseOldWinVersion { get; set; } = false; - public string greyTestDeviceUniqueId { get; set; } = ""; + #endregion #region Methods @@ -331,7 +291,12 @@ public static GeneralData Load() // WARNING: VERY EXPENSIVE CPU TIME WILL BE USED LogWriteLine($"Loaded Genshin Settings: {_ValueName}", LogType.Debug, true); #endif - GeneralData data = (GeneralData?)JsonSerializer.Deserialize(byteStr.Slice(0, byteStr.Length - 1), typeof(GeneralData), GeneralDataContext.Default) ?? new GeneralData(); + JsonSerializerOptions options = new JsonSerializerOptions() + { + TypeInfoResolver = GenshinSettingsJSONContext.Default, + Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping + }; + GeneralData data = (GeneralData?)JsonSerializer.Deserialize(byteStr.Slice(0, byteStr.Length - 1), typeof(GeneralData), options) ?? new GeneralData(); data.graphicsData = GraphicsData.Load(data._graphicsData); data.globalPerfData = new(); return data; @@ -353,8 +318,12 @@ public void Save() _graphicsData = graphicsData.Save(); _globalPerfData = globalPerfData.Create(graphicsData, graphicsData.volatileVersion); - - string data = JsonSerializer.Serialize(this, typeof(GeneralData), GeneralDataContext.Default) + '\0'; + JsonSerializerOptions options = new JsonSerializerOptions() + { + TypeInfoResolver = GenshinSettingsJSONContext.Default, + Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping + }; + string data = JsonSerializer.Serialize(this, typeof(GeneralData), options) + '\0'; byte[] dataByte = Encoding.UTF8.GetBytes(data); RegistryRoot.SetValue(_ValueName, dataByte, RegistryValueKind.Binary); @@ -381,89 +350,7 @@ public void Save() } } - public bool Equals(GeneralData? comparedTo) - { - if (ReferenceEquals(this, comparedTo)) return true; - if (comparedTo == null) return false; - - // nightmare nightmare nightmare nightmare nightmare - return comparedTo.deviceUUID == deviceUUID && - comparedTo.userLocalDataVersionId == userLocalDataVersionId && - comparedTo.deviceLanguageType == deviceLanguageType && - comparedTo.deviceVoiceLanguageType == deviceVoiceLanguageType && - comparedTo.selectedServerName == selectedServerName && - comparedTo.localLevelIndex == localLevelIndex && - comparedTo.deviceID == deviceID && - comparedTo.targetUID == targetUID && - comparedTo.uiSaveData == uiSaveData && - comparedTo.inputData == inputData && - comparedTo.graphicsData == graphicsData && - comparedTo.globalPerfData == globalPerfData && - comparedTo.miniMapConfig == miniMapConfig && - comparedTo.enableCameraSlope == enableCameraSlope && - comparedTo.enableCameraCombatLock == enableCameraCombatLock && - comparedTo.completionPkg == completionPkg && - comparedTo.completionPlayGoPkg == completionPlayGoPkg && - comparedTo.onlyPlayWithPSPlayer == onlyPlayWithPSPlayer && - comparedTo.needPlayGoFullPkgPatch == needPlayGoFullPkgPatch && - comparedTo.resinNotification == resinNotification && - comparedTo.exploreNotification == exploreNotification && - comparedTo.volumeGlobal == volumeGlobal && - comparedTo.volumeSFX == volumeSFX && - comparedTo.volumeVoice == volumeVoice && - comparedTo.audioAPI == audioAPI && - comparedTo.audioDynamicRange == audioDynamicRange && - comparedTo.audioOutput == audioOutput && - comparedTo._audioSuccessInit == _audioSuccessInit && - comparedTo.enableAudioChangeAndroidMinimumBufferCapacity == enableAudioChangeAndroidMinimumBufferCapacity && - comparedTo.audioAndroidMiniumBufferCapacity == audioAndroidMiniumBufferCapacity && - comparedTo.vibrationLevel == vibrationLevel && - comparedTo.vibrationIntensity == vibrationIntensity && - comparedTo.usingNewVibrationSetting == usingNewVibrationSetting && - comparedTo.motionBlur == motionBlur && - comparedTo.gyroAiming == gyroAiming && - comparedTo.firstHDRSetting == firstHDRSetting && - comparedTo.maxLuminosity == maxLuminosity && - comparedTo.uiPaperWhite == uiPaperWhite && - comparedTo.scenePaperWhite == scenePaperWhite && - comparedTo.gammaValue == gammaValue && - comparedTo._overrideControllerMapKeyList == _overrideControllerMapKeyList && - comparedTo._overrideControllerMapValueList == _overrideControllerMapValueList && - comparedTo.rewiredDisableKeyboard == rewiredDisableKeyboard && - comparedTo.rewiredEnableKeyboard == rewiredEnableKeyboard && - comparedTo.rewiredEnableEDS == rewiredEnableEDS && - comparedTo.disableRewiredDelayInit == disableRewiredDelayInit && - comparedTo.disableRewiredInitProtection == disableRewiredInitProtection && - comparedTo.lastSeenPreDownloadTime == lastSeenPreDownloadTime && - comparedTo.enableEffectAssembleInEditor == enableEffectAssembleInEditor && - comparedTo.forceDisableQuestResourceManagement == forceDisableQuestResourceManagement && - comparedTo.needReportQuestResourceDeleteStatusFiles == needReportQuestResourceDeleteStatusFiles && - comparedTo.mtrCached == mtrCached && - comparedTo.mtrIsOpen == mtrIsOpen && - comparedTo.mtrMaxTTL == mtrMaxTTL && - comparedTo.mtrTimeOut == mtrTimeOut && - comparedTo.mtrTraceCount == mtrTraceCount && - comparedTo.mtrAbortTimeOutCount == mtrAbortTimeOutCount && - comparedTo.mtrAutoTraceInterval == mtrAutoTraceInterval && - comparedTo.mtrTraceCDEachReason == mtrTraceCDEachReason && - comparedTo.mtrTimeInterval == mtrTimeInterval && - comparedTo.mtrBanReasons == mtrBanReasons && - comparedTo._customDataKeyList == _customDataKeyList && - comparedTo._customDataValueList == _customDataValueList && - comparedTo._serializedCodeSwitches == _serializedCodeSwitches && - comparedTo.urlCheckCached == urlCheckCached && - comparedTo.urlCheckIsOpen == urlCheckIsOpen && - comparedTo.urlCheckAllIP == urlCheckAllIP && - comparedTo.urlCheckTimeOut == urlCheckTimeOut && - comparedTo.urlCheckSueecssTraceCount == urlCheckSueecssTraceCount && - comparedTo.urlCheckErrorTraceCount == urlCheckErrorTraceCount && - comparedTo.urlCheckAbortTimeOutCount == urlCheckAbortTimeOutCount && - comparedTo.urlCheckTimeInterval == urlCheckTimeInterval && - comparedTo.urlCheckCDEachReason == urlCheckCDEachReason && - comparedTo.urlCheckBanReasons == urlCheckBanReasons && - comparedTo.mtrUseOldWinVersion == mtrUseOldWinVersion && - comparedTo.greyTestDeviceUniqueId == greyTestDeviceUniqueId; - } + public bool Equals(GeneralData? comparedTo) => TypeExtensions.IsInstancePropertyEqual(this, comparedTo); #nullable disable #endregion } diff --git a/CollapseLauncher/Classes/GameManagement/GameSettings/Genshin/RegistryClass/GlobalPerfData.cs b/CollapseLauncher/Classes/GameManagement/GameSettings/Genshin/RegistryClass/GlobalPerfData.cs index 1fb745993..09bcd11ae 100644 --- a/CollapseLauncher/Classes/GameManagement/GameSettings/Genshin/RegistryClass/GlobalPerfData.cs +++ b/CollapseLauncher/Classes/GameManagement/GameSettings/Genshin/RegistryClass/GlobalPerfData.cs @@ -1,8 +1,4 @@ -using CollapseLauncher.GameSettings.Genshin; using CollapseLauncher.GameSettings.Genshin.Context; -using CollapseLauncher.GameSettings.Genshin.Enums; -using Hi3Helper; -using System; using System.Collections.Generic; using System.Text.Json; using static Hi3Helper.Logger; @@ -18,24 +14,41 @@ internal class PerfDataItem #endregion #region Methods - public PerfDataItem(int entryType, int index, string itemVersion) { + public PerfDataItem(int entryType, int index, string itemVersion) + { this.entryType = entryType; this.index = index; this.itemVersion = itemVersion; } #endregion } + + internal class GenshinKeyValuePair + { + #region Properties + public int key { get; set; } + public int value { get; set; } + #endregion + + #region Methods + public GenshinKeyValuePair(int Key, int Value) + { + key = Key; + value = Value; + } + #endregion + } + internal class GlobalPerfData { #region Properties public List saveItems { get; set; } = new(); public bool truePortedFromGraphicData { get; set; } = true; - public string portedVersion { get; set; } = "OSRELWin3.7.0"; + public string portedVersion { get; set; } = "OSRELWin3.8.0"; public bool portedFromGraphicsData { get; set; } = false; #endregion #region Methods - public string Create(GraphicsData graphics, string version) { saveItems = new() @@ -57,9 +70,9 @@ public string Create(GraphicsData graphics, string version) new PerfDataItem (15,(int) graphics.SubsurfaceScattering - 1, version), new PerfDataItem (17,(int) graphics.AnisotropicFiltering - 1, version), }; - string data = JsonSerializer.Serialize(this, typeof(GlobalPerfData), GlobalPerfDataContext.Default); + string data = JsonSerializer.Serialize(this, typeof(GlobalPerfData), GenshinSettingsJSONContext.Default); #if DEBUG - LogWriteLine($"Saved Genshin GlobalPerfData\r\n{data}", LogType.Debug, true); + LogWriteLine($"Saved Genshin GlobalPerfData\r\n{data}", Hi3Helper.LogType.Debug, true); #endif return data; } diff --git a/CollapseLauncher/Classes/GameManagement/GameSettings/Genshin/RegistryClass/GraphicsData.cs b/CollapseLauncher/Classes/GameManagement/GameSettings/Genshin/RegistryClass/GraphicsData.cs index 6dba085e5..6f0f75bca 100644 --- a/CollapseLauncher/Classes/GameManagement/GameSettings/Genshin/RegistryClass/GraphicsData.cs +++ b/CollapseLauncher/Classes/GameManagement/GameSettings/Genshin/RegistryClass/GraphicsData.cs @@ -1,12 +1,13 @@ using CollapseLauncher.GameSettings.Genshin.Context; using CollapseLauncher.GameSettings.Genshin.Enums; -using Hi3Helper; using System; using System.Collections.Generic; using System.Linq; +using System.Text.Encodings.Web; using System.Text.Json; -using static Hi3Helper.Logger; +using Hi3Helper; +using static Hi3Helper.Logger; namespace CollapseLauncher.GameSettings.Genshin { internal class GraphicsData @@ -29,7 +30,7 @@ private static int GetFPSOptionNumber(FPSOption value) public static readonly decimal[] RenderScaleIndex = new decimal[] { 0.6m, 0.8m, 1.0m, 1.1m, 1.2m, 1.3m, 1.4m, 1.5m }; public int currentVolatielGrade { get; set; } = -1; - public List> customVolatileGrades { get; set; } = new(); + public List customVolatileGrades { get; set; } = new(); public string volatileVersion { get; set; } = ""; #endregion @@ -149,102 +150,103 @@ private static int GetFPSOptionNumber(FPSOption value) #endregion #region Methods +#nullable enable public static GraphicsData Load(string graphicsJson) { - GraphicsData graphics = (GraphicsData?)JsonSerializer.Deserialize(graphicsJson, typeof(GraphicsData), GraphicsDataContext.Default) ?? new GraphicsData(); - foreach (Dictionary setting in graphics.customVolatileGrades) + GraphicsData graphics = (GraphicsData?)JsonSerializer.Deserialize(graphicsJson, typeof(GraphicsData), GenshinSettingsJSONContext.Default) ?? new GraphicsData(); + foreach (GenshinKeyValuePair setting in graphics.customVolatileGrades) { - switch (setting["key"]) + switch (setting.key) { case 1: #if DEBUG - LogWriteLine($"Loaded Genshin Settings: Graphics - FPS: {setting["value"]}", LogType.Debug, true); + LogWriteLine($"Loaded Genshin Settings: Graphics - FPS: {setting.value}", LogType.Debug, true); #endif - graphics.FPS = (FPSOption)setting["value"]; + graphics.FPS = (FPSOption)setting.value; break; case 2: #if DEBUG - LogWriteLine($"Loaded Genshin Settings: Graphics - Render Resolution: {setting["value"]}", LogType.Debug, true); + LogWriteLine($"Loaded Genshin Settings: Graphics - Render Resolution: {setting.value}", LogType.Debug, true); #endif - graphics.RenderResolution = (RenderResolutionOption)setting["value"]; + graphics.RenderResolution = (RenderResolutionOption)setting.value; break; case 3: #if DEBUG - LogWriteLine($"Loaded Genshin Settings: Graphics - Shadow Quality: {setting["value"]}", LogType.Debug, true); + LogWriteLine($"Loaded Genshin Settings: Graphics - Shadow Quality: {setting.value}", LogType.Debug, true); #endif - graphics.ShadowQuality = (ShadowQualityOption)setting["value"]; + graphics.ShadowQuality = (ShadowQualityOption)setting.value; break; case 4: #if DEBUG - LogWriteLine($"Loaded Genshin Settings: Graphics - Visual Effects: {setting["value"]}", LogType.Debug, true); + LogWriteLine($"Loaded Genshin Settings: Graphics - Visual Effects: {setting.value}", LogType.Debug, true); #endif - graphics.VisualEffects = (VisualEffectsOption)setting["value"]; + graphics.VisualEffects = (VisualEffectsOption)setting.value; break; case 5: #if DEBUG - LogWriteLine($"Loaded Genshin Settings: Graphics - SFX Quality: {setting["value"]}", LogType.Debug, true); + LogWriteLine($"Loaded Genshin Settings: Graphics - SFX Quality: {setting.value}", LogType.Debug, true); #endif - graphics.SFXQuality = (SFXQualityOption)setting["value"]; + graphics.SFXQuality = (SFXQualityOption)setting.value; break; case 6: #if DEBUG - LogWriteLine($"Loaded Genshin Settings: Graphics - Environment Detail: {setting["value"]}", LogType.Debug, true); + LogWriteLine($"Loaded Genshin Settings: Graphics - Environment Detail: {setting.value}", LogType.Debug, true); #endif - graphics.EnvironmentDetail = (EnvironmentDetailOption)setting["value"]; + graphics.EnvironmentDetail = (EnvironmentDetailOption)setting.value; break; case 7: #if DEBUG - LogWriteLine($"Loaded Genshin Settings: Graphics - Vertical Sync: {setting["value"]}", LogType.Debug, true); + LogWriteLine($"Loaded Genshin Settings: Graphics - Vertical Sync: {setting.value}", LogType.Debug, true); #endif - graphics.VerticalSync = (VerticalSyncOption)setting["value"]; + graphics.VerticalSync = (VerticalSyncOption)setting.value; break; case 8: #if DEBUG - LogWriteLine($"Loaded Genshin Settings: Graphics - Antialiasing: {setting["value"]}", LogType.Debug, true); + LogWriteLine($"Loaded Genshin Settings: Graphics - Antialiasing: {setting.value}", LogType.Debug, true); #endif - graphics.Antialiasing = (AntialiasingOption)setting["value"]; + graphics.Antialiasing = (AntialiasingOption)setting.value; break; case 9: #if DEBUG - LogWriteLine($"Loaded Genshin Settings: Graphics - Volumetric Fog: {setting["value"]}", LogType.Debug, true); + LogWriteLine($"Loaded Genshin Settings: Graphics - Volumetric Fog: {setting.value}", LogType.Debug, true); #endif - graphics.VolumetricFog = (VolumetricFogOption)setting["value"]; + graphics.VolumetricFog = (VolumetricFogOption)setting.value; break; case 10: #if DEBUG - LogWriteLine($"Loaded Genshin Settings: Graphics - Reflections: {setting["value"]}", LogType.Debug, true); + LogWriteLine($"Loaded Genshin Settings: Graphics - Reflections: {setting.value}", LogType.Debug, true); #endif - graphics.Reflections = (ReflectionsOption)setting["value"]; + graphics.Reflections = (ReflectionsOption)setting.value; break; case 11: #if DEBUG - LogWriteLine($"Loaded Genshin Settings: Graphics - Motion Blur: {setting["value"]}", LogType.Debug, true); + LogWriteLine($"Loaded Genshin Settings: Graphics - Motion Blur: {setting.value}", LogType.Debug, true); #endif - graphics.MotionBlur = (MotionBlurOption)setting["value"]; + graphics.MotionBlur = (MotionBlurOption)setting.value; break; case 12: #if DEBUG - LogWriteLine($"Loaded Genshin Settings: Graphics - Bloom: {setting["value"]}", LogType.Debug, true); + LogWriteLine($"Loaded Genshin Settings: Graphics - Bloom: {setting.value}", LogType.Debug, true); #endif - graphics.Bloom = (BloomOption)setting["value"]; + graphics.Bloom = (BloomOption)setting.value; break; case 13: #if DEBUG - LogWriteLine($"Loaded Genshin Settings: Graphics - Crowd Density: {setting["value"]}", LogType.Debug, true); + LogWriteLine($"Loaded Genshin Settings: Graphics - Crowd Density: {setting.value}", LogType.Debug, true); #endif - graphics.CrowdDensity = (CrowdDensityOption)setting["value"]; + graphics.CrowdDensity = (CrowdDensityOption)setting.value; break; // 14 is missing from settings @@ -252,23 +254,23 @@ public static GraphicsData Load(string graphicsJson) // It is meant to be like this because miyoyo case 16: #if DEBUG - LogWriteLine($"Loaded Genshin Settings: Graphics - Co-Op Teammate Effects: {setting["value"]}", LogType.Debug, true); + LogWriteLine($"Loaded Genshin Settings: Graphics - Co-Op Teammate Effects: {setting.value}", LogType.Debug, true); #endif - graphics.CoOpTeammateEffects = (CoOpTeammateEffectsOption)setting["value"]; + graphics.CoOpTeammateEffects = (CoOpTeammateEffectsOption)setting.value; break; case 15: #if DEBUG - LogWriteLine($"Loaded Genshin Settings: Graphics - Subsurface Scattering: {setting["value"]}", LogType.Debug, true); + LogWriteLine($"Loaded Genshin Settings: Graphics - Subsurface Scattering: {setting.value}", LogType.Debug, true); #endif - graphics.SubsurfaceScattering = (SubsurfaceScatteringOption)setting["value"]; + graphics.SubsurfaceScattering = (SubsurfaceScatteringOption)setting.value; break; case 17: #if DEBUG - LogWriteLine($"Loaded Genshin Settings: Graphics - Anisotropic Filtering: {setting["value"]}", LogType.Debug, true); + LogWriteLine($"Loaded Genshin Settings: Graphics - Anisotropic Filtering: {setting.value}", LogType.Debug, true); #endif - graphics.AnisotropicFiltering = (AnisotropicFilteringOption)setting["value"]; + graphics.AnisotropicFiltering = (AnisotropicFilteringOption)setting.value; break; } } @@ -279,29 +281,37 @@ public string Save() { customVolatileGrades = new() { - new Dictionary() { { "key", 1 }, { "value", (int)FPS } }, - new Dictionary() { { "key", 2 }, { "value", (int)RenderResolution } }, - new Dictionary() { { "key", 3 }, { "value", (int)ShadowQuality } }, - new Dictionary() { { "key", 4 }, { "value", (int)VisualEffects } }, - new Dictionary() { { "key", 5 }, { "value", (int)SFXQuality } }, - new Dictionary() { { "key", 6 }, { "value", (int)EnvironmentDetail } }, - new Dictionary() { { "key", 7 }, { "value", (int)VerticalSync } }, - new Dictionary() { { "key", 8 }, { "value", (int)Antialiasing } }, - new Dictionary() { { "key", 9 }, { "value", (int)VolumetricFog } }, - new Dictionary() { { "key", 10 }, { "value", (int)Reflections } }, - new Dictionary() { { "key", 11 }, { "value", (int)MotionBlur } }, - new Dictionary() { { "key", 12 }, { "value", (int)Bloom } }, - new Dictionary() { { "key", 13 }, { "value", (int)CrowdDensity } }, - new Dictionary() { { "key", 16 }, { "value", (int)CoOpTeammateEffects } }, - new Dictionary() { { "key", 15 }, { "value", (int)SubsurfaceScattering } }, - new Dictionary() { { "key", 17 }, { "value", (int)AnisotropicFiltering } }, + new GenshinKeyValuePair(1, (int)FPS), + new GenshinKeyValuePair(2, (int)RenderResolution), + new GenshinKeyValuePair(3, (int)ShadowQuality), + new GenshinKeyValuePair(4, (int)VisualEffects), + new GenshinKeyValuePair(5, (int)SFXQuality), + new GenshinKeyValuePair(6, (int)EnvironmentDetail), + new GenshinKeyValuePair(7, (int)VerticalSync), + new GenshinKeyValuePair(8, (int)Antialiasing), + new GenshinKeyValuePair(9, (int)VolumetricFog), + new GenshinKeyValuePair(10, (int)Reflections), + new GenshinKeyValuePair(11, (int)MotionBlur), + new GenshinKeyValuePair(12, (int)Bloom), + new GenshinKeyValuePair(13, (int)CrowdDensity), + new GenshinKeyValuePair(16, (int)CoOpTeammateEffects), + new GenshinKeyValuePair(15, (int)SubsurfaceScattering), + new GenshinKeyValuePair(17, (int)AnisotropicFiltering) }; - string data = JsonSerializer.Serialize(this, typeof(GraphicsData), GraphicsDataContext.Default); + + JsonSerializerOptions options = new JsonSerializerOptions() + { + TypeInfoResolver = GenshinSettingsJSONContext.Default, + Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping + }; + + string data = JsonSerializer.Serialize(this, typeof(GraphicsData), options); #if DEBUG LogWriteLine($"Saved Genshin GraphicsData\r\n{data}", LogType.Debug, true); #endif return data; } +#nullable disable #endregion } } diff --git a/CollapseLauncher/Classes/GameManagement/GameSettings/Genshin/RegistryClass/ScreenManager.cs b/CollapseLauncher/Classes/GameManagement/GameSettings/Genshin/RegistryClass/ScreenManager.cs index 3d9f0fc6d..8faa4f027 100644 --- a/CollapseLauncher/Classes/GameManagement/GameSettings/Genshin/RegistryClass/ScreenManager.cs +++ b/CollapseLauncher/Classes/GameManagement/GameSettings/Genshin/RegistryClass/ScreenManager.cs @@ -5,7 +5,7 @@ using Microsoft.Win32; using System; using System.Drawing; -using static CollapseLauncher.GameSettings.Statics; +using static CollapseLauncher.GameSettings.Base.SettingsBase; using static Hi3Helper.Logger; namespace CollapseLauncher.GameSettings.Genshin @@ -96,8 +96,9 @@ public override bool isfullScreen }; } #endregion -#nullable enable + #region Methods +#nullable enable public static ScreenManager Load() { try @@ -135,18 +136,12 @@ public override void Save() try { RegistryRoot?.SetValue(_ValueNameScreenManagerFullscreen, fullscreen, RegistryValueKind.DWord); -#if DEBUG - LogWriteLine($"Saved Genshin Settings: {_ValueNameScreenManagerFullscreen} : {RegistryRoot.GetValue(_ValueNameScreenManagerFullscreen, null)}", LogType.Debug, true); -#endif - RegistryRoot?.SetValue(_ValueNameScreenManagerWidth, width, RegistryValueKind.DWord); -#if DEBUG - LogWriteLine($"Saved Genshin Settings: {_ValueNameScreenManagerWidth} : {RegistryRoot.GetValue(_ValueNameScreenManagerWidth, null)}", LogType.Debug, true); -#endif - RegistryRoot?.SetValue(_ValueNameScreenManagerHeight, height, RegistryValueKind.DWord); #if DEBUG - LogWriteLine($"Saved Genshin Settings: {_ValueNameScreenManagerHeight} : {RegistryRoot.GetValue(_ValueNameScreenManagerHeight, null)}", LogType.Debug, true); + LogWriteLine($"Saved Genshin Settings: {_ValueNameScreenManagerFullscreen} : {RegistryRoot?.GetValue(_ValueNameScreenManagerFullscreen, null)}", LogType.Debug, true); + LogWriteLine($"Saved Genshin Settings: {_ValueNameScreenManagerWidth} : {RegistryRoot?.GetValue(_ValueNameScreenManagerWidth, null)}", LogType.Debug, true); + LogWriteLine($"Saved Genshin Settings: {_ValueNameScreenManagerHeight} : {RegistryRoot?.GetValue(_ValueNameScreenManagerHeight, null)}", LogType.Debug, true); #endif } catch (Exception ex) @@ -155,18 +150,8 @@ public override void Save() } } - public bool Equals(ScreenManager? comparedTo) - { - if (ReferenceEquals(this, comparedTo)) return true; - if (comparedTo == null) return false; - - return comparedTo.sizeRes == this.sizeRes && - comparedTo.height == this.height && - comparedTo.width == this.width && - comparedTo.fullscreen == this.fullscreen; - } - #endregion + public bool Equals(ScreenManager? comparedTo) => TypeExtensions.IsInstancePropertyEqual(this, comparedTo); #nullable disable - + #endregion } } \ No newline at end of file diff --git a/CollapseLauncher/Classes/GameManagement/GameSettings/Genshin/Settings.cs b/CollapseLauncher/Classes/GameManagement/GameSettings/Genshin/Settings.cs index cba9d337f..728ebb35f 100644 --- a/CollapseLauncher/Classes/GameManagement/GameSettings/Genshin/Settings.cs +++ b/CollapseLauncher/Classes/GameManagement/GameSettings/Genshin/Settings.cs @@ -1,25 +1,23 @@ using CollapseLauncher.GameSettings.Base; -using CollapseLauncher.GameSettings.Genshin; using CollapseLauncher.GameSettings.Universal; using CollapseLauncher.Interfaces; -using CollapseLauncher.Statics; using Microsoft.Win32; using System.IO; -using static CollapseLauncher.GameSettings.Statics; namespace CollapseLauncher.GameSettings.Genshin { - internal class GenshinSettings : ImportExportBase, IGameSettings, IGameSettingsUniversal + internal class GenshinSettings : SettingsBase, IGameSettings, IGameSettingsUniversal { public CustomArgs SettingsCustomArgument { get; set; } public BaseScreenSettingData SettingsScreen { get; set; } public CollapseScreenSetting SettingsCollapseScreen { get; set; } public GeneralData SettingsGeneralData { get; set; } - public GenshinSettings() + public GenshinSettings(IGameVersionCheck GameVersionManager) + : base(GameVersionManager) { // Init Root Registry Key - RegistryPath = Path.Combine(RegistryRootPath, PageStatics._GameVersion.GamePreset.InternalGameNameInConfig); + RegistryPath = Path.Combine($"Software\\{_gameVersionManager.VendorTypeProp.VendorType}", _gameVersionManager.GamePreset.InternalGameNameInConfig); RegistryRoot = Registry.CurrentUser.OpenSubKey(RegistryPath, true); // If the Root Registry Key is null (not exist), then create a new one. diff --git a/CollapseLauncher/Classes/GameManagement/GameSettings/Honkai/Context.cs b/CollapseLauncher/Classes/GameManagement/GameSettings/Honkai/Context.cs index 23ec9b78c..50a418a78 100644 --- a/CollapseLauncher/Classes/GameManagement/GameSettings/Honkai/Context.cs +++ b/CollapseLauncher/Classes/GameManagement/GameSettings/Honkai/Context.cs @@ -4,22 +4,10 @@ namespace CollapseLauncher.GameSettings.Honkai.Context { [JsonSourceGenerationOptions(IncludeFields = false, GenerationMode = JsonSourceGenerationMode.Metadata, IgnoreReadOnlyFields = true)] + [JsonSerializable(typeof(ScreenSettingData))] [JsonSerializable(typeof(PersonalAudioSetting))] - internal sealed partial class PersonalAudioSettingContext : JsonSerializerContext { } - - [JsonSourceGenerationOptions(IncludeFields = false, GenerationMode = JsonSourceGenerationMode.Metadata, IgnoreReadOnlyFields = true)] - [JsonSerializable(typeof(PersonalAudioSettingVolume))] - internal sealed partial class PersonalAudioSettingVolumeContext : JsonSerializerContext { } - - [JsonSourceGenerationOptions(IncludeFields = false, GenerationMode = JsonSourceGenerationMode.Metadata, IgnoreReadOnlyFields = true)] [JsonSerializable(typeof(PersonalGraphicsSettingV2))] - internal sealed partial class PersonalGraphicsSettingV2Context : JsonSerializerContext { } - - [JsonSourceGenerationOptions(IncludeFields = false, GenerationMode = JsonSourceGenerationMode.Metadata, IgnoreReadOnlyFields = true)] + [JsonSerializable(typeof(PersonalAudioSettingVolume))] [JsonSerializable(typeof(Dictionary))] - internal sealed partial class D_PersonalGraphicsSettingV2Context : JsonSerializerContext { } - - [JsonSourceGenerationOptions(IncludeFields = false, GenerationMode = JsonSourceGenerationMode.Metadata, IgnoreReadOnlyFields = true)] - [JsonSerializable(typeof(ScreenSettingData))] - internal sealed partial class ScreenSettingDataContext : JsonSerializerContext { } + internal sealed partial class HonkaiSettingsJSONContext : JsonSerializerContext { } } diff --git a/CollapseLauncher/Classes/GameManagement/GameSettings/Honkai/RegistryClass/PersonalAudioSetting.cs b/CollapseLauncher/Classes/GameManagement/GameSettings/Honkai/RegistryClass/PersonalAudioSetting.cs index 8c1bbd98c..fde2678f9 100644 --- a/CollapseLauncher/Classes/GameManagement/GameSettings/Honkai/RegistryClass/PersonalAudioSetting.cs +++ b/CollapseLauncher/Classes/GameManagement/GameSettings/Honkai/RegistryClass/PersonalAudioSetting.cs @@ -6,7 +6,7 @@ using System.Text; using System.Text.Json; using System.Text.Json.Serialization; -using static CollapseLauncher.GameSettings.Statics; +using static CollapseLauncher.GameSettings.Base.SettingsBase; using static Hi3Helper.Data.ConverterTool; using static Hi3Helper.Logger; @@ -187,7 +187,7 @@ public static PersonalAudioSetting Load() #if DEBUG LogWriteLine($"Loaded HI3 Settings: {_ValueName}\r\n{Encoding.UTF8.GetString((byte[])value, 0, ((byte[])value).Length - 1)}", LogType.Debug, true); #endif - return (PersonalAudioSetting?)JsonSerializer.Deserialize(byteStr.Slice(0, byteStr.Length - 1), typeof(PersonalAudioSetting), PersonalAudioSettingContext.Default) ?? new PersonalAudioSetting(); + return (PersonalAudioSetting?)JsonSerializer.Deserialize(byteStr.Slice(0, byteStr.Length - 1), typeof(PersonalAudioSetting), HonkaiSettingsJSONContext.Default) ?? new PersonalAudioSetting(); } } catch (Exception ex) @@ -204,7 +204,7 @@ public void Save() { if (RegistryRoot == null) throw new NullReferenceException($"Cannot save {_ValueName} since RegistryKey is unexpectedly not initialized!"); - string data = JsonSerializer.Serialize(this, typeof(PersonalAudioSetting), PersonalAudioSettingContext.Default) + '\0'; + string data = JsonSerializer.Serialize(this, typeof(PersonalAudioSetting), HonkaiSettingsJSONContext.Default) + '\0'; byte[] dataByte = Encoding.UTF8.GetBytes(data); RegistryRoot.SetValue(_ValueName, dataByte, RegistryValueKind.Binary); @@ -219,23 +219,7 @@ public void Save() } } - public bool Equals(PersonalAudioSetting? comparedTo) - { - if (ReferenceEquals(this, comparedTo)) return true; - if (comparedTo == null) return false; - - return comparedTo.IsUserDefined == this.IsUserDefined && - comparedTo.CVLanguage == this.CVLanguage && - comparedTo._userCVLanguage == this._userCVLanguage && - comparedTo.BGMVolume == this.BGMVolume && - comparedTo.ElfVolume == this.ElfVolume && - comparedTo.CGVolumeV2 == this.CGVolumeV2 && - comparedTo.MasterVolume == this.MasterVolume && - comparedTo.SoundEffectVolume == this.SoundEffectVolume && - comparedTo.VoiceVolume == this.VoiceVolume && - comparedTo.Mute == this.Mute; - } -#nullable disable + public bool Equals(PersonalAudioSetting? comparedTo) => TypeExtensions.IsInstancePropertyEqual(this, comparedTo); #endregion } } diff --git a/CollapseLauncher/Classes/GameManagement/GameSettings/Honkai/RegistryClass/PersonalAudioSettingVolume.cs b/CollapseLauncher/Classes/GameManagement/GameSettings/Honkai/RegistryClass/PersonalAudioSettingVolume.cs index 0dd2c582f..8ab1b3ee9 100644 --- a/CollapseLauncher/Classes/GameManagement/GameSettings/Honkai/RegistryClass/PersonalAudioSettingVolume.cs +++ b/CollapseLauncher/Classes/GameManagement/GameSettings/Honkai/RegistryClass/PersonalAudioSettingVolume.cs @@ -5,7 +5,7 @@ using System; using System.Text; using System.Text.Json; -using static CollapseLauncher.GameSettings.Statics; +using static CollapseLauncher.GameSettings.Base.SettingsBase; using static Hi3Helper.Logger; namespace CollapseLauncher.GameSettings.Honkai @@ -81,7 +81,7 @@ public static PersonalAudioSettingVolume Load() #if DEBUG LogWriteLine($"Loaded HI3 Settings: {_ValueName}\r\n{Encoding.UTF8.GetString((byte[])value, 0, ((byte[])value).Length - 1)}", LogType.Debug, true); #endif - return (PersonalAudioSettingVolume?)JsonSerializer.Deserialize(byteStr.Slice(0, byteStr.Length - 1), typeof(PersonalAudioSettingVolume), PersonalAudioSettingVolumeContext.Default) ?? new PersonalAudioSettingVolume(); + return (PersonalAudioSettingVolume?)JsonSerializer.Deserialize(byteStr.Slice(0, byteStr.Length - 1), typeof(PersonalAudioSettingVolume), HonkaiSettingsJSONContext.Default) ?? new PersonalAudioSettingVolume(); } } catch (Exception ex) @@ -97,7 +97,7 @@ public void Save() { if (RegistryRoot == null) throw new NullReferenceException($"Cannot save {_ValueName} since RegistryKey is unexpectedly not initialized!"); - string data = JsonSerializer.Serialize(this, typeof(PersonalAudioSettingVolume), PersonalAudioSettingVolumeContext.Default) + '\0'; + string data = JsonSerializer.Serialize(this, typeof(PersonalAudioSettingVolume), HonkaiSettingsJSONContext.Default) + '\0'; byte[] dataByte = Encoding.UTF8.GetBytes(data); RegistryRoot.SetValue(_ValueName, dataByte, RegistryValueKind.Binary); @@ -111,20 +111,7 @@ public void Save() } } - public bool Equals(PersonalAudioSettingVolume? comparedTo) - { - if (ReferenceEquals(this, comparedTo)) return true; - if (comparedTo == null) return false; - - return comparedTo.BGMVolumeValue == this.BGMVolumeValue && - comparedTo.CGVolumeValue == this.CGVolumeValue && - comparedTo.ElfVolumeValue == this.ElfVolumeValue && - comparedTo.SoundEffectVolumeValue == this.SoundEffectVolumeValue && - comparedTo.CreateByDefault == this.CreateByDefault && - comparedTo.VoiceVolumeValue == this.VoiceVolumeValue && - comparedTo.MasterVolumeValue == this.MasterVolumeValue; - } -#nullable disable + public bool Equals(PersonalAudioSettingVolume? comparedTo) => TypeExtensions.IsInstancePropertyEqual(this, comparedTo); #endregion } } diff --git a/CollapseLauncher/Classes/GameManagement/GameSettings/Honkai/RegistryClass/PersonalGraphicsSettingV2.cs b/CollapseLauncher/Classes/GameManagement/GameSettings/Honkai/RegistryClass/PersonalGraphicsSettingV2.cs index a04519e43..510bcdc86 100644 --- a/CollapseLauncher/Classes/GameManagement/GameSettings/Honkai/RegistryClass/PersonalGraphicsSettingV2.cs +++ b/CollapseLauncher/Classes/GameManagement/GameSettings/Honkai/RegistryClass/PersonalGraphicsSettingV2.cs @@ -7,7 +7,7 @@ using System.Text; using System.Text.Json; using System.Text.Json.Serialization; -using static CollapseLauncher.GameSettings.Statics; +using static CollapseLauncher.GameSettings.Base.SettingsBase; using static Hi3Helper.Logger; namespace CollapseLauncher.GameSettings.Honkai @@ -161,7 +161,7 @@ public static PersonalGraphicsSettingV2 Load() #if DEBUG LogWriteLine($"Loaded HI3 Settings: {_ValueName}\r\n{Encoding.UTF8.GetString((byte[])value, 0, ((byte[])value).Length - 1)}", LogType.Debug, true); #endif - return (PersonalGraphicsSettingV2?)JsonSerializer.Deserialize(byteStr.Slice(0, byteStr.Length - 1), typeof(PersonalGraphicsSettingV2), PersonalGraphicsSettingV2Context.Default) ?? new PersonalGraphicsSettingV2(); + return (PersonalGraphicsSettingV2?)JsonSerializer.Deserialize(byteStr.Slice(0, byteStr.Length - 1), typeof(PersonalGraphicsSettingV2), HonkaiSettingsJSONContext.Default) ?? new PersonalGraphicsSettingV2(); } } catch (Exception ex) @@ -178,7 +178,7 @@ public void Save() { if (RegistryRoot == null) throw new NullReferenceException($"Cannot save {_ValueName} since RegistryKey is unexpectedly not initialized!"); - string data = JsonSerializer.Serialize(this, typeof(PersonalGraphicsSettingV2), PersonalGraphicsSettingV2Context.Default) + '\0'; + string data = JsonSerializer.Serialize(this, typeof(PersonalGraphicsSettingV2), HonkaiSettingsJSONContext.Default) + '\0'; byte[] dataByte = Encoding.UTF8.GetBytes(data); RegistryRoot.SetValue(_ValueName, dataByte, RegistryValueKind.Binary); @@ -192,28 +192,7 @@ public void Save() } } - public bool Equals(PersonalGraphicsSettingV2? comparedTo) - { - if (ReferenceEquals(this, comparedTo)) return true; - if (comparedTo == null) return false; - - return comparedTo.UseHDR == this.UseHDR && - comparedTo.UseFXAA == this.UseFXAA && - comparedTo.UsePostFX == this.UsePostFX && - comparedTo.ResolutionQuality == this.ResolutionQuality && - comparedTo.ReflectionQuality == this.ReflectionQuality && - comparedTo.ShadowLevel == this.ShadowLevel && - comparedTo.AmbientOcclusion == this.AmbientOcclusion && - comparedTo.GlobalIllumination == this.GlobalIllumination && - comparedTo.LodGrade == this.LodGrade && - comparedTo.PostFXGrade == this.PostFXGrade && - comparedTo.TargetFrameRateForInLevel == this.TargetFrameRateForInLevel && - comparedTo.TargetFrameRateForOthers == this.TargetFrameRateForOthers && - comparedTo.UseDistortion == this.UseDistortion && - comparedTo.UseDynamicBone == this.UseDynamicBone && - comparedTo.VolumetricLight == this.VolumetricLight; - } -#nullable disable + public bool Equals(PersonalGraphicsSettingV2? comparedTo) => TypeExtensions.IsInstancePropertyEqual(this, comparedTo); #endregion } } diff --git a/CollapseLauncher/Classes/GameManagement/GameSettings/Honkai/RegistryClass/Preset.cs b/CollapseLauncher/Classes/GameManagement/GameSettings/Honkai/RegistryClass/Preset.cs index bdba0a235..bc4a07e26 100644 --- a/CollapseLauncher/Classes/GameManagement/GameSettings/Honkai/RegistryClass/Preset.cs +++ b/CollapseLauncher/Classes/GameManagement/GameSettings/Honkai/RegistryClass/Preset.cs @@ -7,7 +7,7 @@ using System.Linq; using System.Text.Json; using System.Text.Json.Serialization; -using static CollapseLauncher.GameSettings.Statics; +using static CollapseLauncher.GameSettings.Base.SettingsBase; using static Hi3Helper.Shared.Region.LauncherConfig; namespace CollapseLauncher.GameSettings diff --git a/CollapseLauncher/Classes/GameManagement/GameSettings/Honkai/RegistryClass/ScreenSettingData.cs b/CollapseLauncher/Classes/GameManagement/GameSettings/Honkai/RegistryClass/ScreenSettingData.cs index 44d32ec1b..b1a9d66e8 100644 --- a/CollapseLauncher/Classes/GameManagement/GameSettings/Honkai/RegistryClass/ScreenSettingData.cs +++ b/CollapseLauncher/Classes/GameManagement/GameSettings/Honkai/RegistryClass/ScreenSettingData.cs @@ -9,7 +9,7 @@ using System.Text; using System.Text.Json; using System.Text.Json.Serialization; -using static CollapseLauncher.GameSettings.Statics; +using static CollapseLauncher.GameSettings.Base.SettingsBase; using static Hi3Helper.Logger; namespace CollapseLauncher.GameSettings.Honkai @@ -105,7 +105,7 @@ public static ScreenSettingData Load() #if DEBUG LogWriteLine($"Loaded HI3 Settings: {_ValueName}\r\n{Encoding.UTF8.GetString((byte[])value, 0, ((byte[])value).Length - 1)}", LogType.Debug, true); #endif - return (ScreenSettingData?)JsonSerializer.Deserialize(byteStr.Slice(0, byteStr.Length - 1), typeof(ScreenSettingData), ScreenSettingDataContext.Default) ?? new ScreenSettingData(); + return (ScreenSettingData?)JsonSerializer.Deserialize(byteStr.Slice(0, byteStr.Length - 1), typeof(ScreenSettingData), HonkaiSettingsJSONContext.Default) ?? new ScreenSettingData(); } } catch (Exception ex) @@ -122,7 +122,7 @@ public override void Save() { if (RegistryRoot == null) throw new NullReferenceException($"Cannot save {_ValueName} since RegistryKey is unexpectedly not initialized!"); - string data = JsonSerializer.Serialize(this, typeof(ScreenSettingData), ScreenSettingDataContext.Default) + '\0'; + string data = JsonSerializer.Serialize(this, typeof(ScreenSettingData), HonkaiSettingsJSONContext.Default) + '\0'; byte[] dataByte = Encoding.UTF8.GetBytes(data); RegistryRoot.SetValue(_ValueName, dataByte, RegistryValueKind.Binary); @@ -144,17 +144,7 @@ private void SaveIndividualRegistry() RegistryRoot?.SetValue(_ValueNameScreenManagerHeight, height, RegistryValueKind.DWord); } - public bool Equals(ScreenSettingData? comparedTo) - { - if (ReferenceEquals(this, comparedTo)) return true; - if (comparedTo == null) return false; - - return comparedTo.sizeRes == this.sizeRes && - comparedTo.height == this.height && - comparedTo.width == this.width && - comparedTo.isfullScreen == this.isfullScreen; - } -#nullable disable + public bool Equals(ScreenSettingData? comparedTo) => TypeExtensions.IsInstancePropertyEqual(this, comparedTo); #endregion } } diff --git a/CollapseLauncher/Classes/GameManagement/GameSettings/Honkai/Settings.cs b/CollapseLauncher/Classes/GameManagement/GameSettings/Honkai/Settings.cs index 36246b2dd..cb47a5632 100644 --- a/CollapseLauncher/Classes/GameManagement/GameSettings/Honkai/Settings.cs +++ b/CollapseLauncher/Classes/GameManagement/GameSettings/Honkai/Settings.cs @@ -2,18 +2,16 @@ using CollapseLauncher.GameSettings.Honkai.Context; using CollapseLauncher.GameSettings.Universal; using CollapseLauncher.Interfaces; -using CollapseLauncher.Statics; using Hi3Helper.Preset; using Microsoft.Win32; using System.IO; -using static CollapseLauncher.GameSettings.Statics; namespace CollapseLauncher.GameSettings.Honkai { - internal class HonkaiSettings : ImportExportBase, IGameSettings, IGameSettingsUniversal + internal class HonkaiSettings : SettingsBase, IGameSettings, IGameSettingsUniversal { #region PresetProperties - public Preset Preset_SettingsGraphics { get; set; } + public Preset Preset_SettingsGraphics { get; set; } #endregion #region SettingProperties @@ -24,10 +22,11 @@ internal class HonkaiSettings : ImportExportBase, IGameSettings, IGameSettingsUn public CollapseScreenSetting SettingsCollapseScreen { get; set; } #endregion - public HonkaiSettings() + public HonkaiSettings(IGameVersionCheck GameVersionManager) + : base(GameVersionManager) { // Init Root Registry Key - RegistryPath = Path.Combine(RegistryRootPath, PageStatics._GameVersion.GamePreset.InternalGameNameInConfig); + RegistryPath = Path.Combine($"Software\\{_gameVersionManager.VendorTypeProp.VendorType}", _gameVersionManager.GamePreset.InternalGameNameInConfig); RegistryRoot = Registry.CurrentUser.OpenSubKey(RegistryPath, true); // If the Root Registry Key is null (not exist), then create a new one. @@ -50,7 +49,7 @@ private void InitializeSettings() SettingsCollapseScreen = CollapseScreenSetting.Load(); // Load Preset - Preset_SettingsGraphics = Preset.LoadPreset(GameType.Honkai, D_PersonalGraphicsSettingV2Context.Default); + Preset_SettingsGraphics = Preset.LoadPreset(GameType.Honkai, HonkaiSettingsJSONContext.Default); } public void ReloadSettings() => InitializeSettings(); diff --git a/CollapseLauncher/Classes/GameManagement/GameSettings/StarRail/Context.cs b/CollapseLauncher/Classes/GameManagement/GameSettings/StarRail/Context.cs index c72a20f2f..0a18f5f6d 100644 --- a/CollapseLauncher/Classes/GameManagement/GameSettings/StarRail/Context.cs +++ b/CollapseLauncher/Classes/GameManagement/GameSettings/StarRail/Context.cs @@ -5,9 +5,6 @@ namespace CollapseLauncher.GameSettings.StarRail.Context { [JsonSourceGenerationOptions(IncludeFields = false, GenerationMode = JsonSourceGenerationMode.Metadata, IgnoreReadOnlyFields = true)] [JsonSerializable(typeof(Model))] - internal sealed partial class ModelContext : JsonSerializerContext { } - - [JsonSourceGenerationOptions(IncludeFields = false, GenerationMode = JsonSourceGenerationMode.Metadata, IgnoreReadOnlyFields = true)] [JsonSerializable(typeof(PCResolution))] - internal sealed partial class PCResolutionContext : JsonSerializerContext { } + internal sealed partial class StarRailSettingsJSONContext : JsonSerializerContext { } } diff --git a/CollapseLauncher/Classes/GameManagement/GameSettings/StarRail/RegistryClass/BGMVolume.cs b/CollapseLauncher/Classes/GameManagement/GameSettings/StarRail/RegistryClass/BGMVolume.cs index fcf9b1f54..838c22967 100644 --- a/CollapseLauncher/Classes/GameManagement/GameSettings/StarRail/RegistryClass/BGMVolume.cs +++ b/CollapseLauncher/Classes/GameManagement/GameSettings/StarRail/RegistryClass/BGMVolume.cs @@ -2,10 +2,8 @@ using Hi3Helper; using Microsoft.Win32; using System; -using System.Text; -using static CollapseLauncher.GameSettings.Statics; +using static CollapseLauncher.GameSettings.Base.SettingsBase; using static Hi3Helper.Logger; -using static System.Runtime.InteropServices.JavaScript.JSType; namespace CollapseLauncher.GameSettings.StarRail { @@ -67,14 +65,7 @@ public void Save() } - public bool Equals(BGMVolume? comparedTo) - { - if (ReferenceEquals(this, comparedTo)) return true; - if (comparedTo == null) return false; - - return comparedTo.BGMVol == this.BGMVol; - } -#nullable disable + public bool Equals(BGMVolume? comparedTo) => TypeExtensions.IsInstancePropertyEqual(this, comparedTo); #endregion } } diff --git a/CollapseLauncher/Classes/GameManagement/GameSettings/StarRail/RegistryClass/LocalAudioLanguage.cs b/CollapseLauncher/Classes/GameManagement/GameSettings/StarRail/RegistryClass/LocalAudioLanguage.cs index 667f813f4..45ec39c56 100644 --- a/CollapseLauncher/Classes/GameManagement/GameSettings/StarRail/RegistryClass/LocalAudioLanguage.cs +++ b/CollapseLauncher/Classes/GameManagement/GameSettings/StarRail/RegistryClass/LocalAudioLanguage.cs @@ -3,7 +3,7 @@ using Microsoft.Win32; using System; using System.Text; -using static CollapseLauncher.GameSettings.Statics; +using static CollapseLauncher.GameSettings.Base.SettingsBase; using static Hi3Helper.Logger; @@ -93,14 +93,7 @@ public void Save() } - public bool Equals(LocalAudioLanguage? comparedTo) - { - if (ReferenceEquals(this, comparedTo)) return true; - if (comparedTo == null) return false; - - return comparedTo.LocalAudioLang == this.LocalAudioLang; - } -#nullable disable + public bool Equals(LocalAudioLanguage? comparedTo) => TypeExtensions.IsInstancePropertyEqual(this, comparedTo); #endregion } } diff --git a/CollapseLauncher/Classes/GameManagement/GameSettings/StarRail/RegistryClass/LocalTextLanguage.cs b/CollapseLauncher/Classes/GameManagement/GameSettings/StarRail/RegistryClass/LocalTextLanguage.cs index 69f1c5110..b96af6202 100644 --- a/CollapseLauncher/Classes/GameManagement/GameSettings/StarRail/RegistryClass/LocalTextLanguage.cs +++ b/CollapseLauncher/Classes/GameManagement/GameSettings/StarRail/RegistryClass/LocalTextLanguage.cs @@ -3,7 +3,7 @@ using Microsoft.Win32; using System; using System.Text; -using static CollapseLauncher.GameSettings.Statics; +using static CollapseLauncher.GameSettings.Base.SettingsBase; using static Hi3Helper.Logger; @@ -112,14 +112,7 @@ public void Save() } - public bool Equals(LocalTextLanguage? comparedTo) - { - if (ReferenceEquals(this, comparedTo)) return true; - if (comparedTo == null) return false; - - return comparedTo.LocalTextLang == this.LocalTextLang; - } -#nullable disable + public bool Equals(LocalTextLanguage? comparedTo) => TypeExtensions.IsInstancePropertyEqual(this, comparedTo); #endregion } } diff --git a/CollapseLauncher/Classes/GameManagement/GameSettings/StarRail/RegistryClass/MasterVolume.cs b/CollapseLauncher/Classes/GameManagement/GameSettings/StarRail/RegistryClass/MasterVolume.cs index f7b097b77..f340c99e7 100644 --- a/CollapseLauncher/Classes/GameManagement/GameSettings/StarRail/RegistryClass/MasterVolume.cs +++ b/CollapseLauncher/Classes/GameManagement/GameSettings/StarRail/RegistryClass/MasterVolume.cs @@ -2,7 +2,7 @@ using Hi3Helper; using Microsoft.Win32; using System; -using static CollapseLauncher.GameSettings.Statics; +using static CollapseLauncher.GameSettings.Base.SettingsBase; using static Hi3Helper.Logger; namespace CollapseLauncher.GameSettings.StarRail @@ -65,14 +65,7 @@ public void Save() } - public bool Equals(MasterVolume? comparedTo) - { - if (ReferenceEquals(this, comparedTo)) return true; - if (comparedTo == null) return false; - - return comparedTo.MasterVol == this.MasterVol; - } -#nullable disable + public bool Equals(MasterVolume? comparedTo) => TypeExtensions.IsInstancePropertyEqual(this, comparedTo); #endregion } } diff --git a/CollapseLauncher/Classes/GameManagement/GameSettings/StarRail/RegistryClass/Model.cs b/CollapseLauncher/Classes/GameManagement/GameSettings/StarRail/RegistryClass/Model.cs index 68d4f904b..feb18977c 100644 --- a/CollapseLauncher/Classes/GameManagement/GameSettings/StarRail/RegistryClass/Model.cs +++ b/CollapseLauncher/Classes/GameManagement/GameSettings/StarRail/RegistryClass/Model.cs @@ -1,13 +1,12 @@ using CollapseLauncher.GameSettings.StarRail.Context; using CollapseLauncher.Interfaces; -using Google.Protobuf.WellKnownTypes; using Hi3Helper; using Microsoft.Win32; using System; using System.Collections.Generic; using System.Text; using System.Text.Json; -using static CollapseLauncher.GameSettings.Statics; +using static CollapseLauncher.GameSettings.Base.SettingsBase; using static Hi3Helper.Logger; namespace CollapseLauncher.GameSettings.StarRail @@ -30,7 +29,7 @@ public enum AntialiasingMode // TypeDefIndex: 25409 TAA = 1, FXAA = 2 } -#endregion + #endregion internal class Model : IGameSettingsValue { @@ -114,6 +113,13 @@ private static Dictionary GenerateStaticFPSIndexDict() /// public Quality ReflectionQuality { get; set; } = Quality.Medium; + /// + /// This defines "SFX Quality" combobox In-game settings.
> + /// Options: VeryLow (1), Low (2), Medium(3), High(4) + /// Default: Medium + ///
+ public Quality SFXQuality { get; set; } = Quality.Medium; + /// /// This defines "Bloom Quality" combobox In-game settings.
/// Options: Off(0), VeryLow (1), Low (2), Medium(3), High(4), VeryHigh(5) @@ -145,7 +151,7 @@ public static Model Load() #if DEBUG LogWriteLine($"Loaded StarRail Settings: {_ValueName}\r\n{Encoding.UTF8.GetString((byte[])value, 0, ((byte[])value).Length - 1)}", LogType.Debug, true); #endif - return (Model?)JsonSerializer.Deserialize(byteStr.Slice(0, byteStr.Length - 1), typeof(Model), ModelContext.Default) ?? new Model(); + return (Model?)JsonSerializer.Deserialize(byteStr.Slice(0, byteStr.Length - 1), typeof(Model), StarRailSettingsJSONContext.Default) ?? new Model(); } } catch (Exception ex) @@ -162,7 +168,7 @@ public void Save() { if (RegistryRoot == null) throw new NullReferenceException($"Cannot save {_ValueName} since RegistryKey is unexpectedly not initialized!"); - string data = JsonSerializer.Serialize(this, typeof(Model), ModelContext.Default) + '\0'; + string data = JsonSerializer.Serialize(this, typeof(Model), StarRailSettingsJSONContext.Default) + '\0'; byte[] dataByte = Encoding.UTF8.GetBytes(data); RegistryRoot.SetValue(_ValueName, dataByte, RegistryValueKind.Binary); #if DEBUG @@ -174,24 +180,8 @@ public void Save() LogWriteLine($"Failed to save {_ValueName}!\r\n{ex}", LogType.Error, true); } } - public bool Equals(Model? comparedTo) - { - if (ReferenceEquals(this, comparedTo)) return true; - if (comparedTo == null) return false; - - return comparedTo.AAMode == this.AAMode && - comparedTo.ShadowQuality == this.ShadowQuality && - comparedTo.LightQuality == this.LightQuality && - comparedTo.CharacterQuality == this.CharacterQuality && - comparedTo.BloomQuality == this.BloomQuality && - comparedTo.EnvDetailQuality == this.EnvDetailQuality && - comparedTo.ReflectionQuality == this.ReflectionQuality && - comparedTo.FPS == this.FPS && - comparedTo.EnableVSync == this.EnableVSync && - comparedTo.RenderScale == this.RenderScale && - comparedTo.ResolutionQuality == this.ResolutionQuality; -#nullable disable - } + + public bool Equals(Model? comparedTo) => TypeExtensions.IsInstancePropertyEqual(this, comparedTo); #endregion } } \ No newline at end of file diff --git a/CollapseLauncher/Classes/GameManagement/GameSettings/StarRail/RegistryClass/PCResolution.cs b/CollapseLauncher/Classes/GameManagement/GameSettings/StarRail/RegistryClass/PCResolution.cs index e13e75337..0b5c1ca91 100644 --- a/CollapseLauncher/Classes/GameManagement/GameSettings/StarRail/RegistryClass/PCResolution.cs +++ b/CollapseLauncher/Classes/GameManagement/GameSettings/StarRail/RegistryClass/PCResolution.cs @@ -9,9 +9,8 @@ using System.Text; using System.Text.Json; using System.Text.Json.Serialization; -using static CollapseLauncher.GameSettings.Statics; +using static CollapseLauncher.GameSettings.Base.SettingsBase; using static Hi3Helper.Logger; -using static System.Runtime.InteropServices.JavaScript.JSType; namespace CollapseLauncher.GameSettings.StarRail { @@ -106,7 +105,7 @@ public static PCResolution Load() #if DEBUG LogWriteLine($"Loaded StarRail Settings: {_ValueName}\r\n{Encoding.UTF8.GetString((byte[])value, 0, ((byte[])value).Length - 1)}", LogType.Debug, true); #endif - return (PCResolution?)JsonSerializer.Deserialize(byteStr.Slice(0, byteStr.Length - 1), typeof(PCResolution), PCResolutionContext.Default) ?? new PCResolution(); + return (PCResolution?)JsonSerializer.Deserialize(byteStr.Slice(0, byteStr.Length - 1), typeof(PCResolution), StarRailSettingsJSONContext.Default) ?? new PCResolution(); } } catch (Exception ex) @@ -123,7 +122,7 @@ public override void Save() { if (RegistryRoot == null) throw new NullReferenceException($"Cannot save {_ValueName} since RegistryKey is unexpectedly not initialized!"); - string data = JsonSerializer.Serialize(this, typeof(PCResolution), PCResolutionContext.Default) + '\0'; + string data = JsonSerializer.Serialize(this, typeof(PCResolution), StarRailSettingsJSONContext.Default) + '\0'; byte[] dataByte = Encoding.UTF8.GetBytes(data); RegistryRoot.SetValue(_ValueName, dataByte, RegistryValueKind.Binary); @@ -144,23 +143,13 @@ private void SaveIndividualRegistry() RegistryRoot?.SetValue(_ValueNameScreenManagerWidth, width, RegistryValueKind.DWord); RegistryRoot?.SetValue(_ValueNameScreenManagerHeight, height, RegistryValueKind.DWord); #if DEBUG - LogWriteLine($"Saved StarRail Settings: {_ValueNameScreenManagerFullscreen} : {RegistryRoot.GetValue(_ValueNameScreenManagerFullscreen, null)}", LogType.Debug, true); - LogWriteLine($"Saved StarRail Settings: {_ValueNameScreenManagerWidth} : {RegistryRoot.GetValue(_ValueNameScreenManagerWidth, null)}", LogType.Debug, true); - LogWriteLine($"Saved StarRail Settings: {_ValueNameScreenManagerHeight} : {RegistryRoot.GetValue(_ValueNameScreenManagerHeight, null)}", LogType.Debug, true); + LogWriteLine($"Saved StarRail Settings: {_ValueNameScreenManagerFullscreen} : {RegistryRoot?.GetValue(_ValueNameScreenManagerFullscreen, null)}", LogType.Debug, true); + LogWriteLine($"Saved StarRail Settings: {_ValueNameScreenManagerWidth} : {RegistryRoot?.GetValue(_ValueNameScreenManagerWidth, null)}", LogType.Debug, true); + LogWriteLine($"Saved StarRail Settings: {_ValueNameScreenManagerHeight} : {RegistryRoot?.GetValue(_ValueNameScreenManagerHeight, null)}", LogType.Debug, true); #endif } - public bool Equals(PCResolution? comparedTo) - { - if (ReferenceEquals(this, comparedTo)) return true; - if (comparedTo == null) return false; - - return comparedTo.sizeRes == this.sizeRes && - comparedTo.height == this.height && - comparedTo.width == this.width && - comparedTo.isfullScreen == this.isfullScreen; - } -#nullable disable + public bool Equals(PCResolution? comparedTo) => TypeExtensions.IsInstancePropertyEqual(this, comparedTo); #endregion } } \ No newline at end of file diff --git a/CollapseLauncher/Classes/GameManagement/GameSettings/StarRail/RegistryClass/SFXVolume.cs b/CollapseLauncher/Classes/GameManagement/GameSettings/StarRail/RegistryClass/SFXVolume.cs index 88ad24acd..a7ec102c7 100644 --- a/CollapseLauncher/Classes/GameManagement/GameSettings/StarRail/RegistryClass/SFXVolume.cs +++ b/CollapseLauncher/Classes/GameManagement/GameSettings/StarRail/RegistryClass/SFXVolume.cs @@ -2,7 +2,7 @@ using Hi3Helper; using Microsoft.Win32; using System; -using static CollapseLauncher.GameSettings.Statics; +using static CollapseLauncher.GameSettings.Base.SettingsBase; using static Hi3Helper.Logger; namespace CollapseLauncher.GameSettings.StarRail @@ -65,14 +65,7 @@ public void Save() } - public bool Equals(SFXVolume? comparedTo) - { - if (ReferenceEquals(this, comparedTo)) return true; - if (comparedTo == null) return false; - - return comparedTo.SFXVol == this.SFXVol; - } -#nullable disable + public bool Equals(SFXVolume? comparedTo) => TypeExtensions.IsInstancePropertyEqual(this, comparedTo); #endregion } } diff --git a/CollapseLauncher/Classes/GameManagement/GameSettings/StarRail/RegistryClass/VOVolume.cs b/CollapseLauncher/Classes/GameManagement/GameSettings/StarRail/RegistryClass/VOVolume.cs index ae446e68c..1fdf96a0e 100644 --- a/CollapseLauncher/Classes/GameManagement/GameSettings/StarRail/RegistryClass/VOVolume.cs +++ b/CollapseLauncher/Classes/GameManagement/GameSettings/StarRail/RegistryClass/VOVolume.cs @@ -2,7 +2,7 @@ using Hi3Helper; using Microsoft.Win32; using System; -using static CollapseLauncher.GameSettings.Statics; +using static CollapseLauncher.GameSettings.Base.SettingsBase; using static Hi3Helper.Logger; namespace CollapseLauncher.GameSettings.StarRail @@ -65,14 +65,7 @@ public void Save() } - public bool Equals(VOVolume? comparedTo) - { - if (ReferenceEquals(this, comparedTo)) return true; - if (comparedTo == null) return false; - - return comparedTo.VOVol == this.VOVol; - } -#nullable disable + public bool Equals(VOVolume? comparedTo) => TypeExtensions.IsInstancePropertyEqual(this, comparedTo); #endregion } } diff --git a/CollapseLauncher/Classes/GameManagement/GameSettings/StarRail/Settings.cs b/CollapseLauncher/Classes/GameManagement/GameSettings/StarRail/Settings.cs index 7101a80ee..111947f86 100644 --- a/CollapseLauncher/Classes/GameManagement/GameSettings/StarRail/Settings.cs +++ b/CollapseLauncher/Classes/GameManagement/GameSettings/StarRail/Settings.cs @@ -1,14 +1,12 @@ using CollapseLauncher.GameSettings.Base; using CollapseLauncher.GameSettings.Universal; using CollapseLauncher.Interfaces; -using CollapseLauncher.Statics; using Microsoft.Win32; using System.IO; -using static CollapseLauncher.GameSettings.Statics; namespace CollapseLauncher.GameSettings.StarRail { - internal class StarRailSettings : ImportExportBase, IGameSettings, IGameSettingsUniversal + internal class StarRailSettings : SettingsBase, IGameSettings, IGameSettingsUniversal { public CustomArgs SettingsCustomArgument { get; set; } public BaseScreenSettingData SettingsScreen { get; set; } @@ -18,13 +16,14 @@ internal class StarRailSettings : ImportExportBase, IGameSettings, IGameSettings public MasterVolume AudioSettings_Master { get; set; } public SFXVolume AudioSettings_SFX { get; set; } public VOVolume AudioSettings_VO { get; set; } - public LocalAudioLanguage AudioLanguage { get; set; } + public LocalAudioLanguage AudioLanguage { get; set; } public LocalTextLanguage TextLanguage { get; set; } - public StarRailSettings() + public StarRailSettings(IGameVersionCheck GameVersionManager) + : base(GameVersionManager) { // Init Root Registry Key - RegistryPath = Path.Combine(RegistryRootPath, PageStatics._GameVersion.GamePreset.InternalGameNameInConfig); + RegistryPath = Path.Combine($"Software\\{_gameVersionManager.VendorTypeProp.VendorType}", _gameVersionManager.GamePreset.InternalGameNameInConfig); RegistryRoot = Registry.CurrentUser.OpenSubKey(RegistryPath, true); // If the Root Registry Key is null (not exist), then create a new one. diff --git a/CollapseLauncher/Classes/GameManagement/GameSettings/Statics.cs b/CollapseLauncher/Classes/GameManagement/GameSettings/Statics.cs deleted file mode 100644 index 28005eed4..000000000 --- a/CollapseLauncher/Classes/GameManagement/GameSettings/Statics.cs +++ /dev/null @@ -1,14 +0,0 @@ -using CollapseLauncher.Statics; -using Microsoft.Win32; - -namespace CollapseLauncher.GameSettings -{ - internal static class Statics - { -#nullable enable - internal static string RegistryRootPath { get => $"Software\\{PageStatics._GameVersion.VendorTypeProp.VendorType}"; } - internal static string? RegistryPath; - internal static RegistryKey? RegistryRoot; -#nullable disable - } -} diff --git a/CollapseLauncher/Classes/GameManagement/GameSettings/Universal/Context.cs b/CollapseLauncher/Classes/GameManagement/GameSettings/Universal/Context.cs index 2e1f7c6cd..339f907bd 100644 --- a/CollapseLauncher/Classes/GameManagement/GameSettings/Universal/Context.cs +++ b/CollapseLauncher/Classes/GameManagement/GameSettings/Universal/Context.cs @@ -4,5 +4,5 @@ namespace CollapseLauncher.GameSettings.Universal { [JsonSourceGenerationOptions(IncludeFields = false, GenerationMode = JsonSourceGenerationMode.Metadata, IgnoreReadOnlyFields = true)] [JsonSerializable(typeof(CollapseScreenSetting))] - internal sealed partial class CollapseScreenSettingContext : JsonSerializerContext { } + internal sealed partial class UniversalSettingsJSONContext : JsonSerializerContext { } } diff --git a/CollapseLauncher/Classes/GameManagement/GameSettings/Universal/RegistryClass/CollapseScreenSetting.cs b/CollapseLauncher/Classes/GameManagement/GameSettings/Universal/RegistryClass/CollapseScreenSetting.cs index 684b94869..3d0cabee1 100644 --- a/CollapseLauncher/Classes/GameManagement/GameSettings/Universal/RegistryClass/CollapseScreenSetting.cs +++ b/CollapseLauncher/Classes/GameManagement/GameSettings/Universal/RegistryClass/CollapseScreenSetting.cs @@ -4,7 +4,7 @@ using System; using System.Text; using System.Text.Json; -using static CollapseLauncher.GameSettings.Statics; +using static CollapseLauncher.GameSettings.Base.SettingsBase; using static Hi3Helper.Logger; namespace CollapseLauncher.GameSettings.Universal @@ -17,17 +17,23 @@ internal class CollapseScreenSetting : IGameSettingsValue #region Properties /// - /// This defines if the game will be running in a custom resolution.

+ /// This defines if the game should run in a custom resolution.

/// Default: false ///
public bool UseCustomResolution { get; set; } = false; /// - /// This defines if the game will be running in Exclusive Fullscreen mode.

+ /// This defines if the game should run in Exclusive Fullscreen mode.

/// Default: false ///
public bool UseExclusiveFullscreen { get; set; } = false; + /// + /// This defines if the game should run in Borderless Screen mode.

+ /// Default: false + ///
+ public bool UseBorderlessScreen { get; set; } = false; + /// /// This defines the Graphics API will be used for the game to run.

/// Values:
@@ -57,7 +63,7 @@ public static CollapseScreenSetting Load() #if DEBUG LogWriteLine($"Loaded Collapse Screen Settings:\r\n{Encoding.UTF8.GetString((byte[])value, 0, ((byte[])value).Length - 1)}", LogType.Debug, true); #endif - return (CollapseScreenSetting?)JsonSerializer.Deserialize(byteStr.Slice(0, byteStr.Length - 1), typeof(CollapseScreenSetting), CollapseScreenSettingContext.Default) ?? new CollapseScreenSetting(); + return (CollapseScreenSetting?)JsonSerializer.Deserialize(byteStr.Slice(0, byteStr.Length - 1), typeof(CollapseScreenSetting), UniversalSettingsJSONContext.Default) ?? new CollapseScreenSetting(); } } catch (Exception ex) @@ -74,7 +80,7 @@ public void Save() { if (RegistryRoot == null) throw new NullReferenceException($"Cannot save {_ValueName} since RegistryKey is unexpectedly not initialized!"); - string data = JsonSerializer.Serialize(this, typeof(CollapseScreenSetting), CollapseScreenSettingContext.Default) + '\0'; + string data = JsonSerializer.Serialize(this, typeof(CollapseScreenSetting), UniversalSettingsJSONContext.Default) + '\0'; byte[] dataByte = Encoding.UTF8.GetBytes(data); #if DEBUG LogWriteLine($"Saved Collapse Screen Settings:\r\n{data}", LogType.Debug, true); diff --git a/CollapseLauncher/Classes/GameManagement/GameSettings/Universal/RegistryClass/CustomArgs.cs b/CollapseLauncher/Classes/GameManagement/GameSettings/Universal/RegistryClass/CustomArgs.cs index 310efd6c0..1381ac911 100644 --- a/CollapseLauncher/Classes/GameManagement/GameSettings/Universal/RegistryClass/CustomArgs.cs +++ b/CollapseLauncher/Classes/GameManagement/GameSettings/Universal/RegistryClass/CustomArgs.cs @@ -1,8 +1,8 @@ -using CollapseLauncher.Interfaces; +using CollapseLauncher.GameSettings.Base; +using CollapseLauncher.Interfaces; using Hi3Helper; using Microsoft.Win32; using System; -using static CollapseLauncher.GameSettings.Statics; using static Hi3Helper.Logger; namespace CollapseLauncher.GameSettings.Universal @@ -35,11 +35,11 @@ public static CustomArgs Load() { try { - if (RegistryRoot == null) throw new NullReferenceException($"Cannot load {_ValueName} RegistryKey is unexpectedly not initialized!"); + if (SettingsBase.RegistryRoot == null) throw new NullReferenceException($"Cannot load {_ValueName} RegistryKey is unexpectedly not initialized!"); #if DEBUG - LogWriteLine($"Loaded Collapse Custom Argument Settings:\r\n{(string?)RegistryRoot.GetValue(_ValueName, null) ?? ""}", LogType.Debug, true); + LogWriteLine($"Loaded Collapse Custom Argument Settings:\r\n{(string?)SettingsBase.RegistryRoot.GetValue(_ValueName, null) ?? ""}", LogType.Debug, true); #endif - return new CustomArgs { CustomArgumentValue = (string?)RegistryRoot.GetValue(_ValueName, null) ?? "" }; + return new CustomArgs { CustomArgumentValue = (string?)SettingsBase.RegistryRoot.GetValue(_ValueName, null) ?? "" }; } catch (Exception ex) { @@ -52,11 +52,11 @@ public void Save() { try { - if (RegistryRoot == null) throw new NullReferenceException($"Cannot save {_ValueName} since RegistryKey is unexpectedly not initialized!"); + if (SettingsBase.RegistryRoot == null) throw new NullReferenceException($"Cannot save {_ValueName} since RegistryKey is unexpectedly not initialized!"); #if DEBUG LogWriteLine($"Saved Collapse Custom Argument Settings:\r\n{CustomArgumentValue}", LogType.Debug, true); #endif - RegistryRoot.SetValue(_ValueName, CustomArgumentValue, RegistryValueKind.String); + SettingsBase.RegistryRoot.SetValue(_ValueName, CustomArgumentValue, RegistryValueKind.String); } catch (Exception ex) { diff --git a/CollapseLauncher/Classes/GameManagement/GameVersion/BaseClass/GameVersionBase.cs b/CollapseLauncher/Classes/GameManagement/GameVersion/BaseClass/GameVersionBase.cs index e1fd6a84a..df4e2f875 100644 --- a/CollapseLauncher/Classes/GameManagement/GameVersion/BaseClass/GameVersionBase.cs +++ b/CollapseLauncher/Classes/GameManagement/GameVersion/BaseClass/GameVersionBase.cs @@ -217,7 +217,6 @@ public virtual bool IsGameInstalled() // Check if the executable file exist and has the size at least > 2 MiB. If not, then return as false. FileInfo execFileInfo = new FileInfo(Path.Combine(GameDirPath, GamePreset.GameExecutableName)); - if (execFileInfo.Exists) return execFileInfo.Length > 1 << 16; // Check if the vendor type exist. If not, then return false if (VendorTypeProp.GameName == null || !VendorTypeProp.VendorType.HasValue) return false; @@ -300,7 +299,7 @@ private GameVersion TryGetNextVersionFromPkgFileName(RegionResourceVersion pkgVe // Set the offset of the section. If the length > 2, then set 1 // Otherwise, set 2; - int offset = pkgSections.Length > 2 ? 2 : 1; + int offset = pkgSections.Length > 2 ? 1 : 2; // Try get the version string, lower it and trim it string versionStr = pkgSections[offset].ToLower().Trim('v'); diff --git a/CollapseLauncher/Classes/GameManagement/GameVersion/Genshin/VersionCheck.cs b/CollapseLauncher/Classes/GameManagement/GameVersion/Genshin/VersionCheck.cs index d13348a1f..7a3d94770 100644 --- a/CollapseLauncher/Classes/GameManagement/GameVersion/Genshin/VersionCheck.cs +++ b/CollapseLauncher/Classes/GameManagement/GameVersion/Genshin/VersionCheck.cs @@ -3,7 +3,6 @@ using Hi3Helper.Shared.ClassStruct; using Microsoft.UI.Xaml; using System.Collections.Generic; -using System.Linq; namespace CollapseLauncher.GameVersioning { diff --git a/CollapseLauncher/Classes/InstallManagement/BaseClass/GameInstallPackage.cs b/CollapseLauncher/Classes/InstallManagement/BaseClass/GameInstallPackage.cs index eded01dba..3095ab5b3 100644 --- a/CollapseLauncher/Classes/InstallManagement/BaseClass/GameInstallPackage.cs +++ b/CollapseLauncher/Classes/InstallManagement/BaseClass/GameInstallPackage.cs @@ -70,11 +70,35 @@ public GameInstallPackage(RegionResourceVersion packageProperty, string pathOutp } } + public bool IsReadStreamExist(int count) + { + // Check if the single file exist or not + FileInfo fileInfo = new FileInfo(PathOutput); + if (fileInfo.Exists) + return true; + + // Check for the chunk files + return Enumerable.Range(0, count).All(chunkID => + { + // Get the hash number + long ID = Http.GetHashNumber(count, chunkID); + // Append the hash number to the path + string path = $"{PathOutput}.{ID}"; + // Get the file info + FileInfo fileInfo = new FileInfo(path); + // Check if the file exist + return fileInfo.Exists; + }); + } + public Stream GetReadStream(int count) { + // Get the file info of the single file FileInfo fileInfo = new FileInfo(PathOutput); + // Check if the file exist and the length is equal to the size if (fileInfo.Exists && fileInfo.Length == Size) { + // Return the stream for read return fileInfo.Open(new FileStreamOptions { Access = FileAccess.Read, @@ -85,6 +109,7 @@ public Stream GetReadStream(int count) }); } + // If the single file doesn't exist, then try getting chunk stream return GetCombinedStreamFromPackageAsset(count); } @@ -119,14 +144,20 @@ public void DeleteFile(int count) private CombinedStream GetCombinedStreamFromPackageAsset(int count) { + // Set the array FileStream[] streamList = new FileStream[count]; + // Enumerate the ID for (int i = 0; i < streamList.Length; i++) { + // Get the hash ID long ID = Http.GetHashNumber(count, i); + // Append hash ID to the path string path = $"{PathOutput}.{ID}"; + // Get the file info and check if the file exist FileInfo fileInfo = new FileInfo(path); if (fileInfo.Exists) { + // Allocate to the array and open the stream streamList[i] = fileInfo.Open(new FileStreamOptions { Access = FileAccess.Read, @@ -135,12 +166,15 @@ private CombinedStream GetCombinedStreamFromPackageAsset(int count) Options = FileOptions.None, Share = FileShare.Read }); + // Then go back to the loop routine continue; } + // If not found, then throw throw new FileNotFoundException($"File chunk doesn't exist in this path! -> {path}"); } + // Assign the array and initiate it as a combined stream return new CombinedStream(streamList); } diff --git a/CollapseLauncher/Classes/InstallManagement/BaseClass/InstallManagerBase.cs b/CollapseLauncher/Classes/InstallManagement/BaseClass/InstallManagerBase.cs index f2a68b4a0..8d274db71 100644 --- a/CollapseLauncher/Classes/InstallManagement/BaseClass/InstallManagerBase.cs +++ b/CollapseLauncher/Classes/InstallManagement/BaseClass/InstallManagerBase.cs @@ -1,4 +1,4 @@ -using CollapseLauncher.Interfaces; +using CollapseLauncher.Interfaces; using CollapseLauncher.Statics; using Hi3Helper; using Hi3Helper.Data; @@ -33,7 +33,6 @@ internal class InstallManagerBase : ProgressBase (T)PageStatics._GameVersion; } protected RegionResourceGame _gameRegion { get => _gameVersionManager.GameAPIProp.data; } protected GameVersion _gameLatestVersion { get => _gameVersionManager.GetGameVersionAPI(); } protected GameVersion? _gameLatestPreloadVersion { get => _gameVersionManager.GetGameVersionAPIPreload(); } @@ -46,6 +45,7 @@ internal class InstallManagerBase : ProgressBase !File.Exists(Path.Combine(_gamePath, "@NoDeleteZip")); } protected bool _canSkipVerif { get => File.Exists(Path.Combine(_gamePath, "@NoVerification")); } protected bool _canSkipExtract { get => File.Exists(Path.Combine(_gamePath, "@NoExtraction")); } + protected bool _canMergeDownloadChunks { get => LauncherConfig.GetAppConfigValue("UseDownloadChunksMerging").ToBool(); } protected virtual bool _canDeltaPatch { get => false; } protected virtual DeltaPatchProperty _gameDeltaPatchProperty { get => null; } @@ -53,14 +53,17 @@ internal class InstallManagerBase : ProgressBase Dispose(); @@ -72,6 +75,7 @@ public void Dispose() _httpClient?.Dispose(); _gameRepairTool?.Dispose(); _token?.Cancel(); + IsRunning = false; Flush(); } @@ -79,6 +83,7 @@ public virtual void Flush() { _gameRepairTool?.Dispose(); _assetIndex.Clear(); + UpdateCompletenessStatus(CompletenessStatus.Idle); } #region Public Methods @@ -107,48 +112,59 @@ public virtual async ValueTask GetInstallationPath() public virtual async Task StartPackageDownload(bool skipDialog) { + UpdateCompletenessStatus(CompletenessStatus.Running); ResetToken(); // Get the game state and run the action for each of them GameInstallStateEnum gameState = _gameVersionManager.GetGameState(); LogWriteLine($"Gathering packages information for installation (State: {gameState})...", LogType.Default, true); - switch (gameState) + try { - case GameInstallStateEnum.NotInstalled: - case GameInstallStateEnum.GameBroken: - case GameInstallStateEnum.NeedsUpdate: - await GetLatestPackageList(_assetIndex, gameState, false); - break; - case GameInstallStateEnum.InstalledHavePreload: - await GetLatestPackageList(_assetIndex, gameState, true); - break; - } + switch (gameState) + { + case GameInstallStateEnum.NotInstalled: + case GameInstallStateEnum.GameBroken: + case GameInstallStateEnum.NeedsUpdate: + await GetLatestPackageList(_assetIndex, gameState, false); + break; + case GameInstallStateEnum.InstalledHavePreload: + await GetLatestPackageList(_assetIndex, gameState, true); + break; + } - // Set the progress bar to indetermined - _status.IsIncludePerFileIndicator = _assetIndex.Sum(x => x.Segments != null ? x.Segments.Count : 1) > 1; - _status.IsProgressPerFileIndetermined = true; - _status.IsProgressTotalIndetermined = true; - UpdateStatus(); + // Set the progress bar to indetermined + _status.IsIncludePerFileIndicator = _assetIndex.Sum(x => x.Segments != null ? x.Segments.Count : 1) > 1; + _status.IsProgressPerFileIndetermined = true; + _status.IsProgressTotalIndetermined = true; + UpdateStatus(); - // Start getting the size of the packages - await GetPackagesRemoteSize(_assetIndex, _token.Token); + // Start getting the size of the packages + await GetPackagesRemoteSize(_assetIndex, _token.Token); + + // Get the remote total size and current total size + _progressTotalSize = _assetIndex.Sum(x => x.Size); + _progressTotalSizeCurrent = GetExistingDownloadPackageSize(_assetIndex); - // Get the remote total size and current total size - _progressTotalSize = _assetIndex.Sum(x => x.Size); - _progressTotalSizeCurrent = GetExistingDownloadPackageSize(_assetIndex); + // Sanitize Check: Check for the free space of the drive and show the dialog if necessary + await CheckDriveFreeSpace(_parentUI, _assetIndex); + + // Sanitize Check: Show dialog for resuming/reset the existing download + if (!skipDialog) + { + await CheckExistingDownloadAsync(_parentUI, _assetIndex); + } - // Sanitize Check: Check for the free space of the drive and show the dialog if necessary - await CheckDriveFreeSpace(_parentUI, _assetIndex); + // Start downloading process + await InvokePackageDownloadRoutine(_assetIndex, _token.Token); - // Sanitize Check: Show dialog for resuming/reset the existing download - if (!skipDialog) + UpdateCompletenessStatus(CompletenessStatus.Completed); + } + catch { - await CheckExistingDownloadAsync(_parentUI, _assetIndex); + UpdateCompletenessStatus(CompletenessStatus.Cancelled); + throw; } - - // Start downloading process - await InvokePackageDownloadRoutine(_assetIndex, _token.Token); } // Bool: 0 -> Indicates that one of the package is failing and need to redownload @@ -157,54 +173,65 @@ public virtual async Task StartPackageDownload(bool skipDialog) // -1 -> Cancel the operation public virtual async ValueTask StartPackageVerification() { - // Get the total asset count - int assetCount = _assetIndex.Sum(x => x.Segments != null ? x.Segments.Count : 1); - - // If the assetIndex is empty, then skip and return 0 - if (assetCount == 0) + try { - return 0; - } + UpdateCompletenessStatus(CompletenessStatus.Running); - // If _canSkipVerif flag is true, then return 1 (skip) the verification; - if (_canSkipVerif) return 1; + // Get the total asset count + int assetCount = _assetIndex.Sum(x => x.Segments != null ? x.Segments.Count : 1); - // Set progress count to beginning - _progressTotalSize = _assetIndex.Sum(x => x.Size); - _progressTotalSizeCurrent = 0; - _progressTotalCountCurrent = 1; - _progressTotalCount = assetCount; - _status.IsIncludePerFileIndicator = assetCount > 1; - RestartStopwatch(); + // If the assetIndex is empty, then skip and return 0 + if (assetCount == 0) + { + return 0; + } - // Set progress bar to not indetermined - _status.IsProgressPerFileIndetermined = false; - _status.IsProgressTotalIndetermined = false; + // If _canSkipVerif flag is true, then return 1 (skip) the verification; + if (_canSkipVerif) return 1; - // Iterate the asset - foreach (GameInstallPackage asset in _assetIndex) - { - int returnCode = 0; + // Set progress count to beginning + _progressTotalSize = _assetIndex.Sum(x => x.Size); + _progressTotalSizeCurrent = 0; + _progressTotalCountCurrent = 1; + _progressTotalCount = assetCount; + _status.IsIncludePerFileIndicator = assetCount > 1; + RestartStopwatch(); - // Iterate if the package has segment - if (asset.Segments != null) + // Set progress bar to not indetermined + _status.IsProgressPerFileIndetermined = false; + _status.IsProgressTotalIndetermined = false; + + // Iterate the asset + foreach (GameInstallPackage asset in _assetIndex) { - for (int i = 0; i < asset.Segments.Count; i++) + int returnCode = 0; + + // Iterate if the package has segment + if (asset.Segments != null) { - // Run the package verification routine - if ((returnCode = await RunPackageVerificationRoutine(asset.Segments[i], _token.Token)) < 1) + for (int i = 0; i < asset.Segments.Count; i++) { - return returnCode; + // Run the package verification routine + if ((returnCode = await RunPackageVerificationRoutine(asset.Segments[i], _token.Token)) < 1) + { + return returnCode; + } } + continue; } - continue; - } - // Run the package verification routine as a single package - if ((returnCode = await RunPackageVerificationRoutine(asset, _token.Token)) < 1) - { - return returnCode; + // Run the package verification routine as a single package + if ((returnCode = await RunPackageVerificationRoutine(asset, _token.Token)) < 1) + { + return returnCode; + } } + UpdateCompletenessStatus(CompletenessStatus.Completed); + } + catch + { + UpdateCompletenessStatus(CompletenessStatus.Cancelled); + throw; } return 1; @@ -277,92 +304,110 @@ private void DeleteSingleOrSegmentedDownloadStream(GameInstallPackage asset) asset.DeleteFile(_downloadThreadCount); } - public virtual async Task StartPackageInstallation() => await Task.Run(StartPackageInstallationInner, _token.Token); - - public void StartPackageInstallationInner() + public async Task StartPackageInstallation() { - // Sanity Check: Check if the package list is empty or not - if (_assetIndex.Count == 0) throw new InvalidOperationException("Package list is empty. Make sure you have ran StartPackageDownload() first."); - - // If _canSkipExtract flag is true, then return (skip) the extraction - if (_canSkipExtract) return; + try + { + UpdateCompletenessStatus(CompletenessStatus.Running); - // Start Async Thread - // Since the SevenZipTool (especially with the callbacks) can't run under - // different thread, so the async call will be called at the start + await StartPackageInstallationInner(); - // Initialize the zip tool - using (SevenZipTool zip = new SevenZipTool()) + UpdateCompletenessStatus(CompletenessStatus.Completed); + } + catch { - // Get the sum of uncompressed size and - // Set progress count to beginning - _progressTotalSize = GetAssetIndexTotalUncompressSize(zip, _assetIndex); + UpdateCompletenessStatus(CompletenessStatus.Cancelled); + throw; + } + } - _progressTotalSizeCurrent = 0; - _progressTotalCountCurrent = 1; - _progressTotalCount = _assetIndex.Count; - _status.IsIncludePerFileIndicator = _assetIndex.Count > 1; - RestartStopwatch(); + protected virtual async Task StartPackageInstallationInner() + { + await Task.Run(() => + { + // Sanity Check: Check if the package list is empty or not + if (_assetIndex.Count == 0) throw new InvalidOperationException("Package list is empty. Make sure you have ran StartPackageDownload() first."); - // Reset the last size counter - _totalLastSizeCurrent = 0; + // If _canSkipExtract flag is true, then return (skip) the extraction + if (_canSkipExtract) return; - // Try unassign read-only and redundant diff files - TryUnassignReadOnlyFiles(); - TryRemoveRedundantHDiffList(); + // Start Async Thread + // Since the SevenZipTool (especially with the callbacks) can't run under + // different thread, so the async call will be called at the start - foreach (GameInstallPackage asset in _assetIndex) + // Initialize the zip tool + using (SevenZipTool zip = new SevenZipTool()) { - // Update the status - _status.ActivityStatus = string.Format("{0}: {1}", Lang._Misc.Extracting, string.Format(Lang._Misc.PerFromTo, _progressTotalCountCurrent, _progressTotalCount)); - _status.IsProgressPerFileIndetermined = false; - _status.IsProgressTotalIndetermined = false; - UpdateStatus(); + // Get the sum of uncompressed size and + // Set progress count to beginning + _progressTotalSize = GetAssetIndexTotalUncompressSize(zip, _assetIndex); - try - { - // Load the zip - zip.LoadArchive(GetSingleOrSegmentedDownloadStream(asset)); + _progressTotalSizeCurrent = 0; + _progressTotalCountCurrent = 1; + _progressTotalCount = _assetIndex.Count; + _status.IsIncludePerFileIndicator = _assetIndex.Count > 1; + RestartStopwatch(); - // Start extraction - zip.ExtractProgressChanged += ZipProgressAdapter; - zip.ExtractToDirectory(_gamePath, _threadCount, _token.Token); + // Reset the last size counter + _totalLastSizeCurrent = 0; - // Get the information about diff and delete list file - FileInfo hdiffList = new FileInfo(Path.Combine(_gamePath, "hdifffiles.txt")); - FileInfo deleteList = new FileInfo(Path.Combine(_gamePath, "deletefiles.txt")); + // Try unassign read-only and redundant diff files + TryUnassignReadOnlyFiles(); + TryRemoveRedundantHDiffList(); - // If diff list file exist, then rename the file - if (hdiffList.Exists) - { - hdiffList.MoveTo(Path.Combine(_gamePath, $"hdifffiles_{Path.GetFileNameWithoutExtension(asset.PathOutput)}.txt"), true); - } + foreach (GameInstallPackage asset in _assetIndex) + { + // Update the status + _status.ActivityStatus = string.Format("{0}: {1}", Lang._Misc.Extracting, string.Format(Lang._Misc.PerFromTo, _progressTotalCountCurrent, _progressTotalCount)); + _status.IsProgressPerFileIndetermined = false; + _status.IsProgressTotalIndetermined = false; + UpdateStatus(); - // If the delete zip file exist, then rename the file - if (deleteList.Exists) + try { - deleteList.MoveTo(Path.Combine(_gamePath, $"deletefiles_{Path.GetFileNameWithoutExtension(asset.PathOutput)}.txt"), true); - } + // Load the zip + zip.LoadArchive(GetSingleOrSegmentedDownloadStream(asset)); + + // Start extraction + zip.ExtractProgressChanged += ZipProgressAdapter; + zip.ExtractToDirectory(_gamePath, _threadCount, _token.Token); + + // Get the information about diff and delete list file + FileInfo hdiffList = new FileInfo(Path.Combine(_gamePath, "hdifffiles.txt")); + FileInfo deleteList = new FileInfo(Path.Combine(_gamePath, "deletefiles.txt")); + + // If diff list file exist, then rename the file + if (hdiffList.Exists) + { + hdiffList.MoveTo(Path.Combine(_gamePath, $"hdifffiles_{Path.GetFileNameWithoutExtension(asset.PathOutput)}.txt"), true); + } + + // If the delete zip file exist, then rename the file + if (deleteList.Exists) + { + deleteList.MoveTo(Path.Combine(_gamePath, $"deletefiles_{Path.GetFileNameWithoutExtension(asset.PathOutput)}.txt"), true); + } - // Make sure that the ZipTool is getting disposed first - zip?.Dispose(); + // Make sure that the ZipTool is getting disposed first + zip?.Dispose(); - // If the _canDeleteZip flag is true, then delete the zip - if (_canDeleteZip) + // If the _canDeleteZip flag is true, then delete the zip + if (_canDeleteZip) + { + DeleteSingleOrSegmentedDownloadStream(asset); + } + } + catch (Exception) { throw; } + finally { - DeleteSingleOrSegmentedDownloadStream(asset); + zip.ExtractProgressChanged -= ZipProgressAdapter; + zip?.Dispose(); } - } - catch (Exception) { throw; } - finally - { - zip.ExtractProgressChanged -= ZipProgressAdapter; - zip?.Dispose(); - } - _progressTotalCountCurrent++; + _progressTotalCountCurrent++; + } } - } + }); } public virtual async Task StartPostInstallVerification() @@ -380,35 +425,52 @@ public virtual void ApplyGameConfig(bool forceUpdateToLatest = false) } - public virtual bool IsPreloadCompleted() + public virtual async ValueTask IsPreloadCompleted() { - GetLatestPackageList(_assetIndex, GameInstallStateEnum.InstalledHavePreload, true).Wait(); - bool resultSlice = false, resultZip=false; - foreach (GameInstallPackage asset in _assetIndex) + // Get the latest package list and await + await GetLatestPackageList(_assetIndex, GameInstallStateEnum.InstalledHavePreload, true); + // Get the total size of the packages + await GetPackagesRemoteSize(_assetIndex, _token.Token); + long totalPackageSize = _assetIndex.Sum(x => x.Size); + + // Get the sum of the total size of the single or segmented packages + return _assetIndex.Sum(asset => { - LogWriteLine(asset.PathOutput); - try + // Check if the package is segmented + if (asset.Segments != null && asset.Segments.Count != 0) { - resultSlice= asset.Segments != null && asset.Segments.Count != 0 ? - asset.Segments.Select(selector: x => x.GetReadStream(_downloadThreadCount)).ToArray().Length>0 : asset.GetReadStream(_downloadThreadCount).Length>0; + // Get the sum of the total size/length for each of its streams + return asset.Segments.Sum(segment => + { + // Check if the read stream exist + if (segment.IsReadStreamExist(_downloadThreadCount)) + { + // Get the stream of the segment and using (and auto dispose) it + using Stream segmentStream = segment.GetReadStream(_downloadThreadCount); + // Return the size/length of the stream + return segmentStream.Length; + } + // If not, then return 0 + return 0; + }); } - catch (Exception ex) + + // If segment is none, check if the single stream exist + if (asset.IsReadStreamExist(_downloadThreadCount)) { - LogWriteLine(ex.ToString(), LogType.Default); - continue; + // If yes, then using single stream + using Stream singleStream = asset.GetReadStream(_downloadThreadCount); + // Return the size of the stream + return singleStream.Length; } - } - resultZip = _gameVersionManager.GetGamePreloadZip().All(x => - { - string name = Path.GetFileName(x.path); - string path = Path.Combine(_gamePath, name); - return File.Exists(path); - }); - if (resultZip) LogWriteLine("Zip Found"); - if (resultSlice) LogWriteLine("Slices found"); - return resultSlice || resultZip; + // If neither of both exist, then return 0 + return 0; + }) == totalPackageSize; // Then compare if the total package size is equal + // Note: + // x.GetReadStream() will check if the single package/zip exist. + // So checking the fully downloaded single package is unnecessary. } public async Task MoveGameLocation() @@ -420,7 +482,7 @@ public async ValueTask UninstallGame() { string GameFolder = ConverterTool.NormalizePath(_gamePath); - switch (await Dialog_UninstallGame(_parentUI, GameFolder, _gamePreset.ZoneFullname)) + switch (await Dialog_UninstallGame(_parentUI, GameFolder, _gameVersionManager.GamePreset.ZoneFullname)) { case ContentDialogResult.Primary: try @@ -431,7 +493,7 @@ public async ValueTask UninstallGame() { LogWriteLine($"Failed while deleting the game folder: {GameFolder}\r\n{ex}", LogType.Error, true); } - PageStatics._GameVersion.Reinitialize(); + _gameVersionManager.Reinitialize(); return true; default: return false; @@ -609,7 +671,7 @@ public virtual List TryGetHDiffList() .Deserialize( listReader.ReadLine(), typeof(PkgVersionProperties), - PkgVersionPropertiesContext.Default); + CoreLibraryJSONContext.Default); string filePath = Path.Combine(_gamePath, prop.remoteName + ".hdiff"); if (File.Exists(filePath)) @@ -691,13 +753,13 @@ private async ValueTask CheckExistingBHI3LInstallation() private async ValueTask CheckExistingOfficialInstallation() { - if (_gamePreset.CheckExistingGame()) + if (_gameVersionManager.GamePreset.CheckExistingGame()) { - switch (await Dialog_ExistingInstallation(_parentUI)) + switch (await Dialog_ExistingInstallation(_parentUI, _gameVersionManager.GamePreset.ActualGameDataLocation)) { // If action to migrate was taken, then update the game path (but don't save it to the config file) case ContentDialogResult.Primary: - _gameVersionManager.UpdateGamePath(_gamePreset.ActualGameDataLocation.Replace('\\', '/'), false); + _gameVersionManager.UpdateGamePath(_gameVersionManager.GamePreset.ActualGameDataLocation.Replace('\\', '/'), false); return 0; // If action to fresh install was taken, then return 2 (selecting path) case ContentDialogResult.Secondary: @@ -715,9 +777,9 @@ private async ValueTask CheckExistingOfficialInstallation() private bool TryGetExistingSteamPath(ref string OutputPath) { // If the game preset doesn't have SteamGameID, then return false - if (_gamePreset.SteamGameID == null) return false; + if (_gameVersionManager.GamePreset.SteamGameID == null) return false; // Assign Steam ID - int steamID = _gamePreset.SteamGameID ?? 0; + int steamID = _gameVersionManager.GamePreset.SteamGameID ?? 0; // Try get the list of Steam Libs and Apps List steamLibsList = SteamTool.GetSteamLibs(); @@ -743,7 +805,7 @@ private bool TryGetExistingBHI3LPath(ref string OutputPath) { #nullable enable // If the preset doesn't have BetterHi3Launcher registry ver info, then return false - if (_gamePreset.BetterHi3LauncherVerInfoReg == null) return false; + if (_gameVersionManager.GamePreset.BetterHi3LauncherVerInfoReg == null) return false; // Try open BHI3L registry key // If the key doesn't exist, then return false @@ -752,7 +814,7 @@ private bool TryGetExistingBHI3LPath(ref string OutputPath) // Try get the key value // If the key also doesn't exist, then return false - byte[]? keyValue = (byte[]?)Key?.GetValue(_gamePreset.BetterHi3LauncherVerInfoReg); + byte[]? keyValue = (byte[]?)Key?.GetValue(_gameVersionManager.GamePreset.BetterHi3LauncherVerInfoReg); if (keyValue == null) return false; BHI3LInfo? config; @@ -761,11 +823,11 @@ private bool TryGetExistingBHI3LPath(ref string OutputPath) { // Try parsing the config value = Encoding.UTF8.GetString(keyValue); - config = (BHI3LInfo?)JsonSerializer.Deserialize(value, typeof(BHI3LInfo), BHI3LInfoContext.Default); + config = (BHI3LInfo?)JsonSerializer.Deserialize(value, typeof(BHI3LInfo), CoreLibraryJSONContext.Default); } catch (Exception ex) { - LogWriteLine($"Registry Value {_gamePreset.BetterHi3LauncherVerInfoReg}:\r\n{value}\r\n\r\nException:\r\n{ex}", LogType.Error, true); + LogWriteLine($"Registry Value {_gameVersionManager.GamePreset.BetterHi3LauncherVerInfoReg}:\r\n{value}\r\n\r\nException:\r\n{ex}", LogType.Error, true); return false; } @@ -773,7 +835,7 @@ private bool TryGetExistingBHI3LPath(ref string OutputPath) if (config != null && config.game_info.installed && !string.IsNullOrEmpty(config.game_info.install_path)) { - FileInfo execPath = new FileInfo(Path.Combine(config.game_info.install_path, _gamePreset.GameExecutableName)); + FileInfo execPath = new FileInfo(Path.Combine(config.game_info.install_path, _gameVersionManager.GamePreset.GameExecutableName)); OutputPath = config.game_info.install_path; return execPath.Exists && execPath.Length > 1 >> 16; } @@ -797,7 +859,7 @@ private async Task AskGameFolderDialog() { // If primary button is clicked, then set folder with the default path case ContentDialogResult.Primary: - folder = Path.Combine(LauncherConfig.AppGameFolder, _gamePreset.ProfileName, _gamePreset.GameDirectoryName); + folder = Path.Combine(LauncherConfig.AppGameFolder, _gameVersionManager.GamePreset.ProfileName, _gameVersionManager.GamePreset.GameDirectoryName); isChoosen = true; break; // If secondary, then show folder picker dialog to choose the folder @@ -965,6 +1027,12 @@ private async ValueTask RunPackageDownloadRoutine(GameInstallPackage package, Ca _status.ActivityStatus = string.Format("{0}: {1}", Lang._Misc.Downloading, string.Format(Lang._Misc.PerFromTo, _progressTotalCountCurrent, _progressTotalCount)); LogWriteLine($"Downloading package URL {_progressTotalCountCurrent}/{_progressTotalCount} ({ConverterTool.SummarizeSizeSimple(package.Size)}): {package.URL}"); + // Get the directory path + string pathDir = Path.GetDirectoryName(package.PathOutput); + + // If the directory doesn't exist, then create one + if (!Directory.Exists(pathDir)) Directory.CreateDirectory(pathDir); + // If the file exist or package size is unmatched, // then start downloading FileInfo packageOutInfo = new FileInfo(package.PathOutput); @@ -975,7 +1043,10 @@ private async ValueTask RunPackageDownloadRoutine(GameInstallPackage package, Ca _status.ActivityStatus = string.Format("{0}: {1}", Lang._Misc.Merging, string.Format(Lang._Misc.PerFromTo, _progressTotalCountCurrent, _progressTotalCount)); UpdateStatus(); _stopwatch.Stop(); - // await _httpClient.Merge(); + if (_canMergeDownloadChunks) + { + await _httpClient.Merge(); + } _stopwatch.Start(); } @@ -1096,6 +1167,12 @@ private async ValueTask CheckDriveFreeSpace(UIElement Content, List packageList, C } #endregion #region Virtual Methods - StartPackageDownload + + private enum CompletenessStatus { Running, Completed, Cancelled, Idle } + private void UpdateCompletenessStatus(CompletenessStatus status) + { + switch (status) + { + case CompletenessStatus.Running: + IsRunning = true; + _status.IsRunning = true; + _status.IsCompleted = false; + _status.IsCanceled = false; + break; + case CompletenessStatus.Completed: + IsRunning = false; + _status.IsRunning = false; + _status.IsCompleted = true; + _status.IsCanceled = false; + break; + case CompletenessStatus.Cancelled: + IsRunning = false; + _status.IsRunning = false; + _status.IsCompleted = false; + _status.IsCanceled = true; + break; + case CompletenessStatus.Idle: + IsRunning = false; + _status.IsRunning = false; + _status.IsCompleted = false; + _status.IsCanceled = false; + break; + } + UpdateStatus(); + } + protected async Task TryGetPackageRemoteSize(GameInstallPackage asset, CancellationToken token) { asset.Size = await _httpClient.TryGetContentLengthAsync(asset.URL, token) ?? 0; @@ -1190,7 +1301,7 @@ private async void ZipProgressAdapter(object sender, ExtractProgress e) // Calculate the timelapse _progress.ProgressTotalTimeLeft = TimeSpan.FromSeconds((_progressTotalSize - _progressTotalSizeCurrent) / ConverterTool.Unzeroed(_progress.ProgressTotalSpeed)); - UpdateProgress(); + UpdateAll(); } } diff --git a/CollapseLauncher/Classes/InstallManagement/GameConversionManagement.cs b/CollapseLauncher/Classes/InstallManagement/GameConversionManagement.cs index 4e05aa44c..ba097071b 100644 --- a/CollapseLauncher/Classes/InstallManagement/GameConversionManagement.cs +++ b/CollapseLauncher/Classes/InstallManagement/GameConversionManagement.cs @@ -3,6 +3,7 @@ using Hi3Helper.Http; using Hi3Helper.Preset; using Hi3Helper.Shared.ClassStruct; +using Hi3Helper.SharpHDiffPatch; using System; using System.Collections.Generic; using System.Diagnostics; @@ -73,7 +74,7 @@ public async Task StartPreparation() ConvertDetail = Lang._InstallConvert.Step2Subtitle; await FallbackCDNUtil.DownloadCDNFallbackContent(_http, buffer, URL, Token); buffer.Position = 0; - SourceFileRemote = (List)JsonSerializer.Deserialize(buffer, typeof(List), L_FilePropertiesRemoteContext.Default); + SourceFileRemote = (List)JsonSerializer.Deserialize(buffer, typeof(List), CoreLibraryJSONContext.Default); } using (MemoryStream buffer = new MemoryStream()) @@ -82,7 +83,7 @@ public async Task StartPreparation() ConvertDetail = Lang._InstallConvert.Step2Subtitle; await FallbackCDNUtil.DownloadCDNFallbackContent(_http, buffer, URL, Token); buffer.Position = 0; - TargetFileRemote = (List)JsonSerializer.Deserialize(buffer, typeof(List), L_FilePropertiesRemoteContext.Default); + TargetFileRemote = (List)JsonSerializer.Deserialize(buffer, typeof(List), CoreLibraryJSONContext.Default); } } finally @@ -159,13 +160,16 @@ private async Task> VerifyIngredients(List { await Task.Run(() => { - LocalHash = Entry.DataType != FileType.Blocks ? - BytesToCRC32Simple(fs) : - CreateMD5Shared(fs); + LocalHash = Entry.CurrCRC.Length > 8 ? + CreateMD5Shared(fs) : + BytesToCRC32Simple(fs); Token.ThrowIfCancellationRequested(); if (LocalHash.ToLower() != Entry.CurrCRC) + { + LogWriteLine($"File {Entry.FileName} has unmatched hash. Local: {LocalHash.ToLower()} Remote: {Entry.CurrCRC}", LogType.Warning, true); BrokenManifest.Add(Entry); + } }, Token); } } @@ -278,10 +282,6 @@ private void FetchIngredientsAPI_Progress(object sender, DownloadEvent e) ConvertStatus, ConvertDetail); } - FileSystemWatcher ConvertFsWatcher; - - long ConvertRead = 0; - long ConvertTotalSize = 0; public async Task StartConversion() { ResetSw(); @@ -294,26 +294,20 @@ public async Task StartConversion() TryDirectoryDelete(OutputPath, true); Directory.CreateDirectory(OutputPath); - ConvertTotalSize = TargetFileManifest.Sum(x => x.FileSize); - ConvertFsWatcher = new FileSystemWatcher() - { - Path = OutputPath, - NotifyFilter = NotifyFilters.FileName | NotifyFilters.DirectoryName - | NotifyFilters.Size, - IncludeSubdirectories = true, - EnableRaisingEvents = true - }; + EventListener.PatchEvent += EventListener_PatchEvent; - ConvertFsWatcher.Created += ConvertFsWatcher_Created; + await Task.Run(() => + { + HDiffPatch patch = new HDiffPatch(); + patch.Initialize(CookbookPath); + patch.Patch(IngredientsPath, OutputPath, false, Token); + }, Token); - await Task.Run(() => new HPatchUtil().HPatchDir(IngredientsPath, CookbookPath, OutputPath), Token); TryDirectoryDelete(IngredientsPath, true); TryFileDelete(CookbookPath); MoveMiscSourceFiles(SourceProfile.ActualGameDataLocation, OutputPath); TryDirectoryDelete(SourceProfile.ActualGameDataLocation, true); - - ConvertFsWatcher.Created -= ConvertFsWatcher_Created; } catch (Exception ex) { @@ -329,6 +323,16 @@ public async Task StartConversion() LogWriteLine($"Conversion process has failed! But don't worry, the files have been reverted :D\r\n{ex}", LogType.Error, true); throw new Exception($"Conversion process has failed! But don't worry, the file have been reverted :D\r\n{ex}", ex); } + finally + { + EventListener.PatchEvent -= EventListener_PatchEvent; + } + } + + private void EventListener_PatchEvent(object sender, PatchEvent e) + { + ConvertDetail = string.Format(Lang._Misc.Converting, ""); + UpdateProgress(e.CurrentSizePatched, e.TotalSizeToBePatched, 1, 1, e.TimeLeft, ConvertStatus, ConvertDetail); } private void TryFileDelete(string Input) @@ -390,19 +394,6 @@ private void MoveMiscSourceFiles(string InputPath, string OutputPath) } } - string lastName = null; - private void ConvertFsWatcher_Created(object sender, FileSystemEventArgs e) - { - if (!Directory.Exists(e.FullPath)) - { - ConvertDetail = string.Format(Lang._Misc.Converting, e.Name); - UpdateProgress(ConvertRead, ConvertTotalSize, 1, 1, ConvertSw.Elapsed, ConvertStatus, ConvertDetail); - if (lastName != null) - ConvertRead += new FileInfo(lastName).Length; - lastName = e.FullPath; - } - } - public void UpdateProgress(long StartSize, long EndSize, int StartCount, int EndCount, TimeSpan TimeSpan, string StatusMsg = "", string DetailMsg = "", bool UseCountUnit = false) { diff --git a/CollapseLauncher/Classes/InstallManagement/Genshin/GenshinInstall.cs b/CollapseLauncher/Classes/InstallManagement/Genshin/GenshinInstall.cs index d12c2ec19..011f6618b 100644 --- a/CollapseLauncher/Classes/InstallManagement/Genshin/GenshinInstall.cs +++ b/CollapseLauncher/Classes/InstallManagement/Genshin/GenshinInstall.cs @@ -18,11 +18,11 @@ namespace CollapseLauncher.InstallManager.Genshin internal class GenshinInstall : InstallManagerBase, IGameInstallManager { #region Override Properties - protected override int _gameVoiceLanguageID { get => _gamePreset.GetVoiceLanguageID(); } + protected override int _gameVoiceLanguageID { get => _gameVersionManager.GamePreset.GetVoiceLanguageID(); } #endregion #region Private Properties - private string _gameDataPath { get => Path.Combine(_gamePath, $"{Path.GetFileNameWithoutExtension(_gamePreset.GameExecutableName)}_Data"); } + private string _gameDataPath { get => Path.Combine(_gamePath, $"{Path.GetFileNameWithoutExtension(_gameVersionManager.GamePreset.GameExecutableName)}_Data"); } private string _gameDataPersistentPath { get => Path.Combine(_gameDataPath, "Persistent"); } private string _gameAudioLangListPath { @@ -48,20 +48,20 @@ private string _gameAudioLangListPath private string _gameAudioOldPath { get => Path.Combine(_gameDataPath, "StreamingAssets", "Audio", "GeneratedSoundBanks", "Windows"); } #endregion - public GenshinInstall(UIElement parentUI) - : base(parentUI) + public GenshinInstall(UIElement parentUI, IGameVersionCheck GameVersionManager) + : base(parentUI, GameVersionManager) { } #region Public Methods - public override async Task StartPackageInstallation() + protected override async Task StartPackageInstallationInner() { // Starting from 3.6 update, the Audio files have been moved to "AudioAssets" folder EnsureMoveOldToNewAudioDirectory(); // Run the base installation process - await base.StartPackageInstallation(); + await base.StartPackageInstallationInner(); // Then start on processing hdifffiles list and deletefiles list await ApplyHdiffListPatch(); @@ -105,7 +105,7 @@ private void EnsureMoveOldToNewAudioDirectory() } } - public override bool IsPreloadCompleted() + public override async ValueTask IsPreloadCompleted() { // Get the primary file first check List resource = _gameVersionManager.GetGamePreloadZip(); @@ -198,7 +198,7 @@ protected override async ValueTask TryAddResourceVersionList(RegionResourceVersi packageList.Add(package); // Set the voice language ID to value given - _gamePreset.SetVoiceLanguageID(langID); + _gameVersionManager.GamePreset.SetVoiceLanguageID(langID); LogWriteLine($"Adding primary {package.LanguageName} audio package: {package.Name} to the list (Hash: {package.HashString})", LogType.Default, true); } diff --git a/CollapseLauncher/Classes/InstallManagement/Honkai/HonkaiInstall.cs b/CollapseLauncher/Classes/InstallManagement/Honkai/HonkaiInstall.cs index ea7ca4581..26944046e 100644 --- a/CollapseLauncher/Classes/InstallManagement/Honkai/HonkaiInstall.cs +++ b/CollapseLauncher/Classes/InstallManagement/Honkai/HonkaiInstall.cs @@ -2,10 +2,9 @@ using CollapseLauncher.InstallManager.Base; using CollapseLauncher.Interfaces; using CollapseLauncher.Pages; -using CollapseLauncher.Statics; using Hi3Helper; -using Hi3Helper.Data; using Hi3Helper.Shared.ClassStruct; +using Hi3Helper.SharpHDiffPatch; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; using System; @@ -27,19 +26,21 @@ internal class HonkaiInstall : InstallManagerBase, IGameI #endregion #region Private Properties + private HonkaiCache _gameCacheManager { get; set; } private bool _forceIgnoreDeltaPatch = false; - private FileSystemWatcher _deltaPatchWatcher; #endregion - public HonkaiInstall(UIElement parentUI) - : base(parentUI) + public HonkaiInstall(UIElement parentUI, IGameVersionCheck GameVersionManager, ICache GameCacheManager, IGameSettings GameSettings) + : base(parentUI, GameVersionManager) { - + _gameSettings = GameSettings; + _gameCacheManager = GameCacheManager as HonkaiCache; } #region Public Methods public override async ValueTask StartPackageVerification() { + IsRunning = true; DeltaPatchProperty patchProperty = _gameDeltaPatchProperty; // Check if the game has delta patch and in NeedsUpdate status. If true, then @@ -58,8 +59,11 @@ public override async ValueTask StartPackageVerification() return -1; } + // Always reset the token + ResetToken(); + // Initialize repair tool - _gameRepairTool = new HonkaiRepair(_parentUI, true, patchProperty.SourceVer); + _gameRepairTool = new HonkaiRepair(_parentUI, _gameVersionManager, _gameCacheManager, _gameSettings, true, patchProperty.SourceVer); try { // Set the activity @@ -83,7 +87,11 @@ public override async ValueTask StartPackageVerification() await _gameRepairTool.StartRepairRoutine(true); } } - catch { throw; } + catch + { + IsRunning = false; + throw; + } finally { // Unsubscribe the progress event @@ -98,7 +106,7 @@ public override async ValueTask StartPackageVerification() return await base.StartPackageVerification(); } - public override async Task StartPackageInstallation() + protected override async Task StartPackageInstallationInner() { if (_canDeltaPatch && _gameInstallationStatus == GameInstallStateEnum.NeedsUpdate && !_forceIgnoreDeltaPatch) { @@ -107,19 +115,9 @@ public override async Task StartPackageInstallation() string previousPath = _gamePath; string ingredientPath = previousPath.TrimEnd('\\') + "_Ingredients"; - // Initialize the filesystem watcher to check file changes on event - _deltaPatchWatcher = new FileSystemWatcher() - { - Path = previousPath, - NotifyFilter = NotifyFilters.FileName | NotifyFilters.DirectoryName - | NotifyFilters.Size, - IncludeSubdirectories = true, - EnableRaisingEvents = true - }; - try { - List localAssetIndex = (_gameRepairTool as HonkaiRepair).GetAssetIndex(); + List localAssetIndex = ((HonkaiRepair)_gameRepairTool).GetAssetIndex(); MoveFileToIngredientList(localAssetIndex, previousPath, ingredientPath); // Get the sum of uncompressed size and @@ -128,13 +126,19 @@ public override async Task StartPackageInstallation() _progressTotalSizeCurrent = 0; _progressTotalCountCurrent = 1; _status.IsIncludePerFileIndicator = false; + _status.IsProgressTotalIndetermined = true; _status.ActivityStatus = Lang._Misc.ApplyingPatch; UpdateStatus(); RestartStopwatch(); // Start the patching process - _deltaPatchWatcher.Created += DeltaPatchWatcherProgress; - await Task.Run(() => new HPatchUtil().HPatchDir(ingredientPath, patchProperty.PatchPath, previousPath)); + EventListener.PatchEvent += DeltaPatchCheckProgress; + await Task.Run(() => + { + HDiffPatch patch = new HDiffPatch(); + patch.Initialize(patchProperty.PatchPath); + patch.Patch(ingredientPath, previousPath, false, _token.Token); + }); // Remove ingredient folder Directory.Delete(ingredientPath, true); @@ -154,13 +158,12 @@ public override async Task StartPackageInstallation() } finally { - _deltaPatchWatcher.Created -= DeltaPatchWatcherProgress; - _deltaPatchWatcher?.Dispose(); + EventListener.PatchEvent -= DeltaPatchCheckProgress; } } // If no delta patch is happening, then do the base installation - await base.StartPackageInstallation(); + await base.StartPackageInstallationInner(); } public override async ValueTask TryShowFailedDeltaPatchState() @@ -171,7 +174,7 @@ public override async ValueTask TryShowFailedDeltaPatchState() // If path doesn't exist, then return false if (!Directory.Exists(GamePathIngredients)) return false; - LogWriteLine($"Previous failed delta patch has been detected on Game {_gamePreset.ZoneFullname} ({GamePathIngredients})", LogType.Warning, true); + LogWriteLine($"Previous failed delta patch has been detected on Game {_gameVersionManager.GamePreset.ZoneFullname} ({GamePathIngredients})", LogType.Warning, true); // Show action dialog switch (await Dialog_PreviousDeltaPatchInstallFailed(_parentUI)) { @@ -199,7 +202,7 @@ public override async ValueTask TryShowFailedGameConversionState() long FileSize = Directory.EnumerateFiles(GamePathIngredients).Sum(x => new FileInfo(x).Length); if (FileSize < 1 << 20) return false; - LogWriteLine($"Previous failed game conversion has been detected on Game: {_gamePreset.ZoneFullname} ({GamePathIngredients})", LogType.Warning, true); + LogWriteLine($"Previous failed game conversion has been detected on Game: {_gameVersionManager.GamePreset.ZoneFullname} ({GamePathIngredients})", LogType.Warning, true); // Show action dialog switch (await Dialog_PreviousGameConversionFailed(_parentUI)) { @@ -281,15 +284,15 @@ private void MoveFileToIngredientList(List assetIndex, str #endregion #region Event Methods - private async void DeltaPatchCheckProgress(object sender, TotalPerfileProgress e) + private async void DeltaPatchCheckProgress(object sender, PatchEvent e) { - _progress.ProgressTotalPercentage = e.ProgressTotalPercentage == 0 ? e.ProgressPerFilePercentage : e.ProgressTotalPercentage; + _progress.ProgressTotalPercentage = e.ProgressPercentage; - _progress.ProgressTotalTimeLeft = e.ProgressTotalTimeLeft; - _progress.ProgressTotalSpeed = e.ProgressTotalSpeed; + _progress.ProgressTotalTimeLeft = e.TimeLeft; + _progress.ProgressTotalSpeed = e.Speed; - _progress.ProgressTotalSizeToDownload = e.ProgressTotalSizeToDownload; - _progress.ProgressTotalDownload = e.ProgressTotalDownload; + _progress.ProgressTotalSizeToDownload = e.TotalSizeToBePatched; + _progress.ProgressTotalDownload = e.CurrentSizePatched; if (await CheckIfNeedRefreshStopwatch()) { @@ -299,29 +302,21 @@ private async void DeltaPatchCheckProgress(object sender, TotalPerfileProgress e } } - string lastName = null; - private void DeltaPatchWatcherProgress(object sender, FileSystemEventArgs e) + private async void DeltaPatchCheckProgress(object sender, TotalPerfileProgress e) { - if (!Directory.Exists(e.FullPath)) - { - if (lastName != null) - _progressTotalSizeCurrent += new FileInfo(lastName).Length; - lastName = e.FullPath; - - // Assign local sizes to progress - _progress.ProgressTotalDownload = _progressTotalSizeCurrent; - _progress.ProgressTotalSizeToDownload = _progressTotalSize; - - // Calculate the speed - _progress.ProgressTotalSpeed = _progressTotalSizeCurrent / _stopwatch.Elapsed.TotalSeconds; + _progress.ProgressTotalPercentage = e.ProgressTotalPercentage == 0 ? e.ProgressPerFilePercentage : e.ProgressTotalPercentage; - // Calculate percentage - _progress.ProgressTotalPercentage = Math.Round(((double)_progressTotalSizeCurrent / _progressTotalSize) * 100, 2); + _progress.ProgressTotalTimeLeft = e.ProgressTotalTimeLeft; + _progress.ProgressTotalSpeed = e.ProgressTotalSpeed; - // Calculate the timelapse - _progress.ProgressTotalTimeLeft = TimeSpan.FromSeconds((_progressTotalSize - _progressTotalSizeCurrent) / ConverterTool.Unzeroed(_progress.ProgressTotalSpeed)); + _progress.ProgressTotalSizeToDownload = e.ProgressTotalSizeToDownload; + _progress.ProgressTotalDownload = e.ProgressTotalDownload; - UpdateProgress(); + if (await CheckIfNeedRefreshStopwatch()) + { + _status.IsProgressTotalIndetermined = false; + UpdateProgressBase(); + UpdateStatus(); } } #endregion @@ -334,7 +329,7 @@ private string GetFailedGameConversionFolder(string basepath) // Step back once from the game directory string ParentPath = Path.GetDirectoryName(basepath); // Get the ingredient path - string IngredientPath = Directory.EnumerateDirectories(ParentPath, $"{PageStatics._GameVersion.GamePreset.GameDirectoryName}*_ConvertedTo-*_Ingredients", SearchOption.TopDirectoryOnly) + string IngredientPath = Directory.EnumerateDirectories(ParentPath, $"{_gameVersionManager.GamePreset.GameDirectoryName}*_ConvertedTo-*_Ingredients", SearchOption.TopDirectoryOnly) .FirstOrDefault(); // If the path is not null, then return if (IngredientPath is not null) return IngredientPath; diff --git a/CollapseLauncher/Classes/InstallManagement/StarRail/StarRailInstall.cs b/CollapseLauncher/Classes/InstallManagement/StarRail/StarRailInstall.cs index b4d423c47..f118c8e45 100644 --- a/CollapseLauncher/Classes/InstallManagement/StarRail/StarRailInstall.cs +++ b/CollapseLauncher/Classes/InstallManagement/StarRail/StarRailInstall.cs @@ -15,20 +15,20 @@ namespace CollapseLauncher.InstallManager.StarRail internal class StarRailInstall : InstallManagerBase, IGameInstallManager { #region Override Properties - protected override int _gameVoiceLanguageID { get => _gamePreset.GetVoiceLanguageID(); } + protected override int _gameVoiceLanguageID { get => _gameVersionManager.GamePreset.GetVoiceLanguageID(); } #endregion - public StarRailInstall(UIElement parentUI) - : base(parentUI) + public StarRailInstall(UIElement parentUI, IGameVersionCheck GameVersionManager) + : base(parentUI, GameVersionManager) { } #region Public Methods - public override async Task StartPackageInstallation() + protected override async Task StartPackageInstallationInner() { // Run the base installation process - await base.StartPackageInstallation(); + await base.StartPackageInstallationInner(); // Then start on processing hdifffiles list and deletefiles list await ApplyHdiffListPatch(); @@ -55,10 +55,10 @@ protected override async ValueTask TryAddResourceVersionList(RegionResourceVersi langID = await Dialog_ChooseAudioLanguage(_parentUI, langStrings); // Set the voice language ID to value given - _gamePreset.SetVoiceLanguageID(langID); + _gameVersionManager.GamePreset.SetVoiceLanguageID(langID); } - LogWriteLine($"Setting audio ID to: {_gamePreset.GetStarRailVoiceLanguageFullNameByID(_gameVoiceLanguageID)}", LogType.Default, true); + LogWriteLine($"Setting audio ID to: {_gameVersionManager.GamePreset.GetStarRailVoiceLanguageFullNameByID(_gameVoiceLanguageID)}", LogType.Default, true); } private List EnumerateAudioLanguageString() diff --git a/CollapseLauncher/Classes/Interfaces/Class/CommunityToolsProperty.cs b/CollapseLauncher/Classes/Interfaces/Class/CommunityToolsProperty.cs index fd3036262..6ecd1eadd 100644 --- a/CollapseLauncher/Classes/Interfaces/Class/CommunityToolsProperty.cs +++ b/CollapseLauncher/Classes/Interfaces/Class/CommunityToolsProperty.cs @@ -40,7 +40,7 @@ public static CommunityToolsProperty LoadCommunityTools() { if (!File.Exists(filePath)) throw new FileNotFoundException("Community Tools file is not found!", filePath); - return (CommunityToolsProperty)JsonSerializer.Deserialize(File.ReadAllText(filePath), typeof(CommunityToolsProperty), CommunityToolsPropertyContext.Default); + return (CommunityToolsProperty)JsonSerializer.Deserialize(File.ReadAllText(filePath), typeof(CommunityToolsProperty), InternalAppJSONContext.Default); } catch (Exception ex) { diff --git a/CollapseLauncher/Classes/Interfaces/Class/GamePropertyBase.cs b/CollapseLauncher/Classes/Interfaces/Class/GamePropertyBase.cs index 69c51524b..01955b23a 100644 --- a/CollapseLauncher/Classes/Interfaces/Class/GamePropertyBase.cs +++ b/CollapseLauncher/Classes/Interfaces/Class/GamePropertyBase.cs @@ -1,6 +1,4 @@ -using CollapseLauncher.Statics; -using Hi3Helper.Preset; -using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml; using System; using System.Collections.Generic; using System.Collections.ObjectModel; @@ -16,8 +14,15 @@ internal class GamePropertyBase : IAssetEntry where T1 : Enum private GameVersion _gameVersionOverride { get; init; } private bool _isVersionOverride { get; init; } - public GamePropertyBase(UIElement parentUI, string gamePath, string gameRepoURL, string versionOverride) + public GamePropertyBase(UIElement parentUI, IGameVersionCheck gameVersionManager, IGameSettings gameSettings, string gamePath, string gameRepoURL, string versionOverride) + : this(parentUI, gameVersionManager, gamePath, gameRepoURL, versionOverride) { + _gameSettings = gameSettings; + } + + public GamePropertyBase(UIElement parentUI, IGameVersionCheck gameVersionManager, string gamePath, string gameRepoURL, string versionOverride) + { + _gameVersionManager = gameVersionManager; _parentUI = parentUI; _gamePathField = gamePath; _gameRepoURL = gameRepoURL; @@ -39,16 +44,17 @@ public GamePropertyBase(UIElement parentUI, string gamePath, string gameRepoURL, protected byte _downloadThreadCount { get => (byte)AppCurrentDownloadThread; } protected byte _threadCount { get => (byte)AppCurrentThread; } protected CancellationTokenSource _token { get; set; } - protected UIElement _parentUI { get; init; } protected Stopwatch _stopwatch { get; set; } protected Stopwatch _refreshStopwatch { get; set; } - protected string _gamePath { get => string.IsNullOrEmpty(_gamePathField) ? PageStatics._GameVersion.GameDirPath : _gamePathField; } + protected GameVersion _gameVersion { get => _isVersionOverride ? _gameVersionOverride : _gameVersionManager.GetGameExistingVersion().Value; } + protected IGameVersionCheck _gameVersionManager { get; set; } + protected IGameSettings _gameSettings { get; set; } + protected string _gamePath { get => string.IsNullOrEmpty(_gamePathField) ? _gameVersionManager.GameDirPath : _gamePathField; } protected string _gameRepoURL { get; set; } - protected PresetConfigV2 _gamePreset { get => PageStatics._GameVersion.GamePreset; } - protected GameVersion _gameVersion { get => _isVersionOverride ? _gameVersionOverride : PageStatics._GameVersion.GetGameExistingVersion().Value; } protected List _assetIndex { get; set; } protected bool _useFastMethod { get; set; } public ObservableCollection> AssetEntry { get; set; } + public UIElement _parentUI { get; init; } } } diff --git a/CollapseLauncher/Classes/Interfaces/Class/ProgressBase.cs b/CollapseLauncher/Classes/Interfaces/Class/ProgressBase.cs index 53fe2cbea..b391cb936 100644 --- a/CollapseLauncher/Classes/Interfaces/Class/ProgressBase.cs +++ b/CollapseLauncher/Classes/Interfaces/Class/ProgressBase.cs @@ -22,8 +22,13 @@ internal class ProgressBase : GamePropertyBase where T1 : Enum where T2 : IAssetIndexSummary { - public ProgressBase(UIElement parentUI, string gamePath, string gameRepoURL, string versionOverride) - : base(parentUI, gamePath, gameRepoURL, versionOverride) + public ProgressBase(UIElement parentUI, IGameVersionCheck GameVersionManager, IGameSettings GameSettings, string gamePath, string gameRepoURL, string versionOverride) + : base(parentUI, GameVersionManager, GameSettings, gamePath, gameRepoURL, versionOverride) => Init(); + + public ProgressBase(UIElement parentUI, IGameVersionCheck GameVersionManager, string gamePath, string gameRepoURL, string versionOverride) + : base(parentUI, GameVersionManager, gamePath, gameRepoURL, versionOverride) => Init(); + + private void Init() { _status = new TotalPerfileStatus() { IsIncludePerFileIndicator = true }; _progress = new TotalPerfileProgress(); @@ -526,6 +531,8 @@ protected async Task SpawnRepairDialog(List assetIndex, Action actionIfInter #endregion #region HandlerUpdaters + public void Dispatch(DispatcherQueueHandler handler) => _parentUI.DispatcherQueue.TryEnqueue(handler); + protected virtual void PopRepairAssetEntry() => Dispatch(() => { try @@ -582,7 +589,6 @@ protected virtual void UpdateRepairStatus(string activityStatus, string activity UpdateStatus(); } - protected void Dispatch(DispatcherQueueHandler handler) => _parentUI.DispatcherQueue.TryEnqueue(handler); protected async Task CheckIfNeedRefreshStopwatch() { if (_refreshStopwatch.ElapsedMilliseconds > _refreshInterval) diff --git a/CollapseLauncher/Classes/Interfaces/IBackgroundActivity.cs b/CollapseLauncher/Classes/Interfaces/IBackgroundActivity.cs new file mode 100644 index 000000000..b77aae1c4 --- /dev/null +++ b/CollapseLauncher/Classes/Interfaces/IBackgroundActivity.cs @@ -0,0 +1,16 @@ +using Microsoft.UI.Dispatching; +using Microsoft.UI.Xaml; +using System; + +namespace CollapseLauncher.Interfaces +{ + internal interface IBackgroundActivity + { + event EventHandler ProgressChanged; + event EventHandler StatusChanged; + bool IsRunning { get; } + UIElement _parentUI { get; } + void CancelRoutine(); + void Dispatch(DispatcherQueueHandler handler); + } +} diff --git a/CollapseLauncher/Classes/Interfaces/IGameInstallManager.cs b/CollapseLauncher/Classes/Interfaces/IGameInstallManager.cs index 9cc322193..c85624c88 100644 --- a/CollapseLauncher/Classes/Interfaces/IGameInstallManager.cs +++ b/CollapseLauncher/Classes/Interfaces/IGameInstallManager.cs @@ -1,13 +1,9 @@ -using System; -using System.Threading.Tasks; +using System.Threading.Tasks; namespace CollapseLauncher.Interfaces { - internal interface IGameInstallManager + internal interface IGameInstallManager : IBackgroundActivity { - event EventHandler ProgressChanged; - event EventHandler StatusChanged; - ValueTask GetInstallationPath(); Task StartPackageDownload(bool skipDialog = false); ValueTask StartPackageVerification(); @@ -18,8 +14,7 @@ internal interface IGameInstallManager Task MoveGameLocation(); ValueTask UninstallGame(); void Flush(); - void CancelRoutine(); - bool IsPreloadCompleted(); + ValueTask IsPreloadCompleted(); ValueTask TryShowFailedDeltaPatchState(); ValueTask TryShowFailedGameConversionState(); diff --git a/CollapseLauncher/Classes/PageStatics.cs b/CollapseLauncher/Classes/PageStatics.cs index 2597294f6..4bf8a75bf 100644 --- a/CollapseLauncher/Classes/PageStatics.cs +++ b/CollapseLauncher/Classes/PageStatics.cs @@ -1,14 +1,207 @@ -using CollapseLauncher.Interfaces; +using CollapseLauncher.GameSettings.Genshin; +using CollapseLauncher.GameSettings.Honkai; +using CollapseLauncher.GameSettings.StarRail; +using CollapseLauncher.GameVersioning; +using CollapseLauncher.InstallManager.Genshin; +using CollapseLauncher.InstallManager.Honkai; +using CollapseLauncher.InstallManager.StarRail; +using CollapseLauncher.Interfaces; +using Hi3Helper; +using Hi3Helper.Preset; +using Hi3Helper.Shared.ClassStruct; +using Microsoft.UI.Xaml; +using System; +using System.Collections.Generic; +using System.Linq; namespace CollapseLauncher.Statics { + internal class GamePresetProperty + { + internal GamePresetProperty(UIElement UIElementParent, RegionResourceProp APIResouceProp, PresetConfigV2 GamePreset) + { + _GamePreset = CopyGamePreset(GamePreset); + _APIResouceProp = APIResouceProp.Copy(); + + switch (GamePreset.GameType) + { + case GameType.Honkai: + _GameVersion = new GameTypeHonkaiVersion(UIElementParent, _APIResouceProp, _GamePreset); + _GameSettings = new HonkaiSettings(_GameVersion); + _GameCache = new HonkaiCache(UIElementParent, _GameVersion); + _GameRepair = new HonkaiRepair(UIElementParent, _GameVersion, _GameCache, _GameSettings); + _GameInstall = new HonkaiInstall(UIElementParent, _GameVersion, _GameCache, _GameSettings); + break; + case GameType.StarRail: + _GameVersion = new GameTypeStarRailVersion(UIElementParent, _APIResouceProp, _GamePreset); + _GameSettings = new StarRailSettings(_GameVersion); + _GameCache = new StarRailCache(UIElementParent, _GameVersion); + _GameRepair = new StarRailRepair(UIElementParent, _GameVersion); + _GameInstall = new StarRailInstall(UIElementParent, _GameVersion); + break; + case GameType.Genshin: + _GameVersion = new GameTypeGenshinVersion(UIElementParent, _APIResouceProp, _GamePreset); + _GameSettings = new GenshinSettings(_GameVersion); + _GameCache = null; + _GameRepair = new GenshinRepair(UIElementParent, _GameVersion, _GameVersion.GameAPIProp.data.game.latest.decompressed_path); + _GameInstall = new GenshinInstall(UIElementParent, _GameVersion); + break; + default: + throw new NotSupportedException($"[GamePresetProperty.Ctor] Game type: {GamePreset.GameType} ({GamePreset.ProfileName} - {GamePreset.ZoneName}) is not supported!"); + } + } + + private static T[] CopyReturn(T[] Source) + { + if (Source == null) return null; + T[] returnNew = new T[Source.Length]; + Array.Copy(Source, returnNew, Source.Length); + return returnNew; + } + + private static List CopyReturn(IEnumerable Source) + { + if (Source == null) return null; + return new List(Source); + } + + #region Goofy Ah Copy Method. TODO: Use Generics for this :pepehands: + private PresetConfigV2 CopyGamePreset(PresetConfigV2 GamePreset) => new PresetConfigV2() + { + ActualGameDataLocation = GamePreset.ActualGameDataLocation, + BetterHi3LauncherVerInfoReg = GamePreset.BetterHi3LauncherVerInfoReg, + ConvertibleTo = CopyReturn(GamePreset.ConvertibleTo), + DispatcherKey = GamePreset.DispatcherKey, + DispatcherKeyBitLength = GamePreset.DispatcherKeyBitLength, + FallbackGameType = GamePreset.FallbackGameType, + FallbackLanguage = GamePreset.FallbackLanguage, + GameChannel = GamePreset.GameChannel, + GameDefaultCVLanguage = GamePreset.GameDefaultCVLanguage, + GameDirectoryName = GamePreset.GameDirectoryName, + GameDispatchArrayURL = CopyReturn(GamePreset.GameDispatchArrayURL), + GameDispatchChannelName = GamePreset.GameDispatchChannelName, + GameDispatchDefaultName = GamePreset.GameDispatchDefaultName, + GameDispatchURL = GamePreset.GameDispatchURL, + GameDispatchURLTemplate = GamePreset.GameDispatchURLTemplate, + GameExecutableName = GamePreset.GameExecutableName, + GameGatewayDefault = GamePreset.GameGatewayDefault, + GameGatewayURLTemplate = GamePreset.GameGatewayURLTemplate, + GameName = GamePreset.GameName, + GameSupportedLanguages = CopyReturn(GamePreset.GameSupportedLanguages), + GameType = GamePreset.GameType, + HashID = GamePreset.HashID, + InternalGameNameFolder = GamePreset.InternalGameNameFolder, + InternalGameNameInConfig = GamePreset.InternalGameNameInConfig, + IsCacheUpdateEnabled = GamePreset.IsCacheUpdateEnabled, + IsConvertible = GamePreset.IsConvertible, + IsExperimental = GamePreset.IsExperimental, + IsGenshin = GamePreset.IsGenshin, + IsHideSocMedDesc = GamePreset.IsHideSocMedDesc, + IsRepairEnabled = GamePreset.IsRepairEnabled, + LauncherResourceURL = GamePreset.LauncherResourceURL, + LauncherSpriteURL = GamePreset.LauncherSpriteURL, + LauncherSpriteURLMultiLang = GamePreset.LauncherSpriteURLMultiLang, + LauncherSpriteURLMultiLangFallback = GamePreset.LauncherSpriteURLMultiLangFallback, + ProfileName = GamePreset.ProfileName, + ProtoDispatchKey = GamePreset.ProtoDispatchKey, + SteamGameID = GamePreset.SteamGameID, + SteamInstallRegistryLocation = GamePreset.SteamInstallRegistryLocation, + UseRightSideProgress = GamePreset.UseRightSideProgress, + VendorType = GamePreset.VendorType, + ZoneDescription = GamePreset.ZoneDescription, + ZoneFullname = GamePreset.ZoneFullname, + ZoneLogoURL = GamePreset.ZoneLogoURL, + ZoneName = GamePreset.ZoneName, + ZonePosterURL = GamePreset.ZonePosterURL, + ZoneURL = GamePreset.ZoneURL, + }; + #endregion + + internal RegionResourceProp _APIResouceProp { get; set; } + internal PresetConfigV2 _GamePreset { get; set; } + internal IGameSettings _GameSettings { get; set; } + internal IRepair _GameRepair { get; set; } + internal ICache _GameCache { get; set; } + internal IGameVersionCheck _GameVersion { get; set; } + internal IGameInstallManager _GameInstall { get; set; } + } + + internal static class GamePropertyVault + { + private static Dictionary Vault = new Dictionary(); + public static int LastGameHashID { get; set; } + public static int CurrentGameHashID { get; set; } + public static GamePresetProperty GetCurrentGameProperty() => Vault[CurrentGameHashID]; + + public static void LoadGameProperty(UIElement UIElementParent, RegionResourceProp APIResouceProp, PresetConfigV2 GamePreset) + { + LastGameHashID = LastGameHashID == 0 ? GamePreset.HashID : LastGameHashID; + CurrentGameHashID = GamePreset.HashID; + RegisterGameProperty(UIElementParent, APIResouceProp, GamePreset); + } + + public static void RegisterGameProperty(UIElement UIElementParent, RegionResourceProp APIResouceProp, PresetConfigV2 GamePreset) + { + CleanupUnusedGameProperty(); + if (Vault.ContainsKey(GamePreset.HashID)) + { +#if DEBUG + Logger.LogWriteLine($"[GamePropertyVault] Game property has been cached by Hash ID: {GamePreset.HashID}", LogType.Debug, true); +#endif + return; + } + + GamePresetProperty Property = new GamePresetProperty(UIElementParent, APIResouceProp, GamePreset); + Vault.Add(GamePreset.HashID, Property); +#if DEBUG + Logger.LogWriteLine($"[GamePropertyVault] Creating & caching game property by Hash ID: {GamePreset.HashID}", LogType.Debug, true); +#endif + } + + private static void CleanupUnusedGameProperty() + { + if (Vault.Count == 0) return; + + int[] unusedGamePropertyHashID = Vault.Values + .Where(x => !x._GameInstall.IsRunning && x._GamePreset.HashID != CurrentGameHashID)? + .Select(x => x._GamePreset.HashID)? + .ToArray(); + + foreach (int key in unusedGamePropertyHashID) + { +#if DEBUG + Logger.LogWriteLine($"[GamePropertyVault] Cleaning up unused game property by Hash ID: {key}", LogType.Debug, true); +#endif + Vault.Remove(key); + } + } + + public static void AttachNotifForCurrentGame(int hashID = int.MinValue) + { + if (hashID < 0) hashID = CurrentGameHashID; + if (Vault.ContainsKey(hashID)) AttachNotifForCurrentGame_Inner(hashID); + } + + private static void AttachNotifForCurrentGame_Inner(int HashID) + { + GamePresetProperty GameProperty = Vault[HashID]; + if (GameProperty._GameInstall.IsRunning) + { + string actTitle = $"Downloading game: {GameProperty._GameVersion.GamePreset.GameName}"; + string actSubtitle = GameProperty._GameVersion.GamePreset.ZoneName; + BackgroundActivityManager.Attach(HashID, GameProperty._GameInstall, actTitle, actSubtitle); + } + } + + public static void DetachNotifForCurrentGame(int hashID = int.MinValue) + { + if (hashID < 0) hashID = CurrentGameHashID; + if (Vault.ContainsKey(hashID)) BackgroundActivityManager.Detach(hashID); + } + } + internal partial class PageStatics { - internal static IGameSettings _GameSettings { get; set; } - internal static IRepair _GameRepair { get; set; } - internal static ICache _GameCache { get; set; } - internal static IGameVersionCheck _GameVersion { get; set; } - internal static IGameInstallManager _GameInstall { get; set; } internal static CommunityToolsProperty _CommunityToolsProperty { get; set; } } } diff --git a/CollapseLauncher/Classes/Properties/InnerLauncherConfig.cs b/CollapseLauncher/Classes/Properties/InnerLauncherConfig.cs index b31ae1a57..dc8ef841c 100644 --- a/CollapseLauncher/Classes/Properties/InnerLauncherConfig.cs +++ b/CollapseLauncher/Classes/Properties/InnerLauncherConfig.cs @@ -142,7 +142,7 @@ public static void SaveLocalNotificationData() RegionPushIgnoreMsgIds = NotificationData.RegionPushIgnoreMsgIds }; File.WriteAllText(AppNotifIgnoreFile, - JsonSerializer.Serialize(LocalNotificationData, typeof(NotificationPush), NotificationPushContext.Default)); + JsonSerializer.Serialize(LocalNotificationData, typeof(NotificationPush), InternalAppJSONContext.Default)); } public static void LoadLocalNotificationData() @@ -151,10 +151,10 @@ public static void LoadLocalNotificationData() File.WriteAllText(AppNotifIgnoreFile, JsonSerializer.Serialize(new NotificationPush(), typeof(NotificationPush), - NotificationPushContext.Default)); + InternalAppJSONContext.Default)); string Data = File.ReadAllText(AppNotifIgnoreFile); - NotificationPush LocalNotificationData = (NotificationPush)JsonSerializer.Deserialize(Data, typeof(NotificationPush), NotificationPushContext.Default); + NotificationPush LocalNotificationData = (NotificationPush)JsonSerializer.Deserialize(Data, typeof(NotificationPush), InternalAppJSONContext.Default); NotificationData.AppPushIgnoreMsgIds = LocalNotificationData.AppPushIgnoreMsgIds; NotificationData.RegionPushIgnoreMsgIds = LocalNotificationData.RegionPushIgnoreMsgIds; NotificationData.CurrentShowMsgIds = LocalNotificationData.CurrentShowMsgIds; @@ -172,7 +172,12 @@ public static async Task CheckForNewConfigV2() { await FallbackCDNUtil.DownloadCDNFallbackContent(_http, s, string.Format(AppGameConfigV2URLPrefix, (IsPreview ? "preview" : "stable") + "stamp"), default).ConfigureAwait(false); s.Position = 0; - ConfigStamp = (Stamp)JsonSerializer.Deserialize(s, typeof(Stamp), StampContext.Default); + ConfigStamp = (Stamp)JsonSerializer.Deserialize(s, typeof(Stamp), CoreLibraryJSONContext.Default); +#if DEBUG + LogWriteLine($"Checking for metadata update...\r\n" + + $" LocalStamp : {ConfigV2LastUpdate}\r\n" + + $" RemoteStamp : {ConfigStamp?.LastUpdated}", LogType.Warning, true); +#endif } } catch (Exception ex) @@ -181,7 +186,7 @@ public static async Task CheckForNewConfigV2() return false; } - return ConfigV2LastUpdate != ConfigStamp?.LastUpdated; + return ConfigV2LastUpdate < ConfigStamp?.LastUpdated; } public static async Task DownloadConfigV2Files(bool Stamp, bool Content) diff --git a/CollapseLauncher/Classes/Properties/WindowSizeProp/WindowSizeProp.cs b/CollapseLauncher/Classes/Properties/WindowSizeProp/WindowSizeProp.cs index 71b245360..a808242bb 100644 --- a/CollapseLauncher/Classes/Properties/WindowSizeProp/WindowSizeProp.cs +++ b/CollapseLauncher/Classes/Properties/WindowSizeProp/WindowSizeProp.cs @@ -15,7 +15,7 @@ internal static class WindowSize "Normal", new WindowSizeProp() { - WindowBounds = new Size(1196, 726), + WindowBounds = new Size(1243, 726), EventPostCarouselBounds = new Size(399, 185), PostPanelBounds = new Size(399, 134), PostPanelBottomMargin = new Thickness(0, 0, 0, 52), diff --git a/CollapseLauncher/Classes/RegionManagement/FallbackCDNUtil.cs b/CollapseLauncher/Classes/RegionManagement/FallbackCDNUtil.cs index ef1edf323..38188154f 100644 --- a/CollapseLauncher/Classes/RegionManagement/FallbackCDNUtil.cs +++ b/CollapseLauncher/Classes/RegionManagement/FallbackCDNUtil.cs @@ -6,7 +6,12 @@ using System; using System.IO; using System.Linq; +using System.Net.Http; +using System.Net.Http.Json; +using System.Runtime.Serialization; using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; using static Hi3Helper.Logger; @@ -76,6 +81,7 @@ private string GetRelativePathOnly(string url) internal static class FallbackCDNUtil { + private static HttpClient _client = new HttpClient(); public static event EventHandler DownloadProgress; public static async Task DownloadCDNFallbackContent(Http httpInstance, string outputPath, int parallelThread, string relativeURL, CancellationToken token) @@ -239,10 +245,22 @@ public static CDNURLProperty GetPreferredCDN() { // Get the CurrentCDN index int cdnIndex = GetAppConfigValue("CurrentCDN").ToInt(); + + // Fallback to the first CDN if index < 0 or > length of the list + if (cdnIndex < 0 || cdnIndex > CDNList.Count - 1) cdnIndex = 0; + // Return the CDN property as per index return CDNList[cdnIndex]; } + public static async ValueTask DownloadAsJSONType(string URL, JsonSerializerContext context, CancellationToken token) => + await _client.GetFromJsonAsync(URL, new JsonSerializerOptions() + { + TypeInfoResolver = context + }, token); + + public static async ValueTask DownloadAsStream(string URL, CancellationToken token) => await _client.GetStreamAsync(URL, token); + // Re-send the events to the static DownloadProgress private static void HttpInstance_DownloadProgressAdapter(object sender, DownloadEvent e) => DownloadProgress?.Invoke(sender, e); } diff --git a/CollapseLauncher/Classes/RegionManagement/RegionManagement.cs b/CollapseLauncher/Classes/RegionManagement/RegionManagement.cs index 7b4f7f15e..00ee38316 100644 --- a/CollapseLauncher/Classes/RegionManagement/RegionManagement.cs +++ b/CollapseLauncher/Classes/RegionManagement/RegionManagement.cs @@ -15,6 +15,7 @@ using Microsoft.UI.Xaml.Controls; using System; using System.Collections.Generic; +using System.IO; using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; @@ -34,7 +35,7 @@ private enum ResourceLoadingType DownloadInformation } - private Http _httpClient; + private GamePresetProperty CurrentGameProperty; private bool IsLoadRegionComplete; private bool IsExplicitCancel; private string PreviousTag = string.Empty; @@ -50,55 +51,56 @@ private enum ResourceLoadingType public async Task LoadRegionFromCurrentConfigV2(PresetConfigV2 preset) { - using (_httpClient = new Http(default, 4, 250)) - { - IsExplicitCancel = false; - RegionToChangeName = $"{CurrentConfigV2GameCategory} - {CurrentConfigV2GameRegion}"; - LogWriteLine($"Initializing {RegionToChangeName}...", Hi3Helper.LogType.Scheme, true); + IsExplicitCancel = false; + RegionToChangeName = $"{CurrentConfigV2GameCategory} - {CurrentConfigV2GameRegion}"; + LogWriteLine($"Initializing {RegionToChangeName}...", Hi3Helper.LogType.Scheme, true); - // Set IsLoadRegionComplete to false - IsLoadRegionComplete = false; + // Set IsLoadRegionComplete to false + IsLoadRegionComplete = false; - // Clear MainPage State, like NavigationView, Load State, etc. - ClearMainPageState(); + // Clear MainPage State, like NavigationView, Load State, etc. + ClearMainPageState(); - // Load Region Resource from Launcher API - bool IsLoadLocalizedResourceSuccess = await TryLoadResourceInfo(ResourceLoadingType.LocalizedResource, preset); - bool IsLoadResourceRegionSuccess = false; - if (IsLoadLocalizedResourceSuccess) - { - IsLoadResourceRegionSuccess = await TryLoadResourceInfo(ResourceLoadingType.DownloadInformation, preset); - } + // Load Region Resource from Launcher API + bool IsLoadLocalizedResourceSuccess = await TryLoadResourceInfo(ResourceLoadingType.LocalizedResource, preset); + bool IsLoadResourceRegionSuccess = false; + if (IsLoadLocalizedResourceSuccess) + { + IsLoadResourceRegionSuccess = await TryLoadResourceInfo(ResourceLoadingType.DownloadInformation, preset); + } - if (IsExplicitCancel) + if (IsExplicitCancel) + { + // If explicit cancel was triggered, restore the navigation menu item then return false + foreach (object item in LastNavigationItem) { - // If explicit cancel was triggered, restore the navigation menu item then return false - foreach (object item in LastNavigationItem) - { - NavigationViewControl.MenuItems.Add(item); - } - NavigationViewControl.IsSettingsVisible = true; - regionNewsProp = LastRegionNewsProp.Copy(); - LastRegionNewsProp = null; - LastNavigationItem.Clear(); - return false; + NavigationViewControl.MenuItems.Add(item); } + NavigationViewControl.IsSettingsVisible = true; + regionNewsProp = LastRegionNewsProp.Copy(); + LastRegionNewsProp = null; + LastNavigationItem.Clear(); + return false; + } - if (!IsLoadLocalizedResourceSuccess || !IsLoadResourceRegionSuccess) - { - MainFrameChanger.ChangeWindowFrame(typeof(DisconnectedPage)); - return false; - } + if (!IsLoadLocalizedResourceSuccess || !IsLoadResourceRegionSuccess) + { + MainFrameChanger.ChangeWindowFrame(typeof(DisconnectedPage)); + return false; + } - // Finalize Region Load - await ChangeBackgroundImageAsRegion(); - FinalizeLoadRegion(preset); + // Finalize Region Load + await ChangeBackgroundImageAsRegion(); + FinalizeLoadRegion(preset); + CurrentGameProperty = GamePropertyVault.GetCurrentGameProperty(); - // Set IsLoadRegionComplete to false - IsLoadRegionComplete = true; + GamePropertyVault.AttachNotifForCurrentGame(GamePropertyVault.LastGameHashID); + GamePropertyVault.DetachNotifForCurrentGame(GamePropertyVault.CurrentGameHashID); - return true; - } + // Set IsLoadRegionComplete to false + IsLoadRegionComplete = true; + + return true; } public void ClearMainPageState() @@ -108,6 +110,9 @@ public void ClearMainPageState() NavigationViewControl.MenuItems.Clear(); NavigationViewControl.IsSettingsVisible = false; PreviousTag = "launcher"; + PreviousTagString.Clear(); + PreviousTagString.Add(PreviousTag); + LauncherFrame.BackStack.Clear(); ResetRegionProp(); } @@ -162,6 +167,168 @@ private async ValueTask TryLoadResourceInfo(ResourceLoadingType resourceTy return false; } + private async ValueTask FetchLauncherLocalizedResources(CancellationToken Token, PresetConfigV2 Preset) + { + regionBackgroundProp = Preset.LauncherSpriteURLMultiLang ? + await TryGetMultiLangResourceProp(Token, Preset) : + await TryGetSingleLangResourceProp(Token, Preset); + + await DownloadBackgroundImage(Token); + + await GetLauncherAdvInfo(Token, Preset); + await GetLauncherCarouselInfo(Token); + await GetLauncherEventInfo(Token); + GetLauncherPostInfo(); + } + + private async ValueTask DownloadBackgroundImage(CancellationToken Token) + { + regionBackgroundProp.imgLocalPath = Path.Combine(AppGameImgFolder, "bg", Path.GetFileName(regionBackgroundProp.data.adv.background)); + SetAndSaveConfigValue("CurrentBackground", regionBackgroundProp.imgLocalPath); + + if (!Directory.Exists(Path.Combine(AppGameImgFolder, "bg"))) + Directory.CreateDirectory(Path.Combine(AppGameImgFolder, "bg")); + + FileInfo fI = new FileInfo(regionBackgroundProp.imgLocalPath); + if (fI.Exists) return; + + using (Stream netStream = await FallbackCDNUtil.DownloadAsStream(regionBackgroundProp.data.adv.background, Token)) + using (Stream outStream = fI.Create()) + { + netStream.CopyTo(outStream); + } + } + + private async ValueTask FetchLauncherDownloadInformation(CancellationToken token, PresetConfigV2 Preset) + { + _gameAPIProp = await FallbackCDNUtil.DownloadAsJSONType(Preset.LauncherResourceURL, CoreLibraryJSONContext.Default, token); +#if DEBUG + if (_gameAPIProp.data.game.latest.decompressed_path != null) LogWriteLine($"Decompressed Path: {_gameAPIProp.data.game.latest.decompressed_path}", LogType.Default, true); + if (_gameAPIProp.data.game.latest.path != null) LogWriteLine($"ZIP Path: {_gameAPIProp.data.game.latest.path}", LogType.Default, true); + if (_gameAPIProp.data.pre_download_game?.latest?.decompressed_path != null) LogWriteLine($"Decompressed Path Pre-load: {_gameAPIProp.data.pre_download_game?.latest?.decompressed_path}", LogType.Default, true); + if (_gameAPIProp.data.pre_download_game?.latest?.path != null) LogWriteLine($"ZIP Path Pre-load: {_gameAPIProp.data.pre_download_game?.latest?.path}", LogType.Default, true); +#endif + } + + private async ValueTask TryGetMultiLangResourceProp(CancellationToken Token, PresetConfigV2 Preset) + { + RegionResourceProp ret = await GetMultiLangResourceProp(Lang.LanguageID.ToLower(), Token, Preset); + + return ret.data.adv == null + || ((ret.data.adv.version ?? 5) <= 4 + && Preset.GameType == GameType.Honkai) ? + await GetMultiLangResourceProp(Preset.LauncherSpriteURLMultiLangFallback ?? "en-us", Token, Preset) : + ret; + } + + private async ValueTask GetMultiLangResourceProp(string langID, CancellationToken token, PresetConfigV2 Preset) + => await FallbackCDNUtil.DownloadAsJSONType(string.Format(Preset.LauncherSpriteURL, langID), CoreLibraryJSONContext.Default, token); + + + private async ValueTask TryGetSingleLangResourceProp(CancellationToken token, PresetConfigV2 Preset) + => await FallbackCDNUtil.DownloadAsJSONType(Preset.LauncherSpriteURL, CoreLibraryJSONContext.Default, token); + + private void ResetRegionProp() + { + LastRegionNewsProp = regionNewsProp.Copy(); + regionNewsProp = new HomeMenuPanel() + { + sideMenuPanel = null, + imageCarouselPanel = null, + articlePanel = null, + eventPanel = null + }; + } + + private async ValueTask GetLauncherAdvInfo(CancellationToken Token, PresetConfigV2 Preset) + { + if (regionBackgroundProp.data.icon.Count == 0) return; + + regionNewsProp.sideMenuPanel = new List(); + foreach (RegionSocMedProp item in regionBackgroundProp.data.icon) + { + regionNewsProp.sideMenuPanel.Add(new MenuPanelProp + { + URL = item.url, + Icon = await GetCachedSprites(item.img, Token), + IconHover = await GetCachedSprites(item.img_hover, Token), + QR = string.IsNullOrEmpty(item.qr_img) ? null : await GetCachedSprites(item.qr_img, Token), + QR_Description = string.IsNullOrEmpty(item.qr_desc) ? null : item.qr_desc, + Description = string.IsNullOrEmpty(item.title) || Preset.IsHideSocMedDesc ? item.url : item.title + }); + } + } + + private async ValueTask GetLauncherCarouselInfo(CancellationToken Token) + { + if (regionBackgroundProp.data.banner.Count == 0) return; + + regionNewsProp.imageCarouselPanel = new List(); + foreach (RegionSocMedProp item in regionBackgroundProp.data.banner) + { + regionNewsProp.imageCarouselPanel.Add(new MenuPanelProp + { + URL = item.url, + Icon = await GetCachedSprites(item.img, Token), + Description = string.IsNullOrEmpty(item.name) ? item.url : item.name + }); + } + } + + private async ValueTask GetLauncherEventInfo(CancellationToken Token) + { + if (string.IsNullOrEmpty(regionBackgroundProp.data.adv.icon)) return; + + regionNewsProp.eventPanel = new RegionBackgroundProp + { + url = regionBackgroundProp.data.adv.url, + icon = await GetCachedSprites(regionBackgroundProp.data.adv.icon, Token) + }; + } + + private void GetLauncherPostInfo() + { + if (regionBackgroundProp.data.post.Count == 0) return; + + regionNewsProp.articlePanel = new PostCarouselTypes(); + foreach (RegionSocMedProp item in regionBackgroundProp.data.post) + { + switch (item.type) + { + case PostCarouselType.POST_TYPE_ACTIVITY: + regionNewsProp.articlePanel.Events.Add(item); + break; + case PostCarouselType.POST_TYPE_ANNOUNCE: + regionNewsProp.articlePanel.Notices.Add(item); + break; + case PostCarouselType.POST_TYPE_INFO: + regionNewsProp.articlePanel.Info.Add(item); + break; + } + } + } + + public async ValueTask GetCachedSprites(string URL, CancellationToken token) + { + string cacheFolder = Path.Combine(AppGameImgFolder, "cache"); + string cachePath = Path.Combine(cacheFolder, Path.GetFileNameWithoutExtension(URL)); + if (!Directory.Exists(cacheFolder)) + Directory.CreateDirectory(cacheFolder); + + FileInfo fInfo = new FileInfo(cachePath); + + if (!fInfo.Exists || fInfo.Length < (1 << 10)) + { + using (FileStream fs = fInfo.Create()) + using (Stream netStream = await FallbackCDNUtil.DownloadAsStream(URL, token)) + { + netStream.CopyTo(fs); + } + } + + return cachePath; + } + private uint SendTimeoutCancelationMessage(Exception ex, uint currentTimeout) { DispatcherQueue.TryEnqueue(() => @@ -201,7 +368,7 @@ private async void WatchAndCancelIfTimeout(CancellationTokenSource TokenSource, private void FinalizeLoadRegion(PresetConfigV2 preset) { // Log if region has been successfully loaded - LogWriteLine($"Initializing Region {preset.ZoneFullname} Done!", Hi3Helper.LogType.Scheme, true); + LogWriteLine($"Initializing Region {preset.ZoneFullname} Done!", LogType.Scheme, true); // Initializing Game Statics LoadGameStaticsByGameType(preset); @@ -215,59 +382,22 @@ private void FinalizeLoadRegion(PresetConfigV2 preset) private void LoadGameStaticsByGameType(PresetConfigV2 preset) { + GamePropertyVault.AttachNotifForCurrentGame(); DisposeAllPageStatics(); - switch (preset.GameType) - { - case GameType.Honkai: - // TEMP: - // This is used to handle FallbackGameType - if (preset.FallbackGameType == GameType.StarRail) - { - PageStatics._GameVersion = new GameTypeStarRailVersion(this, _gameAPIProp, preset); - PageStatics._GameSettings = new StarRailSettings(); - PageStatics._GameCache = null; - PageStatics._GameRepair = null; - PageStatics._GameInstall = new StarRailInstall(this); - - preset.GameType = GameType.StarRail; - } - else - { - PageStatics._GameVersion = new GameTypeHonkaiVersion(this, _gameAPIProp, preset); - PageStatics._GameSettings = new HonkaiSettings(); - PageStatics._GameCache = new HonkaiCache(this); - PageStatics._GameRepair = new HonkaiRepair(this); - PageStatics._GameInstall = new HonkaiInstall(this); - } - break; - case GameType.Genshin: - PageStatics._GameVersion = new GameTypeGenshinVersion(this, _gameAPIProp, preset); - PageStatics._GameSettings = new GenshinSettings(); - PageStatics._GameCache = null; - PageStatics._GameRepair = new GenshinRepair(this, PageStatics._GameVersion.GameAPIProp.data.game.latest.decompressed_path); - PageStatics._GameInstall = new GenshinInstall(this); - break; - case GameType.StarRail: - PageStatics._GameVersion = new GameTypeStarRailVersion(this, _gameAPIProp, preset); - PageStatics._GameSettings = new StarRailSettings(); - PageStatics._GameCache = new StarRailCache(this); - PageStatics._GameRepair = new StarRailRepair(this); - PageStatics._GameInstall = new StarRailInstall(this); - break; - } + GamePropertyVault.LoadGameProperty(this, _gameAPIProp, preset); // Spawn Region Notification - SpawnRegionNotification(PageStatics._GameVersion.GamePreset.ProfileName); + SpawnRegionNotification(preset.ProfileName); } private void DisposeAllPageStatics() { - PageStatics._GameInstall?.CancelRoutine(); - PageStatics._GameRepair?.CancelRoutine(); - PageStatics._GameRepair?.Dispose(); - PageStatics._GameCache?.CancelRoutine(); - PageStatics._GameCache?.Dispose(); + // CurrentGameProperty._GameInstall?.CancelRoutine(); + CurrentGameProperty?._GameRepair?.CancelRoutine(); + CurrentGameProperty?._GameRepair?.Dispose(); + CurrentGameProperty?._GameCache?.CancelRoutine(); + CurrentGameProperty?._GameCache?.Dispose(); #if DEBUG LogWriteLine("Page statics have been disposed!", LogType.Debug, true); #endif @@ -330,6 +460,7 @@ private async void ChangeRegionNoWarning(object sender, RoutedEventArgs e) await LoadRegionRootButton(); HideLoadingPopup(true, Lang._MainPage.RegionLoadingTitle, RegionToChangeName); MainFrameChanger.ChangeMainFrame(m_appMode == AppMode.Hi3CacheUpdater ? typeof(CachesPage) : typeof(HomePage)); + LauncherFrame.BackStack.Clear(); } private async void ChangeRegion(object sender, RoutedEventArgs e) @@ -385,6 +516,7 @@ private void ToggleChangeRegionBtn(in object sender, bool IsHide) ChangeRegionConfirmProgressBar.Visibility = Visibility.Collapsed; HideLoadingPopup(true, Lang._MainPage.RegionLoadingTitle, RegionToChangeName); MainFrameChanger.ChangeMainFrame(m_appMode == AppMode.Hi3CacheUpdater ? typeof(CachesPage) : typeof(HomePage)); + LauncherFrame.BackStack.Clear(); } (sender as Button).IsEnabled = !IsHide; diff --git a/CollapseLauncher/Classes/RegistryMonitor/RegistryMonitor.cs b/CollapseLauncher/Classes/RegistryMonitor/RegistryMonitor.cs index 8e294c144..7e98888b4 100644 --- a/CollapseLauncher/Classes/RegistryMonitor/RegistryMonitor.cs +++ b/CollapseLauncher/Classes/RegistryMonitor/RegistryMonitor.cs @@ -15,6 +15,7 @@ using System.Threading; using System.Runtime.InteropServices; using Microsoft.Win32; +using static Hi3Helper.Logger; namespace RegistryUtils { @@ -144,6 +145,11 @@ public RegistryMonitor(string name) public RegistryMonitor(RegistryHive registryHive, string subKey) { InitRegistryKey(registryHive, subKey); +#if DEBUG + LogWriteLine($"RegistryMonitor Initialized!\r\n" + + $" Hive: {registryHive}\r\n" + + $" subKey: {subKey}", Hi3Helper.LogType.Debug, true); +#endif } /// @@ -154,6 +160,9 @@ public void Dispose() Stop(); _disposed = true; GC.SuppressFinalize(this); +#if DEBUG + LogWriteLine($"RegistryMonitor Disposed!", Hi3Helper.LogType.Debug, true); +#endif } /// @@ -333,6 +342,11 @@ private void ThreadLoop() if (WaitHandle.WaitAny(waitHandles) == 0) { +#if DEBUG + LogWriteLine($"[RegistryMonitor] Found change(s) in registry!\r\n" + + $" Hive: {_registryHive}\r\n" + + $" subName: {_registrySubName}", Hi3Helper.LogType.Debug, true); +#endif OnRegChanged(); } } diff --git a/CollapseLauncher/Classes/RepairManagement/Genshin/Check.cs b/CollapseLauncher/Classes/RepairManagement/Genshin/Check.cs index e0ccfde73..032b7a134 100644 --- a/CollapseLauncher/Classes/RepairManagement/Genshin/Check.cs +++ b/CollapseLauncher/Classes/RepairManagement/Genshin/Check.cs @@ -74,7 +74,7 @@ private void TryMoveAudioPersistent() if (!Directory.Exists(audioPersistentPath)) return; if (!Directory.Exists(audioAsbPath)) Directory.CreateDirectory(audioAsbPath); - List audioLangList = ((GameTypeGenshinVersion)PageStatics._GameVersion)._audioVoiceLanguageList; + List audioLangList = ((GameTypeGenshinVersion)_gameVersionManager)._audioVoiceLanguageList; foreach (string path in Directory.EnumerateDirectories(audioPersistentPath, "*", SearchOption.TopDirectoryOnly)) { string langName = Path.GetFileName(path); diff --git a/CollapseLauncher/Classes/RepairManagement/Genshin/Fetch.cs b/CollapseLauncher/Classes/RepairManagement/Genshin/Fetch.cs index 2790c3da5..02eaab8d3 100644 --- a/CollapseLauncher/Classes/RepairManagement/Genshin/Fetch.cs +++ b/CollapseLauncher/Classes/RepairManagement/Genshin/Fetch.cs @@ -66,7 +66,7 @@ private async ValueTask> Fetch(List EliminateUnnecessaryAssetIndex(List assetIndex) { // Section: Eliminate unused audio files - List audioLangList = (PageStatics._GameVersion as GameTypeGenshinVersion)._audioVoiceLanguageList; + List audioLangList = (_gameVersionManager as GameTypeGenshinVersion)._audioVoiceLanguageList; string audioLangListPath = Path.Combine(_gamePath, $"{_execPrefix}_Data", "Persistent", "audio_lang_14"); // Get the list of audio lang list @@ -214,7 +214,7 @@ private void ParsePersistentManifest(string localManifestPath, while (!reader.EndOfStream) { string manifestLine = reader.ReadLine(); - PkgVersionProperties manifestEntry = (PkgVersionProperties)JsonSerializer.Deserialize(manifestLine, typeof(PkgVersionProperties), PkgVersionPropertiesContext.Default); + PkgVersionProperties manifestEntry = (PkgVersionProperties)JsonSerializer.Deserialize(manifestLine, typeof(PkgVersionProperties), CoreLibraryJSONContext.Default); // Ignore if the remote name is "svc_catalog" or "ctable.dat" if (Path.GetFileName(manifestEntry.remoteName).Equals("svc_catalog", StringComparison.OrdinalIgnoreCase) || @@ -301,7 +301,7 @@ private void SavePersistentRevision(QueryProperty dispatchQuery) private async Task GetDispatcherQuery(Http _httpClient, CancellationToken token) { // Initialize dispatch helper - using (GenshinDispatchHelper dispatchHelper = new GenshinDispatchHelper(_dispatcherRegionID, _gamePreset.ProtoDispatchKey, _dispatcherURL, _gameVersion.VersionString, token)) + using (GenshinDispatchHelper dispatchHelper = new GenshinDispatchHelper(_dispatcherRegionID, _gameVersionManager.GamePreset.ProtoDispatchKey, _dispatcherURL, _gameVersion.VersionString, token)) { // Get the master decryptor YSDispatchDec dispatchDecryptor = InitializeMasterDecryptor(); @@ -418,7 +418,7 @@ private void ParseManifestToAssetIndex(string manifestPath, List x.EndsWith(acceptedExtension, StringComparison.OrdinalIgnoreCase))) { // Deserialize JSON line into local entry. - entry = (PkgVersionProperties)JsonSerializer.Deserialize(data, typeof(PkgVersionProperties), PkgVersionPropertiesContext.Default); + entry = (PkgVersionProperties)JsonSerializer.Deserialize(data, typeof(PkgVersionProperties), CoreLibraryJSONContext.Default); // If the parent path is not defined, then use already-defined parent path from JSON and append it as remote name. if (!string.IsNullOrEmpty(parentPath)) diff --git a/CollapseLauncher/Classes/RepairManagement/Genshin/GenshinRepair.cs b/CollapseLauncher/Classes/RepairManagement/Genshin/GenshinRepair.cs index 6215dfec0..5097856b7 100644 --- a/CollapseLauncher/Classes/RepairManagement/Genshin/GenshinRepair.cs +++ b/CollapseLauncher/Classes/RepairManagement/Genshin/GenshinRepair.cs @@ -21,21 +21,21 @@ internal partial class GenshinRepair : ProgressBase, IRepair { #region ExtensionProperties - private protected string _execPrefix { get => Path.GetFileNameWithoutExtension(_gamePreset.GameExecutableName); } + private protected string _execPrefix { get => Path.GetFileNameWithoutExtension(_gameVersionManager.GamePreset.GameExecutableName); } private protected int _dispatcherRegionID { get; init; } - private protected string _dispatcherURL { get => _gamePreset.GameDispatchURL ?? ""; } - private protected string _dispatcherKey { get => _gamePreset.DispatcherKey ?? ""; } - private protected int _dispatcherKeyLength { get => _gamePreset.DispatcherKeyBitLength ?? 0x100; } - private protected string _gamePersistentPath { get => Path.Combine(_gamePath, $"{Path.GetFileNameWithoutExtension(_gamePreset.GameExecutableName)}_Data", "Persistent"); } - private protected string _gameStreamingAssetsPath { get => Path.Combine(_gamePath, $"{Path.GetFileNameWithoutExtension(_gamePreset.GameExecutableName)}_Data", "StreamingAssets"); } + private protected string _dispatcherURL { get => _gameVersionManager.GamePreset.GameDispatchURL ?? ""; } + private protected string _dispatcherKey { get => _gameVersionManager.GamePreset.DispatcherKey ?? ""; } + private protected int _dispatcherKeyLength { get => _gameVersionManager.GamePreset.DispatcherKeyBitLength ?? 0x100; } + private protected string _gamePersistentPath { get => Path.Combine(_gamePath, $"{Path.GetFileNameWithoutExtension(_gameVersionManager.GamePreset.GameExecutableName)}_Data", "Persistent"); } + private protected string _gameStreamingAssetsPath { get => Path.Combine(_gamePath, $"{Path.GetFileNameWithoutExtension(_gameVersionManager.GamePreset.GameExecutableName)}_Data", "StreamingAssets"); } private protected GenshinAudioLanguage _audioLanguage { get; init; } #endregion - public GenshinRepair(UIElement parentUI, string gameRepoURL) - : base(parentUI, null, gameRepoURL, null) + public GenshinRepair(UIElement parentUI, IGameVersionCheck GameVersionManager, string gameRepoURL) + : base(parentUI, GameVersionManager, null, gameRepoURL, null) { - _audioLanguage = (GenshinAudioLanguage)_gamePreset.GetVoiceLanguageID(); - _dispatcherRegionID = _gamePreset.GetRegServerNameID(); + _audioLanguage = (GenshinAudioLanguage)_gameVersionManager.GamePreset.GetVoiceLanguageID(); + _dispatcherRegionID = _gameVersionManager.GamePreset.GetRegServerNameID(); } ~GenshinRepair() => Dispose(); diff --git a/CollapseLauncher/Classes/RepairManagement/Honkai/Check.cs b/CollapseLauncher/Classes/RepairManagement/Honkai/Check.cs index 406ce8ef9..d0721922a 100644 --- a/CollapseLauncher/Classes/RepairManagement/Honkai/Check.cs +++ b/CollapseLauncher/Classes/RepairManagement/Honkai/Check.cs @@ -547,15 +547,19 @@ private void GetUnusedAssetIndexList(List catalog, List assetIndex, CancellationToke // Check for manifest. If it doesn't exist, then throw and warn the user if (!manifestDict.ContainsKey(_gameVersion.VersionString)) { - throw new VersionNotFoundException($"Manifest for {_gamePreset.ZoneName} (version: {_gameVersion.VersionString}) doesn't exist! Please contact @neon-nyan or open an issue for this!"); + throw new VersionNotFoundException($"Manifest for {_gameVersionManager.GamePreset.ZoneName} (version: {_gameVersion.VersionString}) doesn't exist! Please contact @neon-nyan or open an issue for this!"); } // Assign the URL based on the version @@ -276,14 +276,14 @@ private async Task> FetchMetadata(Http _httpClient, C using (MemoryStream mfs = new MemoryStream()) { // Set metadata URL - string urlMetadata = string.Format(AppGameRepoIndexURLPrefix, _gamePreset.ProfileName); + string urlMetadata = string.Format(AppGameRepoIndexURLPrefix, _gameVersionManager.GamePreset.ProfileName); // Start downloading metadata using FallbackCDNUtil await FallbackCDNUtil.DownloadCDNFallbackContent(_httpClient, mfs, urlMetadata, token); // Deserialize metadata mfs.Position = 0; - return (Dictionary)JsonSerializer.Deserialize(mfs, typeof(Dictionary), D_StringString.Default); + return (Dictionary)JsonSerializer.Deserialize(mfs, typeof(Dictionary), CoreLibraryJSONContext.Default); } } @@ -293,7 +293,7 @@ private async Task FetchAssetIndex(Http _httpClient, List using (MemoryStream mfs = new MemoryStream()) { // Set asset index URL - string urlIndex = string.Format(AppGameRepairIndexURLPrefix, _gamePreset.ProfileName, _gameVersion.VersionString) + ".bin"; + string urlIndex = string.Format(AppGameRepairIndexURLPrefix, _gameVersionManager.GamePreset.ProfileName, _gameVersion.VersionString) + ".bin"; // Start downloading asset index using FallbackCDNUtil await FallbackCDNUtil.DownloadCDNFallbackContent(_httpClient, mfs, urlIndex, token); diff --git a/CollapseLauncher/Classes/RepairManagement/Honkai/HonkaiRepair.cs b/CollapseLauncher/Classes/RepairManagement/Honkai/HonkaiRepair.cs index 5b2687735..aa8805aee 100644 --- a/CollapseLauncher/Classes/RepairManagement/Honkai/HonkaiRepair.cs +++ b/CollapseLauncher/Classes/RepairManagement/Honkai/HonkaiRepair.cs @@ -1,4 +1,5 @@ using CollapseLauncher.GameSettings.Honkai; +using CollapseLauncher.GameVersioning; using CollapseLauncher.Interfaces; using CollapseLauncher.Statics; using Hi3Helper.Data; @@ -16,11 +17,10 @@ internal partial class HonkaiRepair : ProgressBase, IRepair { #region Properties - private HonkaiCache _cacheUtil = (PageStatics._GameCache as ICacheBase).AsBaseType(); - private const ulong _assetIndexSignature = 0x657370616C6C6F43; // 657370616C6C6F43 is "Collapse" private const string _assetBasePath = "BH3_Data/StreamingAssets/"; private readonly string[] _skippableAssets = new string[] { "CG_Temp.usm" }; + private HonkaiCache _cacheUtil { get; init; } private string _assetBaseURL { get; set; } private string _blockBaseURL { get => ConverterTool.CombineURLFromString(_assetBaseURL, $"StreamingAsb/{string.Join('_', _gameVersion.VersionArray)}/pc/HD"); } private string _blockAsbBaseURL { get => ConverterTool.CombineURLFromString(_blockBaseURL, "/asb"); } @@ -41,21 +41,23 @@ internal partial class HonkaiRepair : private protected List _originAssetIndex { get; set; } #endregion - public HonkaiRepair(UIElement parentUI, bool onlyRecoverMainAsset = false, string versionOverride = null) - : base(parentUI, null, "", versionOverride) + public HonkaiRepair(UIElement parentUI, IGameVersionCheck GameVersionManager, ICache GameCacheManager, IGameSettings GameSettings, bool onlyRecoverMainAsset = false, string versionOverride = null) + : base(parentUI, GameVersionManager, GameSettings, null, "", versionOverride) { + _cacheUtil = (GameCacheManager as ICacheBase).AsBaseType(); + // Get flag to only recover main assets _isOnlyRecoverMain = onlyRecoverMainAsset; // Initialize audio asset language - string audioLanguage = (PageStatics._GameSettings as HonkaiSettings).SettingsAudio._userCVLanguage; + string audioLanguage = (GameSettings as HonkaiSettings).SettingsAudio._userCVLanguage; switch (audioLanguage) { case "Chinese(PRC)": _audioLanguage = AudioLanguageType.Chinese; break; default: - _audioLanguage = _gamePreset.GameDefaultCVLanguage; + _audioLanguage = _gameVersionManager.GamePreset.GameDefaultCVLanguage; break; } } diff --git a/CollapseLauncher/Classes/RepairManagement/StarRail/Check.cs b/CollapseLauncher/Classes/RepairManagement/StarRail/Check.cs index 8f464b0d3..8a2549f4d 100644 --- a/CollapseLauncher/Classes/RepairManagement/StarRail/Check.cs +++ b/CollapseLauncher/Classes/RepairManagement/StarRail/Check.cs @@ -35,7 +35,7 @@ await Task.Run(() => RestartStopwatch(); // Get persistent and streaming paths - string execName = Path.GetFileNameWithoutExtension(_gamePreset.GameExecutableName); + string execName = Path.GetFileNameWithoutExtension(_innerGameVersionManager.GamePreset.GameExecutableName); string baseBlocksPathPersistent = Path.Combine(_gamePath, @$"{execName}_Data\Persistent\Asb\Windows"); string baseBlocksPathStreaming = Path.Combine(_gamePath, @$"{execName}_Data\StreamingAssets\Asb\Windows"); @@ -99,7 +99,29 @@ private void CheckAssetType(FilePropertiesRemote asset, List AssetEntry.Add( + new AssetProperty( + Path.GetFileName(fileInfoStreaming.FullName), + RepairAssetType.Unused, + Path.GetDirectoryName(fileInfoStreaming.FullName), + asset.S, + null, + null + ) + )); + targetAssetIndex.Add(asset); + + LogWriteLine($"File [T: {asset.FT}]: {asset.N} is redundant (exist both on persistent and streaming)", LogType.Warning, true); + } // Check if both location has the file exist or has the size right if (UsePersistent && !IsPersistentExist && !IsStreamingExist) @@ -176,10 +198,21 @@ private void CheckAssetType(FilePropertiesRemote asset, List assetIndex, CancellationToke try { // Subscribe the fetching progress and subscribe StarRailMetadataTool progress to adapter - _gameVersionManager.StarRailMetadataTool.HttpEvent += _httpClient_FetchAssetProgress; + _innerGameVersionManager.StarRailMetadataTool.HttpEvent += _httpClient_FetchAssetProgress; // Initialize the metadata tool (including dispatcher and gateway) - await _gameVersionManager.StarRailMetadataTool.Initialize(token, GetExistingGameRegionID(), Path.Combine(_gamePath, $"{Path.GetFileNameWithoutExtension(_gamePreset.GameExecutableName)}_Data\\Persistent")); + await _innerGameVersionManager.StarRailMetadataTool.Initialize(token, GetExistingGameRegionID(), Path.Combine(_gamePath, $"{Path.GetFileNameWithoutExtension(_innerGameVersionManager.GamePreset.GameExecutableName)}_Data\\Persistent")); // Read block metadata and convert to FilePropertiesRemote - await _gameVersionManager.StarRailMetadataTool.ReadAsbMetadataInformation(token); - await _gameVersionManager.StarRailMetadataTool.ReadBlockMetadataInformation(token); - ConvertSRMetadataToAssetIndex(_gameVersionManager.StarRailMetadataTool.MetadataBlock, assetIndex); + await _innerGameVersionManager.StarRailMetadataTool.ReadAsbMetadataInformation(token); + await _innerGameVersionManager.StarRailMetadataTool.ReadBlockMetadataInformation(token); + ConvertSRMetadataToAssetIndex(_innerGameVersionManager.StarRailMetadataTool.MetadataBlock, assetIndex); // Read Audio metadata and convert to FilePropertiesRemote - await _gameVersionManager.StarRailMetadataTool.ReadAudioMetadataInformation(token); - ConvertSRMetadataToAssetIndex(_gameVersionManager.StarRailMetadataTool.MetadataAudio, assetIndex); + await _innerGameVersionManager.StarRailMetadataTool.ReadAudioMetadataInformation(token); + ConvertSRMetadataToAssetIndex(_innerGameVersionManager.StarRailMetadataTool.MetadataAudio, assetIndex, true); // Read Video metadata and convert to FilePropertiesRemote - await _gameVersionManager.StarRailMetadataTool.ReadVideoMetadataInformation(token); - ConvertSRMetadataToAssetIndex(_gameVersionManager.StarRailMetadataTool.MetadataVideo, assetIndex); + await _innerGameVersionManager.StarRailMetadataTool.ReadVideoMetadataInformation(token); + ConvertSRMetadataToAssetIndex(_innerGameVersionManager.StarRailMetadataTool.MetadataVideo, assetIndex); } finally { // Unsubscribe the fetching progress and dispose it and unsubscribe cacheUtil progress to adapter - _gameVersionManager.StarRailMetadataTool.HttpEvent -= _httpClient_FetchAssetProgress; + _innerGameVersionManager.StarRailMetadataTool.HttpEvent -= _httpClient_FetchAssetProgress; } } @@ -56,37 +57,57 @@ private async Task Fetch(List assetIndex, CancellationToke private unsafe string GetExistingGameRegionID() { #nullable enable - object? value = GameSettings.Statics.RegistryRoot?.GetValue("App_LastServerName_h2577443795", null); + // Try get the value as nullable object + object? value = RegistryRoot?.GetValue("App_LastServerName_h2577443795", null); + // Check if the value is null, then return the default name if (value == null) { - return _gamePreset.GameDispatchDefaultName ?? throw new KeyNotFoundException("Default dispatcher name in metadata is not exist!"); + // Return the dispatch default name. If none, then throw + return _innerGameVersionManager.GamePreset.GameDispatchDefaultName ?? throw new KeyNotFoundException("Default dispatcher name in metadata is not exist!"); } #nullable disable - ReadOnlySpan span = (value as byte[]).AsSpan(); - fixed (byte* valueSpan = span) - { - string name = Encoding.UTF8.GetString(valueSpan, span.Length - 1); - return name; - } + // Cast the value as byte span + ReadOnlySpan span = ((byte[])value).AsSpan(); + // Get the name from the span and trim the \0 character at the end + string name = Encoding.UTF8.GetString(span.Slice(0, span.Length - 1)); + return name; } - private void ConvertSRMetadataToAssetIndex(SRMetadataBase metadata, List assetIndex) + private void ConvertSRMetadataToAssetIndex(SRMetadataBase metadata, List assetIndex, bool writeAudioLangRedord = false) { - int voLangID = _gamePreset.GetVoiceLanguageID(); - string voLangName = _gamePreset.GetStarRailVoiceLanguageFullNameByID(voLangID); + // Get the voice Lang ID + int voLangID = _innerGameVersionManager.GamePreset.GetVoiceLanguageID(); + // Get the voice Lang name by ID + string voLangName = _innerGameVersionManager.GamePreset.GetStarRailVoiceLanguageFullNameByID(voLangID); - IEnumerable srAssetEnumerateFiltered = metadata.GetAssets().AssetList; + // If prompt to write Redord file + if (writeAudioLangRedord) + { + // Get game executable name, directory and file path + string execName = Path.GetFileNameWithoutExtension(_innerGameVersionManager.GamePreset.GameExecutableName); + string audioRedordDir = Path.Combine(_gamePath, @$"{execName}_Data\Persistent\Audio\AudioPackage\Windows"); + string audioRedordPath = Path.Combine(audioRedordDir, "AudioLangRedord.txt"); + + // Create the directory if not exist + if (!Directory.Exists(audioRedordDir)) Directory.CreateDirectory(audioRedordDir); + // Then write the Redord file content + File.WriteAllText(audioRedordPath, "{\"AudioLang\":\"" + voLangName + "\"}"); + } int count = 0; long countSize = 0; - foreach (SRAsset asset in srAssetEnumerateFiltered) + // Enumerate the Asset List + foreach (SRAsset asset in metadata.EnumerateAssets()) { - if (IsAudioLangFile(asset, voLangName, out bool isHasHashMark)) - { - string hash = HexTool.BytesToHexUnsafe(asset.Hash); + // Get the hash by bytes + string hash = HexTool.BytesToHexUnsafe(asset.Hash); + // Filter only current audio language file and other assets + if (FilterCurrentAudioLangFile(asset, voLangName, out bool IsHasHashMark)) + { + // Convert and add the asset as FilePropertiesRemote to assetIndex assetIndex.Add(new FilePropertiesRemote { N = asset.LocalName, @@ -95,7 +116,7 @@ private void ConvertSRMetadataToAssetIndex(SRMetadataBase metadata, List 1, then start do filtering if (nameDef.Length > 1) { - return (isHasHashMark = nameDef[0] == langName) || nameDef[0] == "SFX"; + // Compare if the first name definition is equal to target langName. + // Also return if the file is an audio language file if it is a SFX file or not. + return nameDef[0] == langName || nameDef[0] == "SFX"; } + // If it's not in criteria of name definition, then return true as "normal asset" return true; default: + // return true as "normal asset" return true; } } diff --git a/CollapseLauncher/Classes/RepairManagement/StarRail/Repair.cs b/CollapseLauncher/Classes/RepairManagement/StarRail/Repair.cs index 57b039d8d..7154029ad 100644 --- a/CollapseLauncher/Classes/RepairManagement/StarRail/Repair.cs +++ b/CollapseLauncher/Classes/RepairManagement/StarRail/Repair.cs @@ -76,9 +76,23 @@ private async Task RepairAssetTypeGeneric(FilePropertiesRemote asset, Http _http string.Format(Lang._GameRepairPage.PerProgressSubtitle2, ConverterTool.SummarizeSizeSimple(_progressTotalSizeCurrent), ConverterTool.SummarizeSizeSimple(_progressTotalSize)), true); - // Start asset download task - await RunDownloadTask(asset.S, asset.N, asset.RN, _httpClient, token); - LogWriteLine($"File [T: {asset.FT}] {(asset.FT == FileType.Blocks ? asset.CRC : asset.N)} has been downloaded!", LogType.Default, true); + // If asset type is unused, then delete it + if (asset.FT == FileType.Unused) + { + FileInfo fileInfo = new FileInfo(asset.N); + if (fileInfo.Exists) + { + fileInfo.IsReadOnly = false; + fileInfo.Delete(); + LogWriteLine($"File [T: {asset.FT}] {(asset.FT == FileType.Blocks ? asset.CRC : asset.N)} deleted!", LogType.Default, true); + } + } + else + { + // Start asset download task + await RunDownloadTask(asset.S, asset.N, asset.RN, _httpClient, token); + LogWriteLine($"File [T: {asset.FT}] {(asset.FT == FileType.Blocks ? asset.CRC : asset.N)} has been downloaded!", LogType.Default, true); + } // Pop repair asset display entry PopRepairAssetEntry(); diff --git a/CollapseLauncher/Classes/RepairManagement/StarRail/StarRailRepair.cs b/CollapseLauncher/Classes/RepairManagement/StarRail/StarRailRepair.cs index 5f7eaa9f4..277962526 100644 --- a/CollapseLauncher/Classes/RepairManagement/StarRail/StarRailRepair.cs +++ b/CollapseLauncher/Classes/RepairManagement/StarRail/StarRailRepair.cs @@ -1,6 +1,5 @@ using CollapseLauncher.GameVersioning; using CollapseLauncher.Interfaces; -using CollapseLauncher.Statics; using Hi3Helper.Data; using Hi3Helper.Shared.ClassStruct; using Microsoft.UI.Xaml; @@ -14,15 +13,16 @@ internal partial class StarRailRepair : ProgressBase, IRepair { #region Properties - private GameTypeStarRailVersion _gameVersionManager { get => PageStatics._GameVersion as GameTypeStarRailVersion; } + private GameTypeStarRailVersion _innerGameVersionManager { get; set; } private bool _isOnlyRecoverMain { get; set; } #endregion - public StarRailRepair(UIElement parentUI, bool onlyRecoverMainAsset = false, string versionOverride = null) - : base(parentUI, null, "", versionOverride) + public StarRailRepair(UIElement parentUI, IGameVersionCheck GameVersionManager, bool onlyRecoverMainAsset = false, string versionOverride = null) + : base(parentUI, GameVersionManager, null, "", versionOverride) { // Get flag to only recover main assets _isOnlyRecoverMain = onlyRecoverMainAsset; + _innerGameVersionManager = GameVersionManager as GameTypeStarRailVersion; } ~StarRailRepair() => Dispose(); diff --git a/CollapseLauncher/CollapseLauncher.csproj b/CollapseLauncher/CollapseLauncher.csproj index ecde80e64..274003dd8 100644 --- a/CollapseLauncher/CollapseLauncher.csproj +++ b/CollapseLauncher/CollapseLauncher.csproj @@ -9,7 +9,7 @@ preview Debug;Release;Publish true - 1.71.2 + 1.71.3 portable app.manifest CollapseLauncher.MainEntryPoint @@ -20,10 +20,10 @@ true true true + true DISABLE_XAML_GENERATED_MAIN;PREVIEW;DISABLETRANSPARENT;DISABLEMOVEMIGRATE - False DISABLE_XAML_GENERATED_MAIN;PREVIEW;DISABLETRANSPARENT;DISABLEMOVEMIGRATE @@ -34,7 +34,7 @@ True - + @@ -43,7 +43,7 @@ - + @@ -59,49 +59,81 @@ Always + Always + Always + + + Always + + + + Always + + + + Always + + + + Always + + - + + Always - + + Always - + + Always - + + Always - + + Always - + + Always - + + Always + Always + Always + Always + Always + Always + Always diff --git a/CollapseLauncher/Properties/PublishProfiles/Publish-PreviewRelease.pubxml b/CollapseLauncher/Properties/PublishProfiles/Publish-PreviewRelease.pubxml index 64d7f6c20..f6567951c 100644 --- a/CollapseLauncher/Properties/PublishProfiles/Publish-PreviewRelease.pubxml +++ b/CollapseLauncher/Properties/PublishProfiles/Publish-PreviewRelease.pubxml @@ -12,7 +12,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121. win-x64 true true - false + true true partial diff --git a/CollapseLauncher/Properties/PublishProfiles/Publish-StableRelease.pubxml b/CollapseLauncher/Properties/PublishProfiles/Publish-StableRelease.pubxml index bb695f7ad..afaff8aa4 100644 --- a/CollapseLauncher/Properties/PublishProfiles/Publish-StableRelease.pubxml +++ b/CollapseLauncher/Properties/PublishProfiles/Publish-StableRelease.pubxml @@ -12,7 +12,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121. win-x64 true true - false + true true partial diff --git a/CollapseLauncher/XAMLs/Invoker/Classes/Migrate.cs b/CollapseLauncher/XAMLs/Invoker/Classes/Migrate.cs index 6bb4172f8..0bc2d80ec 100644 --- a/CollapseLauncher/XAMLs/Invoker/Classes/Migrate.cs +++ b/CollapseLauncher/XAMLs/Invoker/Classes/Migrate.cs @@ -67,7 +67,7 @@ public void DoMigrationBHI3L(string version, string registryName, string sourceG Registry.CurrentUser.OpenSubKey(@"Software\Bp\Better HI3 Launcher", true) .SetValue(registryName, - Encoding.UTF8.GetBytes(JsonSerializer.Serialize(info, typeof(BHI3LInfo), BHI3LInfoContext.Default)), + Encoding.UTF8.GetBytes(JsonSerializer.Serialize(info, typeof(BHI3LInfo), CoreLibraryJSONContext.Default)), RegistryValueKind.Binary); } catch (Exception ex) diff --git a/CollapseLauncher/XAMLs/MainApp/DisconnectedPage.xaml b/CollapseLauncher/XAMLs/MainApp/DisconnectedPage.xaml index 46ba53d82..a1641f0ea 100644 --- a/CollapseLauncher/XAMLs/MainApp/DisconnectedPage.xaml +++ b/CollapseLauncher/XAMLs/MainApp/DisconnectedPage.xaml @@ -21,7 +21,7 @@ - diff --git a/CollapseLauncher/XAMLs/MainApp/MainPage.xaml b/CollapseLauncher/XAMLs/MainApp/MainPage.xaml index 9e3ab8525..22ccc43fe 100644 --- a/CollapseLauncher/XAMLs/MainApp/MainPage.xaml +++ b/CollapseLauncher/XAMLs/MainApp/MainPage.xaml @@ -15,140 +15,32 @@ - - + + + Loaded="NavView_Loaded" + BackRequested="NavigationViewControl_BackRequested" + PaneOpening="NavigationPanelOpening_Event" + PaneClosing="NavigationPanelClosing_Event"> - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -175,13 +67,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -193,7 +195,7 @@ - + diff --git a/CollapseLauncher/XAMLs/MainApp/MainPage.xaml.cs b/CollapseLauncher/XAMLs/MainApp/MainPage.xaml.cs index 06bfd3c57..49f12c60d 100644 --- a/CollapseLauncher/XAMLs/MainApp/MainPage.xaml.cs +++ b/CollapseLauncher/XAMLs/MainApp/MainPage.xaml.cs @@ -21,6 +21,7 @@ using Windows.Foundation; using Windows.Graphics; using static CollapseLauncher.InnerLauncherConfig; +using static CollapseLauncher.Statics.GamePropertyVault; using static Hi3Helper.Locale; using static Hi3Helper.Logger; using static Hi3Helper.Preset.ConfigV2Store; @@ -31,6 +32,7 @@ namespace CollapseLauncher public partial class MainPage : Page { private bool LockRegionChangeBtn; + private bool IsLoadFrameCompleted = true; public static bool IsChangeDragArea = true; private RectInt32[] DragAreaMode_Normal @@ -194,17 +196,21 @@ private void SubscribeEvents() MainFrameChangerInvoker.FrameEvent += MainFrameChangerInvoker_FrameEvent; NotificationInvoker.EventInvoker += NotificationInvoker_EventInvoker; BackgroundImgChangerInvoker.ImgEvent += CustomBackgroundChanger_Event; + BackgroundImgChangerInvoker.IsImageHide += BackgroundImg_IsImageHideEvent; SpawnWebView2Invoker.SpawnEvent += SpawnWebView2Invoker_SpawnEvent; ShowLoadingPageInvoker.PageEvent += ShowLoadingPageInvoker_PageEvent; ChangeTitleDragAreaInvoker.TitleBarEvent += ChangeTitleDragAreaInvoker_TitleBarEvent; } + private void BackgroundImg_IsImageHideEvent(object sender, bool e) => HideBackgroundImage(e); + private void UnsubscribeEvents() { ErrorSenderInvoker.ExceptionEvent -= ErrorSenderInvoker_ExceptionEvent; MainFrameChangerInvoker.FrameEvent -= MainFrameChangerInvoker_FrameEvent; NotificationInvoker.EventInvoker -= NotificationInvoker_EventInvoker; BackgroundImgChangerInvoker.ImgEvent -= CustomBackgroundChanger_Event; + BackgroundImgChangerInvoker.IsImageHide -= BackgroundImg_IsImageHideEvent; SpawnWebView2Invoker.SpawnEvent -= SpawnWebView2Invoker_SpawnEvent; ShowLoadingPageInvoker.PageEvent -= ShowLoadingPageInvoker_PageEvent; ChangeTitleDragAreaInvoker.TitleBarEvent -= ChangeTitleDragAreaInvoker_TitleBarEvent; @@ -225,7 +231,7 @@ private void ChangeTitleDragAreaInvoker_TitleBarEvent(object sender, ChangeTitle private void ShowLoadingPageInvoker_PageEvent(object sender, ShowLoadingPageProperty e) { - HideBackgroundImage(!e.Hide); + BackgroundImgChanger.ToggleBackground(e.Hide); HideLoadingPopup(e.Hide, e.Title, e.Subtitle); } @@ -280,7 +286,7 @@ private async void CheckRunningGameInstance() { while (true && !App.IsAppKilled) { - string execName = Path.GetFileNameWithoutExtension(PageStatics._GameVersion.GamePreset.GameExecutableName); + string execName = Path.GetFileNameWithoutExtension(CurrentGameProperty._GameVersion.GamePreset.GameExecutableName); App.IsGameRunning = Process.GetProcessesByName(execName).Length != 0 && !App.IsAppKilled; await Task.Delay(500); } @@ -288,6 +294,19 @@ private async void CheckRunningGameInstance() private void NotificationInvoker_EventInvoker(object sender, NotificationInvokerProp e) { + if (e.IsCustomNotif) + { + if (e.CustomNotifAction == NotificationCustomAction.Add) + { + SpawnNotificationoUI(e.Notification.MsgId, e.OtherContent as InfoBar); + } + else + { + RemoveNotificationUI(e.Notification.MsgId); + } + return; + } + SpawnNotificationPush(e.Notification.Title, e.Notification.Message, e.Notification.Severity, e.Notification.MsgId, e.Notification.IsClosable ?? true, e.Notification.IsDisposable ?? true, e.CloseAction, e.OtherContent, e.IsAppNotif, e.Notification.Show, e.Notification.IsForceShowNotificationPanel); @@ -343,7 +362,7 @@ private async Task FetchNotificationFeed() { await FallbackCDNUtil.DownloadCDNFallbackContent(_http, fs, string.Format(AppNotifURLPrefix, IsPreview ? "preview" : "stable"), TokenSource.Token); fs.Position = 0; - NotificationData = (NotificationPush)JsonSerializer.Deserialize(fs, typeof(NotificationPush), NotificationPushContext.Default); + NotificationData = (NotificationPush)JsonSerializer.Deserialize(fs, typeof(NotificationPush), InternalAppJSONContext.Default); IsLoadNotifComplete = true; NotificationData.EliminatePushList(); @@ -539,8 +558,6 @@ private void SpawnNotificationPush(string Title, string Content, NotifSeverity S DispatcherQueue.TryEnqueue(() => { - Grid Container = new Grid(); - StackPanel OtherContentContainer = new StackPanel { Orientation = Orientation.Vertical, @@ -587,29 +604,8 @@ private void SpawnNotificationPush(string Title, string Content, NotifSeverity S Notification.Tag = MsgId; Notification.CloseButtonClick += CloseClickHandler; - Notification.Loaded += (a, b) => - { - NoNotificationIndicator.Opacity = NotificationContainer.Children.Count > 0 ? 0f : 1f; - NewNotificationCountBadge.Visibility = Visibility.Visible; - NewNotificationCountBadge.Value++; - }; - Notification.Closed += (s, a) => - { - s.Translation -= Shadow32; - s.Height = 0; - s.Margin = new Thickness(0); - int msg = (int)s.Tag; - if (NotificationData.CurrentShowMsgIds.Contains(msg)) - { - NotificationData.CurrentShowMsgIds.Remove(msg); - } - NotificationContainer.Children.Remove(Container); - NoNotificationIndicator.Opacity = NotificationContainer.Children.Count > 0 ? 0f : 1f; - }; - - Container.Children.Add(Notification); - NotificationContainer.Children.Add(Container); + SpawnNotificationoUI(MsgId, Notification); if (ForceShowNotificationPanel && !IsNotificationPanelShow) { @@ -618,6 +614,56 @@ private void SpawnNotificationPush(string Title, string Content, NotifSeverity S }); } + private void SpawnNotificationoUI(int tagID, InfoBar Notification) + { + Grid Container = new Grid() { Tag = tagID, }; + Notification.Loaded += (a, b) => + { + NoNotificationIndicator.Opacity = NotificationContainer.Children.Count > 0 ? 0f : 1f; + NewNotificationCountBadge.Visibility = Visibility.Visible; + NewNotificationCountBadge.Value++; + }; + + Notification.Closed += (s, a) => + { + s.Translation -= Shadow32; + s.Height = 0; + s.Margin = new Thickness(0); + int msg = (int)s.Tag; + + if (NotificationData.CurrentShowMsgIds.Contains(msg)) + { + NotificationData.CurrentShowMsgIds.Remove(msg); + } + NotificationContainer.Children.Remove(Container); + NoNotificationIndicator.Opacity = NotificationContainer.Children.Count > 0 ? 0f : 1f; + + if (NewNotificationCountBadge.Value > 0) + { + NewNotificationCountBadge.Value--; + } + NoNotificationIndicator.Opacity = NotificationContainer.Children.Count > 0 ? 0f : 1f; + NewNotificationCountBadge.Visibility = NotificationContainer.Children.Count > 0 ? Visibility.Visible : Visibility.Collapsed; + }; + + Container.Children.Add(Notification); + NotificationContainer.Children.Add(Container); + } + + private void RemoveNotificationUI(int tagID) + { + Grid notif = NotificationContainer.Children.OfType().Where(x => (int)x.Tag == tagID).FirstOrDefault(); + if (notif != null) + { + NotificationContainer.Children.Remove(notif); + InfoBar notifBar = notif.Children.OfType()?.FirstOrDefault(); + if (notifBar != null) + { + notifBar.IsOpen = false; + } + } + } + private void NeverAskNotif_Checked(object sender, RoutedEventArgs e) { string[] Data = (sender as CheckBox).Tag.ToString().Split(','); @@ -876,24 +922,24 @@ private void InitializeNavigationItems() NavigationViewControl.MenuItems.Add(new NavigationViewItem() { Content = Lang._HomePage.PageTitle, Icon = IconLauncher, Tag = "launcher" }); - if ((PageStatics._GameVersion.GamePreset.IsCacheUpdateEnabled ?? false) || (PageStatics._GameVersion.GamePreset.IsRepairEnabled ?? false)) + if ((GetCurrentGameProperty()._GameVersion.GamePreset.IsCacheUpdateEnabled ?? false) || (GetCurrentGameProperty()._GameVersion.GamePreset.IsRepairEnabled ?? false)) { - NavigationViewControl.MenuItems.Add(new NavigationViewItemSeparator()); + NavigationViewControl.MenuItems.Add(new NavigationViewItemHeader() { Content = "Utilities" }); - if (PageStatics._GameVersion.GamePreset.IsRepairEnabled ?? false) + if (GetCurrentGameProperty()._GameVersion.GamePreset.IsRepairEnabled ?? false) { NavigationViewControl.MenuItems.Add(new NavigationViewItem() { Content = Lang._GameRepairPage.PageTitle, Icon = IconRepair, Tag = "repair" }); } - if (PageStatics._GameVersion.GamePreset.IsCacheUpdateEnabled ?? false) + if (GetCurrentGameProperty()._GameVersion.GamePreset.IsCacheUpdateEnabled ?? false) { NavigationViewControl.MenuItems.Add(new NavigationViewItem() { Content = Lang._CachesPage.PageTitle, Icon = IconCaches, Tag = "caches" }); } } - switch (PageStatics._GameVersion.GameType) + switch (GetCurrentGameProperty()._GameVersion.GameType) { case GameType.Honkai: NavigationViewControl.MenuItems.Add(new NavigationViewItem() @@ -905,7 +951,7 @@ private void InitializeNavigationItems() break; } - if (PageStatics._GameVersion.GameType == GameType.Genshin) + if (GetCurrentGameProperty()._GameVersion.GameType == GameType.Genshin) { NavigationViewControl.MenuItems.Add(new NavigationViewItem() { Content = Lang._GenshinGameSettingsPage.PageTitle, Icon = IconGameSettings, Tag = "genshingamesettings" }); @@ -930,82 +976,57 @@ private void NavView_Loaded(object sender, RoutedEventArgs e) private void NavView_ItemInvoked(NavigationView sender, NavigationViewItemInvokedEventArgs args) { - if (args.IsSettingsInvoked) - { - MainFrameChanger.ChangeMainFrame(typeof(SettingsPage)); - PreviousTag = "settings"; - LogWriteLine($"Page changed to App Settings", LogType.Scheme); - } - else + if (!IsLoadFrameCompleted) return; + if (args.IsSettingsInvoked && PreviousTag != "settings") Navigate(typeof(SettingsPage), "settings"); + + NavigationViewItem item = sender.MenuItems.OfType().FirstOrDefault(x => (string)x.Content == (string)args.InvokedItem); + if (item == null) return; + + string itemTag = (string)item.Tag; + if (itemTag == PreviousTag) return; + + switch (itemTag) { - if (sender.MenuItems.Count != 0) - { - var item = sender.MenuItems.OfType().FirstOrDefault(x => (string)x.Content == (string)args.InvokedItem); - NavView_Navigate(item); - } - else - { - MainFrameChanger.ChangeMainFrame(typeof(HomePage), new DrillInNavigationTransitionInfo()); - } + case "launcher": + Navigate(typeof(HomePage), itemTag); + break; + + case "repair": + if (!(GetCurrentGameProperty()._GameVersion.GamePreset.IsRepairEnabled ?? false)) + Navigate(typeof(UnavailablePage), itemTag); + else + Navigate(IsGameInstalled() ? typeof(RepairPage) : typeof(NotInstalledPage), itemTag); + break; + + case "caches": + if (GetCurrentGameProperty()._GameVersion.GamePreset.IsCacheUpdateEnabled ?? false) + Navigate(IsGameInstalled() ? typeof(CachesPage) : typeof(NotInstalledPage), itemTag); + else + Navigate(typeof(UnavailablePage), itemTag); + break; + + case "gamesettings": + Navigate(IsGameInstalled() ? typeof(GameSettingsPage) : typeof(NotInstalledPage), itemTag); + break; + + case "starrailgamesettings": + Navigate(IsGameInstalled() ? typeof(StarRailGameSettingsPage) : typeof(NotInstalledPage), itemTag); + break; + + case "genshingamesettings": + Navigate(IsGameInstalled() ? typeof(GenshinGameSettingsPage) : typeof(NotInstalledPage), itemTag); + break; } } - void Navigate(Type sourceType, bool hideImage, NavigationViewItem tag) + private List PreviousTagString = new List(); + + void Navigate(Type sourceType, string tagStr) { - string tagStr = (string)tag.Tag; MainFrameChanger.ChangeMainFrame(sourceType, new DrillInNavigationTransitionInfo()); PreviousTag = tagStr; - } - - private void NavView_Navigate(NavigationViewItem item) - { - try - { - if (!(PreviousTag == (string)item.Tag)) - { - switch (item.Tag) - { - case "launcher": - Navigate(typeof(HomePage), false, item); - break; - - case "repair": - if (!(PageStatics._GameVersion.GamePreset.IsRepairEnabled ?? false)) - Navigate(typeof(UnavailablePage), true, item); - else - Navigate(IsGameInstalled() ? typeof(RepairPage) : typeof(NotInstalledPage), true, item); - break; - - case "caches": - if (PageStatics._GameVersion.GamePreset.IsCacheUpdateEnabled ?? false) - Navigate(IsGameInstalled() ? typeof(CachesPage) : typeof(NotInstalledPage), true, item); - else - Navigate(typeof(UnavailablePage), true, item); - break; - - case "cutscenes": - throw new NotImplementedException("Cutscenes Downloading Page isn't yet implemented for now."); - - case "gamesettings": - Navigate(IsGameInstalled() ? typeof(GameSettingsPage) : typeof(NotInstalledPage), true, item); - break; - - case "starrailgamesettings": - Navigate(IsGameInstalled() ? typeof(StarRailGameSettingsPage) : typeof(NotInstalledPage), true, item); - break; - - case "genshingamesettings": - Navigate(IsGameInstalled() ? typeof(GenshinGameSettingsPage) : typeof(NotInstalledPage), true, item); - break; - } - LogWriteLine($"Page changed to {item.Content}", LogType.Scheme); - } - } - catch (Exception ex) - { - LogWriteLine($"{ex}", LogType.Error, true); - ErrorSender.SendException(ex); - } + PreviousTagString.Add(tagStr); + LogWriteLine($"Page changed to {sourceType.Name} with Tag: {tagStr}", LogType.Scheme); } private bool IsGameInstalled() => GameInstallationState == GameInstallStateEnum.Installed || @@ -1034,13 +1055,11 @@ private void ErrorSenderInvoker_ExceptionEvent(object sender, ErrorProperties e) if (e.Exception.GetType() == typeof(NotImplementedException)) { PreviousTag = "unavailable"; - HideBackgroundImage(); MainFrameChanger.ChangeMainFrame(typeof(UnavailablePage)); } else { PreviousTag = "crashinfo"; - HideBackgroundImage(); MainFrameChanger.ChangeMainFrame(typeof(UnhandledExceptionPage)); } }); @@ -1048,30 +1067,10 @@ private void ErrorSenderInvoker_ExceptionEvent(object sender, ErrorProperties e) private void MainFrameChangerInvoker_FrameEvent(object sender, MainFrameProperties e) { - switch (e.FrameTo.Name) - { - case "HomePage": - HideBackgroundImage(false); - LauncherFrame.Navigate(e.FrameTo, null, e.Transition); - break; - case "RepairPage": - PreviousTag = "repair"; - IList menuItems = NavigationViewControl.MenuItems; - if (menuItems != null && menuItems.Count > 2) - { - NavigationViewControl.SelectedItem = (NavigationViewItem)menuItems[2]; - } - HideBackgroundImage(); - LauncherFrame.Navigate(e.FrameTo, null, e.Transition); - break; - default: - case "UnhandledExceptionPage": - case "BlankPage": - HideBackgroundImage(); - LauncherFrame.Navigate(e.FrameTo, null, e.Transition); - break; - } + IsLoadFrameCompleted = false; m_appCurrentFrameName = e.FrameTo.Name; + LauncherFrame.Navigate(e.FrameTo, null, e.Transition); + IsLoadFrameCompleted = true; } private void SpawnWebView2Panel(Uri URL) @@ -1145,5 +1144,114 @@ private void NotificationContainerBackground_PointerPressed(object sender, Micro ToggleNotificationPanelBtn.IsChecked = false; ShowHideNotificationPanel(); } + + private void NavigationViewControl_BackRequested(NavigationView sender, NavigationViewBackRequestedEventArgs args) + { + if (LauncherFrame.CanGoBack && IsLoadFrameCompleted) + { + LauncherFrame.GoBack(); + if (PreviousTagString.Count < 1) return; + + string lastPreviousTag = PreviousTagString[PreviousTagString.Count - 1]; + string currentNavigationItemTag = (string)((NavigationViewItem)sender.SelectedItem).Tag; + + if (lastPreviousTag.ToLower() == currentNavigationItemTag.ToLower()) + { + string goLastPreviousTag = PreviousTagString[PreviousTagString.Count - 2]; + NavigationViewItem goPreviousNavigationItem = sender.MenuItems.OfType().Where(x => goLastPreviousTag == (string)x.Tag).FirstOrDefault(); + + if (goLastPreviousTag == "settings") + { + PreviousTag = goLastPreviousTag; + PreviousTagString.RemoveAt(PreviousTagString.Count - 1); + sender.SelectedItem = sender.SettingsItem; + return; + } + + if (goPreviousNavigationItem != null) + { + PreviousTag = goLastPreviousTag; + PreviousTagString.RemoveAt(PreviousTagString.Count - 1); + sender.SelectedItem = goPreviousNavigationItem; + } + } + } + } + + private bool IsTitleIconForceShow = false; + + private void NavigationPanelOpening_Event(NavigationView sender, object args) + { + Thickness curMargin = GridBG_Icon.Margin; + curMargin.Left = 48; + GridBG_Icon.Margin = curMargin; + IsTitleIconForceShow = true; + ToggleTitleIcon(false); + } + + private void NavigationPanelClosing_Event(NavigationView sender, NavigationViewPaneClosingEventArgs args) + { + Thickness curMargin = GridBG_Icon.Margin; + curMargin.Left = 58; + GridBG_Icon.Margin = curMargin; + IsTitleIconForceShow = false; + ToggleTitleIcon(true); + } + + private void ToggleTitleIcon(bool hide) + { + if (!hide) + { + GridBG_IconTitle.Width = double.NaN; + if (PreviewBuildIndicator.Visibility == Visibility.Collapsed) + GridBG_IconTitle.Visibility = Visibility.Visible; + return; + } + + GridBG_IconTitle.Width = 0; + if (PreviewBuildIndicator.Visibility == Visibility.Collapsed) + GridBG_IconTitle.Visibility = Visibility.Collapsed; + } + + private void GridBG_Icon_PointerEntered(object sender, Microsoft.UI.Xaml.Input.PointerRoutedEventArgs e) + { + if (!IsTitleIconForceShow) + { + Thickness curMargin = GridBG_Icon.Margin; + curMargin.Left = 50; + GridBG_Icon.Margin = curMargin; + ToggleTitleIcon(false); + } + } + + private void GridBG_Icon_PointerExited(object sender, Microsoft.UI.Xaml.Input.PointerRoutedEventArgs e) + { + if (!IsTitleIconForceShow) + { + Thickness curMargin = GridBG_Icon.Margin; + curMargin.Left = 58; + GridBG_Icon.Margin = curMargin; + ToggleTitleIcon(true); + } + } + + private void GridBG_Icon_Click(object sender, RoutedEventArgs e) + { + if (PreviousTag.ToLower() == "launcher") return; + + MainFrameChanger.ChangeMainFrame(typeof(HomePage)); + PreviousTag = "launcher"; + PreviousTagString.Add(PreviousTag); + + NavigationViewItem navItem = NavigationViewControl.MenuItems + .OfType() + .Where(x => ((string)x.Tag).ToLower() == PreviousTag) + .FirstOrDefault(); + + if (navItem != null) + { + NavigationViewControl.SelectedItem = navItem; + } + } } } diff --git a/CollapseLauncher/XAMLs/MainApp/MainWindow.xaml.cs b/CollapseLauncher/XAMLs/MainApp/MainWindow.xaml.cs index 251f8607e..bf099aa70 100644 --- a/CollapseLauncher/XAMLs/MainApp/MainWindow.xaml.cs +++ b/CollapseLauncher/XAMLs/MainApp/MainWindow.xaml.cs @@ -37,7 +37,7 @@ public void InitializeWindowProperties() try { InitializeWindowSettings(); - m_appWindow.TitleBar.PreferredHeightOption = TitleBarHeightOption.Tall; + if (m_appWindow.TitleBar.ExtendsContentIntoTitleBar) m_appWindow.TitleBar.PreferredHeightOption = TitleBarHeightOption.Tall; if (IsFirstInstall) { @@ -68,6 +68,7 @@ public void StartMainPage() { SetWindowSize(m_windowHandle, WindowSize.WindowSize.CurrentWindowSize.WindowBounds.Width, WindowSize.WindowSize.CurrentWindowSize.WindowBounds.Height); rootFrame.Navigate(typeof(MainPage), null, new DrillInNavigationTransitionInfo()); + // rootFrame.Navigate(typeof(MainPageNew), null, new DrillInNavigationTransitionInfo()); } private void InitializeAppWindowAndIntPtr() diff --git a/CollapseLauncher/XAMLs/MainApp/Pages/CachesPage.xaml b/CollapseLauncher/XAMLs/MainApp/Pages/CachesPage.xaml index cd02529d0..baf8caae7 100644 --- a/CollapseLauncher/XAMLs/MainApp/Pages/CachesPage.xaml +++ b/CollapseLauncher/XAMLs/MainApp/Pages/CachesPage.xaml @@ -11,7 +11,7 @@ mc:Ignorable="d" Loaded="InitializeLoaded" Unloaded="Page_Unloaded"> - + @@ -32,7 +32,7 @@ IsReadOnly="True" AutoGenerateColumns="False" CanUserSortColumns="True" - ItemsSource="{x:Bind statics:PageStatics._GameCache.AssetEntry}"> + ItemsSource="{x:Bind CurrentGameProperty._GameCache.AssetEntry}"> diff --git a/CollapseLauncher/XAMLs/MainApp/Pages/CachesPage.xaml.cs b/CollapseLauncher/XAMLs/MainApp/Pages/CachesPage.xaml.cs index df18935c4..832854f35 100644 --- a/CollapseLauncher/XAMLs/MainApp/Pages/CachesPage.xaml.cs +++ b/CollapseLauncher/XAMLs/MainApp/Pages/CachesPage.xaml.cs @@ -1,4 +1,5 @@ -using Hi3Helper; +using CollapseLauncher.Statics; +using Hi3Helper; #if !DISABLEDISCORD using Hi3Helper.DiscordPresence; #endif @@ -9,7 +10,6 @@ using System; using System.Threading.Tasks; using static CollapseLauncher.InnerLauncherConfig; -using static CollapseLauncher.Statics.PageStatics; using static Hi3Helper.Locale; using static Hi3Helper.Logger; using static Hi3Helper.Shared.Region.LauncherConfig; @@ -18,9 +18,14 @@ namespace CollapseLauncher.Pages { public sealed partial class CachesPage : Page { + private GamePresetProperty CurrentGameProperty { get; set; } + public CachesPage() { + CurrentGameProperty = GamePropertyVault.GetCurrentGameProperty(); + this.InitializeComponent(); + BackgroundImgChanger.ToggleBackground(true); #if !DISABLEDISCORD AppDiscordPresence.SetActivity(ActivityType.Cache); #endif @@ -57,7 +62,7 @@ public async void RunCheckRoutine(object sender, bool isFast, bool isMainButton) { AddEvent(); - bool IsNeedUpdate = await _GameCache.StartCheckRoutine(isFast); + bool IsNeedUpdate = await CurrentGameProperty._GameCache.StartCheckRoutine(isFast); UpdateCachesBtn.IsEnabled = IsNeedUpdate; CheckUpdateBtn.IsEnabled = !IsNeedUpdate; @@ -94,7 +99,7 @@ public async void StartCachesUpdate(object sender, RoutedEventArgs e) { AddEvent(); - await _GameCache.StartUpdateRoutine(); + await CurrentGameProperty._GameCache.StartUpdateRoutine(); UpdateCachesBtn.IsEnabled = false; CheckUpdateBtn.IsEnabled = true; @@ -135,16 +140,16 @@ private void SetMainCheckUpdateBtnProperty(object sender) private void AddEvent() { - _GameCache.ProgressChanged += _cacheTool_ProgressChanged; - _GameCache.StatusChanged += _cacheTool_StatusChanged; + CurrentGameProperty._GameCache.ProgressChanged += _cacheTool_ProgressChanged; + CurrentGameProperty._GameCache.StatusChanged += _cacheTool_StatusChanged; CachesTotalProgressBar.IsIndeterminate = true; } private void RemoveEvent() { - _GameCache.ProgressChanged -= _cacheTool_ProgressChanged; - _GameCache.StatusChanged -= _cacheTool_StatusChanged; + CurrentGameProperty._GameCache.ProgressChanged -= _cacheTool_ProgressChanged; + CurrentGameProperty._GameCache.StatusChanged -= _cacheTool_StatusChanged; CachesTotalProgressBar.IsIndeterminate = false; } @@ -188,7 +193,7 @@ private void ResetStatusAndButtonState() public void CancelOperation(object sender, RoutedEventArgs e) { - _GameCache?.CancelRoutine(); + CurrentGameProperty._GameCache?.CancelRoutine(); } private void InitializeLoaded(object sender, RoutedEventArgs e) @@ -215,7 +220,7 @@ private void InitializeLoaded(object sender, RoutedEventArgs e) private void Page_Unloaded(object sender, RoutedEventArgs e) { - _GameCache?.CancelRoutine(); + CurrentGameProperty._GameCache?.CancelRoutine(); } } } diff --git a/CollapseLauncher/XAMLs/MainApp/Pages/Dialogs/InstallationConvert.xaml.cs b/CollapseLauncher/XAMLs/MainApp/Pages/Dialogs/InstallationConvert.xaml.cs index b02a6b6f2..1b13c6a79 100644 --- a/CollapseLauncher/XAMLs/MainApp/Pages/Dialogs/InstallationConvert.xaml.cs +++ b/CollapseLauncher/XAMLs/MainApp/Pages/Dialogs/InstallationConvert.xaml.cs @@ -34,11 +34,13 @@ public partial class InstallationConvert : Page IniFile SourceIniFile; CancellationTokenSource tokenSource = new CancellationTokenSource(); Dictionary ConvertibleRegions; + private GamePresetProperty CurrentGameProperty { get; set; } public InstallationConvert() { try { + CurrentGameProperty = GamePropertyVault.GetCurrentGameProperty(); this.InitializeComponent(); } catch (Exception ex) @@ -107,12 +109,12 @@ public async void StartConversionProcess() } catch (TaskCanceledException) { - LogWriteLine($"Conversion process is cancelled for Game {PageStatics._GameVersion.GamePreset.ZoneFullname}"); + LogWriteLine($"Conversion process is cancelled for Game {CurrentGameProperty._GameVersion.GamePreset.ZoneFullname}"); OperationCancelled(); } catch (OperationCanceledException) { - LogWriteLine($"Conversion process is cancelled for Game {PageStatics._GameVersion.GamePreset.ZoneFullname}"); + LogWriteLine($"Conversion process is cancelled for Game {CurrentGameProperty._GameVersion.GamePreset.ZoneFullname}"); OperationCancelled(); } catch (Exception ex) @@ -157,7 +159,7 @@ private async Task FetchDataIntegrityURL(PresetConfigV2 Profile) string repoListURL = string.Format(AppGameRepoIndexURLPrefix, Profile.ProfileName); await FallbackCDNUtil.DownloadCDNFallbackContent(_Http, s, repoListURL, tokenSource.Token); s.Position = 0; - _RepoList = (Dictionary)JsonSerializer.Deserialize(s, typeof(Dictionary), D_StringString.Default); + _RepoList = (Dictionary)JsonSerializer.Deserialize(s, typeof(Dictionary), CoreLibraryJSONContext.Default); } } finally @@ -171,7 +173,7 @@ private async Task FetchDataIntegrityURL(PresetConfigV2 Profile) { await _Http.Download(Profile.LauncherResourceURL, s, null, null, tokenSource.Token); s.Position = 0; - _Entry = (RegionResourceProp)JsonSerializer.Deserialize(s, typeof(RegionResourceProp), RegionResourcePropContext.Default); + _Entry = (RegionResourceProp)JsonSerializer.Deserialize(s, typeof(RegionResourceProp), CoreLibraryJSONContext.Default); } GameVersion = _Entry.data.game.latest.version; @@ -195,6 +197,32 @@ public bool IsSourceGameExist(PresetConfigV2 Profile) if (!Directory.Exists(GamePath)) return false; + // Concat the vendor app info file and return if it doesn't exist + string infoVendorPath = Path.Combine(GamePath, $"{Path.GetFileNameWithoutExtension(Profile.GameExecutableName)}_Data\\app.info"); + if (!File.Exists(infoVendorPath)) return false; + + // If does, then process the file + string[] infoEntries = File.ReadAllLines(infoVendorPath); + if (infoEntries.Length < 2) return false; + + // Try parse the vendor name and internal game name. If parsing fail, then return false + if (!Enum.TryParse(infoEntries[0], out GameVendorType _VendorType)) return false; + if (!(_VendorType == SourceProfile.VendorType && infoEntries[1] == SourceProfile.InternalGameNameInConfig)) return false; + + // Try load the Version INI file + string SourceINIVersionPath = Path.Combine(GamePath, "config.ini"); + if (!File.Exists(SourceINIVersionPath)) return false; + IniFile SourceIniVersionFile = new IniFile(); + SourceIniVersionFile.Load(SourceINIVersionPath); + + // Check if the version value exist and matches + if (!(SourceIniVersionFile.ContainsSection("General") && SourceIniVersionFile["General"].ContainsKey("game_version"))) return false; + string localVersionString = SourceIniVersionFile["General"]["game_version"].ToString(); + if (string.IsNullOrEmpty(localVersionString)) return false; + GameVersion localVersion = new GameVersion(localVersionString); + GameVersion remoteVersion = CurrentGameProperty._GameVersion.GetGameVersionAPI(); + if (!localVersion.IsMatch(remoteVersion)) return false; + ExecPath = Path.Combine(GamePath, Profile.GameExecutableName); if (!File.Exists(ExecPath)) return false; @@ -322,7 +350,7 @@ private async Task DoDownloadRecipe() string cPath = null; while (!IsChoosen) { - string FileName = string.Format("Cookbook_{0}_{1}_{2}_lzma2_crc32.diff", SourceProfile.ProfileName, TargetProfile.ProfileName, GameVersion); + string FileName = string.Format("Cookbook_{0}_{1}_{2}_*_crc32.diff", SourceProfile.ProfileName, TargetProfile.ProfileName, GameVersion); switch (await Dialog_LocateDownloadedConvertRecipe(Content, FileName)) { case ContentDialogResult.Primary: @@ -468,8 +496,9 @@ private void Step5ProgressEvents(object sender, ConvertProgress e) public void ApplyConfiguration() { - PageStatics._GameVersion.GamePreset = TargetProfile; - PageStatics._GameVersion.UpdateGamePath(Path.GetFileNameWithoutExtension(TargetProfile.ActualGameDataLocation)); + CurrentGameProperty._GameVersion.GamePreset = TargetProfile; + CurrentGameProperty._GameVersion.Reinitialize(); + CurrentGameProperty._GameVersion.UpdateGamePath(TargetProfile.ActualGameDataLocation); string GameCategory = GetAppConfigValue("GameCategory").ToString(); SetPreviousGameRegion(GameCategory, TargetProfile.ZoneName); diff --git a/CollapseLauncher/XAMLs/MainApp/Pages/Dialogs/SimpleDialogs.cs b/CollapseLauncher/XAMLs/MainApp/Pages/Dialogs/SimpleDialogs.cs index 7482c22df..8be65f6a7 100644 --- a/CollapseLauncher/XAMLs/MainApp/Pages/Dialogs/SimpleDialogs.cs +++ b/CollapseLauncher/XAMLs/MainApp/Pages/Dialogs/SimpleDialogs.cs @@ -1,4 +1,4 @@ -using CollapseLauncher.Statics; +using static CollapseLauncher.Statics.GamePropertyVault; using Microsoft.UI.Text; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; @@ -170,10 +170,10 @@ public static async Task Dialog_ChangeReleaseChannel(string ); } - public static async Task Dialog_ExistingInstallation(UIElement Content) => + public static async Task Dialog_ExistingInstallation(UIElement Content, string actualLocation) => await SpawnDialog( Lang._Dialogs.ExistingInstallTitle, - string.Format(Lang._Dialogs.ExistingInstallSubtitle, PageStatics._GameVersion.GamePreset.ActualGameDataLocation), + string.Format(Lang._Dialogs.ExistingInstallSubtitle, actualLocation), Content, Lang._Misc.Cancel, Lang._Misc.YesMigrateIt, @@ -250,6 +250,17 @@ await SpawnDialog( Lang._StartupPage.ChooseFolderDialogSecondary ); + public static async Task Dialog_CannotUseAppLocationForGameDir(UIElement Content) => + await SpawnDialog( + Lang._Dialogs.CannotUseAppLocationForGameDirTitle, + Lang._Dialogs.CannotUseAppLocationForGameDirSubtitle, + Content, + Lang._Misc.Okay, + null, + null, + ContentDialogButton.Close + ); + public static async Task Dialog_ExistingDownload(UIElement Content, long partialLength, long contentLength) => await SpawnDialog( Lang._Dialogs.InstallDataDownloadResumeTitle, @@ -326,6 +337,16 @@ await SpawnDialog( Lang._Misc.Yes, null ); + + public static async Task Dialog_StopGame(UIElement Content) => + await SpawnDialog( + Lang._Dialogs.StopGameTitle, + Lang._Dialogs.StopGameSubtitle, + Content, + Lang._Misc.NoCancel, + Lang._Misc.Yes, + null + ); public static async Task Dialog_ResetPlaytime (UIElement Content) { diff --git a/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPage.Ext.cs b/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPage.Ext.cs index d743a3c0a..9934ad78b 100644 --- a/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPage.Ext.cs +++ b/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPage.Ext.cs @@ -100,6 +100,12 @@ public bool IsFullscreenEnabled } } + public bool IsBorderlessEnabled + { + get => Settings.SettingsCollapseScreen.UseBorderlessScreen; + set => Settings.SettingsCollapseScreen.UseBorderlessScreen = value; + } + public bool IsCustomResolutionEnabled { get => Settings.SettingsCollapseScreen.UseCustomResolution; diff --git a/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPage.xaml b/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPage.xaml index 81ba6ba56..3cc68f3e3 100644 --- a/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPage.xaml +++ b/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPage.xaml @@ -17,7 +17,7 @@ - + @@ -32,6 +32,9 @@ + diff --git a/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPage.xaml.cs b/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPage.xaml.cs index b009c48db..0f16d9ed0 100644 --- a/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPage.xaml.cs +++ b/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPage.xaml.cs @@ -1,6 +1,5 @@ using CollapseLauncher.GameSettings.Honkai; using CollapseLauncher.Interfaces; -using CollapseLauncher.Statics; #if !DISABLEDISCORD using Hi3Helper.DiscordPresence; #endif @@ -16,24 +15,27 @@ using static Hi3Helper.Locale; using static Hi3Helper.Logger; using static Hi3Helper.Shared.Region.LauncherConfig; -using static CollapseLauncher.GameSettings.Statics; +using static CollapseLauncher.Statics.GamePropertyVault; using Hi3Helper; +using CollapseLauncher.Statics; namespace CollapseLauncher.Pages { public partial class GameSettingsPage : Page { - private HonkaiSettings Settings { get => (HonkaiSettings)PageStatics._GameSettings; } + private GamePresetProperty CurrentGameProperty { get; set; } + private HonkaiSettings Settings { get => (HonkaiSettings)CurrentGameProperty._GameSettings; } private Brush InheritApplyTextColor { get; set; } private RegistryMonitor RegistryWatcher { get; set; } private bool IsNoReload = false; public GameSettingsPage() { + CurrentGameProperty = GetCurrentGameProperty(); try { DispatcherQueue.TryEnqueue(() => { - RegistryWatcher = new RegistryMonitor(RegistryHive.CurrentUser, Path.Combine(RegistryRootPath, PageStatics._GameVersion.GamePreset.InternalGameNameInConfig)); + RegistryWatcher = new RegistryMonitor(RegistryHive.CurrentUser, Path.Combine($"Software\\{CurrentGameProperty._GameVersion.VendorTypeProp.VendorType}", CurrentGameProperty._GameVersion.GamePreset.InternalGameNameInConfig)); RegistryWatcher.Start(); ToggleRegistrySubscribe(true); }); @@ -59,13 +61,14 @@ private void RegistryListener(object sender, EventArgs e) { if (!IsNoReload) { - LogWriteLine("Module: RegistryMonitor has detected registry change outside of the launcher! Reloading the page...", LogType.Warning, true); + LogWriteLine("[HI3 GSP Module] RegistryMonitor has detected registry change outside of the launcher! Reloading the page...", LogType.Warning, true); DispatcherQueue.TryEnqueue(MainFrameChanger.ReloadCurrentMainFrame); } } private void LoadPage() { + BackgroundImgChanger.ToggleBackground(true); Settings.ReloadSettings(); this.InitializeComponent(); @@ -189,11 +192,11 @@ private void ApplyButton_Click(object sender, RoutedEventArgs e) public string CustomArgsValue { - get => ((IGameSettingsUniversal)PageStatics._GameSettings).SettingsCustomArgument.CustomArgumentValue; + get => ((IGameSettingsUniversal)CurrentGameProperty._GameSettings).SettingsCustomArgument.CustomArgumentValue; set { ToggleRegistrySubscribe(false); - ((IGameSettingsUniversal)PageStatics._GameSettings).SettingsCustomArgument.CustomArgumentValue = value; + ((IGameSettingsUniversal)CurrentGameProperty._GameSettings).SettingsCustomArgument.CustomArgumentValue = value; ToggleRegistrySubscribe(true); } } diff --git a/CollapseLauncher/XAMLs/MainApp/Pages/GenshinGameSettingsPage.Ext.cs b/CollapseLauncher/XAMLs/MainApp/Pages/GenshinGameSettingsPage.Ext.cs index 052f12b80..7d8c5ba64 100644 --- a/CollapseLauncher/XAMLs/MainApp/Pages/GenshinGameSettingsPage.Ext.cs +++ b/CollapseLauncher/XAMLs/MainApp/Pages/GenshinGameSettingsPage.Ext.cs @@ -25,6 +25,12 @@ public bool IsFullscreenEnabled } } + public bool IsBorderlessEnabled + { + get => Settings.SettingsCollapseScreen.UseBorderlessScreen; + set => Settings.SettingsCollapseScreen.UseBorderlessScreen = value; + } + public bool IsCustomResolutionEnabled { get => Settings.SettingsCollapseScreen.UseCustomResolution; diff --git a/CollapseLauncher/XAMLs/MainApp/Pages/GenshinGameSettingsPage.xaml b/CollapseLauncher/XAMLs/MainApp/Pages/GenshinGameSettingsPage.xaml index f9c3e96f9..6de0443ad 100644 --- a/CollapseLauncher/XAMLs/MainApp/Pages/GenshinGameSettingsPage.xaml +++ b/CollapseLauncher/XAMLs/MainApp/Pages/GenshinGameSettingsPage.xaml @@ -21,7 +21,7 @@ - + @@ -32,11 +32,14 @@ - + + HorizontalAlignment="Left" VerticalAlignment="Center" + IsChecked="{x:Bind IsFullscreenEnabled, Mode=TwoWay}" Margin="0,0,0,0"/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CollapseLauncher/XAMLs/Prototype/MainPageNew.xaml.cs b/CollapseLauncher/XAMLs/Prototype/MainPageNew.xaml.cs new file mode 100644 index 000000000..3ec8538be --- /dev/null +++ b/CollapseLauncher/XAMLs/Prototype/MainPageNew.xaml.cs @@ -0,0 +1,48 @@ +using Hi3Helper; +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using System; +using static Hi3Helper.Logger; + +namespace CollapseLauncher.Prototype +{ + public partial class MainPageNew : Page + { + public MainPageNew() + { + try + { + InitializeComponent(); + } + catch (Exception ex) + { + LogWriteLine($"FATAL CRASH!!!\r\n{ex}", LogType.Error, true); + ErrorSender.SendException(ex); + } + } + + private void nvSample_PaneOpening(NavigationView sender, object args) + { + Thickness curMargin = GridBG_Icon.Margin; + curMargin.Left = 48; + GridBG_Icon.Margin = curMargin; + GridBG_IconTitle.Width = double.NaN; + if (PreviewBuildIndicator.Visibility == Visibility.Collapsed) + GridBG_IconTitle.Visibility = Visibility.Visible; + } + + private void nvSample_PaneClosing(NavigationView sender, NavigationViewPaneClosingEventArgs args) + { + Thickness curMargin = GridBG_Icon.Margin; + curMargin.Left = 58; + GridBG_IconTitle.Width = 0; + GridBG_Icon.Margin = curMargin; + if (PreviewBuildIndicator.Visibility == Visibility.Collapsed) + GridBG_IconTitle.Visibility = Visibility.Collapsed; + } + + private void NotificationContainerBackground_PointerPressed(object sender, Microsoft.UI.Xaml.Input.PointerRoutedEventArgs e) + { + } + } +} diff --git a/CollapseLauncher/XAMLs/Prototype/genshin-logo.png b/CollapseLauncher/XAMLs/Prototype/genshin-logo.png new file mode 100644 index 000000000..5f76fde44 Binary files /dev/null and b/CollapseLauncher/XAMLs/Prototype/genshin-logo.png differ diff --git a/CollapseLauncher/XAMLs/Prototype/honkai-logo.png b/CollapseLauncher/XAMLs/Prototype/honkai-logo.png new file mode 100644 index 000000000..091171e20 Binary files /dev/null and b/CollapseLauncher/XAMLs/Prototype/honkai-logo.png differ diff --git a/CollapseLauncher/XAMLs/Prototype/starrail-logo.png b/CollapseLauncher/XAMLs/Prototype/starrail-logo.png new file mode 100644 index 000000000..f0b83e4c1 Binary files /dev/null and b/CollapseLauncher/XAMLs/Prototype/starrail-logo.png differ diff --git a/CollapseLauncher/XAMLs/Prototype/zenless-logo.png b/CollapseLauncher/XAMLs/Prototype/zenless-logo.png new file mode 100644 index 000000000..3a47b320d Binary files /dev/null and b/CollapseLauncher/XAMLs/Prototype/zenless-logo.png differ diff --git a/CollapseLauncher/XAMLs/StartUp/StartupLanguageSelect.xaml b/CollapseLauncher/XAMLs/StartUp/StartupLanguageSelect.xaml index 8fe6e76b1..3b41d9b8f 100644 --- a/CollapseLauncher/XAMLs/StartUp/StartupLanguageSelect.xaml +++ b/CollapseLauncher/XAMLs/StartUp/StartupLanguageSelect.xaml @@ -17,7 +17,7 @@ - + diff --git a/CollapseLauncher/XAMLs/Updater/Classes/Updater.cs b/CollapseLauncher/XAMLs/Updater/Classes/Updater.cs index e0fbc3c08..1d098193c 100644 --- a/CollapseLauncher/XAMLs/Updater/Classes/Updater.cs +++ b/CollapseLauncher/XAMLs/Updater/Classes/Updater.cs @@ -132,7 +132,7 @@ private async Task StartLegacyUpdate() { await FallbackCDNUtil.DownloadCDNFallbackContent(_httpClient, ms, $"{this.ChannelName.ToLower()}/fileindex.json", default); ms.Position = 0; - AppUpdateVersionProp updateInfo = (AppUpdateVersionProp)JsonSerializer.Deserialize(ms, typeof(AppUpdateVersionProp), AppUpdateVersionPropContext.Default); + AppUpdateVersionProp updateInfo = (AppUpdateVersionProp)JsonSerializer.Deserialize(ms, typeof(AppUpdateVersionProp), InternalAppJSONContext.Default); NewVersionTag = new GameVersion(updateInfo.ver); UpdateStatus(); UpdateProgress(); diff --git a/CollapseLauncher/XAMLs/Updater/UpdaterWindow.xaml.cs b/CollapseLauncher/XAMLs/Updater/UpdaterWindow.xaml.cs index 71b0a1aa0..e41c204b1 100644 --- a/CollapseLauncher/XAMLs/Updater/UpdaterWindow.xaml.cs +++ b/CollapseLauncher/XAMLs/Updater/UpdaterWindow.xaml.cs @@ -63,7 +63,7 @@ private async void StartAsyncRoutine() { await FallbackCDNUtil.DownloadCDNFallbackContent(_httpClient, ms, $"{m_arguments.Updater.UpdateChannel.ToString().ToLower()}/fileindex.json", default); ms.Position = 0; - updateInfo = (AppUpdateVersionProp)JsonSerializer.Deserialize(ms, typeof(AppUpdateVersionProp), AppUpdateVersionPropContext.Default); + updateInfo = (AppUpdateVersionProp)JsonSerializer.Deserialize(ms, typeof(AppUpdateVersionProp), InternalAppJSONContext.Default); NewVersionLabel.Text = new GameVersion(updateInfo.ver).VersionString; } diff --git a/CollapseLauncher/packages.lock.json b/CollapseLauncher/packages.lock.json new file mode 100644 index 000000000..f5c141836 --- /dev/null +++ b/CollapseLauncher/packages.lock.json @@ -0,0 +1,2259 @@ +{ + "version": 1, + "dependencies": { + "net7.0-windows10.0.19041": { + "Clowd.Squirrel": { + "type": "Direct", + "requested": "[2.9.42, )", + "resolved": "2.9.42", + "contentHash": "bM7h3tqoenZD+tmiV7pUnFdJ/o1oOrC21PaS8crMDRDOuGB4YqsgzlUKFD1g8X6z64IRBqzlUwEKzpsFyFc0mQ==", + "dependencies": { + "SharpCompress": "0.31.0" + } + }, + "CommunityToolkit.WinUI.UI": { + "type": "Direct", + "requested": "[7.1.2, )", + "resolved": "7.1.2", + "contentHash": "jF1GdEJsZX5o81ZfLjSjgC5RuYwQneuW2mdFIb7FDFzITsgqCn7mfn7BglpNiXvjExkocmAKbBgmCcbp0Nypmw==", + "dependencies": { + "CommunityToolkit.WinUI": "7.1.2", + "Microsoft.WindowsAppSDK": "1.0.0" + } + }, + "CommunityToolkit.WinUI.UI.Controls": { + "type": "Direct", + "requested": "[7.1.2, )", + "resolved": "7.1.2", + "contentHash": "+aDc1KqmlYM+HE0Mw5OnfQBOFhY0c7zp1aGz/4qs+1I+Xk8Ot3IRwvs8dYxBEGCD9YzE2OzaJLPztBpQ9JEWig==", + "dependencies": { + "CommunityToolkit.WinUI.UI.Controls.Core": "7.1.2", + "CommunityToolkit.WinUI.UI.Controls.DataGrid": "7.1.2", + "CommunityToolkit.WinUI.UI.Controls.Input": "7.1.2", + "CommunityToolkit.WinUI.UI.Controls.Layout": "7.1.2", + "CommunityToolkit.WinUI.UI.Controls.Markdown": "7.1.2", + "CommunityToolkit.WinUI.UI.Controls.Media": "7.1.2", + "CommunityToolkit.WinUI.UI.Controls.Primitives": "7.1.2", + "Microsoft.WindowsAppSDK": "1.0.0" + } + }, + "Microsoft.Windows.CsWinRT": { + "type": "Direct", + "requested": "[2.0.3, )", + "resolved": "2.0.3", + "contentHash": "viZIwWVUBp7x9QprOZbvocWasVIAfaXN2BK7tgMijYKe4X+WuU1m4RdqE8P2wv+o3q0Bk8mWsUFaMm36rsCvNg==" + }, + "Microsoft.Windows.SDK.BuildTools": { + "type": "Direct", + "requested": "[10.0.22621.756, )", + "resolved": "10.0.22621.756", + "contentHash": "7ZL2sFSioYm1Ry067Kw1hg0SCcW5kuVezC2SwjGbcPE61Nn+gTbH86T73G3LcEOVj0S3IZzNuE/29gZvOLS7VA==" + }, + "Microsoft.WindowsAppSDK": { + "type": "Direct", + "requested": "[1.3.230724000, )", + "resolved": "1.3.230724000", + "contentHash": "cCw26h8Uh8IjDMOUzHaR7/IKxEVJxuqEOgBlmLj0Pu1wDezZb9J0Wz53Vop10FQUOZaTfnwDcHavyPTxgkwbKQ==", + "dependencies": { + "Microsoft.Windows.SDK.BuildTools": "10.0.22621.1" + } + }, + "System.CommandLine": { + "type": "Direct", + "requested": "[2.0.0-beta3.22114.1, )", + "resolved": "2.0.0-beta3.22114.1", + "contentHash": "QMzk1jj+PzdGbwuVsxII7FcQaCelnK+TcRcAqOGVoPovLBCSQPdikKiEzb56vAidvum5t4LSdDZ34O4j7+ALgw==" + }, + "System.Drawing.Common": { + "type": "Direct", + "requested": "[7.0.0, )", + "resolved": "7.0.0", + "contentHash": "KIX+oBU38pxkKPxvLcLfIkOV5Ien8ReN78wro7OF5/erwcmortzeFx+iBswlh2Vz6gVne0khocQudGwaO1Ey6A==", + "dependencies": { + "Microsoft.Win32.SystemEvents": "7.0.0" + } + }, + "ColorCode.Core": { + "type": "Transitive", + "resolved": "2.0.13", + "contentHash": "v0xqipj/6h2TpIKSrOCZpXMmOGvLsyO2prWBXY6t+lduexDSimqKIZXTTZkpq/vG2kNxB8K8nzyrkIB3usoN7A==", + "dependencies": { + "NETStandard.Library": "1.6.1" + } + }, + "ColorCode.WinUI": { + "type": "Transitive", + "resolved": "2.0.13", + "contentHash": "FPuyaXOb9LaD6nSUXtMrK/l564tmRbCfMiQWrnKzzLhJnnRuWkU2JpSJjV2KGCrjyx5ol7wy7TiK0GnGnPsIEA==", + "dependencies": { + "ColorCode.Core": "2.0.13", + "Microsoft.WindowsAppSDK": "1.0.0" + } + }, + "CommunityToolkit.Common": { + "type": "Transitive", + "resolved": "7.1.2", + "contentHash": "KnHnukN+Sc26YT98OWYTp8mvaYlLc61lzDh0RrVRNQXm01hZ+iXAjCgKM59vAojqxNVrlbcXj22LYOyXWDItgg==" + }, + "CommunityToolkit.WinUI": { + "type": "Transitive", + "resolved": "7.1.2", + "contentHash": "0O6hCHy+/adJygcROD3r3yA41gRq972i/r6uGUfo8lfEbr/I1YGePTClAh1P9JYT7DdoI2IqeUhX05lq+rwrHg==", + "dependencies": { + "CommunityToolkit.Common": "7.1.2", + "Microsoft.WindowsAppSDK": "1.0.0" + } + }, + "CommunityToolkit.WinUI.UI.Controls.Core": { + "type": "Transitive", + "resolved": "7.1.2", + "contentHash": "7MVYQKjYlD5SryWNy5FA7Pcer9Rphjk7hCrSIOT9m4dcsOYmekZf36TOJARKxySXvlmjNud6QkmWssJKFC4k5w==", + "dependencies": { + "CommunityToolkit.WinUI": "7.1.2", + "CommunityToolkit.WinUI.UI.Controls.Primitives": "7.1.2", + "Microsoft.WindowsAppSDK": "1.0.0" + } + }, + "CommunityToolkit.WinUI.UI.Controls.DataGrid": { + "type": "Transitive", + "resolved": "7.1.2", + "contentHash": "F73oYdYza8zhDwGHdXCZJJMeiDJ6nR97WPe180o7jOX3U90ZIqvU/GtYZdN3/x8DOS48t5GQG70LqxfyIGeaxw==", + "dependencies": { + "Microsoft.WindowsAppSDK": "1.0.0" + } + }, + "CommunityToolkit.WinUI.UI.Controls.Input": { + "type": "Transitive", + "resolved": "7.1.2", + "contentHash": "fT8s21NI51YCR/mgm1eabwnSSQuXnQRz/TqHKjzYABhfGSvl44YlvuAQzbE9VfZSEUtiv4kesgylrzKd4/dArg==", + "dependencies": { + "CommunityToolkit.WinUI.UI.Controls.Primitives": "7.1.2", + "Microsoft.WindowsAppSDK": "1.0.0" + } + }, + "CommunityToolkit.WinUI.UI.Controls.Layout": { + "type": "Transitive", + "resolved": "7.1.2", + "contentHash": "FpKo2DdJgREAvttTYhOJTy1ru6ODRG41Da+vMrB7bcqavdbPgSTqYzolLcgvMl2InpIdt+fqn6U6mGQYoV+ksQ==", + "dependencies": { + "CommunityToolkit.WinUI.UI": "7.1.2", + "Microsoft.WindowsAppSDK": "1.0.0" + } + }, + "CommunityToolkit.WinUI.UI.Controls.Markdown": { + "type": "Transitive", + "resolved": "7.1.2", + "contentHash": "0hAhwBfWa7aWKYOPGxhJJXowjrncY4he8jizcbuPVCgv8tZS1LXEEH4MoGKq57iLKz2lG3qaVN+1trcDWYq0Sg==", + "dependencies": { + "ColorCode.WinUI": "2.0.13", + "CommunityToolkit.WinUI.UI": "7.1.2", + "CommunityToolkit.WinUI.UI.Controls.Core": "7.1.2", + "Microsoft.WindowsAppSDK": "1.0.0" + } + }, + "CommunityToolkit.WinUI.UI.Controls.Media": { + "type": "Transitive", + "resolved": "7.1.2", + "contentHash": "FFH1mNF+rp3GEIQOceoxzSrRVY3G8aA+sYoK6Fv1kDEFWlCfLYF+cSCexL4sBuw0ARs1QXUvNqW4T1F/nAWsdw==", + "dependencies": { + "CommunityToolkit.WinUI.UI": "7.1.2", + "Microsoft.Graphics.Win2D": "1.0.0.30", + "Microsoft.WindowsAppSDK": "1.0.0", + "System.Text.Json": "5.0.2" + } + }, + "CommunityToolkit.WinUI.UI.Controls.Primitives": { + "type": "Transitive", + "resolved": "7.1.2", + "contentHash": "mNtVRpBVnFzSywRzzLPXBIoYm4UWJPZkpNPNAu75lnl4KcnkfjjyQg90hkfF9MT/JkBJQG0z5XOdMCksn7EiMQ==", + "dependencies": { + "CommunityToolkit.WinUI.UI": "7.1.2", + "Microsoft.WindowsAppSDK": "1.0.0" + } + }, + "Google.Protobuf": { + "type": "Transitive", + "resolved": "3.23.4", + "contentHash": "DF+mB+Fwan5Hm5dnbKbrIl7C5ypMr8tJJheutkYgFXCoM88HfBNo2qYO60CEf6fvEe/fhCGtvfEBCoCIhIn7dQ==" + }, + "Microsoft.Graphics.Win2D": { + "type": "Transitive", + "resolved": "1.0.0.30", + "contentHash": "pEGf7FSx2dRWJuoaSoXk+WYkZfYwhWoJKOyyo0XLRU6V2Ul02MjxRhoxggrzGz6jVFiT7R2NdPdV8M6N1F+QfA==" + }, + "Microsoft.NETCore.Platforms": { + "type": "Transitive", + "resolved": "1.1.0", + "contentHash": "kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A==" + }, + "Microsoft.NETCore.Targets": { + "type": "Transitive", + "resolved": "1.1.0", + "contentHash": "aOZA3BWfz9RXjpzt0sRJJMjAscAUm3Hoa4UWAfceV9UTYxgwZ1lZt5nO2myFf+/jetYQo4uTP7zS8sJY67BBxg==" + }, + "Microsoft.Win32.Primitives": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "9ZQKCWxH7Ijp9BfahvL2Zyf1cJIk8XYLF6Yjzr2yi0b2cOut/HQ31qf1ThHAgCc3WiZMdnWcfJCgN82/0UunxA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "Microsoft.Win32.SystemEvents": { + "type": "Transitive", + "resolved": "7.0.0", + "contentHash": "2nXPrhdAyAzir0gLl8Yy8S5Mnm/uBSQQA7jEsILOS1MTyS7DbmV1NgViMtvV1sfCD1ebITpNwb1NIinKeJgUVQ==" + }, + "NETStandard.Library": { + "type": "Transitive", + "resolved": "1.6.1", + "contentHash": "WcSp3+vP+yHNgS8EV5J7pZ9IRpeDuARBPN28by8zqff1wJQXm26PVU8L3/fYLBJVU7BtDyqNVWq2KlCVvSSR4A==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.Win32.Primitives": "4.3.0", + "System.AppContext": "4.3.0", + "System.Collections": "4.3.0", + "System.Collections.Concurrent": "4.3.0", + "System.Console": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Diagnostics.Tools": "4.3.0", + "System.Diagnostics.Tracing": "4.3.0", + "System.Globalization": "4.3.0", + "System.Globalization.Calendars": "4.3.0", + "System.IO": "4.3.0", + "System.IO.Compression": "4.3.0", + "System.IO.Compression.ZipFile": "4.3.0", + "System.IO.FileSystem": "4.3.0", + "System.IO.FileSystem.Primitives": "4.3.0", + "System.Linq": "4.3.0", + "System.Linq.Expressions": "4.3.0", + "System.Net.Http": "4.3.0", + "System.Net.Primitives": "4.3.0", + "System.Net.Sockets": "4.3.0", + "System.ObjectModel": "4.3.0", + "System.Reflection": "4.3.0", + "System.Reflection.Extensions": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Runtime.InteropServices.RuntimeInformation": "4.3.0", + "System.Runtime.Numerics": "4.3.0", + "System.Security.Cryptography.Algorithms": "4.3.0", + "System.Security.Cryptography.Encoding": "4.3.0", + "System.Security.Cryptography.Primitives": "4.3.0", + "System.Security.Cryptography.X509Certificates": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Text.Encoding.Extensions": "4.3.0", + "System.Text.RegularExpressions": "4.3.0", + "System.Threading": "4.3.0", + "System.Threading.Tasks": "4.3.0", + "System.Threading.Timer": "4.3.0", + "System.Xml.ReaderWriter": "4.3.0", + "System.Xml.XDocument": "4.3.0" + } + }, + "runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "HdSSp5MnJSsg08KMfZThpuLPJpPwE5hBXvHwoKWosyHHfe8Mh5WKT0ylEOf6yNzX6Ngjxe4Whkafh5q7Ymac4Q==" + }, + "runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "+yH1a49wJMy8Zt4yx5RhJrxO/DBDByAiCzNwiETI+1S4mPdCu0OY4djdciC7Vssk0l22wQaDLrXxXkp+3+7bVA==" + }, + "runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "c3YNH1GQJbfIPJeCnr4avseugSqPrxwIqzthYyZDN6EuOyNOzq+y2KSUfRcXauya1sF4foESTgwM5e1A8arAKw==" + }, + "runtime.native.System": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "c/qWt2LieNZIj1jGnVNsE2Kl23Ya2aSTBuXMD6V7k9KWr6l16Tqdwq+hJScEpWER9753NWC8h96PaVNY5Ld7Jw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0" + } + }, + "runtime.native.System.IO.Compression": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "INBPonS5QPEgn7naufQFXJEp3zX6L4bwHgJ/ZH78aBTpeNfQMtf7C6VrAFhlq2xxWBveIOWyFzQjJ8XzHMhdOQ==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0" + } + }, + "runtime.native.System.Net.Http": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "ZVuZJqnnegJhd2k/PtAbbIcZ3aZeITq3sj06oKfMBSfphW3HDmk/t4ObvbOk/JA/swGR0LNqMksAh/f7gpTROg==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0" + } + }, + "runtime.native.System.Security.Cryptography.Apple": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "DloMk88juo0OuOWr56QG7MNchmafTLYWvABy36izkrLI5VledI0rq28KGs1i9wbpeT9NPQrx/wTf8U2vazqQ3Q==", + "dependencies": { + "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.Apple": "4.3.0" + } + }, + "runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "NS1U+700m4KFRHR5o4vo9DSlTmlCKu/u7dtE5sUHVIPB+xpXxYQvgBgA6wEIeCz6Yfn0Z52/72WYsToCEPJnrw==", + "dependencies": { + "runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0", + "runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0", + "runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0", + "runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0", + "runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0", + "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0", + "runtime.rhel.7-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0", + "runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0", + "runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0", + "runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" + } + }, + "runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "b3pthNgxxFcD+Pc0WSEoC0+md3MyhRS6aCEeenvNE3Fdw1HyJ18ZhRFVJJzIeR/O/jpxPboB805Ho0T3Ul7w8A==" + }, + "runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "KeLz4HClKf+nFS7p/6Fi/CqyLXh81FpiGzcmuS8DGi9lUqSnZ6Es23/gv2O+1XVGfrbNmviF7CckBpavkBoIFQ==" + }, + "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.Apple": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "kVXCuMTrTlxq4XOOMAysuNwsXWpYeboGddNGpIgNSZmv1b6r/s/DPk0fYMB7Q5Qo4bY68o48jt4T4y5BVecbCQ==" + }, + "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "X7IdhILzr4ROXd8mI1BUCQMSHSQwelUlBjF1JyTKCjXaOGn2fB4EKBxQbCK2VjO3WaWIdlXZL3W6TiIVnrhX4g==" + }, + "runtime.rhel.7-x64.runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "nyFNiCk/r+VOiIqreLix8yN+q3Wga9+SE8BCgkf+2BwEKiNx6DyvFjCgkfV743/grxv8jHJ8gUK4XEQw7yzRYg==" + }, + "runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "ytoewC6wGorL7KoCAvRfsgoJPJbNq+64k2SqW6JcOAebWsFUvCCYgfzQMrnpvPiEl4OrblUlhF2ji+Q1+SVLrQ==" + }, + "runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "I8bKw2I8k58Wx7fMKQJn2R8lamboCAiHfHeV/pS65ScKWMMI0+wJkLYlEKvgW1D/XvSl/221clBoR2q9QNNM7A==" + }, + "runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "VB5cn/7OzUfzdnC8tqAIMQciVLiq2epm2NrAm1E9OjNRyG4lVhfR61SMcLizejzQP8R8Uf/0l5qOIbUEi+RdEg==" + }, + "SharpCompress": { + "type": "Transitive", + "resolved": "0.31.0", + "contentHash": "wFf5N0ysnlKbG54beDDm4Z1uqM0EAKTupEkTxyG4EGVE1uZgTtohuBd2BhTHR2gNweJ6agxKbMFzmzk181qqjw==" + }, + "System.AppContext": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "fKC+rmaLfeIzUhagxY17Q9siv/sPrjjKcfNg1Ic8IlQkZLipo8ljcaZQu4VtI4Jqbzjc2VTjzGLF6WmsRXAEgA==", + "dependencies": { + "System.Runtime": "4.3.0" + } + }, + "System.Buffers": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "ratu44uTIHgeBeI0dE8DWvmXVBSo4u7ozRZZHOMmK/JPpYyo0dAfgSiHlpiObMQ5lEtEyIXA40sKRYg5J6A8uQ==", + "dependencies": { + "System.Diagnostics.Debug": "4.3.0", + "System.Diagnostics.Tracing": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Threading": "4.3.0" + } + }, + "System.Collections": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "3Dcj85/TBdVpL5Zr+gEEBUuFe2icOnLalmEh9hfck1PTYbbyWuZgh4fmm2ysCLTrqLQw6t3TgTyJ+VLp+Qb+Lw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Collections.Concurrent": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "ztl69Xp0Y/UXCL+3v3tEU+lIy+bvjKNUmopn1wep/a291pVPK7dxBd6T7WnlQqRog+d1a/hSsgRsmFnIBKTPLQ==", + "dependencies": { + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Diagnostics.Tracing": "4.3.0", + "System.Globalization": "4.3.0", + "System.Reflection": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Threading": "4.3.0", + "System.Threading.Tasks": "4.3.0" + } + }, + "System.Console": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "DHDrIxiqk1h03m6khKWV2X8p/uvN79rgSqpilL6uzpmSfxfU5ng8VcPtW4qsDsQDHiTv6IPV9TmD5M/vElPNLg==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.IO": "4.3.0", + "System.Runtime": "4.3.0", + "System.Text.Encoding": "4.3.0" + } + }, + "System.Diagnostics.Debug": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "ZUhUOdqmaG5Jk3Xdb8xi5kIyQYAA4PnTNlHx1mu9ZY3qv4ELIdKbnL/akbGaKi2RnNUWaZsAs31rvzFdewTj2g==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Diagnostics.DiagnosticSource": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "tD6kosZnTAGdrEa0tZSuFyunMbt/5KYDnHdndJYGqZoNy00XVXyACd5d6KnE1YgYv3ne2CjtAfNXo/fwEhnKUA==", + "dependencies": { + "System.Collections": "4.3.0", + "System.Diagnostics.Tracing": "4.3.0", + "System.Reflection": "4.3.0", + "System.Runtime": "4.3.0", + "System.Threading": "4.3.0" + } + }, + "System.Diagnostics.Tools": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "UUvkJfSYJMM6x527dJg2VyWPSRqIVB0Z7dbjHst1zmwTXz5CcXSYJFWRpuigfbO1Lf7yfZiIaEUesfnl/g5EyA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Diagnostics.Tracing": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "rswfv0f/Cqkh78rA5S8eN8Neocz234+emGCtTF3lxPY96F+mmmUen6tbn0glN6PMvlKQb9bPAY5e9u7fgPTkKw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Globalization": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "kYdVd2f2PAdFGblzFswE4hkNANJBKRmsfa2X5LG2AcWE1c7/4t0pYae1L8vfZ5xvE2nK/R9JprtToA61OSHWIg==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Globalization.Calendars": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "GUlBtdOWT4LTV3I+9/PJW+56AnnChTaOqqTLFtdmype/L500M2LIyXgmtd9X2P2VOkmJd5c67H5SaC2QcL1bFA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Globalization": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Globalization.Extensions": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "FhKmdR6MPG+pxow6wGtNAWdZh7noIOpdD5TwQ3CprzgIE1bBBoim0vbR1+AWsWjQmU7zXHgQo4TWSP6lCeiWcQ==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "System.Globalization": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.InteropServices": "4.3.0" + } + }, + "System.IO": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "3qjaHvxQPDpSOYICjUoTsmoq5u6QJAFRUITgeT/4gqkF1bajbSmb1kwSxEA8AHlofqgcKJcM8udgieRNhaJ5Cg==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Threading.Tasks": "4.3.0" + } + }, + "System.IO.Compression": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "YHndyoiV90iu4iKG115ibkhrG+S3jBm8Ap9OwoUAzO5oPDAWcr0SFwQFm0HjM8WkEZWo0zvLTyLmbvTkW1bXgg==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "System.Buffers": "4.3.0", + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.IO": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Threading": "4.3.0", + "System.Threading.Tasks": "4.3.0", + "runtime.native.System": "4.3.0", + "runtime.native.System.IO.Compression": "4.3.0" + } + }, + "System.IO.Compression.ZipFile": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "G4HwjEsgIwy3JFBduZ9quBkAu+eUwjIdJleuNSgmUojbH6O3mlvEIme+GHx/cLlTAPcrnnL7GqvB9pTlWRfhOg==", + "dependencies": { + "System.Buffers": "4.3.0", + "System.IO": "4.3.0", + "System.IO.Compression": "4.3.0", + "System.IO.FileSystem": "4.3.0", + "System.IO.FileSystem.Primitives": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Text.Encoding": "4.3.0" + } + }, + "System.IO.FileSystem": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "3wEMARTnuio+ulnvi+hkRNROYwa1kylvYahhcLk4HSoVdl+xxTFVeVlYOfLwrDPImGls0mDqbMhrza8qnWPTdA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.IO": "4.3.0", + "System.IO.FileSystem.Primitives": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Threading.Tasks": "4.3.0" + } + }, + "System.IO.FileSystem.Primitives": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "6QOb2XFLch7bEc4lIcJH49nJN2HV+OC3fHDgsLVsBVBk3Y4hFAnOBGzJ2lUu7CyDDFo9IBWkSsnbkT6IBwwiMw==", + "dependencies": { + "System.Runtime": "4.3.0" + } + }, + "System.IO.Hashing": { + "type": "Transitive", + "resolved": "7.0.0", + "contentHash": "sDnWM0N3AMCa86LrKTWeF3BZLD2sgWyYUc7HL6z4+xyDZNQRwzmxbo4qP2rX2MqC+Sy1/gOSRDah5ltxY5jPxw==" + }, + "System.Linq": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "5DbqIUpsDp0dFftytzuMmc0oeMdQwjcP/EWxsksIz/w1TcFRkZ3yKKz0PqiYFMmEwPSWw+qNVqD7PJ889JzHbw==", + "dependencies": { + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0" + } + }, + "System.Linq.Expressions": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "PGKkrd2khG4CnlyJwxwwaWWiSiWFNBGlgXvJpeO0xCXrZ89ODrQ6tjEWS/kOqZ8GwEOUATtKtzp1eRgmYNfclg==", + "dependencies": { + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Globalization": "4.3.0", + "System.IO": "4.3.0", + "System.Linq": "4.3.0", + "System.ObjectModel": "4.3.0", + "System.Reflection": "4.3.0", + "System.Reflection.Emit": "4.3.0", + "System.Reflection.Emit.ILGeneration": "4.3.0", + "System.Reflection.Emit.Lightweight": "4.3.0", + "System.Reflection.Extensions": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Reflection.TypeExtensions": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Threading": "4.3.0" + } + }, + "System.Net.Http": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "sYg+FtILtRQuYWSIAuNOELwVuVsxVyJGWQyOnlAzhV4xvhyFnON1bAzYYC+jjRW8JREM45R0R5Dgi8MTC5sEwA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Diagnostics.DiagnosticSource": "4.3.0", + "System.Diagnostics.Tracing": "4.3.0", + "System.Globalization": "4.3.0", + "System.Globalization.Extensions": "4.3.0", + "System.IO": "4.3.0", + "System.IO.FileSystem": "4.3.0", + "System.Net.Primitives": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Security.Cryptography.Algorithms": "4.3.0", + "System.Security.Cryptography.Encoding": "4.3.0", + "System.Security.Cryptography.OpenSsl": "4.3.0", + "System.Security.Cryptography.Primitives": "4.3.0", + "System.Security.Cryptography.X509Certificates": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Threading": "4.3.0", + "System.Threading.Tasks": "4.3.0", + "runtime.native.System": "4.3.0", + "runtime.native.System.Net.Http": "4.3.0", + "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" + } + }, + "System.Net.Primitives": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "qOu+hDwFwoZPbzPvwut2qATe3ygjeQBDQj91xlsaqGFQUI5i4ZnZb8yyQuLGpDGivEPIt8EJkd1BVzVoP31FXA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0", + "System.Runtime.Handles": "4.3.0" + } + }, + "System.Net.Sockets": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "m6icV6TqQOAdgt5N/9I5KNpjom/5NFtkmGseEH+AK/hny8XrytLH3+b5M8zL/Ycg3fhIocFpUMyl/wpFnVRvdw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.IO": "4.3.0", + "System.Net.Primitives": "4.3.0", + "System.Runtime": "4.3.0", + "System.Threading.Tasks": "4.3.0" + } + }, + "System.ObjectModel": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "bdX+80eKv9bN6K4N+d77OankKHGn6CH711a6fcOpMQu2Fckp/Ft4L/kW9WznHpyR0NRAvJutzOMHNNlBGvxQzQ==", + "dependencies": { + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Threading": "4.3.0" + } + }, + "System.Reflection": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "KMiAFoW7MfJGa9nDFNcfu+FpEdiHpWgTcS2HdMpDvt9saK3y/G4GwprPyzqjFH9NTaGPQeWNHU+iDlDILj96aQ==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.IO": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Reflection.Emit": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "228FG0jLcIwTVJyz8CLFKueVqQK36ANazUManGaJHkO0icjiIypKW7YLWLIWahyIkdh5M7mV2dJepllLyA1SKg==", + "dependencies": { + "System.IO": "4.3.0", + "System.Reflection": "4.3.0", + "System.Reflection.Emit.ILGeneration": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Reflection.Emit.ILGeneration": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "59tBslAk9733NXLrUJrwNZEzbMAcu8k344OYo+wfSVygcgZ9lgBdGIzH/nrg3LYhXceynyvTc8t5/GD4Ri0/ng==", + "dependencies": { + "System.Reflection": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Reflection.Emit.Lightweight": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "oadVHGSMsTmZsAF864QYN1t1QzZjIcuKU3l2S9cZOwDdDueNTrqq1yRj7koFfIGEnKpt6NjpL3rOzRhs4ryOgA==", + "dependencies": { + "System.Reflection": "4.3.0", + "System.Reflection.Emit.ILGeneration": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Reflection.Extensions": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "rJkrJD3kBI5B712aRu4DpSIiHRtr6QlfZSQsb0hYHrDCZORXCFjQfoipo2LaMUHoT9i1B7j7MnfaEKWDFmFQNQ==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Reflection": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Reflection.Primitives": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "5RXItQz5As4xN2/YUDxdpsEkMhvw3e6aNveFXUn4Hl/udNTCNhnKp8lT9fnc3MhvGKh1baak5CovpuQUXHAlIA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Reflection.TypeExtensions": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "7u6ulLcZbyxB5Gq0nMkQttcdBTx57ibzw+4IOXEfR+sXYQoHvjW5LTLyNr8O22UIMrqYbchJQJnos4eooYzYJA==", + "dependencies": { + "System.Reflection": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Resources.ResourceManager": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "/zrcPkkWdZmI4F92gL/TPumP98AVDu/Wxr3CSJGQQ+XN6wbRZcyfSKVoPo17ilb3iOr0cCRqJInGwNMolqhS8A==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Globalization": "4.3.0", + "System.Reflection": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Runtime": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "JufQi0vPQ0xGnAczR13AUFglDyVYt4Kqnz1AZaiKZ5+GICq0/1MH/mO/eAJHt/mHW1zjKBJd7kV26SrxddAhiw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0" + } + }, + "System.Runtime.Extensions": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "guW0uK0fn5fcJJ1tJVXYd7/1h5F+pea1r7FLSOz/f8vPEqbR2ZAknuRDvTQ8PzAilDveOxNjSfr0CHfIQfFk8g==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Runtime.Handles": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "OKiSUN7DmTWeYb3l51A7EYaeNMnvxwE249YtZz7yooT4gOZhmTjIn48KgSsw2k2lYdLgTKNJw/ZIfSElwDRVgg==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Runtime.InteropServices": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "uv1ynXqiMK8mp1GM3jDqPCFN66eJ5w5XNomaK2XD+TuCroNTLFGeZ+WCmBMcBDyTFKou3P6cR6J/QsaqDp7fGQ==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Reflection": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Handles": "4.3.0" + } + }, + "System.Runtime.InteropServices.RuntimeInformation": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "cbz4YJMqRDR7oLeMRbdYv7mYzc++17lNhScCX0goO2XpGWdvAt60CGN+FHdePUEHCe/Jy9jUlvNAiNdM+7jsOw==", + "dependencies": { + "System.Reflection": "4.3.0", + "System.Reflection.Extensions": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Threading": "4.3.0", + "runtime.native.System": "4.3.0" + } + }, + "System.Runtime.Numerics": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "yMH+MfdzHjy17l2KESnPiF2dwq7T+xLnSJar7slyimAkUh/gTrS9/UQOtv7xarskJ2/XDSNvfLGOBQPjL7PaHQ==", + "dependencies": { + "System.Globalization": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0" + } + }, + "System.Security.Cryptography.Algorithms": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "W1kd2Y8mYSCgc3ULTAZ0hOP2dSdG5YauTb1089T0/kRcN2MpSAW1izOFROrJgxSlMn3ArsgHXagigyi+ibhevg==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "System.Collections": "4.3.0", + "System.IO": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Runtime.Numerics": "4.3.0", + "System.Security.Cryptography.Encoding": "4.3.0", + "System.Security.Cryptography.Primitives": "4.3.0", + "System.Text.Encoding": "4.3.0", + "runtime.native.System.Security.Cryptography.Apple": "4.3.0", + "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" + } + }, + "System.Security.Cryptography.Cng": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "03idZOqFlsKRL4W+LuCpJ6dBYDUWReug6lZjBa3uJWnk5sPCUXckocevTaUA8iT/MFSrY/2HXkOt753xQ/cf8g==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "System.IO": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Security.Cryptography.Algorithms": "4.3.0", + "System.Security.Cryptography.Encoding": "4.3.0", + "System.Security.Cryptography.Primitives": "4.3.0", + "System.Text.Encoding": "4.3.0" + } + }, + "System.Security.Cryptography.Csp": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "X4s/FCkEUnRGnwR3aSfVIkldBmtURMhmexALNTwpjklzxWU7yjMk7GHLKOZTNkgnWnE0q7+BCf9N2LVRWxewaA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "System.IO": "4.3.0", + "System.Reflection": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Security.Cryptography.Algorithms": "4.3.0", + "System.Security.Cryptography.Encoding": "4.3.0", + "System.Security.Cryptography.Primitives": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Threading": "4.3.0" + } + }, + "System.Security.Cryptography.Encoding": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "1DEWjZZly9ae9C79vFwqaO5kaOlI5q+3/55ohmq/7dpDyDfc8lYe7YVxJUZ5MF/NtbkRjwFRo14yM4OEo9EmDw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "System.Collections": "4.3.0", + "System.Collections.Concurrent": "4.3.0", + "System.Linq": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Security.Cryptography.Primitives": "4.3.0", + "System.Text.Encoding": "4.3.0", + "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" + } + }, + "System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "h4CEgOgv5PKVF/HwaHzJRiVboL2THYCou97zpmhjghx5frc7fIvlkY1jL+lnIQyChrJDMNEXS6r7byGif8Cy4w==", + "dependencies": { + "System.Collections": "4.3.0", + "System.IO": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Runtime.Numerics": "4.3.0", + "System.Security.Cryptography.Algorithms": "4.3.0", + "System.Security.Cryptography.Encoding": "4.3.0", + "System.Security.Cryptography.Primitives": "4.3.0", + "System.Text.Encoding": "4.3.0", + "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" + } + }, + "System.Security.Cryptography.Primitives": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "7bDIyVFNL/xKeFHjhobUAQqSpJq9YTOpbEs6mR233Et01STBMXNAc/V+BM6dwYGc95gVh/Zf+iVXWzj3mE8DWg==", + "dependencies": { + "System.Diagnostics.Debug": "4.3.0", + "System.Globalization": "4.3.0", + "System.IO": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Threading": "4.3.0", + "System.Threading.Tasks": "4.3.0" + } + }, + "System.Security.Cryptography.X509Certificates": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "t2Tmu6Y2NtJ2um0RtcuhP7ZdNNxXEgUm2JeoA/0NvlMjAhKCnM1NX07TDl3244mVp3QU6LPEhT3HTtH1uF7IYw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Globalization": "4.3.0", + "System.Globalization.Calendars": "4.3.0", + "System.IO": "4.3.0", + "System.IO.FileSystem": "4.3.0", + "System.IO.FileSystem.Primitives": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Runtime.Numerics": "4.3.0", + "System.Security.Cryptography.Algorithms": "4.3.0", + "System.Security.Cryptography.Cng": "4.3.0", + "System.Security.Cryptography.Csp": "4.3.0", + "System.Security.Cryptography.Encoding": "4.3.0", + "System.Security.Cryptography.OpenSsl": "4.3.0", + "System.Security.Cryptography.Primitives": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Threading": "4.3.0", + "runtime.native.System": "4.3.0", + "runtime.native.System.Net.Http": "4.3.0", + "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" + } + }, + "System.Text.Encoding": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "BiIg+KWaSDOITze6jGQynxg64naAPtqGHBwDrLaCtixsa5bKiR8dpPOHA7ge3C0JJQizJE+sfkz1wV+BAKAYZw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Text.Encoding.Extensions": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "YVMK0Bt/A43RmwizJoZ22ei2nmrhobgeiYwFzC4YAN+nue8RF6djXDMog0UCn+brerQoYVyaS+ghy9P/MUVcmw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0", + "System.Text.Encoding": "4.3.0" + } + }, + "System.Text.Json": { + "type": "Transitive", + "resolved": "5.0.2", + "contentHash": "I47dVIGiV6SfAyppphxqupertT/5oZkYLDCX6vC3HpOI4ZLjyoKAreUoem2ie6G0RbRuFrlqz/PcTQjfb2DOfQ==" + }, + "System.Text.RegularExpressions": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "RpT2DA+L660cBt1FssIE9CAGpLFdFPuheB7pLpKpn6ZXNby7jDERe8Ua/Ne2xGiwLVG2JOqziiaVCGDon5sKFA==", + "dependencies": { + "System.Runtime": "4.3.0" + } + }, + "System.Threading": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "VkUS0kOBcUf3Wwm0TSbrevDDZ6BlM+b/HRiapRFWjM5O0NS0LviG0glKmFK+hhPDd1XFeSdU1GmlLhb2CoVpIw==", + "dependencies": { + "System.Runtime": "4.3.0", + "System.Threading.Tasks": "4.3.0" + } + }, + "System.Threading.Tasks": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "LbSxKEdOUhVe8BezB/9uOGGppt+nZf6e1VFyw6v3DN6lqitm0OSn2uXMOdtP0M3W4iMcqcivm2J6UgqiwwnXiA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Threading.Tasks.Extensions": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "npvJkVKl5rKXrtl1Kkm6OhOUaYGEiF9wFbppFRWSMoApKzt2PiPHT2Bb8a5sAWxprvdOAtvaARS9QYMznEUtug==", + "dependencies": { + "System.Collections": "4.3.0", + "System.Runtime": "4.3.0", + "System.Threading.Tasks": "4.3.0" + } + }, + "System.Threading.Timer": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "Z6YfyYTCg7lOZjJzBjONJTFKGN9/NIYKSxhU5GRd+DTwHSZyvWp1xuI5aR+dLg+ayyC5Xv57KiY4oJ0tMO89fQ==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Xml.ReaderWriter": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "GrprA+Z0RUXaR4N7/eW71j1rgMnEnEVlgii49GZyAjTH7uliMnrOU3HNFBr6fEDBCJCIdlVNq9hHbaDR621XBA==", + "dependencies": { + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Globalization": "4.3.0", + "System.IO": "4.3.0", + "System.IO.FileSystem": "4.3.0", + "System.IO.FileSystem.Primitives": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Text.Encoding.Extensions": "4.3.0", + "System.Text.RegularExpressions": "4.3.0", + "System.Threading.Tasks": "4.3.0", + "System.Threading.Tasks.Extensions": "4.3.0" + } + }, + "System.Xml.XDocument": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "5zJ0XDxAIg8iy+t4aMnQAu0MqVbqyvfoUVl1yDV61xdo3Vth45oA2FoY4pPkxYAH5f8ixpmTqXeEIya95x0aCQ==", + "dependencies": { + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Diagnostics.Tools": "4.3.0", + "System.Globalization": "4.3.0", + "System.IO": "4.3.0", + "System.Reflection": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Threading": "4.3.0", + "System.Xml.ReaderWriter": "4.3.0" + } + }, + "colorthief": { + "type": "Project", + "dependencies": { + "System.Drawing.Common": "[7.0.0, )" + } + }, + "hi3helper.core": { + "type": "Project", + "dependencies": { + "Hi3Helper.EncTool": "[1.0.0, )", + "Hi3Helper.Http": "[1.0.0, )", + "Hi3Helper.SharpHDiffPatch": "[1.0.0, )" + } + }, + "hi3helper.enctool": { + "type": "Project", + "dependencies": { + "Google.Protobuf": "[3.23.4, )", + "Hi3Helper.Http": "[1.0.0, )", + "System.IO.Hashing": "[7.0.0, )" + } + }, + "hi3helper.http": { + "type": "Project" + }, + "hi3helper.sharphdiffpatch": { + "type": "Project" + } + }, + "net7.0-windows10.0.22000": { + "Clowd.Squirrel": { + "type": "Direct", + "requested": "[2.9.42, )", + "resolved": "2.9.42", + "contentHash": "bM7h3tqoenZD+tmiV7pUnFdJ/o1oOrC21PaS8crMDRDOuGB4YqsgzlUKFD1g8X6z64IRBqzlUwEKzpsFyFc0mQ==", + "dependencies": { + "SharpCompress": "0.31.0" + } + }, + "CommunityToolkit.WinUI.UI": { + "type": "Direct", + "requested": "[7.1.2, )", + "resolved": "7.1.2", + "contentHash": "jF1GdEJsZX5o81ZfLjSjgC5RuYwQneuW2mdFIb7FDFzITsgqCn7mfn7BglpNiXvjExkocmAKbBgmCcbp0Nypmw==", + "dependencies": { + "CommunityToolkit.WinUI": "7.1.2", + "Microsoft.WindowsAppSDK": "1.0.0" + } + }, + "CommunityToolkit.WinUI.UI.Controls": { + "type": "Direct", + "requested": "[7.1.2, )", + "resolved": "7.1.2", + "contentHash": "+aDc1KqmlYM+HE0Mw5OnfQBOFhY0c7zp1aGz/4qs+1I+Xk8Ot3IRwvs8dYxBEGCD9YzE2OzaJLPztBpQ9JEWig==", + "dependencies": { + "CommunityToolkit.WinUI.UI.Controls.Core": "7.1.2", + "CommunityToolkit.WinUI.UI.Controls.DataGrid": "7.1.2", + "CommunityToolkit.WinUI.UI.Controls.Input": "7.1.2", + "CommunityToolkit.WinUI.UI.Controls.Layout": "7.1.2", + "CommunityToolkit.WinUI.UI.Controls.Markdown": "7.1.2", + "CommunityToolkit.WinUI.UI.Controls.Media": "7.1.2", + "CommunityToolkit.WinUI.UI.Controls.Primitives": "7.1.2", + "Microsoft.WindowsAppSDK": "1.0.0" + } + }, + "Microsoft.Windows.CsWinRT": { + "type": "Direct", + "requested": "[2.0.3, )", + "resolved": "2.0.3", + "contentHash": "viZIwWVUBp7x9QprOZbvocWasVIAfaXN2BK7tgMijYKe4X+WuU1m4RdqE8P2wv+o3q0Bk8mWsUFaMm36rsCvNg==" + }, + "Microsoft.Windows.SDK.BuildTools": { + "type": "Direct", + "requested": "[10.0.22621.756, )", + "resolved": "10.0.22621.756", + "contentHash": "7ZL2sFSioYm1Ry067Kw1hg0SCcW5kuVezC2SwjGbcPE61Nn+gTbH86T73G3LcEOVj0S3IZzNuE/29gZvOLS7VA==" + }, + "Microsoft.WindowsAppSDK": { + "type": "Direct", + "requested": "[1.3.230724000, )", + "resolved": "1.3.230724000", + "contentHash": "cCw26h8Uh8IjDMOUzHaR7/IKxEVJxuqEOgBlmLj0Pu1wDezZb9J0Wz53Vop10FQUOZaTfnwDcHavyPTxgkwbKQ==", + "dependencies": { + "Microsoft.Windows.SDK.BuildTools": "10.0.22621.1" + } + }, + "System.CommandLine": { + "type": "Direct", + "requested": "[2.0.0-beta3.22114.1, )", + "resolved": "2.0.0-beta3.22114.1", + "contentHash": "QMzk1jj+PzdGbwuVsxII7FcQaCelnK+TcRcAqOGVoPovLBCSQPdikKiEzb56vAidvum5t4LSdDZ34O4j7+ALgw==" + }, + "System.Drawing.Common": { + "type": "Direct", + "requested": "[7.0.0, )", + "resolved": "7.0.0", + "contentHash": "KIX+oBU38pxkKPxvLcLfIkOV5Ien8ReN78wro7OF5/erwcmortzeFx+iBswlh2Vz6gVne0khocQudGwaO1Ey6A==", + "dependencies": { + "Microsoft.Win32.SystemEvents": "7.0.0" + } + }, + "ColorCode.Core": { + "type": "Transitive", + "resolved": "2.0.13", + "contentHash": "v0xqipj/6h2TpIKSrOCZpXMmOGvLsyO2prWBXY6t+lduexDSimqKIZXTTZkpq/vG2kNxB8K8nzyrkIB3usoN7A==", + "dependencies": { + "NETStandard.Library": "1.6.1" + } + }, + "ColorCode.WinUI": { + "type": "Transitive", + "resolved": "2.0.13", + "contentHash": "FPuyaXOb9LaD6nSUXtMrK/l564tmRbCfMiQWrnKzzLhJnnRuWkU2JpSJjV2KGCrjyx5ol7wy7TiK0GnGnPsIEA==", + "dependencies": { + "ColorCode.Core": "2.0.13", + "Microsoft.WindowsAppSDK": "1.0.0" + } + }, + "CommunityToolkit.Common": { + "type": "Transitive", + "resolved": "7.1.2", + "contentHash": "KnHnukN+Sc26YT98OWYTp8mvaYlLc61lzDh0RrVRNQXm01hZ+iXAjCgKM59vAojqxNVrlbcXj22LYOyXWDItgg==" + }, + "CommunityToolkit.WinUI": { + "type": "Transitive", + "resolved": "7.1.2", + "contentHash": "0O6hCHy+/adJygcROD3r3yA41gRq972i/r6uGUfo8lfEbr/I1YGePTClAh1P9JYT7DdoI2IqeUhX05lq+rwrHg==", + "dependencies": { + "CommunityToolkit.Common": "7.1.2", + "Microsoft.WindowsAppSDK": "1.0.0" + } + }, + "CommunityToolkit.WinUI.UI.Controls.Core": { + "type": "Transitive", + "resolved": "7.1.2", + "contentHash": "7MVYQKjYlD5SryWNy5FA7Pcer9Rphjk7hCrSIOT9m4dcsOYmekZf36TOJARKxySXvlmjNud6QkmWssJKFC4k5w==", + "dependencies": { + "CommunityToolkit.WinUI": "7.1.2", + "CommunityToolkit.WinUI.UI.Controls.Primitives": "7.1.2", + "Microsoft.WindowsAppSDK": "1.0.0" + } + }, + "CommunityToolkit.WinUI.UI.Controls.DataGrid": { + "type": "Transitive", + "resolved": "7.1.2", + "contentHash": "F73oYdYza8zhDwGHdXCZJJMeiDJ6nR97WPe180o7jOX3U90ZIqvU/GtYZdN3/x8DOS48t5GQG70LqxfyIGeaxw==", + "dependencies": { + "Microsoft.WindowsAppSDK": "1.0.0" + } + }, + "CommunityToolkit.WinUI.UI.Controls.Input": { + "type": "Transitive", + "resolved": "7.1.2", + "contentHash": "fT8s21NI51YCR/mgm1eabwnSSQuXnQRz/TqHKjzYABhfGSvl44YlvuAQzbE9VfZSEUtiv4kesgylrzKd4/dArg==", + "dependencies": { + "CommunityToolkit.WinUI.UI.Controls.Primitives": "7.1.2", + "Microsoft.WindowsAppSDK": "1.0.0" + } + }, + "CommunityToolkit.WinUI.UI.Controls.Layout": { + "type": "Transitive", + "resolved": "7.1.2", + "contentHash": "FpKo2DdJgREAvttTYhOJTy1ru6ODRG41Da+vMrB7bcqavdbPgSTqYzolLcgvMl2InpIdt+fqn6U6mGQYoV+ksQ==", + "dependencies": { + "CommunityToolkit.WinUI.UI": "7.1.2", + "Microsoft.WindowsAppSDK": "1.0.0" + } + }, + "CommunityToolkit.WinUI.UI.Controls.Markdown": { + "type": "Transitive", + "resolved": "7.1.2", + "contentHash": "0hAhwBfWa7aWKYOPGxhJJXowjrncY4he8jizcbuPVCgv8tZS1LXEEH4MoGKq57iLKz2lG3qaVN+1trcDWYq0Sg==", + "dependencies": { + "ColorCode.WinUI": "2.0.13", + "CommunityToolkit.WinUI.UI": "7.1.2", + "CommunityToolkit.WinUI.UI.Controls.Core": "7.1.2", + "Microsoft.WindowsAppSDK": "1.0.0" + } + }, + "CommunityToolkit.WinUI.UI.Controls.Media": { + "type": "Transitive", + "resolved": "7.1.2", + "contentHash": "FFH1mNF+rp3GEIQOceoxzSrRVY3G8aA+sYoK6Fv1kDEFWlCfLYF+cSCexL4sBuw0ARs1QXUvNqW4T1F/nAWsdw==", + "dependencies": { + "CommunityToolkit.WinUI.UI": "7.1.2", + "Microsoft.Graphics.Win2D": "1.0.0.30", + "Microsoft.WindowsAppSDK": "1.0.0", + "System.Text.Json": "5.0.2" + } + }, + "CommunityToolkit.WinUI.UI.Controls.Primitives": { + "type": "Transitive", + "resolved": "7.1.2", + "contentHash": "mNtVRpBVnFzSywRzzLPXBIoYm4UWJPZkpNPNAu75lnl4KcnkfjjyQg90hkfF9MT/JkBJQG0z5XOdMCksn7EiMQ==", + "dependencies": { + "CommunityToolkit.WinUI.UI": "7.1.2", + "Microsoft.WindowsAppSDK": "1.0.0" + } + }, + "Google.Protobuf": { + "type": "Transitive", + "resolved": "3.23.4", + "contentHash": "DF+mB+Fwan5Hm5dnbKbrIl7C5ypMr8tJJheutkYgFXCoM88HfBNo2qYO60CEf6fvEe/fhCGtvfEBCoCIhIn7dQ==" + }, + "Microsoft.Graphics.Win2D": { + "type": "Transitive", + "resolved": "1.0.0.30", + "contentHash": "pEGf7FSx2dRWJuoaSoXk+WYkZfYwhWoJKOyyo0XLRU6V2Ul02MjxRhoxggrzGz6jVFiT7R2NdPdV8M6N1F+QfA==" + }, + "Microsoft.NETCore.Platforms": { + "type": "Transitive", + "resolved": "1.1.0", + "contentHash": "kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A==" + }, + "Microsoft.NETCore.Targets": { + "type": "Transitive", + "resolved": "1.1.0", + "contentHash": "aOZA3BWfz9RXjpzt0sRJJMjAscAUm3Hoa4UWAfceV9UTYxgwZ1lZt5nO2myFf+/jetYQo4uTP7zS8sJY67BBxg==" + }, + "Microsoft.Win32.Primitives": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "9ZQKCWxH7Ijp9BfahvL2Zyf1cJIk8XYLF6Yjzr2yi0b2cOut/HQ31qf1ThHAgCc3WiZMdnWcfJCgN82/0UunxA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "Microsoft.Win32.SystemEvents": { + "type": "Transitive", + "resolved": "7.0.0", + "contentHash": "2nXPrhdAyAzir0gLl8Yy8S5Mnm/uBSQQA7jEsILOS1MTyS7DbmV1NgViMtvV1sfCD1ebITpNwb1NIinKeJgUVQ==" + }, + "NETStandard.Library": { + "type": "Transitive", + "resolved": "1.6.1", + "contentHash": "WcSp3+vP+yHNgS8EV5J7pZ9IRpeDuARBPN28by8zqff1wJQXm26PVU8L3/fYLBJVU7BtDyqNVWq2KlCVvSSR4A==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.Win32.Primitives": "4.3.0", + "System.AppContext": "4.3.0", + "System.Collections": "4.3.0", + "System.Collections.Concurrent": "4.3.0", + "System.Console": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Diagnostics.Tools": "4.3.0", + "System.Diagnostics.Tracing": "4.3.0", + "System.Globalization": "4.3.0", + "System.Globalization.Calendars": "4.3.0", + "System.IO": "4.3.0", + "System.IO.Compression": "4.3.0", + "System.IO.Compression.ZipFile": "4.3.0", + "System.IO.FileSystem": "4.3.0", + "System.IO.FileSystem.Primitives": "4.3.0", + "System.Linq": "4.3.0", + "System.Linq.Expressions": "4.3.0", + "System.Net.Http": "4.3.0", + "System.Net.Primitives": "4.3.0", + "System.Net.Sockets": "4.3.0", + "System.ObjectModel": "4.3.0", + "System.Reflection": "4.3.0", + "System.Reflection.Extensions": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Runtime.InteropServices.RuntimeInformation": "4.3.0", + "System.Runtime.Numerics": "4.3.0", + "System.Security.Cryptography.Algorithms": "4.3.0", + "System.Security.Cryptography.Encoding": "4.3.0", + "System.Security.Cryptography.Primitives": "4.3.0", + "System.Security.Cryptography.X509Certificates": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Text.Encoding.Extensions": "4.3.0", + "System.Text.RegularExpressions": "4.3.0", + "System.Threading": "4.3.0", + "System.Threading.Tasks": "4.3.0", + "System.Threading.Timer": "4.3.0", + "System.Xml.ReaderWriter": "4.3.0", + "System.Xml.XDocument": "4.3.0" + } + }, + "runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "HdSSp5MnJSsg08KMfZThpuLPJpPwE5hBXvHwoKWosyHHfe8Mh5WKT0ylEOf6yNzX6Ngjxe4Whkafh5q7Ymac4Q==" + }, + "runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "+yH1a49wJMy8Zt4yx5RhJrxO/DBDByAiCzNwiETI+1S4mPdCu0OY4djdciC7Vssk0l22wQaDLrXxXkp+3+7bVA==" + }, + "runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "c3YNH1GQJbfIPJeCnr4avseugSqPrxwIqzthYyZDN6EuOyNOzq+y2KSUfRcXauya1sF4foESTgwM5e1A8arAKw==" + }, + "runtime.native.System": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "c/qWt2LieNZIj1jGnVNsE2Kl23Ya2aSTBuXMD6V7k9KWr6l16Tqdwq+hJScEpWER9753NWC8h96PaVNY5Ld7Jw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0" + } + }, + "runtime.native.System.IO.Compression": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "INBPonS5QPEgn7naufQFXJEp3zX6L4bwHgJ/ZH78aBTpeNfQMtf7C6VrAFhlq2xxWBveIOWyFzQjJ8XzHMhdOQ==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0" + } + }, + "runtime.native.System.Net.Http": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "ZVuZJqnnegJhd2k/PtAbbIcZ3aZeITq3sj06oKfMBSfphW3HDmk/t4ObvbOk/JA/swGR0LNqMksAh/f7gpTROg==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0" + } + }, + "runtime.native.System.Security.Cryptography.Apple": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "DloMk88juo0OuOWr56QG7MNchmafTLYWvABy36izkrLI5VledI0rq28KGs1i9wbpeT9NPQrx/wTf8U2vazqQ3Q==", + "dependencies": { + "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.Apple": "4.3.0" + } + }, + "runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "NS1U+700m4KFRHR5o4vo9DSlTmlCKu/u7dtE5sUHVIPB+xpXxYQvgBgA6wEIeCz6Yfn0Z52/72WYsToCEPJnrw==", + "dependencies": { + "runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0", + "runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0", + "runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0", + "runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0", + "runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0", + "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0", + "runtime.rhel.7-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0", + "runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0", + "runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0", + "runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" + } + }, + "runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "b3pthNgxxFcD+Pc0WSEoC0+md3MyhRS6aCEeenvNE3Fdw1HyJ18ZhRFVJJzIeR/O/jpxPboB805Ho0T3Ul7w8A==" + }, + "runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "KeLz4HClKf+nFS7p/6Fi/CqyLXh81FpiGzcmuS8DGi9lUqSnZ6Es23/gv2O+1XVGfrbNmviF7CckBpavkBoIFQ==" + }, + "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.Apple": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "kVXCuMTrTlxq4XOOMAysuNwsXWpYeboGddNGpIgNSZmv1b6r/s/DPk0fYMB7Q5Qo4bY68o48jt4T4y5BVecbCQ==" + }, + "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "X7IdhILzr4ROXd8mI1BUCQMSHSQwelUlBjF1JyTKCjXaOGn2fB4EKBxQbCK2VjO3WaWIdlXZL3W6TiIVnrhX4g==" + }, + "runtime.rhel.7-x64.runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "nyFNiCk/r+VOiIqreLix8yN+q3Wga9+SE8BCgkf+2BwEKiNx6DyvFjCgkfV743/grxv8jHJ8gUK4XEQw7yzRYg==" + }, + "runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "ytoewC6wGorL7KoCAvRfsgoJPJbNq+64k2SqW6JcOAebWsFUvCCYgfzQMrnpvPiEl4OrblUlhF2ji+Q1+SVLrQ==" + }, + "runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "I8bKw2I8k58Wx7fMKQJn2R8lamboCAiHfHeV/pS65ScKWMMI0+wJkLYlEKvgW1D/XvSl/221clBoR2q9QNNM7A==" + }, + "runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "VB5cn/7OzUfzdnC8tqAIMQciVLiq2epm2NrAm1E9OjNRyG4lVhfR61SMcLizejzQP8R8Uf/0l5qOIbUEi+RdEg==" + }, + "SharpCompress": { + "type": "Transitive", + "resolved": "0.31.0", + "contentHash": "wFf5N0ysnlKbG54beDDm4Z1uqM0EAKTupEkTxyG4EGVE1uZgTtohuBd2BhTHR2gNweJ6agxKbMFzmzk181qqjw==" + }, + "System.AppContext": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "fKC+rmaLfeIzUhagxY17Q9siv/sPrjjKcfNg1Ic8IlQkZLipo8ljcaZQu4VtI4Jqbzjc2VTjzGLF6WmsRXAEgA==", + "dependencies": { + "System.Runtime": "4.3.0" + } + }, + "System.Buffers": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "ratu44uTIHgeBeI0dE8DWvmXVBSo4u7ozRZZHOMmK/JPpYyo0dAfgSiHlpiObMQ5lEtEyIXA40sKRYg5J6A8uQ==", + "dependencies": { + "System.Diagnostics.Debug": "4.3.0", + "System.Diagnostics.Tracing": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Threading": "4.3.0" + } + }, + "System.Collections": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "3Dcj85/TBdVpL5Zr+gEEBUuFe2icOnLalmEh9hfck1PTYbbyWuZgh4fmm2ysCLTrqLQw6t3TgTyJ+VLp+Qb+Lw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Collections.Concurrent": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "ztl69Xp0Y/UXCL+3v3tEU+lIy+bvjKNUmopn1wep/a291pVPK7dxBd6T7WnlQqRog+d1a/hSsgRsmFnIBKTPLQ==", + "dependencies": { + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Diagnostics.Tracing": "4.3.0", + "System.Globalization": "4.3.0", + "System.Reflection": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Threading": "4.3.0", + "System.Threading.Tasks": "4.3.0" + } + }, + "System.Console": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "DHDrIxiqk1h03m6khKWV2X8p/uvN79rgSqpilL6uzpmSfxfU5ng8VcPtW4qsDsQDHiTv6IPV9TmD5M/vElPNLg==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.IO": "4.3.0", + "System.Runtime": "4.3.0", + "System.Text.Encoding": "4.3.0" + } + }, + "System.Diagnostics.Debug": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "ZUhUOdqmaG5Jk3Xdb8xi5kIyQYAA4PnTNlHx1mu9ZY3qv4ELIdKbnL/akbGaKi2RnNUWaZsAs31rvzFdewTj2g==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Diagnostics.DiagnosticSource": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "tD6kosZnTAGdrEa0tZSuFyunMbt/5KYDnHdndJYGqZoNy00XVXyACd5d6KnE1YgYv3ne2CjtAfNXo/fwEhnKUA==", + "dependencies": { + "System.Collections": "4.3.0", + "System.Diagnostics.Tracing": "4.3.0", + "System.Reflection": "4.3.0", + "System.Runtime": "4.3.0", + "System.Threading": "4.3.0" + } + }, + "System.Diagnostics.Tools": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "UUvkJfSYJMM6x527dJg2VyWPSRqIVB0Z7dbjHst1zmwTXz5CcXSYJFWRpuigfbO1Lf7yfZiIaEUesfnl/g5EyA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Diagnostics.Tracing": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "rswfv0f/Cqkh78rA5S8eN8Neocz234+emGCtTF3lxPY96F+mmmUen6tbn0glN6PMvlKQb9bPAY5e9u7fgPTkKw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Globalization": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "kYdVd2f2PAdFGblzFswE4hkNANJBKRmsfa2X5LG2AcWE1c7/4t0pYae1L8vfZ5xvE2nK/R9JprtToA61OSHWIg==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Globalization.Calendars": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "GUlBtdOWT4LTV3I+9/PJW+56AnnChTaOqqTLFtdmype/L500M2LIyXgmtd9X2P2VOkmJd5c67H5SaC2QcL1bFA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Globalization": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Globalization.Extensions": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "FhKmdR6MPG+pxow6wGtNAWdZh7noIOpdD5TwQ3CprzgIE1bBBoim0vbR1+AWsWjQmU7zXHgQo4TWSP6lCeiWcQ==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "System.Globalization": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.InteropServices": "4.3.0" + } + }, + "System.IO": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "3qjaHvxQPDpSOYICjUoTsmoq5u6QJAFRUITgeT/4gqkF1bajbSmb1kwSxEA8AHlofqgcKJcM8udgieRNhaJ5Cg==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Threading.Tasks": "4.3.0" + } + }, + "System.IO.Compression": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "YHndyoiV90iu4iKG115ibkhrG+S3jBm8Ap9OwoUAzO5oPDAWcr0SFwQFm0HjM8WkEZWo0zvLTyLmbvTkW1bXgg==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "System.Buffers": "4.3.0", + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.IO": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Threading": "4.3.0", + "System.Threading.Tasks": "4.3.0", + "runtime.native.System": "4.3.0", + "runtime.native.System.IO.Compression": "4.3.0" + } + }, + "System.IO.Compression.ZipFile": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "G4HwjEsgIwy3JFBduZ9quBkAu+eUwjIdJleuNSgmUojbH6O3mlvEIme+GHx/cLlTAPcrnnL7GqvB9pTlWRfhOg==", + "dependencies": { + "System.Buffers": "4.3.0", + "System.IO": "4.3.0", + "System.IO.Compression": "4.3.0", + "System.IO.FileSystem": "4.3.0", + "System.IO.FileSystem.Primitives": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Text.Encoding": "4.3.0" + } + }, + "System.IO.FileSystem": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "3wEMARTnuio+ulnvi+hkRNROYwa1kylvYahhcLk4HSoVdl+xxTFVeVlYOfLwrDPImGls0mDqbMhrza8qnWPTdA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.IO": "4.3.0", + "System.IO.FileSystem.Primitives": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Threading.Tasks": "4.3.0" + } + }, + "System.IO.FileSystem.Primitives": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "6QOb2XFLch7bEc4lIcJH49nJN2HV+OC3fHDgsLVsBVBk3Y4hFAnOBGzJ2lUu7CyDDFo9IBWkSsnbkT6IBwwiMw==", + "dependencies": { + "System.Runtime": "4.3.0" + } + }, + "System.IO.Hashing": { + "type": "Transitive", + "resolved": "7.0.0", + "contentHash": "sDnWM0N3AMCa86LrKTWeF3BZLD2sgWyYUc7HL6z4+xyDZNQRwzmxbo4qP2rX2MqC+Sy1/gOSRDah5ltxY5jPxw==" + }, + "System.Linq": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "5DbqIUpsDp0dFftytzuMmc0oeMdQwjcP/EWxsksIz/w1TcFRkZ3yKKz0PqiYFMmEwPSWw+qNVqD7PJ889JzHbw==", + "dependencies": { + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0" + } + }, + "System.Linq.Expressions": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "PGKkrd2khG4CnlyJwxwwaWWiSiWFNBGlgXvJpeO0xCXrZ89ODrQ6tjEWS/kOqZ8GwEOUATtKtzp1eRgmYNfclg==", + "dependencies": { + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Globalization": "4.3.0", + "System.IO": "4.3.0", + "System.Linq": "4.3.0", + "System.ObjectModel": "4.3.0", + "System.Reflection": "4.3.0", + "System.Reflection.Emit": "4.3.0", + "System.Reflection.Emit.ILGeneration": "4.3.0", + "System.Reflection.Emit.Lightweight": "4.3.0", + "System.Reflection.Extensions": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Reflection.TypeExtensions": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Threading": "4.3.0" + } + }, + "System.Net.Http": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "sYg+FtILtRQuYWSIAuNOELwVuVsxVyJGWQyOnlAzhV4xvhyFnON1bAzYYC+jjRW8JREM45R0R5Dgi8MTC5sEwA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Diagnostics.DiagnosticSource": "4.3.0", + "System.Diagnostics.Tracing": "4.3.0", + "System.Globalization": "4.3.0", + "System.Globalization.Extensions": "4.3.0", + "System.IO": "4.3.0", + "System.IO.FileSystem": "4.3.0", + "System.Net.Primitives": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Security.Cryptography.Algorithms": "4.3.0", + "System.Security.Cryptography.Encoding": "4.3.0", + "System.Security.Cryptography.OpenSsl": "4.3.0", + "System.Security.Cryptography.Primitives": "4.3.0", + "System.Security.Cryptography.X509Certificates": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Threading": "4.3.0", + "System.Threading.Tasks": "4.3.0", + "runtime.native.System": "4.3.0", + "runtime.native.System.Net.Http": "4.3.0", + "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" + } + }, + "System.Net.Primitives": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "qOu+hDwFwoZPbzPvwut2qATe3ygjeQBDQj91xlsaqGFQUI5i4ZnZb8yyQuLGpDGivEPIt8EJkd1BVzVoP31FXA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0", + "System.Runtime.Handles": "4.3.0" + } + }, + "System.Net.Sockets": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "m6icV6TqQOAdgt5N/9I5KNpjom/5NFtkmGseEH+AK/hny8XrytLH3+b5M8zL/Ycg3fhIocFpUMyl/wpFnVRvdw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.IO": "4.3.0", + "System.Net.Primitives": "4.3.0", + "System.Runtime": "4.3.0", + "System.Threading.Tasks": "4.3.0" + } + }, + "System.ObjectModel": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "bdX+80eKv9bN6K4N+d77OankKHGn6CH711a6fcOpMQu2Fckp/Ft4L/kW9WznHpyR0NRAvJutzOMHNNlBGvxQzQ==", + "dependencies": { + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Threading": "4.3.0" + } + }, + "System.Reflection": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "KMiAFoW7MfJGa9nDFNcfu+FpEdiHpWgTcS2HdMpDvt9saK3y/G4GwprPyzqjFH9NTaGPQeWNHU+iDlDILj96aQ==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.IO": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Reflection.Emit": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "228FG0jLcIwTVJyz8CLFKueVqQK36ANazUManGaJHkO0icjiIypKW7YLWLIWahyIkdh5M7mV2dJepllLyA1SKg==", + "dependencies": { + "System.IO": "4.3.0", + "System.Reflection": "4.3.0", + "System.Reflection.Emit.ILGeneration": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Reflection.Emit.ILGeneration": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "59tBslAk9733NXLrUJrwNZEzbMAcu8k344OYo+wfSVygcgZ9lgBdGIzH/nrg3LYhXceynyvTc8t5/GD4Ri0/ng==", + "dependencies": { + "System.Reflection": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Reflection.Emit.Lightweight": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "oadVHGSMsTmZsAF864QYN1t1QzZjIcuKU3l2S9cZOwDdDueNTrqq1yRj7koFfIGEnKpt6NjpL3rOzRhs4ryOgA==", + "dependencies": { + "System.Reflection": "4.3.0", + "System.Reflection.Emit.ILGeneration": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Reflection.Extensions": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "rJkrJD3kBI5B712aRu4DpSIiHRtr6QlfZSQsb0hYHrDCZORXCFjQfoipo2LaMUHoT9i1B7j7MnfaEKWDFmFQNQ==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Reflection": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Reflection.Primitives": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "5RXItQz5As4xN2/YUDxdpsEkMhvw3e6aNveFXUn4Hl/udNTCNhnKp8lT9fnc3MhvGKh1baak5CovpuQUXHAlIA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Reflection.TypeExtensions": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "7u6ulLcZbyxB5Gq0nMkQttcdBTx57ibzw+4IOXEfR+sXYQoHvjW5LTLyNr8O22UIMrqYbchJQJnos4eooYzYJA==", + "dependencies": { + "System.Reflection": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Resources.ResourceManager": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "/zrcPkkWdZmI4F92gL/TPumP98AVDu/Wxr3CSJGQQ+XN6wbRZcyfSKVoPo17ilb3iOr0cCRqJInGwNMolqhS8A==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Globalization": "4.3.0", + "System.Reflection": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Runtime": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "JufQi0vPQ0xGnAczR13AUFglDyVYt4Kqnz1AZaiKZ5+GICq0/1MH/mO/eAJHt/mHW1zjKBJd7kV26SrxddAhiw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0" + } + }, + "System.Runtime.Extensions": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "guW0uK0fn5fcJJ1tJVXYd7/1h5F+pea1r7FLSOz/f8vPEqbR2ZAknuRDvTQ8PzAilDveOxNjSfr0CHfIQfFk8g==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Runtime.Handles": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "OKiSUN7DmTWeYb3l51A7EYaeNMnvxwE249YtZz7yooT4gOZhmTjIn48KgSsw2k2lYdLgTKNJw/ZIfSElwDRVgg==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Runtime.InteropServices": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "uv1ynXqiMK8mp1GM3jDqPCFN66eJ5w5XNomaK2XD+TuCroNTLFGeZ+WCmBMcBDyTFKou3P6cR6J/QsaqDp7fGQ==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Reflection": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Handles": "4.3.0" + } + }, + "System.Runtime.InteropServices.RuntimeInformation": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "cbz4YJMqRDR7oLeMRbdYv7mYzc++17lNhScCX0goO2XpGWdvAt60CGN+FHdePUEHCe/Jy9jUlvNAiNdM+7jsOw==", + "dependencies": { + "System.Reflection": "4.3.0", + "System.Reflection.Extensions": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Threading": "4.3.0", + "runtime.native.System": "4.3.0" + } + }, + "System.Runtime.Numerics": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "yMH+MfdzHjy17l2KESnPiF2dwq7T+xLnSJar7slyimAkUh/gTrS9/UQOtv7xarskJ2/XDSNvfLGOBQPjL7PaHQ==", + "dependencies": { + "System.Globalization": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0" + } + }, + "System.Security.Cryptography.Algorithms": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "W1kd2Y8mYSCgc3ULTAZ0hOP2dSdG5YauTb1089T0/kRcN2MpSAW1izOFROrJgxSlMn3ArsgHXagigyi+ibhevg==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "System.Collections": "4.3.0", + "System.IO": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Runtime.Numerics": "4.3.0", + "System.Security.Cryptography.Encoding": "4.3.0", + "System.Security.Cryptography.Primitives": "4.3.0", + "System.Text.Encoding": "4.3.0", + "runtime.native.System.Security.Cryptography.Apple": "4.3.0", + "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" + } + }, + "System.Security.Cryptography.Cng": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "03idZOqFlsKRL4W+LuCpJ6dBYDUWReug6lZjBa3uJWnk5sPCUXckocevTaUA8iT/MFSrY/2HXkOt753xQ/cf8g==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "System.IO": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Security.Cryptography.Algorithms": "4.3.0", + "System.Security.Cryptography.Encoding": "4.3.0", + "System.Security.Cryptography.Primitives": "4.3.0", + "System.Text.Encoding": "4.3.0" + } + }, + "System.Security.Cryptography.Csp": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "X4s/FCkEUnRGnwR3aSfVIkldBmtURMhmexALNTwpjklzxWU7yjMk7GHLKOZTNkgnWnE0q7+BCf9N2LVRWxewaA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "System.IO": "4.3.0", + "System.Reflection": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Security.Cryptography.Algorithms": "4.3.0", + "System.Security.Cryptography.Encoding": "4.3.0", + "System.Security.Cryptography.Primitives": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Threading": "4.3.0" + } + }, + "System.Security.Cryptography.Encoding": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "1DEWjZZly9ae9C79vFwqaO5kaOlI5q+3/55ohmq/7dpDyDfc8lYe7YVxJUZ5MF/NtbkRjwFRo14yM4OEo9EmDw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "System.Collections": "4.3.0", + "System.Collections.Concurrent": "4.3.0", + "System.Linq": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Security.Cryptography.Primitives": "4.3.0", + "System.Text.Encoding": "4.3.0", + "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" + } + }, + "System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "h4CEgOgv5PKVF/HwaHzJRiVboL2THYCou97zpmhjghx5frc7fIvlkY1jL+lnIQyChrJDMNEXS6r7byGif8Cy4w==", + "dependencies": { + "System.Collections": "4.3.0", + "System.IO": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Runtime.Numerics": "4.3.0", + "System.Security.Cryptography.Algorithms": "4.3.0", + "System.Security.Cryptography.Encoding": "4.3.0", + "System.Security.Cryptography.Primitives": "4.3.0", + "System.Text.Encoding": "4.3.0", + "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" + } + }, + "System.Security.Cryptography.Primitives": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "7bDIyVFNL/xKeFHjhobUAQqSpJq9YTOpbEs6mR233Et01STBMXNAc/V+BM6dwYGc95gVh/Zf+iVXWzj3mE8DWg==", + "dependencies": { + "System.Diagnostics.Debug": "4.3.0", + "System.Globalization": "4.3.0", + "System.IO": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Threading": "4.3.0", + "System.Threading.Tasks": "4.3.0" + } + }, + "System.Security.Cryptography.X509Certificates": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "t2Tmu6Y2NtJ2um0RtcuhP7ZdNNxXEgUm2JeoA/0NvlMjAhKCnM1NX07TDl3244mVp3QU6LPEhT3HTtH1uF7IYw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Globalization": "4.3.0", + "System.Globalization.Calendars": "4.3.0", + "System.IO": "4.3.0", + "System.IO.FileSystem": "4.3.0", + "System.IO.FileSystem.Primitives": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Runtime.Numerics": "4.3.0", + "System.Security.Cryptography.Algorithms": "4.3.0", + "System.Security.Cryptography.Cng": "4.3.0", + "System.Security.Cryptography.Csp": "4.3.0", + "System.Security.Cryptography.Encoding": "4.3.0", + "System.Security.Cryptography.OpenSsl": "4.3.0", + "System.Security.Cryptography.Primitives": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Threading": "4.3.0", + "runtime.native.System": "4.3.0", + "runtime.native.System.Net.Http": "4.3.0", + "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" + } + }, + "System.Text.Encoding": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "BiIg+KWaSDOITze6jGQynxg64naAPtqGHBwDrLaCtixsa5bKiR8dpPOHA7ge3C0JJQizJE+sfkz1wV+BAKAYZw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Text.Encoding.Extensions": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "YVMK0Bt/A43RmwizJoZ22ei2nmrhobgeiYwFzC4YAN+nue8RF6djXDMog0UCn+brerQoYVyaS+ghy9P/MUVcmw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0", + "System.Text.Encoding": "4.3.0" + } + }, + "System.Text.Json": { + "type": "Transitive", + "resolved": "5.0.2", + "contentHash": "I47dVIGiV6SfAyppphxqupertT/5oZkYLDCX6vC3HpOI4ZLjyoKAreUoem2ie6G0RbRuFrlqz/PcTQjfb2DOfQ==" + }, + "System.Text.RegularExpressions": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "RpT2DA+L660cBt1FssIE9CAGpLFdFPuheB7pLpKpn6ZXNby7jDERe8Ua/Ne2xGiwLVG2JOqziiaVCGDon5sKFA==", + "dependencies": { + "System.Runtime": "4.3.0" + } + }, + "System.Threading": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "VkUS0kOBcUf3Wwm0TSbrevDDZ6BlM+b/HRiapRFWjM5O0NS0LviG0glKmFK+hhPDd1XFeSdU1GmlLhb2CoVpIw==", + "dependencies": { + "System.Runtime": "4.3.0", + "System.Threading.Tasks": "4.3.0" + } + }, + "System.Threading.Tasks": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "LbSxKEdOUhVe8BezB/9uOGGppt+nZf6e1VFyw6v3DN6lqitm0OSn2uXMOdtP0M3W4iMcqcivm2J6UgqiwwnXiA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Threading.Tasks.Extensions": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "npvJkVKl5rKXrtl1Kkm6OhOUaYGEiF9wFbppFRWSMoApKzt2PiPHT2Bb8a5sAWxprvdOAtvaARS9QYMznEUtug==", + "dependencies": { + "System.Collections": "4.3.0", + "System.Runtime": "4.3.0", + "System.Threading.Tasks": "4.3.0" + } + }, + "System.Threading.Timer": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "Z6YfyYTCg7lOZjJzBjONJTFKGN9/NIYKSxhU5GRd+DTwHSZyvWp1xuI5aR+dLg+ayyC5Xv57KiY4oJ0tMO89fQ==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Xml.ReaderWriter": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "GrprA+Z0RUXaR4N7/eW71j1rgMnEnEVlgii49GZyAjTH7uliMnrOU3HNFBr6fEDBCJCIdlVNq9hHbaDR621XBA==", + "dependencies": { + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Globalization": "4.3.0", + "System.IO": "4.3.0", + "System.IO.FileSystem": "4.3.0", + "System.IO.FileSystem.Primitives": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Text.Encoding.Extensions": "4.3.0", + "System.Text.RegularExpressions": "4.3.0", + "System.Threading.Tasks": "4.3.0", + "System.Threading.Tasks.Extensions": "4.3.0" + } + }, + "System.Xml.XDocument": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "5zJ0XDxAIg8iy+t4aMnQAu0MqVbqyvfoUVl1yDV61xdo3Vth45oA2FoY4pPkxYAH5f8ixpmTqXeEIya95x0aCQ==", + "dependencies": { + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Diagnostics.Tools": "4.3.0", + "System.Globalization": "4.3.0", + "System.IO": "4.3.0", + "System.Reflection": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Threading": "4.3.0", + "System.Xml.ReaderWriter": "4.3.0" + } + }, + "colorthief": { + "type": "Project", + "dependencies": { + "System.Drawing.Common": "[7.0.0, )" + } + }, + "hi3helper.core": { + "type": "Project", + "dependencies": { + "Hi3Helper.EncTool": "[1.0.0, )", + "Hi3Helper.Http": "[1.0.0, )", + "Hi3Helper.SharpHDiffPatch": "[1.0.0, )" + } + }, + "hi3helper.enctool": { + "type": "Project", + "dependencies": { + "Google.Protobuf": "[3.23.4, )", + "Hi3Helper.Http": "[1.0.0, )", + "System.IO.Hashing": "[7.0.0, )" + } + }, + "hi3helper.http": { + "type": "Project" + }, + "hi3helper.sharphdiffpatch": { + "type": "Project" + } + } + } +} \ No newline at end of file diff --git a/ColorThief b/ColorThief index 18b91a798..a79e0c132 160000 --- a/ColorThief +++ b/ColorThief @@ -1 +1 @@ -Subproject commit 18b91a798f51fd97478794b4ed22beb394a92c8f +Subproject commit a79e0c132904eac83053406211701cc3f148443e diff --git a/Hi3Helper.Core/Classes/Data/Tools/GenshinDispatchHelper/GenshinDispatchHelper.cs b/Hi3Helper.Core/Classes/Data/Tools/GenshinDispatchHelper/GenshinDispatchHelper.cs index db4dd7805..d794f75cb 100644 --- a/Hi3Helper.Core/Classes/Data/Tools/GenshinDispatchHelper/GenshinDispatchHelper.cs +++ b/Hi3Helper.Core/Classes/Data/Tools/GenshinDispatchHelper/GenshinDispatchHelper.cs @@ -25,6 +25,10 @@ public class GenshinDispatchHelper : IDisposable public GenshinDispatchHelper(int RegionID, string DispatchKey, string DispatchURLPrefix, string VersionString = "2.6.0", CancellationToken cancelToken = new CancellationToken()) { + if (RegionID == 4) + { + ChannelName = "CNRELWin"; + } this._httpClient = new Http.Http(false, 1, 1); this.RegionSubdomain = GetSubdomainByRegionID(RegionID); this.Version = VersionString; @@ -49,7 +53,7 @@ public async Task LoadDispatchInfo() #endif await this._httpClient.Download(DispatchBaseURL, s, null, null, cancelToken).ConfigureAwait(false); s.Position = 0; - DispatcherDataInfo = (YSDispatchInfo)JsonSerializer.Deserialize(s, typeof(YSDispatchInfo), YSDispatchInfoContext.Default); + DispatcherDataInfo = (YSDispatchInfo)JsonSerializer.Deserialize(s, typeof(YSDispatchInfo), CoreLibraryJSONContext.Default); } return DispatcherDataInfo; @@ -93,15 +97,15 @@ private void ParseDesignDataURL(ref QueryProperty ValProp) { (ValProp.ClientGameRes as List) .Add( - (PkgVersionProperties)JsonSerializer.Deserialize(Data, typeof(PkgVersionProperties), PkgVersionPropertiesContext.Default) + (PkgVersionProperties)JsonSerializer.Deserialize(Data, typeof(PkgVersionProperties), CoreLibraryJSONContext.Default) ); } } private void ParseGameResPkgProp(ref QueryProperty ValProp) { - ValProp.ClientDesignData = (PkgVersionProperties)JsonSerializer.Deserialize(Gateway.GatewayProperties.RepoDesignDataJSON, typeof(PkgVersionProperties), PkgVersionPropertiesContext.Default); - ValProp.ClientDesignDataSil = (PkgVersionProperties)JsonSerializer.Deserialize(Gateway.GatewayProperties.RepoDesignDataSilenceJSON, typeof(PkgVersionProperties), PkgVersionPropertiesContext.Default); + ValProp.ClientDesignData = (PkgVersionProperties)JsonSerializer.Deserialize(Gateway.GatewayProperties.RepoDesignDataJSON, typeof(PkgVersionProperties), CoreLibraryJSONContext.Default); + ValProp.ClientDesignDataSil = (PkgVersionProperties)JsonSerializer.Deserialize(Gateway.GatewayProperties.RepoDesignDataSilenceJSON, typeof(PkgVersionProperties), CoreLibraryJSONContext.Default); } private async Task ParseAudioAssetsURL(QueryProperty ValProp) @@ -131,6 +135,7 @@ private string GetSubdomainByRegionID(int RegionID) * 1 = Europe * 2 = Asia * 3 = TW/HK/MO + * 4 = Mainland China */ case 0: return "osusadispatch"; @@ -140,6 +145,8 @@ private string GetSubdomainByRegionID(int RegionID) return "osasiadispatch"; case 3: return "oschtdispatch"; + case 4: + return "cngfdispatch"; default: throw new FormatException("Unknown region ID!"); } diff --git a/Hi3Helper.Core/Classes/Data/Tools/HPatchTool.cs b/Hi3Helper.Core/Classes/Data/Tools/HPatchTool.cs deleted file mode 100644 index dc617efec..000000000 --- a/Hi3Helper.Core/Classes/Data/Tools/HPatchTool.cs +++ /dev/null @@ -1,53 +0,0 @@ -using Hi3Helper.Shared.ClassStruct; -using System; -using System.IO; -#if HDIFFEXPERIMENTAL -using Hi3Helper.SharpHDiffPatch; -#endif -using static Hi3Helper.InvokeProp; - -namespace Hi3Helper.Data -{ - public class HPatchUtil - { -#if HDIFFEXPERIMENTAL - private HDiffPatch _patcher = new HDiffPatch(); -#endif - uint bufSize = 0x10000; - - public void HPatchFile(string inputFile, string diffFile, string outputFile) => - GetEnumStatus(HPatch( - inputFile, diffFile, outputFile, - false, new UIntPtr(bufSize), 0, - new FileInfo(diffFile).Length)); - - public void HPatchDir(string inputPath, string diffFile, string outputPath) - { -#if HDIFFEXPERIMENTAL - bool isInputAfile = File.Exists(inputPath) && !Directory.Exists(inputPath); - - if (isInputAfile) - { - _patcher.Initialize(diffFile); - _patcher.Patch(inputPath, outputPath, false); - return; - } -#endif - string[] args = new string[] { "_", "-f", "-s", inputPath, diffFile, outputPath }; - - GetEnumStatus(HPatchCommand(args.Length, args)); - } - - void GetEnumStatus(int i) - { - switch ((HPatchUtilStat)i) - { - case HPatchUtilStat.HPATCH_SUCCESS: return; - case HPatchUtilStat.HPATCH_MEM_ERROR: - throw new OutOfMemoryException($"Out Of Memory. ERRMSG: {(HPatchUtilStat)i}"); - default: - throw new Exception($"Unhandled Error. ERRMSG: {(HPatchUtilStat)i}"); - } - } - } -} diff --git a/Hi3Helper.Core/Classes/DiscordPresence/DiscordPresenceManager.cs b/Hi3Helper.Core/Classes/DiscordPresence/DiscordPresenceManager.cs index c11ec91ee..4d86712d4 100644 --- a/Hi3Helper.Core/Classes/DiscordPresence/DiscordPresenceManager.cs +++ b/Hi3Helper.Core/Classes/DiscordPresence/DiscordPresenceManager.cs @@ -218,12 +218,13 @@ private void BuildActivityGameStatus(string activityName, bool isGameStatusEnabl _activity = new Activity { Details = $"{activityName} {(!isGameStatusEnabled ? ConfigV2Store.CurrentConfigV2GameCategory : Lang._Misc.DiscordRP_Ad)}", - State = $"Server: {ConfigV2Store.CurrentConfigV2GameRegion}", + State = $"{Lang._Misc.DiscordRP_Region} {ConfigV2Store.CurrentConfigV2GameRegion}", Assets = new ActivityAssets { LargeImage = $"game-{ConfigV2Store.CurrentConfigV2.GameType.ToString().ToLower()}-logo", LargeText = $"{ConfigV2Store.CurrentConfigV2GameCategory} - {ConfigV2Store.CurrentConfigV2GameRegion}", - SmallImage = $"launcher-logo" + SmallImage = $"launcher-logo", + SmallText = $"Collapse Launcher v{AppCurrentVersionString} {(IsPreview ? "Preview" : "Stable")}" }, Timestamps = new ActivityTimestamps { @@ -247,21 +248,20 @@ private void BuildActivityAppStatus(string activityName, bool isGameStatusEnable _activity = new Activity { Details = $"{activityName} {(!isGameStatusEnabled ? string.Empty : Lang._Misc.DiscordRP_Ad)}", - State = $"Server: {ConfigV2Store.CurrentConfigV2GameRegion}", + State = $"{Lang._Misc.DiscordRP_Region} {ConfigV2Store.CurrentConfigV2GameRegion}", Assets = new ActivityAssets { LargeImage = $"game-{ConfigV2Store.CurrentConfigV2.GameType.ToString().ToLower()}-logo", LargeText = $"{ConfigV2Store.CurrentConfigV2GameCategory}", - SmallImage = $"launcher-logo" + SmallImage = $"launcher-logo", + SmallText = $"Collapse Launcher v{AppCurrentVersionString} {(IsPreview ? "Preview" : "Stable")}" }, }; } private void UpdateActivity() => _activityManager?.UpdateActivity(_activity, (a) => { -#if DEBUG Logger.LogWriteLine($"Activity updated! => {_activity.Details} - {_activity.State}"); -#endif }); private void UpdateCallbacksRoutine() diff --git a/Hi3Helper.Core/Classes/Preset/Classes/ClassesContext.cs b/Hi3Helper.Core/Classes/Preset/Classes/ClassesContext.cs index aa5338816..7d13b8de7 100644 --- a/Hi3Helper.Core/Classes/Preset/Classes/ClassesContext.cs +++ b/Hi3Helper.Core/Classes/Preset/Classes/ClassesContext.cs @@ -7,55 +7,22 @@ namespace Hi3Helper { - [JsonSourceGenerationOptions(IncludeFields = false, GenerationMode = JsonSourceGenerationMode.Metadata, IgnoreReadOnlyFields = true)] - [JsonSerializable(typeof(YSDispatchInfo))] - internal sealed partial class YSDispatchInfoContext : JsonSerializerContext { } - - [JsonSourceGenerationOptions(IncludeFields = false, GenerationMode = JsonSourceGenerationMode.Metadata, IgnoreReadOnlyFields = true)] - [JsonSerializable(typeof(PkgVersionProperties))] - public sealed partial class PkgVersionPropertiesContext : JsonSerializerContext { } - - [JsonSourceGenerationOptions(IncludeFields = true, GenerationMode = JsonSourceGenerationMode.Metadata, IgnoreReadOnlyFields = true)] - [JsonSerializable(typeof(LocalizationParams))] - internal sealed partial class LocalizationParamsContext : JsonSerializerContext { } - - [JsonSourceGenerationOptions(IncludeFields = false, GenerationMode = JsonSourceGenerationMode.Metadata, IgnoreReadOnlyFields = true)] - [JsonSerializable(typeof(GeneralDataProp))] - internal sealed partial class GeneralDataPropContext : JsonSerializerContext { } - - [JsonSourceGenerationOptions(IncludeFields = false, GenerationMode = JsonSourceGenerationMode.Metadata, IgnoreReadOnlyFields = true)] - [JsonSerializable(typeof(Metadata))] - internal sealed partial class MetadataContext : JsonSerializerContext { } - - [JsonSourceGenerationOptions(IncludeFields = false, GenerationMode = JsonSourceGenerationMode.Metadata, IgnoreReadOnlyFields = true)] + [JsonSourceGenerationOptions(IncludeFields = true, GenerationMode = JsonSourceGenerationMode.Metadata, IgnoreReadOnlyFields = false)] [JsonSerializable(typeof(Stamp))] - public sealed partial class StampContext : JsonSerializerContext { } - - [JsonSourceGenerationOptions(IncludeFields = false, GenerationMode = JsonSourceGenerationMode.Metadata, IgnoreReadOnlyFields = true)] + [JsonSerializable(typeof(Metadata))] [JsonSerializable(typeof(BHI3LInfo))] - public sealed partial class BHI3LInfoContext : JsonSerializerContext { } - - [JsonSourceGenerationOptions(IncludeFields = false, GenerationMode = JsonSourceGenerationMode.Metadata, IgnoreReadOnlyFields = true)] [JsonSerializable(typeof(DataProperties))] - public sealed partial class DataPropertiesContext : JsonSerializerContext { } - - [JsonSourceGenerationOptions(IncludeFields = false, GenerationMode = JsonSourceGenerationMode.Metadata, IgnoreReadOnlyFields = true)] - [JsonSerializable(typeof(DataPropertiesContent))] - public sealed partial class DataPropertiesContentContext : JsonSerializerContext { } - - [JsonSourceGenerationOptions(IncludeFields = false, GenerationMode = JsonSourceGenerationMode.Metadata, IgnoreReadOnlyFields = true)] + [JsonSerializable(typeof(YSDispatchInfo))] + [JsonSerializable(typeof(GeneralDataProp))] [JsonSerializable(typeof(RegionResourceProp))] - public sealed partial class RegionResourcePropContext : JsonSerializerContext { } - - [JsonSourceGenerationOptions(IncludeFields = false, GenerationMode = JsonSourceGenerationMode.Metadata, IgnoreReadOnlyFields = true)] + [JsonSerializable(typeof(PkgVersionProperties))] + [JsonSerializable(typeof(DataPropertiesContent))] [JsonSerializable(typeof(FilePropertiesRemote[]))] - public sealed partial class Array_FilePropertiesRemoteContext : JsonSerializerContext { } - - [JsonSourceGenerationOptions(IncludeFields = false, GenerationMode = JsonSourceGenerationMode.Metadata, IgnoreReadOnlyFields = true)] [JsonSerializable(typeof(List))] - public sealed partial class L_FilePropertiesRemoteContext : JsonSerializerContext { } - - [JsonSourceGenerationOptions(IncludeFields = false, GenerationMode = JsonSourceGenerationMode.Metadata, IgnoreReadOnlyFields = true)] [JsonSerializable(typeof(Dictionary))] - public sealed partial class D_StringString : JsonSerializerContext { } + public sealed partial class CoreLibraryJSONContext : JsonSerializerContext { } + + [JsonSourceGenerationOptions(IncludeFields = true, GenerationMode = JsonSourceGenerationMode.Metadata, IgnoreReadOnlyFields = true)] + [JsonSerializable(typeof(LocalizationParams))] + internal sealed partial class CoreLibraryFieldsJSONContext : JsonSerializerContext { } } diff --git a/Hi3Helper.Core/Classes/Preset/Classes/PresetConfigV2.cs b/Hi3Helper.Core/Classes/Preset/Classes/PresetConfigV2.cs index 272615ca3..c03ef6e9b 100644 --- a/Hi3Helper.Core/Classes/Preset/Classes/PresetConfigV2.cs +++ b/Hi3Helper.Core/Classes/Preset/Classes/PresetConfigV2.cs @@ -104,9 +104,26 @@ public void DecryptStrings() } } } + + public void GenerateHashID() + { + foreach (KeyValuePair> game in MetadataV2) + { + foreach (KeyValuePair region in game.Value) + { + string HashComposition = $"{ConverterTool.GetUnixTimestamp(true)} - {game.Key} - {region.Value.ZoneName}"; + int HashID = ConverterTool.BytesToCRC32Int(HashComposition); + region.Value.HashID = HashID; + region.Value.GameName = game.Key; + + LogWriteLine($"Cur. Session Region Hash: {HashID} ({HashComposition})", LogType.Default, true); + } + } + } #nullable enable } + [Serializable] public sealed class PresetConfigV2 { private const string PrefixRegInstallLocation = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{0}"; @@ -226,7 +243,7 @@ private int GetVoiceLanguageID_Genshin(string RegPath) } regValue = Encoding.UTF8.GetString(value).AsSpan().Trim('\0'); - GeneralDataProp? RegValues = (GeneralDataProp?)JsonSerializer.Deserialize(new string(regValue), typeof(GeneralDataProp), GeneralDataPropContext.Default); + GeneralDataProp? RegValues = (GeneralDataProp?)JsonSerializer.Deserialize(new string(regValue), typeof(GeneralDataProp), CoreLibraryJSONContext.Default); return RegValues?.deviceVoiceLanguageType ?? 2; } catch (JsonException ex) @@ -274,13 +291,13 @@ private void SetVoiceLanguageID_Genshin(int LangID) result = (byte[]?)keys.GetValue("GENERAL_DATA_h2389025596"); if (result is null) return; regValue = Encoding.UTF8.GetString(result).AsSpan().Trim('\0'); - initValue = (GeneralDataProp?)JsonSerializer.Deserialize(new string(regValue), typeof(GeneralDataProp), GeneralDataPropContext.Default) ?? initValue; + initValue = (GeneralDataProp?)JsonSerializer.Deserialize(new string(regValue), typeof(GeneralDataProp), CoreLibraryJSONContext.Default) ?? initValue; } initValue.deviceVoiceLanguageType = LangID; keys.SetValue("GENERAL_DATA_h2389025596", Encoding.UTF8.GetBytes( - JsonSerializer.Serialize(initValue, typeof(GeneralDataProp), GeneralDataPropContext.Default) + '\0')); + JsonSerializer.Serialize(initValue, typeof(GeneralDataProp), CoreLibraryJSONContext.Default) + '\0')); } catch (Exception ex) { @@ -325,7 +342,7 @@ public int GetRegServerNameID() try { - return (int?)(((GeneralDataProp?)JsonSerializer.Deserialize(regValue, typeof(GeneralDataProp), GeneralDataPropContext.Default))?.selectedServerName) ?? 0; + return (int?)(((GeneralDataProp?)JsonSerializer.Deserialize(regValue, typeof(GeneralDataProp), CoreLibraryJSONContext.Default))?.selectedServerName) ?? 0; } catch (Exception ex) { @@ -453,6 +470,8 @@ private bool CheckInnerGameConfig(in string GamePath) return File.Exists(Path.Combine(ActualGameDataLocation, "config.ini")) && File.Exists(Path.Combine(ActualGameDataLocation, GameExecutableName)); } + public string? GameName { get; set; } + public int HashID { get; set; } private string? SystemDriveLetter { get => Path.GetPathRoot(Environment.GetFolderPath(Environment.SpecialFolder.System)); } public string? ProfileName { get; set; } public GameChannel GameChannel { get; set; } = GameChannel.Stable; diff --git a/Hi3Helper.Core/Classes/Shared/ClassStruct/Class/RegionResource.cs b/Hi3Helper.Core/Classes/Shared/ClassStruct/Class/RegionResource.cs index 557a55b78..84f25c7ec 100644 --- a/Hi3Helper.Core/Classes/Shared/ClassStruct/Class/RegionResource.cs +++ b/Hi3Helper.Core/Classes/Shared/ClassStruct/Class/RegionResource.cs @@ -5,13 +5,33 @@ namespace Hi3Helper.Shared.ClassStruct { - public class RegionResourceProp + public interface IRegionResourceCopyable + { + T Copy(); + } + + public static class RegionResourceListHelper + { + public static List Copy(this List source) + where T : IRegionResourceCopyable + { + if (source == null) return null; + return new List(source); + } + } + + public class RegionResourceProp : IRegionResourceCopyable { public RegionResourceGame data { get; set; } public string imgLocalPath { get; set; } = string.Empty; + public RegionResourceProp Copy() => new RegionResourceProp() + { + data = data?.Copy(), + imgLocalPath = imgLocalPath + }; } - public class RegionResourceGame + public class RegionResourceGame : IRegionResourceCopyable { public RegionResourceLatest game { get; set; } public RegionResourceLatest pre_download_game { get; set; } @@ -19,15 +39,29 @@ public class RegionResourceGame public List banner { get; set; } public List icon { get; set; } public List post { get; set; } + public RegionResourceGame Copy() => new RegionResourceGame() + { + game = game?.Copy(), + pre_download_game = pre_download_game?.Copy(), + adv = adv?.Copy(), + banner = banner?.Copy(), + icon = icon?.Copy(), + post = post?.Copy() + }; } - public class RegionResourceLatest + public class RegionResourceLatest : IRegionResourceCopyable { public RegionResourceVersion latest { get; set; } public List diffs { get; set; } + public RegionResourceLatest Copy() => new RegionResourceLatest() + { + latest = latest?.Copy(), + diffs = diffs?.Copy() + }; } - public class RegionResourceVersion + public class RegionResourceVersion : IRegionResourceCopyable { public string version { get; set; } public string path { get; set; } @@ -44,25 +78,52 @@ public class RegionResourceVersion public string entry { get; set; } public List voice_packs { get; set; } public List segments { get; set; } + public RegionResourceVersion Copy() => new RegionResourceVersion() + { + version = version, + path = path, + decompressed_path = decompressed_path, + size = size, + package_size = package_size, + md5 = md5, + language = language, + languageID = languageID, + is_recommended_update = is_recommended_update, + entry = entry, + voice_packs = voice_packs?.Copy(), + segments = segments?.Copy() + }; } - public class HomeMenuPanel + public class HomeMenuPanel : IRegionResourceCopyable { public List sideMenuPanel { get; set; } public List imageCarouselPanel { get; set; } public PostCarouselTypes articlePanel { get; set; } public RegionBackgroundProp eventPanel { get; set; } - public HomeMenuPanel Copy() => this; + public HomeMenuPanel Copy() => new HomeMenuPanel() + { + sideMenuPanel = sideMenuPanel?.Copy(), + imageCarouselPanel = imageCarouselPanel?.Copy(), + articlePanel = articlePanel?.Copy(), + eventPanel = eventPanel?.Copy() + }; } - public class PostCarouselTypes + public class PostCarouselTypes : IRegionResourceCopyable { public List Events { get; set; } = new List(); public List Notices { get; set; } = new List(); public List Info { get; set; } = new List(); + public PostCarouselTypes Copy() => new PostCarouselTypes() + { + Events = Events?.Copy(), + Notices = Notices?.Copy(), + Info = Info?.Copy() + }; } - public class MenuPanelProp + public class MenuPanelProp : IRegionResourceCopyable { public string URL { get; set; } public string Icon { get; set; } @@ -73,9 +134,18 @@ public class MenuPanelProp public string Description { get; set; } public bool IsDescriptionExist => !string.IsNullOrEmpty(Description); public bool IsQRDescriptionExist => !string.IsNullOrEmpty(QR_Description); + public MenuPanelProp Copy() => new MenuPanelProp() + { + URL = URL, + Icon = Icon, + IconHover = IconHover, + QR = QR, + QR_Description = QR_Description, + Description = Description + }; } - public class RegionBackgroundProp + public class RegionBackgroundProp : IRegionResourceCopyable { public string background { get; set; } public string bg_checksum { get; set; } @@ -83,6 +153,15 @@ public class RegionBackgroundProp public string url { get; set; } [JsonNumberHandling(JsonNumberHandling.AllowReadingFromString)] public int? version { get; set; } + + public RegionBackgroundProp Copy() => new RegionBackgroundProp + { + background = background, + bg_checksum = bg_checksum, + icon = icon, + url = url, + version = version + }; } [JsonConverter(typeof(JsonStringEnumConverter))] @@ -93,7 +172,7 @@ public enum PostCarouselType POST_TYPE_ANNOUNCE } - public class RegionSocMedProp + public class RegionSocMedProp : IRegionResourceCopyable { private string _url; @@ -128,6 +207,21 @@ private unsafe string StripTabsAndNewlines(ReadOnlySpan s) } return new string(newChars, 0, (int)(currentChar - newChars)); } + + public RegionSocMedProp Copy() => new RegionSocMedProp() + { + icon_id = icon_id, + icon_link = icon_link, + img = img, + img_hover = img_hover, + qr_img = qr_img, + qr_desc = qr_desc, + url = url, + name = name, + title = title, + show_time = show_time, + type = type + }; } public class YSDispatchInfo diff --git a/Hi3Helper.Core/Classes/Shared/GameConversion/CheckIntegrity.cs b/Hi3Helper.Core/Classes/Shared/GameConversion/CheckIntegrity.cs deleted file mode 100644 index 08c8d2e04..000000000 --- a/Hi3Helper.Core/Classes/Shared/GameConversion/CheckIntegrity.cs +++ /dev/null @@ -1,269 +0,0 @@ -using Force.Crc32; -using Hi3Helper.Data; -using Hi3Helper.Preset; -using Hi3Helper.Shared.ClassStruct; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Text.Json; -using System.Threading; -using System.Threading.Tasks; -using static Hi3Helper.Data.ConverterTool; -using static Hi3Helper.Locale; - -namespace Hi3Helper.Shared.GameConversion -{ - public class CheckIntegrity - { - private string targetPath; - private string repoIndexURL; - private Http.Http http; - private Stream stream; - private CancellationTokenSource tokenSource; - private Stopwatch sw; - - private List FileIndexesProperty = new List(); - private List BrokenFileIndexesProperty = new List(); - - public event EventHandler ProgressChanged; - - private string CheckStatus; - private long TotalSizeToRead, TotalRead; - private int TotalCountToRead, TotalCount; - - private string FilePath, FileCRC; - private FileInfo FileInfo; - private FilePropertiesRemote FileIndex; - private Crc32Algorithm FileCRCTool; - private byte[] buffer = new byte[0x400000]; - - public CheckIntegrity(string targetPath, string repoURL, string repoIndexURL, CancellationTokenSource tokenSource) - { - this.sw = Stopwatch.StartNew(); - this.targetPath = targetPath; - this.repoIndexURL = repoIndexURL; - this.tokenSource = tokenSource; - this.http = new Http.Http(); - } - - public async Task StartCheckIntegrity() - { - File.Create(Path.Combine(targetPath, "_conversion_unfinished")).Close(); - await FetchAPI(); - await Task.Run(CheckGameFiles); - stream.Dispose(); - FileIndexesProperty.Clear(); - } - - private async Task FetchAPI() - { - CheckStatus = Lang._InstallMigrateSteam.Step3Subtitle; - - using (stream = new MemoryStream()) - { - http.DownloadProgress += HttpAdapter; - await http.Download(repoIndexURL, stream, null, null, tokenSource.Token); - http.DownloadProgress -= HttpAdapter; - - FileIndexesProperty = (List)JsonSerializer.Deserialize(stream, typeof(List), L_FilePropertiesRemoteContext.Default); - } - } - - public List GetNecessaryFileList() => BrokenFileIndexesProperty; - - private void CheckGameFiles() - { - sw = Stopwatch.StartNew(); - - TotalCount = 0; - TotalRead = 0; - TotalSizeToRead = FileIndexesProperty.Sum(x => x.S) - + FileIndexesProperty.Where(x => x.BlkC != null).Sum(x => x.BlkC.Sum(x => x.BlockSize)); - - TotalCountToRead = FileIndexesProperty.Count - + FileIndexesProperty.Where(x => x.BlkC != null).Sum(y => y.BlkC.Sum(z => z.BlockContent.Count)); - - foreach (FilePropertiesRemote Index in FileIndexesProperty) - { - FilePath = Path.Combine(targetPath, NormalizePath(Index.N)); - FileInfo = new FileInfo(FilePath); - FileIndex = Index; - - switch (Index.FT) - { - case FileType.Generic: - case FileType.Audio: - CheckGenericAudioFile(); - break; - case FileType.Blocks: - CheckBlockFile(); - break; - } - } - } - - private void CheckGenericAudioFile() - { - TotalCount++; - CheckStatus = string.Format(Lang._InstallMigrateSteam.InnerCheckFile, FileIndex.FT, TotalCount, TotalCountToRead, FileIndex.N); - if (!FileInfo.Exists) - { - TotalRead += FileIndex.S; - BrokenFileIndexesProperty.Add(FileIndex); - return; - } - - using (stream = FileInfo.OpenRead()) - if ((FileCRC = GenerateCRC(stream)) != FileIndex.CRC) - BrokenFileIndexesProperty.Add(FileIndex); - } - - private void CheckBlockFile() - { - List BrokenBlock = new List(); - List BrokenChunk = new List(); - string BlockBasePath = FilePath; - byte[] ChunkBuffer; - - foreach (var block in FileIndex.BlkC) - { - FilePath = Path.Combine(BlockBasePath, block.BlockHash + ".wmv"); - FileInfo = new FileInfo(FilePath); - - if (!FileInfo.Exists || FileInfo.Length != block.BlockSize) - { - TotalCount++; - CheckStatus = string.Format(Lang._InstallMigrateSteam.InnerCheckBlock1, FileIndex.FT, block.BlockHash); - TotalRead += block.BlockSize; - TotalCount += block.BlockContent.Count; - - BrokenBlock.Add(new XMFBlockList - { - BlockHash = block.BlockHash, - BlockSize = block.BlockSize, - BlockExistingSize = 0, - BlockMissing = true - }); - - OnProgressChanged(new CheckIntegrityChanged(TotalRead, TotalSizeToRead, sw.Elapsed.TotalSeconds) - { - Message = CheckStatus - }); - } - else - { - using (stream = FileInfo.OpenRead()) - { - BrokenChunk = new List(); - foreach (var chunk in block.BlockContent) - { - CheckStatus = string.Format(Lang._InstallMigrateSteam.InnerCheckBlock2, FileIndex.FT, TotalCount, TotalCountToRead, block.BlockHash, chunk._startoffset.ToString("x8"), chunk._filesize.ToString("x8")); - TotalCount++; - tokenSource.Token.ThrowIfCancellationRequested(); - - stream.Position = chunk._startoffset; - stream.Read(ChunkBuffer = new byte[chunk._filesize], 0, (int)chunk._filesize); - - TotalRead += chunk._filesize; - - FileCRC = GenerateCRC(ChunkBuffer); - - OnProgressChanged(new CheckIntegrityChanged(TotalRead, TotalSizeToRead, sw.Elapsed.TotalSeconds) - { - Message = CheckStatus - }); - - if (!string.Equals(FileCRC, chunk._filecrc32)) - BrokenChunk.Add(chunk); - } - } - - if (BrokenChunk.Count > 0) - BrokenBlock.Add(new XMFBlockList - { - BlockHash = block.BlockHash, - BlockSize = block.BlockSize, - BlockContent = BrokenChunk - }); - } - } - - if (BrokenBlock.Count > 0) - { - BrokenFileIndexesProperty.Add(new FilePropertiesRemote - { - N = FileIndex.N, - RN = FileIndex.RN, - CRC = FileIndex.CRC, - FT = FileIndex.FT, - S = FileIndex.S, - M = FileIndex.M, - BlkC = BrokenBlock - }); - } - } - - private string GenerateCRC(Stream input) - { - FileCRCTool = new Crc32Algorithm(); - int read = 0; - - if (input.Length == 0) return "00000000"; - - using (input) - { - while ((read = input.Read(buffer)) >= buffer.Length) - { - tokenSource.Token.ThrowIfCancellationRequested(); - FileCRCTool.TransformBlock(buffer, 0, buffer.Length, buffer, 0); - TotalRead += read; - OnProgressChanged(new CheckIntegrityChanged(TotalRead, TotalSizeToRead, sw.Elapsed.TotalSeconds) - { - Message = CheckStatus - }); - } - - FileCRCTool.TransformFinalBlock(buffer, 0, read); - TotalRead += read; - - OnProgressChanged(new CheckIntegrityChanged(TotalRead, TotalSizeToRead, sw.Elapsed.TotalSeconds) - { - Message = CheckStatus - }); - } - - return HexTool.BytesToHexUnsafe(FileCRCTool.Hash); - } - - private string GenerateCRC(in byte[] input) => HexTool.BytesToHexUnsafe(new Crc32Algorithm().ComputeHash(input)); - - private void HttpAdapter(object sender, Http.DownloadEvent e) - { - OnProgressChanged(new CheckIntegrityChanged(e.SizeDownloaded, e.SizeToBeDownloaded, sw.Elapsed.TotalSeconds) - { - Message = CheckStatus - }); - } - - protected virtual void OnProgressChanged(CheckIntegrityChanged e) => ProgressChanged?.Invoke(this, e); - } - - public class CheckIntegrityChanged : EventArgs - { - public CheckIntegrityChanged(long totalReceived, long fileSize, double totalSecond) - { - BytesReceived = totalReceived; - TotalBytesToReceive = fileSize; - CurrentSpeed = (long)(totalReceived / totalSecond); - } - public string Message { get; set; } - public long CurrentReceived { get; set; } - public long BytesReceived { get; private set; } - public long TotalBytesToReceive { get; private set; } - public float ProgressPercentage => ((float)BytesReceived / (float)TotalBytesToReceive) * 100; - public long CurrentSpeed { get; private set; } - public TimeSpan TimeLeft => TimeSpan.FromSeconds((TotalBytesToReceive - BytesReceived) / CurrentSpeed); - } -} diff --git a/Hi3Helper.Core/Classes/Shared/GameConversion/SteamConversion.cs b/Hi3Helper.Core/Classes/Shared/GameConversion/SteamConversion.cs deleted file mode 100644 index 764e9e272..000000000 --- a/Hi3Helper.Core/Classes/Shared/GameConversion/SteamConversion.cs +++ /dev/null @@ -1,184 +0,0 @@ -using Hi3Helper.Data; -using Hi3Helper.Shared.ClassStruct; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using static Hi3Helper.Data.ConverterTool; -using static Hi3Helper.Locale; -using static Hi3Helper.Shared.Region.LauncherConfig; - -namespace Hi3Helper.Shared.GameConversion -{ - public class SteamConversion - { - private string targetPath; - private string repoURL; - private Http.Http http; - private Stream stream; - private CancellationTokenSource tokenSource; - private Stopwatch sw; - - private List BrokenFileIndexesProperty = new List(); - - public event EventHandler ProgressChanged; - - private string CheckStatus; - private long TotalSizeToRead, TotalRead; - private int TotalCountToRead, TotalCount; - private byte DownloadThread = (byte)AppCurrentDownloadThread; - - private string FilePath, FileURL; - private FileInfo FileInfo; - private FilePropertiesRemote FileIndex; - - public SteamConversion(string targetPath, string repoURL, List FileList, CancellationTokenSource tokenSource) - { - this.sw = Stopwatch.StartNew(); - this.targetPath = targetPath; - this.repoURL = repoURL; - this.tokenSource = tokenSource; - this.http = new Http.Http(); - this.BrokenFileIndexesProperty = FileList; - } - - public async Task StartConverting() - { - sw = Stopwatch.StartNew(); - - TotalCount = 0; - TotalRead = 0; - TotalSizeToRead = BrokenFileIndexesProperty.Sum(x => x.S) - + BrokenFileIndexesProperty.Where(x => x.BlkC != null).Sum(x => x.BlkC.Sum(x => x.BlockSize)); - - TotalCountToRead = BrokenFileIndexesProperty.Count - + BrokenFileIndexesProperty.Where(x => x.BlkC != null).Sum(y => y.BlkC.Sum(z => z.BlockContent.Count)); - - foreach (var index in BrokenFileIndexesProperty) - { - FileIndex = index; - FilePath = Path.Combine(targetPath, NormalizePath(index.N)); - switch (index.FT) - { - case FileType.Generic: - case FileType.Audio: - await ConvertGenericAudioFile(); - break; - case FileType.Blocks: - await ConvertBlockFile(); - break; - } - } - } - - private async Task ConvertGenericAudioFile() - { - TotalCount++; - CheckStatus = string.Format(Lang._InstallMigrateSteam.InnerConvertFile1, FileIndex.FT, TotalCount, TotalCountToRead, FileIndex.N); - - FileInfo = new FileInfo(FilePath); - - FileURL = CombineURLFromString(repoURL, - FileIndex.FT == FileType.Generic ? FileIndex.N : Path.GetDirectoryName(FileIndex.N).Replace('\\', '/'), $"/{FileIndex.RN}"); - - http.DownloadProgress += HttpAdapter; - - if (FileIndex.S == 0) - FileInfo.Create(); - else - { - if (FileIndex.S > 10 << 20) - { - await http.Download(FileURL, FilePath, DownloadThread, true, tokenSource.Token); - await http.Merge(); - } - else - using (stream = FileInfo.Create()) - await http.Download(FileURL, stream, null, null, tokenSource.Token); - } - - http.DownloadProgress -= HttpAdapter; - } - - private async Task ConvertBlockFile() - { - string BlockBasePath = NormalizePath(FileIndex.N); - long FileExistingLength; - foreach (var block in FileIndex.BlkC) - { - FileURL = CombineURLFromString(repoURL, FileIndex.N, $"/{block.BlockHash}.wmv"); - FilePath = Path.Combine(targetPath, BlockBasePath, block.BlockHash + ".wmv"); - FileInfo = new FileInfo(FilePath); - - FileExistingLength = FileInfo.Exists ? FileInfo.Length : 0; - - if (FileInfo.Exists && FileInfo.Length != block.BlockSize) - FileInfo.Delete(); - - http.DownloadProgress += HttpAdapter; - if (!FileInfo.Exists) - { - TotalCount++; - CheckStatus = string.Format(Lang._InstallMigrateSteam.InnerConvertFile2, FileIndex.FT, TotalCount, TotalCountToRead, block.BlockHash); - - using (stream = FileInfo.Create()) - await http.Download(FileURL, stream, null, null, tokenSource.Token); - } - else - { - using (stream = FileInfo.OpenWrite()) - { - foreach (var chunk in block.BlockContent) - { - TotalCount++; - CheckStatus = string.Format(Lang._InstallMigrateSteam.InnerConvertFile3, FileIndex.FT, TotalCount, TotalCountToRead, block.BlockHash, chunk._startoffset.ToString("x8"), chunk._filesize.ToString("x8")); - - stream.Position = chunk._startoffset; - - using (MemoryStream mStream = new MemoryStream()) - { - await http.Download(FileURL, mStream, chunk._startoffset, chunk._startoffset + chunk._filesize, tokenSource.Token); - stream.Position = chunk._startoffset; - await stream.WriteAsync(mStream.GetBuffer(), tokenSource.Token); - } - } - } - } - http.DownloadProgress -= HttpAdapter; - } - } - - private void HttpAdapter(object sender, Http.DownloadEvent e) - { - if (e.State != Http.DownloadState.Merging) - TotalRead += e.Read; - - OnProgressChanged(new ConversionTaskChanged(TotalRead, TotalSizeToRead, sw.Elapsed.TotalSeconds) - { - Message = CheckStatus - }); - } - - protected virtual void OnProgressChanged(ConversionTaskChanged e) => ProgressChanged?.Invoke(this, e); - } - - public class ConversionTaskChanged : EventArgs - { - public ConversionTaskChanged(long totalReceived, long fileSize, double totalSecond) - { - BytesReceived = totalReceived; - TotalBytesToReceive = fileSize; - CurrentSpeed = (long)(totalReceived / totalSecond); - } - public string Message { get; set; } - public long CurrentReceived { get; set; } - public long BytesReceived { get; private set; } - public long TotalBytesToReceive { get; private set; } - public float ProgressPercentage => ((float)BytesReceived / (float)TotalBytesToReceive) * 100; - public long CurrentSpeed { get; private set; } - public TimeSpan TimeLeft => TimeSpan.FromSeconds((TotalBytesToReceive - BytesReceived) / CurrentSpeed); - } -} diff --git a/Hi3Helper.Core/Classes/Shared/Region/ConfigV2Store.cs b/Hi3Helper.Core/Classes/Shared/Region/ConfigV2Store.cs index 76d3e6cc4..517caebd0 100644 --- a/Hi3Helper.Core/Classes/Shared/Region/ConfigV2Store.cs +++ b/Hi3Helper.Core/Classes/Shared/Region/ConfigV2Store.cs @@ -58,16 +58,17 @@ public static void LoadConfigV2() if (string.IsNullOrEmpty(content)) throw new NullReferenceException($"{AppGameConfigV2MetadataPath} file seems to be empty. Please remove it and restart the launcher!"); ConfigV2 = (Metadata)JsonSerializer - .Deserialize(content, typeof(Metadata), MetadataContext.Default); + .Deserialize(content, typeof(Metadata), CoreLibraryJSONContext.Default); if (ConfigV2 is null) throw new NullReferenceException("Metadata config is broken"); ConfigV2GameCategory = ConfigV2.MetadataV2.Keys.ToList(); ConfigV2LastUpdate = ((Stamp)JsonSerializer - .Deserialize(stamp, typeof(Stamp), StampContext.Default)).LastUpdated; + .Deserialize(stamp, typeof(Stamp), CoreLibraryJSONContext.Default)).LastUpdated; ConfigV2.DecryptStrings(); + ConfigV2.GenerateHashID(); } public static bool GetConfigV2Regions(string GameCategoryName) diff --git a/Hi3Helper.Core/Classes/Shared/Region/Config/LauncherConfig.cs b/Hi3Helper.Core/Classes/Shared/Region/LauncherConfig.cs similarity index 97% rename from Hi3Helper.Core/Classes/Shared/Region/Config/LauncherConfig.cs rename to Hi3Helper.Core/Classes/Shared/Region/LauncherConfig.cs index 57ae54903..af5de90ed 100644 --- a/Hi3Helper.Core/Classes/Shared/Region/Config/LauncherConfig.cs +++ b/Hi3Helper.Core/Classes/Shared/Region/LauncherConfig.cs @@ -98,6 +98,7 @@ public static string AppExecutablePath return Path.Combine(dirPath, execName + ".exe"); } } + public static string AppExecutableName { get => Path.GetFileName(AppExecutablePath); } public static string AppGameImgFolder { get => Path.Combine(AppGameFolder, "_img"); } public static string AppGameImgCachedFolder { get => Path.Combine(AppGameImgFolder, "cached"); } public static string AppGameLogsFolder { get => Path.Combine(AppGameFolder, "_logs"); } @@ -184,8 +185,11 @@ public static bool IsShowRegionChangeWarning { "CurrentCDN", 0 }, { "ShowRegionChangeWarning", true }, #if !DISABLEDISCORD - { "EnableDiscordRPC", false } + { "EnableDiscordRPC", false }, #endif + { "EnableAcrylicEffect", true }, + { "IncludeGameLogs", false }, + { "UseDownloadChunksMerging", false } }; public static void LoadGamePreset() diff --git a/Hi3Helper.Core/Hi3Helper.Core.csproj b/Hi3Helper.Core/Hi3Helper.Core.csproj index 4cecd4ab3..f489fbf97 100644 --- a/Hi3Helper.Core/Hi3Helper.Core.csproj +++ b/Hi3Helper.Core/Hi3Helper.Core.csproj @@ -12,6 +12,7 @@ true portable HDIFFEXPERIMENTAL + true @@ -71,10 +72,6 @@ - - - - Always @@ -109,9 +106,6 @@ Always - - Always - Always diff --git a/Hi3Helper.Core/Lang/Locale/LangDialogs.cs b/Hi3Helper.Core/Lang/Locale/LangDialogs.cs index b7e50a69c..658afd3da 100644 --- a/Hi3Helper.Core/Lang/Locale/LangDialogs.cs +++ b/Hi3Helper.Core/Lang/Locale/LangDialogs.cs @@ -89,7 +89,11 @@ public sealed class LangDialogs public string ReleaseChannelChangeSubtitle2 { get; set; } = LangFallback?._Dialogs.ReleaseChannelChangeSubtitle2; public string ReleaseChannelChangeSubtitle3 { get; set; } = LangFallback?._Dialogs.ReleaseChannelChangeSubtitle3; public string LocateExePathTitle { get; set; } = LangFallback?._Dialogs.LocateInstallTitle; - public string LocateExePathSubtitle{ get; set; } = LangFallback?._Dialogs.LocateExePathSubtitle; + public string CannotUseAppLocationForGameDirTitle { get; set; } = LangFallback?._Dialogs.CannotUseAppLocationForGameDirTitle; + public string CannotUseAppLocationForGameDirSubtitle { get; set; } = LangFallback?._Dialogs.CannotUseAppLocationForGameDirSubtitle; + public string LocateExePathSubtitle { get; set; } = LangFallback?._Dialogs.LocateExePathSubtitle; + public string StopGameTitle { get; set; } = LangFallback?._Dialogs.StopGameTitle; + public string StopGameSubtitle { get; set; } = LangFallback?._Dialogs.StopGameSubtitle; } } #endregion diff --git a/Hi3Helper.Core/Lang/Locale/LangGameSettingsPage.cs b/Hi3Helper.Core/Lang/Locale/LangGameSettingsPage.cs index db1a2822e..0364abbd3 100644 --- a/Hi3Helper.Core/Lang/Locale/LangGameSettingsPage.cs +++ b/Hi3Helper.Core/Lang/Locale/LangGameSettingsPage.cs @@ -12,6 +12,7 @@ public sealed class LangGameSettingsPage public string Graphics_Title { get; set; } = LangFallback?._GameSettingsPage.Graphics_Title; public string Graphics_ResolutionPanel { get; set; } = LangFallback?._GameSettingsPage.Graphics_ResolutionPanel; public string Graphics_Fullscreen { get; set; } = LangFallback?._GameSettingsPage.Graphics_Fullscreen; + public string Graphics_Borderless { get; set; } = LangFallback?._GameSettingsPage.Graphics_Borderless; public string Graphics_ExclusiveFullscreen { get; set; } = LangFallback?._GameSettingsPage.Graphics_ExclusiveFullscreen; public string Graphics_ResSelectPlaceholder { get; set; } = LangFallback?._GameSettingsPage.Graphics_ResSelectPlaceholder; public string Graphics_ResCustom { get; set; } = LangFallback?._GameSettingsPage.Graphics_ResCustom; diff --git a/Hi3Helper.Core/Lang/Locale/LangHomePage.cs b/Hi3Helper.Core/Lang/Locale/LangHomePage.cs index dd6aa1c69..dd50beaed 100644 --- a/Hi3Helper.Core/Lang/Locale/LangHomePage.cs +++ b/Hi3Helper.Core/Lang/Locale/LangHomePage.cs @@ -41,6 +41,7 @@ public sealed class LangHomePage public string GameSettings_Panel2RepairGame { get; set; } = LangFallback?._HomePage.GameSettings_Panel2RepairGame; public string GameSettings_Panel2UninstallGame { get; set; } = LangFallback?._HomePage.GameSettings_Panel2UninstallGame; public string GameSettings_Panel2ConvertVersion { get; set; } = LangFallback?._HomePage.GameSettings_Panel2ConvertVersion; + public string GameSettings_Panel2StopGame { get; set; } = LangFallback?._HomePage.GameSettings_Panel2StopGame; public string GameSettings_Panel3 { get; set; } = LangFallback?._HomePage.GameSettings_Panel3; public string GameSettings_Panel4 { get; set; } = LangFallback?._HomePage.GameSettings_Panel4; public string GameSettings_Panel4ShowEventsPanel { get; set; } = LangFallback?._HomePage.GameSettings_Panel4ShowEventsPanel; diff --git a/Hi3Helper.Core/Lang/Locale/LangMisc.cs b/Hi3Helper.Core/Lang/Locale/LangMisc.cs index 93d4080f4..819a6e5dc 100644 --- a/Hi3Helper.Core/Lang/Locale/LangMisc.cs +++ b/Hi3Helper.Core/Lang/Locale/LangMisc.cs @@ -91,6 +91,7 @@ public sealed class LangMisc public string DiscordRP_Idle { get; set; } = LangFallback?._Misc.DiscordRP_Idle; public string DiscordRP_Default { get; set; } = LangFallback?._Misc.DiscordRP_Default; public string DiscordRP_Ad { get; set; } = LangFallback?._Misc.DiscordRP_Ad; + public string DiscordRP_Region { get; set; } = LangFallback?._Misc.DiscordRP_Region; } } #endregion diff --git a/Hi3Helper.Core/Lang/Locale/LangSettingsPage.cs b/Hi3Helper.Core/Lang/Locale/LangSettingsPage.cs index 3abbebb88..6d10583a6 100644 --- a/Hi3Helper.Core/Lang/Locale/LangSettingsPage.cs +++ b/Hi3Helper.Core/Lang/Locale/LangSettingsPage.cs @@ -11,6 +11,7 @@ public sealed class LangSettingsPage public string PageTitle { get; set; } = LangFallback?._SettingsPage.PageTitle; public string Debug { get; set; } = LangFallback?._SettingsPage.Debug; public string Debug_Console { get; set; } = LangFallback?._SettingsPage.Debug_Console; + public string Debug_IncludeGameLogs { get; set; } = LangFallback?._SettingsPage.Debug_IncludeGameLogs; public string Debug_MultipleInstance { get; set; } = LangFallback?._SettingsPage.Debug_MultipleInstance; public string ChangeRegionWarning_Toggle { get; set; } = LangFallback?._SettingsPage.ChangeRegionWarning_Toggle; public string ChangeRegionWarning_Warning { get; set; } = LangFallback?._SettingsPage.ChangeRegionWarning_Warning; @@ -55,6 +56,7 @@ public sealed class LangSettingsPage public string AppFiles_ClearImgCachesBtn { get; set; } = LangFallback?._SettingsPage.AppFiles_ClearImgCachesBtn; public string ReportIssueBtn { get; set; } = LangFallback?._SettingsPage.ReportIssueBtn; public string ContributePRBtn { get; set; } = LangFallback?._SettingsPage.ContributePRBtn; + public string ContributorListBtn { get; set; } = LangFallback?._SettingsPage.ContributorListBtn; public string About { get; set; } = LangFallback?._SettingsPage.About; public string About_Copyright1 { get; set; } = LangFallback?._SettingsPage.About_Copyright1; public string About_Copyright2 { get; set; } = LangFallback?._SettingsPage.About_Copyright2; @@ -68,6 +70,8 @@ public sealed class LangSettingsPage public string DiscordBtn2 { get; set; } = LangFallback?._SettingsPage.DiscordBtn2; public string DiscordBtn3 { get; set; } = LangFallback?._SettingsPage.DiscordBtn3; public string AppChangeReleaseChannel { get; set; } = LangFallback?._SettingsPage.AppChangeReleaseChannel; + public string EnableAcrylicEffect { get; set; } = LangFallback?._SettingsPage.EnableAcrylicEffect; + public string EnableDownloadChunksMerging { get; set; } = LangFallback?._SettingsPage.EnableDownloadChunksMerging; } } #endregion diff --git a/Hi3Helper.Core/Lang/Locale/LangStarRailGameSettingsPage.cs b/Hi3Helper.Core/Lang/Locale/LangStarRailGameSettingsPage.cs index 7bf20142a..cba342a74 100644 --- a/Hi3Helper.Core/Lang/Locale/LangStarRailGameSettingsPage.cs +++ b/Hi3Helper.Core/Lang/Locale/LangStarRailGameSettingsPage.cs @@ -57,6 +57,7 @@ public sealed class LangStarRailGameSettingsPage public string Graphics_EnvDetailQuality { get; set; } = LangFallback?._StarRailGameSettingsPage.Graphics_EnvDetailQuality; public string Graphics_ReflectionQuality { get; set; } = LangFallback?._StarRailGameSettingsPage.Graphics_ReflectionQuality; public string Graphics_BloomQuality { get; set; } = LangFallback?._StarRailGameSettingsPage.Graphics_BloomQuality; + public string Graphics_SFXQuality { get; set; } = LangFallback?._StarRailGameSettingsPage.Graphics_SFXQuality; public string Graphics_AAMode { get; set; } = LangFallback?._StarRailGameSettingsPage.Graphics_AAMode; public string Graphics_SpecPanel { get; set; } = LangFallback?._StarRailGameSettingsPage.Graphics_SpecPanel; public string SpecEnabled { get; set; } = LangFallback?._StarRailGameSettingsPage.SpecEnabled; diff --git a/Hi3Helper.Core/Lang/Localization.cs b/Hi3Helper.Core/Lang/Localization.cs index 6e69daba4..cf88f7da7 100644 --- a/Hi3Helper.Core/Lang/Localization.cs +++ b/Hi3Helper.Core/Lang/Localization.cs @@ -33,7 +33,7 @@ public LocalizationParams LoadLang() { using (Stream s = new FileStream(this.LangFilePath, FileMode.Open, FileAccess.Read)) { - LocalizationParams _langData = (LocalizationParams)JsonSerializer.Deserialize(s, typeof(LocalizationParams), LocalizationParamsContext.Default); + LocalizationParams _langData = (LocalizationParams)JsonSerializer.Deserialize(s, typeof(LocalizationParams), CoreLibraryFieldsJSONContext.Default); this.LangAuthor = _langData.Author; this.LangID = _langData.LanguageID.ToLower(); this.LangName = _langData.LanguageName; diff --git a/Hi3Helper.Core/Lang/en-us.json b/Hi3Helper.Core/Lang/en-us.json index d3b3fdbc7..a27fe0117 100644 --- a/Hi3Helper.Core/Lang/en-us.json +++ b/Hi3Helper.Core/Lang/en-us.json @@ -113,6 +113,7 @@ "GameSettings_Panel2RepairGame": "Repair Game", "GameSettings_Panel2UninstallGame": "Uninstall Game", "GameSettings_Panel2ConvertVersion": "Convert Game Version", + "GameSettings_Panel2StopGame": "Force Close Game", "GameSettings_Panel3": "Custom Start-up Args", "GameSettings_Panel4": "Miscellaneous", "GameSettings_Panel4ShowEventsPanel": "Show Events Panel", @@ -216,6 +217,7 @@ "Graphics_Title": "Graphics Settings", "Graphics_ResolutionPanel": "Game Resolution", + "Graphics_Borderless": "Borderless Screen", "Graphics_Fullscreen": "Fullscreen", "Graphics_ExclusiveFullscreen": "Use Exclusive Fullscreen", "Graphics_ResSelectPlaceholder": "Select", @@ -305,6 +307,7 @@ "Debug": "Debugging", "Debug_Console": "Show Console", + "Debug_IncludeGameLogs": "Save Game logs to Collapse's (might contain sensitive data)", "Debug_MultipleInstance": "Allow running multiple instances of Collapse", "ChangeRegionWarning_Toggle": "Show Region Change Warning", @@ -360,6 +363,7 @@ "ReportIssueBtn": "Report an Issue", "ContributePRBtn": "Contribute with a Pull Request", + "ContributorListBtn": "Open Source Contributors", "About": "About", "About_Copyright1": "© 2022-2023 Created by", @@ -376,7 +380,10 @@ "DiscordBtn2": "Honkai Impact 3rd Discord", "DiscordBtn3": "Collapse's Official Discord!", - "AppChangeReleaseChannel": "Change to {0} Release Channel" + "AppChangeReleaseChannel": "Change to {0} Release Channel", + + "EnableAcrylicEffect": "Use Acrylic Blur Effect", + "EnableDownloadChunksMerging": "Merge Downloaded Package Chunks" }, "_Misc": { @@ -471,7 +478,8 @@ "DiscordRP_AppSettings": "Changing App Settings", "DiscordRP_Idle": "Idle", "DiscordRP_Default": "No Activity", - "DiscordRP_Ad": "- On Collapse Launcher" + "DiscordRP_Ad": "- With Collapse Launcher", + "DiscordRP_Region": "Region:" }, "_Dialogs": { @@ -556,7 +564,11 @@ "ResetPlaytimeSubtitle2": "destructive", "ResetPlaytimeSubtitle3": " action, meaning that you cannot undo this once you confirm. \n\nDo you wish to proceed?\n\nNote: This has no impact on how Collapse operates and you can change this value again at any time when not playing the game.", "LocateExePathTitle": "Locate Executable Install Path", - "LocateExePathSubtitle": "Please point Collapse to the location of your application's executable:" + "LocateExePathSubtitle": "Please point Collapse to the location of your application's executable:", + "CannotUseAppLocationForGameDirTitle": "Folder is invalid!", + "CannotUseAppLocationForGameDirSubtitle": "You can't use this folder as it is being used as a system folder or being used for main executable of the app. Please choose another folder!", + "StopGameTitle": "Force Stop Game", + "StopGameSubtitle": "Are you sure you want to force stop current running game?\r\nYou may lose some in-game progress." }, "_InstallMgmt": { @@ -719,6 +731,7 @@ "Graphics_ReflectionQuality": "Reflection Quality", "Graphics_BloomQuality": "Bloom Quality", "Graphics_AAMode": "Anti-Aliasing Mode", + "Graphics_SFXQuality": "SFX Quality", "Graphics_SpecPanel": "Global Graphics Settings", "SpecEnabled": "Enabled", diff --git a/Hi3Helper.Core/Lib/HPatchZ.dll b/Hi3Helper.Core/Lib/HPatchZ.dll deleted file mode 100644 index 29a329f06..000000000 Binary files a/Hi3Helper.Core/Lib/HPatchZ.dll and /dev/null differ diff --git a/Hi3Helper.Core/packages.lock.json b/Hi3Helper.Core/packages.lock.json new file mode 100644 index 000000000..432022db9 --- /dev/null +++ b/Hi3Helper.Core/packages.lock.json @@ -0,0 +1,31 @@ +{ + "version": 1, + "dependencies": { + "net7.0": { + "Google.Protobuf": { + "type": "Transitive", + "resolved": "3.23.4", + "contentHash": "DF+mB+Fwan5Hm5dnbKbrIl7C5ypMr8tJJheutkYgFXCoM88HfBNo2qYO60CEf6fvEe/fhCGtvfEBCoCIhIn7dQ==" + }, + "System.IO.Hashing": { + "type": "Transitive", + "resolved": "7.0.0", + "contentHash": "sDnWM0N3AMCa86LrKTWeF3BZLD2sgWyYUc7HL6z4+xyDZNQRwzmxbo4qP2rX2MqC+Sy1/gOSRDah5ltxY5jPxw==" + }, + "hi3helper.enctool": { + "type": "Project", + "dependencies": { + "Google.Protobuf": "[3.23.4, )", + "Hi3Helper.Http": "[1.0.0, )", + "System.IO.Hashing": "[7.0.0, )" + } + }, + "hi3helper.http": { + "type": "Project" + }, + "hi3helper.sharphdiffpatch": { + "type": "Project" + } + } + } +} \ No newline at end of file diff --git a/Hi3Helper.EncTool b/Hi3Helper.EncTool index dd34bf3ae..a33c4cced 160000 --- a/Hi3Helper.EncTool +++ b/Hi3Helper.EncTool @@ -1 +1 @@ -Subproject commit dd34bf3ae54370ff17994669b8b8052bf7c4f9fa +Subproject commit a33c4cced35cb8505a34767c3f122c983fbd965c diff --git a/Hi3Helper.Http b/Hi3Helper.Http index d671e7c48..7e191f0e1 160000 --- a/Hi3Helper.Http +++ b/Hi3Helper.Http @@ -1 +1 @@ -Subproject commit d671e7c481dd238c5cda9f2e456343764bad9eb8 +Subproject commit 7e191f0e139fd98c1c0515820bfb0af4a9120166 diff --git a/Hi3Helper.SharpHDiffPatch b/Hi3Helper.SharpHDiffPatch index 0e5847eda..3bc996afe 160000 --- a/Hi3Helper.SharpHDiffPatch +++ b/Hi3Helper.SharpHDiffPatch @@ -1 +1 @@ -Subproject commit 0e5847eda4c16f3c58414f485b47a13e1bbc076d +Subproject commit 3bc996afe6140edc89a4d3a2b39903353478cdf8 diff --git a/README.md b/README.md index 0aca9a534..df68dc084 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,8 @@ **Collapse** was originally designed for **Honkai Impact 3rd**. However, as the project evolved, this launcher is now a game client for all currently released **miHoYo Games**. +[![Build-Canary](https://github.com/neon-nyan/Collapse/actions/workflows/build.yml/badge.svg?branch=main)](https://github.com/neon-nyan/Collapse/actions/workflows/build.yml) + ![de translation](https://img.shields.io/badge/dynamic/json?color=blue&label=de&style=flat&logo=crowdin&query=%24.progress.0.data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-15551431-552387.json) ![es-419 translation](https://img.shields.io/badge/dynamic/json?color=blue&label=es-419&style=flat&logo=crowdin&query=%24.progress.1.data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-15551431-552387.json) ![id translation](https://img.shields.io/badge/dynamic/json?color=blue&label=id&style=flat&logo=crowdin&query=%24.progress.2.data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-15551431-552387.json) @@ -91,7 +93,7 @@ Not only that, this launcher also has some advanced features for **Genshin Impac :white_check_mark: :white_check_mark: :white_check_mark: - :x: + N/A TW/HK/MO @@ -101,7 +103,7 @@ Not only that, this launcher also has some advanced features for **Genshin Impac :white_check_mark: :white_check_mark: :white_check_mark: - :x: + N/A Japan @@ -111,7 +113,7 @@ Not only that, this launcher also has some advanced features for **Genshin Impac :white_check_mark: :white_check_mark: :white_check_mark: - :x: + N/A Korea @@ -121,7 +123,7 @@ Not only that, this launcher also has some advanced features for **Genshin Impac :white_check_mark: :white_check_mark: :white_check_mark: - :x: + N/A Genshin Impact @@ -132,7 +134,7 @@ Not only that, this launcher also has some advanced features for **Genshin Impac :white_check_mark: :x: :white_check_mark: - :x: + N/A Mainland China @@ -142,7 +144,7 @@ Not only that, this launcher also has some advanced features for **Genshin Impac :x: :x: :white_check_mark: - :x: + N/A Honkai: Star Rail @@ -150,33 +152,34 @@ Not only that, this launcher also has some advanced features for **Genshin Impac :white_check_mark: :white_check_mark: :white_check_mark: - :white_check_mark: - :white_check_mark: - :white_check_mark: :x: + :x: + :white_check_mark: + N/A Mainland China :white_check_mark: :white_check_mark: :white_check_mark: - :white_check_mark: - :white_check_mark: - :white_check_mark: :x: + :x: + :white_check_mark: + N/A > **Note**: -> Some features such as Game Data Repair and Preloading are available for other games, but more advanced features such as Game Settings modification and Caches Download are currently not available and unsupported. The table above serves to illustrate the features Collapse currently support. This list will continuously get updated as new features get added to Collapse and new games get released. +> The table above serves to illustrate the features Collapse currently support. This list will continuously get updated as new features get added to Collapse and new games get released. If you have any issues with any supported features above, checks our GitHub issue tab, report if no active issues for it is found. +> > Please keep in mind that the Game Conversion feature is currently only available for Honkai Impact: 3rd. Other miHoYo/Cognosphere Pte. Ltd. games are currently not planned for game conversion. # Download Ready-To-Use Build -[](https://github.com/neon-nyan/Collapse/releases/download/CL-v1.70.10/CL-1.70.10_Installer.exe) -> **Note**: The version for this build is `1.70.11` (Released on: June 25th, 2023). +[](https://github.com/neon-nyan/Collapse/releases/download/CL-v1.70.12/CL-1.70.12_Installer.exe) +> **Note**: The version for this build is `1.70.12` (Released on: June 25th, 2023). -[](https://github.com/neon-nyan/Collapse/releases/download/v1.71.2-pre/CL-1.71.2-preview_Installer.exe) -> **Note**: The version for this build is `1.71.1` (Released on: July 5th, 2023). +[](https://github.com/neon-nyan/Collapse/releases/download/CL-v1.71.3-pre/CL-1.71.3-preview_Installer.exe) +> **Note**: The version for this build is `1.71.3` (Released on: July 25th, 2023). To view all releases, [**click here**](https://github.com/neon-nyan/CollapseLauncher/releases). @@ -188,18 +191,9 @@ To view all releases, [**click here**](https://github.com/neon-nyan/CollapseLaun *** # Prerequisites for Building Locally/Development -## More information can be found in [**Contribution Guidelines**](https://github.com/neon-nyan/Collapse/blob/main/CONTRIBUTING.md) -*Collapse* is presently powered by .NET 7 and as such, the packages listed below are required to create a local and development build of the launcher. Furthermore, *Collapse* uses many submodules and packages outside of this, which will automatically be loaded when the user sets up a local environment of the application. -1. **Visual Studio 2022 (Any Edition - 17.4 or later)** -2. **Windows 10 SDK (10.0.19043.0) or Windows 11 SDK (10.0.22000.0)** via Visual Studio Installer -3. .NET: [**.NET Core 7 SDK (7.0.100 or later)**](https://dotnet.microsoft.com/en-us/download/dotnet/7.0) -4. WinUI 3: [**WinUI 3 (WindowsAppSDK 1.3.0-230331000 Stable Runtime)**](https://aka.ms/windowsappsdk/1.3/1.3.230331000/windowsappruntimeinstall-x64.exe) +> ### More information can be found in [**Contribution Guidelines**](https://github.com/neon-nyan/Collapse/blob/main/CONTRIBUTING.md) -> **Note**: -> -> Starting from November 13rd 2022, you must have Visual Studio 2022 installed on your computer due to the updated minimum system requirement of `WinUI 3 1.3 Stable`. -> -> Using a lower Visual Studio version (like VS2019) is possible, but it is not recommended as you need to downgrade **WindowsAppSDK** via *NuGet* to **WindowsAppSDK 1.1.5** or **WindowsAppSDK 1.2-preview2** before building. This has an increased risk of breaking the application and as such, minimal support will be provided for this method. **This is not recommended for beginner users.** +*** # Third-party repositories and libraries used in this project - [**Windows UI Library**](https://github.com/microsoft/microsoft-ui-xaml) by Microsoft