DebugLogConsole.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760
  1. using UnityEngine;
  2. using System.Reflection;
  3. using System.Collections.Generic;
  4. using System.Text;
  5. using System;
  6. // Manages the console commands, parses console input and handles execution of commands
  7. // Supported method parameter types: int, float, bool, string, Vector2, Vector3, Vector4
  8. // Helper class to store important information about a command
  9. namespace IngameDebugConsole
  10. {
  11. public class ConsoleMethodInfo
  12. {
  13. public readonly MethodInfo method;
  14. public readonly Type[] parameterTypes;
  15. public readonly object instance;
  16. public readonly string signature;
  17. public ConsoleMethodInfo( MethodInfo method, Type[] parameterTypes, object instance, string signature )
  18. {
  19. this.method = method;
  20. this.parameterTypes = parameterTypes;
  21. this.instance = instance;
  22. this.signature = signature;
  23. }
  24. public bool IsValid()
  25. {
  26. if( !method.IsStatic && ( instance == null || instance.Equals( null ) ) )
  27. return false;
  28. return true;
  29. }
  30. }
  31. public static class DebugLogConsole
  32. {
  33. public delegate bool ParseFunction( string input, out object output );
  34. // All the commands
  35. private static readonly Dictionary<string, ConsoleMethodInfo> methods = new Dictionary<string, ConsoleMethodInfo>();
  36. // All the parse functions
  37. private static readonly Dictionary<Type, ParseFunction> parseFunctions = new Dictionary<Type, ParseFunction>() {
  38. { typeof( string ), ParseString },
  39. { typeof( bool ), ParseBool },
  40. { typeof( int ), ParseInt },
  41. { typeof( uint ), ParseUInt },
  42. { typeof( long ), ParseLong },
  43. { typeof( ulong ), ParseULong },
  44. { typeof( byte ), ParseByte },
  45. { typeof( sbyte ), ParseSByte },
  46. { typeof( short ), ParseShort },
  47. { typeof( ushort ), ParseUShort },
  48. { typeof( char ), ParseChar },
  49. { typeof( float ), ParseFloat },
  50. { typeof( double ), ParseDouble },
  51. { typeof( decimal ), ParseDecimal },
  52. { typeof( Vector2 ), ParseVector2 },
  53. { typeof( Vector3 ), ParseVector3 },
  54. { typeof( Vector4 ), ParseVector4 },
  55. { typeof( GameObject ), ParseGameObject } };
  56. // All the readable names of accepted types
  57. private static readonly Dictionary<Type, string> typeReadableNames = new Dictionary<Type, string>() {
  58. { typeof( string ), "String" },
  59. { typeof( bool ), "Boolean" },
  60. { typeof( int ), "Integer" },
  61. { typeof( uint ), "Unsigned Integer" },
  62. { typeof( long ), "Long" },
  63. { typeof( ulong ), "Unsigned Long" },
  64. { typeof( byte ), "Byte" },
  65. { typeof( sbyte ), "Short Byte" },
  66. { typeof( short ), "Short" },
  67. { typeof( ushort ), "Unsigned Short" },
  68. { typeof( char ), "Char" },
  69. { typeof( float ), "Float" },
  70. { typeof( double ), "Double" },
  71. { typeof( decimal ), "Decimal" },
  72. { typeof( Vector2 ), "Vector2" },
  73. { typeof( Vector3 ), "Vector3" },
  74. { typeof( Vector4 ), "Vector4" },
  75. { typeof( GameObject ), "GameObject" } };
  76. // Split arguments of an entered command
  77. private static readonly List<string> commandArguments = new List<string>( 8 );
  78. // Command parameter delimeter groups
  79. private static readonly string[] inputDelimiters = new string[] { "\"\"", "''", "{}", "()", "[]" };
  80. static DebugLogConsole()
  81. {
  82. #if UNITY_EDITOR || !NETFX_CORE
  83. // Load commands in most common Unity assemblies
  84. HashSet<Assembly> assemblies = new HashSet<Assembly> { Assembly.GetAssembly( typeof( DebugLogConsole ) ) };
  85. try
  86. {
  87. assemblies.Add( Assembly.Load( "Assembly-CSharp" ) );
  88. }
  89. catch { }
  90. foreach( var assembly in assemblies )
  91. {
  92. foreach( var type in assembly.GetExportedTypes() )
  93. {
  94. foreach( var method in type.GetMethods( BindingFlags.Static | BindingFlags.Public | BindingFlags.DeclaredOnly ) )
  95. {
  96. foreach( var attribute in method.GetCustomAttributes( typeof( ConsoleMethodAttribute ), false ) )
  97. {
  98. ConsoleMethodAttribute consoleMethod = attribute as ConsoleMethodAttribute;
  99. if( consoleMethod != null )
  100. AddCommand( consoleMethod.Command, consoleMethod.Description, method );
  101. }
  102. }
  103. }
  104. }
  105. #endif
  106. AddCommand( "help", "Prints all commands", LogAllCommands );
  107. AddCommand( "sysinfo", "Prints system information", LogSystemInfo );
  108. }
  109. // Logs the list of available commands
  110. public static void LogAllCommands()
  111. {
  112. int length = 25;
  113. foreach( var entry in methods )
  114. {
  115. if( entry.Value.IsValid() )
  116. length += 3 + entry.Value.signature.Length;
  117. }
  118. StringBuilder stringBuilder = new StringBuilder( length );
  119. stringBuilder.Append( "Available commands:" );
  120. foreach( var entry in methods )
  121. {
  122. if( entry.Value.IsValid() )
  123. stringBuilder.Append( "\n- " ).Append( entry.Value.signature );
  124. }
  125. Debug.Log( stringBuilder.Append( "\n" ).ToString() );
  126. }
  127. // Logs system information
  128. public static void LogSystemInfo()
  129. {
  130. StringBuilder stringBuilder = new StringBuilder( 1024 );
  131. stringBuilder.Append( "Rig: " ).AppendSysInfoIfPresent( SystemInfo.deviceModel ).AppendSysInfoIfPresent( SystemInfo.processorType )
  132. .AppendSysInfoIfPresent( SystemInfo.systemMemorySize, "MB RAM" ).Append( SystemInfo.processorCount ).Append( " cores\n" );
  133. stringBuilder.Append( "OS: " ).Append( SystemInfo.operatingSystem ).Append( "\n" );
  134. stringBuilder.Append( "GPU: " ).Append( SystemInfo.graphicsDeviceName ).Append( " " ).Append( SystemInfo.graphicsMemorySize )
  135. .Append( "MB " ).Append( SystemInfo.graphicsDeviceVersion )
  136. .Append( SystemInfo.graphicsMultiThreaded ? " multi-threaded\n" : "\n" );
  137. stringBuilder.Append( "Data Path: " ).Append( Application.dataPath ).Append( "\n" );
  138. stringBuilder.Append( "Persistent Data Path: " ).Append( Application.persistentDataPath ).Append( "\n" );
  139. stringBuilder.Append( "StreamingAssets Path: " ).Append( Application.streamingAssetsPath ).Append( "\n" );
  140. stringBuilder.Append( "Temporary Cache Path: " ).Append( Application.temporaryCachePath ).Append( "\n" );
  141. stringBuilder.Append( "Device ID: " ).Append( SystemInfo.deviceUniqueIdentifier ).Append( "\n" );
  142. stringBuilder.Append( "Max Texture Size: " ).Append( SystemInfo.maxTextureSize ).Append( "\n" );
  143. #if UNITY_5_6_OR_NEWER
  144. stringBuilder.Append( "Max Cubemap Size: " ).Append( SystemInfo.maxCubemapSize ).Append( "\n" );
  145. #endif
  146. stringBuilder.Append( "Accelerometer: " ).Append( SystemInfo.supportsAccelerometer ? "supported\n" : "not supported\n" );
  147. stringBuilder.Append( "Gyro: " ).Append( SystemInfo.supportsGyroscope ? "supported\n" : "not supported\n" );
  148. stringBuilder.Append( "Location Service: " ).Append( SystemInfo.supportsLocationService ? "supported\n" : "not supported\n" );
  149. #if !UNITY_2019_1_OR_NEWER
  150. stringBuilder.Append( "Image Effects: " ).Append( SystemInfo.supportsImageEffects ? "supported\n" : "not supported\n" );
  151. stringBuilder.Append( "RenderToCubemap: " ).Append( SystemInfo.supportsRenderToCubemap ? "supported\n" : "not supported\n" );
  152. #endif
  153. stringBuilder.Append( "Compute Shaders: " ).Append( SystemInfo.supportsComputeShaders ? "supported\n" : "not supported\n" );
  154. stringBuilder.Append( "Shadows: " ).Append( SystemInfo.supportsShadows ? "supported\n" : "not supported\n" );
  155. stringBuilder.Append( "Instancing: " ).Append( SystemInfo.supportsInstancing ? "supported\n" : "not supported\n" );
  156. stringBuilder.Append( "Motion Vectors: " ).Append( SystemInfo.supportsMotionVectors ? "supported\n" : "not supported\n" );
  157. stringBuilder.Append( "3D Textures: " ).Append( SystemInfo.supports3DTextures ? "supported\n" : "not supported\n" );
  158. #if UNITY_5_6_OR_NEWER
  159. stringBuilder.Append( "3D Render Textures: " ).Append( SystemInfo.supports3DRenderTextures ? "supported\n" : "not supported\n" );
  160. #endif
  161. stringBuilder.Append( "2D Array Textures: " ).Append( SystemInfo.supports2DArrayTextures ? "supported\n" : "not supported\n" );
  162. stringBuilder.Append( "Cubemap Array Textures: " ).Append( SystemInfo.supportsCubemapArrayTextures ? "supported" : "not supported" );
  163. Debug.Log( stringBuilder.Append( "\n" ).ToString() );
  164. }
  165. private static StringBuilder AppendSysInfoIfPresent( this StringBuilder sb, string info, string postfix = null )
  166. {
  167. if( info != SystemInfo.unsupportedIdentifier )
  168. {
  169. sb.Append( info );
  170. if( postfix != null )
  171. sb.Append( postfix );
  172. sb.Append( " " );
  173. }
  174. return sb;
  175. }
  176. private static StringBuilder AppendSysInfoIfPresent( this StringBuilder sb, int info, string postfix = null )
  177. {
  178. if( info > 0 )
  179. {
  180. sb.Append( info );
  181. if( postfix != null )
  182. sb.Append( postfix );
  183. sb.Append( " " );
  184. }
  185. return sb;
  186. }
  187. // Add a command related with an instance method (i.e. non static method)
  188. public static void AddCommandInstance( string command, string description, string methodName, object instance )
  189. {
  190. if( instance == null )
  191. {
  192. Debug.LogError( "Instance can't be null!" );
  193. return;
  194. }
  195. AddCommand( command, description, methodName, instance.GetType(), instance );
  196. }
  197. // Add a command related with a static method (i.e. no instance is required to call the method)
  198. public static void AddCommandStatic( string command, string description, string methodName, Type ownerType )
  199. {
  200. AddCommand( command, description, methodName, ownerType );
  201. }
  202. // Add a command that can be related to either a static or an instance method
  203. public static void AddCommand( string command, string description, Action method )
  204. {
  205. AddCommand( command, description, method.Method, method.Target );
  206. }
  207. public static void AddCommand<T1>( string command, string description, Action<T1> method )
  208. {
  209. AddCommand( command, description, method.Method, method.Target );
  210. }
  211. public static void AddCommand<T1>( string command, string description, Func<T1> method )
  212. {
  213. AddCommand( command, description, method.Method, method.Target );
  214. }
  215. public static void AddCommand<T1, T2>( string command, string description, Action<T1, T2> method )
  216. {
  217. AddCommand( command, description, method.Method, method.Target );
  218. }
  219. public static void AddCommand<T1, T2>( string command, string description, Func<T1, T2> method )
  220. {
  221. AddCommand( command, description, method.Method, method.Target );
  222. }
  223. public static void AddCommand<T1, T2, T3>( string command, string description, Action<T1, T2, T3> method )
  224. {
  225. AddCommand( command, description, method.Method, method.Target );
  226. }
  227. public static void AddCommand<T1, T2, T3>( string command, string description, Func<T1, T2, T3> method )
  228. {
  229. AddCommand( command, description, method.Method, method.Target );
  230. }
  231. public static void AddCommand<T1, T2, T3, T4>( string command, string description, Action<T1, T2, T3, T4> method )
  232. {
  233. AddCommand( command, description, method.Method, method.Target );
  234. }
  235. public static void AddCommand<T1, T2, T3, T4>( string command, string description, Func<T1, T2, T3, T4> method )
  236. {
  237. AddCommand( command, description, method.Method, method.Target );
  238. }
  239. public static void AddCommand<T1, T2, T3, T4, T5>( string command, string description, Func<T1, T2, T3, T4, T5> method )
  240. {
  241. AddCommand( command, description, method.Method, method.Target );
  242. }
  243. public static void AddCommand( string command, string description, Delegate method )
  244. {
  245. AddCommand( command, description, method.Method, method.Target );
  246. }
  247. // Remove a command from the console
  248. public static void RemoveCommand( string command )
  249. {
  250. if( !string.IsNullOrEmpty( command ) )
  251. methods.Remove( command );
  252. }
  253. // Returns the first command that starts with the entered argument
  254. public static string GetAutoCompleteCommand( string commandStart )
  255. {
  256. foreach( var entry in methods )
  257. {
  258. if( entry.Key.StartsWith( commandStart ) )
  259. return entry.Key;
  260. }
  261. return null;
  262. }
  263. // Create a new command and set its properties
  264. private static void AddCommand( string command, string description, string methodName, Type ownerType, object instance = null )
  265. {
  266. // Get the method from the class
  267. MethodInfo method = ownerType.GetMethod( methodName, BindingFlags.Public | BindingFlags.NonPublic | ( instance != null ? BindingFlags.Instance : BindingFlags.Static ) );
  268. if( method == null )
  269. {
  270. Debug.LogError( methodName + " does not exist in " + ownerType );
  271. return;
  272. }
  273. AddCommand( command, description, method, instance );
  274. }
  275. private static void AddCommand( string command, string description, MethodInfo method, object instance = null )
  276. {
  277. if( string.IsNullOrEmpty( command ) )
  278. {
  279. Debug.LogError( "Command name can't be empty!" );
  280. return;
  281. }
  282. command = command.Trim();
  283. if( command.IndexOf( ' ' ) >= 0 )
  284. {
  285. Debug.LogError( "Command name can't contain whitespace: " + command );
  286. return;
  287. }
  288. // Fetch the parameters of the class
  289. ParameterInfo[] parameters = method.GetParameters();
  290. if( parameters == null )
  291. parameters = new ParameterInfo[0];
  292. bool isMethodValid = true;
  293. // Store the parameter types in an array
  294. Type[] parameterTypes = new Type[parameters.Length];
  295. for( int k = 0; k < parameters.Length; k++ )
  296. {
  297. Type parameterType = parameters[k].ParameterType;
  298. if( parseFunctions.ContainsKey( parameterType ) || typeof( Component ).IsAssignableFrom( parameterType ) )
  299. parameterTypes[k] = parameterType;
  300. else
  301. {
  302. isMethodValid = false;
  303. break;
  304. }
  305. }
  306. // If method is valid, associate it with the entered command
  307. if( isMethodValid )
  308. {
  309. StringBuilder methodSignature = new StringBuilder( 256 );
  310. methodSignature.Append( command ).Append( ": " );
  311. if( !string.IsNullOrEmpty( description ) )
  312. methodSignature.Append( description ).Append( " -> " );
  313. methodSignature.Append( method.DeclaringType.ToString() ).Append( "." ).Append( method.Name ).Append( "(" );
  314. for( int i = 0; i < parameterTypes.Length; i++ )
  315. {
  316. Type type = parameterTypes[i];
  317. string typeName;
  318. if( !typeReadableNames.TryGetValue( type, out typeName ) )
  319. typeName = type.Name;
  320. methodSignature.Append( typeName );
  321. if( i < parameterTypes.Length - 1 )
  322. methodSignature.Append( ", " );
  323. }
  324. methodSignature.Append( ")" );
  325. Type returnType = method.ReturnType;
  326. if( returnType != typeof( void ) )
  327. {
  328. string returnTypeName;
  329. if( !typeReadableNames.TryGetValue( returnType, out returnTypeName ) )
  330. returnTypeName = returnType.Name;
  331. methodSignature.Append( " : " ).Append( returnTypeName );
  332. }
  333. methods[command] = new ConsoleMethodInfo( method, parameterTypes, instance, methodSignature.ToString() );
  334. }
  335. }
  336. // Parse the command and try to execute it
  337. public static void ExecuteCommand( string command )
  338. {
  339. if( command == null )
  340. return;
  341. command = command.Trim();
  342. if( command.Length == 0 )
  343. return;
  344. // Parse the arguments
  345. commandArguments.Clear();
  346. int endIndex = IndexOfChar( command, ' ', 0 );
  347. commandArguments.Add( command.Substring( 0, endIndex ) );
  348. for( int i = endIndex + 1; i < command.Length; i++ )
  349. {
  350. if( command[i] == ' ' )
  351. continue;
  352. int delimiterIndex = IndexOfDelimiter( command[i] );
  353. if( delimiterIndex >= 0 )
  354. {
  355. endIndex = IndexOfChar( command, inputDelimiters[delimiterIndex][1], i + 1 );
  356. commandArguments.Add( command.Substring( i + 1, endIndex - i - 1 ) );
  357. }
  358. else
  359. {
  360. endIndex = IndexOfChar( command, ' ', i + 1 );
  361. commandArguments.Add( command.Substring( i, endIndex - i ) );
  362. }
  363. i = endIndex;
  364. }
  365. // Check if command exists
  366. ConsoleMethodInfo methodInfo;
  367. if( !methods.TryGetValue( commandArguments[0], out methodInfo ) )
  368. Debug.LogWarning( "Can't find command: " + commandArguments[0] );
  369. else if( !methodInfo.IsValid() )
  370. Debug.LogWarning( "Method no longer valid (instance dead): " + commandArguments[0] );
  371. else
  372. {
  373. // Check if number of parameter match
  374. if( methodInfo.parameterTypes.Length != commandArguments.Count - 1 )
  375. {
  376. Debug.LogWarning( "Parameter count mismatch: " + methodInfo.parameterTypes.Length + " parameters are needed" );
  377. return;
  378. }
  379. Debug.Log( "Executing command: " + commandArguments[0] );
  380. // Parse the parameters into objects
  381. object[] parameters = new object[methodInfo.parameterTypes.Length];
  382. for( int i = 0; i < methodInfo.parameterTypes.Length; i++ )
  383. {
  384. string argument = commandArguments[i + 1];
  385. Type parameterType = methodInfo.parameterTypes[i];
  386. if( typeof( Component ).IsAssignableFrom( parameterType ) )
  387. {
  388. UnityEngine.Object val = argument == "null" ? null : GameObject.Find( argument );
  389. if( val )
  390. val = ( (GameObject) val ).GetComponent( parameterType );
  391. parameters[i] = val;
  392. }
  393. else
  394. {
  395. ParseFunction parseFunction;
  396. if( !parseFunctions.TryGetValue( parameterType, out parseFunction ) )
  397. {
  398. Debug.LogError( "Unsupported parameter type: " + parameterType.Name );
  399. return;
  400. }
  401. object val;
  402. if( !parseFunction( argument, out val ) )
  403. {
  404. Debug.LogError( "Couldn't parse " + argument + " to " + parameterType.Name );
  405. return;
  406. }
  407. parameters[i] = val;
  408. }
  409. }
  410. // Execute the method associated with the command
  411. object result = methodInfo.method.Invoke( methodInfo.instance, parameters );
  412. if( methodInfo.method.ReturnType != typeof( void ) )
  413. {
  414. // Print the returned value to the console
  415. if( result == null || result.Equals( null ) )
  416. Debug.Log( "Value returned: null" );
  417. else
  418. Debug.Log( "Value returned: " + result.ToString() );
  419. }
  420. }
  421. }
  422. // Find the index of the delimiter group that 'c' belongs to
  423. private static int IndexOfDelimiter( char c )
  424. {
  425. for( int i = 0; i < inputDelimiters.Length; i++ )
  426. {
  427. if( c == inputDelimiters[i][0] )
  428. return i;
  429. }
  430. return -1;
  431. }
  432. // Find the index of char in the string, or return the length of string instead of -1
  433. private static int IndexOfChar( string command, char c, int startIndex )
  434. {
  435. int result = command.IndexOf( c, startIndex );
  436. if( result < 0 )
  437. result = command.Length;
  438. return result;
  439. }
  440. private static bool ParseString( string input, out object output )
  441. {
  442. output = input;
  443. return input.Length > 0;
  444. }
  445. private static bool ParseBool( string input, out object output )
  446. {
  447. if( input == "1" || input.ToLowerInvariant() == "true" )
  448. {
  449. output = true;
  450. return true;
  451. }
  452. if( input == "0" || input.ToLowerInvariant() == "false" )
  453. {
  454. output = false;
  455. return true;
  456. }
  457. output = false;
  458. return false;
  459. }
  460. private static bool ParseInt( string input, out object output )
  461. {
  462. bool result;
  463. int value;
  464. result = int.TryParse( input, out value );
  465. output = value;
  466. return result;
  467. }
  468. private static bool ParseUInt( string input, out object output )
  469. {
  470. bool result;
  471. uint value;
  472. result = uint.TryParse( input, out value );
  473. output = value;
  474. return result;
  475. }
  476. private static bool ParseLong( string input, out object output )
  477. {
  478. bool result;
  479. long value;
  480. result = long.TryParse( input, out value );
  481. output = value;
  482. return result;
  483. }
  484. private static bool ParseULong( string input, out object output )
  485. {
  486. bool result;
  487. ulong value;
  488. result = ulong.TryParse( input, out value );
  489. output = value;
  490. return result;
  491. }
  492. private static bool ParseByte( string input, out object output )
  493. {
  494. bool result;
  495. byte value;
  496. result = byte.TryParse( input, out value );
  497. output = value;
  498. return result;
  499. }
  500. private static bool ParseSByte( string input, out object output )
  501. {
  502. bool result;
  503. sbyte value;
  504. result = sbyte.TryParse( input, out value );
  505. output = value;
  506. return result;
  507. }
  508. private static bool ParseShort( string input, out object output )
  509. {
  510. bool result;
  511. short value;
  512. result = short.TryParse( input, out value );
  513. output = value;
  514. return result;
  515. }
  516. private static bool ParseUShort( string input, out object output )
  517. {
  518. bool result;
  519. ushort value;
  520. result = ushort.TryParse( input, out value );
  521. output = value;
  522. return result;
  523. }
  524. private static bool ParseChar( string input, out object output )
  525. {
  526. bool result;
  527. char value;
  528. result = char.TryParse( input, out value );
  529. output = value;
  530. return result;
  531. }
  532. private static bool ParseFloat( string input, out object output )
  533. {
  534. bool result;
  535. float value;
  536. result = float.TryParse( input, out value );
  537. output = value;
  538. return result;
  539. }
  540. private static bool ParseDouble( string input, out object output )
  541. {
  542. bool result;
  543. double value;
  544. result = double.TryParse( input, out value );
  545. output = value;
  546. return result;
  547. }
  548. private static bool ParseDecimal( string input, out object output )
  549. {
  550. bool result;
  551. decimal value;
  552. result = decimal.TryParse( input, out value );
  553. output = value;
  554. return result;
  555. }
  556. private static bool ParseVector2( string input, out object output )
  557. {
  558. return CreateVectorFromInput( input, typeof( Vector2 ), out output );
  559. }
  560. private static bool ParseVector3( string input, out object output )
  561. {
  562. return CreateVectorFromInput( input, typeof( Vector3 ), out output );
  563. }
  564. private static bool ParseVector4( string input, out object output )
  565. {
  566. return CreateVectorFromInput( input, typeof( Vector4 ), out output );
  567. }
  568. private static bool ParseGameObject( string input, out object output )
  569. {
  570. output = input == "null" ? null : GameObject.Find( input );
  571. return true;
  572. }
  573. // Create a vector of specified type (fill the blank slots with 0 or ignore unnecessary slots)
  574. private static bool CreateVectorFromInput( string input, Type vectorType, out object output )
  575. {
  576. List<string> tokens = new List<string>( input.Replace( ',', ' ' ).Trim().Split( ' ' ) );
  577. int i;
  578. for( i = tokens.Count - 1; i >= 0; i-- )
  579. {
  580. tokens[i] = tokens[i].Trim();
  581. if( tokens[i].Length == 0 )
  582. tokens.RemoveAt( i );
  583. }
  584. float[] tokenValues = new float[tokens.Count];
  585. for( i = 0; i < tokens.Count; i++ )
  586. {
  587. float val;
  588. if( !float.TryParse( tokens[i], out val ) )
  589. {
  590. if( vectorType == typeof( Vector3 ) )
  591. output = new Vector3();
  592. else if( vectorType == typeof( Vector2 ) )
  593. output = new Vector2();
  594. else
  595. output = new Vector4();
  596. return false;
  597. }
  598. tokenValues[i] = val;
  599. }
  600. if( vectorType == typeof( Vector3 ) )
  601. {
  602. Vector3 result = new Vector3();
  603. for( i = 0; i < tokenValues.Length && i < 3; i++ )
  604. result[i] = tokenValues[i];
  605. for( ; i < 3; i++ )
  606. result[i] = 0;
  607. output = result;
  608. }
  609. else if( vectorType == typeof( Vector2 ) )
  610. {
  611. Vector2 result = new Vector2();
  612. for( i = 0; i < tokenValues.Length && i < 2; i++ )
  613. result[i] = tokenValues[i];
  614. for( ; i < 2; i++ )
  615. result[i] = 0;
  616. output = result;
  617. }
  618. else
  619. {
  620. Vector4 result = new Vector4();
  621. for( i = 0; i < tokenValues.Length && i < 4; i++ )
  622. result[i] = tokenValues[i];
  623. for( ; i < 4; i++ )
  624. result[i] = 0;
  625. output = result;
  626. }
  627. return true;
  628. }
  629. }
  630. }