Compare commits

...

3 Commits
3.2.1 ... 3.2.2

9 changed files with 316 additions and 157 deletions

View File

@ -3,6 +3,7 @@ using System.IO;
using UnityEngine; using UnityEngine;
using IniParser; using IniParser;
using IniParser.Parser; using IniParser.Parser;
using UnityExplorer.UI;
namespace UnityExplorer.Config namespace UnityExplorer.Config
{ {
@ -16,16 +17,20 @@ namespace UnityExplorer.Config
static ExplorerConfig() static ExplorerConfig()
{ {
_parser.Configuration.CommentString = "#"; _parser.Configuration.CommentString = "#";
PanelDragger.OnFinishResize += PanelDragger_OnFinishResize;
} }
// Actual configs // Actual configs
public KeyCode Main_Menu_Toggle = KeyCode.F7; public KeyCode Main_Menu_Toggle = KeyCode.F7;
public bool Force_Unlock_Mouse = true; public bool Force_Unlock_Mouse = true;
public int Default_Page_Limit = 25; public int Default_Page_Limit = 25;
public string Default_Output_Path = ExplorerCore.ExplorerFolder + @"\Output"; public string Default_Output_Path = Path.Combine(ExplorerCore.ExplorerFolder, "Output");
public bool Log_Unity_Debug = false; public bool Log_Unity_Debug = false;
public bool Hide_On_Startup = false; public bool Hide_On_Startup = false;
//public bool Save_Logs_To_Disk = true; public string Window_Anchors = DEFAULT_WINDOW_ANCHORS;
private const string DEFAULT_WINDOW_ANCHORS = "0.25,0.1,0.78,0.95";
public static event Action OnConfigChanged; public static event Action OnConfigChanged;
@ -75,9 +80,9 @@ namespace UnityExplorer.Config
case nameof(Hide_On_Startup): case nameof(Hide_On_Startup):
Instance.Hide_On_Startup = bool.Parse(config.Value); Instance.Hide_On_Startup = bool.Parse(config.Value);
break; break;
//case nameof(Save_Logs_To_Disk): case nameof(Window_Anchors):
// Instance.Save_Logs_To_Disk = bool.Parse(config.Value); Instance.Window_Anchors = config.Value;
// break; break;
} }
} }
@ -97,12 +102,52 @@ namespace UnityExplorer.Config
sec.AddKey(nameof(Log_Unity_Debug), Instance.Log_Unity_Debug.ToString()); sec.AddKey(nameof(Log_Unity_Debug), Instance.Log_Unity_Debug.ToString());
sec.AddKey(nameof(Default_Output_Path), Instance.Default_Output_Path); sec.AddKey(nameof(Default_Output_Path), Instance.Default_Output_Path);
sec.AddKey(nameof(Hide_On_Startup), Instance.Hide_On_Startup.ToString()); sec.AddKey(nameof(Hide_On_Startup), Instance.Hide_On_Startup.ToString());
//sec.AddKey("Save_Logs_To_Disk", Instance.Save_Logs_To_Disk.ToString()); sec.AddKey(nameof(Window_Anchors), GetWindowAnchorsString());
if (!Directory.Exists(ExplorerCore.Loader.ConfigFolder)) if (!Directory.Exists(ExplorerCore.Loader.ConfigFolder))
Directory.CreateDirectory(ExplorerCore.Loader.ConfigFolder); Directory.CreateDirectory(ExplorerCore.Loader.ConfigFolder);
File.WriteAllText(INI_PATH, data.ToString()); File.WriteAllText(INI_PATH, data.ToString());
} }
// ============ Window Anchors specific stuff ============== //
private static void PanelDragger_OnFinishResize()
{
Instance.Window_Anchors = GetWindowAnchorsString();
SaveSettings();
}
internal Vector4 GetWindowAnchorsVector()
{
try
{
var split = Window_Anchors.Split(',');
Vector4 ret = Vector4.zero;
ret.x = float.Parse(split[0]);
ret.y = float.Parse(split[1]);
ret.z = float.Parse(split[2]);
ret.w = float.Parse(split[3]);
return ret;
}
catch
{
Window_Anchors = DEFAULT_WINDOW_ANCHORS;
return GetWindowAnchorsVector();
}
}
internal static string GetWindowAnchorsString()
{
try
{
var rect = PanelDragger.Instance.Panel;
return $"{rect.anchorMin.x},{rect.anchorMin.y},{rect.anchorMax.x},{rect.anchorMax.y}";
}
catch
{
return DEFAULT_WINDOW_ANCHORS;
}
}
} }
} }

