Files
Sprout-Farm/Server/Feature_RemoveCrop.md

277 lines
8.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 铲除作物功能实现
## 功能概述
实现了玩家可以花费500金钱铲除地块上的作物将地块变成空地的功能。这个功能完全基于服务器端处理确保数据的一致性和安全性。
## 功能特点
- **费用固定**铲除任何作物都需要花费500金钱
- **服务器验证**:所有验证和处理都在服务器端完成
- **状态重置**:铲除后地块变成空地,可以重新种植
- **访客保护**:访客模式下无法进行铲除操作
- **实时更新**:操作完成后立即更新客户端显示
## 实现架构
### 1. 服务器端实现
#### 消息路由
```python
elif message_type == "remove_crop":
return self._handle_remove_crop(client_id, message)
```
#### 主处理方法
```python
def _handle_remove_crop(self, client_id, message):
"""处理铲除作物请求"""
# 检查用户是否已登录
logged_in, response = self._check_user_logged_in(client_id, "铲除作物", "remove_crop")
if not logged_in:
return self.send_data(client_id, response)
# 获取玩家数据
player_data, username, response = self._load_player_data_with_check(client_id, "remove_crop")
if not player_data:
return self.send_data(client_id, response)
lot_index = message.get("lot_index", -1)
# 验证地块索引
if lot_index < 0 or lot_index >= len(player_data.get("farm_lots", [])):
return self._send_action_error(client_id, "remove_crop", "无效的地块索引")
lot = player_data["farm_lots"][lot_index]
# 检查地块状态
if not lot.get("is_planted", False) or not lot.get("crop_type", ""):
return self._send_action_error(client_id, "remove_crop", "此地块没有种植作物")
# 处理铲除
return self._process_crop_removal(client_id, player_data, username, lot, lot_index)
```
#### 铲除处理逻辑
```python
def _process_crop_removal(self, client_id, player_data, username, lot, lot_index):
"""处理铲除作物逻辑"""
# 铲除费用
removal_cost = 500
# 检查玩家金钱是否足够
if player_data["money"] < removal_cost:
return self._send_action_error(client_id, "remove_crop", f"金钱不足,铲除作物需要 {removal_cost} 金钱")
# 获取作物名称用于日志
crop_type = lot.get("crop_type", "未知作物")
# 执行铲除操作
player_data["money"] -= removal_cost
lot["is_planted"] = False
lot["crop_type"] = ""
lot["grow_time"] = 0
lot["is_dead"] = False # 重置死亡状态
# 保存玩家数据
self.save_player_data(username, player_data)
# 发送作物更新
self._push_crop_update_to_player(username, player_data)
self.log('INFO', f"玩家 {username} 铲除了地块 {lot_index} 的作物 {crop_type},花费 {removal_cost} 金钱", 'SERVER')
return self.send_data(client_id, {
"type": "action_response",
"action_type": "remove_crop",
"success": True,
"message": f"成功铲除作物 {crop_type},花费 {removal_cost} 金钱",
"updated_data": {
"money": player_data["money"],
"farm_lots": player_data["farm_lots"]
}
})
```
### 2. 网络通信
#### 客户端发送请求
```gdscript
#发送铲除作物信息
func sendRemoveCrop(lot_index):
if not client.is_client_connected():
return false
client.send_data({
"type": "remove_crop",
"lot_index": lot_index,
"timestamp": Time.get_unix_time_from_system()
})
return true
```
### 3. 客户端UI实现
#### 按钮文本更新
```gdscript
# 更新按钮文本
func _update_button_texts():
dig_button.text = "开垦"+"\n花费:"+str(main_game.dig_money)
remove_button.text = "铲除"+"\n花费500"
```
#### 铲除操作处理
```gdscript
#铲除
func _on_remove_button_pressed():
# 检查是否处于访问模式
if main_game.is_visiting_mode:
Toast.show("访问模式下无法铲除作物", Color.ORANGE, 2.0, 1.0)
self.hide()
return
# 检查玩家金钱是否足够
var removal_cost = 500
if main_game.money < removal_cost:
Toast.show("金钱不足,铲除作物需要 " + str(removal_cost) + " 金钱", Color.RED, 2.0, 1.0)
self.hide()
return
# 检查地块是否有作物
var lot = main_game.farm_lots[selected_lot_index]
if not lot.get("is_planted", false) or lot.get("crop_type", "") == "":
Toast.show("此地块没有种植作物", Color.ORANGE, 2.0, 1.0)
self.hide()
return
# 发送铲除作物请求到服务器
if network_manager and network_manager.is_connected_to_server():
if network_manager.sendRemoveCrop(selected_lot_index):
Toast.show("正在铲除作物...", Color.YELLOW, 1.5, 1.0)
self.hide()
else:
Toast.show("发送铲除请求失败", Color.RED, 2.0, 1.0)
self.hide()
else:
Toast.show("网络未连接,无法铲除作物", Color.RED, 2.0, 1.0)
self.hide()
```
## 验证机制
### 服务器端验证
1. **用户登录验证**:确保用户已登录
2. **地块索引验证**:检查地块索引是否有效
3. **地块状态验证**:确保地块有作物可以铲除
4. **金钱验证**:检查玩家金钱是否足够支付铲除费用
### 客户端预验证
1. **访问模式检查**:访客模式下禁止操作
2. **金钱预检查**:提前检查金钱是否足够
3. **地块状态预检查**:确保地块有作物
4. **网络连接检查**:确保能够发送请求
## 操作流程
### 正常流程
1. 玩家点击地块,显示操作面板
2. 面板显示铲除按钮和费用信息
3. 玩家点击铲除按钮
4. 客户端进行预验证
5. 发送铲除请求到服务器
6. 服务器验证并处理请求
7. 服务器返回操作结果
8. 客户端更新UI显示
### 错误处理
- **金钱不足**:显示错误提示,不发送请求
- **无作物**:显示提示信息,不发送请求
- **访客模式**:显示权限提示,不发送请求
- **网络错误**:显示网络错误提示
- **服务器错误**:显示服务器返回的错误信息
## 数据更新
### 地块状态重置
```python
lot["is_planted"] = False # 取消种植状态
lot["crop_type"] = "" # 清空作物类型
lot["grow_time"] = 0 # 重置生长时间
lot["is_dead"] = False # 重置死亡状态
```
### 玩家数据更新
```python
player_data["money"] -= removal_cost # 扣除金钱
```
### 实时同步
- 服务器保存玩家数据到文件
- 推送作物更新到客户端
- 客户端接收并更新UI显示
## 使用场景
1. **清理死亡作物**:当作物死亡时,玩家可以花费金钱清理
2. **重新规划农场**:玩家想要种植不同作物时
3. **紧急处理**:当玩家需要快速清理地块时
4. **策略调整**:根据市场需求调整种植策略
## 安全考虑
1. **服务器权威**:所有验证和处理都在服务器端
2. **数据一致性**:确保客户端和服务器数据同步
3. **防作弊**:客户端无法直接修改游戏数据
4. **访问控制**:访客模式下无法进行破坏性操作
## 扩展性
该功能设计具有良好的扩展性:
1. **费用可配置**:可以根据作物类型设置不同的铲除费用
2. **条件扩展**:可以添加更多的铲除条件(如等级要求)
3. **奖励机制**:可以在铲除时给予部分资源回收
4. **工具系统**:可以引入铲子等工具来影响铲除效果
## 测试用例
### 测试用例1正常铲除
1. 玩家有足够金钱≥500
2. 地块有作物
3. 点击铲除按钮
4. 验证金钱减少500地块变成空地
### 测试用例2金钱不足
1. 玩家金钱不足(<500
2. 地块有作物
3. 点击铲除按钮
4. 验证:显示金钱不足提示,操作失败
### 测试用例3无作物地块
1. 玩家有足够金钱
2. 地块为空地
3. 点击铲除按钮
4. 验证:显示无作物提示,操作失败
### 测试用例4访客模式
1. 玩家处于访客模式
2. 点击铲除按钮
3. 验证:显示权限提示,操作失败
### 测试用例5网络断开
1. 网络连接断开
2. 点击铲除按钮
3. 验证:显示网络错误提示,操作失败
## 总结
铲除作物功能的实现遵循了以下设计原则:
-**服务器权威**:所有关键逻辑在服务器端处理
-**用户体验**:提供清晰的费用信息和操作反馈
-**数据安全**:多层验证确保数据完整性
-**错误处理**:完善的错误提示和处理机制
-**代码复用**:利用现有的验证和处理框架
-**可维护性**:清晰的代码结构和文档
这个功能为玩家提供了更灵活的农场管理选项,同时保持了游戏的平衡性和数据安全性。