【Unity Consoler Redirection】Unity Log 跳转重定向

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)
    {
        // 自定义函数,用来获取stacktrace
        string stack_trace = GetStackTrace();

        // 通过stacktrace来判断是否是自定义Log
        if (!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的assembly
        var assembly_unity_editor = Assembly.GetAssembly(typeof(UnityEditor.EditorWindow));
        if (assembly_unity_editor == null) return null;

        // 找到类UnityEditor.ConsoleWindow
        var type_console_window = assembly_unity_editor.GetType("UnityEditor.ConsoleWindow");
        if (type_console_window == null) return null;
        // 找到UnityEditor.ConsoleWindow中的成员ms_ConsoleWindow
        var 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窗口时焦点窗口的话,获取stacktrace
        if ((object)UnityEditor.EditorWindow.focusedWindow == instance_console_window)
        {
            // 通过assembly获取类ListViewState
            var type_list_view_state = assembly_unity_editor.GetType("UnityEditor.ListViewState");
            if (type_list_view_state == null) return null;

            // 找到类UnityEditor.ConsoleWindow中的成员m_ListView
            var 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_ActiveText
            var 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的值,就是我们需要的stacktrace
            string value_active_text = field_active_text.GetValue(instance_console_window).ToString();
            return value_active_text;
        }

        return null;
    }
#endif
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值