Compare commits

..

30 Commits

Author SHA1 Message Date
qhy040404
2284510852 fix #1588 2024-05-18 15:17:42 +08:00
Lightczx
7da778699b code style 2024-05-09 16:25:21 +08:00
Lightczx
5bfc790ea2 pooled frame 2024-05-08 17:30:04 +08:00
DismissedLight
fc13b85739 Merge pull request #1610 from DGP-Studio/fix/dailynotevmslim/metadata 2024-05-08 09:03:25 +08:00
qhy040404
df999dbf51 ensure metadata in slim 2024-05-07 22:35:36 +08:00
DismissedLight
688562c1dd capture 2024-05-07 21:19:26 +08:00
Lightczx
051a115f84 bump dependency version 2024-05-07 16:23:30 +08:00
Lightczx
b3d75f9fa5 impl #1607 2024-05-07 16:04:46 +08:00
DismissedLight
0b90bdaa42 Merge pull request #1555 from DGP-Studio/feat/dailynote_archon 2024-05-07 15:51:43 +08:00
Lightczx
77067d27d0 code style 2024-05-07 14:23:54 +08:00
Lightczx
e04542606e code style 2024-05-07 13:36:04 +08:00
Lightczx
5be958ff64 impl #1603 2024-05-07 11:04:21 +08:00
qhy040404
a57933388d add static resource 2024-05-06 16:58:57 +08:00
qhy040404
86c6c9574b ensure metadata 2024-05-06 16:58:57 +08:00
qhy040404
47e451df2f use different icon for different state 2024-05-06 16:58:56 +08:00
qhy040404
c8592c798b add icon 2024-05-06 16:58:56 +08:00
qhy040404
5fad960b20 fix build 2024-05-06 16:58:56 +08:00
qhy040404
44ba0a90a6 remove unnecessary abstraction 2024-05-06 16:58:56 +08:00
qhy040404
883c1ca95f refactor 2024-05-06 16:58:56 +08:00
qhy040404
1a29908e5d partial impl #1203 2024-05-06 16:58:56 +08:00
DismissedLight
3e9edd2f62 capture test 2024-05-05 15:41:46 +08:00
DismissedLight
f9c18d2555 Merge pull request #1604 from DGP-Studio/windows-graphics-capture 2024-05-04 20:20:11 +08:00
DismissedLight
b5afca256a fix build 2024-05-04 20:04:45 +08:00
DismissedLight
a0e79344b1 code style 2 2024-05-04 20:01:37 +08:00
DismissedLight
3b8eba3bb1 code style 2024-05-04 18:59:29 +08:00
DismissedLight
08a3db7dc9 capture test 2024-05-04 16:15:36 +08:00
Lightczx
c02e7b0db3 static zip download retry 2024-04-30 15:02:31 +08:00
DismissedLight
a51ede5048 Merge pull request #1592 from DGP-Studio/develop 2024-04-30 13:46:53 +08:00
Lightczx
1f31c946cc bump version 2024-04-30 13:36:34 +08:00
Lightczx
7dee4a0ea5 fix launch package convert 2024-04-30 13:35:05 +08:00
270 changed files with 4582 additions and 837 deletions

View File

@@ -48,6 +48,8 @@ public sealed partial class App : Application
/// <param name="serviceProvider">服务提供器</param>
public App(IServiceProvider serviceProvider)
{
// DispatcherShutdownMode = DispatcherShutdownMode.OnExplicitShutdown;
// Load app resource
InitializeComponent();
activation = serviceProvider.GetRequiredService<IActivation>();

View File

@@ -17,8 +17,13 @@
<x:String x:Key="UI_Icon_Intee_Explore_1">https://api.snapgenshin.com/static/raw/Bg/UI_Icon_Intee_Explore_1.png</x:String>
<x:String x:Key="UI_ImgSign_ItemIcon">https://api.snapgenshin.com/static/raw/Bg/UI_ImgSign_ItemIcon.png</x:String>
<x:String x:Key="UI_ItemIcon_None">https://api.snapgenshin.com/static/raw/Bg/UI_ItemIcon_None.png</x:String>
<x:String x:Key="UI_MarkQuest_Events_Proce">https://api.snapgenshin.com/static/raw/Bg/UI_MarkQuest_Events_Proce.png</x:String>
<x:String x:Key="UI_MarkTower">https://api.snapgenshin.com/static/raw/Bg/UI_MarkTower.png</x:String>
<!-- Mark -->
<x:String x:Key="UI_MarkQuest_Events_Proce">https://api.snapgenshin.com/static/raw/Mark/UI_MarkQuest_Events_Proce.png</x:String>
<x:String x:Key="UI_MarkQuest_Events_Start">https://api.snapgenshin.com/static/raw/Mark/UI_MarkQuest_Events_Start.png</x:String>
<x:String x:Key="UI_MarkQuest_Main_Proce">https://api.snapgenshin.com/static/raw/Mark/UI_MarkQuest_Main_Proce.png</x:String>
<x:String x:Key="UI_MarkQuest_Main_Start">https://api.snapgenshin.com/static/raw/Mark/UI_MarkQuest_Main_Start.png</x:String>
<x:String x:Key="UI_MarkTower">https://api.snapgenshin.com/static/raw/Mark/UI_MarkTower.png</x:String>
<!-- ItemIcon -->
<x:String x:Key="UI_ItemIcon_201">https://api.snapgenshin.com/static/raw/ItemIcon/UI_ItemIcon_201.png</x:String>

View File

@@ -1,25 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using System.Security.Cryptography;
using System.Text;
namespace Snap.Hutao.Core;
/// <summary>
/// 支持Md5转换
/// </summary>
[HighQuality]
internal static class Convert
{
/// <summary>
/// 获取字符串的MD5计算结果
/// </summary>
/// <param name="source">源字符串</param>
/// <returns>计算的结果</returns>
public static string ToMd5HexString(string source)
{
byte[] hash = MD5.HashData(Encoding.UTF8.GetBytes(source));
return System.Convert.ToHexString(hash);
}
}

View File

@@ -51,6 +51,12 @@ internal sealed class HutaoException : Exception
throw new InvalidCastException(message, innerException);
}
[DoesNotReturn]
public static InvalidOperationException InvalidOperation(string message, Exception? innerException = default)
{
throw new InvalidOperationException(message, innerException);
}
[DoesNotReturn]
public static NotSupportedException NotSupported(string? message = default, Exception? innerException = default)
{

View File

@@ -1,7 +1,6 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Win32.Foundation;
using Snap.Hutao.Win32.System.Com;
using Snap.Hutao.Win32.UI.Shell;
using System.IO;
@@ -63,13 +62,13 @@ internal static class FileOperation
result = true;
}
pDestShellItem->Release();
IUnknownMarshal.Release(pDestShellItem);
}
pSourceShellItem->Release();
IUnknownMarshal.Release(pSourceShellItem);
}
pFileOperation->Release();
IUnknownMarshal.Release(pFileOperation);
}
return result;
@@ -90,10 +89,10 @@ internal static class FileOperation
result = true;
}
pShellItem->Release();
IUnknownMarshal.Release(pShellItem);
}
pFileOperation->Release();
IUnknownMarshal.Release(pFileOperation);
}
return result;

View File

@@ -8,12 +8,17 @@ namespace Snap.Hutao.Core.IO.Hashing;
internal static class Hash
{
public static string SHA1HexString(string input)
public static unsafe string SHA1HexString(string input)
{
return HashCore(System.Convert.ToHexString, SHA1.HashData, Encoding.UTF8.GetBytes, input);
return HashCore(Convert.ToHexString, SHA1.HashData, Encoding.UTF8.GetBytes, input);
}
private static TResult HashCore<TInput, TResult>(Func<byte[], TResult> resultConverter, Func<byte[], byte[]> hashMethod, Func<TInput, byte[]> bytesConverter, TInput input)
public static unsafe string MD5HexString(string input)
{
return HashCore(Convert.ToHexString, System.Security.Cryptography.MD5.HashData, Encoding.UTF8.GetBytes, input);
}
private static unsafe TResult HashCore<TInput, TResult>(Func<byte[], TResult> resultConverter, Func<byte[], byte[]> hashMethod, Func<TInput, byte[]> bytesConverter, TInput input)
{
return resultConverter(hashMethod(bytesConverter(input)));
}

View File

@@ -34,6 +34,6 @@ internal static class MD5
public static async ValueTask<string> HashAsync(Stream stream, CancellationToken token = default)
{
byte[] bytes = await System.Security.Cryptography.MD5.HashDataAsync(stream, token).ConfigureAwait(false);
return System.Convert.ToHexString(bytes);
return Convert.ToHexString(bytes);
}
}

View File

@@ -18,6 +18,6 @@ internal static class SHA256
public static async ValueTask<string> HashAsync(Stream stream, CancellationToken token = default)
{
byte[] bytes = await System.Security.Cryptography.SHA256.HashDataAsync(stream, token).ConfigureAwait(false);
return System.Convert.ToHexString(bytes);
return Convert.ToHexString(bytes);
}
}

View File

@@ -0,0 +1,27 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Snap.Hutao.Core;
internal readonly ref struct ReadOnlySpan2D<T>
where T : unmanaged
{
private readonly ref T reference;
private readonly int length;
private readonly int columns;
public unsafe ReadOnlySpan2D(void* pointer, int length, int columns)
{
reference = ref *(T*)pointer;
this.length = length;
this.columns = columns;
}
public ReadOnlySpan<T> this[int row]
{
get => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.Add(ref reference, row * columns), columns);
}
}

View File

@@ -3,6 +3,7 @@
using Microsoft.Web.WebView2.Core;
using Microsoft.Win32;
using Snap.Hutao.Core.IO.Hashing;
using Snap.Hutao.Core.Setting;
using System.IO;
using System.Security.Principal;
@@ -50,7 +51,7 @@ internal sealed class RuntimeOptions
{
string userName = Environment.UserName;
object? machineGuid = Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\", "MachineGuid", userName);
return Convert.ToMd5HexString($"{userName}{machineGuid}");
return Hash.MD5HexString($"{userName}{machineGuid}");
});
private readonly LazySlim<(string Version, bool Supported)> lazyWebViewEnvironment = new(() =>

View File

@@ -54,7 +54,7 @@ internal sealed partial class ShellLinkInterop : IShellLinkInterop
pShellLink->SetShowCmd(SHOW_WINDOW_CMD.SW_NORMAL);
pShellLink->SetIconLocation(targetLogoPath, 0);
if (SUCCEEDED(pShellLink->QueryInterface(in IPersistFile.IID, out IPersistFile* pPersistFile)))
if (SUCCEEDED(IUnknownMarshal.QueryInterface(pShellLink, in IPersistFile.IID, out IPersistFile* pPersistFile)))
{
string desktop = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
string target = Path.Combine(desktop, $"{SH.FormatAppNameAndVersion(runtimeOptions.Version)}.lnk");
@@ -64,10 +64,10 @@ internal sealed partial class ShellLinkInterop : IShellLinkInterop
result = true;
}
pPersistFile->Release();
IUnknownMarshal.Release(pPersistFile);
}
pShellLink->Release();
uint value = IUnknownMarshal.Release(pShellLink);
}
return result;

View File

@@ -13,7 +13,6 @@ using Snap.Hutao.Win32;
using Snap.Hutao.Win32.Foundation;
using Snap.Hutao.Win32.Graphics.Dwm;
using Snap.Hutao.Win32.UI.WindowsAndMessaging;
using System.Collections.Frozen;
using System.IO;
using Windows.Graphics;
using Windows.UI;

View File

@@ -2,7 +2,6 @@
// Licensed under the MIT license.
using Microsoft.UI.Input;
using Microsoft.UI.Windowing;
using Microsoft.UI.Xaml;
using Snap.Hutao.Win32.Foundation;
using Windows.Graphics;

View File

@@ -9,7 +9,6 @@ using Snap.Hutao.Win32.UI.Shell;
using Snap.Hutao.Win32.UI.WindowsAndMessaging;
using static Snap.Hutao.Win32.ComCtl32;
using static Snap.Hutao.Win32.ConstValues;
using static Snap.Hutao.Win32.User32;
namespace Snap.Hutao.Core.Windowing;

View File

