orderBy('position') ->get(); // dd($lands); return $lands->map(function ($land) { return LandInfoDto::fromModel($land); }); } catch (\Exception $e) { Log::error('获取用户土地失败', [ 'user_id' => $userId, 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); return collect(); } } /** * 获取用户指定位置的土地 * * @param int $userId * @param int $position * @return LandInfoDto|null */ public function getUserLandByPosition(int $userId, int $position): ?LandInfoDto { try { $land = FarmLand::where('user_id', $userId) ->where('position', $position) ->first(); if (!$land) { return null; } return LandInfoDto::fromModel($land); } catch (\Exception $e) { Log::error('获取用户指定位置土地失败', [ 'user_id' => $userId, 'position' => $position, 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); return null; } } /** * 创建土地 * * @param int $userId * @param int $position * @param int $landType * @return FarmLand|null */ public function createLand(int $userId, int $position, int $landType): ?FarmLand { try { // 检查位置是否已有土地 $existingLand = FarmLand::where('user_id', $userId) ->where('position', $position) ->first(); if ($existingLand) { return $existingLand; } // 创建新土地 $land = new FarmLand(); $land->user_id = $userId; $land->position = $position; $land->land_type = $landType; $land->status = LAND_STATUS::IDLE->value; $land->save(); // 触发土地创建事件 event(new LandCreatedEvent($userId, $land->id)); Log::info('创建土地成功', [ 'user_id' => $userId, 'position' => $position, 'land_type' => $landType, 'land_id' => $land->id ]); return $land; } catch (\Exception $e) { Log::error('创建土地失败', [ 'user_id' => $userId, 'position' => $position, 'land_type' => $landType, 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); return null; } } /** * 升级土地 * 调用前必须已经完成所有验证(土地归属、状态、路径、材料等) * 要求调用者已开启事务 * * @param int $userId * @param int $landId * @param int $targetType * @return bool */ public function upgradeLand(int $userId, int $landId, int $targetType): bool { // 验证事务是否已开启 Helper::check_tr(); // 获取土地信息 /** * @var FarmLand $land */ $land = FarmLand::where('id', $landId) ->where('user_id', $userId) ->first(); // 防错误机制:基础数据检查 if (!$land) { throw new LogicException('Logic层防错误:土地不存在,验证层应该已经检查过'); } // 防错误机制:状态检查 if ($land->status !== LAND_STATUS::IDLE->value) { throw new LogicException('Logic层防错误:土地状态不允许升级,验证层应该已经检查过'); } // 防错误机制:类型检查 if ($land->land_type === $targetType) { throw new LogicException('Logic层防错误:土地已经是目标类型,验证层应该已经检查过'); } // 获取升级配置(这里不再进行完整验证,只获取配置) $config = FarmLandUpgradeConfig::where('from_type_id', $land->land_type) ->where('to_type_id', $targetType) ->first(); // 防错误机制:配置检查 if (!$config) { throw new LogicException('Logic层防错误:升级配置不存在,验证层应该已经检查过'); } // 更新土地类型 $oldType = $land->land_type; $land->land_type = $targetType; $land->save(); if(!$land->save()){ // 保存失败 throw new LogicException('升级失败-2'); } // 创建升级记录 $upgradeLog = new FarmUpgradeLog(); $upgradeLog->user_id = $userId; $upgradeLog->upgrade_type = UPGRADE_TYPE::LAND->value; $upgradeLog->target_id = $landId; $upgradeLog->old_level = $oldType; $upgradeLog->new_level = $targetType; $upgradeLog->materials_consumed = []; $upgradeLog->upgrade_time = now(); $upgradeLog->created_at = now(); if(!$upgradeLog->save()){ // 保存失败 throw new LogicException('升级失败-3'); } // 进行消耗 $ec = ConsumeService::executeConsume( $userId, $config->materials, REWARD_SOURCE_TYPE::LAND_UPGRADE, $upgradeLog->id, false); if ($ec->error) { throw new LogicException('消耗失败'); } $upgradeLog->materials_consumed = $ec->data['list']; $upgradeLog->save(); // 触发土地升级事件 event(new LandUpgradedEvent($userId, $land, $oldType, $targetType, $upgradeLog)); Log::info('土地升级成功', [ 'user_id' => $userId, 'land_id' => $landId, 'old_type' => $oldType, 'new_type' => $targetType, 'upgrade_log_id' => $upgradeLog->id ]); return true; } /** * 检查升级路径 * * @param $userId * @param $currentType * @param $targetType * @param bool $checkM 是否检查消耗 * @return Res * @throws \Exception */ static public function checkUpgradePath(int $userId, int $currentType, int $targetType, bool $checkM = true): Res { // 获取升级配置 /** * @var FarmLandUpgradeConfig $upgradeConfig */ $upgradeConfig = FarmLandUpgradeConfig::where('from_type_id', $currentType) ->where('to_type_id', $targetType) ->first(); if (!$upgradeConfig) { Log::error('升级路径不存在', [ 'user_id' => $userId, 'current_type' => $currentType, 'target_type' => $targetType ]); return Res::error('升级路径不存在', [ 'user_id' => $userId, 'current_type' => $currentType, 'target_type' => $targetType ]); } // 检查用户房屋等级是否满足要求 $targetLandType = FarmLandType::find($targetType); $farmUser = FarmUser::where('user_id', $userId)->first(); if (!$farmUser || $farmUser->house_level < $targetLandType->unlock_house_level) { Log::error('房屋等级不足,无法升级到该土地类型', [ 'user_id' => $userId, 'current_type' => $currentType, 'target_type' => $targetType, 'house_level' => $farmUser->house_level, 'unlock_house_level' => $targetLandType->unlock_house_level ]); return Res::error('房屋等级不足,无法升级到该土地类型', [ 'user_id' => $userId, 'current_type' => $currentType, 'target_type' => $targetType, 'house_level' => $farmUser->house_level, 'unlock_house_level' => $targetLandType->unlock_house_level ]); } // 检查特殊土地数量限制 if ($targetLandType->is_special) { $specialLandCount = FarmLand::where('user_id', $userId) ->whereIn('land_type', [ LAND_TYPE::GOLD->value, LAND_TYPE::BLUE->value, LAND_TYPE::PURPLE->value ]) ->count(); $houseConfig = $farmUser->houseConfig; if ($specialLandCount >= $houseConfig->special_land_limit) { Log::error('特殊土地数量已达上限', [ 'user_id' => $userId, 'current_type' => $currentType, 'target_type' => $targetType, 'special_land_count' => $specialLandCount, 'special_land_limit' => $houseConfig->special_land_limit ]); return Res::error('特殊土地数量已达上限', [ 'user_id' => $userId, 'current_type' => $currentType, 'target_type' => $targetType, 'special_land_count' => $specialLandCount, 'special_land_limit' => $houseConfig->special_land_limit ]); } } // 检查消耗 if ($checkM) { $res = ConsumeService::checkConsume($userId, $upgradeConfig->materials); if ($res->error) { Log::error('当前路径资源不足', [ 'user_id' => $userId, 'current_type' => $currentType, 'target_type' => $targetType, 'error' => $res->message ]); return Res::error('当前路径资源不足', [ 'msg' => $res->message ]); } } return Res::success('升级路径可用', [ 'config' => $upgradeConfig ]); } /** * 获取升级所需材料 * * @param int $currentType 当前土地类型 * @param int $targetType 目标土地类型 * @return array 升级所需材料 */ public function getUpgradeMaterials(int $currentType, int $targetType): array { try { // 从数据库中获取升级配置 $upgradeConfig = FarmLandUpgradeConfig::where('from_type_id', $currentType) ->where('to_type_id', $targetType) ->first(); if (!$upgradeConfig) { return []; } // 使用模型的 getUpgradeMaterials 方法获取材料 return $upgradeConfig->getUpgradeMaterials(); } catch (\Exception $e) { Log::error('获取升级所需材料失败', [ 'current_type' => $currentType, 'target_type' => $targetType, 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); return []; } } /** * 获取可用的升级路径(不进行消耗检查) * * @param int $userId 用户ID * @param int $landId 土地ID * @param int|null $toType 目标土地类型ID(可选) * @return FarmLandUpgradeConfig[] * */ public function getAvailableUpgradePaths(int $userId, int $landId, ?int $toType = null): array { try { // 获取土地信息 $land = FarmLand::where('id', $landId) ->where('user_id', $userId) ->first(); if (!$land) { return []; } // 获取当前土地类型 $currentType = $land->land_type; // 获取用户房屋等级 /** * @var FarmUser $farmUser */ $farmUser = FarmUser::where('user_id', $userId)->first(); if (!$farmUser) { return []; } $houseLevel = $farmUser->house_level; // 获取可用的升级路径 $query = FarmLandUpgradeConfig::where('from_type_id', $currentType) ->with('toType'); // 如果指定了目标类型,则只获取该类型的升级路径 if ($toType !== null) { $query->where('to_type_id', $toType); } $upgradePaths = $query->get(); // 过滤出符合房屋等级要求的升级路径 $availablePaths = $upgradePaths->filter(function ($path) use ($houseLevel) { return $path->toType->unlock_house_level <= $houseLevel; }); // 检查特殊土地数量限制 $specialLandCount = FarmLand::where('user_id', $userId) ->whereIn('land_type', [ LAND_TYPE::GOLD->value, LAND_TYPE::BLUE->value, LAND_TYPE::PURPLE->value ]) ->count(); $houseConfig = $farmUser->houseConfig; // 如果没有找到对应的房屋配置,使用默认值0 $specialLandLimit = $houseConfig ? $houseConfig->special_land_limit : 0; // 如果特殊土地已达上限,过滤掉特殊土地升级路径 if ($specialLandCount >= $specialLandLimit) { $availablePaths = $availablePaths->filter(function ($path) { return !$path->toType->is_special; }); } // 格式化返回结果 return $availablePaths->toArray(); } catch (\Exception $e) { Log::error('获取可用升级路径失败', [ 'user_id' => $userId, 'land_id' => $landId, 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); return []; } } /** * 获取用户所有可收获的土地 * * @param int $userId 用户ID * @return Collection|LandInfoDto[] */ public function getHarvestableLands(int $userId): Collection { try { // 查询状态为可收获的土地 $lands = FarmLand::where('user_id', $userId) ->where('status', LAND_STATUS::HARVESTABLE->value) ->orderBy('position') ->get(); return $lands->map(function ($land) { return LandInfoDto::fromModel($land); }); } catch (\Exception $e) { Log::error('获取可收获土地失败', [ 'user_id' => $userId, 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); return collect(); } } /** * 获取用户所有空闲的土地 * * @param int $userId 用户ID * @return Collection|LandInfoDto[] */ public function getIdleLands(int $userId): Collection { try { // 查询状态为空闲的土地 $lands = FarmLand::where('user_id', $userId) ->where('status', LAND_STATUS::IDLE->value) ->orderBy('position') ->get(); return $lands->map(function ($land) { return LandInfoDto::fromModel($land); }); } catch (\Exception $e) { Log::error('获取空闲土地失败', [ 'user_id' => $userId, 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); return collect(); } } /** * 获取用户所有有作物的土地 * * @param int $userId 用户ID * @return Collection|LandInfoDto[] */ public function getLandsWithCrops(int $userId): Collection { try { // 查询状态为种植中的土地 $lands = FarmLand::where('user_id', $userId) ->where('has_crop', true) ->orderBy('position') ->get(); return $lands->map(function ($land) { return LandInfoDto::fromModel($land); }); } catch (\Exception $e) { Log::error('获取有作物的土地失败', [ 'user_id' => $userId, 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); return collect(); } } }