更新三个按钮 修了一堆bug
This commit is contained in:
277
Server/Feature_RemoveCrop.md
Normal file
277
Server/Feature_RemoveCrop.md
Normal file
@@ -0,0 +1,277 @@
|
||||
# 铲除作物功能实现
|
||||
|
||||
## 功能概述
|
||||
|
||||
实现了玩家可以花费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. 验证:显示网络错误提示,操作失败
|
||||
|
||||
## 总结
|
||||
|
||||
铲除作物功能的实现遵循了以下设计原则:
|
||||
|
||||
- ✅ **服务器权威**:所有关键逻辑在服务器端处理
|
||||
- ✅ **用户体验**:提供清晰的费用信息和操作反馈
|
||||
- ✅ **数据安全**:多层验证确保数据完整性
|
||||
- ✅ **错误处理**:完善的错误提示和处理机制
|
||||
- ✅ **代码复用**:利用现有的验证和处理框架
|
||||
- ✅ **可维护性**:清晰的代码结构和文档
|
||||
|
||||
这个功能为玩家提供了更灵活的农场管理选项,同时保持了游戏的平衡性和数据安全性。
|
||||
Reference in New Issue
Block a user