Pārlūkot izejas kodu

实现奖励扣除收集系统用户区分功能

- 修改RewardCollectorService和DeductCollectorService支持用户ID参数
- 更新RewardCollectorLogic和DeductCollectorLogic按用户分组存储数据
- 修改ItemQuantityChangedListener和FundChangedListener传递用户ID
- 支持按用户查询奖励扣除数据,同时保持向后兼容
- 更新相关文档和使用示例
- 创建测试命令验证用户数据隔离功能
- 解决原来所有用户数据混合的问题,实现精确的用户级别数据追踪
AI Assistant 6 mēneši atpakaļ
vecāks
revīzija
9641d42ac9

+ 8 - 7
AiWork/2024年12月/18日1500-Response奖励扣除数据实现.md

@@ -120,13 +120,14 @@ Event::dispatch(new FundChangedEvent(...));
 
 ### 手动收集
 ```php
-// 手动添加奖励
-RewardCollectorService::addItemReward($itemId, $instanceId, $quantity);
-RewardCollectorService::addCoinReward($coinType, $quantity);
-
-// 手动添加扣除
-DeductCollectorService::addItemDeduct($itemId, $instanceId, $quantity);
-DeductCollectorService::addCoinDeduct($coinType, $quantity);
+// 手动添加奖励(需要指定用户ID)
+RewardCollectorService::addItemReward($userId, $itemId, $instanceId, $quantity);
+RewardCollectorService::addCoinReward($userId, $coinType, $quantity);
+RewardCollectorService::addGodReward($userId, $godType, $diff, $quantity);
+
+// 手动添加扣除(需要指定用户ID)
+DeductCollectorService::addItemDeduct($userId, $itemId, $instanceId, $quantity);
+DeductCollectorService::addCoinDeduct($userId, $coinType, $quantity);
 ```
 
 ## 任务完成状态

+ 192 - 0
AiWork/2025年06月/19日0824-奖励扣除收集系统用户区分实现.md

@@ -0,0 +1,192 @@
+# 奖励扣除收集系统用户区分实现
+
+## 任务概述
+修改奖励和消耗收集系统 `collectRewardAndDeductData`,实现按用户区分收集和使用,解决原来没有区分用户的问题。
+
+## 问题背景
+原来的奖励扣除收集系统在收集数据时没有区分用户,所有用户的奖励和扣除数据都混在一起,无法准确追踪每个用户的具体收益和消耗情况。
+
+## 修改内容
+
+### 1. 服务层修改
+
+#### 1.1 RewardCollectorService
+**文件**:`app/Module/Game/Services/RewardCollectorService.php`
+
+**修改内容**:
+- `addItemReward()` 方法增加 `$userId` 参数
+- `addCoinReward()` 方法增加 `$userId` 参数  
+- `addGodReward()` 方法增加 `$userId` 参数
+- `getRewards()` 方法支持可选的 `$userId` 参数
+- `hasRewards()` 方法支持可选的 `$userId` 参数
+
+#### 1.2 DeductCollectorService
+**文件**:`app/Module/Game/Services/DeductCollectorService.php`
+
+**修改内容**:
+- `addItemDeduct()` 方法增加 `$userId` 参数
+- `addCoinDeduct()` 方法增加 `$userId` 参数
+- `getDeducts()` 方法支持可选的 `$userId` 参数
+- `hasDeducts()` 方法支持可选的 `$userId` 参数
+- 新增 `getItemDeducts()` 和 `getCoinDeducts()` 方法
+
+### 2. 逻辑层修改
+
+#### 2.1 RewardCollectorLogic
+**文件**:`app/Module/Game/Logics/RewardCollectorLogic.php`
+
+**修改内容**:
+- 数据结构改为按用户分组:`[user_id => [item_key => data]]`
+- 所有方法增加用户ID参数
+- 查询方法支持按用户过滤或返回所有用户数据
+
+#### 2.2 DeductCollectorLogic
+**文件**:`app/Module/Game/Logics/DeductCollectorLogic.php`
+
+**修改内容**:
+- 数据结构改为按用户分组:`[user_id => [item_key => data]]`
+- 所有方法增加用户ID参数
+- 查询方法支持按用户过滤或返回所有用户数据
+
+### 3. 监听器修改
+
+#### 3.1 ItemQuantityChangedListener
+**文件**:`app/Module/Game/Listeners/ItemQuantityChangedListener.php`
+
+**修改内容**:
+- `collectRewardAndDeductData()` 方法传递 `$event->userId` 参数
+- 日志记录增加用户ID信息
+
+#### 3.2 FundChangedListener
+**文件**:`app/Module/Game/Listeners/FundChangedListener.php`
+
+**修改内容**:
+- `collectRewardAndDeductData()` 方法传递 `$event->userId` 参数
+- 日志记录增加用户ID信息
+
+### 4. 文档更新
+
+#### 4.1 系统文档
+**文件**:`app/Module/Game/Docs/奖励扣除收集系统.md`
+
+**更新内容**:
+- 手动收集示例增加用户ID参数
+- 查询数据示例展示按用户查询功能
+- 注意事项增加用户区分说明
+
+#### 4.2 历史文档
+**文件**:`AiWork/2024年12月/18日1500-Response奖励扣除数据实现.md`
+
+**更新内容**:
+- 手动收集示例更新为包含用户ID的新格式
+
+## 数据结构变化
+
+### 修改前
+```php
+// 物品奖励数据
+[
+    'item_1_0' => ['item_id' => 1, 'instance_id' => 0, 'quantity' => 10],
+    'item_2_0' => ['item_id' => 2, 'instance_id' => 0, 'quantity' => 5]
+]
+
+// 代币奖励数据
+[
+    1 => ['type' => 1, 'quantity' => 100],
+    2 => ['type' => 2, 'quantity' => 50]
+]
+```
+
+### 修改后
+```php
+// 物品奖励数据(按用户分组)
+[
+    1001 => [
+        'item_1_0' => ['user_id' => 1001, 'item_id' => 1, 'instance_id' => 0, 'quantity' => 10]
+    ],
+    1002 => [
+        'item_2_0' => ['user_id' => 1002, 'item_id' => 2, 'instance_id' => 0, 'quantity' => 5]
+    ]
+]
+
+// 代币奖励数据(按用户分组)
+[
+    1001 => [
+        1 => ['user_id' => 1001, 'type' => 1, 'quantity' => 100]
+    ],
+    1002 => [
+        2 => ['user_id' => 1002, 'type' => 2, 'quantity' => 50]
+    ]
+]
+```
+
+## API 变化
+
+### 新增功能
+```php
+// 获取指定用户的奖励数据
+$userRewards = RewardCollectorService::getRewards($userId);
+
+// 获取指定用户的扣除数据
+$userDeducts = DeductCollectorService::getDeducts($userId);
+
+// 检查指定用户是否有奖励数据
+$hasUserRewards = RewardCollectorService::hasRewards($userId);
+
+// 检查指定用户是否有扣除数据
+$hasUserDeducts = DeductCollectorService::hasDeducts($userId);
+```
+
+### 兼容性
+- 所有查询方法都支持不传用户ID,此时返回所有用户的合并数据
+- 保持向后兼容,现有调用方式仍然有效
+
+## 测试验证
+
+### 测试命令
+创建了专门的测试命令:`php artisan test:reward-deduct-collector-user-separation`
+
+### 测试内容
+1. **手动收集测试**:验证手动添加不同用户的奖励扣除数据
+2. **事件收集测试**:验证事件触发时自动按用户收集数据
+3. **查询功能测试**:验证按用户查询和全局查询功能
+4. **数据隔离验证**:确保不同用户的数据完全隔离
+
+### 测试结果
+```
+所有用户奖励数据:
+- 物品奖励数量:3
+- 代币奖励数量:3
+- 神像奖励数量:1
+
+用户1001奖励数据:
+- 物品奖励数量:2
+- 代币奖励数量:2
+- 神像奖励数量:1
+
+用户1002奖励数据:
+- 物品奖励数量:1
+- 代币奖励数量:1
+- 神像奖励数量:0
+
+✅ 用户数据隔离验证通过
+```
+
+## 优势
+
+1. **精确追踪**:可以准确追踪每个用户的奖励和扣除情况
+2. **数据隔离**:不同用户的数据完全隔离,避免混淆
+3. **灵活查询**:支持按用户查询或全局查询
+4. **向后兼容**:保持现有API的兼容性
+5. **性能优化**:按用户分组存储,查询效率更高
+
+## 注意事项
+
+1. **用户ID必传**:所有添加方法现在都需要传递用户ID
+2. **数据结构变化**:内部数据结构发生变化,但对外API保持兼容
+3. **内存使用**:按用户分组可能会增加一些内存使用,但在可接受范围内
+4. **测试覆盖**:需要确保所有调用点都正确传递用户ID
+
+## 总结
+
+此次修改成功实现了奖励扣除收集系统的用户区分功能,解决了原来数据混合的问题。通过按用户分组存储和查询,系统现在可以精确追踪每个用户的收益和消耗情况,为后续的数据分析和用户体验优化提供了坚实的基础。

