Files
Sprout-Farm/Script/SmallPanel/DebugPanel.gd

459 lines
16 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
extends Panel
## 调试面板 - 显示资源加载和设备性能信息
## 特别用于在移动设备上调试资源加载问题
@onready var debug_rich_text: RichTextLabel = $DebugRichText
@onready var copy_button: Button = null # 复制按钮引用
# 调试信息管理
var debug_messages: Array = []
var max_debug_messages: int = 50 # 最大保留消息数量
var update_timer: float = 0.0
var update_interval: float = 1.0 # 每秒更新一次
# 性能监控数据
var performance_data: Dictionary = {
"cpu_usage": 0.0,
"memory_usage": 0,
"memory_peak": 0,
"fps": 0.0,
"loading_progress": 0,
"loaded_textures": 0,
"failed_textures": 0,
"current_loading_item": "",
"device_info": {}
}
# 主游戏引用
var main_game = null
func _ready():
print("[DebugPanel] 调试面板已初始化")
# 获取主游戏引用
main_game = get_node("/root/main")
# 创建复制按钮
_create_copy_button()
# 初始化设备信息
_collect_device_info()
# 添加初始消息
add_debug_message("调试面板已启动", Color.GREEN)
add_debug_message("设备: " + OS.get_name(), Color.CYAN)
add_debug_message("CPU核心: " + str(OS.get_processor_count()), Color.CYAN)
func _process(delta):
update_timer += delta
if update_timer >= update_interval:
update_timer = 0.0
_update_performance_data()
_check_performance_warnings()
_update_debug_display()
## 检查性能警告
func _check_performance_warnings():
# 内存警告
var memory_mb = performance_data["memory_usage"] / (1024 * 1024)
if memory_mb > 800:
report_memory_warning(memory_mb)
# FPS警告
if performance_data["fps"] < 20 and performance_data["fps"] > 0:
report_performance_warning(performance_data["fps"])
# 加载失败警告
if performance_data["failed_textures"] > 10:
add_debug_message("⚠ 大量纹理加载失败: %d" % performance_data["failed_textures"], Color.RED)
## 收集设备基本信息
func _collect_device_info():
performance_data["device_info"] = {
"platform": OS.get_name(),
"processor_count": OS.get_processor_count(),
"processor_name": OS.get_processor_name(),
"memory_total": OS.get_static_memory_usage(),
"gpu_vendor": RenderingServer.get_video_adapter_vendor(),
"gpu_name": RenderingServer.get_video_adapter_name(),
"screen_size": DisplayServer.screen_get_size(),
"screen_dpi": DisplayServer.screen_get_dpi()
}
## 更新性能数据
func _update_performance_data():
# CPU使用率通过帧时间估算
var frame_time = Performance.get_monitor(Performance.TIME_PROCESS)
performance_data["cpu_usage"] = min(frame_time * 100.0, 100.0)
# 内存使用情况
var current_memory = OS.get_static_memory_usage()
performance_data["memory_usage"] = current_memory
if current_memory > performance_data["memory_peak"]:
performance_data["memory_peak"] = current_memory
# FPS
performance_data["fps"] = Engine.get_frames_per_second()
# 从主游戏获取加载信息
if main_game and 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()
performance_data["failed_textures"] = manager.failed_resources.size()
# 加载进度
if manager.is_loading:
var total = manager.total_crops * 2 # 序列帧 + 成熟图片
var loaded = manager.loaded_crops
performance_data["loading_progress"] = int((float(loaded) / float(total)) * 100) if total > 0 else 0
else:
performance_data["loading_progress"] = 100
## 更新调试显示
func _update_debug_display():
if not debug_rich_text:
return
var text = ""
# 为复制按钮留出空间,添加一些空行
text += "\n\n"
# 快速摘要(最重要的信息)
text += "[color=yellow][b]=== 快速摘要 ===[/b][/color]\n"
var summary_memory_mb = performance_data["memory_usage"] / (1024 * 1024)
var status_color = "green"
if performance_data["failed_textures"] > 0 or summary_memory_mb > 500 or performance_data["fps"] < 30:
status_color = "red"
elif performance_data["loading_progress"] < 100:
status_color = "yellow"
text += "[color=" + status_color + "]状态: "
if performance_data["loading_progress"] < 100:
text += "加载中 " + str(performance_data["loading_progress"]) + "%"
elif performance_data["failed_textures"] > 0:
text += "" + str(performance_data["failed_textures"]) + " 个资源加载失败"
else:
text += "正常运行"
text += "[/color]\n"
text += "[color=cyan]内存: %.1fMB | FPS: %d | 纹理: %d[/color]\n\n" % [summary_memory_mb, performance_data["fps"], performance_data["loaded_textures"]]
# 设备信息标题
text += "[color=yellow][b]=== 设备信息 ===[/b][/color]\n"
var device = performance_data["device_info"]
text += "[color=cyan]平台:[/color] " + str(device.get("platform", "未知")) + "\n"
text += "[color=cyan]CPU:[/color] " + str(device.get("processor_name", "未知")) + " (" + str(device.get("processor_count", 0)) + "核)\n"
text += "[color=cyan]GPU:[/color] " + str(device.get("gpu_name", "未知")) + "\n"
text += "[color=cyan]屏幕:[/color] " + str(device.get("screen_size", Vector2.ZERO)) + " DPI:" + str(device.get("screen_dpi", 0)) + "\n"
# 性能监控标题
text += "\n[color=yellow][b]=== 性能监控 ===[/b][/color]\n"
# CPU使用率颜色编码
var cpu_color = "green"
if performance_data["cpu_usage"] > 70:
cpu_color = "red"
elif performance_data["cpu_usage"] > 50:
cpu_color = "yellow"
text += "[color=cyan]CPU使用率:[/color] [color=" + cpu_color + "]" + "%.1f%%" % performance_data["cpu_usage"] + "[/color]\n"
# 内存使用情况(颜色编码)
var memory_mb = performance_data["memory_usage"] / (1024 * 1024)
var memory_peak_mb = performance_data["memory_peak"] / (1024 * 1024)
var memory_color = "green"
if memory_mb > 800:
memory_color = "red"
elif memory_mb > 500:
memory_color = "yellow"
text += "[color=cyan]内存使用:[/color] [color=" + memory_color + "]%.1fMB[/color] (峰值: %.1fMB)\n" % [memory_mb, memory_peak_mb]
# FPS颜色编码
var fps_color = "green"
if performance_data["fps"] < 30:
fps_color = "red"
elif performance_data["fps"] < 50:
fps_color = "yellow"
text += "[color=cyan]FPS:[/color] [color=" + fps_color + "]" + str(performance_data["fps"]) + "[/color]\n"
# 资源加载状态标题
text += "\n[color=yellow][b]=== 资源加载状态 ===[/b][/color]\n"
# 加载进度(颜色编码)
var progress_color = "yellow"
if performance_data["loading_progress"] >= 100:
progress_color = "green"
elif performance_data["loading_progress"] < 50:
progress_color = "red"
text += "[color=cyan]加载进度:[/color] [color=" + progress_color + "]" + str(performance_data["loading_progress"]) + "%[/color]\n"
# 纹理统计
text += "[color=cyan]已加载纹理:[/color] " + str(performance_data["loaded_textures"]) + "\n"
# 失败纹理(突出显示)
if performance_data["failed_textures"] > 0:
text += "[color=cyan]失败纹理:[/color] [color=red]" + str(performance_data["failed_textures"]) + "[/color]\n"
else:
text += "[color=cyan]失败纹理:[/color] [color=green]0[/color]\n"
# 当前加载项目
if performance_data["current_loading_item"] != "":
text += "[color=cyan]当前加载:[/color] " + performance_data["current_loading_item"] + "\n"
# 线程信息
if main_game and main_game.crop_texture_manager:
var manager = main_game.crop_texture_manager
text += "[color=cyan]工作线程:[/color] " + str(manager.max_threads) + "\n"
if manager.is_loading:
text += "[color=cyan]队列任务:[/color] " + str(manager.loading_queue.size()) + "\n"
# 调试消息标题
text += "\n[color=yellow][b]=== 调试日志 ===[/b][/color]\n"
# 显示最近的调试消息
var recent_messages = debug_messages.slice(-15) # 显示最近15条消息
for message in recent_messages:
text += message + "\n"
# 更新显示
debug_rich_text.text = text
# 自动滚动到底部
debug_rich_text.scroll_to_line(debug_rich_text.get_line_count())
## 添加调试消息
func add_debug_message(message: String, color: Color = Color.WHITE):
var timestamp = Time.get_datetime_string_from_system()
var time_parts = timestamp.split(" ")
var time_str = ""
# 安全地获取时间部分
if time_parts.size() >= 2:
time_str = time_parts[1].substr(0, 8) # 只要时间部分
else:
# 如果分割失败,使用当前时间
var time_dict = Time.get_time_dict_from_system()
time_str = "%02d:%02d:%02d" % [time_dict.hour, time_dict.minute, time_dict.second]
var color_name = _color_to_name(color)
var formatted_message = "[color=gray]%s[/color] [color=%s]%s[/color]" % [time_str, color_name, message]
debug_messages.append(formatted_message)
# 限制消息数量
if debug_messages.size() > max_debug_messages:
debug_messages = debug_messages.slice(-max_debug_messages)
# 同时输出到控制台
print("[DebugPanel] " + message)
## 颜色转换为名称
func _color_to_name(color: Color) -> String:
if color == Color.RED:
return "red"
elif color == Color.GREEN:
return "green"
elif color == Color.BLUE:
return "blue"
elif color == Color.YELLOW:
return "yellow"
elif color == Color.CYAN:
return "cyan"
elif color == Color.MAGENTA:
return "magenta"
elif color == Color.ORANGE:
return "orange"
elif color == Color.PINK:
return "pink"
else:
return "white"
## 设置当前加载项目
func set_current_loading_item(item_name: String):
performance_data["current_loading_item"] = item_name
if item_name != "":
add_debug_message("正在加载: " + item_name, Color.CYAN)
## 报告加载成功
func report_loading_success(item_name: String):
add_debug_message("✓ 加载成功: " + item_name, Color.GREEN)
## 报告加载失败
func report_loading_failure(item_name: String, reason: String = ""):
var message = "✗ 加载失败: " + item_name
if reason != "":
message += " (" + reason + ")"
add_debug_message(message, Color.RED)
## 报告内存警告
func report_memory_warning(memory_mb: float):
add_debug_message("⚠ 内存使用过高: %.1fMB" % memory_mb, Color.ORANGE)
## 报告性能警告
func report_performance_warning(fps: float):
add_debug_message("⚠ 性能下降: FPS=" + str(fps), Color.ORANGE)
## 清理调试信息
func clear_debug_log():
debug_messages.clear()
add_debug_message("调试日志已清理", Color.YELLOW)
## 导出调试信息到文件
func export_debug_log():
var datetime = Time.get_datetime_dict_from_system()
var filename = "debug_log_%04d%02d%02d_%02d%02d%02d.txt" % [
datetime.year, datetime.month, datetime.day,
datetime.hour, datetime.minute, datetime.second
]
var file_path = OS.get_user_data_dir() + "/" + filename
var file = FileAccess.open(file_path, FileAccess.WRITE)
if file:
file.store_string("=== 萌芽农场调试日志 ===\n\n")
file.store_string("设备信息:\n")
for key in performance_data["device_info"]:
file.store_string(" %s: %s\n" % [key, str(performance_data["device_info"][key])])
file.store_string("\n性能数据:\n")
file.store_string(" CPU使用率: %.1f%%\n" % performance_data["cpu_usage"])
file.store_string(" 内存使用: %.1fMB\n" % (performance_data["memory_usage"] / (1024 * 1024)))
file.store_string(" FPS: %d\n" % performance_data["fps"])
file.store_string(" 已加载纹理: %d\n" % performance_data["loaded_textures"])
file.store_string(" 失败纹理: %d\n" % performance_data["failed_textures"])
file.store_string("\n调试日志:\n")
for message in debug_messages:
# 移除BBCode标签
var clean_message = message.replace("[color=gray]", "").replace("[/color]", "")
clean_message = clean_message.replace("[color=red]", "").replace("[color=green]", "")
clean_message = clean_message.replace("[color=cyan]", "").replace("[color=yellow]", "")
clean_message = clean_message.replace("[color=orange]", "")
file.store_string(clean_message + "\n")
file.close()
add_debug_message("调试日志已导出到: " + filename, Color.GREEN)
return file_path
else:
add_debug_message("导出调试日志失败", Color.RED)
return ""
## 创建复制按钮
func _create_copy_button():
# 复制按钮
copy_button = Button.new()
copy_button.text = "复制调试信息"
copy_button.size = Vector2(140, 35)
copy_button.position = Vector2(10, 10) # 左上角位置
# 设置按钮样式
copy_button.modulate = Color(1.0, 0.8, 0.6, 0.9) # 淡橙色
# 连接点击信号
copy_button.pressed.connect(_on_copy_button_pressed)
# 添加到面板
add_child(copy_button)
# 清理日志按钮
var clear_button = Button.new()
clear_button.text = "清理日志"
clear_button.size = Vector2(100, 35)
clear_button.position = Vector2(160, 10) # 复制按钮右边
# 设置按钮样式
clear_button.modulate = Color(1.0, 0.6, 0.6, 0.9) # 淡红色
# 连接点击信号
clear_button.pressed.connect(_on_clear_button_pressed)
# 添加到面板
add_child(clear_button)
print("[DebugPanel] 复制和清理按钮已创建")
## 清理按钮点击处理
func _on_clear_button_pressed():
clear_debug_log()
print("[DebugPanel] 调试日志已清理")
## 复制按钮点击处理
func _on_copy_button_pressed():
var debug_text = _generate_debug_text_for_copy()
DisplayServer.clipboard_set(debug_text)
add_debug_message("调试信息已复制到剪贴板", Color.GREEN)
print("[DebugPanel] 调试信息已复制到剪贴板")
## 生成用于复制的调试文本(纯文本格式)
func _generate_debug_text_for_copy() -> String:
var text = "=== 萌芽农场调试信息 ===\n\n"
# 设备信息
text += "=== 设备信息 ===\n"
var device = performance_data["device_info"]
text += "平台: " + str(device.get("platform", "未知")) + "\n"
text += "CPU: " + str(device.get("processor_name", "未知")) + " (" + str(device.get("processor_count", 0)) + "核)\n"
text += "GPU: " + str(device.get("gpu_name", "未知")) + "\n"
text += "屏幕: " + str(device.get("screen_size", Vector2.ZERO)) + " DPI:" + str(device.get("screen_dpi", 0)) + "\n"
# 性能监控
text += "\n=== 性能监控 ===\n"
text += "CPU使用率: %.1f%%\n" % performance_data["cpu_usage"]
var memory_mb = performance_data["memory_usage"] / (1024 * 1024)
var memory_peak_mb = performance_data["memory_peak"] / (1024 * 1024)
text += "内存使用: %.1fMB (峰值: %.1fMB)\n" % [memory_mb, memory_peak_mb]
text += "FPS: %d\n" % performance_data["fps"]
# 资源加载状态
text += "\n=== 资源加载状态 ===\n"
text += "加载进度: %d%%\n" % performance_data["loading_progress"]
text += "已加载纹理: %d\n" % performance_data["loaded_textures"]
text += "失败纹理: %d\n" % performance_data["failed_textures"]
if performance_data["current_loading_item"] != "":
text += "当前加载: " + performance_data["current_loading_item"] + "\n"
# 线程信息
if main_game and main_game.crop_texture_manager:
var manager = main_game.crop_texture_manager
text += "工作线程: %d\n" % manager.max_threads
if manager.is_loading:
text += "队列任务: %d\n" % manager.loading_queue.size()
# 调试日志
text += "\n=== 调试日志 ===\n"
for message in debug_messages:
# 移除BBCode标签
var clean_message = _remove_bbcode_tags(message)
text += clean_message + "\n"
return text
## 移除BBCode标签
func _remove_bbcode_tags(text: String) -> String:
var clean_text = text
# 移除所有颜色标签
var color_regex = RegEx.new()
color_regex.compile("\\[color=[^\\]]*\\]|\\[/color\\]")
clean_text = color_regex.sub(clean_text, "", true)
# 移除粗体标签
clean_text = clean_text.replace("[b]", "").replace("[/b]", "")
return clean_text
## 获取当前性能摘要
func get_performance_summary() -> String:
return "CPU:%.1f%% 内存:%.1fMB FPS:%d 纹理:%d/%d" % [
performance_data["cpu_usage"],
performance_data["memory_usage"] / (1024 * 1024),
performance_data["fps"],
performance_data["loaded_textures"],
performance_data["failed_textures"]
]
func _on_quit_button_pressed() -> void:
self.hide()
pass