diff --git a/NineChronicles.DataProvider/DataRendering/Crafting/UnlockCombinationSlotData.cs b/NineChronicles.DataProvider/DataRendering/Crafting/UnlockCombinationSlotData.cs new file mode 100644 index 00000000..b622e84c --- /dev/null +++ b/NineChronicles.DataProvider/DataRendering/Crafting/UnlockCombinationSlotData.cs @@ -0,0 +1,52 @@ +namespace NineChronicles.DataProvider.DataRendering.Crafting +{ + using System; + using System.Collections.Generic; + using Libplanet.Action.State; + using Libplanet.Crypto; + using Nekoyume.Action; + using Nekoyume.Module; + using Nekoyume.TableData; + using NineChronicles.DataProvider.Store.Models.Crafting; + + public static class UnlockCombinationSlotData + { + private const int GoldenDustId = 600201; + private const int RubyDustId = 600202; + + public static UnlockCombinationSlotModel GetUnlockCombinationSlotInfo( + IWorld prevStates, + Address signer, + UnlockCombinationSlot action, + long blockIndex, + DateTimeOffset blockTime + ) + { + var cost = prevStates.GetSheet()[action.SlotIndex]; + var materialCost = new List(); + if (cost.GoldenDustPrice > 0) + { + materialCost.Add($"{GoldenDustId}:{cost.GoldenDustPrice}"); + } + + if (cost.RubyDustPrice > 0) + { + materialCost.Add($"{RubyDustId}:{cost.RubyDustPrice}"); + } + + return new UnlockCombinationSlotModel + { + Id = Guid.NewGuid().ToString(), + AgentAddress = signer.ToString(), + AvatarAddress = action.AvatarAddress.ToString(), + SlotIndex = action.SlotIndex, + NcgCost = (decimal)cost.NcgPrice, + CrystalCost = cost.CrystalPrice, + MaterialCosts = string.Join(",", materialCost), + BlockIndex = blockIndex, + Date = DateOnly.FromDateTime(blockTime.DateTime), + TimeStamp = blockTime, + }; + } + } +} diff --git a/NineChronicles.DataProvider/RenderSubscriber.cs b/NineChronicles.DataProvider/RenderSubscriber.cs index c522f93f..604b43f4 100644 --- a/NineChronicles.DataProvider/RenderSubscriber.cs +++ b/NineChronicles.DataProvider/RenderSubscriber.cs @@ -1658,6 +1658,7 @@ protected override Task ExecuteAsync(CancellationToken stoppingToken) // Crafting _actionRenderer.EveryRender().Subscribe(SubscribeRapidCombination); _actionRenderer.EveryRender().Subscribe(SubscribeCustomEquipmentCraft); + _actionRenderer.EveryRender().Subscribe(SubscribeUnlockCombinationSlot); // Grinding _actionRenderer.EveryRender().Subscribe(SubscribeGrinding); @@ -1685,6 +1686,8 @@ protected override Task ExecuteAsync(CancellationToken stoppingToken) partial void SubscribeCustomEquipmentCraft(ActionEvaluation evt); + partial void SubscribeUnlockCombinationSlot(ActionEvaluation evt); + //// Grinding partial void SubscribeGrinding(ActionEvaluation ev); /* Partial Methods */ diff --git a/NineChronicles.DataProvider/Store/MySql/CraftingStore.cs b/NineChronicles.DataProvider/Store/MySql/CraftingStore.cs index a6034e92..8d467f3f 100644 --- a/NineChronicles.DataProvider/Store/MySql/CraftingStore.cs +++ b/NineChronicles.DataProvider/Store/MySql/CraftingStore.cs @@ -124,5 +124,40 @@ public partial List GetCustomEquipmentCraftCount ? ctx.CustomEquipmentCraftCount.ToList() : ctx.CustomEquipmentCraftCount.Where(c => c.ItemSubType == itemSubType).ToList(); } + + // UnlockCombinationSlot + public async partial Task StoreUnlockCombinationSlotList( + List unlockCombinationSlotList + ) + { + NineChroniclesContext? ctx = null; + try + { + ctx = await _dbContextFactory.CreateDbContextAsync(); + + foreach (var ucs in unlockCombinationSlotList) + { + if (!await ctx.UnlockCombinationSlot.AnyAsync(u => u.Id == ucs.Id)) + { + await ctx.UnlockCombinationSlot.AddAsync(ucs); + } + } + + await ctx.SaveChangesAsync(); + Log.Debug($"[UnlockCombinationSlot] {unlockCombinationSlotList.Count} UnlockCombinationSlot saved."); + } + catch (Exception e) + { + Log.Debug(e.Message); + Log.Debug(e.StackTrace); + } + finally + { + if (ctx is not null) + { + await ctx.DisposeAsync(); + } + } + } } } diff --git a/NineChronicles.DataProvider/Store/MySqlStore.cs b/NineChronicles.DataProvider/Store/MySqlStore.cs index 99d82f7c..cf097187 100644 --- a/NineChronicles.DataProvider/Store/MySqlStore.cs +++ b/NineChronicles.DataProvider/Store/MySqlStore.cs @@ -1898,6 +1898,8 @@ public void StoreRuneSummonFailList(List runeSummonFailList public partial Task StoreGrindList(List grindingList); + public partial Task StoreUnlockCombinationSlotList(List unlockCombinationSlotList); + public List GetRaiderList() { using NineChroniclesContext ctx = _dbContextFactory.CreateDbContext(); diff --git a/NineChronicles.DataProvider/Subscriber/CraftingRenderSubscriber.cs b/NineChronicles.DataProvider/Subscriber/CraftingRenderSubscriber.cs index 95407c54..674aa150 100644 --- a/NineChronicles.DataProvider/Subscriber/CraftingRenderSubscriber.cs +++ b/NineChronicles.DataProvider/Subscriber/CraftingRenderSubscriber.cs @@ -18,6 +18,7 @@ public partial class RenderSubscriber { private List _rapidCombinationList = new (); private List _customEquipmentCraftList = new (); + private List _unlockCombinationSlotList = new (); // Store private void StoreCraftingData() @@ -42,6 +43,14 @@ private void StoreCraftingData() await MySqlStore.StoreCustomEquipmentCraftList(_customEquipmentCraftList); })); + // UnlockCombinationSlot + Log.Debug("[Crafting] Store UnlockCombinationSlot list"); + tasks.Add(Task.Run(async () => + { + Log.Debug($"[UnlockCombinationSlot] {_unlockCombinationSlotList.Count}"); + await MySqlStore.StoreUnlockCombinationSlotList(_unlockCombinationSlotList); + })); + Task.WaitAll(tasks.ToArray()); } catch (Exception e) @@ -56,6 +65,7 @@ private void ClearCraftingList() Log.Debug("[Crafting] Clear crafting related action data"); _rapidCombinationList.Clear(); _customEquipmentCraftList.Clear(); + _unlockCombinationSlotList.Clear(); } // Subscribe @@ -159,5 +169,38 @@ partial void SubscribeCustomEquipmentCraft(ActionEvaluation evt) + { + try + { + if (evt.Exception is null && evt.Action is { } unlockCombinationSlot) + { + var start = DateTimeOffset.UtcNow; + _unlockCombinationSlotList.Add(UnlockCombinationSlotData.GetUnlockCombinationSlotInfo( + new World(_blockChainStates.GetWorldState(evt.PreviousState)), + evt.Signer, + evt.Action, + evt.BlockIndex, + _blockTimeOffset + )); + + Log.Debug( + "[DataProvider] Stored RapidCombination action in block #{index}. Time Taken: {time} ms.", + evt.BlockIndex, + (DateTimeOffset.UtcNow - start).Milliseconds + ); + } + } + catch (Exception e) + { + Log.Error( + e, + "[DataProvider] RenderSubscriber Error: {ErrorMessage}, StackTrace: {StackTrace}", + e.Message, + e.StackTrace + ); + } + } } }