From ef20ef701446e96909f44ff16b1f7ffa71cf3071 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=A9=99=E5=AD=90?= <454313500@qq.com>
Date: Wed, 16 Oct 2024 22:47:04 +0800
Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=8C=E6=88=90=E6=90=AD=E5=BB=BA?=
=?UTF-8?q?=E5=9F=BA=E7=A1=80=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../Jobs/AutoRefreshMiningPoolJob.cs | 3 +
.../{CacheConst.cs => MiningCacheConst.cs} | 6 +-
.../DigitalCollectiblesSettingProvider.cs | 9 +-
.../Dtos/MiningPoolResult.cs | 2 -
.../Dtos/UserMiningLimitCacheDto.cs | 14 +++
.../Managers/MiningPoolManager.cs | 104 ++++++++++++++----
...ramework.DigitalCollectibles.Domain.csproj | 1 +
7 files changed, 112 insertions(+), 27 deletions(-)
rename Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain.Shared/Consts/{CacheConst.cs => MiningCacheConst.cs} (51%)
create mode 100644 Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain/Dtos/UserMiningLimitCacheDto.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 1563a531..fe349a8f 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
@@ -24,6 +24,9 @@ public class AutoRefreshMiningPoolJob : QuartzBackgroundWorkerBase
public override async Task Execute(IJobExecutionContext context)
{
+ //刷新矿池
await _miningPoolManager.RefreshMiningPoolAsync();
+ //刷新用户限制
+ await _miningPoolManager.RefreshMiningUserLimitAsync();
}
}
\ No newline at end of file
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/MiningCacheConst.cs
similarity index 51%
rename from Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain.Shared/Consts/CacheConst.cs
rename to Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain.Shared/Consts/MiningCacheConst.cs
index 015111e3..f1c633ef 100644
--- 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/MiningCacheConst.cs
@@ -1,9 +1,13 @@
namespace Yi.Framework.DigitalCollectibles.Domain.Shared.Consts;
-public class CacheConst
+public class MiningCacheConst
{
///
/// 矿池
///
public const string MiningPoolContent = "MiningPool";
+
+ public const string UserMiningLimit = "UserMiningLimit";
+
+ public const string UserMiningLimitLock = "UserMiningLimitLock";
}
\ No newline at end of file
diff --git a/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain.Shared/Settings/DigitalCollectiblesSettingProvider.cs b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain.Shared/Settings/DigitalCollectiblesSettingProvider.cs
index 29491c38..46ca1a5b 100644
--- a/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain.Shared/Settings/DigitalCollectiblesSettingProvider.cs
+++ b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain.Shared/Settings/DigitalCollectiblesSettingProvider.cs
@@ -18,11 +18,14 @@ namespace Yi.Abp.Domain.Shared.Settings
//每日矿池最大上限
new SettingDefinition("MaxPoolLimit", "100"),
- //每日手动挖矿最大上限
- new SettingDefinition("MiningMaxLimit", "10"),
+ //每日挖矿最大上限
+ new SettingDefinition("MiningMaxLimit", "36"),
//每次挖矿最小间隔(秒)
- new SettingDefinition("MiningMinIntervalSeconds", "5")
+ new SettingDefinition("MiningMinIntervalSeconds", "5"),
+
+ //每次挖到矿的概率
+ new SettingDefinition("MiningMinProbability", "0.06")
);
}
}
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
index 27be92c5..833f81a9 100644
--- 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
@@ -5,7 +5,5 @@ 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/Dtos/UserMiningLimitCacheDto.cs b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain/Dtos/UserMiningLimitCacheDto.cs
new file mode 100644
index 00000000..7f000a55
--- /dev/null
+++ b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain/Dtos/UserMiningLimitCacheDto.cs
@@ -0,0 +1,14 @@
+namespace Yi.Framework.DigitalCollectibles.Domain.Dtos;
+
+public class UserMiningLimitCacheDto
+{
+ ///
+ /// 当前已挖矿次数
+ ///
+ public int Number { get; set; }
+
+ ///
+ /// 上次挖矿时间
+ ///
+ public DateTime? LastMiningTime{ 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 68790cb8..07b6ac08 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,5 @@
-using Microsoft.Extensions.Caching.Distributed;
+using FreeRedis;
+using Microsoft.Extensions.Caching.Distributed;
using Volo.Abp.Caching;
using Volo.Abp.Domain.Services;
using Volo.Abp.Settings;
@@ -21,57 +22,110 @@ public class MiningPoolManager : DomainService
private readonly ISqlSugarRepository _collectiblesRepository;
private readonly ISqlSugarRepository _onHookRepository;
private readonly ISettingProvider _settingProvider;
- private readonly IDistributedCache _cache;
+ private readonly IDistributedCache _miningPoolCache;
+ private readonly IDistributedCache _userMiningLimitCache;
private readonly ISqlSugarRepository _userStoreRepository;
+ private IRedisClient RedisClient => LazyServiceProvider.LazyGetRequiredService();
- public MiningPoolManager(ISettingProvider settingProvider, IDistributedCache cache,
+ public MiningPoolManager(ISettingProvider settingProvider, IDistributedCache miningPoolCache,
ISqlSugarRepository collectiblesRepository,
ISqlSugarRepository onHookRepository,
- ISqlSugarRepository userStoreRepository)
+ ISqlSugarRepository userStoreRepository,
+ IDistributedCache userMiningLimitCache)
{
_settingProvider = settingProvider;
- this._cache = cache;
+ this._miningPoolCache = miningPoolCache;
_collectiblesRepository = collectiblesRepository;
_onHookRepository = onHookRepository;
_userStoreRepository = userStoreRepository;
+ _userMiningLimitCache = userMiningLimitCache;
}
///
/// 每次挖矿概率,每天根据特定算法计算
///
- private static decimal CurrentMiningProbability => AsyncHelper.RunSync(async () =>
+ private decimal CurrentMiningProbability => AsyncHelper.RunSync(async () =>
{
return await ComputeMiningProbabilityAsync();
});
public async Task GetMiningPoolContentAsync()
{
- var pool = await _cache.GetAsync(CacheConst.MiningPoolContent);
+ var pool = await _miningPoolCache.GetAsync(MiningCacheConst.MiningPoolContent);
return pool;
}
+
+ ///
+ /// 校验挖矿限制
+ ///
+ ///
+ private async Task VerifyMiningLimitAsync(Guid userId)
+ {
+ //每天最大次数限制
+ var miningMaxLimit = int.Parse(await _settingProvider.GetOrNullAsync("MiningMaxLimit"));
+ //每次间隔
+ var miningMinIntervalSeconds = int.Parse(await _settingProvider.GetOrNullAsync("MiningMinIntervalSeconds"));
+
+ var currentNumber = 1;
+
+ //根据用户进行上锁
+ if (await RedisClient.SetNxAsync($"UserMiningLimitLock:{userId}", true,
+ TimeSpan.FromSeconds(miningMinIntervalSeconds)))
+ {
+ var userLimit = await _userMiningLimitCache.GetAsync($"{MiningCacheConst.UserMiningLimit}:{userId}");
+
+ if (userLimit is not null)
+ {
+ //符合条件,成功挖矿
+ if (userLimit.Number < miningMaxLimit)
+ {
+ currentNumber = userLimit.Number + 1;
+ }
+ else
+ {
+ throw new UserFriendlyException($"失败,你已达当轮矿池最大限制,给其他人留点吧");
+ }
+ }
+
+ //没有缓存过,必定成功,直接走
+ await _userMiningLimitCache.SetAsync($"{MiningCacheConst.UserMiningLimit}:{userId}",
+ new UserMiningLimitCacheDto
+ {
+ Number = currentNumber,
+ LastMiningTime = DateTime.Now,
+ },
+ new DistributedCacheEntryOptions()
+ {
+ //虽然新增的是一天,但是每次刷新是早上10点,矿池刷新时,还需要清除限制
+ AbsoluteExpirationRelativeToNow = TimeSpan.FromDays(1)
+ });
+ }
+
+ //已上过锁,并且没有到限制时间,必定失败
+ //不符合条件,直接走
+ throw new UserFriendlyException($"失败,你都挖的冒烟了,请稍后再挖");
+ }
+
///
/// 用户进行一次挖矿
///
///
public async Task MiningAsync(Guid userId)
{
-
+ //检验限制
+ await VerifyMiningLimitAsync(userId);
+
var result = new MiningPoolResult();
//从矿池中开挖,判断矿池是否还有矿
//根据挖矿概率,进行挖掘
//挖到了放到用户仓库即可
- var miningMaxLimit = int.Parse(await _settingProvider.GetOrNullAsync("MiningMaxLimit"));
- var miningMinIntervalSeconds = int.Parse(await _settingProvider.GetOrNullAsync("MiningMinIntervalSeconds"));
-
-
//如果概率是挖到了矿,再从矿物中随机选择一个稀有度,再在当前稀有度中的矿物列表,随机选择一个具体的矿物
- var pool =await GetMiningPoolContentAsync();
+ var pool = await GetMiningPoolContentAsync();
if (pool.TotalNumber == 0)
{
- result.Result = MiningResultEnum.PoolIsEmpty;
- return result;
+ throw new UserFriendlyException($"失败,矿池已经被掏空了,请等矿池刷新后再来");
}
// 生成一个 0 到 1 之间的随机数
@@ -87,7 +141,7 @@ public class MiningPoolManager : DomainService
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;
//使用结果新增给对应的用户
@@ -102,8 +156,7 @@ public class MiningPoolManager : DomainService
return result;
}
- result.Result = MiningResultEnum.Empty;
- return result;
+ throw new UserFriendlyException($"恭喜!空空如也,挖了个寂寞");
}
///
@@ -150,7 +203,7 @@ public class MiningPoolManager : DomainService
/// 计算当前挖矿概率
///
///
- public static Task ComputeMiningProbabilityAsync()
+ public async Task ComputeMiningProbabilityAsync()
{
//当前的挖矿期望:当天的所有藏品能被刚好挖完
@@ -160,7 +213,8 @@ public class MiningPoolManager : DomainService
//可影响因素:剩余手动挖矿次数+剩余自动挖矿次数
//简单模式,1/15
- return Task.FromResult(1m / 15);
+ var miningMaxLimit = decimal.Parse(await _settingProvider.GetOrNullAsync("MiningMinProbability"));
+ return miningMaxLimit;
}
///
@@ -179,7 +233,7 @@ public class MiningPoolManager : DomainService
//根据配置,将不同比例的矿,塞入矿池,
//矿池,交给redis
- await _cache.SetAsync(CacheConst.MiningPoolContent, new MiningPoolContent(startTime, endTime)
+ await _miningPoolCache.SetAsync(MiningCacheConst.MiningPoolContent, new MiningPoolContent(startTime, endTime)
{
I0_OrdinaryNumber = result[0],
I1_SeniorNumber = result[1],
@@ -192,6 +246,14 @@ public class MiningPoolManager : DomainService
});
}
+ ///
+ /// 刷新用户挖矿限制
+ ///
+ public async Task RefreshMiningUserLimitAsync()
+ {
+ await RedisClient.DelAsync($"{MiningCacheConst.UserMiningLimit}*");
+ }
+
///
/// 根据概率生成给对应稀有度藏品
///
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 b8434d1a..431565d5 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
@@ -7,6 +7,7 @@
+