feat: 完成搭建基础功能
This commit is contained in:
@@ -24,6 +24,9 @@ public class AutoRefreshMiningPoolJob : QuartzBackgroundWorkerBase
|
|||||||
|
|
||||||
public override async Task Execute(IJobExecutionContext context)
|
public override async Task Execute(IJobExecutionContext context)
|
||||||
{
|
{
|
||||||
|
//刷新矿池
|
||||||
await _miningPoolManager.RefreshMiningPoolAsync();
|
await _miningPoolManager.RefreshMiningPoolAsync();
|
||||||
|
//刷新用户限制
|
||||||
|
await _miningPoolManager.RefreshMiningUserLimitAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,13 @@
|
|||||||
namespace Yi.Framework.DigitalCollectibles.Domain.Shared.Consts;
|
namespace Yi.Framework.DigitalCollectibles.Domain.Shared.Consts;
|
||||||
|
|
||||||
public class CacheConst
|
public class MiningCacheConst
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 矿池
|
/// 矿池
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const string MiningPoolContent = "MiningPool";
|
public const string MiningPoolContent = "MiningPool";
|
||||||
|
|
||||||
|
public const string UserMiningLimit = "UserMiningLimit";
|
||||||
|
|
||||||
|
public const string UserMiningLimitLock = "UserMiningLimitLock";
|
||||||
}
|
}
|
||||||
@@ -18,11 +18,14 @@ namespace Yi.Abp.Domain.Shared.Settings
|
|||||||
//每日矿池最大上限
|
//每日矿池最大上限
|
||||||
new SettingDefinition("MaxPoolLimit", "100"),
|
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")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,5 @@ namespace Yi.Framework.DigitalCollectibles.Domain.Dtos;
|
|||||||
|
|
||||||
public class MiningPoolResult
|
public class MiningPoolResult
|
||||||
{
|
{
|
||||||
public MiningResultEnum Result { get; set; }
|
|
||||||
|
|
||||||
public CollectiblesAggregateRoot? Collectibles { get; set; }
|
public CollectiblesAggregateRoot? Collectibles { get; set; }
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
namespace Yi.Framework.DigitalCollectibles.Domain.Dtos;
|
||||||
|
|
||||||
|
public class UserMiningLimitCacheDto
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 当前已挖矿次数
|
||||||
|
/// </summary>
|
||||||
|
public int Number { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 上次挖矿时间
|
||||||
|
/// </summary>
|
||||||
|
public DateTime? LastMiningTime{ get; set; }
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using Microsoft.Extensions.Caching.Distributed;
|
using FreeRedis;
|
||||||
|
using Microsoft.Extensions.Caching.Distributed;
|
||||||
using Volo.Abp.Caching;
|
using Volo.Abp.Caching;
|
||||||
using Volo.Abp.Domain.Services;
|
using Volo.Abp.Domain.Services;
|
||||||
using Volo.Abp.Settings;
|
using Volo.Abp.Settings;
|
||||||
@@ -21,57 +22,110 @@ public class MiningPoolManager : DomainService
|
|||||||
private readonly ISqlSugarRepository<CollectiblesAggregateRoot> _collectiblesRepository;
|
private readonly ISqlSugarRepository<CollectiblesAggregateRoot> _collectiblesRepository;
|
||||||
private readonly ISqlSugarRepository<OnHookAggregateRoot> _onHookRepository;
|
private readonly ISqlSugarRepository<OnHookAggregateRoot> _onHookRepository;
|
||||||
private readonly ISettingProvider _settingProvider;
|
private readonly ISettingProvider _settingProvider;
|
||||||
private readonly IDistributedCache<MiningPoolContent> _cache;
|
private readonly IDistributedCache<MiningPoolContent?> _miningPoolCache;
|
||||||
|
private readonly IDistributedCache<UserMiningLimitCacheDto?> _userMiningLimitCache;
|
||||||
private readonly ISqlSugarRepository<CollectiblesUserStoreAggregateRoot> _userStoreRepository;
|
private readonly ISqlSugarRepository<CollectiblesUserStoreAggregateRoot> _userStoreRepository;
|
||||||
|
private IRedisClient RedisClient => LazyServiceProvider.LazyGetRequiredService<IRedisClient>();
|
||||||
|
|
||||||
public MiningPoolManager(ISettingProvider settingProvider, IDistributedCache<MiningPoolContent> cache,
|
public MiningPoolManager(ISettingProvider settingProvider, IDistributedCache<MiningPoolContent> miningPoolCache,
|
||||||
ISqlSugarRepository<CollectiblesAggregateRoot> collectiblesRepository,
|
ISqlSugarRepository<CollectiblesAggregateRoot> collectiblesRepository,
|
||||||
ISqlSugarRepository<OnHookAggregateRoot> onHookRepository,
|
ISqlSugarRepository<OnHookAggregateRoot> onHookRepository,
|
||||||
ISqlSugarRepository<CollectiblesUserStoreAggregateRoot> userStoreRepository)
|
ISqlSugarRepository<CollectiblesUserStoreAggregateRoot> userStoreRepository,
|
||||||
|
IDistributedCache<UserMiningLimitCacheDto> userMiningLimitCache)
|
||||||
{
|
{
|
||||||
_settingProvider = settingProvider;
|
_settingProvider = settingProvider;
|
||||||
this._cache = cache;
|
this._miningPoolCache = miningPoolCache;
|
||||||
_collectiblesRepository = collectiblesRepository;
|
_collectiblesRepository = collectiblesRepository;
|
||||||
_onHookRepository = onHookRepository;
|
_onHookRepository = onHookRepository;
|
||||||
_userStoreRepository = userStoreRepository;
|
_userStoreRepository = userStoreRepository;
|
||||||
|
_userMiningLimitCache = userMiningLimitCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 每次挖矿概率,每天根据特定算法计算
|
/// 每次挖矿概率,每天根据特定算法计算
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static decimal CurrentMiningProbability => AsyncHelper.RunSync(async () =>
|
private decimal CurrentMiningProbability => AsyncHelper.RunSync(async () =>
|
||||||
{
|
{
|
||||||
return await ComputeMiningProbabilityAsync();
|
return await ComputeMiningProbabilityAsync();
|
||||||
});
|
});
|
||||||
|
|
||||||
public async Task<MiningPoolContent> GetMiningPoolContentAsync()
|
public async Task<MiningPoolContent> GetMiningPoolContentAsync()
|
||||||
{
|
{
|
||||||
var pool = await _cache.GetAsync(CacheConst.MiningPoolContent);
|
var pool = await _miningPoolCache.GetAsync(MiningCacheConst.MiningPoolContent);
|
||||||
return pool;
|
return pool;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 校验挖矿限制
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="userId"></param>
|
||||||
|
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($"失败,你都挖的冒烟了,请稍后再挖");
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 用户进行一次挖矿
|
/// 用户进行一次挖矿
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task<MiningPoolResult> MiningAsync(Guid userId)
|
public async Task<MiningPoolResult> MiningAsync(Guid userId)
|
||||||
{
|
{
|
||||||
|
//检验限制
|
||||||
|
await VerifyMiningLimitAsync(userId);
|
||||||
|
|
||||||
var result = new MiningPoolResult();
|
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)
|
if (pool.TotalNumber == 0)
|
||||||
{
|
{
|
||||||
result.Result = MiningResultEnum.PoolIsEmpty;
|
throw new UserFriendlyException($"失败,矿池已经被掏空了,请等矿池刷新后再来");
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 生成一个 0 到 1 之间的随机数
|
// 生成一个 0 到 1 之间的随机数
|
||||||
@@ -87,7 +141,7 @@ public class MiningPoolManager : DomainService
|
|||||||
await _collectiblesRepository._DbQueryable.Where(x => x.Rarity == rarityType).ToListAsync();
|
await _collectiblesRepository._DbQueryable.Where(x => x.Rarity == rarityType).ToListAsync();
|
||||||
int randomIndex = new Random().Next(collectiblesList.Count);
|
int randomIndex = new Random().Next(collectiblesList.Count);
|
||||||
var currentCollectibles = collectiblesList[randomIndex];
|
var currentCollectibles = collectiblesList[randomIndex];
|
||||||
result.Result = MiningResultEnum.Success;
|
|
||||||
result.Collectibles = currentCollectibles;
|
result.Collectibles = currentCollectibles;
|
||||||
|
|
||||||
//使用结果新增给对应的用户
|
//使用结果新增给对应的用户
|
||||||
@@ -102,8 +156,7 @@ public class MiningPoolManager : DomainService
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
result.Result = MiningResultEnum.Empty;
|
throw new UserFriendlyException($"恭喜!空空如也,挖了个寂寞");
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -150,7 +203,7 @@ public class MiningPoolManager : DomainService
|
|||||||
/// 计算当前挖矿概率
|
/// 计算当前挖矿概率
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static Task<decimal> ComputeMiningProbabilityAsync()
|
public async Task<decimal> ComputeMiningProbabilityAsync()
|
||||||
{
|
{
|
||||||
//当前的挖矿期望:当天的所有藏品能被刚好挖完
|
//当前的挖矿期望:当天的所有藏品能被刚好挖完
|
||||||
|
|
||||||
@@ -160,7 +213,8 @@ public class MiningPoolManager : DomainService
|
|||||||
//可影响因素:剩余手动挖矿次数+剩余自动挖矿次数
|
//可影响因素:剩余手动挖矿次数+剩余自动挖矿次数
|
||||||
|
|
||||||
//简单模式,1/15
|
//简单模式,1/15
|
||||||
return Task.FromResult(1m / 15);
|
var miningMaxLimit = decimal.Parse(await _settingProvider.GetOrNullAsync("MiningMinProbability"));
|
||||||
|
return miningMaxLimit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -179,7 +233,7 @@ public class MiningPoolManager : DomainService
|
|||||||
|
|
||||||
//根据配置,将不同比例的矿,塞入矿池,
|
//根据配置,将不同比例的矿,塞入矿池,
|
||||||
//矿池,交给redis
|
//矿池,交给redis
|
||||||
await _cache.SetAsync(CacheConst.MiningPoolContent, new MiningPoolContent(startTime, endTime)
|
await _miningPoolCache.SetAsync(MiningCacheConst.MiningPoolContent, new MiningPoolContent(startTime, endTime)
|
||||||
{
|
{
|
||||||
I0_OrdinaryNumber = result[0],
|
I0_OrdinaryNumber = result[0],
|
||||||
I1_SeniorNumber = result[1],
|
I1_SeniorNumber = result[1],
|
||||||
@@ -192,6 +246,14 @@ public class MiningPoolManager : DomainService
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 刷新用户挖矿限制
|
||||||
|
/// </summary>
|
||||||
|
public async Task RefreshMiningUserLimitAsync()
|
||||||
|
{
|
||||||
|
await RedisClient.DelAsync($"{MiningCacheConst.UserMiningLimit}*");
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 根据概率生成给对应稀有度藏品
|
/// 根据概率生成给对应稀有度藏品
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\..\framework\Yi.Framework.Caching.FreeRedis\Yi.Framework.Caching.FreeRedis.csproj" />
|
||||||
<ProjectReference Include="..\..\..\framework\Yi.Framework.Mapster\Yi.Framework.Mapster.csproj" />
|
<ProjectReference Include="..\..\..\framework\Yi.Framework.Mapster\Yi.Framework.Mapster.csproj" />
|
||||||
<ProjectReference Include="..\..\..\framework\Yi.Framework.SqlSugarCore.Abstractions\Yi.Framework.SqlSugarCore.Abstractions.csproj" />
|
<ProjectReference Include="..\..\..\framework\Yi.Framework.SqlSugarCore.Abstractions\Yi.Framework.SqlSugarCore.Abstractions.csproj" />
|
||||||
<ProjectReference Include="..\..\setting-management\Yi.Framework.SettingManagement.Domain\Yi.Framework.SettingManagement.Domain.csproj" />
|
<ProjectReference Include="..\..\setting-management\Yi.Framework.SettingManagement.Domain\Yi.Framework.SettingManagement.Domain.csproj" />
|
||||||
|
|||||||
Reference in New Issue
Block a user