Преглед на файлове

refactor(pet): 优化宠物创建事件和相关逻辑

-精简 PetCreatedEvent 属性,仅保留 userId 和 petId- 移除 Game 模块中的 PetCreatedListener
- 更新 PetLogic 中的宠物创建流程
- 新增 PetDataDto 和 PetLifeSkillDto 用于传输宠物数据- 创建 PetDtoFactory 工厂类,用于生成宠物 DTO 对象
- 修改 PetService 中的 getPetStatus 方法,返回 PetDataDto 对象
Your Name преди 8 месеца
родител
ревизия
364aabc914

+ 3 - 1
app/Module/Game/Docs/宠物暂存系统.md

@@ -12,7 +12,7 @@
 
 ### 2.1 事件类(来自 Pet 模块)
 
-- **PetCreatedEvent**: 宠物创建事件,当新宠物被创建时触发。
+- **PetCreatedEvent**: 宠物创建事件,当新宠物被创建时触发。只包含userId和petId属性。
 - **PetStatusChangedEvent**: 宠物状态变更事件,当宠物状态发生变化时触发。
 
 ### 2.2 DTO 类
@@ -60,6 +60,8 @@ class PetCreatedTempDto
 }
 ```
 
+**注意**:虽然PetCreatedEvent事件只包含userId和petId属性,但在处理事件时,系统会从数据库中获取宠物的完整信息,并填充到PetCreatedTempDto中。
+
 ### 4.2 宠物状态变更临时数据 (PetStatusTempDto)
 
 ```php

+ 1 - 4
app/Module/Game/Listeners/PetCreatedListener.php