View File

@ -15,7 +15,7 @@ namespace UnityExplorer
public class ExplorerCore public class ExplorerCore
{ {
public const string NAME = "UnityExplorer"; public const string NAME = "UnityExplorer";
public const string VERSION = "3.2.1"; public const string VERSION = "3.2.2";
public const string AUTHOR = "Sinai"; public const string AUTHOR = "Sinai";
public const string GUID = "com.sinai.unityexplorer"; public const string GUID = "com.sinai.unityexplorer";

View File

@ -11,20 +11,27 @@ namespace UnityExplorer.Helpers
{ {
private static readonly Dictionary<string, Delegate> iCallCache = new Dictionary<string, Delegate>(); private static readonly Dictionary<string, Delegate> iCallCache = new Dictionary<string, Delegate>();
public static T GetICall<T>(string iCallName) where T : Delegate /// <summary>
/// Helper to get and cache an iCall by providing the signature (eg. "UnityEngine.Resources::FindObjectsOfTypeAll").
/// </summary>
/// <typeparam name="T">The Type of Delegate to provide for the iCall.</typeparam>
/// <param name="signature">The signature of the iCall you want to get.</param>
/// <returns>The <typeparamref name="T"/> delegate if successful.</returns>
/// <exception cref="MissingMethodException">If the iCall could not be found.</exception>
public static T GetICall<T>(string signature) where T : Delegate
{ {
if (iCallCache.ContainsKey(iCallName)) if (iCallCache.ContainsKey(signature))
return (T)iCallCache[iCallName]; return (T)iCallCache[signature];
IntPtr ptr = il2cpp_resolve_icall(iCallName); IntPtr ptr = il2cpp_resolve_icall(signature);
if (ptr == IntPtr.Zero) if (ptr == IntPtr.Zero)
{ {
throw new MissingMethodException($"Could not resolve internal call by name '{iCallName}'!"); throw new MissingMethodException($"Could not resolve internal call by name '{signature}'!");
} }
Delegate iCall = Marshal.GetDelegateForFunctionPointer(ptr, typeof(T)); Delegate iCall = Marshal.GetDelegateForFunctionPointer(ptr, typeof(T));
iCallCache.Add(iCallName, iCall); iCallCache.Add(signature, iCall);
return (T)iCall; return (T)iCall;
} }

View File

@ -21,26 +21,61 @@ namespace UnityExplorer.Helpers
{ {
public static BF CommonFlags = BF.Public | BF.Instance | BF.NonPublic | BF.Static; public static BF CommonFlags = BF.Public | BF.Instance | BF.NonPublic | BF.Static;
// cache for GetTypeByName
internal static readonly Dictionary<string, Type> s_typesByName = new Dictionary<string, Type>();
/// <summary>
/// Find a <see cref="Type"/> in the current AppDomain whose <see cref="Type.FullName"/> matches the provided <paramref name="fullName"/>.
/// </summary>
/// <param name="fullName">The <see cref="Type.FullName"/> you want to search for - case sensitive and full matches only.</param>
/// <returns>The Type if found, otherwise null.</returns>
public static Type GetTypeByName(string fullName) public static Type GetTypeByName(string fullName)
{ {
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) s_typesByName.TryGetValue(fullName, out Type ret);
{
foreach (var type in asm.TryGetTypes()) if (ret != null)
return ret;
foreach (var type in from asm in AppDomain.CurrentDomain.GetAssemblies()
from type in asm.TryGetTypes()
select type)
{ {
if (type.FullName == fullName) if (type.FullName == fullName)
{ {
return type; ret = type;
} break;
} }
} }
return null; if (s_typesByName.ContainsKey(fullName))
s_typesByName[fullName] = ret;
else
s_typesByName.Add(fullName, ret);
return ret;
} }
// cache for GetBaseTypes
internal static readonly Dictionary<string, Type[]> s_cachedTypeInheritance = new Dictionary<string, Type[]>();
/// <summary>
/// Get all base types of the provided Type, including itself.
/// </summary>
public static Type[] GetAllBaseTypes(object obj) => GetAllBaseTypes(GetActualType(obj)); public static Type[] GetAllBaseTypes(object obj) => GetAllBaseTypes(GetActualType(obj));
/// <summary>
/// Get all base types of the provided Type, including itself.
/// </summary>
public static Type[] GetAllBaseTypes(Type type) public static Type[] GetAllBaseTypes(Type type)
{ {
if (type == null)
throw new ArgumentNullException("type");
var name = type.AssemblyQualifiedName;
if (s_cachedTypeInheritance.TryGetValue(name, out Type[] ret))
return ret;
List<Type> list = new List<Type>(); List<Type> list = new List<Type>();
while (type != null) while (type != null)
@ -49,9 +84,18 @@ namespace UnityExplorer.Helpers
type = type.BaseType; type = type.BaseType;
} }
return list.ToArray(); ret = list.ToArray();
s_cachedTypeInheritance.Add(name, ret);
return ret;
} }
/// <summary>
/// Helper for IL2CPP to get the underlying true Type (Unhollowed) of the object.
/// </summary>
/// <param name="obj">The object to get the true Type for.</param>
/// <returns>The most accurate Type of the object which could be identified.</returns>
public static Type GetActualType(this object obj) public static Type GetActualType(this object obj)
{ {
if (obj == null) if (obj == null)
@ -59,9 +103,9 @@ namespace UnityExplorer.Helpers
var type = obj.GetType(); var type = obj.GetType();
#if CPP #if CPP
if (obj is Il2CppSystem.Object ilObject) if (obj is Il2CppSystem.Object cppObject)
{ {
if (ilObject is CppType) if (cppObject is CppType)
return typeof(CppType); return typeof(CppType);
if (!string.IsNullOrEmpty(type.Namespace)) if (!string.IsNullOrEmpty(type.Namespace))
@ -69,22 +113,22 @@ namespace UnityExplorer.Helpers
// Il2CppSystem-namespace objects should just return GetType, // Il2CppSystem-namespace objects should just return GetType,
// because using GetIl2CppType returns the System namespace type instead. // because using GetIl2CppType returns the System namespace type instead.
if (type.Namespace.StartsWith("System.") || type.Namespace.StartsWith("Il2CppSystem.")) if (type.Namespace.StartsWith("System.") || type.Namespace.StartsWith("Il2CppSystem."))
return ilObject.GetType(); return cppObject.GetType();
} }
var il2cppType = ilObject.GetIl2CppType(); var cppType = cppObject.GetIl2CppType();
// check if type is injected // check if type is injected
IntPtr classPtr = il2cpp_object_get_class(ilObject.Pointer); IntPtr classPtr = il2cpp_object_get_class(cppObject.Pointer);
if (RuntimeSpecificsStore.IsInjected(classPtr)) if (RuntimeSpecificsStore.IsInjected(classPtr))
{ {
var typeByName = GetTypeByName(il2cppType.FullName); var typeByName = GetTypeByName(cppType.FullName);
if (typeByName != null) if (typeByName != null)
return typeByName; return typeByName;
} }
// this should be fine for all other il2cpp objects // this should be fine for all other il2cpp objects
var getType = GetMonoType(il2cppType); var getType = GetMonoType(cppType);
if (getType != null) if (getType != null)
return getType; return getType;
} }
@ -93,41 +137,55 @@ namespace UnityExplorer.Helpers
} }
#if CPP #if CPP
// caching for GetMonoType
private static readonly Dictionary<string, Type> Il2CppToMonoType = new Dictionary<string, Type>(); private static readonly Dictionary<string, Type> Il2CppToMonoType = new Dictionary<string, Type>();
// keep unobfuscated type name cache, used to display proper name.
internal static Dictionary<string, string> UnobfuscatedTypeNames = new Dictionary<string, string>();
/// <summary>
/// Try to get the Mono (Unhollowed) Type representation of the provided <see cref="Il2CppSystem.Type"/>.
/// </summary>
/// <param name="cppType">The Cpp Type you want to convert to Mono.</param>
/// <returns>The Mono Type if found, otherwise null.</returns>
public static Type GetMonoType(CppType cppType) public static Type GetMonoType(CppType cppType)
{ {
if (Il2CppToMonoType.ContainsKey(cppType.AssemblyQualifiedName)) string name = cppType.AssemblyQualifiedName;
return Il2CppToMonoType[cppType.AssemblyQualifiedName];
var getType = Type.GetType(cppType.AssemblyQualifiedName); if (Il2CppToMonoType.ContainsKey(name))
return Il2CppToMonoType[name];
if (getType != null) Type ret = Type.GetType(name);
{
Il2CppToMonoType.Add(cppType.AssemblyQualifiedName, getType); if (ret == null)
return getType;
}
else
{ {
string baseName = cppType.FullName; string baseName = cppType.FullName;
string baseAssembly = cppType.Assembly.GetName().name; string baseAssembly = cppType.Assembly.GetName().name;
Type unhollowedType = AppDomain.CurrentDomain ret = AppDomain.CurrentDomain
.GetAssemblies() .GetAssemblies()
.FirstOrDefault(a => a.GetName().Name == baseAssembly)? .FirstOrDefault(a
=> a.GetName().Name == baseAssembly)?
.TryGetTypes() .TryGetTypes()
.FirstOrDefault(t => .FirstOrDefault(t
t.CustomAttributes.Any(ca => t.CustomAttributes.Any(ca
=> ca.AttributeType.Name == "ObfuscatedNameAttribute" => ca.AttributeType.Name == "ObfuscatedNameAttribute"
&& (string)ca.ConstructorArguments[0].Value == baseName)); && (string)ca.ConstructorArguments[0].Value == baseName));
Il2CppToMonoType.Add(cppType.AssemblyQualifiedName, unhollowedType); if (ret != null)
{
return unhollowedType; // unobfuscated type was found, add to cache.
UnobfuscatedTypeNames.Add(cppType.FullName, ret.FullName);
} }
} }
private static readonly Dictionary<Type, IntPtr> CppClassPointers = new Dictionary<Type, IntPtr>(); Il2CppToMonoType.Add(name, ret);
return ret;
}
// cached class pointers for Il2CppCast
private static readonly Dictionary<string, IntPtr> CppClassPointers = new Dictionary<string, IntPtr>();
/// <summary> /// <summary>
/// Attempt to cast the object to its underlying type. /// Attempt to cast the object to its underlying type.
@ -161,7 +219,43 @@ namespace UnityExplorer.Helpers
return Activator.CreateInstance(castTo, ilObj.Pointer); return Activator.CreateInstance(castTo, ilObj.Pointer);
} }
internal static readonly Dictionary<Type, MethodInfo> s_unboxMethods = new Dictionary<Type, MethodInfo>(); /// <summary>
/// Get the Il2Cpp Class Pointer for the provided Mono (Unhollowed) Type.
/// </summary>
/// <param name="type">The Mono/Unhollowed Type you want the Il2Cpp Class Pointer for.</param>
/// <returns>True if successful, false if not.</returns>
public static bool Il2CppTypeNotNull(Type type) => Il2CppTypeNotNull(type, out _);
/// <summary>
/// Get the Il2Cpp Class Pointer for the provided Mono (Unhollowed) Type.
/// </summary>
/// <param name="type">The Mono/Unhollowed Type you want the Il2Cpp Class Pointer for.</param>
/// <param name="il2cppPtr">The IntPtr for the Il2Cpp class, or IntPtr.Zero if not found.</param>
/// <returns>True if successful, false if not.</returns>
public static bool Il2CppTypeNotNull(Type type, out IntPtr il2cppPtr)
{
if (CppClassPointers.TryGetValue(type.AssemblyQualifiedName, out il2cppPtr))
return il2cppPtr != IntPtr.Zero;
il2cppPtr = (IntPtr)typeof(Il2CppClassPointerStore<>)
.MakeGenericType(new Type[] { type })
.GetField("NativeClassPtr", BF.Public | BF.Static)
.GetValue(null);
CppClassPointers.Add(type.AssemblyQualifiedName, il2cppPtr);
return il2cppPtr != IntPtr.Zero;
}
// Extern C++ methods
[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);
// cached il2cpp unbox methods
internal static readonly Dictionary<string, MethodInfo> s_unboxMethods = new Dictionary<string, MethodInfo>();
/// <summary> /// <summary>
/// Attempt to unbox the object to the underlying struct type. /// Attempt to unbox the object to the underlying struct type.
@ -184,41 +278,18 @@ namespace UnityExplorer.Helpers
if (!(obj is Il2CppSystem.Object)) if (!(obj is Il2CppSystem.Object))
return obj; return obj;
if (!s_unboxMethods.ContainsKey(type)) var name = type.AssemblyQualifiedName;
if (!s_unboxMethods.ContainsKey(name))
{ {
s_unboxMethods.Add(type, typeof(Il2CppObjectBase) s_unboxMethods.Add(name, typeof(Il2CppObjectBase)
.GetMethod("Unbox") .GetMethod("Unbox")
.MakeGenericMethod(type)); .MakeGenericMethod(type));
} }
return s_unboxMethods[type].Invoke(obj, new object[0]); return s_unboxMethods[name].Invoke(obj, new object[0]);
} }
public static bool Il2CppTypeNotNull(Type type) => Il2CppTypeNotNull(type, out _);
public static bool Il2CppTypeNotNull(Type type, out IntPtr il2cppPtr)
{
if (!CppClassPointers.ContainsKey(type))
{
il2cppPtr = (IntPtr)typeof(Il2CppClassPointerStore<>)
.MakeGenericType(new Type[] { type })
.GetField("NativeClassPtr", BF.Public | BF.Static)
.GetValue(null);
CppClassPointers.Add(type, il2cppPtr);
}
else
il2cppPtr = CppClassPointers[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)
@ -244,49 +315,17 @@ namespace UnityExplorer.Helpers
} }
} }
#if CPP // Helper for IL2CPP to check if a Type is assignable to IEnumerable
internal static void TryLoadGameModules()
{
LoadModule("Assembly-CSharp");
LoadModule("Assembly-CSharp-firstpass");
}
public static bool LoadModule(string module)
{
#if ML
var path = $@"MelonLoader\Managed\{module}.dll";
#else
var path = $@"BepInEx\unhollowed\{module}.dll";
#endif
return LoadModuleInternal(path);
}
internal static bool LoadModuleInternal(string fullPath)
{
if (!File.Exists(fullPath))
return false;
try
{
Assembly.Load(File.ReadAllBytes(fullPath));
return true;
}
catch (Exception e)
{
Console.WriteLine(e.GetType() + ", " + e.Message);
}
return false;
}
#else
public static bool LoadModule(string module) => true;
#endif
#if CPP #if CPP
internal static IntPtr s_cppEnumerableClassPtr; internal static IntPtr s_cppEnumerableClassPtr;
#endif #endif
/// <summary>
/// Check if the provided Type is assignable to IEnumerable.
/// </summary>
/// <param name="t">The Type to check</param>
/// <returns>True if the Type is assignable to IEnumerable, otherwise false.</returns>
public static bool IsEnumerable(Type t) public static bool IsEnumerable(Type t)
{ {
if (typeof(IEnumerable).IsAssignableFrom(t)) if (typeof(IEnumerable).IsAssignableFrom(t))
@ -309,10 +348,17 @@ namespace UnityExplorer.Helpers
return false; return false;
} }
// Helper for IL2CPP to check if a Type is assignable to IDictionary
#if CPP #if CPP
internal static IntPtr s_cppDictionaryClassPtr; internal static IntPtr s_cppDictionaryClassPtr;
#endif #endif
/// <summary>
/// Check if the provided Type is assignable to IDictionary.
/// </summary>
/// <param name="t">The Type to check</param>
/// <returns>True if the Type is assignable to IDictionary, otherwise false.</returns>
public static bool IsDictionary(Type t) public static bool IsDictionary(Type t)
{ {
if (typeof(IDictionary).IsAssignableFrom(t)) if (typeof(IDictionary).IsAssignableFrom(t))
@ -335,18 +381,68 @@ namespace UnityExplorer.Helpers
return false; return false;
} }
// Helper for IL2CPP to try to make sure the Unhollowed game assemblies are actually loaded.
#if CPP
internal static void TryLoadGameModules()
{
LoadModule("Assembly-CSharp");
LoadModule("Assembly-CSharp-firstpass");
}
public static bool LoadModule(string module)
{
#if ML
var path = Path.Combine("MelonLoader", "Managed", $"{module}.dll");
#else
var path = Path.Combine("BepInEx", "unhollowed", $"{module}.dll");
#endif
return LoadModuleInternal(path);
}
internal static bool LoadModuleInternal(string fullPath)
{
if (!File.Exists(fullPath))
return false;
try
{
Assembly.Load(File.ReadAllBytes(fullPath));
return true;
}
catch (Exception e)
{
Console.WriteLine(e.GetType() + ", " + e.Message);
}
return false;
}
#else
// For Mono, just return true and do nothing, Mono will sort it out itself.
public static bool LoadModule(string module) => true;
#endif
/// <summary>
/// Helper to display a simple "{ExceptionType}: {Message}" of the exception, and optionally use the inner-most exception.
/// </summary>
/// <param name="e">The Exception to convert to string.</param>
/// <param name="innerMost">Should the inner-most Exception of the stack be used? If false, the Exception you provided will be used directly.</param>
/// <returns>The exception to string.</returns>
public static string ExceptionToString(Exception e, bool innerMost = false) public static string ExceptionToString(Exception e, bool innerMost = false)
{ {
while (innerMost && e.InnerException != null) if (innerMost)
{
while (e.InnerException != null)
{ {
#if CPP #if CPP
if (e.InnerException is System.Runtime.CompilerServices.RuntimeWrappedException runtimeEx) if (e.InnerException is System.Runtime.CompilerServices.RuntimeWrappedException)
break; break;
#endif #endif
e = e.InnerException; e = e.InnerException;
} }
}
return e.GetType() + ", " + e.Message; return $"{e.GetType()}: {e.Message}";
} }
} }
} }

