From 5f4b68d5382375647fa39c7a9a4d65b384b1f8a7 Mon Sep 17 00:00:00 2001 From: qhy040404 Date: Tue, 11 Jun 2024 12:55:54 +0800 Subject: [PATCH] add cache to minimal deltas --- .../Service/Inventory/InventoryService.cs | 112 +----------------- .../Inventory/MinimalPromotionDelta.cs | 83 ++++++++++++- 2 files changed, 84 insertions(+), 111 deletions(-) diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Inventory/InventoryService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Inventory/InventoryService.cs index 5452b29a..9dea0796 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Inventory/InventoryService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Inventory/InventoryService.cs @@ -1,13 +1,9 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. -using Snap.Hutao.Core.ExceptionService; using Snap.Hutao.Model.Entity; -using Snap.Hutao.Model.Metadata.Abstraction; using Snap.Hutao.Model.Metadata.Item; -using Snap.Hutao.Model.Primitive; using Snap.Hutao.Service.Cultivation; -using Snap.Hutao.Service.Metadata; using Snap.Hutao.Service.Metadata.ContextAbstraction; using Snap.Hutao.Service.Notification; using Snap.Hutao.Service.User; @@ -15,9 +11,6 @@ using Snap.Hutao.ViewModel.Cultivation; using Snap.Hutao.ViewModel.User; using Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate; using Snap.Hutao.Web.Response; -using System.Runtime.InteropServices; -using MetadataAvatar = Snap.Hutao.Model.Metadata.Avatar.Avatar; -using MetadataWeapon = Snap.Hutao.Model.Metadata.Weapon.Weapon; namespace Snap.Hutao.Service.Inventory; @@ -25,9 +18,9 @@ namespace Snap.Hutao.Service.Inventory; [Injection(InjectAs.Singleton, typeof(IInventoryService))] internal sealed partial class InventoryService : IInventoryService { + private readonly MinimalPromotionDelta minimalPromotionDelta; private readonly IServiceScopeFactory serviceScopeFactory; private readonly IInventoryDbService inventoryDbService; - private readonly IMetadataService metadataService; private readonly IInfoBarService infoBarService; private readonly IUserService userService; @@ -56,13 +49,7 @@ internal sealed partial class InventoryService : IInventoryService /// public async ValueTask RefreshInventoryAsync(CultivateProject project) { - List cultivationItemsEntryList = - [ - .. await metadataService.GetAvatarListAsync().ConfigureAwait(false), - .. await metadataService.GetWeaponListAsync().ConfigureAwait(false), - ]; - - cultivationItemsEntryList = MinimalPromotionDelta.Find(cultivationItemsEntryList); + List deltas = await minimalPromotionDelta.GetAsync().ConfigureAwait(false); BatchConsumption? batchConsumption = default; using (IServiceScope scope = serviceScopeFactory.CreateScope()) @@ -76,7 +63,7 @@ internal sealed partial class InventoryService : IInventoryService CalculateClient calculateClient = scope.ServiceProvider.GetRequiredService(); Response? resp = await calculateClient - .BatchComputeAsync(userAndUid, GeneratePromotionDeltas(cultivationItemsEntryList), true) + .BatchComputeAsync(userAndUid, deltas, true) .ConfigureAwait(false); if (!resp.IsOk()) @@ -93,97 +80,4 @@ internal sealed partial class InventoryService : IInventoryService await inventoryDbService.AddInventoryItemRangeByProjectIdAsync(items.SelectList(item => InventoryItem.From(project.InnerId, item.Id, (uint)((int)item.Num - item.LackNum)))).ConfigureAwait(false); } } - - private static List GeneratePromotionDeltas(List cultivatables) - { - List avatars = []; - List weapons = []; - HashSet materialIds = []; - - while (cultivatables.Count > 0) - { - ICultivationItemsAccess bestItem = cultivatables.OrderByDescending(item => item.CultivationItems.Count(material => !materialIds.Contains(material))).First(); - - if (bestItem.CultivationItems.All(materialIds.Contains)) - { - break; - } - - switch (bestItem) - { - case MetadataAvatar avatar: - avatars.Add(avatar); - break; - case MetadataWeapon weapon: - weapons.Add(weapon); - break; - default: - throw HutaoException.NotSupported(); - } - - foreach (ref readonly MaterialId materialId in CollectionsMarshal.AsSpan(bestItem.CultivationItems)) - { - materialIds.Add(materialId); - } - - cultivatables.Remove(bestItem); - } - - List deltas = []; - - for (int i = 0; i < Math.Max(avatars.Count, weapons.Count); i++) - { - MetadataAvatar? avatar = avatars.ElementAtOrDefault(i); - MetadataWeapon? weapon = weapons.ElementAtOrDefault(i); - - if (avatar is not null) - { - AvatarPromotionDelta delta = new() - { - AvatarId = avatar.Id, - AvatarLevelCurrent = 1, - AvatarLevelTarget = 90, - SkillList = avatar.SkillDepot.CompositeSkillsNoInherents().SelectList(skill => new PromotionDelta() - { - Id = skill.GroupId, - LevelCurrent = 1, - LevelTarget = 10, - }), - }; - - if (weapon is not null) - { - delta.Weapon = new() - { - Id = weapon.Id, - LevelCurrent = 1, - LevelTarget = 90, - }; - } - - deltas.Add(delta); - - continue; - } - - if (weapon is not null) - { - AvatarPromotionDelta delta = new() - { - Weapon = new() - { - Id = weapon.Id, - LevelCurrent = 1, - LevelTarget = 90, - }, - }; - - deltas.Add(delta); - - continue; - } - } - - return deltas; - } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Inventory/MinimalPromotionDelta.cs b/src/Snap.Hutao/Snap.Hutao/Service/Inventory/MinimalPromotionDelta.cs index 7ea09766..91b3ee84 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Inventory/MinimalPromotionDelta.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Inventory/MinimalPromotionDelta.cs @@ -2,16 +2,43 @@ // Licensed under the MIT license. using Google.OrTools.LinearSolver; +using Microsoft.Extensions.Caching.Memory; using Snap.Hutao.Core.ExceptionService; using Snap.Hutao.Model.Metadata.Abstraction; using Snap.Hutao.Model.Primitive; +using Snap.Hutao.Service.Metadata; +using Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate; using System.Runtime.InteropServices; +using MetadataAvatar = Snap.Hutao.Model.Metadata.Avatar.Avatar; +using MetadataWeapon = Snap.Hutao.Model.Metadata.Weapon.Weapon; namespace Snap.Hutao.Service.Inventory; -internal static class MinimalPromotionDelta +[ConstructorGenerated] +[Injection(InjectAs.Singleton)] +internal sealed partial class MinimalPromotionDelta { - public static List Find(List cultivationItems) + private const string CacheKey = $"{nameof(MinimalPromotionDelta)}.Cache"; + + private readonly IMetadataService metadataService; + private readonly IMemoryCache memoryCache; + + public async ValueTask> GetAsync() + { + if (memoryCache.TryGetRequiredValue(CacheKey, out List? cache)) + { + return cache; + } + + List cultivationItemsEntryList = + [ + .. await metadataService.GetAvatarListAsync().ConfigureAwait(false), + .. (await metadataService.GetWeaponListAsync().ConfigureAwait(false)).Where(w => w.Quality >= Model.Intrinsic.QualityType.QUALITY_BLUE), + ]; + return memoryCache.Set(CacheKey, GeneratePromotionDeltas(Minimize(cultivationItemsEntryList))); + } + + private static List Minimize(List cultivationItems) { using (Solver? solver = Solver.CreateSolver("SCIP")) { @@ -54,4 +81,56 @@ internal static class MinimalPromotionDelta return results; } } + + private static List GeneratePromotionDeltas(List cultivationItems) + { + List deltas = []; + + foreach (ref readonly ICultivationItemsAccess item in CollectionsMarshal.AsSpan(cultivationItems)) + { + switch (item) + { + case MetadataAvatar avatar: + deltas.Add(new() + { + AvatarId = avatar.Id, + AvatarLevelCurrent = 1, + AvatarLevelTarget = 90, + SkillList = avatar.SkillDepot.CompositeSkillsNoInherents().SelectList(skill => new PromotionDelta() + { + Id = skill.GroupId, + LevelCurrent = 1, + LevelTarget = 10, + }), + }); + break; + case MetadataWeapon weapon: + if (deltas.FirstOrDefault(d => d.Weapon is null) is { } delta) + { + delta.Weapon = new() + { + Id = weapon.Id, + LevelCurrent = 1, + LevelTarget = 90, + }; + + break; + } + + deltas.Add(new() + { + Weapon = new() + { + Id = weapon.Id, + LevelCurrent = 1, + LevelTarget = 90, + }, + }); + + break; + } + } + + return deltas; + } } \ No newline at end of file