123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362 |
- using UnityEngine;
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Reflection;
- using System.Text;
- using Object = UnityEngine.Object;
- namespace IngameDebugConsole
- {
- public class ConsoleMethodInfo
- {
- public readonly MethodInfo method;
- public readonly Type[] parameterTypes;
- public readonly object instance;
- public readonly string command;
- public readonly string signature;
- public readonly string[] parameters;
- public ConsoleMethodInfo( MethodInfo method, Type[] parameterTypes, object instance, string command, string signature, string[] parameters )
- {
- this.method = method;
- this.parameterTypes = parameterTypes;
- this.instance = instance;
- this.command = command;
- this.signature = signature;
- this.parameters = parameters;
- }
- public bool IsValid()
- {
- if( !method.IsStatic && ( instance == null || instance.Equals( null ) ) )
- return false;
- return true;
- }
- }
- public static class DebugLogConsole
- {
- public delegate bool ParseFunction( string input, out object output );
-
- private static readonly List<ConsoleMethodInfo> methods = new List<ConsoleMethodInfo>();
- private static readonly List<ConsoleMethodInfo> matchingMethods = new List<ConsoleMethodInfo>( 4 );
-
- private static readonly Dictionary<Type, ParseFunction> parseFunctions = new Dictionary<Type, ParseFunction>()
- {
- { typeof( string ), ParseString },
- { typeof( bool ), ParseBool },
- { typeof( int ), ParseInt },
- { typeof( uint ), ParseUInt },
- { typeof( long ), ParseLong },
- { typeof( ulong ), ParseULong },
- { typeof( byte ), ParseByte },
- { typeof( sbyte ), ParseSByte },
- { typeof( short ), ParseShort },
- { typeof( ushort ), ParseUShort },
- { typeof( char ), ParseChar },
- { typeof( float ), ParseFloat },
- { typeof( double ), ParseDouble },
- { typeof( decimal ), ParseDecimal },
- { typeof( Vector2 ), ParseVector2 },
- { typeof( Vector3 ), ParseVector3 },
- { typeof( Vector4 ), ParseVector4 },
- { typeof( Quaternion ), ParseQuaternion },
- { typeof( Color ), ParseColor },
- { typeof( Color32 ), ParseColor32 },
- { typeof( Rect ), ParseRect },
- { typeof( RectOffset ), ParseRectOffset },
- { typeof( Bounds ), ParseBounds },
- { typeof( GameObject ), ParseGameObject },
- #if UNITY_2017_2_OR_NEWER
- { typeof( Vector2Int ), ParseVector2Int },
- { typeof( Vector3Int ), ParseVector3Int },
- { typeof( RectInt ), ParseRectInt },
- { typeof( BoundsInt ), ParseBoundsInt },
- #endif
- };
-
- private static readonly Dictionary<Type, string> typeReadableNames = new Dictionary<Type, string>()
- {
- { typeof( string ), "String" },
- { typeof( bool ), "Boolean" },
- { typeof( int ), "Integer" },
- { typeof( uint ), "Unsigned Integer" },
- { typeof( long ), "Long" },
- { typeof( ulong ), "Unsigned Long" },
- { typeof( byte ), "Byte" },
- { typeof( sbyte ), "Short Byte" },
- { typeof( short ), "Short" },
- { typeof( ushort ), "Unsigned Short" },
- { typeof( char ), "Char" },
- { typeof( float ), "Float" },
- { typeof( double ), "Double" },
- { typeof( decimal ), "Decimal" }
- };
-
- private static readonly List<string> commandArguments = new List<string>( 8 );
-
- private static readonly string[] inputDelimiters = new string[] { "\"\"", "''", "{}", "()", "[]" };
- static DebugLogConsole()
- {
- #if UNITY_EDITOR || !NETFX_CORE
-
- HashSet<Assembly> assemblies = new HashSet<Assembly> { Assembly.GetAssembly( typeof( DebugLogConsole ) )};
- try
- {
- assemblies.Add( Assembly.Load( "Assembly-CSharp" ));
- }
- catch { }
- foreach( var assembly in assemblies )
- {
- foreach( var type in assembly.GetExportedTypes() )
- {
- foreach( var method in type.GetMethods( BindingFlags.Static | BindingFlags.Public | BindingFlags.DeclaredOnly ) )
- {
- foreach( var attribute in method.GetCustomAttributes( typeof( ConsoleMethodAttribute ), false ) )
- {
- ConsoleMethodAttribute consoleMethod = attribute as ConsoleMethodAttribute;
- if( consoleMethod != null )
- AddCommand( consoleMethod.Command, consoleMethod.Description, method );
- }
- }
- }
- }
- #endif
- AddCommand( "help", "Prints all commands", LogAllCommands );
- AddCommand( "sysinfo", "Prints system information", LogSystemInfo );
- }
-
- public static void LogAllCommands()
- {
- int length = 25;
- for( int i = 0; i < methods.Count; i++ )
- {
- if( methods[i].IsValid() )
- length += 3 + methods[i].signature.Length;
- }
- StringBuilder stringBuilder = new StringBuilder( length );
- stringBuilder.Append( "Available commands:" );
- for( int i = 0; i < methods.Count; i++ )
- {
- if( methods[i].IsValid() )
- stringBuilder.Append( "\n- " ).Append( methods[i].signature );
- }
- Debug.Log( stringBuilder.Append( "\n" ).ToString() );
-
- if( DebugLogManager.Instance )
- DebugLogManager.Instance.ExpandLatestPendingLog();
- }
-
- public static void LogSystemInfo()
- {
- StringBuilder stringBuilder = new StringBuilder( 1024 );
- stringBuilder.Append( "Rig: " ).AppendSysInfoIfPresent( SystemInfo.deviceModel ).AppendSysInfoIfPresent( SystemInfo.processorType )
- .AppendSysInfoIfPresent( SystemInfo.systemMemorySize, "MB RAM" ).Append( SystemInfo.processorCount ).Append( " cores\n" );
- stringBuilder.Append( "OS: " ).Append( SystemInfo.operatingSystem ).Append( "\n" );
- stringBuilder.Append( "GPU: " ).Append( SystemInfo.graphicsDeviceName ).Append( " " ).Append( SystemInfo.graphicsMemorySize )
- .Append( "MB " ).Append( SystemInfo.graphicsDeviceVersion )
- .Append( SystemInfo.graphicsMultiThreaded ? " multi-threaded\n" : "\n" );
- stringBuilder.Append( "Data Path: " ).Append( Application.dataPath ).Append( "\n" );
- stringBuilder.Append( "Persistent Data Path: " ).Append( Application.persistentDataPath ).Append( "\n" );
- stringBuilder.Append( "StreamingAssets Path: " ).Append( Application.streamingAssetsPath ).Append( "\n" );
- stringBuilder.Append( "Temporary Cache Path: " ).Append( Application.temporaryCachePath ).Append( "\n" );
- stringBuilder.Append( "Device ID: " ).Append( SystemInfo.deviceUniqueIdentifier ).Append( "\n" );
- stringBuilder.Append( "Max Texture Size: " ).Append( SystemInfo.maxTextureSize ).Append( "\n" );
- #if UNITY_5_6_OR_NEWER
- stringBuilder.Append( "Max Cubemap Size: " ).Append( SystemInfo.maxCubemapSize ).Append( "\n" );
- #endif
- stringBuilder.Append( "Accelerometer: " ).Append( SystemInfo.supportsAccelerometer ? "supported\n" : "not supported\n" );
- stringBuilder.Append( "Gyro: " ).Append( SystemInfo.supportsGyroscope ? "supported\n" : "not supported\n" );
- stringBuilder.Append( "Location Service: " ).Append( SystemInfo.supportsLocationService ? "supported\n" : "not supported\n" );
- #if !UNITY_2019_1_OR_NEWER
- stringBuilder.Append( "Image Effects: " ).Append( SystemInfo.supportsImageEffects ? "supported\n" : "not supported\n" );
- stringBuilder.Append( "RenderToCubemap: " ).Append( SystemInfo.supportsRenderToCubemap ? "supported\n" : "not supported\n" );
- #endif
- stringBuilder.Append( "Compute Shaders: " ).Append( SystemInfo.supportsComputeShaders ? "supported\n" : "not supported\n" );
- stringBuilder.Append( "Shadows: " ).Append( SystemInfo.supportsShadows ? "supported\n" : "not supported\n" );
- stringBuilder.Append( "Instancing: " ).Append( SystemInfo.supportsInstancing ? "supported\n" : "not supported\n" );
- stringBuilder.Append( "Motion Vectors: " ).Append( SystemInfo.supportsMotionVectors ? "supported\n" : "not supported\n" );
- stringBuilder.Append( "3D Textures: " ).Append( SystemInfo.supports3DTextures ? "supported\n" : "not supported\n" );
- #if UNITY_5_6_OR_NEWER
- stringBuilder.Append( "3D Render Textures: " ).Append( SystemInfo.supports3DRenderTextures ? "supported\n" : "not supported\n" );
- #endif
- stringBuilder.Append( "2D Array Textures: " ).Append( SystemInfo.supports2DArrayTextures ? "supported\n" : "not supported\n" );
- stringBuilder.Append( "Cubemap Array Textures: " ).Append( SystemInfo.supportsCubemapArrayTextures ? "supported" : "not supported" );
- Debug.Log( stringBuilder.Append( "\n" ).ToString() );
-
- if( DebugLogManager.Instance )
- DebugLogManager.Instance.ExpandLatestPendingLog();
- }
- private static StringBuilder AppendSysInfoIfPresent( this StringBuilder sb, string info, string postfix = null )
- {
- if( info != SystemInfo.unsupportedIdentifier )
- {
- sb.Append( info );
- if( postfix != null )
- sb.Append( postfix );
- sb.Append( " " );
- }
- return sb;
- }
- private static StringBuilder AppendSysInfoIfPresent( this StringBuilder sb, int info, string postfix = null )
- {
- if( info > 0 )
- {
- sb.Append( info );
- if( postfix != null )
- sb.Append( postfix );
- sb.Append( " " );
- }
- return sb;
- }
-
- public static void AddCustomParameterType( Type type, ParseFunction parseFunction, string typeReadableName = null )
- {
- if( type == null )
- {
- Debug.LogError( "Parameter type can't be null!" );
- return;
- }
- else if( parseFunction == null )
- {
- Debug.LogError( "Parameter parseFunction can't be null!" );
- return;
- }
- parseFunctions[type] = parseFunction;
- if( !string.IsNullOrEmpty( typeReadableName ) )
- typeReadableNames[type] = typeReadableName;
- }
-
- public static void RemoveCustomParameterType( Type type )
- {
- parseFunctions.Remove( type );
- typeReadableNames.Remove( type );
- }
-
- public static void AddCommandInstance( string command, string description, string methodName, object instance )
- {
- if( instance == null )
- {
- Debug.LogError( "Instance can't be null!" );
- return;
- }
- AddCommand( command, description, methodName, instance.GetType(), instance );
- }
-
- public static void AddCommandStatic( string command, string description, string methodName, Type ownerType )
- {
- AddCommand( command, description, methodName, ownerType );
- }
-
- public static void AddCommand( string command, string description, Action method ) { AddCommand( command, description, method.Method, method.Target ); }
- public static void AddCommand<T1>( string command, string description, Action<T1> method ) { AddCommand( command, description, method.Method, method.Target ); }
- public static void AddCommand<T1>( string command, string description, Func<T1> method ) { AddCommand( command, description, method.Method, method.Target ); }
- public static void AddCommand<T1, T2>( string command, string description, Action<T1, T2> method ) { AddCommand( command, description, method.Method, method.Target ); }
- public static void AddCommand<T1, T2>( string command, string description, Func<T1, T2> method ) { AddCommand( command, description, method.Method, method.Target ); }
- public static void AddCommand<T1, T2, T3>( string command, string description, Action<T1, T2, T3> method ) { AddCommand( command, description, method.Method, method.Target ); }
- public static void AddCommand<T1, T2, T3>( string command, string description, Func<T1, T2, T3> method ) { AddCommand( command, description, method.Method, method.Target ); }
- public static void AddCommand<T1, T2, T3, T4>( string command, string description, Action<T1, T2, T3, T4> method ) { AddCommand( command, description, method.Method, method.Target ); }
- public static void AddCommand<T1, T2, T3, T4>( string command, string description, Func<T1, T2, T3, T4> method ) { AddCommand( command, description, method.Method, method.Target ); }
- public static void AddCommand<T1, T2, T3, T4, T5>( string command, string description, Func<T1, T2, T3, T4, T5> method ) { AddCommand( command, description, method.Method, method.Target ); }
- public static void AddCommand( string command, string description, Delegate method ) { AddCommand( command, description, method.Method, method.Target ); }
-
- private static void AddCommand( string command, string description, string methodName, Type ownerType, object instance = null )
- {
-
- MethodInfo method = ownerType.GetMethod( methodName, BindingFlags.Public | BindingFlags.NonPublic | ( instance != null ? BindingFlags.Instance : BindingFlags.Static ) );
- if( method == null )
- {
- Debug.LogError( methodName + " does not exist in " + ownerType );
- return;
- }
- AddCommand( command, description, method, instance );
- }
- private static void AddCommand( string command, string description, MethodInfo method, object instance = null )
- {
- if( string.IsNullOrEmpty( command ) )
- {
- Debug.LogError( "Command name can't be empty!" );
- return;
- }
- command = command.Trim();
- if( command.IndexOf( ' ' ) >= 0 )
- {
- Debug.LogError( "Command name can't contain whitespace: " + command );
- return;
- }
-
- ParameterInfo[] parameters = method.GetParameters();
- if( parameters == null )
- parameters = new ParameterInfo[0];
-
- Type[] parameterTypes = new Type[parameters.Length];
- for( int i = 0; i < parameters.Length; i++ )
- {
- if( parameters[i].ParameterType.IsByRef )
- {
- Debug.LogError( "Command can't have 'out' or 'ref' parameters" );
- return;
- }
- Type parameterType = parameters[i].ParameterType;
- if( parseFunctions.ContainsKey( parameterType ) || typeof( Component ).IsAssignableFrom( parameterType ) || parameterType.IsEnum || IsSupportedArrayType( parameterType ) )
- parameterTypes[i] = parameterType;
- else
- {
- Debug.LogError( string.Concat( "Parameter ", parameters[i].Name, "'s Type ", parameterType, " isn't supported" ) );
- return;
- }
- }
- int commandIndex = FindCommandIndex( command );
- if( commandIndex < 0 )
- commandIndex = ~commandIndex;
- else
- {
- int commandFirstIndex = commandIndex;
- int commandLastIndex = commandIndex;
- while( commandFirstIndex > 0 && methods[commandFirstIndex - 1].command == command )
- commandFirstIndex--;
- while( commandLastIndex < methods.Count - 1 && methods[commandLastIndex + 1].command == command )
- commandLastIndex++;
- commandIndex = commandFirstIndex;
- for( int i = commandFirstIndex; i <= commandLastIndex; i++ )
- {
- int parameterCountDiff = methods[i].parameterTypes.Length - parameterTypes.Length;
- if( parameterCountDiff <= 0 )
- {
-
-
-
- commandIndex = i + 1;
-
- if( parameterCountDiff == 0 )
- {
- int j = 0;
- while( j < parameterTypes.Length && parameterTypes[j] == methods[i].parameterTypes[j] )
- j++;
- if( j >= parameterTypes.Length )
- {
- commandIndex = i;
- commandLastIndex--;
- methods.RemoveAt( i-- );
- continue;
- }
- }
- }
- }
- }
-
- for( int i = methods.Count - 1; i >= 0; i-- )
- {
- if( !methods[i].IsValid() )
- {
- methods.RemoveAt( i );
- continue;
- }
- if( methods[i].command == command && methods[i].parameterTypes.Length == parameterTypes.Length )
- {
- int j = 0;
- while( j < parameterTypes.Length && parameterTypes[j] == methods[i].parameterTypes[j] )
- j++;
- if( j >= parameterTypes.Length )
- {
- methods.RemoveAt( i );
- break;
- }
- }
- }
-
- StringBuilder methodSignature = new StringBuilder( 256 );
- string[] parameterSignatures = new string[parameterTypes.Length];
- methodSignature.Append( command ).Append( ": " );
- if( !string.IsNullOrEmpty( description ) )
- methodSignature.Append( description ).Append( " -> " );
- methodSignature.Append( method.DeclaringType.ToString() ).Append( "." ).Append( method.Name ).Append( "(" );
- for( int i = 0; i < parameterTypes.Length; i++ )
- {
- int parameterSignatureStartIndex = methodSignature.Length;
- methodSignature.Append( GetTypeReadableName( parameterTypes[i] ) ).Append( " " ).Append( parameters[i].Name );
- if( i < parameterTypes.Length - 1 )
- methodSignature.Append( ", " );
- parameterSignatures[i] = methodSignature.ToString( parameterSignatureStartIndex, methodSignature.Length - parameterSignatureStartIndex );
- }
- methodSignature.Append( ")" );
- Type returnType = method.ReturnType;
- if( returnType != typeof( void ) )
- methodSignature.Append( " : " ).Append( GetTypeReadableName( returnType ) );
- methods.Insert( commandIndex, new ConsoleMethodInfo( method, parameterTypes, instance, command, methodSignature.ToString(), parameterSignatures ) );
- }
-
- public static void RemoveCommand( string command )
- {
- if( !string.IsNullOrEmpty( command ) )
- {
- for( int i = methods.Count - 1; i >= 0; i-- )
- {
- if( methods[i].command == command )
- methods.RemoveAt( i );
- }
- }
- }
-
- public static void RemoveCommand( Action method ) { RemoveCommand( method.Method ); }
- public static void RemoveCommand<T1>( Action<T1> method ) { RemoveCommand( method.Method ); }
- public static void RemoveCommand<T1>( Func<T1> method ) { RemoveCommand( method.Method ); }
- public static void RemoveCommand<T1, T2>( Action<T1, T2> method ) { RemoveCommand( method.Method ); }
- public static void RemoveCommand<T1, T2>( Func<T1, T2> method ) { RemoveCommand( method.Method ); }
- public static void RemoveCommand<T1, T2, T3>( Action<T1, T2, T3> method ) { RemoveCommand( method.Method ); }
- public static void RemoveCommand<T1, T2, T3>( Func<T1, T2, T3> method ) { RemoveCommand( method.Method ); }
- public static void RemoveCommand<T1, T2, T3, T4>( Action<T1, T2, T3, T4> method ) { RemoveCommand( method.Method ); }
- public static void RemoveCommand<T1, T2, T3, T4>( Func<T1, T2, T3, T4> method ) { RemoveCommand( method.Method ); }
- public static void RemoveCommand<T1, T2, T3, T4, T5>( Func<T1, T2, T3, T4, T5> method ) { RemoveCommand( method.Method ); }
- public static void RemoveCommand( Delegate method ) { RemoveCommand( method.Method ); }
- public static void RemoveCommand( MethodInfo method )
- {
- if( method != null )
- {
- for( int i = methods.Count - 1; i >= 0; i-- )
- {
- if( methods[i].method == method )
- methods.RemoveAt( i );
- }
- }
- }
-
- public static string GetAutoCompleteCommand( string commandStart )
- {
- int commandIndex = FindCommandIndex( commandStart );
- if( commandIndex < 0 )
- commandIndex = ~commandIndex;
- string result = null;
- for( int i = commandIndex; i >= 0 && methods[i].command.StartsWith( commandStart ); i-- )
- result = methods[i].command;
- if( result == null )
- {
- for( int i = commandIndex + 1; i < methods.Count && methods[i].command.StartsWith( commandStart ); i++ )
- result = methods[i].command;
- }
- return result;
- }
-
- public static void ExecuteCommand( string command )
- {
- if( command == null )
- return;
- command = command.Trim();
- if( command.Length == 0 )
- return;
-
- commandArguments.Clear();
- FetchArgumentsFromCommand( command, commandArguments );
-
- matchingMethods.Clear();
- bool parameterCountMismatch = false;
- int commandIndex = FindCommandIndex( commandArguments[0] );
- if( commandIndex >= 0 )
- {
- string _command = commandArguments[0];
- int commandLastIndex = commandIndex;
- while( commandIndex > 0 && methods[commandIndex - 1].command == _command )
- commandIndex--;
- while( commandLastIndex < methods.Count - 1 && methods[commandLastIndex + 1].command == _command )
- commandLastIndex++;
- while( commandIndex <= commandLastIndex )
- {
- if( !methods[commandIndex].IsValid() )
- {
- methods.RemoveAt( commandIndex );
- commandLastIndex--;
- }
- else
- {
-
- if( methods[commandIndex].parameterTypes.Length == commandArguments.Count - 1 )
- matchingMethods.Add( methods[commandIndex] );
- else
- parameterCountMismatch = true;
- commandIndex++;
- }
- }
- }
- if( matchingMethods.Count == 0 )
- {
- if( parameterCountMismatch )
- Debug.LogWarning( string.Concat( "ERROR: ", commandArguments[0], " doesn't take ", commandArguments.Count - 1, " parameter(s)" ) );
- else
- Debug.LogWarning( "ERROR: can't find command: " + commandArguments[0] );
- return;
- }
- ConsoleMethodInfo methodToExecute = null;
- object[] parameters = new object[commandArguments.Count - 1];
- string errorMessage = null;
- for( int i = 0; i < matchingMethods.Count && methodToExecute == null; i++ )
- {
- ConsoleMethodInfo methodInfo = matchingMethods[i];
-
- bool success = true;
- for( int j = 0; j < methodInfo.parameterTypes.Length && success; j++ )
- {
- try
- {
- string argument = commandArguments[j + 1];
- Type parameterType = methodInfo.parameterTypes[j];
- object val;
- if( ParseArgument( argument, parameterType, out val ) )
- parameters[j] = val;
- else
- {
- success = false;
- errorMessage = string.Concat( "ERROR: couldn't parse ", argument, " to ", GetTypeReadableName( parameterType ) );
- }
- }
- catch( Exception e )
- {
- success = false;
- errorMessage = "ERROR: " + e.ToString();
- }
- }
- if( success )
- methodToExecute = methodInfo;
- }
- if( methodToExecute == null )
- Debug.LogWarning( !string.IsNullOrEmpty( errorMessage ) ? errorMessage : "ERROR: something went wrong" );
- else
- {
- Debug.Log( "Executing command: " + commandArguments[0] );
-
- object result = methodToExecute.method.Invoke( methodToExecute.instance, parameters );
- if( methodToExecute.method.ReturnType != typeof( void ) )
- {
-
- if( result == null || result.Equals( null ) )
- Debug.Log( "Value returned: null" );
- else
- Debug.Log( "Value returned: " + result.ToString() );
- }
- }
- }
- public static void FetchArgumentsFromCommand( string command, List<string> commandArguments )
- {
- for( int i = 0; i < command.Length; i++ )
- {
- if( char.IsWhiteSpace( command[i] ) )
- continue;
- int delimiterIndex = IndexOfDelimiterGroup( command[i] );
- if( delimiterIndex >= 0 )
- {
- int endIndex = IndexOfDelimiterGroupEnd( command, delimiterIndex, i + 1 );
- commandArguments.Add( command.Substring( i + 1, endIndex - i - 1 ) );
- i = ( endIndex < command.Length - 1 && command[endIndex + 1] == ',' ) ? endIndex + 1 : endIndex;
- }
- else
- {
- int endIndex = IndexOfChar( command, ' ', i + 1 );
- commandArguments.Add( command.Substring( i, command[endIndex - 1] == ',' ? endIndex - 1 - i : endIndex - i ) );
- i = endIndex;
- }
- }
- }
-
-
-
-
- internal static void GetCommandSuggestions( string command, List<ConsoleMethodInfo> matchingCommands, List<int> caretIndexIncrements, ref string commandName, out int numberOfParameters )
- {
- bool commandNameCalculated = false;
- bool commandNameFullyTyped = false;
- numberOfParameters = -1;
- for( int i = 0; i < command.Length; i++ )
- {
- if( char.IsWhiteSpace( command[i] ) )
- continue;
- int delimiterIndex = IndexOfDelimiterGroup( command[i] );
- if( delimiterIndex >= 0 )
- {
- int endIndex = IndexOfDelimiterGroupEnd( command, delimiterIndex, i + 1 );
- if( !commandNameCalculated )
- {
- commandNameCalculated = true;
- commandNameFullyTyped = command.Length > endIndex;
- int commandNameLength = endIndex - i - 1;
- if( commandName == null || commandNameLength == 0 || commandName.Length != commandNameLength || command.IndexOf( commandName, i + 1, commandNameLength ) != i + 1 )
- commandName = command.Substring( i + 1, commandNameLength );
- }
- i = ( endIndex < command.Length - 1 && command[endIndex + 1] == ',' ) ? endIndex + 1 : endIndex;
- caretIndexIncrements.Add( i + 1 );
- }
- else
- {
- int endIndex = IndexOfChar( command, ' ', i + 1 );
- if( !commandNameCalculated )
- {
- commandNameCalculated = true;
- commandNameFullyTyped = command.Length > endIndex;
- int commandNameLength = command[endIndex - 1] == ',' ? endIndex - 1 - i : endIndex - i;
- if( commandName == null || commandNameLength == 0 || commandName.Length != commandNameLength || command.IndexOf( commandName, i, commandNameLength ) != i )
- commandName = command.Substring( i, commandNameLength );
- }
- i = endIndex;
- caretIndexIncrements.Add( i );
- }
- numberOfParameters++;
- }
- if( !commandNameCalculated )
- commandName = string.Empty;
- if( !string.IsNullOrEmpty( commandName ) )
- {
- int commandIndex = FindCommandIndex( commandName );
- if( commandIndex < 0 )
- commandIndex = ~commandIndex;
- int commandLastIndex = commandIndex;
- if( !commandNameFullyTyped )
- {
-
- if( commandIndex < methods.Count && methods[commandIndex].command.StartsWith( commandName ) )
- {
- while( commandIndex > 0 && methods[commandIndex - 1].command.StartsWith( commandName ) )
- commandIndex--;
- while( commandLastIndex < methods.Count - 1 && methods[commandLastIndex + 1].command.StartsWith( commandName ) )
- commandLastIndex++;
- }
- else
- commandLastIndex = -1;
- }
- else
- {
-
- if( commandIndex < methods.Count && methods[commandIndex].command == commandName )
- {
- while( commandIndex > 0 && methods[commandIndex - 1].command == commandName )
- commandIndex--;
- while( commandLastIndex < methods.Count - 1 && methods[commandLastIndex + 1].command == commandName )
- commandLastIndex++;
- }
- else
- commandLastIndex = -1;
- }
- for( ; commandIndex <= commandLastIndex; commandIndex++ )
- {
- if( methods[commandIndex].parameterTypes.Length >= numberOfParameters )
- matchingCommands.Add( methods[commandIndex] );
- }
- }
- }
-
- private static int IndexOfDelimiterGroup( char c )
- {
- for( int i = 0; i < inputDelimiters.Length; i++ )
- {
- if( c == inputDelimiters[i][0] )
- return i;
- }
- return -1;
- }
- private static int IndexOfDelimiterGroupEnd( string command, int delimiterIndex, int startIndex )
- {
- char startChar = inputDelimiters[delimiterIndex][0];
- char endChar = inputDelimiters[delimiterIndex][1];
-
- int depth = 1;
- for( int i = startIndex; i < command.Length; i++ )
- {
- char c = command[i];
- if( c == endChar && --depth <= 0 )
- return i;
- else if( c == startChar )
- depth++;
- }
- return command.Length;
- }
-
- private static int IndexOfChar( string command, char c, int startIndex )
- {
- int result = command.IndexOf( c, startIndex );
- if( result < 0 )
- result = command.Length;
- return result;
- }
-
- private static int FindCommandIndex( string command )
- {
- int min = 0;
- int max = methods.Count - 1;
- while( min <= max )
- {
- int mid = ( min + max ) / 2;
- int comparison = command.CompareTo( methods[mid].command );
- if( comparison == 0 )
- return mid;
- else if( comparison < 0 )
- max = mid - 1;
- else
- min = mid + 1;
- }
- return ~min;
- }
- public static bool IsSupportedArrayType( Type type )
- {
- if( type.IsArray )
- {
- if( type.GetArrayRank() != 1 )
- return false;
- type = type.GetElementType();
- }
- else if( type.IsGenericType )
- {
- if( type.GetGenericTypeDefinition() != typeof( List<> ) )
- return false;
- type = type.GetGenericArguments()[0];
- }
- else
- return false;
- return parseFunctions.ContainsKey( type ) || typeof( Component ).IsAssignableFrom( type ) || type.IsEnum;
- }
- public static string GetTypeReadableName( Type type )
- {
- string result;
- if( typeReadableNames.TryGetValue( type, out result ) )
- return result;
- if( IsSupportedArrayType( type ) )
- {
- Type elementType = type.IsArray ? type.GetElementType() : type.GetGenericArguments()[0];
- if( typeReadableNames.TryGetValue( elementType, out result ) )
- return result + "[]";
- else
- return elementType.Name + "[]";
- }
- return type.Name;
- }
- public static bool ParseArgument( string input, Type argumentType, out object output )
- {
- ParseFunction parseFunction;
- if( parseFunctions.TryGetValue( argumentType, out parseFunction ) )
- return parseFunction( input, out output );
- else if( typeof( Component ).IsAssignableFrom( argumentType ) )
- return ParseComponent( input, argumentType, out output );
- else if( argumentType.IsEnum )
- return ParseEnum( input, argumentType, out output );
- else if( IsSupportedArrayType( argumentType ) )
- return ParseArray( input, argumentType, out output );
- else
- {
- output = null;
- return false;
- }
- }
- public static bool ParseString( string input, out object output )
- {
- output = input;
- return true;
- }
- public static bool ParseBool( string input, out object output )
- {
- if( input == "1" || input.ToLowerInvariant() == "true" )
- {
- output = true;
- return true;
- }
- if( input == "0" || input.ToLowerInvariant() == "false" )
- {
- output = false;
- return true;
- }
- output = false;
- return false;
- }
- public static bool ParseInt( string input, out object output )
- {
- int value;
- bool result = int.TryParse( input, out value );
- output = value;
- return result;
- }
- public static bool ParseUInt( string input, out object output )
- {
- uint value;
- bool result = uint.TryParse( input, out value );
- output = value;
- return result;
- }
- public static bool ParseLong( string input, out object output )
- {
- long value;
- bool result = long.TryParse( !input.EndsWith( "L", StringComparison.OrdinalIgnoreCase ) ? input : input.Substring( 0, input.Length - 1 ), out value );
- output = value;
- return result;
- }
- public static bool ParseULong( string input, out object output )
- {
- ulong value;
- bool result = ulong.TryParse( !input.EndsWith( "L", StringComparison.OrdinalIgnoreCase ) ? input : input.Substring( 0, input.Length - 1 ), out value );
- output = value;
- return result;
- }
- public static bool ParseByte( string input, out object output )
- {
- byte value;
- bool result = byte.TryParse( input, out value );
- output = value;
- return result;
- }
- public static bool ParseSByte( string input, out object output )
- {
- sbyte value;
- bool result = sbyte.TryParse( input, out value );
- output = value;
- return result;
- }
- public static bool ParseShort( string input, out object output )
- {
- short value;
- bool result = short.TryParse( input, out value );
- output = value;
- return result;
- }
- public static bool ParseUShort( string input, out object output )
- {
- ushort value;
- bool result = ushort.TryParse( input, out value );
- output = value;
- return result;
- }
- public static bool ParseChar( string input, out object output )
- {
- char value;
- bool result = char.TryParse( input, out value );
- output = value;
- return result;
- }
- public static bool ParseFloat( string input, out object output )
- {
- float value;
- bool result = float.TryParse( !input.EndsWith( "f", StringComparison.OrdinalIgnoreCase ) ? input : input.Substring( 0, input.Length - 1 ), out value );
- output = value;
- return result;
- }
- public static bool ParseDouble( string input, out object output )
- {
- double value;
- bool result = double.TryParse( !input.EndsWith( "f", StringComparison.OrdinalIgnoreCase ) ? input : input.Substring( 0, input.Length - 1 ), out value );
- output = value;
- return result;
- }
- public static bool ParseDecimal( string input, out object output )
- {
- decimal value;
- bool result = decimal.TryParse( !input.EndsWith( "f", StringComparison.OrdinalIgnoreCase ) ? input : input.Substring( 0, input.Length - 1 ), out value );
- output = value;
- return result;
- }
- public static bool ParseVector2( string input, out object output )
- {
- return ParseVector( input, typeof( Vector2 ), out output );
- }
- public static bool ParseVector3( string input, out object output )
- {
- return ParseVector( input, typeof( Vector3 ), out output );
- }
- public static bool ParseVector4( string input, out object output )
- {
- return ParseVector( input, typeof( Vector4 ), out output );
- }
- public static bool ParseQuaternion( string input, out object output )
- {
- return ParseVector( input, typeof( Quaternion ), out output );
- }
- public static bool ParseColor( string input, out object output )
- {
- return ParseVector( input, typeof( Color ), out output );
- }
- public static bool ParseColor32( string input, out object output )
- {
- return ParseVector( input, typeof( Color32 ), out output );
- }
- public static bool ParseRect( string input, out object output )
- {
- return ParseVector( input, typeof( Rect ), out output );
- }
- public static bool ParseRectOffset( string input, out object output )
- {
- return ParseVector( input, typeof( RectOffset ), out output );
- }
- public static bool ParseBounds( string input, out object output )
- {
- return ParseVector( input, typeof( Bounds ), out output );
- }
- #if UNITY_2017_2_OR_NEWER
- public static bool ParseVector2Int( string input, out object output )
- {
- return ParseVector( input, typeof( Vector2Int ), out output );
- }
- public static bool ParseVector3Int( string input, out object output )
- {
- return ParseVector( input, typeof( Vector3Int ), out output );
- }
- public static bool ParseRectInt( string input, out object output )
- {
- return ParseVector( input, typeof( RectInt ), out output );
- }
- public static bool ParseBoundsInt( string input, out object output )
- {
- return ParseVector( input, typeof( BoundsInt ), out output );
- }
- #endif
- public static bool ParseGameObject( string input, out object output )
- {
- output = input == "null" ? null : GameObject.Find( input );
- return true;
- }
- public static bool ParseComponent( string input, Type componentType, out object output )
- {
- GameObject gameObject = input == "null" ? null : GameObject.Find( input );
- output = gameObject ? gameObject.GetComponent( componentType ) : null;
- return true;
- }
- public static bool ParseEnum( string input, Type enumType, out object output )
- {
- const int NONE = 0, OR = 1, AND = 2;
- int outputInt = 0;
- int operation = 0;
- for( int i = 0; i < input.Length; i++ )
- {
- string enumStr;
- int orIndex = input.IndexOf( '|', i );
- int andIndex = input.IndexOf( '&', i );
- if( orIndex < 0 )
- enumStr = input.Substring( i, ( andIndex < 0 ? input.Length : andIndex ) - i ).Trim();
- else
- enumStr = input.Substring( i, ( andIndex < 0 ? orIndex : Mathf.Min( andIndex, orIndex ) ) - i ).Trim();
- int value;
- if( !int.TryParse( enumStr, out value ) )
- {
- if( Enum.IsDefined( enumType, enumStr ) )
- value = Convert.ToInt32( Enum.Parse( enumType, enumStr ) );
- else
- {
- output = null;
- return false;
- }
- }
- if( operation == NONE )
- outputInt = value;
- else if( operation == OR )
- outputInt |= value;
- else
- outputInt &= value;
- if( orIndex >= 0 )
- {
- if( andIndex > orIndex )
- {
- operation = AND;
- i = andIndex;
- }
- else
- {
- operation = OR;
- i = orIndex;
- }
- }
- else if( andIndex >= 0 )
- {
- operation = AND;
- i = andIndex;
- }
- else
- i = input.Length;
- }
- output = Enum.ToObject( enumType, outputInt );
- return true;
- }
- public static bool ParseArray( string input, Type arrayType, out object output )
- {
- List<string> valuesToParse = new List<string>( 2 );
- FetchArgumentsFromCommand( input, valuesToParse );
- IList result = (IList) Activator.CreateInstance( arrayType, new object[1] { valuesToParse.Count } );
- output = result;
- if( arrayType.IsArray )
- {
- Type elementType = arrayType.GetElementType();
- for( int i = 0; i < valuesToParse.Count; i++ )
- {
- object obj;
- if( !ParseArgument( valuesToParse[i], elementType, out obj ) )
- return false;
- result[i] = obj;
- }
- }
- else
- {
- Type elementType = arrayType.GetGenericArguments()[0];
- for( int i = 0; i < valuesToParse.Count; i++ )
- {
- object obj;
- if( !ParseArgument( valuesToParse[i], elementType, out obj ) )
- return false;
- result.Add( obj );
- }
- }
- return true;
- }
-
- private static bool ParseVector( string input, Type vectorType, out object output )
- {
- List<string> tokens = new List<string>( input.Replace( ',', ' ' ).Trim().Split( ' ' ) );
- for( int i = tokens.Count - 1; i >= 0; i-- )
- {
- tokens[i] = tokens[i].Trim();
- if( tokens[i].Length == 0 )
- tokens.RemoveAt( i );
- }
- float[] tokenValues = new float[tokens.Count];
- for( int i = 0; i < tokens.Count; i++ )
- {
- object val;
- if( !ParseFloat( tokens[i], out val ) )
- {
- if( vectorType == typeof( Vector3 ) )
- output = Vector3.zero;
- else if( vectorType == typeof( Vector2 ) )
- output = Vector2.zero;
- else
- output = Vector4.zero;
- return false;
- }
- tokenValues[i] = (float) val;
- }
- if( vectorType == typeof( Vector3 ) )
- {
- Vector3 result = Vector3.zero;
- for( int i = 0; i < tokenValues.Length && i < 3; i++ )
- result[i] = tokenValues[i];
- output = result;
- }
- else if( vectorType == typeof( Vector2 ) )
- {
- Vector2 result = Vector2.zero;
- for( int i = 0; i < tokenValues.Length && i < 2; i++ )
- result[i] = tokenValues[i];
- output = result;
- }
- else if( vectorType == typeof( Vector4 ) )
- {
- Vector4 result = Vector4.zero;
- for( int i = 0; i < tokenValues.Length && i < 4; i++ )
- result[i] = tokenValues[i];
- output = result;
- }
- else if( vectorType == typeof( Quaternion ) )
- {
- Quaternion result = Quaternion.identity;
- for( int i = 0; i < tokenValues.Length && i < 4; i++ )
- result[i] = tokenValues[i];
- output = result;
- }
- else if( vectorType == typeof( Color ) )
- {
- Color result = Color.black;
- for( int i = 0; i < tokenValues.Length && i < 4; i++ )
- result[i] = tokenValues[i];
- output = result;
- }
- else if( vectorType == typeof( Color32 ) )
- {
- Color32 result = new Color32( 0, 0, 0, 255 );
- if( tokenValues.Length > 0 )
- result.r = (byte) Mathf.RoundToInt( tokenValues[0] );
- if( tokenValues.Length > 1 )
- result.g = (byte) Mathf.RoundToInt( tokenValues[1] );
- if( tokenValues.Length > 2 )
- result.b = (byte) Mathf.RoundToInt( tokenValues[2] );
- if( tokenValues.Length > 3 )
- result.a = (byte) Mathf.RoundToInt( tokenValues[3] );
- output = result;
- }
- else if( vectorType == typeof( Rect ) )
- {
- Rect result = Rect.zero;
- if( tokenValues.Length > 0 )
- result.x = tokenValues[0];
- if( tokenValues.Length > 1 )
- result.y = tokenValues[1];
- if( tokenValues.Length > 2 )
- result.width = tokenValues[2];
- if( tokenValues.Length > 3 )
- result.height = tokenValues[3];
- output = result;
- }
- else if( vectorType == typeof( RectOffset ) )
- {
- RectOffset result = new RectOffset();
- if( tokenValues.Length > 0 )
- result.left = Mathf.RoundToInt( tokenValues[0] );
- if( tokenValues.Length > 1 )
- result.right = Mathf.RoundToInt( tokenValues[1] );
- if( tokenValues.Length > 2 )
- result.top = Mathf.RoundToInt( tokenValues[2] );
- if( tokenValues.Length > 3 )
- result.bottom = Mathf.RoundToInt( tokenValues[3] );
- output = result;
- }
- else if( vectorType == typeof( Bounds ) )
- {
- Vector3 center = Vector3.zero;
- for( int i = 0; i < tokenValues.Length && i < 3; i++ )
- center[i] = tokenValues[i];
- Vector3 size = Vector3.zero;
- for( int i = 3; i < tokenValues.Length && i < 6; i++ )
- size[i - 3] = tokenValues[i];
- output = new Bounds( center, size );
- }
- #if UNITY_2017_2_OR_NEWER
- else if( vectorType == typeof( Vector3Int ) )
- {
- Vector3Int result = Vector3Int.zero;
- for( int i = 0; i < tokenValues.Length && i < 3; i++ )
- result[i] = Mathf.RoundToInt( tokenValues[i] );
- output = result;
- }
- else if( vectorType == typeof( Vector2Int ) )
- {
- Vector2Int result = Vector2Int.zero;
- for( int i = 0; i < tokenValues.Length && i < 2; i++ )
- result[i] = Mathf.RoundToInt( tokenValues[i] );
- output = result;
- }
- else if( vectorType == typeof( RectInt ) )
- {
- RectInt result = new RectInt();
- if( tokenValues.Length > 0 )
- result.x = Mathf.RoundToInt( tokenValues[0] );
- if( tokenValues.Length > 1 )
- result.y = Mathf.RoundToInt( tokenValues[1] );
- if( tokenValues.Length > 2 )
- result.width = Mathf.RoundToInt( tokenValues[2] );
- if( tokenValues.Length > 3 )
- result.height = Mathf.RoundToInt( tokenValues[3] );
- output = result;
- }
- else if( vectorType == typeof( BoundsInt ) )
- {
- Vector3Int center = Vector3Int.zero;
- for( int i = 0; i < tokenValues.Length && i < 3; i++ )
- center[i] = Mathf.RoundToInt( tokenValues[i] );
- Vector3Int size = Vector3Int.zero;
- for( int i = 3; i < tokenValues.Length && i < 6; i++ )
- size[i - 3] = Mathf.RoundToInt( tokenValues[i] );
- output = new BoundsInt( center, size );
- }
- #endif
- else
- {
- output = null;
- return false;
- }
- return true;
- }
- }
- }
|