@@ -32,6 +32,7 @@ internal sealed partial class IdentifyMonitorWindow : Window
{
List<IdentifyMonitorWindow> windows = [];
// TODO: the order here is not sync with unity.
IReadOnlyList<DisplayArea> displayAreas = DisplayArea.FindAll();
for (int i = 0; i < displayAreas.Count; i++)
{

View File

@@ -23,6 +23,18 @@
"Equatable": true,
"EqualityOperators": true
},
{
"Name": "ChapterId",
"Documentation": "章节 Id",
"Equatable": true,
"EqualityOperators": true
},
{
"Name": "ChapterGroupId",
"Documentation": "章节分组 Id",
"Equatable": true,
"EqualityOperators": true
},
{
"Name": "EquipAffixId",
"Documentation": "装备属性 Id",
@@ -113,6 +125,12 @@
"Equatable": true,
"EqualityOperators": true
},
{
"Name": "QuestId",
"Documentation": "任务 Id",
"Equatable": true,
"EqualityOperators": true
},
{
"Name": "ReliquaryLevel",
"Documentation": "圣遗物等级 1 - 21",

View File

@@ -4,6 +4,8 @@
using CommunityToolkit.Mvvm.ComponentModel;
using Snap.Hutao.Core.Abstraction;
using Snap.Hutao.Model.Entity.Abstraction;
using Snap.Hutao.Model.Primitive;
using Snap.Hutao.ViewModel.DailyNote;
using Snap.Hutao.ViewModel.User;
using Snap.Hutao.Web.Hoyolab.Takumi.Binding;
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.DailyNote;
@@ -53,6 +55,9 @@ internal sealed class DailyNoteEntry : ObservableObject, IMappingFrom<DailyNoteE
/// </summary>
public DailyNote? DailyNote { get; set; }
[NotMapped]
public DailyNoteArchonQuestView ArchonQuestView { get; set; } = default!;
/// <summary>
/// 刷新时间
/// </summary>
@@ -128,4 +133,4 @@ internal sealed class DailyNoteEntry : ObservableObject, IMappingFrom<DailyNoteE
other.ExpeditionNotifySuppressed = ExpeditionNotifySuppressed;
other.OnPropertyChanged(nameof(ExpeditionNotifySuppressed));
}
}
}

View File

@@ -3,14 +3,42 @@
namespace Snap.Hutao.Model.Intrinsic;
internal enum QuestType
internal enum QuestType : uint
{
/// <summary>
/// Archon Quest 魔神任务
/// </summary>
AQ,
/// <summary>
/// Fractions Quest 帮派任务
/// </summary>
FQ,
/// <summary>
/// Legend Quest 传说任务
/// </summary>
LQ,
/// <summary>
/// Event Quest 活动任务
/// </summary>
EQ,
/// <summary>
/// Daily Quest 日常任务
/// </summary>
DQ,
/// <summary>
/// Indescribable Quest 不可描述的任务?
/// </summary>
IQ,
VQ,
/// <summary>
/// World Quest 世界任务
/// </summary>
WQ,
}

View File

@@ -0,0 +1,34 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Model.Intrinsic;
using Snap.Hutao.Model.Primitive;
namespace Snap.Hutao.Model.Metadata;
internal sealed class Chapter
{
public ChapterId Id { get; set; }
public ChapterGroupId GroupId { get; set; }
public QuestId BeginQuestId { get; set; }
public QuestId EndQuestId { get; set; }
public uint NeedPlayerLevel { get; set; }
public string Number { get; set; } = default!;
public string Title { get; set; } = default!;
public string Icon { get; set; } = default!;
public string ImageTitle { get; set; } = default!;
public string SerialNumberIcon { get; set; } = default!;
public City CityId { get; set; }
public QuestType QuestType { get; set; }
}

View File

@@ -6,6 +6,7 @@ namespace Snap.Hutao.Model.Metadata;
// CityTaskOpenExcelConfig
internal enum City : uint
{
None = 0,
Mondstadt = 1,
Liyue = 2,
Inazuma = 3,

View File

@@ -3,7 +3,6 @@
using Snap.Hutao.Control;
using Snap.Hutao.Model.Intrinsic;
using System.Collections.Frozen;
namespace Snap.Hutao.Model.Metadata.Converter;

View File

@@ -34,8 +34,6 @@ internal sealed class Material : DisplayItem
/// <returns>是否为物品栏物品</returns>
public bool IsInventoryItem()
{
// TODO: Add a pre-filtered metadata set to check if it's an inventory item
// 原质
if (Id == 112001U)
{

View File

@@ -13,7 +13,7 @@
<Identity
Name="60568DGPStudio.SnapHutao"
Publisher="CN=35C8E923-85DF-49A7-9172-B39DC6312C52"
Version="1.10.0.0" />
Version="1.10.1.0" />
<Properties>
<DisplayName>Snap Hutao</DisplayName>

View File

@@ -13,7 +13,7 @@
<Identity
Name="60568DGPStudio.SnapHutaoDev"
Publisher="CN=35C8E923-85DF-49A7-9172-B39DC6312C52"
Version="1.10.0.0" />
Version="1.10.1.0" />
<Properties>
<DisplayName>Snap Hutao Dev</DisplayName>

View File

@@ -2,7 +2,6 @@
// Licensed under the MIT license.
using Microsoft.UI.Xaml;
using Snap.Hutao.Core;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using WinRT;

View File

@@ -3044,6 +3044,9 @@
<data name="WebBridgeShareCopyToClipboardSuccess" xml:space="preserve">
<value>已复制到剪贴板</value>
</data>
<data name="WebDailyNoteArchonQuestChapterFinished" xml:space="preserve">
<value>所有魔神任务已完成</value>
</data>
<data name="WebDailyNoteArchonQuestStatusFinished" xml:space="preserve">
<value>全部完成</value>
</data>

View File

@@ -2,7 +2,6 @@
// Licensed under the MIT license.
using CommunityToolkit.Mvvm.ComponentModel;
using Microsoft.Extensions.Options;
using Snap.Hutao.Core.Database;
using Snap.Hutao.Model.Entity.Database;
using System.Globalization;

View File

@@ -2,10 +2,8 @@
// Licensed under the MIT license.
using Snap.Hutao.Model.Entity;
using Snap.Hutao.Model.Primitive;
using Snap.Hutao.ViewModel.Achievement;
using EntityAchievement = Snap.Hutao.Model.Entity.Achievement;
using MetadataAchievement = Snap.Hutao.Model.Metadata.Achievement.Achievement;
namespace Snap.Hutao.Service.Achievement;

View File

@@ -5,7 +5,6 @@ using Snap.Hutao.Model.InterChange.Achievement;
using Snap.Hutao.ViewModel.Achievement;
using System.Collections.ObjectModel;
using EntityArchive = Snap.Hutao.Model.Entity.AchievementArchive;
using MetadataAchievement = Snap.Hutao.Model.Metadata.Achievement.Achievement;
namespace Snap.Hutao.Service.Achievement;

View File

@@ -1,9 +1,7 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Model.Primitive;
using Snap.Hutao.ViewModel.Achievement;
using MetadataAchievement = Snap.Hutao.Model.Metadata.Achievement.Achievement;
namespace Snap.Hutao.Service.Achievement;

View File

@@ -7,7 +7,6 @@ using Snap.Hutao.Service.Announcement;
using Snap.Hutao.Web.Hoyolab;
using Snap.Hutao.Web.Hoyolab.Hk4e.Common.Announcement;
using Snap.Hutao.Web.Response;
using System.Collections.Specialized;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;

View File

@@ -12,7 +12,6 @@ using Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate;
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord;
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.Avatar;
using Snap.Hutao.Web.Response;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using CalculateAvatar = Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate.Avatar;

View File

@@ -1,9 +1,6 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.EntityFrameworkCore;
using Snap.Hutao.Core.Database;
using Snap.Hutao.Model.Entity.Database;
using Snap.Hutao.Service.Abstraction;
using EntityAvatarInfo = Snap.Hutao.Model.Entity.AvatarInfo;

View File

@@ -2,8 +2,6 @@
// Licensed under the MIT license.
using Snap.Hutao.Core.Abstraction.Extension;
using Snap.Hutao.Model;
using Snap.Hutao.Model.Intrinsic;
using Snap.Hutao.ViewModel.AvatarProperty;
namespace Snap.Hutao.Service.AvatarInfo.Factory.Builder;

View File

@@ -2,7 +2,6 @@
// Licensed under the MIT license.
using Snap.Hutao.Model.Primitive;
using Snap.Hutao.ViewModel.Cultivation;
namespace Snap.Hutao.Service.Cultivation;

View File

@@ -0,0 +1,13 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Model.Metadata;
using Snap.Hutao.Service.Metadata.ContextAbstraction;
namespace Snap.Hutao.Service.DailyNote;
internal class DailyNoteMetadataContext : IMetadataContext,
IMetadataListChapterSource
{
public List<Chapter> Chapters { get; set; } = default!;
}

View File

@@ -8,7 +8,6 @@ using Snap.Hutao.Model.Entity;
using Snap.Hutao.Service.DailyNote.NotifySuppression;
using Snap.Hutao.Service.Game;
using Snap.Hutao.Web.Hoyolab.Takumi.Binding;
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.DailyNote;
using Snap.Hutao.Web.Response;
namespace Snap.Hutao.Service.DailyNote;

View File

@@ -5,7 +5,11 @@ using CommunityToolkit.Mvvm.Messaging;
using Snap.Hutao.Core.DependencyInjection.Abstraction;
using Snap.Hutao.Message;
using Snap.Hutao.Model.Entity;
using Snap.Hutao.Service.Abstraction;
using Snap.Hutao.Service.Metadata;
using Snap.Hutao.Service.Metadata.ContextAbstraction;
using Snap.Hutao.Service.User;
using Snap.Hutao.ViewModel.DailyNote;
using Snap.Hutao.ViewModel.User;
using Snap.Hutao.Web.Hoyolab;
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord;
@@ -83,9 +87,18 @@ internal sealed partial class DailyNoteService : IDailyNoteService, IRecipient<U
await userService.GetRoleCollectionAsync().ConfigureAwait(false);
await RefreshDailyNotesCoreAsync(forceRefresh, token).ConfigureAwait(false);
List<DailyNoteEntry> entryList = await dailyNoteDbService.GetDailyNoteEntryListIncludingUserAsync(token).ConfigureAwait(false);
entryList.ForEach(entry => { entry.UserGameRole = userService.GetUserGameRoleByUid(entry.Uid); });
entries = entryList.ToObservableCollection();
using (IServiceScope scope = serviceProvider.CreateScope())
{
DailyNoteMetadataContext context = await scope.GetRequiredService<IMetadataService>().GetContextAsync<DailyNoteMetadataContext>(token).ConfigureAwait(false);
List<DailyNoteEntry> entryList = await dailyNoteDbService.GetDailyNoteEntryListIncludingUserAsync(token).ConfigureAwait(false);
entryList.ForEach(entry =>
{
entry.UserGameRole = userService.GetUserGameRoleByUid(entry.Uid);
entry.ArchonQuestView = DailyNoteArchonQuestView.Create(entry.DailyNote, context.Chapters);
});
entries = entryList.ToObservableCollection();
}
}
return entries;
@@ -159,4 +172,4 @@ internal sealed partial class DailyNoteService : IDailyNoteService, IRecipient<U
}
}
}
}
}

View File

@@ -6,7 +6,6 @@ using Snap.Hutao.Model.Intrinsic;
using Snap.Hutao.Model.Metadata;
using Snap.Hutao.Model.Metadata.Avatar;
using Snap.Hutao.Model.Metadata.Weapon;
using Snap.Hutao.Service.Metadata;
using Snap.Hutao.Service.Metadata.ContextAbstraction;
using Snap.Hutao.ViewModel.GachaLog;
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;

View File

@@ -0,0 +1,63 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Win32.Foundation;
using Snap.Hutao.Win32.Graphics.Gdi;
using Snap.Hutao.Win32.System.WinRT.Graphics.Capture;
using Windows.Graphics.Capture;
using Windows.Graphics.DirectX;
using Windows.Graphics.DirectX.Direct3D11;
using static Snap.Hutao.Win32.Gdi32;
using static Snap.Hutao.Win32.User32;
namespace Snap.Hutao.Service.Game.Automation.ScreenCapture;
internal readonly struct GameScreenCaptureContext
{
public readonly GraphicsCaptureItem Item;
private readonly IDirect3DDevice direct3DDevice;
private readonly HWND hwnd;
public GameScreenCaptureContext(IDirect3DDevice direct3DDevice, HWND hwnd)
{
this.direct3DDevice = direct3DDevice;
this.hwnd = hwnd;
GraphicsCaptureItem.As<IGraphicsCaptureItemInterop>().CreateForWindow(hwnd, out Item);
}
public Direct3D11CaptureFramePool CreatePool()
{
return Direct3D11CaptureFramePool.CreateFreeThreaded(direct3DDevice, DeterminePixelFormat(hwnd), 2, Item.Size);
}
public void RecreatePool(Direct3D11CaptureFramePool framePool)
{
framePool.Recreate(direct3DDevice, DeterminePixelFormat(hwnd), 2, Item.Size);
}
public GraphicsCaptureSession CreateSession(Direct3D11CaptureFramePool framePool)
{
GraphicsCaptureSession session = framePool.CreateCaptureSession(Item);
session.IsCursorCaptureEnabled = false;
session.IsBorderRequired = false;
return session;
}
private static DirectXPixelFormat DeterminePixelFormat(HWND hwnd)
{
HDC hdc = GetDC(hwnd);
if (hdc != HDC.NULL)
{
int bitsPerPixel = GetDeviceCaps(hdc, GET_DEVICE_CAPS_INDEX.BITSPIXEL);
_ = ReleaseDC(hwnd, hdc);
if (bitsPerPixel >= 32)
{
return DirectXPixelFormat.R16G16B16A16Float;
}
}
return DirectXPixelFormat.B8G8R8A8UIntNormalized;
}
}

View File

