| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303 |
- <?php
- namespace App\Module\GameItems\Services;
- use App\Module\Game\Services\ConsumeService;
- use App\Module\Game\Services\RewardService;
- use App\Module\GameItems\Enums\ITEM_TYPE;
- use App\Module\GameItems\Models\Item;
- use App\Module\GameItems\Models\ItemChestOpenLog;
- use App\Module\GameItems\Models\ItemChestConfig;
- use Exception;
- use Illuminate\Support\Facades\DB;
- use Illuminate\Support\Facades\Log;
- use UCore\Dto\Res;
- /**
- * 宝箱服务类 - 使用消耗组/奖励组系统
- *
- * 提供基于消耗组和奖励组的宝箱开启服务,替代原有的宝箱内容配置系统。
- * 该版本使用统一的组系统架构,提供更灵活的宝箱配置和管理功能。
- */
- class ChestService
- {
- /**
- * 开启宝箱
- *
- * @param int $userId 用户ID
- * @param int $chestId 宝箱ID
- * @param int $quantity 开启数量
- * @param array $options 选项
- * @return Res 开启结果
- * @throws Exception
- */
- public static function openChest(int $userId, int $chestId, int $quantity = 1, array $options = []): Res
- {
- // 获取宝箱信息
- $chest = Item::findOrFail($chestId);
- // 检查是否为宝箱类型
- if ($chest->type != ITEM_TYPE::CHEST) {
- throw new Exception("物品 {$chestId} 不是宝箱类型");
- }
- // 获取宝箱配置
- $chestConfig = ItemChestConfig::with([ 'consumeGroup', 'rewardGroup', 'conditionGroup' ])
- ->where('item_id', $chestId)
- ->where('is_active', true)
- ->first();
- if (!$chestConfig) {
- throw new Exception("宝箱 {$chestId} 没有配置新系统或配置未激活");
- }
- if (!$chestConfig->reward_group_id) {
- throw new Exception("宝箱 {$chestId} 没有配置奖励组");
- }
- $allResults = [];
- // 第一步:先扣除消耗组(如果有消耗组配置,支持倍率)
- if ($chestConfig->consume_group_id) {
- $consumeResult = ConsumeService::executeConsume(
- $userId,
- $chestConfig->consume_group_id,
- "开启宝箱",
- $chestId,
- true, // 检查消耗条件
- $quantity // 使用开启数量作为倍率
- );
- if (!$consumeResult->success) {
- throw new Exception("消耗验证失败: " . $consumeResult->message);
- }
- }
- // 第二步:再扣除宝箱本身(一次性扣除所有宝箱)
- $chestConsumeResult = ItemService::consumeItem(
- $userId,
- $chestId,
- null,
- $quantity,
- [
- 'source_type' => 'chest_open',
- 'source_id' => $chestId,
- 'details' => [ 'quantity' => $quantity ],
- 'ip_address' => $options['ip_address'] ?? null,
- 'device_info' => $options['device_info'] ?? null,
- ]
- );
- if (!$chestConsumeResult['success']) {
- throw new Exception("消耗宝箱失败: " . $chestConsumeResult['message']);
- }
- // 第三步:最后循环产出奖励
- for ($i = 0; $i < $quantity; $i++) {
- // 发放奖励(支持保底机制)
- $rewardResult = RewardService::grantRewardWithPity(
- $userId,
- $chestConfig->reward_group_id,
- 'chest_open',
- $chestId,
- true // 启用保底机制
- );
- if (!$rewardResult->success) {
- throw new Exception("发放奖励失败: " . ($rewardResult->errorMessage ?? '未知错误'));
- }
- // 记录本次开启结果
- $allResults[] = $rewardResult->items;
- }
- // 记录宝箱开启日志
- $openLog = ItemChestOpenLog::create([
- 'user_id' => $userId,
- 'chest_id' => $chestId,
- 'open_quantity' => $quantity,
- 'result_items' => $allResults,
- 'pity_triggered' => false, // V2版本暂不支持保底机制
- 'pity_content_id' => null,
- 'open_time' => now(),
- 'ip_address' => $options['ip_address'] ?? null,
- 'device_info' => $options['device_info'] ?? null,
- ]);
- return Res::success('成功', [
- 'openLog' => $openLog->id
- ]);
- }
- /**
- * 获取宝箱内容预览
- *
- * @param int $chestId 宝箱ID
- * @return array 宝箱内容预览
- */
- public static function getChestContentPreview(int $chestId): array
- {
- // 获取宝箱信息
- $chest = Item::findOrFail($chestId);
- // 检查是否为宝箱类型
- if ($chest->type != ITEM_TYPE::CHEST) {
- throw new Exception("物品 {$chestId} 不是宝箱类型");
- }
- // 获取宝箱配置
- $chestConfig = ItemChestConfig::with([
- 'consumeGroup.consumeItems', 'rewardGroup.rewardItems',
- 'conditionGroup'
- ])
- ->where('item_id', $chestId)
- ->where('is_active', true)
- ->first();
- $preview = [
- 'chest_id' => $chestId,
- 'chest_name' => $chest->name,
- 'version' => 'new',
- 'consume_group' => null,
- 'reward_group' => null,
- 'condition_group' => null,
- 'config_status' => $chestConfig ? 'active' : 'not_configured',
- ];
- if (!$chestConfig) {
- return $preview;
- }
- // 获取消耗组信息
- if ($chestConfig->consumeGroup) {
- $preview['consume_group'] = [
- 'id' => $chestConfig->consumeGroup->id,
- 'name' => $chestConfig->consumeGroup->name,
- 'code' => $chestConfig->consumeGroup->code,
- 'description' => $chestConfig->consumeGroup->description,
- 'items' => $chestConfig->consumeGroup->consumeItems->map(function ($item) {
- return [
- 'consume_type' => $item->consume_type,
- 'target_id' => $item->target_id,
- 'quantity' => $item->quantity,
- ];
- })->toArray(),
- ];
- }
- // 获取奖励组信息
- if ($chestConfig->rewardGroup) {
- $preview['reward_group'] = [
- 'id' => $chestConfig->rewardGroup->id,
- 'name' => $chestConfig->rewardGroup->name,
- 'code' => $chestConfig->rewardGroup->code,
- 'description' => $chestConfig->rewardGroup->description,
- 'is_random' => $chestConfig->rewardGroup->is_random,
- 'random_count' => $chestConfig->rewardGroup->random_count,
- 'reward_mode' => $chestConfig->rewardGroup->reward_mode,
- 'items' => $chestConfig->rewardGroup->rewardItems->map(function ($item) {
- return [
- 'reward_type' => $item->reward_type,
- 'target_id' => $item->target_id,
- 'quantity' => $item->quantity,
- 'weight' => $item->weight,
- 'is_guaranteed' => $item->is_guaranteed,
- ];
- })->toArray(),
- ];
- }
- // 获取条件组信息
- if ($chestConfig->conditionGroup) {
- $preview['condition_group'] = [
- 'id' => $chestConfig->conditionGroup->id,
- 'name' => $chestConfig->conditionGroup->name,
- 'code' => $chestConfig->conditionGroup->code,
- 'description' => $chestConfig->conditionGroup->description,
- ];
- }
- return $preview;
- }
- /**
- * 检查宝箱是否可以开启
- *
- * @param int $userId 用户ID
- * @param int $chestId 宝箱ID
- * @param int $quantity 开启数量
- * @return array 检查结果
- */
- public static function canOpenChest(int $userId, int $chestId, int $quantity = 1): array
- {
- try {
- // 获取宝箱信息
- $chest = Item::findOrFail($chestId);
- // 检查是否为宝箱类型
- if ($chest->type != ITEM_TYPE::CHEST) {
- return [
- 'can_open' => false,
- 'message' => "物品 {$chestId} 不是宝箱类型",
- ];
- }
- // 获取宝箱配置
- $chestConfig = ItemChestConfig::with([ 'consumeGroup' ])
- ->where('item_id', $chestId)
- ->where('is_active', true)
- ->first();
- if (!$chestConfig) {
- return [
- 'can_open' => false,
- 'message' => "宝箱 {$chestId} 没有配置新系统或配置未激活",
- ];
- }
- // 检查是否配置了奖励组
- if (!$chestConfig->reward_group_id) {
- return [
- 'can_open' => false,
- 'message' => "宝箱 {$chestId} 没有配置奖励组",
- ];
- }
- // 检查用户是否拥有足够的宝箱
- $checkResult = ItemService::checkItemQuantity($userId, $chestId, $quantity);
- if (!$checkResult->success) {
- return [
- 'can_open' => false,
- 'message' => $checkResult->message,
- ];
- }
- // 检查消耗组(如果有,支持倍率检查)
- if ($chestConfig->consume_group_id) {
- $canConsume = ConsumeService::checkConsume($userId, $chestConfig->consume_group_id, $quantity);
- if (!$canConsume->success) {
- return [
- 'can_open' => false,
- 'message' => "消耗验证失败: " . $canConsume->message,
- ];
- }
- }
- return [
- 'can_open' => true,
- 'message' => '可以开启',
- ];
- } catch (Exception $e) {
- return [
- 'can_open' => false,
- 'message' => "检查失败: " . $e->getMessage(),
- ];
- }
- }
- }
|