A few important fixes

* Reflection on Il2CppSystem-namespace instances has been fixed
* Type/Value Syntax highlighting generalized and improved globally
* Scene changes now refresh the scene-picker dropdown
* probably other minor stuff too
This commit is contained in:
sinaioutlander
2020-11-13 18:46:36 +11:00
parent dc449d4a1e
commit bc113e9093
21 changed files with 450 additions and 395 deletions

View File

@ -181,14 +181,17 @@ The following helper methods are available:
CurrentIndent = 0; CurrentIndent = 0;
bool stringState = false;
for (int i = 0; i < caret && i < newText.Length; i++) for (int i = 0; i < caret && i < newText.Length; i++)
{ {
char character = newText[i]; char character = newText[i];
if (character == CSharpLexer.indentOpen) if (character == '"')
stringState = !stringState;
else if (!stringState && character == CSharpLexer.indentOpen)
CurrentIndent++; CurrentIndent++;
else if (!stringState && character == CSharpLexer.indentClose)
if (character == CSharpLexer.indentClose)
CurrentIndent--; CurrentIndent--;
} }

View File

@ -17,8 +17,8 @@ namespace UnityExplorer.Console.Lexer
public override bool IsImplicitMatch(CSharpLexer lexer) public override bool IsImplicitMatch(CSharpLexer lexer)
{ {
if (!char.IsWhiteSpace(lexer.Previous) && if (!char.IsWhiteSpace(lexer.Previous) ||
!lexer.IsSpecialSymbol(lexer.Previous, DelimiterType.End)) lexer.IsSpecialSymbol(lexer.Previous, DelimiterType.End))
{ {
return false; return false;
} }

View File

@ -30,27 +30,15 @@ namespace UnityExplorer
{ {
Instance = this; Instance = this;
SceneManager.activeSceneChanged += DoSceneChange;
new ExplorerCore(); new ExplorerCore();
// HarmonyInstance.PatchAll(); // HarmonyInstance.PatchAll();
} }
internal static void DoSceneChange(Scene arg0, Scene arg1)
{
ExplorerCore.OnSceneChange();
}
internal void Update() internal void Update()
{ {
ExplorerCore.Update(); ExplorerCore.Update();
} }
internal void OnApplicationQuit()
{
DebugConsole.OnQuit();
}
} }
#endif #endif
@ -64,9 +52,6 @@ namespace UnityExplorer
public static readonly Harmony HarmonyInstance = new Harmony(ExplorerCore.GUID); public static readonly Harmony HarmonyInstance = new Harmony(ExplorerCore.GUID);
// temporary for Il2Cpp until scene change delegate works
private static string lastSceneName;
// Init // Init
public override void Load() public override void Load()
{ {
@ -85,12 +70,7 @@ namespace UnityExplorer
new ExplorerCore(); new ExplorerCore();
HarmonyInstance.PatchAll(); // HarmonyInstance.PatchAll();
}
internal static void DoSceneChange(Scene arg0, Scene arg1)
{
ExplorerCore.OnSceneChange();
} }
// BepInEx Il2Cpp mod class doesn't have monobehaviour methods yet, so wrap them in a dummy. // BepInEx Il2Cpp mod class doesn't have monobehaviour methods yet, so wrap them in a dummy.
@ -106,18 +86,6 @@ namespace UnityExplorer
internal void Update() internal void Update()
{ {
ExplorerCore.Update(); ExplorerCore.Update();
var scene = SceneManager.GetActiveScene();
if (scene.name != lastSceneName)
{
lastSceneName = scene.name;
DoSceneChange(scene, scene);
}
}
internal void OnApplicationQuit()
{
DebugConsole.OnQuit();
} }
} }
} }

View File

@ -7,29 +7,16 @@ using UnityEngine;
using UnityExplorer.Inspectors; using UnityExplorer.Inspectors;
using System.IO; using System.IO;
using UnityExplorer.Unstrip; using UnityExplorer.Unstrip;
using UnityEngine.SceneManagement;
namespace UnityExplorer namespace UnityExplorer
{ {
public class ExplorerCore public class ExplorerCore
{ {
public const string NAME = "UnityExplorer " + VERSION + " (" + PLATFORM + ", " + MODLOADER + ")"; public const string NAME = "UnityExplorer";
public const string VERSION = "3.0.0"; public const string VERSION = "3.0.0";
public const string AUTHOR = "Sinai"; public const string AUTHOR = "Sinai";
public const string GUID = "com.sinai.unityexplorer"; public const string GUID = "com.sinai.unityexplorer";
public const string PLATFORM =
#if CPP
"Il2Cpp";
#else
"Mono";
#endif
public const string MODLOADER =
#if ML
"MelonLoader";
#else
"BepInEx";
#endif
public const string EXPLORER_FOLDER = @"Mods\UnityExplorer"; public const string EXPLORER_FOLDER = @"Mods\UnityExplorer";
public static ExplorerCore Instance { get; private set; } public static ExplorerCore Instance { get; private set; }
@ -42,7 +29,7 @@ namespace UnityExplorer
public static bool m_showMenu; public static bool m_showMenu;
private static bool s_doneUIInit; private static bool s_doneUIInit;
private static float m_timeSinceStartup; private static float s_timeSinceStartup;
public ExplorerCore() public ExplorerCore()
{ {
@ -62,32 +49,11 @@ namespace UnityExplorer
InputManager.Init(); InputManager.Init();
ForceUnlockCursor.Init(); ForceUnlockCursor.Init();
#if CPP SetupEvents();
Application.add_logMessageReceived(new Action<string, string, LogType>(LogCallback));
#else
Application.logMessageReceived += LogCallback;
#endif
ShowMenu = true; ShowMenu = true;
Log($"{NAME} initialized."); Log($"{NAME} {VERSION} initialized.");
}
private static void SetShowMenu(bool show)
{
m_showMenu = show;
if (UIManager.CanvasRoot)
{
UIManager.CanvasRoot.SetActive(show);
if (show)
ForceUnlockCursor.SetEventSystem();
else
ForceUnlockCursor.ReleaseEventSystem();
}
ForceUnlockCursor.UpdateCursorControl();
} }
public static void Update() public static void Update()
@ -109,9 +75,9 @@ namespace UnityExplorer
private static void CheckUIInit() private static void CheckUIInit()
{ {
m_timeSinceStartup += Time.deltaTime; s_timeSinceStartup += Time.deltaTime;
if (m_timeSinceStartup > 0.1f) if (s_timeSinceStartup > 0.1f)
{ {
s_doneUIInit = true; s_doneUIInit = true;
try try
@ -129,11 +95,45 @@ namespace UnityExplorer
} }
} }
public static void OnSceneChange() private void SetupEvents()
{
#if CPP
try
{
Application.add_logMessageReceived(new Action<string, string, LogType>(LogCallback));
SceneManager.add_sceneLoaded(new Action<Scene, LoadSceneMode>((Scene a, LoadSceneMode b) => { OnSceneLoaded(); }));
SceneManager.add_activeSceneChanged(new Action<Scene, Scene>((Scene a, Scene b) => { OnSceneLoaded(); }));
}
catch { }
#else
Application.logMessageReceived += LogCallback;
SceneManager.sceneLoaded += (Scene a, LoadSceneMode b) => { OnSceneLoaded(); };
SceneManager.activeSceneChanged += (Scene a, Scene b) => { OnSceneLoaded(); };
#endif
}
internal void OnSceneLoaded()
{ {
UIManager.OnSceneChange(); UIManager.OnSceneChange();
} }
private static void SetShowMenu(bool show)
{
m_showMenu = show;
if (UIManager.CanvasRoot)
{
UIManager.CanvasRoot.SetActive(show);
if (show)
ForceUnlockCursor.SetEventSystem();
else
ForceUnlockCursor.ReleaseEventSystem();
}
ForceUnlockCursor.UpdateCursorControl();
}
private void LogCallback(string message, string stackTrace, LogType type) private void LogCallback(string message, string stackTrace, LogType type)
{ {
if (!DebugConsole.LogUnity) if (!DebugConsole.LogUnity)

View File

@ -15,25 +15,15 @@ namespace UnityExplorer
new ExplorerCore(); new ExplorerCore();
} }
public override void OnLevelWasLoaded(int level)
{
ExplorerCore.OnSceneChange();
}
public override void OnUpdate() public override void OnUpdate()
{ {
ExplorerCore.Update(); ExplorerCore.Update();
} }
public override void OnApplicationQuit() public override void OnLevelWasLoaded(int level)
{ {
DebugConsole.OnQuit(); ExplorerCore.Instance.OnSceneLoaded();
} }
//public override void OnGUI()
//{
// ExplorerCore.OnGUI();
//}
} }
} }
#endif #endif