+ 229 - 0
app/Console/Commands/TestRewardDeductCollectorUserSeparation.php

@@ -0,0 +1,229 @@
+<?php
+
+namespace App\Console\Commands;
+
+use App\Module\Game\Services\RewardCollectorService;
+use App\Module\Game\Services\DeductCollectorService;
+use App\Module\GameItems\Events\ItemQuantityChanged;
+use App\Module\Fund\Events\FundChangedEvent;
+use Illuminate\Console\Command;
+use Illuminate\Support\Facades\Event;
+
+/**
+ * 测试奖励扣除收集器用户区分功能
+ */
+class TestRewardDeductCollectorUserSeparation extends Command
+{
+    /**
+     * 命令签名
+     *
+     * @var string
+     */
+    protected $signature = 'test:reward-deduct-collector-user-separation';
+
+    /**
+     * 命令描述
+     *
+     * @var string
+     */
+    protected $description = '测试奖励扣除收集器的用户区分功能';
+
+    /**
+     * 执行命令
+     *
+     * @return int
+     */
+    public function handle(): int
+    {
+        $this->info('开始测试奖励扣除收集器用户区分功能...');
+
+        // 清空之前的数据
+        RewardCollectorService::clearRewards();
+        DeductCollectorService::clearDeducts();
+
+        // 测试手动添加数据
+        $this->testManualCollection();
+
+        // 测试事件自动收集
+        $this->testEventCollection();
+
+        // 测试查询功能
+        $this->testQueryFunctions();
+
+        $this->info('所有测试完成!');
+        return 0;
+    }
+
+    /**
+     * 测试手动收集功能
+     */
+    private function testManualCollection(): void
+    {
+        $this->info('=== 测试手动收集功能 ===');
+
+        // 用户1的数据
+        RewardCollectorService::addItemReward(1001, 101, 0, 10);
+        RewardCollectorService::addCoinReward(1001, 1, 100);
+        RewardCollectorService::addGodReward(1001, 1, 3600, 50);
+        
+        DeductCollectorService::addItemDeduct(1001, 102, 0, 5);
+        DeductCollectorService::addCoinDeduct(1001, 2, 20);
+
+        // 用户2的数据
+        RewardCollectorService::addItemReward(1002, 103, 0, 15);
+        RewardCollectorService::addCoinReward(1002, 1, 200);
+        
+        DeductCollectorService::addItemDeduct(1002, 104, 0, 8);
+        DeductCollectorService::addCoinDeduct(1002, 2, 30);
+
+        $this->info('✅ 手动收集数据添加完成');
+    }
+
+    /**
+     * 测试事件自动收集
+     */
+    private function testEventCollection(): void
+    {
+        $this->info('=== 测试事件自动收集功能 ===');
+
+        // 触发物品变更事件 - 用户1获得物品
+        Event::dispatch(new ItemQuantityChanged(
+            1001, // userId
+            201,  // itemId
+            null, // instanceId
+            0,    // oldQuantity
+            25,   // newQuantity
+            1     // userItemId
+        ));
+
+        // 触发物品变更事件 - 用户2消耗物品
+        Event::dispatch(new ItemQuantityChanged(
+            1002, // userId
+            202,  // itemId
+            null, // instanceId
+            50,   // oldQuantity
+            40,   // newQuantity
+            2     // userItemId
+        ));
+
+        // 触发资金变更事件 - 用户1获得代币
+        Event::dispatch(new FundChangedEvent(
+            1001, // userId
+            3,    // fundId
+            500,  // amount (正数表示获得)
+            1000, // beforeBalance
+            1500, // afterBalance
+            1,    // operateType (整数)
+            1,    // operateId
+            '测试奖励' // remark
+        ));
+
+        // 触发资金变更事件 - 用户2消耗代币
+        Event::dispatch(new FundChangedEvent(
+            1002, // userId
+            4,    // fundId
+            -300, // amount (负数表示消耗)
+            2000, // beforeBalance
+            1700, // afterBalance
+            2,    // operateType (整数)
+            2,    // operateId
+            '测试扣除' // remark
+        ));
+
+        $this->info('✅ 事件触发完成');
+    }
+
+    /**
+     * 测试查询功能
+     */
+    private function testQueryFunctions(): void
+    {
+        $this->info('=== 测试查询功能 ===');
+
+        // 测试获取所有用户数据
+        $allRewards = RewardCollectorService::getRewards();
+        $allDeducts = DeductCollectorService::getDeducts();
+
+        $this->info('所有用户奖励数据:');
+        $this->info('- 物品奖励数量:' . count($allRewards['items']));
+        $this->info('- 代币奖励数量:' . count($allRewards['coins']));
+        $this->info('- 神像奖励数量:' . count($allRewards['gods']));
+
+        $this->info('所有用户扣除数据:');
+        $this->info('- 物品扣除数量:' . count($allDeducts['items']));
+        $this->info('- 代币扣除数量:' . count($allDeducts['coins']));
+
+        // 测试获取指定用户数据
+        $user1Rewards = RewardCollectorService::getRewards(1001);
+        $user1Deducts = DeductCollectorService::getDeducts(1001);
+
+        $this->info('用户1001奖励数据:');
+        $this->info('- 物品奖励数量:' . count($user1Rewards['items']));
+        $this->info('- 代币奖励数量:' . count($user1Rewards['coins']));
+        $this->info('- 神像奖励数量:' . count($user1Rewards['gods']));
+
+        $this->info('用户1001扣除数据:');
+        $this->info('- 物品扣除数量:' . count($user1Deducts['items']));
+        $this->info('- 代币扣除数量:' . count($user1Deducts['coins']));
+
+        $user2Rewards = RewardCollectorService::getRewards(1002);
+        $user2Deducts = DeductCollectorService::getDeducts(1002);
+
+        $this->info('用户1002奖励数据:');
+        $this->info('- 物品奖励数量:' . count($user2Rewards['items']));
+        $this->info('- 代币奖励数量:' . count($user2Rewards['coins']));
+        $this->info('- 神像奖励数量:' . count($user2Rewards['gods']));
+
+        $this->info('用户1002扣除数据:');
+        $this->info('- 物品扣除数量:' . count($user2Deducts['items']));
+        $this->info('- 代币扣除数量:' . count($user2Deducts['coins']));
+
+        // 测试检查功能
+        $hasAllRewards = RewardCollectorService::hasRewards();
+        $hasUser1Rewards = RewardCollectorService::hasRewards(1001);
+        $hasUser3Rewards = RewardCollectorService::hasRewards(9999); // 不存在的用户
+
+        $this->info('检查功能测试:');
+        $this->info('- 是否有奖励数据(所有用户):' . ($hasAllRewards ? '是' : '否'));
+        $this->info('- 用户1001是否有奖励数据:' . ($hasUser1Rewards ? '是' : '否'));
+        $this->info('- 用户9999是否有奖励数据:' . ($hasUser3Rewards ? '是' : '否'));
+
+        // 验证用户数据隔离
+        $this->verifyUserDataSeparation($user1Rewards, $user2Rewards, $user1Deducts, $user2Deducts);
+
+        $this->info('✅ 查询功能测试完成');
+    }
+
+    /**
+     * 验证用户数据隔离
+     */
+    private function verifyUserDataSeparation($user1Rewards, $user2Rewards, $user1Deducts, $user2Deducts): void
+    {
+        $this->info('=== 验证用户数据隔离 ===');
+
+        // 检查用户1的数据是否包含正确的用户ID
+        foreach ($user1Rewards['items'] as $item) {
+            if ($item['user_id'] !== 1001) {
+                $this->error('❌ 用户1001的物品奖励数据包含错误的用户ID:' . $item['user_id']);
+                return;
+            }
+        }
+
+        foreach ($user1Rewards['coins'] as $coin) {
+            if ($coin['user_id'] !== 1001) {
+                $this->error('❌ 用户1001的代币奖励数据包含错误的用户ID:' . $coin['user_id']);
+                return;
+            }
+        }
+
+        // 检查用户2的数据是否包含正确的用户ID
+        foreach ($user2Rewards['items'] as $item) {
+            if ($item['user_id'] !== 1002) {
+                $this->error('❌ 用户1002的物品奖励数据包含错误的用户ID:' . $item['user_id']);
+                return;
+            }
+        }
+
+        $this->info('✅ 用户数据隔离验证通过');
+    }
+}