View File

@ -381,7 +381,7 @@ namespace UnityExplorer.Inspectors.Reflection
argLabelLayout.minHeight = 25; argLabelLayout.minHeight = 25;
var argText = argLabelObj.GetComponent<Text>(); var argText = argLabelObj.GetComponent<Text>();
var argTypeTxt = UISyntaxHighlight.ParseFullSyntax(arg.ParameterType, false); var argTypeTxt = UISyntaxHighlight.ParseFullSyntax(arg.ParameterType, false);
argText.text = $"{argTypeTxt} <color={UISyntaxHighlight.Local}>{arg.Name}</color>"; argText.text = $"{argTypeTxt} <color={UISyntaxHighlight.LOCAL_ARG}>{arg.Name}</color>";
var argInputObj = UIFactory.CreateInputField(rowObj, 14, (int)TextAnchor.MiddleLeft, 1); var argInputObj = UIFactory.CreateInputField(rowObj, 14, (int)TextAnchor.MiddleLeft, 1);
var argInputLayout = argInputObj.AddComponent<LayoutElement>(); var argInputLayout = argInputObj.AddComponent<LayoutElement>();

View File

@ -168,7 +168,7 @@ namespace UnityExplorer.Inspectors.Reflection
//var argLayout = argLabelObj.AddComponent<LayoutElement>(); //var argLayout = argLabelObj.AddComponent<LayoutElement>();
//argLayout.minWidth = 20; //argLayout.minWidth = 20;
var argText = argLabelObj.GetComponent<Text>(); var argText = argLabelObj.GetComponent<Text>();
argText.text = $"{constrainTxt} <color={UISyntaxHighlight.Enum}>{arg.Name}</color>"; argText.text = $"{constrainTxt} <color={UISyntaxHighlight.CONST_VAR}>{arg.Name}</color>";
var argInputObj = UIFactory.CreateInputField(rowObj, 14, (int)TextAnchor.MiddleLeft, 1); var argInputObj = UIFactory.CreateInputField(rowObj, 14, (int)TextAnchor.MiddleLeft, 1);
var argInputLayout = argInputObj.AddComponent<LayoutElement>(); var argInputLayout = argInputObj.AddComponent<LayoutElement>();

