mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
423188c16a | ||
|
|
5fb935635b | ||
|
|
761049ec17 | ||
|
|
3f8c8874f3 | ||
|
|
b8f354bbc7 | ||
|
|
d45c40d4d7 | ||
|
|
6b309c4886 | ||
|
|
26e6d2008e | ||
|
|
fb77bd2f6b | ||
|
|
50459923f9 | ||
|
|
a97bab8a1c | ||
|
|
bbc8324f5d | ||
|
|
2c0b32ab8b | ||
|
|
0073636676 | ||
|
|
7457d72e1b |
1
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
1
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
@@ -68,6 +68,7 @@ body:
|
|||||||
- 游戏启动器
|
- 游戏启动器
|
||||||
- 实时便笺
|
- 实时便笺
|
||||||
- 养成计算器
|
- 养成计算器
|
||||||
|
- 用户面板
|
||||||
- 文件缓存
|
- 文件缓存
|
||||||
- 祈愿记录
|
- 祈愿记录
|
||||||
- 玩家查询
|
- 玩家查询
|
||||||
|
|||||||
14
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
14
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
@@ -8,12 +8,20 @@ body:
|
|||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
value: |
|
value: |
|
||||||
请按下方的要求填写完整的问题表单,以便我们更快的定位问题。
|
请按下方的要求填写完整的问题表单。
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: back
|
||||||
|
attributes:
|
||||||
|
label: 背景与动机
|
||||||
|
description: 添加此功能的理由
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: req
|
id: req
|
||||||
attributes:
|
attributes:
|
||||||
label: 你想要实现或优化的功能?
|
label: 想要实现或优化的功能
|
||||||
description: 详细的描述一下你想要的功能
|
description: 详细的描述一下你想要的功能,描述的越具体,采纳的可能性越高
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
25
README.md
25
README.md
@@ -1,35 +1,26 @@
|
|||||||
# Snap.Hutao
|
# [Snap.Hutao](https://hut.ao)
|
||||||
> 唷,找本堂主有何贵干呀?
|
> 唷,找本堂主有何贵干呀?
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## 项目首页(文档)
|
# 特别感谢
|
||||||
|
|
||||||
[](https://github.com/DGP-Studio/Snap.Hutao.Docs/actions/workflows/deploy-docs.yml)
|
### 原神组织与个人
|
||||||
|
|
||||||
[HUT.AO](https://hut.ao)
|
* [HolographicHat](https://github.com/HolographicHat)
|
||||||
|
* [UIGF organization](https://uigf.org)
|
||||||
|
|
||||||
## 安装
|
### 特定的原神项目
|
||||||
|
|
||||||
* 前往 [下载页面](https://go.hut.ao/down) 下载最新版本的 `胡桃` 安装包
|
|
||||||
* (曾启用的可以跳过此步骤)在系统设置中打开 **开发者选项** 界面,勾选 `开发人员模式` 和 `允许 PowerShell 脚本`
|
|
||||||
* 完全解压后,右键使用 powershell 运行 `install.ps1` 文件
|
|
||||||
* 安装完成后可以关闭 `允许 PowerShell 脚本`
|
|
||||||
|
|
||||||
## 特别感谢
|
|
||||||
|
|
||||||
### 原神项目
|
|
||||||
|
|
||||||
* [biuuu/genshin-wish-export](https://github.com/biuuu/genshin-wish-export)
|
* [biuuu/genshin-wish-export](https://github.com/biuuu/genshin-wish-export)
|
||||||
* [HolographicHat/YaeAchievement](https://github.com/HolographicHat/YaeAchievement)
|
|
||||||
* [HolographicHat/MiHoYoWebBridge](https://github.com/HolographicHat/MiHoYoWebBridge)
|
|
||||||
* [xunkong/xunkong](https://github.com/xunkong/xunkong)
|
* [xunkong/xunkong](https://github.com/xunkong/xunkong)
|
||||||
* [YuehaiTeam/cocogoat](https://github.com/YuehaiTeam/cocogoat)
|
* [YuehaiTeam/cocogoat](https://github.com/YuehaiTeam/cocogoat)
|
||||||
|
|
||||||
### 技术栈
|
### 使用的技术栈
|
||||||
|
|
||||||
* [CommunityToolkit/dotnet](https://github.com/CommunityToolkit/dotnet)
|
* [CommunityToolkit/dotnet](https://github.com/CommunityToolkit/dotnet)
|
||||||
* [CommunityToolkit/WindowsCommunityToolkit](https://github.com/CommunityToolkit/WindowsCommunityToolkit)
|
* [CommunityToolkit/WindowsCommunityToolkit](https://github.com/CommunityToolkit/WindowsCommunityToolkit)
|
||||||
|
* [dahall/taskscheduler](https://github.com/dahall/taskscheduler)
|
||||||
* [dotnet/efcore](https://github.com/dotnet/efcore)
|
* [dotnet/efcore](https://github.com/dotnet/efcore)
|
||||||
* [dotnet/runtime](https://github.com/dotnet/runtime)
|
* [dotnet/runtime](https://github.com/dotnet/runtime)
|
||||||
* [DotNetAnalyzers/StyleCopAnalyzers](https://github.com/DotNetAnalyzers/StyleCopAnalyzers)
|
* [DotNetAnalyzers/StyleCopAnalyzers](https://github.com/DotNetAnalyzers/StyleCopAnalyzers)
|
||||||
|
|||||||
156
azure-pipelines.yml
Normal file
156
azure-pipelines.yml
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
# CI process script for Snap.Hutao
|
||||||
|
# Usage:
|
||||||
|
# 1. Append the script in Pipelines
|
||||||
|
# 2. Upload the pfx and cer certificates to Pipelines Library secrets
|
||||||
|
# 3. Permit the pfx usage
|
||||||
|
# 4. Add a `pw` variable in the script variables, which is pfx password
|
||||||
|
# 5. Connect the GitHub in project settings
|
||||||
|
# 6. Run
|
||||||
|
|
||||||
|
trigger:
|
||||||
|
branches:
|
||||||
|
include:
|
||||||
|
- main
|
||||||
|
paths:
|
||||||
|
exclude:
|
||||||
|
- README.md
|
||||||
|
- azure-pipelines.yml
|
||||||
|
- .github/ISSUE_TEMPLATE/*.yml
|
||||||
|
- .github/workflows/*.yml
|
||||||
|
|
||||||
|
|
||||||
|
pool:
|
||||||
|
vmImage: 'windows-2022'
|
||||||
|
|
||||||
|
variables:
|
||||||
|
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
|
||||||
|
solution: '$(Build.SourcesDirectory)/src/Snap.Hutao/Snap.Hutao.sln'
|
||||||
|
project: $(Build.SourcesDirectory)/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj'
|
||||||
|
buildPlatform: 'x64'
|
||||||
|
buildConfiguration: 'Release'
|
||||||
|
build_date: $[ format('{0:yyyy}.{0:MM}.{0:dd}', pipeline.startTime) ]
|
||||||
|
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- task: GetRevision@1
|
||||||
|
displayName: get Pipelines revision number
|
||||||
|
inputs:
|
||||||
|
VariableName: 'rev_number'
|
||||||
|
|
||||||
|
- task: UseDotNet@2
|
||||||
|
displayName: Install dotNet
|
||||||
|
inputs:
|
||||||
|
packageType: 'sdk'
|
||||||
|
version: '7.x'
|
||||||
|
includePreviewVersions: true
|
||||||
|
|
||||||
|
- task: NuGetToolInstaller@1
|
||||||
|
name: 'NuGetToolInstaller'
|
||||||
|
displayName: 'NuGet Installer'
|
||||||
|
|
||||||
|
- task: NuGetCommand@2
|
||||||
|
displayName: NuGet restore
|
||||||
|
inputs:
|
||||||
|
command: 'restore'
|
||||||
|
restoreSolution: '$(solution)'
|
||||||
|
feedsToUse: 'select'
|
||||||
|
|
||||||
|
- task: MsixPackaging@1
|
||||||
|
displayName: Build binary package
|
||||||
|
inputs:
|
||||||
|
outputPath: '$(Build.ArtifactStagingDirectory)/'
|
||||||
|
solution: '$(solution)'
|
||||||
|
clean: false
|
||||||
|
generateBundle: false
|
||||||
|
buildConfiguration: 'Release'
|
||||||
|
buildPlatform: 'x64'
|
||||||
|
updateAppVersion: false
|
||||||
|
appPackageDistributionMode: 'SideloadOnly'
|
||||||
|
msbuildLocationMethod: 'location'
|
||||||
|
msbuildLocation: 'C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Msbuild\Current\Bin\MSBuild.exe'
|
||||||
|
|
||||||
|
- task: MagicChunks@2
|
||||||
|
inputs:
|
||||||
|
sourcePath: '$(Build.SourcesDirectory)\src\Snap.Hutao\Snap.Hutao\bin\x64\Release\net7.0-windows10.0.18362.0\win10-x64\AppxManifest.xml'
|
||||||
|
fileType: 'Xml'
|
||||||
|
targetPathType: 'source'
|
||||||
|
transformationType: 'json'
|
||||||
|
transformations: |
|
||||||
|
{
|
||||||
|
"Package/Identity/@Name": "7f0db578-026f-4e0b-a75b-d5d06bb0a74c",
|
||||||
|
"Package/Identity/@Publisher": "CN=DGP Studio CI",
|
||||||
|
"Package/Identity/@Version": "$(build_date).$(rev_number)",
|
||||||
|
"Package/Properties/DisplayName": "胡桃 Alpha",
|
||||||
|
"Package/Properties/PublisherDisplayName":"DGP Studio CI"
|
||||||
|
}
|
||||||
|
|
||||||
|
- task: CmdLine@2
|
||||||
|
displayName: Create resources folder
|
||||||
|
inputs:
|
||||||
|
script: |
|
||||||
|
mkdir Assets
|
||||||
|
|
||||||
|
mkdir Resource
|
||||||
|
workingDirectory: '$(Build.SourcesDirectory)\src\Snap.Hutao\Snap.Hutao\bin\x64\Release\net7.0-windows10.0.18362.0\win10-x64'
|
||||||
|
|
||||||
|
|
||||||
|
- task: CopyFiles@2
|
||||||
|
displayName: Copy Assets Folder
|
||||||
|
inputs:
|
||||||
|
SourceFolder: '$(Build.SourcesDirectory)\src\Snap.Hutao\Snap.Hutao\Assets'
|
||||||
|
Contents: '**'
|
||||||
|
TargetFolder: '$(Build.SourcesDirectory)\src\Snap.Hutao\Snap.Hutao\bin\x64\Release\net7.0-windows10.0.18362.0\win10-x64\Assets'
|
||||||
|
|
||||||
|
- task: CopyFiles@2
|
||||||
|
displayName: Copy Resource Folder
|
||||||
|
inputs:
|
||||||
|
SourceFolder: '$(Build.SourcesDirectory)\src\Snap.Hutao\Snap.Hutao\Resource'
|
||||||
|
Contents: '**'
|
||||||
|
TargetFolder: '$(Build.SourcesDirectory)\src\Snap.Hutao\Snap.Hutao\bin\x64\Release\net7.0-windows10.0.18362.0\win10-x64\Resource'
|
||||||
|
|
||||||
|
- task: CmdLine@2
|
||||||
|
displayName: Build MSIX
|
||||||
|
inputs:
|
||||||
|
script: '"C:\Program Files (x86)\Windows Kits\10\bin\10.0.22000.0\x64\makeappx.exe" pack /d $(Build.SourcesDirectory)\src\Snap.Hutao\Snap.Hutao\bin\x64\Release\net7.0-windows10.0.18362.0\win10-x64 /p $(Build.ArtifactStagingDirectory)/Snap.Hutao.Alpha-$(build_date).$(rev_number).msix'
|
||||||
|
|
||||||
|
- task: MsixSigning@1
|
||||||
|
displayName: Sign MSIX package
|
||||||
|
inputs:
|
||||||
|
package: '$(Build.ArtifactStagingDirectory)/Snap.Hutao.Alpha-$(build_date).$(rev_number).msix'
|
||||||
|
certificate: 'DGP_Studio_CI.pfx'
|
||||||
|
passwordVariable: 'pw'
|
||||||
|
|
||||||
|
- task: PublishPipelineArtifact@1
|
||||||
|
displayName: 'Upload Output'
|
||||||
|
inputs:
|
||||||
|
targetPath: '$(Build.ArtifactStagingDirectory)/'
|
||||||
|
artifact: 'Output'
|
||||||
|
publishLocation: 'pipeline'
|
||||||
|
|
||||||
|
- task: DownloadSecureFile@1
|
||||||
|
name: cerFile
|
||||||
|
displayName: Download Root CA
|
||||||
|
inputs:
|
||||||
|
secureFile: 'Snap.Hutao.CI.cer'
|
||||||
|
|
||||||
|
- task: GitHubRelease@1
|
||||||
|
inputs:
|
||||||
|
gitHubConnection: 'github.com_Masterain'
|
||||||
|
repositoryName: 'DGP-Studio/Snap.Hutao'
|
||||||
|
action: 'create'
|
||||||
|
target: '$(Build.SourceVersion)'
|
||||||
|
tagSource: 'userSpecifiedTag'
|
||||||
|
tag: '$(build_date).$(rev_number)'
|
||||||
|
title: '$(build_date).$(rev_number)'
|
||||||
|
releaseNotesSource: 'inline'
|
||||||
|
releaseNotesInline: |
|
||||||
|
## 提示 (Hint)
|
||||||
|
该发布版本由 CI 程序自动打包生成,属于 `Alpha` 测试版,仅用于开发调试和内部测试用途。使用该版本可能存在意料之外的风险,请仅在有明确用途的情况下使用该版本。
|
||||||
|
|
||||||
|
This release is a Alpha Testing version generated by CI program automatically in a purpose of debugging and interal testing. Using this release may have unexpected risk, please only use it when you know what you are doing.
|
||||||
|
assets: |
|
||||||
|
$(Build.ArtifactStagingDirectory)/*
|
||||||
|
$(cerFile.secureFilePath)
|
||||||
|
isPreRelease: true
|
||||||
|
changeLogCompareToRelease: 'lastFullRelease'
|
||||||
|
changeLogType: 'commitBased'
|
||||||
@@ -6,8 +6,9 @@
|
|||||||
<Platforms>x64</Platforms>
|
<Platforms>x64</Platforms>
|
||||||
<RuntimeIdentifiers>win10-x64</RuntimeIdentifiers>
|
<RuntimeIdentifiers>win10-x64</RuntimeIdentifiers>
|
||||||
<UseWinUI>true</UseWinUI>
|
<UseWinUI>true</UseWinUI>
|
||||||
<LangVersion>latest</LangVersion>
|
<LangVersion>latest</LangVersion>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
|
<EnablePreviewMsixTooling>true</EnablePreviewMsixTooling>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -43,8 +43,10 @@
|
|||||||
<CornerRadius x:Key="CompatCornerRadiusBottom">0,0,6,6</CornerRadius>
|
<CornerRadius x:Key="CompatCornerRadiusBottom">0,0,6,6</CornerRadius>
|
||||||
<CornerRadius x:Key="CompatCornerRadiusSmall">2</CornerRadius>
|
<CornerRadius x:Key="CompatCornerRadiusSmall">2</CornerRadius>
|
||||||
<!-- Converters -->
|
<!-- Converters -->
|
||||||
|
<cwuc:BoolNegationConverter x:Key="BoolNegationConverter"/>
|
||||||
<cwuc:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
|
<cwuc:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
|
||||||
<shmmc:AchievementIconConverter x:Key="AchievementIconConverter"/>
|
<shmmc:AchievementIconConverter x:Key="AchievementIconConverter"/>
|
||||||
|
<shmmc:AvatarCardConverter x:Key="AvatarCardConverter"/>
|
||||||
<shmmc:AvatarIconConverter x:Key="AvatarIconConverter"/>
|
<shmmc:AvatarIconConverter x:Key="AvatarIconConverter"/>
|
||||||
<shmmc:AvatarNameCardPicConverter x:Key="AvatarNameCardPicConverter"/>
|
<shmmc:AvatarNameCardPicConverter x:Key="AvatarNameCardPicConverter"/>
|
||||||
<shmmc:AvatarSideIconConverter x:Key="AvatarSideIconConverter"/>
|
<shmmc:AvatarSideIconConverter x:Key="AvatarSideIconConverter"/>
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ public partial class App : Application
|
|||||||
if (firstInstance.IsCurrent)
|
if (firstInstance.IsCurrent)
|
||||||
{
|
{
|
||||||
// manually invoke
|
// manually invoke
|
||||||
Activation.Activate(firstInstance, activatedEventArgs);
|
Activation.NonRedirectToActivate(firstInstance, activatedEventArgs);
|
||||||
firstInstance.Activated += Activation.Activate;
|
firstInstance.Activated += Activation.Activate;
|
||||||
ToastNotificationManagerCompat.OnActivated += Activation.NotificationActivate;
|
ToastNotificationManagerCompat.OnActivated += Activation.NotificationActivate;
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using Windows.ApplicationModel;
|
||||||
|
|
||||||
namespace Snap.Hutao.Context.FileSystem.Location;
|
namespace Snap.Hutao.Context.FileSystem.Location;
|
||||||
|
|
||||||
@@ -19,7 +20,10 @@ internal class HutaoLocation : IFileSystemLocation
|
|||||||
if (string.IsNullOrEmpty(path))
|
if (string.IsNullOrEmpty(path))
|
||||||
{
|
{
|
||||||
string myDocument = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
|
string myDocument = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
|
||||||
path = Path.GetFullPath(Path.Combine(myDocument, "Hutao"));
|
|
||||||
|
// 将测试版与正式版的文件目录分离
|
||||||
|
string folderName = Package.Current.PublisherDisplayName == "DGP Studio CI" ? "HutaoAlpha" : "Hutao";
|
||||||
|
path = Path.GetFullPath(Path.Combine(myDocument, folderName));
|
||||||
}
|
}
|
||||||
|
|
||||||
return path;
|
return path;
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
using CommunityToolkit.Mvvm.Messaging;
|
using CommunityToolkit.Mvvm.Messaging;
|
||||||
using CommunityToolkit.WinUI.UI.Behaviors;
|
using CommunityToolkit.WinUI.UI.Behaviors;
|
||||||
using Microsoft.UI.Xaml;
|
|
||||||
using Microsoft.UI.Xaml.Controls;
|
using Microsoft.UI.Xaml.Controls;
|
||||||
|
|
||||||
namespace Snap.Hutao.Control.Behavior;
|
namespace Snap.Hutao.Control.Behavior;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using Windows.UI;
|
using Windows.UI;
|
||||||
|
|
||||||
namespace Snap.Hutao.Control.Image;
|
namespace Snap.Hutao.Control.Media;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// BGRA8 结构
|
/// BGRA8 结构
|
||||||
175
src/Snap.Hutao/Snap.Hutao/Control/Media/Rgba8.cs
Normal file
175
src/Snap.Hutao/Snap.Hutao/Control/Media/Rgba8.cs
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
// Some part of this file came from:
|
||||||
|
// https://github.com/xunkong/desktop/tree/main/src/Desktop/Desktop/Pages/CharacterInfoPage.xaml.cs
|
||||||
|
|
||||||
|
using CommunityToolkit.WinUI;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using Windows.UI;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Control.Media;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// RGBA 颜色
|
||||||
|
/// </summary>
|
||||||
|
[StructLayout(LayoutKind.Explicit)]
|
||||||
|
public struct Rgba8
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// R
|
||||||
|
/// </summary>
|
||||||
|
[FieldOffset(3)]
|
||||||
|
public byte R;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// G
|
||||||
|
/// </summary>
|
||||||
|
[FieldOffset(2)]
|
||||||
|
public byte G;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// B
|
||||||
|
/// </summary>
|
||||||
|
[FieldOffset(1)]
|
||||||
|
public byte B;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A
|
||||||
|
/// </summary>
|
||||||
|
[FieldOffset(0)]
|
||||||
|
public byte A;
|
||||||
|
|
||||||
|
[FieldOffset(0)]
|
||||||
|
private readonly uint data;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 构造一个新的 RGBA8 颜色
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hex">色值字符串</param>
|
||||||
|
public Rgba8(ReadOnlySpan<char> hex)
|
||||||
|
{
|
||||||
|
Must.Argument(hex.Length == 8, "色值长度不为8");
|
||||||
|
R = 0;
|
||||||
|
G = 0;
|
||||||
|
B = 0;
|
||||||
|
A = 0;
|
||||||
|
data = Convert.ToUInt32(hex.ToString(), 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Rgba8(byte r, byte g, byte b, byte a)
|
||||||
|
{
|
||||||
|
data = 0;
|
||||||
|
R = r;
|
||||||
|
G = g;
|
||||||
|
B = b;
|
||||||
|
A = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static implicit operator Color(Rgba8 hexColor)
|
||||||
|
{
|
||||||
|
return Color.FromArgb(hexColor.A, hexColor.R, hexColor.G, hexColor.B);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 从 HSL 颜色转换
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hsl">HSL 颜色</param>
|
||||||
|
/// <returns>RGBA8颜色</returns>
|
||||||
|
public static Rgba8 FromHsl(HslColor hsl)
|
||||||
|
{
|
||||||
|
double chroma = (1 - Math.Abs((2 * hsl.L) - 1)) * hsl.S;
|
||||||
|
double h1 = hsl.H / 60;
|
||||||
|
double x = chroma * (1 - Math.Abs((h1 % 2) - 1));
|
||||||
|
double m = hsl.L - (0.5 * chroma);
|
||||||
|
double r1, g1, b1;
|
||||||
|
|
||||||
|
if (h1 < 1)
|
||||||
|
{
|
||||||
|
r1 = chroma;
|
||||||
|
g1 = x;
|
||||||
|
b1 = 0;
|
||||||
|
}
|
||||||
|
else if (h1 < 2)
|
||||||
|
{
|
||||||
|
r1 = x;
|
||||||
|
g1 = chroma;
|
||||||
|
b1 = 0;
|
||||||
|
}
|
||||||
|
else if (h1 < 3)
|
||||||
|
{
|
||||||
|
r1 = 0;
|
||||||
|
g1 = chroma;
|
||||||
|
b1 = x;
|
||||||
|
}
|
||||||
|
else if (h1 < 4)
|
||||||
|
{
|
||||||
|
r1 = 0;
|
||||||
|
g1 = x;
|
||||||
|
b1 = chroma;
|
||||||
|
}
|
||||||
|
else if (h1 < 5)
|
||||||
|
{
|
||||||
|
r1 = x;
|
||||||
|
g1 = 0;
|
||||||
|
b1 = chroma;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
r1 = chroma;
|
||||||
|
g1 = 0;
|
||||||
|
b1 = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte r = (byte)(255 * (r1 + m));
|
||||||
|
byte g = (byte)(255 * (g1 + m));
|
||||||
|
byte b = (byte)(255 * (b1 + m));
|
||||||
|
byte a = (byte)(255 * hsl.A);
|
||||||
|
|
||||||
|
return new(r, g, b, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 转换到 HSL 颜色
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>HSL 颜色</returns>
|
||||||
|
public HslColor ToHsl()
|
||||||
|
{
|
||||||
|
const double toDouble = 1.0 / 255;
|
||||||
|
double r = toDouble * R;
|
||||||
|
double g = toDouble * G;
|
||||||
|
double b = toDouble * B;
|
||||||
|
double max = Math.Max(Math.Max(r, g), b);
|
||||||
|
double min = Math.Min(Math.Min(r, g), b);
|
||||||
|
double chroma = max - min;
|
||||||
|
double h1;
|
||||||
|
|
||||||
|
if (chroma == 0)
|
||||||
|
{
|
||||||
|
h1 = 0;
|
||||||
|
}
|
||||||
|
else if (max == r)
|
||||||
|
{
|
||||||
|
// The % operator doesn't do proper modulo on negative
|
||||||
|
// numbers, so we'll add 6 before using it
|
||||||
|
h1 = (((g - b) / chroma) + 6) % 6;
|
||||||
|
}
|
||||||
|
else if (max == g)
|
||||||
|
{
|
||||||
|
h1 = 2 + ((b - r) / chroma);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
h1 = 4 + ((r - g) / chroma);
|
||||||
|
}
|
||||||
|
|
||||||
|
double lightness = 0.5 * (max + min);
|
||||||
|
double saturation = chroma == 0 ? 0 : chroma / (1 - Math.Abs((2 * lightness) - 1));
|
||||||
|
|
||||||
|
HslColor ret;
|
||||||
|
ret.H = 60 * h1;
|
||||||
|
ret.S = saturation;
|
||||||
|
ret.L = lightness;
|
||||||
|
ret.A = toDouble * A;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Windows.Foundation;
|
||||||
|
using Windows.Graphics.Imaging;
|
||||||
|
using Windows.Win32;
|
||||||
|
using Windows.Win32.System.WinRT;
|
||||||
|
using WinRT;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Control.Media;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 软件位图拓展
|
||||||
|
/// </summary>
|
||||||
|
public static class SoftwareBitmapExtension
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 混合模式 正常
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="softwareBitmap">软件位图</param>
|
||||||
|
/// <param name="tint">底色</param>
|
||||||
|
public static unsafe void NormalBlend(this SoftwareBitmap softwareBitmap, Bgra8 tint)
|
||||||
|
{
|
||||||
|
using (BitmapBuffer buffer = softwareBitmap.LockBuffer(BitmapBufferAccessMode.ReadWrite))
|
||||||
|
{
|
||||||
|
using (IMemoryBufferReference reference = buffer.CreateReference())
|
||||||
|
{
|
||||||
|
reference.As<IMemoryBufferByteAccess>().GetBuffer(out byte* data, out uint length);
|
||||||
|
|
||||||
|
for (int i = 0; i < length; i += 4)
|
||||||
|
{
|
||||||
|
Bgra8* pixel = (Bgra8*)(data + i);
|
||||||
|
byte baseAlpha = pixel->A;
|
||||||
|
pixel->B = (byte)(((pixel->B * baseAlpha) + (tint.B * (0xFF - baseAlpha))) / 0xFF);
|
||||||
|
pixel->G = (byte)(((pixel->G * baseAlpha) + (tint.G * (0xFF - baseAlpha))) / 0xFF);
|
||||||
|
pixel->R = (byte)(((pixel->R * baseAlpha) + (tint.R * (0xFF - baseAlpha))) / 0xFF);
|
||||||
|
pixel->A = 0xFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,8 +8,8 @@ using Microsoft.UI.Xaml;
|
|||||||
using Microsoft.UI.Xaml.Controls;
|
using Microsoft.UI.Xaml.Controls;
|
||||||
using Microsoft.UI.Xaml.Documents;
|
using Microsoft.UI.Xaml.Documents;
|
||||||
using Microsoft.UI.Xaml.Media;
|
using Microsoft.UI.Xaml.Media;
|
||||||
|
using Snap.Hutao.Control.Media;
|
||||||
using Snap.Hutao.Core;
|
using Snap.Hutao.Core;
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using Windows.UI;
|
using Windows.UI;
|
||||||
|
|
||||||
namespace Snap.Hutao.Control.Text;
|
namespace Snap.Hutao.Control.Text;
|
||||||
@@ -19,8 +19,7 @@ namespace Snap.Hutao.Control.Text;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class DescriptionTextBlock : ContentControl
|
public class DescriptionTextBlock : ContentControl
|
||||||
{
|
{
|
||||||
private static readonly DependencyProperty DescriptionProperty =
|
private static readonly DependencyProperty DescriptionProperty = Property<DescriptionTextBlock>.Depend(nameof(Description), string.Empty, OnDescriptionChanged);
|
||||||
Property<DescriptionTextBlock>.Depend(nameof(Description), string.Empty, OnDescriptionChanged);
|
|
||||||
|
|
||||||
private static readonly int ColorTagFullLength = "<color=#FFFFFFFF></color>".Length;
|
private static readonly int ColorTagFullLength = "<color=#FFFFFFFF></color>".Length;
|
||||||
private static readonly int ColorTagLeftLength = "<color=#FFFFFFFF>".Length;
|
private static readonly int ColorTagLeftLength = "<color=#FFFFFFFF>".Length;
|
||||||
@@ -79,7 +78,7 @@ public class DescriptionTextBlock : ContentControl
|
|||||||
else if (description[i] == '<' && description[i + 1] == 'c')
|
else if (description[i] == '<' && description[i + 1] == 'c')
|
||||||
{
|
{
|
||||||
AppendText(text, description[last..i]);
|
AppendText(text, description[last..i]);
|
||||||
HexColor color = new(description.Slice(i + 8, 8));
|
Rgba8 color = new(description.Slice(i + 8, 8));
|
||||||
int length = description[(i + ColorTagLeftLength)..].IndexOf('<');
|
int length = description[(i + ColorTagLeftLength)..].IndexOf('<');
|
||||||
AppendColorText(text, description.Slice(i + ColorTagLeftLength, length), color);
|
AppendColorText(text, description.Slice(i + ColorTagLeftLength, length), color);
|
||||||
|
|
||||||
@@ -115,7 +114,7 @@ public class DescriptionTextBlock : ContentControl
|
|||||||
text.Inlines.Add(new Run { Text = slice.ToString() });
|
text.Inlines.Add(new Run { Text = slice.ToString() });
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void AppendColorText(TextBlock text, ReadOnlySpan<char> slice, HexColor color)
|
private static void AppendColorText(TextBlock text, ReadOnlySpan<char> slice, Rgba8 color)
|
||||||
{
|
{
|
||||||
Color targetColor;
|
Color targetColor;
|
||||||
if (ThemeHelper.IsDarkMode(text.ActualTheme))
|
if (ThemeHelper.IsDarkMode(text.ActualTheme))
|
||||||
@@ -126,7 +125,7 @@ public class DescriptionTextBlock : ContentControl
|
|||||||
{
|
{
|
||||||
HslColor hsl = color.ToHsl();
|
HslColor hsl = color.ToHsl();
|
||||||
hsl.L *= 0.3;
|
hsl.L *= 0.3;
|
||||||
targetColor = HexColor.FromHsl(hsl);
|
targetColor = Rgba8.FromHsl(hsl);
|
||||||
}
|
}
|
||||||
|
|
||||||
text.Inlines.Add(new Run
|
text.Inlines.Add(new Run
|
||||||
@@ -154,138 +153,4 @@ public class DescriptionTextBlock : ContentControl
|
|||||||
{
|
{
|
||||||
ApplyDescription((TextBlock)Content, Description);
|
ApplyDescription((TextBlock)Content, Description);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
[StructLayout(LayoutKind.Explicit)]
|
|
||||||
private struct HexColor
|
|
||||||
{
|
|
||||||
[FieldOffset(3)]
|
|
||||||
public byte R;
|
|
||||||
[FieldOffset(2)]
|
|
||||||
public byte G;
|
|
||||||
[FieldOffset(1)]
|
|
||||||
public byte B;
|
|
||||||
[FieldOffset(0)]
|
|
||||||
public byte A;
|
|
||||||
|
|
||||||
[FieldOffset(0)]
|
|
||||||
private readonly uint data;
|
|
||||||
|
|
||||||
public HexColor(ReadOnlySpan<char> hex)
|
|
||||||
{
|
|
||||||
Must.Argument(hex.Length == 8, "色值长度不为8");
|
|
||||||
R = 0;
|
|
||||||
G = 0;
|
|
||||||
B = 0;
|
|
||||||
A = 0;
|
|
||||||
data = Convert.ToUInt32(hex.ToString(), 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
private HexColor(byte r, byte g, byte b, byte a)
|
|
||||||
{
|
|
||||||
data = 0;
|
|
||||||
R = r;
|
|
||||||
G = g;
|
|
||||||
B = b;
|
|
||||||
A = a;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static implicit operator Color(HexColor hexColor)
|
|
||||||
{
|
|
||||||
return Color.FromArgb(hexColor.A, hexColor.R, hexColor.G, hexColor.B);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static HexColor FromHsl(HslColor hsl)
|
|
||||||
{
|
|
||||||
double chroma = (1 - Math.Abs((2 * hsl.L) - 1)) * hsl.S;
|
|
||||||
double h1 = hsl.H / 60;
|
|
||||||
double x = chroma * (1 - Math.Abs((h1 % 2) - 1));
|
|
||||||
double m = hsl.L - (0.5 * chroma);
|
|
||||||
double r1, g1, b1;
|
|
||||||
|
|
||||||
if (h1 < 1)
|
|
||||||
{
|
|
||||||
r1 = chroma;
|
|
||||||
g1 = x;
|
|
||||||
b1 = 0;
|
|
||||||
}
|
|
||||||
else if (h1 < 2)
|
|
||||||
{
|
|
||||||
r1 = x;
|
|
||||||
g1 = chroma;
|
|
||||||
b1 = 0;
|
|
||||||
}
|
|
||||||
else if (h1 < 3)
|
|
||||||
{
|
|
||||||
r1 = 0;
|
|
||||||
g1 = chroma;
|
|
||||||
b1 = x;
|
|
||||||
}
|
|
||||||
else if (h1 < 4)
|
|
||||||
{
|
|
||||||
r1 = 0;
|
|
||||||
g1 = x;
|
|
||||||
b1 = chroma;
|
|
||||||
}
|
|
||||||
else if (h1 < 5)
|
|
||||||
{
|
|
||||||
r1 = x;
|
|
||||||
g1 = 0;
|
|
||||||
b1 = chroma;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
r1 = chroma;
|
|
||||||
g1 = 0;
|
|
||||||
b1 = x;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte r = (byte)(255 * (r1 + m));
|
|
||||||
byte g = (byte)(255 * (g1 + m));
|
|
||||||
byte b = (byte)(255 * (b1 + m));
|
|
||||||
byte a = (byte)(255 * hsl.A);
|
|
||||||
|
|
||||||
return new(r, g, b, a);
|
|
||||||
}
|
|
||||||
|
|
||||||
public HslColor ToHsl()
|
|
||||||
{
|
|
||||||
const double toDouble = 1.0 / 255;
|
|
||||||
double r = toDouble * R;
|
|
||||||
double g = toDouble * G;
|
|
||||||
double b = toDouble * B;
|
|
||||||
double max = Math.Max(Math.Max(r, g), b);
|
|
||||||
double min = Math.Min(Math.Min(r, g), b);
|
|
||||||
double chroma = max - min;
|
|
||||||
double h1;
|
|
||||||
|
|
||||||
if (chroma == 0)
|
|
||||||
{
|
|
||||||
h1 = 0;
|
|
||||||
}
|
|
||||||
else if (max == r)
|
|
||||||
{
|
|
||||||
// The % operator doesn't do proper modulo on negative
|
|
||||||
// numbers, so we'll add 6 before using it
|
|
||||||
h1 = (((g - b) / chroma) + 6) % 6;
|
|
||||||
}
|
|
||||||
else if (max == g)
|
|
||||||
{
|
|
||||||
h1 = 2 + ((b - r) / chroma);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
h1 = 4 + ((r - g) / chroma);
|
|
||||||
}
|
|
||||||
|
|
||||||
double lightness = 0.5 * (max + min);
|
|
||||||
double saturation = chroma == 0 ? 0 : chroma / (1 - Math.Abs((2 * lightness) - 1));
|
|
||||||
|
|
||||||
HslColor ret;
|
|
||||||
ret.H = 60 * h1;
|
|
||||||
ret.S = saturation;
|
|
||||||
ret.L = lightness;
|
|
||||||
ret.A = toDouble * A;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -25,6 +25,17 @@ public class CommandLineBuilder
|
|||||||
return condition ? Append(name, value) : this;
|
return condition ? Append(name, value) : this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 当参数不为 null 时添加参数
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">参数名称</param>
|
||||||
|
/// <param name="value">值</param>
|
||||||
|
/// <returns>命令行建造器</returns>
|
||||||
|
public CommandLineBuilder AppendIfNotNull(string name, object? value = null)
|
||||||
|
{
|
||||||
|
return AppendIf(name, value != null, value);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 添加参数
|
/// 添加参数
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -37,12 +48,6 @@ public class CommandLineBuilder
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="ToString"/>
|
|
||||||
public string Build()
|
|
||||||
{
|
|
||||||
return ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ internal static class CoreEnvironment
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 米游社 Rpc 版本
|
/// 米游社 Rpc 版本
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const string HoyolabXrpcVersion = "2.41.0";
|
public const string HoyolabXrpcVersion = "2.42.1";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 标准UA
|
/// 标准UA
|
||||||
|
|||||||
@@ -44,11 +44,11 @@ public static class DbSetExtension
|
|||||||
/// <param name="dbSet">数据库集</param>
|
/// <param name="dbSet">数据库集</param>
|
||||||
/// <param name="entity">实体</param>
|
/// <param name="entity">实体</param>
|
||||||
/// <returns>影响条数</returns>
|
/// <returns>影响条数</returns>
|
||||||
public static Task<int> AddAndSaveAsync<TEntity>(this DbSet<TEntity> dbSet, TEntity entity)
|
public static async ValueTask<int> AddAndSaveAsync<TEntity>(this DbSet<TEntity> dbSet, TEntity entity)
|
||||||
where TEntity : class
|
where TEntity : class
|
||||||
{
|
{
|
||||||
dbSet.Add(entity);
|
dbSet.Add(entity);
|
||||||
return dbSet.Context().SaveChangesAsync();
|
return await dbSet.Context().SaveChangesAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -72,11 +72,11 @@ public static class DbSetExtension
|
|||||||
/// <param name="dbSet">数据库集</param>
|
/// <param name="dbSet">数据库集</param>
|
||||||
/// <param name="entities">实体</param>
|
/// <param name="entities">实体</param>
|
||||||
/// <returns>影响条数</returns>
|
/// <returns>影响条数</returns>
|
||||||
public static Task<int> AddRangeAndSaveAsync<TEntity>(this DbSet<TEntity> dbSet, IEnumerable<TEntity> entities)
|
public static async ValueTask<int> AddRangeAndSaveAsync<TEntity>(this DbSet<TEntity> dbSet, IEnumerable<TEntity> entities)
|
||||||
where TEntity : class
|
where TEntity : class
|
||||||
{
|
{
|
||||||
dbSet.AddRange(entities);
|
dbSet.AddRange(entities);
|
||||||
return dbSet.Context().SaveChangesAsync();
|
return await dbSet.Context().SaveChangesAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -100,11 +100,11 @@ public static class DbSetExtension
|
|||||||
/// <param name="dbSet">数据库集</param>
|
/// <param name="dbSet">数据库集</param>
|
||||||
/// <param name="entity">实体</param>
|
/// <param name="entity">实体</param>
|
||||||
/// <returns>影响条数</returns>
|
/// <returns>影响条数</returns>
|
||||||
public static Task<int> RemoveAndSaveAsync<TEntity>(this DbSet<TEntity> dbSet, TEntity entity)
|
public static async ValueTask<int> RemoveAndSaveAsync<TEntity>(this DbSet<TEntity> dbSet, TEntity entity)
|
||||||
where TEntity : class
|
where TEntity : class
|
||||||
{
|
{
|
||||||
dbSet.Remove(entity);
|
dbSet.Remove(entity);
|
||||||
return dbSet.Context().SaveChangesAsync();
|
return await dbSet.Context().SaveChangesAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -128,10 +128,10 @@ public static class DbSetExtension
|
|||||||
/// <param name="dbSet">数据库集</param>
|
/// <param name="dbSet">数据库集</param>
|
||||||
/// <param name="entity">实体</param>
|
/// <param name="entity">实体</param>
|
||||||
/// <returns>影响条数</returns>
|
/// <returns>影响条数</returns>
|
||||||
public static Task<int> UpdateAndSaveAsync<TEntity>(this DbSet<TEntity> dbSet, TEntity entity)
|
public static async ValueTask<int> UpdateAndSaveAsync<TEntity>(this DbSet<TEntity> dbSet, TEntity entity)
|
||||||
where TEntity : class
|
where TEntity : class
|
||||||
{
|
{
|
||||||
dbSet.Update(entity);
|
dbSet.Update(entity);
|
||||||
return dbSet.Context().SaveChangesAsync();
|
return await dbSet.Context().SaveChangesAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,6 @@
|
|||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using Snap.Hutao.Core.Json.Annotation;
|
using Snap.Hutao.Core.Json.Annotation;
|
||||||
using Snap.Hutao.Core.Json.Converter;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Text.Json.Serialization.Metadata;
|
using System.Text.Json.Serialization.Metadata;
|
||||||
|
|
||||||
namespace Snap.Hutao.Core.Json;
|
namespace Snap.Hutao.Core.Json;
|
||||||
|
|||||||
@@ -23,6 +23,11 @@ internal static class Activation
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public const string LaunchGame = "LaunchGame";
|
public const string LaunchGame = "LaunchGame";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 从剪贴板导入成就
|
||||||
|
/// </summary>
|
||||||
|
public const string ImportUIAFFromClipBoard = "ImportUIAFFromClipBoard";
|
||||||
|
|
||||||
private static readonly SemaphoreSlim ActivateSemaphore = new(1);
|
private static readonly SemaphoreSlim ActivateSemaphore = new(1);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -49,7 +54,21 @@ internal static class Activation
|
|||||||
_ = sender;
|
_ = sender;
|
||||||
if (!ToastNotificationManagerCompat.WasCurrentProcessToastActivated())
|
if (!ToastNotificationManagerCompat.WasCurrentProcessToastActivated())
|
||||||
{
|
{
|
||||||
HandleActivationAsync(args).SafeForget();
|
HandleActivationAsync(args, true).SafeForget();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 触发激活事件
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sender">发送方</param>
|
||||||
|
/// <param name="args">激活参数</param>
|
||||||
|
public static void NonRedirectToActivate(object? sender, AppActivationArguments args)
|
||||||
|
{
|
||||||
|
_ = sender;
|
||||||
|
if (!ToastNotificationManagerCompat.WasCurrentProcessToastActivated())
|
||||||
|
{
|
||||||
|
HandleActivationAsync(args, false).SafeForget();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,24 +95,24 @@ internal static class Activation
|
|||||||
/// 异步响应激活事件
|
/// 异步响应激活事件
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>任务</returns>
|
/// <returns>任务</returns>
|
||||||
private static async Task HandleActivationAsync(AppActivationArguments args)
|
private static async Task HandleActivationAsync(AppActivationArguments args, bool isRedirected)
|
||||||
{
|
{
|
||||||
if (ActivateSemaphore.CurrentCount > 0)
|
if (ActivateSemaphore.CurrentCount > 0)
|
||||||
{
|
{
|
||||||
using (await ActivateSemaphore.EnterAsync().ConfigureAwait(false))
|
using (await ActivateSemaphore.EnterAsync().ConfigureAwait(false))
|
||||||
{
|
{
|
||||||
await HandleActivationCoreAsync(args).ConfigureAwait(false);
|
await HandleActivationCoreAsync(args, isRedirected).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task HandleActivationCoreAsync(AppActivationArguments args)
|
private static async Task HandleActivationCoreAsync(AppActivationArguments args, bool isRedirected)
|
||||||
{
|
{
|
||||||
if (args.Kind == ExtendedActivationKind.Protocol)
|
if (args.Kind == ExtendedActivationKind.Protocol)
|
||||||
{
|
{
|
||||||
if (args.TryGetProtocolActivatedUri(out Uri? uri))
|
if (args.TryGetProtocolActivatedUri(out Uri? uri))
|
||||||
{
|
{
|
||||||
await HandleUrlActivationAsync(uri).ConfigureAwait(false);
|
await HandleUrlActivationAsync(uri, isRedirected).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (args.Kind == ExtendedActivationKind.Launch)
|
else if (args.Kind == ExtendedActivationKind.Launch)
|
||||||
@@ -131,7 +150,7 @@ internal static class Activation
|
|||||||
.SafeForget();
|
.SafeForget();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task HandleUrlActivationAsync(Uri uri)
|
private static async Task HandleUrlActivationAsync(Uri uri, bool isRedirected)
|
||||||
{
|
{
|
||||||
UriBuilder builder = new(uri);
|
UriBuilder builder = new(uri);
|
||||||
|
|
||||||
@@ -144,28 +163,29 @@ internal static class Activation
|
|||||||
case "achievement":
|
case "achievement":
|
||||||
{
|
{
|
||||||
await WaitMainWindowAsync().ConfigureAwait(false);
|
await WaitMainWindowAsync().ConfigureAwait(false);
|
||||||
await HandleAchievementActionAsync(action, parameter).ConfigureAwait(false);
|
await HandleAchievementActionAsync(action, parameter, isRedirected).ConfigureAwait(false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case "dailynote":
|
case "dailynote":
|
||||||
{
|
{
|
||||||
await HandleDailyNoteActionAsync(action, parameter).ConfigureAwait(false);
|
await HandleDailyNoteActionAsync(action, parameter, isRedirected).ConfigureAwait(false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task HandleAchievementActionAsync(string action, string parameter)
|
private static async Task HandleAchievementActionAsync(string action, string parameter, bool isRedirected)
|
||||||
{
|
{
|
||||||
_ = parameter;
|
_ = parameter;
|
||||||
|
_ = isRedirected;
|
||||||
switch (action)
|
switch (action)
|
||||||
{
|
{
|
||||||
case "/import":
|
case "/import":
|
||||||
{
|
{
|
||||||
await ThreadHelper.SwitchToMainThreadAsync();
|
await ThreadHelper.SwitchToMainThreadAsync();
|
||||||
|
|
||||||
INavigationAwaiter navigationAwaiter = new NavigationExtra("InvokeByUri");
|
INavigationAwaiter navigationAwaiter = new NavigationExtra(ImportUIAFFromClipBoard);
|
||||||
await Ioc.Default
|
await Ioc.Default
|
||||||
.GetRequiredService<INavigationService>()
|
.GetRequiredService<INavigationService>()
|
||||||
.NavigateAsync<View.Page.AchievementPage>(navigationAwaiter, true)
|
.NavigateAsync<View.Page.AchievementPage>(navigationAwaiter, true)
|
||||||
@@ -175,7 +195,7 @@ internal static class Activation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task HandleDailyNoteActionAsync(string action, string parameter)
|
private static async Task HandleDailyNoteActionAsync(string action, string parameter, bool isRedirected)
|
||||||
{
|
{
|
||||||
_ = parameter;
|
_ = parameter;
|
||||||
switch (action)
|
switch (action)
|
||||||
@@ -186,6 +206,14 @@ internal static class Activation
|
|||||||
.GetRequiredService<IDailyNoteService>()
|
.GetRequiredService<IDailyNoteService>()
|
||||||
.RefreshDailyNotesAsync(true)
|
.RefreshDailyNotesAsync(true)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
|
// Check if it's redirected.
|
||||||
|
if (!isRedirected)
|
||||||
|
{
|
||||||
|
// It's a direct open process, should exit immediately.
|
||||||
|
Environment.Exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,20 +19,22 @@ internal static class AppInstanceExtension
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="appInstance">app实例</param>
|
/// <param name="appInstance">app实例</param>
|
||||||
/// <param name="args">参数</param>
|
/// <param name="args">参数</param>
|
||||||
[SuppressMessage("", "VSTHRD002")]
|
|
||||||
[SuppressMessage("", "VSTHRD110")]
|
[SuppressMessage("", "VSTHRD110")]
|
||||||
public static unsafe void RedirectActivationTo(this AppInstance appInstance, AppActivationArguments args)
|
public static void RedirectActivationTo(this AppInstance appInstance, AppActivationArguments args)
|
||||||
{
|
{
|
||||||
HANDLE redirectEventHandle = CreateEvent((SECURITY_ATTRIBUTES*)null, true, false, null);
|
HANDLE redirectEventHandle = UnsafeCreateEvent();
|
||||||
Task.Run(() =>
|
Task.Run(async () =>
|
||||||
{
|
{
|
||||||
appInstance.RedirectActivationToAsync(args).AsTask().Wait();
|
await appInstance.RedirectActivationToAsync(args);
|
||||||
SetEvent(redirectEventHandle);
|
SetEvent(redirectEventHandle);
|
||||||
});
|
});
|
||||||
|
|
||||||
ReadOnlySpan<HANDLE> handles = new(in redirectEventHandle);
|
ReadOnlySpan<HANDLE> handles = new(in redirectEventHandle);
|
||||||
|
|
||||||
// non-blocking
|
|
||||||
CoWaitForMultipleObjects((uint)CWMO_FLAGS.CWMO_DEFAULT, INFINITE, handles, out uint _);
|
CoWaitForMultipleObjects((uint)CWMO_FLAGS.CWMO_DEFAULT, INFINITE, handles, out uint _);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static unsafe HANDLE UnsafeCreateEvent()
|
||||||
|
{
|
||||||
|
return CreateEvent(default(SECURITY_ATTRIBUTES*), true, false, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -10,7 +10,7 @@ namespace Snap.Hutao.Core;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 任务计划器服务
|
/// 任务计划器服务
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static class TaskSchedulerHelper
|
internal static class ScheduleTaskHelper
|
||||||
{
|
{
|
||||||
private const string DailyNoteRefreshTaskName = "SnapHutaoDailyNoteRefreshTask";
|
private const string DailyNoteRefreshTaskName = "SnapHutaoDailyNoteRefreshTask";
|
||||||
|
|
||||||
@@ -45,4 +45,30 @@ internal static class TaskSchedulerHelper
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 卸载全部注册的任务
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>是否卸载成功</returns>
|
||||||
|
public static bool UnregisterAllTasks()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
SchedulerTask? targetTask = TaskService.Instance.GetTask(DailyNoteRefreshTaskName);
|
||||||
|
if (targetTask != null)
|
||||||
|
{
|
||||||
|
TaskService.Instance.RootFolder.DeleteTask(DailyNoteRefreshTaskName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (UnauthorizedAccessException)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch (COMException)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -43,6 +43,9 @@ public readonly struct DispatherQueueSwitchOperation : IAwaitable<DispatherQueue
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public void OnCompleted(Action continuation)
|
public void OnCompleted(Action continuation)
|
||||||
{
|
{
|
||||||
dispatherQueue.TryEnqueue(() => { continuation(); });
|
dispatherQueue.TryEnqueue(() =>
|
||||||
|
{
|
||||||
|
continuation();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -50,6 +50,10 @@ internal abstract class WebView2Helper
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static string Version
|
public static string Version
|
||||||
{
|
{
|
||||||
get => version;
|
get
|
||||||
|
{
|
||||||
|
_ = IsSupported;
|
||||||
|
return version;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -10,7 +10,7 @@ namespace Snap.Hutao.Core.Windowing;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// <see cref="AppWindow"/> 扩展
|
/// <see cref="AppWindow"/> 扩展
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class AppWindowExtensions
|
public static class AppWindowExtension
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取当前 <see cref="AppWindow"/> 的呈现矩形
|
/// 获取当前 <see cref="AppWindow"/> 的呈现矩形
|
||||||
@@ -134,7 +134,8 @@ internal sealed class ExtendedWindow<TWindow> : IRecipient<BackdropTypeChangedMe
|
|||||||
(string pos, string size) = GetPostionAndSize(appWindow);
|
(string pos, string size) = GetPostionAndSize(appWindow);
|
||||||
logger.LogInformation(EventIds.WindowState, "Postion: [{pos}], Size: [{size}]", pos, size);
|
logger.LogInformation(EventIds.WindowState, "Postion: [{pos}], Size: [{size}]", pos, size);
|
||||||
|
|
||||||
appWindow.Show(true);
|
// appWindow.Show(true);
|
||||||
|
window.Activate();
|
||||||
|
|
||||||
systemBackdrop = new(window);
|
systemBackdrop = new(window);
|
||||||
bool micaApplied = systemBackdrop.TryApply();
|
bool micaApplied = systemBackdrop.TryApply();
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ internal class PickerFactory : IPickerFactory
|
|||||||
picker.FileTypeFilter.Add(type);
|
picker.FileTypeFilter.Add(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://github.com/microsoft/WindowsAppSDK/issues/2931
|
||||||
picker.FileTypeFilter.Add(AnyType);
|
picker.FileTypeFilter.Add(AnyType);
|
||||||
|
|
||||||
return picker;
|
return picker;
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using Snap.Hutao.Core.Windowing;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Message;
|
namespace Snap.Hutao.Message;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
|
||||||
namespace Snap.Hutao.Model.Binding;
|
namespace Snap.Hutao.Model.Binding.Achievement;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 用于视图绑定的成就
|
/// 用于视图绑定的成就
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Model.Binding.Achievement;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 绑定成就分类
|
||||||
|
/// </summary>
|
||||||
|
public class AchievementGoal : ObservableObject
|
||||||
|
{
|
||||||
|
private double finishPercent;
|
||||||
|
private string? finishDescription;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 构造一个新的成就分类
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="goal">分类</param>
|
||||||
|
public AchievementGoal(Metadata.Achievement.AchievementGoal goal)
|
||||||
|
{
|
||||||
|
Id = goal.Id;
|
||||||
|
Order = goal.Order;
|
||||||
|
Name = goal.Name;
|
||||||
|
Icon = Metadata.Converter.AchievementIconConverter.IconNameToUri(goal.Icon);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Id
|
||||||
|
/// </summary>
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 排序顺序
|
||||||
|
/// </summary>
|
||||||
|
public int Order { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 名称
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 图标
|
||||||
|
/// </summary>
|
||||||
|
public Uri? Icon { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 完成百分比
|
||||||
|
/// </summary>
|
||||||
|
public double FinishPercent { get => finishPercent; set => SetProperty(ref finishPercent, value); }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 完成百分比
|
||||||
|
/// </summary>
|
||||||
|
public string? FinishDescription { get => finishDescription; set => SetProperty(ref finishDescription, value); }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 更新进度
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="finished">完成项</param>
|
||||||
|
/// <param name="count">总项</param>
|
||||||
|
public void UpdateFinishPercent(int finished, int count)
|
||||||
|
{
|
||||||
|
FinishPercent = (double)finished / count;
|
||||||
|
FinishDescription = $"{finished}/{count} - {FinishPercent:P2}";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,14 +1,17 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Model.Calculable;
|
||||||
using Snap.Hutao.Model.Intrinsic;
|
using Snap.Hutao.Model.Intrinsic;
|
||||||
|
using Snap.Hutao.Model.Primitive;
|
||||||
|
using Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate;
|
||||||
|
|
||||||
namespace Snap.Hutao.Model.Binding.AvatarProperty;
|
namespace Snap.Hutao.Model.Binding.AvatarProperty;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 角色信息
|
/// 角色信息
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Avatar
|
public class Avatar : ICalculableSource<ICalculableAvatar>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 名称
|
/// 名称
|
||||||
@@ -45,11 +48,6 @@ public class Avatar
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string Level { get; set; } = default!;
|
public string Level { get; set; } = default!;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 好感度等级
|
|
||||||
/// </summary>
|
|
||||||
public int FetterLevel { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 武器
|
/// 武器
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -84,4 +82,25 @@ public class Avatar
|
|||||||
/// 双爆评分
|
/// 双爆评分
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string CritScore { get; set; } = default!;
|
public string CritScore { get; set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 好感度等级
|
||||||
|
/// </summary>
|
||||||
|
public int FetterLevel { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Id
|
||||||
|
/// </summary>
|
||||||
|
internal AvatarId Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 等级数字
|
||||||
|
/// </summary>
|
||||||
|
internal int LevelNumber { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public ICalculableAvatar ToCalculable()
|
||||||
|
{
|
||||||
|
return new CalculableAvatar(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,22 +1,35 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Model.Calculable;
|
||||||
using Snap.Hutao.Model.Metadata;
|
using Snap.Hutao.Model.Metadata;
|
||||||
|
using Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate;
|
||||||
|
|
||||||
namespace Snap.Hutao.Model.Binding.AvatarProperty;
|
namespace Snap.Hutao.Model.Binding.AvatarProperty;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 天赋
|
/// 天赋
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Skill : NameIconDescription
|
public class Skill : NameIconDescription, ICalculableSource<ICalculableSkill>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 技能属性
|
/// 技能属性
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public LevelParam<string, ParameterInfo> Info { get; set; } = default!;
|
public LevelParam<string, ParameterInfo> Info { get; set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 技能组Id
|
||||||
|
/// </summary>
|
||||||
|
internal int GroupId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 技能等级,仅用于养成计算
|
/// 技能等级,仅用于养成计算
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal int Level { get; set; }
|
internal int LevelNumber { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public ICalculableSkill ToCalculable()
|
||||||
|
{
|
||||||
|
return new CalculableSkill(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,16 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Model.Calculable;
|
||||||
|
using Snap.Hutao.Model.Primitive;
|
||||||
|
using Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate;
|
||||||
|
|
||||||
namespace Snap.Hutao.Model.Binding.AvatarProperty;
|
namespace Snap.Hutao.Model.Binding.AvatarProperty;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 武器
|
/// 武器
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Weapon : EquipBase
|
public class Weapon : EquipBase, ICalculableSource<ICalculableWeapon>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 副属性
|
/// 副属性
|
||||||
@@ -27,4 +31,20 @@ public class Weapon : EquipBase
|
|||||||
/// 精炼被动
|
/// 精炼被动
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string AffixDescription { get; set; } = default!;
|
public string AffixDescription { get; set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Id
|
||||||
|
/// </summary>
|
||||||
|
internal WeaponId Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 等级数字
|
||||||
|
/// </summary>
|
||||||
|
internal int LevelNumber { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public ICalculableWeapon ToCalculable()
|
||||||
|
{
|
||||||
|
return new CalculableWeapon(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -25,6 +25,7 @@ public class CultivateItem : ObservableObject
|
|||||||
Inner = inner;
|
Inner = inner;
|
||||||
Entity = entity;
|
Entity = entity;
|
||||||
isFinished = Entity.IsFinished;
|
isFinished = Entity.IsFinished;
|
||||||
|
IsToday = CultivateItemHelper.IsTodaysMaterial(inner.Id, DateTimeOffset.Now);
|
||||||
|
|
||||||
FinishStateCommand = new RelayCommand(FlipIsFinished);
|
FinishStateCommand = new RelayCommand(FlipIsFinished);
|
||||||
}
|
}
|
||||||
@@ -59,6 +60,16 @@ public class CultivateItem : ObservableObject
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否为今日物品
|
||||||
|
/// </summary>
|
||||||
|
public bool IsToday { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 对应背包物品的个数
|
||||||
|
/// </summary>
|
||||||
|
public uint InventoryItemCount { get; set; }
|
||||||
|
|
||||||
private void FlipIsFinished()
|
private void FlipIsFinished()
|
||||||
{
|
{
|
||||||
IsFinished = !IsFinished;
|
IsFinished = !IsFinished;
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Model.Binding.Cultivation;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 养成物品帮助类
|
||||||
|
/// </summary>
|
||||||
|
public static class CultivateItemHelper
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 判断是否为当日物品
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="itemId">材料Id</param>
|
||||||
|
/// <param name="now">时间</param>
|
||||||
|
/// <returns>是否为当日物品</returns>
|
||||||
|
public static bool IsTodaysMaterial(int itemId, DateTimeOffset now)
|
||||||
|
{
|
||||||
|
DateTimeOffset utcNow = now.ToUniversalTime();
|
||||||
|
utcNow = utcNow.AddHours(4);
|
||||||
|
DayOfWeek dayOfWeek = utcNow.DayOfWeek;
|
||||||
|
|
||||||
|
return dayOfWeek switch
|
||||||
|
{
|
||||||
|
DayOfWeek.Monday or DayOfWeek.Thursday => itemId switch
|
||||||
|
{
|
||||||
|
104301 or 104302 or 104303 => true, // 「自由」
|
||||||
|
104310 or 104311 or 104312 => true, // 「繁荣」
|
||||||
|
104320 or 104321 or 104322 => true, // 「浮世」
|
||||||
|
104329 or 104330 or 104331 => true, // 「诤言」
|
||||||
|
114001 or 114002 or 114003 or 114004 => true, // 高塔孤王
|
||||||
|
114013 or 114014 or 114015 or 114016 => true, // 孤云寒林
|
||||||
|
114025 or 114026 or 114027 or 114028 => true, // 远海夷地
|
||||||
|
114037 or 114038 or 114039 or 114040 => true, // 谧林涓露
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
DayOfWeek.Tuesday or DayOfWeek.Friday => itemId switch
|
||||||
|
{
|
||||||
|
104304 or 104305 or 104306 => true, // 「抗争」
|
||||||
|
104313 or 104314 or 104315 => true, // 「勤劳」
|
||||||
|
104323 or 104324 or 104325 => true, // 「风雅」
|
||||||
|
104332 or 104333 or 104334 => true, // 「巧思」
|
||||||
|
114005 or 114006 or 114007 or 114008 => true, // 凛风奔狼
|
||||||
|
114017 or 114018 or 114019 or 114020 => true, // 雾海云间
|
||||||
|
114029 or 114030 or 114031 or 114032 => true, // 鸣神御灵
|
||||||
|
114041 or 114042 or 114043 or 114044 => true, // 绿洲花园
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
DayOfWeek.Wednesday or DayOfWeek.Saturday => itemId switch
|
||||||
|
{
|
||||||
|
104307 or 104308 or 104309 => true, // 「诗文」
|
||||||
|
104316 or 104317 or 104318 => true, // 「黄金」
|
||||||
|
104326 or 104327 or 104328 => true, // 「天光」
|
||||||
|
104335 or 104336 or 104337 => true, // 「笃行」
|
||||||
|
114009 or 114010 or 114011 or 114012 => true, // 狮牙斗士
|
||||||
|
114021 or 114022 or 114023 or 114024 => true, // 漆黑陨铁
|
||||||
|
114033 or 114034 or 114035 or 114036 => true, // 今昔剧画
|
||||||
|
114045 or 114046 or 114047 or 114048 => true, // 谧林涓露
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Model.Metadata;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Model.Binding.Cultivation;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 仅用于统计总数的养成物品
|
||||||
|
/// </summary>
|
||||||
|
public class StatisticsCultivateItem
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 构造一个新的统计用养成物品
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="inner">材料</param>
|
||||||
|
/// <param name="entity">实体</param>
|
||||||
|
public StatisticsCultivateItem(Material inner, Entity.CultivateItem entity)
|
||||||
|
{
|
||||||
|
Inner = inner;
|
||||||
|
Count = entity.Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 元数据
|
||||||
|
/// </summary>
|
||||||
|
public Material Inner { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 对应背包物品的个数
|
||||||
|
/// </summary>
|
||||||
|
public int Count { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 对应背包物品的个数
|
||||||
|
/// </summary>
|
||||||
|
public uint TotalCount { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否完成
|
||||||
|
/// </summary>
|
||||||
|
public bool IsFinished { get => Count >= TotalCount; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 格式化总数
|
||||||
|
/// </summary>
|
||||||
|
public string CountFormatted { get => $"{Count}/{TotalCount}"; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Model.Metadata;
|
||||||
|
using Snap.Hutao.Model.Metadata.Avatar;
|
||||||
|
using Snap.Hutao.Model.Primitive;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Model.Binding.Hutao;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 料理奖励视图
|
||||||
|
/// </summary>
|
||||||
|
public class CookBonusView
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 原型
|
||||||
|
/// </summary>
|
||||||
|
public Material OriginItem { get; set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 名称
|
||||||
|
/// </summary>
|
||||||
|
public Material Item { get; set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创建一个新的料理奖励视图
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cookBonus">料理奖励</param>
|
||||||
|
/// <param name="idMaterialMap">材料映射</param>
|
||||||
|
/// <returns>新的料理奖励视图</returns>
|
||||||
|
public static CookBonusView? Create(CookBonus? cookBonus, Dictionary<MaterialId, Material> idMaterialMap)
|
||||||
|
{
|
||||||
|
if (cookBonus == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
CookBonusView view = new()
|
||||||
|
{
|
||||||
|
OriginItem = idMaterialMap[cookBonus.OriginItemId],
|
||||||
|
Item = idMaterialMap[cookBonus.ItemId],
|
||||||
|
};
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,7 +20,7 @@ internal class Team : List<ComplexAvatar>
|
|||||||
public Team(ItemRate<string, int> team, Dictionary<AvatarId, Avatar> idAvatarMap)
|
public Team(ItemRate<string, int> team, Dictionary<AvatarId, Avatar> idAvatarMap)
|
||||||
: base(4)
|
: base(4)
|
||||||
{
|
{
|
||||||
IEnumerable<int> ids = team.Item.Split(',').Select(int.Parse);
|
IOrderedEnumerable<int> ids = team.Item.Split(',').Select(int.Parse).OrderByDescending(x => x);
|
||||||
|
|
||||||
foreach (int id in ids)
|
foreach (int id in ids)
|
||||||
{
|
{
|
||||||
@@ -28,8 +28,14 @@ internal class Team : List<ComplexAvatar>
|
|||||||
}
|
}
|
||||||
|
|
||||||
Rate = $"上场 {team.Rate} 次";
|
Rate = $"上场 {team.Rate} 次";
|
||||||
|
Name = TeamPopularNameParser.GetName(ids.ToHashSet());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 队伍俗名
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 上场次数
|
/// 上场次数
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Model.Metadata;
|
||||||
|
using System.Collections.Immutable;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Model.Binding.Hutao;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 队伍俗名解析器
|
||||||
|
/// </summary>
|
||||||
|
internal static class TeamPopularNameParser
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 已知的队伍名称
|
||||||
|
/// </summary>
|
||||||
|
private static readonly ImmutableDictionary<string, ImmutableHashSet<int>> KnownTeamNames = new Dictionary<string, ImmutableHashSet<int>>()
|
||||||
|
{
|
||||||
|
["雷国|雷行香班"] = new HashSet<int>() { AvatarIds.Shougun, AvatarIds.Xingqiu, AvatarIds.Xiangling, AvatarIds.Bennett, }.ToImmutableHashSet(),
|
||||||
|
["雷国|雷夜香班"] = new HashSet<int>() { AvatarIds.Shougun, AvatarIds.Yelan, AvatarIds.Xiangling, AvatarIds.Bennett, }.ToImmutableHashSet(),
|
||||||
|
["雷国|雷万香班"] = new HashSet<int>() { AvatarIds.Shougun, AvatarIds.Kazuha, AvatarIds.Xiangling, AvatarIds.Bennett, }.ToImmutableHashSet(),
|
||||||
|
["雷九|雷九万班"] = new HashSet<int>() { AvatarIds.Shougun, AvatarIds.Sara, AvatarIds.Kazuha, AvatarIds.Bennett, }.ToImmutableHashSet(),
|
||||||
|
["万达国际"] = new HashSet<int>() { AvatarIds.Kazuha, AvatarIds.Tartaglia, AvatarIds.Xiangling, AvatarIds.Bennett, }.ToImmutableHashSet(),
|
||||||
|
["胡行钟夜"] = new HashSet<int>() { AvatarIds.Hutao, AvatarIds.Xingqiu, AvatarIds.Zhongli, AvatarIds.Yelan, }.ToImmutableHashSet(),
|
||||||
|
["激晴|刻皇万妲"] = new HashSet<int>() { AvatarIds.Keqing, AvatarIds.Fischl, AvatarIds.Kazuha, AvatarIds.Nahida, }.ToImmutableHashSet(),
|
||||||
|
["永冻|神鹤万心"] = new HashSet<int>() { AvatarIds.Ayaka, AvatarIds.Shenhe, AvatarIds.Kazuha, AvatarIds.Kokomi, }.ToImmutableHashSet(),
|
||||||
|
["永冻|神钟万心"] = new HashSet<int>() { AvatarIds.Ayaka, AvatarIds.Zhongli, AvatarIds.Kazuha, AvatarIds.Kokomi, }.ToImmutableHashSet(),
|
||||||
|
["融甘|融化甘雨"] = new HashSet<int>() { AvatarIds.Ganyu, AvatarIds.Zhongli, AvatarIds.Xiangling, AvatarIds.Bennett, }.ToImmutableHashSet(),
|
||||||
|
["妮绽放|女主"] = new HashSet<int>() { AvatarIds.Nilou, AvatarIds.Kokomi, AvatarIds.Nahida, AvatarIds.PlayerGirl, }.ToImmutableHashSet(),
|
||||||
|
["妮绽放|男主"] = new HashSet<int>() { AvatarIds.Nilou, AvatarIds.Kokomi, AvatarIds.Nahida, AvatarIds.PlayerBoy, }.ToImmutableHashSet(),
|
||||||
|
["一斗岩队"] = new HashSet<int>() { AvatarIds.Itto, AvatarIds.Albedo, AvatarIds.Zhongli, AvatarIds.Gorou, }.ToImmutableHashSet(),
|
||||||
|
}.ToImmutableDictionary();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取队伍名称
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ids">队伍集</param>
|
||||||
|
/// <returns>队伍名称</returns>
|
||||||
|
public static string GetName(HashSet<int> ids)
|
||||||
|
{
|
||||||
|
foreach (KeyValuePair<string, ImmutableHashSet<int>> entry in KnownTeamNames)
|
||||||
|
{
|
||||||
|
if (entry.Value.SetEquals(ids))
|
||||||
|
{
|
||||||
|
return entry.Key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "尚未命名";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,16 +2,12 @@
|
|||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using Snap.Hutao.Model.Binding.Gacha;
|
|
||||||
using Snap.Hutao.Model.Binding.Gacha.Abstraction;
|
|
||||||
using Snap.Hutao.Model.Binding.Hutao;
|
|
||||||
using Snap.Hutao.Model.Intrinsic;
|
using Snap.Hutao.Model.Intrinsic;
|
||||||
using Snap.Hutao.Model.Metadata.Abstraction;
|
|
||||||
using Snap.Hutao.Model.Metadata.Converter;
|
using Snap.Hutao.Model.Metadata.Converter;
|
||||||
using Snap.Hutao.Model.Primitive;
|
using Snap.Hutao.Model.Primitive;
|
||||||
using Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate;
|
using Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate;
|
||||||
|
|
||||||
namespace Snap.Hutao.Model.Metadata.Avatar;
|
namespace Snap.Hutao.Model.Calculable;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 可计算角色
|
/// 可计算角色
|
||||||
@@ -25,7 +21,7 @@ internal class CalculableAvatar : ObservableObject, ICalculableAvatar
|
|||||||
/// 构造一个新的可计算角色
|
/// 构造一个新的可计算角色
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="avatar">角色</param>
|
/// <param name="avatar">角色</param>
|
||||||
public CalculableAvatar(Avatar avatar)
|
public CalculableAvatar(Metadata.Avatar.Avatar avatar)
|
||||||
{
|
{
|
||||||
AvatarId = avatar.Id;
|
AvatarId = avatar.Id;
|
||||||
LevelMin = 1;
|
LevelMin = 1;
|
||||||
@@ -34,6 +30,25 @@ internal class CalculableAvatar : ObservableObject, ICalculableAvatar
|
|||||||
Name = avatar.Name;
|
Name = avatar.Name;
|
||||||
Icon = AvatarIconConverter.IconNameToUri(avatar.Icon);
|
Icon = AvatarIconConverter.IconNameToUri(avatar.Icon);
|
||||||
Quality = avatar.Quality;
|
Quality = avatar.Quality;
|
||||||
|
|
||||||
|
LevelCurrent = LevelMin;
|
||||||
|
LevelTarget = LevelMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 构造一个新的可计算角色
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="avatar">角色</param>
|
||||||
|
public CalculableAvatar(Binding.AvatarProperty.Avatar avatar)
|
||||||
|
{
|
||||||
|
AvatarId = avatar.Id;
|
||||||
|
LevelMin = avatar.LevelNumber;
|
||||||
|
LevelMax = 90; // hard coded 90
|
||||||
|
Skills = avatar.Skills.Select(s => s.ToCalculable()).ToList();
|
||||||
|
Name = avatar.Name;
|
||||||
|
Icon = avatar.Icon;
|
||||||
|
Quality = avatar.Quality;
|
||||||
|
|
||||||
LevelCurrent = LevelMin;
|
LevelCurrent = LevelMin;
|
||||||
LevelTarget = LevelMax;
|
LevelTarget = LevelMax;
|
||||||
}
|
}
|
||||||
@@ -3,10 +3,11 @@
|
|||||||
|
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using Snap.Hutao.Model.Intrinsic;
|
using Snap.Hutao.Model.Intrinsic;
|
||||||
|
using Snap.Hutao.Model.Metadata.Avatar;
|
||||||
using Snap.Hutao.Model.Metadata.Converter;
|
using Snap.Hutao.Model.Metadata.Converter;
|
||||||
using Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate;
|
using Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate;
|
||||||
|
|
||||||
namespace Snap.Hutao.Model.Metadata.Avatar;
|
namespace Snap.Hutao.Model.Calculable;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 可计算的技能
|
/// 可计算的技能
|
||||||
@@ -28,6 +29,24 @@ internal class CalculableSkill : ObservableObject, ICalculableSkill
|
|||||||
Name = skill.Name;
|
Name = skill.Name;
|
||||||
Icon = SkillIconConverter.IconNameToUri(skill.Icon);
|
Icon = SkillIconConverter.IconNameToUri(skill.Icon);
|
||||||
Quality = ItemQuality.QUALITY_NONE;
|
Quality = ItemQuality.QUALITY_NONE;
|
||||||
|
|
||||||
|
LevelCurrent = LevelMin;
|
||||||
|
LevelTarget = LevelMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 构造一个新的可计算的技能
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="skill">技能</param>
|
||||||
|
public CalculableSkill(Binding.AvatarProperty.Skill skill)
|
||||||
|
{
|
||||||
|
GruopId = skill.GroupId;
|
||||||
|
LevelMin = skill.LevelNumber;
|
||||||
|
LevelMax = 10; // hard coded 10 here
|
||||||
|
Name = skill.Name;
|
||||||
|
Icon = skill.Icon;
|
||||||
|
Quality = ItemQuality.QUALITY_NONE;
|
||||||
|
|
||||||
LevelCurrent = LevelMin;
|
LevelCurrent = LevelMin;
|
||||||
LevelTarget = LevelMax;
|
LevelTarget = LevelMax;
|
||||||
}
|
}
|
||||||
@@ -2,16 +2,12 @@
|
|||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using Snap.Hutao.Model.Binding.Gacha;
|
|
||||||
using Snap.Hutao.Model.Binding.Gacha.Abstraction;
|
|
||||||
using Snap.Hutao.Model.Binding.Hutao;
|
|
||||||
using Snap.Hutao.Model.Intrinsic;
|
using Snap.Hutao.Model.Intrinsic;
|
||||||
using Snap.Hutao.Model.Metadata.Abstraction;
|
|
||||||
using Snap.Hutao.Model.Metadata.Converter;
|
using Snap.Hutao.Model.Metadata.Converter;
|
||||||
using Snap.Hutao.Model.Primitive;
|
using Snap.Hutao.Model.Primitive;
|
||||||
using Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate;
|
using Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate;
|
||||||
|
|
||||||
namespace Snap.Hutao.Model.Metadata.Weapon;
|
namespace Snap.Hutao.Model.Calculable;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 可计算武器
|
/// 可计算武器
|
||||||
@@ -25,7 +21,7 @@ public class CalculableWeapon : ObservableObject, ICalculableWeapon
|
|||||||
/// 构造一个新的可计算武器
|
/// 构造一个新的可计算武器
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="weapon">武器</param>
|
/// <param name="weapon">武器</param>
|
||||||
public CalculableWeapon(Weapon weapon)
|
public CalculableWeapon(Metadata.Weapon.Weapon weapon)
|
||||||
{
|
{
|
||||||
WeaponId = weapon.Id;
|
WeaponId = weapon.Id;
|
||||||
LevelMin = 1;
|
LevelMin = 1;
|
||||||
@@ -33,6 +29,24 @@ public class CalculableWeapon : ObservableObject, ICalculableWeapon
|
|||||||
Name = weapon.Name;
|
Name = weapon.Name;
|
||||||
Icon = EquipIconConverter.IconNameToUri(weapon.Icon);
|
Icon = EquipIconConverter.IconNameToUri(weapon.Icon);
|
||||||
Quality = weapon.RankLevel;
|
Quality = weapon.RankLevel;
|
||||||
|
|
||||||
|
LevelCurrent = LevelMin;
|
||||||
|
LevelTarget = LevelMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 构造一个新的可计算武器
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="weapon">武器</param>
|
||||||
|
public CalculableWeapon(Binding.AvatarProperty.Weapon weapon)
|
||||||
|
{
|
||||||
|
WeaponId = weapon.Id;
|
||||||
|
LevelMin = weapon.LevelNumber;
|
||||||
|
LevelMax = (int)weapon.Quality >= 3 ? 90 : 70;
|
||||||
|
Name = weapon.Name;
|
||||||
|
Icon = weapon.Icon;
|
||||||
|
Quality = weapon.Quality;
|
||||||
|
|
||||||
LevelCurrent = LevelMin;
|
LevelCurrent = LevelMin;
|
||||||
LevelTarget = LevelMax;
|
LevelTarget = LevelMax;
|
||||||
}
|
}
|
||||||
@@ -31,60 +31,4 @@ internal class UIIF
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonPropertyName("list")]
|
[JsonPropertyName("list")]
|
||||||
public List<UIIFItem> List { get; set; } = default!;
|
public List<UIIFItem> List { get; set; } = default!;
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// UIIF物品
|
|
||||||
/// </summary>
|
|
||||||
[JsonDerivedType(typeof(UIIFReliquary))]
|
|
||||||
[JsonDerivedType(typeof(UIIFWeapon))]
|
|
||||||
internal class UIIFItem
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 物品Id
|
|
||||||
/// </summary>
|
|
||||||
[JsonPropertyName("itemId")]
|
|
||||||
public int ItemId { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 物品Id
|
|
||||||
/// </summary>
|
|
||||||
[JsonPropertyName("count")]
|
|
||||||
public int Count { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// UIIF圣遗物
|
|
||||||
/// </summary>
|
|
||||||
internal class UIIFReliquary : UIIFItem
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 物品Id
|
|
||||||
/// </summary>
|
|
||||||
[JsonPropertyName("level")]
|
|
||||||
public int Level { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 副属性列表
|
|
||||||
/// </summary>
|
|
||||||
[JsonPropertyName("appendPropIdList")]
|
|
||||||
public List<int> AppendPropIdList { get; set; } = default!;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// UIIF武器
|
|
||||||
/// </summary>
|
|
||||||
internal class UIIFWeapon : UIIFItem
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 物品Id
|
|
||||||
/// </summary>
|
|
||||||
[JsonPropertyName("level")]
|
|
||||||
public int Level { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 精炼等级 0-4
|
|
||||||
/// </summary>
|
|
||||||
[JsonPropertyName("promoteLevel")]
|
|
||||||
public int PromoteLevel { get; set; }
|
|
||||||
}
|
}
|
||||||
@@ -3,12 +3,6 @@
|
|||||||
|
|
||||||
using Snap.Hutao.Core;
|
using Snap.Hutao.Core;
|
||||||
using Snap.Hutao.Extension;
|
using Snap.Hutao.Extension;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.Immutable;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Model.InterChange.Inventory;
|
namespace Snap.Hutao.Model.InterChange.Inventory;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Model.InterChange.Inventory;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// UIIF物品
|
||||||
|
/// </summary>
|
||||||
|
internal class UIIFItem
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 物品Id
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("itemId")]
|
||||||
|
public int ItemId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 物品Id
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("count")]
|
||||||
|
public int Count { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 等级
|
||||||
|
/// Reliquary/Weapon
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("level")]
|
||||||
|
public int? Level { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 副属性列表
|
||||||
|
/// Reliquary
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("appendPropIdList")]
|
||||||
|
public List<int>? AppendPropIdList { get; set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 精炼等级 0-4
|
||||||
|
/// Weapon
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("promoteLevel")]
|
||||||
|
public int? PromoteLevel { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Extension;
|
||||||
|
using System.Collections.Immutable;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Model.Intrinsic;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 不可变的原生枚举
|
||||||
|
/// </summary>
|
||||||
|
public static class ImmutableIntrinsics
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 所属地区
|
||||||
|
/// </summary>
|
||||||
|
public static readonly ImmutableList<string> AssociationTypes = Enum.GetValues<AssociationType>().Select(e => e.GetDescriptionOrNull()).OfType<string>().ToImmutableList();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 武器类型
|
||||||
|
/// </summary>
|
||||||
|
public static readonly ImmutableList<string> WeaponTypes = Enum.GetValues<WeaponType>().Select(e => e.GetDescriptionOrNull()).OfType<string>().ToImmutableList();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 物品类型
|
||||||
|
/// </summary>
|
||||||
|
public static readonly ImmutableList<string> ItemQualities = Enum.GetValues<ItemQuality>().Select(e => e.GetDescriptionOrNull()).OfType<string>().ToImmutableList();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 身材类型
|
||||||
|
/// </summary>
|
||||||
|
public static readonly ImmutableList<string> BodyTypes = Enum.GetValues<BodyType>().Select(e => e.GetDescriptionOrNull()).OfType<string>().ToImmutableList();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 战斗属性
|
||||||
|
/// </summary>
|
||||||
|
public static readonly ImmutableList<string> FightProperties = Enum.GetValues<FightProperty>().Select(e => e.GetDescriptionOrNull()).OfType<string>().ToImmutableList();
|
||||||
|
}
|
||||||
59
src/Snap.Hutao/Snap.Hutao/Model/Intrinsic/MaterialType.cs
Normal file
59
src/Snap.Hutao/Snap.Hutao/Model/Intrinsic/MaterialType.cs
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Model.Intrinsic;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 材料类型
|
||||||
|
/// </summary>
|
||||||
|
[SuppressMessage("", "SA1602")]
|
||||||
|
public enum MaterialType
|
||||||
|
{
|
||||||
|
MATERIAL_NONE = 0,
|
||||||
|
MATERIAL_FOOD = 1,
|
||||||
|
MATERIAL_QUEST = 2,
|
||||||
|
MATERIAL_EXCHANGE = 4,
|
||||||
|
MATERIAL_CONSUME,
|
||||||
|
MATERIAL_EXP_FRUIT,
|
||||||
|
MATERIAL_AVATAR,
|
||||||
|
MATERIAL_ADSORBATE,
|
||||||
|
MATERIAL_CRICKET,
|
||||||
|
MATERIAL_ELEM_CRYSTAL,
|
||||||
|
MATERIAL_WEAPON_EXP_STONE,
|
||||||
|
MATERIAL_CHEST,
|
||||||
|
MATERIAL_RELIQUARY_MATERIAL,
|
||||||
|
MATERIAL_AVATAR_MATERIAL,
|
||||||
|
MATERIAL_NOTICE_ADD_HP,
|
||||||
|
MATERIAL_SEA_LAMP,
|
||||||
|
MATERIAL_SELECTABLE_CHEST,
|
||||||
|
MATERIAL_FLYCLOAK,
|
||||||
|
MATERIAL_NAMECARD,
|
||||||
|
MATERIAL_TALENT,
|
||||||
|
MATERIAL_WIDGET,
|
||||||
|
MATERIAL_CHEST_BATCH_USE,
|
||||||
|
MATERIAL_FAKE_ABSORBATE,
|
||||||
|
MATERIAL_CONSUME_BATCH_USE,
|
||||||
|
MATERIAL_WOOD,
|
||||||
|
MATERIAL_FURNITURE_FORMULA = 27,
|
||||||
|
MATERIAL_CHANNELLER_SLAB_BUFF,
|
||||||
|
MATERIAL_FURNITURE_SUITE_FORMULA,
|
||||||
|
MATERIAL_COSTUME,
|
||||||
|
MATERIAL_HOME_SEED,
|
||||||
|
MATERIAL_FISH_BAIT,
|
||||||
|
MATERIAL_FISH_ROD,
|
||||||
|
MATERIAL_SUMO_BUFF, // never appear
|
||||||
|
MATERIAL_FIREWORKS,
|
||||||
|
MATERIAL_BGM,
|
||||||
|
MATERIAL_SPICE_FOOD,
|
||||||
|
MATERIAL_ACTIVITY_ROBOT,
|
||||||
|
MATERIAL_ACTIVITY_GEAR,
|
||||||
|
MATERIAL_ACTIVITY_JIGSAW,
|
||||||
|
MATERIAL_ARANARA,
|
||||||
|
MATERIAL_GCG_CARD,
|
||||||
|
MATERIAL_GCG_CARD_FACE, // 影幻卡面
|
||||||
|
MATERIAL_GCG_CARD_BACK,
|
||||||
|
MATERIAL_GCG_FIELD,
|
||||||
|
MATERIAL_DESHRET_MANUAL,
|
||||||
|
MATERIAL_RENAME_ITEM,
|
||||||
|
MATERIAL_GCG_EXCHANGE_ITEM,
|
||||||
|
}
|
||||||
@@ -74,24 +74,24 @@ public enum WeaponType
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 法器
|
/// 法器
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Description("单手剑")]
|
[Description("法器")]
|
||||||
WEAPON_CATALYST = 10,
|
WEAPON_CATALYST = 10,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 双手剑
|
/// 双手剑
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Description("单手剑")]
|
[Description("双手剑")]
|
||||||
WEAPON_CLAYMORE = 11,
|
WEAPON_CLAYMORE = 11,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 弓
|
/// 弓
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Description("单手剑")]
|
[Description("弓")]
|
||||||
WEAPON_BOW = 12,
|
WEAPON_BOW = 12,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 长柄武器
|
/// 长柄武器
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Description("单手剑")]
|
[Description("长柄武器")]
|
||||||
WEAPON_POLE = 13,
|
WEAPON_POLE = 13,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,5 +31,5 @@ public class AchievementGoal
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 图标
|
/// 图标
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string? Icon { get; set; }
|
public string Icon { get; set; } = default!;
|
||||||
}
|
}
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
using Snap.Hutao.Model.Binding.Gacha;
|
using Snap.Hutao.Model.Binding.Gacha;
|
||||||
using Snap.Hutao.Model.Binding.Gacha.Abstraction;
|
using Snap.Hutao.Model.Binding.Gacha.Abstraction;
|
||||||
using Snap.Hutao.Model.Binding.Hutao;
|
using Snap.Hutao.Model.Binding.Hutao;
|
||||||
|
using Snap.Hutao.Model.Calculable;
|
||||||
using Snap.Hutao.Model.Metadata.Abstraction;
|
using Snap.Hutao.Model.Metadata.Abstraction;
|
||||||
using Snap.Hutao.Model.Metadata.Converter;
|
using Snap.Hutao.Model.Metadata.Converter;
|
||||||
using Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate;
|
using Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate;
|
||||||
@@ -21,6 +22,17 @@ public partial class Avatar : IStatisticsItemSource, ISummaryItemSource, INameQu
|
|||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public ComplexAvatarCollocation? Collocation { get; set; }
|
public ComplexAvatarCollocation? Collocation { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// [非元数据] 烹饪奖励
|
||||||
|
/// </summary>
|
||||||
|
[JsonIgnore]
|
||||||
|
public CookBonusView? CookBonusView { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 养成物品视图
|
||||||
|
/// </summary>
|
||||||
|
public List<Material>? CultivationItemsView { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ICalculableAvatar ToCalculable()
|
public ICalculableAvatar ToCalculable()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -81,5 +81,10 @@ public partial class Avatar
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 皮肤
|
/// 皮肤
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IEnumerable<Costume> Costumes { get; set; } = default!;
|
public List<Costume> Costumes { get; set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 养成物品
|
||||||
|
/// </summary>
|
||||||
|
public List<MaterialId> CultivationItems { get; set; } = default!;
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using Snap.Hutao.Model.Intrinsic;
|
using Snap.Hutao.Model.Primitive;
|
||||||
|
|
||||||
namespace Snap.Hutao.Model.Metadata.Avatar;
|
namespace Snap.Hutao.Model.Metadata.Avatar;
|
||||||
|
|
||||||
@@ -13,45 +13,15 @@ public class CookBonus
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 原型名称
|
/// 原型名称
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string OriginName { get; set; } = default!;
|
public MaterialId OriginItemId { get; set; } = default!;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 原型描述
|
|
||||||
/// </summary>
|
|
||||||
public string OriginDescription { get; set; } = default!;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 原型图标
|
|
||||||
/// </summary>
|
|
||||||
public string OriginIcon { get; set; } = default!;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 名称
|
/// 名称
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Name { get; set; } = default!;
|
public MaterialId ItemId { get; set; } = default!;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 描述
|
|
||||||
/// </summary>
|
|
||||||
public string Description { get; set; } = default!;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 效果描述
|
|
||||||
/// </summary>
|
|
||||||
public string EffectDescription { get; set; } = default!;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 图标
|
|
||||||
/// </summary>
|
|
||||||
public string Icon { get; set; } = default!;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 物品等级
|
|
||||||
/// </summary>
|
|
||||||
public ItemQuality RankLevel { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 材料列表
|
/// 材料列表
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<ItemWithCount> InputList { get; set; } = default!;
|
public List<MaterialId> InputList { get; set; } = default!;
|
||||||
}
|
}
|
||||||
@@ -83,7 +83,7 @@ public class FetterInfo
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 料理
|
/// 料理
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public CookBonus? CookBonus { get; set; }
|
public CookBonus? CookBonus2 { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 好感语音
|
/// 好感语音
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Model.Calculable;
|
||||||
using Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate;
|
using Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate;
|
||||||
|
|
||||||
namespace Snap.Hutao.Model.Metadata.Avatar;
|
namespace Snap.Hutao.Model.Metadata.Avatar;
|
||||||
|
|||||||
@@ -80,6 +80,8 @@ public static class AvatarIds
|
|||||||
public static readonly AvatarId Layla = 10000074;
|
public static readonly AvatarId Layla = 10000074;
|
||||||
public static readonly AvatarId Wanderer = 10000075;
|
public static readonly AvatarId Wanderer = 10000075;
|
||||||
public static readonly AvatarId Faruzan = 10000076;
|
public static readonly AvatarId Faruzan = 10000076;
|
||||||
|
public static readonly AvatarId Yaoyao = 10000077;
|
||||||
|
public static readonly AvatarId Alhaitham = 10000078;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 检查该角色是否为主角
|
/// 检查该角色是否为主角
|
||||||
|
|||||||
@@ -12,9 +12,19 @@ internal class AchievementIconConverter : ValueConverterBase<string, Uri>
|
|||||||
{
|
{
|
||||||
private const string BaseUrl = "https://static.snapgenshin.com/AchievementIcon/{0}.png";
|
private const string BaseUrl = "https://static.snapgenshin.com/AchievementIcon/{0}.png";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 名称转Uri
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">名称</param>
|
||||||
|
/// <returns>链接</returns>
|
||||||
|
public static Uri IconNameToUri(string name)
|
||||||
|
{
|
||||||
|
return new Uri(string.Format(BaseUrl, name));
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override Uri Convert(string from)
|
public override Uri Convert(string from)
|
||||||
{
|
{
|
||||||
return new Uri(string.Format(BaseUrl, from));
|
return IconNameToUri(from);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Control;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Model.Metadata.Converter;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 角色卡片转换器
|
||||||
|
/// </summary>
|
||||||
|
internal class AvatarCardConverter : ValueConverterBase<string, Uri>
|
||||||
|
{
|
||||||
|
private const string BaseUrl = "https://static.snapgenshin.com/AvatarCard/{0}_Card.png";
|
||||||
|
|
||||||
|
private static readonly Uri UIAvatarIconCostumeCard = new("https://static.snapgenshin.com/AvatarCard/UI_AvatarIcon_Costume_Card.png");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 名称转Uri
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">名称</param>
|
||||||
|
/// <returns>链接</returns>
|
||||||
|
public static Uri IconNameToUri(string name)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(name))
|
||||||
|
{
|
||||||
|
return UIAvatarIconCostumeCard;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Uri(string.Format(BaseUrl, name));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override Uri Convert(string from)
|
||||||
|
{
|
||||||
|
return IconNameToUri(from);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using Snap.Hutao.Control;
|
using Snap.Hutao.Control;
|
||||||
using Snap.Hutao.Control.Image;
|
using Snap.Hutao.Control.Media;
|
||||||
using Snap.Hutao.Model.Intrinsic;
|
using Snap.Hutao.Model.Intrinsic;
|
||||||
|
|
||||||
namespace Snap.Hutao.Model.Metadata.Converter;
|
namespace Snap.Hutao.Model.Metadata.Converter;
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ internal class ItemIconConverter : ValueConverterBase<string, Uri>
|
|||||||
{
|
{
|
||||||
private const string BaseUrl = "https://static.snapgenshin.com/ItemIcon/{0}.png";
|
private const string BaseUrl = "https://static.snapgenshin.com/ItemIcon/{0}.png";
|
||||||
|
|
||||||
|
private static readonly Uri UIItemIconNone = new("https://static.snapgenshin.com/Bg/UI_ItemIcon_None.png");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 名称转Uri
|
/// 名称转Uri
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -105,4 +105,4 @@ internal class PropertyInfoDescriptor : ValueConverterBase<PropertyInfo, IList<L
|
|||||||
|
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using Snap.Hutao.Model.Intrinsic;
|
|
||||||
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
||||||
|
|
||||||
namespace Snap.Hutao.Model.Metadata;
|
namespace Snap.Hutao.Model.Metadata;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using Snap.Hutao.Model.Intrinsic;
|
using Snap.Hutao.Model.Intrinsic;
|
||||||
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
using Snap.Hutao.Model.Primitive;
|
||||||
|
|
||||||
namespace Snap.Hutao.Model.Metadata;
|
namespace Snap.Hutao.Model.Metadata;
|
||||||
|
|
||||||
@@ -14,7 +14,7 @@ public class Material
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 物品Id
|
/// 物品Id
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Id { get; set; }
|
public MaterialId Id { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 等级
|
/// 等级
|
||||||
@@ -26,6 +26,11 @@ public class Material
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public ItemType ItemType { get; set; }
|
public ItemType ItemType { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 材料类型
|
||||||
|
/// </summary>
|
||||||
|
public MaterialType MaterialType { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 图标
|
/// 图标
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -45,4 +50,9 @@ public class Material
|
|||||||
/// 类型描述
|
/// 类型描述
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string TypeDescription { get; set; } = default!;
|
public string TypeDescription { get; set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 效果描述
|
||||||
|
/// </summary>
|
||||||
|
public string? EffectDescription { get; set; }
|
||||||
}
|
}
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
using Snap.Hutao.Model.Binding.Gacha;
|
using Snap.Hutao.Model.Binding.Gacha;
|
||||||
using Snap.Hutao.Model.Binding.Gacha.Abstraction;
|
using Snap.Hutao.Model.Binding.Gacha.Abstraction;
|
||||||
using Snap.Hutao.Model.Binding.Hutao;
|
using Snap.Hutao.Model.Binding.Hutao;
|
||||||
|
using Snap.Hutao.Model.Calculable;
|
||||||
using Snap.Hutao.Model.Intrinsic;
|
using Snap.Hutao.Model.Intrinsic;
|
||||||
using Snap.Hutao.Model.Metadata.Abstraction;
|
using Snap.Hutao.Model.Metadata.Abstraction;
|
||||||
using Snap.Hutao.Model.Metadata.Converter;
|
using Snap.Hutao.Model.Metadata.Converter;
|
||||||
|
|||||||
71
src/Snap.Hutao/Snap.Hutao/Model/Primitive/MaterialId.cs
Normal file
71
src/Snap.Hutao/Snap.Hutao/Model/Primitive/MaterialId.cs
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Model.Primitive.Converter;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Model.Primitive;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 3-6位 材料Id
|
||||||
|
/// </summary>
|
||||||
|
[JsonConverter(typeof(IdentityConverter<MaterialId>))]
|
||||||
|
public readonly struct MaterialId : IEquatable<MaterialId>, IComparable<MaterialId>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 值
|
||||||
|
/// </summary>
|
||||||
|
public readonly int Value;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="MaterialId"/> struct.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">value</param>
|
||||||
|
public MaterialId(int value)
|
||||||
|
{
|
||||||
|
Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static implicit operator int(MaterialId value)
|
||||||
|
{
|
||||||
|
return value.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static implicit operator MaterialId(int value)
|
||||||
|
{
|
||||||
|
return new(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(MaterialId left, MaterialId right)
|
||||||
|
{
|
||||||
|
return left.Value == right.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator !=(MaterialId left, MaterialId right)
|
||||||
|
{
|
||||||
|
return !(left == right);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public int CompareTo(MaterialId other)
|
||||||
|
{
|
||||||
|
return Value.CompareTo(other.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public bool Equals(MaterialId other)
|
||||||
|
{
|
||||||
|
return Value == other.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override bool Equals(object? obj)
|
||||||
|
{
|
||||||
|
return obj is MaterialId other && Equals(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return Value.GetHashCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -62,4 +62,4 @@ public readonly struct WeaponId : IEquatable<WeaponId>
|
|||||||
{
|
{
|
||||||
return Value.GetHashCode();
|
return Value.GetHashCode();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
<Identity
|
<Identity
|
||||||
Name="7f0db578-026f-4e0b-a75b-d5d06bb0a74d"
|
Name="7f0db578-026f-4e0b-a75b-d5d06bb0a74d"
|
||||||
Publisher="CN=DGP Studio"
|
Publisher="CN=DGP Studio"
|
||||||
Version="1.2.12.0" />
|
Version="1.2.19.0" />
|
||||||
|
|
||||||
<Properties>
|
<Properties>
|
||||||
<DisplayName>胡桃</DisplayName>
|
<DisplayName>胡桃</DisplayName>
|
||||||
|
|||||||
@@ -66,9 +66,7 @@ public static partial class Program
|
|||||||
ServiceProvider services = new ServiceCollection()
|
ServiceProvider services = new ServiceCollection()
|
||||||
|
|
||||||
// Microsoft extension
|
// Microsoft extension
|
||||||
.AddLogging(builder => builder
|
.AddLogging(builder => builder.AddDebug().AddDatabase())
|
||||||
.AddDebug()
|
|
||||||
.AddDatabase())
|
|
||||||
.AddMemoryCache()
|
.AddMemoryCache()
|
||||||
|
|
||||||
// Hutao extensions
|
// Hutao extensions
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ using Snap.Hutao.Core.Diagnostics;
|
|||||||
using Snap.Hutao.Core.Logging;
|
using Snap.Hutao.Core.Logging;
|
||||||
using Snap.Hutao.Model.InterChange.Achievement;
|
using Snap.Hutao.Model.InterChange.Achievement;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using BindingAchievement = Snap.Hutao.Model.Binding.Achievement;
|
using BindingAchievement = Snap.Hutao.Model.Binding.Achievement.Achievement;
|
||||||
using EntityAchievement = Snap.Hutao.Model.Entity.Achievement;
|
using EntityAchievement = Snap.Hutao.Model.Entity.Achievement;
|
||||||
using EntityArchive = Snap.Hutao.Model.Entity.AchievementArchive;
|
using EntityArchive = Snap.Hutao.Model.Entity.AchievementArchive;
|
||||||
using MetadataAchievement = Snap.Hutao.Model.Metadata.Achievement.Achievement;
|
using MetadataAchievement = Snap.Hutao.Model.Metadata.Achievement.Achievement;
|
||||||
@@ -22,6 +22,7 @@ namespace Snap.Hutao.Service.Achievement;
|
|||||||
[Injection(InjectAs.Scoped, typeof(IAchievementService))]
|
[Injection(InjectAs.Scoped, typeof(IAchievementService))]
|
||||||
internal class AchievementService : IAchievementService
|
internal class AchievementService : IAchievementService
|
||||||
{
|
{
|
||||||
|
private readonly object saveAchievementLocker = new();
|
||||||
private readonly AppDbContext appDbContext;
|
private readonly AppDbContext appDbContext;
|
||||||
private readonly ILogger<AchievementService> logger;
|
private readonly ILogger<AchievementService> logger;
|
||||||
private readonly DbCurrent<EntityArchive, Message.AchievementArchiveChangedMessage> dbCurrent;
|
private readonly DbCurrent<EntityArchive, Message.AchievementArchiveChangedMessage> dbCurrent;
|
||||||
@@ -187,4 +188,19 @@ internal class AchievementService : IAchievementService
|
|||||||
logger.LogInformation(EventIds.Achievement, "{add} added, {update} updated, {remove} removed", result.Add, result.Update, result.Remove);
|
logger.LogInformation(EventIds.Achievement, "{add} added, {update} updated, {remove} removed", result.Add, result.Update, result.Remove);
|
||||||
logger.LogInformation(EventIds.Achievement, "Save achievements for [{name}] completed in {time}ms", name, time);
|
logger.LogInformation(EventIds.Achievement, "Save achievements for [{name}] completed in {time}ms", name, time);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public void SaveAchievement(BindingAchievement achievement)
|
||||||
|
{
|
||||||
|
if (achievement.IsChecked)
|
||||||
|
{
|
||||||
|
// set to default allow multiple time add
|
||||||
|
achievement.Entity.InnerId = default;
|
||||||
|
appDbContext.Achievements.UpdateAndSave(achievement.Entity);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
appDbContext.Achievements.RemoveAndSave(achievement.Entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using Snap.Hutao.Core.Threading.CodeAnalysis;
|
|
||||||
using Snap.Hutao.Model.InterChange.Achievement;
|
using Snap.Hutao.Model.InterChange.Achievement;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using BindingAchievement = Snap.Hutao.Model.Binding.Achievement;
|
using BindingAchievement = Snap.Hutao.Model.Binding.Achievement.Achievement;
|
||||||
using EntityArchive = Snap.Hutao.Model.Entity.AchievementArchive;
|
using EntityArchive = Snap.Hutao.Model.Entity.AchievementArchive;
|
||||||
using MetadataAchievement = Snap.Hutao.Model.Metadata.Achievement.Achievement;
|
using MetadataAchievement = Snap.Hutao.Model.Metadata.Achievement.Achievement;
|
||||||
|
|
||||||
@@ -57,6 +56,12 @@ internal interface IAchievementService
|
|||||||
/// <returns>任务</returns>
|
/// <returns>任务</returns>
|
||||||
Task RemoveArchiveAsync(EntityArchive archive);
|
Task RemoveArchiveAsync(EntityArchive archive);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 保存单个成就
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="achievement">成就</param>
|
||||||
|
void SaveAchievement(BindingAchievement achievement);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 保存成就
|
/// 保存成就
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -69,6 +74,5 @@ internal interface IAchievementService
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="newArchive">新存档</param>
|
/// <param name="newArchive">新存档</param>
|
||||||
/// <returns>存档添加结果</returns>
|
/// <returns>存档添加结果</returns>
|
||||||
[ThreadAccess(ThreadAccessState.AnyThread)]
|
|
||||||
Task<ArchiveAddResult> TryAddArchiveAsync(EntityArchive newArchive);
|
Task<ArchiveAddResult> TryAddArchiveAsync(EntityArchive newArchive);
|
||||||
}
|
}
|
||||||
@@ -15,28 +15,38 @@ internal class AffixWeight : Dictionary<FightProperty, double>
|
|||||||
/// 构造一个新的词条权重
|
/// 构造一个新的词条权重
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="avatarId">角色Id</param>
|
/// <param name="avatarId">角色Id</param>
|
||||||
/// <param name="hp">大生命</param>
|
/// <param name="hpPercent">大生命</param>
|
||||||
/// <param name="atk">大攻击</param>
|
/// <param name="attackPercenr">大攻击</param>
|
||||||
/// <param name="def">大防御</param>
|
/// <param name="defensePercent">大防御</param>
|
||||||
/// <param name="cr">暴击率</param>
|
/// <param name="critical">暴击率</param>
|
||||||
/// <param name="ch">暴击伤害</param>
|
/// <param name="criticalHurt">暴击伤害</param>
|
||||||
/// <param name="em">元素精通</param>
|
/// <param name="elementMastery">元素精通</param>
|
||||||
/// <param name="ce">充能效率</param>
|
/// <param name="chargeEfficiency">充能效率</param>
|
||||||
/// <param name="ha">治疗加成</param>
|
/// <param name="healAdd">治疗加成</param>
|
||||||
/// <param name="name">名称</param>
|
/// <param name="name">名称</param>
|
||||||
public AffixWeight(int avatarId, double hp, double atk, double def, double cr, double ch, double em, double ce, double ha, string name = "通用")
|
public AffixWeight(
|
||||||
|
int avatarId,
|
||||||
|
double hpPercent,
|
||||||
|
double attackPercenr,
|
||||||
|
double defensePercent,
|
||||||
|
double critical,
|
||||||
|
double criticalHurt,
|
||||||
|
double elementMastery,
|
||||||
|
double chargeEfficiency,
|
||||||
|
double healAdd,
|
||||||
|
string name = "通用")
|
||||||
{
|
{
|
||||||
AvatarId = avatarId;
|
AvatarId = avatarId;
|
||||||
Name = name;
|
Name = name;
|
||||||
|
|
||||||
this[FightProperty.FIGHT_PROP_HP_PERCENT] = hp;
|
this[FightProperty.FIGHT_PROP_HP_PERCENT] = hpPercent;
|
||||||
this[FightProperty.FIGHT_PROP_ATTACK_PERCENT] = atk;
|
this[FightProperty.FIGHT_PROP_ATTACK_PERCENT] = attackPercenr;
|
||||||
this[FightProperty.FIGHT_PROP_DEFENSE_PERCENT] = def;
|
this[FightProperty.FIGHT_PROP_DEFENSE_PERCENT] = defensePercent;
|
||||||
this[FightProperty.FIGHT_PROP_CRITICAL] = cr;
|
this[FightProperty.FIGHT_PROP_CRITICAL] = critical;
|
||||||
this[FightProperty.FIGHT_PROP_CRITICAL_HURT] = ch;
|
this[FightProperty.FIGHT_PROP_CRITICAL_HURT] = criticalHurt;
|
||||||
this[FightProperty.FIGHT_PROP_ELEMENT_MASTERY] = em;
|
this[FightProperty.FIGHT_PROP_ELEMENT_MASTERY] = elementMastery;
|
||||||
this[FightProperty.FIGHT_PROP_CHARGE_EFFICIENCY] = ce;
|
this[FightProperty.FIGHT_PROP_CHARGE_EFFICIENCY] = chargeEfficiency;
|
||||||
this[FightProperty.FIGHT_PROP_HEAL_ADD] = ha;
|
this[FightProperty.FIGHT_PROP_HEAL_ADD] = healAdd;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -48,4 +58,92 @@ internal class AffixWeight : Dictionary<FightProperty, double>
|
|||||||
/// 名称
|
/// 名称
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Name { get; }
|
public string Name { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 风元素伤害加成
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">值</param>
|
||||||
|
/// <returns>链式调用对象</returns>
|
||||||
|
public AffixWeight Anemo(double value = 100)
|
||||||
|
{
|
||||||
|
this[FightProperty.FIGHT_PROP_WIND_ADD_HURT] = value;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 冰元素伤害加成
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">值</param>
|
||||||
|
/// <returns>链式调用对象</returns>
|
||||||
|
public AffixWeight Cryo(double value = 100)
|
||||||
|
{
|
||||||
|
this[FightProperty.FIGHT_PROP_ICE_ADD_HURT] = value;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 草元素伤害加成
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">值</param>
|
||||||
|
/// <returns>链式调用对象</returns>
|
||||||
|
public AffixWeight Dendro(double value = 100)
|
||||||
|
{
|
||||||
|
this[FightProperty.FIGHT_PROP_GRASS_ADD_HURT] = value;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 雷元素伤害加成
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">值</param>
|
||||||
|
/// <returns>链式调用对象</returns>
|
||||||
|
public AffixWeight Electro(double value = 100)
|
||||||
|
{
|
||||||
|
this[FightProperty.FIGHT_PROP_ELEC_ADD_HURT] = value;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 岩元素伤害加成
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">值</param>
|
||||||
|
/// <returns>链式调用对象</returns>
|
||||||
|
public AffixWeight Geo(double value = 100)
|
||||||
|
{
|
||||||
|
this[FightProperty.FIGHT_PROP_ROCK_ADD_HURT] = value;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 水元素伤害加成
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">值</param>
|
||||||
|
/// <returns>链式调用对象</returns>
|
||||||
|
public AffixWeight Hydro(double value = 100)
|
||||||
|
{
|
||||||
|
this[FightProperty.FIGHT_PROP_WATER_ADD_HURT] = value;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 火元素伤害加成
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">值</param>
|
||||||
|
/// <returns>链式调用对象</returns>
|
||||||
|
public AffixWeight Pyro(double value = 100)
|
||||||
|
{
|
||||||
|
this[FightProperty.FIGHT_PROP_FIRE_ADD_HURT] = value;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 物理伤害伤害加成
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">值</param>
|
||||||
|
/// <returns>链式调用对象</returns>
|
||||||
|
public AffixWeight Phyiscal(double value = 100)
|
||||||
|
{
|
||||||
|
this[FightProperty.FIGHT_PROP_PHYSICAL_ADD_HURT] = value;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using Snap.Hutao.Model.Intrinsic;
|
|
||||||
using Snap.Hutao.Model.Metadata;
|
using Snap.Hutao.Model.Metadata;
|
||||||
|
|
||||||
namespace Snap.Hutao.Service.AvatarInfo.Factory;
|
namespace Snap.Hutao.Service.AvatarInfo.Factory;
|
||||||
@@ -14,74 +13,74 @@ internal static partial class ReliquaryWeightConfiguration
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 默认
|
/// 默认
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static readonly AffixWeight Default = new(0, 100, 75, 0, 100, 100, 0, 55, 0) { { FightProperty.FIGHT_PROP_WATER_ADD_HURT, 100 } };
|
public static readonly AffixWeight Default = new(0, 100, 75, 0, 100, 100, 0, 55, 0);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 词条权重
|
/// 词条权重
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static readonly List<AffixWeight> AffixWeights = new()
|
public static readonly List<AffixWeight> AffixWeights = new()
|
||||||
{
|
{
|
||||||
new(AvatarIds.Ayaka, 0, 75, 0, 100, 100, 0, 0, 0) { { FightProperty.FIGHT_PROP_ICE_ADD_HURT, 100 } },
|
new AffixWeight(AvatarIds.Ayaka, 0, 75, 0, 100, 100, 0, 0, 0).Cryo(),
|
||||||
new(AvatarIds.Qin, 0, 75, 0, 100, 100, 0, 55, 100) { { FightProperty.FIGHT_PROP_WIND_ADD_HURT, 100 } },
|
new AffixWeight(AvatarIds.Qin, 0, 75, 0, 100, 100, 0, 55, 100).Anemo(),
|
||||||
new(AvatarIds.Lisa, 0, 75, 0, 100, 100, 75, 0, 0) { { FightProperty.FIGHT_PROP_ELEC_ADD_HURT, 100 } },
|
new AffixWeight(AvatarIds.Lisa, 0, 75, 0, 100, 100, 75, 0, 0).Electro(),
|
||||||
new(AvatarIds.Barbara, 100, 50, 0, 50, 50, 0, 55, 100) { { FightProperty.FIGHT_PROP_WATER_ADD_HURT, 80 } },
|
new AffixWeight(AvatarIds.Barbara, 100, 50, 0, 50, 50, 0, 55, 100).Hydro(80),
|
||||||
new(AvatarIds.Barbara, 50, 75, 0, 100, 100, 0, 55, 100, "暴力奶妈") { { FightProperty.FIGHT_PROP_WIND_ADD_HURT, 100 } },
|
new AffixWeight(AvatarIds.Barbara, 50, 75, 0, 100, 100, 0, 55, 100, "暴力奶妈").Hydro(),
|
||||||
new(AvatarIds.Kaeya, 0, 75, 0, 100, 100, 0, 0, 0) { { FightProperty.FIGHT_PROP_ICE_ADD_HURT, 100 } },
|
new AffixWeight(AvatarIds.Kaeya, 0, 75, 0, 100, 100, 0, 0, 0).Cryo(),
|
||||||
new(AvatarIds.Diluc, 0, 75, 0, 100, 100, 75, 0, 0) { { FightProperty.FIGHT_PROP_FIRE_ADD_HURT, 100 } },
|
new AffixWeight(AvatarIds.Diluc, 0, 75, 0, 100, 100, 75, 0, 0).Pyro(),
|
||||||
new(AvatarIds.Razor, 0, 75, 0, 100, 100, 0, 0, 0) { { FightProperty.FIGHT_PROP_ELEC_ADD_HURT, 50 }, { FightProperty.FIGHT_PROP_PHYSICAL_ADD_HURT, 100 } },
|
new AffixWeight(AvatarIds.Razor, 0, 75, 0, 100, 100, 0, 0, 0).Electro(50).Phyiscal(),
|
||||||
new(AvatarIds.Ambor, 0, 75, 0, 100, 100, 75, 0, 0) { { FightProperty.FIGHT_PROP_FIRE_ADD_HURT, 100 } },
|
new AffixWeight(AvatarIds.Ambor, 0, 75, 0, 100, 100, 75, 0, 0).Pyro(),
|
||||||
new(AvatarIds.Venti, 0, 75, 0, 100, 100, 75, 55, 0) { { FightProperty.FIGHT_PROP_WIND_ADD_HURT, 100 } },
|
new AffixWeight(AvatarIds.Venti, 0, 75, 0, 100, 100, 75, 55, 0).Anemo(),
|
||||||
new(AvatarIds.Xiangling, 0, 75, 0, 100, 100, 75, 55, 0) { { FightProperty.FIGHT_PROP_FIRE_ADD_HURT, 100 } },
|
new AffixWeight(AvatarIds.Xiangling, 0, 75, 0, 100, 100, 75, 55, 0).Pyro(),
|
||||||
new(AvatarIds.Beidou, 0, 75, 0, 100, 100, 75, 55, 0) { { FightProperty.FIGHT_PROP_ELEC_ADD_HURT, 100 } },
|
new AffixWeight(AvatarIds.Beidou, 0, 75, 0, 100, 100, 75, 55, 0).Electro(),
|
||||||
new(AvatarIds.Xingqiu, 0, 75, 0, 100, 100, 0, 75, 0) { { FightProperty.FIGHT_PROP_WATER_ADD_HURT, 100 } },
|
new AffixWeight(AvatarIds.Xingqiu, 0, 75, 0, 100, 100, 0, 75, 0).Hydro(),
|
||||||
new(AvatarIds.Xiao, 0, 75, 0, 100, 100, 0, 55, 0) { { FightProperty.FIGHT_PROP_WIND_ADD_HURT, 100 } },
|
new AffixWeight(AvatarIds.Xiao, 0, 75, 0, 100, 100, 0, 55, 0).Anemo(),
|
||||||
new(AvatarIds.Ningguang, 0, 75, 0, 100, 100, 0, 30, 0) { { FightProperty.FIGHT_PROP_ROCK_ADD_HURT, 100 } },
|
new AffixWeight(AvatarIds.Ningguang, 0, 75, 0, 100, 100, 0, 30, 0).Geo(),
|
||||||
new(AvatarIds.Klee, 0, 75, 0, 100, 100, 75, 0, 0) { { FightProperty.FIGHT_PROP_FIRE_ADD_HURT, 100 } },
|
new AffixWeight(AvatarIds.Klee, 0, 75, 0, 100, 100, 75, 0, 0).Pyro(),
|
||||||
new(AvatarIds.Zhongli, 80, 75, 0, 100, 100, 0, 55, 0, "武神钟离") { { FightProperty.FIGHT_PROP_ROCK_ADD_HURT, 100 }, { FightProperty.FIGHT_PROP_PHYSICAL_ADD_HURT, 50 } },
|
new AffixWeight(AvatarIds.Zhongli, 80, 75, 0, 100, 100, 0, 55, 0, "武神钟离").Geo().Phyiscal(50),
|
||||||
new(AvatarIds.Zhongli, 100, 55, 0, 100, 100, 0, 55, 0, "血牛钟离") { { FightProperty.FIGHT_PROP_ROCK_ADD_HURT, 75 } },
|
new AffixWeight(AvatarIds.Zhongli, 100, 55, 0, 100, 100, 0, 55, 0, "血牛钟离").Geo(75),
|
||||||
new(AvatarIds.Zhongli, 100, 55, 0, 100, 100, 0, 75, 0, "血牛钟离(2命+)") { { FightProperty.FIGHT_PROP_ROCK_ADD_HURT, 75 } },
|
new AffixWeight(AvatarIds.Zhongli, 100, 55, 0, 100, 100, 0, 75, 0, "血牛钟离(2命+)").Geo(75),
|
||||||
new(AvatarIds.Fischl, 0, 75, 0, 100, 100, 0, 0, 0) { { FightProperty.FIGHT_PROP_ELEC_ADD_HURT, 100 } },
|
new AffixWeight(AvatarIds.Fischl, 0, 75, 0, 100, 100, 0, 0, 0).Electro(),
|
||||||
new(AvatarIds.Bennett, 100, 50, 0, 100, 100, 0, 55, 100) { { FightProperty.FIGHT_PROP_FIRE_ADD_HURT, 70 } },
|
new AffixWeight(AvatarIds.Bennett, 100, 50, 0, 100, 100, 0, 55, 100).Pyro(70),
|
||||||
new(AvatarIds.Tartaglia, 0, 75, 0, 100, 100, 75, 0, 0) { { FightProperty.FIGHT_PROP_WATER_ADD_HURT, 100 } },
|
new AffixWeight(AvatarIds.Tartaglia, 0, 75, 0, 100, 100, 75, 0, 0).Hydro(),
|
||||||
new(AvatarIds.Noel, 0, 50, 90, 100, 100, 0, 70, 0) { { FightProperty.FIGHT_PROP_ROCK_ADD_HURT, 100 } },
|
new AffixWeight(AvatarIds.Noel, 0, 50, 90, 100, 100, 0, 70, 0).Geo(),
|
||||||
new(AvatarIds.Qiqi, 0, 100, 0, 100, 100, 0, 55, 100) { { FightProperty.FIGHT_PROP_ICE_ADD_HURT, 60 } },
|
new AffixWeight(AvatarIds.Qiqi, 0, 100, 0, 100, 100, 0, 55, 100).Cryo(60),
|
||||||
new(AvatarIds.Chongyun, 0, 75, 0, 100, 100, 75, 55, 0) { { FightProperty.FIGHT_PROP_ICE_ADD_HURT, 100 } },
|
new AffixWeight(AvatarIds.Chongyun, 0, 75, 0, 100, 100, 75, 55, 0).Cryo(),
|
||||||
new(AvatarIds.Ganyu, 0, 75, 0, 100, 100, 75, 0, 0, "融化流") { { FightProperty.FIGHT_PROP_ICE_ADD_HURT, 100 } },
|
new AffixWeight(AvatarIds.Ganyu, 0, 75, 0, 100, 100, 75, 0, 0, "融化流").Cryo(),
|
||||||
new(AvatarIds.Ganyu, 0, 75, 0, 100, 100, 0, 55, 0, "永冻流") { { FightProperty.FIGHT_PROP_ICE_ADD_HURT, 100 } },
|
new AffixWeight(AvatarIds.Ganyu, 0, 75, 0, 100, 100, 0, 55, 0, "永冻流").Cryo(),
|
||||||
new(AvatarIds.Albedo, 0, 0, 100, 100, 100, 0, 0, 0) { { FightProperty.FIGHT_PROP_ROCK_ADD_HURT, 100 } },
|
new AffixWeight(AvatarIds.Albedo, 0, 0, 100, 100, 100, 0, 0, 0).Geo(),
|
||||||
new(AvatarIds.Diona, 100, 50, 0, 50, 50, 0, 90, 100) { { FightProperty.FIGHT_PROP_ICE_ADD_HURT, 100 } },
|
new AffixWeight(AvatarIds.Diona, 100, 50, 0, 50, 50, 0, 90, 100).Cryo(),
|
||||||
new(AvatarIds.Mona, 0, 75, 0, 100, 100, 75, 75, 0) { { FightProperty.FIGHT_PROP_WATER_ADD_HURT, 100 } },
|
new AffixWeight(AvatarIds.Mona, 0, 75, 0, 100, 100, 75, 75, 0).Hydro(),
|
||||||
new(AvatarIds.Keqing, 0, 75, 0, 100, 100, 0, 0, 0) { { FightProperty.FIGHT_PROP_ELEC_ADD_HURT, 100 }, { FightProperty.FIGHT_PROP_PHYSICAL_ADD_HURT, 100 } },
|
new AffixWeight(AvatarIds.Keqing, 0, 75, 0, 100, 100, 0, 0, 0).Electro().Phyiscal(),
|
||||||
new(AvatarIds.Sucrose, 0, 75, 0, 100, 100, 100, 55, 0) { { FightProperty.FIGHT_PROP_WIND_ADD_HURT, 40 } },
|
new AffixWeight(AvatarIds.Sucrose, 0, 75, 0, 100, 100, 100, 55, 0).Anemo(40),
|
||||||
new(AvatarIds.Xinyan, 0, 75, 0, 100, 100, 0, 0, 0) { { FightProperty.FIGHT_PROP_FIRE_ADD_HURT, 50 } },
|
new AffixWeight(AvatarIds.Xinyan, 0, 75, 0, 100, 100, 0, 0, 0).Pyro(50),
|
||||||
new(AvatarIds.Rosaria, 0, 75, 0, 100, 100, 0, 0, 0) { { FightProperty.FIGHT_PROP_ICE_ADD_HURT, 70 }, { FightProperty.FIGHT_PROP_PHYSICAL_ADD_HURT, 80 } },
|
new AffixWeight(AvatarIds.Rosaria, 0, 75, 0, 100, 100, 0, 0, 0).Cryo(70).Phyiscal(80),
|
||||||
new(AvatarIds.Hutao, 80, 50, 0, 100, 100, 75, 0, 0) { { FightProperty.FIGHT_PROP_FIRE_ADD_HURT, 100 } },
|
new AffixWeight(AvatarIds.Hutao, 80, 50, 0, 100, 100, 75, 0, 0).Pyro(),
|
||||||
new(AvatarIds.Kazuha, 0, 75, 0, 100, 100, 100, 55, 0) { { FightProperty.FIGHT_PROP_WIND_ADD_HURT, 100 } },
|
new AffixWeight(AvatarIds.Kazuha, 0, 75, 0, 100, 100, 100, 55, 0).Anemo(),
|
||||||
new(AvatarIds.Feiyan, 0, 75, 0, 100, 100, 75, 0, 0) { { FightProperty.FIGHT_PROP_FIRE_ADD_HURT, 100 } },
|
new AffixWeight(AvatarIds.Feiyan, 0, 75, 0, 100, 100, 75, 0, 0).Pyro(),
|
||||||
new(AvatarIds.Yoimiya, 0, 75, 0, 100, 100, 75, 0, 0) { { FightProperty.FIGHT_PROP_FIRE_ADD_HURT, 100 } },
|
new AffixWeight(AvatarIds.Yoimiya, 0, 75, 0, 100, 100, 75, 0, 0).Pyro(),
|
||||||
new(AvatarIds.Tohma, 100, 50, 0, 50, 50, 0, 90, 0) { { FightProperty.FIGHT_PROP_FIRE_ADD_HURT, 75 } },
|
new AffixWeight(AvatarIds.Tohma, 100, 50, 0, 50, 50, 0, 90, 0).Pyro(75),
|
||||||
new(AvatarIds.Eula, 0, 75, 0, 100, 100, 0, 55, 0) { { FightProperty.FIGHT_PROP_ICE_ADD_HURT, 40 }, { FightProperty.FIGHT_PROP_PHYSICAL_ADD_HURT, 100 } },
|
new AffixWeight(AvatarIds.Eula, 0, 75, 0, 100, 100, 0, 55, 0).Cryo(40).Phyiscal(100),
|
||||||
new(AvatarIds.Shougun, 0, 75, 0, 100, 100, 0, 90, 0) { { FightProperty.FIGHT_PROP_ELEC_ADD_HURT, 75 } },
|
new AffixWeight(AvatarIds.Shougun, 0, 75, 0, 100, 100, 0, 90, 0).Electro(75),
|
||||||
new(AvatarIds.Sayu, 0, 50, 0, 50, 50, 100, 55, 100) { { FightProperty.FIGHT_PROP_WIND_ADD_HURT, 80 } },
|
new AffixWeight(AvatarIds.Sayu, 0, 50, 0, 50, 50, 100, 55, 100).Anemo(80),
|
||||||
new(AvatarIds.Kokomi, 100, 50, 0, 0, 0, 0, 55, 100) { { FightProperty.FIGHT_PROP_WATER_ADD_HURT, 100 } },
|
new AffixWeight(AvatarIds.Kokomi, 100, 50, 0, 0, 0, 0, 55, 100).Hydro(),
|
||||||
new(AvatarIds.Gorou, 0, 50, 100, 50, 50, 0, 90, 0) { { FightProperty.FIGHT_PROP_ROCK_ADD_HURT, 25 } },
|
new AffixWeight(AvatarIds.Gorou, 0, 50, 100, 50, 50, 0, 90, 0).Geo(25),
|
||||||
new(AvatarIds.Sara, 0, 75, 0, 100, 100, 0, 55, 0) { { FightProperty.FIGHT_PROP_ELEC_ADD_HURT, 100 } },
|
new AffixWeight(AvatarIds.Sara, 0, 75, 0, 100, 100, 0, 55, 0).Electro(),
|
||||||
new(AvatarIds.Itto, 0, 50, 100, 100, 100, 0, 30, 0) { { FightProperty.FIGHT_PROP_ROCK_ADD_HURT, 100 } },
|
new AffixWeight(AvatarIds.Itto, 0, 50, 100, 100, 100, 0, 30, 0).Geo(),
|
||||||
new(AvatarIds.Yae, 0, 75, 0, 100, 100, 75, 55, 0) { { FightProperty.FIGHT_PROP_ELEC_ADD_HURT, 100 } },
|
new AffixWeight(AvatarIds.Yae, 0, 75, 0, 100, 100, 75, 55, 0).Electro(),
|
||||||
new(AvatarIds.Heizou, 0, 75, 0, 100, 100, 75, 0, 0) { { FightProperty.FIGHT_PROP_WIND_ADD_HURT, 100 } },
|
new AffixWeight(AvatarIds.Heizou, 0, 75, 0, 100, 100, 75, 0, 0).Anemo(),
|
||||||
new(AvatarIds.Yelan, 80, 0, 0, 100, 100, 0, 75, 0) { { FightProperty.FIGHT_PROP_WATER_ADD_HURT, 100 } },
|
new AffixWeight(AvatarIds.Yelan, 80, 0, 0, 100, 100, 0, 75, 0).Hydro(),
|
||||||
new(AvatarIds.Aloy, 0, 75, 0, 100, 100, 0, 0, 0) { { FightProperty.FIGHT_PROP_ICE_ADD_HURT, 100 } },
|
new AffixWeight(AvatarIds.Aloy, 0, 75, 0, 100, 100, 0, 0, 0).Cryo(),
|
||||||
new(AvatarIds.Shenhe, 0, 100, 0, 100, 100, 0, 55, 0) { { FightProperty.FIGHT_PROP_ICE_ADD_HURT, 100 } },
|
new AffixWeight(AvatarIds.Shenhe, 0, 100, 0, 100, 100, 0, 55, 0).Cryo(),
|
||||||
new(AvatarIds.Yunjin, 0, 0, 100, 50, 50, 0, 90, 0) { { FightProperty.FIGHT_PROP_ROCK_ADD_HURT, 25 } },
|
new AffixWeight(AvatarIds.Yunjin, 0, 0, 100, 50, 50, 0, 90, 0).Geo(25),
|
||||||
new(AvatarIds.Shinobu, 100, 50, 0, 100, 100, 75, 55, 100) { { FightProperty.FIGHT_PROP_ELEC_ADD_HURT, 100 } },
|
new AffixWeight(AvatarIds.Shinobu, 100, 50, 0, 100, 100, 75, 55, 100).Electro(),
|
||||||
new(AvatarIds.Ayato, 50, 75, 0, 100, 100, 0, 0, 0) { { FightProperty.FIGHT_PROP_WATER_ADD_HURT, 100 } },
|
new AffixWeight(AvatarIds.Ayato, 50, 75, 0, 100, 100, 0, 0, 0).Hydro(),
|
||||||
new(AvatarIds.Collei, 0, 75, 0, 100, 100, 0, 55, 0) { { FightProperty.FIGHT_PROP_GRASS_ADD_HURT, 100 } },
|
new AffixWeight(AvatarIds.Collei, 0, 75, 0, 100, 100, 0, 55, 0).Dendro(),
|
||||||
new(AvatarIds.Dori, 100, 75, 0, 100, 100, 0, 55, 0) { { FightProperty.FIGHT_PROP_ELEC_ADD_HURT, 100 } },
|
new AffixWeight(AvatarIds.Dori, 100, 75, 0, 100, 100, 0, 55, 0).Electro(),
|
||||||
new(AvatarIds.Tighnari, 0, 75, 0, 100, 100, 75, 55, 0) { { FightProperty.FIGHT_PROP_GRASS_ADD_HURT, 100 } },
|
new AffixWeight(AvatarIds.Tighnari, 0, 75, 0, 100, 100, 75, 55, 0).Dendro(),
|
||||||
new(AvatarIds.Nilou, 100, 75, 0, 100, 100, 0, 55, 0, "直伤流") { { FightProperty.FIGHT_PROP_WATER_ADD_HURT, 100 } },
|
new AffixWeight(AvatarIds.Nilou, 100, 75, 0, 100, 100, 0, 55, 0, "直伤流").Hydro(),
|
||||||
new(AvatarIds.Nilou, 100, 75, 0, 100, 100, 0, 55, 0, "反应流") { { FightProperty.FIGHT_PROP_WATER_ADD_HURT, 100 } },
|
new AffixWeight(AvatarIds.Nilou, 100, 75, 0, 100, 100, 0, 55, 0, "反应流").Hydro(),
|
||||||
new(AvatarIds.Cyno, 0, 75, 0, 100, 100, 75, 55, 0) { { FightProperty.FIGHT_PROP_ELEC_ADD_HURT, 100 } },
|
new AffixWeight(AvatarIds.Cyno, 0, 75, 0, 100, 100, 75, 55, 0).Electro(),
|
||||||
new(AvatarIds.Candace, 100, 75, 0, 100, 100, 0, 55, 0) { { FightProperty.FIGHT_PROP_WATER_ADD_HURT, 100 } },
|
new AffixWeight(AvatarIds.Candace, 100, 75, 0, 100, 100, 0, 55, 0).Hydro(),
|
||||||
new(AvatarIds.Nahida, 0, 55, 0, 100, 100, 100, 55, 0) { { FightProperty.FIGHT_PROP_GRASS_ADD_HURT, 100 } },
|
new AffixWeight(AvatarIds.Nahida, 0, 55, 0, 100, 100, 100, 55, 0).Dendro(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -5,11 +5,8 @@ using Snap.Hutao.Extension;
|
|||||||
using Snap.Hutao.Model;
|
using Snap.Hutao.Model;
|
||||||
using Snap.Hutao.Model.Intrinsic;
|
using Snap.Hutao.Model.Intrinsic;
|
||||||
using Snap.Hutao.Model.Metadata.Converter;
|
using Snap.Hutao.Model.Metadata.Converter;
|
||||||
using Snap.Hutao.Model.Metadata.Reliquary;
|
|
||||||
using Snap.Hutao.Model.Primitive;
|
|
||||||
using Snap.Hutao.Web.Enka.Model;
|
using Snap.Hutao.Web.Enka.Model;
|
||||||
using MetadataAvatar = Snap.Hutao.Model.Metadata.Avatar.Avatar;
|
using MetadataAvatar = Snap.Hutao.Model.Metadata.Avatar.Avatar;
|
||||||
using MetadataReliquary = Snap.Hutao.Model.Metadata.Reliquary.Reliquary;
|
|
||||||
using MetadataWeapon = Snap.Hutao.Model.Metadata.Weapon.Weapon;
|
using MetadataWeapon = Snap.Hutao.Model.Metadata.Weapon.Weapon;
|
||||||
using ModelAvatarInfo = Snap.Hutao.Web.Enka.Model.AvatarInfo;
|
using ModelAvatarInfo = Snap.Hutao.Web.Enka.Model.AvatarInfo;
|
||||||
using PropertyAvatar = Snap.Hutao.Model.Binding.AvatarProperty.Avatar;
|
using PropertyAvatar = Snap.Hutao.Model.Binding.AvatarProperty.Avatar;
|
||||||
@@ -23,40 +20,17 @@ namespace Snap.Hutao.Service.AvatarInfo.Factory;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal class SummaryAvatarFactory
|
internal class SummaryAvatarFactory
|
||||||
{
|
{
|
||||||
private readonly Dictionary<AvatarId, MetadataAvatar> idAvatarMap;
|
|
||||||
private readonly Dictionary<WeaponId, MetadataWeapon> idWeaponMap;
|
|
||||||
private readonly Dictionary<ReliquaryMainAffixId, FightProperty> idRelicMainPropMap;
|
|
||||||
private readonly Dictionary<ReliquaryAffixId, ReliquaryAffix> idReliquaryAffixMap;
|
|
||||||
private readonly List<ReliquaryLevel> reliqueryLevels;
|
|
||||||
private readonly List<MetadataReliquary> reliquaries;
|
|
||||||
|
|
||||||
private readonly ModelAvatarInfo avatarInfo;
|
private readonly ModelAvatarInfo avatarInfo;
|
||||||
|
private readonly SummaryMetadataContext metadataContext;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 构造一个新的角色工厂
|
/// 构造一个新的角色工厂
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="idAvatarMap">角色映射</param>
|
/// <param name="metadataContext">元数据上下文</param>
|
||||||
/// <param name="idWeaponMap">武器映射</param>
|
|
||||||
/// <param name="idRelicMainPropMap">圣遗物主属性映射</param>
|
|
||||||
/// <param name="idReliquaryAffixMap">圣遗物副词条映射</param>
|
|
||||||
/// <param name="reliqueryLevels">圣遗物主属性等级</param>
|
|
||||||
/// <param name="reliquaries">圣遗物</param>
|
|
||||||
/// <param name="avatarInfo">角色信息</param>
|
/// <param name="avatarInfo">角色信息</param>
|
||||||
public SummaryAvatarFactory(
|
public SummaryAvatarFactory(SummaryMetadataContext metadataContext, ModelAvatarInfo avatarInfo)
|
||||||
Dictionary<AvatarId, MetadataAvatar> idAvatarMap,
|
|
||||||
Dictionary<WeaponId, MetadataWeapon> idWeaponMap,
|
|
||||||
Dictionary<ReliquaryMainAffixId, FightProperty> idRelicMainPropMap,
|
|
||||||
Dictionary<ReliquaryAffixId, ReliquaryAffix> idReliquaryAffixMap,
|
|
||||||
List<ReliquaryLevel> reliqueryLevels,
|
|
||||||
List<MetadataReliquary> reliquaries,
|
|
||||||
ModelAvatarInfo avatarInfo)
|
|
||||||
{
|
{
|
||||||
this.idAvatarMap = idAvatarMap;
|
this.metadataContext = metadataContext;
|
||||||
this.idWeaponMap = idWeaponMap;
|
|
||||||
this.idRelicMainPropMap = idRelicMainPropMap;
|
|
||||||
this.idReliquaryAffixMap = idReliquaryAffixMap;
|
|
||||||
this.reliqueryLevels = reliqueryLevels;
|
|
||||||
this.reliquaries = reliquaries;
|
|
||||||
this.avatarInfo = avatarInfo;
|
this.avatarInfo = avatarInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,10 +41,11 @@ internal class SummaryAvatarFactory
|
|||||||
public PropertyAvatar CreateAvatar()
|
public PropertyAvatar CreateAvatar()
|
||||||
{
|
{
|
||||||
ReliquaryAndWeapon reliquaryAndWeapon = ProcessEquip(avatarInfo.EquipList);
|
ReliquaryAndWeapon reliquaryAndWeapon = ProcessEquip(avatarInfo.EquipList);
|
||||||
MetadataAvatar avatar = idAvatarMap[avatarInfo.AvatarId];
|
MetadataAvatar avatar = metadataContext.IdAvatarMap[avatarInfo.AvatarId];
|
||||||
|
|
||||||
return new()
|
return new()
|
||||||
{
|
{
|
||||||
|
Id = avatar.Id,
|
||||||
Name = avatar.Name,
|
Name = avatar.Name,
|
||||||
Icon = AvatarIconConverter.IconNameToUri(avatar.Icon),
|
Icon = AvatarIconConverter.IconNameToUri(avatar.Icon),
|
||||||
SideIcon = AvatarIconConverter.IconNameToUri(avatar.SideIcon),
|
SideIcon = AvatarIconConverter.IconNameToUri(avatar.SideIcon),
|
||||||
@@ -78,6 +53,7 @@ internal class SummaryAvatarFactory
|
|||||||
Quality = avatar.Quality,
|
Quality = avatar.Quality,
|
||||||
Element = ElementNameIconConverter.ElementNameToElementType(avatar.FetterInfo.VisionBefore),
|
Element = ElementNameIconConverter.ElementNameToElementType(avatar.FetterInfo.VisionBefore),
|
||||||
Level = $"Lv.{avatarInfo.PropMap[PlayerProperty.PROP_LEVEL].Value}",
|
Level = $"Lv.{avatarInfo.PropMap[PlayerProperty.PROP_LEVEL].Value}",
|
||||||
|
LevelNumber = int.Parse(avatarInfo.PropMap[PlayerProperty.PROP_LEVEL].Value ?? string.Empty),
|
||||||
FetterLevel = avatarInfo.FetterInfo.ExpLevel,
|
FetterLevel = avatarInfo.FetterInfo.ExpLevel,
|
||||||
Weapon = reliquaryAndWeapon.Weapon,
|
Weapon = reliquaryAndWeapon.Weapon,
|
||||||
Reliquaries = reliquaryAndWeapon.Reliquaries,
|
Reliquaries = reliquaryAndWeapon.Reliquaries,
|
||||||
@@ -99,7 +75,7 @@ internal class SummaryAvatarFactory
|
|||||||
switch (equip.Flat.ItemType)
|
switch (equip.Flat.ItemType)
|
||||||
{
|
{
|
||||||
case ItemType.ITEM_RELIQUARY:
|
case ItemType.ITEM_RELIQUARY:
|
||||||
SummaryReliquaryFactory summaryReliquaryFactory = new(idReliquaryAffixMap, idRelicMainPropMap, reliqueryLevels, reliquaries, avatarInfo, equip);
|
SummaryReliquaryFactory summaryReliquaryFactory = new(metadataContext, avatarInfo, equip);
|
||||||
reliquaryList.Add(summaryReliquaryFactory.CreateReliquary());
|
reliquaryList.Add(summaryReliquaryFactory.CreateReliquary());
|
||||||
break;
|
break;
|
||||||
case ItemType.ITEM_WEAPON:
|
case ItemType.ITEM_WEAPON:
|
||||||
@@ -113,7 +89,7 @@ internal class SummaryAvatarFactory
|
|||||||
|
|
||||||
private PropertyWeapon CreateWeapon(Equip equip)
|
private PropertyWeapon CreateWeapon(Equip equip)
|
||||||
{
|
{
|
||||||
MetadataWeapon weapon = idWeaponMap[equip.ItemId];
|
MetadataWeapon weapon = metadataContext.IdWeaponMap[equip.ItemId];
|
||||||
|
|
||||||
// AffixMap can be empty when it's a white weapon.
|
// AffixMap can be empty when it's a white weapon.
|
||||||
KeyValuePair<string, int>? idLevel = equip.Weapon!.AffixMap?.Single();
|
KeyValuePair<string, int>? idLevel = equip.Weapon!.AffixMap?.Single();
|
||||||
@@ -146,6 +122,8 @@ internal class SummaryAvatarFactory
|
|||||||
MainProperty = mainStat == null ? default! : new(mainStat.AppendPropId.GetDescription(), mainStat.StatValue.ToString()),
|
MainProperty = mainStat == null ? default! : new(mainStat.AppendPropId.GetDescription(), mainStat.StatValue.ToString()),
|
||||||
|
|
||||||
// Weapon
|
// Weapon
|
||||||
|
Id = weapon.Id,
|
||||||
|
LevelNumber = equip.Weapon!.Level,
|
||||||
SubProperty = subProperty,
|
SubProperty = subProperty,
|
||||||
AffixLevel = $"精炼{affixLevel + 1}",
|
AffixLevel = $"精炼{affixLevel + 1}",
|
||||||
AffixName = weapon.Affix?.Name ?? string.Empty,
|
AffixName = weapon.Affix?.Name ?? string.Empty,
|
||||||
|
|||||||
@@ -2,13 +2,7 @@
|
|||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using Snap.Hutao.Model.Binding.AvatarProperty;
|
using Snap.Hutao.Model.Binding.AvatarProperty;
|
||||||
using Snap.Hutao.Model.Intrinsic;
|
|
||||||
using Snap.Hutao.Model.Metadata.Reliquary;
|
|
||||||
using Snap.Hutao.Model.Primitive;
|
|
||||||
using Snap.Hutao.Service.Metadata;
|
using Snap.Hutao.Service.Metadata;
|
||||||
using MetadataAvatar = Snap.Hutao.Model.Metadata.Avatar.Avatar;
|
|
||||||
using MetadataReliquary = Snap.Hutao.Model.Metadata.Reliquary.Reliquary;
|
|
||||||
using MetadataWeapon = Snap.Hutao.Model.Metadata.Weapon.Weapon;
|
|
||||||
using ModelAvatarInfo = Snap.Hutao.Web.Enka.Model.AvatarInfo;
|
using ModelAvatarInfo = Snap.Hutao.Web.Enka.Model.AvatarInfo;
|
||||||
using ModelPlayerInfo = Snap.Hutao.Web.Enka.Model.PlayerInfo;
|
using ModelPlayerInfo = Snap.Hutao.Web.Enka.Model.PlayerInfo;
|
||||||
|
|
||||||
@@ -34,15 +28,17 @@ internal class SummaryFactory : ISummaryFactory
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public async Task<Summary> CreateAsync(ModelPlayerInfo playerInfo, IEnumerable<ModelAvatarInfo> avatarInfos, CancellationToken token)
|
public async Task<Summary> CreateAsync(ModelPlayerInfo playerInfo, IEnumerable<ModelAvatarInfo> avatarInfos, CancellationToken token)
|
||||||
{
|
{
|
||||||
Dictionary<AvatarId, MetadataAvatar> idAvatarMap = await metadataService.GetIdToAvatarMapAsync(token).ConfigureAwait(false);
|
SummaryMetadataContext metadataContext = new()
|
||||||
Dictionary<WeaponId, MetadataWeapon> idWeaponMap = await metadataService.GetIdToWeaponMapAsync(token).ConfigureAwait(false);
|
{
|
||||||
Dictionary<ReliquaryMainAffixId, FightProperty> idRelicMainPropMap = await metadataService.GetIdToReliquaryMainPropertyMapAsync(token).ConfigureAwait(false);
|
IdAvatarMap = await metadataService.GetIdToAvatarMapAsync(token).ConfigureAwait(false),
|
||||||
Dictionary<ReliquaryAffixId, ReliquaryAffix> idReliquaryAffixMap = await metadataService.GetIdReliquaryAffixMapAsync(token).ConfigureAwait(false);
|
IdWeaponMap = await metadataService.GetIdToWeaponMapAsync(token).ConfigureAwait(false),
|
||||||
|
IdRelicMainPropMap = await metadataService.GetIdToReliquaryMainPropertyMapAsync(token).ConfigureAwait(false),
|
||||||
|
IdReliquaryAffixMap = await metadataService.GetIdReliquaryAffixMapAsync(token).ConfigureAwait(false),
|
||||||
|
ReliqueryLevels = await metadataService.GetReliquaryLevelsAsync(token).ConfigureAwait(false),
|
||||||
|
Reliquaries = await metadataService.GetReliquariesAsync(token).ConfigureAwait(false),
|
||||||
|
};
|
||||||
|
|
||||||
List<ReliquaryLevel> reliqueryLevels = await metadataService.GetReliquaryLevelsAsync(token).ConfigureAwait(false);
|
SummaryFactoryImplementation inner = new(metadataContext);
|
||||||
List<MetadataReliquary> reliquaries = await metadataService.GetReliquariesAsync(token).ConfigureAwait(false);
|
|
||||||
|
|
||||||
SummaryFactoryImplementation inner = new(idAvatarMap, idWeaponMap, idRelicMainPropMap, idReliquaryAffixMap, reliqueryLevels, reliquaries);
|
|
||||||
return inner.Create(playerInfo, avatarInfos);
|
return inner.Create(playerInfo, avatarInfos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,13 +2,7 @@
|
|||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using Snap.Hutao.Model.Binding.AvatarProperty;
|
using Snap.Hutao.Model.Binding.AvatarProperty;
|
||||||
using Snap.Hutao.Model.Intrinsic;
|
|
||||||
using Snap.Hutao.Model.Metadata;
|
using Snap.Hutao.Model.Metadata;
|
||||||
using Snap.Hutao.Model.Metadata.Reliquary;
|
|
||||||
using Snap.Hutao.Model.Primitive;
|
|
||||||
using MetadataAvatar = Snap.Hutao.Model.Metadata.Avatar.Avatar;
|
|
||||||
using MetadataReliquary = Snap.Hutao.Model.Metadata.Reliquary.Reliquary;
|
|
||||||
using MetadataWeapon = Snap.Hutao.Model.Metadata.Weapon.Weapon;
|
|
||||||
using ModelAvatarInfo = Snap.Hutao.Web.Enka.Model.AvatarInfo;
|
using ModelAvatarInfo = Snap.Hutao.Web.Enka.Model.AvatarInfo;
|
||||||
using ModelPlayerInfo = Snap.Hutao.Web.Enka.Model.PlayerInfo;
|
using ModelPlayerInfo = Snap.Hutao.Web.Enka.Model.PlayerInfo;
|
||||||
|
|
||||||
@@ -19,36 +13,15 @@ namespace Snap.Hutao.Service.AvatarInfo.Factory;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal class SummaryFactoryImplementation
|
internal class SummaryFactoryImplementation
|
||||||
{
|
{
|
||||||
private readonly Dictionary<AvatarId, MetadataAvatar> idAvatarMap;
|
private readonly SummaryMetadataContext metadataContext;
|
||||||
private readonly Dictionary<WeaponId, MetadataWeapon> idWeaponMap;
|
|
||||||
private readonly Dictionary<ReliquaryMainAffixId, FightProperty> idRelicMainPropMap;
|
|
||||||
private readonly Dictionary<ReliquaryAffixId, ReliquaryAffix> idReliquaryAffixMap;
|
|
||||||
private readonly List<ReliquaryLevel> reliqueryLevels;
|
|
||||||
private readonly List<MetadataReliquary> reliquaries;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 装配一个工厂实现
|
/// 装配一个工厂实现
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="idAvatarMap">角色映射</param>
|
/// <param name="metadataContext">元数据上下文</param>
|
||||||
/// <param name="idWeaponMap">武器映射</param>
|
public SummaryFactoryImplementation(SummaryMetadataContext metadataContext)
|
||||||
/// <param name="idRelicMainPropMap">圣遗物主属性映射</param>
|
|
||||||
/// <param name="idReliquaryAffixMap">圣遗物副词条映射</param>
|
|
||||||
/// <param name="reliqueryLevels">圣遗物主属性等级</param>
|
|
||||||
/// <param name="reliquaries">圣遗物</param>
|
|
||||||
public SummaryFactoryImplementation(
|
|
||||||
Dictionary<AvatarId, MetadataAvatar> idAvatarMap,
|
|
||||||
Dictionary<WeaponId, MetadataWeapon> idWeaponMap,
|
|
||||||
Dictionary<ReliquaryMainAffixId, FightProperty> idRelicMainPropMap,
|
|
||||||
Dictionary<ReliquaryAffixId, ReliquaryAffix> idReliquaryAffixMap,
|
|
||||||
List<ReliquaryLevel> reliqueryLevels,
|
|
||||||
List<MetadataReliquary> reliquaries)
|
|
||||||
{
|
{
|
||||||
this.idAvatarMap = idAvatarMap;
|
this.metadataContext = metadataContext;
|
||||||
this.idRelicMainPropMap = idRelicMainPropMap;
|
|
||||||
this.idWeaponMap = idWeaponMap;
|
|
||||||
this.reliqueryLevels = reliqueryLevels;
|
|
||||||
this.reliquaries = reliquaries;
|
|
||||||
this.idReliquaryAffixMap = idReliquaryAffixMap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -64,14 +37,7 @@ internal class SummaryFactoryImplementation
|
|||||||
Player = SummaryHelper.CreatePlayer(playerInfo),
|
Player = SummaryHelper.CreatePlayer(playerInfo),
|
||||||
Avatars = avatarInfos.Where(a => !AvatarIds.IsPlayer(a.AvatarId)).Select(a =>
|
Avatars = avatarInfos.Where(a => !AvatarIds.IsPlayer(a.AvatarId)).Select(a =>
|
||||||
{
|
{
|
||||||
SummaryAvatarFactory summaryAvatarFactory = new(
|
SummaryAvatarFactory summaryAvatarFactory = new(metadataContext, a);
|
||||||
idAvatarMap,
|
|
||||||
idWeaponMap,
|
|
||||||
idRelicMainPropMap,
|
|
||||||
idReliquaryAffixMap,
|
|
||||||
reliqueryLevels,
|
|
||||||
reliquaries,
|
|
||||||
a);
|
|
||||||
return summaryAvatarFactory.CreateAvatar();
|
return summaryAvatarFactory.CreateAvatar();
|
||||||
}).ToList(),
|
}).ToList(),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -88,7 +88,8 @@ internal static class SummaryHelper
|
|||||||
Icon = SkillIconConverter.IconNameToUri(proudableSkill.Icon),
|
Icon = SkillIconConverter.IconNameToUri(proudableSkill.Icon),
|
||||||
Description = proudableSkill.Description,
|
Description = proudableSkill.Description,
|
||||||
|
|
||||||
Level = skillLevelMap[proudableSkill.Id.ToString()],
|
GroupId = proudableSkill.GroupId,
|
||||||
|
LevelNumber = skillLevelMap[proudableSkill.Id.ToString()],
|
||||||
Info = DescParamDescriptor.Convert(proudableSkill.Proud, skillExtraLeveledMap[proudableSkill.Id.ToString()]),
|
Info = DescParamDescriptor.Convert(proudableSkill.Proud, skillExtraLeveledMap[proudableSkill.Id.ToString()]),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Model.Intrinsic;
|
||||||
|
using Snap.Hutao.Model.Metadata.Reliquary;
|
||||||
|
using Snap.Hutao.Model.Primitive;
|
||||||
|
using MetadataAvatar = Snap.Hutao.Model.Metadata.Avatar.Avatar;
|
||||||
|
using MetadataReliquary = Snap.Hutao.Model.Metadata.Reliquary.Reliquary;
|
||||||
|
using MetadataWeapon = Snap.Hutao.Model.Metadata.Weapon.Weapon;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Service.AvatarInfo.Factory;
|
||||||
|
|
||||||
|
[SuppressMessage("", "SA1600")]
|
||||||
|
internal class SummaryMetadataContext
|
||||||
|
{
|
||||||
|
public Dictionary<AvatarId, MetadataAvatar> IdAvatarMap { get; set; } = default!;
|
||||||
|
|
||||||
|
public Dictionary<WeaponId, MetadataWeapon> IdWeaponMap { get; set; } = default!;
|
||||||
|
|
||||||
|
public Dictionary<ReliquaryMainAffixId, FightProperty> IdRelicMainPropMap { get; set; } = default!;
|
||||||
|
|
||||||
|
public Dictionary<ReliquaryAffixId, ReliquaryAffix> IdReliquaryAffixMap { get; set; } = default!;
|
||||||
|
|
||||||
|
public List<ReliquaryLevel> ReliqueryLevels { get; set; } = default!;
|
||||||
|
|
||||||
|
public List<MetadataReliquary> Reliquaries { get; set; } = default!;
|
||||||
|
}
|
||||||
@@ -7,7 +7,6 @@ using Snap.Hutao.Model.Intrinsic;
|
|||||||
using Snap.Hutao.Model.Metadata.Annotation;
|
using Snap.Hutao.Model.Metadata.Annotation;
|
||||||
using Snap.Hutao.Model.Metadata.Converter;
|
using Snap.Hutao.Model.Metadata.Converter;
|
||||||
using Snap.Hutao.Model.Metadata.Reliquary;
|
using Snap.Hutao.Model.Metadata.Reliquary;
|
||||||
using Snap.Hutao.Model.Primitive;
|
|
||||||
using Snap.Hutao.Web.Enka.Model;
|
using Snap.Hutao.Web.Enka.Model;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using MetadataReliquary = Snap.Hutao.Model.Metadata.Reliquary.Reliquary;
|
using MetadataReliquary = Snap.Hutao.Model.Metadata.Reliquary.Reliquary;
|
||||||
@@ -22,36 +21,19 @@ namespace Snap.Hutao.Service.AvatarInfo.Factory;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal class SummaryReliquaryFactory
|
internal class SummaryReliquaryFactory
|
||||||
{
|
{
|
||||||
private readonly Dictionary<ReliquaryAffixId, MetadataReliquaryAffix> idReliquaryAffixMap;
|
private readonly SummaryMetadataContext metadataContext;
|
||||||
private readonly Dictionary<ReliquaryMainAffixId, FightProperty> idRelicMainPropMap;
|
|
||||||
private readonly List<ReliquaryLevel> reliqueryLevels;
|
|
||||||
private readonly List<MetadataReliquary> reliquaries;
|
|
||||||
|
|
||||||
private readonly ModelAvatarInfo avatarInfo;
|
private readonly ModelAvatarInfo avatarInfo;
|
||||||
private readonly Equip equip;
|
private readonly Equip equip;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 构造一个新的圣遗物工厂
|
/// 构造一个新的圣遗物工厂
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="idReliquaryAffixMap">圣遗物副词条映射</param>
|
/// <param name="metadataContext">元数据上下文</param>
|
||||||
/// <param name="idRelicMainPropMap">圣遗物主属性映射</param>
|
|
||||||
/// <param name="reliqueryLevels">圣遗物主属性等级</param>
|
|
||||||
/// <param name="reliquaries">圣遗物列表</param>
|
|
||||||
/// <param name="avatarInfo">角色信息</param>
|
/// <param name="avatarInfo">角色信息</param>
|
||||||
/// <param name="equip">圣遗物</param>
|
/// <param name="equip">圣遗物</param>
|
||||||
public SummaryReliquaryFactory(
|
public SummaryReliquaryFactory(SummaryMetadataContext metadataContext, ModelAvatarInfo avatarInfo, Equip equip)
|
||||||
Dictionary<ReliquaryAffixId, MetadataReliquaryAffix> idReliquaryAffixMap,
|
|
||||||
Dictionary<ReliquaryMainAffixId, FightProperty> idRelicMainPropMap,
|
|
||||||
List<ReliquaryLevel> reliqueryLevels,
|
|
||||||
List<MetadataReliquary> reliquaries,
|
|
||||||
ModelAvatarInfo avatarInfo,
|
|
||||||
Equip equip)
|
|
||||||
{
|
{
|
||||||
this.idReliquaryAffixMap = idReliquaryAffixMap;
|
this.metadataContext = metadataContext;
|
||||||
this.idRelicMainPropMap = idRelicMainPropMap;
|
|
||||||
this.reliqueryLevels = reliqueryLevels;
|
|
||||||
this.reliquaries = reliquaries;
|
|
||||||
|
|
||||||
this.avatarInfo = avatarInfo;
|
this.avatarInfo = avatarInfo;
|
||||||
this.equip = equip;
|
this.equip = equip;
|
||||||
}
|
}
|
||||||
@@ -62,7 +44,7 @@ internal class SummaryReliquaryFactory
|
|||||||
/// <returns>圣遗物</returns>
|
/// <returns>圣遗物</returns>
|
||||||
public PropertyReliquary CreateReliquary()
|
public PropertyReliquary CreateReliquary()
|
||||||
{
|
{
|
||||||
MetadataReliquary reliquary = reliquaries.Single(r => r.Ids.Contains(equip.ItemId));
|
MetadataReliquary reliquary = metadataContext.Reliquaries.Single(r => r.Ids.Contains(equip.ItemId));
|
||||||
List<ReliquarySubProperty> subProperty = equip.Reliquary!.AppendPropIdList.EmptyIfNull().Select(CreateSubProperty).ToList();
|
List<ReliquarySubProperty> subProperty = equip.Reliquary!.AppendPropIdList.EmptyIfNull().Select(CreateSubProperty).ToList();
|
||||||
|
|
||||||
int affixCount = GetAffixCount(reliquary);
|
int affixCount = GetAffixCount(reliquary);
|
||||||
@@ -87,8 +69,8 @@ internal class SummaryReliquaryFactory
|
|||||||
|
|
||||||
List<ReliquarySubProperty> composed = equip.Flat.ReliquarySubstats!.Select(CreateComposedSubProperty).ToList();
|
List<ReliquarySubProperty> composed = equip.Flat.ReliquarySubstats!.Select(CreateComposedSubProperty).ToList();
|
||||||
|
|
||||||
ReliquaryLevel relicLevel = reliqueryLevels.Single(r => r.Level == equip.Reliquary!.Level && r.Quality == reliquary.RankLevel);
|
ReliquaryLevel relicLevel = metadataContext.ReliqueryLevels.Single(r => r.Level == equip.Reliquary!.Level && r.Quality == reliquary.RankLevel);
|
||||||
FightProperty property = idRelicMainPropMap[equip.Reliquary.MainPropId];
|
FightProperty property = metadataContext.IdRelicMainPropMap[equip.Reliquary.MainPropId];
|
||||||
|
|
||||||
return new()
|
return new()
|
||||||
{
|
{
|
||||||
@@ -148,7 +130,7 @@ internal class SummaryReliquaryFactory
|
|||||||
if (equip.Flat.EquipType is EquipType.EQUIP_SHOES or EquipType.EQUIP_RING or EquipType.EQUIP_DRESS)
|
if (equip.Flat.EquipType is EquipType.EQUIP_SHOES or EquipType.EQUIP_RING or EquipType.EQUIP_DRESS)
|
||||||
{
|
{
|
||||||
AffixWeight weightConfig = GetAffixWeightForAvatarId();
|
AffixWeight weightConfig = GetAffixWeightForAvatarId();
|
||||||
ReliquaryLevel maxRelicLevel = reliqueryLevels.Where(r => r.Quality == reliquary.RankLevel).MaxBy(r => r.Level)!;
|
ReliquaryLevel maxRelicLevel = metadataContext.ReliqueryLevels.Where(r => r.Quality == reliquary.RankLevel).MaxBy(r => r.Level)!;
|
||||||
|
|
||||||
double percent = relicLevel.Properties[property] / maxRelicLevel.Properties[property];
|
double percent = relicLevel.Properties[property] / maxRelicLevel.Properties[property];
|
||||||
double baseScore = 8 * percent * weightConfig.GetValueOrDefault(property, 0);
|
double baseScore = 8 * percent * weightConfig.GetValueOrDefault(property, 0);
|
||||||
@@ -183,7 +165,7 @@ internal class SummaryReliquaryFactory
|
|||||||
|
|
||||||
private ReliquarySubProperty CreateSubProperty(int appendPropId)
|
private ReliquarySubProperty CreateSubProperty(int appendPropId)
|
||||||
{
|
{
|
||||||
MetadataReliquaryAffix affix = idReliquaryAffixMap[appendPropId];
|
MetadataReliquaryAffix affix = metadataContext.IdReliquaryAffixMap[appendPropId];
|
||||||
FightProperty property = affix.Type;
|
FightProperty property = affix.Type;
|
||||||
|
|
||||||
double score = ScoreSubAffix(appendPropId);
|
double score = ScoreSubAffix(appendPropId);
|
||||||
@@ -192,7 +174,7 @@ internal class SummaryReliquaryFactory
|
|||||||
|
|
||||||
private double ScoreSubAffix(int appendId)
|
private double ScoreSubAffix(int appendId)
|
||||||
{
|
{
|
||||||
MetadataReliquaryAffix affix = idReliquaryAffixMap[appendId];
|
MetadataReliquaryAffix affix = metadataContext.IdReliquaryAffixMap[appendId];
|
||||||
|
|
||||||
AffixWeight weightConfig = GetAffixWeightForAvatarId();
|
AffixWeight weightConfig = GetAffixWeightForAvatarId();
|
||||||
double weight = weightConfig.GetValueOrDefault(affix.Type, 0) / 100D;
|
double weight = weightConfig.GetValueOrDefault(affix.Type, 0) / 100D;
|
||||||
@@ -200,14 +182,14 @@ internal class SummaryReliquaryFactory
|
|||||||
// 小字词条,转换到等效百分比计算
|
// 小字词条,转换到等效百分比计算
|
||||||
if (affix.Type is FightProperty.FIGHT_PROP_HP or FightProperty.FIGHT_PROP_ATTACK or FightProperty.FIGHT_PROP_DEFENSE)
|
if (affix.Type is FightProperty.FIGHT_PROP_HP or FightProperty.FIGHT_PROP_ATTACK or FightProperty.FIGHT_PROP_DEFENSE)
|
||||||
{
|
{
|
||||||
// 等效百分比 [ 当前小字词条 / 角色基本属性 ]
|
// 等效百分比 [ 当前小字词条 / 角色基本属性 ]
|
||||||
double equalPercent = affix.Value / avatarInfo.FightPropMap[affix.Type - 1];
|
double equalPercent = affix.Value / avatarInfo.FightPropMap[affix.Type - 1];
|
||||||
|
|
||||||
// 获取对应百分比词条权重
|
// 获取对应百分比词条权重
|
||||||
weight = weightConfig.GetValueOrDefault(affix.Type + 1, 0) / 100D;
|
weight = weightConfig.GetValueOrDefault(affix.Type + 1, 0) / 100D;
|
||||||
|
|
||||||
// 最大同属性百分比数值 最大同属性百分比Id 第四五位是战斗属性位
|
// 最大同属性百分比数值 最大同属性百分比Id 第四五位是战斗属性位
|
||||||
MetadataReliquaryAffix maxPercentAffix = idReliquaryAffixMap[SummaryHelper.GetAffixMaxId(appendId + 10)];
|
MetadataReliquaryAffix maxPercentAffix = metadataContext.IdReliquaryAffixMap[SummaryHelper.GetAffixMaxId(appendId + 10)];
|
||||||
double equalScore = equalPercent / maxPercentAffix.Value;
|
double equalScore = equalPercent / maxPercentAffix.Value;
|
||||||
|
|
||||||
return weight * equalScore * 100;
|
return weight * equalScore * 100;
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ internal class CultivationService : ICultivationService
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public async Task<ObservableCollection<BindingCultivateEntry>> GetCultivateEntriesAsync(
|
public async Task<ObservableCollection<BindingCultivateEntry>> GetCultivateEntriesAsync(
|
||||||
CultivateProject cultivateProject,
|
CultivateProject cultivateProject,
|
||||||
List<Model.Metadata.Material> metadata,
|
List<Model.Metadata.Material> materials,
|
||||||
Dictionary<AvatarId, Model.Metadata.Avatar.Avatar> idAvatarMap,
|
Dictionary<AvatarId, Model.Metadata.Avatar.Avatar> idAvatarMap,
|
||||||
Dictionary<WeaponId, Model.Metadata.Weapon.Weapon> idWeaponMap)
|
Dictionary<WeaponId, Model.Metadata.Weapon.Weapon> idWeaponMap)
|
||||||
{
|
{
|
||||||
@@ -148,19 +148,20 @@ internal class CultivationService : ICultivationService
|
|||||||
.ToListAsync()
|
.ToListAsync()
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
foreach (CultivateEntry? entry in entries)
|
foreach (CultivateEntry entry in entries)
|
||||||
{
|
{
|
||||||
Guid entryId = entry.InnerId;
|
Guid entryId = entry.InnerId;
|
||||||
|
|
||||||
List<BindingCultivateItem> resultItems = new();
|
List<BindingCultivateItem> resultItems = new();
|
||||||
List<CultivateItem> items = await appDbContext.CultivateItems
|
List<CultivateItem> items = await appDbContext.CultivateItems
|
||||||
.Where(i => i.EntryId == entryId)
|
.Where(i => i.EntryId == entryId)
|
||||||
.OrderBy(i => i.ItemId).ToListAsync()
|
.OrderBy(i => i.ItemId)
|
||||||
|
.ToListAsync()
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
foreach (CultivateItem item in items)
|
foreach (CultivateItem item in items)
|
||||||
{
|
{
|
||||||
resultItems.Add(new(metadata.Single(m => m.Id == item.ItemId), item));
|
resultItems.Add(new(materials.Single(m => m.Id == item.ItemId), item));
|
||||||
}
|
}
|
||||||
|
|
||||||
Model.Binding.Gacha.Abstraction.ItemBase itemBase = entry.Type switch
|
Model.Binding.Gacha.Abstraction.ItemBase itemBase = entry.Type switch
|
||||||
@@ -173,7 +174,71 @@ internal class CultivationService : ICultivationService
|
|||||||
results.Add(new(entry, itemBase, resultItems));
|
results.Add(new(entry, itemBase, resultItems));
|
||||||
}
|
}
|
||||||
|
|
||||||
return new(results);
|
return new(results.OrderByDescending(e => e.Items.Any(i => i.IsToday)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public async Task<List<Model.Binding.Cultivation.StatisticsCultivateItem>> GetStatisticsCultivateItemsAsync(CultivateProject cultivateProject, List<Model.Metadata.Material> materials)
|
||||||
|
{
|
||||||
|
using (IServiceScope scope = scopeFactory.CreateScope())
|
||||||
|
{
|
||||||
|
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||||
|
|
||||||
|
Guid projectId = cultivateProject.InnerId;
|
||||||
|
|
||||||
|
List<Model.Binding.Cultivation.StatisticsCultivateItem> resultItems = new();
|
||||||
|
|
||||||
|
List<CultivateEntry> entries = await appDbContext.CultivateEntries
|
||||||
|
.AsNoTracking()
|
||||||
|
.Where(e => e.ProjectId == projectId)
|
||||||
|
.ToListAsync()
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
|
foreach (CultivateEntry entry in entries)
|
||||||
|
{
|
||||||
|
Guid entryId = entry.InnerId;
|
||||||
|
|
||||||
|
List<CultivateItem> items = await appDbContext.CultivateItems
|
||||||
|
.AsNoTracking()
|
||||||
|
.Where(i => i.EntryId == entryId)
|
||||||
|
.OrderBy(i => i.ItemId)
|
||||||
|
.ToListAsync()
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
|
foreach (CultivateItem item in items)
|
||||||
|
{
|
||||||
|
if (item.IsFinished)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resultItems.SingleOrDefault(i => i.Inner.Id == item.ItemId) is Model.Binding.Cultivation.StatisticsCultivateItem inPlaceItem)
|
||||||
|
{
|
||||||
|
inPlaceItem.Count += item.Count;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
resultItems.Add(new(materials.Single(m => m.Id == item.ItemId), item));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<InventoryItem> inventoryItems = await appDbContext.InventoryItems
|
||||||
|
.AsNoTracking()
|
||||||
|
.Where(e => e.ProjectId == projectId)
|
||||||
|
.ToListAsync()
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
|
foreach (InventoryItem inventoryItem in inventoryItems)
|
||||||
|
{
|
||||||
|
if (resultItems.SingleOrDefault(i => i.Inner.Id == inventoryItem.ItemId) is Model.Binding.Cultivation.StatisticsCultivateItem inPlaceItem)
|
||||||
|
{
|
||||||
|
inPlaceItem.TotalCount += inventoryItem.Count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultItems.OrderByDescending(i => i.Count).ToList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,6 +274,11 @@ internal class CultivationService : ICultivationService
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public async Task<bool> SaveConsumptionAsync(Model.Binding.Cultivation.CultivateType type, int itemId, List<Web.Hoyolab.Takumi.Event.Calculate.Item> items)
|
public async Task<bool> SaveConsumptionAsync(Model.Binding.Cultivation.CultivateType type, int itemId, List<Web.Hoyolab.Takumi.Event.Calculate.Item> items)
|
||||||
{
|
{
|
||||||
|
if (items.Count == 0)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
using (IServiceScope scope = scopeFactory.CreateScope())
|
using (IServiceScope scope = scopeFactory.CreateScope())
|
||||||
{
|
{
|
||||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||||
|
|||||||
@@ -24,11 +24,11 @@ internal interface ICultivationService
|
|||||||
/// 获取绑定用的养成列表
|
/// 获取绑定用的养成列表
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="cultivateProject">养成计划</param>
|
/// <param name="cultivateProject">养成计划</param>
|
||||||
/// <param name="metadata">材料</param>
|
/// <param name="materials">材料</param>
|
||||||
/// <param name="idAvatarMap">Id角色映射</param>
|
/// <param name="idAvatarMap">Id角色映射</param>
|
||||||
/// <param name="idWeaponMap">Id武器映射</param>
|
/// <param name="idWeaponMap">Id武器映射</param>
|
||||||
/// <returns>绑定用的养成列表</returns>
|
/// <returns>绑定用的养成列表</returns>
|
||||||
Task<ObservableCollection<Model.Binding.Cultivation.CultivateEntry>> GetCultivateEntriesAsync(CultivateProject cultivateProject, List<Material> metadata, Dictionary<AvatarId, Model.Metadata.Avatar.Avatar> idAvatarMap, Dictionary<WeaponId, Model.Metadata.Weapon.Weapon> idWeaponMap);
|
Task<ObservableCollection<Model.Binding.Cultivation.CultivateEntry>> GetCultivateEntriesAsync(CultivateProject cultivateProject, List<Material> materials, Dictionary<AvatarId, Model.Metadata.Avatar.Avatar> idAvatarMap, Dictionary<WeaponId, Model.Metadata.Weapon.Weapon> idWeaponMap);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取物品列表
|
/// 获取物品列表
|
||||||
@@ -44,6 +44,14 @@ internal interface ICultivationService
|
|||||||
/// <returns>项目集合</returns>
|
/// <returns>项目集合</returns>
|
||||||
ObservableCollection<CultivateProject> GetProjectCollection();
|
ObservableCollection<CultivateProject> GetProjectCollection();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步获取统计物品列表
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cultivateProject">养成计划</param>
|
||||||
|
/// <param name="materials">元数据</param>
|
||||||
|
/// <returns>统计物品列表</returns>
|
||||||
|
Task<List<StatisticsCultivateItem>> GetStatisticsCultivateItemsAsync(CultivateProject cultivateProject, List<Material> materials);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 删除养成清单
|
/// 删除养成清单
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1,22 +1,14 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using CommunityToolkit.Mvvm.Messaging;
|
|
||||||
using CommunityToolkit.WinUI.Notifications;
|
using CommunityToolkit.WinUI.Notifications;
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Snap.Hutao.Context.Database;
|
using Snap.Hutao.Context.Database;
|
||||||
using Snap.Hutao.Core.Database;
|
using Snap.Hutao.Core.Database;
|
||||||
using Snap.Hutao.Extension;
|
|
||||||
using Snap.Hutao.Message;
|
|
||||||
using Snap.Hutao.Model.Binding.User;
|
|
||||||
using Snap.Hutao.Model.Entity;
|
using Snap.Hutao.Model.Entity;
|
||||||
using Snap.Hutao.Service.User;
|
using Snap.Hutao.Web.Hoyolab.Takumi.Auth;
|
||||||
using Snap.Hutao.Web.Hoyolab.Takumi.Binding;
|
using Snap.Hutao.Web.Hoyolab.Takumi.Binding;
|
||||||
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord;
|
|
||||||
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.DailyNote;
|
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.DailyNote;
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using WebDailyNote = Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.DailyNote.DailyNote;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Service.DailyNote;
|
namespace Snap.Hutao.Service.DailyNote;
|
||||||
|
|
||||||
@@ -26,19 +18,16 @@ namespace Snap.Hutao.Service.DailyNote;
|
|||||||
internal class DailyNoteNotifier
|
internal class DailyNoteNotifier
|
||||||
{
|
{
|
||||||
private readonly IServiceScopeFactory scopeFactory;
|
private readonly IServiceScopeFactory scopeFactory;
|
||||||
private readonly BindingClient bindingClient;
|
|
||||||
private readonly DailyNoteEntry entry;
|
private readonly DailyNoteEntry entry;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 构造一个新的实时便笺通知器
|
/// 构造一个新的实时便笺通知器
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="scopeFactory">范围工厂</param>
|
/// <param name="scopeFactory">范围工厂</param>
|
||||||
/// <param name="bindingClient">绑定客户端</param>
|
|
||||||
/// <param name="entry">实时便笺入口</param>
|
/// <param name="entry">实时便笺入口</param>
|
||||||
public DailyNoteNotifier(IServiceScopeFactory scopeFactory, BindingClient bindingClient, DailyNoteEntry entry)
|
public DailyNoteNotifier(IServiceScopeFactory scopeFactory, DailyNoteEntry entry)
|
||||||
{
|
{
|
||||||
this.scopeFactory = scopeFactory;
|
this.scopeFactory = scopeFactory;
|
||||||
this.bindingClient = bindingClient;
|
|
||||||
this.entry = entry;
|
this.entry = entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,37 +117,48 @@ internal class DailyNoteNotifier
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<UserGameRole> roles = await bindingClient.GetUserGameRolesByCookieAsync(entry.User).ConfigureAwait(false);
|
|
||||||
string attribution = roles.SingleOrDefault(r => r.GameUid == entry.Uid)?.ToString() ?? "未知角色";
|
|
||||||
|
|
||||||
ToastContentBuilder builder = new ToastContentBuilder()
|
|
||||||
.AddHeader("DAILYNOTE", "实时便笺提醒", "DAILYNOTE")
|
|
||||||
.AddAttributionText(attribution)
|
|
||||||
.AddButton(new ToastButton().SetContent("开始游戏").AddArgument("Action", "LaunchGame").AddArgument("Uid", entry.Uid))
|
|
||||||
.AddButton(new ToastButtonDismiss("我知道了"));
|
|
||||||
|
|
||||||
using (IServiceScope scope = scopeFactory.CreateScope())
|
using (IServiceScope scope = scopeFactory.CreateScope())
|
||||||
{
|
{
|
||||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||||
|
BindingClient bindingClient = scope.ServiceProvider.GetRequiredService<BindingClient>();
|
||||||
|
AuthClient authClient = scope.ServiceProvider.GetRequiredService<AuthClient>();
|
||||||
|
|
||||||
|
string? actionTicket = await authClient
|
||||||
|
.GetActionTicketByStokenAsync("game_role", entry.User)
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
|
List<UserGameRole> roles = await scope.ServiceProvider
|
||||||
|
.GetRequiredService<BindingClient>()
|
||||||
|
.GetUserGameRolesByActionTicketAsync(actionTicket!, entry.User)
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
|
string attribution = roles.SingleOrDefault(r => r.GameUid == entry.Uid)?.ToString() ?? "未知角色";
|
||||||
|
|
||||||
|
ToastContentBuilder builder = new ToastContentBuilder()
|
||||||
|
.AddHeader("DAILYNOTE", "实时便笺提醒", "DAILYNOTE")
|
||||||
|
.AddAttributionText(attribution)
|
||||||
|
.AddButton(new ToastButton().SetContent("开始游戏").AddArgument("Action", "LaunchGame").AddArgument("Uid", entry.Uid))
|
||||||
|
.AddButton(new ToastButtonDismiss("我知道了"));
|
||||||
|
|
||||||
if (appDbContext.Settings.SingleOrAdd(SettingEntry.DailyNoteReminderNotify, SettingEntryHelper.FalseString).GetBoolean())
|
if (appDbContext.Settings.SingleOrAdd(SettingEntry.DailyNoteReminderNotify, SettingEntryHelper.FalseString).GetBoolean())
|
||||||
{
|
{
|
||||||
builder.SetToastScenario(ToastScenario.Reminder);
|
builder.SetToastScenario(ToastScenario.Reminder);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (hints.Count > 2)
|
if (hints.Count > 2)
|
||||||
{
|
|
||||||
builder.AddText("多个提醒项达到设定值");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach (string hint in hints)
|
|
||||||
{
|
{
|
||||||
builder.AddText(hint);
|
builder.AddText("多个提醒项达到设定值");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (string hint in hints)
|
||||||
|
{
|
||||||
|
builder.AddText(hint);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
await ThreadHelper.SwitchToMainThreadAsync();
|
await ThreadHelper.SwitchToMainThreadAsync();
|
||||||
builder.Show();
|
builder.Show();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,6 @@
|
|||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using CommunityToolkit.Mvvm.Messaging;
|
using CommunityToolkit.Mvvm.Messaging;
|
||||||
using CommunityToolkit.WinUI.Notifications;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Snap.Hutao.Context.Database;
|
using Snap.Hutao.Context.Database;
|
||||||
@@ -12,9 +11,7 @@ using Snap.Hutao.Message;
|
|||||||
using Snap.Hutao.Model.Binding.User;
|
using Snap.Hutao.Model.Binding.User;
|
||||||
using Snap.Hutao.Model.Entity;
|
using Snap.Hutao.Model.Entity;
|
||||||
using Snap.Hutao.Service.User;
|
using Snap.Hutao.Service.User;
|
||||||
using Snap.Hutao.Web.Hoyolab.Takumi.Binding;
|
|
||||||
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord;
|
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord;
|
||||||
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.DailyNote;
|
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using WebDailyNote = Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.DailyNote.DailyNote;
|
using WebDailyNote = Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.DailyNote.DailyNote;
|
||||||
|
|
||||||
@@ -63,9 +60,9 @@ internal class DailyNoteService : IDailyNoteService, IRecipient<UserRemovedMessa
|
|||||||
{
|
{
|
||||||
DailyNoteEntry newEntry = DailyNoteEntry.Create(role);
|
DailyNoteEntry newEntry = DailyNoteEntry.Create(role);
|
||||||
newEntry.DailyNote = await gameRecordClient.GetDailyNoteAsync(role.User, newEntry.Uid).ConfigureAwait(false);
|
newEntry.DailyNote = await gameRecordClient.GetDailyNoteAsync(role.User, newEntry.Uid).ConfigureAwait(false);
|
||||||
appDbContext.DailyNotes.AddAndSave(newEntry);
|
|
||||||
|
|
||||||
newEntry.UserGameRole = userService.GetUserGameRoleByUid(roleUid);
|
newEntry.UserGameRole = userService.GetUserGameRoleByUid(roleUid);
|
||||||
|
await appDbContext.DailyNotes.AddAndSaveAsync(newEntry).ConfigureAwait(false);
|
||||||
|
|
||||||
await ThreadHelper.SwitchToMainThreadAsync();
|
await ThreadHelper.SwitchToMainThreadAsync();
|
||||||
entries?.Add(newEntry);
|
entries?.Add(newEntry);
|
||||||
}
|
}
|
||||||
@@ -84,7 +81,7 @@ internal class DailyNoteService : IDailyNoteService, IRecipient<UserRemovedMessa
|
|||||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||||
List<DailyNoteEntry> entryList = appDbContext.DailyNotes.AsNoTracking().ToList();
|
List<DailyNoteEntry> entryList = appDbContext.DailyNotes.AsNoTracking().ToList();
|
||||||
entryList.ForEach(entry => { entry.UserGameRole = userService.GetUserGameRoleByUid(entry.Uid); });
|
entryList.ForEach(entry => { entry.UserGameRole = userService.GetUserGameRoleByUid(entry.Uid); });
|
||||||
entries = new(appDbContext.DailyNotes);
|
entries = new(entryList);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,7 +95,6 @@ internal class DailyNoteService : IDailyNoteService, IRecipient<UserRemovedMessa
|
|||||||
{
|
{
|
||||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||||
GameRecordClient gameRecordClient = scope.ServiceProvider.GetRequiredService<GameRecordClient>();
|
GameRecordClient gameRecordClient = scope.ServiceProvider.GetRequiredService<GameRecordClient>();
|
||||||
BindingClient bindingClient = scope.ServiceProvider.GetRequiredService<BindingClient>();
|
|
||||||
|
|
||||||
foreach (DailyNoteEntry entry in appDbContext.DailyNotes.Include(n => n.User))
|
foreach (DailyNoteEntry entry in appDbContext.DailyNotes.Include(n => n.User))
|
||||||
{
|
{
|
||||||
@@ -113,7 +109,7 @@ internal class DailyNoteService : IDailyNoteService, IRecipient<UserRemovedMessa
|
|||||||
|
|
||||||
if (notify)
|
if (notify)
|
||||||
{
|
{
|
||||||
await new DailyNoteNotifier(scopeFactory, bindingClient, entry).NotifyAsync().ConfigureAwait(false);
|
await new DailyNoteNotifier(scopeFactory, entry).NotifyAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Snap.Hutao.Context.Database;
|
using Snap.Hutao.Context.Database;
|
||||||
using Snap.Hutao.Core.Database;
|
using Snap.Hutao.Core.Database;
|
||||||
using Snap.Hutao.Extension;
|
using Snap.Hutao.Extension;
|
||||||
|
|||||||
@@ -244,9 +244,10 @@ internal class GameService : IGameService, IDisposable
|
|||||||
string commandLine = new CommandLineBuilder()
|
string commandLine = new CommandLineBuilder()
|
||||||
.AppendIf("-popupwindow", configuration.IsBorderless)
|
.AppendIf("-popupwindow", configuration.IsBorderless)
|
||||||
.Append("-screen-fullscreen", configuration.IsFullScreen ? 1 : 0)
|
.Append("-screen-fullscreen", configuration.IsFullScreen ? 1 : 0)
|
||||||
|
.AppendIf("-window-mode", configuration.IsExclusive, "exclusive")
|
||||||
.Append("-screen-width", configuration.ScreenWidth)
|
.Append("-screen-width", configuration.ScreenWidth)
|
||||||
.Append("-screen-height", configuration.ScreenHeight)
|
.Append("-screen-height", configuration.ScreenHeight)
|
||||||
.Build();
|
.ToString();
|
||||||
|
|
||||||
Process game = new()
|
Process game = new()
|
||||||
{
|
{
|
||||||
@@ -310,10 +311,6 @@ internal class GameService : IGameService, IDisposable
|
|||||||
{
|
{
|
||||||
account = GameAccount.Create(name, registrySdk);
|
account = GameAccount.Create(name, registrySdk);
|
||||||
|
|
||||||
// sync cache
|
|
||||||
await ThreadHelper.SwitchToMainThreadAsync();
|
|
||||||
gameAccounts.Add(GameAccount.Create(name, registrySdk));
|
|
||||||
|
|
||||||
// sync database
|
// sync database
|
||||||
await ThreadHelper.SwitchToBackgroundAsync();
|
await ThreadHelper.SwitchToBackgroundAsync();
|
||||||
using (IServiceScope scope = scopeFactory.CreateScope())
|
using (IServiceScope scope = scopeFactory.CreateScope())
|
||||||
@@ -324,6 +321,10 @@ internal class GameService : IGameService, IDisposable
|
|||||||
.AddAndSaveAsync(account)
|
.AddAndSaveAsync(account)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sync cache
|
||||||
|
await ThreadHelper.SwitchToMainThreadAsync();
|
||||||
|
gameAccounts.Add(account);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,11 @@ namespace Snap.Hutao.Service.Game;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal readonly struct LaunchConfiguration
|
internal readonly struct LaunchConfiguration
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 是否为独占全屏
|
||||||
|
/// </summary>
|
||||||
|
public readonly bool IsExclusive;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 是否全屏,全屏时无边框设置将被覆盖
|
/// 是否全屏,全屏时无边框设置将被覆盖
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -41,14 +46,16 @@ internal readonly struct LaunchConfiguration
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 构造一个新的启动配置
|
/// 构造一个新的启动配置
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="isExclusive">独占全屏</param>
|
||||||
/// <param name="isFullScreen">全屏</param>
|
/// <param name="isFullScreen">全屏</param>
|
||||||
/// <param name="isBorderless">无边框</param>
|
/// <param name="isBorderless">无边框</param>
|
||||||
/// <param name="screenWidth">宽度</param>
|
/// <param name="screenWidth">宽度</param>
|
||||||
/// <param name="screenHeight">高度</param>
|
/// <param name="screenHeight">高度</param>
|
||||||
/// <param name="unlockFps">解锁帧率</param>
|
/// <param name="unlockFps">解锁帧率</param>
|
||||||
/// <param name="targetFps">目标帧率</param>
|
/// <param name="targetFps">目标帧率</param>
|
||||||
public LaunchConfiguration(bool isFullScreen, bool isBorderless, int screenWidth, int screenHeight, bool unlockFps, int targetFps)
|
public LaunchConfiguration(bool isExclusive, bool isFullScreen, bool isBorderless, int screenWidth, int screenHeight, bool unlockFps, int targetFps)
|
||||||
{
|
{
|
||||||
|
IsExclusive = isExclusive;
|
||||||
IsFullScreen = isFullScreen;
|
IsFullScreen = isFullScreen;
|
||||||
IsBorderless = isBorderless;
|
IsBorderless = isBorderless;
|
||||||
ScreenHeight = screenHeight;
|
ScreenHeight = screenHeight;
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ internal partial class UnityLogGameLocator : IGameLocator
|
|||||||
string appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
|
string appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
|
||||||
string logFilePath = Path.Combine(appDataPath, @"..\LocalLow\miHoYo\原神\output_log.txt");
|
string logFilePath = Path.Combine(appDataPath, @"..\LocalLow\miHoYo\原神\output_log.txt");
|
||||||
|
|
||||||
using (var tempFile = TemporaryFile.CreateFromFileCopy(logFilePath))
|
using (TemporaryFile? tempFile = TemporaryFile.CreateFromFileCopy(logFilePath))
|
||||||
{
|
{
|
||||||
if (tempFile == null)
|
if (tempFile == null)
|
||||||
{
|
{
|
||||||
@@ -32,7 +32,7 @@ internal partial class UnityLogGameLocator : IGameLocator
|
|||||||
|
|
||||||
string content = File.ReadAllText(tempFile.Path);
|
string content = File.ReadAllText(tempFile.Path);
|
||||||
|
|
||||||
var matchResult = WarmupFileLine().Match(content);
|
Match matchResult = WarmupFileLine().Match(content);
|
||||||
if (!matchResult.Success)
|
if (!matchResult.Success)
|
||||||
{
|
{
|
||||||
return new(false, $"在 Unity 日志文件中找不到游戏路径");
|
return new(false, $"在 Unity 日志文件中找不到游戏路径");
|
||||||
|
|||||||
@@ -150,9 +150,12 @@ internal class GameFpsUnlocker : IGameFpsUnlocker
|
|||||||
|
|
||||||
Must.Range(adr >= 0, "未匹配到FPS字节");
|
Must.Range(adr >= 0, "未匹配到FPS字节");
|
||||||
|
|
||||||
int rip = adr + 2;
|
fixed (byte* pSpan = image)
|
||||||
int rel = image.Fixed<int>(rip + 2); // Unsafe.ReadUnaligned<int>(ref image[rip + 2]);
|
{
|
||||||
int ofs = rip + rel + 6;
|
int rip = adr + 2;
|
||||||
fpsAddress = (nuint)((long)unityPlayer.modBaseAddr + ofs);
|
int rel = *(int*)(pSpan + rip + 2); // Unsafe.ReadUnaligned<int>(ref image[rip + 2]);
|
||||||
|
int ofs = rip + rel + 6;
|
||||||
|
fpsAddress = (nuint)((long)unityPlayer.modBaseAddr + ofs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -64,6 +64,13 @@ internal interface IMetadataService
|
|||||||
/// <returns>Id到角色的字典</returns>
|
/// <returns>Id到角色的字典</returns>
|
||||||
ValueTask<Dictionary<AvatarId, Avatar>> GetIdToAvatarMapAsync(CancellationToken token = default);
|
ValueTask<Dictionary<AvatarId, Avatar>> GetIdToAvatarMapAsync(CancellationToken token = default);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步获取Id到材料的字典
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="token">取消令牌</param>
|
||||||
|
/// <returns>Id到材料的字典</returns>
|
||||||
|
ValueTask<Dictionary<MaterialId, Material>> GetIdToMaterialMapAsync(CancellationToken token = default(CancellationToken));
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 异步获取ID到圣遗物副词条的字典
|
/// 异步获取ID到圣遗物副词条的字典
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using Snap.Hutao.Model.Intrinsic;
|
using Snap.Hutao.Model.Intrinsic;
|
||||||
|
using Snap.Hutao.Model.Metadata;
|
||||||
using Snap.Hutao.Model.Metadata.Avatar;
|
using Snap.Hutao.Model.Metadata.Avatar;
|
||||||
using Snap.Hutao.Model.Metadata.Reliquary;
|
using Snap.Hutao.Model.Metadata.Reliquary;
|
||||||
using Snap.Hutao.Model.Metadata.Weapon;
|
using Snap.Hutao.Model.Metadata.Weapon;
|
||||||
@@ -26,6 +27,12 @@ internal partial class MetadataService
|
|||||||
return FromCacheAsDictionaryAsync<AvatarId, Avatar>("Avatar", a => a.Id, token);
|
return FromCacheAsDictionaryAsync<AvatarId, Avatar>("Avatar", a => a.Id, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public ValueTask<Dictionary<MaterialId, Material>> GetIdToMaterialMapAsync(CancellationToken token = default)
|
||||||
|
{
|
||||||
|
return FromCacheAsDictionaryAsync<MaterialId, Material>("Material", a => a.Id, token);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ValueTask<Dictionary<ReliquaryAffixId, ReliquaryAffix>> GetIdReliquaryAffixMapAsync(CancellationToken token = default)
|
public ValueTask<Dictionary<ReliquaryAffixId, ReliquaryAffix>> GetIdReliquaryAffixMapAsync(CancellationToken token = default)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -5,7 +5,9 @@
|
|||||||
<TargetPlatformMinVersion>10.0.18362.0</TargetPlatformMinVersion>
|
<TargetPlatformMinVersion>10.0.18362.0</TargetPlatformMinVersion>
|
||||||
<RootNamespace>Snap.Hutao</RootNamespace>
|
<RootNamespace>Snap.Hutao</RootNamespace>
|
||||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||||
|
<Platform>x64</Platform>
|
||||||
<Platforms>x64</Platforms>
|
<Platforms>x64</Platforms>
|
||||||
|
<RuntimeIdentifier>win10-x64</RuntimeIdentifier>
|
||||||
<RuntimeIdentifiers>win10-x64</RuntimeIdentifiers>
|
<RuntimeIdentifiers>win10-x64</RuntimeIdentifiers>
|
||||||
<PublishProfile>win10-$(Platform).pubxml</PublishProfile>
|
<PublishProfile>win10-$(Platform).pubxml</PublishProfile>
|
||||||
<UseWinUI>true</UseWinUI>
|
<UseWinUI>true</UseWinUI>
|
||||||
@@ -69,6 +71,7 @@
|
|||||||
<None Remove="View\Dialog\AchievementImportDialog.xaml" />
|
<None Remove="View\Dialog\AchievementImportDialog.xaml" />
|
||||||
<None Remove="View\Dialog\AdoptCalculatorDialog.xaml" />
|
<None Remove="View\Dialog\AdoptCalculatorDialog.xaml" />
|
||||||
<None Remove="View\Dialog\AvatarInfoQueryDialog.xaml" />
|
<None Remove="View\Dialog\AvatarInfoQueryDialog.xaml" />
|
||||||
|
<None Remove="View\Dialog\CommunityGameRecordDialog.xaml" />
|
||||||
<None Remove="View\Dialog\CultivateProjectDialog.xaml" />
|
<None Remove="View\Dialog\CultivateProjectDialog.xaml" />
|
||||||
<None Remove="View\Dialog\CultivatePromotionDeltaDialog.xaml" />
|
<None Remove="View\Dialog\CultivatePromotionDeltaDialog.xaml" />
|
||||||
<None Remove="View\Dialog\DailyNoteNotificationDialog.xaml" />
|
<None Remove="View\Dialog\DailyNoteNotificationDialog.xaml" />
|
||||||
@@ -136,7 +139,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.1.0-preview2" />
|
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.1.0-preview3" />
|
||||||
<PackageReference Include="CommunityToolkit.WinUI.Notifications" Version="7.1.2" />
|
<PackageReference Include="CommunityToolkit.WinUI.Notifications" Version="7.1.2" />
|
||||||
<PackageReference Include="CommunityToolkit.WinUI.UI.Behaviors" Version="7.1.2" />
|
<PackageReference Include="CommunityToolkit.WinUI.UI.Behaviors" Version="7.1.2" />
|
||||||
<PackageReference Include="CommunityToolkit.WinUI.UI.Controls" Version="7.1.2" />
|
<PackageReference Include="CommunityToolkit.WinUI.UI.Controls" Version="7.1.2" />
|
||||||
@@ -153,7 +156,7 @@
|
|||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.VisualStudio.Validation" Version="17.0.64" />
|
<PackageReference Include="Microsoft.VisualStudio.Validation" Version="17.0.64" />
|
||||||
<PackageReference Include="Microsoft.Windows.CsWin32" Version="0.2.164-beta">
|
<PackageReference Include="Microsoft.Windows.CsWin32" Version="0.2.138-beta">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
@@ -181,6 +184,11 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="..\.editorconfig" Link=".editorconfig" />
|
<None Include="..\.editorconfig" Link=".editorconfig" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Page Update="View\Dialog\CommunityGameRecordDialog.xaml">
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Page>
|
||||||
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Page Update="View\Dialog\CultivatePromotionDeltaDialog.xaml">
|
<Page Update="View\Dialog\CultivatePromotionDeltaDialog.xaml">
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
|||||||
@@ -41,8 +41,8 @@ public sealed partial class DescParamComboBox : UserControl
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public int PreferredSelectedIndex
|
public int PreferredSelectedIndex
|
||||||
{
|
{
|
||||||
get { return (int)GetValue(PreferredSelectedIndexProperty); }
|
get => (int)GetValue(PreferredSelectedIndexProperty);
|
||||||
set { SetValue(PreferredSelectedIndexProperty, value); }
|
set => SetValue(PreferredSelectedIndexProperty, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void OnSourceChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
|
private static void OnSourceChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
|
||||||
@@ -54,7 +54,7 @@ public sealed partial class DescParamComboBox : UserControl
|
|||||||
if (args.NewValue != args.OldValue && args.NewValue is IList<LevelParam<string, ParameterInfo>> list)
|
if (args.NewValue != args.OldValue && args.NewValue is IList<LevelParam<string, ParameterInfo>> list)
|
||||||
{
|
{
|
||||||
descParamComboBox.ItemHost.ItemsSource = list;
|
descParamComboBox.ItemHost.ItemsSource = list;
|
||||||
descParamComboBox.ItemHost.SelectedIndex = Math.Min(descParamComboBox.PreferredSelectedIndex, list.Count);
|
descParamComboBox.ItemHost.SelectedIndex = Math.Min(descParamComboBox.PreferredSelectedIndex, list.Count - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<!-- Copyright (c) Microsoft Corporation and Contributors. -->
|
||||||
|
<!-- Licensed under the MIT License. -->
|
||||||
|
|
||||||
|
<ContentDialog
|
||||||
|
x:Class="Snap.Hutao.View.Dialog.CommunityGameRecordDialog"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
Closed="OnContentDialogClosed"
|
||||||
|
DefaultButton="Primary"
|
||||||
|
PrimaryButtonText="完成"
|
||||||
|
Style="{StaticResource DefaultContentDialogStyle}"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
|
||||||
|
<Grid Loaded="OnGridLoaded">
|
||||||
|
<WebView2
|
||||||
|
Name="WebView"
|
||||||
|
Width="360"
|
||||||
|
Height="580"/>
|
||||||
|
</Grid>
|
||||||
|
</ContentDialog>
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation and Contributors.
|
||||||
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.UI.Xaml;
|
||||||
|
using Microsoft.UI.Xaml.Controls;
|
||||||
|
using Microsoft.Web.WebView2.Core;
|
||||||
|
using Snap.Hutao.Model.Binding.User;
|
||||||
|
using Snap.Hutao.Service.User;
|
||||||
|
using Snap.Hutao.Web.Bridge;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.View.Dialog;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϸ<EFBFBD><CFB7>¼<EFBFBD>Ի<EFBFBD><D4BB><EFBFBD>
|
||||||
|
/// </summary>
|
||||||
|
public sealed partial class CommunityGameRecordDialog : ContentDialog
|
||||||
|
{
|
||||||
|
private readonly IServiceScope scope;
|
||||||
|
[SuppressMessage("", "IDE0052")]
|
||||||
|
private MiHoYoJSInterface? jsInterface;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <20><><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD>µ<EFBFBD><C2B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϸ<EFBFBD><CFB7>¼<EFBFBD>Ի<EFBFBD><D4BB><EFBFBD>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="window"><3E><><EFBFBD><EFBFBD></param>
|
||||||
|
public CommunityGameRecordDialog(MainWindow window)
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
XamlRoot = window.Content.XamlRoot;
|
||||||
|
scope = Ioc.Default.CreateScope();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnGridLoaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
InitializeAsync().SafeForget();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task InitializeAsync()
|
||||||
|
{
|
||||||
|
await WebView.EnsureCoreWebView2Async();
|
||||||
|
CoreWebView2 coreWebView2 = WebView.CoreWebView2;
|
||||||
|
User? user = scope.ServiceProvider.GetRequiredService<IUserService>().Current;
|
||||||
|
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
coreWebView2.SetCookie(user.CookieToken, user.Ltoken, null).SetMobileUserAgent();
|
||||||
|
jsInterface = new(coreWebView2, scope.ServiceProvider);
|
||||||
|
coreWebView2.Navigate("https://webstatic.mihoyo.com/app/community-game-records/index.html");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnContentDialogClosed(ContentDialog sender, ContentDialogClosedEventArgs args)
|
||||||
|
{
|
||||||
|
jsInterface = null;
|
||||||
|
scope.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,20 +3,8 @@
|
|||||||
|
|
||||||
using Microsoft.UI.Xaml;
|
using Microsoft.UI.Xaml;
|
||||||
using Microsoft.UI.Xaml.Controls;
|
using Microsoft.UI.Xaml.Controls;
|
||||||
using Microsoft.UI.Xaml.Controls.Primitives;
|
|
||||||
using Microsoft.UI.Xaml.Data;
|
|
||||||
using Microsoft.UI.Xaml.Input;
|
|
||||||
using Microsoft.UI.Xaml.Media;
|
|
||||||
using Microsoft.UI.Xaml.Navigation;
|
|
||||||
using Snap.Hutao.Model.Entity;
|
using Snap.Hutao.Model.Entity;
|
||||||
using Snap.Hutao.Service.User;
|
using Snap.Hutao.Service.User;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.InteropServices.WindowsRuntime;
|
|
||||||
using Windows.Foundation;
|
|
||||||
using Windows.Foundation.Collections;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.View.Dialog;
|
namespace Snap.Hutao.View.Dialog;
|
||||||
|
|
||||||
|
|||||||
@@ -36,8 +36,8 @@ public sealed partial class CultivatePromotionDeltaDialog : ContentDialog
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public ICalculableAvatar? Avatar
|
public ICalculableAvatar? Avatar
|
||||||
{
|
{
|
||||||
get { return (ICalculableAvatar?)GetValue(AvatarProperty); }
|
get => (ICalculableAvatar?)GetValue(AvatarProperty);
|
||||||
set { SetValue(AvatarProperty, value); }
|
set => SetValue(AvatarProperty, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -45,8 +45,8 @@ public sealed partial class CultivatePromotionDeltaDialog : ContentDialog
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public ICalculableWeapon? Weapon
|
public ICalculableWeapon? Weapon
|
||||||
{
|
{
|
||||||
get { return (ICalculableWeapon?)GetValue(WeaponProperty); }
|
get => (ICalculableWeapon?)GetValue(WeaponProperty);
|
||||||
set { SetValue(WeaponProperty, value); }
|
set => SetValue(WeaponProperty, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -50,9 +50,6 @@ public sealed partial class DailyNoteVerificationDialog : ContentDialog
|
|||||||
coreWebView2.SetCookie(user.CookieToken, user.Ltoken, null).SetMobileUserAgent();
|
coreWebView2.SetCookie(user.CookieToken, user.Ltoken, null).SetMobileUserAgent();
|
||||||
dailyNoteJsInterface = new(coreWebView2, scope.ServiceProvider);
|
dailyNoteJsInterface = new(coreWebView2, scope.ServiceProvider);
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
coreWebView2.OpenDevToolsWindow();
|
|
||||||
#endif
|
|
||||||
string query = $"?role_id={uid.Value}&server={uid.Region}";
|
string query = $"?role_id={uid.Value}&server={uid.Region}";
|
||||||
coreWebView2.Navigate($"https://webstatic.mihoyo.com/app/community-game-records/index.html?bbs_presentation_style=fullscreen#/ys/daily/{query}");
|
coreWebView2.Navigate($"https://webstatic.mihoyo.com/app/community-game-records/index.html?bbs_presentation_style=fullscreen#/ys/daily/{query}");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,8 +39,7 @@ public sealed partial class SignInWebViewDialog : ContentDialog
|
|||||||
{
|
{
|
||||||
await WebView.EnsureCoreWebView2Async();
|
await WebView.EnsureCoreWebView2Async();
|
||||||
CoreWebView2 coreWebView2 = WebView.CoreWebView2;
|
CoreWebView2 coreWebView2 = WebView.CoreWebView2;
|
||||||
IUserService userService = scope.ServiceProvider.GetRequiredService<IUserService>();
|
User? user = scope.ServiceProvider.GetRequiredService<IUserService>().Current;
|
||||||
User? user = userService.Current;
|
|
||||||
|
|
||||||
if (user == null)
|
if (user == null)
|
||||||
{
|
{
|
||||||
@@ -49,10 +48,6 @@ public sealed partial class SignInWebViewDialog : ContentDialog
|
|||||||
|
|
||||||
coreWebView2.SetCookie(user.CookieToken, user.Ltoken, null).SetMobileUserAgent();
|
coreWebView2.SetCookie(user.CookieToken, user.Ltoken, null).SetMobileUserAgent();
|
||||||
signInJsInterface = new(coreWebView2, scope.ServiceProvider);
|
signInJsInterface = new(coreWebView2, scope.ServiceProvider);
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
coreWebView2.OpenDevToolsWindow();
|
|
||||||
#endif
|
|
||||||
coreWebView2.Navigate("https://webstatic.mihoyo.com/bbs/event/signin-ys/index.html?act_id=e202009291139501");
|
coreWebView2.Navigate("https://webstatic.mihoyo.com/bbs/event/signin-ys/index.html?act_id=e202009291139501");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,4 +56,4 @@ public sealed partial class SignInWebViewDialog : ContentDialog
|
|||||||
signInJsInterface = null;
|
signInJsInterface = null;
|
||||||
scope.Dispose();
|
scope.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -15,6 +15,10 @@
|
|||||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
|
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
|
|
||||||
|
<Page.Resources>
|
||||||
|
<shc:BindingProxy x:Key="BindingProxy" DataContext="{Binding}"/>
|
||||||
|
</Page.Resources>
|
||||||
|
|
||||||
<mxi:Interaction.Behaviors>
|
<mxi:Interaction.Behaviors>
|
||||||
<shcb:InvokeCommandOnLoadedBehavior Command="{Binding OpenUICommand}"/>
|
<shcb:InvokeCommandOnLoadedBehavior Command="{Binding OpenUICommand}"/>
|
||||||
</mxi:Interaction.Behaviors>
|
</mxi:Interaction.Behaviors>
|
||||||
@@ -30,6 +34,12 @@
|
|||||||
<ColumnDefinition/>
|
<ColumnDefinition/>
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Margin="16,0,0,2"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource SubtitleTextBlockStyle}"
|
||||||
|
Text="{Binding FinishDescription}"/>
|
||||||
|
|
||||||
<CommandBar Grid.Column="1" DefaultLabelPosition="Right">
|
<CommandBar Grid.Column="1" DefaultLabelPosition="Right">
|
||||||
|
|
||||||
<CommandBar.Content>
|
<CommandBar.Content>
|
||||||
@@ -71,7 +81,6 @@
|
|||||||
Command="{Binding RemoveArchiveCommand}"
|
Command="{Binding RemoveArchiveCommand}"
|
||||||
Icon="{shcm:FontIcon Glyph=}"
|
Icon="{shcm:FontIcon Glyph=}"
|
||||||
Label="删除当前存档"/>
|
Label="删除当前存档"/>
|
||||||
|
|
||||||
<AppBarSeparator/>
|
<AppBarSeparator/>
|
||||||
|
|
||||||
<AppBarButton Icon="{shcm:FontIcon Glyph=}" Label="导入">
|
<AppBarButton Icon="{shcm:FontIcon Glyph=}" Label="导入">
|
||||||
@@ -93,6 +102,7 @@
|
|||||||
Icon="{shcm:FontIcon Glyph=}"
|
Icon="{shcm:FontIcon Glyph=}"
|
||||||
Label="导出"/>
|
Label="导出"/>
|
||||||
<AppBarSeparator/>
|
<AppBarSeparator/>
|
||||||
|
|
||||||
<AppBarToggleButton
|
<AppBarToggleButton
|
||||||
Command="{Binding SortIncompletedSwitchCommand}"
|
Command="{Binding SortIncompletedSwitchCommand}"
|
||||||
Icon="{shcm:FontIcon Glyph=}"
|
Icon="{shcm:FontIcon Glyph=}"
|
||||||
@@ -114,21 +124,31 @@
|
|||||||
SelectionMode="Single">
|
SelectionMode="Single">
|
||||||
<ListView.ItemTemplate>
|
<ListView.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<Grid>
|
<Grid Margin="0,6">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="24"/>
|
<ColumnDefinition Width="36"/>
|
||||||
<ColumnDefinition/>
|
<ColumnDefinition/>
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<shci:CachedImage
|
<shci:CachedImage
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Width="24"
|
Width="36"
|
||||||
Height="24"
|
Height="36"
|
||||||
Source="{Binding Icon, Converter={StaticResource AchievementIconConverter}}"/>
|
Source="{Binding Icon}"/>
|
||||||
<TextBlock
|
<StackPanel Grid.Column="1" Margin="12,0,0,2">
|
||||||
Grid.Column="1"
|
<TextBlock VerticalAlignment="Center" Text="{Binding Name}"/>
|
||||||
Margin="12,0,0,2"
|
<TextBlock
|
||||||
VerticalAlignment="Center"
|
Margin="0,2,0,0"
|
||||||
Text="{Binding Name}"/>
|
VerticalAlignment="Center"
|
||||||
|
Opacity="0.7"
|
||||||
|
Style="{StaticResource CaptionTextBlockStyle}"
|
||||||
|
Text="{Binding FinishDescription}"/>
|
||||||
|
<ProgressBar
|
||||||
|
Height="1"
|
||||||
|
MinHeight="1"
|
||||||
|
Margin="0,4,0,0"
|
||||||
|
Maximum="1"
|
||||||
|
Value="{Binding FinishPercent}"/>
|
||||||
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ListView.ItemTemplate>
|
</ListView.ItemTemplate>
|
||||||
@@ -163,6 +183,8 @@
|
|||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Margin="6,0,12,0"
|
Margin="6,0,12,0"
|
||||||
Padding="16,0,0,0"
|
Padding="16,0,0,0"
|
||||||
|
Command="{Binding Path=DataContext.SaveAchievementCommand, Source={StaticResource BindingProxy}}"
|
||||||
|
CommandParameter="{Binding}"
|
||||||
IsChecked="{Binding IsChecked, Mode=TwoWay}"
|
IsChecked="{Binding IsChecked, Mode=TwoWay}"
|
||||||
Style="{StaticResource DefaultCheckBoxStyle}">
|
Style="{StaticResource DefaultCheckBoxStyle}">
|
||||||
<CheckBox.Content>
|
<CheckBox.Content>
|
||||||
|
|||||||
@@ -142,6 +142,13 @@
|
|||||||
<Grid>
|
<Grid>
|
||||||
<ScrollViewer Padding="0,0,4,0">
|
<ScrollViewer Padding="0,0,4,0">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
|
<ItemsControl>
|
||||||
|
<ItemsControl.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<InfoBar/>
|
||||||
|
</DataTemplate>
|
||||||
|
</ItemsControl.ItemTemplate>
|
||||||
|
</ItemsControl>
|
||||||
<Pivot>
|
<Pivot>
|
||||||
<PivotItem
|
<PivotItem
|
||||||
Content="{Binding Announcement.List[0]}"
|
Content="{Binding Announcement.List[0]}"
|
||||||
|
|||||||
@@ -58,6 +58,11 @@
|
|||||||
CommandParameter="{Binding ElementName=ImageExportPanel}"
|
CommandParameter="{Binding ElementName=ImageExportPanel}"
|
||||||
Icon="{shcm:FontIcon Glyph=}"
|
Icon="{shcm:FontIcon Glyph=}"
|
||||||
Label="导出图片"/>
|
Label="导出图片"/>
|
||||||
|
<AppBarButton
|
||||||
|
Command="{Binding CultivateCommand}"
|
||||||
|
CommandParameter="{Binding SelectedAvatar}"
|
||||||
|
Icon="{shcm:FontIcon Glyph=}"
|
||||||
|
Label="养成计算"/>
|
||||||
<AppBarSeparator/>
|
<AppBarSeparator/>
|
||||||
<AppBarButton Icon="{shcm:FontIcon Glyph=}" Label="同步角色信息">
|
<AppBarButton Icon="{shcm:FontIcon Glyph=}" Label="同步角色信息">
|
||||||
<AppBarButton.Flyout>
|
<AppBarButton.Flyout>
|
||||||
@@ -129,7 +134,7 @@
|
|||||||
</cwucont:SwitchPresenter>
|
</cwucont:SwitchPresenter>
|
||||||
</SplitView.Pane>
|
</SplitView.Pane>
|
||||||
<SplitView.Content>
|
<SplitView.Content>
|
||||||
<ScrollViewer Padding="0,0,0,-88">
|
<ScrollViewer Padding="0,0,0,0">
|
||||||
<StackPanel
|
<StackPanel
|
||||||
Name="ImageExportPanel"
|
Name="ImageExportPanel"
|
||||||
MaxWidth="800"
|
MaxWidth="800"
|
||||||
@@ -551,30 +556,6 @@
|
|||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ItemsControl.ItemTemplate>
|
</ItemsControl.ItemTemplate>
|
||||||
</ItemsControl>
|
</ItemsControl>
|
||||||
<Border
|
|
||||||
Margin="16,0,16,16"
|
|
||||||
Background="{StaticResource CardBackgroundFillColorDefault}"
|
|
||||||
BorderBrush="{StaticResource CardStrokeColorDefault}"
|
|
||||||
BorderThickness="1"
|
|
||||||
CornerRadius="{StaticResource CompatCornerRadius}">
|
|
||||||
<Grid Margin="16">
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition/>
|
|
||||||
<ColumnDefinition Width="auto"/>
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<TextBlock Style="{StaticResource TitleTextBlockStyle}" Text="{Binding Summary.Player.Nickname}"/>
|
|
||||||
<StackPanel Grid.Column="1">
|
|
||||||
<TextBlock
|
|
||||||
HorizontalAlignment="Right"
|
|
||||||
Style="{StaticResource BaseTextBlockStyle}"
|
|
||||||
Text="Created by Snap Hutao"/>
|
|
||||||
<TextBlock
|
|
||||||
HorizontalAlignment="Right"
|
|
||||||
Style="{StaticResource CaptionTextBlockStyle}"
|
|
||||||
Text="官网 hut.ao"/>
|
|
||||||
</StackPanel>
|
|
||||||
</Grid>
|
|
||||||
</Border>
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</SplitView.Content>
|
</SplitView.Content>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
x:Class="Snap.Hutao.View.Page.CultivationPage"
|
x:Class="Snap.Hutao.View.Page.CultivationPage"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:cwua="using:CommunityToolkit.WinUI.UI.Animations"
|
||||||
xmlns:cwucont="using:CommunityToolkit.WinUI.UI.Controls"
|
xmlns:cwucont="using:CommunityToolkit.WinUI.UI.Controls"
|
||||||
xmlns:cwuconv="using:CommunityToolkit.WinUI.UI.Converters"
|
xmlns:cwuconv="using:CommunityToolkit.WinUI.UI.Converters"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
@@ -29,6 +30,11 @@
|
|||||||
<x:Double>1</x:Double>
|
<x:Double>1</x:Double>
|
||||||
</cwuconv:BoolToObjectConverter.FalseValue>
|
</cwuconv:BoolToObjectConverter.FalseValue>
|
||||||
</cwuconv:BoolToObjectConverter>
|
</cwuconv:BoolToObjectConverter>
|
||||||
|
|
||||||
|
<cwuconv:BoolToObjectConverter
|
||||||
|
x:Key="BoolToStyleSelector"
|
||||||
|
FalseValue="{StaticResource BodyTextBlockStyle}"
|
||||||
|
TrueValue="{StaticResource BaseTextBlockStyle}"/>
|
||||||
</Page.Resources>
|
</Page.Resources>
|
||||||
|
|
||||||
<mxi:Interaction.Behaviors>
|
<mxi:Interaction.Behaviors>
|
||||||
@@ -43,6 +49,54 @@
|
|||||||
<Pivot>
|
<Pivot>
|
||||||
<Pivot.RightHeader>
|
<Pivot.RightHeader>
|
||||||
<CommandBar DefaultLabelPosition="Right">
|
<CommandBar DefaultLabelPosition="Right">
|
||||||
|
<AppBarButton
|
||||||
|
Command="{Binding UpdateStatisticsItemsCommand}"
|
||||||
|
Icon="{shcm:FontIcon Glyph=}"
|
||||||
|
Label="材料统计">
|
||||||
|
<AppBarButton.Flyout>
|
||||||
|
<Flyout Placement="Bottom">
|
||||||
|
<Flyout.FlyoutPresenterStyle>
|
||||||
|
<Style BasedOn="{StaticResource DefaultFlyoutPresenterStyle}" TargetType="FlyoutPresenter">
|
||||||
|
<Setter Property="MaxHeight" Value="480"/>
|
||||||
|
<Setter Property="Padding" Value="0,2,0,2"/>
|
||||||
|
<Setter Property="Background" Value="{ThemeResource FlyoutPresenterBackground}"/>
|
||||||
|
</Style>
|
||||||
|
</Flyout.FlyoutPresenterStyle>
|
||||||
|
<ItemsControl Margin="16,0,16,16" ItemsSource="{Binding StatisticsItems}">
|
||||||
|
<ItemsControl.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<Grid Margin="0,16,0,0">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="auto"/>
|
||||||
|
<ColumnDefinition Width="160"/>
|
||||||
|
<ColumnDefinition/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<shvc:ItemIcon
|
||||||
|
Grid.Column="0"
|
||||||
|
Width="32"
|
||||||
|
Height="32"
|
||||||
|
Icon="{Binding Inner.Icon, Converter={StaticResource ItemIconConverter}}"
|
||||||
|
Quality="{Binding Inner.RankLevel}"/>
|
||||||
|
<TextBlock
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="16,0,0,0"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{Binding Inner.Name}"
|
||||||
|
TextTrimming="CharacterEllipsis"/>
|
||||||
|
<TextBlock
|
||||||
|
Grid.Column="2"
|
||||||
|
Margin="16,0,4,0"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{Binding CountFormatted}"/>
|
||||||
|
</Grid>
|
||||||
|
</DataTemplate>
|
||||||
|
</ItemsControl.ItemTemplate>
|
||||||
|
</ItemsControl>
|
||||||
|
</Flyout>
|
||||||
|
</AppBarButton.Flyout>
|
||||||
|
</AppBarButton>
|
||||||
|
<AppBarSeparator/>
|
||||||
<AppBarElementContainer>
|
<AppBarElementContainer>
|
||||||
<ComboBox
|
<ComboBox
|
||||||
Height="36"
|
Height="36"
|
||||||
@@ -71,7 +125,8 @@
|
|||||||
<PivotItem Header="材料清单">
|
<PivotItem Header="材料清单">
|
||||||
<cwucont:AdaptiveGridView
|
<cwucont:AdaptiveGridView
|
||||||
Padding="16,16,4,4"
|
Padding="16,16,4,4"
|
||||||
DesiredWidth="360"
|
cwua:ItemsReorderAnimation.Duration="0:0:0.1"
|
||||||
|
DesiredWidth="320"
|
||||||
ItemContainerStyle="{StaticResource LargeGridViewItemStyle}"
|
ItemContainerStyle="{StaticResource LargeGridViewItemStyle}"
|
||||||
ItemsSource="{Binding CultivateEntries}"
|
ItemsSource="{Binding CultivateEntries}"
|
||||||
SelectionMode="None">
|
SelectionMode="None">
|
||||||
@@ -81,7 +136,7 @@
|
|||||||
<Grid Background="Transparent">
|
<Grid Background="Transparent">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="auto"/>
|
<RowDefinition Height="auto"/>
|
||||||
<RowDefinition/>
|
<RowDefinition Height="auto"/>
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Grid Margin="8">
|
<Grid Margin="8">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
@@ -115,64 +170,65 @@
|
|||||||
ToolTipService.ToolTip="删除清单"/>
|
ToolTipService.ToolTip="删除清单"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
<ItemsControl
|
<ScrollViewer Grid.Row="1" Height="240">
|
||||||
Grid.Row="1"
|
<ItemsControl Margin="8,0,8,8" ItemsSource="{Binding Items}">
|
||||||
Margin="8,0,8,8"
|
<ItemsControl.ItemTemplate>
|
||||||
ItemsSource="{Binding Items}">
|
<DataTemplate>
|
||||||
<ItemsControl.ItemTemplate>
|
<Grid Margin="0,4,0,0">
|
||||||
<DataTemplate>
|
<Grid.ColumnDefinitions>
|
||||||
<Grid Margin="0,4,0,0">
|
<ColumnDefinition Width="auto"/>
|
||||||
<Grid.ColumnDefinitions>
|
<ColumnDefinition/>
|
||||||
<ColumnDefinition Width="auto"/>
|
</Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition/>
|
<Grid>
|
||||||
</Grid.ColumnDefinitions>
|
<shvc:ItemIcon
|
||||||
<Grid>
|
Width="32"
|
||||||
<shvc:ItemIcon
|
Height="32"
|
||||||
Width="32"
|
Icon="{Binding Inner.Icon, Converter={StaticResource ItemIconConverter}}"
|
||||||
Height="32"
|
Opacity="{Binding IsFinished, Converter={StaticResource BoolToOpacityConverter}}"
|
||||||
Icon="{Binding Inner.Icon, Converter={StaticResource ItemIconConverter}}"
|
Quality="{Binding Inner.RankLevel}"/>
|
||||||
Opacity="{Binding IsFinished, Converter={StaticResource BoolToOpacityConverter}}"
|
<FontIcon
|
||||||
Quality="{Binding Inner.RankLevel}"/>
|
HorizontalAlignment="Center"
|
||||||
<FontIcon
|
|
||||||
HorizontalAlignment="Center"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
FontSize="24"
|
|
||||||
Glyph=""
|
|
||||||
Visibility="{Binding IsFinished, Converter={StaticResource BoolToVisibilityConverter}}"/>
|
|
||||||
</Grid>
|
|
||||||
<Button
|
|
||||||
Grid.Column="1"
|
|
||||||
Height="32"
|
|
||||||
Margin="6,0,0,0"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
HorizontalContentAlignment="Stretch"
|
|
||||||
Background="Transparent"
|
|
||||||
BorderBrush="{x:Null}"
|
|
||||||
BorderThickness="0"
|
|
||||||
Command="{Binding FinishStateCommand}">
|
|
||||||
<Grid Opacity="{Binding IsFinished, Converter={StaticResource BoolToOpacityConverter}}">
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="auto"/>
|
|
||||||
<ColumnDefinition/>
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<TextBlock
|
|
||||||
Grid.Column="0"
|
|
||||||
Margin="0,0,0,0"
|
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Text="{Binding Inner.Name}"
|
FontSize="24"
|
||||||
TextTrimming="CharacterEllipsis"/>
|
Glyph=""
|
||||||
<TextBlock
|
Visibility="{Binding IsFinished, Converter={StaticResource BoolToVisibilityConverter}}"/>
|
||||||
Grid.Column="1"
|
|
||||||
HorizontalAlignment="Right"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Text="{Binding Entity.Count}"/>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</Button>
|
<Button
|
||||||
|
Grid.Column="1"
|
||||||
|
Height="32"
|
||||||
|
Margin="6,0,0,0"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
HorizontalContentAlignment="Stretch"
|
||||||
|
Background="Transparent"
|
||||||
|
BorderBrush="{x:Null}"
|
||||||
|
BorderThickness="0"
|
||||||
|
Command="{Binding FinishStateCommand}">
|
||||||
|
<Grid Opacity="{Binding IsFinished, Converter={StaticResource BoolToOpacityConverter}}">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="auto"/>
|
||||||
|
<ColumnDefinition/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<TextBlock
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="0,0,0,0"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{Binding IsToday, Converter={StaticResource BoolToStyleSelector}}"
|
||||||
|
Text="{Binding Inner.Name}"
|
||||||
|
TextTrimming="CharacterEllipsis"/>
|
||||||
|
<TextBlock
|
||||||
|
Grid.Column="1"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{Binding IsToday, Converter={StaticResource BoolToStyleSelector}}"
|
||||||
|
Text="{Binding Entity.Count}"/>
|
||||||
|
</Grid>
|
||||||
|
</Button>
|
||||||
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ItemsControl.ItemTemplate>
|
</ItemsControl.ItemTemplate>
|
||||||
</ItemsControl>
|
</ItemsControl>
|
||||||
|
</ScrollViewer>
|
||||||
|
|
||||||
<Grid.Resources>
|
<Grid.Resources>
|
||||||
<Storyboard x:Name="ButtonPanelVisibleStoryboard">
|
<Storyboard x:Name="ButtonPanelVisibleStoryboard">
|
||||||
|
|||||||
@@ -87,6 +87,10 @@
|
|||||||
</Flyout>
|
</Flyout>
|
||||||
</AppBarButton.Flyout>
|
</AppBarButton.Flyout>
|
||||||
</AppBarButton>
|
</AppBarButton>
|
||||||
|
<AppBarButton
|
||||||
|
Command="{Binding DailyNoteVerificationCommand}"
|
||||||
|
Icon="{shcm:FontIcon Glyph=}"
|
||||||
|
Label="验证当前账号角色"/>
|
||||||
<AppBarButton Icon="{shcm:FontIcon Glyph=}" Label="通知设置">
|
<AppBarButton Icon="{shcm:FontIcon Glyph=}" Label="通知设置">
|
||||||
<AppBarButton.Flyout>
|
<AppBarButton.Flyout>
|
||||||
<Flyout Placement="BottomEdgeAlignedRight">
|
<Flyout Placement="BottomEdgeAlignedRight">
|
||||||
|
|||||||
@@ -249,7 +249,7 @@
|
|||||||
Margin="0,16,0,8"
|
Margin="0,16,0,8"
|
||||||
Style="{StaticResource BaseTextBlockStyle}"
|
Style="{StaticResource BaseTextBlockStyle}"
|
||||||
Text="五星"/>
|
Text="五星"/>
|
||||||
<GridView ItemsSource="{Binding SelectedHistoryWish.OrangeList}">
|
<GridView ItemsSource="{Binding SelectedHistoryWish.OrangeList}" SelectionMode="None">
|
||||||
<GridView.ItemTemplate>
|
<GridView.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<Grid>
|
<Grid>
|
||||||
@@ -276,7 +276,7 @@
|
|||||||
Margin="0,0,0,8"
|
Margin="0,0,0,8"
|
||||||
Style="{StaticResource BaseTextBlockStyle}"
|
Style="{StaticResource BaseTextBlockStyle}"
|
||||||
Text="四星"/>
|
Text="四星"/>
|
||||||
<GridView ItemsSource="{Binding SelectedHistoryWish.PurpleList}">
|
<GridView ItemsSource="{Binding SelectedHistoryWish.PurpleList}" SelectionMode="None">
|
||||||
<GridView.ItemTemplate>
|
<GridView.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<Grid>
|
<Grid>
|
||||||
@@ -303,7 +303,7 @@
|
|||||||
Margin="0,0,0,8"
|
Margin="0,0,0,8"
|
||||||
Style="{StaticResource BaseTextBlockStyle}"
|
Style="{StaticResource BaseTextBlockStyle}"
|
||||||
Text="三星"/>
|
Text="三星"/>
|
||||||
<GridView ItemsSource="{Binding SelectedHistoryWish.BlueList}">
|
<GridView ItemsSource="{Binding SelectedHistoryWish.BlueList}" SelectionMode="None">
|
||||||
<GridView.ItemTemplate>
|
<GridView.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<Grid>
|
<Grid>
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user