用户浇水成功后,Response 的 LastData 中缺失 DataLands 信息,导致客户端无法及时更新土地状态。
通过代码分析发现,系统使用了土地暂存系统(LandTemp)来处理土地状态变更,然后通过 AppGameProtobufResponseListener 监听器在响应中自动添加 LastData。但是浇水操作成功后,存在以下问题:
灾害清理时未触发土地状态变更事件:在 CropLogic::clearDisaster 方法中,虽然更新了土地状态,但没有触发 LandStatusChangedEvent 事件。
缺少灾害清理事件监听器:虽然触发了 DisasterClearedEvent 事件,但没有相应的监听器来处理土地暂存数据的更新。
灾害生成时也存在同样问题:在 DisasterLogic::applyDisastersToCrop 方法中,更新土地状态时也没有触发相应的事件。
文件: app/Module/Farm/Logics/CropLogic.php
在 clearDisaster 方法中添加土地状态变更事件的触发:
// 如果没有其他活跃灾害,更新土地状态
$oldLandStatus = $land->status;
if (!$hasActiveDisaster) {
$land->status = LAND_STATUS::PLANTING->value;
}
// 保存更改
$crop->save();
$land->save();
// 如果土地状态发生了变化,触发土地状态变更事件
if ($oldLandStatus !== $land->status) {
event(new LandStatusChangedEvent($userId, $landId, $oldLandStatus, $land->status));
}
文件: app/Module/Game/Listeners/DisasterClearedListener.php
创建专门的监听器来处理 DisasterClearedEvent 事件,更新土地暂存数据:
public function handle(DisasterClearedEvent $event): void
{
// 获取土地信息并构建暂存数据
$land = $event->crop->land;
$landStatusData = [
'land_id' => $land->id,
'status' => $land->status,
'crop' => $event->crop->toArray(),
'updated_at' => now()->toDateTimeString()
];
// 存储到暂存系统
$tempKey = LandTemp::TEMP_KEY_STATUS_PREFIX . $event->userId;
$userLandsStatusTemp = \UCore\Helper\Cache::get($tempKey, []);
$userLandsStatusTemp[$land->id] = \App\Module\Game\Dtos\LandStatusTempDto::fromArray($landStatusData);
\UCore\Helper\Cache::put($tempKey, $userLandsStatusTemp, LandTemp::TEMP_TTL);
}
文件: app/Module/Game/Providers/GameServiceProvider.php
在 Game 模块的服务提供者中注册新的监听器:
// 注册灾害清理事件监听器
Event::listen(
DisasterClearedEvent::class,
DisasterClearedListener::class
);
文件: app/Module/Farm/Logics/DisasterLogic.php
在 applyDisastersToCrop 方法中添加土地状态变更事件的触发:
// 更新土地状态为灾害
$land = $crop->land;
$oldLandStatus = $land->status;
$land->status = LAND_STATUS::DISASTER->value;
// 保存更改
$crop->save();
$land->save();
// 如果土地状态发生了变化,触发土地状态变更事件
if ($oldLandStatus !== $land->status) {
event(new \App\Module\Farm\Events\LandStatusChangedEvent($crop->user_id, $land->id, $oldLandStatus, $land->status));
}
修复后,当用户进行浇水操作时:
成功浇水:
DISASTER 更新为 PLANTINGLandStatusChangedEvent 和 DisasterClearedEvent 事件AppGameProtobufResponseListener 自动将暂存数据添加到 Response 的 LastData 中失败浇水:
用户浇水操作
↓
WateringHandler 处理请求
↓
CropService::removeDisasterWithItem (概率判断)
↓
DisasterRemovalLogic::removeDisaster
↓
CropLogic::clearDisaster
↓
触发 LandStatusChangedEvent + DisasterClearedEvent
↓
LandStatusChangedListener + DisasterClearedListener 处理事件
↓
更新土地暂存数据 (LandTemp)
↓
AppGameProtobufResponseListener 监听响应事件
↓
从暂存数据构建 LastData.lands
↓
客户端收到包含 DataLands 的响应
创建了功能测试 tests/Feature/WateringResponseTest.php 来验证:
app/Module/Farm/Logics/CropLogic.phpapp/Module/Farm/Logics/DisasterLogic.phpapp/Module/Game/Providers/GameServiceProvider.phpapp/Module/Game/Listeners/DisasterClearedListener.phptests/Feature/WateringResponseTest.php