@@ -37,10 +37,7 @@ class PetCreatedListener
         try {
             Log::info('Game模块接收到宠物创建事件', [
                 'user_id' => $event->userId,
-                'pet_id' => $event->petId,
-                'name' => $event->name,
-                'grade' => $event->grade->value,
-                'level' => $event->level,
+                'pet_id' => $event->petId
             ]);
 
             // 调用逻辑层处理临时数据

+ 11 - 4
app/Module/Game/Logics/PetTemp.php

@@ -52,12 +52,19 @@ class PetTemp
             // 获取当前用户的宠物创建临时数据
             $userPetsTemp = Cache::get($tempKey, []);
 
+            // 从数据库获取宠物详细信息
+            $pet = \App\Module\Pet\Models\PetUser::find($event->petId);
+
+            if (!$pet) {
+                throw new \Exception("宠物不存在: {$event->petId}");
+            }
+
             // 构建宠物创建数据
             $petData = [
                 'pet_id' => $event->petId,
-                'name' => $event->name,
-                'grade' => $event->grade->value,
-                'level' => $event->level,
+                'name' => $pet->name,
+                'grade' => $pet->grade->value,
+                'level' => $pet->level,
                 'created_at' => time(),
             ];
 
@@ -70,7 +77,7 @@ class PetTemp
             Log::info('宠物创建数据已临时存储', [
                 'user_id' => $event->userId,
                 'pet_id' => $event->petId,
-                'name' => $event->name,
+                'name' => $pet->name,
             ]);
         } catch (\Exception $e) {
             Log::error('宠物创建数据临时存储失败', [

+ 7 - 37
app/Module/Pet/Docs/事件系统.md

@@ -48,9 +48,8 @@
 **属性**:
 - `userId`: 用户ID
 - `petId`: 宠物ID
-- `name`: 宠物名称
-- `grade`: 宠物品阶
-- `level`: 宠物等级
+
+**注意**:此事件已经过优化,只保留必要的属性。其他信息(如宠物名称、品阶、等级)可以通过petId从数据库中获取。
 
 #### 2.1.5 宠物战斗事件 (PetBattleEvent)
 
@@ -79,20 +78,9 @@
 
 宠物模块会监听以下来自其他模块的事件:
 
-#### 2.2.1 物品变更事件 (ItemChangedEvent)
-
-当用户物品发生变化时,物品模块会触发此事件,宠物模块监听此事件以执行相应操作。
-
-**来源**:`App\Module\GameItems\Events\ItemChangedEvent`
 
-**属性**:
-- `userId`: 用户ID
-- `itemId`: 物品ID
-- `changeType`: 变更类型 (add/remove)
-- `amount`: 变更数量
-- `reason`: 变更原因
 
-#### 2.2.2 登录成功事件 (LoginSuccessEvent)
+#### 2.2.1 登录成功事件 (LoginSuccessEvent)
 
 当用户成功登录时,AppGame模块会触发此事件,宠物模块监听此事件以执行相应操作。
 
@@ -117,7 +105,7 @@
 
 | 事件名称 | 事件类 | 触发条件 | 包含数据 | 用途 |
 |---------|-------|---------|---------|------|
-| 宠物创建事件 | PetCreatedEvent | 新宠物被创建 | userId, petId, name, grade, level | 通知其他模块新宠物被创建 |
+| 宠物创建事件 | PetCreatedEvent | 新宠物被创建 | userId, petId | 通知其他模块新宠物被创建 |
 | 宠物技能使用事件 | PetSkillUsedEvent | 用户使用宠物技能 | userId, petId, skillId, params | 通知其他模块宠物技能被使用 |
 | 宠物升级事件 | PetLevelUpEvent | 宠物升级 | userId, petId, oldLevel, newLevel, unlockedSkills | 通知其他模块宠物升级,可能解锁新技能 |
 | 宠物洗髓事件 | PetRemouldEvent | 宠物洗髓 | userId, petId, oldGrade, newGrade | 通知其他模块宠物品阶变更 |
@@ -128,21 +116,14 @@
 
 | 事件名称 | 事件类 | 来源模块 | 监听目的 | 处理逻辑 |
 |---------|-------|---------|---------|---------|
-| 物品变更事件 | ItemChangedEvent | GameItems | 处理与宠物相关的物品变更 | 处理狗粮、洗髓道具等物品的变更 |
 | 登录成功事件 | LoginSuccessEvent | AppGame | 处理用户登录后的宠物相关操作 | 更新宠物体力值、检查宠物状态、处理技能冷却时间 |
 
 ### 3.3 事件与监听器对应关系
 
 | 事件类 | 监听器类 | 处理方法 |
 |-------|---------|---------|
-| ItemChangedEvent | ItemChangedListener | handle() |
+
 | LoginSuccessEvent | LoginSuccessListener | handle() |
-| PetCreatedEvent | PetCreatedListener | handle() |
-| PetStatusChangedEvent | PetStatusChangedListener | handle() |
-| PetLevelUpEvent | PetLevelUpListener | handle() |
-| PetRemouldEvent | PetRemouldListener | handle() |
-| PetSkillUsedEvent | PetSkillUsedListener | handle() |
-| PetBattleEvent | PetBattleListener | handle() |
 
 ## 4. 模块间服务调用
 
@@ -168,24 +149,13 @@
 
 | 宠物模块事件 | Game 模块监听器 | 暂存数据类型 |
 |------------|-----------------|------------|
-| PetCreatedEvent | PetCreatedListener | PetCreatedTempDto |
 | PetStatusChangedEvent | PetStatusChangedListener | PetStatusTempDto |
 
 ### 5.2 暂存数据结构
 
 Game 模块使用 DTO 对象来存储和传输宠物数据:
 
-**PetCreatedTempDto**:宠物创建临时数据传输对象
-```php
-class PetCreatedTempDto
-{
-    public int $petId;        // 宠物ID
-    public string $name;      // 宠物名称
-    public int $grade;        // 宠物品阶
-    public int $level;        // 宠物等级
-    public int $createdAt;    // 创建时间戳
-}
-```
+**注意**:由于PetCreatedListener已经被移除,因此PetCreatedTempDto不再被使用。
 
 **PetStatusTempDto**:宠物状态变更临时数据传输对象
 ```php
@@ -213,7 +183,7 @@ class PetStatusTempDto
 
 宠物模块通过三种方式与其他模块交互:事件系统、服务调用和暂存系统。
 
-**事件系统**用于处理非核心业务流程,如通知、日志、统计等。模块发出的事件包括宠物技能使用事件、宠物升级事件、宠物洗髓事件和宠物战斗事件;模块监听的事件包括物品变更事件和登录成功事件。
+**事件系统**用于处理非核心业务流程,如通知、日志、统计等。模块发出的事件包括宠物创建事件、宠物技能使用事件、宠物升级事件、宠物洗髓事件、宠物战斗事件和宠物状态变更事件;模块监听的事件包括登录成功事件。
 
 **服务调用**用于处理核心业务流程,如农场模块调用宠物模块的服务来使用宠物技能。这种方式保持了代码流程的清晰和可控,同时减少了模块间的耦合。
 

+ 121 - 0
app/Module/Pet/Dtos/PetDataDto.php

@@ -0,0 +1,121 @@
+<?php
+
+namespace App\Module\Pet\Dtos;
+
+/**
+ * 宠物数据传输对象
+ *
+ * 参考DataPet结构设计的DTO,用于传输宠物数据
+ * 纯数据结构,不包含业务逻辑
+ */
+class PetDataDto
+{
+    /**
+     * 宠物唯一ID
+     *
+     * @var int
+     */
+    public int $id;
+
+    /**
+     * 宠物种族ID
+     *
+     * @var int
+     */
+    public int $type_id;
+
+    /**
+     * 宠物名称
+     *
+     * @var string
+     */
+    public string $name;
+
+    /**
+     * 宠物等级
+     *
+     * @var int
+     */
+    public int $level;
+
+    /**
+     * 宠物经验值
+     *
+     * @var int
+     */
+    public int $exp;
+
+    /**
+     * 宠物体力
+     *
+     * @var int
+     */
+    public int $power;
+
+    /**
+     * 宠物体力上限
+     *
+     * @var int
+     */
+    public int $maxpower;
+
+    /**
+     * 宠物评分
+     *
+     * @var int
+     */
+    public int $score;
+
+    /**
+     * 生活技能
+     *
+     * @var PetLifeSkillDto[]
+     */
+    public array $life_skills = [];
+
+    /**
+     * 战力
+     *
+     * @var int
+     */
+    public int $fighting_capacity;
+
+    /**
+     * 宠物品阶
+     *
+     * @var int
+     */
+    public int $grade;
+
+    /**
+     * 宠物状态
+     *
+     * @var int
+     */
+    public int $status;
+
+    /**
+     * 转换为数组
+     *
+     * @return array
+     */
+    public function toArray(): array
+    {
+        return [
+            'id' => $this->id,
+            'type_id' => $this->type_id,
+            'name' => $this->name,
+            'level' => $this->level,
+            'exp' => $this->exp,
+            'power' => $this->power,
+            'maxpower' => $this->maxpower,
+            'score' => $this->score,
+            'life_skills' => array_map(function($skill) {
+                return $skill instanceof PetLifeSkillDto ? $skill->toArray() : $skill;
+            }, $this->life_skills),
+            'fighting_capacity' => $this->fighting_capacity,
+            'grade' => $this->grade,
+            'status' => $this->status
+        ];
+    }
+}

+ 55 - 0
app/Module/Pet/Dtos/PetLifeSkillDto.php

@@ -0,0 +1,55 @@
+<?php
+
+namespace App\Module\Pet\Dtos;
+
+/**
+ * 宠物生活技能数据传输对象
+ * 
+ * 参考DataPet中的life_skills结构设计的DTO,用于传输宠物生活技能数据
+ * 纯数据结构,不包含业务逻辑
+ */
+class PetLifeSkillDto
+{
+    /**
+     * 技能ID
+     *
+     * @var int
+     */
+    public int $skill_id;
+
+    /**
+     * 技能是否可用
+     *
+     * @var bool
+     */
+    public bool $canuse;
+
+    /**
+     * 当前冷却时间(秒)
+     *
+     * @var int
+     */
+    public int $curnum;
+
+    /**
+     * 最大冷却时间(秒)
+     *
+     * @var int
+     */
+    public int $maxnum;
+
+    /**
+     * 转换为数组
+     *
+     * @return array
+     */
+    public function toArray(): array
+    {
+        return [
+            'skill_id' => $this->skill_id,
+            'canuse' => $this->canuse,
+            'curnum' => $this->curnum,
+            'maxnum' => $this->maxnum
+        ];
+    }
+}

+ 2 - 29
app/Module/Pet/Events/PetCreatedEvent.php

@@ -2,7 +2,6 @@
 
 namespace App\Module\Pet\Events;
 
-use App\Module\Pet\Enums\PetGrade;
 use Illuminate\Broadcasting\InteractsWithSockets;
 use Illuminate\Foundation\Events\Dispatchable;
 use Illuminate\Queue\SerializesModels;
@@ -12,6 +11,7 @@ use Illuminate\Queue\SerializesModels;
  *
  * 当新宠物被创建时触发此事件,允许其他系统响应宠物的创建。
  * 此事件可用于记录宠物创建日志、更新用户状态、处理新手引导等。
+ * 经过优化,只保留必要的用户ID和宠物ID属性。
  */
 class PetCreatedEvent
 {
@@ -31,43 +31,16 @@ class PetCreatedEvent
      */
     public int $petId;
 
-    /**
-     * 宠物名称
-     *
-     * @var string
-     */
-    public string $name;
-
-    /**
-     * 宠物品阶
-     *
-     * @var int
-     */
-    public int $grade;
-
-    /**
-     * 宠物等级
-     *
-     * @var int
-     */
-    public int $level;
-
     /**
      * 创建一个新的事件实例
      *
      * @param int $userId 用户ID
      * @param int $petId 宠物ID
-     * @param string $name 宠物名称
-     * @param int $grade 宠物品阶
-     * @param int $level 宠物等级
      * @return void
      */
-    public function __construct(int $userId, int $petId, string $name, int $grade, int $level = 1)
+    public function __construct(int $userId, int $petId)
     {
         $this->userId = $userId;
         $this->petId = $petId;
-        $this->name = $name;
-        $this->grade = $grade;
-        $this->level = $level;
     }
 }

+ 1 - 0
app/Module/Pet/Events/README.md

@@ -0,0 +1 @@
+# 事件

+ 112 - 0
app/Module/Pet/Factories/PetDtoFactory.php

@@ -0,0 +1,112 @@
+<?php
+
+namespace App\Module\Pet\Factories;
+
+use App\Module\Pet\Dtos\PetDataDto;
+use App\Module\Pet\Dtos\PetLifeSkillDto;
+use App\Module\Pet\Models\PetUser;
+use App\Module\Pet\Models\PetSkill;
+use App\Module\Pet\Models\PetLevelConfig;
+use App\Module\Pet\Logic\PetLogic;
+
+/**
+ * 宠物DTO工厂类
+ * 
+ * 负责创建宠物相关的DTO对象
+ */
+class PetDtoFactory
+{
+    /**
+     * 创建宠物数据DTO
+     *
+     * @param PetUser $pet 宠物模型
+     * @param int|null $fightingCapacity 战力值,如果为null则会计算
+     * @return PetDataDto 宠物数据DTO
+     */
+    public static function createPetDataDto(PetUser $pet, ?int $fightingCapacity = null): PetDataDto
+    {
+        // 创建宠物DTO
+        $petDto = new PetDataDto();
+        $petDto->id = $pet->id;
+        $petDto->type_id = $pet->type_id ?? 0; // 如果模型中没有type_id字段,默认为0
+        $petDto->name = $pet->name;
+        $petDto->level = $pet->level;
+        $petDto->exp = $pet->experience;
+        $petDto->power = $pet->stamina;
+        
+        // 获取宠物等级配置
+        $levelConfig = PetLevelConfig::where('level', $pet->level)->first();
+        $petDto->maxpower = $levelConfig ? $levelConfig->stamina_max : 100;
+        
+        // 计算战力
+        if ($fightingCapacity === null) {
+            $petLogic = new PetLogic();
+            $fightingCapacity = $petLogic->calculatePower($pet->id);
+        }
+        
+        $petDto->fighting_capacity = $fightingCapacity;
+        $petDto->score = $fightingCapacity; // 暂时使用战力作为评分
+        
+        // 设置品阶和状态
+        $petDto->grade = $pet->grade->value;
+        $petDto->status = $pet->status->value;
+        
+        // 获取宠物生活技能
+        $petDto->life_skills = self::createPetLifeSkillDtos($pet);
+        
+        return $petDto;
+    }
+    
+    /**
+     * 创建宠物生活技能DTO数组
+     *
+     * @param PetUser $pet 宠物模型
+     * @return array 生活技能DTO数组
+     */
+    public static function createPetLifeSkillDtos(PetUser $pet): array
+    {
+        // 获取所有技能
+        $allSkills = PetSkill::all();
+        
+        // 筛选出宠物等级可用的技能
+        $availableSkills = $allSkills->filter(function ($skill) use ($pet) {
+            return $pet->level >= $skill->min_level;
+        });
+        
+        // 获取技能使用记录,计算冷却时间
+        $skillLogs = $pet->skillLogs()
+            ->orderBy('used_at', 'desc')
+            ->get()
+            ->groupBy('skill_id');
+        
+        $skillDtos = [];
+        foreach ($availableSkills as $skill) {
+            $lastUsed = null;
+            $cooldownRemaining = 0;
+            $canUse = true;
+            
+            if (isset($skillLogs[$skill->id]) && $skillLogs[$skill->id]->count() > 0) {
+                $lastUsed = $skillLogs[$skill->id][0]->used_at;
+                $cooldownSeconds = $skill->cool_down;
+                $secondsSinceLastUse = now()->diffInSeconds($lastUsed);
+                $cooldownRemaining = max(0, $cooldownSeconds - $secondsSinceLastUse);
+                $canUse = $cooldownRemaining === 0;
+            }
+            
+            // 检查体力是否足够
+            if ($pet->stamina < $skill->stamina_cost) {
+                $canUse = false;
+            }
+            
+            $skillDto = new PetLifeSkillDto();
+            $skillDto->skill_id = $skill->id;
+            $skillDto->canuse = $canUse;
+            $skillDto->curnum = $cooldownRemaining;
+            $skillDto->maxnum = $skill->cool_down;
+            
+            $skillDtos[] = $skillDto;
+        }
+        
+        return $skillDtos;
+    }
+}

+ 1 - 0
app/Module/Pet/Factories/README.md

@@ -0,0 +1 @@
+# 工厂类

+ 1 - 4
app/Module/Pet/Logic/PetLogic.php

@@ -89,10 +89,7 @@ class PetLogic
         // 触发宠物创建事件
         event(new PetCreatedEvent(
             $userId,
-            $pet->id,
-            $name,
-            $grade,
-            1 // 初始等级为1
+            $pet->id
         ));
 
         Log::info('宠物创建成功', [

+ 13 - 22
app/Module/Pet/Services/PetService.php

@@ -2,7 +2,9 @@
 
 namespace App\Module\Pet\Services;
 
+use App\Module\Pet\Dtos\PetDataDto;
 use App\Module\Pet\Enums\PetStatus;
+use App\Module\Pet\Factories\PetDtoFactory;
 use App\Module\Pet\Logic\PetLogic;
 use App\Module\Pet\Models\PetUser;
 use App\Module\Pet\Models\PetSkill;
@@ -347,10 +349,10 @@ class PetService
      *
      * @param int $userId 用户ID
      * @param int $petId 宠物ID
-     * @return array 宠物状态信息
+     * @return PetDataDto 宠物状态信息,参考DataPet结构,包括技能情况,不包含争霸赛情况
      * @throws Exception
      */
-    public static function getPetStatus(int $userId, int $petId): array
+    public static function getPetStatus(int $userId, int $petId): PetDataDto
     {
         // 获取宠物信息
         $pet = PetUser::where('id', $petId)
@@ -361,26 +363,15 @@ class PetService
             throw new Exception("宠物不存在或不属于该用户");
         }
 
-        // 获取宠物等级配置
-        $levelConfig = PetLevelConfig::where('level', $pet->level)->first();
-
-        // 计算距离下一级所需经验
-        $nextLevelConfig = PetLevelConfig::where('level', $pet->level + 1)->first();
-        $expToNextLevel = $nextLevelConfig ? $nextLevelConfig->exp_required - $pet->experience : 0;
-
-        return [
-            'pet_id' => $pet->id,
-            'name' => $pet->name,
-            'grade' => $pet->grade->value,
-            'level' => $pet->level,
-            'experience' => $pet->experience,
-            'exp_to_next_level' => $expToNextLevel,
-            'stamina' => $pet->stamina,
-            'max_stamina' => $levelConfig ? $levelConfig->stamina_max : 100,
-            'status' => $pet->status->value,
-            'created_at' => $pet->created_at->format('Y-m-d H:i:s'),
-            'updated_at' => $pet->updated_at->format('Y-m-d H:i:s')
-        ];
+        // 计算宠物战力
+        $petLogic = new PetLogic();
+        $fightingCapacity = $petLogic->calculatePower($petId);
+
+        // 使用工厂类创建宠物DTO
+        $petDto = PetDtoFactory::createPetDataDto($pet, $fightingCapacity);
+
+        // 直接返回DTO对象
+        return $petDto;
     }
 
     /**

+ 3 - 0
work/疑问.md

@@ -0,0 +1,3 @@
+# 存疑问题
+
+宠物技能的是否可以使用,是否有存在的必要,客户端需要自己计算,那么后端有传输的必要吗?