+ 42 - 21
app/Module/Game/Docs/奖励扣除收集系统.md

@@ -99,39 +99,60 @@ Event::dispatch(new FundChangedEvent($userId, $fundId, $amount, $beforeBalance,
 如果需要手动添加奖励或扣除数据:
 
 ```php
-// 添加物品奖励
-RewardCollectorService::addItemReward($itemId, $instanceId, $quantity);
+// 添加物品奖励(需要指定用户ID)
+RewardCollectorService::addItemReward($userId, $itemId, $instanceId, $quantity);
 
-// 添加代币奖励
-RewardCollectorService::addCoinReward($coinType, $quantity);
+// 添加代币奖励(需要指定用户ID)
+RewardCollectorService::addCoinReward($userId, $coinType, $quantity);
 
-// 添加物品扣除
-DeductCollectorService::addItemDeduct($itemId, $instanceId, $quantity);
+// 添加神像奖励(需要指定用户ID)
+RewardCollectorService::addGodReward($userId, $godType, $diff, $quantity);
 
-// 添加代币扣除
-DeductCollectorService::addCoinDeduct($coinType, $quantity);
+// 添加物品扣除(需要指定用户ID)
+DeductCollectorService::addItemDeduct($userId, $itemId, $instanceId, $quantity);
+
+// 添加代币扣除(需要指定用户ID)
+DeductCollectorService::addCoinDeduct($userId, $coinType, $quantity);
 ```
 
 ### 5.3 查询数据
 
 ```php
-// 检查是否有奖励数据
-if (RewardCollectorService::hasRewards()) {
-    $rewards = RewardCollectorService::getRewards();
-}
-
-// 检查是否有扣除数据
-if (DeductCollectorService::hasDeducts()) {
-    $deducts = DeductCollectorService::getDeducts();
-}
+// 获取所有奖励数据(所有用户)
+$allRewards = RewardCollectorService::getRewards();
+// 返回格式:['items' => [...], 'coins' => [...], 'gods' => [...]]
+
+// 获取指定用户的奖励数据
+$userRewards = RewardCollectorService::getRewards($userId);
+// 返回格式:['items' => [...], 'coins' => [...], 'gods' => [...]]
+
+// 获取所有扣除数据(所有用户)
+$allDeducts = DeductCollectorService::getDeducts();
+// 返回格式:['items' => [...], 'coins' => [...]]
+
+// 获取指定用户的扣除数据
+$userDeducts = DeductCollectorService::getDeducts($userId);
+// 返回格式:['items' => [...], 'coins' => [...]]
+
+// 检查是否有数据
+$hasRewards = RewardCollectorService::hasRewards(); // 检查所有用户
+$hasUserRewards = RewardCollectorService::hasRewards($userId); // 检查指定用户
+
+$hasDeducts = DeductCollectorService::hasDeducts(); // 检查所有用户
+$hasUserDeducts = DeductCollectorService::hasDeducts($userId); // 检查指定用户
+
+// 清空数据(通常在请求结束时调用)
+RewardCollectorService::clearRewards();
+DeductCollectorService::clearDeducts();
 ```
 
 ## 6. 注意事项
 
-1. **数据累积**:同一物品/代币的多次变更会自动累积数量
-2. **自动清理**:响应返回后会自动清空收集器中的数据
-3. **线程安全**:使用静态变量,仅适用于单次请求内的数据收集
-4. **区别于LastData**:这里收集的是本次请求的奖励/扣除,而LastData是变化但未同步的数据
+1. **用户区分**:所有奖励和扣除数据都按用户ID进行区分收集
+2. **数据累积**:同一用户的同一物品/代币的多次变更会自动累积数量
+3. **自动清理**:响应返回后会自动清空收集器中的数据
+4. **线程安全**:使用静态变量,仅适用于单次请求内的数据收集
+5. **区别于LastData**:这里收集的是本次请求的奖励/扣除,而LastData是变化但未同步的数据
 
 ## 7. 与LastData的区别
 

+ 5 - 3
app/Module/Game/Listeners/FundChangedListener.php

@@ -69,7 +69,7 @@ class FundChangedListener
     /**
      * 收集奖励和扣除数据
      *
-     * 根据资金变更的金额正负来判断是奖励还是扣除
+     * 根据资金变更的金额正负来判断是奖励还是扣除,区分用户收集
      *
      * @param FundChangedEvent $event
      * @return void
@@ -78,16 +78,18 @@ class FundChangedListener
     {
         // 如果金额为正,表示获得代币(奖励)
         if ($event->amount > 0) {
-            RewardCollectorService::addCoinReward($event->fundId, $event->amount);
+            RewardCollectorService::addCoinReward($event->userId, $event->fundId, $event->amount);
             Log::debug('收集代币奖励数据', [
+                'user_id' => $event->userId,
                 'fund_id' => $event->fundId,
                 'amount' => $event->amount,
             ]);
         }
         // 如果金额为负,表示消耗代币(扣除)
         elseif ($event->amount < 0) {
-            DeductCollectorService::addCoinDeduct($event->fundId, abs($event->amount));
+            DeductCollectorService::addCoinDeduct($event->userId, $event->fundId, abs($event->amount));
             Log::debug('收集代币扣除数据', [
+                'user_id' => $event->userId,
                 'fund_id' => $event->fundId,
                 'amount' => abs($event->amount),
             ]);

+ 5 - 1
app/Module/Game/Listeners/ItemQuantityChangedListener.php

@@ -66,7 +66,7 @@ class ItemQuantityChangedListener
     /**
      * 收集奖励和扣除数据
      *
-     * 根据物品数量变更的正负来判断是奖励还是扣除
+     * 根据物品数量变更的正负来判断是奖励还是扣除,区分用户收集
      *
      * @param ItemQuantityChanged $event
      * @return void
@@ -76,11 +76,13 @@ class ItemQuantityChangedListener
         // 如果变更量为正,表示获得物品(奖励)
         if ($event->changeAmount > 0) {
             RewardCollectorService::addItemReward(
+                $event->userId,
                 $event->itemId,
                 $event->instanceId ?? 0,
                 $event->changeAmount
             );
             Log::debug('收集物品奖励数据', [
+                'user_id' => $event->userId,
                 'item_id' => $event->itemId,
                 'instance_id' => $event->instanceId,
                 'amount' => $event->changeAmount,
@@ -89,11 +91,13 @@ class ItemQuantityChangedListener
         // 如果变更量为负,表示消耗物品(扣除)
         elseif ($event->changeAmount < 0) {
             DeductCollectorService::addItemDeduct(
+                $event->userId,
                 $event->itemId,
                 $event->instanceId ?? 0,
                 abs($event->changeAmount)
             );
             Log::debug('收集物品扣除数据', [
+                'user_id' => $event->userId,
                 'item_id' => $event->itemId,
                 'instance_id' => $event->instanceId,
                 'amount' => abs($event->changeAmount),

+ 78 - 22
app/Module/Game/Logics/DeductCollectorLogic.php

@@ -11,16 +11,16 @@ namespace App\Module\Game\Logics;
 class DeductCollectorLogic
 {
     /**
-     * 物品扣除数据
-     * 格式:[item_id => ['item_id' => int, 'instance_id' => int, 'quantity' => int]]
+     * 物品扣除数据,按用户分组
+     * 格式:[user_id => [item_key => ['user_id' => int, 'item_id' => int, 'instance_id' => int, 'quantity' => int]]]
      *
      * @var array
      */
     private static array $itemDeducts = [];
 
     /**
-     * 代币扣除数据
-     * 格式:[coin_type => ['type' => int, 'quantity' => int]]
+     * 代币扣除数据,按用户分组
+     * 格式:[user_id => [coin_type => ['user_id' => int, 'type' => int, 'quantity' => int]]]
      *
      * @var array
      */
@@ -29,21 +29,27 @@ class DeductCollectorLogic
     /**
      * 添加物品扣除
      *
+     * @param int $userId 用户ID
      * @param int $itemId 物品ID
      * @param int $instanceId 物品实例ID
      * @param int $quantity 扣除数量
      * @return void
      */
-    public static function addItemDeduct(int $itemId, int $instanceId, int $quantity): void
+    public static function addItemDeduct(int $userId, int $itemId, int $instanceId, int $quantity): void
     {
-        $key = $itemId . '_' . $instanceId;
-        
-        if (isset(self::$itemDeducts[$key])) {
+        $key = "{$itemId}_{$instanceId}";
+
+        if (!isset(self::$itemDeducts[$userId])) {
+            self::$itemDeducts[$userId] = [];
+        }
+
+        if (isset(self::$itemDeducts[$userId][$key])) {
             // 如果已存在,累加数量
-            self::$itemDeducts[$key]['quantity'] += $quantity;
+            self::$itemDeducts[$userId][$key]['quantity'] += $quantity;
         } else {
             // 新增扣除记录
-            self::$itemDeducts[$key] = [
+            self::$itemDeducts[$userId][$key] = [
+                'user_id' => $userId,
                 'item_id' => $itemId,
                 'instance_id' => $instanceId,
                 'quantity' => $quantity,
@@ -54,18 +60,24 @@ class DeductCollectorLogic
     /**
      * 添加代币扣除
      *
+     * @param int $userId 用户ID
      * @param int $coinType 代币类型
      * @param int $quantity 扣除数量
      * @return void
      */
-    public static function addCoinDeduct(int $coinType, int $quantity): void
+    public static function addCoinDeduct(int $userId, int $coinType, int $quantity): void
     {
-        if (isset(self::$coinDeducts[$coinType])) {
+        if (!isset(self::$coinDeducts[$userId])) {
+            self::$coinDeducts[$userId] = [];
+        }
+
+        if (isset(self::$coinDeducts[$userId][$coinType])) {
             // 如果已存在,累加数量
-            self::$coinDeducts[$coinType]['quantity'] += $quantity;
+            self::$coinDeducts[$userId][$coinType]['quantity'] += $quantity;
         } else {
             // 新增扣除记录
-            self::$coinDeducts[$coinType] = [
+            self::$coinDeducts[$userId][$coinType] = [
+                'user_id' => $userId,
                 'type' => $coinType,
                 'quantity' => $quantity,
             ];
@@ -75,13 +87,34 @@ class DeductCollectorLogic
     /**
      * 获取本次请求的所有扣除数据
      *
+     * @param int|null $userId 用户ID,如果为null则返回所有用户的数据
      * @return array 扣除数据数组,包含items和coins
      */
-    public static function getDeducts(): array
+    public static function getDeducts(?int $userId = null): array
     {
+        if ($userId !== null) {
+            // 返回指定用户的扣除数据
+            return [
+                'items' => array_values(self::$itemDeducts[$userId] ?? []),
+                'coins' => array_values(self::$coinDeducts[$userId] ?? []),
+            ];
+        }
+
+        // 返回所有用户的扣除数据,合并为一个数组
+        $allItems = [];
+        $allCoins = [];
+
+        foreach (self::$itemDeducts as $userItems) {
+            $allItems = array_merge($allItems, array_values($userItems));
+        }
+
+        foreach (self::$coinDeducts as $userCoins) {
+            $allCoins = array_merge($allCoins, array_values($userCoins));
+        }
+
         return [
-            'items' => array_values(self::$itemDeducts),
-            'coins' => array_values(self::$coinDeducts),
+            'items' => $allItems,
+            'coins' => $allCoins,
         ];
     }
 
@@ -99,30 +132,53 @@ class DeductCollectorLogic
     /**
      * 检查是否有扣除数据
      *
+     * @param int|null $userId 用户ID,如果为null则检查所有用户
      * @return bool
      */
-    public static function hasDeducts(): bool
+    public static function hasDeducts(?int $userId = null): bool
     {
+        if ($userId !== null) {
+            return !empty(self::$itemDeducts[$userId]) || !empty(self::$coinDeducts[$userId]);
+        }
+
         return !empty(self::$itemDeducts) || !empty(self::$coinDeducts);
     }
 
     /**
      * 获取物品扣除数据
      *
+     * @param int|null $userId 用户ID,如果为null则返回所有用户的数据
      * @return array
      */
-    public static function getItemDeducts(): array
+    public static function getItemDeducts(?int $userId = null): array
     {
-        return array_values(self::$itemDeducts);
+        if ($userId !== null) {
+            return array_values(self::$itemDeducts[$userId] ?? []);
+        }
+
+        $allItems = [];
+        foreach (self::$itemDeducts as $userItems) {
+            $allItems = array_merge($allItems, array_values($userItems));
+        }
+        return $allItems;
     }
 
     /**
      * 获取代币扣除数据
      *
+     * @param int|null $userId 用户ID,如果为null则返回所有用户的数据
      * @return array
      */
-    public static function getCoinDeducts(): array
+    public static function getCoinDeducts(?int $userId = null): array
     {
-        return array_values(self::$coinDeducts);
+        if ($userId !== null) {
+            return array_values(self::$coinDeducts[$userId] ?? []);
+        }
+
+        $allItems = [];
+        foreach (self::$coinDeducts as $userCoins) {
+            $allItems = array_merge($allItems, array_values($userCoins));
+        }
+        return $allItems;
     }
 }

+ 109 - 32
app/Module/Game/Logics/RewardCollectorLogic.php

@@ -11,24 +11,24 @@ namespace App\Module\Game\Logics;
 class RewardCollectorLogic
 {
     /**
-     * 物品奖励数据
-     * 格式:[item_id => ['item_id' => int, 'instance_id' => int, 'quantity' => int]]
+     * 物品奖励数据,按用户分组
+     * 格式:[user_id => [item_key => ['user_id' => int, 'item_id' => int, 'instance_id' => int, 'quantity' => int]]]
      *
      * @var array
      */
     private static array $itemRewards = [];
 
     /**
-     * 代币奖励数据
-     * 格式:[coin_type => ['type' => int, 'quantity' => int]]
+     * 代币奖励数据,按用户分组
+     * 格式:[user_id => [coin_type => ['user_id' => int, 'type' => int, 'quantity' => int]]]
      *
      * @var array
      */
     private static array $coinRewards = [];
 
     /**
-     * 神像奖励数据
-     * 格式:[god_type => ['type' => int, 'diff' => int, 'quantity' => int]]
+     * 神像奖励数据,按用户分组
+     * 格式:[user_id => [god_type => ['user_id' => int, 'type' => int, 'diff' => int, 'quantity' => int]]]
      *
      * @var array
      */
@@ -37,21 +37,27 @@ class RewardCollectorLogic
     /**
      * 添加物品奖励
      *
+     * @param int $userId 用户ID
      * @param int $itemId 物品ID
      * @param int $instanceId 物品实例ID
      * @param int $quantity 奖励数量
      * @return void
      */
-    public static function addItemReward(int $itemId, int $instanceId, int $quantity): void
+    public static function addItemReward(int $userId, int $itemId, int $instanceId, int $quantity): void
     {
-        $key = $itemId . '_' . $instanceId;
-        
-        if (isset(self::$itemRewards[$key])) {
+        $key = "{$itemId}_{$instanceId}";
+
+        if (!isset(self::$itemRewards[$userId])) {
+            self::$itemRewards[$userId] = [];
+        }
+
+        if (isset(self::$itemRewards[$userId][$key])) {
             // 如果已存在,累加数量
-            self::$itemRewards[$key]['quantity'] += $quantity;
+            self::$itemRewards[$userId][$key]['quantity'] += $quantity;
         } else {
             // 新增奖励记录
-            self::$itemRewards[$key] = [
+            self::$itemRewards[$userId][$key] = [
+                'user_id' => $userId,
                 'item_id' => $itemId,
                 'instance_id' => $instanceId,
                 'quantity' => $quantity,
@@ -62,18 +68,24 @@ class RewardCollectorLogic
     /**
      * 添加代币奖励
      *
+     * @param int $userId 用户ID
      * @param int $coinType 代币类型
      * @param int $quantity 奖励数量
      * @return void
      */
-    public static function addCoinReward(int $coinType, int $quantity): void
+    public static function addCoinReward(int $userId, int $coinType, int $quantity): void
     {
-        if (isset(self::$coinRewards[$coinType])) {
+        if (!isset(self::$coinRewards[$userId])) {
+            self::$coinRewards[$userId] = [];
+        }
+
+        if (isset(self::$coinRewards[$userId][$coinType])) {
             // 如果已存在,累加数量
-            self::$coinRewards[$coinType]['quantity'] += $quantity;
+            self::$coinRewards[$userId][$coinType]['quantity'] += $quantity;
         } else {
             // 新增奖励记录
-            self::$coinRewards[$coinType] = [
+            self::$coinRewards[$userId][$coinType] = [
+                'user_id' => $userId,
                 'type' => $coinType,
                 'quantity' => $quantity,
             ];
@@ -83,20 +95,26 @@ class RewardCollectorLogic
     /**
      * 添加神像奖励
      *
+     * @param int $userId 用户ID
      * @param int $godType 神像类型
      * @param int $diff 时间差值(秒)
      * @param int $quantity 奖励数量
      * @return void
      */
-    public static function addGodReward(int $godType, int $diff, int $quantity): void
+    public static function addGodReward(int $userId, int $godType, int $diff, int $quantity): void
     {
-        if (isset(self::$godRewards[$godType])) {
+        if (!isset(self::$godRewards[$userId])) {
+            self::$godRewards[$userId] = [];
+        }
+
+        if (isset(self::$godRewards[$userId][$godType])) {
             // 如果已存在,累加数量和时间
-            self::$godRewards[$godType]['quantity'] += $quantity;
-            self::$godRewards[$godType]['diff'] += $diff;
+            self::$godRewards[$userId][$godType]['quantity'] += $quantity;
+            self::$godRewards[$userId][$godType]['diff'] += $diff;
         } else {
             // 新增奖励记录
-            self::$godRewards[$godType] = [
+            self::$godRewards[$userId][$godType] = [
+                'user_id' => $userId,
                 'type' => $godType,
                 'diff' => $diff,
                 'quantity' => $quantity,
@@ -107,14 +125,41 @@ class RewardCollectorLogic
     /**
      * 获取本次请求的所有奖励数据
      *
+     * @param int|null $userId 用户ID,如果为null则返回所有用户的数据
      * @return array 奖励数据数组,包含items、coins和gods
      */
-    public static function getRewards(): array
+    public static function getRewards(?int $userId = null): array
     {
+        if ($userId !== null) {
+            // 返回指定用户的奖励数据
+            return [
+                'items' => array_values(self::$itemRewards[$userId] ?? []),
+                'coins' => array_values(self::$coinRewards[$userId] ?? []),
+                'gods' => array_values(self::$godRewards[$userId] ?? []),
+            ];
+        }
+
+        // 返回所有用户的奖励数据,合并为一个数组
+        $allItems = [];
+        $allCoins = [];
+        $allGods = [];
+
+        foreach (self::$itemRewards as $userItems) {
+            $allItems = array_merge($allItems, array_values($userItems));
+        }
+
+        foreach (self::$coinRewards as $userCoins) {
+            $allCoins = array_merge($allCoins, array_values($userCoins));
+        }
+
+        foreach (self::$godRewards as $userGods) {
+            $allGods = array_merge($allGods, array_values($userGods));
+        }
+
         return [
-            'items' => array_values(self::$itemRewards),
-            'coins' => array_values(self::$coinRewards),
-            'gods' => array_values(self::$godRewards),
+            'items' => $allItems,
+            'coins' => $allCoins,
+            'gods' => $allGods,
         ];
     }
 
@@ -133,40 +178,72 @@ class RewardCollectorLogic
     /**
      * 检查是否有奖励数据
      *
+     * @param int|null $userId 用户ID,如果为null则检查所有用户
      * @return bool
      */
-    public static function hasRewards(): bool
+    public static function hasRewards(?int $userId = null): bool
     {
+        if ($userId !== null) {
+            return !empty(self::$itemRewards[$userId]) || !empty(self::$coinRewards[$userId]) || !empty(self::$godRewards[$userId]);
+        }
+
         return !empty(self::$itemRewards) || !empty(self::$coinRewards) || !empty(self::$godRewards);
     }
 
     /**
      * 获取物品奖励数据
      *
+     * @param int|null $userId 用户ID,如果为null则返回所有用户的数据
      * @return array
      */
-    public static function getItemRewards(): array
+    public static function getItemRewards(?int $userId = null): array
     {
-        return array_values(self::$itemRewards);
+        if ($userId !== null) {
+            return array_values(self::$itemRewards[$userId] ?? []);
+        }
+
+        $allItems = [];
+        foreach (self::$itemRewards as $userItems) {
+            $allItems = array_merge($allItems, array_values($userItems));
+        }
+        return $allItems;
     }
 
     /**
      * 获取代币奖励数据
      *
+     * @param int|null $userId 用户ID,如果为null则返回所有用户的数据
      * @return array
      */
-    public static function getCoinRewards(): array
+    public static function getCoinRewards(?int $userId = null): array
     {
-        return array_values(self::$coinRewards);
+        if ($userId !== null) {
+            return array_values(self::$coinRewards[$userId] ?? []);
+        }
+
+        $allCoins = [];
+        foreach (self::$coinRewards as $userCoins) {
+            $allCoins = array_merge($allCoins, array_values($userCoins));
+        }
+        return $allCoins;
     }
 
     /**
      * 获取神像奖励数据
      *
+     * @param int|null $userId 用户ID,如果为null则返回所有用户的数据
      * @return array
      */
-    public static function getGodRewards(): array
+    public static function getGodRewards(?int $userId = null): array
     {
-        return array_values(self::$godRewards);
+        if ($userId !== null) {
+            return array_values(self::$godRewards[$userId] ?? []);
+        }
+
+        $allGods = [];
+        foreach (self::$godRewards as $userGods) {
+            $allGods = array_merge($allGods, array_values($userGods));
+        }
+        return $allGods;
     }
 }

+ 34 - 8
app/Module/Game/Services/DeductCollectorService.php

@@ -15,36 +15,39 @@ class DeductCollectorService
     /**
      * 添加物品扣除
      *
+     * @param int $userId 用户ID
      * @param int $itemId 物品ID
      * @param int $instanceId 物品实例ID
      * @param int $quantity 扣除数量
      * @return void
      */
-    public static function addItemDeduct(int $itemId, int $instanceId, int $quantity): void
+    public static function addItemDeduct(int $userId, int $itemId, int $instanceId, int $quantity): void
     {
-        DeductCollectorLogic::addItemDeduct($itemId, $instanceId, $quantity);
+        DeductCollectorLogic::addItemDeduct($userId, $itemId, $instanceId, $quantity);
     }
 
     /**
      * 添加代币扣除
      *
+     * @param int $userId 用户ID
      * @param int $coinType 代币类型
      * @param int $quantity 扣除数量
      * @return void
      */
-    public static function addCoinDeduct(int $coinType, int $quantity): void
+    public static function addCoinDeduct(int $userId, int $coinType, int $quantity): void
     {
-        DeductCollectorLogic::addCoinDeduct($coinType, $quantity);
+        DeductCollectorLogic::addCoinDeduct($userId, $coinType, $quantity);
     }
 
     /**
      * 获取本次请求的所有扣除数据
      *
+     * @param int|null $userId 用户ID,如果为null则返回所有用户的数据
      * @return array 扣除数据数组,包含items和coins
      */
-    public static function getDeducts(): array
+    public static function getDeducts(?int $userId = null): array
     {
-        return DeductCollectorLogic::getDeducts();
+        return DeductCollectorLogic::getDeducts($userId);
     }
 
     /**
@@ -60,10 +63,33 @@ class DeductCollectorService
     /**
      * 检查是否有扣除数据
      *
+     * @param int|null $userId 用户ID,如果为null则检查所有用户
      * @return bool
      */
-    public static function hasDeducts(): bool
+    public static function hasDeducts(?int $userId = null): bool
     {
-        return DeductCollectorLogic::hasDeducts();
+        return DeductCollectorLogic::hasDeducts($userId);
+    }
+
+    /**
+     * 获取物品扣除数据
+     *
+     * @param int|null $userId 用户ID,如果为null则返回所有用户的数据
+     * @return array
+     */
+    public static function getItemDeducts(?int $userId = null): array
+    {
+        return DeductCollectorLogic::getItemDeducts($userId);
+    }
+
+    /**
+     * 获取代币扣除数据
+     *
+     * @param int|null $userId 用户ID,如果为null则返回所有用户的数据
+     * @return array
+     */
+    public static function getCoinDeducts(?int $userId = null): array
+    {
+        return DeductCollectorLogic::getCoinDeducts($userId);
     }
 }

+ 16 - 11
app/Module/Game/Services/RewardCollectorService.php

@@ -15,49 +15,53 @@ class RewardCollectorService
     /**
      * 添加物品奖励
      *
+     * @param int $userId 用户ID
      * @param int $itemId 物品ID
      * @param int $instanceId 物品实例ID
      * @param int $quantity 奖励数量
      * @return void
      */
-    public static function addItemReward(int $itemId, int $instanceId, int $quantity): void
+    public static function addItemReward(int $userId, int $itemId, int $instanceId, int $quantity): void
     {
-        RewardCollectorLogic::addItemReward($itemId, $instanceId, $quantity);
+        RewardCollectorLogic::addItemReward($userId, $itemId, $instanceId, $quantity);
     }
 
     /**
      * 添加代币奖励
      *
+     * @param int $userId 用户ID
      * @param int $coinType 代币类型
      * @param int $quantity 奖励数量
      * @return void
      */
-    public static function addCoinReward(int $coinType, int $quantity): void
+    public static function addCoinReward(int $userId, int $coinType, int $quantity): void
     {
-        RewardCollectorLogic::addCoinReward($coinType, $quantity);
+        RewardCollectorLogic::addCoinReward($userId, $coinType, $quantity);
     }
 
     /**
      * 添加神像奖励
      *
+     * @param int $userId 用户ID
      * @param int $godType 神像类型
      * @param int $diff 时间差值(秒)
      * @param int $quantity 奖励数量
      * @return void
      */
-    public static function addGodReward(int $godType, int $diff, int $quantity): void
+    public static function addGodReward(int $userId, int $godType, int $diff, int $quantity): void
     {
-        RewardCollectorLogic::addGodReward($godType, $diff, $quantity);
+        RewardCollectorLogic::addGodReward($userId, $godType, $diff, $quantity);
     }
 
     /**
      * 获取本次请求的所有奖励数据
      *
-     * @return array 奖励数据数组,包含items和coins
+     * @param int|null $userId 用户ID,如果为null则返回所有用户的数据
+     * @return array 奖励数据数组,包含items、coins和gods
      */
-    public static function getRewards(): array
+    public static function getRewards(?int $userId = null): array
     {
-        return RewardCollectorLogic::getRewards();
+        return RewardCollectorLogic::getRewards($userId);
     }
 
     /**
@@ -73,10 +77,11 @@ class RewardCollectorService
     /**
      * 检查是否有奖励数据
      *
+     * @param int|null $userId 用户ID,如果为null则检查所有用户
      * @return bool
      */
-    public static function hasRewards(): bool
+    public static function hasRewards(?int $userId = null): bool
     {
-        return RewardCollectorLogic::hasRewards();
+        return RewardCollectorLogic::hasRewards($userId);
     }
 }