1136 lines
38 KiB
C#
1136 lines
38 KiB
C#
using System;
|
||
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using System.Reflection;
|
||
using UnityEngine;
|
||
using UnityEngine.UI;
|
||
using TMPro;
|
||
|
||
namespace MeowmentDebugTool
|
||
{
|
||
/// <summary>
|
||
/// 通用调试工具 - 支持多标签页的调试界面系统
|
||
/// 默认分辨率: 1080x2340
|
||
/// 使用方法:
|
||
/// 1. 场景中放置 UniversalDebugTool 预制件
|
||
/// 2. 在代码中调用 UniversalDebugTool.Init() 初始化
|
||
/// 3. 未调用 Init() 前不会显示任何UI
|
||
/// </summary>
|
||
public class UniversalDebugTool : MonoBehaviour
|
||
{
|
||
#region 序列化字段
|
||
[Header("主窗口设置")]
|
||
[SerializeField] private RectTransform mainWindow;
|
||
[SerializeField] private Canvas canvas;
|
||
|
||
[Header("标签页系统")]
|
||
[SerializeField] private RectTransform tabButtonContainer;
|
||
[SerializeField] private RectTransform contentContainer;
|
||
[SerializeField] private GameObject tabButtonPrefab;
|
||
[SerializeField] private Button closeButton;
|
||
[SerializeField] private Color activeTabColor = Color.green;
|
||
[SerializeField] private Color inactiveTabColor = Color.gray;
|
||
|
||
[Header("悬浮按钮")]
|
||
[SerializeField] private GameObject floatingButton;
|
||
[SerializeField] private DraggableFloatingButton draggableComponent;
|
||
|
||
[Header("参数查看页面")]
|
||
[SerializeField] private GameObject parametersPage;
|
||
[SerializeField] private TMP_Text deviceInfoText;
|
||
[SerializeField] private TMP_Text systemInfoText;
|
||
[SerializeField] private ScrollRect parametersScrollRect;
|
||
|
||
[Header("自定义按钮页面")]
|
||
[SerializeField] private GameObject customButtonsPage;
|
||
[SerializeField] private RectTransform buttonContainer;
|
||
[SerializeField] private GameObject buttonPrefab;
|
||
[SerializeField] private ScrollRect buttonsScrollRect;
|
||
|
||
[Header("自定义复选框页面")]
|
||
[SerializeField] private GameObject customCheckBoxesPage;
|
||
[SerializeField] private RectTransform checkBoxContainer;
|
||
[SerializeField] private GameObject checkBoxPrefab;
|
||
[SerializeField] private ScrollRect checkBoxesScrollRect;
|
||
|
||
[Header("数值页面")]
|
||
[SerializeField] private GameObject customValuesPage;
|
||
[SerializeField] private RectTransform valueContainer;
|
||
[SerializeField] private GameObject valuePrefab;
|
||
[SerializeField] private ScrollRect valuesScrollRect;
|
||
|
||
[Header("设置页面")]
|
||
[SerializeField] private GameObject settingsPage;
|
||
[SerializeField] private TMP_InputField widthInputField;
|
||
[SerializeField] private TMP_InputField heightInputField;
|
||
[SerializeField] private Button applyResolutionButton;
|
||
[SerializeField] private Button resetResolutionButton;
|
||
[SerializeField] private TMP_Text currentResolutionText;
|
||
[SerializeField] private TMP_InputField infoBufferInputField;
|
||
[SerializeField] private TMP_InputField warningBufferInputField;
|
||
[SerializeField] private TMP_InputField errorBufferInputField;
|
||
[SerializeField] private TMP_InputField fatalBufferInputField;
|
||
[SerializeField] private Button applyBufferButton;
|
||
[SerializeField] private Button resetBufferButton;
|
||
|
||
[Header("控制台页面")]
|
||
[SerializeField] private GameObject consolePage;
|
||
[SerializeField] private ScrollRect consoleLogScrollRect;
|
||
[SerializeField] private RectTransform consoleLogContent;
|
||
[SerializeField] private ScrollRect consoleDetailScrollRect;
|
||
[SerializeField] private TMP_Text consoleDetailText;
|
||
[SerializeField] private Button consoleClearButton;
|
||
[SerializeField] private Toggle consoleLockScrollToggle;
|
||
[SerializeField] private Toggle consoleInfoFilterToggle;
|
||
[SerializeField] private Toggle consoleWarningFilterToggle;
|
||
[SerializeField] private Toggle consoleErrorFilterToggle;
|
||
[SerializeField] private Toggle consoleFatalFilterToggle;
|
||
[SerializeField] private TMP_InputField consoleTextFilterInputField;
|
||
[SerializeField] private GameObject consoleLogItemPrefab;
|
||
|
||
// [Header("输入对话框")]
|
||
// [SerializeField] private GameObject inputDialog;
|
||
// [SerializeField] private TMP_Text inputDialogTitle;
|
||
// [SerializeField] private TMP_InputField inputDialogInputField;
|
||
// [SerializeField] private Button inputDialogConfirmBtn;
|
||
// [SerializeField] private Button inputDialogCancelBtn;
|
||
#endregion
|
||
|
||
#region 私有变量
|
||
private static UniversalDebugTool instance;
|
||
private static bool isInitialized = false;
|
||
private Dictionary<string, GameObject> pages = new Dictionary<string, GameObject>();
|
||
private Dictionary<string, Button> tabButtons = new Dictionary<string, Button>();
|
||
private string currentPageKey = "";
|
||
|
||
// Canvas层级设置
|
||
private const int TOP_SORT_ORDER = 30000;
|
||
|
||
// 保存的SDF字体资源
|
||
private static TMP_FontAsset savedFontAsset = null;
|
||
|
||
// 模块实例
|
||
private ParametersModule parametersModule;
|
||
private CustomButtonsModule customButtonsModule;
|
||
private CustomCheckBoxesModule customCheckBoxesModule;
|
||
private CustomValuesModule customValuesModule;
|
||
private SettingsModule settingsModule;
|
||
private ConsoleModule consoleModule;
|
||
private List<IDebugModule> allModules = new List<IDebugModule>();
|
||
|
||
// 暂时隐藏状态标志
|
||
private bool isHiding = false;
|
||
|
||
// 四指点击检测
|
||
private bool wasFourFingerTouch = false;
|
||
private const float fourFingerTapTime = 0.3f; // 四指同时按下的时间阈值
|
||
private float fourFingerTouchStartTime = 0f;
|
||
|
||
// 键盘测试模式(用于测试,可以用F键代替四指点击)
|
||
private static bool useKeyboardTestMode = false; // 默认开启键盘测试模式 f
|
||
#endregion
|
||
|
||
#region 单例
|
||
public static UniversalDebugTool Instance
|
||
{
|
||
get
|
||
{
|
||
if (instance == null)
|
||
{
|
||
instance = FindObjectOfType<UniversalDebugTool>();
|
||
}
|
||
return instance;
|
||
}
|
||
}
|
||
|
||
public static bool InstanceExists => instance != null;
|
||
#endregion
|
||
|
||
#region Unity生命周期
|
||
private void Awake()
|
||
{
|
||
// 如果未初始化,直接销毁GameObject,不执行任何操作
|
||
if (!isInitialized)
|
||
{
|
||
Destroy(gameObject);
|
||
return;
|
||
}
|
||
|
||
if (instance == null)
|
||
{
|
||
instance = this;
|
||
DontDestroyOnLoad(gameObject);
|
||
}
|
||
else if (instance != this)
|
||
{
|
||
Destroy(gameObject);
|
||
return;
|
||
}
|
||
|
||
// 设置Canvas为最上层
|
||
SetCanvasToTop();
|
||
|
||
// 隐藏所有UI
|
||
HideAllUI();
|
||
|
||
// 注意:如果isInitialized为true,不在Awake中调用InitializeDebugTool
|
||
// 因为此时反射设置的字段可能还没生效,延迟到Start中调用
|
||
}
|
||
|
||
private void Start()
|
||
{
|
||
// 如果未初始化,不执行任何操作
|
||
if (!isInitialized)
|
||
return;
|
||
|
||
// 只有在已初始化但还没调用过InitializeDebugTool时才执行
|
||
// 这是通过Init()创建的实例,需要在Start中完成初始化
|
||
// 此时反射设置的字段已经生效
|
||
if (allModules.Count == 0)
|
||
{
|
||
InitializeDebugTool();
|
||
InitializeAllModules();
|
||
ShowMainWindow();
|
||
}
|
||
}
|
||
|
||
private void Update()
|
||
{
|
||
// 只有初始化后才执行任何逻辑
|
||
if (!isInitialized)
|
||
return;
|
||
|
||
// 键盘测试模式:按F键触发
|
||
if (useKeyboardTestMode && Input.GetKeyDown(KeyCode.F))
|
||
{
|
||
OnFourFingerTap();
|
||
}
|
||
|
||
// 四指点击检测已禁用,如需使用请在主程序中通过公共API控制显示/隐藏
|
||
// if (!useKeyboardTestMode)
|
||
// {
|
||
// DetectFourFingerTap();
|
||
// }
|
||
|
||
// 更新控制台模块
|
||
if (consoleModule != null)
|
||
{
|
||
consoleModule.Update();
|
||
}
|
||
}
|
||
|
||
private void OnDestroy()
|
||
{
|
||
// 如果未初始化,不执行任何操作
|
||
if (!isInitialized)
|
||
return;
|
||
|
||
if (instance == this)
|
||
{
|
||
instance = null;
|
||
|
||
// 销毁控制台模块
|
||
if (consoleModule != null)
|
||
{
|
||
consoleModule.Shutdown();
|
||
}
|
||
}
|
||
}
|
||
#endregion
|
||
|
||
#region 初始化
|
||
/// <summary>
|
||
/// 初始化调试工具(自动创建UI)
|
||
/// </summary>
|
||
public static void Init()
|
||
{
|
||
if (isInitialized)
|
||
{
|
||
Debug.LogWarning("[MeowmentDebugTool] 已经初始化过了");
|
||
return;
|
||
}
|
||
|
||
isInitialized = true;
|
||
Debug.Log("[MeowmentDebugTool] 开始初始化调试工具...");
|
||
|
||
// 如果场景中没有实例,运行时自动创建UI
|
||
if (!InstanceExists)
|
||
{
|
||
Debug.Log("[MeowmentDebugTool] 运行时自动创建UI...");
|
||
instance = RuntimeUIGenerator.CreateDebugToolUI();
|
||
}
|
||
|
||
if (InstanceExists)
|
||
{
|
||
Instance.InitializeDebugTool();
|
||
Instance.InitializeAllModules();
|
||
Instance.ShowMainWindow();
|
||
|
||
Debug.Log("[MeowmentDebugTool] 初始化完成!");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置所有TextMeshProUGUI的SDF字体
|
||
/// </summary>
|
||
/// <param name="fontAsset">TMP字体资源</param>
|
||
public static void SetSDFFont(TMP_FontAsset fontAsset)
|
||
{
|
||
if (!isInitialized || !InstanceExists)
|
||
{
|
||
Debug.LogWarning("[MeowmentDebugTool] 调试工具未初始化,无法设置字体");
|
||
return;
|
||
}
|
||
|
||
if (fontAsset == null)
|
||
{
|
||
Debug.LogWarning("[MeowmentDebugTool] 字体资源为空");
|
||
return;
|
||
}
|
||
|
||
int count = 0;
|
||
|
||
// 1. 获取调试工具Canvas下的所有TextMeshProUGUI组件(包括隐藏的)
|
||
TextMeshProUGUI[] allTexts = Instance.GetComponentsInChildren<TextMeshProUGUI>(true);
|
||
foreach (var text in allTexts)
|
||
{
|
||
text.font = fontAsset;
|
||
count++;
|
||
}
|
||
|
||
// 2. 查找预制件模板(_TempPrefabHolder)下的TextMeshProUGUI
|
||
GameObject tempPrefabHolder = GameObject.Find("_TempPrefabHolder");
|
||
if (tempPrefabHolder != null)
|
||
{
|
||
TextMeshProUGUI[] prefabTexts = tempPrefabHolder.GetComponentsInChildren<TextMeshProUGUI>(true);
|
||
foreach (var text in prefabTexts)
|
||
{
|
||
text.font = fontAsset;
|
||
count++;
|
||
}
|
||
Debug.Log($"[MeowmentDebugTool] 已设置预制件模板中的 {prefabTexts.Length} 个文本组件");
|
||
}
|
||
|
||
Debug.Log($"[MeowmentDebugTool] 共将 {count} 个文本组件的字体设置为: {fontAsset.name}");
|
||
|
||
// 3. 保存字体资源,供后续创建的按钮使用
|
||
savedFontAsset = fontAsset;
|
||
Debug.Log("[MeowmentDebugTool] 字体资源已保存,后续创建的按钮将自动应用此字体");
|
||
|
||
// 4. 通过模块重新加载自定义按钮
|
||
if (Instance.customButtonsModule != null)
|
||
{
|
||
Debug.Log("[MeowmentDebugTool] 重新加载自定义按钮以应用新字体...");
|
||
Instance.customButtonsModule.SetSDFFont(fontAsset);
|
||
Instance.customButtonsModule.ReloadCustomButtons();
|
||
}
|
||
|
||
// 4.5. 通过模块重新加载自定义复选框
|
||
if (Instance.customCheckBoxesModule != null)
|
||
{
|
||
Debug.Log("[MeowmentDebugTool] 重新加载自定义复选框以应用新字体...");
|
||
Instance.customCheckBoxesModule.SetSDFFont(fontAsset);
|
||
Instance.customCheckBoxesModule.ReloadCustomCheckBoxes();
|
||
}
|
||
|
||
// 4.6. 通过模块重新加载数值
|
||
if (Instance.customValuesModule != null)
|
||
{
|
||
Debug.Log("[MeowmentDebugTool] 重新加载数值以应用新字体...");
|
||
Instance.customValuesModule.SetSDFFont(fontAsset);
|
||
Instance.customValuesModule.ReloadCustomValues();
|
||
}
|
||
|
||
// 5. 为控制台模块应用字体
|
||
if (Instance.consoleModule != null)
|
||
{
|
||
Instance.consoleModule.SetSDFFont(fontAsset);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置Canvas为最上层
|
||
/// </summary>
|
||
private void SetCanvasToTop()
|
||
{
|
||
if (canvas != null)
|
||
{
|
||
canvas.sortingOrder = TOP_SORT_ORDER;
|
||
canvas.overrideSorting = true;
|
||
Debug.Log($"[MeowmentDebugTool] Canvas层级设置为: {TOP_SORT_ORDER}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 隐藏所有UI
|
||
/// </summary>
|
||
private void HideAllUI()
|
||
{
|
||
if (mainWindow != null)
|
||
mainWindow.gameObject.SetActive(false);
|
||
if (floatingButton != null)
|
||
floatingButton.SetActive(false);
|
||
}
|
||
|
||
private void InitializeDebugTool()
|
||
{
|
||
Debug.Log("[MeowmentDebugTool] 初始化UniversalDebugTool...");
|
||
|
||
// 创建模块实例
|
||
parametersModule = new ParametersModule(
|
||
parametersPage, deviceInfoText, systemInfoText, parametersScrollRect);
|
||
|
||
customButtonsModule = new CustomButtonsModule(
|
||
customButtonsPage, buttonContainer, buttonPrefab, buttonsScrollRect, CloseDebugWindow);
|
||
|
||
customCheckBoxesModule = new CustomCheckBoxesModule(
|
||
customCheckBoxesPage, checkBoxContainer, checkBoxPrefab, checkBoxesScrollRect);
|
||
|
||
customValuesModule = new CustomValuesModule(
|
||
customValuesPage, valueContainer, valuePrefab, valuesScrollRect, CloseDebugWindow);
|
||
|
||
settingsModule = new SettingsModule(
|
||
settingsPage, widthInputField, heightInputField,
|
||
applyResolutionButton, resetResolutionButton, currentResolutionText,
|
||
infoBufferInputField, warningBufferInputField,
|
||
errorBufferInputField, fatalBufferInputField,
|
||
applyBufferButton, resetBufferButton,
|
||
mainWindow, canvas);
|
||
|
||
consoleModule = new ConsoleModule(
|
||
consolePage, consoleLogScrollRect, consoleLogContent,
|
||
consoleDetailScrollRect, consoleDetailText,
|
||
consoleClearButton, consoleLockScrollToggle,
|
||
consoleInfoFilterToggle, consoleWarningFilterToggle,
|
||
consoleErrorFilterToggle, consoleFatalFilterToggle,
|
||
consoleTextFilterInputField, consoleLogItemPrefab);
|
||
|
||
// 添加所有模块到列表(顺序:控制台、按钮、开关、数值、参数、设置)
|
||
allModules.Add(consoleModule);
|
||
allModules.Add(customButtonsModule);
|
||
allModules.Add(customCheckBoxesModule);
|
||
allModules.Add(customValuesModule);
|
||
allModules.Add(parametersModule);
|
||
allModules.Add(settingsModule);
|
||
|
||
// 注册所有页面
|
||
foreach (var module in allModules)
|
||
{
|
||
RegisterPage(module.GetModuleName(), module.GetPage());
|
||
}
|
||
|
||
Debug.Log($"[MeowmentDebugTool] 已注册{pages.Count}个页面");
|
||
|
||
// 创建标签按钮
|
||
CreateTabButtons();
|
||
|
||
// 设置按钮事件
|
||
if (closeButton != null)
|
||
closeButton.onClick.AddListener(CloseDebugWindow);
|
||
|
||
// 注意:浮窗点击事件现在由DraggableFloatingButton的OnPointerClick处理
|
||
|
||
// 默认显示按钮页面
|
||
if (pages.Count > 0)
|
||
{
|
||
ShowPage("按钮");
|
||
}
|
||
|
||
Debug.Log("[OK] UniversalDebugTool初始化完成!");
|
||
Debug.Log("[MeowmentDebugTool] 提示: 点击窗口顶部的标签切换页面,或按F1-F4使用快捷键");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 初始化所有模块
|
||
/// </summary>
|
||
private void InitializeAllModules()
|
||
{
|
||
Debug.Log("🔧 初始化所有模块...");
|
||
foreach (var module in allModules)
|
||
{
|
||
module.Initialize();
|
||
}
|
||
|
||
// 设置ConsoleModule引用到SettingsModule
|
||
if (settingsModule != null && consoleModule != null)
|
||
{
|
||
settingsModule.SetConsoleModule(consoleModule);
|
||
}
|
||
|
||
Debug.Log("[OK] 所有模块初始化完成!");
|
||
}
|
||
|
||
private void RegisterPage(string pageName, GameObject pageObject)
|
||
{
|
||
if (pageObject != null && !pages.ContainsKey(pageName))
|
||
{
|
||
pages[pageName] = pageObject;
|
||
pageObject.SetActive(false);
|
||
}
|
||
}
|
||
|
||
private void CreateTabButtons()
|
||
{
|
||
if (tabButtonPrefab == null || tabButtonContainer == null)
|
||
{
|
||
string errorDetails = $"tabButtonPrefab={(tabButtonPrefab == null ? "null" : "已设置")}, " +
|
||
$"tabButtonContainer={(tabButtonContainer == null ? "null" : "已设置")}";
|
||
Debug.LogWarning($"⚠ [MeowmentDebugTool] 标签按钮预制件或容器未完全初始化:{errorDetails}");
|
||
Debug.LogWarning("[!] 这可能是Unity初始化顺序问题,如果标签正常显示则可以忽略此警告");
|
||
return;
|
||
}
|
||
|
||
Debug.Log($"[MeowmentDebugTool] 开始创建{pages.Count}个标签按钮...");
|
||
|
||
foreach (var page in pages)
|
||
{
|
||
GameObject buttonObj = Instantiate(tabButtonPrefab, tabButtonContainer);
|
||
buttonObj.name = $"Tab_{page.Key}";
|
||
|
||
Button button = buttonObj.GetComponent<Button>();
|
||
TMP_Text buttonText = buttonObj.GetComponentInChildren<TMP_Text>();
|
||
|
||
if (buttonText != null)
|
||
{
|
||
buttonText.text = page.Key;
|
||
Debug.Log($"[OK] 创建标签: [{page.Key}]");
|
||
}
|
||
else
|
||
{
|
||
Debug.LogWarning($"⚠️ 标签按钮 [{page.Key}] 缺少文本组件");
|
||
}
|
||
|
||
string pageName = page.Key; // 闭包捕获
|
||
button.onClick.AddListener(() => ShowPage(pageName));
|
||
|
||
tabButtons[page.Key] = button;
|
||
}
|
||
|
||
Debug.Log("[OK] 标签按钮创建完成!");
|
||
}
|
||
#endregion
|
||
|
||
#region 页面管理
|
||
/// <summary>
|
||
/// 显示指定的页面
|
||
/// </summary>
|
||
public void ShowPage(string pageName)
|
||
{
|
||
if (!isInitialized)
|
||
{
|
||
Debug.LogWarning("[MeowmentDebugTool] 调试工具未初始化,无法显示页面");
|
||
return;
|
||
}
|
||
|
||
if (!pages.ContainsKey(pageName))
|
||
{
|
||
Debug.LogWarning($"页面 '{pageName}' 不存在!");
|
||
return;
|
||
}
|
||
|
||
// 隐藏所有页面
|
||
foreach (var page in pages.Values)
|
||
{
|
||
page.SetActive(false);
|
||
}
|
||
|
||
// 显示目标页面
|
||
pages[pageName].SetActive(true);
|
||
currentPageKey = pageName;
|
||
|
||
// 更新标签按钮状态
|
||
UpdateTabButtonStates(pageName);
|
||
}
|
||
|
||
private void UpdateTabButtonStates(string activePageName)
|
||
{
|
||
foreach (var kvp in tabButtons)
|
||
{
|
||
Image buttonImage = kvp.Value.GetComponent<Image>();
|
||
if (buttonImage != null)
|
||
{
|
||
buttonImage.color = kvp.Key == activePageName ? activeTabColor : inactiveTabColor;
|
||
}
|
||
}
|
||
}
|
||
#endregion
|
||
|
||
#region 参数查看功能(通过ParametersModule)
|
||
/// <summary>
|
||
/// 复制设备信息到剪贴板
|
||
/// </summary>
|
||
public void CopyDeviceInfoToClipboard()
|
||
{
|
||
if (!isInitialized)
|
||
{
|
||
Debug.LogWarning("[MeowmentDebugTool] 调试工具未初始化");
|
||
return;
|
||
}
|
||
|
||
parametersModule?.CopyDeviceInfoToClipboard();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 复制系统信息到剪贴板
|
||
/// </summary>
|
||
public void CopySystemInfoToClipboard()
|
||
{
|
||
if (!isInitialized)
|
||
{
|
||
Debug.LogWarning("[MeowmentDebugTool] 调试工具未初始化");
|
||
return;
|
||
}
|
||
|
||
parametersModule?.CopySystemInfoToClipboard();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 刷新所有信息
|
||
/// </summary>
|
||
public void RefreshAllInfo()
|
||
{
|
||
if (!isInitialized)
|
||
{
|
||
Debug.LogWarning("[MeowmentDebugTool] 调试工具未初始化");
|
||
return;
|
||
}
|
||
|
||
parametersModule?.RefreshAllInfo();
|
||
}
|
||
#endregion
|
||
|
||
#region 自定义按钮功能(通过CustomButtonsModule)
|
||
/// <summary>
|
||
/// 设置自定义按钮回调
|
||
/// </summary>
|
||
public static void SetCustomButtonCallback(Action<Button, TMP_Text> callback)
|
||
{
|
||
if (!isInitialized || !InstanceExists)
|
||
{
|
||
Debug.LogWarning("[MeowmentDebugTool] 调试工具未初始化,无法设置按钮回调");
|
||
return;
|
||
}
|
||
|
||
if (Instance.customButtonsModule != null)
|
||
{
|
||
Instance.customButtonsModule.SetCustomButtonCallback(callback);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 重新加载自定义按钮
|
||
/// </summary>
|
||
public void ReloadCustomButtons()
|
||
{
|
||
if (!isInitialized)
|
||
{
|
||
Debug.LogWarning("[MeowmentDebugTool] 调试工具未初始化");
|
||
return;
|
||
}
|
||
|
||
customButtonsModule?.ReloadCustomButtons();
|
||
}
|
||
#endregion
|
||
|
||
#region 自定义数值功能(通过CustomValuesModule)
|
||
/// <summary>
|
||
/// 更新指定方法的数值范围
|
||
/// </summary>
|
||
/// <param name="methodName">方法名称(完整路径如"ClassName.MethodName"或简单的"MethodName")</param>
|
||
/// <param name="minValue">新的最小值</param>
|
||
/// <param name="maxValue">新的最大值</param>
|
||
/// <returns>是否成功更新</returns>
|
||
public static bool UpdateDebugValueRange(string methodName, int minValue, int maxValue)
|
||
{
|
||
if (!isInitialized || !InstanceExists)
|
||
{
|
||
Debug.LogWarning("[MeowmentDebugTool] 调试工具未初始化,无法更新数值范围");
|
||
return false;
|
||
}
|
||
|
||
if (Instance.customValuesModule == null)
|
||
{
|
||
Debug.LogWarning("[MeowmentDebugTool] 数值模块未初始化");
|
||
return false;
|
||
}
|
||
|
||
return Instance.customValuesModule.UpdateValueRange(methodName, minValue, maxValue);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新指定方法的当前值
|
||
/// </summary>
|
||
/// <param name="methodName">方法名称(完整路径如"ClassName.MethodName"或简单的"MethodName")</param>
|
||
/// <param name="value">新的值</param>
|
||
/// <returns>是否成功更新</returns>
|
||
public static bool UpdateDebugValue(string methodName, int value)
|
||
{
|
||
if (!isInitialized || !InstanceExists)
|
||
{
|
||
Debug.LogWarning("[MeowmentDebugTool] 调试工具未初始化,无法更新数值");
|
||
return false;
|
||
}
|
||
|
||
if (Instance.customValuesModule == null)
|
||
{
|
||
Debug.LogWarning("[MeowmentDebugTool] 数值模块未初始化");
|
||
return false;
|
||
}
|
||
|
||
return Instance.customValuesModule.UpdateValue(methodName, value);
|
||
}
|
||
#endregion
|
||
|
||
|
||
|
||
|
||
|
||
// #region 输入对话框
|
||
// /// <summary>
|
||
// /// 显示输入对话框
|
||
// /// </summary>
|
||
// public static void ShowInputDialog(string title, Action<string> onConfirmAction,
|
||
// string initialValue = "", TMP_InputField.ContentType contentType = TMP_InputField.ContentType.Standard)
|
||
// {
|
||
// if (!InstanceExists) return;
|
||
|
||
// var inst = Instance;
|
||
// if (inst.inputDialog == null) return;
|
||
|
||
// inst.inputDialogInputField.contentType = contentType;
|
||
// inst.inputDialog.SetActive(true);
|
||
// inst.inputDialogTitle.text = title;
|
||
// inst.inputDialogInputField.text = initialValue;
|
||
|
||
// inst.inputDialogConfirmBtn.onClick.RemoveAllListeners();
|
||
// inst.inputDialogConfirmBtn.onClick.AddListener(() =>
|
||
// {
|
||
// onConfirmAction?.Invoke(inst.inputDialogInputField.text);
|
||
// CloseInputDialog();
|
||
// });
|
||
|
||
// inst.inputDialogCancelBtn.onClick.RemoveAllListeners();
|
||
// inst.inputDialogCancelBtn.onClick.AddListener(CloseInputDialog);
|
||
// }
|
||
|
||
// /// <summary>
|
||
// /// 关闭输入对话框
|
||
// /// </summary>
|
||
// public static void CloseInputDialog()
|
||
// {
|
||
// if (!InstanceExists) return;
|
||
|
||
// var inst = Instance;
|
||
// if (inst.inputDialog == null) return;
|
||
|
||
// inst.inputDialog.SetActive(false);
|
||
// inst.inputDialogInputField.text = "";
|
||
// inst.inputDialogConfirmBtn.onClick.RemoveAllListeners();
|
||
// inst.inputDialogCancelBtn.onClick.RemoveAllListeners();
|
||
// }
|
||
// #endregion
|
||
|
||
#region 公共API
|
||
/// <summary>
|
||
/// 设置键盘测试模式(用F键代替四指点击)
|
||
/// </summary>
|
||
/// <param name="enable">true=使用F键测试, false=使用四指点击</param>
|
||
public static void SetKeyboardTestMode(bool enable)
|
||
{
|
||
useKeyboardTestMode = enable;
|
||
Debug.Log($"[MeowmentDebugTool] 键盘测试模式: {(enable ? "开启 (按F键触发)" : "关闭 (使用四指点击)")})");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取当前是否为键盘测试模式
|
||
/// </summary>
|
||
public static bool IsKeyboardTestMode()
|
||
{
|
||
return useKeyboardTestMode;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取Debugger是否正在显示
|
||
/// </summary>
|
||
/// <returns>true=Debugger正在显示(主窗口或悬浮按钮),false=完全隐藏或未初始化</returns>
|
||
public static bool IsDebuggerVisible()
|
||
{
|
||
if (!isInitialized || !InstanceExists)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
// 首先检查整个GameObject是否激活
|
||
if (!Instance.gameObject.activeSelf)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
// 如果GameObject激活,再检查主窗口或悬浮按钮是否可见
|
||
// 注意:使用 activeInHierarchy 而不是 activeSelf,因为需要考虑父对象的状态
|
||
bool mainWindowVisible = Instance.mainWindow != null && Instance.mainWindow.gameObject.activeInHierarchy;
|
||
bool floatingButtonVisible = Instance.floatingButton != null && Instance.floatingButton.activeInHierarchy;
|
||
|
||
return mainWindowVisible || floatingButtonVisible;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 显示调试工具
|
||
/// </summary>
|
||
public static void Show()
|
||
{
|
||
if (!isInitialized || !InstanceExists)
|
||
{
|
||
Debug.LogWarning("[MeowmentDebugTool] 调试工具未初始化,无法显示");
|
||
return;
|
||
}
|
||
|
||
Instance.gameObject.SetActive(true);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 隐藏调试工具
|
||
/// </summary>
|
||
public static void Hide()
|
||
{
|
||
if (!isInitialized || !InstanceExists)
|
||
{
|
||
Debug.LogWarning("[MeowmentDebugTool] 调试工具未初始化,无法隐藏");
|
||
return;
|
||
}
|
||
|
||
Instance.gameObject.SetActive(false);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 切换调试工具显示状态
|
||
/// </summary>
|
||
public static void Toggle()
|
||
{
|
||
if (!isInitialized || !InstanceExists)
|
||
{
|
||
Debug.LogWarning("[MeowmentDebugTool] 调试工具未初始化,无法切换状态");
|
||
return;
|
||
}
|
||
|
||
if (Instance.mainWindow != null && Instance.mainWindow.gameObject.activeSelf)
|
||
{
|
||
Instance.CloseDebugWindow();
|
||
}
|
||
else
|
||
{
|
||
Instance.OpenDebugWindow();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 关闭调试窗口,显示悬浮按钮
|
||
/// </summary>
|
||
public void CloseDebugWindow()
|
||
{
|
||
if (mainWindow != null)
|
||
mainWindow.gameObject.SetActive(false);
|
||
|
||
if (floatingButton != null)
|
||
floatingButton.SetActive(true);
|
||
|
||
Debug.Log("[关闭] 调试窗口已关闭");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 打开调试窗口,隐藏悬浮按钮
|
||
/// </summary>
|
||
public void OpenDebugWindow()
|
||
{
|
||
if (floatingButton != null)
|
||
floatingButton.SetActive(false);
|
||
|
||
if (mainWindow != null)
|
||
mainWindow.gameObject.SetActive(true);
|
||
|
||
Debug.Log("[打开] 调试窗口已打开");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 显示主窗口(初始化时调用)
|
||
/// </summary>
|
||
private void ShowMainWindow()
|
||
{
|
||
if (mainWindow != null)
|
||
mainWindow.gameObject.SetActive(false);
|
||
|
||
if (floatingButton != null)
|
||
floatingButton.SetActive(true);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 暂时隐藏调试工具UI(用于截图等场景)
|
||
/// </summary>
|
||
/// <param name="seconds">隐藏的秒数,默认5秒</param>
|
||
public static void HideTemporarily(float seconds = 5f)
|
||
{
|
||
if (!isInitialized || !InstanceExists)
|
||
{
|
||
Debug.LogWarning("[MeowmentDebugTool] 调试工具未初始化,无法隐藏");
|
||
return;
|
||
}
|
||
|
||
if (Instance.isHiding)
|
||
{
|
||
Debug.LogWarning("[MeowmentDebugTool] 已经在隐藏状态中,请等待恢复");
|
||
return;
|
||
}
|
||
|
||
Instance.StartCoroutine(Instance.HideTemporarilyCoroutine(seconds));
|
||
}
|
||
|
||
private IEnumerator HideTemporarilyCoroutine(float seconds)
|
||
{
|
||
isHiding = true;
|
||
Debug.Log($"[MeowmentDebugTool] 开始暂时隐藏流程,时长: {seconds}秒");
|
||
|
||
// 保存Canvas初始状态
|
||
if (canvas == null)
|
||
{
|
||
Debug.LogError("[MeowmentDebugTool] Canvas为空!");
|
||
isHiding = false;
|
||
yield break;
|
||
}
|
||
|
||
bool canvasWasEnabled = canvas.enabled;
|
||
Debug.Log($"[MeowmentDebugTool] Canvas初始状态: {(canvasWasEnabled ? "启用" : "禁用")}");
|
||
|
||
// 1. 先关闭主窗口(如果是打开状态)
|
||
bool wasMainWindowOpen = mainWindow != null && mainWindow.gameObject.activeSelf;
|
||
Debug.Log($"[MeowmentDebugTool] 主窗口初始状态: {(wasMainWindowOpen ? "打开" : "关闭")}");
|
||
|
||
if (wasMainWindowOpen)
|
||
{
|
||
CloseDebugWindow();
|
||
yield return null;
|
||
Debug.Log("[MeowmentDebugTool] 主窗口已关闭");
|
||
}
|
||
|
||
// 2. 隐藏Canvas(包括浮窗)
|
||
canvas.enabled = false;
|
||
Debug.Log($"[MeowmentDebugTool] Canvas已禁用,UI完全隐藏");
|
||
|
||
// 3. 等待指定时间
|
||
yield return new WaitForSeconds(seconds);
|
||
|
||
// 4. 恢复Canvas
|
||
canvas.enabled = true;
|
||
Debug.Log($"[MeowmentDebugTool] Canvas已启用,UI恢复显示");
|
||
|
||
// 5. 验证恢复结果
|
||
if (canvas.enabled)
|
||
{
|
||
Debug.Log("[MeowmentDebugTool] [OK] UI已成功恢复(浮窗状态)");
|
||
}
|
||
else
|
||
{
|
||
Debug.LogError("[MeowmentDebugTool] ✗ Canvas恢复失败!");
|
||
}
|
||
|
||
isHiding = false;
|
||
Debug.Log("[MeowmentDebugTool] 暂时隐藏流程结束");
|
||
}
|
||
#endregion
|
||
|
||
// #region 四指点击检测(已禁用)
|
||
// /// <summary>
|
||
// /// 检测四指点击屏幕
|
||
// /// </summary>
|
||
// private void DetectFourFingerTap()
|
||
// {
|
||
// // 只在移动设备或Unity编辑器(模拟触摸)上检测
|
||
// #if UNITY_ANDROID || UNITY_IOS || UNITY_EDITOR
|
||
//
|
||
// // 检测四指同时按下
|
||
// if (Input.touchCount == 4)
|
||
// {
|
||
// // 检查是否所有触摸都刚开始
|
||
// bool allBegan = true;
|
||
// foreach (Touch touch in Input.touches)
|
||
// {
|
||
// if (touch.phase != TouchPhase.Began)
|
||
// {
|
||
// allBegan = false;
|
||
// break;
|
||
// }
|
||
// }
|
||
//
|
||
// if (allBegan && !wasFourFingerTouch)
|
||
// {
|
||
// wasFourFingerTouch = true;
|
||
// fourFingerTouchStartTime = Time.time;
|
||
// }
|
||
// }
|
||
//
|
||
// // 检测四指抬起(点击完成)
|
||
// if (wasFourFingerTouch && Input.touchCount == 0)
|
||
// {
|
||
// float touchDuration = Time.time - fourFingerTouchStartTime;
|
||
//
|
||
// // 如果触摸时间小于阈值,认为是点击(而非长按)
|
||
// if (touchDuration < fourFingerTapTime)
|
||
// {
|
||
// OnFourFingerTap();
|
||
// }
|
||
//
|
||
// wasFourFingerTouch = false;
|
||
// }
|
||
//
|
||
// // 如果触摸数量变化,重置状态
|
||
// if (wasFourFingerTouch && Input.touchCount != 4)
|
||
// {
|
||
// wasFourFingerTouch = false;
|
||
// }
|
||
//
|
||
// #endif
|
||
// }
|
||
|
||
/// <summary>
|
||
/// 四指点击触发的事件 - 切换所有UI的显示/隐藏(包括主窗口和浮窗)
|
||
/// 注意:此方法保留用于键盘测试模式(按F键),四指点击检测已禁用
|
||
/// </summary>
|
||
private void OnFourFingerTap()
|
||
{
|
||
Debug.Log("[MeowmentDebugTool] 检测到F键触发(测试模式)!");
|
||
|
||
// 检查主窗口或浮窗是否有任意一个显示
|
||
bool anyUIVisible = (mainWindow != null && mainWindow.gameObject.activeSelf) ||
|
||
(floatingButton != null && floatingButton.activeSelf);
|
||
|
||
if (anyUIVisible)
|
||
{
|
||
// 隐藏所有UI
|
||
if (mainWindow != null)
|
||
mainWindow.gameObject.SetActive(false);
|
||
if (floatingButton != null)
|
||
floatingButton.SetActive(false);
|
||
|
||
Debug.Log("[MeowmentDebugTool] 所有UI已隐藏");
|
||
}
|
||
else
|
||
{
|
||
// 显示浮窗
|
||
if (mainWindow != null)
|
||
mainWindow.gameObject.SetActive(false);
|
||
if (floatingButton != null)
|
||
floatingButton.SetActive(true);
|
||
|
||
Debug.Log("[MeowmentDebugTool] 已显示浮窗");
|
||
}
|
||
}
|
||
// #endregion
|
||
}
|
||
|
||
#region 自定义特性
|
||
/// <summary>
|
||
/// 调试按钮特性 - 标记方法为调试按钮
|
||
///
|
||
/// 使用说明:
|
||
/// 1. 在主项目中使用此特性时,请用条件编译包裹:
|
||
///
|
||
/// #if MEOWMENT_DEBUG_TOOL
|
||
/// [DebugButton("默认", "我的调试按钮")]
|
||
/// public static void MyDebugMethod()
|
||
/// {
|
||
/// Debug.Log("调试方法被执行");
|
||
/// }
|
||
/// #endif
|
||
///
|
||
/// 2. 这样当包被卸载时,代码不会报错,也不会影响主工程的正常运行
|
||
/// 3. MEOWMENT_DEBUG_TOOL 宏会在包安装时自动定义,卸载时自动移除
|
||
/// 4. 组名参数用于对按钮进行分组显示,未指定组名的按钮会归入"默认"组
|
||
/// </summary>
|
||
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
|
||
public class DebugButtonAttribute : Attribute
|
||
{
|
||
public string GroupName { get; set; }
|
||
public string DisplayName { get; set; }
|
||
public Color ButtonColor { get; set; }
|
||
|
||
public DebugButtonAttribute(string groupName = "默认", string displayName = "", float r = 0.8f, float g = 0.8f, float b = 0.8f)
|
||
{
|
||
GroupName = string.IsNullOrEmpty(groupName) ? "默认" : groupName;
|
||
DisplayName = displayName;
|
||
ButtonColor = new Color(r, g, b, 1f);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 调试复选框特性 - 标记方法为调试复选框开关
|
||
///
|
||
/// 使用说明:
|
||
/// 1. 在主项目中使用此特性时,请用条件编译包裹:
|
||
///
|
||
/// #if MEOWMENT_DEBUG_TOOL
|
||
/// [DebugCheckBox("开关名称")]
|
||
/// public static void MyToggleMethod(bool isOn)
|
||
/// {
|
||
/// Debug.Log($"开关状态: {isOn}");
|
||
/// // 在这里设置某些参数的值
|
||
/// }
|
||
/// #endif
|
||
///
|
||
/// 2. 方法必须接受一个 bool 参数,表示复选框的状态
|
||
/// 3. 这样当包被卸载时,代码不会报错,也不会影响主工程的正常运行
|
||
/// 4. MEOWMENT_DEBUG_TOOL 宏会在包安装时自动定义,卸载时自动移除
|
||
/// </summary>
|
||
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
|
||
public class DebugCheckBoxAttribute : Attribute
|
||
{
|
||
public string DisplayName { get; set; }
|
||
public Color CheckBoxColor { get; set; }
|
||
|
||
public DebugCheckBoxAttribute(string displayName = "", float r = 0.8f, float g = 0.8f, float b = 0.8f)
|
||
{
|
||
DisplayName = displayName;
|
||
CheckBoxColor = new Color(r, g, b, 1f);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 调试数值特性 - 标记方法为调试数值调整器
|
||
///
|
||
/// 使用说明:
|
||
/// 1. 在主项目中使用此特性时,请用条件编译包裹:
|
||
///
|
||
/// #if MEOWMENT_DEBUG_TOOL
|
||
/// [DebugValue("数值名称", 最小值, 最大值)]
|
||
/// public static void MyValueMethod(int value)
|
||
/// {
|
||
/// Debug.Log($"设置数值: {value}");
|
||
/// // 在这里使用value来设置游戏参数
|
||
/// }
|
||
/// #endif
|
||
///
|
||
/// 2. 方法必须接受一个 int 参数,表示调整后的数值
|
||
/// 3. 可以指定最小值和最大值来限制范围
|
||
/// 4. 可以设置自定义颜色
|
||
/// 5. MEOWMENT_DEBUG_TOOL 宏会在包安装时自动定义,卸载时自动移除
|
||
/// </summary>
|
||
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
|
||
public class DebugValueAttribute : Attribute
|
||
{
|
||
public string DisplayName { get; set; }
|
||
public Color ValueColor { get; set; }
|
||
public int MinValue { get; set; }
|
||
public int MaxValue { get; set; }
|
||
public int DefaultValue { get; set; }
|
||
|
||
public DebugValueAttribute(string displayName = "", int minValue = 0, int maxValue = 100, int defaultValue = -1, float r = 0.8f, float g = 0.8f, float b = 0.8f)
|
||
{
|
||
DisplayName = displayName;
|
||
MinValue = minValue;
|
||
MaxValue = maxValue;
|
||
// 如果defaultValue为-1(未设置),则使用minValue作为默认值
|
||
DefaultValue = defaultValue == -1 ? minValue : defaultValue;
|
||
ValueColor = new Color(r, g, b, 1f);
|
||
}
|
||
}
|
||
#endregion
|
||
}
|