修改河南项目的管理后台ui
This commit is contained in:
+167
-142
@@ -16,6 +16,7 @@ import com.ruoyi.admin.service.TtBoxRecordsService;
|
||||
import com.ruoyi.admin.service.TtUpgradeOrnamentsService;
|
||||
import com.ruoyi.admin.service.TtUpgradeRecordService;
|
||||
import com.ruoyi.admin.service.TtUserService;
|
||||
import com.ruoyi.admin.service.UpgradeWatermarkService;
|
||||
import com.ruoyi.common.core.domain.R;
|
||||
import com.ruoyi.common.core.redis.RedisCache;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
@@ -132,6 +133,10 @@ public class ApiLuckyUpgradeServiceImpl implements ApiLuckyUpgradeService {
|
||||
@Autowired
|
||||
private MessageService messageService;
|
||||
|
||||
/** 全局奖池水位:决定每轮抽到的随机数区间(水位越高 → 随机数越低),并负责水位累计记账 */
|
||||
@Autowired
|
||||
private UpgradeWatermarkService watermarkService;
|
||||
|
||||
@Override
|
||||
public List<ApiLuckyOrnamentsDataVO> getOrnamentsList(ApiLuckyUpgradeBody apiLuckyUpgradeBody) {
|
||||
// type 对应 tt_ornament.type 数字字典码(1匕首 2手枪 3步枪 4微型冲锋枪 5重型武器 6手套 7印花 8其它)。
|
||||
@@ -348,6 +353,13 @@ public class ApiLuckyUpgradeServiceImpl implements ApiLuckyUpgradeService {
|
||||
|
||||
boolean isVictory = playResult.isWin();
|
||||
|
||||
// 本次拉取时的全局水位快照(落库,便于事后复盘「这批货是在什么水位下出的」)
|
||||
double watermarkAtPull = watermarkService.getWatermark();
|
||||
// 幸运值累加口径:默认 raw(累加前端传来的原始概率,展示口径,与历史记录一致);
|
||||
// 只有策略里显式配 luckyValueMode=eff 才与判定同口径。
|
||||
// 这是**展示口径**,中奖判定始终用 effectiveProbability,不受它影响。
|
||||
boolean effLuckyValue = watermarkService.isLuckyValueEffMode();
|
||||
|
||||
// 5 同步保存本次结果。
|
||||
// 快照本轮目标金额与已投金额(用于升级记录历史展示,需在累加/重置前读取)
|
||||
// 本轮目标金额使用实际随机出来的目标进度(fullV),而非幸运区间固定最大值
|
||||
@@ -368,57 +380,62 @@ public class ApiLuckyUpgradeServiceImpl implements ApiLuckyUpgradeService {
|
||||
? upgradeOrnament.getBlankEffectiveAmountInvested()
|
||||
: (anchorPool ? upgradeOrnament.getAnchorEffectiveAmountInvested() : upgradeOrnament.getEffectiveAmountInvested());
|
||||
|
||||
// 幸运值快照(累计原始概率,累加/重置前读取,按奖池类型区分)
|
||||
Integer snapshotProbabilityInvested = blankPool
|
||||
? upgradeOrnament.getBlankProbabilityInvested()
|
||||
: (anchorPool ? upgradeOrnament.getAnchorProbabilityInvested() : upgradeOrnament.getProbabilityInvested());
|
||||
int prevProbabilityInvested = snapshotProbabilityInvested == null ? 0 : snapshotProbabilityInvested;
|
||||
// 本饰品当前幸运值:出货成功清 0,失败累加前端原始概率(白号在自己的池里同样累计)
|
||||
int luckyValue = isVictory ? 0 : prevProbabilityInvested + rawProbability;
|
||||
// 本次要累加的幸运值增量:展示口径按「用户在前端拉的那个幸运值」累加(raw=原始概率),
|
||||
// 判定口径另有其人(effectiveProbability,上面已用于出货判定),两者互不影响。
|
||||
int luckyDelta = effLuckyValue ? effectiveProbability : rawProbability;
|
||||
|
||||
// 更新本轮已投入金额(含幸运值)
|
||||
// 白号维护自己的一整套字段(本轮已投金额 + 幸运值),与普通/主播同样的算法,只是不碰它们的列
|
||||
// 幸运值的口径:**三个身份共享同一个累计值**(所以前端所有人看到的数一致),
|
||||
// **任一身份中奖即整体归零**;中奖那一拉的增量仍计入展示值
|
||||
//(玩家在出货那一刻看到的数包含本次,下一拉才从 0 重新累计)。
|
||||
int prevTotal = nvl(upgradeOrnament.getProbabilityInvested())
|
||||
+ nvl(upgradeOrnament.getAnchorProbabilityInvested())
|
||||
+ nvl(upgradeOrnament.getBlankProbabilityInvested());
|
||||
int luckyValue = prevTotal + luckyDelta;
|
||||
|
||||
// 更新:本轮已投金额按身份各自累计/清零;幸运值按共享口径(三列一起清)
|
||||
LambdaUpdateWrapper<TtUpgradeOrnaments> investedUpdate = new LambdaUpdateWrapper<>();
|
||||
investedUpdate.eq(TtUpgradeOrnaments::getId, upgradeOrnament.getId());
|
||||
|
||||
if (isVictory) {
|
||||
// 中奖:幸运值是共享的 ⇒ 三个身份一起清 0(下一个拉取的人从 0 开始)
|
||||
investedUpdate.set(TtUpgradeOrnaments::getProbabilityInvested, 0);
|
||||
investedUpdate.set(TtUpgradeOrnaments::getAnchorProbabilityInvested, 0);
|
||||
investedUpdate.set(TtUpgradeOrnaments::getBlankProbabilityInvested, 0);
|
||||
} else {
|
||||
// 失败:只往自己那一列累加(分列是为了后台能看出各身份的贡献,展示时三列相加)
|
||||
if (blankPool) {
|
||||
investedUpdate.setSql("blank_probability_invested = COALESCE(blank_probability_invested, 0) + " + luckyDelta);
|
||||
} else if (anchorPool) {
|
||||
investedUpdate.setSql("anchor_probability_invested = COALESCE(anchor_probability_invested, 0) + " + luckyDelta);
|
||||
} else {
|
||||
investedUpdate.setSql("probability_invested = COALESCE(probability_invested, 0) + " + luckyDelta);
|
||||
}
|
||||
}
|
||||
|
||||
if (blankPool) {
|
||||
if (isVictory) {
|
||||
// 成功:白号本轮进度清 0 重置,溢出不带入下一轮
|
||||
// 成功:白号本轮已投金额清 0 重置,溢出不带入下一轮
|
||||
investedUpdate.set(TtUpgradeOrnaments::getBlankAmountInvested, BigDecimal.ZERO);
|
||||
investedUpdate.set(TtUpgradeOrnaments::getBlankEffectiveAmountInvested, BigDecimal.ZERO);
|
||||
investedUpdate.set(TtUpgradeOrnaments::getBlankProbabilityInvested, 0);
|
||||
} else {
|
||||
// 失败:实际扣款累计 + price;真实计算口径累计 + effectiveAmount;幸运值累加原始概率
|
||||
investedUpdate.setSql("blank_amount_invested = blank_amount_invested + " + price);
|
||||
investedUpdate.setSql("blank_effective_amount_invested = blank_effective_amount_invested + " + effectiveAmount);
|
||||
investedUpdate.setSql("blank_probability_invested = COALESCE(blank_probability_invested, 0) + " + rawProbability);
|
||||
}
|
||||
} else if (anchorPool) {
|
||||
if (isVictory) {
|
||||
// 成功:本轮进度清 0 重置,溢出不带入下一轮
|
||||
investedUpdate.set(TtUpgradeOrnaments::getAnchorAmountInvested, BigDecimal.ZERO);
|
||||
investedUpdate.set(TtUpgradeOrnaments::getAnchorEffectiveAmountInvested, BigDecimal.ZERO);
|
||||
// 幸运值(累计原始概率)同步清 0
|
||||
investedUpdate.set(TtUpgradeOrnaments::getAnchorProbabilityInvested, 0);
|
||||
} else {
|
||||
// 失败:实际扣款累计 + price;真实计算口径累计 + effectiveAmount
|
||||
investedUpdate.setSql("anchor_amount_invested = anchor_amount_invested + " + price);
|
||||
investedUpdate.setSql("anchor_effective_amount_invested = anchor_effective_amount_invested + " + effectiveAmount);
|
||||
// 幸运值累加前端原始概率(如 90)
|
||||
investedUpdate.setSql("anchor_probability_invested = COALESCE(anchor_probability_invested, 0) + " + rawProbability);
|
||||
}
|
||||
} else {
|
||||
if (isVictory) {
|
||||
// 成功:本轮进度清 0 重置,溢出不带入下一轮
|
||||
investedUpdate.set(TtUpgradeOrnaments::getAmountInvested, BigDecimal.ZERO);
|
||||
investedUpdate.set(TtUpgradeOrnaments::getEffectiveAmountInvested, BigDecimal.ZERO);
|
||||
// 幸运值(累计原始概率)同步清 0
|
||||
investedUpdate.set(TtUpgradeOrnaments::getProbabilityInvested, 0);
|
||||
} else {
|
||||
// 失败:实际扣款累计 + price;真实计算口径累计 + effectiveAmount
|
||||
investedUpdate.setSql("amount_invested = amount_invested + " + price);
|
||||
investedUpdate.setSql("effective_amount_invested = effective_amount_invested + " + effectiveAmount);
|
||||
// 幸运值累加前端原始概率(如 90)
|
||||
investedUpdate.setSql("probability_invested = COALESCE(probability_invested, 0) + " + rawProbability);
|
||||
}
|
||||
}
|
||||
upgradeOrnamentsMapper.update(null, investedUpdate);
|
||||
@@ -467,6 +484,9 @@ public class ApiLuckyUpgradeServiceImpl implements ApiLuckyUpgradeService {
|
||||
|
||||
.gainOrnamentsPrice(prizeTotal)
|
||||
|
||||
.watermark(BigDecimal.valueOf(watermarkAtPull).setScale(2, java.math.RoundingMode.HALF_UP))
|
||||
.roundTarget(playResult.getTargetProgress())
|
||||
|
||||
.openTime(new Date())
|
||||
.build();
|
||||
|
||||
@@ -528,6 +548,9 @@ public class ApiLuckyUpgradeServiceImpl implements ApiLuckyUpgradeService {
|
||||
|
||||
.gainOrnamentsPrice(prizeTotal)
|
||||
|
||||
.watermark(BigDecimal.valueOf(watermarkAtPull).setScale(2, java.math.RoundingMode.HALF_UP))
|
||||
.roundTarget(playResult.getTargetProgress())
|
||||
|
||||
.openTime(new Date())
|
||||
.build();
|
||||
|
||||
@@ -570,6 +593,10 @@ public class ApiLuckyUpgradeServiceImpl implements ApiLuckyUpgradeService {
|
||||
|
||||
ttUpgradeRecordService.save(upgradeRecord);
|
||||
|
||||
// 水位累计记账:本次拉取的下注/返奖入账(白号单独计,不进水位口径)。
|
||||
// 本轮判定用的是本轮开始时的水位,所以这次增量只影响下一轮 —— 顺序不能反。
|
||||
watermarkService.recordPull(price, upgradeRecord.getGainOrnamentsPrice(), blankPool);
|
||||
|
||||
// 发送邮件通知(取第一件获得的饰品)
|
||||
if (!boxRecords.isEmpty()) {
|
||||
TtBoxRecords record = boxRecords.get(0);
|
||||
@@ -592,140 +619,133 @@ public class ApiLuckyUpgradeServiceImpl implements ApiLuckyUpgradeService {
|
||||
|
||||
}
|
||||
|
||||
public UpgradePlayResult playing(TtUser ttUser, TtUpgradeOrnaments upgradeOrnament, UpgradeBodyA upgradeParam, int effectiveProbability) {
|
||||
|
||||
Integer upgradeOrnamentId = upgradeOrnament.getId();
|
||||
// 奖池类型:白号(06)走自己的进度池与幸运值,Redis key 天然按类型隔离,白号之间共享 06 池
|
||||
String poolType = poolType(ttUser);
|
||||
|
||||
String rangeFixedKey = RedisConstants.UPGRADE_RANGE_FIXED + upgradeOrnamentId + ":" + poolType;
|
||||
String rangeFloatKey = RedisConstants.UPGRADE_RANGE + upgradeOrnamentId + ":" + poolType;
|
||||
|
||||
// 读redis的固定概率 [x,y] x进度,y空间大小(缓存缺失或非法时返回 null)
|
||||
Integer[] rangeFixed = parseRange(redisCache.getCacheObject(rangeFixedKey));
|
||||
// 读redis的饰品概率区间 [begin,end]
|
||||
Integer[] rangeFloat = parseRange(redisCache.getCacheObject(rangeFloatKey));
|
||||
|
||||
if (isValidRange(rangeFixed)) {
|
||||
// 抽奖
|
||||
return doUpgrade(
|
||||
ttUser,
|
||||
upgradeOrnament,
|
||||
rangeFixed,
|
||||
upgradeParam,
|
||||
rangeFixedKey,
|
||||
rangeFloatKey,
|
||||
rangeFloat,
|
||||
effectiveProbability);
|
||||
/**
|
||||
* 抽本轮的随机数(= 该饰品位本轮「出货所需的进度」,单位:饰品价百分比)。
|
||||
* <p>
|
||||
* 水位策略启用时:在该饰品位自己的区间内,围绕「按当前水位算出的中心」抖动
|
||||
* (水位高于目标水位 → 中心下移、更容易出货;低于目标 → 上移、收紧)。
|
||||
* 中心值由目标水位反推,不需要后台手配随机数区间。
|
||||
* <p>
|
||||
* 策略关闭({@code sys_config: luckyUpgradeWatermark.enabled=false})时回退到改造前的
|
||||
* 「每个饰品位 × 每个身份一套固定幸运区间」均匀随机,便于出问题时逐字节回退。
|
||||
* <p>
|
||||
* ★ 抽数用的是**虚拟水位**(真实水位 + 已抽走但还没出货的轮次预估),并且抽完就把这一轮的
|
||||
* 预估交易预留进去 —— 这样一批饰品同时开新轮时,后面的随机数不会再按前面那个"过期"的水位放水。
|
||||
* 白号轮次不进水位口径,不参与预留。
|
||||
*/
|
||||
private int drawRoundTarget(TtUpgradeOrnaments upgradeOrnament, TtUser ttUser) {
|
||||
if (watermarkService.isEnabled()) {
|
||||
Integer[] range = resolveRange(upgradeOrnament, ttUser);
|
||||
return watermarkService.drawTarget(
|
||||
range[0], range[1], upgradeOrnament.getOrnamentPrice(), isBlankAccount(ttUser));
|
||||
}
|
||||
|
||||
// 没有,使用redis的概率区间新建,
|
||||
if (isValidRange(rangeFloat)) {
|
||||
|
||||
// 使用饰品概率区间创建新的固定概率(进度从 0 开始)
|
||||
Integer[] newRangeFixed = createRangeFixed(rangeFloat, 0);
|
||||
|
||||
// 抽奖
|
||||
return doUpgrade(
|
||||
ttUser,
|
||||
upgradeOrnament,
|
||||
newRangeFixed,
|
||||
upgradeParam,
|
||||
rangeFixedKey,
|
||||
rangeFloatKey,
|
||||
rangeFloat,
|
||||
effectiveProbability);
|
||||
}
|
||||
|
||||
// 也没有概率区间,用mysql的数据(按奖池类型取:主播/白号/普通)创建固定概率,抽奖
|
||||
String luckSection = resolveLuckSection(upgradeOrnament, ttUser);
|
||||
if (StringUtils.isNotEmpty(luckSection)) {
|
||||
rangeFloat = JSONUtil.toList(luckSection, Integer.class).toArray(new Integer[2]);
|
||||
}
|
||||
|
||||
rangeFixed = createRangeFixed(rangeFloat, 0);
|
||||
|
||||
// 缓存固定概率
|
||||
// redisCache.setCacheList(rangeFixedKey, Arrays.asList(rangeFixed));
|
||||
// redisCache.setCacheObject(rangeFixedKey, Arrays.asList(rangeFixed));
|
||||
// 缓存概率区间
|
||||
redisCache.setCacheObject(rangeFloatKey, rangeFloat, 1, TimeUnit.DAYS);
|
||||
|
||||
// 抽奖
|
||||
return doUpgrade(
|
||||
ttUser,
|
||||
upgradeOrnament,
|
||||
rangeFixed,
|
||||
upgradeParam,
|
||||
rangeFixedKey,
|
||||
rangeFloatKey,
|
||||
rangeFloat,
|
||||
effectiveProbability);
|
||||
|
||||
return legacyFixedTarget(upgradeOrnament, ttUser);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param rangeFixed 本次的固定概率
|
||||
* @param param http请求参数
|
||||
* @param rangeFixedKey redis固定概率key
|
||||
* @param rangeFloat 升级饰品的概率区间
|
||||
* @param effectiveProbability 封顶后的有效概率(仅用于中奖判定)
|
||||
* @return
|
||||
* 玩家的随机数取值区间(水位驱动时用它限定落点范围):读该饰品位 × 本身份配置的区间。
|
||||
* <p>
|
||||
* 与旧逻辑不同,这里**直接读实体的字段**(调用方的 upgradeOrnament 已查过库),不再走 Redis 区间缓存
|
||||
* —— 后台改完区间下一轮立即生效,不用清缓存。未配置 / 解析失败时用兜底区间
|
||||
* {@code [80, 160]},避免区间缺失把中心的负反馈夹死。
|
||||
*/
|
||||
private Integer[] resolveRange(TtUpgradeOrnaments upgradeOrnament, TtUser ttUser) {
|
||||
String luckSection = resolveLuckSection(upgradeOrnament, ttUser);
|
||||
if (StringUtils.isNotEmpty(luckSection)) {
|
||||
try {
|
||||
Integer[] range = JSONUtil.toList(luckSection, Integer.class).toArray(new Integer[2]);
|
||||
if (isValidRange(range) && range[0] != null && range[0] > 0 && range[0] < range[1]) {
|
||||
return range;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("解析随机数区间失败,改用兜底区间。upgradeId={}, luckSection={}",
|
||||
upgradeOrnament.getId(), luckSection, e);
|
||||
}
|
||||
}
|
||||
return new Integer[]{DEFAULT_RANGE_MIN, DEFAULT_RANGE_MAX};
|
||||
}
|
||||
|
||||
/** 随机数兜底区间:饰品未配置区间时使用 */
|
||||
private static final int DEFAULT_RANGE_MIN = 80;
|
||||
private static final int DEFAULT_RANGE_MAX = 160;
|
||||
|
||||
/** 回退分支:改造前的固定幸运区间抽法(Redis 区间缓存 + 每身份一套 luck_section) */
|
||||
private int legacyFixedTarget(TtUpgradeOrnaments upgradeOrnament, TtUser ttUser) {
|
||||
String rangeFloatKey = RedisConstants.UPGRADE_RANGE + upgradeOrnament.getId() + ":" + poolType(ttUser);
|
||||
Integer[] rangeFloat = parseRange(redisCache.getCacheObject(rangeFloatKey));
|
||||
if (!isValidRange(rangeFloat)) {
|
||||
String luckSection = resolveLuckSection(upgradeOrnament, ttUser);
|
||||
if (StringUtils.isNotEmpty(luckSection)) {
|
||||
try {
|
||||
rangeFloat = JSONUtil.toList(luckSection, Integer.class).toArray(new Integer[2]);
|
||||
} catch (Exception e) {
|
||||
log.warn("解析幸运区间失败,改用默认区间。upgradeId={}, luckSection={}",
|
||||
upgradeOrnament.getId(), luckSection, e);
|
||||
rangeFloat = null;
|
||||
}
|
||||
}
|
||||
if (isValidRange(rangeFloat)) {
|
||||
redisCache.setCacheObject(rangeFloatKey, rangeFloat, 1, TimeUnit.DAYS);
|
||||
}
|
||||
}
|
||||
return createRangeFixed(rangeFloat, 0)[1];
|
||||
}
|
||||
|
||||
public UpgradePlayResult playing(TtUser ttUser, TtUpgradeOrnaments upgradeOrnament, UpgradeBodyA upgradeParam, int effectiveProbability) {
|
||||
|
||||
Integer upgradeOrnamentId = upgradeOrnament.getId();
|
||||
// 奖池按身份分池:每个身份有自己的一份「本轮进度 + 本轮随机数」,互不影响
|
||||
// (白号中奖只刷新白号自己的随机数,普通玩家的进度与随机数原样保留,不会互相污染)
|
||||
String poolType = poolType(ttUser);
|
||||
|
||||
String rangeFixedKey = RedisConstants.UPGRADE_RANGE_FIXED + upgradeOrnamentId + ":" + poolType;
|
||||
|
||||
// 读 redis 的本轮状态 [已累计进度, 本轮随机数]
|
||||
Integer[] rangeFixed = parseRange(redisCache.getCacheObject(rangeFixedKey));
|
||||
if (isValidRange(rangeFixed) && rangeFixed[1] != null && rangeFixed[1] > 0) {
|
||||
return doUpgrade(ttUser, upgradeOrnament, rangeFixed[0], rangeFixed[1], rangeFixedKey, effectiveProbability);
|
||||
}
|
||||
|
||||
// 没有(首次 / 缓存过期 / 该身份刚中过奖):进度从 0 起,按当前水位抽一个新的随机数
|
||||
int target = drawRoundTarget(upgradeOrnament, ttUser);
|
||||
redisCache.setCacheObject(rangeFixedKey, new Integer[]{0, target}, 1, TimeUnit.DAYS);
|
||||
return doUpgrade(ttUser, upgradeOrnament, 0, target, rangeFixedKey, effectiveProbability);
|
||||
}
|
||||
|
||||
/**
|
||||
* 一次拉取的判定。
|
||||
*
|
||||
* @param currentV 本轮已累计的进度(判定口径:min(概率,75) 累加)
|
||||
* @param fullV 本轮随机数(= 本轮出货所需的进度)
|
||||
*/
|
||||
public UpgradePlayResult doUpgrade(TtUser ttUser,
|
||||
TtUpgradeOrnaments upgradeOrnament,
|
||||
Integer[] rangeFixed,
|
||||
UpgradeBodyA param,
|
||||
Integer currentV,
|
||||
Integer fullV,
|
||||
String rangeFixedKey,
|
||||
String rangeFloatKey,
|
||||
Integer[] rangeFloat,
|
||||
int effectiveProbability) {
|
||||
|
||||
// 计算进度
|
||||
Integer currentV = rangeFixed[0];
|
||||
Integer fullV = rangeFixed[1];
|
||||
int cur = currentV == null ? 0 : currentV;
|
||||
int space = (fullV == null || fullV <= 0) ? DEFAULT_ROUND_TARGET : fullV;
|
||||
|
||||
// 中奖判定使用封顶后的 effectiveProbability(如 75),而非前端原始传入的 param.getProbability()(如 90)
|
||||
int sub = fullV - (effectiveProbability + currentV);
|
||||
// 中奖判定使用封顶后的 effectiveProbability(如 75),而非前端原始传入的 90
|
||||
int sub = space - (effectiveProbability + cur);
|
||||
|
||||
if (sub > 0) {
|
||||
// 失败,记录进度
|
||||
int i = effectiveProbability + currentV;
|
||||
rangeFixed[0] = i;
|
||||
// redisCache.setCacheList(rangeFixedKey, Arrays.asList(rangeFixed));
|
||||
redisCache.setCacheObject(rangeFixedKey, rangeFixed, 1, TimeUnit.DAYS);
|
||||
return new UpgradePlayResult(false, fullV);
|
||||
// 失败:累加进度,本轮随机数不变
|
||||
redisCache.setCacheObject(rangeFixedKey, new Integer[]{effectiveProbability + cur, space}, 1, TimeUnit.DAYS);
|
||||
return new UpgradePlayResult(false, space);
|
||||
}
|
||||
|
||||
// 成功:先保存本轮目标进度(创建新的固定概率前)
|
||||
Integer currentRoundTarget = fullV;
|
||||
|
||||
// 如果没有概率区间,新建
|
||||
if (isValidRange(rangeFloat)) {
|
||||
|
||||
// 按奖池类型重新读一遍幸运区间(主播/白号/普通),后台改配置后本轮中奖即生效
|
||||
String luckSection = resolveLuckSection(upgradeOrnament, ttUser);
|
||||
if (StringUtils.isNotEmpty(luckSection)) {
|
||||
rangeFloat = JSONUtil.toList(luckSection, Integer.class).toArray(new Integer[2]);
|
||||
}
|
||||
|
||||
// 缓存概率区间
|
||||
redisCache.setCacheObject(rangeFloatKey, rangeFloat, 1, TimeUnit.DAYS);
|
||||
|
||||
// rangeFixed = createRangeFixed(rangeFloat,0);
|
||||
|
||||
}
|
||||
|
||||
// 成功,随机创建新的固定概率(进度清 0 重置,溢出不带入下一轮)
|
||||
Integer[] newRangeFixed = createRangeFixed(rangeFloat, 0);
|
||||
|
||||
// 保存新的固定概率
|
||||
// redisCache.setCacheList(rangeFixedKey, Arrays.asList(newRangeFixed));
|
||||
redisCache.setCacheObject(rangeFixedKey, newRangeFixed, 1, TimeUnit.DAYS);
|
||||
return new UpgradePlayResult(true, currentRoundTarget);
|
||||
|
||||
// 成功:本轮随机数已用掉,**只刷新当前身份自己的随机数**(其他身份的进度与随机数一律不动),
|
||||
// 进度清零;溢出部分不累计到下一轮
|
||||
int newTarget = drawRoundTarget(upgradeOrnament, ttUser);
|
||||
redisCache.setCacheObject(rangeFixedKey, new Integer[]{0, newTarget}, 1, TimeUnit.DAYS);
|
||||
return new UpgradePlayResult(true, space);
|
||||
}
|
||||
|
||||
/** 随机数兜底值:仅在 Redis 里存了非法的本轮随机数时使用(正常路径不会走到) */
|
||||
private static final int DEFAULT_ROUND_TARGET = 120;
|
||||
|
||||
public Integer[] createRangeFixed(Integer[] rangeFloat, Integer initVal) {
|
||||
|
||||
@@ -804,6 +824,11 @@ public class ApiLuckyUpgradeServiceImpl implements ApiLuckyUpgradeService {
|
||||
return range != null && range.length >= 2 && range[0] != null && range[1] != null;
|
||||
}
|
||||
|
||||
/** null 安全取整 */
|
||||
private static int nvl(Integer v) {
|
||||
return v == null ? 0 : v;
|
||||
}
|
||||
|
||||
// 扣款
|
||||
public R<Map<String, BigDecimal>> upgradeAccounting(BigDecimal consumption, TtUser player) {
|
||||
R<UpdateUserAccountBo> updateResult = userService.updateUserAccount(player.getUserId(), consumption.negate(),
|
||||
|
||||
+6
-1
@@ -15,9 +15,14 @@
|
||||
tto.rarity_name,
|
||||
tto.exterior_name,
|
||||
tol.level_img,
|
||||
-- 展示给前端的幸运值 = 三个身份累计之和 ⇒ 所有身份看到的数完全一致
|
||||
COALESCE(tuo.probability_invested, 0)
|
||||
+ COALESCE(tuo.anchor_probability_invested, 0)
|
||||
+ COALESCE(tuo.blank_probability_invested, 0) AS luckyValue,
|
||||
-- 查看者自己所属身份的累计(按登录身份注入的 userType),前端需要时才用
|
||||
CASE WHEN #{userType} = '01' THEN COALESCE(tuo.anchor_probability_invested, 0)
|
||||
WHEN #{userType} = '06' THEN COALESCE(tuo.blank_probability_invested, 0)
|
||||
ELSE COALESCE(tuo.probability_invested, 0) END AS luckyValue
|
||||
ELSE COALESCE(tuo.probability_invested, 0) END AS myLuckyValue
|
||||
FROM tt_upgrade_ornaments tuo
|
||||
LEFT JOIN tt_ornament tto ON tuo.ornaments_id = tto.id
|
||||
LEFT JOIN tt_ornaments_level tol ON LEAST(tuo.ornaments_level_id, 4) = tol.id
|
||||
|
||||
Reference in New Issue
Block a user