View File

@ -35,15 +35,66 @@ namespace UnityExplorer.Helpers
public static Type BehaviourType => typeof(Behaviour); public static Type BehaviourType => typeof(Behaviour);
#endif #endif
public static Type GetTypeByName(string fullName)
{
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
{
foreach (var type in asm.TryGetTypes())
{
if (type.FullName == fullName)
{
return type;
}
}
}
return null;
}
public static Type[] GetAllBaseTypes(object obj) => GetAllBaseTypes(GetActualType(obj));
public static Type[] GetAllBaseTypes(Type type)
{
List<Type> list = new List<Type>();
while (type != null)
{
list.Add(type);
type = type.BaseType;
}
return list.ToArray();
}
public static Type GetActualType(object obj)
{
if (obj == null)
return null;
var type = obj.GetType();
#if CPP
if (obj is Il2CppSystem.Object ilObject)
{
if (obj is ILType)
return typeof(ILType);
// Il2CppSystem-namespace objects should just return GetType,
// because using GetIl2CppType returns the System namespace type instead.
if (type.Namespace.StartsWith("System.") || type.Namespace.StartsWith("Il2CppSystem."))
return ilObject.GetType();
var getType = Type.GetType(ilObject.GetIl2CppType().AssemblyQualifiedName);
if (getType != null)
return getType;
}
#endif
return type;
}
#if CPP #if CPP
private static readonly Dictionary<Type, IntPtr> ClassPointers = new Dictionary<Type, IntPtr>(); private static readonly Dictionary<Type, IntPtr> ClassPointers = new Dictionary<Type, IntPtr>();
[DllImport("GameAssembly", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern bool il2cpp_class_is_assignable_from(IntPtr klass, IntPtr oklass);
[DllImport("GameAssembly", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern IntPtr il2cpp_object_get_class(IntPtr obj);
public static object Il2CppCast(this object obj, Type castTo) public static object Il2CppCast(this object obj, Type castTo)
{ {
if (!(obj is Il2CppSystem.Object ilObj)) if (!(obj is Il2CppSystem.Object ilObj))
@ -51,30 +102,8 @@ namespace UnityExplorer.Helpers
return obj; return obj;
} }
if (!typeof(Il2CppSystem.Object).IsAssignableFrom(castTo)) if (!Il2CppTypeNotNull(castTo, out IntPtr castToPtr))
{
return obj; return obj;
}
IntPtr castToPtr;
if (!ClassPointers.ContainsKey(castTo))
{
castToPtr = (IntPtr)typeof(Il2CppClassPointerStore<>)
.MakeGenericType(new Type[] { castTo })
.GetField("NativeClassPtr", BF.Public | BF.Static)
.GetValue(null);
ClassPointers.Add(castTo, castToPtr);
}
else
{
castToPtr = ClassPointers[castTo];
}
if (castToPtr == IntPtr.Zero)
{
return obj;
}
IntPtr classPtr = il2cpp_object_get_class(ilObj.Pointer); IntPtr classPtr = il2cpp_object_get_class(ilObj.Pointer);
@ -86,6 +115,35 @@ namespace UnityExplorer.Helpers
return Activator.CreateInstance(castTo, ilObj.Pointer); return Activator.CreateInstance(castTo, ilObj.Pointer);
} }
public static bool Il2CppTypeNotNull(Type type)
{
return Il2CppTypeNotNull(type, out _);
}
public static bool Il2CppTypeNotNull(Type type, out IntPtr il2cppPtr)
{
if (!ClassPointers.ContainsKey(type))
{
il2cppPtr = (IntPtr)typeof(Il2CppClassPointerStore<>)
.MakeGenericType(new Type[] { type })
.GetField("NativeClassPtr", BF.Public | BF.Static)
.GetValue(null);
ClassPointers.Add(type, il2cppPtr);
}
else
il2cppPtr = ClassPointers[type];
return il2cppPtr != IntPtr.Zero;
}
[DllImport("GameAssembly", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern bool il2cpp_class_is_assignable_from(IntPtr klass, IntPtr oklass);
[DllImport("GameAssembly", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern IntPtr il2cpp_object_get_class(IntPtr obj);
#endif #endif
public static IEnumerable<Type> TryGetTypes(this Assembly asm) public static IEnumerable<Type> TryGetTypes(this Assembly asm)
@ -111,60 +169,6 @@ namespace UnityExplorer.Helpers
} }
} }
public static Type GetTypeByName(string fullName)
{
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
{
foreach (var type in asm.TryGetTypes())
{
if (type.FullName == fullName)
{
return type;
}
}
}
return null;
}
public static Type GetActualType(object obj)
{
if (obj == null)
return null;
#if CPP
// Need to use GetIl2CppType for Il2CppSystem Objects
if (obj is Il2CppSystem.Object ilObject)
{
// Prevent weird behaviour when inspecting an Il2CppSystem.Type object.
if (ilObject is ILType)
{
return typeof(ILType);
}
return Type.GetType(ilObject.GetIl2CppType().AssemblyQualifiedName) ?? obj.GetType();
}
#endif
// It's a normal object, this is fine
return obj.GetType();
}
public static Type[] GetAllBaseTypes(object obj) => GetAllBaseTypes(GetActualType(obj));
public static Type[] GetAllBaseTypes(Type type)
{
List<Type> list = new List<Type>();
while (type != null)
{
list.Add(type);
type = type.BaseType;
}
return list.ToArray();
}
public static bool LoadModule(string module) public static bool LoadModule(string module)
{ {
#if CPP #if CPP

View File

@ -77,7 +77,7 @@ namespace UnityExplorer.Inspectors.GameObjects
var text = s_compListTexts[i]; var text = s_compListTexts[i];
text.text = UISyntaxHighlight.GetHighlight(ReflectionHelpers.GetActualType(comp), true); text.text = UISyntaxHighlight.ParseFullSyntax(ReflectionHelpers.GetActualType(comp), true);
var toggle = s_compToggles[i]; var toggle = s_compToggles[i];
if (comp is Behaviour behaviour) if (comp is Behaviour behaviour)

View File

@ -8,7 +8,6 @@ namespace UnityExplorer.Inspectors
public abstract class InspectorBase public abstract class InspectorBase
{ {
public object Target; public object Target;
public UnityEngine.Object UnityTarget;
public abstract string TabLabel { get; } public abstract string TabLabel { get; }
@ -22,9 +21,8 @@ namespace UnityExplorer.Inspectors
public InspectorBase(object target) public InspectorBase(object target)
{ {
Target = target; Target = target;
UnityTarget = target as UnityEngine.Object;
if (ObjectNullOrDestroyed(Target, UnityTarget)) if (IsNullOrDestroyed(Target))
{ {
Destroy(); Destroy();
return; return;
@ -47,7 +45,7 @@ namespace UnityExplorer.Inspectors
public virtual void Update() public virtual void Update()
{ {
if (ObjectNullOrDestroyed(Target, UnityTarget)) if (IsNullOrDestroyed(Target))
{ {
Destroy(); Destroy();
return; return;
@ -86,14 +84,13 @@ namespace UnityExplorer.Inspectors
} }
} }
public static bool ObjectNullOrDestroyed(object obj, UnityEngine.Object unityObj, bool suppressWarning = false) public static bool IsNullOrDestroyed(object obj, bool suppressWarning = false)
{ {
var unityObj = obj as UnityEngine.Object;
if (obj == null) if (obj == null)
{ {
if (!suppressWarning) if (!suppressWarning)
{
ExplorerCore.LogWarning("The target instance is null!"); ExplorerCore.LogWarning("The target instance is null!");
}
return true; return true;
} }
@ -102,9 +99,7 @@ namespace UnityExplorer.Inspectors
if (!unityObj) if (!unityObj)
{ {
if (!suppressWarning) if (!suppressWarning)
{
ExplorerCore.LogWarning("The target UnityEngine.Object was destroyed!"); ExplorerCore.LogWarning("The target UnityEngine.Object was destroyed!");
}
return true; return true;
} }

View File

@ -45,13 +45,11 @@ namespace UnityExplorer.Inspectors
#endif #endif
UnityEngine.Object unityObj = obj as UnityEngine.Object; UnityEngine.Object unityObj = obj as UnityEngine.Object;
if (InspectorBase.ObjectNullOrDestroyed(obj, unityObj)) if (InspectorBase.IsNullOrDestroyed(obj))
{ {
return; return;
} }
MainMenu.Instance.SetPage(HomePage.Instance);
// check if currently inspecting this object // check if currently inspecting this object
foreach (InspectorBase tab in m_currentInspectors) foreach (InspectorBase tab in m_currentInspectors)
{ {
@ -84,7 +82,13 @@ namespace UnityExplorer.Inspectors
public void Inspect(Type type) public void Inspect(Type type)
{ {
foreach (var tab in m_currentInspectors) if (type == null)
{
ExplorerCore.LogWarning("The provided type was null!");
return;
}
foreach (var tab in m_currentInspectors.Where(x => x is StaticInspector))
{ {
if (ReferenceEquals(tab.Target as Type, type)) if (ReferenceEquals(tab.Target as Type, type))
{ {
@ -101,8 +105,12 @@ namespace UnityExplorer.Inspectors
public void SetInspectorTab(InspectorBase inspector) public void SetInspectorTab(InspectorBase inspector)
{ {
if (m_activeInspector == inspector)
return;
UnsetInspectorTab(); UnsetInspectorTab();
MainMenu.Instance.SetPage(HomePage.Instance);
m_activeInspector = inspector; m_activeInspector = inspector;
inspector.SetActive(); inspector.SetActive();

View File

@ -152,7 +152,7 @@ namespace UnityExplorer.Inspectors.Reflection
private string GetRichTextName() private string GetRichTextName()
{ {
return m_richTextName = UISyntaxHighlight.GetHighlight(MemInfo.DeclaringType, false, MemInfo); return m_richTextName = UISyntaxHighlight.ParseFullSyntax(MemInfo.DeclaringType, false, MemInfo);
} }
#if CPP #if CPP
@ -179,12 +179,7 @@ namespace UnityExplorer.Inspectors.Reflection
if (!typeof(Il2CppSystem.Object).IsAssignableFrom(type)) if (!typeof(Il2CppSystem.Object).IsAssignableFrom(type))
return true; return true;
var ptr = (IntPtr)typeof(Il2CppClassPointerStore<>) if (!ReflectionHelpers.Il2CppTypeNotNull(type, out IntPtr ptr))
.MakeGenericType(type)
.GetField("NativeClassPtr")
.GetValue(null);
if (ptr == IntPtr.Zero)
return false; return false;
return Il2CppSystem.Type.internal_from_handle(IL2CPP.il2cpp_class_get_type(ptr)) is Il2CppSystem.Type; return Il2CppSystem.Type.internal_from_handle(IL2CPP.il2cpp_class_get_type(ptr)) is Il2CppSystem.Type;
@ -207,7 +202,7 @@ namespace UnityExplorer.Inspectors.Reflection
var textGen = m_memLabelText.cachedTextGeneratorForLayout; var textGen = m_memLabelText.cachedTextGeneratorForLayout;
float preferredWidth = textGen.GetPreferredWidth(RichTextName, textGenSettings); float preferredWidth = textGen.GetPreferredWidth(RichTextName, textGenSettings);
float max = scrollRect.rect.width * 0.5f; float max = scrollRect.rect.width * 0.4f;
if (preferredWidth > max) preferredWidth = max; if (preferredWidth > max) preferredWidth = max;
@ -245,6 +240,10 @@ namespace UnityExplorer.Inspectors.Reflection
topGroup.childControlHeight = true; topGroup.childControlHeight = true;
topGroup.childControlWidth = true; topGroup.childControlWidth = true;
topGroup.spacing = 10; topGroup.spacing = 10;
topGroup.padding.left = 3;
topGroup.padding.right = 3;
topGroup.padding.top = 0;
topGroup.padding.bottom = 0;
// left group // left group
@ -295,6 +294,8 @@ namespace UnityExplorer.Inspectors.Reflection
rightGroup.childControlHeight = true; rightGroup.childControlHeight = true;
rightGroup.childControlWidth = true; rightGroup.childControlWidth = true;
rightGroup.spacing = 4; rightGroup.spacing = 4;
rightGroup.padding.top = 2;
rightGroup.padding.bottom = 2;
// evaluate button // evaluate button
if (this is CacheMethod || HasParameters) if (this is CacheMethod || HasParameters)

View File

@ -22,7 +22,7 @@ namespace UnityExplorer.Inspectors.Reflection
// might not need // might not need
public virtual bool HasSubContent => false; public virtual bool HasSubContent => false;
public string RichTextValue => m_richValue ?? GetRichTextValue(); public string RichTextValue => m_richValue ?? GetLabelForValue();
internal string m_richValue; internal string m_richValue;
internal string m_richValueType; internal string m_richValueType;
@ -45,39 +45,20 @@ namespace UnityExplorer.Inspectors.Reflection
return; return;
} }
GetRichTextValue(); GetLabelForValue();
m_text.text = RichTextValue; m_text.text = RichTextValue;
//if (Value == null) bool shouldShowInspect = !InspectorBase.IsNullOrDestroyed(this.Value, true);
// m_text.text = $"<color=red>null</color> {m_richValueType}"; if (m_inspectButton.activeSelf != shouldShowInspect)
//else m_inspectButton.SetActive(shouldShowInspect);
// m_text.text = RichTextValue;
} }
private MethodInfo GetToStringMethod() public string GetLabelForValue()
{
try
{
m_toStringMethod = ReflectionHelpers.GetActualType(Value).GetMethod("ToString", new Type[0])
?? typeof(object).GetMethod("ToString", new Type[0]);
// test invoke
m_toStringMethod.Invoke(Value, null);
}
catch
{
m_toStringMethod = typeof(object).GetMethod("ToString", new Type[0]);
}
return m_toStringMethod;
}
public string GetRichTextValue()
{ {
if (Value != null) if (Value != null)
ValueType = Value.GetType(); ValueType = Value.GetType();
m_richValueType = UISyntaxHighlight.GetHighlight(ValueType, true); m_richValueType = UISyntaxHighlight.ParseFullSyntax(ValueType, true);
if (OwnerCacheObject is CacheMember cm && !cm.HasEvaluated) if (OwnerCacheObject is CacheMember cm && !cm.HasEvaluated)
return $"<i><color=grey>Not yet evaluated</color> ({m_richValueType})</i>"; return $"<i><color=grey>Not yet evaluated</color> ({m_richValueType})</i>";
@ -103,7 +84,11 @@ namespace UnityExplorer.Inspectors.Reflection
{ {
var toString = (string)ToStringMethod.Invoke(Value, null); var toString = (string)ToStringMethod.Invoke(Value, null);
var temp = toString.Replace(ValueType.FullName, "").Trim(); var fullnametemp = ValueType.ToString();
if (fullnametemp.StartsWith("Il2CppSystem"))
fullnametemp = fullnametemp.Substring(6, fullnametemp.Length - 6);
var temp = toString.Replace(fullnametemp, "").Trim();
if (string.IsNullOrEmpty(temp)) if (string.IsNullOrEmpty(temp))
{ {
@ -127,20 +112,78 @@ namespace UnityExplorer.Inspectors.Reflection
return m_richValue = label; return m_richValue = label;
} }
#region UI CONSTRUCTION private MethodInfo GetToStringMethod()
{
try
{
m_toStringMethod = ReflectionHelpers.GetActualType(Value).GetMethod("ToString", new Type[0])
?? typeof(object).GetMethod("ToString", new Type[0]);
internal GameObject m_UIContent; // test invoke
m_toStringMethod.Invoke(Value, null);
}
catch
{
m_toStringMethod = typeof(object).GetMethod("ToString", new Type[0]);
}
return m_toStringMethod;
}
#region UI CONSTRUCTION
internal GameObject m_mainContent;
internal GameObject m_inspectButton;
internal Text m_text; internal Text m_text;
internal GameObject m_subContentParent; internal GameObject m_subContentParent;
public virtual void ConstructUI(GameObject parent, GameObject subGroup) public virtual void ConstructUI(GameObject parent, GameObject subGroup)
{ {
m_UIContent = UIFactory.CreateLabel(parent, TextAnchor.MiddleLeft); m_mainContent = UIFactory.CreateHorizontalGroup(parent, new Color(1, 1, 1, 0));
var mainLayout = m_UIContent.AddComponent<LayoutElement>(); var mainGroup = m_mainContent.GetComponent<HorizontalLayoutGroup>();
mainLayout.minWidth = 200;
mainLayout.flexibleWidth = 5000; mainGroup.childForceExpandWidth = true;
mainGroup.childControlWidth = true;
mainGroup.childForceExpandHeight = false;
mainGroup.childControlHeight = true;
mainGroup.spacing = 4;
mainGroup.childAlignment = TextAnchor.UpperLeft;
var mainLayout = m_mainContent.AddComponent<LayoutElement>();
mainLayout.flexibleWidth = 9000;
mainLayout.minWidth = 175;
mainLayout.minHeight = 25; mainLayout.minHeight = 25;
m_text = m_UIContent.GetComponent<Text>(); mainLayout.flexibleHeight = 0;
// inspect button
m_inspectButton = UIFactory.CreateButton(m_mainContent, new Color(0.3f, 0.3f, 0.3f, 0.2f));
var inspectLayout = m_inspectButton.AddComponent<LayoutElement>();
inspectLayout.minWidth = 60;
inspectLayout.minHeight = 25;
inspectLayout.flexibleHeight = 0;
inspectLayout.flexibleWidth = 0;
var inspectText = m_inspectButton.GetComponentInChildren<Text>();
inspectText.text = "Inspect";
var inspectBtn = m_inspectButton.GetComponent<Button>();
#if CPP
inspectBtn.onClick.AddListener(new Action(OnInspectClicked));
#else
inspectBtn.onClick.AddListener(OnInspectClicked);
#endif
void OnInspectClicked()
{
if (!InspectorBase.IsNullOrDestroyed(this.Value))
InspectorManager.Instance.Inspect(this.Value);
}
m_inspectButton.SetActive(false);
// value label / tostring
var labelObj = UIFactory.CreateLabel(m_mainContent, TextAnchor.MiddleLeft);
m_text = labelObj.GetComponent<Text>();
var labelLayout = labelObj.AddComponent<LayoutElement>();
labelLayout.flexibleWidth = 9000;
labelLayout.minHeight = 25;
m_subContentParent = subGroup; m_subContentParent = subGroup;
} }

View File

@ -40,11 +40,14 @@ namespace UnityExplorer.Inspectors
// Blacklists // Blacklists
private static readonly HashSet<string> s_typeAndMemberBlacklist = new HashSet<string> private static readonly HashSet<string> s_typeAndMemberBlacklist = new HashSet<string>
{ {
// these cause a crash #if CPP
// these cause a crash in IL2CPP
"Type.DeclaringMethod", "Type.DeclaringMethod",
"Rigidbody2D.Cast", "Rigidbody2D.Cast",
"Collider2D.Cast", "Collider2D.Cast",
"Collider2D.Raycast", "Collider2D.Raycast",
"Texture2D.SetPixelDataImpl",
#endif
}; };
private static readonly HashSet<string> s_methodStartsWithBlacklist = new HashSet<string> private static readonly HashSet<string> s_methodStartsWithBlacklist = new HashSet<string>
{ {
@ -53,9 +56,9 @@ namespace UnityExplorer.Inspectors
"set_", "set_",
}; };
#endregion #endregion
#region INSTANCE #region INSTANCE
public override string TabLabel => m_targetTypeShortName; public override string TabLabel => m_targetTypeShortName;
@ -253,6 +256,9 @@ namespace UnityExplorer.Inspectors
{ {
try try
{ {
//ExplorerCore.Log($"Trying to cache member {sig}...");
//ExplorerCore.Log(member.DeclaringType.FullName + "." + member.Name);
// make sure member type is Field, Method or Property (4 / 8 / 16) // make sure member type is Field, Method or Property (4 / 8 / 16)
int m = (int)member.MemberType; int m = (int)member.MemberType;
if (m < 4 || m > 16) if (m < 4 || m > 16)
@ -303,8 +309,6 @@ namespace UnityExplorer.Inspectors
try try
{ {
//ExplorerCore.Log($"Trying to cache member {sig}...");
var cached = CacheFactory.GetCacheObject(member, target, m_scrollContent); var cached = CacheFactory.GetCacheObject(member, target, m_scrollContent);
if (cached != null) if (cached != null)
@ -337,7 +341,7 @@ namespace UnityExplorer.Inspectors
// ExplorerCore.Log("Cached " + m_allMembers.Length + " members"); // ExplorerCore.Log("Cached " + m_allMembers.Length + " members");
} }
#region UI CONSTRUCTION #region UI CONSTRUCTION
internal void ConstructUI() internal void ConstructUI()
{ {
@ -391,13 +395,13 @@ namespace UnityExplorer.Inspectors
typeLabelLayout.minWidth = 150; typeLabelLayout.minWidth = 150;
typeLabelLayout.flexibleWidth = 5000; typeLabelLayout.flexibleWidth = 5000;
typeLabelInput.text = UISyntaxHighlight.GetHighlight(m_targetType, true); typeLabelInput.text = UISyntaxHighlight.ParseFullSyntax(m_targetType, true);
// Helper tools // Helper tools
if (this is InstanceInspector ii) if (this is InstanceInspector instanceInspector)
{ {
ii.ConstructInstanceHelpers(Content); instanceInspector.ConstructInstanceHelpers(Content);
} }
} }
@ -422,9 +426,9 @@ namespace UnityExplorer.Inspectors
// Instance filters // Instance filters
if (this is InstanceInspector ii) if (this is InstanceInspector instanceInspector)
{ {
ii.ConstructInstanceFilters(filterAreaObj); instanceInspector.ConstructInstanceFilters(filterAreaObj);
} }
} }
@ -436,14 +440,16 @@ namespace UnityExplorer.Inspectors
var scrollGroup = m_scrollContent.GetComponent<VerticalLayoutGroup>(); var scrollGroup = m_scrollContent.GetComponent<VerticalLayoutGroup>();
scrollGroup.spacing = 3; scrollGroup.spacing = 3;
scrollGroup.padding.left = 0;
scrollGroup.padding.right = 0;
m_pageHandler = new PageHandler(m_sliderScroller); m_pageHandler = new PageHandler(m_sliderScroller);
m_pageHandler.ConstructUI(Content); m_pageHandler.ConstructUI(Content);
m_pageHandler.OnPageChanged += OnPageTurned; m_pageHandler.OnPageChanged += OnPageTurned;
} }
#endregion #endregion
#endregion #endregion
} }
} }

View File

@ -62,7 +62,7 @@ namespace UnityExplorer.Inspectors
public void Init() public void Init()
{ {
RefreshActiveScenes(); RefreshSceneSelector();
} }
public void Update() public void Update()
@ -72,7 +72,7 @@ namespace UnityExplorer.Inspectors
return; return;
} }
RefreshActiveScenes(); RefreshSceneSelector();
if (!m_selectedSceneObject) if (!m_selectedSceneObject)
{ {
@ -104,10 +104,10 @@ namespace UnityExplorer.Inspectors
internal void OnSceneChange() internal void OnSceneChange()
{ {
m_sceneDropdown.OnCancel(null); m_sceneDropdown.OnCancel(null);
RefreshActiveScenes(); RefreshSceneSelector();
} }
private void RefreshActiveScenes() private void RefreshSceneSelector()
{ {
var names = new List<string>(); var names = new List<string>();
var handles = new List<int>(); var handles = new List<int>();
@ -132,16 +132,12 @@ namespace UnityExplorer.Inspectors
foreach (string scene in names) foreach (string scene in names)
{ {
m_sceneDropdown.options.Add(new Dropdown.OptionData m_sceneDropdown.options.Add(new Dropdown.OptionData { text = scene });
{
text = scene
});
} }
if (!handles.Contains(m_currentSceneHandle)) if (!names.Contains(m_sceneDropdown.itemText.text))
{ {
//m_sceneDropdown.transform.Find("Label").GetComponent<Text>().text = names[0]; m_sceneDropdown.transform.Find("Label").GetComponent<Text>().text = names[0];
m_sceneDropdown.itemText.text = names[0];
SetTargetScene(handles[0]); SetTargetScene(handles[0]);
} }
} }

View File

@ -98,39 +98,55 @@ namespace UnityExplorer.UI
public void SetPage(Page page) public void SetPage(Page page)
{ {
if (m_activePage == page || page == null) if (page == null || m_activePage == page)
{
return; return;
}
// WIP, was going to hide current page if you press current page's button,
// but the main panel does not resize so its just a big empty gap there.
// Could be good if I resize that gap, not bothering for now.
// Would need a fix in PanelDragger as well.
//if (m_activePage == page)
//{
// SetButtonInactiveColors(page.RefNavbarButton);
// m_activePage.Content.SetActive(false);
// m_activePage = null;
// return;
//}
m_activePage?.Content?.SetActive(false); m_activePage?.Content?.SetActive(false);
// unique case for console page, at the moment this will just go here
if (m_activePage is ConsolePage) if (m_activePage is ConsolePage)
{
AutoCompleter.m_mainObj?.SetActive(false); AutoCompleter.m_mainObj?.SetActive(false);
}
m_activePage = page; m_activePage = page;
m_activePage.Content?.SetActive(true); m_activePage.Content?.SetActive(true);
Button button = page.RefNavbarButton; Button button = page.RefNavbarButton;
SetButtonActiveColors(button);
ColorBlock colors = button.colors;
colors.normalColor = m_navButtonSelected;
//try { colors.selectedColor = m_navButtonSelected; } catch { }
button.colors = colors;
if (m_lastNavButtonPressed && m_lastNavButtonPressed != button) if (m_lastNavButtonPressed && m_lastNavButtonPressed != button)
{ SetButtonInactiveColors(m_lastNavButtonPressed);
ColorBlock oldColors = m_lastNavButtonPressed.colors;
oldColors.normalColor = m_navButtonNormal;
//try { oldColors.selectedColor = m_navButtonNormal; } catch { }
m_lastNavButtonPressed.colors = oldColors;
}
m_lastNavButtonPressed = button; m_lastNavButtonPressed = button;
} }
internal void SetButtonActiveColors(Button button)
{
ColorBlock colors = button.colors;
colors.normalColor = m_navButtonSelected;
button.colors = colors;
}
internal void SetButtonInactiveColors(Button button)
{
ColorBlock colors = button.colors;
colors.normalColor = m_navButtonNormal;
button.colors = colors;
}
#region UI Construction #region UI Construction
private void ConstructMenu() private void ConstructMenu()

View File

@ -18,12 +18,13 @@ namespace UnityExplorer.UI.Modules
public static bool LogUnity { get; set; } = ModConfig.Instance.Log_Unity_Debug; public static bool LogUnity { get; set; } = ModConfig.Instance.Log_Unity_Debug;
public static bool SaveToDisk { get; set; } = ModConfig.Instance.Save_Logs_To_Disk; public static bool SaveToDisk { get; set; } = ModConfig.Instance.Save_Logs_To_Disk;
internal static bool m_savedToDiskChecked; internal static StreamWriter s_streamWriter;
public static readonly List<string> AllMessages = new List<string>(); public static readonly List<string> AllMessages = new List<string>();
public static readonly List<Text> MessageHolders = new List<Text>(); public static readonly List<Text> MessageHolders = new List<Text>();
// logs that occured before the actual UI was ready. // logs that occured before the actual UI was ready.
// these ones include the hex color codes.
internal static readonly List<string> s_preInitMessages = new List<string>(); internal static readonly List<string> s_preInitMessages = new List<string>();
private InputField m_textInput; private InputField m_textInput;
@ -34,6 +35,7 @@ namespace UnityExplorer.UI.Modules
ConstructUI(parent); ConstructUI(parent);
// append messages that logged before we were set up
string preAppend = ""; string preAppend = "";
for (int i = s_preInitMessages.Count - 1; i >= 0; i--) for (int i = s_preInitMessages.Count - 1; i >= 0; i--)
{ {
@ -43,14 +45,8 @@ namespace UnityExplorer.UI.Modules
preAppend += msg; preAppend += msg;
} }
m_textInput.text = preAppend; m_textInput.text = preAppend;
}
public static void OnQuit() // set up IO
{
if (m_savedToDiskChecked)
return;
m_savedToDiskChecked = true;
if (!SaveToDisk) if (!SaveToDisk)
return; return;
@ -60,20 +56,28 @@ namespace UnityExplorer.UI.Modules
if (!Directory.Exists(path)) if (!Directory.Exists(path))
Directory.CreateDirectory(path); Directory.CreateDirectory(path);
// delete oldest log // clean old log(s)
var files = Directory.GetFiles(path); var files = Directory.GetFiles(path);
if (files.Length >= 10) if (files.Length >= 10)
{ {
var sorted = files.ToList(); var sorted = files.ToList();
// sort by datetime.ToString will put the oldest one first // sort by 'datetime.ToString("u")' will put the oldest ones first
sorted.Sort(); sorted.Sort();
File.Delete(sorted[0]); for (int i = 0; i < files.Length - 9; i++)
File.Delete(files[i]);
} }
var fileName = "UnityExplorer " + DateTime.Now.ToString("u") + ".txt"; var fileName = "UnityExplorer " + DateTime.Now.ToString("u") + ".txt";
fileName = ExplorerCore.RemoveInvalidFilenameChars(fileName); fileName = ExplorerCore.RemoveInvalidFilenameChars(fileName);
File.WriteAllText(path + @"\" + fileName, Instance.m_textInput.text); var stream = File.Create(path + @"\" + fileName);
s_streamWriter = new StreamWriter(stream)
{
AutoFlush = true
};
foreach (var msg in AllMessages)
s_streamWriter.WriteLine(msg);
} }
public static void Log(string message) public static void Log(string message)
@ -91,6 +95,7 @@ namespace UnityExplorer.UI.Modules
message = $"{AllMessages.Count}: {message}"; message = $"{AllMessages.Count}: {message}";
AllMessages.Add(message); AllMessages.Add(message);
s_streamWriter?.WriteLine(message);
if (hexColor != null) if (hexColor != null)
message = $"<color=#{hexColor}>{message}</color>"; message = $"<color=#{hexColor}>{message}</color>";
@ -139,7 +144,6 @@ namespace UnityExplorer.UI.Modules
inputScroll.inputField.readOnly = true; inputScroll.inputField.readOnly = true;
m_textInput = inputScroll.inputField; m_textInput = inputScroll.inputField;
#endregion #endregion
#region BOTTOM BAR #region BOTTOM BAR

View File

@ -20,8 +20,6 @@ namespace UnityExplorer.UI
public static event Action OnFinishResize; public static event Action OnFinishResize;
private static bool s_loadedCursorImage;
public PanelDragger(RectTransform dragArea, RectTransform panelToDrag) public PanelDragger(RectTransform dragArea, RectTransform panelToDrag)
{ {
Instance = this; Instance = this;
@ -39,7 +37,7 @@ namespace UnityExplorer.UI
Vector3 resizePos = Panel.InverseTransformPoint(rawMousePos); Vector3 resizePos = Panel.InverseTransformPoint(rawMousePos);
Vector3 dragPos = DragableArea.InverseTransformPoint(rawMousePos); Vector3 dragPos = DragableArea.InverseTransformPoint(rawMousePos);
if (WasHoveringResize && m_resizeCursorImage) if (WasHoveringResize && s_resizeCursorImage)
{ {
UpdateHoverImagePos(); UpdateHoverImagePos();
} }
@ -141,7 +139,7 @@ namespace UnityExplorer.UI
private bool WasHoveringResize { get; set; } private bool WasHoveringResize { get; set; }
private ResizeTypes m_lastResizeHoverType; private ResizeTypes m_lastResizeHoverType;
public GameObject m_resizeCursorImage; public static GameObject s_resizeCursorImage;
private Rect m_resizeRect; private Rect m_resizeRect;
@ -202,48 +200,33 @@ namespace UnityExplorer.UI
private ResizeTypes GetResizeType(Vector2 mousePos) private ResizeTypes GetResizeType(Vector2 mousePos)
{ {
// Calculate which part of the resize area we're in, if any. // Calculate which part of the resize area we're in, if any.
// We do this via a bitmask with the ResizeTypes enum.
// We can return Top/Right/Bottom/Left, or a corner like TopLeft.
int mask = 0; ResizeTypes mask = 0;
if (m_resizeMask[ResizeTypes.Top].Contains(mousePos)) if (m_resizeMask[ResizeTypes.Top].Contains(mousePos))
{ mask |= ResizeTypes.Top;
mask |= (int)ResizeTypes.Top;
}
else if (m_resizeMask[ResizeTypes.Bottom].Contains(mousePos)) else if (m_resizeMask[ResizeTypes.Bottom].Contains(mousePos))
{ mask |= ResizeTypes.Bottom;
mask |= (int)ResizeTypes.Bottom;
}
if (m_resizeMask[ResizeTypes.Left].Contains(mousePos)) if (m_resizeMask[ResizeTypes.Left].Contains(mousePos))
{ mask |= ResizeTypes.Left;
mask |= (int)ResizeTypes.Left;
}
else if (m_resizeMask[ResizeTypes.Right].Contains(mousePos)) else if (m_resizeMask[ResizeTypes.Right].Contains(mousePos))
{ mask |= ResizeTypes.Right;
mask |= (int)ResizeTypes.Right;
}
return (ResizeTypes)mask; return mask;
} }
public void OnHoverResize(ResizeTypes resizeType) public void OnHoverResize(ResizeTypes resizeType)
{ {
if (WasHoveringResize && m_lastResizeHoverType == resizeType) if (WasHoveringResize && m_lastResizeHoverType == resizeType)
{
return; return;
}
if (!s_loadedCursorImage)
LoadCursorImage();
// we are entering resize, or the resize type has changed. // we are entering resize, or the resize type has changed.
WasHoveringResize = true; WasHoveringResize = true;
m_lastResizeHoverType = resizeType; m_lastResizeHoverType = resizeType;
m_resizeCursorImage.SetActive(true); s_resizeCursorImage.SetActive(true);
// set the rotation for the resize icon // set the rotation for the resize icon
float iconRotation = 0f; float iconRotation = 0f;
@ -260,9 +243,9 @@ namespace UnityExplorer.UI
iconRotation = 135f; break; iconRotation = 135f; break;
} }
Quaternion rot = m_resizeCursorImage.transform.rotation; Quaternion rot = s_resizeCursorImage.transform.rotation;
rot.eulerAngles = new Vector3(0, 0, iconRotation); rot.eulerAngles = new Vector3(0, 0, iconRotation);
m_resizeCursorImage.transform.rotation = rot; s_resizeCursorImage.transform.rotation = rot;
UpdateHoverImagePos(); UpdateHoverImagePos();
} }
@ -271,13 +254,13 @@ namespace UnityExplorer.UI
private void UpdateHoverImagePos() private void UpdateHoverImagePos()
{ {
RectTransform t = UIManager.CanvasRoot.GetComponent<RectTransform>(); RectTransform t = UIManager.CanvasRoot.GetComponent<RectTransform>();
m_resizeCursorImage.transform.localPosition = t.InverseTransformPoint(InputManager.MousePosition); s_resizeCursorImage.transform.localPosition = t.InverseTransformPoint(InputManager.MousePosition);
} }
public void OnHoverResizeEnd() public void OnHoverResizeEnd()
{ {
WasHoveringResize = false; WasHoveringResize = false;
m_resizeCursorImage.SetActive(false); s_resizeCursorImage.SetActive(false);
} }
public void OnBeginResize(ResizeTypes resizeType) public void OnBeginResize(ResizeTypes resizeType)
@ -335,25 +318,23 @@ namespace UnityExplorer.UI
OnFinishResize?.Invoke(); OnFinishResize?.Invoke();
} }
private void LoadCursorImage() internal static void LoadCursorImage()
{ {
try try
{ {
var sprite = UIManager.ResizeCursor; var sprite = UIManager.ResizeCursor;
m_resizeCursorImage = new GameObject("ResizeCursorImage"); s_resizeCursorImage = new GameObject("ResizeCursorImage");
m_resizeCursorImage.transform.SetParent(UIManager.CanvasRoot.transform); s_resizeCursorImage.transform.SetParent(UIManager.CanvasRoot.transform);
Image image = m_resizeCursorImage.AddComponent<Image>(); Image image = s_resizeCursorImage.AddComponent<Image>();
image.sprite = sprite; image.sprite = sprite;
image.material = Graphic.defaultGraphicMaterial; image.material = Graphic.defaultGraphicMaterial;
RectTransform rect = image.transform.GetComponent<RectTransform>(); RectTransform rect = image.transform.GetComponent<RectTransform>();
rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, 32); rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, 32);
rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, 32); rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, 32);
//m_resizeCursorImage.SetActive(false); s_resizeCursorImage.SetActive(false);
s_loadedCursorImage = true;
} }
catch (Exception e) catch (Exception e)
{ {

View File

@ -41,7 +41,7 @@ namespace UnityExplorer.UI.Shared
get => m_currentPage; get => m_currentPage;
set set
{ {
if (value < LastPage) if (value < PageCount)
m_currentPage = value; m_currentPage = value;
} }
} }
@ -60,11 +60,11 @@ namespace UnityExplorer.UI.Shared
{ {
m_listCount = value; m_listCount = value;
if (LastPage <= 0 && m_pageUIHolder.activeSelf) if (PageCount <= 0 && m_pageUIHolder.activeSelf)
{ {
m_pageUIHolder.SetActive(false); m_pageUIHolder.SetActive(false);
} }
else if (LastPage > 0 && !m_pageUIHolder.activeSelf) else if (PageCount > 0 && !m_pageUIHolder.activeSelf)
{ {
m_pageUIHolder.SetActive(true); m_pageUIHolder.SetActive(true);
} }
@ -73,7 +73,7 @@ namespace UnityExplorer.UI.Shared
} }
} }
public int LastPage => (int)Math.Ceiling(ListCount / (decimal)ItemsPerPage) - 1; public int PageCount => (int)Math.Ceiling(ListCount / (decimal)ItemsPerPage) - 1;
// The index of the first element of the current page // The index of the first element of the current page
public int StartIndex public int StartIndex
@ -138,7 +138,7 @@ namespace UnityExplorer.UI.Shared
} }
else else
{ {
if (m_currentPage < LastPage) if (m_currentPage < PageCount)
{ {
m_currentPage++; m_currentPage++;
didTurn = true; didTurn = true;
@ -160,7 +160,7 @@ namespace UnityExplorer.UI.Shared
public void RefreshUI() public void RefreshUI()
{ {
m_currentPageLabel.text = $"Page {m_currentPage + 1} / {LastPage + 1}"; m_currentPageLabel.text = $"Page {m_currentPage + 1} / {PageCount + 1}";
} }
public void ConstructUI(GameObject parent) public void ConstructUI(GameObject parent)

View File

@ -22,7 +22,7 @@ namespace UnityExplorer.UI.Shared
public const string Local = "#a6e9e9"; public const string Local = "#a6e9e9";
public const string StructGreen = "#0e9931"; public const string StructGreen = "#0fba3a";
public static string Enum = "#92c470"; public static string Enum = "#92c470";
@ -33,7 +33,7 @@ namespace UnityExplorer.UI.Shared
string classColor; string classColor;
if (type.IsAbstract && type.IsSealed) if (type.IsAbstract && type.IsSealed)
classColor = Class_Static; classColor = Class_Static;
else if (type.IsEnum) else if (type.IsEnum || type.IsGenericParameter)
classColor = Enum; classColor = Enum;
else if (type.IsValueType) else if (type.IsValueType)
classColor = StructGreen; classColor = StructGreen;
@ -43,7 +43,7 @@ namespace UnityExplorer.UI.Shared
return classColor; return classColor;
} }
public static string GetHighlight(Type type, bool includeNamespace, MemberInfo memberInfo = null) public static string ParseFullSyntax(Type type, bool includeNamespace, MemberInfo memberInfo = null)
{ {
string ret = ""; string ret = "";
@ -55,91 +55,132 @@ namespace UnityExplorer.UI.Shared
} }
else else
{ {
string ns = includeNamespace if (includeNamespace && !string.IsNullOrEmpty(type.Namespace))
? $"<color=#{s_silver.ToHex()}>{type.Namespace}</color>." ret += $"<color=#{s_silver.ToHex()}>{type.Namespace}</color>.";
: "";
ret += ns;
var declaring = type.DeclaringType; var declaring = type.DeclaringType;
while (declaring != null) while (declaring != null)
{ {
ret += $"<color={GetClassColor(declaring)}>{declaring.Name}</color>."; ret += HighlightTypeName(declaring) + ".";
declaring = declaring.DeclaringType; declaring = declaring.DeclaringType;
} }
ret += $"<color={GetClassColor(type)}>{type.Name}</color>"; ret += HighlightTypeName(type);
} }
// todo MemberInfo
if (memberInfo != null) if (memberInfo != null)
{ {
ret += "."; ret += ".";
string memberColor = ""; string memberColor = GetMemberInfoColor(memberInfo, out bool isStatic);
bool isStatic = false; string memberHighlight = $"<color={memberColor}>{memberInfo.Name}</color>";
if (memberInfo is FieldInfo fi) if (isStatic)
{ memberHighlight = $"<i>{memberHighlight}</i>";
if (fi.IsStatic)
{
isStatic = true;
memberColor = Field_Static;
}
else
memberColor = Field_Instance;
}
else if (memberInfo is MethodInfo mi)
{
if (mi.IsStatic)
{
isStatic = true;
memberColor = Method_Static;
}
else
memberColor = Method_Instance;
}
else if (memberInfo is PropertyInfo pi)
{
if (pi.GetAccessors(true)[0].IsStatic)
{
isStatic = true;
memberColor = Prop_Static;
}
else
memberColor = Prop_Instance;
}
if (isStatic) ret += memberHighlight;
ret += "<i>";
ret += $"<color={memberColor}>{memberInfo.Name}</color>";
if (isStatic)
ret += "</i>";
// generic method args // generic method args
if (memberInfo is MethodInfo method) if (memberInfo is MethodInfo method)
{ {
var gArgs = method.GetGenericArguments(); var gArgs = method.GetGenericArguments();
if (gArgs.Length > 0) ret += ParseGenericArgs(gArgs, true);
{
ret += "<";
var args = "";
for (int i = 0; i < gArgs.Length; i++)
{
if (i > 0) args += ", ";
args += $"<color={Enum}>{gArgs[i].Name}</color>";
}
ret += args;
ret += ">";
}
} }
} }
return ret; return ret;
} }
private static string HighlightTypeName(Type type)
{
var typeName = type.Name;
var gArgs = type.GetGenericArguments();
if (gArgs.Length > 0)
{
// remove the `N from the end of the type name
// this could actually be >9 in some cases, so get the length of the length string and use that.
// eg, if it was "List`15", we would remove the ending 3 chars
int suffixLen = 1 + gArgs.Length.ToString().Length;
// make sure the typename actually has expected "`N" format.
if (typeName[typeName.Length - suffixLen] == '`')
typeName = typeName.Substring(0, typeName.Length - suffixLen);
}
// highlight the base name itself
// do this after removing the `N suffix, so only the name itself is in the color tags.
typeName = $"<color={GetClassColor(type)}>{typeName}</color>";
// parse the generic args, if any
if (gArgs.Length > 0)
typeName += ParseGenericArgs(gArgs);
return typeName;
}
private static string ParseGenericArgs(Type[] gArgs, bool allGeneric = false)
{
if (gArgs.Length < 1)
return "";
var args = "<";
for (int i = 0; i < gArgs.Length; i++)
{
if (i > 0)
args += ", ";
var arg = gArgs[i];
if (allGeneric)
{
args += $"<color={Enum}>{arg.Name}</color>";
continue;
}
// using HighlightTypeName makes it recursive, so we can parse nested generic args.
args += HighlightTypeName(arg);
}
return args + ">";
}
private static string GetMemberInfoColor(MemberInfo memberInfo, out bool isStatic)
{
string memberColor = "";
isStatic = false;
if (memberInfo is FieldInfo fi)
{
if (fi.IsStatic)
{
isStatic = true;
memberColor = Field_Static;
}
else
memberColor = Field_Instance;
}
else if (memberInfo is MethodInfo mi)
{
if (mi.IsStatic)
{
isStatic = true;
memberColor = Method_Static;
}
else
memberColor = Method_Instance;
}
else if (memberInfo is PropertyInfo pi)
{
if (pi.GetAccessors(true)[0].IsStatic)
{
isStatic = true;
memberColor = Prop_Static;
}
else
memberColor = Prop_Instance;
}
return memberColor;
}
} }
} }

View File

@ -56,11 +56,10 @@ namespace UnityExplorer.UI
// Create submodules // Create submodules
new MainMenu(); new MainMenu();
MouseInspector.ConstructUI(); MouseInspector.ConstructUI();
PanelDragger.LoadCursorImage();
// Force refresh of anchors // Force refresh of anchors
Canvas.ForceUpdateCanvases(); Canvas.ForceUpdateCanvases();
//CanvasRoot.SetActive(false);
//CanvasRoot.SetActive(true);
} }
public static void SetEventSystem() public static void SetEventSystem()

View File

@ -350,7 +350,7 @@
<Compile Include="Input\NoInput.cs" /> <Compile Include="Input\NoInput.cs" />
<Compile Include="UI\Modules\DebugConsole.cs" /> <Compile Include="UI\Modules\DebugConsole.cs" />
<Compile Include="Inspectors\InspectorManager.cs" /> <Compile Include="Inspectors\InspectorManager.cs" />
<Compile Include="Inspectors\ReflectionInspector.cs" /> <Compile Include="Inspectors\Reflection\ReflectionInspector.cs" />
<Compile Include="UI\MainMenu.cs" /> <Compile Include="UI\MainMenu.cs" />
<Compile Include="UI\Modules\ConsolePage.cs" /> <Compile Include="UI\Modules\ConsolePage.cs" />
<Compile Include="Console\AutoCompleter.cs" /> <Compile Include="Console\AutoCompleter.cs" />
@ -366,7 +366,7 @@
<Compile Include="Console\ScriptEvaluator.cs" /> <Compile Include="Console\ScriptEvaluator.cs" />
<Compile Include="Console\ScriptInteraction.cs" /> <Compile Include="Console\ScriptInteraction.cs" />
<Compile Include="UI\Modules\HomePage.cs" /> <Compile Include="UI\Modules\HomePage.cs" />
<Compile Include="Inspectors\GameObjectInspector.cs" /> <Compile Include="Inspectors\GameObjects\GameObjectInspector.cs" />
<Compile Include="Inspectors\InspectorBase.cs" /> <Compile Include="Inspectors\InspectorBase.cs" />
<Compile Include="Inspectors\Reflection\InstanceInspector.cs" /> <Compile Include="Inspectors\Reflection\InstanceInspector.cs" />
<Compile Include="Inspectors\Reflection\StaticInspector.cs" /> <Compile Include="Inspectors\Reflection\StaticInspector.cs" />