Pārlūkot izejas kodu

refactor(farm): 重构灾害处理逻辑

- 移除 CropInfoDto 和 LandInfoDto 中的灾害处理逻辑
- 新增 DisasterConverter 类统一处理灾害信息
- 更新 DataLand 消息格式,添加 disasters 字段
- 重构 DisasterRemovalBaseTest 中的登录和请求创建逻辑
- 更新 FarmLandController 和 FarmUserSummaryController 中的灾害显示逻辑
notfff 7 mēneši atpakaļ
vecāks
revīzija
3c232b1324

+ 2 - 0
app/Module/AppGame/Handler/Land/WeedicideHandler.php

@@ -14,6 +14,8 @@ use UCore\Exception\LogicException;
 
 /**
  * 处理除草操作请求
+ * Weedicide
+ *
  */
 class WeedicideHandler extends BaseHandler
 {

+ 4 - 19
app/Module/AppGame/Proto/CropInfoDto.php

@@ -68,29 +68,14 @@ class CropInfoDto
         // 假设我们有一个映射关系,这里简单地直接使用生长阶段值
         $dataLand->setSeedStatus($cropInfoDto->growthStage);
 
-        // 检查是否有灾害
-        if (!empty($cropInfoDto->disasters)) {
-            foreach ($cropInfoDto->disasters as $disaster) {
-                // 根据灾害类型设置相应的标志
-                if (isset($disaster['type'])) {
-                    switch ($disaster['type']) {
-                        case 1: // 假设1表示杂草
-                            $dataLand->setNeedWeed(true);
-                            break;
-                        case 2: // 假设2表示虫害
-                            $dataLand->setNeedPestControl(true);
-                            break;
-                        case 3: // 假设3表示缺水
-                            $dataLand->setNeedWatering(true);
-                            break;
-                    }
-                }
-            }
-        }
+        // 处理灾害信息
+        DisasterConverter::processDisasters($dataLand, $cropInfoDto->disasters ?? []);
 
         // 检查是否可以施肥
         $dataLand->setCanFertilization(!$cropInfoDto->fertilized);
 
         return $dataLand;
     }
+
+
 }

+ 93 - 0
app/Module/AppGame/Proto/DisasterConverter.php

@@ -0,0 +1,93 @@
+<?php
+
+namespace App\Module\AppGame\Proto;
+
+use Uraus\Kku\Common\LandDisaster;
+
+/**
+ * 灾害转换辅助类
+ * 
+ * 负责将Farm模块的灾害数组转换为Protobuf的LandDisaster对象数组
+ */
+class DisasterConverter
+{
+    /**
+     * 将灾害数组转换为LandDisaster对象数组
+     *
+     * @param array $disasters 灾害数组
+     * @return LandDisaster[] LandDisaster对象数组
+     */
+    public static function convertToLandDisasters(array $disasters): array
+    {
+        $landDisasters = [];
+        
+        foreach ($disasters as $disaster) {
+            if (!isset($disaster['type'])) {
+                continue;
+            }
+            
+            $landDisaster = new LandDisaster();
+            $landDisaster->setType($disaster['type']);
+            
+            // 设置灾害是否活跃,默认为活跃状态
+            $isActive = ($disaster['status'] ?? 'active') === 'active';
+            $landDisaster->setActive($isActive);
+            
+            $landDisasters[] = $landDisaster;
+        }
+        
+        return $landDisasters;
+    }
+
+    /**
+     * 设置DataLand的向后兼容灾害标志
+     * 
+     * 为了保持向后兼容性,根据灾害类型设置对应的布尔值标志
+     *
+     * @param \Uraus\Kku\Common\DataLand $dataLand DataLand对象
+     * @param array $disasters 灾害数组
+     * @return void
+     */
+    public static function setCompatibilityFlags(\Uraus\Kku\Common\DataLand $dataLand, array $disasters): void
+    {
+        foreach ($disasters as $disaster) {
+            if (isset($disaster['type']) && ($disaster['status'] ?? 'active') === 'active') {
+                switch ($disaster['type']) {
+                    case 3: // 杂草 (WEED)
+                        $dataLand->setNeedWeed(true);
+                        break;
+                    case 2: // 虫害 (PEST)
+                        $dataLand->setNeedPestControl(true);
+                        break;
+                    case 1: // 干旱 (DROUGHT)
+                        $dataLand->setNeedWatering(true);
+                        break;
+                }
+            }
+        }
+    }
+
+    /**
+     * 处理DataLand的灾害信息
+     * 
+     * 统一处理灾害信息的设置,包括新的disasters属性和向后兼容的布尔值标志
+     *
+     * @param \Uraus\Kku\Common\DataLand $dataLand DataLand对象
+     * @param array $disasters 灾害数组
+     * @return void
+     */
+    public static function processDisasters(\Uraus\Kku\Common\DataLand $dataLand, array $disasters): void
+    {
+        if (!empty($disasters)) {
+            // 设置新的disasters属性
+            $landDisasters = self::convertToLandDisasters($disasters);
+            $dataLand->setDisasters($landDisasters);
+            
+            // 设置向后兼容的布尔值标志
+            self::setCompatibilityFlags($dataLand, $disasters);
+        } else {
+            // 没有灾害时设置空数组
+            $dataLand->setDisasters([]);
+        }
+    }
+}

+ 4 - 19
app/Module/AppGame/Proto/LandInfoDto.php

@@ -51,25 +51,8 @@ class LandInfoDto
             // 假设我们有一个映射关系,这里简单地直接使用生长阶段值
             $dataLand->setSeedStatus((int)$landInfoDto->crop->growthStage);
 
-            // 检查是否有灾害
-            if (!empty($landInfoDto->crop->disasters)) {
-                foreach ($landInfoDto->crop->disasters as $disaster) {
-                    // 根据灾害类型设置相应的标志
-                    if (isset($disaster['type'])) {
-                        switch ($disaster['type']) {
-                            case 1: // 假设1表示杂草
-                                $dataLand->setNeedWeed(true);
-                                break;
-                            case 2: // 假设2表示虫害
-                                $dataLand->setNeedPestControl(true);
-                                break;
-                            case 3: // 假设3表示缺水
-                                $dataLand->setNeedWatering(true);
-                                break;
-                        }
-                    }
-                }
-            }
+            // 处理灾害信息
+            DisasterConverter::processDisasters($dataLand, $landInfoDto->crop->disasters ?? []);
 
             // 检查是否可以施肥
             $dataLand->setCanFertilization(!$landInfoDto->crop->fertilized);
@@ -78,4 +61,6 @@ class LandInfoDto
         return $dataLand;
     }
 
+
+
 }

+ 63 - 4
app/Module/AppGame/Tests/Land/DisasterRemovalBaseTest.php

@@ -50,6 +50,16 @@ abstract class DisasterRemovalBaseTest extends ProtoRequestTest
         if (TestEnvironment::isDebugMode()) {
             dump('成功响应: ' . $response->serializeToJsonString());
         }
+
+        // 总是输出响应详情用于调试
+        dump('响应详情:', [
+            'code' => $response->getCode(),
+            'code_name' => RESPONSE_CODE::name($response->getCode()),
+            'msg' => $response->getMsg(),
+            'callpath' => $response->getCallpath(),
+            'run_ms' => $response->getRunMs(),
+            'full_response' => $response->serializeToJsonString()
+        ]);
     }
 
     /**
@@ -95,12 +105,61 @@ abstract class DisasterRemovalBaseTest extends ProtoRequestTest
     }
 
     /**
-     * 创建基础请求对象
+     * 用户登录token缓存
+     */
+    private static ?string $userToken = null;
+
+    /**
+     * 获取用户登录token
+     */
+    protected function getUserToken(): string
+    {
+        if (self::$userToken === null) {
+            self::$userToken = $this->performLogin();
+        }
+        return self::$userToken;
+    }
+
+    /**
+     * 执行用户登录,获取token
      */
