mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
add cache to minimal deltas
This commit is contained in:
@@ -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
|
||||
/// <inheritdoc/>
|
||||
public async ValueTask RefreshInventoryAsync(CultivateProject project)
|
||||
{
|
||||
List<ICultivationItemsAccess> cultivationItemsEntryList =
|
||||
[
|
||||
.. await metadataService.GetAvatarListAsync().ConfigureAwait(false),
|
||||
.. await metadataService.GetWeaponListAsync().ConfigureAwait(false),
|
||||
];
|
||||
|
||||
cultivationItemsEntryList = MinimalPromotionDelta.Find(cultivationItemsEntryList);
|
||||
List<AvatarPromotionDelta> 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<CalculateClient>();
|
||||
|
||||
Response<BatchConsumption>? 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<AvatarPromotionDelta> GeneratePromotionDeltas(List<ICultivationItemsAccess> cultivatables)
|
||||
{
|
||||
List<MetadataAvatar> avatars = [];
|
||||
List<MetadataWeapon> weapons = [];
|
||||
HashSet<MaterialId> 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<AvatarPromotionDelta> 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;
|
||||
}
|
||||
}
|
||||
@@ -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<ICultivationItemsAccess> Find(List<ICultivationItemsAccess> cultivationItems)
|
||||
private const string CacheKey = $"{nameof(MinimalPromotionDelta)}.Cache";
|
||||
|
||||
private readonly IMetadataService metadataService;
|
||||
private readonly IMemoryCache memoryCache;
|
||||
|
||||
public async ValueTask<List<AvatarPromotionDelta>> GetAsync()
|
||||
{
|
||||
if (memoryCache.TryGetRequiredValue(CacheKey, out List<AvatarPromotionDelta>? cache))
|
||||
{
|
||||
return cache;
|
||||
}
|
||||
|
||||
List<ICultivationItemsAccess> 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<ICultivationItemsAccess> Minimize(List<ICultivationItemsAccess> cultivationItems)
|
||||
{
|
||||
using (Solver? solver = Solver.CreateSolver("SCIP"))
|
||||
{
|
||||
@@ -54,4 +81,56 @@ internal static class MinimalPromotionDelta
|
||||
return results;
|
||||
}
|
||||
}
|
||||
|
||||
private static List<AvatarPromotionDelta> GeneratePromotionDeltas(List<ICultivationItemsAccess> cultivationItems)
|
||||
{
|
||||
List<AvatarPromotionDelta> 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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user