using System; using System.Collections.Generic; using System.Reflection; using UnityEngine; namespace DebuggingEssentials { [DefaultExecutionOrder(-4000000)] [ConsoleAlias("console")] public class RuntimeConsole : MonoBehaviour { public delegate void RemoteCommand(string command); public class StringDictionarySorted { public Dictionary lookup = new Dictionary(); public string[] names; public void Sort() { names = new string[lookup.Count]; lookup.Keys.CopyTo(names, 0); Array.Sort(names); } public void Clear() { lookup.Clear(); names = null; } } public enum MemberType { Method = 0, Property = 1, Field = 2, Delegate = 3 } public struct CommandData { public static CommandData empty; public ConsoleCommand consoleCommand; public object obj; public bool isStatic; public string syntax; public MemberType memberType; public MemberInfo member; public ParameterInfo[] paramInfos; private object[] args; public CommandData(ConsoleCommand consoleCommand, object obj, string syntax, MemberType memberType, MemberInfo member, ParameterInfo[] paramInfos, bool isStatic) { this.consoleCommand = consoleCommand; this.obj = obj; this.syntax = syntax; this.memberType = memberType; this.member = member; this.isStatic = isStatic; if (paramInfos == null || (paramInfos != null && paramInfos.Length == 0)) { this.paramInfos = null; args = null; } else { this.paramInfos = paramInfos; args = new object[paramInfos.Length]; } } public object GetValue() { object instance; if (isStatic) { instance = obj; } else { int instanceWhenOnlyOne = GetInstanceWhenOnlyOne(out instance); if (instanceWhenOnlyOne == 0) { return "null"; } if (instanceWhenOnlyOne > 1) { return ">"; } } if (memberType == MemberType.Method || memberType == MemberType.Delegate) { return null; } if (memberType == MemberType.Field) { return ((FieldInfo)member).GetValue(instance); } if (memberType == MemberType.Property) { MethodInfo getMethod = ((PropertyInfo)member).GetGetMethod(nonPublic: true); if (getMethod != null) { return getMethod.Invoke(instance, null); } } return null; } public bool IsRegistered() { if (isStatic) { return true; } registeredInstancesLookup.TryGetValue((Type)obj, out var value); if (value != null) { return value.Count > 0; } return false; } public int GetInstanceCount() { if (isStatic || obj == null) { return -1; } registeredInstancesLookup.TryGetValue((Type)obj, out var value); if (value == null) { return 0; } CheckDestroyedMonoBehaviours(value); return value.Count; } public int GetInstanceWhenOnlyOne(out object instance) { registeredInstancesLookup.TryGetValue((Type)obj, out var value); if (value == null) { instance = null; return 0; } CheckDestroyedMonoBehaviours(value); if (value.Count != 1) { instance = null; return value.Count; } using (HashSet.Enumerator enumerator = value.GetEnumerator()) { if (enumerator.MoveNext()) { object current = enumerator.Current; instance = current; return 1; } } instance = null; return 0; } public void Execute(FastQueue arguments, string argumentString) { if (memberType == MemberType.Method || memberType == MemberType.Delegate) { ExecuteMethodOrDelegate(arguments, argumentString); } else if (memberType == MemberType.Field) { ExecuteField(arguments, argumentString); } else if (memberType == MemberType.Property) { ExecuteProperty(arguments, argumentString); } } private void ExecuteMethodOrDelegate(FastQueue arguments, string argumentString) { if (paramInfos != null) { int count = arguments.Count; for (int i = 0; i < paramInfos.Length; i++) { ParameterInfo parameterInfo = paramInfos[i]; Type parameterType = parameterInfo.ParameterType; if (i >= count) { if (!parameterInfo.IsOptional) { LogResultError("Can't execute because of wrong number of arguments"); return; } args[i] = parameterInfo.DefaultValue; } else if (!Parser.TryParse(parameterType, arguments, out args[i])) { return; } } } if (arguments.Count > 0) { LogResultError("Too many arguments"); return; } if (memberType == MemberType.Method) { if (isStatic) { ExecuteMethod(member, (MethodInfo)member, obj, args, argumentString); return; } HashSet hashSet = registeredInstancesLookup[(Type)obj]; CheckDestroyedMonoBehaviours(hashSet); { foreach (object item in hashSet) { if (item as MonoBehaviour == null && item.GetType().IsSubclassOf(typeof(MonoBehaviour))) { Debug.Log("Mono = isDestroyed"); } else { ExecuteMethod(member, (MethodInfo)member, item, args, argumentString); } } return; } } if (isStatic) { ExecuteDelegateMethod(member, obj, args, argumentString); return; } HashSet hashSet2 = registeredInstancesLookup[(Type)obj]; CheckDestroyedMonoBehaviours(hashSet2); foreach (object item2 in hashSet2) { ExecuteDelegateMethod(member, item2, args, argumentString); } } private void ExecuteDelegateMethod(MemberInfo member, object obj, object[] args, string argumentString) { object value = ((FieldInfo)member).GetValue(obj); if (value == null) { LogResultError(obj.ToString() + " : " + member.Name + " delegate is not assigned"); return; } MethodInfo method = value.GetType().GetMethod("Invoke"); ExecuteMethod(member, method, value, args, argumentString); } private void ExecuteMethod(MemberInfo member, MethodInfo method, object obj, object[] args, string argumentString) { try { object obj2 = method.Invoke(obj, args); if (obj2 != null) { LogResult(obj.ToString() + " : " + member.Name + " " + argumentString + " = " + obj2); } } catch (Exception exception) { Debug.LogException(exception); } } private void ExecuteField(FastQueue arguments, string argumentString) { FieldInfo fieldInfo = (FieldInfo)member; if (arguments.Count == 0) { if (!isStatic) { HashSet hashSet = registeredInstancesLookup[(Type)obj]; CheckDestroyedMonoBehaviours(hashSet); { foreach (object item in hashSet) { LogValue(fieldInfo, item); } return; } } LogValue(fieldInfo, obj); } else { if (!Parser.TryParse(fieldInfo.FieldType, arguments, out var result)) { return; } if (arguments.Count > 0) { LogResultError("Too many arguments"); return; } if (!isStatic) { HashSet hashSet2 = registeredInstancesLookup[(Type)obj]; CheckDestroyedMonoBehaviours(hashSet2); { foreach (object item2 in hashSet2) { SetField(fieldInfo, item2, result); } return; } } SetField(fieldInfo, obj, result); } } private void LogValue(FieldInfo field, object obj) { try { LogResult(obj.ToString() + " : " + field.Name + " = " + field.GetValue(obj)); } catch (Exception exception) { Debug.LogException(exception); } } private void SetField(FieldInfo field, object obj, object arg) { try { if (arg != null) { field.SetValue(obj, arg); } LogResult(obj.ToString() + " : " + field.Name + " = " + field.GetValue(obj)); } catch (Exception exception) { Debug.LogException(exception); } } private void ExecuteProperty(FastQueue arguments, string argumentString) { PropertyInfo propertyInfo = (PropertyInfo)member; if (arguments.Count == 0) { if (propertyInfo.GetGetMethod(nonPublic: true) == null) { LogResultError(propertyInfo.Name + " doesn't have a getter"); return; } if (!isStatic) { HashSet hashSet = registeredInstancesLookup[(Type)obj]; CheckDestroyedMonoBehaviours(hashSet); { foreach (object item in hashSet) { LogValue(propertyInfo, item); } return; } } LogValue(propertyInfo, obj); } else if (propertyInfo.GetSetMethod(nonPublic: true) == null) { LogResultError(propertyInfo.Name + " doesn't have a setter"); } else { if (!Parser.TryParse(propertyInfo.PropertyType, arguments, out var result)) { return; } if (arguments.Count > 0) { LogResultError("Too many arguments"); return; } if (!isStatic) { HashSet hashSet2 = registeredInstancesLookup[(Type)obj]; CheckDestroyedMonoBehaviours(hashSet2); { foreach (object item2 in hashSet2) { SetProperty(propertyInfo, item2, result); } return; } } SetProperty(propertyInfo, obj, result); } } private void LogValue(PropertyInfo prop, object obj) { try { LogResult(obj.ToString() + " : " + prop.Name + " = " + prop.GetValue(obj, null)); } catch (Exception exception) { Debug.LogException(exception); } } private void SetProperty(PropertyInfo prop, object obj, object arg) { try { if (arg != null) { prop.SetValue(obj, arg, null); } if (prop.GetGetMethod(nonPublic: true) != null) { LogResult(obj.ToString() + " : " + prop.Name + " = " + prop.GetValue(obj, null)); } } catch (Exception exception) { Debug.LogException(exception); } } private bool CheckParameterCount(int required, int count) { if (required == count) { return true; } LogResultError("Can't execute because " + required + " arguments are needed"); return false; } } public enum AccessMode { EnabledOnConsoleCommand = 0, Enabled = 1, Disabled = 2 } public struct AutoComplete { public string command; public CommandData commandData; public AutoComplete(string command, CommandData commandData) { this.command = command; this.commandData = commandData; } } public static RuntimeConsole instance; public static AccessLevel accessLevel; public static bool show; private static Dictionary> registeredInstancesLookup = new Dictionary>(); private static StringDictionarySorted commandsTable = new StringDictionarySorted(); private static FastList autoCompleteList = new FastList(); private static FastQueue inputCommands = new FastQueue(32); private static FastList threadLogEntries = new FastList(256); private static FastList logEntries = new FastList(256); private SortedFastList commands = new SortedFastList(); private const int logSize = 8192; private const int commandLogs = 0; private const int frameLogs = 1; private const int unityLogs = 2; private const int warningLogs = 3; private const int errorLogs = 4; private const int exceptionLogs = 5; private static bool setFocus; private static int lastFrame = -1; private static LogEntry lastFrameEntry; private WindowSettings consoleWindow; private int commandIndex; private int moveInputCursor; private int autoCompleteIndex; private string inputCommand; private GUIChangeBool _showStack = new GUIChangeBool(value: true); private GUIChangeBool showUnityLogs = new GUIChangeBool(value: true); private GUIChangeBool showLastLog = new GUIChangeBool(value: true); private Vector2 autoCompleteScrollView; private Double2 scrollView; private Double2 scrollViewHeights; private CullGroup cullGroup; private FastList cullLists = new FastList(); private static CullList[] logs; private bool calcDraw; private bool isEnabled; private int oldAutoCompleteCount = -1; private bool updateAutoCompleteScrollView; private bool isDebugBuild; public bool showConsoleOnStart = true; [ConsoleCommand(AccessLevel.Admin)] public bool showConsoleOnWarning; [ConsoleCommand(AccessLevel.Admin)] public bool showConsoleOnError; [ConsoleCommand(AccessLevel.Admin)] public bool showConsoleOnException; [ConsoleCommand(AccessLevel.Admin)] public bool showConsoleWhenInvokingMethod = true; [ConsoleCommand(AccessLevel.Admin)] public bool disableUnityDevelopmentConsole = true; public bool useSameEditorAsBuildShowKey = true; public AdvancedKey showToggleKeyEditor = new AdvancedKey(KeyCode.F9); public AdvancedKey showToggleKeyBuild = new AdvancedKey(KeyCode.F9); [Tooltip("This ignores cases in commands")] [ConsoleCommand(AccessLevel.Admin)] public bool ignoreCasesInCommands; [Tooltip("This ignores cases for auto-complete lookup, but still cases are needed for commands")] [ConsoleCommand(AccessLevel.Admin)] public bool ignoreCasesInAutoCompleteInput = true; public AccessMode adminModeInBuild; public string adminModeConsoleCommand = "*GetAdminAccess*"; public AccessMode specialModeInBuild; public string specialModeConsoleCommand = "*GetSpecialAccess*"; [Tooltip("This will disable admin/special commands in Unity Editor")] public bool testOnlyFreeConsoleCommands; public char searchCommandPrefix = '!'; [ConsoleCommand(AccessLevel.Admin)] public bool ignoreCasesInSearch = true; public char executeOnAllPrefix = '#'; public char executeOnlyOnRemotePrefix = '$'; public int titleFontSize = 18; public int frameFontSize = 14; public int logFontSize = 14; public int stackFontSize = 12; public SO_ConsoleWindow windowData; private Color selectColor = new Color(0.25f, 0.8f, 0.25f); private Color backgroundColor = new Color(0f, 0f, 0f, 0.9f); private Rect rectAutoComplete; private Rect rectScroll; private string lastAutoCompleteCommand; private double scrollViewEndHeight; private bool drawLogsScrollBar; private bool addInput; public static event RemoteCommand onRemoteCommand; public static event SetActiveMethod onSetActive; private void ResetStatic() { RuntimeConsole.onRemoteCommand = null; accessLevel = AccessLevel.Admin; show = false; autoCompleteList.Clear(); inputCommands.Clear(); threadLogEntries.Clear(); logEntries.Clear(); commands.Clear(); LogEntry.ResetStatic(); logs = null; } private void Awake() { isDebugBuild = Debug.isDebugBuild; ResetStatic(); consoleWindow = windowData.consoleWindow; logs = new CullList[6]; cullGroup = new CullGroup(8192 * logs.Length); for (int i = 0; i < logs.Length; i++) { logs[i] = new CullList(8192); } SetActive(showConsoleOnStart); inputCommand = string.Empty; logs[0].cullItems.Add(new LogEntry("-------------------------------------------------------------------------------", Color.white, titleFontSize, FontStyle.Bold)); logs[0].cullItems.Add(new LogEntry(Helper.GetApplicationInfo(), Color.white, titleFontSize, FontStyle.Bold)); logs[0].cullItems.Add(new LogEntry("-------------------------------------------------------------------------------", Color.white, titleFontSize, FontStyle.Bold)); logs[0].cullItems.Add(new LogEntry(string.Empty, Color.white, titleFontSize, FontStyle.Bold)); logs[0].cullItems.Add(new LogEntry("Type '?' to list all commands", Color.white, titleFontSize, FontStyle.Bold)); logs[0].cullItems.Add(new LogEntry(string.Empty, Color.white, titleFontSize, FontStyle.Bold)); GUIChangeBool.ApplyUpdates(); Register(this); CalcDraw(reset: true); if (adminModeInBuild == AccessMode.Enabled) { accessLevel = AccessLevel.Admin; } } private void OnEnable() { isEnabled = true; } private void OnDisable() { isEnabled = false; } private void OnDestroy() { if (instance == this) { instance = null; } Unregister(this); } public void ManualUpdate() { if (isDebugBuild && disableUnityDevelopmentConsole) { Debug.developerConsoleVisible = false; } UpdateLogs(); if (isEnabled && EventInput.isMouseButtonUp0) { consoleWindow.drag = 0; } } public static void SetActive(bool active) { instance.consoleWindow.drag = 0; show = active; instance.gameObject.SetActive(active); if (show) { setFocus = true; } if (RuntimeConsole.onSetActive != null) { RuntimeConsole.onSetActive(show); } WindowManager.CheckMouseCursorState(); } public static void Log(string logString, bool showConsole) { if (!(instance == null)) { AddLog(new LogEntry(logString, null, LogType.Log, EntryType.Console, Color.white)); if (showConsole && !show) { SetActive(active: true); } } } public static void Log(string logString, Color color, bool showConsole) { if (!(instance == null)) { AddLog(new LogEntry(logString, null, LogType.Log, EntryType.Console, color)); if (showConsole && !show) { SetActive(active: true); } } } public static void Log(string logString, LogType logType = LogType.Log, Color color = default(Color), bool showConsole = false) { if (!(instance == null)) { AddLog(new LogEntry(logString, null, logType, EntryType.Console, color)); if (showConsole && !show) { SetActive(active: true); } } } public static void Log(string logString, string[] lines, LogType logType = LogType.Log, Color color = default(Color), int threadId = -1) { if (!(instance == null)) { AddLog(new LogEntry(logString, lines, logType, EntryType.Unity, color, instance.logFontSize, FontStyle.Normal, threadId)); } } public static void Log(LogEntry logEntry) { if (!(instance == null)) { AddLog(logEntry); } } private static void AddLog(LogEntry logEntry) { if (CheckNewFrame()) { logEntry.id = LogEntry.currentId++; } threadLogEntries.AddThreadSafe(logEntry); } private void UpdateLogs() { logEntries.GrabListThreadSafe(threadLogEntries); for (int i = 0; i < logEntries.Count; i++) { LogEntry logEntry = logEntries.items[i]; if (logEntry.entryType == EntryType.Unity) { if (logEntry.logType == LogType.Log) { instance.windowData.logIcon.count++; lastFrameEntry.flag |= 1; logs[2].cullItems.Add(logEntry); } else if (logEntry.logType == LogType.Warning) { if (instance.showConsoleOnWarning && !show) { SetActive(active: true); } instance.windowData.warningIcon.count++; lastFrameEntry.flag |= 2; logs[3].cullItems.Add(logEntry); } else if (logEntry.logType == LogType.Error) { if (instance.showConsoleOnError && !show) { SetActive(active: true); } instance.windowData.errorIcon.count++; lastFrameEntry.flag |= 4; logs[4].cullItems.Add(logEntry); } else if (logEntry.logType == LogType.Exception) { if (instance.showConsoleOnException && !show) { SetActive(active: true); } instance.windowData.exceptionIcon.count++; lastFrameEntry.flag |= 8; logs[5].cullItems.Add(logEntry); } } else if (logEntry.entryType == EntryType.Frame) { logs[1].cullItems.Add(lastFrameEntry); } else { lastFrameEntry.flag |= 16; logs[0].cullItems.Add(logEntry); } } logEntries.Clear(); instance.CalcDraw(reset: false); } private static bool CheckNewFrame() { if (HtmlDebug.currentFrame != lastFrame) { lastFrame = HtmlDebug.currentFrame; lastFrameEntry = new LogEntry("[Frame " + lastFrame.ToString("D6") + "][Time " + Helper.ToTimeFormat(HtmlDebug.frameTime) + "] -----------------------------------------------------------------------------------------------", null, LogType.Log, EntryType.Frame, new Color(0.31f, 0.55f, 0.63f), instance.frameFontSize, FontStyle.Bold); threadLogEntries.AddThreadSafe(lastFrameEntry); return true; } return false; } public static void SortCommandsTable() { commandsTable.Sort(); } public static void Register(object instance) { if (Application.isPlaying) { Type type = instance.GetType(); if (!registeredInstancesLookup.TryGetValue(type, out var value)) { value = new HashSet(); registeredInstancesLookup[type] = value; } else if (value.Contains(instance)) { Debug.LogError("Instance " + type.Name + " is already registered"); return; } value.Add(instance); } } public static void Unregister(object instance) { Type type = instance.GetType(); registeredInstancesLookup.TryGetValue(type, out var value); if (instance == null || !value.Contains(instance)) { Debug.LogError("Instance " + type.Name + " is not registered"); return; } value.Remove(instance); if (value.Count == 0) { registeredInstancesLookup.Remove(type); } } public static void RegisterStaticType(Type objType) { if (instance == null) { return; } ConsoleAlias[] array = (ConsoleAlias[])objType.GetCustomAttributes(typeof(ConsoleAlias), inherit: true); if (array.Length != 0) { commandsTable.lookup[array[0].alias] = CommandData.empty; } MemberInfo[] members = objType.GetMembers(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (MemberInfo memberInfo in members) { ConsoleCommand[] array2 = (ConsoleCommand[])memberInfo.GetCustomAttributes(typeof(ConsoleCommand), inherit: false); if (array2.Length == 0) { continue; } ConsoleCommand consoleCommand = array2[0]; if (array.Length != 0) { consoleCommand.alias = array[0].alias + ((consoleCommand.alias.Length > 0) ? ("." + consoleCommand.alias) : string.Empty); } if (AddMethod(objType, consoleCommand, memberInfo, memberInfo as MethodInfo, MemberType.Method, memberInfo.Name)) { continue; } FieldInfo fieldInfo = memberInfo as FieldInfo; if (fieldInfo != null) { Type fieldType = fieldInfo.FieldType; if (typeof(Delegate).IsAssignableFrom(fieldType)) { AddMethod(objType, consoleCommand, memberInfo, fieldType.GetMethod("Invoke"), MemberType.Delegate, fieldInfo.Name); } else if (ValidParam(objType, fieldInfo, fieldType)) { if (fieldType.IsEnum && consoleCommand.description == string.Empty) { consoleCommand.description = string.Join(", ", Enum.GetNames(fieldType)); } string syntax = fieldInfo.Name + " " + fieldType.Name; AddCommand(memberInfo, consoleCommand, memberInfo.Name, new CommandData(consoleCommand, objType, syntax, MemberType.Field, memberInfo, null, fieldInfo.IsStatic)); } continue; } PropertyInfo propertyInfo = memberInfo as PropertyInfo; if (!(propertyInfo != null)) { continue; } Type propertyType = propertyInfo.PropertyType; if (!ValidParam(objType, propertyInfo, propertyType)) { continue; } MethodInfo getMethod = propertyInfo.GetGetMethod(nonPublic: true); MethodInfo setMethod = propertyInfo.GetSetMethod(nonPublic: true); bool flag = getMethod != null; bool flag2 = setMethod != null; bool isStatic; if (flag) { isStatic = getMethod.IsStatic; } else { if (!flag2) { Debug.Log("Property has no getter or setter"); continue; } isStatic = setMethod.IsStatic; } string text = propertyInfo.Name + " " + propertyType.Name; AddCommand(commandData: new CommandData(consoleCommand, objType, (flag && !flag2) ? (text + " (get)") : ((!(flag && flag2)) ? (text + " (set)") : (text + " (get set)")), MemberType.Property, memberInfo, null, isStatic), member: memberInfo, consoleCommand: consoleCommand, commandName: memberInfo.Name); } } private static bool AddMethod(Type objType, ConsoleCommand consoleCommand, MemberInfo member, MethodInfo method, MemberType memberType, string methodName, bool logFailed = true) { if (method != null) { ParameterInfo[] parameters = method.GetParameters(); if (!ValidParams(objType, method, parameters)) { return true; } string syntax = method.ToString(); AddCommand(member, consoleCommand, methodName, new CommandData(consoleCommand, objType, syntax, memberType, member, parameters, method.IsStatic), logFailed); return true; } return false; } private static void AddCommand(MemberInfo member, ConsoleCommand consoleCommand, string commandName, CommandData commandData, bool logFailed = true) { if (instance.ignoreCasesInCommands) { commandName = commandName.ToLower(); } if (consoleCommand.command == string.Empty) { consoleCommand.command = commandName; } else { commandName = consoleCommand.command; if (instance.ignoreCasesInCommands) { commandName = commandName.ToLower(); } } if (consoleCommand.alias != string.Empty) { if (!commandsTable.lookup.ContainsKey(consoleCommand.alias)) { commandsTable.lookup[consoleCommand.alias] = CommandData.empty; } commandName = consoleCommand.alias + "." + consoleCommand.command; } if (commandsTable.lookup.ContainsKey(commandName)) { if (logFailed) { Debug.LogError("Duplicate command: `" + commandName + "` on " + member.Name + " in " + commandData.obj.ToString() + " class "); } } else { commandsTable.lookup[commandName] = commandData; } } public static bool ValidParams(Type objType, MethodInfo method, ParameterInfo[] paramInfos, bool logFailed = true) { foreach (ParameterInfo parameterInfo in paramInfos) { Type parameterType = parameterInfo.ParameterType; if (!ValidParam(objType, parameterInfo.Member, parameterType, logFailed)) { return false; } } return true; } private static bool ValidParam(Type objType, MemberInfo member, Type type, bool logFailed = true) { bool flag = false; if (type.IsPrimitive) { flag = true; } else if (type == typeof(decimal)) { flag = true; } else if (type == typeof(string)) { flag = true; } else if (type == typeof(Vector2) || type == typeof(Vector3) || type == typeof(Vector4)) { flag = true; } else if (type.IsEnum) { flag = true; } if (!flag) { if (logFailed) { Debug.LogError("Cannot register: " + objType.Name + " => " + member.Name + " method contains parameter of type " + type.Name + ". Only primitive and string parameters are allowed at the moment."); } return false; } return true; } private static void CheckDestroyedMonoBehaviours(HashSet instances) { instances.RemoveWhere((object s) => s as MonoBehaviour == null && s.GetType().IsSubclassOf(typeof(MonoBehaviour))); } private static int IsRemoteCommand(ref string command) { int result; if (command[0] == instance.executeOnAllPrefix) { result = 1; command = command.Substring(1); } else if (command[0] == instance.executeOnlyOnRemotePrefix) { result = 2; command = command.Substring(1); } else { result = 0; } return result; } public static void ExecuteCommand(string command) { command = command.Replace(',', ' '); command = command.Trim(' '); if (command == string.Empty) { return; } if (command == instance.adminModeConsoleCommand && (instance.adminModeInBuild == AccessMode.EnabledOnConsoleCommand || instance.testOnlyFreeConsoleCommands)) { accessLevel = AccessLevel.Admin; LogResult("AccessLevel = Admin"); } else if (command == instance.specialModeConsoleCommand && (instance.specialModeInBuild == AccessMode.EnabledOnConsoleCommand || instance.testOnlyFreeConsoleCommands)) { accessLevel = AccessLevel.Special; LogResult("AccessLevel = Special"); } else { if (command[0] == instance.searchCommandPrefix) { return; } int num = IsRemoteCommand(ref command); int num2 = command.IndexOf(" "); string argumentString = ((num2 == -1) ? string.Empty : command.Substring(num2 + 1)); GetArguments(command, inputCommands); string text = inputCommands.Dequeue(); if (!commandsTable.lookup.TryGetValue(text, out var value) || value.obj == null) { CannotFindCommand(command, text); return; } if (value.consoleCommand != null && !value.consoleCommand.HasAccess(accessLevel)) { CannotFindCommand(command, text); return; } if (!value.IsRegistered()) { LogResultError("There is no registered instance for command '" + text + "'"); return; } if (num > 0) { if (RuntimeConsole.onRemoteCommand != null) { RuntimeConsole.onRemoteCommand(command); } command = ((num != 2) ? ("Execute on all '" + command + "'") : ("Execute only on remote '" + command + "'")); } Log(new LogEntry(command, null, LogType.Log, EntryType.Command, Color.green, instance.logFontSize, FontStyle.Bold)); if ((bool)HtmlDebug.instance) { HtmlDebug.instance.UnityDebugLog(command, null, LogType.Log, isMainThread: true, -1, null, EntryType2.Command, closeLi: false); } if (num != 2) { value.Execute(inputCommands, argumentString); } } } public static void GetArguments(string argumentString, FastQueue inputCommands) { argumentString = argumentString.Trim(' '); inputCommands.FastClear(); int num = 0; for (int i = 0; i < argumentString.Length; i++) { char c = argumentString[i]; if (i == argumentString.Length - 1) { inputCommands.Enqueue(argumentString.Substring(num, i - num + 1).Trim()); break; } if (c == ' ') { if (i < argumentString.Length - 1 && argumentString[i + 1] == ' ') { continue; } int num2 = argumentString.IndexOf(' ', i + 1); int num3 = i - num; inputCommands.Enqueue(argumentString.Substring(num, num3).Trim()); if (num2 == -1) { inputCommands.Enqueue(argumentString.Substring(i + 1).Trim()); break; } num += num3 + 1; } if (c == '"') { int num4 = argumentString.IndexOf('"', i + 1); if (num4 == -1) { LogCommandFailed(argumentString, "String closing \" is missing"); break; } int num5 = num4 - num; inputCommands.Enqueue(argumentString.Substring(num + 1, num5 - 1).Trim()); num += num5 + 1; i = num4 + 1; } } } private static void CannotFindCommand(string command, string firstCommand) { string result = "Cannot find command '" + firstCommand + "'"; LogCommandFailed(command, result); } private static void LogCommandFailed(string command, string result) { Log(new LogEntry(command, null, LogType.Log, EntryType.Command, Color.green, instance.logFontSize, FontStyle.Bold)); Log(new LogEntry(result, null, LogType.Log, EntryType.CommandResult, Helper.colCommandResultFailed, instance.logFontSize, FontStyle.Bold)); if ((bool)HtmlDebug.instance) { HtmlDebug.instance.UnityDebugLog(result, null, LogType.Log, isMainThread: true, -1, null, EntryType2.CommandFault); } } public static bool FindCommand(string command) { string[] array = command.Split(' '); if (!commandsTable.lookup.TryGetValue(array[0], out var value) || value.obj == null) { return false; } return true; } private static void LogResult(string result) { Log(new LogEntry(result, null, LogType.Log, EntryType.CommandResult, Helper.colCommandResult, instance.logFontSize, FontStyle.Bold)); if ((bool)HtmlDebug.instance) { HtmlDebug.instance.UnityDebugLog(result, null, LogType.Log, isMainThread: true, -1, null, EntryType2.CommandResult); } } public static void LogResultError(string result, bool onlyConsoleAndHtml = true) { if (onlyConsoleAndHtml) { Log(new LogEntry(result, null, LogType.Log, EntryType.CommandResult, Helper.colCommandResultFailed, instance.logFontSize, FontStyle.Bold)); if ((bool)HtmlDebug.instance) { HtmlDebug.instance.UnityDebugLog(result, null, LogType.Log, isMainThread: true, -1, null, EntryType2.CommandFault); } } else { Debug.LogError(result); } } [ConsoleCommand("", "Clears all logs in the Console Window", AccessLevel.Admin)] private static void Clear() { for (int i = 0; i < logs.Length; i++) { logs[i].cullItems.Clear(); } instance.CalcDraw(reset: true); instance.windowData.logIcon.count = 0; instance.windowData.warningIcon.count = 0; instance.windowData.errorIcon.count = 0; instance.windowData.exceptionIcon.count = 0; } [ConsoleCommand("", "Change the height of the Console Window based on line height", AccessLevel.Admin)] private static void Lines(int count = 20) { instance.consoleWindow.rect.height = 25 * count; } [ConsoleCommand("", "Open the Console Window", AccessLevel.Admin)] private static void Open() { SetActive(active: true); } [ConsoleCommand("", "Close the Console Window", AccessLevel.Admin)] private static void Close() { SetActive(active: false); } [ConsoleCommand("", "Unload unused Assets", AccessLevel.Admin)] private static void UnloadUnusedAssets() { Resources.UnloadUnusedAssets(); } [ConsoleCommand("", "Runs Garbage Collect", AccessLevel.Admin)] private static void GarbageCollect() { GC.Collect(); } [ConsoleCommand("", "Search for methods in assemblies", AccessLevel.Admin)] private static void SearchMethod(string name) { FastList customAssemblies = RuntimeInspector.customAssemblies; for (int i = 0; i < customAssemblies.Count; i++) { CustomAssembly customAssembly = customAssemblies.items[i]; FastList allTypes = customAssembly.allTypes; if (customAssembly.type != AssemblyType.Unity) { continue; } for (int j = 0; j < allTypes.Count; j++) { Type type = allTypes.items[j].type; MethodInfo[] methods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy); for (int k = 0; k < methods.Length; k++) { string text = methods[k].ToString(); if (text.IndexOf(name, StringComparison.CurrentCultureIgnoreCase) != -1) { Log(customAssembly.name + "." + type.Name + "." + text); } } } } } private Vector2 GetDockPos() { float num = WindowManager.instance.windowData.guiScale.value * 2f; return new Vector2(((float)Screen.width / num - consoleWindow.rect.width / 2f) / (float)Screen.width, 0f); } private void CalcDraw(bool reset) { LogEntry.showCommandLogs = logs[0].show.Value; LogEntry.showUnityLogs = logs[2].show.Value; LogEntry.showWarningLogs = logs[3].show.Value; LogEntry.showErrorLogs = logs[4].show.Value; LogEntry.showExceptionLogs = logs[5].show.Value; LogEntry.showStack = _showStack.Value; if (reset) { LogEntry.lastLog = null; } cullLists.Clear(); if (logs[0].show.Value) { cullLists.Add(logs[0]); } if (showUnityLogs.Value) { for (int i = 1; i <= 5; i++) { if (logs[i].show.Value) { cullLists.Add(logs[i]); } } } cullGroup.CalcDraw(reset, cullLists); } public void MyOnGUI() { Event current = Event.current; if (Helper.IsShowKeyPressed(current, useSameEditorAsBuildShowKey, showToggleKeyEditor, showToggleKeyBuild)) { SetActive(!show); } else { if (!show) { return; } if (current.type == EventType.Layout && calcDraw) { calcDraw = false; CalcDraw(reset: true); } if (consoleWindow.isDocked.Value) { if (consoleWindow.drag == 1) { if (consoleWindow.position != GetDockPos()) { consoleWindow.isDocked.Value = false; } } else { consoleWindow.position = GetDockPos(); } } consoleWindow.Update(700f, 94f); GUI.skin = windowData.skin; if (WindowManager.instance.useCanvas) { GUI.backgroundColor = new Color(1f, 1f, 1f, 0f); } else { GUI.backgroundColor = windowData.color; } Helper.DrawWindow(23423022, consoleWindow, DrawConsole); DrawAutoComplete(); } } private void DrawConsole(int windowId) { WindowManager.BeginRenderTextureGUI(); Event current = Event.current; windowData.skin.box.fontStyle = FontStyle.Bold; Rect rect = consoleWindow.rect; GUI.backgroundColor = Helper.GetColor(windowData, backgroundColor); GUI.Box(new Rect(0f, 0f, rect.width, rect.height), ""); GUILayout.Box("Console"); Helper.Drag(consoleWindow, null, null, titleDrag: true, onlyRightCorner: true); GUI.backgroundColor = Color.white; DrawButtons(); DrawLogs(current, rect); GUILayout.Space(1f); DrawInput(current, rect); drawLogsScrollBar = DrawLogsScrollBar(current); GUILayout.Space(-1f); Helper.Drag(consoleWindow, null, null, titleDrag: false, onlyRightCorner: true); WindowManager.SetToolTip(windowId); WindowManager.EndRenderTextureGUI(); } private void DrawButtons() { GUISkin skin = windowData.skin; int num = 80; GUILayout.BeginHorizontal(); if (Helper.DrawShowButton(windowData, Helper.GetGUIContent("Commands", "Show/Hide Command Logs"), logs[0].show, selectColor, num)) { calcDraw = true; } if (Helper.DrawShowButton(windowData, Helper.GetGUIContent("Unity Log", "Show/Hide Debug Logs"), showUnityLogs, selectColor, num)) { calcDraw = true; } if (showUnityLogs.Value) { GUIContent gUIContent = windowData.logIcon.GetGUIContent(); gUIContent.tooltip = "Show/Hide Debug Logs"; float width = skin.button.CalcSize(gUIContent).x + 2f; if (Helper.DrawShowButton(windowData, gUIContent, logs[2].show, selectColor, width)) { calcDraw = true; } GUIContent gUIContent2 = windowData.warningIcon.GetGUIContent(); gUIContent2.tooltip = "Show/Hide Debug Warnings"; width = skin.button.CalcSize(gUIContent2).x + 2f; if (Helper.DrawShowButton(windowData, gUIContent2, logs[3].show, selectColor, width)) { calcDraw = true; } GUIContent gUIContent3 = windowData.errorIcon.GetGUIContent(); gUIContent3.tooltip = "Show/Hide Debug Errors"; width = skin.button.CalcSize(gUIContent3).x + 2f; if (Helper.DrawShowButton(windowData, gUIContent3, logs[4].show, selectColor, width)) { calcDraw = true; } GUIContent gUIContent4 = windowData.exceptionIcon.GetGUIContent(); gUIContent4.tooltip = "Show/Hide Debug Exceptions"; width = skin.button.CalcSize(gUIContent4).x + 2f; if (Helper.DrawShowButton(windowData, gUIContent4, logs[5].show, selectColor, width)) { calcDraw = true; } if (Helper.DrawShowButton(windowData, Helper.GetGUIContent("Stack", _showStack.Value ? windowData.texStackOn : windowData.texStackOff, "Show/Hide Stack Trace"), _showStack, selectColor, num)) { calcDraw = true; } } if (GUILayout.Button(Helper.GetGUIContent("Html Log", "Open Html Log in browser"), GUILayout.Width(num))) { if ((bool)HtmlDebug.instance) { Application.OpenURL("file://" + HtmlDebug.instance.logPathIncludingFilename); } else { Debug.LogError("Can't find Html Debug, make sure you have the 'Html Debug' GameObject in your Scene and that it's enabled"); } } if (GUILayout.Button(Helper.GetGUIContent("Logs Folder", "Open Logs Folder in File Exlorer"), GUILayout.Width(num))) { if ((bool)HtmlDebug.instance) { if ((bool)HtmlDebug.instance) { Application.OpenURL("file://" + HtmlDebug.instance.logPath); } else { Application.OpenURL("file://" + Application.persistentDataPath); } } else { Debug.LogError("Can't find Html Debug, make sure you have the 'Html Debug' GameObject in your Scene and that it's enabled"); } } if (!consoleWindow.isDocked.Value && GUILayout.Button(Helper.GetGUIContent("Dock", "Centers the window in the top of the screen"), GUILayout.Width(num))) { consoleWindow.isDocked.Value = true; } GUILayout.EndHorizontal(); GUI.backgroundColor = Color.white; } private void DrawLogs(Event currentEvent, Rect window) { GUISkin skin = windowData.skin; rectScroll = new Rect(4f, 54f, window.width - (float)(drawLogsScrollBar ? 22 : 10), window.height - 80f); bool value = _showStack.Value; CullList cullList = cullGroup.cullList; if (currentEvent.type == EventType.Layout) { scrollViewEndHeight = 0.0; if (cullList.cullItems.Count > 0) { scrollViewEndHeight = cullList.cullItems.items[cullList.cullItems.Count - 1].endHeight; } double y = scrollViewEndHeight - (double)rectScroll.height; if (scrollViewEndHeight > (double)rectScroll.height && showLastLog.Value) { scrollView.y = y; } scrollViewHeights = new Double2(scrollView.y, scrollView.y + (double)rectScroll.height); cullList.Cull(scrollViewHeights); } if (cullList.cullItems.Count == 0) { return; } GUILayout.BeginArea(rectScroll); GUILayout.Space((float)(cullList.cullItems.items[cullList.startIndex].startHeight - scrollView.y)); for (int i = cullList.startIndex; i <= cullList.endIndex; i++) { LogEntry logEntry = (LogEntry)cullList.cullItems.items[i]; skin.label.fontSize = logEntry.fontSize; skin.label.fontStyle = logEntry.fontStyle; if (logEntry.entryType == EntryType.Frame) { GUILayout.Space(20f); } GUILayout.BeginHorizontal(); if (logEntry.entryType == EntryType.Unity) { if (logEntry.logType == LogType.Warning) { GUI.color = Color.yellow; } else if (logEntry.logType == LogType.Error) { GUI.color = Color.red; } else if (logEntry.logType == LogType.Exception) { GUI.color = Color.magenta; } else if (logEntry.logType == LogType.Log) { GUI.color = Color.white; } } else { GUI.color = logEntry.color; } if (logEntry.entryType == EntryType.Unity || logEntry.entryType == EntryType.Console || logEntry.entryType == EntryType.Command || logEntry.entryType == EntryType.CommandResult) { GUILayout.Space(30f); } if (logEntry.threadString != null) { float x = GUI.skin.label.CalcSize(Helper.GetGUIContent(logEntry.logString)).x; GUILayout.Label(logEntry.logString, GUILayout.Width(x)); } else { GUILayout.Label(logEntry.logString); } if (logEntry.entryType == EntryType.Unity || logEntry.entryType == EntryType.Console || logEntry.entryType == EntryType.Command) { Rect lastRect = GUILayoutUtility.GetLastRect(); lastRect.x -= 12f; lastRect.y += logEntry.fontSize / 2; if (logEntry.entryType == EntryType.Unity) { lastRect.width = 4f; lastRect.height = 4f; GUI.DrawTexture(lastRect, windowData.texDot); } else { lastRect.y -= 2f; lastRect.width = 8f; lastRect.height = 8f; GUI.DrawTexture(lastRect, windowData.texArrow); } } if (logEntry.threadString != null) { GUI.skin.label.fontStyle = FontStyle.Italic; GUILayout.Label(logEntry.threadString); GUI.skin.label.fontStyle = FontStyle.Normal; } GUILayout.EndHorizontal(); if (value && logEntry.stackLines != null) { skin.label.fontSize = stackFontSize; GUILayout.Space(-3f); GUI.color *= 0.825f; for (int j = 0; j < logEntry.stackLines.Length; j++) { GUILayout.BeginHorizontal(); GUILayout.Space(30f); GUILayout.Label(logEntry.stackLines[j]); GUILayout.EndHorizontal(); } } GUI.color = Color.white; if (!logs[0].show.RealValue && !showUnityLogs.RealValue) { showUnityLogs.Value = true; } } skin.label.fontSize = 12; skin.label.fontStyle = FontStyle.Normal; GUILayout.EndArea(); } private bool DrawLogsScrollBar(Event currentEvent) { Rect position = new Rect { y = 55f, x = rectScroll.width + 5f, width = 20f, height = consoleWindow.rect.height - 80f }; double num = scrollViewEndHeight - (double)rectScroll.height; if (scrollViewEndHeight > (double)rectScroll.height) { if (currentEvent.isScrollWheel && autoCompleteList.Count == 0) { scrollView.y += currentEvent.delta.y * 10f; showLastLog.Value = scrollView.y >= num; } if (showLastLog.Value) { scrollView.y = num; } GUI.changed = false; scrollView.y = GUI.VerticalScrollbar(position, (float)scrollView.y, rectScroll.height, 0f, (float)scrollViewEndHeight); if (GUI.changed) { showLastLog.Value = scrollView.y >= num - 0.10000000149011612; } return true; } scrollView.y = 0.0; return false; } private void DrawInput(Event currentEvent, Rect window) { GUILayout.Space(window.height - 82f); int num = 45; TextEditor textEditor = (TextEditor)GUIUtility.GetStateObject(typeof(TextEditor), GUIUtility.keyboardControl); int num2 = textEditor?.cursorIndex ?? 0; bool flag = GUI.GetNameOfFocusedControl() == "ConsoleInput"; if (flag) { if (currentEvent.type == EventType.KeyDown && currentEvent.keyCode == KeyCode.Return) { showLastLog.Value = true; commands.Add(inputCommand); commandIndex = commands.Count; if (!FindCommand(inputCommand)) { AutoCompleteInputCommand(); } ExecuteCommand(inputCommand); inputCommand = string.Empty; setFocus = true; } if (currentEvent.type == EventType.KeyDown) { if (currentEvent.keyCode == KeyCode.DownArrow && num2 > 0) { autoCompleteIndex++; updateAutoCompleteScrollView = true; } else if (currentEvent.keyCode == KeyCode.UpArrow && num2 > 0) { moveInputCursor = 1; autoCompleteIndex--; updateAutoCompleteScrollView = true; } else if (currentEvent.keyCode != KeyCode.Tab) { autoCompleteIndex = 0; updateAutoCompleteScrollView = true; } } } autoCompleteIndex = Helper.Repeat(autoCompleteIndex, autoCompleteList.Count); GUILayout.BeginHorizontal(); GUILayout.Space(4f); GUI.SetNextControlName("ConsoleInput"); GUI.color = Color.white; GUI.backgroundColor = Color.white; GUI.changed = false; if (currentEvent.type == EventType.KeyDown) { if (currentEvent.keyCode == showToggleKeyEditor.keyCode) { addInput = false; } else if (addInput) { inputCommand = GUILayout.TextField(inputCommand, GUILayout.Width(window.width - 8f - (float)((num + 4) * 2 + 18))); } else { addInput = true; } } else { GUILayout.TextField(inputCommand, GUILayout.Width(window.width - 8f - (float)((num + 4) * 2 + 18))); } if (GUI.changed && addInput) { if (inputCommand.Length >= 2 && inputCommand[0] == searchCommandPrefix) { LogEntry.search = inputCommand.Substring(1); LogEntry.ignoreCasesInSearch = ignoreCasesInSearch; CalcDraw(reset: true); } else if (LogEntry.search != string.Empty) { LogEntry.search = string.Empty; CalcDraw(reset: true); } } if (moveInputCursor != 0 && textEditor != null) { if (moveInputCursor == 1) { textEditor.MoveTextEnd(); } else if (moveInputCursor == -1) { textEditor.MoveTextStart(); } moveInputCursor = 0; } if (GUILayout.Button(Helper.GetGUIContent("Clear", "Clear all Logs"), GUILayout.Width(num))) { Clear(); } Helper.DrawShowButton(windowData, Helper.GetGUIContent("Last", "Scroll to last Log"), showLastLog, selectColor, num); Rect lastRect = GUILayoutUtility.GetLastRect(); lastRect.x += num + 7; lastRect.y += 9f; lastRect.width = 10f; lastRect.height = 10f; if (new Rect(lastRect.x, lastRect.y, 16f, 16f).Contains(currentEvent.mousePosition)) { GUI.color = Color.white; } else { GUI.color = Color.grey; } GUI.Label(lastRect, Helper.GetGUIContent(windowData.texCornerScale, "Resize console window")); GUI.color = Color.white; GUILayout.EndHorizontal(); if (commands.Count > 0 && num2 == 0) { if (currentEvent.keyCode == KeyCode.UpArrow && currentEvent.type == EventType.KeyUp) { commandIndex--; if (commandIndex < 0) { commandIndex = 0; } inputCommand = commands.items[commandIndex]; } else if (currentEvent.keyCode == KeyCode.DownArrow) { if (currentEvent.type == EventType.KeyUp) { commandIndex++; if (commandIndex > commands.Count - 1) { commandIndex = commands.Count - 1; inputCommand = string.Empty; } else { inputCommand = commands.items[commandIndex]; } } moveInputCursor = -1; } } if (flag) { GetAutoCompleteList(inputCommand); } else { ClearAutoCompleteList(); } if (currentEvent.type == EventType.Repaint && setFocus) { setFocus = false; GUI.FocusControl("ConsoleInput"); } } private void DrawAutoComplete() { Event current = Event.current; if (autoCompleteList.Count != oldAutoCompleteCount && current.type == EventType.Layout) { oldAutoCompleteCount = autoCompleteList.Count; updateAutoCompleteScrollView = true; } if (autoCompleteList.Count > 0 && autoCompleteList.Count == oldAutoCompleteCount) { rectAutoComplete = consoleWindow.rect; rectAutoComplete.y += rectAutoComplete.height; rectAutoComplete.height = Mathf.Min(autoCompleteList.Count * 25 + 2, 302); rectAutoComplete.width += 10f; GUI.skin = windowData.skinAutoComplete; GUILayout.Window(23423023, rectAutoComplete, DrawAutoComplete, GUIContent.none); GUI.skin = windowData.skin; } if (current.type == EventType.KeyDown && current.keyCode == KeyCode.Tab) { AutoCompleteInputCommand(); } } private void DrawAutoComplete(int windowId) { WindowManager.BeginRenderTextureGUI(); GUISkin skin = windowData.skin; GUI.backgroundColor = backgroundColor; GUI.Box(new Rect(0f, 0f, rectAutoComplete.width - 10f, rectAutoComplete.height), string.Empty); GUI.backgroundColor = Color.white; if (updateAutoCompleteScrollView) { updateAutoCompleteScrollView = false; autoCompleteScrollView.y = Mathf.Max((float)(autoCompleteIndex * 25) - rectAutoComplete.height / 2f, 0f); } autoCompleteScrollView = GUILayout.BeginScrollView(autoCompleteScrollView); float num = 0f; float num2 = 0f; float num3 = 0f; float num4 = 0f; for (int i = 0; i < autoCompleteList.Count; i++) { AutoComplete autoComplete = autoCompleteList.items[i]; CommandData commandData = autoComplete.commandData; float x = skin.button.CalcSize(Helper.GetGUIContent(autoComplete.command)).x; if (x > num) { num = x; } if (commandData.memberType == MemberType.Field || commandData.memberType == MemberType.Property) { object value = commandData.GetValue(); if (value != null) { x = skin.label.CalcSize(Helper.GetGUIContent(value.ToString())).x; if (x > num3) { num3 = x; } } } x = skin.label.CalcSize(Helper.GetGUIContent(commandData.syntax)).x; if (x > num2) { num2 = x; } int instanceCount = commandData.GetInstanceCount(); if (instanceCount > 0) { x = skin.label.CalcSize(Helper.GetGUIContent("Instances: " + instanceCount)).x; if (x > num4) { num4 = x; } } } num2 += 15f; if (num3 > 0f) { num3 += 15f; } if (num4 > 0f) { num4 += 15f; } GUILayout.Space(-2f); for (int j = 0; j < autoCompleteList.Count; j++) { AutoComplete autoComplete2 = autoCompleteList.items[j]; CommandData commandData2 = autoComplete2.commandData; string command = autoComplete2.command; if (j % 2 == 0) { Rect rect = GUILayoutUtility.GetRect(0f, 27f); rect.width = rectAutoComplete.width - 11f; rect.y += 2f; rect.height -= 2f; GUILayout.Space(-27f); GUI.backgroundColor = new Color(0.0675f, 0.0675f, 0.0675f, 1f); GUI.Box(rect, string.Empty); GUI.backgroundColor = Color.white; } GUILayout.BeginHorizontal(); GUI.backgroundColor = ((j == autoCompleteIndex) ? Color.green : Color.white); if (GUILayout.Button(command, GUILayout.Width(num))) { inputCommand = command; moveInputCursor = 1; } GUILayout.BeginVertical(); GUILayout.Space(7f); GUILayout.BeginHorizontal(); GUILayout.Label(commandData2.syntax, GUILayout.Width(num2)); if (num3 > 0f) { if (commandData2.memberType == MemberType.Field || commandData2.memberType == MemberType.Property) { object value2 = commandData2.GetValue(); if (value2 != null) { GUI.color = Color.green; GUILayout.Label(value2.ToString(), GUILayout.Width(num3)); GUI.color = Color.white; } else { GUILayout.Space(num3); } } else { GUILayout.Space(num3); } } if (num4 > 0f) { int instanceCount2 = commandData2.GetInstanceCount(); if (instanceCount2 > 0) { GUI.color = new Color(0.3f, 0.5f, 1f, 1f); GUILayout.Label("Instances: " + instanceCount2, GUILayout.Width(num4)); GUI.color = Color.white; } else { GUILayout.Space(num4); } } if (commandData2.consoleCommand != null && commandData2.consoleCommand.description != string.Empty) { GUI.color = Color.yellow; GUILayout.Label(commandData2.consoleCommand.description); GUI.color = Color.white; } GUILayout.EndHorizontal(); GUILayout.Space(-7f); GUILayout.EndVertical(); GUILayout.EndHorizontal(); } GUI.backgroundColor = Color.white; GUILayout.EndScrollView(); WindowManager.EndRenderTextureGUI(); } private void AutoCompleteInputCommand() { if (autoCompleteList.Count > 0) { inputCommand = inputCommand.TrimStart(' '); int num = IsRemoteCommand(ref inputCommand); string text = string.Empty; int num2 = inputCommand.IndexOf(' '); if (num2 != -1) { text = inputCommand.Substring(num2); } inputCommand = autoCompleteList.items[autoCompleteIndex].command + text; switch (num) { case 1: inputCommand = "#" + inputCommand; break; case 2: inputCommand = "$" + inputCommand; break; } if (inputCommand[inputCommand.Length - 1] == '.') { inputCommand = inputCommand.Substring(0, inputCommand.Length - 1); } moveInputCursor = 1; } } private void ClearAutoCompleteList() { lastAutoCompleteCommand = string.Empty; autoCompleteList.FastClear(); } private void GetAutoCompleteList(string command) { if (command == lastAutoCompleteCommand) { if (command == string.Empty && autoCompleteList.Count > 0) { ClearAutoCompleteList(); } return; } lastAutoCompleteCommand = command; ClearAutoCompleteList(); command = command.Trim(' '); if (command == string.Empty || command[0] == searchCommandPrefix) { return; } int num = command.IndexOf(" "); if (num != -1) { command = command.Substring(0, num); } IsRemoteCommand(ref command); if (command == string.Empty) { return; } if (command[0] == '?') { command = command.Substring(1); } string[] names = commandsTable.names; for (int i = 0; i < names.Length; i++) { if (!(ignoreCasesInAutoCompleteInput ? names[i].StartsWith(command, StringComparison.CurrentCultureIgnoreCase) : names[i].StartsWith(command))) { continue; } string text = names[i]; CommandData commandData = commandsTable.lookup[text]; if (commandData.consoleCommand == null) { if (accessLevel != AccessLevel.Admin) { continue; } bool flag = false; for (int j = i + 1; j < names.Length && (ignoreCasesInAutoCompleteInput ? names[j].StartsWith(text, StringComparison.CurrentCultureIgnoreCase) : names[j].StartsWith(text)); j++) { CommandData commandData2 = commandsTable.lookup[names[j]]; if (commandData2.consoleCommand != null && commandData2.consoleCommand.HasAccess(accessLevel) && commandData2.IsRegistered()) { flag = true; break; } } if (!flag) { continue; } } else if (!commandData.consoleCommand.HasAccess(accessLevel) || !commandData.IsRegistered()) { continue; } autoCompleteList.Add(new AutoComplete(text, commandData)); } } private static bool TryParse(Type t, FastQueue paramQueue, out object result) { bool valid = true; if (t == typeof(Vector2)) { Vector2 vector = default(Vector2); for (int i = 0; i < 2; i++) { object obj = ChangeType(typeof(float), paramQueue, ref valid); if (obj != null) { vector[i] = (float)obj; continue; } result = null; return false; } result = vector; } else if (t == typeof(Vector3)) { Vector3 vector2 = default(Vector3); for (int j = 0; j < 3; j++) { object obj2 = ChangeType(typeof(float), paramQueue, ref valid); if (obj2 != null) { vector2[j] = (float)obj2; continue; } result = null; return false; } result = vector2; } else if (t == typeof(Vector4)) { Vector4 vector3 = default(Vector4); for (int k = 0; k < 4; k++) { object obj3 = ChangeType(typeof(float), paramQueue, ref valid); if (obj3 != null) { vector3[k] = (float)obj3; continue; } result = null; return false; } result = vector3; } else if (t == typeof(Quaternion)) { Quaternion quaternion = default(Quaternion); for (int l = 0; l < 4; l++) { object obj4 = ChangeType(typeof(float), paramQueue, ref valid); if (obj4 != null) { quaternion[l] = (float)obj4; continue; } result = null; return false; } result = quaternion; } else { result = ChangeType(t, paramQueue, ref valid); } return valid; } private static object ChangeType(Type t, FastQueue paramQueue, ref bool valid) { if (paramQueue.Count == 0) { LogResultError("Not enough parameters"); valid = false; return null; } string text = paramQueue.Dequeue(); text = text.Trim(); if (t == typeof(string)) { return text; } if (t == typeof(bool)) { bool.TryParse(text, out var result); return result; } if (t == typeof(byte)) { byte.TryParse(text, out var result2); return result2; } if (t == typeof(sbyte)) { sbyte.TryParse(text, out var result3); return result3; } if (t == typeof(char)) { char.TryParse(text, out var result4); return result4; } if (t == typeof(decimal)) { decimal.TryParse(text, out var result5); return result5; } if (t == typeof(double)) { double.TryParse(text, out var result6); return result6; } if (t == typeof(float)) { float.TryParse(text, out var result7); return result7; } if (t == typeof(int)) { int.TryParse(text, out var result8); return result8; } if (t == typeof(uint)) { uint.TryParse(text, out var result9); return result9; } if (t == typeof(long)) { long.TryParse(text, out var result10); return result10; } if (t == typeof(ulong)) { ulong.TryParse(text, out var result11); return result11; } if (t == typeof(short)) { short.TryParse(text, out var result12); return result12; } if (t == typeof(ushort)) { ushort.TryParse(text, out var result13); return result13; } if (t.IsEnum) { try { return Enum.Parse(t, text, ignoreCase: true); } catch (Exception) { LogResultError("Cannot find '" + text + "'"); } } valid = false; return null; } } }