AI Assistant 6 ヶ月 前
コミット
23e630feb8

+ 162 - 0
AiWork/2025年06月/26日1802-修复物品冻结拆堆lastdata同步问题.md

@@ -0,0 +1,162 @@
+# 修复物品冻结拆堆lastdata同步问题
+
+**任务时间**: 2025年06月26日 18:02
+**任务类型**: 功能修复
+**模块**: GameItems, Game
+**状态**: ✅ 已完成
+
+## 问题描述
+
+用户反馈:Mex模块挂单时,物品冻结产生了拆堆,但同步物品状态只同步了一个物品堆的,应该是两个物品堆。
+
+### 问题分析
+
+通过 `debug:reproduce-error` 命令重放请求 69010888,发现:
+
+1. **拆堆场景**:当用户有10000个萝卜,挂单冻结100个时,会发生拆堆:
+   - 原堆叠:数量从10000减少到9900
+   - 新冻结堆叠:创建100个冻结状态的物品
+
+2. **同步问题**:在修复前,lastdata中只显示一个物品堆的信息,缺少另一个堆叠的状态
+
+3. **根本原因**:`ItemTemp::handleItemQuantityChanged` 方法使用 `item_id` 作为键存储临时数据,导致同一物品的多个堆叠变更事件相互覆盖
+
+## 解决方案
+
+### 1. 修改临时数据存储键
+
+**文件**: `app/Module/Game/Logics/ItemTemp.php`
+
+```php
+// 修改前:使用物品ID作为键,导致同一物品的不同堆叠相互覆盖
+$userItemsTemp[$event->itemId] = $itemData;
+
+// 修改后:使用用户物品记录ID作为键,避免覆盖
+$userItemsTemp[$event->userItemId] = $itemData;
+```
+
+### 2. 调整数据获取方法
+
+**文件**: `app/Module/Game/Logics/ItemTemp.php`
+
+- 修改 `getUserItemChanges()` 方法返回所有物品堆的变更记录
+- 新增 `getUserItemChangeByUserItemId()` 方法支持按用户物品记录ID查询
+- 调整 `getUserItemChange()` 方法返回指定物品ID的所有堆叠变更
+
+### 3. 事件触发机制验证
+
+确认 `ItemFreeze::freezeNormalItem` 方法在拆堆时正确触发两个事件:
+1. 原堆叠数量减少事件(`change_type: quantity_decrease`)
+2. 新冻结堆叠创建事件(`change_type: frozen_item_create`)
+
+## 修复验证
+
+### 1. 请求重放验证
+
+使用 `php artisan debug:reproduce-error 69010888` 重放原问题请求:
+
+**修复前响应**:
+```json
+{
+  "lastData": {
+    "items": [
+      {
+        "itemId": "2",
+        "quantity": "100",
+        "isFrozen": true,
+        "iuId": "1047"
+      }
+    ]
+  }
+}
+```
+
+**修复后响应**:
+```json
+{
+  "lastData": {
+    "items": [
+      {
+        "itemId": "2",
+        "quantity": "9600",
+        "iuId": "1042"
+      },
+      {
+        "itemId": "2",
+        "quantity": "100",
+        "isFrozen": true,
+        "iuId": "1055"
+      }
+    ]
+  }
+}
+```
+
+### 2. 单元测试验证
+
+新增测试文件:
+- `tests/Unit/GameItems/ItemFreezeSyncFixTest.php`
+- `tests/Unit/GameItems/ItemFreezeSplitStackSyncTest.php`
+
+测试覆盖场景:
+1. **拆堆冻结**:部分冻结导致拆堆,验证两个物品堆状态同步
+2. **全部冻结**:全部冻结不拆堆,验证单个物品堆状态变更
+
+所有测试通过,验证修复正确性。
+
+## 技术细节
+
+### 拆堆逻辑分析
+
+当执行部分冻结时,`ItemFreeze::freezeNormalItem` 方法会:
+
+1. **检查可用数量**:查找用户可用的物品堆叠
+2. **判断是否拆堆**:
+   - 如果冻结数量 == 可用数量:全部冻结,直接标记 `is_frozen=true`
+   - 如果冻结数量 < 可用数量:部分冻结,需要拆堆
+
+3. **拆堆操作**:
+   - 减少原堆叠数量:`quantity = 原数量 - 冻结数量`
+   - 创建新冻结堆叠:`quantity = 冻结数量, is_frozen = true`
+
+4. **事件触发**:
+   - 原堆叠:触发数量减少事件(冻结状态不变)
+   - 新堆叠:触发冻结物品创建事件(从无到冻结状态)
+
+### 同步机制
+
+修复后的同步流程:
+1. 冻结操作触发多个 `ItemQuantityChanged` 事件
+2. `ItemTemp` 使用 `user_item_id` 作为键存储每个堆叠的变更
+3. `AppGameProtobufResponseListener` 获取所有变更记录
+4. 构建 `lastData` 包含所有变更的物品堆信息
+
+## 影响范围
+
+- **正面影响**:修复拆堆场景下的状态同步问题,客户端能正确获取所有物品堆状态
+- **兼容性**:向后兼容,不影响现有功能
+- **性能**:轻微提升,避免了数据覆盖导致的信息丢失
+
+## 提交信息
+
+```
+修复物品冻结拆堆时lastdata同步问题
+
+问题描述:
+- Mex模块挂单时,物品冻结产生拆堆,但只同步了一个物品堆的状态
+- 原因是ItemTemp使用item_id作为键存储临时数据,导致同一物品的多个堆叠相互覆盖
+
+修复内容:
+1. 修改ItemTemp::handleItemQuantityChanged方法,使用user_item_id作为键而不是item_id
+2. 调整getUserItemChanges方法返回所有物品堆的变更记录
+3. 新增getUserItemChangeByUserItemId方法支持按用户物品记录ID查询
+4. 添加测试用例验证拆堆场景下的双堆叠同步功能
+
+测试验证:
+- 通过debug:reproduce-error命令验证,拆堆时lastdata正确包含两个物品堆信息
+- 新增单元测试覆盖拆堆和全部冻结两种场景
+```
+
+## 总结
+
+成功修复了物品冻结拆堆时的lastdata同步问题。通过改进临时数据存储机制,确保同一物品的多个堆叠变更都能正确同步到客户端,提升了系统的数据一致性和用户体验。