Files
dafuweng-saiadmin6.x/server/app/api/service/LotteryService.php
2026-03-07 10:07:44 +08:00

162 lines
5.2 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
declare(strict_types=1);
namespace app\api\service;
use app\dice\model\lottery_config\DiceLotteryConfig;
use app\dice\model\player\DicePlayer;
use support\think\Cache;
/**
* 彩金池实例,按玩家权重与奖池配置创建,存 Redis 便于增删改查
*/
class LotteryService
{
private const REDIS_KEY_PREFIX = 'api:game:lottery_pool:';
private const REDIS_KEY_START_INDEX = 'api:game:start_index:';
private const EXPIRE = 86400 * 7; // 7天
private int $playerId;
private ?int $configType0Id = null;
private ?int $configType1Id = null;
/** @var array{t1_weight?:int,t2_weight?:int,t3_weight?:int,t4_weight?:int,t5_weight?:int} */
private array $playerWeights = [];
public function __construct(int $playerId)
{
$this->playerId = $playerId;
}
public static function getRedisKey(int $playerId): string
{
return self::REDIS_KEY_PREFIX . $playerId;
}
public static function getStartIndexKey(int $playerId): string
{
return self::REDIS_KEY_START_INDEX . $playerId;
}
/** 从 Redis 加载或根据玩家与 DiceLotteryConfig 创建并保存 */
public static function getOrCreate(int $playerId): self
{
$key = self::getRedisKey($playerId);
$cached = Cache::get($key);
if ($cached && is_string($cached)) {
$data = json_decode($cached, true);
if (is_array($data)) {
$s = new self($playerId);
$s->configType0Id = (int) ($data['config_type_0_id'] ?? 0);
$s->configType1Id = (int) ($data['config_type_1_id'] ?? 0);
$s->playerWeights = $data['player_weights'] ?? [];
return $s;
}
}
$player = DicePlayer::find($playerId);
if (!$player) {
throw new \RuntimeException('玩家不存在');
}
$config0 = DiceLotteryConfig::where('type', 0)->find();
$config1 = DiceLotteryConfig::where('type', 1)->find();
$s = new self($playerId);
$s->configType0Id = $config0 ? (int) $config0->id : null;
$s->configType1Id = $config1 ? (int) $config1->id : null;
$s->playerWeights = [
't1_weight' => (int) ($player->t1_weight ?? 0),
't2_weight' => (int) ($player->t2_weight ?? 0),
't3_weight' => (int) ($player->t3_weight ?? 0),
't4_weight' => (int) ($player->t4_weight ?? 0),
't5_weight' => (int) ($player->t5_weight ?? 0),
];
$s->save();
return $s;
}
public function save(): void
{
$key = self::getRedisKey($this->playerId);
$data = [
'config_type_0_id' => $this->configType0Id,
'config_type_1_id' => $this->configType1Id,
'player_weights' => $this->playerWeights,
];
Cache::set($key, json_encode($data), self::EXPIRE);
}
/** 根据奖池配置的 t1_weight..t5_weight 权重随机抽取档位 T1-T5 */
public static function drawTierByWeights(DiceLotteryConfig $config): string
{
$tiers = ['T1', 'T2', 'T3', 'T4', 'T5'];
$weights = [
(int) ($config->t1_weight ?? 0),
(int) ($config->t2_weight ?? 0),
(int) ($config->t3_weight ?? 0),
(int) ($config->t4_weight ?? 0),
(int) ($config->t5_weight ?? 0),
];
return self::drawTierByWeightArray($tiers, $weights);
}
/**
* 根据玩家 t1_weightt5_weight 权重随机抽取中奖档位 T1-T5
* t1_weight=T1, t2_weight=T2, t3_weight=T3, t4_weight=T4, t5_weight=T5
*/
public static function drawTierByPlayerWeights(DicePlayer $player): string
{
$tiers = ['T1', 'T2', 'T3', 'T4', 'T5'];
$weights = [
(int) ($player->t1_weight ?? 0),
(int) ($player->t2_weight ?? 0),
(int) ($player->t3_weight ?? 0),
(int) ($player->t4_weight ?? 0),
(int) ($player->t5_weight ?? 0),
];
return self::drawTierByWeightArray($tiers, $weights);
}
/** 按档位权重数组抽取 T1-T5 */
private static function drawTierByWeightArray(array $tiers, array $weights): string
{
$total = array_sum($weights);
if ($total <= 0) {
return $tiers[array_rand($tiers)];
}
$r = mt_rand(1, $total);
$acc = 0;
foreach ($weights as $i => $w) {
$acc += $w;
if ($r <= $acc) {
return $tiers[$i];
}
}
return $tiers[4];
}
/** 按 paid_ticket_count 与 free_ticket_count 权重随机抽取 0=付费 1=免费 */
public static function drawTicketType(int $paid, int $free): int
{
if ($paid <= 0 && $free <= 0) {
throw new \RuntimeException('抽奖券不足');
}
if ($paid <= 0) {
return 1;
}
if ($free <= 0) {
return 0;
}
$total = $paid + $free;
$r = mt_rand(1, $total);
return $r <= $paid ? 0 : 1;
}
public function getConfigType0Id(): ?int
{
return $this->configType0Id;
}
public function getConfigType1Id(): ?int
{
return $this->configType1Id;
}
}