@@ -0,0 +1,82 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Core;
using Snap.Hutao.Core.ExceptionService;
using System.Buffers;
namespace Snap.Hutao.Service.Game.Automation.ScreenCapture;
internal sealed class GameScreenCaptureMemoryPool : MemoryPool<byte>
{
private static LazySlim<GameScreenCaptureMemoryPool> lazyShared = new(() => new());
private readonly object syncRoot = new();
private readonly LinkedList<GameScreenCaptureBuffer> unrentedBuffers = [];
private readonly LinkedList<GameScreenCaptureBuffer> rentedBuffers = [];
private int bufferCount;
public new static GameScreenCaptureMemoryPool Shared { get => lazyShared.Value; }
public override int MaxBufferSize { get => Array.MaxLength; }
public int BufferCount { get => bufferCount; }
public override IMemoryOwner<byte> Rent(int minBufferSize = -1)
{
ArgumentOutOfRangeException.ThrowIfLessThan(minBufferSize, 0);
lock (syncRoot)
{
foreach (GameScreenCaptureBuffer buffer in unrentedBuffers)
{
if (buffer.Memory.Length >= minBufferSize)
{
unrentedBuffers.Remove(buffer);
rentedBuffers.AddLast(buffer);
return buffer;
}
}
GameScreenCaptureBuffer newBuffer = new(this, minBufferSize);
rentedBuffers.AddLast(newBuffer);
++bufferCount;
return newBuffer;
}
}
protected override void Dispose(bool disposing)
{
lock (syncRoot)
{
if (rentedBuffers.Count > 0)
{
HutaoException.InvalidOperation("There are still rented buffers.");
}
}
}
internal sealed class GameScreenCaptureBuffer : IMemoryOwner<byte>
{
private readonly GameScreenCaptureMemoryPool pool;
private readonly byte[] buffer;
public GameScreenCaptureBuffer(GameScreenCaptureMemoryPool pool, int bufferSize)
{
this.pool = pool;
buffer = GC.AllocateUninitializedArray<byte>(bufferSize);
}
public Memory<byte> Memory { get => buffer.AsMemory(); }
public void Dispose()
{
lock (pool.syncRoot)
{
pool.rentedBuffers.Remove(this);
pool.unrentedBuffers.AddLast(this);
}
}
}
}

View File

@@ -0,0 +1,86 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Core;
using Snap.Hutao.Win32.Foundation;
using Snap.Hutao.Win32.Graphics.Direct3D;
using Snap.Hutao.Win32.Graphics.Direct3D11;
using Snap.Hutao.Win32.Graphics.Dxgi;
using Snap.Hutao.Win32.System.Com;
using Windows.Graphics.Capture;
using Windows.Graphics.DirectX.Direct3D11;
using WinRT;
using static Snap.Hutao.Win32.ConstValues;
using static Snap.Hutao.Win32.D3D11;
using static Snap.Hutao.Win32.Macros;
namespace Snap.Hutao.Service.Game.Automation.ScreenCapture;
[ConstructorGenerated]
[Injection(InjectAs.Singleton, typeof(IGameScreenCaptureService))]
internal sealed partial class GameScreenCaptureService : IGameScreenCaptureService
{
private readonly ILogger<GameScreenCaptureService> logger;
public bool IsSupported()
{
if (!Core.UniversalApiContract.IsPresent(WindowsVersion.Windows10Version1903))
{
logger.LogWarning("Windows 10 Version 1903 or later is required for Windows.Graphics.Capture API.");
return false;
}
if (!GraphicsCaptureSession.IsSupported())
{
logger.LogWarning("GraphicsCaptureSession is not supported.");
return false;
}
return true;
}
[SuppressMessage("", "SH002")]
public unsafe bool TryStartCapture(HWND hwnd, [NotNullWhen(true)] out GameScreenCaptureSession? session)
{
session = default;
D3D11_CREATE_DEVICE_FLAG flag = D3D11_CREATE_DEVICE_FLAG.D3D11_CREATE_DEVICE_BGRA_SUPPORT
#if DEBUG
| D3D11_CREATE_DEVICE_FLAG.D3D11_CREATE_DEVICE_DEBUG
#endif
;
HRESULT hr;
hr = D3D11CreateDevice(default, D3D_DRIVER_TYPE.D3D_DRIVER_TYPE_HARDWARE, default, flag, [], D3D11_SDK_VERSION, out ID3D11Device* pD3D11Device, out _, out _);
if (FAILED(hr))
{
logger.LogWarning("D3D11CreateDevice failed with code: {Code}", hr);
return false;
}
hr = IUnknownMarshal.QueryInterface(pD3D11Device, in IDXGIDevice.IID, out IDXGIDevice* pDXGIDevice);
if (FAILED(hr))
{
logger.LogWarning("ID3D11Device.QueryInterface<IDXGIDevice> failed with code: {Code}", hr);
return false;
}
IUnknownMarshal.Release(pDXGIDevice);
hr = CreateDirect3D11DeviceFromDXGIDevice(pDXGIDevice, out Win32.System.WinRT.IInspectable* inspectable);
if (FAILED(hr))
{
logger.LogWarning("CreateDirect3D11DeviceFromDXGIDevice failed with code: {Code}", hr);
return false;
}
IUnknownMarshal.Release(inspectable);
IDirect3DDevice direct3DDevice = IInspectable.FromAbi((nint)inspectable).ObjRef.AsInterface<IDirect3DDevice>();
GameScreenCaptureContext captureContext = new(direct3DDevice, hwnd);
session = new(captureContext, logger);
return true;
}
}

View File

@@ -0,0 +1,197 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Core;
using Snap.Hutao.Core.ExceptionService;
using Snap.Hutao.Win32.Graphics.Direct3D11;
using Snap.Hutao.Win32.Graphics.Dxgi;
using Snap.Hutao.Win32.Graphics.Dxgi.Common;
using Snap.Hutao.Win32.System.WinRT.Graphics.Capture;
using System.Buffers;
using System.Runtime.CompilerServices;
using Windows.Graphics;
using Windows.Graphics.Capture;
using Windows.Graphics.DirectX.Direct3D11;
using WinRT;
using static Snap.Hutao.Win32.Macros;
namespace Snap.Hutao.Service.Game.Automation.ScreenCapture;
internal sealed class GameScreenCaptureSession : IDisposable
{
private readonly GameScreenCaptureContext captureContext;
private readonly Direct3D11CaptureFramePool framePool;
private readonly GraphicsCaptureSession session;
private readonly ILogger logger;
private TaskCompletionSource<IMemoryOwner<byte>>? frameRawPixelDataTaskCompletionSource;
private bool isFrameRawPixelDataRequested;
private SizeInt32 contentSize;
private bool isDisposed;
[SuppressMessage("", "SH002")]
public GameScreenCaptureSession(GameScreenCaptureContext captureContext, ILogger logger)
{
this.captureContext = captureContext;
this.logger = logger;
contentSize = captureContext.Item.Size;
captureContext.Item.Closed += OnItemClosed;
framePool = captureContext.CreatePool();
framePool.FrameArrived += OnFrameArrived;
session = captureContext.CreateSession(framePool);
session.StartCapture();
}
public async ValueTask<IMemoryOwner<byte>> RequestFrameRawPixelDataAsync()
{
if (Volatile.Read(ref isFrameRawPixelDataRequested))
{
HutaoException.InvalidOperation("The frame raw pixel data has already been requested.");
}
if (isDisposed)
{
HutaoException.InvalidOperation("The session has been disposed.");
}
frameRawPixelDataTaskCompletionSource = new();
Volatile.Write(ref isFrameRawPixelDataRequested, true);
return await frameRawPixelDataTaskCompletionSource.Task.ConfigureAwait(false);
}
public void Dispose()
{
if (isDisposed)
{
return;
}
session.Dispose();
framePool.Dispose();
isDisposed = true;
}
private void OnItemClosed(GraphicsCaptureItem sender, object args)
{
Dispose();
}
private unsafe void OnFrameArrived(Direct3D11CaptureFramePool sender, object args)
{
// Simply ignore the frame if the frame raw pixel data is not requested.
if (!Volatile.Read(ref isFrameRawPixelDataRequested))
{
return;
}
using (Direct3D11CaptureFrame? frame = sender.TryGetNextFrame())
{
if (frame is null)
{
return;
}
bool needsReset = false;
if (frame.ContentSize != contentSize)
{
needsReset = true;
contentSize = frame.ContentSize;
}
try
{
UnsafeProcessFrameSurface(frame.Surface);
}
catch (Exception ex) // TODO: test if it's device lost.
{
logger.LogError(ex, "Failed to process the frame surface.");
needsReset = true;
}
if (needsReset)
{
captureContext.RecreatePool(sender);
}
}
}
private unsafe void UnsafeProcessFrameSurface(IDirect3DSurface surface)
{
IDirect3DDxgiInterfaceAccess access = surface.As<IDirect3DDxgiInterfaceAccess>();
if (FAILED(access.GetInterface(in IDXGISurface.IID, out IDXGISurface* pDXGISurface)))
{
return;
}
if (FAILED(pDXGISurface->GetDesc(out DXGI_SURFACE_DESC dxgiSurfaceDesc)))
{
return;
}
// Should be the same device used to create the frame pool.
if (FAILED(pDXGISurface->GetDevice(in ID3D11Device.IID, out ID3D11Device* pD3D11Device)))
{
return;
}
D3D11_TEXTURE2D_DESC d3d11Texture2DDesc = default;
d3d11Texture2DDesc.Width = dxgiSurfaceDesc.Width;
d3d11Texture2DDesc.Height = dxgiSurfaceDesc.Height;
d3d11Texture2DDesc.ArraySize = 1;
// We have to copy out the resource to a CPU readable texture.
d3d11Texture2DDesc.CPUAccessFlags = D3D11_CPU_ACCESS_FLAG.D3D11_CPU_ACCESS_READ;
// DirectX will automatically convert any format to B8G8R8A8_UNORM.
d3d11Texture2DDesc.Format = DXGI_FORMAT.DXGI_FORMAT_B8G8R8A8_UNORM;
d3d11Texture2DDesc.MipLevels = 1;
d3d11Texture2DDesc.SampleDesc.Count = 1;
d3d11Texture2DDesc.Usage = D3D11_USAGE.D3D11_USAGE_STAGING;
if (FAILED(pD3D11Device->CreateTexture2D(ref d3d11Texture2DDesc, ref Unsafe.NullRef<D3D11_SUBRESOURCE_DATA>(), out ID3D11Texture2D* pD3D11Texture2D)))
{
return;
}
if (FAILED(access.GetInterface(in ID3D11Resource.IID, out ID3D11Resource* pD3D11Resource)))
{
return;
}
pD3D11Device->GetImmediateContext(out ID3D11DeviceContext* pD3D11DeviceContext);
pD3D11DeviceContext->CopyResource((ID3D11Resource*)pD3D11Texture2D, pD3D11Resource);
if (FAILED(pD3D11DeviceContext->Map((ID3D11Resource*)pD3D11Texture2D, 0U, D3D11_MAP.D3D11_MAP_READ, 0U, out D3D11_MAPPED_SUBRESOURCE d3d11MappedSubresource)))
{
return;
}
// The D3D11_MAPPED_SUBRESOURCE data is arranged as follows:
// |--------- Row pitch ----------|
// |---- Data width ----|- Blank -|
// ┌────────────────────┬─────────┐
// │ │ │
// │ Actual data │ Stride │
// │ │ │
// └────────────────────┴─────────┘
ReadOnlySpan2D<byte> subresource = new(d3d11MappedSubresource.pData, (int)d3d11Texture2DDesc.Height, (int)d3d11MappedSubresource.RowPitch);
int rowLength = contentSize.Width * 4;
IMemoryOwner<byte> buffer = GameScreenCaptureMemoryPool.Shared.Rent(contentSize.Height * rowLength);
for (int row = 0; row < contentSize.Height; row++)
{
subresource[row][..rowLength].CopyTo(buffer.Memory.Span.Slice(row * rowLength, rowLength));
}
ArgumentNullException.ThrowIfNull(frameRawPixelDataTaskCompletionSource);
frameRawPixelDataTaskCompletionSource.SetResult(buffer);
}
}

View File

@@ -0,0 +1,13 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Win32.Foundation;
namespace Snap.Hutao.Service.Game.Automation.ScreenCapture;
internal interface IGameScreenCaptureService
{
bool IsSupported();
bool TryStartCapture(HWND hwnd, [NotNullWhen(true)] out GameScreenCaptureSession? session);
}

View File

@@ -5,7 +5,6 @@ using Snap.Hutao.Core.Diagnostics;
using Snap.Hutao.Win32.Foundation;
using Snap.Hutao.Win32.Memory;
using Snap.Hutao.Win32.System.ProcessStatus;
using System.Diagnostics;
using System.Runtime.InteropServices;
using static Snap.Hutao.Win32.Kernel32;

View File

@@ -0,0 +1,11 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Model.Metadata;
namespace Snap.Hutao.Service.Metadata.ContextAbstraction;
internal interface IMetadataListChapterSource
{
public List<Chapter> Chapters { get; set; }
}

View File

