mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
impl #1016
This commit is contained in:
@@ -38,9 +38,23 @@ internal static class StringBuilderExtension
|
|||||||
return condition ? sb.Append(value) : sb;
|
return condition ? sb.Append(value) : sb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string ToStringTrimEnd(this StringBuilder builder)
|
||||||
|
{
|
||||||
|
if (builder.Length > 1 && char.IsWhiteSpace(builder[^1]))
|
||||||
|
{
|
||||||
|
return builder.ToString(0, builder.Length - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
public static string ToStringTrimEndReturn(this StringBuilder builder)
|
public static string ToStringTrimEndReturn(this StringBuilder builder)
|
||||||
{
|
{
|
||||||
Must.Argument(builder.Length >= 1, "StringBuilder 的长度必须大于 0");
|
if (builder.Length < 1)
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
int remove = 0;
|
int remove = 0;
|
||||||
if (builder[^1] is '\n')
|
if (builder[^1] is '\n')
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
|
|
||||||
b.HasIndex("ArchiveId");
|
b.HasIndex("ArchiveId");
|
||||||
|
|
||||||
b.ToTable("achievements");
|
b.ToTable("achievements", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.AchievementArchive", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.AchievementArchive", b =>
|
||||||
@@ -60,7 +60,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
|
|
||||||
b.HasKey("InnerId");
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
b.ToTable("achievement_archives");
|
b.ToTable("achievement_archives", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.AvatarInfo", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.AvatarInfo", b =>
|
||||||
@@ -88,7 +88,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
|
|
||||||
b.HasKey("InnerId");
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
b.ToTable("avatar_infos");
|
b.ToTable("avatar_infos", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.CultivateEntry", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.CultivateEntry", b =>
|
||||||
@@ -110,7 +110,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
|
|
||||||
b.HasIndex("ProjectId");
|
b.HasIndex("ProjectId");
|
||||||
|
|
||||||
b.ToTable("cultivate_entries");
|
b.ToTable("cultivate_entries", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.CultivateEntryLevelInformation", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.CultivateEntryLevelInformation", b =>
|
||||||
@@ -156,7 +156,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
|
|
||||||
b.HasIndex("EntryId");
|
b.HasIndex("EntryId");
|
||||||
|
|
||||||
b.ToTable("cultivate_entry_level_informations");
|
b.ToTable("cultivate_entry_level_informations", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.CultivateItem", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.CultivateItem", b =>
|
||||||
@@ -181,7 +181,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
|
|
||||||
b.HasIndex("EntryId");
|
b.HasIndex("EntryId");
|
||||||
|
|
||||||
b.ToTable("cultivate_items");
|
b.ToTable("cultivate_items", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.CultivateProject", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.CultivateProject", b =>
|
||||||
@@ -202,7 +202,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
|
|
||||||
b.HasKey("InnerId");
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
b.ToTable("cultivate_projects");
|
b.ToTable("cultivate_projects", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.DailyNoteEntry", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.DailyNoteEntry", b =>
|
||||||
@@ -258,7 +258,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
|
|
||||||
b.HasIndex("UserId");
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
b.ToTable("daily_notes");
|
b.ToTable("daily_notes", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.GachaArchive", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.GachaArchive", b =>
|
||||||
@@ -276,7 +276,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
|
|
||||||
b.HasKey("InnerId");
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
b.ToTable("gacha_archives");
|
b.ToTable("gacha_archives", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.GachaItem", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.GachaItem", b =>
|
||||||
@@ -307,7 +307,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
|
|
||||||
b.HasIndex("ArchiveId");
|
b.HasIndex("ArchiveId");
|
||||||
|
|
||||||
b.ToTable("gacha_items");
|
b.ToTable("gacha_items", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.GameAccount", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.GameAccount", b =>
|
||||||
@@ -332,7 +332,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
|
|
||||||
b.HasKey("InnerId");
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
b.ToTable("game_accounts");
|
b.ToTable("game_accounts", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.InventoryItem", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.InventoryItem", b =>
|
||||||
@@ -354,7 +354,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
|
|
||||||
b.HasIndex("ProjectId");
|
b.HasIndex("ProjectId");
|
||||||
|
|
||||||
b.ToTable("inventory_items");
|
b.ToTable("inventory_items", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.InventoryReliquary", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.InventoryReliquary", b =>
|
||||||
@@ -383,7 +383,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
|
|
||||||
b.HasIndex("ProjectId");
|
b.HasIndex("ProjectId");
|
||||||
|
|
||||||
b.ToTable("inventory_reliquaries");
|
b.ToTable("inventory_reliquaries", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.InventoryWeapon", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.InventoryWeapon", b =>
|
||||||
@@ -408,7 +408,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
|
|
||||||
b.HasIndex("ProjectId");
|
b.HasIndex("ProjectId");
|
||||||
|
|
||||||
b.ToTable("inventory_weapons");
|
b.ToTable("inventory_weapons", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.ObjectCacheEntry", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.ObjectCacheEntry", b =>
|
||||||
@@ -424,7 +424,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
|
|
||||||
b.HasKey("Key");
|
b.HasKey("Key");
|
||||||
|
|
||||||
b.ToTable("object_cache");
|
b.ToTable("object_cache", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.SettingEntry", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.SettingEntry", b =>
|
||||||
@@ -437,7 +437,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
|
|
||||||
b.HasKey("Key");
|
b.HasKey("Key");
|
||||||
|
|
||||||
b.ToTable("settings");
|
b.ToTable("settings", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.SpiralAbyssEntry", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.SpiralAbyssEntry", b =>
|
||||||
@@ -459,7 +459,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
|
|
||||||
b.HasKey("InnerId");
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
b.ToTable("spiral_abysses");
|
b.ToTable("spiral_abysses", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.User", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.User", b =>
|
||||||
@@ -502,7 +502,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
|
|
||||||
b.HasKey("InnerId");
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
b.ToTable("users");
|
b.ToTable("users", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.Achievement", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.Achievement", b =>
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ internal sealed class CultivateEntry : IDbMappingForeignKeyFrom<CultivateEntry,
|
|||||||
[ForeignKey(nameof(ProjectId))]
|
[ForeignKey(nameof(ProjectId))]
|
||||||
public CultivateProject Project { get; set; } = default!;
|
public CultivateProject Project { get; set; } = default!;
|
||||||
|
|
||||||
|
public CultivateEntryLevelInformation? LevelInformation { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 养成类型
|
/// 养成类型
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -59,4 +61,10 @@ internal sealed class CultivateEntry : IDbMappingForeignKeyFrom<CultivateEntry,
|
|||||||
Id = id,
|
Id = id,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static CultivateEntry Join(CultivateEntry entry, CultivateEntryLevelInformation levelInformation)
|
||||||
|
{
|
||||||
|
entry.LevelInformation = levelInformation;
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using Snap.Hutao.Core.Abstraction;
|
using Snap.Hutao.Core.Abstraction;
|
||||||
|
using Snap.Hutao.Model.Entity.Primitive;
|
||||||
using Snap.Hutao.Service.Cultivation;
|
using Snap.Hutao.Service.Cultivation;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
@@ -9,7 +10,7 @@ using System.ComponentModel.DataAnnotations.Schema;
|
|||||||
namespace Snap.Hutao.Model.Entity;
|
namespace Snap.Hutao.Model.Entity;
|
||||||
|
|
||||||
[Table("cultivate_entry_level_informations")]
|
[Table("cultivate_entry_level_informations")]
|
||||||
internal sealed class CultivateEntryLevelInformation : IMappingFrom<CultivateEntryLevelInformation, Guid, LevelInformation>
|
internal sealed class CultivateEntryLevelInformation : IMappingFrom<CultivateEntryLevelInformation, Guid, CultivateType, LevelInformation>
|
||||||
{
|
{
|
||||||
[Key]
|
[Key]
|
||||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||||
@@ -40,21 +41,29 @@ internal sealed class CultivateEntryLevelInformation : IMappingFrom<CultivateEnt
|
|||||||
|
|
||||||
public uint WeaponLevelTo { get; set; }
|
public uint WeaponLevelTo { get; set; }
|
||||||
|
|
||||||
public static CultivateEntryLevelInformation From(Guid entryId, LevelInformation source)
|
public static CultivateEntryLevelInformation From(Guid entryId, CultivateType type, LevelInformation source)
|
||||||
{
|
{
|
||||||
return new()
|
return type switch
|
||||||
{
|
{
|
||||||
EntryId = entryId,
|
CultivateType.AvatarAndSkill => new()
|
||||||
AvatarLevelFrom = source.AvatarLevelFrom,
|
{
|
||||||
AvatarLevelTo = source.AvatarLevelTo,
|
EntryId = entryId,
|
||||||
SkillALevelFrom = source.SkillALevelFrom,
|
AvatarLevelFrom = source.AvatarLevelFrom,
|
||||||
SkillALevelTo = source.SkillALevelTo,
|
AvatarLevelTo = source.AvatarLevelTo,
|
||||||
SkillELevelFrom = source.SkillELevelFrom,
|
SkillALevelFrom = source.SkillALevelFrom,
|
||||||
SkillELevelTo = source.SkillELevelTo,
|
SkillALevelTo = source.SkillALevelTo,
|
||||||
SkillQLevelFrom = source.SkillQLevelFrom,
|
SkillELevelFrom = source.SkillELevelFrom,
|
||||||
SkillQLevelTo = source.SkillQLevelTo,
|
SkillELevelTo = source.SkillELevelTo,
|
||||||
WeaponLevelFrom = source.WeaponLevelFrom,
|
SkillQLevelFrom = source.SkillQLevelFrom,
|
||||||
WeaponLevelTo = source.WeaponLevelTo,
|
SkillQLevelTo = source.SkillQLevelTo,
|
||||||
|
},
|
||||||
|
CultivateType.Weapon => new()
|
||||||
|
{
|
||||||
|
EntryId = entryId,
|
||||||
|
WeaponLevelFrom = source.WeaponLevelFrom,
|
||||||
|
WeaponLevelTo = source.WeaponLevelTo,
|
||||||
|
},
|
||||||
|
_ => throw Must.NeverHappen($"不支持的养成类型{type}"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1406,6 +1406,9 @@
|
|||||||
<data name="ViewModelCultivationEntryAddWarning" xml:space="preserve">
|
<data name="ViewModelCultivationEntryAddWarning" xml:space="preserve">
|
||||||
<value>请先前往养成计划页面创建计划并选中</value>
|
<value>请先前往养成计划页面创建计划并选中</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="ViewModelCultivationEntryViewDescriptionDefault" xml:space="preserve">
|
||||||
|
<value>重新添加物品以查看养成描述</value>
|
||||||
|
</data>
|
||||||
<data name="ViewModelCultivationProjectAdded" xml:space="preserve">
|
<data name="ViewModelCultivationProjectAdded" xml:space="preserve">
|
||||||
<value>添加成功</value>
|
<value>添加成功</value>
|
||||||
</data>
|
</data>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Internal;
|
||||||
using Snap.Hutao.Core.Database;
|
using Snap.Hutao.Core.Database;
|
||||||
using Snap.Hutao.Model.Entity;
|
using Snap.Hutao.Model.Entity;
|
||||||
using Snap.Hutao.Model.Entity.Database;
|
using Snap.Hutao.Model.Entity.Database;
|
||||||
@@ -51,6 +52,20 @@ internal sealed partial class CultivationDbService : ICultivationDbService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async ValueTask<List<CultivateEntry>> GetCultivateEntryIncludeLevelInformationListByProjectIdAsync(Guid projectId)
|
||||||
|
{
|
||||||
|
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||||
|
{
|
||||||
|
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||||
|
return await appDbContext.CultivateEntries
|
||||||
|
.AsNoTracking()
|
||||||
|
.Where(e => e.ProjectId == projectId)
|
||||||
|
.Include(e => e.LevelInformation)
|
||||||
|
.ToListAsync()
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async ValueTask<List<CultivateItem>> GetCultivateItemListByEntryIdAsync(Guid entryId)
|
public async ValueTask<List<CultivateItem>> GetCultivateItemListByEntryIdAsync(Guid entryId)
|
||||||
{
|
{
|
||||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||||
|
|||||||
@@ -54,19 +54,19 @@ internal sealed partial class CultivationService : ICultivationService
|
|||||||
{
|
{
|
||||||
await taskContext.SwitchToBackgroundAsync();
|
await taskContext.SwitchToBackgroundAsync();
|
||||||
List<CultivateEntry> entries = await cultivationDbService
|
List<CultivateEntry> entries = await cultivationDbService
|
||||||
.GetCultivateEntryListByProjectIdAsync(cultivateProject.InnerId)
|
.GetCultivateEntryIncludeLevelInformationListByProjectIdAsync(cultivateProject.InnerId)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
List<CultivateEntryView> resultEntries = new(entries.Count);
|
List<CultivateEntryView> resultEntries = new(entries.Count);
|
||||||
foreach (CultivateEntry entry in entries)
|
foreach (CultivateEntry entry in entries)
|
||||||
{
|
{
|
||||||
List<CultivateItemView> entryItems = [];
|
List<CultivateItemView> entryItems = [];
|
||||||
foreach (CultivateItem item in await cultivationDbService.GetCultivateItemListByEntryIdAsync(entry.InnerId).ConfigureAwait(false))
|
foreach (CultivateItem cultivateItem in await cultivationDbService.GetCultivateItemListByEntryIdAsync(entry.InnerId).ConfigureAwait(false))
|
||||||
{
|
{
|
||||||
entryItems.Add(new(item, context.GetMaterial(item.ItemId)));
|
entryItems.Add(new(cultivateItem, context.GetMaterial(cultivateItem.ItemId)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Item itemBase = entry.Type switch
|
Item item = entry.Type switch
|
||||||
{
|
{
|
||||||
CultivateType.AvatarAndSkill => context.GetAvatar(entry.Id).ToItem(),
|
CultivateType.AvatarAndSkill => context.GetAvatar(entry.Id).ToItem(),
|
||||||
CultivateType.Weapon => context.GetWeapon(entry.Id).ToItem(),
|
CultivateType.Weapon => context.GetWeapon(entry.Id).ToItem(),
|
||||||
@@ -75,7 +75,7 @@ internal sealed partial class CultivationService : ICultivationService
|
|||||||
_ => default!,
|
_ => default!,
|
||||||
};
|
};
|
||||||
|
|
||||||
resultEntries.Add(new(entry, itemBase, entryItems));
|
resultEntries.Add(new(entry, item, entryItems));
|
||||||
}
|
}
|
||||||
|
|
||||||
return resultEntries
|
return resultEntries
|
||||||
@@ -184,7 +184,7 @@ internal sealed partial class CultivationService : ICultivationService
|
|||||||
Guid entryId = entry.InnerId;
|
Guid entryId = entry.InnerId;
|
||||||
|
|
||||||
await cultivationDbService.RemoveLevelInformationByEntryIdAsync(entryId).ConfigureAwait(false);
|
await cultivationDbService.RemoveLevelInformationByEntryIdAsync(entryId).ConfigureAwait(false);
|
||||||
CultivateEntryLevelInformation entryLevelInformation = CultivateEntryLevelInformation.From(entryId, levelInformation);
|
CultivateEntryLevelInformation entryLevelInformation = CultivateEntryLevelInformation.From(entryId, type, levelInformation);
|
||||||
await cultivationDbService.AddLevelInformationAsync(entryLevelInformation).ConfigureAwait(false);
|
await cultivationDbService.AddLevelInformationAsync(entryLevelInformation).ConfigureAwait(false);
|
||||||
|
|
||||||
await cultivationDbService.RemoveCultivateItemRangeByEntryIdAsync(entryId).ConfigureAwait(false);
|
await cultivationDbService.RemoveCultivateItemRangeByEntryIdAsync(entryId).ConfigureAwait(false);
|
||||||
|
|||||||
@@ -35,6 +35,10 @@ internal interface ICultivationDbService
|
|||||||
void UpdateCultivateItem(CultivateItem item);
|
void UpdateCultivateItem(CultivateItem item);
|
||||||
|
|
||||||
ValueTask UpdateCultivateItemAsync(CultivateItem item);
|
ValueTask UpdateCultivateItemAsync(CultivateItem item);
|
||||||
|
|
||||||
ValueTask RemoveLevelInformationByEntryIdAsync(Guid entryId);
|
ValueTask RemoveLevelInformationByEntryIdAsync(Guid entryId);
|
||||||
|
|
||||||
ValueTask AddLevelInformationAsync(CultivateEntryLevelInformation levelInformation);
|
ValueTask AddLevelInformationAsync(CultivateEntryLevelInformation levelInformation);
|
||||||
|
|
||||||
|
ValueTask<List<CultivateEntry>> GetCultivateEntryIncludeLevelInformationListByProjectIdAsync(Guid projectId);
|
||||||
}
|
}
|
||||||
@@ -74,7 +74,7 @@
|
|||||||
Margin="0,8,0,0"
|
Margin="0,8,0,0"
|
||||||
Visibility="{x:Bind Avatar, Converter={StaticResource EmptyObjectToVisibilityConverter}}">
|
Visibility="{x:Bind Avatar, Converter={StaticResource EmptyObjectToVisibilityConverter}}">
|
||||||
<Grid
|
<Grid
|
||||||
Margin="8"
|
Padding="8"
|
||||||
DataContext="{x:Bind Avatar}"
|
DataContext="{x:Bind Avatar}"
|
||||||
Style="{ThemeResource GridCardStyle}">
|
Style="{ThemeResource GridCardStyle}">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
@@ -124,10 +124,10 @@
|
|||||||
|
|
||||||
<StackPanel
|
<StackPanel
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
Margin="0,8,0,0"
|
Margin="0,6,0,0"
|
||||||
Visibility="{x:Bind Weapon, Converter={StaticResource EmptyObjectToVisibilityConverter}}">
|
Visibility="{x:Bind Weapon, Converter={StaticResource EmptyObjectToVisibilityConverter}}">
|
||||||
<Grid
|
<Grid
|
||||||
Margin="8"
|
Padding="8"
|
||||||
DataContext="{x:Bind Weapon}"
|
DataContext="{x:Bind Weapon}"
|
||||||
Style="{ThemeResource GridCardStyle}">
|
Style="{ThemeResource GridCardStyle}">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
|
|||||||
@@ -130,11 +130,17 @@
|
|||||||
Height="48"
|
Height="48"
|
||||||
Icon="{Binding Icon}"
|
Icon="{Binding Icon}"
|
||||||
Quality="{Binding Quality}"/>
|
Quality="{Binding Quality}"/>
|
||||||
<TextBlock
|
<StackPanel
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Margin="8,0,0,0"
|
Margin="8,0,0,0"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center">
|
||||||
Text="{Binding Name}"/>
|
<TextBlock Text="{Binding Name}"/>
|
||||||
|
<TextBlock
|
||||||
|
Opacity="0.7"
|
||||||
|
Style="{StaticResource CaptionTextBlockStyle}"
|
||||||
|
Text="{Binding Description}"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
<StackPanel Grid.Column="2" Orientation="Horizontal">
|
<StackPanel Grid.Column="2" Orientation="Horizontal">
|
||||||
<Button
|
<Button
|
||||||
Width="48"
|
Width="48"
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ using Snap.Hutao.Service.Notification;
|
|||||||
using Snap.Hutao.Service.User;
|
using Snap.Hutao.Service.User;
|
||||||
using Snap.Hutao.View.Dialog;
|
using Snap.Hutao.View.Dialog;
|
||||||
using Snap.Hutao.ViewModel.User;
|
using Snap.Hutao.ViewModel.User;
|
||||||
|
using Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate;
|
||||||
using Snap.Hutao.Web.Response;
|
using Snap.Hutao.Web.Response;
|
||||||
using Windows.Graphics.Imaging;
|
using Windows.Graphics.Imaging;
|
||||||
using Windows.Storage.Streams;
|
using Windows.Storage.Streams;
|
||||||
@@ -51,6 +52,13 @@ internal sealed partial class AvatarPropertyViewModel : Abstraction.ViewModel, I
|
|||||||
private Summary? summary;
|
private Summary? summary;
|
||||||
private AvatarView? selectedAvatar;
|
private AvatarView? selectedAvatar;
|
||||||
|
|
||||||
|
private enum CultivateCoreResult
|
||||||
|
{
|
||||||
|
Ok,
|
||||||
|
ComputeConsumptionFailed,
|
||||||
|
SaveConsumptionFailed,
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 简述对象
|
/// 简述对象
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -187,153 +195,86 @@ internal sealed partial class AvatarPropertyViewModel : Abstraction.ViewModel, I
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Response<CalculatorConsumption> consumptionResponse = await calculatorClient
|
CultivateCoreResult result = await CultivateCoreAsync(userService.Current.Entity, delta, avatar).ConfigureAwait(false);
|
||||||
.ComputeAsync(userService.Current.Entity, delta)
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (!consumptionResponse.IsOk())
|
switch (result)
|
||||||
{
|
{
|
||||||
return;
|
case CultivateCoreResult.Ok:
|
||||||
}
|
|
||||||
|
|
||||||
CalculatorConsumption consumption = consumptionResponse.Data;
|
|
||||||
LevelInformation levelInformation = LevelInformation.From(delta);
|
|
||||||
|
|
||||||
List<CalculatorItem> items = CalculatorItemHelper.Merge(consumption.AvatarConsume, consumption.AvatarSkillConsume);
|
|
||||||
bool avatarSaved = await cultivationService
|
|
||||||
.SaveConsumptionAsync(CultivateType.AvatarAndSkill, avatar.Id, items, levelInformation)
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Take a hot path if avatar is not saved.
|
|
||||||
bool avatarAndWeaponSaved = avatarSaved && await cultivationService
|
|
||||||
.SaveConsumptionAsync(CultivateType.Weapon, avatar.Weapon.Id, consumption.WeaponConsume.EmptyIfNull(), levelInformation)
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (avatarAndWeaponSaved)
|
|
||||||
{
|
|
||||||
infoBarService.Success(SH.ViewModelCultivationEntryAddSuccess);
|
infoBarService.Success(SH.ViewModelCultivationEntryAddSuccess);
|
||||||
}
|
break;
|
||||||
else
|
case CultivateCoreResult.SaveConsumptionFailed:
|
||||||
{
|
|
||||||
infoBarService.Warning(SH.ViewModelCultivationEntryAddWarning);
|
infoBarService.Warning(SH.ViewModelCultivationEntryAddWarning);
|
||||||
}
|
break;
|
||||||
}
|
|
||||||
catch (Core.ExceptionService.UserdataCorruptedException ex)
|
|
||||||
{
|
|
||||||
infoBarService.Error(ex, SH.ViewModelCultivationAddWarning);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command("BatchCultivateCommand")]
|
[Command("BatchCultivateCommand")]
|
||||||
private async Task BatchCultivateAsync()
|
private async Task BatchCultivateAsync()
|
||||||
{
|
{
|
||||||
if (summary is { Avatars: { } avatars })
|
if (summary is not { Avatars: { } avatars })
|
||||||
{
|
{
|
||||||
if (userService.Current is null)
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userService.Current is null)
|
||||||
|
{
|
||||||
|
infoBarService.Warning(SH.MustSelectUserAndUid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CultivatePromotionDeltaBatchDialog dialog = await contentDialogFactory.CreateInstanceAsync<CultivatePromotionDeltaBatchDialog>().ConfigureAwait(false);
|
||||||
|
(bool isOk, CalculatorAvatarPromotionDelta baseline) = await dialog.GetPromotionDeltaBaselineAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (!isOk)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArgumentNullException.ThrowIfNull(baseline.SkillList);
|
||||||
|
ArgumentNullException.ThrowIfNull(baseline.Weapon);
|
||||||
|
|
||||||
|
ContentDialog progressDialog = await contentDialogFactory
|
||||||
|
.CreateForIndeterminateProgressAsync(SH.ViewModelAvatarPropertyBatchCultivateProgressTitle)
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
using (await progressDialog.BlockAsync(taskContext).ConfigureAwait(false))
|
||||||
|
{
|
||||||
|
BatchCultivateResult result = default;
|
||||||
|
foreach (AvatarView avatar in avatars)
|
||||||
{
|
{
|
||||||
infoBarService.Warning(SH.MustSelectUserAndUid);
|
if (!baseline.TryGetNonErrorCopy(avatar, out CalculatorAvatarPromotionDelta? copy))
|
||||||
|
{
|
||||||
|
++result.SkippedCount;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
CultivateCoreResult coreResult = await CultivateCoreAsync(userService.Current.Entity, copy, avatar).ConfigureAwait(false);
|
||||||
|
|
||||||
|
switch (coreResult)
|
||||||
|
{
|
||||||
|
case CultivateCoreResult.Ok:
|
||||||
|
++result.SucceedCount;
|
||||||
|
break;
|
||||||
|
case CultivateCoreResult.ComputeConsumptionFailed:
|
||||||
|
result.Interrupted = true;
|
||||||
|
break;
|
||||||
|
case CultivateCoreResult.SaveConsumptionFailed:
|
||||||
|
result.Interrupted = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.Interrupted)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.Interrupted)
|
||||||
|
{
|
||||||
|
infoBarService.Warning(SH.FormatViewModelCultivationBatchAddIncompletedFormat(result.SucceedCount, result.SkippedCount));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CultivatePromotionDeltaBatchDialog dialog = await contentDialogFactory.CreateInstanceAsync<CultivatePromotionDeltaBatchDialog>().ConfigureAwait(false);
|
infoBarService.Success(SH.FormatViewModelCultivationBatchAddCompletedFormat(result.SucceedCount, result.SkippedCount));
|
||||||
(bool isOk, CalculatorAvatarPromotionDelta baseline) = await dialog.GetPromotionDeltaBaselineAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (isOk)
|
|
||||||
{
|
|
||||||
ArgumentNullException.ThrowIfNull(baseline.SkillList);
|
|
||||||
ArgumentNullException.ThrowIfNull(baseline.Weapon);
|
|
||||||
|
|
||||||
ContentDialog progressDialog = await contentDialogFactory
|
|
||||||
.CreateForIndeterminateProgressAsync(SH.ViewModelAvatarPropertyBatchCultivateProgressTitle)
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
using (await progressDialog.BlockAsync(taskContext).ConfigureAwait(false))
|
|
||||||
{
|
|
||||||
BatchCultivateResult result = default;
|
|
||||||
foreach (AvatarView avatar in avatars)
|
|
||||||
{
|
|
||||||
baseline.AvatarId = avatar.Id;
|
|
||||||
baseline.AvatarLevelCurrent = Math.Min(avatar.LevelNumber, baseline.AvatarLevelTarget);
|
|
||||||
|
|
||||||
if (avatar.Skills.Count < 3)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
baseline.SkillList[0].Id = avatar.Skills[0].GroupId;
|
|
||||||
baseline.SkillList[0].LevelCurrent = Math.Min(avatar.Skills[0].LevelNumber, baseline.SkillList[0].LevelTarget);
|
|
||||||
baseline.SkillList[1].Id = avatar.Skills[1].GroupId;
|
|
||||||
baseline.SkillList[1].LevelCurrent = Math.Min(avatar.Skills[1].LevelNumber, baseline.SkillList[1].LevelTarget);
|
|
||||||
baseline.SkillList[2].Id = avatar.Skills[2].GroupId;
|
|
||||||
baseline.SkillList[2].LevelCurrent = Math.Min(avatar.Skills[2].LevelNumber, baseline.SkillList[2].LevelTarget);
|
|
||||||
|
|
||||||
if (avatar.Weapon is null)
|
|
||||||
{
|
|
||||||
result.SkippedCount++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: handle this correctly.
|
|
||||||
// We should always create a new baseline each time.
|
|
||||||
baseline.Weapon.Id = avatar.Weapon.Id;
|
|
||||||
baseline.Weapon.LevelCurrent = Math.Min(avatar.Weapon.LevelNumber, baseline.Weapon.LevelTarget);
|
|
||||||
baseline.Weapon.LevelTarget = Math.Min(avatar.Weapon.MaxLevel, baseline.Weapon.LevelTarget);
|
|
||||||
|
|
||||||
Response<CalculatorConsumption> consumptionResponse = await calculatorClient
|
|
||||||
.ComputeAsync(userService.Current.Entity, baseline)
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (!consumptionResponse.IsOk())
|
|
||||||
{
|
|
||||||
result.Interrupted = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
CalculatorConsumption consumption = consumptionResponse.Data;
|
|
||||||
LevelInformation levelInformation = LevelInformation.From(baseline);
|
|
||||||
|
|
||||||
List<CalculatorItem> items = CalculatorItemHelper.Merge(consumption.AvatarConsume, consumption.AvatarSkillConsume);
|
|
||||||
bool avatarSaved = await cultivationService
|
|
||||||
.SaveConsumptionAsync(CultivateType.AvatarAndSkill, avatar.Id, items, levelInformation)
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// take a hot path if avatar is not saved.
|
|
||||||
bool avatarAndWeaponSaved = avatarSaved && await cultivationService
|
|
||||||
.SaveConsumptionAsync(CultivateType.Weapon, avatar.Weapon.Id, consumption.WeaponConsume.EmptyIfNull(), levelInformation)
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (avatarAndWeaponSaved)
|
|
||||||
{
|
|
||||||
result.SucceedCount++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result.Interrupted = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Core.ExceptionService.UserdataCorruptedException ex)
|
|
||||||
{
|
|
||||||
infoBarService.Error(ex, SH.ViewModelCultivationAddWarning);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result.Interrupted)
|
|
||||||
{
|
|
||||||
infoBarService.Warning(SH.ViewModelCultivationEntryAddWarning);
|
|
||||||
infoBarService.Warning(SH.FormatViewModelCultivationBatchAddIncompletedFormat(result.SucceedCount, result.SkippedCount));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
infoBarService.Success(SH.FormatViewModelCultivationBatchAddCompletedFormat(result.SucceedCount, result.SkippedCount));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -372,4 +313,43 @@ internal sealed partial class AvatarPropertyViewModel : Abstraction.ViewModel, I
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async ValueTask<CultivateCoreResult> CultivateCoreAsync(Model.Entity.User user, CalculatorAvatarPromotionDelta delta, AvatarView avatar)
|
||||||
|
{
|
||||||
|
Response<CalculatorConsumption> consumptionResponse = await calculatorClient.ComputeAsync(user, delta).ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (!consumptionResponse.IsOk())
|
||||||
|
{
|
||||||
|
return CultivateCoreResult.ComputeConsumptionFailed;
|
||||||
|
}
|
||||||
|
|
||||||
|
CalculatorConsumption consumption = consumptionResponse.Data;
|
||||||
|
LevelInformation levelInformation = LevelInformation.From(delta);
|
||||||
|
|
||||||
|
List<CalculatorItem> items = CalculatorItemHelper.Merge(consumption.AvatarConsume, consumption.AvatarSkillConsume);
|
||||||
|
bool avatarSaved = await cultivationService
|
||||||
|
.SaveConsumptionAsync(CultivateType.AvatarAndSkill, avatar.Id, items, levelInformation)
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ArgumentNullException.ThrowIfNull(avatar.Weapon);
|
||||||
|
|
||||||
|
// Take a hot path if avatar is not saved.
|
||||||
|
bool avatarAndWeaponSaved = avatarSaved && await cultivationService
|
||||||
|
.SaveConsumptionAsync(CultivateType.Weapon, avatar.Weapon.Id, consumption.WeaponConsume.EmptyIfNull(), levelInformation)
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (!avatarAndWeaponSaved)
|
||||||
|
{
|
||||||
|
return CultivateCoreResult.SaveConsumptionFailed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Core.ExceptionService.UserdataCorruptedException ex)
|
||||||
|
{
|
||||||
|
infoBarService.Error(ex, SH.ViewModelCultivationAddWarning);
|
||||||
|
}
|
||||||
|
|
||||||
|
return CultivateCoreResult.Ok;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,8 @@
|
|||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using Snap.Hutao.Model;
|
using Snap.Hutao.Model;
|
||||||
|
using Snap.Hutao.Model.Entity;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
namespace Snap.Hutao.ViewModel.Cultivation;
|
namespace Snap.Hutao.ViewModel.Cultivation;
|
||||||
|
|
||||||
@@ -11,13 +13,7 @@ namespace Snap.Hutao.ViewModel.Cultivation;
|
|||||||
[HighQuality]
|
[HighQuality]
|
||||||
internal sealed class CultivateEntryView : Item
|
internal sealed class CultivateEntryView : Item
|
||||||
{
|
{
|
||||||
/// <summary>
|
public CultivateEntryView(CultivateEntry entry, Item item, List<CultivateItemView> items)
|
||||||
/// 构造一个新的养成清单入口
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="entry">实体入口</param>
|
|
||||||
/// <param name="item">对应物品</param>
|
|
||||||
/// <param name="items">物品列表</param>
|
|
||||||
public CultivateEntryView(Model.Entity.CultivateEntry entry, Item item, List<CultivateItemView> items)
|
|
||||||
{
|
{
|
||||||
Id = entry.Id;
|
Id = entry.Id;
|
||||||
EntryId = entry.InnerId;
|
EntryId = entry.InnerId;
|
||||||
@@ -26,33 +22,75 @@ internal sealed class CultivateEntryView : Item
|
|||||||
Badge = item.Badge;
|
Badge = item.Badge;
|
||||||
Quality = item.Quality;
|
Quality = item.Quality;
|
||||||
Items = items;
|
Items = items;
|
||||||
|
|
||||||
|
Description = ParseDescription(entry);
|
||||||
|
IsToday = items.Any(i => i.IsToday);
|
||||||
|
DaysOfWeek = items.FirstOrDefault(i => i.DaysOfWeek != DaysOfWeek.Any)?.DaysOfWeek ?? DaysOfWeek.Any;
|
||||||
|
|
||||||
|
static string ParseDescription(CultivateEntry entry)
|
||||||
|
{
|
||||||
|
if (entry.LevelInformation is null)
|
||||||
|
{
|
||||||
|
return SH.ViewModelCultivationEntryViewDescriptionDefault;
|
||||||
|
}
|
||||||
|
|
||||||
|
CultivateEntryLevelInformation info = entry.LevelInformation;
|
||||||
|
|
||||||
|
switch (entry.Type)
|
||||||
|
{
|
||||||
|
case Model.Entity.Primitive.CultivateType.AvatarAndSkill:
|
||||||
|
{
|
||||||
|
StringBuilder stringBuilder = new();
|
||||||
|
|
||||||
|
if (info.AvatarLevelFrom != info.AvatarLevelTo)
|
||||||
|
{
|
||||||
|
stringBuilder.Append("Lv.").Append(info.AvatarLevelFrom).Append(" → Lv.").Append(info.AvatarLevelTo).Append(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.SkillALevelFrom != info.SkillALevelTo)
|
||||||
|
{
|
||||||
|
stringBuilder.Append("A: ").Append(info.SkillALevelFrom).Append(" → ").Append(info.SkillALevelTo).Append(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.SkillELevelFrom != info.SkillELevelTo)
|
||||||
|
{
|
||||||
|
stringBuilder.Append("E: ").Append(info.SkillELevelFrom).Append(" → ").Append(info.SkillELevelTo).Append(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.SkillQLevelFrom != info.SkillQLevelTo)
|
||||||
|
{
|
||||||
|
stringBuilder.Append("Q: ").Append(info.SkillQLevelFrom).Append(" → ").Append(info.SkillQLevelTo).Append(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
return stringBuilder.ToStringTrimEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
case Model.Entity.Primitive.CultivateType.Weapon:
|
||||||
|
{
|
||||||
|
StringBuilder stringBuilder = new();
|
||||||
|
|
||||||
|
if (info.WeaponLevelFrom != info.WeaponLevelTo)
|
||||||
|
{
|
||||||
|
stringBuilder.Append("Lv.").Append(info.WeaponLevelFrom).Append(" → Lv.").Append(info.WeaponLevelTo);
|
||||||
|
}
|
||||||
|
|
||||||
|
return stringBuilder.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 实体
|
|
||||||
/// </summary>
|
|
||||||
public List<CultivateItemView> Items { get; set; } = default!;
|
public List<CultivateItemView> Items { get; set; } = default!;
|
||||||
|
|
||||||
/// <summary>
|
public bool IsToday { get; }
|
||||||
/// 是否为今日的材料
|
|
||||||
/// </summary>
|
|
||||||
public bool IsToday { get => Items.Any(i => i.IsToday); }
|
|
||||||
|
|
||||||
/// <summary>
|
public DaysOfWeek DaysOfWeek { get; }
|
||||||
/// 星期中的日期
|
|
||||||
/// </summary>
|
public string Description { get; }
|
||||||
public DaysOfWeek DaysOfWeek
|
|
||||||
{
|
|
||||||
get => Items.FirstOrDefault(i => i.DaysOfWeek != DaysOfWeek.Any)?.DaysOfWeek ?? DaysOfWeek.Any;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Id
|
|
||||||
/// </summary>
|
|
||||||
internal uint Id { get; set; }
|
internal uint Id { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 入口Id
|
|
||||||
/// </summary>
|
|
||||||
internal Guid EntryId { get; set; }
|
internal Guid EntryId { get; set; }
|
||||||
}
|
}
|
||||||
@@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
using Snap.Hutao.Core.Setting;
|
using Snap.Hutao.Core.Setting;
|
||||||
using Snap.Hutao.Model.Primitive;
|
using Snap.Hutao.Model.Primitive;
|
||||||
using Snap.Hutao.ViewModel.AvatarProperty;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate;
|
namespace Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate;
|
||||||
|
|
||||||
@@ -63,41 +62,4 @@ internal sealed class AvatarPromotionDelta
|
|||||||
Weapon = new() { LevelTarget = LocalSetting.Get(SettingKeys.CultivationWeapon90LevelTarget, 90U), },
|
Weapon = new() { LevelTarget = LocalSetting.Get(SettingKeys.CultivationWeapon90LevelTarget, 90U), },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool TryGetNonErrorCopy(AvatarPromotionDelta source, AvatarView avatar, out AvatarPromotionDelta? copy)
|
|
||||||
{
|
|
||||||
copy = new()
|
|
||||||
{
|
|
||||||
AvatarId = avatar.Id,
|
|
||||||
AvatarLevelCurrent = Math.Min(avatar.LevelNumber, source.AvatarLevelTarget),
|
|
||||||
};
|
|
||||||
|
|
||||||
if (avatar.Skills is [SkillView skillA, SkillView skillE, SkillView skillQ, ..])
|
|
||||||
{
|
|
||||||
copy.SkillList = new(3);
|
|
||||||
copy.SkillList.Add(new()
|
|
||||||
{
|
|
||||||
Id = skillA.GroupId,
|
|
||||||
LevelCurrent = Math.Min(skillA.LevelNumber, skillA.LevelTarget),
|
|
||||||
});
|
|
||||||
copy.SkillList[0].Id = skillA.GroupId;
|
|
||||||
copy.SkillList[0].LevelCurrent = Math.Min(skillA.LevelNumber, copy.SkillList[0].LevelTarget);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
target = new()
|
|
||||||
{
|
|
||||||
AvatarId = source.AvatarId,
|
|
||||||
AvatarLevelCurrent = source.AvatarLevelCurrent,
|
|
||||||
AvatarLevelTarget = source.AvatarLevelTarget,
|
|
||||||
ElementAttrId = source.ElementAttrId,
|
|
||||||
SkillList = source.SkillList?.Select(i => i.Clone()).ToList(),
|
|
||||||
Weapon = source.Weapon?.Clone(),
|
|
||||||
};
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.ViewModel.AvatarProperty;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate;
|
||||||
|
|
||||||
|
internal static class AvatarPromotionDeltaExtension
|
||||||
|
{
|
||||||
|
public static bool TryGetNonErrorCopy(this AvatarPromotionDelta source, AvatarView avatar, [NotNullWhen(true)] out AvatarPromotionDelta? copy)
|
||||||
|
{
|
||||||
|
copy = new()
|
||||||
|
{
|
||||||
|
AvatarId = avatar.Id,
|
||||||
|
AvatarLevelCurrent = Math.Min(avatar.LevelNumber, source.AvatarLevelTarget),
|
||||||
|
AvatarLevelTarget = source.AvatarLevelTarget,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (avatar.Skills is not ([SkillView skillViewA, SkillView skillViewE, SkillView skillViewQ, ..]) ||
|
||||||
|
source.SkillList is not ([PromotionDelta deltaA, PromotionDelta deltaE, PromotionDelta deltaQ, ..]))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
copy.SkillList = new(3)
|
||||||
|
{
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
Id = skillViewA.GroupId,
|
||||||
|
LevelCurrent = Math.Min(skillViewA.LevelNumber, deltaA.LevelTarget),
|
||||||
|
LevelTarget = deltaA.LevelTarget,
|
||||||
|
},
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
Id = skillViewE.GroupId,
|
||||||
|
LevelCurrent = Math.Min(skillViewE.LevelNumber, deltaE.LevelTarget),
|
||||||
|
LevelTarget = deltaE.LevelTarget,
|
||||||
|
},
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
Id = skillViewQ.GroupId,
|
||||||
|
LevelCurrent = Math.Min(skillViewQ.LevelNumber, deltaQ.LevelTarget),
|
||||||
|
LevelTarget = deltaQ.LevelTarget,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (avatar.Weapon is not WeaponView weaponView || source.Weapon is not { } deltaWeapon)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
copy.Weapon = new()
|
||||||
|
{
|
||||||
|
Id = weaponView.Id,
|
||||||
|
LevelCurrent = Math.Min(weaponView.LevelNumber, deltaWeapon.LevelTarget),
|
||||||
|
LevelTarget = Math.Min(weaponView.MaxLevel, deltaWeapon.LevelTarget),
|
||||||
|
};
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user