mirror of
https://github.com/wangdage12/Snap.Hutao.git
synced 2026-07-31 04:10:25 +08:00
材料统计支持周本材料转化后的结果
This commit is contained in:
@@ -76,6 +76,7 @@ internal static class SettingKeys
|
|||||||
public const string ResinStatisticsSelectedDropDistribution = "Snap::Hutao::Cultivation::ResinStatistics::DropDistribution";
|
public const string ResinStatisticsSelectedDropDistribution = "Snap::Hutao::Cultivation::ResinStatistics::DropDistribution";
|
||||||
public const string CultivationStatisticsMergeUpgradeMaterials = "Snap::Hutao::Cultivation::Statistics::MergeUpgradeMaterials";
|
public const string CultivationStatisticsMergeUpgradeMaterials = "Snap::Hutao::Cultivation::Statistics::MergeUpgradeMaterials";
|
||||||
public const string CultivationStatisticsTalentSynthCritTenPercent = "Snap::Hutao::Cultivation::Statistics::TalentSynthCritTenPercent";
|
public const string CultivationStatisticsTalentSynthCritTenPercent = "Snap::Hutao::Cultivation::Statistics::TalentSynthCritTenPercent";
|
||||||
|
public const string CultivationStatisticsWeeklyBossMaterialInterchange = "Snap::Hutao::Cultivation::Statistics::WeeklyBossMaterialInterchange";
|
||||||
|
|
||||||
// GachaLog
|
// GachaLog
|
||||||
public const string IsEmptyHistoryWishVisible = "Snap::Hutao::GachaLog::HistoryWish::EmptyVisible";
|
public const string IsEmptyHistoryWishVisible = "Snap::Hutao::GachaLog::HistoryWish::EmptyVisible";
|
||||||
|
|||||||
@@ -2429,6 +2429,9 @@ Space Available: {2}</value>
|
|||||||
<data name="ViewPageCultivationTalentSynthCritTenPercentLabel" xml:space="preserve">
|
<data name="ViewPageCultivationTalentSynthCritTenPercentLabel" xml:space="preserve">
|
||||||
<value>Character talent (10%)</value>
|
<value>Character talent (10%)</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="ViewPageCultivationWeeklyBossMaterialInterchangeLabel" xml:space="preserve">
|
||||||
|
<value>Weekly boss material interchange</value>
|
||||||
|
</data>
|
||||||
<data name="ViewPageCultivationMaterialListResinStatisticsLabel" xml:space="preserve">
|
<data name="ViewPageCultivationMaterialListResinStatisticsLabel" xml:space="preserve">
|
||||||
<value>Resin Estimation</value>
|
<value>Resin Estimation</value>
|
||||||
</data>
|
</data>
|
||||||
|
|||||||
@@ -2480,6 +2480,9 @@
|
|||||||
<data name="ViewPageCultivationTalentSynthCritTenPercentLabel" xml:space="preserve">
|
<data name="ViewPageCultivationTalentSynthCritTenPercentLabel" xml:space="preserve">
|
||||||
<value>角色天赋(10%)</value>
|
<value>角色天赋(10%)</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="ViewPageCultivationWeeklyBossMaterialInterchangeLabel" xml:space="preserve">
|
||||||
|
<value>周本材料转化</value>
|
||||||
|
</data>
|
||||||
<data name="ViewPageCultivationMaterialListResinStatisticsLabel" xml:space="preserve">
|
<data name="ViewPageCultivationMaterialListResinStatisticsLabel" xml:space="preserve">
|
||||||
<value>树脂预估</value>
|
<value>树脂预估</value>
|
||||||
</data>
|
</data>
|
||||||
|
|||||||
@@ -23,6 +23,9 @@ internal class CultivationMetadataContext : ICultivationMetadataContext
|
|||||||
|
|
||||||
public ImmutableDictionary<MaterialId, Combine> ResultMaterialIdCombineMap { get; set; } = default!;
|
public ImmutableDictionary<MaterialId, Combine> ResultMaterialIdCombineMap { get; set; } = default!;
|
||||||
|
|
||||||
|
public ImmutableArray<ImmutableArray<MaterialId>> WeeklyBossMaterialInterchangeGroups { get; set; }
|
||||||
|
= ImmutableArray<ImmutableArray<MaterialId>>.Empty;
|
||||||
|
|
||||||
public Item GetAvatarItem(AvatarId avatarId)
|
public Item GetAvatarItem(AvatarId avatarId)
|
||||||
{
|
{
|
||||||
return this.GetAvatar(avatarId).GetOrCreateItem();
|
return this.GetAvatar(avatarId).GetOrCreateItem();
|
||||||
|
|||||||
@@ -152,6 +152,10 @@ internal sealed partial class CultivationService : ICultivationService
|
|||||||
}
|
}
|
||||||
|
|
||||||
CultivationStatisticsSurplusMerge.Apply(resultItems, context, mergeOptions);
|
CultivationStatisticsSurplusMerge.Apply(resultItems, context, mergeOptions);
|
||||||
|
CultivationStatisticsWeeklyBossInterchange.Apply(
|
||||||
|
resultItems,
|
||||||
|
context.WeeklyBossMaterialInterchangeGroups,
|
||||||
|
mergeOptions.WeeklyBossMaterialInterchange);
|
||||||
ApplyStatisticsConsumerMenuLines(resultItems, projectId, context, cultivationRepository, token);
|
ApplyStatisticsConsumerMenuLines(resultItems, projectId, context, cultivationRepository, token);
|
||||||
|
|
||||||
return new(resultItems);
|
return new(resultItems);
|
||||||
|
|||||||
@@ -3,4 +3,7 @@
|
|||||||
|
|
||||||
namespace Snap.Hutao.Service.Cultivation;
|
namespace Snap.Hutao.Service.Cultivation;
|
||||||
|
|
||||||
internal readonly record struct CultivationStatisticsMergeOptions(bool MergeUpgradeMaterials, bool TalentSynthCritTenPercent);
|
internal readonly record struct CultivationStatisticsMergeOptions(
|
||||||
|
bool MergeUpgradeMaterials,
|
||||||
|
bool TalentSynthCritTenPercent,
|
||||||
|
bool WeeklyBossMaterialInterchange);
|
||||||
|
|||||||
+109
@@ -0,0 +1,109 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Model.Primitive;
|
||||||
|
using Snap.Hutao.ViewModel.Cultivation;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Immutable;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Service.Cultivation;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 材料统计:同一周本 Boss 材料池内,将超出需求的虚拟持有量 1:1 调配给池内缺口(不计异梦溶媒消耗)。
|
||||||
|
/// </summary>
|
||||||
|
internal static class CultivationStatisticsWeeklyBossInterchange
|
||||||
|
{
|
||||||
|
public static void Apply(
|
||||||
|
Dictionary<uint, StatisticsCultivateItem> items,
|
||||||
|
ImmutableArray<ImmutableArray<MaterialId>> interchangeGroups,
|
||||||
|
bool enabled)
|
||||||
|
{
|
||||||
|
if (!enabled || interchangeGroups.IsDefault || interchangeGroups.IsEmpty)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (ImmutableArray<MaterialId> group in interchangeGroups)
|
||||||
|
{
|
||||||
|
ApplySingleGroup(items, group);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ApplySingleGroup(Dictionary<uint, StatisticsCultivateItem> items, ImmutableArray<MaterialId> group)
|
||||||
|
{
|
||||||
|
List<uint> poolIds = [];
|
||||||
|
foreach (MaterialId mid in group)
|
||||||
|
{
|
||||||
|
uint id = mid;
|
||||||
|
if (items.ContainsKey(id))
|
||||||
|
{
|
||||||
|
poolIds.Add(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (poolIds.Count < 2)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Dictionary<uint, uint> virt = new(poolIds.Count);
|
||||||
|
foreach (uint id in poolIds)
|
||||||
|
{
|
||||||
|
StatisticsCultivateItem it = items[id];
|
||||||
|
virt[id] = it.MergeAdjustedCurrent ?? it.Current;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
uint? donor = null;
|
||||||
|
uint maxSurplus = 0U;
|
||||||
|
foreach (uint id in poolIds)
|
||||||
|
{
|
||||||
|
uint v = virt[id];
|
||||||
|
uint need = items[id].Count;
|
||||||
|
if (v > need && v - need > maxSurplus)
|
||||||
|
{
|
||||||
|
maxSurplus = v - need;
|
||||||
|
donor = id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint? receiver = null;
|
||||||
|
uint maxDeficit = 0U;
|
||||||
|
foreach (uint id in poolIds)
|
||||||
|
{
|
||||||
|
if (id == donor)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint v = virt[id];
|
||||||
|
uint need = items[id].Count;
|
||||||
|
if (v < need && need - v > maxDeficit)
|
||||||
|
{
|
||||||
|
maxDeficit = need - v;
|
||||||
|
receiver = id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (donor is null || receiver is null || maxSurplus is 0U || maxDeficit is 0U)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
virt[donor.Value]--;
|
||||||
|
virt[receiver.Value]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (uint id in poolIds)
|
||||||
|
{
|
||||||
|
StatisticsCultivateItem it = items[id];
|
||||||
|
uint baseline = it.MergeAdjustedCurrent ?? it.Current;
|
||||||
|
uint finalV = virt[id];
|
||||||
|
if (finalV != baseline)
|
||||||
|
{
|
||||||
|
it.WeeklyBossInterchangeAdjustedCurrent = finalV;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,7 +14,8 @@ internal interface ICultivationMetadataContext : IMetadataContext,
|
|||||||
IMetadataDictionaryIdMaterialSource,
|
IMetadataDictionaryIdMaterialSource,
|
||||||
IMetadataDictionaryIdAvatarSource,
|
IMetadataDictionaryIdAvatarSource,
|
||||||
IMetadataDictionaryIdWeaponSource,
|
IMetadataDictionaryIdWeaponSource,
|
||||||
IMetadataDictionaryResultMaterialIdCombineSource
|
IMetadataDictionaryResultMaterialIdCombineSource,
|
||||||
|
IMetadataWeeklyBossMaterialInterchangeGroupsSource
|
||||||
{
|
{
|
||||||
Item GetAvatarItem(AvatarId avatarId);
|
Item GetAvatarItem(AvatarId avatarId);
|
||||||
|
|
||||||
|
|||||||
+138
@@ -0,0 +1,138 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Model.Intrinsic;
|
||||||
|
using Snap.Hutao.Model.Metadata;
|
||||||
|
using Snap.Hutao.Model.Primitive;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Immutable;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Service.Cultivation;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 自 Combine 列表解析周本材料异梦转化互通组:配方为 Type=9、CONVERT、产物×1、材料为「异梦溶媒」+ 另一周本材料各×1。
|
||||||
|
/// </summary>
|
||||||
|
internal static class WeeklyBossMaterialInterchangeGroupsBuilder
|
||||||
|
{
|
||||||
|
/// <summary>异梦溶媒 Id(转化消耗,统计虚拟调配时不扣溶媒,仅利用池内 1:1 等价)。</summary>
|
||||||
|
private const uint DreamSolventMaterialId = 113021U;
|
||||||
|
|
||||||
|
public static ImmutableArray<ImmutableArray<MaterialId>> Build(ImmutableArray<Combine> combines)
|
||||||
|
{
|
||||||
|
Dictionary<MaterialId, HashSet<MaterialId>> adjacency = [];
|
||||||
|
|
||||||
|
foreach (Combine combine in combines)
|
||||||
|
{
|
||||||
|
if (combine.Type is not 9U)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (combine.RecipeType is not RecipeType.RECIPE_TYPE_CONVERT)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (combine.Materials.Length is not 2 || combine.Result.Count is not 1)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
MaterialId resultId = combine.Result.Id;
|
||||||
|
MaterialId? otherMaterial = null;
|
||||||
|
foreach (ref readonly IdCount m in combine.Materials.AsSpan())
|
||||||
|
{
|
||||||
|
if (m.Id == DreamSolventMaterialId)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m.Count is not 1)
|
||||||
|
{
|
||||||
|
otherMaterial = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
otherMaterial = m.Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (otherMaterial is null || otherMaterial.Value == resultId)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
AddUndirectedEdge(adjacency, resultId, otherMaterial.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ToComponents(adjacency);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AddUndirectedEdge(Dictionary<MaterialId, HashSet<MaterialId>> adjacency, MaterialId a, MaterialId b)
|
||||||
|
{
|
||||||
|
if (!adjacency.TryGetValue(a, out HashSet<MaterialId>? setA))
|
||||||
|
{
|
||||||
|
setA = [];
|
||||||
|
adjacency[a] = setA;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!adjacency.TryGetValue(b, out HashSet<MaterialId>? setB))
|
||||||
|
{
|
||||||
|
setB = [];
|
||||||
|
adjacency[b] = setB;
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = setA.Add(b);
|
||||||
|
_ = setB.Add(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ImmutableArray<ImmutableArray<MaterialId>> ToComponents(Dictionary<MaterialId, HashSet<MaterialId>> adjacency)
|
||||||
|
{
|
||||||
|
if (adjacency.Count is 0)
|
||||||
|
{
|
||||||
|
return ImmutableArray<ImmutableArray<MaterialId>>.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
HashSet<MaterialId> visited = [];
|
||||||
|
ImmutableArray<ImmutableArray<MaterialId>>.Builder groups = ImmutableArray.CreateBuilder<ImmutableArray<MaterialId>>();
|
||||||
|
|
||||||
|
foreach (MaterialId start in adjacency.Keys)
|
||||||
|
{
|
||||||
|
if (visited.Contains(start))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<MaterialId> component = [];
|
||||||
|
Queue<MaterialId> queue = new();
|
||||||
|
queue.Enqueue(start);
|
||||||
|
visited.Add(start);
|
||||||
|
|
||||||
|
while (queue.Count > 0)
|
||||||
|
{
|
||||||
|
MaterialId id = queue.Dequeue();
|
||||||
|
component.Add(id);
|
||||||
|
|
||||||
|
if (!adjacency.TryGetValue(id, out HashSet<MaterialId>? neighbors))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (MaterialId n in neighbors)
|
||||||
|
{
|
||||||
|
if (visited.Add(n))
|
||||||
|
{
|
||||||
|
queue.Enqueue(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (component.Count >= 2)
|
||||||
|
{
|
||||||
|
component.Sort(MaterialIdComparer.Shared);
|
||||||
|
groups.Add(component.ToImmutableArray());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return groups.ToImmutable();
|
||||||
|
}
|
||||||
|
}
|
||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Model.Primitive;
|
||||||
|
using System.Collections.Immutable;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Service.Metadata.ContextAbstraction;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 周本 Boss 掉落材料「异梦转化」互通组(由 Combine 元数据解析)。
|
||||||
|
/// </summary>
|
||||||
|
internal interface IMetadataWeeklyBossMaterialInterchangeGroupsSource : IMetadataContext
|
||||||
|
{
|
||||||
|
ImmutableArray<ImmutableArray<MaterialId>> WeeklyBossMaterialInterchangeGroups { get; set; }
|
||||||
|
}
|
||||||
+5
@@ -211,6 +211,11 @@ internal static class MetadataServiceContextExtension
|
|||||||
{
|
{
|
||||||
dictionaryResultMaterialIdCombineSource.ResultMaterialIdCombineMap = await metadataService.GetResultMaterialIdToCombineMapAsync(token).ConfigureAwait(false);
|
dictionaryResultMaterialIdCombineSource.ResultMaterialIdCombineMap = await metadataService.GetResultMaterialIdToCombineMapAsync(token).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (context is IMetadataWeeklyBossMaterialInterchangeGroupsSource weeklyBossInterchange)
|
||||||
|
{
|
||||||
|
weeklyBossInterchange.WeeklyBossMaterialInterchangeGroups = await metadataService.GetWeeklyBossMaterialInterchangeGroupsAsync(token).ConfigureAwait(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context is IMetadataSupportInitialization supportInitialization)
|
if (context is IMetadataSupportInitialization supportInitialization)
|
||||||
|
|||||||
+13
@@ -13,6 +13,7 @@ using Snap.Hutao.Model.Metadata.Reliquary;
|
|||||||
using Snap.Hutao.Model.Metadata.Tower;
|
using Snap.Hutao.Model.Metadata.Tower;
|
||||||
using Snap.Hutao.Model.Metadata.Weapon;
|
using Snap.Hutao.Model.Metadata.Weapon;
|
||||||
using Snap.Hutao.Model.Primitive;
|
using Snap.Hutao.Model.Primitive;
|
||||||
|
using Snap.Hutao.Service.Cultivation;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
|
|
||||||
namespace Snap.Hutao.Service.Metadata;
|
namespace Snap.Hutao.Service.Metadata;
|
||||||
@@ -229,6 +230,18 @@ internal static class MetadataServiceImmutableDictionaryExtension
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async ValueTask<ImmutableArray<ImmutableArray<MaterialId>>> GetWeeklyBossMaterialInterchangeGroupsAsync(CancellationToken token = default)
|
||||||
|
{
|
||||||
|
string cacheKey = $"{nameof(MetadataService)}.Cache.{MetadataFileStrategies.Combine.Name}.WeeklyBossMaterialInterchangeGroups";
|
||||||
|
ImmutableArray<ImmutableArray<MaterialId>>? result = await metadataService.MemoryCache.GetOrCreateAsync(cacheKey, async entry =>
|
||||||
|
{
|
||||||
|
ImmutableArray<Combine> array = await metadataService.FromCacheOrFileAsync<Combine>(MetadataFileStrategies.Combine, token).ConfigureAwait(false);
|
||||||
|
return WeeklyBossMaterialInterchangeGroupsBuilder.Build(array);
|
||||||
|
}).ConfigureAwait(false);
|
||||||
|
|
||||||
|
return result ?? ImmutableArray<ImmutableArray<MaterialId>>.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
private ValueTask<ImmutableDictionary<TKey, TValue>> FromCacheAsDictionaryAsync<TKey, TValue>(MetadataFileStrategy strategy, CancellationToken token)
|
private ValueTask<ImmutableDictionary<TKey, TValue>> FromCacheAsDictionaryAsync<TKey, TValue>(MetadataFileStrategy strategy, CancellationToken token)
|
||||||
where TKey : notnull
|
where TKey : notnull
|
||||||
where TValue : class, IDefaultIdentity<TKey>
|
where TValue : class, IDefaultIdentity<TKey>
|
||||||
|
|||||||
@@ -588,6 +588,12 @@
|
|||||||
IsEnabled="{Binding MergeUpgradeMaterials}"
|
IsEnabled="{Binding MergeUpgradeMaterials}"
|
||||||
Label="{shuxm:ResourceString Name=ViewPageCultivationTalentSynthCritTenPercentLabel}"
|
Label="{shuxm:ResourceString Name=ViewPageCultivationTalentSynthCritTenPercentLabel}"
|
||||||
Visibility="{Binding ElementName=MaterialListPivot, Path=SelectedItem.Tag, Converter={StaticResource MaterialListSelectedItemIsStatisticsViewConverter}}"/>
|
Visibility="{Binding ElementName=MaterialListPivot, Path=SelectedItem.Tag, Converter={StaticResource MaterialListSelectedItemIsStatisticsViewConverter}}"/>
|
||||||
|
<AppBarToggleButton
|
||||||
|
Command="{Binding RefreshStatisticsItemsCommand}"
|
||||||
|
Icon="{shuxm:FontIcon Glyph=}"
|
||||||
|
IsChecked="{Binding WeeklyBossMaterialInterchange, Mode=TwoWay}"
|
||||||
|
Label="{shuxm:ResourceString Name=ViewPageCultivationWeeklyBossMaterialInterchangeLabel}"
|
||||||
|
Visibility="{Binding ElementName=MaterialListPivot, Path=SelectedItem.Tag, Converter={StaticResource MaterialListSelectedItemIsStatisticsViewConverter}}"/>
|
||||||
<AppBarButton Icon="{shuxm:FontIcon Glyph=}" Label="{shuxm:ResourceString Name=ViewPageCultivationMaterialListResinStatisticsLabel}">
|
<AppBarButton Icon="{shuxm:FontIcon Glyph=}" Label="{shuxm:ResourceString Name=ViewPageCultivationMaterialListResinStatisticsLabel}">
|
||||||
<AppBarButton.Flyout>
|
<AppBarButton.Flyout>
|
||||||
<Flyout FlyoutPresenterStyle="{ThemeResource FlyoutPresenterPadding0Style}" Placement="BottomEdgeAlignedRight">
|
<Flyout FlyoutPresenterStyle="{ThemeResource FlyoutPresenterPadding0Style}" Placement="BottomEdgeAlignedRight">
|
||||||
|
|||||||
@@ -77,6 +77,9 @@ internal sealed partial class CultivationViewModel : Abstraction.ViewModel
|
|||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
public partial bool TalentSynthCritTenPercent { get; set; } = LocalSetting.Get(SettingKeys.CultivationStatisticsTalentSynthCritTenPercent, false);
|
public partial bool TalentSynthCritTenPercent { get; set; } = LocalSetting.Get(SettingKeys.CultivationStatisticsTalentSynthCritTenPercent, false);
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
public partial bool WeeklyBossMaterialInterchange { get; set; } = LocalSetting.Get(SettingKeys.CultivationStatisticsWeeklyBossMaterialInterchange, false);
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
public partial ObservableCollection<StatisticsCultivateItem>? StatisticsItems { get; set; }
|
public partial ObservableCollection<StatisticsCultivateItem>? StatisticsItems { get; set; }
|
||||||
|
|
||||||
@@ -365,8 +368,10 @@ internal sealed partial class CultivationViewModel : Abstraction.ViewModel
|
|||||||
|
|
||||||
bool merge = MergeUpgradeMaterials;
|
bool merge = MergeUpgradeMaterials;
|
||||||
bool talentCrit = merge && TalentSynthCritTenPercent;
|
bool talentCrit = merge && TalentSynthCritTenPercent;
|
||||||
|
bool weeklyBoss = WeeklyBossMaterialInterchange;
|
||||||
LocalSetting.Set(SettingKeys.CultivationStatisticsMergeUpgradeMaterials, merge);
|
LocalSetting.Set(SettingKeys.CultivationStatisticsMergeUpgradeMaterials, merge);
|
||||||
LocalSetting.Set(SettingKeys.CultivationStatisticsTalentSynthCritTenPercent, talentCrit);
|
LocalSetting.Set(SettingKeys.CultivationStatisticsTalentSynthCritTenPercent, talentCrit);
|
||||||
|
LocalSetting.Set(SettingKeys.CultivationStatisticsWeeklyBossMaterialInterchange, weeklyBoss);
|
||||||
|
|
||||||
CancellationToken token = exclusiveTokenProvider.GetNewToken();
|
CancellationToken token = exclusiveTokenProvider.GetNewToken();
|
||||||
StatisticsCultivateItemCollection statistics;
|
StatisticsCultivateItemCollection statistics;
|
||||||
@@ -374,7 +379,7 @@ internal sealed partial class CultivationViewModel : Abstraction.ViewModel
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
statistics = await cultivationService
|
statistics = await cultivationService
|
||||||
.GetStatisticsCultivateItemCollectionAsync(Projects.CurrentItem, metadataContext, new CultivationStatisticsMergeOptions(merge, talentCrit), token)
|
.GetStatisticsCultivateItemCollectionAsync(Projects.CurrentItem, metadataContext, new CultivationStatisticsMergeOptions(merge, talentCrit, weeklyBoss), token)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
resinStatistics = await cultivationService.GetResinStatisticsAsync(statistics, token).ConfigureAwait(false);
|
resinStatistics = await cultivationService.GetResinStatisticsAsync(statistics, token).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,26 +35,33 @@ internal sealed class StatisticsCultivateItem
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public uint? MergeAdjustedCurrent { get; set; }
|
public uint? MergeAdjustedCurrent { get; set; }
|
||||||
|
|
||||||
public uint DisplayCurrent { get => MergeAdjustedCurrent ?? Current; }
|
/// <summary>
|
||||||
|
/// 周本材料异梦转化池内调配后的展示用持有量;未启用时为 <see langword="null"/>。在 <see cref="MergeAdjustedCurrent"/> 之后应用。
|
||||||
|
/// </summary>
|
||||||
|
public uint? WeeklyBossInterchangeAdjustedCurrent { get; set; }
|
||||||
|
|
||||||
|
public uint DisplayCurrent { get => WeeklyBossInterchangeAdjustedCurrent ?? MergeAdjustedCurrent ?? Current; }
|
||||||
|
|
||||||
public bool IsFinished { get => DisplayCurrent >= Count; }
|
public bool IsFinished { get => DisplayCurrent >= Count; }
|
||||||
|
|
||||||
public string FormattedCount { get => $"{DisplayCurrent}/{Count}"; }
|
public string FormattedCount { get => $"{DisplayCurrent}/{Count}"; }
|
||||||
|
|
||||||
|
private bool HasStatisticsAdjustedDisplay { get => MergeAdjustedCurrent.HasValue || WeeklyBossInterchangeAdjustedCurrent.HasValue; }
|
||||||
|
|
||||||
/// <summary>未启用合并展示链时,使用紧凑 <see cref="FormattedCount"/>。</summary>
|
/// <summary>未启用合并展示链时,使用紧凑 <see cref="FormattedCount"/>。</summary>
|
||||||
public bool ShowNonMergeCompactCount { get => !MergeAdjustedCurrent.HasValue; }
|
public bool ShowNonMergeCompactCount { get => !HasStatisticsAdjustedDisplay; }
|
||||||
|
|
||||||
/// <summary>已合并但合成前后有效持有量与背包数一致,不显示括号,仅「合并后 / 需求」加空格。</summary>
|
/// <summary>已合并但合成前后有效持有量与背包数一致,不显示括号,仅「合并后 / 需求」加空格。</summary>
|
||||||
public bool ShowMergeSpacedWithoutParen { get => MergeAdjustedCurrent.HasValue && DisplayCurrent == Current; }
|
public bool ShowMergeSpacedWithoutParen { get => HasStatisticsAdjustedDisplay && DisplayCurrent == Current; }
|
||||||
|
|
||||||
/// <summary>合并后有效持有与背包原数不同,显示「合并后 (背包原数)」。</summary>
|
/// <summary>合并后有效持有与背包原数不同,显示「合并后 (背包原数)」。</summary>
|
||||||
public bool ShowMergeInventoryParen { get => MergeAdjustedCurrent.HasValue && DisplayCurrent != Current; }
|
public bool ShowMergeInventoryParen { get => HasStatisticsAdjustedDisplay && DisplayCurrent != Current; }
|
||||||
|
|
||||||
/// <summary>首位合并显示量 > 背包原数时着红色(相对原库存变多)。</summary>
|
/// <summary>首位合并显示量 > 背包原数时着红色(相对原库存变多)。</summary>
|
||||||
public bool MergeDisplayLeadUseRed { get => MergeAdjustedCurrent.HasValue && DisplayCurrent > Current; }
|
public bool MergeDisplayLeadUseRed { get => HasStatisticsAdjustedDisplay && DisplayCurrent > Current; }
|
||||||
|
|
||||||
/// <summary>首位合并显示量 < 背包原数时着绿色(相对原库存变少,如低档被向上消耗)。</summary>
|
/// <summary>首位合并显示量 < 背包原数时着绿色(相对原库存变少,如低档被向上消耗)。</summary>
|
||||||
public bool MergeDisplayLeadUseGreen { get => MergeAdjustedCurrent.HasValue && DisplayCurrent < Current; }
|
public bool MergeDisplayLeadUseGreen { get => HasStatisticsAdjustedDisplay && DisplayCurrent < Current; }
|
||||||
|
|
||||||
/// <summary>背包原数,紧接在合并后数字后,如 <c>(44)</c>。</summary>
|
/// <summary>背包原数,紧接在合并后数字后,如 <c>(44)</c>。</summary>
|
||||||
public string RawInventoryParenthetical { get => $"({Current})"; }
|
public string RawInventoryParenthetical { get => $"({Current})"; }
|
||||||
|
|||||||
Reference in New Issue
Block a user