Unity v2020.3 コンソール ウィンドウのログ リダイレクト

プロジェクトは v2020.3 にアップグレードされ、元の v2017.3 ログ リダイレクトは利用できなくなりました。

v2017.3 ログ リダイレクト参照アドレス: https://blog.csdn.net/sufcd/article/details/72553678

理由は、UnityEditor.LogEntry と UnityEditor.LogEntries の API が変更されたためです。

直接移植すると、null エラーと Assert Failed が報告されます。

オリジナルのバージョンと比較すると、null エラーを処理するために条件フィールドがメッセージに変更され、Assert Failed の問題を処理するために StartGettingEntries と EndGettingEntries が使用されます。

コードは参考用です。直接移植しても効果がない場合があります

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using MiniJSON;
using UnityEditor;
using UnityEditor.Callbacks;
using UnityEngine;

/// <summary>
/// 日志重定向,双击调用Debugger而生成的日志,将其定位到正确的地方而不是Debugger.cs中
/// </summary>
public static class DebuggerRedirect
{
    private const string LogCsName = "Debugger.cs";
    private static object _logListView;
    private static EditorWindow _consoleWindow;
    private static MethodInfo _logEntriesGetEntry;
    private static MethodInfo _logEntriesStartGettingEntries;
    private static MethodInfo _logEntriesEndGettingEntries;
    private static FieldInfo _logListViewCurrentRow;
    private static FieldInfo _logEntryMessage;
    private static object _logEntry;
    private static int _openInstanceID;
    private static int _openLine;

    private static bool GetConsoleWindowListView()
    {
        if (_logListView != null) return true;

        var unityEditorAssembly = Assembly.GetAssembly(typeof(EditorWindow));
        var consoleWindowType = unityEditorAssembly.GetType("UnityEditor.ConsoleWindow");
        var fieldInfo = consoleWindowType.GetField(
            "ms_ConsoleWindow", BindingFlags.Static | BindingFlags.NonPublic
        );
        _consoleWindow = fieldInfo.GetValue(null) as EditorWindow;
        if (_consoleWindow == null)
        {
            _logListView = null;
            return false;
        }

        var listViewFieldInfo = consoleWindowType.GetField(
            "m_ListView", BindingFlags.Instance | BindingFlags.NonPublic
        );
        _logListView = listViewFieldInfo.GetValue(_consoleWindow);
        _logListViewCurrentRow = listViewFieldInfo.FieldType.GetField(
            "row", BindingFlags.Instance | BindingFlags.Public
        );

        var logEntriesType = unityEditorAssembly.GetType("UnityEditor.LogEntries");
        _logEntriesGetEntry = logEntriesType.GetMethod(
            "GetEntryInternal", BindingFlags.Static | BindingFlags.Public
        );
        _logEntriesStartGettingEntries = logEntriesType.GetMethod(
            "StartGettingEntries", BindingFlags.Static | BindingFlags.Public
        );
        _logEntriesEndGettingEntries = logEntriesType.GetMethod(
            "EndGettingEntries", BindingFlags.Static | BindingFlags.Public
        );

        var logEntryType = unityEditorAssembly.GetType("UnityEditor.LogEntry");
        _logEntry = Activator.CreateInstance(logEntryType);
        _logEntryMessage = logEntryType.GetField("message", BindingFlags.Instance | BindingFlags.Public);

        return true;
    }


    private static string GetListViewRowCount(ref int line)
    {
        var row = (int) _logListViewCurrentRow.GetValue(_logListView);
        _logEntriesStartGettingEntries.Invoke(null, null);
        _logEntriesGetEntry.Invoke(null, new[] {row, _logEntry});
        _logEntriesEndGettingEntries.Invoke(null, null);
        var message = _logEntryMessage.GetValue(_logEntry) as string;
        var index = message.IndexOf(LogCsName, StringComparison.Ordinal);
        if (index < 0)
            return null;

        var lineIndex = message.IndexOf(")", index, StringComparison.Ordinal);
        message = message.Substring(lineIndex + 2);
        index = message.IndexOf(".cs:", StringComparison.Ordinal);
        if (index < 0)
            return null;
        var lineEndIndex = message.IndexOf(")", index, StringComparison.Ordinal);
        var lineStr = message.Substring(index + 4, lineEndIndex - index - 4);
        int.TryParse(lineStr, out line);
        message = message.Substring(0, index);
        var startIndex = message.LastIndexOf("/", StringComparison.Ordinal);
        var fileName = message.Substring(startIndex + 1);
        fileName += ".cs";
        return fileName;

    }

