|
|
@@ -13,6 +13,7 @@ use App\Module\Farm\Models\FarmLand;
|
|
|
use App\Module\Farm\Models\FarmCropLog;
|
|
|
use App\Module\Farm\Services\DisasterService;
|
|
|
use Illuminate\Support\Collection;
|
|
|
+use Illuminate\Support\Facades\DB;
|
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
|
|
/**
|
|
|
@@ -114,10 +115,7 @@ class DisasterLogic
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
- // 跳过已经有灾害的土地
|
|
|
- if ($land->status === LAND_STATUS::DISASTER) {
|
|
|
- return null;
|
|
|
- }
|
|
|
+ // 注意:根据文档,作物灾害和土地无关,不需要检查土地状态
|
|
|
|
|
|
$userId = $crop->user_id;
|
|
|
$seed = $crop->seed;
|
|
|
@@ -277,6 +275,7 @@ class DisasterLogic
|
|
|
$disasters = array_merge($disasters, $disasterInfos);
|
|
|
$crop->disasters = $disasters;
|
|
|
|
|
|
+ // TODO: 根据文档,作物灾害和土地无关,此处更新土地状态可能需要重新评估
|
|
|
// 更新土地状态为灾害
|
|
|
$land = $crop->land;
|
|
|
$oldLandStatus = $land->status;
|
|
|
@@ -371,12 +370,10 @@ class DisasterLogic
|
|
|
public function generateDisasters(FarmCrop $crop): string
|
|
|
{
|
|
|
try {
|
|
|
- // 更新检查时间
|
|
|
- $crop->last_disaster_check_time = now();
|
|
|
+ // 1. 先进行基础检查和计算(不在事务中,减少锁时间)
|
|
|
|
|
|
- // 检查用户是否存在,如果不存在则跳过
|
|
|
+ // 检查用户是否存在
|
|
|
if (!$crop->user) {
|
|
|
- $crop->save(); // 仍需更新检查时间
|
|
|
Log::warning('作物关联的用户不存在,跳过灾害生成', [
|
|
|
'crop_id' => $crop->id,
|
|
|
'user_id' => $crop->user_id
|
|
|
@@ -384,41 +381,58 @@ class DisasterLogic
|
|
|
return 'skipped';
|
|
|
}
|
|
|
|
|
|
- // 跳过已经有灾害的土地
|
|
|
- if ($crop->land->status === LAND_STATUS::DISASTER) {
|
|
|
- $crop->save(); // 仍需更新检查时间
|
|
|
- return 'skipped';
|
|
|
- }
|
|
|
+ // 注意:根据文档,作物灾害和土地无关,不需要检查土地状态
|
|
|
|
|
|
- // 获取相关数据
|
|
|
+ // 获取相关数据并计算灾害
|
|
|
$disasterResistance = $crop->seed->disaster_resistance ?? null;
|
|
|
- $landDisasterResistance = ($crop->land->landType->disaster_resistance ?? 0) / 100; // 数据库存储百分比,需要除以100
|
|
|
+ $landDisasterResistance = ($crop->land->landType->disaster_resistance ?? 0) / 100;
|
|
|
$activeBuffs = $crop->user->buffs->pluck('buff_type')->toArray();
|
|
|
|
|
|
// 尝试生成灾害(支持多种灾害)
|
|
|
$disasterInfos = $this->tryGenerateDisasterForCrop($crop, $disasterResistance, $landDisasterResistance, $activeBuffs);
|
|
|
|
|
|
- if (!empty($disasterInfos)) {
|
|
|
- // 应用灾害到作物
|
|
|
- $this->applyDisastersToCrop($crop, $disasterInfos);
|
|
|
-
|
|
|
- // 生成灾害后,设置当前阶段不能再产生灾害
|
|
|
- $crop->can_disaster = false;
|
|
|
- $crop->save();
|
|
|
-
|
|
|
- Log::info('单个作物灾害生成成功', [
|
|
|
- 'crop_id' => $crop->id,
|
|
|
- 'user_id' => $crop->user_id,
|
|
|
- 'disaster_count' => count($disasterInfos),
|
|
|
- 'disaster_types' => array_column($disasterInfos, 'type')
|
|
|
- ]);
|
|
|
+ // 2. 开启事务进行有锁更新
|
|
|
+ return DB::transaction(function () use ($crop, $disasterInfos) {
|
|
|
+ // 使用行锁重新获取作物,确保数据一致性
|
|
|
+ $lockedCrop = FarmCrop::where('id', $crop->id)
|
|
|
+ ->lockForUpdate()
|
|
|
+ ->first();
|
|
|
+
|
|
|
+ // 如果作物不存在或已被软删除,跳过处理
|
|
|
+ if (!$lockedCrop || $lockedCrop->trashed()) {
|
|
|
+ Log::info('作物已被删除,跳过灾害生成', [
|
|
|
+ 'crop_id' => $crop->id,
|
|
|
+ 'user_id' => $crop->user_id
|
|
|
+ ]);
|
|
|
+ return 'skipped';
|
|
|
+ }
|
|
|
|
|
|
- return 'generated';
|
|
|
- } else {
|
|
|
- // 没有生成灾害,但需要保存检查时间
|
|
|
- $crop->save();
|
|
|
- return 'checked';
|
|
|
- }
|
|
|
+ // 更新检查时间
|
|
|
+ $lockedCrop->last_disaster_check_time = now();
|
|
|
+
|
|
|
+ // 如果有灾害需要生成,应用到作物
|
|
|
+ if (!empty($disasterInfos)) {
|
|
|
+ // 应用灾害到作物
|
|
|
+ $this->applyDisastersToCrop($lockedCrop, $disasterInfos);
|
|
|
+
|
|
|
+ // 生成灾害后,设置当前阶段不能再产生灾害
|
|
|
+ $lockedCrop->can_disaster = false;
|
|
|
+ $lockedCrop->save();
|
|
|
+
|
|
|
+ Log::info('单个作物灾害生成成功', [
|
|
|
+ 'crop_id' => $lockedCrop->id,
|
|
|
+ 'user_id' => $lockedCrop->user_id,
|
|
|
+ 'disaster_count' => count($disasterInfos),
|
|
|
+ 'disaster_types' => array_column($disasterInfos, 'type')
|
|
|
+ ]);
|
|
|
+
|
|
|
+ return 'generated';
|
|
|
+ } else {
|
|
|
+ // 没有生成灾害,但需要保存检查时间
|
|
|
+ $lockedCrop->save();
|
|
|
+ return 'checked';
|
|
|
+ }
|
|
|
+ });
|
|
|
|
|
|
} catch (\Exception $e) {
|
|
|
Log::error('单个作物灾害生成失败', [
|