From a0ef3af1555643244c9a945149174da6b206c6cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A9=99=E5=AD=90?= <454313500@qq.com> Date: Tue, 15 Oct 2024 21:50:31 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=8C=E6=88=90=E5=9F=BA=E7=A1=80?= =?UTF-8?q?=E6=A1=86=E6=9E=B6=E6=90=AD=E5=BB=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Jobs/AutoRefreshMiningPoolJob.cs | 26 +++- .../Jobs/OnHookAutoMiningJob.cs | 29 ++++- ...ork.DigitalCollectibles.Application.csproj | 1 + .../Consts/RarityEnum.cs | 2 +- .../Enums/MiningResultEnum.cs | 8 ++ ...k.DigitalCollectibles.Domain.Shared.csproj | 1 - .../Dtos/MiningPoolContent.cs | 8 +- .../Dtos/MiningPoolResult.cs | 11 ++ .../Managers/MiningPoolManager.cs | 123 +++++++++++++++--- 9 files changed, 181 insertions(+), 28 deletions(-) create mode 100644 Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain.Shared/Enums/MiningResultEnum.cs rename Yi.Abp.Net8/module/digital-collectibles/{Yi.Framework.DigitalCollectibles.Domain.Shared => Yi.Framework.DigitalCollectibles.Domain}/Dtos/MiningPoolContent.cs (80%) create mode 100644 Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain/Dtos/MiningPoolResult.cs diff --git a/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Application/Jobs/AutoRefreshMiningPoolJob.cs b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Application/Jobs/AutoRefreshMiningPoolJob.cs index 8d895ee3..1563a531 100644 --- a/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Application/Jobs/AutoRefreshMiningPoolJob.cs +++ b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Application/Jobs/AutoRefreshMiningPoolJob.cs @@ -1,9 +1,29 @@ -namespace Yi.Framework.DigitalCollectibles.Application.Jobs; +using Quartz; +using Volo.Abp.BackgroundWorkers.Quartz; +using Yi.Framework.DigitalCollectibles.Domain.Managers; + +namespace Yi.Framework.DigitalCollectibles.Application.Jobs; /// /// 自动刷新填满矿池 /// -public class AutoRefreshMiningPoolJob +public class AutoRefreshMiningPoolJob : QuartzBackgroundWorkerBase { - + private readonly MiningPoolManager _miningPoolManager; + + public AutoRefreshMiningPoolJob() + { + JobDetail = JobBuilder.Create().WithIdentity(nameof(AutoRefreshMiningPoolJob)) + .Build(); + + //每天早上10点执行一次 + Trigger = TriggerBuilder.Create().WithIdentity(nameof(AutoRefreshMiningPoolJob)) + .WithCronSchedule("0 0 10 * * ?") + .Build(); + } + + public override async Task Execute(IJobExecutionContext context) + { + await _miningPoolManager.RefreshMiningPoolAsync(); + } } \ No newline at end of file diff --git a/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Application/Jobs/OnHookAutoMiningJob.cs b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Application/Jobs/OnHookAutoMiningJob.cs index 216ea04c..fe6f69f6 100644 --- a/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Application/Jobs/OnHookAutoMiningJob.cs +++ b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Application/Jobs/OnHookAutoMiningJob.cs @@ -1,9 +1,32 @@ -namespace Yi.Framework.DigitalCollectibles.Application.Jobs; +using Quartz; +using Volo.Abp.BackgroundWorkers.Quartz; +using Yi.Framework.DigitalCollectibles.Domain.Entities; +using Yi.Framework.DigitalCollectibles.Domain.Managers; +using Yi.Framework.SqlSugarCore.Abstractions; + +namespace Yi.Framework.DigitalCollectibles.Application.Jobs; /// /// 处理挂机挖矿定时任务 /// -public class OnHookAutoMiningJob +public class OnHookAutoMiningJob : QuartzBackgroundWorkerBase { - + private readonly MiningPoolManager _miningPoolManager; + + public OnHookAutoMiningJob(MiningPoolManager miningPoolManager) + { + _miningPoolManager = miningPoolManager; + JobDetail = JobBuilder.Create().WithIdentity(nameof(AutoRefreshMiningPoolJob)) + .Build(); + + //每小时执行一次 + Trigger = TriggerBuilder.Create().WithIdentity(nameof(AutoRefreshMiningPoolJob)) + .WithCronSchedule("0 0 * * * ?") + .Build(); + } + + public override async Task Execute(IJobExecutionContext context) + { + await _miningPoolManager.OnHookMiningAsync(); + } } \ No newline at end of file diff --git a/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Application/Yi.Framework.DigitalCollectibles.Application.csproj b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Application/Yi.Framework.DigitalCollectibles.Application.csproj index 3a010e50..57a561a8 100644 --- a/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Application/Yi.Framework.DigitalCollectibles.Application.csproj +++ b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Application/Yi.Framework.DigitalCollectibles.Application.csproj @@ -6,6 +6,7 @@ + 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 453aa212..2d988935 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 @@ -37,7 +37,7 @@ public static class RarityEnumExtensions return display.Name!; } - public static decimal[] GetProbabilityValues() + public static decimal[] GetProbabilityArray() { List probabilityList = new List(); diff --git a/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain.Shared/Enums/MiningResultEnum.cs b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain.Shared/Enums/MiningResultEnum.cs new file mode 100644 index 00000000..2a94fd35 --- /dev/null +++ b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain.Shared/Enums/MiningResultEnum.cs @@ -0,0 +1,8 @@ +namespace Yi.Framework.DigitalCollectibles.Domain.Shared.Enums; + +public enum MiningResultEnum +{ + Success, + Empty, + PoolIsEmpty +} \ No newline at end of file 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 1c8256fb..5a8191e1 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.Shared/Dtos/MiningPoolContent.cs b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain/Dtos/MiningPoolContent.cs similarity index 80% rename from Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain.Shared/Dtos/MiningPoolContent.cs rename to Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain/Dtos/MiningPoolContent.cs index 1ff8714b..b5094bc3 100644 --- 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/Dtos/MiningPoolContent.cs @@ -1,4 +1,4 @@ -namespace Yi.Framework.DigitalCollectibles.Domain.Shared.Dtos; +namespace Yi.Framework.DigitalCollectibles.Domain.Dtos; /// /// 矿池内容 @@ -45,6 +45,10 @@ public class MiningPoolContent /// 结束时间 /// public DateTime EndTime{ get; set; } - + + /// + /// 总共剩余藏品数量 + /// + public int TotalNumber => I0_OrdinaryNumber + I1_SeniorNumber + I2_RareNumber + I3_GemNumber + I4_LegendNumber; } diff --git a/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain/Dtos/MiningPoolResult.cs b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain/Dtos/MiningPoolResult.cs new file mode 100644 index 00000000..27be92c5 --- /dev/null +++ b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain/Dtos/MiningPoolResult.cs @@ -0,0 +1,11 @@ +using Yi.Framework.DigitalCollectibles.Domain.Entities; +using Yi.Framework.DigitalCollectibles.Domain.Shared.Enums; + +namespace Yi.Framework.DigitalCollectibles.Domain.Dtos; + +public class MiningPoolResult +{ + public MiningResultEnum Result { get; set; } + + public CollectiblesAggregateRoot? Collectibles { 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 20105288..ce9d1402 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 @@ -2,9 +2,13 @@ using Volo.Abp.Caching; using Volo.Abp.Domain.Services; using Volo.Abp.Settings; +using Volo.Abp.Threading; +using Yi.Framework.DigitalCollectibles.Domain.Dtos; +using Yi.Framework.DigitalCollectibles.Domain.Entities; using Yi.Framework.DigitalCollectibles.Domain.Shared.Consts; -using Yi.Framework.DigitalCollectibles.Domain.Shared.Dtos; +using Yi.Framework.DigitalCollectibles.Domain.Shared.Enums; using Yi.Framework.SettingManagement.Domain; +using Yi.Framework.SqlSugarCore.Abstractions; namespace Yi.Framework.DigitalCollectibles.Domain.Managers; @@ -14,55 +18,138 @@ namespace Yi.Framework.DigitalCollectibles.Domain.Managers; /// public class MiningPoolManager : DomainService { - /// - /// 每次挖矿概率,每天根据特定算法计算 - /// - private static decimal CurrentMiningProbability { get; set; } - + private readonly ISqlSugarRepository _collectiblesRepository; + private readonly ISqlSugarRepository _onHookRepository; private readonly ISettingProvider _settingProvider; private readonly IDistributedCache _cache; + private readonly ISqlSugarRepository _userStoreRepository; - public MiningPoolManager(ISettingProvider settingProvider, IDistributedCache cache) + public MiningPoolManager(ISettingProvider settingProvider, IDistributedCache cache, + ISqlSugarRepository collectiblesRepository, + ISqlSugarRepository onHookRepository, + ISqlSugarRepository userStoreRepository) { _settingProvider = settingProvider; this._cache = cache; + _collectiblesRepository = collectiblesRepository; + _onHookRepository = onHookRepository; + _userStoreRepository = userStoreRepository; } /// - /// 最后一次计算挖矿概率的时间,如果时间跨了早上10点,重新计算 + /// 每次挖矿概率,每天根据特定算法计算 /// - private static DateTime LastComputeMiningProbabilityTime { get; set; } + private static decimal CurrentMiningProbability => AsyncHelper.RunSync(async () => + { + return await ComputeMiningProbabilityAsync(); + }); /// /// 用户进行一次挖矿 /// /// - public Task MiningAsync(Guid userId) + public async Task MiningAsync(Guid userId) { - //从矿池中开挖 + var result = new MiningPoolResult(); + //从矿池中开挖,判断矿池是否还有矿 //根据挖矿概率,进行挖掘 //挖到了放到用户仓库即可 //如果概率是挖到了矿,再从矿物中随机选择一个稀有度,再在当前稀有度中的矿物列表,随机选择一个具体的矿物 + var pool = await _cache.GetAsync(CacheConst.MiningPoolContent); + if (pool.TotalNumber == 0) + { + result.Result = MiningResultEnum.PoolIsEmpty; + return result; + } - throw new NotImplementedException(); + // 生成一个 0 到 1 之间的随机数 + double randomValue = new Random().NextDouble(); + //如果随机的概率在当前概率内,成功 + if (randomValue.To() < CurrentMiningProbability) + { + //成功后在藏品中根据稀有度概率必定获取一个 + var probabilityArray = RarityEnumExtensions.GetProbabilityArray(); + var index = GetRandomIndex(probabilityArray); + var rarityType = (RarityEnum)Enum.GetValues(typeof(RarityEnum)).GetValue(index); + var collectiblesList = + await _collectiblesRepository._DbQueryable.Where(x => x.Rarity == rarityType).ToListAsync(); + int randomIndex = new Random().Next(collectiblesList.Count); + var currentCollectibles = collectiblesList[randomIndex]; + result.Result = MiningResultEnum.Success; + result.Collectibles = currentCollectibles; + + //使用结果新增给对应的用户 + await _userStoreRepository.InsertAsync(new CollectiblesUserStoreAggregateRoot + { + UserId = userId, + CollectiblesId = result.Collectibles.Id, + IsRead = false + }); + + + return result; + } + + result.Result = MiningResultEnum.Empty; + return result; + } + + /// + /// 挂机挖矿 + /// + public async Task OnHookMiningAsync() + { + //获取当前激活的挂机挖矿 + var currentOnHook = await _onHookRepository._DbQueryable.Where(x => x.IsActive == true) + .Where(x => x.EndTime <= DateTime.Now).ToListAsync(); + + //根据用户对挂机卡hash关系 + var userOnHookDic = currentOnHook.GroupBy(x => x.UserId).ToDictionary(x => x.Key, y => y.First()); + foreach (var onHookItem in userOnHookDic) + { + await MiningAsync(onHookItem.Value.UserId); + } + } + + private int GetRandomIndex(decimal[] probabilities) + { + // 生成0到1之间的随机数 + Random random = new Random(); + decimal randomValue = random.NextDouble().To(); + + decimal cumulativeProbability = 0.0m; + + for (int i = 0; i < probabilities.Length; i++) + { + cumulativeProbability += probabilities[i]; + + // 判断随机数是否小于当前的累积概率 + if (randomValue < cumulativeProbability) + { + return i; // 返回中标的索引 + } + } + + //剩余情况都是普通 + return 0; } /// /// 计算当前挖矿概率 /// /// - public Task ComputeMiningProbabilityAsync() + public static Task ComputeMiningProbabilityAsync() { //当前的挖矿期望:当天的所有藏品能被刚好挖完 - + //保底概率:最大不能高过一个值,百分之10 //手动挖矿:1天可挖10次,每次至少间隔6秒 //自动挖矿:1天可以挖24次 每次间隔60分钟(需要使用自动挖矿卡) //可影响因素:剩余手动挖矿次数+剩余自动挖矿次数 - - //所有能够挖掘次数 - throw new NotImplementedException(); + + //简单模式,1/15 + return Task.FromResult(1m / 15); } /// @@ -76,7 +163,7 @@ public class MiningPoolManager : DomainService DateTime startTime = DateTime.Today.AddHours(10); DateTime endTime = startTime.AddDays(1); - var probabilityValues = RarityEnumExtensions.GetProbabilityValues(); + var probabilityValues = RarityEnumExtensions.GetProbabilityArray(); var result = GenerateDistribution(maximumPoolLimit, probabilityValues); //根据配置,将不同比例的矿,塞入矿池,