2025-12-21 16:04:34 +08:00
|
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
|
|
namespace app\common\library;
|
|
|
|
|
|
|
|
|
|
|
|
class LotteryGiftLua
|
|
|
|
|
|
{
|
|
|
|
|
|
// 获取Lua脚本
|
|
|
|
|
|
public static function getLotteryLuaScript()
|
|
|
|
|
|
{
|
|
|
|
|
|
return <<<LUA
|
|
|
|
|
|
-- 接收参数:send_uid, recv_uid, gift_gold, small_trigger_times, big_threshold, small_round, big_round, big_total_gold
|
|
|
|
|
|
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]) -- 大奖池当前轮次金额
|
|
|
|
|
|
|
|
|
|
|
|
-- 核心约束:强制小轮次 ≥ 大轮次
|
|
|
|
|
|
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与入参一致)
|
|
|
|
|
|
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
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
-- 5. 小奖池开奖判断(小轮次+1)
|
|
|
|
|
|
if small_total_times >= small_trigger_times then
|
|
|
|
|
|
result.is_small_prize = 1
|
|
|
|
|
|
-- 小奖随机比例
|
|
|
|
|
|
local small_ratio = math.random(2, 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. 大奖池开奖判断(大轮次+1)
|
|
|
|
|
|
if big_total_gold >= big_threshold then
|
|
|
|
|
|
result.is_big_prize = 1
|
|
|
|
|
|
-- 大奖比例权重
|
|
|
|
|
|
local weight_sum = 20 + 50 + 30
|
|
|
|
|
|
local random_weight = math.random(1, weight_sum)
|
|
|
|
|
|
local big_ratio = random_weight <= 20 and 60 or (random_weight <= 70 and 70 or 80)
|
|
|
|
|
|
-- 大奖金额
|
|
|
|
|
|
result.big_prize_amount = math.floor(big_total_gold * big_ratio / 100 * 100) / 100
|
|
|
|
|
|
result.big_release_amount = math.floor((big_total_gold - 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
|
|
|
|
|
|
|
|
|
|
|
|
-- ===================== 新增核心逻辑 =====================
|
|
|
|
|
|
-- 小奖开奖金额累加到大奖池下一轮次(新的big_round)
|
|
|
|
|
|
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
|
|
|
|
|
|
|
2025-12-21 19:08:05 +08:00
|
|
|
|
-- 返回结果
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
|
|
-- 大奖金额计算(基于开奖前的总金额)
|
2025-12-21 20:54:12 +08:00
|
|
|
|
result.big_prize_amount = math.floor(big_threshold * big_ratio / 100)
|
2025-12-21 20:59:41 +08:00
|
|
|
|
result.big_release_amount = math.floor(big_total_gold - result.big_prize_amount)
|
2025-12-21 19:08:05 +08:00
|
|
|
|
|
|
|
|
|
|
-- 重置大奖池,大轮次+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
|
|
|
|
|
|
|
2025-12-21 16:04:34 +08:00
|
|
|
|
-- 返回结果
|
|
|
|
|
|
return cjson.encode(result)
|
|
|
|
|
|
LUA;
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|