Files
Sprout-Farm/Server/TCPGameServer.py
2025-06-28 14:39:37 +08:00

5775 lines
244 KiB
Python
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.
from TCPServer import TCPServer
import time
import json
import os
import glob
import threading
import datetime
import re
import random
"""
萌芽农场TCP游戏服务器 - 代码结构说明
====================================================================
📁 代码组织结构:
├── 1. 初始化和生命周期管理 - 服务器启动、停止、客户端管理
├── 2. 验证和检查方法 - 版本检查、登录状态验证
├── 3. 数据管理方法 - 玩家数据读写、缓存管理
├── 4. 作物系统管理 - 作物生长、更新推送
├── 5. 消息处理路由 - 客户端消息分发处理
├── 6. 用户认证处理 - 登录、注册、验证码
├── 7. 游戏操作处理 - 种植、收获、浇水等
├── 8. 系统功能处理 - 签到、抽奖、排行榜
└── 9. 性能优化功能 - 缓存优化、批量保存
🔧 性能优化特性:
- 内存缓存系统减少磁盘I/O操作
- 分层更新策略:在线玩家快速更新,离线玩家慢速更新
- 批量数据保存:定时批量写入,提升性能
- 智能缓存管理LRU策略自动清理过期数据
🎮 游戏功能模块:
- 用户系统:注册、登录、邮箱验证
- 农场系统:种植、收获、浇水、施肥
- 升级系统:经验获取、等级提升
- 社交系统:访问农场、点赞互动
- 奖励系统:每日签到、幸运抽奖
- 排行系统:玩家排行榜展示
📊 数据存储:
- 玩家数据JSON格式存储在game_saves目录
- 配置文件:作物数据、初始模板等
- 缓存策略:内存缓存 + 定时持久化
🌐 网络通信:
- 协议TCP长连接
- 数据格式JSON消息
- 消息类型:请求/响应模式
====================================================================
"""
# ============================================================================
# 服务器配置参数
# ============================================================================
server_host: str = "0.0.0.0"
server_port: int = 4040
buffer_size: int = 4096
server_version: str = "1.0.5"
# ============================================================================
# TCP游戏服务器类
# ============================================================================
class TCPGameServer(TCPServer):
"""
萌芽农场TCP游戏服务器
"""
#==========================初始化和生命周期管理==========================
#初始化操作
def __init__(self, server_host=server_host, server_port=server_port, buffer_size=buffer_size):
"""初始化TCP游戏服务器"""
super().__init__(server_host, server_port, buffer_size)
# 基础数据存储
self.user_data = {} # 存储用户相关数据
self.crop_timer = None # 作物生长计时器
self.weed_timer = None # 杂草生长计时器
# 性能优化相关配置
self._init_performance_settings()
self.log('INFO', f"萌芽农场TCP游戏服务器初始化完成 - 版本: {server_version}", 'SERVER')
# 启动定时器
self.start_crop_growth_timer()
self.start_batch_save_timer()
self.start_weed_growth_timer()
#初始化性能操作
def _init_performance_settings(self):
"""初始化性能优化配置"""
self.player_cache = {} # 玩家数据内存缓存
self.dirty_players = set() # 需要保存到磁盘的玩家列表
self.last_save_time = time.time() # 上次批量保存时间
self.save_interval = 30 # 批量保存间隔(秒)
self.update_counter = 0 # 更新计数器
self.slow_update_interval = 10 # 慢速更新间隔每10秒进行一次完整更新
self.active_players_cache = {} # 活跃玩家缓存
self.cache_expire_time = 300 # 缓存过期时间5分钟
# 杂草生长相关配置
self.weed_check_interval = 86400 # 杂草检查间隔24小时
self.offline_threshold_days = 3 # 离线多少天后开始长杂草
self.max_weeds_per_check = 3 # 每次检查时最多长多少个杂草
self.weed_growth_probability = 0.3 # 每个空地长杂草的概率30%
self.last_weed_check_time = time.time() # 上次检查杂草的时间
#启动作物生长计时器
def start_crop_growth_timer(self):
"""启动作物生长计时器,每秒更新一次"""
try:
self.update_crops_growth_optimized()
except Exception as e:
self.log('ERROR', f"作物生长更新时出错: {str(e)}", 'SERVER')
# 创建下一个计时器
self.crop_timer = threading.Timer(1.0, self.start_crop_growth_timer)
self.crop_timer.daemon = True
self.crop_timer.start()
#启动批量报错计时器
def start_batch_save_timer(self):
"""启动批量保存计时器"""
try:
self.batch_save_dirty_players()
self.cleanup_expired_cache()
except Exception as e:
self.log('ERROR', f"批量保存时出错: {str(e)}", 'SERVER')
# 创建下一个批量保存计时器
batch_timer = threading.Timer(self.save_interval, self.start_batch_save_timer)
batch_timer.daemon = True
batch_timer.start()
#启动杂草生长计时器
def start_weed_growth_timer(self):
"""启动杂草生长计时器,每天检查一次"""
try:
current_time = time.time()
# 检查是否到了杂草检查时间
if current_time - self.last_weed_check_time >= self.weed_check_interval:
self.check_and_grow_weeds()
self.last_weed_check_time = current_time
except Exception as e:
self.log('ERROR', f"杂草生长检查时出错: {str(e)}", 'SERVER')
# 创建下一个杂草检查计时器(每小时检查一次是否到时间)
self.weed_timer = threading.Timer(3600, self.start_weed_growth_timer) # 每小时检查一次
self.weed_timer.daemon = True
self.weed_timer.start()
#获取服务器统计信息
def get_server_stats(self):
"""获取服务器统计信息"""
online_players = len([cid for cid in self.user_data if self.user_data[cid].get("logged_in", False)])
return {
"cached_players": len(self.player_cache),
"online_players": online_players,
"total_connections": len(self.clients)
}
#停止服务器
def stop(self):
"""停止服务器"""
self.log('INFO', "正在停止服务器...", 'SERVER')
# 停止作物生长计时器
if self.crop_timer:
self.crop_timer.cancel()
self.crop_timer = None
self.log('INFO', "作物生长计时器已停止", 'SERVER')
# 停止杂草生长计时器
if hasattr(self, 'weed_timer') and self.weed_timer:
self.weed_timer.cancel()
self.weed_timer = None
self.log('INFO', "杂草生长计时器已停止", 'SERVER')
# 强制保存所有缓存数据
self.log('INFO', "正在保存所有玩家数据...", 'SERVER')
saved_count = self.force_save_all_data()
self.log('INFO', f"已保存 {saved_count} 个玩家的数据", 'SERVER')
# 显示服务器统计信息
stats = self.get_server_stats()
self.log('INFO', f"服务器统计 - 缓存玩家: {stats['cached_players']}, 在线玩家: {stats['online_players']}, 总连接: {stats['total_connections']}", 'SERVER')
# 调用父类方法完成实际停止
super().stop()
#==========================初始化和生命周期管理==========================
#==========================客户端连接管理==========================
#移除客户端
def _remove_client(self, client_id):
"""覆盖客户端移除方法,添加用户离开通知和数据保存"""
if client_id in self.clients:
username = self.user_data.get(client_id, {}).get("username", client_id)
# 处理已登录用户的离开
if client_id in self.user_data and self.user_data[client_id].get("logged_in", False):
self._update_player_logout_time(client_id, username)
# 立即保存离线玩家的数据
if username and username in self.player_cache:
self.save_player_data_immediate(username)
self.dirty_players.discard(username)
self.log('INFO', f"已立即保存离线玩家 {username} 的数据", 'SERVER')
self.log('INFO', f"用户 {username} 登出", 'SERVER')
# 广播用户离开消息
self.broadcast({
"type": "user_left",
"user_id": client_id,
"timestamp": time.time(),
"remaining_users": len(self.clients) - 1
}, exclude=[client_id])
# 清理用户数据
if client_id in self.user_data:
del self.user_data[client_id]
self.log('INFO', f"用户 {username} 已离开游戏", 'SERVER')
super()._remove_client(client_id)
#==========================客户端连接管理==========================
#==========================验证和检查方法==========================
#检查用户是否已登录的通用方法
def _check_user_logged_in(self, client_id, action_name, action_type=None):
"""检查用户是否已登录的通用方法"""
if client_id not in self.user_data or not self.user_data[client_id].get("logged_in", False):
self.log('WARNING', f"未登录用户 {client_id} 尝试{action_name}", 'SERVER')
response = {
"success": False,
"message": "您需要先登录才能执行此操作"
}
if action_type:
response["type"] = "action_response"
response["action_type"] = action_type
else:
response["type"] = f"{action_name}_response"
return False, response
return True, None
#==========================验证和检查方法==========================
#=================================数据管理方法====================================
#加载玩家数据
def load_player_data(self, account_id):
"""从缓存或文件加载玩家数据(优化版本)"""
# 先检查内存缓存
if account_id in self.player_cache:
self._update_cache_access_time(account_id)
return self.player_cache[account_id]
# 缓存未命中,从文件读取
return self._load_player_data_from_file(account_id)
#更新缓存访问时间
def _update_cache_access_time(self, account_id):
"""更新缓存访问时间"""
if account_id not in self.active_players_cache:
self.active_players_cache[account_id] = {}
self.active_players_cache[account_id]["last_access"] = time.time()
#从文件里加载玩家数据
def _load_player_data_from_file(self, account_id):
"""从文件加载玩家数据"""
file_path = os.path.join("game_saves", f"{account_id}.json")
try:
if os.path.exists(file_path):
with open(file_path, 'r', encoding='utf-8') as file:
player_data = json.load(file)
# 存入缓存
self.player_cache[account_id] = player_data
self.active_players_cache[account_id] = {
"last_access": time.time(),
"is_online": account_id in self.user_data and self.user_data[account_id].get("logged_in", False)
}
return player_data
return None
except Exception as e:
self.log('ERROR', f"读取玩家 {account_id} 的数据时出错: {str(e)}", 'SERVER')
return None
#保存玩家数据到缓存
def save_player_data(self, account_id, player_data):
"""保存玩家数据到缓存"""
# 更新内存缓存
self.player_cache[account_id] = player_data
# 标记为脏数据,等待批量保存
self.dirty_players.add(account_id)
# 更新活跃缓存
self._update_cache_access_time(account_id)
return True
#保存玩家数据到磁盘
def save_player_data_immediate(self, account_id):
"""立即保存玩家数据到磁盘"""
if account_id not in self.player_cache:
return False
file_path = os.path.join("game_saves", f"{account_id}.json")
try:
with open(file_path, 'w', encoding='utf-8') as file:
json.dump(self.player_cache[account_id], file, indent=2, ensure_ascii=False)
return True
except Exception as e:
self.log('ERROR', f"保存玩家 {account_id} 的数据时出错: {str(e)}", 'SERVER')
return False
#加载玩家数据
def _load_player_data_with_check(self, client_id, action_type=None):
"""加载玩家数据并进行错误检查的通用方法"""
username = self.user_data[client_id]["username"]
player_data = self.load_player_data(username)
if not player_data:
self.log('ERROR', f"无法加载玩家 {username} 的数据", 'SERVER')
response = {
"success": False,
"message": "无法加载玩家数据"
}
if action_type:
response["type"] = "action_response"
response["action_type"] = action_type
else:
response["type"] = "data_response"
return None, username, response
return player_data, username, None
#加载作物配置数据
def _load_crop_data(self):
"""加载作物配置数据"""
try:
with open("config/crop_data.json", 'r', encoding='utf-8') as file:
return json.load(file)
except Exception as e:
self.log('ERROR', f"无法加载作物数据: {str(e)}", 'SERVER')
return {}
#更新玩家登录时间
def _update_player_logout_time(self, client_id, username):
"""更新玩家登出时间和总游玩时间"""
login_timestamp = self.user_data[client_id].get("login_timestamp", time.time())
play_time_seconds = int(time.time() - login_timestamp)
# 清除访问状态
self.user_data[client_id]["visiting_mode"] = False
self.user_data[client_id]["visiting_target"] = ""
# 加载和更新玩家数据
player_data = self.load_player_data(username)
if player_data:
# 更新总游玩时间
self._update_total_play_time(player_data, play_time_seconds)
# 更新今日在线礼包累计时间
current_date = datetime.datetime.now().strftime("%Y-%m-%d")
online_gift_data = player_data.get("online_gift", {})
if current_date in online_gift_data:
today_data = online_gift_data[current_date]
today_data["total_online_time"] = today_data.get("total_online_time", 0.0) + play_time_seconds
player_data["online_gift"] = online_gift_data
self.save_player_data(username, player_data)
self.log('INFO', f"用户 {username} 本次游玩时间: {play_time_seconds} 秒,总游玩时间: {player_data['total_login_time']}", 'SERVER')
#更新总游玩时间
def _update_total_play_time(self, player_data, play_time_seconds):
"""更新总游玩时间"""
total_time_str = player_data.get("total_login_time", "0时0分0秒")
time_parts = re.match(r"(?:(\d+)时)?(?:(\d+)分)?(?:(\d+)秒)?", total_time_str)
if time_parts:
hours = int(time_parts.group(1) or 0)
minutes = int(time_parts.group(2) or 0)
seconds = int(time_parts.group(3) or 0)
# 计算新的总游玩时间
total_seconds = hours * 3600 + minutes * 60 + seconds + play_time_seconds
new_hours = total_seconds // 3600
new_minutes = (total_seconds % 3600) // 60
new_seconds = total_seconds % 60
# 更新总游玩时间
player_data["total_login_time"] = f"{new_hours}{new_minutes}{new_seconds}"
# 检查玩家是否享受新玩家注册奖励
def _is_new_player_bonus_active(self, player_data):
"""检查玩家是否在新玩家奖励期内注册后3天内享受10倍生长速度"""
register_time_str = player_data.get("注册时间", "")
# 如果没有注册时间或者是默认的老玩家时间,则不享受奖励
if not register_time_str or register_time_str == "2025年05月21日15时00分00秒":
return False
try:
# 解析注册时间
register_time = datetime.datetime.strptime(register_time_str, "%Y年%m月%d%H时%M分%S秒")
current_time = datetime.datetime.now()
# 计算注册天数
time_diff = current_time - register_time
days_since_register = time_diff.total_seconds() / 86400 # 转换为天数
# 3天内享受新玩家奖励
if days_since_register <= 3:
return True
else:
return False
except ValueError as e:
self.log('WARNING', f"解析注册时间格式错误: {register_time_str}, 错误: {str(e)}", 'SERVER')
return False
#=================================数据管理方法====================================
#================================作物系统管理=========================================
#优化的作物生长更新系统
def update_crops_growth_optimized(self):
"""优化的作物生长更新系统"""
self.update_counter += 1
# 每秒快速更新在线玩家
self.update_online_players_crops()
# 每10秒进行一次慢速更新离线玩家和深度检查
if self.update_counter % self.slow_update_interval == 0:
self.update_offline_players_crops()
#快速更新在线玩家的作物
def update_online_players_crops(self):
"""快速更新在线玩家的作物"""
for client_id, user_info in self.user_data.items():
if not user_info.get("logged_in", False):
continue
username = user_info.get("username")
if not username:
continue
try:
player_data = self.load_player_data(username)
if not player_data:
continue
if self.update_player_crops_fast(player_data, username):
self.save_player_data(username, player_data)
self._push_crop_update_to_player(username, player_data)
except Exception as e:
self.log('ERROR', f"快速更新在线玩家 {username} 作物时出错: {str(e)}", 'SERVER')
#慢速更新离线玩家的作物
def update_offline_players_crops(self):
"""慢速更新离线玩家的作物每10秒一次"""
import glob
try:
save_files = glob.glob(os.path.join("game_saves", "*.json"))
offline_count = 0
updated_count = 0
for save_file in save_files:
account_id = os.path.basename(save_file).split('.')[0]
# 跳过在线玩家
is_online = any(
user_info.get("username") == account_id and user_info.get("logged_in", False)
for user_info in self.user_data.values()
)
if is_online:
continue
offline_count += 1
player_data = self.load_player_data(account_id)
if not player_data:
continue
if self.update_player_crops_slow(player_data, account_id):
self.save_player_data(account_id, player_data)
updated_count += 1
if updated_count > 0:
self.log('INFO', f"慢速更新:检查了 {offline_count} 个离线玩家,更新了 {updated_count}", 'SERVER')
except Exception as e:
self.log('ERROR', f"慢速更新离线玩家作物时出错: {str(e)}", 'SERVER')
#快速更新单个玩家的作物
def update_player_crops_fast(self, player_data, account_id):
"""快速更新单个玩家的作物(在线玩家用)"""
return self.update_player_crops_common(player_data, account_id, 1)
#慢速更新单个玩家的作物
def update_player_crops_slow(self, player_data, account_id):
"""慢速更新单个玩家的作物(离线玩家用,补偿倍数)"""
return self.update_player_crops_common(player_data, account_id, self.slow_update_interval)
#通用的作物更新逻辑
def update_player_crops_common(self, player_data, account_id, time_multiplier):
"""通用的作物更新逻辑"""
growth_updated = False
for farm_lot in player_data.get("farm_lots", []):
if (farm_lot.get("crop_type") and farm_lot.get("is_planted") and
not farm_lot.get("is_dead") and farm_lot["grow_time"] < farm_lot["max_grow_time"]):
# 计算生长速度倍数
growth_multiplier = 1.0
# 新玩家注册奖励注册后3天内享受10倍生长速度
if self._is_new_player_bonus_active(player_data):
growth_multiplier *= 10.0
# 土地等级影响 - 根据不同等级应用不同倍数
land_level = farm_lot.get("土地等级", 0)
land_speed_multipliers = {
0: 1.0, # 默认土地:正常生长速度
1: 2.0, # 黄土地2倍速
2: 4.0, # 红土地4倍速
3: 6.0, # 紫土地6倍速
4: 10.0 # 黑土地10倍速
}
growth_multiplier *= land_speed_multipliers.get(land_level, 1.0)
# 施肥影响 - 支持不同类型的道具施肥
if farm_lot.get("已施肥", False) and "施肥时间" in farm_lot:
fertilize_time = farm_lot.get("施肥时间", 0)
current_time = time.time()
# 获取施肥类型和对应的持续时间、倍数
fertilize_type = farm_lot.get("施肥类型", "普通施肥")
fertilize_duration = farm_lot.get("施肥持续时间", 600) # 默认10分钟
fertilize_multiplier = farm_lot.get("施肥倍数", 2.0) # 默认2倍速
if current_time - fertilize_time <= fertilize_duration:
# 施肥效果仍在有效期内
growth_multiplier *= fertilize_multiplier
else:
# 施肥效果过期,清除施肥状态
farm_lot["已施肥"] = False
if "施肥时间" in farm_lot:
del farm_lot["施肥时间"]
if "施肥类型" in farm_lot:
del farm_lot["施肥类型"]
if "施肥倍数" in farm_lot:
del farm_lot["施肥倍数"]
if "施肥持续时间" in farm_lot:
del farm_lot["施肥持续时间"]
# 应用生长速度倍数和时间补偿
growth_increase = int(growth_multiplier * time_multiplier)
if growth_increase < 1:
growth_increase = 1
farm_lot["grow_time"] += growth_increase
growth_updated = True
return growth_updated
#向在线玩家推送作物生长更新
def _push_crop_update_to_player(self, account_id, player_data):
"""向在线玩家推送作物生长更新"""
client_id = self._find_client_by_username(account_id)
if client_id:
visiting_mode = self.user_data[client_id].get("visiting_mode", False)
visiting_target = self.user_data[client_id].get("visiting_target", "")
if visiting_mode and visiting_target:
self._send_visiting_update(client_id, visiting_target)
else:
self._send_normal_update(client_id, player_data)
#根据用户名查找客户端ID
def _find_client_by_username(self, username):
"""根据用户名查找客户端ID"""
for cid, user_info in self.user_data.items():
if user_info.get("username") == username and user_info.get("logged_in", False):
return cid
return None
#发送访问模式的更新
def _send_visiting_update(self, client_id, visiting_target):
"""发送访问模式的更新"""
target_player_data = self.load_player_data(visiting_target)
if target_player_data:
target_client_id = self._find_client_by_username(visiting_target)
update_message = {
"type": "crop_update",
"farm_lots": target_player_data.get("farm_lots", []),
"timestamp": time.time(),
"is_visiting": True,
"visited_player": visiting_target,
"target_online": target_client_id is not None
}
self.send_data(client_id, update_message)
#发送正常模式的更新
def _send_normal_update(self, client_id, player_data):
"""发送正常模式的更新"""
update_message = {
"type": "crop_update",
"farm_lots": player_data.get("farm_lots", []),
"timestamp": time.time(),
"is_visiting": False
}
self.send_data(client_id, update_message)
#================================作物系统管理=========================================
# =======================服务端与客户端通信注册==========================================
#服务端与客户端通用消息处理-这个是服务端与客户端通信的核心中的核心
def _handle_message(self, client_id, message):
"""接收客户端消息并路由到对应处理函数"""
message_type = message.get("type", "")
# 用户认证相关
if message_type == "greeting":#默认欢迎
return self._handle_greeting(client_id, message)
elif message_type == "login":#玩家登录
return self._handle_login(client_id, message)
elif message_type == "register":#玩家注册
return self._handle_register(client_id, message)
elif message_type == "request_verification_code":#验证码请求
return self._handle_verification_code_request(client_id, message)
elif message_type == "verify_code":#验证码
return self._handle_verify_code(client_id, message)
#---------------------------------------------------------------------------
# 游戏操作相关
elif message_type == "harvest_crop":#收获作物
return self._handle_harvest_crop(client_id, message)
elif message_type == "plant_crop":#种植作物
return self._handle_plant_crop(client_id, message)
elif message_type == "buy_seed":#购买种子
return self._handle_buy_seed(client_id, message)
elif message_type == "buy_item":#购买道具
return self._handle_buy_item(client_id, message)
elif message_type == "dig_ground":#开垦土地
return self._handle_dig_ground(client_id, message)
elif message_type == "remove_crop":#铲除作物
return self._handle_remove_crop(client_id, message)
elif message_type == "water_crop":#浇水
return self._handle_water_crop(client_id, message)
elif message_type == "fertilize_crop":#施肥
return self._handle_fertilize_crop(client_id, message)
elif message_type == "use_item":#使用道具
return self._handle_use_item(client_id, message)
elif message_type == "upgrade_land":#升级土地
return self._handle_upgrade_land(client_id, message)
elif message_type == "buy_new_ground":#添加新的土地
return self._handle_buy_new_ground(client_id, message)
elif message_type == "like_player":#点赞玩家
return self._handle_like_player(client_id, message)
elif message_type == "request_online_players":#请求在线玩家
return self._handle_online_players_request(client_id, message)
elif message_type == "get_play_time":#获取游玩时间
return self._handle_get_play_time(client_id)
elif message_type == "update_play_time":#更新游玩时间
return self._handle_update_play_time(client_id)
elif message_type == "request_player_rankings":#请求玩家排行榜
return self._handle_player_rankings_request(client_id, message)
elif message_type == "request_crop_data":#请求作物数据
return self._handle_crop_data_request(client_id)
elif message_type == "visit_player":#拜访其他玩家农场
return self._handle_visit_player_request(client_id, message)
elif message_type == "return_my_farm":#返回我的农场
return self._handle_return_my_farm_request(client_id, message)
elif message_type == "daily_check_in":#每日签到
return self._handle_daily_check_in_request(client_id, message)
elif message_type == "get_check_in_data":#获取签到数据
return self._handle_get_check_in_data_request(client_id, message)
elif message_type == "lucky_draw":#幸运抽奖
return self._handle_lucky_draw_request(client_id, message)
elif message_type == "claim_new_player_gift":#领取新手大礼包
return self._handle_new_player_gift_request(client_id, message)
elif message_type == "get_online_gift_data":#获取在线礼包数据
return self._handle_get_online_gift_data_request(client_id, message)
elif message_type == "claim_online_gift":#领取在线礼包
return self._handle_claim_online_gift_request(client_id, message)
elif message_type == "ping":#客户端ping请求
return self._handle_ping_request(client_id, message)
elif message_type == "modify_account_info":#修改账号信息
return self._handle_modify_account_info_request(client_id, message)
elif message_type == "delete_account":#删除账号
return self._handle_delete_account_request(client_id, message)
elif message_type == "refresh_player_info":#刷新玩家信息
return self._handle_refresh_player_info_request(client_id, message)
#---------------------------------------------------------------------------
elif message_type == "message":#处理聊天消息(暂未实现)
return self._handle_chat_message(client_id, message)
else:
return super()._handle_message(client_id, message)
# =======================服务端与客户端通信注册==========================================
#==========================用户认证相关==========================
#处理问候消息
def _handle_greeting(self, client_id, message):
"""处理问候消息"""
content = message.get("content", "")
self.log('INFO', f"收到来自客户端 {client_id} 的问候: {content}", 'CLIENT')
# 保存用户会话信息
self.user_data[client_id] = {
"last_active": time.time(),
"messages_count": 0
}
# 回复欢迎消息
response = {
"type": "greeting_response",
"content": f"欢迎 {client_id}!",
"server_time": time.time(),
"active_users": len(self.clients)
}
# 通知其他用户有新用户加入
self.broadcast(
{
"type": "user_joined",
"user_id": client_id,
"timestamp": time.time(),
"active_users": len(self.clients)
},
exclude=[client_id]
)
self.log('INFO', f"用户 {client_id} 已加入游戏", 'SERVER')
return self.send_data(client_id, response)
#处理玩家登录
def _handle_login(self, client_id, message):
"""处理登录消息"""
username = message.get("username", "")
password = message.get("password", "")
client_version = message.get("client_version", "")
# 验证客户端版本
version_valid, version_response = self._check_client_version(client_version, f"用户 {username} 登录")
if not version_valid:
version_response["type"] = "login_response"
version_response["status"] = "failed"
return self.send_data(client_id, version_response)
# 读取玩家数据
player_data = self.load_player_data(username)
if player_data and player_data.get("user_password") == password:
# 登录成功
self.log('INFO', f"用户 {username} 登录成功", 'SERVER')
# 更新最后登录时间
current_time = datetime.datetime.now()
player_data["last_login_time"] = current_time.strftime("%Y年%m月%d%H时%M分%S秒")
# 检查并更新体力值
stamina_updated = self._check_and_update_stamina(player_data)
if stamina_updated:
self.log('INFO', f"玩家 {username} 体力值已更新:{player_data.get('体力值', 20)}", 'SERVER')
# 检查并更新已存在玩家的注册时间
self._check_and_update_register_time(player_data, username)
# 初始化今日在线礼包数据
current_date = datetime.datetime.now().strftime("%Y-%m-%d")
if "online_gift" not in player_data:
player_data["online_gift"] = {}
online_gift_data = player_data["online_gift"]
if current_date not in online_gift_data:
online_gift_data[current_date] = {
"start_time": time.time(),
"claimed_gifts": {}
}
self.log('INFO', f"玩家 {username} 初始化今日在线礼包数据", 'SERVER')
# 保存用户会话信息
self.user_data[client_id] = {
"username": username,
"last_active": time.time(),
"messages_count": 0,
"logged_in": True,
"login_timestamp": time.time()
}
# 保存更新后的玩家数据
self.save_player_data(username, player_data)
# 发送初始数据
self._send_initial_login_data(client_id, player_data)
# 返回登录成功消息
response = {
"type": "login_response",
"status": "success",
"message": "登录成功",
"player_data": player_data
}
else:
# 登录失败
self.log('WARNING', f"用户 {username} 登录失败: 账号或密码错误", 'SERVER')
response = {
"type": "login_response",
"status": "failed",
"message": "账号或密码错误"
}
return self.send_data(client_id, response)
#辅助函数-发送登录后初始数据
def _send_initial_login_data(self, client_id, player_data):
"""发送登录后的初始数据"""
# 立即向客户端发送一次作物状态
farm_lots = player_data.get("farm_lots", [])
initial_crop_update = {
"type": "crop_update",
"farm_lots": farm_lots,
"timestamp": time.time()
}
self.send_data(client_id, initial_crop_update)
# 发送最新的作物数据配置
crop_data = self._load_crop_data()
if crop_data:
crop_data_message = {
"type": "crop_data_response",
"success": True,
"crop_data": crop_data
}
self.send_data(client_id, crop_data_message)
self.log('INFO', f"已向登录用户发送作物数据配置", 'SERVER')
#处理注册消息
def _handle_register(self, client_id, message):
"""处理注册消息"""
username = message.get("username", "")
password = message.get("password", "")
farm_name = message.get("farm_name", "")
player_name = message.get("player_name", "")
verification_code = message.get("verification_code", "")
client_version = message.get("client_version", "")
# 验证客户端版本
version_valid, version_response = self._check_client_version(client_version, f"用户 {username} 注册")
if not version_valid:
version_response["type"] = "register_response"
version_response["status"] = "failed"
return self.send_data(client_id, version_response)
# 验证必填字段
if not username or not password:
return self._send_register_error(client_id, "用户名或密码不能为空")
# 验证用户名是否是QQ号
if not self._validate_qq_number(username):
return self._send_register_error(client_id, "用户名必须是5-12位的QQ号码")
# 验证验证码
if verification_code:
from QQEmailSend import EmailVerification
success, verify_message = EmailVerification.verify_code(username, verification_code)
if not success:
return self._send_register_error(client_id, f"验证码错误: {verify_message}")
# 检查用户是否已存在
file_path = os.path.join("game_saves", f"{username}.json")
if os.path.exists(file_path):
return self._send_register_error(client_id, "该用户名已被注册")
# 创建新用户
return self._create_new_user(client_id, username, password, farm_name, player_name)
#检查客户端版本是否与服务端匹配
#创建新用户
#辅助函数-发送注册错误处理
def _send_register_error(self, client_id, message):
"""发送注册错误响应"""
self.log('WARNING', f"注册失败: {message}", 'SERVER')
return self.send_data(client_id, {
"type": "register_response",
"status": "failed",
"message": message
})
#辅助函数-创建新用户
def _create_new_user(self, client_id, username, password, farm_name, player_name):
"""创建新用户"""
try:
# 从模板加载初始玩家数据
template_path = os.path.join("config", "initial_player_data_template.json")
if not os.path.exists(template_path):
return self._send_register_error(client_id, "服务器配置错误,无法注册新用户")
with open(template_path, 'r', encoding='utf-8') as file:
player_data = json.load(file)
# 更新玩家数据
player_data.update({
"user_name": username,
"user_password": password,
"farm_name": farm_name or "我的农场",
"player_name": player_name or username,
"个人简介": "", # 新增个人简介字段,默认为空
"experience": player_data.get("experience", 0),
"level": player_data.get("level", 1),
"money": player_data.get("money", 1000)
})
# 确保农场地块存在
if "farm_lots" not in player_data:
player_data["farm_lots"] = []
for i in range(40):
player_data["farm_lots"].append({
"crop_type": "",
"grow_time": 0,
"is_dead": False,
"is_diged": i < 5, # 默认开垦前5块地
"is_planted": False,
"max_grow_time": 5 if i >= 5 else 3
})
if "player_bag" not in player_data:
player_data["player_bag"] = []
# 更新注册时间和登录时间
current_time = datetime.datetime.now()
time_str = current_time.strftime("%Y年%m月%d%H时%M分%S秒")
player_data["last_login_time"] = time_str
# 设置新玩家的注册时间(不同于模板中的默认时间)
player_data["注册时间"] = time_str
if "total_login_time" not in player_data:
player_data["total_login_time"] = "0时0分0秒"
# 保存新用户数据
file_path = os.path.join("game_saves", f"{username}.json")
with open(file_path, 'w', encoding='utf-8') as file:
json.dump(player_data, file, indent=2, ensure_ascii=False)
self.log('INFO', f"用户 {username} 注册成功,注册时间: {time_str}享受3天新玩家10倍生长速度奖励", 'SERVER')
# 返回成功响应
return self.send_data(client_id, {
"type": "register_response",
"status": "success",
"message": "注册成功请登录游戏新玩家享受3天10倍作物生长速度奖励"
})
except Exception as e:
self.log('ERROR', f"注册用户 {username} 时出错: {str(e)}", 'SERVER')
return self._send_register_error(client_id, f"注册过程中出现错误: {str(e)}")
#辅助函数-客户端版本检查
def _check_client_version(self, client_version, action_name="操作"):
"""检查客户端版本是否与服务端匹配"""
if client_version != server_version:
self.log('WARNING', f"{action_name}失败: 版本不匹配 (客户端: {client_version}, 服务端: {server_version})", 'SERVER')
response = {
"success": False,
"message": f"版本不匹配!客户端版本: {client_version},\n 服务端版本: {server_version},请更新客户端"
}
return False, response
return True, None
#处理验证码请求
def _handle_verification_code_request(self, client_id, message):
"""处理验证码请求"""
from QQEmailSend import EmailVerification
qq_number = message.get("qq_number", "")
# 验证QQ号
if not self._validate_qq_number(qq_number):
return self.send_data(client_id, {
"type": "verification_code_response",
"success": False,
"message": "QQ号格式无效请输入5-12位数字"
})
# 生成验证码
verification_code = EmailVerification.generate_verification_code()
# 发送验证码邮件
success, send_message = EmailVerification.send_verification_email(qq_number, verification_code)
if success:
# 保存验证码
EmailVerification.save_verification_code(qq_number, verification_code)
self.log('INFO', f"已向QQ号 {qq_number} 发送验证码", 'SERVER')
return self.send_data(client_id, {
"type": "verification_code_response",
"success": True,
"message": "验证码已发送到您的QQ邮箱请查收"
})
else:
self.log('ERROR', f"发送验证码失败: {send_message}", 'SERVER')
return self.send_data(client_id, {
"type": "verification_code_response",
"success": False,
"message": f"发送验证码失败: {send_message}"
})
#处理验证码验证
def _handle_verify_code(self, client_id, message):
"""处理验证码验证"""
from QQEmailSend import EmailVerification
qq_number = message.get("qq_number", "")
input_code = message.get("code", "")
if not input_code:
return self.send_data(client_id, {
"type": "verify_code_response",
"success": False,
"message": "验证码不能为空"
})
# 验证验证码
success, verify_message = EmailVerification.verify_code(qq_number, input_code)
if success:
self.log('INFO', f"QQ号 {qq_number} 的验证码验证成功", 'SERVER')
return self.send_data(client_id, {
"type": "verify_code_response",
"success": True,
"message": "验证成功"
})
else:
self.log('WARNING', f"QQ号 {qq_number} 的验证码验证失败: {verify_message}", 'SERVER')
return self.send_data(client_id, {
"type": "verify_code_response",
"success": False,
"message": verify_message
})
#验证QQ号格式
#辅助函数-验证QQ号格式
def _validate_qq_number(self, qq_number):
"""验证QQ号格式"""
return re.match(r'^\d{5,12}$', qq_number) is not None
#==========================用户认证相关==========================
#==========================收获作物处理==========================
#处理收获作物请求
def _handle_harvest_crop(self, client_id, message):
"""处理收获作物请求"""
# 检查用户是否已登录
logged_in, response = self._check_user_logged_in(client_id, "收获作物", "harvest_crop")
if not logged_in:
return self.send_data(client_id, response)
# 获取当前操作用户的数据
current_player_data, current_username, response = self._load_player_data_with_check(client_id, "harvest_crop")
if not current_player_data:
return self.send_data(client_id, response)
lot_index = message.get("lot_index", -1)
target_username = message.get("target_username", "")
# 确定操作目标如果有target_username就是访问模式偷菜否则是自己的农场
if target_username and target_username != current_username:
# 访问模式:偷菜(收益给自己,清空目标玩家的作物)
target_player_data = self.load_player_data(target_username)
if not target_player_data:
return self._send_action_error(client_id, "harvest_crop", f"无法找到玩家 {target_username} 的数据")
# 验证地块索引
if lot_index < 0 or lot_index >= len(target_player_data.get("farm_lots", [])):
return self._send_action_error(client_id, "harvest_crop", "无效的地块索引")
target_lot = target_player_data["farm_lots"][lot_index]
# 检查地块状态
if not target_lot.get("is_planted", False) or not target_lot.get("crop_type", ""):
return self._send_action_error(client_id, "harvest_crop", "此地块没有种植作物")
if target_lot.get("is_dead", False):
# 处理已死亡的作物(只清理,不给收益)
target_lot["is_planted"] = False
target_lot["crop_type"] = ""
target_lot["grow_time"] = 0
self.save_player_data(target_username, target_player_data)
self._push_crop_update_to_player(target_username, target_player_data)
return self.send_data(client_id, {
"type": "action_response",
"action_type": "harvest_crop",
"success": True,
"message": f"已帮助 {target_username} 清理死亡的作物",
"updated_data": {
"money": current_player_data["money"],
"experience": current_player_data["experience"],
"level": current_player_data["level"]
}
})
if target_lot["grow_time"] < target_lot["max_grow_time"]:
return self._send_action_error(client_id, "harvest_crop", "作物尚未成熟,无法偷菜")
# 处理偷菜
return self._process_steal_crop(client_id, current_player_data, current_username, target_player_data, target_username, target_lot, lot_index)
else:
# 正常模式:收获自己的作物
# 验证地块索引
if lot_index < 0 or lot_index >= len(current_player_data.get("farm_lots", [])):
return self._send_action_error(client_id, "harvest_crop", "无效的地块索引")
lot = current_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, "harvest_crop", "此地块没有种植作物")
if lot.get("is_dead", False):
# 处理已死亡的作物
lot["is_planted"] = False
lot["crop_type"] = ""
lot["grow_time"] = 0
self.save_player_data(current_username, current_player_data)
self._push_crop_update_to_player(current_username, current_player_data)
return self.send_data(client_id, {
"type": "action_response",
"action_type": "harvest_crop",
"success": True,
"message": "已铲除死亡的作物",
"updated_data": {
"money": current_player_data["money"],
"experience": current_player_data["experience"],
"level": current_player_data["level"]
}
})
if lot["grow_time"] < lot["max_grow_time"]:
return self._send_action_error(client_id, "harvest_crop", "作物尚未成熟")
# 处理正常收获
return self._process_harvest(client_id, current_player_data, current_username, lot, lot_index)
#辅助函数-处理作物收获
def _process_harvest(self, client_id, player_data, username, lot, lot_index):
"""处理作物收获逻辑"""
# 读取作物配置
crop_data = self._load_crop_data()
# 获取作物类型和经验
crop_type = lot["crop_type"]
# 检查是否为杂草类型(杂草不能收获,只能铲除)
if crop_type in crop_data:
crop_info = crop_data[crop_type]
is_weed = crop_info.get("是否杂草", False)
if is_weed:
return self._send_action_error(client_id, "harvest_crop", f"{crop_type}不能收获,只能铲除!请使用铲除功能清理杂草。")
crop_exp = crop_info.get("经验", 10)
# 额外检查:如果作物收益为负数,也视为杂草
crop_income = crop_info.get("收益", 100) + crop_info.get("花费", 0)
if crop_income < 0:
return self._send_action_error(client_id, "harvest_crop", f"{crop_type}不能收获,只能铲除!请使用铲除功能清理杂草。")
else:
# 默认经验
crop_exp = 10
# 生成成熟物收获1-5个
import random
harvest_count = random.randint(1, 5)
crop_harvest = {
"name": crop_type,
"count": harvest_count
}
# 10%概率获得1-2个该作物的种子
seed_reward = self._generate_harvest_seed_reward(crop_type)
# 更新玩家经验(不再直接给钱)
player_data["experience"] += crop_exp
# 添加成熟物到作物仓库
self._add_crop_to_warehouse(player_data, crop_harvest)
# 添加种子奖励到背包
if seed_reward:
self._add_seeds_to_bag(player_data, seed_reward)
# 检查升级
level_up_experience = 100 * player_data["level"]
if player_data["experience"] >= level_up_experience:
player_data["level"] += 1
player_data["experience"] -= level_up_experience
self.log('INFO', f"玩家 {username} 升级到 {player_data['level']}", 'SERVER')
# 清理地块
lot["is_planted"] = False
lot["crop_type"] = ""
lot["grow_time"] = 0
lot["已浇水"] = False
lot["已施肥"] = False
# 清除施肥时间戳
if "施肥时间" in lot:
del lot["施肥时间"]
# 保存玩家数据
self.save_player_data(username, player_data)
# 发送作物更新
self._push_crop_update_to_player(username, player_data)
# 构建消息
message = f"收获成功,获得 {crop_type} x{harvest_count}{crop_exp} 经验"
if seed_reward:
message += f",额外获得 {seed_reward['name']} 种子 x{seed_reward['count']}"
self.log('INFO', f"玩家 {username} 从地块 {lot_index} 收获了作物,获得 {crop_type} x{harvest_count}{crop_exp} 经验" + (f",额外获得 {seed_reward['name']} 种子 x{seed_reward['count']}" if seed_reward else ""), 'SERVER')
return self.send_data(client_id, {
"type": "action_response",
"action_type": "harvest_crop",
"success": True,
"message": message,
"updated_data": {
"money": player_data["money"],
"experience": player_data["experience"],
"level": player_data["level"],
"player_bag": player_data.get("player_bag", []),
"作物仓库": player_data.get("作物仓库", [])
}
})
#辅助函数-处理偷菜逻辑(访问模式下收获其他玩家作物的操作)
def _process_steal_crop(self, client_id, current_player_data, current_username, target_player_data, target_username, target_lot, lot_index):
"""处理偷菜逻辑(收益给当前玩家,清空目标玩家的作物)"""
# 偷菜体力值消耗
stamina_cost = 2
# 检查并更新当前玩家的体力值
self._check_and_update_stamina(current_player_data)
# 检查体力值是否足够
if not self._check_stamina_sufficient(current_player_data, stamina_cost):
return self._send_action_error(client_id, "harvest_crop", f"体力值不足,偷菜需要 {stamina_cost} 点体力,当前体力:{current_player_data.get('体力值', 0)}")
# 读取作物配置
crop_data = self._load_crop_data()
# 获取作物类型和经验偷菜获得的经验稍微少一些比如50%
crop_type = target_lot["crop_type"]
# 检查是否为杂草类型(杂草不能偷取,只能铲除)
if crop_type in crop_data:
crop_info = crop_data[crop_type]
is_weed = crop_info.get("是否杂草", False)
if is_weed:
return self._send_action_error(client_id, "harvest_crop", f"{crop_type}不能偷取,只能铲除!这是杂草,没有收益价值。")
crop_exp = int(crop_info.get("经验", 10) * 0.5) # 偷菜获得50%经验
# 额外检查:如果作物收益为负数,也视为杂草
crop_income = crop_info.get("收益", 100) + crop_info.get("花费", 0)
if crop_income < 0:
return self._send_action_error(client_id, "harvest_crop", f"{crop_type}不能偷取,只能铲除!这是杂草,没有收益价值。")
else:
# 默认经验
crop_exp = 5
# 生成成熟物收获偷菜获得较少1-3个
import random
harvest_count = random.randint(1, 3)
crop_harvest = {
"name": crop_type,
"count": harvest_count
}
# 10%概率获得1-2个该作物的种子偷菜也有机会获得种子
seed_reward = self._generate_harvest_seed_reward(crop_type)
# 消耗当前玩家的体力值
stamina_success, stamina_message = self._consume_stamina(current_player_data, stamina_cost, "偷菜")
if not stamina_success:
return self._send_action_error(client_id, "harvest_crop", stamina_message)
# 更新当前玩家数据(获得经验)
current_player_data["experience"] += crop_exp
# 添加成熟物到作物仓库
self._add_crop_to_warehouse(current_player_data, crop_harvest)
# 添加种子奖励到背包
if seed_reward:
self._add_seeds_to_bag(current_player_data, seed_reward)
# 检查当前玩家升级
level_up_experience = 100 * current_player_data["level"]
if current_player_data["experience"] >= level_up_experience:
current_player_data["level"] += 1
current_player_data["experience"] -= level_up_experience
self.log('INFO', f"玩家 {current_username} 升级到 {current_player_data['level']}", 'SERVER')
# 清理目标玩家的地块
target_lot["is_planted"] = False
target_lot["crop_type"] = ""
target_lot["grow_time"] = 0
target_lot["已浇水"] = False
target_lot["已施肥"] = False
# 清除施肥时间戳
if "施肥时间" in target_lot:
del target_lot["施肥时间"]
# 保存两个玩家的数据
self.save_player_data(current_username, current_player_data)
self.save_player_data(target_username, target_player_data)
# 向目标玩家推送作物更新(如果在线)
self._push_crop_update_to_player(target_username, target_player_data)
# 构建消息
message = f"偷菜成功!从 {target_username} 那里获得 {crop_type} x{harvest_count}{crop_exp} 经验,{stamina_message}"
if seed_reward:
message += f",额外获得 {seed_reward['name']} 种子 x{seed_reward['count']}"
self.log('INFO', f"玩家 {current_username} 偷了玩家 {target_username} 地块 {lot_index} 的作物,获得 {crop_type} x{harvest_count}{crop_exp} 经验" + (f",额外获得 {seed_reward['name']} 种子 x{seed_reward['count']}" if seed_reward else ""), 'SERVER')
return self.send_data(client_id, {
"type": "action_response",
"action_type": "harvest_crop",
"success": True,
"message": message,
"updated_data": {
"money": current_player_data["money"],
"experience": current_player_data["experience"],
"level": current_player_data["level"],
"体力值": current_player_data["体力值"],
"player_bag": current_player_data.get("player_bag", []),
"作物仓库": current_player_data.get("作物仓库", [])
}
})
# 生成收获种子奖励10%概率获得1-2个种子
def _generate_harvest_seed_reward(self, crop_type):
"""生成收获作物时的种子奖励"""
# 10%概率获得种子
if random.random() > 0.1:
return None
# 随机获得1-2个种子
seed_count = random.randint(1, 2)
return {
"name": crop_type,
"count": seed_count
}
# 添加种子到玩家背包
def _add_seeds_to_bag(self, player_data, seed_reward):
"""将种子奖励添加到玩家背包"""
if not seed_reward:
return
seed_name = seed_reward["name"]
seed_count = seed_reward["count"]
# 确保背包存在
if "player_bag" not in player_data:
player_data["player_bag"] = []
# 查找背包中是否已有该种子
seed_found = False
for item in player_data["player_bag"]:
if item.get("name") == seed_name:
item["count"] += seed_count
seed_found = True
break
# 如果背包中没有该种子,添加新条目
if not seed_found:
# 从作物数据获取品质信息
crop_data = self._load_crop_data()
quality = "普通"
if crop_data and seed_name in crop_data:
quality = crop_data[seed_name].get("品质", "普通")
player_data["player_bag"].append({
"name": seed_name,
"quality": quality,
"count": seed_count
})
def _add_crop_to_warehouse(self, player_data, crop_harvest):
"""将成熟物添加到玩家作物仓库"""
if not crop_harvest:
return
crop_name = crop_harvest["name"]
crop_count = crop_harvest["count"]
# 确保作物仓库存在
if "作物仓库" not in player_data:
player_data["作物仓库"] = []
# 查找仓库中是否已有该成熟物
crop_found = False
for item in player_data["作物仓库"]:
if item.get("name") == crop_name:
item["count"] += crop_count
crop_found = True
break
# 如果仓库中没有该成熟物,添加新条目
if not crop_found:
# 从作物数据获取品质信息
crop_data = self._load_crop_data()
quality = "普通"
if crop_data and crop_name in crop_data:
quality = crop_data[crop_name].get("品质", "普通")
player_data["作物仓库"].append({
"name": crop_name,
"quality": quality,
"count": crop_count
})
#==========================收获作物处理==========================
#==========================杂草生长处理==========================
def check_and_grow_weeds(self):
"""检查所有玩家的离线时间,并在长时间离线玩家的空地上随机生长杂草"""
try:
self.log('INFO', "开始检查杂草生长...", 'SERVER')
current_time = time.time()
affected_players = 0
total_weeds_added = 0
# 获取所有玩家存档文件
game_saves_dir = "game_saves"
if not os.path.exists(game_saves_dir):
return
# 获取作物数据以验证杂草类型
crop_data = self._load_crop_data()
if not crop_data:
self.log('ERROR', "无法加载作物数据,跳过杂草检查", 'SERVER')
return
# 可用的杂草类型(从作物数据中筛选标记为杂草的作物)
available_weeds = []
for crop_name, crop_info in crop_data.items():
if crop_info.get("是否杂草", False):
available_weeds.append(crop_name)
if not available_weeds:
self.log('WARNING', "没有找到可用的杂草类型,跳过杂草检查", 'SERVER')
return
# 遍历所有玩家文件
for filename in os.listdir(game_saves_dir):
if not filename.endswith('.json'):
continue
account_id = filename[:-5] # 移除.json后缀
try:
# 加载玩家数据
player_data = self.load_player_data(account_id)
if not player_data:
continue
# 检查玩家是否长时间离线
if self._is_player_long_offline(player_data, current_time):
# 为该玩家的空地生长杂草
weeds_added = self._grow_weeds_for_player(player_data, account_id, available_weeds)
if weeds_added > 0:
affected_players += 1
total_weeds_added += weeds_added
# 保存玩家数据
self.save_player_data(account_id, player_data)
except Exception as e:
self.log('ERROR', f"处理玩家 {account_id} 的杂草生长时出错: {str(e)}", 'SERVER')
continue
self.log('INFO', f"杂草检查完成,共为 {affected_players} 个玩家的农场添加了 {total_weeds_added} 个杂草", 'SERVER')
except Exception as e:
self.log('ERROR', f"杂草生长检查过程中出错: {str(e)}", 'SERVER')
def _is_player_long_offline(self, player_data, current_time):
"""检查玩家是否长时间离线"""
# 获取玩家最后登录时间
last_login_time_str = player_data.get("last_login_time", "")
if not last_login_time_str:
return False
try:
# 解析最后登录时间戳
last_login_timestamp = self._parse_login_time_to_timestamp(last_login_time_str)
if last_login_timestamp is None:
return False
# 计算离线天数
offline_seconds = current_time - last_login_timestamp
offline_days = offline_seconds / 86400 # 转换为天数
return offline_days >= self.offline_threshold_days
except Exception as e:
self.log('ERROR', f"解析玩家登录时间时出错: {str(e)}", 'SERVER')
return False
def _grow_weeds_for_player(self, player_data, account_id, available_weeds):
"""为指定玩家的空地生长杂草"""
import random
farm_lots = player_data.get("farm_lots", [])
if not farm_lots:
return 0
# 找到所有空的已开垦地块
empty_lots = []
for i, lot in enumerate(farm_lots):
if (lot.get("is_diged", False) and
not lot.get("is_planted", False) and
lot.get("crop_type", "") == ""):
empty_lots.append(i)
if not empty_lots:
return 0
# 随机选择要长杂草的地块数量
max_weeds = min(self.max_weeds_per_check, len(empty_lots))
weeds_to_add = random.randint(1, max_weeds)
# 随机选择地块
selected_lots = random.sample(empty_lots, weeds_to_add)
weeds_added = 0
crop_data = self._load_crop_data()
for lot_index in selected_lots:
# 按概率决定是否在这个地块长杂草
if random.random() < self.weed_growth_probability:
# 随机选择杂草类型
weed_type = random.choice(available_weeds)
weed_info = crop_data.get(weed_type, {})
# 在地块上种植杂草
lot = farm_lots[lot_index]
lot["is_planted"] = True
lot["crop_type"] = weed_type
lot["grow_time"] = weed_info.get("生长时间", 5) # 杂草立即成熟
lot["max_grow_time"] = weed_info.get("生长时间", 5)
lot["已浇水"] = False
lot["已施肥"] = False
weeds_added += 1
if weeds_added > 0:
self.log('INFO', f"为玩家 {account_id} 的农场添加了 {weeds_added} 个杂草", 'SERVER')
return weeds_added
#==========================杂草生长处理==========================
#==========================种植作物处理==========================
#处理种植作物请求
def _handle_plant_crop(self, client_id, message):
"""处理种植作物请求"""
# 检查用户是否已登录
logged_in, response = self._check_user_logged_in(client_id, "种植作物", "plant_crop")
if not logged_in:
return self.send_data(client_id, response)
# 获取玩家数据
player_data, username, response = self._load_player_data_with_check(client_id, "plant_crop")
if not player_data:
return self.send_data(client_id, response)
lot_index = message.get("lot_index", -1)
crop_name = message.get("crop_name", "")
# 验证参数
if lot_index < 0 or lot_index >= len(player_data.get("farm_lots", [])):
return self._send_action_error(client_id, "plant_crop", "无效的地块索引")
lot = player_data["farm_lots"][lot_index]
# 检查地块状态
if not lot.get("is_diged", False):
return self._send_action_error(client_id, "plant_crop", "此地块尚未开垦")
if lot.get("is_planted", False):
return self._send_action_error(client_id, "plant_crop", "此地块已经种植了作物")
# 处理种植
return self._process_planting(client_id, player_data, username, lot, crop_name)
#辅助函数-处理作物种植逻辑
def _process_planting(self, client_id, player_data, username, lot, crop_name):
"""处理作物种植逻辑"""
# 读取作物配置
crop_data = self._load_crop_data()
# 检查玩家背包中是否有此种子
seed_found = False
seed_index = -1
for i, item in enumerate(player_data.get("player_bag", [])):
if item.get("name") == crop_name:
seed_found = True
seed_index = i
break
if not seed_found:
return self._send_action_error(client_id, "plant_crop", "背包中没有此种子")
# 获取作物生长时间
if crop_name in crop_data:
grow_time = crop_data[crop_name].get("生长时间", 600)
else:
grow_time = 600
# 从背包中减少种子数量
player_data["player_bag"][seed_index]["count"] -= 1
# 如果种子用完,从背包中移除
if player_data["player_bag"][seed_index]["count"] <= 0:
player_data["player_bag"].pop(seed_index)
# 更新地块数据
lot.update({
"is_planted": True,
"crop_type": crop_name,
"grow_time": 0,
"max_grow_time": grow_time,
"is_dead": False,
"已浇水": False,
"已施肥": False
})
# 清除施肥时间戳
if "施肥时间" in lot:
del lot["施肥时间"]
# 保存玩家数据
self.save_player_data(username, player_data)
# 发送作物更新
self._push_crop_update_to_player(username, player_data)
self.log('INFO', f"玩家 {username} 种植了 {crop_name}", 'SERVER')
return self.send_data(client_id, {
"type": "action_response",
"action_type": "plant_crop",
"success": True,
"message": f"成功种植 {crop_name}",
"updated_data": {
"player_bag": player_data["player_bag"]
}
})
#==========================种植作物处理==========================
#==========================购买种子处理==========================
#处理购买种子请求
def _handle_buy_seed(self, client_id, message):
"""处理购买种子请求"""
# 检查用户是否已登录
logged_in, response = self._check_user_logged_in(client_id, "购买种子", "buy_seed")
if not logged_in:
return self.send_data(client_id, response)
# 获取玩家数据
player_data, username, response = self._load_player_data_with_check(client_id, "buy_seed")
if not player_data:
return self.send_data(client_id, response)
crop_name = message.get("crop_name", "")
# 加载作物配置
crop_data = self._load_crop_data()
if not crop_data:
return self._send_action_error(client_id, "buy_seed", "服务器无法加载作物数据")
# 检查作物是否存在
if crop_name not in crop_data:
return self._send_action_error(client_id, "buy_seed", "该种子不存在")
# 处理购买
return self._process_seed_purchase(client_id, player_data, username, crop_name, crop_data[crop_name])
#处理种子购买逻辑
def _process_seed_purchase(self, client_id, player_data, username, crop_name, crop):
"""处理种子购买逻辑"""
# 检查玩家等级
if player_data["level"] < crop.get("等级", 1):
return self._send_action_error(client_id, "buy_seed", "等级不足,无法购买此种子")
# 检查玩家金钱
if player_data["money"] < crop.get("花费", 0):
return self._send_action_error(client_id, "buy_seed", "金钱不足,无法购买此种子")
# 扣除金钱
player_data["money"] -= crop.get("花费", 0)
# 将种子添加到背包
seed_found = False
for item in player_data.get("player_bag", []):
if item.get("name") == crop_name:
item["count"] += 1
seed_found = True
break
if not seed_found:
if "player_bag" not in player_data:
player_data["player_bag"] = []
player_data["player_bag"].append({
"name": crop_name,
"quality": crop.get("品质", "普通"),
"count": 1
})
# 保存玩家数据
self.save_player_data(username, player_data)
self.log('INFO', f"玩家 {username} 购买了种子 {crop_name}", 'SERVER')
return self.send_data(client_id, {
"type": "action_response",
"action_type": "buy_seed",
"success": True,
"message": f"成功购买 {crop_name} 种子",
"updated_data": {
"money": player_data["money"],
"player_bag": player_data["player_bag"]
}
})
#==========================购买种子处理==========================
#==========================购买道具处理==========================
#处理购买道具请求
def _handle_buy_item(self, client_id, message):
"""处理购买道具请求"""
# 检查用户是否已登录
logged_in, response = self._check_user_logged_in(client_id, "购买道具", "buy_item")
if not logged_in:
return self.send_data(client_id, response)
# 获取玩家数据
player_data, username, response = self._load_player_data_with_check(client_id, "buy_item")
if not player_data:
return self.send_data(client_id, response)
item_name = message.get("item_name", "")
item_cost = message.get("item_cost", 0)
# 加载道具配置
item_config = self._load_item_config()
if not item_config:
return self._send_action_error(client_id, "buy_item", "服务器无法加载道具数据")
# 检查道具是否存在
if item_name not in item_config:
return self._send_action_error(client_id, "buy_item", "该道具不存在")
# 验证价格是否正确
actual_cost = item_config[item_name].get("花费", 0)
if item_cost != actual_cost:
return self._send_action_error(client_id, "buy_item", f"道具价格验证失败,实际价格为{actual_cost}")
# 处理购买
return self._process_item_purchase(client_id, player_data, username, item_name, item_config[item_name])
#处理道具购买逻辑
def _process_item_purchase(self, client_id, player_data, username, item_name, item_info):
"""处理道具购买逻辑"""
item_cost = item_info.get("花费", 0)
# 检查玩家金钱
if player_data["money"] < item_cost:
return self._send_action_error(client_id, "buy_item", "金钱不足,无法购买此道具")
# 扣除金钱
player_data["money"] -= item_cost
# 将道具添加到道具背包
item_found = False
# 确保道具背包存在
if "道具背包" not in player_data:
player_data["道具背包"] = []
for item in player_data["道具背包"]:
if item.get("name") == item_name:
item["count"] += 1
item_found = True
break
if not item_found:
player_data["道具背包"].append({
"name": item_name,
"count": 1
})
# 保存玩家数据
self.save_player_data(username, player_data)
self.log('INFO', f"玩家 {username} 购买了道具 {item_name},花费 {item_cost}", 'SERVER')
return self.send_data(client_id, {
"type": "action_response",
"action_type": "buy_item",
"success": True,
"message": f"成功购买 {item_name}",
"updated_data": {
"money": player_data["money"],
"道具背包": player_data["道具背包"]
}
})
#加载道具配置数据
def _load_item_config(self):
"""从item_config.json加载道具配置数据"""
try:
with open("config/item_config.json", 'r', encoding='utf-8') as file:
return json.load(file)
except Exception as e:
self.log('ERROR', f"无法加载道具数据: {str(e)}", 'SERVER')
return {}
#==========================购买道具处理==========================
#==========================开垦土地处理==========================
#处理开垦土地请求
def _handle_dig_ground(self, client_id, message):
"""处理开垦土地请求"""
# 检查用户是否已登录
logged_in, response = self._check_user_logged_in(client_id, "开垦土地", "dig_ground")
if not logged_in:
return self.send_data(client_id, response)
# 获取玩家数据
player_data, username, response = self._load_player_data_with_check(client_id, "dig_ground")
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, "dig_ground", "无效的地块索引")
lot = player_data["farm_lots"][lot_index]
# 检查地块是否已开垦
if lot.get("is_diged", False):
return self._send_action_error(client_id, "dig_ground", "此地块已经开垦过了")
# 处理开垦
return self._process_digging(client_id, player_data, username, lot, lot_index)
#辅助函数-处理土地开垦逻辑
def _process_digging(self, client_id, player_data, username, lot, lot_index):
"""处理土地开垦逻辑"""
# 计算开垦费用 - 基于已开垦地块数量
digged_count = sum(1 for l in player_data.get("farm_lots", []) if l.get("is_diged", False))
dig_money = digged_count * 1000
# 检查玩家金钱是否足够
if player_data["money"] < dig_money:
return self._send_action_error(client_id, "dig_ground", f"金钱不足,开垦此地块需要 {dig_money} 金钱")
# 执行开垦操作
player_data["money"] -= dig_money
lot["is_diged"] = True
# 生成开垦随机奖励
rewards = self._generate_dig_rewards()
# 应用奖励
player_data["money"] += rewards["money"]
player_data["experience"] += rewards["experience"]
# 添加种子到背包
if "player_bag" not in player_data:
player_data["player_bag"] = []
for seed_name, quantity in rewards["seeds"].items():
# 查找是否已有该种子
found = False
for item in player_data["player_bag"]:
if item.get("name") == seed_name:
item["count"] += quantity
found = True
break
# 如果没有找到,添加新种子
if not found:
player_data["player_bag"].append({
"name": seed_name,
"count": quantity
})
# 检查是否升级
self._check_level_up(player_data)
# 保存玩家数据
self.save_player_data(username, player_data)
# 发送作物更新
self._push_crop_update_to_player(username, player_data)
# 构建奖励消息
reward_message = f"获得 {rewards['money']} 金钱、{rewards['experience']} 经验"
if rewards["seeds"]:
seed_list = [f"{name} x{qty}" for name, qty in rewards["seeds"].items()]
reward_message += f"、种子:{', '.join(seed_list)}"
self.log('INFO', f"玩家 {username} 成功开垦地块 {lot_index},花费 {dig_money} 金钱,{reward_message}", 'SERVER')
return self.send_data(client_id, {
"type": "action_response",
"action_type": "dig_ground",
"success": True,
"message": f"成功开垦地块,花费 {dig_money} 金钱!{reward_message}",
"updated_data": {
"money": player_data["money"],
"experience": player_data["experience"],
"level": player_data["level"],
"farm_lots": player_data["farm_lots"],
"player_bag": player_data["player_bag"]
}
})
#辅助函数-生成开垦土地随机奖励
def _generate_dig_rewards(self):
"""生成开垦土地的随机奖励"""
rewards = {
"money": 0,
"experience": 0,
"seeds": {}
}
# 随机金钱200-500元
rewards["money"] = random.randint(200, 500)
# 随机经验300-600经验
rewards["experience"] = random.randint(300, 600)
# 随机种子0-3种种子
seed_types_count = random.randint(0, 3)
if seed_types_count > 0:
# 获取作物数据
crop_data = self._load_crop_data()
if crop_data:
# 获取所有可购买的种子
all_seeds = []
for crop_name, crop_info in crop_data.items():
if crop_info.get("能否购买", False):
all_seeds.append(crop_name)
if all_seeds:
# 随机选择种子类型
selected_seeds = random.sample(all_seeds, min(seed_types_count, len(all_seeds)))
for seed_name in selected_seeds:
# 每种种子1-3个
quantity = random.randint(1, 3)
rewards["seeds"][seed_name] = quantity
return rewards
#==========================开垦土地处理==========================
#==========================铲除作物处理==========================
#处理铲除作物请求
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)
#辅助函数-处理铲除作物逻辑
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"]
}
})
#==========================铲除作物处理==========================
#==========================浇水作物处理==========================
#处理浇水请求
def _handle_water_crop(self, client_id, message):
"""处理浇水作物请求"""
# 检查用户是否已登录
logged_in, response = self._check_user_logged_in(client_id, "浇水作物", "water_crop")
if not logged_in:
return self.send_data(client_id, response)
# 获取当前操作用户的数据
current_player_data, current_username, response = self._load_player_data_with_check(client_id, "water_crop")
if not current_player_data:
return self.send_data(client_id, response)
lot_index = message.get("lot_index", -1)
target_username = message.get("target_username", "")
# 确定操作目标如果有target_username就是访问模式否则是自己的农场
if target_username and target_username != current_username:
# 访问模式:浇水别人的作物,但花自己的钱
target_player_data = self.load_player_data(target_username)
if not target_player_data:
return self._send_action_error(client_id, "water_crop", f"无法找到玩家 {target_username} 的数据")
# 验证地块索引
if lot_index < 0 or lot_index >= len(target_player_data.get("farm_lots", [])):
return self._send_action_error(client_id, "water_crop", "无效的地块索引")
target_lot = target_player_data["farm_lots"][lot_index]
# 检查地块状态
if not target_lot.get("is_planted", False) or not target_lot.get("crop_type", ""):
return self._send_action_error(client_id, "water_crop", "此地块没有种植作物")
# 处理访问模式浇水(花自己的钱,效果作用在目标玩家作物上)
return self._process_visiting_watering(client_id, current_player_data, current_username, target_player_data, target_username, target_lot, lot_index)
else:
# 正常模式:浇水自己的作物
# 验证地块索引
if lot_index < 0 or lot_index >= len(current_player_data.get("farm_lots", [])):
return self._send_action_error(client_id, "water_crop", "无效的地块索引")
lot = current_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, "water_crop", "此地块没有种植作物")
# 处理正常浇水
return self._process_watering(client_id, current_player_data, current_username, lot, lot_index)
#辅助函数-处理浇水逻辑
def _process_watering(self, client_id, player_data, username, lot, lot_index):
"""处理浇水逻辑"""
# 浇水费用
water_cost = 50
# 检查玩家金钱是否足够
if player_data["money"] < water_cost:
return self._send_action_error(client_id, "water_crop", f"金钱不足,浇水需要 {water_cost} 金钱")
# 检查作物是否已死亡
if lot.get("is_dead", False):
return self._send_action_error(client_id, "water_crop", "死亡的作物无法浇水")
# 检查是否已经成熟
if lot["grow_time"] >= lot["max_grow_time"]:
return self._send_action_error(client_id, "water_crop", "作物已经成熟,无需浇水")
# 检查是否在1小时内已经浇过水3600秒 = 1小时
current_time = time.time()
last_water_time = lot.get("浇水时间", 0)
water_cooldown = 3600 # 1小时冷却时间
if current_time - last_water_time < water_cooldown:
remaining_time = water_cooldown - (current_time - last_water_time)
remaining_minutes = int(remaining_time // 60)
remaining_seconds = int(remaining_time % 60)
return self._send_action_error(client_id, "water_crop", f"浇水冷却中,还需等待 {remaining_minutes} 分钟 {remaining_seconds}")
# 执行浇水操作
player_data["money"] -= water_cost
# 生成随机经验奖励100-300
experience_reward = random.randint(100, 300)
player_data["experience"] += experience_reward
# 检查是否升级
self._check_level_up(player_data)
# 计算浇水效果增加1%的生长进度
growth_increase = int(lot["max_grow_time"] * 0.01) # 1%的生长时间
if growth_increase < 1:
growth_increase = 1 # 至少增加1秒
lot["grow_time"] += growth_increase
# 确保不超过最大生长时间
if lot["grow_time"] > lot["max_grow_time"]:
lot["grow_time"] = lot["max_grow_time"]
# 记录浇水时间戳
lot["浇水时间"] = current_time
# 保存玩家数据
self.save_player_data(username, player_data)
# 发送作物更新
self._push_crop_update_to_player(username, player_data)
crop_type = lot.get("crop_type", "未知作物")
progress = (lot["grow_time"] / lot["max_grow_time"]) * 100
self.log('INFO', f"玩家 {username} 给地块 {lot_index}{crop_type} 浇水,花费 {water_cost} 金钱,获得 {experience_reward} 经验,生长进度: {progress:.1f}%", 'SERVER')
message = f"浇水成功!{crop_type} 生长了 {growth_increase} 秒,当前进度: {progress:.1f}%,获得 {experience_reward} 经验"
if lot["grow_time"] >= lot["max_grow_time"]:
message += ",作物已成熟!"
return self.send_data(client_id, {
"type": "action_response",
"action_type": "water_crop",
"success": True,
"message": message,
"updated_data": {
"money": player_data["money"],
"experience": player_data["experience"],
"level": player_data["level"],
"farm_lots": player_data["farm_lots"]
}
})
#处理访问模式浇水逻辑
def _process_visiting_watering(self, client_id, current_player_data, current_username, target_player_data, target_username, target_lot, lot_index):
"""处理访问模式浇水逻辑(花自己的钱,效果作用在目标玩家作物上)"""
# 浇水费用
water_cost = 50
# 检查当前玩家金钱是否足够
if current_player_data["money"] < water_cost:
return self._send_action_error(client_id, "water_crop", f"金钱不足,帮助浇水需要 {water_cost} 金钱")
# 检查目标作物是否已死亡
if target_lot.get("is_dead", False):
return self._send_action_error(client_id, "water_crop", "死亡的作物无法浇水")
# 检查是否已经成熟
if target_lot["grow_time"] >= target_lot["max_grow_time"]:
return self._send_action_error(client_id, "water_crop", "作物已经成熟,无需浇水")
# 检查是否在1小时内已经浇过水
current_time = time.time()
last_water_time = target_lot.get("浇水时间", 0)
water_cooldown = 3600 # 1小时冷却时间
if current_time - last_water_time < water_cooldown:
remaining_time = water_cooldown - (current_time - last_water_time)
remaining_minutes = int(remaining_time // 60)
remaining_seconds = int(remaining_time % 60)
return self._send_action_error(client_id, "water_crop", f"浇水冷却中,还需等待 {remaining_minutes} 分钟 {remaining_seconds}")
# 执行浇水操作:扣除当前玩家的钱
current_player_data["money"] -= water_cost
# 生成随机经验奖励100-300给当前玩家
experience_reward = random.randint(100, 300)
current_player_data["experience"] += experience_reward
# 检查当前玩家是否升级
self._check_level_up(current_player_data)
# 计算浇水效果:增加目标作物的生长进度
growth_increase = int(target_lot["max_grow_time"] * 0.01) # 1%的生长时间
if growth_increase < 1:
growth_increase = 1 # 至少增加1秒
target_lot["grow_time"] += growth_increase
# 确保不超过最大生长时间
if target_lot["grow_time"] > target_lot["max_grow_time"]:
target_lot["grow_time"] = target_lot["max_grow_time"]
# 记录浇水时间戳
target_lot["浇水时间"] = current_time
# 保存两个玩家的数据
self.save_player_data(current_username, current_player_data)
self.save_player_data(target_username, target_player_data)
# 向目标玩家推送作物更新(如果在线)
self._push_crop_update_to_player(target_username, target_player_data)
crop_type = target_lot.get("crop_type", "未知作物")
progress = (target_lot["grow_time"] / target_lot["max_grow_time"]) * 100
self.log('INFO', f"玩家 {current_username} 帮助玩家 {target_username} 给地块 {lot_index}{crop_type} 浇水,花费 {water_cost} 金钱,获得 {experience_reward} 经验,生长进度: {progress:.1f}%", 'SERVER')
message = f"帮助浇水成功!{target_username}{crop_type} 生长了 {growth_increase} 秒,当前进度: {progress:.1f}%,获得 {experience_reward} 经验"
if target_lot["grow_time"] >= target_lot["max_grow_time"]:
message += ",作物已成熟!"
return self.send_data(client_id, {
"type": "action_response",
"action_type": "water_crop",
"success": True,
"message": message,
"updated_data": {
"money": current_player_data["money"],
"experience": current_player_data["experience"],
"level": current_player_data["level"]
}
})
#==========================浇水作物处理==========================
#==========================施肥作物处理==========================
#处理施肥请求
def _handle_fertilize_crop(self, client_id, message):
"""处理施肥作物请求"""
# 检查用户是否已登录
logged_in, response = self._check_user_logged_in(client_id, "施肥作物", "fertilize_crop")
if not logged_in:
return self.send_data(client_id, response)
# 获取当前操作用户的数据
current_player_data, current_username, response = self._load_player_data_with_check(client_id, "fertilize_crop")
if not current_player_data:
return self.send_data(client_id, response)
lot_index = message.get("lot_index", -1)
target_username = message.get("target_username", "")
# 确定操作目标如果有target_username就是访问模式否则是自己的农场
if target_username and target_username != current_username:
# 访问模式:施肥别人的作物,但花自己的钱
target_player_data = self.load_player_data(target_username)
if not target_player_data:
return self._send_action_error(client_id, "fertilize_crop", f"无法找到玩家 {target_username} 的数据")
# 验证地块索引
if lot_index < 0 or lot_index >= len(target_player_data.get("farm_lots", [])):
return self._send_action_error(client_id, "fertilize_crop", "无效的地块索引")
target_lot = target_player_data["farm_lots"][lot_index]
# 检查地块状态
if not target_lot.get("is_planted", False) or not target_lot.get("crop_type", ""):
return self._send_action_error(client_id, "fertilize_crop", "此地块没有种植作物")
# 处理访问模式施肥
return self._process_visiting_fertilizing(client_id, current_player_data, current_username, target_player_data, target_username, target_lot, lot_index)
else:
# 正常模式:施肥自己的作物
# 验证地块索引
if lot_index < 0 or lot_index >= len(current_player_data.get("farm_lots", [])):
return self._send_action_error(client_id, "fertilize_crop", "无效的地块索引")
lot = current_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, "fertilize_crop", "此地块没有种植作物")
# 处理正常施肥
return self._process_fertilizing(client_id, current_player_data, current_username, lot, lot_index)
#辅助函数-处理访问模式施肥逻辑
def _process_visiting_fertilizing(self, client_id, current_player_data, current_username, target_player_data, target_username, target_lot, lot_index):
"""处理访问模式施肥逻辑(花自己的钱,效果作用在目标玩家作物上)"""
# 施肥费用
fertilize_cost = 150
# 检查当前玩家金钱是否足够
if current_player_data["money"] < fertilize_cost:
return self._send_action_error(client_id, "fertilize_crop", f"金钱不足,帮助施肥需要 {fertilize_cost} 金钱")
# 检查目标作物是否已死亡
if target_lot.get("is_dead", False):
return self._send_action_error(client_id, "fertilize_crop", "死亡的作物无法施肥")
# 检查是否已经成熟
if target_lot["grow_time"] >= target_lot["max_grow_time"]:
return self._send_action_error(client_id, "fertilize_crop", "作物已经成熟,无需施肥")
# 检查是否已经施过肥
if target_lot.get("已施肥", False):
return self._send_action_error(client_id, "fertilize_crop", "此作物已经施过肥了")
# 执行施肥操作:扣除当前玩家的钱
current_player_data["money"] -= fertilize_cost
# 生成随机经验奖励100-300给当前玩家
experience_reward = random.randint(100, 300)
current_player_data["experience"] += experience_reward
# 检查当前玩家是否升级
self._check_level_up(current_player_data)
# 标记目标作物已施肥,施肥效果会在作物生长更新时生效
target_lot["已施肥"] = True
# 记录施肥时间戳用于计算10分钟的双倍生长效果
target_lot["施肥时间"] = time.time()
# 保存两个玩家的数据
self.save_player_data(current_username, current_player_data)
self.save_player_data(target_username, target_player_data)
# 向目标玩家推送作物更新(如果在线)
self._push_crop_update_to_player(target_username, target_player_data)
crop_type = target_lot.get("crop_type", "未知作物")
self.log('INFO', f"玩家 {current_username} 帮助玩家 {target_username} 给地块 {lot_index}{crop_type} 施肥,花费 {fertilize_cost} 金钱,获得 {experience_reward} 经验", 'SERVER')
return self.send_data(client_id, {
"type": "action_response",
"action_type": "fertilize_crop",
"success": True,
"message": f"帮助施肥成功!{target_username}{crop_type} 将在10分钟内以双倍速度生长获得 {experience_reward} 经验",
"updated_data": {
"money": current_player_data["money"],
"experience": current_player_data["experience"],
"level": current_player_data["level"]
}
})
#辅助函数-处理施肥逻辑
def _process_fertilizing(self, client_id, player_data, username, lot, lot_index):
"""处理施肥逻辑"""
# 施肥费用
fertilize_cost = 150
# 检查玩家金钱是否足够
if player_data["money"] < fertilize_cost:
return self._send_action_error(client_id, "fertilize_crop", f"金钱不足,施肥需要 {fertilize_cost} 金钱")
# 检查作物是否已死亡
if lot.get("is_dead", False):
return self._send_action_error(client_id, "fertilize_crop", "死亡的作物无法施肥")
# 检查是否已经成熟
if lot["grow_time"] >= lot["max_grow_time"]:
return self._send_action_error(client_id, "fertilize_crop", "作物已经成熟,无需施肥")
# 检查是否已经施过肥
if lot.get("已施肥", False):
return self._send_action_error(client_id, "fertilize_crop", "此作物已经施过肥了")
# 执行施肥操作
player_data["money"] -= fertilize_cost
# 生成随机经验奖励100-300
experience_reward = random.randint(100, 300)
player_data["experience"] += experience_reward
# 检查是否升级
self._check_level_up(player_data)
# 标记已施肥,施肥效果会在作物生长更新时生效
lot["已施肥"] = True
# 记录施肥时间戳用于计算10分钟的双倍生长效果
lot["施肥时间"] = time.time()
# 保存玩家数据
self.save_player_data(username, player_data)
# 发送作物更新
self._push_crop_update_to_player(username, player_data)
crop_type = lot.get("crop_type", "未知作物")
self.log('INFO', f"玩家 {username} 给地块 {lot_index}{crop_type} 施肥,花费 {fertilize_cost} 金钱,获得 {experience_reward} 经验", 'SERVER')
return self.send_data(client_id, {
"type": "action_response",
"action_type": "fertilize_crop",
"success": True,
"message": f"施肥成功!{crop_type} 将在10分钟内以双倍速度生长获得 {experience_reward} 经验",
"updated_data": {
"money": player_data["money"],
"experience": player_data["experience"],
"level": player_data["level"],
"farm_lots": player_data["farm_lots"]
}
})
#==========================施肥作物处理==========================
#==========================道具使用处理==========================
def _handle_use_item(self, client_id, message):
"""处理使用道具请求"""
print(f"调试:服务器收到道具使用请求")
print(f" - client_id: {client_id}")
print(f" - message: {message}")
# 检查用户是否已登录
logged_in, response = self._check_user_logged_in(client_id, "使用道具", "use_item")
if not logged_in:
print(f"错误:用户未登录")
return self.send_data(client_id, response)
# 获取玩家数据
player_data, username, response = self._load_player_data_with_check(client_id, "use_item")
if not player_data:
print(f"错误:无法加载玩家数据")
return self.send_data(client_id, response)
lot_index = message.get("lot_index", -1)
item_name = message.get("item_name", "")
use_type = message.get("use_type", "")
target_username = message.get("target_username", "")
print(f"调试:解析参数")
print(f" - username: {username}")
print(f" - lot_index: {lot_index}")
print(f" - item_name: {item_name}")
print(f" - use_type: {use_type}")
print(f" - target_username: {target_username}")
# 验证参数
if not item_name:
return self._send_action_error(client_id, "use_item", "道具名称不能为空")
if not use_type:
return self._send_action_error(client_id, "use_item", "使用类型不能为空")
# 检查玩家是否拥有该道具
if not self._has_item_in_inventory(player_data, item_name):
return self._send_action_error(client_id, "use_item", f"您没有 {item_name}")
# 确定操作目标
if target_username and target_username != username:
# 访问模式:对别人的作物使用道具
target_player_data = self.load_player_data(target_username)
if not target_player_data:
return self._send_action_error(client_id, "use_item", f"无法找到玩家 {target_username} 的数据")
# 验证地块索引
if lot_index < 0 or lot_index >= len(target_player_data.get("farm_lots", [])):
return self._send_action_error(client_id, "use_item", "无效的地块索引")
target_lot = target_player_data["farm_lots"][lot_index]
return self._process_item_use_visiting(client_id, player_data, username, target_player_data, target_username, target_lot, lot_index, item_name, use_type)
else:
# 正常模式:对自己的作物使用道具
if lot_index < 0 or lot_index >= len(player_data.get("farm_lots", [])):
return self._send_action_error(client_id, "use_item", "无效的地块索引")
lot = player_data["farm_lots"][lot_index]
return self._process_item_use_normal(client_id, player_data, username, lot, lot_index, item_name, use_type)
def _has_item_in_inventory(self, player_data, item_name):
"""检查玩家是否拥有指定道具"""
item_bag = player_data.get("道具背包", [])
for item in item_bag:
if item.get("name", "") == item_name and item.get("count", 0) > 0:
return True
return False
def _remove_item_from_inventory(self, player_data, item_name, count=1):
"""从玩家道具背包中移除指定数量的道具"""
item_bag = player_data.get("道具背包", [])
for i, item in enumerate(item_bag):
if item.get("name", "") == item_name and item.get("count", 0) >= count:
item["count"] -= count
if item["count"] <= 0:
item_bag.pop(i)
return True
return False
def _process_item_use_normal(self, client_id, player_data, username, lot, lot_index, item_name, use_type):
"""处理正常模式下的道具使用"""
# 检查地块状态
if not lot.get("is_planted", False) or not lot.get("crop_type", ""):
return self._send_action_error(client_id, "use_item", "此地块没有种植作物")
# 检查作物是否已死亡
if lot.get("is_dead", False):
return self._send_action_error(client_id, "use_item", "死亡的作物无法使用道具")
# 根据使用类型和道具名称执行不同逻辑
if use_type == "fertilize":
# 检查是否已经成熟(施肥道具需要检查)
if lot.get("grow_time", 0) >= lot.get("max_grow_time", 1):
return self._send_action_error(client_id, "use_item", "作物已经成熟,无需施肥")
return self._use_fertilizer_item(client_id, player_data, username, lot, lot_index, item_name)
elif use_type == "water":
# 检查是否已经成熟(浇水道具需要检查)
if lot.get("grow_time", 0) >= lot.get("max_grow_time", 1):
return self._send_action_error(client_id, "use_item", "作物已经成熟,无需浇水")
return self._use_watering_item(client_id, player_data, username, lot, lot_index, item_name)
elif use_type == "remove":
# 铲子可以清除任何作物,包括成熟的
return self._use_removal_item(client_id, player_data, username, lot, lot_index, item_name)
elif use_type == "weed_killer":
# 除草剂可以清除任何杂草,包括成熟的
return self._use_weed_killer_item(client_id, player_data, username, lot, lot_index, item_name)
elif use_type == "harvest":
# 采集道具只能对成熟的作物使用
if lot.get("grow_time", 0) < lot.get("max_grow_time", 1):
return self._send_action_error(client_id, "use_item", "作物还未成熟,无法使用采集道具")
return self._use_harvest_item(client_id, player_data, username, lot, lot_index, item_name)
else:
return self._send_action_error(client_id, "use_item", f"不支持的使用类型: {use_type}")
def _process_item_use_visiting(self, client_id, current_player_data, current_username, target_player_data, target_username, target_lot, lot_index, item_name, use_type):
"""处理访问模式下的道具使用"""
# 检查地块状态
if not target_lot.get("is_planted", False) or not target_lot.get("crop_type", ""):
return self._send_action_error(client_id, "use_item", "此地块没有种植作物")
# 检查作物是否已死亡
if target_lot.get("is_dead", False):
return self._send_action_error(client_id, "use_item", "死亡的作物无法使用道具")
# 根据使用类型和道具名称执行不同逻辑
if use_type == "fertilize":
# 检查是否已经成熟(施肥道具需要检查)
if target_lot.get("grow_time", 0) >= target_lot.get("max_grow_time", 1):
return self._send_action_error(client_id, "use_item", "作物已经成熟,无需施肥")
return self._use_fertilizer_item_visiting(client_id, current_player_data, current_username, target_player_data, target_username, target_lot, lot_index, item_name)
elif use_type == "water":
# 检查是否已经成熟(浇水道具需要检查)
if target_lot.get("grow_time", 0) >= target_lot.get("max_grow_time", 1):
return self._send_action_error(client_id, "use_item", "作物已经成熟,无需浇水")
return self._use_watering_item_visiting(client_id, current_player_data, current_username, target_player_data, target_username, target_lot, lot_index, item_name)
elif use_type == "remove":
# 铲子可以清除任何作物,包括成熟的
return self._use_removal_item_visiting(client_id, current_player_data, current_username, target_player_data, target_username, target_lot, lot_index, item_name)
elif use_type == "weed_killer":
# 除草剂可以清除任何杂草,包括成熟的
return self._use_weed_killer_item_visiting(client_id, current_player_data, current_username, target_player_data, target_username, target_lot, lot_index, item_name)
elif use_type == "harvest":
# 采集道具只能对成熟的作物使用
if target_lot.get("grow_time", 0) < target_lot.get("max_grow_time", 1):
return self._send_action_error(client_id, "use_item", "作物还未成熟,无法使用采集道具")
return self._use_harvest_item_visiting(client_id, current_player_data, current_username, target_player_data, target_username, target_lot, lot_index, item_name)
else:
return self._send_action_error(client_id, "use_item", f"不支持的使用类型: {use_type}")
def _use_fertilizer_item(self, client_id, player_data, username, lot, lot_index, item_name):
"""使用施肥类道具"""
# 检查是否已经施过肥
if lot.get("已施肥", False):
return self._send_action_error(client_id, "use_item", "此作物已经施过肥了")
# 移除道具
if not self._remove_item_from_inventory(player_data, item_name, 1):
return self._send_action_error(client_id, "use_item", f"移除道具 {item_name} 失败")
# 生成随机经验奖励
experience_reward = random.randint(50, 150)
player_data["experience"] += experience_reward
# 检查是否升级
self._check_level_up(player_data)
# 根据道具类型设置不同的施肥效果
current_time = time.time()
if item_name == "农家肥":
# 30分钟内2倍速生长
lot["已施肥"] = True
lot["施肥时间"] = current_time
lot["施肥类型"] = "农家肥"
lot["施肥倍数"] = 2.0
lot["施肥持续时间"] = 1800 # 30分钟
message = f"使用 {item_name} 成功作物将在30分钟内以2倍速度生长"
elif item_name == "金坷垃":
# 5分钟内5倍速生长
lot["已施肥"] = True
lot["施肥时间"] = current_time
lot["施肥类型"] = "金坷垃"
lot["施肥倍数"] = 5.0
lot["施肥持续时间"] = 300 # 5分钟
message = f"使用 {item_name} 成功作物将在5分钟内以5倍速度生长"
elif item_name == "生长素":
# 10分钟内3倍速生长
lot["已施肥"] = True
lot["施肥时间"] = current_time
lot["施肥类型"] = "生长素"
lot["施肥倍数"] = 3.0
lot["施肥持续时间"] = 600 # 10分钟
message = f"使用 {item_name} 成功作物将在10分钟内以3倍速度生长"
else:
return self._send_action_error(client_id, "use_item", f"不支持的施肥道具: {item_name}")
# 保存玩家数据
self.save_player_data(username, player_data)
# 发送作物更新
self._push_crop_update_to_player(username, player_data)
crop_type = lot.get("crop_type", "未知作物")
self.log('INFO', f"玩家 {username} 对地块 {lot_index}{crop_type} 使用了 {item_name},获得 {experience_reward} 经验", 'SERVER')
return self.send_data(client_id, {
"type": "action_response",
"action_type": "use_item",
"success": True,
"message": f"{message},获得 {experience_reward} 经验",
"updated_data": {
"experience": player_data["experience"],
"level": player_data["level"],
"farm_lots": player_data["farm_lots"],
"道具背包": player_data["道具背包"]
}
})
def _use_watering_item(self, client_id, player_data, username, lot, lot_index, item_name):
"""使用浇水类道具"""
# 移除道具
if not self._remove_item_from_inventory(player_data, item_name, 1):
return self._send_action_error(client_id, "use_item", f"移除道具 {item_name} 失败")
# 生成随机经验奖励
experience_reward = random.randint(30, 100)
player_data["experience"] += experience_reward
# 检查是否升级
self._check_level_up(player_data)
# 根据道具类型计算浇水效果
if item_name == "水壶":
# 增加1%的生长进度
growth_increase = int(lot["max_grow_time"] * 0.01)
message = f"使用 {item_name} 成功作物生长进度增加了1%"
elif item_name == "水桶":
# 增加2%的生长进度
growth_increase = int(lot["max_grow_time"] * 0.02)
message = f"使用 {item_name} 成功作物生长进度增加了2%"
else:
return self._send_action_error(client_id, "use_item", f"不支持的浇水道具: {item_name}")
if growth_increase < 1:
growth_increase = 1 # 至少增加1秒
lot["grow_time"] += growth_increase
# 确保不超过最大生长时间
if lot["grow_time"] > lot["max_grow_time"]:
lot["grow_time"] = lot["max_grow_time"]
# 记录浇水时间戳
lot["浇水时间"] = time.time()
# 保存玩家数据
self.save_player_data(username, player_data)
# 发送作物更新
self._push_crop_update_to_player(username, player_data)
crop_type = lot.get("crop_type", "未知作物")
progress = (lot["grow_time"] / lot["max_grow_time"]) * 100
self.log('INFO', f"玩家 {username} 对地块 {lot_index}{crop_type} 使用了 {item_name},生长进度: {progress:.1f}%,获得 {experience_reward} 经验", 'SERVER')
final_message = f"{message},当前进度: {progress:.1f}%,获得 {experience_reward} 经验"
if lot["grow_time"] >= lot["max_grow_time"]:
final_message += ",作物已成熟!"
return self.send_data(client_id, {
"type": "action_response",
"action_type": "use_item",
"success": True,
"message": final_message,
"updated_data": {
"experience": player_data["experience"],
"level": player_data["level"],
"farm_lots": player_data["farm_lots"],
"道具背包": player_data["道具背包"]
}
})
def _use_fertilizer_item_visiting(self, client_id, current_player_data, current_username, target_player_data, target_username, target_lot, lot_index, item_name):
"""访问模式下使用施肥类道具"""
# 检查是否已经施过肥
if target_lot.get("已施肥", False):
return self._send_action_error(client_id, "use_item", "此作物已经施过肥了")
# 移除当前玩家的道具
if not self._remove_item_from_inventory(current_player_data, item_name, 1):
return self._send_action_error(client_id, "use_item", f"移除道具 {item_name} 失败")
# 生成随机经验奖励给当前玩家
experience_reward = random.randint(50, 150)
current_player_data["experience"] += experience_reward
# 检查当前玩家是否升级
self._check_level_up(current_player_data)
# 根据道具类型设置不同的施肥效果
current_time = time.time()
if item_name == "农家肥":
# 30分钟内2倍速生长
target_lot["已施肥"] = True
target_lot["施肥时间"] = current_time
target_lot["施肥类型"] = "农家肥"
target_lot["施肥倍数"] = 2.0
target_lot["施肥持续时间"] = 1800 # 30分钟
message = f"帮助施肥成功!{target_username} 的作物将在30分钟内以2倍速度生长"
elif item_name == "金坷垃":
# 5分钟内5倍速生长
target_lot["已施肥"] = True
target_lot["施肥时间"] = current_time
target_lot["施肥类型"] = "金坷垃"
target_lot["施肥倍数"] = 5.0
target_lot["施肥持续时间"] = 300 # 5分钟
message = f"帮助施肥成功!{target_username} 的作物将在5分钟内以5倍速度生长"
elif item_name == "生长素":
# 10分钟内3倍速生长
target_lot["已施肥"] = True
target_lot["施肥时间"] = current_time
target_lot["施肥类型"] = "生长素"
target_lot["施肥倍数"] = 3.0
target_lot["施肥持续时间"] = 600 # 10分钟
message = f"帮助施肥成功!{target_username} 的作物将在10分钟内以3倍速度生长"
else:
return self._send_action_error(client_id, "use_item", f"不支持的施肥道具: {item_name}")
# 保存两个玩家的数据
self.save_player_data(current_username, current_player_data)
self.save_player_data(target_username, target_player_data)
# 向目标玩家推送作物更新
self._push_crop_update_to_player(target_username, target_player_data)
crop_type = target_lot.get("crop_type", "未知作物")
self.log('INFO', f"玩家 {current_username} 帮助玩家 {target_username} 对地块 {lot_index}{crop_type} 使用了 {item_name},获得 {experience_reward} 经验", 'SERVER')
return self.send_data(client_id, {
"type": "action_response",
"action_type": "use_item",
"success": True,
"message": f"{message},获得 {experience_reward} 经验",
"updated_data": {
"experience": current_player_data["experience"],
"level": current_player_data["level"],
"道具背包": current_player_data["道具背包"]
}
})
def _use_watering_item_visiting(self, client_id, current_player_data, current_username, target_player_data, target_username, target_lot, lot_index, item_name):
"""访问模式下使用浇水类道具"""
# 移除当前玩家的道具
if not self._remove_item_from_inventory(current_player_data, item_name, 1):
return self._send_action_error(client_id, "use_item", f"移除道具 {item_name} 失败")
# 生成随机经验奖励给当前玩家
experience_reward = random.randint(30, 100)
current_player_data["experience"] += experience_reward
# 检查当前玩家是否升级
self._check_level_up(current_player_data)
# 根据道具类型计算浇水效果
if item_name == "水壶":
# 增加1%的生长进度
growth_increase = int(target_lot["max_grow_time"] * 0.01)
message = f"帮助浇水成功!{target_username} 的作物生长进度增加了1%"
elif item_name == "水桶":
# 增加2%的生长进度
growth_increase = int(target_lot["max_grow_time"] * 0.02)
message = f"帮助浇水成功!{target_username} 的作物生长进度增加了2%"
else:
return self._send_action_error(client_id, "use_item", f"不支持的浇水道具: {item_name}")
if growth_increase < 1:
growth_increase = 1 # 至少增加1秒
target_lot["grow_time"] += growth_increase
# 确保不超过最大生长时间
if target_lot["grow_time"] > target_lot["max_grow_time"]:
target_lot["grow_time"] = target_lot["max_grow_time"]
# 记录浇水时间戳
target_lot["浇水时间"] = time.time()
# 保存两个玩家的数据
self.save_player_data(current_username, current_player_data)
self.save_player_data(target_username, target_player_data)
# 向目标玩家推送作物更新
self._push_crop_update_to_player(target_username, target_player_data)
crop_type = target_lot.get("crop_type", "未知作物")
progress = (target_lot["grow_time"] / target_lot["max_grow_time"]) * 100
self.log('INFO', f"玩家 {current_username} 帮助玩家 {target_username} 对地块 {lot_index}{crop_type} 使用了 {item_name},生长进度: {progress:.1f}%,获得 {experience_reward} 经验", 'SERVER')
final_message = f"{message},当前进度: {progress:.1f}%,获得 {experience_reward} 经验"
if target_lot["grow_time"] >= target_lot["max_grow_time"]:
final_message += ",作物已成熟!"
return self.send_data(client_id, {
"type": "action_response",
"action_type": "use_item",
"success": True,
"message": final_message,
"updated_data": {
"experience": current_player_data["experience"],
"level": current_player_data["level"],
"道具背包": current_player_data["道具背包"]
}
})
def _use_removal_item(self, client_id, player_data, username, lot, lot_index, item_name):
"""使用铲除类道具(铲子)"""
# 检查玩家是否有这个道具
if not self._has_item_in_inventory(player_data, item_name):
return self._send_action_error(client_id, "use_item", f"您没有 {item_name}")
# 移除道具
if not self._remove_item_from_inventory(player_data, item_name, 1):
return self._send_action_error(client_id, "use_item", f"移除道具 {item_name} 失败")
# 生成随机经验奖励
experience_reward = random.randint(20, 60)
player_data["experience"] += experience_reward
# 检查是否升级
self._check_level_up(player_data)
# 获取作物名称用于日志
crop_type = lot.get("crop_type", "未知作物")
# 执行铲除操作
lot["is_planted"] = False
lot["crop_type"] = ""
lot["grow_time"] = 0
lot["is_dead"] = False # 重置死亡状态
lot["已浇水"] = False # 重置浇水状态
lot["已施肥"] = False # 重置施肥状态
# 保存玩家数据
self.save_player_data(username, player_data)
# 发送作物更新
self._push_crop_update_to_player(username, player_data)
self.log('INFO', f"玩家 {username} 使用 {item_name} 铲除了地块 {lot_index} 的作物 {crop_type},获得 {experience_reward} 经验", 'SERVER')
return self.send_data(client_id, {
"type": "action_response",
"action_type": "use_item",
"success": True,
"message": f"使用 {item_name} 成功铲除作物 {crop_type},获得 {experience_reward} 经验",
"updated_data": {
"experience": player_data["experience"],
"level": player_data["level"],
"farm_lots": player_data["farm_lots"],
"道具背包": player_data["道具背包"]
}
})
def _use_weed_killer_item(self, client_id, player_data, username, lot, lot_index, item_name):
"""使用除草剂"""
# 检查是否为杂草
crop_type = lot.get("crop_type", "")
crop_data = self._load_crop_data()
if not crop_data or crop_type not in crop_data:
return self._send_action_error(client_id, "use_item", f"未知的作物类型: {crop_type}")
is_weed = crop_data[crop_type].get("是否杂草", False)
if not is_weed:
return self._send_action_error(client_id, "use_item", "除草剂只能用于清除杂草,此作物不是杂草")
# 检查玩家是否有这个道具
if not self._has_item_in_inventory(player_data, item_name):
return self._send_action_error(client_id, "use_item", f"您没有 {item_name}")
# 移除道具
if not self._remove_item_from_inventory(player_data, item_name, 1):
return self._send_action_error(client_id, "use_item", f"移除道具 {item_name} 失败")
# 生成随机经验奖励
experience_reward = random.randint(15, 50)
player_data["experience"] += experience_reward
# 检查是否升级
self._check_level_up(player_data)
# 执行除草操作
lot["is_planted"] = False
lot["crop_type"] = ""
lot["grow_time"] = 0
lot["is_dead"] = False # 重置死亡状态
lot["已浇水"] = False # 重置浇水状态
lot["已施肥"] = False # 重置施肥状态
# 保存玩家数据
self.save_player_data(username, player_data)
# 发送作物更新
self._push_crop_update_to_player(username, player_data)
self.log('INFO', f"玩家 {username} 使用 {item_name} 清除了地块 {lot_index} 的杂草 {crop_type},获得 {experience_reward} 经验", 'SERVER')
return self.send_data(client_id, {
"type": "action_response",
"action_type": "use_item",
"success": True,
"message": f"使用 {item_name} 成功清除杂草 {crop_type},获得 {experience_reward} 经验",
"updated_data": {
"experience": player_data["experience"],
"level": player_data["level"],
"farm_lots": player_data["farm_lots"],
"道具背包": player_data["道具背包"]
}
})
def _use_removal_item_visiting(self, client_id, current_player_data, current_username, target_player_data, target_username, target_lot, lot_index, item_name):
"""访问模式下使用铲除道具"""
# 检查当前玩家是否有这个道具
if not self._has_item_in_inventory(current_player_data, item_name):
return self._send_action_error(client_id, "use_item", f"您没有 {item_name}")
# 移除当前玩家的道具
if not self._remove_item_from_inventory(current_player_data, item_name, 1):
return self._send_action_error(client_id, "use_item", f"移除道具 {item_name} 失败")
# 生成随机经验奖励给当前玩家
experience_reward = random.randint(20, 60)
current_player_data["experience"] += experience_reward
# 检查当前玩家是否升级
self._check_level_up(current_player_data)
# 获取作物名称用于日志
crop_type = target_lot.get("crop_type", "未知作物")
# 执行铲除操作
target_lot["is_planted"] = False
target_lot["crop_type"] = ""
target_lot["grow_time"] = 0
target_lot["is_dead"] = False # 重置死亡状态
target_lot["已浇水"] = False # 重置浇水状态
target_lot["已施肥"] = False # 重置施肥状态
# 保存两个玩家的数据
self.save_player_data(current_username, current_player_data)
self.save_player_data(target_username, target_player_data)
# 向目标玩家推送作物更新
self._push_crop_update_to_player(target_username, target_player_data)
self.log('INFO', f"玩家 {current_username} 帮助玩家 {target_username} 使用 {item_name} 铲除了地块 {lot_index} 的作物 {crop_type},获得 {experience_reward} 经验", 'SERVER')
return self.send_data(client_id, {
"type": "action_response",
"action_type": "use_item",
"success": True,
"message": f"帮助 {target_username} 铲除作物 {crop_type} 成功,获得 {experience_reward} 经验",
"updated_data": {
"experience": current_player_data["experience"],
"level": current_player_data["level"],
"道具背包": current_player_data["道具背包"]
}
})
def _use_weed_killer_item_visiting(self, client_id, current_player_data, current_username, target_player_data, target_username, target_lot, lot_index, item_name):
"""访问模式下使用除草剂"""
# 检查是否为杂草
crop_type = target_lot.get("crop_type", "")
crop_data = self._load_crop_data()
if not crop_data or crop_type not in crop_data:
return self._send_action_error(client_id, "use_item", f"未知的作物类型: {crop_type}")
is_weed = crop_data[crop_type].get("是否杂草", False)
if not is_weed:
return self._send_action_error(client_id, "use_item", "除草剂只能用于清除杂草,此作物不是杂草")
# 检查当前玩家是否有这个道具
if not self._has_item_in_inventory(current_player_data, item_name):
return self._send_action_error(client_id, "use_item", f"您没有 {item_name}")
# 移除当前玩家的道具
if not self._remove_item_from_inventory(current_player_data, item_name, 1):
return self._send_action_error(client_id, "use_item", f"移除道具 {item_name} 失败")
# 生成随机经验奖励给当前玩家
experience_reward = random.randint(15, 50)
current_player_data["experience"] += experience_reward
# 检查当前玩家是否升级
self._check_level_up(current_player_data)
# 执行除草操作
target_lot["is_planted"] = False
target_lot["crop_type"] = ""
target_lot["grow_time"] = 0
target_lot["is_dead"] = False # 重置死亡状态
target_lot["已浇水"] = False # 重置浇水状态
target_lot["已施肥"] = False # 重置施肥状态
# 保存两个玩家的数据
self.save_player_data(current_username, current_player_data)
self.save_player_data(target_username, target_player_data)
# 向目标玩家推送作物更新
self._push_crop_update_to_player(target_username, target_player_data)
self.log('INFO', f"玩家 {current_username} 帮助玩家 {target_username} 使用 {item_name} 清除了地块 {lot_index} 的杂草 {crop_type},获得 {experience_reward} 经验", 'SERVER')
return self.send_data(client_id, {
"type": "action_response",
"action_type": "use_item",
"success": True,
"message": f"帮助 {target_username} 清除杂草 {crop_type} 成功,获得 {experience_reward} 经验",
"updated_data": {
"experience": current_player_data["experience"],
"level": current_player_data["level"],
"道具背包": current_player_data["道具背包"]
}
})
def _use_harvest_item(self, client_id, player_data, username, lot, lot_index, item_name):
"""使用采集道具(精准采集锄、时运锄)"""
# 移除道具
if not self._remove_item_from_inventory(player_data, item_name, 1):
return self._send_action_error(client_id, "use_item", f"移除道具 {item_name} 失败")
# 读取作物配置
crop_data = self._load_crop_data()
# 获取作物类型
crop_type = lot["crop_type"]
# 检查是否为杂草类型(杂草不能用采集道具收获)
if crop_type in crop_data:
crop_info = crop_data[crop_type]
is_weed = crop_info.get("是否杂草", False)
if is_weed:
return self._send_action_error(client_id, "use_item", f"{crop_type}不能使用采集道具收获,只能铲除!")
crop_exp = crop_info.get("经验", 10)
# 额外检查:如果作物收益为负数,也视为杂草
crop_income = crop_info.get("收益", 100) + crop_info.get("花费", 0)
if crop_income < 0:
return self._send_action_error(client_id, "use_item", f"{crop_type}不能使用采集道具收获,只能铲除!")
else:
# 默认经验
crop_exp = 10
# 道具特殊效果
import random
if item_name == "精准采集锄":
# 精准采集锄收获数量正常1-5个但必定掉落种子
harvest_count = random.randint(1, 5)
# 100%概率获得2-4个该作物的种子
seed_reward = {
"name": crop_type + "种子",
"count": random.randint(2, 4)
}
message_suffix = ",精准采集锄确保了种子的获得"
elif item_name == "时运锄":
# 时运锄收获数量更多3-8个种子掉落率正常
harvest_count = random.randint(3, 8)
# 15%概率获得1-3个该作物的种子稍微提高
seed_reward = None
if random.random() < 0.15:
seed_reward = {
"name": crop_type + "种子",
"count": random.randint(1, 3)
}
message_suffix = ",时运锄增加了收获数量"
else:
return self._send_action_error(client_id, "use_item", f"不支持的采集道具: {item_name}")
# 生成采集奖励经验
experience_reward = random.randint(30, 80)
crop_exp += experience_reward
# 创建收获物
crop_harvest = {
"name": crop_type,
"count": harvest_count
}
# 更新玩家经验
player_data["experience"] += crop_exp
# 检查是否升级
self._check_level_up(player_data)
# 添加成熟物到作物仓库
self._add_crop_to_warehouse(player_data, crop_harvest)
# 添加种子奖励到背包
if seed_reward:
self._add_seeds_to_bag(player_data, seed_reward)
# 清理地块
lot["is_planted"] = False
lot["crop_type"] = ""
lot["grow_time"] = 0
lot["已浇水"] = False
lot["已施肥"] = False
# 清除施肥时间戳
if "施肥时间" in lot:
del lot["施肥时间"]
# 保存玩家数据
self.save_player_data(username, player_data)
# 发送作物更新
self._push_crop_update_to_player(username, player_data)
# 构建消息
message = f"使用 {item_name} 收获成功,获得 {crop_type} x{harvest_count}{crop_exp} 经验{message_suffix}"
if seed_reward:
message += f",额外获得 {seed_reward['name']} x{seed_reward['count']}"
self.log('INFO', f"玩家 {username} 使用 {item_name} 从地块 {lot_index} 收获了作物,获得 {crop_type} x{harvest_count}{crop_exp} 经验" + (f",额外获得 {seed_reward['name']} x{seed_reward['count']}" if seed_reward else ""), 'SERVER')
return self.send_data(client_id, {
"type": "action_response",
"action_type": "use_item",
"success": True,
"message": message,
"updated_data": {
"experience": player_data["experience"],
"level": player_data["level"],
"player_bag": player_data.get("player_bag", []),
"作物仓库": player_data.get("作物仓库", []),
"道具背包": player_data.get("道具背包", [])
}
})
def _use_harvest_item_visiting(self, client_id, current_player_data, current_username, target_player_data, target_username, target_lot, lot_index, item_name):
"""访问模式下使用采集道具"""
# 移除当前玩家的道具
if not self._remove_item_from_inventory(current_player_data, item_name, 1):
return self._send_action_error(client_id, "use_item", f"移除道具 {item_name} 失败")
# 读取作物配置
crop_data = self._load_crop_data()
# 获取作物类型
crop_type = target_lot["crop_type"]
# 检查是否为杂草类型(杂草不能用采集道具收获)
if crop_type in crop_data:
crop_info = crop_data[crop_type]
is_weed = crop_info.get("是否杂草", False)
if is_weed:
return self._send_action_error(client_id, "use_item", f"{crop_type}不能使用采集道具收获,只能铲除!")
crop_exp = int(crop_info.get("经验", 10) * 0.7) # 访问模式获得70%经验
# 额外检查:如果作物收益为负数,也视为杂草
crop_income = crop_info.get("收益", 100) + crop_info.get("花费", 0)
if crop_income < 0:
return self._send_action_error(client_id, "use_item", f"{crop_type}不能使用采集道具收获,只能铲除!")
else:
# 默认经验
crop_exp = 7
# 道具特殊效果(访问模式稍微降低效果)
import random
if item_name == "精准采集锄":
# 精准采集锄收获数量稍少1-4个但必定掉落种子
harvest_count = random.randint(1, 4)
# 100%概率获得1-3个该作物的种子
seed_reward = {
"name": crop_type + "种子",
"count": random.randint(1, 3)
}
message_suffix = ",精准采集锄确保了种子的获得"
elif item_name == "时运锄":
# 时运锄收获数量较多2-6个种子掉落率正常
harvest_count = random.randint(2, 6)
# 10%概率获得1-2个该作物的种子
seed_reward = None
if random.random() < 0.10:
seed_reward = {
"name": crop_type + "种子",
"count": random.randint(1, 2)
}
message_suffix = ",时运锄增加了收获数量"
else:
return self._send_action_error(client_id, "use_item", f"不支持的采集道具: {item_name}")
# 生成帮助采集奖励经验
experience_reward = random.randint(20, 60)
crop_exp += experience_reward
# 创建收获物
crop_harvest = {
"name": crop_type,
"count": harvest_count
}
# 更新当前玩家经验
current_player_data["experience"] += crop_exp
# 检查当前玩家是否升级
self._check_level_up(current_player_data)
# 收获物给当前玩家
self._add_crop_to_warehouse(current_player_data, crop_harvest)
# 种子奖励给当前玩家
if seed_reward:
self._add_seeds_to_bag(current_player_data, seed_reward)
# 清理目标玩家的地块
target_lot["is_planted"] = False
target_lot["crop_type"] = ""
target_lot["grow_time"] = 0
target_lot["已浇水"] = False
target_lot["已施肥"] = False
# 清除施肥时间戳
if "施肥时间" in target_lot:
del target_lot["施肥时间"]
# 保存两个玩家的数据
self.save_player_data(current_username, current_player_data)
self.save_player_data(target_username, target_player_data)
# 向目标玩家推送作物更新(如果在线)
self._push_crop_update_to_player(target_username, target_player_data)
# 构建消息
message = f"使用 {item_name} 帮助收获成功!从 {target_username} 那里获得 {crop_type} x{harvest_count}{crop_exp} 经验{message_suffix}"
if seed_reward:
message += f",额外获得 {seed_reward['name']} x{seed_reward['count']}"
self.log('INFO', f"玩家 {current_username} 使用 {item_name} 帮助玩家 {target_username} 收获地块 {lot_index} 的作物,获得 {crop_type} x{harvest_count}{crop_exp} 经验" + (f",额外获得 {seed_reward['name']} x{seed_reward['count']}" if seed_reward else ""), 'SERVER')
return self.send_data(client_id, {
"type": "action_response",
"action_type": "use_item",
"success": True,
"message": message,
"updated_data": {
"experience": current_player_data["experience"],
"level": current_player_data["level"],
"player_bag": current_player_data.get("player_bag", []),
"作物仓库": current_player_data.get("作物仓库", []),
"道具背包": current_player_data.get("道具背包", [])
}
})
#==========================道具使用处理==========================
#==========================升级土地处理==========================
#处理升级土地请求
def _handle_upgrade_land(self, client_id, message):
"""处理升级土地请求"""
# 检查用户是否已登录
logged_in, response = self._check_user_logged_in(client_id, "升级土地", "upgrade_land")
if not logged_in:
return self.send_data(client_id, response)
# 获取玩家数据
player_data, username, response = self._load_player_data_with_check(client_id, "upgrade_land")
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, "upgrade_land", "无效的地块索引")
lot = player_data["farm_lots"][lot_index]
# 检查地块是否已开垦
if not lot.get("is_diged", False):
return self._send_action_error(client_id, "upgrade_land", "此地块尚未开垦")
# 处理升级
return self._process_land_upgrade(client_id, player_data, username, lot, lot_index)
#辅助函数-处理土地升级逻辑
def _process_land_upgrade(self, client_id, player_data, username, lot, lot_index):
"""处理土地升级逻辑"""
# 土地升级配置
upgrade_config = {
0: {"cost": 1000, "name": "黄土地", "speed": 2.0}, # 0级->1级1000元2倍速
1: {"cost": 2000, "name": "红土地", "speed": 4.0}, # 1级->2级2000元4倍速
2: {"cost": 4000, "name": "紫土地", "speed": 6.0}, # 2级->3级4000元6倍速
3: {"cost": 8000, "name": "黑土地", "speed": 10.0} # 3级->4级8000元10倍速
}
# 获取当前土地等级
current_level = lot.get("土地等级", 0)
# 检查是否已达到最高等级
if current_level >= 4:
return self._send_action_error(client_id, "upgrade_land", "此土地已达到最高等级(黑土地)")
# 检查升级配置是否存在
if current_level not in upgrade_config:
return self._send_action_error(client_id, "upgrade_land", f"土地等级数据异常,当前等级: {current_level}")
# 获取升级配置
config = upgrade_config[current_level]
upgrade_cost = config["cost"]
next_name = config["name"]
next_level = current_level + 1
speed_multiplier = config["speed"]
# 检查玩家金钱是否足够
if player_data["money"] < upgrade_cost:
return self._send_action_error(client_id, "upgrade_land", f"金钱不足,升级到{next_name}需要 {upgrade_cost} 金钱")
# 执行升级操作
player_data["money"] -= upgrade_cost
lot["土地等级"] = next_level
# 保存玩家数据
self.save_player_data(username, player_data)
# 发送作物更新
self._push_crop_update_to_player(username, player_data)
self.log('INFO', f"玩家 {username} 将地块 {lot_index} 升级到{next_level}{next_name},花费 {upgrade_cost} 金钱", 'SERVER')
return self.send_data(client_id, {
"type": "action_response",
"action_type": "upgrade_land",
"success": True,
"message": f"土地升级成功!升级到{next_level}{next_name},作物将以{speed_multiplier}倍速度生长",
"updated_data": {
"money": player_data["money"],
"farm_lots": player_data["farm_lots"]
}
})
#==========================升级土地处理==========================
#==========================购买新地块处理==========================
#处理购买新地块请求
def _handle_buy_new_ground(self, client_id, message):
"""处理购买新地块请求"""
# 检查用户是否已登录
logged_in, response = self._check_user_logged_in(client_id, "购买新地块", "buy_new_ground")
if not logged_in:
return self.send_data(client_id, response)
# 获取玩家数据
player_data, username, response = self._load_player_data_with_check(client_id, "buy_new_ground")
if not player_data:
return self.send_data(client_id, response)
# 处理购买新地块
return self._process_buy_new_ground(client_id, player_data, username)
#辅助函数-处理购买新地块逻辑
def _process_buy_new_ground(self, client_id, player_data, username):
"""处理购买新地块逻辑"""
# 购买新地块费用
new_ground_cost = 2000
# 检查玩家金钱是否足够
if player_data["money"] < new_ground_cost:
return self._send_action_error(client_id, "buy_new_ground", f"金钱不足,购买新地块需要 {new_ground_cost} 金钱")
# 检查地块数量限制
max_lots = 1000 # 最大地块数量限制
current_lots = len(player_data.get("farm_lots", []))
if current_lots >= max_lots:
return self._send_action_error(client_id, "buy_new_ground", f"已达到最大地块数量限制({max_lots}个)")
# 执行购买操作
player_data["money"] -= new_ground_cost
# 创建新的未开垦地块
new_lot = {
"crop_type": "",
"grow_time": 0,
"is_dead": False,
"is_diged": False, # 新购买的地块默认未开垦
"is_planted": False,
"max_grow_time": 5,
"已浇水": False,
"已施肥": False,
"土地等级": 0
}
# 添加到农场地块数组
if "farm_lots" not in player_data:
player_data["farm_lots"] = []
player_data["farm_lots"].append(new_lot)
# 保存玩家数据
self.save_player_data(username, player_data)
# 发送作物更新
self._push_crop_update_to_player(username, player_data)
new_lot_index = len(player_data["farm_lots"])
self.log('INFO', f"玩家 {username} 成功购买新地块,花费 {new_ground_cost} 金钱,新地块位置:{new_lot_index}", 'SERVER')
return self.send_data(client_id, {
"type": "action_response",
"action_type": "buy_new_ground",
"success": True,
"message": f"购买新地块成功!花费 {new_ground_cost} 元,新地块位置:{new_lot_index}",
"updated_data": {
"money": player_data["money"],
"farm_lots": player_data["farm_lots"]
}
})
#==========================购买新地块处理==========================
#==========================点赞玩家处理==========================
#处理玩家点赞请求
def _handle_like_player(self, client_id, message):
"""处理点赞请求"""
# 检查用户是否已登录
logged_in, response = self._check_user_logged_in(client_id, "点赞玩家", "like_player")
if not logged_in:
return self.send_data(client_id, response)
# 获取玩家数据
player_data, username, response = self._load_player_data_with_check(client_id, "like_player")
if not player_data:
return self.send_data(client_id, response)
target_username = message.get("target_username", "")
if not target_username:
return self.send_data(client_id, {
"type": "like_player_response",
"success": False,
"message": "缺少目标用户名"
})
# 不能给自己点赞
if target_username == username:
return self.send_data(client_id, {
"type": "like_player_response",
"success": False,
"message": "不能给自己点赞"
})
# 检查今天是否已经给这个玩家点过赞
current_date = datetime.datetime.now().strftime("%Y-%m-%d")
# 初始化点赞记录
if "daily_likes" not in player_data:
player_data["daily_likes"] = {}
# 检查今天的点赞记录
if current_date not in player_data["daily_likes"]:
player_data["daily_likes"][current_date] = []
if target_username in player_data["daily_likes"][current_date]:
return self.send_data(client_id, {
"type": "like_player_response",
"success": False,
"message": f"今天已经给 {target_username} 点过赞了"
})
# 加载目标玩家数据
target_player_data = self.load_player_data(target_username)
if not target_player_data:
return self.send_data(client_id, {
"type": "like_player_response",
"success": False,
"message": f"无法找到玩家 {target_username} 的数据"
})
# 记录点赞
player_data["daily_likes"][current_date].append(target_username)
# 更新目标玩家的点赞数量
target_player_data["total_likes"] = target_player_data.get("total_likes", 0) + 1
# 保存两个玩家的数据
self.save_player_data(username, player_data)
self.save_player_data(target_username, target_player_data)
self.log('INFO', f"玩家 {username} 点赞了玩家 {target_username},目标玩家总赞数:{target_player_data['total_likes']}", 'SERVER')
return self.send_data(client_id, {
"type": "like_player_response",
"success": True,
"message": f"成功点赞玩家 {target_username}",
"target_likes": target_player_data["total_likes"]
})
#==========================点赞玩家处理==========================
#==========================在线玩家处理==========================
#处理请求在线玩家请求
def _handle_online_players_request(self, client_id, message):
"""处理获取在线玩家数量的请求"""
online_players = len([cid for cid in self.user_data if self.user_data[cid].get("logged_in", False)])
return self.send_data(client_id, {
"type": "online_players_response",
"success": True,
"online_players": online_players
})
#==========================在线玩家处理==========================
#==========================玩家体力值处理==========================
#检查并更新体力值
def _check_and_update_stamina(self, player_data):
"""检查并更新体力值每小时恢复1点每天重置"""
import datetime
current_time = time.time()
current_date = datetime.datetime.now().strftime("%Y-%m-%d")
# 初始化体力值相关字段
if "体力值" not in player_data:
player_data["体力值"] = 20
if "体力上次刷新时间" not in player_data:
player_data["体力上次刷新时间"] = current_date
if "体力上次恢复时间" not in player_data:
player_data["体力上次恢复时间"] = current_time
# 检查是否需要每日重置
last_refresh_date = player_data.get("体力上次刷新时间", "")
if last_refresh_date != current_date:
# 新的一天,重置体力值
player_data["体力值"] = 20
player_data["体力上次刷新时间"] = current_date
player_data["体力上次恢复时间"] = current_time
return True # 发生了重置
# 检查每小时恢复
last_recovery_time = player_data.get("体力上次恢复时间", current_time)
time_diff = current_time - last_recovery_time
# 如果超过1小时3600秒恢复体力值
if time_diff >= 3600:
hours_passed = int(time_diff // 3600)
current_stamina = player_data.get("体力值", 0)
# 体力值恢复但不能超过20
new_stamina = min(20, current_stamina + hours_passed)
if new_stamina > current_stamina:
player_data["体力值"] = new_stamina
player_data["体力上次恢复时间"] = current_time
return True # 发生了恢复
return False # 没有变化
#消耗体力值
def _consume_stamina(self, player_data, amount, action_name):
"""消耗体力值"""
current_stamina = player_data.get("体力值", 20)
if current_stamina < amount:
return False, f"体力值不足!{action_name}需要 {amount} 点体力,当前体力:{current_stamina}"
player_data["体力值"] = current_stamina - amount
return True, f"消耗 {amount} 点体力,剩余体力:{player_data['体力值']}"
#检查体力值是否足够
def _check_stamina_sufficient(self, player_data, amount):
"""检查体力值是否足够"""
current_stamina = player_data.get("体力值", 20)
return current_stamina >= amount
def _check_and_update_register_time(self, player_data, username):
"""检查并更新已存在玩家的注册时间"""
default_register_time = "2025年05月21日15时00分00秒"
# 如果玩家没有注册时间字段,设为默认值(老玩家)
if "注册时间" not in player_data:
player_data["注册时间"] = default_register_time
self.save_player_data(username, player_data)
self.log('INFO', f"为已存在玩家 {username} 设置默认注册时间", 'SERVER')
#==========================玩家体力值处理==========================
#==========================玩家游玩时间处理==========================
#处理获取玩家游玩时间请求
def _handle_get_play_time(self, client_id):
"""处理获取游玩时间请求"""
# 检查用户是否已登录
logged_in, response = self._check_user_logged_in(client_id, "获取游玩时间")
if not logged_in:
return self.send_data(client_id, response)
# 获取玩家数据
player_data, username, response = self._load_player_data_with_check(client_id, "play_time")
if not player_data:
return self.send_data(client_id, response)
# 计算当前会话的游玩时间
login_timestamp = self.user_data[client_id].get("login_timestamp", time.time())
current_session_seconds = int(time.time() - login_timestamp)
# 格式化当前会话时间
current_hours = current_session_seconds // 3600
current_minutes = (current_session_seconds % 3600) // 60
current_seconds = current_session_seconds % 60
current_session_time = f"{current_hours}{current_minutes}{current_seconds}"
# 获取最后登录时间和总游玩时间
last_login_time = player_data.get("last_login_time", "未知")
total_login_time = player_data.get("total_login_time", "0时0分0秒")
self.log('INFO', f"玩家 {username} 请求游玩时间统计", 'SERVER')
return self.send_data(client_id, {
"type": "play_time_response",
"success": True,
"last_login_time": last_login_time,
"total_login_time": total_login_time,
"current_session_time": current_session_time
})
#处理更新游玩时间请求
def _handle_update_play_time(self, client_id):
"""处理更新游玩时间请求"""
# 检查用户是否已登录
logged_in, response = self._check_user_logged_in(client_id, "更新游玩时间", "update_time")
if not logged_in:
return self.send_data(client_id, response)
# 获取玩家数据
player_data, username, response = self._load_player_data_with_check(client_id, "update_time")
if not player_data:
return self.send_data(client_id, response)
# 计算当前会话的游玩时间
login_timestamp = self.user_data[client_id].get("login_timestamp", time.time())
play_time_seconds = int(time.time() - login_timestamp)
# 解析现有的总游玩时间
total_time_str = player_data.get("total_login_time", "0时0分0秒")
time_parts = re.match(r"(?:(\d+)时)?(?:(\d+)分)?(?:(\d+)秒)?", total_time_str)
if time_parts:
hours = int(time_parts.group(1) or 0)
minutes = int(time_parts.group(2) or 0)
seconds = int(time_parts.group(3) or 0)
# 计算新的总游玩时间
total_seconds = hours * 3600 + minutes * 60 + seconds + play_time_seconds
new_hours = total_seconds // 3600
new_minutes = (total_seconds % 3600) // 60
new_seconds = total_seconds % 60
# 更新总游玩时间
player_data["total_login_time"] = f"{new_hours}{new_minutes}{new_seconds}"
# 保存玩家数据
self.save_player_data(username, player_data)
# 重置登录时间戳,以便下次计算
self.user_data[client_id]["login_timestamp"] = time.time()
self.log('INFO', f"已更新玩家 {username} 的游玩时间,当前游玩时间: {play_time_seconds} 秒,总游玩时间: {player_data['total_login_time']}", 'SERVER')
return self.send_data(client_id, {
"type": "update_time_response",
"success": True,
"message": "游玩时间已更新",
"total_login_time": player_data["total_login_time"]
})
else:
self.log('ERROR', f"解析玩家 {username} 的游玩时间失败", 'SERVER')
return self.send_data(client_id, {
"type": "update_time_response",
"success": False,
"message": "更新游玩时间失败,格式错误"
})
#==========================玩家游玩时间处理==========================
#==========================玩家排行榜处理==========================
#处理获取玩家排行榜请求
def _handle_player_rankings_request(self, client_id, message):
"""处理获取玩家排行榜的请求"""
# 检查用户是否已登录
logged_in, response = self._check_user_logged_in(client_id, "获取玩家排行榜", "player_rankings")
if not logged_in:
return self.send_data(client_id, response)
# 获取排序和筛选参数
sort_by = message.get("sort_by", "level") # 排序字段seed_count, level, online_time, login_time, like_num, money
sort_order = message.get("sort_order", "desc") # 排序顺序asc, desc
filter_online = message.get("filter_online", False) # 是否只显示在线玩家
search_qq = message.get("search_qq", "") # 搜索的QQ号
# 获取所有玩家存档文件
save_files = glob.glob(os.path.join("game_saves", "*.json"))
players_data = []
# 统计注册总人数
total_registered_players = len(save_files)
for save_file in save_files:
try:
# 从文件名提取账号ID
account_id = os.path.basename(save_file).split('.')[0]
# 如果有搜索条件,先检查是否匹配
if search_qq and search_qq not in account_id:
continue
# 加载玩家数据
with open(save_file, 'r', encoding='utf-8') as file:
player_data = json.load(file)
if player_data:
# 统计背包中的种子数量
seed_count = sum(item.get("count", 0) for item in player_data.get("player_bag", []))
# 检查玩家是否在线
is_online = any(
user_info.get("username") == account_id and user_info.get("logged_in", False)
for user_info in self.user_data.values()
)
# 如果筛选在线玩家,跳过离线玩家
if filter_online and not is_online:
continue
# 解析总游玩时间为秒数(用于排序)
total_time_str = player_data.get("total_login_time", "0时0分0秒")
total_time_seconds = self._parse_time_to_seconds(total_time_str)
# 解析最后登录时间为时间戳(用于排序)
last_login_str = player_data.get("last_login_time", "未知")
last_login_timestamp = self._parse_login_time_to_timestamp(last_login_str)
# 获取所需的玩家信息
player_info = {
"user_name": player_data.get("user_name", account_id),
"player_name": player_data.get("player_name", player_data.get("user_name", account_id)),
"farm_name": player_data.get("farm_name", ""),
"level": player_data.get("level", 1),
"money": player_data.get("money", 0),
"experience": player_data.get("experience", 0),
"体力值": player_data.get("体力值", 20),
"seed_count": seed_count,
"last_login_time": last_login_str,
"last_login_timestamp": last_login_timestamp,
"total_login_time": total_time_str,
"total_time_seconds": total_time_seconds,
"like_num": player_data.get("total_likes", 0),
"is_online": is_online
}
players_data.append(player_info)
except Exception as e:
self.log('ERROR', f"读取玩家 {account_id} 的数据时出错: {str(e)}", 'SERVER')
# 根据排序参数进行排序
reverse_order = (sort_order == "desc")
if sort_by == "seed_count":
players_data.sort(key=lambda x: x["seed_count"], reverse=reverse_order)
elif sort_by == "level":
players_data.sort(key=lambda x: x["level"], reverse=reverse_order)
elif sort_by == "online_time":
players_data.sort(key=lambda x: x["total_time_seconds"], reverse=reverse_order)
elif sort_by == "login_time":
players_data.sort(key=lambda x: x["last_login_timestamp"], reverse=reverse_order)
elif sort_by == "like_num":
players_data.sort(key=lambda x: x["like_num"], reverse=reverse_order)
elif sort_by == "money":
players_data.sort(key=lambda x: x["money"], reverse=reverse_order)
else:
# 默认按等级排序
players_data.sort(key=lambda x: x["level"], reverse=True)
# 统计在线玩家数量
online_count = sum(1 for player in players_data if player.get("is_online", False))
# 记录日志
search_info = f"搜索QQ{search_qq}" if search_qq else ""
filter_info = ",仅在线玩家" if filter_online else ""
sort_info = f",按{sort_by}{'降序' if reverse_order else '升序'}排序"
self.log('INFO', f"玩家 {self.user_data[client_id].get('username')} 请求玩家排行榜{search_info}{filter_info}{sort_info},返回 {len(players_data)} 个玩家数据,注册总人数:{total_registered_players},在线人数:{online_count}", 'SERVER')
# 返回排行榜数据(包含注册总人数)
return self.send_data(client_id, {
"type": "player_rankings_response",
"success": True,
"players": players_data,
"total_registered_players": total_registered_players,
"sort_by": sort_by,
"sort_order": sort_order,
"filter_online": filter_online,
"search_qq": search_qq
})
# 辅助函数:将时间字符串转换为秒数
def _parse_time_to_seconds(self, time_str):
"""将时间字符串(如'1时30分45秒')转换为总秒数"""
try:
import re
# 使用正则表达式提取时、分、秒
pattern = r'(\d+)时(\d+)分(\d+)秒'
match = re.match(pattern, time_str)
if match:
hours = int(match.group(1))
minutes = int(match.group(2))
seconds = int(match.group(3))
return hours * 3600 + minutes * 60 + seconds
return 0
except:
return 0
# 辅助函数:将登录时间字符串转换为时间戳
def _parse_login_time_to_timestamp(self, login_time_str):
"""将登录时间字符串转换为时间戳用于排序"""
try:
if login_time_str == "未知":
return 0
# 解析格式2024年01月01日12时30分45秒
import datetime
dt = datetime.datetime.strptime(login_time_str, "%Y年%m月%d%H时%M分%S秒")
return dt.timestamp()
except:
return 0
#==========================玩家排行榜处理==========================
#==========================作物数据处理==========================
#处理客户端请求作物数据
def _handle_crop_data_request(self, client_id):
"""处理客户端请求作物数据"""
crop_data = self._load_crop_data()
if crop_data:
self.log('INFO', f"向客户端 {client_id} 发送作物数据", 'SERVER')
return self.send_data(client_id, {
"type": "crop_data_response",
"success": True,
"crop_data": crop_data
})
else:
return self.send_data(client_id, {
"type": "crop_data_response",
"success": False,
"message": "无法读取作物数据"
})
#==========================作物数据处理==========================
#==========================访问其他玩家农场处理==========================
#处理访问其他玩家农场的请求
def _handle_visit_player_request(self, client_id, message):
"""处理访问其他玩家农场的请求"""
# 检查用户是否已登录
logged_in, response = self._check_user_logged_in(client_id, "访问玩家农场", "visit_player")
if not logged_in:
return self.send_data(client_id, response)
target_username = message.get("target_username", "")
if not target_username:
return self.send_data(client_id, {
"type": "visit_player_response",
"success": False,
"message": "缺少目标用户名"
})
# 加载目标玩家数据
target_player_data = self.load_player_data(target_username)
if not target_player_data:
return self.send_data(client_id, {
"type": "visit_player_response",
"success": False,
"message": f"无法找到玩家 {target_username} 的数据"
})
# 返回目标玩家的农场数据(只返回可见的数据,不包含敏感信息如密码)
safe_player_data = {
"user_name": target_player_data.get("user_name", target_username),
"player_name": target_player_data.get("player_name", target_username),
"farm_name": target_player_data.get("farm_name", ""),
"level": target_player_data.get("level", 1),
"money": target_player_data.get("money", 0),
"experience": target_player_data.get("experience", 0),
"体力值": target_player_data.get("体力值", 20),
"farm_lots": target_player_data.get("farm_lots", []),
"player_bag": target_player_data.get("player_bag", []),
"作物仓库": target_player_data.get("作物仓库", []),
"道具背包": target_player_data.get("道具背包", []),
"last_login_time": target_player_data.get("last_login_time", "未知"),
"total_login_time": target_player_data.get("total_login_time", "0时0分0秒"),
"total_likes": target_player_data.get("total_likes", 0)
}
current_username = self.user_data[client_id]["username"]
self.log('INFO', f"玩家 {current_username} 访问了玩家 {target_username} 的农场", 'SERVER')
# 记录玩家的访问状态
self.user_data[client_id]["visiting_mode"] = True
self.user_data[client_id]["visiting_target"] = target_username
return self.send_data(client_id, {
"type": "visit_player_response",
"success": True,
"message": f"成功获取玩家 {target_username} 的农场数据",
"player_data": safe_player_data,
"is_visiting": True
})
#==========================访问其他玩家农场处理==========================
#==========================返回自己农场处理==========================
#处理玩家返回自己农场的请求
def _handle_return_my_farm_request(self, client_id, message):
"""处理玩家返回自己农场的请求"""
# 检查用户是否已登录
logged_in, response = self._check_user_logged_in(client_id, "返回自己农场", "return_my_farm")
if not logged_in:
return self.send_data(client_id, response)
# 获取玩家数据
player_data, username, response = self._load_player_data_with_check(client_id, "return_my_farm")
if not player_data:
return self.send_data(client_id, response)
# 清除访问状态
self.user_data[client_id]["visiting_mode"] = False
self.user_data[client_id]["visiting_target"] = ""
self.log('INFO', f"玩家 {username} 返回了自己的农场", 'SERVER')
# 返回玩家自己的农场数据
return self.send_data(client_id, {
"type": "return_my_farm_response",
"success": True,
"message": "已返回自己的农场",
"player_data": {
"user_name": player_data.get("user_name", username),
"player_name": player_data.get("player_name", username),
"farm_name": player_data.get("farm_name", ""),
"level": player_data.get("level", 1),
"money": player_data.get("money", 0),
"experience": player_data.get("experience", 0),
"体力值": player_data.get("体力值", 20),
"farm_lots": player_data.get("farm_lots", []),
"player_bag": player_data.get("player_bag", []),
"total_likes": player_data.get("total_likes", 0)
},
"is_visiting": False
})
#==========================返回自己农场处理==========================
#==========================在线礼包处理==========================
#处理获取在线礼包数据请求
def _handle_get_online_gift_data_request(self, client_id, message):
"""处理获取在线礼包数据请求"""
# 检查用户是否已登录
logged_in, response = self._check_user_logged_in(client_id, "获取在线礼包数据", "get_online_gift_data")
if not logged_in:
return self.send_data(client_id, response)
# 获取玩家数据
player_data, username, response = self._load_player_data_with_check(client_id, "get_online_gift_data")
if not player_data:
return self.send_data(client_id, response)
# 获取今日在线礼包数据
current_date = datetime.datetime.now().strftime("%Y-%m-%d")
online_gift_data = player_data.get("online_gift", {})
# 检查是否是新的一天,如果是则重置领取状态和在线时间
if current_date not in online_gift_data:
online_gift_data[current_date] = {
"total_online_time": 0.0, # 累计在线时间(秒)
"last_login_time": time.time(), # 最后登录时间
"claimed_gifts": {}
}
player_data["online_gift"] = online_gift_data
self.save_player_data(username, player_data)
today_data = online_gift_data[current_date]
# 更新在线时间 - 只有当前用户在线时才累加时间
current_time = time.time()
if client_id in self.user_data and self.user_data[client_id].get("logged_in", False):
# 计算本次登录的在线时间并累加
login_time = self.user_data[client_id].get("login_timestamp", current_time)
session_online_time = current_time - login_time
# 更新最后登录时间为当前时间,以便下次计算
today_data["last_login_time"] = current_time
else:
session_online_time = 0
# 获取总在线时长
online_duration = today_data.get("total_online_time", 0.0) + session_online_time
return self.send_data(client_id, {
"type": "online_gift_data_response",
"success": True,
"online_start_time": today_data.get("last_login_time", current_time),
"current_online_duration": online_duration,
"claimed_gifts": today_data.get("claimed_gifts", {})
})
#处理领取在线礼包请求
def _handle_claim_online_gift_request(self, client_id, message):
"""处理领取在线礼包请求"""
# 检查用户是否已登录
logged_in, response = self._check_user_logged_in(client_id, "领取在线礼包", "claim_online_gift")
if not logged_in:
return self.send_data(client_id, response)
# 获取玩家数据
player_data, username, response = self._load_player_data_with_check(client_id, "claim_online_gift")
if not player_data:
return self.send_data(client_id, response)
gift_name = message.get("gift_name", "")
if not gift_name:
return self.send_data(client_id, {
"type": "claim_online_gift_response",
"success": False,
"message": "礼包名称不能为空"
})
# 定义在线礼包配置
online_gift_config = {
"1分钟": {
"time_seconds": 60,
"rewards": {
"money": 100,
"experience": 50,
"seeds": [{"name": "小麦", "count": 5}, {"name": "胡萝卜", "count": 3}]
}
},
"3分钟": {
"time_seconds": 180,
"rewards": {
"money": 250,
"experience": 150,
"seeds": [{"name": "胡萝卜", "count": 5}, {"name": "玉米", "count": 3}]
}
},
"5分钟": {
"time_seconds": 300,
"rewards": {
"money": 500,
"experience": 250,
"seeds": [{"name": "玉米", "count": 3}, {"name": "番茄", "count": 2}]
}
},
"10分钟": {
"time_seconds": 600,
"rewards": {
"money": 500,
"experience": 200,
"seeds": [{"name": "玉米", "count": 3}, {"name": "番茄", "count": 2}]
}
},
"30分钟": {
"time_seconds": 1800,
"rewards": {
"money": 1200,
"experience": 500,
"seeds": [{"name": "草莓", "count": 2}, {"name": "花椰菜", "count": 1}]
}
},
"1小时": {
"time_seconds": 3600,
"rewards": {
"money": 2500,
"experience": 1000,
"seeds": [{"name": "葡萄", "count": 1}, {"name": "南瓜", "count": 1}, {"name": "咖啡豆", "count": 1}]
}
},
"3小时": {
"time_seconds": 10800,
"rewards": {
"money": 6000,
"experience": 2500,
"seeds": [{"name": "人参", "count": 1}, {"name": "藏红花", "count": 1}]
}
},
"5小时": {
"time_seconds": 18000,
"rewards": {
"money": 12000,
"experience": 5000,
"seeds": [{"name": "龙果", "count": 1}, {"name": "松露", "count": 1}, {"name": "月光草", "count": 1}]
}
}
}
if gift_name not in online_gift_config:
return self.send_data(client_id, {
"type": "claim_online_gift_response",
"success": False,
"message": "无效的礼包名称"
})
# 获取今日在线礼包数据
current_date = datetime.datetime.now().strftime("%Y-%m-%d")
online_gift_data = player_data.get("online_gift", {})
if current_date not in online_gift_data:
return self.send_data(client_id, {
"type": "claim_online_gift_response",
"success": False,
"message": "在线礼包数据异常,请重新登录"
})
today_data = online_gift_data[current_date]
# 检查是否已领取
if gift_name in today_data.get("claimed_gifts", {}):
return self.send_data(client_id, {
"type": "claim_online_gift_response",
"success": False,
"message": "该礼包今日已领取"
})
# 更新当前在线时间并检查是否满足条件
current_time = time.time()
# 计算本次登录的在线时间
if client_id in self.user_data and self.user_data[client_id].get("logged_in", False):
login_time = self.user_data[client_id].get("login_timestamp", current_time)
session_online_time = current_time - login_time
# 更新累计在线时间
today_data["total_online_time"] = today_data.get("total_online_time", 0.0) + session_online_time
# 重置登录时间
self.user_data[client_id]["login_timestamp"] = current_time
online_duration = today_data.get("total_online_time", 0.0)
required_time = online_gift_config[gift_name]["time_seconds"]
if online_duration < required_time:
return self.send_data(client_id, {
"type": "claim_online_gift_response",
"success": False,
"message": f"在线时间不足,还需要 {self._format_time(required_time - online_duration)}"
})
# 发放奖励
rewards = online_gift_config[gift_name]["rewards"]
self._apply_online_gift_rewards(player_data, rewards)
# 记录领取状态
if "claimed_gifts" not in today_data:
today_data["claimed_gifts"] = {}
today_data["claimed_gifts"][gift_name] = time.time()
# 保存数据
self.save_player_data(username, player_data)
self.log('INFO', f"玩家 {username} 领取在线礼包 {gift_name},获得奖励: {rewards}", 'SERVER')
return self.send_data(client_id, {
"type": "claim_online_gift_response",
"success": True,
"message": f"成功领取{gift_name}在线礼包!",
"gift_name": gift_name,
"rewards": rewards,
"updated_data": {
"money": player_data["money"],
"experience": player_data["experience"],
"level": player_data["level"],
"player_bag": player_data.get("player_bag", [])
}
})
#发放在线礼包奖励
def _apply_online_gift_rewards(self, player_data, rewards):
"""发放在线礼包奖励"""
# 发放金币
if "money" in rewards:
player_data["money"] = player_data.get("money", 0) + rewards["money"]
# 发放经验
if "experience" in rewards:
old_experience = player_data.get("experience", 0)
player_data["experience"] = old_experience + rewards["experience"]
# 检查是否升级
self._check_level_up(player_data)
# 发放种子
if "seeds" in rewards:
player_bag = player_data.get("player_bag", [])
crop_data = self._load_crop_data()
for seed_info in rewards["seeds"]:
seed_name = seed_info["name"]
seed_count = seed_info["count"]
# 从作物数据中获取品质信息
quality = "普通" # 默认品质
if crop_data and seed_name in crop_data:
quality = crop_data[seed_name].get("品质", "普通")
# 查找是否已有该种子
found = False
for item in player_bag:
if item["name"] == seed_name:
item["count"] += seed_count
found = True
break
# 如果没有找到,添加新物品
if not found:
player_bag.append({
"name": seed_name,
"count": seed_count,
"type": "seed",
"quality": quality
})
player_data["player_bag"] = player_bag
#检查玩家是否升级
def _check_level_up(self, player_data):
"""检查玩家是否升级"""
current_level = player_data.get("level", 1)
current_experience = player_data.get("experience", 0)
# 计算升级所需经验 (每级需要的经验递增)
experience_needed = current_level * 100
# 检查是否可以升级
while current_experience >= experience_needed:
current_level += 1
current_experience -= experience_needed
experience_needed = current_level * 100
player_data["level"] = current_level
player_data["experience"] = current_experience
#更新玩家今日在线时间
def _update_daily_online_time(self, client_id, player_data):
"""更新玩家今日在线时间"""
if client_id not in self.user_data or not self.user_data[client_id].get("logged_in", False):
return
current_date = datetime.datetime.now().strftime("%Y-%m-%d")
online_gift_data = player_data.get("online_gift", {})
# 确保今日数据存在
if current_date not in online_gift_data:
online_gift_data[current_date] = {
"total_online_time": 0.0,
"last_login_time": time.time(),
"claimed_gifts": {}
}
player_data["online_gift"] = online_gift_data
today_data = online_gift_data[current_date]
current_time = time.time()
login_time = self.user_data[client_id].get("login_timestamp", current_time)
session_online_time = current_time - login_time
# 更新累计在线时间
today_data["total_online_time"] = today_data.get("total_online_time", 0.0) + session_online_time
today_data["last_login_time"] = current_time
# 重置用户登录时间戳
self.user_data[client_id]["login_timestamp"] = current_time
return today_data["total_online_time"]
#格式化时间显示
def _format_time(self, seconds):
"""格式化时间显示"""
hours = int(seconds // 3600)
minutes = int((seconds % 3600) // 60)
secs = int(seconds % 60)
if hours > 0:
return f"{hours}小时{minutes}分钟{secs}"
elif minutes > 0:
return f"{minutes}分钟{secs}"
else:
return f"{secs}"
#==========================在线礼包处理==========================
#==========================PING延迟检测处理==========================
#处理ping请求
def _handle_ping_request(self, client_id, message):
"""处理客户端ping请求立即返回pong响应"""
timestamp = message.get("timestamp", time.time())
# 立即返回pong响应
pong_response = {
"type": "pong",
"timestamp": timestamp,
"server_time": time.time()
}
return self.send_data(client_id, pong_response)
#==========================PING延迟检测处理==========================
#==========================聊天消息处理==========================
#处理聊天消息(暂未完成)
def _handle_chat_message(self, client_id, message):
"""处理聊天消息"""
# 检查用户是否已登录
logged_in, response = self._check_user_logged_in(client_id, "发送聊天消息")
if not logged_in:
return self.send_data(client_id, response)
content = message.get("content", "")
if not content.strip():
return self.send_data(client_id, {
"type": "chat_response",
"success": False,
"message": "消息内容不能为空"
})
username = self.user_data[client_id]["username"]
# 广播聊天消息给所有在线用户
chat_message = {
"type": "chat_message",
"username": username,
"content": content,
"timestamp": time.time()
}
self.broadcast(chat_message)
self.log('INFO', f"用户 {username} 发送聊天消息: {content}", 'SERVER')
return True
#==========================聊天消息处理==========================
#==========================每日签到处理==========================
#处理每日签到请求
def _handle_daily_check_in_request(self, client_id, message):
"""处理每日签到请求"""
# 检查用户是否已登录
logged_in, response = self._check_user_logged_in(client_id, "每日签到", "daily_check_in")
if not logged_in:
return self.send_data(client_id, response)
# 获取玩家数据
player_data, username, response = self._load_player_data_with_check(client_id, "daily_check_in")
if not player_data:
return self.send_data(client_id, response)
# 检查今日是否已签到
current_date = datetime.datetime.now().strftime("%Y-%m-%d")
check_in_data = player_data.get("daily_check_in", {})
if current_date in check_in_data:
return self.send_data(client_id, {
"type": "daily_check_in_response",
"success": False,
"message": "今日已签到,请明日再来",
"has_checked_in": True
})
# 计算连续签到天数
consecutive_days = self._calculate_consecutive_check_in_days(check_in_data, current_date)
# 生成签到奖励
rewards = self._generate_check_in_rewards(consecutive_days)
# 发放奖励
self._apply_check_in_rewards(player_data, rewards)
# 保存签到记录
if "daily_check_in" not in player_data:
player_data["daily_check_in"] = {}
player_data["daily_check_in"][current_date] = {
"rewards": rewards,
"consecutive_days": consecutive_days,
"timestamp": time.time()
}
# 保存玩家数据
self.save_player_data(username, player_data)
self.log('INFO', f"玩家 {username} 完成每日签到,连续 {consecutive_days} 天,获得奖励: {rewards}", 'SERVER')
return self.send_data(client_id, {
"type": "daily_check_in_response",
"success": True,
"message": f"签到成功!连续签到 {consecutive_days}",
"rewards": rewards,
"consecutive_days": consecutive_days,
"updated_data": {
"money": player_data["money"],
"experience": player_data["experience"],
"level": player_data["level"],
"player_bag": player_data.get("player_bag", [])
}
})
#处理客户端获取签到数据请求
def _handle_get_check_in_data_request(self, client_id, message):
"""处理获取签到数据请求"""
# 检查用户是否已登录
logged_in, response = self._check_user_logged_in(client_id, "获取签到数据", "get_check_in_data")
if not logged_in:
return self.send_data(client_id, response)
# 获取玩家数据
player_data, username, response = self._load_player_data_with_check(client_id, "get_check_in_data")
if not player_data:
return self.send_data(client_id, response)
current_date = datetime.datetime.now().strftime("%Y-%m-%d")
check_in_data = player_data.get("daily_check_in", {})
# 计算连续签到天数
consecutive_days = self._calculate_consecutive_check_in_days(check_in_data, current_date)
# 检查今日是否已签到
has_checked_in_today = current_date in check_in_data
return self.send_data(client_id, {
"type": "check_in_data_response",
"success": True,
"check_in_data": check_in_data,
"consecutive_days": consecutive_days,
"has_checked_in_today": has_checked_in_today,
"current_date": current_date
})
#计算连续签到天数
def _calculate_consecutive_check_in_days(self, check_in_data, current_date):
"""计算连续签到天数"""
if not check_in_data:
return 0
# 获取所有签到日期并排序
sorted_dates = sorted(check_in_data.keys())
if not sorted_dates:
return 0
# 从最新日期开始向前计算连续天数
consecutive_days = 0
current_datetime = datetime.datetime.strptime(current_date, "%Y-%m-%d")
# 如果今天已经签到,从今天开始计算,否则从昨天开始
if current_date in check_in_data:
check_date = current_datetime
else:
check_date = current_datetime - datetime.timedelta(days=1)
# 向前查找连续签到天数
while True:
date_string = check_date.strftime("%Y-%m-%d")
if date_string in check_in_data:
consecutive_days += 1
check_date -= datetime.timedelta(days=1)
else:
break
# 限制最大连续天数为30天避免过度奖励
if consecutive_days >= 30:
break
return consecutive_days
#生成签到奖励
def _generate_check_in_rewards(self, consecutive_days):
"""生成签到奖励"""
import random
# 加载作物配置
crop_data = self._load_crop_data()
rewards = {}
# 基础奖励倍数(根据连续签到天数)
base_multiplier = 1.0 + (consecutive_days - 1) * 0.1 # 每连续签到一天增加10%
max_multiplier = 3.0 # 最大3倍奖励
multiplier = min(base_multiplier, max_multiplier)
# 钱币奖励 (基础200-500受连续签到影响)
base_coins = random.randint(200, 500)
rewards["coins"] = int(base_coins * multiplier)
# 经验奖励 (基础50-120受连续签到影响)
base_exp = random.randint(50, 120)
rewards["exp"] = int(base_exp * multiplier)
# 种子奖励 (根据连续签到天数获得更好的种子)
seeds = self._generate_check_in_seeds(consecutive_days, crop_data)
if seeds:
rewards["seeds"] = seeds
# 连续签到特殊奖励
if consecutive_days >= 3:
rewards["bonus_coins"] = int(100 * (consecutive_days // 3))
if consecutive_days >= 7:
rewards["bonus_exp"] = int(200 * (consecutive_days // 7))
return rewards
#生成签到种子奖励
def _generate_check_in_seeds(self, consecutive_days, crop_data):
"""生成签到种子奖励"""
import random
seeds = []
# 根据连续签到天数确定种子类型和数量
if consecutive_days <= 2:
# 1-2天普通种子
common_seeds = ["小麦", "胡萝卜", "土豆", "稻谷"]
elif consecutive_days <= 5:
# 3-5天优良种子
common_seeds = ["玉米", "番茄", "洋葱", "大豆", "豌豆", "黄瓜", "大白菜"]
elif consecutive_days <= 10:
# 6-10天稀有种子
common_seeds = ["草莓", "花椰菜", "柿子", "蓝莓", "树莓"]
elif consecutive_days <= 15:
# 11-15天史诗种子
common_seeds = ["葡萄", "南瓜", "芦笋", "茄子", "向日葵", "蕨菜"]
else:
# 16天以上传奇种子
common_seeds = ["西瓜", "甘蔗", "香草", "甜菜", "人参", "富贵竹", "芦荟", "哈密瓜"]
# 生成1-3个种子
seed_count = random.randint(1, min(3, len(common_seeds)))
selected_seeds = random.sample(common_seeds, seed_count)
for seed_name in selected_seeds:
if seed_name in crop_data:
# 根据种子等级确定数量
seed_level = crop_data[seed_name].get("等级", 1)
if seed_level <= 2:
quantity = random.randint(2, 5)
elif seed_level <= 4:
quantity = random.randint(1, 3)
else:
quantity = 1
seeds.append({
"name": seed_name,
"quantity": quantity,
"quality": crop_data[seed_name].get("品质", "普通")
})
return seeds
#应用签到奖励到玩家数据
def _apply_check_in_rewards(self, player_data, rewards):
"""应用签到奖励到玩家数据"""
# 应用钱币奖励
if "coins" in rewards:
player_data["money"] = player_data.get("money", 0) + rewards["coins"]
if "bonus_coins" in rewards:
player_data["money"] = player_data.get("money", 0) + rewards["bonus_coins"]
# 应用经验奖励
if "exp" in rewards:
player_data["experience"] = player_data.get("experience", 0) + rewards["exp"]
if "bonus_exp" in rewards:
player_data["experience"] = player_data.get("experience", 0) + rewards["bonus_exp"]
# 检查升级
level_up_experience = 100 * player_data.get("level", 1)
while player_data.get("experience", 0) >= level_up_experience:
player_data["level"] = player_data.get("level", 1) + 1
player_data["experience"] -= level_up_experience
level_up_experience = 100 * player_data["level"]
# 应用种子奖励
if "seeds" in rewards:
if "player_bag" not in player_data:
player_data["player_bag"] = []
for seed_reward in rewards["seeds"]:
seed_name = seed_reward["name"]
quantity = seed_reward["quantity"]
quality = seed_reward["quality"]
# 查找背包中是否已有该种子
found = False
for item in player_data["player_bag"]:
if item.get("name") == seed_name:
item["count"] += quantity
found = True
break
# 如果背包中没有,添加新条目
if not found:
player_data["player_bag"].append({
"name": seed_name,
"quality": quality,
"count": quantity
})
#==========================每日签到处理==========================
#==========================新手大礼包处理==========================
#处理新手大礼包请求
def _handle_new_player_gift_request(self, client_id, message):
"""处理新手大礼包请求"""
try:
# 检查用户是否已登录
logged_in, response = self._check_user_logged_in(client_id, "领取新手大礼包", "new_player_gift")
if not logged_in:
return self.send_data(client_id, response)
# 获取玩家数据
player_data, username, response = self._load_player_data_with_check(client_id, "new_player_gift")
if not player_data:
return self.send_data(client_id, response)
# 检查是否已经领取过新手大礼包
if player_data.get("new_player_gift_claimed", False):
return self.send_data(client_id, {
"type": "new_player_gift_response",
"success": False,
"message": "新手大礼包已经领取过了"
})
# 新手大礼包内容
gift_contents = {
"coins": 6000,
"experience": 1000,
"seeds": [
{"name": "龙果", "quality": "传奇", "count": 1},
{"name": "杂交树1", "quality": "传奇", "count": 1},
{"name": "杂交树2", "quality": "传奇", "count": 1}
]
}
# 应用奖励
self._apply_new_player_gift_rewards(player_data, gift_contents)
# 标记已领取
player_data["new_player_gift_claimed"] = True
# 记录领取时间
player_data["new_player_gift_time"] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
# 保存玩家数据
self.save_player_data(username, player_data)
self.log('INFO', f"玩家 {username} 成功领取新手大礼包", 'SERVER')
return self.send_data(client_id, {
"type": "new_player_gift_response",
"success": True,
"message": "新手大礼包领取成功获得6000金币、1000经验和3个传奇种子",
"gift_contents": gift_contents,
"updated_data": {
"money": player_data["money"],
"experience": player_data["experience"],
"level": player_data["level"],
"player_bag": player_data.get("player_bag", []),
"new_player_gift_claimed": True
}
})
except Exception as e:
# 捕获所有异常,防止服务器崩溃
self.log('ERROR', f"处理新手大礼包请求时出错: {str(e)}", 'SERVER')
# 尝试获取用户名
try:
username = self.user_data[client_id].get("username", "未知用户")
except:
username = "未知用户"
# 发送错误响应
return self.send_data(client_id, {
"type": "new_player_gift_response",
"success": False,
"message": "服务器处理新手大礼包时出现错误,请稍后重试"
})
#应用新手大礼包奖励到玩家数据
def _apply_new_player_gift_rewards(self, player_data, gift_contents):
"""应用新手大礼包奖励到玩家数据"""
# 应用金币奖励
if "coins" in gift_contents:
player_data["money"] = player_data.get("money", 0) + gift_contents["coins"]
# 应用经验奖励
if "experience" in gift_contents:
player_data["experience"] = player_data.get("experience", 0) + gift_contents["experience"]
# 检查升级
level_up_experience = 100 * player_data.get("level", 1)
while player_data.get("experience", 0) >= level_up_experience:
player_data["level"] = player_data.get("level", 1) + 1
player_data["experience"] -= level_up_experience
level_up_experience = 100 * player_data["level"]
# 应用种子奖励
if "seeds" in gift_contents:
if "player_bag" not in player_data:
player_data["player_bag"] = []
for seed_reward in gift_contents["seeds"]:
seed_name = seed_reward["name"]
quantity = seed_reward["count"]
quality = seed_reward["quality"]
# 查找背包中是否已有该种子
found = False
for item in player_data["player_bag"]:
if item.get("name") == seed_name:
item["count"] += quantity
found = True
break
# 如果背包中没有,添加新条目
if not found:
player_data["player_bag"].append({
"name": seed_name,
"quality": quality,
"count": quantity
})
#==========================新手大礼包处理==========================
#==========================幸运抽奖处理==========================
#处理幸运抽奖请求
def _handle_lucky_draw_request(self, client_id, message):
"""处理幸运抽奖请求"""
try:
# 检查用户是否已登录
logged_in, response = self._check_user_logged_in(client_id, "幸运抽奖", "lucky_draw")
if not logged_in:
return self.send_data(client_id, response)
# 获取玩家数据
player_data, username, response = self._load_player_data_with_check(client_id, "lucky_draw")
if not player_data:
return self.send_data(client_id, response)
draw_type = message.get("draw_type", "single") # single, five, ten
draw_count = 1
base_cost = 800 # 基础抽奖费用
# 计算抽奖费用和数量
if draw_type == "single":
draw_count = 1
total_cost = base_cost
elif draw_type == "five":
draw_count = 5
total_cost = int(base_cost * 5 * 0.9) # 五连抽九折
elif draw_type == "ten":
draw_count = 10
total_cost = int(base_cost * 10 * 0.8) # 十连抽八折
else:
self.log('WARNING', f"玩家 {username} 使用了无效的抽奖类型: {draw_type}", 'SERVER')
return self.send_data(client_id, {
"type": "lucky_draw_response",
"success": False,
"message": "无效的抽奖类型"
})
# 检查玩家金钱是否足够
if player_data.get("money", 0) < total_cost:
self.log('WARNING', f"玩家 {username} 金币不足进行{draw_type}抽奖,需要{total_cost},当前{player_data.get('money', 0)}", 'SERVER')
return self.send_data(client_id, {
"type": "lucky_draw_response",
"success": False,
"message": f"金钱不足,{draw_type}抽奖需要 {total_cost} 金币"
})
# 扣除金钱
player_data["money"] -= total_cost
# 生成奖励
rewards = self._generate_lucky_draw_rewards(draw_count, draw_type)
# 验证奖励格式
for reward in rewards:
if not reward.get("rarity"):
reward["rarity"] = "普通"
self.log('WARNING', f"奖励缺少稀有度字段,已设置为普通: {reward}", 'SERVER')
# 应用奖励到玩家数据
self._apply_lucky_draw_rewards(player_data, rewards)
# 记录抽奖历史
if "lucky_draw_history" not in player_data:
player_data["lucky_draw_history"] = []
draw_record = {
"date": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"type": draw_type,
"cost": total_cost,
"rewards": rewards
}
player_data["lucky_draw_history"].append(draw_record)
# 只保留最近100次记录
if len(player_data["lucky_draw_history"]) > 100:
player_data["lucky_draw_history"] = player_data["lucky_draw_history"][-100:]
# 保存玩家数据
self.save_player_data(username, player_data)
self.log('INFO', f"玩家 {username} 进行{draw_type}抽奖,花费 {total_cost} 金币,获得 {len(rewards)} 个奖励", 'SERVER')
return self.send_data(client_id, {
"type": "lucky_draw_response",
"success": True,
"message": f"{draw_type}抽奖成功!",
"draw_type": draw_type,
"cost": total_cost,
"rewards": rewards,
"updated_data": {
"money": player_data["money"],
"experience": player_data["experience"],
"level": player_data["level"],
"player_bag": player_data.get("player_bag", [])
}
})
except Exception as e:
# 捕获所有异常,防止服务器崩溃
self.log('ERROR', f"处理玩家抽奖请求时出错: {str(e)}", 'SERVER')
# 尝试获取用户名
try:
username = self.user_data[client_id].get("username", "未知用户")
except:
username = "未知用户"
# 发送错误响应
return self.send_data(client_id, {
"type": "lucky_draw_response",
"success": False,
"message": "服务器处理抽奖时出现错误,请稍后重试"
})
#生成幸运抽奖奖励
def _generate_lucky_draw_rewards(self, count: int, draw_type: str):
"""生成幸运抽奖奖励"""
import random
# 加载作物配置
crop_data = self._load_crop_data()
rewards = []
# 根据 crop_data.json 构建奖励池
common_seeds = []
good_seeds = []
rare_seeds = []
epic_seeds = []
legendary_seeds = []
for crop_name, crop_info in crop_data.items():
if not crop_info.get("能否购买", True):
continue # 跳过不能购买的作物
quality = crop_info.get("品质", "普通")
if quality == "普通":
common_seeds.append(crop_name)
elif quality == "优良":
good_seeds.append(crop_name)
elif quality == "稀有":
rare_seeds.append(crop_name)
elif quality == "史诗":
epic_seeds.append(crop_name)
elif quality == "传奇":
legendary_seeds.append(crop_name)
# 十连抽保底机制:至少一个稀有以上
guaranteed_rare = (draw_type == "ten")
rare_given = False
for i in range(count):
# 生成单个奖励
reward = self._generate_single_lucky_reward(
common_seeds, good_seeds, rare_seeds, epic_seeds, legendary_seeds,
guaranteed_rare and i == count - 1 and not rare_given
)
# 检查是否给出了稀有奖励(使用安全的方式访问)
reward_rarity = reward.get("rarity", "普通")
if reward_rarity in ["稀有", "史诗", "传奇"]:
rare_given = True
rewards.append(reward)
return rewards
#生成单个抽奖奖励
def _generate_single_lucky_reward(self, common_seeds, good_seeds, rare_seeds, epic_seeds, legendary_seeds, force_rare=False):
"""生成单个幸运抽奖奖励"""
import random
# 概率配置
if force_rare:
# 强制稀有33%稀有33%史诗34%传奇
rand = random.random()
if rand < 0.33:
reward_type = "rare"
elif rand < 0.66:
reward_type = "epic"
else:
reward_type = "legendary"
else:
# 正常概率45%普通25%优良15%空奖12%稀有2.5%史诗0.5%传奇
rand = random.random()
if rand < 0.45:
reward_type = "common"
elif rand < 0.70:
reward_type = "good"
elif rand < 0.85:
reward_type = "empty"
elif rand < 0.97:
reward_type = "rare"
elif rand < 0.995:
reward_type = "epic"
else:
reward_type = "legendary"
reward = {}
if reward_type == "empty":
# 谢谢惠顾
empty_messages = ["谢谢惠顾", "下次再来", "再试一次", "继续努力"]
reward = {
"type": "empty",
"name": random.choice(empty_messages),
"rarity": "空奖",
"amount": 0
}
elif reward_type == "common":
# 普通奖励:金币、经验或普通种子
reward_choice = random.choice(["coins", "exp", "seed"])
if reward_choice == "coins":
reward = {
"type": "coins",
"name": "金币",
"rarity": "普通",
"amount": random.randint(100, 300)
}
elif reward_choice == "exp":
reward = {
"type": "exp",
"name": "经验",
"rarity": "普通",
"amount": random.randint(50, 150)
}
else: # seed
if common_seeds:
seed_name = random.choice(common_seeds)
reward = {
"type": "seed",
"name": seed_name,
"rarity": "普通",
"amount": random.randint(2, 4)
}
else:
reward = {
"type": "coins",
"name": "金币",
"rarity": "普通",
"amount": random.randint(100, 300)
}
elif reward_type == "good":
# 优良奖励:更多金币经验或优良种子
reward_choice = random.choice(["coins", "exp", "seed", "package"])
if reward_choice == "coins":
reward = {
"type": "coins",
"name": "金币",
"rarity": "优良",
"amount": random.randint(300, 600)
}
elif reward_choice == "exp":
reward = {
"type": "exp",
"name": "经验",
"rarity": "优良",
"amount": random.randint(150, 300)
}
elif reward_choice == "seed":
if good_seeds:
seed_name = random.choice(good_seeds)
reward = {
"type": "seed",
"name": seed_name,
"rarity": "优良",
"amount": random.randint(1, 3)
}
else:
reward = {
"type": "coins",
"name": "金币",
"rarity": "优良",
"amount": random.randint(300, 600)
}
else: # package
reward = {
"type": "package",
"name": "成长套餐",
"rarity": "优良",
"amount": 1,
"contents": [
{"type": "coins", "amount": random.randint(200, 400)},
{"type": "exp", "amount": random.randint(100, 200)},
{"type": "seed", "name": random.choice(common_seeds) if common_seeds else "小麦", "amount": random.randint(2, 3)}
]
}
elif reward_type == "rare":
# 稀有奖励
reward_choice = random.choice(["coins", "exp", "seed", "package"])
if reward_choice == "coins":
reward = {
"type": "coins",
"name": "金币",
"rarity": "稀有",
"amount": random.randint(600, 1000)
}
elif reward_choice == "exp":
reward = {
"type": "exp",
"name": "经验",
"rarity": "稀有",
"amount": random.randint(300, 500)
}
elif reward_choice == "seed":
if rare_seeds:
seed_name = random.choice(rare_seeds)
reward = {
"type": "seed",
"name": seed_name,
"rarity": "稀有",
"amount": random.randint(1, 2)
}
else:
reward = {
"type": "coins",
"name": "金币",
"rarity": "稀有",
"amount": random.randint(600, 1000)
}
else: # package
reward = {
"type": "package",
"name": "稀有礼包",
"rarity": "稀有",
"amount": 1,
"contents": [
{"type": "coins", "amount": random.randint(400, 700)},
{"type": "exp", "amount": random.randint(200, 350)},
{"type": "seed", "name": random.choice(good_seeds) if good_seeds else "番茄", "amount": random.randint(2, 3)}
]
}
elif reward_type == "epic":
# 史诗奖励
reward_choice = random.choice(["coins", "exp", "seed", "package"])
if reward_choice == "coins":
reward = {
"type": "coins",
"name": "金币",
"rarity": "史诗",
"amount": random.randint(1000, 1500)
}
elif reward_choice == "exp":
reward = {
"type": "exp",
"name": "经验",
"rarity": "史诗",
"amount": random.randint(500, 800)
}
elif reward_choice == "seed":
if epic_seeds:
seed_name = random.choice(epic_seeds)
reward = {
"type": "seed",
"name": seed_name,
"rarity": "史诗",
"amount": 1
}
else:
reward = {
"type": "coins",
"name": "金币",
"rarity": "史诗",
"amount": random.randint(1000, 1500)
}
else: # package
reward = {
"type": "package",
"name": "史诗礼包",
"rarity": "史诗",
"amount": 1,
"contents": [
{"type": "coins", "amount": random.randint(700, 1200)},
{"type": "exp", "amount": random.randint(350, 600)},
{"type": "seed", "name": random.choice(rare_seeds) if rare_seeds else "草莓", "amount": random.randint(1, 2)}
]
}
else: # legendary
# 传奇奖励
reward_choice = random.choice(["coins", "exp", "seed", "package"])
if reward_choice == "coins":
reward = {
"type": "coins",
"name": "金币",
"rarity": "传奇",
"amount": random.randint(1500, 2500)
}
elif reward_choice == "exp":
reward = {
"type": "exp",
"name": "经验",
"rarity": "传奇",
"amount": random.randint(800, 1200)
}
elif reward_choice == "seed":
if legendary_seeds:
seed_name = random.choice(legendary_seeds)
reward = {
"type": "seed",
"name": seed_name,
"rarity": "传奇",
"amount": 1
}
else:
reward = {
"type": "coins",
"name": "金币",
"rarity": "传奇",
"amount": random.randint(1500, 2500)
}
else: # package
reward = {
"type": "package",
"name": "传奇大礼包",
"rarity": "传奇",
"amount": 1,
"contents": [
{"type": "coins", "amount": random.randint(1000, 2000)},
{"type": "exp", "amount": random.randint(600, 1000)},
{"type": "seed", "name": random.choice(epic_seeds) if epic_seeds else "葡萄", "amount": 1},
{"type": "seed", "name": random.choice(rare_seeds) if rare_seeds else "草莓", "amount": random.randint(2, 3)}
]
}
# 确保所有奖励都有基本字段
if not reward.get("rarity"):
reward["rarity"] = "普通"
if not reward.get("amount"):
reward["amount"] = 0
if not reward.get("type"):
reward["type"] = "empty"
if not reward.get("name"):
reward["name"] = "未知奖励"
return reward
#应用幸运抽奖奖励到玩家数据
def _apply_lucky_draw_rewards(self, player_data, rewards):
"""应用幸运抽奖奖励到玩家数据"""
for reward in rewards:
reward_type = reward.get("type", "empty")
if reward_type == "empty":
continue # 空奖励不处理
elif reward_type == "coins":
player_data["money"] = player_data.get("money", 0) + reward.get("amount", 0)
elif reward_type == "exp":
player_data["experience"] = player_data.get("experience", 0) + reward.get("amount", 0)
# 检查升级
level_up_experience = 100 * player_data.get("level", 1)
while player_data.get("experience", 0) >= level_up_experience:
player_data["level"] = player_data.get("level", 1) + 1
player_data["experience"] -= level_up_experience
level_up_experience = 100 * player_data["level"]
elif reward_type == "seed":
if "player_bag" not in player_data:
player_data["player_bag"] = []
# 查找背包中是否已有该种子
found = False
for item in player_data["player_bag"]:
if item.get("name") == reward.get("name", ""):
item["count"] += reward.get("amount", 0)
found = True
break
# 如果背包中没有,添加新条目
if not found:
player_data["player_bag"].append({
"name": reward.get("name", "未知种子"),
"quality": reward.get("rarity", "普通"),
"count": reward.get("amount", 0)
})
elif reward_type == "package":
# 递归处理礼包内容
contents = reward.get("contents", [])
if contents:
# 为礼包内容添加默认的rarity字段
for content in contents:
if not content.get("rarity"):
content["rarity"] = reward.get("rarity", "普通")
# 递归处理礼包内容
self._apply_lucky_draw_rewards(player_data, contents)
#==========================幸运抽奖处理==========================
#==========================发送游戏操作错误处理==========================
#发送游戏操作错误
def _send_action_error(self, client_id, action_type, message):
"""发送游戏操作错误响应"""
return self.send_data(client_id, {
"type": "action_response",
"action_type": action_type,
"success": False,
"message": message
})
#==========================发送游戏操作错误处理==========================
#==========================缓存数据处理==========================
#清理过期的缓存数据
def cleanup_expired_cache(self):
"""清理过期的缓存数据"""
current_time = time.time()
expired_players = []
for account_id, cache_data in self.active_players_cache.items():
if current_time - cache_data.get("last_access", 0) > self.cache_expire_time:
expired_players.append(account_id)
for account_id in expired_players:
# 如果是脏数据,先保存
if account_id in self.dirty_players:
self.save_player_data_immediate(account_id)
self.dirty_players.discard(account_id)
# 移除过期缓存
self.player_cache.pop(account_id, None)
self.active_players_cache.pop(account_id, None)
if expired_players:
self.log('INFO', f"清理了 {len(expired_players)} 个过期缓存", 'SERVER')
#批量保存脏数据到磁盘
def batch_save_dirty_players(self):
"""批量保存脏数据到磁盘"""
if not self.dirty_players:
return
saved_count = 0
for account_id in list(self.dirty_players):
try:
if self.save_player_data_immediate(account_id):
saved_count += 1
except Exception as e:
self.log('ERROR', f"保存玩家 {account_id} 数据时出错: {str(e)}", 'SERVER')
self.dirty_players.clear()
self.last_save_time = time.time()
if saved_count > 0:
self.log('INFO', f"批量保存了 {saved_count} 个玩家的数据", 'SERVER')
#强制保存所有缓存数据
def force_save_all_data(self):
"""强制保存所有缓存数据(用于服务器关闭时)"""
saved_count = 0
for account_id in list(self.player_cache.keys()):
try:
if self.save_player_data_immediate(account_id):
saved_count += 1
except Exception as e:
self.log('ERROR', f"强制保存玩家 {account_id} 数据时出错: {str(e)}", 'SERVER')
self.dirty_players.clear()
self.log('INFO', f"强制保存完成,保存了 {saved_count} 个玩家的数据", 'SERVER')
return saved_count
#优化缓存大小,移除不活跃的数据
def optimize_cache_size(self):
"""优化缓存大小,移除不活跃的数据"""
current_time = time.time()
removed_count = 0
# 如果缓存过大,移除最不活跃的数据
if len(self.player_cache) > 1000: # 缓存超过1000个玩家时进行清理
sorted_players = sorted(
self.active_players_cache.items(),
key=lambda x: x[1].get("last_access", 0)
)
# 移除最不活跃的50%
remove_count = len(sorted_players) // 2
for account_id, _ in sorted_players[:remove_count]:
if account_id in self.dirty_players:
self.save_player_data_immediate(account_id)
self.dirty_players.discard(account_id)
self.player_cache.pop(account_id, None)
self.active_players_cache.pop(account_id, None)
removed_count += 1
if removed_count > 0:
self.log('INFO', f"缓存优化:移除了 {removed_count} 个不活跃的缓存数据", 'SERVER')
return removed_count
#获取缓存命中信息(用于调试)
def get_cache_hit_info(self, account_id):
"""获取缓存命中信息(用于调试)"""
return {
"in_memory_cache": account_id in self.player_cache,
"in_active_cache": account_id in self.active_players_cache,
"is_dirty": account_id in self.dirty_players,
"last_access": self.active_players_cache.get(account_id, {}).get("last_access", 0)
}
#==========================缓存数据处理==========================
# ================================账户设置处理方法================================
def _handle_modify_account_info_request(self, client_id, message):
"""处理修改账号信息请求"""
# 检查用户是否已登录
is_logged_in, error_response = self._check_user_logged_in(client_id, "修改账号信息")
if not is_logged_in:
return self._send_modify_account_error(client_id, error_response["message"])
# 加载玩家数据
player_data, username, error_response = self._load_player_data_with_check(client_id, "modify_account_info")
if not player_data:
return self.send_data(client_id, error_response)
# 获取新的信息
new_password = message.get("new_password", "").strip()
new_player_name = message.get("new_player_name", "").strip()
new_farm_name = message.get("new_farm_name", "").strip()
new_personal_profile = message.get("new_personal_profile", "").strip()
# 验证输入
if not new_password:
return self._send_modify_account_error(client_id, "密码不能为空")
if not new_player_name:
return self._send_modify_account_error(client_id, "玩家昵称不能为空")
if not new_farm_name:
return self._send_modify_account_error(client_id, "农场名称不能为空")
if len(new_password) < 6:
return self._send_modify_account_error(client_id, "密码长度至少6个字符")
if len(new_player_name) > 20:
return self._send_modify_account_error(client_id, "玩家昵称不能超过20个字符")
if len(new_farm_name) > 20:
return self._send_modify_account_error(client_id, "农场名称不能超过20个字符")
if len(new_personal_profile) > 100:
return self._send_modify_account_error(client_id, "个人简介不能超过100个字符")
try:
# 更新玩家数据
player_data["user_password"] = new_password
player_data["player_name"] = new_player_name
player_data["farm_name"] = new_farm_name
player_data["个人简介"] = new_personal_profile
# 保存到缓存和文件
self.player_cache[username] = player_data
self.dirty_players.add(username)
# 立即保存重要的账户信息
self.save_player_data_immediate(username)
# 发送成功响应
self.send_data(client_id, {
"type": "modify_account_info_response",
"success": True,
"message": "账号信息修改成功",
"updated_data": {
"user_password": new_password,
"player_name": new_player_name,
"farm_name": new_farm_name,
"个人简介": new_personal_profile
}
})
self.log('INFO', f"用户 {username} 修改账号信息成功", 'ACCOUNT')
except Exception as e:
self.log('ERROR', f"修改账号信息时出错: {str(e)}", 'ACCOUNT')
return self._send_modify_account_error(client_id, "修改账号信息失败,请稍后重试")
def _handle_delete_account_request(self, client_id, message):
"""处理删除账号请求"""
# 检查用户是否已登录
is_logged_in, error_response = self._check_user_logged_in(client_id, "删除账号")
if not is_logged_in:
return self._send_delete_account_error(client_id, error_response["message"])
# 获取用户名
username = self.user_data[client_id]["username"]
try:
# 删除玩家文件
file_path = os.path.join("game_saves", f"{username}.json")
if os.path.exists(file_path):
os.remove(file_path)
self.log('INFO', f"已删除玩家文件: {file_path}", 'ACCOUNT')
# 从缓存中删除
if username in self.player_cache:
del self.player_cache[username]
if username in self.dirty_players:
self.dirty_players.discard(username)
if username in self.active_players_cache:
del self.active_players_cache[username]
# 清理用户数据
if client_id in self.user_data:
del self.user_data[client_id]
# 发送成功响应
self.send_data(client_id, {
"type": "delete_account_response",
"success": True,
"message": "账号删除成功,即将返回主菜单"
})
self.log('INFO', f"用户 {username} 账号删除成功", 'ACCOUNT')
# 稍后断开连接
import threading
def delayed_disconnect():
import time
time.sleep(2)
self._remove_client(client_id)
disconnect_thread = threading.Thread(target=delayed_disconnect)
disconnect_thread.daemon = True
disconnect_thread.start()
except Exception as e:
self.log('ERROR', f"删除账号时出错: {str(e)}", 'ACCOUNT')
return self._send_delete_account_error(client_id, "删除账号失败,请稍后重试")
def _handle_refresh_player_info_request(self, client_id, message):
"""处理刷新玩家信息请求"""
# 检查用户是否已登录
is_logged_in, error_response = self._check_user_logged_in(client_id, "刷新玩家信息")
if not is_logged_in:
return self._send_refresh_info_error(client_id, error_response["message"])
# 获取用户名
username = self.user_data[client_id]["username"]
try:
# 强制从文件重新加载最新数据
player_data = self._load_player_data_from_file(username)
if not player_data:
return self._send_refresh_info_error(client_id, "无法加载玩家数据")
# 只发送账户相关信息,不发送农场数据等
account_info = {
"user_name": player_data.get("user_name", ""),
"user_password": player_data.get("user_password", ""),
"player_name": player_data.get("player_name", ""),
"farm_name": player_data.get("farm_name", ""),
"个人简介": player_data.get("个人简介", ""),
"level": player_data.get("level", 1),
"experience": player_data.get("experience", 0),
"money": player_data.get("money", 0)
}
# 发送刷新后的账户信息
self.send_data(client_id, {
"type": "refresh_player_info_response",
"success": True,
"message": "玩家信息已刷新",
"account_info": account_info
})
self.log('INFO', f"用户 {username} 刷新玩家信息成功", 'ACCOUNT')
except Exception as e:
self.log('ERROR', f"刷新玩家信息时出错: {str(e)}", 'ACCOUNT')
return self._send_refresh_info_error(client_id, "刷新玩家信息失败,请稍后重试")
def _send_modify_account_error(self, client_id, message):
"""发送修改账号信息错误响应"""
self.send_data(client_id, {
"type": "modify_account_info_response",
"success": False,
"message": message
})
def _send_delete_account_error(self, client_id, message):
"""发送删除账号错误响应"""
self.send_data(client_id, {
"type": "delete_account_response",
"success": False,
"message": message
})
def _send_refresh_info_error(self, client_id, message):
"""发送刷新信息错误响应"""
self.send_data(client_id, {
"type": "refresh_player_info_response",
"success": False,
"message": message
})
# ================================账户设置处理方法================================
# 主程序启动入口
if __name__ == "__main__":
import sys
try:
print("=" * 60)
print(f"🌱 萌芽农场游戏服务器 v{server_version} 🌱")
print("=" * 60)
print(f"📡 服务器地址: {server_host}:{server_port}")
print(f"📦 缓冲区大小: {buffer_size} bytes")
print(f"🔧 性能优化: 已启用")
print("=" * 60)
# 创建并启动游戏服务器
server = TCPGameServer()
# 在后台线程中启动服务器
server_thread = threading.Thread(target=server.start)
server_thread.daemon = True
server_thread.start()
print("✅ 服务器启动成功!")
print("📋 功能列表:")
print(" ├── 用户注册/登录系统")
print(" ├── 作物种植与收获")
print(" ├── 浇水与施肥系统")
print(" ├── 每日签到奖励")
print(" ├── 幸运抽奖系统")
print(" ├── 玩家互动功能")
print(" └── 性能优化缓存")
print("=" * 60)
print("🔥 服务器运行中... 按 Ctrl+C 停止服务器")
print("=" * 60)
# 主循环:保持服务器运行
while True:
time.sleep(1)
except KeyboardInterrupt:
print("\n" + "=" * 60)
print("⚠️ 程序被用户中断")
print("💾 正在保存数据并关闭服务器...")
if 'server' in locals():
server.stop()
print("✅ 服务器已安全关闭")
print("👋 感谢使用萌芽农场服务器!")
print("=" * 60)
sys.exit(0)
except Exception as e:
print(f"\n❌ 服务器启动失败: {str(e)}")
print("🔧 请检查配置并重试")
sys.exit(1)