where('status', $filters['status']); } if (isset($filters['min_level'])) { $query->where('level', '>=', $filters['min_level']); } if (isset($filters['max_level'])) { $query->where('level', '<=', $filters['max_level']); } return $query->get(); } /** * 创建宠物 * * 注意:调用此方法前,请确保已开启数据库事务 * * @param int $userId 用户ID * @param string $name 宠物名称 * @param array $options 其他选项 * @return array 创建结果 * @throws Exception */ public static function createPet(int $userId, string $name, array $options = []): array { // 验证事务是否已开启 Helper::check_tr(); try { // 创建宠物逻辑 $petLogic = new PetLogic(); // 创建宠物 $result = $petLogic->createPet($userId, $name, $options); return [ 'success' => true, 'pet_id' => $result['pet_id'], 'name' => $name, 'level' => 1, 'message' => '宠物创建成功' ]; } catch (Exception $e) { Log::error('创建宠物失败', [ 'user_id' => $userId, 'name' => $name, 'error' => $e->getMessage() ]); throw $e; } } /** * 宠物喂养 * * 注意:调用此方法前,请确保已开启数据库事务 * * @param int $userId 用户ID * @param int $petId 宠物ID * @param int $itemId 物品ID(狗粮) * @param int $amount 数量 * @return array 喂养结果 * @throws Exception */ public static function feedPet(int $userId, int $petId, int $itemId, int $amount = 1): Res { // 验证事务是否已开启 Helper::check_tr(); // 宠物逻辑 $petLogic = new PetLogic(); // 获取宠物信息 $pet = PetUser::where('id', $petId) ->where('user_id', $userId) ->first(); if (!$pet) { throw new LogicException("宠物不存在或不属于该用户"); } // 检查宠物状态 if ($pet->status !== PetStatus::NORMAL) { throw new LogicException("宠物当前状态不允许喂养"); } // 执行喂养逻辑 $result = $petLogic->feedPet($petId, $itemId, $amount); return Res::success('', [ 'pet_id' => $petId, 'item_id' => $itemId, 'amount' => $amount ]); } /** * 使用宠物技能 * * 注意:调用此方法前,请确保已开启数据库事务 * * @param int $userId 用户ID * @param int $petId 宠物ID * @param int $skillId 技能ID * @param array $params 技能参数 * @return array 技能使用结果 * @throws Exception */ public static function useSkill(int $userId, int $petId, int $skillId, array $params = []): array { // 验证事务是否已开启 Helper::check_tr(); try { // 宠物逻辑 $petLogic = new PetLogic(); // 获取宠物信息 $pet = PetUser::where('id', $petId) ->where('user_id', $userId) ->first(); if (!$pet) { throw new Exception("宠物不存在或不属于该用户"); } // 获取技能信息 /** * @var PetSkill $skill */ $skill = PetSkill::find($skillId); if (!$skill) { throw new Exception("技能不存在"); } // 检查宠物状态 if ($pet->status !== PetStatus::NORMAL) { throw new Exception("宠物当前状态不允许使用技能"); } // 检查宠物当前等级是否可以使用该技能(基于等级配置表) if (!self::checkPetSkillAvailable($pet, $skillId)) { throw new Exception("该技能在当前等级不可用"); } // 检查宠物体力是否足够 if ($pet->stamina < $skill->stamina_cost) { throw new Exception("宠物体力不足,无法使用该技能"); } // 执行技能使用逻辑 $result = $petLogic->useSkill($petId, $skillId, $params); return [ 'success' => true, 'pet_id' => $petId, 'skill_id' => $skillId, 'stamina_cost' => $skill->stamina_cost, 'effect_result' => $result['effect_result'], 'message' => '技能使用成功' ]; } catch (Exception $e) { Log::error('使用宠物技能失败', [ 'user_id' => $userId, 'pet_id' => $petId, 'skill_id' => $skillId, 'params' => $params, 'error' => $e->getMessage() ]); throw $e; } } /** * 获取宠物状态 * * @param int $userId 用户ID * @param int $petId 宠物ID * @return PetDataDto 宠物状态信息,参考DataPet结构,包括技能情况 * @throws Exception */ public static function getPetStatus(int $userId, int $petId): PetDataDto { // 获取宠物信息 $pet = PetUser::where('id', $petId) ->where('user_id', $userId) ->first(); if (!$pet) { throw new Exception("宠物不存在或不属于该用户"); } // 计算宠物战力 $petLogic = new PetLogic(); $fightingCapacity = $petLogic->calculatePower($petId); // 使用工厂类创建宠物DTO $petDto = PetDtoFactory::createPetDataDto($pet, $fightingCapacity); // 直接返回DTO对象 return $petDto; } /** * 更新宠物状态 * * 注意:调用此方法前,请确保已开启数据库事务 * * @param int $userId 用户ID * @param int $petId 宠物ID * @param PetStatus $status 新状态 * @param string $reason 变更原因 * @return bool 是否更新成功 * @throws Exception */ public static function updatePetStatus(int $userId, int $petId, PetStatus $status, string $reason = ''): bool { // 验证事务是否已开启 Helper::check_tr(); try { // 宠物逻辑 $petLogic = new PetLogic(); // 获取宠物信息 $pet = PetUser::where('id', $petId) ->where('user_id', $userId) ->first(); if (!$pet) { throw new Exception("宠物不存在或不属于该用户"); } // 记录旧状态 $oldStatus = $pet->status; // 执行状态变更逻辑 $result = $petLogic->changeStatus($petId, $status, $reason); return true; } catch (Exception $e) { Log::error('更新宠物状态失败', [ 'user_id' => $userId, 'pet_id' => $petId, 'status' => $status->value, 'reason' => $reason, 'error' => $e->getMessage() ]); throw $e; } } /** * 恢复宠物体力 * * 注意:调用此方法前,请确保已开启数据库事务 * * @param int $userId 用户ID * @param int $petId 宠物ID * @param int $minutes 经过的分钟数 * @return array 恢复结果 * @throws Exception */ public static function recoverStamina(int $userId, int $petId, int $minutes): array { // 验证事务是否已开启 Helper::check_tr(); try { // 宠物逻辑 $petLogic = new PetLogic(); // 获取宠物信息 $pet = PetUser::where('id', $petId) ->where('user_id', $userId) ->first(); if (!$pet) { throw new Exception("宠物不存在或不属于该用户"); } // 执行体力恢复逻辑 $recoveredStamina = $petLogic->recoverStamina($petId, $minutes); return [ 'success' => true, 'pet_id' => $petId, 'recovered_stamina' => $recoveredStamina, 'current_stamina' => $pet->fresh()->stamina, 'message' => '宠物体力恢复成功' ]; } catch (Exception $e) { Log::error('恢复宠物体力失败', [ 'user_id' => $userId, 'pet_id' => $petId, 'minutes' => $minutes, 'error' => $e->getMessage() ]); throw $e; } } /** * 获取宠物可用技能列表 * * @param int $userId 用户ID * @param int $petId 宠物ID * @return array 技能列表 * @throws Exception */ public static function getPetSkills(int $userId, int $petId): array { // 获取宠物信息 $pet = PetUser::where('id', $petId) ->where('user_id', $userId) ->first(); if (!$pet) { throw new Exception("宠物不存在或不属于该用户"); } // 获取所有技能 $allSkills = PetSkill::all(); // 筛选出宠物等级可用的技能(基于等级配置表) $availableSkills = $allSkills->filter(function ($skill) use ($pet) { // 检查等级配置表中的可用技能 return self::checkPetSkillAvailable($pet, $skill->id); }); // 获取技能使用记录,计算冷却时间 $skillLogs = $pet->skillLogs() ->orderBy('used_at', 'desc') ->get() ->groupBy('skill_id'); $result = []; foreach ($availableSkills as $skill) { $lastUsed = null; $cooldownRemaining = 0; if (isset($skillLogs[$skill->id]) && $skillLogs[$skill->id]->count() > 0) { $lastUsed = $skillLogs[$skill->id][0]->used_at; $cooldownSeconds = $skill->cool_down; $now = now(); // 确保时间计算的正确性 if ($lastUsed instanceof \Carbon\Carbon) { $secondsSinceLastUse = $now->diffInSeconds($lastUsed, false); } else { // 如果不是Carbon对象,尝试解析 $lastUsed = \Carbon\Carbon::parse($lastUsed); $secondsSinceLastUse = $now->diffInSeconds($lastUsed, false); } // 如果secondsSinceLastUse为负数,说明lastUsed时间在未来,这是异常情况 if ($secondsSinceLastUse < 0) { $secondsSinceLastUse = 0; } $cooldownRemaining = max(0, $cooldownSeconds - $secondsSinceLastUse); } $result[] = [ 'skill_id' => $skill->id, 'skill_name' => $skill->skill_name, 'stamina_cost' => $skill->stamina_cost, 'cool_down' => $skill->cool_down, 'effect_desc' => $skill->effect_desc, 'last_used' => $lastUsed ? $lastUsed->format('Y-m-d H:i:s') : null, 'cooldown_remaining' => $cooldownRemaining, 'is_available' => $cooldownRemaining === 0 && $pet->stamina >= $skill->stamina_cost ]; } return $result; } /** * 检查宠物当前等级是否可以使用指定技能 * * 基于宠物等级配置表中的 skills 字段进行检查 * * @param PetUser $pet 宠物对象 * @param int $skillId 技能ID * @return bool 是否可以使用该技能 */ private static function checkPetSkillAvailable(PetUser $pet, int $skillId): bool { try { // 获取宠物当前等级的配置 // 注意:这里假设所有宠物都使用 pet_id=1 的配置,如果有多种宠物类型,需要修改 $levelConfig = PetLevelConfig::where('pet_id', 1) ->where('level', $pet->level) ->first(); if (!$levelConfig) { Log::warning('宠物等级配置不存在', [ 'pet_id' => $pet->id, 'pet_level' => $pet->level, 'skill_id' => $skillId ]); // 如果没有配置,默认允许使用(向后兼容) return true; } // 检查技能是否在可用技能列表中 $availableSkills = $levelConfig->skills ?? []; $isAvailable = in_array($skillId, $availableSkills); Log::info('宠物技能可用性检查', [ 'pet_id' => $pet->id, 'pet_level' => $pet->level, 'skill_id' => $skillId, 'available_skills' => $availableSkills, 'is_available' => $isAvailable ]); return $isAvailable; } catch (\Exception $e) { Log::error('检查宠物技能可用性时发生错误', [ 'pet_id' => $pet->id, 'pet_level' => $pet->level, 'skill_id' => $skillId, 'error' => $e->getMessage() ]); // 发生错误时默认允许使用(向后兼容) return true; } } }