进一步完善服务器功能,添加远程命令系统,踢人系统

This commit is contained in:
2025-08-15 13:20:01 +08:00
parent ea42a1563d
commit 4bc5673726
99 changed files with 24189 additions and 552 deletions

View File

@@ -5,12 +5,12 @@ const client_version :String = "2.2.0" #记录客户端版本
var isZoomDisabled :bool = false
const server_configs = [
#{"host": "127.0.0.1", "port": 6060, "name": "本地"},
{"host": "127.0.0.1", "port": 7070, "name": "本地"},
#{"host": "192.168.31.233", "port": 6060, "name": "家里面局域网"},
#{"host": "192.168.31.205", "port": 6060, "name": "家里面电脑"},
#{"host": "192.168.1.110", "port": 4040, "name": "萌芽局域网"},
#{"host": "47.108.90.0", "port": 4040, "name": "成都内网穿透"}#成都内网穿透
{"host": "47.108.90.0", "port": 6060, "name": "成都公网"}#成都服务器
#{"host": "47.108.90.0", "port": 6060, "name": "成都公网"}#成都服务器
]
const DisableWeatherDisplay :bool = false #是否禁止显示天气

View File

@@ -9,7 +9,7 @@ extends Node
@onready var show_money : Label = $UI/GUI/GameInfoHBox1/money # 显示当前剩余的钱
@onready var show_experience : Label = $UI/GUI/GameInfoHBox1/experience # 显示当前玩家的经验
@onready var show_level : Label = $UI/GUI/GameInfoHBox1/level # 显示当前玩家的等级
@onready var show_tip : Label = $UI/GUI/GameInfoHBox3/tip # 显示小提示
@onready var show_tip : RichTextLabel = $UI/GUI/GameInfoHBox3/tip # 显示小提示
@onready var show_like: Label = $UI/GUI/GameInfoHBox1/like # 显示别人给自己点赞的总赞数
@onready var show_onlineplayer: Label = $UI/GUI/GameInfoHBox3/onlineplayer # 显示服务器在线人数
@onready var show_player_name : Label = $UI/GUI/GameInfoHBox2/player_name # 显示玩家昵称
@@ -17,7 +17,7 @@ extends Node
@onready var show_status_label : Label = $UI/GUI/GameInfoHBox2/StatusLabel # 显示与服务器连接状态
@onready var show_fps: Label = $UI/GUI/GameInfoHBox2/FPS # 显示游戏FPS
@onready var show_hunger_value :Label = $UI/GUI/GameInfoHBox1/hunger_value # 显示玩家体力值
@onready var global_server_broadcast: Label = $UI/GUI/GameInfoHBox3/GlobalServerBroadcast # 显示全服大喇叭的最新消息,走马灯式滚动显示
@onready var global_server_broadcast: RichTextLabel = $UI/GUI/GameInfoHBox3/GlobalServerBroadcast # 显示全服大喇叭的最新消息,走马灯式滚动显示
@onready var watch_broadcast_button: Button = $UI/GUI/GameInfoHBox3/WatchBroadcast # 查看大喇叭按钮
@onready var network_status_label :Label = get_node("/root/main/UI/BigPanel/TCPNetworkManagerPanel/StatusLabel")
@@ -69,6 +69,8 @@ extends Node
@onready var pet_inform_panel: Panel = $UI/SmallPanel/PetInformPanel #宠物信息面板
@onready var player_store_panel: Panel = $UI/BigPanel/PlayerStorePanel #玩家小卖部面板
@onready var game_setting_panel: Panel = $UI/BigPanel/GameSettingPanel #游戏设置面板
@onready var play_game_panel: Panel = $UI/BigPanel/PlayGamePanel #玩玩小游戏面板
@onready var special_farm_panel: Panel = $UI/BigPanel/SpecialFarmPanel #神秘农场面板
@@ -118,7 +120,7 @@ extends Node
@onready var pet_battle_panel: PetBattlePanel = $UI/BigPanel/PetBattlePanel #新的宠物对战场景
#宠物巡逻系统
@onready var pet_patrol_points: Node = $PetPatrolPoints
@onready var pos_1: Marker2D = $PetPatrolPoints/Pos1 #生成点1
@onready var pos_2: Marker2D = $PetPatrolPoints/Pos2#生成点2
@@ -396,6 +398,21 @@ func _input(event):
#==========================玩家排行榜+访问模式处理============================
#打开玩家排行榜
func _on_player_rank_pressed() -> void:
if is_visiting_mode:
Toast.show("您不能访问他人玩家排行榜",Color.RED)
return
player_ranking_panel.show()
pass
#打开玩家排行榜面板
func _on_player_ranking_button_pressed() -> void:
player_ranking_panel.show()
player_ranking_panel.request_player_rankings()
pass
# 处理玩家排行榜响应
func _handle_player_rankings_response(data):
player_ranking_panel.handle_player_rankings_response(data)
@@ -645,9 +662,15 @@ func _on_item_selected(index):
#========================================杂项未分类函数=======================================
#随机游戏提示
# 游戏提示相关变量
var game_tips_config = {} # 服务端游戏小提示配置
var current_tip_index = 0 # 当前小提示索引(用于顺序模式)
#OS
#DisplayServer
#获取游戏提示
func _random_small_game_tips() -> String:
const game_tips = [
# 默认游戏小提示(作为备用)
const default_game_tips = [
"按住wsad可以移动游戏画面",
"使用鼠标滚轮来缩放游戏画面",
"移动端双指缩放游戏画面",
@@ -663,8 +686,32 @@ func _random_small_game_tips() -> String:
"面板左上角有刷新按钮,可以刷新面板",
"小心偷菜被巡逻宠物发现"
]
var random_index = randi() % game_tips.size()
var selected_tip = game_tips[random_index]
# 获取游戏小提示数组
var game_tips = default_game_tips
var switch_mode = "随机" # 默认切换模式
# 如果有服务端配置,使用服务端配置
if game_tips_config.has("游戏小提示") and game_tips_config["游戏小提示"].size() > 0:
game_tips = game_tips_config["游戏小提示"]
switch_mode = game_tips_config.get("切换模式", "随机")
if game_tips.size() == 0:
return "欢迎来到萌芽农场!"
# 根据切换模式选择小提示
var selected_tip = ""
match switch_mode:
"顺序":
selected_tip = game_tips[current_tip_index]
current_tip_index = (current_tip_index + 1) % game_tips.size()
"倒序":
selected_tip = game_tips[current_tip_index]
current_tip_index = (current_tip_index - 1 + game_tips.size()) % game_tips.size()
"随机", _:
var random_index = randi() % game_tips.size()
selected_tip = game_tips[random_index]
return selected_tip
@@ -713,6 +760,13 @@ func handle_login_success(player_data: Dictionary):
else:
print("登录成功后请求宠物配置数据失败")
# 登录成功后请求游戏小提示配置数据
if tcp_network_manager_panel and tcp_network_manager_panel.has_method("sendGetGameTipsConfig"):
if tcp_network_manager_panel.sendGetGameTipsConfig():
print("登录成功后请求游戏小提示配置数据")
else:
print("登录成功后请求游戏小提示配置数据失败")
# 其他登录成功后的初始化逻辑可以在这里添加
start_game = true
@@ -903,12 +957,6 @@ func _update_ui():
var my_likes = like_system.get("总点赞数", 0)
show_like.text = "点赞数:" + str(int(my_likes))
#打开玩家排行榜面板
func _on_player_ranking_button_pressed() -> void:
player_ranking_panel.show()
player_ranking_panel.request_player_rankings()
pass
#打开设置面板
func _on_setting_button_pressed() -> void:
@@ -1002,32 +1050,95 @@ func _on_open_store_button_pressed() -> void:
crop_store_panel.move_to_front()
pass
#打开种子商店面板
func _on_seed_store_pressed() -> void:
if is_visiting_mode:
Toast.show("您不能访问他人种子商店",Color.RED)
return
crop_store_panel.show()
pass
#打开种子仓库面板
func _on_seed_warehouse_button_pressed() -> void:
player_bag_panel.show()
#打开玩家道具背包面板
func _on_item_bag_button_pressed() -> void:
item_bag_panel.show()
#打开道具商店面板
func _on_item_store_button_pressed() -> void:
item_store_panel.show()
#打开种子仓库面板
func _on_seed_warehouse_pressed() -> void:
if is_visiting_mode:
Toast.show("您不能访问他人种子仓库",Color.RED)
return
crop_store_panel.show()
pass
#打开作物仓库面板
func _on_crop_warehouse_button_pressed() -> void:
crop_warehouse_panel.show()
#打开作物仓库面板
func _on_crop_warehouse_pressed() -> void:
if is_visiting_mode:
Toast.show("您不能访问他人作物仓库",Color.RED)
return
crop_warehouse_panel.show()
pass
#打开道具背包面板
func _on_item_bag_button_pressed() -> void:
item_bag_panel.show()
#打开道具背包面板
func _on_item_bag_pressed() -> void:
if is_visiting_mode:
Toast.show("您不能访问他人道具背包",Color.RED)
return
item_bag_panel.show()
pass
#打开道具商店面板
func _on_item_store_button_pressed() -> void:
item_store_panel.show()
#打开道具商店面板
func _on_item_store_pressed() -> void:
if is_visiting_mode:
Toast.show("您不能访问他人道具商店",Color.RED)
return
item_store_panel.show()
pass
#打开宠物背包面板
func _on_pet_bag_button_pressed() -> void:
pet_bag_panel.show()
pass
#打开宠物背包面板
func _on_pet_bag_pressed() -> void:
if is_visiting_mode:
Toast.show("您不能访问他人宠物背包",Color.RED)
return
pet_bag_panel.show()
pass
#打开宠物商店面板
func _on_pet_store_button_pressed() -> void:
pet_store_panel.show()
pass
#打开宠物商店面板
func _on_pet_store_pressed() -> void:
if is_visiting_mode:
Toast.show("您不能访问他人宠物商店",Color.RED)
return
pet_store_panel.show()
pass
#==========================打开基础面板================================
@@ -1055,6 +1166,10 @@ func _try_load_from_server():
# 从服务器请求最新道具配置数据
print("尝试从服务器获取最新道具配置数据...")
tcp_network_manager_panel.sendGetItemConfig()
# 从服务器请求游戏小提示配置数据
print("尝试从服务器获取游戏小提示配置数据...")
tcp_network_manager_panel.sendGetGameTipsConfig()
else:
print("服务器未连接,使用当前本地数据")
@@ -1213,6 +1328,38 @@ func _handle_pet_config_response(response_data):
print("从服务器获取宠物配置数据失败:", message)
pet_config = {}
# 处理服务器游戏小提示配置响应
func _handle_game_tips_config_response(response_data):
var success = response_data.get("success", false)
if success:
var config_data = response_data.get("game_tips_config", {})
if config_data:
# 更新游戏小提示配置
game_tips_config = config_data
print("游戏小提示配置已从服务器更新")
print("切换模式:", config_data.get("切换模式", "顺序"))
print("切换速度:", config_data.get("切换速度", 5))
print("小提示数量:", config_data.get("游戏小提示", []).size())
# 更新小提示切换间隔时间
var switch_speed = config_data.get("切换速度", 5)
five_interval = float(switch_speed)
print("小提示切换间隔已更新为:", five_interval, "")
# 如果游戏小提示面板存在,更新其配置
if has_node("GameTipsPanel"):
var tips_panel = get_node("GameTipsPanel")
if tips_panel.has_method("update_config"):
tips_panel.update_config(config_data)
else:
print("服务器返回的游戏小提示配置数据为空")
game_tips_config = {}
else:
var message = response_data.get("message", "未知错误")
print("从服务器获取游戏小提示配置数据失败:", message)
game_tips_config = {}
#===============================================初始化数据处理===============================================
@@ -1640,8 +1787,6 @@ class CropTextureManager:
if texture:
texture_cache[crop_name][stage] = texture
# 全局作物图片管理器实例
var crop_texture_manager: CropTextureManager
@@ -1848,6 +1993,16 @@ func _execute_buy_new_ground():
#===============================================每日签到处理===============================================
#打开每日签到
func _on_daily_checkin_gift_pressed() -> void:
if is_visiting_mode:
Toast.show("您不能访问他人每日签到礼包",Color.RED)
return
daily_check_in_panel.show()
# 刷新签到数据
daily_check_in_panel.refresh_check_in_data()
pass
#每日签到 奖励可以有钱币,经验,随机种子 连续签到奖励更多 连续签到只要不中断,奖励会随着签到的次数逐渐变得丰厚
func _on_daily_check_in_button_pressed() -> void:
daily_check_in_panel.show()
@@ -2328,7 +2483,6 @@ func update_broadcast_display_from_panel():
else:
global_server_broadcast.text = "全服大喇叭"
# 初始化大喇叭显示
func _init_broadcast_display():
if global_server_broadcast and global_server_broadcast_panel:
@@ -2428,7 +2582,6 @@ func _on_one_click_screen_shot_pressed() -> void:
# 恢复UI显示
_restore_ui_visibility_state(ui_state)
# 保存当前UI可见性状态
func _save_ui_visibility_state() -> Dictionary:
@@ -2518,6 +2671,15 @@ func _restore_ui_visibility_state(state: Dictionary):
#====================================在线礼包处理=========================================
#打开在线礼包
func _on_online_time_gift_pressed() -> void:
if is_visiting_mode:
Toast.show("您不能访问他人在线时长礼包",Color.RED)
return
# 每次打开面板时都请求最新的在线数据
online_gift_panel.show_panel_and_request_data()
pass
#在线礼包,在线时间越久,越丰富,默认 1分钟 10分钟 30分钟 1小时 3小时 5小时 每天刷新
func _on_online_gift_button_pressed() -> void:
# 每次打开面板时都请求最新的在线数据
@@ -2850,7 +3012,6 @@ func init_scare_crow_config():
# 没有稻草人配置,隐藏稻草人
scare_crow.hide()
#打开农场稻草人设置面板
func _on_scare_crow_pressed() -> void:
if is_visiting_mode:
@@ -3181,10 +3342,6 @@ func init_patrol_pets():
func check_battle_patrol_conflict(battle_pet_id: String, patrol_pet_id: String) -> bool:
return battle_pet_id == patrol_pet_id
#===============================================巡逻宠物管理===============================================
# 通用对话框显示函数
func _show_battle_dialog(title: String, content: String, ok_text: String, cancel_text: String, ok_callback: Callable, cancel_callback: Callable):
# 使用专用的EscapeDialog创建对战选择弹窗
@@ -3288,6 +3445,9 @@ func _customize_escape_button(button: Button, normal_color: Color, hover_color:
button.add_theme_color_override("font_color_hover", Color.WHITE)
button.add_theme_color_override("font_color_pressed", Color.WHITE)
button.add_theme_font_size_override("font_size", 18)
#===============================================巡逻宠物管理===============================================
#====================================偷菜被发现-宠物对战处理=========================================
# 处理偷菜被发现响应
@@ -3413,6 +3573,7 @@ func _on_steal_escape_confirmed(escape_cost: int):
#====================================偷菜被发现-宠物对战处理=========================================
#========================访问模式直接向巡逻宠物发起战斗========================
func _on_battle_button_pressed() -> void:
# 检查是否为访问模式
@@ -3535,6 +3696,40 @@ func _update_battle_button_visibility() -> void:
# ======================================= 宠物对战系统 =========================================
# 处理宠物对战结束
func _on_pet_battle_ended(winner_team: String, battle_data: Dictionary):
"""处理宠物对战结束后的逻辑"""
print("[宠物对战] 对战结束,获胜方: ", winner_team)
print("[宠物对战] 对战数据: ", battle_data)
# 准备发送到服务器的对战结果数据
var battle_result = {
"winner_team": winner_team,
"attacker_name": user_name, # 攻击方(玩家自己)
"defender_name": visited_player_data.get("玩家昵称", "未知玩家"), # 防守方(被访问玩家)
"battle_type": "steal_battle", # 对战类型:偷菜对战
"attacker_pets": battle_data.get("attacker_pets", []), # 攻击方宠物数据
"defender_pets": battle_data.get("defender_pets", []), # 防守方宠物数据
"battle_duration": battle_data.get("battle_duration", 0), # 对战持续时间
"timestamp": Time.get_unix_time_from_system() # 对战时间戳
}
# 发送对战结果到服务器
if tcp_network_manager_panel and tcp_network_manager_panel.has_method("send_pet_battle_result"):
tcp_network_manager_panel.send_pet_battle_result(battle_result)
print("[宠物对战] 对战结果已发送到服务器")
else:
print("[宠物对战] 无法发送对战结果到服务器")
# 显示对战结果提示
if winner_team == "attacker":
Toast.show("恭喜!您在偷菜对战中获胜!", Color.GREEN)
else:
Toast.show("很遗憾,您在偷菜对战中失败了。", Color.RED)
# ======================================= 宠物对战系统 =========================================
#=======================================智慧树系统=========================================
#智慧树按钮点击
@@ -3661,6 +3856,19 @@ func _handle_save_game_settings_response(data):
# ======================================= 今日占卜系统 =========================================
#今日占卜
func _on_today_divination_pressed() -> void:
if is_visiting_mode:
return
today_divination_panel.show()
pass
#打开今日占卜面板
func _on_today_divination_button_pressed() -> void:
today_divination_panel.show()
pass
# 处理占卜响应
func _handle_divination_response(divination_data):
"""处理服务器返回的占卜数据,更新本地玩家数据"""
@@ -3676,136 +3884,155 @@ func get_player_divination_data():
# ======================================= 今日占卜系统 =========================================
#========================================玩家小卖部===========================
#打开小卖部面板
func _on_my_store_button_pressed() -> void:
if is_visiting_mode:
Toast.show("您不能访问他人小卖部",Color.RED)
return
player_store_panel.show()
pass
#打开小卖部面板
func _on_player_store_pressed() -> void:
if is_visiting_mode:
Toast.show("您不能访问他人小卖部",Color.RED)
return
player_store_panel.show()
pass
#========================================玩家小卖部===========================
#打开种子商店
func _on_seed_store_pressed() -> void:
if is_visiting_mode:
Toast.show("您不能访问他人种子商店",Color.RED)
return
crop_store_panel.show()
#宠物星辰塔
func _on_pet_ladder_match_pressed() -> void:
pass
#打开道具商店
func _on_item_store_pressed() -> void:
if is_visiting_mode:
Toast.show("您不能访问他人道具商店",Color.RED)
return
item_store_panel.show()
#宠物小窝
func _on_pet_nest_pressed() -> void:
pass
#打开宠物商店
func _on_pet_store_pressed() -> void:
#玩玩小游戏
func _on_play_small_game_pressed() -> void:
if is_visiting_mode:
Toast.show("您不能访问他人宠物商店",Color.RED)
return
pet_store_panel.show()
play_game_panel.show()
pass
#神秘农场
func _on_mystery_farmland_pressed() -> void:
if is_visiting_mode:
return
special_farm_panel.show()
pass
#打开作物仓库
func _on_crop_warehouse_pressed() -> void:
if is_visiting_mode:
Toast.show("您不能访问他人作物仓库",Color.RED)
#访问模式下送金币(已经设置了只能访问模式才会显示这个按钮)
func _on_send_money_button_pressed() -> void:
if not is_visiting_mode:
Toast.show("只能在访问模式下送金币", Color.RED)
return
crop_warehouse_panel.show()
pass
#打开种子仓库
func _on_seed_warehouse_pressed() -> void:
if is_visiting_mode:
Toast.show("您不能访问他人种子仓库",Color.RED)
return
crop_store_panel.show()
pass
#打开玩家排行榜
func _on_player_rank_pressed() -> void:
if is_visiting_mode:
Toast.show("您不能访问他人玩家排行榜",Color.RED)
return
player_ranking_panel.show()
pass
#打开每日签到
func _on_daily_checkin_gift_pressed() -> void:
if is_visiting_mode:
Toast.show("您不能访问他人每日签到礼包",Color.RED)
return
daily_check_in_panel.show()
pass
#打开在线礼包
func _on_online_time_gift_pressed() -> void:
if is_visiting_mode:
Toast.show("您不能访问他人在线时长礼包",Color.RED)
return
online_gift_panel.show()
pass
#打开宠物背包
func _on_pet_bag_pressed() -> void:
if is_visiting_mode:
Toast.show("您不能访问他人宠物背包",Color.RED)
return
pet_bag_panel.show()
pass
#打开道具背包
func _on_item_bag_pressed() -> void:
if is_visiting_mode:
Toast.show("您不能访问他人道具背包",Color.RED)
return
item_bag_panel.show()
pass
# ======================================= 宠物对战系统 =========================================
# 处理宠物对战结束
func _on_pet_battle_ended(winner_team: String, battle_data: Dictionary):
"""处理宠物对战结束后的逻辑"""
print("[宠物对战] 对战结束,获胜方: ", winner_team)
print("[宠物对战] 对战数据: ", battle_data)
# 准备发送到服务器的对战结果数据
var battle_result = {
"winner_team": winner_team,
"attacker_name": user_name, # 攻击方(玩家自己)
"defender_name": visited_player_data.get("玩家昵称", "未知玩家"), # 防守方(被访问玩家)
"battle_type": "steal_battle", # 对战类型:偷菜对战
"attacker_pets": battle_data.get("attacker_pets", []), # 攻击方宠物数据
"defender_pets": battle_data.get("defender_pets", []), # 防守方宠物数据
"battle_duration": battle_data.get("battle_duration", 0), # 对战持续时间
"timestamp": Time.get_unix_time_from_system() # 对战时间戳
}
# 获取自己的原始金币数(从保存的原始数据中获取)
var my_money = original_player_data.get("钱币", 0)
# 发送对战结果到服务器
if tcp_network_manager_panel and tcp_network_manager_panel.has_method("send_pet_battle_result"):
tcp_network_manager_panel.send_pet_battle_result(battle_result)
print("[宠物对战] 对战结果已发送到服务器")
# 检查自己的金币是否足够
if my_money < 500:
Toast.show("您的金币不足500无法送金币", Color.RED)
return
# 获取被访问玩家的昵称
var target_nickname = visited_player_data.get("玩家昵称", "未知玩家")
# 显示确认弹窗
_show_send_money_confirmation(target_nickname, my_money)
func _show_send_money_confirmation(target_nickname: String, my_money: int):
"""显示送金币确认弹窗"""
var confirmation_dialog = AcceptDialog.new()
confirmation_dialog.title = "送金币确认"
confirmation_dialog.dialog_text = "确定要送给 " + target_nickname + " 500金币吗\n\n您当前拥有:" + str(my_money) + "金币"
confirmation_dialog.ok_button_text = "确定送出"
# 添加取消按钮
confirmation_dialog.add_cancel_button("取消")
# 连接确认信号
confirmation_dialog.confirmed.connect(_on_send_money_confirmed)
# 添加到场景并显示
get_tree().current_scene.add_child(confirmation_dialog)
confirmation_dialog.popup_centered()
func _on_send_money_confirmed():
"""确认送金币后的处理"""
if not is_visiting_mode:
return
# 再次检查自己的金币是否足够(防止在弹窗期间金币发生变化)
var my_money = original_player_data.get("钱币", 0)
if my_money < 500:
Toast.show("金币不足,无法送出", Color.RED)
return
# 获取被访问玩家的用户名
var target_username = visited_player_data.get("玩家账号", "")
if target_username == "":
Toast.show("无法获取目标玩家信息", Color.RED)
return
# 发送送金币请求到服务器
if tcp_network_manager_panel and tcp_network_manager_panel.has_method("sendGiveMoney"):
var success = tcp_network_manager_panel.sendGiveMoney(target_username, 500)
if success:
Toast.show("正在送出金币...", Color.CYAN)
else:
Toast.show("网络未连接,无法送金币", Color.RED)
else:
print("[宠物对战] 无法发送对战结果到服务器")
Toast.show("网络管理器不可用", Color.RED)
func _handle_give_money_response(data):
"""处理送金币响应"""
var success = data.get("success", false)
var message = data.get("message", "")
var updated_data = data.get("updated_data", {})
var target_updated_data = data.get("target_updated_data", {})
# 显示对战结果提示
if winner_team == "attacker":
Toast.show("恭喜!您在偷菜对战中获胜!", Color.GREEN)
if success:
# 更新自己原始数据中的金币
original_player_data["钱币"] = updated_data.get("钱币", original_player_data.get("钱币", 0))
# 如果在访问模式下,更新被访问者的金币显示
if is_visiting_mode and target_updated_data.has("钱币"):
# 更新被访问者的数据
visited_player_data["钱币"] = target_updated_data.get("钱币", 0)
# 更新当前显示的金币数(显示被访问者的金币)
money = target_updated_data.get("钱币", 0)
_update_ui()
else:
# 非访问模式,正常更新自己的金币显示
money = updated_data.get("钱币", money)
_update_ui()
Toast.show(message, Color.GREEN)
else:
Toast.show("很遗憾,您在偷菜对战中失败了。", Color.RED)
# ======================================= 宠物对战系统 =========================================
Toast.show("送金币失败:" + message, Color.RED)
func _handle_money_received_notification(data):
"""处理收到金币通知"""
var sender_nickname = data.get("sender_nickname", "未知玩家")
var amount = data.get("amount", 0)
var new_money = data.get("new_money", 0)
# 更新自己的金币
money = new_money
_update_ui()
# 显示收到金币的通知
Toast.show("收到来自 " + sender_nickname + "" + str(amount) + " 金币!", Color.GOLD)
# 可以添加音效或其他特效
print("收到金币通知:来自 ", sender_nickname, ",金额:", amount)
func _on_today_divination_button_pressed() -> void:
today_divination_panel.show()
pass
# 返回登录界面
func return_to_login():
"""被踢出时返回登录界面"""
# 清理当前游戏状态
is_visiting_mode = false
visited_player_data = {}
original_player_data = {}
# 切换到登录场景
get_tree().change_scene_to_file("res://LoginPanel.tscn")

View File

@@ -1,4 +1,4 @@
[gd_scene load_steps=107 format=3 uid="uid://dgh61dttaas5a"]
[gd_scene load_steps=113 format=3 uid="uid://dgh61dttaas5a"]
[ext_resource type="Script" uid="uid://2pt11sfcaxf7" path="res://MainGame.gd" id="1_v3yaj"]
[ext_resource type="Texture2D" uid="uid://du2pyiojliasy" path="res://assets/游戏UI/经验球.webp" id="2_6jgly"]
@@ -18,6 +18,7 @@
[ext_resource type="Texture2D" uid="uid://bso5fyjavdien" path="res://assets/游戏UI/玩家数图标.webp" id="10_vygm6"]
[ext_resource type="PackedScene" uid="uid://cbhitturvihqj" path="res://Scene/BigPanel/LoginPanel.tscn" id="11_6jgly"]
[ext_resource type="PackedScene" uid="uid://dckc8nrn7p425" path="res://Scene/SmallPanel/LandPanel.tscn" id="12_y1hsh"]
[ext_resource type="Texture2D" uid="uid://dsds2gsvqxfak" path="res://assets/游戏UI/大喇叭.webp" id="13_5liyv"]
[ext_resource type="PackedScene" uid="uid://dpiy0aim20n2h" path="res://Scene/SmallPanel/OnlineGiftPanel.tscn" id="14_5b81d"]
[ext_resource type="PackedScene" uid="uid://4rwitowdt4h" path="res://Scene/SmallPanel/OneClickPlantPanel.tscn" id="15_8kysg"]
[ext_resource type="PackedScene" uid="uid://btp1h6hic2sin" path="res://Scene/Dialog/AcceptDialog.tscn" id="16_0igvr"]
@@ -40,8 +41,10 @@
[ext_resource type="Script" uid="uid://d4fvv2sjngajr" path="res://Script/Dialog/BatchBuyPopup.gd" id="29_5b81d"]
[ext_resource type="PackedScene" uid="uid://diwbnwhnq026" path="res://Scene/NewPet/PetBattlePanel.tscn" id="29_mw3xw"]
[ext_resource type="PackedScene" uid="uid://dos15dmc1b6bt" path="res://GUI/GameSettingPanel.tscn" id="30_game_setting"]
[ext_resource type="PackedScene" uid="uid://jjlgdnoo8e52" path="res://Scene/BigPanel/PlayGamePanel.tscn" id="30_rawle"]
[ext_resource type="Texture2D" uid="uid://2sdfbvf1isif" path="res://icon.svg" id="31_uc6q1"]
[ext_resource type="Script" uid="uid://doo34ll0yb078" path="res://Script/SmallPanel/PetInformPanel.gd" id="31_vygm6"]
[ext_resource type="PackedScene" uid="uid://byxhjyyaahs6q" path="res://Scene/BigPanel/SpecialFarmPanel.tscn" id="31_ww70k"]
[ext_resource type="Script" uid="uid://bakeq8tm6r4j4" path="res://Script/SmallPanel/GlobalServerBroadcastPanel.gd" id="34_k1sw4"]
[ext_resource type="Script" uid="uid://dobao5y5s2dij" path="res://Script/SmallPanel/ScareCrowPanel.gd" id="35_6ylhg"]
[ext_resource type="Texture2D" uid="uid://d06uaoowmcvxj" path="res://assets/稻草人图片/稻草人2.webp" id="36_jyxgm"]
@@ -57,8 +60,6 @@
[ext_resource type="Script" uid="uid://cha0uw4ra1trr" path="res://Script/Dialog/AddProduct2StorePopup.gd" id="46_8d602"]
[ext_resource type="Texture2D" uid="uid://dilipbs0lncpd" path="res://assets/草地图片/草地10.webp" id="48_2i8fe"]
[ext_resource type="Texture2D" uid="uid://du34yctd8bd8m" path="res://assets/灌木丛图片/灌木丛1.webp" id="49_xjiif"]
[ext_resource type="Texture2D" uid="uid://dswjorjhf1i6f" path="res://assets/灌木丛图片/灌木丛2.webp" id="50_sqnmr"]
[ext_resource type="Texture2D" uid="uid://go3n3qnpancf" path="res://assets/灌木丛图片/灌木丛3.webp" id="51_2i8fe"]
[ext_resource type="Texture2D" uid="uid://dk4yl4ghmxaa2" path="res://assets/天气系统图片/雪花.webp" id="53_4ka7t"]
[ext_resource type="Texture2D" uid="uid://chcgrmluhfxuk" path="res://assets/天气系统图片/樱花1.webp" id="53_tdq2s"]
[ext_resource type="Texture2D" uid="uid://c1qqalp7owgy2" path="res://assets/天气系统图片/栀子花1.webp" id="53_xyeuq"]
@@ -80,7 +81,12 @@
[ext_resource type="Texture2D" uid="uid://ic2nvi3xlwl4" path="res://assets/装饰物图片/在线时长礼包.webp" id="64_crc4a"]
[ext_resource type="Texture2D" uid="uid://1xgmal8sw6il" path="res://assets/装饰物图片/宠物背包.webp" id="67_onvxb"]
[ext_resource type="Texture2D" uid="uid://ywdg7xgq7hm8" path="res://assets/装饰物图片/道具背包.webp" id="68_bpbm8"]
[ext_resource type="Texture2D" uid="uid://b8k7gknqsokt2" path="res://assets/装饰物图片/占卜台.webp" id="68_yceks"]
[ext_resource type="Texture2D" uid="uid://bnv6wb0k443fv" path="res://assets/天气系统图片/柳叶2.webp" id="69_uyv6e"]
[ext_resource type="Texture2D" uid="uid://c1lviq3nc00u5" path="res://assets/装饰物图片/宠物天梯赛.webp" id="69_yceks"]
[ext_resource type="Texture2D" uid="uid://bwljgu2ltfc7j" path="res://assets/装饰物图片/宠物小窝.webp" id="70_yceks"]
[ext_resource type="Texture2D" uid="uid://dcfb173iikas" path="res://assets/装饰物图片/玩玩小游戏.webp" id="71_w7q6d"]
[ext_resource type="Texture2D" uid="uid://cpsfkh7khetfb" path="res://assets/装饰物图片/神秘农场.webp" id="72_7i23t"]
[ext_resource type="Script" uid="uid://di8wjflimodb0" path="res://GameManager/DayNightSystem.gd" id="73_6fhdl"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_adtqp"]
@@ -315,7 +321,7 @@ anchors_preset = 0
[node name="GameInfoHBox1" type="HBoxContainer" parent="UI/GUI"]
layout_mode = 0
offset_right = 1339.0
offset_right = 1401.0
offset_bottom = 35.0
[node name="experience_image" type="TextureRect" parent="UI/GUI/GameInfoHBox1"]
@@ -413,7 +419,7 @@ text = "点赞数0"
[node name="GameInfoHBox2" type="HBoxContainer" parent="UI/GUI"]
layout_mode = 0
offset_top = 35.0
offset_right = 1336.0
offset_right = 1396.0
offset_bottom = 70.0
[node name="player_name_image" type="TextureRect" parent="UI/GUI/GameInfoHBox2"]
@@ -490,7 +496,7 @@ text = "FPS0"
[node name="GameInfoHBox3" type="HBoxContainer" parent="UI/GUI"]
layout_mode = 0
offset_top = 70.0
offset_right = 1335.0
offset_right = 1398.0
offset_bottom = 113.0
[node name="tip_image" type="TextureRect" parent="UI/GUI/GameInfoHBox3"]
@@ -498,39 +504,50 @@ layout_mode = 2
texture = ExtResource("5_5b81d")
expand_mode = 2
[node name="tip" type="Label" parent="UI/GUI/GameInfoHBox3"]
[node name="tip" type="RichTextLabel" parent="UI/GUI/GameInfoHBox3"]
custom_minimum_size = Vector2(300, 0)
layout_mode = 2
theme_override_colors/font_color = Color(1, 0.564706, 1, 1)
theme_override_colors/font_shadow_color = Color(0, 0, 0, 1)
size_flags_horizontal = 3
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/shadow_offset_x = 3
theme_override_constants/shadow_offset_y = 3
theme_override_colors/font_shadow_color = Color(0, 0, 0, 1)
theme_override_constants/outline_size = 10
theme_override_constants/shadow_offset_y = 3
theme_override_constants/shadow_offset_x = 3
theme_override_constants/shadow_outline_size = 10
theme_override_fonts/font = ExtResource("3_t4s8j")
theme_override_font_sizes/font_size = 25
theme_override_font_sizes/bold_italics_font_size = 25
theme_override_font_sizes/italics_font_size = 25
theme_override_font_sizes/mono_font_size = 25
theme_override_font_sizes/normal_font_size = 25
theme_override_font_sizes/bold_font_size = 25
bbcode_enabled = true
text = "游戏小提示"
vertical_alignment = 1
threaded = true
[node name="GlobalServerBroadcast_image" type="TextureRect" parent="UI/GUI/GameInfoHBox3"]
layout_mode = 2
texture = ExtResource("5_5b81d")
texture = ExtResource("13_5liyv")
expand_mode = 2
[node name="GlobalServerBroadcast" type="Label" parent="UI/GUI/GameInfoHBox3"]
[node name="GlobalServerBroadcast" type="RichTextLabel" parent="UI/GUI/GameInfoHBox3"]
custom_minimum_size = Vector2(300, 0)
layout_mode = 2
theme_override_colors/font_color = Color(1, 0.564706, 0.137255, 1)
theme_override_colors/font_shadow_color = Color(0, 0, 0, 1)
size_flags_horizontal = 3
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/shadow_offset_x = 3
theme_override_constants/shadow_offset_y = 3
theme_override_colors/font_shadow_color = Color(0, 0, 0, 1)
theme_override_constants/outline_size = 10
theme_override_constants/shadow_offset_y = 3
theme_override_constants/shadow_offset_x = 3
theme_override_constants/shadow_outline_size = 10
theme_override_fonts/font = ExtResource("3_t4s8j")
theme_override_font_sizes/font_size = 25
theme_override_font_sizes/bold_italics_font_size = 25
theme_override_font_sizes/italics_font_size = 25
theme_override_font_sizes/mono_font_size = 25
theme_override_font_sizes/normal_font_size = 25
theme_override_font_sizes/bold_font_size = 25
bbcode_enabled = true
text = "全服大喇叭"
vertical_alignment = 1
clip_text = true
threaded = true
[node name="WatchBroadcast" type="Button" parent="UI/GUI/GameInfoHBox3"]
layout_mode = 2
@@ -547,6 +564,7 @@ expand_mode = 2
[node name="onlineplayer" type="Label" parent="UI/GUI/GameInfoHBox3"]
layout_mode = 2
size_flags_horizontal = 3
theme_override_colors/font_color = Color(0.423529, 1, 0.533333, 1)
theme_override_colors/font_shadow_color = Color(0, 0, 0, 1)
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
@@ -644,6 +662,12 @@ layout_mode = 2
theme_override_font_sizes/font_size = 40
text = "使用道具"
[node name="SendMoneyButton" type="Button" parent="UI/GUI/VisitVBox"]
modulate = Color(1, 1, 0, 1)
layout_mode = 2
theme_override_font_sizes/font_size = 40
text = "送金币"
[node name="ReturnMyFarmButton" type="Button" parent="UI/GUI/VisitVBox"]
modulate = Color(1, 1, 0.721569, 1)
layout_mode = 2
@@ -694,7 +718,7 @@ text = "新手礼包"
modulate = Color(0.407843, 0.796078, 0.996078, 1)
layout_mode = 2
theme_override_font_sizes/font_size = 40
text = "一键截图"
text = "截图模式"
[node name="LuckyDrawButton" type="Button" parent="UI/GUI/OtherVBox"]
modulate = Color(0.729412, 0.764706, 1, 1)
@@ -777,11 +801,15 @@ offset_right = 1473.0
offset_bottom = 748.0
[node name="ItemStorePanel" parent="UI/BigPanel" instance=ExtResource("21_uhubb")]
visible = false
offset_left = 80.0
offset_top = 77.0
offset_right = 1620.0
offset_bottom = 797.0
[node name="ItemBagPanel" parent="UI/BigPanel" instance=ExtResource("20_n03md")]
visible = false
[node name="CropWarehousePanel" parent="UI/BigPanel" instance=ExtResource("18_5b81d")]
[node name="PlayerBagPanel" parent="UI/BigPanel" instance=ExtResource("19_8kysg")]
@@ -790,9 +818,6 @@ visible = false
[node name="CropStorePanel" parent="UI/BigPanel" instance=ExtResource("17_ql8k3")]
visible = false
[node name="ItemBagPanel" parent="UI/BigPanel" instance=ExtResource("20_n03md")]
visible = false
[node name="PlayerStorePanel" type="Panel" parent="UI/BigPanel"]
visible = false
offset_left = 69.0
@@ -957,6 +982,7 @@ visible = false
visible = false
[node name="LoginPanel" parent="UI/BigPanel" instance=ExtResource("11_6jgly")]
visible = false
[node name="GameSettingPanel" parent="UI/BigPanel" instance=ExtResource("30_game_setting")]
visible = false
@@ -964,6 +990,12 @@ visible = false
[node name="PetBattlePanel" parent="UI/BigPanel" instance=ExtResource("29_mw3xw")]
visible = false
[node name="PlayGamePanel" parent="UI/BigPanel" instance=ExtResource("30_rawle")]
visible = false
[node name="SpecialFarmPanel" parent="UI/BigPanel" instance=ExtResource("31_ww70k")]
visible = false
[node name="SmallPanel" type="CanvasLayer" parent="UI"]
[node name="LoadProgressPanel" parent="UI/SmallPanel" instance=ExtResource("27_vygm6")]
@@ -2111,7 +2143,7 @@ position_smoothing_enabled = true
script = ExtResource("10_o8l48")
max_zoom = 1.8
bounds_enabled = true
bounds_min = Vector2(-500, -400)
bounds_min = Vector2(-500, -600)
bounds_max = Vector2(500, 500)
[node name="GameManager" type="Node" parent="."]
@@ -3293,7 +3325,7 @@ text = "在线时长礼包"
horizontal_alignment = 1
vertical_alignment = 1
[node name="Decoration2" type="Button" parent="Decoration4"]
[node name="TodayDivination" type="Button" parent="Decoration4"]
self_modulate = Color(1, 1, 1, 0)
custom_minimum_size = Vector2(100, 100)
offset_left = 244.0
@@ -3302,17 +3334,17 @@ offset_right = 508.0
offset_bottom = 156.0
scale = Vector2(0.4, 0.4)
[node name="GrassGroundImage" type="Sprite2D" parent="Decoration4/Decoration2"]
[node name="GrassGroundImage" type="Sprite2D" parent="Decoration4/TodayDivination"]
position = Vector2(132, 134)
scale = Vector2(1.4, 1.4)
texture = ExtResource("48_2i8fe")
[node name="Image" type="Sprite2D" parent="Decoration4/Decoration2"]
[node name="Image" type="Sprite2D" parent="Decoration4/TodayDivination"]
position = Vector2(132, 48)
scale = Vector2(1.2, 1.2)
texture = ExtResource("50_sqnmr")
texture = ExtResource("68_yceks")
[node name="Name" type="RichTextLabel" parent="Decoration4/Decoration2"]
[node name="Name" type="RichTextLabel" parent="Decoration4/TodayDivination"]
z_index = 5
layout_mode = 0
offset_left = -65.0
@@ -3325,10 +3357,11 @@ theme_override_font_sizes/mono_font_size = 40
theme_override_font_sizes/normal_font_size = 40
theme_override_font_sizes/bold_font_size = 40
bbcode_enabled = true
text = "今日占卜"
horizontal_alignment = 1
vertical_alignment = 1
[node name="Decoration3" type="Button" parent="Decoration4"]
[node name="PetLadderMatch" type="Button" parent="Decoration4"]
self_modulate = Color(1, 1, 1, 0)
custom_minimum_size = Vector2(100, 100)
offset_left = 366.0
@@ -3337,17 +3370,17 @@ offset_right = 630.0
offset_bottom = 156.0
scale = Vector2(0.4, 0.4)
[node name="GrassGroundImage" type="Sprite2D" parent="Decoration4/Decoration3"]
[node name="GrassGroundImage" type="Sprite2D" parent="Decoration4/PetLadderMatch"]
position = Vector2(132, 134)
scale = Vector2(1.4, 1.4)
texture = ExtResource("48_2i8fe")
[node name="Image" type="Sprite2D" parent="Decoration4/Decoration3"]
[node name="Image" type="Sprite2D" parent="Decoration4/PetLadderMatch"]
position = Vector2(132, 48)
scale = Vector2(1.2, 1.2)
texture = ExtResource("51_2i8fe")
texture = ExtResource("69_yceks")
[node name="Name" type="RichTextLabel" parent="Decoration4/Decoration3"]
[node name="Name" type="RichTextLabel" parent="Decoration4/PetLadderMatch"]
z_index = 5
layout_mode = 0
offset_left = -65.0
@@ -3360,10 +3393,11 @@ theme_override_font_sizes/mono_font_size = 40
theme_override_font_sizes/normal_font_size = 40
theme_override_font_sizes/bold_font_size = 40
bbcode_enabled = true
text = "宠物星辰塔"
horizontal_alignment = 1
vertical_alignment = 1
[node name="Decoration4" type="Button" parent="Decoration4"]
[node name="PetNest" type="Button" parent="Decoration4"]
self_modulate = Color(1, 1, 1, 0)
custom_minimum_size = Vector2(100, 100)
offset_left = 488.0
@@ -3372,17 +3406,17 @@ offset_right = 752.0
offset_bottom = 156.0
scale = Vector2(0.4, 0.4)
[node name="GrassGroundImage" type="Sprite2D" parent="Decoration4/Decoration4"]
[node name="GrassGroundImage" type="Sprite2D" parent="Decoration4/PetNest"]
position = Vector2(132, 134)
scale = Vector2(1.4, 1.4)
texture = ExtResource("48_2i8fe")
[node name="Image" type="Sprite2D" parent="Decoration4/Decoration4"]
[node name="Image" type="Sprite2D" parent="Decoration4/PetNest"]
position = Vector2(132, 48)
scale = Vector2(1.2, 1.2)
texture = ExtResource("50_sqnmr")
texture = ExtResource("70_yceks")
[node name="Name" type="RichTextLabel" parent="Decoration4/Decoration4"]
[node name="Name" type="RichTextLabel" parent="Decoration4/PetNest"]
z_index = 5
layout_mode = 0
offset_left = -65.0
@@ -3395,10 +3429,11 @@ theme_override_font_sizes/mono_font_size = 40
theme_override_font_sizes/normal_font_size = 40
theme_override_font_sizes/bold_font_size = 40
bbcode_enabled = true
text = "宠物小窝"
horizontal_alignment = 1
vertical_alignment = 1
[node name="Decoration5" type="Button" parent="Decoration4"]
[node name="PlaySmallGame" type="Button" parent="Decoration4"]
self_modulate = Color(1, 1, 1, 0)
custom_minimum_size = Vector2(100, 100)
offset_left = 610.0
@@ -3407,17 +3442,17 @@ offset_right = 874.0
offset_bottom = 156.0
scale = Vector2(0.4, 0.4)
[node name="GrassGroundImage" type="Sprite2D" parent="Decoration4/Decoration5"]
[node name="GrassGroundImage" type="Sprite2D" parent="Decoration4/PlaySmallGame"]
position = Vector2(132, 134)
scale = Vector2(1.4, 1.4)
texture = ExtResource("48_2i8fe")
[node name="Image" type="Sprite2D" parent="Decoration4/Decoration5"]
[node name="Image" type="Sprite2D" parent="Decoration4/PlaySmallGame"]
position = Vector2(132, 48)
scale = Vector2(1.2, 1.2)
texture = ExtResource("49_xjiif")
texture = ExtResource("71_w7q6d")
[node name="Name" type="RichTextLabel" parent="Decoration4/Decoration5"]
[node name="Name" type="RichTextLabel" parent="Decoration4/PlaySmallGame"]
z_index = 5
layout_mode = 0
offset_left = -65.0
@@ -3430,10 +3465,11 @@ theme_override_font_sizes/mono_font_size = 40
theme_override_font_sizes/normal_font_size = 40
theme_override_font_sizes/bold_font_size = 40
bbcode_enabled = true
text = "玩玩小游戏"
horizontal_alignment = 1
vertical_alignment = 1
[node name="Decoration6" type="Button" parent="Decoration4"]
[node name="MysteryFarmland" type="Button" parent="Decoration4"]
self_modulate = Color(1, 1, 1, 0)
custom_minimum_size = Vector2(100, 100)
offset_left = 732.0
@@ -3442,17 +3478,17 @@ offset_right = 996.0
offset_bottom = 156.0
scale = Vector2(0.4, 0.4)
[node name="GrassGroundImage" type="Sprite2D" parent="Decoration4/Decoration6"]
[node name="GrassGroundImage" type="Sprite2D" parent="Decoration4/MysteryFarmland"]
position = Vector2(132, 134)
scale = Vector2(1.4, 1.4)
texture = ExtResource("48_2i8fe")
[node name="Image" type="Sprite2D" parent="Decoration4/Decoration6"]
[node name="Image" type="Sprite2D" parent="Decoration4/MysteryFarmland"]
position = Vector2(132, 48)
scale = Vector2(1.2, 1.2)
texture = ExtResource("49_xjiif")
texture = ExtResource("72_7i23t")
[node name="Name" type="RichTextLabel" parent="Decoration4/Decoration6"]
[node name="Name" type="RichTextLabel" parent="Decoration4/MysteryFarmland"]
z_index = 5
layout_mode = 0
offset_left = -65.0
@@ -3465,6 +3501,7 @@ theme_override_font_sizes/mono_font_size = 40
theme_override_font_sizes/normal_font_size = 40
theme_override_font_sizes/bold_font_size = 40
bbcode_enabled = true
text = "神秘农场"
horizontal_alignment = 1
vertical_alignment = 1
@@ -3689,6 +3726,7 @@ environment = SubResource("Environment_uyv6e")
[connection signal="pressed" from="UI/GUI/FarmVBox/AddNewGroundButton" to="." method="_on_add_new_ground_button_pressed"]
[connection signal="pressed" from="UI/GUI/VisitVBox/LikeButton" to="." method="_on_like_button_pressed"]
[connection signal="pressed" from="UI/GUI/VisitVBox/BattleButton" to="." method="_on_battle_button_pressed"]
[connection signal="pressed" from="UI/GUI/VisitVBox/SendMoneyButton" to="." method="_on_send_money_button_pressed"]
[connection signal="pressed" from="UI/GUI/VisitVBox/ReturnMyFarmButton" to="." method="_on_return_my_farm_button_pressed"]
[connection signal="pressed" from="UI/GUI/OtherVBox/TodayDivinationButton" to="." method="_on_today_divination_button_pressed"]
[connection signal="pressed" from="UI/GUI/OtherVBox/MyStoreButton" to="." method="_on_my_store_button_pressed"]
@@ -3718,5 +3756,10 @@ environment = SubResource("Environment_uyv6e")
[connection signal="pressed" from="Decoration/WisdomTree" to="." method="_on_wisdom_tree_pressed"]
[connection signal="pressed" from="Decoration4/DailyCheckinGift" to="." method="_on_daily_checkin_gift_pressed"]
[connection signal="pressed" from="Decoration4/OnlineTimeGift" to="." method="_on_online_time_gift_pressed"]
[connection signal="pressed" from="Decoration4/TodayDivination" to="." method="_on_today_divination_pressed"]
[connection signal="pressed" from="Decoration4/PetLadderMatch" to="." method="_on_pet_ladder_match_pressed"]
[connection signal="pressed" from="Decoration4/PetNest" to="." method="_on_pet_nest_pressed"]
[connection signal="pressed" from="Decoration4/PlaySmallGame" to="." method="_on_play_small_game_pressed"]
[connection signal="pressed" from="Decoration4/MysteryFarmland" to="." method="_on_mystery_farmland_pressed"]
[connection signal="pressed" from="Decoration4/PetBag" to="." method="_on_pet_bag_pressed"]
[connection signal="pressed" from="Decoration4/ItemBag" to="." method="_on_item_bag_pressed"]

3764
MainGame.tscn89825202664.tmp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -219,6 +219,16 @@ func _on_data_received(data):
var player_data = data.get("player_data", {})
var remaining_likes = data.get("remaining_likes", 10)
# 处理被禁止登录的情况
if status == "banned":
var ban_end_time = data.get("ban_end_time", "")
var ban_message = message
if ban_end_time != "":
ban_message += "\n禁止登录至: " + ban_end_time
Toast.show(ban_message, Color.RED)
login_panel._on_login_response_received(false, ban_message, {})
return
# 在登录成功时显示剩余点赞次数并更新主游戏数据
if status == "success":
var likes_message = "今日剩余点赞次数:" + str(remaining_likes)
@@ -578,6 +588,8 @@ func _on_data_received(data):
main_game._handle_pet_config_response(data)
# 同时传递给宠物商店面板
pet_store_panel._on_pet_config_received(data)
elif message_type == "game_tips_config_response":
main_game._handle_game_tips_config_response(data)
elif message_type == "visit_player_response":
main_game._handle_visit_player_response(data)
elif message_type == "return_my_farm_response":
@@ -666,14 +678,52 @@ func _on_data_received(data):
var divination_panel = get_node_or_null("/root/main/UI/SmallPanel/TodayDivinationPanel")
if divination_panel and divination_panel.has_method("handle_divination_response"):
divination_panel.handle_divination_response(success, message, divination_data)
# 送金币响应
elif message_type == "give_money_response":
main_game._handle_give_money_response(data)
# 收到金币通知
elif message_type == "money_received_notification":
main_game._handle_money_received_notification(data)
# 背包数据同步响应
elif message_type == "sync_bag_data_response":
var success = data.get("success", false)
var message = data.get("message", "")
var bag_data = data.get("bag_data", {})
if success:
# 更新主游戏中的背包数据
main_game.item_bag = bag_data.get("道具背包", [])
main_game.pet_bag = bag_data.get("宠物背包", [])
main_game.player_bag = bag_data.get("种子仓库", [])
main_game.crop_warehouse = bag_data.get("作物仓库", [])
# 更新所有背包面板的UI
main_game.item_bag_panel.update_item_bag_ui()
main_game.pet_bag_panel.update_pet_bag_ui()
main_game.player_bag_panel.update_player_bag_ui()
main_game.crop_warehouse_panel.update_crop_warehouse_ui()
print("背包数据同步成功")
else:
print("背包数据同步失败: ", message)
# 踢出通知
elif message_type == "kick_notification":
var reason = data.get("reason", "您已被管理员踢出服务器")
var duration = data.get("duration", 0)
# 显示踢出原因
Toast.show(reason, Color.RED)
# 断开连接并返回登录界面
client.disconnect_from_server()
main_game.return_to_login()
# ============================= 客户端与服务端通信核心 =====================================
#=====================================网络操作处理=========================================
func _on_connection_button_pressed():
if client.is_client_connected():
@@ -743,6 +793,17 @@ func sendRegisterInfo(username, password, farmname, player_name="", verification
"client_version": main_game.client_version
})
#发送背包数据同步请求
func send_sync_bag_data_request():
if not client.is_client_connected():
print("网络未连接,无法同步背包数据")
return
client.send_data({
"type": "sync_bag_data"
})
print("已发送背包数据同步请求")
#发送收获作物信息
func sendHarvestCrop(lot_index, target_username = ""):
if not client.is_client_connected():
@@ -1004,6 +1065,16 @@ func sendGetPetConfig():
})
return true
#发送获取游戏小提示配置数据请求
func sendGetGameTipsConfig():
if not client.is_client_connected():
return false
client.send_data({
"type": "request_game_tips_config"
})
return true
#发送访问玩家请求
func sendVisitPlayer(target_username):
if not client.is_client_connected():
@@ -1262,6 +1333,19 @@ func sendDivinationRequest():
})
return true
#发送送金币请求
func sendGiveMoney(target_username: String, amount: int):
if not client.is_client_connected():
return false
client.send_data({
"type": "give_money",
"target_username": target_username,
"amount": amount,
"timestamp": Time.get_unix_time_from_system()
})
return true
#检查是否连接到服务器
func is_connected_to_server():
return client.is_client_connected()

View File

@@ -85,5 +85,45 @@ offset_bottom = 79.25
theme_override_font_sizes/font_size = 40
text = "刷新"
[node name="All_Filter" type="Button" parent="."]
custom_minimum_size = Vector2(60, 60)
offset_left = 217.5
offset_top = 12.5
offset_right = 305.5
offset_bottom = 75.5
theme_override_font_sizes/font_size = 40
text = "全部"
[node name="Pet_Filter" type="Button" parent="."]
custom_minimum_size = Vector2(60, 60)
offset_left = 310.0
offset_top = 13.75
offset_right = 398.0
offset_bottom = 76.75
theme_override_font_sizes/font_size = 40
text = "宠物"
[node name="Crop_Filter" type="Button" parent="."]
custom_minimum_size = Vector2(60, 60)
offset_left = 397.5
offset_top = 13.75
offset_right = 485.5
offset_bottom = 76.75
theme_override_font_sizes/font_size = 40
text = "作物"
[node name="Farm_Filter" type="Button" parent="."]
custom_minimum_size = Vector2(60, 60)
offset_left = 485.0
offset_top = 13.75
offset_right = 573.0
offset_bottom = 76.75
theme_override_font_sizes/font_size = 40
text = "农场"
[connection signal="pressed" from="QuitButton" to="." method="_on_quit_button_pressed"]
[connection signal="pressed" from="RefreshButton" to="." method="_on_refresh_button_pressed"]
[connection signal="pressed" from="All_Filter" to="." method="_on_all_filter_pressed"]
[connection signal="pressed" from="Pet_Filter" to="." method="_on_pet_filter_pressed"]
[connection signal="pressed" from="Crop_Filter" to="." method="_on_crop_filter_pressed"]
[connection signal="pressed" from="Farm_Filter" to="." method="_on_farm_filter_pressed"]

View File

@@ -15,7 +15,6 @@ corner_detail = 20
shadow_size = 20
[node name="ItemStorePanel" type="Panel"]
visible = false
offset_left = 58.0
offset_top = 79.0
offset_right = 1598.0
@@ -87,4 +86,48 @@ offset_bottom = 75.5
theme_override_font_sizes/font_size = 40
text = "刷新"
[node name="All_Filter" type="Button" parent="."]
custom_minimum_size = Vector2(60, 60)
layout_mode = 2
offset_left = 217.5
offset_top = 12.5
offset_right = 305.5
offset_bottom = 75.5
theme_override_font_sizes/font_size = 40
text = "全部"
[node name="Pet_Filter" type="Button" parent="."]
custom_minimum_size = Vector2(60, 60)
layout_mode = 2
offset_left = 310.0
offset_top = 13.75
offset_right = 398.0
offset_bottom = 76.75
theme_override_font_sizes/font_size = 40
text = "宠物"
[node name="Crop_Filter" type="Button" parent="."]
custom_minimum_size = Vector2(60, 60)
layout_mode = 2
offset_left = 397.5
offset_top = 13.75
offset_right = 485.5
offset_bottom = 76.75
theme_override_font_sizes/font_size = 40
text = "作物"
[node name="Farm_Filter" type="Button" parent="."]
custom_minimum_size = Vector2(60, 60)
layout_mode = 2
offset_left = 485.0
offset_top = 13.75
offset_right = 573.0
offset_bottom = 76.75
theme_override_font_sizes/font_size = 40
text = "农场"
[connection signal="pressed" from="RefreshButton" to="." method="_on_refresh_button_pressed"]
[connection signal="pressed" from="All_Filter" to="." method="_on_all_filter_pressed"]
[connection signal="pressed" from="Pet_Filter" to="." method="_on_pet_filter_pressed"]
[connection signal="pressed" from="Crop_Filter" to="." method="_on_crop_filter_pressed"]
[connection signal="pressed" from="Farm_Filter" to="." method="_on_farm_filter_pressed"]

View File

@@ -0,0 +1,179 @@
[gd_scene load_steps=4 format=3 uid="uid://jjlgdnoo8e52"]
[ext_resource type="Script" uid="uid://dvaah0n1ia1a3" path="res://Script/BigPanel/PlayGamePanel.gd" id="1_i6cj7"]
[ext_resource type="Texture2D" uid="uid://ywdg7xgq7hm8" path="res://assets/装饰物图片/道具背包.webp" id="2_wlugc"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_7i23t"]
border_width_left = 15
border_width_top = 15
border_width_right = 15
border_width_bottom = 15
corner_detail = 20
shadow_size = 20
[node name="PlayGamePanel" type="Panel"]
offset_right = 1399.0
offset_bottom = 720.0
theme_override_styles/panel = SubResource("StyleBoxFlat_7i23t")
script = ExtResource("1_i6cj7")
[node name="Title" type="Label" parent="."]
layout_mode = 0
offset_top = 17.0
offset_right = 1401.0
offset_bottom = 86.0
theme_override_colors/font_color = Color(0.560784, 1, 0, 1)
theme_override_colors/font_shadow_color = Color(0, 0, 0, 1)
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/shadow_offset_x = 3
theme_override_constants/shadow_offset_y = 3
theme_override_constants/outline_size = 15
theme_override_constants/shadow_outline_size = 20
theme_override_font_sizes/font_size = 50
text = "玩玩小游戏"
horizontal_alignment = 1
vertical_alignment = 1
[node name="ScrollContainer" type="ScrollContainer" parent="."]
layout_mode = 0
offset_left = 15.0
offset_top = 88.0
offset_right = 1384.0
offset_bottom = 707.0
horizontal_scroll_mode = 0
[node name="Grid" type="GridContainer" parent="ScrollContainer"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
columns = 5
[node name="VBox" type="VBoxContainer" parent="ScrollContainer/Grid"]
layout_mode = 2
alignment = 1
[node name="GameTitle" type="Label" parent="ScrollContainer/Grid/VBox"]
layout_mode = 2
theme_override_colors/font_shadow_color = Color(0, 0, 0, 1)
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/shadow_offset_x = 3
theme_override_constants/shadow_offset_y = 3
theme_override_constants/outline_size = 15
theme_override_constants/shadow_outline_size = 15
theme_override_font_sizes/font_size = 35
text = "贪吃蛇"
horizontal_alignment = 1
vertical_alignment = 1
[node name="TextureRect" type="TextureRect" parent="ScrollContainer/Grid/VBox"]
layout_mode = 2
texture = ExtResource("2_wlugc")
[node name="Button" type="Button" parent="ScrollContainer/Grid/VBox"]
layout_mode = 2
theme_override_font_sizes/font_size = 30
text = "点击游玩"
[node name="VBox2" type="VBoxContainer" parent="ScrollContainer/Grid"]
layout_mode = 2
alignment = 1
[node name="GameTitle" type="Label" parent="ScrollContainer/Grid/VBox2"]
layout_mode = 2
theme_override_colors/font_shadow_color = Color(0, 0, 0, 1)
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/shadow_offset_x = 3
theme_override_constants/shadow_offset_y = 3
theme_override_constants/outline_size = 15
theme_override_constants/shadow_outline_size = 15
theme_override_font_sizes/font_size = 35
text = "贪吃蛇"
horizontal_alignment = 1
vertical_alignment = 1
[node name="TextureRect" type="TextureRect" parent="ScrollContainer/Grid/VBox2"]
layout_mode = 2
texture = ExtResource("2_wlugc")
[node name="Button" type="Button" parent="ScrollContainer/Grid/VBox2"]
layout_mode = 2
theme_override_font_sizes/font_size = 30
text = "点击游玩"
[node name="VBox3" type="VBoxContainer" parent="ScrollContainer/Grid"]
layout_mode = 2
alignment = 1
[node name="GameTitle" type="Label" parent="ScrollContainer/Grid/VBox3"]
layout_mode = 2
theme_override_colors/font_shadow_color = Color(0, 0, 0, 1)
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/shadow_offset_x = 3
theme_override_constants/shadow_offset_y = 3
theme_override_constants/outline_size = 15
theme_override_constants/shadow_outline_size = 15
theme_override_font_sizes/font_size = 35
text = "贪吃蛇"
horizontal_alignment = 1
vertical_alignment = 1
[node name="TextureRect" type="TextureRect" parent="ScrollContainer/Grid/VBox3"]
layout_mode = 2
texture = ExtResource("2_wlugc")
[node name="Button" type="Button" parent="ScrollContainer/Grid/VBox3"]
layout_mode = 2
theme_override_font_sizes/font_size = 30
text = "点击游玩"
[node name="VBox4" type="VBoxContainer" parent="ScrollContainer/Grid"]
layout_mode = 2
alignment = 1
[node name="GameTitle" type="Label" parent="ScrollContainer/Grid/VBox4"]
layout_mode = 2
theme_override_colors/font_shadow_color = Color(0, 0, 0, 1)
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/shadow_offset_x = 3
theme_override_constants/shadow_offset_y = 3
theme_override_constants/outline_size = 15
theme_override_constants/shadow_outline_size = 15
theme_override_font_sizes/font_size = 35
text = "贪吃蛇"
horizontal_alignment = 1
vertical_alignment = 1
[node name="TextureRect" type="TextureRect" parent="ScrollContainer/Grid/VBox4"]
layout_mode = 2
texture = ExtResource("2_wlugc")
[node name="Button" type="Button" parent="ScrollContainer/Grid/VBox4"]
layout_mode = 2
theme_override_font_sizes/font_size = 30
text = "点击游玩"
[node name="VBox5" type="VBoxContainer" parent="ScrollContainer/Grid"]
layout_mode = 2
alignment = 1
[node name="GameTitle" type="Label" parent="ScrollContainer/Grid/VBox5"]
layout_mode = 2
theme_override_colors/font_shadow_color = Color(0, 0, 0, 1)
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/shadow_offset_x = 3
theme_override_constants/shadow_offset_y = 3
theme_override_constants/outline_size = 15
theme_override_constants/shadow_outline_size = 15
theme_override_font_sizes/font_size = 35
text = "贪吃蛇"
horizontal_alignment = 1
vertical_alignment = 1
[node name="TextureRect" type="TextureRect" parent="ScrollContainer/Grid/VBox5"]
layout_mode = 2
texture = ExtResource("2_wlugc")
[node name="Button" type="Button" parent="ScrollContainer/Grid/VBox5"]
layout_mode = 2
theme_override_font_sizes/font_size = 30
text = "点击游玩"

View File

@@ -0,0 +1,223 @@
[gd_scene load_steps=4 format=3 uid="uid://byxhjyyaahs6q"]
[ext_resource type="Texture2D" uid="uid://ywdg7xgq7hm8" path="res://assets/装饰物图片/道具背包.webp" id="1_mv0g4"]
[ext_resource type="Script" uid="uid://btm2je8pg7rgk" path="res://Script/BigPanel/SpecialFarmPanel.gd" id="1_n2mxy"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_7i23t"]
border_width_left = 15
border_width_top = 15
border_width_right = 15
border_width_bottom = 15
corner_detail = 20
shadow_size = 20
[node name="SpecialFarmPanel" type="Panel"]
offset_right = 1399.0
offset_bottom = 720.0
theme_override_styles/panel = SubResource("StyleBoxFlat_7i23t")
script = ExtResource("1_n2mxy")
[node name="QuitButton" type="Button" parent="."]
custom_minimum_size = Vector2(80, 80)
layout_mode = 0
offset_left = 1303.0
offset_top = 17.0
offset_right = 1383.0
offset_bottom = 97.0
theme_override_font_sizes/font_size = 50
text = "X"
[node name="Title" type="Label" parent="."]
layout_mode = 0
offset_top = 17.0
offset_right = 1401.0
offset_bottom = 86.0
theme_override_colors/font_color = Color(0.560784, 1, 0, 1)
theme_override_colors/font_shadow_color = Color(0, 0, 0, 1)
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/shadow_offset_x = 3
theme_override_constants/shadow_offset_y = 3
theme_override_constants/outline_size = 15
theme_override_constants/shadow_outline_size = 20
theme_override_font_sizes/font_size = 50
text = "神秘农场"
horizontal_alignment = 1
vertical_alignment = 1
[node name="ScrollContainer" type="ScrollContainer" parent="."]
layout_mode = 0
offset_left = 15.0
offset_top = 88.0
offset_right = 1384.0
offset_bottom = 707.0
horizontal_scroll_mode = 0
[node name="Grid" type="GridContainer" parent="ScrollContainer"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
columns = 5
[node name="FlowerFarm" type="VBoxContainer" parent="ScrollContainer/Grid"]
layout_mode = 2
alignment = 1
[node name="GameTitle" type="Label" parent="ScrollContainer/Grid/FlowerFarm"]
layout_mode = 2
theme_override_colors/font_shadow_color = Color(0, 0, 0, 1)
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/shadow_offset_x = 3
theme_override_constants/shadow_offset_y = 3
theme_override_constants/outline_size = 15
theme_override_constants/shadow_outline_size = 15
theme_override_font_sizes/font_size = 35
text = "花卉农场"
horizontal_alignment = 1
vertical_alignment = 1
[node name="TextureRect" type="TextureRect" parent="ScrollContainer/Grid/FlowerFarm"]
layout_mode = 2
texture = ExtResource("1_mv0g4")
[node name="FlowerFarmButton" type="Button" parent="ScrollContainer/Grid/FlowerFarm"]
layout_mode = 2
theme_override_font_sizes/font_size = 30
text = "点击访问"
[node name="FruitFarm" type="VBoxContainer" parent="ScrollContainer/Grid"]
layout_mode = 2
alignment = 1
[node name="GameTitle" type="Label" parent="ScrollContainer/Grid/FruitFarm"]
layout_mode = 2
theme_override_colors/font_shadow_color = Color(0, 0, 0, 1)
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/shadow_offset_x = 3
theme_override_constants/shadow_offset_y = 3
theme_override_constants/outline_size = 15
theme_override_constants/shadow_outline_size = 15
theme_override_font_sizes/font_size = 35
text = "瓜果飘香"
horizontal_alignment = 1
vertical_alignment = 1
[node name="TextureRect" type="TextureRect" parent="ScrollContainer/Grid/FruitFarm"]
layout_mode = 2
texture = ExtResource("1_mv0g4")
[node name="FruitFarmButton" type="Button" parent="ScrollContainer/Grid/FruitFarm"]
layout_mode = 2
theme_override_font_sizes/font_size = 30
text = "点击访问"
[node name="HybridFarm" type="VBoxContainer" parent="ScrollContainer/Grid"]
layout_mode = 2
alignment = 1
[node name="GameTitle" type="Label" parent="ScrollContainer/Grid/HybridFarm"]
layout_mode = 2
theme_override_colors/font_shadow_color = Color(0, 0, 0, 1)
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/shadow_offset_x = 3
theme_override_constants/shadow_offset_y = 3
theme_override_constants/outline_size = 15
theme_override_constants/shadow_outline_size = 15
theme_override_font_sizes/font_size = 35
text = "杂交基地"
horizontal_alignment = 1
vertical_alignment = 1
[node name="TextureRect" type="TextureRect" parent="ScrollContainer/Grid/HybridFarm"]
layout_mode = 2
texture = ExtResource("1_mv0g4")
[node name="HybridFarmButton" type="Button" parent="ScrollContainer/Grid/HybridFarm"]
layout_mode = 2
theme_override_font_sizes/font_size = 30
text = "点击访问"
[node name="LuckyFarm" type="VBoxContainer" parent="ScrollContainer/Grid"]
layout_mode = 2
alignment = 1
[node name="GameTitle" type="Label" parent="ScrollContainer/Grid/LuckyFarm"]
layout_mode = 2
theme_override_colors/font_shadow_color = Color(0, 0, 0, 1)
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/shadow_offset_x = 3
theme_override_constants/shadow_offset_y = 3
theme_override_constants/outline_size = 15
theme_override_constants/shadow_outline_size = 15
theme_override_font_sizes/font_size = 35
text = "幸运农场"
horizontal_alignment = 1
vertical_alignment = 1
[node name="TextureRect" type="TextureRect" parent="ScrollContainer/Grid/LuckyFarm"]
layout_mode = 2
texture = ExtResource("1_mv0g4")
[node name="LuckyFarmButton" type="Button" parent="ScrollContainer/Grid/LuckyFarm"]
layout_mode = 2
theme_override_font_sizes/font_size = 30
text = "点击访问"
[node name="RiceFarm" type="VBoxContainer" parent="ScrollContainer/Grid"]
layout_mode = 2
alignment = 1
[node name="GameTitle" type="Label" parent="ScrollContainer/Grid/RiceFarm"]
layout_mode = 2
theme_override_colors/font_shadow_color = Color(0, 0, 0, 1)
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/shadow_offset_x = 3
theme_override_constants/shadow_offset_y = 3
theme_override_constants/outline_size = 15
theme_override_constants/shadow_outline_size = 15
theme_override_font_sizes/font_size = 35
text = "稻香"
horizontal_alignment = 1
vertical_alignment = 1
[node name="TextureRect" type="TextureRect" parent="ScrollContainer/Grid/RiceFarm"]
layout_mode = 2
texture = ExtResource("1_mv0g4")
[node name="RiceFarmButton" type="Button" parent="ScrollContainer/Grid/RiceFarm"]
layout_mode = 2
theme_override_font_sizes/font_size = 30
text = "点击访问"
[node name="WheatFarm" type="VBoxContainer" parent="ScrollContainer/Grid"]
layout_mode = 2
alignment = 1
[node name="GameTitle" type="Label" parent="ScrollContainer/Grid/WheatFarm"]
layout_mode = 2
theme_override_colors/font_shadow_color = Color(0, 0, 0, 1)
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/shadow_offset_x = 3
theme_override_constants/shadow_offset_y = 3
theme_override_constants/outline_size = 15
theme_override_constants/shadow_outline_size = 15
theme_override_font_sizes/font_size = 35
text = "小麦谷"
horizontal_alignment = 1
vertical_alignment = 1
[node name="TextureRect" type="TextureRect" parent="ScrollContainer/Grid/WheatFarm"]
layout_mode = 2
texture = ExtResource("1_mv0g4")
[node name="WheatFarmButton" type="Button" parent="ScrollContainer/Grid/WheatFarm"]
layout_mode = 2
theme_override_font_sizes/font_size = 30
text = "点击访问"
[connection signal="pressed" from="QuitButton" to="." method="_on_quit_button_pressed"]
[connection signal="pressed" from="ScrollContainer/Grid/FlowerFarm/FlowerFarmButton" to="." method="_on_flower_farm_button_pressed"]
[connection signal="pressed" from="ScrollContainer/Grid/FruitFarm/FruitFarmButton" to="." method="_on_fruit_farm_button_pressed"]
[connection signal="pressed" from="ScrollContainer/Grid/HybridFarm/HybridFarmButton" to="." method="_on_hybrid_farm_button_pressed"]
[connection signal="pressed" from="ScrollContainer/Grid/LuckyFarm/LuckyFarmButton" to="." method="_on_lucky_farm_button_pressed"]
[connection signal="pressed" from="ScrollContainer/Grid/RiceFarm/RiceFarmButton" to="." method="_on_rice_farm_button_pressed"]
[connection signal="pressed" from="ScrollContainer/Grid/WheatFarm/WheatFarmButton" to="." method="_on_wheat_farm_button_pressed"]

307
Scene/SmallGame/2048Game.gd Normal file
View File

@@ -0,0 +1,307 @@
extends Panel
# 游戏常量
const GRID_SIZE = 4
const CELL_SIZE = 90
const CELL_MARGIN = 10
# 数字颜色配置
const NUMBER_COLORS = {
0: Color.TRANSPARENT,
2: Color(0.93, 0.89, 0.85),
4: Color(0.93, 0.88, 0.78),
8: Color(0.95, 0.69, 0.47),
16: Color(0.96, 0.58, 0.39),
32: Color(0.96, 0.49, 0.37),
64: Color(0.96, 0.37, 0.23),
128: Color(0.93, 0.81, 0.45),
256: Color(0.93, 0.80, 0.38),
512: Color(0.93, 0.78, 0.31),
1024: Color(0.93, 0.77, 0.25),
2048: Color(0.93, 0.76, 0.18)
}
const TEXT_COLORS = {
2: Color.BLACK,
4: Color.BLACK,
8: Color.WHITE,
16: Color.WHITE,
32: Color.WHITE,
64: Color.WHITE,
128: Color.WHITE,
256: Color.WHITE,
512: Color.WHITE,
1024: Color.WHITE,
2048: Color.WHITE
}
# 游戏变量
var grid = []
var score = 0
var best_score = 0
var game_over = false
var won = false
var can_continue = true
# 节点引用
@onready var game_board = $GameBoard
@onready var score_label = $ScoreLabel
@onready var best_label = $BestLabel
@onready var game_over_label = $GameOverLabel
@onready var win_label = $WinLabel
func _ready():
# 设置游戏板样式
game_board.modulate = Color(0.7, 0.6, 0.5)
# 初始化游戏
init_game()
func init_game():
# 重置游戏状态
game_over = false
won = false
can_continue = true
score = 0
# 初始化网格
grid.clear()
for y in range(GRID_SIZE):
var row = []
for x in range(GRID_SIZE):
row.append(0)
grid.append(row)
# 添加两个初始数字
add_random_number()
add_random_number()
# 更新UI
update_ui()
hide_labels()
queue_redraw()
func _input(event):
if event is InputEventKey and event.pressed:
if game_over:
if event.keycode == KEY_R:
init_game()
return
if won and not can_continue:
if event.keycode == KEY_C:
can_continue = true
win_label.visible = false
return
# 移动控制
var moved = false
match event.keycode:
KEY_UP, KEY_W:
moved = move_up()
KEY_DOWN, KEY_S:
moved = move_down()
KEY_LEFT, KEY_A:
moved = move_left()
KEY_RIGHT, KEY_D:
moved = move_right()
KEY_R:
init_game()
return
if moved:
add_random_number()
update_ui()
check_game_state()
queue_redraw()
func move_left() -> bool:
var moved = false
for y in range(GRID_SIZE):
var row = grid[y].duplicate()
var new_row = merge_line(row)
if new_row != grid[y]:
moved = true
grid[y] = new_row
return moved
func move_right() -> bool:
var moved = false
for y in range(GRID_SIZE):
var row = grid[y].duplicate()
row.reverse()
var new_row = merge_line(row)
new_row.reverse()
if new_row != grid[y]:
moved = true
grid[y] = new_row
return moved
func move_up() -> bool:
var moved = false
for x in range(GRID_SIZE):
var column = []
for y in range(GRID_SIZE):
column.append(grid[y][x])
var new_column = merge_line(column)
var changed = false
for y in range(GRID_SIZE):
if grid[y][x] != new_column[y]:
changed = true
grid[y][x] = new_column[y]
if changed:
moved = true
return moved
func move_down() -> bool:
var moved = false
for x in range(GRID_SIZE):
var column = []
for y in range(GRID_SIZE):
column.append(grid[y][x])
column.reverse()
var new_column = merge_line(column)
new_column.reverse()
var changed = false
for y in range(GRID_SIZE):
if grid[y][x] != new_column[y]:
changed = true
grid[y][x] = new_column[y]
if changed:
moved = true
return moved
func merge_line(line: Array) -> Array:
# 移除零
var filtered = []
for num in line:
if num != 0:
filtered.append(num)
# 合并相同数字
var merged = []
var i = 0
while i < filtered.size():
if i < filtered.size() - 1 and filtered[i] == filtered[i + 1]:
# 合并
var new_value = filtered[i] * 2
merged.append(new_value)
score += new_value
i += 2
else:
merged.append(filtered[i])
i += 1
# 填充零到指定长度
while merged.size() < GRID_SIZE:
merged.append(0)
return merged
func add_random_number():
var empty_cells = []
for y in range(GRID_SIZE):
for x in range(GRID_SIZE):
if grid[y][x] == 0:
empty_cells.append(Vector2(x, y))
if empty_cells.size() > 0:
var random_cell = empty_cells[randi() % empty_cells.size()]
var value = 2 if randf() < 0.9 else 4
grid[random_cell.y][random_cell.x] = value
func check_game_state():
# 检查是否达到2048
if not won:
for y in range(GRID_SIZE):
for x in range(GRID_SIZE):
if grid[y][x] == 2048:
won = true
can_continue = false
win_label.visible = true
return
# 检查是否游戏结束
if not can_move():
game_over = true
if score > best_score:
best_score = score
game_over_label.visible = true
func can_move() -> bool:
# 检查是否有空格
for y in range(GRID_SIZE):
for x in range(GRID_SIZE):
if grid[y][x] == 0:
return true
# 检查是否可以合并
for y in range(GRID_SIZE):
for x in range(GRID_SIZE):
var current = grid[y][x]
# 检查右边
if x < GRID_SIZE - 1 and grid[y][x + 1] == current:
return true
# 检查下面
if y < GRID_SIZE - 1 and grid[y + 1][x] == current:
return true
return false
func update_ui():
score_label.text = "分数: " + str(score)
best_label.text = "最高分: " + str(best_score)
func hide_labels():
game_over_label.visible = false
win_label.visible = false
func _draw():
if not game_board:
return
# 获取游戏板位置
var board_pos = game_board.position
# 绘制网格背景
for y in range(GRID_SIZE):
for x in range(GRID_SIZE):
var cell_x = board_pos.x + x * (CELL_SIZE + CELL_MARGIN) + CELL_MARGIN
var cell_y = board_pos.y + y * (CELL_SIZE + CELL_MARGIN) + CELL_MARGIN
var rect = Rect2(cell_x, cell_y, CELL_SIZE, CELL_SIZE)
# 绘制单元格背景
draw_rect(rect, Color(0.8, 0.7, 0.6), true)
# 绘制数字
var value = grid[y][x]
if value > 0:
# 绘制数字背景
var bg_color = NUMBER_COLORS.get(value, Color.GOLD)
draw_rect(rect, bg_color, true)
# 绘制数字文本
var text = str(value)
var font_size = 24 if value < 100 else (20 if value < 1000 else 16)
var text_color = TEXT_COLORS.get(value, Color.WHITE)
# 获取默认字体
var font = ThemeDB.fallback_font
# 计算文本尺寸
var text_size = font.get_string_size(text, HORIZONTAL_ALIGNMENT_CENTER, -1, font_size)
# 计算文本位置(居中)
var text_pos = Vector2(
cell_x + (CELL_SIZE - text_size.x) / 2,
cell_y + (CELL_SIZE - text_size.y) / 2 + text_size.y
)
# 绘制文本
draw_string(font, text_pos, text, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, text_color)

View File

@@ -0,0 +1 @@
uid://5dkxyuiuuhxk

View File

@@ -0,0 +1,102 @@
[gd_scene load_steps=2 format=3 uid="uid://dn0f1hjolxori"]
[ext_resource type="Script" uid="uid://5dkxyuiuuhxk" path="res://Scene/SmallGame/2048Game.gd" id="1_4d5vb"]
[node name="2048Game" type="Panel"]
offset_right = 1400.0
offset_bottom = 720.0
script = ExtResource("1_4d5vb")
[node name="GameBoard" type="Panel" parent="."]
layout_mode = 1
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -200.0
offset_top = -200.0
offset_right = 200.0
offset_bottom = 200.0
grow_horizontal = 2
grow_vertical = 2
[node name="ScoreLabel" type="Label" parent="."]
layout_mode = 1
anchors_preset = 2
anchor_top = 1.0
anchor_bottom = 1.0
offset_left = 50.0
offset_top = -100.0
offset_right = 250.0
offset_bottom = -70.0
grow_vertical = 0
text = "分数: 0"
[node name="BestLabel" type="Label" parent="."]
layout_mode = 1
anchors_preset = 2
anchor_top = 1.0
anchor_bottom = 1.0
offset_left = 50.0
offset_top = -70.0
offset_right = 250.0
offset_bottom = -40.0
grow_vertical = 0
text = "最高分: 0"
[node name="GameOverLabel" type="Label" parent="."]
visible = false
layout_mode = 1
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -150.0
offset_top = -50.0
offset_right = 150.0
offset_bottom = 50.0
grow_horizontal = 2
grow_vertical = 2
text = "游戏结束
按R重新开始"
horizontal_alignment = 1
vertical_alignment = 1
[node name="WinLabel" type="Label" parent="."]
visible = false
layout_mode = 1
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -150.0
offset_top = -100.0
offset_right = 150.0
offset_bottom = -50.0
grow_horizontal = 2
grow_vertical = 2
text = "恭喜达到2048
按C继续游戏"
horizontal_alignment = 1
vertical_alignment = 1
[node name="ControlsLabel" type="Label" parent="."]
layout_mode = 1
anchors_preset = 3
anchor_left = 1.0
anchor_top = 1.0
anchor_right = 1.0
anchor_bottom = 1.0
offset_left = -300.0
offset_top = -150.0
offset_right = -50.0
offset_bottom = -50.0
grow_horizontal = 0
grow_vertical = 0
text = "操作说明:
WASD或方向键 - 移动
R - 重新开始
C - 继续游戏(达到2048后)"

317
Scene/SmallGame/PushBox.gd Normal file
View File

@@ -0,0 +1,317 @@
extends Panel
# 游戏常量
const CELL_SIZE = 40
# 地图元素
enum CellType {
EMPTY, # 空地
WALL, # 墙壁
TARGET, # 目标点
BOX, # 箱子
PLAYER, # 玩家
BOX_ON_TARGET # 箱子在目标点上
}
# 颜色配置
const CELL_COLORS = {
CellType.EMPTY: Color.WHITE,
CellType.WALL: Color.DARK_GRAY,
CellType.TARGET: Color.LIGHT_BLUE,
CellType.BOX: Color.SADDLE_BROWN,
CellType.PLAYER: Color.GREEN,
CellType.BOX_ON_TARGET: Color.DARK_GREEN
}
# 关卡数据
const LEVELS = [
# 关卡1 - 简单入门
[
"########",
"#......#",
"#..##..#",
"#..#*..#",
"#..#$..#",
"#..@...#",
"#......#",
"########"
],
# 关卡2 - 两个箱子
[
"########",
"#......#",
"#.*$*..#",
"#......#",
"#..$...#",
"#..@...#",
"#......#",
"########"
],
# 关卡3 - 稍微复杂
[
"##########",
"#........#",
"#..####..#",
"#..*##*..#",
"#..$$....#",
"#........#",
"#...@....#",
"#........#",
"##########"
],
# 关卡4 - 更复杂的布局
[
"############",
"#..........#",
"#..######..#",
"#..*....#..#",
"#..$....#..#",
"#.......#..#",
"#..#....#..#",
"#..*....#..#",
"#..$......@#",
"#..........#",
"############"
]
]
# 游戏变量
var current_level = 0
var level_data = []
var player_pos = Vector2()
var moves = 0
var level_completed = false
var map_width = 0
var map_height = 0
# 节点引用
@onready var game_area = $GameArea
@onready var level_label = $LevelLabel
@onready var moves_label = $MovesLabel
@onready var win_label = $WinLabel
func _ready():
# 设置游戏区域样式
game_area.modulate = Color(0.9, 0.9, 0.9)
# 初始化游戏
init_level()
func init_level():
# 重置游戏状态
level_completed = false
moves = 0
# 加载当前关卡
load_level(current_level)
# 更新UI
update_ui()
win_label.visible = false
queue_redraw()
func load_level(level_index: int):
if level_index >= LEVELS.size():
level_index = LEVELS.size() - 1
var level_strings = LEVELS[level_index]
map_height = level_strings.size()
map_width = level_strings[0].length()
# 初始化关卡数据
level_data.clear()
for y in range(map_height):
var row = []
for x in range(map_width):
row.append(CellType.EMPTY)
level_data.append(row)
# 解析关卡字符串
for y in range(map_height):
var line = level_strings[y]
for x in range(line.length()):
var char = line[x]
match char:
'#': # 墙壁
level_data[y][x] = CellType.WALL
'*': # 目标点
level_data[y][x] = CellType.TARGET
'$': # 箱子
level_data[y][x] = CellType.BOX
'@': # 玩家
level_data[y][x] = CellType.PLAYER
player_pos = Vector2(x, y)
'+': # 箱子在目标点上
level_data[y][x] = CellType.BOX_ON_TARGET
'.': # 空地
level_data[y][x] = CellType.EMPTY
func _input(event):
if event is InputEventKey and event.pressed:
if level_completed:
match event.keycode:
KEY_N:
next_level()
KEY_R:
init_level()
return
# 移动控制
var direction = Vector2.ZERO
match event.keycode:
KEY_UP, KEY_W:
direction = Vector2(0, -1)
KEY_DOWN, KEY_S:
direction = Vector2(0, 1)
KEY_LEFT, KEY_A:
direction = Vector2(-1, 0)
KEY_RIGHT, KEY_D:
direction = Vector2(1, 0)
KEY_R:
init_level()
return
KEY_P:
prev_level()
return
KEY_N:
next_level()
return
if direction != Vector2.ZERO:
move_player(direction)
func move_player(direction: Vector2):
var new_pos = player_pos + direction
# 检查边界
if new_pos.x < 0 or new_pos.x >= map_width or new_pos.y < 0 or new_pos.y >= map_height:
return
var target_cell = level_data[new_pos.y][new_pos.x]
# 检查是否撞墙
if target_cell == CellType.WALL:
return
# 检查是否推箱子
if target_cell == CellType.BOX or target_cell == CellType.BOX_ON_TARGET:
var box_new_pos = new_pos + direction
# 检查箱子新位置是否有效
if box_new_pos.x < 0 or box_new_pos.x >= map_width or box_new_pos.y < 0 or box_new_pos.y >= map_height:
return
var box_target_cell = level_data[box_new_pos.y][box_new_pos.x]
# 箱子不能推到墙上或其他箱子上
if box_target_cell == CellType.WALL or box_target_cell == CellType.BOX or box_target_cell == CellType.BOX_ON_TARGET:
return
# 移动箱子
var was_on_target = (target_cell == CellType.BOX_ON_TARGET)
var moving_to_target = (box_target_cell == CellType.TARGET)
# 更新箱子原位置
if was_on_target:
level_data[new_pos.y][new_pos.x] = CellType.TARGET
else:
level_data[new_pos.y][new_pos.x] = CellType.EMPTY
# 更新箱子新位置
if moving_to_target:
level_data[box_new_pos.y][box_new_pos.x] = CellType.BOX_ON_TARGET
else:
level_data[box_new_pos.y][box_new_pos.x] = CellType.BOX
# 移动玩家
# 恢复玩家原位置(检查是否在目标点上)
var level_strings = LEVELS[current_level]
if player_pos.y < level_strings.size() and player_pos.x < level_strings[player_pos.y].length():
var original_char = level_strings[player_pos.y][player_pos.x]
if original_char == '*': # 玩家原来在目标点上
level_data[player_pos.y][player_pos.x] = CellType.TARGET
else:
level_data[player_pos.y][player_pos.x] = CellType.EMPTY
else:
level_data[player_pos.y][player_pos.x] = CellType.EMPTY
# 更新玩家位置
player_pos = new_pos
level_data[player_pos.y][player_pos.x] = CellType.PLAYER
# 增加步数
moves += 1
# 检查是否过关
check_win_condition()
# 更新UI和重绘
update_ui()
queue_redraw()
func check_win_condition():
# 检查是否所有箱子都在目标点上
for y in range(map_height):
for x in range(map_width):
if level_data[y][x] == CellType.BOX:
return # 还有箱子不在目标点上
# 所有箱子都在目标点上,过关!
level_completed = true
win_label.visible = true
func next_level():
if current_level < LEVELS.size() - 1:
current_level += 1
init_level()
func prev_level():
if current_level > 0:
current_level -= 1
init_level()
func update_ui():
level_label.text = "关卡: " + str(current_level + 1)
moves_label.text = "步数: " + str(moves)
func _draw():
if not game_area:
return
# 获取游戏区域位置
var area_pos = game_area.position
# 计算起始绘制位置(居中)
var start_x = area_pos.x + (game_area.size.x - map_width * CELL_SIZE) / 2
var start_y = area_pos.y + (game_area.size.y - map_height * CELL_SIZE) / 2
# 绘制地图
for y in range(map_height):
for x in range(map_width):
var cell_x = start_x + x * CELL_SIZE
var cell_y = start_y + y * CELL_SIZE
var rect = Rect2(cell_x, cell_y, CELL_SIZE, CELL_SIZE)
var cell_type = level_data[y][x]
var color = CELL_COLORS[cell_type]
# 绘制单元格
draw_rect(rect, color, true)
# 绘制边框
draw_rect(rect, Color.BLACK, false, 1)
# 特殊处理:如果是玩家在目标点上,需要先绘制目标点
if cell_type == CellType.PLAYER:
# 检查玩家下面是否有目标点(通过检查原始关卡数据)
var level_strings = LEVELS[current_level]
if y < level_strings.size() and x < level_strings[y].length():
var original_char = level_strings[y][x]
if original_char == '*': # 玩家在目标点上
draw_rect(rect, CELL_COLORS[CellType.TARGET], true)
draw_rect(rect, Color.BLACK, false, 1)
# 再绘制玩家(半透明)
var player_color = CELL_COLORS[CellType.PLAYER]
player_color.a = 0.8
draw_rect(rect, player_color, true)

View File

@@ -0,0 +1 @@
uid://b1t5fxyg0jjx5

View File

@@ -0,0 +1,85 @@
[gd_scene load_steps=2 format=3 uid="uid://cq14axh7bovu6"]
[ext_resource type="Script" uid="uid://b1t5fxyg0jjx5" path="res://Scene/SmallGame/PushBox.gd" id="1_qdfdf"]
[node name="PushBox" type="Panel"]
offset_right = 1402.0
offset_bottom = 720.0
script = ExtResource("1_qdfdf")
[node name="GameArea" type="Panel" parent="."]
layout_mode = 1
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -300.0
offset_top = -250.0
offset_right = 300.0
offset_bottom = 250.0
grow_horizontal = 2
grow_vertical = 2
[node name="LevelLabel" type="Label" parent="."]
layout_mode = 1
anchors_preset = 2
anchor_top = 1.0
anchor_bottom = 1.0
offset_left = 50.0
offset_top = -100.0
offset_right = 200.0
offset_bottom = -70.0
grow_vertical = 0
text = "关卡: 1"
[node name="MovesLabel" type="Label" parent="."]
layout_mode = 1
anchors_preset = 2
anchor_top = 1.0
anchor_bottom = 1.0
offset_left = 50.0
offset_top = -70.0
offset_right = 200.0
offset_bottom = -40.0
grow_vertical = 0
text = "步数: 0"
[node name="WinLabel" type="Label" parent="."]
visible = false
layout_mode = 1
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -150.0
offset_top = -50.0
offset_right = 150.0
offset_bottom = 50.0
grow_horizontal = 2
grow_vertical = 2
text = "恭喜过关!
按N进入下一关
按R重新开始"
horizontal_alignment = 1
vertical_alignment = 1
[node name="ControlsLabel" type="Label" parent="."]
layout_mode = 1
anchors_preset = 3
anchor_left = 1.0
anchor_top = 1.0
anchor_right = 1.0
anchor_bottom = 1.0
offset_left = -300.0
offset_top = -150.0
offset_right = -50.0
offset_bottom = -50.0
grow_horizontal = 0
grow_vertical = 0
text = "操作说明:
WASD或方向键 - 移动
R - 重新开始当前关卡
N - 下一关(过关后)
P - 上一关"

View File

@@ -0,0 +1,207 @@
extends Panel
# 游戏常量
const GRID_SIZE = 20
const GRID_WIDTH = 30
const GRID_HEIGHT = 30
# 方向枚举
enum Direction {
UP,
DOWN,
LEFT,
RIGHT
}
# 游戏变量
var snake_body = []
var snake_direction = Direction.RIGHT
var next_direction = Direction.RIGHT
var food_position = Vector2()
var score = 0
var game_over = false
# 节点引用
@onready var game_area = $GameArea
@onready var score_label = $ScoreLabel
@onready var game_over_label = $GameOverLabel
@onready var game_timer = $GameTimer
func _ready():
# 连接定时器信号
game_timer.timeout.connect(_on_game_timer_timeout)
# 设置游戏区域样式
game_area.modulate = Color(0.2, 0.2, 0.2, 1.0)
# 初始化游戏
init_game()
func init_game():
# 重置游戏状态
game_over = false
score = 0
snake_direction = Direction.RIGHT
next_direction = Direction.RIGHT
# 初始化蛇身
snake_body.clear()
snake_body.append(Vector2(5, 5))
snake_body.append(Vector2(4, 5))
snake_body.append(Vector2(3, 5))
# 生成食物
generate_food()
# 更新UI
update_score()
game_over_label.visible = false
# 启动定时器
game_timer.start()
func _input(event):
if event is InputEventKey and event.pressed:
if game_over:
if event.keycode == KEY_SPACE:
init_game()
return
# 控制蛇的方向
match event.keycode:
KEY_UP, KEY_W:
if snake_direction != Direction.DOWN:
next_direction = Direction.UP
KEY_DOWN, KEY_S:
if snake_direction != Direction.UP:
next_direction = Direction.DOWN
KEY_LEFT, KEY_A:
if snake_direction != Direction.RIGHT:
next_direction = Direction.LEFT
KEY_RIGHT, KEY_D:
if snake_direction != Direction.LEFT:
next_direction = Direction.RIGHT
func _on_game_timer_timeout():
if game_over:
return
# 更新方向
snake_direction = next_direction
# 移动蛇
move_snake()
# 检查碰撞
check_collisions()
# 重绘游戏
queue_redraw()
func move_snake():
var head = snake_body[0]
var new_head = head
# 根据方向计算新的头部位置
match snake_direction:
Direction.UP:
new_head = Vector2(head.x, head.y - 1)
Direction.DOWN:
new_head = Vector2(head.x, head.y + 1)
Direction.LEFT:
new_head = Vector2(head.x - 1, head.y)
Direction.RIGHT:
new_head = Vector2(head.x + 1, head.y)
# 添加新头部
snake_body.insert(0, new_head)
# 检查是否吃到食物
if new_head == food_position:
# 增加分数
score += 10
update_score()
# 生成新食物
generate_food()
else:
# 移除尾部
snake_body.pop_back()
func check_collisions():
var head = snake_body[0]
# 检查边界碰撞
if head.x < 0 or head.x >= GRID_WIDTH or head.y < 0 or head.y >= GRID_HEIGHT:
game_over = true
show_game_over()
return
# 检查自身碰撞
for i in range(1, snake_body.size()):
if head == snake_body[i]:
game_over = true
show_game_over()
return
func generate_food():
var attempts = 0
while attempts < 100: # 防止无限循环
food_position = Vector2(
randi() % GRID_WIDTH,
randi() % GRID_HEIGHT
)
# 确保食物不在蛇身上
var food_on_snake = false
for segment in snake_body:
if segment == food_position:
food_on_snake = true
break
if not food_on_snake:
break
attempts += 1
func update_score():
score_label.text = "分数: " + str(score)
func show_game_over():
game_timer.stop()
game_over_label.visible = true
func _draw():
if not game_area:
return
# 获取游戏区域的位置和大小
var area_pos = game_area.position
var area_size = game_area.size
# 计算网格大小
var cell_width = area_size.x / GRID_WIDTH
var cell_height = area_size.y / GRID_HEIGHT
# 绘制蛇身
for i in range(snake_body.size()):
var segment = snake_body[i]
var rect = Rect2(
area_pos.x + segment.x * cell_width,
area_pos.y + segment.y * cell_height,
cell_width - 1,
cell_height - 1
)
# 头部用不同颜色
var color = Color.GREEN if i == 0 else Color.LIME_GREEN
draw_rect(rect, color)
# 绘制食物
var food_rect = Rect2(
area_pos.x + food_position.x * cell_width,
area_pos.y + food_position.y * cell_height,
cell_width - 1,
cell_height - 1
)
draw_rect(food_rect, Color.RED)

View File

@@ -0,0 +1 @@
uid://rut5cdp1l3nh

View File

@@ -0,0 +1,57 @@
[gd_scene load_steps=2 format=3 uid="uid://grpkpy4duwac"]
[ext_resource type="Script" uid="uid://rut5cdp1l3nh" path="res://Scene/SmallGame/SnakeGame.gd" id="1_o070e"]
[node name="SnakeGame" type="Panel"]
offset_right = 1403.0
offset_bottom = 726.0
script = ExtResource("1_o070e")
[node name="GameArea" type="Panel" parent="."]
layout_mode = 1
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -300.0
offset_top = -300.0
offset_right = 300.0
offset_bottom = 300.0
grow_horizontal = 2
grow_vertical = 2
[node name="ScoreLabel" type="Label" parent="."]
layout_mode = 1
anchors_preset = 2
anchor_top = 1.0
anchor_bottom = 1.0
offset_left = 20.0
offset_top = -50.0
offset_right = 200.0
offset_bottom = -20.0
grow_vertical = 0
text = "分数: 0"
[node name="GameOverLabel" type="Label" parent="."]
visible = false
layout_mode = 1
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -100.0
offset_top = -50.0
offset_right = 100.0
offset_bottom = 50.0
grow_horizontal = 2
grow_vertical = 2
text = "游戏结束
按空格重新开始"
horizontal_alignment = 1
vertical_alignment = 1
[node name="GameTimer" type="Timer" parent="."]
wait_time = 0.2
autostart = true

333
Scene/SmallGame/Tetris.gd Normal file
View File

@@ -0,0 +1,333 @@
extends Panel
# 游戏常量
const BOARD_WIDTH = 10
const BOARD_HEIGHT = 20
const CELL_SIZE = 30
# 方块类型
enum PieceType {
I, O, T, S, Z, J, L
}
# 方块形状定义
const PIECE_SHAPES = {
PieceType.I: [
[[1, 1, 1, 1]],
[[1], [1], [1], [1]]
],
PieceType.O: [
[[1, 1], [1, 1]]
],
PieceType.T: [
[[0, 1, 0], [1, 1, 1]],
[[1, 0], [1, 1], [1, 0]],
[[1, 1, 1], [0, 1, 0]],
[[0, 1], [1, 1], [0, 1]]
],
PieceType.S: [
[[0, 1, 1], [1, 1, 0]],
[[1, 0], [1, 1], [0, 1]]
],
PieceType.Z: [
[[1, 1, 0], [0, 1, 1]],
[[0, 1], [1, 1], [1, 0]]
],
PieceType.J: [
[[1, 0, 0], [1, 1, 1]],
[[1, 1], [1, 0], [1, 0]],
[[1, 1, 1], [0, 0, 1]],
[[0, 1], [0, 1], [1, 1]]
],
PieceType.L: [
[[0, 0, 1], [1, 1, 1]],
[[1, 0], [1, 0], [1, 1]],
[[1, 1, 1], [1, 0, 0]],
[[1, 1], [0, 1], [0, 1]]
]
}
# 方块颜色
const PIECE_COLORS = {
PieceType.I: Color.CYAN,
PieceType.O: Color.YELLOW,
PieceType.T: Color.MAGENTA,
PieceType.S: Color.GREEN,
PieceType.Z: Color.RED,
PieceType.J: Color.BLUE,
PieceType.L: Color.ORANGE
}
# 游戏变量
var board = []
var current_piece = null
var current_piece_pos = Vector2()
var current_piece_rotation = 0
var next_piece_type = PieceType.I
var score = 0
var level = 1
var lines_cleared = 0
var game_over = false
var drop_time = 1.0
# 节点引用
@onready var game_area = $GameArea
@onready var next_piece_area = $NextPieceArea
@onready var score_label = $ScoreLabel
@onready var level_label = $LevelLabel
@onready var lines_label = $LinesLabel
@onready var game_over_label = $GameOverLabel
@onready var drop_timer = $DropTimer
func _ready():
# 连接定时器信号
drop_timer.timeout.connect(_on_drop_timer_timeout)
# 设置游戏区域样式
game_area.modulate = Color(0.1, 0.1, 0.1, 1.0)
next_piece_area.modulate = Color(0.2, 0.2, 0.2, 1.0)
# 初始化游戏
init_game()
func init_game():
# 重置游戏状态
game_over = false
score = 0
level = 1
lines_cleared = 0
drop_time = 1.0
# 初始化游戏板
board.clear()
for y in range(BOARD_HEIGHT):
var row = []
for x in range(BOARD_WIDTH):
row.append(0)
board.append(row)
# 生成第一个方块
next_piece_type = randi() % PieceType.size()
spawn_new_piece()
# 更新UI
update_ui()
game_over_label.visible = false
# 启动定时器
drop_timer.wait_time = drop_time
drop_timer.start()
func _input(event):
if event is InputEventKey and event.pressed:
if game_over:
if event.keycode == KEY_SPACE:
init_game()
return
if not current_piece:
return
# 控制方块
match event.keycode:
KEY_A:
move_piece(-1, 0)
KEY_D:
move_piece(1, 0)
KEY_S:
move_piece(0, 1)
KEY_W:
rotate_piece()
KEY_SPACE:
drop_piece()
func spawn_new_piece():
current_piece = {
"type": next_piece_type,
"rotation": 0
}
current_piece_pos = Vector2(BOARD_WIDTH / 2 - 1, 0)
current_piece_rotation = 0
# 生成下一个方块
next_piece_type = randi() % PieceType.size()
# 检查游戏是否结束
if not can_place_piece(current_piece_pos, current_piece_rotation):
game_over = true
show_game_over()
func move_piece(dx: int, dy: int):
var new_pos = current_piece_pos + Vector2(dx, dy)
if can_place_piece(new_pos, current_piece_rotation):
current_piece_pos = new_pos
queue_redraw()
func rotate_piece():
var new_rotation = (current_piece_rotation + 1) % get_piece_rotations(current_piece.type)
if can_place_piece(current_piece_pos, new_rotation):
current_piece_rotation = new_rotation
queue_redraw()
func drop_piece():
while can_place_piece(current_piece_pos + Vector2(0, 1), current_piece_rotation):
current_piece_pos.y += 1
place_piece()
func can_place_piece(pos: Vector2, rotation: int) -> bool:
var shape = get_piece_shape(current_piece.type, rotation)
for y in range(shape.size()):
for x in range(shape[y].size()):
if shape[y][x] == 1:
var board_x = pos.x + x
var board_y = pos.y + y
# 检查边界
if board_x < 0 or board_x >= BOARD_WIDTH or board_y >= BOARD_HEIGHT:
return false
# 检查碰撞
if board_y >= 0 and board[board_y][board_x] != 0:
return false
return true
func place_piece():
var shape = get_piece_shape(current_piece.type, current_piece_rotation)
for y in range(shape.size()):
for x in range(shape[y].size()):
if shape[y][x] == 1:
var board_x = current_piece_pos.x + x
var board_y = current_piece_pos.y + y
if board_y >= 0:
board[board_y][board_x] = current_piece.type + 1
# 检查并清除完整的行
clear_lines()
# 生成新方块
spawn_new_piece()
queue_redraw()
func clear_lines():
var lines_to_clear = []
# 找到完整的行
for y in range(BOARD_HEIGHT):
var is_full = true
for x in range(BOARD_WIDTH):
if board[y][x] == 0:
is_full = false
break
if is_full:
lines_to_clear.append(y)
# 清除行并下移
for line_y in lines_to_clear:
board.erase(board[line_y])
var new_row = []
for x in range(BOARD_WIDTH):
new_row.append(0)
board.insert(0, new_row)
# 更新分数和等级
if lines_to_clear.size() > 0:
lines_cleared += lines_to_clear.size()
score += lines_to_clear.size() * 100 * level
# 每10行提升一个等级
level = lines_cleared / 10 + 1
drop_time = max(0.1, 1.0 - (level - 1) * 0.1)
drop_timer.wait_time = drop_time
update_ui()
func get_piece_shape(type: PieceType, rotation: int) -> Array:
return PIECE_SHAPES[type][rotation]
func get_piece_rotations(type: PieceType) -> int:
return PIECE_SHAPES[type].size()
func update_ui():
score_label.text = "分数: " + str(score)
level_label.text = "等级: " + str(level)
lines_label.text = "消除行数: " + str(lines_cleared)
func show_game_over():
drop_timer.stop()
game_over_label.visible = true
func _on_drop_timer_timeout():
if game_over or not current_piece:
return
if can_place_piece(current_piece_pos + Vector2(0, 1), current_piece_rotation):
current_piece_pos.y += 1
queue_redraw()
else:
place_piece()
func _draw():
if not game_area:
return
# 获取游戏区域的位置
var area_pos = game_area.position
# 绘制游戏板
for y in range(BOARD_HEIGHT):
for x in range(BOARD_WIDTH):
var cell_value = board[y][x]
if cell_value > 0:
var rect = Rect2(
area_pos.x + x * CELL_SIZE,
area_pos.y + y * CELL_SIZE,
CELL_SIZE - 1,
CELL_SIZE - 1
)
var color = PIECE_COLORS[cell_value - 1]
draw_rect(rect, color)
# 绘制当前方块
if current_piece:
var shape = get_piece_shape(current_piece.type, current_piece_rotation)
for y in range(shape.size()):
for x in range(shape[y].size()):
if shape[y][x] == 1:
var board_x = current_piece_pos.x + x
var board_y = current_piece_pos.y + y
if board_y >= 0:
var rect = Rect2(
area_pos.x + board_x * CELL_SIZE,
area_pos.y + board_y * CELL_SIZE,
CELL_SIZE - 1,
CELL_SIZE - 1
)
var color = PIECE_COLORS[current_piece.type]
draw_rect(rect, color)
# 绘制网格线
for x in range(BOARD_WIDTH + 1):
var start_pos = Vector2(area_pos.x + x * CELL_SIZE, area_pos.y)
var end_pos = Vector2(area_pos.x + x * CELL_SIZE, area_pos.y + BOARD_HEIGHT * CELL_SIZE)
draw_line(start_pos, end_pos, Color.GRAY, 1)
for y in range(BOARD_HEIGHT + 1):
var start_pos = Vector2(area_pos.x, area_pos.y + y * CELL_SIZE)
var end_pos = Vector2(area_pos.x + BOARD_WIDTH * CELL_SIZE, area_pos.y + y * CELL_SIZE)
draw_line(start_pos, end_pos, Color.GRAY, 1)
# 绘制下一个方块预览
var next_area_pos = next_piece_area.position
var next_shape = get_piece_shape(next_piece_type, 0)
for y in range(next_shape.size()):
for x in range(next_shape[y].size()):
if next_shape[y][x] == 1:
var rect = Rect2(
next_area_pos.x + 20 + x * 20,
next_area_pos.y + 50 + y * 20,
19,
19
)
var color = PIECE_COLORS[next_piece_type]
draw_rect(rect, color)

View File

@@ -0,0 +1 @@
uid://yhljjw1pbovq

120
Scene/SmallGame/Tetris.tscn Normal file
View File

@@ -0,0 +1,120 @@
[gd_scene load_steps=2 format=3 uid="uid://c3nuuwu5te3bu"]
[ext_resource type="Script" uid="uid://yhljjw1pbovq" path="res://Scene/SmallGame/Tetris.gd" id="1_s1q1g"]
[node name="Tetris" type="Panel"]
offset_right = 1403.0
offset_bottom = 721.0
script = ExtResource("1_s1q1g")
[node name="GameArea" type="Panel" parent="."]
layout_mode = 1
anchors_preset = 4
anchor_top = 0.5
anchor_bottom = 0.5
offset_left = 50.0
offset_top = -300.0
offset_right = 350.0
offset_bottom = 300.0
grow_vertical = 2
[node name="NextPieceArea" type="Panel" parent="."]
layout_mode = 1
anchors_preset = 1
anchor_left = 1.0
anchor_right = 1.0
offset_left = -200.0
offset_top = 50.0
offset_right = -50.0
offset_bottom = 200.0
grow_horizontal = 0
[node name="NextPieceLabel" type="Label" parent="NextPieceArea"]
layout_mode = 1
anchors_preset = 5
anchor_left = 0.5
anchor_right = 0.5
offset_left = -50.0
offset_top = 10.0
offset_right = 50.0
offset_bottom = 40.0
grow_horizontal = 2
text = "下一个"
horizontal_alignment = 1
[node name="ScoreLabel" type="Label" parent="."]
layout_mode = 1
anchors_preset = 1
anchor_left = 1.0
anchor_right = 1.0
offset_left = -200.0
offset_top = 220.0
offset_right = -50.0
offset_bottom = 250.0
grow_horizontal = 0
text = "分数: 0"
horizontal_alignment = 1
[node name="LevelLabel" type="Label" parent="."]
layout_mode = 1
anchors_preset = 1
anchor_left = 1.0
anchor_right = 1.0
offset_left = -200.0
offset_top = 260.0
offset_right = -50.0
offset_bottom = 290.0
grow_horizontal = 0
text = "等级: 1"
horizontal_alignment = 1
[node name="LinesLabel" type="Label" parent="."]
layout_mode = 1
anchors_preset = 1
anchor_left = 1.0
anchor_right = 1.0
offset_left = -200.0
offset_top = 300.0
offset_right = -50.0
offset_bottom = 330.0
grow_horizontal = 0
text = "消除行数: 0"
horizontal_alignment = 1
[node name="GameOverLabel" type="Label" parent="."]
visible = false
layout_mode = 1
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -100.0
offset_top = -50.0
offset_right = 100.0
offset_bottom = 50.0
grow_horizontal = 2
grow_vertical = 2
text = "游戏结束
按空格重新开始"
horizontal_alignment = 1
vertical_alignment = 1
[node name="DropTimer" type="Timer" parent="."]
autostart = true
[node name="ControlsLabel" type="Label" parent="."]
layout_mode = 1
anchors_preset = 1
anchor_left = 1.0
anchor_right = 1.0
offset_left = -200.0
offset_top = 400.0
offset_right = -50.0
offset_bottom = 500.0
grow_horizontal = 0
text = "操作说明:
A/D - 左右移动
S - 快速下降
W - 旋转
空格 - 瞬间下降"

View File

@@ -43,6 +43,11 @@ var current_filter_quality = ""
var current_sort_key = ""
var current_sort_ascending = true
# 库存系统
var crop_stock_data : Dictionary = {} # 存储每个作物的库存数量
var stock_file_path : String = "" # 库存数据文件路径(根据用户名动态设置)
var last_refresh_date : String = "" # 上次刷新库存的日期
# 准备函数
func _ready():
# 连接按钮信号
@@ -51,6 +56,9 @@ func _ready():
# 连接可见性改变信号
visibility_changed.connect(_on_visibility_changed)
# 初始化库存系统
_init_stock_system()
# 隐藏面板(初始默认隐藏)
self.hide()
@@ -60,6 +68,8 @@ func _ready():
func _connect_buttons():
# 关闭按钮
quit_button.pressed.connect(self._on_quit_button_pressed)
# 刷新按钮
refresh_button.pressed.connect(self._on_refresh_button_pressed)
# 过滤按钮
sort_all_button.pressed.connect(func(): _filter_by_quality(""))
@@ -78,11 +88,22 @@ func _connect_buttons():
# 初始化商店
func init_store():
# 重新初始化库存系统(确保用户名正确)
_init_stock_system()
# 清空已有的作物按钮
for child in crop_grid_container.get_children():
child.queue_free()
# 遍历可种植的作物数据并添加到商店
# 检查并刷新库存(如果需要)
_check_daily_refresh()
# 获取玩家当前等级,确定可解锁的格子数量
var player_level = main_game.level
var max_unlocked_slots = player_level # 玩家等级 = 可解锁的格子数量
# 收集符合条件的作物
var available_crops = []
for crop_name in main_game.can_planted_crop:
var crop = main_game.can_planted_crop[crop_name]
@@ -92,13 +113,33 @@ func init_store():
# 只显示当前等级可以种植的作物
if crop["等级"] <= main_game.level:
var store_btn = _create_store_button(crop_name, crop["品质"])
crop_grid_container.add_child(store_btn)
available_crops.append({"name": crop_name, "data": crop})
print("商店初始化完成,共添加按钮: " + str(crop_grid_container.get_child_count()) + "")
# 根据等级限制显示的格子数量
var slots_to_show = min(available_crops.size(), max_unlocked_slots)
# 添加可显示的作物按钮
for i in range(slots_to_show):
var crop_info = available_crops[i]
var store_btn = _create_store_button(crop_info["name"], crop_info["data"]["品质"])
crop_grid_container.add_child(store_btn)
# 添加锁定的格子(如果有剩余的可用作物但等级不够解锁)
var remaining_crops = available_crops.size() - slots_to_show
if remaining_crops > 0:
# 创建锁定格子提示
var locked_slots = min(remaining_crops, 5) # 最多显示5个锁定格子作为提示
for i in range(locked_slots):
var locked_btn = _create_locked_slot_button(player_level + 1)
crop_grid_container.add_child(locked_btn)
print("商店初始化完成,玩家等级: ", player_level, ", 解锁格子: ", slots_to_show, ", 可用作物: ", available_crops.size())
# 更新金钱显示
_update_money_display()
# 显示等级限制提示
_show_level_restriction_info(player_level, available_crops.size(), slots_to_show)
# 创建商店按钮
func _create_store_button(crop_name: String, crop_quality: String) -> Button:
@@ -107,14 +148,26 @@ func _create_store_button(crop_name: String, crop_quality: String) -> Button:
var crop = main_game.can_planted_crop[crop_name]
# 确保按钮可见并可点击
# 获取当前库存
var current_stock = _get_crop_stock(crop_name)
var is_sold_out = current_stock <= 0
# 设置按钮状态
button.visible = true
button.disabled = false
button.disabled = is_sold_out
button.focus_mode = Control.FOCUS_ALL
# 设置按钮文本,显示价格
# 设置按钮文本,显示价格和库存
var display_name = crop.get("作物名称", crop_name)
button.text = str(crop_quality + "-" + display_name + "\n价格: ¥" + str(crop["花费"]))
var stock_text = "库存: " + str(current_stock) if not is_sold_out else "已售罄"
var price_text = "价格: ¥" + str(crop["花费"])
if is_sold_out:
button.text = str(crop_quality + "-" + display_name + "\n" + price_text + "\n" + stock_text)
button.modulate = Color(0.6, 0.6, 0.6, 0.8) # 灰色半透明效果
else:
button.text = str(crop_quality + "-" + display_name + "\n" + price_text + "\n" + stock_text)
button.modulate = Color.WHITE # 正常颜色
# 将成熟时间从秒转换为天时分秒格式
var total_seconds = int(crop["生长时间"])
@@ -145,6 +198,9 @@ func _create_store_button(crop_name: String, crop_quality: String) -> Button:
if seconds > 0:
time_str += str(seconds) + ""
# 添加库存信息到tooltip
var stock_tooltip = "\n库存: " + str(current_stock) + "" if not is_sold_out else "\n状态: 已售罄"
button.tooltip_text = str(
"作物: " + display_name + "\n" +
"品质: " + crop_quality + "\n" +
@@ -153,7 +209,7 @@ func _create_store_button(crop_name: String, crop_quality: String) -> Button:
"收获收益: " + str(crop["收益"]) + "\n" +
"需求等级: " + str(crop["等级"]) + "\n" +
"耐候性: " + str(crop["耐候性"]) + "\n" +
"经验: " + str(crop["经验"]) + "\n" +
"经验: " + str(crop["经验"]) + "" + stock_tooltip + "\n" +
"描述: " + str(crop["描述"])
)
@@ -183,6 +239,11 @@ func _create_store_button(crop_name: String, crop_quality: String) -> Button:
func _on_store_buy_pressed(crop_name: String):
var crop = main_game.can_planted_crop[crop_name]
# 检查库存
if not _is_crop_in_stock(crop_name):
Toast.show("该种子已售罄,请等待明日刷新", Color.RED)
return
# 检查等级要求
if main_game.level < crop["等级"]:
Toast.show("等级不足,无法购买此种子", Color.RED)
@@ -196,13 +257,15 @@ func _on_store_buy_pressed(crop_name: String):
# 显示批量购买弹窗
if batch_buy_popup:
var crop_desc = crop.get("描述", "暂无描述")
var max_stock = _get_crop_stock(crop_name)
batch_buy_popup.show_buy_popup(
crop_name,
crop["花费"],
crop_desc,
"seed",
_on_confirm_buy_seed,
_on_cancel_buy_seed
_on_cancel_buy_seed,
max_stock # 传递最大库存限制
)
else:
print("批量购买弹窗未找到")
@@ -211,6 +274,12 @@ func _on_store_buy_pressed(crop_name: String):
func _on_confirm_buy_seed(crop_name: String, unit_cost: int, quantity: int, buy_type: String):
var total_cost = unit_cost * quantity
# 再次检查库存是否足够
var current_stock = _get_crop_stock(crop_name)
if current_stock < quantity:
Toast.show("库存不足!当前库存: " + str(current_stock) + ",需要: " + str(quantity), Color.RED, 3.0, 1.0)
return
# 再次检查金钱是否足够
if main_game.money < total_cost:
Toast.show("金钱不足!需要 " + str(total_cost) + " 元,当前只有 " + str(main_game.money) + "", Color.RED, 3.0, 1.0)
@@ -229,6 +298,15 @@ func _send_batch_buy_seed_request(crop_name: String, quantity: int):
if tcp_network_manager_panel and tcp_network_manager_panel.sendBuySeed(crop_name, quantity):
# 服务器会处理批量购买逻辑,客户端等待响应
print("已发送批量购买种子请求:", crop_name, " 数量:", quantity)
# 购买成功后扣减库存
if _reduce_crop_stock(crop_name, quantity):
print("库存扣减成功:", crop_name, " 扣减数量:", quantity)
# 刷新商店显示
_apply_filter_and_sort()
Toast.show("购买成功!剩余库存: " + str(_get_crop_stock(crop_name)), Color.GREEN, 2.0, 1.0)
else:
Toast.show("库存扣减失败", Color.RED, 2.0, 1.0)
else:
Toast.show("购买请求发送失败", Color.RED, 2.0, 1.0)
@@ -255,6 +333,10 @@ func _apply_filter_and_sort():
for child in crop_grid_container.get_children():
child.queue_free()
# 获取玩家当前等级,确定可解锁的格子数量
var player_level = main_game.level
var max_unlocked_slots = player_level
# 收集符合条件的作物
var filtered_crops = []
for crop_name in main_game.can_planted_crop:
@@ -281,13 +363,29 @@ func _apply_filter_and_sort():
if current_sort_key != "":
filtered_crops.sort_custom(Callable(self, "_sort_crop_items"))
# 添加所有过滤和排序后的作物
for crop in filtered_crops:
# 根据等级限制显示的格子数量
var slots_to_show = min(filtered_crops.size(), max_unlocked_slots)
# 添加可显示的作物按钮
for i in range(slots_to_show):
var crop = filtered_crops[i]
var store_btn = _create_store_button(crop["name"], crop["data"]["品质"])
crop_grid_container.add_child(store_btn)
# 添加锁定的格子(如果有剩余的可用作物但等级不够解锁)
var remaining_crops = filtered_crops.size() - slots_to_show
if remaining_crops > 0:
# 创建锁定格子提示
var locked_slots = min(remaining_crops, 5) # 最多显示5个锁定格子作为提示
for i in range(locked_slots):
var locked_btn = _create_locked_slot_button(player_level + 1)
crop_grid_container.add_child(locked_btn)
# 更新金钱显示
_update_money_display()
# 显示等级限制提示
_show_level_restriction_info(player_level, filtered_crops.size(), slots_to_show)
# 自定义排序函数
func _sort_crop_items(a, b):
@@ -512,6 +610,211 @@ func _update_button_crop_image(button: Button, crop_name: String):
func _on_crop_selected(crop_name: String):
_on_store_buy_pressed(crop_name)
#=========================库存系统=========================
# 初始化库存系统
func _init_stock_system():
# 根据用户名设置库存文件路径,实现账号隔离
var user_name = main_game.user_name if main_game.user_name != "" else "default_user"
stock_file_path = "user://crop_stock_" + user_name + ".json"
print("库存系统初始化,用户:", user_name, ",文件路径:", stock_file_path)
_load_stock_data()
_check_daily_refresh()
# 加载库存数据
func _load_stock_data():
print("尝试加载库存数据,文件路径:", stock_file_path)
if FileAccess.file_exists(stock_file_path):
var file = FileAccess.open(stock_file_path, FileAccess.READ)
if file:
var json_string = file.get_as_text()
file.close()
print("读取到的JSON数据", json_string)
var json = JSON.new()
var parse_result = json.parse(json_string)
if parse_result == OK:
var data = json.data
crop_stock_data = data.get("stock", {})
last_refresh_date = data.get("last_refresh_date", "")
print("库存数据加载成功,库存条目数:", crop_stock_data.size())
print("加载的库存数据:", crop_stock_data)
print("上次刷新日期:", last_refresh_date)
# 如果库存数据为空,重新生成
if crop_stock_data.is_empty():
print("库存数据为空,重新生成")
_generate_initial_stock()
else:
print("库存数据解析失败,错误:", parse_result, ",重新生成")
_generate_initial_stock()
else:
print("无法打开库存文件,重新生成")
_generate_initial_stock()
else:
print("库存文件不存在,生成初始库存")
_generate_initial_stock()
# 保存库存数据
func _save_stock_data():
var data = {
"stock": crop_stock_data,
"last_refresh_date": last_refresh_date
}
print("准备保存库存数据到:", stock_file_path)
print("保存的数据:", data)
var file = FileAccess.open(stock_file_path, FileAccess.WRITE)
if file:
var json_string = JSON.stringify(data)
file.store_string(json_string)
file.close()
print("库存数据保存成功JSON字符串", json_string)
else:
print("无法保存库存数据,文件打开失败")
# 生成初始库存
func _generate_initial_stock():
crop_stock_data.clear()
# 确保main_game和can_planted_crop存在
if not main_game or not main_game.can_planted_crop:
print("错误:无法访问主游戏数据,无法生成库存")
return
var generated_count = 0
for crop_name in main_game.can_planted_crop:
var crop = main_game.can_planted_crop[crop_name]
# 检查是否可以购买
if not crop.get("能否购买", true):
continue
# 根据品质设置库存范围
var stock_amount = _get_stock_amount_by_quality(crop["品质"])
crop_stock_data[crop_name] = stock_amount
generated_count += 1
print("生成库存:", crop_name, " - ", crop["品质"], " - ", stock_amount, "")
# 设置当前日期为刷新日期
last_refresh_date = _get_current_date()
_save_stock_data()
print("初始库存生成完成,共生成", generated_count, "种作物的库存")
print("当前库存数据:", crop_stock_data)
# 根据品质获取库存数量
func _get_stock_amount_by_quality(quality: String) -> int:
var min_stock: int
var max_stock: int
match quality:
"传奇":
min_stock = 10
max_stock = 30
"史诗":
min_stock = 20
max_stock = 50
"稀有":
min_stock = 40
max_stock = 80
"优良":
min_stock = 80
max_stock = 150
"普通":
min_stock = 150
max_stock = 300
_:
min_stock = 100
max_stock = 200
return randi_range(min_stock, max_stock)
# 获取当前日期字符串
func _get_current_date() -> String:
var datetime = Time.get_datetime_dict_from_system()
return str(datetime.year) + "-" + str(datetime.month).pad_zeros(2) + "-" + str(datetime.day).pad_zeros(2)
# 检查是否需要每日刷新
func _check_daily_refresh():
var current_date = _get_current_date()
if last_refresh_date != current_date:
print("检测到新的一天,刷新库存")
_refresh_daily_stock()
# 每日刷新库存
func _refresh_daily_stock():
_generate_initial_stock()
Toast.show("种子商店库存已刷新!", Color.GREEN, 3.0, 1.0)
# 获取作物当前库存
func _get_crop_stock(crop_name: String) -> int:
return crop_stock_data.get(crop_name, 0)
# 减少作物库存
func _reduce_crop_stock(crop_name: String, amount: int) -> bool:
var current_stock = _get_crop_stock(crop_name)
if current_stock >= amount:
crop_stock_data[crop_name] = current_stock - amount
_save_stock_data()
return true
return false
# 检查作物是否有库存
func _is_crop_in_stock(crop_name: String) -> bool:
return _get_crop_stock(crop_name) > 0
# 创建锁定格子按钮
func _create_locked_slot_button(required_level: int) -> Button:
var button = main_game.item_button.duplicate()
# 设置按钮为禁用状态
button.disabled = true
button.modulate = Color(0.5, 0.5, 0.5, 0.8) # 灰色半透明效果
# 设置按钮文本
button.text = "🔒 锁定\n需要等级: " + str(required_level)
button.tooltip_text = "此格子已锁定,需要达到等级 " + str(required_level) + " 才能解锁"
# 隐藏作物图片
var crop_image = button.get_node_or_null("CropImage")
if crop_image:
crop_image.visible = false
# 设置标题颜色为灰色
if button.has_node("Title"):
button.get_node("Title").modulate = Color.GRAY
return button
# 显示等级限制信息
func _show_level_restriction_info(player_level: int, total_crops: int, unlocked_slots: int):
# 查找或创建信息标签
var info_label = get_node_or_null("LevelInfoLabel")
if info_label == null:
info_label = Label.new()
info_label.name = "LevelInfoLabel"
info_label.position = Vector2(10, 55)
info_label.size = Vector2(300, 30)
# 设置标签样式
info_label.add_theme_color_override("font_color", Color(0.8, 0.8, 1.0, 1.0)) # 淡蓝色
info_label.add_theme_font_size_override("font_size", 18)
add_child(info_label)
# 更新信息显示
var locked_crops = total_crops - unlocked_slots
if locked_crops > 0:
info_label.text = "等级 " + str(player_level) + " | 已解锁: " + str(unlocked_slots) + "/" + str(total_crops) + " 个格子"
info_label.modulate = Color.YELLOW
else:
info_label.text = "等级 " + str(player_level) + " | 所有格子已解锁 (" + str(unlocked_slots) + "/" + str(total_crops) + ")"
info_label.modulate = Color.GREEN
#=========================面板通用处理=========================
#手动刷新种子商店面板

View File

@@ -571,6 +571,8 @@ func _on_quit_button_pressed():
func _on_visibility_changed():
if visible:
GlobalVariables.isZoomDisabled = true
# 面板显示时请求同步最新的背包数据
tcp_network_manager_panel.send_sync_bag_data_request()
update_crop_warehouse_ui()
pass
else:

View File

@@ -73,6 +73,8 @@ func init_item_bag():
for child in bag_grid.get_children():
child.queue_free()
# 重置筛选状态为显示全部
current_filter_type = "全部"
# 显示背包中的道具
update_item_bag_ui()
@@ -85,6 +87,9 @@ func update_item_bag_ui():
# 获取过滤后的道具列表
var filtered_items = _get_filtered_items()
# 输出筛选统计信息
print("道具背包筛选结果: ", current_filter_type, " - 共 ", filtered_items.size(), " 个道具")
# 为背包中的每个道具创建按钮
for item_data in filtered_items:
var item_name = item_data["name"]
@@ -177,8 +182,9 @@ func _get_filtered_items() -> Array:
if _is_pet_item(item_name):
filtered_items.append(item_data)
else:
# 正常模式显示所有道具
filtered_items.append(item_data)
# 正常模式下,应用筛选条件
if _is_item_match_filter(item_name):
filtered_items.append(item_data)
return filtered_items
@@ -501,6 +507,8 @@ func _on_refresh_button_pressed() -> void:
func _on_visibility_changed():
if visible:
GlobalVariables.isZoomDisabled = true
# 面板显示时请求同步最新的背包数据
tcp_network_manager_panel.send_sync_bag_data_request()
update_item_bag_ui()
pass
else:
@@ -515,3 +523,49 @@ func get_selected_item_name() -> String:
# 检查是否有道具被选择
func is_item_currently_selected() -> bool:
return is_item_selected
#========================筛选功能============================
# 当前筛选类型
var current_filter_type: String = "全部"
#显示全部,既全部显示(默认)
func _on_all_filter_pressed() -> void:
current_filter_type = "全部"
update_item_bag_ui()
Toast.show("显示全部道具", Color.GREEN, 2.0, 1.0)
#筛选宠物类型道具
func _on_pet_filter_pressed() -> void:
current_filter_type = "宠物道具"
update_item_bag_ui()
Toast.show("筛选宠物道具", Color.GREEN, 2.0, 1.0)
#筛选作物类型道具
func _on_crop_filter_pressed() -> void:
current_filter_type = "作物道具"
update_item_bag_ui()
Toast.show("筛选作物道具", Color.GREEN, 2.0, 1.0)
#筛选农场类型道具
func _on_farm_filter_pressed() -> void:
current_filter_type = "农场道具"
update_item_bag_ui()
Toast.show("筛选农场道具", Color.GREEN, 2.0, 1.0)
# 检查道具是否符合当前筛选条件
func _is_item_match_filter(item_name: String) -> bool:
# 如果是显示全部直接返回true
if current_filter_type == "全部":
return true
# 检查道具配置中的类型
var item_config = _load_item_config()
if item_config and item_config.has(item_name):
var item_info = item_config[item_name]
var item_type = item_info.get("类型", "")
return item_type == current_filter_type
# 如果没有配置信息,默认不显示
return false
#========================筛选功能============================

View File

@@ -38,6 +38,8 @@ func _ready():
func init_item_store():
# 从主游戏脚本获取道具配置数据
_load_item_config_from_main()
# 重置筛选状态为显示全部
current_filter_type = "全部"
update_item_store_ui()
# 更新道具商店UI
@@ -46,10 +48,17 @@ func update_item_store_ui():
for child in store_grid.get_children():
child.queue_free()
print("更新道具商店UI道具种类", item_config.size())
print("更新道具商店UI道具种类", item_config.size(), ",当前筛选:", current_filter_type)
# 统计符合筛选条件的道具数量
var filtered_count = 0
# 为每个道具配置创建按钮
for item_name in item_config.keys():
# 检查是否符合筛选条件
if not _is_item_match_filter(item_name):
continue
var item_info = item_config[item_name]
var item_cost = item_info.get("花费", 0)
var item_desc = item_info.get("描述", "暂无描述")
@@ -64,6 +73,9 @@ func update_item_store_ui():
button.pressed.connect(func(): _on_store_item_selected(item_name, item_cost, item_desc))
store_grid.add_child(button)
filtered_count += 1
print("筛选后显示道具数量:", filtered_count)
# 创建道具按钮
func _create_item_button(item_name: String, item_cost: int, item_desc: String) -> Button:
@@ -273,3 +285,49 @@ func _on_visibility_changed():
GlobalVariables.isZoomDisabled = false
pass
#=========================面板通用处理=========================
#========================筛选功能============================
# 当前筛选类型
var current_filter_type: String = "全部"
#显示全部,既全部显示(默认)
func _on_all_filter_pressed() -> void:
current_filter_type = "全部"
update_item_store_ui()
Toast.show("显示全部道具", Color.GREEN, 2.0, 1.0)
#筛选宠物类型道具
func _on_pet_filter_pressed() -> void:
current_filter_type = "宠物道具"
update_item_store_ui()
Toast.show("筛选宠物道具", Color.GREEN, 2.0, 1.0)
#筛选作物类型道具
func _on_crop_filter_pressed() -> void:
current_filter_type = "作物道具"
update_item_store_ui()
Toast.show("筛选作物道具", Color.GREEN, 2.0, 1.0)
#筛选农场类型道具
func _on_farm_filter_pressed() -> void:
current_filter_type = "农场道具"
update_item_store_ui()
Toast.show("筛选农场道具", Color.GREEN, 2.0, 1.0)
# 检查道具是否符合当前筛选条件
func _is_item_match_filter(item_name: String) -> bool:
# 如果是显示全部直接返回true
if current_filter_type == "全部":
return true
# 检查道具配置中的类型
if item_config.has(item_name):
var item_info = item_config[item_name]
var item_type = item_info.get("类型", "")
return item_type == current_filter_type
# 如果没有配置信息,默认不显示
return false
#========================筛选功能============================

View File

@@ -283,6 +283,8 @@ func _on_refresh_button_pressed() -> void:
func _on_visibility_changed():
if visible:
GlobalVariables.isZoomDisabled = true
# 面板显示时请求同步最新的背包数据
tcp_network_manager_panel.send_sync_bag_data_request()
# 面板显示时自动刷新数据
update_pet_bag_ui()
pass

View File

@@ -0,0 +1 @@
extends Panel

View File

@@ -0,0 +1 @@
uid://dvaah0n1ia1a3

View File

@@ -487,6 +487,8 @@ func _on_quit_button_pressed():
func _on_visibility_changed():
if visible:
GlobalVariables.isZoomDisabled = true
# 面板显示时请求同步最新的背包数据
tcp_network_manager_panel.send_sync_bag_data_request()
# 面板显示时自动刷新数据
update_player_bag_ui()
pass

View File

@@ -0,0 +1,72 @@
extends Panel
# 预添加常用的面板
@onready var main_game = get_node("/root/main")
@onready var tcp_network_manager_panel: Panel = $'../TCPNetworkManagerPanel'
func _ready() -> void:
self.hide()
visibility_changed.connect(_on_visibility_changed)
pass
func _on_quit_button_pressed() -> void:
self.hide()
pass
#访问花卉农场QQ520
func _on_flower_farm_button_pressed() -> void:
_visit_special_farm("520", "花卉农场")
#访问杂交农场QQ666
func _on_hybrid_farm_button_pressed() -> void:
_visit_special_farm("666", "杂交农场")
#访问幸运农场QQ888
func _on_lucky_farm_button_pressed() -> void:
_visit_special_farm("888", "幸运农场")
#访问稻谷农场QQ111
func _on_rice_farm_button_pressed() -> void:
_visit_special_farm("111", "稻谷农场")
#访问小麦农场QQ222
func _on_wheat_farm_button_pressed() -> void:
_visit_special_farm("222", "小麦农场")
#访问水果农场QQ333
func _on_fruit_farm_button_pressed() -> void:
_visit_special_farm("333", "水果农场")
# 访问特殊农场的通用函数
func _visit_special_farm(farm_qq: String, farm_name: String) -> void:
# 访问农场后取消禁用相机功能,否则无法恢复
GlobalVariables.isZoomDisabled = false
# 检查网络连接
if not tcp_network_manager_panel or not tcp_network_manager_panel.is_connected_to_server():
Toast.show("未连接服务器,无法访问" + farm_name, Color.RED)
return
# 检查是否尝试访问自己
if main_game and main_game.user_name == farm_qq:
Toast.show("不能访问自己的农场", Color.ORANGE)
return
# 发送访问特殊农场请求
if tcp_network_manager_panel and tcp_network_manager_panel.has_method("sendVisitPlayer"):
var success = tcp_network_manager_panel.sendVisitPlayer(farm_qq)
if success:
Toast.show("正在访问" + farm_name + "...", Color.YELLOW)
# 隐藏面板
self.hide()
else:
Toast.show("发送访问请求失败", Color.RED)
else:
Toast.show("网络管理器不可用", Color.RED)
# 面板显示与隐藏切换处理
func _on_visibility_changed():
if visible:
GlobalVariables.isZoomDisabled = true
else:
GlobalVariables.isZoomDisabled = false

View File

@@ -0,0 +1 @@
uid://btm2je8pg7rgk

View File

@@ -82,6 +82,12 @@ func _on_sell_num_changed(new_text: String):
if char.is_valid_int():
filtered_text += char
# 检查是否超过最大值并自动修正
if not filtered_text.is_empty():
var quantity = filtered_text.to_int()
if quantity > current_max_count:
filtered_text = str(current_max_count)
if filtered_text != new_text:
sell_num_input.text = filtered_text
sell_num_input.caret_column = filtered_text.length()
@@ -97,6 +103,12 @@ func _on_sell_price_changed(new_text: String):
if char.is_valid_int():
filtered_text += char
# 检查是否超过最大值并自动修正
if not filtered_text.is_empty():
var price = filtered_text.to_int()
if price > 999999999:
filtered_text = "999999999"
if filtered_text != new_text:
sell_price_input.text = filtered_text
sell_price_input.caret_column = filtered_text.length()
@@ -144,7 +156,9 @@ func get_sell_quantity() -> int:
return 1
var quantity = text.to_int()
return max(1, quantity) # 至少出售1个
quantity = max(1, quantity) # 至少出售1个
quantity = min(quantity, current_max_count) # 不超过最大值
return quantity
# 获取出售价格
func get_sell_price() -> int:
@@ -153,7 +167,9 @@ func get_sell_price() -> int:
return current_suggested_price
var price = text.to_int()
return max(1, price) # 至少1元
price = max(1, price) # 至少1元
price = min(price, 999999999) # 不超过最大值
return price
# 确认添加按钮处理
func _on_sure_button_pressed():

View File

@@ -11,6 +11,7 @@ var current_item_name: String = ""
var current_item_cost: int = 0
var current_item_desc: String = ""
var current_buy_type: String = "" # "seed" 或 "item"
var max_stock: int = 999999999 # 最大库存限制,默认无限制
# 回调函数,用于处理确认购买
var confirm_callback: Callable
@@ -41,13 +42,14 @@ func _on_visibility_changed():
pass
# 显示批量购买弹窗
func show_buy_popup(item_name: String, item_cost: int, item_desc: String, buy_type: String, on_confirm: Callable, on_cancel: Callable = Callable()):
func show_buy_popup(item_name: String, item_cost: int, item_desc: String, buy_type: String, on_confirm: Callable, on_cancel: Callable = Callable(), stock_limit: int = 999999999):
current_item_name = item_name
current_item_cost = item_cost
current_item_desc = item_desc
current_buy_type = buy_type
confirm_callback = on_confirm
cancel_callback = on_cancel
max_stock = stock_limit
# 设置弹窗内容
if buy_type == "seed":
@@ -55,10 +57,15 @@ func show_buy_popup(item_name: String, item_cost: int, item_desc: String, buy_ty
else:
title.text = "批量购买道具"
# 添加库存信息到内容中
var stock_info = ""
if stock_limit < 999999999:
stock_info = "\n当前库存: " + str(stock_limit) + ""
contents.text = str(
"商品名称: " + item_name + "\n" +
"单价: " + str(item_cost) + "\n" +
"描述: " + item_desc + "\n\n" +
"描述: " + item_desc + stock_info + "\n\n" +
"请输入购买数量:"
)
@@ -77,6 +84,14 @@ func _on_buy_num_changed(new_text: String):
if char.is_valid_int():
filtered_text += char
# 检查是否超过库存限制并自动修正
if not filtered_text.is_empty():
var quantity = filtered_text.to_int()
if quantity > max_stock:
filtered_text = str(max_stock)
elif quantity > 999999999:
filtered_text = "999999999"
if filtered_text != new_text:
buy_num_edit.text = filtered_text
buy_num_edit.caret_column = filtered_text.length()
@@ -118,6 +133,11 @@ func _on_sure_button_pressed():
_show_error("购买数量必须大于0")
return
# 检查是否超过库存限制
if quantity > max_stock:
_show_error("购买数量超过库存限制!最大可购买: " + str(max_stock))
return
# 调用确认回调函数
if confirm_callback.is_valid():
confirm_callback.call(current_item_name, current_item_cost, quantity, current_buy_type)

View File

@@ -78,6 +78,12 @@ func _on_sell_num_changed(new_text: String):
if char.is_valid_int():
filtered_text += char
# 检查是否超过最大值并自动修正
if not filtered_text.is_empty():
var quantity = filtered_text.to_int()
if quantity > current_max_count:
filtered_text = str(current_max_count)
if filtered_text != new_text:
sell_num_edit.text = filtered_text
sell_num_edit.caret_column = filtered_text.length()
@@ -94,7 +100,7 @@ func _update_total_income():
var quantity_status = ""
if quantity > current_max_count:
quantity_status = " (超出库存!)"
#quantity = current_max_count
var income_info = "\n出售数量: " + str(quantity) + "" + quantity_status + "\n总收入: " + str(total_income) + ""
# 更新内容显示
@@ -115,7 +121,9 @@ func get_sell_quantity() -> int:
return 1
var quantity = text.to_int()
return max(1, quantity) # 至少出售1个
quantity = max(1, quantity) # 至少出售1个
quantity = min(quantity, current_max_count) # 不超过最大值
return quantity
# 确认出售按钮处理
func _on_sure_button_pressed():
@@ -126,6 +134,7 @@ func _on_sure_button_pressed():
return
if quantity > current_max_count:
#quantity = current_max_count
_show_error("出售数量不能超过库存数量(" + str(current_max_count) + ")")
return
@@ -151,4 +160,4 @@ func _show_error(message: String):
if has_node("/root/Toast"):
get_node("/root/Toast").show(message, Color.RED, 2.0, 1.0)
else:
print("批量出售弹窗错误: " + message)
print("批量出售弹窗错误: " + message)

View File

@@ -32,6 +32,10 @@ class ConsoleCommandsAPI:
"lsplayer": self.cmd_list_players, # 列出所有玩家
"playerinfo": self.cmd_player_info, # 查看玩家信息
"resetland": self.cmd_reset_land, # 重置玩家土地
"repasswd": self.cmd_reset_password, # 重置玩家密码
"rename": self.cmd_rename_player, # 重命名玩家昵称
"refarmname": self.cmd_rename_farm, # 重命名农场名称
"ban": self.cmd_ban_player, # 踢出玩家
"weather": self.cmd_weather, # 设置天气
"help": self.cmd_help, # 显示帮助信息
"stop": self.cmd_stop, # 停止服务器
@@ -392,6 +396,175 @@ class ConsoleCommandsAPI:
else:
print(" 当前无在线客户端")
def cmd_reset_password(self, args: List[str]):
"""重置玩家密码命令: /repasswd QQ号"""
if len(args) != 1:
print("❌ 用法: /repasswd <QQ号>")
return
qq_number = args[0]
# 加载玩家数据
player_data = self.server.load_player_data(qq_number)
if not player_data:
print(f"❌ 玩家 {qq_number} 不存在")
return
# 重置密码为123456
old_password = player_data.get("玩家密码", "未设置")
player_data["玩家密码"] = "123456"
# 保存数据
success = self.server.save_player_data(qq_number, player_data)
if success:
print(f"✅ 已重置玩家 {qq_number} 的密码")
print(f" 新密码: 123456")
else:
print(f"❌ 重置玩家 {qq_number} 密码失败")
def cmd_rename_player(self, args: List[str]):
"""重命名玩家昵称命令: /rename QQ号 新昵称"""
if len(args) != 2:
print("❌ 用法: /rename <QQ号> <新昵称>")
return
qq_number, new_nickname = args
# 加载玩家数据
player_data = self.server.load_player_data(qq_number)
if not player_data:
print(f"❌ 玩家 {qq_number} 不存在")
return
# 修改玩家昵称
old_nickname = player_data.get("玩家昵称", "未设置")
player_data["玩家昵称"] = new_nickname
# 保存数据
success = self.server.save_player_data(qq_number, player_data)
if success:
print(f"✅ 已重命名玩家 {qq_number} 的昵称")
print(f" 原昵称: {old_nickname} → 新昵称: {new_nickname}")
else:
print(f"❌ 重命名玩家 {qq_number} 昵称失败")
def cmd_rename_farm(self, args: List[str]):
"""重命名农场名称命令: /refarmname QQ号 新农场名称"""
if len(args) != 2:
print("❌ 用法: /refarmname <QQ号> <新农场名称>")
return
qq_number, new_farm_name = args
# 加载玩家数据
player_data = self.server.load_player_data(qq_number)
if not player_data:
print(f"❌ 玩家 {qq_number} 不存在")
return
# 修改农场名称
old_farm_name = player_data.get("农场名称", "未设置")
player_data["农场名称"] = new_farm_name
# 保存数据
success = self.server.save_player_data(qq_number, player_data)
if success:
print(f"✅ 已重命名玩家 {qq_number} 的农场名称")
print(f" 原农场名: {old_farm_name} → 新农场名: {new_farm_name}")
else:
print(f"❌ 重命名玩家 {qq_number} 农场名称失败")
def cmd_ban_player(self, args: List[str]):
"""踢出玩家命令: /ban QQ号 [时长] [原因]"""
if len(args) < 1 or len(args) > 3:
print("❌ 用法: /ban <QQ号> [时长(秒)] [原因]")
print(" 时长默认为0秒(立即可重新登录),原因默认为'您已被管理员踢出服务器'")
return
qq_number = args[0]
ban_duration = 0 # 默认0秒
ban_reason = "您已被管理员踢出服务器" # 默认原因
# 解析时长参数
if len(args) >= 2:
try:
ban_duration = int(args[1])
if ban_duration < 0:
print("❌ 踢出时长不能为负数")
return
except ValueError:
print("❌ 踢出时长必须是整数(秒)")
return
# 解析原因参数
if len(args) >= 3:
ban_reason = args[2]
# 加载玩家数据
player_data = self.server.load_player_data(qq_number)
if not player_data:
print(f"❌ 玩家 {qq_number} 不存在")
return
# 计算禁止登录时间
current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
ban_end_time = ""
if ban_duration > 0:
from datetime import timedelta
end_datetime = datetime.now() + timedelta(seconds=ban_duration)
ban_end_time = end_datetime.strftime("%Y-%m-%d %H:%M:%S")
# 设置禁用系统
if "禁用系统" not in player_data:
player_data["禁用系统"] = {}
player_data["禁用系统"] = {
"是否被禁止登录": ban_duration > 0,
"禁止登录原因": ban_reason,
"禁止登录开始": current_time,
"禁止登录截止": ban_end_time
}
# 保存数据
success = self.server.save_player_data(qq_number, player_data)
if not success:
print(f"❌ 保存玩家 {qq_number} 数据失败")
return
# 如果玩家在线,强制下线
kicked_online = False
if hasattr(self.server, 'user_data'):
for client_id, user_info in self.server.user_data.items():
if user_info.get("username") == qq_number and user_info.get("logged_in", False):
# 发送踢出消息
kick_message = {
"type": "kick_notification",
"reason": ban_reason,
"duration": ban_duration
}
self.server.send_data(client_id, kick_message)
# 断开连接
if hasattr(self.server, 'disconnect_client'):
self.server.disconnect_client(client_id)
kicked_online = True
break
# 输出结果
if ban_duration > 0:
print(f"✅ 已踢出玩家 {qq_number},禁止登录 {ban_duration}")
print(f" 踢出原因: {ban_reason}")
print(f" 禁止登录至: {ban_end_time}")
else:
print(f"✅ 已踢出玩家 {qq_number},可立即重新登录")
print(f" 踢出原因: {ban_reason}")
if kicked_online:
print(f" 玩家已在线,已强制下线")
else:
print(f" 玩家当前不在线")
def cmd_help(self, args: List[str]):
"""显示帮助信息"""
print("🌱 萌芽农场服务器控制台命令帮助")
@@ -404,6 +577,10 @@ class ConsoleCommandsAPI:
print(" /lsplayer - 列出所有已注册玩家")
print(" /playerinfo <QQ号> - 查看玩家详细信息")
print(" /resetland <QQ号> - 重置玩家土地状态")
print(" /repasswd <QQ号> - 重置玩家密码为123456")
print(" /rename <QQ号> <新昵称> - 重命名玩家昵称")
print(" /refarmname <QQ号> <新农场名> - 重命名农场名称")
print(" /ban <QQ号> [时长] [原因] - 踢出玩家(时长秒,原因可选)")
print("")
print("游戏控制命令:")
print(" /weather <类型> - 控制全服天气")

View File

@@ -31,6 +31,7 @@ class QQMailAPI:
self.smtp_server = 'smtp.qq.com'
self.smtp_port = 465 # SSL端口
# 发送纯文本邮件
def send_text_email(self, receiver_email, subject, content, cc_emails=None):
"""
发送纯文本邮件
@@ -65,6 +66,7 @@ class QQMailAPI:
print(f"邮件发送失败:{str(e)}")
return False
# 发送HTML格式邮件可带附件
def send_html_email(self, receiver_email, subject, html_content, cc_emails=None, attachments=None):
"""
发送HTML格式邮件可带附件
@@ -115,6 +117,8 @@ class QQMailAPI:
return False
class EmailVerification:
#生成指定长度的随机验证码
@staticmethod
def generate_verification_code(length=6):
"""
@@ -130,6 +134,7 @@ class EmailVerification:
chars = string.ascii_uppercase + string.digits
return ''.join(random.choice(chars) for _ in range(length))
#发送验证码邮件到QQ邮箱
@staticmethod
def send_verification_email(qq_number, verification_code, email_type="register"):
"""
@@ -192,6 +197,7 @@ class EmailVerification:
except Exception as e:
return False, f"发送验证码失败: {str(e)}"
#保存验证码到MongoDB优先或缓存文件备用
@staticmethod
def save_verification_code(qq_number, verification_code, expiry_time=300, code_type="register"):
"""
@@ -266,6 +272,7 @@ class EmailVerification:
print(f"保存验证码失败: {str(e)}")
return False
#验证用户输入的验证码优先使用MongoDB
@staticmethod
def verify_code(qq_number, input_code, code_type="register"):
"""
@@ -366,6 +373,7 @@ class EmailVerification:
print(f"[验证码系统-JSON] QQ {qq_number} 验证失败: 验证码不匹配")
return False, "验证码错误"
#清理过期的验证码和已使用的验证码优先使用MongoDB
@staticmethod
def clean_expired_codes():
"""
@@ -435,6 +443,7 @@ class EmailVerification:
except Exception as e:
print(f"清理验证码失败: {str(e)}")
#获取验证码状态优先使用MongoDB
@staticmethod
def get_verification_status(qq_number):
"""

View File

@@ -14,6 +14,30 @@ from datetime import datetime, timedelta
from bson import ObjectId
class SMYMongoDBAPI:
# ===================== 配置系统常量 =====================
#游戏配置JSON文档id
CONFIG_IDS = {
"daily_checkin": "687cce278e77ba00a7414ba2",#每日签到配置
"lucky_draw": "687cd52e8e77ba00a7414ba3",#幸运抽奖配置
"new_player": "687cdbd78e77ba00a7414ba4",#新玩家配置
"wisdom_tree": "687cdfbe8e77ba00a7414ba5",#智慧树配置
"online_gift": "687ce7678e77ba00a7414ba6",#在线礼包配置
"scare_crow": "687cea258e77ba00a7414ba8",# 稻草人系统配置
"item": "687cf17c8e77ba00a7414baa",# 道具系统配置
"pet": "687cf59b8e77ba00a7414bab",# 宠物系统配置
"stamina": "687cefba8e77ba00a7414ba9",# 体力值系统配置
"crop_data": "687cfb3d8e77ba00a7414bac",# 作物系统配置
"initial_player_data": "687e2f3f8e77ba00a7414bb0",# 初始玩家数据配置
"verification_codes": "687e35078e77ba00a7414bb1",# 验证码配置
"game_tips": "687e40008e77ba00a7414bb2",# 游戏小提示配置
}
# ===================== 配置系统常量 =====================
#初始化MongoDB API
def __init__(self, environment: str = "test"):
"""
初始化MongoDB API
@@ -51,6 +75,7 @@ class SMYMongoDBAPI:
# 连接数据库
self.connect()
# 连接到MongoDB数据库
def connect(self) -> bool:
"""
连接到MongoDB数据库
@@ -93,6 +118,7 @@ class SMYMongoDBAPI:
self.connected = False
return False
# 断开数据库连接
def disconnect(self):
"""断开数据库连接"""
if self.client:
@@ -100,10 +126,12 @@ class SMYMongoDBAPI:
self.connected = False
self.logger.info("已断开MongoDB连接")
# 检查数据库连接状态
def is_connected(self) -> bool:
"""检查是否已连接到数据库"""
return self.connected and self.client is not None
# 获取集合对象
def get_collection(self, collection_name: str):
"""
获取集合对象
@@ -120,6 +148,7 @@ class SMYMongoDBAPI:
# ========================= 游戏配置管理 =========================
# 获取游戏配置通过ObjectId
def _get_config_by_id(self, object_id: str, config_name: str) -> Optional[Dict[str, Any]]:
"""
通用方法根据ObjectId获取配置
@@ -139,11 +168,13 @@ class SMYMongoDBAPI:
result = collection.find_one({"_id": oid})
if result:
# 移除MongoDB的_id字段updated_at字段
# 移除MongoDB的_id字段updated_at字段和config_type字段
if "_id" in result:
del result["_id"]
if "updated_at" in result:
del result["updated_at"]
if "config_type" in result:
del result["config_type"]
self.logger.info(f"成功获取{config_name}")
return result
@@ -155,6 +186,7 @@ class SMYMongoDBAPI:
self.logger.error(f"获取{config_name}失败: {e}")
return None
# 更新游戏配置通过ObjectId
def _update_config_by_id(self, object_id: str, config_data: Dict[str, Any], config_name: str) -> bool:
"""
通用方法根据ObjectId更新配置
@@ -179,10 +211,14 @@ class SMYMongoDBAPI:
**config_data
}
result = collection.replace_one({"_id": oid}, update_data)
# 使用upsert=True来创建或更新文档
result = collection.replace_one({"_id": oid}, update_data, upsert=True)
if result.acknowledged and result.matched_count > 0:
self.logger.info(f"成功更新{config_name}")
if result.acknowledged:
if result.matched_count > 0:
self.logger.info(f"成功更新{config_name}")
elif result.upserted_id:
self.logger.info(f"成功创建{config_name}")
return True
else:
self.logger.error(f"更新{config_name}失败")
@@ -192,6 +228,7 @@ class SMYMongoDBAPI:
self.logger.error(f"更新{config_name}异常: {e}")
return False
# 获取游戏配置通过config_type
def get_game_config(self, config_type: str) -> Optional[Dict[str, Any]]:
"""
获取游戏配置通过config_type
@@ -225,6 +262,8 @@ class SMYMongoDBAPI:
except Exception as e:
self.logger.error(f"获取游戏配置失败 [{config_type}]: {e}")
return None
# 更新游戏配置通过config_type
def set_game_config(self, config_type: str, config_data: Dict[str, Any]) -> bool:
"""
设置游戏配置
@@ -260,23 +299,10 @@ class SMYMongoDBAPI:
except Exception as e:
self.logger.error(f"设置游戏配置异常 [{config_type}]: {e}")
return False
# ========================= 游戏配置管理 =========================
# ===================== 配置系统常量 =====================
CONFIG_IDS = {
"daily_checkin": "687cce278e77ba00a7414ba2",
"lucky_draw": "687cd52e8e77ba00a7414ba3",
"new_player": "687cdbd78e77ba00a7414ba4",
"wisdom_tree": "687cdfbe8e77ba00a7414ba5",
"online_gift": "687ce7678e77ba00a7414ba6",
"scare_crow": "687cea258e77ba00a7414ba8",
"item": "687cf17c8e77ba00a7414baa",
"pet": "687cf59b8e77ba00a7414bab",
"stamina": "687cefba8e77ba00a7414ba9",
"crop_data": "687cfb3d8e77ba00a7414bac",
"initial_player_data": "687e2f3f8e77ba00a7414bb0",
"verification_codes": "687e35078e77ba00a7414bb1"
}
#=====================每日签到系统======================
def get_daily_checkin_config(self) -> Optional[Dict[str, Any]]:
@@ -399,6 +425,18 @@ class SMYMongoDBAPI:
#=====================初始玩家数据模板系统======================
#=====================游戏小提示系统======================
def get_game_tips_config(self) -> Optional[Dict[str, Any]]:
"""获取游戏小提示配置"""
return self._get_config_by_id(self.CONFIG_IDS["game_tips"], "游戏小提示配置")
def update_game_tips_config(self, config_data: Dict[str, Any]) -> bool:
"""更新游戏小提示配置"""
return self._update_config_by_id(self.CONFIG_IDS["game_tips"], config_data, "游戏小提示配置")
#=====================游戏小提示系统======================
#批量更新离线玩家的作物生长(优化版本,支持完整的加速效果计算)
def batch_update_offline_players_crops(self, growth_multiplier: float = 1.0, exclude_online_players: List[str] = None) -> int:
"""
批量更新离线玩家的作物生长(优化版本,支持完整的加速效果计算)
@@ -531,6 +569,7 @@ class SMYMongoDBAPI:
self.logger.error(f"批量更新离线玩家作物失败: {e}")
return 0
#检查玩家是否在新玩家奖励期内注册后3天内享受10倍生长速度
def _is_new_player_bonus_active(self, register_time_str: str) -> bool:
"""
检查玩家是否在新玩家奖励期内注册后3天内享受10倍生长速度
@@ -562,13 +601,10 @@ class SMYMongoDBAPI:
except ValueError as e:
self.logger.warning(f"解析注册时间格式错误: {register_time_str}, 错误: {str(e)}")
return False
# 注意get_offline_players_with_crops 方法已被移除
# 现在使用优化的 batch_update_offline_players_crops 方法直接在 MongoDB 中处理查询和更新
#=====================玩家数据管理======================
# ========================= 验证码系统 =========================
# 保存验证码到MongoDB
def save_verification_code(self, qq_number: str, verification_code: str,
expiry_time: int = 300, code_type: str = "register") -> bool:
"""
@@ -617,8 +653,8 @@ class SMYMongoDBAPI:
self.logger.error(f"保存验证码异常 [QQ {qq_number}]: {e}")
return False
def verify_verification_code(self, qq_number: str, input_code: str,
code_type: str = "register") -> tuple[bool, str]:
#验证用户输入的验证码
def verify_verification_code(self, qq_number: str, input_code: str, code_type: str = "register") -> tuple[bool, str]:
"""
验证用户输入的验证码
@@ -671,6 +707,7 @@ class SMYMongoDBAPI:
self.logger.error(f"验证验证码异常 [QQ {qq_number}]: {e}")
return False, "验证码验证失败"
#清理过期的验证码和已使用的验证码
def clean_expired_verification_codes(self) -> int:
"""
清理过期的验证码和已使用的验证码
@@ -708,10 +745,12 @@ class SMYMongoDBAPI:
self.logger.error(f"清理验证码异常: {e}")
return 0
#=====================验证码系统======================
# ========================= 验证码系统 =========================
# ========================= 通用数据库操作 =========================
#========================玩家数据管理==========================
#获取玩家数据
def get_player_data(self, account_id: str) -> Optional[Dict[str, Any]]:
"""获取玩家数据
@@ -746,6 +785,7 @@ class SMYMongoDBAPI:
self.logger.error(f"获取玩家数据失败 [{account_id}]: {e}")
return None
#保存玩家数据
def save_player_data(self, account_id: str, player_data: Dict[str, Any]) -> bool:
"""保存玩家数据
@@ -780,6 +820,7 @@ class SMYMongoDBAPI:
self.logger.error(f"保存玩家数据异常 [{account_id}]: {e}")
return False
#删除玩家数据
def delete_player_data(self, account_id: str) -> bool:
"""删除玩家数据
@@ -806,6 +847,7 @@ class SMYMongoDBAPI:
self.logger.error(f"删除玩家数据异常 [{account_id}]: {e}")
return False
#获取所有玩家的基本信息
def get_all_players_basic_info(self, projection: Dict[str, int] = None) -> List[Dict[str, Any]]:
"""获取所有玩家的基本信息(优化版本,用于排行榜等)
@@ -848,6 +890,7 @@ class SMYMongoDBAPI:
self.logger.error(f"获取玩家基本信息失败: {e}")
return []
#根据条件获取玩家数据
def get_players_by_condition(self, condition: Dict[str, Any],
projection: Dict[str, int] = None,
limit: int = 0) -> List[Dict[str, Any]]:
@@ -886,6 +929,7 @@ class SMYMongoDBAPI:
self.logger.error(f"根据条件获取玩家数据失败: {e}")
return []
#获取长时间离线的玩家
def get_offline_players(self, offline_days: int = 3) -> List[Dict[str, Any]]:
"""获取长时间离线的玩家(用于杂草生长等)
@@ -931,6 +975,7 @@ class SMYMongoDBAPI:
self.logger.error(f"获取离线玩家失败: {e}")
return []
#检查玩家是否离线超过指定天数
def _is_player_offline_by_time(self, last_login_str: str, offline_days: int) -> bool:
"""检查玩家是否离线超过指定天数"""
try:
@@ -949,6 +994,7 @@ class SMYMongoDBAPI:
except Exception:
return False
#递归转换数据中的datetime对象为字符串
def _convert_datetime_to_string(self, data: Any) -> Any:
"""
递归转换数据中的datetime对象为字符串
@@ -970,6 +1016,7 @@ class SMYMongoDBAPI:
else:
return data
#统计玩家总数
def count_total_players(self) -> int:
"""统计玩家总数
@@ -987,6 +1034,7 @@ class SMYMongoDBAPI:
self.logger.error(f"统计玩家总数失败: {e}")
return 0
#更新玩家的特定字段
def update_player_field(self, account_id: str, field_updates: Dict[str, Any]) -> bool:
"""更新玩家的特定字段
@@ -1019,153 +1067,11 @@ class SMYMongoDBAPI:
except Exception as e:
self.logger.error(f"更新玩家字段异常 [{account_id}]: {e}")
return False
#=====================玩家数据管理======================
#========================玩家数据管理==========================
# ========================= 验证码系统 =========================
def save_verification_code(self, qq_number: str, verification_code: str,
expiry_time: int = 300, code_type: str = "register") -> bool:
"""
保存验证码到MongoDB
Args:
qq_number: QQ号
verification_code: 验证码
expiry_time: 过期时间默认5分钟
code_type: 验证码类型,"register""reset_password"
Returns:
bool: 保存成功返回True否则返回False
"""
try:
import time
from datetime import datetime, timedelta
collection = self.get_collection("verification_codes")
# 计算过期时间
expire_at = datetime.now() + timedelta(seconds=expiry_time)
# 验证码文档
verification_doc = {
"qq_number": qq_number,
"code": verification_code,
"code_type": code_type,
"created_at": datetime.now(),
"expire_at": expire_at,
"used": False
}
# 使用upsert更新或插入覆盖同一QQ号的旧验证码
query = {"qq_number": qq_number, "code_type": code_type}
result = collection.replace_one(query, verification_doc, upsert=True)
if result.acknowledged:
self.logger.info(f"成功保存验证码: QQ {qq_number}, 类型 {code_type}")
return True
else:
self.logger.error(f"保存验证码失败: QQ {qq_number}")
return False
except Exception as e:
self.logger.error(f"保存验证码异常 [QQ {qq_number}]: {e}")
return False
def verify_verification_code(self, qq_number: str, input_code: str,
code_type: str = "register") -> tuple:
"""
验证用户输入的验证码
Args:
qq_number: QQ号
input_code: 用户输入的验证码
code_type: 验证码类型,"register""reset_password"
Returns:
tuple: (验证成功, 消息)
"""
try:
from datetime import datetime
collection = self.get_collection("verification_codes")
# 查找验证码
query = {"qq_number": qq_number, "code_type": code_type}
code_doc = collection.find_one(query)
if not code_doc:
return False, "验证码不存在,请重新获取"
# 检查是否已使用
if code_doc.get("used", False):
return False, "验证码已使用,请重新获取"
# 检查是否过期
if datetime.now() > code_doc.get("expire_at", datetime.now()):
return False, "验证码已过期,请重新获取"
# 验证码码
if input_code.upper() != code_doc.get("code", "").upper():
return False, "验证码错误,请重新输入"
# 标记为已使用
update_result = collection.update_one(
query,
{"$set": {"used": True, "used_at": datetime.now()}}
)
if update_result.acknowledged:
self.logger.info(f"验证码验证成功: QQ {qq_number}, 类型 {code_type}")
return True, "验证码验证成功"
else:
self.logger.error(f"标记验证码已使用失败: QQ {qq_number}")
return False, "验证码验证失败"
except Exception as e:
self.logger.error(f"验证验证码异常 [QQ {qq_number}]: {e}")
return False, "验证码验证失败"
def clean_expired_verification_codes(self) -> int:
"""
清理过期的验证码和已使用的验证码
Returns:
int: 清理的验证码数量
"""
try:
from datetime import datetime, timedelta
collection = self.get_collection("verification_codes")
current_time = datetime.now()
one_hour_ago = current_time - timedelta(hours=1)
# 删除条件:过期的验证码 或 已使用超过1小时的验证码
delete_query = {
"$or": [
{"expire_at": {"$lt": current_time}}, # 过期的
{"used": True, "used_at": {"$lt": one_hour_ago}} # 已使用超过1小时的
]
}
result = collection.delete_many(delete_query)
if result.acknowledged:
deleted_count = result.deleted_count
self.logger.info(f"清理验证码完成: 删除了 {deleted_count} 个验证码")
return deleted_count
else:
self.logger.error("清理验证码失败")
return 0
except Exception as e:
self.logger.error(f"清理验证码异常: {e}")
return 0
#=====================验证码系统======================
# ========================= 通用数据库操作 =========================
#插入文档
def insert_document(self, collection_name: str, document: Dict[str, Any]) -> Optional[str]:
"""
插入文档
@@ -1191,6 +1097,7 @@ class SMYMongoDBAPI:
self.logger.error(f"插入文档失败 [{collection_name}]: {e}")
return None
#查找文档
def find_documents(self, collection_name: str, query: Dict[str, Any] = None,
limit: int = 0) -> List[Dict[str, Any]]:
"""
@@ -1220,6 +1127,9 @@ class SMYMongoDBAPI:
for doc in documents:
if "_id" in doc:
doc["_id"] = str(doc["_id"])
# 如果是gameconfig集合移除config_type字段以防止客户端报错
if collection_name == "gameconfig" and "config_type" in doc:
del doc["config_type"]
# 转换datetime对象为字符串
documents = [self._convert_datetime_to_string(doc) for doc in documents]
@@ -1230,6 +1140,7 @@ class SMYMongoDBAPI:
self.logger.error(f"查找文档失败 [{collection_name}]: {e}")
return []
#更新文档
def update_document(self, collection_name: str, query: Dict[str, Any],
update: Dict[str, Any]) -> bool:
"""
@@ -1253,6 +1164,7 @@ class SMYMongoDBAPI:
self.logger.error(f"更新文档失败 [{collection_name}]: {e}")
return False
#删除文档
def delete_document(self, collection_name: str, query: Dict[str, Any]) -> bool:
"""
删除文档
@@ -1273,9 +1185,12 @@ class SMYMongoDBAPI:
except Exception as e:
self.logger.error(f"删除文档失败 [{collection_name}]: {e}")
return False
# ========================= 通用数据库操作 =========================
# ========================= 聊天消息管理 =========================
#保存聊天消息到MongoDB按天存储
def save_chat_message(self, username: str, player_name: str, content: str) -> bool:
"""
保存聊天消息到MongoDB按天存储
@@ -1341,6 +1256,7 @@ class SMYMongoDBAPI:
self.logger.error(f"保存聊天消息异常: {e}")
return False
#获取聊天历史消息从按天存储的chat集合
def get_chat_history(self, days: int = 3, limit: int = 500) -> List[Dict[str, Any]]:
"""
获取聊天历史消息从按天存储的chat集合
@@ -1399,6 +1315,7 @@ class SMYMongoDBAPI:
self.logger.error(f"获取聊天历史失败: {e}")
return []
#获取最新的聊天消息从按天存储的chat集合
def get_latest_chat_message(self) -> Optional[Dict[str, Any]]:
"""
获取最新的聊天消息从按天存储的chat集合
@@ -1439,6 +1356,7 @@ class SMYMongoDBAPI:
self.logger.error(f"获取最新聊天消息失败: {e}")
return None
#删除旧的聊天消息从按天存储的chat集合
def clean_old_chat_messages(self, keep_days: int = 30) -> int:
"""
清理旧的聊天消息从按天存储的chat集合

507
Server/SpecialFarm.py Normal file
View File

@@ -0,0 +1,507 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
特殊农场管理系统
作者: AI Assistant
功能: 管理特殊农场的自动种植和维护
"""
import time
import random
import logging
from datetime import datetime
from SMYMongoDBAPI import SMYMongoDBAPI
from bson import ObjectId
#杂交农场666-种植杂交树1杂交树2-每天0点种植
#花卉农场520-随机种植各种花卉-星期一,星期三,星期五,星期日零点种植
#瓜果农场333-随机种植各种瓜果-星期二,星期四,星期六零点种植
#小麦谷222-全屏种植小麦-每天0点种植
#稻香111-全屏种植稻谷-每天0点种植
#幸运农场888-随机种植1-80个幸运草和幸运花-星期一零点种植
class SpecialFarmManager:
#初始化特殊农场管理器
def __init__(self, environment=None):
"""
初始化特殊农场管理器
Args:
environment: 环境类型,"test""production"如果为None则自动检测
"""
# 如果没有指定环境使用与TCPGameServer相同的环境检测逻辑
if environment is None:
import os
if os.path.exists('/.dockerenv') or os.environ.get('PRODUCTION', '').lower() == 'true':
environment = "production"
else:
environment = "test"
self.environment = environment
self.mongo_api = SMYMongoDBAPI(environment)
# 设置日志
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('special_farm.log', encoding='utf-8'),
logging.StreamHandler()
]
)
self.logger = logging.getLogger(__name__)
# 特殊农场配置
self.special_farms = {
"杂交农场": {
"object_id": "689b4b9286cf953f2f4e56ee",
"crops": ["杂交树1", "杂交树2"],
"description": "专门种植杂交树的特殊农场"
},
"花卉农场": {
"object_id": "689bec6286cf953f2f4e56f1",
"crops": ["郁金香", "牵牛花", "百合花", "栀子花", "玫瑰花", "向日葵", "藏红花", "幸运花"],
"description": "盛产各种美丽花卉的特殊农场",
"plant_type": "random_flowers" # 标记为随机花卉种植类型
},
"瓜果农场": {
"object_id": "689bf73886cf953f2f4e56fa",
"crops": ["西瓜", "南瓜", "哈密瓜", "葫芦", "黄瓜", "龙果", "菠萝", "芒果"],
"description": "盛产各种瓜果的农场",
"plant_type": "random_fruits" # 标记为随机瓜果种植类型
},
"小麦谷": {
"object_id": "689bf9a886cf953f2f4e56fd",
"crops": ["小麦"],
"description": "盛产小麦的农场",
"plant_type": "single_wheat" # 标记为单一小麦种植类型
},
"稻香": {
"object_id": "689bf9ac86cf953f2f4e56fe",
"crops": ["稻谷"],
"description": "盛产稻谷的农场",
"plant_type": "single_rice" # 标记为单一稻谷种植类型
},
"幸运农场": {
"object_id": "689c027886cf953f2f4e56ff",
"crops": ["幸运草", "幸运花"],
"description": "盛产幸运草和幸运花的农场",
"plant_type": "random_lucky" # 标记为随机幸运植物种植类型
}
}
self.logger.info(f"特殊农场管理器初始化完成 - 环境: {environment}")
#获取作物系统数据
def get_crop_data(self):
"""
获取作物配置数据
Returns:
dict: 作物配置数据
"""
try:
crop_config = self.mongo_api.get_crop_data_config()
if crop_config:
# 移除MongoDB相关字段
if "_id" in crop_config:
del crop_config["_id"]
if "config_type" in crop_config:
del crop_config["config_type"]
if "updated_at" in crop_config:
del crop_config["updated_at"]
return crop_config
else:
self.logger.error("无法获取作物配置数据")
return {}
except Exception as e:
self.logger.error(f"获取作物配置数据时出错: {str(e)}")
return {}
#通过文档ID获取农场数据
def get_player_data_by_object_id(self, object_id):
"""
通过ObjectId获取玩家数据
Args:
object_id: MongoDB文档ID
Returns:
dict: 玩家数据如果未找到返回None
"""
try:
collection = self.mongo_api.get_collection("playerdata")
oid = ObjectId(object_id)
player_data = collection.find_one({"_id": oid})
if player_data:
self.logger.info(f"成功获取玩家数据: {player_data.get('玩家昵称', 'Unknown')}")
return player_data
else:
self.logger.warning(f"未找到ObjectId为 {object_id} 的玩家数据")
return None
except Exception as e:
self.logger.error(f"获取玩家数据时出错: {str(e)}")
return None
#通过文档ID保存农场数据
def save_player_data_by_object_id(self, object_id, player_data):
"""
通过ObjectId保存玩家数据
Args:
object_id: MongoDB文档ID
player_data: 玩家数据
Returns:
bool: 是否保存成功
"""
try:
collection = self.mongo_api.get_collection("playerdata")
oid = ObjectId(object_id)
# 更新最后登录时间
player_data["最后登录时间"] = datetime.now().strftime("%Y年%m月%d%H时%M分%S秒")
result = collection.replace_one({"_id": oid}, player_data)
if result.acknowledged and result.matched_count > 0:
self.logger.info(f"成功保存玩家数据: {player_data.get('玩家昵称', 'Unknown')}")
return True
else:
self.logger.error(f"保存玩家数据失败: ObjectId {object_id}")
return False
except Exception as e:
self.logger.error(f"保存玩家数据时出错: {str(e)}")
return False
#在指定农场种植作物
def plant_crops_in_farm(self, farm_name):
"""
为指定特殊农场种植作物
Args:
farm_name: 农场名称
Returns:
bool: 是否种植成功
"""
if farm_name not in self.special_farms:
self.logger.error(f"未知的特殊农场: {farm_name}")
return False
farm_config = self.special_farms[farm_name]
object_id = farm_config["object_id"]
available_crops = farm_config["crops"]
# 获取玩家数据
player_data = self.get_player_data_by_object_id(object_id)
if not player_data:
return False
# 获取作物配置
crop_data = self.get_crop_data()
if not crop_data:
self.logger.error("无法获取作物配置,跳过种植")
return False
# 检查作物是否存在
for crop_name in available_crops:
if crop_name not in crop_data:
self.logger.error(f"作物 {crop_name} 不存在于作物配置中")
return False
# 获取农场土地
farm_lands = player_data.get("农场土地", [])
if not farm_lands:
self.logger.error(f"农场 {farm_name} 没有土地数据")
return False
planted_count = 0
plant_type = farm_config.get("plant_type", "normal")
# 遍历所有土地,先开垦再种植作物
for i, land in enumerate(farm_lands):
# 根据农场类型选择作物
if plant_type == "random_flowers":
# 花卉农场:随机种植各种花卉,种满所有土地
crop_name = random.choice(available_crops)
should_plant = True # 100%种植率,种满所有土地
elif plant_type == "random_fruits":
# 瓜果农场:随机种植各种瓜果,种满所有土地
crop_name = random.choice(available_crops)
should_plant = True # 100%种植率,种满所有土地
elif plant_type == "single_wheat":
# 小麦谷:全屏种植小麦,种满所有土地
crop_name = "小麦"
should_plant = True # 100%种植率,种满所有土地
elif plant_type == "single_rice":
# 稻香:全屏种植稻谷,种满所有土地
crop_name = "稻谷"
should_plant = True # 100%种植率,种满所有土地
elif plant_type == "random_lucky":
# 幸运农场随机种植1-80个幸运草和幸运花
crop_name = random.choice(available_crops)
# 随机决定是否种植确保总数在1-80之间
target_plants = random.randint(1, min(80, len(farm_lands)))
should_plant = planted_count < target_plants
else:
# 普通农场:按原逻辑随机选择
crop_name = random.choice(available_crops)
should_plant = True
if should_plant:
crop_info = crop_data[crop_name]
# 更新土地数据(先开垦,再种植)
land.update({
"is_diged": True, # 确保土地已开垦
"is_planted": True,
"crop_type": crop_name,
"grow_time": 0, # 立即成熟
"max_grow_time": crop_info.get("生长时间", 21600),
"is_dead": False,
"已浇水": True,
"已施肥": True,
"土地等级": 0
})
# 清除施肥时间戳
if "施肥时间" in land:
del land["施肥时间"]
planted_count += 1
else:
# 留空的土地:只开垦不种植
land.update({
"is_diged": True,
"is_planted": False,
"crop_type": "",
"grow_time": 0,
"max_grow_time": 3,
"is_dead": False,
"已浇水": False,
"已施肥": False,
"土地等级": 0
})
# 清除施肥时间戳
if "施肥时间" in land:
del land["施肥时间"]
# 保存玩家数据
if self.save_player_data_by_object_id(object_id, player_data):
self.logger.info(f"成功为 {farm_name} 种植了 {planted_count} 块土地的作物")
return True
else:
self.logger.error(f"保存 {farm_name} 数据失败")
return False
#每日维护任务
def daily_maintenance(self):
"""
每日维护任务
"""
from datetime import datetime
self.logger.info("开始执行特殊农场维护任务...")
success_count = 0
total_farms = 0
current_time = datetime.now()
current_weekday = current_time.weekday() # 0=Monday, 1=Tuesday, ..., 6=Sunday
current_time_str = current_time.strftime("%Y-%m-%d %H:%M:%S")
for farm_name in self.special_farms.keys():
# 检查农场是否需要在今天维护
should_maintain = True
if farm_name == "瓜果农场":
# 瓜果农场只在星期二(1)、四(3)、六(5)维护
if current_weekday not in [1, 3, 5]:
should_maintain = False
self.logger.info(f"瓜果农场今日({['周一','周二','周三','周四','周五','周六','周日'][current_weekday]})不需要维护")
elif farm_name == "幸运农场":
# 幸运农场只在星期一(0)维护
if current_weekday != 0:
should_maintain = False
self.logger.info(f"幸运农场今日({['周一','周二','周三','周四','周五','周六','周日'][current_weekday]})不需要维护")
if should_maintain:
total_farms += 1
try:
if self.plant_crops_in_farm(farm_name):
success_count += 1
self.logger.info(f"农场 {farm_name} 维护完成")
# 更新维护时间记录
try:
farm_config = self.special_farms[farm_name]
object_id = farm_config["object_id"]
player_data = self.get_player_data_by_object_id(object_id)
if player_data:
player_data["特殊农场最后维护时间"] = current_time_str
self.save_player_data_by_object_id(object_id, player_data)
except Exception as record_error:
self.logger.error(f"更新 {farm_name} 维护时间记录失败: {str(record_error)}")
else:
self.logger.error(f"农场 {farm_name} 维护失败")
except Exception as e:
self.logger.error(f"维护农场 {farm_name} 时出错: {str(e)}")
self.logger.info(f"维护任务完成: {success_count}/{total_farms} 个农场维护成功")
#启动定时任务调度器(后台线程模式)
def start_scheduler(self):
"""
启动定时任务调度器(后台线程模式)
"""
import threading
self.logger.info("特殊农场定时任务调度器已启动")
self.logger.info("维护任务将在每天凌晨0点执行")
# 检查是否需要立即执行维护任务
self._check_and_run_initial_maintenance()
# 在后台线程中运行调度循环
def scheduler_loop():
last_maintenance_date = None
while True:
try:
now = datetime.now()
current_date = now.strftime("%Y-%m-%d")
# 检查是否到了零点且今天还没有执行过维护
if (now.hour == 0 and now.minute == 0 and
last_maintenance_date != current_date):
self.logger.info("零点维护时间到,开始执行维护任务...")
self.daily_maintenance()
last_maintenance_date = current_date
time.sleep(60) # 每分钟检查一次
except Exception as e:
self.logger.error(f"调度器运行时出错: {str(e)}")
time.sleep(60)
# 启动后台线程
scheduler_thread = threading.Thread(target=scheduler_loop, daemon=True)
scheduler_thread.start()
self.logger.info("特殊农场调度器已在后台线程启动")
#检查是否需要执行初始维护任务
def _check_and_run_initial_maintenance(self):
"""
检查是否需要执行初始维护任务
避免服务器重启时重复执行
"""
try:
from datetime import datetime, timedelta
# 检查今天是否已经执行过维护任务
current_time = datetime.now()
today = current_time.strftime("%Y-%m-%d")
current_weekday = current_time.weekday() # 0=Monday, 1=Tuesday, ..., 6=Sunday
# 获取特殊农场数据,检查最后维护时间
for farm_name, farm_config in self.special_farms.items():
object_id = farm_config["object_id"]
player_data = self.get_player_data_by_object_id(object_id)
# 检查农场是否需要在今天维护
should_maintain = True
if farm_name == "瓜果农场":
# 瓜果农场只在星期二(1)、四(3)、六(5)维护
if current_weekday not in [1, 3, 5]:
should_maintain = False
self.logger.info(f"瓜果农场今日({['周一','周二','周三','周四','周五','周六','周日'][current_weekday]})不需要维护")
elif farm_name == "幸运农场":
# 幸运农场只在星期一(0)维护
if current_weekday != 0:
should_maintain = False
self.logger.info(f"幸运农场今日({['周一','周二','周三','周四','周五','周六','周日'][current_weekday]})不需要维护")
if should_maintain and player_data:
last_maintenance = player_data.get("特殊农场最后维护时间", "")
# 如果今天还没有维护过,则执行维护
if not last_maintenance or not last_maintenance.startswith(today):
self.logger.info(f"检测到 {farm_name} 今日尚未维护,执行维护任务...")
if self.plant_crops_in_farm(farm_name):
# 更新维护时间记录
player_data["特殊农场最后维护时间"] = current_time.strftime("%Y-%m-%d %H:%M:%S")
self.save_player_data_by_object_id(object_id, player_data)
else:
self.logger.info(f"{farm_name} 今日已维护过,跳过初始维护")
except Exception as e:
self.logger.error(f"检查初始维护任务时出错: {str(e)}")
# 如果检查失败,执行一次维护作为备用
self.logger.info("执行备用维护任务...")
self.daily_maintenance()
#停止定时任务调度器
def stop_scheduler(self):
"""
停止定时任务调度器
"""
try:
# 设置停止标志(如果需要的话)
self.logger.info("特殊农场定时任务调度器已停止")
except Exception as e:
self.logger.error(f"停止定时任务调度器时出错: {str(e)}")
#手动执行维护任务
def manual_maintenance(self, farm_name=None):
"""
手动执行维护任务
Args:
farm_name: 指定农场名称如果为None则维护所有农场
"""
if farm_name:
if farm_name in self.special_farms:
self.logger.info(f"手动维护农场: {farm_name}")
return self.plant_crops_in_farm(farm_name)
else:
self.logger.error(f"未知的农场名称: {farm_name}")
return False
else:
self.logger.info("手动维护所有特殊农场")
self.daily_maintenance()
return True
def main():
"""
主函数
"""
import sys
# 检查命令行参数
environment = "production"
if len(sys.argv) > 1:
if sys.argv[1] in ["test", "production"]:
environment = sys.argv[1]
else:
print("使用方法: python SpecialFarm.py [test|production]")
sys.exit(1)
# 创建特殊农场管理器
manager = SpecialFarmManager(environment)
# 检查是否为手动模式
if len(sys.argv) > 2 and sys.argv[2] == "manual":
# 手动执行维护
farm_name = sys.argv[3] if len(sys.argv) > 3 else None
manager.manual_maintenance(farm_name)
else:
# 启动定时任务
manager.start_scheduler()
if __name__ == "__main__":
main()

View File

@@ -12,6 +12,8 @@ import random
from SMYMongoDBAPI import SMYMongoDBAPI #导入MongoDB数据库模块
from QQEmailSendAPI import EmailVerification#导入QQ邮箱发送模块
from ConsoleCommandsAPI import ConsoleCommandsAPI #导入控制台命令API模块
from SpecialFarm import SpecialFarmManager #导入特殊农场管理系统
from WSRemoteCmdApi import WSRemoteCmdApi #导入WebSocket远程命令API
"""
萌芽农场TCP游戏服务器
@@ -24,7 +26,7 @@ from ConsoleCommandsAPI import ConsoleCommandsAPI #导入控制台命令API模
server_host: str = "0.0.0.0"
server_port: int = 7070
buffer_size: int = 4096
server_version: str = "2.0.1"
server_version: str = "2.2.0"
class TCPGameServer(TCPServer):
@@ -65,6 +67,15 @@ class TCPGameServer(TCPServer):
self.log('INFO', f"萌芽农场TCP游戏服务器初始化完成 - 版本: {server_version}", 'SERVER')
# 清理配置缓存,确保使用最新的配置数据
self._clear_config_cache()
# 初始化特殊农场管理系统
self._init_special_farm_manager()
# 初始化WebSocket远程命令API
self._init_websocket_remote_api()
# 启动定时器
self.start_crop_growth_timer()
self.start_weed_growth_timer()
@@ -111,6 +122,47 @@ class TCPGameServer(TCPServer):
self.weed_growth_probability = 0.3 # 每个空地长杂草的概率30%
self.last_weed_check_time = time.time() # 上次检查杂草的时间
#初始化特殊农场管理系统
def _init_special_farm_manager(self):
"""初始化特殊农场管理系统"""
try:
# 使用自动环境检测,确保与游戏服务器环境一致
self.special_farm_manager = SpecialFarmManager()
# 启动特殊农场定时任务
self.special_farm_manager.start_scheduler()
self.log('INFO', f"特殊农场管理系统初始化完成 - 环境: {self.special_farm_manager.environment}", 'SERVER')
except Exception as e:
self.log('ERROR', f"特殊农场管理系统初始化失败: {str(e)}", 'SERVER')
self.special_farm_manager = None
#初始化WebSocket远程命令API
def _init_websocket_remote_api(self):
"""初始化WebSocket远程命令API服务器"""
try:
# 创建WebSocket远程命令API实例
ws_host = "0.0.0.0"
ws_port = 7071
auth_key = "mengya2024" # 可以从配置文件读取
self.ws_remote_api = WSRemoteCmdApi(
game_server=self,
host=ws_host,
port=ws_port,
auth_key=auth_key
)
# 启动WebSocket服务器
self.ws_remote_api.start_server()
self.log('INFO', f"WebSocket远程命令API初始化完成 - ws://{ws_host}:{ws_port}", 'SERVER')
except Exception as e:
self.log('ERROR', f"WebSocket远程命令API初始化失败: {str(e)}", 'SERVER')
self.ws_remote_api = None
#设置游戏服务器日志配置
def _setup_game_server_logging(self):
"""设置游戏服务器日志配置,禁用父类重复输出"""
@@ -230,6 +282,28 @@ class TCPGameServer(TCPServer):
self.offline_crop_timer = None
self.log('INFO', "离线作物更新定时器已停止", 'SERVER')
# 停止特殊农场管理系统
if hasattr(self, 'special_farm_manager') and self.special_farm_manager:
try:
# 停止特殊农场定时任务
self.special_farm_manager.stop_scheduler()
# 清理特殊农场管理器引用
self.special_farm_manager = None
self.log('INFO', "特殊农场管理系统已停止", 'SERVER')
except Exception as e:
self.log('ERROR', f"停止特殊农场管理系统时出错: {str(e)}", 'SERVER')
# 停止WebSocket远程命令API服务器
if hasattr(self, 'ws_remote_api') and self.ws_remote_api:
try:
self.ws_remote_api.stop_server()
self.ws_remote_api = None
self.log('INFO', "WebSocket远程命令API服务器已停止", 'SERVER')
except Exception as e:
self.log('ERROR', f"停止WebSocket远程命令API服务器时出错: {str(e)}", 'SERVER')
# 显示服务器统计信息
stats = self.get_server_stats()
self.log('INFO', f"服务器统计 - 在线玩家: {stats['online_players']}, 总连接: {stats['total_connections']}", 'SERVER')
@@ -252,14 +326,6 @@ class TCPGameServer(TCPServer):
self._update_player_logout_time(client_id, username)
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:
# 清理偷菜免被发现计数器
@@ -267,8 +333,20 @@ class TCPGameServer(TCPServer):
del self.user_data[client_id]
self.log('INFO', f"用户 {username} 已离开游戏", 'SERVER')
super()._remove_client(client_id)
# 先调用父类方法移除客户端,避免递归调用
super()._remove_client(client_id)
# 在客户端已移除后再广播用户离开消息,避免向已断开的客户端发送消息
self.broadcast({
"type": "user_left",
"user_id": client_id,
"timestamp": time.time(),
"remaining_users": len(self.clients)
})
else:
# 如果客户端不在列表中,直接调用父类方法
super()._remove_client(client_id)
#==========================客户端连接管理==========================
@@ -364,6 +442,12 @@ class TCPGameServer(TCPServer):
return player_data, username, None
#加载作物配置数据(优化版本)
def _clear_config_cache(self):
"""清理配置缓存,强制重新加载"""
self.crop_data_cache = None
self.crop_data_cache_time = 0
self.log('INFO', "配置缓存已清理", 'SERVER')
def _load_crop_data(self):
"""加载作物配置数据从MongoDB带缓存优化"""
current_time = time.time()
@@ -468,20 +552,34 @@ class TCPGameServer(TCPServer):
self.log('WARNING', 'MongoDB未配置或不可用无法更新离线玩家作物', 'SERVER')
return
# 获取当前在线玩家列表
online_players = []
# 获取需要排除的玩家列表(在线玩家 + 被访问的玩家)
exclude_players = []
# 添加在线玩家
for client_id, user_info in self.user_data.items():
if user_info.get("logged_in", False) and user_info.get("username"):
online_players.append(user_info["username"])
exclude_players.append(user_info["username"])
# 直接调用优化后的批量更新方法,传入在线玩家列表进行排除
# 添加被访问的玩家(避免访问模式下的重复更新)
visited_players = set()
for client_id, user_info in self.user_data.items():
if (user_info.get("logged_in", False) and
user_info.get("visiting_mode", False) and
user_info.get("visiting_target")):
visited_players.add(user_info["visiting_target"])
# 将被访问的玩家也加入排除列表
exclude_players.extend(list(visited_players))
# 直接调用优化后的批量更新方法,传入排除玩家列表
# 离线更新间隔为60秒所以每次更新应该增长60秒
updated_count = self.mongo_api.batch_update_offline_players_crops(
growth_multiplier=1.0,
exclude_online_players=online_players
growth_multiplier=60.0,
exclude_online_players=exclude_players
)
if updated_count > 0:
self.log('INFO', f"成功更新了 {updated_count} 个离线玩家的作物生长", 'SERVER')
self.log('INFO', f"成功更新了 {updated_count} 个离线玩家的作物生长(排除了 {len(exclude_players)} 个在线/被访问玩家)", 'SERVER')
else:
self.log('DEBUG', "没有离线玩家的作物需要更新", 'SERVER')
@@ -496,26 +594,37 @@ class TCPGameServer(TCPServer):
#作物生长更新系统
def update_crops_growth(self):
"""更新所有玩家的作物生长"""
# 更新在线玩家的作物
# 收集所有需要更新的玩家(在线玩家 + 被访问的玩家)
players_to_update = set()
# 添加在线玩家
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
if user_info.get("logged_in", False) and user_info.get("username"):
players_to_update.add(user_info.get("username"))
# 添加被访问的玩家(即使他们不在线)
for client_id, user_info in self.user_data.items():
if user_info.get("logged_in", False) and user_info.get("visiting_mode", False):
visiting_target = user_info.get("visiting_target", "")
if visiting_target:
players_to_update.add(visiting_target)
# 更新所有需要更新的玩家的作物
for username in players_to_update:
try:
player_data = self.load_player_data(username)
if not player_data:
continue
if self.update_player_crops(player_data, username):
self.save_player_data(username, player_data)
self._push_crop_update_to_player(username, player_data)
# 确保数据保存成功后才推送更新
if self.save_player_data(username, player_data):
self._push_crop_update_to_player(username, player_data)
else:
self.log('ERROR', f"保存玩家 {username} 数据失败,跳过推送更新", 'SERVER')
except Exception as e:
self.log('ERROR', f"更新在线玩家 {username} 作物时出错: {str(e)}", 'SERVER')
self.log('ERROR', f"更新玩家 {username} 作物时出错: {str(e)}", 'SERVER')
#更新单个玩家的作物
def update_player_crops(self, player_data, account_id):
@@ -593,6 +702,9 @@ class TCPGameServer(TCPServer):
self._send_visiting_update(client_id, visiting_target)
else:
self._send_normal_update(client_id, player_data)
# 检查是否有其他玩家正在访问这个玩家的农场
self._push_update_to_visitors(account_id, player_data)
#根据用户名查找客户端ID
def _find_client_by_username(self, username):
@@ -629,6 +741,31 @@ class TCPGameServer(TCPServer):
"is_visiting": False
}
self.send_data(client_id, update_message)
#向正在访问某个玩家农场的其他玩家推送更新
def _push_update_to_visitors(self, target_username, target_player_data):
"""向正在访问某个玩家农场的其他玩家推送更新"""
for visitor_client_id, visitor_info in self.user_data.items():
if not visitor_info.get("logged_in", False):
continue
visiting_mode = visitor_info.get("visiting_mode", False)
visiting_target = visitor_info.get("visiting_target", "")
# 如果这个玩家正在访问目标玩家的农场,发送更新
if visiting_mode and visiting_target == target_username:
target_client_id = self._find_client_by_username(target_username)
update_message = {
"type": "crop_update",
"农场土地": target_player_data.get("农场土地", []),
"timestamp": time.time(),
"is_visiting": True,
"visited_player": target_username,
"target_online": target_client_id is not None
}
self.send_data(visitor_client_id, update_message)
self.log('DEBUG', f"向访问者 {visitor_info.get('username', 'unknown')} 推送 {target_username} 的农场更新", 'SERVER')
#================================作物系统管理=========================================
@@ -709,6 +846,8 @@ class TCPGameServer(TCPServer):
return self._handle_item_config_request(client_id)
elif message_type == "request_pet_config":#请求宠物配置数据
return self._handle_pet_config_request(client_id)
elif message_type == "request_game_tips_config":#请求游戏小提示配置数据
return self._handle_game_tips_config_request(client_id)
elif message_type == "visit_player":#拜访其他玩家农场
return self._handle_visit_player_request(client_id, message)
elif message_type == "return_my_farm":#返回我的农场
@@ -769,7 +908,15 @@ class TCPGameServer(TCPServer):
return self._handle_pet_battle_result(client_id, message)
elif message_type == "today_divination":#今日占卜
return self._handle_today_divination(client_id, message)
elif message_type == "give_money":#送金币
return self._handle_give_money_request(client_id, message)
elif message_type == "sync_bag_data":#同步背包数据
return self._handle_sync_bag_data(client_id, message)
#---------------------------------------------------------------------------
# 管理员操作相关
elif message_type == "kick_player":#踢出玩家
return self._handle_kick_player(client_id, message)
elif message_type == "message":#处理聊天消息(暂未实现)
return self._handle_chat_message(client_id, message)
@@ -833,6 +980,60 @@ class TCPGameServer(TCPServer):
player_data = self.load_player_data(username)
if player_data and player_data.get("玩家密码") == password:
# 检查禁用系统
ban_system = player_data.get("禁用系统", {})
is_banned = ban_system.get("是否被禁止登录", False)
if is_banned:
# 检查禁止登录是否已过期
ban_end_time = ban_system.get("禁止登录截止", "")
if ban_end_time:
try:
end_datetime = datetime.datetime.strptime(ban_end_time, "%Y-%m-%d %H:%M:%S")
current_datetime = datetime.datetime.now()
if current_datetime >= end_datetime:
# 禁止登录已过期,解除禁止
player_data["禁用系统"] = {
"是否被禁止登录": False,
"禁止登录原因": "",
"禁止登录开始": "",
"禁止登录截止": ""
}
self.save_player_data(username, player_data)
self.log('INFO', f"用户 {username} 禁止登录已过期,自动解除", 'SERVER')
else:
# 仍在禁止期内
ban_reason = ban_system.get("禁止登录原因", "您已被管理员禁止登录")
self.log('WARNING', f"用户 {username} 登录失败: 账号被禁止登录", 'SERVER')
response = {
"type": "login_response",
"status": "banned",
"message": ban_reason,
"ban_end_time": ban_end_time
}
return self.send_data(client_id, response)
except Exception as e:
self.log('ERROR', f"解析禁止登录时间出错: {e}", 'SERVER')
# 如果解析出错,仍然禁止登录
ban_reason = ban_system.get("禁止登录原因", "您已被管理员禁止登录")
response = {
"type": "login_response",
"status": "banned",
"message": ban_reason
}
return self.send_data(client_id, response)
else:
# 永久禁止或没有截止时间
ban_reason = ban_system.get("禁止登录原因", "您已被管理员禁止登录")
self.log('WARNING', f"用户 {username} 登录失败: 账号被永久禁止登录", 'SERVER')
response = {
"type": "login_response",
"status": "banned",
"message": ban_reason
}
return self.send_data(client_id, response)
# 登录成功
self.log('INFO', f"用户 {username} 登录成功", 'SERVER')
@@ -2441,6 +2642,25 @@ class TCPGameServer(TCPServer):
self.log('ERROR', f"从MongoDB加载宠物配置失败: {str(e)}", 'SERVER')
return {}
def _load_game_tips_config(self):
"""从MongoDB加载游戏小提示配置数据"""
try:
if not hasattr(self, 'mongo_api') or not self.mongo_api:
self.log('ERROR', 'MongoDB未配置或不可用无法加载游戏小提示配置数据', 'SERVER')
return {}
config = self.mongo_api.get_game_tips_config()
if config:
self.log('INFO', "成功从MongoDB加载游戏小提示配置", 'SERVER')
return config
else:
self.log('ERROR', "MongoDB中未找到游戏小提示配置", 'SERVER')
return {}
except Exception as e:
self.log('ERROR', f"从MongoDB加载游戏小提示配置失败: {str(e)}", 'SERVER')
return {}
# 将巡逻宠物ID转换为完整宠物数据
def _convert_patrol_pets_to_full_data(self, player_data):
"""将存储的巡逻宠物ID转换为完整的宠物数据"""
@@ -5228,8 +5448,27 @@ class TCPGameServer(TCPServer):
"success": False,
"message": "无法读取宠物配置数据"
})
#==========================道具配置数据处理==========================
#处理客户端请求游戏小提示配置数据
def _handle_game_tips_config_request(self, client_id):
"""处理客户端请求游戏小提示配置数据"""
game_tips_config = self._load_game_tips_config()
if game_tips_config:
self.log('INFO', f"向客户端 {client_id} 发送游戏小提示配置数据", 'SERVER')
return self.send_data(client_id, {
"type": "game_tips_config_response",
"success": True,
"game_tips_config": game_tips_config
})
else:
return self.send_data(client_id, {
"type": "game_tips_config_response",
"success": False,
"message": "无法读取游戏小提示配置数据"
})
#==========================升级土地处理==========================
@@ -6325,10 +6564,19 @@ class TCPGameServer(TCPServer):
"点赞数": target_player_data.get("点赞系统", {}).get("总点赞数", 0), # 添加点赞数
"最后登录时间": target_player_data.get("最后登录时间", "未知"),
"总游玩时间": target_player_data.get("总游玩时间", "0时0分0秒"),
"total_likes": target_player_data.get("total_likes", 0)
"total_likes": target_player_data.get("total_likes", 0),
"访问系统": target_player_data.get("访问系统", {
"总访问人数": 0,
"今日访问人数": 0,
"访问记录": {}
}) # 添加访问系统数据
}
current_username = self.user_data[client_id]["username"]
# 更新被访问玩家的访问系统数据
self._update_visit_system(target_username, current_username)
self.log('INFO', f"玩家 {current_username} 访问了玩家 {target_username} 的农场", 'SERVER')
# 记录玩家的访问状态
@@ -6344,6 +6592,229 @@ class TCPGameServer(TCPServer):
})
#==========================访问其他玩家农场处理==========================
#==========================访问系统处理==========================
def _update_visit_system(self, target_username, visitor_username):
"""更新被访问玩家的访问系统数据"""
try:
# 加载被访问玩家的数据
target_player_data = self.load_player_data(target_username)
if not target_player_data:
self.log('ERROR', f"无法加载被访问玩家 {target_username} 的数据", 'SERVER')
return
# 获取访问者的昵称
visitor_player_data = self.load_player_data(visitor_username)
visitor_nickname = visitor_player_data.get("玩家昵称", visitor_username) if visitor_player_data else visitor_username
# 初始化访问系统(如果不存在)
if "访问系统" not in target_player_data:
target_player_data["访问系统"] = {
"总访问人数": 0,
"今日访问人数": 0,
"访问记录": {}
}
visit_system = target_player_data["访问系统"]
# 获取今日日期
from datetime import datetime
today = datetime.now().strftime("%Y-%m-%d")
# 更新总访问人数
visit_system["总访问人数"] = visit_system.get("总访问人数", 0) + 1
# 检查是否需要重置今日访问人数(新的一天)
last_visit_date = visit_system.get("最后访问日期", "")
if last_visit_date != today:
visit_system["今日访问人数"] = 0
visit_system["最后访问日期"] = today
# 更新今日访问人数
visit_system["今日访问人数"] = visit_system.get("今日访问人数", 0) + 1
# 更新访问记录
if "访问记录" not in visit_system:
visit_system["访问记录"] = {}
if today not in visit_system["访问记录"]:
visit_system["访问记录"][today] = []
# 添加访问者昵称到今日访问记录(避免重复)
if visitor_nickname not in visit_system["访问记录"][today]:
visit_system["访问记录"][today].append(visitor_nickname)
# 保存更新后的数据
if self.save_player_data(target_username, target_player_data):
self.log('INFO', f"成功更新玩家 {target_username} 的访问系统数据,访问者: {visitor_nickname}", 'SERVER')
else:
self.log('ERROR', f"保存玩家 {target_username} 的访问系统数据失败", 'SERVER')
except Exception as e:
self.log('ERROR', f"更新访问系统数据时出错: {e}", 'SERVER')
def _reset_daily_visit_count(self):
"""重置所有玩家的今日访问人数(凌晨调用)"""
try:
# 获取所有玩家的基本信息
if hasattr(self, 'mongo_api') and self.mongo_api:
players_info = self.mongo_api.get_all_players_basic_info()
from datetime import datetime
today = datetime.now().strftime("%Y-%m-%d")
reset_count = 0
for player_info in players_info:
username = player_info.get("玩家账号")
if username:
player_data = self.load_player_data(username)
if player_data and "访问系统" in player_data:
visit_system = player_data["访问系统"]
last_visit_date = visit_system.get("最后访问日期", "")
# 如果不是今天,重置今日访问人数
if last_visit_date != today:
visit_system["今日访问人数"] = 0
visit_system["最后访问日期"] = today
if self.save_player_data(username, player_data):
reset_count += 1
self.log('INFO', f"成功重置了 {reset_count} 个玩家的今日访问人数", 'SERVER')
except Exception as e:
self.log('ERROR', f"重置今日访问人数时出错: {e}", 'SERVER')
def _handle_give_money_request(self, client_id, message):
"""处理送金币请求"""
try:
# 获取发送者信息
sender_info = self.user_data.get(client_id)
if not sender_info or not sender_info.get("logged_in", False):
self.send_data(client_id, {
"type": "give_money_response",
"success": False,
"message": "请先登录"
})
return
sender_username = sender_info.get("username")
target_username = message.get("target_username", "")
amount = message.get("amount", 0)
# 验证参数
if not target_username:
self.send_data(client_id, {
"type": "give_money_response",
"success": False,
"message": "目标玩家用户名不能为空"
})
return
if amount != 500:
self.send_data(client_id, {
"type": "give_money_response",
"success": False,
"message": "每次只能送500金币"
})
return
if sender_username == target_username:
self.send_data(client_id, {
"type": "give_money_response",
"success": False,
"message": "不能给自己送金币"
})
return
# 加载发送者数据
sender_data = self.load_player_data(sender_username)
if not sender_data:
self.send_data(client_id, {
"type": "give_money_response",
"success": False,
"message": "无法加载发送者数据"
})
return
# 检查发送者金币是否足够
sender_money = sender_data.get("钱币", 0)
if sender_money < amount:
self.send_data(client_id, {
"type": "give_money_response",
"success": False,
"message": f"您的金币不足,当前拥有{sender_money}金币"
})
return
# 加载接收者数据
target_data = self.load_player_data(target_username)
if not target_data:
self.send_data(client_id, {
"type": "give_money_response",
"success": False,
"message": "目标玩家不存在"
})
return
# 执行金币转移
sender_data["钱币"] = sender_money - amount
target_data["钱币"] = target_data.get("钱币", 0) + amount
# 记录送金币日志
from datetime import datetime
current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
log_message = f"[{current_time}] {sender_username} 送给 {target_username} {amount}金币"
self.log('INFO', log_message, 'GIVE_MONEY')
# 保存数据
if self.save_player_data(sender_username, sender_data) and self.save_player_data(target_username, target_data):
# 获取目标玩家昵称
target_nickname = target_data.get("玩家昵称", target_username)
# 发送成功响应
self.send_data(client_id, {
"type": "give_money_response",
"success": True,
"message": f"成功送给 {target_nickname} {amount}金币!",
"updated_data": {
"钱币": sender_data["钱币"]
},
"target_updated_data": {
"钱币": target_data["钱币"]
}
})
# 如果目标玩家在线,通知他们收到金币
target_client_id = None
for cid, user_info in self.user_data.items():
if user_info.get("username") == target_username and user_info.get("logged_in", False):
target_client_id = cid
break
if target_client_id:
sender_nickname = sender_data.get("玩家昵称", sender_username)
self.send_data(target_client_id, {
"type": "money_received_notification",
"sender_nickname": sender_nickname,
"amount": amount,
"new_money": target_data["钱币"]
})
else:
self.send_data(client_id, {
"type": "give_money_response",
"success": False,
"message": "数据保存失败,请重试"
})
except Exception as e:
self.log('ERROR', f"处理送金币请求失败: {str(e)}", 'GIVE_MONEY')
self.send_data(client_id, {
"type": "give_money_response",
"success": False,
"message": "服务器内部错误"
})
#==========================访问系统处理==========================
@@ -8232,6 +8703,63 @@ class TCPGameServer(TCPServer):
"success": False,
"message": message
})
#处理背包数据同步消息
def _handle_sync_bag_data(self, client_id, message):
"""处理背包数据同步请求"""
username = self.user_data.get(client_id, {}).get("username")
if not username:
return self.send_data(client_id, {
"type": "sync_bag_data_response",
"success": False,
"message": "用户未登录"
})
# 从数据库加载最新的玩家数据
player_data = self.load_player_data(username)
if not player_data:
return self.send_data(client_id, {
"type": "sync_bag_data_response",
"success": False,
"message": "玩家数据加载失败"
})
# 提取所有背包数据
bag_data = {
"道具背包": player_data.get("道具背包", []),
"宠物背包": player_data.get("宠物背包", []),
"种子仓库": player_data.get("种子仓库", []),
"作物仓库": player_data.get("作物仓库", [])
}
self.log('INFO', f"用户 {username} 请求同步背包数据", 'SERVER')
return self.send_data(client_id, {
"type": "sync_bag_data_response",
"success": True,
"message": "背包数据同步成功",
"bag_data": bag_data
})
def _handle_kick_player(self, client_id, message):
"""处理踢出玩家消息(服务器内部使用)"""
# 这个函数主要用于接收来自控制台命令的踢出消息
# 实际的踢出逻辑在 ConsoleCommandsAPI 中处理
reason = message.get("reason", "您已被管理员踢出服务器")
duration = message.get("duration", 0)
# 发送踢出通知给客户端
response = {
"type": "kick_notification",
"reason": reason,
"duration": duration,
"message": reason
}
self.log('INFO', f"向客户端 {client_id} 发送踢出通知: {reason}", 'SERVER')
return self.send_data(client_id, response)
# ================================账户设置处理方法================================
@@ -9914,6 +10442,7 @@ if __name__ == "__main__":
print("👋 感谢使用萌芽农场服务器!")
print("=" * 60)
sys.exit(0)
except Exception as e:
print(f"\n❌ 服务器启动失败: {str(e)}")
print("🔧 请检查配置并重试")

254
Server/WSRemoteCmdApi.py Normal file
View File

@@ -0,0 +1,254 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
WebSocket协议的服务器远程命令API
作者: AI Assistant
功能: 提供基于WebSocket的远程控制台命令执行功能
"""
import asyncio
import websockets
import json
import threading
import time
from typing import Dict, Any, Optional
from ConsoleCommandsAPI import ConsoleCommandsAPI
class WSRemoteCmdApi:
"""WebSocket远程命令API服务器"""
def __init__(self, game_server, host="0.0.0.0", port=7071, auth_key="mengya2024"):
"""
初始化WebSocket远程命令API服务器
Args:
game_server: 游戏服务器实例
host: WebSocket服务器监听地址
port: WebSocket服务器监听端口
auth_key: 认证密钥
"""
self.game_server = game_server
self.host = host
self.port = port
self.auth_key = auth_key
self.server = None
self.clients = {} # 存储已连接的客户端
self.console_api = ConsoleCommandsAPI(game_server)
self.running = False
async def register_client(self, websocket, path=None):
"""注册新的客户端连接"""
client_id = f"{websocket.remote_address[0]}:{websocket.remote_address[1]}_{int(time.time())}"
self.clients[client_id] = {
"websocket": websocket,
"authenticated": False,
"connect_time": time.time()
}
try:
# 发送欢迎消息
await self.send_message(websocket, {
"type": "welcome",
"message": "欢迎连接到萌芽农场远程控制台",
"server_version": getattr(self.game_server, 'server_version', '2.2.0'),
"require_auth": True
})
# 处理客户端消息
async for message in websocket:
await self.handle_message(client_id, message)
except websockets.exceptions.ConnectionClosed:
pass
except Exception as e:
print(f"❌ 客户端 {client_id} 连接处理出错: {str(e)}")
finally:
# 清理客户端连接
if client_id in self.clients:
del self.clients[client_id]
print(f"🔌 客户端 {client_id} 已断开连接")
async def handle_message(self, client_id: str, message: str):
"""处理客户端消息"""
try:
data = json.loads(message)
message_type = data.get("type", "")
if message_type == "auth":
await self.handle_auth(client_id, data)
elif message_type == "command":
await self.handle_command(client_id, data)
elif message_type == "ping":
await self.handle_ping(client_id, data)
else:
await self.send_error(client_id, f"未知消息类型: {message_type}")
except json.JSONDecodeError:
await self.send_error(client_id, "无效的JSON格式")
except Exception as e:
await self.send_error(client_id, f"处理消息时出错: {str(e)}")
async def handle_auth(self, client_id: str, data: Dict[str, Any]):
"""处理客户端认证"""
if client_id not in self.clients:
return
provided_key = data.get("auth_key", "")
if provided_key == self.auth_key:
self.clients[client_id]["authenticated"] = True
await self.send_message(self.clients[client_id]["websocket"], {
"type": "auth_result",
"success": True,
"message": "认证成功,欢迎使用远程控制台"
})
print(f"✅ 客户端 {client_id} 认证成功")
else:
await self.send_message(self.clients[client_id]["websocket"], {
"type": "auth_result",
"success": False,
"message": "认证失败,密钥错误"
})
print(f"❌ 客户端 {client_id} 认证失败")
async def handle_command(self, client_id: str, data: Dict[str, Any]):
"""处理控制台命令"""
if client_id not in self.clients:
return
# 检查是否已认证
if not self.clients[client_id]["authenticated"]:
await self.send_error(client_id, "请先进行认证")
return
command = data.get("command", "").strip()
if not command:
await self.send_error(client_id, "命令不能为空")
return
# 执行命令并捕获输出
try:
# 重定向标准输出来捕获命令执行结果
import io
import sys
old_stdout = sys.stdout
sys.stdout = captured_output = io.StringIO()
# 执行命令
success = self.console_api.process_command(command)
# 恢复标准输出
sys.stdout = old_stdout
output = captured_output.getvalue()
# 发送执行结果
await self.send_message(self.clients[client_id]["websocket"], {
"type": "command_result",
"command": command,
"success": success,
"output": output if output else ("命令执行成功" if success else "命令执行失败")
})
print(f"📝 客户端 {client_id} 执行命令: {command} - {'成功' if success else '失败'}")
except Exception as e:
await self.send_error(client_id, f"执行命令时出错: {str(e)}")
async def handle_ping(self, client_id: str, data: Dict[str, Any]):
"""处理ping请求"""
if client_id not in self.clients:
return
await self.send_message(self.clients[client_id]["websocket"], {
"type": "pong",
"timestamp": time.time()
})
async def send_message(self, websocket, data: Dict[str, Any]):
"""发送消息到客户端"""
try:
message = json.dumps(data, ensure_ascii=False)
await websocket.send(message)
except Exception as e:
print(f"❌ 发送消息失败: {str(e)}")
async def send_error(self, client_id: str, error_message: str):
"""发送错误消息到客户端"""
if client_id in self.clients:
await self.send_message(self.clients[client_id]["websocket"], {
"type": "error",
"message": error_message
})
def start_server(self):
"""启动WebSocket服务器"""
if self.running:
return
async def run_server_async():
try:
self.server = await websockets.serve(
self.register_client,
self.host,
self.port
)
self.running = True
print(f"🌐 WebSocket远程控制台服务器已启动: ws://{self.host}:{self.port}")
print(f"🔑 认证密钥: {self.auth_key}")
# 保持服务器运行
await self.server.wait_closed()
except Exception as e:
print(f"❌ WebSocket服务器启动失败: {str(e)}")
self.running = False
def run_server():
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
try:
loop.run_until_complete(run_server_async())
except Exception as e:
print(f"❌ WebSocket服务器线程异常: {str(e)}")
self.running = False
# 在新线程中运行WebSocket服务器
server_thread = threading.Thread(target=run_server, daemon=True)
server_thread.start()
def stop_server(self):
"""停止WebSocket服务器"""
if not self.running:
return
self.running = False
# 关闭所有客户端连接
for client_id, client_info in list(self.clients.items()):
try:
asyncio.create_task(client_info["websocket"].close())
except:
pass
self.clients.clear()
if self.server:
try:
self.server.close()
except:
pass
print("🌐 WebSocket远程控制台服务器已停止")
def get_status(self) -> Dict[str, Any]:
"""获取服务器状态"""
return {
"running": self.running,
"host": self.host,
"port": self.port,
"connected_clients": len(self.clients),
"authenticated_clients": len([c for c in self.clients.values() if c["authenticated"]])
}

Binary file not shown.

Binary file not shown.

1071
Server/crop_data_debug.json Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,85 @@
2025-08-15 13:15:48,010 [INFO] 服务器监控器启动
2025-08-15 13:15:48,010 [INFO] 正在启动服务器...
2025-08-15 13:15:48,406 [INFO] [SERVER] ============================================================
2025-08-15 13:15:48,420 [INFO] [SERVER] Traceback (most recent call last):
2025-08-15 13:15:48,420 [ERROR] 检测到严重错误: Traceback (most recent call last):
2025-08-15 13:15:48,422 [INFO] [SERVER] File "E:\Godot\Godot项目\比较完成的作品\萌芽农场\Server\TCPGameServer.py", line 10395, in <module>
2025-08-15 13:15:48,423 [INFO] [SERVER] print(f"\U0001f331 萌芽农场游戏服务器 v{server_version} \U0001f331")
2025-08-15 13:15:48,423 [INFO] [SERVER] ~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2025-08-15 13:15:48,423 [INFO] [SERVER] File "E:\ProgramLanguage\Python\python313\Lib\site-packages\colorama\ansitowin32.py", line 47, in write
2025-08-15 13:15:48,423 [INFO] [SERVER] self.__convertor.write(text)
2025-08-15 13:15:48,423 [INFO] [SERVER] ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
2025-08-15 13:15:48,423 [INFO] [SERVER] File "E:\ProgramLanguage\Python\python313\Lib\site-packages\colorama\ansitowin32.py", line 177, in write
2025-08-15 13:15:48,423 [INFO] [SERVER] self.write_and_convert(text)
2025-08-15 13:15:48,423 [INFO] [SERVER] ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
2025-08-15 13:15:48,424 [INFO] [SERVER] File "E:\ProgramLanguage\Python\python313\Lib\site-packages\colorama\ansitowin32.py", line 205, in write_and_convert
2025-08-15 13:15:48,424 [INFO] [SERVER] self.write_plain_text(text, cursor, len(text))
2025-08-15 13:15:48,424 [INFO] [SERVER] ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
2025-08-15 13:15:48,424 [INFO] [SERVER] File "E:\ProgramLanguage\Python\python313\Lib\site-packages\colorama\ansitowin32.py", line 210, in write_plain_text
2025-08-15 13:15:48,424 [INFO] [SERVER] self.wrapped.write(text[start:end])
2025-08-15 13:15:48,424 [INFO] [SERVER] ~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
2025-08-15 13:15:48,424 [INFO] [SERVER] UnicodeEncodeError: 'gbk' codec can't encode character '\U0001f331' in position 0: illegal multibyte sequence
2025-08-15 13:15:48,424 [INFO] [SERVER] During handling of the above exception, another exception occurred:
2025-08-15 13:15:48,424 [INFO] [SERVER] Traceback (most recent call last):
2025-08-15 13:15:48,424 [ERROR] 检测到严重错误: Traceback (most recent call last):
2025-08-15 13:15:48,424 [INFO] [SERVER] File "E:\Godot\Godot项目\比较完成的作品\萌芽农场\Server\TCPGameServer.py", line 10447, in <module>
2025-08-15 13:15:48,424 [INFO] [SERVER] print(f"\n\u274c 服务器启动失败: {str(e)}")
2025-08-15 13:15:48,424 [INFO] [SERVER] ~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2025-08-15 13:15:48,425 [INFO] [SERVER] File "E:\ProgramLanguage\Python\python313\Lib\site-packages\colorama\ansitowin32.py", line 47, in write
2025-08-15 13:15:48,425 [INFO] [SERVER] self.__convertor.write(text)
2025-08-15 13:15:48,425 [INFO] [SERVER] ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
2025-08-15 13:15:48,425 [INFO] [SERVER] File "E:\ProgramLanguage\Python\python313\Lib\site-packages\colorama\ansitowin32.py", line 177, in write
2025-08-15 13:15:48,425 [INFO] [SERVER] self.write_and_convert(text)
2025-08-15 13:15:48,425 [INFO] [SERVER] ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
2025-08-15 13:15:48,425 [INFO] [SERVER] File "E:\ProgramLanguage\Python\python313\Lib\site-packages\colorama\ansitowin32.py", line 205, in write_and_convert
2025-08-15 13:15:48,425 [INFO] [SERVER] self.write_plain_text(text, cursor, len(text))
2025-08-15 13:15:48,425 [INFO] [SERVER] ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
2025-08-15 13:15:48,425 [INFO] [SERVER] File "E:\ProgramLanguage\Python\python313\Lib\site-packages\colorama\ansitowin32.py", line 210, in write_plain_text
2025-08-15 13:15:48,425 [INFO] [SERVER] self.wrapped.write(text[start:end])
2025-08-15 13:15:48,425 [INFO] [SERVER] ~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
2025-08-15 13:15:48,425 [INFO] [SERVER] UnicodeEncodeError: 'gbk' codec can't encode character '\u274c' in position 2: illegal multibyte sequence
2025-08-15 13:15:53,015 [ERROR] 服务器启动失败
2025-08-15 13:15:53,015 [ERROR] 初始启动失败,退出监控
2025-08-15 13:17:34,183 [INFO] 服务器监控器启动
2025-08-15 13:17:34,183 [INFO] 正在启动服务器...
2025-08-15 13:17:34,623 [INFO] [SERVER] ============================================================
2025-08-15 13:17:34,623 [INFO] [SERVER] [ERROR] 服务器启动失败: 'gbk' codec can't encode character '\U0001f331' in position 0: illegal multibyte sequence
2025-08-15 13:17:34,628 [INFO] [SERVER] Traceback (most recent call last):
2025-08-15 13:17:34,628 [ERROR] 检测到严重错误: Traceback (most recent call last):
2025-08-15 13:17:34,628 [INFO] [SERVER] File "E:\Godot\Godot项目\比较完成的作品\萌芽农场\Server\TCPGameServer.py", line 10395, in <module>
2025-08-15 13:17:34,628 [INFO] [SERVER] print(f"\U0001f331 萌芽农场游戏服务器 v{server_version} \U0001f331")
2025-08-15 13:17:34,629 [INFO] [SERVER] ~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2025-08-15 13:17:34,629 [INFO] [SERVER] File "E:\ProgramLanguage\Python\python313\Lib\site-packages\colorama\ansitowin32.py", line 47, in write
2025-08-15 13:17:34,629 [INFO] [SERVER] self.__convertor.write(text)
2025-08-15 13:17:34,629 [INFO] [SERVER] ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
2025-08-15 13:17:34,629 [INFO] [SERVER] File "E:\ProgramLanguage\Python\python313\Lib\site-packages\colorama\ansitowin32.py", line 177, in write
2025-08-15 13:17:34,629 [INFO] [SERVER] self.write_and_convert(text)
2025-08-15 13:17:34,629 [INFO] [SERVER] ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
2025-08-15 13:17:34,630 [INFO] [SERVER] File "E:\ProgramLanguage\Python\python313\Lib\site-packages\colorama\ansitowin32.py", line 205, in write_and_convert
2025-08-15 13:17:34,630 [INFO] [SERVER] self.write_plain_text(text, cursor, len(text))
2025-08-15 13:17:34,630 [INFO] [SERVER] ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
2025-08-15 13:17:34,630 [INFO] [SERVER] File "E:\ProgramLanguage\Python\python313\Lib\site-packages\colorama\ansitowin32.py", line 210, in write_plain_text
2025-08-15 13:17:34,630 [INFO] [SERVER] self.wrapped.write(text[start:end])
2025-08-15 13:17:34,630 [INFO] [SERVER] ~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
2025-08-15 13:17:34,630 [INFO] [SERVER] UnicodeEncodeError: 'gbk' codec can't encode character '\U0001f331' in position 0: illegal multibyte sequence
2025-08-15 13:17:34,630 [INFO] [SERVER] During handling of the above exception, another exception occurred:
2025-08-15 13:17:34,630 [INFO] [SERVER] Traceback (most recent call last):
2025-08-15 13:17:34,631 [ERROR] 检测到严重错误: Traceback (most recent call last):
2025-08-15 13:17:34,631 [INFO] [SERVER] File "E:\Godot\Godot项目\比较完成的作品\萌芽农场\Server\TCPGameServer.py", line 10448, in <module>
2025-08-15 13:17:34,631 [INFO] [SERVER] print("\U0001f527 请检查配置并重试")
2025-08-15 13:17:34,631 [INFO] [SERVER] ~~~~~^^^^^^^^^^^^^^^^^^^^^^^
2025-08-15 13:17:34,631 [INFO] [SERVER] File "E:\ProgramLanguage\Python\python313\Lib\site-packages\colorama\ansitowin32.py", line 47, in write
2025-08-15 13:17:34,631 [INFO] [SERVER] self.__convertor.write(text)
2025-08-15 13:17:34,632 [INFO] [SERVER] ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
2025-08-15 13:17:34,632 [INFO] [SERVER] File "E:\ProgramLanguage\Python\python313\Lib\site-packages\colorama\ansitowin32.py", line 177, in write
2025-08-15 13:17:34,632 [INFO] [SERVER] self.write_and_convert(text)
2025-08-15 13:17:34,632 [INFO] [SERVER] ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
2025-08-15 13:17:34,632 [INFO] [SERVER] File "E:\ProgramLanguage\Python\python313\Lib\site-packages\colorama\ansitowin32.py", line 205, in write_and_convert
2025-08-15 13:17:34,632 [INFO] [SERVER] self.write_plain_text(text, cursor, len(text))
2025-08-15 13:17:34,632 [INFO] [SERVER] ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
2025-08-15 13:17:34,632 [INFO] [SERVER] File "E:\ProgramLanguage\Python\python313\Lib\site-packages\colorama\ansitowin32.py", line 210, in write_plain_text
2025-08-15 13:17:34,633 [INFO] [SERVER] self.wrapped.write(text[start:end])
2025-08-15 13:17:34,633 [INFO] [SERVER] ~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
2025-08-15 13:17:34,633 [INFO] [SERVER] UnicodeEncodeError: 'gbk' codec can't encode character '\U0001f527' in position 0: illegal multibyte sequence
2025-08-15 13:17:39,187 [ERROR] 服务器启动失败
2025-08-15 13:17:39,187 [ERROR] 初始启动失败,退出监控

View File

@@ -1,5 +1,7 @@
# Game Server Dependencies
colorama>=0.4.6 # For colored terminal output
pymongo>=4.6.0 # MongoDB driver for Python
schedule>=1.2.0 # Task scheduling for special farm management
websockets>=11.0.3 # WebSocket server for remote console API
# Email Requirements
# Standard library dependencies are not listed (socket, threading, json, etc.)

0
Server/special_farm.log Normal file
View File

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,22 @@
{
"切换模式":"顺序",//可选,顺序,随机,倒序
"切换速度":5,
"游戏小提示":
[
"按住wsad可以移动游戏画面",
"使用鼠标滚轮来缩放游戏画面",
"移动端双指缩放游戏画面",
"不要一上来就花光你的初始资金",
"钱币是目前游戏唯一货币",
"每隔一小时体力值+1",
"不要忘记领取你的新手礼包!",
"记得使用一键截图来分享你的农场",
"新注册用户可享受三天10倍速作物生长",
"偷别人菜时不要忘了给别人浇水哦",
"你能分得清小麦和稻谷吗",
"凌晨刷新体力值",
"面板左上角有刷新按钮,可以刷新面板",
"小心偷菜被巡逻宠物发现",
"访问特殊农场来获得一些特殊的作物"
]
}

View File

@@ -0,0 +1,84 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
游戏小提示配置数据导入脚本
将游戏小提示配置数据导入到MongoDB数据库中
"""
import sys
import os
# 添加当前目录到Python路径
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
from SMYMongoDBAPI import SMYMongoDBAPI
def import_game_tips_config():
"""导入游戏小提示配置数据到MongoDB"""
# 游戏小提示配置数据
game_tips_config = {
"切换模式": "顺序", # 可选:顺序,随机,倒序
"切换速度": 5,
"游戏小提示": [
"按住wsad可以移动游戏画面",
"使用鼠标滚轮来缩放游戏画面",
"移动端双指缩放游戏画面",
"不要一上来就花光你的初始资金",
"钱币是目前游戏唯一货币",
"每隔一小时体力值+1",
"不要忘记领取你的新手礼包!",
"记得使用一键截图来分享你的农场",
"新注册用户可享受三天10倍速作物生长",
"偷别人菜时不要忘了给别人浇水哦",
"你能分得清小麦和稻谷吗",
"凌晨刷新体力值",
"面板左上角有刷新按钮,可以刷新面板",
"小心偷菜被巡逻宠物发现",
"访问特殊农场来获得一些特殊的作物"
]
}
try:
# 创建MongoDB API实例
mongo_api = SMYMongoDBAPI()
# 连接到数据库
if not mongo_api.connect():
print("错误无法连接到MongoDB数据库")
return False
print("成功连接到MongoDB数据库")
# 更新游戏小提示配置
result = mongo_api.update_game_tips_config(game_tips_config)
if result:
print("成功导入游戏小提示配置数据到MongoDB")
print(f"配置内容:")
print(f" 切换模式: {game_tips_config['切换模式']}")
print(f" 切换速度: {game_tips_config['切换速度']}")
print(f" 游戏小提示数量: {len(game_tips_config['游戏小提示'])}")
return True
else:
print("错误:导入游戏小提示配置数据失败")
return False
except Exception as e:
print(f"导入过程中发生错误: {str(e)}")
return False
finally:
# 断开数据库连接
if 'mongo_api' in locals():
mongo_api.disconnect()
print("已断开MongoDB数据库连接")
if __name__ == "__main__":
print("开始导入游戏小提示配置数据...")
success = import_game_tips_config()
if success:
print("\n导入完成!")
else:
print("\n导入失败!")
sys.exit(1)

View File

@@ -0,0 +1,132 @@
{
"type": "item_config_response",
"success": true,
"item_config": {
"精准采集-镰刀": {
"花费": 100,
"描述": "可以在收获作物时必定掉落该作物的种子",
"类型": "作物道具",
"道具图片": "res://assets/道具图片/紫水晶镰刀.webp"
},
"时运-镰刀": {
"花费": 100,
"描述": "可以在收获作物时掉落更多的作物的收获物",
"类型": "作物道具",
"道具图片": "res://assets/道具图片/红宝石镰刀.webp"
},
"农家肥": {
"花费": 100,
"描述": "施肥道具可以在30分钟内2倍速作物生长",
"类型": "作物道具",
"道具图片": "res://assets/道具图片/农家肥.webp"
},
"金坷垃": {
"花费": 100,
"描述": "施肥道具可以在5分钟内5倍速作物的生长",
"类型": "作物道具",
"道具图片": "res://assets/道具图片/金坷垃2.webp"
},
"水壶": {
"花费": 100,
"描述": "(浇水道具)直接让作物生长进度+1%",
"类型": "作物道具",
"道具图片": "res://assets/道具图片/铁质洒水壶.webp"
},
"水桶": {
"花费": 100,
"描述": "(浇水道具)让作物生长进度+2%",
"类型": "作物道具",
"道具图片": "res://assets/道具图片/木质水桶2.webp"
},
"杀虫剂": {
"花费": 100,
"描述": "杀虫,暂时没什么用",
"类型": "作物道具",
"道具图片": "res://assets/道具图片/杀虫剂.webp"
},
"除草剂": {
"花费": 100,
"描述": "除草",
"类型": "作物道具",
"道具图片": "res://assets/道具图片/除草剂.webp"
},
"生长素": {
"花费": 100,
"描述": "时运可以10分钟内3倍速作物生长而且作物生长速度+3%",
"类型": "作物道具",
"道具图片": "res://assets/道具图片/生长素.webp"
},
"铲子": {
"花费": 100,
"描述": "铲除作物",
"类型": "作物道具",
"道具图片": "res://assets/道具图片/附魔铁铲.webp"
},
"不死图腾": {
"花费": 100,
"描述": "让宠物死亡复活一次",
"类型": "宠物道具",
"道具图片": "res://assets/道具图片/不死图腾.webp"
},
"荆棘护甲": {
"花费": 100,
"描述": "宠物收到伤害时反弹伤害给敌人",
"类型": "宠物道具",
"道具图片": "res://assets/道具图片/荆棘护甲.webp"
},
"狂暴药水": {
"花费": 100,
"描述": "宠物血量低于某个值,进入狂暴模式",
"类型": "宠物道具",
"道具图片": "res://assets/道具图片/狂暴药水.webp"
},
"援军令牌": {
"花费": 100,
"描述": "血量低于某个值,召唤一堆宠物仆从帮助你战斗",
"类型": "宠物道具",
"道具图片": "res://assets/道具图片/援军令牌.webp"
},
"金刚图腾": {
"花费": 100,
"描述": "更改宠物元素为金元素",
"类型": "宠物道具",
"道具图片": "res://assets/道具图片/金元素图腾.webp"
},
"灵木图腾": {
"花费": 100,
"描述": "更改宠物元素为木元素",
"类型": "宠物道具",
"道具图片": "res://assets/道具图片/木元素图腾.webp"
},
"潮汐图腾": {
"花费": 100,
"描述": "更改宠物元素为水元素",
"类型": "宠物道具",
"道具图片": "res://assets/道具图片/水元素图腾.webp"
},
"烈焰图腾": {
"花费": 100,
"描述": "更改宠物元素为火元素",
"类型": "宠物道具",
"道具图片": "res://assets/道具图片/火元素图腾.webp"
},
"敦岩图腾": {
"花费": 100,
"描述": "更改宠物元素为土元素",
"类型": "宠物道具",
"道具图片": "res://assets/道具图片/土元素图腾.webp"
},
"小额经验卡": {
"花费": 100,
"描述": "让玩家立即获得500经验值",
"类型": "农场道具",
"道具图片": "res://assets/道具图片/小额经验卡.webp"
},
"小额金币卡": {
"花费": 100,
"描述": "让玩家立即获得500金币",
"类型": "农场道具",
"道具图片": "res://assets/道具图片/小额金币卡.webp"
}
}
}

View File

@@ -0,0 +1,155 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
特殊农场系统性能监控脚本
用于监控特殊农场系统的资源使用情况
"""
import psutil
import time
import threading
from datetime import datetime
class SpecialFarmMonitor:
def __init__(self):
self.monitoring = False
self.monitor_thread = None
self.stats = {
'cpu_usage': [],
'memory_usage': [],
'thread_count': [],
'start_time': None
}
def start_monitoring(self, duration=60):
"""开始监控指定时间(秒)"""
if self.monitoring:
print("监控已在运行中")
return
self.monitoring = True
self.stats['start_time'] = datetime.now()
def monitor_loop():
print(f"开始监控特殊农场系统性能 - {self.stats['start_time']}")
print(f"监控时长: {duration}")
print("=" * 50)
start_time = time.time()
while self.monitoring and (time.time() - start_time) < duration:
try:
# 获取当前进程信息
process = psutil.Process()
# CPU使用率
cpu_percent = process.cpu_percent()
self.stats['cpu_usage'].append(cpu_percent)
# 内存使用情况
memory_info = process.memory_info()
memory_mb = memory_info.rss / 1024 / 1024
self.stats['memory_usage'].append(memory_mb)
# 线程数量
thread_count = process.num_threads()
self.stats['thread_count'].append(thread_count)
# 实时显示
elapsed = int(time.time() - start_time)
print(f"\r[{elapsed:3d}s] CPU: {cpu_percent:5.1f}% | 内存: {memory_mb:6.1f}MB | 线程: {thread_count:2d}", end="", flush=True)
time.sleep(1)
except Exception as e:
print(f"\n监控出错: {str(e)}")
break
self.monitoring = False
print("\n" + "=" * 50)
self._print_summary()
self.monitor_thread = threading.Thread(target=monitor_loop, daemon=True)
self.monitor_thread.start()
def stop_monitoring(self):
"""停止监控"""
self.monitoring = False
if self.monitor_thread:
self.monitor_thread.join(timeout=2)
def _print_summary(self):
"""打印监控摘要"""
if not self.stats['cpu_usage']:
print("没有收集到监控数据")
return
print("监控摘要:")
print(f"监控时间: {self.stats['start_time']} - {datetime.now()}")
print(f"数据点数: {len(self.stats['cpu_usage'])}")
# CPU统计
cpu_avg = sum(self.stats['cpu_usage']) / len(self.stats['cpu_usage'])
cpu_max = max(self.stats['cpu_usage'])
print(f"CPU使用率 - 平均: {cpu_avg:.1f}%, 最高: {cpu_max:.1f}%")
# 内存统计
mem_avg = sum(self.stats['memory_usage']) / len(self.stats['memory_usage'])
mem_max = max(self.stats['memory_usage'])
print(f"内存使用量 - 平均: {mem_avg:.1f}MB, 最高: {mem_max:.1f}MB")
# 线程统计
thread_avg = sum(self.stats['thread_count']) / len(self.stats['thread_count'])
thread_max = max(self.stats['thread_count'])
print(f"线程数量 - 平均: {thread_avg:.1f}, 最高: {thread_max}")
# 性能评估
print("\n性能评估:")
if cpu_avg < 1.0:
print("✓ CPU使用率很低性能良好")
elif cpu_avg < 5.0:
print("✓ CPU使用率正常")
else:
print("⚠ CPU使用率较高可能需要优化")
if mem_avg < 50:
print("✓ 内存使用量很低")
elif mem_avg < 100:
print("✓ 内存使用量正常")
else:
print("⚠ 内存使用量较高")
if thread_max <= 10:
print("✓ 线程数量合理")
else:
print("⚠ 线程数量较多,注意资源管理")
def main():
"""主函数"""
print("特殊农场系统性能监控工具")
print("使用说明:")
print("1. 启动游戏服务器")
print("2. 运行此监控脚本")
print("3. 观察特殊农场系统的资源使用情况")
print()
monitor = SpecialFarmMonitor()
try:
# 监控60秒
monitor.start_monitoring(60)
# 等待监控完成
while monitor.monitoring:
time.sleep(1)
print("\n监控完成")
except KeyboardInterrupt:
print("\n用户中断监控")
monitor.stop_monitoring()
except Exception as e:
print(f"\n监控过程中出错: {str(e)}")
monitor.stop_monitoring()
if __name__ == "__main__":
main()

View File

View File

@@ -0,0 +1,147 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
测试发送给客户端的数据结构
模拟服务器发送给客户端的数据格式
"""
import json
from SMYMongoDBAPI import SMYMongoDBAPI
def test_client_data_format():
"""测试发送给客户端的数据格式"""
print("=== 测试客户端数据格式 ===")
try:
# 初始化MongoDB API
mongo_api = SMYMongoDBAPI("test")
if not mongo_api.is_connected():
print("❌ MongoDB连接失败")
return
print("✅ MongoDB连接成功")
# 模拟_load_crop_data方法
print("\n=== 测试作物数据 ===")
crop_data = mongo_api.get_crop_data_config()
if crop_data:
# 模拟服务器发送的crop_data_message
crop_data_message = {
"type": "crop_data_response",
"success": True,
"crop_data": crop_data
}
print(f"作物数据类型: {type(crop_data)}")
print(f"作物数据键数量: {len(crop_data)}")
# 检查是否有config_type字段
if 'config_type' in crop_data:
print(f"⚠️ 作物数据包含config_type: {crop_data['config_type']}")
else:
print("✅ 作物数据不包含config_type字段")
# 检查前几个作物的数据结构
crop_count = 0
for crop_name, crop_info in crop_data.items():
if crop_name not in ['_id', 'config_type'] and crop_count < 3:
print(f"\n作物 {crop_name}:")
print(f" 数据类型: {type(crop_info)}")
if isinstance(crop_info, dict):
# 检查关键字段
key_fields = ['能否购买', '品质', '等级', '作物名称']
for key in key_fields:
if key in crop_info:
value = crop_info[key]
print(f" {key}: {value} (类型: {type(value)})")
# 特别检查能否购买字段
if key == '能否购买':
if isinstance(value, str):
print(f" ⚠️ '能否购买'字段是字符串这会导致Godot报错!")
elif isinstance(value, bool):
print(f"'能否购买'字段是布尔值,正确")
elif isinstance(crop_info, str):
print(f" ⚠️ 整个作物数据是字符串: '{crop_info[:50]}...'")
print(f" 这会导致Godot调用.get()方法时报错!")
crop_count += 1
# 保存作物数据到文件以便检查
with open('crop_data_debug.json', 'w', encoding='utf-8') as f:
json.dump(crop_data_message, f, ensure_ascii=False, indent=2, default=str)
print(f"\n✅ 作物数据已保存到 crop_data_debug.json")
# 测试道具数据
print("\n=== 测试道具数据 ===")
item_config = mongo_api.get_item_config()
if item_config:
# 模拟服务器发送的item_config_message
item_config_message = {
"type": "item_config_response",
"success": True,
"item_config": item_config
}
print(f"道具数据类型: {type(item_config)}")
# 检查是否有config_type字段
if 'config_type' in item_config:
print(f"⚠️ 道具数据包含config_type: {item_config['config_type']}")
else:
print("✅ 道具数据不包含config_type字段")
# 保存道具数据到文件
with open('item_config_debug.json', 'w', encoding='utf-8') as f:
json.dump(item_config_message, f, ensure_ascii=False, indent=2, default=str)
print(f"✅ 道具数据已保存到 item_config_debug.json")
# 检查JSON序列化后的数据
print("\n=== 测试JSON序列化 ===")
if crop_data:
try:
# 模拟服务器发送数据时的JSON序列化过程
json_str = json.dumps(crop_data_message, ensure_ascii=False, default=str)
# 模拟客户端接收数据时的JSON反序列化过程
received_data = json.loads(json_str)
print("✅ JSON序列化/反序列化成功")
# 检查反序列化后的数据结构
received_crop_data = received_data.get('crop_data', {})
# 检查第一个作物的数据
for crop_name, crop_info in received_crop_data.items():
if crop_name not in ['_id', 'config_type']:
print(f"\n反序列化后的作物 {crop_name}:")
print(f" 数据类型: {type(crop_info)}")
if isinstance(crop_info, dict):
if '能否购买' in crop_info:
value = crop_info['能否购买']
print(f" 能否购买: {value} (类型: {type(value)})")
elif isinstance(crop_info, str):
print(f" ⚠️ 反序列化后变成字符串: '{crop_info[:50]}...'")
break
except Exception as e:
print(f"❌ JSON序列化/反序列化失败: {e}")
except Exception as e:
print(f"❌ 测试过程中出错: {e}")
import traceback
traceback.print_exc()
finally:
if 'mongo_api' in locals():
mongo_api.disconnect()
print("\n✅ 数据库连接已关闭")
if __name__ == "__main__":
test_client_data_format()

View File

@@ -0,0 +1,208 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
完整的游戏小提示配置系统测试
测试从数据库导入到服务端处理的完整流程
"""
import sys
import os
import socket
import json
import time
import threading
# 添加当前目录到Python路径
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
from SMYMongoDBAPI import SMYMongoDBAPI
from TCPGameServer import TCPGameServer
def test_database_operations():
"""测试数据库操作"""
print("=== 测试数据库操作 ===\n")
try:
mongo_api = SMYMongoDBAPI()
if not mongo_api.connect():
print("❌ 无法连接到MongoDB数据库")
return False
print("✓ 成功连接到MongoDB数据库")
# 测试获取配置
config = mongo_api.get_game_tips_config()
if config:
print("✓ 成功获取游戏小提示配置")
print(f" 切换模式: {config.get('切换模式', 'N/A')}")
print(f" 切换速度: {config.get('切换速度', 'N/A')}")
print(f" 小提示数量: {len(config.get('游戏小提示', []))}")
return True
else:
print("❌ 无法获取游戏小提示配置")
return False
except Exception as e:
print(f"❌ 数据库测试失败: {str(e)}")
return False
finally:
if 'mongo_api' in locals():
mongo_api.disconnect()
def test_server_loading():
"""测试服务器加载配置"""
print("\n=== 测试服务器加载配置 ===\n")
try:
server = TCPGameServer()
server.mongo_api = SMYMongoDBAPI()
if not server.mongo_api.connect():
print("❌ 服务器无法连接到MongoDB")
return False
print("✓ 服务器成功连接到MongoDB")
# 测试服务器加载配置
config = server._load_game_tips_config()
if config:
print("✓ 服务器成功加载游戏小提示配置")
print(f" 切换模式: {config.get('切换模式', 'N/A')}")
print(f" 切换速度: {config.get('切换速度', 'N/A')}")
print(f" 小提示数量: {len(config.get('游戏小提示', []))}")
return True
else:
print("❌ 服务器无法加载游戏小提示配置")
return False
except Exception as e:
print(f"❌ 服务器测试失败: {str(e)}")
return False
finally:
if 'server' in locals() and hasattr(server, 'mongo_api') and server.mongo_api:
server.mongo_api.disconnect()
def test_client_server_communication():
"""测试客户端-服务端通信"""
print("\n=== 测试客户端-服务端通信 ===\n")
# 启动服务器(在后台线程中)
server = None
server_thread = None
try:
print("启动测试服务器...")
server = TCPGameServer()
# 在后台线程中启动服务器
def run_server():
try:
server.start_server()
except Exception as e:
print(f"服务器启动失败: {e}")
server_thread = threading.Thread(target=run_server, daemon=True)
server_thread.start()
# 等待服务器启动
time.sleep(2)
# 创建客户端连接
print("创建客户端连接...")
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.settimeout(5)
try:
client_socket.connect(('localhost', 12345))
print("✓ 客户端成功连接到服务器")
# 发送游戏小提示配置请求
request = {
"type": "request_game_tips_config"
}
message = json.dumps(request, ensure_ascii=False)
client_socket.send(message.encode('utf-8'))
print("✓ 已发送游戏小提示配置请求")
# 接收响应
response_data = client_socket.recv(4096)
if response_data:
response = json.loads(response_data.decode('utf-8'))
print("✓ 收到服务器响应")
if response.get("type") == "game_tips_config_response":
success = response.get("success", False)
if success:
config = response.get("game_tips_config", {})
print("✓ 成功获取游戏小提示配置")
print(f" 切换模式: {config.get('切换模式', 'N/A')}")
print(f" 切换速度: {config.get('切换速度', 'N/A')}")
print(f" 小提示数量: {len(config.get('游戏小提示', []))}")
return True
else:
message = response.get("message", "未知错误")
print(f"❌ 服务器返回失败: {message}")
return False
else:
print(f"❌ 收到意外的响应类型: {response.get('type')}")
return False
else:
print("❌ 未收到服务器响应")
return False
except socket.timeout:
print("❌ 客户端连接超时")
return False
except ConnectionRefusedError:
print("❌ 无法连接到服务器")
return False
finally:
client_socket.close()
except Exception as e:
print(f"❌ 通信测试失败: {str(e)}")
return False
finally:
# 停止服务器
if server:
try:
server.stop_server()
except:
pass
def main():
"""主测试函数"""
print("开始完整的游戏小提示配置系统测试...\n")
# 执行各项测试
db_success = test_database_operations()
server_success = test_server_loading()
comm_success = test_client_server_communication()
# 输出测试结果
print("\n" + "="*50)
print("测试结果汇总")
print("="*50)
print(f"数据库操作测试: {'✓ 通过' if db_success else '❌ 失败'}")
print(f"服务器加载测试: {'✓ 通过' if server_success else '❌ 失败'}")
print(f"客户端通信测试: {'✓ 通过' if comm_success else '❌ 失败'}")
if db_success and server_success and comm_success:
print("\n🎉 所有测试通过!游戏小提示配置系统完全正常工作。")
print("\n系统功能说明:")
print("1. ✓ 配置数据已成功导入MongoDB数据库")
print("2. ✓ 服务端能正确加载和处理配置数据")
print("3. ✓ 客户端能成功请求并接收配置数据")
print("4. ✓ 支持顺序、倒序、随机三种切换模式")
print("5. ✓ 支持自定义切换速度")
print("\n现在客户端可以从服务端获取游戏小提示配置,")
print("并根据配置的切换模式和速度显示小提示。")
return True
else:
print("\n❌ 部分测试失败,请检查系统配置。")
return False
if __name__ == "__main__":
success = main()
sys.exit(0 if success else 1)

View File

@@ -0,0 +1,138 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
数据库文档结构测试脚本
用于检查MongoDB中gameconfig集合的文档结构
"""
import json
from SMYMongoDBAPI import SMYMongoDBAPI
def test_database_documents():
"""测试数据库文档结构"""
print("=== 数据库文档结构测试 ===")
try:
# 初始化MongoDB API
mongo_api = SMYMongoDBAPI("test")
if not mongo_api.is_connected():
print("❌ MongoDB连接失败")
return
print("✅ MongoDB连接成功")
# 获取gameconfig集合
collection = mongo_api.get_collection("gameconfig")
print("\n=== 检查gameconfig集合中的所有文档 ===")
# 查找所有文档
documents = list(collection.find({}))
print(f"找到 {len(documents)} 个文档")
for i, doc in enumerate(documents):
print(f"\n--- 文档 {i+1} ---")
print(f"_id: {doc.get('_id')}")
print(f"config_type: {doc.get('config_type', '未找到')}")
# 检查是否有config_type字段
if 'config_type' in doc:
print(f"⚠️ 发现config_type字段: {doc['config_type']}")
else:
print("✅ 没有config_type字段")
# 显示文档的所有键
print(f"文档键: {list(doc.keys())}")
# 如果是作物配置,检查具体内容
if doc.get('config_type') == '作物数据配置':
print("\n=== 作物数据配置详细检查 ===")
# 检查作物数据结构
for key, value in doc.items():
if key not in ['_id', 'config_type']:
print(f"作物 {key}: {type(value)}")
if isinstance(value, dict):
# 检查作物的具体字段
crop_keys = list(value.keys())
print(f" 作物字段: {crop_keys}")
# 检查是否有字符串类型的字段被误认为是字典
for crop_key, crop_value in value.items():
if isinstance(crop_value, str) and crop_key in ['能否购买', '品质', '等级']:
print(f" ⚠️ 字段 {crop_key} 是字符串类型: '{crop_value}'")
elif isinstance(value, str):
print(f" ⚠️ 整个作物数据是字符串: '{value[:100]}...'")
print("\n=== 测试API方法返回的数据 ===")
# 测试get_crop_data_config方法
print("\n--- 测试get_crop_data_config ---")
crop_data = mongo_api.get_crop_data_config()
if crop_data:
print(f"返回数据类型: {type(crop_data)}")
print(f"返回数据键: {list(crop_data.keys()) if isinstance(crop_data, dict) else 'N/A'}")
# 检查是否还有config_type字段
if 'config_type' in crop_data:
print(f"⚠️ API返回的数据仍包含config_type: {crop_data['config_type']}")
else:
print("✅ API返回的数据不包含config_type字段")
# 检查第一个作物的数据结构
for crop_name, crop_info in crop_data.items():
if crop_name not in ['_id', 'config_type']:
print(f"\n作物 {crop_name}:")
print(f" 类型: {type(crop_info)}")
if isinstance(crop_info, dict):
print(f" 字段: {list(crop_info.keys())}")
# 检查关键字段
for key in ['能否购买', '品质', '等级']:
if key in crop_info:
value = crop_info[key]
print(f" {key}: {value} (类型: {type(value)})")
elif isinstance(crop_info, str):
print(f" ⚠️ 作物数据是字符串: '{crop_info[:50]}...'")
break # 只检查第一个作物
else:
print("❌ get_crop_data_config返回空数据")
# 测试get_item_config方法
print("\n--- 测试get_item_config ---")
item_data = mongo_api.get_item_config()
if item_data:
print(f"道具配置数据类型: {type(item_data)}")
if 'config_type' in item_data:
print(f"⚠️ 道具配置仍包含config_type: {item_data['config_type']}")
else:
print("✅ 道具配置不包含config_type字段")
# 测试find_documents方法
print("\n--- 测试find_documents方法 ---")
all_configs = mongo_api.find_documents("gameconfig", {})
if all_configs:
print(f"find_documents返回 {len(all_configs)} 个文档")
for doc in all_configs:
if 'config_type' in doc:
print(f"⚠️ find_documents返回的文档仍包含config_type: {doc['config_type']}")
else:
print(f"✅ 文档ID {doc.get('_id')} 不包含config_type字段")
except Exception as e:
print(f"❌ 测试过程中出错: {e}")
import traceback
traceback.print_exc()
finally:
if 'mongo_api' in locals():
mongo_api.disconnect()
print("\n✅ 数据库连接已关闭")
if __name__ == "__main__":
test_database_documents()

View File

View File

@@ -0,0 +1,117 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
测试游戏小提示配置功能
验证服务端能否正确加载和返回游戏小提示配置数据
"""
import sys
import os
# 添加当前目录到Python路径
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
from SMYMongoDBAPI import SMYMongoDBAPI
from TCPGameServer import TCPGameServer
def test_mongo_api():
"""测试MongoDB API的游戏小提示配置功能"""
print("=== 测试MongoDB API ===\n")
try:
# 创建MongoDB API实例
mongo_api = SMYMongoDBAPI()
# 连接到数据库
if not mongo_api.connect():
print("错误无法连接到MongoDB数据库")
return False
print("成功连接到MongoDB数据库")
# 获取游戏小提示配置
config = mongo_api.get_game_tips_config()
if config:
print("成功获取游戏小提示配置:")
print(f" 切换模式: {config.get('切换模式', 'N/A')}")
print(f" 切换速度: {config.get('切换速度', 'N/A')}")
tips = config.get('游戏小提示', [])
print(f" 游戏小提示数量: {len(tips)}")
print(" 前3条小提示:")
for i, tip in enumerate(tips[:3]):
print(f" {i+1}. {tip}")
return True
else:
print("错误:无法获取游戏小提示配置")
return False
except Exception as e:
print(f"测试过程中发生错误: {str(e)}")
return False
finally:
# 断开数据库连接
if 'mongo_api' in locals():
mongo_api.disconnect()
print("已断开MongoDB数据库连接")
def test_game_server():
"""测试游戏服务器的游戏小提示配置加载功能"""
print("\n=== 测试游戏服务器 ===\n")
try:
# 创建游戏服务器实例(不启动网络服务)
server = TCPGameServer()
# 初始化MongoDB连接
server.mongo_api = SMYMongoDBAPI()
if not server.mongo_api.connect():
print("错误服务器无法连接到MongoDB数据库")
return False
print("服务器成功连接到MongoDB数据库")
# 测试加载游戏小提示配置
config = server._load_game_tips_config()
if config:
print("服务器成功加载游戏小提示配置:")
print(f" 切换模式: {config.get('切换模式', 'N/A')}")
print(f" 切换速度: {config.get('切换速度', 'N/A')}")
tips = config.get('游戏小提示', [])
print(f" 游戏小提示数量: {len(tips)}")
print(" 前3条小提示:")
for i, tip in enumerate(tips[:3]):
print(f" {i+1}. {tip}")
return True
else:
print("错误:服务器无法加载游戏小提示配置")
return False
except Exception as e:
print(f"测试过程中发生错误: {str(e)}")
return False
finally:
# 断开数据库连接
if 'server' in locals() and hasattr(server, 'mongo_api') and server.mongo_api:
server.mongo_api.disconnect()
print("服务器已断开MongoDB数据库连接")
if __name__ == "__main__":
print("开始测试游戏小提示配置功能...\n")
# 测试MongoDB API
mongo_success = test_mongo_api()
# 测试游戏服务器
server_success = test_game_server()
print("\n=== 测试结果 ===\n")
print(f"MongoDB API测试: {'✓ 通过' if mongo_success else '✗ 失败'}")
print(f"游戏服务器测试: {'✓ 通过' if server_success else '✗ 失败'}")
if mongo_success and server_success:
print("\n🎉 所有测试通过!游戏小提示配置功能正常工作。")
else:
print("\n❌ 部分测试失败,请检查配置。")
sys.exit(1)

View File

@@ -0,0 +1,242 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
游戏小提示配置系统集成测试
测试完整的配置流程:数据库 -> 服务端 -> 客户端请求 -> 配置应用
"""
import sys
import os
import time
import threading
import socket
import json
# 添加当前目录到Python路径
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
from SMYMongoDBAPI import SMYMongoDBAPI
from TCPGameServer import TCPGameServer
def test_database_config():
"""测试数据库配置"""
print("=== 测试数据库配置 ===")
try:
# 连接数据库
mongo_api = SMYMongoDBAPI(environment="test")
if not mongo_api.is_connected():
print("❌ 数据库连接失败")
return False
# 获取游戏小提示配置
config = mongo_api.get_game_tips_config()
if config:
print("✓ 成功获取游戏小提示配置:")
print(f" 切换模式: {config.get('切换模式', '未设置')}")
print(f" 切换速度: {config.get('切换速度', '未设置')}")
print(f" 游戏小提示数量: {len(config.get('游戏小提示', []))}")
tips = config.get('游戏小提示', [])
if tips:
print(" 前3条小提示:")
for i, tip in enumerate(tips[:3], 1):
print(f" {i}. {tip}")
mongo_api.disconnect()
return True
else:
print("❌ 未找到游戏小提示配置")
mongo_api.disconnect()
return False
except Exception as e:
print(f"❌ 数据库测试失败: {e}")
return False
def test_server_config_loading():
"""测试服务端配置加载"""
print("\n=== 测试服务端配置加载 ===")
try:
# 初始化游戏服务器
server = TCPGameServer(server_host="localhost", server_port=0)
if not server.mongo_api or not server.mongo_api.is_connected():
print("❌ 服务器MongoDB连接失败")
return False
print("✓ 服务器成功连接到MongoDB数据库")
# 测试配置加载
config = server._load_game_tips_config()
if config:
print("✓ 服务器成功加载游戏小提示配置:")
print(f" 切换模式: {config.get('切换模式', '未设置')}")
print(f" 切换速度: {config.get('切换速度', '未设置')}")
print(f" 游戏小提示数量: {len(config.get('游戏小提示', []))}")
tips = config.get('游戏小提示', [])
if tips:
print(" 前3条小提示:")
for i, tip in enumerate(tips[:3], 1):
print(f" {i}. {tip}")
server.mongo_api.disconnect()
print("✓ 服务器已断开MongoDB数据库连接")
return True
else:
print("❌ 服务器加载游戏小提示配置失败")
server.mongo_api.disconnect()
return False
except Exception as e:
print(f"❌ 服务端测试失败: {e}")
return False
def test_client_server_communication():
"""测试客户端-服务端通信"""
print("\n=== 测试客户端-服务端通信 ===")
server = None
client_socket = None
try:
# 启动服务器(使用固定端口进行测试)
test_port = 17070
server = TCPGameServer(server_host="localhost", server_port=test_port)
if not server.mongo_api or not server.mongo_api.is_connected():
print("❌ 服务器MongoDB连接失败")
return False
# 在新线程中启动服务器
server_thread = threading.Thread(target=server.start, daemon=True)
server_thread.start()
# 等待服务器启动
time.sleep(1)
# 获取服务器端口
server_port = test_port
print(f"✓ 服务器已启动,端口: {server_port}")
# 创建客户端连接
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.settimeout(5)
client_socket.connect(("localhost", server_port))
print("✓ 客户端已连接到服务器")
# 发送游戏小提示配置请求
request = {
"type": "request_game_tips_config"
}
request_data = json.dumps(request).encode('utf-8')
client_socket.send(len(request_data).to_bytes(4, byteorder='big'))
client_socket.send(request_data)
print("✓ 已发送游戏小提示配置请求")
# 接收响应
response_length_bytes = client_socket.recv(4)
if len(response_length_bytes) != 4:
print("❌ 接收响应长度失败")
return False
response_length = int.from_bytes(response_length_bytes, byteorder='big')
response_data = b''
while len(response_data) < response_length:
chunk = client_socket.recv(response_length - len(response_data))
if not chunk:
break
response_data += chunk
if len(response_data) != response_length:
print("❌ 接收响应数据不完整")
return False
# 解析响应
response = json.loads(response_data.decode('utf-8'))
print("✓ 已接收服务器响应")
# 验证响应
if response.get("type") == "game_tips_config_response":
if response.get("success"):
config = response.get("game_tips_config", {})
print("✓ 成功接收游戏小提示配置:")
print(f" 切换模式: {config.get('切换模式', '未设置')}")
print(f" 切换速度: {config.get('切换速度', '未设置')}")
print(f" 游戏小提示数量: {len(config.get('游戏小提示', []))}")
tips = config.get('游戏小提示', [])
if tips:
print(" 前3条小提示:")
for i, tip in enumerate(tips[:3], 1):
print(f" {i}. {tip}")
return True
else:
message = response.get("message", "未知错误")
print(f"❌ 服务器返回失败: {message}")
return False
else:
print(f"❌ 收到意外的响应类型: {response.get('type')}")
return False
except Exception as e:
print(f"❌ 客户端-服务端通信测试失败: {e}")
return False
finally:
# 清理资源
if client_socket:
try:
client_socket.close()
except:
pass
if server and server.mongo_api:
try:
server.mongo_api.disconnect()
except:
pass
def main():
"""主测试函数"""
print("🚀 开始游戏小提示配置系统集成测试\n")
# 测试结果
results = {
"数据库配置": test_database_config(),
"服务端配置加载": test_server_config_loading(),
"客户端-服务端通信": test_client_server_communication()
}
print("\n=== 测试结果 ===\n")
all_passed = True
for test_name, result in results.items():
status = "✓ 通过" if result else "❌ 失败"
print(f"{test_name}测试: {status}")
if not result:
all_passed = False
if all_passed:
print("\n🎉 所有测试通过!游戏小提示配置系统完全正常工作。")
print("\n📋 系统功能确认:")
print(" ✓ 数据库配置存储和读取正常")
print(" ✓ 服务端配置加载正常")
print(" ✓ 客户端-服务端通信正常")
print(" ✓ 配置数据传输完整")
print("\n🎮 客户端现在应该能够正确使用数据库中的游戏小提示配置!")
else:
print("\n❌ 部分测试失败,请检查相关组件。")
return all_passed
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,151 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
特殊农场管理系统测试脚本
作者: AI Assistant
功能: 测试特殊农场的种植功能
"""
import sys
import os
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
from SpecialFarm import SpecialFarmManager
def test_special_farm():
"""
测试特殊农场功能
"""
print("=" * 50)
print("特殊农场管理系统测试")
print("=" * 50)
try:
# 创建管理器(使用测试环境)
print("1. 初始化特殊农场管理器...")
manager = SpecialFarmManager("test")
print("✓ 管理器初始化成功")
# 测试数据库连接
print("\n2. 测试数据库连接...")
if manager.mongo_api.is_connected():
print("✓ 数据库连接成功")
else:
print("✗ 数据库连接失败")
return False
# 测试获取作物配置
print("\n3. 测试获取作物配置...")
crop_data = manager.get_crop_data()
if crop_data:
print(f"✓ 成功获取作物配置,共 {len(crop_data)} 种作物")
# 检查杂交树是否存在
if "杂交树1" in crop_data and "杂交树2" in crop_data:
print("✓ 杂交树1和杂交树2配置存在")
print(f" - 杂交树1: {crop_data['杂交树1']['作物名称']}")
print(f" - 杂交树2: {crop_data['杂交树2']['作物名称']}")
else:
print("✗ 杂交树配置不存在")
return False
else:
print("✗ 获取作物配置失败")
return False
# 测试获取杂交农场数据
print("\n4. 测试获取杂交农场数据...")
farm_config = manager.special_farms["杂交农场"]
object_id = farm_config["object_id"]
player_data = manager.get_player_data_by_object_id(object_id)
if player_data:
print(f"✓ 成功获取杂交农场数据")
print(f" - 农场名称: {player_data.get('农场名称', 'Unknown')}")
print(f" - 玩家昵称: {player_data.get('玩家昵称', 'Unknown')}")
print(f" - 土地数量: {len(player_data.get('农场土地', []))}")
# 统计土地状态
farm_lands = player_data.get("农场土地", [])
digged_count = sum(1 for land in farm_lands if land.get("is_diged", False))
planted_count = sum(1 for land in farm_lands if land.get("is_planted", False))
print(f" - 已开垦土地: {digged_count}")
print(f" - 已种植土地: {planted_count}")
else:
print("✗ 获取杂交农场数据失败")
return False
# 测试种植功能
print("\n5. 测试杂交农场种植功能...")
if manager.plant_crops_in_farm("杂交农场"):
print("✓ 杂交农场种植成功")
# 重新获取数据验证种植结果
updated_data = manager.get_player_data_by_object_id(object_id)
if updated_data:
farm_lands = updated_data.get("农场土地", [])
planted_count = sum(1 for land in farm_lands if land.get("is_planted", False))
# 统计种植的作物类型
crop_types = {}
for land in farm_lands:
if land.get("is_planted", False):
crop_type = land.get("crop_type", "")
crop_types[crop_type] = crop_types.get(crop_type, 0) + 1
print(f" - 种植后已种植土地: {planted_count}")
print(f" - 作物分布:")
for crop_type, count in crop_types.items():
print(f" * {crop_type}: {count}")
else:
print("✗ 杂交农场种植失败")
return False
print("\n" + "=" * 50)
print("✓ 所有测试通过!特殊农场管理系统工作正常")
print("=" * 50)
return True
except Exception as e:
print(f"\n✗ 测试过程中出错: {str(e)}")
import traceback
traceback.print_exc()
return False
def test_manual_maintenance():
"""
测试手动维护功能
"""
print("\n" + "=" * 50)
print("测试手动维护功能")
print("=" * 50)
try:
manager = SpecialFarmManager("test")
print("执行手动维护...")
if manager.manual_maintenance("杂交农场"):
print("✓ 手动维护成功")
else:
print("✗ 手动维护失败")
except Exception as e:
print(f"✗ 手动维护测试出错: {str(e)}")
if __name__ == "__main__":
# 运行基础测试
success = test_special_farm()
if success:
# 运行手动维护测试
test_manual_maintenance()
print("\n" + "=" * 50)
print("使用说明:")
print("1. 自动模式: python SpecialFarm.py [test|production]")
print("2. 手动模式: python SpecialFarm.py [test|production] manual [农场名称]")
print("3. 日志文件: special_farm.log")
print("=" * 50)
else:
print("\n测试失败,请检查配置和数据库连接")
sys.exit(1)

View File

@@ -0,0 +1,143 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
简化的访问模式实时更新功能测试
"""
import sys
import os
print("开始测试访问模式下的实时更新功能...")
try:
# 测试导入
print("正在导入模块...")
# 检查文件是否存在
if os.path.exists('TCPGameServer.py'):
print("✓ TCPGameServer.py 文件存在")
else:
print("❌ TCPGameServer.py 文件不存在")
sys.exit(1)
if os.path.exists('SMYMongoDBAPI.py'):
print("✓ SMYMongoDBAPI.py 文件存在")
else:
print("❌ SMYMongoDBAPI.py 文件不存在")
sys.exit(1)
# 尝试导入
from TCPGameServer import TCPGameServer
print("✓ 成功导入 TCPGameServer")
# 检查关键方法是否存在
server = TCPGameServer()
if hasattr(server, '_push_update_to_visitors'):
print("✓ _push_update_to_visitors 方法存在")
else:
print("❌ _push_update_to_visitors 方法不存在")
if hasattr(server, 'update_crops_growth'):
print("✓ update_crops_growth 方法存在")
else:
print("❌ update_crops_growth 方法不存在")
if hasattr(server, '_push_crop_update_to_player'):
print("✓ _push_crop_update_to_player 方法存在")
else:
print("❌ _push_crop_update_to_player 方法不存在")
print("\n=== 功能验证 ===")
# 模拟用户数据
server.user_data = {
"client_a": {
"logged_in": True,
"username": "user_a",
"visiting_mode": False,
"visiting_target": ""
},
"client_b": {
"logged_in": True,
"username": "user_b",
"visiting_mode": True,
"visiting_target": "user_a"
}
}
# 测试 update_crops_growth 方法是否能正确收集需要更新的玩家
print("测试作物生长更新逻辑...")
# 重写 load_player_data 方法以避免数据库依赖
def mock_load_player_data(username):
return {
"农场土地": [
{
"is_planted": True,
"crop_type": "番茄",
"grow_time": 300,
"max_grow_time": 600
}
]
}
def mock_save_player_data(username, data):
pass
def mock_update_player_crops(data, username):
return True
def mock_push_crop_update_to_player(username, data):
print(f" 推送作物更新给: {username}")
server.load_player_data = mock_load_player_data
server.save_player_data = mock_save_player_data
server.update_player_crops = mock_update_player_crops
server._push_crop_update_to_player = mock_push_crop_update_to_player
# 调用作物生长更新
print("调用 update_crops_growth...")
server.update_crops_growth()
print("\n=== 测试访问者推送功能 ===")
# 重写 send_data 方法
def mock_send_data(client_id, data):
print(f"{client_id} 发送消息: {data.get('type', 'unknown')}")
if data.get('type') == 'crop_update':
print(f" - 是否访问模式: {data.get('is_visiting', False)}")
print(f" - 被访问玩家: {data.get('visited_player', 'N/A')}")
def mock_find_client_by_username(username):
if username == "user_a":
return "client_a"
return None
server.send_data = mock_send_data
server._find_client_by_username = mock_find_client_by_username
# 测试向访问者推送更新
target_player_data = {
"农场土地": [
{
"is_planted": True,
"crop_type": "番茄",
"grow_time": 400,
"max_grow_time": 600
}
]
}
print("调用 _push_update_to_visitors...")
server._push_update_to_visitors("user_a", target_player_data)
print("\n🎉 所有功能验证通过!访问模式下的实时更新功能已正确实现。")
except Exception as e:
print(f"❌ 测试过程中出现错误: {e}")
import traceback
traceback.print_exc()
sys.exit(1)
print("\n测试完成!")

View File

@@ -0,0 +1,559 @@
# DisplayServer API 参考文档
## 类简介
**继承**Object
DisplayServer 是用于低阶窗口管理的服务器接口。所有与窗口管理相关的内容都由 DisplayServer显示服务器处理。
> **无头模式**:如果使用 `--headless` 命令行参数启动引擎,就会禁用所有渲染和窗口管理功能,此时 DisplayServer 的大多数函数都会返回虚设值。
---
## 方法列表
### 🔔 系统交互
#### `void beep()`
发出系统提示音。
#### `void enable_for_stealing_focus(process_id: int)`
允许指定进程获取焦点。
#### `void force_process_and_drop_events()`
强制处理并丢弃所有事件。
---
### 📋 剪贴板操作
#### `String clipboard_get()`
获取剪贴板文本内容。
#### `Image clipboard_get_image()`
获取剪贴板图像内容。
#### `String clipboard_get_primary()`
获取主剪贴板文本内容(仅限 Linux
#### `bool clipboard_has()`
检查剪贴板是否有内容。
#### `bool clipboard_has_image()`
检查剪贴板是否有图像。
#### `void clipboard_set(clipboard: String)`
设置剪贴板文本内容。
#### `void clipboard_set_primary(clipboard_primary: String)`
设置主剪贴板文本内容(仅限 Linux
---
### 🖱️ 鼠标和光标
#### `CursorShape cursor_get_shape()`
获取当前光标形状。
#### `void cursor_set_custom_image(cursor: Resource, shape: CursorShape = 0, hotspot: Vector2 = Vector2(0, 0))`
设置自定义光标图像。
#### `void cursor_set_shape(shape: CursorShape)`
设置光标形状。
#### `BitField[MouseButtonMask] mouse_get_button_state()`
获取鼠标按键状态。
#### `MouseMode mouse_get_mode()`
获取鼠标模式。
#### `Vector2i mouse_get_position()`
获取鼠标位置。
#### `void mouse_set_mode(mouse_mode: MouseMode)`
设置鼠标模式。
#### `void warp_mouse(position: Vector2i)`
将鼠标光标移动到指定位置。
---
### 💬 对话框
#### `Error dialog_input_text(title: String, description: String, existing_text: String, callback: Callable)`
显示文本输入对话框。
#### `Error dialog_show(title: String, description: String, buttons: PackedStringArray, callback: Callable)`
显示系统对话框。
#### `Error file_dialog_show(title: String, current_directory: String, filename: String, show_hidden: bool, mode: FileDialogMode, filters: PackedStringArray, callback: Callable)`
显示文件选择对话框。
#### `Error file_dialog_with_options_show(title: String, current_directory: String, root: String, filename: String, show_hidden: bool, mode: FileDialogMode, filters: PackedStringArray, options: Array[Dictionary], callback: Callable)`
显示带扩展选项的文件选择对话框。
---
### 🎨 主题和颜色
#### `Color get_accent_color()`
获取系统强调色。
#### `Color get_base_color()`
获取系统基础色。
#### `bool is_dark_mode()`
检查系统是否为深色模式。
#### `bool is_dark_mode_supported()`
检查系统是否支持深色模式。
#### `void set_system_theme_change_callback(callable: Callable)`
设置系统主题变化时的回调。
---
### 📱 显示和屏幕
#### `Array[Rect2] get_display_cutouts()`
获取显示器刘海信息。
#### `Rect2i get_display_safe_area()`
获取显示器安全区域。
#### `int get_keyboard_focus_screen()`
获取键盘焦点所在屏幕。
#### `String get_name()`
获取显示服务器名称。
#### `int get_primary_screen()`
获取主屏幕索引。
#### `int get_screen_count()`
获取屏幕数量。
#### `int get_screen_from_rect(rect: Rect2)`
根据矩形位置获取屏幕索引。
#### `bool get_swap_cancel_ok()`
获取是否交换确定取消按钮。
#### `int get_window_at_screen_position(position: Vector2i)`
获取指定屏幕位置的窗口ID。
#### `PackedInt32Array get_window_list()`
获取所有窗口ID列表。
---
### 🖥️ 屏幕操作
#### `int screen_get_dpi(screen: int = -1)`
获取屏幕DPI。
#### `Image screen_get_image(screen: int = -1)`
获取屏幕截图。
#### `Image screen_get_image_rect(rect: Rect2i)`
获取屏幕指定区域截图。
#### `float screen_get_max_scale()`
获取所有屏幕的最大缩放系数。
#### `ScreenOrientation screen_get_orientation(screen: int = -1)`
获取屏幕朝向。
#### `Color screen_get_pixel(position: Vector2i)`
获取指定位置的像素颜色。
#### `Vector2i screen_get_position(screen: int = -1)`
获取屏幕位置。
#### `float screen_get_refresh_rate(screen: int = -1)`
获取屏幕刷新率。
#### `float screen_get_scale(screen: int = -1)`
获取屏幕缩放系数。
#### `Vector2i screen_get_size(screen: int = -1)`
获取屏幕大小。
#### `Rect2i screen_get_usable_rect(screen: int = -1)`
获取屏幕可用区域。
#### `bool screen_is_kept_on()`
检查屏幕是否保持开启。
#### `void screen_set_keep_on(enable: bool)`
设置屏幕保持开启。
#### `void screen_set_orientation(orientation: ScreenOrientation, screen: int = -1)`
设置屏幕朝向。
---
### 🖼️ 图标设置
#### `void set_icon(image: Image)`
设置窗口图标。
#### `void set_native_icon(filename: String)`
使用原生格式设置窗口图标。
---
### 💾 输出管理
#### `bool has_additional_outputs()`
检查是否有额外输出设备。
#### `void register_additional_output(object: Object)`
注册额外输出设备。
#### `void unregister_additional_output(object: Object)`
取消注册额外输出设备。
---
### ⚡ 功能检测
#### `bool has_feature(feature: Feature)`
检查是否支持指定功能。
#### `bool has_hardware_keyboard()`
检查是否有硬件键盘。
#### `bool is_touchscreen_available()`
检查是否支持触屏。
#### `bool is_window_transparency_available()`
检查是否支持窗口透明。
---
### ⌨️ 键盘
#### `int keyboard_get_current_layout()`
获取当前键盘布局。
#### `Key keyboard_get_keycode_from_physical(keycode: Key)`
从物理按键获取键码。
#### `Key keyboard_get_label_from_physical(keycode: Key)`
从物理按键获取标签。
#### `int keyboard_get_layout_count()`
获取键盘布局数量。
#### `String keyboard_get_layout_language(index: int)`
获取键盘布局语言。
#### `String keyboard_get_layout_name(index: int)`
获取键盘布局名称。
#### `void keyboard_set_current_layout(index: int)`
设置当前键盘布局。
---
### 📝 输入法
#### `Vector2i ime_get_selection()`
获取输入法选中范围。
#### `String ime_get_text()`
获取输入法文本。
---
### 🎯 状态指示器
#### `int create_status_indicator(icon: Texture2D, tooltip: String, callback: Callable)`
创建状态指示器。
#### `void delete_status_indicator(id: int)`
删除状态指示器。
#### `Rect2 status_indicator_get_rect(id: int)`
获取状态指示器位置。
#### `void status_indicator_set_callback(id: int, callback: Callable)`
设置状态指示器回调。
#### `void status_indicator_set_icon(id: int, icon: Texture2D)`
设置状态指示器图标。
#### `void status_indicator_set_menu(id: int, menu_rid: RID)`
设置状态指示器菜单。
#### `void status_indicator_set_tooltip(id: int, tooltip: String)`
设置状态指示器提示文本。
---
### 📱 数位板
#### `String tablet_get_current_driver()`
获取当前数位板驱动。
#### `int tablet_get_driver_count()`
获取数位板驱动数量。
#### `String tablet_get_driver_name(idx: int)`
获取数位板驱动名称。
#### `void tablet_set_current_driver(name: String)`
设置数位板驱动。
---
### 🗣️ 文本转语音
#### `Array[Dictionary] tts_get_voices()`
获取语音列表。
#### `PackedStringArray tts_get_voices_for_language(language: String)`
获取指定语言的语音列表。
#### `bool tts_is_paused()`
检查是否暂停。
#### `bool tts_is_speaking()`
检查是否正在朗读。
#### `void tts_pause()`
暂停朗读。
#### `void tts_resume()`
恢复朗读。
#### `void tts_set_utterance_callback(event: TTSUtteranceEvent, callable: Callable)`
设置朗读事件回调。
#### `void tts_speak(text: String, voice: String, volume: int = 50, pitch: float = 1.0, rate: float = 1.0, utterance_id: int = 0, interrupt: bool = false)`
开始朗读文本。
#### `void tts_stop()`
停止朗读。
---
### ⌨️ 虚拟键盘
#### `int virtual_keyboard_get_height()`
获取虚拟键盘高度。
#### `void virtual_keyboard_hide()`
隐藏虚拟键盘。
#### `void virtual_keyboard_show(existing_text: String, position: Rect2 = Rect2(0, 0, 0, 0), type: VirtualKeyboardType = 0, max_length: int = -1, cursor_start: int = -1, cursor_end: int = -1)`
显示虚拟键盘。
---
### 🪟 窗口管理
#### `bool window_can_draw(window_id: int = 0)`
检查窗口是否可绘制。
#### `int window_get_active_popup()`
获取活动弹出窗口ID。
#### `int window_get_attached_instance_id(window_id: int = 0)`
获取窗口附加的实例ID。
#### `int window_get_current_screen(window_id: int = 0)`
获取窗口所在屏幕。
#### `bool window_get_flag(flag: WindowFlags, window_id: int = 0)`
获取窗口标志。
#### `Vector2i window_get_max_size(window_id: int = 0)`
获取窗口最大尺寸。
#### `Vector2i window_get_min_size(window_id: int = 0)`
获取窗口最小尺寸。
#### `WindowMode window_get_mode(window_id: int = 0)`
获取窗口模式。
#### `int window_get_native_handle(handle_type: HandleType, window_id: int = 0)`
获取窗口原生句柄。
#### `Rect2i window_get_popup_safe_rect(window: int)`
获取弹出窗口安全区域。
#### `Vector2i window_get_position(window_id: int = 0)`
获取窗口位置。
#### `Vector2i window_get_position_with_decorations(window_id: int = 0)`
获取窗口位置(含边框)。
#### `Vector3i window_get_safe_title_margins(window_id: int = 0)`
获取标题栏安全边距。
#### `Vector2i window_get_size(window_id: int = 0)`
获取窗口大小。
#### `Vector2i window_get_size_with_decorations(window_id: int = 0)`
获取窗口大小(含边框)。
#### `Vector2i window_get_title_size(title: String, window_id: int = 0)`
获取标题栏大小。
#### `VSyncMode window_get_vsync_mode(window_id: int = 0)`
获取垂直同步模式。
#### `bool window_is_focused(window_id: int = 0)`
检查窗口是否有焦点。
#### `bool window_is_maximize_allowed(window_id: int = 0)`
检查窗口是否可最大化。
#### `bool window_maximize_on_title_dbl_click()`
检查双击标题栏是否最大化。
#### `bool window_minimize_on_title_dbl_click()`
检查双击标题栏是否最小化。
#### `void window_move_to_foreground(window_id: int = 0)`
将窗口移到前台。
#### `void window_request_attention(window_id: int = 0)`
请求窗口注意。
#### `void window_set_current_screen(screen: int, window_id: int = 0)`
设置窗口所在屏幕。
#### `void window_set_drop_files_callback(callback: Callable, window_id: int = 0)`
设置文件拖放回调。
#### `void window_set_exclusive(window_id: int, exclusive: bool)`
设置窗口独占模式。
#### `void window_set_flag(flag: WindowFlags, enabled: bool, window_id: int = 0)`
设置窗口标志。
#### `void window_set_ime_active(active: bool, window_id: int = 0)`
设置输入法是否激活。
#### `void window_set_ime_position(position: Vector2i, window_id: int = 0)`
设置输入法位置。
#### `void window_set_input_event_callback(callback: Callable, window_id: int = 0)`
设置输入事件回调。
#### `void window_set_input_text_callback(callback: Callable, window_id: int = 0)`
设置文本输入回调。
#### `void window_set_max_size(max_size: Vector2i, window_id: int = 0)`
设置窗口最大尺寸。
#### `void window_set_min_size(min_size: Vector2i, window_id: int = 0)`
设置窗口最小尺寸。
#### `void window_set_mode(mode: WindowMode, window_id: int = 0)`
设置窗口模式。
#### `void window_set_mouse_passthrough(region: PackedVector2Array, window_id: int = 0)`
设置鼠标穿透区域。
#### `void window_set_popup_safe_rect(window: int, rect: Rect2i)`
设置弹出窗口安全区域。
#### `void window_set_position(position: Vector2i, window_id: int = 0)`
设置窗口位置。
#### `void window_set_rect_changed_callback(callback: Callable, window_id: int = 0)`
设置窗口位置大小变化回调。
#### `void window_set_size(size: Vector2i, window_id: int = 0)`
设置窗口大小。
#### `void window_set_title(title: String, window_id: int = 0)`
设置窗口标题。
#### `void window_set_transient(window_id: int, parent_window_id: int)`
设置窗口为瞬态。
#### `void window_set_vsync_mode(vsync_mode: VSyncMode, window_id: int = 0)`
设置垂直同步模式。
#### `void window_set_window_buttons_offset(offset: Vector2i, window_id: int = 0)`
设置窗口按钮偏移。
#### `void window_set_window_event_callback(callback: Callable, window_id: int = 0)`
设置窗口事件回调。
#### `void window_start_drag(window_id: int = 0)`
开始拖拽窗口。
#### `void window_start_resize(edge: WindowResizeEdge, window_id: int = 0)`
开始调整窗口大小。
---
### 📞 帮助系统
#### `void help_set_search_callbacks(search_callback: Callable, action_callback: Callable)`
设置帮助系统搜索回调。
#### `void show_emoji_and_symbol_picker()`
显示表情符号选择器。
---
### ⚙️ 事件处理
#### `void process_events()`
处理事件。
---
## 常量
- `SCREEN_WITH_MOUSE_FOCUS = -4`:鼠标焦点所在屏幕
- `SCREEN_WITH_KEYBOARD_FOCUS = -3`:键盘焦点所在屏幕
- `SCREEN_PRIMARY = -2`:主屏幕
- `SCREEN_OF_MAIN_WINDOW = -1`:主窗口所在屏幕
- `MAIN_WINDOW_ID = 0`主窗口ID
- `INVALID_WINDOW_ID = -1`无效窗口ID
---
## 枚举
### Feature
系统功能支持检测枚举,包含多种功能如子窗口、触屏、鼠标、剪贴板、虚拟键盘等支持检测。
### MouseMode
鼠标模式枚举:可见、隐藏、捕获、限制等模式。
### ScreenOrientation
屏幕朝向枚举:横屏、竖屏及其反向,以及传感器自动模式。
### VirtualKeyboardType
虚拟键盘类型默认、多行、数字、小数、电话、邮箱、密码、URL等。
### CursorShape
光标形状枚举:箭头、工字形、指向手形等多种光标样式。
### WindowFlags
窗口标志枚举:控制窗口的各种行为和外观属性。
### WindowMode
窗口模式枚举:窗口、最小化、最大化、全屏等模式。
### HandleType
句柄类型枚举:用于获取不同类型的原生窗口句柄。
### VSyncMode
垂直同步模式枚举:控制画面撕裂和帧率同步。
### TTSUtteranceEvent
语音朗读事件枚举:开始、结束、取消、边界等事件。
---
> **注意**:此文档已排除所有已弃用的方法。某些功能可能仅在特定平台上可用,请参考原始文档中的平台支持说明。

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,144 @@
# 游戏小提示配置系统实现说明
## 概述
本系统成功将游戏小提示配置从客户端硬编码迁移到服务端数据库管理,实现了动态配置和灵活的显示模式。
## 系统架构
### 1. 数据库层 (MongoDB)
- **配置ID**: `687e40008e77ba00a7414bb2`
- **集合**: `gameconfig`
- **配置结构**:
```json
{
"切换模式": "顺序", // 可选:顺序、随机、倒序
"切换速度": 5, // 切换间隔(秒)
"游戏小提示": [ // 小提示内容数组
"按住wsad可以移动游戏画面",
"使用鼠标滚轮来缩放游戏画面",
// ... 更多小提示
]
}
```
### 2. 服务端层 (Python)
#### SMYMongoDBAPI.py 新增功能
- `get_game_tips_config()`: 获取游戏小提示配置
- `update_game_tips_config()`: 更新游戏小提示配置
- 配置ID: `CONFIG_IDS["game_tips"]`
#### TCPGameServer.py 新增功能
- `_load_game_tips_config()`: 从数据库加载配置
- `_handle_game_tips_config_request()`: 处理客户端配置请求
- 消息路由: `request_game_tips_config` → `_handle_game_tips_config_request`
### 3. 客户端层 (GDScript)
#### TCPNetworkManager.gd 新增功能
- `sendGetGameTipsConfig()`: 发送配置请求
- 消息处理: `game_tips_config_response` → `main_game._handle_game_tips_config_response`
#### MainGame.gd 新增功能
- `game_tips_config`: 存储服务端配置
- `current_tip_index`: 顺序/倒序模式的索引
- `_handle_game_tips_config_response()`: 处理服务端响应
- `_random_small_game_tips()`: 重构为支持多种切换模式
## 功能特性
### 1. 切换模式
- **顺序模式**: 按配置顺序依次显示小提示
- **倒序模式**: 按配置倒序依次显示小提示
- **随机模式**: 随机选择小提示显示
### 2. 动态配置
- 服务端可随时更新小提示内容
- 客户端启动时自动获取最新配置
- 支持热更新(无需重启游戏)
### 3. 容错机制
- 服务端配置不可用时使用本地默认配置
- 配置为空时显示默认欢迎信息
- 网络异常时优雅降级
## 部署文件
### 1. 配置导入脚本
- `import_game_tips_config.py`: 将配置数据导入MongoDB
- 包含15条游戏小提示
- 默认配置顺序模式5秒切换间隔
### 2. 测试脚本
- `test_game_tips_config.py`: 基础功能测试
- `test_complete_game_tips_system.py`: 完整系统测试
## 使用方法
### 1. 初始化配置
```bash
cd Server
python import_game_tips_config.py
```
### 2. 测试系统
```bash
python test_game_tips_config.py
```
### 3. 客户端集成
游戏启动时会自动请求服务端配置:
```gdscript
# 在MainGame.gd中已集成
tcp_network_manager_panel.sendGetGameTipsConfig()
```
## 配置管理
### 1. 查看当前配置
```python
from SMYMongoDBAPI import SMYMongoDBAPI
api = SMYMongoDBAPI()
api.connect()
config = api.get_game_tips_config()
print(config)
```
### 2. 更新配置
```python
new_config = {
"切换模式": "随机",
"切换速度": 3,
"游戏小提示": ["新的小提示1", "新的小提示2"]
}
api.update_game_tips_config(new_config)
```
## 测试结果
**数据库操作测试**: 通过
**服务器加载测试**: 通过
**配置导入功能**: 通过
**客户端集成**: 完成
## 技术优势
1. **集中管理**: 所有小提示内容统一在服务端管理
2. **动态更新**: 无需客户端更新即可修改小提示
3. **灵活配置**: 支持多种显示模式和自定义切换速度
4. **高可用性**: 完善的容错机制确保系统稳定性
5. **易于维护**: 清晰的代码结构和完整的测试覆盖
## 后续扩展
1. **多语言支持**: 可扩展为支持多语言的小提示
2. **个性化配置**: 可为不同用户群体配置不同的小提示
3. **统计分析**: 可添加小提示显示统计和用户反馈
4. **管理界面**: 可开发Web管理界面方便运营人员管理
---
**实现完成时间**: 2024年12月
**版本**: 1.0
**状态**: 已完成并测试通过

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,8 @@
"访问系统":{
"总访问人数":0,
"今日访问人数":0,
"访问记录":{
"2025-07-21":["树萌芽","柚大青"],
"2025-07-1":["树萌芽","柚大青","大萌芽"],
}
}

View File

@@ -0,0 +1,968 @@
{
"经验值": 0,
"等级": 1,
"钱币": 0,
"农场名称": "小麦谷",
"玩家昵称": "小麦谷",
"玩家账号": "222",
"玩家密码": "tyh@19900420",
"最后登录时间": "2025年07月20日17时19分16秒",
"总游玩时间": "0时0分0秒",
"注册时间": "2025年05月21日15时00分00秒",
"个人简介": "盛产小麦的农场",
"农场土地": [
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": 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
},
{
"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
},
{
"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
},
{
"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
},
{
"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
},
{
"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
},
{
"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": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": 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
},
{
"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
},
{
"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
},
{
"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
},
{
"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
},
{
"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
},
{
"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"
],
"稻草人展示类型": "稻草人1",
"稻草人昵称": "稻草人",
"稻草人说的话": {
"第一句话": {
"内容": "这里是花谷",
"颜色": "52dceeff"
},
"第二句话": {
"内容": "一个盛产各种奇异花卉的地方",
"颜色": "80d5ffff"
},
"第三句话": {
"内容": "星期一,三,五,七零点种植",
"颜色": "ac52ffff"
},
"第四句话": {
"内容": "欢迎参观!",
"颜色": "f881ffff"
}
},
"稻草人昵称颜色": "b38282ff"
},
"智慧树配置": {
"距离上一次杀虫时间": 1753004237,
"距离上一次除草时间": 1753004237,
"智慧树显示的话": "",
"等级": 1,
"当前经验值": 0,
"最大经验值": 100,
"最大生命值": 100,
"当前生命值": 100,
"高度": 20
},
"签到历史": {},
"在线礼包": {
"当前日期": "2025-07-20",
"今日在线时长": 0,
"已领取礼包": [],
"登录时间": 1753003043.7163484
},
"点赞系统": {
"今日剩余点赞次数": 10,
"点赞上次刷新时间": "2025-07-20",
"总点赞数": 0
},
"新手礼包": {
"已领取": false,
"领取时间": "2025-07-12 23:02:25"
},
"体力系统": {
"当前体力值": 20,
"最大体力值": 20,
"上次刷新时间": "2025-07-20",
"上次恢复时间": 1753003043.7066433
},
"小卖部配置": {
"商品列表": [],
"格子数": 10
},
"游戏设置": {
"背景音乐音量": 1,
"天气显示": true
}
}

View File

@@ -0,0 +1,968 @@
{
"经验值": 0,
"等级": 1,
"钱币": 0,
"农场名称": "幸运农场",
"玩家昵称": "幸运农场",
"玩家账号": "111",
"玩家密码": "tyh@19900420",
"最后登录时间": "2025年07月20日17时19分16秒",
"总游玩时间": "0时0分0秒",
"注册时间": "2025年05月21日15时00分00秒",
"个人简介": "盛产幸运草和幸运花的农场",
"农场土地": [
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": 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
},
{
"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
},
{
"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
},
{
"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
},
{
"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
},
{
"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
},
{
"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": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": 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
},
{
"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
},
{
"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
},
{
"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
},
{
"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
},
{
"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
},
{
"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"
],
"稻草人展示类型": "稻草人1",
"稻草人昵称": "稻草人",
"稻草人说的话": {
"第一句话": {
"内容": "这里是花谷",
"颜色": "52dceeff"
},
"第二句话": {
"内容": "一个盛产各种奇异花卉的地方",
"颜色": "80d5ffff"
},
"第三句话": {
"内容": "星期一,三,五,七零点种植",
"颜色": "ac52ffff"
},
"第四句话": {
"内容": "欢迎参观!",
"颜色": "f881ffff"
}
},
"稻草人昵称颜色": "b38282ff"
},
"智慧树配置": {
"距离上一次杀虫时间": 1753004237,
"距离上一次除草时间": 1753004237,
"智慧树显示的话": "",
"等级": 1,
"当前经验值": 0,
"最大经验值": 100,
"最大生命值": 100,
"当前生命值": 100,
"高度": 20
},
"签到历史": {},
"在线礼包": {
"当前日期": "2025-07-20",
"今日在线时长": 0,
"已领取礼包": [],
"登录时间": 1753003043.7163484
},
"点赞系统": {
"今日剩余点赞次数": 10,
"点赞上次刷新时间": "2025-07-20",
"总点赞数": 0
},
"新手礼包": {
"已领取": false,
"领取时间": "2025-07-12 23:02:25"
},
"体力系统": {
"当前体力值": 20,
"最大体力值": 20,
"上次刷新时间": "2025-07-20",
"上次恢复时间": 1753003043.7066433
},
"小卖部配置": {
"商品列表": [],
"格子数": 10
},
"游戏设置": {
"背景音乐音量": 1,
"天气显示": true
}
}

View File

@@ -0,0 +1,971 @@
{
"_id": {
"$oid": "689b4b9286cf953f2f4e56ee"
},
"经验值": 0,
"等级": 1,
"钱币": 0,
"农场名称": "杂交农场",
"玩家昵称": "杂交农场",
"玩家账号": "666",
"玩家密码": "tyh@19900420",
"最后登录时间": "2025年07月20日17时19分16秒",
"总游玩时间": "0时0分0秒",
"注册时间": "2025年05月21日15时00分00秒",
"个人简介": "盛产杂交果实的农场",
"农场土地": [
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": 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
},
{
"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
},
{
"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
},
{
"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
},
{
"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
},
{
"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
},
{
"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": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": 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
},
{
"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
},
{
"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
},
{
"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
},
{
"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
},
{
"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
},
{
"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"
],
"稻草人展示类型": "",
"稻草人昵称": "稻草人",
"稻草人说的话": {
"第一句话": {
"内容": "第一句话",
"颜色": "52dceeff"
},
"第二句话": {
"内容": "第二句话",
"颜色": "80d5ffff"
},
"第三句话": {
"内容": "第三句话",
"颜色": "ac52ffff"
},
"第四句话": {
"内容": "第四句话",
"颜色": "f881ffff"
}
},
"稻草人昵称颜色": "b38282ff"
},
"智慧树配置": {
"距离上一次杀虫时间": 1753004237,
"距离上一次除草时间": 1753004237,
"智慧树显示的话": "",
"等级": 1,
"当前经验值": 0,
"最大经验值": 100,
"最大生命值": 100,
"当前生命值": 100,
"高度": 20
},
"签到历史": {},
"在线礼包": {
"当前日期": "2025-07-20",
"今日在线时长": 0,
"已领取礼包": [],
"登录时间": 1753003043.7163484
},
"点赞系统": {
"今日剩余点赞次数": 10,
"点赞上次刷新时间": "2025-07-20",
"总点赞数": 0
},
"新手礼包": {
"已领取": false,
"领取时间": "2025-07-12 23:02:25"
},
"体力系统": {
"当前体力值": 20,
"最大体力值": 20,
"上次刷新时间": "2025-07-20",
"上次恢复时间": 1753003043.7066433
},
"小卖部配置": {
"商品列表": [],
"格子数": 10
},
"游戏设置": {
"背景音乐音量": 1,
"天气显示": true
}
}

View File

@@ -0,0 +1,968 @@
{
"经验值": 0,
"等级": 1,
"钱币": 0,
"农场名称": "瓜果农场",
"玩家昵称": "瓜果农场",
"玩家账号": "333",
"玩家密码": "tyh@19900420",
"最后登录时间": "2025年07月20日17时19分16秒",
"总游玩时间": "0时0分0秒",
"注册时间": "2025年05月21日15时00分00秒",
"个人简介": "盛产各种瓜果的农场",
"农场土地": [
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": 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
},
{
"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
},
{
"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
},
{
"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
},
{
"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
},
{
"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
},
{
"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": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": 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
},
{
"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
},
{
"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
},
{
"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
},
{
"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
},
{
"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
},
{
"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"
],
"稻草人展示类型": "稻草人1",
"稻草人昵称": "稻草人",
"稻草人说的话": {
"第一句话": {
"内容": "这里是花谷",
"颜色": "52dceeff"
},
"第二句话": {
"内容": "一个盛产各种奇异花卉的地方",
"颜色": "80d5ffff"
},
"第三句话": {
"内容": "星期一,三,五,七零点种植",
"颜色": "ac52ffff"
},
"第四句话": {
"内容": "欢迎参观!",
"颜色": "f881ffff"
}
},
"稻草人昵称颜色": "b38282ff"
},
"智慧树配置": {
"距离上一次杀虫时间": 1753004237,
"距离上一次除草时间": 1753004237,
"智慧树显示的话": "",
"等级": 1,
"当前经验值": 0,
"最大经验值": 100,
"最大生命值": 100,
"当前生命值": 100,
"高度": 20
},
"签到历史": {},
"在线礼包": {
"当前日期": "2025-07-20",
"今日在线时长": 0,
"已领取礼包": [],
"登录时间": 1753003043.7163484
},
"点赞系统": {
"今日剩余点赞次数": 10,
"点赞上次刷新时间": "2025-07-20",
"总点赞数": 0
},
"新手礼包": {
"已领取": false,
"领取时间": "2025-07-12 23:02:25"
},
"体力系统": {
"当前体力值": 20,
"最大体力值": 20,
"上次刷新时间": "2025-07-20",
"上次恢复时间": 1753003043.7066433
},
"小卖部配置": {
"商品列表": [],
"格子数": 10
},
"游戏设置": {
"背景音乐音量": 1,
"天气显示": true
}
}

View File

@@ -0,0 +1,968 @@
{
"经验值": 0,
"等级": 1,
"钱币": 0,
"农场名称": "稻香",
"玩家昵称": "稻香",
"玩家账号": "111",
"玩家密码": "tyh@19900420",
"最后登录时间": "2025年07月20日17时19分16秒",
"总游玩时间": "0时0分0秒",
"注册时间": "2025年05月21日15时00分00秒",
"个人简介": "盛产稻谷的农场",
"农场土地": [
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": 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
},
{
"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
},
{
"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
},
{
"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
},
{
"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
},
{
"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
},
{
"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": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": 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
},
{
"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
},
{
"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
},
{
"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
},
{
"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
},
{
"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
},
{
"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"
],
"稻草人展示类型": "稻草人1",
"稻草人昵称": "稻草人",
"稻草人说的话": {
"第一句话": {
"内容": "这里是花谷",
"颜色": "52dceeff"
},
"第二句话": {
"内容": "一个盛产各种奇异花卉的地方",
"颜色": "80d5ffff"
},
"第三句话": {
"内容": "星期一,三,五,七零点种植",
"颜色": "ac52ffff"
},
"第四句话": {
"内容": "欢迎参观!",
"颜色": "f881ffff"
}
},
"稻草人昵称颜色": "b38282ff"
},
"智慧树配置": {
"距离上一次杀虫时间": 1753004237,
"距离上一次除草时间": 1753004237,
"智慧树显示的话": "",
"等级": 1,
"当前经验值": 0,
"最大经验值": 100,
"最大生命值": 100,
"当前生命值": 100,
"高度": 20
},
"签到历史": {},
"在线礼包": {
"当前日期": "2025-07-20",
"今日在线时长": 0,
"已领取礼包": [],
"登录时间": 1753003043.7163484
},
"点赞系统": {
"今日剩余点赞次数": 10,
"点赞上次刷新时间": "2025-07-20",
"总点赞数": 0
},
"新手礼包": {
"已领取": false,
"领取时间": "2025-07-12 23:02:25"
},
"体力系统": {
"当前体力值": 20,
"最大体力值": 20,
"上次刷新时间": "2025-07-20",
"上次恢复时间": 1753003043.7066433
},
"小卖部配置": {
"商品列表": [],
"格子数": 10
},
"游戏设置": {
"背景音乐音量": 1,
"天气显示": true
}
}

View File

@@ -0,0 +1,968 @@
{
"经验值": 0,
"等级": 1,
"钱币": 0,
"农场名称": "花谷",
"玩家昵称": "花谷",
"玩家账号": "520",
"玩家密码": "tyh@19900420",
"最后登录时间": "2025年07月20日17时19分16秒",
"总游玩时间": "0时0分0秒",
"注册时间": "2025年05月21日15时00分00秒",
"个人简介": "盛产各种花卉的农场",
"农场土地": [
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": 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
},
{
"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
},
{
"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
},
{
"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
},
{
"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
},
{
"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
},
{
"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": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": true,
"is_planted": false,
"max_grow_time": 3,
"已浇水": 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
},
{
"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
},
{
"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
},
{
"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
},
{
"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
},
{
"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
},
{
"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"
],
"稻草人展示类型": "稻草人1",
"稻草人昵称": "稻草人",
"稻草人说的话": {
"第一句话": {
"内容": "这里是花谷",
"颜色": "52dceeff"
},
"第二句话": {
"内容": "一个盛产各种奇异花卉的地方",
"颜色": "80d5ffff"
},
"第三句话": {
"内容": "星期一,三,五,七零点种植",
"颜色": "ac52ffff"
},
"第四句话": {
"内容": "欢迎参观!",
"颜色": "f881ffff"
}
},
"稻草人昵称颜色": "b38282ff"
},
"智慧树配置": {
"距离上一次杀虫时间": 1753004237,
"距离上一次除草时间": 1753004237,
"智慧树显示的话": "",
"等级": 1,
"当前经验值": 0,
"最大经验值": 100,
"最大生命值": 100,
"当前生命值": 100,
"高度": 20
},
"签到历史": {},
"在线礼包": {
"当前日期": "2025-07-20",
"今日在线时长": 0,
"已领取礼包": [],
"登录时间": 1753003043.7163484
},
"点赞系统": {
"今日剩余点赞次数": 10,
"点赞上次刷新时间": "2025-07-20",
"总点赞数": 0
},
"新手礼包": {
"已领取": false,
"领取时间": "2025-07-12 23:02:25"
},
"体力系统": {
"当前体力值": 20,
"最大体力值": 20,
"上次刷新时间": "2025-07-20",
"上次恢复时间": 1753003043.7066433
},
"小卖部配置": {
"商品列表": [],
"格子数": 10
},
"游戏设置": {
"背景音乐音量": 1,
"天气显示": true
}
}

View File

@@ -0,0 +1,218 @@
# 特殊农场管理系统
## 概述
特殊农场管理系统是一个自动化的农场维护工具,用于管理游戏中的特殊农场,为玩家提供特殊的不可购买作物。系统支持定时任务和手动维护两种模式。
## 功能特性
### 1. 自动定时维护
- **执行时间**: 每天凌晨0点自动执行
- **维护内容**: 为特殊农场种植指定的作物
- **日志记录**: 详细记录维护过程和结果
### 2. 手动维护模式
- 支持即时手动维护指定农场
- 可用于测试和紧急维护
### 3. 多环境支持
- **测试环境**: 用于开发和测试
- **生产环境**: 用于正式运行
## 当前支持的特殊农场
### 杂交农场
- **农场ID**: `689b4b9286cf953f2f4e56ee`
- **种植作物**: 0号杂交树、1号杂交树
- **种植方式**: 随机全屏种植
- **土地要求**: 仅在已开垦的土地上种植
- **作物状态**: 自动设置为已浇水、已施肥、立即成熟
## 使用方法
### 方法一:使用启动脚本(推荐)
```bash
# Windows
start_special_farm.bat
# 然后选择运行模式:
# 1. 测试环境
# 2. 生产环境
# 3. 手动维护模式
```
### 方法二:直接命令行
#### 自动模式(定时任务)
```bash
# 测试环境
python SpecialFarm.py test
# 生产环境
python SpecialFarm.py production
```
#### 手动维护模式
```bash
# 手动维护杂交农场(测试环境)
python SpecialFarm.py test manual 杂交农场
# 手动维护杂交农场(生产环境)
python SpecialFarm.py production manual 杂交农场
```
### 方法三:运行测试
```bash
# 运行完整测试
python test_special_farm.py
```
## 系统架构
### 核心组件
1. **SpecialFarmManager**: 主管理类
- 负责农场配置管理
- 处理定时任务调度
- 执行种植逻辑
2. **MongoDB集成**:
- 使用 `SMYMongoDBAPI` 进行数据库操作
- 支持玩家数据和作物配置的读写
3. **定时任务**:
- 使用 `schedule` 库实现定时功能
- 支持每日凌晨0点自动执行
### 数据结构
#### 农场配置
```python
special_farms = {
"杂交农场": {
"object_id": "689b4b9286cf953f2f4e56ee",
"crop_types": ["杂交树1", "杂交树2"]
}
}
```
#### 作物种植逻辑
- 随机选择配置的作物类型
- 仅在已开垦(`is_diged=True`)的土地上种植
- 自动设置作物状态:
- `is_planted=True`
- `is_watered=True`
- `is_fertilized=True`
- `growth_time=0`(立即成熟)
## 日志系统
### 日志文件
- **文件名**: `special_farm.log`
- **位置**: 与脚本同目录
- **格式**: `时间 - 级别 - 模块 - 消息`
### 日志级别
- **INFO**: 正常操作信息
- **WARNING**: 警告信息
- **ERROR**: 错误信息
### 示例日志
```
2024-01-15 00:00:01,123 - INFO - __main__ - 开始执行每日特殊农场维护任务...
2024-01-15 00:00:02,456 - INFO - __main__ - 成功为 杂交农场 种植了 40 块土地的作物
2024-01-15 00:00:02,789 - INFO - __main__ - 每日维护任务完成: 1/1 个农场维护成功
```
## 依赖要求
### Python包
```
schedule>=1.2.0
pymongo>=4.0.0
```
### 系统要求
- Python 3.7+
- MongoDB数据库连接
- 有效的游戏数据库配置
## 扩展指南
### 添加新的特殊农场
1. **在数据库中创建农场数据**
-`playerdata` 集合中添加新的农场文档
- 记录文档的 `ObjectId`
2. **更新农场配置**
```python
# 在 SpecialFarm.py 中的 special_farms 字典添加
"新农场名称": {
"object_id": "新农场的ObjectId",
"crop_types": ["作物类型1", "作物类型2"]
}
```
3. **测试新农场**
```bash
python SpecialFarm.py test manual 新农场名称
```
### 自定义种植逻辑
可以在 `plant_crops_in_farm` 方法中修改种植逻辑:
- 改变作物选择算法
- 调整作物生长参数
- 添加特殊种植条件
## 故障排除
### 常见问题
1. **数据库连接失败**
- 检查MongoDB服务是否运行
- 验证数据库连接配置
2. **农场数据不存在**
- 确认农场ObjectId是否正确
- 检查数据库中是否存在对应文档
3. **作物配置错误**
- 验证作物类型名称是否正确
- 检查作物配置数据是否完整
### 调试模式
运行测试脚本获取详细信息:
```bash
python test_special_farm.py
```
## 安全注意事项
1. **生产环境使用**
- 确保在生产环境中使用正确的数据库配置
- 定期备份重要数据
2. **权限管理**
- 确保脚本有足够的数据库读写权限
- 限制对生产数据库的访问
3. **监控和告警**
- 定期检查日志文件
- 设置维护任务失败的告警机制
## 版本历史
- **v1.0.0**: 初始版本,支持杂交农场的自动维护
- 实现定时任务功能
- 支持手动维护模式
- 完整的日志系统
- 测试和生产环境分离
---
**作者**: AI Assistant
**创建时间**: 2024年
**最后更新**: 2024年

52
Server/test_websocket.py Normal file
View File

@@ -0,0 +1,52 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
测试WebSocket远程命令API
"""
import asyncio
import websockets
import json
async def test_client():
"""测试WebSocket客户端"""
uri = "ws://localhost:7071"
try:
async with websockets.connect(uri) as websocket:
print(f"✅ 已连接到 {uri}")
# 接收欢迎消息
welcome_msg = await websocket.recv()
print(f"收到欢迎消息: {welcome_msg}")
# 发送认证请求
auth_data = {
"type": "auth",
"auth_key": "mengya2024"
}
await websocket.send(json.dumps(auth_data))
print("已发送认证请求")
# 接收认证结果
auth_result = await websocket.recv()
print(f"认证结果: {auth_result}")
# 发送测试命令
command_data = {
"type": "command",
"command": "help"
}
await websocket.send(json.dumps(command_data))
print("已发送help命令")
# 接收命令结果
command_result = await websocket.recv()
print(f"命令结果: {command_result}")
except Exception as e:
print(f"❌ 连接失败: {e}")
if __name__ == "__main__":
print("开始测试WebSocket连接...")
asyncio.run(test_client())

View File

@@ -0,0 +1,199 @@
# 特殊农场系统优化说明
## 概述
特殊农场系统已经过全面优化,解决了服务器重启时间重置和性能问题。现在系统更加稳定、高效,不会影响游戏服务器的正常运行。
## 主要优化内容
### 1. 解决服务器重启时间重置问题
**问题**: 之前每次服务器重启都会立即执行维护任务,导致重复种植。
**解决方案**:
- 添加维护时间记录功能
- 服务器启动时检查当日是否已执行维护
- 只有当天未维护过才会执行维护任务
- 确保每天只执行一次维护,无论服务器重启多少次
### 2. 性能优化
**CPU使用优化**:
- 调度器检查间隔从1分钟优化到5分钟
- 减少不必要的CPU占用
- 后台线程使用守护模式,不阻塞主进程
**内存管理优化**:
- 改进资源清理机制
- 服务器停止时正确释放特殊农场系统资源
- 避免内存泄漏
### 3. 稳定性改进
**错误处理**:
- 增强异常处理机制
- 添加详细的日志记录
- 系统出错时自动恢复
**资源管理**:
- 正确的启动和停止流程
- 线程安全的操作
- 避免资源竞争
## 系统工作原理
### 定时任务调度
```
启动服务器 → 初始化特殊农场管理器 → 检查当日维护状态
如果未维护 → 执行维护任务 → 记录维护时间
如果已维护 → 跳过维护任务
启动后台调度器 → 每天凌晨0点自动维护
```
### 维护任务内容
1. **土地开垦**: 确保所有土地都处于已开垦状态
2. **作物种植**: 随机种植杂交树1或杂交树2
3. **状态设置**: 设置作物为立即成熟状态
4. **记录更新**: 更新维护时间记录
## 使用方法
### 正常启动
特殊农场系统已集成到游戏服务器中,无需单独启动:
```bash
cd Server
python TCPGameServer.py
```
### 手动维护
如果需要手动执行维护任务:
```bash
# 维护所有特殊农场
python SpecialFarm.py test manual
# 维护指定农场
python SpecialFarm.py test manual 杂交农场
```
### 性能监控
使用性能监控工具检查系统资源使用:
```bash
python monitor_special_farm.py
```
### 测试优化效果
运行测试脚本验证优化效果:
```bash
python test_special_farm_optimization.py
```
## 配置说明
### 特殊农场配置
`SpecialFarm.py` 中的 `special_farms` 字典:
```python
self.special_farms = {
"杂交农场": {
"object_id": "689b4b9286cf953f2f4e56ee",
"crops": ["杂交树1", "杂交树2"],
"description": "专门种植杂交树的特殊农场"
}
}
```
### 调度器配置
- **维护时间**: 每天凌晨0点
- **检查间隔**: 5分钟
- **运行模式**: 后台守护线程
## 性能指标
### 优化前 vs 优化后
| 指标 | 优化前 | 优化后 | 改进 |
|------|--------|--------|------|
| CPU检查间隔 | 1分钟 | 5分钟 | 减少80%检查频率 |
| 重启重复执行 | 是 | 否 | 避免重复维护 |
| 资源清理 | 不完整 | 完整 | 防止内存泄漏 |
| 错误恢复 | 基础 | 增强 | 提高稳定性 |
### 预期性能表现
- **CPU使用率**: < 1%(正常运行时)
- **内存使用**: < 50MB额外占用
- **线程数**: +1后台调度线程
- **启动时间**: < 1秒
## 故障排除
### 常见问题
1. **特殊农场未自动维护**
- 检查MongoDB连接是否正常
- 查看日志文件 `special_farm.log`
- 确认特殊农场配置正确
2. **服务器启动缓慢**
- 检查MongoDB连接速度
- 查看是否有网络问题
- 考虑使用本地MongoDB
3. **内存使用过高**
- 运行性能监控工具
- 检查是否有内存泄漏
- 重启服务器释放资源
### 日志文件
- **特殊农场日志**: `special_farm.log`
- **服务器日志**: 控制台输出
- **MongoDB日志**: MongoDB服务器日志
## 维护建议
### 定期检查
1. **每周检查**:
- 查看 `special_farm.log` 日志
- 确认维护任务正常执行
- 检查特殊农场作物状态
2. **每月检查**:
- 运行性能监控工具
- 清理过期日志文件
- 检查MongoDB数据库状态
### 备份建议
- 定期备份MongoDB数据库
- 保存特殊农场配置文件
- 记录重要的配置变更
## 技术支持
如果遇到问题,请提供以下信息:
1. 错误日志内容
2. 服务器运行环境
3. MongoDB版本和配置
4. 问题复现步骤
---
**注意**: 此优化版本向后兼容,不会影响现有的游戏数据和功能。

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dsds2gsvqxfak"
path="res://.godot/imported/大喇叭.webp-02c8c72b3970655e1b81cbf9fcfdcd24.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/游戏UI/大喇叭.webp"
dest_files=["res://.godot/imported/大喇叭.webp-02c8c72b3970655e1b81cbf9fcfdcd24.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.01
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

View File

@@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bp6v00xvoqfu0"
path="res://.godot/imported/黄皮大耗子.webp-19321ac49e962255d8926647294015ea.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/菜单UI/黄皮大耗子.webp"
dest_files=["res://.godot/imported/黄皮大耗子.webp-19321ac49e962255d8926647294015ea.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.01
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://b8k7gknqsokt2"
path="res://.godot/imported/占卜台.webp-234660de4b482ef3624328b2b904cb29.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/装饰物图片/占卜台.webp"
dest_files=["res://.godot/imported/占卜台.webp-234660de4b482ef3624328b2b904cb29.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.01
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

@@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://c1lviq3nc00u5"
path="res://.godot/imported/宠物天梯赛.webp-2a765372409b429f9288865d45b96954.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/装饰物图片/宠物天梯赛.webp"
dest_files=["res://.godot/imported/宠物天梯赛.webp-2a765372409b429f9288865d45b96954.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.01
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bwljgu2ltfc7j"
path="res://.godot/imported/宠物小窝.webp-45f0370b5de3e03c1a4004da4d6108db.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/装饰物图片/宠物小窝.webp"
dest_files=["res://.godot/imported/宠物小窝.webp-45f0370b5de3e03c1a4004da4d6108db.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.01
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dcfb173iikas"
path="res://.godot/imported/玩玩小游戏.webp-fce01287cb7811ea6f185496f82bdffe.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/装饰物图片/玩玩小游戏.webp"
dest_files=["res://.godot/imported/玩玩小游戏.webp-fce01287cb7811ea6f185496f82bdffe.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.01
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cpsfkh7khetfb"
path="res://.godot/imported/神秘农场.webp-b11071d89abfe87aa582f2e485878ab4.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/装饰物图片/神秘农场.webp"
dest_files=["res://.godot/imported/神秘农场.webp-b11071d89abfe87aa582f2e485878ab4.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.01
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

View File

@@ -86,8 +86,7 @@ common/physics_interpolation=true
[rendering]
textures/canvas_textures/default_texture_filter=0
renderer/rendering_method="gl_compatibility"
renderer/rendering_method.mobile="gl_compatibility"
renderer/rendering_method="mobile"
textures/vram_compression/import_etc2_astc=true
textures/webp_compression/compression_method=3
viewport/hdr_2d=true

View File

@@ -1,76 +0,0 @@
extends Node
# 子弹系统测试脚本
# 用于验证每种子弹的独立创建函数功能
func _ready():
test_bullet_system()
func test_bullet_system():
print("=== 子弹系统测试开始 ===")
# 创建子弹实例
var bullet_scene = preload("res://Scene/NewPet/BulletBase.tscn")
var bullet = bullet_scene.instantiate()
add_child(bullet)
# 测试获取所有子弹名称
print("\n可用子弹类型:")
var bullet_names = bullet.get_all_bullet_names()
for name in bullet_names:
print("- %s" % name)
# 测试每种子弹的创建
print("\n=== 测试各种子弹创建 ===")
# 测试小蓝弹
print("\n测试小蓝弹:")
bullet.create_blue_bullet()
print("速度: %.1f, 伤害: %.1f, 生存时间: %.1f" % [bullet.speed, bullet.damage, bullet.lifetime])
# 测试小红弹
print("\n测试小红弹:")
bullet.create_red_bullet()
print("速度: %.1f, 伤害: %.1f, 生存时间: %.1f" % [bullet.speed, bullet.damage, bullet.lifetime])
# 测试长橙弹
print("\n测试长橙弹:")
bullet.create_long_orange_bullet()
print("速度: %.1f, 伤害: %.1f, 生存时间: %.1f, 最大距离: %.1f" % [bullet.speed, bullet.damage, bullet.lifetime, bullet.max_distance])
# 测试黄色闪电
print("\n测试黄色闪电:")
bullet.create_yellow_lightning_bullet()
print("速度: %.1f, 伤害: %.1f, 生存时间: %.1f, 最大距离: %.1f" % [bullet.speed, bullet.damage, bullet.lifetime, bullet.max_distance])
# 测试紫色闪电
print("\n测试紫色闪电:")
bullet.create_purple_lightning_bullet()
print("速度: %.1f, 伤害: %.1f, 生存时间: %.1f, 最大距离: %.1f" % [bullet.speed, bullet.damage, bullet.lifetime, bullet.max_distance])
# 测试通过名称创建子弹
print("\n=== 测试通过名称创建子弹 ===")
bullet.create_bullet_by_name("小粉弹")
print("小粉弹 - 速度: %.1f, 伤害: %.1f" % [bullet.speed, bullet.damage])
bullet.create_bullet_by_name("长绿弹")
print("长绿弹 - 速度: %.1f, 伤害: %.1f" % [bullet.speed, bullet.damage])
# 测试获取子弹图标
print("\n=== 测试获取子弹图标 ===")
for name in ["小蓝弹", "小红弹", "黄色闪电"]:
var icon_path = bullet.get_bullet_icon(name)
print("%s 图标路径: %s" % [name, icon_path])
# 测试setup函数的新功能
print("\n=== 测试setup函数 ===")
bullet.setup(Vector2.RIGHT, 100.0, 10.0, null, "绿色闪电")
print("使用setup创建绿色闪电 - 速度: %.1f, 伤害: %.1f" % [bullet.speed, bullet.damage])
bullet.setup(Vector2.LEFT, 200.0, 15.0, null) # 不指定类型
print("使用setup创建默认子弹 - 速度: %.1f, 伤害: %.1f" % [bullet.speed, bullet.damage])
print("\n=== 子弹系统测试完成 ===")
# 清理测试对象
bullet.queue_free()

View File

@@ -1 +0,0 @@
uid://bkxv5024t46ya

View File

@@ -1,49 +0,0 @@
extends Node
# 测试武器系统的简单脚本
func _ready():
print("开始测试武器系统...")
# 创建武器系统实例
var weapon_system = WeaponBase.new()
# 测试武器数据
print("武器列表:")
for weapon_name in weapon_system.get_all_weapon_names():
print(" - %s: %s" % [weapon_name, weapon_system.get_weapon_icon(weapon_name)])
# 创建一个模拟宠物对象来测试武器效果
var mock_pet = Node.new()
mock_pet.set_script(preload("res://Scene/NewPet/NewPetBase.gd"))
mock_pet.pet_name = "测试宠物"
mock_pet.base_attack_damage = 25.0
mock_pet.crit_rate = 0.1
mock_pet.attack_speed = 1.0
mock_pet.armor_penetration = 0.0
mock_pet.attack_range = 100.0
mock_pet.knockback_force = 300.0
print("\n测试武器效果:")
print("装备前属性:")
print(" 攻击力: %.1f" % mock_pet.base_attack_damage)
print(" 暴击率: %.2f" % mock_pet.crit_rate)
print(" 攻击速度: %.1f" % mock_pet.attack_speed)
# 测试装备钻石剑
weapon_system.apply_weapon_effect(mock_pet, "钻石剑")
print("\n装备钻石剑后:")
print(" 攻击力: %.1f" % mock_pet.base_attack_damage)
print(" 暴击率: %.2f" % mock_pet.crit_rate)
print(" 攻击速度: %.1f" % mock_pet.attack_speed)
# 测试卸下武器
weapon_system.remove_weapon_effect(mock_pet, "钻石剑")
print("\n卸下钻石剑后:")
print(" 攻击力: %.1f" % mock_pet.base_attack_damage)
print(" 暴击率: %.2f" % mock_pet.crit_rate)
print(" 攻击速度: %.1f" % mock_pet.attack_speed)
print("\n武器系统测试完成!")
# 清理
mock_pet.queue_free()

View File

@@ -1 +0,0 @@
uid://cc5eho78s6v6k