天气系统完成

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

View File

@@ -184,8 +184,8 @@ theme_override_colors/font_shadow_color = Color(0, 0, 0, 1)
theme_override_colors/font_outline_color = Color(0, 0, 0, 1) theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/shadow_offset_x = 5 theme_override_constants/shadow_offset_x = 5
theme_override_constants/shadow_offset_y = 5 theme_override_constants/shadow_offset_y = 5
theme_override_constants/outline_size = 10 theme_override_constants/outline_size = 20
theme_override_constants/shadow_outline_size = 10 theme_override_constants/shadow_outline_size = 20
theme_override_font_sizes/font_size = 45 theme_override_font_sizes/font_size = 45
text = "关于" text = "关于"
horizontal_alignment = 1 horizontal_alignment = 1

View File

@@ -0,0 +1,51 @@
extends Node2D
@onready var cherry_blossom_rain: Node2D = $CherryBlossomRain #栀子花雨
@onready var gardenia_rain: Node2D = $GardeniaRain #樱花雨
@onready var willow_leaf_rain: Node2D = $WillowLeafRain #柳叶雨
@onready var rain: GPUParticles2D = $Rain #下雨
@onready var snow: GPUParticles2D = $Snow #下雪
# 天气系统
# 要显示哪种天气直接调用相应天气的show()然后一并隐藏其他天气hide()
# 设置天气的统一方法
func set_weather(weather_type: String):
# 先隐藏所有天气效果
hide_all_weather()
# 根据天气类型显示对应效果
match weather_type:
"clear", "stop":
# 晴天或停止天气 - 所有天气效果都隐藏
pass
"rain":
if rain:
rain.show()
"snow":
if snow:
snow.show()
"cherry":
if cherry_blossom_rain:
cherry_blossom_rain.show()
"gardenia":
if gardenia_rain:
gardenia_rain.show()
"willow":
if willow_leaf_rain:
willow_leaf_rain.show()
_:
print("未知的天气类型: ", weather_type)
# 隐藏所有天气效果
func hide_all_weather():
if cherry_blossom_rain:
cherry_blossom_rain.hide()
if gardenia_rain:
gardenia_rain.hide()
if willow_leaf_rain:
willow_leaf_rain.hide()
if rain:
rain.hide()
if snow:
snow.hide()

View File

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

View File

@@ -11,7 +11,7 @@ extends Node
@onready var show_level : Label = $UI/GUI/GameInfoHBox1/level # 显示当前玩家的等级 @onready var show_level : Label = $UI/GUI/GameInfoHBox1/level # 显示当前玩家的等级
@onready var show_tip : Label = $UI/GUI/GameInfoHBox3/tip # 显示小提示 @onready var show_tip : Label = $UI/GUI/GameInfoHBox3/tip # 显示小提示
@onready var show_like: Label = $UI/GUI/GameInfoHBox1/like # 显示别人给自己点赞的总赞数 @onready var show_like: Label = $UI/GUI/GameInfoHBox1/like # 显示别人给自己点赞的总赞数
@onready var show_onlineplayer: Label = $UI/GUI/GameInfoHBox2/onlineplayer # 显示服务器在线人数 @onready var show_onlineplayer: Label = $UI/GUI/GameInfoHBox3/onlineplayer # 显示服务器在线人数
@onready var show_player_name : Label = $UI/GUI/GameInfoHBox2/player_name # 显示玩家昵称 @onready var show_player_name : Label = $UI/GUI/GameInfoHBox2/player_name # 显示玩家昵称
@onready var show_farm_name : Label = $UI/GUI/GameInfoHBox2/farm_name # 显示农场名称 @onready var show_farm_name : Label = $UI/GUI/GameInfoHBox2/farm_name # 显示农场名称
@onready var show_status_label : Label = $UI/GUI/GameInfoHBox2/StatusLabel # 显示与服务器连接状态 @onready var show_status_label : Label = $UI/GUI/GameInfoHBox2/StatusLabel # 显示与服务器连接状态
@@ -67,6 +67,7 @@ extends Node
@onready var pet_store_panel: Panel = $UI/BigPanel/PetStorePanel #宠物商店面板 @onready var pet_store_panel: Panel = $UI/BigPanel/PetStorePanel #宠物商店面板
@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 #玩家小卖部面板
#小面板 #小面板
@@ -92,6 +93,9 @@ extends Node
@onready var tree_status: Label = $Decoration/WisdomTree/TreeStatus #智慧树状态 只显示 等级和高度 @onready var tree_status: Label = $Decoration/WisdomTree/TreeStatus #智慧树状态 只显示 等级和高度
@onready var anonymous_talk: RichTextLabel = $Decoration/WisdomTree/BackgroundPanel/AnonymousTalk #给智慧树听音乐100%会刷新 施肥浇水 @onready var anonymous_talk: RichTextLabel = $Decoration/WisdomTree/BackgroundPanel/AnonymousTalk #给智慧树听音乐100%会刷新 施肥浇水
#天气系统
@onready var weather_system: Node2D = $WeatherSystem #天气系统节点
#各种弹窗 #各种弹窗
@onready var accept_dialog: AcceptDialog = $UI/DiaLog/AcceptDialog @onready var accept_dialog: AcceptDialog = $UI/DiaLog/AcceptDialog
@@ -200,10 +204,6 @@ func _ready():
# 初始化调试面板(默认隐藏) # 初始化调试面板(默认隐藏)
debug_panel.hide() debug_panel.hide()
debug_panel_script = debug_panel
# 在加载进度面板上添加调试按钮
_add_debug_button_to_loading_panel()
#未登录时隐藏所有UI #未登录时隐藏所有UI
game_info_h_box_1.hide() game_info_h_box_1.hide()
@@ -1158,16 +1158,17 @@ func _handle_item_config_response(response_data):
#===============================================作物图片缓存系统=============================================== #===============================================作物图片缓存系统===============================================
## 优化的作物图片缓存和管理系统 ## 优化的作物图片缓存和管理系统
class CropTextureManager: class CropTextureManager:
# 缓存字典 # 缓存字典 - 改为三阶段图片缓存
var texture_cache: Dictionary = {} # 序列帧缓存 {crop_name: [Texture2D]} var texture_cache: Dictionary = {} # 阶段图片缓存 {crop_name: {"幼苗": Texture2D, "未成熟": Texture2D, "成熟": Texture2D}}
var mature_texture_cache: Dictionary = {} # 成熟图片缓存 {crop_name: Texture2D} var default_textures: Dictionary = {} # 默认图片缓存 {"幼苗": Texture2D, "未成熟": Texture2D, "成熟": Texture2D}
var frame_counts: Dictionary = {} # 帧数记录 {crop_name: int}
var failed_resources: Array = [] # 记录加载失败的资源路径 var failed_resources: Array = [] # 记录加载失败的资源路径
# 三个生长阶段
const GROWTH_STAGES = ["幼苗", "未成熟", "成熟"]
# 加载状态 # 加载状态
var is_loading: bool = false var is_loading: bool = false
var load_progress: float = 0.0 var load_progress: float = 0.0
@@ -1183,9 +1184,6 @@ class CropTextureManager:
var results_mutex: Mutex var results_mutex: Mutex
var completed_results: Array = [] var completed_results: Array = []
# 调试面板引用
var debug_panel_ref = null
# 内存管理 # 内存管理
var max_cache_size: int = 300 # 最大缓存图片数量 var max_cache_size: int = 300 # 最大缓存图片数量
var cache_access_order: Array = [] # LRU缓存访问顺序 var cache_access_order: Array = [] # LRU缓存访问顺序
@@ -1196,8 +1194,6 @@ class CropTextureManager:
results_mutex = Mutex.new() results_mutex = Mutex.new()
# 根据设备性能动态调整线程数 # 根据设备性能动态调整线程数
_adjust_thread_count() _adjust_thread_count()
# 尝试获取调试面板引用
_connect_debug_panel()
## 根据设备性能调整线程数 ## 根据设备性能调整线程数
func _adjust_thread_count(): func _adjust_thread_count():
@@ -1216,28 +1212,8 @@ class CropTextureManager:
print("[CropTextureManager] 设备: %s, CPU核心: %d, 使用线程数: %d" % [platform, processor_count, max_threads]) print("[CropTextureManager] 设备: %s, CPU核心: %d, 使用线程数: %d" % [platform, processor_count, max_threads])
## 连接调试面板
func _connect_debug_panel():
# 延迟获取调试面板引用,因为初始化时可能还未创建
call_deferred("_try_get_debug_panel")
## 尝试获取调试面板引用
func _try_get_debug_panel():
var main_node = Engine.get_main_loop().current_scene
if main_node:
debug_panel_ref = main_node.get_node_or_null("UI/SmallPanel/DebugPanel")
if debug_panel_ref:
print("[CropTextureManager] 已连接到调试面板")
## 向调试面板发送消息
func _send_debug_message(message: String, color: Color = Color.WHITE):
if debug_panel_ref and debug_panel_ref.has_method("add_debug_message"):
debug_panel_ref.add_debug_message(message, color)
## 设置当前加载项目
func _set_current_loading_item(item_name: String):
if debug_panel_ref and debug_panel_ref.has_method("set_current_loading_item"):
debug_panel_ref.set_current_loading_item(item_name)
## 异步预加载所有作物图片 - 主要入口函数 ## 异步预加载所有作物图片 - 主要入口函数
func preload_all_textures_async(crop_data: Dictionary, progress_callback: Callable) -> void: func preload_all_textures_async(crop_data: Dictionary, progress_callback: Callable) -> void:
@@ -1254,23 +1230,18 @@ class CropTextureManager:
completed_results.clear() completed_results.clear()
print("[CropTextureManager] 开始预加载 %d 种作物图片" % total_crops) print("[CropTextureManager] 开始预加载 %d 种作物图片" % total_crops)
_send_debug_message("开始预加载 %d 种作物图片" % total_crops, Color.CYAN)
# 阶段1加载默认图片 (0-10%) # 阶段1加载默认图片 (0-10%)
progress_callback.call(0, "正在加载默认图片...") progress_callback.call(0, "正在加载默认图片...")
_send_debug_message("阶段1: 加载默认图片", Color.YELLOW)
await _load_default_textures_async() await _load_default_textures_async()
progress_callback.call(10, "默认图片加载完成") progress_callback.call(10, "默认图片加载完成")
_send_debug_message("默认图片加载完成", Color.GREEN)
# 阶段2多线程批量加载作物图片 (10-90%) # 阶段2多线程批量加载作物图片 (10-90%)
_send_debug_message("阶段2: 多线程加载作物图片", Color.YELLOW)
await _load_crops_multithreaded_async(crop_data, progress_callback) await _load_crops_multithreaded_async(crop_data, progress_callback)
# 阶段3完成 (90-100%) # 阶段3完成 (90-100%)
progress_callback.call(100, "所有作物图片加载完成!") progress_callback.call(100, "所有作物图片加载完成!")
_print_cache_stats() _print_cache_stats()
_send_debug_message("所有作物图片加载完成!", Color.GREEN)
# 清理线程 # 清理线程
await _cleanup_threads() await _cleanup_threads()
@@ -1278,28 +1249,23 @@ class CropTextureManager:
is_loading = false is_loading = false
var success_message = "预加载完成,成功: %d, 失败: %d" % [loaded_crops, failed_crops] var success_message = "预加载完成,成功: %d, 失败: %d" % [loaded_crops, failed_crops]
print("[CropTextureManager] " + success_message) print("[CropTextureManager] " + success_message)
_send_debug_message(success_message, Color.CYAN)
## 多线程批量异步加载作物图片 ## 多线程批量异步加载作物图片
func _load_crops_multithreaded_async(crop_data: Dictionary, progress_callback: Callable) -> void: func _load_crops_multithreaded_async(crop_data: Dictionary, progress_callback: Callable) -> void:
var crop_names = crop_data.keys() var crop_names = crop_data.keys()
# 准备加载队列 # 准备加载队列 - 为每个作物的每个阶段创建任务
loading_mutex.lock() loading_mutex.lock()
loading_queue.clear() loading_queue.clear()
for crop_name in crop_names: for crop_name in crop_names:
loading_queue.append({ for stage in GROWTH_STAGES:
"crop_name": crop_name, loading_queue.append({
"type": "sequence" "crop_name": crop_name,
}) "stage": stage
loading_queue.append({ })
"crop_name": crop_name,
"type": "mature"
})
loading_mutex.unlock() loading_mutex.unlock()
# 启动工作线程 # 启动工作线程
_send_debug_message("启动 %d 个工作线程" % max_threads, Color.CYAN)
for i in range(max_threads): for i in range(max_threads):
var thread = Thread.new() var thread = Thread.new()
worker_threads.append(thread) worker_threads.append(thread)
@@ -1363,66 +1329,42 @@ class CropTextureManager:
## 执行单个纹理加载任务 ## 执行单个纹理加载任务
func _load_texture_task(task: Dictionary) -> Dictionary: func _load_texture_task(task: Dictionary) -> Dictionary:
var crop_name = task["crop_name"] var crop_name = task["crop_name"]
var task_type = task["type"] var stage = task["stage"]
var result = { var result = {
"crop_name": crop_name, "crop_name": crop_name,
"type": task_type, "stage": stage,
"success": false, "success": false,
"textures": [],
"texture": null, "texture": null,
"error": "" "error": ""
} }
if task_type == "sequence": result["texture"] = _load_stage_texture_threadsafe(crop_name, stage)
result["textures"] = _load_crop_textures_threadsafe(crop_name) result["success"] = result["texture"] != null
result["success"] = result["textures"].size() > 0
elif task_type == "mature":
result["texture"] = _load_mature_texture_threadsafe(crop_name)
result["success"] = result["texture"] != null
# 检查加载是否成功 # 检查加载是否成功
if not result["success"]: if not result["success"]:
result["error"] = "加载失败: " + crop_name result["error"] = "加载失败: %s - %s" % [crop_name, stage]
failed_resources.append(crop_name) failed_resources.append(crop_name + "/" + stage)
return result return result
## 线程安全的作物序列帧加载 ## 线程安全的阶段图片加载
func _load_crop_textures_threadsafe(crop_name: String) -> Array: func _load_stage_texture_threadsafe(crop_name: String, stage: String) -> Texture2D:
var textures = []
var crop_path = "res://assets/作物/" + crop_name + "/" var crop_path = "res://assets/作物/" + crop_name + "/"
var texture_path = crop_path + stage + ".webp"
# 检查作物文件夹是否存在 # 首先尝试加载作物特定的阶段图片
if not DirAccess.dir_exists_absolute(crop_path): if ResourceLoader.exists(texture_path):
return []
# 使用ResourceLoader.load_threaded_request进行异步加载
var frame_index = 0
var max_frames = 20 # 限制最大帧数,避免无限循环
while frame_index < max_frames:
var texture_path = crop_path + str(frame_index) + ".webp"
if not ResourceLoader.exists(texture_path):
break
# 使用线程安全的资源加载
var texture = _load_resource_safe(texture_path) var texture = _load_resource_safe(texture_path)
if texture: if texture:
textures.append(texture) return texture
frame_index += 1
else:
break
return textures # 如果没有找到,尝试使用默认图片
var default_path = "res://assets/作物/默认/" + stage + ".webp"
## 线程安全的成熟图片加载 if ResourceLoader.exists(default_path):
func _load_mature_texture_threadsafe(crop_name: String) -> Texture2D: var default_texture = _load_resource_safe(default_path)
var crop_path = "res://assets/作物/" + crop_name + "/" if default_texture:
var mature_path = crop_path + "成熟.webp" return default_texture
if ResourceLoader.exists(mature_path):
return _load_resource_safe(mature_path)
return null return null
@@ -1448,76 +1390,41 @@ class CropTextureManager:
## 应用加载结果到缓存 ## 应用加载结果到缓存
func _apply_loading_result(result: Dictionary): func _apply_loading_result(result: Dictionary):
var crop_name = result["crop_name"] var crop_name = result["crop_name"]
var task_type = result["type"] var stage = result["stage"]
var success = result["success"] var success = result["success"]
if not success: if not success:
var error_msg = "加载失败: %s (%s)" % [crop_name, task_type]
_send_debug_message(error_msg, Color.RED)
return return
if task_type == "sequence": var texture = result["texture"]
var textures = result["textures"] if texture:
if textures.size() > 0: # 确保作物有缓存字典
texture_cache[crop_name] = textures if not texture_cache.has(crop_name):
frame_counts[crop_name] = textures.size() texture_cache[crop_name] = {}
_update_cache_access(crop_name)
_send_debug_message("%s: %d" % [crop_name, textures.size()], Color.GREEN) # 缓存阶段图片
elif task_type == "mature": texture_cache[crop_name][stage] = texture
var texture = result["texture"] _update_cache_access(crop_name + "_" + stage)
if texture:
mature_texture_cache[crop_name] = texture
_update_cache_access(crop_name + "_mature")
_send_debug_message("%s: 成熟图片" % crop_name, Color.GREEN)
# 检查缓存大小,必要时清理 # 检查缓存大小,必要时清理
_check_and_cleanup_cache() _check_and_cleanup_cache()
## 立即加载默认图片(同步,但优化) ## 立即加载默认图片(同步,但优化)
func _load_default_textures_async() -> void: func _load_default_textures_async() -> void:
const DEFAULT_CROP = "默认"
const DEFAULT_PATH = "res://assets/作物/默认/" const DEFAULT_PATH = "res://assets/作物/默认/"
if texture_cache.has(DEFAULT_CROP): if default_textures.size() > 0:
return return
var textures = [] # 加载三个阶段的默认图片
var frame_index = 0 for stage in GROWTH_STAGES:
var texture_path = DEFAULT_PATH + stage + ".webp"
# 限制默认图片帧数
while frame_index < 10:
var texture_path = DEFAULT_PATH + str(frame_index) + ".webp"
if ResourceLoader.exists(texture_path): if ResourceLoader.exists(texture_path):
var texture = _load_resource_safe(texture_path) var texture = _load_resource_safe(texture_path)
if texture: if texture:
textures.append(texture) default_textures[stage] = texture
frame_index += 1
else:
break
else:
break
# 如果没有序列帧,尝试加载单个图片 print("[CropTextureManager] 默认图片加载完成:%d 个阶段" % default_textures.size())
if textures.size() == 0:
var single_path = DEFAULT_PATH + "0.webp"
if ResourceLoader.exists(single_path):
var texture = _load_resource_safe(single_path)
if texture:
textures.append(texture)
# 缓存结果
if textures.size() > 0:
texture_cache[DEFAULT_CROP] = textures
frame_counts[DEFAULT_CROP] = textures.size()
# 加载默认成熟图片
var mature_path = DEFAULT_PATH + "成熟.webp"
if ResourceLoader.exists(mature_path):
var mature_texture = _load_resource_safe(mature_path)
if mature_texture:
mature_texture_cache[DEFAULT_CROP] = mature_texture
print("[CropTextureManager] 默认图片加载完成:%d" % textures.size())
# 让出一帧 # 让出一帧
await Engine.get_main_loop().process_frame await Engine.get_main_loop().process_frame
@@ -1530,62 +1437,81 @@ class CropTextureManager:
## 检查并清理缓存 ## 检查并清理缓存
func _check_and_cleanup_cache(): func _check_and_cleanup_cache():
var total_cached = texture_cache.size() + mature_texture_cache.size() var total_cached = 0
for crop_name in texture_cache.keys():
total_cached += texture_cache[crop_name].size()
if total_cached > max_cache_size: if total_cached > max_cache_size:
var to_remove = total_cached - max_cache_size + 10 # 多清理一些 var to_remove = total_cached - max_cache_size + 10 # 多清理一些
_send_debug_message("⚠ 缓存超限,开始清理 %d 个项目" % to_remove, Color.ORANGE)
for i in range(min(to_remove, cache_access_order.size())): for i in range(min(to_remove, cache_access_order.size())):
var key = cache_access_order[i] var key = cache_access_order[i]
# 不清理默认图片 # 不清理默认图片相关的键
if key.begins_with("默认"): if key.begins_with("默认"):
continue continue
if key.ends_with("_mature"): # 解析键crop_name_stage
var crop_name = key.replace("_mature", "") var parts = key.split("_")
mature_texture_cache.erase(crop_name) if parts.size() >= 2:
else: var stage = parts[-1]
texture_cache.erase(key) var crop_name = "_".join(parts.slice(0, -1))
frame_counts.erase(key)
if texture_cache.has(crop_name) and texture_cache[crop_name].has(stage):
texture_cache[crop_name].erase(stage)
# 如果作物的所有阶段都被清理,删除作物条目
if texture_cache[crop_name].is_empty():
texture_cache.erase(crop_name)
# 更新访问顺序 # 更新访问顺序
cache_access_order = cache_access_order.slice(to_remove) cache_access_order = cache_access_order.slice(to_remove)
var current_size = texture_cache.size() + mature_texture_cache.size() var current_size = 0
for crop_name in texture_cache.keys():
current_size += texture_cache[crop_name].size()
var cleanup_msg = "缓存清理完成,当前缓存: %d" % current_size var cleanup_msg = "缓存清理完成,当前缓存: %d" % current_size
print("[CropTextureManager] " + cleanup_msg) print("[CropTextureManager] " + cleanup_msg)
_send_debug_message(cleanup_msg, Color.YELLOW)
## 根据生长进度获取作物图片(带缓存优化) ## 根据生长进度获取作物图片(带缓存优化)
func get_texture_by_progress(crop_name: String, progress: float) -> Texture2D: func get_texture_by_progress(crop_name: String, progress: float) -> Texture2D:
# 根据进度确定阶段
var stage = ""
if progress < 0.33:
stage = "幼苗"
elif progress < 0.85:
stage = "未成熟"
else:
stage = "成熟"
# 更新访问记录 # 更新访问记录
_update_cache_access(crop_name) var access_key = crop_name + "_" + stage
_update_cache_access(access_key)
# 100%成熟时优先使用成熟图片 # 尝试获取作物特定的阶段图片
if progress >= 1.0: if texture_cache.has(crop_name) and texture_cache[crop_name].has(stage):
var mature_texture = mature_texture_cache.get(crop_name, null) var texture = texture_cache[crop_name][stage]
if mature_texture: if texture:
_update_cache_access(crop_name + "_mature") return texture
return mature_texture
# 使用序列帧图片 # 如果没有缓存,尝试直接从文件夹加载
var textures = texture_cache.get(crop_name, []) var direct_texture = _load_stage_texture_threadsafe(crop_name, stage)
if textures.size() == 0: if direct_texture:
# 如果没有缓存,尝试使用默认图片 # 将直接加载的图片加入缓存,避免下次再次加载
textures = texture_cache.get("默认", []) if not texture_cache.has(crop_name):
if textures.size() == 0: texture_cache[crop_name] = {}
return null texture_cache[crop_name][stage] = direct_texture
_update_cache_access(crop_name + "_" + stage)
return direct_texture
if textures.size() == 1: # 最后才回退到默认图片
return textures[0] if default_textures.has(stage):
var default_texture = default_textures[stage]
if default_texture:
return default_texture
# 根据进度计算帧索引 # 如果都没有返回null
var frame_index = int(progress * (textures.size() - 1)) return null
frame_index = clamp(frame_index, 0, textures.size() - 1)
return textures[frame_index]
## 清理线程 ## 清理线程
func _cleanup_threads() -> void: func _cleanup_threads() -> void:
@@ -1599,8 +1525,7 @@ class CropTextureManager:
func clear_cache() -> void: func clear_cache() -> void:
await _cleanup_threads() await _cleanup_threads()
texture_cache.clear() texture_cache.clear()
mature_texture_cache.clear() default_textures.clear()
frame_counts.clear()
cache_access_order.clear() cache_access_order.clear()
failed_resources.clear() failed_resources.clear()
print("[CropTextureManager] 缓存已清理") print("[CropTextureManager] 缓存已清理")
@@ -1608,13 +1533,13 @@ class CropTextureManager:
## 打印缓存统计信息 ## 打印缓存统计信息
func _print_cache_stats() -> void: func _print_cache_stats() -> void:
print("[CropTextureManager] 缓存统计:") print("[CropTextureManager] 缓存统计:")
print(" - 序列帧缓存: %d 种作物" % texture_cache.size()) print(" - 阶段图片缓存: %d 种作物" % texture_cache.size())
print(" - 成熟图片缓存: %d 种作物" % mature_texture_cache.size()) print(" - 默认图片缓存: %d 个阶段" % default_textures.size())
print(" - 加载失败: %d 个资源" % failed_resources.size()) print(" - 加载失败: %d 个资源" % failed_resources.size())
var total_frames = 0 var total_stages = 0
for count in frame_counts.values(): for crop_name in texture_cache.keys():
total_frames += count total_stages += texture_cache[crop_name].size()
print(" - 总图片数: %d " % total_frames) print(" - 总阶段图片数: %d " % total_stages)
if failed_resources.size() > 0: if failed_resources.size() > 0:
print(" - 失败的资源:") print(" - 失败的资源:")
@@ -1625,13 +1550,15 @@ class CropTextureManager:
func get_cache_info() -> String: func get_cache_info() -> String:
var info = "作物图片缓存详情:\n" var info = "作物图片缓存详情:\n"
for crop_name in texture_cache.keys(): for crop_name in texture_cache.keys():
var frame_count = frame_counts.get(crop_name, 0) var stages = texture_cache[crop_name].keys()
var has_mature = mature_texture_cache.has(crop_name) info += " - %s: %s" % [crop_name, "/".join(stages)]
info += " - %s: %d" % [crop_name, frame_count]
if has_mature:
info += " (含成熟图片)"
info += "\n" info += "\n"
if default_textures.size() > 0:
info += "\n默认图片:\n"
for stage in default_textures.keys():
info += " - " + stage + "\n"
if failed_resources.size() > 0: if failed_resources.size() > 0:
info += "\n加载失败的资源:\n" info += "\n加载失败的资源:\n"
for failed in failed_resources: for failed in failed_resources:
@@ -1645,25 +1572,19 @@ class CropTextureManager:
for crop_name in common_crops: for crop_name in common_crops:
# 确保常用作物在缓存中 # 确保常用作物在缓存中
if not texture_cache.has(crop_name): if not texture_cache.has(crop_name):
var textures = _load_crop_textures_threadsafe(crop_name) texture_cache[crop_name] = {}
if textures.size() > 0:
texture_cache[crop_name] = textures # 加载各个阶段的图片
frame_counts[crop_name] = textures.size() for stage in GROWTH_STAGES:
var texture = _load_stage_texture_threadsafe(crop_name, stage)
if not mature_texture_cache.has(crop_name): if texture:
var mature = _load_mature_texture_threadsafe(crop_name) texture_cache[crop_name][stage] = texture
if mature:
mature_texture_cache[crop_name] = mature
# 全局作物图片管理器实例 # 全局作物图片管理器实例
var crop_texture_manager: CropTextureManager var crop_texture_manager: CropTextureManager
# 资源加载调试器(可选,用于调试)
var resource_debugger = null
# 调试面板脚本引用
var debug_panel_script = null
#===============================================作物图片缓存系统=============================================== #===============================================作物图片缓存系统===============================================
@@ -1724,11 +1645,7 @@ func _update_load_progress(progress: int, message: String = "") -> void:
if message_label and message != "": if message_label and message != "":
message_label.text = message message_label.text = message
# 向调试面板发送进度信息
if debug_panel_script and debug_panel_script.has_method("add_debug_message"):
if message != "":
#debug_panel_script.add_debug_message("进度 %d%%: %s" % [progress, message], Color.CYAN)
pass
# 检测卡顿 # 检测卡顿
_check_loading_stuck(progress) _check_loading_stuck(progress)
@@ -1748,8 +1665,7 @@ func _check_loading_stuck(progress: int):
if progress == last_progress_value: if progress == last_progress_value:
var stuck_time = current_time - last_progress_time var stuck_time = current_time - last_progress_time
if stuck_time > 5.0: # 5秒没有进度变化 if stuck_time > 5.0: # 5秒没有进度变化
if debug_panel_script and debug_panel_script.has_method("add_debug_message"): print("⚠ 加载卡顿检测: 在 %d%% 停留了 %.1f" % [progress, stuck_time])
debug_panel_script.add_debug_message("⚠ 加载卡顿检测: 在 %d%% 停留了 %.1f" % [progress, stuck_time], Color.ORANGE)
else: else:
# 进度有变化,更新记录 # 进度有变化,更新记录
last_progress_value = progress last_progress_value = progress
@@ -1797,95 +1713,7 @@ func _wait_for_crop_data() -> void:
#===============================================调试和维护工具=============================================== #===============================================调试和维护工具===============================================
## 调试:打印缓存信息
func _debug_print_crop_cache() -> void:
if crop_texture_manager:
print(crop_texture_manager.get_cache_info())
else:
print("[调试] 作物图片管理器未初始化")
## 调试:强制刷新所有图片
func _debug_refresh_all_crop_sprites() -> void:
print("[调试] 强制刷新所有地块图片...")
_refresh_all_crop_sprites()
print("[调试] 图片刷新完成")
## 调试:清理图片缓存
func _debug_clear_crop_cache() -> void:
if crop_texture_manager:
crop_texture_manager.clear_cache()
print("[调试] 图片缓存已清理")
## 调试:启用资源加载调试器
func _debug_enable_resource_debugger() -> void:
if not resource_debugger:
resource_debugger = preload("res://GlobalScript/ResourceLoadingDebugger.gd").new()
add_child(resource_debugger)
print("[调试] 资源加载调试器已启用")
else:
print("[调试] 资源加载调试器已经在运行")
## 调试:生成资源加载报告
func _debug_generate_loading_report() -> void:
if resource_debugger:
var report = resource_debugger.generate_loading_report()
print(report)
resource_debugger.export_debug_data_to_file()
else:
print("[调试] 资源加载调试器未启用,请先调用 _debug_enable_resource_debugger()")
## 调试:检测设备能力
func _debug_detect_device_capabilities() -> void:
if resource_debugger:
var capabilities = resource_debugger.detect_device_capabilities()
print("[调试] 设备能力检测结果:")
for key in capabilities:
print(" %s: %s" % [key, str(capabilities[key])])
else:
print("[调试] 资源加载调试器未启用")
## 调试:强制触发低内存模式
func _debug_trigger_low_memory_mode() -> void:
if crop_texture_manager:
# 临时降低缓存大小来模拟低内存环境
crop_texture_manager.max_cache_size = 50
crop_texture_manager._check_and_cleanup_cache()
print("[调试] 已触发低内存模式缓存大小限制为50")
## 调试:恢复正常内存模式
func _debug_restore_normal_memory_mode() -> void:
if crop_texture_manager:
crop_texture_manager.max_cache_size = 200
print("[调试] 已恢复正常内存模式缓存大小限制为200")
## 在加载进度面板上添加调试按钮
func _add_debug_button_to_loading_panel():
# 创建调试按钮
var debug_button = Button.new()
debug_button.text = "调试信息"
debug_button.size_flags_horizontal = Control.SIZE_SHRINK_CENTER
debug_button.position = Vector2(10, 500) # 左下角位置
debug_button.size = Vector2(120, 40)
# 设置按钮样式
debug_button.modulate = Color(0.8, 0.8, 1.0, 0.9) # 半透明蓝色
# 连接点击信号
debug_button.pressed.connect(_on_debug_button_pressed)
# 添加到加载进度面板
load_progress_panel.add_child(debug_button)
print("[MainGame] 调试按钮已添加到加载进度面板")
## 调试按钮点击处理
func _on_debug_button_pressed():
if debug_panel.visible:
debug_panel.hide()
else:
debug_panel.show()
debug_panel.move_to_front()
print("[MainGame] 调试面板切换显示状态")
#===============================================调试和维护工具=============================================== #===============================================调试和维护工具===============================================
@@ -1894,8 +1722,14 @@ func _on_debug_button_pressed():
#===============================================向后兼容性=============================================== #===============================================向后兼容性===============================================
# 为了保持向后兼容,保留一些原来的函数名 # 为了保持向后兼容,保留一些原来的函数名
func _load_crop_textures(crop_name: String) -> Array: func _load_crop_textures(crop_name: String) -> Array:
if crop_texture_manager: # 返回所有阶段的图片
return crop_texture_manager._load_crop_textures_threadsafe(crop_name) if crop_texture_manager and crop_texture_manager.texture_cache.has(crop_name):
var stages = crop_texture_manager.texture_cache[crop_name]
var textures = []
for stage in crop_texture_manager.GROWTH_STAGES:
if stages.has(stage):
textures.append(stages[stage])
return textures
return [] return []
func _get_crop_texture_by_progress(crop_name: String, progress: float) -> Texture2D: func _get_crop_texture_by_progress(crop_name: String, progress: float) -> Texture2D:
@@ -2398,12 +2232,11 @@ func _handle_broadcast_history_response(data: Dictionary):
# 更新主界面大喇叭显示为最新消息 # 更新主界面大喇叭显示为最新消息
if global_server_broadcast: if global_server_broadcast:
var latest_message = global_server_broadcast_panel.get_latest_message() var latest_message = global_server_broadcast_panel.get_latest_message()
if latest_message != "暂无消息": if latest_message != "全服大喇叭":
global_server_broadcast.text = latest_message global_server_broadcast.text = latest_message
print("主界面大喇叭已更新为: ", latest_message) print("主界面大喇叭已更新为: ", latest_message)
else: else:
global_server_broadcast.text = "" global_server_broadcast.text = "全服大喇叭"
print("没有消息,清空主界面大喇叭显示")
# 初始化大喇叭显示 # 初始化大喇叭显示
@@ -3479,3 +3312,39 @@ func _handle_wisdom_tree_config_response(data):
wisdom_tree_panel.wisdom_tree_config = config wisdom_tree_panel.wisdom_tree_config = config
wisdom_tree_panel.update_ui() wisdom_tree_panel.update_ui()
# ======================================= 智慧树系统 ========================================= # ======================================= 智慧树系统 =========================================
# ======================================= 天气系统 =========================================
# 处理天气变更
func _handle_weather_change(weather_type: String, weather_name: String):
"""处理服务器发送的天气变更消息"""
if weather_system and weather_system.has_method("set_weather"):
weather_system.set_weather(weather_type)
Toast.show("天气已变更为:" + weather_name, Color.CYAN, 3.0)
print("天气已切换为:", weather_name)
else:
print("天气系统不可用")
# ======================================= 天气系统 =========================================
#打开小卖部面板
func _on_my_store_button_pressed() -> void:
player_store_panel.show()
pass
#打开小卖部面板
func _on_player_store_pressed() -> void:
player_store_panel.show()
pass
func _on_seed_store_pressed() -> void:
crop_store_panel.show()
pass
func _on_item_store_pressed() -> void:
item_store_panel.show()
pass
func _on_pet_store_pressed() -> void:
pet_store_panel.show()
pass

