From e8fcab4c6b5571119f11ebdbf6c56da24298cb06 Mon Sep 17 00:00:00 2001 From: chenchun Date: Tue, 15 Oct 2024 18:32:50 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E7=9F=BF=E6=B1=A0?= =?UTF-8?q?=E6=9C=BA=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Services/CollectiblesService.cs | 27 +++- .../Services/MarketService.cs | 23 ++- .../Attributes/ProbabilityAttribute.cs | 16 ++ .../Consts/CacheConst.cs | 9 ++ .../Consts/RarityEnum.cs | 53 ++++++- .../Dtos/MiningPoolContent.cs | 50 +++++++ ...k.DigitalCollectibles.Domain.Shared.csproj | 1 - .../CollectiblesUserStoreAggregateRoot.cs | 5 + .../Managers/MiningPoolManager.cs | 138 +++++++++++++++++- ...ramework.DigitalCollectibles.Domain.csproj | 1 + ...rameworkDigitalCollectiblesDomainModule.cs | 2 + ...rk.DigitalCollectibles.SqlSugarCore.csproj | 1 + ...rkDigitalCollectiblesSqlSugarCoreModule.cs | 7 +- 13 files changed, 313 insertions(+), 20 deletions(-) create mode 100644 Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain.Shared/Attributes/ProbabilityAttribute.cs create mode 100644 Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain.Shared/Consts/CacheConst.cs create mode 100644 Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain.Shared/Dtos/MiningPoolContent.cs diff --git a/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Application/Services/CollectiblesService.cs b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Application/Services/CollectiblesService.cs index e68bed84..8e8ce010 100644 --- a/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Application/Services/CollectiblesService.cs +++ b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Application/Services/CollectiblesService.cs @@ -1,17 +1,28 @@ -using Microsoft.AspNetCore.Authorization; +using Mapster; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using SqlSugar; using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Services; using Yi.Framework.DigitalCollectibles.Application.Contracts.Dtos.Collectibles; using Yi.Framework.DigitalCollectibles.Application.Contracts.Dtos.Market; +using Yi.Framework.DigitalCollectibles.Domain.Entities; +using Yi.Framework.SqlSugarCore.Abstractions; namespace Yi.Framework.DigitalCollectibles.Application.Services; /// /// 藏品应用服务 /// -public class CollectiblesService:ApplicationService +public class CollectiblesService : ApplicationService { + private readonly ISqlSugarRepository _collectiblesUserStoreRepository; + + public CollectiblesService(ISqlSugarRepository collectiblesUserStoreRepository) + { + _collectiblesUserStoreRepository = collectiblesUserStoreRepository; + } + /// /// 获取当前用户的藏品 /// @@ -20,8 +31,16 @@ public class CollectiblesService:ApplicationService /// [HttpGet("user")] [Authorize] - public async Task> GetForAccountUserAsync(CollectiblesUserGetInput input) + public async Task> GetForAccountUserAsync( + CollectiblesUserGetInput input) { - throw new NotImplementedException(); + RefAsync total = 0; + var entities = await _collectiblesUserStoreRepository._DbQueryable.WhereIF( + input.StartTime is not null && input.EndTime is not null, + x => x.CreationTime >= input.StartTime && x.CreationTime <= input.EndTime) + .OrderByDescending(x => x.CreationTime) + .ToPageListAsync(input.SkipCount, input.MaxResultCount, total); + var output = entities.Adapt>(); + return new PagedResultDto(total, output); } } \ No newline at end of file diff --git a/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Application/Services/MarketService.cs b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Application/Services/MarketService.cs index a16c4da6..f5222f45 100644 --- a/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Application/Services/MarketService.cs +++ b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Application/Services/MarketService.cs @@ -1,6 +1,10 @@ -using Volo.Abp.Application.Dtos; +using Mapster; +using SqlSugar; +using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Services; using Yi.Framework.DigitalCollectibles.Application.Contracts.Dtos.Market; +using Yi.Framework.DigitalCollectibles.Domain.Entities; +using Yi.Framework.SqlSugarCore.Abstractions; namespace Yi.Framework.DigitalCollectibles.Application.Services; @@ -9,14 +13,27 @@ namespace Yi.Framework.DigitalCollectibles.Application.Services; /// public class MarketService:ApplicationService { + private readonly ISqlSugarRepository _marketGoodsRepository; + + public MarketService(ISqlSugarRepository marketGoodsRepository) + { + _marketGoodsRepository = marketGoodsRepository; + } + /// /// 交易市场查询 /// /// /// - /// public async Task> GetListAsync(MarketGetListInput input) { - throw new NotImplementedException(); + RefAsync total = 0; + var entities = await _marketGoodsRepository._DbQueryable.WhereIF( + input.StartTime is not null && input.EndTime is not null, + x => x.CreationTime >= input.StartTime && x.CreationTime <= input.EndTime) + .OrderByDescending(x => x.CreationTime) + .ToPageListAsync(input.SkipCount, input.MaxResultCount, total); + var output = entities.Adapt>(); + return new PagedResultDto(total, output); } } \ No newline at end of file diff --git a/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain.Shared/Attributes/ProbabilityAttribute.cs b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain.Shared/Attributes/ProbabilityAttribute.cs new file mode 100644 index 00000000..6dee35df --- /dev/null +++ b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain.Shared/Attributes/ProbabilityAttribute.cs @@ -0,0 +1,16 @@ +using System.ComponentModel.DataAnnotations; +using System.Reflection; +using Yi.Framework.DigitalCollectibles.Domain.Shared.Consts; + +namespace Yi.Framework.DigitalCollectibles.Domain.Shared.Attributes; + +public class ProbabilityAttribute : Attribute +{ + public double Value { get; set; } + + public ProbabilityAttribute(double value) + { + this.Value = value; + } +} + diff --git a/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain.Shared/Consts/CacheConst.cs b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain.Shared/Consts/CacheConst.cs new file mode 100644 index 00000000..015111e3 --- /dev/null +++ b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain.Shared/Consts/CacheConst.cs @@ -0,0 +1,9 @@ +namespace Yi.Framework.DigitalCollectibles.Domain.Shared.Consts; + +public class CacheConst +{ + /// + /// 矿池 + /// + public const string MiningPoolContent = "MiningPool"; +} \ No newline at end of file diff --git a/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain.Shared/Consts/RarityEnum.cs b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain.Shared/Consts/RarityEnum.cs index a1cc1156..453aa212 100644 --- a/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain.Shared/Consts/RarityEnum.cs +++ b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain.Shared/Consts/RarityEnum.cs @@ -1,4 +1,6 @@ using System.ComponentModel.DataAnnotations; +using System.Reflection; +using Yi.Framework.DigitalCollectibles.Domain.Shared.Attributes; namespace Yi.Framework.DigitalCollectibles.Domain.Shared.Consts; @@ -7,9 +9,50 @@ namespace Yi.Framework.DigitalCollectibles.Domain.Shared.Consts; /// public enum RarityEnum { - [Display(Name = "普通")] Ordinary = 0, - [Display(Name = "高级")] Senior = 1, - [Display(Name = "稀有")] Rare = 2, - [Display(Name = "珍品")] Gem = 3, - [Display(Name = "传说")] Legend = 4 + [Display(Name = "普通")][Probability(0.8f)] Ordinary = 0, + [Display(Name = "高级")][Probability(0.1f)] Senior = 1, + [Display(Name = "稀有")][Probability(0.06f)] Rare = 2, + [Display(Name = "珍品")][Probability(0.039f)] Gem = 3, + [Display(Name = "传说")][Probability(0.001f)] Legend = 4 +} + +public static class RarityEnumExtensions +{ + private static T GetAttribute(RarityEnum rarity) where T : Attribute + { + var fieldInfo = typeof(RarityEnum).GetField(rarity.ToString()); + var attribute = fieldInfo.GetCustomAttribute(); + return attribute!; + } + + public static decimal GetProbabilityValue(this RarityEnum rarity) + { + var attribute = GetAttribute(rarity); + return attribute.Value.To(); + } + + public static string GetDisplayValue(this RarityEnum rarity) + { + var display = GetAttribute(rarity); + return display.Name!; + } + + public static decimal[] GetProbabilityValues() + { + List probabilityList = new List(); + + foreach (var field in typeof(RarityEnum).GetFields()) + { + // 获取特性 + var attribute = field.GetCustomAttribute(); + if (attribute != null) + { + // 将特性值添加到列表 + probabilityList.Add(attribute.Value.To()); + } + } + + return probabilityList.ToArray(); + } + } \ No newline at end of file diff --git a/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain.Shared/Dtos/MiningPoolContent.cs b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain.Shared/Dtos/MiningPoolContent.cs new file mode 100644 index 00000000..1ff8714b --- /dev/null +++ b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain.Shared/Dtos/MiningPoolContent.cs @@ -0,0 +1,50 @@ +namespace Yi.Framework.DigitalCollectibles.Domain.Shared.Dtos; + +/// +/// 矿池内容 +/// +public class MiningPoolContent +{ + public MiningPoolContent(DateTime startTime, DateTime endTime) + { + StartTime = startTime; + EndTime = endTime; + } + + /// + /// 普通藏品剩余数量 + /// + public int I0_OrdinaryNumber { get; set; } + + /// + /// 高级藏品剩余数量 + /// + public int I1_SeniorNumber { get; set; } + + /// + /// 稀有藏品剩余数量 + /// + public int I2_RareNumber { get; set; } + + /// + /// 珍品藏品剩余数量 + /// + public int I3_GemNumber { get; set; } + + /// + /// 传说藏品剩余数量 + /// + public int I4_LegendNumber { get; set; } + + /// + /// 开始时间 + /// + public DateTime StartTime{ get; set; } + + /// + /// 结束时间 + /// + public DateTime EndTime{ get; set; } + +} + diff --git a/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain.Shared/Yi.Framework.DigitalCollectibles.Domain.Shared.csproj b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain.Shared/Yi.Framework.DigitalCollectibles.Domain.Shared.csproj index 186bab0b..1c8256fb 100644 --- a/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain.Shared/Yi.Framework.DigitalCollectibles.Domain.Shared.csproj +++ b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain.Shared/Yi.Framework.DigitalCollectibles.Domain.Shared.csproj @@ -10,7 +10,6 @@ - diff --git a/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain/Entities/CollectiblesUserStoreAggregateRoot.cs b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain/Entities/CollectiblesUserStoreAggregateRoot.cs index cd81f4e0..e6345b4a 100644 --- a/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain/Entities/CollectiblesUserStoreAggregateRoot.cs +++ b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain/Entities/CollectiblesUserStoreAggregateRoot.cs @@ -19,4 +19,9 @@ public class CollectiblesUserStoreAggregateRoot:FullAuditedAggregateRoot /// 藏品id /// public Guid CollectiblesId { get; set; } + + /// + /// 用户是否已读 + /// + public bool IsRead { get; set; } } \ No newline at end of file diff --git a/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain/Managers/MiningPoolManager.cs b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain/Managers/MiningPoolManager.cs index d6cfeea5..20105288 100644 --- a/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain/Managers/MiningPoolManager.cs +++ b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain/Managers/MiningPoolManager.cs @@ -1,4 +1,10 @@ -using Volo.Abp.Domain.Services; +using Microsoft.Extensions.Caching.Distributed; +using Volo.Abp.Caching; +using Volo.Abp.Domain.Services; +using Volo.Abp.Settings; +using Yi.Framework.DigitalCollectibles.Domain.Shared.Consts; +using Yi.Framework.DigitalCollectibles.Domain.Shared.Dtos; +using Yi.Framework.SettingManagement.Domain; namespace Yi.Framework.DigitalCollectibles.Domain.Managers; @@ -6,6 +12,134 @@ namespace Yi.Framework.DigitalCollectibles.Domain.Managers; /// 矿池领域服务 /// 处理矿池相关业务,例如挖矿等 /// -public class MiningPoolManager:DomainService +public class MiningPoolManager : DomainService { + /// + /// 每次挖矿概率,每天根据特定算法计算 + /// + private static decimal CurrentMiningProbability { get; set; } + + private readonly ISettingProvider _settingProvider; + private readonly IDistributedCache _cache; + + public MiningPoolManager(ISettingProvider settingProvider, IDistributedCache cache) + { + _settingProvider = settingProvider; + this._cache = cache; + } + + /// + /// 最后一次计算挖矿概率的时间,如果时间跨了早上10点,重新计算 + /// + private static DateTime LastComputeMiningProbabilityTime { get; set; } + + /// + /// 用户进行一次挖矿 + /// + /// + public Task MiningAsync(Guid userId) + { + //从矿池中开挖 + //根据挖矿概率,进行挖掘 + //挖到了放到用户仓库即可 + + //如果概率是挖到了矿,再从矿物中随机选择一个稀有度,再在当前稀有度中的矿物列表,随机选择一个具体的矿物 + + throw new NotImplementedException(); + } + + /// + /// 计算当前挖矿概率 + /// + /// + public Task ComputeMiningProbabilityAsync() + { + //当前的挖矿期望:当天的所有藏品能被刚好挖完 + + //保底概率:最大不能高过一个值,百分之10 + //手动挖矿:1天可挖10次,每次至少间隔6秒 + //自动挖矿:1天可以挖24次 每次间隔60分钟(需要使用自动挖矿卡) + //可影响因素:剩余手动挖矿次数+剩余自动挖矿次数 + + //所有能够挖掘次数 + throw new NotImplementedException(); + } + + /// + /// 刷新矿池 + /// + /// + public async Task RefreshMiningPoolAsync() + { + //获取当前最大的限制 + var maximumPoolLimit = int.Parse(await _settingProvider.GetOrNullAsync("MaximumPoolLimit")); + + DateTime startTime = DateTime.Today.AddHours(10); + DateTime endTime = startTime.AddDays(1); + var probabilityValues = RarityEnumExtensions.GetProbabilityValues(); + var result = GenerateDistribution(maximumPoolLimit, probabilityValues); + + //根据配置,将不同比例的矿,塞入矿池, + //矿池,交给redis + await _cache.SetAsync(CacheConst.MiningPoolContent, new MiningPoolContent(startTime, endTime) + { + I0_OrdinaryNumber = result[0], + I1_SeniorNumber = result[1], + I2_RareNumber = result[2], + I3_GemNumber = result[3], + I4_LegendNumber = result[4] + }, new DistributedCacheEntryOptions + { + AbsoluteExpiration = endTime + }); + } + + /// + /// 根据概率生成给对应稀有度藏品 + /// + /// + /// + /// + /// + private int[] GenerateDistribution(int totalCount, decimal[] probabilities) + { + int[] counts = new int[probabilities.Length]; + decimal totalProbability = 0; + + // 计算概率总和,确保为 1 + foreach (var prob in probabilities) + { + totalProbability += prob; + } + + // 检查概率之和是否为 1 + if (totalProbability < 0.99m || totalProbability > 1.01m) + { + throw new ArgumentException("概率总和必须接近1"); + } + + // 生成分布 + for (int i = 0; i < probabilities.Length; i++) + { + counts[i] = (int)(totalCount * probabilities[i]); + } + + // 处理可能因精度问题导致的总数不足 + int sum = 0; + foreach (var count in counts) + { + sum += count; + } + + int difference = totalCount - sum; + + // 将差值分配给概率最大的一项 + if (difference > 0) + { + int maxIndex = Array.IndexOf(counts, Math.Max(counts[0], counts[1])); + counts[maxIndex] += difference; + } + + return counts; + } } \ No newline at end of file diff --git a/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain/Yi.Framework.DigitalCollectibles.Domain.csproj b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain/Yi.Framework.DigitalCollectibles.Domain.csproj index 8c36f501..b8434d1a 100644 --- a/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain/Yi.Framework.DigitalCollectibles.Domain.csproj +++ b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain/Yi.Framework.DigitalCollectibles.Domain.csproj @@ -9,6 +9,7 @@ + diff --git a/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain/YiFrameworkDigitalCollectiblesDomainModule.cs b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain/YiFrameworkDigitalCollectiblesDomainModule.cs index c2837b07..9171ca5b 100644 --- a/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain/YiFrameworkDigitalCollectiblesDomainModule.cs +++ b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain/YiFrameworkDigitalCollectiblesDomainModule.cs @@ -3,12 +3,14 @@ using Volo.Abp.Domain; using Volo.Abp.Modularity; using Yi.Framework.DigitalCollectibles.Domain.Shared; using Yi.Framework.Mapster; +using Yi.Framework.SettingManagement.Domain; namespace Yi.Framework.DigitalCollectibles.Domain { [DependsOn( typeof(YiFrameworkDigitalCollectiblesDomainSharedModule), + typeof(YiFrameworkSettingManagementDomainModule), typeof(YiFrameworkMapsterModule), typeof(AbpDddDomainModule), typeof(AbpCachingModule) diff --git a/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.SqlSugarCore/Yi.Framework.DigitalCollectibles.SqlSugarCore.csproj b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.SqlSugarCore/Yi.Framework.DigitalCollectibles.SqlSugarCore.csproj index 3cfeec1e..52f1ba49 100644 --- a/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.SqlSugarCore/Yi.Framework.DigitalCollectibles.SqlSugarCore.csproj +++ b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.SqlSugarCore/Yi.Framework.DigitalCollectibles.SqlSugarCore.csproj @@ -4,6 +4,7 @@ + diff --git a/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.SqlSugarCore/YiFrameworkDigitalCollectiblesSqlSugarCoreModule.cs b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.SqlSugarCore/YiFrameworkDigitalCollectiblesSqlSugarCoreModule.cs index 336d5147..01bf8331 100644 --- a/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.SqlSugarCore/YiFrameworkDigitalCollectiblesSqlSugarCoreModule.cs +++ b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.SqlSugarCore/YiFrameworkDigitalCollectiblesSqlSugarCoreModule.cs @@ -1,16 +1,13 @@ -using Microsoft.Extensions.DependencyInjection; -using Volo.Abp.Modularity; using Yi.Framework.DigitalCollectibles.Domain; using Yi.Framework.Mapster; +using Yi.Framework.SettingManagement.SqlSugarCore; using Yi.Framework.SqlSugarCore; -using Yi.Framework.SqlSugarCore.Abstractions; - namespace Yi.Framework.DigitalCollectibles.SqlsugarCore { [DependsOn( typeof(YiFrameworkDigitalCollectiblesDomainModule), - + typeof(YiFrameworkSettingManagementSqlSugarCoreModule), typeof(YiFrameworkMapsterModule), typeof(YiFrameworkSqlSugarCoreModule) )]