|
|
@@ -0,0 +1,665 @@
|
|
|
+# 农场摘取功能设计文档
|
|
|
+
|
|
|
+## 目录
|
|
|
+
|
|
|
+1. [功能概述](#1-功能概述)
|
|
|
+2. [数据库设计](#2-数据库设计)
|
|
|
+3. [摘取来源定义](#3-摘取来源定义)
|
|
|
+4. [模型层设计](#4-模型层设计)
|
|
|
+5. [DTO层设计](#5-dto层设计)
|
|
|
+6. [验证层设计](#6-验证层设计)
|
|
|
+7. [逻辑层设计](#7-逻辑层设计)
|
|
|
+8. [服务层设计](#8-服务层设计)
|
|
|
+9. [配置设计](#9-配置设计)
|
|
|
+10. [事件系统](#10-事件系统)
|
|
|
+11. [使用示例](#11-使用示例)
|
|
|
+12. [Handler层设计](#12-handler层设计)
|
|
|
+13. [作物日志扩展](#13-作物日志扩展)
|
|
|
+14. [植物配置表扩展](#14-植物配置表扩展)
|
|
|
+15. [数据库迁移SQL](#15-数据库迁移sql)
|
|
|
+16. [总结](#16-总结)
|
|
|
+
|
|
|
+## 1. 功能概述
|
|
|
+
|
|
|
+摘取功能是农场模块的一个重要特性,允许用户在作物成熟期对作物进行部分摘取,而不是完全收获。摘取功能与收获功能的主要区别在于:
|
|
|
+
|
|
|
+- **收获**:完全收获作物,作物进入枯萎期,土地状态变为枯萎
|
|
|
+- **摘取**:部分摘取作物产出,作物依然保持成熟期,可以继续摘取或收获
|
|
|
+
|
|
|
+### 1.1 核心特性
|
|
|
+
|
|
|
+1. **允许任何用户摘取**:不限制摘取者身份,无需鉴权,任何用户都可以摘取任何成熟的作物
|
|
|
+2. **保持成熟期状态**:摘取后作物依然处于成熟期,不进入枯萎期
|
|
|
+3. **减少可收获数量**:每次摘取会减少作物的最终可收获数量
|
|
|
+4. **完整日志记录**:记录所有摘取行为,包括摘取者、数量、时间等
|
|
|
+5. **服务层接口**:提供静态方法供其他模块调用
|
|
|
+
|
|
|
+### 1.2 业务规则
|
|
|
+
|
|
|
+1. **摘取条件**:作物必须处于成熟期(GROWTH_STAGE::MATURE)
|
|
|
+2. **无权限限制**:任何用户都可以摘取任何成熟的作物,无需身份验证或好友关系
|
|
|
+3. **摘取限制**:每次摘取数量不能超过当前可摘取数量
|
|
|
+4. **最小保留**:作物必须保留最小数量,不能完全摘取完
|
|
|
+5. **摘取比例**:每次摘取数量为当前可摘取数量的一定比例
|
|
|
+6. **冷却时间**:同一作物被摘取后有冷却时间限制
|
|
|
+
|
|
|
+## 2. 数据库设计
|
|
|
+
|
|
|
+### 2.1 作物表扩展字段
|
|
|
+
|
|
|
+需要在 `farm_crops` 表中添加以下字段来支持摘取功能:
|
|
|
+
|
|
|
+```sql
|
|
|
+ALTER TABLE `kku_farm_crops`
|
|
|
+ADD COLUMN `picked_amount` int(11) NOT NULL DEFAULT '0' COMMENT '已摘取数量',
|
|
|
+ADD COLUMN `last_pick_time` timestamp NULL DEFAULT NULL COMMENT '最后摘取时间',
|
|
|
+ADD COLUMN `pick_cooldown_end` timestamp NULL DEFAULT NULL COMMENT '摘取冷却结束时间',
|
|
|
+ADD COLUMN `min_reserve_amount` int(11) NOT NULL DEFAULT '0' COMMENT '最小保留数量(不可摘取)';
|
|
|
+```
|
|
|
+
|
|
|
+### 2.2 摘取日志记录
|
|
|
+
|
|
|
+摘取功能使用现有的作物日志表(`farm_crop_logs`)来记录摘取事件,无需创建单独的摘取日志表。这样做的优势:
|
|
|
+
|
|
|
+1. **架构统一**:所有作物相关事件都在一个表中,便于统一管理
|
|
|
+2. **数据完整性**:可以在一个地方查看作物的完整生命周期
|
|
|
+3. **减少复杂度**:避免数据库表过多,降低维护成本
|
|
|
+4. **查询便利**:作物日志表已有完善的索引和关联关系
|
|
|
+
|
|
|
+摘取事件将作为新的事件类型添加到作物日志中:
|
|
|
+
|
|
|
+```php
|
|
|
+// 在FarmCropLog模型中添加摘取事件类型
|
|
|
+const EVENT_PICKED = 'picked'; // 摘取事件
|
|
|
+
|
|
|
+// 摘取时的event_data结构
|
|
|
+{
|
|
|
+ "picker_id": 1001, // 摘取者ID
|
|
|
+ "pick_amount": 50, // 摘取数量
|
|
|
+ "remaining_amount": 150, // 摘取后剩余数量
|
|
|
+ "pick_ratio": 0.25, // 摘取比例
|
|
|
+ "pick_type": "friend", // 摘取类型
|
|
|
+ "item_id": 3001, // 摘取的物品ID
|
|
|
+ "total_picked": 80, // 累计摘取数量
|
|
|
+ "cooldown_end": "2025-07-07 23:00:00", // 冷却结束时间
|
|
|
+ "ip_address": "127.0.0.1", // 摘取者IP
|
|
|
+ "user_agent": "Mozilla/5.0..." // 用户代理
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+## 3. 摘取来源定义
|
|
|
+
|
|
|
+### 3.1 摘取来源说明
|
|
|
+
|
|
|
+**常见摘取来源**:
|
|
|
+- `manual`: 手动摘取
|
|
|
+- `friend_visit`: 好友访问摘取
|
|
|
+- `system_auto`: 系统自动摘取
|
|
|
+- `task_reward`: 任务奖励摘取
|
|
|
+- `event_bonus`: 活动奖励摘取
|
|
|
+
|
|
|
+**来源ID说明**:
|
|
|
+- 好友访问:好友访问记录ID
|
|
|
+- 系统任务:任务ID
|
|
|
+- 活动奖励:活动ID
|
|
|
+- 手动摘取:可为空
|
|
|
+
|
|
|
+**设计原则**:
|
|
|
+- 摘取来源由调用方决定,农场模块只负责记录
|
|
|
+- 来源信息用于日志记录和统计分析
|
|
|
+- 不影响摘取权限和业务逻辑
|
|
|
+
|
|
|
+## 4. 模型层设计
|
|
|
+
|
|
|
+### 4.1 作物日志模型扩展
|
|
|
+
|
|
|
+在现有的 `FarmCropLog` 模型中添加摘取事件支持:
|
|
|
+
|
|
|
+**需要添加的内容**:
|
|
|
+- 摘取事件常量:`EVENT_PICKED = 'picked'`
|
|
|
+- 摘取日志记录方法:`logPicked()` 静态方法
|
|
|
+- 事件类型名称获取方法
|
|
|
+- 摘取事件查询作用域方法
|
|
|
+
|
|
|
+### 4.2 作物模型扩展
|
|
|
+
|
|
|
+在 `FarmCrop` 模型中添加摘取相关的方法和属性:
|
|
|
+
|
|
|
+**需要添加的方法**:
|
|
|
+- `getPickableAmountAttribute()`: 计算可摘取数量的访问器
|
|
|
+- `canBePicked()`: 检查是否可以摘取的方法
|
|
|
+- `getPickLogsAttribute()`: 获取摘取记录的访问器(通过作物日志查询)
|
|
|
+- `getPickCountAttribute()`: 获取摘取次数的访问器
|
|
|
+
|
|
|
+**业务逻辑要点**:
|
|
|
+- 可摘取数量 = 总产量 - 已摘取数量 - 最小保留数量
|
|
|
+- 摘取条件:成熟期 + 有可摘取数量 + 冷却时间已过
|
|
|
+- 摘取记录通过作物日志表的摘取事件获取
|
|
|
+
|
|
|
+## 5. DTO层设计
|
|
|
+
|
|
|
+### 5.1 摘取结果DTO
|
|
|
+
|
|
|
+**PickResultDto 类设计**:
|
|
|
+
|
|
|
+**属性字段**:
|
|
|
+- `cropId`: 作物ID
|
|
|
+- `itemId`: 摘取的物品ID
|
|
|
+- `pickAmount`: 摘取数量
|
|
|
+- `remainingAmount`: 剩余可摘取数量
|
|
|
+- `pickRatio`: 摘取比例
|
|
|
+- `pickTime`: 摘取时间
|
|
|
+- `pickSource`: 摘取来源
|
|
|
+- `sourceId`: 来源ID
|
|
|
+- `pickLogId`: 摘取记录ID(作物日志ID)
|
|
|
+- `canPickAgain`: 是否可以再次摘取
|
|
|
+- `nextPickTime`: 下次可摘取时间
|
|
|
+
|
|
|
+**创建方法**:
|
|
|
+- `fromPickOperation()`: 从摘取操作创建DTO
|
|
|
+
|
|
|
+### 5.2 摘取信息DTO
|
|
|
+
|
|
|
+**PickInfoDto 类设计**:
|
|
|
+
|
|
|
+**属性字段**:
|
|
|
+- `cropId`: 作物ID
|
|
|
+- `seedId`: 种子ID
|
|
|
+- `totalAmount`: 总产出数量
|
|
|
+- `pickedAmount`: 已摘取数量
|
|
|
+- `pickableAmount`: 可摘取数量
|
|
|
+- `minReserveAmount`: 最小保留数量
|
|
|
+- `canPick`: 是否可以摘取
|
|
|
+- `lastPickTime`: 最后摘取时间
|
|
|
+- `nextPickTime`: 下次可摘取时间
|
|
|
+- `pickCount`: 摘取次数
|
|
|
+- `maxPickRatio`: 最大摘取比例
|
|
|
+
|
|
|
+**创建方法**:
|
|
|
+- `fromCrop()`: 从作物模型创建DTO
|
|
|
+
|
|
|
+## 6. 验证层设计
|
|
|
+
|
|
|
+### 6.1 摘取验证类
|
|
|
+
|
|
|
+**CropPickValidation 类设计**:
|
|
|
+
|
|
|
+**验证字段**:
|
|
|
+- `pickerId`: 摘取者ID
|
|
|
+- `cropId`: 作物ID
|
|
|
+- `pickAmount`: 摘取数量
|
|
|
+- `pickSource`: 摘取来源
|
|
|
+- `sourceId`: 来源ID(可选)
|
|
|
+
|
|
|
+**验证规则**:
|
|
|
+- 所有ID字段必填且为正整数
|
|
|
+- 摘取数量必须大于0
|
|
|
+- 摘取来源必须为有效字符串
|
|
|
+- 来源ID为可选参数
|
|
|
+
|
|
|
+**验证器链**:
|
|
|
+- `PickableStatusValidator`: 摘取状态验证器
|
|
|
+- `PickAmountValidator`: 摘取数量验证器
|
|
|
+- `PickCooldownValidator`: 摘取冷却验证器
|
|
|
+- `PickSourceValidator`: 摘取来源验证器(可选)
|
|
|
+
|
|
|
+### 6.2 摘取状态验证器
|
|
|
+
|
|
|
+**PickableStatusValidator 验证逻辑**:
|
|
|
+- 验证作物是否存在
|
|
|
+- 检查作物是否处于成熟期
|
|
|
+- 检查作物是否满足摘取条件
|
|
|
+- 将验证通过的作物信息存储供后续验证器使用
|
|
|
+- 无需验证用户权限或所有权关系
|
|
|
+
|
|
|
+### 6.3 摘取数量验证器
|
|
|
+
|
|
|
+**PickAmountValidator 验证逻辑**:
|
|
|
+- 检查摘取数量是否超过当前可摘取数量
|
|
|
+- 检查单次摘取比例是否超过配置限制
|
|
|
+- 验证摘取数量的合理性
|
|
|
+
|
|
|
+### 6.4 摘取冷却验证器
|
|
|
+
|
|
|
+**PickCooldownValidator 验证逻辑**:
|
|
|
+- 检查作物是否在摘取冷却期内
|
|
|
+- 验证摘取时间间隔是否符合要求
|
|
|
+
|
|
|
+### 6.5 摘取来源验证器
|
|
|
+
|
|
|
+**PickSourceValidator 验证逻辑**:
|
|
|
+- 验证摘取来源字符串格式
|
|
|
+- 检查来源ID的有效性(如果提供)
|
|
|
+- 确保来源信息符合业务规范
|
|
|
+
|
|
|
+## 7. 逻辑层设计
|
|
|
+
|
|
|
+### 7.1 摘取逻辑类
|
|
|
+
|
|
|
+**PickLogic 类设计**:
|
|
|
+
|
|
|
+**核心方法**:
|
|
|
+- `executePick($pickerId, $cropId, $pickAmount, $pickSource, $sourceId)`: 执行摘取操作的核心方法
|
|
|
+- `getPickInfo($cropId)`: 获取作物摘取信息
|
|
|
+- `batchPick($pickerId, $cropRequests)`: 批量摘取多个作物
|
|
|
+
|
|
|
+**executePick() 方法逻辑**:
|
|
|
+1. 事务检查确保在事务中执行
|
|
|
+2. 根据作物ID获取并验证作物信息
|
|
|
+3. 检查摘取条件和数量限制
|
|
|
+4. 计算摘取比例
|
|
|
+5. 更新作物的摘取相关字段
|
|
|
+6. 设置摘取冷却时间
|
|
|
+7. 记录摘取事件到作物日志(包含来源信息)
|
|
|
+8. 给摘取者添加物品到背包(记录来源)
|
|
|
+9. 记录操作日志
|
|
|
+10. 返回摘取结果DTO(包含来源信息)
|
|
|
+**getPickInfo() 方法逻辑**:
|
|
|
+- 根据作物ID获取作物信息
|
|
|
+- 将作物信息转换为摘取信息DTO
|
|
|
+- 返回摘取相关的详细信息
|
|
|
+
|
|
|
+**batchPick() 方法逻辑**:
|
|
|
+- 接收批量摘取请求数组(包含作物ID、数量、来源信息)
|
|
|
+- 循环处理每个摘取请求
|
|
|
+- 捕获异常并记录失败原因
|
|
|
+- 返回包含成功和失败结果的数组
|
|
|
+
|
|
|
+**辅助方法**:
|
|
|
+- `formatPickSource()`: 格式化摘取来源信息用于日志记录
|
|
|
+```
|
|
|
+
|
|
|
+## 8. 服务层设计
|
|
|
+
|
|
|
+### 8.1 摘取服务类
|
|
|
+
|
|
|
+**PickService 类设计**:
|
|
|
+
|
|
|
+**核心静态方法**:
|
|
|
+- `pickCrop($pickerId, $cropId, $pickAmount, $pickSource, $sourceId)`: 摘取指定作物
|
|
|
+- `getPickInfo($cropId)`: 获取作物摘取信息
|
|
|
+- `batchPickCrops($pickerId, $cropRequests)`: 批量摘取多个作物
|
|
|
+- `canPickCrop($cropId)`: 检查作物是否可以摘取
|
|
|
+- `getPickHistory($userId, $type, $limit)`: 获取摘取历史记录
|
|
|
+
|
|
|
+**pickCrop() 方法流程**:
|
|
|
+1. 验证摘取参数(包括来源信息)
|
|
|
+2. 在数据库事务中调用逻辑层执行摘取
|
|
|
+3. 记录摘取来源和来源ID到日志
|
|
|
+4. 返回成功结果或错误信息
|
|
|
+5. 记录详细的操作日志
|
|
|
+**其他服务方法**:
|
|
|
+
|
|
|
+**getPickInfo() 方法**:
|
|
|
+- 调用逻辑层获取作物摘取信息
|
|
|
+- 异常处理和日志记录
|
|
|
+- 返回摘取信息DTO或null
|
|
|
+
|
|
|
+**batchPickCrops() 方法**:
|
|
|
+- 在事务中执行批量摘取操作
|
|
|
+- 调用逻辑层的批量摘取方法
|
|
|
+- 统一的异常处理和错误返回
|
|
|
+**canPickCrop() 方法**:
|
|
|
+- 根据作物ID检查摘取条件
|
|
|
+- 检查作物状态和摘取限制
|
|
|
+- 无需验证用户身份或权限关系
|
|
|
+- 返回详细的检查结果和原因
|
|
|
+**getPickHistory() 方法**:
|
|
|
+- 从作物日志表查询摘取事件记录
|
|
|
+- 支持按摘取者或农场主身份查询
|
|
|
+- 通过JSON字段查询摘取者信息
|
|
|
+- 返回格式化的摘取历史数组
|
|
|
+```
|
|
|
+
|
|
|
+## 9. 配置设计
|
|
|
+
|
|
|
+### 9.1 摘取配置文件
|
|
|
+
|
|
|
+**配置文件位置**:`config/farm.php`
|
|
|
+
|
|
|
+**摘取配置项**:
|
|
|
+- `enabled`: 摘取功能开关
|
|
|
+- `max_ratio`: 最大摘取比例(单次摘取不能超过总产量的百分比)
|
|
|
+- `cooldown_seconds`: 摘取冷却时间(秒)
|
|
|
+- `min_reserve_ratio`: 最小保留比例(必须保留的最小产量比例)
|
|
|
+- `daily_pick_limit`: 每日摘取次数限制(可选,由其他模块实现)
|
|
|
+- `experience_reward`: 摘取经验奖励(可选,由其他模块实现)
|
|
|
+
|
|
|
+### 9.2 环境变量配置
|
|
|
+
|
|
|
+**环境变量列表**:
|
|
|
+- `FARM_PICK_ENABLED`: 功能开关
|
|
|
+- `FARM_PICK_MAX_RATIO`: 最大摘取比例
|
|
|
+- `FARM_PICK_COOLDOWN_SECONDS`: 冷却时间
|
|
|
+- `FARM_PICK_MIN_RESERVE_RATIO`: 最小保留比例
|
|
|
+
|
|
|
+## 10. 事件系统
|
|
|
+
|
|
|
+### 10.1 摘取事件
|
|
|
+
|
|
|
+**CropPickedEvent 事件类设计**:
|
|
|
+
|
|
|
+**事件属性**:
|
|
|
+- `pickerId`: 摘取者ID
|
|
|
+- `ownerId`: 农场主ID(通过作物获取)
|
|
|
+- `landId`: 土地ID(通过作物获取)
|
|
|
+- `cropId`: 作物ID(摘取目标)
|
|
|
+- `itemId`: 摘取的物品ID
|
|
|
+- `pickAmount`: 摘取数量
|
|
|
+- `originalAmount`: 摘取前总数量
|
|
|
+- `remainingAmount`: 摘取后剩余数量
|
|
|
+- `pickSource`: 摘取来源
|
|
|
+- `sourceId`: 来源ID
|
|
|
+- `land`: 土地信息对象
|
|
|
+- `crop`: 作物信息对象
|
|
|
+- `cropLog`: 作物日志记录对象
|
|
|
+
|
|
|
+**触发时机**:
|
|
|
+- 摘取操作成功完成后触发
|
|
|
+- 包含完整的摘取上下文信息,供其他模块使用
|
|
|
+
|
|
|
+### 10.2 事件监听器
|
|
|
+
|
|
|
+**PickStatisticsListener 监听器设计**:
|
|
|
+
|
|
|
+**主要功能**:
|
|
|
+- 更新摘取统计数据
|
|
|
+- 记录详细的摘取行为日志
|
|
|
+- 触发其他模块的相关逻辑(通过事件)
|
|
|
+
|
|
|
+**处理逻辑**:
|
|
|
+- `updatePickStatistics()`: 更新摘取统计信息
|
|
|
+- `logPickBehavior()`: 记录摘取行为日志
|
|
|
+- `triggerExternalLogic()`: 触发外部模块逻辑(如通知、奖励等)
|
|
|
+
|
|
|
+**扩展点**:
|
|
|
+- 其他模块可以监听摘取事件实现自己的业务逻辑
|
|
|
+- 农场模块只负责核心的摘取功能和统计
|
|
|
+
|
|
|
+## 11. 使用示例
|
|
|
+
|
|
|
+### 11.1 基本摘取操作
|
|
|
+
|
|
|
+**调用方式**:
|
|
|
+```php
|
|
|
+PickService::pickCrop($pickerId, $cropId, $pickAmount, $pickSource, $sourceId)
|
|
|
+```
|
|
|
+
|
|
|
+**参数说明**:
|
|
|
+- `pickerId`: 摘取者用户ID
|
|
|
+- `cropId`: 作物ID(摘取目标)
|
|
|
+- `pickAmount`: 摘取数量
|
|
|
+- `pickSource`: 摘取来源(如:'manual', 'friend_visit', 'system_auto'等)
|
|
|
+- `sourceId`: 来源ID(如:好友访问记录ID、系统任务ID等,可选)
|
|
|
+
|
|
|
+**返回结果**:
|
|
|
+- 成功:返回包含摘取详情的DTO对象
|
|
|
+- 失败:返回错误信息
|
|
|
+
|
|
|
+### 11.2 不同来源的摘取操作
|
|
|
+
|
|
|
+**使用场景**:任何用户都可以摘取任何成熟的作物
|
|
|
+**摘取来源**:根据实际业务场景设置(如:'manual'、'friend_visit'、'system_auto'等)
|
|
|
+**权限检查**:无需权限验证,允许任何用户摘取
|
|
|
+
|
|
|
+### 11.3 获取摘取信息
|
|
|
+
|
|
|
+**调用方式**:
|
|
|
+```php
|
|
|
+PickService::getPickInfo($cropId)
|
|
|
+```
|
|
|
+
|
|
|
+**返回信息**:
|
|
|
+- 总产量、已摘取数量、可摘取数量
|
|
|
+- 摘取状态、冷却时间信息
|
|
|
+- 摘取次数、最大摘取比例等
|
|
|
+
|
|
|
+### 11.4 批量摘取操作
|
|
|
+
|
|
|
+**使用场景**:一次性摘取多个作物
|
|
|
+**请求格式**:包含作物ID、摘取数量、来源信息的数组
|
|
|
+**返回结果**:每个摘取请求的成功/失败状态
|
|
|
+
|
|
|
+**请求示例**:
|
|
|
+```php
|
|
|
+$cropRequests = [
|
|
|
+ ['crop_id' => 123, 'amount' => 20, 'source' => 'friend_visit', 'source_id' => 456],
|
|
|
+ ['crop_id' => 124, 'amount' => 30, 'source' => 'manual', 'source_id' => null],
|
|
|
+ ['crop_id' => 125, 'amount' => 25, 'source' => 'task_reward', 'source_id' => 789],
|
|
|
+];
|
|
|
+```
|
|
|
+
|
|
|
+### 11.5 检查摘取条件
|
|
|
+
|
|
|
+**功能**:在实际摘取前检查作物是否满足摘取条件
|
|
|
+**检查项目**:作物状态、摘取限制、冷却时间等(无需权限检查)
|
|
|
+**返回信息**:是否可摘取及详细原因
|
|
|
+
|
|
|
+## 12. Handler层设计
|
|
|
+
|
|
|
+### 12.1 摘取Handler
|
|
|
+
|
|
|
+**PickHandler 类设计**:
|
|
|
+
|
|
|
+**处理流程**:
|
|
|
+1. 获取请求参数(作物ID、摘取数量、来源信息等)
|
|
|
+2. 确定摘取来源和来源ID
|
|
|
+3. 执行数据验证
|
|
|
+4. 开启数据库事务
|
|
|
+5. 调用摘取服务执行操作
|
|
|
+6. 设置protobuf响应数据
|
|
|
+7. 记录操作日志
|
|
|
+
|
|
|
+**响应字段**:
|
|
|
+- `success`: 操作是否成功
|
|
|
+- `cropId`: 作物ID
|
|
|
+- `itemId`: 摘取的物品ID
|
|
|
+- `pickAmount`: 摘取数量
|
|
|
+- `remainingAmount`: 剩余可摘取数量
|
|
|
+- `pickTime`: 摘取时间
|
|
|
+- `pickSource`: 摘取来源
|
|
|
+- `sourceId`: 来源ID
|
|
|
+- `canPickAgain`: 是否可以再次摘取
|
|
|
+- `nextPickTime`: 下次可摘取时间(可选)
|
|
|
+- `errorMessage`: 错误信息(失败时)
|
|
|
+
|
|
|
+### 12.2 获取摘取信息Handler
|
|
|
+
|
|
|
+**PickInfoHandler 类设计**:
|
|
|
+
|
|
|
+**处理流程**:
|
|
|
+1. 获取作物ID参数
|
|
|
+2. 调用摘取服务获取摘取信息
|
|
|
+3. 设置protobuf响应数据
|
|
|
+4. 异常处理和日志记录
|
|
|
+
|
|
|
+**响应字段**:
|
|
|
+- `success`: 操作是否成功
|
|
|
+- `cropId`: 作物ID
|
|
|
+- `seedId`: 种子ID
|
|
|
+- `totalAmount`: 总产出数量
|
|
|
+- `pickedAmount`: 已摘取数量
|
|
|
+- `pickableAmount`: 可摘取数量
|
|
|
+- `minReserveAmount`: 最小保留数量
|
|
|
+- `canPick`: 是否可以摘取
|
|
|
+- `pickCount`: 摘取次数
|
|
|
+- `maxPickRatio`: 最大摘取比例
|
|
|
+- `lastPickTime`: 最后摘取时间(可选)
|
|
|
+- `nextPickTime`: 下次可摘取时间(可选)
|
|
|
+- `errorMessage`: 错误信息(失败时)
|
|
|
+
|
|
|
+## 13. 作物日志扩展
|
|
|
+
|
|
|
+### 13.1 在FarmCropLog模型中添加摘取事件
|
|
|
+
|
|
|
+**需要添加的内容**:
|
|
|
+- 摘取事件常量:`EVENT_PICKED = 'picked'`
|
|
|
+- 摘取日志记录方法:`logPicked()` 静态方法
|
|
|
+- 事件数据结构定义
|
|
|
+- 查询作用域方法
|
|
|
+
|
|
|
+**事件数据结构**:
|
|
|
+- `picker_id`: 摘取者ID
|
|
|
+- `pick_amount`: 摘取数量
|
|
|
+- `remaining_amount`: 剩余数量
|
|
|
+- `pick_ratio`: 摘取比例
|
|
|
+- `pick_source`: 摘取来源
|
|
|
+- `source_id`: 来源ID
|
|
|
+- `item_id`: 摘取的物品ID
|
|
|
+- `total_picked`: 累计摘取数量
|
|
|
+- `cooldown_end`: 冷却结束时间
|
|
|
+- `ip_address`: 摘取者IP
|
|
|
+- `user_agent`: 用户代理
|
|
|
+
|
|
|
+## 14. 植物配置表扩展
|
|
|
+
|
|
|
+### 14.1 种子配置表摘取限制扩展
|
|
|
+
|
|
|
+**表名**:`farm_seeds`
|
|
|
+
|
|
|
+**需要添加的字段**:
|
|
|
+- `pick_enabled`: 是否允许摘取(tinyint,默认1)
|
|
|
+- `pick_max_ratio`: 最大摘取比例(decimal(5,4),默认0.3000)
|
|
|
+- `pick_min_reserve_ratio`: 最小保留比例(decimal(5,4),默认0.1000)
|
|
|
+- `pick_cooldown_seconds`: 摘取冷却时间秒(int,默认1800)
|
|
|
+
|
|
|
+**字段说明**:
|
|
|
+- `pick_enabled`: 控制该种子的作物是否允许摘取
|
|
|
+- `pick_max_ratio`: 单次最大摘取比例(如0.3表示最多摘取30%)
|
|
|
+- `pick_min_reserve_ratio`: 必须保留的最小比例(如0.1表示至少保留10%)
|
|
|
+- `pick_cooldown_seconds`: 摘取后的冷却时间(秒)
|
|
|
+
|
|
|
+### 14.2 果实生长周期表摘取限制扩展
|
|
|
+
|
|
|
+**表名**:`farm_fruit_growth_cycles`
|
|
|
+
|
|
|
+**需要添加的字段**:
|
|
|
+- `pick_enabled`: 是否允许摘取(tinyint,默认1)
|
|
|
+- `pick_start_stage`: 允许摘取的最早阶段(tinyint,默认40,表示成熟期)
|
|
|
+- `pick_efficiency`: 摘取效率(decimal(5,4),默认1.0000)
|
|
|
+
|
|
|
+**字段说明**:
|
|
|
+- `pick_enabled`: 控制该果实是否允许摘取
|
|
|
+- `pick_start_stage`: 从哪个生长阶段开始允许摘取(40=成熟期)
|
|
|
+- `pick_efficiency`: 摘取效率,影响摘取获得的数量
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+## 15. 数据库迁移SQL
|
|
|
+
|
|
|
+### 15.1 作物表字段扩展SQL
|
|
|
+
|
|
|
+```sql
|
|
|
+-- 为作物表添加摘取相关字段
|
|
|
+ALTER TABLE `kku_farm_crops`
|
|
|
+ADD COLUMN `picked_amount` int(11) NOT NULL DEFAULT '0' COMMENT '已摘取数量' AFTER `final_output_amount`,
|
|
|
+ADD COLUMN `last_pick_time` timestamp NULL DEFAULT NULL COMMENT '最后摘取时间' AFTER `picked_amount`,
|
|
|
+ADD COLUMN `pick_cooldown_end` timestamp NULL DEFAULT NULL COMMENT '摘取冷却结束时间' AFTER `last_pick_time`,
|
|
|
+ADD COLUMN `min_reserve_amount` int(11) NOT NULL DEFAULT '0' COMMENT '最小保留数量(不可摘取)' AFTER `pick_cooldown_end`;
|
|
|
+
|
|
|
+-- 添加索引
|
|
|
+ALTER TABLE `kku_farm_crops`
|
|
|
+ADD INDEX `idx_last_pick_time` (`last_pick_time`),
|
|
|
+ADD INDEX `idx_pick_cooldown_end` (`pick_cooldown_end`),
|
|
|
+ADD INDEX `idx_picked_amount` (`picked_amount`);
|
|
|
+```
|
|
|
+
|
|
|
+### 15.2 种子配置表摘取限制扩展SQL
|
|
|
+
|
|
|
+```sql
|
|
|
+-- 为种子配置表添加摘取限制字段
|
|
|
+ALTER TABLE `kku_farm_seeds`
|
|
|
+ADD COLUMN `pick_enabled` tinyint(1) NOT NULL DEFAULT '1' COMMENT '是否允许摘取:0否,1是' AFTER `display_attributes`,
|
|
|
+ADD COLUMN `pick_max_ratio` decimal(5,4) NOT NULL DEFAULT '0.3000' COMMENT '最大摘取比例' AFTER `pick_enabled`,
|
|
|
+ADD COLUMN `pick_min_reserve_ratio` decimal(5,4) NOT NULL DEFAULT '0.1000' COMMENT '最小保留比例' AFTER `pick_max_ratio`,
|
|
|
+ADD COLUMN `pick_cooldown_seconds` int(10) unsigned NOT NULL DEFAULT '1800' COMMENT '摘取冷却时间(秒)' AFTER `pick_min_reserve_ratio`;
|
|
|
+
|
|
|
+-- 添加索引
|
|
|
+ALTER TABLE `kku_farm_seeds`
|
|
|
+ADD INDEX `idx_pick_enabled` (`pick_enabled`),
|
|
|
+ADD INDEX `idx_pick_max_ratio` (`pick_max_ratio`);
|
|
|
+```
|
|
|
+
|
|
|
+### 15.3 果实生长周期表摘取限制扩展SQL
|
|
|
+
|
|
|
+```sql
|
|
|
+-- 为果实生长周期表添加摘取限制字段
|
|
|
+ALTER TABLE `kku_farm_fruit_growth_cycles`
|
|
|
+ADD COLUMN `pick_enabled` tinyint(1) NOT NULL DEFAULT '1' COMMENT '是否允许摘取:0否,1是' AFTER `wither_time`,
|
|
|
+ADD COLUMN `pick_start_stage` tinyint(3) unsigned NOT NULL DEFAULT '40' COMMENT '允许摘取的最早阶段:40成熟期' AFTER `pick_enabled`,
|
|
|
+ADD COLUMN `pick_efficiency` decimal(5,4) NOT NULL DEFAULT '1.0000' COMMENT '摘取效率' AFTER `pick_start_stage`;
|
|
|
+
|
|
|
+-- 添加索引
|
|
|
+ALTER TABLE `kku_farm_fruit_growth_cycles`
|
|
|
+ADD INDEX `idx_pick_enabled` (`pick_enabled`),
|
|
|
+ADD INDEX `idx_pick_start_stage` (`pick_start_stage`);
|
|
|
+```
|
|
|
+
|
|
|
+### 15.4 作物日志表事件类型更新SQL
|
|
|
+
|
|
|
+```sql
|
|
|
+-- 更新作物日志表的事件类型注释,添加摘取事件
|
|
|
+ALTER TABLE `kku_farm_crop_logs`
|
|
|
+MODIFY COLUMN `event_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL
|
|
|
+COMMENT '事件类型:fruit_confirmed(确认果实种类), output_calculated(确认产出数量), disaster_occurred(灾害产生), disaster_cleared(灾害清除), harvested(收获), fertilized(施肥), pesticide_used(使用杀虫剂), weedicide_used(使用除草剂), watering(浇水), removed(铲除作物), picked(摘取)';
|
|
|
+
|
|
|
+-- 为作物日志表添加摘取相关索引
|
|
|
+ALTER TABLE `kku_farm_crop_logs`
|
|
|
+ADD INDEX `idx_event_type_user` (`event_type`, `user_id`),
|
|
|
+ADD INDEX `idx_event_type_created` (`event_type`, `created_at`);
|
|
|
+```
|
|
|
+
|
|
|
+## 16. 总结
|
|
|
+
|
|
|
+### 16.1 功能特点
|
|
|
+
|
|
|
+摘取功能作为农场模块的核心功能,具有以下特点:
|
|
|
+
|
|
|
+1. **开放性**:允许任何用户摘取任何成熟作物,无权限限制
|
|
|
+2. **可控性**:通过比例限制、冷却时间等机制控制摘取行为
|
|
|
+3. **可追溯性**:完整记录摘取来源和来源ID,支持业务追溯
|
|
|
+4. **模块化**:专注于农场核心功能,通过事件系统与其他模块交互
|
|
|
+5. **灵活性**:支持多种摘取来源,适应不同业务场景
|
|
|
+6. **安全性**:通过验证层和事务机制保证数据安全
|
|
|
+
|
|
|
+### 16.2 与收获功能的区别
|
|
|
+
|
|
|
+| 特性 | 摘取功能 | 收获功能 |
|
|
|
+|------|---------|---------|
|
|
|
+| 操作者 | 任何用户(包括好友) | 仅农场主 |
|
|
|
+| 作物状态 | 保持成熟期 | 进入枯萎期 |
|
|
|
+| 获得数量 | 部分产出 | 全部产出 |
|
|
|
+| 操作限制 | 有冷却时间和比例限制 | 无限制 |
|
|
|
+| 土地状态 | 不变 | 变为枯萎状态 |
|
|
|
+| 后续操作 | 可继续摘取或收获 | 需要重新种植 |
|
|
|
+
|
|
|
+### 16.3 实现要点
|
|
|
+
|
|
|
+1. **数据库设计**:扩展作物表字段,利用现有作物日志表记录摘取事件
|
|
|
+2. **植物配置**:在种子配置表和果实生长周期表中添加摘取限制参数
|
|
|
+3. **业务逻辑**:实现摘取验证、执行、记录的完整流程
|
|
|
+4. **服务接口**:提供静态方法供其他模块调用
|
|
|
+5. **配置管理**:通过配置文件和数据库配置灵活控制摘取参数
|
|
|
+6. **事件系统**:通过事件与其他模块解耦,农场模块专注核心功能
|
|
|
+7. **日志记录**:利用作物日志表统一记录摘取行为和作物状态变化
|
|
|
+8. **来源追溯**:完整记录摘取来源和来源ID,支持业务追溯
|
|
|
+9. **模块边界**:明确农场模块职责,不包含好友关系、通知等其他模块逻辑
|
|
|
+
|
|
|
+### 16.4 模块协作
|
|
|
+
|
|
|
+农场模块通过事件系统与其他模块协作:
|
|
|
+
|
|
|
+1. **好友系统**:监听摘取事件,实现好友关系相关的业务逻辑
|
|
|
+2. **奖励系统**:监听摘取事件,为摘取行为提供经验、积分等奖励
|
|
|
+3. **通知系统**:监听摘取事件,发送摘取通知给相关用户
|
|
|
+4. **统计系统**:监听摘取事件,进行用户行为分析和数据统计
|
|
|
+5. **防护系统**:可以在摘取前进行额外的防护检查
|
|
|
+
|
|
|
+### 16.5 设计原则
|
|
|
+
|
|
|
+1. **单一职责**:农场模块只负责作物摘取的核心功能
|
|
|
+2. **开放封闭**:通过事件系统支持扩展,核心逻辑保持稳定
|
|
|
+3. **模块解耦**:不依赖其他模块的具体实现
|
|
|
+4. **接口清晰**:提供简洁明确的服务接口
|
|
|
+
|
|
|
+通过以上设计,摘取功能成为农场模块的核心功能,同时为其他模块提供了丰富的扩展点。
|