PetSkillUseValidator.php 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. <?php
  2. namespace App\Module\Pet\Validators;
  3. use App\Module\Pet\Enums\PetStatus;
  4. use App\Module\Pet\Models\PetLevelConfig;
  5. use App\Module\Pet\Models\PetSkill;
  6. use App\Module\Pet\Models\PetUser;
  7. use Illuminate\Support\Facades\Log;
  8. use UCore\Validator;
  9. /**
  10. * 宠物技能使用验证器
  11. *
  12. * 用于验证宠物技能使用条件的合法性
  13. */
  14. class PetSkillUseValidator extends Validator
  15. {
  16. /**
  17. * 验证方法
  18. *
  19. * @param mixed $value 宠物ID
  20. * @param array $data 所有数据
  21. * @return bool 验证是否通过
  22. */
  23. public function validate(mixed $value, array $data): bool
  24. {
  25. $petId = $value;
  26. $skillId = $data['skillId'] ?? 0;
  27. try {
  28. // 获取宠物信息
  29. $pet = PetUser::find($petId);
  30. if (!$pet) {
  31. $this->addError('宠物不存在');
  32. return false;
  33. }
  34. // 获取技能信息
  35. $skill = PetSkill::find($skillId);
  36. if (!$skill) {
  37. $this->addError('技能(' . $skillId . ')不存在');
  38. return false;
  39. }
  40. // 检查宠物状态
  41. if ($pet->status !== PetStatus::NORMAL) {
  42. $this->addError('宠物当前状态(' . $pet->status->name . ')不允许使用技能');
  43. return false;
  44. }
  45. // 检查宠物当前等级是否可以使用该技能(基于等级配置表)
  46. if (!$this->checkPetSkillAvailable($pet, $skillId)) {
  47. $this->addError('该技能在当前等级(' . $pet->level . ')不可用');
  48. return false;
  49. }
  50. // 检查宠物体力是否足够
  51. if ($pet->stamina < $skill->stamina_cost) {
  52. $this->addError('宠物体力(' . $pet->stamina . ')不足,需要体力(' . $skill->stamina_cost . ')才能使用该技能');
  53. return false;
  54. }
  55. // 检查技能冷却时间
  56. $lastUsed = $pet->skillLogs()
  57. ->where('skill_id', $skillId)
  58. ->orderBy('used_at', 'desc')
  59. ->first();
  60. if ($lastUsed) {
  61. $cooldownSeconds = $skill->cool_down;
  62. $now = now();
  63. $lastUsedTime = $lastUsed->used_at;
  64. // 确保时间计算的正确性
  65. if ($lastUsedTime instanceof \Carbon\Carbon) {
  66. $secondsSinceLastUse = $now->diffInSeconds($lastUsedTime, false);
  67. } else {
  68. // 如果不是Carbon对象,尝试解析
  69. $lastUsedTime = \Carbon\Carbon::parse($lastUsedTime);
  70. $secondsSinceLastUse = $now->diffInSeconds($lastUsedTime, false);
  71. }
  72. // 如果secondsSinceLastUse为负数,说明lastUsed时间在未来,这是异常情况
  73. if ($secondsSinceLastUse < 0) {
  74. // 异常情况下,重置为0,允许技能使用
  75. $secondsSinceLastUse = 0;
  76. }
  77. if ($secondsSinceLastUse < $cooldownSeconds) {
  78. $remainingCooldown = $cooldownSeconds - $secondsSinceLastUse;
  79. $this->addError('技能冷却中,还需等待' . $remainingCooldown . '秒');
  80. return false;
  81. }
  82. }
  83. return true;
  84. } catch (\Exception $e) {
  85. $this->addError('验证过程发生错误: ' . $e->getMessage());
  86. return false;
  87. }
  88. }
  89. /**
  90. * 检查宠物当前等级是否可以使用指定技能
  91. *
  92. * 基于宠物等级配置表中的 skills 字段进行检查
  93. *
  94. * @param PetUser $pet 宠物对象
  95. * @param int $skillId 技能ID
  96. * @return bool 是否可以使用该技能
  97. */
  98. private function checkPetSkillAvailable(PetUser $pet, int $skillId): bool
  99. {
  100. try {
  101. // 获取宠物当前等级的配置
  102. // 注意:这里假设所有宠物都使用 pet_id=1 的配置,如果有多种宠物类型,需要修改
  103. $levelConfig = PetLevelConfig::where('pet_id', 1)
  104. ->where('level', $pet->level)
  105. ->first();
  106. if (!$levelConfig) {
  107. Log::warning('宠物等级配置不存在', [
  108. 'pet_id' => $pet->id,
  109. 'pet_level' => $pet->level,
  110. 'skill_id' => $skillId
  111. ]);
  112. // 如果没有配置,默认允许使用(向后兼容)
  113. return true;
  114. }
  115. // 检查技能是否在可用技能列表中
  116. $availableSkills = $levelConfig->skills ?? [];
  117. $isAvailable = in_array($skillId, $availableSkills);
  118. Log::info('宠物技能可用性检查', [
  119. 'pet_id' => $pet->id,
  120. 'pet_level' => $pet->level,
  121. 'skill_id' => $skillId,
  122. 'available_skills' => $availableSkills,
  123. 'is_available' => $isAvailable
  124. ]);
  125. return $isAvailable;
  126. } catch (\Exception $e) {
  127. Log::error('检查宠物技能可用性时发生错误', [
  128. 'pet_id' => $pet->id,
  129. 'pet_level' => $pet->level,
  130. 'skill_id' => $skillId,
  131. 'error' => $e->getMessage()
  132. ]);
  133. // 发生错误时默认允许使用(向后兼容)
  134. return true;
  135. }
  136. }
  137. }