| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178 |
- <?php
- namespace App\Module\Game\Logics;
- use App\Module\Game\Dtos\RewardGroupDto;
- use App\Module\Game\Dtos\RewardItemDto;
- use App\Module\Game\Logics\Reward\Item;
- use App\Module\Game\Services\PityService;
- use App\Module\Game\Models\GameRewardItem;
- use Illuminate\Support\Facades\Log;
- use UCore\Exception\LogicException;
- /**
- * 权重选择模式奖励处理
- */
- class WeightSelectionReward
- {
- /**
- * 处理权重选择模式奖励
- *
- * @param RewardGroupDto $groupDto 奖励组DTO
- * @param int|null $userId 用户ID(用于保底机制)
- * @return RewardItemDto[] 要发放的奖励项
- */
- public static function process(RewardGroupDto $groupDto, ?int $userId = null,$multiplier = 1): array
- {
- $items = $groupDto->items;
- if($multiplier > 1){
- $userId = null;
- }
- // 应用保底机制调整(如果有用户ID)
- if ($userId !== null) {
- $items = self::applyPityAdjustments($userId, $items);
- }
- // 如果不是随机发放,返回所有奖励项
- if (!$groupDto->isRandom) {
- $selectedItems =[];
- foreach ($items as $item){
- $selectedItems[] = Item::processQuantity($item,$multiplier);
- }
- return $selectedItems;
- }
- if($multiplier > 1){
- throw new LogicException('倍率下,错误的进入了随机发放!');
- }
- // 随机发放:按权重选择指定数量的奖励项
- return self::processRandomSelection($groupDto, $items);
- }
- /**
- * 处理随机选择
- */
- private static function processRandomSelection(RewardGroupDto $groupDto, array $items): array
- {
- $randomCount = $groupDto->randomCount;
- // 分离必中项和普通项
- $guaranteedItems = [];
- $normalItems = [];
- foreach ($items as $item) {
- if ($item->isGuaranteed) {
- $guaranteedItems[] = $item;
- } else {
- $normalItems[] = $item;
- }
- }
- // 先选择必中项
- $selectedItems = array_map([ self::class, 'processQuantity' ], $guaranteedItems);
- // 如果必中项数量已经达到或超过随机数量,直接返回必中项
- if (count($selectedItems) >= $randomCount) {
- return array_slice($selectedItems, 0, $randomCount);
- }
- // 计算剩余需要选择的数量
- $remainingCount = $randomCount - count($selectedItems);
- // 如果没有普通项,直接返回必中项
- if (empty($normalItems)) {
- return $selectedItems;
- }
- // 按权重随机选择普通项
- $selectedNormalItems = self::selectByWeight($normalItems, $remainingCount);
- // 合并必中项和选中的普通项
- return array_merge($selectedItems, $selectedNormalItems);
- }
- /**
- * 按权重随机选择奖励项
- */
- private static function selectByWeight(array $items, int $count): array
- {
- $selectedItems = [];
- $availableItems = $items;
- for ($i = 0; $i < $count; $i++) {
- if (empty($availableItems)) {
- break;
- }
- // 计算总权重
- $totalWeight = array_sum(array_map(function ($item) {
- return $item->weight;
- }, $availableItems));
- if ($totalWeight <= 0) {
- // 如果总权重为0,随机选择
- shuffle($availableItems);
- $selectedItems[] = self::processQuantity(array_shift($availableItems));
- continue;
- }
- // 生成随机权重
- $randomWeight = mt_rand(1, $totalWeight * 100) / 100;
- $currentWeight = 0;
- // 选择奖励项
- foreach ($availableItems as $index => $item) {
- $currentWeight += $item->weight;
- if ($randomWeight <= $currentWeight) {
- $selectedItems[] = self::processQuantity($item);
- unset($availableItems[$index]);
- $availableItems = array_values($availableItems);
- break;
- }
- }
- }
- return $selectedItems;
- }
- /**
- * 处理奖励项数量(支持随机数量)
- * @deprecated
- */
- private static function processQuantity(RewardItemDto $item): RewardItemDto
- {
- return Item::processQuantity($item);
- }
- /**
- * 应用保底机制调整
- */
- private static function applyPityAdjustments(int $userId, array $items): array
- {
- try {
- // 将DTO转换为模型集合以便保底服务处理
- $rewardItemModels = collect($items)->map(function ($itemDto) {
- return GameRewardItem::find($itemDto->id);
- })->filter();
- // 应用保底机制调整权重
- $adjustedItems = PityService::applyPityAdjustments($userId, $rewardItemModels);
- // 将调整后的模型转换回DTO
- return $adjustedItems->map(function ($model) {
- return RewardItemDto::fromModel($model);
- })->toArray();
- } catch (\Exception $e) {
- Log::warning("权重选择模式:保底机制调整失败", [
- 'userId' => $userId,
- 'error' => $e->getMessage()
- ]);
- return $items; // 返回原始项目
- }
- }
- }
|