where('reward_group_id', $rewardGroupId) ->with('rewardItem') ->get(); } /** * 初始化用户的保底计数 * * @param int $userId 用户ID * @param int $rewardGroupId 奖励组ID * @return void */ public static function initializePityCounts(int $userId, int $rewardGroupId): void { // 获取奖励组中启用保底的奖励项 $pityEnabledItems = GameRewardItem::where('group_id', $rewardGroupId) ->where('pity_enabled', true) ->where('pity_threshold', '>', 0) ->get(); foreach ($pityEnabledItems as $item) { // 检查是否已存在保底计数记录 $existingCount = GameRewardGroupPityCount::where('user_id', $userId) ->where('reward_group_id', $rewardGroupId) ->where('reward_item_id', $item->id) ->first(); if (!$existingCount) { // 创建新的保底计数记录 GameRewardGroupPityCount::create([ 'user_id' => $userId, 'reward_group_id' => $rewardGroupId, 'reward_item_id' => $item->id, 'count' => 0, 'pity_threshold' => $item->pity_threshold, 'last_attempt_at' => now(), ]); } } } /** * 应用保底机制调整奖励权重 * * @param int $userId 用户ID * @param Collection $rewardItems 奖励项集合 * @return Collection 调整后的奖励项集合 */ public static function applyPityAdjustments(int $userId, Collection $rewardItems): Collection { if ($rewardItems->isEmpty()) { return $rewardItems; } $rewardGroupId = $rewardItems->first()->group_id; // 初始化保底计数(如果需要) self::initializePityCounts($userId, $rewardGroupId); // 获取用户的保底计数 $pityCounts = self::getUserPityCounts($userId, $rewardGroupId); $pityCountsMap = $pityCounts->keyBy('reward_item_id'); // 调整每个奖励项的权重 return $rewardItems->map(function (GameRewardItem $item) use ($pityCountsMap) { $pityCount = $pityCountsMap->get($item->id); if ($pityCount && $item->pity_enabled && $item->pity_threshold > 0) { // 计算调整后的权重 $adjustedWeight = $pityCount->getAdjustedWeight( $item->weight, $item->pity_weight_factor ); // 创建一个新的奖励项实例,避免修改原始数据 $adjustedItem = clone $item; $adjustedItem->weight = $adjustedWeight; // 添加保底信息到额外数据中 $extraData = $adjustedItem->extra_data ?: []; $extraData['pity_info'] = [ 'current_count' => $pityCount->count, 'threshold' => $pityCount->pity_threshold, 'is_at_threshold' => $pityCount->isAtPityThreshold(), 'original_weight' => $item->weight, 'adjusted_weight' => $adjustedWeight, ]; $adjustedItem->extra_data = $extraData; return $adjustedItem; } return $item; }); } /** * 更新保底计数 * * @param int $userId 用户ID * @param int $rewardGroupId 奖励组ID * @param array $obtainedItemIds 获得的奖励项ID数组 * @return void */ public static function updatePityCounts(int $userId, int $rewardGroupId, array $obtainedItemIds): void { // 获取用户的保底计数 $pityCounts = self::getUserPityCounts($userId, $rewardGroupId); foreach ($pityCounts as $pityCount) { if (in_array($pityCount->reward_item_id, $obtainedItemIds)) { // 获得了该奖励项,重置计数 $pityCount->resetCount(); } else { // 未获得该奖励项,增加计数 $pityCount->incrementCount(); } } } /** * 检查是否有保底触发 * * @param int $userId 用户ID * @param int $rewardGroupId 奖励组ID * @return array 触发保底的奖励项ID数组 */ public static function checkPityTriggers(int $userId, int $rewardGroupId): array { $pityCounts = self::getUserPityCounts($userId, $rewardGroupId); $triggeredItems = []; foreach ($pityCounts as $pityCount) { if ($pityCount->isAtPityThreshold()) { $triggeredItems[] = $pityCount->reward_item_id; } } return $triggeredItems; } /** * 获取用户保底状态信息 * * @param int $userId 用户ID * @param int $rewardGroupId 奖励组ID * @return array */ public static function getPityStatus(int $userId, int $rewardGroupId): array { $pityCounts = self::getUserPityCounts($userId, $rewardGroupId); $status = []; foreach ($pityCounts as $pityCount) { $rewardItem = $pityCount->rewardItem; $status[] = [ 'reward_item_id' => $pityCount->reward_item_id, 'reward_item_name' => $rewardItem ? $rewardItem->getTargetName() : '未知奖励', 'current_count' => $pityCount->count, 'threshold' => $pityCount->pity_threshold, 'progress_percentage' => $pityCount->pity_threshold > 0 ? round(($pityCount->count / $pityCount->pity_threshold) * 100, 2) : 0, 'is_at_threshold' => $pityCount->isAtPityThreshold(), 'last_attempt_at' => $pityCount->last_attempt_at, 'last_hit_at' => $pityCount->last_hit_at, ]; } return $status; } /** * 重置用户的所有保底计数 * * @param int $userId 用户ID * @param int $rewardGroupId 奖励组ID * @return void */ public static function resetAllPityCounts(int $userId, int $rewardGroupId): void { GameRewardGroupPityCount::where('user_id', $userId) ->where('reward_group_id', $rewardGroupId) ->update([ 'count' => 0, 'last_hit_at' => now(), ]); } /** * 清理过期的保底计数记录 * * @param int $daysOld 清理多少天前的记录 * @return int 清理的记录数量 */ public static function cleanupOldPityCounts(int $daysOld = 90): int { $cutoffDate = now()->subDays($daysOld); return GameRewardGroupPityCount::where('last_attempt_at', '<', $cutoffDate) ->where('count', 0) ->delete(); } }