This commit is contained in:
2025-12-21 19:08:05 +08:00
parent 6e81a0942f
commit 33450890aa
4 changed files with 178 additions and 6 deletions

View File

@@ -189,7 +189,8 @@ class Room extends BaseCom
$pit_number = input('pit_number', 0);
$heart_id = input('heart_id', 0);
if($gift_id == 88){
$pool_gift_id = db::name('bb_lottery_config')->where(['key' => 'pool_gift_id'])->value('value');
if($gift_id == $pool_gift_id){
$reslut = model('Lottery')->gift($this->uid, $to_uid, $gift_id, $room_id,$gift_num);
}else{
$reslut = model('Room')->room_gift($this->uid, $to_uid, $gift_id, $gift_num, $type, $room_id, $pit_number,$heart_id);

View File

@@ -23,8 +23,11 @@ class Lottery extends Model
if(in_array($send_uid,$toarray)){
return ['code' => 0, 'msg' => '收礼人不能包含自己', 'data' => null];
}
//获取礼物信息
$gift_info = Db::name('vs_gift')->where(['gid'=>$gift_id])
->field('gid as gift_id,gift_name,gift_price,file_type,base_image,play_image,gift_type,label,is_public_server')->find();
//送给所有人的总价格
$all_gift_price = $gift_info['gift_price'] * $num * count($toarray);
//判断是否有足够的金币

View File

@@ -126,6 +126,148 @@ if small_total_times >= small_trigger_times then
end
end
-- 返回结果
return cjson.encode(result)
LUA;
}
// 获取Lua脚本
public static function getLotteryLuaScripts()
{
return <<<LUA
-- 接收参数:
-- send_uid, recv_uid, gift_gold, small_trigger_times, big_threshold,
-- small_round, big_round, big_total_gold,
-- big_weight_60, big_weight_70, big_weight_80, big_weight_total
local send_uid = ARGV[1]
local recv_uid = ARGV[2]
local gift_gold = tonumber(ARGV[3])
local small_trigger_times = tonumber(ARGV[4])
local big_threshold = tonumber(ARGV[5])
local small_round = tonumber(ARGV[6])
local big_round = tonumber(ARGV[7])
local big_total_gold = tonumber(ARGV[8])
local big_weight_60 = tonumber(ARGV[9])
local big_weight_70 = tonumber(ARGV[10])
local big_weight_80 = tonumber(ARGV[11])
local big_weight_total = tonumber(ARGV[12])
-- 核心约束:强制小轮次 ≥ 大轮次
if small_round < big_round then
small_round = big_round
end
-- 1. 基础金额拆分
local recv_gold = gift_gold * 0.5
local small_pool_add = gift_gold * 0.5
-- 2. Redis键定义
local small_round_key = "lottery:small_pool:round"
local small_total_times_key = "lottery:small_pool:total_times"
local small_total_gold_key = "lottery:small_pool:total_gold"
local big_round_key = "lottery:big_pool:round"
local big_total_gold_key = "lottery:big_pool:total_gold"
-- 初始化轮次
redis.call('set', small_round_key, small_round)
redis.call('set', big_round_key, big_round)
if big_total_gold == 0 or big_total_gold == nil then
big_total_gold = tonumber(redis.call('get', big_total_gold_key) or 0)
end
-- 3. 小奖池累计更新
local small_total_times = tonumber(redis.call('incr', small_total_times_key))
local small_total_gold = tonumber(redis.call('get', small_total_gold_key) or 0)
small_total_gold = math.floor((small_total_gold + small_pool_add) * 100) / 100
redis.call('set', small_total_gold_key, small_total_gold)
-- 4. 返回结果初始化
local result = {
send_uid = send_uid,
recv_uid = recv_uid,
gift_gold = gift_gold,
recv_gold = recv_gold,
small_pool_add = small_pool_add,
small_total_times = small_total_times,
small_total_gold = small_total_gold,
is_small_prize = 0,
small_prize_amount = 0,
small_remain_amount = 0,
is_big_prize = 0,
big_prize_amount = 0,
big_release_amount = 0,
small_round = small_round,
big_round = big_round,
big_total_gold = big_total_gold,
small_prize_to_big_next_round = 0,
big_ratio = 0,
-- ===================== 新增核心字段 =====================
big_pool_total_before_open = 0 -- 大奖开奖前的奖池总金额
-- ======================================================
}
-- 5. 小奖池开奖判断
if small_total_times >= small_trigger_times then
result.is_small_prize = 1
-- 小奖随机比例
local small_ratio = math.random(1, 99)
result.small_prize_amount = math.floor(small_total_gold * small_ratio / 100 * 100) / 100
result.small_remain_amount = math.floor((small_total_gold - result.small_prize_amount) * 100) / 100
-- 重置小奖池,小轮次+1
redis.call('set', small_total_times_key, 0)
redis.call('set', small_total_gold_key, 0)
small_round = small_round + 1
redis.call('set', small_round_key, small_round)
result.small_round = small_round
-- 6. 小奖剩余划入大奖池当前轮次
big_total_gold = math.floor((big_total_gold + result.small_remain_amount) * 100) / 100
redis.call('set', big_total_gold_key, big_total_gold)
result.big_total_gold = big_total_gold
-- 7. 大奖池开奖判断
if big_total_gold >= big_threshold then
-- ===================== 关键修改:记录开奖前总金额 =====================
result.big_pool_total_before_open = big_total_gold -- 保存开奖前的总金额
-- ======================================================
result.is_big_prize = 1
-- 从配置读取权重计算出奖比例
local random_weight = math.random(1, big_weight_total)
local big_ratio = 60
if random_weight > big_weight_60 and random_weight <= (big_weight_60 + big_weight_70) then
big_ratio = 70
elseif random_weight > (big_weight_60 + big_weight_70) then
big_ratio = 80
end
result.big_ratio = big_ratio
-- 大奖金额计算(基于开奖前的总金额)
result.big_prize_amount = math.floor(result.big_pool_total_before_open * big_ratio / 100 * 100) / 100
result.big_release_amount = math.floor((result.big_pool_total_before_open - result.big_prize_amount) * 100) / 100
-- 重置大奖池,大轮次+1
redis.call('set', big_total_gold_key, 0)
big_round = big_round + 1
redis.call('set', big_round_key, big_round)
if small_round < big_round then
small_round = big_round
redis.call('set', small_round_key, small_round)
result.small_round = small_round
end
result.big_round = big_round
result.big_total_gold = 0
-- 小奖开奖金额划入大奖池下一轮
result.small_prize_to_big_next_round = result.small_prize_amount
local new_big_total_gold = math.floor(result.small_prize_amount * 100) / 100
redis.call('set', big_total_gold_key, new_big_total_gold)
result.big_total_gold = new_big_total_gold
end
end
-- 返回结果
return cjson.encode(result)
LUA;

View File

@@ -12,6 +12,7 @@ class LotteryService
private $redis;
// 配置参数
private $config;
private $bigPrizeWeights;
public function __construct()
{
@@ -19,10 +20,31 @@ class LotteryService
// 加载配置
$this->config = Db::name('bb_lottery_config')->column('value', 'key');
// 初始化Redis缓存若Redis数据丢失从数据库恢复
$this->initBigPrizeWeights();
$this->initRedisFromDb();
$this->checkRoundConstraint();
}
private function initBigPrizeWeights()
{
$this->bigPrizeWeights = [
'60' => intval($this->config['big_prize_ratio_60_weight'] ?? 20),
'70' => intval($this->config['big_prize_ratio_70_weight'] ?? 50),
'80' => intval($this->config['big_prize_ratio_80_weight'] ?? 30)
];
$this->bigPrizeWeights['total'] = array_sum($this->bigPrizeWeights);
}
private function checkRoundConstraint()
{
$small_round = intval($this->redis->get('lottery:small_pool:round') ?: 1);
$big_round = intval($this->redis->get('lottery:big_pool:round') ?: 1);
if ($small_round < $big_round) {
$this->redis->set('lottery:small_pool:round', $big_round);
}
}
/**
* 缓存恢复:独立恢复大小轮次+对应金额
*/
@@ -92,13 +114,17 @@ class LotteryService
$big_total_gold = floatval($this->redis->get('lottery:big_pool:total_gold') ?: 0);
// 加载Lua脚本
$luaSha = LotteryGiftLua::getLotteryLuaScript();
$luaSha = LotteryGiftLua::getLotteryLuaScripts();
// 执行Lua脚本入参small_round + big_round
$result = $this->redis->eval($luaSha, [
$send_uid, 0, $gift_gold,
$small_trigger_times, $big_threshold,
$small_round, $big_round, $big_total_gold
$small_round, $big_round, $big_total_gold,
$this->bigPrizeWeights['60'],
$this->bigPrizeWeights['70'],
$this->bigPrizeWeights['80'],
$this->bigPrizeWeights['total']
], 0);
// var_dump($result);die;
$result = json_decode($result, true);
@@ -143,8 +169,8 @@ class LotteryService
$winnerUid,
2, // 大奖
$result['big_prize_amount'],//中奖金额
$result['big_total_gold'], // 开奖时大奖池金额
$this->getBigRatio($result['big_prize_amount'], $result['big_total_gold']),
$result['big_pool_total_before_open'], // 开奖时大奖池金额
$result['big_ratio'],
$result['big_release_amount']//释放金额
);
@@ -153,7 +179,7 @@ class LotteryService
2, // 大奖池
4, // 释放
-$result['big_release_amount'],//释放金额
$result['big_total_gold'],// 开奖时大奖池金额
$result['big_pool_total_before_open'],// 开奖时大奖池金额
0,
$giftId,
$result['big_round'] - 1, // 关联已结束的小奖池轮次