重新优化中奖权重计算方式

This commit is contained in:
2026-03-11 15:40:15 +08:00
parent bb166350fd
commit 2af7fedcce
13 changed files with 330 additions and 322 deletions

View File

@@ -13,46 +13,36 @@ use support\think\Cache;
* 奖励配置模型
*
* dice_reward_config 奖励配置
* 奖励列表为全玩家通用,保存时刷新缓存,游戏时优先读缓存。
* 按档位 T1-T5 直接权重抽取 grid_numberweight 1-10000起始索引 s_start_index / n_start_index
*
* @property $id ID
* @property $grid_number 色子点数
* @property $ui_text 前端显示文本
* @property $real_ev 真实资金结算
* @property $tier 所属档位
* @property $weight 权重%(仅 tier=BIGWIN 时可设定0-100
* @property $s_end_index 时针结束索引
* @property $n_end_index 时针结束索引
* @property $weight 权重 1-10000档位内按权重比抽取
* @property $n_start_index 时针起始索引
* @property $s_start_index 时针起始索引
* @property $remark 备注
* @property $create_time 创建时间
* @property $update_time 修改时间
*/
class DiceRewardConfig extends BaseModel
{
/** 缓存键:彩金池奖励列表实例(含列表与索引) */
/** 缓存键:彩金池奖励列表实例 */
private const CACHE_KEY_INSTANCE = 'dice:reward_config:instance';
/** 缓存过期时间(秒),保存时会主动刷新故设较长 */
private const CACHE_TTL = 86400 * 30;
/** 当前请求内已加载的实例,避免同请求多次读缓存 */
private static ?array $instance = null;
/**
* 数据表主键
* @var string
*/
protected $pk = 'id';
/**
* 数据库表名称
* @var string
*/
protected $table = 'dice_reward_config';
/**
* 获取彩金池实例(含 list / 索引),无则从库加载并写入缓存;同请求内复用
* @return array{list: array, by_tier: array, by_tier_grid: array, by_s_end_index: array, by_n_end_index: array, min_real_ev: float}
* 获取彩金池实例(含 list / by_tier / by_tier_grid),无则从库加载并写入缓存
* @return array{list: array, by_tier: array, by_tier_grid: array, min_real_ev: float}
*/
public static function getCachedInstance(): array
{
@@ -70,10 +60,6 @@ class DiceRewardConfig extends BaseModel
return self::$instance;
}
/**
* 获取缓存的奖励列表(无则从库加载并写入缓存)
* @return array<int, array>
*/
public static function getCachedList(): array
{
$inst = self::getCachedInstance();
@@ -81,26 +67,20 @@ class DiceRewardConfig extends BaseModel
}
/**
* 重新从数据库加载并写入缓存(DiceRewardConfig 新增/修改/删除后调用),构建列表与索引
* 实例化结果含完整行(含 weight供 playStart 从缓存中查找 BIGWIN 的 weight 按概率抽奖
* 重新从数据库加载并写入缓存(按档位+权重抽 grid_number含 by_tier、by_tier_grid
*/
public static function refreshCache(): void
{
$list = (new self())->order('id', 'asc')->select()->toArray();
$byTier = [];
$byTierGrid = [];
$bySEndIndex = [];
$byNEndIndex = [];
foreach ($list as $row) {
$tier = isset($row['tier']) ? (string) $row['tier'] : '';
if ($tier !== '') {
// 过滤 tier=BIGWIN不参与档位抽奖仅豹子时通过 getCachedByTierAndGridNumber('BIGWIN', ...) 使用
if ($tier !== 'BIGWIN') {
if (!isset($byTier[$tier])) {
$byTier[$tier] = [];
}
$byTier[$tier][] = $row;
if (!isset($byTier[$tier])) {
$byTier[$tier] = [];
}
$byTier[$tier][] = $row;
$gridNum = isset($row['grid_number']) ? (int) $row['grid_number'] : 0;
if (!isset($byTierGrid[$tier])) {
$byTierGrid[$tier] = [];
@@ -109,48 +89,29 @@ class DiceRewardConfig extends BaseModel
$byTierGrid[$tier][$gridNum] = $row;
}
}
$sEnd = isset($row['s_end_index']) ? (int) $row['s_end_index'] : 0;
if (!isset($bySEndIndex[$sEnd])) {
$bySEndIndex[$sEnd] = [];
}
$bySEndIndex[$sEnd][] = $row;
$nEnd = isset($row['n_end_index']) ? (int) $row['n_end_index'] : 0;
if (!isset($byNEndIndex[$nEnd])) {
$byNEndIndex[$nEnd] = [];
}
$byNEndIndex[$nEnd][] = $row;
}
$minRealEv = empty($list) ? 0.0 : (float) min(array_column($list, 'real_ev'));
self::$instance = [
'list' => $list,
'by_tier' => $byTier,
'by_tier_grid' => $byTierGrid,
'by_s_end_index' => $bySEndIndex,
'by_n_end_index' => $byNEndIndex,
'min_real_ev' => $minRealEv,
'list' => $list,
'by_tier' => $byTier,
'by_tier_grid' => $byTierGrid,
'min_real_ev' => $minRealEv,
];
Cache::set(self::CACHE_KEY_INSTANCE, self::$instance, self::CACHE_TTL);
}
/** 空实例结构 */
private static function buildEmptyInstance(): array
{
return [
'list' => [],
'by_tier' => [],
'by_tier_grid' => [],
'by_s_end_index' => [],
'by_n_end_index' => [],
'min_real_ev' => 0.0,
'list' => [],
'by_tier' => [],
'by_tier_grid' => [],
'min_real_ev' => 0.0,
];
}
/**
* 从缓存实例按档位 + 色子点数取一条奖励配置(用于超级大奖 tier=BIGWIN + grid_number=roll_number
* 返回行含 weight0-100playStart 据此概率抽奖weight=100 表示摇到该 roll_number 时 100% 中超级大奖
* @param string $tier 档位,如 BIGWIN
* @param int $gridNumber 色子点数(摇出总和 roll_number
* @return array|null 配置行(含 weight、real_ev 等)或 null
* 按档位+色子点数取一条(用于 BIGWIN
*/
public static function getCachedByTierAndGridNumber(string $tier, int $gridNumber): ?array
{
@@ -161,9 +122,6 @@ class DiceRewardConfig extends BaseModel
return is_array($row) ? $row : null;
}
/**
* 从缓存取最小 real_ev
*/
public static function getCachedMinRealEv(): float
{
$inst = self::getCachedInstance();
@@ -171,8 +129,7 @@ class DiceRewardConfig extends BaseModel
}
/**
* 从缓存按档位取奖励列表
* @return array<int, array>
* 从缓存按档位取奖励列表(含 weight用于按权重抽 grid_number
*/
public static function getCachedByTier(string $tier): array
{
@@ -181,55 +138,26 @@ class DiceRewardConfig extends BaseModel
return $byTier[$tier] ?? [];
}
/**
* 从缓存按顺时针结束索引取列表s_end_index = id 的配置)
* @return array<int, array>
*/
public static function getCachedBySEndIndex(int $id): array
{
$inst = self::getCachedInstance();
$by = $inst['by_s_end_index'] ?? [];
return $by[$id] ?? [];
}
/**
* 从缓存按逆时针结束索引取列表n_end_index = id 的配置)
* @return array<int, array>
*/
public static function getCachedByNEndIndex(int $id): array
{
$inst = self::getCachedInstance();
$by = $inst['by_n_end_index'] ?? [];
return $by[$id] ?? [];
}
/**
* 清除当前请求内实例(如测试或需强制下次读缓存时调用)
*/
public static function clearRequestInstance(): void
{
self::$instance = null;
}
/** 保存后刷新缓存 */
public static function onAfterInsert($model): void
{
self::refreshCache();
}
/** 更新后刷新缓存 */
public static function onAfterUpdate($model): void
{
self::refreshCache();
}
/** 删除后刷新缓存 */
public static function onAfterDelete($model): void
{
self::refreshCache();
}
/** 色子点数下限 */
public function searchGridNumberMinAttr($query, $value)
{
if ($value !== '' && $value !== null) {
@@ -237,7 +165,6 @@ class DiceRewardConfig extends BaseModel
}
}
/** 色子点数上限 */
public function searchGridNumberMaxAttr($query, $value)
{
if ($value !== '' && $value !== null) {
@@ -245,7 +172,6 @@ class DiceRewardConfig extends BaseModel
}
}
/** 前端显示文本模糊 */
public function searchUiTextAttr($query, $value)
{
if ($value !== '' && $value !== null) {
@@ -253,7 +179,6 @@ class DiceRewardConfig extends BaseModel
}
}
/** 真实资金结算下限 */
public function searchRealEvMinAttr($query, $value)
{
if ($value !== '' && $value !== null) {
@@ -261,7 +186,6 @@ class DiceRewardConfig extends BaseModel
}
}
/** 真实资金结算上限 */
public function searchRealEvMaxAttr($query, $value)
{
if ($value !== '' && $value !== null) {
@@ -269,7 +193,6 @@ class DiceRewardConfig extends BaseModel
}
}
/** 所属档位 */
public function searchTierAttr($query, $value)
{
if ($value !== '' && $value !== null) {
@@ -277,7 +200,6 @@ class DiceRewardConfig extends BaseModel
}
}
/** 权重下限(仅 tier=BIGWIN 时有意义) */
public function searchWeightMinAttr($query, $value)
{
if ($value !== '' && $value !== null) {
@@ -285,7 +207,6 @@ class DiceRewardConfig extends BaseModel
}
}
/** 权重上限 */
public function searchWeightMaxAttr($query, $value)
{
if ($value !== '' && $value !== null) {