mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
cultivation
This commit is contained in:
@@ -59,6 +59,7 @@
|
||||
<shmmc:QualityColorConverter x:Key="QualityColorConverter"/>
|
||||
<shmmc:WeaponTypeIconConverter x:Key="WeaponTypeIconConverter"/>
|
||||
<shvc:BoolToVisibilityRevertConverter x:Key="BoolToVisibilityRevertConverter"/>
|
||||
<shvc:EmptyObjectToVisibilityConverter x:Key="EmptyObjectToVisibilityConverter"/>
|
||||
|
||||
<!-- Styles -->
|
||||
<Style
|
||||
@@ -67,6 +68,13 @@
|
||||
TargetType="GridViewItem">
|
||||
<Setter Property="Margin" Value="0,0,12,12"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="BorderCardStyle" TargetType="Border">
|
||||
<Setter Property="Background" Value="{ThemeResource CardBackgroundFillColorDefaultBrush}"/>
|
||||
<Setter Property="BorderBrush" Value="{ThemeResource CardStrokeColorDefaultBrush}"/>
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Setter Property="CornerRadius" Value="{StaticResource CompatCornerRadius}"/>
|
||||
</Style>
|
||||
<!-- ItemsPanelTemplate -->
|
||||
<ItemsPanelTemplate x:Key="ItemsStackPanelTemplate">
|
||||
<ItemsStackPanel/>
|
||||
|
||||
@@ -36,28 +36,35 @@ public partial class App : Application
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
[SuppressMessage("", "VSTHRD100")]
|
||||
protected override async void OnLaunched(LaunchActivatedEventArgs args)
|
||||
protected override void OnLaunched(LaunchActivatedEventArgs args)
|
||||
{
|
||||
AppActivationArguments activatedEventArgs = AppInstance.GetCurrent().GetActivatedEventArgs();
|
||||
AppInstance firstInstance = AppInstance.FindOrRegisterForKey("main");
|
||||
|
||||
if (firstInstance.IsCurrent)
|
||||
try
|
||||
{
|
||||
// manually invoke
|
||||
Activation.Activate(firstInstance, activatedEventArgs);
|
||||
firstInstance.Activated += Activation.Activate;
|
||||
ToastNotificationManagerCompat.OnActivated += Activation.NotificationActivate;
|
||||
AppActivationArguments activatedEventArgs = AppInstance.GetCurrent().GetActivatedEventArgs();
|
||||
AppInstance firstInstance = AppInstance.FindOrRegisterForKey("main");
|
||||
|
||||
logger.LogInformation(EventIds.CommonLog, "Snap Hutao | {name} : {version}", CoreEnvironment.FamilyName, CoreEnvironment.Version);
|
||||
logger.LogInformation(EventIds.CommonLog, "Cache folder : {folder}", ApplicationData.Current.TemporaryFolder.Path);
|
||||
if (firstInstance.IsCurrent)
|
||||
{
|
||||
// manually invoke
|
||||
Activation.Activate(firstInstance, activatedEventArgs);
|
||||
firstInstance.Activated += Activation.Activate;
|
||||
ToastNotificationManagerCompat.OnActivated += Activation.NotificationActivate;
|
||||
|
||||
JumpListHelper.ConfigAsync().SafeForget(logger);
|
||||
logger.LogInformation(EventIds.CommonLog, "Snap Hutao | {name} : {version}", CoreEnvironment.FamilyName, CoreEnvironment.Version);
|
||||
logger.LogInformation(EventIds.CommonLog, "Cache folder : {folder}", ApplicationData.Current.TemporaryFolder.Path);
|
||||
|
||||
JumpListHelper.ConfigureAsync().SafeForget(logger);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Redirect the activation (and args) to the "main" instance, and exit.
|
||||
firstInstance.RedirectActivationTo(activatedEventArgs);
|
||||
Process.GetCurrentProcess().Kill();
|
||||
}
|
||||
}
|
||||
else
|
||||
catch (Exception)
|
||||
{
|
||||
// Redirect the activation (and args) to the "main" instance, and exit.
|
||||
await firstInstance.RedirectActivationToAsync(activatedEventArgs);
|
||||
// AppInstance.GetCurrent() calls failed
|
||||
Process.GetCurrentProcess().Kill();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,6 +102,21 @@ public sealed class AppDbContext : DbContext
|
||||
/// </summary>
|
||||
public DbSet<CultivateItem> CultivateItems { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 背包内物品
|
||||
/// </summary>
|
||||
public DbSet<InventoryItem> InventoryItems { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 背包内武器
|
||||
/// </summary>
|
||||
public DbSet<InventoryWeapon> InventoryWeapons { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 背包内圣遗物
|
||||
/// </summary>
|
||||
public DbSet<InventoryReliquary> InventoryReliquaries { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个临时的应用程序数据库上下文
|
||||
/// </summary>
|
||||
@@ -125,6 +140,7 @@ public sealed class AppDbContext : DbContext
|
||||
modelBuilder
|
||||
.ApplyConfiguration(new AvatarInfoConfiguration())
|
||||
.ApplyConfiguration(new UserConfiguration())
|
||||
.ApplyConfiguration(new DailyNoteEntryConfiguration());
|
||||
.ApplyConfiguration(new DailyNoteEntryConfiguration())
|
||||
.ApplyConfiguration(new InventoryReliquaryConfiguration());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using CommunityToolkit.WinUI.UI.Behaviors;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Snap.Hutao.Control.Behavior;
|
||||
|
||||
/// <summary>
|
||||
/// AppTitleBar Workaround
|
||||
/// https://github.com/microsoft/microsoft-ui-xaml/issues/7756
|
||||
/// </summary>
|
||||
internal class ComboBoxExtendsContentIntoTitleBarWorkaroundBehavior : BehaviorBase<ComboBox>
|
||||
{
|
||||
private readonly IMessenger messenger;
|
||||
|
||||
/// <summary>
|
||||
/// AppTitleBar Workaround
|
||||
/// </summary>
|
||||
public ComboBoxExtendsContentIntoTitleBarWorkaroundBehavior()
|
||||
{
|
||||
messenger = Ioc.Default.GetRequiredService<IMessenger>();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void OnAssociatedObjectLoaded()
|
||||
{
|
||||
AssociatedObject.DropDownOpened += OnDropDownOpened;
|
||||
AssociatedObject.DropDownClosed += OnDropDownClosed;
|
||||
}
|
||||
|
||||
private void OnDropDownOpened(object? sender, object e)
|
||||
{
|
||||
messenger.Send(new Message.FlyoutOpenCloseMessage(true));
|
||||
}
|
||||
|
||||
private void OnDropDownClosed(object? sender, object e)
|
||||
{
|
||||
messenger.Send(new Message.FlyoutOpenCloseMessage(false));
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,7 @@ internal class InvokeCommandOnUnloadedBehavior : BehaviorBase<UIElement>
|
||||
/// <inheritdoc/>
|
||||
protected override void OnDetaching()
|
||||
{
|
||||
// 由于卸载顺序问题,必须重写此方法才能正确触发命令
|
||||
if (Command != null && Command.CanExecute(null))
|
||||
{
|
||||
Command.Execute(null);
|
||||
@@ -32,4 +33,4 @@ internal class InvokeCommandOnUnloadedBehavior : BehaviorBase<UIElement>
|
||||
|
||||
base.OnDetaching();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -244,6 +244,10 @@ public class ImageCache : IImageCache
|
||||
logger.LogInformation("Retry after {delay}.", delay);
|
||||
await Task.Delay(delay).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (retryCount == 3)
|
||||
|
||||
@@ -23,33 +23,6 @@ public static class DbSetExtension
|
||||
return dbSet.GetService<ICurrentDbContext>().Context;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取或添加一个对应的实体
|
||||
/// </summary>
|
||||
/// <typeparam name="TEntity">实体类型</typeparam>
|
||||
/// <param name="dbSet">数据库集</param>
|
||||
/// <param name="predicate">谓词</param>
|
||||
/// <param name="entityFactory">实体工厂</param>
|
||||
/// <param name="added">是否添加</param>
|
||||
/// <returns>实体</returns>
|
||||
public static TEntity SingleOrAdd<TEntity>(this DbSet<TEntity> dbSet, Func<TEntity, bool> predicate, Func<TEntity> entityFactory, out bool added)
|
||||
where TEntity : class
|
||||
{
|
||||
added = false;
|
||||
TEntity? entry = dbSet.SingleOrDefault(predicate);
|
||||
|
||||
if (entry == null)
|
||||
{
|
||||
entry = entityFactory();
|
||||
dbSet.Add(entry);
|
||||
dbSet.Context().SaveChanges();
|
||||
|
||||
added = true;
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加并保存
|
||||
/// </summary>
|
||||
|
||||
@@ -15,7 +15,7 @@ public static class JumpListHelper
|
||||
/// 异步配置跳转列表
|
||||
/// </summary>
|
||||
/// <returns>任务</returns>
|
||||
public static async Task ConfigAsync()
|
||||
public static async Task ConfigureAsync()
|
||||
{
|
||||
if (JumpList.IsSupported())
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using CommunityToolkit.WinUI.Notifications;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Windows.AppLifecycle;
|
||||
using Snap.Hutao.Extension;
|
||||
using Snap.Hutao.Service.Abstraction;
|
||||
@@ -192,9 +193,9 @@ internal static class Activation
|
||||
|
||||
private static async Task HandleLaunchGameActionAsync(string? uid = null)
|
||||
{
|
||||
Ioc.Default.GetRequiredService<IMemoryCache>().Set(ViewModel.LaunchGameViewModel.DesiredUid, uid);
|
||||
await ThreadHelper.SwitchToMainThreadAsync();
|
||||
|
||||
// TODO auto switch to account
|
||||
if (!MainWindow.IsPresent)
|
||||
{
|
||||
_ = Ioc.Default.GetRequiredService<LaunchGameWindow>();
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.Windows.AppLifecycle;
|
||||
using Windows.Win32.Foundation;
|
||||
using Windows.Win32.Security;
|
||||
using Windows.Win32.System.Com;
|
||||
using static Windows.Win32.PInvoke;
|
||||
|
||||
namespace Snap.Hutao.Core.LifeCycle;
|
||||
|
||||
/// <summary>
|
||||
/// App 实例拓展
|
||||
/// </summary>
|
||||
internal static class AppInstanceExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// 同步非阻塞重定向
|
||||
/// </summary>
|
||||
/// <param name="appInstance">app实例</param>
|
||||
/// <param name="args">参数</param>
|
||||
[SuppressMessage("", "VSTHRD002")]
|
||||
[SuppressMessage("", "VSTHRD110")]
|
||||
public static unsafe void RedirectActivationTo(this AppInstance appInstance, AppActivationArguments args)
|
||||
{
|
||||
HANDLE redirectEventHandle = CreateEvent((SECURITY_ATTRIBUTES*)null, true, false, null);
|
||||
Task.Run(() =>
|
||||
{
|
||||
appInstance.RedirectActivationToAsync(args).AsTask().Wait();
|
||||
SetEvent(redirectEventHandle);
|
||||
});
|
||||
|
||||
ReadOnlySpan<HANDLE> handles = new(in redirectEventHandle);
|
||||
|
||||
// non-blocking
|
||||
CoWaitForMultipleObjects((uint)CWMO_FLAGS.CWMO_DEFAULT, INFINITE, handles, out uint _);
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,7 @@ namespace Snap.Hutao.Core.Windowing;
|
||||
/// </summary>
|
||||
/// <typeparam name="TWindow">窗体类型</typeparam>
|
||||
[SuppressMessage("", "CA1001")]
|
||||
internal sealed class ExtendedWindow<TWindow> : IRecipient<BackdropTypeChangedMessage>
|
||||
internal sealed class ExtendedWindow<TWindow> : IRecipient<BackdropTypeChangedMessage>, IRecipient<FlyoutOpenCloseMessage>
|
||||
where TWindow : Window, IExtendedWindowSource
|
||||
{
|
||||
private readonly HWND handle;
|
||||
@@ -82,6 +82,12 @@ internal sealed class ExtendedWindow<TWindow> : IRecipient<BackdropTypeChangedMe
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Receive(FlyoutOpenCloseMessage message)
|
||||
{
|
||||
UpdateDragRectangles(appWindow.TitleBar, message.IsOpen);
|
||||
}
|
||||
|
||||
private static void UpdateTitleButtonColor(AppWindowTitleBar appTitleBar)
|
||||
{
|
||||
appTitleBar.ButtonBackgroundColor = Colors.Transparent;
|
||||
@@ -137,7 +143,9 @@ internal sealed class ExtendedWindow<TWindow> : IRecipient<BackdropTypeChangedMe
|
||||
bool subClassApplied = subclassManager.TrySetWindowSubclass();
|
||||
logger.LogInformation(EventIds.SubClassing, "Apply {name} : {result}", nameof(WindowSubclassManager<TWindow>), subClassApplied ? "succeed" : "failed");
|
||||
|
||||
Ioc.Default.GetRequiredService<IMessenger>().Register(this);
|
||||
IMessenger messenger = Ioc.Default.GetRequiredService<IMessenger>();
|
||||
messenger.Register<BackdropTypeChangedMessage>(this);
|
||||
messenger.Register<FlyoutOpenCloseMessage>(this);
|
||||
window.Closed += OnWindowClosed;
|
||||
}
|
||||
|
||||
@@ -172,17 +180,25 @@ internal sealed class ExtendedWindow<TWindow> : IRecipient<BackdropTypeChangedMe
|
||||
}
|
||||
}
|
||||
|
||||
private unsafe void UpdateDragRectangles(AppWindowTitleBar appTitleBar)
|
||||
private void UpdateDragRectangles(AppWindowTitleBar appTitleBar, bool isFlyoutOpened = false)
|
||||
{
|
||||
double scale = Persistence.GetScaleForWindow(handle);
|
||||
if (isFlyoutOpened)
|
||||
{
|
||||
// set to 0
|
||||
appTitleBar.SetDragRectangles(default(RectInt32).Enumerate().ToArray());
|
||||
}
|
||||
else
|
||||
{
|
||||
double scale = Persistence.GetScaleForWindow(handle);
|
||||
|
||||
// 48 is the navigation button leftInset
|
||||
RectInt32 dragRect = StructMarshal.RectInt32(new(48, 0), titleBar.ActualSize).Scale(scale);
|
||||
appTitleBar.SetDragRectangles(dragRect.Enumerate().ToArray());
|
||||
// 48 is the navigation button leftInset
|
||||
RectInt32 dragRect = StructMarshal.RectInt32(new(48, 0), titleBar.ActualSize).Scale(scale);
|
||||
appTitleBar.SetDragRectangles(dragRect.Enumerate().ToArray());
|
||||
|
||||
// workaround for https://github.com/microsoft/WindowsAppSDK/issues/2976
|
||||
SizeInt32 size = appWindow.ClientSize;
|
||||
size.Height -= (int)(31 * scale);
|
||||
appWindow.ResizeClient(size);
|
||||
// workaround for https://github.com/microsoft/WindowsAppSDK/issues/2976
|
||||
SizeInt32 size = appWindow.ClientSize;
|
||||
size.Height -= (int)(31 * scale);
|
||||
appWindow.ResizeClient(size);
|
||||
}
|
||||
}
|
||||
}
|
||||
26
src/Snap.Hutao/Snap.Hutao/Message/FlyoutOpenCloseMessage.cs
Normal file
26
src/Snap.Hutao/Snap.Hutao/Message/FlyoutOpenCloseMessage.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Core.Windowing;
|
||||
|
||||
namespace Snap.Hutao.Message;
|
||||
|
||||
/// <summary>
|
||||
/// Flyout开启关闭消息
|
||||
/// </summary>
|
||||
internal class FlyoutOpenCloseMessage
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造一个新的Flyout开启关闭消息
|
||||
/// </summary>
|
||||
/// <param name="isOpen">是否为开启状态</param>
|
||||
public FlyoutOpenCloseMessage(bool isOpen)
|
||||
{
|
||||
IsOpen = isOpen;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否为开启状态
|
||||
/// </summary>
|
||||
public bool IsOpen { get; }
|
||||
}
|
||||
512
src/Snap.Hutao/Snap.Hutao/Migrations/20221210111128_Inventory.Designer.cs
generated
Normal file
512
src/Snap.Hutao/Snap.Hutao/Migrations/20221210111128_Inventory.Designer.cs
generated
Normal file
@@ -0,0 +1,512 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Snap.Hutao.Context.Database;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Snap.Hutao.Migrations
|
||||
{
|
||||
[DbContext(typeof(AppDbContext))]
|
||||
[Migration("20221210111128_Inventory")]
|
||||
partial class Inventory
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder.HasAnnotation("ProductVersion", "7.0.0");
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.Achievement", b =>
|
||||
{
|
||||
b.Property<Guid>("InnerId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("ArchiveId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("Current")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Id")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Status")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTimeOffset>("Time")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("InnerId");
|
||||
|
||||
b.HasIndex("ArchiveId");
|
||||
|
||||
b.ToTable("achievements");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.AchievementArchive", b =>
|
||||
{
|
||||
b.Property<Guid>("InnerId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsSelected")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("InnerId");
|
||||
|
||||
b.ToTable("achievement_archives");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.AvatarInfo", b =>
|
||||
{
|
||||
b.Property<Guid>("InnerId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Info")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Uid")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("InnerId");
|
||||
|
||||
b.ToTable("avatar_infos");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.CultivateEntry", b =>
|
||||
{
|
||||
b.Property<Guid>("InnerId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("Id")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<Guid>("ProjectId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("Type")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("InnerId");
|
||||
|
||||
b.HasIndex("ProjectId");
|
||||
|
||||
b.ToTable("cultivate_entries");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.CultivateItem", b =>
|
||||
{
|
||||
b.Property<Guid>("InnerId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("Count")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<Guid>("EntryId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("ItemId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("InnerId");
|
||||
|
||||
b.HasIndex("EntryId");
|
||||
|
||||
b.ToTable("cultivate_items");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.CultivateProject", b =>
|
||||
{
|
||||
b.Property<Guid>("InnerId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("AttachedUid")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsSelected")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("InnerId");
|
||||
|
||||
b.ToTable("cultivate_projects");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.DailyNoteEntry", b =>
|
||||
{
|
||||
b.Property<Guid>("InnerId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("DailyNote")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("DailyTaskNotify")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("DailyTaskNotifySuppressed")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("ExpeditionNotify")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("ExpeditionNotifySuppressed")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("HomeCoinNotifySuppressed")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("HomeCoinNotifyThreshold")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("ResinNotifySuppressed")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("ResinNotifyThreshold")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("ShowInHomeWidget")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("TransformerNotify")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("TransformerNotifySuppressed")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Uid")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("InnerId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("daily_notes");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.GachaArchive", b =>
|
||||
{
|
||||
b.Property<Guid>("InnerId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsSelected")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Uid")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("InnerId");
|
||||
|
||||
b.ToTable("gacha_archives");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.GachaItem", b =>
|
||||
{
|
||||
b.Property<Guid>("InnerId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("ArchiveId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("GachaType")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<long>("Id")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("ItemId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("QueryType")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTimeOffset>("Time")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("InnerId");
|
||||
|
||||
b.HasIndex("ArchiveId");
|
||||
|
||||
b.ToTable("gacha_items");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.GameAccount", b =>
|
||||
{
|
||||
b.Property<Guid>("InnerId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("AttachUid")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("MihoyoSDK")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("Type")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("InnerId");
|
||||
|
||||
b.ToTable("game_accounts");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.InventoryItem", b =>
|
||||
{
|
||||
b.Property<Guid>("InnerId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("Count")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("ItemId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<Guid>("ProjectId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("InnerId");
|
||||
|
||||
b.HasIndex("ProjectId");
|
||||
|
||||
b.ToTable("inventory_items");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.InventoryReliquary", b =>
|
||||
{
|
||||
b.Property<Guid>("InnerId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("AppendPropIdList")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("ItemId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Level")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("MainPropId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<Guid>("ProjectId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("InnerId");
|
||||
|
||||
b.HasIndex("ProjectId");
|
||||
|
||||
b.ToTable("inventory_reliquaries");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.InventoryWeapon", b =>
|
||||
{
|
||||
b.Property<Guid>("InnerId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("ItemId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Level")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<Guid>("ProjectId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("PromoteLevel")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("InnerId");
|
||||
|
||||
b.HasIndex("ProjectId");
|
||||
|
||||
b.ToTable("inventory_weapons");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.ObjectCacheEntry", b =>
|
||||
{
|
||||
b.Property<string>("Key")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTimeOffset>("ExpireTime")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Key");
|
||||
|
||||
b.ToTable("object_cache");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.SettingEntry", b =>
|
||||
{
|
||||
b.Property<string>("Key")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Key");
|
||||
|
||||
b.ToTable("settings");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.User", b =>
|
||||
{
|
||||
b.Property<Guid>("InnerId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Aid")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("CookieToken")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsSelected")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Ltoken")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Mid")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Stoken")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("InnerId");
|
||||
|
||||
b.ToTable("users");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.Achievement", b =>
|
||||
{
|
||||
b.HasOne("Snap.Hutao.Model.Entity.AchievementArchive", "Archive")
|
||||
.WithMany()
|
||||
.HasForeignKey("ArchiveId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Archive");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.CultivateEntry", b =>
|
||||
{
|
||||
b.HasOne("Snap.Hutao.Model.Entity.CultivateProject", "Project")
|
||||
.WithMany()
|
||||
.HasForeignKey("ProjectId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Project");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.CultivateItem", b =>
|
||||
{
|
||||
b.HasOne("Snap.Hutao.Model.Entity.CultivateEntry", "Entry")
|
||||
.WithMany()
|
||||
.HasForeignKey("EntryId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Entry");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.DailyNoteEntry", b =>
|
||||
{
|
||||
b.HasOne("Snap.Hutao.Model.Entity.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.GachaItem", b =>
|
||||
{
|
||||
b.HasOne("Snap.Hutao.Model.Entity.GachaArchive", "Archive")
|
||||
.WithMany("Items")
|
||||
.HasForeignKey("ArchiveId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Archive");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.InventoryItem", b =>
|
||||
{
|
||||
b.HasOne("Snap.Hutao.Model.Entity.CultivateProject", "Project")
|
||||
.WithMany()
|
||||
.HasForeignKey("ProjectId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Project");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.InventoryReliquary", b =>
|
||||
{
|
||||
b.HasOne("Snap.Hutao.Model.Entity.CultivateProject", "Project")
|
||||
.WithMany()
|
||||
.HasForeignKey("ProjectId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Project");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.InventoryWeapon", b =>
|
||||
{
|
||||
b.HasOne("Snap.Hutao.Model.Entity.CultivateProject", "Project")
|
||||
.WithMany()
|
||||
.HasForeignKey("ProjectId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Project");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.GachaArchive", b =>
|
||||
{
|
||||
b.Navigation("Items");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
117
src/Snap.Hutao/Snap.Hutao/Migrations/20221210111128_Inventory.cs
Normal file
117
src/Snap.Hutao/Snap.Hutao/Migrations/20221210111128_Inventory.cs
Normal file
@@ -0,0 +1,117 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Snap.Hutao.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class Inventory : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "AttachedUid",
|
||||
table: "cultivate_projects",
|
||||
type: "TEXT",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "inventory_items",
|
||||
columns: table => new
|
||||
{
|
||||
InnerId = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||
ProjectId = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||
ItemId = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
Count = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_inventory_items", x => x.InnerId);
|
||||
table.ForeignKey(
|
||||
name: "FK_inventory_items_cultivate_projects_ProjectId",
|
||||
column: x => x.ProjectId,
|
||||
principalTable: "cultivate_projects",
|
||||
principalColumn: "InnerId",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "inventory_reliquaries",
|
||||
columns: table => new
|
||||
{
|
||||
InnerId = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||
ProjectId = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||
ItemId = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
Level = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
MainPropId = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
AppendPropIdList = table.Column<string>(type: "TEXT", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_inventory_reliquaries", x => x.InnerId);
|
||||
table.ForeignKey(
|
||||
name: "FK_inventory_reliquaries_cultivate_projects_ProjectId",
|
||||
column: x => x.ProjectId,
|
||||
principalTable: "cultivate_projects",
|
||||
principalColumn: "InnerId",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "inventory_weapons",
|
||||
columns: table => new
|
||||
{
|
||||
InnerId = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||
ProjectId = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||
ItemId = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
Level = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
PromoteLevel = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_inventory_weapons", x => x.InnerId);
|
||||
table.ForeignKey(
|
||||
name: "FK_inventory_weapons_cultivate_projects_ProjectId",
|
||||
column: x => x.ProjectId,
|
||||
principalTable: "cultivate_projects",
|
||||
principalColumn: "InnerId",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_inventory_items_ProjectId",
|
||||
table: "inventory_items",
|
||||
column: "ProjectId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_inventory_reliquaries_ProjectId",
|
||||
table: "inventory_reliquaries",
|
||||
column: "ProjectId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_inventory_weapons_ProjectId",
|
||||
table: "inventory_weapons",
|
||||
column: "ProjectId");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "inventory_items");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "inventory_reliquaries");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "inventory_weapons");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "AttachedUid",
|
||||
table: "cultivate_projects");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,7 +42,7 @@ namespace Snap.Hutao.Migrations
|
||||
|
||||
b.HasIndex("ArchiveId");
|
||||
|
||||
b.ToTable("achievements");
|
||||
b.ToTable("achievements", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.AchievementArchive", b =>
|
||||
@@ -60,7 +60,7 @@ namespace Snap.Hutao.Migrations
|
||||
|
||||
b.HasKey("InnerId");
|
||||
|
||||
b.ToTable("achievement_archives");
|
||||
b.ToTable("achievement_archives", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.AvatarInfo", b =>
|
||||
@@ -79,7 +79,7 @@ namespace Snap.Hutao.Migrations
|
||||
|
||||
b.HasKey("InnerId");
|
||||
|
||||
b.ToTable("avatar_infos");
|
||||
b.ToTable("avatar_infos", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.CultivateEntry", b =>
|
||||
@@ -101,7 +101,7 @@ namespace Snap.Hutao.Migrations
|
||||
|
||||
b.HasIndex("ProjectId");
|
||||
|
||||
b.ToTable("cultivate_entries");
|
||||
b.ToTable("cultivate_entries", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.CultivateItem", b =>
|
||||
@@ -123,7 +123,7 @@ namespace Snap.Hutao.Migrations
|
||||
|
||||
b.HasIndex("EntryId");
|
||||
|
||||
b.ToTable("cultivate_items");
|
||||
b.ToTable("cultivate_items", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.CultivateProject", b =>
|
||||
@@ -132,6 +132,9 @@ namespace Snap.Hutao.Migrations
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("AttachedUid")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsSelected")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
@@ -141,7 +144,7 @@ namespace Snap.Hutao.Migrations
|
||||
|
||||
b.HasKey("InnerId");
|
||||
|
||||
b.ToTable("cultivate_projects");
|
||||
b.ToTable("cultivate_projects", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.DailyNoteEntry", b =>
|
||||
@@ -197,7 +200,7 @@ namespace Snap.Hutao.Migrations
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("daily_notes");
|
||||
b.ToTable("daily_notes", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.GachaArchive", b =>
|
||||
@@ -215,7 +218,7 @@ namespace Snap.Hutao.Migrations
|
||||
|
||||
b.HasKey("InnerId");
|
||||
|
||||
b.ToTable("gacha_archives");
|
||||
b.ToTable("gacha_archives", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.GachaItem", b =>
|
||||
@@ -246,7 +249,7 @@ namespace Snap.Hutao.Migrations
|
||||
|
||||
b.HasIndex("ArchiveId");
|
||||
|
||||
b.ToTable("gacha_items");
|
||||
b.ToTable("gacha_items", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.GameAccount", b =>
|
||||
@@ -271,7 +274,83 @@ namespace Snap.Hutao.Migrations
|
||||
|
||||
b.HasKey("InnerId");
|
||||
|
||||
b.ToTable("game_accounts");
|
||||
b.ToTable("game_accounts", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.InventoryItem", b =>
|
||||
{
|
||||
b.Property<Guid>("InnerId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("Count")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("ItemId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<Guid>("ProjectId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("InnerId");
|
||||
|
||||
b.HasIndex("ProjectId");
|
||||
|
||||
b.ToTable("inventory_items", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.InventoryReliquary", b =>
|
||||
{
|
||||
b.Property<Guid>("InnerId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("AppendPropIdList")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("ItemId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Level")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("MainPropId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<Guid>("ProjectId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("InnerId");
|
||||
|
||||
b.HasIndex("ProjectId");
|
||||
|
||||
b.ToTable("inventory_reliquaries", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.InventoryWeapon", b =>
|
||||
{
|
||||
b.Property<Guid>("InnerId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("ItemId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Level")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<Guid>("ProjectId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("PromoteLevel")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("InnerId");
|
||||
|
||||
b.HasIndex("ProjectId");
|
||||
|
||||
b.ToTable("inventory_weapons", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.ObjectCacheEntry", b =>
|
||||
@@ -287,7 +366,7 @@ namespace Snap.Hutao.Migrations
|
||||
|
||||
b.HasKey("Key");
|
||||
|
||||
b.ToTable("object_cache");
|
||||
b.ToTable("object_cache", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.SettingEntry", b =>
|
||||
@@ -300,7 +379,7 @@ namespace Snap.Hutao.Migrations
|
||||
|
||||
b.HasKey("Key");
|
||||
|
||||
b.ToTable("settings");
|
||||
b.ToTable("settings", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.User", b =>
|
||||
@@ -329,13 +408,13 @@ namespace Snap.Hutao.Migrations
|
||||
|
||||
b.HasKey("InnerId");
|
||||
|
||||
b.ToTable("users");
|
||||
b.ToTable("users", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.Achievement", b =>
|
||||
{
|
||||
b.HasOne("Snap.Hutao.Model.Entity.AchievementArchive", "Archive")
|
||||
.WithMany("Achievements")
|
||||
.WithMany()
|
||||
.HasForeignKey("ArchiveId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
@@ -346,7 +425,7 @@ namespace Snap.Hutao.Migrations
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.CultivateEntry", b =>
|
||||
{
|
||||
b.HasOne("Snap.Hutao.Model.Entity.CultivateProject", "Project")
|
||||
.WithMany("Entries")
|
||||
.WithMany()
|
||||
.HasForeignKey("ProjectId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
@@ -357,7 +436,7 @@ namespace Snap.Hutao.Migrations
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.CultivateItem", b =>
|
||||
{
|
||||
b.HasOne("Snap.Hutao.Model.Entity.CultivateEntry", "Entry")
|
||||
.WithMany("Items")
|
||||
.WithMany()
|
||||
.HasForeignKey("EntryId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
@@ -387,19 +466,37 @@ namespace Snap.Hutao.Migrations
|
||||
b.Navigation("Archive");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.AchievementArchive", b =>
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.InventoryItem", b =>
|
||||
{
|
||||
b.Navigation("Achievements");
|
||||
b.HasOne("Snap.Hutao.Model.Entity.CultivateProject", "Project")
|
||||
.WithMany()
|
||||
.HasForeignKey("ProjectId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Project");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.CultivateEntry", b =>
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.InventoryReliquary", b =>
|
||||
{
|
||||
b.Navigation("Items");
|
||||
b.HasOne("Snap.Hutao.Model.Entity.CultivateProject", "Project")
|
||||
.WithMany()
|
||||
.HasForeignKey("ProjectId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Project");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.CultivateProject", b =>
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.InventoryWeapon", b =>
|
||||
{
|
||||
b.Navigation("Entries");
|
||||
b.HasOne("Snap.Hutao.Model.Entity.CultivateProject", "Project")
|
||||
.WithMany()
|
||||
.HasForeignKey("ProjectId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Project");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.GachaArchive", b =>
|
||||
|
||||
@@ -15,9 +15,6 @@ public class Achievement : ObservableObject
|
||||
/// </summary>
|
||||
public const int FullProgressPlaceholder = int.MaxValue;
|
||||
|
||||
private readonly Metadata.Achievement.Achievement inner;
|
||||
private readonly Entity.Achievement entity;
|
||||
|
||||
private bool isChecked;
|
||||
|
||||
/// <summary>
|
||||
@@ -27,22 +24,21 @@ public class Achievement : ObservableObject
|
||||
/// <param name="entity">实体部分</param>
|
||||
public Achievement(Metadata.Achievement.Achievement inner, Entity.Achievement entity)
|
||||
{
|
||||
this.inner = inner;
|
||||
this.entity = entity;
|
||||
Inner = inner;
|
||||
Entity = entity;
|
||||
|
||||
// Property should only be set when it's user checking.
|
||||
isChecked = (int)entity.Status >= 2;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 实体
|
||||
/// </summary>
|
||||
public Entity.Achievement Entity { get => entity; }
|
||||
public Entity.Achievement Entity { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 元数据
|
||||
/// </summary>
|
||||
public Metadata.Achievement.Achievement Inner { get => inner; }
|
||||
public Metadata.Achievement.Achievement Inner { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否选中
|
||||
@@ -69,6 +65,6 @@ public class Achievement : ObservableObject
|
||||
/// </summary>
|
||||
public string Time
|
||||
{
|
||||
get => entity.Time.ToString("yyyy.MM.dd HH:mm:ss");
|
||||
get => Entity.Time.ToString("yyyy.MM.dd HH:mm:ss");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Model.Binding.Gacha.Abstraction;
|
||||
|
||||
namespace Snap.Hutao.Model.Binding.Cultivation;
|
||||
|
||||
/// <summary>
|
||||
/// 养成物品
|
||||
/// </summary>
|
||||
public class CultivateEntry : ItemBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Id
|
||||
/// </summary>
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 入口Id
|
||||
/// </summary>
|
||||
public Guid EntryId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 实体
|
||||
/// </summary>
|
||||
public List<CultivateItem> Items { get; set; } = default!;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Snap.Hutao.Model.Metadata;
|
||||
|
||||
namespace Snap.Hutao.Model.Binding.Cultivation;
|
||||
|
||||
/// <summary>
|
||||
/// 养成物品
|
||||
/// </summary>
|
||||
public class CultivateItem : ObservableObject
|
||||
{
|
||||
/// <summary>
|
||||
/// 养成物品
|
||||
/// </summary>
|
||||
/// <param name="inner">元数据</param>
|
||||
/// <param name="entity">实体</param>
|
||||
public CultivateItem(Material inner, Entity.CultivateItem entity)
|
||||
{
|
||||
Inner = inner;
|
||||
Entity = entity;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 元数据
|
||||
/// </summary>
|
||||
public Material Inner { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 实体
|
||||
/// </summary>
|
||||
public Entity.CultivateItem Entity { get; }
|
||||
}
|
||||
@@ -14,14 +14,9 @@ public enum CultivateType
|
||||
None,
|
||||
|
||||
/// <summary>
|
||||
/// 角色
|
||||
/// 角色与技能
|
||||
/// </summary>
|
||||
Avatar,
|
||||
|
||||
/// <summary>
|
||||
/// 角色技能
|
||||
/// </summary>
|
||||
Skill,
|
||||
AvatarAndSkill,
|
||||
|
||||
/// <summary>
|
||||
/// 武器
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Snap.Hutao.Model.Metadata;
|
||||
|
||||
namespace Snap.Hutao.Model.Binding.Inventory;
|
||||
|
||||
/// <summary>
|
||||
/// 背包物品
|
||||
/// </summary>
|
||||
internal class InventoryItem : ObservableObject
|
||||
{
|
||||
private uint count;
|
||||
|
||||
/// <summary>
|
||||
/// 创建一个新的背包物品
|
||||
/// </summary>
|
||||
/// <param name="inner">元数据</param>
|
||||
/// <param name="entity">实体</param>
|
||||
public InventoryItem(Material inner, Entity.InventoryItem entity)
|
||||
{
|
||||
Entity = entity;
|
||||
Inner = inner;
|
||||
count = entity.Count;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 实体
|
||||
/// </summary>
|
||||
public Entity.InventoryItem Entity { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 元数据
|
||||
/// </summary>
|
||||
public Material Inner { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 个数
|
||||
/// </summary>
|
||||
public uint Count
|
||||
{
|
||||
get => count; set
|
||||
{
|
||||
if (SetProperty(ref count, value))
|
||||
{
|
||||
Entity.Count = value;
|
||||
Ioc.Default.GetRequiredService<Service.Cultivation.ICultivationService>().SaveInventoryItem(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
namespace Snap.Hutao.Model.Entity.Configuration;
|
||||
|
||||
/// <summary>
|
||||
/// 背包圣遗物配置
|
||||
/// </summary>
|
||||
internal class InventoryReliquaryConfiguration : IEntityTypeConfiguration<InventoryReliquary>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public void Configure(EntityTypeBuilder<InventoryReliquary> builder)
|
||||
{
|
||||
builder.Property(e => e.AppendPropIdList)
|
||||
.HasColumnType("TEXT")
|
||||
.HasConversion(
|
||||
list => string.Join(',', list),
|
||||
text => text.Split(',', StringSplitOptions.None).Select(x => int.Parse(x)).ToList());
|
||||
}
|
||||
}
|
||||
@@ -42,7 +42,18 @@ public class CultivateEntry
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 物品
|
||||
/// 创建一个新的养成入口点
|
||||
/// </summary>
|
||||
public virtual ICollection<CultivateItem> Items { get; set; } = default!;
|
||||
/// <param name="type">类型</param>
|
||||
/// <param name="id">主Id</param>
|
||||
/// <returns>养成入口点</returns>
|
||||
public static CultivateEntry Create(Guid projectId,CultivateType type, int id)
|
||||
{
|
||||
return new()
|
||||
{
|
||||
ProjectId = projectId,
|
||||
Type = type,
|
||||
Id = id,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -39,4 +39,21 @@ public class CultivateItem
|
||||
/// 物品个数
|
||||
/// </summary>
|
||||
public int Count { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建一个新的养成物品
|
||||
/// </summary>
|
||||
/// <param name="entryId">入口点 Id</param>
|
||||
/// <param name="itemId">物品 Id</param>
|
||||
/// <param name="count">个数</param>
|
||||
/// <returns>养成物品</returns>
|
||||
public static CultivateItem Create(Guid entryId, int itemId, int count)
|
||||
{
|
||||
return new()
|
||||
{
|
||||
EntryId = entryId,
|
||||
ItemId = itemId,
|
||||
Count = count,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,18 @@ public class CultivateProject : ISelectable
|
||||
public string Name { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 入口集合
|
||||
/// 所属的Uid
|
||||
/// </summary>
|
||||
public virtual ICollection<CultivateEntry> Entries { get; set; } = default!;
|
||||
}
|
||||
public string? AttachedUid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建新的养成计划
|
||||
/// </summary>
|
||||
/// <param name="name">名称</param>
|
||||
/// <param name="attachedUid">绑定的Uid</param>
|
||||
/// <returns>新的养成计划</returns>
|
||||
public static CultivateProject Create(string name, string? attachedUid = null)
|
||||
{
|
||||
return new() { Name = name, AttachedUid = attachedUid };
|
||||
}
|
||||
}
|
||||
57
src/Snap.Hutao/Snap.Hutao/Model/Entity/InventoryItem.cs
Normal file
57
src/Snap.Hutao/Snap.Hutao/Model/Entity/InventoryItem.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Snap.Hutao.Model.Entity;
|
||||
|
||||
/// <summary>
|
||||
/// 背包物品
|
||||
/// </summary>
|
||||
[Table("inventory_items")]
|
||||
public class InventoryItem
|
||||
{
|
||||
/// <summary>
|
||||
/// 内部Id
|
||||
/// </summary>
|
||||
[Key]
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public Guid InnerId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 培养计划Id
|
||||
/// </summary>
|
||||
public Guid ProjectId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 所属的计划
|
||||
/// </summary>
|
||||
[ForeignKey(nameof(ProjectId))]
|
||||
public CultivateProject Project { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 物品Id
|
||||
/// </summary>
|
||||
public int ItemId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 个数 4294967295
|
||||
/// </summary>
|
||||
public uint Count { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的个数为0的物品
|
||||
/// </summary>
|
||||
/// <param name="projectId">项目Id</param>
|
||||
/// <param name="itemId">物品Id</param>
|
||||
/// <returns>新的个数为0的物品</returns>
|
||||
public static InventoryItem Create(Guid projectId, int itemId)
|
||||
{
|
||||
return new()
|
||||
{
|
||||
ProjectId = projectId,
|
||||
ItemId = itemId,
|
||||
};
|
||||
}
|
||||
}
|
||||
52
src/Snap.Hutao/Snap.Hutao/Model/Entity/InventoryReliquary.cs
Normal file
52
src/Snap.Hutao/Snap.Hutao/Model/Entity/InventoryReliquary.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Snap.Hutao.Model.Entity;
|
||||
|
||||
/// <summary>
|
||||
/// 背包圣遗物
|
||||
/// </summary>
|
||||
[Table("inventory_reliquaries")]
|
||||
public class InventoryReliquary
|
||||
{
|
||||
/// <summary>
|
||||
/// 内部Id
|
||||
/// </summary>
|
||||
[Key]
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public Guid InnerId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 培养计划Id
|
||||
/// </summary>
|
||||
public Guid ProjectId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 所属的计划
|
||||
/// </summary>
|
||||
[ForeignKey(nameof(ProjectId))]
|
||||
public CultivateProject Project { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 物品Id
|
||||
/// </summary>
|
||||
public int ItemId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 等级
|
||||
/// </summary>
|
||||
public int Level { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 主属性
|
||||
/// </summary>
|
||||
public int MainPropId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 副词条Id
|
||||
/// </summary>
|
||||
public List<int> AppendPropIdList { get; set; } = default!;
|
||||
}
|
||||
47
src/Snap.Hutao/Snap.Hutao/Model/Entity/InventoryWeapon.cs
Normal file
47
src/Snap.Hutao/Snap.Hutao/Model/Entity/InventoryWeapon.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Snap.Hutao.Model.Entity;
|
||||
|
||||
/// <summary>
|
||||
/// 背包武器
|
||||
/// </summary>
|
||||
[Table("inventory_weapons")]
|
||||
public class InventoryWeapon
|
||||
{
|
||||
/// <summary>
|
||||
/// 内部Id
|
||||
/// </summary>
|
||||
[Key]
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public Guid InnerId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 培养计划Id
|
||||
/// </summary>
|
||||
public Guid ProjectId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 所属的计划
|
||||
/// </summary>
|
||||
[ForeignKey(nameof(ProjectId))]
|
||||
public CultivateProject Project { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 物品Id
|
||||
/// </summary>
|
||||
public int ItemId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 等级
|
||||
/// </summary>
|
||||
public int Level { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 精炼等级 0-4
|
||||
/// </summary>
|
||||
public int PromoteLevel { get; set; }
|
||||
}
|
||||
@@ -5,7 +5,7 @@ namespace Snap.Hutao.Model.InterChange.Achievement;
|
||||
|
||||
/// <summary>
|
||||
/// 统一可交换成就格式
|
||||
/// https://www.snapgenshin.com/development/UIAF.html
|
||||
/// https://uigf.org/standards/UIAF.html
|
||||
/// </summary>
|
||||
public class UIAF
|
||||
{
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace Snap.Hutao.Model.InterChange.GachaLog;
|
||||
|
||||
/// <summary>
|
||||
/// 统一可交换祈愿格式
|
||||
/// https://www.snapgenshin.com/development/UIGF.html
|
||||
/// https://uigf.org/standards/UIGF.html
|
||||
/// </summary>
|
||||
public class UIGF
|
||||
{
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.Collections.Immutable;
|
||||
|
||||
namespace Snap.Hutao.Model.InterChange.Inventory;
|
||||
|
||||
/// <summary>
|
||||
/// 统一可交换物品格式
|
||||
/// </summary>
|
||||
internal class UIIF
|
||||
{
|
||||
/// <summary>
|
||||
/// 当前发行的版本
|
||||
/// </summary>
|
||||
public const string CurrentVersion = "v1.0";
|
||||
|
||||
private static readonly ImmutableList<string> SupportedVersion = new List<string>()
|
||||
{
|
||||
CurrentVersion,
|
||||
}.ToImmutableList();
|
||||
|
||||
/// <summary>
|
||||
/// 信息
|
||||
/// </summary>
|
||||
[JsonPropertyName("info")]
|
||||
public UIIFInfo Info { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 列表
|
||||
/// </summary>
|
||||
[JsonPropertyName("list")]
|
||||
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; }
|
||||
}
|
||||
|
||||
/// <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; }
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
using Snap.Hutao.Core;
|
||||
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;
|
||||
|
||||
/// <summary>
|
||||
/// UIIF格式的信息
|
||||
/// </summary>
|
||||
public class UIIFInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// 用户Uid
|
||||
/// </summary>
|
||||
[JsonPropertyName("uid")]
|
||||
public string Uid { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 语言
|
||||
/// </summary>
|
||||
[JsonPropertyName("lang")]
|
||||
public string Language { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 导出的时间戳
|
||||
/// </summary>
|
||||
[JsonPropertyName("export_timestamp")]
|
||||
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString)]
|
||||
public long? ExportTimestamp { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 导出时间
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public DateTimeOffset ExportDateTime
|
||||
{
|
||||
get => DateTimeOffsetExtension.FromUnixTime(ExportTimestamp, DateTimeOffset.MinValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 导出的 App 名称
|
||||
/// </summary>
|
||||
[JsonPropertyName("export_app")]
|
||||
public string ExportApp { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 导出的 App 版本
|
||||
/// </summary>
|
||||
[JsonPropertyName("export_app_version")]
|
||||
public string ExportAppVersion { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 使用的UIGF版本
|
||||
/// </summary>
|
||||
[JsonPropertyName("uiif_version")]
|
||||
public string UIIFVersion { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的专用 UIGF 信息
|
||||
/// </summary>
|
||||
/// <param name="uid">uid</param>
|
||||
/// <returns>专用 UIGF 信息</returns>
|
||||
public static UIIFInfo Create(string uid)
|
||||
{
|
||||
return new()
|
||||
{
|
||||
Uid = uid,
|
||||
Language = "zh-cn",
|
||||
ExportTimestamp = DateTimeOffset.Now.ToUnixTimeSeconds(),
|
||||
ExportApp = "胡桃",
|
||||
ExportAppVersion = CoreEnvironment.Version.ToString(),
|
||||
UIIFVersion = UIIF.CurrentVersion,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -19,4 +19,5 @@ public interface INameQuality
|
||||
/// 星级
|
||||
/// </summary>
|
||||
ItemQuality Quality { get; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Model.Binding.Gacha;
|
||||
using Snap.Hutao.Model.Binding.Gacha.Abstraction;
|
||||
using Snap.Hutao.Model.Binding.Hutao;
|
||||
using Snap.Hutao.Model.Metadata.Abstraction;
|
||||
using Snap.Hutao.Model.Metadata.Converter;
|
||||
using Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate;
|
||||
|
||||
namespace Snap.Hutao.Model.Metadata.Avatar;
|
||||
|
||||
/// <summary>
|
||||
/// 角色的接口实现部分
|
||||
/// </summary>
|
||||
public partial class Avatar : IStatisticsItemSource, ISummaryItemSource, INameQuality, ICalculableSource<ICalculableAvatar>
|
||||
{
|
||||
/// <summary>
|
||||
/// [非元数据] 搭配数据
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public ComplexAvatarCollocation? Collocation { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ICalculableAvatar ToCalculable()
|
||||
{
|
||||
return new CalculableAvatar(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为基础物品
|
||||
/// </summary>
|
||||
/// <returns>基础物品</returns>
|
||||
public ItemBase ToItemBase()
|
||||
{
|
||||
return new()
|
||||
{
|
||||
Name = Name,
|
||||
Icon = AvatarIconConverter.IconNameToUri(Icon),
|
||||
Badge = ElementNameIconConverter.ElementNameToIconUri(FetterInfo.VisionBefore),
|
||||
Quality = Quality,
|
||||
};
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public StatisticsItem ToStatisticsItem(int count)
|
||||
{
|
||||
return new()
|
||||
{
|
||||
Name = Name,
|
||||
Icon = AvatarIconConverter.IconNameToUri(Icon),
|
||||
Badge = ElementNameIconConverter.ElementNameToIconUri(FetterInfo.VisionBefore),
|
||||
Quality = Quality,
|
||||
|
||||
Count = count,
|
||||
};
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public SummaryItem ToSummaryItem(int lastPull, DateTimeOffset time, bool isUp)
|
||||
{
|
||||
return new()
|
||||
{
|
||||
Name = Name,
|
||||
Icon = AvatarIconConverter.IconNameToUri(Icon),
|
||||
Badge = ElementNameIconConverter.ElementNameToIconUri(FetterInfo.VisionBefore),
|
||||
Quality = Quality,
|
||||
|
||||
Time = time,
|
||||
LastPull = lastPull,
|
||||
IsUp = isUp,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -2,12 +2,7 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Core.Json.Annotation;
|
||||
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.Metadata.Abstraction;
|
||||
using Snap.Hutao.Model.Metadata.Converter;
|
||||
using Snap.Hutao.Model.Primitive;
|
||||
|
||||
namespace Snap.Hutao.Model.Metadata.Avatar;
|
||||
@@ -15,7 +10,7 @@ namespace Snap.Hutao.Model.Metadata.Avatar;
|
||||
/// <summary>
|
||||
/// 角色
|
||||
/// </summary>
|
||||
public class Avatar : IStatisticsItemSource, ISummaryItemSource, INameQuality
|
||||
public partial class Avatar
|
||||
{
|
||||
/// <summary>
|
||||
/// Id
|
||||
@@ -87,65 +82,4 @@ public class Avatar : IStatisticsItemSource, ISummaryItemSource, INameQuality
|
||||
/// 皮肤
|
||||
/// </summary>
|
||||
public IEnumerable<Costume> Costumes { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// [非元数据] 搭配数据
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public ComplexAvatarCollocation? Collocation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 转换为基础物品
|
||||
/// </summary>
|
||||
/// <returns>基础物品</returns>
|
||||
public ItemBase ToItemBase()
|
||||
{
|
||||
return new()
|
||||
{
|
||||
Name = Name,
|
||||
Icon = AvatarIconConverter.IconNameToUri(Icon),
|
||||
Badge = ElementNameIconConverter.ElementNameToIconUri(FetterInfo.VisionBefore),
|
||||
Quality = Quality,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换到统计物品
|
||||
/// </summary>
|
||||
/// <param name="count">个数</param>
|
||||
/// <returns>统计物品</returns>
|
||||
public StatisticsItem ToStatisticsItem(int count)
|
||||
{
|
||||
return new()
|
||||
{
|
||||
Name = Name,
|
||||
Icon = AvatarIconConverter.IconNameToUri(Icon),
|
||||
Badge = ElementNameIconConverter.ElementNameToIconUri(FetterInfo.VisionBefore),
|
||||
Quality = Quality,
|
||||
|
||||
Count = count,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换到简述统计物品
|
||||
/// </summary>
|
||||
/// <param name="lastPull">距上个五星</param>
|
||||
/// <param name="time">时间</param>
|
||||
/// <param name="isUp">是否为Up物品</param>
|
||||
/// <returns>简述统计物品</returns>
|
||||
public SummaryItem ToSummaryItem(int lastPull, DateTimeOffset time, bool isUp)
|
||||
{
|
||||
return new()
|
||||
{
|
||||
Name = Name,
|
||||
Icon = AvatarIconConverter.IconNameToUri(Icon),
|
||||
Badge = ElementNameIconConverter.ElementNameToIconUri(FetterInfo.VisionBefore),
|
||||
Quality = Quality,
|
||||
|
||||
Time = time,
|
||||
LastPull = lastPull,
|
||||
IsUp = isUp,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
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.Metadata.Abstraction;
|
||||
using Snap.Hutao.Model.Metadata.Converter;
|
||||
using Snap.Hutao.Model.Primitive;
|
||||
using Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate;
|
||||
|
||||
namespace Snap.Hutao.Model.Metadata.Avatar;
|
||||
|
||||
/// <summary>
|
||||
/// 可计算角色
|
||||
/// </summary>
|
||||
internal class CalculableAvatar : ObservableObject, ICalculableAvatar
|
||||
{
|
||||
private int levelCurrent;
|
||||
private int levelTarget;
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的可计算角色
|
||||
/// </summary>
|
||||
/// <param name="avatar">角色</param>
|
||||
public CalculableAvatar(Avatar avatar)
|
||||
{
|
||||
AvatarId = avatar.Id;
|
||||
LevelMin = 1;
|
||||
LevelMax = int.Parse(avatar.Property.Parameters.Last().Level);
|
||||
Skills = avatar.SkillDepot.GetCompositeSkillsNoInherents().Select(p => p.ToCalculable()).ToList();
|
||||
Name = avatar.Name;
|
||||
Icon = AvatarIconConverter.IconNameToUri(avatar.Icon);
|
||||
Quality = avatar.Quality;
|
||||
LevelCurrent = LevelMin;
|
||||
LevelTarget = LevelMax;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public AvatarId AvatarId { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int LevelMin { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int LevelMax { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IList<ICalculableSkill> Skills { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string Name { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Uri Icon { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ItemQuality Quality { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int LevelCurrent { get => levelCurrent; set => SetProperty(ref levelCurrent, value); }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int LevelTarget { get => levelTarget; set => SetProperty(ref levelTarget, value); }
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Snap.Hutao.Model.Intrinsic;
|
||||
using Snap.Hutao.Model.Metadata.Converter;
|
||||
using Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate;
|
||||
|
||||
namespace Snap.Hutao.Model.Metadata.Avatar;
|
||||
|
||||
/// <summary>
|
||||
/// 可计算的技能
|
||||
/// </summary>
|
||||
internal class CalculableSkill : ObservableObject, ICalculableSkill
|
||||
{
|
||||
private int levelCurrent;
|
||||
private int levelTarget;
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的可计算的技能
|
||||
/// </summary>
|
||||
/// <param name="skill">技能</param>
|
||||
public CalculableSkill(ProudableSkill skill)
|
||||
{
|
||||
GruopId = skill.GroupId;
|
||||
LevelMin = 1;
|
||||
LevelMax = 10; // hard coded 10 here
|
||||
Name = skill.Name;
|
||||
Icon = SkillIconConverter.IconNameToUri(skill.Icon);
|
||||
Quality = ItemQuality.QUALITY_NONE;
|
||||
LevelCurrent = LevelMin;
|
||||
LevelTarget = LevelMax;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int GruopId { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int LevelMin { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int LevelMax { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string Name { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Uri Icon { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ItemQuality Quality { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int LevelCurrent { get => levelCurrent; set => SetProperty(ref levelCurrent, value); }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int LevelTarget { get => levelTarget; set => SetProperty(ref levelTarget, value); }
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate;
|
||||
|
||||
namespace Snap.Hutao.Model.Metadata.Avatar;
|
||||
|
||||
/// <summary>
|
||||
/// 技能信息的接口实现
|
||||
/// </summary>
|
||||
public partial class ProudableSkill : ICalculableSource<ICalculableSkill>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public ICalculableSkill ToCalculable()
|
||||
{
|
||||
return new CalculableSkill(this);
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ namespace Snap.Hutao.Model.Metadata.Avatar;
|
||||
/// <summary>
|
||||
/// 技能信息
|
||||
/// </summary>
|
||||
public class ProudableSkill : SkillBase
|
||||
public partial class ProudableSkill : SkillBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 组Id
|
||||
@@ -17,4 +17,4 @@ public class ProudableSkill : SkillBase
|
||||
/// 提升属性
|
||||
/// </summary>
|
||||
public DescParam Proud { get; set; } = default!;
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,8 @@ public class SkillDepot
|
||||
public IList<ProudableSkill> Inherents { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 全部天赋,包括固有天赋
|
||||
/// 全部天赋,包括固有天赋
|
||||
/// 在 Wiki 中使用
|
||||
/// </summary>
|
||||
public IList<ProudableSkill> CompositeSkills
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Model.Intrinsic;
|
||||
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
||||
|
||||
namespace Snap.Hutao.Model.Metadata;
|
||||
@@ -49,4 +50,4 @@ public class GachaEvent
|
||||
/// 四星列表
|
||||
/// </summary>
|
||||
public List<string> UpPurpleList { get; set; } = default!;
|
||||
}
|
||||
}
|
||||
48
src/Snap.Hutao/Snap.Hutao/Model/Metadata/Material.cs
Normal file
48
src/Snap.Hutao/Snap.Hutao/Model/Metadata/Material.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Model.Intrinsic;
|
||||
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
||||
|
||||
namespace Snap.Hutao.Model.Metadata;
|
||||
|
||||
/// <summary>
|
||||
/// 材料
|
||||
/// </summary>
|
||||
public class Material
|
||||
{
|
||||
/// <summary>
|
||||
/// 物品Id
|
||||
/// </summary>
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 等级
|
||||
/// </summary>
|
||||
public ItemQuality RankLevel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 物品类型
|
||||
/// </summary>
|
||||
public ItemType ItemType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 图标
|
||||
/// </summary>
|
||||
public string Icon { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 名称
|
||||
/// </summary>
|
||||
public string Name { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 描述
|
||||
/// </summary>
|
||||
public string Description { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 类型描述
|
||||
/// </summary>
|
||||
public string TypeDescription { get; set; } = default!;
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
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.Metadata.Abstraction;
|
||||
using Snap.Hutao.Model.Metadata.Converter;
|
||||
using Snap.Hutao.Model.Primitive;
|
||||
using Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate;
|
||||
|
||||
namespace Snap.Hutao.Model.Metadata.Weapon;
|
||||
|
||||
/// <summary>
|
||||
/// 可计算武器
|
||||
/// </summary>
|
||||
public class CalculableWeapon : ObservableObject, ICalculableWeapon
|
||||
{
|
||||
private int levelCurrent;
|
||||
private int levelTarget;
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的可计算武器
|
||||
/// </summary>
|
||||
/// <param name="weapon">武器</param>
|
||||
public CalculableWeapon(Weapon weapon)
|
||||
{
|
||||
WeaponId = weapon.Id;
|
||||
LevelMin = 1;
|
||||
LevelMax = int.Parse(weapon.Property.Parameters.Last().Level);
|
||||
Name = weapon.Name;
|
||||
Icon = EquipIconConverter.IconNameToUri(weapon.Icon);
|
||||
Quality = weapon.RankLevel;
|
||||
LevelCurrent = LevelMin;
|
||||
LevelTarget = LevelMax;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public WeaponId WeaponId { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int LevelMin { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int LevelMax { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string Name { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Uri Icon { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ItemQuality Quality { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int LevelCurrent { get => levelCurrent; set => SetProperty(ref levelCurrent, value); }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int LevelTarget { get => levelTarget; set => SetProperty(ref levelTarget, value); }
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
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.Metadata.Abstraction;
|
||||
using Snap.Hutao.Model.Metadata.Converter;
|
||||
using Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate;
|
||||
|
||||
namespace Snap.Hutao.Model.Metadata.Weapon;
|
||||
|
||||
/// <summary>
|
||||
/// 武器的接口实现
|
||||
/// </summary>
|
||||
public partial class Weapon : IStatisticsItemSource, ISummaryItemSource, INameQuality, ICalculableSource<ICalculableWeapon>
|
||||
{
|
||||
/// <summary>
|
||||
/// [非元数据] 搭配数据
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public ComplexWeaponCollocation? Collocation { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
[JsonIgnore]
|
||||
public ItemQuality Quality
|
||||
{
|
||||
get => RankLevel;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ICalculableWeapon ToCalculable()
|
||||
{
|
||||
return new CalculableWeapon(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为基础物品
|
||||
/// </summary>
|
||||
/// <returns>基础物品</returns>
|
||||
public ItemBase ToItemBase()
|
||||
{
|
||||
return new()
|
||||
{
|
||||
Name = Name,
|
||||
Icon = EquipIconConverter.IconNameToUri(Icon),
|
||||
Badge = WeaponTypeIconConverter.WeaponTypeToIconUri(WeaponType),
|
||||
Quality = RankLevel,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换到统计物品
|
||||
/// </summary>
|
||||
/// <param name="count">个数</param>
|
||||
/// <returns>统计物品</returns>
|
||||
public StatisticsItem ToStatisticsItem(int count)
|
||||
{
|
||||
return new()
|
||||
{
|
||||
Name = Name,
|
||||
Icon = EquipIconConverter.IconNameToUri(Icon),
|
||||
Badge = WeaponTypeIconConverter.WeaponTypeToIconUri(WeaponType),
|
||||
Quality = RankLevel,
|
||||
Count = count,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换到简述统计物品
|
||||
/// </summary>
|
||||
/// <param name="lastPull">距上个五星</param>
|
||||
/// <param name="time">时间</param>
|
||||
/// <param name="isUp">是否为Up物品</param>
|
||||
/// <returns>简述统计物品</returns>
|
||||
public SummaryItem ToSummaryItem(int lastPull, DateTimeOffset time, bool isUp)
|
||||
{
|
||||
return new()
|
||||
{
|
||||
Name = Name,
|
||||
Icon = EquipIconConverter.IconNameToUri(Icon),
|
||||
Badge = WeaponTypeIconConverter.WeaponTypeToIconUri(WeaponType),
|
||||
Time = time,
|
||||
Quality = RankLevel,
|
||||
LastPull = lastPull,
|
||||
IsUp = isUp,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,7 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
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.Metadata.Abstraction;
|
||||
using Snap.Hutao.Model.Metadata.Converter;
|
||||
using Snap.Hutao.Model.Primitive;
|
||||
|
||||
namespace Snap.Hutao.Model.Metadata.Weapon;
|
||||
@@ -14,7 +9,7 @@ namespace Snap.Hutao.Model.Metadata.Weapon;
|
||||
/// <summary>
|
||||
/// 武器
|
||||
/// </summary>
|
||||
public class Weapon : IStatisticsItemSource, ISummaryItemSource, INameQuality
|
||||
public partial class Weapon
|
||||
{
|
||||
/// <summary>
|
||||
/// Id
|
||||
@@ -60,70 +55,4 @@ public class Weapon : IStatisticsItemSource, ISummaryItemSource, INameQuality
|
||||
/// 被动信息, 无被动的武器为 <see langword="null"/>
|
||||
/// </summary>
|
||||
public AffixInfo? Affix { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// [非元数据] 搭配数据
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public ComplexWeaponCollocation? Collocation { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
[JsonIgnore]
|
||||
public ItemQuality Quality
|
||||
{
|
||||
get => RankLevel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为基础物品
|
||||
/// </summary>
|
||||
/// <returns>基础物品</returns>
|
||||
public ItemBase ToItemBase()
|
||||
{
|
||||
return new()
|
||||
{
|
||||
Name = Name,
|
||||
Icon = EquipIconConverter.IconNameToUri(Icon),
|
||||
Badge = WeaponTypeIconConverter.WeaponTypeToIconUri(WeaponType),
|
||||
Quality = RankLevel,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换到统计物品
|
||||
/// </summary>
|
||||
/// <param name="count">个数</param>
|
||||
/// <returns>统计物品</returns>
|
||||
public StatisticsItem ToStatisticsItem(int count)
|
||||
{
|
||||
return new()
|
||||
{
|
||||
Name = Name,
|
||||
Icon = EquipIconConverter.IconNameToUri(Icon),
|
||||
Badge = WeaponTypeIconConverter.WeaponTypeToIconUri(WeaponType),
|
||||
Quality = RankLevel,
|
||||
Count = count,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换到简述统计物品
|
||||
/// </summary>
|
||||
/// <param name="lastPull">距上个五星</param>
|
||||
/// <param name="time">时间</param>
|
||||
/// <param name="isUp">是否为Up物品</param>
|
||||
/// <returns>简述统计物品</returns>
|
||||
public SummaryItem ToSummaryItem(int lastPull, DateTimeOffset time, bool isUp)
|
||||
{
|
||||
return new()
|
||||
{
|
||||
Name = Name,
|
||||
Icon = EquipIconConverter.IconNameToUri(Icon),
|
||||
Badge = WeaponTypeIconConverter.WeaponTypeToIconUri(WeaponType),
|
||||
Time = time,
|
||||
Quality = RankLevel,
|
||||
LastPull = lastPull,
|
||||
IsUp = isUp,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,24 +1,31 @@
|
||||
// Const value
|
||||
INFINITE
|
||||
WM_GETMINMAXINFO
|
||||
WM_NCRBUTTONDOWN
|
||||
WM_NCRBUTTONUP
|
||||
|
||||
// Type definition
|
||||
CWMO_FLAGS
|
||||
HRESULT
|
||||
MINMAXINFO
|
||||
|
||||
// Comctl32
|
||||
// COMCTL32
|
||||
DefSubclassProc
|
||||
SetWindowSubclass
|
||||
RemoveWindowSubclass
|
||||
|
||||
// Kernel32
|
||||
// KERNEL32
|
||||
CreateEvent
|
||||
CreateToolhelp32Snapshot
|
||||
Module32First
|
||||
Module32Next
|
||||
ReadProcessMemory
|
||||
SetEvent
|
||||
WriteProcessMemory
|
||||
|
||||
// User32
|
||||
// OLE32
|
||||
CoWaitForMultipleObjects
|
||||
|
||||
// USER32
|
||||
FindWindowEx
|
||||
GetDpiForWindow
|
||||
@@ -12,7 +12,7 @@
|
||||
<Identity
|
||||
Name="7f0db578-026f-4e0b-a75b-d5d06bb0a74d"
|
||||
Publisher="CN=DGP Studio"
|
||||
Version="1.2.7.0" />
|
||||
Version="1.2.10.0" />
|
||||
|
||||
<Properties>
|
||||
<DisplayName>胡桃</DisplayName>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Snap.Hutao.Context.Database;
|
||||
using Snap.Hutao.Core.Database;
|
||||
using Snap.Hutao.Core.Diagnostics;
|
||||
@@ -53,7 +54,7 @@ internal class AchievementService : IAchievementService
|
||||
/// <inheritdoc/>
|
||||
public ObservableCollection<EntityArchive> GetArchiveCollection()
|
||||
{
|
||||
return archiveCollection ??= new(appDbContext.AchievementArchives.ToList());
|
||||
return archiveCollection ??= new(appDbContext.AchievementArchives.AsNoTracking().ToList());
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -78,7 +79,7 @@ internal class AchievementService : IAchievementService
|
||||
}
|
||||
|
||||
// 查找是否有相同的名称
|
||||
if (archiveCollection!.SingleOrDefault(a => a.Name == newArchive.Name) is EntityArchive userWithSameUid)
|
||||
if (archiveCollection!.SingleOrDefault(a => a.Name == newArchive.Name) != null)
|
||||
{
|
||||
return ArchiveAddResult.AlreadyExists;
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ public enum ArchiveAddResult
|
||||
InvalidName,
|
||||
|
||||
/// <summary>
|
||||
/// 已经存在该用户
|
||||
/// 已经存在该存档
|
||||
/// </summary>
|
||||
AlreadyExists,
|
||||
}
|
||||
@@ -2,9 +2,17 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Snap.Hutao.Context.Database;
|
||||
using Snap.Hutao.Core.Database;
|
||||
using Snap.Hutao.Model.Binding.Cultivation;
|
||||
using Snap.Hutao.Model.Entity;
|
||||
using Snap.Hutao.Model.Primitive;
|
||||
using System.Collections.ObjectModel;
|
||||
using BindingCultivateEntry = Snap.Hutao.Model.Binding.Cultivation.CultivateEntry;
|
||||
using BindingCultivateItem = Snap.Hutao.Model.Binding.Cultivation.CultivateItem;
|
||||
using BindingInventoryItem = Snap.Hutao.Model.Binding.Inventory.InventoryItem;
|
||||
|
||||
namespace Snap.Hutao.Service.Cultivation;
|
||||
|
||||
@@ -14,24 +22,239 @@ namespace Snap.Hutao.Service.Cultivation;
|
||||
[Injection(InjectAs.Singleton, typeof(ICultivationService))]
|
||||
internal class CultivationService : ICultivationService
|
||||
{
|
||||
private readonly DbCurrent<CultivateProject, Message.CultivateProjectChangedMessage> dbCurrent;
|
||||
private readonly IServiceScopeFactory scopeFactory;
|
||||
private readonly ScopedDbCurrent<CultivateProject, Message.CultivateProjectChangedMessage> dbCurrent;
|
||||
|
||||
private ObservableCollection<CultivateProject>? projects;
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的养成计算服务
|
||||
/// </summary>
|
||||
/// <param name="appDbContext">数据库上下文</param>
|
||||
/// <param name="scopeFactory">范围工厂</param>
|
||||
/// <param name="messenger">消息器</param>
|
||||
public CultivationService(AppDbContext appDbContext, IMessenger messenger)
|
||||
public CultivationService(IServiceScopeFactory scopeFactory, IMessenger messenger)
|
||||
{
|
||||
dbCurrent = new(appDbContext.CultivateProjects, messenger);
|
||||
this.scopeFactory = scopeFactory;
|
||||
dbCurrent = new(scopeFactory, provider => provider.GetRequiredService<AppDbContext>().CultivateProjects, messenger);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前养成计划
|
||||
/// </summary>
|
||||
/// <inheritdoc/>
|
||||
public CultivateProject? Current
|
||||
{
|
||||
get => dbCurrent.Current;
|
||||
set => dbCurrent.Current = value;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ObservableCollection<CultivateProject> GetProjectCollection()
|
||||
{
|
||||
if (projects == null)
|
||||
{
|
||||
using (IServiceScope scope = scopeFactory.CreateScope())
|
||||
{
|
||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
projects = new(appDbContext.CultivateProjects.AsNoTracking().ToList());
|
||||
}
|
||||
|
||||
Current ??= projects.SingleOrDefault(proj => proj.IsSelected);
|
||||
}
|
||||
|
||||
return projects;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<ProjectAddResult> TryAddProjectAsync(CultivateProject project)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(project.Name))
|
||||
{
|
||||
return ProjectAddResult.InvalidName;
|
||||
}
|
||||
|
||||
if (projects!.SingleOrDefault(a => a.Name == project.Name) != null)
|
||||
{
|
||||
return ProjectAddResult.AlreadyExists;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Sync cache
|
||||
await ThreadHelper.SwitchToMainThreadAsync();
|
||||
projects!.Add(project);
|
||||
|
||||
// Sync database
|
||||
await ThreadHelper.SwitchToBackgroundAsync();
|
||||
using (IServiceScope scope = scopeFactory.CreateScope())
|
||||
{
|
||||
await scope.ServiceProvider.GetRequiredService<AppDbContext>().CultivateProjects.AddAndSaveAsync(project).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
return ProjectAddResult.Added;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task RemoveProjectAsync(CultivateProject project)
|
||||
{
|
||||
// Sync cache
|
||||
// Keep this on main thread.
|
||||
await ThreadHelper.SwitchToMainThreadAsync();
|
||||
projects!.Remove(project);
|
||||
|
||||
// Sync database
|
||||
await ThreadHelper.SwitchToBackgroundAsync();
|
||||
using (IServiceScope scope = scopeFactory.CreateScope())
|
||||
{
|
||||
await scope.ServiceProvider.GetRequiredService<AppDbContext>().CultivateProjects.RemoveAndSaveAsync(project).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public List<BindingInventoryItem> GetInventoryItems(CultivateProject cultivateProject, List<Model.Metadata.Material> metadata)
|
||||
{
|
||||
Guid projectId = cultivateProject.InnerId;
|
||||
using (IServiceScope scope = scopeFactory.CreateScope())
|
||||
{
|
||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
List<InventoryItem> entities = appDbContext.InventoryItems
|
||||
.Where(a => a.ProjectId == projectId)
|
||||
.ToList();
|
||||
|
||||
List<BindingInventoryItem> results = new();
|
||||
foreach (Model.Metadata.Material meta in metadata.Where(IsInventoryItem).OrderBy(m => m.Id))
|
||||
{
|
||||
InventoryItem entity = entities.SingleOrDefault(e => e.ItemId == meta.Id) ?? InventoryItem.Create(projectId, meta.Id);
|
||||
results.Add(new(meta, entity));
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<ObservableCollection<BindingCultivateEntry>> GetCultivateEntriesAsync(
|
||||
CultivateProject cultivateProject,
|
||||
List<Model.Metadata.Material> metadata,
|
||||
Dictionary<AvatarId, Model.Metadata.Avatar.Avatar> idAvatarMap,
|
||||
Dictionary<WeaponId, Model.Metadata.Weapon.Weapon> idWeaponMap)
|
||||
{
|
||||
// TODO: cache the collection
|
||||
await ThreadHelper.SwitchToBackgroundAsync();
|
||||
Guid projectId = cultivateProject.InnerId;
|
||||
using (IServiceScope scope = scopeFactory.CreateScope())
|
||||
{
|
||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
List<BindingCultivateEntry> bindingEntries = new();
|
||||
foreach (Model.Entity.CultivateEntry? entry in await appDbContext.CultivateEntries.ToListAsync().ConfigureAwait(false))
|
||||
{
|
||||
Guid entryId = entry.InnerId;
|
||||
|
||||
List<BindingCultivateItem> items = new();
|
||||
foreach (Model.Entity.CultivateItem? item in await appDbContext.CultivateItems.Where(i => i.EntryId == entryId).OrderBy(i => i.ItemId).ToListAsync().ConfigureAwait(false))
|
||||
{
|
||||
items.Add(new(metadata.Single(m => m.Id == item.ItemId), item));
|
||||
}
|
||||
|
||||
Model.Binding.Gacha.Abstraction.ItemBase itemBase = entry.Type switch
|
||||
{
|
||||
CultivateType.AvatarAndSkill => idAvatarMap[entry.Id].ToItemBase(),
|
||||
CultivateType.Weapon => idWeaponMap[entry.Id].ToItemBase(),
|
||||
_ => null!, // TODO: support furniture calc
|
||||
};
|
||||
|
||||
bindingEntries.Add(new()
|
||||
{
|
||||
Id = entry.Id,
|
||||
EntryId = entryId,
|
||||
Name = itemBase.Name,
|
||||
Icon = itemBase.Icon,
|
||||
Badge = itemBase.Badge,
|
||||
Quality = itemBase.Quality,
|
||||
Items = items,
|
||||
});
|
||||
}
|
||||
|
||||
return new(bindingEntries);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task RemoveCultivateEntryAsync(Guid entryId)
|
||||
{
|
||||
await ThreadHelper.SwitchToBackgroundAsync();
|
||||
using (IServiceScope scope = scopeFactory.CreateScope())
|
||||
{
|
||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
await appDbContext.CultivateEntries.Where(i => i.InnerId == entryId).ExecuteDeleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void SaveInventoryItem(BindingInventoryItem item)
|
||||
{
|
||||
using (IServiceScope scope = scopeFactory.CreateScope())
|
||||
{
|
||||
scope.ServiceProvider.GetRequiredService<AppDbContext>().InventoryItems.UpdateAndSave(item.Entity);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<bool> SaveConsumptionAsync(CultivateType type, int itemId, List<Web.Hoyolab.Takumi.Event.Calculate.Item> items)
|
||||
{
|
||||
using (IServiceScope scope = scopeFactory.CreateScope())
|
||||
{
|
||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
|
||||
Current ??= appDbContext.CultivateProjects.AsNoTracking().SingleOrDefault(proj => proj.IsSelected);
|
||||
if (Current == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Guid projectId = Current!.InnerId;
|
||||
Model.Entity.CultivateEntry? entry = await appDbContext.CultivateEntries
|
||||
.SingleOrDefaultAsync(e => e.ProjectId == projectId && e.Id == itemId)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (entry == null)
|
||||
{
|
||||
entry = Model.Entity.CultivateEntry.Create(projectId, type, itemId);
|
||||
await appDbContext.CultivateEntries.AddAndSaveAsync(entry).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
Guid entryId = entry.InnerId;
|
||||
await appDbContext.CultivateItems.Where(i => i.EntryId == entryId).ExecuteDeleteAsync().ConfigureAwait(false);
|
||||
IEnumerable<Model.Entity.CultivateItem> toAdd = items.Select(i => Model.Entity.CultivateItem.Create(entryId, i.Id, i.Num));
|
||||
await appDbContext.CultivateItems.AddRangeAndSaveAsync(toAdd).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool IsInventoryItem(Model.Metadata.Material material)
|
||||
{
|
||||
// 原质
|
||||
if (material.Id == 112001)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// 摩拉
|
||||
if (material.Id == 202)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (material.TypeDescription.EndsWith("区域特产"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return material.TypeDescription switch
|
||||
{
|
||||
"角色经验素材" => true,
|
||||
"角色培养素材" => true,
|
||||
"天赋培养素材" => true,
|
||||
"武器强化素材" => true,
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,13 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Model.Binding.Cultivation;
|
||||
using Snap.Hutao.Model.Entity;
|
||||
using Snap.Hutao.Model.Metadata;
|
||||
using Snap.Hutao.Model.Primitive;
|
||||
using Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace Snap.Hutao.Service.Cultivation;
|
||||
|
||||
/// <summary>
|
||||
@@ -8,4 +15,68 @@ namespace Snap.Hutao.Service.Cultivation;
|
||||
/// </summary>
|
||||
internal interface ICultivationService
|
||||
{
|
||||
/// <summary>
|
||||
/// 当前养成计划
|
||||
/// </summary>
|
||||
CultivateProject? Current { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取绑定用的养成列表
|
||||
/// </summary>
|
||||
/// <param name="cultivateProject">养成计划</param>
|
||||
/// <param name="metadata">材料</param>
|
||||
/// <param name="idAvatarMap">Id角色映射</param>
|
||||
/// <param name="idWeaponMap">Id武器映射</param>
|
||||
/// <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);
|
||||
|
||||
/// <summary>
|
||||
/// 获取物品列表
|
||||
/// </summary>
|
||||
/// <param name="cultivateProject">养成计划</param>
|
||||
/// <param name="metadata">元数据</param>
|
||||
/// <returns>物品列表</returns>
|
||||
List<Model.Binding.Inventory.InventoryItem> GetInventoryItems(CultivateProject cultivateProject, List<Material> metadata);
|
||||
|
||||
/// <summary>
|
||||
/// 获取用于绑定的项目集合
|
||||
/// </summary>
|
||||
/// <returns>项目集合</returns>
|
||||
ObservableCollection<CultivateProject> GetProjectCollection();
|
||||
|
||||
/// <summary>
|
||||
/// 删除养成清单
|
||||
/// </summary>
|
||||
/// <param name="entryId">入口Id</param>
|
||||
/// <returns>任务</returns>
|
||||
Task RemoveCultivateEntryAsync(Guid entryId);
|
||||
|
||||
/// <summary>
|
||||
/// 异步移除项目
|
||||
/// </summary>
|
||||
/// <param name="project">项目</param>
|
||||
/// <returns>任务</returns>
|
||||
Task RemoveProjectAsync(CultivateProject project);
|
||||
|
||||
/// <summary>
|
||||
/// 异步保存养成物品
|
||||
/// </summary>
|
||||
/// <param name="type">类型</param>
|
||||
/// <param name="itemId">主Id</param>
|
||||
/// <param name="items">待存物品</param>
|
||||
/// <returns>是否保存成功</returns>
|
||||
Task<bool> SaveConsumptionAsync(CultivateType type, int itemId, List<Item> items);
|
||||
|
||||
/// <summary>
|
||||
/// 保存单个物品
|
||||
/// </summary>
|
||||
/// <param name="item">物品</param>
|
||||
void SaveInventoryItem(Model.Binding.Inventory.InventoryItem item);
|
||||
|
||||
/// <summary>
|
||||
/// 异步尝试添加新的项目
|
||||
/// </summary>
|
||||
/// <param name="project">项目</param>
|
||||
/// <returns>添加操作的结果</returns>
|
||||
Task<ProjectAddResult> TryAddProjectAsync(CultivateProject project);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Service.Cultivation;
|
||||
|
||||
/// <summary>
|
||||
/// 项目添加结果
|
||||
/// </summary>
|
||||
public enum ProjectAddResult
|
||||
{
|
||||
/// <summary>
|
||||
/// 添加成功
|
||||
/// </summary>
|
||||
Added,
|
||||
|
||||
/// <summary>
|
||||
/// 名称无效
|
||||
/// </summary>
|
||||
InvalidName,
|
||||
|
||||
/// <summary>
|
||||
/// 已经存在该存档
|
||||
/// </summary>
|
||||
AlreadyExists,
|
||||
}
|
||||
@@ -140,4 +140,11 @@ internal interface IMetadataService
|
||||
/// <param name="token">取消令牌</param>
|
||||
/// <returns>圣遗物套装列表</returns>
|
||||
ValueTask<List<ReliquarySet>> GetReliquarySetsAsync(CancellationToken token = default);
|
||||
|
||||
/// <summary>
|
||||
/// 异步获取材料列表
|
||||
/// </summary>
|
||||
/// <param name="token">取消令牌</param>
|
||||
/// <returns>材料列表</returns>
|
||||
ValueTask<List<Material>> GetMaterialsAsync(CancellationToken token = default(CancellationToken));
|
||||
}
|
||||
@@ -38,6 +38,12 @@ internal partial class MetadataService
|
||||
return FromCacheOrFileAsync<List<GachaEvent>>("GachaEvent", token);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ValueTask<List<Material>> GetMaterialsAsync(CancellationToken token = default)
|
||||
{
|
||||
return FromCacheOrFileAsync<List<Material>>("Material", token);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ValueTask<List<Reliquary>> GetReliquariesAsync(CancellationToken token = default)
|
||||
{
|
||||
|
||||
@@ -69,6 +69,8 @@
|
||||
<None Remove="View\Dialog\AchievementImportDialog.xaml" />
|
||||
<None Remove="View\Dialog\AdoptCalculatorDialog.xaml" />
|
||||
<None Remove="View\Dialog\AvatarInfoQueryDialog.xaml" />
|
||||
<None Remove="View\Dialog\CultivateProjectDialog.xaml" />
|
||||
<None Remove="View\Dialog\CultivatePromotionDeltaDialog.xaml" />
|
||||
<None Remove="View\Dialog\DailyNoteNotificationDialog.xaml" />
|
||||
<None Remove="View\Dialog\DailyNoteVerificationDialog.xaml" />
|
||||
<None Remove="View\Dialog\GachaLogImportDialog.xaml" />
|
||||
@@ -134,12 +136,12 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.1.0-preview1" />
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.1.0-preview2" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.Notifications" 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="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.0">
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.1">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
@@ -151,12 +153,12 @@
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.VisualStudio.Validation" Version="17.0.64" />
|
||||
<PackageReference Include="Microsoft.Windows.CsWin32" Version="0.2.138-beta">
|
||||
<PackageReference Include="Microsoft.Windows.CsWin32" Version="0.2.164-beta">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.25247-preview" />
|
||||
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.2.221116.1" />
|
||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.25267-preview" />
|
||||
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.2.221209.1" />
|
||||
<PackageReference Include="StyleCop.Analyzers.Unstable" Version="1.2.0.435">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
@@ -179,6 +181,16 @@
|
||||
<ItemGroup>
|
||||
<None Include="..\.editorconfig" Link=".editorconfig" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="View\Dialog\CultivatePromotionDeltaDialog.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="View\Dialog\CultivateProjectDialog.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="View\Page\CultivationPage.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
|
||||
@@ -16,6 +16,9 @@ public sealed partial class DescParamComboBox : UserControl
|
||||
private static readonly DependencyProperty SourceProperty = Property<DescParamComboBox>
|
||||
.Depend<IList<LevelParam<string, ParameterInfo>>>(nameof(Source), default!, OnSourceChanged);
|
||||
|
||||
private static readonly DependencyProperty PreferredSelectedIndexProperty = Property<DescParamComboBox>
|
||||
.Depend<int>(nameof(PreferredSelectedIndex), 0);
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的描述参数组合框
|
||||
/// </summary>
|
||||
@@ -33,6 +36,15 @@ public sealed partial class DescParamComboBox : UserControl
|
||||
set => SetValue(SourceProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 期望的选中索引
|
||||
/// </summary>
|
||||
public int PreferredSelectedIndex
|
||||
{
|
||||
get { return (int)GetValue(PreferredSelectedIndexProperty); }
|
||||
set { SetValue(PreferredSelectedIndexProperty, value); }
|
||||
}
|
||||
|
||||
private static void OnSourceChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
// Some of the {x:Bind} feature is not working properly,
|
||||
@@ -42,7 +54,7 @@ public sealed partial class DescParamComboBox : UserControl
|
||||
if (args.NewValue != args.OldValue && args.NewValue is IList<LevelParam<string, ParameterInfo>> list)
|
||||
{
|
||||
descParamComboBox.ItemHost.ItemsSource = list;
|
||||
descParamComboBox.ItemHost.SelectedIndex = 0;
|
||||
descParamComboBox.ItemHost.SelectedIndex = Math.Min(descParamComboBox.PreferredSelectedIndex, list.Count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using CommunityToolkit.WinUI.UI.Converters;
|
||||
using Microsoft.UI.Xaml;
|
||||
|
||||
namespace Snap.Hutao.View.Converter;
|
||||
|
||||
/// <summary>
|
||||
/// This class converts a object? value into a Visibility enumeration.
|
||||
/// </summary>
|
||||
public class EmptyObjectToVisibilityConverter : EmptyObjectToObjectConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="EmptyObjectToVisibilityConverter"/> class.
|
||||
/// </summary>
|
||||
public EmptyObjectToVisibilityConverter()
|
||||
{
|
||||
EmptyValue = Visibility.Collapsed;
|
||||
NotEmptyValue = Visibility.Visible;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<ContentDialog
|
||||
x:Class="Snap.Hutao.View.Dialog.CultivateProjectDialog"
|
||||
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"
|
||||
Title="创建新的养成计划"
|
||||
CloseButtonText="取消"
|
||||
DefaultButton="Primary"
|
||||
PrimaryButtonText="确认"
|
||||
Style="{StaticResource DefaultContentDialogStyle}"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<StackPanel>
|
||||
<TextBox
|
||||
x:Name="InputText"
|
||||
VerticalAlignment="Top"
|
||||
PlaceholderText="在此处输入计划名称"/>
|
||||
<CheckBox
|
||||
x:Name="AttachUidBox"
|
||||
Margin="0,8,0,0"
|
||||
Content="绑定当前选中的账号角色"/>
|
||||
</StackPanel>
|
||||
</ContentDialog>
|
||||
@@ -0,0 +1,59 @@
|
||||
// Copyright (c) Microsoft Corporation and Contributors.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using Microsoft.UI.Xaml;
|
||||
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.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;
|
||||
|
||||
/// <summary>
|
||||
/// <20><><EFBFBD>ɼƻ<C9BC><C6BB>Ի<EFBFBD><D4BB><EFBFBD>
|
||||
/// </summary>
|
||||
public sealed partial class CultivateProjectDialog : ContentDialog
|
||||
{
|
||||
/// <summary>
|
||||
/// <20><><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD>µ<EFBFBD><C2B5><EFBFBD><EFBFBD>ɼƻ<C9BC><C6BB>Ի<EFBFBD><D4BB><EFBFBD>
|
||||
/// </summary>
|
||||
/// <param name="window"><3E><><EFBFBD><EFBFBD></param>
|
||||
public CultivateProjectDialog(Window window)
|
||||
{
|
||||
InitializeComponent();
|
||||
XamlRoot = window.Content.XamlRoot;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <20><><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD>µģ<C2B5><C4A3>û<EFBFBD>ָ<EFBFBD><D6B8><EFBFBD>ļƻ<C4BC>
|
||||
/// </summary>
|
||||
/// <returns><3E>ƻ<EFBFBD></returns>
|
||||
public async ValueTask<ValueResult<bool, CultivateProject>> CreateProjectAsync()
|
||||
{
|
||||
await ThreadHelper.SwitchToMainThreadAsync();
|
||||
ContentDialogResult result = await ShowAsync();
|
||||
if (result == ContentDialogResult.Primary)
|
||||
{
|
||||
string text = InputText.Text;
|
||||
string? uid = AttachUidBox.IsChecked == true
|
||||
? Ioc.Default.GetRequiredService<IUserService>().Current?.SelectedUserGameRole?.GameUid
|
||||
: null;
|
||||
|
||||
CultivateProject project = CultivateProject.Create(text, uid);
|
||||
return new(true, project);
|
||||
}
|
||||
|
||||
return new(false, null!);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
<ContentDialog
|
||||
x:Class="Snap.Hutao.View.Dialog.CultivatePromotionDeltaDialog"
|
||||
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"
|
||||
xmlns:shci="using:Snap.Hutao.Control.Image"
|
||||
xmlns:shvc="using:Snap.Hutao.View.Control"
|
||||
xmlns:shvd="using:Snap.Hutao.View.Dialog"
|
||||
Title="添加到当前养成计划"
|
||||
d:DataContext="{d:DesignInstance shvd:CultivatePromotionDeltaDialog}"
|
||||
CloseButtonText="取消"
|
||||
DefaultButton="Primary"
|
||||
PrimaryButtonText="确认"
|
||||
Style="{StaticResource DefaultContentDialogStyle}"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition Height="auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<StackPanel
|
||||
Grid.Row="0"
|
||||
Margin="0,8,0,0"
|
||||
Visibility="{Binding Avatar, Converter={StaticResource EmptyObjectToVisibilityConverter}}">
|
||||
<Border Style="{StaticResource BorderCardStyle}">
|
||||
<Grid Margin="8" DataContext="{Binding Avatar}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
<ColumnDefinition Width="160"/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<shvc:ItemIcon
|
||||
Grid.Column="0"
|
||||
Width="36"
|
||||
Height="36"
|
||||
Icon="{Binding Icon}"
|
||||
Quality="{Binding Quality}"/>
|
||||
<TextBlock
|
||||
Grid.Column="1"
|
||||
Margin="16,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding Name}"
|
||||
TextTrimming="CharacterEllipsis"/>
|
||||
<NumberBox
|
||||
Grid.Column="2"
|
||||
MinWidth="100"
|
||||
VerticalAlignment="Center"
|
||||
Maximum="{Binding LevelMax}"
|
||||
Minimum="{Binding LevelMin}"
|
||||
SpinButtonPlacementMode="Compact"
|
||||
Value="{Binding LevelCurrent, Mode=TwoWay}"/>
|
||||
<FontIcon
|
||||
Grid.Column="3"
|
||||
Margin="8"
|
||||
FontSize="12"
|
||||
Glyph=""/>
|
||||
<NumberBox
|
||||
Grid.Column="4"
|
||||
MinWidth="100"
|
||||
VerticalAlignment="Center"
|
||||
Maximum="{Binding LevelMax}"
|
||||
Minimum="{Binding LevelMin}"
|
||||
SpinButtonPlacementMode="Compact"
|
||||
Value="{Binding LevelTarget, Mode=TwoWay}"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<ItemsControl ItemsSource="{Binding Avatar.Skills}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border Margin="0,2,0,0" Style="{StaticResource BorderCardStyle}">
|
||||
<Grid Margin="8">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
<ColumnDefinition Width="160"/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<shci:MonoChrome
|
||||
Grid.Column="0"
|
||||
Width="36"
|
||||
Height="36"
|
||||
Source="{Binding Icon}"/>
|
||||
<TextBlock
|
||||
Grid.Column="1"
|
||||
Margin="16,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding Name}"
|
||||
TextTrimming="CharacterEllipsis"/>
|
||||
<NumberBox
|
||||
Grid.Column="2"
|
||||
MinWidth="100"
|
||||
VerticalAlignment="Center"
|
||||
Maximum="{Binding LevelMax}"
|
||||
Minimum="{Binding LevelMin}"
|
||||
SpinButtonPlacementMode="Compact"
|
||||
Value="{Binding LevelCurrent, Mode=TwoWay}"/>
|
||||
<FontIcon
|
||||
Grid.Column="3"
|
||||
Margin="8"
|
||||
FontSize="12"
|
||||
Glyph=""/>
|
||||
<NumberBox
|
||||
Grid.Column="4"
|
||||
MinWidth="100"
|
||||
VerticalAlignment="Center"
|
||||
Maximum="{Binding LevelMax}"
|
||||
Minimum="{Binding LevelMin}"
|
||||
SpinButtonPlacementMode="Compact"
|
||||
Value="{Binding LevelTarget, Mode=TwoWay}"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</StackPanel>
|
||||
<StackPanel
|
||||
Grid.Row="1"
|
||||
Margin="0,8,0,0"
|
||||
Visibility="{Binding Weapon, Converter={StaticResource EmptyObjectToVisibilityConverter}}">
|
||||
<Border Style="{StaticResource BorderCardStyle}">
|
||||
<Grid Margin="8" DataContext="{Binding Weapon}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
<ColumnDefinition Width="160"/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<shvc:ItemIcon
|
||||
Grid.Column="0"
|
||||
Width="36"
|
||||
Height="36"
|
||||
Icon="{Binding Icon}"
|
||||
Quality="{Binding Quality}"/>
|
||||
<TextBlock
|
||||
Grid.Column="1"
|
||||
Margin="16,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding Name}"
|
||||
TextTrimming="CharacterEllipsis"/>
|
||||
<NumberBox
|
||||
Grid.Column="2"
|
||||
MinWidth="100"
|
||||
VerticalAlignment="Center"
|
||||
Maximum="{Binding LevelMax}"
|
||||
Minimum="{Binding LevelMin}"
|
||||
SpinButtonPlacementMode="Compact"
|
||||
Value="{Binding LevelCurrent, Mode=TwoWay}"/>
|
||||
<FontIcon
|
||||
Grid.Column="3"
|
||||
Margin="8"
|
||||
FontSize="12"
|
||||
Glyph=""/>
|
||||
<NumberBox
|
||||
Grid.Column="4"
|
||||
MinWidth="100"
|
||||
VerticalAlignment="Center"
|
||||
Maximum="{Binding LevelMax}"
|
||||
Minimum="{Binding LevelMin}"
|
||||
SpinButtonPlacementMode="Compact"
|
||||
Value="{Binding LevelTarget, Mode=TwoWay}"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</ContentDialog>
|
||||
@@ -0,0 +1,88 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Snap.Hutao.Control;
|
||||
using Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate;
|
||||
|
||||
namespace Snap.Hutao.View.Dialog;
|
||||
|
||||
/// <summary>
|
||||
/// <20><><EFBFBD>ɼ<EFBFBD><C9BC><EFBFBD><EFBFBD>Ի<EFBFBD><D4BB><EFBFBD>
|
||||
/// </summary>
|
||||
public sealed partial class CultivatePromotionDeltaDialog : ContentDialog
|
||||
{
|
||||
private static readonly DependencyProperty AvatarProperty = Property<CultivatePromotionDeltaDialog>.Depend<ICalculableAvatar?>(nameof(Avatar));
|
||||
private static readonly DependencyProperty WeaponProperty = Property<CultivatePromotionDeltaDialog>.Depend<ICalculableAvatar?>(nameof(Weapon));
|
||||
|
||||
/// <summary>
|
||||
/// <20><><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD>µ<EFBFBD><C2B5><EFBFBD><EFBFBD>ɼ<EFBFBD><C9BC><EFBFBD><EFBFBD>Ի<EFBFBD><D4BB><EFBFBD>
|
||||
/// </summary>
|
||||
/// <param name="window"><3E><><EFBFBD><EFBFBD></param>
|
||||
/// <param name="avatar"><3E><>ɫ</param>
|
||||
/// <param name="weapon"><3E><><EFBFBD><EFBFBD></param>
|
||||
public CultivatePromotionDeltaDialog(Window window, ICalculableAvatar? avatar, ICalculableWeapon? weapon)
|
||||
{
|
||||
InitializeComponent();
|
||||
XamlRoot = window.Content.XamlRoot;
|
||||
DataContext = this;
|
||||
Avatar = avatar;
|
||||
Weapon = weapon;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <20><>ɫ
|
||||
/// </summary>
|
||||
public ICalculableAvatar? Avatar
|
||||
{
|
||||
get { return (ICalculableAvatar?)GetValue(AvatarProperty); }
|
||||
set { SetValue(AvatarProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <20><><EFBFBD><EFBFBD>
|
||||
/// </summary>
|
||||
public ICalculableWeapon? Weapon
|
||||
{
|
||||
get { return (ICalculableWeapon?)GetValue(WeaponProperty); }
|
||||
set { SetValue(WeaponProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <20>첽<EFBFBD><ECB2BD>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
/// </summary>
|
||||
/// <returns><3E><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD></returns>
|
||||
public async Task<ValueResult<bool, AvatarPromotionDelta>> GetPromotionDeltaAsync()
|
||||
{
|
||||
ContentDialogResult result = await ShowAsync();
|
||||
|
||||
if (result == ContentDialogResult.Primary)
|
||||
{
|
||||
AvatarPromotionDelta delta = new()
|
||||
{
|
||||
AvatarId = Avatar?.AvatarId ?? 0,
|
||||
AvatarLevelCurrent = Avatar?.LevelCurrent ?? 0,
|
||||
AvatarLevelTarget = Avatar?.LevelTarget ?? 0,
|
||||
SkillList = Avatar?.Skills.Select(s => new PromotionDelta()
|
||||
{
|
||||
Id = s.GruopId,
|
||||
LevelCurrent = s.LevelCurrent,
|
||||
LevelTarget = s.LevelTarget,
|
||||
}),
|
||||
Weapon = Weapon == null ? null : new PromotionDelta()
|
||||
{
|
||||
Id = Weapon.WeaponId,
|
||||
LevelCurrent = Weapon.LevelCurrent,
|
||||
LevelTarget = Weapon.LevelTarget,
|
||||
},
|
||||
};
|
||||
|
||||
return new(true, delta);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new(false, null!);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,6 @@
|
||||
x:Name="InputText"
|
||||
Margin="0,0,0,0"
|
||||
VerticalAlignment="Top"
|
||||
PlaceholderText="在此处输入"/>
|
||||
PlaceholderText="在此处输入名称"/>
|
||||
</Grid>
|
||||
</ContentDialog>
|
||||
|
||||
@@ -24,10 +24,7 @@
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid
|
||||
Background="{StaticResource CardBackgroundFillColorDefaultBrush}"
|
||||
BorderBrush="{StaticResource CardStrokeColorDefaultBrush}"
|
||||
BorderThickness="0,0,0,1">
|
||||
<Grid Background="{StaticResource CardBackgroundFillColorDefaultBrush}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="252"/>
|
||||
<ColumnDefinition/>
|
||||
@@ -61,7 +58,11 @@
|
||||
Margin="2,6,3,6"
|
||||
DisplayMemberPath="Name"
|
||||
ItemsSource="{Binding Archives, Mode=OneWay}"
|
||||
SelectedItem="{Binding SelectedArchive, Mode=TwoWay}"/>
|
||||
SelectedItem="{Binding SelectedArchive, Mode=TwoWay}">
|
||||
<mxi:Interaction.Behaviors>
|
||||
<shcb:ComboBoxExtendsContentIntoTitleBarWorkaroundBehavior/>
|
||||
</mxi:Interaction.Behaviors>
|
||||
</ComboBox>
|
||||
</AppBarElementContainer>
|
||||
<AppBarButton
|
||||
Command="{Binding AddArchiveCommand}"
|
||||
|
||||
@@ -1,12 +1,229 @@
|
||||
<shc:ScopedPage
|
||||
<shc:ScopedPage
|
||||
x:Class="Snap.Hutao.View.Page.CultivationPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:cwuc="using:CommunityToolkit.WinUI.UI.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:mxi="using:Microsoft.Xaml.Interactivity"
|
||||
xmlns:mxic="using:Microsoft.Xaml.Interactions.Core"
|
||||
xmlns:mxim="using:Microsoft.Xaml.Interactions.Media"
|
||||
xmlns:shc="using:Snap.Hutao.Control"
|
||||
xmlns:shcb="using:Snap.Hutao.Control.Behavior"
|
||||
xmlns:shcm="using:Snap.Hutao.Control.Markup"
|
||||
xmlns:shv="using:Snap.Hutao.ViewModel"
|
||||
xmlns:shvc="using:Snap.Hutao.View.Control"
|
||||
d:DataContext="{d:DesignInstance shv:CultivationViewModel}"
|
||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid/>
|
||||
<Page.Resources>
|
||||
<shc:BindingProxy x:Key="BindingProxy" DataContext="{Binding}"/>
|
||||
</Page.Resources>
|
||||
|
||||
<mxi:Interaction.Behaviors>
|
||||
<shcb:InvokeCommandOnLoadedBehavior Command="{Binding OpenUICommand}"/>
|
||||
</mxi:Interaction.Behaviors>
|
||||
<Grid>
|
||||
<Rectangle
|
||||
Height="48"
|
||||
VerticalAlignment="Top"
|
||||
Fill="{StaticResource CardBackgroundFillColorDefaultBrush}"
|
||||
IsHitTestVisible="False"/>
|
||||
<Pivot>
|
||||
<Pivot.RightHeader>
|
||||
<CommandBar DefaultLabelPosition="Right">
|
||||
<AppBarElementContainer>
|
||||
<ComboBox
|
||||
Height="36"
|
||||
MinWidth="160"
|
||||
Margin="6,6,6,6"
|
||||
DisplayMemberPath="Name"
|
||||
ItemsSource="{Binding Projects}"
|
||||
SelectedItem="{Binding SelectedProject, Mode=TwoWay}">
|
||||
<mxi:Interaction.Behaviors>
|
||||
<shcb:ComboBoxExtendsContentIntoTitleBarWorkaroundBehavior/>
|
||||
</mxi:Interaction.Behaviors>
|
||||
</ComboBox>
|
||||
</AppBarElementContainer>
|
||||
<AppBarButton
|
||||
Command="{Binding AddProjectCommand}"
|
||||
Icon="{shcm:FontIcon Glyph=}"
|
||||
Label="新建计划"/>
|
||||
<AppBarButton
|
||||
Command="{Binding RemoveProjectCommand}"
|
||||
CommandParameter="{Binding SelectedProject, Mode=OneWay}"
|
||||
Icon="{shcm:FontIcon Glyph=}"
|
||||
Label="删除当前计划"/>
|
||||
</CommandBar>
|
||||
</Pivot.RightHeader>
|
||||
|
||||
<PivotItem Header="材料清单">
|
||||
<cwuc:AdaptiveGridView
|
||||
Padding="16,16,4,4"
|
||||
DesiredWidth="360"
|
||||
ItemContainerStyle="{StaticResource LargeGridViewItemStyle}"
|
||||
ItemsSource="{Binding CultivateEntries}"
|
||||
SelectionMode="None">
|
||||
<cwuc:AdaptiveGridView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border Style="{StaticResource BorderCardStyle}">
|
||||
<Grid Background="Transparent">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid Margin="8">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<shvc:ItemIcon
|
||||
Grid.Column="0"
|
||||
Width="48"
|
||||
Height="48"
|
||||
Icon="{Binding Icon}"
|
||||
Quality="{Binding Quality}"/>
|
||||
<TextBlock
|
||||
Grid.Column="1"
|
||||
Margin="8,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding Name}"/>
|
||||
<StackPanel
|
||||
x:Name="ButtonPanel"
|
||||
Grid.Column="2"
|
||||
Orientation="Horizontal"
|
||||
Visibility="Collapsed">
|
||||
<Button
|
||||
Width="48"
|
||||
Height="48"
|
||||
Margin="8,0,0,0"
|
||||
Content=""
|
||||
FontFamily="{StaticResource SymbolThemeFontFamily}"
|
||||
ToolTipService.ToolTip="编辑清单"/>
|
||||
<Button
|
||||
Width="48"
|
||||
Height="48"
|
||||
Margin="8,0,0,0"
|
||||
Command="{Binding Path=DataContext.RemoveEntryCommand, Source={StaticResource BindingProxy}}"
|
||||
CommandParameter="{Binding}"
|
||||
Content=""
|
||||
FontFamily="{StaticResource SymbolThemeFontFamily}"
|
||||
ToolTipService.ToolTip="删除清单"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
<ItemsControl
|
||||
Grid.Row="1"
|
||||
Margin="8,0,8,8"
|
||||
ItemsSource="{Binding Items}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid Margin="0,4,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<shvc:ItemIcon
|
||||
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"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding Entity.Count}"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
|
||||
<Grid.Resources>
|
||||
<Storyboard x:Name="ButtonPanelVisibleStoryboard">
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ButtonPanel" Storyboard.TargetProperty="Visibility">
|
||||
<DiscreteObjectKeyFrame KeyTime="0">
|
||||
<DiscreteObjectKeyFrame.Value>
|
||||
<Visibility>Visible</Visibility>
|
||||
</DiscreteObjectKeyFrame.Value>
|
||||
</DiscreteObjectKeyFrame>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
|
||||
<Storyboard x:Name="ButtonPanelCollapsedStoryboard">
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ButtonPanel" Storyboard.TargetProperty="Visibility">
|
||||
<DiscreteObjectKeyFrame KeyTime="0">
|
||||
<DiscreteObjectKeyFrame.Value>
|
||||
<Visibility>Collapsed</Visibility>
|
||||
</DiscreteObjectKeyFrame.Value>
|
||||
</DiscreteObjectKeyFrame>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</Grid.Resources>
|
||||
|
||||
<mxi:Interaction.Behaviors>
|
||||
<mxic:EventTriggerBehavior EventName="PointerEntered">
|
||||
<mxim:ControlStoryboardAction Storyboard="{StaticResource ButtonPanelVisibleStoryboard}"/>
|
||||
</mxic:EventTriggerBehavior>
|
||||
<mxic:EventTriggerBehavior EventName="PointerExited">
|
||||
<mxim:ControlStoryboardAction Storyboard="{StaticResource ButtonPanelCollapsedStoryboard}"/>
|
||||
</mxic:EventTriggerBehavior>
|
||||
</mxi:Interaction.Behaviors>
|
||||
</Grid>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</cwuc:AdaptiveGridView.ItemTemplate>
|
||||
</cwuc:AdaptiveGridView>
|
||||
</PivotItem>
|
||||
<PivotItem Header="背包物品">
|
||||
<cwuc:AdaptiveGridView
|
||||
Padding="16,16,4,4"
|
||||
ItemContainerStyle="{StaticResource LargeGridViewItemStyle}"
|
||||
ItemsSource="{Binding InventoryItems}"
|
||||
SelectionMode="None">
|
||||
<cwuc:AdaptiveGridView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Button
|
||||
Padding="0"
|
||||
Background="Transparent"
|
||||
BorderBrush="{x:Null}"
|
||||
BorderThickness="0"
|
||||
CornerRadius="{StaticResource CompatCornerRadius}">
|
||||
<shvc:BottomTextControl Text="{Binding Count, Mode=OneWay}">
|
||||
<shvc:ItemIcon Icon="{Binding Inner.Icon, Converter={StaticResource ItemIconConverter}}" Quality="{Binding Inner.RankLevel}"/>
|
||||
</shvc:BottomTextControl>
|
||||
<Button.Flyout>
|
||||
<Flyout>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock Style="{StaticResource BaseTextBlockStyle}" Text="{Binding Inner.Name}"/>
|
||||
<NumberBox
|
||||
Grid.Row="1"
|
||||
MinWidth="160"
|
||||
Margin="0,16,0,0"
|
||||
Maximum="4294967295"
|
||||
Minimum="0"
|
||||
Value="{Binding Count, Mode=TwoWay}"/>
|
||||
</Grid>
|
||||
</Flyout>
|
||||
</Button.Flyout>
|
||||
</Button>
|
||||
</DataTemplate>
|
||||
</cwuc:AdaptiveGridView.ItemTemplate>
|
||||
</cwuc:AdaptiveGridView>
|
||||
</PivotItem>
|
||||
</Pivot>
|
||||
</Grid>
|
||||
</shc:ScopedPage>
|
||||
|
||||
@@ -23,8 +23,9 @@
|
||||
<Rectangle
|
||||
Height="48"
|
||||
VerticalAlignment="Top"
|
||||
Fill="{StaticResource CardBackgroundFillColorDefaultBrush}"/>
|
||||
<Pivot Grid.RowSpan="2">
|
||||
Fill="{StaticResource CardBackgroundFillColorDefaultBrush}"
|
||||
IsHitTestVisible="False"/>
|
||||
<Pivot>
|
||||
<Pivot.LeftHeader>
|
||||
<ComboBox
|
||||
Height="36"
|
||||
@@ -32,7 +33,11 @@
|
||||
Margin="16,6,0,6"
|
||||
DisplayMemberPath="Uid"
|
||||
ItemsSource="{Binding Archives}"
|
||||
SelectedItem="{Binding SelectedArchive, Mode=TwoWay}"/>
|
||||
SelectedItem="{Binding SelectedArchive, Mode=TwoWay}">
|
||||
<mxi:Interaction.Behaviors>
|
||||
<shcb:ComboBoxExtendsContentIntoTitleBarWorkaroundBehavior/>
|
||||
</mxi:Interaction.Behaviors>
|
||||
</ComboBox>
|
||||
</Pivot.LeftHeader>
|
||||
<Pivot.RightHeader>
|
||||
<CommandBar DefaultLabelPosition="Right">
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
<shvc:DescParamComboBox
|
||||
Grid.Column="0"
|
||||
HorizontalAlignment="Stretch"
|
||||
PreferredSelectedIndex="9"
|
||||
Source="{Binding Proud, Mode=OneWay, Converter={StaticResource DescParamDescriptor}}"/>
|
||||
</StackPanel>
|
||||
|
||||
@@ -40,7 +41,10 @@
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate x:Key="PropertyDataTemplate">
|
||||
<shvc:DescParamComboBox HorizontalAlignment="Stretch" Source="{Binding Converter={StaticResource PropertyDescriptor}}"/>
|
||||
<shvc:DescParamComboBox
|
||||
HorizontalAlignment="Stretch"
|
||||
PreferredSelectedIndex="13"
|
||||
Source="{Binding Converter={StaticResource PropertyDescriptor}}"/>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate x:Key="TalentDataTemplate">
|
||||
@@ -68,7 +72,11 @@
|
||||
<CommandBar.Content>
|
||||
<shcp:PanelSelector x:Name="ItemsPanelSelector" Margin="6,8,0,0"/>
|
||||
</CommandBar.Content>
|
||||
<AppBarButton Icon="{shcm:FontIcon Glyph=}" Label="养成计算"/>
|
||||
<AppBarButton
|
||||
Command="{Binding CultivateCommand}"
|
||||
CommandParameter="{Binding Selected}"
|
||||
Icon="{shcm:FontIcon Glyph=}"
|
||||
Label="养成计算"/>
|
||||
</CommandBar>
|
||||
<SplitView
|
||||
Grid.Row="1"
|
||||
|
||||
@@ -23,7 +23,10 @@
|
||||
|
||||
<Page.Resources>
|
||||
<DataTemplate x:Key="PropertyDataTemplate">
|
||||
<shvc:DescParamComboBox HorizontalAlignment="Stretch" Source="{Binding Converter={StaticResource PropertyDescriptor}}"/>
|
||||
<shvc:DescParamComboBox
|
||||
HorizontalAlignment="Stretch"
|
||||
PreferredSelectedIndex="13"
|
||||
Source="{Binding Converter={StaticResource PropertyDescriptor}}"/>
|
||||
</DataTemplate>
|
||||
</Page.Resources>
|
||||
|
||||
|
||||
@@ -25,7 +25,11 @@ public sealed partial class TitleView : UserControl
|
||||
[SuppressMessage("", "CA1822")]
|
||||
public string Title
|
||||
{
|
||||
#if DEBUG
|
||||
get => $"胡桃 Dev Build";
|
||||
#else
|
||||
get => $"胡桃 {Core.CoreEnvironment.Version}";
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -2,7 +2,17 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using Snap.Hutao.Control;
|
||||
using Snap.Hutao.Factory.Abstraction;
|
||||
using Snap.Hutao.Message;
|
||||
using Snap.Hutao.Model.Entity;
|
||||
using Snap.Hutao.Service.Abstraction;
|
||||
using Snap.Hutao.Service.Cultivation;
|
||||
using Snap.Hutao.Service.Metadata;
|
||||
using Snap.Hutao.View.Dialog;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace Snap.Hutao.ViewModel;
|
||||
|
||||
@@ -10,8 +20,193 @@ namespace Snap.Hutao.ViewModel;
|
||||
/// 养成视图模型
|
||||
/// </summary>
|
||||
[Injection(InjectAs.Scoped)]
|
||||
internal class CultivationViewModel : ObservableObject, ISupportCancellation
|
||||
internal class CultivationViewModel : ObservableObject, ISupportCancellation, IRecipient<CultivateProjectChangedMessage>
|
||||
{
|
||||
private readonly ICultivationService cultivationService;
|
||||
private readonly IInfoBarService infoBarService;
|
||||
private readonly IMetadataService metadataService;
|
||||
private readonly ILogger<CultivationViewModel> logger;
|
||||
|
||||
private ObservableCollection<CultivateProject>? projects;
|
||||
private CultivateProject? selectedProject;
|
||||
private List<Model.Binding.Inventory.InventoryItem>? inventoryItems;
|
||||
private ObservableCollection<Model.Binding.Cultivation.CultivateEntry>? cultivateEntries;
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的养成视图模型
|
||||
/// </summary>
|
||||
/// <param name="cultivationService">养成服务</param>
|
||||
/// <param name="infoBarService">信息服务</param>
|
||||
/// <param name="asyncRelayCommandFactory">异步命令工厂</param>
|
||||
/// <param name="metadataService">元数据服务</param>
|
||||
/// <param name="logger">日志器</param>
|
||||
/// <param name="messenger">消息器</param>
|
||||
public CultivationViewModel(
|
||||
ICultivationService cultivationService,
|
||||
IInfoBarService infoBarService,
|
||||
IAsyncRelayCommandFactory asyncRelayCommandFactory,
|
||||
IMetadataService metadataService,
|
||||
ILogger<CultivationViewModel> logger,
|
||||
IMessenger messenger)
|
||||
{
|
||||
this.cultivationService = cultivationService;
|
||||
this.infoBarService = infoBarService;
|
||||
this.metadataService = metadataService;
|
||||
this.logger = logger;
|
||||
|
||||
OpenUICommand = asyncRelayCommandFactory.Create(OpenUIAsync);
|
||||
AddProjectCommand = asyncRelayCommandFactory.Create(AddProjectAsync);
|
||||
RemoveProjectCommand = asyncRelayCommandFactory.Create<CultivateProject>(RemoveProjectAsync);
|
||||
RemoveEntryCommand = asyncRelayCommandFactory.Create<Model.Binding.Cultivation.CultivateEntry>(RemoveEntryAsync);
|
||||
SaveInventoryItemCommand = new RelayCommand<Model.Binding.Inventory.InventoryItem>(SaveInventoryItem);
|
||||
|
||||
messenger.Register(this);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public CancellationToken CancellationToken { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 项目
|
||||
/// </summary>
|
||||
public ObservableCollection<CultivateProject>? Projects { get => projects; set => SetProperty(ref projects, value); }
|
||||
|
||||
/// <summary>
|
||||
/// 当前选中的计划
|
||||
/// </summary>
|
||||
public CultivateProject? SelectedProject
|
||||
{
|
||||
get => selectedProject; set
|
||||
{
|
||||
if (SetProperty(ref selectedProject, value))
|
||||
{
|
||||
cultivationService.Current = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 物品列表
|
||||
/// </summary>
|
||||
public List<Model.Binding.Inventory.InventoryItem>? InventoryItems { get => inventoryItems; set => SetProperty(ref inventoryItems, value); }
|
||||
|
||||
/// <summary>
|
||||
/// 养成列表
|
||||
/// </summary>
|
||||
public ObservableCollection<Model.Binding.Cultivation.CultivateEntry>? CultivateEntries { get => cultivateEntries; set => SetProperty(ref cultivateEntries, value); }
|
||||
|
||||
/// <summary>
|
||||
/// 打开界面命令
|
||||
/// </summary>
|
||||
public ICommand OpenUICommand { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 添加项目命令
|
||||
/// </summary>
|
||||
public ICommand AddProjectCommand { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 删除项目命令
|
||||
/// </summary>
|
||||
public ICommand RemoveProjectCommand { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 移除
|
||||
/// </summary>
|
||||
public ICommand RemoveEntryCommand { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 保存物品命令
|
||||
/// </summary>
|
||||
public ICommand SaveInventoryItemCommand { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Receive(CultivateProjectChangedMessage message)
|
||||
{
|
||||
UpdateCultivateEntriesAndInventoryItemsAsync(message.NewValue).SafeForget(logger);
|
||||
}
|
||||
|
||||
private async Task OpenUIAsync()
|
||||
{
|
||||
if (await metadataService.InitializeAsync().ConfigureAwait(true))
|
||||
{
|
||||
Projects = cultivationService.GetProjectCollection();
|
||||
SelectedProject = cultivationService.Current;
|
||||
await UpdateCultivateEntriesAndInventoryItemsAsync(SelectedProject).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task AddProjectAsync()
|
||||
{
|
||||
MainWindow mainWindow = Ioc.Default.GetRequiredService<MainWindow>();
|
||||
(bool isOk, CultivateProject project) = await new CultivateProjectDialog(mainWindow).CreateProjectAsync().ConfigureAwait(false);
|
||||
|
||||
if (isOk)
|
||||
{
|
||||
ProjectAddResult result = await cultivationService.TryAddProjectAsync(project).ConfigureAwait(false);
|
||||
|
||||
switch (result)
|
||||
{
|
||||
case ProjectAddResult.Added:
|
||||
infoBarService.Success($"添加成功");
|
||||
break;
|
||||
case ProjectAddResult.InvalidName:
|
||||
infoBarService.Information($"不能添加名称无效的计划");
|
||||
break;
|
||||
case ProjectAddResult.AlreadyExists:
|
||||
infoBarService.Information($"不能添加名称重复的计划");
|
||||
break;
|
||||
default:
|
||||
throw Must.NeverHappen();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task RemoveProjectAsync(CultivateProject? project)
|
||||
{
|
||||
if (project != null)
|
||||
{
|
||||
await cultivationService.RemoveProjectAsync(project).ConfigureAwait(false);
|
||||
|
||||
await ThreadHelper.SwitchToMainThreadAsync();
|
||||
SelectedProject = Projects!.FirstOrDefault();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task UpdateCultivateEntriesAndInventoryItemsAsync(CultivateProject? project)
|
||||
{
|
||||
if (project != null)
|
||||
{
|
||||
List<Model.Metadata.Material> materials = await metadataService.GetMaterialsAsync().ConfigureAwait(false);
|
||||
Dictionary<Model.Primitive.AvatarId, Model.Metadata.Avatar.Avatar> idAvatarMap = await metadataService.GetIdToAvatarMapAsync().ConfigureAwait(false);
|
||||
Dictionary<Model.Primitive.WeaponId, Model.Metadata.Weapon.Weapon> idWeaponMap = await metadataService.GetIdToWeaponMapAsync().ConfigureAwait(false);
|
||||
|
||||
ObservableCollection<Model.Binding.Cultivation.CultivateEntry> entries = await cultivationService
|
||||
.GetCultivateEntriesAsync(project, materials, idAvatarMap, idWeaponMap)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
await ThreadHelper.SwitchToMainThreadAsync();
|
||||
CultivateEntries = entries;
|
||||
InventoryItems = cultivationService.GetInventoryItems(project, materials);
|
||||
}
|
||||
}
|
||||
|
||||
private Task RemoveEntryAsync(Model.Binding.Cultivation.CultivateEntry? entry)
|
||||
{
|
||||
if (entry != null)
|
||||
{
|
||||
CultivateEntries!.Remove(entry);
|
||||
return cultivationService.RemoveCultivateEntryAsync(entry.EntryId);
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private void SaveInventoryItem(Model.Binding.Inventory.InventoryItem? inventoryItem)
|
||||
{
|
||||
if (inventoryItem != null)
|
||||
{
|
||||
cultivationService.SaveInventoryItem(inventoryItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Snap.Hutao.Context.Database;
|
||||
using Snap.Hutao.Control;
|
||||
using Snap.Hutao.Core.Database;
|
||||
@@ -27,11 +28,17 @@ namespace Snap.Hutao.ViewModel;
|
||||
[Injection(InjectAs.Scoped)]
|
||||
internal class LaunchGameViewModel : ObservableObject, ISupportCancellation
|
||||
{
|
||||
/// <summary>
|
||||
/// 启动游戏目标 Uid
|
||||
/// </summary>
|
||||
public const string DesiredUid = nameof(DesiredUid);
|
||||
|
||||
private static readonly string TrueString = true.ToString();
|
||||
private static readonly string FalseString = false.ToString();
|
||||
|
||||
private readonly IGameService gameService;
|
||||
private readonly AppDbContext appDbContext;
|
||||
private readonly IMemoryCache memoryCache;
|
||||
|
||||
private readonly List<LaunchScheme> knownSchemes = new()
|
||||
{
|
||||
@@ -55,12 +62,18 @@ internal class LaunchGameViewModel : ObservableObject, ISupportCancellation
|
||||
/// 构造一个新的启动游戏视图模型
|
||||
/// </summary>
|
||||
/// <param name="gameService">游戏服务</param>
|
||||
/// <param name="memoryCache">内存缓存</param>
|
||||
/// <param name="appDbContext">数据库上下文</param>
|
||||
/// <param name="asyncRelayCommandFactory">异步命令工厂</param>
|
||||
public LaunchGameViewModel(IGameService gameService, AppDbContext appDbContext, IAsyncRelayCommandFactory asyncRelayCommandFactory)
|
||||
public LaunchGameViewModel(
|
||||
IGameService gameService,
|
||||
IMemoryCache memoryCache,
|
||||
AppDbContext appDbContext,
|
||||
IAsyncRelayCommandFactory asyncRelayCommandFactory)
|
||||
{
|
||||
this.gameService = gameService;
|
||||
this.appDbContext = appDbContext;
|
||||
this.memoryCache = memoryCache;
|
||||
|
||||
OpenUICommand = asyncRelayCommandFactory.Create(OpenUIAsync);
|
||||
LaunchCommand = asyncRelayCommandFactory.Create(LaunchAsync);
|
||||
@@ -169,13 +182,21 @@ internal class LaunchGameViewModel : ObservableObject, ISupportCancellation
|
||||
SelectedScheme = KnownSchemes.FirstOrDefault(s => s.Channel == multi.Channel && s.SubChannel == multi.SubChannel);
|
||||
GameAccounts = gameService.GetGameAccountCollection();
|
||||
|
||||
// Sync uid
|
||||
if (memoryCache.TryGetValue(DesiredUid, out object? value) && value is string uid)
|
||||
{
|
||||
SelectedGameAccount = GameAccounts.SingleOrDefault(g => g.AttachUid == uid);
|
||||
}
|
||||
|
||||
// Sync from Settings
|
||||
RetiveSetting();
|
||||
}
|
||||
else
|
||||
{
|
||||
Ioc.Default.GetRequiredService<IInfoBarService>().Warning("游戏路径不正确,前往设置更改游戏路径。");
|
||||
await Ioc.Default.GetRequiredService<INavigationService>().NavigateAsync<View.Page.SettingPage>(INavigationAwaiter.Default, true).ConfigureAwait(false);
|
||||
await Ioc.Default.GetRequiredService<INavigationService>()
|
||||
.NavigateAsync<View.Page.SettingPage>(INavigationAwaiter.Default, true)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,12 +5,22 @@ using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.WinUI.UI;
|
||||
using Snap.Hutao.Factory.Abstraction;
|
||||
using Snap.Hutao.Model;
|
||||
using Snap.Hutao.Model.Binding.Cultivation;
|
||||
using Snap.Hutao.Model.Binding.Hutao;
|
||||
using Snap.Hutao.Model.Intrinsic;
|
||||
using Snap.Hutao.Model.Metadata.Avatar;
|
||||
using Snap.Hutao.Model.Primitive;
|
||||
using Snap.Hutao.Service.Abstraction;
|
||||
using Snap.Hutao.Service.Cultivation;
|
||||
using Snap.Hutao.Service.Hutao;
|
||||
using Snap.Hutao.Service.Metadata;
|
||||
using Snap.Hutao.Service.User;
|
||||
using Snap.Hutao.View.Dialog;
|
||||
using CalcAvatarPromotionDelta = Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate.AvatarPromotionDelta;
|
||||
using CalcClient = Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate.CalculateClient;
|
||||
using CalcConsumption = Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate.Consumption;
|
||||
using CalcItem = Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate.Item;
|
||||
using CalcItemHelper = Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate.ItemHelper;
|
||||
|
||||
namespace Snap.Hutao.ViewModel;
|
||||
|
||||
@@ -44,6 +54,7 @@ internal class WikiAvatarViewModel : ObservableObject
|
||||
this.metadataService = metadataService;
|
||||
this.hutaoCache = hutaoCache;
|
||||
OpenUICommand = asyncRelayCommandFactory.Create(OpenUIAsync);
|
||||
CultivateCommand = asyncRelayCommandFactory.Create<Avatar>(CultivateAsync);
|
||||
|
||||
filterElementInfos = new()
|
||||
{
|
||||
@@ -147,6 +158,11 @@ internal class WikiAvatarViewModel : ObservableObject
|
||||
/// </summary>
|
||||
public ICommand OpenUICommand { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 养成命令
|
||||
/// </summary>
|
||||
public ICommand CultivateCommand { get; }
|
||||
|
||||
private async Task OpenUIAsync()
|
||||
{
|
||||
if (await metadataService.InitializeAsync().ConfigureAwait(false))
|
||||
@@ -160,8 +176,6 @@ internal class WikiAvatarViewModel : ObservableObject
|
||||
await CombineWithAvatarCollocationsAsync(sorted).ConfigureAwait(false);
|
||||
|
||||
await ThreadHelper.SwitchToMainThreadAsync();
|
||||
|
||||
// RPC_E_WRONG_THREAD ?
|
||||
Avatars = new AdvancedCollectionView(sorted, true);
|
||||
Selected = Avatars.Cast<Avatar>().FirstOrDefault();
|
||||
}
|
||||
@@ -222,4 +236,47 @@ internal class WikiAvatarViewModel : ObservableObject
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task CultivateAsync(Avatar? avatar)
|
||||
{
|
||||
IInfoBarService infoBarService = Ioc.Default.GetRequiredService<IInfoBarService>();
|
||||
if (avatar != null)
|
||||
{
|
||||
IUserService userService = Ioc.Default.GetRequiredService<IUserService>();
|
||||
if (userService.Current != null)
|
||||
{
|
||||
MainWindow mainWindow = Ioc.Default.GetRequiredService<MainWindow>();
|
||||
(bool isOk, CalcAvatarPromotionDelta delta) = await new CultivatePromotionDeltaDialog(mainWindow, avatar.ToCalculable(), null)
|
||||
.GetPromotionDeltaAsync()
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (isOk)
|
||||
{
|
||||
CalcClient calculateClient = Ioc.Default.GetRequiredService<CalcClient>();
|
||||
CalcConsumption? consumption = await calculateClient.ComputeAsync(userService.Current.Entity, delta).ConfigureAwait(false);
|
||||
if (consumption != null)
|
||||
{
|
||||
List<CalcItem> items = CalcItemHelper.Merge(consumption.AvatarConsume, consumption.AvatarSkillConsume);
|
||||
bool saved = await Ioc.Default
|
||||
.GetRequiredService<ICultivationService>()
|
||||
.SaveConsumptionAsync(CultivateType.AvatarAndSkill, avatar.Id, items)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (saved)
|
||||
{
|
||||
infoBarService.Success("已成功添加至当前养成计划");
|
||||
}
|
||||
else
|
||||
{
|
||||
infoBarService.Warning("请先前往养成计划页面创建计划并选中");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
infoBarService.Warning("必须先选择一个用户与角色");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -51,7 +51,9 @@ public partial class Cookie
|
||||
string name = parts[0].Trim();
|
||||
string value = parts.Length == 1 ? string.Empty : parts[1].Trim();
|
||||
|
||||
cookieMap.Add(name, value);
|
||||
// System.ArgumentException: An item with the same key has already been added.
|
||||
// cookieMap.Add(name, value);
|
||||
cookieMap[name] = value;
|
||||
}
|
||||
|
||||
return new(cookieMap);
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Extension;
|
||||
using Snap.Hutao.Web.Request;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab;
|
||||
|
||||
/// <summary>
|
||||
/// Hoyolab HttpClient 拓展
|
||||
/// </summary>
|
||||
internal static class HoyolabHttpClientExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 设置用户的 Cookie
|
||||
/// </summary>
|
||||
/// <param name="httpClient">http客户端</param>
|
||||
/// <param name="user">实体用户</param>
|
||||
/// <param name="cookie">Cookie类型</param>
|
||||
/// <returns>客户端</returns>
|
||||
internal static HttpClient SetUser(this HttpClient httpClient, Model.Entity.User user, CookieType cookie)
|
||||
{
|
||||
httpClient.DefaultRequestHeaders.Remove("Cookie");
|
||||
StringBuilder stringBuilder = new();
|
||||
|
||||
if ((cookie & CookieType.CookieToken) == CookieType.CookieToken)
|
||||
{
|
||||
stringBuilder.Append(user.CookieToken).AppendIf(user.CookieToken != null, ';');
|
||||
}
|
||||
|
||||
if ((cookie & CookieType.Ltoken) == CookieType.Ltoken)
|
||||
{
|
||||
stringBuilder.Append(user.Ltoken).AppendIf(user.Ltoken != null, ';');
|
||||
}
|
||||
|
||||
if ((cookie & CookieType.Stoken) == CookieType.Stoken)
|
||||
{
|
||||
stringBuilder.Append(user.Stoken).AppendIf(user.Stoken != null, ';');
|
||||
}
|
||||
|
||||
if ((cookie & CookieType.Mid) == CookieType.Mid)
|
||||
{
|
||||
stringBuilder.Append("mid=").Append(user.Mid).Append(';');
|
||||
}
|
||||
|
||||
httpClient.DefaultRequestHeaders.Set("Cookie", stringBuilder.ToString());
|
||||
return httpClient;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置Referer
|
||||
/// </summary>
|
||||
/// <param name="httpClient">http客户端</param>
|
||||
/// <param name="referer">用户</param>
|
||||
/// <returns>客户端</returns>
|
||||
internal static HttpClient SetReferer(this HttpClient httpClient, string referer)
|
||||
{
|
||||
httpClient.DefaultRequestHeaders.Set("Referer", referer);
|
||||
return httpClient;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置验证流水号
|
||||
/// </summary>
|
||||
/// <param name="httpClient">http客户端</param>
|
||||
/// <param name="challenge">验证流水号</param>
|
||||
/// <returns>客户端</returns>
|
||||
internal static HttpClient SetXrpcChallenge(this HttpClient httpClient, string challenge)
|
||||
{
|
||||
httpClient.DefaultRequestHeaders.Set("x-rpc-challenge", challenge);
|
||||
return httpClient;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置头
|
||||
/// </summary>
|
||||
/// <param name="httpClient">http客户端</param>
|
||||
/// <param name="key">键</param>
|
||||
/// <param name="value">值</param>
|
||||
/// <returns>客户端</returns>
|
||||
internal static HttpClient SetHeader(this HttpClient httpClient, string key, string value)
|
||||
{
|
||||
httpClient.DefaultRequestHeaders.Set(key, value);
|
||||
return httpClient;
|
||||
}
|
||||
}
|
||||
@@ -39,7 +39,7 @@ internal class CalculateClient
|
||||
/// <param name="delta">差异</param>
|
||||
/// <param name="token">取消令牌</param>
|
||||
/// <returns>消耗结果</returns>
|
||||
public async Task<Consumption?> ComputeAsync(User user, AvatarPromotionDelta delta, CancellationToken token)
|
||||
public async Task<Consumption?> ComputeAsync(User user, AvatarPromotionDelta delta, CancellationToken token = default)
|
||||
{
|
||||
Response<Consumption>? resp = await httpClient
|
||||
.SetUser(user, CookieType.CookieToken)
|
||||
|
||||
@@ -8,6 +8,11 @@ namespace Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate;
|
||||
/// </summary>
|
||||
public enum ElementAttributeId
|
||||
{
|
||||
/// <summary>
|
||||
/// 无
|
||||
/// </summary>
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// 火元素
|
||||
/// </summary>
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Model.Intrinsic;
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate;
|
||||
|
||||
/// <summary>
|
||||
/// 可计算源
|
||||
/// </summary>
|
||||
public interface ICalculable
|
||||
{
|
||||
/// <summary>
|
||||
/// 名称
|
||||
/// </summary>
|
||||
string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 图标
|
||||
/// </summary>
|
||||
Uri Icon { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 星级
|
||||
/// </summary>
|
||||
ItemQuality Quality { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 当前等级
|
||||
/// </summary>
|
||||
int LevelCurrent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 目标等级
|
||||
/// </summary>
|
||||
int LevelTarget { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Model.Primitive;
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate;
|
||||
|
||||
/// <summary>
|
||||
/// 可计算的角色
|
||||
/// </summary>
|
||||
public interface ICalculableAvatar : ICalculable
|
||||
{
|
||||
/// <summary>
|
||||
/// 角色Id
|
||||
/// </summary>
|
||||
AvatarId AvatarId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 最小等级
|
||||
/// </summary>
|
||||
int LevelMin { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 最大等级
|
||||
/// </summary>
|
||||
int LevelMax { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 技能组
|
||||
/// </summary>
|
||||
IList<ICalculableSkill> Skills { get; }
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate;
|
||||
|
||||
/// <summary>
|
||||
/// 可计算的技能
|
||||
/// </summary>
|
||||
public interface ICalculableSkill : ICalculable
|
||||
{
|
||||
/// <summary>
|
||||
/// 技能组Id
|
||||
/// </summary>
|
||||
int GruopId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 最小等级
|
||||
/// </summary>
|
||||
int LevelMin { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 最大等级
|
||||
/// </summary>
|
||||
int LevelMax { get; }
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate;
|
||||
|
||||
/// <summary>
|
||||
/// 可计算物品的源
|
||||
/// </summary>
|
||||
/// <typeparam name="T">可计算类型</typeparam>
|
||||
public interface ICalculableSource<T>
|
||||
where T : ICalculable
|
||||
{
|
||||
/// <summary>
|
||||
/// 转换到可计算的对象
|
||||
/// </summary>
|
||||
/// <returns>可计算物品</returns>
|
||||
public T ToCalculable();
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Model.Primitive;
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate;
|
||||
|
||||
/// <summary>
|
||||
/// 可计算的武器
|
||||
/// </summary>
|
||||
public interface ICalculableWeapon : ICalculable
|
||||
{
|
||||
/// <summary>
|
||||
/// 武器Id
|
||||
/// </summary>
|
||||
WeaponId WeaponId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 最小等级
|
||||
/// </summary>
|
||||
int LevelMin { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 最大等级
|
||||
/// </summary>
|
||||
int LevelMax { get; }
|
||||
}
|
||||
@@ -37,6 +37,6 @@ public class Item
|
||||
/// <summary>
|
||||
/// 物品星级 仅有家具为有效值
|
||||
/// </summary>
|
||||
[JsonPropertyName("num")]
|
||||
[JsonPropertyName("level")]
|
||||
public ItemQuality Level { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate;
|
||||
|
||||
/// <summary>
|
||||
/// 物品帮助类
|
||||
/// </summary>
|
||||
public static class ItemHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 合并两个物品列表
|
||||
/// </summary>
|
||||
/// <param name="left">左列表</param>
|
||||
/// <param name="right">右列表</param>
|
||||
/// <returns>合并且排序好的列表</returns>
|
||||
public static List<Item> Merge(List<Item>? left, List<Item>? right)
|
||||
{
|
||||
if (left == null && right == null)
|
||||
{
|
||||
return new(0);
|
||||
}
|
||||
|
||||
if (right == null)
|
||||
{
|
||||
return left!;
|
||||
}
|
||||
|
||||
if (left == null)
|
||||
{
|
||||
return right!;
|
||||
}
|
||||
|
||||
List<Item> result = new(left.Count + right.Count);
|
||||
result.AddRange(left);
|
||||
|
||||
foreach (Item item in right)
|
||||
{
|
||||
if (result.SingleOrDefault(i => i.Id == item.Id) is Item existed)
|
||||
{
|
||||
existed.Num += item.Num;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -3,13 +3,15 @@
|
||||
|
||||
using Snap.Hutao.Core.Logging;
|
||||
using Snap.Hutao.Extension;
|
||||
using Snap.Hutao.Web.Hoyolab;
|
||||
using Snap.Hutao.Web.Request;
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Json;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab;
|
||||
namespace Snap.Hutao.Web;
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="HttpClient"/> 扩展
|
||||
@@ -34,6 +36,16 @@ internal static class HttpClientExtensions
|
||||
logger.LogWarning(EventIds.HttpException, ex, "请求异常已忽略");
|
||||
return null;
|
||||
}
|
||||
catch (JsonException ex)
|
||||
{
|
||||
logger.LogWarning(EventIds.HttpException, ex, "请求异常已忽略");
|
||||
return null;
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
logger.LogWarning(EventIds.HttpException, ex, "请求异常已忽略");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="HttpClientJsonExtensions.PostAsJsonAsync{TValue}(HttpClient, string?, TValue, JsonSerializerOptions?, CancellationToken)"/>
|
||||
@@ -55,6 +67,16 @@ internal static class HttpClientExtensions
|
||||
logger.LogWarning(EventIds.HttpException, ex, "请求异常已忽略");
|
||||
return null;
|
||||
}
|
||||
catch (JsonException ex)
|
||||
{
|
||||
logger.LogWarning(EventIds.HttpException, ex, "请求异常已忽略");
|
||||
return null;
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
logger.LogWarning(EventIds.HttpException, ex, "请求异常已忽略");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="HttpClientJsonExtensions.PostAsJsonAsync{TValue}(HttpClient, string?, TValue, JsonSerializerOptions?, CancellationToken)"/>
|
||||
@@ -74,78 +96,13 @@ internal static class HttpClientExtensions
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置用户的 Cookie
|
||||
/// </summary>
|
||||
/// <param name="httpClient">http客户端</param>
|
||||
/// <param name="user">实体用户</param>
|
||||
/// <param name="cookie">Cookie类型</param>
|
||||
/// <returns>客户端</returns>
|
||||
internal static HttpClient SetUser(this HttpClient httpClient, Model.Entity.User user, CookieType cookie)
|
||||
{
|
||||
httpClient.DefaultRequestHeaders.Remove("Cookie");
|
||||
StringBuilder stringBuilder = new();
|
||||
|
||||
if ((cookie & CookieType.CookieToken) == CookieType.CookieToken)
|
||||
catch (JsonException)
|
||||
{
|
||||
stringBuilder.Append(user.CookieToken).AppendIf(user.CookieToken != null, ';');
|
||||
return null;
|
||||
}
|
||||
|
||||
if ((cookie & CookieType.Ltoken) == CookieType.Ltoken)
|
||||
catch (IOException)
|
||||
{
|
||||
stringBuilder.Append(user.Ltoken).AppendIf(user.Ltoken != null, ';');
|
||||
return null;
|
||||
}
|
||||
|
||||
if ((cookie & CookieType.Stoken) == CookieType.Stoken)
|
||||
{
|
||||
stringBuilder.Append(user.Stoken).AppendIf(user.Stoken != null, ';');
|
||||
}
|
||||
|
||||
if ((cookie & CookieType.Mid) == CookieType.Mid)
|
||||
{
|
||||
stringBuilder.Append("mid=").Append(user.Mid).Append(';');
|
||||
}
|
||||
|
||||
httpClient.DefaultRequestHeaders.Set("Cookie", stringBuilder.ToString());
|
||||
return httpClient;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置Referer
|
||||
/// </summary>
|
||||
/// <param name="httpClient">http客户端</param>
|
||||
/// <param name="referer">用户</param>
|
||||
/// <returns>客户端</returns>
|
||||
internal static HttpClient SetReferer(this HttpClient httpClient, string referer)
|
||||
{
|
||||
httpClient.DefaultRequestHeaders.Set("Referer", referer);
|
||||
return httpClient;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置验证流水号
|
||||
/// </summary>
|
||||
/// <param name="httpClient">http客户端</param>
|
||||
/// <param name="challenge">验证流水号</param>
|
||||
/// <returns>客户端</returns>
|
||||
internal static HttpClient SetXrpcChallenge(this HttpClient httpClient, string challenge)
|
||||
{
|
||||
httpClient.DefaultRequestHeaders.Set("x-rpc-challenge", challenge);
|
||||
return httpClient;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置头
|
||||
/// </summary>
|
||||
/// <param name="httpClient">http客户端</param>
|
||||
/// <param name="key">键</param>
|
||||
/// <param name="value">值</param>
|
||||
/// <returns>客户端</returns>
|
||||
internal static HttpClient SetHeader(this HttpClient httpClient, string key, string value)
|
||||
{
|
||||
httpClient.DefaultRequestHeaders.Set(key, value);
|
||||
return httpClient;
|
||||
}
|
||||
}
|
||||
@@ -101,7 +101,7 @@ internal class HomaClient
|
||||
public async Task<List<AvatarAppearanceRank>> GetAvatarAttendanceRatesAsync(CancellationToken token = default)
|
||||
{
|
||||
Response<List<AvatarAppearanceRank>>? resp = await httpClient
|
||||
.GetFromJsonAsync<Response<List<AvatarAppearanceRank>>>($"{HutaoAPI}/Statistics/Avatar/AttendanceRate", token)
|
||||
.TryCatchGetFromJsonAsync<Response<List<AvatarAppearanceRank>>>($"{HutaoAPI}/Statistics/Avatar/AttendanceRate", options, logger, token)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return EnumerableExtension.EmptyIfNull(resp?.Data);
|
||||
@@ -116,7 +116,7 @@ internal class HomaClient
|
||||
public async Task<List<AvatarUsageRank>> GetAvatarUtilizationRatesAsync(CancellationToken token = default)
|
||||
{
|
||||
Response<List<AvatarUsageRank>>? resp = await httpClient
|
||||
.GetFromJsonAsync<Response<List<AvatarUsageRank>>>($"{HutaoAPI}/Statistics/Avatar/UtilizationRate", token)
|
||||
.TryCatchGetFromJsonAsync<Response<List<AvatarUsageRank>>>($"{HutaoAPI}/Statistics/Avatar/UtilizationRate", options, logger, token)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return EnumerableExtension.EmptyIfNull(resp?.Data);
|
||||
@@ -131,7 +131,7 @@ internal class HomaClient
|
||||
public async Task<List<AvatarCollocation>> GetAvatarCollocationsAsync(CancellationToken token = default)
|
||||
{
|
||||
Response<List<AvatarCollocation>>? resp = await httpClient
|
||||
.GetFromJsonAsync<Response<List<AvatarCollocation>>>($"{HutaoAPI}/Statistics/Avatar/AvatarCollocation", token)
|
||||
.TryCatchGetFromJsonAsync<Response<List<AvatarCollocation>>>($"{HutaoAPI}/Statistics/Avatar/AvatarCollocation", options, logger, token)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return EnumerableExtension.EmptyIfNull(resp?.Data);
|
||||
@@ -146,7 +146,7 @@ internal class HomaClient
|
||||
public async Task<List<WeaponCollocation>> GetWeaponCollocationsAsync(CancellationToken token = default)
|
||||
{
|
||||
Response<List<WeaponCollocation>>? resp = await httpClient
|
||||
.GetFromJsonAsync<Response<List<WeaponCollocation>>>($"{HutaoAPI}/Statistics/Weapon/WeaponCollocation", token)
|
||||
.TryCatchGetFromJsonAsync<Response<List<WeaponCollocation>>>($"{HutaoAPI}/Statistics/Weapon/WeaponCollocation", options, logger, token)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return EnumerableExtension.EmptyIfNull(resp?.Data);
|
||||
@@ -161,7 +161,7 @@ internal class HomaClient
|
||||
public async Task<List<AvatarConstellationInfo>> GetAvatarHoldingRatesAsync(CancellationToken token = default)
|
||||
{
|
||||
Response<List<AvatarConstellationInfo>>? resp = await httpClient
|
||||
.GetFromJsonAsync<Response<List<AvatarConstellationInfo>>>($"{HutaoAPI}/Statistics/Avatar/HoldingRate", token)
|
||||
.TryCatchGetFromJsonAsync<Response<List<AvatarConstellationInfo>>>($"{HutaoAPI}/Statistics/Avatar/HoldingRate", options, logger, token)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return EnumerableExtension.EmptyIfNull(resp?.Data);
|
||||
@@ -176,7 +176,7 @@ internal class HomaClient
|
||||
public async Task<List<TeamAppearance>> GetTeamCombinationsAsync(CancellationToken token = default)
|
||||
{
|
||||
Response<List<TeamAppearance>>? resp = await httpClient
|
||||
.GetFromJsonAsync<Response<List<TeamAppearance>>>($"{HutaoAPI}/Statistics/Team/Combination", token)
|
||||
.TryCatchGetFromJsonAsync<Response<List<TeamAppearance>>>($"{HutaoAPI}/Statistics/Team/Combination", options, logger, token)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return EnumerableExtension.EmptyIfNull(resp?.Data);
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
|
||||
using Snap.Hutao.Web.Hoyolab;
|
||||
using Snap.Hutao.Web.Hutao.Log;
|
||||
using Snap.Hutao.Web.Response;
|
||||
using System.Net.Http;
|
||||
|
||||
@@ -53,6 +53,11 @@ public enum KnownReturnCode : int
|
||||
/// </summary>
|
||||
PleaseOpenInBbsApp = -1104,
|
||||
|
||||
/// <summary>
|
||||
/// 天赋等级超出限制~
|
||||
/// </summary>
|
||||
SkillLevelLimitExcceed = -1009,
|
||||
|
||||
/// <summary>
|
||||
/// 登录信息已失效,请重新登录
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user