| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347 |
- <?php
- namespace App\Module\Pet\Logic;
- use App\Module\Pet\Models\PetUser;
- use App\Module\Pet\Models\PetStealLog;
- use App\Module\Pet\Enums\PetStatus;
- use App\Module\Pet\Dtos\StealResultDto;
- use App\Module\Farm\Models\FarmCrop;
- use App\Module\Farm\Models\FarmLand;
- use App\Module\Farm\Enums\GROWTH_STAGE;
- use App\Module\Pet\Events\PetUpdateEvent;
- use App\Module\Farm\Services\PickService;
- use Illuminate\Support\Facades\Log;
- /**
- * 宠物偷菜逻辑类
- *
- * 处理宠物偷菜的核心业务逻辑
- */
- class PetStealLogic
- {
- /**
- * 执行偷菜操作
- *
- * @param int $stealerId 偷菜者用户ID
- * @param int $targetUserId 被偷者用户ID
- * @param int $plantId 作物ID
- * @param int $petId 宠物ID
- * @return StealResultDto 偷菜结果
- * @throws \Exception 偷菜失败时抛出异常
- */
- public static function stealCrop(int $stealerId, int $targetUserId, int $plantId, int $petId): StealResultDto
- {
- // 检查事务是否已开启
- \UCore\Db\Helper::check_tr();
- try {
- // 1. 获取作物信息
- $crop = FarmCrop::find($plantId);
- if (!$crop) {
- throw new \Exception('作物不存在');
- }
- $landId = $crop->land_id;
- // 2. 基础验证
- $canStealResult = static::canSteal($stealerId, $targetUserId, $landId);
- if (!$canStealResult['can_steal']) {
- throw new \Exception($canStealResult['reason']);
- }
- // 3. 获取指定的偷菜者宠物
- $stealerPet = PetUser::where('id', $petId)
- ->where('user_id', $stealerId)
- ->where('status', PetStatus::NORMAL)
- ->where('stamina', '>=', 20)
- ->first();
- if (!$stealerPet) {
- throw new \Exception('指定的宠物不存在、不属于当前用户、状态异常或体力不足');
- }
- // 4. 验证作物状态
- if ($crop->growth_stage !== GROWTH_STAGE::MATURE) {
- throw new \Exception('作物尚未成熟,无法偷取');
- }
- // 4. 获取被偷者宠物(用于防御判定)
- $targetPet = PetUser::where('user_id', $targetUserId)
- ->where('status', PetStatus::NORMAL)
- ->first();
- // 5. 防御判定
- $defended = false;
- $stealSuccess = true;
- $targetStaminaCost = 0;
- if ($targetPet && $targetPet->stamina >= 10) {
- // 有宠物且有体力,进行防御判定
- if ($targetPet->level >= $stealerPet->level) {
- // 防御成功
- $defended = true;
- $stealSuccess = false;
- $targetStaminaCost = 10;
- }
- }
- // 6. 扣除偷菜者体力(偷菜是瞬时操作,不改变状态)
- $stealerPet->stamina -= 20;
- $stealerPet->save();
- // 触发偷菜者宠物更新事件
- event(new PetUpdateEvent($stealerId, $stealerPet->id));
- // 7. 扣除被偷者体力(如果防御成功)
- if ($defended && $targetPet) {
- $targetPet->stamina -= 10;
- $targetPet->save();
- // 触发被偷者宠物更新事件
- event(new PetUpdateEvent($targetUserId, $targetPet->id));
- }
- $actualPickAmount = 0;
- $pickLogId = null;
- $itemId = null;
- // 8. 如果偷菜成功,执行摘取
- if ($stealSuccess) {
- // 检查是否可以摘取
- if ($crop->pickable_amount <= 0) {
- throw new \Exception('没有可摘取的作物');
- }
- // 计算偷取数量(5-20个随机)
- $pickAmount = rand(5,20);
- $maxPickable = $crop->pickable_amount;
- $actualPickAmount = min($pickAmount, $maxPickable);
- if ($actualPickAmount > 0) {
- // 调用Farm模块的摘取服务进行正规摘取
- $pickResult = PickService::pickCrop(
- $stealerId,
- $crop->id,
- $actualPickAmount,
- 'pet_steal',
- $stealerPet->id
- );
- // 获取摘取结果信息
- $itemId = $pickResult->itemId;
- $pickLogId = $pickResult->pickLogId;
- // 重新获取作物信息(摘取后数据已更新)
- $crop->refresh();
- Log::info('偷菜摘取成功', [
- 'stealer_id' => $stealerId,
- 'crop_id' => $crop->id,
- 'pick_amount' => $actualPickAmount,
- 'item_id' => $itemId,
- 'pick_log_id' => $pickLogId,
- ]);
- }
- }
- // 9. 记录偷菜日志
- $stealLog = PetStealLog::create([
- 'stealer_user_id' => $stealerId,
- 'stealer_pet_id' => $stealerPet->id,
- 'target_user_id' => $targetUserId,
- 'target_pet_id' => $targetPet?->id,
- 'land_id' => $landId,
- 'crop_id' => $crop->id,
- 'success' => $stealSuccess,
- 'defended' => $defended,
- 'steal_amount' => $actualPickAmount,
- 'stealer_stamina_cost' => 20,
- 'target_stamina_cost' => $targetStaminaCost,
- 'pick_log_id' => $pickLogId,
- ]);
- // 10. 记录日志
- Log::info('宠物偷菜操作完成', [
- 'stealer_id' => $stealerId,
- 'target_id' => $targetUserId,
- 'land_id' => $landId,
- 'success' => $stealSuccess,
- 'defended' => $defended,
- 'steal_amount' => $actualPickAmount,
- ]);
- // 13. 返回结果
- if ($stealSuccess) {
- return StealResultDto::success(
- $actualPickAmount,
- $itemId ?? 0,
- $pickLogId,
- $stealLog->id,
- $stealerPet->id,
- $targetPet?->id
- );
- } else {
- return StealResultDto::defended(
- $stealLog->id,
- $stealerPet->id,
- $targetPet?->id
- );
- }
- } catch (\Exception $e) {
- // 记录失败日志
- $stealLog = PetStealLog::create([
- 'stealer_user_id' => $stealerId,
- 'stealer_pet_id' => $stealerPet?->id ?? null,
- 'target_user_id' => $targetUserId,
- 'land_id' => $landId,
- 'success' => false,
- 'defended' => false,
- 'steal_amount' => 0,
- 'stealer_stamina_cost' => 20,
- 'target_stamina_cost' => 0,
- 'fail_reason' => $e->getMessage(),
- ]);
- // 偷菜是瞬时操作,无需恢复状态
- Log::warning('宠物偷菜操作失败', [
- 'stealer_id' => $stealerId,
- 'target_id' => $targetUserId,
- 'land_id' => $landId,
- 'error' => $e->getMessage(),
- ]);
- // 重新抛出异常,不隐藏错误
- throw $e;
- }
- }
- /**
- * 检查是否可以偷菜
- *
- * @param int $stealerId 偷菜者用户ID
- * @param int $targetUserId 被偷者用户ID
- * @param int $landId 土地ID
- * @return array 检查结果 ['can_steal' => bool, 'reason' => string]
- */
- public static function canSteal(int $stealerId, int $targetUserId, int $landId): array
- {
- // 1. 不能偷自己的菜
- if ($stealerId === $targetUserId) {
- return [ 'can_steal' => false, 'reason' => '不能偷自己的菜' ];
- }
- // 2. 检查偷菜者是否有可用宠物
- $stealerPet = PetUser::where('user_id', $stealerId)
- ->where('status', PetStatus::NORMAL)
- ->where('stamina', '>=', 20)
- ->first();
- if (!$stealerPet) {
- return [ 'can_steal' => false, 'reason' => '没有可用的宠物或体力不足' ];
- }
- // 3. 检查土地是否存在
- $land = FarmLand::where('id', $landId)
- ->where('user_id', $targetUserId)
- ->first();
- if (!$land) {
- // 检查土地是否存在但属于其他用户
- $actualLand = FarmLand::where('id', $landId)->first();
- if ($actualLand) {
- return [
- 'can_steal' => false, 'reason' => "土地{$landId}存在但属于用户{$actualLand->user_id},不属于目标用户{$targetUserId}"
- ];
- }
- return [ 'can_steal' => false, 'reason' => "土地{$landId}不存在" ];
- }
- // 4. 检查是否有成熟作物
- $crop = FarmCrop::where('land_id', $landId)
- ->where('growth_stage', GROWTH_STAGE::MATURE)
- ->first();
- if (!$crop) {
- return [ 'can_steal' => false, 'reason' => '没有可偷的成熟作物' ];
- }
- // 5. 检查偷菜次数限制
- if (!PetStealLog::canStealLand($landId)) {
- return [ 'can_steal' => false, 'reason' => '该作物已被偷取5次,无法继续偷取' ];
- }
- // 6. 检查作物是否可摘取
- if ($crop->pickable_amount <= 0) {
- return [ 'can_steal' => false, 'reason' => '没有可摘取的作物' ];
- }
- return [ 'can_steal' => true, 'reason' => '' ];
- }
- /**
- * 获取土地的偷菜信息
- *
- * @param int $landId 土地ID
- * @return array 偷菜信息
- */
- public static function getStealInfo(int $landId): array
- {
- $successfulStealCount = PetStealLog::getSuccessfulStealCount($landId);
- $canSteal = PetStealLog::canStealLand($landId);
- return [
- 'land_id' => $landId,
- 'successful_steal_count' => $successfulStealCount,
- 'max_steal_times' => 5,
- 'remaining_steal_times' => max(0, 5 - $successfulStealCount),
- 'can_steal' => $canSteal,
- ];
- }
- /**
- * 获取用户的偷菜统计
- *
- * @param int $userId 用户ID
- * @return array 偷菜统计信息
- */
- public static function getStealStats(int $userId): array
- {
- $todayStealCount = PetStealLog::getTodayStealCount($userId);
- $todayBeingStolenCount = PetStealLog::getTodayBeingStolenCount($userId);
- // 获取总偷菜次数
- $totalStealCount = PetStealLog::where('stealer_user_id', $userId)->count();
- $totalSuccessfulStealCount = PetStealLog::where('stealer_user_id', $userId)
- ->where('success', true)
- ->count();
- // 获取总被偷次数
- $totalBeingStolenCount = PetStealLog::where('target_user_id', $userId)->count();
- $totalBeingDefendedCount = PetStealLog::where('target_user_id', $userId)
- ->where('defended', true)
- ->count();
- return [
- 'user_id' => $userId,
- 'today' => [
- 'steal_count' => $todayStealCount,
- 'being_stolen_count' => $todayBeingStolenCount,
- ],
- 'total' => [
- 'steal_count' => $totalStealCount,
- 'successful_steal_count' => $totalSuccessfulStealCount,
- 'steal_success_rate' => $totalStealCount > 0 ? round($totalSuccessfulStealCount / $totalStealCount * 100, 2) : 0,
- 'being_stolen_count' => $totalBeingStolenCount,
- 'defended_count' => $totalBeingDefendedCount,
- 'defend_success_rate' => $totalBeingStolenCount > 0 ? round($totalBeingDefendedCount / $totalBeingStolenCount * 100, 2) : 0,
- ],
- ];
- }
- }
|