【编辑器】UnityConsole界面双击日志跳转

本文介绍如何在Unity中实现日志跳转功能,通过不到一百行代码即可完成。主要涉及UnityEditor.ConsoleWindow类的使用,以及如何通过解析日志信息定位到具体的代码文件和行数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

环境

发布正式包时,Unity的原生Log肯定是要屏蔽的。最常用的做法就是自己封装一下,实现一个debug。不过这样的话,双击跳转就会去到Debug类里面去。为了方便查bug,实现一下日志跳转。

实现

看了一下网上的资料,思路应该就是通过类型实例化Console界面,得到Log具体数据。然后解析跳转。网上的实现步骤稍微复杂了一点。这里给出不到一百行代码,轻松实现功能。这个代码需要放到Editor目录下。

using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text.RegularExpressions;
using UnityEditor;
public class LogEditor
{    
    private static LogEditor m_Instance;    
    public static LogEditor GetInstacne()
    {
        if (m_Instance == null)
        {
            m_Instance = new LogEditor();
        }        return m_Instance;
    }
    private const string DEBUGERFILEPATH = "Assets/Debuger/Debuger.cs";//替换成你自己的封装类地址
    private int m_DebugerFileInstanceId;
    private Type m_ConsoleWindowType = null;
    private FieldInfo m_ActiveTextInfo;
    private FieldInfo m_ConsoleWindowFileInfo;    

    private LogEditor()
    {
        UnityEngine. Object debuggerFile = AssetDatabase.LoadAssetAtPath(DEBUGERFILEPATH,typeof(UnityEngine.Object));
        m_DebugerFileInstanceId = debuggerFile.GetInstanceID();        
        m_ConsoleWindowType = Type.GetType("UnityEditor.ConsoleWindow,UnityEditor");
        m_ActiveTextInfo = m_ConsoleWindowType.GetField("m_ActiveText", BindingFlags.Instance | BindingFlags.NonPublic);
        m_ConsoleWindowFileInfo = m_ConsoleWindowType.GetField("ms_ConsoleWindow", BindingFlags.Static | BindingFlags.NonPublic);
    }
    
    [UnityEditor.Callbacks.OnOpenAssetAttribute(-1)]
    private static bool OnOpenAsset(int instanceID, int line)
    {
        if (instanceID == LogEditor.GetInstacne().m_DebugerFileInstanceId)
        {
            return LogEditor.GetInstacne().FindCode();
        }
        return false;
    }    
    
    public bool FindCode()
    {
        var windowInstance = m_ConsoleWindowFileInfo.GetValue(null);
        var activeText = m_ActiveTextInfo.GetValue(windowInstance);        
        string[] contentStrings = activeText.ToString().Split('\n');
        List<string> filePath = new List<string>();
        for (int index = 0; index < contentStrings.Length; index++)
        {
            if (contentStrings[index].Contains("at"))
            {
                filePath.Add(contentStrings[index]);
            }
        }        bool success = PingAndOpen(filePath[1]);
        return success;
    }    
    
    public bool PingAndOpen(string fileContext)
    {
        string regexRule = @"at ([\w\W]*):(\d+)\)";        
        Match match = Regex.Match(fileContext, regexRule);
        if (match.Groups.Count > 1)
        {
            string path = match.Groups[1].Value;
            string line = match.Groups[2].Value;
            UnityEngine.Object codeObject = AssetDatabase.LoadAssetAtPath(path, typeof(UnityEngine.Object));
            if (codeObject == null)
            {
                return false;
            }            
            EditorGUIUtility.PingObject(codeObject);
            AssetDatabase.OpenAsset(codeObject, int.Parse(line));            
            return true;
        }        
        return false;
    }
}

技术点

如果只是要实现功能,看上面代码就足够了。接下来讲几个点说明为什么要这样做。重点在于ConsoleWindow的源码。
1."UnityEditor.ConsoleWindow"是Console界面的类。需要查看的话,装个ReSharper到VS,或者装一个ILSpy去反编译。这样就都能看到源码了。
在这里插入图片描述
2.“m_ActiveText”是当前被选中的Log的详细信息。就是我们平时查看堆栈数据的那段内容。
在这里插入图片描述
在这里插入图片描述
3.AssetDatabase.OpenAsset(codeObject, int.Parse(line));第二个参数是行数。这个函数会重新触发OnOpenAssetAttribute回调。这就是为什么需要判断Degger类的实例id,是这个才进去重定位。不判断这个也可用其他来判断。反正要小心死循环。

参考文档:

1.http://www.cppblog.com/heath/archive/2016/06/21/213777.html
2.https://blog.youkuaiyun.com/qq_26999509/article/details/78516237
3.http://dsqiu.iteye.com/blog/2263664

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值