    private static string IsLuaDebugger(ref int line)
    {
        var row = (int) _logListViewCurrentRow.GetValue(_logListView);
        _logEntriesStartGettingEntries.Invoke(null, null);
        _logEntriesGetEntry.Invoke(null, new[] {row, _logEntry});
        _logEntriesEndGettingEntries.Invoke(null, null);
        var message = _logEntryMessage.GetValue(_logEntry) as string;
        if (message.Contains("print_json_start:") && message.Contains(":print_json_end"))
        {
            var start = message.IndexOf("print_json_start:", StringComparison.Ordinal);
            var end = message.IndexOf(":print_json_end", StringComparison.Ordinal);
            var filename = message.Substring(start + "print_json_start:".Length,
                end - start - "print_json_start:".Length);
            var dic = Json.Deserialize(filename) as Dictionary<string, object>;
            line = int.Parse(dic["curLine"].ToString());
            filename = dic["curSrcFile"].ToString();
            return filename;
        }

        if (message.Contains("stack traceback:"))
        {
            var start = message.IndexOf("stack traceback:", StringComparison.Ordinal) +
                        "stack traceback:\n".Length;
            var end = message.IndexOf("(...tail calls...)", StringComparison.Ordinal);
            if (end == -1)
                end = message.Length;
            var str = message.Substring(start, end - start).Split('\n');
            for (int i = 0, len = str.Length; i < len; i++)
            {
                var str2 = str[i].Split(':');
                if (str2.Length > 2)
                {
                    int.TryParse(str2[1], out line);
                    if (line > 0)
                        if (Regex.IsMatch(str2[0], @"^\s+[a-zA-Z0-9.]+"))
                            return str2[0].TrimStart('\t').TrimStart(' ');
                }
            }
        }

        var index = message.IndexOf(LogCsName, StringComparison.Ordinal);
        if (index < 0)
            return null;

        return null;
    }

    [OnOpenAssetAttribute(0)]
    public static bool OnOpenAsset(int instanceID, int line)
    {
        if (!EditorWindow.focusedWindow.titleContent.text.Equals("Console")) return false;
        var openFileName = EditorUtility.InstanceIDToObject(instanceID).name;
        if (!openFileName.StartsWith("Debugger"))
            return false;

        if (_openInstanceID == instanceID && _openLine == line)
        {
            _openInstanceID = -1;
            _openLine = -1;
            return false;
        }

        _openInstanceID = instanceID;
        _openLine = line;
        var fileName = EditorUtility.InstanceIDToObject(instanceID).name;
        if (fileName != LogCsName.Substring(0, LogCsName.IndexOf(".cs", StringComparison.Ordinal)))
            return false;
        
        if (!GetConsoleWindowListView()) return false;
        
        fileName = GetListViewRowCount(ref line) ?? IsLuaDebugger(ref line);
        if (fileName == null) return false;

        if (fileName.EndsWith(".cs", StringComparison.Ordinal))
        {
            var filter = fileName.Substring(0, fileName.Length - 3);
            filter += " t:TextAsset";
            var searchPaths = AssetDatabase.FindAssets(filter);
          
            for (var i = 0; i < searchPaths.Length; i++)
            {
                var path = AssetDatabase.GUIDToAssetPath(searchPaths[i]);
                if (fileName == Path.GetFileName(path))
                {
                    var obj = AssetDatabase.LoadAssetAtPath(path, typeof(TextAsset));
                    AssetDatabase.OpenAsset(obj, line);
                    return true;
                }
            }
        }
        else
        {
            var paths = fileName.Split('.');
            fileName = paths.Aggregate("", (current, t) => current + "/" + t);
            fileName += ".lua.txt";
            var path = "/Lua/LuaScripts" + fileName;
            if (!File.Exists(Application.dataPath + path)) path = "/Lua/Core/LuaScripts" + fileName;

            var obj = AssetDatabase.LoadAssetAtPath("Assets" + path, typeof(TextAsset));
            AssetDatabase.OpenAsset(obj, line);
            return true;
        }

        return false;
    }
}

おすすめ

転載: blog.csdn.net/qq_41225779/article/details/125552101