26日1802-修复物品冻结拆堆lastdata同步问题.md 5.0 KB

修复物品冻结拆堆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

// 修改前:使用物品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 重放原问题请求:

修复前响应

{
  "lastData": {
    "items": [
      {
        "itemId": "2",
        "quantity": "100",
        "isFrozen": true,
        "iuId": "1047"
      }
    ]
  }
}

修复后响应

{
  "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同步问题。通过改进临时数据存储机制,确保同一物品的多个堆叠变更都能正确同步到客户端,提升了系统的数据一致性和用户体验。