@@ -1,7 +1,6 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.EntityFrameworkCore.Metadata.Internal;
using Snap.Hutao.Model.Metadata.Avatar;
using Snap.Hutao.Model.Metadata.Item;
using Snap.Hutao.Model.Metadata.Weapon;
@@ -24,6 +23,11 @@ internal static class MetadataServiceContextExtension
listAchievementSource.Achievements = await metadataService.GetAchievementListAsync(token).ConfigureAwait(false);
}
if (context is IMetadataListChapterSource listChapterSource)
{
listChapterSource.Chapters = await metadataService.GetChapterListAsync(token).ConfigureAwait(false);
}
if (context is IMetadataListGachaEventSource listGachaEventSource)
{
listGachaEventSource.GachaEvents = await metadataService.GetGachaEventListAsync(token).ConfigureAwait(false);

View File

@@ -10,6 +10,7 @@ internal static class MetadataFileNames
public const string FileNameAvatar = "Avatar";
public const string FileNameAvatarCurve = "AvatarCurve";
public const string FileNameAvatarPromote = "AvatarPromote";
public const string FileNameChapter = "Chapter";
public const string FileNameDisplayItem = "DisplayItem";
public const string FileNameGachaEvent = "GachaEvent";
public const string FileNameMaterial = "Material";

View File

@@ -20,6 +20,11 @@ internal static class MetadataServiceListExtension
return metadataService.FromCacheOrFileAsync<List<Model.Metadata.Achievement.Achievement>>(FileNameAchievement, token);
}
public static ValueTask<List<Chapter>> GetChapterListAsync(this IMetadataService metadataService, CancellationToken token = default)
{
return metadataService.FromCacheOrFileAsync<List<Chapter>>(FileNameChapter, token);
}
public static ValueTask<List<AchievementGoal>> GetAchievementGoalListAsync(this IMetadataService metadataService, CancellationToken token = default)
{
return metadataService.FromCacheOrFileAsync<List<AchievementGoal>>(FileNameAchievementGoal, token);

View File

@@ -1,19 +1,7 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Core;
using Snap.Hutao.Core.IO.Hashing;
using Snap.Hutao.Core.IO.Http.Sharding;
using Snap.Hutao.Core.Setting;
using Snap.Hutao.Service.Abstraction;
using Snap.Hutao.Service.Notification;
using Snap.Hutao.Web.Hutao;
using Snap.Hutao.Web.Hutao.Response;
using Snap.Hutao.Web.Response;
using System.Diagnostics;
using System.IO;
using System.Net.Http;
using Windows.Storage;
namespace Snap.Hutao.Service.Update;

View File

@@ -1,18 +1,7 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Core;
using Snap.Hutao.Core.IO.Hashing;
using Snap.Hutao.Core.IO.Http.Sharding;
using Snap.Hutao.Core.Setting;
using Snap.Hutao.Service.Abstraction;
using Snap.Hutao.Service.Notification;
using Snap.Hutao.Web.Hutao;
using Snap.Hutao.Web.Hutao.Response;
using System.Diagnostics;
using System.IO;
using System.Net.Http;
using Windows.Storage;
namespace Snap.Hutao.Service.Update;

View File

@@ -323,8 +323,8 @@
</PackageReference>
<PackageReference Include="Microsoft.VisualStudio.Validation" Version="17.8.8" />
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.3233" />
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.5.240404000" />
<PackageReference Include="QRCoder" Version="1.4.3" />
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.5.240428000" />
<PackageReference Include="QRCoder" Version="1.5.1" />
<PackageReference Include="Snap.Discord.GameSDK" Version="1.6.0" />
<PackageReference Include="Snap.Hutao.Deployment.Runtime" Version="1.16.0">
<PrivateAssets>all</PrivateAssets>
@@ -343,7 +343,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="System.IO.Hashing" Version="8.0.0" />
<PackageReference Include="TaskScheduler" Version="2.10.1" />
<PackageReference Include="TaskScheduler" Version="2.11.0" />
<Manifest Include="$(ApplicationManifest)" />
</ItemGroup>

View File

@@ -47,7 +47,7 @@
<NavigationView
x:Name="NavView"
Margin="-1,0,0,-1"
Margin="0,0,0,0"
shch:NavigationViewHelper.PaneCornerRadius="0"
CompactPaneLength="48"
IsBackEnabled="{x:Bind ContentFrame.CanGoBack, Mode=OneWay}"

View File

@@ -41,9 +41,11 @@
x:Name="ImageZoomBorder"
VerticalAlignment="Top"
cw:VisualExtensions.NormalizedCenterPoint="0.5">
<cww:ConstrainedBox AspectRatio="1080:390" CornerRadius="{ThemeResource ControlCornerRadiusTop}">
<cww:ConstrainedBox
Margin="-4"
AspectRatio="1080:390"
CornerRadius="{ThemeResource ControlCornerRadiusTop}">
<shci:CachedImage
Margin="-1"
VerticalAlignment="Center"
PlaceholderMargin="16"
PlaceholderSource="{StaticResource UI_EmotionIcon271}"

View File

@@ -3,7 +3,8 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cw="using:CommunityToolkit.WinUI"
xmlns:cwc="using:CommunityToolkit.WinUI.Controls"
xmlns:cwcont="using:CommunityToolkit.WinUI.Controls"
xmlns:cwconv="using:CommunityToolkit.WinUI.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:mxi="using:Microsoft.Xaml.Interactivity"
@@ -12,6 +13,7 @@
xmlns:shch="using:Snap.Hutao.Control.Helper"
xmlns:shci="using:Snap.Hutao.Control.Image"
xmlns:shcm="using:Snap.Hutao.Control.Markup"
xmlns:shme="using:Snap.Hutao.Model.Entity"
xmlns:shvc="using:Snap.Hutao.View.Control"
xmlns:shvcp="using:Snap.Hutao.View.Card.Primitive"
xmlns:shvd="using:Snap.Hutao.ViewModel.DailyNote"
@@ -26,6 +28,16 @@
<Page.Resources>
<shc:BindingProxy x:Key="ViewModelBindingProxy" DataContext="{Binding}"/>
<cwconv:BoolToObjectConverter
x:Name="DailyTaskIconConverter"
FalseValue="{StaticResource UI_MarkQuest_Events_Start}"
TrueValue="{StaticResource UI_MarkQuest_Events_Proce}"/>
<cwconv:BoolToObjectConverter
x:Name="ArchonQuestIconConverter"
FalseValue="{StaticResource UI_MarkQuest_Main_Start}"
TrueValue="{StaticResource UI_MarkQuest_Main_Proce}"/>
<DataTemplate x:Key="UserAndUidTemplate">
<Grid Padding="0,0,0,16">
<TextBlock VerticalAlignment="Center" Text="{Binding Uid}"/>
@@ -43,7 +55,7 @@
</Grid>
</DataTemplate>
<DataTemplate x:Key="DailyNoteEntryTemplate">
<DataTemplate x:Key="DailyNoteEntryTemplate" x:DataType="shme:DailyNoteEntry">
<ItemContainer cw:Effects.Shadow="{ThemeResource CompatCardShadow}">
<ItemContainer.Resources>
<SolidColorBrush x:Key="ItemContainerPointerOverBackground" Color="Transparent"/>
@@ -108,6 +120,43 @@
Grid.Row="1"
Margin="0,8,0,0"
Spacing="6">
<Grid Style="{ThemeResource GridCardStyle}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<ProgressBar
Grid.ColumnSpan="2"
Height="40"
MinHeight="48"
Background="{x:Null}"
CornerRadius="{ThemeResource ControlCornerRadius}"
Maximum="{Binding ArchonQuestView.Ids.Count, Mode=OneWay}"
Opacity="{StaticResource LargeBackgroundProgressBarOpacity}"
Value="{Binding ArchonQuestView.ProgressValue, Mode=OneWay}"/>
<shci:CachedImage
Grid.Column="0"
Margin="4"
VerticalAlignment="Center"
shch:FrameworkElementHelper.SquareLength="32"
Source="{Binding DailyNote.IsArchonQuestFinished, Converter={StaticResource ArchonQuestIconConverter}}"/>
<StackPanel
Grid.Column="1"
Margin="8,0,0,0"
VerticalAlignment="Center">
<TextBlock
Style="{StaticResource SubtitleTextBlockStyle}"
Text="{Binding ArchonQuestView.ProgressFormatted, Mode=OneWay}"
TextTrimming="CharacterEllipsis"
TextWrapping="NoWrap"/>
<TextBlock
Opacity="0.6"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{Binding ArchonQuestView.ChapterFormatted, Mode=OneWay}"
TextTrimming="CharacterEllipsis"
TextWrapping="NoWrap"/>
</StackPanel>
</Grid>
<Grid Style="{ThemeResource GridCardStyle}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
@@ -202,7 +251,7 @@
Margin="4"
VerticalAlignment="Center"
shch:FrameworkElementHelper.SquareLength="32"
Source="{StaticResource UI_MarkQuest_Events_Proce}"/>
Source="{Binding DailyNote.DailyTask.IsExtraTaskRewardReceived, Converter={StaticResource DailyTaskIconConverter}}"/>
<StackPanel
Grid.Column="1"
Margin="8,0,0,0"
@@ -333,7 +382,7 @@
ItemsSource="{Binding DailyNote.Expeditions, Mode=OneWay}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<cwc:UniformGrid
<cwcont:UniformGrid
ColumnSpacing="8"
Columns="2"
RowSpacing="8"/>
@@ -450,16 +499,16 @@
<x:Double x:Key="SettingsCardWrapNoIconThreshold">0</x:Double>
</StackPanel.Resources>
<cwc:HeaderedContentControl
<cwcont:HeaderedContentControl
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
IsEnabled="{Binding RuntimeOptions.IsElevated, Converter={StaticResource BoolNegationConverter}}">
<cwc:HeaderedContentControl.Header>
<cwcont:HeaderedContentControl.Header>
<TextBlock
Margin="1,0,0,5"
Style="{StaticResource SettingsSectionHeaderTextBlockStyle}"
Text="{shcm:ResourceString Name=ViewPageDailyNoteSettingRefreshHeader}"/>
</cwc:HeaderedContentControl.Header>
</cwcont:HeaderedContentControl.Header>
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
<InfoBar
Title="{shcm:ResourceString Name=ViewPageDailyNoteSettingRefreshElevatedHint}"
@@ -467,12 +516,12 @@
IsOpen="True"
Severity="Warning"
Visibility="{Binding RuntimeOptions.IsElevated, Converter={StaticResource BoolToVisibilityConverter}}"/>
<cwc:SettingsCard
<cwcont:SettingsCard
Description="{shcm:ResourceString Name=ViewPageDailyNoteSettingAutoRefreshDescription}"
Header="{shcm:ResourceString Name=ViewPageDailyNoteSettingAutoRefresh}"
HeaderIcon="{shcm:FontIcon Glyph=&#xE72C;}">
<ToggleSwitch Margin="24,0,0,0" IsOn="{Binding DailyNoteOptions.IsAutoRefreshEnabled, Mode=TwoWay}"/>
</cwc:SettingsCard>
</cwcont:SettingsCard>
<RadioButtons
Margin="1,11,0,5"
IsEnabled="{Binding DailyNoteOptions.IsAutoRefreshEnabled}"
@@ -488,15 +537,15 @@
</RadioButtons.ItemTemplate>
</RadioButtons>
</StackPanel>
</cwc:HeaderedContentControl>
</cwcont:HeaderedContentControl>
<cwc:HeaderedContentControl
<cwcont:HeaderedContentControl
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
IsEnabled="{Binding RuntimeOptions.IsToastAvailable}">
<cwc:HeaderedContentControl.Header>
<cwcont:HeaderedContentControl.Header>
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" Text="{shcm:ResourceString Name=ViewPageDailyNoteNotificationHeader}"/>
</cwc:HeaderedContentControl.Header>
</cwcont:HeaderedContentControl.Header>
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
<InfoBar
Title="胡桃的通知权限已被关闭"
@@ -504,23 +553,23 @@
IsOpen="True"
Severity="Warning"
Visibility="{Binding RuntimeOptions.IsToastAvailable, Converter={StaticResource BoolToVisibilityRevertConverter}}"/>
<cwc:SettingsCard
<cwcont:SettingsCard
Description="{shcm:ResourceString Name=ViewPageDailyNoteSlientModeDescription}"
Header="{shcm:ResourceString Name=ViewPageDailyNoteSlientModeHeader}"
HeaderIcon="{shcm:FontIcon Glyph=&#xE7ED;}">
<ToggleSwitch Margin="24,0,0,0" IsOn="{Binding DailyNoteOptions.IsSilentWhenPlayingGame, Mode=TwoWay}"/>
</cwc:SettingsCard>
<cwc:SettingsCard
</cwcont:SettingsCard>
<cwcont:SettingsCard
Description="{shcm:ResourceString Name=ViewPageDailyNoteReminderDescription}"
Header="{shcm:ResourceString Name=ViewPageDailyNoteReminderHeader}"
HeaderIcon="{shcm:FontIcon Glyph=&#xEA8F;}">
<ToggleSwitch Margin="24,0,0,0" IsOn="{Binding DailyNoteOptions.IsReminderNotification, Mode=TwoWay}"/>
</cwc:SettingsCard>
</cwcont:SettingsCard>
</StackPanel>
</cwc:HeaderedContentControl>
</cwcont:HeaderedContentControl>
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" Text="{shcm:ResourceString Name=ViewPageDailyNoteDataInteropHeader}"/>
<cwc:SettingsCard
<cwcont:SettingsCard
Command="{Binding ConfigDailyNoteWebhookUrlCommand}"
Description="{shcm:ResourceString Name=ViewPageDailyNoteConfigWebhookDescription}"
Header="{shcm:ResourceString Name=ViewPageDailyNoteConfigWebhookHeader}"

View File

@@ -98,6 +98,13 @@
Style="{ThemeResource SettingButtonStyle}"/>
</cwc:SettingsCard>
<cwc:SettingsCard Header="Test Windows.Graphics.Capture">
<Button
Command="{Binding TestWindowsGraphicsCaptureCommand}"
Content="Test"
Style="{ThemeResource SettingButtonStyle}"/>
</cwc:SettingsCard>
<cwc:SettingsCard Header="Suppress Metadata Initialization">
<ToggleSwitch IsOn="{Binding SuppressMetadataInitialization, Mode=TwoWay}"/>
</cwc:SettingsCard>

View File

@@ -4,8 +4,6 @@
using Microsoft.UI.Xaml.Controls;
using Snap.Hutao.Control.Extension;
using Snap.Hutao.Core.IO;
using Snap.Hutao.Core.IO.DataTransfer;
using Snap.Hutao.Factory.ContentDialog;
using Snap.Hutao.Factory.Picker;
using Snap.Hutao.Model.InterChange.Achievement;
using Snap.Hutao.Service.Achievement;

View File

@@ -16,7 +16,6 @@ using Snap.Hutao.View.Dialog;
using System.Collections.ObjectModel;
using System.Text.RegularExpressions;
using EntityAchievementArchive = Snap.Hutao.Model.Entity.AchievementArchive;
using MetadataAchievement = Snap.Hutao.Model.Metadata.Achievement.Achievement;
using MetadataAchievementGoal = Snap.Hutao.Model.Metadata.Achievement.AchievementGoal;
using SortDescription = CommunityToolkit.WinUI.Collections.SortDescription;
using SortDirection = CommunityToolkit.WinUI.Collections.SortDirection;

View File

@@ -1,7 +1,6 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Model.Primitive;
using Snap.Hutao.Service.Achievement;
using Snap.Hutao.Service.Metadata;
using Snap.Hutao.Service.Metadata.ContextAbstraction;

View File

@@ -5,7 +5,6 @@ using Snap.Hutao.Model;
using Snap.Hutao.Model.Calculable;
using Snap.Hutao.Model.Intrinsic;
using Snap.Hutao.Model.Primitive;
using Snap.Hutao.Service.AvatarInfo.Factory.Builder;
namespace Snap.Hutao.ViewModel.AvatarProperty;

View File

@@ -46,7 +46,7 @@ internal sealed class CultivateItemView : ObservableObject, IEntityWithMetadata<
/// <summary>
/// 是否为今日物品
/// </summary>
public bool IsToday { get => Inner.IsTodaysItem(); }
public bool IsToday { get => Inner.IsTodaysItem(true); }
/// <summary>
/// 星期中的日期

View File

@@ -0,0 +1,82 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Model.Intrinsic;
using Snap.Hutao.Model.Metadata;
using Snap.Hutao.Model.Primitive;
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.DailyNote;
using WebDailyNote = Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.DailyNote.DailyNote;
namespace Snap.Hutao.ViewModel.DailyNote;
internal sealed class DailyNoteArchonQuestView
{
private readonly WebDailyNote? dailyNote;
private DailyNoteArchonQuestView(WebDailyNote? dailyNote, List<Chapter> chapters)
{
this.dailyNote = dailyNote;
Ids = chapters
.Where(chapter => chapter.QuestType is QuestType.AQ)
.Select(chapter => chapter.Id)
.ToList();
}
public List<ChapterId> Ids { get; set; } = default!;
public int ProgressValue
{
get
{
if (TryGetFirstArchonQuest(out ArchonQuest? quest))
{
return Ids.IndexOf(quest.Id);
}
return Ids.Count;
}
}
public string ProgressFormatted
{
get
{
if (TryGetFirstArchonQuest(out ArchonQuest? quest))
{
return quest.Status.GetLocalizedDescription();
}
return SH.WebDailyNoteArchonQuestStatusFinished;
}
}
public string ChapterFormatted
{
get
{
if (TryGetFirstArchonQuest(out ArchonQuest? quest))
{
return $"{quest.ChapterNum} {quest.ChapterTitle}";
}
return SH.WebDailyNoteArchonQuestChapterFinished;
}
}
public static DailyNoteArchonQuestView Create(WebDailyNote? dailyNote, List<Chapter> chapters)
{
return new(dailyNote, chapters);
}
private bool TryGetFirstArchonQuest([NotNullWhen(true)] out ArchonQuest? archonQuest)
{
if (dailyNote is { ArchonQuestProgress.List: [{ } target, ..] })
{
archonQuest = target;
return true;
}
archonQuest = default;
return false;
}
}

View File

@@ -7,6 +7,7 @@ using Snap.Hutao.Core;
using Snap.Hutao.Factory.ContentDialog;
using Snap.Hutao.Model.Entity;
using Snap.Hutao.Service.DailyNote;
using Snap.Hutao.Service.Metadata;
using Snap.Hutao.Service.Notification;
using Snap.Hutao.Service.User;
using Snap.Hutao.View.Control;
@@ -27,6 +28,7 @@ internal sealed partial class DailyNoteViewModel : Abstraction.ViewModel
private readonly IContentDialogFactory contentDialogFactory;
private readonly IDailyNoteService dailyNoteService;
private readonly DailyNoteOptions dailyNoteOptions;
private readonly IMetadataService metadataService;
private readonly IInfoBarService infoBarService;
private readonly RuntimeOptions runtimeOptions;
private readonly ITaskContext taskContext;
@@ -53,22 +55,26 @@ internal sealed partial class DailyNoteViewModel : Abstraction.ViewModel
protected override async ValueTask<bool> InitializeUIAsync()
{
try
if (await metadataService.InitializeAsync().ConfigureAwait(false))
{
await taskContext.SwitchToBackgroundAsync();
ObservableCollection<UserAndUid> roles = await userService.GetRoleCollectionAsync().ConfigureAwait(false);
ObservableCollection<DailyNoteEntry> entries = await dailyNoteService.GetDailyNoteEntryCollectionAsync().ConfigureAwait(false);
try
{
await taskContext.SwitchToBackgroundAsync();
ObservableCollection<UserAndUid> roles = await userService.GetRoleCollectionAsync().ConfigureAwait(false);
ObservableCollection<DailyNoteEntry> entries = await dailyNoteService.GetDailyNoteEntryCollectionAsync().ConfigureAwait(false);
await taskContext.SwitchToMainThreadAsync();
UserAndUids = roles;
DailyNoteEntries = entries;
return true;
}
catch (Core.ExceptionService.UserdataCorruptedException ex)
{
infoBarService.Error(ex);
return false;
await taskContext.SwitchToMainThreadAsync();
UserAndUids = roles;
DailyNoteEntries = entries;
return true;
}
catch (Core.ExceptionService.UserdataCorruptedException ex)
{
infoBarService.Error(ex);
}
}
return false;
}
[Command("TrackRoleCommand")]

View File

@@ -3,6 +3,7 @@
using Snap.Hutao.Model.Entity;
using Snap.Hutao.Service.DailyNote;
using Snap.Hutao.Service.Metadata;
using Snap.Hutao.Service.Notification;
using System.Collections.ObjectModel;
@@ -17,6 +18,7 @@ internal sealed partial class DailyNoteViewModelSlim : Abstraction.ViewModelSlim
{
private readonly ITaskContext taskContext;
private readonly IInfoBarService infoBarService;
private readonly IMetadataService metadataService;
private readonly IDailyNoteService dailyNoteService;
private List<DailyNoteEntry>? dailyNoteEntries;
@@ -29,25 +31,28 @@ internal sealed partial class DailyNoteViewModelSlim : Abstraction.ViewModelSlim
/// <inheritdoc/>
protected override async Task OpenUIAsync()
{
try
if (await metadataService.InitializeAsync().ConfigureAwait(false))
{
await taskContext.SwitchToBackgroundAsync();
ObservableCollection<DailyNoteEntry> entries = await dailyNoteService
.GetDailyNoteEntryCollectionAsync()
.ConfigureAwait(false);
try
{
await taskContext.SwitchToBackgroundAsync();
ObservableCollection<DailyNoteEntry> entries = await dailyNoteService
.GetDailyNoteEntryCollectionAsync()
.ConfigureAwait(false);
// 此处使用浅拷贝的列表以避免当导航到实时便笺页面后
// 由于主页尚未卸载,添加或删除便笺可能会崩溃的问题
List<DailyNoteEntry> entryList = [.. entries];
// 此处使用浅拷贝的列表以避免当导航到实时便笺页面后
// 由于主页尚未卸载,添加或删除便笺可能会崩溃的问题
List<DailyNoteEntry> entryList = [.. entries];
await taskContext.SwitchToMainThreadAsync();
DailyNoteEntries = entryList;
IsInitialized = true;
}
catch (Core.ExceptionService.UserdataCorruptedException ex)
{
infoBarService.Error(ex);
return;
await taskContext.SwitchToMainThreadAsync();
DailyNoteEntries = entryList;
IsInitialized = true;
}
catch (Core.ExceptionService.UserdataCorruptedException ex)
{
infoBarService.Error(ex);
return;
}
}
}
}

View File

@@ -66,7 +66,7 @@ internal sealed partial class TypedWishSummary : Wish
/// </summary>
public string TotalOrangeFormatted
{
get => $"{TotalOrangePull} [{TotalOrangePercent,6:p2}]";
get => $"{TotalOrangePull} [{(TotalOrangePercent is double.NaN ? 0D : TotalOrangePercent),6:p2}]";
}
/// <summary>
@@ -74,7 +74,7 @@ internal sealed partial class TypedWishSummary : Wish
/// </summary>
public string TotalPurpleFormatted
{
get => $"{TotalPurplePull} [{TotalPurplePercent,6:p2}]";
get => $"{TotalPurplePull} [{(TotalPurplePercent is double.NaN ? 0D : TotalPurplePercent),6:p2}]";
}
/// <summary>
@@ -82,7 +82,7 @@ internal sealed partial class TypedWishSummary : Wish
/// </summary>
public string TotalBlueFormatted
{
get => $"{TotalBluePull} [{TotalBluePercent,6:p2}]";
get => $"{TotalBluePull} [{(TotalBluePercent is double.NaN ? 0D : TotalBluePercent),6:p2}]";
}
public ColorSegmentCollection PullPercentSegmentSource

View File

@@ -3,7 +3,6 @@
using Snap.Hutao.Model.Entity;
using Snap.Hutao.Service.Game.PathAbstraction;
using Snap.Hutao.Service.Notification;
using System.Collections.Immutable;
namespace Snap.Hutao.ViewModel.Game;

View File

@@ -9,17 +9,17 @@ namespace Snap.Hutao.ViewModel.Game;
internal static class LaunchGameLaunchExecution
{
public static async ValueTask LaunchExecutionAsync(this IViewModelSupportLaunchExecution launchExecution)
public static async ValueTask LaunchExecutionAsync(this IViewModelSupportLaunchExecution launchExecution, LaunchScheme? targetScheme)
{
IServiceProvider root = Ioc.Default;
IInfoBarService infoBarService = root.GetRequiredService<IInfoBarService>();
ILogger<IViewModelSupportLaunchExecution> logger = root.GetRequiredService<ILogger<IViewModelSupportLaunchExecution>>();
LaunchScheme? scheme = launchExecution.Shared.GetCurrentLaunchSchemeFromConfigFile();
// LaunchScheme? scheme = launchExecution.Shared.GetCurrentLaunchSchemeFromConfigFile();
try
{
// Root service provider is required.
LaunchExecutionContext context = new(root, launchExecution, scheme, launchExecution.SelectedGameAccount);
LaunchExecutionContext context = new(root, launchExecution, targetScheme, launchExecution.SelectedGameAccount);
LaunchExecutionResult result = await new LaunchExecutionInvoker().InvokeAsync(context).ConfigureAwait(false);
if (result.Kind is not LaunchExecutionResultKind.Ok)

View File

@@ -2,7 +2,6 @@
// Licensed under the MIT license.
using Microsoft.Extensions.Caching.Memory;
using Microsoft.UI.Windowing;
using Snap.Hutao.Control.Collection.AdvancedCollectionView;
using Snap.Hutao.Core;
using Snap.Hutao.Core.Database;
@@ -11,7 +10,6 @@ using Snap.Hutao.Core.ExceptionService;
using Snap.Hutao.Model.Entity;
using Snap.Hutao.Service;
using Snap.Hutao.Service.Game;
using Snap.Hutao.Service.Game.Launching;
using Snap.Hutao.Service.Game.Locator;
using Snap.Hutao.Service.Game.PathAbstraction;
using Snap.Hutao.Service.Game.Scheme;
@@ -216,7 +214,7 @@ internal sealed partial class LaunchGameViewModel : Abstraction.ViewModel, IView
[Command("LaunchCommand")]
private async Task LaunchAsync()
{
await this.LaunchExecutionAsync().ConfigureAwait(false);
await this.LaunchExecutionAsync(SelectedScheme).ConfigureAwait(false);
}
[Command("DetectGameAccountCommand")]

View File

@@ -2,14 +2,10 @@
// Licensed under the MIT license.
using Snap.Hutao.Control.Collection.AdvancedCollectionView;
using Snap.Hutao.Core.ExceptionService;
using Snap.Hutao.Model.Entity;
using Snap.Hutao.Service.Game;
using Snap.Hutao.Service.Game.Launching;
using Snap.Hutao.Service.Game.PathAbstraction;
using Snap.Hutao.Service.Game.Scheme;
using Snap.Hutao.Service.Notification;
using System.Collections.Immutable;
using System.Collections.ObjectModel;
namespace Snap.Hutao.ViewModel.Game;
@@ -73,6 +69,6 @@ internal sealed partial class LaunchGameViewModelSlim : Abstraction.ViewModelSli
[Command("LaunchCommand")]
private async Task LaunchAsync()
{
await this.LaunchExecutionAsync().ConfigureAwait(false);
await this.LaunchExecutionAsync(launchGameShared.GetCurrentLaunchSchemeFromConfigFile()).ConfigureAwait(false);
}
}

View File

@@ -65,41 +65,57 @@ internal sealed class DownloadSummary : ObservableObject
ILogger<DownloadSummary> logger = serviceProvider.GetRequiredService<ILogger<DownloadSummary>>();
try
{
HttpRequestMessage message = httpRequestMessageBuilderFactory
.Create()
.SetRequestUri(fileUrl)
.SetStaticResourceControlHeaders()
.Get()
.HttpRequestMessage;
using (message)
int retryTimes = 0;
while (retryTimes++ < 3)
{
using (HttpResponseMessage response = await httpClient.SendAsync(message, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false))
{
if (!AllowedMediaTypes.Contains(response.Content.Headers.ContentType?.MediaType))
{
logger.LogWarning("Download Static Zip failed, Content-Type is {Type}", response.Content.Headers.ContentType);
await taskContext.SwitchToMainThreadAsync();
Description = SH.ViewModelWelcomeDownloadSummaryContentTypeNotMatch;
return false;
}
HttpRequestMessage message = httpRequestMessageBuilderFactory
.Create()
.SetRequestUri(fileUrl)
.SetStaticResourceControlHeaders()
.Get()
.HttpRequestMessage;
long contentLength = response.Content.Headers.ContentLength ?? 0;
logger.LogInformation("Begin download, size: {length}", Converters.ToFileSizeString(contentLength));
using (Stream content = await response.Content.ReadAsStreamAsync().ConfigureAwait(false))
TimeSpan delay = default;
using (message)
{
using (HttpResponseMessage response = await httpClient.SendAsync(message, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false))
{
using (TempFileStream temp = new(FileMode.OpenOrCreate, FileAccess.ReadWrite))
if (!AllowedMediaTypes.Contains(response.Content.Headers.ContentType?.MediaType))
{
await new StreamCopyWorker(content, temp, contentLength).CopyAsync(progress).ConfigureAwait(false);
ExtractFiles(temp);
logger.LogWarning("Download Static Zip failed, Content-Type is {Type}", response.Content.Headers.ContentType);
await taskContext.SwitchToMainThreadAsync();
ProgressValue = 1;
Description = SH.ViewModelWelcomeDownloadSummaryComplete;
return true;
Description = SH.ViewModelWelcomeDownloadSummaryContentTypeNotMatch;
}
else
{
long contentLength = response.Content.Headers.ContentLength ?? 0;
logger.LogInformation("Begin download, size: {length}", Converters.ToFileSizeString(contentLength));
using (Stream content = await response.Content.ReadAsStreamAsync().ConfigureAwait(false))
{
using (TempFileStream temp = new(FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
await new StreamCopyWorker(content, temp, contentLength).CopyAsync(progress).ConfigureAwait(false);
ExtractFiles(temp);
await taskContext.SwitchToMainThreadAsync();
ProgressValue = 1;
Description = SH.ViewModelWelcomeDownloadSummaryComplete;
return true;
}
}
}
if (response.Headers.RetryAfter?.Delta is { } retryAfter)
{
delay = retryAfter;
}
}
}
await Task.Delay(delay).ConfigureAwait(false);
}
return false;
}
catch (Exception ex)
{

View File

@@ -33,6 +33,7 @@ internal static class StaticResource
{ "IconElement", 0 },
{ "ItemIcon", 0 },
{ "LoadingPic", 0 },
{ "Mark", 0 },
{ "MonsterIcon", 0 },
{ "MonsterSmallIcon", 0 },
{ "NameCardIcon", 0 },
@@ -62,6 +63,7 @@ internal static class StaticResource
{ "IconElement", 3 },
{ "ItemIcon", 4 },
{ "LoadingPic", 2 },
{ "Mark", 0 },
{ "MonsterIcon", 3 },
{ "MonsterSmallIcon", 2 },
{ "NameCardIcon", 3 },

View File

@@ -14,8 +14,8 @@ internal static class StaticResourceHttpHeaderBuilderExtension
where TBuilder : IHttpHeadersBuilder<HttpHeaders>
{
return builder
.SetHeader("x-quality", $"{UnsafeLocalSetting.Get(SettingKeys.StaticResourceImageQuality, StaticResourceQuality.Raw)}")
.SetHeader("x-archive", $"{UnsafeLocalSetting.Get(SettingKeys.StaticResourceImageArchive, StaticResourceArchive.Full)}");
.SetHeader("x-hutao-quality", $"{UnsafeLocalSetting.Get(SettingKeys.StaticResourceImageQuality, StaticResourceQuality.Raw)}")
.SetHeader("x-hutao-archive", $"{UnsafeLocalSetting.Get(SettingKeys.StaticResourceImageArchive, StaticResourceArchive.Full)}");
}
public static TBuilder SetStaticResourceControlHeadersIf<TBuilder>(this TBuilder builder, bool condition)

View File

@@ -2,7 +2,6 @@
// Licensed under the MIT license.
using CommunityToolkit.Mvvm.Messaging;
using Microsoft.UI.Xaml.Controls;
using Snap.Hutao.Factory.ContentDialog;
using Snap.Hutao.Message;
using Snap.Hutao.Service.Hutao;

View File

@@ -2,11 +2,33 @@
// Licensed under the MIT license.
using Microsoft.Extensions.Caching.Memory;
using Snap.Hutao.Core;
using Snap.Hutao.Core.Caching;
using Snap.Hutao.Core.LifeCycle;
using Snap.Hutao.Core.Setting;
using Snap.Hutao.Service.Notification;
using Snap.Hutao.ViewModel.Guide;
using Snap.Hutao.Web.Hutao.HutaoAsAService;
using Snap.Hutao.Win32.Foundation;
using Snap.Hutao.Win32.Graphics.Direct3D;
using Snap.Hutao.Win32.Graphics.Direct3D11;
using Snap.Hutao.Win32.Graphics.Dxgi;
using Snap.Hutao.Win32.Graphics.Dxgi.Common;
using Snap.Hutao.Win32.System.Com;
using Snap.Hutao.Win32.System.WinRT;
using Snap.Hutao.Win32.System.WinRT.Graphics.Capture;
using System.IO;
using System.Runtime.CompilerServices;
using Windows.Foundation;
using Windows.Graphics.Capture;
using Windows.Graphics.DirectX;
using Windows.Graphics.DirectX.Direct3D11;
using Windows.Graphics.Imaging;
using Windows.Storage.Streams;
using WinRT;
using static Snap.Hutao.Win32.ConstValues;
using static Snap.Hutao.Win32.D3D11;
using static Snap.Hutao.Win32.Macros;
namespace Snap.Hutao.ViewModel;
@@ -19,6 +41,7 @@ namespace Snap.Hutao.ViewModel;
internal sealed partial class TestViewModel : Abstraction.ViewModel
{
private readonly HutaoAsAServiceClient homaAsAServiceClient;
private readonly IServiceProvider serviceProvider;
private readonly IInfoBarService infoBarService;
private readonly ILogger<TestViewModel> logger;
private readonly IMemoryCache memoryCache;
@@ -136,4 +159,156 @@ internal sealed partial class TestViewModel : Abstraction.ViewModel
logger.LogInformation("Failed ImageCache download tasks: [{Tasks}]", set?.ToString(','));
}
}
[Command("TestWindowsGraphicsCaptureCommand")]
private unsafe void TestWindowsGraphicsCapture()
{
// https://github.com/obsproject/obs-studio/blob/master/libobs-winrt/winrt-capture.cpp
if (!Core.UniversalApiContract.IsPresent(WindowsVersion.Windows10Version1903))
{
logger.LogWarning("Windows 10 Version 1903 or later is required for Windows.Graphics.Capture API.");
return;
}
if (!GraphicsCaptureSession.IsSupported())
{
logger.LogWarning("GraphicsCaptureSession is not supported.");
return;
}
D3D11_CREATE_DEVICE_FLAG flag = D3D11_CREATE_DEVICE_FLAG.D3D11_CREATE_DEVICE_BGRA_SUPPORT | D3D11_CREATE_DEVICE_FLAG.D3D11_CREATE_DEVICE_DEBUG;
if (SUCCEEDED(D3D11CreateDevice(default, D3D_DRIVER_TYPE.D3D_DRIVER_TYPE_HARDWARE, default, flag, [], D3D11_SDK_VERSION, out ID3D11Device* pD3D11Device, out _, out _)))
{
if (SUCCEEDED(IUnknownMarshal.QueryInterface(pD3D11Device, in IDXGIDevice.IID, out IDXGIDevice* pDXGIDevice)))
{
if (SUCCEEDED(CreateDirect3D11DeviceFromDXGIDevice(pDXGIDevice, out Win32.System.WinRT.IInspectable* inspectable)))
{
IDirect3DDevice direct3DDevice = WinRT.IInspectable.FromAbi((nint)inspectable).ObjRef.AsInterface<IDirect3DDevice>();
HWND hwnd = serviceProvider.GetRequiredService<ICurrentWindowReference>().GetWindowHandle();
GraphicsCaptureItem.As<IGraphicsCaptureItemInterop>().CreateForWindow(hwnd, out GraphicsCaptureItem item);
using (Direct3D11CaptureFramePool framePool = Direct3D11CaptureFramePool.CreateFreeThreaded(direct3DDevice, DirectXPixelFormat.B8G8R8A8UIntNormalized, 2, item.Size))
{
framePool.FrameArrived += (pool, _) =>
{
using (Direct3D11CaptureFrame frame = pool.TryGetNextFrame())
{
if (frame is not null)
{
logger.LogInformation("Content Size: {Width} x {Height}", frame.ContentSize.Width, frame.ContentSize.Height);
IDirect3DDxgiInterfaceAccess access = frame.Surface.As<IDirect3DDxgiInterfaceAccess>();
if (FAILED(access.GetInterface(in IDXGISurface.IID, out IDXGISurface* pDXGISurface)))
{
return;
}
if (FAILED(pDXGISurface->GetDesc(out DXGI_SURFACE_DESC surfaceDesc)))
{
return;
}
D3D11_TEXTURE2D_DESC texture2DDesc = default;
texture2DDesc.Width = surfaceDesc.Width;
texture2DDesc.Height = surfaceDesc.Height;
texture2DDesc.ArraySize = 1;
texture2DDesc.CPUAccessFlags = D3D11_CPU_ACCESS_FLAG.D3D11_CPU_ACCESS_READ;
texture2DDesc.Format = DXGI_FORMAT.DXGI_FORMAT_B8G8R8A8_UNORM;
texture2DDesc.MipLevels = 1;
texture2DDesc.SampleDesc.Count = 1;
texture2DDesc.Usage = D3D11_USAGE.D3D11_USAGE_STAGING;
if (FAILED(pDXGISurface->GetDevice(in ID3D11Device.IID, out ID3D11Device* pD3D11Device)))
{
return;
}
if (FAILED(pD3D11Device->CreateTexture2D(ref texture2DDesc, ref Unsafe.NullRef<D3D11_SUBRESOURCE_DATA>(), out ID3D11Texture2D* pTexture2D)))
{
return;
}
if (FAILED(access.GetInterface(in ID3D11Resource.IID, out ID3D11Resource* pD3D11Resource)))
{
return;
}
pD3D11Device->GetImmediateContext(out ID3D11DeviceContext* pDeviceContext);
pDeviceContext->CopyResource((ID3D11Resource*)pTexture2D, pD3D11Resource);
if (FAILED(pDeviceContext->Map((ID3D11Resource*)pTexture2D, 0, D3D11_MAP.D3D11_MAP_READ, 0, out D3D11_MAPPED_SUBRESOURCE mappedSubresource)))
{
return;
}
int size = (int)(mappedSubresource.RowPitch * texture2DDesc.Height * 4);
SoftwareBitmap softwareBitmap = new(BitmapPixelFormat.Bgra8, (int)texture2DDesc.Width, (int)texture2DDesc.Height, BitmapAlphaMode.Premultiplied);
using (BitmapBuffer bitmapBuffer = softwareBitmap.LockBuffer(BitmapBufferAccessMode.Write))
{
using (IMemoryBufferReference reference = bitmapBuffer.CreateReference())
{
reference.As<IMemoryBufferByteAccess>().GetBuffer(out Span<byte> bufferSpan);
fixed (byte* p = bufferSpan)
{
for (uint i = 0; i < texture2DDesc.Height; i++)
{
System.Buffer.MemoryCopy(((byte*)mappedSubresource.pData) + (i * mappedSubresource.RowPitch), p + (i * texture2DDesc.Width * 4), texture2DDesc.Width * 4, texture2DDesc.Width * 4);
}
}
}
}
using (InMemoryRandomAccessStream stream = new())
{
BitmapEncoder encoder = BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, stream).AsTask().Result;
encoder.SetSoftwareBitmap(softwareBitmap);
encoder.FlushAsync().AsTask().Wait();
using (FileStream fileStream = new("D:\\test.png", FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
{
stream.AsStream().CopyTo(fileStream);
}
}
_ = 1;
pDeviceContext->Unmap((ID3D11Resource*)pTexture2D, 0);
}
else
{
logger.LogInformation("Null Frame");
}
}
};
using (GraphicsCaptureSession captureSession = framePool.CreateCaptureSession(item))
{
captureSession.IsCursorCaptureEnabled = false;
captureSession.IsBorderRequired = false;
captureSession.StartCapture();
Thread.Sleep(1000);
}
}
}
else
{
logger.LogWarning("CreateDirect3D11DeviceFromDXGIDevice failed");
}
IUnknownMarshal.Release(pDXGIDevice);
}
else
{
logger.LogWarning("ID3D11Device As IDXGIDevice failed");
}
}
else
{
logger.LogWarning("D3D11CreateDevice failed");
}
}
}

View File

@@ -11,7 +11,6 @@ using Snap.Hutao.Service.Abstraction;
using Snap.Hutao.Service.Notification;
using Snap.Hutao.Service.Update;
using Snap.Hutao.View.Dialog;
using System.Diagnostics;
using System.Globalization;
using System.Text;

View File

@@ -1,6 +1,8 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Core.IO.Hashing;
namespace Snap.Hutao.Web.Hoyolab.DataSigning;
internal static class DataSignAlgorithm
@@ -19,7 +21,7 @@ internal static class DataSignAlgorithm
}
#pragma warning disable CA1308
string check = Core.Convert.ToMd5HexString(dsContent).ToLowerInvariant();
string check = Hash.MD5HexString(dsContent).ToLowerInvariant();
#pragma warning restore CA1308
return $"{t},{r},{check}";

View File

@@ -8,9 +8,7 @@ using Snap.Hutao.Web.Hoyolab.SdkStatic.Hk4e.Launcher.Resource;
using Snap.Hutao.Web.Request.Builder;
using Snap.Hutao.Web.Request.Builder.Abstraction;
using Snap.Hutao.Web.Response;
using System.IO;
using System.Net.Http;
using System.Text;
namespace Snap.Hutao.Web.Hoyolab.SdkStatic.Hk4e.Launcher;

View File

@@ -132,4 +132,10 @@ internal sealed class DailyNote : DailyNoteCommon
[JsonPropertyName("archon_quest_progress")]
public ArchonQuestProgress ArchonQuestProgress { get; set; } = default!;
[JsonIgnore]
public bool IsArchonQuestFinished
{
get => ArchonQuestProgress.List.Count == 0;
}
}

View File

@@ -43,7 +43,7 @@ internal sealed partial class HutaoInfrastructureClient
{
HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create()
.SetRequestUri(HutaoEndpoints.PatchSnapHutao)
.SetHeader("x-device-id", runtimeOptions.DeviceId)
.SetHeader("x-hutao-device-id", runtimeOptions.DeviceId)
.Get();
HutaoResponse<HutaoVersionInformation>? resp = await builder.TryCatchSendAsync<HutaoResponse<HutaoVersionInformation>>(httpClient, logger, token).ConfigureAwait(false);

View File

@@ -1,8 +1,8 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using System.Net.Http;
using Snap.Hutao.Core.Abstraction;
using System.Net.Http;
namespace Snap.Hutao.Web.Request.Builder.Abstraction;

View File

@@ -1,8 +1,8 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using System.Net.Http.Headers;
using Snap.Hutao.Core.Abstraction;
using System.Net.Http.Headers;
namespace Snap.Hutao.Web.Request.Builder.Abstraction;

View File

@@ -1,8 +1,8 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using System.Net.Http;
using Snap.Hutao.Core.Abstraction;
using System.Net.Http;
namespace Snap.Hutao.Web.Request.Builder.Abstraction;

View File

@@ -1,8 +1,8 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using System.Net.Http;
using Snap.Hutao.Core.Abstraction;
using System.Net.Http;
namespace Snap.Hutao.Web.Request.Builder.Abstraction;

View File

@@ -1,8 +1,8 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using System.Net.Http;
using Snap.Hutao.Core.Abstraction;
using System.Net.Http;
namespace Snap.Hutao.Web.Request.Builder.Abstraction;

View File

@@ -6,6 +6,7 @@ namespace Snap.Hutao.Win32;
[SuppressMessage("", "SA1310")]
internal static class ConstValues
{
public const uint D3D11_SDK_VERSION = 0x00000007U;
public const uint WM_NULL = 0x00000000U;
public const uint WM_ERASEBKGND = 0x00000014U;
public const uint WM_GETMINMAXINFO = 0x00000024U;

View File

@@ -0,0 +1,49 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Win32.Foundation;
using Snap.Hutao.Win32.Graphics.Direct3D;
using Snap.Hutao.Win32.Graphics.Direct3D11;
using Snap.Hutao.Win32.Graphics.Dxgi;
using Snap.Hutao.Win32.System.WinRT;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace Snap.Hutao.Win32;
[SuppressMessage("", "SA1313")]
[SuppressMessage("", "SYSLIB1054")]
internal static class D3D11
{
[DllImport("d3d11.dll", CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
public static unsafe extern HRESULT CreateDirect3D11DeviceFromDXGIDevice(IDXGIDevice* dxgiDevice, IInspectable** graphicsDevice);
[DebuggerStepThrough]
public static unsafe HRESULT CreateDirect3D11DeviceFromDXGIDevice(IDXGIDevice* dxgiDevice, out IInspectable* graphicsDevice)
{
fixed (IInspectable** pGraphicsDevice = &graphicsDevice)
{
return CreateDirect3D11DeviceFromDXGIDevice(dxgiDevice, pGraphicsDevice);
}
}
[DllImport("d3d11.dll", CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
public static unsafe extern HRESULT D3D11CreateDevice([AllowNull] IDXGIAdapter* pAdapter, D3D_DRIVER_TYPE DriverType, HMODULE Software, D3D11_CREATE_DEVICE_FLAG Flags, [AllowNull] D3D_FEATURE_LEVEL* pFeatureLevels, uint FeatureLevels, uint SDKVersion, [MaybeNull] ID3D11Device** ppDevice, [MaybeNull] D3D_FEATURE_LEVEL* pFeatureLevel, [MaybeNull] ID3D11DeviceContext** ppImmediateContext);
public static unsafe HRESULT D3D11CreateDevice([AllowNull] IDXGIAdapter* pAdapter, D3D_DRIVER_TYPE DriverType, HMODULE Software, D3D11_CREATE_DEVICE_FLAG Flags, [AllowNull] ReadOnlySpan<D3D_FEATURE_LEVEL> featureLevels, uint SDKVersion, out ID3D11Device* pDevice, out D3D_FEATURE_LEVEL featureLevel, out ID3D11DeviceContext* pImmediateContext)
{
fixed (ID3D11Device** ppDevice = &pDevice)
{
fixed (D3D_FEATURE_LEVEL* pFeatureLevels = featureLevels)
{
fixed (D3D_FEATURE_LEVEL* pFeatureLevel = &featureLevel)
{
fixed (ID3D11DeviceContext** ppImmediateContext = &pImmediateContext)
{
return D3D11CreateDevice(pAdapter, DriverType, Software, Flags, pFeatureLevels, (uint)featureLevels.Length, SDKVersion, ppDevice, pFeatureLevel, ppImmediateContext);
}
}
}
}
}
}

View File

@@ -15,12 +15,17 @@ internal readonly partial struct HRESULT
public static unsafe implicit operator int(HRESULT value) => *(int*)&value;
public static unsafe implicit operator HRESULT(int value) => *(HRESULT*)&value;
public override string ToString()
{
return $"0x{Value:X8}";
}
}
#if DEBUG
[DebuggerDisplay("{DebuggerDisplay}")]
internal readonly partial struct HRESULT
{
private string DebuggerDisplay => $"0x{Value:X8}";
private string DebuggerDisplay { get => ToString(); }
}
#endif

View File

@@ -9,7 +9,7 @@ internal readonly struct HWND
public HWND(nint value) => Value = value;
public bool IsNull => Value is 0;
public static unsafe implicit operator HWND(nint value) => *(HWND*)&value;
public static unsafe implicit operator nint(HWND value) => *(nint*)&value;
}

View File

@@ -0,0 +1,10 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Win32.Foundation;
internal readonly struct LUID
{
public readonly uint LowPart;
public readonly int HighPart;
}

View File

@@ -0,0 +1,9 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Win32.Foundation;
internal readonly struct PCSTR
{
public readonly unsafe byte* Value;
}

View File

@@ -0,0 +1,9 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Win32.Foundation;
internal readonly struct PSTR
{
public readonly unsafe byte* Value;
}

View File

@@ -0,0 +1,14 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Win32.Graphics.Direct3D;
internal enum D3D_DRIVER_TYPE
{
D3D_DRIVER_TYPE_UNKNOWN = 0,
D3D_DRIVER_TYPE_HARDWARE = 1,
D3D_DRIVER_TYPE_REFERENCE = 2,
D3D_DRIVER_TYPE_NULL = 3,
D3D_DRIVER_TYPE_SOFTWARE = 4,
D3D_DRIVER_TYPE_WARP = 5,
}

View File

@@ -0,0 +1,20 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Win32.Graphics.Direct3D;
internal enum D3D_FEATURE_LEVEL
{
D3D_FEATURE_LEVEL_1_0_GENERIC = 0x100,
D3D_FEATURE_LEVEL_1_0_CORE = 0x1000,
D3D_FEATURE_LEVEL_9_1 = 0x9100,
D3D_FEATURE_LEVEL_9_2 = 0x9200,
D3D_FEATURE_LEVEL_9_3 = 0x9300,
D3D_FEATURE_LEVEL_10_0 = 0xA000,
D3D_FEATURE_LEVEL_10_1 = 0xA100,
D3D_FEATURE_LEVEL_11_0 = 0xB000,
D3D_FEATURE_LEVEL_11_1 = 0xB100,
D3D_FEATURE_LEVEL_12_0 = 0xC000,
D3D_FEATURE_LEVEL_12_1 = 0xC100,
D3D_FEATURE_LEVEL_12_2 = 0xC200,
}

View File

@@ -0,0 +1,103 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Win32.Graphics.Direct3D;
internal enum D3D_PRIMITIVE_TOPOLOGY
{
D3D_PRIMITIVE_TOPOLOGY_UNDEFINED = 0,
D3D_PRIMITIVE_TOPOLOGY_POINTLIST = 1,
D3D_PRIMITIVE_TOPOLOGY_LINELIST = 2,
D3D_PRIMITIVE_TOPOLOGY_LINESTRIP = 3,
D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST = 4,
D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP = 5,
D3D_PRIMITIVE_TOPOLOGY_TRIANGLEFAN = 6,
D3D_PRIMITIVE_TOPOLOGY_LINELIST_ADJ = 10,
D3D_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ = 11,
D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ = 12,
D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ = 13,
D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST = 33,
D3D_PRIMITIVE_TOPOLOGY_2_CONTROL_POINT_PATCHLIST = 34,
D3D_PRIMITIVE_TOPOLOGY_3_CONTROL_POINT_PATCHLIST = 35,
D3D_PRIMITIVE_TOPOLOGY_4_CONTROL_POINT_PATCHLIST = 36,
D3D_PRIMITIVE_TOPOLOGY_5_CONTROL_POINT_PATCHLIST = 37,
D3D_PRIMITIVE_TOPOLOGY_6_CONTROL_POINT_PATCHLIST = 38,
D3D_PRIMITIVE_TOPOLOGY_7_CONTROL_POINT_PATCHLIST = 39,
D3D_PRIMITIVE_TOPOLOGY_8_CONTROL_POINT_PATCHLIST = 40,
D3D_PRIMITIVE_TOPOLOGY_9_CONTROL_POINT_PATCHLIST = 41,
D3D_PRIMITIVE_TOPOLOGY_10_CONTROL_POINT_PATCHLIST = 42,
D3D_PRIMITIVE_TOPOLOGY_11_CONTROL_POINT_PATCHLIST = 43,
D3D_PRIMITIVE_TOPOLOGY_12_CONTROL_POINT_PATCHLIST = 44,
D3D_PRIMITIVE_TOPOLOGY_13_CONTROL_POINT_PATCHLIST = 45,
D3D_PRIMITIVE_TOPOLOGY_14_CONTROL_POINT_PATCHLIST = 46,
D3D_PRIMITIVE_TOPOLOGY_15_CONTROL_POINT_PATCHLIST = 47,
D3D_PRIMITIVE_TOPOLOGY_16_CONTROL_POINT_PATCHLIST = 48,
D3D_PRIMITIVE_TOPOLOGY_17_CONTROL_POINT_PATCHLIST = 49,
D3D_PRIMITIVE_TOPOLOGY_18_CONTROL_POINT_PATCHLIST = 50,
D3D_PRIMITIVE_TOPOLOGY_19_CONTROL_POINT_PATCHLIST = 51,
D3D_PRIMITIVE_TOPOLOGY_20_CONTROL_POINT_PATCHLIST = 52,
D3D_PRIMITIVE_TOPOLOGY_21_CONTROL_POINT_PATCHLIST = 53,
D3D_PRIMITIVE_TOPOLOGY_22_CONTROL_POINT_PATCHLIST = 54,
D3D_PRIMITIVE_TOPOLOGY_23_CONTROL_POINT_PATCHLIST = 55,
D3D_PRIMITIVE_TOPOLOGY_24_CONTROL_POINT_PATCHLIST = 56,
D3D_PRIMITIVE_TOPOLOGY_25_CONTROL_POINT_PATCHLIST = 57,
D3D_PRIMITIVE_TOPOLOGY_26_CONTROL_POINT_PATCHLIST = 58,
D3D_PRIMITIVE_TOPOLOGY_27_CONTROL_POINT_PATCHLIST = 59,
D3D_PRIMITIVE_TOPOLOGY_28_CONTROL_POINT_PATCHLIST = 60,
D3D_PRIMITIVE_TOPOLOGY_29_CONTROL_POINT_PATCHLIST = 61,
D3D_PRIMITIVE_TOPOLOGY_30_CONTROL_POINT_PATCHLIST = 62,
D3D_PRIMITIVE_TOPOLOGY_31_CONTROL_POINT_PATCHLIST = 63,
D3D_PRIMITIVE_TOPOLOGY_32_CONTROL_POINT_PATCHLIST = 64,
D3D10_PRIMITIVE_TOPOLOGY_UNDEFINED = 0,
D3D10_PRIMITIVE_TOPOLOGY_POINTLIST = 1,
D3D10_PRIMITIVE_TOPOLOGY_LINELIST = 2,
D3D10_PRIMITIVE_TOPOLOGY_LINESTRIP = 3,
D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST = 4,
D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP = 5,
D3D10_PRIMITIVE_TOPOLOGY_LINELIST_ADJ = 10,
D3D10_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ = 11,
D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ = 12,
D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ = 13,
D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED = 0,
D3D11_PRIMITIVE_TOPOLOGY_POINTLIST = 1,
D3D11_PRIMITIVE_TOPOLOGY_LINELIST = 2,
D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP = 3,
D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST = 4,
D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP = 5,
D3D11_PRIMITIVE_TOPOLOGY_LINELIST_ADJ = 10,
D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ = 11,
D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ = 12,
D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ = 13,
D3D11_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST = 33,
D3D11_PRIMITIVE_TOPOLOGY_2_CONTROL_POINT_PATCHLIST = 34,
D3D11_PRIMITIVE_TOPOLOGY_3_CONTROL_POINT_PATCHLIST = 35,
D3D11_PRIMITIVE_TOPOLOGY_4_CONTROL_POINT_PATCHLIST = 36,
D3D11_PRIMITIVE_TOPOLOGY_5_CONTROL_POINT_PATCHLIST = 37,
D3D11_PRIMITIVE_TOPOLOGY_6_CONTROL_POINT_PATCHLIST = 38,
D3D11_PRIMITIVE_TOPOLOGY_7_CONTROL_POINT_PATCHLIST = 39,
D3D11_PRIMITIVE_TOPOLOGY_8_CONTROL_POINT_PATCHLIST = 40,
D3D11_PRIMITIVE_TOPOLOGY_9_CONTROL_POINT_PATCHLIST = 41,
D3D11_PRIMITIVE_TOPOLOGY_10_CONTROL_POINT_PATCHLIST = 42,
D3D11_PRIMITIVE_TOPOLOGY_11_CONTROL_POINT_PATCHLIST = 43,
D3D11_PRIMITIVE_TOPOLOGY_12_CONTROL_POINT_PATCHLIST = 44,
D3D11_PRIMITIVE_TOPOLOGY_13_CONTROL_POINT_PATCHLIST = 45,
D3D11_PRIMITIVE_TOPOLOGY_14_CONTROL_POINT_PATCHLIST = 46,
D3D11_PRIMITIVE_TOPOLOGY_15_CONTROL_POINT_PATCHLIST = 47,
D3D11_PRIMITIVE_TOPOLOGY_16_CONTROL_POINT_PATCHLIST = 48,
D3D11_PRIMITIVE_TOPOLOGY_17_CONTROL_POINT_PATCHLIST = 49,
D3D11_PRIMITIVE_TOPOLOGY_18_CONTROL_POINT_PATCHLIST = 50,
D3D11_PRIMITIVE_TOPOLOGY_19_CONTROL_POINT_PATCHLIST = 51,
D3D11_PRIMITIVE_TOPOLOGY_20_CONTROL_POINT_PATCHLIST = 52,
D3D11_PRIMITIVE_TOPOLOGY_21_CONTROL_POINT_PATCHLIST = 53,
D3D11_PRIMITIVE_TOPOLOGY_22_CONTROL_POINT_PATCHLIST = 54,
D3D11_PRIMITIVE_TOPOLOGY_23_CONTROL_POINT_PATCHLIST = 55,
D3D11_PRIMITIVE_TOPOLOGY_24_CONTROL_POINT_PATCHLIST = 56,
D3D11_PRIMITIVE_TOPOLOGY_25_CONTROL_POINT_PATCHLIST = 57,
D3D11_PRIMITIVE_TOPOLOGY_26_CONTROL_POINT_PATCHLIST = 58,
D3D11_PRIMITIVE_TOPOLOGY_27_CONTROL_POINT_PATCHLIST = 59,
D3D11_PRIMITIVE_TOPOLOGY_28_CONTROL_POINT_PATCHLIST = 60,
D3D11_PRIMITIVE_TOPOLOGY_29_CONTROL_POINT_PATCHLIST = 61,
D3D11_PRIMITIVE_TOPOLOGY_30_CONTROL_POINT_PATCHLIST = 62,
D3D11_PRIMITIVE_TOPOLOGY_31_CONTROL_POINT_PATCHLIST = 63,
D3D11_PRIMITIVE_TOPOLOGY_32_CONTROL_POINT_PATCHLIST = 64,
}

View File

@@ -0,0 +1,53 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Win32.Graphics.Direct3D;
internal enum D3D_SRV_DIMENSION
{
D3D_SRV_DIMENSION_UNKNOWN = 0,
D3D_SRV_DIMENSION_BUFFER = 1,
D3D_SRV_DIMENSION_TEXTURE1D = 2,
D3D_SRV_DIMENSION_TEXTURE1DARRAY = 3,
D3D_SRV_DIMENSION_TEXTURE2D = 4,
D3D_SRV_DIMENSION_TEXTURE2DARRAY = 5,
D3D_SRV_DIMENSION_TEXTURE2DMS = 6,
D3D_SRV_DIMENSION_TEXTURE2DMSARRAY = 7,
D3D_SRV_DIMENSION_TEXTURE3D = 8,
D3D_SRV_DIMENSION_TEXTURECUBE = 9,
D3D_SRV_DIMENSION_TEXTURECUBEARRAY = 10,
D3D_SRV_DIMENSION_BUFFEREX = 11,
D3D10_SRV_DIMENSION_UNKNOWN = 0,
D3D10_SRV_DIMENSION_BUFFER = 1,
D3D10_SRV_DIMENSION_TEXTURE1D = 2,
D3D10_SRV_DIMENSION_TEXTURE1DARRAY = 3,
D3D10_SRV_DIMENSION_TEXTURE2D = 4,
D3D10_SRV_DIMENSION_TEXTURE2DARRAY = 5,
D3D10_SRV_DIMENSION_TEXTURE2DMS = 6,
D3D10_SRV_DIMENSION_TEXTURE2DMSARRAY = 7,
D3D10_SRV_DIMENSION_TEXTURE3D = 8,
D3D10_SRV_DIMENSION_TEXTURECUBE = 9,
D3D10_1_SRV_DIMENSION_UNKNOWN = 0,
D3D10_1_SRV_DIMENSION_BUFFER = 1,
D3D10_1_SRV_DIMENSION_TEXTURE1D = 2,
D3D10_1_SRV_DIMENSION_TEXTURE1DARRAY = 3,
D3D10_1_SRV_DIMENSION_TEXTURE2D = 4,
D3D10_1_SRV_DIMENSION_TEXTURE2DARRAY = 5,
D3D10_1_SRV_DIMENSION_TEXTURE2DMS = 6,
D3D10_1_SRV_DIMENSION_TEXTURE2DMSARRAY = 7,
D3D10_1_SRV_DIMENSION_TEXTURE3D = 8,
D3D10_1_SRV_DIMENSION_TEXTURECUBE = 9,
D3D10_1_SRV_DIMENSION_TEXTURECUBEARRAY = 10,
D3D11_SRV_DIMENSION_UNKNOWN = 0,
D3D11_SRV_DIMENSION_BUFFER = 1,
D3D11_SRV_DIMENSION_TEXTURE1D = 2,
D3D11_SRV_DIMENSION_TEXTURE1DARRAY = 3,
D3D11_SRV_DIMENSION_TEXTURE2D = 4,
D3D11_SRV_DIMENSION_TEXTURE2DARRAY = 5,
D3D11_SRV_DIMENSION_TEXTURE2DMS = 6,
D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY = 7,
D3D11_SRV_DIMENSION_TEXTURE3D = 8,
D3D11_SRV_DIMENSION_TEXTURECUBE = 9,
D3D11_SRV_DIMENSION_TEXTURECUBEARRAY = 10,
D3D11_SRV_DIMENSION_BUFFEREX = 11,
}

View File

@@ -0,0 +1,19 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Win32.Graphics.Direct3D11;
[Flags]
internal enum D3D11_BIND_FLAG : uint
{
D3D11_BIND_VERTEX_BUFFER = 0x1,
D3D11_BIND_INDEX_BUFFER = 0x2,
D3D11_BIND_CONSTANT_BUFFER = 0x4,
D3D11_BIND_SHADER_RESOURCE = 0x8,
D3D11_BIND_STREAM_OUTPUT = 0x10,
D3D11_BIND_RENDER_TARGET = 0x20,
D3D11_BIND_DEPTH_STENCIL = 0x40,
D3D11_BIND_UNORDERED_ACCESS = 0x80,
D3D11_BIND_DECODER = 0x200,
D3D11_BIND_VIDEO_ENCODER = 0x400,
}

View File

@@ -0,0 +1,25 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Win32.Graphics.Direct3D11;
internal enum D3D11_BLEND
{
D3D11_BLEND_ZERO = 1,
D3D11_BLEND_ONE = 2,
D3D11_BLEND_SRC_COLOR = 3,
D3D11_BLEND_INV_SRC_COLOR = 4,
D3D11_BLEND_SRC_ALPHA = 5,
D3D11_BLEND_INV_SRC_ALPHA = 6,
D3D11_BLEND_DEST_ALPHA = 7,
D3D11_BLEND_INV_DEST_ALPHA = 8,
D3D11_BLEND_DEST_COLOR = 9,
D3D11_BLEND_INV_DEST_COLOR = 10,
D3D11_BLEND_SRC_ALPHA_SAT = 11,
D3D11_BLEND_BLEND_FACTOR = 14,
D3D11_BLEND_INV_BLEND_FACTOR = 15,
D3D11_BLEND_SRC1_COLOR = 16,
D3D11_BLEND_INV_SRC1_COLOR = 17,
D3D11_BLEND_SRC1_ALPHA = 18,
D3D11_BLEND_INV_SRC1_ALPHA = 19,
}

View File

@@ -0,0 +1,20 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Win32.Foundation;
using System.Runtime.CompilerServices;
namespace Snap.Hutao.Win32.Graphics.Direct3D11;
internal struct D3D11_BLEND_DESC
{
public BOOL AlphaToCoverageEnable;
public BOOL IndependentBlendEnable;
public D3D11_RENDER_TARGET_BLEND_DESC_8 RenderTarget;
[InlineArray(8)]
internal struct D3D11_RENDER_TARGET_BLEND_DESC_8
{
public D3D11_RENDER_TARGET_BLEND_DESC Value;
}
}

View File

@@ -0,0 +1,13 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Win32.Graphics.Direct3D11;
internal enum D3D11_BLEND_OP
{
D3D11_BLEND_OP_ADD = 1,
D3D11_BLEND_OP_SUBTRACT = 2,
D3D11_BLEND_OP_REV_SUBTRACT = 3,
D3D11_BLEND_OP_MIN = 4,
D3D11_BLEND_OP_MAX = 5,
}

View File

@@ -0,0 +1,14 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Win32.Graphics.Direct3D11;
public struct D3D11_BOX
{
public uint left;
public uint top;
public uint front;
public uint right;
public uint bottom;
public uint back;
}

Some files were not shown because too many files have changed in this diff Show More