View File

@ -194,6 +194,7 @@ namespace UnityExplorer.Inspectors.Reflection
string label; string label;
// Two dirty fixes for TextAsset and EventSystem, which can have very long ToString results.
if (Value is TextAsset textAsset) if (Value is TextAsset textAsset)
{ {
label = textAsset.text; label = textAsset.text;
@ -207,7 +208,7 @@ namespace UnityExplorer.Inspectors.Reflection
{ {
label = m_richValueType; label = m_richValueType;
} }
else else // For everything else...
{ {
if (!m_gotToStringMethods) if (!m_gotToStringMethods)
{ {
@ -233,17 +234,24 @@ namespace UnityExplorer.Inspectors.Reflection
else else
toString = (string)m_toStringMethod.Invoke(Value, new object[0]); toString = (string)m_toStringMethod.Invoke(Value, new object[0]);
var fullnametemp = valueType.ToString(); string typeName = valueType.FullName;
if (fullnametemp.StartsWith("Il2CppSystem")) if (typeName.StartsWith("Il2CppSystem."))
fullnametemp = fullnametemp.Substring(6, fullnametemp.Length - 6); typeName = typeName.Substring(6, typeName.Length - 6);
#if CPP
var cppType = UnhollowerRuntimeLib.Il2CppType.From(valueType);
if (cppType != null && ReflectionHelpers.UnobfuscatedTypeNames.ContainsKey(cppType.FullName))
{
typeName = ReflectionHelpers.UnobfuscatedTypeNames[cppType.FullName];
toString = toString.Replace(cppType.FullName, typeName);
}
#endif
var temp = toString.Replace(fullnametemp, "").Trim(); // If the ToString is just the type name, use our syntax highlighted type name instead.
if (toString == typeName)
if (string.IsNullOrEmpty(temp))
{ {
label = m_richValueType; label = m_richValueType;
} }
else else // Otherwise, parse the result and put our highlighted name in.
{ {
if (toString.Length > 200) if (toString.Length > 200)
toString = toString.Substring(0, 200) + "..."; toString = toString.Substring(0, 200) + "...";

View File

@ -155,8 +155,11 @@ namespace UnityExplorer.UI
MainPanel = UIFactory.CreatePanel(UIManager.CanvasRoot, "MainMenu", out GameObject content); MainPanel = UIFactory.CreatePanel(UIManager.CanvasRoot, "MainMenu", out GameObject content);
RectTransform panelRect = MainPanel.GetComponent<RectTransform>(); RectTransform panelRect = MainPanel.GetComponent<RectTransform>();
panelRect.anchorMin = new Vector2(0.25f, 0.1f); //panelRect.anchorMin = new Vector2(0.25f, 0.1f);
panelRect.anchorMax = new Vector2(0.78f, 0.95f); //panelRect.anchorMax = new Vector2(0.78f, 0.95f);
var anchors = ExplorerConfig.Instance.GetWindowAnchorsVector();
panelRect.anchorMin = new Vector2(anchors.x, anchors.y);
panelRect.anchorMax = new Vector2(anchors.z, anchors.w);
MainPanel.AddComponent<Mask>(); MainPanel.AddComponent<Mask>();

View File

@ -8,36 +8,36 @@ namespace UnityExplorer.UI
{ {
public class UISyntaxHighlight public class UISyntaxHighlight
{ {
public const string Field_Static = "#8d8dc6"; public const string FIELD_STATIC = "#8d8dc6";
public const string Field_Instance = "#c266ff"; public const string FIELD_INSTANCE = "#c266ff";
public const string Method_Static = "#b55b02"; public const string METHOD_STATIC = "#b55b02";
public const string Method_Instance = "#ff8000"; public const string METHOD_INSTANCE = "#ff8000";
public const string Prop_Static = "#588075"; public const string PROP_STATIC = "#588075";
public const string Prop_Instance = "#55a38e"; public const string PROP_INSTANCE = "#55a38e";
public const string Class_Static = "#3a8d71"; public const string CLASS_STATIC = "#3a8d71";
public const string Class_Instance = "#2df7b2"; public const string CLASS_INSTANCE = "#2df7b2";
public const string Local = "#a6e9e9"; public const string CLASS_STRUCT = "#0fba3a";
public const string StructGreen = "#0fba3a"; public const string LOCAL_ARG = "#a6e9e9";
public static string Enum = "#92c470"; public static string CONST_VAR = "#92c470";
internal static readonly Color s_silver = new Color(0.66f, 0.66f, 0.66f); internal static readonly Color s_silver = new Color(0.66f, 0.66f, 0.66f);
internal static string GetClassColor(Type type) internal static string GetClassColor(Type type)
{ {
if (type.IsAbstract && type.IsSealed) if (type.IsAbstract && type.IsSealed)
return Class_Static; return CLASS_STATIC;
else if (type.IsEnum || type.IsGenericParameter) else if (type.IsEnum || type.IsGenericParameter)
return Enum; return CONST_VAR;
else if (type.IsValueType) else if (type.IsValueType)
return StructGreen; return CLASS_STRUCT;
else else
return Class_Instance; return CLASS_INSTANCE;
} }
public static string ParseFullSyntax(Type type, bool includeNamespace, MemberInfo memberInfo = null) public static string ParseFullSyntax(Type type, bool includeNamespace, MemberInfo memberInfo = null)
@ -49,7 +49,7 @@ namespace UnityExplorer.UI
if (type.IsGenericParameter || (type.HasElementType && type.GetElementType().IsGenericParameter)) if (type.IsGenericParameter || (type.HasElementType && type.GetElementType().IsGenericParameter))
{ {
ret = $"<color={Enum}>{type.Name}</color>"; ret = $"<color={CONST_VAR}>{type.Name}</color>";
} }
else else
{ {
@ -134,7 +134,7 @@ namespace UnityExplorer.UI
if (allGeneric) if (allGeneric)
{ {
args += $"<color={Enum}>{arg.Name}</color>"; args += $"<color={CONST_VAR}>{arg.Name}</color>";
continue; continue;
} }
@ -153,30 +153,30 @@ namespace UnityExplorer.UI
if (fi.IsStatic) if (fi.IsStatic)
{ {
isStatic = true; isStatic = true;
memberColor = Field_Static; memberColor = FIELD_STATIC;
} }
else else
memberColor = Field_Instance; memberColor = FIELD_INSTANCE;
} }
else if (memberInfo is MethodInfo mi) else if (memberInfo is MethodInfo mi)
{ {
if (mi.IsStatic) if (mi.IsStatic)
{ {
isStatic = true; isStatic = true;
memberColor = Method_Static; memberColor = METHOD_STATIC;
} }
else else
memberColor = Method_Instance; memberColor = METHOD_INSTANCE;
} }
else if (memberInfo is PropertyInfo pi) else if (memberInfo is PropertyInfo pi)
{ {
if (pi.GetAccessors(true)[0].IsStatic) if (pi.GetAccessors(true)[0].IsStatic)
{ {
isStatic = true; isStatic = true;
memberColor = Prop_Static; memberColor = PROP_STATIC;
} }
else else
memberColor = Prop_Instance; memberColor = PROP_INSTANCE;
} }
return memberColor; return memberColor;
} }