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

ops/2024/9/24 20:52:23/

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
}

http://www.ppmy.cn/ops/32361.html

相关文章

数据结构——哈希表的平均查找长度

我们要首先知道哈希表是干什么的&#xff0c;哈希表并不是为了单纯存储数据的&#xff0c;他并不会减小存储这些数据使用的空间&#xff0c;而是为了实现快速的数据查找&#xff0c;插入和删除操作。map就可以使用哈希表来实现&#xff0c;所以map可以实现利用键来快速访问到值…

Unity 性能优化之Profiler窗口(二)怎么看懂这个分析器

提示&#xff1a;仅供参考&#xff0c;有误之处&#xff0c;麻烦大佬指出&#xff0c;不胜感激&#xff01; 文章目录 前言一、Profiler打开方式二、Profile简介添加没有的模块1.点击Profiler Modules&#xff08;分析器模块&#xff09;2.勾选GPU即可 自定义模块1.点击Profile…

windows内核开发:如何使用反汇编引擎

前言 最近在写个人项目中需要在内核模式下使用到反汇编引擎&#xff0c;找到几个并使用对比后我强烈推荐一款名叫BeaEngine的反汇编引擎。这是它的项目仓库链接&#xff1a;https://github.com/BeaEngine/beaengine 编译 项目下载下来后需要使用CMake编译&#xff0c;在此之前…

数据结构学习/复习6---双向链表的实现/随机指针链表练习/顺序表与链表对比/存储体系简述

一、链表的结构*8 二、带头双向循环链表的实现 注意事项1&#xff1a;是否需要断言于实际情况中传来的指针是否可以为空&#xff0c;不可以则要断言 三、链表、指针、拷贝经典练习题 四、顺序表与链表总结对比

【redis】Redis数据类型(四)Set类型

目录 Set类型介绍使用场景 Set类型数据结构set的单个元素的添加过程IntSet哈希表内存结构 常用命令SADD示例 SREM示例 SMEMBERS示例 SISMEMBER示例 SCARD示例 SMOVE示例 SPOP示例 SRANDMEMBER示例 SINTER示例 SINTERSTORE示例 SUNION示例 SUNIONSTORE示例 SDIFF示例 SDIFFSTORE…

MySQL 和 Hive 存储引擎对表数量、索引有那些限制?

目录 MySQL 存储引擎限制 Hive 存储引擎限制 MySQL 存储引擎限制 MySQL支持多种存储引擎&#xff0c;如InnoDB和MyISAM&#xff0c;每种引擎都有自己的特性和限制。 最大表数: InnoDB存储引擎没有硬性限制表的数量&#xff0c;它通常受限于操作系统文件数的限制。MyISAM存储引…

公开课—京东生产环境海量数据架构优化实战

文章目录 读多写少——主库用来写&#xff0c;从库用来读单库的写压力太大——数据库的垂直和水平拆分分表怎么分呢&#xff1f;hash分表range分表多数据源操作与分布式事务问题 ShardingSphare分库分表&#xff08;京东开源&#xff09;关联查询怎么办&#xff1f;跨多个库&am…

机器学习笔记-22

终章 至此吴恩达老师的机器学习课程已经完成啦&#xff0c;总结一下&#xff1a; 1.监督学习的算法&#xff1a;线性回归、逻辑回归、神经网络和向量机 2.无监督学习的算法&#xff1a;K-Means、PCA、异常检测 3.推荐系统、大规模数据处理、正则化、如何评估算法 4.上限分析、…