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 加载或根据玩家与 DiceLotteryPoolConfig 创建并保存 */ 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 = DiceLotteryPoolConfig::where('name', 'default')->find(); $config1 = DiceLotteryPoolConfig::where('name', 'killScore')->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(DiceLotteryPoolConfig $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_weight~t5_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 权重数组抽取档位(用于测试自定义档位概率) * @param array $tierWeights 如 ['T1'=>100, 'T2'=>200, ...] 或 [100,200,300,400,500] */ public static function drawTierByWeightsFromArray(array $tierWeights): string { $tiers = ['T1', 'T2', 'T3', 'T4', 'T5']; $weights = []; foreach ($tiers as $i => $t) { $weights[] = (int) ($tierWeights[$t] ?? $tierWeights[$i] ?? 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[random_int(0, count($tiers) - 1)]; } $r = random_int(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 = random_int(1, $total); return $r <= $paid ? 0 : 1; } public function getConfigType0Id(): ?int { return $this->configType0Id; } public function getConfigType1Id(): ?int { return $this->configType1Id; } }