mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
Compare commits
2 Commits
readme2024
...
feat/wikis
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3b86783493 | ||
|
|
e3adc2e595 |
31
README.md
31
README.md
@@ -1,36 +1,41 @@
|
||||

|
||||

|
||||
|
||||
|
||||
胡桃工具箱是一款以 MIT 协议开源的原神工具箱,专为现代化 Windows 平台设计,旨在改善桌面端玩家的游戏体验。通过将既有的官方资源与开发团队设计的全新功能相结合,提供了一套完整且实用的工具集,且无需依赖任何移动设备。它不对游戏客户端进行任何破坏性修改以确保工具箱的安全性
|
||||
胡桃工具箱是一款以 MIT 协议开源的原神工具箱,专为现代化 Windows 平台设计,旨在改善桌面端玩家的游戏体验。通过将既有的官方资源与开发团队设计的全新 功能相结合,它提供了一套完整且实用的工具集,且无需依赖任何移动设备。它不对游戏客户端进行任何破坏性修改以确保工具箱的安全性
|
||||
|
||||
Snap Hutao is an open-source Genshin Impact toolkit under MIT license, designed for modern Windows platform to improve the gaming experience for desktop players. By combining existing official resources with new features designed by the development team, it provides a complete and useful set of tools without the need to rely on mobile devices. Snap Hutao does not take any destructive modification to the game client to ensure the security of the toolkit.
|
||||
|
||||
## 安装 / Installation
|
||||
## 下载使用 / Download
|
||||
|
||||
 [](https://github.com/DGP-Studio/Snap.Hutao/releases/latest) []()
|
||||
|
||||
---
|
||||
|
||||
你可以按照[快速开始](https://hut.ao/zh/quick-start.html)文档中提供的流程安装并设置 Snap Hutao。
|
||||
#### 使用安装器安装 / Install with Snap.Hutao.Depolyment Installer
|
||||
|
||||
You can follow the instructions in the [Quick Start](https://hut.ao/en/quick-start.html) document to install and set up Snap Hutao.
|
||||
Snap.Hutao.Depolyment 是一个由 DGP-Studio 重新包装的 Windows 应用安装器,适用于缺少专业计算机知识的一般用户,可以在安装时同时解决缺少必要系统环境的问题。
|
||||
|
||||
## 本地化翻译 / Localization
|
||||
Snap.Hutao.Depolyment is a Windows application installer repackaged by DGP-Studio for the users who lacks computer knowledge and can solve the problem of missing necessary system environment at the same time as the installation.
|
||||
|
||||
].data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-15670597-565845.json) ].data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-15670597-565845.json) ].data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-15670597-565845.json) ].data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-15670597-565845.json) ].data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-15670597-565845.json)].data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-15670597-565845.json) ].data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-15670597-565845.json)
|
||||
[从 GitHub 发布页获取 / Download from GitHub release](https://github.com/DGP-Studio/Snap.Hutao.Deployment/releases/latest)
|
||||
|
||||
Snap Hutao 使用 [Crowdin](https://translate.hut.ao/) 作为客户端文本翻译平台,在该平台上你可以为你熟悉的语言提交翻译文本。我们感谢每一个为 Snap Hutao 做出贡献的社区成员,并且欢迎更多的朋友能参与到这个项目中。
|
||||
[从极狐Lab 发布页获取 / Download from Jihu Gitlab release](https://jihulab.com/DGP-Studio/Snap.Hutao.Deployment/-/releases)
|
||||
|
||||
Snap Hutao uses [Crowdin](https://translate.hut.ao/) as a client text translation platform where you can submit translated text for languages you are familiar with. We are grateful to every community member who has contributed to Snap Hutao and welcome more friends to participate in this project.
|
||||
#### 使用 MSIX 包安装 / Install with MSIX Package
|
||||
|
||||
## 社区 / Community
|
||||
直接使用 Snap Hutao MSIX 安装包,使用 Windows 内置的 App Installer 即可安装。如在安装中出现问题,请查阅我们的[常见问题](https://hut.ao/zh/advanced/FAQ.html)文档
|
||||
|
||||
[](https://discord.gg/CcH5XtDtvR) [](https://qm.qq.com/q/WJKykrY9W)
|
||||
Install with Snap Hutao MSIX package, can be installed with Windows built-in App Installer. If you faced any issue, please check our [FAQ](https://hut.ao/en/advanced/FAQ.html) document.
|
||||
|
||||
[从 GitHub 发布页获取 / Download from GitHub release](https://github.com/DGP-Studio/Snap.Hutao/releases/latest)
|
||||
|
||||
[从极狐Lab 发布页获取 / Download from Jihu Gitlab release](https://jihulab.com/DGP-Studio/Snap.Hutao/-/releases)
|
||||
|
||||
## 贡献 / Contribute
|
||||
|
||||
* [向我们提交 PR / Make Pull Requests](https://hut.ao/development/contribute.html)
|
||||
* [为我们更新文档 / Enhance our Document](https://github.com/DGP-Studio/Snap.Hutao.Docs)
|
||||
* [向我们提交 PR / Make Pull Requests](https://github.com/DGP-Studio/Snap.Hutao/pulls)
|
||||
* [在 Crowdin 上进行本地化 / Translate Project on Crowdin](https://translate.hut.ao/)
|
||||
* [为我们更新文档 / Enhance our Document ](https://github.com/DGP-Studio/Snap.Hutao.Docs)
|
||||
|
||||
## 特别感谢 / Special Thanks
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | ------------------ |
|
||||
| >=1.9.0 | :white_check_mark: |
|
||||
| <1.9.0 | :x: |
|
||||
| >=1.6.0 | :white_check_mark: |
|
||||
| <1.6.0 | :x: |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
|
||||
24
build.cake
24
build.cake
@@ -69,15 +69,6 @@ else if (AppVeyor.IsRunningOnAppVeyor)
|
||||
})[..^2];
|
||||
Information($"Version: {version}");
|
||||
}
|
||||
else // Local
|
||||
{
|
||||
repoDir = System.Environment.CurrentDirectory;
|
||||
outputPath = System.IO.Path.Combine(repoDir, "src", "output");
|
||||
|
||||
version = System.DateTime.Now.ToString("yyyy.M.d.") + ((int)((System.DateTime.Now - System.DateTime.Today).TotalSeconds / 86400 * 65535)).ToString();
|
||||
|
||||
Information($"Version: {version}");
|
||||
}
|
||||
|
||||
Task("Build")
|
||||
.IsDependentOn("Build binary package")
|
||||
@@ -121,17 +112,6 @@ Task("Generate AppxManifest")
|
||||
Information("Using Release configuration");
|
||||
content = System.Text.RegularExpressions.Regex.Replace(content, " Publisher=\"([^\"]*)\"", " Publisher=\"CN=SignPath Foundation, O=SignPath Foundation, L=Lewes, S=Delaware, C=US\"");
|
||||
}
|
||||
else
|
||||
{
|
||||
Information("Using Local configuration.");
|
||||
content = content
|
||||
.Replace("Snap Hutao", "Snap Hutao Local")
|
||||
.Replace("胡桃", "胡桃 Local")
|
||||
.Replace("DGP Studio", "DGP Studio CI");
|
||||
content = System.Text.RegularExpressions.Regex.Replace(content, " Name=\"([^\"]*)\"", " Name=\"E8B6E2B3-D2A0-4435-A81D-2A16AAF405C7\"");
|
||||
content = System.Text.RegularExpressions.Regex.Replace(content, " Publisher=\"([^\"]*)\"", " Publisher=\"E=admin@dgp-studio.cn, CN=DGP Studio CI, OU=CI, O=DGP-Studio, L=San Jose, S=CA, C=US\"");
|
||||
content = System.Text.RegularExpressions.Regex.Replace(content, " Version=\"([0-9\\.]+)\"", $" Version=\"{version}\"");
|
||||
}
|
||||
|
||||
System.IO.File.WriteAllText(manifest, content);
|
||||
|
||||
@@ -193,10 +173,6 @@ Task("Build MSIX")
|
||||
{
|
||||
arguments = "pack /d " + binPath + " /p " + System.IO.Path.Combine(outputPath, $"Snap.Hutao-{version}.msix");
|
||||
}
|
||||
else
|
||||
{
|
||||
arguments = "pack /d " + binPath + " /p " + System.IO.Path.Combine(outputPath, $"Snap.Hutao.Local-{version}.msix");
|
||||
}
|
||||
var p = StartProcess(
|
||||
"makeappx.exe",
|
||||
new ProcessSettings
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="3.2.2" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="3.2.2" />
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.1">
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="3.2.1" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="3.2.1" />
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<XamlControlsResources/>
|
||||
<ResourceDictionary Source="ms-appx:///CommunityToolkit.WinUI.Controls.TokenizingTextBox/TokenizingTextBox.xaml"/>
|
||||
<ResourceDictionary Source="ms-appx:///Control/Loading.xaml"/>
|
||||
<ResourceDictionary Source="ms-appx:///Control/Image/CachedImage.xaml"/>
|
||||
<ResourceDictionary Source="ms-appx:///Control/Theme/Card.xaml"/>
|
||||
@@ -23,7 +22,6 @@
|
||||
<ResourceDictionary Source="ms-appx:///Control/Theme/PageOverride.xaml"/>
|
||||
<ResourceDictionary Source="ms-appx:///Control/Theme/PivotOverride.xaml"/>
|
||||
<ResourceDictionary Source="ms-appx:///Control/Theme/ScrollViewer.xaml"/>
|
||||
<ResourceDictionary Source="ms-appx:///Control/Theme/SegmentedOverride.xaml"/>
|
||||
<ResourceDictionary Source="ms-appx:///Control/Theme/SettingsStyle.xaml"/>
|
||||
<ResourceDictionary Source="ms-appx:///Control/Theme/Thickness.xaml"/>
|
||||
<ResourceDictionary Source="ms-appx:///Control/Theme/TransitionCollection.xaml"/>
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using CommunityToolkit.WinUI.Controls;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Snap.Hutao.Control.Extension;
|
||||
|
||||
namespace Snap.Hutao.Control.AutoSuggestBox;
|
||||
|
||||
[DependencyProperty("FilterCommand", typeof(ICommand))]
|
||||
[DependencyProperty("FilterCommandParameter", typeof(object))]
|
||||
[DependencyProperty("AvailableTokens", typeof(IReadOnlyDictionary<string, SearchToken>))]
|
||||
internal sealed partial class AutoSuggestTokenBox : TokenizingTextBox
|
||||
{
|
||||
public AutoSuggestTokenBox()
|
||||
{
|
||||
DefaultStyleKey = typeof(TokenizingTextBox);
|
||||
TextChanged += OnFilterSuggestionRequested;
|
||||
QuerySubmitted += OnQuerySubmitted;
|
||||
TokenItemAdding += OnTokenItemAdding;
|
||||
TokenItemAdded += OnTokenItemModified;
|
||||
TokenItemRemoved += OnTokenItemModified;
|
||||
}
|
||||
|
||||
private void OnFilterSuggestionRequested(Microsoft.UI.Xaml.Controls.AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Text))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.Reason == AutoSuggestionBoxTextChangeReason.UserInput)
|
||||
{
|
||||
sender.ItemsSource = AvailableTokens.Values.Where(q => q.Value.Contains(Text, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
// TODO: CornerRadius
|
||||
// Popup? popup = this.FindDescendant("SuggestionsPopup") as Popup;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnQuerySubmitted(Microsoft.UI.Xaml.Controls.AutoSuggestBox sender, AutoSuggestBoxQuerySubmittedEventArgs args)
|
||||
{
|
||||
if (args.ChosenSuggestion is not null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CommandExtension.TryExecute(FilterCommand, FilterCommandParameter);
|
||||
}
|
||||
|
||||
private void OnTokenItemAdding(TokenizingTextBox sender, TokenItemAddingEventArgs args)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(args.TokenText))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
args.Item = AvailableTokens.GetValueOrDefault(args.TokenText) ?? new SearchToken(SearchTokenKind.None, args.TokenText);
|
||||
}
|
||||
|
||||
private void OnTokenItemModified(TokenizingTextBox sender, object args)
|
||||
{
|
||||
CommandExtension.TryExecute(FilterCommand, FilterCommandParameter);
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Windows.UI;
|
||||
|
||||
namespace Snap.Hutao.Control.AutoSuggestBox;
|
||||
|
||||
internal sealed class SearchToken
|
||||
{
|
||||
public SearchToken(SearchTokenKind kind, string value, Uri? iconUri = null, Uri? sideIconUri = null, Color? quality = null)
|
||||
{
|
||||
Value = value;
|
||||
Kind = kind;
|
||||
IconUri = iconUri;
|
||||
SideIconUri = sideIconUri;
|
||||
Quality = quality;
|
||||
}
|
||||
|
||||
public SearchTokenKind Kind { get; }
|
||||
|
||||
public string Value { get; set; } = default!;
|
||||
|
||||
public Uri? IconUri { get; }
|
||||
|
||||
public Uri? SideIconUri { get; }
|
||||
|
||||
public Color? Quality { get; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Control.AutoSuggestBox;
|
||||
|
||||
internal enum SearchTokenKind
|
||||
{
|
||||
None,
|
||||
AssociationType,
|
||||
Avatar,
|
||||
BodyType,
|
||||
ElementName,
|
||||
FightProperty,
|
||||
ItemQuality,
|
||||
Weapon,
|
||||
WeaponType,
|
||||
}
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
using CommunityToolkit.WinUI.Behaviors;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Snap.Hutao.Control.Extension;
|
||||
|
||||
namespace Snap.Hutao.Control.Behavior;
|
||||
|
||||
@@ -46,6 +45,10 @@ internal sealed partial class InvokeCommandOnLoadedBehavior : BehaviorBase<UIEle
|
||||
return;
|
||||
}
|
||||
|
||||
executed = Command.TryExecute(CommandParameter);
|
||||
if (Command is not null && Command.CanExecute(CommandParameter))
|
||||
{
|
||||
Command.Execute(CommandParameter);
|
||||
executed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
using CommunityToolkit.WinUI.Behaviors;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Snap.Hutao.Control.Extension;
|
||||
|
||||
namespace Snap.Hutao.Control.Behavior;
|
||||
|
||||
@@ -50,7 +49,10 @@ internal sealed partial class PeriodicInvokeCommandOrOnActualThemeChangedBehavio
|
||||
return;
|
||||
}
|
||||
|
||||
Command.TryExecute(CommandParameter);
|
||||
if (Command is not null && Command.CanExecute(CommandParameter))
|
||||
{
|
||||
Command.Execute(CommandParameter);
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask RunCoreAsync()
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Control.Extension;
|
||||
|
||||
internal static class CommandExtension
|
||||
{
|
||||
public static bool TryExecute(this ICommand? command, object? parameter = null)
|
||||
{
|
||||
if (command is not null && command.CanExecute(parameter))
|
||||
{
|
||||
command.Execute(parameter);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.UI.Xaml;
|
||||
|
||||
namespace Snap.Hutao.Control.Helper;
|
||||
|
||||
[SuppressMessage("", "SH001")]
|
||||
[DependencyProperty("VisibilityObject", typeof(object), null, nameof(OnVisibilityObjectChanged), IsAttached = true, AttachedType = typeof(UIElement))]
|
||||
[DependencyProperty("OpacityObject", typeof(object), null, nameof(OnOpacityObjectChanged), IsAttached = true, AttachedType = typeof(UIElement))]
|
||||
public sealed partial class UIElementHelper
|
||||
{
|
||||
private static void OnVisibilityObjectChanged(DependencyObject dp, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
UIElement element = (UIElement)dp;
|
||||
element.Visibility = e.NewValue is null ? Visibility.Collapsed : Visibility.Visible;
|
||||
}
|
||||
|
||||
private static void OnOpacityObjectChanged(DependencyObject dp, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
UIElement element = (UIElement)dp;
|
||||
element.Opacity = e.NewValue is null ? 0D : 1D;
|
||||
}
|
||||
}
|
||||
@@ -168,7 +168,6 @@ internal abstract partial class CompositionImage : Microsoft.UI.Xaml.Controls.Co
|
||||
if (surface.DecodedPhysicalSize.Size() <= 0D)
|
||||
{
|
||||
await Task.WhenAny(surfaceLoadTaskCompletionSource.Task, Task.Delay(5000, token)).ConfigureAwait(true);
|
||||
await Task.Delay(50, token).ConfigureAwait(true);
|
||||
}
|
||||
|
||||
LoadImageSurfaceCompleted(surface);
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.UI.Xaml;
|
||||
using System.Data;
|
||||
using System.Runtime.InteropServices;
|
||||
using Windows.Foundation;
|
||||
|
||||
namespace Snap.Hutao.Control.Panel;
|
||||
|
||||
[DependencyProperty("Spacing", typeof(double), default(double), nameof(OnSpacingChanged))]
|
||||
internal partial class EqualPanel : Microsoft.UI.Xaml.Controls.Panel
|
||||
{
|
||||
private double maxItemWidth;
|
||||
private double maxItemHeight;
|
||||
private int visibleItemsCount;
|
||||
|
||||
public EqualPanel()
|
||||
{
|
||||
RegisterPropertyChangedCallback(HorizontalAlignmentProperty, OnHorizontalAlignmentChanged);
|
||||
}
|
||||
|
||||
protected override Size MeasureOverride(Size availableSize)
|
||||
{
|
||||
maxItemWidth = 0;
|
||||
maxItemHeight = 0;
|
||||
|
||||
List<UIElement> elements = [.. Children.Where(element => element.Visibility == Visibility.Visible)];
|
||||
visibleItemsCount = elements.Count;
|
||||
|
||||
foreach (ref readonly UIElement child in CollectionsMarshal.AsSpan(elements))
|
||||
{
|
||||
child.Measure(availableSize);
|
||||
maxItemWidth = Math.Max(maxItemWidth, child.DesiredSize.Width);
|
||||
maxItemHeight = Math.Max(maxItemHeight, child.DesiredSize.Height);
|
||||
}
|
||||
|
||||
if (visibleItemsCount > 0)
|
||||
{
|
||||
// Return equal widths based on the widest item
|
||||
// In very specific edge cases the AvailableWidth might be infinite resulting in a crash.
|
||||
if (HorizontalAlignment is not HorizontalAlignment.Stretch || double.IsInfinity(availableSize.Width))
|
||||
{
|
||||
return new Size((maxItemWidth * visibleItemsCount) + (Spacing * (visibleItemsCount - 1)), maxItemHeight);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Equal columns based on the available width, adjust for spacing
|
||||
double totalWidth = availableSize.Width - (Spacing * (visibleItemsCount - 1));
|
||||
maxItemWidth = totalWidth / visibleItemsCount;
|
||||
return new Size(availableSize.Width, maxItemHeight);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return new Size(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
protected override Size ArrangeOverride(Size finalSize)
|
||||
{
|
||||
double x = 0;
|
||||
|
||||
// Check if there's more (little) width available - if so, set max item width to the maximum possible as we have an almost perfect height.
|
||||
if (finalSize.Width > (visibleItemsCount * maxItemWidth) + (Spacing * (visibleItemsCount - 1)))
|
||||
{
|
||||
maxItemWidth = (finalSize.Width - (Spacing * (visibleItemsCount - 1))) / visibleItemsCount;
|
||||
}
|
||||
|
||||
IEnumerable<UIElement> elements = Children.Where(static e => e.Visibility == Visibility.Visible);
|
||||
foreach (UIElement child in elements)
|
||||
{
|
||||
child.Arrange(new Rect(x, 0, maxItemWidth, maxItemHeight));
|
||||
x += maxItemWidth + Spacing;
|
||||
}
|
||||
|
||||
return finalSize;
|
||||
}
|
||||
|
||||
private static void OnSpacingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
(d as EqualPanel)?.InvalidateMeasure();
|
||||
}
|
||||
|
||||
private void OnHorizontalAlignmentChanged(DependencyObject sender, DependencyProperty dp)
|
||||
{
|
||||
InvalidateMeasure();
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.UI.Xaml;
|
||||
using Windows.Foundation;
|
||||
|
||||
namespace Snap.Hutao.Control.Panel;
|
||||
|
||||
[DependencyProperty("MinItemWidth", typeof(double))]
|
||||
[DependencyProperty("Spacing", typeof(double))]
|
||||
internal partial class HorizontalEqualPanel : Microsoft.UI.Xaml.Controls.Panel
|
||||
{
|
||||
public HorizontalEqualPanel()
|
||||
{
|
||||
Loaded += OnLoaded;
|
||||
SizeChanged += OnSizeChanged;
|
||||
}
|
||||
|
||||
protected override Size MeasureOverride(Size availableSize)
|
||||
{
|
||||
foreach (UIElement child in Children)
|
||||
{
|
||||
// ScrollViewer will always return an Infinity Size, we should use ActualWidth for this situation.
|
||||
double availableWidth = double.IsInfinity(availableSize.Width) ? ActualWidth : availableSize.Width;
|
||||
double childAvailableWidth = (availableWidth + Spacing) / Children.Count;
|
||||
double childMaxAvailableWidth = Math.Max(MinItemWidth, childAvailableWidth);
|
||||
child.Measure(new(childMaxAvailableWidth - Spacing, ActualHeight));
|
||||
}
|
||||
|
||||
return base.MeasureOverride(availableSize);
|
||||
}
|
||||
|
||||
protected override Size ArrangeOverride(Size finalSize)
|
||||
{
|
||||
int itemCount = Children.Count;
|
||||
double availableWidthPerItem = (finalSize.Width - (Spacing * (itemCount - 1))) / itemCount;
|
||||
double actualItemWidth = Math.Max(MinItemWidth, availableWidthPerItem);
|
||||
|
||||
double offset = 0;
|
||||
foreach (UIElement child in Children)
|
||||
{
|
||||
child.Arrange(new Rect(offset, 0, actualItemWidth, finalSize.Height));
|
||||
offset += actualItemWidth + Spacing;
|
||||
}
|
||||
|
||||
return finalSize;
|
||||
}
|
||||
|
||||
private void OnLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
MinWidth = (MinItemWidth * Children.Count) + (Spacing * (Children.Count - 1));
|
||||
}
|
||||
|
||||
private void OnSizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
InvalidateMeasure();
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,6 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:shcm="using:Snap.Hutao.Control.Markup"
|
||||
Style="{StaticResource DefaultSegmentedStyle}"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<cwc:SegmentedItem
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
using CommunityToolkit.WinUI.Controls;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Snap.Hutao.Core.Setting;
|
||||
using System.Collections.Frozen;
|
||||
|
||||
namespace Snap.Hutao.Control.Panel;
|
||||
|
||||
@@ -20,11 +19,11 @@ internal sealed partial class PanelSelector : Segmented
|
||||
public const string List = nameof(List);
|
||||
public const string Grid = nameof(Grid);
|
||||
|
||||
private static readonly FrozenDictionary<int, string> IndexTypeMap = FrozenDictionary.ToFrozenDictionary(
|
||||
[
|
||||
KeyValuePair.Create(0, List),
|
||||
KeyValuePair.Create(1, Grid),
|
||||
]);
|
||||
private static readonly Dictionary<int, string> IndexTypeMap = new()
|
||||
{
|
||||
[0] = List,
|
||||
[1] = Grid,
|
||||
};
|
||||
|
||||
private readonly RoutedEventHandler loadedEventHandler;
|
||||
private readonly RoutedEventHandler unloadedEventHandler;
|
||||
|
||||
@@ -41,12 +41,14 @@ internal class ScopedPage : Page
|
||||
/// 应当在 InitializeComponent() 前调用
|
||||
/// </summary>
|
||||
/// <typeparam name="TViewModel">视图模型类型</typeparam>
|
||||
protected void InitializeWith<TViewModel>()
|
||||
protected TViewModel InitializeWith<TViewModel>()
|
||||
where TViewModel : class, IViewModel
|
||||
{
|
||||
IViewModel viewModel = currentScope.ServiceProvider.GetRequiredService<TViewModel>();
|
||||
viewModel.CancellationToken = viewCancellationTokenSource.Token;
|
||||
DataContext = viewModel;
|
||||
|
||||
return (TViewModel)viewModel;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
||||
@@ -4,19 +4,21 @@
|
||||
xmlns:cwm="using:CommunityToolkit.WinUI.Media">
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Key="Light">
|
||||
<x:Double x:Key="CompatShadowThemeOpacity">0.14</x:Double>
|
||||
<cwm:AttachedCardShadow
|
||||
x:Key="CompatCardShadow"
|
||||
BlurRadius="8"
|
||||
Opacity="0.14"
|
||||
Offset="0,4,0"/>
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="Dark">
|
||||
<x:Double x:Key="CompatShadowThemeOpacity">0.28</x:Double>
|
||||
<cwm:AttachedCardShadow
|
||||
x:Key="CompatCardShadow"
|
||||
BlurRadius="8"
|
||||
Opacity="0.28"
|
||||
Offset="0,4,0"/>
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
|
||||
<cwm:AttachedCardShadow
|
||||
x:Key="CompatCardShadow"
|
||||
BlurRadius="8"
|
||||
Opacity="{ThemeResource CompatShadowThemeOpacity}"
|
||||
Offset="0,4,0"/>
|
||||
|
||||
<Style x:Key="BorderCardStyle" TargetType="Border">
|
||||
<Setter Property="Background" Value="{ThemeResource CardBackgroundFillColorDefaultBrush}"/>
|
||||
<Setter Property="BorderBrush" Value="{ThemeResource CardStrokeColorDefaultBrush}"/>
|
||||
|
||||
@@ -8,9 +8,6 @@
|
||||
<ItemsPanelTemplate x:Key="WrapPanelSpacing0Template">
|
||||
<cwcont:WrapPanel/>
|
||||
</ItemsPanelTemplate>
|
||||
<ItemsPanelTemplate x:Key="WrapPanelSpacing2Template">
|
||||
<cwcont:WrapPanel HorizontalSpacing="2" VerticalSpacing="2"/>
|
||||
</ItemsPanelTemplate>
|
||||
<ItemsPanelTemplate x:Key="WrapPanelSpacing4Template">
|
||||
<cwcont:WrapPanel HorizontalSpacing="4" VerticalSpacing="4"/>
|
||||
</ItemsPanelTemplate>
|
||||
@@ -20,9 +17,6 @@
|
||||
<ItemsPanelTemplate x:Key="HorizontalStackPanelSpacing2Template">
|
||||
<StackPanel Orientation="Horizontal" Spacing="2"/>
|
||||
</ItemsPanelTemplate>
|
||||
<ItemsPanelTemplate x:Key="HorizontalStackPanelSpacing4Template">
|
||||
<StackPanel Orientation="Horizontal" Spacing="4"/>
|
||||
</ItemsPanelTemplate>
|
||||
<ItemsPanelTemplate x:Key="StackPanelSpacing4Template">
|
||||
<StackPanel Spacing="4"/>
|
||||
</ItemsPanelTemplate>
|
||||
|
||||
@@ -11,6 +11,4 @@ internal static class KnownColors
|
||||
public static readonly Color Orange = StructMarshal.Color(0xFFBC6932);
|
||||
public static readonly Color Purple = StructMarshal.Color(0xFFA156E0);
|
||||
public static readonly Color Blue = StructMarshal.Color(0xFF5180CB);
|
||||
public static readonly Color Green = StructMarshal.Color(0xFF2A8F72);
|
||||
public static readonly Color White = StructMarshal.Color(0xFF72778B);
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:cw="using:CommunityToolkit.WinUI"
|
||||
xmlns:cwc="using:CommunityToolkit.WinUI.Controls"
|
||||
xmlns:shcp="using:Snap.Hutao.Control.Panel"
|
||||
xmlns:win="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="ms-appx:///CommunityToolkit.WinUI.Controls.Segmented/SegmentedItem/SegmentedItem.xaml"/>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Key="Default">
|
||||
<StaticResource x:Key="SegmentedBackground" ResourceKey="ControlAltFillColorSecondaryBrush"/>
|
||||
<StaticResource x:Key="SegmentedBorderBrush" ResourceKey="ControlStrokeColorDefaultBrush"/>
|
||||
<Thickness x:Key="SegmentedBorderThickness">1</Thickness>
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="Light">
|
||||
<StaticResource x:Key="SegmentedBackground" ResourceKey="ControlAltFillColorSecondaryBrush"/>
|
||||
<StaticResource x:Key="SegmentedBorderBrush" ResourceKey="ControlStrokeColorDefaultBrush"/>
|
||||
<Thickness x:Key="SegmentedBorderThickness">1</Thickness>
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="HighContrast">
|
||||
<StaticResource x:Key="SegmentedBackground" ResourceKey="SystemColorButtonFaceColor"/>
|
||||
<StaticResource x:Key="SegmentedBorderBrush" ResourceKey="SystemColorHighlightColorBrush"/>
|
||||
<Thickness x:Key="SegmentedBorderThickness">1</Thickness>
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
|
||||
<x:Double x:Key="SegmentedItemSpacing">1</x:Double>
|
||||
<x:Double x:Key="ButtonItemSpacing">2</x:Double>
|
||||
|
||||
<Style BasedOn="{StaticResource DefaultSegmentedStyle}" TargetType="cwc:Segmented"/>
|
||||
|
||||
<Style x:Key="DefaultSegmentedStyle" TargetType="cwc:Segmented">
|
||||
<Style.Setters>
|
||||
<Setter Property="CornerRadius" Value="{ThemeResource ControlCornerRadius}"/>
|
||||
<Setter Property="Background" Value="{ThemeResource SegmentedBackground}"/>
|
||||
<Setter Property="BorderBrush" Value="{ThemeResource SegmentedBorderBrush}"/>
|
||||
<Setter Property="BorderThickness" Value="{ThemeResource SegmentedBorderThickness}"/>
|
||||
<Setter Property="HorizontalAlignment" Value="Left"/>
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
<Setter Property="SelectionMode" Value="Single"/>
|
||||
<Setter Property="IsItemClickEnabled" Value="False"/>
|
||||
<win:Setter Property="SingleSelectionFollowsFocus" Value="False"/>
|
||||
<Setter Property="IsTabStop" Value="False"/>
|
||||
<Setter Property="TabNavigation" Value="Once"/>
|
||||
<Setter Property="ItemsPanel">
|
||||
<Setter.Value>
|
||||
<ItemsPanelTemplate>
|
||||
<shcp:EqualPanel
|
||||
HorizontalAlignment="{Binding (cw:FrameworkElementExtensions.Ancestor).HorizontalAlignment, RelativeSource={RelativeSource Self}}"
|
||||
cw:FrameworkElementExtensions.AncestorType="cwc:Segmented"
|
||||
Spacing="{ThemeResource SegmentedItemSpacing}"/>
|
||||
</ItemsPanelTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="cwc:Segmented">
|
||||
<Grid>
|
||||
<Border
|
||||
VerticalAlignment="Stretch"
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
CornerRadius="{TemplateBinding CornerRadius}"/>
|
||||
<ItemsPresenter Margin="{TemplateBinding Padding}"/>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style.Setters>
|
||||
</Style>
|
||||
|
||||
<Style
|
||||
x:Key="PivotSegmentedStyle"
|
||||
BasedOn="{StaticResource DefaultSegmentedStyle}"
|
||||
TargetType="cwc:Segmented">
|
||||
<Style.Setters>
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Setter Property="BorderBrush" Value="Transparent"/>
|
||||
<Setter Property="BorderThickness" Value="0"/>
|
||||
<Setter Property="Padding" Value="0"/>
|
||||
<Setter Property="ItemContainerStyle" Value="{StaticResource PivotSegmentedItemStyle}"/>
|
||||
<Setter Property="ItemsPanel">
|
||||
<Setter.Value>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Horizontal" Spacing="{ThemeResource SegmentedItemSpacing}"/>
|
||||
</ItemsPanelTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style.Setters>
|
||||
</Style>
|
||||
|
||||
<Style
|
||||
x:Key="ButtonSegmentedStyle"
|
||||
BasedOn="{StaticResource DefaultSegmentedStyle}"
|
||||
TargetType="cwc:Segmented">
|
||||
<Style.Setters>
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Setter Property="BorderBrush" Value="Transparent"/>
|
||||
<Setter Property="BorderThickness" Value="0"/>
|
||||
<Setter Property="Padding" Value="0"/>
|
||||
<Setter Property="ItemContainerStyle" Value="{StaticResource ButtonSegmentedItemStyle}"/>
|
||||
<Setter Property="ItemsPanel">
|
||||
<Setter.Value>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Horizontal" Spacing="{ThemeResource ButtonItemSpacing}"/>
|
||||
</ItemsPanelTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style.Setters>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
@@ -1,25 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Win32;
|
||||
using Windows.UI;
|
||||
|
||||
namespace Snap.Hutao.Control.Theme;
|
||||
|
||||
internal static class SystemColors
|
||||
{
|
||||
public static Color BaseLowColor(bool isDarkMode)
|
||||
{
|
||||
return isDarkMode ? StructMarshal.Color(0x33FFFFFF) : StructMarshal.Color(0x33000000);
|
||||
}
|
||||
|
||||
public static Color BaseMediumLowColor(bool isDarkMode)
|
||||
{
|
||||
return isDarkMode ? StructMarshal.Color(0x66FFFFFF) : StructMarshal.Color(0x66000000);
|
||||
}
|
||||
|
||||
public static Color BaseHighColor(bool isDarkMode)
|
||||
{
|
||||
return isDarkMode ? StructMarshal.Color(0xFFFFFFFF) : StructMarshal.Color(0xFF000000);
|
||||
}
|
||||
}
|
||||
@@ -26,12 +26,12 @@ internal sealed partial class ImageCache : IImageCache, IImageCacheFilePathOpera
|
||||
{
|
||||
private const string CacheFolderName = nameof(ImageCache);
|
||||
|
||||
private readonly FrozenDictionary<int, TimeSpan> retryCountToDelay = FrozenDictionary.ToFrozenDictionary(
|
||||
[
|
||||
KeyValuePair.Create(0, TimeSpan.FromSeconds(4)),
|
||||
KeyValuePair.Create(1, TimeSpan.FromSeconds(16)),
|
||||
KeyValuePair.Create(2, TimeSpan.FromSeconds(64)),
|
||||
]);
|
||||
private readonly FrozenDictionary<int, TimeSpan> retryCountToDelay = new Dictionary<int, TimeSpan>()
|
||||
{
|
||||
[0] = TimeSpan.FromSeconds(4),
|
||||
[1] = TimeSpan.FromSeconds(16),
|
||||
[2] = TimeSpan.FromSeconds(64),
|
||||
}.ToFrozenDictionary();
|
||||
|
||||
private readonly ConcurrentDictionary<string, Task> concurrentTasks = new();
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@ internal static partial class IocHttpClientConfiguration
|
||||
.ConfigurePrimaryHttpMessageHandler((handler, provider) =>
|
||||
{
|
||||
HttpClientHandler clientHandler = (HttpClientHandler)handler;
|
||||
clientHandler.AllowAutoRedirect = true;
|
||||
clientHandler.UseProxy = true;
|
||||
clientHandler.Proxy = provider.GetRequiredService<DynamicHttpProxy>();
|
||||
});
|
||||
|
||||
@@ -23,16 +23,8 @@ internal sealed partial class ExceptionRecorder
|
||||
public void Record(Application app)
|
||||
{
|
||||
app.UnhandledException += OnAppUnhandledException;
|
||||
app.DebugSettings.FailFastOnErrors = false;
|
||||
|
||||
app.DebugSettings.IsBindingTracingEnabled = true;
|
||||
app.DebugSettings.BindingFailed += OnXamlBindingFailed;
|
||||
|
||||
app.DebugSettings.IsXamlResourceReferenceTracingEnabled = true;
|
||||
app.DebugSettings.XamlResourceReferenceFailed += OnXamlResourceReferenceFailed;
|
||||
|
||||
app.DebugSettings.LayoutCycleTracingLevel = LayoutCycleTracingLevel.High;
|
||||
app.DebugSettings.LayoutCycleDebugBreakLevel = LayoutCycleDebugBreakLevel.High;
|
||||
}
|
||||
|
||||
[SuppressMessage("", "CA2012")]
|
||||
|
||||
@@ -32,23 +32,9 @@ internal sealed class HutaoException : Exception
|
||||
}
|
||||
}
|
||||
|
||||
public static void ThrowIfNot(bool condition, HutaoExceptionKind kind, string message, Exception? innerException = default)
|
||||
{
|
||||
if (!condition)
|
||||
{
|
||||
throw new HutaoException(kind, message, innerException);
|
||||
}
|
||||
}
|
||||
|
||||
public static HutaoException ServiceTypeCastFailed<TFrom, TTo>(string name, Exception? innerException = default)
|
||||
{
|
||||
string message = $"This instance of '{typeof(TFrom).FullName}' '{name}' doesn't implement '{typeof(TTo).FullName}'";
|
||||
throw new HutaoException(HutaoExceptionKind.ServiceTypeCastFailed, message, innerException);
|
||||
}
|
||||
|
||||
public static HutaoException GachaStatisticsInvalidItemId(uint id, Exception? innerException = default)
|
||||
{
|
||||
string message = SH.FormatServiceGachaStatisticsFactoryItemIdInvalid(id);
|
||||
throw new HutaoException(HutaoExceptionKind.GachaStatisticsInvalidItemId, message, innerException);
|
||||
}
|
||||
}
|
||||
@@ -6,15 +6,7 @@ namespace Snap.Hutao.Core.ExceptionService;
|
||||
internal enum HutaoExceptionKind
|
||||
{
|
||||
None,
|
||||
|
||||
// Foundation
|
||||
ServiceTypeCastFailed,
|
||||
|
||||
// IO
|
||||
FileSystemCreateFileInsufficientPermissions,
|
||||
PrivateNamedPipeContentHashIncorrect,
|
||||
|
||||
// Service
|
||||
GachaStatisticsInvalidItemId,
|
||||
GameFpsUnlockingFailed,
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System.Collections.Frozen;
|
||||
using System.Text;
|
||||
|
||||
namespace Snap.Hutao.Core;
|
||||
@@ -15,25 +14,25 @@ internal static class TypeNameHelper
|
||||
{
|
||||
private const char DefaultNestedTypeDelimiter = '+';
|
||||
|
||||
private static readonly FrozenDictionary<Type, string> BuiltInTypeNames = FrozenDictionary.ToFrozenDictionary(
|
||||
[
|
||||
KeyValuePair.Create(typeof(void), "void"),
|
||||
KeyValuePair.Create(typeof(bool), "bool"),
|
||||
KeyValuePair.Create(typeof(byte), "byte"),
|
||||
KeyValuePair.Create(typeof(char), "char"),
|
||||
KeyValuePair.Create(typeof(decimal), "decimal"),
|
||||
KeyValuePair.Create(typeof(double), "double"),
|
||||
KeyValuePair.Create(typeof(float), "float"),
|
||||
KeyValuePair.Create(typeof(int), "int"),
|
||||
KeyValuePair.Create(typeof(long), "long"),
|
||||
KeyValuePair.Create(typeof(object), "object"),
|
||||
KeyValuePair.Create(typeof(sbyte), "sbyte"),
|
||||
KeyValuePair.Create(typeof(short), "short"),
|
||||
KeyValuePair.Create(typeof(string), "string"),
|
||||
KeyValuePair.Create(typeof(uint), "uint"),
|
||||
KeyValuePair.Create(typeof(ulong), "ulong"),
|
||||
KeyValuePair.Create(typeof(ushort), "ushort"),
|
||||
]);
|
||||
private static readonly Dictionary<Type, string> BuiltInTypeNames = new()
|
||||
{
|
||||
{ typeof(void), "void" },
|
||||
{ typeof(bool), "bool" },
|
||||
{ typeof(byte), "byte" },
|
||||
{ typeof(char), "char" },
|
||||
{ typeof(decimal), "decimal" },
|
||||
{ typeof(double), "double" },
|
||||
{ typeof(float), "float" },
|
||||
{ typeof(int), "int" },
|
||||
{ typeof(long), "long" },
|
||||
{ typeof(object), "object" },
|
||||
{ typeof(sbyte), "sbyte" },
|
||||
{ typeof(short), "short" },
|
||||
{ typeof(string), "string" },
|
||||
{ typeof(uint), "uint" },
|
||||
{ typeof(ulong), "ulong" },
|
||||
{ typeof(ushort), "ushort" },
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// 获取对象类型的显示名称
|
||||
|
||||
@@ -9,7 +9,6 @@ namespace Snap.Hutao.Core.Validation;
|
||||
/// 封装验证方法,简化微软验证
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
[Obsolete("Use HutaoException instead")]
|
||||
internal static class Must
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -13,7 +13,6 @@ using Snap.Hutao.Win32;
|
||||
using Snap.Hutao.Win32.Foundation;
|
||||
using Snap.Hutao.Win32.Graphics.Dwm;
|
||||
using Snap.Hutao.Win32.UI.WindowsAndMessaging;
|
||||
using System.Collections.Frozen;
|
||||
using System.IO;
|
||||
using Windows.Graphics;
|
||||
using Windows.UI;
|
||||
@@ -57,22 +56,25 @@ internal sealed class WindowController
|
||||
private void InitializeCore()
|
||||
{
|
||||
RuntimeOptions runtimeOptions = serviceProvider.GetRequiredService<RuntimeOptions>();
|
||||
AppOptions appOptions = serviceProvider.GetRequiredService<AppOptions>();
|
||||
|
||||
window.AppWindow.Title = SH.FormatAppNameAndVersion(runtimeOptions.Version);
|
||||
window.AppWindow.SetIcon(Path.Combine(runtimeOptions.InstalledLocation, "Assets/Logo.ico"));
|
||||
ExtendsContentIntoTitleBar();
|
||||
|
||||
RecoverOrInitWindowSize();
|
||||
UpdateElementTheme(appOptions.ElementTheme);
|
||||
UpdateImmersiveDarkMode(options.TitleBar, default!);
|
||||
|
||||
// appWindow.Show(true);
|
||||
// appWindow.Show can't bring window to top.
|
||||
window.Activate();
|
||||
options.BringToForeground();
|
||||
UpdateSystemBackdrop(appOptions.BackdropType);
|
||||
appOptions.PropertyChanged += OnOptionsPropertyChanged;
|
||||
|
||||
if (options.UseSystemBackdrop)
|
||||
{
|
||||
AppOptions appOptions = serviceProvider.GetRequiredService<AppOptions>();
|
||||
UpdateSystemBackdrop(appOptions.BackdropType);
|
||||
appOptions.PropertyChanged += OnOptionsPropertyChanged;
|
||||
}
|
||||
|
||||
subclass.Initialize();
|
||||
|
||||
@@ -120,17 +122,13 @@ internal sealed class WindowController
|
||||
|
||||
private void OnOptionsPropertyChanged(object? sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (sender is not AppOptions options)
|
||||
if (e.PropertyName is nameof(AppOptions.BackdropType))
|
||||
{
|
||||
return;
|
||||
if (sender is AppOptions options)
|
||||
{
|
||||
UpdateSystemBackdrop(options.BackdropType);
|
||||
}
|
||||
}
|
||||
|
||||
_ = e.PropertyName switch
|
||||
{
|
||||
nameof(AppOptions.BackdropType) => UpdateSystemBackdrop(options.BackdropType),
|
||||
nameof(AppOptions.ElementTheme) => UpdateElementTheme(options.ElementTheme),
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
|
||||
private void OnWindowClosed(object sender, WindowEventArgs args)
|
||||
@@ -160,7 +158,7 @@ internal sealed class WindowController
|
||||
}
|
||||
}
|
||||
|
||||
private bool UpdateSystemBackdrop(BackdropType backdropType)
|
||||
private void UpdateSystemBackdrop(BackdropType backdropType)
|
||||
{
|
||||
window.SystemBackdrop = backdropType switch
|
||||
{
|
||||
@@ -170,15 +168,6 @@ internal sealed class WindowController
|
||||
BackdropType.Acrylic => new DesktopAcrylicBackdrop(),
|
||||
_ => null,
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool UpdateElementTheme(ElementTheme theme)
|
||||
{
|
||||
((FrameworkElement)window.Content).RequestedTheme = theme;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void UpdateTitleButtonColor()
|
||||
@@ -188,12 +177,12 @@ internal sealed class WindowController
|
||||
appTitleBar.ButtonBackgroundColor = Colors.Transparent;
|
||||
appTitleBar.ButtonInactiveBackgroundColor = Colors.Transparent;
|
||||
|
||||
bool isDarkMode = Control.Theme.ThemeHelper.IsDarkMode(options.TitleBar.ActualTheme);
|
||||
IAppResourceProvider resourceProvider = serviceProvider.GetRequiredService<IAppResourceProvider>();
|
||||
|
||||
Color systemBaseLowColor = Control.Theme.SystemColors.BaseLowColor(isDarkMode);
|
||||
Color systemBaseLowColor = resourceProvider.GetResource<Color>("SystemBaseLowColor");
|
||||
appTitleBar.ButtonHoverBackgroundColor = systemBaseLowColor;
|
||||
|
||||
Color systemBaseMediumLowColor = Control.Theme.SystemColors.BaseMediumLowColor(isDarkMode);
|
||||
Color systemBaseMediumLowColor = resourceProvider.GetResource<Color>("SystemBaseMediumLowColor");
|
||||
appTitleBar.ButtonPressedBackgroundColor = systemBaseMediumLowColor;
|
||||
|
||||
// The Foreground doesn't accept Alpha channel. So we translate it to gray.
|
||||
@@ -201,7 +190,7 @@ internal sealed class WindowController
|
||||
byte result = (byte)((systemBaseMediumLowColor.A / 255.0) * light);
|
||||
appTitleBar.ButtonInactiveForegroundColor = Color.FromArgb(0xFF, result, result, result);
|
||||
|
||||
Color systemBaseHighColor = Control.Theme.SystemColors.BaseHighColor(isDarkMode);
|
||||
Color systemBaseHighColor = resourceProvider.GetResource<Color>("SystemBaseHighColor");
|
||||
appTitleBar.ButtonForegroundColor = systemBaseHighColor;
|
||||
appTitleBar.ButtonHoverForegroundColor = systemBaseHighColor;
|
||||
appTitleBar.ButtonPressedForegroundColor = systemBaseHighColor;
|
||||
|
||||
@@ -41,18 +41,21 @@ internal readonly struct WindowOptions
|
||||
/// </summary>
|
||||
public readonly bool PersistSize;
|
||||
|
||||
public readonly bool UseSystemBackdrop;
|
||||
|
||||
/// <summary>
|
||||
/// 是否使用 Win UI 3 自带的拓展标题栏实现
|
||||
/// </summary>
|
||||
public readonly bool UseLegacyDragBarImplementation = !AppWindowTitleBar.IsCustomizationSupported();
|
||||
|
||||
public WindowOptions(Window window, FrameworkElement titleBar, SizeInt32 initSize, bool persistSize = false)
|
||||
public WindowOptions(Window window, FrameworkElement titleBar, SizeInt32 initSize, bool persistSize = false, bool useSystemBackdrop = true)
|
||||
{
|
||||
Hwnd = WindowNative.GetWindowHandle(window);
|
||||
InputNonClientPointerSource = InputNonClientPointerSource.GetForWindowId(window.AppWindow.Id);
|
||||
TitleBar = titleBar;
|
||||
InitSize = initSize;
|
||||
PersistSize = persistSize;
|
||||
UseSystemBackdrop = useSystemBackdrop;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -15,12 +15,6 @@ namespace Snap.Hutao.Extension;
|
||||
[HighQuality]
|
||||
internal static partial class EnumerableExtension
|
||||
{
|
||||
public static void Deconstruct<TKey, TElement>(this IGrouping<TKey, TElement> grouping, out TKey key, out IEnumerable<TElement> elements)
|
||||
{
|
||||
key = grouping.Key;
|
||||
elements = grouping;
|
||||
}
|
||||
|
||||
public static TElement? ElementAtOrLastOrDefault<TElement>(this IEnumerable<TElement> source, int index)
|
||||
{
|
||||
return source.ElementAtOrDefault(index) ?? source.LastOrDefault();
|
||||
|
||||
@@ -41,30 +41,6 @@
|
||||
"Equatable": true,
|
||||
"EqualityOperators": true
|
||||
},
|
||||
{
|
||||
"Name": "FurnitureId",
|
||||
"Documentation": "家具 Id",
|
||||
"Equatable": true,
|
||||
"EqualityOperators": true
|
||||
},
|
||||
{
|
||||
"Name": "FurnitureMakeId",
|
||||
"Documentation": "家具配方 Id",
|
||||
"Equatable": true,
|
||||
"EqualityOperators": true
|
||||
},
|
||||
{
|
||||
"Name": "FurnitureSuiteId",
|
||||
"Documentation": "家具套装 Id",
|
||||
"Equatable": true,
|
||||
"EqualityOperators": true
|
||||
},
|
||||
{
|
||||
"Name": "FurnitureTypeId",
|
||||
"Documentation": "家具分类 Id",
|
||||
"Equatable": true,
|
||||
"EqualityOperators": true
|
||||
},
|
||||
{
|
||||
"Name": "Level",
|
||||
"Documentation": "等级 1 - 90",
|
||||
|
||||
@@ -42,14 +42,14 @@ internal sealed partial class GachaItem
|
||||
/// <summary>
|
||||
/// 祈愿记录分类
|
||||
/// </summary>
|
||||
public GachaType GachaType { get; set; }
|
||||
public GachaConfigType GachaType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 祈愿记录查询分类
|
||||
/// 合并保底的卡池使用此属性
|
||||
/// 仅4种(不含400)
|
||||
/// </summary>
|
||||
public GachaType QueryType { get; set; }
|
||||
public GachaConfigType QueryType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 物品Id
|
||||
|
||||
@@ -13,7 +13,6 @@ internal sealed partial class SettingEntry
|
||||
public const string Culture = "Culture";
|
||||
|
||||
public const string SystemBackdropType = "SystemBackdropType";
|
||||
public const string ElementTheme = "ElementTheme";
|
||||
public const string BackgroundImageType = "BackgroundImageType";
|
||||
|
||||
public const string AnnouncementRegion = "AnnouncementRegion";
|
||||
|
||||
@@ -17,7 +17,7 @@ internal sealed class UIGF : IJsonOnSerializing, IJsonOnDeserialized
|
||||
/// <summary>
|
||||
/// 当前版本
|
||||
/// </summary>
|
||||
public const string CurrentVersion = "v3.0";
|
||||
public const string CurrentVersion = "v2.4";
|
||||
|
||||
/// <summary>
|
||||
/// 信息
|
||||
@@ -61,7 +61,6 @@ internal sealed class UIGF : IJsonOnSerializing, IJsonOnDeserialized
|
||||
"v2.2" => UIGFVersion.Major2Minor2OrLower,
|
||||
"v2.3" => UIGFVersion.Major2Minor3OrHigher,
|
||||
"v2.4" => UIGFVersion.Major2Minor3OrHigher,
|
||||
"v3.0" => UIGFVersion.Major2Minor3OrHigher,
|
||||
_ => UIGFVersion.NotSupported,
|
||||
};
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ internal sealed class UIGFItem : GachaLogItem, IMappingFrom<UIGFItem, GachaItem,
|
||||
/// </summary>
|
||||
[JsonPropertyName("uigf_gacha_type")]
|
||||
[JsonEnum(JsonSerializeType.NumberString)]
|
||||
public GachaType UIGFGachaType { get; set; } = default!;
|
||||
public GachaConfigType UIGFGachaType { get; set; } = default!;
|
||||
|
||||
public static UIGFItem From(GachaItem item, INameQuality nameQuality)
|
||||
{
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Model.Intrinsic;
|
||||
|
||||
internal enum FurnitureDeploySurfaceType
|
||||
{
|
||||
Ground = 0,
|
||||
Wall = 1,
|
||||
Ceil = 2,
|
||||
StackObjPlane = 3,
|
||||
Door = 4,
|
||||
Chandelier = 5,
|
||||
Floor = 6,
|
||||
WallBody = 7,
|
||||
Carpet = 8,
|
||||
LegoRockery = 9,
|
||||
Stair = 10,
|
||||
NPC = 11,
|
||||
Animal = 12,
|
||||
Apartment = 13,
|
||||
FurnitureSuite = 14,
|
||||
Road = 15,
|
||||
Terrain = 16,
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Model.Intrinsic;
|
||||
|
||||
internal enum FurnitureDeployType
|
||||
{
|
||||
Interior,
|
||||
Exterior,
|
||||
InteriorRoom,
|
||||
InteriorHall,
|
||||
Skybox,
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Model.Intrinsic;
|
||||
|
||||
internal enum GroupRecordType
|
||||
{
|
||||
None,
|
||||
Racing,
|
||||
Balloon,
|
||||
Stake,
|
||||
Seek,
|
||||
Explosion,
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Model.Intrinsic;
|
||||
|
||||
internal enum SpecialFurnitureType
|
||||
{
|
||||
NormalFurniture,
|
||||
BlockDependent,
|
||||
FarmField,
|
||||
TeleportPoint,
|
||||
Fishpond,
|
||||
Npc,
|
||||
Apartment,
|
||||
FurnitureSuite,
|
||||
Paimon,
|
||||
Fish,
|
||||
CustomBaseFurniture,
|
||||
CustomNodeFurniture,
|
||||
VirtualFurniture,
|
||||
GroupFurniture,
|
||||
CoopPictureFrame,
|
||||
ChangeBgmFurniture,
|
||||
ServerGadget,
|
||||
Fishtank,
|
||||
}
|
||||
@@ -1,9 +1,22 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Model.Primitive;
|
||||
|
||||
namespace Snap.Hutao.Model.Metadata.Achievement;
|
||||
|
||||
/// <summary>
|
||||
/// 奖励
|
||||
/// </summary>
|
||||
internal sealed class Reward : IdCount;
|
||||
internal sealed class Reward
|
||||
{
|
||||
/// <summary>
|
||||
/// Id
|
||||
/// </summary>
|
||||
public MaterialId Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 数量
|
||||
/// </summary>
|
||||
public uint Count { get; set; }
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Control;
|
||||
using Snap.Hutao.Model.Intrinsic;
|
||||
using System.Collections.Frozen;
|
||||
|
||||
namespace Snap.Hutao.Model.Metadata.Converter;
|
||||
|
||||
internal sealed class AssociationTypeIconConverter : ValueConverter<AssociationType, Uri?>
|
||||
{
|
||||
private static readonly FrozenDictionary<string, AssociationType> LocalizedNameToAssociationType = FrozenDictionary.ToFrozenDictionary(
|
||||
[
|
||||
KeyValuePair.Create(SH.ModelIntrinsicAssociationTypeMondstadt, AssociationType.ASSOC_TYPE_MONDSTADT),
|
||||
KeyValuePair.Create(SH.ModelIntrinsicAssociationTypeLiyue, AssociationType.ASSOC_TYPE_LIYUE),
|
||||
KeyValuePair.Create(SH.ModelIntrinsicAssociationTypeFatui, AssociationType.ASSOC_TYPE_FATUI),
|
||||
KeyValuePair.Create(SH.ModelIntrinsicAssociationTypeInazuma, AssociationType.ASSOC_TYPE_INAZUMA),
|
||||
KeyValuePair.Create(SH.ModelIntrinsicAssociationTypeRanger, AssociationType.ASSOC_TYPE_RANGER),
|
||||
KeyValuePair.Create(SH.ModelIntrinsicAssociationTypeSumeru, AssociationType.ASSOC_TYPE_SUMERU),
|
||||
KeyValuePair.Create(SH.ModelIntrinsicAssociationTypeFontaine, AssociationType.ASSOC_TYPE_FONTAINE),
|
||||
KeyValuePair.Create(SH.ModelIntrinsicAssociationTypeNatlan, AssociationType.ASSOC_TYPE_NATLAN),
|
||||
KeyValuePair.Create(SH.ModelIntrinsicAssociationTypeSnezhnaya, AssociationType.ASSOC_TYPE_SNEZHNAYA),
|
||||
]);
|
||||
|
||||
public static Uri? AssociationTypeNameToIconUri(string associationTypeName)
|
||||
{
|
||||
return AssociationTypeToIconUri(LocalizedNameToAssociationType.GetValueOrDefault(associationTypeName));
|
||||
}
|
||||
|
||||
public static Uri? AssociationTypeToIconUri(AssociationType type)
|
||||
{
|
||||
string? association = type switch
|
||||
{
|
||||
AssociationType.ASSOC_TYPE_MONDSTADT => "Mengde",
|
||||
AssociationType.ASSOC_TYPE_LIYUE => "Liyue",
|
||||
AssociationType.ASSOC_TYPE_FATUI => default,
|
||||
AssociationType.ASSOC_TYPE_INAZUMA => "Inazuma",
|
||||
AssociationType.ASSOC_TYPE_RANGER => default,
|
||||
AssociationType.ASSOC_TYPE_SUMERU => "Sumeru",
|
||||
AssociationType.ASSOC_TYPE_FONTAINE => "Fontaine",
|
||||
AssociationType.ASSOC_TYPE_NATLAN => default,
|
||||
AssociationType.ASSOC_TYPE_SNEZHNAYA => default,
|
||||
_ => throw Must.NeverHappen(),
|
||||
};
|
||||
|
||||
return association is null
|
||||
? default
|
||||
: Web.HutaoEndpoints.StaticRaw("ChapterIcon", $"UI_ChapterIcon_{association}.png").ToUri();
|
||||
}
|
||||
|
||||
public override Uri? Convert(AssociationType from)
|
||||
{
|
||||
return AssociationTypeToIconUri(from);
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
using Snap.Hutao.Control;
|
||||
using Snap.Hutao.Model.Intrinsic;
|
||||
using System.Collections.Frozen;
|
||||
|
||||
namespace Snap.Hutao.Model.Metadata.Converter;
|
||||
|
||||
@@ -13,27 +12,27 @@ namespace Snap.Hutao.Model.Metadata.Converter;
|
||||
[HighQuality]
|
||||
internal sealed class ElementNameIconConverter : ValueConverter<string, Uri>
|
||||
{
|
||||
private static readonly FrozenDictionary<string, string> LocalizedNameToElementIconName = FrozenDictionary.ToFrozenDictionary(
|
||||
[
|
||||
KeyValuePair.Create(SH.ModelIntrinsicElementNameElec, "Electric"),
|
||||
KeyValuePair.Create(SH.ModelIntrinsicElementNameFire, "Fire"),
|
||||
KeyValuePair.Create(SH.ModelIntrinsicElementNameGrass, "Grass"),
|
||||
KeyValuePair.Create(SH.ModelIntrinsicElementNameIce, "Ice"),
|
||||
KeyValuePair.Create(SH.ModelIntrinsicElementNameRock, "Rock"),
|
||||
KeyValuePair.Create(SH.ModelIntrinsicElementNameWater, "Water"),
|
||||
KeyValuePair.Create(SH.ModelIntrinsicElementNameWind, "Wind"),
|
||||
]);
|
||||
private static readonly Dictionary<string, string> LocalizedNameToElementIconName = new()
|
||||
{
|
||||
[SH.ModelIntrinsicElementNameElec] = "Electric",
|
||||
[SH.ModelIntrinsicElementNameFire] = "Fire",
|
||||
[SH.ModelIntrinsicElementNameGrass] = "Grass",
|
||||
[SH.ModelIntrinsicElementNameIce] = "Ice",
|
||||
[SH.ModelIntrinsicElementNameRock] = "Rock",
|
||||
[SH.ModelIntrinsicElementNameWater] = "Water",
|
||||
[SH.ModelIntrinsicElementNameWind] = "Wind",
|
||||
};
|
||||
|
||||
private static readonly FrozenDictionary<string, ElementType> LocalizedNameToElementType = FrozenDictionary.ToFrozenDictionary(
|
||||
[
|
||||
KeyValuePair.Create(SH.ModelIntrinsicElementNameElec, ElementType.Electric),
|
||||
KeyValuePair.Create(SH.ModelIntrinsicElementNameFire, ElementType.Fire),
|
||||
KeyValuePair.Create(SH.ModelIntrinsicElementNameGrass, ElementType.Grass),
|
||||
KeyValuePair.Create(SH.ModelIntrinsicElementNameIce, ElementType.Ice),
|
||||
KeyValuePair.Create(SH.ModelIntrinsicElementNameRock, ElementType.Rock),
|
||||
KeyValuePair.Create(SH.ModelIntrinsicElementNameWater, ElementType.Water),
|
||||
KeyValuePair.Create(SH.ModelIntrinsicElementNameWind, ElementType.Wind),
|
||||
]);
|
||||
private static readonly Dictionary<string, ElementType> LocalizedNameToElementType = new()
|
||||
{
|
||||
[SH.ModelIntrinsicElementNameElec] = ElementType.Electric,
|
||||
[SH.ModelIntrinsicElementNameFire] = ElementType.Fire,
|
||||
[SH.ModelIntrinsicElementNameGrass] = ElementType.Grass,
|
||||
[SH.ModelIntrinsicElementNameIce] = ElementType.Ice,
|
||||
[SH.ModelIntrinsicElementNameRock] = ElementType.Rock,
|
||||
[SH.ModelIntrinsicElementNameWater] = ElementType.Water,
|
||||
[SH.ModelIntrinsicElementNameWind] = ElementType.Wind,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// 将中文元素名称转换为图标链接
|
||||
|
||||
@@ -3,9 +3,8 @@
|
||||
|
||||
using Microsoft.UI;
|
||||
using Snap.Hutao.Control;
|
||||
using Snap.Hutao.Control.Theme;
|
||||
using Snap.Hutao.Model.Intrinsic;
|
||||
using System.Collections.Frozen;
|
||||
using Snap.Hutao.Win32;
|
||||
using Windows.UI;
|
||||
|
||||
namespace Snap.Hutao.Model.Metadata.Converter;
|
||||
@@ -16,39 +15,17 @@ namespace Snap.Hutao.Model.Metadata.Converter;
|
||||
[HighQuality]
|
||||
internal sealed class QualityColorConverter : ValueConverter<QualityType, Color>
|
||||
{
|
||||
private static readonly FrozenDictionary<string, QualityType> LocalizedNameToQualityType = FrozenDictionary.ToFrozenDictionary(
|
||||
[
|
||||
KeyValuePair.Create(SH.ModelIntrinsicItemQualityWhite, QualityType.QUALITY_WHITE),
|
||||
KeyValuePair.Create(SH.ModelIntrinsicItemQualityGreen, QualityType.QUALITY_GREEN),
|
||||
KeyValuePair.Create(SH.ModelIntrinsicItemQualityBlue, QualityType.QUALITY_BLUE),
|
||||
KeyValuePair.Create(SH.ModelIntrinsicItemQualityPurple, QualityType.QUALITY_PURPLE),
|
||||
KeyValuePair.Create(SH.ModelIntrinsicItemQualityOrange, QualityType.QUALITY_ORANGE),
|
||||
KeyValuePair.Create(SH.ModelIntrinsicItemQualityRed, QualityType.QUALITY_ORANGE_SP),
|
||||
]);
|
||||
|
||||
private static readonly FrozenDictionary<QualityType, Color> QualityTypeToColor = FrozenDictionary.ToFrozenDictionary(
|
||||
[
|
||||
KeyValuePair.Create(QualityType.QUALITY_WHITE, KnownColors.White),
|
||||
KeyValuePair.Create(QualityType.QUALITY_GREEN, KnownColors.Green),
|
||||
KeyValuePair.Create(QualityType.QUALITY_BLUE, KnownColors.Blue),
|
||||
KeyValuePair.Create(QualityType.QUALITY_PURPLE, KnownColors.Purple),
|
||||
KeyValuePair.Create(QualityType.QUALITY_ORANGE, KnownColors.Orange),
|
||||
KeyValuePair.Create(QualityType.QUALITY_ORANGE_SP, KnownColors.Orange),
|
||||
]);
|
||||
|
||||
public static Color QualityNameToColor(string qualityName)
|
||||
{
|
||||
return QualityToColor(LocalizedNameToQualityType.GetValueOrDefault(qualityName));
|
||||
}
|
||||
|
||||
public static Color QualityToColor(QualityType quality)
|
||||
{
|
||||
return QualityTypeToColor.GetValueOrDefault(quality, Colors.Transparent);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Color Convert(QualityType from)
|
||||
{
|
||||
return QualityToColor(from);
|
||||
return from switch
|
||||
{
|
||||
QualityType.QUALITY_WHITE => StructMarshal.Color(0xFF72778B),
|
||||
QualityType.QUALITY_GREEN => StructMarshal.Color(0xFF2A8F72),
|
||||
QualityType.QUALITY_BLUE => StructMarshal.Color(0xFF5180CB),
|
||||
QualityType.QUALITY_PURPLE => StructMarshal.Color(0xFFA156E0),
|
||||
QualityType.QUALITY_ORANGE or QualityType.QUALITY_ORANGE_SP => StructMarshal.Color(0xFFBC6932),
|
||||
_ => Colors.Transparent,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
using Snap.Hutao.Control;
|
||||
using Snap.Hutao.Model.Intrinsic;
|
||||
using System.Collections.Frozen;
|
||||
|
||||
namespace Snap.Hutao.Model.Metadata.Converter;
|
||||
|
||||
@@ -13,20 +12,6 @@ namespace Snap.Hutao.Model.Metadata.Converter;
|
||||
[HighQuality]
|
||||
internal sealed class WeaponTypeIconConverter : ValueConverter<WeaponType, Uri>
|
||||
{
|
||||
private static readonly FrozenDictionary<string, WeaponType> LocalizedNameToWeaponType = FrozenDictionary.ToFrozenDictionary(
|
||||
[
|
||||
KeyValuePair.Create(SH.ModelIntrinsicWeaponTypeSwordOneHand, WeaponType.WEAPON_SWORD_ONE_HAND),
|
||||
KeyValuePair.Create(SH.ModelIntrinsicWeaponTypeBow, WeaponType.WEAPON_BOW),
|
||||
KeyValuePair.Create(SH.ModelIntrinsicWeaponTypePole, WeaponType.WEAPON_POLE),
|
||||
KeyValuePair.Create(SH.ModelIntrinsicWeaponTypeClaymore, WeaponType.WEAPON_CLAYMORE),
|
||||
KeyValuePair.Create(SH.ModelIntrinsicWeaponTypeCatalyst, WeaponType.WEAPON_CATALYST),
|
||||
]);
|
||||
|
||||
public static Uri WeaponTypeNameToIconUri(string weaponTypeName)
|
||||
{
|
||||
return WeaponTypeToIconUri(LocalizedNameToWeaponType.GetValueOrDefault(weaponTypeName));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将武器类型转换为图标链接
|
||||
/// </summary>
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Model.Intrinsic;
|
||||
using Snap.Hutao.Model.Primitive;
|
||||
|
||||
namespace Snap.Hutao.Model.Metadata.Furniture;
|
||||
|
||||
internal sealed class Furniture
|
||||
{
|
||||
public List<FurnitureTypeId> Types { get; set; } = default!;
|
||||
|
||||
public FurnitureDeploySurfaceType SurfaceType { get; set; }
|
||||
|
||||
public bool IsSpecial { get; set; }
|
||||
|
||||
public SpecialFurnitureType SpecialType { get; set; }
|
||||
|
||||
public uint Comfort { get; set; }
|
||||
|
||||
public uint Cost { get; set; }
|
||||
|
||||
public uint DiscountCost { get; set; }
|
||||
|
||||
public bool CanFloat { get; set; }
|
||||
|
||||
public bool IsUnique { get; set; }
|
||||
|
||||
public string? ItemIcon { get; set; }
|
||||
|
||||
public string? EffectIcon { get; set; }
|
||||
|
||||
public QualityType RankLevel { get; set; }
|
||||
|
||||
public List<FurnitureId> GruopUnits { get; set; } = default!;
|
||||
|
||||
public GroupRecordType GroupRecordType { get; set; }
|
||||
|
||||
public List<string> SourceTexts { get; set; } = default!;
|
||||
|
||||
public FurnitureId Id { get; set; }
|
||||
|
||||
public string Name { get; set; } = default!;
|
||||
|
||||
public string Description { get; set; } = default!;
|
||||
|
||||
public string? Icon { get; set; }
|
||||
|
||||
public uint Rank { get; set; }
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Model.Primitive;
|
||||
|
||||
namespace Snap.Hutao.Model.Metadata.Furniture;
|
||||
|
||||
internal sealed class FurnitureMake
|
||||
{
|
||||
public FurnitureMakeId Id { get; set; }
|
||||
|
||||
public FurnitureId ItemId { get; set; }
|
||||
|
||||
public uint Experience { get; set; }
|
||||
|
||||
public List<IdCount> Materials { get; set; } = default!;
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Model.Primitive;
|
||||
|
||||
namespace Snap.Hutao.Model.Metadata.Furniture;
|
||||
|
||||
internal sealed class FurnitureSuite
|
||||
{
|
||||
public FurnitureSuiteId Id { get; set; }
|
||||
|
||||
public List<FurnitureTypeId> Types { get; set; } = default!;
|
||||
|
||||
public string Name { get; set; } = default!;
|
||||
|
||||
public string Description { get; set; } = default!;
|
||||
|
||||
public string ItemIcon { get; set; } = default!;
|
||||
|
||||
public string? MapIcon { get; set; }
|
||||
|
||||
public List<AvatarId>? FavoriteNpcs { get; set; }
|
||||
|
||||
public List<FurnitureId> Units { get; set; } = default!;
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Model.Intrinsic;
|
||||
using Snap.Hutao.Model.Primitive;
|
||||
|
||||
namespace Snap.Hutao.Model.Metadata.Furniture;
|
||||
|
||||
internal sealed class FurnitureType
|
||||
{
|
||||
public FurnitureTypeId Id { get; set; }
|
||||
|
||||
public uint Category { get; set; }
|
||||
|
||||
public string Name { get; set; } = default!;
|
||||
|
||||
public string Name2 { get; set; } = default!;
|
||||
|
||||
public string TabIcon { get; set; } = default!;
|
||||
|
||||
public FurnitureDeployType SceneType { get; set; }
|
||||
|
||||
public bool BagPageOnly { get; set; }
|
||||
|
||||
public bool IsShowInBag { get; set; }
|
||||
|
||||
public uint Sort { get; set; }
|
||||
}
|
||||
@@ -49,7 +49,7 @@ internal sealed class GachaEvent
|
||||
/// <summary>
|
||||
/// 卡池类型
|
||||
/// </summary>
|
||||
public GachaType Type { get; set; }
|
||||
public GachaConfigType Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 五星列表
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Model.Primitive;
|
||||
|
||||
namespace Snap.Hutao.Model.Metadata;
|
||||
|
||||
internal class IdCount
|
||||
{
|
||||
/// <summary>
|
||||
/// Id
|
||||
/// </summary>
|
||||
public MaterialId Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 数量
|
||||
/// </summary>
|
||||
public uint Count { get; set; }
|
||||
}
|
||||
@@ -13,7 +13,7 @@
|
||||
<Identity
|
||||
Name="60568DGPStudio.SnapHutao"
|
||||
Publisher="CN=35C8E923-85DF-49A7-9172-B39DC6312C52"
|
||||
Version="1.9.8.0" />
|
||||
Version="1.9.7.0" />
|
||||
|
||||
<Properties>
|
||||
<DisplayName>Snap Hutao</DisplayName>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<Identity
|
||||
Name="60568DGPStudio.SnapHutaoDev"
|
||||
Publisher="CN=35C8E923-85DF-49A7-9172-B39DC6312C52"
|
||||
Version="1.9.8.0" />
|
||||
Version="1.9.7.0" />
|
||||
|
||||
<Properties>
|
||||
<DisplayName>Snap Hutao Dev</DisplayName>
|
||||
|
||||
@@ -186,18 +186,6 @@
|
||||
<data name="CoreWebView2HelperVersionUndetected" xml:space="preserve">
|
||||
<value>No WebView2 Runtime detected</value>
|
||||
</data>
|
||||
<data name="CoreWindowHotkeyCombinationRegisterFailed" xml:space="preserve">
|
||||
<value>Register [{0}] hotkey [{1}] failed</value>
|
||||
</data>
|
||||
<data name="CoreWindowThemeDark" xml:space="preserve">
|
||||
<value>Dark</value>
|
||||
</data>
|
||||
<data name="CoreWindowThemeLight" xml:space="preserve">
|
||||
<value>Light</value>
|
||||
</data>
|
||||
<data name="CoreWindowThemeSystem" xml:space="preserve">
|
||||
<value>System</value>
|
||||
</data>
|
||||
<data name="FilePickerExportCommit" xml:space="preserve">
|
||||
<value>Export</value>
|
||||
</data>
|
||||
@@ -869,9 +857,6 @@
|
||||
<data name="ServiceGachaLogFactoryAvatarWishName" xml:space="preserve">
|
||||
<value>Character Event Wish</value>
|
||||
</data>
|
||||
<data name="ServiceGachaLogFactoryChronicledWishName" xml:space="preserve">
|
||||
<value>Chronicled Wish</value>
|
||||
</data>
|
||||
<data name="ServiceGachaLogFactoryPermanentWishName" xml:space="preserve">
|
||||
<value>Wanderlust Invocation</value>
|
||||
</data>
|
||||
@@ -2229,7 +2214,7 @@
|
||||
<value>Auto start Better GUI for automation tasks after game launched</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameBetterGIHeader" xml:space="preserve">
|
||||
<value>Automated Tasks</value>
|
||||
<value>Better GI</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameCommonHeader" xml:space="preserve">
|
||||
<value>General</value>
|
||||
@@ -2247,7 +2232,7 @@
|
||||
<value>File</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameInterProcessHeader" xml:space="preserve">
|
||||
<value>Process Linkage</value>
|
||||
<value>InterProcess</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameMonitorsDescription" xml:space="preserve">
|
||||
<value>Run the software on the selected monitor</value>
|
||||
@@ -2268,7 +2253,7 @@
|
||||
<value>Try to start Starward after the game is started for game duration statistics</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGamePlayTimeHeader" xml:space="preserve">
|
||||
<value>Game Hours Record</value>
|
||||
<value>Hours Played</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameProcessHeader" xml:space="preserve">
|
||||
<value>Progress</value>
|
||||
@@ -2381,9 +2366,6 @@
|
||||
<data name="ViewPageSettingBackgroundImageHeader" xml:space="preserve">
|
||||
<value>Wallpaper Image</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingBackgroundImageLocalFolderCopyrightHeader" xml:space="preserve">
|
||||
<value>Using local images as the background</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingCacheFolderDescription" xml:space="preserve">
|
||||
<value>Images cache are saved here</value>
|
||||
</data>
|
||||
@@ -2639,12 +2621,6 @@
|
||||
<data name="ViewPageSettingStoreReviewNavigate" xml:space="preserve">
|
||||
<value>Rate Snap Hutao</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingThemeDescription" xml:space="preserve">
|
||||
<value>Change window theme</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingThemeHeader" xml:space="preserve">
|
||||
<value>Theme</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingTranslateNavigate" xml:space="preserve">
|
||||
<value>Contribute Translations</value>
|
||||
</data>
|
||||
@@ -2654,12 +2630,6 @@
|
||||
<data name="ViewPageSettingWebview2Header" xml:space="preserve">
|
||||
<value>Webview2 Runtime</value>
|
||||
</data>
|
||||
<data name="ViewPageSpiralAbyssTeamAppearanceDownHeader" xml:space="preserve">
|
||||
<value>Second Half</value>
|
||||
</data>
|
||||
<data name="ViewPageSpiralAbyssTeamAppearanceUpHeader" xml:space="preserve">
|
||||
<value>First Half</value>
|
||||
</data>
|
||||
<data name="ViewPageWiKiAvatarArtifactSetCombinationHeader" xml:space="preserve">
|
||||
<value>Artifact Set Combination</value>
|
||||
</data>
|
||||
@@ -2766,7 +2736,7 @@
|
||||
<value>Character Appearance Rate = Character Appearance in this Floor (only count for 1 if repeated) / Total Number of Abyss Record of this Floor</value>
|
||||
</data>
|
||||
<data name="ViewSpiralAbyssAvatarUsageRankDescription" xml:space="preserve">
|
||||
<value>Character Usage Rate = Character Appearance in this Floor (only count for 1 if repeated) / Number of Player who Own this Character</value>
|
||||
<value>Character Usage Rate = Character Appearance in this Floor (only count for 1 is repeated) / Number of Player who Own this Character</value>
|
||||
</data>
|
||||
<data name="ViewSpiralAbyssBattleHeader" xml:space="preserve">
|
||||
<value>Battle Statistics</value>
|
||||
@@ -3074,9 +3044,6 @@
|
||||
<data name="WebGachaConfigTypeAvatarEventWish2" xml:space="preserve">
|
||||
<value>Character Event Wish-2</value>
|
||||
</data>
|
||||
<data name="WebGachaConfigTypeChronicledWish" xml:space="preserve">
|
||||
<value>Chronicled Wish</value>
|
||||
</data>
|
||||
<data name="WebGachaConfigTypeNoviceWish" xml:space="preserve">
|
||||
<value>Beginners' Wish</value>
|
||||
</data>
|
||||
|
||||
@@ -186,18 +186,6 @@
|
||||
<data name="CoreWebView2HelperVersionUndetected" xml:space="preserve">
|
||||
<value>WebView2 Runtime tidak terdeteksi.</value>
|
||||
</data>
|
||||
<data name="CoreWindowHotkeyCombinationRegisterFailed" xml:space="preserve">
|
||||
<value>[{0}] Hotkey [{1}] gagal terdaftar</value>
|
||||
</data>
|
||||
<data name="CoreWindowThemeDark" xml:space="preserve">
|
||||
<value>深色</value>
|
||||
</data>
|
||||
<data name="CoreWindowThemeLight" xml:space="preserve">
|
||||
<value>浅色</value>
|
||||
</data>
|
||||
<data name="CoreWindowThemeSystem" xml:space="preserve">
|
||||
<value>跟随系统</value>
|
||||
</data>
|
||||
<data name="FilePickerExportCommit" xml:space="preserve">
|
||||
<value>Ekspor</value>
|
||||
</data>
|
||||
@@ -211,19 +199,19 @@
|
||||
<value>Pilih akun untuk memulai</value>
|
||||
</data>
|
||||
<data name="MetadataSpecialNameMetaAvatarSexProInfoPronounBoyGirlD" xml:space="preserve">
|
||||
<value><color=#1E90FF>Prince</color>/<color=#FFB6C1>Princess</color></value>
|
||||
<value><color=#1E90FF>王子</color>/<color=#FFB6C1>公主</color></value>
|
||||
</data>
|
||||
<data name="MetadataSpecialNameMetaAvatarSexProInfoPronounBoyGirlFirst" xml:space="preserve">
|
||||
<value><color=#1E90FF>I</color>/<color=#FFB6C1>I</color></value>
|
||||
<value><color=#1E90FF>我</color>/<color=#FFB6C1>我</color></value>
|
||||
</data>
|
||||
<data name="MetadataSpecialNameNickname" xml:space="preserve">
|
||||
<value>Pengembara</value>
|
||||
</data>
|
||||
<data name="MetadataSpecialNamePlayerAvatarSexProInfoPronounHeShe" xml:space="preserve">
|
||||
<value><color=#1E90FF>He</color>/<color=#FFB6C1>She</color></value>
|
||||
<value><color=#1E90FF>他</color>/<color=#FFB6C1>她</color></value>
|
||||
</data>
|
||||
<data name="MetadataSpecialNameRealNameId1" xml:space="preserve">
|
||||
<value>Pengembara</value>
|
||||
<value>流浪者</value>
|
||||
</data>
|
||||
<data name="ModelBindingAvatarPropertyWeaponAffixFormat" xml:space="preserve">
|
||||
<value>Perbaiki {0}</value>
|
||||
@@ -525,7 +513,7 @@
|
||||
<value>Gelombang 4: Gelombang akan muncul hanya setelah membunuh semua musuh di gelombang sebelumnya</value>
|
||||
</data>
|
||||
<data name="ModelMetadataTowerWaveTypeWave99999" xml:space="preserve">
|
||||
<value>Tetapkan 4 Perampok Harta Karun di lapangan, langsung muncul kembali setelah mati. Total 12.</value>
|
||||
<value>维持场上 4 个盗宝团怪物,击杀后立即替换,总数 12 个</value>
|
||||
</data>
|
||||
<data name="ModelNameValueDefaultDescription" xml:space="preserve">
|
||||
<value>Silakan perbarui data tampilan.</value>
|
||||
@@ -780,19 +768,19 @@
|
||||
<value>Pameran Karakter: {0:MM-dd HH:mm}</value>
|
||||
</data>
|
||||
<data name="ServiceBackgroundImageTypeBing" xml:space="preserve">
|
||||
<value>Wallpaper Harian Bing</value>
|
||||
<value>必应每日一图</value>
|
||||
</data>
|
||||
<data name="ServiceBackgroundImageTypeDaily" xml:space="preserve">
|
||||
<value>Wallpaper Harian Hutao</value>
|
||||
<value>胡桃每日一图</value>
|
||||
</data>
|
||||
<data name="ServiceBackgroundImageTypeLauncher" xml:space="preserve">
|
||||
<value>Wallpaper Resmi Peluncur Genshin</value>
|
||||
<value>官方启动器壁纸</value>
|
||||
</data>
|
||||
<data name="ServiceBackgroundImageTypeLocalFolder" xml:space="preserve">
|
||||
<value>Gambar Acak Lokal</value>
|
||||
<value>本地随机图片</value>
|
||||
</data>
|
||||
<data name="ServiceBackgroundImageTypeNone" xml:space="preserve">
|
||||
<value>Tanpa Gambar Latar</value>
|
||||
<value>无背景图片</value>
|
||||
</data>
|
||||
<data name="ServiceCultivationProjectCurrentUserdataCourrpted" xml:space="preserve">
|
||||
<value>Gagal menyimpan status rencana pengembangan</value>
|
||||
@@ -852,7 +840,7 @@
|
||||
<value>Parametric Transformer telah siap</value>
|
||||
</data>
|
||||
<data name="ServiceDiscordActivityElevationRequiredHint" xml:space="preserve">
|
||||
<value>Izin hilang, tidak dapat mengatur Aktivitas Discord Anda.</value>
|
||||
<value>权限不足,将无法为您设置 Discord Activity 状态</value>
|
||||
</data>
|
||||
<data name="ServiceDiscordGameActivityDetails" xml:space="preserve">
|
||||
<value>Menjelajahi di Teyvat</value>
|
||||
@@ -869,9 +857,6 @@
|
||||
<data name="ServiceGachaLogFactoryAvatarWishName" xml:space="preserve">
|
||||
<value>Event Wish Karakter</value>
|
||||
</data>
|
||||
<data name="ServiceGachaLogFactoryChronicledWishName" xml:space="preserve">
|
||||
<value>集录祈愿</value>
|
||||
</data>
|
||||
<data name="ServiceGachaLogFactoryPermanentWishName" xml:space="preserve">
|
||||
<value>Wanderlust Invocation</value>
|
||||
</data>
|
||||
@@ -1239,10 +1224,10 @@
|
||||
<value>Catatan Realtime Webhook URL</value>
|
||||
</data>
|
||||
<data name="ViewDialogFeedbackEnableLoopbackContent" xml:space="preserve">
|
||||
<value>Anda memerlukan alat lain untuk mengembalikan loopback setelah dikecualikan</value>
|
||||
<value>解除限制后需要使用其他工具恢复限制</value>
|
||||
</data>
|
||||
<data name="ViewDialogFeedbackEnableLoopbackTitle" xml:space="preserve">
|
||||
<value>Konfirmasi untuk Mengonfigurasi Pengecualian Loopback</value>
|
||||
<value>是否解除 Loopback 限制</value>
|
||||
</data>
|
||||
<data name="ViewDialogGachaLogImportTitle" xml:space="preserve">
|
||||
<value>Mengimpor riwayat wish</value>
|
||||
@@ -1425,7 +1410,7 @@
|
||||
<value>Game Launcher</value>
|
||||
</data>
|
||||
<data name="ViewListViewDragElevatedHint" xml:space="preserve">
|
||||
<value>Tidak dapat mengurutkan dalam Mode Administrator</value>
|
||||
<value>管理员模式下无法拖动排序</value>
|
||||
</data>
|
||||
<data name="ViewModelAchievementArchiveAdded" xml:space="preserve">
|
||||
<value>Arsip [{0}] berhasil ditambahkan</value>
|
||||
@@ -1707,7 +1692,7 @@
|
||||
<value>Selesai</value>
|
||||
</data>
|
||||
<data name="ViewModelWelcomeDownloadSummaryContentTypeNotMatch" xml:space="preserve">
|
||||
<value>Stream respons tidak berisi tipe konten yang valid</value>
|
||||
<value>响应内容不是有效的文件字节流</value>
|
||||
</data>
|
||||
<data name="ViewModelWelcomeDownloadSummaryDefault" xml:space="preserve">
|
||||
<value>Mengantre</value>
|
||||
@@ -1926,16 +1911,16 @@
|
||||
<value>Tautan Berguna</value>
|
||||
</data>
|
||||
<data name="ViewPageFeedbackCurrentProxyHeader" xml:space="preserve">
|
||||
<value>Proxy Saat ini</value>
|
||||
<value>当前代理</value>
|
||||
</data>
|
||||
<data name="ViewPageFeedbackCurrentProxyNoProxyDescription" xml:space="preserve">
|
||||
<value>Tidak ada Proxy</value>
|
||||
<value>无代理</value>
|
||||
</data>
|
||||
<data name="ViewPageFeedbackEnableLoopbackEnabledDescription" xml:space="preserve">
|
||||
<value>Dikecualikan</value>
|
||||
<value>已解除</value>
|
||||
</data>
|
||||
<data name="ViewPageFeedbackEnableLoopbackHeader" xml:space="preserve">
|
||||
<value>Konfigurasikan Pengecualian Loopback</value>
|
||||
<value>解除 Loopback 限制</value>
|
||||
</data>
|
||||
<data name="ViewPageFeedbackEngageWithUsDescription" xml:space="preserve">
|
||||
<value>Tetap berhubungan dengan kami</value>
|
||||
@@ -2226,10 +2211,10 @@
|
||||
<value>Argumen Awalan</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameBetterGIDescription" xml:space="preserve">
|
||||
<value>Mulai Otomatis Antarmuka Pengguna yang Lebih Baik untuk tugas otomatis setelah game diluncurkan</value>
|
||||
<value>在游戏启动后尝试启动并使用 Better GI 进行自动化任务</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameBetterGIHeader" xml:space="preserve">
|
||||
<value>自动化任务</value>
|
||||
<value>Better GI</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameCommonHeader" xml:space="preserve">
|
||||
<value>Umum</value>
|
||||
@@ -2247,7 +2232,7 @@
|
||||
<value>Berkas</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameInterProcessHeader" xml:space="preserve">
|
||||
<value>进程联动</value>
|
||||
<value>InterProcess</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameMonitorsDescription" xml:space="preserve">
|
||||
<value>Menjalankan perangkat lunak pada layar yang dipilih</value>
|
||||
@@ -2373,16 +2358,13 @@
|
||||
<value>Backdrop Material</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingBackgroundImageCopyrightHeader" xml:space="preserve">
|
||||
<value>Informasi Hak Cipta Gambar</value>
|
||||
<value>图片版权信息</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingBackgroundImageDescription" xml:space="preserve">
|
||||
<value>Ubah sumber gambar latar, restart Snap Hutao untuk menerapkan perubahan</value>
|
||||
<value>更改窗体的背景图片来源,重启胡桃以尽快生效</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingBackgroundImageHeader" xml:space="preserve">
|
||||
<value>Gambar Latar</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingBackgroundImageLocalFolderCopyrightHeader" xml:space="preserve">
|
||||
<value>当前背景为本地图片,如遇版权问题由用户个人负责</value>
|
||||
<value>背景图片</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingCacheFolderDescription" xml:space="preserve">
|
||||
<value>Cache gambar disimpan di sini</value>
|
||||
@@ -2391,7 +2373,7 @@
|
||||
<value>Berkas Cache</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingCardHutaoPassportHeader" xml:space="preserve">
|
||||
<value>Hutao Passport</value>
|
||||
<value>胡桃通行证</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingCopyDeviceIdAction" xml:space="preserve">
|
||||
<value>Salin</value>
|
||||
@@ -2586,10 +2568,10 @@
|
||||
<value>Website Resmi</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingOpenBackgroundImageFolderDescription" xml:space="preserve">
|
||||
<value>Latar Belakang Kustom, format didukung bmp/gif/ico/jpg/jpeg/png/tiff/webp</value>
|
||||
<value>自定义背景图片,支持 bmp / gif / ico / jpg / jpeg / png / tiff / webp 格式</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingOpenBackgroundImageFolderHeader" xml:space="preserve">
|
||||
<value>Buka Berkas Latar Belakang</value>
|
||||
<value>打开背景图片文件夹</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingResetAction" xml:space="preserve">
|
||||
<value>Reset</value>
|
||||
@@ -2601,10 +2583,10 @@
|
||||
<value>Setel ulang Sumber Daya Gambar</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingsAdvancedOptionsLaunchUnlockFpsDescription" xml:space="preserve">
|
||||
<value>Tambahkan Opsi Batasan FPS di Bagian Proses Peluncur Permainan</value>
|
||||
<value>在启动游戏页面的进程部分加入解锁帧率限制选项</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingsAdvancedOptionsLaunchUnlockFpsHeader" xml:space="preserve">
|
||||
<value>Peluncur Permainan - Buka Limit FPS</value>
|
||||
<value>启动游戏-解锁帧率限制</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingSetDataFolderDescription" xml:space="preserve">
|
||||
<value>Anda perlu memindahkan data di direktori secara manual, jika tidak, data pengguna baru akan dibuat.</value>
|
||||
@@ -2639,12 +2621,6 @@
|
||||
<data name="ViewPageSettingStoreReviewNavigate" xml:space="preserve">
|
||||
<value>Beri Rating untuk Snap Hutao</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingThemeDescription" xml:space="preserve">
|
||||
<value>更改窗体的颜色主题</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingThemeHeader" xml:space="preserve">
|
||||
<value>颜色主题</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingTranslateNavigate" xml:space="preserve">
|
||||
<value>Kontribusi penerjemahan</value>
|
||||
</data>
|
||||
@@ -2654,12 +2630,6 @@
|
||||
<data name="ViewPageSettingWebview2Header" xml:space="preserve">
|
||||
<value>Webview2 Runtime</value>
|
||||
</data>
|
||||
<data name="ViewPageSpiralAbyssTeamAppearanceDownHeader" xml:space="preserve">
|
||||
<value>下半</value>
|
||||
</data>
|
||||
<data name="ViewPageSpiralAbyssTeamAppearanceUpHeader" xml:space="preserve">
|
||||
<value>上半</value>
|
||||
</data>
|
||||
<data name="ViewPageWiKiAvatarArtifactSetCombinationHeader" xml:space="preserve">
|
||||
<value>Kombinasi Set Artefak</value>
|
||||
</data>
|
||||
@@ -2922,7 +2892,7 @@
|
||||
<value>〓Durasi Event〓.*?\d\.\d Tersedia selama versi ini</value>
|
||||
</data>
|
||||
<data name="WebAnnouncementMatchTransientActivityTime" xml:space="preserve">
|
||||
<value>(?:〓Waktu Acara〓|Waktu Menginginkan|【Waktu Peluncuran】|〓Waktu Diskon〓).*?(\d\.\d Setelah Pembaruan Versi).*?~.*?&lt;t class="t_(?:gl|lc)".*?&gt;(.*?)&lt;/t&gt;</value>
|
||||
<value>(?:〓Durasi Event〓|Durasi Event Wish|【Ketersediaan DUrasi】).*?(\d\.\dSetelah pembaruan versi).*?~.*?&lt;t class="t_(?:gl|lc)".*?&gt;(.*?)&lt;/t&gt;</value>
|
||||
</data>
|
||||
<data name="WebAnnouncementMatchVersionUpdateTime" xml:space="preserve">
|
||||
<value>〓Durasi Pemeliharaan Pembaruan.+?&lt;t class=\"t_(?:gl|lc)\".*?&gt;(.*?)&lt;/t&gt;</value>
|
||||
@@ -3074,9 +3044,6 @@
|
||||
<data name="WebGachaConfigTypeAvatarEventWish2" xml:space="preserve">
|
||||
<value>Event WIsh Karakter-2</value>
|
||||
</data>
|
||||
<data name="WebGachaConfigTypeChronicledWish" xml:space="preserve">
|
||||
<value>集录祈愿</value>
|
||||
</data>
|
||||
<data name="WebGachaConfigTypeNoviceWish" xml:space="preserve">
|
||||
<value>Wish Pemula</value>
|
||||
</data>
|
||||
|
||||
@@ -186,18 +186,6 @@
|
||||
<data name="CoreWebView2HelperVersionUndetected" xml:space="preserve">
|
||||
<value>WebView2 ランタイムが検出されませんでした</value>
|
||||
</data>
|
||||
<data name="CoreWindowHotkeyCombinationRegisterFailed" xml:space="preserve">
|
||||
<value>[{0}] 热键 [{1}] 注册失败</value>
|
||||
</data>
|
||||
<data name="CoreWindowThemeDark" xml:space="preserve">
|
||||
<value>深色</value>
|
||||
</data>
|
||||
<data name="CoreWindowThemeLight" xml:space="preserve">
|
||||
<value>浅色</value>
|
||||
</data>
|
||||
<data name="CoreWindowThemeSystem" xml:space="preserve">
|
||||
<value>跟随系统</value>
|
||||
</data>
|
||||
<data name="FilePickerExportCommit" xml:space="preserve">
|
||||
<value>エクスポート</value>
|
||||
</data>
|
||||
@@ -869,9 +857,6 @@
|
||||
<data name="ServiceGachaLogFactoryAvatarWishName" xml:space="preserve">
|
||||
<value>イベント祈願・キャラクター</value>
|
||||
</data>
|
||||
<data name="ServiceGachaLogFactoryChronicledWishName" xml:space="preserve">
|
||||
<value>集录祈愿</value>
|
||||
</data>
|
||||
<data name="ServiceGachaLogFactoryPermanentWishName" xml:space="preserve">
|
||||
<value>奔走世間</value>
|
||||
</data>
|
||||
@@ -1368,7 +1353,7 @@
|
||||
<value>クッキーを設定</value>
|
||||
</data>
|
||||
<data name="ViewFeedbackHeader" xml:space="preserve">
|
||||
<value>フィードバックセンター</value>
|
||||
<value>フィードバック センター</value>
|
||||
</data>
|
||||
<data name="ViewGachaLogHeader" xml:space="preserve">
|
||||
<value>祈願履歴</value>
|
||||
@@ -2229,7 +2214,7 @@
|
||||
<value>在游戏启动后尝试启动并使用 Better GI 进行自动化任务</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameBetterGIHeader" xml:space="preserve">
|
||||
<value>自动化任务</value>
|
||||
<value>Better GI</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameCommonHeader" xml:space="preserve">
|
||||
<value>一般</value>
|
||||
@@ -2247,7 +2232,7 @@
|
||||
<value>ファイル</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameInterProcessHeader" xml:space="preserve">
|
||||
<value>进程联动</value>
|
||||
<value>インタープロセス</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameMonitorsDescription" xml:space="preserve">
|
||||
<value>指定したディスプレイで実行</value>
|
||||
@@ -2381,9 +2366,6 @@
|
||||
<data name="ViewPageSettingBackgroundImageHeader" xml:space="preserve">
|
||||
<value>背景图片</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingBackgroundImageLocalFolderCopyrightHeader" xml:space="preserve">
|
||||
<value>当前背景为本地图片,如遇版权问题由用户个人负责</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingCacheFolderDescription" xml:space="preserve">
|
||||
<value>イメージキャッシュはここに格納されます</value>
|
||||
</data>
|
||||
@@ -2505,7 +2487,7 @@
|
||||
<value>アチーブメント</value>
|
||||
</data>
|
||||
<data name="ViewpageSettingHomeCardItemDailyNoteHeader" xml:space="preserve">
|
||||
<value>リアルタイムノート</value>
|
||||
<value>リアルタイムノート</value>
|
||||
</data>
|
||||
<data name="ViewpageSettingHomeCardItemgachaStatisticsHeader" xml:space="preserve">
|
||||
<value>祈願履歴</value>
|
||||
@@ -2639,12 +2621,6 @@
|
||||
<data name="ViewPageSettingStoreReviewNavigate" xml:space="preserve">
|
||||
<value>レビューや感想</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingThemeDescription" xml:space="preserve">
|
||||
<value>更改窗体的颜色主题</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingThemeHeader" xml:space="preserve">
|
||||
<value>颜色主题</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingTranslateNavigate" xml:space="preserve">
|
||||
<value>和訳を提供</value>
|
||||
</data>
|
||||
@@ -2654,12 +2630,6 @@
|
||||
<data name="ViewPageSettingWebview2Header" xml:space="preserve">
|
||||
<value>Webview2 ランタイム</value>
|
||||
</data>
|
||||
<data name="ViewPageSpiralAbyssTeamAppearanceDownHeader" xml:space="preserve">
|
||||
<value>下半</value>
|
||||
</data>
|
||||
<data name="ViewPageSpiralAbyssTeamAppearanceUpHeader" xml:space="preserve">
|
||||
<value>上半</value>
|
||||
</data>
|
||||
<data name="ViewPageWiKiAvatarArtifactSetCombinationHeader" xml:space="preserve">
|
||||
<value>おすすめ聖遺物</value>
|
||||
</data>
|
||||
@@ -2859,7 +2829,7 @@
|
||||
<value>QRコードでログイン</value>
|
||||
</data>
|
||||
<data name="ViewUserCookieOperationManualInputAction" xml:space="preserve">
|
||||
<value>手動入力</value>
|
||||
<value>手入力</value>
|
||||
</data>
|
||||
<data name="ViewUserCookieOperationRefreshCookieAction" xml:space="preserve">
|
||||
<value>Cookie 再取得</value>
|
||||
@@ -2922,13 +2892,13 @@
|
||||
<value>〓イベント期間〓.*?\d\.\d当バージョン期間オープン</value>
|
||||
</data>
|
||||
<data name="WebAnnouncementMatchTransientActivityTime" xml:space="preserve">
|
||||
<value>(?:〓活动时间〓|祈愿时间|【上架时间】|〓折扣时间〓).*?(\d\.\d版本更新后).*?~.*?&lt;t class="t_(?:gl|lc)".*?&gt;(.*?)&lt;/t&gt;</value>
|
||||
<value>(?:〓イベント期間〓|祈願期間|【開始日時】).*?(\d\.\dバージョンアップ完了後).*?~.*?&lt;t class="t_(?:gl|lc)".*?&gt;(.*?)&lt;/t&gt;</value>
|
||||
</data>
|
||||
<data name="WebAnnouncementMatchVersionUpdateTime" xml:space="preserve">
|
||||
<value>〓メンテナンス時間〓.+?&lt;t class=\"t_(?:gl|lc)\".*?&gt;(.*?)&lt;/t&gt;</value>
|
||||
<value>〓更新日時〓.+?&lt;t class=\"t_(?:gl|lc)\".*?&gt;(.*?)&lt;/t&gt;</value>
|
||||
</data>
|
||||
<data name="WebAnnouncementMatchVersionUpdateTitle" xml:space="preserve">
|
||||
<value>Ver.\d\.\d.+正式リリース</value>
|
||||
<value>Ver.\d\.\d 更新内容</value>
|
||||
</data>
|
||||
<data name="WebAnnouncementTimeDaysBeginFormat" xml:space="preserve">
|
||||
<value>{0} 日後に開始</value>
|
||||
@@ -3074,9 +3044,6 @@
|
||||
<data name="WebGachaConfigTypeAvatarEventWish2" xml:space="preserve">
|
||||
<value>イベント祈願・キャラクター2</value>
|
||||
</data>
|
||||
<data name="WebGachaConfigTypeChronicledWish" xml:space="preserve">
|
||||
<value>集录祈愿</value>
|
||||
</data>
|
||||
<data name="WebGachaConfigTypeNoviceWish" xml:space="preserve">
|
||||
<value>初心者祈願</value>
|
||||
</data>
|
||||
|
||||
@@ -186,18 +186,6 @@
|
||||
<data name="CoreWebView2HelperVersionUndetected" xml:space="preserve">
|
||||
<value>WebView2 런타임이 감지되지 않음</value>
|
||||
</data>
|
||||
<data name="CoreWindowHotkeyCombinationRegisterFailed" xml:space="preserve">
|
||||
<value>[{0}] 热键 [{1}] 注册失败</value>
|
||||
</data>
|
||||
<data name="CoreWindowThemeDark" xml:space="preserve">
|
||||
<value>深色</value>
|
||||
</data>
|
||||
<data name="CoreWindowThemeLight" xml:space="preserve">
|
||||
<value>浅色</value>
|
||||
</data>
|
||||
<data name="CoreWindowThemeSystem" xml:space="preserve">
|
||||
<value>跟随系统</value>
|
||||
</data>
|
||||
<data name="FilePickerExportCommit" xml:space="preserve">
|
||||
<value>내보내기</value>
|
||||
</data>
|
||||
@@ -869,9 +857,6 @@
|
||||
<data name="ServiceGachaLogFactoryAvatarWishName" xml:space="preserve">
|
||||
<value>캐릭터 이벤트</value>
|
||||
</data>
|
||||
<data name="ServiceGachaLogFactoryChronicledWishName" xml:space="preserve">
|
||||
<value>集录祈愿</value>
|
||||
</data>
|
||||
<data name="ServiceGachaLogFactoryPermanentWishName" xml:space="preserve">
|
||||
<value>세상 여행</value>
|
||||
</data>
|
||||
@@ -2229,7 +2214,7 @@
|
||||
<value>在游戏启动后尝试启动并使用 Better GI 进行自动化任务</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameBetterGIHeader" xml:space="preserve">
|
||||
<value>自动化任务</value>
|
||||
<value>Better GI</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameCommonHeader" xml:space="preserve">
|
||||
<value>보통</value>
|
||||
@@ -2247,7 +2232,7 @@
|
||||
<value>文件</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameInterProcessHeader" xml:space="preserve">
|
||||
<value>进程联动</value>
|
||||
<value>进程间</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameMonitorsDescription" xml:space="preserve">
|
||||
<value>지정한 모니터에서 실행</value>
|
||||
@@ -2381,9 +2366,6 @@
|
||||
<data name="ViewPageSettingBackgroundImageHeader" xml:space="preserve">
|
||||
<value>背景图片</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingBackgroundImageLocalFolderCopyrightHeader" xml:space="preserve">
|
||||
<value>当前背景为本地图片,如遇版权问题由用户个人负责</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingCacheFolderDescription" xml:space="preserve">
|
||||
<value>여기에 저장된 이미지 캐시</value>
|
||||
</data>
|
||||
@@ -2639,12 +2621,6 @@
|
||||
<data name="ViewPageSettingStoreReviewNavigate" xml:space="preserve">
|
||||
<value>评价软件</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingThemeDescription" xml:space="preserve">
|
||||
<value>更改窗体的颜色主题</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingThemeHeader" xml:space="preserve">
|
||||
<value>颜色主题</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingTranslateNavigate" xml:space="preserve">
|
||||
<value>번역에 기여하기</value>
|
||||
</data>
|
||||
@@ -2654,12 +2630,6 @@
|
||||
<data name="ViewPageSettingWebview2Header" xml:space="preserve">
|
||||
<value>Webview2 런타임</value>
|
||||
</data>
|
||||
<data name="ViewPageSpiralAbyssTeamAppearanceDownHeader" xml:space="preserve">
|
||||
<value>下半</value>
|
||||
</data>
|
||||
<data name="ViewPageSpiralAbyssTeamAppearanceUpHeader" xml:space="preserve">
|
||||
<value>上半</value>
|
||||
</data>
|
||||
<data name="ViewPageWiKiAvatarArtifactSetCombinationHeader" xml:space="preserve">
|
||||
<value>搭配圣遗物</value>
|
||||
</data>
|
||||
@@ -2922,7 +2892,7 @@
|
||||
<value>〓活动时间〓.*?\d\.\d版本期间持续开放</value>
|
||||
</data>
|
||||
<data name="WebAnnouncementMatchTransientActivityTime" xml:space="preserve">
|
||||
<value>(?:〓活动时间〓|祈愿时间|【上架时间】|〓折扣时间〓).*?(\d\.\d版本更新后).*?~.*?&lt;t class="t_(?:gl|lc)".*?&gt;(.*?)&lt;/t&gt;</value>
|
||||
<value>(?:〓活动时间〓|祈愿时间|【上架时间】).*?(\d\.\d版本更新后).*?~.*?&lt;t class="t_(?:gl|lc)".*?&gt;(.*?)&lt;/t&gt;</value>
|
||||
</data>
|
||||
<data name="WebAnnouncementMatchVersionUpdateTime" xml:space="preserve">
|
||||
<value>〓更新时间〓.+?&lt;t class=\"t_(?:gl|lc)\".*?&gt;(.*?)&lt;/t&gt;</value>
|
||||
@@ -3074,9 +3044,6 @@
|
||||
<data name="WebGachaConfigTypeAvatarEventWish2" xml:space="preserve">
|
||||
<value>캐릭터 이벤트 기원-2</value>
|
||||
</data>
|
||||
<data name="WebGachaConfigTypeChronicledWish" xml:space="preserve">
|
||||
<value>集录祈愿</value>
|
||||
</data>
|
||||
<data name="WebGachaConfigTypeNoviceWish" xml:space="preserve">
|
||||
<value>초심자 기원</value>
|
||||
</data>
|
||||
|
||||
@@ -186,18 +186,6 @@
|
||||
<data name="CoreWebView2HelperVersionUndetected" xml:space="preserve">
|
||||
<value>O WebView2 Runtime não foi detectado</value>
|
||||
</data>
|
||||
<data name="CoreWindowHotkeyCombinationRegisterFailed" xml:space="preserve">
|
||||
<value>[{0}] 热键 [{1}] 注册失败</value>
|
||||
</data>
|
||||
<data name="CoreWindowThemeDark" xml:space="preserve">
|
||||
<value>深色</value>
|
||||
</data>
|
||||
<data name="CoreWindowThemeLight" xml:space="preserve">
|
||||
<value>浅色</value>
|
||||
</data>
|
||||
<data name="CoreWindowThemeSystem" xml:space="preserve">
|
||||
<value>跟随系统</value>
|
||||
</data>
|
||||
<data name="FilePickerExportCommit" xml:space="preserve">
|
||||
<value>Exportar</value>
|
||||
</data>
|
||||
@@ -869,9 +857,6 @@
|
||||
<data name="ServiceGachaLogFactoryAvatarWishName" xml:space="preserve">
|
||||
<value>Evento de oração de personagem</value>
|
||||
</data>
|
||||
<data name="ServiceGachaLogFactoryChronicledWishName" xml:space="preserve">
|
||||
<value>集录祈愿</value>
|
||||
</data>
|
||||
<data name="ServiceGachaLogFactoryPermanentWishName" xml:space="preserve">
|
||||
<value>Invocação do Mochileiro</value>
|
||||
</data>
|
||||
@@ -1137,7 +1122,7 @@
|
||||
<value>Sorte média</value>
|
||||
</data>
|
||||
<data name="ViewControlStatisticsCardUpText" xml:space="preserve">
|
||||
<value>Em destaque</value>
|
||||
<value>Acima</value>
|
||||
</data>
|
||||
<data name="ViewControlStatisticsSegmentedItemContentPrediction" xml:space="preserve">
|
||||
<value>Previsão</value>
|
||||
@@ -1155,7 +1140,7 @@
|
||||
<value>Planejamento</value>
|
||||
</data>
|
||||
<data name="ViewDailyNoteHeader" xml:space="preserve">
|
||||
<value>Lembretes</value>
|
||||
<value>Lembrete em tempo real</value>
|
||||
</data>
|
||||
<data name="ViewDataHeader" xml:space="preserve">
|
||||
<value>Dados</value>
|
||||
@@ -2049,7 +2034,7 @@
|
||||
<value>Visão geral</value>
|
||||
</data>
|
||||
<data name="ViewPageGahcaLogPivotStatistics" xml:space="preserve">
|
||||
<value>Estatísticas globais</value>
|
||||
<value>全球祈愿统计</value>
|
||||
</data>
|
||||
<data name="ViewPageGahcaLogPivotWeapon" xml:space="preserve">
|
||||
<value>Arma</value>
|
||||
@@ -2229,7 +2214,7 @@
|
||||
<value>在游戏启动后尝试启动并使用 Better GI 进行自动化任务</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameBetterGIHeader" xml:space="preserve">
|
||||
<value>自动化任务</value>
|
||||
<value>Better GI</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameCommonHeader" xml:space="preserve">
|
||||
<value>Geral</value>
|
||||
@@ -2247,7 +2232,7 @@
|
||||
<value>Arquivo</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameInterProcessHeader" xml:space="preserve">
|
||||
<value>进程联动</value>
|
||||
<value>Comunicações entre processos</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameMonitorsDescription" xml:space="preserve">
|
||||
<value>Executar o software na tela selecionada</value>
|
||||
@@ -2381,9 +2366,6 @@
|
||||
<data name="ViewPageSettingBackgroundImageHeader" xml:space="preserve">
|
||||
<value>背景图片</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingBackgroundImageLocalFolderCopyrightHeader" xml:space="preserve">
|
||||
<value>当前背景为本地图片,如遇版权问题由用户个人负责</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingCacheFolderDescription" xml:space="preserve">
|
||||
<value>O cache de imagens é salvo aqui</value>
|
||||
</data>
|
||||
@@ -2639,12 +2621,6 @@
|
||||
<data name="ViewPageSettingStoreReviewNavigate" xml:space="preserve">
|
||||
<value>Avalie o Snap Hutao</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingThemeDescription" xml:space="preserve">
|
||||
<value>更改窗体的颜色主题</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingThemeHeader" xml:space="preserve">
|
||||
<value>颜色主题</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingTranslateNavigate" xml:space="preserve">
|
||||
<value>Contribuir com traduções</value>
|
||||
</data>
|
||||
@@ -2654,12 +2630,6 @@
|
||||
<data name="ViewPageSettingWebview2Header" xml:space="preserve">
|
||||
<value>Webview2 Runtime</value>
|
||||
</data>
|
||||
<data name="ViewPageSpiralAbyssTeamAppearanceDownHeader" xml:space="preserve">
|
||||
<value>下半</value>
|
||||
</data>
|
||||
<data name="ViewPageSpiralAbyssTeamAppearanceUpHeader" xml:space="preserve">
|
||||
<value>上半</value>
|
||||
</data>
|
||||
<data name="ViewPageWiKiAvatarArtifactSetCombinationHeader" xml:space="preserve">
|
||||
<value>Combinação de conjuntos de artefatos</value>
|
||||
</data>
|
||||
@@ -2922,7 +2892,7 @@
|
||||
<value>〓Duração do evento〓.*?\d\.\d Disponível em toda as versões</value>
|
||||
</data>
|
||||
<data name="WebAnnouncementMatchTransientActivityTime" xml:space="preserve">
|
||||
<value>(?:〓活动时间〓|祈愿时间|【上架时间】|〓折扣时间〓).*?(\d\.\d版本更新后).*?~.*?&lt;t class="t_(?:gl|lc)".*?&gt;(.*?)&lt;/t&gt;</value>
|
||||
<value>(?:〓Duração do evento〓|Duração da oração do evento|【Duração da disponibilidade】).*?(\d\.\dApós a atualização da versão).*?~.*?&lt;t class="t_(?:gl|lc)".*?&gt;(.*?)&lt;/t&gt;</value>
|
||||
</data>
|
||||
<data name="WebAnnouncementMatchVersionUpdateTime" xml:space="preserve">
|
||||
<value>〓Duração da manutenção da atualização.+?&lt;t class=\"t_(?:gl|lc)\".*?&gt;(.*?)&lt;/t&gt;</value>
|
||||
@@ -2991,7 +2961,7 @@
|
||||
<value>Recompensa de comissão diária resgatada</value>
|
||||
</data>
|
||||
<data name="WebDailyNoteHomeCoinRecoveryFormat" xml:space="preserve">
|
||||
<value>Estará cheio {0} às {1:HH:mm}</value>
|
||||
<value>Estará cheio em {0} {1:HH:mm}</value>
|
||||
</data>
|
||||
<data name="WebDailyNoteHomeLocked" xml:space="preserve">
|
||||
<value>Bule de Relachá não desbloqueado</value>
|
||||
@@ -3074,9 +3044,6 @@
|
||||
<data name="WebGachaConfigTypeAvatarEventWish2" xml:space="preserve">
|
||||
<value>Evento de oração de personagem-2</value>
|
||||
</data>
|
||||
<data name="WebGachaConfigTypeChronicledWish" xml:space="preserve">
|
||||
<value>集录祈愿</value>
|
||||
</data>
|
||||
<data name="WebGachaConfigTypeNoviceWish" xml:space="preserve">
|
||||
<value>Oração de Novatos</value>
|
||||
</data>
|
||||
|
||||
@@ -189,15 +189,6 @@
|
||||
<data name="CoreWindowHotkeyCombinationRegisterFailed" xml:space="preserve">
|
||||
<value>[{0}] 热键 [{1}] 注册失败</value>
|
||||
</data>
|
||||
<data name="CoreWindowThemeDark" xml:space="preserve">
|
||||
<value>深色</value>
|
||||
</data>
|
||||
<data name="CoreWindowThemeLight" xml:space="preserve">
|
||||
<value>浅色</value>
|
||||
</data>
|
||||
<data name="CoreWindowThemeSystem" xml:space="preserve">
|
||||
<value>跟随系统</value>
|
||||
</data>
|
||||
<data name="FilePickerExportCommit" xml:space="preserve">
|
||||
<value>导出</value>
|
||||
</data>
|
||||
@@ -869,9 +860,6 @@
|
||||
<data name="ServiceGachaLogFactoryAvatarWishName" xml:space="preserve">
|
||||
<value>角色活动</value>
|
||||
</data>
|
||||
<data name="ServiceGachaLogFactoryChronicledWishName" xml:space="preserve">
|
||||
<value>集录祈愿</value>
|
||||
</data>
|
||||
<data name="ServiceGachaLogFactoryPermanentWishName" xml:space="preserve">
|
||||
<value>奔行世间</value>
|
||||
</data>
|
||||
@@ -2229,7 +2217,7 @@
|
||||
<value>在游戏启动后尝试启动并使用 Better GI 进行自动化任务</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameBetterGIHeader" xml:space="preserve">
|
||||
<value>自动化任务</value>
|
||||
<value>Better GI</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameCommonHeader" xml:space="preserve">
|
||||
<value>常规</value>
|
||||
@@ -2247,7 +2235,7 @@
|
||||
<value>文件</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameInterProcessHeader" xml:space="preserve">
|
||||
<value>进程联动</value>
|
||||
<value>进程间</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameMonitorsDescription" xml:space="preserve">
|
||||
<value>在指定的显示器上运行</value>
|
||||
@@ -2381,9 +2369,6 @@
|
||||
<data name="ViewPageSettingBackgroundImageHeader" xml:space="preserve">
|
||||
<value>背景图片</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingBackgroundImageLocalFolderCopyrightHeader" xml:space="preserve">
|
||||
<value>当前背景为本地图片,如遇版权问题由用户个人负责</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingCacheFolderDescription" xml:space="preserve">
|
||||
<value>图片缓存 在此处存放</value>
|
||||
</data>
|
||||
@@ -2639,12 +2624,6 @@
|
||||
<data name="ViewPageSettingStoreReviewNavigate" xml:space="preserve">
|
||||
<value>评价软件</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingThemeDescription" xml:space="preserve">
|
||||
<value>更改窗体的颜色主题</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingThemeHeader" xml:space="preserve">
|
||||
<value>颜色主题</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingTranslateNavigate" xml:space="preserve">
|
||||
<value>贡献翻译</value>
|
||||
</data>
|
||||
@@ -2654,12 +2633,6 @@
|
||||
<data name="ViewPageSettingWebview2Header" xml:space="preserve">
|
||||
<value>Webview2 运行时</value>
|
||||
</data>
|
||||
<data name="ViewPageSpiralAbyssTeamAppearanceDownHeader" xml:space="preserve">
|
||||
<value>下半</value>
|
||||
</data>
|
||||
<data name="ViewPageSpiralAbyssTeamAppearanceUpHeader" xml:space="preserve">
|
||||
<value>上半</value>
|
||||
</data>
|
||||
<data name="ViewPageWiKiAvatarArtifactSetCombinationHeader" xml:space="preserve">
|
||||
<value>搭配圣遗物</value>
|
||||
</data>
|
||||
@@ -2922,7 +2895,7 @@
|
||||
<value>〓活动时间〓.*?\d\.\d版本期间持续开放</value>
|
||||
</data>
|
||||
<data name="WebAnnouncementMatchTransientActivityTime" xml:space="preserve">
|
||||
<value>(?:〓活动时间〓|祈愿时间|【上架时间】|〓折扣时间〓).*?(\d\.\d版本更新后).*?~.*?&lt;t class="t_(?:gl|lc)".*?&gt;(.*?)&lt;/t&gt;</value>
|
||||
<value>(?:〓活动时间〓|祈愿时间|【上架时间】).*?(\d\.\d版本更新后).*?~.*?&lt;t class="t_(?:gl|lc)".*?&gt;(.*?)&lt;/t&gt;</value>
|
||||
</data>
|
||||
<data name="WebAnnouncementMatchVersionUpdateTime" xml:space="preserve">
|
||||
<value>〓更新时间〓.+?&lt;t class=\"t_(?:gl|lc)\".*?&gt;(.*?)&lt;/t&gt;</value>
|
||||
@@ -3074,9 +3047,6 @@
|
||||
<data name="WebGachaConfigTypeAvatarEventWish2" xml:space="preserve">
|
||||
<value>角色活动祈愿-2</value>
|
||||
</data>
|
||||
<data name="WebGachaConfigTypeChronicledWish" xml:space="preserve">
|
||||
<value>集录祈愿</value>
|
||||
</data>
|
||||
<data name="WebGachaConfigTypeNoviceWish" xml:space="preserve">
|
||||
<value>新手祈愿</value>
|
||||
</data>
|
||||
|
||||
@@ -186,18 +186,6 @@
|
||||
<data name="CoreWebView2HelperVersionUndetected" xml:space="preserve">
|
||||
<value>Среда выполнения WebView2 не обнаружена</value>
|
||||
</data>
|
||||
<data name="CoreWindowHotkeyCombinationRegisterFailed" xml:space="preserve">
|
||||
<value>[{0}] 热键 [{1}] 注册失败</value>
|
||||
</data>
|
||||
<data name="CoreWindowThemeDark" xml:space="preserve">
|
||||
<value>深色</value>
|
||||
</data>
|
||||
<data name="CoreWindowThemeLight" xml:space="preserve">
|
||||
<value>浅色</value>
|
||||
</data>
|
||||
<data name="CoreWindowThemeSystem" xml:space="preserve">
|
||||
<value>跟随系统</value>
|
||||
</data>
|
||||
<data name="FilePickerExportCommit" xml:space="preserve">
|
||||
<value>Экспорт</value>
|
||||
</data>
|
||||
@@ -869,9 +857,6 @@
|
||||
<data name="ServiceGachaLogFactoryAvatarWishName" xml:space="preserve">
|
||||
<value>角色活动</value>
|
||||
</data>
|
||||
<data name="ServiceGachaLogFactoryChronicledWishName" xml:space="preserve">
|
||||
<value>集录祈愿</value>
|
||||
</data>
|
||||
<data name="ServiceGachaLogFactoryPermanentWishName" xml:space="preserve">
|
||||
<value>奔行世间</value>
|
||||
</data>
|
||||
@@ -2229,7 +2214,7 @@
|
||||
<value>在游戏启动后尝试启动并使用 Better GI 进行自动化任务</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameBetterGIHeader" xml:space="preserve">
|
||||
<value>自动化任务</value>
|
||||
<value>Better GI</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameCommonHeader" xml:space="preserve">
|
||||
<value>常规</value>
|
||||
@@ -2247,7 +2232,7 @@
|
||||
<value>文件</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameInterProcessHeader" xml:space="preserve">
|
||||
<value>进程联动</value>
|
||||
<value>进程间</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameMonitorsDescription" xml:space="preserve">
|
||||
<value>在指定的显示器上运行</value>
|
||||
@@ -2381,9 +2366,6 @@
|
||||
<data name="ViewPageSettingBackgroundImageHeader" xml:space="preserve">
|
||||
<value>背景图片</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingBackgroundImageLocalFolderCopyrightHeader" xml:space="preserve">
|
||||
<value>当前背景为本地图片,如遇版权问题由用户个人负责</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingCacheFolderDescription" xml:space="preserve">
|
||||
<value>图片缓存 在此处存放</value>
|
||||
</data>
|
||||
@@ -2639,12 +2621,6 @@
|
||||
<data name="ViewPageSettingStoreReviewNavigate" xml:space="preserve">
|
||||
<value>评价软件</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingThemeDescription" xml:space="preserve">
|
||||
<value>更改窗体的颜色主题</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingThemeHeader" xml:space="preserve">
|
||||
<value>颜色主题</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingTranslateNavigate" xml:space="preserve">
|
||||
<value>贡献翻译</value>
|
||||
</data>
|
||||
@@ -2654,12 +2630,6 @@
|
||||
<data name="ViewPageSettingWebview2Header" xml:space="preserve">
|
||||
<value>Webview2 Runtime</value>
|
||||
</data>
|
||||
<data name="ViewPageSpiralAbyssTeamAppearanceDownHeader" xml:space="preserve">
|
||||
<value>下半</value>
|
||||
</data>
|
||||
<data name="ViewPageSpiralAbyssTeamAppearanceUpHeader" xml:space="preserve">
|
||||
<value>上半</value>
|
||||
</data>
|
||||
<data name="ViewPageWiKiAvatarArtifactSetCombinationHeader" xml:space="preserve">
|
||||
<value>搭配圣遗物</value>
|
||||
</data>
|
||||
@@ -2922,7 +2892,7 @@
|
||||
<value>〓活动时间〓.*?\d\.\d版本期间持续开放</value>
|
||||
</data>
|
||||
<data name="WebAnnouncementMatchTransientActivityTime" xml:space="preserve">
|
||||
<value>(?:〓活动时间〓|祈愿时间|【上架时间】|〓折扣时间〓).*?(\d\.\d版本更新后).*?~.*?&lt;t class="t_(?:gl|lc)".*?&gt;(.*?)&lt;/t&gt;</value>
|
||||
<value>(?:〓活动时间〓|祈愿时间|【上架时间】).*?(\d\.\d版本更新后).*?~.*?&lt;t class="t_(?:gl|lc)".*?&gt;(.*?)&lt;/t&gt;</value>
|
||||
</data>
|
||||
<data name="WebAnnouncementMatchVersionUpdateTime" xml:space="preserve">
|
||||
<value>〓更新时间〓.+?&lt;t class=\"t_(?:gl|lc)\".*?&gt;(.*?)&lt;/t&gt;</value>
|
||||
@@ -3074,9 +3044,6 @@
|
||||
<data name="WebGachaConfigTypeAvatarEventWish2" xml:space="preserve">
|
||||
<value>Молитва события персонажа - 2</value>
|
||||
</data>
|
||||
<data name="WebGachaConfigTypeChronicledWish" xml:space="preserve">
|
||||
<value>集录祈愿</value>
|
||||
</data>
|
||||
<data name="WebGachaConfigTypeNoviceWish" xml:space="preserve">
|
||||
<value>Молитва новичка</value>
|
||||
</data>
|
||||
|
||||
@@ -186,18 +186,6 @@
|
||||
<data name="CoreWebView2HelperVersionUndetected" xml:space="preserve">
|
||||
<value>未檢測到 WebView2 運行時</value>
|
||||
</data>
|
||||
<data name="CoreWindowHotkeyCombinationRegisterFailed" xml:space="preserve">
|
||||
<value>[{0}] 鍵盤快速鍵 [{1}] 註冊失敗</value>
|
||||
</data>
|
||||
<data name="CoreWindowThemeDark" xml:space="preserve">
|
||||
<value>深色</value>
|
||||
</data>
|
||||
<data name="CoreWindowThemeLight" xml:space="preserve">
|
||||
<value>淺色</value>
|
||||
</data>
|
||||
<data name="CoreWindowThemeSystem" xml:space="preserve">
|
||||
<value>跟隨系統</value>
|
||||
</data>
|
||||
<data name="FilePickerExportCommit" xml:space="preserve">
|
||||
<value>匯出</value>
|
||||
</data>
|
||||
@@ -217,7 +205,7 @@
|
||||
<value><color=#1E90FF>我</color>/<color=#FFB6C1>我</color></value>
|
||||
</data>
|
||||
<data name="MetadataSpecialNameNickname" xml:space="preserve">
|
||||
<value>旅行者</value>
|
||||
<value>旅人</value>
|
||||
</data>
|
||||
<data name="MetadataSpecialNamePlayerAvatarSexProInfoPronounHeShe" xml:space="preserve">
|
||||
<value><color=#1E90FF>他</color>/<color=#FFB6C1>她</color></value>
|
||||
@@ -525,7 +513,7 @@
|
||||
<value>第四波:擊敗所有怪物,下一波才會出現</value>
|
||||
</data>
|
||||
<data name="ModelMetadataTowerWaveTypeWave99999" xml:space="preserve">
|
||||
<value>維持場上 4 個盜寶團怪物,擊殺後立即替換,總數 12 個</value>
|
||||
<value>维持场上 4 个盗宝团怪物,击杀后立即替换,总数 12 个</value>
|
||||
</data>
|
||||
<data name="ModelNameValueDefaultDescription" xml:space="preserve">
|
||||
<value>請更新角色櫥窗數據</value>
|
||||
@@ -780,19 +768,19 @@
|
||||
<value>角色櫥窗:{0:MM-dd HH:mm}</value>
|
||||
</data>
|
||||
<data name="ServiceBackgroundImageTypeBing" xml:space="preserve">
|
||||
<value>Bing每日一圖</value>
|
||||
<value>必应每日一图</value>
|
||||
</data>
|
||||
<data name="ServiceBackgroundImageTypeDaily" xml:space="preserve">
|
||||
<value>胡桃每日一圖</value>
|
||||
<value>胡桃每日一图</value>
|
||||
</data>
|
||||
<data name="ServiceBackgroundImageTypeLauncher" xml:space="preserve">
|
||||
<value>官方啟動器壁紙</value>
|
||||
<value>官方启动器壁纸</value>
|
||||
</data>
|
||||
<data name="ServiceBackgroundImageTypeLocalFolder" xml:space="preserve">
|
||||
<value>本地隨機圖片</value>
|
||||
<value>本地随机图片</value>
|
||||
</data>
|
||||
<data name="ServiceBackgroundImageTypeNone" xml:space="preserve">
|
||||
<value>無背景圖片</value>
|
||||
<value>无背景图片</value>
|
||||
</data>
|
||||
<data name="ServiceCultivationProjectCurrentUserdataCourrpted" xml:space="preserve">
|
||||
<value>保存養成計劃狀態失敗</value>
|
||||
@@ -852,7 +840,7 @@
|
||||
<value>參量質變儀已準備完成</value>
|
||||
</data>
|
||||
<data name="ServiceDiscordActivityElevationRequiredHint" xml:space="preserve">
|
||||
<value>權限不足,將無法為您設定 Discord Activity 狀態</value>
|
||||
<value>权限不足,将无法为您设置 Discord Activity 状态</value>
|
||||
</data>
|
||||
<data name="ServiceDiscordGameActivityDetails" xml:space="preserve">
|
||||
<value>正在提瓦特大陸中探索</value>
|
||||
@@ -869,9 +857,6 @@
|
||||
<data name="ServiceGachaLogFactoryAvatarWishName" xml:space="preserve">
|
||||
<value>角色活動</value>
|
||||
</data>
|
||||
<data name="ServiceGachaLogFactoryChronicledWishName" xml:space="preserve">
|
||||
<value>集錄祈願</value>
|
||||
</data>
|
||||
<data name="ServiceGachaLogFactoryPermanentWishName" xml:space="preserve">
|
||||
<value>奔行世間</value>
|
||||
</data>
|
||||
@@ -1239,7 +1224,7 @@
|
||||
<value>即時便箋 Webhook Url</value>
|
||||
</data>
|
||||
<data name="ViewDialogFeedbackEnableLoopbackContent" xml:space="preserve">
|
||||
<value>解除限制後需使用其他工具恢復限制</value>
|
||||
<value>解除限制后需要使用其他工具恢复限制</value>
|
||||
</data>
|
||||
<data name="ViewDialogFeedbackEnableLoopbackTitle" xml:space="preserve">
|
||||
<value>是否解除 Loopback 限制</value>
|
||||
@@ -1425,7 +1410,7 @@
|
||||
<value>啟動遊戲</value>
|
||||
</data>
|
||||
<data name="ViewListViewDragElevatedHint" xml:space="preserve">
|
||||
<value>管理員模式下無法拖動排序</value>
|
||||
<value>管理员模式下无法拖动排序</value>
|
||||
</data>
|
||||
<data name="ViewModelAchievementArchiveAdded" xml:space="preserve">
|
||||
<value>存檔 [{0}] 添加成功</value>
|
||||
@@ -1707,7 +1692,7 @@
|
||||
<value>完成</value>
|
||||
</data>
|
||||
<data name="ViewModelWelcomeDownloadSummaryContentTypeNotMatch" xml:space="preserve">
|
||||
<value>回應內容不是有效的檔案位元組</value>
|
||||
<value>响应内容不是有效的文件字节流</value>
|
||||
</data>
|
||||
<data name="ViewModelWelcomeDownloadSummaryDefault" xml:space="preserve">
|
||||
<value>待處理</value>
|
||||
@@ -1926,16 +1911,16 @@
|
||||
<value>常用連結</value>
|
||||
</data>
|
||||
<data name="ViewPageFeedbackCurrentProxyHeader" xml:space="preserve">
|
||||
<value>當前代理</value>
|
||||
<value>当前代理</value>
|
||||
</data>
|
||||
<data name="ViewPageFeedbackCurrentProxyNoProxyDescription" xml:space="preserve">
|
||||
<value>無代理</value>
|
||||
<value>无代理</value>
|
||||
</data>
|
||||
<data name="ViewPageFeedbackEnableLoopbackEnabledDescription" xml:space="preserve">
|
||||
<value>已解除</value>
|
||||
</data>
|
||||
<data name="ViewPageFeedbackEnableLoopbackHeader" xml:space="preserve">
|
||||
<value>是否解除 Loopback 限制</value>
|
||||
<value>解除 Loopback 限制</value>
|
||||
</data>
|
||||
<data name="ViewPageFeedbackEngageWithUsDescription" xml:space="preserve">
|
||||
<value>與我們密切聯繫</value>
|
||||
@@ -2226,10 +2211,10 @@
|
||||
<value>啟動參數</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameBetterGIDescription" xml:space="preserve">
|
||||
<value>在遊戲啟動後嘗試啟動並使用 Better GI 進行自動化任務</value>
|
||||
<value>在游戏启动后尝试启动并使用 Better GI 进行自动化任务</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameBetterGIHeader" xml:space="preserve">
|
||||
<value>自動化任務</value>
|
||||
<value>Better GI</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameCommonHeader" xml:space="preserve">
|
||||
<value>一般</value>
|
||||
@@ -2247,7 +2232,7 @@
|
||||
<value>檔案</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameInterProcessHeader" xml:space="preserve">
|
||||
<value>進程聯動</value>
|
||||
<value>行程間</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameMonitorsDescription" xml:space="preserve">
|
||||
<value>在指定的屏幕上運行</value>
|
||||
@@ -2373,16 +2358,13 @@
|
||||
<value>背景材質</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingBackgroundImageCopyrightHeader" xml:space="preserve">
|
||||
<value>圖片版權訊息</value>
|
||||
<value>图片版权信息</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingBackgroundImageDescription" xml:space="preserve">
|
||||
<value>更改視窗的背景圖片來源,重啟胡桃以盡快生效</value>
|
||||
<value>更改窗体的背景图片来源,重启胡桃以尽快生效</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingBackgroundImageHeader" xml:space="preserve">
|
||||
<value>背景圖片</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingBackgroundImageLocalFolderCopyrightHeader" xml:space="preserve">
|
||||
<value>當前背景為本地圖片,如遇版權問題由用戶個人負責</value>
|
||||
<value>背景图片</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingCacheFolderDescription" xml:space="preserve">
|
||||
<value>圖片暫存存放在此</value>
|
||||
@@ -2391,7 +2373,7 @@
|
||||
<value>暫存檔案夾</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingCardHutaoPassportHeader" xml:space="preserve">
|
||||
<value>胡桃通行證</value>
|
||||
<value>胡桃通行证</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingCopyDeviceIdAction" xml:space="preserve">
|
||||
<value>複製</value>
|
||||
@@ -2586,10 +2568,10 @@
|
||||
<value>前往官網</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingOpenBackgroundImageFolderDescription" xml:space="preserve">
|
||||
<value>自定義背景圖片,支援 bmp / gif / ico / jpg / jpeg / png / tiff / webp 格式</value>
|
||||
<value>自定义背景图片,支持 bmp / gif / ico / jpg / jpeg / png / tiff / webp 格式</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingOpenBackgroundImageFolderHeader" xml:space="preserve">
|
||||
<value>打開背景圖片資料夾</value>
|
||||
<value>打开背景图片文件夹</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingResetAction" xml:space="preserve">
|
||||
<value>重設</value>
|
||||
@@ -2601,10 +2583,10 @@
|
||||
<value>重設圖片資源</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingsAdvancedOptionsLaunchUnlockFpsDescription" xml:space="preserve">
|
||||
<value>在啟動遊戲頁面的程序部分加入解鎖幀率限制選項</value>
|
||||
<value>在启动游戏页面的进程部分加入解锁帧率限制选项</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingsAdvancedOptionsLaunchUnlockFpsHeader" xml:space="preserve">
|
||||
<value>啟動遊戲-解鎖幀率限制</value>
|
||||
<value>启动游戏-解锁帧率限制</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingSetDataFolderDescription" xml:space="preserve">
|
||||
<value>更改目錄后需要手動移動目錄内的數據,否則會重新創建用戶數據</value>
|
||||
@@ -2639,12 +2621,6 @@
|
||||
<data name="ViewPageSettingStoreReviewNavigate" xml:space="preserve">
|
||||
<value>評價軟體</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingThemeDescription" xml:space="preserve">
|
||||
<value>更改窗體的顏色主題</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingThemeHeader" xml:space="preserve">
|
||||
<value>顏色主題</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingTranslateNavigate" xml:space="preserve">
|
||||
<value>貢獻翻譯</value>
|
||||
</data>
|
||||
@@ -2654,12 +2630,6 @@
|
||||
<data name="ViewPageSettingWebview2Header" xml:space="preserve">
|
||||
<value>WebView 2 運行時</value>
|
||||
</data>
|
||||
<data name="ViewPageSpiralAbyssTeamAppearanceDownHeader" xml:space="preserve">
|
||||
<value>下半</value>
|
||||
</data>
|
||||
<data name="ViewPageSpiralAbyssTeamAppearanceUpHeader" xml:space="preserve">
|
||||
<value>上半</value>
|
||||
</data>
|
||||
<data name="ViewPageWiKiAvatarArtifactSetCombinationHeader" xml:space="preserve">
|
||||
<value>搭配聖遺物</value>
|
||||
</data>
|
||||
@@ -2922,7 +2892,7 @@
|
||||
<value>〓活動時間〓.*?\d\.\d版本期間持續開放</value>
|
||||
</data>
|
||||
<data name="WebAnnouncementMatchTransientActivityTime" xml:space="preserve">
|
||||
<value>(?:〓活動時間〓|祈願時間|【上架時間】|〓折扣時間〓).*?(\d\.\d版本更新後).*?~.*?&lt;t class="t_(?:gl|lc)".*?&gt;(.*?)&lt;/t&gt;</value>
|
||||
<value>(?:〓活動時間〓|祈願時間|【上架時間】).*?(\d\.\d版本更新後).*?~.*?&lt;t class="t_(?:gl|lc)".*?&gt;(.*?)&lt;/t&gt;</value>
|
||||
</data>
|
||||
<data name="WebAnnouncementMatchVersionUpdateTime" xml:space="preserve">
|
||||
<value>〓更新時間〓.+?&lt;t class=\"t_(?:gl|lc)\".*?&gt;(.*?)&lt;/t&gt;</value>
|
||||
@@ -3074,9 +3044,6 @@
|
||||
<data name="WebGachaConfigTypeAvatarEventWish2" xml:space="preserve">
|
||||
<value>角色活動祈願-2</value>
|
||||
</data>
|
||||
<data name="WebGachaConfigTypeChronicledWish" xml:space="preserve">
|
||||
<value>集錄祈願</value>
|
||||
</data>
|
||||
<data name="WebGachaConfigTypeNoviceWish" xml:space="preserve">
|
||||
<value>新手祈願</value>
|
||||
</data>
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 8.0 KiB After Width: | Height: | Size: 5.5 KiB |
@@ -85,13 +85,8 @@ internal sealed partial class AnnouncementService : IAnnouncementService
|
||||
{
|
||||
foreach (ref readonly Announcement item in CollectionsMarshal.AsSpan(listWrapper.List))
|
||||
{
|
||||
item.Subtitle = new StringBuilder(item.Subtitle)
|
||||
.Replace("\r<br>", string.Empty)
|
||||
.Replace("<br />", string.Empty)
|
||||
.ToString();
|
||||
item.Content = AnnouncementRegex
|
||||
.XmlTimeTagRegex()
|
||||
.Replace(item.Content, x => x.Groups[1].Value);
|
||||
item.Subtitle = new StringBuilder(item.Subtitle).Replace("\r<br>", string.Empty).ToString();
|
||||
item.Content = AnnouncementRegex.XmlTimeTagRegex().Replace(item.Content, x => x.Groups[1].Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.UI.Xaml;
|
||||
using Snap.Hutao.Core.Windowing;
|
||||
using Snap.Hutao.Model;
|
||||
using Snap.Hutao.Model.Entity;
|
||||
@@ -17,7 +16,6 @@ internal sealed partial class AppOptions : DbStoreOptions
|
||||
{
|
||||
private bool? isEmptyHistoryWishVisible;
|
||||
private BackdropType? backdropType;
|
||||
private ElementTheme? elementTheme;
|
||||
private BackgroundImageType? backgroundImageType;
|
||||
private Region? region;
|
||||
private string? geetestCustomCompositeUrl;
|
||||
@@ -36,19 +34,6 @@ internal sealed partial class AppOptions : DbStoreOptions
|
||||
set => SetOption(ref backdropType, SettingEntry.SystemBackdropType, value, EnumToStringOrEmpty);
|
||||
}
|
||||
|
||||
public Lazy<List<NameValue<ElementTheme>>> LazyElementThemes { get; } = new(() =>
|
||||
[
|
||||
new(SH.CoreWindowThemeLight, ElementTheme.Light),
|
||||
new(SH.CoreWindowThemeDark, ElementTheme.Dark),
|
||||
new(SH.CoreWindowThemeSystem, ElementTheme.Default),
|
||||
]);
|
||||
|
||||
public ElementTheme ElementTheme
|
||||
{
|
||||
get => GetOption(ref elementTheme, SettingEntry.ElementTheme, EnumParse<ElementTheme>, ElementTheme.Default).Value;
|
||||
set => SetOption(ref elementTheme, SettingEntry.ElementTheme, value, EnumToStringOrEmpty);
|
||||
}
|
||||
|
||||
public List<NameValue<BackgroundImageType>> BackgroundImageTypes { get; } = CollectionsNameValue.FromEnum<BackgroundImageType>(type => type.GetLocalizedDescription());
|
||||
|
||||
public BackgroundImageType BackgroundImageType
|
||||
|
||||
@@ -28,16 +28,16 @@ internal sealed partial class BackgroundImageService : IBackgroundImageService
|
||||
|
||||
private HashSet<string> currentBackgroundPathSet;
|
||||
|
||||
public async ValueTask<ValueResult<bool, BackgroundImage?>> GetNextBackgroundImageAsync(BackgroundImage? previous)
|
||||
public async ValueTask<ValueResult<bool, BackgroundImage>> GetNextBackgroundImageAsync(BackgroundImage? previous)
|
||||
{
|
||||
HashSet<string> backgroundSet = await SkipOrInitBackgroundAsync().ConfigureAwait(false);
|
||||
|
||||
if (backgroundSet.Count <= 0)
|
||||
{
|
||||
return new(true, default!);
|
||||
return new(false, default!);
|
||||
}
|
||||
|
||||
string path = System.Random.Shared.GetItems([.. backgroundSet], 1)[0];
|
||||
string path = System.Random.Shared.GetItems([..backgroundSet], 1)[0];
|
||||
backgroundSet.Remove(path);
|
||||
|
||||
if (string.Equals(path, previous?.Path, StringComparison.OrdinalIgnoreCase))
|
||||
@@ -109,9 +109,6 @@ internal sealed partial class BackgroundImageService : IBackgroundImageService
|
||||
case BackgroundImageType.HutaoOfficialLauncher:
|
||||
await SetCurrentBackgroundPathSetAsync(client => client.GetLauncherWallpaperAsync()).ConfigureAwait(false);
|
||||
break;
|
||||
default:
|
||||
currentBackgroundPathSet = [];
|
||||
break;
|
||||
}
|
||||
|
||||
currentBackgroundPathSet ??= [];
|
||||
|
||||
@@ -5,5 +5,5 @@ namespace Snap.Hutao.Service.BackgroundImage;
|
||||
|
||||
internal interface IBackgroundImageService
|
||||
{
|
||||
ValueTask<ValueResult<bool, BackgroundImage?>> GetNextBackgroundImageAsync(BackgroundImage? previous);
|
||||
ValueTask<ValueResult<bool, BackgroundImage>> GetNextBackgroundImageAsync(BackgroundImage? previous);
|
||||
}
|
||||
@@ -39,7 +39,7 @@ internal sealed partial class CultivationService : ICultivationService
|
||||
List<InventoryItem> entities = cultivationDbService.GetInventoryItemListByProjectId(projectId);
|
||||
|
||||
List<InventoryItemView> results = [];
|
||||
foreach (Material meta in context.EnumerateInventoryMaterial())
|
||||
foreach (Material meta in context.EnumerateInventroyMaterial())
|
||||
{
|
||||
InventoryItem entity = entities.SingleOrDefault(e => e.ItemId == meta.Id) ?? InventoryItem.From(projectId, meta.Id);
|
||||
results.Add(new(entity, meta, saveCommand));
|
||||
|
||||
@@ -41,33 +41,39 @@ internal sealed partial class DiscordService : IDiscordService, IDisposable
|
||||
|
||||
private bool IsSupported()
|
||||
{
|
||||
// Actually requires a discord client to be running on Windows platform.
|
||||
// If not, discord core creation code will throw.
|
||||
Process[] discordProcesses = Process.GetProcessesByName("Discord");
|
||||
|
||||
if (discordProcesses.Length <= 0)
|
||||
try
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// Actually requires a discord client to be running on Windows platform.
|
||||
// If not, discord core creation code will throw.
|
||||
Process[] discordProcesses = Process.GetProcessesByName("Discord");
|
||||
|
||||
foreach (Process process in discordProcesses)
|
||||
{
|
||||
try
|
||||
if (discordProcesses.Length <= 0)
|
||||
{
|
||||
_ = process.Handle;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
if (!isInitialized)
|
||||
{
|
||||
isInitialized = true;
|
||||
infoBarService.Warning(SH.ServiceDiscordActivityElevationRequiredHint);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
foreach (Process process in discordProcesses)
|
||||
{
|
||||
try
|
||||
{
|
||||
_ = process.Handle;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
if (!isInitialized)
|
||||
{
|
||||
infoBarService.Warning(SH.ServiceDiscordActivityElevationRequiredHint);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
isInitialized = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
||||
using System.Collections.Frozen;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Snap.Hutao.Service.GachaLog.Factory;
|
||||
|
||||
/// <summary>
|
||||
/// 祈愿配置类型比较器
|
||||
/// </summary>
|
||||
internal sealed class GachaConfigTypeComparer : IComparer<GachaConfigType>
|
||||
{
|
||||
private static readonly Lazy<GachaConfigTypeComparer> LazyShared = new(() => new());
|
||||
private static readonly FrozenDictionary<GachaConfigType, int> OrderMap = new Dictionary<GachaConfigType, int>()
|
||||
{
|
||||
[GachaConfigType.AvatarEventWish] = 0,
|
||||
[GachaConfigType.AvatarEventWish2] = 1,
|
||||
[GachaConfigType.WeaponEventWish] = 2,
|
||||
[GachaConfigType.StandardWish] = 3,
|
||||
[GachaConfigType.NoviceWish] = 4,
|
||||
}.ToFrozenDictionary();
|
||||
|
||||
/// <summary>
|
||||
/// 共享的比较器
|
||||
/// </summary>
|
||||
public static GachaConfigTypeComparer Shared { get => LazyShared.Value; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int Compare(GachaConfigType x, GachaConfigType y)
|
||||
{
|
||||
return OrderOf(x) - OrderOf(y);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static int OrderOf(GachaConfigType type)
|
||||
{
|
||||
return OrderMap.GetValueOrDefault(type, 0);
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
using Snap.Hutao.Model.Metadata.Abstraction;
|
||||
using Snap.Hutao.ViewModel.GachaLog;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using Windows.UI;
|
||||
@@ -26,7 +25,7 @@ internal static class GachaStatisticsExtension
|
||||
bool isPreviousUp = true;
|
||||
|
||||
// mark the IsGuarantee
|
||||
foreach (ref readonly SummaryItem item in CollectionsMarshal.AsSpan(summaryItems))
|
||||
foreach (SummaryItem item in summaryItems)
|
||||
{
|
||||
if (item.IsUp && (!isPreviousUp))
|
||||
{
|
||||
@@ -63,4 +62,4 @@ internal static class GachaStatisticsExtension
|
||||
ReadOnlySpan<byte> codes = MD5.HashData(Encoding.UTF8.GetBytes(name));
|
||||
return Color.FromArgb(255, codes.Slice(0, 5).Average(), codes.Slice(5, 5).Average(), codes.Slice(10, 5).Average());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
|
||||
using Snap.Hutao.Core.ExceptionService;
|
||||
using Snap.Hutao.Model.Intrinsic;
|
||||
using Snap.Hutao.Model.Metadata;
|
||||
using Snap.Hutao.Model.Metadata.Avatar;
|
||||
using Snap.Hutao.Model.Metadata.Weapon;
|
||||
using Snap.Hutao.Service.Metadata;
|
||||
using Snap.Hutao.Service.Metadata.ContextAbstraction;
|
||||
using Snap.Hutao.ViewModel.GachaLog;
|
||||
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
||||
using Snap.Hutao.Web.Hutao.GachaLog;
|
||||
@@ -31,8 +31,9 @@ internal sealed partial class GachaStatisticsFactory : IGachaStatisticsFactory
|
||||
public async ValueTask<GachaStatistics> CreateAsync(List<Model.Entity.GachaItem> items, GachaLogServiceMetadataContext context)
|
||||
{
|
||||
await taskContext.SwitchToBackgroundAsync();
|
||||
List<GachaEvent> gachaEvents = await metadataService.GetGachaEventListAsync().ConfigureAwait(false);
|
||||
List<HistoryWishBuilder> historyWishBuilders = gachaEvents.SelectList(gachaEvent => new HistoryWishBuilder(gachaEvent, context));
|
||||
|
||||
List<HistoryWishBuilder> historyWishBuilders = context.GachaEvents.SelectList(gachaEvent => new HistoryWishBuilder(gachaEvent, context));
|
||||
return CreateCore(taskContext, homaGachaLogClient, items, historyWishBuilders, context, options.IsEmptyHistoryWishVisible);
|
||||
}
|
||||
|
||||
@@ -53,9 +54,6 @@ internal sealed partial class GachaStatisticsFactory : IGachaStatisticsFactory
|
||||
TypedWishSummaryBuilderContext weaponContext = TypedWishSummaryBuilderContext.WeaponEventWish(taskContext, gachaLogClient);
|
||||
TypedWishSummaryBuilder weaponWishBuilder = new(weaponContext);
|
||||
|
||||
TypedWishSummaryBuilderContext chronicledContext = TypedWishSummaryBuilderContext.ChronicledWish(taskContext, gachaLogClient);
|
||||
TypedWishSummaryBuilder chronicledWishBuilder = new(chronicledContext);
|
||||
|
||||
Dictionary<Avatar, int> orangeAvatarCounter = [];
|
||||
Dictionary<Avatar, int> purpleAvatarCounter = [];
|
||||
Dictionary<Weapon, int> orangeWeaponCounter = [];
|
||||
@@ -63,25 +61,24 @@ internal sealed partial class GachaStatisticsFactory : IGachaStatisticsFactory
|
||||
Dictionary<Weapon, int> blueWeaponCounter = [];
|
||||
|
||||
// Pre group builders
|
||||
Dictionary<GachaType, List<HistoryWishBuilder>> historyWishBuilderMap = historyWishBuilders
|
||||
Dictionary<GachaConfigType, List<HistoryWishBuilder>> historyWishBuilderMap = historyWishBuilders
|
||||
.GroupBy(b => b.ConfigType)
|
||||
.ToDictionary(g => g.Key, g => g.ToList().SortBy(b => b.From));
|
||||
|
||||
// Items are ordered by precise time, first is oldest
|
||||
// 'ref' is not allowed here because we have lambda below
|
||||
foreach (ref readonly Model.Entity.GachaItem item in CollectionsMarshal.AsSpan(items))
|
||||
foreach (Model.Entity.GachaItem item in CollectionsMarshal.AsSpan(items))
|
||||
{
|
||||
// Find target history wish to operate. // banner.From <= item.Time <= banner.To
|
||||
Model.Entity.GachaItem pinned = item;
|
||||
HistoryWishBuilder? targetHistoryWishBuilder = item.GachaType is not (GachaType.Standard or GachaType.NewBie)
|
||||
? historyWishBuilderMap[item.GachaType].BinarySearch(banner => pinned.Time < banner.From ? -1 : pinned.Time > banner.To ? 1 : 0)
|
||||
// Find target history wish to operate. // w.From <= item.Time <= w.To
|
||||
HistoryWishBuilder? targetHistoryWishBuilder = item.GachaType is not (GachaConfigType.StandardWish or GachaConfigType.NoviceWish)
|
||||
? historyWishBuilderMap[item.GachaType].BinarySearch(w => item.Time < w.From ? -1 : item.Time > w.To ? 1 : 0)
|
||||
: default;
|
||||
|
||||
switch (item.ItemId.StringLength())
|
||||
{
|
||||
case 8U:
|
||||
{
|
||||
Avatar avatar = context.GetAvatar(item.ItemId);
|
||||
Avatar avatar = context.IdAvatarMap[item.ItemId];
|
||||
|
||||
bool isUp = false;
|
||||
switch (avatar.Quality)
|
||||
@@ -101,7 +98,6 @@ internal sealed partial class GachaStatisticsFactory : IGachaStatisticsFactory
|
||||
standardWishBuilder.Track(item, avatar, isUp);
|
||||
avatarWishBuilder.Track(item, avatar, isUp);
|
||||
weaponWishBuilder.Track(item, avatar, isUp);
|
||||
chronicledWishBuilder.Track(item, avatar, isUp);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -131,18 +127,17 @@ internal sealed partial class GachaStatisticsFactory : IGachaStatisticsFactory
|
||||
standardWishBuilder.Track(item, weapon, isUp);
|
||||
avatarWishBuilder.Track(item, weapon, isUp);
|
||||
weaponWishBuilder.Track(item, weapon, isUp);
|
||||
chronicledWishBuilder.Track(item, weapon, isUp);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
// ItemId string length not correct.
|
||||
HutaoException.GachaStatisticsInvalidItemId(item.ItemId);
|
||||
ThrowHelper.UserdataCorrupted(SH.FormatServiceGachaStatisticsFactoryItemIdInvalid(item.ItemId), default!);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
AsyncBarrier barrier = new(4);
|
||||
AsyncBarrier barrier = new(3);
|
||||
|
||||
return new()
|
||||
{
|
||||
@@ -150,7 +145,7 @@ internal sealed partial class GachaStatisticsFactory : IGachaStatisticsFactory
|
||||
HistoryWishes = historyWishBuilders
|
||||
.Where(b => isEmptyHistoryWishVisible || (!b.IsEmpty))
|
||||
.OrderByDescending(builder => builder.From)
|
||||
.ThenBy(builder => builder.ConfigType, GachaTypeComparer.Shared)
|
||||
.ThenBy(builder => builder.ConfigType, GachaConfigTypeComparer.Shared)
|
||||
.Select(builder => builder.ToHistoryWish())
|
||||
.ToList(),
|
||||
|
||||
@@ -167,7 +162,6 @@ internal sealed partial class GachaStatisticsFactory : IGachaStatisticsFactory
|
||||
StandardWish = standardWishBuilder.ToTypedWishSummary(barrier),
|
||||
AvatarWish = avatarWishBuilder.ToTypedWishSummary(barrier),
|
||||
WeaponWish = weaponWishBuilder.ToTypedWishSummary(barrier),
|
||||
ChronicledWish = chronicledWishBuilder.ToTypedWishSummary(barrier),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -62,29 +62,22 @@ internal sealed partial class GachaStatisticsSlimFactory : IGachaStatisticsSlimF
|
||||
int weaponPurpleTracker = 0;
|
||||
TypedWishSummarySlim weaponWish = new(SH.ServiceGachaLogFactoryWeaponWishName, 80, 10);
|
||||
|
||||
int chronicledOrangeTracker = 0;
|
||||
int chronicledPurpleTracker = 0;
|
||||
TypedWishSummarySlim chronicledWish = new(SH.ServiceGachaLogFactoryChronicledWishName, 90, 10);
|
||||
|
||||
// O(n) operation
|
||||
foreach (ref readonly GachaItem item in CollectionsMarshal.AsSpan(items))
|
||||
{
|
||||
INameQuality nameQuality = context.GetNameQualityByItemId(item.ItemId);
|
||||
switch (item.QueryType)
|
||||
{
|
||||
case GachaType.Standard:
|
||||
case GachaConfigType.StandardWish:
|
||||
Track(nameQuality, ref standardOrangeTracker, ref standardPurpleTracker);
|
||||
break;
|
||||
case GachaType.ActivityAvatar:
|
||||
case GachaType.SpecialActivityAvatar:
|
||||
case GachaConfigType.AvatarEventWish:
|
||||
case GachaConfigType.AvatarEventWish2:
|
||||
Track(nameQuality, ref avatarOrangeTracker, ref avatarPurpleTracker);
|
||||
break;
|
||||
case GachaType.ActivityWeapon:
|
||||
case GachaConfigType.WeaponEventWish:
|
||||
Track(nameQuality, ref weaponOrangeTracker, ref weaponPurpleTracker);
|
||||
break;
|
||||
case GachaType.ActivityCity:
|
||||
Track(nameQuality, ref chronicledOrangeTracker, ref chronicledPurpleTracker);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -92,16 +85,11 @@ internal sealed partial class GachaStatisticsSlimFactory : IGachaStatisticsSlimF
|
||||
|
||||
standardWish.LastOrangePull = standardOrangeTracker;
|
||||
standardWish.LastPurplePull = standardPurpleTracker;
|
||||
|
||||
avatarWish.LastOrangePull = avatarOrangeTracker;
|
||||
avatarWish.LastPurplePull = avatarPurpleTracker;
|
||||
|
||||
weaponWish.LastOrangePull = weaponOrangeTracker;
|
||||
weaponWish.LastPurplePull = weaponPurpleTracker;
|
||||
|
||||
chronicledWish.LastOrangePull = chronicledOrangeTracker;
|
||||
chronicledWish.LastPurplePull = chronicledPurpleTracker;
|
||||
|
||||
return new()
|
||||
{
|
||||
Uid = uid,
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
||||
using System.Collections.Frozen;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Snap.Hutao.Service.GachaLog.Factory;
|
||||
|
||||
/// <summary>
|
||||
/// 祈愿配置类型比较器
|
||||
/// </summary>
|
||||
internal sealed class GachaTypeComparer : IComparer<GachaType>
|
||||
{
|
||||
private static readonly Lazy<GachaTypeComparer> LazyShared = new(() => new());
|
||||
private static readonly FrozenDictionary<GachaType, int> OrderMap = FrozenDictionary.ToFrozenDictionary(
|
||||
[
|
||||
KeyValuePair.Create(GachaType.ActivityAvatar, 0),
|
||||
KeyValuePair.Create(GachaType.SpecialActivityAvatar, 1),
|
||||
KeyValuePair.Create(GachaType.ActivityWeapon, 2),
|
||||
KeyValuePair.Create(GachaType.ActivityCity, 3),
|
||||
KeyValuePair.Create(GachaType.Standard, 4),
|
||||
KeyValuePair.Create(GachaType.NewBie, 5),
|
||||
]);
|
||||
|
||||
/// <summary>
|
||||
/// 共享的比较器
|
||||
/// </summary>
|
||||
public static GachaTypeComparer Shared { get => LazyShared.Value; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int Compare(GachaType x, GachaType y)
|
||||
{
|
||||
return OrderOf(x) - OrderOf(y);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static int OrderOf(GachaType type)
|
||||
{
|
||||
return OrderMap.GetValueOrDefault(type, 0);
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,7 @@ internal sealed class HistoryWishBuilder
|
||||
/// </summary>
|
||||
/// <param name="gachaEvent">卡池配置</param>
|
||||
/// <param name="context">祈愿记录上下文</param>
|
||||
[SuppressMessage("", "SH002")]
|
||||
public HistoryWishBuilder(GachaEvent gachaEvent, GachaLogServiceMetadataContext context)
|
||||
{
|
||||
this.gachaEvent = gachaEvent;
|
||||
@@ -36,27 +37,21 @@ internal sealed class HistoryWishBuilder
|
||||
|
||||
switch (ConfigType)
|
||||
{
|
||||
case GachaType.ActivityAvatar or GachaType.SpecialActivityAvatar:
|
||||
case GachaConfigType.AvatarEventWish or GachaConfigType.AvatarEventWish2:
|
||||
orangeUpCounter = gachaEvent.UpOrangeList.Select(id => context.IdAvatarMap[id]).ToDictionary(a => (IStatisticsItemSource)a, a => 0);
|
||||
purpleUpCounter = gachaEvent.UpPurpleList.Select(id => context.IdAvatarMap[id]).ToDictionary(a => (IStatisticsItemSource)a, a => 0);
|
||||
break;
|
||||
case GachaType.ActivityWeapon:
|
||||
case GachaConfigType.WeaponEventWish:
|
||||
orangeUpCounter = gachaEvent.UpOrangeList.Select(id => context.IdWeaponMap[id]).ToDictionary(w => (IStatisticsItemSource)w, w => 0);
|
||||
purpleUpCounter = gachaEvent.UpPurpleList.Select(id => context.IdWeaponMap[id]).ToDictionary(w => (IStatisticsItemSource)w, w => 0);
|
||||
break;
|
||||
case GachaType.ActivityCity:
|
||||
|
||||
// Avatars are less than weapons, so we try to get the value from avatar map first
|
||||
orangeUpCounter = gachaEvent.UpOrangeList.Select(id => (IStatisticsItemSource?)context.IdAvatarMap.GetValueOrDefault(id) ?? context.IdWeaponMap[id]).ToDictionary(c => c, c => 0);
|
||||
purpleUpCounter = gachaEvent.UpPurpleList.Select(id => (IStatisticsItemSource?)context.IdAvatarMap.GetValueOrDefault(id) ?? context.IdWeaponMap[id]).ToDictionary(c => c, c => 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 祈愿配置类型
|
||||
/// </summary>
|
||||
public GachaType ConfigType { get; }
|
||||
public GachaConfigType ConfigType { get; }
|
||||
|
||||
/// <inheritdoc cref="GachaEvent.From"/>
|
||||
public DateTimeOffset From { get => gachaEvent.From; }
|
||||
@@ -111,13 +106,13 @@ internal sealed class HistoryWishBuilder
|
||||
{
|
||||
HistoryWish historyWish = new()
|
||||
{
|
||||
// Base
|
||||
// base
|
||||
Name = gachaEvent.Name,
|
||||
From = gachaEvent.From,
|
||||
To = gachaEvent.To,
|
||||
TotalCount = totalCountTracker,
|
||||
|
||||
// Fill
|
||||
// fill
|
||||
Version = gachaEvent.Version,
|
||||
BannerImage = gachaEvent.Banner,
|
||||
OrangeUpList = orangeUpCounter.ToStatisticsList(),
|
||||
|
||||
@@ -5,7 +5,6 @@ using Snap.Hutao.Core.ExceptionService;
|
||||
using Snap.Hutao.Model.Intrinsic;
|
||||
using Snap.Hutao.Model.Metadata;
|
||||
using Snap.Hutao.Model.Metadata.Abstraction;
|
||||
using Snap.Hutao.Service.Metadata.ContextAbstraction;
|
||||
using Snap.Hutao.ViewModel.GachaLog;
|
||||
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
||||
using Snap.Hutao.Web.Hutao.GachaLog;
|
||||
@@ -19,20 +18,18 @@ internal sealed class HutaoStatisticsFactory
|
||||
private readonly GachaEvent avatarEvent;
|
||||
private readonly GachaEvent avatarEvent2;
|
||||
private readonly GachaEvent weaponEvent;
|
||||
private readonly GachaEvent chronicledEvent;
|
||||
|
||||
public HutaoStatisticsFactory(in HutaoStatisticsFactoryMetadataContext context)
|
||||
{
|
||||
this.context = context;
|
||||
|
||||
// when in new verion
|
||||
// TODO: when in new verion
|
||||
// due to lack of newer metadata
|
||||
// this can crash
|
||||
DateTimeOffset now = DateTimeOffset.UtcNow;
|
||||
avatarEvent = context.GachaEvents.Single(g => g.From < now && g.To > now && g.Type == GachaType.ActivityAvatar);
|
||||
avatarEvent2 = context.GachaEvents.Single(g => g.From < now && g.To > now && g.Type == GachaType.SpecialActivityAvatar);
|
||||
weaponEvent = context.GachaEvents.Single(g => g.From < now && g.To > now && g.Type == GachaType.ActivityWeapon);
|
||||
chronicledEvent = context.GachaEvents.Single(g => g.From < now && g.To > now && g.Type == GachaType.ActivityCity);
|
||||
avatarEvent = context.GachaEvents.Single(g => g.From < now && g.To > now && g.Type == GachaConfigType.AvatarEventWish);
|
||||
avatarEvent2 = context.GachaEvents.Single(g => g.From < now && g.To > now && g.Type == GachaConfigType.AvatarEventWish2);
|
||||
weaponEvent = context.GachaEvents.Single(g => g.From < now && g.To > now && g.Type == GachaConfigType.WeaponEventWish);
|
||||
}
|
||||
|
||||
public HutaoStatistics Create(GachaEventStatistics raw)
|
||||
@@ -41,8 +38,7 @@ internal sealed class HutaoStatisticsFactory
|
||||
{
|
||||
AvatarEvent = CreateWishSummary(avatarEvent, raw.AvatarEvent),
|
||||
AvatarEvent2 = CreateWishSummary(avatarEvent2, raw.AvatarEvent2),
|
||||
WeaponEvent = CreateWishSummary(weaponEvent, raw.WeaponEvent),
|
||||
Chronicled = CreateWishSummary(chronicledEvent, raw.Chronicled),
|
||||
WeaponWish = CreateWishSummary(weaponEvent, raw.WeaponEvent),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -57,13 +53,12 @@ internal sealed class HutaoStatisticsFactory
|
||||
{
|
||||
IStatisticsItemSource source = item.Item.StringLength() switch
|
||||
{
|
||||
8U => context.GetAvatar(item.Item),
|
||||
5U => context.GetWeapon(item.Item),
|
||||
_ => throw HutaoException.GachaStatisticsInvalidItemId(item.Item),
|
||||
8U => context.IdAvatarMap[item.Item],
|
||||
5U => context.IdWeaponMap[item.Item],
|
||||
_ => throw ThrowHelper.UserdataCorrupted(SH.FormatServiceGachaStatisticsFactoryItemIdInvalid(item.Item), default!),
|
||||
};
|
||||
StatisticsItem statisticsItem = source.ToStatisticsItem(unchecked((int)item.Count));
|
||||
|
||||
// Put UP items to a separate list
|
||||
if (gachaEvent.UpOrangeList.Contains(item.Item) || gachaEvent.UpPurpleList.Contains(item.Item))
|
||||
{
|
||||
upItems.Add(statisticsItem);
|
||||
|
||||
@@ -5,18 +5,19 @@ using Snap.Hutao.Model.Metadata;
|
||||
using Snap.Hutao.Model.Metadata.Avatar;
|
||||
using Snap.Hutao.Model.Metadata.Weapon;
|
||||
using Snap.Hutao.Model.Primitive;
|
||||
using Snap.Hutao.Service.Metadata.ContextAbstraction;
|
||||
|
||||
namespace Snap.Hutao.Service.GachaLog.Factory;
|
||||
|
||||
internal sealed class HutaoStatisticsFactoryMetadataContext : IMetadataContext,
|
||||
IMetadataDictionaryIdAvatarSource,
|
||||
IMetadataDictionaryIdWeaponSource,
|
||||
IMetadataListGachaEventSource
|
||||
internal readonly struct HutaoStatisticsFactoryMetadataContext
|
||||
{
|
||||
public Dictionary<AvatarId, Avatar> IdAvatarMap { get; set; } = default!;
|
||||
public readonly Dictionary<AvatarId, Avatar> IdAvatarMap;
|
||||
public readonly Dictionary<WeaponId, Weapon> IdWeaponMap;
|
||||
public readonly List<GachaEvent> GachaEvents;
|
||||
|
||||
public Dictionary<WeaponId, Weapon> IdWeaponMap { get; set; } = default!;
|
||||
|
||||
public List<GachaEvent> GachaEvents { get; set; } = default!;
|
||||
public HutaoStatisticsFactoryMetadataContext(Dictionary<AvatarId, Avatar> idAvatarMap, Dictionary<WeaponId, Weapon> idWeaponMap, List<GachaEvent> gachaEvents)
|
||||
{
|
||||
IdAvatarMap = idAvatarMap;
|
||||
IdWeaponMap = idWeaponMap;
|
||||
GachaEvents = gachaEvents;
|
||||
}
|
||||
}
|
||||
@@ -38,10 +38,6 @@ internal sealed class PullPrediction
|
||||
typedWishSummary.PredictedPullLeftToOrange = result.PredictedPullLeftToOrange;
|
||||
typedWishSummary.IsPredictPullAvailable = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
await barrier.SignalAndWaitAsync().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
private static PredictResult PredictCore(List<PullCount> distribution, TypedWishSummary typedWishSummary)
|
||||
|
||||
@@ -5,6 +5,7 @@ using Snap.Hutao.Model.Entity;
|
||||
using Snap.Hutao.Model.Intrinsic;
|
||||
using Snap.Hutao.Model.Metadata.Abstraction;
|
||||
using Snap.Hutao.ViewModel.GachaLog;
|
||||
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
||||
|
||||
namespace Snap.Hutao.Service.GachaLog.Factory;
|
||||
|
||||
@@ -14,6 +15,21 @@ namespace Snap.Hutao.Service.GachaLog.Factory;
|
||||
[HighQuality]
|
||||
internal sealed class TypedWishSummaryBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// 常驻祈愿
|
||||
/// </summary>
|
||||
public static readonly Func<GachaConfigType, bool> IsStandardWish = type => type is GachaConfigType.StandardWish;
|
||||
|
||||
/// <summary>
|
||||
/// 角色活动
|
||||
/// </summary>
|
||||
public static readonly Func<GachaConfigType, bool> IsAvatarEventWish = type => type is GachaConfigType.AvatarEventWish or GachaConfigType.AvatarEventWish2;
|
||||
|
||||
/// <summary>
|
||||
/// 武器活动
|
||||
/// </summary>
|
||||
public static readonly Func<GachaConfigType, bool> IsWeaponEventWish = type => type is GachaConfigType.WeaponEventWish;
|
||||
|
||||
private readonly TypedWishSummaryBuilderContext context;
|
||||
|
||||
private readonly List<int> averageOrangePullTracker = [];
|
||||
@@ -46,54 +62,52 @@ internal sealed class TypedWishSummaryBuilder
|
||||
/// <param name="isUp">是否为Up物品</param>
|
||||
public void Track(GachaItem item, ISummaryItemSource source, bool isUp)
|
||||
{
|
||||
if (!context.TypeEvaluator(item.GachaType))
|
||||
if (context.TypeEvaluator(item.GachaType))
|
||||
{
|
||||
return;
|
||||
}
|
||||
++lastOrangePullTracker;
|
||||
++lastPurplePullTracker;
|
||||
++lastUpOrangePullTracker;
|
||||
|
||||
++lastOrangePullTracker;
|
||||
++lastPurplePullTracker;
|
||||
++lastUpOrangePullTracker;
|
||||
// track total pulls
|
||||
++totalCountTracker;
|
||||
TrackFromToTime(item.Time);
|
||||
|
||||
// track total pulls
|
||||
++totalCountTracker;
|
||||
TrackFromToTime(item.Time);
|
||||
|
||||
switch (source.Quality)
|
||||
{
|
||||
case QualityType.QUALITY_ORANGE:
|
||||
{
|
||||
TrackMinMaxOrangePull(lastOrangePullTracker);
|
||||
averageOrangePullTracker.Add(lastOrangePullTracker);
|
||||
|
||||
if (isUp)
|
||||
switch (source.Quality)
|
||||
{
|
||||
case QualityType.QUALITY_ORANGE:
|
||||
{
|
||||
averageUpOrangePullTracker.Add(lastUpOrangePullTracker);
|
||||
lastUpOrangePullTracker = 0;
|
||||
TrackMinMaxOrangePull(lastOrangePullTracker);
|
||||
averageOrangePullTracker.Add(lastOrangePullTracker);
|
||||
|
||||
if (isUp)
|
||||
{
|
||||
averageUpOrangePullTracker.Add(lastUpOrangePullTracker);
|
||||
lastUpOrangePullTracker = 0;
|
||||
}
|
||||
|
||||
summaryItems.Add(source.ToSummaryItem(lastOrangePullTracker, item.Time, isUp));
|
||||
|
||||
lastOrangePullTracker = 0;
|
||||
++totalOrangePullTracker;
|
||||
break;
|
||||
}
|
||||
|
||||
summaryItems.Add(source.ToSummaryItem(lastOrangePullTracker, item.Time, isUp));
|
||||
case QualityType.QUALITY_PURPLE:
|
||||
{
|
||||
lastPurplePullTracker = 0;
|
||||
++totalPurplePullTracker;
|
||||
break;
|
||||
}
|
||||
|
||||
lastOrangePullTracker = 0;
|
||||
++totalOrangePullTracker;
|
||||
case QualityType.QUALITY_BLUE:
|
||||
{
|
||||
++totalBluePullTracker;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
case QualityType.QUALITY_PURPLE:
|
||||
{
|
||||
lastPurplePullTracker = 0;
|
||||
++totalPurplePullTracker;
|
||||
break;
|
||||
}
|
||||
|
||||
case QualityType.QUALITY_BLUE:
|
||||
{
|
||||
++totalBluePullTracker;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,13 +14,12 @@ internal readonly struct TypedWishSummaryBuilderContext
|
||||
public readonly string Name;
|
||||
public readonly int GuaranteeOrangeThreshold;
|
||||
public readonly int GuaranteePurpleThreshold;
|
||||
public readonly Func<GachaType, bool> TypeEvaluator;
|
||||
public readonly Func<GachaConfigType, bool> TypeEvaluator;
|
||||
public readonly GachaDistributionType DistributionType;
|
||||
|
||||
private static readonly Func<GachaType, bool> IsStandardWish = type => type is GachaType.Standard;
|
||||
private static readonly Func<GachaType, bool> IsAvatarEventWish = type => type is GachaType.ActivityAvatar or GachaType.SpecialActivityAvatar;
|
||||
private static readonly Func<GachaType, bool> IsWeaponEventWish = type => type is GachaType.ActivityWeapon;
|
||||
private static readonly Func<GachaType, bool> IsChronicledWish = type => type is GachaType.ActivityCity;
|
||||
private static readonly Func<GachaConfigType, bool> IsStandardWish = type => type is GachaConfigType.StandardWish;
|
||||
private static readonly Func<GachaConfigType, bool> IsAvatarEventWish = type => type is GachaConfigType.AvatarEventWish or GachaConfigType.AvatarEventWish2;
|
||||
private static readonly Func<GachaConfigType, bool> IsWeaponEventWish = type => type is GachaConfigType.WeaponEventWish;
|
||||
|
||||
public TypedWishSummaryBuilderContext(
|
||||
ITaskContext taskContext,
|
||||
@@ -28,7 +27,7 @@ internal readonly struct TypedWishSummaryBuilderContext
|
||||
string name,
|
||||
int guaranteeOrangeThreshold,
|
||||
int guaranteePurpleThreshold,
|
||||
Func<GachaType, bool> typeEvaluator,
|
||||
Func<GachaConfigType, bool> typeEvaluator,
|
||||
GachaDistributionType distributionType)
|
||||
{
|
||||
TaskContext = taskContext;
|
||||
@@ -55,11 +54,6 @@ internal readonly struct TypedWishSummaryBuilderContext
|
||||
return new(taskContext, gachaLogClient, SH.ServiceGachaLogFactoryWeaponWishName, 80, 10, IsWeaponEventWish, GachaDistributionType.WeaponEvent);
|
||||
}
|
||||
|
||||
public static TypedWishSummaryBuilderContext ChronicledWish(ITaskContext taskContext, HomaGachaLogClient gachaLogClient)
|
||||
{
|
||||
return new(taskContext, gachaLogClient, SH.ServiceGachaLogFactoryChronicledWishName, 90, 10, IsChronicledWish, GachaDistributionType.Chronicled);
|
||||
}
|
||||
|
||||
public ValueTask<HutaoResponse<GachaDistribution>> GetGachaDistributionAsync()
|
||||
{
|
||||
return GachaLogClient.GetGachaDistributionAsync(DistributionType);
|
||||
|
||||
@@ -15,14 +15,12 @@ internal static class GachaArchiveOperation
|
||||
{
|
||||
archive = archives.SingleOrDefault(a => a.Uid == uid);
|
||||
|
||||
if (archive is not null)
|
||||
if (archive is null)
|
||||
{
|
||||
return;
|
||||
GachaArchive created = GachaArchive.From(uid);
|
||||
gachaLogDbService.AddGachaArchive(created);
|
||||
taskContext.InvokeOnMainThread(() => archives.Add(created));
|
||||
archive = created;
|
||||
}
|
||||
|
||||
GachaArchive created = GachaArchive.From(uid);
|
||||
gachaLogDbService.AddGachaArchive(created);
|
||||
taskContext.InvokeOnMainThread(() => archives.Add(created));
|
||||
archive = created;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Model.Entity;
|
||||
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
||||
|
||||
namespace Snap.Hutao.Service.GachaLog;
|
||||
|
||||
/// <summary>
|
||||
/// 祈愿物品保存上下文
|
||||
/// </summary>
|
||||
internal readonly struct GachaItemSaveContext
|
||||
{
|
||||
/// <summary>
|
||||
/// 待添加物品
|
||||
/// </summary>
|
||||
public readonly List<GachaItem> ItemsToAdd;
|
||||
|
||||
/// <summary>
|
||||
/// 是否懒惰
|
||||
/// </summary>
|
||||
public readonly bool IsLazy;
|
||||
|
||||
public readonly GachaConfigType QueryType;
|
||||
|
||||
/// <summary>
|
||||
/// 结尾 Id
|
||||
/// </summary>
|
||||
public readonly long EndId;
|
||||
|
||||
/// <summary>
|
||||
/// 数据集
|
||||
/// </summary>
|
||||
public readonly IGachaLogDbService GachaLogDbService;
|
||||
|
||||
public GachaItemSaveContext(List<GachaItem> itemsToAdd, bool isLazy, GachaConfigType queryType, long endId, IGachaLogDbService gachaLogDbService)
|
||||
{
|
||||
ItemsToAdd = itemsToAdd;
|
||||
IsLazy = isLazy;
|
||||
QueryType = queryType;
|
||||
EndId = endId;
|
||||
GachaLogDbService = gachaLogDbService;
|
||||
}
|
||||
|
||||
public void SaveItems(GachaArchive archive)
|
||||
{
|
||||
if (ItemsToAdd.Count > 0)
|
||||
{
|
||||
// 全量刷新
|
||||
if (!IsLazy)
|
||||
{
|
||||
GachaLogDbService.RemoveNewerGachaItemRangeByArchiveIdQueryTypeAndEndId(archive.InnerId, QueryType, EndId);
|
||||
}
|
||||
|
||||
GachaLogDbService.AddGachaItemRange(ItemsToAdd);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,12 +14,11 @@ internal static class GachaLog
|
||||
/// <summary>
|
||||
/// 查询类型
|
||||
/// </summary>
|
||||
public static readonly FrozenSet<GachaType> QueryTypes = FrozenSet.ToFrozenSet(
|
||||
public static readonly FrozenSet<GachaConfigType> QueryTypes = FrozenSet.ToFrozenSet(
|
||||
[
|
||||
GachaType.NewBie,
|
||||
GachaType.Standard,
|
||||
GachaType.ActivityAvatar,
|
||||
GachaType.ActivityWeapon,
|
||||
GachaType.ActivityCity,
|
||||
GachaConfigType.NoviceWish,
|
||||
GachaConfigType.StandardWish,
|
||||
GachaConfigType.AvatarEventWish,
|
||||
GachaConfigType.WeaponEventWish,
|
||||
]);
|
||||
}
|
||||
@@ -73,7 +73,7 @@ internal sealed partial class GachaLogDbService : IGachaLogDbService
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask<long> GetNewestGachaItemIdByArchiveIdAndQueryTypeAsync(Guid archiveId, GachaType queryType, CancellationToken token)
|
||||
public async ValueTask<long> GetNewestGachaItemIdByArchiveIdAndQueryTypeAsync(Guid archiveId, GachaConfigType queryType, CancellationToken token)
|
||||
{
|
||||
GachaItem? item = null;
|
||||
|
||||
@@ -103,7 +103,7 @@ internal sealed partial class GachaLogDbService : IGachaLogDbService
|
||||
return item?.Id ?? 0L;
|
||||
}
|
||||
|
||||
public long GetNewestGachaItemIdByArchiveIdAndQueryType(Guid archiveId, GachaType queryType)
|
||||
public long GetNewestGachaItemIdByArchiveIdAndQueryType(Guid archiveId, GachaConfigType queryType)
|
||||
{
|
||||
GachaItem? item = null;
|
||||
|
||||
@@ -132,7 +132,7 @@ internal sealed partial class GachaLogDbService : IGachaLogDbService
|
||||
return item?.Id ?? 0L;
|
||||
}
|
||||
|
||||
public async ValueTask<long> GetNewestGachaItemIdByArchiveIdAndQueryTypeAsync(Guid archiveId, GachaType queryType)
|
||||
public async ValueTask<long> GetNewestGachaItemIdByArchiveIdAndQueryTypeAsync(Guid archiveId, GachaConfigType queryType)
|
||||
{
|
||||
GachaItem? item = null;
|
||||
|
||||
@@ -205,7 +205,7 @@ internal sealed partial class GachaLogDbService : IGachaLogDbService
|
||||
return item?.Id ?? long.MaxValue;
|
||||
}
|
||||
|
||||
public long GetOldestGachaItemIdByArchiveIdAndQueryType(Guid archiveId, GachaType queryType)
|
||||
public long GetOldestGachaItemIdByArchiveIdAndQueryType(Guid archiveId, GachaConfigType queryType)
|
||||
{
|
||||
GachaItem? item = null;
|
||||
|
||||
@@ -226,7 +226,7 @@ internal sealed partial class GachaLogDbService : IGachaLogDbService
|
||||
return item?.Id ?? long.MaxValue;
|
||||
}
|
||||
|
||||
public async ValueTask<long> GetOldestGachaItemIdByArchiveIdAndQueryTypeAsync(Guid archiveId, GachaType queryType, CancellationToken token)
|
||||
public async ValueTask<long> GetOldestGachaItemIdByArchiveIdAndQueryTypeAsync(Guid archiveId, GachaConfigType queryType, CancellationToken token)
|
||||
{
|
||||
GachaItem? item = null;
|
||||
|
||||
@@ -266,7 +266,7 @@ internal sealed partial class GachaLogDbService : IGachaLogDbService
|
||||
}
|
||||
}
|
||||
|
||||
public List<Web.Hutao.GachaLog.GachaItem> GetHutaoGachaItemList(Guid archiveId, GachaType queryType, long endId)
|
||||
public List<Web.Hutao.GachaLog.GachaItem> GetHutaoGachaItemList(Guid archiveId, GachaConfigType queryType, long endId)
|
||||
{
|
||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||
{
|
||||
@@ -291,7 +291,7 @@ internal sealed partial class GachaLogDbService : IGachaLogDbService
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask<List<Web.Hutao.GachaLog.GachaItem>> GetHutaoGachaItemListAsync(Guid archiveId, GachaType queryType, long endId)
|
||||
public async ValueTask<List<Web.Hutao.GachaLog.GachaItem>> GetHutaoGachaItemListAsync(Guid archiveId, GachaConfigType queryType, long endId)
|
||||
{
|
||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||
{
|
||||
@@ -368,7 +368,7 @@ internal sealed partial class GachaLogDbService : IGachaLogDbService
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveNewerGachaItemRangeByArchiveIdQueryTypeAndEndId(Guid archiveId, GachaType queryType, long endId)
|
||||
public void RemoveNewerGachaItemRangeByArchiveIdQueryTypeAndEndId(Guid archiveId, GachaConfigType queryType, long endId)
|
||||
{
|
||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||
{
|
||||
@@ -381,7 +381,7 @@ internal sealed partial class GachaLogDbService : IGachaLogDbService
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask RemoveNewerGachaItemRangeByArchiveIdQueryTypeAndEndIdAsync(Guid archiveId, GachaType queryType, long endId)
|
||||
public async ValueTask RemoveNewerGachaItemRangeByArchiveIdQueryTypeAndEndIdAsync(Guid archiveId, GachaConfigType queryType, long endId)
|
||||
{
|
||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||
{
|
||||
|
||||
@@ -46,14 +46,14 @@ internal struct GachaLogFetchContext
|
||||
/// <summary>
|
||||
/// 当前类型
|
||||
/// </summary>
|
||||
public GachaType CurrentType;
|
||||
public GachaConfigType CurrentType;
|
||||
|
||||
private readonly GachaLogServiceMetadataContext serviceContext;
|
||||
private readonly IGachaLogDbService gachaLogDbService;
|
||||
private readonly ITaskContext taskContext;
|
||||
private readonly bool isLazy;
|
||||
|
||||
public GachaLogFetchContext(IGachaLogDbService gachaLogDbService, ITaskContext taskContext, GachaLogServiceMetadataContext serviceContext, bool isLazy)
|
||||
public GachaLogFetchContext(IGachaLogDbService gachaLogDbService, ITaskContext taskContext, in GachaLogServiceMetadataContext serviceContext, bool isLazy)
|
||||
{
|
||||
this.gachaLogDbService = gachaLogDbService;
|
||||
this.taskContext = taskContext;
|
||||
@@ -66,7 +66,7 @@ internal struct GachaLogFetchContext
|
||||
/// </summary>
|
||||
/// <param name="configType">卡池类型</param>
|
||||
/// <param name="query">查询</param>
|
||||
public void ResetForProcessingType(GachaType configType, in GachaLogQuery query)
|
||||
public void ResetForProcessingType(GachaConfigType configType, in GachaLogQuery query)
|
||||
{
|
||||
DbEndId = null;
|
||||
CurrentType = configType;
|
||||
@@ -140,18 +140,8 @@ internal struct GachaLogFetchContext
|
||||
// While no item is fetched, archive can be null.
|
||||
if (TargetArchive is not null)
|
||||
{
|
||||
if (ItemsToAdd.Count <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 全量刷新
|
||||
if (!isLazy)
|
||||
{
|
||||
gachaLogDbService.RemoveNewerGachaItemRangeByArchiveIdQueryTypeAndEndId(TargetArchive.InnerId, QueryOptions.Type, QueryOptions.EndId);
|
||||
}
|
||||
|
||||
gachaLogDbService.AddGachaItemRange(ItemsToAdd);
|
||||
GachaItemSaveContext saveContext = new(ItemsToAdd, isLazy, QueryOptions.Type, QueryOptions.EndId, gachaLogDbService);
|
||||
saveContext.SaveItems(TargetArchive);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,17 +6,33 @@ using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
||||
|
||||
namespace Snap.Hutao.Service.GachaLog;
|
||||
|
||||
/// <summary>
|
||||
/// 祈愿记录获取状态
|
||||
/// </summary>
|
||||
internal sealed class GachaLogFetchStatus
|
||||
{
|
||||
public GachaLogFetchStatus(GachaType configType)
|
||||
/// <summary>
|
||||
/// 构造一个新的祈愿记录获取状态
|
||||
/// </summary>
|
||||
/// <param name="configType">卡池类型</param>
|
||||
public GachaLogFetchStatus(GachaConfigType configType)
|
||||
{
|
||||
ConfigType = configType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证密钥是否过期
|
||||
/// </summary>
|
||||
public bool AuthKeyTimeout { get; set; }
|
||||
|
||||
public GachaType ConfigType { get; set; }
|
||||
/// <summary>
|
||||
/// 卡池类型
|
||||
/// </summary>
|
||||
public GachaConfigType ConfigType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 当前获取的物品
|
||||
/// </summary>
|
||||
public List<Item> Items { get; set; } = new(20);
|
||||
|
||||
public string Header
|
||||
|
||||
@@ -2,9 +2,12 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Model.Entity;
|
||||
using Snap.Hutao.Model.Metadata;
|
||||
using Snap.Hutao.Model.Metadata.Avatar;
|
||||
using Snap.Hutao.Model.Metadata.Weapon;
|
||||
using Snap.Hutao.Model.Primitive;
|
||||
using Snap.Hutao.Service.GachaLog.Factory;
|
||||
using Snap.Hutao.Service.Metadata;
|
||||
using Snap.Hutao.Service.Metadata.ContextAbstraction;
|
||||
using Snap.Hutao.ViewModel.GachaLog;
|
||||
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
||||
using Snap.Hutao.Web.Hutao.GachaLog;
|
||||
@@ -37,7 +40,7 @@ internal sealed partial class GachaLogHutaoCloudService : IGachaLogHutaoCloudSer
|
||||
if (await GetEndIdsFromCloudAsync(uid, token).ConfigureAwait(false) is { } endIds)
|
||||
{
|
||||
List<Web.Hutao.GachaLog.GachaItem> items = [];
|
||||
foreach ((GachaType type, long endId) in endIds)
|
||||
foreach ((GachaConfigType type, long endId) in endIds)
|
||||
{
|
||||
List<Web.Hutao.GachaLog.GachaItem> part = await gachaLogDbService
|
||||
.GetHutaoGachaItemListAsync(gachaArchive.InnerId, type, endId)
|
||||
@@ -52,16 +55,14 @@ internal sealed partial class GachaLogHutaoCloudService : IGachaLogHutaoCloudSer
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async ValueTask<ValueResult<bool, Guid>> RetrieveGachaArchiveIdAsync(string uid, CancellationToken token = default)
|
||||
public async ValueTask<ValueResult<bool, Guid>> RetrieveGachaItemsAsync(string uid, CancellationToken token = default)
|
||||
{
|
||||
GachaArchive? archive = await gachaLogDbService
|
||||
.GetGachaArchiveByUidAsync(uid, token)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
EndIds endIds = await CreateEndIdsAsync(archive, token).ConfigureAwait(false);
|
||||
Response<List<Web.Hutao.GachaLog.GachaItem>> resp = await homaGachaLogClient
|
||||
.RetrieveGachaItemsAsync(uid, endIds, token)
|
||||
.ConfigureAwait(false);
|
||||
Response<List<Web.Hutao.GachaLog.GachaItem>> resp = await homaGachaLogClient.RetrieveGachaItemsAsync(uid, endIds, token).ConfigureAwait(false);
|
||||
|
||||
if (!resp.IsOk())
|
||||
{
|
||||
@@ -74,8 +75,7 @@ internal sealed partial class GachaLogHutaoCloudService : IGachaLogHutaoCloudSer
|
||||
await gachaLogDbService.AddGachaArchiveAsync(archive).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
Guid archiveId = archive.InnerId;
|
||||
List<Model.Entity.GachaItem> gachaItems = resp.Data.SelectList(i => Model.Entity.GachaItem.From(archiveId, i));
|
||||
List<Model.Entity.GachaItem> gachaItems = resp.Data.SelectList(i => Model.Entity.GachaItem.From(archive.InnerId, i));
|
||||
await gachaLogDbService.AddGachaItemsAsync(gachaItems).ConfigureAwait(false);
|
||||
return new(true, archive.InnerId);
|
||||
}
|
||||
@@ -94,9 +94,10 @@ internal sealed partial class GachaLogHutaoCloudService : IGachaLogHutaoCloudSer
|
||||
{
|
||||
if (await metadataService.InitializeAsync().ConfigureAwait(false))
|
||||
{
|
||||
HutaoStatisticsFactoryMetadataContext context = await metadataService
|
||||
.GetContextAsync<HutaoStatisticsFactoryMetadataContext>(token)
|
||||
.ConfigureAwait(false);
|
||||
Dictionary<AvatarId, Avatar> idAvatarMap = await metadataService.GetIdToAvatarMapAsync(token).ConfigureAwait(false);
|
||||
Dictionary<WeaponId, Weapon> idWeaponMap = await metadataService.GetIdToWeaponMapAsync(token).ConfigureAwait(false);
|
||||
List<GachaEvent> gachaEvents = await metadataService.GetGachaEventListAsync(token).ConfigureAwait(false);
|
||||
HutaoStatisticsFactoryMetadataContext context = new(idAvatarMap, idWeaponMap, gachaEvents);
|
||||
|
||||
GachaEventStatistics raw = response.Data;
|
||||
try
|
||||
@@ -125,7 +126,7 @@ internal sealed partial class GachaLogHutaoCloudService : IGachaLogHutaoCloudSer
|
||||
private async ValueTask<EndIds> CreateEndIdsAsync(GachaArchive? archive, CancellationToken token)
|
||||
{
|
||||
EndIds endIds = new();
|
||||
foreach (GachaType type in GachaLog.QueryTypes)
|
||||
foreach (GachaConfigType type in GachaLog.QueryTypes)
|
||||
{
|
||||
if (archive is not null)
|
||||
{
|
||||
|
||||
@@ -5,10 +5,10 @@ using Snap.Hutao.Core.Database;
|
||||
using Snap.Hutao.Core.Diagnostics;
|
||||
using Snap.Hutao.Model.Entity;
|
||||
using Snap.Hutao.Model.InterChange.GachaLog;
|
||||
using Snap.Hutao.Model.Primitive;
|
||||
using Snap.Hutao.Service.GachaLog.Factory;
|
||||
using Snap.Hutao.Service.GachaLog.QueryProvider;
|
||||
using Snap.Hutao.Service.Metadata;
|
||||
using Snap.Hutao.Service.Metadata.ContextAbstraction;
|
||||
using Snap.Hutao.ViewModel.GachaLog;
|
||||
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
||||
using Snap.Hutao.Web.Response;
|
||||
@@ -55,14 +55,20 @@ internal sealed partial class GachaLogService : IGachaLogService
|
||||
/// <inheritdoc/>
|
||||
public async ValueTask<bool> InitializeAsync(CancellationToken token = default)
|
||||
{
|
||||
if (context is { IsInitialized: true })
|
||||
if (context.IsInitialized)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (await metadataService.InitializeAsync().ConfigureAwait(false))
|
||||
{
|
||||
context = await metadataService.GetContextAsync<GachaLogServiceMetadataContext>(token).ConfigureAwait(false);
|
||||
Dictionary<AvatarId, Model.Metadata.Avatar.Avatar> idAvatarMap = await metadataService.GetIdToAvatarMapAsync(token).ConfigureAwait(false);
|
||||
Dictionary<WeaponId, Model.Metadata.Weapon.Weapon> idWeaponMap = await metadataService.GetIdToWeaponMapAsync(token).ConfigureAwait(false);
|
||||
|
||||
Dictionary<string, Model.Metadata.Avatar.Avatar> nameAvatarMap = await metadataService.GetNameToAvatarMapAsync(token).ConfigureAwait(false);
|
||||
Dictionary<string, Model.Metadata.Weapon.Weapon> nameWeaponMap = await metadataService.GetNameToWeaponMapAsync(token).ConfigureAwait(false);
|
||||
context = new(idAvatarMap, idWeaponMap, nameAvatarMap, nameWeaponMap);
|
||||
|
||||
ArchiveCollection = gachaLogDbService.GetGachaArchiveCollection();
|
||||
return true;
|
||||
}
|
||||
@@ -176,7 +182,7 @@ internal sealed partial class GachaLogService : IGachaLogService
|
||||
ArgumentNullException.ThrowIfNull(ArchiveCollection);
|
||||
GachaLogFetchContext fetchContext = new(gachaLogDbService, taskContext, context, isLazy);
|
||||
|
||||
foreach (GachaType configType in GachaLog.QueryTypes)
|
||||
foreach (GachaConfigType configType in GachaLog.QueryTypes)
|
||||
{
|
||||
fetchContext.ResetForProcessingType(configType, query);
|
||||
|
||||
|
||||
@@ -2,12 +2,10 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Model;
|
||||
using Snap.Hutao.Model.Metadata;
|
||||
using Snap.Hutao.Model.Metadata.Abstraction;
|
||||
using Snap.Hutao.Model.Metadata.Avatar;
|
||||
using Snap.Hutao.Model.Metadata.Weapon;
|
||||
using Snap.Hutao.Model.Primitive;
|
||||
using Snap.Hutao.Service.Metadata.ContextAbstraction;
|
||||
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
||||
|
||||
namespace Snap.Hutao.Service.GachaLog;
|
||||
@@ -15,28 +13,65 @@ namespace Snap.Hutao.Service.GachaLog;
|
||||
/// <summary>
|
||||
/// 祈愿记录服务上下文
|
||||
/// </summary>
|
||||
internal sealed class GachaLogServiceMetadataContext : IMetadataContext,
|
||||
IMetadataSupportInitialization,
|
||||
IMetadataListGachaEventSource,
|
||||
IMetadataDictionaryIdAvatarSource,
|
||||
IMetadataDictionaryIdWeaponSource,
|
||||
IMetadataDictionaryNameAvatarSource,
|
||||
IMetadataDictionaryNameWeaponSource
|
||||
internal readonly struct GachaLogServiceMetadataContext
|
||||
{
|
||||
public Dictionary<string, Item> ItemCache { get; set; } = [];
|
||||
/// <summary>
|
||||
/// 物品缓存
|
||||
/// </summary>
|
||||
public readonly Dictionary<string, Item> ItemCache = [];
|
||||
|
||||
public List<GachaEvent> GachaEvents { get; set; } = default!;
|
||||
/// <summary>
|
||||
/// Id 角色 映射
|
||||
/// </summary>
|
||||
public readonly Dictionary<AvatarId, Avatar> IdAvatarMap;
|
||||
|
||||
public Dictionary<AvatarId, Avatar> IdAvatarMap { get; set; } = default!;
|
||||
/// <summary>
|
||||
/// Id 武器 映射
|
||||
/// </summary>
|
||||
public readonly Dictionary<WeaponId, Weapon> IdWeaponMap;
|
||||
|
||||
public Dictionary<WeaponId, Weapon> IdWeaponMap { get; set; } = default!;
|
||||
/// <summary>
|
||||
/// 名称 角色 映射
|
||||
/// </summary>
|
||||
public readonly Dictionary<string, Avatar> NameAvatarMap;
|
||||
|
||||
public Dictionary<string, Avatar> NameAvatarMap { get; set; } = default!;
|
||||
/// <summary>
|
||||
/// 名称 武器 映射
|
||||
/// </summary>
|
||||
public readonly Dictionary<string, Weapon> NameWeaponMap;
|
||||
|
||||
public Dictionary<string, Weapon> NameWeaponMap { get; set; } = default!;
|
||||
/// <summary>
|
||||
/// 是否初始化完成
|
||||
/// </summary>
|
||||
public readonly bool IsInitialized;
|
||||
|
||||
public bool IsInitialized { get; set; }
|
||||
/// <summary>
|
||||
/// 构造一个新的祈愿记录服务上下文
|
||||
/// </summary>
|
||||
/// <param name="idAvatarMap">Id 角色 映射</param>
|
||||
/// <param name="idWeaponMap">Id 武器 映射</param>
|
||||
/// <param name="nameAvatarMap">名称 角色 映射</param>
|
||||
/// <param name="nameWeaponMap">名称 武器 映射</param>
|
||||
public GachaLogServiceMetadataContext(
|
||||
Dictionary<AvatarId, Avatar> idAvatarMap,
|
||||
Dictionary<WeaponId, Weapon> idWeaponMap,
|
||||
Dictionary<string, Avatar> nameAvatarMap,
|
||||
Dictionary<string, Weapon> nameWeaponMap)
|
||||
{
|
||||
IdAvatarMap = idAvatarMap;
|
||||
IdWeaponMap = idWeaponMap;
|
||||
NameAvatarMap = nameAvatarMap;
|
||||
NameWeaponMap = nameWeaponMap;
|
||||
|
||||
IsInitialized = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 按名称获取物品
|
||||
/// </summary>
|
||||
/// <param name="name">名称</param>
|
||||
/// <param name="type">类型</param>
|
||||
/// <returns>物品</returns>
|
||||
public Item GetItemByNameAndType(string name, string type)
|
||||
{
|
||||
if (!ItemCache.TryGetValue(name, out Item? result))
|
||||
@@ -58,6 +93,11 @@ internal sealed class GachaLogServiceMetadataContext : IMetadataContext,
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 按物品 Id 获取名称星级
|
||||
/// </summary>
|
||||
/// <param name="id">Id</param>
|
||||
/// <returns>名称星级</returns>
|
||||
public INameQuality GetNameQualityByItemId(uint id)
|
||||
{
|
||||
uint place = id.StringLength();
|
||||
@@ -69,6 +109,12 @@ internal sealed class GachaLogServiceMetadataContext : IMetadataContext,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取物品 Id
|
||||
/// O(1)
|
||||
/// </summary>
|
||||
/// <param name="item">祈愿物品</param>
|
||||
/// <returns>物品 Id</returns>
|
||||
public uint GetItemId(GachaLogItem item)
|
||||
{
|
||||
if (item.ItemType == SH.ModelInterchangeUIGFItemTypeAvatar)
|
||||
|
||||
@@ -19,7 +19,7 @@ internal interface IGachaLogDbService
|
||||
|
||||
ValueTask RemoveGachaArchiveByIdAsync(Guid archiveId);
|
||||
|
||||
void RemoveNewerGachaItemRangeByArchiveIdQueryTypeAndEndId(Guid archiveId, GachaType queryType, long endId);
|
||||
void RemoveNewerGachaItemRangeByArchiveIdQueryTypeAndEndId(Guid archiveId, GachaConfigType queryType, long endId);
|
||||
|
||||
ValueTask<GachaArchive?> GetGachaArchiveByIdAsync(Guid archiveId, CancellationToken token);
|
||||
|
||||
@@ -31,25 +31,25 @@ internal interface IGachaLogDbService
|
||||
|
||||
ValueTask<List<GachaItem>> GetGachaItemListByArchiveIdAsync(Guid archiveId);
|
||||
|
||||
List<Web.Hutao.GachaLog.GachaItem> GetHutaoGachaItemList(Guid archiveId, GachaType queryType, long endId);
|
||||
List<Web.Hutao.GachaLog.GachaItem> GetHutaoGachaItemList(Guid archiveId, GachaConfigType queryType, long endId);
|
||||
|
||||
long GetNewestGachaItemIdByArchiveIdAndQueryType(Guid archiveId, GachaType queryType);
|
||||
long GetNewestGachaItemIdByArchiveIdAndQueryType(Guid archiveId, GachaConfigType queryType);
|
||||
|
||||
ValueTask<long> GetNewestGachaItemIdByArchiveIdAndQueryTypeAsync(Guid archiveId, GachaType queryType, CancellationToken token);
|
||||
ValueTask<long> GetNewestGachaItemIdByArchiveIdAndQueryTypeAsync(Guid archiveId, GachaConfigType queryType, CancellationToken token);
|
||||
|
||||
long GetOldestGachaItemIdByArchiveId(Guid archiveId);
|
||||
|
||||
long GetOldestGachaItemIdByArchiveIdAndQueryType(Guid archiveId, GachaType queryType);
|
||||
long GetOldestGachaItemIdByArchiveIdAndQueryType(Guid archiveId, GachaConfigType queryType);
|
||||
|
||||
ValueTask<long> GetOldestGachaItemIdByArchiveIdAndQueryTypeAsync(Guid archiveId, GachaType queryType, CancellationToken token);
|
||||
ValueTask<long> GetOldestGachaItemIdByArchiveIdAndQueryTypeAsync(Guid archiveId, GachaConfigType queryType, CancellationToken token);
|
||||
|
||||
ValueTask<long> GetNewestGachaItemIdByArchiveIdAndQueryTypeAsync(Guid archiveId, GachaType queryType);
|
||||
ValueTask<long> GetNewestGachaItemIdByArchiveIdAndQueryTypeAsync(Guid archiveId, GachaConfigType queryType);
|
||||
|
||||
ValueTask<long> GetOldestGachaItemIdByArchiveIdAsync(Guid archiveId);
|
||||
|
||||
ValueTask<List<Web.Hutao.GachaLog.GachaItem>> GetHutaoGachaItemListAsync(Guid archiveId, GachaType queryType, long endId);
|
||||
ValueTask<List<Web.Hutao.GachaLog.GachaItem>> GetHutaoGachaItemListAsync(Guid archiveId, GachaConfigType queryType, long endId);
|
||||
|
||||
ValueTask AddGachaItemRangeAsync(List<GachaItem> items);
|
||||
|
||||
ValueTask RemoveNewerGachaItemRangeByArchiveIdQueryTypeAndEndIdAsync(Guid archiveId, GachaType queryType, long endId);
|
||||
ValueTask RemoveNewerGachaItemRangeByArchiveIdQueryTypeAndEndIdAsync(Guid archiveId, GachaConfigType queryType, long endId);
|
||||
}
|
||||
@@ -36,7 +36,7 @@ internal interface IGachaLogHutaoCloudService
|
||||
/// <param name="uid">uid</param>
|
||||
/// <param name="token">取消令牌</param>
|
||||
/// <returns>是否获取成功</returns>
|
||||
ValueTask<ValueResult<bool, Guid>> RetrieveGachaArchiveIdAsync(string uid, CancellationToken token = default);
|
||||
ValueTask<ValueResult<bool, Guid>> RetrieveGachaItemsAsync(string uid, CancellationToken token = default);
|
||||
|
||||
/// <summary>
|
||||
/// 异步上传祈愿记录
|
||||
|
||||
@@ -105,8 +105,8 @@ internal sealed partial class GachaLogQueryWebCacheProvider : IGachaLogQueryProv
|
||||
{
|
||||
ReadOnlySpan<byte> span = stream.ToArray();
|
||||
ReadOnlySpan<byte> match = isOversea
|
||||
? "https://gs.hoyoverse.com/genshin/event/e20190909gacha-v3/index.html"u8
|
||||
: "https://webstatic.mihoyo.com/hk4e/event/e20190909gacha-v3/index.html"u8;
|
||||
? "https://gs.hoyoverse.com/genshin/event/e20190909gacha-v2/index.html"u8
|
||||
: "https://webstatic.mihoyo.com/hk4e/event/e20190909gacha-v2/index.html"u8;
|
||||
|
||||
int index = span.LastIndexOf(match);
|
||||
if (index >= 0)
|
||||
|
||||
@@ -62,7 +62,7 @@ internal sealed partial class UIGFImportService : IUIGFImportService
|
||||
Guid archiveId = archive.InnerId;
|
||||
|
||||
List<GachaItem> fullItems = [];
|
||||
foreach (GachaType queryType in GachaLog.QueryTypes)
|
||||
foreach (GachaConfigType queryType in GachaLog.QueryTypes)
|
||||
{
|
||||
long trimId = gachaLogDbService.GetOldestGachaItemIdByArchiveIdAndQueryType(archiveId, queryType);
|
||||
logger.LogInformation("Last Id to trim with: [{Id}]", trimId);
|
||||
|
||||
@@ -109,7 +109,7 @@ internal sealed class LaunchOptions : DbStoreOptions
|
||||
|
||||
public bool IsEnabled
|
||||
{
|
||||
get => GetOption(ref isEnabled, SettingEntry.LaunchIsLaunchOptionsEnabled, false);
|
||||
get => GetOption(ref isEnabled, SettingEntry.LaunchIsLaunchOptionsEnabled, true);
|
||||
set => SetOption(ref isEnabled, SettingEntry.LaunchIsLaunchOptionsEnabled, value);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,9 +17,9 @@ internal sealed class LaunchStatus
|
||||
|
||||
public string Description { get; set; }
|
||||
|
||||
public static LaunchStatus FromUnlockState(GameFpsUnlockerState unlockerState)
|
||||
public static LaunchStatus FromUnlockStatus(UnlockerStatus unlockerStatus)
|
||||
{
|
||||
if (unlockerState.FindModuleResult == FindModuleResult.Ok)
|
||||
if (unlockerStatus.FindModuleState == FindModuleResult.Ok)
|
||||
{
|
||||
return new(LaunchPhase.UnlockFpsSucceed, SH.ServiceGameLaunchPhaseUnlockFpsSucceed);
|
||||
}
|
||||
|
||||
@@ -23,16 +23,8 @@ internal sealed class LaunchExecutionBetterGenshinImpactAutomationHandlder : ILa
|
||||
Uri betterGenshinImpactUri = "bettergi://start".ToUri();
|
||||
if (await Launcher.QueryUriSupportAsync(betterGenshinImpactUri, LaunchQuerySupportType.Uri) is LaunchQuerySupportStatus.Available)
|
||||
{
|
||||
try
|
||||
{
|
||||
context.Logger.LogInformation("Waiting game window to be ready");
|
||||
context.Process.WaitForInputIdle();
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
context.Logger.LogInformation("Failed to wait Input idle waiting");
|
||||
return;
|
||||
}
|
||||
context.Logger.LogInformation("Waiting game window to be ready");
|
||||
context.Process.WaitForInputIdle();
|
||||
|
||||
context.Logger.LogInformation("Launching BetterGI");
|
||||
await Launcher.LaunchUriAsync(betterGenshinImpactUri);
|
||||
|
||||
@@ -1,27 +1,18 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Snap.Hutao.Service.Game.Launching.Handler;
|
||||
|
||||
internal sealed class LaunchExecutionEnsureGameNotRunningHandler : ILaunchExecutionDelegateHandler
|
||||
{
|
||||
public static bool IsGameRunning([NotNullWhen(true)] out Process? runningProcess)
|
||||
public static bool IsGameRunning([NotNullWhen(true)] out System.Diagnostics.Process? runningProcess)
|
||||
{
|
||||
int currentSessionId = Process.GetCurrentProcess().SessionId;
|
||||
|
||||
// GetProcesses once and manually loop is O(n)
|
||||
foreach (ref readonly Process process in Process.GetProcesses().AsSpan())
|
||||
foreach (ref readonly System.Diagnostics.Process process in System.Diagnostics.Process.GetProcesses().AsSpan())
|
||||
{
|
||||
if (string.Equals(process.ProcessName, GameConstants.YuanShenProcessName, StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(process.ProcessName, GameConstants.GenshinImpactProcessName, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
if (process.SessionId != currentSessionId)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
runningProcess = process;
|
||||
return true;
|
||||
}
|
||||
@@ -33,7 +24,7 @@ internal sealed class LaunchExecutionEnsureGameNotRunningHandler : ILaunchExecut
|
||||
|
||||
public async ValueTask OnExecutionAsync(LaunchExecutionContext context, LaunchExecutionDelegate next)
|
||||
{
|
||||
if (IsGameRunning(out Process? process))
|
||||
if (IsGameRunning(out System.Diagnostics.Process? process))
|
||||
{
|
||||
context.Logger.LogInformation("Game process detected, id: {Id}", process.Id);
|
||||
|
||||
|
||||
@@ -18,13 +18,12 @@ internal sealed class LaunchExecutionUnlockFpsHandler : ILaunchExecutionDelegate
|
||||
context.Progress.Report(new(LaunchPhase.UnlockingFps, SH.ServiceGameLaunchPhaseUnlockingFps));
|
||||
|
||||
IProgressFactory progressFactory = context.ServiceProvider.GetRequiredService<IProgressFactory>();
|
||||
IProgress<GameFpsUnlockerState> progress = progressFactory.CreateForMainThread<GameFpsUnlockerState>(status => context.Progress.Report(LaunchStatus.FromUnlockState(status)));
|
||||
GameFpsUnlocker unlocker = new(context.ServiceProvider, context.Process, new(100, 20000, 3000), progress);
|
||||
IProgress<UnlockerStatus> progress = progressFactory.CreateForMainThread<UnlockerStatus>(status => context.Progress.Report(LaunchStatus.FromUnlockStatus(status)));
|
||||
GameFpsUnlocker unlocker = context.ServiceProvider.CreateInstance<GameFpsUnlocker>(context.Process);
|
||||
|
||||
try
|
||||
{
|
||||
await unlocker.UnlockAsync(context.CancellationToken).ConfigureAwait(false);
|
||||
unlocker.PostUnlockAsync(context.CancellationToken).SafeForget();
|
||||
await unlocker.UnlockAsync(new(100, 20000, 3000), progress, context.CancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
|
||||
@@ -24,25 +24,25 @@ internal sealed class LaunchExecutionInvoker
|
||||
handlers.Enqueue(new LaunchExecutionGameProcessInitializationHandler());
|
||||
handlers.Enqueue(new LaunchExecutionSetDiscordActivityHandler());
|
||||
handlers.Enqueue(new LaunchExecutionGameProcessStartHandler());
|
||||
handlers.Enqueue(new LaunchExecutionUnlockFpsHandler());
|
||||
handlers.Enqueue(new LaunchExecutionStarwardPlayTimeStatisticsHandler());
|
||||
handlers.Enqueue(new LaunchExecutionBetterGenshinImpactAutomationHandlder());
|
||||
handlers.Enqueue(new LaunchExecutionUnlockFpsHandler());
|
||||
handlers.Enqueue(new LaunchExecutionGameProcessExitHandler());
|
||||
}
|
||||
|
||||
public async ValueTask<LaunchExecutionResult> InvokeAsync(LaunchExecutionContext context)
|
||||
{
|
||||
await RecursiveInvokeHandlerAsync(context).ConfigureAwait(false);
|
||||
await InvokeHandlerAsync(context).ConfigureAwait(false);
|
||||
return context.Result;
|
||||
}
|
||||
|
||||
private async ValueTask<LaunchExecutionContext> RecursiveInvokeHandlerAsync(LaunchExecutionContext context)
|
||||
private async ValueTask<LaunchExecutionContext> InvokeHandlerAsync(LaunchExecutionContext context)
|
||||
{
|
||||
if (handlers.TryDequeue(out ILaunchExecutionDelegateHandler? handler))
|
||||
{
|
||||
string typeName = TypeNameHelper.GetTypeDisplayName(handler, false);
|
||||
context.Logger.LogInformation("Handler [{Handler}] begin execution", typeName);
|
||||
await handler.OnExecutionAsync(context, () => RecursiveInvokeHandlerAsync(context)).ConfigureAwait(false);
|
||||
await handler.OnExecutionAsync(context, () => InvokeHandlerAsync(context)).ConfigureAwait(false);
|
||||
context.Logger.LogInformation("Handler [{Handler}] end execution", typeName);
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user