-    protected function createBaseRequest(): Request
+    private function performLogin(): string
     {
-        $request = new Request();
-        // 这里可以添加通用的请求头设置,如用户认证等
+        // 暂时返回一个模拟的token,实际应用中需要真正的登录流程
+        $testUser = TestEnvironment::getTestUser();
+        $token = 'test_token_' . $testUser['user_id'] . '_' . time();
+
+        if (TestEnvironment::isDebugMode()) {
+            dump('模拟用户登录,token: ' . $token);
+        }
+
+        return $token;
+    }
+
+    /**
+     * 创建基础请求对象,包含认证信息
+     */
+    protected function createBaseRequest(?Request $request = null): Request
+    {
+        if ($request === null) {
+            $request = new Request();
+        }
+
+        // 获取用户token
+        $token = $this->getUserToken();
+
+        // 设置token到请求中
+        $tokenRequest = new \Uraus\Kku\Request\RequestPublicToken();
+        $tokenRequest->setTimes(time());
+        $request->setPublicToken($tokenRequest);
+
+        // 这里需要设置session或其他认证方式
+        // 由于protobuf的限制,我们可能需要通过其他方式传递token
+
+        if (TestEnvironment::isDebugMode()) {
+            dump('创建基础请求,token: ' . $token);
+        }
+
         return $request;
     }
 

+ 11 - 14
app/Module/Farm/AdminControllers/FarmLandController.php

@@ -69,25 +69,22 @@ class FarmLandController extends AdminController
                 if (!$disasters) return '无';
 
                 $result = [];
-                foreach (json_decode($disasters, true) ?: [] as $disaster) {
+                $disasterData = is_string($disasters) ? json_decode($disasters, true) : $disasters;
+
+                foreach ($disasterData ?: [] as $disaster) {
                     if (isset($disaster['type'])) {
-                        switch ($disaster['type']) {
-                            case 1:
-                                $result[] = '杂草';
-                                break;
-                            case 2:
-                                $result[] = '虫害';
-                                break;
-                            case 3:
-                                $result[] = '缺水';
-                                break;
-                            default:
-                                $result[] = '未知灾害';
+                        $typeName = \App\Module\Farm\Enums\DISASTER_TYPE::getName($disaster['type']);
+                        $status = $disaster['status'] ?? 'active';
+
+                        if ($status === 'active') {
+                            $result[] = '<span class="badge badge-danger">' . $typeName . '</span>';
+                        } else {
+                            $result[] = '<span class="badge badge-secondary">' . $typeName . '(已处理)</span>';
                         }
                     }
                 }
 
-                return empty($result) ? '无' : implode('', $result);
+                return empty($result) ? '无' : implode(' ', $result);
             });
 
             $grid->column('crop.fertilized', '是否施肥')->bool();

+ 10 - 3
app/Module/Game/AdminControllers/FarmUserSummaryController.php

@@ -516,7 +516,7 @@ class FarmUserSummaryController extends AdminController
 
         foreach ($disasters as $disaster) {
             $type   = $disaster['type'] ?? 0;
-            $status = $disaster['status'] ?? 'inactive';
+            $status = $disaster['status'] ?? 'active'; // 默认为活跃状态
 
             // 获取灾害类型名称
             $typeName = DISASTER_TYPE::getName($type);
@@ -533,8 +533,10 @@ class FarmUserSummaryController extends AdminController
                 $endTime = date('Y-m-d H:i:s', $disaster['end_time']);
             }
 
-            // 减产比例
-            $penalty = isset($disaster['penalty']) ? ($disaster['penalty'] * 100) . '%' : '5%';
+            // 减产比例 - 从DisasterService获取默认值
+            $defaultPenalties = \App\Module\Farm\Services\DisasterService::getAllDisasters();
+            $defaultPenalty = $defaultPenalties[$type] ?? 0.05;
+            $penalty = isset($disaster['penalty']) ? ($disaster['penalty'] * 100) . '%' : ($defaultPenalty * 100) . '%';
 
             // 组合灾害信息
             $disasterInfo = "<div><strong>{$typeName}</strong>: {$statusText}</div>";
@@ -546,6 +548,11 @@ class FarmUserSummaryController extends AdminController
 
             $disasterInfo .= "<div>减产: {$penalty}</div>";
 
+            // 如果有额外的灾害信息,也显示出来
+            if (isset($disaster['id'])) {
+                $disasterInfo .= "<div>ID: {$disaster['id']}</div>";
+            }
+
             $result[] = $disasterInfo;
         }
 

+ 1 - 1
config/proto_route.php

@@ -89,7 +89,7 @@ return array (
       7 => 'query_data',
     ),
   ),
