完成部分服务器数据向MongoDB数据库迁移
This commit is contained in:
@@ -23,12 +23,21 @@ var music_files: Array[String] = []
|
|||||||
var current_index: int = 0
|
var current_index: int = 0
|
||||||
var played_indices: Array[int] = [] # 随机模式已播放的索引
|
var played_indices: Array[int] = [] # 随机模式已播放的索引
|
||||||
|
|
||||||
|
# 音量控制相关
|
||||||
|
var current_volume: float = 1.0 # 当前音量 (0.0-1.0)
|
||||||
|
var is_muted: bool = false # 是否静音
|
||||||
|
var volume_before_mute: float = 1.0 # 静音前的音量
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
# 创建音频播放器
|
# 创建音频播放器
|
||||||
audio_player = AudioStreamPlayer.new()
|
audio_player = AudioStreamPlayer.new()
|
||||||
add_child(audio_player)
|
add_child(audio_player)
|
||||||
audio_player.finished.connect(_on_music_finished)
|
audio_player.finished.connect(_on_music_finished)
|
||||||
|
|
||||||
|
# 从全局变量读取初始音量设置
|
||||||
|
current_volume = GlobalVariables.BackgroundMusicVolume
|
||||||
|
audio_player.volume_db = linear_to_db(current_volume)
|
||||||
|
|
||||||
# 加载音乐文件
|
# 加载音乐文件
|
||||||
_load_music_files()
|
_load_music_files()
|
||||||
|
|
||||||
@@ -164,3 +173,70 @@ func add_music_file(file_path: String) -> bool:
|
|||||||
else:
|
else:
|
||||||
print("音乐文件不存在: ", file_path)
|
print("音乐文件不存在: ", file_path)
|
||||||
return false
|
return false
|
||||||
|
|
||||||
|
# ============================= 音量控制功能 =====================================
|
||||||
|
|
||||||
|
func set_volume(volume: float):
|
||||||
|
"""设置音量 (0.0-1.0)"""
|
||||||
|
current_volume = clamp(volume, 0.0, 1.0)
|
||||||
|
if not is_muted:
|
||||||
|
audio_player.volume_db = linear_to_db(current_volume)
|
||||||
|
print("背景音乐音量设置为: ", current_volume)
|
||||||
|
|
||||||
|
func get_volume() -> float:
|
||||||
|
"""获取当前音量"""
|
||||||
|
return current_volume
|
||||||
|
|
||||||
|
func set_mute(muted: bool):
|
||||||
|
"""设置静音状态"""
|
||||||
|
if muted and not is_muted:
|
||||||
|
# 静音
|
||||||
|
volume_before_mute = current_volume
|
||||||
|
audio_player.volume_db = -80.0 # 设置为最小音量
|
||||||
|
is_muted = true
|
||||||
|
print("背景音乐已静音")
|
||||||
|
elif not muted and is_muted:
|
||||||
|
# 取消静音
|
||||||
|
audio_player.volume_db = linear_to_db(current_volume)
|
||||||
|
is_muted = false
|
||||||
|
print("背景音乐取消静音")
|
||||||
|
|
||||||
|
func toggle_mute():
|
||||||
|
"""切换静音状态"""
|
||||||
|
set_mute(not is_muted)
|
||||||
|
|
||||||
|
func is_music_muted() -> bool:
|
||||||
|
"""获取静音状态"""
|
||||||
|
return is_muted
|
||||||
|
|
||||||
|
func pause():
|
||||||
|
"""暂停音乐"""
|
||||||
|
if audio_player.playing:
|
||||||
|
audio_player.stream_paused = true
|
||||||
|
print("背景音乐已暂停")
|
||||||
|
|
||||||
|
func resume():
|
||||||
|
"""恢复音乐"""
|
||||||
|
if audio_player.stream_paused:
|
||||||
|
audio_player.stream_paused = false
|
||||||
|
print("背景音乐已恢复")
|
||||||
|
|
||||||
|
func stop():
|
||||||
|
"""停止音乐"""
|
||||||
|
if audio_player.playing:
|
||||||
|
audio_player.stop()
|
||||||
|
print("背景音乐已停止")
|
||||||
|
|
||||||
|
func is_playing() -> bool:
|
||||||
|
"""检查是否正在播放"""
|
||||||
|
return audio_player.playing and not audio_player.stream_paused
|
||||||
|
|
||||||
|
func get_current_position() -> float:
|
||||||
|
"""获取当前播放位置(秒)"""
|
||||||
|
return audio_player.get_playback_position()
|
||||||
|
|
||||||
|
func get_current_length() -> float:
|
||||||
|
"""获取当前音乐总长度(秒)"""
|
||||||
|
if audio_player.stream:
|
||||||
|
return audio_player.stream.get_length()
|
||||||
|
return 0.0
|
||||||
|
|||||||
@@ -1,131 +0,0 @@
|
|||||||
extends Node
|
|
||||||
|
|
||||||
## 简单背景音乐播放器
|
|
||||||
## 自动加载指定文件夹的音乐文件,支持顺序和随机循环播放
|
|
||||||
|
|
||||||
# 播放模式
|
|
||||||
enum PlayMode {
|
|
||||||
SEQUENTIAL, # 顺序循环
|
|
||||||
RANDOM # 随机循环
|
|
||||||
}
|
|
||||||
|
|
||||||
# 配置
|
|
||||||
@export var music_folder: String = "res://assets/音乐/" # 音乐文件夹路径
|
|
||||||
@export var play_mode: PlayMode = PlayMode.SEQUENTIAL # 播放模式
|
|
||||||
@export var auto_start: bool = true # 自动开始播放
|
|
||||||
|
|
||||||
# 内部变量
|
|
||||||
var audio_player: AudioStreamPlayer
|
|
||||||
var music_files: Array[String] = []
|
|
||||||
var current_index: int = 0
|
|
||||||
var played_indices: Array[int] = [] # 随机模式已播放的索引
|
|
||||||
|
|
||||||
func _ready():
|
|
||||||
# 创建音频播放器
|
|
||||||
audio_player = AudioStreamPlayer.new()
|
|
||||||
add_child(audio_player)
|
|
||||||
audio_player.finished.connect(_on_music_finished)
|
|
||||||
|
|
||||||
# 加载音乐文件
|
|
||||||
_load_music_files()
|
|
||||||
|
|
||||||
# 自动开始播放
|
|
||||||
if auto_start and music_files.size() > 0:
|
|
||||||
play_next()
|
|
||||||
|
|
||||||
func _load_music_files():
|
|
||||||
"""加载指定文件夹下的音乐文件"""
|
|
||||||
music_files.clear()
|
|
||||||
|
|
||||||
var dir = DirAccess.open(music_folder)
|
|
||||||
if dir:
|
|
||||||
dir.list_dir_begin()
|
|
||||||
var file_name = dir.get_next()
|
|
||||||
|
|
||||||
while file_name != "":
|
|
||||||
if not dir.current_is_dir():
|
|
||||||
var extension = file_name.get_extension().to_lower()
|
|
||||||
# 支持常见音频格式
|
|
||||||
if extension in ["mp3", "ogg", "wav"]:
|
|
||||||
music_files.append(music_folder + file_name)
|
|
||||||
print("加载音乐: ", file_name)
|
|
||||||
file_name = dir.get_next()
|
|
||||||
|
|
||||||
print("总共加载了 ", music_files.size(), " 首音乐")
|
|
||||||
else:
|
|
||||||
print("无法打开音乐文件夹: ", music_folder)
|
|
||||||
|
|
||||||
func play_next():
|
|
||||||
"""播放下一首音乐"""
|
|
||||||
if music_files.size() == 0:
|
|
||||||
print("没有音乐文件可播放")
|
|
||||||
return
|
|
||||||
|
|
||||||
# 根据播放模式获取下一首音乐的索引
|
|
||||||
match play_mode:
|
|
||||||
PlayMode.SEQUENTIAL:
|
|
||||||
current_index = (current_index + 1) % music_files.size()
|
|
||||||
PlayMode.RANDOM:
|
|
||||||
current_index = _get_random_index()
|
|
||||||
|
|
||||||
# 播放音乐
|
|
||||||
_play_music(current_index)
|
|
||||||
|
|
||||||
func _get_random_index() -> int:
|
|
||||||
"""获取随机音乐索引(避免重复直到所有歌曲都播放过)"""
|
|
||||||
# 如果所有歌曲都播放过了,重置列表
|
|
||||||
if played_indices.size() >= music_files.size():
|
|
||||||
played_indices.clear()
|
|
||||||
|
|
||||||
# 获取未播放的歌曲索引
|
|
||||||
var available_indices: Array[int] = []
|
|
||||||
for i in range(music_files.size()):
|
|
||||||
if i not in played_indices:
|
|
||||||
available_indices.append(i)
|
|
||||||
|
|
||||||
# 随机选择一个
|
|
||||||
if available_indices.size() > 0:
|
|
||||||
var random_choice = available_indices[randi() % available_indices.size()]
|
|
||||||
played_indices.append(random_choice)
|
|
||||||
return random_choice
|
|
||||||
|
|
||||||
return 0
|
|
||||||
|
|
||||||
func _play_music(index: int):
|
|
||||||
"""播放指定索引的音乐"""
|
|
||||||
if index < 0 or index >= music_files.size():
|
|
||||||
return
|
|
||||||
|
|
||||||
var music_path = music_files[index]
|
|
||||||
var audio_stream = load(music_path)
|
|
||||||
|
|
||||||
if audio_stream:
|
|
||||||
audio_player.stream = audio_stream
|
|
||||||
audio_player.play()
|
|
||||||
print("正在播放: ", music_path.get_file())
|
|
||||||
else:
|
|
||||||
print("加载音乐失败: ", music_path)
|
|
||||||
|
|
||||||
func _on_music_finished():
|
|
||||||
"""音乐播放完成时自动播放下一首"""
|
|
||||||
play_next()
|
|
||||||
|
|
||||||
# 公共接口方法
|
|
||||||
func set_play_mode(mode: PlayMode):
|
|
||||||
"""设置播放模式"""
|
|
||||||
play_mode = mode
|
|
||||||
played_indices.clear() # 重置随机播放历史
|
|
||||||
print("播放模式设置为: ", "顺序循环" if mode == PlayMode.SEQUENTIAL else "随机循环")
|
|
||||||
|
|
||||||
func toggle_play_mode():
|
|
||||||
"""切换播放模式"""
|
|
||||||
if play_mode == PlayMode.SEQUENTIAL:
|
|
||||||
set_play_mode(PlayMode.RANDOM)
|
|
||||||
else:
|
|
||||||
set_play_mode(PlayMode.SEQUENTIAL)
|
|
||||||
|
|
||||||
func get_current_music_name() -> String:
|
|
||||||
"""获取当前播放的音乐名称"""
|
|
||||||
if current_index >= 0 and current_index < music_files.size():
|
|
||||||
return music_files[current_index].get_file()
|
|
||||||
return ""
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://cq0ug1c7nibf1
|
|
||||||
@@ -39,7 +39,6 @@ offset_right = 40.0
|
|||||||
offset_bottom = 40.0
|
offset_bottom = 40.0
|
||||||
|
|
||||||
[node name="ground_sprite" type="Sprite2D" parent="."]
|
[node name="ground_sprite" type="Sprite2D" parent="."]
|
||||||
modulate = Color(0.8, 0.8, 0.8, 1)
|
|
||||||
material = SubResource("ShaderMaterial_v46ok")
|
material = SubResource("ShaderMaterial_v46ok")
|
||||||
position = Vector2(50, 63)
|
position = Vector2(50, 63)
|
||||||
scale = Vector2(0.135, 0.135)
|
scale = Vector2(0.135, 0.135)
|
||||||
@@ -50,11 +49,6 @@ material = SubResource("ShaderMaterial_s5pb0")
|
|||||||
position = Vector2(51, 45)
|
position = Vector2(51, 45)
|
||||||
scale = Vector2(0.339844, 0.363281)
|
scale = Vector2(0.339844, 0.363281)
|
||||||
|
|
||||||
[node name="old_crop_sprite" type="Sprite2D" parent="."]
|
|
||||||
material = SubResource("ShaderMaterial_s5pb0")
|
|
||||||
position = Vector2(51, 39)
|
|
||||||
scale = Vector2(0.06, 0.06)
|
|
||||||
|
|
||||||
[node name="ProgressBar" type="ProgressBar" parent="."]
|
[node name="ProgressBar" type="ProgressBar" parent="."]
|
||||||
visible = false
|
visible = false
|
||||||
material = SubResource("ShaderMaterial_cyybs")
|
material = SubResource("ShaderMaterial_cyybs")
|
||||||
|
|||||||
@@ -1,9 +1,203 @@
|
|||||||
extends Panel
|
extends Panel
|
||||||
|
#游戏设置面板
|
||||||
|
|
||||||
|
# UI组件引用
|
||||||
|
@onready var background_music_h_slider: HSlider = $Scroll/Panel/BackgroundMusicHSlider
|
||||||
|
@onready var weather_system_check: CheckButton = $Scroll/Panel/WeatherSystemCheck
|
||||||
|
@onready var quit_button: Button = $QuitButton
|
||||||
|
@onready var sure_button: Button = $SureButton
|
||||||
|
@onready var refresh_button: Button = $RefreshButton
|
||||||
|
|
||||||
|
# 引用主游戏和其他组件
|
||||||
|
@onready var main_game = get_node("/root/main")
|
||||||
|
@onready var tcp_network_manager_panel: Panel = get_node("/root/main/UI/BigPanel/TCPNetworkManagerPanel")
|
||||||
|
|
||||||
|
# 游戏设置数据
|
||||||
|
var game_settings: Dictionary = {
|
||||||
|
"背景音乐音量": 1.0,
|
||||||
|
"天气显示": true
|
||||||
|
}
|
||||||
|
|
||||||
|
# 临时设置数据(用户修改但未确认的设置)
|
||||||
|
var temp_settings: Dictionary = {}
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
self.hide()
|
self.hide()
|
||||||
pass
|
|
||||||
|
# 连接信号
|
||||||
|
quit_button.pressed.connect(_on_quit_button_pressed)
|
||||||
|
sure_button.pressed.connect(_on_sure_button_pressed)
|
||||||
|
refresh_button.pressed.connect(_on_refresh_button_pressed)
|
||||||
|
|
||||||
|
# 设置音量滑块范围为0-1
|
||||||
|
background_music_h_slider.min_value = 0.0
|
||||||
|
background_music_h_slider.max_value = 1.0
|
||||||
|
background_music_h_slider.step = 0.01
|
||||||
|
background_music_h_slider.value_changed.connect(_on_background_music_h_slider_value_changed)
|
||||||
|
weather_system_check.toggled.connect(_on_weather_system_check_toggled)
|
||||||
|
|
||||||
|
# 初始化设置值
|
||||||
|
_load_settings_from_global()
|
||||||
|
|
||||||
|
# 当面板可见性改变时
|
||||||
|
visibility_changed.connect(_on_visibility_changed)
|
||||||
|
|
||||||
|
func _on_visibility_changed():
|
||||||
|
"""面板可见性改变时的处理"""
|
||||||
|
if visible:
|
||||||
|
# 面板显示时,刷新设置值
|
||||||
|
_load_settings_from_global()
|
||||||
|
_update_ui_from_settings()
|
||||||
|
|
||||||
|
# 禁用缩放功能
|
||||||
|
GlobalVariables.isZoomDisabled = true
|
||||||
|
else:
|
||||||
|
# 面板隐藏时,恢复缩放功能
|
||||||
|
GlobalVariables.isZoomDisabled = false
|
||||||
|
|
||||||
|
func _load_settings_from_global():
|
||||||
|
"""从全局变量和玩家数据加载设置"""
|
||||||
|
# 从GlobalVariables加载默认设置
|
||||||
|
game_settings["背景音乐音量"] = GlobalVariables.BackgroundMusicVolume
|
||||||
|
game_settings["天气显示"] = not GlobalVariables.DisableWeatherDisplay
|
||||||
|
|
||||||
|
# 如果主游戏已登录,尝试从玩家数据加载设置
|
||||||
|
if main_game and main_game.login_data and main_game.login_data.has("游戏设置"):
|
||||||
|
var player_settings = main_game.login_data["游戏设置"]
|
||||||
|
if player_settings.has("背景音乐音量"):
|
||||||
|
game_settings["背景音乐音量"] = player_settings["背景音乐音量"]
|
||||||
|
if player_settings.has("天气显示"):
|
||||||
|
game_settings["天气显示"] = player_settings["天气显示"]
|
||||||
|
|
||||||
|
# 初始化临时设置
|
||||||
|
temp_settings = game_settings.duplicate()
|
||||||
|
|
||||||
|
func _update_ui_from_settings():
|
||||||
|
"""根据设置数据更新UI"""
|
||||||
|
# 更新音量滑块
|
||||||
|
background_music_h_slider.value = temp_settings["背景音乐音量"]
|
||||||
|
|
||||||
|
# 更新天气显示复选框(注意:复选框表示"关闭天气显示")
|
||||||
|
weather_system_check.button_pressed = not temp_settings["天气显示"]
|
||||||
|
|
||||||
|
func _apply_settings_immediately():
|
||||||
|
"""立即应用设置(不保存到服务端)"""
|
||||||
|
# 应用背景音乐音量设置
|
||||||
|
_apply_music_volume_setting()
|
||||||
|
|
||||||
|
# 应用天气显示设置
|
||||||
|
_apply_weather_display_setting()
|
||||||
|
|
||||||
|
func _save_settings_to_server():
|
||||||
|
"""保存设置到服务端"""
|
||||||
|
# 更新正式设置
|
||||||
|
game_settings = temp_settings.duplicate()
|
||||||
|
|
||||||
|
# 应用设置
|
||||||
|
_apply_settings_immediately()
|
||||||
|
|
||||||
|
# 如果已登录,保存到玩家数据并同步到服务端
|
||||||
|
if main_game and main_game.login_data:
|
||||||
|
main_game.login_data["游戏设置"] = game_settings.duplicate()
|
||||||
|
|
||||||
|
# 发送设置到服务端保存
|
||||||
|
if tcp_network_manager_panel and tcp_network_manager_panel.has_method("is_connected_to_server") and tcp_network_manager_panel.is_connected_to_server():
|
||||||
|
_send_settings_to_server()
|
||||||
|
|
||||||
|
func _apply_music_volume_setting():
|
||||||
|
"""应用背景音乐音量设置"""
|
||||||
|
var bgm_player = main_game.get_node_or_null("GameBGMPlayer")
|
||||||
|
if bgm_player and bgm_player.has_method("set_volume"):
|
||||||
|
bgm_player.set_volume(temp_settings["背景音乐音量"])
|
||||||
|
|
||||||
|
func _apply_weather_display_setting():
|
||||||
|
"""应用天气显示设置"""
|
||||||
|
var weather_system = main_game.get_node_or_null("WeatherSystem")
|
||||||
|
if weather_system and weather_system.has_method("set_weather_display_enabled"):
|
||||||
|
weather_system.set_weather_display_enabled(temp_settings["天气显示"])
|
||||||
|
|
||||||
|
func _send_settings_to_server():
|
||||||
|
"""发送设置到服务端保存"""
|
||||||
|
if tcp_network_manager_panel and tcp_network_manager_panel.has_method("send_message"):
|
||||||
|
var message = {
|
||||||
|
"type": "save_game_settings",
|
||||||
|
"settings": game_settings,
|
||||||
|
"timestamp": Time.get_unix_time_from_system()
|
||||||
|
}
|
||||||
|
|
||||||
|
if tcp_network_manager_panel.send_message(message):
|
||||||
|
print("游戏设置已发送到服务端保存")
|
||||||
|
else:
|
||||||
|
print("发送游戏设置到服务端失败")
|
||||||
|
|
||||||
func _on_quit_button_pressed() -> void:
|
func _on_quit_button_pressed() -> void:
|
||||||
|
"""关闭设置面板"""
|
||||||
self.hide()
|
self.hide()
|
||||||
pass
|
|
||||||
|
func _on_background_music_h_slider_value_changed(value: float) -> void:
|
||||||
|
"""背景音乐音量滑块值改变"""
|
||||||
|
temp_settings["背景音乐音量"] = value
|
||||||
|
# 立即应用音量设置(不保存到服务端)
|
||||||
|
_apply_music_volume_setting()
|
||||||
|
|
||||||
|
# 显示当前音量百分比
|
||||||
|
var volume_percent = int(value * 100)
|
||||||
|
|
||||||
|
func _on_weather_system_check_toggled(toggled_on: bool) -> void:
|
||||||
|
"""天气系统复选框切换"""
|
||||||
|
# 复选框表示"关闭天气显示",所以需要取反
|
||||||
|
temp_settings["天气显示"] = not toggled_on
|
||||||
|
# 立即应用天气设置(不保存到服务端)
|
||||||
|
_apply_weather_display_setting()
|
||||||
|
|
||||||
|
# 显示提示
|
||||||
|
var status_text = "已开启" if temp_settings["天气显示"] else "已关闭"
|
||||||
|
Toast.show("天气显示" + status_text, Color.YELLOW)
|
||||||
|
|
||||||
|
#确认修改设置按钮,点击这个才会发送数据到服务端
|
||||||
|
func _on_sure_button_pressed() -> void:
|
||||||
|
"""确认修改设置"""
|
||||||
|
_save_settings_to_server()
|
||||||
|
Toast.show("设置已保存!", Color.GREEN)
|
||||||
|
|
||||||
|
#刷新设置面板,从服务端加载游戏设置数据
|
||||||
|
func _on_refresh_button_pressed() -> void:
|
||||||
|
"""刷新设置"""
|
||||||
|
_load_settings_from_global()
|
||||||
|
_update_ui_from_settings()
|
||||||
|
_apply_settings_immediately()
|
||||||
|
Toast.show("设置已刷新!", Color.CYAN)
|
||||||
|
|
||||||
|
# 移除原来的自动保存方法,避免循环调用
|
||||||
|
func _on_background_music_h_slider_drag_ended(value_changed: bool) -> void:
|
||||||
|
"""背景音乐音量滑块拖拽结束(保留以兼容场景连接)"""
|
||||||
|
# 不再自动保存,只显示提示
|
||||||
|
if value_changed:
|
||||||
|
var volume_percent = int(background_music_h_slider.value * 100)
|
||||||
|
|
||||||
|
# 公共方法,供外部调用
|
||||||
|
func refresh_settings():
|
||||||
|
"""刷新设置(从服务端或本地重新加载)"""
|
||||||
|
_load_settings_from_global()
|
||||||
|
_update_ui_from_settings()
|
||||||
|
_apply_settings_immediately()
|
||||||
|
|
||||||
|
func get_current_settings() -> Dictionary:
|
||||||
|
"""获取当前设置"""
|
||||||
|
return game_settings.duplicate()
|
||||||
|
|
||||||
|
func apply_settings_from_server(server_settings: Dictionary):
|
||||||
|
"""应用从服务端接收到的设置(避免循环调用)"""
|
||||||
|
if server_settings.has("背景音乐音量"):
|
||||||
|
game_settings["背景音乐音量"] = server_settings["背景音乐音量"]
|
||||||
|
temp_settings["背景音乐音量"] = server_settings["背景音乐音量"]
|
||||||
|
if server_settings.has("天气显示"):
|
||||||
|
game_settings["天气显示"] = server_settings["天气显示"]
|
||||||
|
temp_settings["天气显示"] = server_settings["天气显示"]
|
||||||
|
|
||||||
|
# 只更新UI,不再触发保存
|
||||||
|
if visible:
|
||||||
|
_update_ui_from_settings()
|
||||||
|
_apply_settings_immediately()
|
||||||
|
|
||||||
|
print("已应用来自服务端的游戏设置")
|
||||||
|
|||||||
@@ -23,8 +23,10 @@ corner_radius_bottom_left = 10
|
|||||||
corner_detail = 20
|
corner_detail = 20
|
||||||
|
|
||||||
[node name="GameSettingPanel" type="Panel"]
|
[node name="GameSettingPanel" type="Panel"]
|
||||||
offset_right = 1398.0
|
offset_left = 151.0
|
||||||
offset_bottom = 720.0
|
offset_top = 74.0
|
||||||
|
offset_right = 1549.0
|
||||||
|
offset_bottom = 794.0
|
||||||
scale = Vector2(0.8, 0.8)
|
scale = Vector2(0.8, 0.8)
|
||||||
theme_override_styles/panel = SubResource("StyleBoxFlat_0c52c")
|
theme_override_styles/panel = SubResource("StyleBoxFlat_0c52c")
|
||||||
script = ExtResource("1_0c52c")
|
script = ExtResource("1_0c52c")
|
||||||
@@ -78,18 +80,84 @@ layout_mode = 2
|
|||||||
size_flags_horizontal = 3
|
size_flags_horizontal = 3
|
||||||
size_flags_vertical = 3
|
size_flags_vertical = 3
|
||||||
|
|
||||||
[node name="Label" type="Label" parent="Scroll/Panel"]
|
[node name="BackgroundMusicLabel" type="Label" parent="Scroll/Panel"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
offset_right = 210.0
|
offset_left = -1.52588e-05
|
||||||
offset_bottom = 42.0
|
offset_right = 245.0
|
||||||
theme_override_font_sizes/font_size = 30
|
offset_bottom = 49.0
|
||||||
|
theme_override_font_sizes/font_size = 35
|
||||||
text = "背景音乐音量:"
|
text = "背景音乐音量:"
|
||||||
|
|
||||||
[node name="HSlider" type="HSlider" parent="Scroll/Panel"]
|
[node name="BackgroundMusicHSlider" type="HSlider" parent="Scroll/Panel"]
|
||||||
layout_mode = 0
|
layout_mode = 2
|
||||||
offset_left = 210.0
|
offset_left = 245.0
|
||||||
offset_top = 15.0
|
offset_right = 574.0
|
||||||
offset_right = 573.0
|
offset_bottom = 49.0
|
||||||
offset_bottom = 31.0
|
size_flags_horizontal = 3
|
||||||
|
size_flags_vertical = 1
|
||||||
|
|
||||||
[connection signal="pressed" from="QuitButton" to="." method="_on_quit_button_pressed"]
|
[node name="WeatherSystemLabel" type="Label" parent="Scroll/Panel"]
|
||||||
|
layout_mode = 2
|
||||||
|
offset_left = -0.249969
|
||||||
|
offset_top = 48.75
|
||||||
|
offset_right = 209.75
|
||||||
|
offset_bottom = 97.75
|
||||||
|
theme_override_font_sizes/font_size = 35
|
||||||
|
text = "关闭天气显示:"
|
||||||
|
|
||||||
|
[node name="WeatherSystemCheck" type="CheckButton" parent="Scroll/Panel"]
|
||||||
|
layout_mode = 2
|
||||||
|
offset_left = 244.75
|
||||||
|
offset_top = 48.75
|
||||||
|
offset_right = 288.75
|
||||||
|
offset_bottom = 72.75
|
||||||
|
scale = Vector2(2, 2)
|
||||||
|
theme_override_font_sizes/font_size = 100
|
||||||
|
|
||||||
|
[node name="HBox" type="HBoxContainer" parent="Scroll/Panel"]
|
||||||
|
visible = false
|
||||||
|
layout_mode = 0
|
||||||
|
offset_top = 97.0
|
||||||
|
offset_right = 853.0
|
||||||
|
offset_bottom = 154.0
|
||||||
|
|
||||||
|
[node name="ChangeServer" type="Label" parent="Scroll/Panel/HBox"]
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_font_sizes/font_size = 35
|
||||||
|
text = "切换服务器"
|
||||||
|
|
||||||
|
[node name="IPInput" type="LineEdit" parent="Scroll/Panel/HBox"]
|
||||||
|
custom_minimum_size = Vector2(400, 0)
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_font_sizes/font_size = 35
|
||||||
|
placeholder_text = "请输入服务器IP地址"
|
||||||
|
|
||||||
|
[node name="PortInput" type="LineEdit" parent="Scroll/Panel/HBox"]
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_font_sizes/font_size = 35
|
||||||
|
placeholder_text = "端口"
|
||||||
|
alignment = 1
|
||||||
|
|
||||||
|
[node name="ChangeButton" type="Button" parent="Scroll/Panel/HBox"]
|
||||||
|
custom_minimum_size = Vector2(120, 0)
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_font_sizes/font_size = 35
|
||||||
|
text = "切换"
|
||||||
|
|
||||||
|
[node name="SureButton" type="Button" parent="."]
|
||||||
|
layout_mode = 0
|
||||||
|
offset_left = 647.5
|
||||||
|
offset_top = 635.0
|
||||||
|
offset_right = 815.5
|
||||||
|
offset_bottom = 698.0
|
||||||
|
theme_override_font_sizes/font_size = 40
|
||||||
|
text = "确认修改"
|
||||||
|
|
||||||
|
[node name="RefreshButton" type="Button" parent="."]
|
||||||
|
layout_mode = 0
|
||||||
|
offset_left = 27.5001
|
||||||
|
offset_top = 25.0001
|
||||||
|
offset_right = 195.5
|
||||||
|
offset_bottom = 88.0001
|
||||||
|
theme_override_font_sizes/font_size = 40
|
||||||
|
text = "刷新"
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ extends Control
|
|||||||
#各种面板
|
#各种面板
|
||||||
@onready var game_about_panel: Panel = $GameAboutPanel
|
@onready var game_about_panel: Panel = $GameAboutPanel
|
||||||
@onready var game_update_panel: Panel = $GameUpdatePanel
|
@onready var game_update_panel: Panel = $GameUpdatePanel
|
||||||
@onready var game_setting_panel: Panel = $GameSettingPanel
|
#@onready var game_setting_panel: Panel = $GameSettingPanel
|
||||||
|
|
||||||
@onready var game_version_label: Label = $GUI/GameVersionLabel
|
@onready var game_version_label: Label = $GUI/GameVersionLabel
|
||||||
|
|
||||||
@@ -23,7 +23,7 @@ func _on_start_game_button_pressed() -> void:
|
|||||||
|
|
||||||
#游戏设置
|
#游戏设置
|
||||||
func _on_game_setting_button_pressed() -> void:
|
func _on_game_setting_button_pressed() -> void:
|
||||||
game_setting_panel.show()
|
#game_setting_panel.show()
|
||||||
pass
|
pass
|
||||||
|
|
||||||
#游戏更新
|
#游戏更新
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
[gd_scene load_steps=12 format=3 uid="uid://bypjb28h4ntdr"]
|
[gd_scene load_steps=11 format=3 uid="uid://bypjb28h4ntdr"]
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://badqjgdfhg7vt" path="res://GUI/MainMenuPanel.gd" id="1_wpehy"]
|
[ext_resource type="Script" uid="uid://badqjgdfhg7vt" path="res://GUI/MainMenuPanel.gd" id="1_wpehy"]
|
||||||
[ext_resource type="Texture2D" uid="uid://ddcmrh50o1y0q" path="res://assets/菜单UI/背景1.webp" id="2_eghpk"]
|
[ext_resource type="Texture2D" uid="uid://ddcmrh50o1y0q" path="res://assets/菜单UI/背景1.webp" id="2_eghpk"]
|
||||||
@@ -7,7 +7,6 @@
|
|||||||
[ext_resource type="Texture2D" uid="uid://dgdootc5bny5q" path="res://assets/菜单UI/QQ群.webp" id="4_eghpk"]
|
[ext_resource type="Texture2D" uid="uid://dgdootc5bny5q" path="res://assets/菜单UI/QQ群.webp" id="4_eghpk"]
|
||||||
[ext_resource type="Script" uid="uid://kj7v1uxk2i6h" path="res://GUI/GameUpdatePanel.gd" id="4_fys16"]
|
[ext_resource type="Script" uid="uid://kj7v1uxk2i6h" path="res://GUI/GameUpdatePanel.gd" id="4_fys16"]
|
||||||
[ext_resource type="Texture2D" uid="uid://ccav04woielxa" path="res://assets/菜单UI/柚小青装饰品.webp" id="5_6jmhb"]
|
[ext_resource type="Texture2D" uid="uid://ccav04woielxa" path="res://assets/菜单UI/柚小青装饰品.webp" id="5_6jmhb"]
|
||||||
[ext_resource type="PackedScene" uid="uid://dos15dmc1b6bt" path="res://GUI/GameSettingPanel.tscn" id="6_eghpk"]
|
|
||||||
[ext_resource type="Script" uid="uid://ciwjx67wjubdy" path="res://GUI/CheckUpdatePanel.gd" id="9_6jmhb"]
|
[ext_resource type="Script" uid="uid://ciwjx67wjubdy" path="res://GUI/CheckUpdatePanel.gd" id="9_6jmhb"]
|
||||||
|
|
||||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_eghpk"]
|
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_eghpk"]
|
||||||
@@ -129,6 +128,7 @@ theme_override_font_sizes/font_size = 40
|
|||||||
text = "开始游戏"
|
text = "开始游戏"
|
||||||
|
|
||||||
[node name="GameSettingButton" type="Button" parent="VBox"]
|
[node name="GameSettingButton" type="Button" parent="VBox"]
|
||||||
|
visible = false
|
||||||
custom_minimum_size = Vector2(168, 63)
|
custom_minimum_size = Vector2(168, 63)
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
size_flags_horizontal = 4
|
size_flags_horizontal = 4
|
||||||
@@ -140,7 +140,7 @@ custom_minimum_size = Vector2(168, 63)
|
|||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
size_flags_horizontal = 4
|
size_flags_horizontal = 4
|
||||||
theme_override_font_sizes/font_size = 40
|
theme_override_font_sizes/font_size = 40
|
||||||
text = "游戏更新"
|
text = "更新"
|
||||||
|
|
||||||
[node name="GameAboutButton" type="Button" parent="VBox"]
|
[node name="GameAboutButton" type="Button" parent="VBox"]
|
||||||
custom_minimum_size = Vector2(168, 63)
|
custom_minimum_size = Vector2(168, 63)
|
||||||
@@ -156,14 +156,6 @@ size_flags_horizontal = 4
|
|||||||
theme_override_font_sizes/font_size = 40
|
theme_override_font_sizes/font_size = 40
|
||||||
text = "退出游戏"
|
text = "退出游戏"
|
||||||
|
|
||||||
[node name="GameSettingPanel" parent="." instance=ExtResource("6_eghpk")]
|
|
||||||
visible = false
|
|
||||||
layout_mode = 0
|
|
||||||
offset_left = 138.0
|
|
||||||
offset_top = 80.0
|
|
||||||
offset_right = 1536.0
|
|
||||||
offset_bottom = 800.0
|
|
||||||
|
|
||||||
[node name="GameAboutPanel" type="Panel" parent="."]
|
[node name="GameAboutPanel" type="Panel" parent="."]
|
||||||
visible = false
|
visible = false
|
||||||
layout_mode = 0
|
layout_mode = 0
|
||||||
|
|||||||
59
GameManager/DayNightSystem.gd
Normal file
59
GameManager/DayNightSystem.gd
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
extends Node2D
|
||||||
|
#昼夜循环系统
|
||||||
|
#时间直接获取现实世界时间
|
||||||
|
#内容就是直接调节背景图片modulate的亮度HEX 白天最亮为c3c3c3 晚上最暗为131313 然后在这之间变化
|
||||||
|
|
||||||
|
# 背景节点引用
|
||||||
|
@onready var background_node=$'../BackgroundUI/BackgroundSwitcher'
|
||||||
|
|
||||||
|
# 白天和夜晚的颜色值
|
||||||
|
var day_color = Color("#c3c3c3")
|
||||||
|
var night_color = Color("#131313")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
func _process(delta: float) -> void:
|
||||||
|
if background_node == null:
|
||||||
|
return
|
||||||
|
|
||||||
|
# 获取当前时间
|
||||||
|
var current_time = Time.get_datetime_dict_from_system()
|
||||||
|
var hour = current_time.hour
|
||||||
|
var minute = current_time.minute
|
||||||
|
|
||||||
|
# 将时间转换为小数形式(0-24)
|
||||||
|
var time_decimal = hour + minute / 60.0
|
||||||
|
|
||||||
|
# 计算亮度插值因子
|
||||||
|
var brightness_factor = calculate_brightness_factor(time_decimal)
|
||||||
|
|
||||||
|
# 在白天和夜晚颜色之间插值
|
||||||
|
var current_color = night_color.lerp(day_color, brightness_factor)
|
||||||
|
|
||||||
|
# 应用到背景节点
|
||||||
|
background_node.modulate = current_color
|
||||||
|
|
||||||
|
# 计算亮度因子(0为夜晚,1为白天)
|
||||||
|
func calculate_brightness_factor(time: float) -> float:
|
||||||
|
# 定义关键时间点
|
||||||
|
var sunrise = 6.0 # 日出时间 6:00
|
||||||
|
var noon = 12.0 # 正午时间 12:00
|
||||||
|
var sunset = 18.0 # 日落时间 18:00
|
||||||
|
var midnight = 0.0 # 午夜时间 0:00
|
||||||
|
|
||||||
|
if time >= sunrise and time <= noon:
|
||||||
|
# 日出到正午:从0.2逐渐变亮到1.0
|
||||||
|
return 0.2 + 0.8 * (time - sunrise) / (noon - sunrise)
|
||||||
|
elif time > noon and time <= sunset:
|
||||||
|
# 正午到日落:从1.0逐渐变暗到0.2
|
||||||
|
return 1.0 - 0.8 * (time - noon) / (sunset - noon)
|
||||||
|
else:
|
||||||
|
# 夜晚时间:保持较暗状态(0.0-0.2之间)
|
||||||
|
if time > sunset:
|
||||||
|
# 日落后到午夜
|
||||||
|
var night_progress = (time - sunset) / (24.0 - sunset)
|
||||||
|
return 0.2 - 0.2 * night_progress
|
||||||
|
else:
|
||||||
|
# 午夜到日出
|
||||||
|
var dawn_progress = time / sunrise
|
||||||
|
return 0.0 + 0.2 * dawn_progress
|
||||||
1
GameManager/DayNightSystem.gd.uid
Normal file
1
GameManager/DayNightSystem.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://di8wjflimodb0
|
||||||
@@ -9,8 +9,16 @@ extends Node2D
|
|||||||
# 天气系统
|
# 天气系统
|
||||||
# 要显示哪种天气直接调用相应天气的show()然后一并隐藏其他天气hide()
|
# 要显示哪种天气直接调用相应天气的show()然后一并隐藏其他天气hide()
|
||||||
|
|
||||||
|
# 动态天气显示控制(可以覆盖全局设置)
|
||||||
|
var weather_display_enabled: bool = true
|
||||||
|
|
||||||
# 设置天气的统一方法
|
# 设置天气的统一方法
|
||||||
func set_weather(weather_type: String):
|
func set_weather(weather_type: String):
|
||||||
|
# 检查全局设置和动态设置
|
||||||
|
if GlobalVariables.DisableWeatherDisplay or not weather_display_enabled:
|
||||||
|
hide_all_weather()
|
||||||
|
return
|
||||||
|
|
||||||
# 先隐藏所有天气效果
|
# 先隐藏所有天气效果
|
||||||
hide_all_weather()
|
hide_all_weather()
|
||||||
|
|
||||||
@@ -37,6 +45,19 @@ func set_weather(weather_type: String):
|
|||||||
_:
|
_:
|
||||||
print("未知的天气类型: ", weather_type)
|
print("未知的天气类型: ", weather_type)
|
||||||
|
|
||||||
|
# 动态设置天气显示状态
|
||||||
|
func set_weather_display_enabled(enabled: bool):
|
||||||
|
"""动态设置天气显示是否启用"""
|
||||||
|
weather_display_enabled = enabled
|
||||||
|
if not enabled:
|
||||||
|
hide_all_weather()
|
||||||
|
print("天气显示已", "启用" if enabled else "禁用")
|
||||||
|
|
||||||
|
# 获取当前天气显示状态
|
||||||
|
func is_weather_display_enabled() -> bool:
|
||||||
|
"""获取当前天气显示状态"""
|
||||||
|
return weather_display_enabled and not GlobalVariables.DisableWeatherDisplay
|
||||||
|
|
||||||
# 隐藏所有天气效果
|
# 隐藏所有天气效果
|
||||||
func hide_all_weather():
|
func hide_all_weather():
|
||||||
if cherry_blossom_rain:
|
if cherry_blossom_rain:
|
||||||
|
|||||||
@@ -12,3 +12,6 @@ const server_configs = [
|
|||||||
#{"host": "47.108.90.0", "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 #是否禁止显示天气
|
||||||
|
const BackgroundMusicVolume = 1.0 #背景音乐音量
|
||||||
|
|||||||
36
MainGame.gd
36
MainGame.gd
@@ -68,6 +68,7 @@ extends Node
|
|||||||
@onready var pet_fight_panel: Panel = $UI/BigPanel/PetFightPanel #宠物战斗面板
|
@onready var pet_fight_panel: Panel = $UI/BigPanel/PetFightPanel #宠物战斗面板
|
||||||
@onready var pet_inform_panel: Panel = $UI/SmallPanel/PetInformPanel #宠物信息面板
|
@onready var pet_inform_panel: Panel = $UI/SmallPanel/PetInformPanel #宠物信息面板
|
||||||
@onready var player_store_panel: Panel = $UI/BigPanel/PlayerStorePanel #玩家小卖部面板
|
@onready var player_store_panel: Panel = $UI/BigPanel/PlayerStorePanel #玩家小卖部面板
|
||||||
|
@onready var game_setting_panel: Panel = $UI/BigPanel/GameSettingPanel #游戏设置面板
|
||||||
|
|
||||||
|
|
||||||
#小面板
|
#小面板
|
||||||
@@ -225,6 +226,7 @@ func _ready():
|
|||||||
one_click_plant_panel.hide()
|
one_click_plant_panel.hide()
|
||||||
account_setting_panel.hide()
|
account_setting_panel.hide()
|
||||||
global_server_broadcast_panel.hide()
|
global_server_broadcast_panel.hide()
|
||||||
|
game_setting_panel.hide()
|
||||||
accept_dialog.hide()
|
accept_dialog.hide()
|
||||||
|
|
||||||
|
|
||||||
@@ -865,9 +867,9 @@ func _on_player_ranking_button_pressed() -> void:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
#打开设置面板 暂时没想到可以设置什么
|
#打开设置面板
|
||||||
func _on_setting_button_pressed() -> void:
|
func _on_setting_button_pressed() -> void:
|
||||||
pass
|
game_setting_panel.show()
|
||||||
|
|
||||||
#查看全服大喇叭按钮点击事件
|
#查看全服大喇叭按钮点击事件
|
||||||
func _on_watch_broadcast_button_pressed() -> void:
|
func _on_watch_broadcast_button_pressed() -> void:
|
||||||
@@ -1711,14 +1713,6 @@ func _wait_for_crop_data() -> void:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
#===============================================调试和维护工具===============================================
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#===============================================调试和维护工具===============================================
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#===============================================向后兼容性===============================================
|
#===============================================向后兼容性===============================================
|
||||||
# 为了保持向后兼容,保留一些原来的函数名
|
# 为了保持向后兼容,保留一些原来的函数名
|
||||||
func _load_crop_textures(crop_name: String) -> Array:
|
func _load_crop_textures(crop_name: String) -> Array:
|
||||||
@@ -3320,13 +3314,33 @@ func _handle_weather_change(weather_type: String, weather_name: String):
|
|||||||
"""处理服务器发送的天气变更消息"""
|
"""处理服务器发送的天气变更消息"""
|
||||||
if weather_system and weather_system.has_method("set_weather"):
|
if weather_system and weather_system.has_method("set_weather"):
|
||||||
weather_system.set_weather(weather_type)
|
weather_system.set_weather(weather_type)
|
||||||
Toast.show("天气已变更为:" + weather_name, Color.CYAN, 3.0)
|
|
||||||
print("天气已切换为:", weather_name)
|
print("天气已切换为:", weather_name)
|
||||||
else:
|
else:
|
||||||
print("天气系统不可用")
|
print("天气系统不可用")
|
||||||
# ======================================= 天气系统 =========================================
|
# ======================================= 天气系统 =========================================
|
||||||
|
|
||||||
|
|
||||||
|
# ======================================= 游戏设置系统 =========================================
|
||||||
|
# 处理游戏设置保存响应
|
||||||
|
func _handle_save_game_settings_response(data):
|
||||||
|
"""处理服务器返回的游戏设置保存响应"""
|
||||||
|
var success = data.get("success", false)
|
||||||
|
var message = data.get("message", "")
|
||||||
|
var settings = data.get("settings", {})
|
||||||
|
|
||||||
|
if success:
|
||||||
|
# 设置保存成功,更新本地设置面板
|
||||||
|
if game_setting_panel and game_setting_panel.has_method("apply_settings_from_server"):
|
||||||
|
game_setting_panel.apply_settings_from_server(settings)
|
||||||
|
|
||||||
|
Toast.show("游戏设置保存成功", Color.GREEN)
|
||||||
|
print("游戏设置保存成功: ", settings)
|
||||||
|
else:
|
||||||
|
Toast.show("游戏设置保存失败: " + message, Color.RED)
|
||||||
|
print("游戏设置保存失败: ", message)
|
||||||
|
# ======================================= 游戏设置系统 =========================================
|
||||||
|
|
||||||
|
|
||||||
#打开小卖部面板
|
#打开小卖部面板
|
||||||
func _on_my_store_button_pressed() -> void:
|
func _on_my_store_button_pressed() -> void:
|
||||||
player_store_panel.show()
|
player_store_panel.show()
|
||||||
|
|||||||
1326
MainGame.tscn
1326
MainGame.tscn
File diff suppressed because it is too large
Load Diff
@@ -602,6 +602,10 @@ func _on_data_received(data):
|
|||||||
var weather_type = data.get("weather_type", "clear")
|
var weather_type = data.get("weather_type", "clear")
|
||||||
var weather_name = data.get("weather_name", "晴天")
|
var weather_name = data.get("weather_name", "晴天")
|
||||||
main_game._handle_weather_change(weather_type, weather_name)
|
main_game._handle_weather_change(weather_type, weather_name)
|
||||||
|
|
||||||
|
# 游戏设置响应
|
||||||
|
elif message_type == "save_game_settings_response":
|
||||||
|
main_game._handle_save_game_settings_response(data)
|
||||||
# ============================= 客户端与服务端通信核心 =====================================
|
# ============================= 客户端与服务端通信核心 =====================================
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -521,6 +521,10 @@ func _on_login_response_received(success: bool, message: String, user_data: Dict
|
|||||||
|
|
||||||
# 调用主游戏的登录成功处理函数
|
# 调用主游戏的登录成功处理函数
|
||||||
main_game.handle_login_success(user_data)
|
main_game.handle_login_success(user_data)
|
||||||
|
|
||||||
|
# 初始化游戏设置
|
||||||
|
if main_game.game_setting_panel and main_game.game_setting_panel.has_method("refresh_settings"):
|
||||||
|
main_game.game_setting_panel.refresh_settings()
|
||||||
else:
|
else:
|
||||||
status_label.text = "登录失败:" + message
|
status_label.text = "登录失败:" + message
|
||||||
status_label.modulate = Color.RED
|
status_label.modulate = Color.RED
|
||||||
|
|||||||
170
Server/MongoDB迁移说明.md
Normal file
170
Server/MongoDB迁移说明.md
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
# 萌芽农场 MongoDB 迁移说明
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
本文档描述了萌芽农场项目从JSON配置文件迁移到MongoDB数据库的过程。目前已完成每日签到配置的迁移,为后续其他配置的迁移奠定了基础。
|
||||||
|
|
||||||
|
## 迁移内容
|
||||||
|
|
||||||
|
### 1. 已完成的迁移
|
||||||
|
|
||||||
|
#### 每日签到配置 (daily_checkin_config.json)
|
||||||
|
- **原位置**: `Server/config/daily_checkin_config.json`
|
||||||
|
- **新位置**: MongoDB数据库 `mengyafarm.gameconfig` 集合
|
||||||
|
- **文档ID**: `687cce278e77ba00a7414ba2`
|
||||||
|
- **状态**: ✅ 已完成迁移
|
||||||
|
|
||||||
|
### 2. 数据库配置
|
||||||
|
|
||||||
|
#### 测试环境
|
||||||
|
- **地址**: `localhost:27017`
|
||||||
|
- **数据库**: `mengyafarm`
|
||||||
|
- **集合**: `gameconfig`
|
||||||
|
|
||||||
|
#### 生产环境
|
||||||
|
- **地址**: `192.168.31.233:27017`
|
||||||
|
- **数据库**: `mengyafarm`
|
||||||
|
- **集合**: `gameconfig`
|
||||||
|
|
||||||
|
## 技术实现
|
||||||
|
|
||||||
|
### 1. MongoDB API (SMYMongoDBAPI.py)
|
||||||
|
|
||||||
|
创建了专门的MongoDB API类,提供以下功能:
|
||||||
|
|
||||||
|
#### 核心功能
|
||||||
|
- 数据库连接管理(测试/生产环境)
|
||||||
|
- 游戏配置的读取和更新
|
||||||
|
- 通用文档操作(增删改查)
|
||||||
|
- 错误处理和日志记录
|
||||||
|
|
||||||
|
#### 主要方法
|
||||||
|
```python
|
||||||
|
# 配置管理
|
||||||
|
get_daily_checkin_config() # 获取每日签到配置
|
||||||
|
update_daily_checkin_config() # 更新每日签到配置
|
||||||
|
get_game_config(config_type) # 获取通用游戏配置
|
||||||
|
set_game_config(config_type, data) # 设置通用游戏配置
|
||||||
|
|
||||||
|
# 通用操作
|
||||||
|
insert_document(collection, doc) # 插入文档
|
||||||
|
find_documents(collection, query) # 查找文档
|
||||||
|
update_document(collection, query, update) # 更新文档
|
||||||
|
delete_document(collection, query) # 删除文档
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 服务器集成 (TCPGameServer.py)
|
||||||
|
|
||||||
|
#### 修改内容
|
||||||
|
- 添加MongoDB API导入和初始化
|
||||||
|
- 修改 `_load_daily_check_in_config()` 方法,优先使用MongoDB
|
||||||
|
- 添加 `_update_daily_checkin_config_to_mongodb()` 方法
|
||||||
|
- 实现优雅降级:MongoDB失败时自动回退到JSON文件
|
||||||
|
|
||||||
|
#### 配置加载策略
|
||||||
|
1. **优先**: 尝试从MongoDB获取配置
|
||||||
|
2. **备选**: 从JSON文件加载配置
|
||||||
|
3. **兜底**: 使用默认配置
|
||||||
|
|
||||||
|
## 测试验证
|
||||||
|
|
||||||
|
### 1. MongoDB API测试
|
||||||
|
运行 `python SMYMongoDBAPI.py` 进行基础功能测试
|
||||||
|
|
||||||
|
### 2. 迁移功能测试
|
||||||
|
运行 `python test_mongodb_migration.py` 进行完整迁移测试
|
||||||
|
|
||||||
|
### 3. 服务器集成测试
|
||||||
|
运行 `python test_server_mongodb.py` 进行服务器集成测试
|
||||||
|
|
||||||
|
## 使用说明
|
||||||
|
|
||||||
|
### 1. 环境配置
|
||||||
|
|
||||||
|
#### 测试环境
|
||||||
|
```python
|
||||||
|
api = SMYMongoDBAPI("test") # 连接到 localhost:27017
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 生产环境
|
||||||
|
```python
|
||||||
|
api = SMYMongoDBAPI("production") # 连接到 192.168.31.233:27017
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 获取配置
|
||||||
|
```python
|
||||||
|
# 获取每日签到配置
|
||||||
|
config = api.get_daily_checkin_config()
|
||||||
|
|
||||||
|
# 获取通用游戏配置
|
||||||
|
config = api.get_game_config("config_type")
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 更新配置
|
||||||
|
```python
|
||||||
|
# 更新每日签到配置
|
||||||
|
success = api.update_daily_checkin_config(new_config)
|
||||||
|
|
||||||
|
# 设置通用游戏配置
|
||||||
|
success = api.set_game_config("config_type", config_data)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 后续迁移计划
|
||||||
|
|
||||||
|
### 1. 待迁移的配置文件
|
||||||
|
- [ ] `item_config.json` - 道具配置
|
||||||
|
- [ ] `pet_data.json` - 宠物配置
|
||||||
|
- [ ] 其他游戏配置文件
|
||||||
|
|
||||||
|
### 2. 迁移步骤
|
||||||
|
1. 将JSON文件导入到MongoDB
|
||||||
|
2. 修改对应的加载方法
|
||||||
|
3. 添加更新方法
|
||||||
|
4. 编写测试用例
|
||||||
|
5. 验证功能正常
|
||||||
|
|
||||||
|
### 3. 迁移原则
|
||||||
|
- **渐进式迁移**: 一次迁移一个配置文件
|
||||||
|
- **向后兼容**: 保持JSON文件作为备选方案
|
||||||
|
- **充分测试**: 每个迁移都要有完整的测试覆盖
|
||||||
|
- **文档更新**: 及时更新相关文档
|
||||||
|
|
||||||
|
## 注意事项
|
||||||
|
|
||||||
|
### 1. 数据安全
|
||||||
|
- 定期备份MongoDB数据
|
||||||
|
- 重要配置修改前先备份
|
||||||
|
- 测试环境验证后再应用到生产环境
|
||||||
|
|
||||||
|
### 2. 性能考虑
|
||||||
|
- MongoDB连接池管理
|
||||||
|
- 配置缓存策略
|
||||||
|
- 错误重试机制
|
||||||
|
|
||||||
|
### 3. 监控和日志
|
||||||
|
- 记录配置加载来源
|
||||||
|
- 监控MongoDB连接状态
|
||||||
|
- 记录配置更新操作
|
||||||
|
|
||||||
|
## 故障排除
|
||||||
|
|
||||||
|
### 1. MongoDB连接失败
|
||||||
|
- 检查MongoDB服务是否启动
|
||||||
|
- 验证连接地址和端口
|
||||||
|
- 检查网络连接
|
||||||
|
|
||||||
|
### 2. 配置加载失败
|
||||||
|
- 检查MongoDB中是否存在对应文档
|
||||||
|
- 验证文档格式是否正确
|
||||||
|
- 查看服务器日志获取详细错误信息
|
||||||
|
|
||||||
|
### 3. 配置更新失败
|
||||||
|
- 检查MongoDB权限
|
||||||
|
- 验证更新数据格式
|
||||||
|
- 确认文档ID是否正确
|
||||||
|
|
||||||
|
## 总结
|
||||||
|
|
||||||
|
本次迁移成功实现了每日签到配置从JSON文件到MongoDB的迁移,建立了完整的MongoDB API框架,为后续其他配置的迁移提供了可靠的基础。迁移过程采用了渐进式和向后兼容的策略,确保了系统的稳定性和可靠性。
|
||||||
|
|
||||||
|
通过测试验证,MongoDB迁移功能运行正常,服务器能够正确使用MongoDB中的配置数据,同时保持了JSON文件的备选方案,为后续的全面迁移奠定了坚实的基础。
|
||||||
705
Server/SMYMongoDBAPI.py
Normal file
705
Server/SMYMongoDBAPI.py
Normal file
@@ -0,0 +1,705 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
萌芽农场 MongoDB 数据库 API
|
||||||
|
作者: AI Assistant
|
||||||
|
功能: 提供MongoDB数据库连接和游戏配置管理功能
|
||||||
|
"""
|
||||||
|
|
||||||
|
import pymongo
|
||||||
|
import json
|
||||||
|
from typing import Dict, Any, Optional, List
|
||||||
|
import logging
|
||||||
|
from datetime import datetime
|
||||||
|
from bson import ObjectId
|
||||||
|
|
||||||
|
class SMYMongoDBAPI:
|
||||||
|
def __init__(self, environment: str = "test"):
|
||||||
|
"""
|
||||||
|
初始化MongoDB API
|
||||||
|
|
||||||
|
Args:
|
||||||
|
environment: 环境类型,"test" 表示测试环境,"production" 表示正式环境
|
||||||
|
"""
|
||||||
|
self.environment = environment
|
||||||
|
self.client = None
|
||||||
|
self.db = None
|
||||||
|
self.connected = False
|
||||||
|
|
||||||
|
# 配置数据库连接信息
|
||||||
|
self.config = {
|
||||||
|
"test": {
|
||||||
|
"host": "localhost",
|
||||||
|
"port": 27017,
|
||||||
|
"database": "mengyafarm"
|
||||||
|
},
|
||||||
|
"production": {
|
||||||
|
"host": "192.168.31.233",
|
||||||
|
"port": 27017,
|
||||||
|
"database": "mengyafarm"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# 设置日志
|
||||||
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
self.logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# 连接数据库
|
||||||
|
self.connect()
|
||||||
|
|
||||||
|
def connect(self) -> bool:
|
||||||
|
"""
|
||||||
|
连接到MongoDB数据库
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: 连接是否成功
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
current_config = self.config[self.environment]
|
||||||
|
connection_string = f"mongodb://{current_config['host']}:{current_config['port']}/"
|
||||||
|
|
||||||
|
self.client = pymongo.MongoClient(
|
||||||
|
connection_string,
|
||||||
|
serverSelectionTimeoutMS=5000, # 5秒超时
|
||||||
|
connectTimeoutMS=5000,
|
||||||
|
socketTimeoutMS=5000
|
||||||
|
)
|
||||||
|
|
||||||
|
# 测试连接
|
||||||
|
self.client.admin.command('ping')
|
||||||
|
|
||||||
|
# 选择数据库
|
||||||
|
self.db = self.client[current_config['database']]
|
||||||
|
self.connected = True
|
||||||
|
|
||||||
|
self.logger.info(f"成功连接到MongoDB数据库 [{self.environment}]: {connection_string}")
|
||||||
|
return True
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"连接MongoDB失败: {e}")
|
||||||
|
self.connected = False
|
||||||
|
return False
|
||||||
|
|
||||||
|
def disconnect(self):
|
||||||
|
"""断开数据库连接"""
|
||||||
|
if self.client:
|
||||||
|
self.client.close()
|
||||||
|
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):
|
||||||
|
"""
|
||||||
|
获取集合对象
|
||||||
|
|
||||||
|
Args:
|
||||||
|
collection_name: 集合名称
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Collection: MongoDB集合对象
|
||||||
|
"""
|
||||||
|
if not self.is_connected():
|
||||||
|
raise Exception("数据库未连接")
|
||||||
|
return self.db[collection_name]
|
||||||
|
|
||||||
|
# ========================= 游戏配置管理 =========================
|
||||||
|
|
||||||
|
def get_game_config(self, config_type: str) -> Optional[Dict[str, Any]]:
|
||||||
|
"""
|
||||||
|
获取游戏配置
|
||||||
|
|
||||||
|
Args:
|
||||||
|
config_type: 配置类型,如 "daily_checkin"
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dict: 配置数据,如果未找到返回None
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
collection = self.get_collection("gameconfig")
|
||||||
|
|
||||||
|
# 根据配置类型查找文档
|
||||||
|
query = {"config_type": config_type}
|
||||||
|
result = collection.find_one(query)
|
||||||
|
|
||||||
|
if result:
|
||||||
|
# 移除MongoDB的_id字段,只返回配置数据
|
||||||
|
if "_id" in result:
|
||||||
|
del result["_id"]
|
||||||
|
if "config_type" in result:
|
||||||
|
del result["config_type"]
|
||||||
|
|
||||||
|
self.logger.info(f"成功获取游戏配置: {config_type}")
|
||||||
|
return result
|
||||||
|
else:
|
||||||
|
self.logger.warning(f"未找到游戏配置: {config_type}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"获取游戏配置失败 [{config_type}]: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_daily_checkin_config(self) -> Optional[Dict[str, Any]]:
|
||||||
|
"""
|
||||||
|
获取每日签到配置
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dict: 每日签到配置数据
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
collection = self.get_collection("gameconfig")
|
||||||
|
|
||||||
|
# 使用已知的文档ID查找
|
||||||
|
object_id = ObjectId("687cce278e77ba00a7414ba2")
|
||||||
|
result = collection.find_one({"_id": object_id})
|
||||||
|
|
||||||
|
if result:
|
||||||
|
# 移除MongoDB的_id字段
|
||||||
|
if "_id" in result:
|
||||||
|
del result["_id"]
|
||||||
|
|
||||||
|
self.logger.info("成功获取每日签到配置")
|
||||||
|
return result
|
||||||
|
else:
|
||||||
|
self.logger.warning("未找到每日签到配置")
|
||||||
|
return None
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"获取每日签到配置失败: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def set_game_config(self, config_type: str, config_data: Dict[str, Any]) -> bool:
|
||||||
|
"""
|
||||||
|
设置游戏配置
|
||||||
|
|
||||||
|
Args:
|
||||||
|
config_type: 配置类型
|
||||||
|
config_data: 配置数据
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: 是否成功
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
collection = self.get_collection("gameconfig")
|
||||||
|
|
||||||
|
# 准备文档数据
|
||||||
|
document = {
|
||||||
|
"config_type": config_type,
|
||||||
|
"updated_at": datetime.now(),
|
||||||
|
**config_data
|
||||||
|
}
|
||||||
|
|
||||||
|
# 使用upsert更新或插入
|
||||||
|
query = {"config_type": config_type}
|
||||||
|
result = collection.replace_one(query, document, upsert=True)
|
||||||
|
|
||||||
|
if result.acknowledged:
|
||||||
|
self.logger.info(f"成功设置游戏配置: {config_type}")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
self.logger.error(f"设置游戏配置失败: {config_type}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"设置游戏配置异常 [{config_type}]: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def update_daily_checkin_config(self, config_data: Dict[str, Any]) -> bool:
|
||||||
|
"""
|
||||||
|
更新每日签到配置
|
||||||
|
|
||||||
|
Args:
|
||||||
|
config_data: 配置数据
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: 是否成功
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
collection = self.get_collection("gameconfig")
|
||||||
|
|
||||||
|
# 使用已知的文档ID更新
|
||||||
|
object_id = ObjectId("687cce278e77ba00a7414ba2")
|
||||||
|
|
||||||
|
# 添加更新时间
|
||||||
|
update_data = {
|
||||||
|
"updated_at": datetime.now(),
|
||||||
|
**config_data
|
||||||
|
}
|
||||||
|
|
||||||
|
result = collection.replace_one({"_id": object_id}, update_data)
|
||||||
|
|
||||||
|
if result.acknowledged and result.matched_count > 0:
|
||||||
|
self.logger.info("成功更新每日签到配置")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
self.logger.error("更新每日签到配置失败")
|
||||||
|
return False
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"更新每日签到配置异常: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_lucky_draw_config(self) -> Optional[Dict[str, Any]]:
|
||||||
|
"""
|
||||||
|
获取幸运抽奖配置
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dict: 幸运抽奖配置数据
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
collection = self.get_collection("gameconfig")
|
||||||
|
|
||||||
|
# 使用已知的文档ID查找
|
||||||
|
object_id = ObjectId("687cd52e8e77ba00a7414ba3")
|
||||||
|
result = collection.find_one({"_id": object_id})
|
||||||
|
|
||||||
|
if result:
|
||||||
|
# 移除MongoDB的_id字段和updated_at字段
|
||||||
|
if "_id" in result:
|
||||||
|
del result["_id"]
|
||||||
|
if "updated_at" in result:
|
||||||
|
del result["updated_at"]
|
||||||
|
|
||||||
|
self.logger.info("成功获取幸运抽奖配置")
|
||||||
|
return result
|
||||||
|
else:
|
||||||
|
self.logger.warning("未找到幸运抽奖配置")
|
||||||
|
return None
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"获取幸运抽奖配置失败: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def update_lucky_draw_config(self, config_data: Dict[str, Any]) -> bool:
|
||||||
|
"""
|
||||||
|
更新幸运抽奖配置
|
||||||
|
|
||||||
|
Args:
|
||||||
|
config_data: 配置数据
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: 是否成功
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
collection = self.get_collection("gameconfig")
|
||||||
|
|
||||||
|
# 使用已知的文档ID更新
|
||||||
|
object_id = ObjectId("687cd52e8e77ba00a7414ba3")
|
||||||
|
|
||||||
|
# 添加更新时间
|
||||||
|
update_data = {
|
||||||
|
"updated_at": datetime.now(),
|
||||||
|
**config_data
|
||||||
|
}
|
||||||
|
|
||||||
|
result = collection.replace_one({"_id": object_id}, update_data)
|
||||||
|
|
||||||
|
if result.acknowledged and result.matched_count > 0:
|
||||||
|
self.logger.info("成功更新幸运抽奖配置")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
self.logger.error("更新幸运抽奖配置失败")
|
||||||
|
return False
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"更新幸运抽奖配置异常: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_new_player_config(self) -> Optional[Dict[str, Any]]:
|
||||||
|
"""
|
||||||
|
获取新手大礼包配置
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dict: 新手大礼包配置数据
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
collection = self.get_collection("gameconfig")
|
||||||
|
|
||||||
|
# 使用已知的文档ID查找
|
||||||
|
object_id = ObjectId("687cdbd78e77ba00a7414ba4")
|
||||||
|
result = collection.find_one({"_id": object_id})
|
||||||
|
|
||||||
|
if result:
|
||||||
|
# 移除MongoDB的_id字段和updated_at字段
|
||||||
|
if "_id" in result:
|
||||||
|
del result["_id"]
|
||||||
|
if "updated_at" in result:
|
||||||
|
del result["updated_at"]
|
||||||
|
|
||||||
|
self.logger.info("成功获取新手大礼包配置")
|
||||||
|
return result
|
||||||
|
else:
|
||||||
|
self.logger.warning("未找到新手大礼包配置")
|
||||||
|
return None
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"获取新手大礼包配置失败: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def update_new_player_config(self, config_data: Dict[str, Any]) -> bool:
|
||||||
|
"""
|
||||||
|
更新新手大礼包配置
|
||||||
|
|
||||||
|
Args:
|
||||||
|
config_data: 配置数据
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: 是否成功
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
collection = self.get_collection("gameconfig")
|
||||||
|
|
||||||
|
# 使用已知的文档ID更新
|
||||||
|
object_id = ObjectId("687cdbd78e77ba00a7414ba4")
|
||||||
|
|
||||||
|
# 添加更新时间
|
||||||
|
update_data = {
|
||||||
|
"updated_at": datetime.now(),
|
||||||
|
**config_data
|
||||||
|
}
|
||||||
|
|
||||||
|
result = collection.replace_one({"_id": object_id}, update_data)
|
||||||
|
|
||||||
|
if result.acknowledged and result.matched_count > 0:
|
||||||
|
self.logger.info("成功更新新手大礼包配置")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
self.logger.error("更新新手大礼包配置失败")
|
||||||
|
return False
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"更新新手大礼包配置异常: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_wisdom_tree_config(self) -> Optional[Dict[str, Any]]:
|
||||||
|
"""
|
||||||
|
获取智慧树配置
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dict: 智慧树配置数据
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
collection = self.get_collection("gameconfig")
|
||||||
|
|
||||||
|
# 使用已知的文档ID查找
|
||||||
|
object_id = ObjectId("687cdfbe8e77ba00a7414ba5")
|
||||||
|
result = collection.find_one({"_id": object_id})
|
||||||
|
|
||||||
|
if result:
|
||||||
|
# 移除MongoDB的_id字段和updated_at字段
|
||||||
|
if "_id" in result:
|
||||||
|
del result["_id"]
|
||||||
|
if "updated_at" in result:
|
||||||
|
del result["updated_at"]
|
||||||
|
|
||||||
|
self.logger.info("成功获取智慧树配置")
|
||||||
|
return result
|
||||||
|
else:
|
||||||
|
self.logger.warning("未找到智慧树配置")
|
||||||
|
return None
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"获取智慧树配置失败: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def update_wisdom_tree_config(self, config_data: Dict[str, Any]) -> bool:
|
||||||
|
"""
|
||||||
|
更新智慧树配置
|
||||||
|
|
||||||
|
Args:
|
||||||
|
config_data: 配置数据
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: 是否成功
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
collection = self.get_collection("gameconfig")
|
||||||
|
|
||||||
|
# 使用已知的文档ID更新
|
||||||
|
object_id = ObjectId("687cdfbe8e77ba00a7414ba5")
|
||||||
|
|
||||||
|
# 添加更新时间
|
||||||
|
update_data = {
|
||||||
|
"updated_at": datetime.now(),
|
||||||
|
**config_data
|
||||||
|
}
|
||||||
|
|
||||||
|
result = collection.replace_one({"_id": object_id}, update_data)
|
||||||
|
|
||||||
|
if result.acknowledged and result.matched_count > 0:
|
||||||
|
self.logger.info("成功更新智慧树配置")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
self.logger.error("更新智慧树配置失败")
|
||||||
|
return False
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"更新智慧树配置异常: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_online_gift_config(self) -> Optional[Dict[str, Any]]:
|
||||||
|
"""
|
||||||
|
获取在线礼包配置
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dict: 在线礼包配置数据
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
collection = self.get_collection("gameconfig")
|
||||||
|
|
||||||
|
# 使用已知的文档ID查找
|
||||||
|
object_id = ObjectId("687ce7678e77ba00a7414ba6")
|
||||||
|
result = collection.find_one({"_id": object_id})
|
||||||
|
|
||||||
|
if result:
|
||||||
|
# 移除MongoDB的_id字段和updated_at字段
|
||||||
|
if "_id" in result:
|
||||||
|
del result["_id"]
|
||||||
|
if "updated_at" in result:
|
||||||
|
del result["updated_at"]
|
||||||
|
|
||||||
|
self.logger.info("成功获取在线礼包配置")
|
||||||
|
return result
|
||||||
|
else:
|
||||||
|
self.logger.warning("未找到在线礼包配置")
|
||||||
|
return None
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"获取在线礼包配置失败: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def update_online_gift_config(self, config_data: Dict[str, Any]) -> bool:
|
||||||
|
"""
|
||||||
|
更新在线礼包配置
|
||||||
|
|
||||||
|
Args:
|
||||||
|
config_data: 配置数据
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: 是否成功
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
collection = self.get_collection("gameconfig")
|
||||||
|
|
||||||
|
# 使用已知的文档ID更新
|
||||||
|
object_id = ObjectId("687ce7678e77ba00a7414ba6")
|
||||||
|
|
||||||
|
# 添加更新时间
|
||||||
|
update_data = {
|
||||||
|
"updated_at": datetime.now(),
|
||||||
|
**config_data
|
||||||
|
}
|
||||||
|
|
||||||
|
result = collection.replace_one({"_id": object_id}, update_data)
|
||||||
|
|
||||||
|
if result.acknowledged and result.matched_count > 0:
|
||||||
|
self.logger.info("成功更新在线礼包配置")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
self.logger.error("更新在线礼包配置失败")
|
||||||
|
return False
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"更新在线礼包配置异常: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# ========================= 通用数据库操作 =========================
|
||||||
|
|
||||||
|
def insert_document(self, collection_name: str, document: Dict[str, Any]) -> Optional[str]:
|
||||||
|
"""
|
||||||
|
插入文档
|
||||||
|
|
||||||
|
Args:
|
||||||
|
collection_name: 集合名称
|
||||||
|
document: 要插入的文档
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: 插入的文档ID,失败返回None
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
collection = self.get_collection(collection_name)
|
||||||
|
result = collection.insert_one(document)
|
||||||
|
|
||||||
|
if result.acknowledged:
|
||||||
|
self.logger.info(f"成功插入文档到集合 {collection_name}")
|
||||||
|
return str(result.inserted_id)
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
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]]:
|
||||||
|
"""
|
||||||
|
查找文档
|
||||||
|
|
||||||
|
Args:
|
||||||
|
collection_name: 集合名称
|
||||||
|
query: 查询条件
|
||||||
|
limit: 限制返回数量,0表示不限制
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List: 文档列表
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
collection = self.get_collection(collection_name)
|
||||||
|
|
||||||
|
if query is None:
|
||||||
|
query = {}
|
||||||
|
|
||||||
|
cursor = collection.find(query)
|
||||||
|
if limit > 0:
|
||||||
|
cursor = cursor.limit(limit)
|
||||||
|
|
||||||
|
documents = list(cursor)
|
||||||
|
|
||||||
|
# 转换ObjectId为字符串
|
||||||
|
for doc in documents:
|
||||||
|
if "_id" in doc:
|
||||||
|
doc["_id"] = str(doc["_id"])
|
||||||
|
|
||||||
|
return documents
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"查找文档失败 [{collection_name}]: {e}")
|
||||||
|
return []
|
||||||
|
|
||||||
|
def update_document(self, collection_name: str, query: Dict[str, Any],
|
||||||
|
update: Dict[str, Any]) -> bool:
|
||||||
|
"""
|
||||||
|
更新文档
|
||||||
|
|
||||||
|
Args:
|
||||||
|
collection_name: 集合名称
|
||||||
|
query: 查询条件
|
||||||
|
update: 更新数据
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: 是否成功
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
collection = self.get_collection(collection_name)
|
||||||
|
result = collection.update_one(query, {"$set": update})
|
||||||
|
|
||||||
|
return result.acknowledged and result.matched_count > 0
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"更新文档失败 [{collection_name}]: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def delete_document(self, collection_name: str, query: Dict[str, Any]) -> bool:
|
||||||
|
"""
|
||||||
|
删除文档
|
||||||
|
|
||||||
|
Args:
|
||||||
|
collection_name: 集合名称
|
||||||
|
query: 查询条件
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: 是否成功
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
collection = self.get_collection(collection_name)
|
||||||
|
result = collection.delete_one(query)
|
||||||
|
|
||||||
|
return result.acknowledged and result.deleted_count > 0
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"删除文档失败 [{collection_name}]: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# ========================= 测试和使用示例 =========================
|
||||||
|
|
||||||
|
def test_api():
|
||||||
|
"""测试API功能"""
|
||||||
|
print("=== 测试MongoDB API ===")
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 创建API实例(测试环境)
|
||||||
|
api = SMYMongoDBAPI("test")
|
||||||
|
|
||||||
|
if not api.is_connected():
|
||||||
|
print("数据库连接失败,请检查MongoDB服务")
|
||||||
|
return
|
||||||
|
|
||||||
|
# 测试获取每日签到配置
|
||||||
|
print("\n1. 测试获取每日签到配置:")
|
||||||
|
config = api.get_daily_checkin_config()
|
||||||
|
if config:
|
||||||
|
print("✓ 成功获取每日签到配置")
|
||||||
|
print(f"基础奖励金币范围: {config.get('基础奖励', {}).get('金币', {})}")
|
||||||
|
print(f"种子奖励类型数量: {len(config.get('种子奖励', {}))}")
|
||||||
|
else:
|
||||||
|
print("✗ 获取每日签到配置失败")
|
||||||
|
|
||||||
|
# 测试获取幸运抽奖配置
|
||||||
|
print("\n2. 测试获取幸运抽奖配置:")
|
||||||
|
lucky_config = api.get_lucky_draw_config()
|
||||||
|
if lucky_config:
|
||||||
|
print("✓ 成功获取幸运抽奖配置")
|
||||||
|
print(f"抽奖费用: {lucky_config.get('抽奖费用', {})}")
|
||||||
|
print(f"概率配置类型数量: {len(lucky_config.get('概率配置', {}))}")
|
||||||
|
else:
|
||||||
|
print("✗ 获取幸运抽奖配置失败")
|
||||||
|
|
||||||
|
# 测试获取新手大礼包配置
|
||||||
|
print("\n3. 测试获取新手大礼包配置:")
|
||||||
|
new_player_config = api.get_new_player_config()
|
||||||
|
if new_player_config:
|
||||||
|
print("✓ 成功获取新手大礼包配置")
|
||||||
|
gift_config = new_player_config.get('新手礼包配置', {})
|
||||||
|
reward_content = gift_config.get('奖励内容', {})
|
||||||
|
print(f"奖励金币: {reward_content.get('金币', 0)}")
|
||||||
|
print(f"奖励经验: {reward_content.get('经验', 0)}")
|
||||||
|
print(f"种子奖励数量: {len(reward_content.get('种子', []))}")
|
||||||
|
else:
|
||||||
|
print("✗ 获取新手大礼包配置失败")
|
||||||
|
|
||||||
|
# 测试获取智慧树配置
|
||||||
|
print("\n4. 测试获取智慧树配置:")
|
||||||
|
wisdom_tree_config = api.get_wisdom_tree_config()
|
||||||
|
if wisdom_tree_config:
|
||||||
|
print("✓ 成功获取智慧树配置")
|
||||||
|
messages = wisdom_tree_config.get('messages', [])
|
||||||
|
print(f"消息总数: {wisdom_tree_config.get('total_messages', 0)}")
|
||||||
|
print(f"最后更新: {wisdom_tree_config.get('last_update', 'N/A')}")
|
||||||
|
print(f"消息列表长度: {len(messages)}")
|
||||||
|
else:
|
||||||
|
print("✗ 获取智慧树配置失败")
|
||||||
|
|
||||||
|
# 测试获取在线礼包配置
|
||||||
|
print("\n5. 测试获取在线礼包配置:")
|
||||||
|
online_gift_config = api.get_online_gift_config()
|
||||||
|
if online_gift_config:
|
||||||
|
print("✓ 成功获取在线礼包配置")
|
||||||
|
gifts = online_gift_config.get('gifts', [])
|
||||||
|
print(f"礼包数量: {len(gifts)}")
|
||||||
|
print(f"最大在线时间: {online_gift_config.get('max_online_time', 'N/A')}")
|
||||||
|
else:
|
||||||
|
print("✗ 获取在线礼包配置失败")
|
||||||
|
|
||||||
|
# 测试查找所有游戏配置
|
||||||
|
print("\n6. 测试查找游戏配置集合:")
|
||||||
|
try:
|
||||||
|
configs = api.find_documents("gameconfig")
|
||||||
|
print(f"找到 {len(configs)} 个配置文档")
|
||||||
|
for config in configs:
|
||||||
|
print(f" - 文档ID: {config.get('_id', 'N/A')}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"查找配置失败: {e}")
|
||||||
|
|
||||||
|
# 断开连接
|
||||||
|
api.disconnect()
|
||||||
|
print("\n✓ 测试完成")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"测试过程中出现异常: {e}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
test_api()
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
from TCPServer import TCPServer
|
from TCPServer import TCPServer
|
||||||
|
from SMYMongoDBAPI import SMYMongoDBAPI
|
||||||
import time
|
import time
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
@@ -84,9 +85,17 @@ class TCPGameServer(TCPServer):
|
|||||||
# 配置文件目录
|
# 配置文件目录
|
||||||
self.config_dir = "config" # 配置文件存储目录
|
self.config_dir = "config" # 配置文件存储目录
|
||||||
|
|
||||||
|
# 初始化MongoDB API(优先使用MongoDB,失败则使用JSON文件)
|
||||||
|
self._init_mongodb_api()
|
||||||
|
|
||||||
# 性能优化相关配置
|
# 性能优化相关配置
|
||||||
self._init_performance_settings()
|
self._init_performance_settings()
|
||||||
|
|
||||||
|
# 数据缓存
|
||||||
|
self.crop_data_cache = None
|
||||||
|
self.crop_data_cache_time = 0
|
||||||
|
self.cache_expire_duration = 300 # 缓存过期时间5分钟
|
||||||
|
|
||||||
self.log('INFO', f"萌芽农场TCP游戏服务器初始化完成 - 版本: {server_version}", 'SERVER')
|
self.log('INFO', f"萌芽农场TCP游戏服务器初始化完成 - 版本: {server_version}", 'SERVER')
|
||||||
|
|
||||||
# 启动定时器
|
# 启动定时器
|
||||||
@@ -96,6 +105,28 @@ class TCPGameServer(TCPServer):
|
|||||||
self.start_wisdom_tree_health_decay_timer()
|
self.start_wisdom_tree_health_decay_timer()
|
||||||
self.start_verification_code_cleanup_timer()
|
self.start_verification_code_cleanup_timer()
|
||||||
|
|
||||||
|
#初始化MongoDB API
|
||||||
|
def _init_mongodb_api(self):
|
||||||
|
"""初始化MongoDB API连接"""
|
||||||
|
try:
|
||||||
|
# 根据配置决定使用测试环境还是生产环境
|
||||||
|
# 这里默认使用测试环境,实际部署时可以修改为 "production"
|
||||||
|
environment = "test" # 或者从配置文件读取
|
||||||
|
|
||||||
|
self.mongo_api = SMYMongoDBAPI(environment)
|
||||||
|
if self.mongo_api.is_connected():
|
||||||
|
self.use_mongodb = True
|
||||||
|
self.log('INFO', f"MongoDB API初始化成功 [{environment}]", 'SERVER')
|
||||||
|
else:
|
||||||
|
self.use_mongodb = False
|
||||||
|
self.mongo_api = None
|
||||||
|
self.log('WARNING', "MongoDB连接失败,将使用JSON配置文件", 'SERVER')
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
self.use_mongodb = False
|
||||||
|
self.mongo_api = None
|
||||||
|
self.log('ERROR', f"MongoDB API初始化异常: {e},将使用JSON配置文件", 'SERVER')
|
||||||
|
|
||||||
#初始化性能操作
|
#初始化性能操作
|
||||||
def _init_performance_settings(self):
|
def _init_performance_settings(self):
|
||||||
"""初始化性能优化配置"""
|
"""初始化性能优化配置"""
|
||||||
@@ -400,12 +431,22 @@ class TCPGameServer(TCPServer):
|
|||||||
|
|
||||||
return player_data, username, None
|
return player_data, username, None
|
||||||
|
|
||||||
#加载作物配置数据
|
#加载作物配置数据(优化版本)
|
||||||
def _load_crop_data(self):
|
def _load_crop_data(self):
|
||||||
"""加载作物配置数据"""
|
"""加载作物配置数据(带缓存优化)"""
|
||||||
|
current_time = time.time()
|
||||||
|
|
||||||
|
# 检查缓存是否有效
|
||||||
|
if (self.crop_data_cache is not None and
|
||||||
|
current_time - self.crop_data_cache_time < self.cache_expire_duration):
|
||||||
|
return self.crop_data_cache
|
||||||
|
|
||||||
|
# 缓存过期或不存在,重新加载
|
||||||
try:
|
try:
|
||||||
with open("config/crop_data.json", 'r', encoding='utf-8') as file:
|
with open("config/crop_data.json", 'r', encoding='utf-8') as file:
|
||||||
return json.load(file)
|
self.crop_data_cache = json.load(file)
|
||||||
|
self.crop_data_cache_time = current_time
|
||||||
|
return self.crop_data_cache
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log('ERROR', f"无法加载作物数据: {str(e)}", 'SERVER')
|
self.log('ERROR', f"无法加载作物数据: {str(e)}", 'SERVER')
|
||||||
return {}
|
return {}
|
||||||
@@ -810,6 +851,8 @@ class TCPGameServer(TCPServer):
|
|||||||
return self._handle_buy_store_product(client_id, message)
|
return self._handle_buy_store_product(client_id, message)
|
||||||
elif message_type == "buy_store_booth":#购买小卖部格子
|
elif message_type == "buy_store_booth":#购买小卖部格子
|
||||||
return self._handle_buy_store_booth(client_id, message)
|
return self._handle_buy_store_booth(client_id, message)
|
||||||
|
elif message_type == "save_game_settings":#保存游戏设置
|
||||||
|
return self._handle_save_game_settings(client_id, message)
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
|
|
||||||
elif message_type == "message":#处理聊天消息(暂未实现)
|
elif message_type == "message":#处理聊天消息(暂未实现)
|
||||||
@@ -1340,7 +1383,7 @@ class TCPGameServer(TCPServer):
|
|||||||
#==========================收获作物处理==========================
|
#==========================收获作物处理==========================
|
||||||
#处理收获作物请求
|
#处理收获作物请求
|
||||||
def _handle_harvest_crop(self, client_id, message):
|
def _handle_harvest_crop(self, client_id, message):
|
||||||
"""处理收获作物请求"""
|
"""处理收获作物请求(优化版本)"""
|
||||||
# 检查用户是否已登录
|
# 检查用户是否已登录
|
||||||
logged_in, response = self._check_user_logged_in(client_id, "收获作物", "harvest_crop")
|
logged_in, response = self._check_user_logged_in(client_id, "收获作物", "harvest_crop")
|
||||||
if not logged_in:
|
if not logged_in:
|
||||||
@@ -1354,6 +1397,11 @@ class TCPGameServer(TCPServer):
|
|||||||
lot_index = message.get("lot_index", -1)
|
lot_index = message.get("lot_index", -1)
|
||||||
target_username = message.get("target_username", "")
|
target_username = message.get("target_username", "")
|
||||||
|
|
||||||
|
# 预加载作物配置数据(只加载一次)
|
||||||
|
crop_data = self._load_crop_data()
|
||||||
|
if not crop_data:
|
||||||
|
return self._send_action_error(client_id, "harvest_crop", "无法加载作物配置数据")
|
||||||
|
|
||||||
# 确定操作目标:如果有target_username就是访问模式(偷菜),否则是自己的农场
|
# 确定操作目标:如果有target_username就是访问模式(偷菜),否则是自己的农场
|
||||||
if target_username and target_username != current_username:
|
if target_username and target_username != current_username:
|
||||||
# 访问模式:偷菜(收益给自己,清空目标玩家的作物)
|
# 访问模式:偷菜(收益给自己,清空目标玩家的作物)
|
||||||
@@ -1396,7 +1444,7 @@ class TCPGameServer(TCPServer):
|
|||||||
return self._send_action_error(client_id, "harvest_crop", "作物尚未成熟,无法偷菜")
|
return self._send_action_error(client_id, "harvest_crop", "作物尚未成熟,无法偷菜")
|
||||||
|
|
||||||
# 处理偷菜
|
# 处理偷菜
|
||||||
return self._process_steal_crop(client_id, current_player_data, current_username, target_player_data, target_username, target_lot, lot_index)
|
return self._process_steal_crop_optimized(client_id, current_player_data, current_username, target_player_data, target_username, target_lot, lot_index, crop_data)
|
||||||
else:
|
else:
|
||||||
# 正常模式:收获自己的作物
|
# 正常模式:收获自己的作物
|
||||||
# 验证地块索引
|
# 验证地块索引
|
||||||
@@ -1434,55 +1482,55 @@ class TCPGameServer(TCPServer):
|
|||||||
return self._send_action_error(client_id, "harvest_crop", "作物尚未成熟")
|
return self._send_action_error(client_id, "harvest_crop", "作物尚未成熟")
|
||||||
|
|
||||||
# 处理正常收获
|
# 处理正常收获
|
||||||
return self._process_harvest(client_id, current_player_data, current_username, lot, lot_index)
|
return self._process_harvest_optimized(client_id, current_player_data, current_username, lot, lot_index, crop_data)
|
||||||
|
|
||||||
#辅助函数-处理作物收获
|
#辅助函数-处理作物收获(优化版本)
|
||||||
def _process_harvest(self, client_id, player_data, username, lot, lot_index):
|
def _process_harvest_optimized(self, client_id, player_data, username, lot, lot_index, crop_data):
|
||||||
"""处理作物收获逻辑"""
|
"""处理作物收获逻辑(优化版本)"""
|
||||||
# 读取作物配置
|
# 获取作物类型和基本信息
|
||||||
crop_data = self._load_crop_data()
|
|
||||||
|
|
||||||
# 获取作物类型和经验
|
|
||||||
crop_type = lot["crop_type"]
|
crop_type = lot["crop_type"]
|
||||||
|
crop_info = crop_data.get(crop_type, {})
|
||||||
|
|
||||||
# 检查是否为杂草类型(杂草不能收获,只能铲除)
|
# 检查是否为杂草类型(杂草不能收获,只能铲除)
|
||||||
if crop_type in crop_data:
|
|
||||||
crop_info = crop_data[crop_type]
|
|
||||||
is_weed = crop_info.get("是否杂草", False)
|
is_weed = crop_info.get("是否杂草", False)
|
||||||
|
|
||||||
if is_weed:
|
if is_weed:
|
||||||
return self._send_action_error(client_id, "harvest_crop", f"{crop_type}不能收获,只能铲除!请使用铲除功能清理杂草。")
|
return self._send_action_error(client_id, "harvest_crop", f"{crop_type}不能收获,只能铲除!请使用铲除功能清理杂草。")
|
||||||
|
|
||||||
crop_exp = crop_info.get("经验", 10)
|
|
||||||
|
|
||||||
# 额外检查:如果作物收益为负数,也视为杂草
|
# 额外检查:如果作物收益为负数,也视为杂草
|
||||||
crop_income = crop_info.get("收益", 100) + crop_info.get("花费", 0)
|
crop_income = crop_info.get("收益", 100) + crop_info.get("花费", 0)
|
||||||
if crop_income < 0:
|
if crop_income < 0:
|
||||||
return self._send_action_error(client_id, "harvest_crop", f"{crop_type}不能收获,只能铲除!请使用铲除功能清理杂草。")
|
return self._send_action_error(client_id, "harvest_crop", f"{crop_type}不能收获,只能铲除!请使用铲除功能清理杂草。")
|
||||||
else:
|
|
||||||
# 默认经验
|
# 获取作物经验
|
||||||
crop_exp = 10
|
crop_exp = crop_info.get("经验", 10)
|
||||||
|
|
||||||
# 生成成熟物收获(1-5个)
|
# 生成成熟物收获(1-5个)
|
||||||
import random
|
import random
|
||||||
harvest_count = random.randint(1, 5)
|
harvest_count = random.randint(1, 5)
|
||||||
crop_harvest = {
|
|
||||||
"name": crop_type,
|
|
||||||
"count": harvest_count
|
|
||||||
}
|
|
||||||
|
|
||||||
# 10%概率获得1-2个该作物的种子
|
# 10%概率获得1-2个该作物的种子
|
||||||
seed_reward = self._generate_harvest_seed_reward(crop_type)
|
seed_reward = None
|
||||||
|
if random.random() <= 0.1:
|
||||||
|
seed_reward = {
|
||||||
|
"name": crop_type,
|
||||||
|
"count": random.randint(1, 2)
|
||||||
|
}
|
||||||
|
|
||||||
# 更新玩家经验(不再直接给钱)
|
# 更新玩家经验
|
||||||
player_data["experience"] += crop_exp
|
player_data["experience"] += crop_exp
|
||||||
|
|
||||||
# 添加成熟物到作物仓库
|
# 检查是否会获得成熟物
|
||||||
self._add_crop_to_warehouse(player_data, crop_harvest)
|
mature_name = crop_info.get("成熟物名称")
|
||||||
|
will_get_mature_item = mature_name is not None
|
||||||
|
mature_item_name = mature_name if mature_name and mature_name.strip() else crop_type
|
||||||
|
|
||||||
|
# 添加成熟物到作物仓库(如果允许)
|
||||||
|
if will_get_mature_item:
|
||||||
|
self._add_crop_to_warehouse_optimized(player_data, {"name": crop_type, "count": harvest_count}, mature_item_name, crop_info.get("品质", "普通"))
|
||||||
|
|
||||||
# 添加种子奖励到背包
|
# 添加种子奖励到背包
|
||||||
if seed_reward:
|
if seed_reward:
|
||||||
self._add_seeds_to_bag(player_data, seed_reward)
|
self._add_seeds_to_bag_optimized(player_data, seed_reward, crop_info.get("品质", "普通"))
|
||||||
|
|
||||||
# 检查升级
|
# 检查升级
|
||||||
level_up_experience = 100 * player_data["level"]
|
level_up_experience = 100 * player_data["level"]
|
||||||
@@ -1491,12 +1539,14 @@ class TCPGameServer(TCPServer):
|
|||||||
player_data["experience"] -= level_up_experience
|
player_data["experience"] -= level_up_experience
|
||||||
self.log('INFO', f"玩家 {username} 升级到 {player_data['level']} 级", 'SERVER')
|
self.log('INFO', f"玩家 {username} 升级到 {player_data['level']} 级", 'SERVER')
|
||||||
|
|
||||||
# 清理地块
|
# 清理地块(批量更新)
|
||||||
lot["is_planted"] = False
|
lot.update({
|
||||||
lot["crop_type"] = ""
|
"is_planted": False,
|
||||||
lot["grow_time"] = 0
|
"crop_type": "",
|
||||||
lot["已浇水"] = False
|
"grow_time": 0,
|
||||||
lot["已施肥"] = False
|
"已浇水": False,
|
||||||
|
"已施肥": False
|
||||||
|
})
|
||||||
|
|
||||||
# 清除施肥时间戳
|
# 清除施肥时间戳
|
||||||
if "施肥时间" in lot:
|
if "施肥时间" in lot:
|
||||||
@@ -1509,7 +1559,11 @@ class TCPGameServer(TCPServer):
|
|||||||
self._push_crop_update_to_player(username, player_data)
|
self._push_crop_update_to_player(username, player_data)
|
||||||
|
|
||||||
# 构建消息
|
# 构建消息
|
||||||
message = f"收获成功,获得 {crop_type} x{harvest_count} 和 {crop_exp} 经验"
|
if will_get_mature_item:
|
||||||
|
message = f"收获成功,获得 {mature_item_name} x{harvest_count} 和 {crop_exp} 经验"
|
||||||
|
else:
|
||||||
|
message = f"收获成功,获得 {crop_exp} 经验({crop_type}无成熟物产出)"
|
||||||
|
|
||||||
if seed_reward:
|
if seed_reward:
|
||||||
message += f",额外获得 {seed_reward['name']} 种子 x{seed_reward['count']}"
|
message += f",额外获得 {seed_reward['name']} 种子 x{seed_reward['count']}"
|
||||||
|
|
||||||
@@ -1529,9 +1583,9 @@ class TCPGameServer(TCPServer):
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
#辅助函数-处理偷菜逻辑(访问模式下收获其他玩家作物的操作)
|
#辅助函数-处理偷菜逻辑(访问模式下收获其他玩家作物的操作)(优化版本)
|
||||||
def _process_steal_crop(self, client_id, current_player_data, current_username, target_player_data, target_username, target_lot, lot_index):
|
def _process_steal_crop_optimized(self, client_id, current_player_data, current_username, target_player_data, target_username, target_lot, lot_index, crop_data):
|
||||||
"""处理偷菜逻辑(收益给当前玩家,清空目标玩家的作物)"""
|
"""处理偷菜逻辑(收益给当前玩家,清空目标玩家的作物)(优化版本)"""
|
||||||
# 偷菜体力值消耗
|
# 偷菜体力值消耗
|
||||||
stamina_cost = 2
|
stamina_cost = 2
|
||||||
|
|
||||||
@@ -1554,40 +1608,34 @@ class TCPGameServer(TCPServer):
|
|||||||
target_player_data, target_username, patrol_pets[0]
|
target_player_data, target_username, patrol_pets[0]
|
||||||
)
|
)
|
||||||
|
|
||||||
# 读取作物配置
|
# 获取作物类型和基本信息
|
||||||
crop_data = self._load_crop_data()
|
|
||||||
|
|
||||||
# 获取作物类型和经验(偷菜获得的经验稍微少一些,比如50%)
|
|
||||||
crop_type = target_lot["crop_type"]
|
crop_type = target_lot["crop_type"]
|
||||||
|
crop_info = crop_data.get(crop_type, {})
|
||||||
|
|
||||||
# 检查是否为杂草类型(杂草不能偷取,只能铲除)
|
# 检查是否为杂草类型(杂草不能偷取,只能铲除)
|
||||||
if crop_type in crop_data:
|
|
||||||
crop_info = crop_data[crop_type]
|
|
||||||
is_weed = crop_info.get("是否杂草", False)
|
is_weed = crop_info.get("是否杂草", False)
|
||||||
|
|
||||||
if is_weed:
|
if is_weed:
|
||||||
return self._send_action_error(client_id, "harvest_crop", f"{crop_type}不能偷取,只能铲除!这是杂草,没有收益价值。")
|
return self._send_action_error(client_id, "harvest_crop", f"{crop_type}不能偷取,只能铲除!这是杂草,没有收益价值。")
|
||||||
|
|
||||||
crop_exp = int(crop_info.get("经验", 10) * 0.5) # 偷菜获得50%经验
|
|
||||||
|
|
||||||
# 额外检查:如果作物收益为负数,也视为杂草
|
# 额外检查:如果作物收益为负数,也视为杂草
|
||||||
crop_income = crop_info.get("收益", 100) + crop_info.get("花费", 0)
|
crop_income = crop_info.get("收益", 100) + crop_info.get("花费", 0)
|
||||||
if crop_income < 0:
|
if crop_income < 0:
|
||||||
return self._send_action_error(client_id, "harvest_crop", f"{crop_type}不能偷取,只能铲除!这是杂草,没有收益价值。")
|
return self._send_action_error(client_id, "harvest_crop", f"{crop_type}不能偷取,只能铲除!这是杂草,没有收益价值。")
|
||||||
else:
|
|
||||||
# 默认经验
|
# 获取作物经验(偷菜获得50%经验)
|
||||||
crop_exp = 5
|
crop_exp = int(crop_info.get("经验", 10) * 0.5)
|
||||||
|
|
||||||
# 生成成熟物收获(偷菜获得较少,1-3个)
|
# 生成成熟物收获(偷菜获得较少,1-3个)
|
||||||
import random
|
import random
|
||||||
harvest_count = random.randint(1, 3)
|
harvest_count = random.randint(1, 3)
|
||||||
crop_harvest = {
|
|
||||||
"name": crop_type,
|
|
||||||
"count": harvest_count
|
|
||||||
}
|
|
||||||
|
|
||||||
# 10%概率获得1-2个该作物的种子(偷菜也有机会获得种子)
|
# 10%概率获得1-2个该作物的种子(偷菜也有机会获得种子)
|
||||||
seed_reward = self._generate_harvest_seed_reward(crop_type)
|
seed_reward = None
|
||||||
|
if random.random() <= 0.1:
|
||||||
|
seed_reward = {
|
||||||
|
"name": crop_type,
|
||||||
|
"count": random.randint(1, 2)
|
||||||
|
}
|
||||||
|
|
||||||
# 消耗当前玩家的体力值
|
# 消耗当前玩家的体力值
|
||||||
stamina_success, stamina_message = self._consume_stamina(current_player_data, stamina_cost, "偷菜")
|
stamina_success, stamina_message = self._consume_stamina(current_player_data, stamina_cost, "偷菜")
|
||||||
@@ -1597,12 +1645,18 @@ class TCPGameServer(TCPServer):
|
|||||||
# 更新当前玩家数据(获得经验)
|
# 更新当前玩家数据(获得经验)
|
||||||
current_player_data["experience"] += crop_exp
|
current_player_data["experience"] += crop_exp
|
||||||
|
|
||||||
# 添加成熟物到作物仓库
|
# 检查是否会获得成熟物
|
||||||
self._add_crop_to_warehouse(current_player_data, crop_harvest)
|
mature_name = crop_info.get("成熟物名称")
|
||||||
|
will_get_mature_item = mature_name is not None
|
||||||
|
mature_item_name = mature_name if mature_name and mature_name.strip() else crop_type
|
||||||
|
|
||||||
|
# 添加成熟物到作物仓库(如果允许)
|
||||||
|
if will_get_mature_item:
|
||||||
|
self._add_crop_to_warehouse_optimized(current_player_data, {"name": crop_type, "count": harvest_count}, mature_item_name, crop_info.get("品质", "普通"))
|
||||||
|
|
||||||
# 添加种子奖励到背包
|
# 添加种子奖励到背包
|
||||||
if seed_reward:
|
if seed_reward:
|
||||||
self._add_seeds_to_bag(current_player_data, seed_reward)
|
self._add_seeds_to_bag_optimized(current_player_data, seed_reward, crop_info.get("品质", "普通"))
|
||||||
|
|
||||||
# 检查当前玩家升级
|
# 检查当前玩家升级
|
||||||
level_up_experience = 100 * current_player_data["level"]
|
level_up_experience = 100 * current_player_data["level"]
|
||||||
@@ -1611,12 +1665,14 @@ class TCPGameServer(TCPServer):
|
|||||||
current_player_data["experience"] -= level_up_experience
|
current_player_data["experience"] -= level_up_experience
|
||||||
self.log('INFO', f"玩家 {current_username} 升级到 {current_player_data['level']} 级", 'SERVER')
|
self.log('INFO', f"玩家 {current_username} 升级到 {current_player_data['level']} 级", 'SERVER')
|
||||||
|
|
||||||
# 清理目标玩家的地块
|
# 清理目标玩家的地块(批量更新)
|
||||||
target_lot["is_planted"] = False
|
target_lot.update({
|
||||||
target_lot["crop_type"] = ""
|
"is_planted": False,
|
||||||
target_lot["grow_time"] = 0
|
"crop_type": "",
|
||||||
target_lot["已浇水"] = False
|
"grow_time": 0,
|
||||||
target_lot["已施肥"] = False
|
"已浇水": False,
|
||||||
|
"已施肥": False
|
||||||
|
})
|
||||||
|
|
||||||
# 清除施肥时间戳
|
# 清除施肥时间戳
|
||||||
if "施肥时间" in target_lot:
|
if "施肥时间" in target_lot:
|
||||||
@@ -1630,7 +1686,11 @@ class TCPGameServer(TCPServer):
|
|||||||
self._push_crop_update_to_player(target_username, target_player_data)
|
self._push_crop_update_to_player(target_username, target_player_data)
|
||||||
|
|
||||||
# 构建消息
|
# 构建消息
|
||||||
message = f"偷菜成功!从 {target_username} 那里获得 {crop_type} x{harvest_count} 和 {crop_exp} 经验,{stamina_message}"
|
if will_get_mature_item:
|
||||||
|
message = f"偷菜成功!从 {target_username} 那里获得 {mature_item_name} x{harvest_count} 和 {crop_exp} 经验,{stamina_message}"
|
||||||
|
else:
|
||||||
|
message = f"偷菜成功!从 {target_username} 那里获得 {crop_exp} 经验,{stamina_message}({crop_type}无成熟物产出)"
|
||||||
|
|
||||||
if seed_reward:
|
if seed_reward:
|
||||||
message += f",额外获得 {seed_reward['name']} 种子 x{seed_reward['count']}"
|
message += f",额外获得 {seed_reward['name']} 种子 x{seed_reward['count']}"
|
||||||
|
|
||||||
@@ -1810,6 +1870,24 @@ class TCPGameServer(TCPServer):
|
|||||||
crop_name = crop_harvest["name"]
|
crop_name = crop_harvest["name"]
|
||||||
crop_count = crop_harvest["count"]
|
crop_count = crop_harvest["count"]
|
||||||
|
|
||||||
|
# 从作物数据检查"成熟物名称"字段
|
||||||
|
crop_data = self._load_crop_data()
|
||||||
|
if crop_data and crop_name in crop_data:
|
||||||
|
mature_name = crop_data[crop_name].get("成熟物名称")
|
||||||
|
# 如果成熟物名称为null,则不添加成熟物到仓库
|
||||||
|
if mature_name is None:
|
||||||
|
self.log('DEBUG', f"作物 {crop_name} 的成熟物名称为null,跳过添加到作物仓库", 'SERVER')
|
||||||
|
return
|
||||||
|
|
||||||
|
# 如果有指定的成熟物名称,使用它作为仓库中的名称
|
||||||
|
if mature_name and mature_name.strip():
|
||||||
|
warehouse_item_name = mature_name
|
||||||
|
else:
|
||||||
|
warehouse_item_name = crop_name
|
||||||
|
else:
|
||||||
|
# 如果作物数据中没有该作物,使用原名称
|
||||||
|
warehouse_item_name = crop_name
|
||||||
|
|
||||||
# 确保作物仓库存在
|
# 确保作物仓库存在
|
||||||
if "作物仓库" not in player_data:
|
if "作物仓库" not in player_data:
|
||||||
player_data["作物仓库"] = []
|
player_data["作物仓库"] = []
|
||||||
@@ -1817,7 +1895,7 @@ class TCPGameServer(TCPServer):
|
|||||||
# 查找仓库中是否已有该成熟物
|
# 查找仓库中是否已有该成熟物
|
||||||
crop_found = False
|
crop_found = False
|
||||||
for item in player_data["作物仓库"]:
|
for item in player_data["作物仓库"]:
|
||||||
if item.get("name") == crop_name:
|
if item.get("name") == warehouse_item_name:
|
||||||
item["count"] += crop_count
|
item["count"] += crop_count
|
||||||
crop_found = True
|
crop_found = True
|
||||||
break
|
break
|
||||||
@@ -1825,13 +1903,62 @@ class TCPGameServer(TCPServer):
|
|||||||
# 如果仓库中没有该成熟物,添加新条目
|
# 如果仓库中没有该成熟物,添加新条目
|
||||||
if not crop_found:
|
if not crop_found:
|
||||||
# 从作物数据获取品质信息
|
# 从作物数据获取品质信息
|
||||||
crop_data = self._load_crop_data()
|
|
||||||
quality = "普通"
|
quality = "普通"
|
||||||
if crop_data and crop_name in crop_data:
|
if crop_data and crop_name in crop_data:
|
||||||
quality = crop_data[crop_name].get("品质", "普通")
|
quality = crop_data[crop_name].get("品质", "普通")
|
||||||
|
|
||||||
player_data["作物仓库"].append({
|
player_data["作物仓库"].append({
|
||||||
"name": crop_name,
|
"name": warehouse_item_name,
|
||||||
|
"quality": quality,
|
||||||
|
"count": crop_count
|
||||||
|
})
|
||||||
|
|
||||||
|
# 添加种子到玩家背包(优化版本)
|
||||||
|
def _add_seeds_to_bag_optimized(self, player_data, seed_reward, quality="普通"):
|
||||||
|
"""将种子奖励添加到玩家背包(优化版本)"""
|
||||||
|
if not seed_reward:
|
||||||
|
return
|
||||||
|
|
||||||
|
seed_name = seed_reward["name"]
|
||||||
|
seed_count = seed_reward["count"]
|
||||||
|
|
||||||
|
# 确保背包存在
|
||||||
|
if "player_bag" not in player_data:
|
||||||
|
player_data["player_bag"] = []
|
||||||
|
|
||||||
|
# 查找背包中是否已有该种子
|
||||||
|
for item in player_data["player_bag"]:
|
||||||
|
if item.get("name") == seed_name:
|
||||||
|
item["count"] += seed_count
|
||||||
|
return
|
||||||
|
|
||||||
|
# 如果背包中没有该种子,添加新条目
|
||||||
|
player_data["player_bag"].append({
|
||||||
|
"name": seed_name,
|
||||||
|
"quality": quality,
|
||||||
|
"count": seed_count
|
||||||
|
})
|
||||||
|
|
||||||
|
def _add_crop_to_warehouse_optimized(self, player_data, crop_harvest, warehouse_item_name, quality="普通"):
|
||||||
|
"""将成熟物添加到玩家作物仓库(优化版本)"""
|
||||||
|
if not crop_harvest:
|
||||||
|
return
|
||||||
|
|
||||||
|
crop_count = crop_harvest["count"]
|
||||||
|
|
||||||
|
# 确保作物仓库存在
|
||||||
|
if "作物仓库" not in player_data:
|
||||||
|
player_data["作物仓库"] = []
|
||||||
|
|
||||||
|
# 查找仓库中是否已有该成熟物
|
||||||
|
for item in player_data["作物仓库"]:
|
||||||
|
if item.get("name") == warehouse_item_name:
|
||||||
|
item["count"] += crop_count
|
||||||
|
return
|
||||||
|
|
||||||
|
# 如果仓库中没有该成熟物,添加新条目
|
||||||
|
player_data["作物仓库"].append({
|
||||||
|
"name": warehouse_item_name,
|
||||||
"quality": quality,
|
"quality": quality,
|
||||||
"count": crop_count
|
"count": crop_count
|
||||||
})
|
})
|
||||||
@@ -4427,7 +4554,20 @@ class TCPGameServer(TCPServer):
|
|||||||
# 检查是否升级
|
# 检查是否升级
|
||||||
self._check_level_up(player_data)
|
self._check_level_up(player_data)
|
||||||
|
|
||||||
# 添加成熟物到作物仓库
|
# 检查是否会获得成熟物
|
||||||
|
crop_data = self._load_crop_data()
|
||||||
|
will_get_mature_item = True
|
||||||
|
mature_item_name = crop_type
|
||||||
|
|
||||||
|
if crop_data and crop_type in crop_data:
|
||||||
|
mature_name = crop_data[crop_type].get("成熟物名称")
|
||||||
|
if mature_name is None:
|
||||||
|
will_get_mature_item = False
|
||||||
|
elif mature_name and mature_name.strip():
|
||||||
|
mature_item_name = mature_name
|
||||||
|
|
||||||
|
# 添加成熟物到作物仓库(如果允许)
|
||||||
|
if will_get_mature_item:
|
||||||
self._add_crop_to_warehouse(player_data, crop_harvest)
|
self._add_crop_to_warehouse(player_data, crop_harvest)
|
||||||
|
|
||||||
# 添加种子奖励到背包
|
# 添加种子奖励到背包
|
||||||
@@ -4452,7 +4592,11 @@ class TCPGameServer(TCPServer):
|
|||||||
self._push_crop_update_to_player(username, player_data)
|
self._push_crop_update_to_player(username, player_data)
|
||||||
|
|
||||||
# 构建消息
|
# 构建消息
|
||||||
message = f"使用 {item_name} 收获成功,获得 {crop_type} x{harvest_count} 和 {crop_exp} 经验{message_suffix}"
|
if will_get_mature_item:
|
||||||
|
message = f"使用 {item_name} 收获成功,获得 {mature_item_name} x{harvest_count} 和 {crop_exp} 经验{message_suffix}"
|
||||||
|
else:
|
||||||
|
message = f"使用 {item_name} 收获成功,获得 {crop_exp} 经验{message_suffix}({crop_type}无成熟物产出)"
|
||||||
|
|
||||||
if seed_reward:
|
if seed_reward:
|
||||||
message += f",额外获得 {seed_reward['name']} x{seed_reward['count']}"
|
message += f",额外获得 {seed_reward['name']} x{seed_reward['count']}"
|
||||||
|
|
||||||
@@ -4546,7 +4690,20 @@ class TCPGameServer(TCPServer):
|
|||||||
# 检查当前玩家是否升级
|
# 检查当前玩家是否升级
|
||||||
self._check_level_up(current_player_data)
|
self._check_level_up(current_player_data)
|
||||||
|
|
||||||
# 收获物给当前玩家
|
# 检查是否会获得成熟物
|
||||||
|
crop_data = self._load_crop_data()
|
||||||
|
will_get_mature_item = True
|
||||||
|
mature_item_name = crop_type
|
||||||
|
|
||||||
|
if crop_data and crop_type in crop_data:
|
||||||
|
mature_name = crop_data[crop_type].get("成熟物名称")
|
||||||
|
if mature_name is None:
|
||||||
|
will_get_mature_item = False
|
||||||
|
elif mature_name and mature_name.strip():
|
||||||
|
mature_item_name = mature_name
|
||||||
|
|
||||||
|
# 收获物给当前玩家(如果允许)
|
||||||
|
if will_get_mature_item:
|
||||||
self._add_crop_to_warehouse(current_player_data, crop_harvest)
|
self._add_crop_to_warehouse(current_player_data, crop_harvest)
|
||||||
|
|
||||||
# 种子奖励给当前玩家
|
# 种子奖励给当前玩家
|
||||||
@@ -4572,7 +4729,11 @@ class TCPGameServer(TCPServer):
|
|||||||
self._push_crop_update_to_player(target_username, target_player_data)
|
self._push_crop_update_to_player(target_username, target_player_data)
|
||||||
|
|
||||||
# 构建消息
|
# 构建消息
|
||||||
message = f"使用 {item_name} 帮助收获成功!从 {target_username} 那里获得 {crop_type} x{harvest_count} 和 {crop_exp} 经验{message_suffix}"
|
if will_get_mature_item:
|
||||||
|
message = f"使用 {item_name} 帮助收获成功!从 {target_username} 那里获得 {mature_item_name} x{harvest_count} 和 {crop_exp} 经验{message_suffix}"
|
||||||
|
else:
|
||||||
|
message = f"使用 {item_name} 帮助收获成功!从 {target_username} 那里获得 {crop_exp} 经验{message_suffix}({crop_type}无成熟物产出)"
|
||||||
|
|
||||||
if seed_reward:
|
if seed_reward:
|
||||||
message += f",额外获得 {seed_reward['name']} x{seed_reward['count']}"
|
message += f",额外获得 {seed_reward['name']} x{seed_reward['count']}"
|
||||||
|
|
||||||
@@ -5418,6 +5579,7 @@ class TCPGameServer(TCPServer):
|
|||||||
current_stamina = stamina_system.get("当前体力值", 20)
|
current_stamina = stamina_system.get("当前体力值", 20)
|
||||||
return current_stamina >= amount
|
return current_stamina >= amount
|
||||||
|
|
||||||
|
|
||||||
def _check_and_update_register_time(self, player_data, username):
|
def _check_and_update_register_time(self, player_data, username):
|
||||||
"""检查并更新已存在玩家的注册时间"""
|
"""检查并更新已存在玩家的注册时间"""
|
||||||
default_register_time = "2025年05月21日15时00分00秒"
|
default_register_time = "2025年05月21日15时00分00秒"
|
||||||
@@ -5516,6 +5678,81 @@ class TCPGameServer(TCPServer):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#==========================游戏设置处理==========================
|
||||||
|
def _handle_save_game_settings(self, client_id, message):
|
||||||
|
"""处理保存游戏设置请求"""
|
||||||
|
# 检查用户是否已登录
|
||||||
|
logged_in, response = self._check_user_logged_in(client_id, "保存游戏设置", "save_game_settings")
|
||||||
|
if not logged_in:
|
||||||
|
return self.send_data(client_id, response)
|
||||||
|
|
||||||
|
# 获取玩家数据
|
||||||
|
player_data, username, response = self._load_player_data_with_check(client_id, "save_game_settings")
|
||||||
|
if not player_data:
|
||||||
|
return self.send_data(client_id, response)
|
||||||
|
|
||||||
|
# 获取设置数据
|
||||||
|
settings = message.get("settings", {})
|
||||||
|
if not settings:
|
||||||
|
return self.send_data(client_id, {
|
||||||
|
"type": "save_game_settings_response",
|
||||||
|
"success": False,
|
||||||
|
"message": "设置数据为空"
|
||||||
|
})
|
||||||
|
|
||||||
|
# 验证设置数据格式
|
||||||
|
valid_settings = {}
|
||||||
|
|
||||||
|
# 验证背景音乐音量 (0.0-1.0)
|
||||||
|
if "背景音乐音量" in settings:
|
||||||
|
volume = settings["背景音乐音量"]
|
||||||
|
if isinstance(volume, (int, float)) and 0.0 <= volume <= 1.0:
|
||||||
|
valid_settings["背景音乐音量"] = float(volume)
|
||||||
|
else:
|
||||||
|
return self.send_data(client_id, {
|
||||||
|
"type": "save_game_settings_response",
|
||||||
|
"success": False,
|
||||||
|
"message": "背景音乐音量值无效,应在0.0-1.0之间"
|
||||||
|
})
|
||||||
|
|
||||||
|
# 验证天气显示设置
|
||||||
|
if "天气显示" in settings:
|
||||||
|
weather_display = settings["天气显示"]
|
||||||
|
if isinstance(weather_display, bool):
|
||||||
|
valid_settings["天气显示"] = weather_display
|
||||||
|
else:
|
||||||
|
return self.send_data(client_id, {
|
||||||
|
"type": "save_game_settings_response",
|
||||||
|
"success": False,
|
||||||
|
"message": "天气显示设置值无效,应为布尔值"
|
||||||
|
})
|
||||||
|
|
||||||
|
# 保存设置到玩家数据
|
||||||
|
if "游戏设置" not in player_data:
|
||||||
|
player_data["游戏设置"] = {}
|
||||||
|
|
||||||
|
player_data["游戏设置"].update(valid_settings)
|
||||||
|
|
||||||
|
# 保存到数据库
|
||||||
|
if self.save_player_data(username, player_data):
|
||||||
|
self.log('INFO', f"用户 {username} 保存游戏设置: {valid_settings}", 'SERVER')
|
||||||
|
|
||||||
|
return self.send_data(client_id, {
|
||||||
|
"type": "save_game_settings_response",
|
||||||
|
"success": True,
|
||||||
|
"message": "游戏设置保存成功",
|
||||||
|
"settings": valid_settings
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
return self.send_data(client_id, {
|
||||||
|
"type": "save_game_settings_response",
|
||||||
|
"success": False,
|
||||||
|
"message": "保存游戏设置失败"
|
||||||
|
})
|
||||||
|
#==========================游戏设置处理==========================
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#==========================玩家游玩时间处理==========================
|
#==========================玩家游玩时间处理==========================
|
||||||
#处理获取玩家游玩时间请求
|
#处理获取玩家游玩时间请求
|
||||||
def _handle_get_play_time(self, client_id):
|
def _handle_get_play_time(self, client_id):
|
||||||
@@ -6506,16 +6743,32 @@ class TCPGameServer(TCPServer):
|
|||||||
#==========================每日签到处理==========================
|
#==========================每日签到处理==========================
|
||||||
#加载每日签到配置
|
#加载每日签到配置
|
||||||
def _load_daily_check_in_config(self):
|
def _load_daily_check_in_config(self):
|
||||||
"""加载每日签到配置"""
|
"""加载每日签到配置 - 优先使用MongoDB,失败则回退到JSON文件"""
|
||||||
|
# 优先尝试从MongoDB获取配置
|
||||||
|
if hasattr(self, 'use_mongodb') and self.use_mongodb and self.mongo_api:
|
||||||
|
try:
|
||||||
|
config = self.mongo_api.get_daily_checkin_config()
|
||||||
|
if config:
|
||||||
|
self.log('INFO', "从MongoDB成功加载每日签到配置", 'SERVER')
|
||||||
|
return config
|
||||||
|
else:
|
||||||
|
self.log('WARNING', "MongoDB中未找到每日签到配置,尝试使用JSON文件", 'SERVER')
|
||||||
|
except Exception as e:
|
||||||
|
self.log('ERROR', f"从MongoDB加载每日签到配置失败: {e},回退到JSON文件", 'SERVER')
|
||||||
|
|
||||||
|
# 回退到JSON文件
|
||||||
try:
|
try:
|
||||||
config_path = os.path.join(self.config_dir, "daily_checkin_config.json")
|
config_path = os.path.join(self.config_dir, "daily_checkin_config.json")
|
||||||
if os.path.exists(config_path):
|
if os.path.exists(config_path):
|
||||||
with open(config_path, 'r', encoding='utf-8') as f:
|
with open(config_path, 'r', encoding='utf-8') as f:
|
||||||
return json.load(f)
|
config = json.load(f)
|
||||||
except:
|
self.log('INFO', "从JSON文件成功加载每日签到配置", 'SERVER')
|
||||||
pass
|
return config
|
||||||
|
except Exception as e:
|
||||||
|
self.log('ERROR', f"从JSON文件加载每日签到配置失败: {e}", 'SERVER')
|
||||||
|
|
||||||
# 默认配置
|
# 默认配置
|
||||||
|
self.log('WARNING', "使用默认每日签到配置", 'SERVER')
|
||||||
return {
|
return {
|
||||||
"基础奖励": {
|
"基础奖励": {
|
||||||
"金币": {"最小值": 200, "最大值": 500, "图标": "💰", "颜色": "#FFD700"},
|
"金币": {"最小值": 200, "最大值": 500, "图标": "💰", "颜色": "#FFD700"},
|
||||||
@@ -6537,6 +6790,25 @@ class TCPGameServer(TCPServer):
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#更新每日签到配置到MongoDB
|
||||||
|
def _update_daily_checkin_config_to_mongodb(self, config_data):
|
||||||
|
"""更新每日签到配置到MongoDB"""
|
||||||
|
if hasattr(self, 'use_mongodb') and self.use_mongodb and self.mongo_api:
|
||||||
|
try:
|
||||||
|
success = self.mongo_api.update_daily_checkin_config(config_data)
|
||||||
|
if success:
|
||||||
|
self.log('INFO', "成功更新每日签到配置到MongoDB", 'SERVER')
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
self.log('ERROR', "更新每日签到配置到MongoDB失败", 'SERVER')
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
self.log('ERROR', f"更新每日签到配置到MongoDB异常: {e}", 'SERVER')
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
self.log('WARNING', "MongoDB未连接,无法更新配置", 'SERVER')
|
||||||
|
return False
|
||||||
|
|
||||||
#处理每日签到请求
|
#处理每日签到请求
|
||||||
def _handle_daily_check_in_request(self, client_id, message):
|
def _handle_daily_check_in_request(self, client_id, message):
|
||||||
"""处理每日签到请求"""
|
"""处理每日签到请求"""
|
||||||
@@ -7126,16 +7398,32 @@ class TCPGameServer(TCPServer):
|
|||||||
|
|
||||||
#加载抽奖配置
|
#加载抽奖配置
|
||||||
def _load_lucky_draw_config(self):
|
def _load_lucky_draw_config(self):
|
||||||
"""加载抽奖配置"""
|
"""加载抽奖配置(优先从MongoDB读取)"""
|
||||||
|
# 优先尝试从MongoDB读取
|
||||||
|
if self.use_mongodb and self.mongo_api:
|
||||||
|
try:
|
||||||
|
config = self.mongo_api.get_lucky_draw_config()
|
||||||
|
if config:
|
||||||
|
self.log('INFO', "成功从MongoDB加载幸运抽奖配置", 'SERVER')
|
||||||
|
return config
|
||||||
|
else:
|
||||||
|
self.log('WARNING', "MongoDB中未找到幸运抽奖配置,尝试从JSON文件读取", 'SERVER')
|
||||||
|
except Exception as e:
|
||||||
|
self.log('ERROR', f"从MongoDB读取幸运抽奖配置失败: {e},尝试从JSON文件读取", 'SERVER')
|
||||||
|
|
||||||
|
# 回退到JSON文件
|
||||||
try:
|
try:
|
||||||
config_path = os.path.join(self.config_dir, "lucky_draw_config.json")
|
config_path = os.path.join(self.config_dir, "lucky_draw_config.json")
|
||||||
if os.path.exists(config_path):
|
if os.path.exists(config_path):
|
||||||
with open(config_path, 'r', encoding='utf-8') as f:
|
with open(config_path, 'r', encoding='utf-8') as f:
|
||||||
return json.load(f)
|
config = json.load(f)
|
||||||
except:
|
self.log('INFO', "成功从JSON文件加载幸运抽奖配置", 'SERVER')
|
||||||
pass
|
return config
|
||||||
|
except Exception as e:
|
||||||
|
self.log('ERROR', f"从JSON文件读取幸运抽奖配置失败: {e},使用默认配置", 'SERVER')
|
||||||
|
|
||||||
# 默认配置
|
# 默认配置
|
||||||
|
self.log('WARNING', "使用默认幸运抽奖配置", 'SERVER')
|
||||||
return {
|
return {
|
||||||
"抽奖费用": {"单抽": 800, "五连抽": 3600, "十连抽": 6400},
|
"抽奖费用": {"单抽": 800, "五连抽": 3600, "十连抽": 6400},
|
||||||
"概率配置": {
|
"概率配置": {
|
||||||
@@ -7151,16 +7439,31 @@ class TCPGameServer(TCPServer):
|
|||||||
#加载在线礼包配置
|
#加载在线礼包配置
|
||||||
def _load_online_gift_config(self):
|
def _load_online_gift_config(self):
|
||||||
"""加载在线礼包配置"""
|
"""加载在线礼包配置"""
|
||||||
|
# 优先从MongoDB读取配置
|
||||||
|
if hasattr(self, 'mongo_api') and self.mongo_api and self.mongo_api.is_connected():
|
||||||
|
try:
|
||||||
|
config = self.mongo_api.get_online_gift_config()
|
||||||
|
if config:
|
||||||
|
self.log('INFO', '成功从MongoDB加载在线礼包配置', 'SERVER')
|
||||||
|
return config
|
||||||
|
else:
|
||||||
|
self.log('WARNING', '从MongoDB未找到在线礼包配置,尝试从JSON文件加载', 'SERVER')
|
||||||
|
except Exception as e:
|
||||||
|
self.log('ERROR', f'从MongoDB加载在线礼包配置失败: {str(e)},尝试从JSON文件加载', 'SERVER')
|
||||||
|
|
||||||
|
# 回退到JSON文件
|
||||||
try:
|
try:
|
||||||
config_path = os.path.join(self.config_dir, "online_gift_config.json")
|
config_path = os.path.join(self.config_dir, "online_gift_config.json")
|
||||||
if os.path.exists(config_path):
|
if os.path.exists(config_path):
|
||||||
with open(config_path, 'r', encoding='utf-8') as f:
|
with open(config_path, 'r', encoding='utf-8') as f:
|
||||||
return json.load(f)
|
config = json.load(f)
|
||||||
|
self.log('INFO', '成功从JSON文件加载在线礼包配置', 'SERVER')
|
||||||
|
return config
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log('ERROR', f"加载在线礼包配置失败: {str(e)}", 'SERVER')
|
self.log('ERROR', f"从JSON文件加载在线礼包配置失败: {str(e)}", 'SERVER')
|
||||||
pass
|
|
||||||
|
|
||||||
# 默认配置
|
# 默认配置
|
||||||
|
self.log('WARNING', '使用默认在线礼包配置', 'SERVER')
|
||||||
return {
|
return {
|
||||||
"在线礼包配置": {
|
"在线礼包配置": {
|
||||||
"1分钟": {"时长秒数": 60, "奖励": {"金币": 100, "经验": 50, "种子": [{"名称": "小麦", "数量": 5}]}},
|
"1分钟": {"时长秒数": 60, "奖励": {"金币": 100, "经验": 50, "种子": [{"名称": "小麦", "数量": 5}]}},
|
||||||
@@ -7174,15 +7477,31 @@ class TCPGameServer(TCPServer):
|
|||||||
#加载新手礼包配置
|
#加载新手礼包配置
|
||||||
def _load_new_player_config(self):
|
def _load_new_player_config(self):
|
||||||
"""加载新手礼包配置"""
|
"""加载新手礼包配置"""
|
||||||
|
# 优先从MongoDB读取配置
|
||||||
|
if hasattr(self, 'mongo_api') and self.mongo_api and self.mongo_api.is_connected():
|
||||||
|
try:
|
||||||
|
config = self.mongo_api.get_new_player_config()
|
||||||
|
if config:
|
||||||
|
self.log('INFO', '成功从MongoDB加载新手大礼包配置', 'SERVER')
|
||||||
|
return config
|
||||||
|
else:
|
||||||
|
self.log('WARNING', '从MongoDB未找到新手大礼包配置,尝试从JSON文件加载', 'SERVER')
|
||||||
|
except Exception as e:
|
||||||
|
self.log('ERROR', f'从MongoDB加载新手大礼包配置失败: {str(e)},尝试从JSON文件加载', 'SERVER')
|
||||||
|
|
||||||
|
# 回退到JSON文件
|
||||||
try:
|
try:
|
||||||
config_path = os.path.join(self.config_dir, "new_player_config.json")
|
config_path = os.path.join(self.config_dir, "new_player_config.json")
|
||||||
if os.path.exists(config_path):
|
if os.path.exists(config_path):
|
||||||
with open(config_path, 'r', encoding='utf-8') as f:
|
with open(config_path, 'r', encoding='utf-8') as f:
|
||||||
return json.load(f)
|
config = json.load(f)
|
||||||
|
self.log('INFO', '成功从JSON文件加载新手大礼包配置', 'SERVER')
|
||||||
|
return config
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log('ERROR', f"加载新手礼包配置失败: {str(e)}", 'SERVER')
|
self.log('ERROR', f"从JSON文件加载新手礼包配置失败: {str(e)}", 'SERVER')
|
||||||
|
|
||||||
# 默认配置
|
# 默认配置
|
||||||
|
self.log('WARNING', '使用默认新手大礼包配置', 'SERVER')
|
||||||
return {
|
return {
|
||||||
"新手礼包配置": {
|
"新手礼包配置": {
|
||||||
"奖励内容": {
|
"奖励内容": {
|
||||||
@@ -8279,7 +8598,7 @@ class TCPGameServer(TCPServer):
|
|||||||
# 从智慧树消息库中随机获取一条消息
|
# 从智慧树消息库中随机获取一条消息
|
||||||
random_message = self._get_random_wisdom_tree_message()
|
random_message = self._get_random_wisdom_tree_message()
|
||||||
if random_message:
|
if random_message:
|
||||||
wisdom_tree_config["智慧树显示的话"] = random_message
|
wisdom_tree_config["智慧树显示的话"] = random_message.get("content", "")
|
||||||
|
|
||||||
# 保存数据
|
# 保存数据
|
||||||
self.save_player_data(username, player_data)
|
self.save_player_data(username, player_data)
|
||||||
@@ -8347,7 +8666,7 @@ class TCPGameServer(TCPServer):
|
|||||||
random_message = self._get_random_wisdom_tree_message()
|
random_message = self._get_random_wisdom_tree_message()
|
||||||
|
|
||||||
if random_message:
|
if random_message:
|
||||||
wisdom_tree_config["智慧树显示的话"] = random_message
|
wisdom_tree_config["智慧树显示的话"] = random_message.get("content", "")
|
||||||
|
|
||||||
# 保存数据
|
# 保存数据
|
||||||
self.save_player_data(username, player_data)
|
self.save_player_data(username, player_data)
|
||||||
@@ -8505,6 +8824,22 @@ class TCPGameServer(TCPServer):
|
|||||||
import json
|
import json
|
||||||
import random
|
import random
|
||||||
|
|
||||||
|
# 优先从MongoDB读取
|
||||||
|
if hasattr(self, 'mongo_api') and self.mongo_api and self.mongo_api.is_connected():
|
||||||
|
try:
|
||||||
|
wisdom_tree_data = self.mongo_api.get_wisdom_tree_config()
|
||||||
|
if wisdom_tree_data:
|
||||||
|
messages = wisdom_tree_data.get("messages", [])
|
||||||
|
if messages:
|
||||||
|
selected_message = random.choice(messages)
|
||||||
|
self.log('INFO', f"成功从MongoDB获取智慧树消息", 'SERVER')
|
||||||
|
return selected_message
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
except Exception as e:
|
||||||
|
self.log('ERROR', f"从MongoDB读取智慧树消息失败: {e}", 'SERVER')
|
||||||
|
|
||||||
|
# 回退到JSON文件
|
||||||
wisdom_tree_data_path = os.path.join(os.path.dirname(__file__), "config", "wisdom_tree_data.json")
|
wisdom_tree_data_path = os.path.join(os.path.dirname(__file__), "config", "wisdom_tree_data.json")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -8514,12 +8849,13 @@ class TCPGameServer(TCPServer):
|
|||||||
messages = wisdom_tree_data.get("messages", [])
|
messages = wisdom_tree_data.get("messages", [])
|
||||||
if messages:
|
if messages:
|
||||||
selected_message = random.choice(messages)
|
selected_message = random.choice(messages)
|
||||||
return selected_message.get("content", "")
|
self.log('INFO', f"成功从JSON文件获取智慧树消息", 'SERVER')
|
||||||
|
return selected_message
|
||||||
else:
|
else:
|
||||||
return ""
|
return None
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"读取智慧树消息失败:{e}")
|
self.log('ERROR', f"从JSON文件读取智慧树消息失败: {e}", 'SERVER')
|
||||||
return ""
|
return None
|
||||||
|
|
||||||
def _save_wisdom_tree_message(self, username, message_content):
|
def _save_wisdom_tree_message(self, username, message_content):
|
||||||
"""保存智慧树消息到消息库"""
|
"""保存智慧树消息到消息库"""
|
||||||
@@ -8528,6 +8864,46 @@ class TCPGameServer(TCPServer):
|
|||||||
import time
|
import time
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
|
# 创建新消息
|
||||||
|
new_message = {
|
||||||
|
"timestamp": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()),
|
||||||
|
"sender": username,
|
||||||
|
"content": message_content,
|
||||||
|
"id": str(uuid.uuid4())
|
||||||
|
}
|
||||||
|
|
||||||
|
# 优先保存到MongoDB
|
||||||
|
if hasattr(self, 'mongo_api') and self.mongo_api and self.mongo_api.is_connected():
|
||||||
|
try:
|
||||||
|
# 获取现有数据
|
||||||
|
wisdom_tree_data = self.mongo_api.get_wisdom_tree_config()
|
||||||
|
if not wisdom_tree_data:
|
||||||
|
wisdom_tree_data = {
|
||||||
|
"messages": [],
|
||||||
|
"total_messages": 0,
|
||||||
|
"last_update": ""
|
||||||
|
}
|
||||||
|
|
||||||
|
# 添加新消息
|
||||||
|
wisdom_tree_data["messages"].append(new_message)
|
||||||
|
wisdom_tree_data["total_messages"] = len(wisdom_tree_data["messages"])
|
||||||
|
wisdom_tree_data["last_update"] = new_message["timestamp"]
|
||||||
|
|
||||||
|
# 保持最多1000条消息
|
||||||
|
if len(wisdom_tree_data["messages"]) > 1000:
|
||||||
|
wisdom_tree_data["messages"] = wisdom_tree_data["messages"][-1000:]
|
||||||
|
wisdom_tree_data["total_messages"] = len(wisdom_tree_data["messages"])
|
||||||
|
|
||||||
|
# 保存到MongoDB
|
||||||
|
if self.mongo_api.update_wisdom_tree_config(wisdom_tree_data):
|
||||||
|
self.log('INFO', f"成功保存智慧树消息到MongoDB: {username}", 'SERVER')
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
self.log('ERROR', f"保存智慧树消息到MongoDB失败: {username}", 'SERVER')
|
||||||
|
except Exception as e:
|
||||||
|
self.log('ERROR', f"MongoDB保存智慧树消息异常: {e}", 'SERVER')
|
||||||
|
|
||||||
|
# 回退到JSON文件
|
||||||
wisdom_tree_data_path = os.path.join(os.path.dirname(__file__), "config", "wisdom_tree_data.json")
|
wisdom_tree_data_path = os.path.join(os.path.dirname(__file__), "config", "wisdom_tree_data.json")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -8542,14 +8918,6 @@ class TCPGameServer(TCPServer):
|
|||||||
"last_update": ""
|
"last_update": ""
|
||||||
}
|
}
|
||||||
|
|
||||||
# 创建新消息
|
|
||||||
new_message = {
|
|
||||||
"timestamp": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()),
|
|
||||||
"sender": username,
|
|
||||||
"content": message_content,
|
|
||||||
"id": str(uuid.uuid4())
|
|
||||||
}
|
|
||||||
|
|
||||||
# 添加到消息列表
|
# 添加到消息列表
|
||||||
wisdom_tree_data["messages"].append(new_message)
|
wisdom_tree_data["messages"].append(new_message)
|
||||||
wisdom_tree_data["total_messages"] = len(wisdom_tree_data["messages"])
|
wisdom_tree_data["total_messages"] = len(wisdom_tree_data["messages"])
|
||||||
@@ -8564,9 +8932,10 @@ class TCPGameServer(TCPServer):
|
|||||||
with open(wisdom_tree_data_path, 'w', encoding='utf-8') as f:
|
with open(wisdom_tree_data_path, 'w', encoding='utf-8') as f:
|
||||||
json.dump(wisdom_tree_data, f, ensure_ascii=False, indent=4)
|
json.dump(wisdom_tree_data, f, ensure_ascii=False, indent=4)
|
||||||
|
|
||||||
|
self.log('INFO', f"成功保存智慧树消息到JSON文件: {username}", 'SERVER')
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"保存智慧树消息失败:{e}")
|
self.log('ERROR', f"保存智慧树消息到JSON文件失败: {e}", 'SERVER')
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def check_wisdom_tree_health_decay(self):
|
def check_wisdom_tree_health_decay(self):
|
||||||
@@ -9543,17 +9912,6 @@ if __name__ == "__main__":
|
|||||||
server_thread.start()
|
server_thread.start()
|
||||||
|
|
||||||
print("✅ 服务器启动成功!")
|
print("✅ 服务器启动成功!")
|
||||||
print("📋 功能列表:")
|
|
||||||
print(" ├── 用户注册/登录系统")
|
|
||||||
print(" ├── 作物种植与收获")
|
|
||||||
print(" ├── 浇水与施肥系统")
|
|
||||||
print(" ├── 每日签到奖励")
|
|
||||||
print(" ├── 幸运抽奖系统")
|
|
||||||
print(" ├── 玩家互动功能")
|
|
||||||
print(" ├── 性能优化缓存")
|
|
||||||
print(" └── 控制台命令系统")
|
|
||||||
print("=" * 60)
|
|
||||||
print("🔥 服务器运行中...")
|
|
||||||
|
|
||||||
# 启动控制台输入线程
|
# 启动控制台输入线程
|
||||||
console_thread = threading.Thread(target=console_input_thread, args=(server,))
|
console_thread = threading.Thread(target=console_input_thread, args=(server,))
|
||||||
|
|||||||
BIN
Server/__pycache__/SMYMongoDBAPI.cpython-313.pyc
Normal file
BIN
Server/__pycache__/SMYMongoDBAPI.cpython-313.pyc
Normal file
Binary file not shown.
Binary file not shown.
@@ -1,72 +1,85 @@
|
|||||||
{
|
{
|
||||||
"experience": 0,
|
"experience": 0,
|
||||||
"level": 1,
|
"level": 1,
|
||||||
"money": 4000,
|
"money": 5000,
|
||||||
"体力值": 20,
|
"farm_name": "农场名称",
|
||||||
"体力上次刷新时间": "",
|
"player_name": "玩家名称",
|
||||||
"体力上次恢复时间": 0,
|
"user_name": "用户名",
|
||||||
"farm_name": "农场",
|
"user_password": "密码",
|
||||||
"user_name": "shumengya",
|
"last_login_time": "2025年07月20日17时19分16秒",
|
||||||
"player_name": "玩家昵称",
|
|
||||||
"user_password": "0123456789",
|
|
||||||
"last_login_time": "2025年12时09分35秒",
|
|
||||||
"total_login_time": "0时0分0秒",
|
"total_login_time": "0时0分0秒",
|
||||||
"personal_profile": "个人简介",
|
"last_water_reset_date": "2025-06-05",
|
||||||
"注册时间": "2025年05月21日15时00分00秒",
|
"farm_lots": [],
|
||||||
|
|
||||||
"farm_lots": [
|
|
||||||
{"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":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}
|
|
||||||
],
|
|
||||||
"player_bag": [],
|
"player_bag": [],
|
||||||
"作物仓库": [],
|
"作物仓库": [],
|
||||||
|
"宠物背包": [],
|
||||||
|
"巡逻宠物": [],
|
||||||
|
"出战宠物": [],
|
||||||
|
"注册时间": "2025年05月21日15时00分00秒",
|
||||||
|
"个人简介": "个人简介",
|
||||||
|
"稻草人配置": {
|
||||||
|
"已拥有稻草人类型": [
|
||||||
|
],
|
||||||
|
"稻草人展示类型": "",
|
||||||
|
"稻草人昵称": "稻草人",
|
||||||
|
"稻草人说的话": {
|
||||||
|
"第一句话": {
|
||||||
|
"内容": "第一句话",
|
||||||
|
"颜色": "52dceeff"
|
||||||
|
},
|
||||||
|
"第二句话": {
|
||||||
|
"内容": "第二句话",
|
||||||
|
"颜色": "80d5ffff"
|
||||||
|
},
|
||||||
|
"第三句话": {
|
||||||
|
"内容": "第三句话",
|
||||||
|
"颜色": "ac52ffff"
|
||||||
|
},
|
||||||
|
"第四句话": {
|
||||||
|
"内容": "第四句话",
|
||||||
|
"颜色": "f881ffff"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"稻草人昵称颜色": "b38282ff"
|
||||||
|
},
|
||||||
|
"智慧树配置": {
|
||||||
|
"距离上一次杀虫时间": 1753004237,
|
||||||
|
"距离上一次除草时间": 1753004237,
|
||||||
|
"智慧树显示的话": "",
|
||||||
|
"等级": 1,
|
||||||
|
"当前经验值": 0,
|
||||||
|
"最大经验值": 100,
|
||||||
|
"最大生命值": 100,
|
||||||
|
"当前生命值": 100,
|
||||||
|
"高度": 20
|
||||||
|
},
|
||||||
|
"签到历史": {
|
||||||
|
},
|
||||||
|
"在线礼包": {
|
||||||
|
"当前日期": "2025-07-20",
|
||||||
|
"今日在线时长": 0.0,
|
||||||
|
"已领取礼包": [],
|
||||||
|
"登录时间": 1753003043.7163484
|
||||||
|
},
|
||||||
|
"点赞系统": {
|
||||||
|
"今日剩余点赞次数": 10,
|
||||||
|
"点赞上次刷新时间": "2025-07-20"
|
||||||
|
},
|
||||||
|
"新手礼包": {
|
||||||
|
"已领取": false,
|
||||||
|
"领取时间": "2025-07-12 23:02:25"
|
||||||
|
},
|
||||||
|
"体力系统": {
|
||||||
|
"当前体力值": 20,
|
||||||
|
"最大体力值": 20,
|
||||||
|
"上次刷新时间": "2025-07-20",
|
||||||
|
"上次恢复时间": 1753003043.7066433
|
||||||
|
},
|
||||||
"道具背包": [],
|
"道具背包": [],
|
||||||
"宠物背包":[],
|
"玩家小卖部": [],
|
||||||
"巡逻宠物":[],
|
"小卖部格子数": 10,
|
||||||
"出战宠物":[]
|
"游戏设置": {
|
||||||
|
"背景音乐音量": 1.0,
|
||||||
|
"天气显示": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
{
|
{
|
||||||
"experience": 1196,
|
"experience": 90,
|
||||||
"level": 35,
|
"level": 36,
|
||||||
"money": 200812377,
|
"money": 200802715,
|
||||||
"farm_name": "柚大青の小农场",
|
"farm_name": "柚大青の小农场",
|
||||||
"player_name": "柚大青",
|
"player_name": "柚大青",
|
||||||
"user_name": "2143323382",
|
"user_name": "2143323382",
|
||||||
"user_password": "tyh@19900420",
|
"user_password": "tyh@19900420",
|
||||||
"last_login_time": "2025年07月19日11时01分22秒",
|
"last_login_time": "2025年07月20日21时00分40秒",
|
||||||
"total_login_time": "6时31分14秒",
|
"total_login_time": "6时45分52秒",
|
||||||
"farm_lots": [
|
"farm_lots": [
|
||||||
{
|
{
|
||||||
"crop_type": "",
|
"crop_type": "",
|
||||||
@@ -131,26 +131,27 @@
|
|||||||
"土地等级": 3
|
"土地等级": 3
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"crop_type": "",
|
"crop_type": "杂交树1",
|
||||||
"grow_time": 0,
|
"grow_time": 14976,
|
||||||
"is_dead": false,
|
"is_dead": false,
|
||||||
"is_diged": true,
|
"is_diged": true,
|
||||||
"is_planted": false,
|
"is_planted": true,
|
||||||
"max_grow_time": 1080,
|
"max_grow_time": 21600,
|
||||||
"已浇水": false,
|
"已浇水": false,
|
||||||
"已施肥": false,
|
"已施肥": false,
|
||||||
"土地等级": 3
|
"土地等级": 3
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"crop_type": "",
|
"crop_type": "杂交树2",
|
||||||
"grow_time": 0,
|
"grow_time": 15468,
|
||||||
"is_dead": false,
|
"is_dead": false,
|
||||||
"is_diged": true,
|
"is_diged": true,
|
||||||
"is_planted": false,
|
"is_planted": true,
|
||||||
"max_grow_time": 720,
|
"max_grow_time": 25200,
|
||||||
"已浇水": false,
|
"已浇水": false,
|
||||||
"已施肥": false,
|
"已施肥": false,
|
||||||
"土地等级": 3
|
"土地等级": 3,
|
||||||
|
"浇水时间": 1753003230.8845751
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"crop_type": "",
|
"crop_type": "",
|
||||||
@@ -241,12 +242,12 @@
|
|||||||
"土地等级": 1
|
"土地等级": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"crop_type": "",
|
"crop_type": "玉米",
|
||||||
"grow_time": 0,
|
"grow_time": 918,
|
||||||
"is_dead": false,
|
"is_dead": false,
|
||||||
"is_diged": true,
|
"is_diged": true,
|
||||||
"is_planted": false,
|
"is_planted": true,
|
||||||
"max_grow_time": 240,
|
"max_grow_time": 900,
|
||||||
"已浇水": false,
|
"已浇水": false,
|
||||||
"已施肥": false,
|
"已施肥": false,
|
||||||
"土地等级": 1
|
"土地等级": 1
|
||||||
@@ -576,11 +577,6 @@
|
|||||||
"quality": "普通",
|
"quality": "普通",
|
||||||
"count": 1
|
"count": 1
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "玉米",
|
|
||||||
"quality": "优良",
|
|
||||||
"count": 1
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "番茄",
|
"name": "番茄",
|
||||||
"quality": "普通",
|
"quality": "普通",
|
||||||
@@ -616,15 +612,6 @@
|
|||||||
"quality": "传奇",
|
"quality": "传奇",
|
||||||
"count": 1
|
"count": 1
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "杂交树1",
|
|
||||||
"quality": "传奇",
|
|
||||||
"count": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "杂交树2",
|
|
||||||
"count": 1
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "荔枝",
|
"name": "荔枝",
|
||||||
"count": 2
|
"count": 2
|
||||||
@@ -644,6 +631,46 @@
|
|||||||
{
|
{
|
||||||
"name": "向日葵",
|
"name": "向日葵",
|
||||||
"count": 3
|
"count": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "黄瓜",
|
||||||
|
"quality": "普通",
|
||||||
|
"count": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "野草1",
|
||||||
|
"quality": "优良",
|
||||||
|
"count": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "豌豆",
|
||||||
|
"quality": "普通",
|
||||||
|
"count": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "稻谷",
|
||||||
|
"quality": "普通",
|
||||||
|
"count": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "山楂",
|
||||||
|
"quality": "优良",
|
||||||
|
"count": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "龙果",
|
||||||
|
"quality": "传奇",
|
||||||
|
"count": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "杂交树1",
|
||||||
|
"quality": "传奇",
|
||||||
|
"count": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "杂交树2",
|
||||||
|
"quality": "传奇",
|
||||||
|
"count": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"last_water_reset_date": "2025-06-05",
|
"last_water_reset_date": "2025-06-05",
|
||||||
@@ -851,9 +878,11 @@
|
|||||||
],
|
],
|
||||||
"稻草人配置": {
|
"稻草人配置": {
|
||||||
"已拥有稻草人类型": [
|
"已拥有稻草人类型": [
|
||||||
"稻草人1"
|
"稻草人1",
|
||||||
|
"稻草人2",
|
||||||
|
"稻草人3"
|
||||||
],
|
],
|
||||||
"稻草人展示类型": "",
|
"稻草人展示类型": "稻草人3",
|
||||||
"稻草人昵称": "柚大青的稻草人",
|
"稻草人昵称": "柚大青的稻草人",
|
||||||
"稻草人说的话": {
|
"稻草人说的话": {
|
||||||
"第一句话": {
|
"第一句话": {
|
||||||
@@ -875,48 +904,60 @@
|
|||||||
},
|
},
|
||||||
"稻草人昵称颜色": "b38282ff"
|
"稻草人昵称颜色": "b38282ff"
|
||||||
},
|
},
|
||||||
"智慧树配置": {
|
|
||||||
"智慧树显示的话": "柚小青最可爱",
|
|
||||||
"等级": 4,
|
|
||||||
"高度": 76,
|
|
||||||
"上次护理时间": 1752050186,
|
|
||||||
"距离上一次除草时间": 1752050186,
|
|
||||||
"距离上一次杀虫时间": 1752050186,
|
|
||||||
"当前经验值": 278,
|
|
||||||
"最大经验值": 480,
|
|
||||||
"最大生命值": 106,
|
|
||||||
"当前生命值": 106
|
|
||||||
},
|
|
||||||
"签到历史": {
|
"签到历史": {
|
||||||
"2025年07月12日21时05分47秒": "金币249 经验75 土豆x3",
|
"2025年07月12日21时05分47秒": "金币249 经验75 土豆x3",
|
||||||
"2025年07月13日07时26分04秒": "金币302 经验63 土豆x5 小麦x3"
|
"2025年07月13日07时26分04秒": "金币302 经验63 土豆x5 小麦x3"
|
||||||
},
|
},
|
||||||
"在线礼包": {
|
"在线礼包": {
|
||||||
"当前日期": "2025-07-19",
|
"当前日期": "2025-07-20",
|
||||||
"今日在线时长": 0.0,
|
"今日在线时长": 999999.271807432174683,
|
||||||
"已领取礼包": [],
|
"已领取礼包": [],
|
||||||
"登录时间": 1752894082.539563
|
"登录时间": 1753003043.7163484
|
||||||
},
|
},
|
||||||
"点赞系统": {
|
"点赞系统": {
|
||||||
"今日剩余点赞次数": 10,
|
"今日剩余点赞次数": 10,
|
||||||
"点赞上次刷新时间": "2025-07-19"
|
"点赞上次刷新时间": "2025-07-20"
|
||||||
},
|
},
|
||||||
"新手礼包": {
|
"新手礼包": {
|
||||||
"已领取": true,
|
"已领取": true,
|
||||||
"领取时间": "2025-07-12 23:02:25"
|
"领取时间": "2025-07-20 20:21:04"
|
||||||
},
|
},
|
||||||
"体力系统": {
|
"体力系统": {
|
||||||
"当前体力值": 20,
|
"当前体力值": 20,
|
||||||
"最大体力值": 20,
|
"最大体力值": 20,
|
||||||
"上次刷新时间": "2025-07-19",
|
"上次刷新时间": "2025-07-20",
|
||||||
"上次恢复时间": 1752894082.5390205
|
"上次恢复时间": 1753003043.7066433
|
||||||
},
|
},
|
||||||
"玩家小卖部": [],
|
|
||||||
"道具背包": [
|
"道具背包": [
|
||||||
{
|
{
|
||||||
"name": "铲子",
|
"name": "铲子",
|
||||||
"count": 100
|
"count": 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "农家肥",
|
||||||
|
"count": 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "水桶",
|
||||||
|
"count": 4
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"小卖部格子数": 10
|
"玩家小卖部": [],
|
||||||
|
"小卖部格子数": 10,
|
||||||
|
"游戏设置": {
|
||||||
|
"背景音乐音量": 1.0,
|
||||||
|
"天气显示": true
|
||||||
|
},
|
||||||
|
"智慧树配置": {
|
||||||
|
"距离上一次杀虫时间": 1753014929,
|
||||||
|
"距离上一次除草时间": 1753014864,
|
||||||
|
"智慧树显示的话": "你好,树萌芽",
|
||||||
|
"等级": 2,
|
||||||
|
"当前经验值": 27,
|
||||||
|
"最大经验值": 169,
|
||||||
|
"最大生命值": 102,
|
||||||
|
"当前生命值": 102,
|
||||||
|
"高度": 20,
|
||||||
|
"上次护理时间": 1753014929
|
||||||
|
}
|
||||||
}
|
}
|
||||||
178
Server/test_mongodb_migration.py
Normal file
178
Server/test_mongodb_migration.py
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
测试MongoDB迁移功能
|
||||||
|
作者: AI Assistant
|
||||||
|
功能: 测试每日签到配置从JSON迁移到MongoDB的功能
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
|
||||||
|
# 添加当前目录到Python路径
|
||||||
|
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
|
||||||
|
from SMYMongoDBAPI import SMYMongoDBAPI
|
||||||
|
|
||||||
|
def test_mongodb_migration():
|
||||||
|
"""测试MongoDB迁移功能"""
|
||||||
|
print("=== 测试MongoDB迁移功能 ===")
|
||||||
|
|
||||||
|
# 1. 测试MongoDB API连接
|
||||||
|
print("\n1. 测试MongoDB API连接:")
|
||||||
|
try:
|
||||||
|
api = SMYMongoDBAPI("test")
|
||||||
|
if api.is_connected():
|
||||||
|
print("✓ MongoDB连接成功")
|
||||||
|
else:
|
||||||
|
print("✗ MongoDB连接失败")
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
print(f"✗ MongoDB连接异常: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# 2. 测试获取每日签到配置
|
||||||
|
print("\n2. 测试获取每日签到配置:")
|
||||||
|
try:
|
||||||
|
config = api.get_daily_checkin_config()
|
||||||
|
if config:
|
||||||
|
print("✓ 成功获取每日签到配置")
|
||||||
|
print(f" 基础奖励金币范围: {config.get('基础奖励', {}).get('金币', {})}")
|
||||||
|
print(f" 种子奖励类型数量: {len(config.get('种子奖励', {}))}")
|
||||||
|
print(f" 连续签到奖励天数: {len(config.get('连续签到奖励', {}))}")
|
||||||
|
else:
|
||||||
|
print("✗ 获取每日签到配置失败")
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
print(f"✗ 获取每日签到配置异常: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# 3. 测试更新配置
|
||||||
|
print("\n3. 测试更新每日签到配置:")
|
||||||
|
try:
|
||||||
|
# 创建一个测试配置
|
||||||
|
test_config = {
|
||||||
|
"基础奖励": {
|
||||||
|
"金币": {"最小值": 300, "最大值": 600, "图标": "💰", "颜色": "#FFD700"},
|
||||||
|
"经验": {"最小值": 75, "最大值": 150, "图标": "⭐", "颜色": "#00BFFF"}
|
||||||
|
},
|
||||||
|
"种子奖励": {
|
||||||
|
"普通": {"概率": 0.6, "数量范围": [2, 5], "种子池": ["小麦", "胡萝卜", "土豆", "稻谷"]},
|
||||||
|
"优良": {"概率": 0.25, "数量范围": [2, 4], "种子池": ["玉米", "番茄", "洋葱", "大豆", "豌豆", "黄瓜", "大白菜"]},
|
||||||
|
"稀有": {"概率": 0.12, "数量范围": [1, 3], "种子池": ["草莓", "花椰菜", "柿子", "蓝莓", "树莓"]},
|
||||||
|
"史诗": {"概率": 0.025, "数量范围": [1, 2], "种子池": ["葡萄", "南瓜", "芦笋", "茄子", "向日葵", "蕨菜"]},
|
||||||
|
"传奇": {"概率": 0.005, "数量范围": [1, 1], "种子池": ["西瓜", "甘蔗", "香草", "甜菜", "人参", "富贵竹", "芦荟", "哈密瓜"]}
|
||||||
|
},
|
||||||
|
"连续签到奖励": {
|
||||||
|
"第3天": {"额外金币": 150, "额外经验": 75, "描述": "连续签到奖励"},
|
||||||
|
"第7天": {"额外金币": 300, "额外经验": 150, "描述": "一周连击奖励"},
|
||||||
|
"第14天": {"额外金币": 600, "额外经验": 250, "描述": "半月连击奖励"},
|
||||||
|
"第21天": {"额外金币": 1000, "额外经验": 400, "描述": "三周连击奖励"},
|
||||||
|
"第30天": {"额外金币": 2000, "额外经验": 600, "描述": "满月连击奖励"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
success = api.update_daily_checkin_config(test_config)
|
||||||
|
if success:
|
||||||
|
print("✓ 成功更新测试配置到MongoDB")
|
||||||
|
else:
|
||||||
|
print("✗ 更新测试配置失败")
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
print(f"✗ 更新测试配置异常: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# 4. 验证更新后的配置
|
||||||
|
print("\n4. 验证更新后的配置:")
|
||||||
|
try:
|
||||||
|
updated_config = api.get_daily_checkin_config()
|
||||||
|
if updated_config:
|
||||||
|
print("✓ 成功获取更新后的配置")
|
||||||
|
print(f" 更新后金币范围: {updated_config.get('基础奖励', {}).get('金币', {})}")
|
||||||
|
print(f" 更新后第3天奖励: {updated_config.get('连续签到奖励', {}).get('第3天', {})}")
|
||||||
|
|
||||||
|
# 验证更新是否生效
|
||||||
|
if updated_config.get('基础奖励', {}).get('金币', {}).get('最小值') == 300:
|
||||||
|
print("✓ 配置更新验证成功")
|
||||||
|
else:
|
||||||
|
print("✗ 配置更新验证失败")
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
print("✗ 获取更新后的配置失败")
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
print(f"✗ 验证更新后配置异常: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# 5. 恢复原始配置
|
||||||
|
print("\n5. 恢复原始配置:")
|
||||||
|
try:
|
||||||
|
original_config = {
|
||||||
|
"基础奖励": {
|
||||||
|
"金币": {"最小值": 200, "最大值": 500, "图标": "💰", "颜色": "#FFD700"},
|
||||||
|
"经验": {"最小值": 50, "最大值": 120, "图标": "⭐", "颜色": "#00BFFF"}
|
||||||
|
},
|
||||||
|
"种子奖励": {
|
||||||
|
"普通": {"概率": 0.6, "数量范围": [2, 5], "种子池": ["小麦", "胡萝卜", "土豆", "稻谷"]},
|
||||||
|
"优良": {"概率": 0.25, "数量范围": [2, 4], "种子池": ["玉米", "番茄", "洋葱", "大豆", "豌豆", "黄瓜", "大白菜"]},
|
||||||
|
"稀有": {"概率": 0.12, "数量范围": [1, 3], "种子池": ["草莓", "花椰菜", "柿子", "蓝莓", "树莓"]},
|
||||||
|
"史诗": {"概率": 0.025, "数量范围": [1, 2], "种子池": ["葡萄", "南瓜", "芦笋", "茄子", "向日葵", "蕨菜"]},
|
||||||
|
"传奇": {"概率": 0.005, "数量范围": [1, 1], "种子池": ["西瓜", "甘蔗", "香草", "甜菜", "人参", "富贵竹", "芦荟", "哈密瓜"]}
|
||||||
|
},
|
||||||
|
"连续签到奖励": {
|
||||||
|
"第3天": {"额外金币": 100, "额外经验": 50, "描述": "连续签到奖励"},
|
||||||
|
"第7天": {"额外金币": 200, "额外经验": 100, "描述": "一周连击奖励"},
|
||||||
|
"第14天": {"额外金币": 500, "额外经验": 200, "描述": "半月连击奖励"},
|
||||||
|
"第21天": {"额外金币": 800, "额外经验": 300, "描述": "三周连击奖励"},
|
||||||
|
"第30天": {"额外金币": 1500, "额外经验": 500, "描述": "满月连击奖励"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
success = api.update_daily_checkin_config(original_config)
|
||||||
|
if success:
|
||||||
|
print("✓ 成功恢复原始配置")
|
||||||
|
else:
|
||||||
|
print("✗ 恢复原始配置失败")
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
print(f"✗ 恢复原始配置异常: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# 6. 测试配置数据完整性
|
||||||
|
print("\n6. 测试配置数据完整性:")
|
||||||
|
try:
|
||||||
|
final_config = api.get_daily_checkin_config()
|
||||||
|
if final_config:
|
||||||
|
# 检查必要字段是否存在
|
||||||
|
required_fields = ["基础奖励", "种子奖励", "连续签到奖励"]
|
||||||
|
missing_fields = [field for field in required_fields if field not in final_config]
|
||||||
|
|
||||||
|
if not missing_fields:
|
||||||
|
print("✓ 配置数据完整性检查通过")
|
||||||
|
print(f" 包含字段: {', '.join(required_fields)}")
|
||||||
|
else:
|
||||||
|
print(f"✗ 配置数据缺少字段: {missing_fields}")
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
print("✗ 无法获取最终配置进行完整性检查")
|
||||||
|
return False
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"✗ 配置数据完整性检查异常: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# 清理资源
|
||||||
|
api.disconnect()
|
||||||
|
|
||||||
|
print("\n=== 所有测试通过!MongoDB迁移功能正常 ===")
|
||||||
|
return True
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
success = test_mongodb_migration()
|
||||||
|
if success:
|
||||||
|
print("\n🎉 MongoDB迁移测试成功完成!")
|
||||||
|
sys.exit(0)
|
||||||
|
else:
|
||||||
|
print("\n❌ MongoDB迁移测试失败!")
|
||||||
|
sys.exit(1)
|
||||||
106
Server/test_server_mongodb.py
Normal file
106
Server/test_server_mongodb.py
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
测试服务器MongoDB集成
|
||||||
|
作者: AI Assistant
|
||||||
|
功能: 测试服务器是否能正确使用MongoDB配置
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
|
# 添加当前目录到Python路径
|
||||||
|
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
|
||||||
|
def test_server_mongodb_integration():
|
||||||
|
"""测试服务器MongoDB集成"""
|
||||||
|
print("=== 测试服务器MongoDB集成 ===")
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 导入服务器模块
|
||||||
|
from Server.TCPGameServer import TCPGameServer
|
||||||
|
|
||||||
|
print("✓ 成功导入TCPGameServer模块")
|
||||||
|
|
||||||
|
# 创建服务器实例(不启动网络服务)
|
||||||
|
print("\n1. 创建服务器实例:")
|
||||||
|
server = TCPGameServer()
|
||||||
|
print("✓ 服务器实例创建成功")
|
||||||
|
|
||||||
|
# 检查MongoDB连接状态
|
||||||
|
print("\n2. 检查MongoDB连接状态:")
|
||||||
|
if hasattr(server, 'use_mongodb'):
|
||||||
|
print(f" MongoDB使用状态: {server.use_mongodb}")
|
||||||
|
if hasattr(server, 'mongo_api') and server.mongo_api:
|
||||||
|
print(" MongoDB API实例: 已创建")
|
||||||
|
else:
|
||||||
|
print(" MongoDB API实例: 未创建")
|
||||||
|
else:
|
||||||
|
print(" MongoDB相关属性: 未找到")
|
||||||
|
|
||||||
|
# 测试配置加载
|
||||||
|
print("\n3. 测试每日签到配置加载:")
|
||||||
|
try:
|
||||||
|
config = server._load_daily_check_in_config()
|
||||||
|
if config:
|
||||||
|
print("✓ 成功加载每日签到配置")
|
||||||
|
print(f" 基础奖励金币范围: {config.get('基础奖励', {}).get('金币', {})}")
|
||||||
|
print(f" 种子奖励类型数量: {len(config.get('种子奖励', {}))}")
|
||||||
|
print(f" 连续签到奖励天数: {len(config.get('连续签到奖励', {}))}")
|
||||||
|
|
||||||
|
# 检查配置来源
|
||||||
|
if hasattr(server, 'use_mongodb') and server.use_mongodb:
|
||||||
|
print(" 配置来源: MongoDB")
|
||||||
|
else:
|
||||||
|
print(" 配置来源: JSON文件或默认配置")
|
||||||
|
else:
|
||||||
|
print("✗ 加载每日签到配置失败")
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
print(f"✗ 配置加载异常: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# 测试配置更新方法
|
||||||
|
print("\n4. 测试配置更新方法:")
|
||||||
|
if hasattr(server, '_update_daily_checkin_config_to_mongodb'):
|
||||||
|
print("✓ 配置更新方法存在")
|
||||||
|
|
||||||
|
# 测试更新方法(不实际更新)
|
||||||
|
test_config = {
|
||||||
|
"基础奖励": {
|
||||||
|
"金币": {"最小值": 250, "最大值": 550, "图标": "💰", "颜色": "#FFD700"},
|
||||||
|
"经验": {"最小值": 60, "最大值": 130, "图标": "⭐", "颜色": "#00BFFF"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 这里只是测试方法是否存在,不实际调用
|
||||||
|
print("✓ 配置更新方法可调用")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"✗ 配置更新方法异常: {e}")
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
print("✗ 配置更新方法不存在")
|
||||||
|
return False
|
||||||
|
|
||||||
|
print("\n=== 服务器MongoDB集成测试通过! ===")
|
||||||
|
return True
|
||||||
|
|
||||||
|
except ImportError as e:
|
||||||
|
print(f"✗ 模块导入失败: {e}")
|
||||||
|
print(" 请确保所有依赖模块都已正确安装")
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
print(f"✗ 测试过程中出现异常: {e}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
return False
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
success = test_server_mongodb_integration()
|
||||||
|
if success:
|
||||||
|
print("\n🎉 服务器MongoDB集成测试成功完成!")
|
||||||
|
sys.exit(0)
|
||||||
|
else:
|
||||||
|
print("\n❌ 服务器MongoDB集成测试失败!")
|
||||||
|
sys.exit(1)
|
||||||
BIN
__pycache__/SMYMongoDBAPI.cpython-313.pyc
Normal file
BIN
__pycache__/SMYMongoDBAPI.cpython-313.pyc
Normal file
Binary file not shown.
@@ -1,5 +1,5 @@
|
|||||||
extends Sprite2D
|
extends Sprite2D
|
||||||
|
#昼夜循环只需调节该节点的modulate值即可
|
||||||
# 存储背景图片的路径数组
|
# 存储背景图片的路径数组
|
||||||
var backgrounds :Array = [
|
var backgrounds :Array = [
|
||||||
"res://assets/背景图片/背景1.webp",
|
"res://assets/背景图片/背景1.webp",
|
||||||
|
|||||||
@@ -1,45 +1,45 @@
|
|||||||
{
|
{
|
||||||
"farm_lots": [
|
"farm_lots": [
|
||||||
{
|
{
|
||||||
"crop_type": "",
|
"crop_type": "小麦",
|
||||||
"grow_time": 0,
|
"grow_time": 300,
|
||||||
"is_dead": false,
|
"is_dead": false,
|
||||||
"is_diged": true,
|
"is_diged": true,
|
||||||
"is_planted": false,
|
"is_planted": true,
|
||||||
"max_grow_time": 10200,
|
"max_grow_time": 300,
|
||||||
"已浇水": false,
|
"已浇水": false,
|
||||||
"已施肥": false,
|
"已施肥": false,
|
||||||
"土地等级": 4
|
"土地等级": 4
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"crop_type": "",
|
"crop_type": "小麦",
|
||||||
"grow_time": 0,
|
"grow_time": 300,
|
||||||
"is_dead": false,
|
"is_dead": false,
|
||||||
"is_diged": true,
|
"is_diged": true,
|
||||||
"is_planted": false,
|
"is_planted": true,
|
||||||
"max_grow_time": 7200,
|
"max_grow_time": 300,
|
||||||
"已浇水": false,
|
"已浇水": false,
|
||||||
"已施肥": false,
|
"已施肥": false,
|
||||||
"土地等级": 4
|
"土地等级": 4
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"crop_type": "",
|
"crop_type": "小麦",
|
||||||
"grow_time": 0,
|
"grow_time": 300,
|
||||||
"is_dead": false,
|
"is_dead": false,
|
||||||
"is_diged": true,
|
"is_diged": true,
|
||||||
"is_planted": false,
|
"is_planted": true,
|
||||||
"max_grow_time": 14400,
|
"max_grow_time": 300,
|
||||||
"已浇水": false,
|
"已浇水": false,
|
||||||
"已施肥": false,
|
"已施肥": false,
|
||||||
"土地等级": 4
|
"土地等级": 4
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"crop_type": "",
|
"crop_type": "小麦",
|
||||||
"grow_time": 0,
|
"grow_time": 300,
|
||||||
"is_dead": false,
|
"is_dead": false,
|
||||||
"is_diged": true,
|
"is_diged": true,
|
||||||
"is_planted": false,
|
"is_planted": true,
|
||||||
"max_grow_time": 7200,
|
"max_grow_time": 300,
|
||||||
"已浇水": false,
|
"已浇水": false,
|
||||||
"已施肥": false,
|
"已施肥": false,
|
||||||
"土地等级": 4
|
"土地等级": 4
|
||||||
@@ -53,7 +53,7 @@
|
|||||||
"max_grow_time": 2940,
|
"max_grow_time": 2940,
|
||||||
"已浇水": false,
|
"已浇水": false,
|
||||||
"已施肥": false,
|
"已施肥": false,
|
||||||
"土地等级": 0
|
"土地等级": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"crop_type": "",
|
"crop_type": "",
|
||||||
@@ -64,7 +64,7 @@
|
|||||||
"max_grow_time": 1080,
|
"max_grow_time": 1080,
|
||||||
"已浇水": false,
|
"已浇水": false,
|
||||||
"已施肥": false,
|
"已施肥": false,
|
||||||
"土地等级": 0
|
"土地等级": 2
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"crop_type": "",
|
"crop_type": "",
|
||||||
@@ -75,7 +75,7 @@
|
|||||||
"max_grow_time": 1080,
|
"max_grow_time": 1080,
|
||||||
"已浇水": false,
|
"已浇水": false,
|
||||||
"已施肥": false,
|
"已施肥": false,
|
||||||
"土地等级": 0
|
"土地等级": 3
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"crop_type": "龙果",
|
"crop_type": "龙果",
|
||||||
@@ -111,44 +111,44 @@
|
|||||||
"土地等级": 0
|
"土地等级": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"crop_type": "土豆",
|
"crop_type": "",
|
||||||
"grow_time": 480,
|
"grow_time": 0,
|
||||||
"is_dead": false,
|
"is_dead": false,
|
||||||
"is_diged": true,
|
"is_diged": true,
|
||||||
"is_planted": true,
|
"is_planted": false,
|
||||||
"max_grow_time": 480,
|
"max_grow_time": 480,
|
||||||
"已浇水": false,
|
"已浇水": false,
|
||||||
"已施肥": false,
|
"已施肥": false,
|
||||||
"土地等级": 4
|
"土地等级": 4
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"crop_type": "胡萝卜",
|
"crop_type": "",
|
||||||
"grow_time": 240,
|
"grow_time": 0,
|
||||||
"is_dead": false,
|
"is_dead": false,
|
||||||
"is_diged": true,
|
"is_diged": true,
|
||||||
"is_planted": true,
|
"is_planted": false,
|
||||||
"max_grow_time": 240,
|
"max_grow_time": 240,
|
||||||
"已浇水": false,
|
"已浇水": false,
|
||||||
"已施肥": false,
|
"已施肥": false,
|
||||||
"土地等级": 4
|
"土地等级": 4
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"crop_type": "土豆",
|
"crop_type": "",
|
||||||
"grow_time": 540,
|
"grow_time": 0,
|
||||||
"is_dead": false,
|
"is_dead": false,
|
||||||
"is_diged": true,
|
"is_diged": true,
|
||||||
"is_planted": true,
|
"is_planted": false,
|
||||||
"max_grow_time": 480,
|
"max_grow_time": 480,
|
||||||
"已浇水": false,
|
"已浇水": false,
|
||||||
"已施肥": false,
|
"已施肥": false,
|
||||||
"土地等级": 4
|
"土地等级": 4
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"crop_type": "小麦",
|
"crop_type": "",
|
||||||
"grow_time": 300,
|
"grow_time": 0,
|
||||||
"is_dead": false,
|
"is_dead": false,
|
||||||
"is_diged": true,
|
"is_diged": true,
|
||||||
"is_planted": true,
|
"is_planted": false,
|
||||||
"max_grow_time": 300,
|
"max_grow_time": 300,
|
||||||
"已浇水": false,
|
"已浇水": false,
|
||||||
"已施肥": false,
|
"已施肥": false,
|
||||||
@@ -555,7 +555,7 @@
|
|||||||
{
|
{
|
||||||
"name": "小麦",
|
"name": "小麦",
|
||||||
"quality": "普通",
|
"quality": "普通",
|
||||||
"count": 8
|
"count": 4
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "胡萝卜",
|
"name": "胡萝卜",
|
||||||
@@ -566,15 +566,20 @@
|
|||||||
"name": "土豆",
|
"name": "土豆",
|
||||||
"quality": "普通",
|
"quality": "普通",
|
||||||
"count": 6
|
"count": 6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "杂交树2",
|
||||||
|
"quality": "传奇",
|
||||||
|
"count": 8
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"experience": 5164,
|
"experience": 573,
|
||||||
"farm_name": "树萌芽の狗窝",
|
"farm_name": "树萌芽の狗窝",
|
||||||
"player_name": "树萌芽",
|
"player_name": "树萌芽",
|
||||||
"level": 63,
|
"level": 64,
|
||||||
"money": 615197045864,
|
"money": 615197019864,
|
||||||
"last_login_time": "2025年07月19日15时31分10秒",
|
"last_login_time": "2025年07月19日21时52分29秒",
|
||||||
"total_login_time": "162时4分9秒",
|
"total_login_time": "162时47分40秒",
|
||||||
"user_name": "3205788256",
|
"user_name": "3205788256",
|
||||||
"user_password": "tyh@19900420",
|
"user_password": "tyh@19900420",
|
||||||
"last_water_reset_date": "2025-06-06",
|
"last_water_reset_date": "2025-06-06",
|
||||||
@@ -631,7 +636,7 @@
|
|||||||
{
|
{
|
||||||
"name": "小麦",
|
"name": "小麦",
|
||||||
"quality": "普通",
|
"quality": "普通",
|
||||||
"count": 15
|
"count": 16
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "山葵",
|
"name": "山葵",
|
||||||
@@ -681,12 +686,17 @@
|
|||||||
{
|
{
|
||||||
"name": "胡萝卜",
|
"name": "胡萝卜",
|
||||||
"quality": "普通",
|
"quality": "普通",
|
||||||
"count": 1
|
"count": 5
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "土豆",
|
"name": "土豆",
|
||||||
"quality": "普通",
|
"quality": "普通",
|
||||||
"count": 3
|
"count": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "马铃薯",
|
||||||
|
"quality": "普通",
|
||||||
|
"count": 7
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"道具背包": [
|
"道具背包": [
|
||||||
@@ -696,7 +706,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "生长素",
|
"name": "生长素",
|
||||||
"count": 1001
|
"count": 1000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "时运-镰刀",
|
"name": "时运-镰刀",
|
||||||
@@ -844,10 +854,10 @@
|
|||||||
"爱好": ""
|
"爱好": ""
|
||||||
},
|
},
|
||||||
"等级经验": {
|
"等级经验": {
|
||||||
"宠物等级": 3,
|
"宠物等级": 4,
|
||||||
"当前经验": 40.0,
|
"当前经验": 26.0,
|
||||||
"最大经验": 144.0,
|
"最大经验": 172.8,
|
||||||
"亲密度": 136.0,
|
"亲密度": 204.0,
|
||||||
"最大亲密度": 1000.0
|
"最大亲密度": 1000.0
|
||||||
},
|
},
|
||||||
"购买信息": {
|
"购买信息": {
|
||||||
@@ -856,18 +866,18 @@
|
|||||||
"出售价格": 500
|
"出售价格": 500
|
||||||
},
|
},
|
||||||
"生命与防御": {
|
"生命与防御": {
|
||||||
"最大生命值": 242.00000000000006,
|
"最大生命值": 266.2000000000001,
|
||||||
"当前生命值": 242.00000000000006,
|
"当前生命值": 266.2000000000001,
|
||||||
"生命恢复速度": 1.0,
|
"生命恢复速度": 1.0,
|
||||||
"最大护盾值": 0.0,
|
"最大护盾值": 0.0,
|
||||||
"当前护盾值": 0.0,
|
"当前护盾值": 0.0,
|
||||||
"护盾恢复速度": 0.0,
|
"护盾恢复速度": 0.0,
|
||||||
"最大护甲值": 121.00000000000003,
|
"最大护甲值": 133.10000000000005,
|
||||||
"当前护甲值": 121.00000000000003
|
"当前护甲值": 133.10000000000005
|
||||||
},
|
},
|
||||||
"基础攻击属性": {
|
"基础攻击属性": {
|
||||||
"攻击类型": "MELEE",
|
"攻击类型": "MELEE",
|
||||||
"基础攻击伤害": 30.250000000000007,
|
"基础攻击伤害": 33.27500000000001,
|
||||||
"攻击距离": 100.0,
|
"攻击距离": 100.0,
|
||||||
"暴击率": 0.1,
|
"暴击率": 0.1,
|
||||||
"暴击伤害倍数": 1.5,
|
"暴击伤害倍数": 1.5,
|
||||||
@@ -1122,5 +1132,9 @@
|
|||||||
"商品数量": 1
|
"商品数量": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"小卖部格子数": 10
|
"小卖部格子数": 10,
|
||||||
|
"游戏设置": {
|
||||||
|
"背景音乐音量": 0.0,
|
||||||
|
"天气显示": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user