diff --git a/Unity/Assets/Editor/LogRedirection.cs b/Unity/Assets/Editor/LogRedirection.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ebf0c1924b9902a76afc9402b976e72191701a54
--- /dev/null
+++ b/Unity/Assets/Editor/LogRedirection.cs
@@ -0,0 +1,106 @@
+using System.Reflection;
+using System.Text.RegularExpressions;
+using UnityEditor;
+using UnityEditor.Callbacks;
+using UnityEditorInternal;
+using UnityEngine;
+
+///
+/// 日志重定向相关的实用函数。
+/// author: NOW
+/// Time: 20180226
+///
+internal static class LogRedirection
+{
+ private static readonly Regex LogRegex = new Regex(@" \(at (.+)\:(\d+)\)\r?\n");
+
+ [OnOpenAsset(0)]
+ private static bool OnOpenAsset(int instanceId, int line)
+ {
+ string selectedStackTrace = GetSelectedStackTrace();
+ if (string.IsNullOrEmpty(selectedStackTrace))
+ {
+ return false;
+ }
+
+ if (!selectedStackTrace.Contains("Model.Log"))
+ {
+ return false;
+ }
+
+ Match match = LogRegex.Match(selectedStackTrace);
+ if (!match.Success)
+ {
+ return false;
+ }
+
+ // 跳过第一次匹配的堆栈
+ match = match.NextMatch();
+ if (!match.Success)
+ {
+ return false;
+ }
+ if (!selectedStackTrace.Contains("Hotfix.Log"))
+ {
+ InternalEditorUtility.OpenFileAtLineExternal(Application.dataPath.Replace("Assets", "") + match.Groups[1].Value, int.Parse(match.Groups[2].Value));
+
+ return true;
+ }
+ else
+ {
+ // 跳过第2次匹配的堆栈
+ match = match.NextMatch();
+ if (!match.Success)
+ {
+ return false;
+ }
+ InternalEditorUtility.OpenFileAtLineExternal(Application.dataPath.Replace("Assets", "") + match.Groups[1].Value, int.Parse(match.Groups[2].Value));
+
+ return true;
+ }
+
+
+
+
+ }
+
+ private static string GetSelectedStackTrace()
+ {
+ Assembly editorWindowAssembly = typeof(EditorWindow).Assembly;
+ if (editorWindowAssembly == null)
+ {
+ return null;
+ }
+
+ System.Type consoleWindowType = editorWindowAssembly.GetType("UnityEditor.ConsoleWindow");
+ if (consoleWindowType == null)
+ {
+ return null;
+ }
+
+ FieldInfo consoleWindowFieldInfo = consoleWindowType.GetField("ms_ConsoleWindow", BindingFlags.Static | BindingFlags.NonPublic);
+ if (consoleWindowFieldInfo == null)
+ {
+ return null;
+ }
+
+ EditorWindow consoleWindow = consoleWindowFieldInfo.GetValue(null) as EditorWindow;
+ if (consoleWindow == null)
+ {
+ return null;
+ }
+
+ if (consoleWindow != EditorWindow.focusedWindow)
+ {
+ return null;
+ }
+
+ FieldInfo activeTextFieldInfo = consoleWindowType.GetField("m_ActiveText", BindingFlags.Instance | BindingFlags.NonPublic);
+ if (activeTextFieldInfo == null)
+ {
+ return null;
+ }
+
+ return (string)activeTextFieldInfo.GetValue(consoleWindow);
+ }
+}
\ No newline at end of file
diff --git a/Unity/Assets/Editor/LogRedirection.cs.meta b/Unity/Assets/Editor/LogRedirection.cs.meta
new file mode 100644
index 0000000000000000000000000000000000000000..f5ce433795456a5797105e3d2a3c46e50ce1cbae
--- /dev/null
+++ b/Unity/Assets/Editor/LogRedirection.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 311d256107e00ed4bbdd3f0d81922b82
+timeCreated: 1525772883
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Unity/Unity.Editor.csproj b/Unity/Unity.Editor.csproj
index 2081845c18b120e50560d6ad5a5bfacf25d9d6c7..174a50c944b6ec21a97ce4805b91125b9c9f9b57 100644
--- a/Unity/Unity.Editor.csproj
+++ b/Unity/Unity.Editor.csproj
@@ -12,13 +12,16 @@
{E097FAD1-6243-4DAD-9C02-E9B9EFC3FFC1};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
.NETFramework
v4.6
-
-
+
+
+
+
VSTU
Editor:5
StandaloneWindows:5
2017.1.3p2
-
+
+
6
@@ -213,6 +216,7 @@
+
@@ -241,4 +245,4 @@
-
+
\ No newline at end of file