diff --git a/Packages/com.bywaystudios.meowmentdebugtool/BUGFIX_REBUILD_LOOP.md b/Packages/com.bywaystudios.meowmentdebugtool/BUGFIX_REBUILD_LOOP.md deleted file mode 100644 index 0592dcb..0000000 --- a/Packages/com.bywaystudios.meowmentdebugtool/BUGFIX_REBUILD_LOOP.md +++ /dev/null @@ -1,215 +0,0 @@ -# Console模块错误修复说明 - -## 🐛 已修复的问题 - -### 1. Rebuild Loop 错误 - -**问题描述**: -``` -Trying to remove/add Background (UnityEngine.UI.Image) from/to rebuild list -while we are already inside a rebuild loop. This is not supported. -``` - -**原因**: -- 在 `OnLogMessageReceived` 回调中立即调用 `RefreshLogDisplay()` 刷新UI -- 在Unity的Canvas rebuild循环中修改UI元素会触发此错误 -- `Canvas.ForceUpdateCanvases()` 在初始化时也会导致rebuild loop - -**修复方案**: - -#### ConsoleModule.cs -1. ✅ **延迟刷新机制**: 添加 `needRefresh` 标志,不在回调中立即刷新UI -```csharp -private bool needRefresh = false; - -// 在OnLogMessageReceived中 -needRefresh = true; // 标记需要刷新 - -// 在Update中 -if (needRefresh) -{ - needRefresh = false; - RefreshLogDisplay(); // 延迟到下一帧刷新 -} -``` - -2. ✅ **滚动位置延迟设置**: 使用帧计数延迟设置滚动位置 -```csharp -private int lastRefreshFrame = -1; - -// 只在刷新后的第2帧设置滚动位置 -if (lockScroll && Time.frameCount > lastRefreshFrame + 1) -{ - logScrollRect.verticalNormalizedPosition = 0f; -} -``` - -3. ✅ **过滤器事件优化**: 过滤器改变时也使用延迟刷新 -```csharp -private void OnInfoFilterChanged(bool value) -{ - infoFilter = value; - needRefresh = true; // 而不是立即RefreshLogDisplay() -} -``` - -#### SettingsModule.cs -4. ✅ **移除ForceUpdateCanvases**: Canvas会自动在下一帧更新 -```csharp -private void ApplyResolution(Vector2 resolution) -{ - mainWindow.sizeDelta = resolution; - currentResolutionText.text = $"当前窗口尺寸: {resolution.x} x {resolution.y}"; - - // 移除了 Canvas.ForceUpdateCanvases(); - // Canvas会自动更新,不需要强制刷新 -} -``` - -### 2. 中文字体警告 - -**问题描述**: -``` -The character with Unicode value \u5F84 was not found in the [LiberationSans SDF] -font asset or any potential fallbacks. -``` - -**原因**: -- RuntimeUIGenerator使用的默认字体 `LiberationSans SDF` 不支持中文字符 -- TextMeshPro需要专门的中文字体资源 - -**解决方案** (选择其一): - -#### 方案1: 使用中文字体 (推荐) -```csharp -// 在游戏初始化时设置中文字体 -UniversalDebugTool.Init(); - -// 加载支持中文的TMP字体 -TMP_FontAsset chineseFont = Resources.Load("Fonts/ChineseFont SDF"); -UniversalDebugTool.SetSDFFont(chineseFont); -``` - -#### 方案2: 禁用字体警告 -在RuntimeUIGenerator的GetDefaultFont方法中添加过滤: -```csharp -private static TMP_FontAsset GetDefaultFont() -{ - // 禁用TMP字体警告 - TMPro.TMP_Settings.warningsDisabled = true; - - // 查找默认字体... -} -``` - -#### 方案3: 创建中文字体资源 -1. 在Unity中:Window > TextMeshPro > Font Asset Creator -2. 选择支持中文的字体(如Arial Unicode MS、Microsoft YaHei等) -3. 设置Character Set为Unicode或Custom Characters -4. 添加常用中文字符 -5. 生成字体资源并在代码中加载 - -## 📋 修改总结 - -### 文件变更 - -#### ConsoleModule.cs -- ✅ 添加 `needRefresh` 标志 -- ✅ 添加 `lastRefreshFrame` 帧计数 -- ✅ 修改 `OnLogMessageReceived` 使用延迟刷新 -- ✅ 修改 `Update` 方法处理延迟刷新和滚动 -- ✅ 修改所有过滤器事件使用延迟刷新 - -#### SettingsModule.cs -- ✅ 移除 `Canvas.ForceUpdateCanvases()` 调用 - -### 性能影响 - -✅ **更好**: 延迟刷新减少了不必要的UI重建 -✅ **更稳定**: 避免了rebuild loop错误 -✅ **无副作用**: 延迟一帧刷新对用户体验无影响 - -## 🧪 测试建议 - -### 1. 测试Rebuild Loop修复 -```csharp -void Start() -{ - UniversalDebugTool.Init(); - - // 快速生成大量日志 - for (int i = 0; i < 100; i++) - { - Debug.Log($"测试日志 {i}"); - Debug.LogWarning($"警告 {i}"); - Debug.LogError($"错误 {i}"); - } - - // 不应该再有rebuild loop错误 -} -``` - -### 2. 测试滚动功能 -```csharp -void Update() -{ - if (Input.GetKeyDown(KeyCode.Space)) - { - Debug.Log($"新日志 - 帧数: {Time.frameCount}"); - // 应该自动滚动到底部(如果锁定滚动已启用) - } -} -``` - -### 3. 测试过滤器 -1. 生成多种类型的日志 -2. 点击Console标签页 -3. 切换Info/Warning/Error/Fatal过滤器 -4. 不应该有rebuild loop错误 - -### 4. 测试分辨率设置 -1. 进入Settings标签页 -2. 修改宽度和高度 -3. 点击"应用"按钮 -4. 不应该有rebuild loop错误 - -## ⚠️ 注意事项 - -### 关于中文字体 -如果你的游戏需要显示中文,必须: -1. 创建或导入支持中文的TMP字体资源 -2. 在初始化后调用 `UniversalDebugTool.SetSDFFont(yourChineseFont)` -3. 或者在RuntimeUIGenerator中修改GetDefaultFont方法返回中文字体 - -### 最佳实践 -```csharp -public class GameInit : MonoBehaviour -{ - [SerializeField] private TMP_FontAsset chineseFont; - - void Start() - { - // 1. 初始化调试工具 - UniversalDebugTool.Init(); - - // 2. 设置中文字体(如果需要) - if (chineseFont != null) - { - UniversalDebugTool.SetSDFFont(chineseFont); - } - - // 3. 其他初始化... - } -} -``` - -## ✅ 预期结果 - -修复后,你应该看到: -- ✅ 没有 "Trying to remove/add ... from/to rebuild list" 错误 -- ✅ Console正常显示日志 -- ✅ 过滤器正常工作 -- ✅ 滚动功能正常 -- ⚠️ 可能仍有字体警告(如果没有设置中文字体) - -字体警告不影响功能,只是文本显示为方块。如果需要中文显示,请按照上述方案添加中文字体。 diff --git a/Packages/com.bywaystudios.meowmentdebugtool/BUGFIX_REBUILD_LOOP.md.meta b/Packages/com.bywaystudios.meowmentdebugtool/BUGFIX_REBUILD_LOOP.md.meta deleted file mode 100644 index a555966..0000000 --- a/Packages/com.bywaystudios.meowmentdebugtool/BUGFIX_REBUILD_LOOP.md.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 3d6ac60c7ac1db84299fc8dde7508c38 -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.bywaystudios.meowmentdebugtool/CHANGELOG.md b/Packages/com.bywaystudios.meowmentdebugtool/CHANGELOG.md index ed8d539..ad9fb2d 100644 --- a/Packages/com.bywaystudios.meowmentdebugtool/CHANGELOG.md +++ b/Packages/com.bywaystudios.meowmentdebugtool/CHANGELOG.md @@ -5,6 +5,29 @@ 格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.0.0/), 版本号遵循 [Semantic Versioning](https://semver.org/lang/zh-CN/)。 +## [0.3.11] - 2025-12-30 + +### Added + +- 添加按钮分组功能 + +## [0.3.9] - 2025-12-25 + +### Added +- **数值模块运行时控制** + - 新增 `UpdateDebugValue()` 公开接口,支持运行时动态修改数值特性的当前值 + - 支持完整方法名("ClassName.MethodName")或简单方法名("MethodName")查找 + - 自动限制值在特性定义的最小值和最大值范围内 + - 同步更新UI滑块和输入框显示 + +## [0.3.8] - 2025-12-25 +### Improved +- **控制台模块性能优化** + - 默认不显示Info和Warning类型日志(Error和Fatal保持默认显示) + - 对于被过滤的日志类型不创建LogItem UI元素,大幅减少初始内存占用和UI开销 + - 仅在用户手动激活对应过滤器时才创建和显示相关日志UI + - 显著提升启动性能,特别是在大量Info/Warning日志场景下 + ## [0.3.7] - 2025-12-24 diff --git a/Packages/com.bywaystudios.meowmentdebugtool/CONSOLE_INTEGRATION.md b/Packages/com.bywaystudios.meowmentdebugtool/CONSOLE_INTEGRATION.md deleted file mode 100644 index 8cd95d1..0000000 --- a/Packages/com.bywaystudios.meowmentdebugtool/CONSOLE_INTEGRATION.md +++ /dev/null @@ -1,236 +0,0 @@ -# Console 控制台模块 - 添加说明 - -## ✅ 已完成的工作 - -### 1. 新增文件 - -#### [LogNode.cs](Runtime/LogNode.cs) -日志节点数据结构,包含: -- LogType: 日志类型(Info/Warning/Error/Exception) -- LogMessage: 日志消息 -- StackTrace: 堆栈跟踪 -- LogTime: 日志时间 -- LogFrameCount: 日志帧数 - -#### [ConsoleModule.cs](Runtime/ConsoleModule.cs) -控制台模块实现,基于UGUI,包含以下功能: -- ✅ 实时捕获Unity日志 -- ✅ 日志分类和过滤(Info/Warning/Error/Fatal) -- ✅ 锁定滚动到底部 -- ✅ 点击查看详细堆栈信息 -- ✅ 清除日志功能 -- ✅ 日志颜色区分 -- ✅ 对象池性能优化 -- ✅ 最大日志行数限制(500行) -- ✅ SDF字体支持 - -### 2. 修改的文件 - -#### [UniversalDebugTool.cs](Runtime/UniversalDebugTool.cs) -添加了以下内容: -1. **序列化字段** - Console页面的所有UI组件引用 -2. **ConsoleModule实例** - 控制台模块对象 -3. **初始化代码** - 在InitializeDebugTool中创建和注册Console模块 -4. **Update方法** - 调用consoleModule.Update()更新UI -5. **OnDestroy方法** - 清理控制台模块资源 -6. **SetSDFFont支持** - 为Console模块应用字体 - -## 📋 需要在Unity中配置的UI - -### Unity Inspector 配置清单 - -在UniversalDebugTool组件的Inspector中,需要配置以下字段: - -``` -[控制台页面] -├── Console Page (GameObject) -├── Console Log Scroll Rect (ScrollRect) -├── Console Log Content (RectTransform) -├── Console Detail Scroll Rect (ScrollRect) -├── Console Detail Text (TMP_Text) -├── Console Clear Button (Button) -├── Console Lock Scroll Toggle (Toggle) -├── Console Info Filter Toggle (Toggle) -├── Console Warning Filter Toggle (Toggle) -├── Console Error Filter Toggle (Toggle) -├── Console Fatal Filter Toggle (Toggle) -└── Console Log Item Prefab (GameObject) -``` - -### UI层次结构示例 - -``` -ConsolePage -├── ControlPanel (HorizontalLayoutGroup) -│ ├── ClearButton -│ ├── LockScrollToggle -│ ├── Spacer (LayoutElement - FlexibleWidth) -│ ├── InfoFilterToggle -│ ├── WarningFilterToggle -│ ├── ErrorFilterToggle -│ └── FatalFilterToggle -│ -├── LogArea (60% 高度) -│ └── LogScrollView (ScrollRect) -│ ├── Viewport -│ └── Content (VerticalLayoutGroup) -│ └── [日志项动态生成在这里] -│ -└── DetailArea (40% 高度) - └── DetailScrollView (ScrollRect) - ├── Viewport - └── Content - └── DetailText -``` - -### 日志项预制件 (ConsoleLogItemPrefab) - -创建一个预制件,结构如下: -``` -LogItem (GameObject) -├── Toggle (Toggle组件) -├── Background (Image) -└── Label (TextMeshPro - Text) - - RichText: 启用 - - Word Wrapping: 启用 - - Overflow: Overflow -``` - -## 🎨 UI组件配置建议 - -### ControlPanel -- Component: HorizontalLayoutGroup -- Padding: (10, 10, 10, 10) -- Spacing: 10 -- Child Force Expand: Width = false, Height = false - -### LogScrollView -- Component: ScrollRect -- Content: 指向LogContent -- Vertical: ✅ -- Horizontal: ❌ -- Movement Type: Elastic -- Inertia: ✅ -- Scrollbar Visibility: Auto Hide - -### LogContent -- Component: VerticalLayoutGroup -- Child Alignment: Upper Center -- Child Control Size: Height = ✅ -- Child Force Expand: Width = ✅ -- Spacing: 2 - -### DetailScrollView -- Component: ScrollRect -- Vertical: ✅ -- Horizontal: ❌ -- Movement Type: Clamped - -### DetailText -- Rich Text: ✅ -- Wrapping: ✅ -- Overflow: Overflow -- Font Size: 14-16 - -### Toggle组件 -- Is On: 根据默认值 -- Toggle Transition: Fade -- 每个Toggle添加Label (TMP_Text)显示文本 - -## 🔧 代码集成 - -### 模块已自动集成 -ConsoleModule已经在UniversalDebugTool中自动初始化和管理,无需额外代码。 - -### 使用示例 - -```csharp -// 1. 初始化调试工具(会自动初始化Console) -UniversalDebugTool.Init(); - -// 2. 设置字体(可选) -UniversalDebugTool.SetSDFFont(myFont); - -// 3. 获取日志统计(可选) -if (UniversalDebugTool.InstanceExists) -{ - var console = UniversalDebugTool.Instance.consoleModule; - if (console != null) - { - console.GetLogCount(out int info, out int warning, - out int error, out int fatal); - Debug.Log($"日志: Info={info}, Warn={warning}, " + - $"Error={error}, Fatal={fatal}"); - } -} -``` - -## 📊 与GameFramework对比 - -### 主要差异 - -| 项目 | GameFramework | MeowmentDebugTool | -|------|---------------|-------------------| -| UI系统 | OnGUI | UGUI | -| 渲染方式 | 即时模式(每帧重绘) | 保留模式(按需刷新) | -| 性能 | 中等 | 更优(对象池优化) | -| 布局方式 | GUILayout | LayoutGroup + RectTransform | -| 交互组件 | GUILayout.Button/Toggle | Button/Toggle组件 | -| 滚动视图 | GUILayout.BeginScrollView | ScrollRect组件 | -| 定制性 | 通过GUISkin | 完全UGUI定制 | - -### 实现等价性 - -✅ **完全实现的功能**: -- 日志捕获(Application.logMessageReceived) -- 日志分类(Info/Warning/Error/Fatal) -- 过滤器(4种日志类型独立过滤) -- 锁定滚动 -- 选中查看详情 -- 清除日志 -- 日志颜色区分 -- 最大行数限制 - -✅ **优化功能**: -- 对象池(避免频繁创建销毁) -- UGUI性能更好 -- 更灵活的布局系统 - -❌ **未实现的功能**: -- 复制到剪贴板(可以通过DetailText选择复制) -- SettingComponent持久化(使用PlayerPrefs替代即可) - -## 🎯 后续步骤 - -1. **在Unity中创建UI** - - 在Scene或Prefab中创建Console页面UI - - 按照层次结构创建各个组件 - - 创建日志项预制件 - -2. **配置引用** - - 在UniversalDebugTool组件Inspector中 - - 将所有Console相关UI组件拖拽到对应字段 - -3. **测试** - - 运行游戏 - - 调用 `UniversalDebugTool.Init()` - - 查看Console标签页 - - 测试各个过滤器和功能 - -4. **调整样式**(可选) - - 修改颜色、字体大小 - - 调整布局间距 - - 优化日志项高度 - -## ⚠️ 注意事项 - -1. **日志项预制件必须有Toggle组件** -2. **ScrollRect的Content必须正确设置** -3. **VerticalLayoutGroup的设置影响滚动性能** -4. **大量日志时注意性能(已有500行限制)** -5. **确保Console Page在初始化时是隐藏的** - -## 📚 参考文档 - -- [CONSOLE_MODULE_GUIDE.md](CONSOLE_MODULE_GUIDE.md) - 详细的UI结构和配置指南 -- [REFACTORING_NOTES.md](REFACTORING_NOTES.md) - 模块化重构说明 diff --git a/Packages/com.bywaystudios.meowmentdebugtool/CONSOLE_INTEGRATION.md.meta b/Packages/com.bywaystudios.meowmentdebugtool/CONSOLE_INTEGRATION.md.meta deleted file mode 100644 index 84de8e0..0000000 --- a/Packages/com.bywaystudios.meowmentdebugtool/CONSOLE_INTEGRATION.md.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 9bc4f10ea5e6a9d49b550c5aec275f1a -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.bywaystudios.meowmentdebugtool/CONSOLE_MODULE_GUIDE.md b/Packages/com.bywaystudios.meowmentdebugtool/CONSOLE_MODULE_GUIDE.md deleted file mode 100644 index 8cf5eca..0000000 --- a/Packages/com.bywaystudios.meowmentdebugtool/CONSOLE_MODULE_GUIDE.md +++ /dev/null @@ -1,171 +0,0 @@ -# Console 控制台模块 UI 结构说明 - -## 概述 - -Console模块是一个基于UGUI的日志控制台,用于实时显示Unity的日志信息(Info/Warning/Error/Exception)。 - -## 功能特性 - -- ✅ 实时捕获Unity日志(Application.logMessageReceived) -- ✅ 日志分类显示(Info/Warning/Error/Fatal) -- ✅ 日志过滤器(可以单独开关各类型日志) -- ✅ 锁定滚动到底部 -- ✅ 点击日志查看详细堆栈信息 -- ✅ 清除所有日志 -- ✅ 日志颜色区分 -- ✅ 最大日志行数限制(默认500行) -- ✅ 对象池优化性能 - -## UI结构 - -### Console Page 层次结构 -``` -ConsolePage (GameObject) -├── ControlPanel (水平布局) -│ ├── ClearButton (Button) - 清空日志按钮 -│ ├── LockScrollToggle (Toggle) - 锁定滚动 -│ ├── Spacer (空白区域) -│ ├── InfoFilterToggle (Toggle) - Info过滤器 -│ ├── WarningFilterToggle (Toggle) - Warning过滤器 -│ ├── ErrorFilterToggle (Toggle) - Error过滤器 -│ └── FatalFilterToggle (Toggle) - Fatal过滤器 -│ -├── LogScrollView (ScrollRect) - 日志列表区域 -│ └── LogContent (RectTransform) - 日志内容容器 -│ └── [动态生成的日志项] -│ -└── DetailScrollView (ScrollRect) - 详细信息区域 - └── DetailText (TMP_Text) - 显示选中日志的详细信息和堆栈 -``` - -### 日志项预制件结构 (ConsoleLogItemPrefab) -``` -LogItem (GameObject) -├── Toggle (Toggle组件) - 用于选中日志 -├── Background (Image) - 背景 -└── Label (TMP_Text) - 显示日志文本 -``` - -## 序列化字段配置 - -在 UniversalDebugTool 的 Inspector 中需要配置以下字段: - -### Console页面字段 -```csharp -[Header("控制台页面")] -consolePage // 控制台页面根对象 -consoleLogScrollRect // 日志列表ScrollRect -consoleLogContent // 日志内容容器RectTransform -consoleDetailScrollRect // 详情ScrollRect -consoleDetailText // 详情文本TMP_Text -consoleClearButton // 清空按钮 -consoleLockScrollToggle // 锁定滚动Toggle -consoleInfoFilterToggle // Info过滤Toggle -consoleWarningFilterToggle // Warning过滤Toggle -consoleErrorFilterToggle // Error过滤Toggle -consoleFatalFilterToggle // Fatal过滤Toggle -consoleLogItemPrefab // 日志项预制件 -``` - -## UI组件要求 - -### 1. ControlPanel -- 使用 HorizontalLayoutGroup -- 建议添加 ContentSizeFitter -- Padding: 10, 10, 10, 10 -- Spacing: 10 - -### 2. LogScrollView -- ScrollRect 设置: - - Vertical: true - - Horizontal: false - - Movement Type: Elastic - - Scrollbar Visibility: Automatic If Needed -- LogContent 需要 VerticalLayoutGroup: - - Child Alignment: Upper Center - - Child Force Expand: Width - - Child Control Size: Height - - Spacing: 2 - -### 3. DetailScrollView -- ScrollRect 设置: - - Vertical: true - - Horizontal: false - - Movement Type: Clamped -- 建议高度: 150-200 -- DetailText 设置: - - Enable Word Wrapping - - Overflow: Overflow - - Enable Rich Text - -### 4. Toggles -- 每个Toggle需要一个Label (TMP_Text) -- 建议宽度: 100-120 -- Toggle Group: 不需要(可以多选) - -## 日志颜色配置 - -在 ConsoleModule 中默认的颜色: -```csharp -Info: Color.white (255, 255, 255) -Warning: Color.yellow (255, 255, 0) -Error: Color.red (255, 0, 0) -Fatal: Color(0.7f, 0.2f, 0.2f) (178, 51, 51) -``` - -## 性能优化 - -1. **对象池机制**: 日志项使用对象池,避免频繁创建销毁 -2. **最大行数限制**: 默认500行,防止内存溢出 -3. **按需刷新**: 只在日志变化或过滤器改变时刷新显示 -4. **Toggle优化**: 使用Toggle而不是Button,减少重绘 - -## 使用示例 - -### 在代码中获取日志统计 -```csharp -if (UniversalDebugTool.InstanceExists) -{ - var console = UniversalDebugTool.Instance.consoleModule; - if (console != null) - { - console.GetLogCount(out int info, out int warning, out int error, out int fatal); - Debug.Log($"日志统计 - Info:{info}, Warning:{warning}, Error:{error}, Fatal:{fatal}"); - } -} -``` - -### 设置字体 -```csharp -UniversalDebugTool.SetSDFFont(myFont); -// 会自动应用到控制台模块 -``` - -## 注意事项 - -1. **日志项预制件**: 必须包含 Toggle 和 TMP_Text 组件 -2. **ScrollRect**: 必须正确设置 Content 和 Viewport -3. **性能**: 大量日志时建议增加日志项的高度以减少可见数量 -4. **线程安全**: 日志回调在主线程执行,无需担心线程问题 -5. **内存管理**: 超过最大行数的日志会自动删除 - -## 与GameFramework的差异 - -| 特性 | GameFramework (GUI) | MeowmentDebugTool (UGUI) | -|------|---------------------|--------------------------| -| UI系统 | OnGUI (即时模式) | UGUI (保留模式) | -| 性能 | 每帧重绘 | 按需刷新 | -| 布局 | GUILayout自动布局 | RectTransform + LayoutGroup | -| 交互 | GUILayout.Button/Toggle | Button/Toggle组件 | -| 对象池 | 不需要 | 使用对象池优化 | -| 滚动 | GUILayout.BeginScrollView | ScrollRect组件 | - -## 未来扩展 - -可以考虑添加的功能: -- [ ] 搜索/过滤日志内容 -- [ ] 导出日志到文件 -- [ ] 日志标签/分类 -- [ ] 日志统计图表 -- [ ] 复制日志到剪贴板 -- [ ] 日志时间范围过滤 diff --git a/Packages/com.bywaystudios.meowmentdebugtool/CONSOLE_MODULE_GUIDE.md.meta b/Packages/com.bywaystudios.meowmentdebugtool/CONSOLE_MODULE_GUIDE.md.meta deleted file mode 100644 index 90d1a6f..0000000 --- a/Packages/com.bywaystudios.meowmentdebugtool/CONSOLE_MODULE_GUIDE.md.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 2e77813ce2d912b42b65134e2ce344f9 -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.bywaystudios.meowmentdebugtool/CONSOLE_QUICK_SETUP.md b/Packages/com.bywaystudios.meowmentdebugtool/CONSOLE_QUICK_SETUP.md deleted file mode 100644 index 633fff1..0000000 --- a/Packages/com.bywaystudios.meowmentdebugtool/CONSOLE_QUICK_SETUP.md +++ /dev/null @@ -1,233 +0,0 @@ -# Console模块快速设置指南 - -## 🚀 5分钟快速设置 - -### 步骤1: 创建Console页面GameObject - -在UniversalDebugTool的预制件中,创建以下结构: - -``` -[添加到ContentContainer下] -└── ConsolePage - ├── ControlPanel - │ ├── ClearButton (Button) - │ ├── LockScrollToggle (Toggle + Label) - │ ├── Spacer (Empty GameObject + LayoutElement) - │ ├── InfoToggle (Toggle + Label) - │ ├── WarningToggle (Toggle + Label) - │ ├── ErrorToggle (Toggle + Label) - │ └── FatalToggle (Toggle + Label) - │ - ├── LogArea - │ └── LogScrollView (ScrollRect) - │ └── Viewport - │ └── Content (VerticalLayoutGroup) - │ - └── DetailArea - └── DetailScrollView (ScrollRect) - └── Viewport - └── Content - └── DetailText (TMP_Text) -``` - -### 步骤2: 配置组件 - -#### ConsolePage -- RectTransform: Stretch (全屏) -- 默认禁用(Active = false) - -#### ControlPanel -- Height: 50 -- Add Component: HorizontalLayoutGroup - - Padding: 10, 10, 10, 10 - - Spacing: 10 - - Child Force Expand: 都不勾选 - -#### Spacer (占位符) -- Add Component: LayoutElement - - Flexible Width: 1 - -#### LogArea -- Height: 60% (~400) -- Add Component: VerticalLayoutGroup - -#### LogScrollView -- Add Component: ScrollRect - - Content: LogContent - - Vertical: ✅ - - Horizontal: ❌ - - Scrollbar Visibility: Auto Hide And Expand Viewport - -#### LogContent -- Add Component: VerticalLayoutGroup - - Child Alignment: Upper Center - - Spacing: 2 - - Child Control Size: Height ✅ - - Child Force Expand: Width ✅ -- Add Component: ContentSizeFitter - - Vertical Fit: Preferred Size - -#### DetailArea -- Height: 40% (~200) - -#### DetailScrollView -- 同LogScrollView配置 - -#### DetailText -- Font Size: 14 -- Color: White -- Alignment: Top Left -- Overflow: Overflow -- Wrapping: Enabled -- Rich Text: ✅ - -### 步骤3: 创建日志项预制件 - -创建一个新的预制件 `ConsoleLogItem`: - -``` -LogItem -├── Toggle (Toggle组件) -│ - Is On: false -│ - Transition: None或Fade -│ -├── Background (Image) -│ - Color: (30, 30, 30, 255) -│ -└── Label (TextMeshPro) - - Font Size: 12 - - Color: White - - Alignment: Middle Left - - Overflow: Truncate - - Rich Text: ✅ -``` - -组件设置: -- RectTransform: - - Anchor: Stretch Horizontal - - Height: 25 - - Left: 0, Right: 0 -- Toggle: - - Target Graphic: Background - - Graphic: Background - -### 步骤4: 配置UniversalDebugTool - -在Inspector中找到 `[控制台页面]` 部分,拖拽对应的对象: - -``` -✅ Console Page → ConsolePage -✅ Console Log Scroll Rect → LogScrollView -✅ Console Log Content → LogContent -✅ Console Detail Scroll Rect → DetailScrollView -✅ Console Detail Text → DetailText -✅ Console Clear Button → ClearButton -✅ Console Lock Scroll Toggle → LockScrollToggle -✅ Console Info Filter Toggle → InfoToggle -✅ Console Warning Filter Toggle → WarningToggle -✅ Console Error Filter Toggle → ErrorToggle -✅ Console Fatal Filter Toggle → FatalToggle -✅ Console Log Item Prefab → ConsoleLogItem预制件 -``` - -### 步骤5: 测试 - -```csharp -// 在游戏开始时调用 -UniversalDebugTool.Init(); - -// 测试日志 -Debug.Log("这是一条Info日志"); -Debug.LogWarning("这是一条Warning日志"); -Debug.LogError("这是一条Error日志"); -``` - -运行游戏,点击调试工具,切换到"控制台"标签页,应该能看到日志了! - -## 🎨 样式建议 - -### 颜色方案(深色主题) -``` -Background: (20, 20, 20) -ControlPanel: (40, 40, 40) -LogItem: (30, 30, 30) -LogItem Selected: (60, 60, 60) -Text: (220, 220, 220) - -日志颜色: -Info: White (255, 255, 255) -Warning: Yellow (255, 235, 0) -Error: Red (255, 80, 80) -Fatal: Dark Red (180, 50, 50) -``` - -### 字体大小 -``` -ControlPanel按钮: 14 -Toggle标签: 12 -日志项: 11-12 -详情文本: 13-14 -``` - -### 间距 -``` -ControlPanel Spacing: 10 -LogContent Spacing: 2 -Padding: 10 -``` - -## ⚡ 性能优化提示 - -1. **限制可见日志项**: 调整LogArea高度,减少同时渲染的日志数量 -2. **日志项高度**: 25-30像素最佳,太高会影响滚动性能 -3. **最大日志数**: 默认500行,可在ConsoleModule构造函数中修改maxLine -4. **禁用不需要的过滤器**: 减少日志显示可以提升性能 - -## 🐛 常见问题 - -### Q: 日志不显示? -A: 检查: -1. Console Page是否已添加到pages字典 -2. 是否调用了UniversalDebugTool.Init() -3. 日志项预制件是否正确配置 - -### Q: 滚动不工作? -A: 检查: -1. ScrollRect的Content是否正确设置 -2. Content是否有VerticalLayoutGroup -3. Content Size Fitter是否启用 - -### Q: 点击日志无反应? -A: 检查: -1. 日志项是否有Toggle组件 -2. Toggle的Target Graphic是否设置 -3. EventSystem是否存在于场景中 - -### Q: 性能问题? -A: 尝试: -1. 减少maxLine值(默认500) -2. 减少LogArea高度 -3. 使用Text而非TextMeshPro(性能更好但效果差) -4. 关闭不需要的日志类型 - -## 📱 移动端优化 - -如果在移动设备上使用: - -1. 增大日志项高度(35-40像素) -2. 增大字体(14-16) -3. 减少最大日志数(200-300行) -4. 使用简化的日志格式(去掉帧数显示) - -## ✨ 完成! - -现在你已经有一个功能完整的Console控制台了! - -测试所有功能: -- ✅ 清除日志 -- ✅ 锁定/解锁滚动 -- ✅ 过滤不同类型日志 -- ✅ 点击查看详情 -- ✅ 滚动浏览日志 - -享受调试吧! 🎉 diff --git a/Packages/com.bywaystudios.meowmentdebugtool/CONSOLE_QUICK_SETUP.md.meta b/Packages/com.bywaystudios.meowmentdebugtool/CONSOLE_QUICK_SETUP.md.meta deleted file mode 100644 index 365385b..0000000 --- a/Packages/com.bywaystudios.meowmentdebugtool/CONSOLE_QUICK_SETUP.md.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 1531af79f3e63374182c727d39576258 -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.bywaystudios.meowmentdebugtool/CONSOLE_RUNTIME_READY.md b/Packages/com.bywaystudios.meowmentdebugtool/CONSOLE_RUNTIME_READY.md deleted file mode 100644 index dd51251..0000000 --- a/Packages/com.bywaystudios.meowmentdebugtool/CONSOLE_RUNTIME_READY.md +++ /dev/null @@ -1,186 +0,0 @@ -# Console模块 - 运行时UI创建完成 - -## ✅ 已完成 - -Console模块的UI已经添加到RuntimeUIGenerator中,会在运行时自动创建。 - -## 🎯 使用方法 - -### 1. 直接运行测试 - -```csharp -using UnityEngine; -using MeowmentDebugTool; - -public class TestDebugTool : MonoBehaviour -{ - void Start() - { - // 初始化调试工具(会自动创建所有UI包括Console) - UniversalDebugTool.Init(); - - // 测试各种日志 - Debug.Log("这是一条普通日志"); - Debug.LogWarning("这是一条警告日志"); - Debug.LogError("这是一条错误日志"); - - // 测试异常 - try - { - throw new System.Exception("测试异常"); - } - catch (System.Exception e) - { - Debug.LogException(e); - } - } - - void Update() - { - // 按空格键生成测试日志 - if (Input.GetKeyDown(KeyCode.Space)) - { - Debug.Log($"测试日志 - 帧数: {Time.frameCount}"); - } - } -} -``` - -### 2. 运行游戏 - -1. 创建一个空GameObject -2. 添加TestDebugTool脚本 -3. 运行游戏 -4. Console页面会自动出现在标签页中 - -### 3. 测试功能 - -- ✅ **清空按钮**: 清除所有日志 -- ✅ **锁定滚动**: 自动滚动到最新日志 -- ✅ **过滤器**: 显示/隐藏不同类型的日志 - - Info (白色) - - Warning (黄色) - - Error (红色) - - Fatal (深红色) -- ✅ **点击日志**: 在下方显示详细信息和堆栈跟踪 -- ✅ **实时计数**: Toggle显示每种日志的数量 - -## 📋 UI结构说明 - -RuntimeUIGenerator会创建以下结构: - -``` -ConsolePage -├── ControlPanel (控制面板 - 高度80) -│ ├── ConsoleClearButton (清空按钮) -│ ├── ConsoleLockScrollToggle (锁定滚动) -│ ├── Spacer (弹性空白) -│ ├── ConsoleInfoFilterToggle (Info过滤) -│ ├── ConsoleWarningFilterToggle (Warning过滤) -│ ├── ConsoleErrorFilterToggle (Error过滤) -│ └── ConsoleFatalFilterToggle (Fatal过滤) -│ -├── LogArea (60% 高度) -│ └── ConsoleLogScrollView -│ └── Viewport -│ └── ConsoleLogContent (垂直布局组) -│ └── [日志项动态生成] -│ -└── DetailArea (40% 高度) - └── ConsoleDetailScrollView - └── Viewport - └── Content - └── ConsoleDetailText (详细信息) -``` - -## 🎨 样式配置 - -### 颜色方案 -- **背景**: (12, 12, 12) - 深灰色 -- **日志区域**: (5, 5, 5) - 更深的灰色 -- **详情区域**: (8, 8, 8) - 中等深灰色 -- **日志项背景**: (12, 12, 12) -- **日志项选中**: (25, 35, 45) - 蓝灰色 - -### 日志颜色(ConsoleModule中定义) -- **Info**: (255, 255, 255) - 白色 -- **Warning**: (255, 255, 0) - 黄色 -- **Error**: (255, 0, 0) - 红色 -- **Fatal**: (178, 51, 51) - 深红色 - -### 字体大小 -- Toggle标签: 24 -- 日志项: 22 -- 详情文本: 24 - -## 🔧 自定义配置 - -如果需要修改样式,可以在RuntimeUIGenerator.cs中找到CreateConsolePage方法进行调整: - -### 修改日志项高度 -```csharp -// 在CreateConsoleLogItemPrefab方法中 -rect.sizeDelta = new Vector2(0, 30); // 改为你想要的高度 -``` - -### 修改区域比例 -```csharp -// 在CreateConsolePage方法中 -logAreaLayout.flexibleHeight = 3; // 日志区域权重 -detailAreaLayout.flexibleHeight = 2; // 详情区域权重 -``` - -### 修改最大日志数 -```csharp -// 在ConsoleModule.cs构造函数中 -private int maxLine = 500; // 改为你想要的数量 -``` - -## 🚀 性能提示 - -1. **默认500行限制**: 超过的日志会自动删除 -2. **对象池优化**: 日志项会被重用,不会频繁创建销毁 -3. **按需刷新**: 只在日志变化或过滤器改变时刷新UI -4. **适中的日志项高度**: 30像素平衡了可读性和性能 - -## 📱 移动端建议 - -如果在移动设备上运行: - -```csharp -// 在CreateConsoleLogItemPrefab中调整 -labelTmp.fontSize = 28; // 增大字体 -rect.sizeDelta = new Vector2(0, 40); // 增加高度 -``` - -## 🐛 调试技巧 - -### 查看Console模块是否初始化成功 -```csharp -if (UniversalDebugTool.InstanceExists) -{ - var console = UniversalDebugTool.Instance.GetType() - .GetField("consoleModule", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance) - ?.GetValue(UniversalDebugTool.Instance); - - if (console != null) - { - Debug.Log("✅ Console模块已初始化"); - } -} -``` - -### 检查UI是否创建 -在Hierarchy中查找: -- UniversalDebugTool_Canvas - - MainWindow - - ContentContainer - - ConsolePage ← 应该能找到这个 - -## ✨ 完成! - -现在你可以直接运行游戏测试Console模块了! - -所有的UI都会在调用 `UniversalDebugTool.Init()` 时自动创建。 - -享受调试吧! 🎉 diff --git a/Packages/com.bywaystudios.meowmentdebugtool/CONSOLE_RUNTIME_READY.md.meta b/Packages/com.bywaystudios.meowmentdebugtool/CONSOLE_RUNTIME_READY.md.meta deleted file mode 100644 index 0c0063e..0000000 --- a/Packages/com.bywaystudios.meowmentdebugtool/CONSOLE_RUNTIME_READY.md.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: aa6bf6f6937d0ff4da7b444f776bf41e -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.bywaystudios.meowmentdebugtool/README.md b/Packages/com.bywaystudios.meowmentdebugtool/README.md index b33dc59..ddf5f7c 100644 --- a/Packages/com.bywaystudios.meowmentdebugtool/README.md +++ b/Packages/com.bywaystudios.meowmentdebugtool/README.md @@ -47,14 +47,14 @@ void Start() ```csharp public static class DebugFunctions { - [DebugButton("清空数据")] + [DebugButton("分组1","清空数据")] private static void ClearData() { PlayerPrefs.DeleteAll(); } // 设置按钮颜色 (r, g, b) - [DebugButton("添加金币", 0.2f, 0.8f, 0.2f)] + [DebugButton("分组1","添加金币", 0.2f, 0.8f, 0.2f)] private static void AddCoins() { PlayerData.Coins += 1000; diff --git a/Packages/com.bywaystudios.meowmentdebugtool/REFACTORING_NOTES.md b/Packages/com.bywaystudios.meowmentdebugtool/REFACTORING_NOTES.md deleted file mode 100644 index 9a4747a..0000000 --- a/Packages/com.bywaystudios.meowmentdebugtool/REFACTORING_NOTES.md +++ /dev/null @@ -1,111 +0,0 @@ -# MeowmentDebugTool 模块化重构说明 - -## 重构概述 - -已将 UniversalDebugTool 的4个主要功能模块分离成独立的脚本文件,使代码结构更清晰、更易维护。 - -## 新增文件 - -### 1. IDebugModule.cs -- **作用**: 调试模块的基础接口 -- **方法**: - - `Initialize()`: 初始化模块 - - `GetPage()`: 获取模块的UI页面GameObject - - `GetModuleName()`: 获取模块名称 - -### 2. ParametersModule.cs -- **作用**: 参数查看模块,显示设备和系统信息 -- **主要功能**: - - 显示设备信息(设备名称、型号、处理器等) - - 显示系统信息(Unity版本、平台、分辨率、图形设备等) - - 复制信息到剪贴板 - - 刷新信息 - -### 3. CustomButtonsModule.cs -- **作用**: 自定义按钮模块,通过反射加载标记为DebugButton的方法 -- **主要功能**: - - 自动扫描并加载所有带 `[DebugButton]` 特性的静态方法 - - 动态创建按钮UI - - 设置SDF字体 - - 支持自定义按钮回调 - - 点击按钮后自动关闭调试窗口 - -### 4. ToolbarModule.cs -- **作用**: 工具栏模块,提供时间调整等工具 -- **主要功能**: - - 时间调整滑块(支持秒和分钟显示) - - 增加/减少时间按钮 - - 可扩展的游戏时间调整接口 - -### 5. SettingsModule.cs -- **作用**: 设置模块,提供分辨率设置等功能 -- **主要功能**: - - 自定义窗口分辨率 - - 重置为默认分辨率 - - 实时显示当前窗口尺寸 - -## UniversalDebugTool.cs 的改动 - -### 主要变化 - -1. **移除了具体实现代码**: - - 参数查看功能 → ParametersModule - - 自定义按钮功能 → CustomButtonsModule - - 工具栏功能 → ToolbarModule - - 分辨率设置功能 → SettingsModule - -2. **新增模块管理**: - ```csharp - private ParametersModule parametersModule; - private CustomButtonsModule customButtonsModule; - private ToolbarModule toolbarModule; - private SettingsModule settingsModule; - private List allModules = new List(); - ``` - -3. **初始化流程**: - - `InitializeDebugTool()`: 创建所有模块实例并注册页面 - - `InitializeAllModules()`: 调用各模块的Initialize方法 - -4. **保留的公共API**: - - `CopyDeviceInfoToClipboard()` - 委托给 ParametersModule - - `CopySystemInfoToClipboard()` - 委托给 ParametersModule - - `RefreshAllInfo()` - 委托给 ParametersModule - - `SetCustomButtonCallback()` - 委托给 CustomButtonsModule - - `ReloadCustomButtons()` - 委托给 CustomButtonsModule - -## 优势 - -1. **职责分离**: 每个模块只负责一个功能领域 -2. **易于维护**: 修改某个功能时只需要编辑对应的模块文件 -3. **可扩展性**: 添加新模块只需实现 IDebugModule 接口 -4. **代码清晰**: UniversalDebugTool.cs 现在主要负责协调各模块,代码更简洁 - -## 使用方式 - -使用方式完全不变,所有现有的API和功能保持兼容: - -```csharp -// 初始化调试工具 -UniversalDebugTool.Init(); - -// 设置字体 -UniversalDebugTool.SetSDFFont(myFont); - -// 刷新信息 -UniversalDebugTool.Instance.RefreshAllInfo(); - -// 自定义按钮仍然使用相同的特性 -[DebugButton("测试按钮")] -public static void TestMethod() -{ - Debug.Log("测试"); -} -``` - -## 未来扩展 - -如果需要添加新的调试功能模块,只需: -1. 创建新的类并实现 `IDebugModule` 接口 -2. 在 `UniversalDebugTool.InitializeDebugTool()` 中实例化并添加到 `allModules` 列表 -3. 调用 `InitializeAllModules()` 会自动初始化新模块 diff --git a/Packages/com.bywaystudios.meowmentdebugtool/REFACTORING_NOTES.md.meta b/Packages/com.bywaystudios.meowmentdebugtool/REFACTORING_NOTES.md.meta deleted file mode 100644 index 0b6f1dd..0000000 --- a/Packages/com.bywaystudios.meowmentdebugtool/REFACTORING_NOTES.md.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 7a75e76e7a8253b4a97f7c353af12a0f -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.bywaystudios.meowmentdebugtool/Runtime/ConsoleModule.cs b/Packages/com.bywaystudios.meowmentdebugtool/Runtime/ConsoleModule.cs index 2a6204d..8f52c7d 100644 --- a/Packages/com.bywaystudios.meowmentdebugtool/Runtime/ConsoleModule.cs +++ b/Packages/com.bywaystudios.meowmentdebugtool/Runtime/ConsoleModule.cs @@ -28,11 +28,18 @@ namespace MeowmentDebugTool private Toggle errorFilterToggle; private Toggle fatalFilterToggle; + // 文字筛选 + private TMP_InputField textFilterInputField; + private string textFilter = ""; + // 日志项预制件 private GameObject logItemPrefab; - // 日志数据 - private Queue logNodes = new Queue(); + // 日志数据 - 分离的缓存池 + private Queue infoLogNodes = new Queue(); + private Queue warningLogNodes = new Queue(); + private Queue errorLogNodes = new Queue(); + private Queue fatalLogNodes = new Queue(); private LogNode selectedNode = null; // 日志计数 @@ -43,9 +50,12 @@ namespace MeowmentDebugTool // 设置 private bool lockScroll = true; - private int maxLine = 200; - private bool infoFilter = true; - private bool warningFilter = true; + private int maxInfoLines = 50; + private int maxWarningLines = 50; + private int maxErrorLines = 50; + private int maxFatalLines = 50; + private bool infoFilter = false; // 默认不显示Info + private bool warningFilter = false; // 默认不显示Warning private bool errorFilter = true; private bool fatalFilter = true; @@ -71,7 +81,7 @@ namespace MeowmentDebugTool public ConsoleModule(GameObject page, ScrollRect logScroll, RectTransform logContentTransform, ScrollRect detailScroll, TMP_Text detail, Button clearBtn, Toggle lockToggle, Toggle infoToggle, Toggle warningToggle, - Toggle errorToggle, Toggle fatalToggle, GameObject logItemPrefabObj) + Toggle errorToggle, Toggle fatalToggle, TMP_InputField textFilterInput, GameObject logItemPrefabObj) { consolePage = page; logScrollRect = logScroll; @@ -84,6 +94,7 @@ namespace MeowmentDebugTool warningFilterToggle = warningToggle; errorFilterToggle = errorToggle; fatalFilterToggle = fatalToggle; + textFilterInputField = textFilterInput; logItemPrefab = logItemPrefabObj; } #endregion @@ -147,6 +158,13 @@ namespace MeowmentDebugTool fatalFilterToggle.onValueChanged.AddListener(OnFatalFilterChanged); } + // 设置文字筛选输入框事件 + if (textFilterInputField != null) + { + textFilterInputField.text = textFilter; + textFilterInputField.onValueChanged.AddListener(OnTextFilterChanged); + } + // 清空详情 if (detailText != null) detailText.text = "点击日志查看详细信息..."; @@ -195,6 +213,29 @@ namespace MeowmentDebugTool fatal = fatalCount; } + /// + /// 设置各类型日志的最大缓存数量 + /// + public void SetMaxLogLines(int maxInfo, int maxWarning, int maxError, int maxFatal) + { + maxInfoLines = Mathf.Max(1, maxInfo); + maxWarningLines = Mathf.Max(1, maxWarning); + maxErrorLines = Mathf.Max(1, maxError); + maxFatalLines = Mathf.Max(1, maxFatal); + Debug.Log($"[ConsoleModule] 设置缓存池大小 - Info:{maxInfoLines}, Warning:{maxWarningLines}, Error:{maxErrorLines}, Fatal:{maxFatalLines}"); + } + + /// + /// 获取各类型日志的最大缓存数量 + /// + public void GetMaxLogLines(out int maxInfo, out int maxWarning, out int maxError, out int maxFatal) + { + maxInfo = maxInfoLines; + maxWarning = maxWarningLines; + maxError = maxErrorLines; + maxFatal = maxFatalLines; + } + /// /// 更新(每帧调用) /// @@ -246,12 +287,40 @@ namespace MeowmentDebugTool // 创建日志节点 LogNode logNode = LogNode.Create(logType, logMessage, stackTrace); - logNodes.Enqueue(logNode); - // 限制最大行数 - while (logNodes.Count > maxLine) + // 根据类型添加到对应的缓存池 + Queue targetQueue = null; + int maxLines = 0; + + switch (logType) { - logNodes.Dequeue(); + case LogType.Log: + targetQueue = infoLogNodes; + maxLines = maxInfoLines; + break; + case LogType.Warning: + targetQueue = warningLogNodes; + maxLines = maxWarningLines; + break; + case LogType.Error: + targetQueue = errorLogNodes; + maxLines = maxErrorLines; + break; + case LogType.Exception: + targetQueue = fatalLogNodes; + maxLines = maxFatalLines; + break; + } + + if (targetQueue != null) + { + targetQueue.Enqueue(logNode); + + // 限制该类型的最大行数 + while (targetQueue.Count > maxLines) + { + targetQueue.Dequeue(); + } } // 标记需要刷新,而不是立即刷新(避免rebuild loop) @@ -293,13 +362,22 @@ namespace MeowmentDebugTool } activeLogItems.Clear(); - // 遍历日志节点并创建UI + // 遍历日志节点并创建UI(性能优化:只为需要显示的日志创建LogItem) int index = 0; int displayCount = 0; - foreach (LogNode logNode in logNodes) + + // 合并所有缓存池的日志,按时间排序 + List allLogs = new List(); + allLogs.AddRange(infoLogNodes); + allLogs.AddRange(warningLogNodes); + allLogs.AddRange(errorLogNodes); + allLogs.AddRange(fatalLogNodes); + allLogs.Sort((a, b) => a.LogTime.CompareTo(b.LogTime)); + + foreach (LogNode logNode in allLogs) { - // 根据过滤器判断是否显示 - if (!ShouldShowLog(logNode.LogType)) + // 根据过滤器判断是否显示,如果不显示则跳过创建LogItem + if (!ShouldShowLog(logNode)) continue; // 从对象池获取或创建日志项 @@ -328,21 +406,41 @@ namespace MeowmentDebugTool } } - private bool ShouldShowLog(LogType logType) + private bool ShouldShowLog(LogNode logNode) { - switch (logType) + // 首先检查类型筛选 + bool typeMatch = false; + switch (logNode.LogType) { case LogType.Log: - return infoFilter; + typeMatch = infoFilter; + break; case LogType.Warning: - return warningFilter; + typeMatch = warningFilter; + break; case LogType.Error: - return errorFilter; + typeMatch = errorFilter; + break; case LogType.Exception: - return fatalFilter; + typeMatch = fatalFilter; + break; default: - return true; + typeMatch = true; + break; } + + if (!typeMatch) + return false; + + // 然后检查文字筛选 + if (!string.IsNullOrEmpty(textFilter)) + { + // 如果日志消息不包含筛选文字,则不显示 + if (!logNode.LogMessage.Contains(textFilter)) + return false; + } + + return true; } private GameObject GetLogItemFromPool() @@ -475,29 +573,10 @@ namespace MeowmentDebugTool private void RefreshCount() { - infoCount = 0; - warningCount = 0; - errorCount = 0; - fatalCount = 0; - - foreach (LogNode logNode in logNodes) - { - switch (logNode.LogType) - { - case LogType.Log: - infoCount++; - break; - case LogType.Warning: - warningCount++; - break; - case LogType.Error: - errorCount++; - break; - case LogType.Exception: - fatalCount++; - break; - } - } + infoCount = infoLogNodes.Count; + warningCount = warningLogNodes.Count; + errorCount = errorLogNodes.Count; + fatalCount = fatalLogNodes.Count; } private void UpdateFilterToggleText() @@ -535,7 +614,10 @@ namespace MeowmentDebugTool private void ClearAllLogs() { - logNodes.Clear(); + infoLogNodes.Clear(); + warningLogNodes.Clear(); + errorLogNodes.Clear(); + fatalLogNodes.Clear(); selectedNode = null; if (detailText != null) @@ -574,6 +656,12 @@ namespace MeowmentDebugTool fatalFilter = value; needRefresh = true; } + + private void OnTextFilterChanged(string value) + { + textFilter = value; + needRefresh = true; + } #endregion } } diff --git a/Packages/com.bywaystudios.meowmentdebugtool/Runtime/CustomButtonsModule.cs b/Packages/com.bywaystudios.meowmentdebugtool/Runtime/CustomButtonsModule.cs index dd19081..e213928 100644 --- a/Packages/com.bywaystudios.meowmentdebugtool/Runtime/CustomButtonsModule.cs +++ b/Packages/com.bywaystudios.meowmentdebugtool/Runtime/CustomButtonsModule.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using System.Linq; using System.Reflection; using UnityEngine; using UnityEngine.UI; @@ -7,7 +9,7 @@ using TMPro; namespace MeowmentDebugTool { /// - /// 自定义按钮模块 - 通过反射加载标记为DebugButton的方法 + /// 自定义按钮模块 - 通过反射加载标记为DebugButton的方法,支持分组显示 /// public class CustomButtonsModule : IDebugModule { @@ -25,6 +27,20 @@ namespace MeowmentDebugTool // 关闭窗口回调 private Action onCloseWindowCallback; + + // 分组相关 + private Dictionary> buttonGroups = new Dictionary>(); + #endregion + + #region 内部类 + /// + /// 按钮信息 + /// + private class ButtonInfo + { + public MethodInfo Method; + public DebugButtonAttribute Attribute; + } #endregion #region 构造函数 @@ -43,6 +59,13 @@ namespace MeowmentDebugTool public void Initialize() { Debug.Log("[CustomButtonsModule] 初始化自定义按钮模块..."); + + if (buttonContainer == null || buttonPrefab == null) + { + Debug.LogError("[CustomButtonsModule] 必要组件缺失,初始化失败"); + return; + } + LoadCustomButtons(); } @@ -83,7 +106,7 @@ namespace MeowmentDebugTool } #endregion - #region 私有方法 + #region 私有方法 - 按钮加载 /// /// 加载所有自定义按钮(使用反射) /// @@ -95,11 +118,8 @@ namespace MeowmentDebugTool return; } - // 清空现有按钮 - foreach (Transform child in buttonContainer) - { - UnityEngine.Object.Destroy(child.gameObject); - } + // 清空现有数据 + buttonGroups.Clear(); // 查找所有标记为DebugButton的方法 var assemblies = AppDomain.CurrentDomain.GetAssemblies(); @@ -116,7 +136,20 @@ namespace MeowmentDebugTool var attribute = method.GetCustomAttribute(); if (attribute != null) { - CreateCustomButton(method, attribute); + // 获取组名(如果为空则使用"默认") + string groupName = string.IsNullOrEmpty(attribute.GroupName) ? "默认" : attribute.GroupName; + + // 添加到对应的组 + if (!buttonGroups.ContainsKey(groupName)) + { + buttonGroups[groupName] = new List(); + } + + buttonGroups[groupName].Add(new ButtonInfo + { + Method = method, + Attribute = attribute + }); } } } @@ -127,6 +160,252 @@ namespace MeowmentDebugTool Debug.LogWarning($"[CustomButtonsModule] 无法访问程序集 {assembly.FullName}: {e.Message}"); } } + + Debug.Log($"[CustomButtonsModule] 共找到 {buttonGroups.Count} 个按钮组"); + foreach (var group in buttonGroups) + { + Debug.Log($" - {group.Key}: {group.Value.Count} 个按钮"); + } + + // 显示所有组的按钮 + ShowAllGroupsWithTitles(); + } + + /// + /// 显示所有组的按钮,每个组带标题 + /// + private void ShowAllGroupsWithTitles() + { + // 清空现有内容 + foreach (Transform child in buttonContainer) + { + UnityEngine.Object.Destroy(child.gameObject); + } + + // 确保 buttonContainer 使用垂直布局而不是网格布局 + SetupButtonContainerLayout(); + + // 按组名排序("默认"组排在最前面) + var sortedGroups = buttonGroups.OrderBy(kvp => kvp.Key == "默认" ? "" : kvp.Key); + + foreach (var group in sortedGroups) + { + string groupName = group.Key; + List buttons = group.Value; + + // 为每个组创建一个独立的容器 + GameObject groupContainer = CreateGroupContainer(groupName); + + // 在组容器中创建标题 + CreateGroupTitle(groupName, groupContainer.transform); + + // 在组容器中创建该组的所有按钮 + foreach (var buttonInfo in buttons) + { + CreateCustomButtonInGroup(buttonInfo.Method, buttonInfo.Attribute, groupContainer.transform); + } + } + + // 重置滚动位置到顶部 + if (buttonsScrollRect != null) + { + Canvas.ForceUpdateCanvases(); + buttonsScrollRect.verticalNormalizedPosition = 1f; + } + } + + /// + /// 设置 buttonContainer 的布局 + /// + private void SetupButtonContainerLayout() + { + if (buttonContainer == null) + { + Debug.LogError("[CustomButtonsModule] buttonContainer 为 null,无法设置布局"); + return; + } + + GameObject containerObject = buttonContainer.gameObject; + + // 移除可能存在的 GridLayoutGroup + GridLayoutGroup gridLayout = containerObject.GetComponent(); + if (gridLayout != null) + { + UnityEngine.Object.DestroyImmediate(gridLayout); + } + + // 添加或获取 VerticalLayoutGroup + VerticalLayoutGroup verticalLayout = containerObject.GetComponent(); + if (verticalLayout == null) + { + verticalLayout = containerObject.AddComponent(); + + if (verticalLayout == null) + { + Debug.LogError("[CustomButtonsModule] 错误:无法添加 VerticalLayoutGroup!"); + return; + } + } + + // 配置垂直布局 + verticalLayout.childForceExpandWidth = true; + verticalLayout.childForceExpandHeight = false; + verticalLayout.childControlWidth = true; + verticalLayout.childControlHeight = true; + verticalLayout.spacing = 20; + verticalLayout.padding = new RectOffset(10, 10, 10, 10); + + // 确保有 ContentSizeFitter + ContentSizeFitter sizeFitter = containerObject.GetComponent(); + if (sizeFitter == null) + { + sizeFitter = containerObject.AddComponent(); + } + + sizeFitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize; + sizeFitter.horizontalFit = ContentSizeFitter.FitMode.Unconstrained; + } + + /// + /// 创建组容器 + /// + private GameObject CreateGroupContainer(string groupName) + { + GameObject groupContainer = new GameObject($"Group_{groupName}"); + groupContainer.transform.SetParent(buttonContainer, false); + + // 添加RectTransform + RectTransform rectTransform = groupContainer.AddComponent(); + + // 添加VerticalLayoutGroup,让标题和按钮垂直排列 + VerticalLayoutGroup verticalLayout = groupContainer.AddComponent(); + verticalLayout.childForceExpandWidth = true; + verticalLayout.childForceExpandHeight = false; + verticalLayout.childControlWidth = true; + verticalLayout.childControlHeight = true; + verticalLayout.spacing = 5; + verticalLayout.padding = new RectOffset(0, 0, 10, 10); + + // 添加ContentSizeFitter,让容器自动调整大小 + ContentSizeFitter sizeFitter = groupContainer.AddComponent(); + sizeFitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize; + sizeFitter.horizontalFit = ContentSizeFitter.FitMode.Unconstrained; + + // 添加LayoutElement,确保占满宽度 + LayoutElement layoutElement = groupContainer.AddComponent(); + layoutElement.flexibleWidth = 1; + + return groupContainer; + } + + /// + /// 创建组标题 + /// + private void CreateGroupTitle(string groupName, Transform parent) + { + // 创建标题GameObject + GameObject titleObj = new GameObject($"Title_{groupName}"); + titleObj.transform.SetParent(parent, false); + + // 添加RectTransform + RectTransform rectTransform = titleObj.AddComponent(); + + // 添加TextMeshProUGUI组件 + TMP_Text titleText = titleObj.AddComponent(); + titleText.text = groupName; + titleText.fontSize = 32; + titleText.fontStyle = FontStyles.Bold; + titleText.alignment = TextAlignmentOptions.Left; + titleText.color = new Color(1f, 1f, 1f, 0.9f); + titleText.margin = new Vector4(10, 5, 0, 5); + + // 应用保存的字体 + if (savedFontAsset != null) + { + titleText.font = savedFontAsset; + } + + // 添加LayoutElement + LayoutElement layoutElement = titleObj.AddComponent(); + layoutElement.preferredHeight = 50; + layoutElement.flexibleWidth = 1; + } + + /// + /// 在组容器中创建按钮(需要创建一个按钮区域容器) + /// + private void CreateCustomButtonInGroup(MethodInfo method, DebugButtonAttribute attribute, Transform groupParent) + { + // 查找或创建按钮区域容器 + Transform buttonArea = groupParent.Find("ButtonArea"); + if (buttonArea == null) + { + GameObject buttonAreaObj = new GameObject("ButtonArea"); + buttonAreaObj.transform.SetParent(groupParent, false); + + // 添加GridLayoutGroup,让按钮以网格形式排列 + GridLayoutGroup gridLayout = buttonAreaObj.AddComponent(); + gridLayout.cellSize = new Vector2(200, 80); // 按钮大小,根据你的buttonPrefab调整 + gridLayout.spacing = new Vector2(10, 10); + gridLayout.constraint = GridLayoutGroup.Constraint.Flexible; + gridLayout.childAlignment = TextAnchor.UpperLeft; + + // 添加ContentSizeFitter + ContentSizeFitter sizeFitter = buttonAreaObj.AddComponent(); + sizeFitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize; + sizeFitter.horizontalFit = ContentSizeFitter.FitMode.Unconstrained; + + // 添加LayoutElement + LayoutElement layoutElement = buttonAreaObj.AddComponent(); + layoutElement.flexibleWidth = 1; + + buttonArea = buttonAreaObj.transform; + } + + // 在按钮区域中创建按钮 + GameObject buttonObj = UnityEngine.Object.Instantiate(buttonPrefab, buttonArea); + Button button = buttonObj.GetComponent