天气系统完成

This commit is contained in:
2025-07-19 17:27:56 +08:00
parent 106a69c89e
commit e466cde9d5
514 changed files with 4678 additions and 4389 deletions

View File

@@ -131,13 +131,14 @@ class EmailVerification:
return ''.join(random.choice(chars) for _ in range(length))
@staticmethod
def send_verification_email(qq_number, verification_code):
def send_verification_email(qq_number, verification_code, email_type="register"):
"""
发送验证码邮件到QQ邮箱
参数:
qq_number (str): 接收者QQ号
verification_code (str): 验证码
email_type (str): 邮件类型,"register""reset_password"
返回:
bool: 发送成功返回True否则返回False
@@ -145,15 +146,25 @@ class EmailVerification:
"""
receiver_email = f"{qq_number}@qq.com"
# 根据邮件类型设置不同的内容
if email_type == "reset_password":
email_title = "【萌芽农场】密码重置验证码"
email_purpose = "重置萌芽农场游戏账号密码"
email_color = "#FF6B35" # 橙红色,表示警告性操作
else:
email_title = "【萌芽农场】注册验证码"
email_purpose = "注册萌芽农场游戏账号"
email_color = "#4CAF50" # 绿色,表示正常操作
# 创建邮件内容
message = MIMEText(f'''
<html>
<body>
<div style="font-family: Arial, sans-serif; color: #333;">
<h2 style="color: #4CAF50;">萌芽农场 - 邮箱验证码</h2>
<h2 style="color: {email_color};">萌芽农场 - 邮箱验证码</h2>
<p>亲爱的玩家,您好!</p>
<p>您正在注册萌芽农场游戏账号,您的验证码是:</p>
<div style="background-color: #f2f2f2; padding: 10px; font-size: 24px; font-weight: bold; color: #4CAF50; text-align: center; margin: 20px 0;">
<p>您正在{email_purpose},您的验证码是:</p>
<div style="background-color: #f2f2f2; padding: 10px; font-size: 24px; font-weight: bold; color: {email_color}; text-align: center; margin: 20px 0;">
{verification_code}
</div>
<p>该验证码有效期为5分钟请勿泄露给他人。</p>
@@ -169,7 +180,7 @@ class EmailVerification:
# 修正From头格式符合QQ邮箱的要求
message['From'] = SENDER_EMAIL
message['To'] = receiver_email
message['Subject'] = Header('【萌芽农场】注册验证码', 'utf-8')
message['Subject'] = Header(email_title, 'utf-8')
try:
# 使用SSL/TLS连接而不是STARTTLS
@@ -182,7 +193,7 @@ class EmailVerification:
return False, f"发送验证码失败: {str(e)}"
@staticmethod
def save_verification_code(qq_number, verification_code, expiry_time=300):
def save_verification_code(qq_number, verification_code, expiry_time=300, code_type="register"):
"""
保存验证码到缓存文件
@@ -190,6 +201,7 @@ class EmailVerification:
qq_number (str): QQ号
verification_code (str): 验证码
expiry_time (int): 过期时间默认5分钟
code_type (str): 验证码类型,"register""reset_password"
返回:
bool: 保存成功返回True否则返回False
@@ -205,33 +217,43 @@ class EmailVerification:
try:
with open(VERIFICATION_CACHE_FILE, 'r', encoding='utf-8') as file:
verification_data = json.load(file)
except:
except Exception as e:
print(f"读取验证码文件失败: {str(e)}")
verification_data = {}
# 添加新的验证码
expire_at = time.time() + expiry_time
current_time = time.time()
# 创建验证码记录,包含更多信息用于调试
verification_data[qq_number] = {
"code": verification_code,
"expire_at": expire_at
"expire_at": expire_at,
"code_type": code_type,
"created_at": current_time,
"used": False # 新增:标记验证码是否已使用
}
# 保存到文件
try:
with open(VERIFICATION_CACHE_FILE, 'w', encoding='utf-8') as file:
json.dump(verification_data, file, indent=2, ensure_ascii=False)
print(f"[验证码系统] 为QQ {qq_number} 保存{code_type}验证码: {verification_code}, 过期时间: {expire_at}")
return True
except Exception as e:
print(f"保存验证码失败: {str(e)}")
return False
@staticmethod
def verify_code(qq_number, input_code):
def verify_code(qq_number, input_code, code_type="register"):
"""
验证用户输入的验证码
参数:
qq_number (str): QQ号
input_code (str): 用户输入的验证码
code_type (str): 验证码类型,"register""reset_password"
返回:
bool: 验证成功返回True否则返回False
@@ -241,23 +263,41 @@ class EmailVerification:
# 检查缓存文件是否存在
if not os.path.exists(VERIFICATION_CACHE_FILE):
print(f"[验证码系统] QQ {qq_number} 验证失败: 缓存文件不存在")
return False, "验证码不存在或已过期"
# 读取验证码数据
try:
with open(VERIFICATION_CACHE_FILE, 'r', encoding='utf-8') as file:
verification_data = json.load(file)
except:
except Exception as e:
print(f"[验证码系统] 读取验证码文件失败: {str(e)}")
return False, "验证码数据损坏"
# 检查该QQ号是否有验证码
if qq_number not in verification_data:
print(f"[验证码系统] QQ {qq_number} 验证失败: 没有找到验证码记录")
return False, "验证码不存在,请重新获取"
# 获取存储的验证码信息
code_info = verification_data[qq_number]
stored_code = code_info.get("code", "")
expire_at = code_info.get("expire_at", 0)
stored_code_type = code_info.get("code_type", "register")
is_used = code_info.get("used", False)
created_at = code_info.get("created_at", 0)
print(f"[验证码系统] QQ {qq_number} 验证码详情: 存储码={stored_code}, 输入码={input_code}, 类型={stored_code_type}, 已使用={is_used}, 创建时间={created_at}")
# 检查验证码类型是否匹配
if stored_code_type != code_type:
print(f"[验证码系统] QQ {qq_number} 验证失败: 验证码类型不匹配,存储类型={stored_code_type}, 请求类型={code_type}")
return False, f"验证码类型不匹配,请重新获取{code_type}验证码"
# 检查验证码是否已被使用
if is_used:
print(f"[验证码系统] QQ {qq_number} 验证失败: 验证码已被使用")
return False, "验证码已被使用,请重新获取"
# 检查验证码是否过期
current_time = time.time()
@@ -266,22 +306,31 @@ class EmailVerification:
del verification_data[qq_number]
with open(VERIFICATION_CACHE_FILE, 'w', encoding='utf-8') as file:
json.dump(verification_data, file, indent=2, ensure_ascii=False)
print(f"[验证码系统] QQ {qq_number} 验证失败: 验证码已过期")
return False, "验证码已过期,请重新获取"
# 验证码比较(不区分大小写)
if input_code.upper() == stored_code.upper():
# 验证成功后移除该验证码
del verification_data[qq_number]
with open(VERIFICATION_CACHE_FILE, 'w', encoding='utf-8') as file:
json.dump(verification_data, file, indent=2, ensure_ascii=False)
return True, "验证码正确"
# 验证成功,标记为已使用而不是删除
verification_data[qq_number]["used"] = True
verification_data[qq_number]["used_at"] = current_time
try:
with open(VERIFICATION_CACHE_FILE, 'w', encoding='utf-8') as file:
json.dump(verification_data, file, indent=2, ensure_ascii=False)
print(f"[验证码系统] QQ {qq_number} 验证成功: 验证码已标记为已使用")
return True, "验证码正确"
except Exception as e:
print(f"[验证码系统] 标记验证码已使用时失败: {str(e)}")
return True, "验证码正确" # 即使标记失败,验证还是成功的
else:
print(f"[验证码系统] QQ {qq_number} 验证失败: 验证码不匹配")
return False, "验证码错误"
@staticmethod
def clean_expired_codes():
"""
清理过期的验证码
清理过期的验证码和已使用的验证码
"""
import time
@@ -295,22 +344,79 @@ class EmailVerification:
current_time = time.time()
removed_keys = []
# 找出过期的验证码
# 找出过期的验证码和已使用的验证码超过1小时
for qq_number, code_info in verification_data.items():
expire_at = code_info.get("expire_at", 0)
is_used = code_info.get("used", False)
used_at = code_info.get("used_at", 0)
should_remove = False
# 过期的验证码
if current_time > expire_at:
should_remove = True
print(f"[验证码清理] 移除过期验证码: QQ {qq_number}")
# 已使用超过1小时的验证码
elif is_used and used_at > 0 and (current_time - used_at) > 3600:
should_remove = True
print(f"[验证码清理] 移除已使用的验证码: QQ {qq_number}")
if should_remove:
removed_keys.append(qq_number)
# 移除过期的验证码
# 移除标记的验证码
for key in removed_keys:
del verification_data[key]
# 保存更新后的数据
with open(VERIFICATION_CACHE_FILE, 'w', encoding='utf-8') as file:
json.dump(verification_data, file, indent=2, ensure_ascii=False)
if removed_keys:
with open(VERIFICATION_CACHE_FILE, 'w', encoding='utf-8') as file:
json.dump(verification_data, file, indent=2, ensure_ascii=False)
print(f"[验证码清理] 共清理了 {len(removed_keys)} 个验证码")
except Exception as e:
print(f"清理过期验证码失败: {str(e)}")
print(f"清理验证码失败: {str(e)}")
@staticmethod
def get_verification_status(qq_number):
"""
获取验证码状态(用于调试)
参数:
qq_number (str): QQ号
返回:
dict: 验证码状态信息
"""
import time
if not os.path.exists(VERIFICATION_CACHE_FILE):
return {"status": "no_cache_file"}
try:
with open(VERIFICATION_CACHE_FILE, 'r', encoding='utf-8') as file:
verification_data = json.load(file)
if qq_number not in verification_data:
return {"status": "no_code"}
code_info = verification_data[qq_number]
current_time = time.time()
return {
"status": "found",
"code": code_info.get("code", ""),
"code_type": code_info.get("code_type", "unknown"),
"used": code_info.get("used", False),
"expired": current_time > code_info.get("expire_at", 0),
"created_at": code_info.get("created_at", 0),
"expire_at": code_info.get("expire_at", 0),
"used_at": code_info.get("used_at", 0)
}
except Exception as e:
return {"status": "error", "message": str(e)}
# 测试邮件发送

View File

@@ -94,6 +94,7 @@ class TCPGameServer(TCPServer):
self.start_batch_save_timer()
self.start_weed_growth_timer()
self.start_wisdom_tree_health_decay_timer()
self.start_verification_code_cleanup_timer()
#初始化性能操作
def _init_performance_settings(self):
@@ -170,6 +171,20 @@ class TCPGameServer(TCPServer):
self.wisdom_tree_decay_timer.daemon = True
self.wisdom_tree_decay_timer.start()
def start_verification_code_cleanup_timer(self):
"""启动验证码清理定时器"""
try:
from QQEmailSend import EmailVerification
EmailVerification.clean_expired_codes()
self.log('INFO', "验证码清理完成", 'SERVER')
except Exception as e:
self.log('ERROR', f"验证码清理时出错: {str(e)}", 'SERVER')
# 创建下一个验证码清理计时器每30分钟检查一次
self.verification_cleanup_timer = threading.Timer(1800, self.start_verification_code_cleanup_timer) # 每30分钟清理一次
self.verification_cleanup_timer.daemon = True
self.verification_cleanup_timer.start()
#获取服务器统计信息
def get_server_stats(self):
"""获取服务器统计信息"""
@@ -203,6 +218,12 @@ class TCPGameServer(TCPServer):
self.wisdom_tree_decay_timer = None
self.log('INFO', "智慧树生命值衰减计时器已停止", 'SERVER')
# 停止验证码清理定时器
if hasattr(self, 'verification_cleanup_timer') and self.verification_cleanup_timer:
self.verification_cleanup_timer.cancel()
self.verification_cleanup_timer = None
self.log('INFO', "验证码清理定时器已停止", 'SERVER')
# 强制保存所有缓存数据
self.log('INFO', "正在保存所有玩家数据...", 'SERVER')
saved_count = self.force_save_all_data()
@@ -678,6 +699,10 @@ class TCPGameServer(TCPServer):
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 == "request_forget_password_verification_code":#忘记密码验证码请求
return self._handle_forget_password_verification_code_request(client_id, message)
elif message_type == "reset_password":#重置密码
return self._handle_reset_password_request(client_id, message)
elif message_type == "verify_code":#验证码
return self._handle_verify_code(client_id, message)
@@ -775,6 +800,16 @@ class TCPGameServer(TCPServer):
return self._handle_wisdom_tree_message(client_id, message)
elif message_type == "get_wisdom_tree_config":#获取智慧树配置
return self._handle_get_wisdom_tree_config(client_id, message)
elif message_type == "sell_crop":#出售作物
return self._handle_sell_crop(client_id, message)
elif message_type == "add_product_to_store":#添加商品到小卖部
return self._handle_add_product_to_store(client_id, message)
elif message_type == "remove_store_product":#下架小卖部商品
return self._handle_remove_store_product(client_id, message)
elif message_type == "buy_store_product":#购买小卖部商品
return self._handle_buy_store_product(client_id, message)
elif message_type == "buy_store_booth":#购买小卖部格子
return self._handle_buy_store_booth(client_id, message)
#---------------------------------------------------------------------------
elif message_type == "message":#处理聊天消息(暂未实现)
@@ -982,9 +1017,12 @@ class TCPGameServer(TCPServer):
# 验证验证码
if verification_code:
from QQEmailSend import EmailVerification
success, verify_message = EmailVerification.verify_code(username, verification_code)
success, verify_message = EmailVerification.verify_code(username, verification_code, "register")
if not success:
self.log('WARNING', f"QQ号 {username} 注册验证码验证失败: {verify_message}", 'SERVER')
return self._send_register_error(client_id, f"验证码错误: {verify_message}")
else:
self.log('INFO', f"QQ号 {username} 注册验证码验证成功", 'SERVER')
# 检查用户是否已存在
file_path = os.path.join("game_saves", f"{username}.json")
@@ -1114,9 +1152,9 @@ class TCPGameServer(TCPServer):
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')
# 保存验证码(注册类型)
EmailVerification.save_verification_code(qq_number, verification_code, 300, "register")
self.log('INFO', f"已向QQ号 {qq_number} 发送注册验证码: {verification_code}", 'SERVER')
return self.send_data(client_id, {
"type": "verification_code_response",
@@ -1166,6 +1204,127 @@ class TCPGameServer(TCPServer):
#验证QQ号格式
#处理忘记密码验证码请求
def _handle_forget_password_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": "forget_password_verification_code_response",
"success": False,
"message": "QQ号格式无效请输入5-12位数字"
})
# 检查账号是否存在
player_data = self.load_player_data(qq_number)
if not player_data:
return self.send_data(client_id, {
"type": "forget_password_verification_code_response",
"success": False,
"message": "该账号不存在请检查QQ号是否正确"
})
# 生成验证码
verification_code = EmailVerification.generate_verification_code()
# 发送验证码邮件(专门用于密码重置)
success, send_message = EmailVerification.send_verification_email(qq_number, verification_code, "reset_password")
if success:
# 保存验证码(密码重置类型)
EmailVerification.save_verification_code(qq_number, verification_code, 300, "reset_password")
self.log('INFO', f"已向QQ号 {qq_number} 发送密码重置验证码: {verification_code}", 'SERVER')
return self.send_data(client_id, {
"type": "forget_password_verification_code_response",
"success": True,
"message": "密码重置验证码已发送到您的QQ邮箱请查收"
})
else:
self.log('ERROR', f"发送密码重置验证码失败: {send_message}", 'SERVER')
return self.send_data(client_id, {
"type": "forget_password_verification_code_response",
"success": False,
"message": f"发送验证码失败: {send_message}"
})
#处理重置密码请求
def _handle_reset_password_request(self, client_id, message):
"""处理重置密码请求"""
from QQEmailSend import EmailVerification
username = message.get("username", "")
new_password = message.get("new_password", "")
verification_code = message.get("verification_code", "")
# 验证必填字段
if not username or not new_password or not verification_code:
return self.send_data(client_id, {
"type": "reset_password_response",
"success": False,
"message": "用户名、新密码或验证码不能为空"
})
# 验证QQ号格式
if not self._validate_qq_number(username):
return self.send_data(client_id, {
"type": "reset_password_response",
"success": False,
"message": "用户名必须是5-12位的QQ号码"
})
# 检查账号是否存在
player_data = self.load_player_data(username)
if not player_data:
return self.send_data(client_id, {
"type": "reset_password_response",
"success": False,
"message": "该账号不存在请检查QQ号是否正确"
})
# 验证验证码(密码重置类型)
success, verify_message = EmailVerification.verify_code(username, verification_code, "reset_password")
if not success:
self.log('WARNING', f"QQ号 {username} 密码重置验证码验证失败: {verify_message}", 'SERVER')
return self.send_data(client_id, {
"type": "reset_password_response",
"success": False,
"message": f"验证码错误: {verify_message}"
})
else:
self.log('INFO', f"QQ号 {username} 密码重置验证码验证成功", 'SERVER')
# 更新密码
try:
player_data["user_password"] = new_password
# 保存到缓存和文件
self.player_cache[username] = player_data
self.dirty_players.add(username)
# 立即保存重要的账户信息
self.save_player_data_immediate(username)
self.log('INFO', f"用户 {username} 密码重置成功", 'ACCOUNT')
return self.send_data(client_id, {
"type": "reset_password_response",
"success": True,
"message": "密码重置成功,请使用新密码登录"
})
except Exception as e:
self.log('ERROR', f"重置密码时出错: {str(e)}", 'ACCOUNT')
return self.send_data(client_id, {
"type": "reset_password_response",
"success": False,
"message": "密码重置失败,请稍后重试"
})
#辅助函数-验证QQ号格式
def _validate_qq_number(self, qq_number):
"""验证QQ号格式"""
@@ -5675,6 +5834,7 @@ class TCPGameServer(TCPServer):
safe_player_data = {
"user_name": target_player_data.get("user_name", target_username),
"username": target_username, # 添加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),
@@ -5690,6 +5850,9 @@ class TCPGameServer(TCPServer):
"出战宠物": self._convert_battle_pets_to_full_data(target_player_data),
"稻草人配置": target_player_data.get("稻草人配置", {}),
"智慧树配置": target_player_data.get("智慧树配置", {}),
"玩家小卖部": target_player_data.get("玩家小卖部", []), # 添加小卖部数据
"小卖部格子数": target_player_data.get("小卖部格子数", 10), # 添加小卖部格子数
"点赞数": target_player_data.get("点赞数", 0), # 添加点赞数
"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)
@@ -8502,6 +8665,454 @@ class TCPGameServer(TCPServer):
#==========================智慧树系统处理==========================
#==========================作物出售处理==========================
def _handle_sell_crop(self, client_id, message):
"""处理作物出售请求"""
# 检查用户是否已登录
logged_in, response = self._check_user_logged_in(client_id, "出售作物", "sell_crop")
if not logged_in:
return self.send_data(client_id, response)
# 获取玩家数据
player_data, username, response = self._load_player_data_with_check(client_id, "sell_crop")
if not player_data:
return self.send_data(client_id, response)
crop_name = message.get("crop_name", "")
sell_count = message.get("sell_count", 1)
unit_price = message.get("unit_price", 0)
# 验证参数
if not crop_name:
return self._send_action_error(client_id, "sell_crop", "作物名称不能为空")
if sell_count <= 0:
return self._send_action_error(client_id, "sell_crop", "出售数量必须大于0")
if unit_price <= 0:
return self._send_action_error(client_id, "sell_crop", "单价必须大于0")
# 检查作物仓库中是否有足够的作物
crop_warehouse = player_data.get("作物仓库", [])
crop_found = False
crop_index = -1
available_count = 0
for i, crop_item in enumerate(crop_warehouse):
if crop_item.get("name") == crop_name:
crop_found = True
crop_index = i
available_count = crop_item.get("count", 0)
break
if not crop_found:
return self._send_action_error(client_id, "sell_crop", f"作物仓库中没有 {crop_name}")
if available_count < sell_count:
return self._send_action_error(client_id, "sell_crop", f"作物数量不足,仓库中只有 {available_count}{crop_name}")
# 验证价格(防止客户端篡改价格)
crop_data = self._load_crop_data()
if crop_name in crop_data:
expected_price = crop_data[crop_name].get("收益", 0)
if unit_price != expected_price:
return self._send_action_error(client_id, "sell_crop", f"价格验证失败,{crop_name} 的正确价格应为 {expected_price} 元/个")
else:
return self._send_action_error(client_id, "sell_crop", f"未知的作物类型:{crop_name}")
# 计算总收入
total_income = sell_count * unit_price
# 执行出售操作
player_data["money"] += total_income
# 从作物仓库中减少数量
crop_warehouse[crop_index]["count"] -= sell_count
# 如果数量为0从仓库中移除该作物
if crop_warehouse[crop_index]["count"] <= 0:
crop_warehouse.pop(crop_index)
# 给予少量出售经验
sell_experience = max(1, sell_count // 5) # 每5个作物给1点经验
player_data["experience"] += sell_experience
# 检查是否升级
self._check_level_up(player_data)
# 保存玩家数据
self.save_player_data(username, player_data)
# 获取显示名称
display_name = crop_name
if crop_name in crop_data:
mature_name = crop_data[crop_name].get("成熟物名称")
if mature_name:
display_name = mature_name
else:
display_name = crop_data[crop_name].get("作物名称", crop_name)
self.log('INFO', f"玩家 {username} 出售了 {sell_count}{crop_name},获得 {total_income} 金币和 {sell_experience} 经验", 'SERVER')
return self.send_data(client_id, {
"type": "action_response",
"action_type": "sell_crop",
"success": True,
"message": f"成功出售 {sell_count}{display_name},获得 {total_income} 金币和 {sell_experience} 经验",
"updated_data": {
"money": player_data["money"],
"experience": player_data["experience"],
"level": player_data["level"],
"作物仓库": player_data["作物仓库"]
}
})
#==========================作物出售处理==========================
#==========================小卖部管理处理==========================
def _handle_add_product_to_store(self, client_id, message):
"""处理添加商品到小卖部请求"""
# 检查用户是否已登录
logged_in, response = self._check_user_logged_in(client_id, "添加商品到小卖部", "add_product_to_store")
if not logged_in:
return self.send_data(client_id, response)
# 获取玩家数据
player_data, username, response = self._load_player_data_with_check(client_id, "add_product_to_store")
if not player_data:
return self.send_data(client_id, response)
product_type = message.get("product_type", "")
product_name = message.get("product_name", "")
product_count = message.get("product_count", 1)
product_price = message.get("product_price", 0)
# 验证参数
if not product_type or not product_name:
return self._send_action_error(client_id, "add_product_to_store", "商品类型或名称不能为空")
if product_count <= 0:
return self._send_action_error(client_id, "add_product_to_store", "商品数量必须大于0")
if product_price <= 0:
return self._send_action_error(client_id, "add_product_to_store", "商品价格必须大于0")
# 初始化小卖部数据
if "玩家小卖部" not in player_data:
player_data["玩家小卖部"] = []
if "小卖部格子数" not in player_data:
player_data["小卖部格子数"] = 10
player_store = player_data["玩家小卖部"]
max_slots = player_data["小卖部格子数"]
# 检查小卖部格子是否已满
if len(player_store) >= max_slots:
return self._send_action_error(client_id, "add_product_to_store", f"小卖部格子已满({len(player_store)}/{max_slots})")
# 检查作物仓库中是否有足够的商品
if product_type == "作物":
crop_warehouse = player_data.get("作物仓库", [])
crop_found = False
crop_index = -1
available_count = 0
for i, crop_item in enumerate(crop_warehouse):
if crop_item.get("name") == product_name:
crop_found = True
crop_index = i
available_count = crop_item.get("count", 0)
break
if not crop_found:
return self._send_action_error(client_id, "add_product_to_store", f"作物仓库中没有 {product_name}")
if available_count < product_count:
return self._send_action_error(client_id, "add_product_to_store", f"作物数量不足,仓库中只有 {available_count}{product_name}")
# 从作物仓库中扣除商品
crop_warehouse[crop_index]["count"] -= product_count
if crop_warehouse[crop_index]["count"] <= 0:
crop_warehouse.pop(crop_index)
# 添加商品到小卖部
new_product = {
"商品类型": product_type,
"商品名称": product_name,
"商品价格": product_price,
"商品数量": product_count
}
player_store.append(new_product)
# 保存玩家数据
self.save_player_data(username, player_data)
self.log('INFO', f"玩家 {username} 添加商品到小卖部: {product_name} x{product_count}, 价格 {product_price}元/个", 'SERVER')
return self.send_data(client_id, {
"type": "action_response",
"action_type": "add_product_to_store",
"success": True,
"message": f"成功添加 {product_count}{product_name} 到小卖部",
"updated_data": {
"玩家小卖部": player_data["玩家小卖部"],
"作物仓库": player_data.get("作物仓库", [])
}
})
def _handle_remove_store_product(self, client_id, message):
"""处理下架小卖部商品请求"""
# 检查用户是否已登录
logged_in, response = self._check_user_logged_in(client_id, "下架小卖部商品", "remove_store_product")
if not logged_in:
return self.send_data(client_id, response)
# 获取玩家数据
player_data, username, response = self._load_player_data_with_check(client_id, "remove_store_product")
if not player_data:
return self.send_data(client_id, response)
slot_index = message.get("slot_index", -1)
# 验证参数
if slot_index < 0:
return self._send_action_error(client_id, "remove_store_product", "无效的商品槽位")
# 检查小卖部数据
player_store = player_data.get("玩家小卖部", [])
if slot_index >= len(player_store):
return self._send_action_error(client_id, "remove_store_product", "商品槽位不存在")
# 获取要下架的商品信息
product_data = player_store[slot_index]
product_type = product_data.get("商品类型", "")
product_name = product_data.get("商品名称", "")
product_count = product_data.get("商品数量", 0)
# 将商品返回到对应仓库
if product_type == "作物":
# 返回到作物仓库
if "作物仓库" not in player_data:
player_data["作物仓库"] = []
crop_warehouse = player_data["作物仓库"]
# 查找是否已有该作物
crop_found = False
for crop_item in crop_warehouse:
if crop_item.get("name") == product_name:
crop_item["count"] += product_count
crop_found = True
break
if not crop_found:
# 添加新的作物条目
crop_data = self._load_crop_data()
quality = "普通"
if crop_data and product_name in crop_data:
quality = crop_data[product_name].get("品质", "普通")
crop_warehouse.append({
"name": product_name,
"quality": quality,
"count": product_count
})
# 从小卖部移除商品
player_store.pop(slot_index)
# 保存玩家数据
self.save_player_data(username, player_data)
self.log('INFO', f"玩家 {username} 下架小卖部商品: {product_name} x{product_count}", 'SERVER')
return self.send_data(client_id, {
"type": "action_response",
"action_type": "remove_store_product",
"success": True,
"message": f"成功下架 {product_count}{product_name},已返回仓库",
"updated_data": {
"玩家小卖部": player_data["玩家小卖部"],
"作物仓库": player_data.get("作物仓库", [])
}
})
def _handle_buy_store_product(self, client_id, message):
"""处理购买小卖部商品请求"""
# 检查用户是否已登录
logged_in, response = self._check_user_logged_in(client_id, "购买小卖部商品", "buy_store_product")
if not logged_in:
return self.send_data(client_id, response)
# 获取买家数据
buyer_data, buyer_username, response = self._load_player_data_with_check(client_id, "buy_store_product")
if not buyer_data:
return self.send_data(client_id, response)
seller_username = message.get("seller_username", "")
slot_index = message.get("slot_index", -1)
product_name = message.get("product_name", "")
unit_price = message.get("unit_price", 0)
quantity = message.get("quantity", 1)
# 验证参数
if not seller_username:
return self._send_action_error(client_id, "buy_store_product", "卖家用户名不能为空")
if slot_index < 0:
return self._send_action_error(client_id, "buy_store_product", "无效的商品槽位")
if quantity <= 0:
return self._send_action_error(client_id, "buy_store_product", "购买数量必须大于0")
# 检查是否是自己购买自己的商品
if buyer_username == seller_username:
return self._send_action_error(client_id, "buy_store_product", "不能购买自己的商品")
# 加载卖家数据
seller_data = self.load_player_data(seller_username)
if not seller_data:
return self._send_action_error(client_id, "buy_store_product", f"卖家 {seller_username} 不存在")
# 检查卖家小卖部
seller_store = seller_data.get("玩家小卖部", [])
if slot_index >= len(seller_store):
return self._send_action_error(client_id, "buy_store_product", "商品不存在")
product_data = seller_store[slot_index]
product_type = product_data.get("商品类型", "")
store_product_name = product_data.get("商品名称", "")
store_unit_price = product_data.get("商品价格", 0)
available_count = product_data.get("商品数量", 0)
# 验证商品信息
if store_product_name != product_name:
return self._send_action_error(client_id, "buy_store_product", "商品名称不匹配")
if store_unit_price != unit_price:
return self._send_action_error(client_id, "buy_store_product", "商品价格已变更,请刷新重试")
if available_count < quantity:
return self._send_action_error(client_id, "buy_store_product", f"商品库存不足,仅剩 {available_count}")
# 计算总价
total_cost = quantity * unit_price
# 检查买家金钱是否足够
if buyer_data["money"] < total_cost:
return self._send_action_error(client_id, "buy_store_product", f"金钱不足,需要 {total_cost}")
# 执行交易
buyer_data["money"] -= total_cost
seller_data["money"] += total_cost
# 扣除卖家商品
seller_store[slot_index]["商品数量"] -= quantity
if seller_store[slot_index]["商品数量"] <= 0:
seller_store.pop(slot_index)
# 给买家添加商品
if product_type == "作物":
if "作物仓库" not in buyer_data:
buyer_data["作物仓库"] = []
buyer_warehouse = buyer_data["作物仓库"]
# 查找是否已有该作物
crop_found = False
for crop_item in buyer_warehouse:
if crop_item.get("name") == product_name:
crop_item["count"] += quantity
crop_found = True
break
if not crop_found:
# 添加新的作物条目
crop_data = self._load_crop_data()
quality = "普通"
if crop_data and product_name in crop_data:
quality = crop_data[product_name].get("品质", "普通")
buyer_warehouse.append({
"name": product_name,
"quality": quality,
"count": quantity
})
# 保存两个玩家的数据
self.save_player_data(buyer_username, buyer_data)
self.save_player_data(seller_username, seller_data)
self.log('INFO', f"玩家 {buyer_username}{seller_username} 的小卖部购买了 {quantity}{product_name},花费 {total_cost}", 'SERVER')
return self.send_data(client_id, {
"type": "action_response",
"action_type": "buy_store_product",
"success": True,
"message": f"成功购买 {quantity}{product_name},花费 {total_cost}",
"updated_data": {
"money": buyer_data["money"],
"作物仓库": buyer_data.get("作物仓库", [])
}
})
def _handle_buy_store_booth(self, client_id, message):
"""处理购买小卖部格子请求"""
# 检查用户是否已登录
logged_in, response = self._check_user_logged_in(client_id, "购买小卖部格子", "buy_store_booth")
if not logged_in:
return self.send_data(client_id, response)
# 获取玩家数据
player_data, username, response = self._load_player_data_with_check(client_id, "buy_store_booth")
if not player_data:
return self.send_data(client_id, response)
cost = message.get("cost", 0)
# 验证参数
if cost <= 0:
return self._send_action_error(client_id, "buy_store_booth", "无效的购买费用")
# 初始化小卖部数据
if "小卖部格子数" not in player_data:
player_data["小卖部格子数"] = 10
current_slots = player_data["小卖部格子数"]
# 检查是否已达上限
if current_slots >= 40:
return self._send_action_error(client_id, "buy_store_booth", "小卖部格子数已达上限(40)")
# 验证费用
expected_cost = 1000 + (current_slots - 10) * 500
if cost != expected_cost:
return self._send_action_error(client_id, "buy_store_booth", f"费用不正确,应为 {expected_cost}")
# 检查玩家金钱是否足够
if player_data["money"] < cost:
return self._send_action_error(client_id, "buy_store_booth", f"金钱不足,需要 {cost}")
# 执行购买
player_data["money"] -= cost
player_data["小卖部格子数"] += 1
# 保存玩家数据
self.save_player_data(username, player_data)
self.log('INFO', f"玩家 {username} 购买小卖部格子,花费 {cost} 元,格子数:{current_slots} -> {player_data['小卖部格子数']}", 'SERVER')
return self.send_data(client_id, {
"type": "action_response",
"action_type": "buy_store_booth",
"success": True,
"message": f"成功购买格子,花费 {cost} 元,当前格子数:{player_data['小卖部格子数']}",
"updated_data": {
"money": player_data["money"],
"小卖部格子数": player_data["小卖部格子数"]
}
})
#==========================小卖部管理处理==========================
# 控制台命令系统
class ConsoleCommands:
"""控制台命令处理类"""
@@ -8516,6 +9127,7 @@ class ConsoleCommands:
"lsplayer": self.cmd_list_players,
"playerinfo": self.cmd_player_info,
"resetland": self.cmd_reset_land,
"weather": self.cmd_weather,
"help": self.cmd_help,
"stop": self.cmd_stop,
"save": self.cmd_save_all,
@@ -8790,6 +9402,51 @@ class ConsoleCommands:
else:
print("❌ 初始化模板中没有找到土地数据")
def cmd_weather(self, args):
"""天气控制命令: /weather <天气类型>"""
if len(args) != 1:
print("❌ 用法: /weather <天气类型>")
print(" 可用天气: clear, rain, snow, cherry, gardenia, willow")
return
weather_type = args[0].lower()
# 定义可用的天气类型映射
weather_map = {
"clear": "晴天",
"rain": "下雨",
"snow": "下雪",
"cherry": "樱花雨",
"gardenia": "栀子花雨",
"willow": "柳叶雨",
"stop": "停止天气"
}
if weather_type not in weather_map:
print("❌ 无效的天气类型")
print(" 可用天气: clear, rain, snow, cherry, gardenia, willow, stop")
return
# 广播天气变更消息给所有在线客户端
weather_message = {
"type": "weather_change",
"weather_type": weather_type,
"weather_name": weather_map[weather_type]
}
# 发送给所有连接的客户端
for client_id in list(self.server.clients.keys()):
try:
self.server.send_data(client_id, weather_message)
except Exception as e:
print(f"⚠️ 向客户端 {client_id} 发送天气消息失败: {str(e)}")
print(f"🌤️ 已将天气切换为: {weather_map[weather_type]}")
if len(self.server.clients) > 0:
print(f" 已通知 {len(self.server.clients)} 个在线客户端")
else:
print(" 当前无在线客户端")
def cmd_help(self, args):
"""显示帮助信息"""
print("🌱 萌芽农场服务器控制台命令帮助")
@@ -8803,6 +9460,10 @@ class ConsoleCommands:
print(" /playerinfo <QQ号> - 查看玩家详细信息")
print(" /resetland <QQ号> - 重置玩家土地状态")
print("")
print("游戏控制命令:")
print(" /weather <类型> - 控制全服天气")
print(" 可用类型: clear, rain, snow, cherry, gardenia, willow, stop")
print("")
print("服务器管理命令:")
print(" /save - 立即保存所有玩家数据")
print(" /reload - 重新加载配置文件")
@@ -8841,6 +9502,7 @@ class ConsoleCommands:
import sys
sys.exit(0)
def console_input_thread(server):
"""控制台输入处理线程"""
console = ConsoleCommands(server)

View File

@@ -68,18 +68,5 @@
"道具背包": [],
"宠物背包":[],
"巡逻宠物":[],
"出战宠物":[],
"last_water_reset_date": "",
"daily_likes": {},
"seeds": {},
"last_check_in_date": "",
"check_in_count": 0,
"daily_check_in": {},
"lucky_draw_history": [],
"total_likes": 0,
"new_player_gift_claimed": false,
"new_player_gift_time": "",
"session_start_time": 0,
"online_gift": {}
"出战宠物":[]
}

View File

@@ -1,6 +0,0 @@
{
"1232132": {
"code": "5UFH2Z",
"expire_at": 1748005553.6155243
}
}

View File

@@ -1,35 +1,35 @@
{
"experience": 3039,
"level": 32,
"money": 1224518,
"experience": 1196,
"level": 35,
"money": 200812377,
"farm_name": "柚大青の小农场",
"player_name": "柚大青",
"user_name": "2143323382",
"user_password": "tyh@19900420",
"last_login_time": "2025年07月14日08时03分08秒",
"total_login_time": "5时36分14秒",
"last_login_time": "2025年07月19日11时01分22秒",
"total_login_time": "6时31分14秒",
"farm_lots": [
{
"crop_type": "番茄",
"grow_time": 724,
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": true,
"max_grow_time": 720,
"is_planted": false,
"max_grow_time": 1440,
"已浇水": false,
"已施肥": false,
"土地等级": 4
},
{
"crop_type": "小麦",
"grow_time": 300,
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": true,
"is_planted": false,
"max_grow_time": 300,
"已浇水": false,
"已施肥": false,
"土地等级": 2
"土地等级": 4
},
{
"crop_type": "野草1",
@@ -40,158 +40,202 @@
"max_grow_time": 5,
"已浇水": false,
"已施肥": false,
"土地等级": 3
"土地等级": 4
},
{
"crop_type": "龙果",
"grow_time": 14492,
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": true,
"max_grow_time": 14400,
"is_planted": false,
"max_grow_time": 300,
"已浇水": false,
"已施肥": false,
"土地等级": 4
},
{
"crop_type": "小麦",
"grow_time": 318,
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": true,
"max_grow_time": 300,
"is_planted": false,
"max_grow_time": 1080,
"已浇水": false,
"已施肥": false,
"土地等级": 1
},
{
"crop_type": "玉米",
"grow_time": 918,
"is_dead": false,
"is_diged": true,
"is_planted": true,
"max_grow_time": 900,
"已浇水": false,
"已施肥": false,
"土地等级": 1
},
{
"crop_type": "小麦",
"grow_time": 316,
"is_dead": false,
"is_diged": true,
"is_planted": true,
"max_grow_time": 300,
"已浇水": false,
"已施肥": false,
"土地等级": 1
"土地等级": 3
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 5,
"max_grow_time": 25200,
"已浇水": false,
"已施肥": false,
"土地等级": 0
"土地等级": 3
},
{
"crop_type": "橘子",
"grow_time": 10234,
"is_dead": false,
"is_diged": true,
"is_planted": true,
"max_grow_time": 10200,
"已浇水": false,
"已施肥": false,
"土地等级": 3
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 5,
"max_grow_time": 300,
"已浇水": false,
"已施肥": false,
"土地等级": 0
"土地等级": 3
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 5,
"max_grow_time": 12000,
"已浇水": false,
"已施肥": false,
"土地等级": 0
"土地等级": 3
},
{
"crop_type": "小麦",
"grow_time": 300,
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": true,
"is_planted": false,
"max_grow_time": 1080,
"已浇水": false,
"已施肥": false,
"土地等级": 3
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 240,
"已浇水": false,
"已施肥": false,
"土地等级": 3
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 1080,
"已浇水": false,
"已施肥": false,
"土地等级": 3
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 720,
"已浇水": false,
"已施肥": false,
"土地等级": 3
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 300,
"已浇水": false,
"已施肥": false,
"土地等级": 2
"土地等级": 3
},
{
"crop_type": "玉米",
"grow_time": 912,
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": true,
"max_grow_time": 900,
"已浇水": false,
"已施肥": false,
"土地等级": 2
},
{
"crop_type": "杂交树1",
"grow_time": 21632,
"is_dead": false,
"is_diged": true,
"is_planted": true,
"max_grow_time": 21600,
"已浇水": false,
"已施肥": false,
"土地等级": 2
},
{
"crop_type": "小麦",
"grow_time": 314,
"is_dead": false,
"is_diged": true,
"is_planted": true,
"max_grow_time": 300,
"已浇水": false,
"已施肥": false,
"土地等级": 1
},
{
"crop_type": "稻谷",
"grow_time": 614,
"is_dead": false,
"is_diged": true,
"is_planted": true,
"max_grow_time": 600,
"已浇水": false,
"已施肥": false,
"土地等级": 1
},
{
"crop_type": "胡萝卜",
"grow_time": 240,
"is_dead": false,
"is_diged": true,
"is_planted": true,
"is_planted": false,
"max_grow_time": 240,
"已浇水": false,
"已施肥": false,
"土地等级": 1
},
{
"crop_type": "花椰菜",
"grow_time": 1334,
"crop_type": "藏红花",
"grow_time": 7006,
"is_dead": false,
"is_diged": true,
"is_planted": true,
"max_grow_time": 1320,
"max_grow_time": 7000,
"已浇水": false,
"已施肥": false,
"土地等级": 1
},
{
"crop_type": "杂交树2",
"grow_time": 25208,
"is_dead": false,
"is_diged": true,
"is_planted": true,
"max_grow_time": 25200,
"已浇水": false,
"已施肥": false,
"土地等级": 1
},
{
"crop_type": "杂交树1",
"grow_time": 21642,
"is_dead": false,
"is_diged": true,
"is_planted": true,
"max_grow_time": 21600,
"已浇水": false,
"已施肥": false,
"土地等级": 4
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 480,
"已浇水": false,
"已施肥": false,
"土地等级": 4
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 14400,
"已浇水": false,
"已施肥": false,
"土地等级": 3
},
{
"crop_type": "芦荟",
"grow_time": 6013,
"is_dead": false,
"is_diged": true,
"is_planted": true,
"max_grow_time": 6000,
"已浇水": false,
"已施肥": false,
"土地等级": 1
@@ -200,144 +244,100 @@
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 5,
"max_grow_time": 240,
"已浇水": false,
"已施肥": false,
"土地等级": 0
"土地等级": 1
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": false,
"is_planted": false,
"max_grow_time": 5,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": false,
"is_planted": false,
"max_grow_time": 5,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "番茄",
"grow_time": 726,
"crop_type": "松露",
"grow_time": 18001,
"is_dead": false,
"is_diged": true,
"is_planted": true,
"max_grow_time": 720,
"max_grow_time": 18000,
"已浇水": false,
"已施肥": false,
"土地等级": 0
"土地等级": 1
},
{
"crop_type": "土豆",
"grow_time": 486,
"crop_type": "藏红花",
"grow_time": 7009,
"is_dead": false,
"is_diged": true,
"is_planted": true,
"max_grow_time": 480,
"max_grow_time": 7000,
"已浇水": false,
"已施肥": false,
"土地等级": 0
"土地等级": 1
},
{
"crop_type": "土豆",
"grow_time": 486,
"crop_type": "杂交树1",
"grow_time": 21607,
"is_dead": false,
"is_diged": true,
"is_planted": true,
"max_grow_time": 480,
"max_grow_time": 21600,
"已浇水": false,
"已施肥": false,
"土地等级": 0
"土地等级": 1
},
{
"crop_type": "杂交树1",
"grow_time": 21603,
"is_dead": false,
"is_diged": true,
"is_planted": true,
"max_grow_time": 21600,
"已浇水": false,
"已施肥": false,
"土地等级": 1
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 5,
"max_grow_time": 3060,
"已浇水": false,
"已施肥": false,
"土地等级": 0
"土地等级": 1
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 5,
"max_grow_time": 2500,
"已浇水": false,
"已施肥": false,
"土地等级": 0
"土地等级": 1
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 5,
"max_grow_time": 600,
"已浇水": false,
"已施肥": false,
"土地等级": 0
"土地等级": 1
},
{
"crop_type": "",
"grow_time": 0,
"crop_type": "杂交树2",
"grow_time": 25215,
"is_dead": false,
"is_diged": false,
"is_planted": false,
"max_grow_time": 5,
"is_diged": true,
"is_planted": true,
"max_grow_time": 25200,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": false,
"is_planted": false,
"max_grow_time": 5,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": false,
"is_planted": false,
"max_grow_time": 5,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": false,
"is_planted": false,
"max_grow_time": 5,
"已浇水": false,
"已施肥": false,
"土地等级": 0
"土地等级": 1
},
{
"crop_type": "",
@@ -561,45 +561,40 @@
}
],
"player_bag": [
{
"name": "稻谷",
"quality": "普通",
"count": 1
},
{
"name": "土豆",
"quality": "普通",
"count": 6
"count": 2
},
{
"name": "小麦",
"quality": "普通",
"count": 8
"count": 2
},
{
"name": "胡萝卜",
"quality": "普通",
"count": 7
"count": 1
},
{
"name": "玉米",
"quality": "优良",
"count": 4
"count": 1
},
{
"name": "番茄",
"quality": "普通",
"count": 3
"count": 1
},
{
"name": "辣椒",
"quality": "普通",
"count": 2
"count": 1
},
{
"name": "草莓",
"quality": "稀有",
"count": 2
"count": 1
},
{
"name": "花椰菜",
@@ -616,15 +611,94 @@
"quality": "普通",
"count": 1
},
{
"name": "月光草",
"quality": "传奇",
"count": 1
},
{
"name": "杂交树1",
"quality": "传奇",
"count": 1
},
{
"name": "杂交树2",
"count": 1
},
{
"name": "荔枝",
"count": 2
},
{
"name": "玫瑰花",
"count": 1
},
{
"name": "石榴",
"count": 2
},
{
"name": "芦荟",
"count": 1
},
{
"name": "向日葵",
"count": 3
}
],
"last_water_reset_date": "2025-06-05",
"注册时间": "2025年05月21日15时00分00秒",
"个人简介": "其实我是一个梨子,真的,不骗你",
"作物仓库": [
{
"name": "番茄",
"quality": "普通",
"count": 23
},
{
"name": "小麦",
"quality": "普通",
"count": 44
},
{
"name": "龙果",
"quality": "稀有",
"count": 4
},
{
"name": "玉米",
"quality": "优良",
"count": 1
},
{
"name": "稻谷",
"quality": "普通",
"count": 3
},
{
"name": "胡萝卜",
"quality": "普通",
"count": 20
},
{
"name": "花椰菜",
"quality": "优良",
"count": 1
},
{
"name": "土豆",
"quality": "普通",
"count": 18
},
{
"name": "咖啡豆",
"quality": "稀有",
"count": 1
"count": 9
},
{
"name": "人参",
"quality": "史诗",
"count": 1
"count": 3
},
{
"name": "藏红花",
@@ -632,30 +706,36 @@
"count": 1
},
{
"name": "龙果",
"quality": "稀有",
"count": 1
},
{
"name": "松露",
"name": "杨桃",
"quality": "史诗",
"count": 1
},
{
"name": "月光草",
"quality": "传奇",
"name": "冬虫夏草",
"quality": "史诗",
"count": 1
},
{
"name": "仙人掌",
"quality": "优良",
"count": 4
},
{
"name": "大豆",
"quality": "普通",
"count": 5
},
{
"name": "荔枝",
"quality": "优良",
"count": 5
},
{
"name": "杂交树2",
"quality": "传奇",
"count": 1
}
],
"last_water_reset_date": "2025-06-05",
"注册时间": "2025年05月21日15时00分00秒",
"个人简介": "其实我是一个梨子,真的,不骗你",
"作物仓库": [],
"宠物背包": [
{
"场景路径": "res://Scene/Pet/SmallBeetle.tscn",
@@ -812,14 +892,14 @@
"2025年07月13日07时26分04秒": "金币302 经验63 土豆x5 小麦x3"
},
"在线礼包": {
"当前日期": "2025-07-14",
"当前日期": "2025-07-19",
"今日在线时长": 0.0,
"已领取礼包": [],
"登录时间": 1752451388.1583223
"登录时间": 1752894082.539563
},
"点赞系统": {
"今日剩余点赞次数": 10,
"点赞上次刷新时间": "2025-07-14"
"点赞上次刷新时间": "2025-07-19"
},
"新手礼包": {
"已领取": true,
@@ -828,7 +908,15 @@
"体力系统": {
"当前体力值": 20,
"最大体力值": 20,
"上次刷新时间": "2025-07-14",
"上次恢复时间": 1752451388.157905
}
"上次刷新时间": "2025-07-19",
"上次恢复时间": 1752894082.5390205
},
"玩家小卖部": [],
"道具背包": [
{
"name": "铲子",
"count": 100
}
],
"小卖部格子数": 10
}