464 lines
16 KiB
GDScript
464 lines
16 KiB
GDScript
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
|
||
# 计算所有加载的纹理数量(新的三阶段系统)
|
||
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()
|
||
|
||
# 加载进度
|
||
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
|