Unity Log 跳转重定向
- 为何要写这个重定向?
- 开始
Hello大家好,这里VimalaEric,今天给大家介绍一个实用脚本 UnityConsoler 跳转重定向。
为何要写这个重定向?
因为有时候会自己写脚本打log,从而实现如输出不同的颜色、Release宏定义、 或者Debug.Log 要向服务器发送数据等。 有时候会自己写一个DebugExtension类,调用unity的Debug的同时封装一些我们需要的内容在上面。
那么在 Console双击信息的时候,会定位到 Debug调用的位置,而不是 DebugEx调用的位置,这篇脚本 是做重新定位双击打开脚本位置的。
开始
在开始之前,首先感谢 @神一般的狄狄 带来的思路。我也是在做公司架构的时候发现这个问题,遂找到了这篇文章。https://blog.csdn.net/qq_37776196/article/details/85324348
基本逻辑如其所示一般,然而在使用时我稍作改动。
1来兼容了对更深层Log的点击重定向。
2来增加了部分注释,微调了部分判断是否属于LogExtension 的逻辑。
将代码贴在下面,以供大家使用。
/** CopyRight By VimalaEric & Fox.Huang* 2024.4.28*/using UnityEngine;
using System;
using System.Reflection;
using System.Text.RegularExpressions;/// <summary>
/// Unity Log重定向。编辑器下,点击log跳转到代码位置
/// </summary>
public class ConsolerRedirection
{
#if UNITY_EDITOR/// <summary>/// 最大匹配检索深度/// </summary>private const int MaxRegexMatch = 20;// 处理asset打开的callback函数[UnityEditor.Callbacks.OnOpenAssetAttribute(0)]static bool OnOpenAsset(int instance, int line){// 自定义函数,用来获取stacktracestring stack_trace = GetStackTrace();// 通过stacktrace来判断是否是自定义Logif (!string.IsNullOrEmpty(stack_trace)){if (stack_trace.StartsWith("* "))//这里的“* ”是从堆栈中筛选自定义的Log{//匹配所有Log行Match matches = Regex.Match(stack_trace, @"\(at(.+)\)", RegexOptions.IgnoreCase);string pathline = "";if (matches.Success) {/* 找到跳转目标层:* 需要分别判断点击为首层还是其它层。* 首层时:跳过自定义Log层,向下一层跳转。* 其它层:直接跳转。*/if (matches.Groups[1].Value.EndsWith(line.ToString())) //首层{matches = matches.NextMatch();}else{for (int i = 0; i < MaxRegexMatch; i++) //其他层{if (matches.Groups[1].Value.EndsWith(line.ToString()))break;matches = matches.NextMatch();}}//跳转逻辑if (matches.Success){pathline = matches.Groups[1].Value;pathline = pathline.Replace(" ", "");//找到代码及行数int split_index = pathline.LastIndexOf(":");string path = pathline.Substring(0, split_index);line = Convert.ToInt32(pathline.Substring(split_index + 1));string fullpath = Application.dataPath.Substring(0, Application.dataPath.LastIndexOf("Assets"));fullpath += path;string strPath = fullpath.Replace('/', '\\');UnityEditorInternal.InternalEditorUtility.OpenFileAtLineExternal(strPath, line);}else{Debug.LogError("DebugCodeLocation OnOpenAsset, Error StackTrace");}matches = matches.NextMatch();}return true;}}return false;}static string GetStackTrace(){// 找到UnityEditor.EditorWindow的assemblyvar assembly_unity_editor = Assembly.GetAssembly(typeof(UnityEditor.EditorWindow));if (assembly_unity_editor == null) return null;// 找到类UnityEditor.ConsoleWindowvar type_console_window = assembly_unity_editor.GetType("UnityEditor.ConsoleWindow");if (type_console_window == null) return null;// 找到UnityEditor.ConsoleWindow中的成员ms_ConsoleWindowvar field_console_window = type_console_window.GetField("ms_ConsoleWindow",System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);if (field_console_window == null) return null;// 获取ms_ConsoleWindow的值var instance_console_window = field_console_window.GetValue(null);if (instance_console_window == null) return null;// 如果console窗口时焦点窗口的话,获取stacktraceif ((object)UnityEditor.EditorWindow.focusedWindow == instance_console_window){// 通过assembly获取类ListViewStatevar type_list_view_state = assembly_unity_editor.GetType("UnityEditor.ListViewState");if (type_list_view_state == null) return null;// 找到类UnityEditor.ConsoleWindow中的成员m_ListViewvar field_list_view = type_console_window.GetField("m_ListView",System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);if (field_list_view == null) return null;// 获取m_ListView的值var value_list_view = field_list_view.GetValue(instance_console_window);if (value_list_view == null) return null;// 找到类UnityEditor.ConsoleWindow中的成员m_ActiveTextvar field_active_text = type_console_window.GetField("m_ActiveText",System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);if (field_active_text == null) return null;// 获得m_ActiveText的值,就是我们需要的stacktracestring value_active_text = field_active_text.GetValue(instance_console_window).ToString();return value_active_text;}return null;}
#endif
}