View File

@@ -1,8 +1,9 @@
[gd_scene load_steps=85 format=3 uid="uid://dgh61dttaas5a"] [gd_scene load_steps=96 format=3 uid="uid://dgh61dttaas5a"]
[ext_resource type="Script" uid="uid://2pt11sfcaxf7" path="res://MainGame.gd" id="1_v3yaj"] [ext_resource type="Script" uid="uid://2pt11sfcaxf7" path="res://MainGame.gd" id="1_v3yaj"]
[ext_resource type="Texture2D" uid="uid://du2pyiojliasy" path="res://assets/游戏UI/经验球.webp" id="2_6jgly"] [ext_resource type="Texture2D" uid="uid://du2pyiojliasy" path="res://assets/游戏UI/经验球.webp" id="2_6jgly"]
[ext_resource type="PackedScene" uid="uid://bkivlkirrx6u8" path="res://CopyItems/crop_item.tscn" id="3_isiom"] [ext_resource type="PackedScene" uid="uid://bkivlkirrx6u8" path="res://CopyItems/crop_item.tscn" id="3_isiom"]
[ext_resource type="FontFile" uid="uid://dl31rnmd4lia" path="res://assets/字体/MapleMono-NF-CN-Bold.ttf" id="3_t4s8j"]
[ext_resource type="Texture2D" uid="uid://ftv231igtdoq" path="res://assets/游戏UI/等级.webp" id="3_y1hsh"] [ext_resource type="Texture2D" uid="uid://ftv231igtdoq" path="res://assets/游戏UI/等级.webp" id="3_y1hsh"]
[ext_resource type="Texture2D" uid="uid://bqib5y8uwg6hx" path="res://assets/游戏UI/钱币.webp" id="4_ql8k3"] [ext_resource type="Texture2D" uid="uid://bqib5y8uwg6hx" path="res://assets/游戏UI/钱币.webp" id="4_ql8k3"]
[ext_resource type="Texture2D" uid="uid://waqbwo2r33j3" path="res://assets/游戏UI/小提示.webp" id="5_5b81d"] [ext_resource type="Texture2D" uid="uid://waqbwo2r33j3" path="res://assets/游戏UI/小提示.webp" id="5_5b81d"]
@@ -31,6 +32,7 @@
[ext_resource type="PackedScene" uid="uid://j4ft87o7jk14" path="res://Scene/BigPanel/ItemStorePanel.tscn" id="21_uhubb"] [ext_resource type="PackedScene" uid="uid://j4ft87o7jk14" path="res://Scene/BigPanel/ItemStorePanel.tscn" id="21_uhubb"]
[ext_resource type="PackedScene" uid="uid://cw8am7nnbgca5" path="res://Scene/Pet/PetFightPanel.tscn" id="23_n03md"] [ext_resource type="PackedScene" uid="uid://cw8am7nnbgca5" path="res://Scene/Pet/PetFightPanel.tscn" id="23_n03md"]
[ext_resource type="Script" uid="uid://bdhwvqsmakna2" path="res://Script/BigPanel/PetBagPanel.gd" id="23_uc6q1"] [ext_resource type="Script" uid="uid://bdhwvqsmakna2" path="res://Script/BigPanel/PetBagPanel.gd" id="23_uc6q1"]
[ext_resource type="Script" uid="uid://bdavskipn547h" path="res://Script/BigPanel/PlayerStorePanel.gd" id="24_dygid"]
[ext_resource type="PackedScene" uid="uid://cnjidcwuv4nn4" path="res://Scene/BigPanel/PetStorePanel.tscn" id="24_uc6q1"] [ext_resource type="PackedScene" uid="uid://cnjidcwuv4nn4" path="res://Scene/BigPanel/PetStorePanel.tscn" id="24_uc6q1"]
[ext_resource type="PackedScene" uid="uid://d3i0l6ysrde6o" path="res://Scene/SmallPanel/AccountSettingPanel.tscn" id="26_uc6q1"] [ext_resource type="PackedScene" uid="uid://d3i0l6ysrde6o" path="res://Scene/SmallPanel/AccountSettingPanel.tscn" id="26_uc6q1"]
[ext_resource type="PackedScene" uid="uid://d1lu2yg4xl382" path="res://Scene/SmallPanel/LoadProgressPanel.tscn" id="27_vygm6"] [ext_resource type="PackedScene" uid="uid://d1lu2yg4xl382" path="res://Scene/SmallPanel/LoadProgressPanel.tscn" id="27_vygm6"]
@@ -46,31 +48,33 @@
[ext_resource type="PackedScene" uid="uid://ibl5wbbw3pwc" path="res://CopyItems/item_button.tscn" id="39_cdkxt"] [ext_resource type="PackedScene" uid="uid://ibl5wbbw3pwc" path="res://CopyItems/item_button.tscn" id="39_cdkxt"]
[ext_resource type="Script" uid="uid://dwf28j01ckg3y" path="res://Script/SmallPanel/WisdomTreePanel.gd" id="39_np7ck"] [ext_resource type="Script" uid="uid://dwf28j01ckg3y" path="res://Script/SmallPanel/WisdomTreePanel.gd" id="39_np7ck"]
[ext_resource type="Texture2D" uid="uid://bt1i2yhhlor5e" path="res://assets/地块/土块1.webp" id="41_cdkxt"] [ext_resource type="Texture2D" uid="uid://bt1i2yhhlor5e" path="res://assets/地块/土块1.webp" id="41_cdkxt"]
[ext_resource type="Script" uid="uid://b185o1hjnlrv5" path="res://Script/SmallPanel/CropInformPanel.gd" id="41_iluto"]
[ext_resource type="Texture2D" uid="uid://3ff2lnbc0op7" path="res://assets/稻草人图片/稻草人1.webp" id="43_6rkns"] [ext_resource type="Texture2D" uid="uid://3ff2lnbc0op7" path="res://assets/稻草人图片/稻草人1.webp" id="43_6rkns"]
[ext_resource type="Script" uid="uid://dsmmxivba06ab" path="res://Script/Dialog/BatchSellPopup.gd" id="44_av1bx"]
[ext_resource type="Texture2D" uid="uid://cbdm5e6s8bf6l" path="res://assets/智慧树图片/智慧树4.webp" id="45_xvovi"] [ext_resource type="Texture2D" uid="uid://cbdm5e6s8bf6l" path="res://assets/智慧树图片/智慧树4.webp" id="45_xvovi"]
[ext_resource type="Script" uid="uid://cha0uw4ra1trr" path="res://Script/Dialog/AddProduct2StorePopup.gd" id="46_8d602"]
[ext_resource type="Texture2D" uid="uid://dilipbs0lncpd" path="res://assets/草地图片/草地10.webp" id="48_2i8fe"] [ext_resource type="Texture2D" uid="uid://dilipbs0lncpd" path="res://assets/草地图片/草地10.webp" id="48_2i8fe"]
[ext_resource type="Texture2D" uid="uid://du34yctd8bd8m" path="res://assets/灌木丛图片/灌木丛1.webp" id="49_xjiif"] [ext_resource type="Texture2D" uid="uid://du34yctd8bd8m" path="res://assets/灌木丛图片/灌木丛1.webp" id="49_xjiif"]
[ext_resource type="Texture2D" uid="uid://dswjorjhf1i6f" path="res://assets/灌木丛图片/灌木丛2.webp" id="50_sqnmr"] [ext_resource type="Texture2D" uid="uid://dswjorjhf1i6f" path="res://assets/灌木丛图片/灌木丛2.webp" id="50_sqnmr"]
[ext_resource type="Texture2D" uid="uid://go3n3qnpancf" path="res://assets/灌木丛图片/灌木丛3.webp" id="51_2i8fe"] [ext_resource type="Texture2D" uid="uid://go3n3qnpancf" path="res://assets/灌木丛图片/灌木丛3.webp" id="51_2i8fe"]
[ext_resource type="Texture2D" uid="uid://dk4yl4ghmxaa2" path="res://assets/天气系统图片/雪花.webp" id="53_4ka7t"] [ext_resource type="Texture2D" uid="uid://dk4yl4ghmxaa2" path="res://assets/天气系统图片/雪花.webp" id="53_4ka7t"]
[ext_resource type="PackedScene" uid="uid://cvg38nsrm77jy" path="res://Scene/Particle/WillowLeafRain.tscn" id="53_nf3jg"]
[ext_resource type="Texture2D" uid="uid://chcgrmluhfxuk" path="res://assets/天气系统图片/樱花1.webp" id="53_tdq2s"] [ext_resource type="Texture2D" uid="uid://chcgrmluhfxuk" path="res://assets/天气系统图片/樱花1.webp" id="53_tdq2s"]
[ext_resource type="Texture2D" uid="uid://c1qqalp7owgy2" path="res://assets/天气系统图片/栀子花1.webp" id="53_xyeuq"] [ext_resource type="Texture2D" uid="uid://c1qqalp7owgy2" path="res://assets/天气系统图片/栀子花1.webp" id="53_xyeuq"]
[ext_resource type="Texture2D" uid="uid://b7g5ut03rm53n" path="res://assets/装饰物图片/小卖部.webp" id="54_06tja"]
[ext_resource type="Texture2D" uid="uid://dfkgmj7e0555q" path="res://assets/天气系统图片/樱花2.webp" id="54_dygjy"] [ext_resource type="Texture2D" uid="uid://dfkgmj7e0555q" path="res://assets/天气系统图片/樱花2.webp" id="54_dygjy"]
[ext_resource type="Texture2D" uid="uid://bfducebx4c4il" path="res://assets/天气系统图片/柳叶3.webp" id="54_jiccn"] [ext_resource type="Texture2D" uid="uid://bfducebx4c4il" path="res://assets/天气系统图片/柳叶3.webp" id="54_jiccn"]
[ext_resource type="Texture2D" uid="uid://cd7x78uyi2csh" path="res://assets/天气系统图片/栀子花2.webp" id="54_t4s8j"] [ext_resource type="Texture2D" uid="uid://cd7x78uyi2csh" path="res://assets/天气系统图片/栀子花2.webp" id="54_t4s8j"]
[ext_resource type="Texture2D" uid="uid://dl58ie2lneq77" path="res://assets/天气系统图片/柳叶1.webp" id="55_e8wx8"] [ext_resource type="Texture2D" uid="uid://dl58ie2lneq77" path="res://assets/天气系统图片/柳叶1.webp" id="55_e8wx8"]
[ext_resource type="Texture2D" uid="uid://q0difb6wjkgm" path="res://assets/天气系统图片/樱花3.webp" id="55_edvcq"] [ext_resource type="Texture2D" uid="uid://q0difb6wjkgm" path="res://assets/天气系统图片/樱花3.webp" id="55_edvcq"]
[ext_resource type="Texture2D" uid="uid://j3h0ocagxf8" path="res://assets/装饰物图片/种子商店.webp" id="55_g4i0f"]
[ext_resource type="Texture2D" uid="uid://cqqyc3ddwtvpn" path="res://assets/天气系统图片/栀子花3.webp" id="55_iluto"] [ext_resource type="Texture2D" uid="uid://cqqyc3ddwtvpn" path="res://assets/天气系统图片/栀子花3.webp" id="55_iluto"]
[ext_resource type="Texture2D" uid="uid://d4e54gh5iccul" path="res://assets/装饰物图片/道具商店.webp" id="56_rlmnt"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_5dq3w"] [ext_resource type="Texture2D" uid="uid://deow5dqdm412v" path="res://assets/装饰物图片/宠物商店.webp" id="57_rlmnt"]
[ext_resource type="Script" uid="uid://o4mcuqoivqri" path="res://GameManager/WeatherSystem.gd" id="62_uyv6e"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_nf3jg"] [ext_resource type="Texture2D" uid="uid://bnv6wb0k443fv" path="res://assets/天气系统图片/柳叶2.webp" id="69_uyv6e"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_adtqp"] [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_adtqp"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_4ka7t"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_n03md"] [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_n03md"]
border_width_left = 5 border_width_left = 5
border_width_top = 5 border_width_top = 5
@@ -83,6 +87,18 @@ corner_radius_bottom_left = 20
corner_detail = 20 corner_detail = 20
shadow_size = 20 shadow_size = 20
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_8d602"]
border_width_left = 5
border_width_top = 5
border_width_right = 5
border_width_bottom = 5
corner_radius_top_left = 20
corner_radius_top_right = 20
corner_radius_bottom_right = 20
corner_radius_bottom_left = 20
corner_detail = 20
shadow_size = 20
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_5b81d"] [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_5b81d"]
border_width_left = 10 border_width_left = 10
border_width_top = 10 border_width_top = 10
@@ -116,10 +132,22 @@ corner_radius_bottom_left = 20
corner_detail = 20 corner_detail = 20
shadow_size = 30 shadow_size = 30
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_xyeuq"]
border_width_left = 15
border_width_top = 15
border_width_right = 15
border_width_bottom = 15
corner_detail = 20
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_t4s8j"]
border_width_left = 15
border_width_top = 15
border_width_right = 15
border_width_bottom = 15
[sub_resource type="Environment" id="Environment_m6fch"] [sub_resource type="Environment" id="Environment_m6fch"]
background_mode = 3 background_mode = 3
ambient_light_energy = 0.0 ambient_light_energy = 0.0
glow_enabled = true
glow_intensity = 1.0 glow_intensity = 1.0
glow_bloom = 0.3 glow_bloom = 0.3
glow_blend_mode = 0 glow_blend_mode = 0
@@ -164,6 +192,18 @@ turbulence_noise_speed = Vector3(10, 0, 0)
turbulence_influence_min = 0.02 turbulence_influence_min = 0.02
turbulence_influence_max = 0.07 turbulence_influence_max = 0.07
[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_6fhdl"]
particle_flag_disable_z = true
emission_shape = 3
emission_box_extents = Vector3(1000, 1, 1)
gravity = Vector3(-30, 80, 0)
scale_min = 0.4
scale_max = 0.5
turbulence_enabled = true
turbulence_noise_speed = Vector3(10, 0, 0)
turbulence_influence_min = 0.02
turbulence_influence_max = 0.07
[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_e8wx8"] [sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_e8wx8"]
particle_flag_disable_z = true particle_flag_disable_z = true
emission_shape = 3 emission_shape = 3
@@ -243,7 +283,7 @@ anchors_preset = 0
[node name="GameInfoHBox1" type="HBoxContainer" parent="UI/GUI"] [node name="GameInfoHBox1" type="HBoxContainer" parent="UI/GUI"]
layout_mode = 0 layout_mode = 0
offset_right = 1400.0 offset_right = 1339.0
offset_bottom = 35.0 offset_bottom = 35.0
[node name="experience_image" type="TextureRect" parent="UI/GUI/GameInfoHBox1"] [node name="experience_image" type="TextureRect" parent="UI/GUI/GameInfoHBox1"]
@@ -261,8 +301,10 @@ theme_override_constants/shadow_offset_x = 3
theme_override_constants/shadow_offset_y = 3 theme_override_constants/shadow_offset_y = 3
theme_override_constants/outline_size = 10 theme_override_constants/outline_size = 10
theme_override_constants/shadow_outline_size = 10 theme_override_constants/shadow_outline_size = 10
theme_override_fonts/font = ExtResource("3_t4s8j")
theme_override_font_sizes/font_size = 25 theme_override_font_sizes/font_size = 25
text = "经验999" text = "经验999"
vertical_alignment = 1
[node name="level_image" type="TextureRect" parent="UI/GUI/GameInfoHBox1"] [node name="level_image" type="TextureRect" parent="UI/GUI/GameInfoHBox1"]
layout_mode = 2 layout_mode = 2
@@ -278,6 +320,7 @@ theme_override_constants/shadow_offset_x = 3
theme_override_constants/shadow_offset_y = 3 theme_override_constants/shadow_offset_y = 3
theme_override_constants/outline_size = 10 theme_override_constants/outline_size = 10
theme_override_constants/shadow_outline_size = 10 theme_override_constants/shadow_outline_size = 10
theme_override_fonts/font = ExtResource("3_t4s8j")
theme_override_font_sizes/font_size = 25 theme_override_font_sizes/font_size = 25
text = "等级100" text = "等级100"
@@ -295,6 +338,7 @@ theme_override_constants/shadow_offset_x = 3
theme_override_constants/shadow_offset_y = 3 theme_override_constants/shadow_offset_y = 3
theme_override_constants/outline_size = 10 theme_override_constants/outline_size = 10
theme_override_constants/shadow_outline_size = 10 theme_override_constants/shadow_outline_size = 10
theme_override_fonts/font = ExtResource("3_t4s8j")
theme_override_font_sizes/font_size = 25 theme_override_font_sizes/font_size = 25
text = "钱币999" text = "钱币999"
@@ -312,6 +356,7 @@ theme_override_constants/shadow_offset_x = 3
theme_override_constants/shadow_offset_y = 3 theme_override_constants/shadow_offset_y = 3
theme_override_constants/outline_size = 10 theme_override_constants/outline_size = 10
theme_override_constants/shadow_outline_size = 10 theme_override_constants/shadow_outline_size = 10
theme_override_fonts/font = ExtResource("3_t4s8j")
theme_override_font_sizes/font_size = 25 theme_override_font_sizes/font_size = 25
text = "体力值20" text = "体力值20"
@@ -329,13 +374,14 @@ theme_override_constants/shadow_offset_x = 3
theme_override_constants/shadow_offset_y = 3 theme_override_constants/shadow_offset_y = 3
theme_override_constants/outline_size = 10 theme_override_constants/outline_size = 10
theme_override_constants/shadow_outline_size = 10 theme_override_constants/shadow_outline_size = 10
theme_override_fonts/font = ExtResource("3_t4s8j")
theme_override_font_sizes/font_size = 25 theme_override_font_sizes/font_size = 25
text = "点赞数0" text = "点赞数0"
[node name="GameInfoHBox2" type="HBoxContainer" parent="UI/GUI"] [node name="GameInfoHBox2" type="HBoxContainer" parent="UI/GUI"]
layout_mode = 0 layout_mode = 0
offset_top = 35.0 offset_top = 35.0
offset_right = 1400.0 offset_right = 1336.0
offset_bottom = 70.0 offset_bottom = 70.0
[node name="player_name_image" type="TextureRect" parent="UI/GUI/GameInfoHBox2"] [node name="player_name_image" type="TextureRect" parent="UI/GUI/GameInfoHBox2"]
@@ -352,8 +398,9 @@ theme_override_constants/shadow_offset_x = 3
theme_override_constants/shadow_offset_y = 3 theme_override_constants/shadow_offset_y = 3
theme_override_constants/outline_size = 10 theme_override_constants/outline_size = 10
theme_override_constants/shadow_outline_size = 10 theme_override_constants/shadow_outline_size = 10
theme_override_fonts/font = ExtResource("3_t4s8j")
theme_override_font_sizes/font_size = 25 theme_override_font_sizes/font_size = 25
text = "玩家昵称树萌芽" text = "玩家昵称:树萌芽"
[node name="farm_name_image" type="TextureRect" parent="UI/GUI/GameInfoHBox2"] [node name="farm_name_image" type="TextureRect" parent="UI/GUI/GameInfoHBox2"]
layout_mode = 2 layout_mode = 2
@@ -369,6 +416,7 @@ theme_override_constants/shadow_offset_x = 3
theme_override_constants/shadow_offset_y = 3 theme_override_constants/shadow_offset_y = 3
theme_override_constants/outline_size = 10 theme_override_constants/outline_size = 10
theme_override_constants/shadow_outline_size = 10 theme_override_constants/shadow_outline_size = 10
theme_override_fonts/font = ExtResource("3_t4s8j")
theme_override_font_sizes/font_size = 25 theme_override_font_sizes/font_size = 25
text = "农场名称:树萌芽的农场" text = "农场名称:树萌芽的农场"
@@ -385,6 +433,7 @@ theme_override_constants/shadow_offset_x = 3
theme_override_constants/shadow_offset_y = 3 theme_override_constants/shadow_offset_y = 3
theme_override_constants/outline_size = 10 theme_override_constants/outline_size = 10
theme_override_constants/shadow_outline_size = 10 theme_override_constants/shadow_outline_size = 10
theme_override_fonts/font = ExtResource("3_t4s8j")
theme_override_font_sizes/font_size = 25 theme_override_font_sizes/font_size = 25
text = "服务器状态:正在检测中" text = "服务器状态:正在检测中"
@@ -402,31 +451,15 @@ theme_override_constants/shadow_offset_x = 3
theme_override_constants/shadow_offset_y = 3 theme_override_constants/shadow_offset_y = 3
theme_override_constants/outline_size = 10 theme_override_constants/outline_size = 10
theme_override_constants/shadow_outline_size = 10 theme_override_constants/shadow_outline_size = 10
theme_override_fonts/font = ExtResource("3_t4s8j")
theme_override_font_sizes/font_size = 25 theme_override_font_sizes/font_size = 25
text = "FPS0" text = "FPS0"
[node name="onlineplayer_image" type="TextureRect" parent="UI/GUI/GameInfoHBox2"]
layout_mode = 2
texture = ExtResource("10_vygm6")
expand_mode = 2
[node name="onlineplayer" type="Label" parent="UI/GUI/GameInfoHBox2"]
layout_mode = 2
theme_override_colors/font_color = Color(0.423529, 1, 0.533333, 1)
theme_override_colors/font_shadow_color = Color(0, 0, 0, 1)
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/shadow_offset_x = 3
theme_override_constants/shadow_offset_y = 3
theme_override_constants/outline_size = 10
theme_override_constants/shadow_outline_size = 10
theme_override_font_sizes/font_size = 25
text = "检测中..."
[node name="GameInfoHBox3" type="HBoxContainer" parent="UI/GUI"] [node name="GameInfoHBox3" type="HBoxContainer" parent="UI/GUI"]
layout_mode = 0 layout_mode = 0
offset_top = 70.0 offset_top = 70.0
offset_right = 1400.0 offset_right = 1335.0
offset_bottom = 105.0 offset_bottom = 113.0
[node name="tip_image" type="TextureRect" parent="UI/GUI/GameInfoHBox3"] [node name="tip_image" type="TextureRect" parent="UI/GUI/GameInfoHBox3"]
layout_mode = 2 layout_mode = 2
@@ -442,6 +475,7 @@ theme_override_constants/shadow_offset_x = 3
theme_override_constants/shadow_offset_y = 3 theme_override_constants/shadow_offset_y = 3
theme_override_constants/outline_size = 10 theme_override_constants/outline_size = 10
theme_override_constants/shadow_outline_size = 10 theme_override_constants/shadow_outline_size = 10
theme_override_fonts/font = ExtResource("3_t4s8j")
theme_override_font_sizes/font_size = 25 theme_override_font_sizes/font_size = 25
text = "游戏小提示" text = "游戏小提示"
@@ -460,6 +494,7 @@ theme_override_constants/shadow_offset_x = 3
theme_override_constants/shadow_offset_y = 3 theme_override_constants/shadow_offset_y = 3
theme_override_constants/outline_size = 10 theme_override_constants/outline_size = 10
theme_override_constants/shadow_outline_size = 10 theme_override_constants/shadow_outline_size = 10
theme_override_fonts/font = ExtResource("3_t4s8j")
theme_override_font_sizes/font_size = 25 theme_override_font_sizes/font_size = 25
text = "全服大喇叭" text = "全服大喇叭"
vertical_alignment = 1 vertical_alignment = 1
@@ -473,6 +508,24 @@ theme_override_constants/outline_size = 10
theme_override_font_sizes/font_size = 25 theme_override_font_sizes/font_size = 25
text = "查看" text = "查看"
[node name="onlineplayer_image" type="TextureRect" parent="UI/GUI/GameInfoHBox3"]
layout_mode = 2
texture = ExtResource("10_vygm6")
expand_mode = 2
[node name="onlineplayer" type="Label" parent="UI/GUI/GameInfoHBox3"]
layout_mode = 2
theme_override_colors/font_color = Color(0.423529, 1, 0.533333, 1)
theme_override_colors/font_shadow_color = Color(0, 0, 0, 1)
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/shadow_offset_x = 3
theme_override_constants/shadow_offset_y = 3
theme_override_constants/outline_size = 10
theme_override_constants/shadow_outline_size = 10
theme_override_fonts/font = ExtResource("3_t4s8j")
theme_override_font_sizes/font_size = 25
text = "检测中..."
[node name="FarmVBox" type="VBoxContainer" parent="UI/GUI"] [node name="FarmVBox" type="VBoxContainer" parent="UI/GUI"]
layout_mode = 0 layout_mode = 0
offset_left = 4.0 offset_left = 4.0
@@ -483,6 +536,7 @@ scale = Vector2(0.8, 0.8)
alignment = 2 alignment = 2
[node name="SeedStoreButton" type="Button" parent="UI/GUI/FarmVBox"] [node name="SeedStoreButton" type="Button" parent="UI/GUI/FarmVBox"]
visible = false
modulate = Color(1, 0.564706, 0.647059, 1) modulate = Color(1, 0.564706, 0.647059, 1)
layout_mode = 2 layout_mode = 2
theme_override_font_sizes/font_size = 40 theme_override_font_sizes/font_size = 40
@@ -501,6 +555,7 @@ theme_override_font_sizes/font_size = 40
text = "作物仓库" text = "作物仓库"
[node name="ItemStoreButton" type="Button" parent="UI/GUI/FarmVBox"] [node name="ItemStoreButton" type="Button" parent="UI/GUI/FarmVBox"]
visible = false
modulate = Color(0.231373, 0.772549, 1, 1) modulate = Color(0.231373, 0.772549, 1, 1)
layout_mode = 2 layout_mode = 2
theme_override_font_sizes/font_size = 40 theme_override_font_sizes/font_size = 40
@@ -560,6 +615,13 @@ offset_bottom = 408.0
scale = Vector2(0.8, 0.8) scale = Vector2(0.8, 0.8)
alignment = 2 alignment = 2
[node name="MyStoreButton" type="Button" parent="UI/GUI/OtherVBox"]
visible = false
modulate = Color(0.917346, 0.737213, 1, 1)
layout_mode = 2
theme_override_font_sizes/font_size = 40
text = "我的小卖部"
[node name="AccountSettingButton" type="Button" parent="UI/GUI/OtherVBox"] [node name="AccountSettingButton" type="Button" parent="UI/GUI/OtherVBox"]
modulate = Color(0.843137, 0.772549, 1, 1) modulate = Color(0.843137, 0.772549, 1, 1)
layout_mode = 2 layout_mode = 2
@@ -636,6 +698,7 @@ theme_override_font_sizes/font_size = 40
text = "宠物背包" text = "宠物背包"
[node name="PetStoreButton" type="Button" parent="UI/GUI/OtherVBox"] [node name="PetStoreButton" type="Button" parent="UI/GUI/OtherVBox"]
visible = false
modulate = Color(0.992157, 0.482353, 0.870588, 1) modulate = Color(0.992157, 0.482353, 0.870588, 1)
layout_mode = 2 layout_mode = 2
theme_override_font_sizes/font_size = 40 theme_override_font_sizes/font_size = 40
@@ -650,22 +713,6 @@ text = "稻草人"
[node name="BigPanel" type="CanvasLayer" parent="UI"] [node name="BigPanel" type="CanvasLayer" parent="UI"]
[node name="LuckyDrawPanel" parent="UI/BigPanel" instance=ExtResource("17_f21le")]
visible = false
offset_left = 425.0
offset_top = 2.0
offset_right = 1025.0
offset_bottom = 722.0
theme_override_styles/panel = SubResource("StyleBoxFlat_5dq3w")
[node name="DailyCheckInPanel" parent="UI/BigPanel" instance=ExtResource("18_m6fch")]
visible = false
offset_left = 442.0
offset_top = 3.0
offset_right = 1042.0
offset_bottom = 723.0
theme_override_styles/panel = SubResource("StyleBoxFlat_nf3jg")
[node name="TCPNetworkManagerPanel" parent="UI/BigPanel" instance=ExtResource("7_401ut")] [node name="TCPNetworkManagerPanel" parent="UI/BigPanel" instance=ExtResource("7_401ut")]
visible = false visible = false
offset_top = 97.0 offset_top = 97.0
@@ -688,15 +735,6 @@ offset_bottom = 797.0
[node name="CropWarehousePanel" parent="UI/BigPanel" instance=ExtResource("18_5b81d")] [node name="CropWarehousePanel" parent="UI/BigPanel" instance=ExtResource("18_5b81d")]
[node name="LoginPanel" parent="UI/BigPanel" instance=ExtResource("11_6jgly")]
visible = false
top_level = true
offset_left = 342.0
offset_top = 40.0
offset_right = 1092.0
offset_bottom = 700.0
theme_override_styles/panel = SubResource("StyleBoxFlat_4ka7t")
[node name="PlayerBagPanel" parent="UI/BigPanel" instance=ExtResource("19_8kysg")] [node name="PlayerBagPanel" parent="UI/BigPanel" instance=ExtResource("19_8kysg")]
visible = false visible = false
@@ -706,6 +744,88 @@ visible = false
[node name="ItemBagPanel" parent="UI/BigPanel" instance=ExtResource("20_n03md")] [node name="ItemBagPanel" parent="UI/BigPanel" instance=ExtResource("20_n03md")]
visible = false visible = false
[node name="PlayerStorePanel" type="Panel" parent="UI/BigPanel"]
visible = false
offset_left = 69.0
offset_top = 56.0
offset_right = 1635.0
offset_bottom = 836.0
scale = Vector2(0.8, 0.8)
size_flags_horizontal = 3
size_flags_vertical = 3
theme_override_styles/panel = SubResource("StyleBoxFlat_n03md")
script = ExtResource("24_dygid")
[node name="TMBackGround" type="ColorRect" parent="UI/BigPanel/PlayerStorePanel"]
layout_mode = 0
offset_left = -90.0
offset_top = -71.0
offset_right = 1672.0
offset_bottom = 831.0
color = Color(1, 1, 1, 0)
[node name="ScrollContainer" type="ScrollContainer" parent="UI/BigPanel/PlayerStorePanel"]
layout_mode = 2
offset_left = 28.0
offset_top = 95.0
offset_right = 3805.0
offset_bottom = 1723.0
scale = Vector2(0.4, 0.4)
size_flags_vertical = 3
horizontal_scroll_mode = 0
[node name="Store_Grid" type="GridContainer" parent="UI/BigPanel/PlayerStorePanel/ScrollContainer"]
layout_mode = 2
size_flags_horizontal = 6
size_flags_vertical = 3
columns = 8
[node name="Title" type="Label" parent="UI/BigPanel/PlayerStorePanel"]
layout_mode = 2
offset_right = 1566.0
offset_bottom = 69.0
size_flags_horizontal = 3
theme_override_colors/font_color = Color(1, 1, 0.807843, 1)
theme_override_colors/font_shadow_color = Color(0, 0, 0, 1)
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/shadow_offset_x = 4
theme_override_constants/shadow_offset_y = 4
theme_override_constants/outline_size = 15
theme_override_constants/shadow_outline_size = 15
theme_override_font_sizes/font_size = 50
text = "玩家小卖部"
horizontal_alignment = 1
[node name="QuitButton" type="Button" parent="UI/BigPanel/PlayerStorePanel"]
custom_minimum_size = Vector2(60, 60)
layout_mode = 2
offset_left = 1478.75
offset_top = 20.0
offset_right = 1538.75
offset_bottom = 83.0
theme_override_font_sizes/font_size = 40
text = "X"
[node name="RefreshButton" type="Button" parent="UI/BigPanel/PlayerStorePanel"]
custom_minimum_size = Vector2(60, 60)
layout_mode = 2
offset_left = 27.5
offset_top = 16.25
offset_right = 115.5
offset_bottom = 79.25
theme_override_font_sizes/font_size = 40
text = "刷新"
[node name="BuyProductBoothButton" type="Button" parent="UI/BigPanel/PlayerStorePanel"]
custom_minimum_size = Vector2(60, 60)
layout_mode = 2
offset_left = 207.5
offset_top = 17.5
offset_right = 535.5
offset_bottom = 80.5
theme_override_font_sizes/font_size = 40
text = "购买商品摊位"
[node name="PetStorePanel" parent="UI/BigPanel" instance=ExtResource("24_uc6q1")] [node name="PetStorePanel" parent="UI/BigPanel" instance=ExtResource("24_uc6q1")]
visible = false visible = false
@@ -718,7 +838,7 @@ offset_bottom = 836.0
scale = Vector2(0.8, 0.8) scale = Vector2(0.8, 0.8)
size_flags_horizontal = 3 size_flags_horizontal = 3
size_flags_vertical = 3 size_flags_vertical = 3
theme_override_styles/panel = SubResource("StyleBoxFlat_n03md") theme_override_styles/panel = SubResource("StyleBoxFlat_8d602")
script = ExtResource("23_uc6q1") script = ExtResource("23_uc6q1")
[node name="TMBackGround" type="ColorRect" parent="UI/BigPanel/PetBagPanel"] [node name="TMBackGround" type="ColorRect" parent="UI/BigPanel/PetBagPanel"]
@@ -784,6 +904,14 @@ text = "刷新"
[node name="PetFightPanel" parent="UI/BigPanel" instance=ExtResource("23_n03md")] [node name="PetFightPanel" parent="UI/BigPanel" instance=ExtResource("23_n03md")]
visible = false visible = false
[node name="DailyCheckInPanel" parent="UI/BigPanel" instance=ExtResource("18_m6fch")]
visible = false
[node name="LuckyDrawPanel" parent="UI/BigPanel" instance=ExtResource("17_f21le")]
visible = false
[node name="LoginPanel" parent="UI/BigPanel" instance=ExtResource("11_6jgly")]
[node name="SmallPanel" type="CanvasLayer" parent="UI"] [node name="SmallPanel" type="CanvasLayer" parent="UI"]
[node name="LoadProgressPanel" parent="UI/SmallPanel" instance=ExtResource("27_vygm6")] [node name="LoadProgressPanel" parent="UI/SmallPanel" instance=ExtResource("27_vygm6")]
@@ -1450,6 +1578,101 @@ offset_top = 166.0
offset_right = 979.0 offset_right = 979.0
offset_bottom = 482.0 offset_bottom = 482.0
[node name="CropInformPanel" type="Panel" parent="UI/SmallPanel"]
visible = false
offset_left = 330.0
offset_right = 958.0
offset_bottom = 723.0
theme_override_styles/panel = SubResource("StyleBoxFlat_xyeuq")
script = ExtResource("41_iluto")
[node name="Title" type="Label" parent="UI/SmallPanel/CropInformPanel"]
layout_mode = 0
offset_top = 17.0
offset_right = 628.0
offset_bottom = 74.0
theme_override_colors/font_shadow_color = Color(0, 0, 0, 1)
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/shadow_offset_x = 4
theme_override_constants/shadow_offset_y = 4
theme_override_constants/outline_size = 20
theme_override_constants/shadow_outline_size = 20
theme_override_font_sizes/font_size = 35
text = "作物信息"
horizontal_alignment = 1
vertical_alignment = 1
[node name="QuitButton" type="Button" parent="UI/SmallPanel/CropInformPanel"]
custom_minimum_size = Vector2(50, 50)
layout_mode = 0
offset_left = 561.0
offset_top = 17.0
offset_right = 611.0
offset_bottom = 67.0
theme_override_font_sizes/font_size = 30
text = "X"
[node name="VBox" type="VBoxContainer" parent="UI/SmallPanel/CropInformPanel"]
layout_mode = 0
offset_left = 17.0
offset_top = 74.0
offset_right = 615.0
offset_bottom = 708.0
[node name="CropImage" type="TextureRect" parent="UI/SmallPanel/CropInformPanel/VBox"]
layout_mode = 2
texture = ExtResource("31_uc6q1")
stretch_mode = 3
[node name="CropName" type="Label" parent="UI/SmallPanel/CropInformPanel/VBox"]
layout_mode = 2
theme_override_font_sizes/font_size = 30
text = "名称:"
horizontal_alignment = 1
vertical_alignment = 1
[node name="CropDescription" type="Label" parent="UI/SmallPanel/CropInformPanel/VBox"]
layout_mode = 2
theme_override_font_sizes/font_size = 25
text = "描述:"
horizontal_alignment = 1
vertical_alignment = 1
[node name="CropPrice" type="Label" parent="UI/SmallPanel/CropInformPanel/VBox"]
layout_mode = 2
theme_override_font_sizes/font_size = 25
text = "收购价:"
horizontal_alignment = 1
vertical_alignment = 1
[node name="CropQuality" type="Label" parent="UI/SmallPanel/CropInformPanel/VBox"]
layout_mode = 2
theme_override_font_sizes/font_size = 25
text = "品质:"
horizontal_alignment = 1
vertical_alignment = 1
[node name="HBox" type="HBoxContainer" parent="UI/SmallPanel/CropInformPanel/VBox"]
layout_mode = 2
size_flags_vertical = 10
alignment = 1
[node name="SaleProduct" type="Button" parent="UI/SmallPanel/CropInformPanel/VBox/HBox"]
custom_minimum_size = Vector2(120, 70)
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 10
theme_override_font_sizes/font_size = 30
text = "直接出售"
[node name="AddToStore" type="Button" parent="UI/SmallPanel/CropInformPanel/VBox/HBox"]
custom_minimum_size = Vector2(120, 70)
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 10
theme_override_font_sizes/font_size = 30
text = "放入小卖部"
[node name="DiaLog" type="CanvasLayer" parent="UI"] [node name="DiaLog" type="CanvasLayer" parent="UI"]
[node name="AcceptDialog" parent="UI/DiaLog" instance=ExtResource("16_0igvr")] [node name="AcceptDialog" parent="UI/DiaLog" instance=ExtResource("16_0igvr")]
@@ -1461,6 +1684,7 @@ offset_left = 426.0
offset_top = 90.0 offset_top = 90.0
offset_right = 928.0 offset_right = 928.0
offset_bottom = 556.0 offset_bottom = 556.0
theme_override_styles/panel = SubResource("StyleBoxFlat_t4s8j")
script = ExtResource("29_5b81d") script = ExtResource("29_5b81d")
[node name="VBox" type="VBoxContainer" parent="UI/DiaLog/BatchBuyPopup"] [node name="VBox" type="VBoxContainer" parent="UI/DiaLog/BatchBuyPopup"]
@@ -1499,6 +1723,145 @@ size_flags_horizontal = 3
theme_override_font_sizes/font_size = 30 theme_override_font_sizes/font_size = 30
text = "取消" text = "取消"
[node name="BatchSellPopup" type="PanelContainer" parent="UI/DiaLog"]
visible = false
offset_left = 391.0
offset_top = 95.0
offset_right = 893.0
offset_bottom = 561.0
theme_override_styles/panel = SubResource("StyleBoxFlat_t4s8j")
script = ExtResource("44_av1bx")
[node name="VBox" type="VBoxContainer" parent="UI/DiaLog/BatchSellPopup"]
layout_mode = 2
[node name="Title" type="Label" parent="UI/DiaLog/BatchSellPopup/VBox"]
layout_mode = 2
theme_override_colors/font_shadow_color = Color(0, 0, 0, 1)
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/shadow_offset_x = 3
theme_override_constants/shadow_offset_y = 3
theme_override_constants/outline_size = 20
theme_override_constants/shadow_outline_size = 20
theme_override_font_sizes/font_size = 40
text = "请选择出售数量"
horizontal_alignment = 1
vertical_alignment = 1
[node name="Contents" type="Label" parent="UI/DiaLog/BatchSellPopup/VBox"]
layout_mode = 2
size_flags_vertical = 3
theme_override_font_sizes/font_size = 20
text = "这是说明内容"
horizontal_alignment = 1
[node name="SellNumEdit" type="LineEdit" parent="UI/DiaLog/BatchSellPopup/VBox"]
layout_mode = 2
theme_override_font_sizes/font_size = 30
[node name="HBox" type="HBoxContainer" parent="UI/DiaLog/BatchSellPopup/VBox"]
layout_mode = 2
[node name="SureButton" type="Button" parent="UI/DiaLog/BatchSellPopup/VBox/HBox"]
layout_mode = 2
size_flags_horizontal = 3
theme_override_font_sizes/font_size = 30
text = "确定"
[node name="CancelButton" type="Button" parent="UI/DiaLog/BatchSellPopup/VBox/HBox"]
layout_mode = 2
size_flags_horizontal = 3
theme_override_font_sizes/font_size = 30
text = "取消"
[node name="AddProductToStorePopup" type="PanelContainer" parent="UI/DiaLog"]
visible = false
offset_left = 426.0
offset_top = 59.0
offset_right = 1026.0
offset_bottom = 559.0
theme_override_styles/panel = SubResource("StyleBoxFlat_t4s8j")
script = ExtResource("46_8d602")
[node name="VBox" type="VBoxContainer" parent="UI/DiaLog/AddProductToStorePopup"]
layout_mode = 2
[node name="Title" type="Label" parent="UI/DiaLog/AddProductToStorePopup/VBox"]
layout_mode = 2
theme_override_colors/font_shadow_color = Color(0, 0, 0, 1)
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/shadow_offset_x = 3
theme_override_constants/shadow_offset_y = 3
theme_override_constants/outline_size = 20
theme_override_constants/shadow_outline_size = 20
theme_override_font_sizes/font_size = 40
text = "弹窗标题"
horizontal_alignment = 1
vertical_alignment = 1
[node name="Contents" type="Label" parent="UI/DiaLog/AddProductToStorePopup/VBox"]
layout_mode = 2
theme_override_colors/font_color = Color(0.762404, 0.762404, 0.762404, 1)
theme_override_colors/font_shadow_color = Color(0, 0, 0, 1)
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/shadow_offset_x = 3
theme_override_constants/shadow_offset_y = 3
theme_override_constants/outline_size = 20
theme_override_constants/shadow_outline_size = 20
theme_override_font_sizes/font_size = 24
text = "弹窗内容"
horizontal_alignment = 1
vertical_alignment = 1
[node name="SellNum" type="Label" parent="UI/DiaLog/AddProductToStorePopup/VBox"]
layout_mode = 2
theme_override_colors/font_shadow_color = Color(0, 0, 0, 1)
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/shadow_offset_x = 3
theme_override_constants/shadow_offset_y = 3
theme_override_constants/outline_size = 20
theme_override_constants/shadow_outline_size = 20
theme_override_font_sizes/font_size = 24
text = "请选择售卖的数量"
horizontal_alignment = 1
vertical_alignment = 1
[node name="SellNumInput" type="LineEdit" parent="UI/DiaLog/AddProductToStorePopup/VBox"]
layout_mode = 2
theme_override_font_sizes/font_size = 30
[node name="SellPrice" type="Label" parent="UI/DiaLog/AddProductToStorePopup/VBox"]
layout_mode = 2
theme_override_colors/font_shadow_color = Color(0, 0, 0, 1)
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/shadow_offset_x = 3
theme_override_constants/shadow_offset_y = 3
theme_override_constants/outline_size = 20
theme_override_constants/shadow_outline_size = 20
theme_override_font_sizes/font_size = 24
text = "请选择售卖的价格"
horizontal_alignment = 1
vertical_alignment = 1
[node name="SellPriceInput" type="LineEdit" parent="UI/DiaLog/AddProductToStorePopup/VBox"]
layout_mode = 2
theme_override_font_sizes/font_size = 30
[node name="HBox" type="HBoxContainer" parent="UI/DiaLog/AddProductToStorePopup/VBox"]
layout_mode = 2
[node name="SureButton" type="Button" parent="UI/DiaLog/AddProductToStorePopup/VBox/HBox"]
layout_mode = 2
size_flags_horizontal = 3
theme_override_font_sizes/font_size = 30
text = "确定"
[node name="CancelButton" type="Button" parent="UI/DiaLog/AddProductToStorePopup/VBox/HBox"]
layout_mode = 2
size_flags_horizontal = 3
theme_override_font_sizes/font_size = 30
text = "取消"
[node name="BackgroundUI" type="CanvasLayer" parent="."] [node name="BackgroundUI" type="CanvasLayer" parent="."]
layer = -1 layer = -1
@@ -2991,7 +3354,7 @@ autowrap_mode = 2
horizontal_alignment = 1 horizontal_alignment = 1
vertical_alignment = 1 vertical_alignment = 1
[node name="Decoration1" type="Button" parent="Decoration"] [node name="PlayerStore" type="Button" parent="Decoration"]
self_modulate = Color(1, 1, 1, 0) self_modulate = Color(1, 1, 1, 0)
custom_minimum_size = Vector2(100, 100) custom_minimum_size = Vector2(100, 100)
offset_left = 122.0 offset_left = 122.0
@@ -3000,18 +3363,17 @@ offset_right = 386.0
offset_bottom = 156.0 offset_bottom = 156.0
scale = Vector2(0.4, 0.4) scale = Vector2(0.4, 0.4)
[node name="GrassGroundImage" type="Sprite2D" parent="Decoration/Decoration1"] [node name="GrassGroundImage" type="Sprite2D" parent="Decoration/PlayerStore"]
position = Vector2(132, 134) position = Vector2(132, 134)
scale = Vector2(1.4, 1.4) scale = Vector2(1.4, 1.4)
texture = ExtResource("48_2i8fe") texture = ExtResource("48_2i8fe")
[node name="Image" type="Sprite2D" parent="Decoration/Decoration1"] [node name="Image" type="Sprite2D" parent="Decoration/PlayerStore"]
position = Vector2(132, 48) position = Vector2(140, 57.5)
scale = Vector2(1.2, 1.2) scale = Vector2(1.5, 1.5)
texture = ExtResource("49_xjiif") texture = ExtResource("54_06tja")
[node name="Name" type="RichTextLabel" parent="Decoration/Decoration1"] [node name="Name" type="RichTextLabel" parent="Decoration/PlayerStore"]
visible = false
layout_mode = 0 layout_mode = 0
offset_left = -65.0 offset_left = -65.0
offset_top = -145.0 offset_top = -145.0
@@ -3023,11 +3385,11 @@ theme_override_font_sizes/mono_font_size = 40
theme_override_font_sizes/normal_font_size = 40 theme_override_font_sizes/normal_font_size = 40
theme_override_font_sizes/bold_font_size = 40 theme_override_font_sizes/bold_font_size = 40
bbcode_enabled = true bbcode_enabled = true
text = "稻草人" text = "小卖部"
horizontal_alignment = 1 horizontal_alignment = 1
vertical_alignment = 1 vertical_alignment = 1
[node name="Decoration2" type="Button" parent="Decoration"] [node name="SeedStore" type="Button" parent="Decoration"]
self_modulate = Color(1, 1, 1, 0) self_modulate = Color(1, 1, 1, 0)
custom_minimum_size = Vector2(100, 100) custom_minimum_size = Vector2(100, 100)
offset_left = 244.0 offset_left = 244.0
@@ -3036,18 +3398,17 @@ offset_right = 508.0
offset_bottom = 156.0 offset_bottom = 156.0
scale = Vector2(0.4, 0.4) scale = Vector2(0.4, 0.4)
[node name="GrassGroundImage" type="Sprite2D" parent="Decoration/Decoration2"] [node name="GrassGroundImage" type="Sprite2D" parent="Decoration/SeedStore"]
position = Vector2(132, 134) position = Vector2(132, 134)
scale = Vector2(1.4, 1.4) scale = Vector2(1.4, 1.4)
texture = ExtResource("48_2i8fe") texture = ExtResource("48_2i8fe")
[node name="Image" type="Sprite2D" parent="Decoration/Decoration2"] [node name="Image" type="Sprite2D" parent="Decoration/SeedStore"]
position = Vector2(132, 48) position = Vector2(132, 48)
scale = Vector2(1.2, 1.2) scale = Vector2(1.5, 1.5)
texture = ExtResource("50_sqnmr") texture = ExtResource("55_g4i0f")
[node name="Name" type="RichTextLabel" parent="Decoration/Decoration2"] [node name="Name" type="RichTextLabel" parent="Decoration/SeedStore"]
visible = false
layout_mode = 0 layout_mode = 0
offset_left = -65.0 offset_left = -65.0
offset_top = -145.0 offset_top = -145.0
@@ -3059,11 +3420,11 @@ theme_override_font_sizes/mono_font_size = 40
theme_override_font_sizes/normal_font_size = 40 theme_override_font_sizes/normal_font_size = 40
theme_override_font_sizes/bold_font_size = 40 theme_override_font_sizes/bold_font_size = 40
bbcode_enabled = true bbcode_enabled = true
text = "稻草人" text = "种子商店"
horizontal_alignment = 1 horizontal_alignment = 1
vertical_alignment = 1 vertical_alignment = 1
[node name="Decoration3" type="Button" parent="Decoration"] [node name="ItemStore" type="Button" parent="Decoration"]
self_modulate = Color(1, 1, 1, 0) self_modulate = Color(1, 1, 1, 0)
custom_minimum_size = Vector2(100, 100) custom_minimum_size = Vector2(100, 100)
offset_left = 366.0 offset_left = 366.0
@@ -3072,18 +3433,17 @@ offset_right = 630.0
offset_bottom = 156.0 offset_bottom = 156.0
scale = Vector2(0.4, 0.4) scale = Vector2(0.4, 0.4)
[node name="GrassGroundImage" type="Sprite2D" parent="Decoration/Decoration3"] [node name="GrassGroundImage" type="Sprite2D" parent="Decoration/ItemStore"]
position = Vector2(132, 134) position = Vector2(132, 134)
scale = Vector2(1.4, 1.4) scale = Vector2(1.4, 1.4)
texture = ExtResource("48_2i8fe") texture = ExtResource("48_2i8fe")
[node name="Image" type="Sprite2D" parent="Decoration/Decoration3"] [node name="Image" type="Sprite2D" parent="Decoration/ItemStore"]
position = Vector2(132, 48) position = Vector2(132, 48)
scale = Vector2(1.2, 1.2) scale = Vector2(1.5, 1.5)
texture = ExtResource("51_2i8fe") texture = ExtResource("56_rlmnt")
[node name="Name" type="RichTextLabel" parent="Decoration/Decoration3"] [node name="Name" type="RichTextLabel" parent="Decoration/ItemStore"]
visible = false
layout_mode = 0 layout_mode = 0
offset_left = -65.0 offset_left = -65.0
offset_top = -145.0 offset_top = -145.0
@@ -3095,11 +3455,11 @@ theme_override_font_sizes/mono_font_size = 40
theme_override_font_sizes/normal_font_size = 40 theme_override_font_sizes/normal_font_size = 40
theme_override_font_sizes/bold_font_size = 40 theme_override_font_sizes/bold_font_size = 40
bbcode_enabled = true bbcode_enabled = true
text = "稻草人" text = "道具商店"
horizontal_alignment = 1 horizontal_alignment = 1
vertical_alignment = 1 vertical_alignment = 1
[node name="Decoration4" type="Button" parent="Decoration"] [node name="PetStore" type="Button" parent="Decoration"]
self_modulate = Color(1, 1, 1, 0) self_modulate = Color(1, 1, 1, 0)
custom_minimum_size = Vector2(100, 100) custom_minimum_size = Vector2(100, 100)
offset_left = 488.0 offset_left = 488.0
@@ -3108,18 +3468,17 @@ offset_right = 752.0
offset_bottom = 156.0 offset_bottom = 156.0
scale = Vector2(0.4, 0.4) scale = Vector2(0.4, 0.4)
[node name="GrassGroundImage" type="Sprite2D" parent="Decoration/Decoration4"] [node name="GrassGroundImage" type="Sprite2D" parent="Decoration/PetStore"]
position = Vector2(132, 134) position = Vector2(132, 134)
scale = Vector2(1.4, 1.4) scale = Vector2(1.4, 1.4)
texture = ExtResource("48_2i8fe") texture = ExtResource("48_2i8fe")
[node name="Image" type="Sprite2D" parent="Decoration/Decoration4"] [node name="Image" type="Sprite2D" parent="Decoration/PetStore"]
position = Vector2(132, 48) position = Vector2(132, 48)
scale = Vector2(1.2, 1.2) scale = Vector2(1.5, 1.5)
texture = ExtResource("50_sqnmr") texture = ExtResource("57_rlmnt")
[node name="Name" type="RichTextLabel" parent="Decoration/Decoration4"] [node name="Name" type="RichTextLabel" parent="Decoration/PetStore"]
visible = false
layout_mode = 0 layout_mode = 0
offset_left = -65.0 offset_left = -65.0
offset_top = -145.0 offset_top = -145.0
@@ -3131,7 +3490,7 @@ theme_override_font_sizes/mono_font_size = 40
theme_override_font_sizes/normal_font_size = 40 theme_override_font_sizes/normal_font_size = 40
theme_override_font_sizes/bold_font_size = 40 theme_override_font_sizes/bold_font_size = 40
bbcode_enabled = true bbcode_enabled = true
text = "稻草人" text = "宠物商店"
horizontal_alignment = 1 horizontal_alignment = 1
vertical_alignment = 1 vertical_alignment = 1
@@ -4344,9 +4703,11 @@ horizontal_alignment = 1
vertical_alignment = 1 vertical_alignment = 1
[node name="WeatherSystem" type="Node2D" parent="."] [node name="WeatherSystem" type="Node2D" parent="."]
script = ExtResource("62_uyv6e")
[node name="CherryBlossomRain" type="Node2D" parent="WeatherSystem"] [node name="CherryBlossomRain" type="Node2D" parent="WeatherSystem"]
visible = false visible = false
z_index = 10
position = Vector2(934, -469) position = Vector2(934, -469)
[node name="CherryBlossomRain1" type="GPUParticles2D" parent="WeatherSystem/CherryBlossomRain"] [node name="CherryBlossomRain1" type="GPUParticles2D" parent="WeatherSystem/CherryBlossomRain"]
@@ -4383,6 +4744,8 @@ visibility_rect = Rect2(-900, 0, 2300, 2000)
process_material = SubResource("ParticleProcessMaterial_tdq2s") process_material = SubResource("ParticleProcessMaterial_tdq2s")
[node name="GardeniaRain" type="Node2D" parent="WeatherSystem"] [node name="GardeniaRain" type="Node2D" parent="WeatherSystem"]
visible = false
z_index = 10
position = Vector2(759, -370) position = Vector2(759, -370)
[node name="WillowLeafRain1" type="GPUParticles2D" parent="WeatherSystem/GardeniaRain"] [node name="WillowLeafRain1" type="GPUParticles2D" parent="WeatherSystem/GardeniaRain"]
@@ -4417,13 +4780,20 @@ process_material = SubResource("ParticleProcessMaterial_dygjy")
[node name="WillowLeafRain" type="Node2D" parent="WeatherSystem"] [node name="WillowLeafRain" type="Node2D" parent="WeatherSystem"]
visible = false visible = false
z_index = 10
position = Vector2(882, -469) position = Vector2(882, -469)
[node name="WillowLeafRain1" parent="WeatherSystem/WillowLeafRain" instance=ExtResource("53_nf3jg")] [node name="WillowLeafRain1" type="GPUParticles2D" parent="WeatherSystem/WillowLeafRain"]
visible = false self_modulate = Color(0.7, 0.7, 0.7, 1)
z_index = 10
amount = 50
texture = ExtResource("69_uyv6e")
lifetime = 20.0
preprocess = 10.0
visibility_rect = Rect2(-900, 0, 2300, 2000)
process_material = SubResource("ParticleProcessMaterial_6fhdl")
[node name="WillowLeafRain2" type="GPUParticles2D" parent="WeatherSystem/WillowLeafRain"] [node name="WillowLeafRain2" type="GPUParticles2D" parent="WeatherSystem/WillowLeafRain"]
visible = false
self_modulate = Color(0.7, 0.7, 0.7, 1) self_modulate = Color(0.7, 0.7, 0.7, 1)
z_index = 10 z_index = 10
amount = 50 amount = 50
@@ -4457,6 +4827,7 @@ process_material = SubResource("ParticleProcessMaterial_jiccn")
[node name="Snow" type="GPUParticles2D" parent="WeatherSystem"] [node name="Snow" type="GPUParticles2D" parent="WeatherSystem"]
visible = false visible = false
z_index = 10
position = Vector2(16, -520) position = Vector2(16, -520)
amount = 300 amount = 300
texture = ExtResource("53_4ka7t") texture = ExtResource("53_4ka7t")
@@ -4478,6 +4849,7 @@ process_material = SubResource("ParticleProcessMaterial_nf3jg")
[connection signal="pressed" from="UI/GUI/FarmVBox/AddNewGroundButton" to="." method="_on_add_new_ground_button_pressed"] [connection signal="pressed" from="UI/GUI/FarmVBox/AddNewGroundButton" to="." method="_on_add_new_ground_button_pressed"]
[connection signal="pressed" from="UI/GUI/VisitVBox/LikeButton" to="." method="_on_like_button_pressed"] [connection signal="pressed" from="UI/GUI/VisitVBox/LikeButton" to="." method="_on_like_button_pressed"]
[connection signal="pressed" from="UI/GUI/VisitVBox/ReturnMyFarmButton" to="." method="_on_return_my_farm_button_pressed"] [connection signal="pressed" from="UI/GUI/VisitVBox/ReturnMyFarmButton" to="." method="_on_return_my_farm_button_pressed"]
[connection signal="pressed" from="UI/GUI/OtherVBox/MyStoreButton" to="." method="_on_my_store_button_pressed"]
[connection signal="pressed" from="UI/GUI/OtherVBox/AccountSettingButton" to="." method="_on_account_setting_button_pressed"] [connection signal="pressed" from="UI/GUI/OtherVBox/AccountSettingButton" to="." method="_on_account_setting_button_pressed"]
[connection signal="pressed" from="UI/GUI/OtherVBox/OnlineGiftButton" to="." method="_on_online_gift_button_pressed"] [connection signal="pressed" from="UI/GUI/OtherVBox/OnlineGiftButton" to="." method="_on_online_gift_button_pressed"]
[connection signal="pressed" from="UI/GUI/OtherVBox/NewPlayerGiftButton" to="." method="_on_new_player_gift_button_pressed"] [connection signal="pressed" from="UI/GUI/OtherVBox/NewPlayerGiftButton" to="." method="_on_new_player_gift_button_pressed"]
@@ -4494,6 +4866,10 @@ process_material = SubResource("ParticleProcessMaterial_nf3jg")
[connection signal="pressed" from="UI/GUI/OtherVBox/ScareCrowButton" to="." method="_on_my_pet_button_pressed"] [connection signal="pressed" from="UI/GUI/OtherVBox/ScareCrowButton" to="." method="_on_my_pet_button_pressed"]
[connection signal="pressed" from="UI/SmallPanel/DebugPanel/QuitButton" to="UI/SmallPanel/DebugPanel" method="_on_quit_button_pressed"] [connection signal="pressed" from="UI/SmallPanel/DebugPanel/QuitButton" to="UI/SmallPanel/DebugPanel" method="_on_quit_button_pressed"]
[connection signal="pressed" from="Decoration/ScareCrow" to="." method="_on_scare_crow_pressed"] [connection signal="pressed" from="Decoration/ScareCrow" to="." method="_on_scare_crow_pressed"]
[connection signal="pressed" from="Decoration/PlayerStore" to="." method="_on_player_store_pressed"]
[connection signal="pressed" from="Decoration/SeedStore" to="." method="_on_seed_store_pressed"]
[connection signal="pressed" from="Decoration/ItemStore" to="." method="_on_item_store_pressed"]
[connection signal="pressed" from="Decoration/PetStore" to="." method="_on_pet_store_pressed"]
[connection signal="pressed" from="Decoration/WisdomTree" to="." method="_on_wisdom_tree_pressed"] [connection signal="pressed" from="Decoration/WisdomTree" to="." method="_on_wisdom_tree_pressed"]
[connection signal="pressed" from="Decoration4/ScareCrow" to="." method="_on_scare_crow_pressed"] [connection signal="pressed" from="Decoration4/ScareCrow" to="." method="_on_scare_crow_pressed"]
[connection signal="pressed" from="Decoration4/WisdomTree" to="." method="_on_wisdom_tree_pressed"] [connection signal="pressed" from="Decoration4/WisdomTree" to="." method="_on_wisdom_tree_pressed"]

View File

@@ -239,6 +239,18 @@ func _on_data_received(data):
login_panel._on_verification_code_response(success, message) login_panel._on_verification_code_response(success, message)
return return
if message_type == "forget_password_verification_code_response":
var success = data.get("success", false)
var message = data.get("message", "")
login_panel._on_verification_code_response(success, message)
return
if message_type == "reset_password_response":
var success = data.get("success", false)
var message = data.get("message", "")
login_panel._on_forget_password_response_received(success, message)
return
if message_type == "verify_code_response": if message_type == "verify_code_response":
var success = data.get("success", false) var success = data.get("success", false)
var message = data.get("message", "") var message = data.get("message", "")
@@ -428,6 +440,88 @@ func _on_data_received(data):
else: else:
Toast.show(message, Color.RED) Toast.show(message, Color.RED)
# 出售作物响应
elif action_type == "sell_crop":
if success:
main_game.money = updated_data["money"]
main_game.crop_warehouse = updated_data["作物仓库"]
main_game.experience = updated_data.get("experience", main_game.experience)
main_game.level = updated_data.get("level", main_game.level)
main_game._update_ui()
main_game.crop_warehouse_panel.update_crop_warehouse_ui()
Toast.show(message, Color.GREEN)
else:
Toast.show(message, Color.RED)
# 添加商品到小卖部响应
elif action_type == "add_product_to_store":
if success:
main_game.login_data["玩家小卖部"] = updated_data["玩家小卖部"]
main_game.crop_warehouse = updated_data["作物仓库"]
# 更新UI
main_game.crop_warehouse_panel.update_crop_warehouse_ui()
var player_store_panel = get_node_or_null("/root/main/UI/BigPanel/PlayerStorePanel")
if player_store_panel and player_store_panel.has_method("update_player_store_ui"):
player_store_panel.update_player_store_ui()
Toast.show(message, Color.GREEN)
else:
Toast.show(message, Color.RED)
# 下架小卖部商品响应
elif action_type == "remove_store_product":
if success:
main_game.login_data["玩家小卖部"] = updated_data["玩家小卖部"]
main_game.crop_warehouse = updated_data["作物仓库"]
# 更新UI
main_game.crop_warehouse_panel.update_crop_warehouse_ui()
var player_store_panel = get_node_or_null("/root/main/UI/BigPanel/PlayerStorePanel")
if player_store_panel and player_store_panel.has_method("update_player_store_ui"):
player_store_panel.update_player_store_ui()
Toast.show(message, Color.GREEN)
else:
Toast.show(message, Color.RED)
# 购买小卖部商品响应
elif action_type == "buy_store_product":
if success:
main_game.money = updated_data["money"]
main_game.crop_warehouse = updated_data["作物仓库"]
# 更新UI
main_game._update_ui()
main_game.crop_warehouse_panel.update_crop_warehouse_ui()
# 如果在访问模式下,刷新被访问玩家的小卖部(通过重新请求访问)
if main_game.is_visiting_mode:
var visited_username = main_game.visited_player_data.get("username", "")
if visited_username != "":
# 重新访问玩家以刷新数据
sendVisitPlayer(visited_username)
Toast.show(message, Color.GREEN)
else:
Toast.show(message, Color.RED)
# 购买小卖部格子响应
elif action_type == "buy_store_booth":
if success:
main_game.money = updated_data["money"]
main_game.login_data["小卖部格子数"] = updated_data["小卖部格子数"]
# 更新UI
main_game._update_ui()
var player_store_panel = get_node_or_null("/root/main/UI/BigPanel/PlayerStorePanel")
if player_store_panel and player_store_panel.has_method("update_player_store_ui"):
player_store_panel.update_player_store_ui()
Toast.show(message, Color.GREEN)
else:
Toast.show(message, Color.RED)
return return
# 游戏功能响应消息 # 游戏功能响应消息
@@ -502,6 +596,12 @@ func _on_data_received(data):
elif message_type == "wisdom_tree_config_response": elif message_type == "wisdom_tree_config_response":
main_game._handle_wisdom_tree_config_response(data) main_game._handle_wisdom_tree_config_response(data)
# 天气变更消息
elif message_type == "weather_change":
var weather_type = data.get("weather_type", "clear")
var weather_name = data.get("weather_name", "晴天")
main_game._handle_weather_change(weather_type, weather_name)
# ============================= 客户端与服务端通信核心 ===================================== # ============================= 客户端与服务端通信核心 =====================================
@@ -771,6 +871,32 @@ func sendVerificationCodeRequest(qq_number):
}) })
return true return true
#发送忘记密码验证码请求
func sendForgetPasswordVerificationCode(qq_number):
if not client.is_client_connected():
return false
client.send_data({
"type": "request_forget_password_verification_code",
"qq_number": qq_number,
"timestamp": Time.get_unix_time_from_system()
})
return true
#发送忘记密码请求
func sendForgetPasswordRequest(username, new_password, verification_code):
if not client.is_client_connected():
return false
client.send_data({
"type": "reset_password",
"username": username,
"new_password": new_password,
"verification_code": verification_code,
"timestamp": Time.get_unix_time_from_system()
})
return true
#发送验证码验证 #发送验证码验证
func sendVerifyCode(qq_number, code): func sendVerifyCode(qq_number, code):
if not client.is_client_connected(): if not client.is_client_connected():

