Compare commits

..

11 Commits

Author SHA1 Message Date
DismissedLight
48ddb4c091 code style 2023-12-24 21:50:47 +08:00
qhy040404
ea95f2e2b1 say goodbye to powershell 2023-12-24 17:09:49 +08:00
DismissedLight
93077104b8 direct set registry value 2023-12-24 13:52:06 +08:00
DismissedLight
3ffdc901c7 fix server convert set game path null 2023-12-24 12:52:06 +08:00
DismissedLight
0d66c85744 remove redundant element 2023-12-23 20:42:35 +08:00
DismissedLight
d293149672 1.9.1 package 2023-12-23 19:18:29 +08:00
DismissedLight
3784df67a3 adjust launch page ui 2023-12-23 19:15:04 +08:00
DismissedLight
4aaca4d19f fix reentrant issue 2023-12-23 18:51:41 +08:00
DismissedLight
e6cf39831d fix daily note fetch uid crash 2023-12-23 18:22:12 +08:00
DismissedLight
24a2a18760 fix #1212 2023-12-23 17:34:44 +08:00
DismissedLight
d8dce5c062 empty sha256 tolerance 2023-12-23 14:48:24 +08:00
24 changed files with 115 additions and 257 deletions

View File

@@ -22,7 +22,7 @@ body:
- label: 我知道文档站的导航栏中有**搜索功能**,且已经搜索过相关关键词
required: true
- label: 我的问题不是[已完成](https://github.com/DGP-Studio/Snap.Hutao/issues?q=is%3Aopen+is%3Aissue+label%3A%E5%B7%B2%E5%AE%8C%E6%88%90)的问题也不是一个别人已发布的**重复的**问题
- label: 我的问题不是[已修复](https://github.com/DGP-Studio/Snap.Hutao/issues?q=is%3Aopen+is%3Aissue+label%3A%E5%B7%B2%E4%BF%AE%E5%A4%8D)的问题也不是一个别人已发布的**重复的**问题
required: true
- type: input
@@ -51,7 +51,7 @@ body:
description: |
在胡桃工具箱的设置界面,你可以找到并复制你的设备 ID
如果你的问题涉及程序崩溃,请填写该项,这将有助于我们定位问题
如果你的程序已经无法启动,请下载并运行[此工具](https://github.com/DGP-Automation/ISSUE_TEMPLATES/releases/download/diagnosis_tools/Snap.Hutao.DiagTools.exe),它将显示你的设备 ID
如果你的程序已经无法启动,请下载并运行[此PowerShell脚本](https://github.com/DGP-Studio/ISSUE_TEMPLATES/releases/download/get_device_id/GetHutaoDeviceId.ps1),它将显示你的设备 ID
validations:
required: false
@@ -87,7 +87,7 @@ body:
label: 发生了什么?
description: |
详细的描述问题发生前后的行为,以便我们解决问题。**如果你的问题涉及程序崩溃,你应当检查 Windows 事件查看器,并将相关的 `.Net 错误`详情附上**
如果你无法找到该日志,请下载并运行[此工具](https://github.com/DGP-Automation/ISSUE_TEMPLATES/releases/download/diagnosis_tools/Snap.Hutao.DiagTools.exe),它将转储问题日志至工具运行目录中的 `Snap.Hutao Error Log.txt`
如果你无法找到该日志,请下载并运行[此PowerShell脚本](https://github.com/DGP-Studio/ISSUE_TEMPLATES/releases/download/dump_log_script/dump_log_zh.ps1),它将输出错误日志
validations:
required: true

View File

@@ -22,7 +22,7 @@ body:
- label: I and tried **search feature** in Snap Hutao document site, and no associated article
required: true
- label: My issue is not a [finished issue](https://github.com/DGP-Studio/Snap.Hutao/issues?q=is%3Aopen+is%3Aissue+label%3A%E5%B7%B2%E5%AE%8C%E6%88%90), and it's not a duplicated issue
- label: My issue is not a [fixed issue](https://github.com/DGP-Studio/Snap.Hutao/issues?q=is%3Aopen+is%3Aissue+label%3A%E5%B7%B2%E4%BF%AE%E5%A4%8D), and it's not a duplicated issue
required: true
- type: input
@@ -51,7 +51,7 @@ body:
description: |
In Snap Hutao's settings page, you can find and copy your device ID
If your issue is about program crash, please fill this so we can dump the log and locate the source easier
If your program cannot startup, please download and run [this tool](https://github.com/DGP-Automation/ISSUE_TEMPLATES/releases/download/diagnosis_tools/Snap.Hutao.DiagTools.exe), it will shows your device ID.
If your program cannot startup, please download and run [this PowerShell script](https://github.com/DGP-Studio/ISSUE_TEMPLATES/releases/download/get_device_id/GetHutaoDeviceId.ps1), it will shows your device ID.
validations:
required: false
@@ -87,7 +87,7 @@ body:
label: What Happened?
description: |
Describe your issue in detail to help us identify the issue. **If your issue is about program crash, you should check Windows Event Viewer, and attach associated `.Net Error` details here**If your program cannot startup, please download and run [this PowerShell script](https://github.com/DGP-Studio/ISSUE_TEMPLATES/releases/download/get_device_id/GetHutaoDeviceId.ps1), it will shows your device ID.
If you cannot find it, please download and run [this tool](https://github.com/DGP-Automation/ISSUE_TEMPLATES/releases/download/diagnosis_tools/Snap.Hutao.DiagTools.exe), it will dump the error log to `Snap.Hutao Error Log.txt` in the working directory of the tool.
If you cannot find it, please download and run [this PowerShell script](https://github.com/DGP-Studio/ISSUE_TEMPLATES/releases/download/dump_log_script/dump_log_en.ps1), it will dump the error log.
validations:
required: true

View File

@@ -12,32 +12,50 @@ body:
value: |
## 创建版本
- [ ] 同步一次 [Crowdin](https://crowdin.com/project/snap-hutao) 翻译
- [ ] 发布 RC 版本Optional
- [ ] 合并入主分支
- [ ] 整理更新内容,等待翻译
- [ ] 打包
- [ ] 提交微软商店
- [ ] 包含更新日志
- [ ] 在 [Snap.Hutao.Docs@next-patch](https://github.com/DGP-Studio/Snap.Hutao.Docs/tree/next-patch) 分支更新文档并直接开 PR
- [ ] 更新日志
- [ ] 功能文档更新
## 发布版本 [半自动]
- [ ] 在 GitHub 个人设置中更新 [Publish-Automate Beta PAT](https://github.com/settings/tokens?type=beta),有效期需小于预计发版需要天数
- [ ] 将更新的 PAT 更新至 Publish-Automate 库的 [Actions Secrets](https://github.com/DGP-Automation/Publish-Automate/settings/secrets/actions) 中
- [ ] 将更新的 PAT 更新至 Publish-Automate 库的 [Actions Secrets](https://github.com/DGP-Studio/Publish-Automate/settings/secrets/actions) 中
***
- [ ] 主分支合并入 release 分支
- [ ] 等待 Release 自动发布
- [ ] 检查极狐是否同步完成 Release
- [ ] 通知用户
- [ ] 运行 [Auto Publish Action](https://github.com/DGP-Studio/Publish-Automate/actions/workflows/auto-publish.yml)
- [ ] 在 https://store.rg-adguard.net/ 下载新版本安装包
- [ ] Store URL: https://apps.microsoft.com/store/detail/snap-hutao/9PH4NXJ2JN52
- [ ] 命名格式为 `Snap.Hutao x.x.x.msix`
- [ ] Merge 文档 PR
- [ ] 发布 Release
- [ ] 更新日志格式(以 1.6.2 版本为例)
```jsx
## Update log
https://hut.ao/en/statements/update-log.html#_1-6-2
## 更新日志
[此处从文档复制]
## What's Changed
**Full Changelog**: https://github.com/DGP-Studio/Snap.Hutao/compare/1.6.0...1.6.2
```
- [ ] 通知用户
- type: checkboxes
id: checklist-final
attributes:
label: Final Check
description: Understand what you are doing
description: Understand what you are doing
options:
- label: I understand that I will get banned from repository if I don't have permission to use this template
required: true
required: true

View File

@@ -1,62 +0,0 @@
stages:
- fetch
- release
Fetch:
stage: fetch
rules:
- if: $CI_COMMIT_TAG
tags:
- us3
script:
- apt-get update -qy
- apt-get install -y curl jq
- RELEASE_INFO=$(curl -sSL "https://api.github.com/repos/$CI_PROJECT_PATH/releases/latest")
- ASSET_URL=$(echo "$RELEASE_INFO" | jq -r '.assets[] | select(.name | endswith(".msix")) | .browser_download_url')
- SHA256SUMS_URL=$(echo "$RELEASE_INFO" | jq -r '.assets[] | select(.name == "SHA256SUMS") | .browser_download_url')
- curl -LJO "$ASSET_URL"
- curl -LJO "$SHA256SUMS_URL"
- FILE_NAME=$(basename "$ASSET_URL")
- SHA256SUMS_NAME=$(basename "$SHA256SUMS_URL")
- echo "File name at script stage is $FILE_NAME"
- echo "SHA256SUMS name at script stage is $SHA256SUMS_NAME"
- echo "THIS_FILE_NAME=$FILE_NAME" >> next.env
- echo "THIS_SHA256SUMS_NAME=$SHA256SUMS_NAME" >> next.env
after_script:
- echo "Current Job ID is $CI_JOB_ID"
- echo "THIS_JOB_ID=$CI_JOB_ID" >> next.env
artifacts:
paths:
- "*.msix"
- "SHA256SUMS"
expire_in: 180 days
reports:
dotenv: next.env
release:
stage: release
image: registry.gitlab.com/gitlab-org/release-cli:latest
rules:
- if: $CI_COMMIT_TAG
needs:
- job: Fetch
artifacts: true
variables:
TAG: '$CI_COMMIT_TAG'
script:
- echo "Create Release $TAG"
- echo "$THIS_JOB_ID"
- echo "$THIS_FILE_NAME"
release:
name: '$TAG'
tag_name: '$TAG'
ref: '$TAG'
description: 'Release $TAG by CI'
assets:
links:
- name: "$THIS_FILE_NAME"
url: "https://$CI_SERVER_SHELL_SSH_HOST/$CI_PROJECT_PATH/-/jobs/$THIS_JOB_ID/artifacts/raw/$THIS_FILE_NAME?inline=false"
link_type: package
- name: "$THIS_SHA256SUMS_NAME"
url: "https://$CI_SERVER_SHELL_SSH_HOST/$CI_PROJECT_PATH/-/jobs/$THIS_JOB_ID/artifacts/raw/$THIS_SHA256SUMS_NAME?inline=false"
link_type: other

View File

@@ -61,6 +61,7 @@ FileSaveDialog
IFileOpenDialog
IFileSaveDialog
IPersistFile
IShellLinkDataList
IShellLinkW
ShellLink
SHELL_LINK_DATA_FLAGS
@@ -69,6 +70,7 @@ SHELL_LINK_DATA_FLAGS
IMemoryBufferByteAccess
// Const value
E_FAIL
INFINITE
RPC_E_WRONG_THREAD
MAX_PATH

View File

@@ -31,4 +31,5 @@
<x:String x:Key="UI_EmotionIcon250">https://api.snapgenshin.com/static/raw/EmotionIcon/UI_EmotionIcon250.png</x:String>
<x:String x:Key="UI_EmotionIcon272">https://api.snapgenshin.com/static/raw/EmotionIcon/UI_EmotionIcon272.png</x:String>
<x:String x:Key="UI_EmotionIcon293">https://api.snapgenshin.com/static/raw/EmotionIcon/UI_EmotionIcon293.png</x:String>
<x:String x:Key="UI_EmotionIcon445">https://api.snapgenshin.com/static/raw/EmotionIcon/UI_EmotionIcon445.png</x:String>
</ResourceDictionary>

View File

@@ -1,7 +1,6 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Service;
using System.IO;
using System.Runtime.InteropServices;
using Windows.Storage;
@@ -19,7 +18,6 @@ namespace Snap.Hutao.Core.Shell;
internal sealed partial class ShellLinkInterop : IShellLinkInterop
{
private readonly RuntimeOptions runtimeOptions;
private readonly AppOptions appOptions;
public async ValueTask<bool> TryCreateDesktopShoutcutForElevatedLaunchAsync()
{
@@ -45,12 +43,15 @@ internal sealed partial class ShellLinkInterop : IShellLinkInterop
HRESULT result = CoCreateInstance<ShellLink, IShellLinkW>(null, CLSCTX.CLSCTX_INPROC_SERVER, out IShellLinkW shellLink);
Marshal.ThrowExceptionForHR(result);
shellLink.SetPath(appOptions.PowerShellPath);
shellLink.SetArguments($"""
-Command "Start-Process shell:AppsFolder\{runtimeOptions.FamilyName}!App -verb runas"
""");
shellLink.SetShowCmd(SHOW_WINDOW_CMD.SW_SHOWMINNOACTIVE);
shellLink.SetPath($"shell:AppsFolder\\{runtimeOptions.FamilyName}!App");
shellLink.SetShowCmd(SHOW_WINDOW_CMD.SW_NORMAL);
shellLink.SetIconLocation(targetLogoPath, 0);
IShellLinkDataList shellLinkDataList = (IShellLinkDataList)shellLink;
shellLinkDataList.GetFlags(out uint flags);
flags |= (uint)SHELL_LINK_DATA_FLAGS.SLDF_RUNAS_USER;
shellLinkDataList.SetFlags(flags);
string desktop = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
string target = Path.Combine(desktop, $"{SH.FormatAppNameAndVersion(runtimeOptions.Version)}.lnk");

View File

@@ -1,19 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using System.Collections.Concurrent;
using System.Runtime.CompilerServices;
namespace Snap.Hutao.Core.Threading;
internal sealed class Throttler
{
private readonly ConcurrentDictionary<string, SemaphoreSlim> methodSemaphoreMap = new();
public ValueTask<SemaphoreSlimToken> ThrottleAsync(CancellationToken token = default, [CallerMemberName] string callerName = default!, [CallerLineNumber] int callerLine = 0)
{
string key = $"{callerName}L{callerLine}";
SemaphoreSlim semaphore = methodSemaphoreMap.GetOrAdd(key, name => new SemaphoreSlim(1));
return semaphore.EnterAsync(token);
}
}

View File

@@ -2,9 +2,7 @@
// Licensed under the MIT license.
using Microsoft.UI.Xaml;
using Snap.Hutao.Control;
using Snap.Hutao.Core.Windowing;
using Windows.Foundation;
using Windows.Win32.UI.WindowsAndMessaging;
namespace Snap.Hutao;

View File

@@ -15,9 +15,7 @@ internal sealed partial class SettingEntry
public const string GamePathEntries = "GamePathEntries";
/// <summary>
/// PowerShell 路径
/// </summary>
[Obsolete("不再使用 PowerShell")]
public const string PowerShellPath = "PowerShellPath";
/// <summary>

View File

@@ -4,20 +4,22 @@
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10"
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
xmlns:desktop6="http://schemas.microsoft.com/appx/manifest/desktop/windows10/6"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
IgnorableNamespaces="com uap desktop rescap mp">
IgnorableNamespaces="com uap desktop desktop6 rescap mp">
<Identity
Name="60568DGPStudio.SnapHutao"
Publisher="CN=35C8E923-85DF-49A7-9172-B39DC6312C52"
Version="1.9.0.0" />
Version="1.9.1.0" />
<Properties>
<DisplayName>Snap Hutao</DisplayName>
<PublisherDisplayName>DGP Studio</PublisherDisplayName>
<Logo>Assets\StoreLogo.png</Logo>
<desktop6:RegistryWriteVirtualization>disabled</desktop6:RegistryWriteVirtualization>
</Properties>
<Dependencies>
@@ -64,5 +66,6 @@
<Capabilities>
<rescap:Capability Name="runFullTrust"/>
<rescap:Capability Name="unvirtualizedResources"/>
</Capabilities>
</Package>

View File

@@ -4,20 +4,22 @@
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10"
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
xmlns:desktop6="http://schemas.microsoft.com/appx/manifest/desktop/windows10/6"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
IgnorableNamespaces="com uap desktop rescap mp">
IgnorableNamespaces="com uap desktop desktop6 rescap mp">
<Identity
Name="60568DGPStudio.SnapHutaoDev"
Publisher="CN=35C8E923-85DF-49A7-9172-B39DC6312C52"
Version="1.9.0.0" />
Version="1.9.1.0" />
<Properties>
<DisplayName>Snap Hutao Dev</DisplayName>
<PublisherDisplayName>DGP Studio</PublisherDisplayName>
<Logo>Assets\StoreLogo.png</Logo>
<desktop6:RegistryWriteVirtualization>disabled</desktop6:RegistryWriteVirtualization>
</Properties>
<Dependencies>
@@ -64,5 +66,6 @@
<Capabilities>
<rescap:Capability Name="runFullTrust"/>
<rescap:Capability Name="unvirtualizedResources"/>
</Capabilities>
</Package>

View File

@@ -186,9 +186,6 @@
<data name="FilePickerImportCommit" xml:space="preserve">
<value>导入</value>
</data>
<data name="FilePickerPowerShellCommit" xml:space="preserve">
<value>选择 PowerShell</value>
</data>
<data name="GuideWindowTitle" xml:space="preserve">
<value>欢迎使用胡桃</value>
</data>
@@ -932,9 +929,6 @@
<data name="ServiceGameRegisteryInteropLongPathsDisabled" xml:space="preserve">
<value>未开启长路径功能,无法设置注册表键值</value>
</data>
<data name="ServiceGameRegisteryInteropPowershellNotFound" xml:space="preserve">
<value>找不到 PowerShell 的安装目录</value>
</data>
<data name="ServiceGameSetMultiChannelConfigFileNotFound" xml:space="preserve">
<value>无法读取游戏配置文件 {0},可能是文件不存在</value>
</data>
@@ -2144,6 +2138,9 @@
<data name="ViewPageLaunchGameResourcePreDownloadHeader" xml:space="preserve">
<value>预下载</value>
</data>
<data name="ViewPageLaunchGameSelectGamePath" xml:space="preserve">
<value>选择游戏路径</value>
</data>
<data name="ViewPageLaunchGameSwitchAccountAttachUidNull" xml:space="preserve">
<value>该账号尚未绑定实时便笺通知 UID</value>
</data>
@@ -2432,12 +2429,6 @@
<data name="ViewPageSettingSetGamePathHint" xml:space="preserve">
<value>设置游戏路径时请选择游戏本体YuanShen.exe 或 GenshinImpact.exe而不是启动器launcher.exe</value>
</data>
<data name="ViewPageSettingSetPowerShellDescription" xml:space="preserve">
<value>胡桃使用 PowerShell 更改注册表中的信息以修改游戏内账号</value>
</data>
<data name="ViewPageSettingSetPowerShellPathHeader" xml:space="preserve">
<value>PowerShell 路径</value>
</data>
<data name="ViewPageSettingShellExperienceHeader" xml:space="preserve">
<value>Shell 体验</value>
</data>

View File

@@ -16,42 +16,12 @@ namespace Snap.Hutao.Service;
[Injection(InjectAs.Singleton)]
internal sealed partial class AppOptions : DbStoreOptions
{
private string? powerShellPath;
private bool? isEmptyHistoryWishVisible;
private BackdropType? backdropType;
private CultureInfo? currentCulture;
private Region? region;
private string? geetestCustomCompositeUrl;
public string PowerShellPath
{
get
{
return GetOption(ref powerShellPath, SettingEntry.PowerShellPath, GetDefaultPowerShellLocationOrEmpty);
static string GetDefaultPowerShellLocationOrEmpty()
{
string? paths = Environment.GetEnvironmentVariable("Path");
if (!string.IsNullOrEmpty(paths))
{
foreach (StringSegment path in new StringTokenizer(paths, [';']))
{
if (path is { HasValue: true, Length: > 0 })
{
if (path.Value.Contains("WindowsPowerShell", StringComparison.OrdinalIgnoreCase))
{
return Path.Combine(path.Value, "powershell.exe");
}
}
}
}
return string.Empty;
}
}
set => SetOption(ref powerShellPath, SettingEntry.PowerShellPath, value);
}
public bool IsEmptyHistoryWishVisible
{
get => GetOption(ref isEmptyHistoryWishVisible, SettingEntry.IsEmptyHistoryWishVisible);

View File

@@ -77,7 +77,7 @@ internal sealed partial class DailyNoteService : IDailyNoteService, IRecipient<U
List<DailyNoteEntry> entryList = await dailyNoteDbService.GetDailyNoteEntryIncludeUserListAsync().ConfigureAwait(false);
entryList.ForEach(entry => { entry.UserGameRole = userService.GetUserGameRoleByUid(entry.Uid); });
entries = new(entryList);
entries = entryList.ToObservableCollection();
}
return entries;

View File

@@ -16,7 +16,6 @@ internal sealed partial class GameAccountService : IGameAccountService
private readonly IContentDialogFactory contentDialogFactory;
private readonly IGameDbService gameDbService;
private readonly ITaskContext taskContext;
private readonly AppOptions appOptions;
private ObservableCollection<GameAccount>? gameAccounts;
@@ -90,12 +89,7 @@ internal sealed partial class GameAccountService : IGameAccountService
public bool SetGameAccount(GameAccount account)
{
if (string.IsNullOrEmpty(appOptions.PowerShellPath))
{
ThrowHelper.RuntimeEnvironment(SH.ServiceGameRegisteryInteropPowershellNotFound, default!);
}
return RegistryInterop.Set(account, appOptions.PowerShellPath);
return RegistryInterop.Set(account);
}
public void AttachGameAccountToUid(GameAccount gameAccount, string uid)

View File

@@ -20,48 +20,16 @@ internal static class RegistryInterop
private const string GenshinKey = $@"HKEY_CURRENT_USER\{GenshinPath}";
private const string SdkChineseKey = "MIHOYOSDK_ADL_PROD_CN_h3123967166";
/// <summary>
/// 设置键值
/// 需要支持
/// https://learn.microsoft.com/zh-cn/windows/win32/fileio/maximum-file-path-limitation
/// </summary>
/// <param name="account">账户</param>
/// <param name="powerShellPath">PowerShell 路径</param>
/// <returns>账号是否设置</returns>
public static bool Set(GameAccount? account, string powerShellPath)
public static bool Set(GameAccount? account)
{
if (account is not null)
{
// 存回注册表的字节需要 '\0' 结尾
Encoding.UTF8.GetByteCount(account.MihoyoSDK);
byte[] tempBytes = Encoding.UTF8.GetBytes(account.MihoyoSDK);
byte[] target = new byte[tempBytes.Length + 1];
tempBytes.CopyTo(target, 0);
byte[] target = [.. Encoding.UTF8.GetBytes(account.MihoyoSDK), 0];
Registry.SetValue(GenshinKey, SdkChineseKey, target);
string base64 = Convert.ToBase64String(target);
string path = $"HKCU:{GenshinPath}";
string command = $"""
-Command "$value = [Convert]::FromBase64String('{base64}'); Set-ItemProperty -Path '{path}' -Name '{SdkChineseKey}' -Value $value -Force;"
""";
ProcessStartInfo startInfo = new()
{
Arguments = command,
WorkingDirectory = Path.GetDirectoryName(powerShellPath),
CreateNoWindow = true,
FileName = powerShellPath,
};
try
{
System.Diagnostics.Process.Start(startInfo)?.WaitForExit();
}
catch (Win32Exception ex)
{
ThrowHelper.RuntimeEnvironment(SH.ServiceGameRegisteryInteropLongPathsDisabled, ex);
}
if (Get() == account.MihoyoSDK)
string? get = Get();
if (get == account.MihoyoSDK)
{
return true;
}
@@ -70,10 +38,6 @@ internal static class RegistryInterop
return false;
}
/// <summary>
/// 在注册表中获取账号信息
/// </summary>
/// <returns>当前注册表中的信息</returns>
public static unsafe string? Get()
{
object? sdk = Registry.GetValue(GenshinKey, SdkChineseKey, Array.Empty<byte>());

View File

@@ -49,7 +49,7 @@ internal sealed partial class UpdateService : IUpdateService
progress.Report(new(versionInformation.Version.ToString(), 0, 0));
if (versionInformation.Sha256 is not { } sha256)
if (versionInformation.Sha256 is not { Length: > 0 } sha256)
{
return false;
}

View File

@@ -14,7 +14,7 @@ namespace Snap.Hutao.Service.User;
[ConstructorGenerated]
[Injection(InjectAs.Singleton, typeof(IUserCollectionService))]
internal sealed partial class UserCollectionService : IUserCollectionService
internal sealed partial class UserCollectionService : IUserCollectionService, IDisposable
{
private readonly ScopedDbCurrent<BindingUser, Model.Entity.User, UserChangedMessage> dbCurrent;
private readonly IUserInitializationService userInitializationService;
@@ -22,7 +22,7 @@ internal sealed partial class UserCollectionService : IUserCollectionService
private readonly ITaskContext taskContext;
private readonly IMessenger messenger;
private readonly Throttler throttler = new();
private readonly SemaphoreSlim throttler = new(1);
private ObservableCollection<BindingUser>? userCollection;
private Dictionary<string, BindingUser>? midUserMap;
@@ -38,7 +38,9 @@ internal sealed partial class UserCollectionService : IUserCollectionService
public async ValueTask<ObservableCollection<BindingUser>> GetUserCollectionAsync()
{
using (await throttler.ThrottleAsync().ConfigureAwait(false))
// Force run in background thread, otherwise will cause reentrance
await Task.CompletedTask.ConfigureAwait(ConfigureAwaitOptions.ForceYielding);
using (await throttler.EnterAsync().ConfigureAwait(false))
{
if (userCollection is null)
{
@@ -131,17 +133,7 @@ internal sealed partial class UserCollectionService : IUserCollectionService
return default;
}
try
{
return uidUserGameRoleMap[uid];
}
catch (InvalidOperationException)
{
// Sequence contains more than one matching element
// TODO: return a specialize UserGameRole to indicate error
}
return default;
return uidUserGameRoleMap.GetValueOrDefault(uid);
}
public bool TryGetUserByMid(string mid, [NotNullWhen(true)] out BindingUser? user)
@@ -186,4 +178,9 @@ internal sealed partial class UserCollectionService : IUserCollectionService
ArgumentNullException.ThrowIfNull(newUser.UserInfo);
return new(UserOptionResult.Added, newUser.UserInfo.Uid);
}
public void Dispose()
{
throttler.Dispose();
}
}

View File

@@ -13,6 +13,7 @@
xmlns:shcb="using:Snap.Hutao.Control.Behavior"
xmlns:shccs="using:Snap.Hutao.Control.Collection.Selector"
xmlns:shch="using:Snap.Hutao.Control.Helper"
xmlns:shci="using:Snap.Hutao.Control.Image"
xmlns:shcm="using:Snap.Hutao.Control.Markup"
xmlns:shvc="using:Snap.Hutao.View.Control"
xmlns:shvg="using:Snap.Hutao.ViewModel.Game"
@@ -346,10 +347,20 @@
</Grid>
<Grid Visibility="{Binding GamePathSelectedAndValid, Converter={StaticResource BoolToVisibilityRevertConverter}}">
<StackPanel
MaxWidth="600"
Margin="128,0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Spacing="3">
<shci:CachedImage
Width="120"
Height="120"
EnableLazyLoading="False"
Source="{StaticResource UI_EmotionIcon445}"/>
<TextBlock
Margin="0,5,0,21"
HorizontalAlignment="Center"
Style="{StaticResource SubtitleTextBlockStyle}"
Text="{shcm:ResourceString Name=ViewPageLaunchGameSelectGamePath}"/>
<Border Style="{ThemeResource BorderCardStyle}">
<ListView
ItemTemplate="{StaticResource GamePathEntryListTemplate}"
@@ -364,9 +375,7 @@
HeaderIcon="{shcm:FontIcon Glyph=&#xE7FC;}"
IsClickEnabled="True">
<cwc:SettingsCard.Description>
<StackPanel>
<TextBlock Foreground="{ThemeResource SystemErrorTextColor}" Text="{shcm:ResourceString Name=ViewPageSettingSetGamePathHint}"/>
</StackPanel>
<TextBlock Foreground="{ThemeResource SystemErrorTextColor}" Text="{shcm:ResourceString Name=ViewPageSettingSetGamePathHint}"/>
</cwc:SettingsCard.Description>
</cwc:SettingsCard>
</StackPanel>

View File

@@ -136,17 +136,17 @@
Background="{ThemeResource SystemFillColorSuccessBackgroundBrush}"
Description="{shcm:ResourceString Name=ViewPageSettingHutaoPassportLicensedDeveloperDescription}"
Header="{shcm:ResourceString Name=ViewPageSettingHutaoPassportLicensedDeveloperHeader}"
Visibility="{Binding UserOptions.IsLicensedDeveloper, Converter={StaticResource BoolToVisibilityConverter}}"/>
<cwc:SettingsCard
Background="{ThemeResource SystemFillColorSuccessBackgroundBrush}"
Description="{shcm:ResourceString Name=ViewPageSettingHutaoPassportMaintainerDescription}"
Header="{shcm:ResourceString Name=ViewPageSettingHutaoPassportMaintainerHeader}"
Visibility="{Binding UserOptions.IsMaintainer, Converter={StaticResource BoolToVisibilityConverter}}">
Visibility="{Binding UserOptions.IsLicensedDeveloper, Converter={StaticResource BoolToVisibilityConverter}}">
<Button
Command="{Binding OpenTestPageCommand}"
Content="TEST"
Style="{ThemeResource SettingButtonStyle}"/>
</cwc:SettingsCard>
<cwc:SettingsCard
Background="{ThemeResource SystemFillColorSuccessBackgroundBrush}"
Description="{shcm:ResourceString Name=ViewPageSettingHutaoPassportMaintainerDescription}"
Header="{shcm:ResourceString Name=ViewPageSettingHutaoPassportMaintainerHeader}"
Visibility="{Binding UserOptions.IsMaintainer, Converter={StaticResource BoolToVisibilityConverter}}"/>
<cwc:SettingsCard Description="{Binding UserOptions.GachaLogExpireAtSlim}" Header="{shcm:ResourceString Name=ViewPageSettingHutaoPassportGachaLogExpiredAtHeader}"/>
<cwc:SettingsCard
Command="{Binding Passport.OpenRedeemWebsiteCommand}"
@@ -308,20 +308,6 @@
</cwc:SettingsCard>
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" Text="{shcm:ResourceString Name=ViewPageSettingGameHeader}"/>
<cwc:SettingsCard
ActionIcon="{shcm:FontIcon Glyph=&#xE76C;}"
ActionIconToolTip="{shcm:ResourceString Name=ViewPageSettingSetGamePathAction}"
Command="{Binding SetPowerShellPathCommand}"
Header="{shcm:ResourceString Name=ViewPageSettingSetPowerShellPathHeader}"
HeaderIcon="{shcm:FontIcon Glyph=&#xE756;}"
IsClickEnabled="True">
<cwc:SettingsCard.Description>
<StackPanel>
<TextBlock Text="{shcm:ResourceString Name=ViewPageSettingSetPowerShellDescription}"/>
<TextBlock Text="{Binding AppOptions.PowerShellPath}"/>
</StackPanel>
</cwc:SettingsCard.Description>
</cwc:SettingsCard>
<cwc:SettingsCard
ActionIcon="{shcm:FontIcon Glyph=&#xE76C;}"
ActionIconToolTip="{shcm:ResourceString Name=ViewPageSettingDeleteCacheAction}"

View File

@@ -23,6 +23,7 @@ using Snap.Hutao.Web.Hoyolab.SdkStatic.Hk4e.Launcher;
using System.Collections.Immutable;
using System.Collections.ObjectModel;
using System.IO;
using Windows.Win32.Foundation;
namespace Snap.Hutao.ViewModel.Game;
@@ -42,6 +43,7 @@ internal sealed partial class LaunchGameViewModel : Abstraction.ViewModel
private readonly IContentDialogFactory contentDialogFactory;
private readonly LaunchStatusOptions launchStatusOptions;
private readonly IGameLocatorFactory gameLocatorFactory;
private readonly ILogger<LaunchGameViewModel> logger;
private readonly IProgressFactory progressFactory;
private readonly IInfoBarService infoBarService;
private readonly ResourceClient resourceClient;
@@ -261,7 +263,7 @@ internal sealed partial class LaunchGameViewModel : Abstraction.ViewModel
{
await taskContext.SwitchToMainThreadAsync();
GamePathEntries = launchOptions.GetGamePathEntries(out GamePathEntry? entry);
UpdateSelectedGamePathEntry(entry, false);
UpdateSelectedGamePathEntry(entry, true);
}
}
@@ -279,6 +281,13 @@ internal sealed partial class LaunchGameViewModel : Abstraction.ViewModel
}
catch (Exception ex)
{
if (ex is Win32Exception win32Exception && win32Exception.HResult == HRESULT.E_FAIL)
{
// User canceled the operation. ignore
return;
}
logger.LogCritical(ex, "Launch failed");
infoBarService.Error(ex);
}
}

View File

@@ -6,6 +6,7 @@ using Snap.Hutao.Model.Entity;
using Snap.Hutao.Service.Game;
using Snap.Hutao.Service.Notification;
using System.Collections.ObjectModel;
using Windows.Win32.Foundation;
namespace Snap.Hutao.ViewModel.Game;
@@ -71,6 +72,12 @@ internal sealed partial class LaunchGameViewModelSlim : Abstraction.ViewModelSli
}
catch (Exception ex)
{
if (ex is Win32Exception win32Exception && win32Exception.HResult == HRESULT.E_FAIL)
{
// User canceled the operation. ignore
return;
}
infoBarService.Error(ex);
}
}

View File

@@ -174,18 +174,6 @@ internal sealed partial class SettingViewModel : Abstraction.ViewModel
await Launcher.LaunchUriAsync(new("ms-windows-store://pdp/?productid=9PH4NXJ2JN52"));
}
[Command("SetPowerShellPathCommand")]
private async Task SetPowerShellPathAsync()
{
(bool isOk, ValueFile file) = fileSystemPickerInteraction.PickFile(SH.FilePickerPowerShellCommit, [("PowerShell", "powershell.exe;pwsh.exe")]);
if (isOk && Path.GetFileNameWithoutExtension(file).EqualsAny(["POWERSHELL", "PWSH"], StringComparison.OrdinalIgnoreCase))
{
await taskContext.SwitchToMainThreadAsync();
AppOptions.PowerShellPath = file;
}
}
[Command("DeleteGameWebCacheCommand")]
private void DeleteGameWebCache()
{