From a427a4fcca9c9957bc5988410207b34d05fdaa53 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Mon, 1 Jun 2026 18:23:53 +0700 Subject: [PATCH 01/15] Update NuGet, Submodules and Bump Version --- CollapseLauncher/CollapseLauncher.csproj | 18 +- CollapseLauncher/packages.lock.json | 250 +++++++++--------- ColorThief | 2 +- H.NotifyIcon | 2 +- ...Toolkit.WinUI.Controls.ImageCropper.csproj | 2 +- .../ImageCropper/packages.lock.json | 104 ++++---- ...kit.WinUI.Controls.SettingsControls.csproj | 2 +- .../SettingsControls/packages.lock.json | 104 ++++---- Hi3Helper.Core/Hi3Helper.Core.csproj | 2 +- Hi3Helper.Core/packages.lock.json | 36 +-- Hi3Helper.EncTool | 2 +- Hi3Helper.Plugin.Core | 2 +- Hi3Helper.SharpDiscordRPC | 2 +- Hi3Helper.Sophon | 2 +- .../Hi3Helper.TaskScheduler.csproj | 2 +- Hi3Helper.TaskScheduler/packages.lock.json | 6 +- Hi3Helper.Win32 | 2 +- ImageEx | 2 +- InnoSetupHelper/InnoSetupHelper.csproj | 2 +- InnoSetupHelper/packages.lock.json | 12 +- env.json | 2 +- global.json | 2 +- 22 files changed, 276 insertions(+), 284 deletions(-) diff --git a/CollapseLauncher/CollapseLauncher.csproj b/CollapseLauncher/CollapseLauncher.csproj index ef4305ab11..5ec2b064b3 100644 --- a/CollapseLauncher/CollapseLauncher.csproj +++ b/CollapseLauncher/CollapseLauncher.csproj @@ -16,7 +16,7 @@ $(Company). neon-nyan, Cry0, bagusnl, shatyuka, gablm. Copyright 2022-2025 $(Company) - 1.83.18 + 1.83.19 preview x64 @@ -257,15 +257,15 @@ - + - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + @@ -284,18 +284,18 @@ - + - + - + - - + + diff --git a/CollapseLauncher/packages.lock.json b/CollapseLauncher/packages.lock.json index f164b721f7..c8c33edd71 100644 --- a/CollapseLauncher/packages.lock.json +++ b/CollapseLauncher/packages.lock.json @@ -101,23 +101,23 @@ }, "Markdig.Signed": { "type": "Direct", - "requested": "[1.1.3, )", - "resolved": "1.1.3", - "contentHash": "1Is+2AhZEUw8tWk9v7kGuji1bnO5/qnaI5bbyrA3WQmESUWYC0wPFQLv0blKIfDoN+x10WBagl7sLgb7u4Rptw==" + "requested": "[1.2.0, )", + "resolved": "1.2.0", + "contentHash": "NAVbdsCt8sLQ39IK7Huzzl5kDPPUmnFPFxOoUfb2gtQN6OnZfE70csEp3xkAvaydeuzMXoejWW+AWG9Wk6gtQg==" }, "Microsoft.Extensions.DependencyInjection.Abstractions": { "type": "Direct", - "requested": "[10.0.7, )", - "resolved": "10.0.7", - "contentHash": "Z6mfFEaFcwCfSboxJwOLfu7/31npCY9q70WUamHW/vRQhDvBKOT4Vf9YkZj5J6hLvJpb0oDEYfHunQZj0xxvKw==" + "requested": "[10.0.8, )", + "resolved": "10.0.8", + "contentHash": "21nbDV60SRPWGIivsyl6lqBeEJNG1sginhhfWgRrr3Ais7aQ12To25OAHQxgoiJkjqy1aQ6RxpZBGYuTi7Ge6A==" }, "Microsoft.Extensions.Logging.Abstractions": { "type": "Direct", - "requested": "[10.0.7, )", - "resolved": "10.0.7", - "contentHash": "tIEcQ2gvERrH2KiCjdsVcHGhXt9lIsuDStfOIeZWr7/fP8IXhGiYfx0/80PNI7WPO2IYuFtlZLSlnTS8+/Mchw==", + "requested": "[10.0.8, )", + "resolved": "10.0.8", + "contentHash": "fdVadZmsC8jRP0KvKy8mO8f6GV/HyBvElfcSxEhd+5FM5boAw/01iSaCto5G3G37ApJira4A3pNaVvBv8cUiLQ==", "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.7" + "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8" } }, "Microsoft.Graphics.Win2D": { @@ -131,15 +131,15 @@ }, "Microsoft.NET.ILLink.Tasks": { "type": "Direct", - "requested": "[10.0.7, )", - "resolved": "10.0.7", - "contentHash": "AA/yhzFHNtQZXLdqjzujPy25G8EWwGWsAnxOE2zYSBoT/8QHP6ketN3CToD3DFreO653ipUwnKHo22B8AlBMCw==" + "requested": "[10.0.8, )", + "resolved": "10.0.8", + "contentHash": "dVbSXGIFNR5nZcv2tOLoWI+a9T4jtFd77IYjuND+QVe360qWgAF7H0WtoopYhRw/+SgpGUTyrkrh+65+ClNnfw==" }, "Microsoft.Web.WebView2": { "type": "Direct", - "requested": "[1.0.3912.50, )", - "resolved": "1.0.3912.50", - "contentHash": "mEIKZDSmb6CxGWKoxaxTSJ0yi0DD2zp29TA7kJY2GdanuH3c5aYruwfqsm3OsYn/h2hUhybQZvfbxyZe4O+X4Q==" + "requested": "[1.0.3967.48, )", + "resolved": "1.0.3967.48", + "contentHash": "b7dZ5kZ9bfU5Yo11M8feCOoiyalXCN+2Gsw674RBDBmQ2dJV5EOXb8/ivN2LuLJ+VO2V7FmK6l6LsyfEnG1lXw==" }, "Microsoft.Windows.CsWinRT": { "type": "Direct", @@ -155,19 +155,19 @@ }, "Microsoft.WindowsAppSDK": { "type": "Direct", - "requested": "[2.0.1, )", - "resolved": "2.0.1", - "contentHash": "R+iN0mqIUUppbzpHU178R5malnttTTVBOBIGi1NQVVZAs34bAANM/iLJhjj6uUBgYiPfpvjcLbHT5IZ8kKKaqg==", + "requested": "[2.1.3, )", + "resolved": "2.1.3", + "contentHash": "46KCntcmWPS0nbV3a8iEMslpYy0W9wTsmkANrXFxDWuiAnm8jXytFNvwNVN5HfoA3d+Cxb3pO+JE2UNnB5wn7w==", "dependencies": { - "Microsoft.WindowsAppSDK.AI": "2.0.185", - "Microsoft.WindowsAppSDK.Base": "2.0.3", - "Microsoft.WindowsAppSDK.DWrite": "2.0.26041403", - "Microsoft.WindowsAppSDK.Foundation": "2.0.20", - "Microsoft.WindowsAppSDK.InteractiveExperiences": "2.0.12", - "Microsoft.WindowsAppSDK.ML": "2.0.300", - "Microsoft.WindowsAppSDK.Runtime": "[2.0.1]", - "Microsoft.WindowsAppSDK.Widgets": "2.0.4", - "Microsoft.WindowsAppSDK.WinUI": "2.0.12" + "Microsoft.WindowsAppSDK.AI": "2.1.10", + "Microsoft.WindowsAppSDK.Base": "2.0.4", + "Microsoft.WindowsAppSDK.DWrite": "2.1.0", + "Microsoft.WindowsAppSDK.Foundation": "2.0.21", + "Microsoft.WindowsAppSDK.InteractiveExperiences": "2.0.13", + "Microsoft.WindowsAppSDK.ML": "2.1.1", + "Microsoft.WindowsAppSDK.Runtime": "[2.1.3]", + "Microsoft.WindowsAppSDK.Widgets": "2.0.5", + "Microsoft.WindowsAppSDK.WinUI": "2.1.0" } }, "Microsoft.Xaml.Behaviors.WinUI.Managed": { @@ -202,15 +202,15 @@ }, "System.CommandLine": { "type": "Direct", - "requested": "[2.0.7, )", - "resolved": "2.0.7", - "contentHash": "ih4yNLLF2Ebz85xJJBaPeddLa4d1AekYId7Y1g8oSsEaBHHd/CtyeBJ+tDvQadqeXz7i591K5ry/td+4aaHnQA==" + "requested": "[2.0.8, )", + "resolved": "2.0.8", + "contentHash": "FbpgF8p/ClXnoXEWLjQB34kNh5rsLewEgIgLyVzLDucAOQ4cNs7ec9Cam7gdKPruSb6zp4Mx8htZGTL4/5PJPg==" }, "System.Security.Cryptography.ProtectedData": { "type": "Direct", - "requested": "[10.0.7, )", - "resolved": "10.0.7", - "contentHash": "eqKW9wyPUhZi6pxy9Y0fQO/bdHROcwj0tYdmoGEPCPCtCJLFdVVAlzuuYYEnJI64HxhoXPYGhtx891g/jwN4rg==" + "requested": "[10.0.8, )", + "resolved": "10.0.8", + "contentHash": "/ldVgSfImIBp6fLWS7sLH0BnmtFj0ZwGlZo4Xx2q0K3ZhJNDbW45kj2f6zPoC+L+BTINuHdMzTsopuwmkbgcNA==" }, "ThisAssembly.Constants": { "type": "Direct", @@ -226,12 +226,9 @@ }, "Velopack": { "type": "Direct", - "requested": "[0.0.1298, )", - "resolved": "0.0.1298", - "contentHash": "PJ6Nm28qJ4ChsHYzgHUJ8g+DGyyHes2+bwxY709+znMhgi8fMp8M1FTF8x6pZMjnsPCWVwoMlxVEyq0NLeRZtA==", - "dependencies": { - "NuGet.Versioning": "6.14.0" - } + "requested": "[1.1.1, )", + "resolved": "1.1.1", + "contentHash": "NvPcAHnGj97qFToV4HZIEs05UfWYMXo0BAFUVmsf+/Xb1Bxqvk7H09CXanCqb5Vpd42tN5h7dz/qHLvWnTMpzw==" }, "CommunityToolkit.WinUI.Animations": { "type": "Transitive", @@ -262,8 +259,8 @@ }, "Google.Protobuf": { "type": "Transitive", - "resolved": "3.34.1", - "contentHash": "212vdYxRuVopGE5bess6Jg5oXWyizA6hcLPTI7G+qA4PthQEvfeof3njT+7VSY5v/+O0P22xTydiP5fSJJpGEA==" + "resolved": "3.35.0", + "contentHash": "OrUZCUzBXqdSmsQSWp/EPeINjOBcMU+PrZEJegw0aLgOGFHZ9ZI37X/SFrIxo8C9ghKynaKpPr3BVPc4EujWYg==" }, "Hi3Helper.ZstdNet": { "type": "Transitive", @@ -272,45 +269,45 @@ }, "Microsoft.Extensions.DependencyInjection": { "type": "Transitive", - "resolved": "10.0.7", - "contentHash": "91F/o3emPV/+xY/ip3s2LqDNF14kjttlVtq0BXgg6p4MnCzeSZxnUJm+t6WRrtD3JdGo88/oX+z7OwK4y8PZuw==", + "resolved": "10.0.8", + "contentHash": "daf62xHIrq8pnE709hgaZZN9tSam9TGGepWe1+bE6V3GEuVwJiMs6ib+38lfMCyAJAHiX0vapxBhsuMSV7U+cg==", "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.7" + "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8" } }, "Microsoft.Extensions.Logging": { "type": "Transitive", - "resolved": "10.0.7", - "contentHash": "hOeRIQ63GkgiYCB/MIFp+LQs8aXpJXpB55t6Aj37ab7t2/6WeFcPXxYM9hdy/o5tffzwf8mhqzLJP6mjGYCxjw==", + "resolved": "10.0.8", + "contentHash": "K60JhWC2hN/Gi7TP68tBxSzk5ACWOs7lkmPzsfA8Bcf/IXTajujt2ORMf9rSMk1bsng6Lv4Y3fuxp3bm1+15ug==", "dependencies": { - "Microsoft.Extensions.DependencyInjection": "10.0.7", - "Microsoft.Extensions.Logging.Abstractions": "10.0.7", - "Microsoft.Extensions.Options": "10.0.7" + "Microsoft.Extensions.DependencyInjection": "10.0.8", + "Microsoft.Extensions.Logging.Abstractions": "10.0.8", + "Microsoft.Extensions.Options": "10.0.8" } }, "Microsoft.Extensions.Options": { "type": "Transitive", - "resolved": "10.0.7", - "contentHash": "00SHUGTh2jSMvIr6x9Xwd2nE+B5/qFCO/9hDwUDhJsjYRDlADmaBZ7tqehXzBDsfjHSXJzuRHJzPYPPjphBQ7Q==", + "resolved": "10.0.8", + "contentHash": "VBD+131DpTNCNDfA4kIyKTiCySvJGNhwibdWBSdFRu7GMfXLXcXODkgA+KStKbbhzraLglZWUN4nXyHgW4JIRA==", "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.7", - "Microsoft.Extensions.Primitives": "10.0.7" + "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8", + "Microsoft.Extensions.Primitives": "10.0.8" } }, "Microsoft.Extensions.Primitives": { "type": "Transitive", - "resolved": "10.0.7", - "contentHash": "D5M0Jr551iTgwkZMN9rm0pSkgNLj5quUWQUmQPMZh7k/bnvZTnXRGfE2KuvXf1EEjt/ofD9yw9IumpgdP9QCnw==" + "resolved": "10.0.8", + "contentHash": "OBPo4nYhMyIbtueoC10CBm6AGAbo/A9IV8QQ/6ryZS7VvmqpGT7hunazeHLxFawRzn3oLOq4jhqhpBX4tfswWQ==" }, "Microsoft.Win32.SystemEvents": { "type": "Transitive", - "resolved": "10.0.7", - "contentHash": "yRy88RjP9RlFxiaxwkGSh5e7lhSRCUaSwYW323ssK85XTm13b3y65Yp8HuURXNnxGQGo9L4Bz19aQAbrfTyJqA==" + "resolved": "10.0.8", + "contentHash": "J9+VT0lkrA7wW38CGxO2sZd+iH9C0qzioMi/2ztpT32WOVr+04uNqFIrxisTRf+mvtXLtdqcio1AoS0vfAVLLQ==" }, "Microsoft.Windows.AI.MachineLearning": { "type": "Transitive", - "resolved": "2.0.300", - "contentHash": "OiJX15N198kG30Lop7LH8WjmBfk2/9iU9it9eLPnkNZ49Yi/vAa4ntONGiGOgv5mb8/fvFHV5trCWSPM+OQhSw==", + "resolved": "2.1.1", + "contentHash": "A5BbYPLVrcaRJvpwx0nv7aMDOMqR20qaw9EaLcUe9pkSArzKoSk6cilRsSioU+eRa9+HahidBZTegawdswKqIQ==", "dependencies": { "System.Numerics.Tensors": "9.0.0" } @@ -322,17 +319,17 @@ }, "Microsoft.WindowsAppSDK.AI": { "type": "Transitive", - "resolved": "2.0.185", - "contentHash": "KkWthQS+QuiTQJ8HgSpobUgfJDRUAwps0/1MjYM3wZ/hQzSKr1UoyiYLgk/I8Z2I+/NNphbZ9NsY7DwHKrZJlg==", + "resolved": "2.1.10", + "contentHash": "4rOxfQbOZkdGK/wzajqyXZeCl9WW1qdtb63hTBFEA7pZ14iyF3iV64VNg6KOXuRRUL64/wyHHsiBwLlvFSFgcw==", "dependencies": { - "Microsoft.WindowsAppSDK.Base": "2.0.3", - "Microsoft.WindowsAppSDK.Foundation": "2.0.19" + "Microsoft.WindowsAppSDK.Base": "2.0.4", + "Microsoft.WindowsAppSDK.Foundation": "2.0.21" } }, "Microsoft.WindowsAppSDK.Base": { "type": "Transitive", - "resolved": "2.0.3", - "contentHash": "UZIO8/Vk2FKONlKNM8ZyFLhkSZcMZSzFDVmmzZOCnOBcvxNwWRW/+klUlTEI8tLpPVHJTQUsZE677GaYyDzrHw==", + "resolved": "2.0.4", + "contentHash": "QXSy2llX2/Bx9dYWGUEsb10F40q94ZiDnPMzqa2/qRmTG4y9EXxGp6uHITb7c0b4FCa+6KFBlgh6D53M0QEMEg==", "dependencies": { "Microsoft.Windows.SDK.BuildTools": "10.0.26100.4654", "Microsoft.Windows.SDK.BuildTools.MSIX": "1.7.251221100" @@ -340,75 +337,70 @@ }, "Microsoft.WindowsAppSDK.DWrite": { "type": "Transitive", - "resolved": "2.0.26041403", - "contentHash": "iClF//qwKk82OWR84acdTezu9euInOYo6QvtFz/IobfbpWBLfXA4mjbu5DpK03z/BF8hHG7COIwvJ+D/5iNvsg==", + "resolved": "2.1.0", + "contentHash": "dgix7NSeo7Z8SZPyrsOqYm/6OUvBveHCiVyorYecmtDYoZW26dJ6/i9yveIxgWvmFpgfKXPeIuQBCvhbetHiYg==", "dependencies": { "Microsoft.WindowsAppSDK.Base": "2.0.3" } }, "Microsoft.WindowsAppSDK.Foundation": { "type": "Transitive", - "resolved": "2.0.20", - "contentHash": "PwoRG/eddoi9SOSVPyanei5WAHMyAeVFAeqcovd0V0Ebx6dw7S+ksVVGThAoMjrRI6f93Fa6mTmwXqFHExOtlw==", + "resolved": "2.0.21", + "contentHash": "Wzr4c9dSXXcNQw67wVmy+32FXW6+TLyrQHD5eZXAjNydMsLRMZjUXzD1qQgBg1bdgzjlkYnOyYqoXbOL6lfqkw==", "dependencies": { - "Microsoft.WindowsAppSDK.Base": "2.0.3", - "Microsoft.WindowsAppSDK.InteractiveExperiences": "2.0.12" + "Microsoft.WindowsAppSDK.Base": "2.0.4", + "Microsoft.WindowsAppSDK.InteractiveExperiences": "2.0.13" } }, "Microsoft.WindowsAppSDK.InteractiveExperiences": { "type": "Transitive", - "resolved": "2.0.12", - "contentHash": "uGNDuIhBHTO1azsa0SCO6/h/0JBVKqoKiJA0K8JSgrlGeC5Lx7g0xppS8aOF/aTnOPSR9BIEHWRvH9JldWTbBg==", + "resolved": "2.0.13", + "contentHash": "jxzb2F0thCzUhxX3EMthKyxMaWINGSAf1/uMfS3pyCODCzHoR39LUQE22DZDAmMJEM4pebCnIj2PYRQjSuy65Q==", "dependencies": { "Microsoft.WindowsAppSDK.Base": "2.0.3" } }, "Microsoft.WindowsAppSDK.ML": { "type": "Transitive", - "resolved": "2.0.300", - "contentHash": "3/PInpjZozhI+KryPO2b3gZVNyFVOd5qSBhiGW/qFo2VzKQCMc0+cyaCPVm8uhfm3jqgYjQ4g/EqHFA5gJIaoQ==", + "resolved": "2.1.1", + "contentHash": "q+luYBGlPdzMwhOsZCUmWbIZMvmc0pn5+nBvrKyQzvd/mC2+YBEaqfN2/zkfkFKsmJUuPvnG73RouAP/1oKPaA==", "dependencies": { - "Microsoft.Windows.AI.MachineLearning": "[2.0.300, 3.0.0)", - "Microsoft.WindowsAppSDK.Base": "2.0.3", - "Microsoft.WindowsAppSDK.Foundation": "2.0.19" + "Microsoft.Windows.AI.MachineLearning": "[2.1.1, 3.0.0)", + "Microsoft.WindowsAppSDK.Base": "2.0.4", + "Microsoft.WindowsAppSDK.Foundation": "2.0.21" } }, "Microsoft.WindowsAppSDK.Runtime": { "type": "Transitive", - "resolved": "2.0.1", - "contentHash": "auDu0gwvIrxM1gbOJsRiyRJHHeFaAC9ORO4EppreRQEeD+BteTdl6Z/bP4aUgmUimrr7gOQQ87iLcQOsahbvSQ==", + "resolved": "2.1.3", + "contentHash": "dbddzTTnePoiFEw2h9QeGxJ8jyFtx7OEMIt053vjd/FQU4hzdnK9/LGPF5cwCkCD8gLvrXqyfR8AhCjz5Ni9sQ==", "dependencies": { - "Microsoft.WindowsAppSDK.Base": "2.0.3" + "Microsoft.WindowsAppSDK.Base": "2.0.4" } }, "Microsoft.WindowsAppSDK.Widgets": { "type": "Transitive", - "resolved": "2.0.4", - "contentHash": "gvfIHLmQKBQ+KQKrWb+Oc+eQEZtpKx2zHQDBzFF7Tio+SDkXtaONU4nvHgaqcnkbqNpDPPT/pYIr7UaI51vNEQ==", + "resolved": "2.0.5", + "contentHash": "lRz+8+QU65gV8hRzLVE+GRsPKZ42lnzqkmsw96HzQd/DuFYfr4JYpUU7ZZ5YrkV2EfQe4BCmoRKAeZ3WwalMcg==", "dependencies": { "Microsoft.WindowsAppSDK.Base": "2.0.3" } }, "Microsoft.WindowsAppSDK.WinUI": { "type": "Transitive", - "resolved": "2.0.12", - "contentHash": "qNyajFTgO9xuxKtcs7vLqg7NLSuZK5+EUKeRh6fHQ9Da8hhmymoKci/srxyQwyLkFOXRL7nnuoxovUpzNjlsCg==", + "resolved": "2.1.0", + "contentHash": "HXFdlOESmUM7RPPWO5z4lpJX7zIPhDDPngfEP1itAUG/1SWFWKxYdEpt6nciMGITj92OpSK70R8/h06j5tfhIg==", "dependencies": { "Microsoft.Web.WebView2": "1.0.3719.77", - "Microsoft.WindowsAppSDK.Base": "2.0.3", - "Microsoft.WindowsAppSDK.Foundation": "2.0.20", - "Microsoft.WindowsAppSDK.InteractiveExperiences": "2.0.12" + "Microsoft.WindowsAppSDK.Base": "2.0.4", + "Microsoft.WindowsAppSDK.Foundation": "2.0.21", + "Microsoft.WindowsAppSDK.InteractiveExperiences": "2.0.13" } }, - "NuGet.Versioning": { - "type": "Transitive", - "resolved": "6.14.0", - "contentHash": "4v4blkhCv8mpKtfx+z0G/X0daVCzdIaHSC51GkUspugi5JIMn2Bo8xm5PdZYF0U68gOBfz/+aPWMnpRd85Jbow==" - }, "Sentry": { "type": "Transitive", - "resolved": "6.5.0", - "contentHash": "EuC4Da4WcC8eE8d+AHoDGLK0wfyrQ/OYeNghDnR9dc3q/jDUadqXsJtEsq8U9Dt+VG6lCg0K8AoksheCVe3q8w==" + "resolved": "6.6.0", + "contentHash": "1D3xo3P9Y94VQN3RoV/86XqgtylHp1pdeEml3/UB649BrzJeZ/pqO/o8YgJ5g+GqpMQiGI09yjAI7s5ff2A1IA==" }, "SharpHDiffPatch.Core": { "type": "Transitive", @@ -421,16 +413,16 @@ }, "System.Drawing.Common": { "type": "Transitive", - "resolved": "10.0.7", - "contentHash": "t0dLoUJOFMMyHqwpDuTKVlKVry92yUhf7qwihVT2MUrg3y/ZOHKpij5nb+jb20UT3vc7UlQWQlNmV9NQ5c7aSA==", + "resolved": "10.0.8", + "contentHash": "LCISd6JAF80vsy9L6wuetZeOMR3FH+SwKovw5Zl0Nov9pB9ZOiCSqvOfMzooypPItQLv0mGfEePjJ1nCCQztNw==", "dependencies": { - "Microsoft.Win32.SystemEvents": "10.0.7" + "Microsoft.Win32.SystemEvents": "10.0.8" } }, "System.IO.Hashing": { "type": "Transitive", - "resolved": "10.0.7", - "contentHash": "6hsjdSr4VOXSOnhALkYplHpAxnTG1J33YN42IB6nH2fEg4QnJqrZ4Ft+qn7mkrKAOYC8pCSFYwVWw6rQbmwgLQ==" + "resolved": "10.0.8", + "contentHash": "+dJsbPJ3FyUbTZNplFj0RCKePFizmv6ewDV46JE9q/IVH4c3xTCftHfHelLsAKf0jryIPqgMb5GpS0x7TAY3mg==" }, "System.Numerics.Tensors": { "type": "Transitive", @@ -445,33 +437,33 @@ "colorthief": { "type": "Project", "dependencies": { - "System.Drawing.Common": "[10.0.7, )" + "System.Drawing.Common": "[10.0.8, )" } }, "discordrpc": { "type": "Project", "dependencies": { - "Microsoft.Extensions.Logging": "[10.0.7, )" + "Microsoft.Extensions.Logging": "[10.0.8, )" } }, "h.generatedicons.system.drawing": { "type": "Project", "dependencies": { - "System.Drawing.Common": "[10.0.7, )" + "System.Drawing.Common": "[10.0.8, )" } }, "h.notifyicon": { "type": "Project", "dependencies": { "H.GeneratedIcons.System.Drawing": "[1.0.0, )", - "Microsoft.Extensions.Logging": "[10.0.7, )" + "Microsoft.Extensions.Logging": "[10.0.8, )" } }, "h.notifyicon.winui": { "type": "Project", "dependencies": { "H.NotifyIcon": "[1.0.0, )", - "Microsoft.WindowsAppSDK": "[2.0.1, )" + "Microsoft.WindowsAppSDK": "[2.1.3, )" } }, "hi3helper.core": { @@ -480,16 +472,16 @@ "Hi3Helper.EncTool": "[1.0.0, )", "Hi3Helper.Win32": "[1.0.0, )", "Microsoft.Windows.CsWinRT": "[2.3.0-prerelease.251115.2, )", - "Sentry": "[6.5.0, )" + "Sentry": "[6.6.0, )" } }, "hi3helper.enctool": { "type": "Project", "dependencies": { - "Google.Protobuf": "[3.34.1, )", + "Google.Protobuf": "[3.35.0, )", "Hi3Helper.Http": "[2.0.0, )", "Hi3Helper.Win32": "[1.0.0, )", - "System.IO.Hashing": "[10.0.7, )" + "System.IO.Hashing": "[10.0.8, )" } }, "hi3helper.http": { @@ -498,7 +490,7 @@ "hi3helper.plugin.core": { "type": "Project", "dependencies": { - "Microsoft.Extensions.Logging.Abstractions": "[10.0.7, )" + "Microsoft.Extensions.Logging.Abstractions": "[10.0.8, )" } }, "hi3helper.simpleziparchivereader": { @@ -507,23 +499,23 @@ "hi3helper.sophon": { "type": "Project", "dependencies": { - "Google.Protobuf": "[3.34.1, )", + "Google.Protobuf": "[3.35.0, )", "Hi3Helper.ZstdNet": "[*, )", "SharpHDiffPatch.Core": "[*, )", - "System.IO.Hashing": "[10.0.7, )" + "System.IO.Hashing": "[10.0.8, )" } }, "hi3helper.win32": { "type": "Project", "dependencies": { - "Microsoft.Extensions.Logging.Abstractions": "[10.0.7, )" + "Microsoft.Extensions.Logging.Abstractions": "[10.0.8, )" } }, "hi3helper.win32.winrt": { "type": "Project", "dependencies": { "Hi3Helper.Win32": "[1.0.0, )", - "Microsoft.Extensions.Logging.Abstractions": "[10.0.7, )", + "Microsoft.Extensions.Logging.Abstractions": "[10.0.8, )", "Microsoft.Windows.CsWinRT": "[2.3.0-prerelease.251115.2, )" } }, @@ -536,7 +528,7 @@ "Microsoft.Graphics.Win2D": "[1.4.0, )", "Microsoft.Windows.CsWinRT": "[2.3.0-prerelease.251115.2, )", "Microsoft.Windows.SDK.BuildTools": "[10.0.28000.1839, )", - "Microsoft.WindowsAppSDK": "[2.0.1, )" + "Microsoft.WindowsAppSDK": "[2.1.3, )" } }, "imageex": { @@ -545,13 +537,13 @@ "CommunityToolkit.Common": "[8.4.2, )", "CommunityToolkit.WinUI.Extensions": "[8.2.251219, )", "Microsoft.Windows.SDK.BuildTools": "[10.0.28000.1839, )", - "Microsoft.WindowsAppSDK": "[2.0.1, )" + "Microsoft.WindowsAppSDK": "[2.1.3, )" } }, "innosetuphelper": { "type": "Project", "dependencies": { - "System.IO.Hashing": "[10.0.7, )" + "System.IO.Hashing": "[10.0.8, )" } }, "SettingsControls": { @@ -561,7 +553,7 @@ "CommunityToolkit.WinUI.Triggers": "[8.2.251219, )", "Microsoft.Windows.CsWinRT": "[2.3.0-prerelease.251115.2, )", "Microsoft.Windows.SDK.BuildTools": "[10.0.28000.1839, )", - "Microsoft.WindowsAppSDK": "[2.0.1, )" + "Microsoft.WindowsAppSDK": "[2.1.3, )" } }, "sevenzipextractor": { @@ -586,9 +578,9 @@ }, "Microsoft.Web.WebView2": { "type": "Direct", - "requested": "[1.0.3912.50, )", - "resolved": "1.0.3912.50", - "contentHash": "mEIKZDSmb6CxGWKoxaxTSJ0yi0DD2zp29TA7kJY2GdanuH3c5aYruwfqsm3OsYn/h2hUhybQZvfbxyZe4O+X4Q==" + "requested": "[1.0.3967.48, )", + "resolved": "1.0.3967.48", + "contentHash": "b7dZ5kZ9bfU5Yo11M8feCOoiyalXCN+2Gsw674RBDBmQ2dJV5EOXb8/ivN2LuLJ+VO2V7FmK6l6LsyfEnG1lXw==" }, "PhotoSauce.NativeCodecs.Libwebp": { "type": "Direct", @@ -601,24 +593,24 @@ }, "Microsoft.Win32.SystemEvents": { "type": "Transitive", - "resolved": "10.0.7", - "contentHash": "yRy88RjP9RlFxiaxwkGSh5e7lhSRCUaSwYW323ssK85XTm13b3y65Yp8HuURXNnxGQGo9L4Bz19aQAbrfTyJqA==" + "resolved": "10.0.8", + "contentHash": "J9+VT0lkrA7wW38CGxO2sZd+iH9C0qzioMi/2ztpT32WOVr+04uNqFIrxisTRf+mvtXLtdqcio1AoS0vfAVLLQ==" }, "Microsoft.Windows.AI.MachineLearning": { "type": "Transitive", - "resolved": "2.0.300", - "contentHash": "OiJX15N198kG30Lop7LH8WjmBfk2/9iU9it9eLPnkNZ49Yi/vAa4ntONGiGOgv5mb8/fvFHV5trCWSPM+OQhSw==", + "resolved": "2.1.1", + "contentHash": "A5BbYPLVrcaRJvpwx0nv7aMDOMqR20qaw9EaLcUe9pkSArzKoSk6cilRsSioU+eRa9+HahidBZTegawdswKqIQ==", "dependencies": { "System.Numerics.Tensors": "9.0.0" } }, "Microsoft.WindowsAppSDK.Foundation": { "type": "Transitive", - "resolved": "2.0.20", - "contentHash": "PwoRG/eddoi9SOSVPyanei5WAHMyAeVFAeqcovd0V0Ebx6dw7S+ksVVGThAoMjrRI6f93Fa6mTmwXqFHExOtlw==", + "resolved": "2.0.21", + "contentHash": "Wzr4c9dSXXcNQw67wVmy+32FXW6+TLyrQHD5eZXAjNydMsLRMZjUXzD1qQgBg1bdgzjlkYnOyYqoXbOL6lfqkw==", "dependencies": { - "Microsoft.WindowsAppSDK.Base": "2.0.3", - "Microsoft.WindowsAppSDK.InteractiveExperiences": "2.0.12" + "Microsoft.WindowsAppSDK.Base": "2.0.4", + "Microsoft.WindowsAppSDK.InteractiveExperiences": "2.0.13" } } } diff --git a/ColorThief b/ColorThief index 1972a9c7fd..238893b1fa 160000 --- a/ColorThief +++ b/ColorThief @@ -1 +1 @@ -Subproject commit 1972a9c7fddd77c50da381860d5280733f5c33cb +Subproject commit 238893b1fa321d0303b421edb5b5982d61456204 diff --git a/H.NotifyIcon b/H.NotifyIcon index 0edb6711d4..1cc422ef6e 160000 --- a/H.NotifyIcon +++ b/H.NotifyIcon @@ -1 +1 @@ -Subproject commit 0edb6711d4b601e8659910b39671c91d86dc07c7 +Subproject commit 1cc422ef6e18e2674fd2c34217fea1b52865bfbf diff --git a/Hi3Helper.CommunityToolkit/ImageCropper/Hi3Helper.CommunityToolkit.WinUI.Controls.ImageCropper.csproj b/Hi3Helper.CommunityToolkit/ImageCropper/Hi3Helper.CommunityToolkit.WinUI.Controls.ImageCropper.csproj index e544a13a12..8b341ded03 100644 --- a/Hi3Helper.CommunityToolkit/ImageCropper/Hi3Helper.CommunityToolkit.WinUI.Controls.ImageCropper.csproj +++ b/Hi3Helper.CommunityToolkit/ImageCropper/Hi3Helper.CommunityToolkit.WinUI.Controls.ImageCropper.csproj @@ -35,7 +35,7 @@ - + diff --git a/Hi3Helper.CommunityToolkit/ImageCropper/packages.lock.json b/Hi3Helper.CommunityToolkit/ImageCropper/packages.lock.json index d66f3d1326..5c2e36b4b1 100644 --- a/Hi3Helper.CommunityToolkit/ImageCropper/packages.lock.json +++ b/Hi3Helper.CommunityToolkit/ImageCropper/packages.lock.json @@ -41,9 +41,9 @@ }, "Microsoft.NET.ILLink.Tasks": { "type": "Direct", - "requested": "[10.0.7, )", - "resolved": "10.0.7", - "contentHash": "AA/yhzFHNtQZXLdqjzujPy25G8EWwGWsAnxOE2zYSBoT/8QHP6ketN3CToD3DFreO653ipUwnKHo22B8AlBMCw==" + "requested": "[10.0.8, )", + "resolved": "10.0.8", + "contentHash": "dVbSXGIFNR5nZcv2tOLoWI+a9T4jtFd77IYjuND+QVe360qWgAF7H0WtoopYhRw/+SgpGUTyrkrh+65+ClNnfw==" }, "Microsoft.Windows.CsWinRT": { "type": "Direct", @@ -59,19 +59,19 @@ }, "Microsoft.WindowsAppSDK": { "type": "Direct", - "requested": "[2.0.1, )", - "resolved": "2.0.1", - "contentHash": "R+iN0mqIUUppbzpHU178R5malnttTTVBOBIGi1NQVVZAs34bAANM/iLJhjj6uUBgYiPfpvjcLbHT5IZ8kKKaqg==", + "requested": "[2.1.3, )", + "resolved": "2.1.3", + "contentHash": "46KCntcmWPS0nbV3a8iEMslpYy0W9wTsmkANrXFxDWuiAnm8jXytFNvwNVN5HfoA3d+Cxb3pO+JE2UNnB5wn7w==", "dependencies": { - "Microsoft.WindowsAppSDK.AI": "2.0.185", - "Microsoft.WindowsAppSDK.Base": "2.0.3", - "Microsoft.WindowsAppSDK.DWrite": "2.0.26041403", - "Microsoft.WindowsAppSDK.Foundation": "2.0.20", - "Microsoft.WindowsAppSDK.InteractiveExperiences": "2.0.12", - "Microsoft.WindowsAppSDK.ML": "2.0.300", - "Microsoft.WindowsAppSDK.Runtime": "[2.0.1]", - "Microsoft.WindowsAppSDK.Widgets": "2.0.4", - "Microsoft.WindowsAppSDK.WinUI": "2.0.12" + "Microsoft.WindowsAppSDK.AI": "2.1.10", + "Microsoft.WindowsAppSDK.Base": "2.0.4", + "Microsoft.WindowsAppSDK.DWrite": "2.1.0", + "Microsoft.WindowsAppSDK.Foundation": "2.0.21", + "Microsoft.WindowsAppSDK.InteractiveExperiences": "2.0.13", + "Microsoft.WindowsAppSDK.ML": "2.1.1", + "Microsoft.WindowsAppSDK.Runtime": "[2.1.3]", + "Microsoft.WindowsAppSDK.Widgets": "2.0.5", + "Microsoft.WindowsAppSDK.WinUI": "2.1.0" } }, "CommunityToolkit.WinUI.Animations": { @@ -90,8 +90,8 @@ }, "Microsoft.Windows.AI.MachineLearning": { "type": "Transitive", - "resolved": "2.0.300", - "contentHash": "OiJX15N198kG30Lop7LH8WjmBfk2/9iU9it9eLPnkNZ49Yi/vAa4ntONGiGOgv5mb8/fvFHV5trCWSPM+OQhSw==", + "resolved": "2.1.1", + "contentHash": "A5BbYPLVrcaRJvpwx0nv7aMDOMqR20qaw9EaLcUe9pkSArzKoSk6cilRsSioU+eRa9+HahidBZTegawdswKqIQ==", "dependencies": { "System.Numerics.Tensors": "9.0.0" } @@ -103,17 +103,17 @@ }, "Microsoft.WindowsAppSDK.AI": { "type": "Transitive", - "resolved": "2.0.185", - "contentHash": "KkWthQS+QuiTQJ8HgSpobUgfJDRUAwps0/1MjYM3wZ/hQzSKr1UoyiYLgk/I8Z2I+/NNphbZ9NsY7DwHKrZJlg==", + "resolved": "2.1.10", + "contentHash": "4rOxfQbOZkdGK/wzajqyXZeCl9WW1qdtb63hTBFEA7pZ14iyF3iV64VNg6KOXuRRUL64/wyHHsiBwLlvFSFgcw==", "dependencies": { - "Microsoft.WindowsAppSDK.Base": "2.0.3", - "Microsoft.WindowsAppSDK.Foundation": "2.0.19" + "Microsoft.WindowsAppSDK.Base": "2.0.4", + "Microsoft.WindowsAppSDK.Foundation": "2.0.21" } }, "Microsoft.WindowsAppSDK.Base": { "type": "Transitive", - "resolved": "2.0.3", - "contentHash": "UZIO8/Vk2FKONlKNM8ZyFLhkSZcMZSzFDVmmzZOCnOBcvxNwWRW/+klUlTEI8tLpPVHJTQUsZE677GaYyDzrHw==", + "resolved": "2.0.4", + "contentHash": "QXSy2llX2/Bx9dYWGUEsb10F40q94ZiDnPMzqa2/qRmTG4y9EXxGp6uHITb7c0b4FCa+6KFBlgh6D53M0QEMEg==", "dependencies": { "Microsoft.Windows.SDK.BuildTools": "10.0.26100.4654", "Microsoft.Windows.SDK.BuildTools.MSIX": "1.7.251221100" @@ -121,64 +121,64 @@ }, "Microsoft.WindowsAppSDK.DWrite": { "type": "Transitive", - "resolved": "2.0.26041403", - "contentHash": "iClF//qwKk82OWR84acdTezu9euInOYo6QvtFz/IobfbpWBLfXA4mjbu5DpK03z/BF8hHG7COIwvJ+D/5iNvsg==", + "resolved": "2.1.0", + "contentHash": "dgix7NSeo7Z8SZPyrsOqYm/6OUvBveHCiVyorYecmtDYoZW26dJ6/i9yveIxgWvmFpgfKXPeIuQBCvhbetHiYg==", "dependencies": { "Microsoft.WindowsAppSDK.Base": "2.0.3" } }, "Microsoft.WindowsAppSDK.Foundation": { "type": "Transitive", - "resolved": "2.0.20", - "contentHash": "PwoRG/eddoi9SOSVPyanei5WAHMyAeVFAeqcovd0V0Ebx6dw7S+ksVVGThAoMjrRI6f93Fa6mTmwXqFHExOtlw==", + "resolved": "2.0.21", + "contentHash": "Wzr4c9dSXXcNQw67wVmy+32FXW6+TLyrQHD5eZXAjNydMsLRMZjUXzD1qQgBg1bdgzjlkYnOyYqoXbOL6lfqkw==", "dependencies": { - "Microsoft.WindowsAppSDK.Base": "2.0.3", - "Microsoft.WindowsAppSDK.InteractiveExperiences": "2.0.12" + "Microsoft.WindowsAppSDK.Base": "2.0.4", + "Microsoft.WindowsAppSDK.InteractiveExperiences": "2.0.13" } }, "Microsoft.WindowsAppSDK.InteractiveExperiences": { "type": "Transitive", - "resolved": "2.0.12", - "contentHash": "uGNDuIhBHTO1azsa0SCO6/h/0JBVKqoKiJA0K8JSgrlGeC5Lx7g0xppS8aOF/aTnOPSR9BIEHWRvH9JldWTbBg==", + "resolved": "2.0.13", + "contentHash": "jxzb2F0thCzUhxX3EMthKyxMaWINGSAf1/uMfS3pyCODCzHoR39LUQE22DZDAmMJEM4pebCnIj2PYRQjSuy65Q==", "dependencies": { "Microsoft.WindowsAppSDK.Base": "2.0.3" } }, "Microsoft.WindowsAppSDK.ML": { "type": "Transitive", - "resolved": "2.0.300", - "contentHash": "3/PInpjZozhI+KryPO2b3gZVNyFVOd5qSBhiGW/qFo2VzKQCMc0+cyaCPVm8uhfm3jqgYjQ4g/EqHFA5gJIaoQ==", + "resolved": "2.1.1", + "contentHash": "q+luYBGlPdzMwhOsZCUmWbIZMvmc0pn5+nBvrKyQzvd/mC2+YBEaqfN2/zkfkFKsmJUuPvnG73RouAP/1oKPaA==", "dependencies": { - "Microsoft.Windows.AI.MachineLearning": "[2.0.300, 3.0.0)", - "Microsoft.WindowsAppSDK.Base": "2.0.3", - "Microsoft.WindowsAppSDK.Foundation": "2.0.19" + "Microsoft.Windows.AI.MachineLearning": "[2.1.1, 3.0.0)", + "Microsoft.WindowsAppSDK.Base": "2.0.4", + "Microsoft.WindowsAppSDK.Foundation": "2.0.21" } }, "Microsoft.WindowsAppSDK.Runtime": { "type": "Transitive", - "resolved": "2.0.1", - "contentHash": "auDu0gwvIrxM1gbOJsRiyRJHHeFaAC9ORO4EppreRQEeD+BteTdl6Z/bP4aUgmUimrr7gOQQ87iLcQOsahbvSQ==", + "resolved": "2.1.3", + "contentHash": "dbddzTTnePoiFEw2h9QeGxJ8jyFtx7OEMIt053vjd/FQU4hzdnK9/LGPF5cwCkCD8gLvrXqyfR8AhCjz5Ni9sQ==", "dependencies": { - "Microsoft.WindowsAppSDK.Base": "2.0.3" + "Microsoft.WindowsAppSDK.Base": "2.0.4" } }, "Microsoft.WindowsAppSDK.Widgets": { "type": "Transitive", - "resolved": "2.0.4", - "contentHash": "gvfIHLmQKBQ+KQKrWb+Oc+eQEZtpKx2zHQDBzFF7Tio+SDkXtaONU4nvHgaqcnkbqNpDPPT/pYIr7UaI51vNEQ==", + "resolved": "2.0.5", + "contentHash": "lRz+8+QU65gV8hRzLVE+GRsPKZ42lnzqkmsw96HzQd/DuFYfr4JYpUU7ZZ5YrkV2EfQe4BCmoRKAeZ3WwalMcg==", "dependencies": { "Microsoft.WindowsAppSDK.Base": "2.0.3" } }, "Microsoft.WindowsAppSDK.WinUI": { "type": "Transitive", - "resolved": "2.0.12", - "contentHash": "qNyajFTgO9xuxKtcs7vLqg7NLSuZK5+EUKeRh6fHQ9Da8hhmymoKci/srxyQwyLkFOXRL7nnuoxovUpzNjlsCg==", + "resolved": "2.1.0", + "contentHash": "HXFdlOESmUM7RPPWO5z4lpJX7zIPhDDPngfEP1itAUG/1SWFWKxYdEpt6nciMGITj92OpSK70R8/h06j5tfhIg==", "dependencies": { "Microsoft.Web.WebView2": "1.0.3719.77", - "Microsoft.WindowsAppSDK.Base": "2.0.3", - "Microsoft.WindowsAppSDK.Foundation": "2.0.20", - "Microsoft.WindowsAppSDK.InteractiveExperiences": "2.0.12" + "Microsoft.WindowsAppSDK.Base": "2.0.4", + "Microsoft.WindowsAppSDK.Foundation": "2.0.21", + "Microsoft.WindowsAppSDK.InteractiveExperiences": "2.0.13" } }, "System.Numerics.Tensors": { @@ -204,19 +204,19 @@ }, "Microsoft.Windows.AI.MachineLearning": { "type": "Transitive", - "resolved": "2.0.300", - "contentHash": "OiJX15N198kG30Lop7LH8WjmBfk2/9iU9it9eLPnkNZ49Yi/vAa4ntONGiGOgv5mb8/fvFHV5trCWSPM+OQhSw==", + "resolved": "2.1.1", + "contentHash": "A5BbYPLVrcaRJvpwx0nv7aMDOMqR20qaw9EaLcUe9pkSArzKoSk6cilRsSioU+eRa9+HahidBZTegawdswKqIQ==", "dependencies": { "System.Numerics.Tensors": "9.0.0" } }, "Microsoft.WindowsAppSDK.Foundation": { "type": "Transitive", - "resolved": "2.0.20", - "contentHash": "PwoRG/eddoi9SOSVPyanei5WAHMyAeVFAeqcovd0V0Ebx6dw7S+ksVVGThAoMjrRI6f93Fa6mTmwXqFHExOtlw==", + "resolved": "2.0.21", + "contentHash": "Wzr4c9dSXXcNQw67wVmy+32FXW6+TLyrQHD5eZXAjNydMsLRMZjUXzD1qQgBg1bdgzjlkYnOyYqoXbOL6lfqkw==", "dependencies": { - "Microsoft.WindowsAppSDK.Base": "2.0.3", - "Microsoft.WindowsAppSDK.InteractiveExperiences": "2.0.12" + "Microsoft.WindowsAppSDK.Base": "2.0.4", + "Microsoft.WindowsAppSDK.InteractiveExperiences": "2.0.13" } } } diff --git a/Hi3Helper.CommunityToolkit/SettingsControls/Hi3Helper.CommunityToolkit.WinUI.Controls.SettingsControls.csproj b/Hi3Helper.CommunityToolkit/SettingsControls/Hi3Helper.CommunityToolkit.WinUI.Controls.SettingsControls.csproj index b0bf04700b..fdb66e02bc 100644 --- a/Hi3Helper.CommunityToolkit/SettingsControls/Hi3Helper.CommunityToolkit.WinUI.Controls.SettingsControls.csproj +++ b/Hi3Helper.CommunityToolkit/SettingsControls/Hi3Helper.CommunityToolkit.WinUI.Controls.SettingsControls.csproj @@ -35,7 +35,7 @@ - + diff --git a/Hi3Helper.CommunityToolkit/SettingsControls/packages.lock.json b/Hi3Helper.CommunityToolkit/SettingsControls/packages.lock.json index 12040d4ac7..061589d54d 100644 --- a/Hi3Helper.CommunityToolkit/SettingsControls/packages.lock.json +++ b/Hi3Helper.CommunityToolkit/SettingsControls/packages.lock.json @@ -20,9 +20,9 @@ }, "Microsoft.NET.ILLink.Tasks": { "type": "Direct", - "requested": "[10.0.7, )", - "resolved": "10.0.7", - "contentHash": "AA/yhzFHNtQZXLdqjzujPy25G8EWwGWsAnxOE2zYSBoT/8QHP6ketN3CToD3DFreO653ipUwnKHo22B8AlBMCw==" + "requested": "[10.0.8, )", + "resolved": "10.0.8", + "contentHash": "dVbSXGIFNR5nZcv2tOLoWI+a9T4jtFd77IYjuND+QVe360qWgAF7H0WtoopYhRw/+SgpGUTyrkrh+65+ClNnfw==" }, "Microsoft.Windows.CsWinRT": { "type": "Direct", @@ -38,19 +38,19 @@ }, "Microsoft.WindowsAppSDK": { "type": "Direct", - "requested": "[2.0.1, )", - "resolved": "2.0.1", - "contentHash": "R+iN0mqIUUppbzpHU178R5malnttTTVBOBIGi1NQVVZAs34bAANM/iLJhjj6uUBgYiPfpvjcLbHT5IZ8kKKaqg==", + "requested": "[2.1.3, )", + "resolved": "2.1.3", + "contentHash": "46KCntcmWPS0nbV3a8iEMslpYy0W9wTsmkANrXFxDWuiAnm8jXytFNvwNVN5HfoA3d+Cxb3pO+JE2UNnB5wn7w==", "dependencies": { - "Microsoft.WindowsAppSDK.AI": "2.0.185", - "Microsoft.WindowsAppSDK.Base": "2.0.3", - "Microsoft.WindowsAppSDK.DWrite": "2.0.26041403", - "Microsoft.WindowsAppSDK.Foundation": "2.0.20", - "Microsoft.WindowsAppSDK.InteractiveExperiences": "2.0.12", - "Microsoft.WindowsAppSDK.ML": "2.0.300", - "Microsoft.WindowsAppSDK.Runtime": "[2.0.1]", - "Microsoft.WindowsAppSDK.Widgets": "2.0.4", - "Microsoft.WindowsAppSDK.WinUI": "2.0.12" + "Microsoft.WindowsAppSDK.AI": "2.1.10", + "Microsoft.WindowsAppSDK.Base": "2.0.4", + "Microsoft.WindowsAppSDK.DWrite": "2.1.0", + "Microsoft.WindowsAppSDK.Foundation": "2.0.21", + "Microsoft.WindowsAppSDK.InteractiveExperiences": "2.0.13", + "Microsoft.WindowsAppSDK.ML": "2.1.1", + "Microsoft.WindowsAppSDK.Runtime": "[2.1.3]", + "Microsoft.WindowsAppSDK.Widgets": "2.0.5", + "Microsoft.WindowsAppSDK.WinUI": "2.1.0" } }, "CommunityToolkit.WinUI.Extensions": { @@ -78,8 +78,8 @@ }, "Microsoft.Windows.AI.MachineLearning": { "type": "Transitive", - "resolved": "2.0.300", - "contentHash": "OiJX15N198kG30Lop7LH8WjmBfk2/9iU9it9eLPnkNZ49Yi/vAa4ntONGiGOgv5mb8/fvFHV5trCWSPM+OQhSw==", + "resolved": "2.1.1", + "contentHash": "A5BbYPLVrcaRJvpwx0nv7aMDOMqR20qaw9EaLcUe9pkSArzKoSk6cilRsSioU+eRa9+HahidBZTegawdswKqIQ==", "dependencies": { "System.Numerics.Tensors": "9.0.0" } @@ -91,17 +91,17 @@ }, "Microsoft.WindowsAppSDK.AI": { "type": "Transitive", - "resolved": "2.0.185", - "contentHash": "KkWthQS+QuiTQJ8HgSpobUgfJDRUAwps0/1MjYM3wZ/hQzSKr1UoyiYLgk/I8Z2I+/NNphbZ9NsY7DwHKrZJlg==", + "resolved": "2.1.10", + "contentHash": "4rOxfQbOZkdGK/wzajqyXZeCl9WW1qdtb63hTBFEA7pZ14iyF3iV64VNg6KOXuRRUL64/wyHHsiBwLlvFSFgcw==", "dependencies": { - "Microsoft.WindowsAppSDK.Base": "2.0.3", - "Microsoft.WindowsAppSDK.Foundation": "2.0.19" + "Microsoft.WindowsAppSDK.Base": "2.0.4", + "Microsoft.WindowsAppSDK.Foundation": "2.0.21" } }, "Microsoft.WindowsAppSDK.Base": { "type": "Transitive", - "resolved": "2.0.3", - "contentHash": "UZIO8/Vk2FKONlKNM8ZyFLhkSZcMZSzFDVmmzZOCnOBcvxNwWRW/+klUlTEI8tLpPVHJTQUsZE677GaYyDzrHw==", + "resolved": "2.0.4", + "contentHash": "QXSy2llX2/Bx9dYWGUEsb10F40q94ZiDnPMzqa2/qRmTG4y9EXxGp6uHITb7c0b4FCa+6KFBlgh6D53M0QEMEg==", "dependencies": { "Microsoft.Windows.SDK.BuildTools": "10.0.26100.4654", "Microsoft.Windows.SDK.BuildTools.MSIX": "1.7.251221100" @@ -109,64 +109,64 @@ }, "Microsoft.WindowsAppSDK.DWrite": { "type": "Transitive", - "resolved": "2.0.26041403", - "contentHash": "iClF//qwKk82OWR84acdTezu9euInOYo6QvtFz/IobfbpWBLfXA4mjbu5DpK03z/BF8hHG7COIwvJ+D/5iNvsg==", + "resolved": "2.1.0", + "contentHash": "dgix7NSeo7Z8SZPyrsOqYm/6OUvBveHCiVyorYecmtDYoZW26dJ6/i9yveIxgWvmFpgfKXPeIuQBCvhbetHiYg==", "dependencies": { "Microsoft.WindowsAppSDK.Base": "2.0.3" } }, "Microsoft.WindowsAppSDK.Foundation": { "type": "Transitive", - "resolved": "2.0.20", - "contentHash": "PwoRG/eddoi9SOSVPyanei5WAHMyAeVFAeqcovd0V0Ebx6dw7S+ksVVGThAoMjrRI6f93Fa6mTmwXqFHExOtlw==", + "resolved": "2.0.21", + "contentHash": "Wzr4c9dSXXcNQw67wVmy+32FXW6+TLyrQHD5eZXAjNydMsLRMZjUXzD1qQgBg1bdgzjlkYnOyYqoXbOL6lfqkw==", "dependencies": { - "Microsoft.WindowsAppSDK.Base": "2.0.3", - "Microsoft.WindowsAppSDK.InteractiveExperiences": "2.0.12" + "Microsoft.WindowsAppSDK.Base": "2.0.4", + "Microsoft.WindowsAppSDK.InteractiveExperiences": "2.0.13" } }, "Microsoft.WindowsAppSDK.InteractiveExperiences": { "type": "Transitive", - "resolved": "2.0.12", - "contentHash": "uGNDuIhBHTO1azsa0SCO6/h/0JBVKqoKiJA0K8JSgrlGeC5Lx7g0xppS8aOF/aTnOPSR9BIEHWRvH9JldWTbBg==", + "resolved": "2.0.13", + "contentHash": "jxzb2F0thCzUhxX3EMthKyxMaWINGSAf1/uMfS3pyCODCzHoR39LUQE22DZDAmMJEM4pebCnIj2PYRQjSuy65Q==", "dependencies": { "Microsoft.WindowsAppSDK.Base": "2.0.3" } }, "Microsoft.WindowsAppSDK.ML": { "type": "Transitive", - "resolved": "2.0.300", - "contentHash": "3/PInpjZozhI+KryPO2b3gZVNyFVOd5qSBhiGW/qFo2VzKQCMc0+cyaCPVm8uhfm3jqgYjQ4g/EqHFA5gJIaoQ==", + "resolved": "2.1.1", + "contentHash": "q+luYBGlPdzMwhOsZCUmWbIZMvmc0pn5+nBvrKyQzvd/mC2+YBEaqfN2/zkfkFKsmJUuPvnG73RouAP/1oKPaA==", "dependencies": { - "Microsoft.Windows.AI.MachineLearning": "[2.0.300, 3.0.0)", - "Microsoft.WindowsAppSDK.Base": "2.0.3", - "Microsoft.WindowsAppSDK.Foundation": "2.0.19" + "Microsoft.Windows.AI.MachineLearning": "[2.1.1, 3.0.0)", + "Microsoft.WindowsAppSDK.Base": "2.0.4", + "Microsoft.WindowsAppSDK.Foundation": "2.0.21" } }, "Microsoft.WindowsAppSDK.Runtime": { "type": "Transitive", - "resolved": "2.0.1", - "contentHash": "auDu0gwvIrxM1gbOJsRiyRJHHeFaAC9ORO4EppreRQEeD+BteTdl6Z/bP4aUgmUimrr7gOQQ87iLcQOsahbvSQ==", + "resolved": "2.1.3", + "contentHash": "dbddzTTnePoiFEw2h9QeGxJ8jyFtx7OEMIt053vjd/FQU4hzdnK9/LGPF5cwCkCD8gLvrXqyfR8AhCjz5Ni9sQ==", "dependencies": { - "Microsoft.WindowsAppSDK.Base": "2.0.3" + "Microsoft.WindowsAppSDK.Base": "2.0.4" } }, "Microsoft.WindowsAppSDK.Widgets": { "type": "Transitive", - "resolved": "2.0.4", - "contentHash": "gvfIHLmQKBQ+KQKrWb+Oc+eQEZtpKx2zHQDBzFF7Tio+SDkXtaONU4nvHgaqcnkbqNpDPPT/pYIr7UaI51vNEQ==", + "resolved": "2.0.5", + "contentHash": "lRz+8+QU65gV8hRzLVE+GRsPKZ42lnzqkmsw96HzQd/DuFYfr4JYpUU7ZZ5YrkV2EfQe4BCmoRKAeZ3WwalMcg==", "dependencies": { "Microsoft.WindowsAppSDK.Base": "2.0.3" } }, "Microsoft.WindowsAppSDK.WinUI": { "type": "Transitive", - "resolved": "2.0.12", - "contentHash": "qNyajFTgO9xuxKtcs7vLqg7NLSuZK5+EUKeRh6fHQ9Da8hhmymoKci/srxyQwyLkFOXRL7nnuoxovUpzNjlsCg==", + "resolved": "2.1.0", + "contentHash": "HXFdlOESmUM7RPPWO5z4lpJX7zIPhDDPngfEP1itAUG/1SWFWKxYdEpt6nciMGITj92OpSK70R8/h06j5tfhIg==", "dependencies": { "Microsoft.Web.WebView2": "1.0.3719.77", - "Microsoft.WindowsAppSDK.Base": "2.0.3", - "Microsoft.WindowsAppSDK.Foundation": "2.0.20", - "Microsoft.WindowsAppSDK.InteractiveExperiences": "2.0.12" + "Microsoft.WindowsAppSDK.Base": "2.0.4", + "Microsoft.WindowsAppSDK.Foundation": "2.0.21", + "Microsoft.WindowsAppSDK.InteractiveExperiences": "2.0.13" } }, "System.Numerics.Tensors": { @@ -183,19 +183,19 @@ }, "Microsoft.Windows.AI.MachineLearning": { "type": "Transitive", - "resolved": "2.0.300", - "contentHash": "OiJX15N198kG30Lop7LH8WjmBfk2/9iU9it9eLPnkNZ49Yi/vAa4ntONGiGOgv5mb8/fvFHV5trCWSPM+OQhSw==", + "resolved": "2.1.1", + "contentHash": "A5BbYPLVrcaRJvpwx0nv7aMDOMqR20qaw9EaLcUe9pkSArzKoSk6cilRsSioU+eRa9+HahidBZTegawdswKqIQ==", "dependencies": { "System.Numerics.Tensors": "9.0.0" } }, "Microsoft.WindowsAppSDK.Foundation": { "type": "Transitive", - "resolved": "2.0.20", - "contentHash": "PwoRG/eddoi9SOSVPyanei5WAHMyAeVFAeqcovd0V0Ebx6dw7S+ksVVGThAoMjrRI6f93Fa6mTmwXqFHExOtlw==", + "resolved": "2.0.21", + "contentHash": "Wzr4c9dSXXcNQw67wVmy+32FXW6+TLyrQHD5eZXAjNydMsLRMZjUXzD1qQgBg1bdgzjlkYnOyYqoXbOL6lfqkw==", "dependencies": { - "Microsoft.WindowsAppSDK.Base": "2.0.3", - "Microsoft.WindowsAppSDK.InteractiveExperiences": "2.0.12" + "Microsoft.WindowsAppSDK.Base": "2.0.4", + "Microsoft.WindowsAppSDK.InteractiveExperiences": "2.0.13" } } } diff --git a/Hi3Helper.Core/Hi3Helper.Core.csproj b/Hi3Helper.Core/Hi3Helper.Core.csproj index 83d594f017..37eb843417 100644 --- a/Hi3Helper.Core/Hi3Helper.Core.csproj +++ b/Hi3Helper.Core/Hi3Helper.Core.csproj @@ -43,7 +43,7 @@ - + diff --git a/Hi3Helper.Core/packages.lock.json b/Hi3Helper.Core/packages.lock.json index 6f3883f09c..2e6843dcc9 100644 --- a/Hi3Helper.Core/packages.lock.json +++ b/Hi3Helper.Core/packages.lock.json @@ -4,9 +4,9 @@ "net10.0-windows10.0.26100": { "Microsoft.NET.ILLink.Tasks": { "type": "Direct", - "requested": "[10.0.7, )", - "resolved": "10.0.7", - "contentHash": "AA/yhzFHNtQZXLdqjzujPy25G8EWwGWsAnxOE2zYSBoT/8QHP6ketN3CToD3DFreO653ipUwnKHo22B8AlBMCw==" + "requested": "[10.0.8, )", + "resolved": "10.0.8", + "contentHash": "dVbSXGIFNR5nZcv2tOLoWI+a9T4jtFd77IYjuND+QVe360qWgAF7H0WtoopYhRw/+SgpGUTyrkrh+65+ClNnfw==" }, "Microsoft.Windows.CsWinRT": { "type": "Direct", @@ -16,40 +16,40 @@ }, "Sentry": { "type": "Direct", - "requested": "[6.5.0, )", - "resolved": "6.5.0", - "contentHash": "EuC4Da4WcC8eE8d+AHoDGLK0wfyrQ/OYeNghDnR9dc3q/jDUadqXsJtEsq8U9Dt+VG6lCg0K8AoksheCVe3q8w==" + "requested": "[6.6.0, )", + "resolved": "6.6.0", + "contentHash": "1D3xo3P9Y94VQN3RoV/86XqgtylHp1pdeEml3/UB649BrzJeZ/pqO/o8YgJ5g+GqpMQiGI09yjAI7s5ff2A1IA==" }, "Google.Protobuf": { "type": "Transitive", - "resolved": "3.34.1", - "contentHash": "212vdYxRuVopGE5bess6Jg5oXWyizA6hcLPTI7G+qA4PthQEvfeof3njT+7VSY5v/+O0P22xTydiP5fSJJpGEA==" + "resolved": "3.35.0", + "contentHash": "OrUZCUzBXqdSmsQSWp/EPeINjOBcMU+PrZEJegw0aLgOGFHZ9ZI37X/SFrIxo8C9ghKynaKpPr3BVPc4EujWYg==" }, "Microsoft.Extensions.DependencyInjection.Abstractions": { "type": "Transitive", - "resolved": "10.0.7", - "contentHash": "Z6mfFEaFcwCfSboxJwOLfu7/31npCY9q70WUamHW/vRQhDvBKOT4Vf9YkZj5J6hLvJpb0oDEYfHunQZj0xxvKw==" + "resolved": "10.0.8", + "contentHash": "21nbDV60SRPWGIivsyl6lqBeEJNG1sginhhfWgRrr3Ais7aQ12To25OAHQxgoiJkjqy1aQ6RxpZBGYuTi7Ge6A==" }, "Microsoft.Extensions.Logging.Abstractions": { "type": "Transitive", - "resolved": "10.0.7", - "contentHash": "tIEcQ2gvERrH2KiCjdsVcHGhXt9lIsuDStfOIeZWr7/fP8IXhGiYfx0/80PNI7WPO2IYuFtlZLSlnTS8+/Mchw==", + "resolved": "10.0.8", + "contentHash": "fdVadZmsC8jRP0KvKy8mO8f6GV/HyBvElfcSxEhd+5FM5boAw/01iSaCto5G3G37ApJira4A3pNaVvBv8cUiLQ==", "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.7" + "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8" } }, "System.IO.Hashing": { "type": "Transitive", - "resolved": "10.0.7", - "contentHash": "6hsjdSr4VOXSOnhALkYplHpAxnTG1J33YN42IB6nH2fEg4QnJqrZ4Ft+qn7mkrKAOYC8pCSFYwVWw6rQbmwgLQ==" + "resolved": "10.0.8", + "contentHash": "+dJsbPJ3FyUbTZNplFj0RCKePFizmv6ewDV46JE9q/IVH4c3xTCftHfHelLsAKf0jryIPqgMb5GpS0x7TAY3mg==" }, "hi3helper.enctool": { "type": "Project", "dependencies": { - "Google.Protobuf": "[3.34.1, )", + "Google.Protobuf": "[3.35.0, )", "Hi3Helper.Http": "[2.0.0, )", "Hi3Helper.Win32": "[1.0.0, )", - "System.IO.Hashing": "[10.0.7, )" + "System.IO.Hashing": "[10.0.8, )" } }, "hi3helper.http": { @@ -58,7 +58,7 @@ "hi3helper.win32": { "type": "Project", "dependencies": { - "Microsoft.Extensions.Logging.Abstractions": "[10.0.7, )" + "Microsoft.Extensions.Logging.Abstractions": "[10.0.8, )" } } } diff --git a/Hi3Helper.EncTool b/Hi3Helper.EncTool index b3ef9d1219..7648748e03 160000 --- a/Hi3Helper.EncTool +++ b/Hi3Helper.EncTool @@ -1 +1 @@ -Subproject commit b3ef9d121959ad32c3c534ec490c6fd11199efbf +Subproject commit 7648748e03092c7a94ef2c4da3d5d127ba9e0c93 diff --git a/Hi3Helper.Plugin.Core b/Hi3Helper.Plugin.Core index 368363637f..ebf52d8fa6 160000 --- a/Hi3Helper.Plugin.Core +++ b/Hi3Helper.Plugin.Core @@ -1 +1 @@ -Subproject commit 368363637f1eb64ac014e49244ee3cb8e7439471 +Subproject commit ebf52d8fa64b2a61597c235bb4abb2361685dd4a diff --git a/Hi3Helper.SharpDiscordRPC b/Hi3Helper.SharpDiscordRPC index c5de1a8fc3..6080f31833 160000 --- a/Hi3Helper.SharpDiscordRPC +++ b/Hi3Helper.SharpDiscordRPC @@ -1 +1 @@ -Subproject commit c5de1a8fc34c6595bc580b0563560c178b5ea2d2 +Subproject commit 6080f31833b96167d52bdb71daad407ea1418ba2 diff --git a/Hi3Helper.Sophon b/Hi3Helper.Sophon index 84d56e012b..5b40e0907c 160000 --- a/Hi3Helper.Sophon +++ b/Hi3Helper.Sophon @@ -1 +1 @@ -Subproject commit 84d56e012b90e83d02a8df35d578fd7178c3e14f +Subproject commit 5b40e0907c8b6bf6e2fea1d5a1da2e955e10365e diff --git a/Hi3Helper.TaskScheduler/Hi3Helper.TaskScheduler.csproj b/Hi3Helper.TaskScheduler/Hi3Helper.TaskScheduler.csproj index 77ed8a763a..fb155e6f7d 100644 --- a/Hi3Helper.TaskScheduler/Hi3Helper.TaskScheduler.csproj +++ b/Hi3Helper.TaskScheduler/Hi3Helper.TaskScheduler.csproj @@ -21,7 +21,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive; compile diff --git a/Hi3Helper.TaskScheduler/packages.lock.json b/Hi3Helper.TaskScheduler/packages.lock.json index 77423fb6d7..dd14c88fc8 100644 --- a/Hi3Helper.TaskScheduler/packages.lock.json +++ b/Hi3Helper.TaskScheduler/packages.lock.json @@ -4,9 +4,9 @@ ".NETFramework,Version=v4.6.2": { "Costura.Fody": { "type": "Direct", - "requested": "[6.1.0, )", - "resolved": "6.1.0", - "contentHash": "11W5jOuFqZreNfzYK4MDMBgJlVGyOgcKxKvaxnrBByABXsLEjug5P288pdk8kFOv7dw9BQI0o00FvqfZY/o8Jg==", + "requested": "[6.2.0, )", + "resolved": "6.2.0", + "contentHash": "jaX+A6sw6pI7lkLDTvxN7zU8Ja/a50N2xPKF6RYy0J6QF62wVg+hJMXJph2K8XarDaAlxQ82EaKv3fAvUNyRpg==", "dependencies": { "Fody": "6.9.3" } diff --git a/Hi3Helper.Win32 b/Hi3Helper.Win32 index 9ffcfb85ef..ba996e0de0 160000 --- a/Hi3Helper.Win32 +++ b/Hi3Helper.Win32 @@ -1 +1 @@ -Subproject commit 9ffcfb85efb2eca86ccf21d20244adc23c05b581 +Subproject commit ba996e0de0336b9b892880adffee2c991571e8c2 diff --git a/ImageEx b/ImageEx index a6f892d0f4..e79117c587 160000 --- a/ImageEx +++ b/ImageEx @@ -1 +1 @@ -Subproject commit a6f892d0f43652abccc71a88be9a99ccc3ae5caf +Subproject commit e79117c587cde0dd333fcb653100b6e7112d3faf diff --git a/InnoSetupHelper/InnoSetupHelper.csproj b/InnoSetupHelper/InnoSetupHelper.csproj index b7e5b546b7..fd6209ecd9 100644 --- a/InnoSetupHelper/InnoSetupHelper.csproj +++ b/InnoSetupHelper/InnoSetupHelper.csproj @@ -19,7 +19,7 @@ - + \ No newline at end of file diff --git a/InnoSetupHelper/packages.lock.json b/InnoSetupHelper/packages.lock.json index bb6df6da45..772f25419f 100644 --- a/InnoSetupHelper/packages.lock.json +++ b/InnoSetupHelper/packages.lock.json @@ -4,15 +4,15 @@ "net10.0": { "Microsoft.NET.ILLink.Tasks": { "type": "Direct", - "requested": "[10.0.7, )", - "resolved": "10.0.7", - "contentHash": "AA/yhzFHNtQZXLdqjzujPy25G8EWwGWsAnxOE2zYSBoT/8QHP6ketN3CToD3DFreO653ipUwnKHo22B8AlBMCw==" + "requested": "[10.0.8, )", + "resolved": "10.0.8", + "contentHash": "dVbSXGIFNR5nZcv2tOLoWI+a9T4jtFd77IYjuND+QVe360qWgAF7H0WtoopYhRw/+SgpGUTyrkrh+65+ClNnfw==" }, "System.IO.Hashing": { "type": "Direct", - "requested": "[10.0.7, )", - "resolved": "10.0.7", - "contentHash": "6hsjdSr4VOXSOnhALkYplHpAxnTG1J33YN42IB6nH2fEg4QnJqrZ4Ft+qn7mkrKAOYC8pCSFYwVWw6rQbmwgLQ==" + "requested": "[10.0.8, )", + "resolved": "10.0.8", + "contentHash": "+dJsbPJ3FyUbTZNplFj0RCKePFizmv6ewDV46JE9q/IVH4c3xTCftHfHelLsAKf0jryIPqgMb5GpS0x7TAY3mg==" } } } diff --git a/env.json b/env.json index 3be6aa1519..b71798a5d7 100644 --- a/env.json +++ b/env.json @@ -1,5 +1,5 @@ { "DOTNET_INSTALL_DIR": ".\\.dotnet", - "DOTNET_VERSION": "10.0.2xx", + "DOTNET_VERSION": "10.0.3xx", "DOTNET_QUALITY": "ga" } \ No newline at end of file diff --git a/global.json b/global.json index a3746b587b..b531b3c432 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "10.0.203", + "version": "10.0.300", "rollForward": "latestPatch", "allowPrerelease": true } From ddcb0254133964cdb6dff62338ce4f50a9cc8a95 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Sat, 30 May 2026 21:58:18 +0700 Subject: [PATCH 02/15] [Honkai GSP] Fix throw while saving empty game settings This due to absence of the ScreenSettingData while the game has never been played before. --- .../GameSettings/Honkai/RegistryClass/ScreenSettingData.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CollapseLauncher/Classes/GameManagement/GameSettings/Honkai/RegistryClass/ScreenSettingData.cs b/CollapseLauncher/Classes/GameManagement/GameSettings/Honkai/RegistryClass/ScreenSettingData.cs index 0f6ea47405..f18314a526 100644 --- a/CollapseLauncher/Classes/GameManagement/GameSettings/Honkai/RegistryClass/ScreenSettingData.cs +++ b/CollapseLauncher/Classes/GameManagement/GameSettings/Honkai/RegistryClass/ScreenSettingData.cs @@ -132,7 +132,7 @@ public static ScreenSettingData Load(IGameSettings gameSettings) $"{ex}", ex)); } - return new ScreenSettingData(); + return new ScreenSettingData(gameSettings); } public override void Save() From fff9820b87e0f9cd45991f9d3c982d27ae7da2b7 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Sat, 30 May 2026 23:09:46 +0700 Subject: [PATCH 03/15] [HonkaiRepair] Fix Audio_Default redownload after game repair --- .../HonkaiV2/HonkaiRepairV2.Fetch.cs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Fetch.cs b/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Fetch.cs index bdece09bc2..d93c23c1a2 100644 --- a/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Fetch.cs +++ b/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Fetch.cs @@ -319,14 +319,20 @@ private async Task FinalizeAudioAssetsPath(List originAsse FilePropertiesRemote? audioDefaultManifestAsset = originAssetList.FirstOrDefault(x => x.N.EndsWith("AUDIO_Default_manifest.m")); // Edit: 2026-05-07 - // Starting from 8.8, AUDIO_Default_manifest.m must expect to be existed. So, if the file is missing or hash doesn't match, + // Starting from 8.8, AUDIO_Default_manifest.m must be present. So, if the file is missing or hash doesn't match, // perform download in the background. Then write AUDIO_Default_Version.txt after. - string audioDefaultVersionPath = Path.Combine(audioBasePath, "AUDIO_Default_Version.txt"); + // + // Edit: 2026-05-30 + // So turns out, I was an idiot. The audioDefaultAssetHash wasn't actually generated from the hash of the AUDIO_Default_manifest.m, + // but it was the first 8 bytes of the hash of the AUDIO_Default file itself, being read as a Big-Endian UInt64. + // I was a bit exagerated while looking at the reversed code and I thought it was reading the hash from the .m file LMFAO. + string audioDefaultVersionPath = Path.Combine(audioBasePath, "AUDIO_Default_Version.txt"); string audioDefaultManifestPath = Path.Combine(audioBasePath, "AUDIO_Default_manifest.m"); - if (await EnsureAudioDefaultManifestExisted(HttpClientGeneric, audioDefaultManifestAsset, audioDefaultManifestPath, token)) + if (audioDefaultAsset != null && + await EnsureAudioDefaultManifestExisted(HttpClientGeneric, audioDefaultManifestAsset, audioDefaultManifestPath, token)) { - byte[] manifestContent = File.ReadAllBytes(audioDefaultManifestPath); - ulong audioDefaultAssetHash = BinaryPrimitives.ReadUInt64BigEndian(manifestContent.AsSpan(0, 8)); + ReadOnlySpan defaultHashBytes = audioDefaultAsset.Hash; + ulong audioDefaultAssetHash = BinaryPrimitives.ReadUInt64BigEndian(defaultHashBytes[..8]); await File.WriteAllTextAsync(audioDefaultVersionPath, $"{gameVersion}\t{audioDefaultAssetHash}", token); } From b549b810d21448100f32915cb3e2d547488b4b3d Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Sun, 31 May 2026 01:21:22 +0700 Subject: [PATCH 04/15] Fix MhyMurmurHash264B reporting wrong pre-defined length --- .../RepairManagement/HonkaiV2/HonkaiRepairV2.Check.Generic.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Check.Generic.cs b/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Check.Generic.cs index f8f160dbbf..8c4d1f0bec 100644 --- a/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Check.Generic.cs +++ b/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Check.Generic.cs @@ -163,7 +163,7 @@ private async ValueTask TryIsAssetRemoteSizeEquals( { case 8: { - MhyMurmurHash264B hasher = new((uint)asset.S); + MhyMurmurHash264B hasher = new((ulong)assetFileInfo.Length); HashUtility hashUtil = HashUtility.ThreadSafe; (resultStatus, _) = From e06ad77d95152870dc842671096cd8cc27e5b16c Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Sun, 31 May 2026 02:08:42 +0700 Subject: [PATCH 05/15] Fix MhyMurmurHash264B reporting wrong pre-defined length (pt. 2) --- .../RepairManagement/HonkaiV2/HonkaiRepairV2.Repair.Audio.cs | 2 +- .../RepairManagement/HonkaiV2/HonkaiRepairV2.Repair.Block.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Repair.Audio.cs b/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Repair.Audio.cs index 0a37b146c7..cccec0330f 100644 --- a/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Repair.Audio.cs +++ b/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Repair.Audio.cs @@ -72,7 +72,7 @@ private async ValueTask RepairAssetAudioType( { byte[] hashBuffer = new byte[8]; byte[] buffer = ArrayPool.Shared.Rent(bufferSize); - MhyMurmurHash264B hasher = new(patchInfo.PatchFileSize); + MhyMurmurHash264B hasher = new((ulong)patchFileStream.Length); try { diff --git a/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Repair.Block.cs b/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Repair.Block.cs index e63f458912..d1bdbbb4bd 100644 --- a/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Repair.Block.cs +++ b/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Repair.Block.cs @@ -72,7 +72,7 @@ private async ValueTask RepairAssetBlockType( { byte[] hashBuffer = new byte[8]; byte[] buffer = ArrayPool.Shared.Rent(bufferSize); - MhyMurmurHash264B hasher = new(patchInfo.PatchSize); + MhyMurmurHash264B hasher = new((ulong)patchFileStream.Length); try { From ef59be01018f319d9ac6581abb244845b1c9d9c0 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Sun, 31 May 2026 02:10:07 +0700 Subject: [PATCH 06/15] [BSDiff] Use SIMD on Diff Add (on 256 or 128 bit data) --- .../Classes/RepairManagement/BSDiff.cs | 264 ++++++++++-------- 1 file changed, 147 insertions(+), 117 deletions(-) diff --git a/CollapseLauncher/Classes/RepairManagement/BSDiff.cs b/CollapseLauncher/Classes/RepairManagement/BSDiff.cs index b67d2a9e8a..2acd64909c 100644 --- a/CollapseLauncher/Classes/RepairManagement/BSDiff.cs +++ b/CollapseLauncher/Classes/RepairManagement/BSDiff.cs @@ -5,11 +5,13 @@ using Hi3Helper.Data; using System; +using System.Buffers; using System.Diagnostics; using System.IO; using System.IO.Compression; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; using System.Threading; // ReSharper disable CommentTypo // ReSharper disable CheckNamespace @@ -241,7 +243,7 @@ private long[] ReadControlNumbers(Stream source, long newPosition) /// /// /// - public unsafe void Apply(CancellationToken token = default) + public void Apply(CancellationToken token = default) { // check if apply can proceed if (!CanContinueApply) @@ -253,126 +255,154 @@ public unsafe void Apply(CancellationToken token = default) ProgressStopwatch.Restart(); Progress = new BinaryPatchProgress(); - if (InputStream.CanSeek) InputStream.Position = 0; + if (InputStream.CanSeek) InputStream.Position = 0; if (OutputStream.CanSeek) OutputStream.Position = 0; // preallocate buffers for reading and writing - Span newData = stackalloc byte[CBufferSize]; - Span oldData = stackalloc byte[CBufferSize]; - - // decompress each part (to read it) - using (Stream controlCompStream = PatchStream()) - using (Stream diffCompStream = PatchStream()) - using (Stream extraCompStream = PatchStream()) - using (Stream controlStream = TryGetCompressionStream(controlCompStream, CHeaderSize)) - using (Stream diffStream = TryGetCompressionStream(diffCompStream, CHeaderSize + ControlLength)) - using (Stream extraStream = TryGetCompressionStream(extraCompStream, CHeaderSize + ControlLength + DiffLength)) - { - // ReSharper disable once RedundantAssignment - Span control = stackalloc long[3]; - // ReSharper disable once UnusedVariable - Span buffer = stackalloc byte[8]; - - long oldPosition = 0; - long newPosition = 0; - while (newPosition < NewSize) - { - // Get the control array - control = ReadControlNumbers(controlStream, newPosition); - - // Get the size to copy - long bytesToCopy = control[0]; - - // Seek old file to the position that the new data is diffed against - InputStream.Position = oldPosition; - - // Start the copy process - while (bytesToCopy > 0) - { - // Throw if cancelation is called - token.ThrowIfCancellationRequested(); - - // Get minimum size to copy - int actualBytesToCopy = (int)Math.Min(bytesToCopy, CBufferSize); - // Get the minimum size from old data to copy - int availableInputBytes = (int)Math.Min(actualBytesToCopy, InputStream.Length - InputStream.Position); - - // Read diff and old data - diffStream.ReadExactly(newData[..actualBytesToCopy]); - InputStream.ReadExactly(oldData[..availableInputBytes]); - - // Add the old with new data in vectors - fixed (byte* newDataPtr = &newData[0]) - fixed (byte* oldDataPtr = &oldData[0]) - { - // Get the offset and remained offset - int offset; - long offsetRemained = CBufferSize % Vector128.Count; - for (offset = 0; offset < CBufferSize - offsetRemained; offset += Vector128.Count) - { - Vector128 newVector = Sse2.LoadVector128(newDataPtr + offset); - Vector128 oldVector = Sse2.LoadVector128(oldDataPtr + offset); - Vector128 resultVector = Sse2.Add(newVector, oldVector); - - Sse2.Store(newDataPtr + offset, resultVector); - } - - // Process the remained data by the last offset - while (offset < CBufferSize) *(newDataPtr + offset) += *(oldDataPtr + offset++); - - // Write the data into the output - OutputStream.Write(newData[..actualBytesToCopy]); - - // Adjust counters - newPosition += actualBytesToCopy; - oldPosition += actualBytesToCopy; - bytesToCopy -= actualBytesToCopy; - - // Update progress - UpdateProgress(OutputStream.Length, NewSize, actualBytesToCopy); - } - } - - // SANITY CHECK: Check if the new position + Additional/new data has more size than _newSize. - // If yes, then throw. - if (newPosition + control[1] > NewSize) - { - throw new InvalidDataException($"The patch file is corrupted! newPosition + control[1] ({newPosition} + {control[1]}) > newSize ({NewSize})"); - } - - // Get the bytes to copy for the additional data (new data) - bytesToCopy = (int)control[1]; - while (bytesToCopy > 0) - { - // Throw if cancelation is called - token.ThrowIfCancellationRequested(); - - // Get the size of the additional data to copy - int actualBytesToCopy = (int)Math.Min(bytesToCopy, CBufferSize); - - // Read the new data from extra stream and write it to output - extraStream.ReadExactly(newData[..actualBytesToCopy]); - OutputStream.Write(newData[..actualBytesToCopy]); - - newPosition += actualBytesToCopy; - bytesToCopy -= actualBytesToCopy; - - // Update progress - UpdateProgress(OutputStream.Length, NewSize, actualBytesToCopy); - } - - // Adjust the position (either move it towards or behind the current position) - oldPosition += control[2]; - } - } - - if (!LeaveOpenStream) + byte[] bufferData = ArrayPool.Shared.Rent(CBufferSize * 2); + Span newData = bufferData.AsSpan(0, CBufferSize); + Span oldData = bufferData.AsSpan(CBufferSize); + + try { - InputStream.Dispose(); - OutputStream.Dispose(); - } + // decompress each part (to read it) + using Stream controlCompStream = PatchStream(); + using Stream diffCompStream = PatchStream(); + using Stream extraCompStream = PatchStream(); + + const long controlOffset = CHeaderSize; + long diffOffset = controlOffset + ControlLength; + long extraOffset = diffOffset + DiffLength; + using Stream controlStream = TryGetCompressionStream(controlCompStream, controlOffset); + using Stream diffStream = TryGetCompressionStream(diffCompStream, diffOffset); + using Stream extraStream = TryGetCompressionStream(extraCompStream, extraOffset); + + long oldPosition = 0; + long newPosition = 0; + + while (newPosition < NewSize) + { + // Get the control array + Span control = ReadControlNumbers(controlStream, newPosition); + + // Get the size to copy + long bytesToCopy = control[0]; + + // Seek old file to the position that the new data is diffed against + InputStream.Position = oldPosition; + + // Start the copy process + while (bytesToCopy > 0) + { + // Throw if cancelation is called + token.ThrowIfCancellationRequested(); + + // Get minimum size to copy + int actualBytesToCopy = (int)Math.Min(bytesToCopy, CBufferSize); + // Get the minimum size from old data to copy + int availableInputBytes = (int)Math.Min(actualBytesToCopy, InputStream.Length - InputStream.Position); + + // Read diff and old data + diffStream.ReadExactly(newData[..actualBytesToCopy]); + InputStream.ReadExactly(oldData[..availableInputBytes]); + + // Add the old with new data in vectors + ref byte newDataRef = ref MemoryMarshal.GetReference(newData); + ref byte oldDataRef = ref MemoryMarshal.GetReference(oldData); + + // Get the offset and remained offset + int offset = 0; + + // Try with 256-bit vectors first + if (Vector256.IsHardwareAccelerated) + { + long offsetRemained = CBufferSize % Vector256.Count; + for (offset = 0; offset < CBufferSize - offsetRemained; offset += Vector256.Count) + { + Vector256 newVector = Vector256.LoadUnsafe(ref newDataRef, (nuint)offset); + Vector256 oldVector = Vector256.LoadUnsafe(ref oldDataRef, (nuint)offset); + Vector256 resultVector = Vector256.Add(newVector, oldVector); + + resultVector.StoreUnsafe(ref newDataRef, (nuint)offset); + } + } + // Fall back to 128-bit vectors + else if (Vector128.IsHardwareAccelerated) + { + long offsetRemained = CBufferSize % Vector128.Count; + for (offset = 0; offset < CBufferSize - offsetRemained; offset += Vector128.Count) + { + Vector128 newVector = Vector128.LoadUnsafe(ref newDataRef, (nuint)offset); + Vector128 oldVector = Vector128.LoadUnsafe(ref oldDataRef, (nuint)offset); + Vector128 resultVector = Vector128.Add(newVector, oldVector); + + resultVector.StoreUnsafe(ref newDataRef, (nuint)offset); + } + } + + // Process the remained data by the last offset + while (offset < CBufferSize) + { + Unsafe.Add(ref newDataRef, offset) += Unsafe.Add(ref oldDataRef, offset); + offset++; + } + + // Write the data into the output + OutputStream.Write(newData[..actualBytesToCopy]); + + // Adjust counters + newPosition += actualBytesToCopy; + oldPosition += actualBytesToCopy; + bytesToCopy -= actualBytesToCopy; + + // Update progress + UpdateProgress(OutputStream.Length, NewSize, actualBytesToCopy); + } + + // SANITY CHECK: Check if the new position + Additional/new data has more size than _newSize. + // If yes, then throw. + if (newPosition + control[1] > NewSize) + { + throw new InvalidDataException($"The patch file is corrupted! newPosition + control[1] ({newPosition} + {control[1]}) > newSize ({NewSize})"); + } + + // Get the bytes to copy for the additional data (new data) + bytesToCopy = control[1]; + while (bytesToCopy > 0) + { + // Throw if cancelation is called + token.ThrowIfCancellationRequested(); + + // Get the size of the additional data to copy + int actualBytesToCopy = (int)Math.Min(bytesToCopy, CBufferSize); + + // Read the new data from extra stream and write it to output + extraStream.ReadExactly(newData[..actualBytesToCopy]); + OutputStream.Write(newData[..actualBytesToCopy]); + + newPosition += actualBytesToCopy; + bytesToCopy -= actualBytesToCopy; + + // Update progress + UpdateProgress(OutputStream.Length, NewSize, actualBytesToCopy); + } + + // Adjust the position (either move it towards or behind the current position) + oldPosition += control[2]; + } + + if (!LeaveOpenStream) + { + InputStream.Dispose(); + OutputStream.Dispose(); + } - CanContinueApply = false; + CanContinueApply = false; + } + finally + { + ArrayPool.Shared.Return(bufferData); + } } private static unsafe long ReadInt64Sanity(ReadOnlySpan buf) From 9a5de6f5db7224ce2fa23a0e351e165e26decc97 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Sun, 31 May 2026 03:11:45 +0700 Subject: [PATCH 07/15] [Hi3GameRepair] Fix 404 (Not Found) error for some present CGs --- .../HonkaiV2/HonkaiRepairV2.AsbExt.Video.cs | 15 ++++++++++++--- .../HonkaiV2/HonkaiRepairV2.Check.Generic.cs | 2 +- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.AsbExt.Video.cs b/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.AsbExt.Video.cs index ec45171d74..78a5d58411 100644 --- a/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.AsbExt.Video.cs +++ b/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.AsbExt.Video.cs @@ -7,6 +7,7 @@ using Hi3Helper.EncTool.Parser.AssetMetadata; using Hi3Helper.EncTool.Parser.CacheParser; using Hi3Helper.EncTool.Parser.KianaDispatch; +using Hi3Helper.Plugin.Core.Management; using Hi3Helper.Preset; using Hi3Helper.Shared.ClassStruct; using System; @@ -58,6 +59,8 @@ internal static async Task> AudioLanguageType gameLanguageType = GetCurrentGameAudioLanguage(presetConfig); int parallelThread = Math.Clamp(progressibleInstance.ThreadForIONormalized * 4, 16, 64); + GameVersion currentVersion = progressibleInstance.GameVersion; + HashSet ignoredCgHashset = new(ignoredCgIds ?? []); List assetInfoList = await assetBundleHttpClient @@ -133,14 +136,16 @@ async ValueTask ImplCheckAndAdd(KeyValuePair entry, Cancel progressibleInstance.Status.IsProgressPerFileIndetermined = true; progressibleInstance.UpdateStatus(); - if (entry.Value.Category is CGCategory.Birthday or CGCategory.Activity or CGCategory.VersionPV) + if (entry.Value.Category is CGCategory.Birthday or CGCategory.Activity or CGCategory.VersionPV || + IsCgOnCurrentVersionOrPresent(assetName, currentVersion)) { UrlStatus urlStatus = await assetBundleHttpClient.GetURLStatusCode(assetUrl, innerToken); Logger.LogWriteLine($"The CG asset: {assetName} " + - (urlStatus.IsSuccessStatusCode ? "is" : "is not") + $" available (Status code: {urlStatus.StatusCode})", LogType.Default, true); + (urlStatus.IsSuccessStatusCode ? "is" : "is not") + + $" available (Status code: {urlStatus.StatusCode})", LogType.Default, true); if (!urlStatus.IsSuccessStatusCode) { - throw new HttpRequestException("No Asset bundle URLs were reachable"); + return; } if (urlStatus.FileSize > 0) @@ -161,5 +166,9 @@ async ValueTask ImplCheckAndAdd(KeyValuePair entry, Cancel }); } } + + static bool IsCgOnCurrentVersionOrPresent(string assetName, GameVersion gameVersion) => + GameVersion.TryParse(assetName.GetSplit(0, '_'), out GameVersion fileVersion) && + fileVersion >= gameVersion; } } \ No newline at end of file diff --git a/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Check.Generic.cs b/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Check.Generic.cs index 8c4d1f0bec..e07855a9b6 100644 --- a/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Check.Generic.cs +++ b/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Check.Generic.cs @@ -63,7 +63,7 @@ private async ValueTask TryIsAssetRemoteSizeEquals( bool useFastCheck, CancellationToken token = default) { - if (!fileInfo.Exists) + if (!fileInfo.Exists || fileInfo.Length == 0) { return false; } From a569e0fcb257b22a9832bef26a4f7c72230db747 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Sun, 31 May 2026 19:45:22 +0700 Subject: [PATCH 08/15] Fix preload progress not updating to 100% on Sophon --- .../Base/InstallManagerBase.Sophon.cs | 5 +++++ .../Base/InstallManagerBase.SophonPatch.cs | 10 ++++++++++ .../Classes/Interfaces/Class/ProgressBase.cs | 9 +++++---- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/CollapseLauncher/Classes/InstallManagement/Base/InstallManagerBase.Sophon.cs b/CollapseLauncher/Classes/InstallManagement/Base/InstallManagerBase.Sophon.cs index 3a363e33d7..abcdd02987 100644 --- a/CollapseLauncher/Classes/InstallManagement/Base/InstallManagerBase.Sophon.cs +++ b/CollapseLauncher/Classes/InstallManagement/Base/InstallManagerBase.Sophon.cs @@ -903,6 +903,11 @@ await Parallel.ForEachAsync(sophonUpdateAssetList parallelOptions, (asset, _) => Action(httpClient, asset)); + // Forcely update status + UpdateSophonDownloadStatus(null!); + UpdateSophonFileTotalProgress(0, true); + UpdateSophonFileDownloadProgress(0, 0); + _isSophonPreloadCompleted = isPreloadMode; // If it's in update mode, then clean up the temp sophon verified files diff --git a/CollapseLauncher/Classes/InstallManagement/Base/InstallManagerBase.SophonPatch.cs b/CollapseLauncher/Classes/InstallManagement/Base/InstallManagerBase.SophonPatch.cs index 52140d5245..29ef36b086 100644 --- a/CollapseLauncher/Classes/InstallManagement/Base/InstallManagerBase.SophonPatch.cs +++ b/CollapseLauncher/Classes/InstallManagement/Base/InstallManagerBase.SophonPatch.cs @@ -533,6 +533,11 @@ await EnsureDiskSpaceSufficiencyAsync(downloadSizePatchOnlyRemote, // Run parallel pipeline for download await Parallel.ForEachAsync(pipelineDownloadEnumerable, parallelOptions, ImplDownload); + // Forcely update status + UpdateCurrentDownloadStatus(); + UpdateSophonFileTotalProgress(0, true); + UpdateSophonFileDownloadProgress(0, 0); + // If it's on preload mode, then return as we only need to perform patch download. if (isPreloadMode) { @@ -551,6 +556,11 @@ await EnsureDiskSpaceSufficiencyAsync(downloadSizePatchOnlyRemote, // Run parallel pipeline for patch await Parallel.ForEachAsync(pipelinePatchEnumerable, parallelOptions, ImplPatchUpdate); + // Forcely update status + UpdateCurrentDownloadStatus(); + UpdateSophonFileTotalProgress(0, true); + UpdateSophonFileDownloadProgress(0, 0); + if (_canDeleteZip) { patchAssets.RemovePatches(patchOutputDir); diff --git a/CollapseLauncher/Classes/Interfaces/Class/ProgressBase.cs b/CollapseLauncher/Classes/Interfaces/Class/ProgressBase.cs index 40e95e61e0..768de8a381 100644 --- a/CollapseLauncher/Classes/Interfaces/Class/ProgressBase.cs +++ b/CollapseLauncher/Classes/Interfaces/Class/ProgressBase.cs @@ -509,7 +509,10 @@ protected bool CheckIfNeedRefreshStopwatch() private long _sophonDownloadOnlyCurrentDownloadedBytes; private long _sophonDownloadOnlyLastDownloadedBytes; - protected void UpdateSophonFileTotalProgress(long read) + + protected void UpdateSophonFileTotalProgress(long read) => UpdateSophonFileTotalProgress(read, false); + + protected void UpdateSophonFileTotalProgress(long read, bool forceUpdate) { _ = Interlocked.Add(ref ProgressAllSizeCurrent, read); @@ -523,10 +526,8 @@ protected void UpdateSophonFileTotalProgress(long read) // Calculate the speed for download (just use it for update only by setting receivedBytes to 0) _sophonDownloadOnlySpeed = CalculateSpeed(lastReceivedDownloadBytes, ref _sophonDownloadOnlyLastSpeed, ref _sophonDownloadOnlyReceivedBytes, ref _sophonDownloadOnlyLastTick); - // Calculate the clamped speed for download and timelapse - double speedDownloadClamped = _sophonDownloadOnlySpeed.ClampLimitedSpeedNumber(); - if (!CheckIfNeedRefreshStopwatch()) + if (!CheckIfNeedRefreshStopwatch() && !forceUpdate) { return; } From fba6eb25be68e28819088588fc784f5e92b9dd4e Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Mon, 1 Jun 2026 16:59:07 +0700 Subject: [PATCH 09/15] [HSR 4.3] Adjustment on data struct (DesignDataV) --- .../StarRailV2/StarRailPersistentRefResult.cs | 30 +++++++++- .../StarRailAssetSignaturelessMetadata.cs | 59 ++++++++++++++++--- 2 files changed, 79 insertions(+), 10 deletions(-) diff --git a/CollapseLauncher/Classes/RepairManagement/StarRailV2/StarRailPersistentRefResult.cs b/CollapseLauncher/Classes/RepairManagement/StarRailV2/StarRailPersistentRefResult.cs index e228d16fc2..040919b22d 100644 --- a/CollapseLauncher/Classes/RepairManagement/StarRailV2/StarRailPersistentRefResult.cs +++ b/CollapseLauncher/Classes/RepairManagement/StarRailV2/StarRailPersistentRefResult.cs @@ -338,7 +338,7 @@ await LoadMetadataFile(instance, await LoadMetadataFile(instance, handleArchive, client, - baseUrl.Audio, + baseUrl.AudioPersistent, "AudioV", aDirAudio, token); @@ -348,7 +348,7 @@ await LoadMetadataFile(instance, await LoadMetadataFile(instance, handleArchive, client, - baseUrl.Video, + baseUrl.VideoPersistent, "VideoV", aDirVideo, token); @@ -524,20 +524,44 @@ private static async ValueTask SaveLocalIndexFiles( string fileUrl = baseUrl.CombineURLFromString(filename); await using Stream networkStream = (await client.TryGetCachedStreamFrom(fileUrl, token: token)).Stream; await using Stream sourceStream = !string.IsNullOrEmpty(saveToLocalDir) +#if DEBUG + ? await CreateLocalStream(networkStream, Path.Combine(saveToLocalDir, filename), token) +#else ? CreateLocalStream(networkStream, Path.Combine(saveToLocalDir, filename)) +#endif : networkStream; await parser.ParseAsync(sourceStream, true, token); return parser; - static Stream CreateLocalStream(Stream thisSourceStream, string filePath) +#if DEBUG + static async ValueTask +#else + static Stream +#endif + CreateLocalStream(Stream thisSourceStream, + string filePath, +#if DEBUG + CancellationToken token) +#else + ) +#endif { FileInfo fileInfo = new FileInfo(filePath) .EnsureCreationOfDirectory() .EnsureNoReadOnly() .StripAlternateDataStream(); +#if DEBUG + FileStream fileStream = fileInfo.Open(FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite); + await thisSourceStream.CopyToAsync(fileStream, token); + fileStream.Flush(true); + fileStream.Position = 0; + + return fileStream; +#else return new CopyToStream(thisSourceStream, fileInfo.Create(), null, true); +#endif } } diff --git a/CollapseLauncher/Classes/RepairManagement/StarRailV2/Struct/Assets/StarRailAssetSignaturelessMetadata.cs b/CollapseLauncher/Classes/RepairManagement/StarRailV2/Struct/Assets/StarRailAssetSignaturelessMetadata.cs index 9853059985..a75ceef648 100644 --- a/CollapseLauncher/Classes/RepairManagement/StarRailV2/Struct/Assets/StarRailAssetSignaturelessMetadata.cs +++ b/CollapseLauncher/Classes/RepairManagement/StarRailV2/Struct/Assets/StarRailAssetSignaturelessMetadata.cs @@ -3,9 +3,9 @@ using System; using System.Buffers; using System.Buffers.Binary; -using System.Collections.Generic; using System.IO; using System.Runtime.CompilerServices; +using System.Text; using System.Threading; using System.Threading.Tasks; @@ -78,10 +78,13 @@ protected override async ValueTask ReadDataCoreAsync( cancellationToken: token) .ConfigureAwait(false); - Span countBufferSpan = countBuffer; - int parentDataCount = BinaryPrimitives.ReadInt32BigEndian(countBufferSpan); + Span countBufferSpan = countBuffer; + int parentDataCount = BinaryPrimitives.ReadInt32BigEndian(countBufferSpan); // -- Declare constant length for each parent and children data + StarRailBinaryDataHeaderStruct header = Header; + short typeVersion = header.TypeVersionFlag.ReverseEndianess(); + const int parentDataBufferLen = 32; const int childrenDataBufferLen = 12; @@ -89,8 +92,12 @@ protected override async ValueTask ReadDataCoreAsync( byte[] parentDataBuffer = ArrayPool.Shared.Rent(parentDataBufferLen); Memory parentDataBufferMemory = parentDataBuffer.AsMemory(0, parentDataBufferLen); + // -- Allocate v3 string field buffer to the Memory + byte[] v3StringFieldLenBuffer = new byte[2]; + Memory v3StringFieldLenBufferMemory = v3StringFieldLenBuffer.AsMemory(); + // -- Allocate list - DataList = new List(parentDataCount); + DataList = [with(parentDataCount)]; try { @@ -108,11 +115,50 @@ protected override async ValueTask ReadDataCoreAsync( lastPos, out int bytesToSkip, out Metadata result); - DataList.Add(result); // -- Skip children data currentOffset += await dataStream.SeekForwardAsync(bytesToSkip, token) .ConfigureAwait(false); + + switch (typeVersion) + { + // Starting from Star Rail 4.3 (Manifest Ver. 3) update, they are adding additional field which contains the subdirectory of the asset. + // So we need to read the string field, and append the subdirectory to the filename if found. + case >= 3: + // Read the string length + await dataStream.ReadAtLeastAsync(v3StringFieldLenBufferMemory, + v3StringFieldLenBufferMemory.Length, + cancellationToken: token); + short v3StringFieldLen = BinaryPrimitives.ReadInt16BigEndian(v3StringFieldLenBuffer); + + // If there's a string field, read and append it to the filename + if (v3StringFieldLen != 0) + { + byte[] strBuffer = new byte[v3StringFieldLen]; + await dataStream.ReadAtLeastAsync(strBuffer, + strBuffer.Length, + cancellationToken: token); + + string str = Encoding.UTF8.GetString(strBuffer); + result = new Metadata + { + Filename = str.CombineURLFromString(result.Filename), + FileSize = result.FileSize, + Flags = result.Flags, + MD5Checksum = result.MD5Checksum + }; + } + break; + } + + // Dummy read to append into the end-of-struct mark (0x80) + Sanity. + int endOfStructMark = dataStream.ReadByte(); + if (endOfStructMark != 0x80) + { + throw new InvalidDataException($"Game data structure might be changed. Unexpected end-of-struct mark, expect 0x80 but received 0x{endOfStructMark:x2} instead. Please report this issue to Collapse developers."); + } + + DataList.Add(result); } } finally @@ -142,8 +188,7 @@ public static void Parse(ReadOnlySpan buffer, // subDataCount = Number of sub-data struct count // subDataSize = Number of sub-data struct size - // 1 = Unknown offset, seek +1 - bytesToSkip = subDataCount * subDataSize + 1; + bytesToSkip = subDataCount * subDataSize; result = new Metadata { MD5Checksum = md5Hash, From 5b89dfd2595d1087add22b89cdcd62c28a7aeecb Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Mon, 1 Jun 2026 17:14:37 +0700 Subject: [PATCH 10/15] [HSR 4.3] Adjustment on data struct (IFixV) --- .../StarRailV2/Struct/Assets/StarRailAssetCsvMetadata.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CollapseLauncher/Classes/RepairManagement/StarRailV2/Struct/Assets/StarRailAssetCsvMetadata.cs b/CollapseLauncher/Classes/RepairManagement/StarRailV2/Struct/Assets/StarRailAssetCsvMetadata.cs index 73128c659c..dd412da73c 100644 --- a/CollapseLauncher/Classes/RepairManagement/StarRailV2/Struct/Assets/StarRailAssetCsvMetadata.cs +++ b/CollapseLauncher/Classes/RepairManagement/StarRailV2/Struct/Assets/StarRailAssetCsvMetadata.cs @@ -69,6 +69,12 @@ public static bool Parse(ReadOnlySpan line, out Metadata result) return false; } + const string emptyFlag = "Empty"; + if (line.Equals(emptyFlag, StringComparison.OrdinalIgnoreCase)) + { + return false; + } + const string separators = ",;"; // Include ; as well, just in case. const StringSplitOptions options = StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries; From f87393ca1854fd5cfc4dc8e17ada4f01811f5d35 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Mon, 1 Jun 2026 18:36:07 +0700 Subject: [PATCH 11/15] Fix missing cherry-pick line --- CollapseLauncher/Classes/Interfaces/Class/ProgressBase.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CollapseLauncher/Classes/Interfaces/Class/ProgressBase.cs b/CollapseLauncher/Classes/Interfaces/Class/ProgressBase.cs index 768de8a381..0969e17f8c 100644 --- a/CollapseLauncher/Classes/Interfaces/Class/ProgressBase.cs +++ b/CollapseLauncher/Classes/Interfaces/Class/ProgressBase.cs @@ -526,6 +526,8 @@ protected void UpdateSophonFileTotalProgress(long read, bool forceUpdate) // Calculate the speed for download (just use it for update only by setting receivedBytes to 0) _sophonDownloadOnlySpeed = CalculateSpeed(lastReceivedDownloadBytes, ref _sophonDownloadOnlyLastSpeed, ref _sophonDownloadOnlyReceivedBytes, ref _sophonDownloadOnlyLastTick); + // Calculate the clamped speed for download and timelapse + double speedDownloadClamped = _sophonDownloadOnlySpeed.ClampLimitedSpeedNumber(); if (!CheckIfNeedRefreshStopwatch() && !forceUpdate) { From f3518a26977d9be80d39ad0ceedcb82b3fd640eb Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Mon, 1 Jun 2026 18:58:44 +0700 Subject: [PATCH 12/15] Manual cherry-pick fixes --- .../Classes/CachesManagement/Honkai/Fetch.cs | 12 +- .../DiscordPresence/DiscordPresenceManager.cs | 9 +- .../Extension/VelopackLocatorExtension.cs | 18 +- .../Extension/WriteableBitmapExtension.cs | 39 +- .../Classes/Helper/TaskSchedulerHelper.cs | 38 +- .../Helper/Update/LauncherUpdateHelper.cs | 15 +- .../Classes/Plugins/PluginInfo.cs | 89 ++- .../Plugins/PluginPresetConfigWrapper.cs | 38 +- .../RegistryMonitor/RegistryMonitor.cs | 578 ++++++++++-------- .../Classes/RepairManagement/Genshin/Fetch.cs | 3 +- .../HonkaiV2/HonkaiRepairV2.AsbExt.Cache.cs | 26 +- .../GenshinGameSettingsPage.xaml.cs | 10 +- .../HonkaiGameSettingsPage.xaml.cs | 8 +- .../StarRailGameSettingsPage.xaml.cs | 9 +- .../ZenlessGameSettingsPage.xaml.cs | 10 +- .../XAMLs/Updater/Classes/Updater.cs | 6 +- 16 files changed, 470 insertions(+), 438 deletions(-) diff --git a/CollapseLauncher/Classes/CachesManagement/Honkai/Fetch.cs b/CollapseLauncher/Classes/CachesManagement/Honkai/Fetch.cs index 8f7adda5d6..e3c456190d 100644 --- a/CollapseLauncher/Classes/CachesManagement/Honkai/Fetch.cs +++ b/CollapseLauncher/Classes/CachesManagement/Honkai/Fetch.cs @@ -4,6 +4,7 @@ using CollapseLauncher.RepairManagement; using Hi3Helper; using Hi3Helper.EncTool; +using Hi3Helper.EncTool.Enc; using Hi3Helper.EncTool.Parser.KianaDispatch; using Hi3Helper.UABT; using System; @@ -310,8 +311,15 @@ private byte[] GetAssetIndexSalt(string data) key = LauncherMetadataHelper.CurrentMasterKey?.Key; } - MhyEncTool saltTool = new MhyEncTool(data, key); - return saltTool.GetSalt(); + byte[] saltBytes = new byte[8]; + if (!MhyEncTool.TryGetSalt(data, + key, + saltBytes, + out _, + out Exception exception)) + throw exception; + + return saltBytes; } private string GetAssetBasePathByType(CacheAssetType type) => Path.Combine(GamePath!, type == CacheAssetType.Data ? "Data" : "Resources"); diff --git a/CollapseLauncher/Classes/DiscordPresence/DiscordPresenceManager.cs b/CollapseLauncher/Classes/DiscordPresence/DiscordPresenceManager.cs index 0f843e4e7d..eb44c659b5 100644 --- a/CollapseLauncher/Classes/DiscordPresence/DiscordPresenceManager.cs +++ b/CollapseLauncher/Classes/DiscordPresence/DiscordPresenceManager.cs @@ -2,6 +2,7 @@ using CollapseLauncher.Helper.Update; using CollapseLauncher.Plugins; using DiscordRPC; +using DiscordRPC.Entities; using DiscordRPC.Message; using Hi3Helper; using System; @@ -139,9 +140,9 @@ private void EnablePresence(ulong applicationId) Logger.LogWriteLine("Discord Presence is Enabled!"); } - private void OnReady(object? _, ReadyMessage msg) + private void OnReady(object? _, ReadyMessage? msg) { - Logger.LogWriteLine($"Connected to Discord with user {msg.User.Username}"); + Logger.LogWriteLine($"Connected to Discord with user {msg?.User?.Username}"); if (!_firstTimeConnect) { // Restart Discord RPC client @@ -161,9 +162,9 @@ private void OnReady(object? _, ReadyMessage msg) } } - private static void OnPresenceUpdate(object? _, PresenceMessage msg) + private static void OnPresenceUpdate(object? _, PresenceMessage? msg) { - if (msg.Presence == null) + if (msg?.Presence == null) { Logger.LogWriteLine("Activity cleared!"); } diff --git a/CollapseLauncher/Classes/Extension/VelopackLocatorExtension.cs b/CollapseLauncher/Classes/Extension/VelopackLocatorExtension.cs index 70bb13f9d3..38e68a3928 100644 --- a/CollapseLauncher/Classes/Extension/VelopackLocatorExtension.cs +++ b/CollapseLauncher/Classes/Extension/VelopackLocatorExtension.cs @@ -5,9 +5,7 @@ using Hi3Helper.SentryHelper; using Hi3Helper.Shared.Region; using Hi3Helper.Win32.ShellLinkCOM; -using NuGet.Versioning; using System; -using System.Diagnostics; using System.IO; using System.Linq; using System.Runtime.CompilerServices; @@ -34,12 +32,8 @@ internal static void StartUpdaterHook(string aumid) // its custom AUMID IVelopackLogger? logger = ILoggerHelper.GetILogger("Velopack").ToVelopackLogger(); - Process currentProcess = Process.GetCurrentProcess(); - - WindowsVelopackLocator locator = - new(currentProcess.MainModule!.FileName, - (uint)currentProcess.Id, - logger); + DefaultProcessImpl procDefault = new(logger); + WindowsVelopackLocator locator = new(procDefault, logger); // HACK: Always ensure to set the AUMID field null so it won't // set the AUMID to its own. locator.GetLocatorAumidField() = null; @@ -168,7 +162,7 @@ public static void TryCleanupFallbackUpdate(SemanticVersion newVersion) // Try open the shortcut and check whether this shortcut is actually pointing to // CollapseLauncher.exe file - using ShellLink shellLink = new(thisUserStartMenuShortcut); + ShellLink shellLink = new(thisUserStartMenuShortcut); // Try to get the target path and its filename string shortcutTargetPath = shellLink.Target; if (!shortcutTargetPath.Equals(currentExecutedPath, StringComparison.OrdinalIgnoreCase)) @@ -247,10 +241,10 @@ internal static void GenerateVelopackMetadata(string aumid) """; // Adding shortcutAumid for future use, since they typo-ed the XML tag LMAO string currentVersion = LauncherUpdateHelper.LauncherCurrentVersionString; - string xmlPath = Path.Combine(LauncherConfig.AppExecutableDir, "sq.version"); + string xmlPath = Path.Combine(LauncherConfig.AppExecutableDir, "sq.version"); string xmlContent = string.Format(xmlTemplate, currentVersion, LauncherConfig.IsPreview ? "preview" : "stable", aumid).ReplaceLineEndings("\n"); - + // Check if file exist if (File.Exists(xmlPath)) { @@ -266,4 +260,4 @@ internal static void GenerateVelopackMetadata(string aumid) Logger.LogWriteLine($"Velopack metadata has been successfully written!\r\n{xmlContent}", LogType.Default, true); } } -} +} \ No newline at end of file diff --git a/CollapseLauncher/Classes/Extension/WriteableBitmapExtension.cs b/CollapseLauncher/Classes/Extension/WriteableBitmapExtension.cs index 2cabdd0159..0325e7cf43 100644 --- a/CollapseLauncher/Classes/Extension/WriteableBitmapExtension.cs +++ b/CollapseLauncher/Classes/Extension/WriteableBitmapExtension.cs @@ -1,6 +1,5 @@ using Hi3Helper; using Hi3Helper.SentryHelper; -using Hi3Helper.Win32.ManagedTools; using Hi3Helper.Win32.Native.Interfaces; using Hi3Helper.Win32.WinRT.IBufferCOM; using Microsoft.UI.Xaml.Media.Imaging; @@ -9,29 +8,27 @@ #pragma warning disable IDE0130 #nullable enable -namespace CollapseLauncher.Extension +namespace CollapseLauncher.Extension; + +internal static class WriteableBitmapExtension { - internal static class WriteableBitmapExtension + internal static nint GetBufferPointer(this WriteableBitmap writeableBitmap, out uint length) { - internal static nint GetBufferPointer(this WriteableBitmap writeableBitmap, out uint length) + length = writeableBitmap.PixelBuffer.Length; + try { - length = writeableBitmap.PixelBuffer.Length; IBufferByteAccess byteAccess = writeableBitmap.PixelBuffer.AsBufferByteAccess(); - try - { - byteAccess.Buffer(out nint bufferP); - return bufferP; - } - finally - { - if (!ComMarshal.TryReleaseComObject(byteAccess, out Exception? ex)) - { - SentryHelper.ExceptionHandler(ex, SentryHelper.ExceptionType.UnhandledOther); - Logger.LogWriteLine($"Cannot free the instance of IBufferByteAccess from WriteableBitmap\r\n{ex}", - LogType.Error, - true); - } - } + byteAccess.Buffer(out nint bufferP); + return bufferP; + } + catch (Exception ex) + { + SentryHelper.ExceptionHandler(ex, SentryHelper.ExceptionType.UnhandledOther); + Logger.LogWriteLine($"Cannot free the instance of IBufferByteAccess from WriteableBitmap\r\n{ex}", + LogType.Error, + true); } + + return nint.Zero; } -} +} \ No newline at end of file diff --git a/CollapseLauncher/Classes/Helper/TaskSchedulerHelper.cs b/CollapseLauncher/Classes/Helper/TaskSchedulerHelper.cs index 9874fa95d3..4f831ba3b4 100644 --- a/CollapseLauncher/Classes/Helper/TaskSchedulerHelper.cs +++ b/CollapseLauncher/Classes/Helper/TaskSchedulerHelper.cs @@ -7,7 +7,7 @@ using System.Diagnostics; using System.IO; using System.Text; -using System.Threading.Tasks; + // ReSharper disable CommentTypo // ReSharper disable StringLiteralTypo // ReSharper disable GrammarMistakeInComment @@ -59,11 +59,11 @@ private static void InvokeGetStatusCommand() // -1 means task is disabled with tray enabled -1 => (false, true), // 0 means task is disabled with tray disabled - 0 => (false, false), + 0 => (false, false), // 1 means task is enabled with tray disabled - 1 => (true, false), + 1 => (true, false), // 2 means task is enabled with tray enabled - 2 => (true, true), + 2 => (true, true), // Otherwise, return both disabled (due to failure) _ => (false, false) }; @@ -172,9 +172,9 @@ private static void CreateShortcut( // Try create directory Directory.CreateDirectory(iconLocationDir); - + // Create ShellLink instance - using ShellLink shellLink = new ShellLink(); + ShellLink shellLink = new(); // If existing icon exist, try open it try @@ -188,14 +188,14 @@ private static void CreateShortcut( SentryHelper.ExceptionHandler(new Exception(msg, ex)); Logger.LogWriteLine(msg + $"\r\n{ex}", LogType.Error, true); } - + // Set params on the shortcut instance - shellLink.IconIndex = 0; - shellLink.IconPath = executablePath ?? ""; - shellLink.DisplayMode = LinkDisplayMode.edmNormal; - shellLink.WorkingDirectory = workingDirPath ?? ""; - shellLink.Target = executablePath ?? ""; - shellLink.Description = appDescription ?? ""; + shellLink.IconIndex = 0; + shellLink.IconPath = executablePath ?? ""; + shellLink.DisplayMode = LinkDisplayMode.edmNormal; + shellLink.WorkingDirectory = workingDirPath ?? ""; + shellLink.Target = executablePath ?? ""; + shellLink.Description = appDescription ?? ""; // Save the icons shellLink.Save(iconLocation); @@ -248,11 +248,11 @@ private static int GetInvokeCommandReturnCode(string argument) using Process process = new Process(); process.StartInfo = new ProcessStartInfo { - FileName = appletPath, - Arguments = argument, - UseShellExecute = false, + FileName = appletPath, + Arguments = argument, + UseShellExecute = false, RedirectStandardOutput = true, - CreateNoWindow = true + CreateNoWindow = true }; #if DEBUG @@ -264,7 +264,7 @@ private static int GetInvokeCommandReturnCode(string argument) { // Start the applet and wait until it exit. process.Start(); - while (process.StandardOutput.ReadLine() is {} consoleStdOut) + while (process.StandardOutput.ReadLine() is { } consoleStdOut) { Logger.LogWriteLine("[TaskScheduler] " + consoleStdOut, LogType.Debug, true); @@ -294,4 +294,4 @@ private static int GetInvokeCommandReturnCode(string argument) return lastErrCode; } } -} +} \ No newline at end of file diff --git a/CollapseLauncher/Classes/Helper/Update/LauncherUpdateHelper.cs b/CollapseLauncher/Classes/Helper/Update/LauncherUpdateHelper.cs index 61cc73e1a1..364940ed04 100644 --- a/CollapseLauncher/Classes/Helper/Update/LauncherUpdateHelper.cs +++ b/CollapseLauncher/Classes/Helper/Update/LauncherUpdateHelper.cs @@ -5,9 +5,9 @@ using Hi3Helper.SentryHelper; using Hi3Helper.Shared.Region; using System; -using System.Threading.Tasks; using System.Diagnostics.CodeAnalysis; using System.IO; +using System.Threading.Tasks; using Velopack; using Velopack.Locators; using Velopack.Logging; @@ -22,7 +22,7 @@ namespace CollapseLauncher.Helper.Update internal static class LauncherUpdateHelper { internal static AppUpdateVersionProp? AppUpdateVersionProp; - private static bool _isLauncherUpdateAvailable; + private static bool _isLauncherUpdateAvailable; internal static GameVersion? LauncherCurrentVersion => field ??= LauncherConfig.AppCurrentVersionString; @@ -41,7 +41,7 @@ internal static async Task RunUpdateCheckDetached() Logger.LogWriteLine($"The update manager check throws an error, Skipping update check!\r\n{ex}", LogType.Warning, true); if (!ex.Message.Contains("application which is not installed", - StringComparison.InvariantCultureIgnoreCase)) + StringComparison.InvariantCultureIgnoreCase)) await SentryHelper.ExceptionHandlerAsync(ex); } } @@ -60,7 +60,8 @@ internal static async Task IsUpdateAvailable(bool isForceCheckUpdate = fal IFileDownloader updateManagerHttpAdapter = new UpdateManagerHttpAdapter(); // Initialize update manager logger, locator and options IVelopackLogger? velopackLogger = ILoggerHelper.GetILogger("Velopack").ToVelopackLogger(); - IVelopackLocator updateManagerLocator = VelopackLocator.CreateDefaultForPlatform(velopackLogger); + DefaultProcessImpl defaultProcessImpl = new(velopackLogger); + IVelopackLocator updateManagerLocator = VelopackLocator.CreateDefaultForPlatform(defaultProcessImpl, velopackLogger); UpdateOptions updateManagerOptions = new() { AllowVersionDowngrade = true, @@ -102,9 +103,9 @@ internal static async Task IsUpdateAvailable(bool isForceCheckUpdate = fal private static async ValueTask GetUpdateMetadata(string updateChannel) { - string relativePath = updateChannel.CombineURLFromString("fileindex.json"); - await using Stream ms = await FallbackCDNUtil.TryGetCDNFallbackStream(relativePath); + string relativePath = updateChannel.CombineURLFromString("fileindex.json"); + await using Stream ms = await FallbackCDNUtil.TryGetCDNFallbackStream(relativePath); return await ms.DeserializeAsync(AppUpdateVersionPropJsonContext.Default.AppUpdateVersionProp); } } -} +} \ No newline at end of file diff --git a/CollapseLauncher/Classes/Plugins/PluginInfo.cs b/CollapseLauncher/Classes/Plugins/PluginInfo.cs index dd551975a6..b6f9d06135 100644 --- a/CollapseLauncher/Classes/Plugins/PluginInfo.cs +++ b/CollapseLauncher/Classes/Plugins/PluginInfo.cs @@ -32,13 +32,6 @@ public partial class PluginInfo : INotifyPropertyChanged, IDisposable internal const string MarkPendingUpdateFileName = "_markPendingUpdate"; internal const string MarkPendingUpdateApplyFileName = "_markPendingUpdateApply"; - private unsafe delegate void DelegateGetPluginUpdateCdnList(int* count, ushort*** ptr); - private unsafe delegate GameVersion* DelegateGetPluginStandardVersion(); - private unsafe delegate GameVersion* DelegateGetPluginVersion(); - private unsafe delegate void* DelegateGetPlugin(); - private delegate void DelegateFreePlugin(); - private delegate void DelegateSetCallback(nint callbackP); - private bool _isDisposed; public event PropertyChangedEventHandler? PropertyChanged = delegate { }; @@ -141,10 +134,10 @@ public unsafe PluginInfo(string pluginFilePath, string pluginRelName, PluginMani Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); } - if (!libraryHandle.TryGetExport("GetPluginStandardVersion", out DelegateGetPluginStandardVersion getPluginStandardVersionHandle) || - !libraryHandle.TryGetExport("GetPluginVersion", out DelegateGetPluginVersion getPluginVersionHandle) || - !libraryHandle.TryGetExport("GetPlugin", out DelegateGetPlugin getPluginHandle) || - !libraryHandle.TryGetExport("SetLoggerCallback", out DelegateSetCallback setLoggerCallbackHandle)) + if (!libraryHandle.TryGetExportUnsafe("GetPluginStandardVersion", out nint getPluginStandardVersionHandleP) || + !libraryHandle.TryGetExportUnsafe("GetPluginVersion", out nint getPluginVersionHandleP) || + !libraryHandle.TryGetExportUnsafe("GetPlugin", out nint getPluginHandleP) || + !libraryHandle.TryGetExportUnsafe("SetLoggerCallback", out nint setLoggerCallbackHandleP)) { throw new InvalidOperationException($"Plugin: {Path.GetFileName(pluginFilePath)} is missing some required exports. Plugin won't be loaded!"); } @@ -153,23 +146,25 @@ public unsafe PluginInfo(string pluginFilePath, string pluginRelName, PluginMani nint callbackForLogger = Marshal.GetFunctionPointerForDelegate(_sharedLoggerCallback); if (callbackForLogger != nint.Zero) { - setLoggerCallbackHandle(callbackForLogger); + ((delegate* unmanaged[Cdecl])setLoggerCallbackHandleP)(callbackForLogger); } // TODO: Add versioning check. - GameVersion pluginStandardVersion = *getPluginStandardVersionHandle(); - GameVersion pluginVersion = *getPluginVersionHandle(); - void* pluginInstancePtr = getPluginHandle(); + GameVersion pluginStandardVersion = *((delegate* unmanaged[Cdecl])getPluginStandardVersionHandleP)(); + GameVersion pluginVersion = *((delegate* unmanaged[Cdecl])getPluginVersionHandleP)(); + nint pluginInstancePtr = ((delegate* unmanaged[Cdecl])getPluginHandleP)(); - if (pluginInstancePtr == null) + if (pluginInstancePtr == nint.Zero) { throw new NullReferenceException($"Plugin's \"GetPlugin\" ({pluginRelName}) export function returns a null pointer!"); } - IPlugin? pluginInstance = ComInterfaceMarshaller.ConvertToManaged(pluginInstancePtr); - if (pluginInstance == null) + if (!ComMarshal.TryCreateComObjectFromReference(pluginInstancePtr, + out IPlugin? pluginInstance, + out Exception? ex)) { - throw new NullReferenceException($"Plugin's \"GetPlugin\" ({pluginRelName}) export returns an invalid interface contract! Make sure that the plugin returns the valid interface instance!"); + throw new NullReferenceException($"Plugin's \"GetPlugin\" ({pluginRelName}) export returns an invalid interface contract! Make sure that the plugin returns the valid interface instance!", + ex); } // Get Self Updater @@ -177,15 +172,12 @@ public unsafe PluginInfo(string pluginFilePath, string pluginRelName, PluginMani Updater = selfUpdater; // Get Managed Update CDN List - if (libraryHandle.TryGetExport("GetPluginUpdateCdnList", out DelegateGetPluginUpdateCdnList getPluginUpdateCdnList)) + if (libraryHandle.TryGetExportUnsafe("GetPluginUpdateCdnList", out nint getPluginUpdateCdnListP)) { - int pluginCdnListCount = 0; - ushort** urlsPtr = null; - - getPluginUpdateCdnList(&pluginCdnListCount, &urlsPtr); - - if (pluginCdnListCount != 0 && urlsPtr != null) + ((delegate* unmanaged[Cdecl])getPluginUpdateCdnListP)(out int pluginCdnListCount, out nint urlArrayPtr); + if (pluginCdnListCount != 0 && urlArrayPtr != nint.Zero) { + ushort** urlsPtr = (ushort**)urlArrayPtr; string[] urlList = GC.AllocateUninitializedArray(pluginCdnListCount); for (int i = 0; i < pluginCdnListCount; i++) { @@ -229,7 +221,7 @@ public unsafe PluginInfo(string pluginFilePath, string pluginRelName, PluginMani pluginInstance.SetPluginLocaleId(LauncherConfig.GetAppConfigValue("AppLanguage")); - Logger.LogWriteLine($"[PluginInfo] Successfully loaded plugin: {Name} from: {pluginRelName}@0x{libraryHandle:x8} with version {Version} and standard version {StandardVersion}.", LogType.Debug, true); + Logger.LogWriteLine($"[PluginInfo] Successfully loaded plugin: {Name} from: {pluginRelName}@0x{libraryHandle:x8} with version {Version} and standard version {StandardVersion}.", LogType.Info, true); PresetConfigs = new PluginPresetConfigWrapper[presetConfigCount]; for (int i = 0; i < presetConfigCount; i++) @@ -255,22 +247,22 @@ public unsafe PluginInfo(string pluginFilePath, string pluginRelName, PluginMani } } - internal void EnableDnsResolver() + internal unsafe void EnableDnsResolver() { if (!IsLoaded) { return; } - if (Handle.TryGetExport("SetDnsResolverCallback", - out DelegateSetCallback setDnsResolverCallbackHandle)) + if (Handle.TryGetExportUnsafe("SetDnsResolverCallback", + out delegate* unmanaged[Cdecl] setDnsResolverCallbackHandle)) { nint dnsCallback = Marshal.GetFunctionPointerForDelegate(SharedDnsResolverCallback); setDnsResolverCallbackHandle(dnsCallback); } - if (!Handle.TryGetExport("SetDnsResolverCallbackAsync", - out DelegateSetCallback setDnsResolverCallbackAsyncHandle)) + if (!Handle.TryGetExportUnsafe("SetDnsResolverCallbackAsync", + out delegate* unmanaged[Cdecl] setDnsResolverCallbackAsyncHandle)) { return; } @@ -279,21 +271,21 @@ internal void EnableDnsResolver() setDnsResolverCallbackAsyncHandle(dnsCallbackAsync); } - internal void DisableDnsResolver() + internal unsafe void DisableDnsResolver() { if (!IsLoaded) { return; } - if (Handle.TryGetExport("SetDnsResolverCallback", - out DelegateSetCallback setDnsResolverCallbackHandle)) + if (Handle.TryGetExportUnsafe("SetDnsResolverCallback", + out delegate* unmanaged[Cdecl] setDnsResolverCallbackHandle)) { setDnsResolverCallbackHandle(nint.Zero); } - if (Handle.TryGetExport("SetDnsResolverCallbackAsync", - out DelegateSetCallback setDnsResolverCallbackAsyncHandle)) + if (Handle.TryGetExportUnsafe("SetDnsResolverCallbackAsync", + out delegate* unmanaged[Cdecl] setDnsResolverCallbackAsyncHandle)) { setDnsResolverCallbackAsyncHandle(nint.Zero); } @@ -321,7 +313,7 @@ internal async Task Initialize(CancellationToken token = default) internal void SetPluginLocaleId(string localeId) => Instance?.SetPluginLocaleId(localeId); - public void Dispose() + public unsafe void Dispose() { if (_isDisposed || !IsLoaded) { @@ -332,7 +324,8 @@ public void Dispose() { // Disable callbacks DisableDnsResolver(); - if (Handle.TryGetExport("SetLoggerCallback", out DelegateSetCallback setLoggerCallbackHandle)) + if (Handle.TryGetExportUnsafe("SetLoggerCallback", + out delegate* unmanaged[Cdecl] setLoggerCallbackHandle)) { setLoggerCallbackHandle(nint.Zero); Logger.LogWriteLine($"[PluginInfo] Plugin: {Name} Logger Callbacks have been detached!", LogType.Debug, true); @@ -345,7 +338,8 @@ public void Dispose() } // Try to dispose the IPlugin instance using the plugin's safe FreePlugin method first. - if (Handle.TryGetExport("FreePlugin", out DelegateFreePlugin freePluginCallback)) + if (Handle.TryGetExportUnsafe("FreePlugin", + out delegate* unmanaged[Cdecl] freePluginCallback)) { // Try call the free function. freePluginCallback(); @@ -369,11 +363,6 @@ public void Dispose() finally { // Free the plugin handle and remove it from the dictionary. - if (!ComMarshal.TryReleaseComObject(Instance, out Exception? ex)) - { - Logger.LogWriteLine($"[PluginInfo] Cannot release COM Object reference for IPlugin instance due to unexpected error: {ex}", LogType.Error, true); - } - NativeLibrary.Free(Handle); // Free GCHandle and nullify the delegate. @@ -386,9 +375,9 @@ public void Dispose() private static unsafe nint DnsResolverCallbackAsync(char* hostnameP, int hostnameLength, void** cancelCallbackP) { - string hostnameString = new string(new ReadOnlySpan(hostnameP, hostnameLength)); + string hostnameString = new(new ReadOnlySpan(hostnameP, hostnameLength)); - CancellationTokenSource tcs = new CancellationTokenSource(); + CancellationTokenSource tcs = new(); VoidCallback cancelCallback = CancelDelegate; GCHandle handle = GCHandle.Alloc(cancelCallback); // Lock the callback from getting GCed @@ -397,9 +386,9 @@ private static unsafe nint DnsResolverCallbackAsync(char* hostnameP, int hostnam Task task = DnsResolverCallbackAsync(hostnameString, tcs.Token); task.GetAwaiter() .OnCompleted(() => - { - handle.Free(); // Allow the GC to free the callback - }); + { + handle.Free(); // Allow the GC to free the callback + }); return task.AsResult(); diff --git a/CollapseLauncher/Classes/Plugins/PluginPresetConfigWrapper.cs b/CollapseLauncher/Classes/Plugins/PluginPresetConfigWrapper.cs index 31dd3e5844..ccf7762151 100644 --- a/CollapseLauncher/Classes/Plugins/PluginPresetConfigWrapper.cs +++ b/CollapseLauncher/Classes/Plugins/PluginPresetConfigWrapper.cs @@ -8,7 +8,6 @@ using Hi3Helper.Plugin.Core.Management.PresetConfig; using Hi3Helper.Plugin.Core.Utility; using Hi3Helper.Shared.Region; -using Hi3Helper.Win32.ManagedTools; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; @@ -92,9 +91,9 @@ public override ILauncherApi? GameLauncherApi set; } - public override GameNameType GameType => GameNameType.Plugin; - public override LauncherType LauncherType => LauncherType.Plugin; - public override GameVendorType VendorType => GameVendorType.CollapsePlugin; + public override GameNameType GameType => GameNameType.Plugin; + public override LauncherType LauncherType => LauncherType.Plugin; + public override GameVendorType VendorType => GameVendorType.CollapsePlugin; public string VendorTypeInString { get @@ -264,11 +263,11 @@ public override GameChannel GameChannel { _config.comGet_ReleaseChannel(out GameReleaseChannel result); return result switch - { - GameReleaseChannel.OpenBeta => GameChannel.Beta, - GameReleaseChannel.ClosedBeta => GameChannel.DevRelease, - _ => GameChannel.Stable - }; + { + GameReleaseChannel.OpenBeta => GameChannel.Beta, + GameReleaseChannel.ClosedBeta => GameChannel.DevRelease, + _ => GameChannel.Stable + }; } } @@ -282,7 +281,7 @@ public override string DefaultLanguage } private int? _hashID; - public override int HashID { get => _hashID ??= HashCode.Combine(GameName, ZoneName); set => _hashID = value; } + public override int HashID => _hashID ??= HashCode.Combine(GameName, ZoneName); [field: AllowNull, MaybeNull] @@ -388,23 +387,6 @@ public void Dispose() { _config.Free(); DiscordPresenceContext.Dispose(); - - ReleaseComObject(PluginNewsApi); - ReleaseComObject(PluginMediaApi); - ReleaseComObject(PluginGameManager); - ReleaseComObject(PluginGameInstaller); - ReleaseComObject(_config); - GC.SuppressFinalize(this); - return; - - static void ReleaseComObject(T obj) - where T : class - { - if (!ComMarshal.TryReleaseComObject(obj, out Exception? ex)) - { - Logger.LogWriteLine($"[PluginPresetConfigWrapper::Dispose] Cannot release COM Instance of {typeof(T).Name}\r\n{ex}", LogType.Error, true); - } - } } -} +} \ No newline at end of file diff --git a/CollapseLauncher/Classes/RegistryMonitor/RegistryMonitor.cs b/CollapseLauncher/Classes/RegistryMonitor/RegistryMonitor.cs index 926d961c8d..21ec04e4ab 100644 --- a/CollapseLauncher/Classes/RegistryMonitor/RegistryMonitor.cs +++ b/CollapseLauncher/Classes/RegistryMonitor/RegistryMonitor.cs @@ -1,9 +1,4 @@ -// ReSharper disable CommentTypo -// ReSharper disable PartialTypeWithSinglePart -// ReSharper disable StringLiteralTypo -// ReSharper disable UnusedMember.Global - -/* +/* * Credit * ============================================================================================= * Original code by: Thomas Freudenberg ©2003 - 2005 @@ -15,337 +10,386 @@ */ using Hi3Helper; +using Hi3Helper.Data; using Hi3Helper.SentryHelper; -using Hi3Helper.Win32.Native.Enums; +using Hi3Helper.Win32.Native.Enums.Registry; using Hi3Helper.Win32.Native.LibraryImport; using Hi3Helper.Win32.Native.Structs; using Microsoft.Win32; using System; +using System.Collections.Generic; using System.ComponentModel; using System.IO; using System.Threading; -using static Hi3Helper.Logger; +// ReSharper disable CommentTypo +// ReSharper disable PartialTypeWithSinglePart +// ReSharper disable StringLiteralTypo +// ReSharper disable UnusedMember.Global +// ReSharper disable CheckNamespace -namespace RegistryUtils +#nullable enable +namespace CollapseLauncher.RegistryUtils; + +public sealed partial class RegistryMonitor : IDisposable { - public sealed partial class RegistryMonitor : IDisposable + #region Event handling + + /// + /// Occurs when the specified registry key has changed. + /// + public event EventHandler? RegChanged; + + /// + /// Occurs when the access to the registry fails. + /// + public event ErrorEventHandler? Error; + + /// + /// Raises the event. + /// + /// + ///

+ /// OnRegChanged is called when the specified registry key has changed. + ///

+ /// + /// When overriding in a derived class, be sure to call + /// the base class's method. + /// + ///
+ private void OnRegChanged() => RegChanged?.Invoke(this, null!); + + /// + /// Raises the event. + /// + /// The which occured while watching the registry. + /// + /// + private void OnError(Exception e) { - #region Event handling - - /// - /// Occurs when the specified registry key has changed. - /// - public event EventHandler RegChanged; - - /// - /// Raises the event. - /// - /// - ///

- /// OnRegChanged is called when the specified registry key has changed. - ///

- /// - /// When overriding in a derived class, be sure to call - /// the base class's method. - /// - ///
- private void OnRegChanged() - { - EventHandler handler = RegChanged; - handler?.Invoke(this, null!); - } +#if DEBUG + Logger.LogWriteLine($"[RegistryMonitor] An error has occurred:\r\n" + + $" Hive: {_registryHive}\r\n" + + $" SubKey: {_registrySubKey}" + + $" Error: {e}", LogType.Debug, true); +#endif - /// - /// Occurs when the access to the registry fails. - /// - public event ErrorEventHandler Error; - - /// - /// Raises the event. - /// - /// The which occured while watching the registry. - /// - ///

- /// OnError is called when an exception occurs while watching the registry. - ///

- /// - /// When overriding in a derived class, be sure to call - /// the base class's method. - /// - ///
- private void OnError(Exception e) - { - SentryHelper.ExceptionHandler(e, SentryHelper.ExceptionType.UnhandledOther); - ErrorEventHandler handler = Error; - handler?.Invoke(this, new ErrorEventArgs(e)); - } + SentryHelper.ExceptionHandler(e, SentryHelper.ExceptionType.UnhandledOther); + Error?.Invoke(this, new ErrorEventArgs(e)); + } + + #endregion + + #region Private member variables + + private const RegChangeNotifyFilter DefaultRegFilter = + RegChangeNotifyFilter.Key + | RegChangeNotifyFilter.Attribute + | RegChangeNotifyFilter.Value + | RegChangeNotifyFilter.Security; + + private readonly HKEY _registryHive; + private readonly string _registrySubKey; + private Thread? _thread; + private readonly Lock _threadLock = new(); + private bool _disposed; + private readonly ManualResetEvent _eventTerminate = new(false); + + #endregion + + /// + /// Initializes a new instance of the class. + /// + /// The registry key to monitor. + public RegistryMonitor(RegistryKey registryKey) : this(registryKey.Name) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The subpath of the key or full path of the registry key, which include these valid Hive names:
+ /// + /// - HKEY_CLASSES_ROOT
+ /// - HKEY_CURRENT_CONFIG
+ /// - HKEY_CURRENT_USER
+ /// - HKEY_LOCAL_MACHINE
+ /// - HKEY_PERFORMANCE_DATA
+ /// - HKEY_USERS + ///
+ /// If no valid Hive name is found at the beginning of the path, + /// HKEY_CURRENT_USER or the value from will be used by default. + ///
+ /// And if is provided, the root key of HKEY_CURRENT_USER or will be used by default. + /// + /// + /// The registry hive to be used for monitoring. If a valid hive name from is defined and + /// both the value from is defined too, the hive from will + /// be used instead. + /// + public RegistryMonitor(string? subKeyOrFullKeyPath, HKEY? registryHive = null) + { + _registryHive = registryHive ?? GetRegistryHiveFromName(subKeyOrFullKeyPath) ?? HKEY.HKEY_CURRENT_USER; + _registrySubKey = GetRegistrySubKeyFromName(subKeyOrFullKeyPath); + RegistryNotifyFilter = DefaultRegFilter; - #endregion +#if DEBUG + Logger.LogWriteLine($"RegistryMonitor Initialized!\r\n" + + $" Hive: {_registryHive}\r\n" + + $" subKey: {_registrySubKey}", LogType.Debug, true); +#endif + } - #region Private member variables + #region String Utils - private HKEYCLASS _registryHive; - private string _registrySubName; - private readonly Lock _threadLock = new(); - private Thread _thread; - private bool _disposed; - private readonly ManualResetEvent _eventTerminate = new(false); + private const string PathSeparators = @"\/"; + private const string UnderscoreSeparators = "_-"; - private RegChangeNotifyFilter _regFilter = RegChangeNotifyFilter.Key | RegChangeNotifyFilter.Attribute | - RegChangeNotifyFilter.Value | RegChangeNotifyFilter.Security; + private static readonly Dictionary AlternateHKeyNames = GenerateAlternateHKeyNames(); - #endregion + private static readonly Dictionary.AlternateLookup> AlternateHKeyNamesL = + AlternateHKeyNames.GetAlternateLookup>(); - /// - /// Initializes a new instance of the class. - /// - /// The registry key to monitor. - public RegistryMonitor(RegistryKey registryKey) + private static HKEY? GetRegistryHiveFromName(ReadOnlySpan fullName) + { + ReadOnlySpan firstSplit = ConverterTool.GetSplit(fullName, 0, PathSeparators); + return Enum.TryParse(firstSplit, true, out HKEY key) || + AlternateHKeyNamesL.TryGetValue(firstSplit, out key) ? key : null; + } + + private static string GetRegistrySubKeyFromName(ReadOnlySpan fullName) + { + if (fullName.IsEmpty) { - InitRegistryKey(registryKey.Name); + return ""; } - /// - /// Initializes a new instance of the class. - /// - /// The name. - public RegistryMonitor(string name) - { - if (string.IsNullOrEmpty(name)) - throw new ArgumentNullException(nameof(name)); + fullName = fullName.Trim(PathSeparators); - InitRegistryKey(name); - } + HKEY? keyHive = GetRegistryHiveFromName(fullName); + ReadOnlySpan firstSplit = ConverterTool.GetSplit(keyHive.HasValue ? fullName : ReadOnlySpan.Empty, + 0, + PathSeparators); - /// - /// Initializes a new instance of the class. - /// - /// The registry hive. - /// The sub key. - public RegistryMonitor(RegistryHive registryHive, string subKey) + if (firstSplit.IsEmpty) { - InitRegistryKey(registryHive, subKey); -#if DEBUG - LogWriteLine($"RegistryMonitor Initialized!\r\n" + - $" Hive: {registryHive}\r\n" + - $" subKey: {subKey}", LogType.Debug, true); -#endif + return fullName.ToString(); } - ~RegistryMonitor() => Dispose(); + int offset = (int)firstSplit.GetByteOffsetFromSource(fullName) + + firstSplit.Length; + + return fullName[offset..].Trim(PathSeparators).ToString(); + } - /// - /// Disposes this object. - /// - public void Dispose() + private static Dictionary GenerateAlternateHKeyNames() + { + Dictionary returnDict = new(StringComparer.OrdinalIgnoreCase); + Dictionary.AlternateLookup> returnDictL = + returnDict.GetAlternateLookup>(); + Span buffer = stackalloc char[64]; + + foreach (HKEY value in Enum.GetValues()) { - try - { - Stop(); - } - catch (Exception ex) + if (!Enum.TryFormat(value, buffer, out int written)) { - LogWriteLine($"Error at stopping RegistryWatcher!\r\n{ex}", LogType.Error, true); - SentryHelper.ExceptionHandler(ex, SentryHelper.ExceptionType.UnhandledOther); - throw new Exception($"Error in RegistryMonitor Dispose routine!\r\n{ex}"); + continue; } - _disposed = true; -#if DEBUG - LogWriteLine("RegistryMonitor Disposed!", LogType.Debug, true); -#endif - GC.SuppressFinalize(this); + + ReadOnlySpan name = buffer[..written]; + ReadOnlySpan nameNoPrefix = GetNameWithoutPrefix(name); + + // Add general name with and without prefix + returnDictL.TryAdd(name, value); + returnDictL.TryAdd(nameNoPrefix, value); + + // Add general name with and without prefix for no underscore version + string nameNoUnderscore = GetNameNoUnderscore(name); + string nameNoUnderscoreNoPrefix = GetNameNoUnderscore(nameNoPrefix); + + returnDict.TryAdd(nameNoUnderscore, value); + returnDict.TryAdd(nameNoUnderscoreNoPrefix, value); } - /// - /// Gets or sets the RegChangeNotifyFilter. - /// - public RegChangeNotifyFilter RegChangeNotifyType + return returnDict; + + static string GetNameNoUnderscore(ReadOnlySpan name) { - get { return _regFilter; } - set + return string.Create(name.Length, name, Action); + + static void Action(Span span, ReadOnlySpan source) { - using (_threadLock.EnterScope()) + int index = 0; + foreach (char c in source) { - if (IsMonitoring) - throw new InvalidOperationException("Monitoring thread is already running"); - - _regFilter = value; + if (!UnderscoreSeparators.Contains(c)) + { + span[index++] = c; + } } + + span[index..].Clear(); } } - #region Initialization - - private void InitRegistryKey(RegistryHive hive, string name) + static ReadOnlySpan GetNameWithoutPrefix(ReadOnlySpan name) { - _registryHive = hive switch - { - RegistryHive.ClassesRoot => HKEYCLASS.HKEY_CLASSES_ROOT, - RegistryHive.CurrentConfig => HKEYCLASS.HKEY_CURRENT_CONFIG, - RegistryHive.CurrentUser => HKEYCLASS.HKEY_CURRENT_USER, - RegistryHive.LocalMachine => HKEYCLASS.HKEY_LOCAL_MACHINE, - RegistryHive.PerformanceData => HKEYCLASS.HKEY_PERFORMANCE_DATA, - RegistryHive.Users => HKEYCLASS.HKEY_USERS, - _ => throw new InvalidEnumArgumentException("hive", (int)hive, typeof(RegistryHive)) - }; - _registrySubName = name; + const string prefix = "HKEY"; + + return name.StartsWith(prefix, StringComparison.OrdinalIgnoreCase) + ? name[prefix.Length..].Trim(UnderscoreSeparators) // Slice + : name; // Use previous span } + } - private void InitRegistryKey(string name) - { - string[] nameParts = name.Split('\\'); + #endregion - switch (nameParts[0]) - { - case "HKEY_CLASSES_ROOT": - case "HKCR": - _registryHive = HKEYCLASS.HKEY_CLASSES_ROOT; - break; - - case "HKEY_CURRENT_USER": - case "HKCU": - _registryHive = HKEYCLASS.HKEY_CURRENT_USER; - break; - - case "HKEY_LOCAL_MACHINE": - case "HKLM": - _registryHive = HKEYCLASS.HKEY_LOCAL_MACHINE; - break; - - case "HKEY_USERS": - _registryHive = HKEYCLASS.HKEY_USERS; - break; - - case "HKEY_CURRENT_CONFIG": - _registryHive = HKEYCLASS.HKEY_CURRENT_CONFIG; - break; - - default: - _registryHive = HKEYCLASS.None; - throw new ArgumentException("The registry hive '" + nameParts[0] + "' is not supported", nameof(name)); - } + ~RegistryMonitor() => Dispose(); + + /// + /// Disposes this object. + /// + public void Dispose() + { + Interlocked.Exchange(ref _disposed, true); - _registrySubName = string.Join("\\", nameParts, 1, nameParts.Length - 1); + try + { + Stop(); + } + catch (Exception ex) + { + Logger.LogWriteLine($"Error at stopping RegistryWatcher!\r\n{ex}", LogType.Error, true); + SentryHelper.ExceptionHandler(ex, SentryHelper.ExceptionType.UnhandledOther); + throw new Exception($"Error in RegistryMonitor Dispose routine!\r\n{ex}"); } +#if DEBUG + Logger.LogWriteLine("RegistryMonitor Disposed!", LogType.Debug, true); +#endif + GC.SuppressFinalize(this); + } + + /// + /// Gets or sets the . + /// + public RegChangeNotifyFilter RegistryNotifyFilter { get; set; } - #endregion + /// + /// if the monitoring thread is running, otherwise . + /// + private bool IsMonitoring => _thread != null; - /// - /// true if this object is currently monitoring; - /// otherwise, false. - /// - private bool IsMonitoring + /// + /// Start monitoring. + /// + public void Start() + { + if (IsMonitoring) { - get { return _thread != null; } + return; } - /// - /// Start monitoring. - /// - public void Start() - { - if (_disposed) - throw new ObjectDisposedException(null, "This instance is already disposed"); + if (Volatile.Read(ref _disposed)) + throw new ObjectDisposedException(null, "This instance is already disposed"); - using (_threadLock.EnterScope()) + using (_threadLock.EnterScope()) + { + _eventTerminate.Reset(); + Interlocked.Exchange(ref _thread, new Thread(MonitorThread) { - if (IsMonitoring) - { - return; - } - - _eventTerminate.Reset(); - _thread = new Thread(MonitorThread) - { - IsBackground = true - }; - _thread.Start(); - } + IsBackground = true + }); + _thread.Start(); } + } - /// - /// Stops the monitoring thread. - /// - public void Stop() + /// + /// Stops the monitoring thread. + /// + public void Stop() + { + if (Volatile.Read(ref _disposed) || + Volatile.Read(ref _thread) == null) { - if (_disposed) return; + return; + } - using (_threadLock.EnterScope()) - { - Thread thread = _thread; - if (thread == null) - { - return; - } + using (_threadLock.EnterScope()) + { + _eventTerminate.Set(); + _thread?.Join(); + } + } - _eventTerminate.Set(); - thread.Join(); - } + private void MonitorThread() + { + try + { + ThreadLoop(); + } + catch (Exception e) + { + OnError(e); } - private void MonitorThread() + Interlocked.Exchange(ref _thread, null); + } + + private void ThreadLoop() + { + HResult result = + PInvoke.RegOpenKeyEx(_registryHive, + _registrySubKey, + RegOption.NonVolatile, + RegSAM.Read | RegSAM.QueryValue | RegSAM.Notify, + out nint registryKey); + + Exception? resultEx = result.GetException(); + if (resultEx != null) { - try - { - ThreadLoop(); - } - catch (Exception e) - { - OnError(e); - } - _thread = null; + OnError(resultEx); + return; } - private void ThreadLoop() + AutoResetEvent eventNotify = new(false); + try { - int result = PInvoke.RegOpenKeyEx(_registryHive, - _registrySubName, - 0, - (uint)ACCESS_MASK.STANDARD_RIGHTS_READ | (uint)RegKeyAccess.KEY_QUERY_VALUE | (uint)RegKeyAccess.KEY_NOTIFY, - out var registryKey); - if (result != 0) - throw new Win32Exception(result); - - AutoResetEvent eventNotify = new AutoResetEvent(false); - try - { - WaitHandle[] waitHandles = [eventNotify, _eventTerminate]; + WaitHandle[] waitHandles = [eventNotify, _eventTerminate]; - while (!_eventTerminate.WaitOne(0, true)) + while (!_eventTerminate.WaitOne(0, true)) + { + if (_disposed) break; + + int resultNotify = PInvoke.RegNotifyChangeKeyValue(registryKey, + true, + RegistryNotifyFilter, + eventNotify.SafeWaitHandle, + true); + if (resultNotify != 0) + throw new Win32Exception(resultNotify); + + int waitHandlerAny = WaitHandle.WaitAny(waitHandles); + if (waitHandlerAny != 0) { - if (_disposed) break; - - int resultNotify = PInvoke.RegNotifyChangeKeyValue(registryKey, - true, - _regFilter, - eventNotify.SafeWaitHandle, - true); - if (resultNotify != 0) - throw new Win32Exception(resultNotify); - - int waitHandlerAny = WaitHandle.WaitAny(waitHandles); - if (waitHandlerAny != 0) - { - continue; - } + continue; + } #if DEBUG - LogWriteLine($"[RegistryMonitor] Found change(s) in registry!\r\n" + - $" Hive: {_registryHive}\r\n" + - $" subName: {_registrySubName}", LogType.Debug, true); + Logger.LogWriteLine($"[RegistryMonitor] Found change(s) in registry!\r\n" + + $" Hive: {_registryHive}\r\n" + + $" SubKey: {_registrySubKey}", LogType.Debug, true); #endif - OnRegChanged(); - } + OnRegChanged(); } - finally + } + finally + { + if (registryKey != nint.Zero) { - if (registryKey != IntPtr.Zero) - { - ((HResult)PInvoke.RegCloseKey(registryKey)).ThrowOnFailure(); - } - - eventNotify.Dispose(); + ((HResult)PInvoke.RegCloseKey(registryKey)).ThrowOnFailure(); } + + eventNotify.Dispose(); } } -} +} \ No newline at end of file diff --git a/CollapseLauncher/Classes/RepairManagement/Genshin/Fetch.cs b/CollapseLauncher/Classes/RepairManagement/Genshin/Fetch.cs index e01d1ab46d..2ea5b2c136 100644 --- a/CollapseLauncher/Classes/RepairManagement/Genshin/Fetch.cs +++ b/CollapseLauncher/Classes/RepairManagement/Genshin/Fetch.cs @@ -5,6 +5,7 @@ using CollapseLauncher.InstallManager.Genshin; using Hi3Helper; using Hi3Helper.EncTool; +using Hi3Helper.EncTool.Enc; using Hi3Helper.EncTool.Hashes; using Hi3Helper.EncTool.Parser.AssetIndex; using Hi3Helper.EncTool.Parser.YSDispatchHelper; @@ -324,7 +325,7 @@ private async Task TryDecryptAndParseDispatcher(DispatchInfo disp // DEBUG ONLY: Show the decrypted Proto as Base64 format string dFormat = $"Proto Response (RAW Decrypted form):\r\n{Convert.ToBase64String(decryptedData)}"; #if DEBUG - LogWriteLine(dFormat); + LogWriteLine(dFormat, LogType.Debug, true); #endif await LogFileWriter.WriteLineAsync(dFormat); diff --git a/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.AsbExt.Cache.cs b/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.AsbExt.Cache.cs index 4fc0a1fb51..00183d6646 100644 --- a/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.AsbExt.Cache.cs +++ b/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.AsbExt.Cache.cs @@ -5,6 +5,7 @@ using Hi3Helper; using Hi3Helper.Data; using Hi3Helper.EncTool; +using Hi3Helper.EncTool.Enc; using Hi3Helper.EncTool.Parser.AssetMetadata; using Hi3Helper.EncTool.Parser.KianaDispatch; using Hi3Helper.Plugin.Core.Management; @@ -50,7 +51,7 @@ private static async Task> KianaDispatch gameServerInfo, CacheAssetType? cacheAssetType, ProgressBase progressibleInstance, - CancellationToken token = default) + CancellationToken token = default) where T : IAssetIndexSummary { // ReSharper disable once RedundantAssignment @@ -140,7 +141,7 @@ private static async Task> DeserializeCacheAssetListAsync currentJsonEntry in packageVersionText.GetStringEnumeration()) @@ -153,7 +154,7 @@ private static async Task> DeserializeCacheAssetListAsync> DeserializeCacheAssetListAsync> DeserializeCacheAssetListAsync GetGameServerInfoAsync( throw new NullReferenceException("GameGatewayDefault cannot be empty on the game preset"); } +#if DEBUG + // Assign Dispatcher Logger for Debug + KianaDispatch.DebugLogger = ILoggerHelper.GetILogger("KianaDispatch"); +#endif + Exception? lastException = null; for (int i = 0; i < presetConfig.GameDispatchArrayURL?.Count; i++) { diff --git a/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPages/GenshinGameSettingsPage.xaml.cs b/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPages/GenshinGameSettingsPage.xaml.cs index a6b10ebf4f..4868ad2124 100644 --- a/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPages/GenshinGameSettingsPage.xaml.cs +++ b/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPages/GenshinGameSettingsPage.xaml.cs @@ -1,8 +1,11 @@ using CollapseLauncher.GameSettings.Genshin; using CollapseLauncher.Helper; using CollapseLauncher.Helper.Animation; +using CollapseLauncher.RegistryUtils; using Hi3Helper; +using Hi3Helper.SentryHelper; using Hi3Helper.Shared.ClassStruct; +using Hi3Helper.Win32.Native.Enums.Registry; using Microsoft.Graphics.Canvas; using Microsoft.Graphics.Canvas.Brushes; using Microsoft.Graphics.Canvas.Effects; @@ -13,8 +16,6 @@ using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Controls.Primitives; using Microsoft.UI.Xaml.Media; -using Microsoft.Win32; -using RegistryUtils; using System; using System.Diagnostics.CodeAnalysis; using System.IO; @@ -26,12 +27,11 @@ using Windows.Storage; using Windows.Storage.Streams; using Windows.UI; +using static CollapseLauncher.Statics.GamePropertyVault; using static Hi3Helper.Locale; using static Hi3Helper.Logger; using static Hi3Helper.Shared.Region.LauncherConfig; -using static CollapseLauncher.Statics.GamePropertyVault; using Brush = Microsoft.UI.Xaml.Media.Brush; -using Hi3Helper.SentryHelper; #if !DISABLEDISCORD @@ -67,7 +67,7 @@ public GenshinGameSettingsPage() CurrentGameProperty = GetCurrentGameProperty(); DispatcherQueue?.TryEnqueue(() => { - RegistryWatcher = new RegistryMonitor(RegistryHive.CurrentUser, Path.Combine($"Software\\{CurrentGameProperty.GameVersion.VendorTypeProp.VendorType}", CurrentGameProperty.GameVersion.GamePreset.InternalGameNameInConfig!)); + RegistryWatcher = new RegistryMonitor(Path.Combine($"Software\\{CurrentGameProperty.GameVersion.VendorTypeProp.VendorType}", CurrentGameProperty.GameVersion.GamePreset.InternalGameNameInConfig!), HKEY.HKEY_CURRENT_USER); ToggleRegistrySubscribe(true); }); diff --git a/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPages/HonkaiGameSettingsPage.xaml.cs b/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPages/HonkaiGameSettingsPage.xaml.cs index a228d062d6..7d2b11dceb 100644 --- a/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPages/HonkaiGameSettingsPage.xaml.cs +++ b/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPages/HonkaiGameSettingsPage.xaml.cs @@ -1,20 +1,20 @@ using CollapseLauncher.GameSettings.Honkai; using CollapseLauncher.Helper.Animation; +using CollapseLauncher.RegistryUtils; using Hi3Helper; using Hi3Helper.Shared.ClassStruct; +using Hi3Helper.Win32.Native.Enums.Registry; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Media; -using Microsoft.Win32; -using RegistryUtils; using System; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Numerics; using Windows.UI; +using static CollapseLauncher.Statics.GamePropertyVault; using static Hi3Helper.Locale; using static Hi3Helper.Logger; using static Hi3Helper.Shared.Region.LauncherConfig; -using static CollapseLauncher.Statics.GamePropertyVault; #if !DISABLEDISCORD using CollapseLauncher.DiscordPresence; @@ -37,7 +37,7 @@ public HonkaiGameSettingsPage() CurrentGameProperty = GetCurrentGameProperty(); DispatcherQueue?.TryEnqueue(() => { - RegistryWatcher = new RegistryMonitor(RegistryHive.CurrentUser, Path.Combine($"Software\\{CurrentGameProperty.GameVersion.VendorTypeProp.VendorType}", CurrentGameProperty.GameVersion.GamePreset.InternalGameNameInConfig!)); + RegistryWatcher = new RegistryMonitor(Path.Combine($"Software\\{CurrentGameProperty.GameVersion.VendorTypeProp.VendorType}", CurrentGameProperty.GameVersion.GamePreset.InternalGameNameInConfig!), HKEY.HKEY_CURRENT_USER); ToggleRegistrySubscribe(true); }); diff --git a/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPages/StarRailGameSettingsPage.xaml.cs b/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPages/StarRailGameSettingsPage.xaml.cs index c92bfae34e..e6a7d5f2b5 100644 --- a/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPages/StarRailGameSettingsPage.xaml.cs +++ b/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPages/StarRailGameSettingsPage.xaml.cs @@ -1,22 +1,23 @@ using CollapseLauncher.Dialogs; using CollapseLauncher.GameSettings.StarRail; using CollapseLauncher.Helper.Animation; +using CollapseLauncher.RegistryUtils; using Hi3Helper; +using Hi3Helper.SentryHelper; using Hi3Helper.Shared.ClassStruct; +using Hi3Helper.Win32.Native.Enums.Registry; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Media; using Microsoft.Win32; -using RegistryUtils; using System; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Numerics; using Windows.UI; +using static CollapseLauncher.Statics.GamePropertyVault; using static Hi3Helper.Locale; using static Hi3Helper.Logger; using static Hi3Helper.Shared.Region.LauncherConfig; -using static CollapseLauncher.Statics.GamePropertyVault; -using Hi3Helper.SentryHelper; #if !DISABLEDISCORD @@ -43,7 +44,7 @@ public StarRailGameSettingsPage() DispatcherQueue?.TryEnqueue(() => { - RegistryWatcher = new RegistryMonitor(RegistryHive.CurrentUser, Path.Combine($"Software\\{CurrentGameProperty.GameVersion.VendorTypeProp.VendorType}", CurrentGameProperty.GameVersion.GamePreset.InternalGameNameInConfig!)); + RegistryWatcher = new RegistryMonitor(Path.Combine($"Software\\{CurrentGameProperty.GameVersion.VendorTypeProp.VendorType}", CurrentGameProperty.GameVersion.GamePreset.InternalGameNameInConfig!), HKEY.HKEY_CURRENT_USER); ToggleRegistrySubscribe(true); }); diff --git a/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPages/ZenlessGameSettingsPage.xaml.cs b/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPages/ZenlessGameSettingsPage.xaml.cs index 7fe827379d..700374d00f 100644 --- a/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPages/ZenlessGameSettingsPage.xaml.cs +++ b/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPages/ZenlessGameSettingsPage.xaml.cs @@ -3,14 +3,14 @@ #endif using CollapseLauncher.GameSettings.Zenless; using CollapseLauncher.Helper.Animation; +using CollapseLauncher.RegistryUtils; using Hi3Helper; using Hi3Helper.Data; using Hi3Helper.Shared.ClassStruct; +using Hi3Helper.Win32.Native.Enums.Registry; +using Hi3Helper.Win32.Screen; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Media; -using Microsoft.Win32; -using Hi3Helper.Win32.Screen; -using RegistryUtils; using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; @@ -18,10 +18,10 @@ using System.IO; using System.Linq; using System.Numerics; +using static CollapseLauncher.Statics.GamePropertyVault; using static Hi3Helper.Locale; using static Hi3Helper.Logger; using static Hi3Helper.Shared.Region.LauncherConfig; -using static CollapseLauncher.Statics.GamePropertyVault; using Brush = Microsoft.UI.Xaml.Media.Brush; using Color = Windows.UI.Color; // ReSharper disable CommentTypo @@ -46,7 +46,7 @@ public ZenlessGameSettingsPage() DispatcherQueue?.TryEnqueue(() => { - RegistryWatcher = new RegistryMonitor(RegistryHive.CurrentUser, Path.Combine($"Software\\{CurrentGameProperty.GameVersion.VendorTypeProp.VendorType}", CurrentGameProperty.GameVersion.GamePreset.InternalGameNameInConfig!)); + RegistryWatcher = new RegistryMonitor(Path.Combine($"Software\\{CurrentGameProperty.GameVersion.VendorTypeProp.VendorType}", CurrentGameProperty.GameVersion.GamePreset.InternalGameNameInConfig!), HKEY.HKEY_CURRENT_USER); ToggleRegistrySubscribe(true); }); diff --git a/CollapseLauncher/XAMLs/Updater/Classes/Updater.cs b/CollapseLauncher/XAMLs/Updater/Classes/Updater.cs index c0c6743980..230b853878 100644 --- a/CollapseLauncher/XAMLs/Updater/Classes/Updater.cs +++ b/CollapseLauncher/XAMLs/Updater/Classes/Updater.cs @@ -63,12 +63,14 @@ public Updater(string channelName) _updateDownloader = new UpdateManagerHttpAdapter(); _updateManagerLogger = ILoggerHelper.GetILogger("Velopack").ToVelopackLogger(); - IVelopackLocator updateManagerLocator = VelopackLocator.CreateDefaultForPlatform(_updateManagerLogger); + DefaultProcessImpl defaultProcessImpl = new(_updateManagerLogger); + IVelopackLocator updateManagerLocator = VelopackLocator.CreateDefaultForPlatform(defaultProcessImpl, _updateManagerLogger); UpdateOptions updateManagerOptions = new() { AllowVersionDowngrade = true, - ExplicitChannel = _channelName + ExplicitChannel = _channelName }; + // Initialize update manager // Initialize update manager source IUpdateSource updateSource = new SimpleWebSource(_channelURL, _updateDownloader); _updateManager = new UpdateManager( From 2489aedaf572cc031c6e54a83750a25d6d7db94c Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Mon, 1 Jun 2026 19:40:45 +0700 Subject: [PATCH 13/15] Manual cherry-pick fixes (pt. 2) --- .../HonkaiV2/HonkaiRepairV2.AsbExt.Audio.cs | 22 +++---- .../HonkaiV2/HonkaiRepairV2.AsbExt.Block.cs | 8 +-- .../HonkaiV2/HonkaiRepairV2.AsbExt.Cache.cs | 2 +- .../HonkaiV2/HonkaiRepairV2.AsbExt.Generic.cs | 58 +++++-------------- .../HonkaiV2/HonkaiRepairV2.AsbExt.Video.cs | 16 ++--- .../HonkaiV2/HonkaiRepairV2.Check.Audio.cs | 16 ++--- .../HonkaiV2/HonkaiRepairV2.Check.Block.cs | 2 +- .../HonkaiV2/HonkaiRepairV2.Check.Generic.cs | 27 +++++---- .../HonkaiV2/HonkaiRepairV2.Check.Unused.cs | 24 ++++---- .../HonkaiV2/HonkaiRepairV2.Check.cs | 10 ++-- .../HonkaiV2/HonkaiRepairV2.Fetch.cs | 46 +++++++-------- .../HonkaiV2/HonkaiRepairV2.Repair.Audio.cs | 2 +- .../HonkaiV2/HonkaiRepairV2.Repair.Block.cs | 4 +- .../HonkaiV2/HonkaiRepairV2.Repair.Generic.cs | 2 +- .../HonkaiV2/HonkaiRepairV2.Repair.cs | 44 +++++++------- .../HonkaiV2/HonkaiRepairV2.SenadinaExt.cs | 14 ++--- .../HonkaiV2/HonkaiRepairV2.cs | 14 ++--- 17 files changed, 140 insertions(+), 171 deletions(-) diff --git a/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.AsbExt.Audio.cs b/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.AsbExt.Audio.cs index ec88eac057..32c868b3de 100644 --- a/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.AsbExt.Audio.cs +++ b/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.AsbExt.Audio.cs @@ -50,7 +50,7 @@ internal static async Task> // Update Progress progressibleInstance.Status.ActivityStatus = - string.Format(Locale.Lang._CachesPage.CachesStatusFetchingType, "Audio Manifest"); + string.Format(Locale.Lang?._CachesPage?.CachesStatusFetchingType ?? "", "Audio Manifest"); progressibleInstance.Status.IsProgressAllIndetermined = true; progressibleInstance.Status.IsIncludePerFileIndicator = false; @@ -114,13 +114,13 @@ async ValueTask ImplCheckAndAdd(ManifestAssetInfo audioAsset, CancellationToken assetList.Add(new FilePropertiesRemote { IsPatchApplicable = audioAsset.IsHasPatch, - AssociatedObject = audioAsset, - AudioPatchInfo = audioAsset.PatchInfo, - CRC = audioAsset.HashString, - FT = FileType.Audio, - RN = baseAudioUrl.CombineURLFromString(audioAsset.Path), - N = audioAsset.Name + ".pck", - S = audioAsset.Size + AssociatedObject = audioAsset, + AudioPatchInfo = audioAsset.PatchInfo, + CRC = audioAsset.HashString, + FT = FileType.Audio, + RN = baseAudioUrl.CombineURLFromString(audioAsset.Path), + N = audioAsset.Name + ".pck", + S = audioAsset.Size }); } } @@ -131,7 +131,7 @@ internal static bool GetAudioPatchUrlProperty( [NotNullWhen(true)] out ManifestAudioPatchInfo? patchInfo, [NotNullWhen(true)] out string? patchUrl) { - const string startTrim = "/"; + const string startTrim = "/"; patchInfo = null; patchUrl = null; @@ -142,7 +142,7 @@ internal static bool GetAudioPatchUrlProperty( throw new InvalidOperationException("This method cannot be called while AudioPatchInfo is null"); } - if (asset.AssociatedObject is not ManifestAssetInfo audioAssetInfo) + if (asset.AssociatedObject is not ManifestAssetInfo) { throw new InvalidOperationException("This method cannot be called while AssociatedObject is not a ManifestAssetInfo type"); } @@ -162,4 +162,4 @@ internal static bool GetAudioPatchUrlProperty( return true; } -} +} \ No newline at end of file diff --git a/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.AsbExt.Block.cs b/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.AsbExt.Block.cs index 5ce178a827..2a5974fc83 100644 --- a/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.AsbExt.Block.cs +++ b/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.AsbExt.Block.cs @@ -48,17 +48,17 @@ internal static async Task> KianaDispatch gameServerInfo, SenadinaFileResult senadinaResults, ProgressBase progressibleInstance, - CancellationToken token = default) + CancellationToken token = default) where T : IAssetIndexSummary { // Update Progress progressibleInstance.Status.ActivityStatus = - string.Format(Locale.Lang._CachesPage.CachesStatusFetchingType, "Block Files"); + string.Format(Locale.Lang?._CachesPage?.CachesStatusFetchingType ?? "", "Block Files"); progressibleInstance.Status.IsProgressAllIndetermined = true; progressibleInstance.Status.IsIncludePerFileIndicator = false; progressibleInstance.UpdateStatus(); - await using Stream xmfMetaCurrentFileStream = senadinaResults.XmfMeta?.fileStream ?? throw new NullReferenceException("Senadina BlockMeta Identifier Stream cannot be null!"); + await using Stream xmfMetaCurrentFileStream = senadinaResults.XmfMeta?.fileStream ?? throw new NullReferenceException("Senadina BlockMeta Identifier Stream cannot be null!"); await using Stream xmfPatchCurrentFileStream = senadinaResults.XmfPatch?.fileStream ?? throw new NullReferenceException("Senadina BlockPatch Identifier Stream cannot be null!"); XMFParser xmfMetaParser = new(string.Empty, xmfMetaCurrentFileStream, true); @@ -182,4 +182,4 @@ internal static bool GetBlockPatchUrlProperty( return true; } -} +} \ No newline at end of file diff --git a/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.AsbExt.Cache.cs b/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.AsbExt.Cache.cs index 00183d6646..4bcb06dffc 100644 --- a/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.AsbExt.Cache.cs +++ b/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.AsbExt.Cache.cs @@ -216,7 +216,7 @@ private static async Task> DeserializeCacheAssetListAsync progressBase) { internal void AddBrokenAssetToList(FilePropertiesRemote asset, - byte[]? finalHash = null, - long? useFoundSize = null) + byte[]? finalHash = null, + long? useFoundSize = null) { AssetProperty property = - new AssetProperty(Path.GetFileName(asset.N), - asset.GetRepairAssetType(), - Path.GetDirectoryName(asset.N) ?? "\\", - useFoundSize ?? asset.S, - finalHash, - asset.CRCArray); + new(Path.GetFileName(asset.N), + asset.GetRepairAssetType(), + Path.GetDirectoryName(asset.N) ?? "\\", + useFoundSize ?? asset.S, + finalHash, + asset.CRCArray); asset.AssociatedAssetProperty = property; progressBase.Dispatch(AddToUITable); @@ -60,7 +60,7 @@ internal void UpdateCurrentRepairStatus(FilePropertiesRemote asset, bool isCache { // Increment total count current progressBase.ProgressAllCountCurrent++; - progressBase.Status.ActivityStatus = string.Format(isCacheUpdateMode ? Locale.Lang!._Misc!.Downloading + ": {0}" : Locale.Lang._GameRepairPage.Status8, asset.N); + progressBase.Status.ActivityStatus = string.Format(isCacheUpdateMode ? Locale.Lang?._Misc?.Downloading + ": {0}" : Locale.Lang?._GameRepairPage?.Status8 ?? "", asset.N); progressBase.UpdateStatus(); } } @@ -69,39 +69,11 @@ private static RepairAssetType GetRepairAssetType(this FilePropertiesRemote asse asset switch { { FT: FileType.Audio, IsPatchApplicable: true } => RepairAssetType.AudioUpdate, - { FT: FileType.Audio } => RepairAssetType.Audio, + { FT: FileType.Audio } => RepairAssetType.Audio, { FT: FileType.Block, IsPatchApplicable: true } => RepairAssetType.BlockUpdate, - { FT: FileType.Block } => RepairAssetType.Block, - { FT: FileType.Video } => RepairAssetType.Video, - { FT: FileType.Unused } => RepairAssetType.Unused, - _ => RepairAssetType.Generic + { FT: FileType.Block } => RepairAssetType.Block, + { FT: FileType.Video } => RepairAssetType.Video, + { FT: FileType.Unused } => RepairAssetType.Unused, + _ => RepairAssetType.Generic }; - - /* - internal static long GetDownloadableSize(this List assetList) - { - if (assetList.Count == 0) - { - return 0; - } - - IEnumerable nonPatchableQuery = - assetList.Where(x => x.FT != FileType.Unused && !x.IsPatchApplicable); - - IEnumerable patchableBlockLengthQuery = - assetList.Where(x => x.FT != FileType.Unused && x is { IsPatchApplicable: true, BlockPatchInfo: not null }) - .Select(x => x.BlockPatchInfo) - .SelectMany(x => x?.PatchPairs ?? []) - .Select(x => x.PatchSize); - - IEnumerable patchableAudioLengthQuery = - assetList.Where(x => x.FT != FileType.Unused && x is { IsPatchApplicable: true, AudioPatchInfo: not null }) - .Select(x => x.AudioPatchInfo) - .Select(x => x?.PatchFileSize ?? 0); - - return nonPatchableQuery.Sum(x => x.S) - + patchableBlockLengthQuery.Sum(x => x) - + patchableAudioLengthQuery.Sum(x => x); - } - */ -} +} \ No newline at end of file diff --git a/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.AsbExt.Video.cs b/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.AsbExt.Video.cs index 78a5d58411..1a168094d5 100644 --- a/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.AsbExt.Video.cs +++ b/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.AsbExt.Video.cs @@ -1,5 +1,4 @@ -using CollapseLauncher.Helper; -using CollapseLauncher.Helper.Metadata; +using CollapseLauncher.Helper.Metadata; using CollapseLauncher.Interfaces; using Hi3Helper; using Hi3Helper.Data; @@ -30,13 +29,13 @@ namespace CollapseLauncher.RepairManagement; internal static partial class AssetBundleExtension { internal const string RelativePathVideo = @"BH3_Data\StreamingAssets\Video\"; - internal const string MetadataFilename = "107438912"; + internal const string MetadataFilename = "107438912"; internal static void RemoveUnlistedVideoAssetFromList(this List originList, List assetListFromVideo) { List originOthersListOnly = originList.Where(x => x.FT != FileType.Video).ToList(); - List originVideoListOnly = originList.Where(x => x.FT == FileType.Video).ToList(); + List originVideoListOnly = originList.Where(x => x.FT == FileType.Video).ToList(); originList.Clear(); originList.AddRange(originOthersListOnly); @@ -83,7 +82,7 @@ await assetBundleHttpClient // Update Progress progressibleInstance.Status.ActivityStatus = - string.Format(Locale.Lang._CachesPage.CachesStatusFetchingType, "Video"); + string.Format(Locale.Lang?._CachesPage?.CachesStatusFetchingType ?? "", "Video"); progressibleInstance.Status.IsProgressAllIndetermined = true; progressibleInstance.Status.IsIncludePerFileIndicator = false; @@ -104,7 +103,7 @@ await Parallel .ForEachAsync(KianaCgMetadata.Parse(dechipheredCgStream), new ParallelOptions { - CancellationToken = token, + CancellationToken = token, MaxDegreeOfParallelism = parallelThread }, ImplCheckAndAdd); @@ -131,8 +130,9 @@ async ValueTask ImplCheckAndAdd(KeyValuePair entry, Cancel string assetUrl = baseUrl.CombineURLFromString("Video", assetName); // Update status - progressibleInstance.Status.ActivityStatus = string.Format(Locale.Lang?._GameRepairPage?.Status14 ?? "", assetName); - progressibleInstance.Status.IsProgressAllIndetermined = true; + progressibleInstance.Status.ActivityStatus = + string.Format(Locale.Lang?._GameRepairPage?.Status14 ?? "", assetName); + progressibleInstance.Status.IsProgressAllIndetermined = true; progressibleInstance.Status.IsProgressPerFileIndetermined = true; progressibleInstance.UpdateStatus(); diff --git a/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Check.Audio.cs b/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Check.Audio.cs index 91271a34a1..80514be388 100644 --- a/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Check.Audio.cs +++ b/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Check.Audio.cs @@ -65,13 +65,13 @@ await IsHashMatchedAuto(asset, } // Step 2: If asset has no patch applicable, add it to broken asset - if (!asset.IsPatchApplicable || // 1st Check: Ensure if patch is applicable - asset.AssociatedObject is not ManifestAssetInfo audioAssetInfo || // 2nd Check: Ensure if AssociatedObject is ManifestAssetInfo - audioAssetInfo.AllPatchInfo // 3rd Check: Ensure if matching patch info is available - .FirstOrDefault(x => - IsBytesEqualReversible(hashBufferMemory.Span, - x.OldAudioMD5Array)) - is not { } patchInfo) + if (!asset.IsPatchApplicable || // 1st Check: Ensure if patch is applicable + asset.AssociatedObject is not ManifestAssetInfo audioAssetInfo || // 2nd Check: Ensure if AssociatedObject is ManifestAssetInfo + audioAssetInfo.AllPatchInfo // 3rd Check: Ensure if matching patch info is available + .FirstOrDefault(x => + IsBytesEqualReversible(hashBufferMemory.Span, + x.OldAudioMD5Array)) + is not { } patchInfo) { byte[] finalBytesToDisplay = new byte[hashBufferSize]; hashBufferMemory.CopyTo(finalBytesToDisplay); @@ -112,4 +112,4 @@ private static bool IsBytesEqualReversible(Span hash, Span toCheck) toCheck.Reverse(); // Restore original order return false; } -} +} \ No newline at end of file diff --git a/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Check.Block.cs b/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Check.Block.cs index 5f022d80bb..8ebf9b52ca 100644 --- a/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Check.Block.cs +++ b/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Check.Block.cs @@ -101,4 +101,4 @@ private async ValueTask CheckAssetBlockWithPatchableType( this.AddBrokenAssetToList(asset, patchInfo.OldHash, patchInfo.PatchSize); return true; } -} +} \ No newline at end of file diff --git a/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Check.Generic.cs b/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Check.Generic.cs index e07855a9b6..380fdd1a52 100644 --- a/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Check.Generic.cs +++ b/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Check.Generic.cs @@ -5,7 +5,6 @@ using Hi3Helper.Data; using Hi3Helper.EncTool; using Hi3Helper.EncTool.Hashes; -using Hi3Helper.EncTool.Parser.CacheParser; using Hi3Helper.EncTool.Parser.Senadina; using Hi3Helper.Shared.ClassStruct; using System; @@ -55,7 +54,7 @@ private async Task IsHashMatchedAuto( /// Check actual remote size asset from the actual URL.
///
/// Note: This method only works on asset type with URL defined. - /// Otherwise, the method will immediately returns . + /// Otherwise, the method will immediately return . /// private async ValueTask TryIsAssetRemoteSizeEquals( FilePropertiesRemote asset, @@ -76,7 +75,7 @@ private async ValueTask TryIsAssetRemoteSizeEquals( } UrlStatus status = await HttpClientAssetBundle.GetCachedUrlStatus(asset.RN, token); - if (!status.IsSuccessStatusCode || status.FileSize == 0) // Returns true if status is not successful or size is 0 anyways + if (!status.IsSuccessStatusCode || status.FileSize == 0) // Returns true if status is not successful or size is 0 anyway { return true; } @@ -95,7 +94,7 @@ private async ValueTask TryIsAssetRemoteSizeEquals( CancellationToken token = default) { // Update activity status - Status.ActivityStatus = string.Format(Locale.Lang._GameRepairPage.Status6, asset.N); + Status.ActivityStatus = string.Format(Locale.Lang?._GameRepairPage?.Status6 ?? "", asset.N); // Increment current total count Interlocked.Increment(ref ProgressAllCountCurrent); @@ -106,7 +105,7 @@ private async ValueTask TryIsAssetRemoteSizeEquals( int hashSize = asset.CRCArray?.Length ?? 0; - string assetFilePath = Path.Combine(GamePath, asset.N); + string assetFilePath = Path.Combine(GamePath, asset.N); FileInfo assetFileInfo = new FileInfo(assetFilePath) .EnsureNoReadOnly(out bool isAssetExist) .StripAlternateDataStream(); @@ -148,12 +147,12 @@ private async ValueTask TryIsAssetRemoteSizeEquals( int bufferSize = asset.S.GetFileStreamBufferSize(); await using FileStream assetFileStream = assetFileInfo .Open(new FileStreamOptions - { - Mode = FileMode.Open, - Access = FileAccess.Read, - Share = FileShare.Read, - BufferSize = bufferSize - }); + { + Mode = FileMode.Open, + Access = FileAccess.Read, + Share = FileShare.Read, + BufferSize = bufferSize + }); // Override hash if HMAC key is null and asset's AssociatedObject is CacheAssetInfo hmacKey ??= (asset.AssociatedObject as CacheAssetInfo)?.HmacSha1Salt; @@ -189,8 +188,8 @@ await hashUtil ImplReadBytesAction, bufferSize, token); - break; - } + break; + } case MD5.HashSizeInBytes: { using HashAlgorithm hasher = hmacKey != null ? new HMACMD5(hmacKey) : MD5.Create(); @@ -262,4 +261,4 @@ await Logger.LogWriteLineAsync($"Asset with {asset} has unmatched hash! {asset.C void ImplReadBytesAction(int read) => UpdateHashReadProgress(read, true, isUpdateTotalProgressCounter); } -} +} \ No newline at end of file diff --git a/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Check.Unused.cs b/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Check.Unused.cs index 354d5574f5..e0818939d5 100644 --- a/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Check.Unused.cs +++ b/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Check.Unused.cs @@ -29,7 +29,7 @@ private void CheckAssetUnusedType( "@", "d3d", "dxgi.dll", - GameVersionManager!.GamePreset.ProfileName! + GameVersionManager.GamePreset.ProfileName! ], StringComparison.OrdinalIgnoreCase); SearchValues searchValuesContains = SearchValues.Create([ @@ -42,17 +42,17 @@ private void CheckAssetUnusedType( ".ini" ], StringComparison.OrdinalIgnoreCase); - HashSet hashSetList = GetExclusionHashSetFromAssetList(foundList, assetList); - var hashSetLookup = hashSetList.GetAlternateLookup>(); + HashSet hashSetList = GetExclusionHashSetFromAssetList(foundList, assetList); + var hashSetLookup = hashSetList.GetAlternateLookup>(); Regex? matchIgnoredRegex = null; - string ignoredFilesPath = Path.Combine(GamePath, "@IgnoredFiles"); + string ignoredFilesPath = Path.Combine(GamePath, "@IgnoredFiles"); if (File.Exists(ignoredFilesPath)) { try { - string[] ignoredFiles = File.ReadAllLines(ignoredFilesPath); - string mergedPattern = PatternMatcher.MergeRegexPattern(ignoredFiles); + string[] ignoredFiles = File.ReadAllLines(ignoredFilesPath); + string mergedPattern = PatternMatcher.MergeRegexPattern(ignoredFiles); matchIgnoredRegex = new Regex(mergedPattern, RegexOptions.IgnoreCase | RegexOptions.NonBacktracking | @@ -70,9 +70,9 @@ private void CheckAssetUnusedType( DirectoryInfo dirInfo = new(gameDir); foreach (FileInfo fileInfo in dirInfo.EnumerateFiles("*", SearchOption.AllDirectories)) { - string fileFullPath = fileInfo.FullName; + string fileFullPath = fileInfo.FullName; ReadOnlySpan fileRelativePath = TrimToRelativePath(fileFullPath); - ReadOnlySpan fileName = Path.GetFileName(fileRelativePath); + ReadOnlySpan fileName = Path.GetFileName(fileRelativePath); if (fileRelativePath.IndexOfAny(searchValuesStartsWith) == 0) continue; @@ -90,8 +90,8 @@ private void CheckAssetUnusedType( FilePropertiesRemote asset = new() { FT = FileType.Unused, - N = fileRelativePath.ToString(), - S = fileInfo.Length + N = fileRelativePath.ToString(), + S = fileInfo.Length }; this.AddBrokenAssetToList(asset, null, 0); } @@ -121,7 +121,7 @@ private static HashSet GetExclusionHashSetFromAssetList(List() .SelectMany(x => x.PatchPairs)) { - string oldFileName = Path.Combine(AssetBundleExtension.RelativePathBlock, blockPatchAsset.OldName); + string oldFileName = Path.Combine(AssetBundleExtension.RelativePathBlock, blockPatchAsset.OldName); string patchFileName = Path.Combine(AssetBundleExtension.RelativePathBlockPatch, blockPatchAsset.PatchName); ConverterTool.NormalizePathInplaceNoTrim(oldFileName); ConverterTool.NormalizePathInplaceNoTrim(patchFileName); @@ -146,4 +146,4 @@ private static HashSet GetExclusionHashSetFromAssetList(List StartCheckRoutineCoreAsync(bool useFastCheck) ResetStatusAndProgress(); // Set total activity string as "Loading Indexes..." - Status.ActivityStatus = Locale.Lang._GameRepairPage.Status2; + Status.ActivityStatus = Locale.Lang?._GameRepairPage?.Status2; Status.IsProgressAllIndetermined = true; UpdateStatus(); @@ -54,7 +54,7 @@ private async Task StartCheckRoutineCoreAsync(bool useFastCheck) await Parallel.ForEachAsync(checkAssetIndex, new ParallelOptions { - CancellationToken = Token.Token, + CancellationToken = Token.Token, MaxDegreeOfParallelism = ThreadForIONormalized }, Impl); @@ -65,10 +65,10 @@ await Parallel.ForEachAsync(checkAssetIndex, } return SummarizeStatusAndProgress(AssetIndex, - string.Format(Locale.Lang._GameRepairPage.Status3, + string.Format(Locale.Lang?._GameRepairPage?.Status3 ?? "", ProgressAllCountFound, ConverterTool.SummarizeSizeSimple(ProgressAllSizeFound)), - Locale.Lang._GameRepairPage.Status4); + Locale.Lang?._GameRepairPage?.Status4 ?? ""); ValueTask Impl(FilePropertiesRemote asset, CancellationToken token) => asset.FT switch @@ -78,4 +78,4 @@ ValueTask Impl(FilePropertiesRemote asset, CancellationToken token) => _ => CheckAssetGenericType(asset, useFastCheck, token) }; } -} +} \ No newline at end of file diff --git a/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Fetch.cs b/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Fetch.cs index d93c23c1a2..e6362a4a55 100644 --- a/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Fetch.cs +++ b/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Fetch.cs @@ -86,7 +86,7 @@ private async Task FetchAssetFromGameAssetBundle(List asse #endregion #region Fetch Video Assets from AssetBundle - List assetListFromVideo = []; + List assetListFromVideo = []; List assetListFromVideoOnlyDownloadable = []; Task assetListFromVideoTask = HttpClientAssetBundle @@ -96,11 +96,11 @@ private async Task FetchAssetFromGameAssetBundle(List asse ignoredAssets.IgnoredVideoCgSubCategory, token) .GetResultFromAction(result => - { - assetListFromVideo.AddRange(result); - assetListFromVideoOnlyDownloadable.AddRange(result.Where(x => ((KianaCgMetadata)x.AssociatedObject).DownloadMode == CGDownloadMode.DownloadTipOnce)); - FinalizeVideoAssetsPath(assetListFromVideo); - }); + { + assetListFromVideo.AddRange(result); + assetListFromVideoOnlyDownloadable.AddRange(result.Where(x => ((KianaCgMetadata)x.AssociatedObject).DownloadMode == CGDownloadMode.DownloadTipOnce)); + FinalizeVideoAssetsPath(assetListFromVideo); + }); #endregion #region Fetch Audio Assets from AssetBundle @@ -115,13 +115,13 @@ private async Task FetchAssetFromGameAssetBundle(List asse ignoredAssets.IgnoredAudioPckType, token) .GetResultFromAction(async result => - { - assetListFromAudio.AddRange(result); - await FinalizeAudioAssetsPath(assetIndex, - assetListFromAudio, - senadinaResult.Audio, - token); - }); + { + assetListFromAudio.AddRange(result); + await FinalizeAudioAssetsPath(assetIndex, + assetListFromAudio, + senadinaResult.Audio, + token); + }); #endregion #region Fetch Block Assets from AssetBundle @@ -136,13 +136,13 @@ await FinalizeAudioAssetsPath(assetIndex, this, token) .GetResultFromAction(async result => - { - assetListFromBlock.AddRange(result); - await FinalizeBlockAssetsPath(assetIndex, - assetListFromBlock, - senadinaResult, - token); - }); + { + assetListFromBlock.AddRange(result); + await FinalizeBlockAssetsPath(assetIndex, + assetListFromBlock, + senadinaResult, + token); + }); #endregion #region Run Task Continuation in Parallel @@ -397,10 +397,10 @@ await audioManifestIdentifier } private async Task EnsureAudioDefaultManifestExisted( - HttpClient client, + HttpClient client, FilePropertiesRemote? audioDefaultManifestAsset, - string audioDefaultManifestPath, - CancellationToken token) + string audioDefaultManifestPath, + CancellationToken token) { if (audioDefaultManifestAsset == null) { diff --git a/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Repair.Audio.cs b/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Repair.Audio.cs index cccec0330f..6cc5b3ac73 100644 --- a/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Repair.Audio.cs +++ b/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Repair.Audio.cs @@ -160,4 +160,4 @@ await Task.Factory void UpdatePatchProgress(object? sender, BinaryPatchProgress progress) => UpdateProgressCounter(progress.Read, 0); } -} +} \ No newline at end of file diff --git a/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Repair.Block.cs b/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Repair.Block.cs index d1bdbbb4bd..8ed983552b 100644 --- a/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Repair.Block.cs +++ b/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Repair.Block.cs @@ -61,8 +61,8 @@ private async ValueTask RepairAssetBlockType( .EnsureNoReadOnly() .StripAlternateDataStream(); - int bufferSize = patchInfo.PatchSize.GetFileStreamBufferSize(); - long loaded = 0; + int bufferSize = patchInfo.PatchSize.GetFileStreamBufferSize(); + long loaded = 0; await using (FileStream patchFileStream = patchOutputFileInfo.Open(FileMode.OpenOrCreate, diff --git a/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Repair.Generic.cs b/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Repair.Generic.cs index 905b650f37..dbf7137523 100644 --- a/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Repair.Generic.cs +++ b/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Repair.Generic.cs @@ -111,4 +111,4 @@ await RunDownloadTask(asset.S, // This is intended that we ignore DownloadProgress for now as the download size for "per-file" progress // is now being handled by this own class progress counter. private void ProgressRepairAssetGenericType(int read, DownloadProgress progress) => UpdateProgressCounter(read, read); -} +} \ No newline at end of file diff --git a/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Repair.cs b/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Repair.cs index a819cbd1fe..90ff964651 100644 --- a/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Repair.cs +++ b/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.Repair.cs @@ -1,5 +1,4 @@ -using CollapseLauncher.Extension; -using Hi3Helper; +using Hi3Helper; using Hi3Helper.Data; using Hi3Helper.Shared.ClassStruct; using Hi3Helper.Sophon; @@ -26,7 +25,7 @@ public async Task StartRepairRoutine( ResetStatusAndProgress(); // Set as completed - Status.ActivityStatus = Locale.Lang._GameRepairPage.Status7; + Status.ActivityStatus = Locale.Lang?._GameRepairPage?.Status7; // Update status and progress UpdateAll(); @@ -51,8 +50,8 @@ private async Task StartRepairRoutineCoreAsync(bool showInteractivePrompt } int threadNum = IsBurstDownloadEnabled - ? 1 - : ThreadForIONormalized; + ? ThreadForIONormalized + : 1; await Parallel.ForEachAsync(AssetIndex, new ParallelOptions @@ -79,16 +78,16 @@ async ValueTask Impl(FilePropertiesRemote asset, CancellationToken token) catch (HttpRequestException httpEx) { string message = "An HTTP error has occurred while trying to download this following asset:" + - $""" - Asset Path: {asset.N} - Asset Remote URL: {asset.RN} - Asset Size: {asset.S} - Asset Hash: {asset.CRC} - Type: {asset.FT} - Object Association: {(asset.AssociatedObject is var obj ? obj.GetType().Name : "GenericDownload")} - HTTP Status code: {httpEx.StatusCode} ({(int)(httpEx.StatusCode ?? default)}) - HTTP Error category: {httpEx.HttpRequestError} - """; + $""" + Asset Path: {asset.N} + Asset Remote URL: {asset.RN} + Asset Size: {asset.S} + Asset Hash: {asset.CRC} + Type: {asset.FT} + Object Association: {(asset.AssociatedObject is var obj ? obj.GetType().Name : "GenericDownload")} + HTTP Status code: {httpEx.StatusCode} ({(int)(httpEx.StatusCode ?? default)}) + HTTP Error category: {httpEx.HttpRequestError} + """; throw new HttpRequestException(httpEx.HttpRequestError, message, httpEx, httpEx.StatusCode); } } @@ -136,10 +135,9 @@ private void UpdateProgressCounter(long dataWrite, long downloadRead) return; } - double speedClamped = speedAll.ClampLimitedSpeedNumber(); TimeSpan timeLeftSpan = ConverterTool.ToTimeSpanRemain(ProgressAllSizeTotal, ProgressAllSizeCurrent, - speedClamped); + speedAll); double percentPerFile = ProgressPerFileSizeCurrent != 0 ? ConverterTool.ToPercentage(ProgressPerFileSizeTotal, ProgressPerFileSizeCurrent) @@ -157,7 +155,7 @@ private void UpdateProgressCounter(long dataWrite, long downloadRead) Progress.ProgressAllSizeTotal = ProgressAllSizeTotal; // Calculate speed - Progress.ProgressAllSpeed = speedClamped; + Progress.ProgressAllSpeed = speedAll; Progress.ProgressAllTimeLeft = timeLeftSpan; // Update current progress percentages @@ -171,14 +169,14 @@ private void UpdateProgressCounter(long dataWrite, long downloadRead) Status.IsProgressPerFileIndetermined = false; // Set time estimation string - string timeLeftString = string.Format(Locale.Lang._Misc.TimeRemainHMSFormat, Progress.ProgressAllTimeLeft); + string timeLeftString = string.Format(Locale.Lang?._Misc?.TimeRemainHMSFormat ?? "", Progress.ProgressAllTimeLeft); - Status.ActivityPerFile = string.Format(Locale.Lang._Misc.Speed, ConverterTool.SummarizeSizeSimple(speedPerFile)); - Status.ActivityAll = string.Format(Locale.Lang._GameRepairPage.PerProgressSubtitle2, + Status.ActivityPerFile = string.Format(Locale.Lang?._Misc?.Speed ?? "", ConverterTool.SummarizeSizeSimple(speedPerFile)); + Status.ActivityAll = string.Format(Locale.Lang?._GameRepairPage?.PerProgressSubtitle2 ?? "", ConverterTool.SummarizeSizeSimple(ProgressAllSizeCurrent), ConverterTool.SummarizeSizeSimple(ProgressAllSizeTotal)) + $" | {timeLeftString}" - + $" ({string.Format(Locale.Lang._Misc.Speed, ConverterTool.SummarizeSizeSimple(speedAll))})"; + + $" ({string.Format(Locale.Lang?._Misc?.Speed ?? "", ConverterTool.SummarizeSizeSimple(speedAll))})"; // Trigger update UpdateAll(); @@ -198,4 +196,4 @@ private void ResetProgressCounter() ProgressAllSizeCurrent = 0; ProgressPerFileSizeCurrent = 0; } -} +} \ No newline at end of file diff --git a/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.SenadinaExt.cs b/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.SenadinaExt.cs index 09edc16f8e..56f964ab5a 100644 --- a/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.SenadinaExt.cs +++ b/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.SenadinaExt.cs @@ -45,7 +45,7 @@ internal static async Task if (progressibleInstance != null) { progressibleInstance.Status.ActivityStatus = - string.Format(Locale.Lang._CachesPage.CachesStatusFetchingType, "Senadina Files"); + string.Format(Locale.Lang?._CachesPage?.CachesStatusFetchingType ?? "", "Senadina Files"); progressibleInstance.Status.IsProgressAllIndetermined = true; progressibleInstance.Status.IsIncludePerFileIndicator = false; progressibleInstance.UpdateStatus(); @@ -154,7 +154,7 @@ private static async Task try { string origFileRelativePath = $"{gameVersion.Major}_{gameVersion.Minor}_{kind.ToString().ToLower()}"; - string hashedRelativePath = SenadinaFileIdentifier.GetHashedString(origFileRelativePath); + string hashedRelativePath = SenadinaFileIdentifier.GetHashedString(origFileRelativePath); string fileUrl = mainUrl.CombineURLFromString(hashedRelativePath); if (!dict.TryGetValue(origFileRelativePath, out SenadinaFileIdentifier? identifier)) @@ -166,8 +166,8 @@ private static async Task "Please contact us in GitHub issues or Discord to let us know about this issue."); } - CDNCacheResult result = await client.TryGetCachedStreamFrom(fileUrl, token: token); - Stream networkStream = result.Stream; + CDNCacheResult result = await client.TryGetCachedStreamFrom(fileUrl, token: token); + Stream networkStream = result.Stream; await ThrowIfFileIsNotSenadina(networkStream, token); identifier.fileStream = SenadinaFileIdentifier.CreateKangBakso(networkStream, identifier.lastIdentifier!, origFileRelativePath, (int)identifier.fileTime); @@ -203,8 +203,8 @@ private static async Task?> await ThrowIfFileIsNotSenadina(fileIdentifierStream, token); #if DEBUG - using StreamReader rd = new StreamReader(fileIdentifierStreamDecoder); - string response = await rd.ReadToEndAsync(token); + using StreamReader rd = new StreamReader(fileIdentifierStreamDecoder); + string response = await rd.ReadToEndAsync(token); Logger.LogWriteLine($"[HonkaiRepair::GetSenadinaIdentifierDictionary() Dictionary Response:\r\n{response}", LogType.Debug, true); return response.Deserialize(SenadinaJsonContext.Default.DictionaryStringSenadinaFileIdentifier); #else @@ -222,4 +222,4 @@ private static async Task?> return await GetSenadinaManifestAsync(client, null, secondaryUrl, true, token); } } -} +} \ No newline at end of file diff --git a/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.cs b/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.cs index 015e1b97a9..5c8c790fe9 100644 --- a/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.cs +++ b/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.cs @@ -78,20 +78,20 @@ public HonkaiRepairV2( .UseLauncherConfig(DownloadThreadCount * DownloadThreadCount) .SetAllowedDecompression(DecompressionMethods.None) .SetUserAgent(AssetBundleUserAgent) - #if AOT +#if AOT .SetHttpVersion(HttpVersion.Version20) - #else +#else .SetHttpVersion(HttpVersion.Version30) - #endif +#endif .Create(); HttpClientGeneric = new HttpClientBuilder() .UseLauncherConfig(DownloadThreadCount * DownloadThreadCount) - #if AOT +#if AOT .SetHttpVersion(HttpVersion.Version20) - #else +#else .SetHttpVersion(HttpVersion.Version30) - #endif +#endif .Create(); } @@ -113,4 +113,4 @@ public void CancelRoutine() Token?.Dispose(); Token = null; } -} +} \ No newline at end of file From d089ad1a34674d89b31c615317f1ad60ff2e33a3 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Mon, 1 Jun 2026 22:49:38 +0700 Subject: [PATCH 14/15] [Hi3 Game Repair] Fix CN wrong VA files downloaded --- .../HonkaiV2/HonkaiRepairV2.AsbExt.Cache.cs | 31 +++++++++---------- .../HonkaiV2/HonkaiRepairV2.AsbExt.Video.cs | 6 ++-- 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.AsbExt.Cache.cs b/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.AsbExt.Cache.cs index 4bcb06dffc..462c8cc2c5 100644 --- a/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.AsbExt.Cache.cs +++ b/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.AsbExt.Cache.cs @@ -367,26 +367,23 @@ internal static async Task GetGameServerInfoAsync( private static AudioLanguageType GetCurrentGameAudioLanguage(PresetConfig presetConfig) { using RegistryKey? rootRegistryKey = Registry.CurrentUser.OpenSubKey(presetConfig.ConfigRegistryLocation); - if (rootRegistryKey?.GetValue(PersonalAudioSetting.ValueName) is not byte[] jsonValue) - { - return presetConfig.GameDefaultCVLanguage; - } + return GetAudioLanguageTypeFromString((rootRegistryKey?.GetValue(PersonalAudioSetting.ValueName) as byte[])? + .Deserialize(HonkaiSettingsJsonContext.Default.PersonalAudioSetting)?._userCVLanguage) + ?? presetConfig.GameDefaultCVLanguage; - PersonalAudioSetting? audioSetting = - jsonValue.Deserialize(HonkaiSettingsJsonContext.Default.PersonalAudioSetting); - if (audioSetting == null) + static AudioLanguageType? GetAudioLanguageTypeFromString(string? lang) { - return presetConfig.GameDefaultCVLanguage; - } + if (lang?.StartsWith("Japanese") ?? false) + { + return AudioLanguageType.Japanese; + } - if (audioSetting - ._userCVLanguage? - .StartsWith("Chinese", StringComparison.OrdinalIgnoreCase) ?? false) - { - return AudioLanguageType.Chinese; - } + if (lang?.StartsWith("Chinese") ?? false) + { + return AudioLanguageType.Chinese; + } - // Use default value based on preset. - return presetConfig.GameDefaultCVLanguage; + return null; + } } } \ No newline at end of file diff --git a/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.AsbExt.Video.cs b/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.AsbExt.Video.cs index 1a168094d5..7c0db02fad 100644 --- a/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.AsbExt.Video.cs +++ b/CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.AsbExt.Video.cs @@ -34,8 +34,8 @@ internal static partial class AssetBundleExtension internal static void RemoveUnlistedVideoAssetFromList(this List originList, List assetListFromVideo) { - List originOthersListOnly = originList.Where(x => x.FT != FileType.Video).ToList(); - List originVideoListOnly = originList.Where(x => x.FT == FileType.Video).ToList(); + List originOthersListOnly = [.. originList.Where(x => x.FT != FileType.Video)]; + List originVideoListOnly = [.. originList.Where(x => x.FT == FileType.Video)]; originList.Clear(); originList.AddRange(originOthersListOnly); @@ -60,7 +60,7 @@ internal static async Task> GameVersion currentVersion = progressibleInstance.GameVersion; - HashSet ignoredCgHashset = new(ignoredCgIds ?? []); + HashSet ignoredCgHashset = [.. ignoredCgIds ?? []]; List assetInfoList = await assetBundleHttpClient .GetCacheAssetBundleListAsync(presetConfig, From 2cf92eecd34d1914f0dc5172d54e6862fdc502b6 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Fri, 5 Jun 2026 23:19:51 +0700 Subject: [PATCH 15/15] Fix compile error --- .../StarRailV2/StarRailPersistentRefResult.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CollapseLauncher/Classes/RepairManagement/StarRailV2/StarRailPersistentRefResult.cs b/CollapseLauncher/Classes/RepairManagement/StarRailV2/StarRailPersistentRefResult.cs index 040919b22d..da4d554e98 100644 --- a/CollapseLauncher/Classes/RepairManagement/StarRailV2/StarRailPersistentRefResult.cs +++ b/CollapseLauncher/Classes/RepairManagement/StarRailV2/StarRailPersistentRefResult.cs @@ -541,9 +541,9 @@ static async ValueTask static Stream #endif CreateLocalStream(Stream thisSourceStream, - string filePath, + string filePath #if DEBUG - CancellationToken token) + , CancellationToken token) #else ) #endif