View File

@@ -1,17 +1,26 @@
[gd_scene load_steps=2 format=3 uid="uid://smypui0vyso5"] [gd_scene load_steps=3 format=3 uid="uid://smypui0vyso5"]
[ext_resource type="Script" uid="uid://c0jfbtkh0mj5b" path="res://Script/BigPanel/DailyCheckInPanel.gd" id="1_fj7a7"] [ext_resource type="Script" uid="uid://c0jfbtkh0mj5b" path="res://Script/BigPanel/DailyCheckInPanel.gd" id="1_fj7a7"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_217t6"]
border_width_left = 15
border_width_top = 15
border_width_right = 15
border_width_bottom = 15
corner_detail = 20
[node name="DailyCheckInPanel" type="Panel"] [node name="DailyCheckInPanel" type="Panel"]
offset_right = 600.0 offset_left = 441.0
offset_right = 1041.0
offset_bottom = 720.0 offset_bottom = 720.0
theme_override_styles/panel = SubResource("StyleBoxFlat_217t6")
script = ExtResource("1_fj7a7") script = ExtResource("1_fj7a7")
[node name="Title" type="Label" parent="."] [node name="Title" type="Label" parent="."]
layout_mode = 0 layout_mode = 0
offset_top = -1.0 offset_top = 20.0
offset_right = 600.0 offset_right = 600.0
offset_bottom = 41.0 offset_bottom = 69.0
theme_override_colors/font_color = Color(0.624759, 0.8051, 0.828302, 1) theme_override_colors/font_color = Color(0.624759, 0.8051, 0.828302, 1)
theme_override_colors/font_shadow_color = Color(0, 0, 0, 1) theme_override_colors/font_shadow_color = Color(0, 0, 0, 1)
theme_override_colors/font_outline_color = Color(0, 0, 0, 1) theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
@@ -37,10 +46,10 @@ vertical_alignment = 1
[node name="QuitButton" type="Button" parent="."] [node name="QuitButton" type="Button" parent="."]
custom_minimum_size = Vector2(57, 57) custom_minimum_size = Vector2(57, 57)
layout_mode = 0 layout_mode = 0
offset_left = 543.0 offset_left = 520.0
offset_top = 1.0 offset_top = 22.0
offset_right = 600.0 offset_right = 577.0
offset_bottom = 58.0 offset_bottom = 79.0
theme_override_font_sizes/font_size = 35 theme_override_font_sizes/font_size = 35
text = "X" text = "X"
@@ -48,16 +57,16 @@ text = "X"
modulate = Color(1, 1, 0.52549, 1) modulate = Color(1, 1, 0.52549, 1)
custom_minimum_size = Vector2(150, 70) custom_minimum_size = Vector2(150, 70)
layout_mode = 0 layout_mode = 0
offset_left = 243.0 offset_left = 239.0
offset_top = 649.0 offset_top = 630.0
offset_right = 393.0 offset_right = 389.0
offset_bottom = 719.0 offset_bottom = 700.0
theme_override_font_sizes/font_size = 35 theme_override_font_sizes/font_size = 35
text = "签到" text = "签到"
[node name="Scroll" type="ScrollContainer" parent="."] [node name="Scroll" type="ScrollContainer" parent="."]
layout_mode = 0 layout_mode = 0
offset_top = 58.0 offset_top = 77.0
offset_right = 600.0 offset_right = 600.0
offset_bottom = 419.0 offset_bottom = 419.0

View File

@@ -1,18 +1,26 @@
[gd_scene load_steps=2 format=3 uid="uid://cbhitturvihqj"] [gd_scene load_steps=3 format=3 uid="uid://cbhitturvihqj"]
[ext_resource type="Script" uid="uid://cka0r4g8tbf0" path="res://Script/BigPanel/LoginPanel.gd" id="1_xnwaq"] [ext_resource type="Script" uid="uid://cka0r4g8tbf0" path="res://Script/BigPanel/LoginPanel.gd" id="1_xnwaq"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_n8m38"]
border_width_left = 15
border_width_top = 15
border_width_right = 15
border_width_bottom = 15
[node name="LoginPanel" type="PanelContainer"] [node name="LoginPanel" type="PanelContainer"]
offset_left = 343.0 offset_left = 343.0
offset_top = 36.0 offset_top = 5.0
offset_right = 1071.0 offset_right = 1093.0
offset_bottom = 667.0 offset_bottom = 795.0
scale = Vector2(0.9, 0.9)
theme_override_styles/panel = SubResource("StyleBoxFlat_n8m38")
script = ExtResource("1_xnwaq") script = ExtResource("1_xnwaq")
[node name="VBox" type="VBoxContainer" parent="."] [node name="LoginVBox" type="VBoxContainer" parent="."]
layout_mode = 2 layout_mode = 2
[node name="Title" type="Label" parent="VBox"] [node name="Title" type="Label" parent="LoginVBox"]
modulate = Color(1, 1, 0.537255, 1) modulate = Color(1, 1, 0.537255, 1)
layout_mode = 2 layout_mode = 2
theme_override_colors/font_shadow_color = Color(0, 0, 0, 1) theme_override_colors/font_shadow_color = Color(0, 0, 0, 1)
@@ -22,153 +30,59 @@ theme_override_constants/shadow_offset_y = 5
theme_override_constants/outline_size = 15 theme_override_constants/outline_size = 15
theme_override_constants/shadow_outline_size = 15 theme_override_constants/shadow_outline_size = 15
theme_override_font_sizes/font_size = 40 theme_override_font_sizes/font_size = 40
text = "登录/注册面板" text = "登录面板"
horizontal_alignment = 1 horizontal_alignment = 1
vertical_alignment = 1 vertical_alignment = 1
[node name="UserName" type="HBoxContainer" parent="VBox"] [node name="UserName" type="HBoxContainer" parent="LoginVBox"]
layout_mode = 2 layout_mode = 2
[node name="Label" type="Label" parent="VBox/UserName"] [node name="Label" type="Label" parent="LoginVBox/UserName"]
layout_mode = 2 layout_mode = 2
theme_override_font_sizes/font_size = 30 theme_override_font_sizes/font_size = 30
text = "账号" text = "账号"
horizontal_alignment = 1 horizontal_alignment = 1
vertical_alignment = 1 vertical_alignment = 1
[node name="username_input" type="LineEdit" parent="VBox/UserName"] [node name="username_input" type="LineEdit" parent="LoginVBox/UserName"]
layout_mode = 2 layout_mode = 2
size_flags_horizontal = 3 size_flags_horizontal = 3
theme_override_font_sizes/font_size = 30 theme_override_font_sizes/font_size = 30
placeholder_text = "请输入QQ号" placeholder_text = "请输入QQ号"
metadata/_edit_use_anchors_ = true metadata/_edit_use_anchors_ = true
[node name="Password1" type="HBoxContainer" parent="VBox"] [node name="Password" type="HBoxContainer" parent="LoginVBox"]
layout_mode = 2 layout_mode = 2
[node name="Label2" type="Label" parent="VBox/Password1"] [node name="Label2" type="Label" parent="LoginVBox/Password"]
layout_mode = 2 layout_mode = 2
theme_override_font_sizes/font_size = 30 theme_override_font_sizes/font_size = 30
text = "密码" text = "密码"
horizontal_alignment = 1 horizontal_alignment = 1
vertical_alignment = 1 vertical_alignment = 1
[node name="password_input" type="LineEdit" parent="VBox/Password1"] [node name="password_input" type="LineEdit" parent="LoginVBox/Password"]
layout_mode = 2 layout_mode = 2
size_flags_horizontal = 3 size_flags_horizontal = 3
theme_override_font_sizes/font_size = 30 theme_override_font_sizes/font_size = 30
placeholder_text = "请输入密码" placeholder_text = "请输入密码"
[node name="Password2" type="HBoxContainer" parent="VBox"] [node name="LoginButton" type="Button" parent="LoginVBox"]
layout_mode = 2 layout_mode = 2
[node name="Label2" type="Label" parent="VBox/Password2"]
layout_mode = 2
theme_override_font_sizes/font_size = 30
text = "确认密码"
horizontal_alignment = 1
vertical_alignment = 1
[node name="password_input2" type="LineEdit" parent="VBox/Password2"]
layout_mode = 2
size_flags_horizontal = 3
theme_override_font_sizes/font_size = 30
placeholder_text = "请再次输入密码"
[node name="VerificationCode" type="HBoxContainer" parent="VBox"]
layout_mode = 2
[node name="Label" type="Label" parent="VBox/VerificationCode"]
layout_mode = 2
theme_override_font_sizes/font_size = 30
text = "验证码"
horizontal_alignment = 1
vertical_alignment = 1
[node name="verificationcode_input" type="LineEdit" parent="VBox/VerificationCode"]
layout_mode = 2
size_flags_horizontal = 3
theme_override_font_sizes/font_size = 30
placeholder_text = "请输入您的QQ邮箱收到的验证码"
metadata/_edit_use_anchors_ = true
[node name="SendButton" type="Button" parent="VBox/VerificationCode"]
layout_mode = 2
theme_override_font_sizes/font_size = 30
text = "发送验证码"
[node name="PlayerName" type="HBoxContainer" parent="VBox"]
layout_mode = 2
[node name="Label2" type="Label" parent="VBox/PlayerName"]
layout_mode = 2
theme_override_font_sizes/font_size = 30
text = "玩家昵称"
horizontal_alignment = 1
vertical_alignment = 1
[node name="playername_input" type="LineEdit" parent="VBox/PlayerName"]
layout_mode = 2
size_flags_horizontal = 3
theme_override_font_sizes/font_size = 30
placeholder_text = "请输入您的玩家昵称"
[node name="FarmName" type="HBoxContainer" parent="VBox"]
layout_mode = 2
[node name="Label" type="Label" parent="VBox/FarmName"]
layout_mode = 2
theme_override_font_sizes/font_size = 30
text = "农场名称"
horizontal_alignment = 1
vertical_alignment = 1
[node name="farmname_input" type="LineEdit" parent="VBox/FarmName"]
layout_mode = 2
size_flags_horizontal = 3
theme_override_font_sizes/font_size = 30
placeholder_text = "请输入您的农场名称"
metadata/_edit_use_anchors_ = true
[node name="LoginRegister" type="HBoxContainer" parent="VBox"]
layout_mode = 2
[node name="login_button" type="Button" parent="VBox/LoginRegister"]
layout_mode = 2
size_flags_horizontal = 3
theme_override_font_sizes/font_size = 30 theme_override_font_sizes/font_size = 30
text = "登录" text = "登录"
[node name="register_button" type="Button" parent="VBox/LoginRegister"] [node name="RegisterButton" type="Button" parent="LoginVBox"]
layout_mode = 2 layout_mode = 2
size_flags_horizontal = 3
theme_override_font_sizes/font_size = 30 theme_override_font_sizes/font_size = 30
text = "注册" text = "注册"
[node name="Password3" type="HBoxContainer" parent="VBox"] [node name="ForgetPasswdButton" type="Button" parent="LoginVBox"]
visible = false
layout_mode = 2 layout_mode = 2
theme_override_font_sizes/font_size = 30
text = "忘记密码"
[node name="login_button" type="Button" parent="VBox/Password3"] [node name="Note" type="Label" parent="LoginVBox"]
layout_mode = 2
size_flags_horizontal = 3
theme_override_font_sizes/font_size = 20
text = "发送验证码"
[node name="Label2" type="Label" parent="VBox/Password3"]
layout_mode = 2
theme_override_font_sizes/font_size = 20
text = "找回密码"
horizontal_alignment = 1
vertical_alignment = 1
[node name="password_input2" type="LineEdit" parent="VBox/Password3"]
layout_mode = 2
size_flags_horizontal = 3
theme_override_font_sizes/font_size = 20
placeholder_text = "请输入QQ邮箱验证码"
[node name="Note" type="Label" parent="VBox"]
modulate = Color(1, 0.552941, 1, 1) modulate = Color(1, 0.552941, 1, 1)
layout_mode = 2 layout_mode = 2
theme_override_font_sizes/font_size = 30 theme_override_font_sizes/font_size = 30
@@ -179,7 +93,246 @@ text = "注意:首次游玩游戏需要注册账号,
horizontal_alignment = 1 horizontal_alignment = 1
vertical_alignment = 1 vertical_alignment = 1
[node name="status_label" type="Label" parent="VBox"] [node name="status_label" type="Label" parent="LoginVBox"]
layout_mode = 2
theme_override_font_sizes/font_size = 30
text = "连接状态"
horizontal_alignment = 1
[node name="RegisterVbox" type="VBoxContainer" parent="."]
visible = false
layout_mode = 2
[node name="Title" type="Label" parent="RegisterVbox"]
modulate = Color(1, 1, 0.537255, 1)
layout_mode = 2
theme_override_colors/font_shadow_color = Color(0, 0, 0, 1)
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/shadow_offset_x = 5
theme_override_constants/shadow_offset_y = 5
theme_override_constants/outline_size = 15
theme_override_constants/shadow_outline_size = 15
theme_override_font_sizes/font_size = 40
text = "注册面板"
horizontal_alignment = 1
vertical_alignment = 1
[node name="RegisterUserName" type="HBoxContainer" parent="RegisterVbox"]
layout_mode = 2
[node name="Label" type="Label" parent="RegisterVbox/RegisterUserName"]
layout_mode = 2
theme_override_font_sizes/font_size = 30
text = "账号"
horizontal_alignment = 1
vertical_alignment = 1
[node name="username_input" type="LineEdit" parent="RegisterVbox/RegisterUserName"]
layout_mode = 2
size_flags_horizontal = 3
theme_override_font_sizes/font_size = 30
placeholder_text = "请输入QQ号"
metadata/_edit_use_anchors_ = true
[node name="Password1" type="HBoxContainer" parent="RegisterVbox"]
layout_mode = 2
[node name="Label2" type="Label" parent="RegisterVbox/Password1"]
layout_mode = 2
theme_override_font_sizes/font_size = 30
text = "密码"
horizontal_alignment = 1
vertical_alignment = 1
[node name="password_input" type="LineEdit" parent="RegisterVbox/Password1"]
layout_mode = 2
size_flags_horizontal = 3
theme_override_font_sizes/font_size = 30
placeholder_text = "请输入密码"
[node name="Password2" type="HBoxContainer" parent="RegisterVbox"]
layout_mode = 2
[node name="Label2" type="Label" parent="RegisterVbox/Password2"]
layout_mode = 2
theme_override_font_sizes/font_size = 30
text = "确认密码"
horizontal_alignment = 1
vertical_alignment = 1
[node name="password_input2" type="LineEdit" parent="RegisterVbox/Password2"]
layout_mode = 2
size_flags_horizontal = 3
theme_override_font_sizes/font_size = 30
placeholder_text = "请再次输入密码"
[node name="PlayerName" type="HBoxContainer" parent="RegisterVbox"]
layout_mode = 2
[node name="Label2" type="Label" parent="RegisterVbox/PlayerName"]
layout_mode = 2
theme_override_font_sizes/font_size = 30
text = "玩家昵称"
horizontal_alignment = 1
vertical_alignment = 1
[node name="playername_input" type="LineEdit" parent="RegisterVbox/PlayerName"]
layout_mode = 2
size_flags_horizontal = 3
theme_override_font_sizes/font_size = 30
placeholder_text = "请输入您的玩家昵称"
[node name="FarmName" type="HBoxContainer" parent="RegisterVbox"]
layout_mode = 2
[node name="Label" type="Label" parent="RegisterVbox/FarmName"]
layout_mode = 2
theme_override_font_sizes/font_size = 30
text = "农场名称"
horizontal_alignment = 1
vertical_alignment = 1
[node name="farmname_input" type="LineEdit" parent="RegisterVbox/FarmName"]
layout_mode = 2
size_flags_horizontal = 3
theme_override_font_sizes/font_size = 30
placeholder_text = "请输入您的农场名称"
metadata/_edit_use_anchors_ = true
[node name="VerificationCode" type="HBoxContainer" parent="RegisterVbox"]
layout_mode = 2
[node name="Label" type="Label" parent="RegisterVbox/VerificationCode"]
layout_mode = 2
theme_override_font_sizes/font_size = 30
text = "验证码"
horizontal_alignment = 1
vertical_alignment = 1
[node name="verificationcode_input" type="LineEdit" parent="RegisterVbox/VerificationCode"]
layout_mode = 2
size_flags_horizontal = 3
theme_override_font_sizes/font_size = 30
placeholder_text = "请输入您的QQ邮箱收到的验证码"
metadata/_edit_use_anchors_ = true
[node name="SendButton" type="Button" parent="RegisterVbox/VerificationCode"]
layout_mode = 2
theme_override_font_sizes/font_size = 30
text = "发送验证码"
[node name="RegisterButton2" type="Button" parent="RegisterVbox"]
layout_mode = 2
theme_override_font_sizes/font_size = 30
text = "注册"
[node name="Note" type="Label" parent="RegisterVbox"]
modulate = Color(1, 0.552941, 1, 1)
layout_mode = 2
theme_override_font_sizes/font_size = 30
text = "注意:首次游玩游戏需要注册账号,
账号请直接输入您的QQ号系统会直接向您的QQ
邮箱发送一串验证码进行注册验证,密码请设置的复杂一
点,以免被暴力破解("
horizontal_alignment = 1
vertical_alignment = 1
[node name="status_label2" type="Label" parent="RegisterVbox"]
layout_mode = 2
theme_override_font_sizes/font_size = 30
text = "连接状态"
horizontal_alignment = 1
[node name="ForgetPasswordVbox" type="VBoxContainer" parent="."]
visible = false
layout_mode = 2
[node name="Title" type="Label" parent="ForgetPasswordVbox"]
modulate = Color(1, 1, 0.537255, 1)
layout_mode = 2
theme_override_colors/font_shadow_color = Color(0, 0, 0, 1)
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/shadow_offset_x = 5
theme_override_constants/shadow_offset_y = 5
theme_override_constants/outline_size = 15
theme_override_constants/shadow_outline_size = 15
theme_override_font_sizes/font_size = 40
text = "忘记密码"
horizontal_alignment = 1
vertical_alignment = 1
[node name="ForgetPasswordUserName" type="HBoxContainer" parent="ForgetPasswordVbox"]
layout_mode = 2
[node name="Label" type="Label" parent="ForgetPasswordVbox/ForgetPasswordUserName"]
layout_mode = 2
theme_override_font_sizes/font_size = 30
text = "账号"
horizontal_alignment = 1
vertical_alignment = 1
[node name="username_input" type="LineEdit" parent="ForgetPasswordVbox/ForgetPasswordUserName"]
layout_mode = 2
size_flags_horizontal = 3
theme_override_font_sizes/font_size = 30
placeholder_text = "请输入QQ号"
metadata/_edit_use_anchors_ = true
[node name="NewPassword" type="HBoxContainer" parent="ForgetPasswordVbox"]
layout_mode = 2
[node name="Label2" type="Label" parent="ForgetPasswordVbox/NewPassword"]
layout_mode = 2
theme_override_font_sizes/font_size = 30
text = "新密码"
horizontal_alignment = 1
vertical_alignment = 1
[node name="password_input" type="LineEdit" parent="ForgetPasswordVbox/NewPassword"]
layout_mode = 2
size_flags_horizontal = 3
theme_override_font_sizes/font_size = 30
placeholder_text = "请设置新的密码"
[node name="VerificationCode2" type="HBoxContainer" parent="ForgetPasswordVbox"]
layout_mode = 2
[node name="Label" type="Label" parent="ForgetPasswordVbox/VerificationCode2"]
layout_mode = 2
theme_override_font_sizes/font_size = 30
text = "验证码"
horizontal_alignment = 1
vertical_alignment = 1
[node name="verificationcode_input" type="LineEdit" parent="ForgetPasswordVbox/VerificationCode2"]
layout_mode = 2
size_flags_horizontal = 3
theme_override_font_sizes/font_size = 30
placeholder_text = "请输入您的QQ邮箱收到的验证码"
metadata/_edit_use_anchors_ = true
[node name="SendButton" type="Button" parent="ForgetPasswordVbox/VerificationCode2"]
layout_mode = 2
theme_override_font_sizes/font_size = 30
text = "发送验证码"
[node name="ForgetPasswordButton" type="Button" parent="ForgetPasswordVbox"]
layout_mode = 2
theme_override_font_sizes/font_size = 30
text = "确认"
[node name="Note" type="Label" parent="ForgetPasswordVbox"]
modulate = Color(1, 0.552941, 1, 1)
layout_mode = 2
theme_override_font_sizes/font_size = 30
text = "注意:首次游玩游戏需要注册账号,
账号请直接输入您的QQ号系统会直接向您的QQ
邮箱发送一串验证码进行注册验证,密码请设置的复杂一
点,以免被暴力破解("
horizontal_alignment = 1
vertical_alignment = 1
[node name="status_label3" type="Label" parent="ForgetPasswordVbox"]
layout_mode = 2 layout_mode = 2
theme_override_font_sizes/font_size = 30 theme_override_font_sizes/font_size = 30
text = "连接状态" text = "连接状态"

View File

@@ -1,17 +1,27 @@
[gd_scene load_steps=2 format=3 uid="uid://bndf1e4sgdjr6"] [gd_scene load_steps=3 format=3 uid="uid://bndf1e4sgdjr6"]
[ext_resource type="Script" uid="uid://65e0rl31fx0i" path="res://Script/BigPanel/LuckyDrawPanel.gd" id="1_dcmen"] [ext_resource type="Script" uid="uid://65e0rl31fx0i" path="res://Script/BigPanel/LuckyDrawPanel.gd" id="1_dcmen"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_ynokl"]
border_width_left = 15
border_width_top = 15
border_width_right = 15
border_width_bottom = 15
corner_detail = 20
[node name="LuckyDrawPanel" type="Panel"] [node name="LuckyDrawPanel" type="Panel"]
offset_right = 600.0 offset_left = 373.0
offset_bottom = 720.0 offset_top = 1.0
offset_right = 1045.0
offset_bottom = 721.0
theme_override_styles/panel = SubResource("StyleBoxFlat_ynokl")
script = ExtResource("1_dcmen") script = ExtResource("1_dcmen")
[node name="Title" type="Label" parent="."] [node name="Title" type="Label" parent="."]
layout_mode = 0 layout_mode = 0
offset_top = -1.0 offset_top = 19.0
offset_right = 600.0 offset_right = 669.0
offset_bottom = 58.0 offset_bottom = 78.0
theme_override_colors/font_color = Color(0.624759, 0.8051, 0.828302, 1) theme_override_colors/font_color = Color(0.624759, 0.8051, 0.828302, 1)
theme_override_colors/font_shadow_color = Color(0, 0, 0, 1) theme_override_colors/font_shadow_color = Color(0, 0, 0, 1)
theme_override_colors/font_outline_color = Color(0, 0, 0, 1) theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
@@ -28,7 +38,7 @@ vertical_alignment = 1
modulate = Color(0.642982, 0.510828, 1, 1) modulate = Color(0.642982, 0.510828, 1, 1)
layout_mode = 0 layout_mode = 0
offset_top = 419.0 offset_top = 419.0
offset_right = 600.0 offset_right = 671.0
offset_bottom = 468.0 offset_bottom = 468.0
theme_override_font_sizes/font_size = 30 theme_override_font_sizes/font_size = 30
text = "🎉获得奖励🎉" text = "🎉获得奖励🎉"
@@ -38,18 +48,19 @@ vertical_alignment = 1
[node name="QuitButton" type="Button" parent="."] [node name="QuitButton" type="Button" parent="."]
custom_minimum_size = Vector2(57, 57) custom_minimum_size = Vector2(57, 57)
layout_mode = 0 layout_mode = 0
offset_left = 543.0 offset_left = 595.0
offset_top = 1.0 offset_top = 21.0
offset_right = 600.0 offset_right = 652.0
offset_bottom = 58.0 offset_bottom = 78.0
theme_override_font_sizes/font_size = 35 theme_override_font_sizes/font_size = 35
text = "X" text = "X"
[node name="LuckyDrawReward" type="RichTextLabel" parent="."] [node name="LuckyDrawReward" type="RichTextLabel" parent="."]
layout_mode = 0 layout_mode = 0
offset_left = 16.0
offset_top = 481.0 offset_top = 481.0
offset_right = 600.0 offset_right = 671.0
offset_bottom = 649.0 offset_bottom = 633.0
theme_override_font_sizes/normal_font_size = 20 theme_override_font_sizes/normal_font_size = 20
bbcode_enabled = true bbcode_enabled = true
text = "+500 经验,+400 钱币,+5 普通-番茄种子,+1 传奇-火龙果种子 " text = "+500 经验,+400 钱币,+5 普通-番茄种子,+1 传奇-火龙果种子 "
@@ -57,14 +68,18 @@ horizontal_alignment = 1
[node name="Grid" type="GridContainer" parent="."] [node name="Grid" type="GridContainer" parent="."]
layout_mode = 0 layout_mode = 0
offset_top = 58.0 offset_left = 16.0
offset_right = 600.0 offset_top = 85.0
offset_right = 657.0
offset_bottom = 419.0 offset_bottom = 419.0
columns = 5 columns = 5
[node name="RewardItem" type="RichTextLabel" parent="Grid"] [node name="RewardItem" type="RichTextLabel" parent="Grid"]
custom_minimum_size = Vector2(120, 120) custom_minimum_size = Vector2(120, 120)
layout_mode = 2 layout_mode = 2
theme_override_constants/outline_size = 15
theme_override_font_sizes/normal_font_size = 17
bbcode_enabled = true
text = "+50钱币 text = "+50钱币
+100经验 +100经验
+4番茄种子 +4番茄种子
@@ -75,9 +90,10 @@ threaded = true
[node name="HBox" type="HBoxContainer" parent="."] [node name="HBox" type="HBoxContainer" parent="."]
layout_mode = 0 layout_mode = 0
offset_top = 649.0 offset_left = -2.0
offset_right = 600.0 offset_top = 633.0
offset_bottom = 719.0 offset_right = 671.0
offset_bottom = 703.0
alignment = 1 alignment = 1
[node name="FiveLuckyDrawButton" type="Button" parent="HBox"] [node name="FiveLuckyDrawButton" type="Button" parent="HBox"]

View File

@@ -320,45 +320,51 @@ func _create_crop_button(crop_name: String, crop_quality: String) -> Button:
# 正常模式下的成熟物点击处理 # 正常模式下的成熟物点击处理
func _on_crop_selected(crop_name, crop_count): func _on_crop_selected(crop_name, crop_count):
# 显示成熟物信息 # 获取作物信息面板的引用
var info_text = "" var crop_inform_panel = get_node("/root/main/UI/SmallPanel/CropInformPanel")
if crop_inform_panel and crop_inform_panel.has_method("show_crop_info"):
if main_game.can_planted_crop.has(crop_name): # 打开作物信息面板并传递作物数据
var crop = main_game.can_planted_crop[crop_name] crop_inform_panel.show_crop_info(crop_name, crop_count)
var display_name = crop_name
var mature_name = crop.get("成熟物名称")
if mature_name != null and mature_name != "":
display_name = mature_name
else:
display_name = crop.get("作物名称", crop_name)
var quality = crop.get("品质", "未知")
var price = crop.get("花费", 0)
var grow_time = crop.get("生长时间", 0)
var profit = crop.get("收益", 0)
var level_req = crop.get("等级", 1)
# 将成熟时间转换为可读格式
var time_str = ""
var total_seconds = int(grow_time)
var hours = total_seconds / 3600
var minutes = (total_seconds % 3600) / 60
var seconds = total_seconds % 60
if hours > 0:
time_str += str(hours) + "小时"
if minutes > 0:
time_str += str(minutes) + "分钟"
if seconds > 0:
time_str += str(seconds) + ""
info_text = quality + "-" + display_name + " (数量: " + str(crop_count) + ")\n"
info_text += "原价格: " + str(price) + "元, 原收益: " + str(profit) + "\n"
info_text += "成熟时间: " + time_str + ", 需求等级: " + str(level_req) + "\n"
info_text += "这是收获的成熟品,可以用于出售或其他用途"
else: else:
info_text = crop_name + " (数量: " + str(crop_count) + ")" # 如果作物信息面板不可用显示Toast作为后备方案
var info_text = ""
Toast.show(info_text, Color.GOLD, 3.0, 1.0)
if main_game.can_planted_crop.has(crop_name):
var crop = main_game.can_planted_crop[crop_name]
var display_name = crop_name
var mature_name = crop.get("成熟物名称")
if mature_name != null and mature_name != "":
display_name = mature_name
else:
display_name = crop.get("作物名称", crop_name)
var quality = crop.get("品质", "未知")
var price = crop.get("花费", 0)
var grow_time = crop.get("生长时间", 0)
var profit = crop.get("收益", 0)
var level_req = crop.get("等级", 1)
# 将成熟时间转换为可读格式
var time_str = ""
var total_seconds = int(grow_time)
var hours = total_seconds / 3600
var minutes = (total_seconds % 3600) / 60
var seconds = total_seconds % 60
if hours > 0:
time_str += str(hours) + "小时"
if minutes > 0:
time_str += str(minutes) + "分钟"
if seconds > 0:
time_str += str(seconds) + ""
info_text = quality + "-" + display_name + " (数量: " + str(crop_count) + ")\n"
info_text += "原价格: " + str(price) + "元, 原收益: " + str(profit) + "\n"
info_text += "成熟时间: " + time_str + ", 需求等级: " + str(level_req) + "\n"
info_text += "这是收获的成熟品,可以用于出售或其他用途"
else:
info_text = crop_name + " (数量: " + str(crop_count) + ")"
Toast.show(info_text, Color.GOLD, 3.0, 1.0)
# 访问模式下的成熟物点击处理 # 访问模式下的成熟物点击处理
func _on_visit_crop_selected(crop_name, crop_count): func _on_visit_crop_selected(crop_name, crop_count):

View File

@@ -1,35 +1,52 @@
#玩家登录注册面板 #玩家登录注册面板
extends PanelContainer extends PanelContainer
#玩家登录账号用QQ号代替 #默认显示登录面板(登录面板可以进入注册面板和忘记密码面板)
@onready var username_input : LineEdit = $VBox/UserName/username_input @onready var login_v_box: VBoxContainer = $LoginVBox #显示或隐藏登录面板
#用户登录密码 @onready var user_name: HBoxContainer = $LoginVBox/UserName #玩家账号
@onready var password_input : LineEdit = $VBox/Password1/password_input @onready var password: HBoxContainer = $LoginVBox/Password #玩家密码
#登录按钮 @onready var login_button: Button = $LoginVBox/LoginButton #登录按钮
@onready var login_button : Button = $VBox/LoginRegister/login_button @onready var register_button: Button = $LoginVBox/RegisterButton #注册按钮,点击后隐藏登录面板显示注册面板
@onready var forget_passwd_button: Button = $LoginVBox/ForgetPasswdButton #忘记密码按钮,点击后隐藏登录面板显示忘记密码面板
@onready var status_label: Label = $LoginVBox/status_label #登录状态
#下面是注册相关的 # 登录面板输入框
#注册按钮 @onready var username_input: LineEdit = $LoginVBox/UserName/username_input
@onready var register_button : Button = $VBox/LoginRegister/register_button @onready var password_input: LineEdit = $LoginVBox/Password/password_input
#注册账号时二次确认密码
@onready var password_input_2 : LineEdit = $VBox/Password2/password_input2
#农场名称
@onready var farmname_input : LineEdit = $VBox/FarmName/farmname_input
#玩家昵称
@onready var playername_input :LineEdit = $VBox/PlayerName/playername_input
#邮箱验证码
@onready var verificationcode_input :LineEdit = $VBox/VerificationCode/verificationcode_input
#发送验证码按钮
@onready var send_button :Button = $VBox/VerificationCode/SendButton
#状态提示标签
@onready var status_label : Label = $VBox/status_label
#注册面板,注册成功跳转回登录面板
@onready var register_vbox: VBoxContainer = $RegisterVbox #显示或隐藏注册面板
@onready var register_user_name: HBoxContainer = $RegisterVbox/RegisterUserName #注册玩家账号
@onready var password_1: HBoxContainer = $RegisterVbox/Password1 #注册密码
@onready var password_2: HBoxContainer = $RegisterVbox/Password2 #二次确认密码
@onready var player_name: HBoxContainer = $RegisterVbox/PlayerName #注册玩家昵称
@onready var farm_name: HBoxContainer = $RegisterVbox/FarmName #注册玩家农场名称
@onready var verification_code: HBoxContainer = $RegisterVbox/VerificationCode #注册所需验证码
@onready var register_button_2: Button = $RegisterVbox/RegisterButton2 #注册按钮
@onready var status_label_2: Label = $RegisterVbox/status_label2 #注册状态
@onready var password_2: HBoxContainer = $VBox/Password2 # 注册面板输入框
@onready var verification_code: HBoxContainer = $VBox/VerificationCode @onready var register_username_input: LineEdit = $RegisterVbox/RegisterUserName/username_input
@onready var player_name: HBoxContainer = $VBox/PlayerName @onready var password_input_1: LineEdit = $RegisterVbox/Password1/password_input
@onready var farm_name: HBoxContainer = $VBox/FarmName @onready var password_input_2: LineEdit = $RegisterVbox/Password2/password_input2
@onready var playername_input: LineEdit = $RegisterVbox/PlayerName/playername_input
@onready var farmname_input: LineEdit = $RegisterVbox/FarmName/farmname_input
@onready var verificationcode_input: LineEdit = $RegisterVbox/VerificationCode/verificationcode_input
@onready var send_button: Button = $RegisterVbox/VerificationCode/SendButton
#忘记密码面板,设置新密码成功后同样跳转到登录面板
@onready var forget_password_vbox: VBoxContainer = $ForgetPasswordVbox #显示或隐藏忘记密码面板
@onready var forget_password_user_name: HBoxContainer = $ForgetPasswordVbox/ForgetPasswordUserName #忘记密码的玩家账号
@onready var new_password: HBoxContainer = $ForgetPasswordVbox/NewPassword #设置该账号新的密码
@onready var verification_code_2: HBoxContainer = $ForgetPasswordVbox/VerificationCode2 #忘记密码所需验证码
@onready var forget_password_button: Button = $ForgetPasswordVbox/ForgetPasswordButton #设置新密码确认按钮
@onready var status_label_3: Label = $ForgetPasswordVbox/status_label3 #设置新密码状态
# 忘记密码面板输入框
@onready var forget_username_input: LineEdit = $ForgetPasswordVbox/ForgetPasswordUserName/username_input
@onready var new_password_input: LineEdit = $ForgetPasswordVbox/NewPassword/password_input
@onready var forget_verificationcode_input: LineEdit = $ForgetPasswordVbox/VerificationCode2/verificationcode_input
@onready var forget_send_button: Button = $ForgetPasswordVbox/VerificationCode2/SendButton
# 记住密码选项 # 记住密码选项
@@ -53,16 +70,20 @@ var remember_password : bool = true # 默认记住密码
# 准备函数 # 准备函数
func _ready(): func _ready():
self.show() self.show()
#隐藏注册相关UI
password_2.hide() # 初始状态:只显示登录面板,隐藏注册和忘记密码面板
verification_code.hide() login_v_box.show()
player_name.hide() register_vbox.hide()
farm_name.hide() forget_password_vbox.hide()
# 连接按钮信号 # 连接按钮信号
login_button.pressed.connect(self._on_login_button_pressed) login_button.pressed.connect(self._on_login_button_pressed)
register_button.pressed.connect(self._on_register_button_pressed) register_button.pressed.connect(self._on_show_register_panel)
forget_passwd_button.pressed.connect(self._on_forget_password_button_pressed)
register_button_2.pressed.connect(self._on_register_button_2_pressed)
forget_password_button.pressed.connect(self._on_forget_password_confirm_pressed)
send_button.pressed.connect(self._on_send_button_pressed) send_button.pressed.connect(self._on_send_button_pressed)
forget_send_button.pressed.connect(self._on_forget_send_button_pressed)
# 加载保存的登录信息 # 加载保存的登录信息
_load_login_info() _load_login_info()
@@ -70,6 +91,23 @@ func _ready():
# 显示客户端版本号 # 显示客户端版本号
_display_version_info() _display_version_info()
# 面板切换函数
func _on_show_register_panel():
"""切换到注册面板"""
login_v_box.hide()
register_vbox.show()
forget_password_vbox.hide()
status_label_2.text = "请填写注册信息"
status_label_2.modulate = Color.WHITE
func _on_forget_password_button_pressed():
"""切换到忘记密码面板"""
login_v_box.hide()
register_vbox.hide()
forget_password_vbox.show()
status_label_3.text = "请输入账号和新密码"
status_label_3.modulate = Color.WHITE
# 处理登录按钮点击 # 处理登录按钮点击
func _on_login_button_pressed(): func _on_login_button_pressed():
password_2.hide() password_2.hide()
@@ -129,32 +167,30 @@ func _on_login_button_pressed():
# 处理验证码发送按钮点击 # 处理验证码发送按钮点击
func _on_send_button_pressed(): func _on_send_button_pressed():
var user_name = register_username_input.text.strip_edges()
var user_name = username_input.text.strip_edges()
if user_name == "": if user_name == "":
status_label.text = "请输入QQ号以接收验证码" status_label_2.text = "请输入QQ号以接收验证码"
status_label.modulate = Color.RED status_label_2.modulate = Color.RED
return return
if !is_valid_qq_number(user_name): if !is_valid_qq_number(user_name):
status_label.text = "请输入正确的QQ号码5-12位数字" status_label_2.text = "请输入正确的QQ号码5-12位数字"
status_label.modulate = Color.RED status_label_2.modulate = Color.RED
return return
# 检查网络连接状态 # 检查网络连接状态
if !tcp_network_manager_panel.client.is_client_connected(): if !tcp_network_manager_panel.client.is_client_connected():
status_label.text = "未连接到服务器,正在尝试连接..." status_label_2.text = "未连接到服务器,正在尝试连接..."
status_label.modulate = Color.YELLOW status_label_2.modulate = Color.YELLOW
# 尝试自动连接到服务器 # 尝试自动连接到服务器
tcp_network_manager_panel.connect_to_current_server() tcp_network_manager_panel.connect_to_current_server()
await get_tree().create_timer(2.0).timeout await get_tree().create_timer(2.0).timeout
# 再次检查连接状态 # 再次检查连接状态
if !tcp_network_manager_panel.client.is_client_connected(): if !tcp_network_manager_panel.client.is_client_connected():
status_label.text = "连接服务器失败,正在尝试其他服务器..." status_label_2.text = "连接服务器失败,正在尝试其他服务器..."
status_label.modulate = Color.YELLOW status_label_2.modulate = Color.YELLOW
# 等待自动服务器切换完成 # 等待自动服务器切换完成
await get_tree().create_timer(3.0).timeout await get_tree().create_timer(3.0).timeout
@@ -162,8 +198,8 @@ func _on_send_button_pressed():
# 禁用按钮,防止重复点击 # 禁用按钮,防止重复点击
send_button.disabled = true send_button.disabled = true
status_label.text = "正在发送验证码,请稍候..." status_label_2.text = "正在发送验证码,请稍候..."
status_label.modulate = Color.YELLOW status_label_2.modulate = Color.YELLOW
# 发送验证码请求 # 发送验证码请求
tcp_network_manager_panel.sendVerificationCodeRequest(user_name) tcp_network_manager_panel.sendVerificationCodeRequest(user_name)
@@ -179,19 +215,14 @@ func _on_send_button_pressed():
send_button.disabled = false send_button.disabled = false
send_button.text = "发送验证码" send_button.text = "发送验证码"
if status_label.text == "正在发送验证码,请稍候...": if status_label_2.text == "正在发送验证码,请稍候...":
status_label.text = "验证码发送超时,请重试!" status_label_2.text = "验证码发送超时,请重试!"
status_label.modulate = Color.RED status_label_2.modulate = Color.RED
# 处理注册按钮点击 # 处理注册按钮点击
func _on_register_button_pressed(): func _on_register_button_2_pressed():
password_2.show() var user_name = register_username_input.text.strip_edges()
verification_code.show() var user_password = password_input_1.text.strip_edges()
player_name.show()
farm_name.show()
var user_name = username_input.text.strip_edges()
var user_password = password_input.text.strip_edges()
var user_password_2 = password_input_2.text.strip_edges() var user_password_2 = password_input_2.text.strip_edges()
var farmname = farmname_input.text.strip_edges() var farmname = farmname_input.text.strip_edges()
var player_name = playername_input.text.strip_edges() var player_name = playername_input.text.strip_edges()
@@ -199,69 +230,180 @@ func _on_register_button_pressed():
# 检查密码格式(只允许数字和字母) # 检查密码格式(只允许数字和字母)
if not is_valid_password(user_password): if not is_valid_password(user_password):
status_label.text = "密码只能包含数字和字母!" status_label_2.text = "密码只能包含数字和字母!"
status_label.modulate = Color.RED status_label_2.modulate = Color.RED
return return
if user_name == "" or user_password == "": if user_name == "" or user_password == "":
status_label.text = "用户名或密码不能为空!" status_label_2.text = "用户名或密码不能为空!"
status_label.modulate = Color.RED status_label_2.modulate = Color.RED
return return
if farmname == "": if farmname == "":
status_label.text = "农场名称不能为空!" status_label_2.text = "农场名称不能为空!"
status_label.modulate = Color.RED status_label_2.modulate = Color.RED
return return
if user_password != user_password_2: if user_password != user_password_2:
status_label.text = "两次输入的密码不一致!" status_label_2.text = "两次输入的密码不一致!"
status_label.modulate = Color.RED status_label_2.modulate = Color.RED
return return
if !is_valid_qq_number(user_name): if !is_valid_qq_number(user_name):
status_label.text = "请输入正确的QQ号码5-12位数字" status_label_2.text = "请输入正确的QQ号码5-12位数字"
status_label.modulate = Color.RED status_label_2.modulate = Color.RED
return return
if verification_code == "": if verification_code == "":
status_label.text = "请输入验证码!" status_label_2.text = "请输入验证码!"
status_label.modulate = Color.RED status_label_2.modulate = Color.RED
return return
# 检查网络连接状态 # 检查网络连接状态
if !tcp_network_manager_panel.client.is_client_connected(): if !tcp_network_manager_panel.client.is_client_connected():
status_label.text = "未连接到服务器,正在尝试连接..." status_label_2.text = "未连接到服务器,正在尝试连接..."
status_label.modulate = Color.YELLOW status_label_2.modulate = Color.YELLOW
# 尝试自动连接到服务器 # 尝试自动连接到服务器
tcp_network_manager_panel.connect_to_current_server() tcp_network_manager_panel.connect_to_current_server()
await get_tree().create_timer(2.0).timeout await get_tree().create_timer(2.0).timeout
# 再次检查连接状态 # 再次检查连接状态
if !tcp_network_manager_panel.client.is_client_connected(): if !tcp_network_manager_panel.client.is_client_connected():
status_label.text = "连接服务器失败,正在尝试其他服务器..." status_label_2.text = "连接服务器失败,正在尝试其他服务器..."
status_label.modulate = Color.YELLOW status_label_2.modulate = Color.YELLOW
# 等待自动服务器切换完成 # 等待自动服务器切换完成
await get_tree().create_timer(3.0).timeout await get_tree().create_timer(3.0).timeout
# 禁用按钮,防止重复点击 # 禁用按钮,防止重复点击
register_button.disabled = true register_button_2.disabled = true
status_label.text = "正在注册,请稍候..." status_label_2.text = "正在注册,请稍候..."
status_label.modulate = Color.YELLOW status_label_2.modulate = Color.YELLOW
# 发送注册请求 # 发送注册请求
tcp_network_manager_panel.sendRegisterInfo(user_name, user_password, farmname, player_name, verification_code) tcp_network_manager_panel.sendRegisterInfo(user_name, user_password, farmname, player_name, verification_code)
# 更新主游戏数据 # 更新主游戏数据
main_game.user_name = user_name main_game.user_name = user_name
main_game.user_password = user_password main_game.user_password = user_password
main_game.farmname = farmname # farmname 直接在注册成功后通过UI更新这里不需要设置
# 5秒后重新启用按钮如果没有收到响应 # 5秒后重新启用按钮如果没有收到响应
await get_tree().create_timer(5.0).timeout await get_tree().create_timer(5.0).timeout
if register_button.disabled: if register_button_2.disabled:
register_button.disabled = false register_button_2.disabled = false
status_label.text = "注册超时,请重试!" status_label_2.text = "注册超时,请重试!"
status_label.modulate = Color.RED status_label_2.modulate = Color.RED
# 忘记密码发送验证码按钮处理
func _on_forget_send_button_pressed():
var user_name = forget_username_input.text.strip_edges()
if user_name == "":
status_label_3.text = "请输入QQ号以接收验证码"
status_label_3.modulate = Color.RED
return
if !is_valid_qq_number(user_name):
status_label_3.text = "请输入正确的QQ号码5-12位数字"
status_label_3.modulate = Color.RED
return
# 检查网络连接状态
if !tcp_network_manager_panel.client.is_client_connected():
status_label_3.text = "未连接到服务器,正在尝试连接..."
status_label_3.modulate = Color.YELLOW
# 尝试自动连接到服务器
tcp_network_manager_panel.connect_to_current_server()
await get_tree().create_timer(2.0).timeout
# 再次检查连接状态
if !tcp_network_manager_panel.client.is_client_connected():
status_label_3.text = "连接服务器失败,正在尝试其他服务器..."
status_label_3.modulate = Color.YELLOW
# 等待自动服务器切换完成
await get_tree().create_timer(3.0).timeout
# 禁用按钮,防止重复点击
forget_send_button.disabled = true
status_label_3.text = "正在发送验证码,请稍候..."
status_label_3.modulate = Color.YELLOW
# 发送验证码请求(用于忘记密码)
tcp_network_manager_panel.sendForgetPasswordVerificationCode(user_name)
# 60秒后重新启用按钮
var timer = 60
while timer > 0 and forget_send_button.disabled:
forget_send_button.text = "重新发送(%d)" % timer
await get_tree().create_timer(1.0).timeout
timer -= 1
if forget_send_button.disabled:
forget_send_button.disabled = false
forget_send_button.text = "发送验证码"
if status_label_3.text == "正在发送验证码,请稍候...":
status_label_3.text = "验证码发送超时,请重试!"
status_label_3.modulate = Color.RED
# 忘记密码确认按钮处理
func _on_forget_password_confirm_pressed():
var user_name = forget_username_input.text.strip_edges()
var new_password = new_password_input.text.strip_edges()
var verification_code = forget_verificationcode_input.text.strip_edges()
# 检查密码格式(只允许数字和字母)
if not is_valid_password(new_password):
status_label_3.text = "密码只能包含数字和字母!"
status_label_3.modulate = Color.RED
return
if user_name == "" or new_password == "":
status_label_3.text = "用户名或新密码不能为空!"
status_label_3.modulate = Color.RED
return
if !is_valid_qq_number(user_name):
status_label_3.text = "请输入正确的QQ号码5-12位数字"
status_label_3.modulate = Color.RED
return
if verification_code == "":
status_label_3.text = "请输入验证码!"
status_label_3.modulate = Color.RED
return
# 检查网络连接状态
if !tcp_network_manager_panel.client.is_client_connected():
status_label_3.text = "未连接到服务器,正在尝试连接..."
status_label_3.modulate = Color.YELLOW
# 尝试自动连接到服务器
tcp_network_manager_panel.connect_to_current_server()
await get_tree().create_timer(2.0).timeout
# 再次检查连接状态
if !tcp_network_manager_panel.client.is_client_connected():
status_label_3.text = "连接服务器失败,正在尝试其他服务器..."
status_label_3.modulate = Color.YELLOW
# 等待自动服务器切换完成
await get_tree().create_timer(3.0).timeout
# 禁用按钮,防止重复点击
forget_password_button.disabled = true
status_label_3.text = "正在重置密码,请稍候..."
status_label_3.modulate = Color.YELLOW
# 发送忘记密码请求
tcp_network_manager_panel.sendForgetPasswordRequest(user_name, new_password, verification_code)
# 5秒后重新启用按钮如果没有收到响应
await get_tree().create_timer(5.0).timeout
if forget_password_button.disabled:
forget_password_button.disabled = false
status_label_3.text = "重置密码超时,请重试!"
status_label_3.modulate = Color.RED
# 处理验证码发送响应 # 处理验证码发送响应
func _on_verification_code_response(success: bool, message: String): func _on_verification_code_response(success: bool, message: String):
@@ -390,24 +532,67 @@ func _on_login_response_received(success: bool, message: String, user_data: Dict
# 处理注册响应 # 处理注册响应
func _on_register_response_received(success: bool, message: String): func _on_register_response_received(success: bool, message: String):
# 启用按钮 # 启用按钮
register_button.disabled = false register_button_2.disabled = false
if success: if success:
status_label.text = "注册成功!请登录游戏" status_label_2.text = "注册成功!请登录游戏"
status_label.modulate = Color.GREEN status_label_2.modulate = Color.GREEN
# 注册成功后,如果启用了记住密码,保存登录信息 # 注册成功后,如果启用了记住密码,保存登录信息
if remember_password: if remember_password:
var user_name = username_input.text.strip_edges() var user_name = register_username_input.text.strip_edges()
var user_password = password_input.text.strip_edges() var user_password = password_input_1.text.strip_edges()
_save_login_info(user_name, user_password) _save_login_info(user_name, user_password)
# 清除注册相关的输入框 # 清除注册相关的输入框
password_input_2.text = "" password_input_2.text = ""
verificationcode_input.text = "" verificationcode_input.text = ""
# 切换回登录面板
register_vbox.hide()
forget_password_vbox.hide()
login_v_box.show()
# 如果记住密码,自动填充登录信息
if remember_password:
username_input.text = register_username_input.text
password_input.text = password_input_1.text
else: else:
status_label.text = "注册失败:" + message status_label_2.text = "注册失败:" + message
status_label.modulate = Color.RED status_label_2.modulate = Color.RED
# 处理忘记密码响应
func _on_forget_password_response_received(success: bool, message: String):
# 启用按钮
forget_password_button.disabled = false
if success:
status_label_3.text = "密码重置成功!请使用新密码登录"
status_label_3.modulate = Color.GREEN
# 保存新的登录信息
if remember_password:
var user_name = forget_username_input.text.strip_edges()
var new_password = new_password_input.text.strip_edges()
_save_login_info(user_name, new_password)
# 清除输入框
forget_verificationcode_input.text = ""
# 切换回登录面板并自动填充账号信息
forget_password_vbox.hide()
register_vbox.hide()
login_v_box.show()
# 自动填充登录信息
username_input.text = forget_username_input.text
password_input.text = new_password_input.text
status_label.text = "密码已重置,请登录"
status_label.modulate = Color.GREEN
else:
status_label_3.text = "密码重置失败:" + message
status_label_3.modulate = Color.RED
# 保存登录信息到JSON文件 # 保存登录信息到JSON文件
func _save_login_info(user_name: String, password: String): func _save_login_info(user_name: String, password: String):

View File

@@ -0,0 +1,374 @@
extends Panel
#玩家小卖部(目前可以卖道具,种子,成熟作物)
#初始玩家有10个格子
#然后玩家额外购买格子需要1000元多加一个格子加500元最多40个格子格子满了不能再放了
#玩家自己点击自己的摊位(商品格子)显示弹窗是否要取消放置商品
#别人拜访玩家打开小卖部点击被拜访玩家的摊位显示批量购买弹窗
@onready var quit_button: Button = $QuitButton #关闭玩家小卖部面板
@onready var refresh_button: Button = $RefreshButton #刷新小卖部按钮
@onready var store_grid: GridContainer = $ScrollContainer/Store_Grid #小卖部商品格子
@onready var buy_product_booth_button: Button = $BuyProductBoothButton #购买格子按钮
# 获取主游戏引用
@onready var main_game = get_node("/root/main")
# 当前小卖部数据
var player_store_data: Array = []
var max_store_slots: int = 10 # 默认10个格子
func _ready():
# 连接按钮信号
quit_button.pressed.connect(_on_quit_button_pressed)
refresh_button.pressed.connect(_on_refresh_button_pressed)
buy_product_booth_button.pressed.connect(_on_buy_product_booth_button_pressed)
# 连接可见性改变信号
visibility_changed.connect(_on_visibility_changed)
# 默认隐藏面板
self.hide()
#面板显示与隐藏切换处理
func _on_visibility_changed():
if visible:
GlobalVariables.isZoomDisabled = true
# 面板显示时更新小卖部数据
update_player_store_ui()
else:
GlobalVariables.isZoomDisabled = false
# 初始化玩家小卖部
func init_player_store():
update_player_store_ui()
# 更新小卖部UI
func update_player_store_ui():
# 清空商品格子
for child in store_grid.get_children():
child.queue_free()
# 获取小卖部数据
if main_game.is_visiting_mode:
# 访问模式:显示被访问玩家的小卖部
player_store_data = main_game.visited_player_data.get("玩家小卖部", [])
max_store_slots = main_game.visited_player_data.get("小卖部格子数", 10)
buy_product_booth_button.hide() # 访问模式下隐藏购买格子按钮
else:
# 正常模式:显示自己的小卖部
player_store_data = main_game.login_data.get("玩家小卖部", [])
max_store_slots = main_game.login_data.get("小卖部格子数", 10)
buy_product_booth_button.show() # 正常模式下显示购买格子按钮
# 创建商品按钮
_create_store_buttons()
# 更新购买格子按钮文本
_update_buy_booth_button()
# 创建小卖部商品按钮
func _create_store_buttons():
# 为每个格子创建按钮
for i in range(max_store_slots):
var button = _create_store_slot_button(i)
store_grid.add_child(button)
# 创建单个商品格子按钮
func _create_store_slot_button(slot_index: int) -> Button:
var button = main_game.item_button.duplicate()
# 确保按钮可见并可点击
button.visible = true
button.disabled = false
button.focus_mode = Control.FOCUS_ALL
# 检查该格子是否有商品
var product_data = null
if slot_index < player_store_data.size():
product_data = player_store_data[slot_index]
if product_data:
# 有商品的格子
var product_name = product_data.get("商品名称", "未知商品")
var product_price = product_data.get("商品价格", 0)
var product_count = product_data.get("商品数量", 0)
var product_type = product_data.get("商品类型", "作物")
# 设置按钮文本
button.text = str(product_name + "\n" + str(product_price) + "元/个\n库存:" + str(product_count))
# 更新商品图片
_update_button_product_image(button, product_name, product_type)
# 设置工具提示
button.tooltip_text = str(
"商品: " + product_name + "\n" +
"类型: " + product_type + "\n" +
"单价: " + str(product_price) + "\n" +
"库存: " + str(product_count) + ""
)
# 连接点击事件
if main_game.is_visiting_mode:
# 访问模式:显示购买弹窗
button.pressed.connect(func(): _on_product_buy_selected(product_data, slot_index))
else:
# 自己的小卖部:显示移除商品弹窗
button.pressed.connect(func(): _on_product_manage_selected(product_data, slot_index))
else:
# 空格子
button.text = "空闲格子\n\n点击添加商品"
# 设置为灰色样式
if button.has_node("Title"):
button.get_node("Title").modulate = Color.GRAY
# 只有在非访问模式下才允许点击空格子
if not main_game.is_visiting_mode:
button.pressed.connect(func(): _on_empty_slot_selected(slot_index))
else:
button.disabled = true
return button
# 更新商品图片
func _update_button_product_image(button: Button, product_name: String, product_type: String):
var crop_image = button.get_node_or_null("CropImage")
if not crop_image:
return
var texture = null
if product_type == "作物":
# 作物商品:加载收获物图片
texture = _get_crop_harvest_texture(product_name)
# 未来可以添加其他类型的商品图片加载
if texture:
crop_image.texture = texture
crop_image.visible = true
else:
crop_image.visible = false
# 获取作物的收获物图片
func _get_crop_harvest_texture(crop_name: String) -> Texture2D:
var crop_path = "res://assets/作物/" + crop_name + "/"
var harvest_texture_path = crop_path + "收获物.webp"
if ResourceLoader.exists(harvest_texture_path):
var texture = load(harvest_texture_path)
if texture:
return texture
# 如果没有找到,使用默认的收获物图片
var default_harvest_path = "res://assets/作物/默认/收获物.webp"
if ResourceLoader.exists(default_harvest_path):
var texture = load(default_harvest_path)
if texture:
return texture
return null
# 访问模式:点击商品购买
func _on_product_buy_selected(product_data: Dictionary, slot_index: int):
var product_name = product_data.get("商品名称", "未知商品")
var product_price = product_data.get("商品价格", 0)
var product_count = product_data.get("商品数量", 0)
var product_type = product_data.get("商品类型", "作物")
# 检查商品是否还有库存
if product_count <= 0:
Toast.show("该商品已售罄", Color.RED, 2.0, 1.0)
return
# 获取批量购买弹窗
var batch_buy_popup = get_node_or_null("/root/main/UI/DiaLog/BatchBuyPopup")
if batch_buy_popup and batch_buy_popup.has_method("show_buy_popup"):
# 显示批量购买弹窗
batch_buy_popup.show_buy_popup(
product_name,
product_price,
"玩家小卖部商品",
"store_product", # 特殊类型标识
_on_confirm_buy_store_product,
_on_cancel_buy_store_product
)
# 临时保存购买信息
batch_buy_popup.set_meta("store_slot_index", slot_index)
batch_buy_popup.set_meta("store_product_data", product_data)
else:
Toast.show("购买功能暂未实现", Color.RED, 2.0, 1.0)
# 确认购买小卖部商品
func _on_confirm_buy_store_product(product_name: String, unit_price: int, quantity: int, buy_type: String):
var slot_index = get_node("/root/main/UI/DiaLog/BatchBuyPopup").get_meta("store_slot_index", -1)
var product_data = get_node("/root/main/UI/DiaLog/BatchBuyPopup").get_meta("store_product_data", {})
if slot_index == -1 or product_data.is_empty():
Toast.show("购买信息错误", Color.RED, 2.0, 1.0)
return
# 发送购买请求到服务器
var tcp_network_manager = get_node_or_null("/root/main/UI/BigPanel/TCPNetworkManagerPanel")
if tcp_network_manager and tcp_network_manager.has_method("send_message"):
var visited_player_name = main_game.visited_player_data.get("player_name", "")
var message = {
"type": "buy_store_product",
"seller_username": main_game.visited_player_data.get("username", ""),
"slot_index": slot_index,
"product_name": product_name,
"unit_price": unit_price,
"quantity": quantity
}
tcp_network_manager.send_message(message)
Toast.show("购买请求已发送", Color.YELLOW, 2.0, 1.0)
else:
Toast.show("网络连接异常,无法购买", Color.RED, 2.0, 1.0)
# 取消购买小卖部商品
func _on_cancel_buy_store_product():
# 不需要做任何事情,弹窗会自动关闭
pass
# 自己的小卖部:点击商品管理
func _on_product_manage_selected(product_data: Dictionary, slot_index: int):
var product_name = product_data.get("商品名称", "未知商品")
var product_count = product_data.get("商品数量", 0)
# 显示管理确认对话框
_show_product_manage_dialog(product_name, product_count, slot_index)
# 显示商品管理对话框
func _show_product_manage_dialog(product_name: String, product_count: int, slot_index: int):
var confirm_dialog = AcceptDialog.new()
confirm_dialog.dialog_text = str(
"商品管理\n\n" +
"商品:" + product_name + "\n" +
"库存:" + str(product_count) + "\n\n" +
"确认要下架这个商品吗?\n" +
"商品将返回到您的仓库中。"
)
confirm_dialog.title = "商品管理"
confirm_dialog.ok_button_text = "下架商品"
confirm_dialog.add_cancel_button("取消")
# 添加到场景
add_child(confirm_dialog)
# 连接信号
confirm_dialog.confirmed.connect(_on_confirm_remove_product.bind(slot_index, confirm_dialog))
confirm_dialog.canceled.connect(_on_cancel_remove_product.bind(confirm_dialog))
# 显示对话框
confirm_dialog.popup_centered()
# 确认下架商品
func _on_confirm_remove_product(slot_index: int, dialog: AcceptDialog):
# 发送下架商品请求到服务器
var tcp_network_manager = get_node_or_null("/root/main/UI/BigPanel/TCPNetworkManagerPanel")
if tcp_network_manager and tcp_network_manager.has_method("send_message"):
var message = {
"type": "remove_store_product",
"slot_index": slot_index
}
tcp_network_manager.send_message(message)
Toast.show("下架请求已发送", Color.YELLOW, 2.0, 1.0)
else:
Toast.show("网络连接异常,无法下架", Color.RED, 2.0, 1.0)
dialog.queue_free()
# 取消下架商品
func _on_cancel_remove_product(dialog: AcceptDialog):
dialog.queue_free()
# 点击空格子
func _on_empty_slot_selected(slot_index: int):
Toast.show("请从作物仓库选择商品添加到小卖部", Color.CYAN, 3.0, 1.0)
# 更新购买格子按钮
func _update_buy_booth_button():
if main_game.is_visiting_mode:
return
var next_slot_cost = 1000 + (max_store_slots - 10) * 500
if max_store_slots >= 40:
buy_product_booth_button.text = "格子已满(40/40)"
buy_product_booth_button.disabled = true
else:
buy_product_booth_button.text = str("购买格子(+" + str(next_slot_cost) + "元)")
buy_product_booth_button.disabled = false
# 购买格子按钮处理
func _on_buy_product_booth_button_pressed():
if main_game.is_visiting_mode:
return
if max_store_slots >= 40:
Toast.show("格子数量已达上限", Color.RED, 2.0, 1.0)
return
var next_slot_cost = 1000 + (max_store_slots - 10) * 500
if main_game.money < next_slot_cost:
Toast.show("金钱不足,需要 " + str(next_slot_cost) + "", Color.RED, 2.0, 1.0)
return
# 显示购买确认对话框
_show_buy_booth_dialog(next_slot_cost)
# 显示购买格子确认对话框
func _show_buy_booth_dialog(cost: int):
var confirm_dialog = AcceptDialog.new()
confirm_dialog.dialog_text = str(
"购买小卖部格子\n\n" +
"费用:" + str(cost) + "\n" +
"当前格子数:" + str(max_store_slots) + "\n" +
"购买后格子数:" + str(max_store_slots + 1) + "\n\n" +
"确认购买吗?"
)
confirm_dialog.title = "购买格子"
confirm_dialog.ok_button_text = "确认购买"
confirm_dialog.add_cancel_button("取消")
# 添加到场景
add_child(confirm_dialog)
# 连接信号
confirm_dialog.confirmed.connect(_on_confirm_buy_booth.bind(cost, confirm_dialog))
confirm_dialog.canceled.connect(_on_cancel_buy_booth.bind(confirm_dialog))
# 显示对话框
confirm_dialog.popup_centered()
# 确认购买格子
func _on_confirm_buy_booth(cost: int, dialog: AcceptDialog):
# 发送购买格子请求到服务器
var tcp_network_manager = get_node_or_null("/root/main/UI/BigPanel/TCPNetworkManagerPanel")
if tcp_network_manager and tcp_network_manager.has_method("send_message"):
var message = {
"type": "buy_store_booth",
"cost": cost
}
tcp_network_manager.send_message(message)
Toast.show("购买请求已发送", Color.YELLOW, 2.0, 1.0)
else:
Toast.show("网络连接异常,无法购买", Color.RED, 2.0, 1.0)
dialog.queue_free()
# 取消购买格子
func _on_cancel_buy_booth(dialog: AcceptDialog):
dialog.queue_free()
# 关闭面板
func _on_quit_button_pressed():
self.hide()
# 刷新小卖部
func _on_refresh_button_pressed():
update_player_store_ui()
Toast.show("小卖部已刷新", Color.GREEN, 2.0, 1.0)

View File

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

View File

@@ -0,0 +1,197 @@
extends PanelContainer
#用于添加商品到玩家小卖部的弹窗
@onready var title: Label = $VBox/Title #弹窗标题
@onready var contents: Label = $VBox/Contents #这里显示弹窗内容
@onready var sell_num_input: LineEdit = $VBox/SellNumInput #这里输入需要放入小卖部的商品数量
@onready var sell_price_input: LineEdit = $VBox/SellPriceInput #这里输入每件商品的价格
@onready var sure_button: Button = $VBox/HBox/SureButton #确定放入按钮
@onready var cancel_button: Button = $VBox/HBox/CancelButton #取消按钮
# 当前要添加的商品信息
var current_product_name: String = ""
var current_max_count: int = 0
var current_suggested_price: int = 0
var current_product_desc: String = ""
# 回调函数,用于处理确认添加
var confirm_callback: Callable
var cancel_callback: Callable
func _ready():
# 连接按钮信号
sure_button.pressed.connect(_on_sure_button_pressed)
cancel_button.pressed.connect(_on_cancel_button_pressed)
# 设置输入框的默认值和限制
sell_num_input.text = "1"
sell_num_input.placeholder_text = "请输入数量"
sell_price_input.placeholder_text = "请输入单价"
# 只允许输入数字
sell_num_input.text_changed.connect(_on_sell_num_changed)
sell_price_input.text_changed.connect(_on_sell_price_changed)
# 连接可见性改变信号
visibility_changed.connect(_on_visibility_changed)
# 默认隐藏弹窗
self.hide()
#面板显示与隐藏切换处理
func _on_visibility_changed():
if visible:
GlobalVariables.isZoomDisabled = true
pass
else:
GlobalVariables.isZoomDisabled = false
pass
# 显示添加商品弹窗
func show_add_product_popup(product_name: String, max_count: int, suggested_price: int, product_desc: String, on_confirm: Callable, on_cancel: Callable = Callable()):
current_product_name = product_name
current_max_count = max_count
current_suggested_price = suggested_price
current_product_desc = product_desc
confirm_callback = on_confirm
cancel_callback = on_cancel
# 设置弹窗内容
title.text = "添加商品到小卖部"
contents.text = str(
"商品名称: " + product_name + "\n" +
"可用数量: " + str(max_count) + "\n" +
"建议价格: " + str(suggested_price) + " 元/个\n" +
"描述: " + product_desc + "\n\n" +
"请设置出售数量和价格:"
)
# 设置默认值
sell_num_input.text = "1"
sell_price_input.text = str(suggested_price)
# 显示弹窗并居中
self.show()
self.move_to_front()
# 处理数量输入变化
func _on_sell_num_changed(new_text: String):
# 只允许输入数字
var filtered_text = ""
for char in new_text:
if char.is_valid_int():
filtered_text += char
if filtered_text != new_text:
sell_num_input.text = filtered_text
sell_num_input.caret_column = filtered_text.length()
# 更新预览信息
_update_preview_info()
# 处理价格输入变化
func _on_sell_price_changed(new_text: String):
# 只允许输入数字
var filtered_text = ""
for char in new_text:
if char.is_valid_int():
filtered_text += char
if filtered_text != new_text:
sell_price_input.text = filtered_text
sell_price_input.caret_column = filtered_text.length()
# 更新预览信息
_update_preview_info()
# 更新预览信息
func _update_preview_info():
var quantity = get_sell_quantity()
var unit_price = get_sell_price()
var total_value = quantity * unit_price
# 检查数量是否超过最大可用数量
var quantity_status = ""
if quantity > current_max_count:
quantity_status = " (超出库存!)"
# 检查价格是否合理
var price_status = ""
if unit_price <= 0:
price_status = " (价格无效!)"
elif unit_price < current_suggested_price * 0.5:
price_status = " (价格偏低)"
elif unit_price > current_suggested_price * 2:
price_status = " (价格偏高)"
var preview_info = "\n上架数量: " + str(quantity) + "" + quantity_status + "\n单价: " + str(unit_price) + " 元/个" + price_status + "\n总价值: " + str(total_value) + ""
# 更新内容显示
var base_content = str(
"商品名称: " + current_product_name + "\n" +
"可用数量: " + str(current_max_count) + "\n" +
"建议价格: " + str(current_suggested_price) + " 元/个\n" +
"描述: " + current_product_desc + "\n\n" +
"请设置出售数量和价格:"
)
contents.text = base_content + preview_info
# 获取出售数量
func get_sell_quantity() -> int:
var text = sell_num_input.text.strip_edges()
if text.is_empty():
return 1
var quantity = text.to_int()
return max(1, quantity) # 至少出售1个
# 获取出售价格
func get_sell_price() -> int:
var text = sell_price_input.text.strip_edges()
if text.is_empty():
return current_suggested_price
var price = text.to_int()
return max(1, price) # 至少1元
# 确认添加按钮处理
func _on_sure_button_pressed():
var quantity = get_sell_quantity()
var unit_price = get_sell_price()
if quantity <= 0:
_show_error("数量必须大于0")
return
if quantity > current_max_count:
_show_error("数量不能超过库存数量(" + str(current_max_count) + ")")
return
if unit_price <= 0:
_show_error("价格必须大于0")
return
# 调用确认回调函数
if confirm_callback.is_valid():
confirm_callback.call(current_product_name, quantity, unit_price)
# 隐藏弹窗
self.hide()
# 取消添加按钮处理
func _on_cancel_button_pressed():
# 调用取消回调函数
if cancel_callback.is_valid():
cancel_callback.call()
# 隐藏弹窗
self.hide()
# 显示错误信息
func _show_error(message: String):
# 显示Toast错误提示
if has_node("/root/Toast"):
get_node("/root/Toast").show(message, Color.RED, 2.0, 1.0)
else:
print("添加商品弹窗错误: " + message)

View File

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

View File

@@ -0,0 +1,154 @@
extends PanelContainer
#用于作物批量出售作物弹窗
@onready var title: Label = $VBox/Title #弹窗标题
@onready var contents: Label = $VBox/Contents #这里显示弹窗内容
@onready var sell_num_edit: LineEdit = $VBox/SellNumEdit #出售作物数量
@onready var sure_button: Button = $VBox/HBox/SureButton #确定按钮
@onready var cancel_button: Button = $VBox/HBox/CancelButton #取消按钮
# 当前出售的作物信息
var current_crop_name: String = ""
var current_max_count: int = 0
var current_unit_price: int = 0
var current_crop_desc: String = ""
# 回调函数,用于处理确认出售
var confirm_callback: Callable
var cancel_callback: Callable
func _ready():
# 连接按钮信号
sure_button.pressed.connect(_on_sure_button_pressed)
cancel_button.pressed.connect(_on_cancel_button_pressed)
# 设置数量输入框的默认值和限制
sell_num_edit.text = "1"
sell_num_edit.placeholder_text = "请输入出售数量"
# 只允许输入数字
sell_num_edit.text_changed.connect(_on_sell_num_changed)
# 连接可见性改变信号
visibility_changed.connect(_on_visibility_changed)
# 默认隐藏弹窗
self.hide()
#面板显示与隐藏切换处理
func _on_visibility_changed():
if visible:
GlobalVariables.isZoomDisabled = true
pass
else:
GlobalVariables.isZoomDisabled = false
pass
# 显示批量出售弹窗
func show_sell_popup(crop_name: String, max_count: int, unit_price: int, crop_desc: String, on_confirm: Callable, on_cancel: Callable = Callable()):
current_crop_name = crop_name
current_max_count = max_count
current_unit_price = unit_price
current_crop_desc = crop_desc
confirm_callback = on_confirm
cancel_callback = on_cancel
# 设置弹窗内容
title.text = "批量出售作物"
contents.text = str(
"作物名称: " + crop_name + "\n" +
"单价: " + str(unit_price) + " 元/个\n" +
"可出售数量: " + str(max_count) + "\n" +
"描述: " + crop_desc + "\n\n" +
"请输入出售数量:"
)
# 重置出售数量为1
sell_num_edit.text = "1"
# 显示弹窗并居中
self.show()
self.move_to_front()
# 处理数量输入变化
func _on_sell_num_changed(new_text: String):
# 只允许输入数字
var filtered_text = ""
for char in new_text:
if char.is_valid_int():
filtered_text += char
if filtered_text != new_text:
sell_num_edit.text = filtered_text
sell_num_edit.caret_column = filtered_text.length()
# 更新总价显示
_update_total_income()
# 更新总收入显示
func _update_total_income():
var quantity = get_sell_quantity()
var total_income = quantity * current_unit_price
# 检查数量是否超过最大可售数量
var quantity_status = ""
if quantity > current_max_count:
quantity_status = " (超出库存!)"
var income_info = "\n出售数量: " + str(quantity) + "" + quantity_status + "\n总收入: " + str(total_income) + ""
# 更新内容显示
var base_content = str(
"作物名称: " + current_crop_name + "\n" +
"单价: " + str(current_unit_price) + " 元/个\n" +
"可出售数量: " + str(current_max_count) + "\n" +
"描述: " + current_crop_desc + "\n\n" +
"请输入出售数量:"
)
contents.text = base_content + income_info
# 获取出售数量
func get_sell_quantity() -> int:
var text = sell_num_edit.text.strip_edges()
if text.is_empty():
return 1
var quantity = text.to_int()
return max(1, quantity) # 至少出售1个
# 确认出售按钮处理
func _on_sure_button_pressed():
var quantity = get_sell_quantity()
if quantity <= 0:
_show_error("出售数量必须大于0")
return
if quantity > current_max_count:
_show_error("出售数量不能超过库存数量(" + str(current_max_count) + ")")
return
# 调用确认回调函数
if confirm_callback.is_valid():
confirm_callback.call(current_crop_name, quantity, current_unit_price)
# 隐藏弹窗
self.hide()
# 取消出售按钮处理
func _on_cancel_button_pressed():
# 调用取消回调函数
if cancel_callback.is_valid():
cancel_callback.call()
# 隐藏弹窗
self.hide()
# 显示错误信息
func _show_error(message: String):
# 显示Toast错误提示
if has_node("/root/Toast"):
get_node("/root/Toast").show(message, Color.RED, 2.0, 1.0)
else:
print("批量出售弹窗错误: " + message)

View File

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

View File

@@ -0,0 +1,216 @@
extends Panel
@onready var quit_button: Button = $QuitButton #关闭作物信息面板
@onready var crop_image: TextureRect = $VBox/CropImage #显示作物图片
@onready var crop_name: Label = $VBox/CropName #作物名称
@onready var crop_description: Label = $VBox/CropDescription #作物介绍
@onready var crop_price: Label = $VBox/CropPrice #作物价格
@onready var crop_quality: Label = $VBox/CropQuality #作物品质
@onready var sale_product: Button = $VBox/HBox/SaleProduct #直接出售
@onready var add_to_store: Button = $VBox/HBox/AddToStore #添加到小卖部
@onready var add_product_to_store_popup: PanelContainer = $'../../DiaLog/AddProductToStorePopup'
# 当前显示的作物信息
var current_crop_name: String = ""
var current_crop_count: int = 0
# 获取主游戏引用
@onready var main_game = get_node("/root/main")
func _ready():
# 连接按钮信号
quit_button.pressed.connect(_on_quit_button_pressed)
sale_product.pressed.connect(_on_sale_product_pressed)
add_to_store.pressed.connect(_on_add_to_store_pressed)
# 默认隐藏面板
self.hide()
# 显示作物信息
func show_crop_info(crop_name: String, crop_count: int):
current_crop_name = crop_name
current_crop_count = crop_count
# 更新作物信息显示
_update_crop_display()
# 显示面板
self.show()
self.move_to_front()
# 更新作物信息显示
func _update_crop_display():
if not main_game.can_planted_crop.has(current_crop_name):
crop_name.text = "作物名称:" + current_crop_name
crop_description.text = "描述:未知作物"
crop_price.text = "收购价:未知"
crop_quality.text = "品质:未知"
return
var crop_data = main_game.can_planted_crop[current_crop_name]
# 获取显示名称
var display_name = current_crop_name
var mature_name = crop_data.get("成熟物名称")
if mature_name != null and mature_name != "":
display_name = mature_name
else:
display_name = crop_data.get("作物名称", current_crop_name)
# 更新文本显示
crop_name.text = "作物名称:" + display_name + " (数量: " + str(current_crop_count) + ")"
crop_description.text = "描述:" + crop_data.get("描述", "美味的作物")
# 计算出售价格(基于收益)
var sell_price = crop_data.get("收益", 0)
crop_price.text = "收购价:" + str(sell_price) + " 元/个"
var quality = crop_data.get("品质", "普通")
crop_quality.text = "品质:" + quality
# 更新作物图片
_update_crop_image()
# 更新作物图片
func _update_crop_image():
var texture = _get_crop_harvest_texture(current_crop_name)
if texture:
crop_image.texture = texture
else:
# 使用默认图片
var default_texture = _get_crop_harvest_texture("默认")
if default_texture:
crop_image.texture = default_texture
# 获取作物的收获物图片
func _get_crop_harvest_texture(crop_name: String) -> Texture2D:
var crop_path = "res://assets/作物/" + crop_name + "/"
var harvest_texture_path = crop_path + "收获物.webp"
if ResourceLoader.exists(harvest_texture_path):
var texture = load(harvest_texture_path)
if texture:
return texture
# 如果没有找到,使用默认的收获物图片
var default_harvest_path = "res://assets/作物/默认/收获物.webp"
if ResourceLoader.exists(default_harvest_path):
var texture = load(default_harvest_path)
if texture:
return texture
return null
# 关闭面板
func _on_quit_button_pressed():
self.hide()
# 直接出售按钮处理
func _on_sale_product_pressed():
# 检查是否在访问模式
if main_game.is_visiting_mode:
Toast.show("访问模式下无法出售作物", Color.ORANGE, 2.0, 1.0)
return
# 获取批量出售弹窗
var batch_sell_popup = get_node_or_null("/root/main/UI/DiaLog/BatchSellPopup")
if batch_sell_popup and batch_sell_popup.has_method("show_sell_popup"):
# 获取作物数据以传递给出售弹窗
var crop_data = main_game.can_planted_crop.get(current_crop_name, {})
var sell_price = crop_data.get("收益", 0)
var description = crop_data.get("描述", "美味的作物")
# 显示批量出售弹窗
batch_sell_popup.show_sell_popup(
current_crop_name,
current_crop_count,
sell_price,
description,
_on_confirm_sell_crop,
_on_cancel_sell_crop
)
else:
Toast.show("批量出售功能暂未实现", Color.RED, 2.0, 1.0)
print("错误找不到BatchSellPopup或相关方法")
# 确认出售作物回调
func _on_confirm_sell_crop(crop_name: String, sell_count: int, unit_price: int):
# 发送出售请求到服务器
var tcp_network_manager = get_node_or_null("/root/main/UI/BigPanel/TCPNetworkManagerPanel")
if tcp_network_manager and tcp_network_manager.has_method("send_message"):
var message = {
"type": "sell_crop",
"crop_name": crop_name,
"sell_count": sell_count,
"unit_price": unit_price
}
tcp_network_manager.send_message(message)
# 关闭作物信息面板
self.hide()
Toast.show("出售请求已发送", Color.YELLOW, 2.0, 1.0)
else:
Toast.show("网络连接异常,无法出售", Color.RED, 2.0, 1.0)
# 取消出售作物回调
func _on_cancel_sell_crop():
# 不需要做任何事情,弹窗会自动关闭
pass
# 添加到小卖部按钮处理
func _on_add_to_store_pressed():
# 检查是否在访问模式
if main_game.is_visiting_mode:
Toast.show("访问模式下无法操作小卖部", Color.ORANGE, 2.0, 1.0)
return
# 获取添加商品到小卖部的弹窗
if add_product_to_store_popup and add_product_to_store_popup.has_method("show_add_product_popup"):
# 获取作物数据以传递给弹窗
var crop_data = main_game.can_planted_crop.get(current_crop_name, {})
var sell_price = crop_data.get("收益", 0)
var description = crop_data.get("描述", "美味的作物")
# 显示添加商品弹窗
add_product_to_store_popup.show_add_product_popup(
current_crop_name,
current_crop_count,
sell_price,
description,
_on_confirm_add_to_store,
_on_cancel_add_to_store
)
else:
Toast.show("添加商品功能暂未实现", Color.RED, 2.0, 1.0)
print("错误找不到AddProduct2StorePopup或相关方法")
# 确认添加到小卖部回调
func _on_confirm_add_to_store(crop_name: String, add_count: int, unit_price: int):
# 发送添加商品到小卖部的请求到服务器
var tcp_network_manager = get_node_or_null("/root/main/UI/BigPanel/TCPNetworkManagerPanel")
if tcp_network_manager and tcp_network_manager.has_method("send_message"):
var message = {
"type": "add_product_to_store",
"product_type": "作物",
"product_name": crop_name,
"product_count": add_count,
"product_price": unit_price
}
tcp_network_manager.send_message(message)
# 关闭作物信息面板
self.hide()
Toast.show("添加商品请求已发送", Color.YELLOW, 2.0, 1.0)
else:
Toast.show("网络连接异常,无法添加商品", Color.RED, 2.0, 1.0)
# 取消添加到小卖部回调
func _on_cancel_add_to_store():
# 不需要做任何事情,弹窗会自动关闭
pass

View File

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

View File

@@ -98,7 +98,12 @@ func _update_performance_data():
# 从主游戏获取加载信息 # 从主游戏获取加载信息
if main_game and main_game.crop_texture_manager: if main_game and main_game.crop_texture_manager:
var manager = main_game.crop_texture_manager var manager = main_game.crop_texture_manager
performance_data["loaded_textures"] = manager.texture_cache.size() + manager.mature_texture_cache.size() # 计算所有加载的纹理数量(新的三阶段系统)
var total_textures = 0
for crop_name in manager.texture_cache.keys():
total_textures += manager.texture_cache[crop_name].size()
total_textures += manager.default_textures.size()
performance_data["loaded_textures"] = total_textures
performance_data["failed_textures"] = manager.failed_resources.size() performance_data["failed_textures"] = manager.failed_resources.size()
# 加载进度 # 加载进度

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -12,43 +12,43 @@ uniform float height_curve : hint_range(1.0, 4.0) = 2.0; // 高度影响曲线
void fragment() { void fragment() {
vec2 uv = UV; vec2 uv = UV;
// 计算摆动强度(只有上半部分摆动) // 计算摆动强度(只有上半部分摆动)
float height_factor = 0.0; float height_factor = 0.0;
if (uv.y < sway_start_height) { if (uv.y < sway_start_height) {
// 计算从底部到摆动开始位置的渐变 // 计算从底部到摆动开始位置的渐变
height_factor = pow((sway_start_height - uv.y) / sway_start_height, height_curve); height_factor = pow((sway_start_height - uv.y) / sway_start_height, height_curve);
} }
// 创建多层摆动效果 // 创建多层摆动效果
float time_offset = TIME * sway_speed; float time_offset = TIME * sway_speed;
// 主摆动波 // 主摆动波
float main_sway = sin(time_offset + uv.y * 3.14159) * sway_strength; float main_sway = sin(time_offset + uv.y * 3.14159) * sway_strength;
// 次级摆动波(频率更高,幅度更小) // 次级摆动波(频率更高,幅度更小)
float secondary_sway = sin(time_offset * 2.3 + uv.y * 6.28318) * sway_strength * 0.3; float secondary_sway = sin(time_offset * 2.3 + uv.y * 6.28318) * sway_strength * 0.3;
// 第三层摆动(更细微的抖动) // 第三层摆动(更细微的抖动)
float micro_sway = sin(time_offset * 4.7 + uv.y * 12.56636) * sway_strength * 0.1; float micro_sway = sin(time_offset * 4.7 + uv.y * 12.56636) * sway_strength * 0.1;
// 结合所有摆动 // 结合所有摆动
float total_sway = (main_sway + secondary_sway + micro_sway) * height_factor; float total_sway = (main_sway + secondary_sway + micro_sway) * height_factor;
// 添加风向偏移 // 添加风向偏移
total_sway += wind_direction * sway_strength * height_factor * 0.5; total_sway += wind_direction * sway_strength * height_factor * 0.5;
// 添加摆动变化(随机性) // 添加摆动变化(随机性)
float variation = sin(time_offset * 0.37 + uv.x * 6.28318) * sway_variation * 0.01; float variation = sin(time_offset * 0.37 + uv.x * 6.28318) * sway_variation * 0.01;
total_sway += variation * height_factor; total_sway += variation * height_factor;
// 应用摆动到UV坐标 // 应用摆动到UV坐标
uv.x += total_sway; uv.x += total_sway;
// 边界检查防止UV超出范围 // 边界检查防止UV超出范围
if (uv.x < 0.0 || uv.x > 1.0) { if (uv.x < 0.0 || uv.x > 1.0) {
COLOR = vec4(0.0, 0.0, 0.0, 0.0); // 透明 COLOR = vec4(0.0, 0.0, 0.0, 0.0); // 透明
} else { } else {
COLOR = texture(TEXTURE, uv); COLOR = texture(TEXTURE, uv);
} }
} }

View File

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View File

@@ -3,15 +3,15 @@
importer="texture" importer="texture"
type="CompressedTexture2D" type="CompressedTexture2D"
uid="uid://xyj4ro44cwj5" uid="uid://xyj4ro44cwj5"
path="res://.godot/imported/0.webp-9339f1eb71d8e2d2c9d6eff2a61109e8.ctex" path="res://.godot/imported/幼苗.webp-e31b638e539187dd68d4f0b356b0ede9.ctex"
metadata={ metadata={
"vram_texture": false "vram_texture": false
} }
[deps] [deps]
source_file="res://assets/作物/人参/0.webp" source_file="res://assets/作物/人参/幼苗.webp"
dest_files=["res://.godot/imported/0.webp-9339f1eb71d8e2d2c9d6eff2a61109e8.ctex"] dest_files=["res://.godot/imported/幼苗.webp-e31b638e539187dd68d4f0b356b0ede9.ctex"]
[params] [params]

View File

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View File

@@ -3,15 +3,15 @@
importer="texture" importer="texture"
type="CompressedTexture2D" type="CompressedTexture2D"
uid="uid://btro2s0v3vjvc" uid="uid://btro2s0v3vjvc"
path="res://.godot/imported/0.webp-a498150286b3ef11bcaf7062fb7c4c72.ctex" path="res://.godot/imported/幼苗.webp-d7486902f1f60fe55e6aa621b78d2bdd.ctex"
metadata={ metadata={
"vram_texture": false "vram_texture": false
} }
[deps] [deps]
source_file="res://assets/作物/仙人掌/0.webp" source_file="res://assets/作物/仙人掌/幼苗.webp"
dest_files=["res://.godot/imported/0.webp-a498150286b3ef11bcaf7062fb7c4c72.ctex"] dest_files=["res://.godot/imported/幼苗.webp-d7486902f1f60fe55e6aa621b78d2bdd.ctex"]
[params] [params]

View File

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

@@ -3,15 +3,15 @@
importer="texture" importer="texture"
type="CompressedTexture2D" type="CompressedTexture2D"
uid="uid://nh4rwteg18hf" uid="uid://nh4rwteg18hf"
path="res://.godot/imported/1.webp-eac2af28e41e5166de4e45fa1d9b023c.ctex" path="res://.godot/imported/未成熟.webp-e0f54244cf971f24edbb0bf5ab6f5b9d.ctex"
metadata={ metadata={
"vram_texture": false "vram_texture": false
} }
[deps] [deps]
source_file="res://assets/作物/仙人掌/1.webp" source_file="res://assets/作物/仙人掌/未成熟.webp"
dest_files=["res://.godot/imported/1.webp-eac2af28e41e5166de4e45fa1d9b023c.ctex"] dest_files=["res://.godot/imported/未成熟.webp-e0f54244cf971f24edbb0bf5ab6f5b9d.ctex"]
[params] [params]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

View File

@@ -1,34 +0,0 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://2tms3lcydcf7"
path="res://.godot/imported/1.webp-1c762135840fee82b6f1524cf7b93c28.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/作物/冬虫夏草/1.webp"
dest_files=["res://.godot/imported/1.webp-1c762135840fee82b6f1524cf7b93c28.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.01
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

View File

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -3,15 +3,15 @@
importer="texture" importer="texture"
type="CompressedTexture2D" type="CompressedTexture2D"
uid="uid://dr3cu2f7agkgk" uid="uid://dr3cu2f7agkgk"
path="res://.godot/imported/0.webp-8e6372f99a77669bfdae2b147d801863.ctex" path="res://.godot/imported/幼苗.webp-30da2eafd5a696c6c1eca5ffdc30f96f.ctex"
metadata={ metadata={
"vram_texture": false "vram_texture": false
} }
[deps] [deps]
source_file="res://assets/作物/冬虫夏草/0.webp" source_file="res://assets/作物/冬虫夏草/幼苗.webp"
dest_files=["res://.godot/imported/0.webp-8e6372f99a77669bfdae2b147d801863.ctex"] dest_files=["res://.godot/imported/幼苗.webp-30da2eafd5a696c6c1eca5ffdc30f96f.ctex"]
[params] [params]

View File

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View File

@@ -3,15 +3,15 @@
importer="texture" importer="texture"
type="CompressedTexture2D" type="CompressedTexture2D"
uid="uid://dcn3nga3a3n6a" uid="uid://dcn3nga3a3n6a"
path="res://.godot/imported/2.webp-62669dec635d4d6139cbede94abc0c42.ctex" path="res://.godot/imported/未成熟.webp-ab438ee4d595b7620c449192b5775f38.ctex"
metadata={ metadata={
"vram_texture": false "vram_texture": false
} }
[deps] [deps]
source_file="res://assets/作物/冬虫夏草/2.webp" source_file="res://assets/作物/冬虫夏草/未成熟.webp"
dest_files=["res://.godot/imported/2.webp-62669dec635d4d6139cbede94abc0c42.ctex"] dest_files=["res://.godot/imported/未成熟.webp-ab438ee4d595b7620c449192b5775f38.ctex"]
[params] [params]

View File

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

View File

@@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://b3yb6xi5dif75"
path="res://.godot/imported/幼苗.webp-a4b4bf49ecdb32ea6d2abba5c9629e01.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/作物/凤凰木/幼苗.webp"
dest_files=["res://.godot/imported/幼苗.webp-a4b4bf49ecdb32ea6d2abba5c9629e01.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.01
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

View File

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 33 KiB

View File

@@ -3,15 +3,15 @@
importer="texture" importer="texture"
type="CompressedTexture2D" type="CompressedTexture2D"
uid="uid://b7ko81p17vwd5" uid="uid://b7ko81p17vwd5"
path="res://.godot/imported/1.webp-70a0c6dc2f51cf788ff580d54c9c392f.ctex" path="res://.godot/imported/未成熟.webp-0769b207da58122cbb7ec64d5b2a2941.ctex"
metadata={ metadata={
"vram_texture": false "vram_texture": false
} }
[deps] [deps]
source_file="res://assets/作物/凤凰木/1.webp" source_file="res://assets/作物/凤凰木/未成熟.webp"
dest_files=["res://.godot/imported/1.webp-70a0c6dc2f51cf788ff580d54c9c392f.ctex"] dest_files=["res://.godot/imported/未成熟.webp-0769b207da58122cbb7ec64d5b2a2941.ctex"]
[params] [params]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

View File

@@ -1,34 +0,0 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://mtmunwgy1x3g"
path="res://.godot/imported/3.webp-7bbb31894686faa8c9080a58b509200d.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/作物/南瓜/3.webp"
dest_files=["res://.godot/imported/3.webp-7bbb31894686faa8c9080a58b509200d.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.01
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

View File

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

View File

@@ -3,15 +3,15 @@
importer="texture" importer="texture"
type="CompressedTexture2D" type="CompressedTexture2D"
uid="uid://bhynib53o87sv" uid="uid://bhynib53o87sv"
path="res://.godot/imported/0.webp-d98890577b76bfa710d6a00e6916c0c7.ctex" path="res://.godot/imported/幼苗.webp-c454289b425b29d0c91fa12480484aa0.ctex"
metadata={ metadata={
"vram_texture": false "vram_texture": false
} }
[deps] [deps]
source_file="res://assets/作物/南瓜/0.webp" source_file="res://assets/作物/南瓜/幼苗.webp"
dest_files=["res://.godot/imported/0.webp-d98890577b76bfa710d6a00e6916c0c7.ctex"] dest_files=["res://.godot/imported/幼苗.webp-c454289b425b29d0c91fa12480484aa0.ctex"]
[params] [params]

View File

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View File

@@ -3,15 +3,15 @@
importer="texture" importer="texture"
type="CompressedTexture2D" type="CompressedTexture2D"
uid="uid://dcmcy8sk6qeuj" uid="uid://dcmcy8sk6qeuj"
path="res://.godot/imported/1.webp-113308ca15b586eaeb0bbd809b6997c6.ctex" path="res://.godot/imported/未成熟.webp-180314de08cf809eae5e8bf494c6f569.ctex"
metadata={ metadata={
"vram_texture": false "vram_texture": false
} }
[deps] [deps]
source_file="res://assets/作物/南瓜/1.webp" source_file="res://assets/作物/南瓜/未成熟.webp"
dest_files=["res://.godot/imported/1.webp-113308ca15b586eaeb0bbd809b6997c6.ctex"] dest_files=["res://.godot/imported/未成熟.webp-180314de08cf809eae5e8bf494c6f569.ctex"]
[params] [params]

View File

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View File

@@ -3,15 +3,15 @@
importer="texture" importer="texture"
type="CompressedTexture2D" type="CompressedTexture2D"
uid="uid://m0k2go1722l3" uid="uid://m0k2go1722l3"
path="res://.godot/imported/0.webp-821822db21f66aa9245299fab7cf906e.ctex" path="res://.godot/imported/幼苗.webp-afd9dee9030c742a3a58654be7b5150f.ctex"
metadata={ metadata={
"vram_texture": false "vram_texture": false
} }
[deps] [deps]
source_file="res://assets/作物/可可豆/0.webp" source_file="res://assets/作物/可可豆/幼苗.webp"
dest_files=["res://.godot/imported/0.webp-821822db21f66aa9245299fab7cf906e.ctex"] dest_files=["res://.godot/imported/幼苗.webp-afd9dee9030c742a3a58654be7b5150f.ctex"]
[params] [params]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

View File

@@ -1,34 +0,0 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bxhe4pl7e2h4r"
path="res://.godot/imported/2.webp-a4ac518035e8dc36ed57f415183fccf4.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/作物/向日葵/2.webp"
dest_files=["res://.godot/imported/2.webp-a4ac518035e8dc36ed57f415183fccf4.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.01
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

View File

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View File

@@ -3,15 +3,15 @@
importer="texture" importer="texture"
type="CompressedTexture2D" type="CompressedTexture2D"
uid="uid://cgvoioriuf7y0" uid="uid://cgvoioriuf7y0"
path="res://.godot/imported/0.webp-e38fa2090339e41d8e2bc2f4382d5f43.ctex" path="res://.godot/imported/幼苗.webp-193e6077d0df53351f2012da9f7451e7.ctex"
metadata={ metadata={
"vram_texture": false "vram_texture": false
} }
[deps] [deps]
source_file="res://assets/作物/向日葵/0.webp" source_file="res://assets/作物/向日葵/幼苗.webp"
dest_files=["res://.godot/imported/0.webp-e38fa2090339e41d8e2bc2f4382d5f43.ctex"] dest_files=["res://.godot/imported/幼苗.webp-193e6077d0df53351f2012da9f7451e7.ctex"]
[params] [params]

View File

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

@@ -3,15 +3,15 @@
importer="texture" importer="texture"
type="CompressedTexture2D" type="CompressedTexture2D"
uid="uid://wqfspwqqpcwa" uid="uid://wqfspwqqpcwa"
path="res://.godot/imported/1.webp-39c5186218d6a70b3b214094d5602b76.ctex" path="res://.godot/imported/未成熟.webp-6b7798c51cbe39e5ab328bc5836f3c9b.ctex"
metadata={ metadata={
"vram_texture": false "vram_texture": false
} }
[deps] [deps]
source_file="res://assets/作物/向日葵/1.webp" source_file="res://assets/作物/向日葵/未成熟.webp"
dest_files=["res://.godot/imported/1.webp-39c5186218d6a70b3b214094d5602b76.ctex"] dest_files=["res://.godot/imported/未成熟.webp-6b7798c51cbe39e5ab328bc5836f3c9b.ctex"]
[params] [params]

View File

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

@@ -3,15 +3,15 @@
importer="texture" importer="texture"
type="CompressedTexture2D" type="CompressedTexture2D"
uid="uid://bvcmrkatbo0f1" uid="uid://bvcmrkatbo0f1"
path="res://.godot/imported/0.webp-6d779ef7b648b1e546e4ba9e87048adb.ctex" path="res://.godot/imported/幼苗.webp-63eb1edffbc9e3e228ea5afcf106ea2a.ctex"
metadata={ metadata={
"vram_texture": false "vram_texture": false
} }
[deps] [deps]
source_file="res://assets/作物/咖啡豆/0.webp" source_file="res://assets/作物/咖啡豆/幼苗.webp"
dest_files=["res://.godot/imported/0.webp-6d779ef7b648b1e546e4ba9e87048adb.ctex"] dest_files=["res://.godot/imported/幼苗.webp-63eb1edffbc9e3e228ea5afcf106ea2a.ctex"]
[params] [params]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

View File

@@ -1,34 +0,0 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://b7rryqoraiind"
path="res://.godot/imported/1.webp-1f85d6df04e3014f721dc62f7c60a301.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/作物/哈密瓜/1.webp"
dest_files=["res://.godot/imported/1.webp-1f85d6df04e3014f721dc62f7c60a301.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.01
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

View File

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

View File

@@ -3,15 +3,15 @@
importer="texture" importer="texture"
type="CompressedTexture2D" type="CompressedTexture2D"
uid="uid://bilp5c3p4muup" uid="uid://bilp5c3p4muup"
path="res://.godot/imported/0.webp-44b93bb80f1aa61722d002b9c7673b92.ctex" path="res://.godot/imported/幼苗.webp-8799bc4c3eb57cb4d190ad1a2f2aa952.ctex"
metadata={ metadata={
"vram_texture": false "vram_texture": false
} }
[deps] [deps]
source_file="res://assets/作物/哈密瓜/0.webp" source_file="res://assets/作物/哈密瓜/幼苗.webp"
dest_files=["res://.godot/imported/0.webp-44b93bb80f1aa61722d002b9c7673b92.ctex"] dest_files=["res://.godot/imported/幼苗.webp-8799bc4c3eb57cb4d190ad1a2f2aa952.ctex"]
[params] [params]

View File

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View File

@@ -3,15 +3,15 @@
importer="texture" importer="texture"
type="CompressedTexture2D" type="CompressedTexture2D"
uid="uid://by01gwdqm2b25" uid="uid://by01gwdqm2b25"
path="res://.godot/imported/2.webp-241c30c524225cf14a34f44113ad84e5.ctex" path="res://.godot/imported/未成熟.webp-ef1ae6a286c854a08ebc8551517f6823.ctex"
metadata={ metadata={
"vram_texture": false "vram_texture": false
} }
[deps] [deps]
source_file="res://assets/作物/哈密瓜/2.webp" source_file="res://assets/作物/哈密瓜/未成熟.webp"
dest_files=["res://.godot/imported/2.webp-241c30c524225cf14a34f44113ad84e5.ctex"] dest_files=["res://.godot/imported/未成熟.webp-ef1ae6a286c854a08ebc8551517f6823.ctex"]
[params] [params]

View File

@@ -1,34 +0,0 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cfbyrlvyw7mbm"
path="res://.godot/imported/0.webp-7c561674e7465fe1b7ab139e2d86374d.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/作物/土豆/0.webp"
dest_files=["res://.godot/imported/0.webp-7c561674e7465fe1b7ab139e2d86374d.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.01
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

View File

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

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

@@ -3,15 +3,15 @@
importer="texture" importer="texture"
type="CompressedTexture2D" type="CompressedTexture2D"
uid="uid://bkn5q3cyenc0q" uid="uid://bkn5q3cyenc0q"
path="res://.godot/imported/1.webp-f108974cb62a8d6c198d2e6263bb15ff.ctex" path="res://.godot/imported/幼苗.webp-2dd945057ed9aef6aa603482ab806e5d.ctex"
metadata={ metadata={
"vram_texture": false "vram_texture": false
} }
[deps] [deps]
source_file="res://assets/作物/土豆/1.webp" source_file="res://assets/作物/土豆/幼苗.webp"
dest_files=["res://.godot/imported/1.webp-f108974cb62a8d6c198d2e6263bb15ff.ctex"] dest_files=["res://.godot/imported/幼苗.webp-2dd945057ed9aef6aa603482ab806e5d.ctex"]
[params] [params]

View File

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

View File

@@ -2,16 +2,16 @@
importer="texture" importer="texture"
type="CompressedTexture2D" type="CompressedTexture2D"
uid="uid://dnb0afavrjkbx" uid="uid://dig8kyw0tib3"
path="res://.godot/imported/4.webp-09e380791e9c9ce6f1a8aefbef1f05a1.ctex" path="res://.godot/imported/未成熟.webp-e6ea031a6f258edaec1f424b49b0de94.ctex"
metadata={ metadata={
"vram_texture": false "vram_texture": false
} }
[deps] [deps]
source_file="res://assets/作物/茄子/4.webp" source_file="res://assets/作物/土豆/未成熟.webp"
dest_files=["res://.godot/imported/4.webp-09e380791e9c9ce6f1a8aefbef1f05a1.ctex"] dest_files=["res://.godot/imported/未成熟.webp-e6ea031a6f258edaec1f424b49b0de94.ctex"]
[params] [params]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

View File

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

View File

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View File

@@ -3,15 +3,15 @@
importer="texture" importer="texture"
type="CompressedTexture2D" type="CompressedTexture2D"
uid="uid://cla1xws7k5qbo" uid="uid://cla1xws7k5qbo"
path="res://.godot/imported/0.webp-95fd204d42c46a44e3c4313652f5ffce.ctex" path="res://.godot/imported/幼苗.webp-43a7c9b6afafbf0d5e6af53488d2eff9.ctex"
metadata={ metadata={
"vram_texture": false "vram_texture": false
} }
[deps] [deps]
source_file="res://assets/作物/大白菜/0.webp" source_file="res://assets/作物/大白菜/幼苗.webp"
dest_files=["res://.godot/imported/0.webp-95fd204d42c46a44e3c4313652f5ffce.ctex"] dest_files=["res://.godot/imported/幼苗.webp-43a7c9b6afafbf0d5e6af53488d2eff9.ctex"]
[params] [params]

View File

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

View File

@@ -3,15 +3,15 @@
importer="texture" importer="texture"
type="CompressedTexture2D" type="CompressedTexture2D"
uid="uid://dftmxuhrl4jqa" uid="uid://dftmxuhrl4jqa"
path="res://.godot/imported/2.webp-bdd6486dc35f8c758136190cc6fa9895.ctex" path="res://.godot/imported/未成熟.webp-2f315bd8829c1b18106ea1b7cbeb08d1.ctex"
metadata={ metadata={
"vram_texture": false "vram_texture": false
} }
[deps] [deps]
source_file="res://assets/作物/大白菜/2.webp" source_file="res://assets/作物/大白菜/未成熟.webp"
dest_files=["res://.godot/imported/2.webp-bdd6486dc35f8c758136190cc6fa9895.ctex"] dest_files=["res://.godot/imported/未成熟.webp-2f315bd8829c1b18106ea1b7cbeb08d1.ctex"]
[params] [params]

View File

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View File

@@ -3,15 +3,15 @@
importer="texture" importer="texture"
type="CompressedTexture2D" type="CompressedTexture2D"
uid="uid://8ncjpot0587o" uid="uid://8ncjpot0587o"
path="res://.godot/imported/0.webp-667c2ea589e0f98450ef6af17a7a5f5b.ctex" path="res://.godot/imported/幼苗.webp-9ff6d4c1a71eb35de524cfcce9a4d803.ctex"
metadata={ metadata={
"vram_texture": false "vram_texture": false
} }
[deps] [deps]
source_file="res://assets/作物/大蒜/0.webp" source_file="res://assets/作物/大蒜/幼苗.webp"
dest_files=["res://.godot/imported/0.webp-667c2ea589e0f98450ef6af17a7a5f5b.ctex"] dest_files=["res://.godot/imported/幼苗.webp-9ff6d4c1a71eb35de524cfcce9a4d803.ctex"]
[params] [params]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

View File

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

View File

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -3,15 +3,15 @@
importer="texture" importer="texture"
type="CompressedTexture2D" type="CompressedTexture2D"
uid="uid://d0j0eifp0iemu" uid="uid://d0j0eifp0iemu"
path="res://.godot/imported/0.webp-d2cef997bf4d87930aa951d63b7c2706.ctex" path="res://.godot/imported/幼苗.webp-bb6a44973037d348d8f253c2318a4b11.ctex"
metadata={ metadata={
"vram_texture": false "vram_texture": false
} }
[deps] [deps]
source_file="res://assets/作物/大豆/0.webp" source_file="res://assets/作物/大豆/幼苗.webp"
dest_files=["res://.godot/imported/0.webp-d2cef997bf4d87930aa951d63b7c2706.ctex"] dest_files=["res://.godot/imported/幼苗.webp-bb6a44973037d348d8f253c2318a4b11.ctex"]
[params] [params]

View File

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

@@ -3,15 +3,15 @@
importer="texture" importer="texture"
type="CompressedTexture2D" type="CompressedTexture2D"
uid="uid://cofjstbs0r8h0" uid="uid://cofjstbs0r8h0"
path="res://.godot/imported/1.webp-902de037c7b6f80519e6d76f562055ed.ctex" path="res://.godot/imported/未成熟.webp-4e2ae24acb538888e1f85c849bd74a22.ctex"
metadata={ metadata={
"vram_texture": false "vram_texture": false
} }
[deps] [deps]
source_file="res://assets/作物/大豆/1.webp" source_file="res://assets/作物/大豆/未成熟.webp"
dest_files=["res://.godot/imported/1.webp-902de037c7b6f80519e6d76f562055ed.ctex"] dest_files=["res://.godot/imported/未成熟.webp-4e2ae24acb538888e1f85c849bd74a22.ctex"]
[params] [params]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

View File

@@ -1,34 +0,0 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://5x2uq2r3yjms"
path="res://.godot/imported/2.webp-638bab14e5309cf618b4ad0d9893879c.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/作物/富贵竹/2.webp"
dest_files=["res://.godot/imported/2.webp-638bab14e5309cf618b4ad0d9893879c.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.01
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

View File

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

View File

@@ -3,15 +3,15 @@
importer="texture" importer="texture"
type="CompressedTexture2D" type="CompressedTexture2D"
uid="uid://clfqb3o1k4rby" uid="uid://clfqb3o1k4rby"
path="res://.godot/imported/0.webp-a726644bf3d2533e1a0c1dab78519549.ctex" path="res://.godot/imported/幼苗.webp-fc281ae82dc0894a59b7e69aa4caf221.ctex"
metadata={ metadata={
"vram_texture": false "vram_texture": false
} }
[deps] [deps]
source_file="res://assets/作物/富贵竹/0.webp" source_file="res://assets/作物/富贵竹/幼苗.webp"
dest_files=["res://.godot/imported/0.webp-a726644bf3d2533e1a0c1dab78519549.ctex"] dest_files=["res://.godot/imported/幼苗.webp-fc281ae82dc0894a59b7e69aa4caf221.ctex"]
[params] [params]

View File

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

View File

@@ -3,15 +3,15 @@
importer="texture" importer="texture"
type="CompressedTexture2D" type="CompressedTexture2D"
uid="uid://bd3omqp1ps1hw" uid="uid://bd3omqp1ps1hw"
path="res://.godot/imported/1.webp-e919d49ea2e08a7abff7233ed4b5039a.ctex" path="res://.godot/imported/未成熟.webp-cdc0b439ef04abe0bed4481eaea3017c.ctex"
metadata={ metadata={
"vram_texture": false "vram_texture": false
} }
[deps] [deps]
source_file="res://assets/作物/富贵竹/1.webp" source_file="res://assets/作物/富贵竹/未成熟.webp"
dest_files=["res://.godot/imported/1.webp-e919d49ea2e08a7abff7233ed4b5039a.ctex"] dest_files=["res://.godot/imported/未成熟.webp-cdc0b439ef04abe0bed4481eaea3017c.ctex"]
[params] [params]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

View File

@@ -1,34 +0,0 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://4cbuoe4jv4qf"
path="res://.godot/imported/2.webp-944f6e4f9f746fb1e8751aa4709965cf.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/作物/小麦/2.webp"
dest_files=["res://.godot/imported/2.webp-944f6e4f9f746fb1e8751aa4709965cf.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.01
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

View File

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 33 KiB

View File

@@ -3,15 +3,15 @@
importer="texture" importer="texture"
type="CompressedTexture2D" type="CompressedTexture2D"
uid="uid://lu6s5qts4hnv" uid="uid://lu6s5qts4hnv"
path="res://.godot/imported/0.webp-01976b7393f4108b4278b5fddaf5c9f1.ctex" path="res://.godot/imported/幼苗.webp-c9bfd368c0884062ab89b3e32f3a883f.ctex"
metadata={ metadata={
"vram_texture": false "vram_texture": false
} }
[deps] [deps]
source_file="res://assets/作物/小麦/0.webp" source_file="res://assets/作物/小麦/幼苗.webp"
dest_files=["res://.godot/imported/0.webp-01976b7393f4108b4278b5fddaf5c9f1.ctex"] dest_files=["res://.godot/imported/幼苗.webp-c9bfd368c0884062ab89b3e32f3a883f.ctex"]
[params] [params]

View File

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 38 KiB

View File

@@ -3,15 +3,15 @@
importer="texture" importer="texture"
type="CompressedTexture2D" type="CompressedTexture2D"
uid="uid://doqkqexho8u2" uid="uid://doqkqexho8u2"
path="res://.godot/imported/1.webp-aecdb4ce7bebcc6234fa8729e020c125.ctex" path="res://.godot/imported/未成熟.webp-bb4304385d4c9de770a65d34847911d9.ctex"
metadata={ metadata={
"vram_texture": false "vram_texture": false
} }
[deps] [deps]
source_file="res://assets/作物/小麦/1.webp" source_file="res://assets/作物/小麦/未成熟.webp"
dest_files=["res://.godot/imported/1.webp-aecdb4ce7bebcc6234fa8729e020c125.ctex"] dest_files=["res://.godot/imported/未成熟.webp-bb4304385d4c9de770a65d34847911d9.ctex"]
[params] [params]

View File

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View File

@@ -3,15 +3,15 @@
importer="texture" importer="texture"
type="CompressedTexture2D" type="CompressedTexture2D"
uid="uid://qgt86c1p2dn2" uid="uid://qgt86c1p2dn2"
path="res://.godot/imported/0.webp-9ef5f54aba5e5ec96a14a0d1b8959df9.ctex" path="res://.godot/imported/幼苗.webp-49470da8a1d98df376f51873985985d2.ctex"
metadata={ metadata={
"vram_texture": false "vram_texture": false
} }
[deps] [deps]
source_file="res://assets/作物/山楂/0.webp" source_file="res://assets/作物/山楂/幼苗.webp"
dest_files=["res://.godot/imported/0.webp-9ef5f54aba5e5ec96a14a0d1b8959df9.ctex"] dest_files=["res://.godot/imported/幼苗.webp-49470da8a1d98df376f51873985985d2.ctex"]
[params] [params]

Some files were not shown because too many files have changed in this diff Show More