DisasterRemovalLogic.php 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. <?php
  2. namespace App\Module\Farm\Logics;
  3. use App\Module\Farm\Enums\DISASTER_TYPE;
  4. use App\Module\GameItems\Services\ItemService;
  5. use Illuminate\Support\Facades\Log;
  6. use UCore\Db\Helper;
  7. use UCore\Exception\LogicException;
  8. /**
  9. * 灾害去除逻辑类
  10. *
  11. * 处理各种类型的灾害去除操作,包括概率计算、状态验证和物品消耗
  12. */
  13. class DisasterRemovalLogic
  14. {
  15. /**
  16. * 灾害类型与物品属性的映射关系
  17. */
  18. private const DISASTER_ITEM_ATTRIBUTES = [
  19. DISASTER_TYPE::DROUGHT->value => 'fram_drought_rate', // 干旱 -> 浇水概率
  20. DISASTER_TYPE::PEST->value => 'fram_pesticide_rate', // 虫害 -> 除虫概率
  21. DISASTER_TYPE::WEED->value => 'fram_weedicide_rate', // 杂草 -> 除草概率
  22. ];
  23. /**
  24. * 灾害类型与操作名称的映射关系
  25. */
  26. private const DISASTER_ACTION_NAMES = [
  27. DISASTER_TYPE::DROUGHT->value => '浇水',
  28. DISASTER_TYPE::PEST->value => '除虫',
  29. DISASTER_TYPE::WEED->value => '除草',
  30. ];
  31. /**
  32. * 尝试去除指定类型的灾害
  33. *
  34. * 注意:此方法假设所有验证已经通过,专注于业务逻辑处理
  35. *
  36. * @param int $userId 用户ID
  37. * @param int $landId 土地ID
  38. * @param int $itemId 物品ID
  39. * @param int $disasterType 灾害类型
  40. * @param string $sourceType 消耗来源类型
  41. * @return array 操作结果
  42. * @throws LogicException
  43. */
  44. public function removeDisaster(int $userId, int $landId, int $itemId, int $disasterType, string $sourceType): array
  45. {
  46. // 检查事务状态
  47. Helper::check_tr();
  48. // 获取物品成功率
  49. $successRate = $this->getItemSuccessRate($itemId, $disasterType);
  50. // 进行概率判断
  51. if (!$this->rollSuccess($successRate)) {
  52. // 失败时仍然消耗物品
  53. $this->consumeItem($userId, $itemId, $landId, $sourceType);
  54. $actionName = self::DISASTER_ACTION_NAMES[$disasterType];
  55. throw new LogicException("{$actionName}失败,请再次尝试");
  56. }
  57. // 执行灾害清理
  58. $result = $this->clearDisasterFromCrop($userId, $landId, $disasterType);
  59. if (!$result) {
  60. throw new LogicException("灾害清理失败,请检查土地状态或作物生长阶段");
  61. }
  62. // 消耗物品
  63. $this->consumeItem($userId, $itemId, $landId, $sourceType);
  64. // 记录灾害清除事件日志
  65. $this->logDisasterRemovalEvent($userId, $landId, $itemId, $disasterType, $successRate, $sourceType);
  66. $actionName = self::DISASTER_ACTION_NAMES[$disasterType];
  67. Log::info("用户{$actionName}成功", [
  68. 'user_id' => $userId,
  69. 'land_id' => $landId,
  70. 'item_id' => $itemId,
  71. 'disaster_type' => $disasterType,
  72. 'success_rate' => $successRate
  73. ]);
  74. return [
  75. 'success' => true,
  76. 'message' => "{$actionName}成功",
  77. 'disaster_type' => $disasterType,
  78. 'success_rate' => $successRate
  79. ];
  80. }
  81. /**
  82. * 获取物品的成功率
  83. *
  84. * @param int $itemId 物品ID
  85. * @param int $disasterType 灾害类型
  86. * @return int 成功率(百分比)
  87. */
  88. private function getItemSuccessRate(int $itemId, int $disasterType): int
  89. {
  90. $attributeName = self::DISASTER_ITEM_ATTRIBUTES[$disasterType];
  91. return ItemService::getItemNumericAttribute($itemId, $attributeName, 0);
  92. }
  93. /**
  94. * 进行概率判断
  95. *
  96. * @param int $successRate 成功率(百分比,100=100%)
  97. * @return bool 是否成功
  98. */
  99. private function rollSuccess(int $successRate): bool
  100. {
  101. if ($successRate <= 0) {
  102. return false;
  103. }
  104. if ($successRate >= 100) {
  105. return true;
  106. }
  107. $randomNumber = mt_rand(1, 100);
  108. return $randomNumber <= $successRate;
  109. }
  110. /**
  111. * 从作物中清理指定类型的灾害
  112. *
  113. * @param int $userId 用户ID
  114. * @param int $landId 土地ID
  115. * @param int $disasterType 灾害类型
  116. * @return bool 是否成功
  117. */
  118. private function clearDisasterFromCrop(int $userId, int $landId, int $disasterType): bool
  119. {
  120. try {
  121. $cropLogic = new CropLogic();
  122. return $cropLogic->clearDisaster($userId, $landId, $disasterType);
  123. } catch (\Exception $e) {
  124. Log::error('清理灾害失败', [
  125. 'user_id' => $userId,
  126. 'land_id' => $landId,
  127. 'disaster_type' => $disasterType,
  128. 'error' => $e->getMessage(),
  129. 'trace' => $e->getTraceAsString()
  130. ]);
  131. return false;
  132. }
  133. }
  134. /**
  135. * 消耗物品
  136. *
  137. * @param int $userId 用户ID
  138. * @param int $itemId 物品ID
  139. * @param int $landId 土地ID
  140. * @param string $sourceType 消耗来源类型
  141. * @throws LogicException
  142. */
  143. private function consumeItem(int $userId, int $itemId, int $landId, string $sourceType): void
  144. {
  145. ItemService::consumeItem($userId, $itemId, null, 1, [
  146. 'source_type' => $sourceType,
  147. 'source_id' => $landId,
  148. 'details' => ['land_id' => $landId]
  149. ]);
  150. }
  151. /**
  152. * 记录灾害清除事件日志
  153. *
  154. * @param int $userId 用户ID
  155. * @param int $landId 土地ID
  156. * @param int $itemId 物品ID
  157. * @param int $disasterType 灾害类型
  158. * @param float $successRate 成功率
  159. * @param string $sourceType 消耗来源类型
  160. * @return void
  161. */
  162. private function logDisasterRemovalEvent(int $userId, int $landId, int $itemId, int $disasterType, float $successRate, string $sourceType): void
  163. {
  164. try {
  165. // 获取作物信息
  166. $crop = \App\Module\Farm\Models\FarmCrop::where('land_id', $landId)->first();
  167. if (!$crop) {
  168. Log::warning('记录灾害清除事件时未找到作物', [
  169. 'user_id' => $userId,
  170. 'land_id' => $landId,
  171. 'disaster_type' => $disasterType
  172. ]);
  173. return;
  174. }
  175. // 根据灾害类型选择对应的日志方法
  176. $eventData = [
  177. 'growth_stage' => $crop->growth_stage,
  178. 'land_type' => $crop->land->land_type ?? 1,
  179. 'disaster_type' => $disasterType,
  180. 'item_id' => $itemId,
  181. 'success_rate' => $successRate,
  182. 'source_type' => $sourceType,
  183. 'cleared_at' => now()->format('Y-m-d H:i:s'),
  184. ];
  185. switch ($disasterType) {
  186. case \App\Module\Farm\Enums\DISASTER_TYPE::PEST->value:
  187. \App\Module\Farm\Models\FarmCropLog::logPesticideUsed(
  188. $userId, $landId, $crop->id, $crop->seed_id, $eventData
  189. );
  190. break;
  191. case \App\Module\Farm\Enums\DISASTER_TYPE::WEED->value:
  192. \App\Module\Farm\Models\FarmCropLog::logWeedicideUsed(
  193. $userId, $landId, $crop->id, $crop->seed_id, $eventData
  194. );
  195. break;
  196. case \App\Module\Farm\Enums\DISASTER_TYPE::DROUGHT->value:
  197. \App\Module\Farm\Models\FarmCropLog::logWatering(
  198. $userId, $landId, $crop->id, $crop->seed_id, $eventData
  199. );
  200. break;
  201. default:
  202. Log::warning('未知的灾害类型,无法记录日志', [
  203. 'disaster_type' => $disasterType,
  204. 'user_id' => $userId,
  205. 'land_id' => $landId
  206. ]);
  207. }
  208. } catch (\Exception $e) {
  209. Log::error('记录灾害清除事件日志失败', [
  210. 'user_id' => $userId,
  211. 'land_id' => $landId,
  212. 'disaster_type' => $disasterType,
  213. 'error' => $e->getMessage(),
  214. 'trace' => $e->getTraceAsString()
  215. ]);
  216. }
  217. }
  218. }