-  'generated_at' => '+08:00 2025-05-22 17:40:12',
+  'generated_at' => '+08:00 2025-05-24 14:32:44',
   'conventions' => 
   array (
     'handler_namespace' => 'App\\Module\\AppGame\\Handler',

+ 119 - 0
docs/DataLand灾害属性处理完成说明.md

@@ -0,0 +1,119 @@
+# DataLand 灾害属性处理完成说明
+
+## 概述
+
+本次更新完成了对 `DataLand` 中新增的 `disasters` 灾害属性的处理,实现了从数据库中的灾害信息到 Protobuf 对象的完整转换流程。
+
+## 主要更新内容
+
+### 1. 创建灾害转换辅助类
+
+**文件**: `app/Module/AppGame/Proto/DisasterConverter.php`
+
+- 提供统一的灾害转换逻辑
+- 将 Farm 模块的灾害数组转换为 Protobuf 的 `LandDisaster` 对象数组
+- 处理向后兼容性,同时设置新的 `disasters` 属性和旧的布尔值标志
+
+**主要方法**:
+- `convertToLandDisasters()`: 转换灾害数组为 LandDisaster 对象数组
+- `setCompatibilityFlags()`: 设置向后兼容的布尔值标志
+- `processDisasters()`: 统一处理灾害信息的设置
+
+### 2. 更新转换逻辑
+
+**文件**: `app/Module/AppGame/Proto/LandInfoDto.php`
+- 更新 `toDataLand()` 方法,使用新的 `DisasterConverter` 处理灾害信息
+- 移除重复的转换代码
+
+**文件**: `app/Module/AppGame/Proto/CropInfoDto.php`
+- 更新 `toDataLand()` 方法,使用新的 `DisasterConverter` 处理灾害信息
+- 移除重复的转换代码
+
+### 3. 改进后台显示
+
+**文件**: `app/Module/Game/AdminControllers/FarmUserSummaryController.php`
+- 更新 `formatDisasterInfo()` 方法,改进灾害信息的显示
+- 从 `DisasterService` 获取默认减产比例
+- 显示更详细的灾害信息,包括ID、状态等
+
+**文件**: `app/Module/Farm/AdminControllers/FarmLandController.php`
+- 更新灾害显示逻辑,使用正确的灾害类型映射
+- 使用 `DISASTER_TYPE::getName()` 获取灾害名称
+- 区分活跃和已处理的灾害状态
+
+### 4. 创建单元测试
+
+**文件**: `tests/Unit/DisasterConverterTest.php`
+- 测试灾害转换器的各种功能
+- 验证转换逻辑的正确性
+- 测试边界情况和异常处理
+
+## 技术细节
+
+### 灾害类型映射
+
+根据 `DISASTER_TYPE` 枚举:
+- `1`: 干旱 (DROUGHT) -> 对应 `need_watering`
+- `2`: 虫害 (PEST) -> 对应 `need_pest_control`  
+- `3`: 杂草 (WEED) -> 对应 `need_weed`
+
+### 向后兼容性
+
+为了保持向后兼容性,系统同时设置:
+1. **新属性**: `disasters` - LandDisaster 对象数组
+2. **旧属性**: `need_weed`, `need_pest_control`, `need_watering` - 布尔值标志
+
+### 灾害状态处理
+
+- `active`: 活跃的灾害,会影响作物产量
+- `inactive`/其他: 已处理的灾害,不再影响作物
+
+## 数据流程
+
+```
+FarmCrop.disasters (JSON数组)
+    ↓
+DisasterConverter::processDisasters()
+    ↓
+DataLand.disasters (LandDisaster对象数组) + 向后兼容标志
+    ↓
+客户端接收完整的灾害信息
+```
+
+## 使用示例
+
+### 在转换代码中使用
+
+```php
+// 处理灾害信息
+DisasterConverter::processDisasters($dataLand, $cropInfoDto->disasters ?? []);
+```
+
+### 在后台显示中使用
+
+```php
+// 格式化灾害信息显示
+$disasterInfo = $this->formatDisasterInfo($crop->disasters);
+```
+
+## 测试验证
+
+创建了完整的单元测试来验证:
+- 灾害数组到 LandDisaster 对象的转换
+- 向后兼容标志的正确设置
+- 边界情况和异常处理
+- 空数据的处理
+
+## 注意事项
+
+1. **数据格式**: 确保数据库中的灾害信息包含 `type` 和 `status` 字段
+2. **状态默认值**: 如果没有指定 `status`,默认为 `active`
+3. **类型验证**: 只处理包含有效 `type` 字段的灾害记录
+4. **性能考虑**: 使用统一的转换器避免代码重复,提高维护性
+
+## 后续建议
+
+1. 监控新的灾害属性在客户端的使用情况
+2. 在确认客户端完全支持新属性后,可以考虑逐步移除旧的布尔值标志
+3. 根据实际使用情况优化灾害信息的显示格式
+4. 考虑添加更多的灾害属性,如持续时间、严重程度等

+ 14 - 5
protophp/GPBMetadata/Proto/Game.php

@@ -16,7 +16,7 @@ class Game
         }
         $pool->internalAddGeneratedFile(
             '
-„š
+ú›
 proto/game.proto	uraus.kku"÷2
 Request;
 public_tokend (2%.uraus.kku.Request.RequestPublicToken;
@@ -471,7 +471,7 @@ to_user_id (
 APPLYING	
 AGREE
 
-REFUSE"û)
+REFUSE"ñ+
 Common)
 KeyValue
 kname (	
@@ -546,7 +546,7 @@ pet_simple (2.uraus.kku.Common.DataPetSimple-
 item_id (
 instance_id (
 quantity (
-expire_time (
+expire_time (É
 DataLand
 
 id (
@@ -564,7 +564,11 @@ pet_simple (2.uraus.kku.Common.DataPetSimple-
 plant_id! (2
 seed_status" (2.uraus.kku.Common.SEED_STATUS
 stage_start_times# (
-stage_next_times$ (8
+stage_next_times$ (1
+	disasters% (2.uraus.kku.Common.LandDisasterM
+LandDisaster-
+type (2.uraus.kku.Common.DISASTER_TYPE
+active (8
 DataGod
 
 id (
@@ -729,7 +733,12 @@ SEEN_STAGE
 SPROUTING_STAGE
 
GROWING_STAGE
 MATURE_STAGE(
-WITHERED_STAGE2"Æ
+WITHERED_STAGE2"r
+
DISASTER_TYPE
+DISASTER_TYPE_NONE
+DISASTER_TYPE_DROUGHT
+DISASTER_TYPE_PEST
+DISASTER_TYPE_WEED"Æ
 
 TaskStatus
 TASK_STATUS_UNKNOWN

+ 72 - 0
protophp/Uraus/Kku/Common/DISASTER_TYPE.php

@@ -0,0 +1,72 @@
+<?php
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: proto/game.proto
+
+namespace Uraus\Kku\Common;
+
+use UnexpectedValueException;
+
+/**
+ * 灾害类型
+ *
+ * Protobuf type <code>uraus.kku.Common.DISASTER_TYPE</code>
+ */
+class DISASTER_TYPE
+{
+    /**
+     * Generated from protobuf enum <code>DISASTER_TYPE_NONE = 0;</code>
+     */
+    const DISASTER_TYPE_NONE = 0;
+    /**
+     **
+     * 干旱
+     *
+     * Generated from protobuf enum <code>DISASTER_TYPE_DROUGHT = 1;</code>
+     */
+    const DISASTER_TYPE_DROUGHT = 1;
+    /**
+     **
+     * 虫害
+     *
+     * Generated from protobuf enum <code>DISASTER_TYPE_PEST = 2;</code>
+     */
+    const DISASTER_TYPE_PEST = 2;
+    /**
+     **
+     * 杂草
+     *
+     * Generated from protobuf enum <code>DISASTER_TYPE_WEED = 3;</code>
+     */
+    const DISASTER_TYPE_WEED = 3;
+
+    private static $valueToName = [
+        self::DISASTER_TYPE_NONE => 'DISASTER_TYPE_NONE',
+        self::DISASTER_TYPE_DROUGHT => 'DISASTER_TYPE_DROUGHT',
+        self::DISASTER_TYPE_PEST => 'DISASTER_TYPE_PEST',
+        self::DISASTER_TYPE_WEED => 'DISASTER_TYPE_WEED',
+    ];
+
+    public static function name($value)
+    {
+        if (!isset(self::$valueToName[$value])) {
+            throw new UnexpectedValueException(sprintf(
+                    'Enum %s has no name defined for value %s', __CLASS__, $value));
+        }
+        return self::$valueToName[$value];
+    }
+
+
+    public static function value($name)
+    {
+        $const = __CLASS__ . '::' . strtoupper($name);
+        if (!defined($const)) {
+            throw new UnexpectedValueException(sprintf(
+                    'Enum %s has no value defined for name %s', __CLASS__, $name));
+        }
+        return constant($const);
+    }
+}
+
+// Adding a class alias for backwards compatibility with the previous class name.
+class_alias(DISASTER_TYPE::class, \Uraus\Kku\Common_DISASTER_TYPE::class);
+

+ 34 - 0
protophp/Uraus/Kku/Common/DataLand.php

@@ -112,6 +112,12 @@ class DataLand extends \Google\Protobuf\Internal\Message
      * Generated from protobuf field <code>int64 stage_next_times = 36;</code>
      */
     protected $stage_next_times = 0;
+    /**
+     * 灾害
+     *
+     * Generated from protobuf field <code>repeated .uraus.kku.Common.LandDisaster disasters = 37;</code>
+     */
+    private $disasters;
 
     /**
      * Constructor.
@@ -152,6 +158,8 @@ class DataLand extends \Google\Protobuf\Internal\Message
      *           当前阶段开始时间
      *     @type int|string $stage_next_times
      *           当前阶段结束时间
+     *     @type \Uraus\Kku\Common\LandDisaster[]|\Google\Protobuf\Internal\RepeatedField $disasters
+     *           灾害
      * }
      */
     public function __construct($data = NULL) {
@@ -577,6 +585,32 @@ class DataLand extends \Google\Protobuf\Internal\Message
         return $this;
     }
 
+    /**
+     * 灾害
+     *
+     * Generated from protobuf field <code>repeated .uraus.kku.Common.LandDisaster disasters = 37;</code>
+     * @return \Google\Protobuf\Internal\RepeatedField
+     */
+    public function getDisasters()
+    {
+        return $this->disasters;
+    }
+
+    /**
+     * 灾害
+     *
+     * Generated from protobuf field <code>repeated .uraus.kku.Common.LandDisaster disasters = 37;</code>
+     * @param \Uraus\Kku\Common\LandDisaster[]|\Google\Protobuf\Internal\RepeatedField $var
+     * @return $this
+     */
+    public function setDisasters($var)
+    {
+        $arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \Uraus\Kku\Common\LandDisaster::class);
+        $this->disasters = $arr;
+
+        return $this;
+    }
+
 }
 
 // Adding a class alias for backwards compatibility with the previous class name.

+ 104 - 0
protophp/Uraus/Kku/Common/LandDisaster.php

@@ -0,0 +1,104 @@
+<?php
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: proto/game.proto
+
+namespace Uraus\Kku\Common;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ *灾害
+ *
+ * Generated from protobuf message <code>uraus.kku.Common.LandDisaster</code>
+ */
+class LandDisaster extends \Google\Protobuf\Internal\Message
+{
+    /**
+     * 灾害类型
+     *
+     * Generated from protobuf field <code>.uraus.kku.Common.DISASTER_TYPE type = 1;</code>
+     */
+    protected $type = 0;
+    /**
+     * 活跃(不活跃就是被处理了)
+     *
+     * Generated from protobuf field <code>bool active = 2;</code>
+     */
+    protected $active = false;
+
+    /**
+     * Constructor.
+     *
+     * @param array $data {
+     *     Optional. Data for populating the Message object.
+     *
+     *     @type int $type
+     *           灾害类型
+     *     @type bool $active
+     *           活跃(不活跃就是被处理了)
+     * }
+     */
+    public function __construct($data = NULL) {
+        \GPBMetadata\Proto\Game::initOnce();
+        parent::__construct($data);
+    }
+
+    /**
+     * 灾害类型
+     *
+     * Generated from protobuf field <code>.uraus.kku.Common.DISASTER_TYPE type = 1;</code>
+     * @return int
+     */
+    public function getType()
+    {
+        return $this->type;
+    }
+
+    /**
+     * 灾害类型
+     *
+     * Generated from protobuf field <code>.uraus.kku.Common.DISASTER_TYPE type = 1;</code>
+     * @param int $var
+     * @return $this
+     */
+    public function setType($var)
+    {
+        GPBUtil::checkEnum($var, \Uraus\Kku\Common\DISASTER_TYPE::class);
+        $this->type = $var;
+
+        return $this;
+    }
+
+    /**
+     * 活跃(不活跃就是被处理了)
+     *
+     * Generated from protobuf field <code>bool active = 2;</code>
+     * @return bool
+     */
+    public function getActive()
+    {
+        return $this->active;
+    }
+
+    /**
+     * 活跃(不活跃就是被处理了)
+     *
+     * Generated from protobuf field <code>bool active = 2;</code>
+     * @param bool $var
+     * @return $this
+     */
+    public function setActive($var)
+    {
+        GPBUtil::checkBool($var);
+        $this->active = $var;
+
+        return $this;
+    }
+
+}
+
+// Adding a class alias for backwards compatibility with the previous class name.
+class_alias(LandDisaster::class, \Uraus\Kku\Common_LandDisaster::class);
+

+ 0 - 1
protophp/Uraus/Kku/Common/SEED_STATUS.php

@@ -37,7 +37,6 @@ class SEED_STATUS
      * Generated from protobuf enum <code>GROWING_STAGE = 30;</code>
      */
     const GROWING_STAGE = 30;
-
     /**
      * 成熟
      *

+ 16 - 0
protophp/Uraus/Kku/Common_DISASTER_TYPE.php

@@ -0,0 +1,16 @@
+<?php
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: proto/game.proto
+
+namespace Uraus\Kku;
+
+if (false) {
+    /**
+     * This class is deprecated. Use Uraus\Kku\Common\DISASTER_TYPE instead.
+     * @deprecated
+     */
+    class Common_DISASTER_TYPE {}
+}
+class_exists(Common\DISASTER_TYPE::class);
+@trigger_error('Uraus\Kku\Common_DISASTER_TYPE is deprecated and will be removed in the next major release. Use Uraus\Kku\Common\DISASTER_TYPE instead', E_USER_DEPRECATED);
+

+ 16 - 0
protophp/Uraus/Kku/Common_LandDisaster.php

@@ -0,0 +1,16 @@
+<?php
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: proto/game.proto
+
+namespace Uraus\Kku;
+
+if (false) {
+    /**
+     * This class is deprecated. Use Uraus\Kku\Common\LandDisaster instead.
+     * @deprecated
+     */
+    class Common_LandDisaster {}
+}
+class_exists(Common\LandDisaster::class);
+@trigger_error('Uraus\Kku\Common_LandDisaster is deprecated and will be removed in the next major release. Use Uraus\Kku\Common\LandDisaster instead', E_USER_DEPRECATED);
+

+ 145 - 0
tests/Unit/DisasterConverterTest.php

@@ -0,0 +1,145 @@
+<?php
+
+namespace Tests\Unit;
+
+use App\Module\AppGame\Proto\DisasterConverter;
+use PHPUnit\Framework\TestCase;
+use Uraus\Kku\Common\DataLand;
+use Uraus\Kku\Common\LandDisaster;
+
+/**
+ * 灾害转换器测试
+ */
+class DisasterConverterTest extends TestCase
+{
+    /**
+     * 测试将灾害数组转换为LandDisaster对象数组
+     */
+    public function testConvertToLandDisasters()
+    {
+        $disasters = [
+            [
+                'type' => 1,
+                'status' => 'active'
+            ],
+            [
+                'type' => 2,
+                'status' => 'inactive'
+            ],
+            [
+                'type' => 3,
+                'status' => 'active'
+            ]
+        ];
+
+        $landDisasters = DisasterConverter::convertToLandDisasters($disasters);
+
+        $this->assertCount(3, $landDisasters);
+        
+        // 检查第一个灾害
+        $this->assertInstanceOf(LandDisaster::class, $landDisasters[0]);
+        $this->assertEquals(1, $landDisasters[0]->getType());
+        $this->assertTrue($landDisasters[0]->getActive());
+        
+        // 检查第二个灾害
+        $this->assertInstanceOf(LandDisaster::class, $landDisasters[1]);
+        $this->assertEquals(2, $landDisasters[1]->getType());
+        $this->assertFalse($landDisasters[1]->getActive());
+        
+        // 检查第三个灾害
+        $this->assertInstanceOf(LandDisaster::class, $landDisasters[2]);
+        $this->assertEquals(3, $landDisasters[2]->getType());
+        $this->assertTrue($landDisasters[2]->getActive());
+    }
+
+    /**
+     * 测试处理空灾害数组
+     */
+    public function testConvertEmptyDisasters()
+    {
+        $landDisasters = DisasterConverter::convertToLandDisasters([]);
+        $this->assertEmpty($landDisasters);
+    }
+
+    /**
+     * 测试处理无效灾害数据
+     */
+    public function testConvertInvalidDisasters()
+    {
+        $disasters = [
+            ['invalid' => 'data'],
+            ['type' => 1, 'status' => 'active'],
+            ['status' => 'active'] // 缺少type
+        ];
+
+        $landDisasters = DisasterConverter::convertToLandDisasters($disasters);
+        
+        // 只有一个有效的灾害
+        $this->assertCount(1, $landDisasters);
+        $this->assertEquals(1, $landDisasters[0]->getType());
+    }
+
+    /**
+     * 测试设置向后兼容标志
+     */
+    public function testSetCompatibilityFlags()
+    {
+        $dataLand = new DataLand();
+        
+        $disasters = [
+            ['type' => 1, 'status' => 'active'],  // 干旱
+            ['type' => 2, 'status' => 'active'],  // 虫害
+            ['type' => 3, 'status' => 'active'],  // 杂草
+            ['type' => 1, 'status' => 'inactive'] // 已处理的干旱
+        ];
+
+        DisasterConverter::setCompatibilityFlags($dataLand, $disasters);
+
+        $this->assertTrue($dataLand->getNeedWatering());    // 干旱
+        $this->assertTrue($dataLand->getNeedPestControl()); // 虫害
+        $this->assertTrue($dataLand->getNeedWeed());        // 杂草
+    }
+
+    /**
+     * 测试完整的灾害处理流程
+     */
+    public function testProcessDisasters()
+    {
+        $dataLand = new DataLand();
+        
+        $disasters = [
+            ['type' => 1, 'status' => 'active'],
+            ['type' => 2, 'status' => 'inactive']
+        ];
+
+        DisasterConverter::processDisasters($dataLand, $disasters);
+
+        // 检查disasters属性是否正确设置
+        $landDisasters = $dataLand->getDisasters();
+        $this->assertCount(2, $landDisasters);
+        
+        // 检查向后兼容标志
+        $this->assertTrue($dataLand->getNeedWatering());
+        $this->assertFalse($dataLand->getNeedPestControl()); // inactive状态不设置标志
+        $this->assertFalse($dataLand->getNeedWeed());
+    }
+
+    /**
+     * 测试处理空灾害数组
+     */
+    public function testProcessEmptyDisasters()
+    {
+        $dataLand = new DataLand();
+        
+        DisasterConverter::processDisasters($dataLand, []);
+
+        // 检查disasters属性是否设置为空数组
+        $landDisasters = $dataLand->getDisasters();
+        $this->assertEmpty($landDisasters);
+        
+        // 检查向后兼容标志都为false
+        $this->assertFalse($dataLand->getNeedWatering());
+        $this->assertFalse($dataLand->getNeedPestControl());
+        $this->assertFalse($dataLand->getNeedWeed());
+    }
+}

+ 23 - 0
vendor/composer/autoload_classmap.php

@@ -159,7 +159,17 @@ return array(
     'App\\Module\\AppGame\\Service\\MinerService' => $baseDir . '/app/Module/AppGame/Service/MinerService.php',
     'App\\Module\\AppGame\\Service\\TransactionService' => $baseDir . '/app/Module/AppGame/Service/TransactionService.php',
     'App\\Module\\AppGame\\SessionApp' => $baseDir . '/app/Module/AppGame/SessionApp.php',
+    'App\\Module\\AppGame\\Tests\\Land\\DisasterRemovalBaseTest' => $baseDir . '/app/Module/AppGame/Tests/Land/DisasterRemovalBaseTest.php',
+    'App\\Module\\AppGame\\Tests\\Land\\DisasterRemovalTestSuite' => $baseDir . '/app/Module/AppGame/Tests/Land/DisasterRemovalTestSuite.php',
+    'App\\Module\\AppGame\\Tests\\Land\\FertilizerHandlerTest' => $baseDir . '/app/Module/AppGame/Tests/Land/FertilizerHandlerTest.php',
+    'App\\Module\\AppGame\\Tests\\Land\\HarvestHandlerTest' => $baseDir . '/app/Module/AppGame/Tests/Land/HarvestHandlerTest.php',
+    'App\\Module\\AppGame\\Tests\\Land\\PesticideHandlerTest' => $baseDir . '/app/Module/AppGame/Tests/Land/PesticideHandlerTest.php',
+    'App\\Module\\AppGame\\Tests\\Land\\SowHandlerTest' => $baseDir . '/app/Module/AppGame/Tests/Land/SowHandlerTest.php',
+    'App\\Module\\AppGame\\Tests\\Land\\WateringHandlerTest' => $baseDir . '/app/Module/AppGame/Tests/Land/WateringHandlerTest.php',
+    'App\\Module\\AppGame\\Tests\\Land\\WeedicideHandlerTest' => $baseDir . '/app/Module/AppGame/Tests/Land/WeedicideHandlerTest.php',
     'App\\Module\\AppGame\\Tests\\Public\\PublicTokenTest' => $baseDir . '/app/Module/AppGame/Tests/Public/PublicTokenTest.php',
+    'App\\Module\\AppGame\\Tests\\TestConfig' => $baseDir . '/app/Module/AppGame/Tests/TestConfig.php',
+    'App\\Module\\AppGame\\Tests\\TestEnvironment' => $baseDir . '/app/Module/AppGame/Tests/TestEnvironment.php',
     'App\\Module\\AppGame\\Tools\\Protobuf' => $baseDir . '/app/Module/AppGame/Tools/Protobuf.php',
     'App\\Module\\AppGame\\UserService' => $baseDir . '/app/Module/AppGame/UserService.php',
     'App\\Module\\AppGame\\Validations\\LandSowValidation' => $baseDir . '/app/Module/AppGame/Validations/LandSowValidation.php',
@@ -317,6 +327,7 @@ return array(
     'App\\Module\\Farm\\Logics\\BuffLogic' => $baseDir . '/app/Module/Farm/Logics/BuffLogic.php',
     'App\\Module\\Farm\\Logics\\CropLogic' => $baseDir . '/app/Module/Farm/Logics/CropLogic.php',
     'App\\Module\\Farm\\Logics\\DisasterLogic' => $baseDir . '/app/Module/Farm/Logics/DisasterLogic.php',
+    'App\\Module\\Farm\\Logics\\DisasterRemovalLogic' => $baseDir . '/app/Module/Farm/Logics/DisasterRemovalLogic.php',
     'App\\Module\\Farm\\Logics\\FarmLogic' => $baseDir . '/app/Module/Farm/Logics/FarmLogic.php',
     'App\\Module\\Farm\\Logics\\HarvestLogLogic' => $baseDir . '/app/Module/Farm/Logics/HarvestLogLogic.php',
     'App\\Module\\Farm\\Logics\\HouseLogic' => $baseDir . '/app/Module/Farm/Logics/HouseLogic.php',
@@ -355,11 +366,15 @@ return array(
     'App\\Module\\Farm\\Repositories\\FarmUserRepository' => $baseDir . '/app/Module/Farm/Repositories/FarmUserRepository.php',
     'App\\Module\\Farm\\Services\\BuffService' => $baseDir . '/app/Module/Farm/Services/BuffService.php',
     'App\\Module\\Farm\\Services\\CropService' => $baseDir . '/app/Module/Farm/Services/CropService.php',
+    'App\\Module\\Farm\\Services\\DisasterService' => $baseDir . '/app/Module/Farm/Services/DisasterService.php',
     'App\\Module\\Farm\\Services\\FarmService' => $baseDir . '/app/Module/Farm/Services/FarmService.php',
     'App\\Module\\Farm\\Services\\HouseService' => $baseDir . '/app/Module/Farm/Services/HouseService.php',
     'App\\Module\\Farm\\Services\\LandService' => $baseDir . '/app/Module/Farm/Services/LandService.php',
     'App\\Module\\Farm\\Services\\SeedService' => $baseDir . '/app/Module/Farm/Services/SeedService.php',
     'App\\Module\\Farm\\Services\\TeamService' => $baseDir . '/app/Module/Farm/Services/TeamService.php',
+    'App\\Module\\Farm\\Validations\\DisasterRemovalValidation' => $baseDir . '/app/Module/Farm/Validations/DisasterRemovalValidation.php',
+    'App\\Module\\Farm\\Validators\\DisasterRemovalItemValidator' => $baseDir . '/app/Module/Farm/Validators/DisasterRemovalItemValidator.php',
+    'App\\Module\\Farm\\Validators\\LandOwnershipValidator' => $baseDir . '/app/Module/Farm/Validators/LandOwnershipValidator.php',
     'App\\Module\\File\\AdminControllers\\FileController' => $baseDir . '/app/Module/File/AdminControllers/FileController.php',
     'App\\Module\\File\\AdminControllers\\Helper\\FileHelper' => $baseDir . '/app/Module/File/AdminControllers/Helper/FileHelper.php',
     'App\\Module\\File\\AdminControllers\\Helper\\FilterHelper' => $baseDir . '/app/Module/File/AdminControllers/Helper/FilterHelper.php',
@@ -717,6 +732,7 @@ return array(
     'App\\Module\\Game\\Events\\TestEvent' => $baseDir . '/app/Module/Game/Events/TestEvent.php',
     'App\\Module\\Game\\Exceptions\\TestException' => $baseDir . '/app/Module/Game/Exceptions/TestException.php',
     'App\\Module\\Game\\Jobs\\TestJob' => $baseDir . '/app/Module/Game/Jobs/TestJob.php',
+    'App\\Module\\Game\\Listeners\\CropGrowthStageChangedListener' => $baseDir . '/app/Module/Game/Listeners/CropGrowthStageChangedListener.php',
     'App\\Module\\Game\\Listeners\\CropPlantedListener' => $baseDir . '/app/Module/Game/Listeners/CropPlantedListener.php',
     'App\\Module\\Game\\Listeners\\FundChangedListener' => $baseDir . '/app/Module/Game/Listeners/FundChangedListener.php',
     'App\\Module\\Game\\Listeners\\HouseDowngradedListener' => $baseDir . '/app/Module/Game/Listeners/HouseDowngradedListener.php',
@@ -9434,6 +9450,8 @@ return array(
     'Tests\\TestCase' => $baseDir . '/tests/TestCase.php',
     'Tests\\Unit\\CommonTest' => $baseDir . '/tests/Unit/CommonTest.php',
     'Tests\\Unit\\ExampleTest' => $baseDir . '/tests/Unit/ExampleTest.php',
+    'Tests\\Unit\\Farm\\DisasterRemovalLogicTest' => $baseDir . '/tests/Unit/Farm/DisasterRemovalLogicTest.php',
+    'Tests\\Unit\\Farm\\DisasterRemovalValidationTest' => $baseDir . '/tests/Unit/Farm/DisasterRemovalValidationTest.php',
     'Tests\\Unit\\ProtoRequest' => $baseDir . '/tests/Unit/ProtoRequest.php',
     'Tests\\Unit\\ProtoRequestTest' => $baseDir . '/tests/Unit/ProtoRequestTest.php',
     'Tests\\Unit\\Protobuf2ControllerTest' => $baseDir . '/tests/Unit/Protobuf2ControllerTest.php',
@@ -9587,6 +9605,7 @@ return array(
     'UCore\\DcatAdmin\\Metrics\\Examples\\DataLabel2' => $baseDir . '/UCore/DcatAdmin/Metrics/Examples/DataLabel2.php',
     'UCore\\DcatAdmin\\Metrics\\Examples\\DataNumber' => $baseDir . '/UCore/DcatAdmin/Metrics/Examples/DataNumber.php',
     'UCore\\DcatAdmin\\Metrics\\Examples\\Link' => $baseDir . '/UCore/DcatAdmin/Metrics/Examples/Link.php',
+    'UCore\\DcatAdmin\\Metrics\\Examples\\LinkA' => $baseDir . '/UCore/DcatAdmin/Metrics/Examples/LinkA.php',
     'UCore\\DcatAdmin\\Metrics\\Examples\\ListDataColor' => $baseDir . '/UCore/DcatAdmin/Metrics/Examples/ListDataColor.php',
     'UCore\\DcatAdmin\\Metrics\\Examples\\NewDevices' => $baseDir . '/UCore/DcatAdmin/Metrics/Examples/NewDevices.php',
     'UCore\\DcatAdmin\\Metrics\\Examples\\NewUsers' => $baseDir . '/UCore/DcatAdmin/Metrics/Examples/NewUsers.php',
@@ -9721,6 +9740,7 @@ return array(
     'Uraus\\Kku\\Common\\CHAT_CHANNEL' => $baseDir . '/protophp/Uraus/Kku/Common/CHAT_CHANNEL.php',
     'Uraus\\Kku\\Common\\CONDITION_TYPE' => $baseDir . '/protophp/Uraus/Kku/Common/CONDITION_TYPE.php',
     'Uraus\\Kku\\Common\\COST_TYPE' => $baseDir . '/protophp/Uraus/Kku/Common/COST_TYPE.php',
+    'Uraus\\Kku\\Common\\DISASTER_TYPE' => $baseDir . '/protophp/Uraus/Kku/Common/DISASTER_TYPE.php',
     'Uraus\\Kku\\Common\\DataCoin' => $baseDir . '/protophp/Uraus/Kku/Common/DataCoin.php',
     'Uraus\\Kku\\Common\\DataGod' => $baseDir . '/protophp/Uraus/Kku/Common/DataGod.php',
     'Uraus\\Kku\\Common\\DataHourse' => $baseDir . '/protophp/Uraus/Kku/Common/DataHourse.php',
@@ -9741,6 +9761,7 @@ return array(
     'Uraus\\Kku\\Common\\KeyValue' => $baseDir . '/protophp/Uraus/Kku/Common/KeyValue.php',
     'Uraus\\Kku\\Common\\LAND_STATUS' => $baseDir . '/protophp/Uraus/Kku/Common/LAND_STATUS.php',
     'Uraus\\Kku\\Common\\LANG_CHANGE_TYPE' => $baseDir . '/protophp/Uraus/Kku/Common/LANG_CHANGE_TYPE.php',
+    'Uraus\\Kku\\Common\\LandDisaster' => $baseDir . '/protophp/Uraus/Kku/Common/LandDisaster.php',
     'Uraus\\Kku\\Common\\LastData' => $baseDir . '/protophp/Uraus/Kku/Common/LastData.php',
     'Uraus\\Kku\\Common\\PET_STATUS' => $baseDir . '/protophp/Uraus/Kku/Common/PET_STATUS.php',
     'Uraus\\Kku\\Common\\PetFightAttr' => $baseDir . '/protophp/Uraus/Kku/Common/PetFightAttr.php',
@@ -9767,6 +9788,7 @@ return array(
     'Uraus\\Kku\\Common_CHAT_CHANNEL' => $baseDir . '/protophp/Uraus/Kku/Common_CHAT_CHANNEL.php',
     'Uraus\\Kku\\Common_CONDITION_TYPE' => $baseDir . '/protophp/Uraus/Kku/Common_CONDITION_TYPE.php',
     'Uraus\\Kku\\Common_COST_TYPE' => $baseDir . '/protophp/Uraus/Kku/Common_COST_TYPE.php',
+    'Uraus\\Kku\\Common_DISASTER_TYPE' => $baseDir . '/protophp/Uraus/Kku/Common_DISASTER_TYPE.php',
     'Uraus\\Kku\\Common_DataCoin' => $baseDir . '/protophp/Uraus/Kku/Common_DataCoin.php',
     'Uraus\\Kku\\Common_DataGod' => $baseDir . '/protophp/Uraus/Kku/Common_DataGod.php',
     'Uraus\\Kku\\Common_DataHourse' => $baseDir . '/protophp/Uraus/Kku/Common_DataHourse.php',
@@ -9787,6 +9809,7 @@ return array(
     'Uraus\\Kku\\Common_KeyValue' => $baseDir . '/protophp/Uraus/Kku/Common_KeyValue.php',
     'Uraus\\Kku\\Common_LAND_STATUS' => $baseDir . '/protophp/Uraus/Kku/Common_LAND_STATUS.php',
     'Uraus\\Kku\\Common_LANG_CHANGE_TYPE' => $baseDir . '/protophp/Uraus/Kku/Common_LANG_CHANGE_TYPE.php',
+    'Uraus\\Kku\\Common_LandDisaster' => $baseDir . '/protophp/Uraus/Kku/Common_LandDisaster.php',
     'Uraus\\Kku\\Common_LastData' => $baseDir . '/protophp/Uraus/Kku/Common_LastData.php',
     'Uraus\\Kku\\Common_PET_STATUS' => $baseDir . '/protophp/Uraus/Kku/Common_PET_STATUS.php',
     'Uraus\\Kku\\Common_PetFightAttr' => $baseDir . '/protophp/Uraus/Kku/Common_PetFightAttr.php',

+ 23 - 0
vendor/composer/autoload_static.php

@@ -879,7 +879,17 @@ class ComposerStaticInita2207959542f13e6e79e83f2b0d9a425
         'App\\Module\\AppGame\\Service\\MinerService' => __DIR__ . '/../..' . '/app/Module/AppGame/Service/MinerService.php',
         'App\\Module\\AppGame\\Service\\TransactionService' => __DIR__ . '/../..' . '/app/Module/AppGame/Service/TransactionService.php',
         'App\\Module\\AppGame\\SessionApp' => __DIR__ . '/../..' . '/app/Module/AppGame/SessionApp.php',
+        'App\\Module\\AppGame\\Tests\\Land\\DisasterRemovalBaseTest' => __DIR__ . '/../..' . '/app/Module/AppGame/Tests/Land/DisasterRemovalBaseTest.php',
+        'App\\Module\\AppGame\\Tests\\Land\\DisasterRemovalTestSuite' => __DIR__ . '/../..' . '/app/Module/AppGame/Tests/Land/DisasterRemovalTestSuite.php',
+        'App\\Module\\AppGame\\Tests\\Land\\FertilizerHandlerTest' => __DIR__ . '/../..' . '/app/Module/AppGame/Tests/Land/FertilizerHandlerTest.php',
+        'App\\Module\\AppGame\\Tests\\Land\\HarvestHandlerTest' => __DIR__ . '/../..' . '/app/Module/AppGame/Tests/Land/HarvestHandlerTest.php',
+        'App\\Module\\AppGame\\Tests\\Land\\PesticideHandlerTest' => __DIR__ . '/../..' . '/app/Module/AppGame/Tests/Land/PesticideHandlerTest.php',
+        'App\\Module\\AppGame\\Tests\\Land\\SowHandlerTest' => __DIR__ . '/../..' . '/app/Module/AppGame/Tests/Land/SowHandlerTest.php',
+        'App\\Module\\AppGame\\Tests\\Land\\WateringHandlerTest' => __DIR__ . '/../..' . '/app/Module/AppGame/Tests/Land/WateringHandlerTest.php',
+        'App\\Module\\AppGame\\Tests\\Land\\WeedicideHandlerTest' => __DIR__ . '/../..' . '/app/Module/AppGame/Tests/Land/WeedicideHandlerTest.php',
         'App\\Module\\AppGame\\Tests\\Public\\PublicTokenTest' => __DIR__ . '/../..' . '/app/Module/AppGame/Tests/Public/PublicTokenTest.php',
+        'App\\Module\\AppGame\\Tests\\TestConfig' => __DIR__ . '/../..' . '/app/Module/AppGame/Tests/TestConfig.php',
+        'App\\Module\\AppGame\\Tests\\TestEnvironment' => __DIR__ . '/../..' . '/app/Module/AppGame/Tests/TestEnvironment.php',
         'App\\Module\\AppGame\\Tools\\Protobuf' => __DIR__ . '/../..' . '/app/Module/AppGame/Tools/Protobuf.php',
         'App\\Module\\AppGame\\UserService' => __DIR__ . '/../..' . '/app/Module/AppGame/UserService.php',
         'App\\Module\\AppGame\\Validations\\LandSowValidation' => __DIR__ . '/../..' . '/app/Module/AppGame/Validations/LandSowValidation.php',
@@ -1037,6 +1047,7 @@ class ComposerStaticInita2207959542f13e6e79e83f2b0d9a425
         'App\\Module\\Farm\\Logics\\BuffLogic' => __DIR__ . '/../..' . '/app/Module/Farm/Logics/BuffLogic.php',
         'App\\Module\\Farm\\Logics\\CropLogic' => __DIR__ . '/../..' . '/app/Module/Farm/Logics/CropLogic.php',
         'App\\Module\\Farm\\Logics\\DisasterLogic' => __DIR__ . '/../..' . '/app/Module/Farm/Logics/DisasterLogic.php',
+        'App\\Module\\Farm\\Logics\\DisasterRemovalLogic' => __DIR__ . '/../..' . '/app/Module/Farm/Logics/DisasterRemovalLogic.php',
         'App\\Module\\Farm\\Logics\\FarmLogic' => __DIR__ . '/../..' . '/app/Module/Farm/Logics/FarmLogic.php',
         'App\\Module\\Farm\\Logics\\HarvestLogLogic' => __DIR__ . '/../..' . '/app/Module/Farm/Logics/HarvestLogLogic.php',
         'App\\Module\\Farm\\Logics\\HouseLogic' => __DIR__ . '/../..' . '/app/Module/Farm/Logics/HouseLogic.php',
@@ -1075,11 +1086,15 @@ class ComposerStaticInita2207959542f13e6e79e83f2b0d9a425
         'App\\Module\\Farm\\Repositories\\FarmUserRepository' => __DIR__ . '/../..' . '/app/Module/Farm/Repositories/FarmUserRepository.php',
         'App\\Module\\Farm\\Services\\BuffService' => __DIR__ . '/../..' . '/app/Module/Farm/Services/BuffService.php',
         'App\\Module\\Farm\\Services\\CropService' => __DIR__ . '/../..' . '/app/Module/Farm/Services/CropService.php',
+        'App\\Module\\Farm\\Services\\DisasterService' => __DIR__ . '/../..' . '/app/Module/Farm/Services/DisasterService.php',
         'App\\Module\\Farm\\Services\\FarmService' => __DIR__ . '/../..' . '/app/Module/Farm/Services/FarmService.php',
         'App\\Module\\Farm\\Services\\HouseService' => __DIR__ . '/../..' . '/app/Module/Farm/Services/HouseService.php',
         'App\\Module\\Farm\\Services\\LandService' => __DIR__ . '/../..' . '/app/Module/Farm/Services/LandService.php',
         'App\\Module\\Farm\\Services\\SeedService' => __DIR__ . '/../..' . '/app/Module/Farm/Services/SeedService.php',
         'App\\Module\\Farm\\Services\\TeamService' => __DIR__ . '/../..' . '/app/Module/Farm/Services/TeamService.php',
+        'App\\Module\\Farm\\Validations\\DisasterRemovalValidation' => __DIR__ . '/../..' . '/app/Module/Farm/Validations/DisasterRemovalValidation.php',
+        'App\\Module\\Farm\\Validators\\DisasterRemovalItemValidator' => __DIR__ . '/../..' . '/app/Module/Farm/Validators/DisasterRemovalItemValidator.php',
+        'App\\Module\\Farm\\Validators\\LandOwnershipValidator' => __DIR__ . '/../..' . '/app/Module/Farm/Validators/LandOwnershipValidator.php',
         'App\\Module\\File\\AdminControllers\\FileController' => __DIR__ . '/../..' . '/app/Module/File/AdminControllers/FileController.php',
         'App\\Module\\File\\AdminControllers\\Helper\\FileHelper' => __DIR__ . '/../..' . '/app/Module/File/AdminControllers/Helper/FileHelper.php',
         'App\\Module\\File\\AdminControllers\\Helper\\FilterHelper' => __DIR__ . '/../..' . '/app/Module/File/AdminControllers/Helper/FilterHelper.php',
@@ -1437,6 +1452,7 @@ class ComposerStaticInita2207959542f13e6e79e83f2b0d9a425
         'App\\Module\\Game\\Events\\TestEvent' => __DIR__ . '/../..' . '/app/Module/Game/Events/TestEvent.php',
         'App\\Module\\Game\\Exceptions\\TestException' => __DIR__ . '/../..' . '/app/Module/Game/Exceptions/TestException.php',
         'App\\Module\\Game\\Jobs\\TestJob' => __DIR__ . '/../..' . '/app/Module/Game/Jobs/TestJob.php',
+        'App\\Module\\Game\\Listeners\\CropGrowthStageChangedListener' => __DIR__ . '/../..' . '/app/Module/Game/Listeners/CropGrowthStageChangedListener.php',
         'App\\Module\\Game\\Listeners\\CropPlantedListener' => __DIR__ . '/../..' . '/app/Module/Game/Listeners/CropPlantedListener.php',
         'App\\Module\\Game\\Listeners\\FundChangedListener' => __DIR__ . '/../..' . '/app/Module/Game/Listeners/FundChangedListener.php',
         'App\\Module\\Game\\Listeners\\HouseDowngradedListener' => __DIR__ . '/../..' . '/app/Module/Game/Listeners/HouseDowngradedListener.php',
@@ -10154,6 +10170,8 @@ class ComposerStaticInita2207959542f13e6e79e83f2b0d9a425
         'Tests\\TestCase' => __DIR__ . '/../..' . '/tests/TestCase.php',
         'Tests\\Unit\\CommonTest' => __DIR__ . '/../..' . '/tests/Unit/CommonTest.php',
         'Tests\\Unit\\ExampleTest' => __DIR__ . '/../..' . '/tests/Unit/ExampleTest.php',
+        'Tests\\Unit\\Farm\\DisasterRemovalLogicTest' => __DIR__ . '/../..' . '/tests/Unit/Farm/DisasterRemovalLogicTest.php',
+        'Tests\\Unit\\Farm\\DisasterRemovalValidationTest' => __DIR__ . '/../..' . '/tests/Unit/Farm/DisasterRemovalValidationTest.php',
         'Tests\\Unit\\ProtoRequest' => __DIR__ . '/../..' . '/tests/Unit/ProtoRequest.php',
         'Tests\\Unit\\ProtoRequestTest' => __DIR__ . '/../..' . '/tests/Unit/ProtoRequestTest.php',
         'Tests\\Unit\\Protobuf2ControllerTest' => __DIR__ . '/../..' . '/tests/Unit/Protobuf2ControllerTest.php',
@@ -10307,6 +10325,7 @@ class ComposerStaticInita2207959542f13e6e79e83f2b0d9a425
         'UCore\\DcatAdmin\\Metrics\\Examples\\DataLabel2' => __DIR__ . '/../..' . '/UCore/DcatAdmin/Metrics/Examples/DataLabel2.php',
         'UCore\\DcatAdmin\\Metrics\\Examples\\DataNumber' => __DIR__ . '/../..' . '/UCore/DcatAdmin/Metrics/Examples/DataNumber.php',
         'UCore\\DcatAdmin\\Metrics\\Examples\\Link' => __DIR__ . '/../..' . '/UCore/DcatAdmin/Metrics/Examples/Link.php',
+        'UCore\\DcatAdmin\\Metrics\\Examples\\LinkA' => __DIR__ . '/../..' . '/UCore/DcatAdmin/Metrics/Examples/LinkA.php',
         'UCore\\DcatAdmin\\Metrics\\Examples\\ListDataColor' => __DIR__ . '/../..' . '/UCore/DcatAdmin/Metrics/Examples/ListDataColor.php',
         'UCore\\DcatAdmin\\Metrics\\Examples\\NewDevices' => __DIR__ . '/../..' . '/UCore/DcatAdmin/Metrics/Examples/NewDevices.php',
         'UCore\\DcatAdmin\\Metrics\\Examples\\NewUsers' => __DIR__ . '/../..' . '/UCore/DcatAdmin/Metrics/Examples/NewUsers.php',
@@ -10441,6 +10460,7 @@ class ComposerStaticInita2207959542f13e6e79e83f2b0d9a425
         'Uraus\\Kku\\Common\\CHAT_CHANNEL' => __DIR__ . '/../..' . '/protophp/Uraus/Kku/Common/CHAT_CHANNEL.php',
         'Uraus\\Kku\\Common\\CONDITION_TYPE' => __DIR__ . '/../..' . '/protophp/Uraus/Kku/Common/CONDITION_TYPE.php',
         'Uraus\\Kku\\Common\\COST_TYPE' => __DIR__ . '/../..' . '/protophp/Uraus/Kku/Common/COST_TYPE.php',
+        'Uraus\\Kku\\Common\\DISASTER_TYPE' => __DIR__ . '/../..' . '/protophp/Uraus/Kku/Common/DISASTER_TYPE.php',
         'Uraus\\Kku\\Common\\DataCoin' => __DIR__ . '/../..' . '/protophp/Uraus/Kku/Common/DataCoin.php',
         'Uraus\\Kku\\Common\\DataGod' => __DIR__ . '/../..' . '/protophp/Uraus/Kku/Common/DataGod.php',
         'Uraus\\Kku\\Common\\DataHourse' => __DIR__ . '/../..' . '/protophp/Uraus/Kku/Common/DataHourse.php',
@@ -10461,6 +10481,7 @@ class ComposerStaticInita2207959542f13e6e79e83f2b0d9a425
         'Uraus\\Kku\\Common\\KeyValue' => __DIR__ . '/../..' . '/protophp/Uraus/Kku/Common/KeyValue.php',
         'Uraus\\Kku\\Common\\LAND_STATUS' => __DIR__ . '/../..' . '/protophp/Uraus/Kku/Common/LAND_STATUS.php',
         'Uraus\\Kku\\Common\\LANG_CHANGE_TYPE' => __DIR__ . '/../..' . '/protophp/Uraus/Kku/Common/LANG_CHANGE_TYPE.php',
+        'Uraus\\Kku\\Common\\LandDisaster' => __DIR__ . '/../..' . '/protophp/Uraus/Kku/Common/LandDisaster.php',
         'Uraus\\Kku\\Common\\LastData' => __DIR__ . '/../..' . '/protophp/Uraus/Kku/Common/LastData.php',
         'Uraus\\Kku\\Common\\PET_STATUS' => __DIR__ . '/../..' . '/protophp/Uraus/Kku/Common/PET_STATUS.php',
         'Uraus\\Kku\\Common\\PetFightAttr' => __DIR__ . '/../..' . '/protophp/Uraus/Kku/Common/PetFightAttr.php',
@@ -10487,6 +10508,7 @@ class ComposerStaticInita2207959542f13e6e79e83f2b0d9a425
         'Uraus\\Kku\\Common_CHAT_CHANNEL' => __DIR__ . '/../..' . '/protophp/Uraus/Kku/Common_CHAT_CHANNEL.php',
         'Uraus\\Kku\\Common_CONDITION_TYPE' => __DIR__ . '/../..' . '/protophp/Uraus/Kku/Common_CONDITION_TYPE.php',
         'Uraus\\Kku\\Common_COST_TYPE' => __DIR__ . '/../..' . '/protophp/Uraus/Kku/Common_COST_TYPE.php',
+        'Uraus\\Kku\\Common_DISASTER_TYPE' => __DIR__ . '/../..' . '/protophp/Uraus/Kku/Common_DISASTER_TYPE.php',
         'Uraus\\Kku\\Common_DataCoin' => __DIR__ . '/../..' . '/protophp/Uraus/Kku/Common_DataCoin.php',
         'Uraus\\Kku\\Common_DataGod' => __DIR__ . '/../..' . '/protophp/Uraus/Kku/Common_DataGod.php',
         'Uraus\\Kku\\Common_DataHourse' => __DIR__ . '/../..' . '/protophp/Uraus/Kku/Common_DataHourse.php',
@@ -10507,6 +10529,7 @@ class ComposerStaticInita2207959542f13e6e79e83f2b0d9a425
         'Uraus\\Kku\\Common_KeyValue' => __DIR__ . '/../..' . '/protophp/Uraus/Kku/Common_KeyValue.php',
         'Uraus\\Kku\\Common_LAND_STATUS' => __DIR__ . '/../..' . '/protophp/Uraus/Kku/Common_LAND_STATUS.php',
         'Uraus\\Kku\\Common_LANG_CHANGE_TYPE' => __DIR__ . '/../..' . '/protophp/Uraus/Kku/Common_LANG_CHANGE_TYPE.php',
+        'Uraus\\Kku\\Common_LandDisaster' => __DIR__ . '/../..' . '/protophp/Uraus/Kku/Common_LandDisaster.php',
         'Uraus\\Kku\\Common_LastData' => __DIR__ . '/../..' . '/protophp/Uraus/Kku/Common_LastData.php',
         'Uraus\\Kku\\Common_PET_STATUS' => __DIR__ . '/../..' . '/protophp/Uraus/Kku/Common_PET_STATUS.php',
         'Uraus\\Kku\\Common_PetFightAttr' => __DIR__ . '/../..' . '/protophp/Uraus/Kku/Common_PetFightAttr.php',