using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using Object = UnityEngine.Object;
namespace EnhancedHierarchy {
///
/// Log Entries from the console, to check if a game object has any errors or warnings.
///
public sealed class LogEntry {
private const double UPDATE_FREQUENCY = 0.75; // Every 750ms
private static readonly Type logEntriesType;
private static readonly Type logEntryType;
public int RowIndex { get; private set; }
public string Condition { get; private set; }
public int ErrorNum { get; private set; }
public string File { get; private set; }
public int Line { get; private set; }
public int Column { get; private set; }
public EntryMode Mode { get; private set; }
public int InstanceID { get; private set; }
public int Identifier { get; private set; }
public Object ObjectReference { get; private set; }
public MonoScript Script { get; private set; }
public Type ClassType { get; private set; }
public static Dictionary> gameObjectEntries = new Dictionary>(100);
public static List compileEntries = new List(100);
private static int lastCount;
private static bool entriesDirty;
private static bool lastCompileFailedState;
private static double lastUpdatedTime;
private static readonly Icons.Warnings warnings = new Icons.Warnings();
static LogEntry() {
try {
logEntriesType = ReflectionHelper.FindType("UnityEditorInternal.LogEntries");
logEntryType = ReflectionHelper.FindType("UnityEditorInternal.LogEntry");
if (logEntriesType == null)
logEntriesType = ReflectionHelper.FindType("UnityEditor.LogEntries");
if (logEntryType == null)
logEntryType = ReflectionHelper.FindType("UnityEditor.LogEntry");
ReloadReferences();
} catch (Exception e) {
Debug.LogException(e);
Preferences.ForceDisableButton(new Icons.Warnings());
}
Application.logMessageReceived += (logString, stackTrace, type) => MarkEntriesDirty();
EditorApplication.update += () => {
try {
#if UNITY_2017_1_OR_NEWER
if (!entriesDirty && EditorUtility.scriptCompilationFailed != lastCompileFailedState) {
lastCompileFailedState = EditorUtility.scriptCompilationFailed;
MarkEntriesDirty();
}
#endif
if (EditorApplication.timeSinceStartup - lastUpdatedTime > UPDATE_FREQUENCY) {
if (!entriesDirty) {
var currentCount = GetLogCount();
if (lastCount > currentCount) { // Console possibly cleared
if (Preferences.DebugEnabled)
Debug.Log("Detected console clear");
MarkEntriesDirty();
}
lastCount = currentCount;
}
if (entriesDirty)
ReloadReferences();
}
} catch (Exception e) {
Debug.LogException(e);
Preferences.ForceDisableButton(new Icons.Warnings());
}
};
}
private LogEntry(object nativeEntry, int rowIndex) {
RowIndex = rowIndex;
if (nativeEntry.HasField("condition"))
Condition = nativeEntry.GetInstanceField("condition");
else if (nativeEntry.HasField("message"))
Condition = nativeEntry.GetInstanceField("message");
else
throw new MissingFieldException("LogEntry doesn't have a message field");
if (nativeEntry.HasField("errorNum"))
ErrorNum = nativeEntry.GetInstanceField("errorNum");
File = nativeEntry.GetInstanceField("file");
Line = nativeEntry.GetInstanceField("line");
if (nativeEntry.HasField("column"))
Column = nativeEntry.GetInstanceField("column");
Mode = nativeEntry.GetInstanceField("mode");
InstanceID = nativeEntry.GetInstanceField("instanceID");
Identifier = nativeEntry.GetInstanceField("identifier");
if (InstanceID != 0)
ObjectReference = EditorUtility.InstanceIDToObject(InstanceID);
if (ObjectReference)
Script = ObjectReference as MonoScript;
if (Script)
ClassType = Script.GetClass();
}
public static void MarkEntriesDirty() {
if (!entriesDirty && Preferences.Enabled && Preferences.IsButtonEnabled(warnings))
entriesDirty = true;
}
private static void ReloadReferences() {
if (Preferences.DebugEnabled)
Debug.Log("Reloading Logs References");
gameObjectEntries.Clear();
compileEntries.Clear();
try {
var count = logEntriesType.InvokeStaticMethod("StartGettingEntries");
var nativeEntry = Activator.CreateInstance(logEntryType);
for (var i = 0; i < count; i++) {
logEntriesType.InvokeStaticMethod("GetEntryInternal", i, nativeEntry);
var proxyEntry = new LogEntry(nativeEntry, i);
var go = proxyEntry.ObjectReference as GameObject;
if (proxyEntry.ObjectReference && !go) {
var component = proxyEntry.ObjectReference as Component;
if (component)
go = component.gameObject;
}
// if(entry.HasMode(EntryMode.ScriptCompileError | EntryMode.ScriptCompileWarning | EntryMode.AssetImportWarning) && entry.ClassType != null)
// if(!referencedComponents.Any(e => e.ClassType == entry.ClassType))
if (proxyEntry.ClassType != null)
compileEntries.Add(proxyEntry);
if (go)
if (gameObjectEntries.ContainsKey(go))
gameObjectEntries[go].Add(proxyEntry);
else
gameObjectEntries.Add(go, new List() { proxyEntry });
}
EditorApplication.RepaintHierarchyWindow();
} catch (Exception e) {
Debug.LogException(e);
Preferences.ForceDisableButton(new Icons.Warnings());
} finally {
entriesDirty = false;
lastUpdatedTime = EditorApplication.timeSinceStartup;
logEntriesType.InvokeStaticMethod("EndGettingEntries");
}
}
public bool HasMode(EntryMode toCheck) {
return (Mode & toCheck) != 0;
}
public void OpenToEdit() {
logEntriesType.InvokeStaticMethod("RowGotDoubleClicked", RowIndex);
}
private static int GetLogCount() {
return logEntriesType.InvokeStaticMethod("GetCount");
}
public override string ToString() {
return Condition;
}
}
}