范川铭

1.导入Debug组件

Showing 44 changed files with 3782 additions and 0 deletions

Too many changes to show.

To preserve performance only 44 of 44+ files are displayed.

@@ -758,6 +758,14 @@ @@ -758,6 +758,14 @@
758 </Reference> 758 </Reference>
759 </ItemGroup> 759 </ItemGroup>
760 <ItemGroup> 760 <ItemGroup>
  761 + <ProjectReference Include="IngameDebugConsole.Editor.csproj">
  762 + <Project>{9b47dfc7-464c-e716-7c49-c01c25245e7d}</Project>
  763 + <Name>IngameDebugConsole.Editor</Name>
  764 + </ProjectReference>
  765 + <ProjectReference Include="IngameDebugConsole.Runtime.csproj">
  766 + <Project>{f455341b-6302-350b-c7b4-f9a38305d0ae}</Project>
  767 + <Name>IngameDebugConsole.Runtime</Name>
  768 + </ProjectReference>
761 </ItemGroup> 769 </ItemGroup>
762 <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> 770 <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
763 <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 771 <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
@@ -763,6 +763,14 @@ @@ -763,6 +763,14 @@
763 <Project>{0fb0da77-85a4-96d4-1dc2-8ddaab877745}</Project> 763 <Project>{0fb0da77-85a4-96d4-1dc2-8ddaab877745}</Project>
764 <Name>Assembly-CSharp-firstpass</Name> 764 <Name>Assembly-CSharp-firstpass</Name>
765 </ProjectReference> 765 </ProjectReference>
  766 + <ProjectReference Include="IngameDebugConsole.Editor.csproj">
  767 + <Project>{9b47dfc7-464c-e716-7c49-c01c25245e7d}</Project>
  768 + <Name>IngameDebugConsole.Editor</Name>
  769 + </ProjectReference>
  770 + <ProjectReference Include="IngameDebugConsole.Runtime.csproj">
  771 + <Project>{f455341b-6302-350b-c7b4-f9a38305d0ae}</Project>
  772 + <Name>IngameDebugConsole.Runtime</Name>
  773 + </ProjectReference>
766 </ItemGroup> 774 </ItemGroup>
767 <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> 775 <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
768 <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 776 <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
  1 +fileFormatVersion: 2
  2 +guid: 3c57523b63ddb094b835b6613da12763
  3 +folderAsset: yes
  4 +timeCreated: 1596819199
  5 +licenseType: Store
  6 +DefaultImporter:
  7 + userData:
  8 + assetBundleName:
  9 + assetBundleVariant:
  1 +fileFormatVersion: 2
  2 +guid: 3d7d7a61a5341904eb3c65af025b1d86
  3 +folderAsset: yes
  4 +timeCreated: 1510075633
  5 +licenseType: Store
  6 +DefaultImporter:
  7 + userData:
  8 + assetBundleName:
  9 + assetBundleVariant:
  1 +#if UNITY_EDITOR || UNITY_ANDROID
  2 +using System.Collections.Generic;
  3 +using UnityEngine;
  4 +
  5 +// Credit: https://stackoverflow.com/a/41018028/2373034
  6 +namespace IngameDebugConsole
  7 +{
  8 + public class DebugLogLogcatListener : AndroidJavaProxy
  9 + {
  10 + private Queue<string> queuedLogs;
  11 + private AndroidJavaObject nativeObject;
  12 +
  13 + public DebugLogLogcatListener() : base( "com.yasirkula.unity.DebugConsoleLogcatLogReceiver" )
  14 + {
  15 + queuedLogs = new Queue<string>( 16 );
  16 + }
  17 +
  18 + ~DebugLogLogcatListener()
  19 + {
  20 + Stop();
  21 +
  22 + if( nativeObject != null )
  23 + nativeObject.Dispose();
  24 + }
  25 +
  26 + public void Start( string arguments )
  27 + {
  28 + if( nativeObject == null )
  29 + nativeObject = new AndroidJavaObject( "com.yasirkula.unity.DebugConsoleLogcatLogger" );
  30 +
  31 + nativeObject.Call( "Start", this, arguments );
  32 + }
  33 +
  34 + public void Stop()
  35 + {
  36 + if( nativeObject != null )
  37 + nativeObject.Call( "Stop" );
  38 + }
  39 +
  40 + [UnityEngine.Scripting.Preserve]
  41 + public void OnLogReceived( string log )
  42 + {
  43 + queuedLogs.Enqueue( log );
  44 + }
  45 +
  46 + public string GetLog()
  47 + {
  48 + if( queuedLogs.Count > 0 )
  49 + return queuedLogs.Dequeue();
  50 +
  51 + return null;
  52 + }
  53 + }
  54 +}
  55 +#endif
  1 +fileFormatVersion: 2
  2 +guid: dd3b7385882055d4a8c2b91deb6b2470
  3 +timeCreated: 1510076185
  4 +licenseType: Store
  5 +MonoImporter:
  6 + serializedVersion: 2
  7 + defaultReferences: []
  8 + executionOrder: 0
  9 + icon: {instanceID: 0}
  10 + userData:
  11 + assetBundleName:
  12 + assetBundleVariant:
  1 +fileFormatVersion: 2
  2 +guid: bf909fab1c14af446b0a854de42289b2
  3 +timeCreated: 1510086220
  4 +licenseType: Store
  5 +PluginImporter:
  6 + serializedVersion: 2
  7 + iconMap: {}
  8 + executionOrder: {}
  9 + isPreloaded: 0
  10 + isOverridable: 0
  11 + platformData:
  12 + data:
  13 + first:
  14 + Android: Android
  15 + second:
  16 + enabled: 1
  17 + settings: {}
  18 + data:
  19 + first:
  20 + Any:
  21 + second:
  22 + enabled: 0
  23 + settings: {}
  24 + data:
  25 + first:
  26 + Editor: Editor
  27 + second:
  28 + enabled: 0
  29 + settings:
  30 + DefaultValueInitialized: true
  31 + userData:
  32 + assetBundleName:
  33 + assetBundleVariant:
  1 +fileFormatVersion: 2
  2 +guid: 86f54622630720f4abe279acdbb8886f
  3 +folderAsset: yes
  4 +timeCreated: 1561217660
  5 +licenseType: Store
  6 +DefaultImporter:
  7 + userData:
  8 + assetBundleName:
  9 + assetBundleVariant:
  1 +using UnityEditor;
  2 +using UnityEngine;
  3 +
  4 +namespace IngameDebugConsole
  5 +{
  6 + [CustomEditor( typeof( DebugLogManager ) )]
  7 + public class DebugLogManagerEditor : Editor
  8 + {
  9 + private SerializedProperty singleton;
  10 + private SerializedProperty minimumHeight;
  11 + private SerializedProperty enableHorizontalResizing;
  12 + private SerializedProperty resizeFromRight;
  13 + private SerializedProperty minimumWidth;
  14 + private SerializedProperty logWindowOpacity;
  15 + private SerializedProperty popupOpacity;
  16 + private SerializedProperty popupVisibility;
  17 + private SerializedProperty popupVisibilityLogFilter;
  18 + private SerializedProperty startMinimized;
  19 + private SerializedProperty toggleWithKey;
  20 + private SerializedProperty toggleKey;
  21 + private SerializedProperty enableSearchbar;
  22 + private SerializedProperty topSearchbarMinWidth;
  23 + private SerializedProperty receiveLogsWhileInactive;
  24 + private SerializedProperty receiveInfoLogs;
  25 + private SerializedProperty receiveWarningLogs;
  26 + private SerializedProperty receiveErrorLogs;
  27 + private SerializedProperty receiveExceptionLogs;
  28 + private SerializedProperty captureLogTimestamps;
  29 + private SerializedProperty alwaysDisplayTimestamps;
  30 + private SerializedProperty maxLogCount;
  31 + private SerializedProperty logsToRemoveAfterMaxLogCount;
  32 + private SerializedProperty queuedLogLimit;
  33 + private SerializedProperty clearCommandAfterExecution;
  34 + private SerializedProperty commandHistorySize;
  35 + private SerializedProperty showCommandSuggestions;
  36 + private SerializedProperty receiveLogcatLogsInAndroid;
  37 + private SerializedProperty logcatArguments;
  38 + private SerializedProperty avoidScreenCutout;
  39 + private SerializedProperty popupAvoidsScreenCutout;
  40 + private SerializedProperty autoFocusOnCommandInputField;
  41 +
  42 +#if UNITY_2017_3_OR_NEWER
  43 + private readonly GUIContent popupVisibilityLogFilterLabel = new GUIContent( "Log Filter", "Determines which log types will show the popup on screen" );
  44 +#endif
  45 + private readonly GUIContent receivedLogTypesLabel = new GUIContent( "Received Log Types", "Only these logs will be received by the console window, other logs will simply be skipped" );
  46 + private readonly GUIContent receiveInfoLogsLabel = new GUIContent( "Info" );
  47 + private readonly GUIContent receiveWarningLogsLabel = new GUIContent( "Warning" );
  48 + private readonly GUIContent receiveErrorLogsLabel = new GUIContent( "Error" );
  49 + private readonly GUIContent receiveExceptionLogsLabel = new GUIContent( "Exception" );
  50 +
  51 + private void OnEnable()
  52 + {
  53 + singleton = serializedObject.FindProperty( "singleton" );
  54 + minimumHeight = serializedObject.FindProperty( "minimumHeight" );
  55 + enableHorizontalResizing = serializedObject.FindProperty( "enableHorizontalResizing" );
  56 + resizeFromRight = serializedObject.FindProperty( "resizeFromRight" );
  57 + minimumWidth = serializedObject.FindProperty( "minimumWidth" );
  58 + logWindowOpacity = serializedObject.FindProperty( "logWindowOpacity" );
  59 + popupOpacity = serializedObject.FindProperty( "popupOpacity" );
  60 + popupVisibility = serializedObject.FindProperty( "popupVisibility" );
  61 + popupVisibilityLogFilter = serializedObject.FindProperty( "popupVisibilityLogFilter" );
  62 + startMinimized = serializedObject.FindProperty( "startMinimized" );
  63 + toggleWithKey = serializedObject.FindProperty( "toggleWithKey" );
  64 +#if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER
  65 + toggleKey = serializedObject.FindProperty( "toggleBinding" );
  66 +#else
  67 + toggleKey = serializedObject.FindProperty( "toggleKey" );
  68 +#endif
  69 + enableSearchbar = serializedObject.FindProperty( "enableSearchbar" );
  70 + topSearchbarMinWidth = serializedObject.FindProperty( "topSearchbarMinWidth" );
  71 + receiveLogsWhileInactive = serializedObject.FindProperty( "receiveLogsWhileInactive" );
  72 + receiveInfoLogs = serializedObject.FindProperty( "receiveInfoLogs" );
  73 + receiveWarningLogs = serializedObject.FindProperty( "receiveWarningLogs" );
  74 + receiveErrorLogs = serializedObject.FindProperty( "receiveErrorLogs" );
  75 + receiveExceptionLogs = serializedObject.FindProperty( "receiveExceptionLogs" );
  76 + captureLogTimestamps = serializedObject.FindProperty( "captureLogTimestamps" );
  77 + alwaysDisplayTimestamps = serializedObject.FindProperty( "alwaysDisplayTimestamps" );
  78 + maxLogCount = serializedObject.FindProperty( "maxLogCount" );
  79 + logsToRemoveAfterMaxLogCount = serializedObject.FindProperty( "logsToRemoveAfterMaxLogCount" );
  80 + queuedLogLimit = serializedObject.FindProperty( "queuedLogLimit" );
  81 + clearCommandAfterExecution = serializedObject.FindProperty( "clearCommandAfterExecution" );
  82 + commandHistorySize = serializedObject.FindProperty( "commandHistorySize" );
  83 + showCommandSuggestions = serializedObject.FindProperty( "showCommandSuggestions" );
  84 + receiveLogcatLogsInAndroid = serializedObject.FindProperty( "receiveLogcatLogsInAndroid" );
  85 + logcatArguments = serializedObject.FindProperty( "logcatArguments" );
  86 + avoidScreenCutout = serializedObject.FindProperty( "avoidScreenCutout" );
  87 + popupAvoidsScreenCutout = serializedObject.FindProperty( "popupAvoidsScreenCutout" );
  88 + autoFocusOnCommandInputField = serializedObject.FindProperty( "autoFocusOnCommandInputField" );
  89 + }
  90 +
  91 + public override void OnInspectorGUI()
  92 + {
  93 + serializedObject.Update();
  94 +
  95 + EditorGUILayout.PropertyField( singleton );
  96 +
  97 + EditorGUILayout.Space();
  98 +
  99 + EditorGUILayout.PropertyField( minimumHeight );
  100 +
  101 + EditorGUILayout.PropertyField( enableHorizontalResizing );
  102 + if( enableHorizontalResizing.boolValue )
  103 + {
  104 + DrawSubProperty( resizeFromRight );
  105 + DrawSubProperty( minimumWidth );
  106 + }
  107 +
  108 + EditorGUILayout.PropertyField( avoidScreenCutout );
  109 + DrawSubProperty( popupAvoidsScreenCutout );
  110 +
  111 + EditorGUILayout.Space();
  112 +
  113 + EditorGUILayout.PropertyField( startMinimized );
  114 + EditorGUILayout.PropertyField( logWindowOpacity );
  115 + EditorGUILayout.PropertyField( popupOpacity );
  116 +
  117 + EditorGUILayout.PropertyField( popupVisibility );
  118 + if( popupVisibility.intValue == (int) PopupVisibility.WhenLogReceived )
  119 + {
  120 + EditorGUI.indentLevel++;
  121 +#if UNITY_2017_3_OR_NEWER
  122 + Rect rect = EditorGUILayout.GetControlRect();
  123 + EditorGUI.BeginProperty( rect, GUIContent.none, popupVisibilityLogFilter );
  124 + popupVisibilityLogFilter.intValue = (int) (DebugLogFilter) EditorGUI.EnumFlagsField( rect, popupVisibilityLogFilterLabel, (DebugLogFilter) popupVisibilityLogFilter.intValue );
  125 +#else
  126 + EditorGUI.BeginProperty( new Rect(), GUIContent.none, popupVisibilityLogFilter );
  127 + EditorGUI.BeginChangeCheck();
  128 +
  129 + bool infoLog = EditorGUILayout.Toggle( "Info", ( (DebugLogFilter) popupVisibilityLogFilter.intValue & DebugLogFilter.Info ) == DebugLogFilter.Info );
  130 + bool warningLog = EditorGUILayout.Toggle( "Warning", ( (DebugLogFilter) popupVisibilityLogFilter.intValue & DebugLogFilter.Warning ) == DebugLogFilter.Warning );
  131 + bool errorLog = EditorGUILayout.Toggle( "Error", ( (DebugLogFilter) popupVisibilityLogFilter.intValue & DebugLogFilter.Error ) == DebugLogFilter.Error );
  132 +
  133 + if( EditorGUI.EndChangeCheck() )
  134 + popupVisibilityLogFilter.intValue = ( infoLog ? (int) DebugLogFilter.Info : 0 ) | ( warningLog ? (int) DebugLogFilter.Warning : 0 ) | ( errorLog ? (int) DebugLogFilter.Error : 0 );
  135 +#endif
  136 + EditorGUI.EndProperty();
  137 + EditorGUI.indentLevel--;
  138 + }
  139 +
  140 + EditorGUILayout.PropertyField( toggleWithKey );
  141 + if( toggleWithKey.boolValue )
  142 + DrawSubProperty( toggleKey );
  143 +
  144 + EditorGUILayout.Space();
  145 +
  146 + EditorGUILayout.PropertyField( enableSearchbar );
  147 + if( enableSearchbar.boolValue )
  148 + DrawSubProperty( topSearchbarMinWidth );
  149 +
  150 + EditorGUILayout.Space();
  151 +
  152 + EditorGUILayout.PropertyField( receiveLogsWhileInactive );
  153 +
  154 + EditorGUILayout.PrefixLabel( receivedLogTypesLabel );
  155 + EditorGUI.indentLevel++;
  156 + EditorGUILayout.PropertyField( receiveInfoLogs, receiveInfoLogsLabel );
  157 + EditorGUILayout.PropertyField( receiveWarningLogs, receiveWarningLogsLabel );
  158 + EditorGUILayout.PropertyField( receiveErrorLogs, receiveErrorLogsLabel );
  159 + EditorGUILayout.PropertyField( receiveExceptionLogs, receiveExceptionLogsLabel );
  160 + EditorGUI.indentLevel--;
  161 +
  162 + EditorGUILayout.PropertyField( receiveLogcatLogsInAndroid );
  163 + if( receiveLogcatLogsInAndroid.boolValue )
  164 + DrawSubProperty( logcatArguments );
  165 +
  166 + EditorGUILayout.PropertyField( captureLogTimestamps );
  167 + if( captureLogTimestamps.boolValue )
  168 + DrawSubProperty( alwaysDisplayTimestamps );
  169 +
  170 + EditorGUILayout.PropertyField( maxLogCount );
  171 + DrawSubProperty( logsToRemoveAfterMaxLogCount );
  172 +
  173 + EditorGUILayout.PropertyField( queuedLogLimit );
  174 +
  175 + EditorGUILayout.Space();
  176 +
  177 + EditorGUILayout.PropertyField( clearCommandAfterExecution );
  178 + EditorGUILayout.PropertyField( commandHistorySize );
  179 + EditorGUILayout.PropertyField( showCommandSuggestions );
  180 + EditorGUILayout.PropertyField( autoFocusOnCommandInputField );
  181 +
  182 + EditorGUILayout.Space();
  183 +
  184 + DrawPropertiesExcluding( serializedObject, "m_Script" );
  185 + serializedObject.ApplyModifiedProperties();
  186 + }
  187 +
  188 + private void DrawSubProperty( SerializedProperty property )
  189 + {
  190 + EditorGUI.indentLevel++;
  191 + EditorGUILayout.PropertyField( property );
  192 + EditorGUI.indentLevel--;
  193 + }
  194 + }
  195 +}
  1 +fileFormatVersion: 2
  2 +guid: 4c23e5c521cb0c54b9a638b2a653d1d3
  3 +timeCreated: 1561217671
  4 +licenseType: Store
  5 +MonoImporter:
  6 + serializedVersion: 2
  7 + defaultReferences: []
  8 + executionOrder: 0
  9 + icon: {instanceID: 0}
  10 + userData:
  11 + assetBundleName:
  12 + assetBundleVariant:
  1 +{
  2 + "name": "IngameDebugConsole.Editor",
  3 + "references": [
  4 + "IngameDebugConsole.Runtime"
  5 + ],
  6 + "includePlatforms": [
  7 + "Editor"
  8 + ],
  9 + "excludePlatforms": [],
  10 + "allowUnsafeCode": false,
  11 + "overrideReferences": false,
  12 + "precompiledReferences": [],
  13 + "autoReferenced": true,
  14 + "defineConstraints": [],
  15 + "versionDefines": [],
  16 + "noEngineReferences": false
  17 +}
  1 +fileFormatVersion: 2
  2 +guid: 466e67dabd1db22468246c39eddb6c3f
  3 +AssemblyDefinitionImporter:
  4 + externalObjects: {}
  5 + userData:
  6 + assetBundleName:
  7 + assetBundleVariant:
  1 +{
  2 + "name": "IngameDebugConsole.Runtime",
  3 + "references": [
  4 + "Unity.InputSystem"
  5 + ]
  6 +}
  1 +fileFormatVersion: 2
  2 +guid: 3de88c88fbbb8f944b9210d496af9762
  3 +AssemblyDefinitionImporter:
  4 + externalObjects: {}
  5 + userData:
  6 + assetBundleName:
  7 + assetBundleVariant:
This diff could not be displayed because it is too large.
  1 +fileFormatVersion: 2
  2 +guid: 67117722a812a2e46ab8cb8eafbf5f5e
  3 +timeCreated: 1466014755
  4 +licenseType: Store
  5 +NativeFormatImporter:
  6 + userData:
  7 + assetBundleName:
  8 + assetBundleVariant:
  1 +fileFormatVersion: 2
  2 +guid: 7dbc36665bc0d684db9a4447e27a7a4b
  3 +folderAsset: yes
  4 +timeCreated: 1520417401
  5 +licenseType: Store
  6 +DefaultImporter:
  7 + userData:
  8 + assetBundleName:
  9 + assetBundleVariant:
  1 +%YAML 1.1
  2 +%TAG !u! tag:unity3d.com,2011:
  3 +--- !u!1001 &100100000
  4 +Prefab:
  5 + m_ObjectHideFlags: 1
  6 + serializedVersion: 2
  7 + m_Modification:
  8 + m_TransformParent: {fileID: 0}
  9 + m_Modifications: []
  10 + m_RemovedComponents: []
  11 + m_ParentPrefab: {fileID: 0}
  12 + m_RootGameObject: {fileID: 1386426139070838}
  13 + m_IsPrefabParent: 1
  14 +--- !u!1 &1386426139070838
  15 +GameObject:
  16 + m_ObjectHideFlags: 0
  17 + m_PrefabParentObject: {fileID: 0}
  18 + m_PrefabInternal: {fileID: 100100000}
  19 + serializedVersion: 5
  20 + m_Component:
  21 + - component: {fileID: 224955737853170496}
  22 + - component: {fileID: 222541766812100524}
  23 + - component: {fileID: 114169395487023046}
  24 + m_Layer: 5
  25 + m_Name: CommandSuggestion
  26 + m_TagString: Untagged
  27 + m_Icon: {fileID: 0}
  28 + m_NavMeshLayer: 0
  29 + m_StaticEditorFlags: 0
  30 + m_IsActive: 1
  31 +--- !u!114 &114169395487023046
  32 +MonoBehaviour:
  33 + m_ObjectHideFlags: 1
  34 + m_PrefabParentObject: {fileID: 0}
  35 + m_PrefabInternal: {fileID: 100100000}
  36 + m_GameObject: {fileID: 1386426139070838}
  37 + m_Enabled: 1
  38 + m_EditorHideFlags: 0
  39 + m_Script: {fileID: 708705254, guid: f70555f144d8491a825f0804e09c671c, type: 3}
  40 + m_Name:
  41 + m_EditorClassIdentifier:
  42 + m_Material: {fileID: 0}
  43 + m_Color: {r: 0.83823526, g: 0.84439874, b: 0.84439874, a: 1}
  44 + m_RaycastTarget: 0
  45 + m_OnCullStateChanged:
  46 + m_PersistentCalls:
  47 + m_Calls: []
  48 + m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
  49 + Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
  50 + m_FontData:
  51 + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
  52 + m_FontSize: 16
  53 + m_FontStyle: 0
  54 + m_BestFit: 0
  55 + m_MinSize: 1
  56 + m_MaxSize: 40
  57 + m_Alignment: 3
  58 + m_AlignByGeometry: 0
  59 + m_RichText: 1
  60 + m_HorizontalOverflow: 0
  61 + m_VerticalOverflow: 0
  62 + m_LineSpacing: 1
  63 + m_Text: help
  64 +--- !u!222 &222541766812100524
  65 +CanvasRenderer:
  66 + m_ObjectHideFlags: 1
  67 + m_PrefabParentObject: {fileID: 0}
  68 + m_PrefabInternal: {fileID: 100100000}
  69 + m_GameObject: {fileID: 1386426139070838}
  70 +--- !u!224 &224955737853170496
  71 +RectTransform:
  72 + m_ObjectHideFlags: 1
  73 + m_PrefabParentObject: {fileID: 0}
  74 + m_PrefabInternal: {fileID: 100100000}
  75 + m_GameObject: {fileID: 1386426139070838}
  76 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
  77 + m_LocalPosition: {x: 0, y: 0, z: 0}
  78 + m_LocalScale: {x: 1, y: 1, z: 1}
  79 + m_Children: []
  80 + m_Father: {fileID: 0}
  81 + m_RootOrder: 0
  82 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
  83 + m_AnchorMin: {x: 0, y: 0}
  84 + m_AnchorMax: {x: 0, y: 0}
  85 + m_AnchoredPosition: {x: 0, y: 0}
  86 + m_SizeDelta: {x: 0, y: 0}
  87 + m_Pivot: {x: 0.5, y: 0.5}
  1 +fileFormatVersion: 2
  2 +guid: 5e66896448428cf46a1854dbdc014914
  3 +timeCreated: 1601390136
  4 +licenseType: Store
  5 +NativeFormatImporter:
  6 + mainObjectFileID: 100100000
  7 + userData:
  8 + assetBundleName:
  9 + assetBundleVariant:
  1 +%YAML 1.1
  2 +%TAG !u! tag:unity3d.com,2011:
  3 +--- !u!1 &104862
  4 +GameObject:
  5 + m_ObjectHideFlags: 0
  6 + m_PrefabParentObject: {fileID: 0}
  7 + m_PrefabInternal: {fileID: 100100000}
  8 + serializedVersion: 5
  9 + m_Component:
  10 + - component: {fileID: 22461494}
  11 + - component: {fileID: 22233942}
  12 + - component: {fileID: 11411806}
  13 + m_Layer: 5
  14 + m_Name: LogCount
  15 + m_TagString: Untagged
  16 + m_Icon: {fileID: 0}
  17 + m_NavMeshLayer: 0
  18 + m_StaticEditorFlags: 0
  19 + m_IsActive: 0
  20 +--- !u!1 &151462
  21 +GameObject:
  22 + m_ObjectHideFlags: 1
  23 + m_PrefabParentObject: {fileID: 0}
  24 + m_PrefabInternal: {fileID: 100100000}
  25 + serializedVersion: 5
  26 + m_Component:
  27 + - component: {fileID: 22420350}
  28 + - component: {fileID: 22200920}
  29 + - component: {fileID: 11432936}
  30 + m_Layer: 5
  31 + m_Name: LogCountText
  32 + m_TagString: Untagged
  33 + m_Icon: {fileID: 0}
  34 + m_NavMeshLayer: 0
  35 + m_StaticEditorFlags: 0
  36 + m_IsActive: 1
  37 +--- !u!1 &152362
  38 +GameObject:
  39 + m_ObjectHideFlags: 0
  40 + m_PrefabParentObject: {fileID: 0}
  41 + m_PrefabInternal: {fileID: 100100000}
  42 + serializedVersion: 5
  43 + m_Component:
  44 + - component: {fileID: 22427300}
  45 + - component: {fileID: 22262284}
  46 + - component: {fileID: 11404142}
  47 + m_Layer: 5
  48 + m_Name: LogType
  49 + m_TagString: Untagged
  50 + m_Icon: {fileID: 0}
  51 + m_NavMeshLayer: 0
  52 + m_StaticEditorFlags: 0
  53 + m_IsActive: 1
  54 +--- !u!1 &166880
  55 +GameObject:
  56 + m_ObjectHideFlags: 0
  57 + m_PrefabParentObject: {fileID: 0}
  58 + m_PrefabInternal: {fileID: 100100000}
  59 + serializedVersion: 5
  60 + m_Component:
  61 + - component: {fileID: 22479264}
  62 + - component: {fileID: 22288988}
  63 + - component: {fileID: 11459012}
  64 + - component: {fileID: 11408050}
  65 + - component: {fileID: 11456372}
  66 + - component: {fileID: 225819852034701160}
  67 + m_Layer: 5
  68 + m_Name: DebugLogItem
  69 + m_TagString: Untagged
  70 + m_Icon: {fileID: 0}
  71 + m_NavMeshLayer: 0
  72 + m_StaticEditorFlags: 0
  73 + m_IsActive: 1
  74 +--- !u!114 &11404142
  75 +MonoBehaviour:
  76 + m_ObjectHideFlags: 1
  77 + m_PrefabParentObject: {fileID: 0}
  78 + m_PrefabInternal: {fileID: 100100000}
  79 + m_GameObject: {fileID: 152362}
  80 + m_Enabled: 1
  81 + m_EditorHideFlags: 0
  82 + m_Script: {fileID: -765806418, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3}
  83 + m_Name:
  84 + m_EditorClassIdentifier:
  85 + m_Material: {fileID: 0}
  86 + m_Color: {r: 1, g: 1, b: 1, a: 1}
  87 + m_RaycastTarget: 0
  88 + m_OnCullStateChanged:
  89 + m_PersistentCalls:
  90 + m_Calls: []
  91 + m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
  92 + Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
  93 + m_Sprite: {fileID: 21300000, guid: 33b115bf5efdfa04d8e2e0b70a6643cd, type: 3}
  94 + m_Type: 0
  95 + m_PreserveAspect: 0
  96 + m_FillCenter: 1
  97 + m_FillMethod: 4
  98 + m_FillAmount: 1
  99 + m_FillClockwise: 1
  100 + m_FillOrigin: 0
  101 +--- !u!114 &11408050
  102 +MonoBehaviour:
  103 + m_ObjectHideFlags: 1
  104 + m_PrefabParentObject: {fileID: 0}
  105 + m_PrefabInternal: {fileID: 100100000}
  106 + m_GameObject: {fileID: 166880}
  107 + m_Enabled: 1
  108 + m_EditorHideFlags: 0
  109 + m_Script: {fileID: 11500000, guid: d2ea291be9de70a4abfec595203c96c1, type: 3}
  110 + m_Name:
  111 + m_EditorClassIdentifier:
  112 + transformComponent: {fileID: 22479264}
  113 + imageComponent: {fileID: 11459012}
  114 + canvasGroupComponent: {fileID: 225819852034701160}
  115 + logText: {fileID: 114694493629914950}
  116 + logTypeImage: {fileID: 11404142}
  117 + logCountParent: {fileID: 104862}
  118 + logCountText: {fileID: 11432936}
  119 + copyLogButton: {fileID: 224006190298411330}
  120 +--- !u!114 &11411806
  121 +MonoBehaviour:
  122 + m_ObjectHideFlags: 1
  123 + m_PrefabParentObject: {fileID: 0}
  124 + m_PrefabInternal: {fileID: 100100000}
  125 + m_GameObject: {fileID: 104862}
  126 + m_Enabled: 1
  127 + m_EditorHideFlags: 0
  128 + m_Script: {fileID: -765806418, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3}
  129 + m_Name:
  130 + m_EditorClassIdentifier:
  131 + m_Material: {fileID: 0}
  132 + m_Color: {r: 0.42647058, g: 0.42647058, b: 0.42647058, a: 1}
  133 + m_RaycastTarget: 0
  134 + m_OnCullStateChanged:
  135 + m_PersistentCalls:
  136 + m_Calls: []
  137 + m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
  138 + Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
  139 + m_Sprite: {fileID: 21300000, guid: b3f0d976f6d6802479d6465d11b3aa68, type: 3}
  140 + m_Type: 1
  141 + m_PreserveAspect: 0
  142 + m_FillCenter: 1
  143 + m_FillMethod: 4
  144 + m_FillAmount: 1
  145 + m_FillClockwise: 1
  146 + m_FillOrigin: 0
  147 +--- !u!114 &11432936
  148 +MonoBehaviour:
  149 + m_ObjectHideFlags: 1
  150 + m_PrefabParentObject: {fileID: 0}
  151 + m_PrefabInternal: {fileID: 100100000}
  152 + m_GameObject: {fileID: 151462}
  153 + m_Enabled: 1
  154 + m_EditorHideFlags: 0
  155 + m_Script: {fileID: 708705254, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3}
  156 + m_Name:
  157 + m_EditorClassIdentifier:
  158 + m_Material: {fileID: 0}
  159 + m_Color: {r: 0.83823526, g: 0.84439874, b: 0.84439874, a: 1}
  160 + m_RaycastTarget: 0
  161 + m_OnCullStateChanged:
  162 + m_PersistentCalls:
  163 + m_Calls: []
  164 + m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
  165 + Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
  166 + m_FontData:
  167 + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
  168 + m_FontSize: 16
  169 + m_FontStyle: 0
  170 + m_BestFit: 1
  171 + m_MinSize: 1
  172 + m_MaxSize: 16
  173 + m_Alignment: 4
  174 + m_AlignByGeometry: 0
  175 + m_RichText: 1
  176 + m_HorizontalOverflow: 0
  177 + m_VerticalOverflow: 0
  178 + m_LineSpacing: 1
  179 + m_Text: 1
  180 +--- !u!114 &11456372
  181 +MonoBehaviour:
  182 + m_ObjectHideFlags: 1
  183 + m_PrefabParentObject: {fileID: 0}
  184 + m_PrefabInternal: {fileID: 100100000}
  185 + m_GameObject: {fileID: 166880}
  186 + m_Enabled: 1
  187 + m_EditorHideFlags: 0
  188 + m_Script: {fileID: 1392445389, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3}
  189 + m_Name:
  190 + m_EditorClassIdentifier:
  191 + m_Navigation:
  192 + m_Mode: 3
  193 + m_SelectOnUp: {fileID: 0}
  194 + m_SelectOnDown: {fileID: 0}
  195 + m_SelectOnLeft: {fileID: 0}
  196 + m_SelectOnRight: {fileID: 0}
  197 + m_Transition: 1
  198 + m_Colors:
  199 + m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
  200 + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
  201 + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
  202 + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
  203 + m_ColorMultiplier: 1
  204 + m_FadeDuration: 0.1
  205 + m_SpriteState:
  206 + m_HighlightedSprite: {fileID: 0}
  207 + m_PressedSprite: {fileID: 0}
  208 + m_DisabledSprite: {fileID: 0}
  209 + m_AnimationTriggers:
  210 + m_NormalTrigger: Normal
  211 + m_HighlightedTrigger: Highlighted
  212 + m_PressedTrigger: Pressed
  213 + m_DisabledTrigger: Disabled
  214 + m_Interactable: 1
  215 + m_TargetGraphic: {fileID: 11459012}
  216 + m_OnClick:
  217 + m_PersistentCalls:
  218 + m_Calls: []
  219 + m_TypeName: UnityEngine.UI.Button+ButtonClickedEvent, UnityEngine.UI, Version=1.0.0.0,
  220 + Culture=neutral, PublicKeyToken=null
  221 +--- !u!114 &11459012
  222 +MonoBehaviour:
  223 + m_ObjectHideFlags: 1
  224 + m_PrefabParentObject: {fileID: 0}
  225 + m_PrefabInternal: {fileID: 100100000}
  226 + m_GameObject: {fileID: 166880}
  227 + m_Enabled: 1
  228 + m_EditorHideFlags: 0
  229 + m_Script: {fileID: -765806418, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3}
  230 + m_Name:
  231 + m_EditorClassIdentifier:
  232 + m_Material: {fileID: 0}
  233 + m_Color: {r: 0.23529412, g: 0.23529412, b: 0.23529412, a: 0.697}
  234 + m_RaycastTarget: 1
  235 + m_OnCullStateChanged:
  236 + m_PersistentCalls:
  237 + m_Calls: []
  238 + m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
  239 + Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
  240 + m_Sprite: {fileID: 21300000, guid: 98e8e1cf8dc7dbf469617c2e40c8a944, type: 3}
  241 + m_Type: 1
  242 + m_PreserveAspect: 0
  243 + m_FillCenter: 1
  244 + m_FillMethod: 4
  245 + m_FillAmount: 1
  246 + m_FillClockwise: 1
  247 + m_FillOrigin: 0
  248 +--- !u!222 &22200920
  249 +CanvasRenderer:
  250 + m_ObjectHideFlags: 1
  251 + m_PrefabParentObject: {fileID: 0}
  252 + m_PrefabInternal: {fileID: 100100000}
  253 + m_GameObject: {fileID: 151462}
  254 +--- !u!222 &22233942
  255 +CanvasRenderer:
  256 + m_ObjectHideFlags: 1
  257 + m_PrefabParentObject: {fileID: 0}
  258 + m_PrefabInternal: {fileID: 100100000}
  259 + m_GameObject: {fileID: 104862}
  260 +--- !u!222 &22262284
  261 +CanvasRenderer:
  262 + m_ObjectHideFlags: 1
  263 + m_PrefabParentObject: {fileID: 0}
  264 + m_PrefabInternal: {fileID: 100100000}
  265 + m_GameObject: {fileID: 152362}
  266 +--- !u!222 &22288988
  267 +CanvasRenderer:
  268 + m_ObjectHideFlags: 1
  269 + m_PrefabParentObject: {fileID: 0}
  270 + m_PrefabInternal: {fileID: 100100000}
  271 + m_GameObject: {fileID: 166880}
  272 +--- !u!224 &22420350
  273 +RectTransform:
  274 + m_ObjectHideFlags: 1
  275 + m_PrefabParentObject: {fileID: 0}
  276 + m_PrefabInternal: {fileID: 100100000}
  277 + m_GameObject: {fileID: 151462}
  278 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
  279 + m_LocalPosition: {x: 0, y: 0, z: 0}
  280 + m_LocalScale: {x: 1, y: 1, z: 1}
  281 + m_Children: []
  282 + m_Father: {fileID: 22461494}
  283 + m_RootOrder: 0
  284 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
  285 + m_AnchorMin: {x: 0, y: 0}
  286 + m_AnchorMax: {x: 1, y: 1}
  287 + m_AnchoredPosition: {x: 0, y: 0}
  288 + m_SizeDelta: {x: -2, y: 0}
  289 + m_Pivot: {x: 0.5, y: 0.5}
  290 +--- !u!224 &22427300
  291 +RectTransform:
  292 + m_ObjectHideFlags: 1
  293 + m_PrefabParentObject: {fileID: 0}
  294 + m_PrefabInternal: {fileID: 100100000}
  295 + m_GameObject: {fileID: 152362}
  296 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
  297 + m_LocalPosition: {x: 0, y: 0, z: 0}
  298 + m_LocalScale: {x: 1, y: 1, z: 1}
  299 + m_Children: []
  300 + m_Father: {fileID: 22479264}
  301 + m_RootOrder: 0
  302 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
  303 + m_AnchorMin: {x: 0, y: 0.5}
  304 + m_AnchorMax: {x: 0, y: 0.5}
  305 + m_AnchoredPosition: {x: 18, y: 0}
  306 + m_SizeDelta: {x: 25, y: 25}
  307 + m_Pivot: {x: 0.5, y: 0.5}
  308 +--- !u!224 &22461494
  309 +RectTransform:
  310 + m_ObjectHideFlags: 1
  311 + m_PrefabParentObject: {fileID: 0}
  312 + m_PrefabInternal: {fileID: 100100000}
  313 + m_GameObject: {fileID: 104862}
  314 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
  315 + m_LocalPosition: {x: 0, y: 0, z: 0}
  316 + m_LocalScale: {x: 1, y: 1, z: 1}
  317 + m_Children:
  318 + - {fileID: 22420350}
  319 + m_Father: {fileID: 22479264}
  320 + m_RootOrder: 2
  321 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
  322 + m_AnchorMin: {x: 1, y: 0.5}
  323 + m_AnchorMax: {x: 1, y: 0.5}
  324 + m_AnchoredPosition: {x: -28, y: 0}
  325 + m_SizeDelta: {x: 38, y: 28}
  326 + m_Pivot: {x: 0.5, y: 0.5}
  327 +--- !u!224 &22479264
  328 +RectTransform:
  329 + m_ObjectHideFlags: 1
  330 + m_PrefabParentObject: {fileID: 0}
  331 + m_PrefabInternal: {fileID: 100100000}
  332 + m_GameObject: {fileID: 166880}
  333 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
  334 + m_LocalPosition: {x: 0, y: 0, z: 0}
  335 + m_LocalScale: {x: 1, y: 1, z: 1}
  336 + m_Children:
  337 + - {fileID: 22427300}
  338 + - {fileID: 224737693311518052}
  339 + - {fileID: 22461494}
  340 + - {fileID: 224006190298411330}
  341 + m_Father: {fileID: 0}
  342 + m_RootOrder: 0
  343 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
  344 + m_AnchorMin: {x: 0, y: 1}
  345 + m_AnchorMax: {x: 1, y: 1}
  346 + m_AnchoredPosition: {x: 0, y: 0}
  347 + m_SizeDelta: {x: 0, y: 35}
  348 + m_Pivot: {x: 0, y: 1}
  349 +--- !u!1001 &100100000
  350 +Prefab:
  351 + m_ObjectHideFlags: 1
  352 + serializedVersion: 2
  353 + m_Modification:
  354 + m_TransformParent: {fileID: 0}
  355 + m_Modifications: []
  356 + m_RemovedComponents: []
  357 + m_ParentPrefab: {fileID: 0}
  358 + m_RootGameObject: {fileID: 166880}
  359 + m_IsPrefabParent: 1
  360 +--- !u!1 &1396836967994216
  361 +GameObject:
  362 + m_ObjectHideFlags: 0
  363 + m_PrefabParentObject: {fileID: 0}
  364 + m_PrefabInternal: {fileID: 100100000}
  365 + serializedVersion: 5
  366 + m_Component:
  367 + - component: {fileID: 224006190298411330}
  368 + - component: {fileID: 222870443111501910}
  369 + - component: {fileID: 114119781176956926}
  370 + - component: {fileID: 114694923173451186}
  371 + m_Layer: 5
  372 + m_Name: CopyLogButton
  373 + m_TagString: Untagged
  374 + m_Icon: {fileID: 0}
  375 + m_NavMeshLayer: 0
  376 + m_StaticEditorFlags: 0
  377 + m_IsActive: 0
  378 +--- !u!1 &1503640463151286
  379 +GameObject:
  380 + m_ObjectHideFlags: 1
  381 + m_PrefabParentObject: {fileID: 0}
  382 + m_PrefabInternal: {fileID: 100100000}
  383 + serializedVersion: 5
  384 + m_Component:
  385 + - component: {fileID: 224887990600088790}
  386 + - component: {fileID: 222313182602304162}
  387 + - component: {fileID: 114549765989288124}
  388 + m_Layer: 5
  389 + m_Name: Text
  390 + m_TagString: Untagged
  391 + m_Icon: {fileID: 0}
  392 + m_NavMeshLayer: 0
  393 + m_StaticEditorFlags: 0
  394 + m_IsActive: 1
  395 +--- !u!1 &1785910143472904
  396 +GameObject:
  397 + m_ObjectHideFlags: 0
  398 + m_PrefabParentObject: {fileID: 0}
  399 + m_PrefabInternal: {fileID: 100100000}
  400 + serializedVersion: 5
  401 + m_Component:
  402 + - component: {fileID: 224737693311518052}
  403 + - component: {fileID: 222175805939703770}
  404 + - component: {fileID: 114694493629914950}
  405 + m_Layer: 5
  406 + m_Name: LogText
  407 + m_TagString: Untagged
  408 + m_Icon: {fileID: 0}
  409 + m_NavMeshLayer: 0
  410 + m_StaticEditorFlags: 0
  411 + m_IsActive: 1
  412 +--- !u!114 &114119781176956926
  413 +MonoBehaviour:
  414 + m_ObjectHideFlags: 1
  415 + m_PrefabParentObject: {fileID: 0}
  416 + m_PrefabInternal: {fileID: 100100000}
  417 + m_GameObject: {fileID: 1396836967994216}
  418 + m_Enabled: 1
  419 + m_EditorHideFlags: 0
  420 + m_Script: {fileID: -765806418, guid: f70555f144d8491a825f0804e09c671c, type: 3}
  421 + m_Name:
  422 + m_EditorClassIdentifier:
  423 + m_Material: {fileID: 0}
  424 + m_Color: {r: 0.42647058, g: 0.42647058, b: 0.42647058, a: 1}
  425 + m_RaycastTarget: 1
  426 + m_OnCullStateChanged:
  427 + m_PersistentCalls:
  428 + m_Calls: []
  429 + m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
  430 + Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
  431 + m_Sprite: {fileID: 21300000, guid: 066d3840badf4d24dba1d42b4c59b888, type: 3}
  432 + m_Type: 1
  433 + m_PreserveAspect: 0
  434 + m_FillCenter: 1
  435 + m_FillMethod: 4
  436 + m_FillAmount: 1
  437 + m_FillClockwise: 1
  438 + m_FillOrigin: 0
  439 +--- !u!114 &114549765989288124
  440 +MonoBehaviour:
  441 + m_ObjectHideFlags: 1
  442 + m_PrefabParentObject: {fileID: 0}
  443 + m_PrefabInternal: {fileID: 100100000}
  444 + m_GameObject: {fileID: 1503640463151286}
  445 + m_Enabled: 1
  446 + m_EditorHideFlags: 0
  447 + m_Script: {fileID: 708705254, guid: f70555f144d8491a825f0804e09c671c, type: 3}
  448 + m_Name:
  449 + m_EditorClassIdentifier:
  450 + m_Material: {fileID: 0}
  451 + m_Color: {r: 0.83823526, g: 0.84439874, b: 0.84439874, a: 1}
  452 + m_RaycastTarget: 0
  453 + m_OnCullStateChanged:
  454 + m_PersistentCalls:
  455 + m_Calls: []
  456 + m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
  457 + Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
  458 + m_FontData:
  459 + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
  460 + m_FontSize: 16
  461 + m_FontStyle: 0
  462 + m_BestFit: 0
  463 + m_MinSize: 1
  464 + m_MaxSize: 40
  465 + m_Alignment: 4
  466 + m_AlignByGeometry: 0
  467 + m_RichText: 1
  468 + m_HorizontalOverflow: 0
  469 + m_VerticalOverflow: 0
  470 + m_LineSpacing: 1
  471 + m_Text: Copy
  472 +--- !u!114 &114694493629914950
  473 +MonoBehaviour:
  474 + m_ObjectHideFlags: 1
  475 + m_PrefabParentObject: {fileID: 0}
  476 + m_PrefabInternal: {fileID: 100100000}
  477 + m_GameObject: {fileID: 1785910143472904}
  478 + m_Enabled: 1
  479 + m_EditorHideFlags: 0
  480 + m_Script: {fileID: 708705254, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3}
  481 + m_Name:
  482 + m_EditorClassIdentifier:
  483 + m_Material: {fileID: 0}
  484 + m_Color: {r: 0.83823526, g: 0.84439874, b: 0.84439874, a: 1}
  485 + m_RaycastTarget: 0
  486 + m_OnCullStateChanged:
  487 + m_PersistentCalls:
  488 + m_Calls: []
  489 + m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
  490 + Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
  491 + m_FontData:
  492 + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
  493 + m_FontSize: 15
  494 + m_FontStyle: 0
  495 + m_BestFit: 0
  496 + m_MinSize: 1
  497 + m_MaxSize: 40
  498 + m_Alignment: 3
  499 + m_AlignByGeometry: 0
  500 + m_RichText: 1
  501 + m_HorizontalOverflow: 1
  502 + m_VerticalOverflow: 0
  503 + m_LineSpacing: 1
  504 + m_Text: Debug.Log summary
  505 +--- !u!114 &114694923173451186
  506 +MonoBehaviour:
  507 + m_ObjectHideFlags: 1
  508 + m_PrefabParentObject: {fileID: 0}
  509 + m_PrefabInternal: {fileID: 100100000}
  510 + m_GameObject: {fileID: 1396836967994216}
  511 + m_Enabled: 1
  512 + m_EditorHideFlags: 0
  513 + m_Script: {fileID: 1392445389, guid: f70555f144d8491a825f0804e09c671c, type: 3}
  514 + m_Name:
  515 + m_EditorClassIdentifier:
  516 + m_Navigation:
  517 + m_Mode: 3
  518 + m_SelectOnUp: {fileID: 0}
  519 + m_SelectOnDown: {fileID: 0}
  520 + m_SelectOnLeft: {fileID: 0}
  521 + m_SelectOnRight: {fileID: 0}
  522 + m_Transition: 1
  523 + m_Colors:
  524 + m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
  525 + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
  526 + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
  527 + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
  528 + m_ColorMultiplier: 1
  529 + m_FadeDuration: 0.1
  530 + m_SpriteState:
  531 + m_HighlightedSprite: {fileID: 0}
  532 + m_PressedSprite: {fileID: 0}
  533 + m_DisabledSprite: {fileID: 0}
  534 + m_AnimationTriggers:
  535 + m_NormalTrigger: Normal
  536 + m_HighlightedTrigger: Highlighted
  537 + m_PressedTrigger: Pressed
  538 + m_DisabledTrigger: Disabled
  539 + m_Interactable: 1
  540 + m_TargetGraphic: {fileID: 114119781176956926}
  541 + m_OnClick:
  542 + m_PersistentCalls:
  543 + m_Calls:
  544 + - m_Target: {fileID: 11408050}
  545 + m_MethodName: CopyLog
  546 + m_Mode: 1
  547 + m_Arguments:
  548 + m_ObjectArgument: {fileID: 0}
  549 + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
  550 + m_IntArgument: 0
  551 + m_FloatArgument: 0
  552 + m_StringArgument:
  553 + m_BoolArgument: 0
  554 + m_CallState: 2
  555 + m_TypeName: UnityEngine.UI.Button+ButtonClickedEvent, UnityEngine.UI, Version=1.0.0.0,
  556 + Culture=neutral, PublicKeyToken=null
  557 +--- !u!222 &222175805939703770
  558 +CanvasRenderer:
  559 + m_ObjectHideFlags: 1
  560 + m_PrefabParentObject: {fileID: 0}
  561 + m_PrefabInternal: {fileID: 100100000}
  562 + m_GameObject: {fileID: 1785910143472904}
  563 +--- !u!222 &222313182602304162
  564 +CanvasRenderer:
  565 + m_ObjectHideFlags: 1
  566 + m_PrefabParentObject: {fileID: 0}
  567 + m_PrefabInternal: {fileID: 100100000}
  568 + m_GameObject: {fileID: 1503640463151286}
  569 +--- !u!222 &222870443111501910
  570 +CanvasRenderer:
  571 + m_ObjectHideFlags: 1
  572 + m_PrefabParentObject: {fileID: 0}
  573 + m_PrefabInternal: {fileID: 100100000}
  574 + m_GameObject: {fileID: 1396836967994216}
  575 +--- !u!224 &224006190298411330
  576 +RectTransform:
  577 + m_ObjectHideFlags: 1
  578 + m_PrefabParentObject: {fileID: 0}
  579 + m_PrefabInternal: {fileID: 100100000}
  580 + m_GameObject: {fileID: 1396836967994216}
  581 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
  582 + m_LocalPosition: {x: 0, y: 0, z: 0}
  583 + m_LocalScale: {x: 1, y: 1, z: 1}
  584 + m_Children:
  585 + - {fileID: 224887990600088790}
  586 + m_Father: {fileID: 22479264}
  587 + m_RootOrder: 3
  588 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
  589 + m_AnchorMin: {x: 0, y: 0}
  590 + m_AnchorMax: {x: 1, y: 0}
  591 + m_AnchoredPosition: {x: 0, y: 2}
  592 + m_SizeDelta: {x: -70, y: 36}
  593 + m_Pivot: {x: 0.5, y: 0}
  594 +--- !u!224 &224737693311518052
  595 +RectTransform:
  596 + m_ObjectHideFlags: 1
  597 + m_PrefabParentObject: {fileID: 0}
  598 + m_PrefabInternal: {fileID: 100100000}
  599 + m_GameObject: {fileID: 1785910143472904}
  600 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
  601 + m_LocalPosition: {x: 0, y: 0, z: 0}
  602 + m_LocalScale: {x: 1, y: 1, z: 1}
  603 + m_Children: []
  604 + m_Father: {fileID: 22479264}
  605 + m_RootOrder: 1
  606 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
  607 + m_AnchorMin: {x: 0, y: 0}
  608 + m_AnchorMax: {x: 1, y: 1}
  609 + m_AnchoredPosition: {x: 15, y: 0}
  610 + m_SizeDelta: {x: -40, y: -2}
  611 + m_Pivot: {x: 0.5, y: 0.5}
  612 +--- !u!224 &224887990600088790
  613 +RectTransform:
  614 + m_ObjectHideFlags: 1
  615 + m_PrefabParentObject: {fileID: 0}
  616 + m_PrefabInternal: {fileID: 100100000}
  617 + m_GameObject: {fileID: 1503640463151286}
  618 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
  619 + m_LocalPosition: {x: 0, y: 0, z: 0}
  620 + m_LocalScale: {x: 1, y: 1, z: 1}
  621 + m_Children: []
  622 + m_Father: {fileID: 224006190298411330}
  623 + m_RootOrder: 0
  624 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
  625 + m_AnchorMin: {x: 0, y: 0}
  626 + m_AnchorMax: {x: 1, y: 1}
  627 + m_AnchoredPosition: {x: 0, y: 0}
  628 + m_SizeDelta: {x: 0, y: 0}
  629 + m_Pivot: {x: 0.5, y: 0.5}
  630 +--- !u!225 &225819852034701160
  631 +CanvasGroup:
  632 + m_ObjectHideFlags: 1
  633 + m_PrefabParentObject: {fileID: 0}
  634 + m_PrefabInternal: {fileID: 100100000}
  635 + m_GameObject: {fileID: 166880}
  636 + m_Enabled: 1
  637 + m_Alpha: 1
  638 + m_Interactable: 1
  639 + m_BlocksRaycasts: 1
  640 + m_IgnoreParentGroups: 0
  1 +fileFormatVersion: 2
  2 +guid: 391be5df5ef62f345bb76a1051c04da7
  3 +timeCreated: 1465919887
  4 +licenseType: Store
  5 +NativeFormatImporter:
  6 + userData:
  7 + assetBundleName:
  8 + assetBundleVariant:
  1 += In-game Debug Console (v1.6.8) =
  2 +
  3 +Documentation: https://github.com/yasirkula/UnityIngameDebugConsole
  4 +FAQ: https://github.com/yasirkula/UnityIngameDebugConsole#faq
  5 +E-mail: yasirkula@gmail.com
  6 +
  7 +You can simply place the IngameDebugConsole prefab to your scene. Hovering the cursor over its properties in the Inspector will reveal explanatory tooltips.
  1 +fileFormatVersion: 2
  2 +guid: edf2ac73f7bc3064c96d53009106dc53
  3 +timeCreated: 1563307881
  4 +licenseType: Store
  5 +TextScriptImporter:
  6 + userData:
  7 + assetBundleName:
  8 + assetBundleVariant:
  1 +fileFormatVersion: 2
  2 +guid: 860c08388401a6d4e858fe4910ea9337
  3 +folderAsset: yes
  4 +timeCreated: 1465930645
  5 +licenseType: Store
  6 +DefaultImporter:
  7 + userData:
  8 + assetBundleName:
  9 + assetBundleVariant:
  1 +using System;
  2 +using UnityEngine;
  3 +
  4 +namespace IngameDebugConsole
  5 +{
  6 + public class CircularBuffer<T>
  7 + {
  8 + private readonly T[] array;
  9 + private int startIndex;
  10 +
  11 + public int Count { get; private set; }
  12 + public T this[int index] { get { return array[( startIndex + index ) % array.Length]; } }
  13 +
  14 + public CircularBuffer( int capacity )
  15 + {
  16 + array = new T[capacity];
  17 + }
  18 +
  19 + // Old elements are overwritten when capacity is reached
  20 + public void Add( T value )
  21 + {
  22 + if( Count < array.Length )
  23 + array[Count++] = value;
  24 + else
  25 + {
  26 + array[startIndex] = value;
  27 + if( ++startIndex >= array.Length )
  28 + startIndex = 0;
  29 + }
  30 + }
  31 + }
  32 +
  33 + public class DynamicCircularBuffer<T>
  34 + {
  35 + private T[] array;
  36 + private int startIndex;
  37 +
  38 + public int Count { get; private set; }
  39 + public int Capacity { get { return array.Length; } }
  40 +
  41 + public T this[int index]
  42 + {
  43 + get { return array[( startIndex + index ) % array.Length]; }
  44 + set { array[( startIndex + index ) % array.Length] = value; }
  45 + }
  46 +
  47 + public DynamicCircularBuffer( int initialCapacity = 2 )
  48 + {
  49 + array = new T[initialCapacity];
  50 + }
  51 +
  52 + private void SetCapacity( int capacity )
  53 + {
  54 + T[] newArray = new T[capacity];
  55 + if( Count > 0 )
  56 + {
  57 + int elementsBeforeWrap = Mathf.Min( Count, array.Length - startIndex );
  58 + Array.Copy( array, startIndex, newArray, 0, elementsBeforeWrap );
  59 + if( elementsBeforeWrap < Count )
  60 + Array.Copy( array, 0, newArray, elementsBeforeWrap, Count - elementsBeforeWrap );
  61 + }
  62 +
  63 + array = newArray;
  64 + startIndex = 0;
  65 + }
  66 +
  67 + /// <summary>Inserts the value to the beginning of the collection.</summary>
  68 + public void AddFirst( T value )
  69 + {
  70 + if( array.Length == Count )
  71 + SetCapacity( Mathf.Max( array.Length * 2, 4 ) );
  72 +
  73 + startIndex = ( startIndex > 0 ) ? ( startIndex - 1 ) : ( array.Length - 1 );
  74 + array[startIndex] = value;
  75 + Count++;
  76 + }
  77 +
  78 + /// <summary>Adds the value to the end of the collection.</summary>
  79 + public void Add( T value )
  80 + {
  81 + if( array.Length == Count )
  82 + SetCapacity( Mathf.Max( array.Length * 2, 4 ) );
  83 +
  84 + this[Count++] = value;
  85 + }
  86 +
  87 + public void AddRange( DynamicCircularBuffer<T> other )
  88 + {
  89 + if( other.Count == 0 )
  90 + return;
  91 +
  92 + if( array.Length < Count + other.Count )
  93 + SetCapacity( Mathf.Max( array.Length * 2, Count + other.Count ) );
  94 +
  95 + int insertStartIndex = ( startIndex + Count ) % array.Length;
  96 + int elementsBeforeWrap = Mathf.Min( other.Count, array.Length - insertStartIndex );
  97 + int otherElementsBeforeWrap = Mathf.Min( other.Count, other.array.Length - other.startIndex );
  98 +
  99 + Array.Copy( other.array, other.startIndex, array, insertStartIndex, Mathf.Min( elementsBeforeWrap, otherElementsBeforeWrap ) );
  100 + if( elementsBeforeWrap < otherElementsBeforeWrap ) // This array wrapped before the other array
  101 + Array.Copy( other.array, other.startIndex + elementsBeforeWrap, array, 0, otherElementsBeforeWrap - elementsBeforeWrap );
  102 + else if( elementsBeforeWrap > otherElementsBeforeWrap ) // The other array wrapped before this array
  103 + Array.Copy( other.array, 0, array, insertStartIndex + otherElementsBeforeWrap, elementsBeforeWrap - otherElementsBeforeWrap );
  104 +
  105 + int copiedElements = Mathf.Max( elementsBeforeWrap, otherElementsBeforeWrap );
  106 + if( copiedElements < other.Count ) // Both arrays wrapped and there's still some elements left to copy
  107 + Array.Copy( other.array, copiedElements - otherElementsBeforeWrap, array, copiedElements - elementsBeforeWrap, other.Count - copiedElements );
  108 +
  109 + Count += other.Count;
  110 + }
  111 +
  112 + public T RemoveFirst()
  113 + {
  114 + T element = array[startIndex];
  115 + array[startIndex] = default( T );
  116 +
  117 + if( ++startIndex == array.Length )
  118 + startIndex = 0;
  119 +
  120 + Count--;
  121 + return element;
  122 + }
  123 +
  124 + public T RemoveLast()
  125 + {
  126 + int index = ( startIndex + Count - 1 ) % array.Length;
  127 + T element = array[index];
  128 + array[index] = default( T );
  129 +
  130 + Count--;
  131 + return element;
  132 + }
  133 +
  134 + public int RemoveAll( Predicate<T> shouldRemoveElement )
  135 + {
  136 + return RemoveAll<T>( shouldRemoveElement, null, null );
  137 + }
  138 +
  139 + public int RemoveAll<Y>( Predicate<T> shouldRemoveElement, Action<T, int> onElementIndexChanged, DynamicCircularBuffer<Y> synchronizedBuffer )
  140 + {
  141 + Y[] synchronizedArray = ( synchronizedBuffer != null ) ? synchronizedBuffer.array : null;
  142 + int elementsBeforeWrap = Mathf.Min( Count, array.Length - startIndex );
  143 + int removedElements = 0;
  144 + int i = startIndex, newIndex = startIndex, endIndex = startIndex + elementsBeforeWrap;
  145 + for( ; i < endIndex; i++ )
  146 + {
  147 + if( shouldRemoveElement( array[i] ) )
  148 + removedElements++;
  149 + else
  150 + {
  151 + if( removedElements > 0 )
  152 + {
  153 + T element = array[i];
  154 + array[newIndex] = element;
  155 +
  156 + if( synchronizedArray != null )
  157 + synchronizedArray[newIndex] = synchronizedArray[i];
  158 +
  159 + if( onElementIndexChanged != null )
  160 + onElementIndexChanged( element, newIndex - startIndex );
  161 + }
  162 +
  163 + newIndex++;
  164 + }
  165 + }
  166 +
  167 + i = 0;
  168 + endIndex = Count - elementsBeforeWrap;
  169 +
  170 + if( newIndex < array.Length )
  171 + {
  172 + for( ; i < endIndex; i++ )
  173 + {
  174 + if( shouldRemoveElement( array[i] ) )
  175 + removedElements++;
  176 + else
  177 + {
  178 + T element = array[i];
  179 + array[newIndex] = element;
  180 +
  181 + if( synchronizedArray != null )
  182 + synchronizedArray[newIndex] = synchronizedArray[i];
  183 +
  184 + if( onElementIndexChanged != null )
  185 + onElementIndexChanged( element, newIndex - startIndex );
  186 +
  187 + if( ++newIndex == array.Length )
  188 + {
  189 + i++;
  190 + break;
  191 + }
  192 + }
  193 + }
  194 + }
  195 +
  196 + if( newIndex == array.Length )
  197 + {
  198 + newIndex = 0;
  199 + for( ; i < endIndex; i++ )
  200 + {
  201 + if( shouldRemoveElement( array[i] ) )
  202 + removedElements++;
  203 + else
  204 + {
  205 + if( removedElements > 0 )
  206 + {
  207 + T element = array[i];
  208 + array[newIndex] = element;
  209 +
  210 + if( synchronizedArray != null )
  211 + synchronizedArray[newIndex] = synchronizedArray[i];
  212 +
  213 + if( onElementIndexChanged != null )
  214 + onElementIndexChanged( element, newIndex + elementsBeforeWrap );
  215 + }
  216 +
  217 + newIndex++;
  218 + }
  219 + }
  220 + }
  221 +
  222 + TrimEnd( removedElements );
  223 + if( synchronizedBuffer != null )
  224 + synchronizedBuffer.TrimEnd( removedElements );
  225 +
  226 + return removedElements;
  227 + }
  228 +
  229 + public void TrimStart( int trimCount, Action<T> perElementCallback = null )
  230 + {
  231 + TrimInternal( trimCount, startIndex, perElementCallback );
  232 + startIndex = ( startIndex + trimCount ) % array.Length;
  233 + }
  234 +
  235 + public void TrimEnd( int trimCount, Action<T> perElementCallback = null )
  236 + {
  237 + TrimInternal( trimCount, ( startIndex + Count - trimCount ) % array.Length, perElementCallback );
  238 + }
  239 +
  240 + private void TrimInternal( int trimCount, int startIndex, Action<T> perElementCallback )
  241 + {
  242 + int elementsBeforeWrap = Mathf.Min( trimCount, array.Length - startIndex );
  243 + if( perElementCallback == null )
  244 + {
  245 + Array.Clear( array, startIndex, elementsBeforeWrap );
  246 + if( elementsBeforeWrap < trimCount )
  247 + Array.Clear( array, 0, trimCount - elementsBeforeWrap );
  248 + }
  249 + else
  250 + {
  251 + for( int i = startIndex, endIndex = startIndex + elementsBeforeWrap; i < endIndex; i++ )
  252 + {
  253 + perElementCallback( array[i] );
  254 + array[i] = default( T );
  255 + }
  256 +
  257 + for( int i = 0, endIndex = trimCount - elementsBeforeWrap; i < endIndex; i++ )
  258 + {
  259 + perElementCallback( array[i] );
  260 + array[i] = default( T );
  261 + }
  262 + }
  263 +
  264 + Count -= trimCount;
  265 + }
  266 +
  267 + public void Clear()
  268 + {
  269 + int elementsBeforeWrap = Mathf.Min( Count, array.Length - startIndex );
  270 + Array.Clear( array, startIndex, elementsBeforeWrap );
  271 + if( elementsBeforeWrap < Count )
  272 + Array.Clear( array, 0, Count - elementsBeforeWrap );
  273 +
  274 + startIndex = 0;
  275 + Count = 0;
  276 + }
  277 +
  278 + public int IndexOf( T value )
  279 + {
  280 + int elementsBeforeWrap = Mathf.Min( Count, array.Length - startIndex );
  281 + int index = Array.IndexOf( array, value, startIndex, elementsBeforeWrap );
  282 + if( index >= 0 )
  283 + return index - startIndex;
  284 +
  285 + if( elementsBeforeWrap < Count )
  286 + {
  287 + index = Array.IndexOf( array, value, 0, Count - elementsBeforeWrap );
  288 + if( index >= 0 )
  289 + return index + elementsBeforeWrap;
  290 + }
  291 +
  292 + return -1;
  293 + }
  294 +
  295 + public void ForEach( Action<T> action )
  296 + {
  297 + int elementsBeforeWrap = Mathf.Min( Count, array.Length - startIndex );
  298 + for( int i = startIndex, endIndex = startIndex + elementsBeforeWrap; i < endIndex; i++ )
  299 + action( array[i] );
  300 + for( int i = 0, endIndex = Count - elementsBeforeWrap; i < endIndex; i++ )
  301 + action( array[i] );
  302 + }
  303 + }
  304 +}
  1 +fileFormatVersion: 2
  2 +guid: 6136cb3c00eac0149901b8e7f2fecef8
  3 +timeCreated: 1550943949
  4 +licenseType: Store
  5 +MonoImporter:
  6 + serializedVersion: 2
  7 + defaultReferences: []
  8 + executionOrder: 0
  9 + icon: {instanceID: 0}
  10 + userData:
  11 + assetBundleName:
  12 + assetBundleVariant:
  1 +fileFormatVersion: 2
  2 +guid: bb9b6e1ab379cec46bfae8f8abcc1f45
  3 +folderAsset: yes
  4 +DefaultImporter:
  5 + externalObjects: {}
  6 + userData:
  7 + assetBundleName:
  8 + assetBundleVariant:
  1 +#if IDG_ENABLE_HELPER_COMMANDS
  2 +using UnityEngine;
  3 +
  4 +namespace IngameDebugConsole.Commands
  5 +{
  6 + public class PlayerPrefsCommands
  7 + {
  8 + [ConsoleMethod( "prefs.int", "Returns the value of an Integer PlayerPrefs field" ), UnityEngine.Scripting.Preserve]
  9 + public static string PlayerPrefsGetInt( string key )
  10 + {
  11 + if( !PlayerPrefs.HasKey( key ) ) return "Key Not Found";
  12 + return PlayerPrefs.GetInt( key ).ToString();
  13 + }
  14 +
  15 + [ConsoleMethod( "prefs.int", "Sets the value of an Integer PlayerPrefs field" ), UnityEngine.Scripting.Preserve]
  16 + public static void PlayerPrefsSetInt( string key, int value )
  17 + {
  18 + PlayerPrefs.SetInt( key, value );
  19 + }
  20 +
  21 + [ConsoleMethod( "prefs.float", "Returns the value of a Float PlayerPrefs field" ), UnityEngine.Scripting.Preserve]
  22 + public static string PlayerPrefsGetFloat( string key )
  23 + {
  24 + if( !PlayerPrefs.HasKey( key ) ) return "Key Not Found";
  25 + return PlayerPrefs.GetFloat( key ).ToString();
  26 + }
  27 +
  28 + [ConsoleMethod( "prefs.float", "Sets the value of a Float PlayerPrefs field" ), UnityEngine.Scripting.Preserve]
  29 + public static void PlayerPrefsSetFloat( string key, float value )
  30 + {
  31 + PlayerPrefs.SetFloat( key, value );
  32 + }
  33 +
  34 + [ConsoleMethod( "prefs.string", "Returns the value of a String PlayerPrefs field" ), UnityEngine.Scripting.Preserve]
  35 + public static string PlayerPrefsGetString( string key )
  36 + {
  37 + if( !PlayerPrefs.HasKey( key ) ) return "Key Not Found";
  38 + return PlayerPrefs.GetString( key );
  39 + }
  40 +
  41 + [ConsoleMethod( "prefs.string", "Sets the value of a String PlayerPrefs field" ), UnityEngine.Scripting.Preserve]
  42 + public static void PlayerPrefsSetString( string key, string value )
  43 + {
  44 + PlayerPrefs.SetString( key, value );
  45 + }
  46 +
  47 + [ConsoleMethod( "prefs.delete", "Deletes a PlayerPrefs field" ), UnityEngine.Scripting.Preserve]
  48 + public static void PlayerPrefsDelete( string key )
  49 + {
  50 + PlayerPrefs.DeleteKey( key );
  51 + }
  52 +
  53 + [ConsoleMethod( "prefs.clear", "Deletes all PlayerPrefs fields" ), UnityEngine.Scripting.Preserve]
  54 + public static void PlayerPrefsClear()
  55 + {
  56 + PlayerPrefs.DeleteAll();
  57 + }
  58 + }
  59 +}
  60 +#endif
  1 +fileFormatVersion: 2
  2 +guid: 33fb3ee25c8764f4c905fa3ac7c4eb89
  3 +MonoImporter:
  4 + externalObjects: {}
  5 + serializedVersion: 2
  6 + defaultReferences: []
  7 + executionOrder: 0
  8 + icon: {instanceID: 0}
  9 + userData:
  10 + assetBundleName:
  11 + assetBundleVariant:
  1 +#if IDG_ENABLE_HELPER_COMMANDS
  2 +using UnityEngine;
  3 +using UnityEngine.SceneManagement;
  4 +
  5 +namespace IngameDebugConsole.Commands
  6 +{
  7 + public class SceneCommands
  8 + {
  9 + [ConsoleMethod( "scene.load", "Loads a scene" ), UnityEngine.Scripting.Preserve]
  10 + public static void LoadScene( string sceneName )
  11 + {
  12 + LoadSceneInternal( sceneName, false, LoadSceneMode.Single );
  13 + }
  14 +
  15 + [ConsoleMethod( "scene.load", "Loads a scene" ), UnityEngine.Scripting.Preserve]
  16 + public static void LoadScene( string sceneName, LoadSceneMode mode )
  17 + {
  18 + LoadSceneInternal( sceneName, false, mode );
  19 + }
  20 +
  21 + [ConsoleMethod( "scene.loadasync", "Loads a scene asynchronously" ), UnityEngine.Scripting.Preserve]
  22 + public static void LoadSceneAsync( string sceneName )
  23 + {
  24 + LoadSceneInternal( sceneName, true, LoadSceneMode.Single );
  25 + }
  26 +
  27 + [ConsoleMethod( "scene.loadasync", "Loads a scene asynchronously" ), UnityEngine.Scripting.Preserve]
  28 + public static void LoadSceneAsync( string sceneName, LoadSceneMode mode )
  29 + {
  30 + LoadSceneInternal( sceneName, true, mode );
  31 + }
  32 +
  33 + private static void LoadSceneInternal( string sceneName, bool isAsync, LoadSceneMode mode )
  34 + {
  35 + if( SceneManager.GetSceneByName( sceneName ).IsValid() )
  36 + {
  37 + Debug.Log( "Scene " + sceneName + " is already loaded" );
  38 + return;
  39 + }
  40 +
  41 + if( isAsync )
  42 + SceneManager.LoadSceneAsync( sceneName, mode );
  43 + else
  44 + SceneManager.LoadScene( sceneName, mode );
  45 + }
  46 +
  47 + [ConsoleMethod( "scene.unload", "Unloads a scene" ), UnityEngine.Scripting.Preserve]
  48 + public static void UnloadScene( string sceneName )
  49 + {
  50 + SceneManager.UnloadSceneAsync( sceneName );
  51 + }
  52 +
  53 + [ConsoleMethod( "scene.restart", "Restarts the active scene" ), UnityEngine.Scripting.Preserve]
  54 + public static void RestartScene()
  55 + {
  56 + SceneManager.LoadScene( SceneManager.GetActiveScene().name, LoadSceneMode.Single );
  57 + }
  58 + }
  59 +}
  60 +#endif
  1 +fileFormatVersion: 2
  2 +guid: 45984eacd62d9a3489fd62689265a23c
  3 +MonoImporter:
  4 + externalObjects: {}
  5 + serializedVersion: 2
  6 + defaultReferences: []
  7 + executionOrder: 0
  8 + icon: {instanceID: 0}
  9 + userData:
  10 + assetBundleName:
  11 + assetBundleVariant:
  1 +#if IDG_ENABLE_HELPER_COMMANDS
  2 +using UnityEngine;
  3 +
  4 +namespace IngameDebugConsole.Commands
  5 +{
  6 + public class TimeCommands
  7 + {
  8 + [ConsoleMethod( "time.scale", "Sets the Time.timeScale value" ), UnityEngine.Scripting.Preserve]
  9 + public static void SetTimeScale( float value )
  10 + {
  11 + Time.timeScale = Mathf.Max( value, 0f );
  12 + }
  13 +
  14 + [ConsoleMethod( "time.scale", "Returns the current Time.timeScale value" ), UnityEngine.Scripting.Preserve]
  15 + public static float GetTimeScale()
  16 + {
  17 + return Time.timeScale;
  18 + }
  19 + }
  20 +}
  21 +#endif
  1 +fileFormatVersion: 2
  2 +guid: bb12a1f557fffa541909fcfe92d9c1bf
  3 +MonoImporter:
  4 + externalObjects: {}
  5 + serializedVersion: 2
  6 + defaultReferences: []
  7 + executionOrder: 0
  8 + icon: {instanceID: 0}
  9 + userData:
  10 + assetBundleName:
  11 + assetBundleVariant:
  1 +using System;
  2 +
  3 +namespace IngameDebugConsole
  4 +{
  5 + [AttributeUsage( AttributeTargets.Method, Inherited = false, AllowMultiple = true )]
  6 + public class ConsoleMethodAttribute : Attribute
  7 + {
  8 + private string m_command;
  9 + private string m_description;
  10 + private string[] m_parameterNames;
  11 +
  12 + public string Command { get { return m_command; } }
  13 + public string Description { get { return m_description; } }
  14 + public string[] ParameterNames { get { return m_parameterNames; } }
  15 +
  16 + public ConsoleMethodAttribute( string command, string description, params string[] parameterNames )
  17 + {
  18 + m_command = command;
  19 + m_description = description;
  20 + m_parameterNames = parameterNames;
  21 + }
  22 + }
  23 +}
  1 +fileFormatVersion: 2
  2 +guid: 324bb39c0bff0f74fa42f83e91f07e3a
  3 +timeCreated: 1520710946
  4 +licenseType: Store
  5 +MonoImporter:
  6 + serializedVersion: 2
  7 + defaultReferences: []
  8 + executionOrder: 0
  9 + icon: {instanceID: 0}
  10 + userData:
  11 + assetBundleName:
  12 + assetBundleVariant:
  1 +#if UNITY_EDITOR || UNITY_STANDALONE
  2 +// Unity's Text component doesn't render <b> tag correctly on mobile devices
  3 +#define USE_BOLD_COMMAND_SIGNATURES
  4 +#endif
  5 +
  6 +using UnityEngine;
  7 +using System;
  8 +using System.Collections;
  9 +using System.Collections.Generic;
  10 +using System.Globalization;
  11 +using System.Reflection;
  12 +using System.Text;
  13 +using Object = UnityEngine.Object;
  14 +#if UNITY_EDITOR && UNITY_2021_1_OR_NEWER
  15 +using SystemInfo = UnityEngine.Device.SystemInfo; // To support Device Simulator on Unity 2021.1+
  16 +#endif
  17 +
  18 +// Manages the console commands, parses console input and handles execution of commands
  19 +// Supported method parameter types: int, float, bool, string, Vector2, Vector3, Vector4
  20 +
  21 +// Helper class to store important information about a command
  22 +namespace IngameDebugConsole
  23 +{
  24 + public class ConsoleMethodInfo
  25 + {
  26 + public readonly MethodInfo method;
  27 + public readonly Type[] parameterTypes;
  28 + public readonly object instance;
  29 +
  30 + public readonly string command;
  31 + public readonly string signature;
  32 + public readonly string[] parameters;
  33 +
  34 + public ConsoleMethodInfo( MethodInfo method, Type[] parameterTypes, object instance, string command, string signature, string[] parameters )
  35 + {
  36 + this.method = method;
  37 + this.parameterTypes = parameterTypes;
  38 + this.instance = instance;
  39 + this.command = command;
  40 + this.signature = signature;
  41 + this.parameters = parameters;
  42 + }
  43 +
  44 + public bool IsValid()
  45 + {
  46 + if( !method.IsStatic && ( instance == null || instance.Equals( null ) ) )
  47 + return false;
  48 +
  49 + return true;
  50 + }
  51 + }
  52 +
  53 + public static class DebugLogConsole
  54 + {
  55 + public delegate bool ParseFunction( string input, out object output );
  56 +
  57 + public delegate void CommandExecutedDelegate( string command, object[] parameters );
  58 + public static event CommandExecutedDelegate OnCommandExecuted;
  59 +
  60 + // All the commands
  61 + private static readonly List<ConsoleMethodInfo> methods = new List<ConsoleMethodInfo>();
  62 + private static readonly List<ConsoleMethodInfo> matchingMethods = new List<ConsoleMethodInfo>( 4 );
  63 +
  64 + // All the parse functions
  65 + private static readonly Dictionary<Type, ParseFunction> parseFunctions = new Dictionary<Type, ParseFunction>()
  66 + {
  67 + { typeof( string ), ParseString },
  68 + { typeof( bool ), ParseBool },
  69 + { typeof( int ), ParseInt },
  70 + { typeof( uint ), ParseUInt },
  71 + { typeof( long ), ParseLong },
  72 + { typeof( ulong ), ParseULong },
  73 + { typeof( byte ), ParseByte },
  74 + { typeof( sbyte ), ParseSByte },
  75 + { typeof( short ), ParseShort },
  76 + { typeof( ushort ), ParseUShort },
  77 + { typeof( char ), ParseChar },
  78 + { typeof( float ), ParseFloat },
  79 + { typeof( double ), ParseDouble },
  80 + { typeof( decimal ), ParseDecimal },
  81 + { typeof( Vector2 ), ParseVector2 },
  82 + { typeof( Vector3 ), ParseVector3 },
  83 + { typeof( Vector4 ), ParseVector4 },
  84 + { typeof( Quaternion ), ParseQuaternion },
  85 + { typeof( Color ), ParseColor },
  86 + { typeof( Color32 ), ParseColor32 },
  87 + { typeof( Rect ), ParseRect },
  88 + { typeof( RectOffset ), ParseRectOffset },
  89 + { typeof( Bounds ), ParseBounds },
  90 + { typeof( GameObject ), ParseGameObject },
  91 +#if UNITY_2017_2_OR_NEWER
  92 + { typeof( Vector2Int ), ParseVector2Int },
  93 + { typeof( Vector3Int ), ParseVector3Int },
  94 + { typeof( RectInt ), ParseRectInt },
  95 + { typeof( BoundsInt ), ParseBoundsInt },
  96 +#endif
  97 + };
  98 +
  99 + // All the readable names of accepted types
  100 + private static readonly Dictionary<Type, string> typeReadableNames = new Dictionary<Type, string>()
  101 + {
  102 + { typeof( string ), "String" },
  103 + { typeof( bool ), "Boolean" },
  104 + { typeof( int ), "Integer" },
  105 + { typeof( uint ), "Unsigned Integer" },
  106 + { typeof( long ), "Long" },
  107 + { typeof( ulong ), "Unsigned Long" },
  108 + { typeof( byte ), "Byte" },
  109 + { typeof( sbyte ), "Short Byte" },
  110 + { typeof( short ), "Short" },
  111 + { typeof( ushort ), "Unsigned Short" },
  112 + { typeof( char ), "Char" },
  113 + { typeof( float ), "Float" },
  114 + { typeof( double ), "Double" },
  115 + { typeof( decimal ), "Decimal" }
  116 + };
  117 +
  118 + // Split arguments of an entered command
  119 + private static readonly List<string> commandArguments = new List<string>( 8 );
  120 +
  121 + // Command parameter delimeter groups
  122 + private static readonly string[] inputDelimiters = new string[] { "\"\"", "''", "{}", "()", "[]" };
  123 +
  124 + // CompareInfo used for case-insensitive command name comparison
  125 + internal static readonly CompareInfo caseInsensitiveComparer = new CultureInfo( "en-US" ).CompareInfo;
  126 +
  127 + static DebugLogConsole()
  128 + {
  129 +#if !IDG_DISABLE_HELP_COMMAND
  130 + AddCommand( "help", "Prints all commands", LogAllCommands );
  131 + AddCommand<string>( "help", "Prints all matching commands", LogAllCommandsWithName );
  132 +#endif
  133 +#if IDG_ENABLE_HELPER_COMMANDS || IDG_ENABLE_SYSINFO_COMMAND
  134 + AddCommand( "sysinfo", "Prints system information", LogSystemInfo );
  135 +#endif
  136 +
  137 +#if UNITY_EDITOR || !NETFX_CORE
  138 + // Find all [ConsoleMethod] functions
  139 + // Don't search built-in assemblies for console methods since they can't have any
  140 + string[] ignoredAssemblies = new string[]
  141 + {
  142 + "Unity",
  143 + "System",
  144 + "Mono.",
  145 + "mscorlib",
  146 + "netstandard",
  147 + "TextMeshPro",
  148 + "Microsoft.GeneratedCode",
  149 + "I18N",
  150 + "Boo.",
  151 + "UnityScript.",
  152 + "ICSharpCode.",
  153 + "ExCSS.Unity",
  154 +#if UNITY_EDITOR
  155 + "Assembly-CSharp-Editor",
  156 + "Assembly-UnityScript-Editor",
  157 + "nunit.",
  158 + "SyntaxTree.",
  159 + "AssetStoreTools",
  160 +#endif
  161 + };
  162 +#endif
  163 +
  164 +#if UNITY_EDITOR || !NETFX_CORE
  165 + foreach( Assembly assembly in AppDomain.CurrentDomain.GetAssemblies() )
  166 +#else
  167 + foreach( Assembly assembly in new Assembly[] { typeof( DebugLogConsole ).Assembly } ) // On UWP, at least search this plugin's Assembly for console methods
  168 +#endif
  169 + {
  170 +#if( NET_4_6 || NET_STANDARD_2_0 ) && ( UNITY_EDITOR || !NETFX_CORE )
  171 + if( assembly.IsDynamic )
  172 + continue;
  173 +#endif
  174 +
  175 +
  176 +#if UNITY_EDITOR || !NETFX_CORE
  177 + string assemblyName = assembly.GetName().Name;
  178 + bool ignoreAssembly = false;
  179 + for( int i = 0; i < ignoredAssemblies.Length; i++ )
  180 + {
  181 + if( caseInsensitiveComparer.IsPrefix( assemblyName, ignoredAssemblies[i], CompareOptions.IgnoreCase ) )
  182 + {
  183 + ignoreAssembly = true;
  184 + break;
  185 + }
  186 + }
  187 +
  188 + if( ignoreAssembly )
  189 + continue;
  190 +#endif
  191 +
  192 + SearchAssemblyForConsoleMethods( assembly );
  193 + }
  194 + }
  195 +
  196 + public static void SearchAssemblyForConsoleMethods( Assembly assembly )
  197 + {
  198 + try
  199 + {
  200 + foreach( Type type in assembly.GetExportedTypes() )
  201 + {
  202 + foreach( MethodInfo method in type.GetMethods( BindingFlags.Static | BindingFlags.Public | BindingFlags.DeclaredOnly ) )
  203 + {
  204 + foreach( object attribute in method.GetCustomAttributes( typeof( ConsoleMethodAttribute ), false ) )
  205 + {
  206 + ConsoleMethodAttribute consoleMethod = attribute as ConsoleMethodAttribute;
  207 + if( consoleMethod != null )
  208 + AddCommand( consoleMethod.Command, consoleMethod.Description, method, null, consoleMethod.ParameterNames );
  209 + }
  210 + }
  211 + }
  212 + }
  213 + catch( NotSupportedException ) { }
  214 + catch( System.IO.FileNotFoundException ) { }
  215 + catch( ReflectionTypeLoadException ) { }
  216 + catch( Exception e )
  217 + {
  218 + Debug.LogError( "Couldn't search assembly for [ConsoleMethod] attributes: " + assembly.GetName().Name + "\n" + e.ToString() );
  219 + }
  220 + }
  221 +
  222 + public static List<ConsoleMethodInfo> GetAllCommands()
  223 + {
  224 + return methods;
  225 + }
  226 +
  227 + // Logs the list of available commands
  228 + public static void LogAllCommands()
  229 + {
  230 + int length = 25;
  231 + for( int i = 0; i < methods.Count; i++ )
  232 + {
  233 + if( methods[i].IsValid() )
  234 + length += methods[i].signature.Length + 7;
  235 + }
  236 +
  237 + StringBuilder stringBuilder = new StringBuilder( length );
  238 + stringBuilder.Append( "Available commands:" );
  239 +
  240 + for( int i = 0; i < methods.Count; i++ )
  241 + {
  242 + if( methods[i].IsValid() )
  243 + stringBuilder.Append( "\n - " ).Append( methods[i].signature );
  244 + }
  245 +
  246 + Debug.Log( stringBuilder.ToString() );
  247 +
  248 + // After typing help, the log that lists all the commands should automatically be expanded for better UX
  249 + if( DebugLogManager.Instance )
  250 + DebugLogManager.Instance.AdjustLatestPendingLog( true, true );
  251 + }
  252 +
  253 + // Logs the list of available commands that are either equal to commandName or contain commandName as substring
  254 + public static void LogAllCommandsWithName( string commandName )
  255 + {
  256 + matchingMethods.Clear();
  257 +
  258 + // First, try to find commands that exactly match the commandName. If there are no such commands, try to find
  259 + // commands that contain commandName as substring
  260 + FindCommands( commandName, false, matchingMethods );
  261 + if( matchingMethods.Count == 0 )
  262 + FindCommands( commandName, true, matchingMethods );
  263 +
  264 + if( matchingMethods.Count == 0 )
  265 + Debug.LogWarning( string.Concat( "ERROR: can't find command '", commandName, "'" ) );
  266 + else
  267 + {
  268 + int commandsLength = 25;
  269 + for( int i = 0; i < matchingMethods.Count; i++ )
  270 + commandsLength += matchingMethods[i].signature.Length + 7;
  271 +
  272 + StringBuilder stringBuilder = new StringBuilder( commandsLength );
  273 + stringBuilder.Append( "Matching commands:" );
  274 +
  275 + for( int i = 0; i < matchingMethods.Count; i++ )
  276 + stringBuilder.Append( "\n - " ).Append( matchingMethods[i].signature );
  277 +
  278 + Debug.Log( stringBuilder.ToString() );
  279 +
  280 + if( DebugLogManager.Instance )
  281 + DebugLogManager.Instance.AdjustLatestPendingLog( true, true );
  282 + }
  283 + }
  284 +
  285 + // Logs system information
  286 + public static void LogSystemInfo()
  287 + {
  288 + StringBuilder stringBuilder = new StringBuilder( 1024 );
  289 + stringBuilder.Append( "Rig: " ).AppendSysInfoIfPresent( SystemInfo.deviceModel ).AppendSysInfoIfPresent( SystemInfo.processorType )
  290 + .AppendSysInfoIfPresent( SystemInfo.systemMemorySize, "MB RAM" ).Append( SystemInfo.processorCount ).Append( " cores\n" );
  291 + stringBuilder.Append( "OS: " ).Append( SystemInfo.operatingSystem ).Append( "\n" );
  292 + stringBuilder.Append( "GPU: " ).Append( SystemInfo.graphicsDeviceName ).Append( " " ).Append( SystemInfo.graphicsMemorySize )
  293 + .Append( "MB " ).Append( SystemInfo.graphicsDeviceVersion )
  294 + .Append( SystemInfo.graphicsMultiThreaded ? " multi-threaded\n" : "\n" );
  295 + stringBuilder.Append( "Data Path: " ).Append( Application.dataPath ).Append( "\n" );
  296 + stringBuilder.Append( "Persistent Data Path: " ).Append( Application.persistentDataPath ).Append( "\n" );
  297 + stringBuilder.Append( "StreamingAssets Path: " ).Append( Application.streamingAssetsPath ).Append( "\n" );
  298 + stringBuilder.Append( "Temporary Cache Path: " ).Append( Application.temporaryCachePath ).Append( "\n" );
  299 + stringBuilder.Append( "Device ID: " ).Append( SystemInfo.deviceUniqueIdentifier ).Append( "\n" );
  300 + stringBuilder.Append( "Max Texture Size: " ).Append( SystemInfo.maxTextureSize ).Append( "\n" );
  301 +#if UNITY_5_6_OR_NEWER
  302 + stringBuilder.Append( "Max Cubemap Size: " ).Append( SystemInfo.maxCubemapSize ).Append( "\n" );
  303 +#endif
  304 + stringBuilder.Append( "Accelerometer: " ).Append( SystemInfo.supportsAccelerometer ? "supported\n" : "not supported\n" );
  305 + stringBuilder.Append( "Gyro: " ).Append( SystemInfo.supportsGyroscope ? "supported\n" : "not supported\n" );
  306 + stringBuilder.Append( "Location Service: " ).Append( SystemInfo.supportsLocationService ? "supported\n" : "not supported\n" );
  307 +#if !UNITY_2019_1_OR_NEWER
  308 + stringBuilder.Append( "Image Effects: " ).Append( SystemInfo.supportsImageEffects ? "supported\n" : "not supported\n" );
  309 + stringBuilder.Append( "RenderToCubemap: " ).Append( SystemInfo.supportsRenderToCubemap ? "supported\n" : "not supported\n" );
  310 +#endif
  311 + stringBuilder.Append( "Compute Shaders: " ).Append( SystemInfo.supportsComputeShaders ? "supported\n" : "not supported\n" );
  312 + stringBuilder.Append( "Shadows: " ).Append( SystemInfo.supportsShadows ? "supported\n" : "not supported\n" );
  313 + stringBuilder.Append( "Instancing: " ).Append( SystemInfo.supportsInstancing ? "supported\n" : "not supported\n" );
  314 + stringBuilder.Append( "Motion Vectors: " ).Append( SystemInfo.supportsMotionVectors ? "supported\n" : "not supported\n" );
  315 + stringBuilder.Append( "3D Textures: " ).Append( SystemInfo.supports3DTextures ? "supported\n" : "not supported\n" );
  316 +#if UNITY_5_6_OR_NEWER
  317 + stringBuilder.Append( "3D Render Textures: " ).Append( SystemInfo.supports3DRenderTextures ? "supported\n" : "not supported\n" );
  318 +#endif
  319 + stringBuilder.Append( "2D Array Textures: " ).Append( SystemInfo.supports2DArrayTextures ? "supported\n" : "not supported\n" );
  320 + stringBuilder.Append( "Cubemap Array Textures: " ).Append( SystemInfo.supportsCubemapArrayTextures ? "supported" : "not supported" );
  321 +
  322 + Debug.Log( stringBuilder.ToString() );
  323 +
  324 + // After typing sysinfo, the log that lists system information should automatically be expanded for better UX
  325 + if( DebugLogManager.Instance )
  326 + DebugLogManager.Instance.AdjustLatestPendingLog( true, true );
  327 + }
  328 +
  329 + private static StringBuilder AppendSysInfoIfPresent( this StringBuilder sb, string info, string postfix = null )
  330 + {
  331 + if( info != SystemInfo.unsupportedIdentifier )
  332 + {
  333 + sb.Append( info );
  334 +
  335 + if( postfix != null )
  336 + sb.Append( postfix );
  337 +
  338 + sb.Append( " " );
  339 + }
  340 +
  341 + return sb;
  342 + }
  343 +
  344 + private static StringBuilder AppendSysInfoIfPresent( this StringBuilder sb, int info, string postfix = null )
  345 + {
  346 + if( info > 0 )
  347 + {
  348 + sb.Append( info );
  349 +
  350 + if( postfix != null )
  351 + sb.Append( postfix );
  352 +
  353 + sb.Append( " " );
  354 + }
  355 +
  356 + return sb;
  357 + }
  358 +
  359 + // Add a custom Type to the list of recognized command parameter Types
  360 + public static void AddCustomParameterType( Type type, ParseFunction parseFunction, string typeReadableName = null )
  361 + {
  362 + if( type == null )
  363 + {
  364 + Debug.LogError( "Parameter type can't be null!" );
  365 + return;
  366 + }
  367 + else if( parseFunction == null )
  368 + {
  369 + Debug.LogError( "Parameter parseFunction can't be null!" );
  370 + return;
  371 + }
  372 +
  373 + parseFunctions[type] = parseFunction;
  374 +
  375 + if( !string.IsNullOrEmpty( typeReadableName ) )
  376 + typeReadableNames[type] = typeReadableName;
  377 + }
  378 +
  379 + // Remove a custom Type from the list of recognized command parameter Types
  380 + public static void RemoveCustomParameterType( Type type )
  381 + {
  382 + parseFunctions.Remove( type );
  383 + typeReadableNames.Remove( type );
  384 + }
  385 +
  386 + // Add a command related with an instance method (i.e. non static method)
  387 + public static void AddCommandInstance( string command, string description, string methodName, object instance, params string[] parameterNames )
  388 + {
  389 + if( instance == null )
  390 + {
  391 + Debug.LogError( "Instance can't be null!" );
  392 + return;
  393 + }
  394 +
  395 + AddCommand( command, description, methodName, instance.GetType(), instance, parameterNames );
  396 + }
  397 +
  398 + // Add a command related with a static method (i.e. no instance is required to call the method)
  399 + public static void AddCommandStatic( string command, string description, string methodName, Type ownerType, params string[] parameterNames )
  400 + {
  401 + AddCommand( command, description, methodName, ownerType, null, parameterNames );
  402 + }
  403 +
  404 + // Add a command that can be related to either a static or an instance method
  405 + public static void AddCommand( string command, string description, Action method ) { AddCommand( command, description, method.Method, method.Target, null ); }
  406 + public static void AddCommand<T1>( string command, string description, Action<T1> method ) { AddCommand( command, description, method.Method, method.Target, null ); }
  407 + public static void AddCommand<T1>( string command, string description, Func<T1> method ) { AddCommand( command, description, method.Method, method.Target, null ); }
  408 + public static void AddCommand<T1, T2>( string command, string description, Action<T1, T2> method ) { AddCommand( command, description, method.Method, method.Target, null ); }
  409 + public static void AddCommand<T1, T2>( string command, string description, Func<T1, T2> method ) { AddCommand( command, description, method.Method, method.Target, null ); }
  410 + public static void AddCommand<T1, T2, T3>( string command, string description, Action<T1, T2, T3> method ) { AddCommand( command, description, method.Method, method.Target, null ); }
  411 + public static void AddCommand<T1, T2, T3>( string command, string description, Func<T1, T2, T3> method ) { AddCommand( command, description, method.Method, method.Target, null ); }
  412 + 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, null ); }
  413 + 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, null ); }
  414 + 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, null ); }
  415 + public static void AddCommand( string command, string description, Delegate method ) { AddCommand( command, description, method.Method, method.Target, null ); }
  416 +
  417 + // Add a command with custom parameter names
  418 + public static void AddCommand<T1>( string command, string description, Action<T1> method, string parameterName ) { AddCommand( command, description, method.Method, method.Target, new string[1] { parameterName } ); }
  419 + public static void AddCommand<T1, T2>( string command, string description, Action<T1, T2> method, string parameterName1, string parameterName2 ) { AddCommand( command, description, method.Method, method.Target, new string[2] { parameterName1, parameterName2 } ); }
  420 + public static void AddCommand<T1, T2>( string command, string description, Func<T1, T2> method, string parameterName ) { AddCommand( command, description, method.Method, method.Target, new string[1] { parameterName } ); }
  421 + public static void AddCommand<T1, T2, T3>( string command, string description, Action<T1, T2, T3> method, string parameterName1, string parameterName2, string parameterName3 ) { AddCommand( command, description, method.Method, method.Target, new string[3] { parameterName1, parameterName2, parameterName3 } ); }
  422 + public static void AddCommand<T1, T2, T3>( string command, string description, Func<T1, T2, T3> method, string parameterName1, string parameterName2 ) { AddCommand( command, description, method.Method, method.Target, new string[2] { parameterName1, parameterName2 } ); }
  423 + public static void AddCommand<T1, T2, T3, T4>( string command, string description, Action<T1, T2, T3, T4> method, string parameterName1, string parameterName2, string parameterName3, string parameterName4 ) { AddCommand( command, description, method.Method, method.Target, new string[4] { parameterName1, parameterName2, parameterName3, parameterName4 } ); }
  424 + public static void AddCommand<T1, T2, T3, T4>( string command, string description, Func<T1, T2, T3, T4> method, string parameterName1, string parameterName2, string parameterName3 ) { AddCommand( command, description, method.Method, method.Target, new string[3] { parameterName1, parameterName2, parameterName3 } ); }
  425 + public static void AddCommand<T1, T2, T3, T4, T5>( string command, string description, Func<T1, T2, T3, T4, T5> method, string parameterName1, string parameterName2, string parameterName3, string parameterName4 ) { AddCommand( command, description, method.Method, method.Target, new string[4] { parameterName1, parameterName2, parameterName3, parameterName4 } ); }
  426 + public static void AddCommand( string command, string description, Delegate method, params string[] parameterNames ) { AddCommand( command, description, method.Method, method.Target, parameterNames ); }
  427 +
  428 + // Create a new command and set its properties
  429 + private static void AddCommand( string command, string description, string methodName, Type ownerType, object instance, string[] parameterNames )
  430 + {
  431 + // Get the method from the class
  432 + MethodInfo method = ownerType.GetMethod( methodName, BindingFlags.Public | BindingFlags.NonPublic | ( instance != null ? BindingFlags.Instance : BindingFlags.Static ) );
  433 + if( method == null )
  434 + {
  435 + Debug.LogError( methodName + " does not exist in " + ownerType );
  436 + return;
  437 + }
  438 +
  439 + AddCommand( command, description, method, instance, parameterNames );
  440 + }
  441 +
  442 + private static void AddCommand( string command, string description, MethodInfo method, object instance, string[] parameterNames )
  443 + {
  444 + if( string.IsNullOrEmpty( command ) )
  445 + {
  446 + Debug.LogError( "Command name can't be empty!" );
  447 + return;
  448 + }
  449 +
  450 + command = command.Trim();
  451 + if( command.IndexOf( ' ' ) >= 0 )
  452 + {
  453 + Debug.LogError( "Command name can't contain whitespace: " + command );
  454 + return;
  455 + }
  456 +
  457 + // Fetch the parameters of the class
  458 + ParameterInfo[] parameters = method.GetParameters();
  459 + if( parameters == null )
  460 + parameters = new ParameterInfo[0];
  461 +
  462 + // Store the parameter types in an array
  463 + Type[] parameterTypes = new Type[parameters.Length];
  464 + for( int i = 0; i < parameters.Length; i++ )
  465 + {
  466 + if( parameters[i].ParameterType.IsByRef )
  467 + {
  468 + Debug.LogError( "Command can't have 'out' or 'ref' parameters" );
  469 + return;
  470 + }
  471 +
  472 + Type parameterType = parameters[i].ParameterType;
  473 + if( parseFunctions.ContainsKey( parameterType ) || typeof( Component ).IsAssignableFrom( parameterType ) || parameterType.IsEnum || IsSupportedArrayType( parameterType ) )
  474 + parameterTypes[i] = parameterType;
  475 + else
  476 + {
  477 + Debug.LogError( string.Concat( "Parameter ", parameters[i].Name, "'s Type ", parameterType, " isn't supported" ) );
  478 + return;
  479 + }
  480 + }
  481 +
  482 + int commandIndex = FindCommandIndex( command );
  483 + if( commandIndex < 0 )
  484 + commandIndex = ~commandIndex;
  485 + else
  486 + {
  487 + int commandFirstIndex = commandIndex;
  488 + int commandLastIndex = commandIndex;
  489 +
  490 + while( commandFirstIndex > 0 && caseInsensitiveComparer.Compare( methods[commandFirstIndex - 1].command, command, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ) == 0 )
  491 + commandFirstIndex--;
  492 + while( commandLastIndex < methods.Count - 1 && caseInsensitiveComparer.Compare( methods[commandLastIndex + 1].command, command, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ) == 0 )
  493 + commandLastIndex++;
  494 +
  495 + commandIndex = commandFirstIndex;
  496 + for( int i = commandFirstIndex; i <= commandLastIndex; i++ )
  497 + {
  498 + int parameterCountDiff = methods[i].parameterTypes.Length - parameterTypes.Length;
  499 + if( parameterCountDiff <= 0 )
  500 + {
  501 + // We are sorting the commands in 2 steps:
  502 + // 1: Sorting by their 'command' names which is handled by FindCommandIndex
  503 + // 2: Sorting by their parameter counts which is handled here (parameterCountDiff <= 0)
  504 + commandIndex = i + 1;
  505 +
  506 + // Check if this command has been registered before and if it is, overwrite that command
  507 + if( parameterCountDiff == 0 )
  508 + {
  509 + int j = 0;
  510 + while( j < parameterTypes.Length && parameterTypes[j] == methods[i].parameterTypes[j] )
  511 + j++;
  512 +
  513 + if( j >= parameterTypes.Length )
  514 + {
  515 + commandIndex = i;
  516 + commandLastIndex--;
  517 + methods.RemoveAt( i-- );
  518 +
  519 + continue;
  520 + }
  521 + }
  522 + }
  523 + }
  524 + }
  525 +
  526 + // Create the command
  527 + StringBuilder methodSignature = new StringBuilder( 256 );
  528 + string[] parameterSignatures = new string[parameterTypes.Length];
  529 +
  530 +#if USE_BOLD_COMMAND_SIGNATURES
  531 + methodSignature.Append( "<b>" );
  532 +#endif
  533 + methodSignature.Append( command );
  534 +
  535 + if( parameterTypes.Length > 0 )
  536 + {
  537 + methodSignature.Append( " " );
  538 +
  539 + for( int i = 0; i < parameterTypes.Length; i++ )
  540 + {
  541 + int parameterSignatureStartIndex = methodSignature.Length;
  542 +
  543 + methodSignature.Append( "[" ).Append( GetTypeReadableName( parameterTypes[i] ) ).Append( " " ).Append( ( parameterNames != null && i < parameterNames.Length && !string.IsNullOrEmpty( parameterNames[i] ) ) ? parameterNames[i] : parameters[i].Name ).Append( "]" );
  544 +
  545 + if( i < parameterTypes.Length - 1 )
  546 + methodSignature.Append( " " );
  547 +
  548 + parameterSignatures[i] = methodSignature.ToString( parameterSignatureStartIndex, methodSignature.Length - parameterSignatureStartIndex );
  549 + }
  550 + }
  551 +
  552 +#if USE_BOLD_COMMAND_SIGNATURES
  553 + methodSignature.Append( "</b>" );
  554 +#endif
  555 +
  556 + if( !string.IsNullOrEmpty( description ) )
  557 + methodSignature.Append( ": " ).Append( description );
  558 +
  559 + methods.Insert( commandIndex, new ConsoleMethodInfo( method, parameterTypes, instance, command, methodSignature.ToString(), parameterSignatures ) );
  560 + }
  561 +
  562 + // Remove all commands with the matching command name from the console
  563 + public static void RemoveCommand( string command )
  564 + {
  565 + if( !string.IsNullOrEmpty( command ) )
  566 + {
  567 + for( int i = methods.Count - 1; i >= 0; i-- )
  568 + {
  569 + if( caseInsensitiveComparer.Compare( methods[i].command, command, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ) == 0 )
  570 + methods.RemoveAt( i );
  571 + }
  572 + }
  573 + }
  574 +
  575 + // Remove all commands with the matching method from the console
  576 + public static void RemoveCommand( Action method ) { RemoveCommand( method.Method ); }
  577 + public static void RemoveCommand<T1>( Action<T1> method ) { RemoveCommand( method.Method ); }
  578 + public static void RemoveCommand<T1>( Func<T1> method ) { RemoveCommand( method.Method ); }
  579 + public static void RemoveCommand<T1, T2>( Action<T1, T2> method ) { RemoveCommand( method.Method ); }
  580 + public static void RemoveCommand<T1, T2>( Func<T1, T2> method ) { RemoveCommand( method.Method ); }
  581 + public static void RemoveCommand<T1, T2, T3>( Action<T1, T2, T3> method ) { RemoveCommand( method.Method ); }
  582 + public static void RemoveCommand<T1, T2, T3>( Func<T1, T2, T3> method ) { RemoveCommand( method.Method ); }
  583 + public static void RemoveCommand<T1, T2, T3, T4>( Action<T1, T2, T3, T4> method ) { RemoveCommand( method.Method ); }
  584 + public static void RemoveCommand<T1, T2, T3, T4>( Func<T1, T2, T3, T4> method ) { RemoveCommand( method.Method ); }
  585 + public static void RemoveCommand<T1, T2, T3, T4, T5>( Func<T1, T2, T3, T4, T5> method ) { RemoveCommand( method.Method ); }
  586 + public static void RemoveCommand( Delegate method ) { RemoveCommand( method.Method ); }
  587 +
  588 + public static void RemoveCommand( MethodInfo method )
  589 + {
  590 + if( method != null )
  591 + {
  592 + for( int i = methods.Count - 1; i >= 0; i-- )
  593 + {
  594 + if( methods[i].method == method )
  595 + methods.RemoveAt( i );
  596 + }
  597 + }
  598 + }
  599 +
  600 + // Returns the first command that starts with the entered argument
  601 + public static string GetAutoCompleteCommand( string commandStart, string previousSuggestion )
  602 + {
  603 + int commandIndex = FindCommandIndex( !string.IsNullOrEmpty( previousSuggestion ) ? previousSuggestion : commandStart );
  604 + if( commandIndex < 0 )
  605 + {
  606 + commandIndex = ~commandIndex;
  607 + return ( commandIndex < methods.Count && caseInsensitiveComparer.IsPrefix( methods[commandIndex].command, commandStart, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ) ) ? methods[commandIndex].command : null;
  608 + }
  609 +
  610 + // Find the next command that starts with commandStart and is different from previousSuggestion
  611 + for( int i = commandIndex + 1; i < methods.Count; i++ )
  612 + {
  613 + if( caseInsensitiveComparer.Compare( methods[i].command, previousSuggestion, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ) == 0 )
  614 + continue;
  615 + else if( caseInsensitiveComparer.IsPrefix( methods[i].command, commandStart, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ) )
  616 + return methods[i].command;
  617 + else
  618 + break;
  619 + }
  620 +
  621 + // Couldn't find a command that follows previousSuggestion and satisfies commandStart, loop back to the beginning of the autocomplete suggestions
  622 + string result = null;
  623 + for( int i = commandIndex - 1; i >= 0 && caseInsensitiveComparer.IsPrefix( methods[i].command, commandStart, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ); i-- )
  624 + result = methods[i].command;
  625 +
  626 + return result;
  627 + }
  628 +
  629 + // Parse the command and try to execute it
  630 + public static void ExecuteCommand( string command )
  631 + {
  632 + if( command == null )
  633 + return;
  634 +
  635 + command = command.Trim();
  636 +
  637 + if( command.Length == 0 )
  638 + return;
  639 +
  640 + // Split the command's arguments
  641 + commandArguments.Clear();
  642 + FetchArgumentsFromCommand( command, commandArguments );
  643 +
  644 + // Find all matching commands
  645 + matchingMethods.Clear();
  646 + bool parameterCountMismatch = false;
  647 + int commandIndex = FindCommandIndex( commandArguments[0] );
  648 + if( commandIndex >= 0 )
  649 + {
  650 + string _command = commandArguments[0];
  651 +
  652 + int commandLastIndex = commandIndex;
  653 + while( commandIndex > 0 && caseInsensitiveComparer.Compare( methods[commandIndex - 1].command, _command, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ) == 0 )
  654 + commandIndex--;
  655 + while( commandLastIndex < methods.Count - 1 && caseInsensitiveComparer.Compare( methods[commandLastIndex + 1].command, _command, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ) == 0 )
  656 + commandLastIndex++;
  657 +
  658 + while( commandIndex <= commandLastIndex )
  659 + {
  660 + if( !methods[commandIndex].IsValid() )
  661 + {
  662 + methods.RemoveAt( commandIndex );
  663 + commandLastIndex--;
  664 + }
  665 + else
  666 + {
  667 + // Check if number of parameters match
  668 + if( methods[commandIndex].parameterTypes.Length == commandArguments.Count - 1 )
  669 + matchingMethods.Add( methods[commandIndex] );
  670 + else
  671 + parameterCountMismatch = true;
  672 +
  673 + commandIndex++;
  674 + }
  675 + }
  676 + }
  677 +
  678 + if( matchingMethods.Count == 0 )
  679 + {
  680 + string _command = commandArguments[0];
  681 + FindCommands( _command, !parameterCountMismatch, matchingMethods );
  682 +
  683 + if( matchingMethods.Count == 0 )
  684 + Debug.LogWarning( string.Concat( "ERROR: can't find command '", _command, "'" ) );
  685 + else
  686 + {
  687 + int commandsLength = _command.Length + 75;
  688 + for( int i = 0; i < matchingMethods.Count; i++ )
  689 + commandsLength += matchingMethods[i].signature.Length + 7;
  690 +
  691 + StringBuilder stringBuilder = new StringBuilder( commandsLength );
  692 + if( parameterCountMismatch )
  693 + stringBuilder.Append( "ERROR: '" ).Append( _command ).Append( "' doesn't take " ).Append( commandArguments.Count - 1 ).Append( " parameter(s). Available command(s):" );
  694 + else
  695 + stringBuilder.Append( "ERROR: can't find command '" ).Append( _command ).Append( "'. Did you mean:" );
  696 +
  697 + for( int i = 0; i < matchingMethods.Count; i++ )
  698 + stringBuilder.Append( "\n - " ).Append( matchingMethods[i].signature );
  699 +
  700 + Debug.LogWarning( stringBuilder.ToString() );
  701 +
  702 + // The log that lists method signature(s) for this command should automatically be expanded for better UX
  703 + if( DebugLogManager.Instance )
  704 + DebugLogManager.Instance.AdjustLatestPendingLog( true, true );
  705 + }
  706 +
  707 + return;
  708 + }
  709 +
  710 + ConsoleMethodInfo methodToExecute = null;
  711 + object[] parameters = new object[commandArguments.Count - 1];
  712 + string errorMessage = null;
  713 + for( int i = 0; i < matchingMethods.Count && methodToExecute == null; i++ )
  714 + {
  715 + ConsoleMethodInfo methodInfo = matchingMethods[i];
  716 +
  717 + // Parse the parameters into objects
  718 + bool success = true;
  719 + for( int j = 0; j < methodInfo.parameterTypes.Length && success; j++ )
  720 + {
  721 + try
  722 + {
  723 + string argument = commandArguments[j + 1];
  724 + Type parameterType = methodInfo.parameterTypes[j];
  725 +
  726 + object val;
  727 + if( ParseArgument( argument, parameterType, out val ) )
  728 + parameters[j] = val;
  729 + else
  730 + {
  731 + success = false;
  732 + errorMessage = string.Concat( "ERROR: couldn't parse ", argument, " to ", GetTypeReadableName( parameterType ) );
  733 + }
  734 + }
  735 + catch( Exception e )
  736 + {
  737 + success = false;
  738 + errorMessage = "ERROR: " + e.ToString();
  739 + }
  740 + }
  741 +
  742 + if( success )
  743 + methodToExecute = methodInfo;
  744 + }
  745 +
  746 + if( methodToExecute == null )
  747 + Debug.LogWarning( !string.IsNullOrEmpty( errorMessage ) ? errorMessage : "ERROR: something went wrong" );
  748 + else
  749 + {
  750 + // Execute the method associated with the command
  751 + object result = methodToExecute.method.Invoke( methodToExecute.instance, parameters );
  752 + if( methodToExecute.method.ReturnType != typeof( void ) )
  753 + {
  754 + // Print the returned value to the console
  755 + if( result == null || result.Equals( null ) )
  756 + Debug.Log( "Returned: null" );
  757 + else
  758 + Debug.Log( "Returned: " + result.ToString() );
  759 + }
  760 +
  761 + if( OnCommandExecuted != null )
  762 + OnCommandExecuted( methodToExecute.command, parameters );
  763 + }
  764 + }
  765 +
  766 + public static void FetchArgumentsFromCommand( string command, List<string> commandArguments )
  767 + {
  768 + for( int i = 0; i < command.Length; i++ )
  769 + {
  770 + if( char.IsWhiteSpace( command[i] ) )
  771 + continue;
  772 +
  773 + int delimiterIndex = IndexOfDelimiterGroup( command[i] );
  774 + if( delimiterIndex >= 0 )
  775 + {
  776 + int endIndex = IndexOfDelimiterGroupEnd( command, delimiterIndex, i + 1 );
  777 + commandArguments.Add( command.Substring( i + 1, endIndex - i - 1 ) );
  778 + i = ( endIndex < command.Length - 1 && command[endIndex + 1] == ',' ) ? endIndex + 1 : endIndex;
  779 + }
  780 + else
  781 + {
  782 + int endIndex = IndexOfChar( command, ' ', i + 1 );
  783 + commandArguments.Add( command.Substring( i, command[endIndex - 1] == ',' ? endIndex - 1 - i : endIndex - i ) );
  784 + i = endIndex;
  785 + }
  786 + }
  787 + }
  788 +
  789 + public static void FindCommands( string commandName, bool allowSubstringMatching, List<ConsoleMethodInfo> matchingCommands )
  790 + {
  791 + if( allowSubstringMatching )
  792 + {
  793 + for( int i = 0; i < methods.Count; i++ )
  794 + {
  795 + if( methods[i].IsValid() && caseInsensitiveComparer.IndexOf( methods[i].command, commandName, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ) >= 0 )
  796 + matchingCommands.Add( methods[i] );
  797 + }
  798 + }
  799 + else
  800 + {
  801 + for( int i = 0; i < methods.Count; i++ )
  802 + {
  803 + if( methods[i].IsValid() && caseInsensitiveComparer.Compare( methods[i].command, commandName, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ) == 0 )
  804 + matchingCommands.Add( methods[i] );
  805 + }
  806 + }
  807 + }
  808 +
  809 + // Finds all commands that have a matching signature with command
  810 + // - caretIndexIncrements: indices inside "string command" that separate two arguments in the command. This is used to
  811 + // figure out which argument the caret is standing on
  812 + // - commandName: command's name (first argument)
  813 + internal static void GetCommandSuggestions( string command, List<ConsoleMethodInfo> matchingCommands, List<int> caretIndexIncrements, ref string commandName, out int numberOfParameters )
  814 + {
  815 + bool commandNameCalculated = false;
  816 + bool commandNameFullyTyped = false;
  817 + numberOfParameters = -1;
  818 + for( int i = 0; i < command.Length; i++ )
  819 + {
  820 + if( char.IsWhiteSpace( command[i] ) )
  821 + continue;
  822 +
  823 + int delimiterIndex = IndexOfDelimiterGroup( command[i] );
  824 + if( delimiterIndex >= 0 )
  825 + {
  826 + int endIndex = IndexOfDelimiterGroupEnd( command, delimiterIndex, i + 1 );
  827 + if( !commandNameCalculated )
  828 + {
  829 + commandNameCalculated = true;
  830 + commandNameFullyTyped = command.Length > endIndex;
  831 +
  832 + int commandNameLength = endIndex - i - 1;
  833 + if( commandName == null || commandNameLength == 0 || commandName.Length != commandNameLength || caseInsensitiveComparer.IndexOf( command, commandName, i + 1, commandNameLength, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ) != i + 1 )
  834 + commandName = command.Substring( i + 1, commandNameLength );
  835 + }
  836 +
  837 + i = ( endIndex < command.Length - 1 && command[endIndex + 1] == ',' ) ? endIndex + 1 : endIndex;
  838 + caretIndexIncrements.Add( i + 1 );
  839 + }
  840 + else
  841 + {
  842 + int endIndex = IndexOfChar( command, ' ', i + 1 );
  843 + if( !commandNameCalculated )
  844 + {
  845 + commandNameCalculated = true;
  846 + commandNameFullyTyped = command.Length > endIndex;
  847 +
  848 + int commandNameLength = command[endIndex - 1] == ',' ? endIndex - 1 - i : endIndex - i;
  849 + if( commandName == null || commandNameLength == 0 || commandName.Length != commandNameLength || caseInsensitiveComparer.IndexOf( command, commandName, i, commandNameLength, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ) != i )
  850 + commandName = command.Substring( i, commandNameLength );
  851 + }
  852 +
  853 + i = endIndex;
  854 + caretIndexIncrements.Add( i );
  855 + }
  856 +
  857 + numberOfParameters++;
  858 + }
  859 +
  860 + if( !commandNameCalculated )
  861 + commandName = string.Empty;
  862 +
  863 + if( !string.IsNullOrEmpty( commandName ) )
  864 + {
  865 + int commandIndex = FindCommandIndex( commandName );
  866 + if( commandIndex < 0 )
  867 + commandIndex = ~commandIndex;
  868 +
  869 + int commandLastIndex = commandIndex;
  870 + if( !commandNameFullyTyped )
  871 + {
  872 + // Match all commands that start with commandName
  873 + if( commandIndex < methods.Count && caseInsensitiveComparer.IsPrefix( methods[commandIndex].command, commandName, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ) )
  874 + {
  875 + while( commandIndex > 0 && caseInsensitiveComparer.IsPrefix( methods[commandIndex - 1].command, commandName, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ) )
  876 + commandIndex--;
  877 + while( commandLastIndex < methods.Count - 1 && caseInsensitiveComparer.IsPrefix( methods[commandLastIndex + 1].command, commandName, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ) )
  878 + commandLastIndex++;
  879 + }
  880 + else
  881 + commandLastIndex = -1;
  882 + }
  883 + else
  884 + {
  885 + // Match only the commands that are equal to commandName
  886 + if( commandIndex < methods.Count && caseInsensitiveComparer.Compare( methods[commandIndex].command, commandName, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ) == 0 )
  887 + {
  888 + while( commandIndex > 0 && caseInsensitiveComparer.Compare( methods[commandIndex - 1].command, commandName, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ) == 0 )
  889 + commandIndex--;
  890 + while( commandLastIndex < methods.Count - 1 && caseInsensitiveComparer.Compare( methods[commandLastIndex + 1].command, commandName, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ) == 0 )
  891 + commandLastIndex++;
  892 + }
  893 + else
  894 + commandLastIndex = -1;
  895 + }
  896 +
  897 + for( ; commandIndex <= commandLastIndex; commandIndex++ )
  898 + {
  899 + if( methods[commandIndex].parameterTypes.Length >= numberOfParameters )
  900 + matchingCommands.Add( methods[commandIndex] );
  901 + }
  902 + }
  903 + }
  904 +
  905 + // Find the index of the delimiter group that 'c' belongs to
  906 + private static int IndexOfDelimiterGroup( char c )
  907 + {
  908 + for( int i = 0; i < inputDelimiters.Length; i++ )
  909 + {
  910 + if( c == inputDelimiters[i][0] )
  911 + return i;
  912 + }
  913 +
  914 + return -1;
  915 + }
  916 +
  917 + private static int IndexOfDelimiterGroupEnd( string command, int delimiterIndex, int startIndex )
  918 + {
  919 + char startChar = inputDelimiters[delimiterIndex][0];
  920 + char endChar = inputDelimiters[delimiterIndex][1];
  921 +
  922 + // Check delimiter's depth for array support (e.g. [[1 2] [3 4]] for Vector2 array)
  923 + int depth = 1;
  924 +
  925 + for( int i = startIndex; i < command.Length; i++ )
  926 + {
  927 + char c = command[i];
  928 + if( c == endChar && --depth <= 0 )
  929 + return i;
  930 + else if( c == startChar )
  931 + depth++;
  932 + }
  933 +
  934 + return command.Length;
  935 + }
  936 +
  937 + // Find the index of char in the string, or return the length of string instead of -1
  938 + private static int IndexOfChar( string command, char c, int startIndex )
  939 + {
  940 + int result = command.IndexOf( c, startIndex );
  941 + if( result < 0 )
  942 + result = command.Length;
  943 +
  944 + return result;
  945 + }
  946 +
  947 + // Find command's index in the list of registered commands using binary search
  948 + private static int FindCommandIndex( string command )
  949 + {
  950 + int min = 0;
  951 + int max = methods.Count - 1;
  952 + while( min <= max )
  953 + {
  954 + int mid = ( min + max ) / 2;
  955 + int comparison = caseInsensitiveComparer.Compare( command, methods[mid].command, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace );
  956 + if( comparison == 0 )
  957 + return mid;
  958 + else if( comparison < 0 )
  959 + max = mid - 1;
  960 + else
  961 + min = mid + 1;
  962 + }
  963 +
  964 + return ~min;
  965 + }
  966 +
  967 + public static bool IsSupportedArrayType( Type type )
  968 + {
  969 + if( type.IsArray )
  970 + {
  971 + if( type.GetArrayRank() != 1 )
  972 + return false;
  973 +
  974 + type = type.GetElementType();
  975 + }
  976 + else if( type.IsGenericType )
  977 + {
  978 + if( type.GetGenericTypeDefinition() != typeof( List<> ) )
  979 + return false;
  980 +
  981 + type = type.GetGenericArguments()[0];
  982 + }
  983 + else
  984 + return false;
  985 +
  986 + return parseFunctions.ContainsKey( type ) || typeof( Component ).IsAssignableFrom( type ) || type.IsEnum;
  987 + }
  988 +
  989 + public static string GetTypeReadableName( Type type )
  990 + {
  991 + string result;
  992 + if( typeReadableNames.TryGetValue( type, out result ) )
  993 + return result;
  994 +
  995 + if( IsSupportedArrayType( type ) )
  996 + {
  997 + Type elementType = type.IsArray ? type.GetElementType() : type.GetGenericArguments()[0];
  998 + if( typeReadableNames.TryGetValue( elementType, out result ) )
  999 + return result + "[]";
  1000 + else
  1001 + return elementType.Name + "[]";
  1002 + }
  1003 +
  1004 + return type.Name;
  1005 + }
  1006 +
  1007 + public static bool ParseArgument( string input, Type argumentType, out object output )
  1008 + {
  1009 + ParseFunction parseFunction;
  1010 + if( parseFunctions.TryGetValue( argumentType, out parseFunction ) )
  1011 + return parseFunction( input, out output );
  1012 + else if( typeof( Component ).IsAssignableFrom( argumentType ) )
  1013 + return ParseComponent( input, argumentType, out output );
  1014 + else if( argumentType.IsEnum )
  1015 + return ParseEnum( input, argumentType, out output );
  1016 + else if( IsSupportedArrayType( argumentType ) )
  1017 + return ParseArray( input, argumentType, out output );
  1018 + else
  1019 + {
  1020 + output = null;
  1021 + return false;
  1022 + }
  1023 + }
  1024 +
  1025 + public static bool ParseString( string input, out object output )
  1026 + {
  1027 + output = input;
  1028 + return true;
  1029 + }
  1030 +
  1031 + public static bool ParseBool( string input, out object output )
  1032 + {
  1033 + if( input == "1" || input.ToLowerInvariant() == "true" )
  1034 + {
  1035 + output = true;
  1036 + return true;
  1037 + }
  1038 +
  1039 + if( input == "0" || input.ToLowerInvariant() == "false" )
  1040 + {
  1041 + output = false;
  1042 + return true;
  1043 + }
  1044 +
  1045 + output = false;
  1046 + return false;
  1047 + }
  1048 +
  1049 + public static bool ParseInt( string input, out object output )
  1050 + {
  1051 + int value;
  1052 + bool result = int.TryParse( input, out value );
  1053 +
  1054 + output = value;
  1055 + return result;
  1056 + }
  1057 +
  1058 + public static bool ParseUInt( string input, out object output )
  1059 + {
  1060 + uint value;
  1061 + bool result = uint.TryParse( input, out value );
  1062 +
  1063 + output = value;
  1064 + return result;
  1065 + }
  1066 +
  1067 + public static bool ParseLong( string input, out object output )
  1068 + {
  1069 + long value;
  1070 + bool result = long.TryParse( !input.EndsWith( "L", StringComparison.OrdinalIgnoreCase ) ? input : input.Substring( 0, input.Length - 1 ), out value );
  1071 +
  1072 + output = value;
  1073 + return result;
  1074 + }
  1075 +
  1076 + public static bool ParseULong( string input, out object output )
  1077 + {
  1078 + ulong value;
  1079 + bool result = ulong.TryParse( !input.EndsWith( "L", StringComparison.OrdinalIgnoreCase ) ? input : input.Substring( 0, input.Length - 1 ), out value );
  1080 +
  1081 + output = value;
  1082 + return result;
  1083 + }
  1084 +
  1085 + public static bool ParseByte( string input, out object output )
  1086 + {
  1087 + byte value;
  1088 + bool result = byte.TryParse( input, out value );
  1089 +
  1090 + output = value;
  1091 + return result;
  1092 + }
  1093 +
  1094 + public static bool ParseSByte( string input, out object output )
  1095 + {
  1096 + sbyte value;
  1097 + bool result = sbyte.TryParse( input, out value );
  1098 +
  1099 + output = value;
  1100 + return result;
  1101 + }
  1102 +
  1103 + public static bool ParseShort( string input, out object output )
  1104 + {
  1105 + short value;
  1106 + bool result = short.TryParse( input, out value );
  1107 +
  1108 + output = value;
  1109 + return result;
  1110 + }
  1111 +
  1112 + public static bool ParseUShort( string input, out object output )
  1113 + {
  1114 + ushort value;
  1115 + bool result = ushort.TryParse( input, out value );
  1116 +
  1117 + output = value;
  1118 + return result;
  1119 + }
  1120 +
  1121 + public static bool ParseChar( string input, out object output )
  1122 + {
  1123 + char value;
  1124 + bool result = char.TryParse( input, out value );
  1125 +
  1126 + output = value;
  1127 + return result;
  1128 + }
  1129 +
  1130 + public static bool ParseFloat( string input, out object output )
  1131 + {
  1132 + float value;
  1133 + bool result = float.TryParse( !input.EndsWith( "f", StringComparison.OrdinalIgnoreCase ) ? input : input.Substring( 0, input.Length - 1 ), NumberStyles.Float, CultureInfo.InvariantCulture, out value );
  1134 +
  1135 + output = value;
  1136 + return result;
  1137 + }
  1138 +
  1139 + public static bool ParseDouble( string input, out object output )
  1140 + {
  1141 + double value;
  1142 + bool result = double.TryParse( !input.EndsWith( "f", StringComparison.OrdinalIgnoreCase ) ? input : input.Substring( 0, input.Length - 1 ), NumberStyles.Float, CultureInfo.InvariantCulture, out value );
  1143 +
  1144 + output = value;
  1145 + return result;
  1146 + }
  1147 +
  1148 + public static bool ParseDecimal( string input, out object output )
  1149 + {
  1150 + decimal value;
  1151 + bool result = decimal.TryParse( !input.EndsWith( "f", StringComparison.OrdinalIgnoreCase ) ? input : input.Substring( 0, input.Length - 1 ), NumberStyles.Float, CultureInfo.InvariantCulture, out value );
  1152 +
  1153 + output = value;
  1154 + return result;
  1155 + }
  1156 +
  1157 + public static bool ParseVector2( string input, out object output )
  1158 + {
  1159 + return ParseVector( input, typeof( Vector2 ), out output );
  1160 + }
  1161 +
  1162 + public static bool ParseVector3( string input, out object output )
  1163 + {
  1164 + return ParseVector( input, typeof( Vector3 ), out output );
  1165 + }
  1166 +
  1167 + public static bool ParseVector4( string input, out object output )
  1168 + {
  1169 + return ParseVector( input, typeof( Vector4 ), out output );
  1170 + }
  1171 +
  1172 + public static bool ParseQuaternion( string input, out object output )
  1173 + {
  1174 + return ParseVector( input, typeof( Quaternion ), out output );
  1175 + }
  1176 +
  1177 + public static bool ParseColor( string input, out object output )
  1178 + {
  1179 + return ParseVector( input, typeof( Color ), out output );
  1180 + }
  1181 +
  1182 + public static bool ParseColor32( string input, out object output )
  1183 + {
  1184 + return ParseVector( input, typeof( Color32 ), out output );
  1185 + }
  1186 +
  1187 + public static bool ParseRect( string input, out object output )
  1188 + {
  1189 + return ParseVector( input, typeof( Rect ), out output );
  1190 + }
  1191 +
  1192 + public static bool ParseRectOffset( string input, out object output )
  1193 + {
  1194 + return ParseVector( input, typeof( RectOffset ), out output );
  1195 + }
  1196 +
  1197 + public static bool ParseBounds( string input, out object output )
  1198 + {
  1199 + return ParseVector( input, typeof( Bounds ), out output );
  1200 + }
  1201 +
  1202 +#if UNITY_2017_2_OR_NEWER
  1203 + public static bool ParseVector2Int( string input, out object output )
  1204 + {
  1205 + return ParseVector( input, typeof( Vector2Int ), out output );
  1206 + }
  1207 +
  1208 + public static bool ParseVector3Int( string input, out object output )
  1209 + {
  1210 + return ParseVector( input, typeof( Vector3Int ), out output );
  1211 + }
  1212 +
  1213 + public static bool ParseRectInt( string input, out object output )
  1214 + {
  1215 + return ParseVector( input, typeof( RectInt ), out output );
  1216 + }
  1217 +
  1218 + public static bool ParseBoundsInt( string input, out object output )
  1219 + {
  1220 + return ParseVector( input, typeof( BoundsInt ), out output );
  1221 + }
  1222 +#endif
  1223 +
  1224 + public static bool ParseGameObject( string input, out object output )
  1225 + {
  1226 + output = input == "null" ? null : GameObject.Find( input );
  1227 + return true;
  1228 + }
  1229 +
  1230 + public static bool ParseComponent( string input, Type componentType, out object output )
  1231 + {
  1232 + GameObject gameObject = input == "null" ? null : GameObject.Find( input );
  1233 + output = gameObject ? gameObject.GetComponent( componentType ) : null;
  1234 + return true;
  1235 + }
  1236 +
  1237 + public static bool ParseEnum( string input, Type enumType, out object output )
  1238 + {
  1239 + const int NONE = 0, OR = 1, AND = 2;
  1240 +
  1241 + int outputInt = 0;
  1242 + int operation = NONE; // 0: nothing, 1: OR with outputInt, 2: AND with outputInt
  1243 + for( int i = 0; i < input.Length; i++ )
  1244 + {
  1245 + string enumStr;
  1246 + int orIndex = input.IndexOf( '|', i );
  1247 + int andIndex = input.IndexOf( '&', i );
  1248 + if( orIndex < 0 )
  1249 + enumStr = input.Substring( i, ( andIndex < 0 ? input.Length : andIndex ) - i ).Trim();
  1250 + else
  1251 + enumStr = input.Substring( i, ( andIndex < 0 ? orIndex : Mathf.Min( andIndex, orIndex ) ) - i ).Trim();
  1252 +
  1253 + int value;
  1254 + if( !int.TryParse( enumStr, out value ) )
  1255 + {
  1256 + try
  1257 + {
  1258 + // Case-insensitive enum parsing
  1259 + value = Convert.ToInt32( Enum.Parse( enumType, enumStr, true ) );
  1260 + }
  1261 + catch
  1262 + {
  1263 + output = null;
  1264 + return false;
  1265 + }
  1266 + }
  1267 +
  1268 + if( operation == NONE )
  1269 + outputInt = value;
  1270 + else if( operation == OR )
  1271 + outputInt |= value;
  1272 + else
  1273 + outputInt &= value;
  1274 +
  1275 + if( orIndex >= 0 )
  1276 + {
  1277 + if( andIndex > orIndex )
  1278 + {
  1279 + operation = AND;
  1280 + i = andIndex;
  1281 + }
  1282 + else
  1283 + {
  1284 + operation = OR;
  1285 + i = orIndex;
  1286 + }
  1287 + }
  1288 + else if( andIndex >= 0 )
  1289 + {
  1290 + operation = AND;
  1291 + i = andIndex;
  1292 + }
  1293 + else
  1294 + i = input.Length;
  1295 + }
  1296 +
  1297 + output = Enum.ToObject( enumType, outputInt );
  1298 + return true;
  1299 + }
  1300 +
  1301 + public static bool ParseArray( string input, Type arrayType, out object output )
  1302 + {
  1303 + List<string> valuesToParse = new List<string>( 2 );
  1304 + FetchArgumentsFromCommand( input, valuesToParse );
  1305 +
  1306 + IList result = (IList) Activator.CreateInstance( arrayType, new object[1] { valuesToParse.Count } );
  1307 + output = result;
  1308 +
  1309 + if( arrayType.IsArray )
  1310 + {
  1311 + Type elementType = arrayType.GetElementType();
  1312 + for( int i = 0; i < valuesToParse.Count; i++ )
  1313 + {
  1314 + object obj;
  1315 + if( !ParseArgument( valuesToParse[i], elementType, out obj ) )
  1316 + return false;
  1317 +
  1318 + result[i] = obj;
  1319 + }
  1320 + }
  1321 + else
  1322 + {
  1323 + Type elementType = arrayType.GetGenericArguments()[0];
  1324 + for( int i = 0; i < valuesToParse.Count; i++ )
  1325 + {
  1326 + object obj;
  1327 + if( !ParseArgument( valuesToParse[i], elementType, out obj ) )
  1328 + return false;
  1329 +
  1330 + result.Add( obj );
  1331 + }
  1332 + }
  1333 +
  1334 + return true;
  1335 + }
  1336 +
  1337 + // Create a vector of specified type (fill the blank slots with 0 or ignore unnecessary slots)
  1338 + private static bool ParseVector( string input, Type vectorType, out object output )
  1339 + {
  1340 + List<string> tokens = new List<string>( input.Replace( ',', ' ' ).Trim().Split( ' ' ) );
  1341 + for( int i = tokens.Count - 1; i >= 0; i-- )
  1342 + {
  1343 + tokens[i] = tokens[i].Trim();
  1344 + if( tokens[i].Length == 0 )
  1345 + tokens.RemoveAt( i );
  1346 + }
  1347 +
  1348 + float[] tokenValues = new float[tokens.Count];
  1349 + for( int i = 0; i < tokens.Count; i++ )
  1350 + {
  1351 + object val;
  1352 + if( !ParseFloat( tokens[i], out val ) )
  1353 + {
  1354 + if( vectorType == typeof( Vector3 ) )
  1355 + output = Vector3.zero;
  1356 + else if( vectorType == typeof( Vector2 ) )
  1357 + output = Vector2.zero;
  1358 + else
  1359 + output = Vector4.zero;
  1360 +
  1361 + return false;
  1362 + }
  1363 +
  1364 + tokenValues[i] = (float) val;
  1365 + }
  1366 +
  1367 + if( vectorType == typeof( Vector3 ) )
  1368 + {
  1369 + Vector3 result = Vector3.zero;
  1370 +
  1371 + for( int i = 0; i < tokenValues.Length && i < 3; i++ )
  1372 + result[i] = tokenValues[i];
  1373 +
  1374 + output = result;
  1375 + }
  1376 + else if( vectorType == typeof( Vector2 ) )
  1377 + {
  1378 + Vector2 result = Vector2.zero;
  1379 +
  1380 + for( int i = 0; i < tokenValues.Length && i < 2; i++ )
  1381 + result[i] = tokenValues[i];
  1382 +
  1383 + output = result;
  1384 + }
  1385 + else if( vectorType == typeof( Vector4 ) )
  1386 + {
  1387 + Vector4 result = Vector4.zero;
  1388 +
  1389 + for( int i = 0; i < tokenValues.Length && i < 4; i++ )
  1390 + result[i] = tokenValues[i];
  1391 +
  1392 + output = result;
  1393 + }
  1394 + else if( vectorType == typeof( Quaternion ) )
  1395 + {
  1396 + Quaternion result = Quaternion.identity;
  1397 +
  1398 + for( int i = 0; i < tokenValues.Length && i < 4; i++ )
  1399 + result[i] = tokenValues[i];
  1400 +
  1401 + output = result;
  1402 + }
  1403 + else if( vectorType == typeof( Color ) )
  1404 + {
  1405 + Color result = Color.black;
  1406 +
  1407 + for( int i = 0; i < tokenValues.Length && i < 4; i++ )
  1408 + result[i] = tokenValues[i];
  1409 +
  1410 + output = result;
  1411 + }
  1412 + else if( vectorType == typeof( Color32 ) )
  1413 + {
  1414 + Color32 result = new Color32( 0, 0, 0, 255 );
  1415 +
  1416 + if( tokenValues.Length > 0 )
  1417 + result.r = (byte) Mathf.RoundToInt( tokenValues[0] );
  1418 + if( tokenValues.Length > 1 )
  1419 + result.g = (byte) Mathf.RoundToInt( tokenValues[1] );
  1420 + if( tokenValues.Length > 2 )
  1421 + result.b = (byte) Mathf.RoundToInt( tokenValues[2] );
  1422 + if( tokenValues.Length > 3 )
  1423 + result.a = (byte) Mathf.RoundToInt( tokenValues[3] );
  1424 +
  1425 + output = result;
  1426 + }
  1427 + else if( vectorType == typeof( Rect ) )
  1428 + {
  1429 + Rect result = Rect.zero;
  1430 +
  1431 + if( tokenValues.Length > 0 )
  1432 + result.x = tokenValues[0];
  1433 + if( tokenValues.Length > 1 )
  1434 + result.y = tokenValues[1];
  1435 + if( tokenValues.Length > 2 )
  1436 + result.width = tokenValues[2];
  1437 + if( tokenValues.Length > 3 )
  1438 + result.height = tokenValues[3];
  1439 +
  1440 + output = result;
  1441 + }
  1442 + else if( vectorType == typeof( RectOffset ) )
  1443 + {
  1444 + RectOffset result = new RectOffset();
  1445 +
  1446 + if( tokenValues.Length > 0 )
  1447 + result.left = Mathf.RoundToInt( tokenValues[0] );
  1448 + if( tokenValues.Length > 1 )
  1449 + result.right = Mathf.RoundToInt( tokenValues[1] );
  1450 + if( tokenValues.Length > 2 )
  1451 + result.top = Mathf.RoundToInt( tokenValues[2] );
  1452 + if( tokenValues.Length > 3 )
  1453 + result.bottom = Mathf.RoundToInt( tokenValues[3] );
  1454 +
  1455 + output = result;
  1456 + }
  1457 + else if( vectorType == typeof( Bounds ) )
  1458 + {
  1459 + Vector3 center = Vector3.zero;
  1460 + for( int i = 0; i < tokenValues.Length && i < 3; i++ )
  1461 + center[i] = tokenValues[i];
  1462 +
  1463 + Vector3 size = Vector3.zero;
  1464 + for( int i = 3; i < tokenValues.Length && i < 6; i++ )
  1465 + size[i - 3] = tokenValues[i];
  1466 +
  1467 + output = new Bounds( center, size );
  1468 + }
  1469 +#if UNITY_2017_2_OR_NEWER
  1470 + else if( vectorType == typeof( Vector3Int ) )
  1471 + {
  1472 + Vector3Int result = Vector3Int.zero;
  1473 +
  1474 + for( int i = 0; i < tokenValues.Length && i < 3; i++ )
  1475 + result[i] = Mathf.RoundToInt( tokenValues[i] );
  1476 +
  1477 + output = result;
  1478 + }
  1479 + else if( vectorType == typeof( Vector2Int ) )
  1480 + {
  1481 + Vector2Int result = Vector2Int.zero;
  1482 +
  1483 + for( int i = 0; i < tokenValues.Length && i < 2; i++ )
  1484 + result[i] = Mathf.RoundToInt( tokenValues[i] );
  1485 +
  1486 + output = result;
  1487 + }
  1488 + else if( vectorType == typeof( RectInt ) )
  1489 + {
  1490 + RectInt result = new RectInt();
  1491 +
  1492 + if( tokenValues.Length > 0 )
  1493 + result.x = Mathf.RoundToInt( tokenValues[0] );
  1494 + if( tokenValues.Length > 1 )
  1495 + result.y = Mathf.RoundToInt( tokenValues[1] );
  1496 + if( tokenValues.Length > 2 )
  1497 + result.width = Mathf.RoundToInt( tokenValues[2] );
  1498 + if( tokenValues.Length > 3 )
  1499 + result.height = Mathf.RoundToInt( tokenValues[3] );
  1500 +
  1501 + output = result;
  1502 + }
  1503 + else if( vectorType == typeof( BoundsInt ) )
  1504 + {
  1505 + Vector3Int center = Vector3Int.zero;
  1506 + for( int i = 0; i < tokenValues.Length && i < 3; i++ )
  1507 + center[i] = Mathf.RoundToInt( tokenValues[i] );
  1508 +
  1509 + Vector3Int size = Vector3Int.zero;
  1510 + for( int i = 3; i < tokenValues.Length && i < 6; i++ )
  1511 + size[i - 3] = Mathf.RoundToInt( tokenValues[i] );
  1512 +
  1513 + output = new BoundsInt( center, size );
  1514 + }
  1515 +#endif
  1516 + else
  1517 + {
  1518 + output = null;
  1519 + return false;
  1520 + }
  1521 +
  1522 + return true;
  1523 + }
  1524 + }
  1525 +}
  1 +fileFormatVersion: 2
  2 +guid: d15693a03d0d33b4892c6365a2a97e19
  3 +timeCreated: 1472036503
  4 +licenseType: Store
  5 +MonoImporter:
  6 + serializedVersion: 2
  7 + defaultReferences: []
  8 + executionOrder: 0
  9 + icon: {instanceID: 0}
  10 + userData:
  11 + assetBundleName:
  12 + assetBundleVariant:
  1 +using System.Collections.Generic;
  2 +using System.Globalization;
  3 +using System.Text;
  4 +using UnityEngine;
  5 +
  6 +// Container for a simple debug entry
  7 +namespace IngameDebugConsole
  8 +{
  9 + public class DebugLogEntry
  10 + {
  11 + private const int HASH_NOT_CALCULATED = -623218;
  12 +
  13 + public string logString;
  14 + public string stackTrace;
  15 + private string completeLog;
  16 +
  17 + // Sprite to show with this entry
  18 + public Sprite logTypeSpriteRepresentation;
  19 +
  20 + // Collapsed count
  21 + public int count;
  22 +
  23 + // Index of this entry among all collapsed entries
  24 + public int collapsedIndex;
  25 +
  26 + private int hashValue;
  27 +
  28 + public void Initialize( string logString, string stackTrace )
  29 + {
  30 + this.logString = logString;
  31 + this.stackTrace = stackTrace;
  32 +
  33 + completeLog = null;
  34 + count = 1;
  35 + hashValue = HASH_NOT_CALCULATED;
  36 + }
  37 +
  38 + public void Clear()
  39 + {
  40 + logString = null;
  41 + stackTrace = null;
  42 + completeLog = null;
  43 + }
  44 +
  45 + // Checks if logString or stackTrace contains the search term
  46 + public bool MatchesSearchTerm( string searchTerm )
  47 + {
  48 + return ( logString != null && DebugLogConsole.caseInsensitiveComparer.IndexOf( logString, searchTerm, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ) >= 0 ) ||
  49 + ( stackTrace != null && DebugLogConsole.caseInsensitiveComparer.IndexOf( stackTrace, searchTerm, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ) >= 0 );
  50 + }
  51 +
  52 + // Return a string containing complete information about this debug entry
  53 + public override string ToString()
  54 + {
  55 + if( completeLog == null )
  56 + completeLog = string.Concat( logString, "\n", stackTrace );
  57 +
  58 + return completeLog;
  59 + }
  60 +
  61 + // Credit: https://stackoverflow.com/a/19250516/2373034
  62 + public int GetContentHashCode()
  63 + {
  64 + if( hashValue == HASH_NOT_CALCULATED )
  65 + {
  66 + unchecked
  67 + {
  68 + hashValue = 17;
  69 + hashValue = hashValue * 23 + ( logString == null ? 0 : logString.GetHashCode() );
  70 + hashValue = hashValue * 23 + ( stackTrace == null ? 0 : stackTrace.GetHashCode() );
  71 + }
  72 + }
  73 +
  74 + return hashValue;
  75 + }
  76 + }
  77 +
  78 + public struct QueuedDebugLogEntry
  79 + {
  80 + public readonly string logString;
  81 + public readonly string stackTrace;
  82 + public readonly LogType logType;
  83 +
  84 + public QueuedDebugLogEntry( string logString, string stackTrace, LogType logType )
  85 + {
  86 + this.logString = logString;
  87 + this.stackTrace = stackTrace;
  88 + this.logType = logType;
  89 + }
  90 +
  91 + // Checks if logString or stackTrace contains the search term
  92 + public bool MatchesSearchTerm( string searchTerm )
  93 + {
  94 + return ( logString != null && DebugLogConsole.caseInsensitiveComparer.IndexOf( logString, searchTerm, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ) >= 0 ) ||
  95 + ( stackTrace != null && DebugLogConsole.caseInsensitiveComparer.IndexOf( stackTrace, searchTerm, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ) >= 0 );
  96 + }
  97 + }
  98 +
  99 + public struct DebugLogEntryTimestamp
  100 + {
  101 + public readonly System.DateTime dateTime;
  102 +#if !IDG_OMIT_ELAPSED_TIME
  103 + public readonly float elapsedSeconds;
  104 +#endif
  105 +#if !IDG_OMIT_FRAMECOUNT
  106 + public readonly int frameCount;
  107 +#endif
  108 +
  109 +#if !IDG_OMIT_ELAPSED_TIME && !IDG_OMIT_FRAMECOUNT
  110 + public DebugLogEntryTimestamp( System.DateTime dateTime, float elapsedSeconds, int frameCount )
  111 +#elif !IDG_OMIT_ELAPSED_TIME
  112 + public DebugLogEntryTimestamp( System.DateTime dateTime, float elapsedSeconds )
  113 +#elif !IDG_OMIT_FRAMECOUNT
  114 + public DebugLogEntryTimestamp( System.DateTime dateTime, int frameCount )
  115 +#else
  116 + public DebugLogEntryTimestamp( System.DateTime dateTime )
  117 +#endif
  118 + {
  119 + this.dateTime = dateTime;
  120 +#if !IDG_OMIT_ELAPSED_TIME
  121 + this.elapsedSeconds = elapsedSeconds;
  122 +#endif
  123 +#if !IDG_OMIT_FRAMECOUNT
  124 + this.frameCount = frameCount;
  125 +#endif
  126 + }
  127 +
  128 + public void AppendTime( StringBuilder sb )
  129 + {
  130 + // Add DateTime in format: [HH:mm:ss]
  131 + sb.Append( "[" );
  132 +
  133 + int hour = dateTime.Hour;
  134 + if( hour >= 10 )
  135 + sb.Append( hour );
  136 + else
  137 + sb.Append( "0" ).Append( hour );
  138 +
  139 + sb.Append( ":" );
  140 +
  141 + int minute = dateTime.Minute;
  142 + if( minute >= 10 )
  143 + sb.Append( minute );
  144 + else
  145 + sb.Append( "0" ).Append( minute );
  146 +
  147 + sb.Append( ":" );
  148 +
  149 + int second = dateTime.Second;
  150 + if( second >= 10 )
  151 + sb.Append( second );
  152 + else
  153 + sb.Append( "0" ).Append( second );
  154 +
  155 + sb.Append( "]" );
  156 + }
  157 +
  158 + public void AppendFullTimestamp( StringBuilder sb )
  159 + {
  160 + AppendTime( sb );
  161 +
  162 +#if !IDG_OMIT_ELAPSED_TIME && !IDG_OMIT_FRAMECOUNT
  163 + // Append elapsed seconds and frame count in format: [1.0s at #Frame]
  164 + sb.Append( "[" ).Append( elapsedSeconds.ToString( "F1" ) ).Append( "s at " ).Append( "#" ).Append( frameCount ).Append( "]" );
  165 +#elif !IDG_OMIT_ELAPSED_TIME
  166 + // Append elapsed seconds in format: [1.0s]
  167 + sb.Append( "[" ).Append( elapsedSeconds.ToString( "F1" ) ).Append( "s]" );
  168 +#elif !IDG_OMIT_FRAMECOUNT
  169 + // Append frame count in format: [#Frame]
  170 + sb.Append( "[#" ).Append( frameCount ).Append( "]" );
  171 +#endif
  172 + }
  173 + }
  174 +
  175 + public class DebugLogEntryContentEqualityComparer : EqualityComparer<DebugLogEntry>
  176 + {
  177 + public override bool Equals( DebugLogEntry x, DebugLogEntry y )
  178 + {
  179 + return x.logString == y.logString && x.stackTrace == y.stackTrace;
  180 + }
  181 +
  182 + public override int GetHashCode( DebugLogEntry obj )
  183 + {
  184 + return obj.GetContentHashCode();
  185 + }
  186 + }
  187 +}
  1 +fileFormatVersion: 2
  2 +guid: e7b1a420c564be040bf73b8a377fc2c2
  3 +timeCreated: 1466375168
  4 +licenseType: Store
  5 +MonoImporter:
  6 + serializedVersion: 2
  7 + defaultReferences: []
  8 + executionOrder: 0
  9 + icon: {instanceID: 0}
  10 + userData:
  11 + assetBundleName:
  12 + assetBundleVariant:
  1 +using UnityEngine;
  2 +using UnityEngine.UI;
  3 +using UnityEngine.EventSystems;
  4 +using System.Text;
  5 +#if UNITY_EDITOR
  6 +using UnityEditor;
  7 +using System.Text.RegularExpressions;
  8 +#endif
  9 +
  10 +// A UI element to show information about a debug entry
  11 +namespace IngameDebugConsole
  12 +{
  13 + public class DebugLogItem : MonoBehaviour, IPointerClickHandler
  14 + {
  15 + #region Platform Specific Elements
  16 +#if !UNITY_2018_1_OR_NEWER
  17 +#if !UNITY_EDITOR && UNITY_ANDROID
  18 + private static AndroidJavaClass m_ajc = null;
  19 + private static AndroidJavaClass AJC
  20 + {
  21 + get
  22 + {
  23 + if( m_ajc == null )
  24 + m_ajc = new AndroidJavaClass( "com.yasirkula.unity.DebugConsole" );
  25 +
  26 + return m_ajc;
  27 + }
  28 + }
  29 +
  30 + private static AndroidJavaObject m_context = null;
  31 + private static AndroidJavaObject Context
  32 + {
  33 + get
  34 + {
  35 + if( m_context == null )
  36 + {
  37 + using( AndroidJavaObject unityClass = new AndroidJavaClass( "com.unity3d.player.UnityPlayer" ) )
  38 + {
  39 + m_context = unityClass.GetStatic<AndroidJavaObject>( "currentActivity" );
  40 + }
  41 + }
  42 +
  43 + return m_context;
  44 + }
  45 + }
  46 +#elif !UNITY_EDITOR && UNITY_IOS
  47 + [System.Runtime.InteropServices.DllImport( "__Internal" )]
  48 + private static extern void _DebugConsole_CopyText( string text );
  49 +#endif
  50 +#endif
  51 + #endregion
  52 +
  53 +#pragma warning disable 0649
  54 + // Cached components
  55 + [SerializeField]
  56 + private RectTransform transformComponent;
  57 + public RectTransform Transform { get { return transformComponent; } }
  58 +
  59 + [SerializeField]
  60 + private Image imageComponent;
  61 + public Image Image { get { return imageComponent; } }
  62 +
  63 + [SerializeField]
  64 + private CanvasGroup canvasGroupComponent;
  65 + public CanvasGroup CanvasGroup { get { return canvasGroupComponent; } }
  66 +
  67 + [SerializeField]
  68 + private Text logText;
  69 + [SerializeField]
  70 + private Image logTypeImage;
  71 +
  72 + // Objects related to the collapsed count of the debug entry
  73 + [SerializeField]
  74 + private GameObject logCountParent;
  75 + [SerializeField]
  76 + private Text logCountText;
  77 +
  78 + [SerializeField]
  79 + private RectTransform copyLogButton;
  80 +#pragma warning restore 0649
  81 +
  82 + // Debug entry to show with this log item
  83 + private DebugLogEntry logEntry;
  84 + public DebugLogEntry Entry { get { return logEntry; } }
  85 +
  86 + private DebugLogEntryTimestamp? logEntryTimestamp;
  87 + public DebugLogEntryTimestamp? Timestamp { get { return logEntryTimestamp; } }
  88 +
  89 + // Index of the entry in the list of entries
  90 + [System.NonSerialized] public int Index;
  91 +
  92 + private bool isExpanded;
  93 + public bool Expanded { get { return isExpanded; } }
  94 +
  95 + private Vector2 logTextOriginalPosition;
  96 + private Vector2 logTextOriginalSize;
  97 + private float copyLogButtonHeight;
  98 +
  99 + private DebugLogRecycledListView listView;
  100 +
  101 + public void Initialize( DebugLogRecycledListView listView )
  102 + {
  103 + this.listView = listView;
  104 +
  105 + logTextOriginalPosition = logText.rectTransform.anchoredPosition;
  106 + logTextOriginalSize = logText.rectTransform.sizeDelta;
  107 + copyLogButtonHeight = copyLogButton.anchoredPosition.y + copyLogButton.sizeDelta.y + 2f; // 2f: space between text and button
  108 +
  109 +#if !UNITY_EDITOR && UNITY_WEBGL
  110 + copyLogButton.gameObject.AddComponent<DebugLogItemCopyWebGL>().Initialize( this );
  111 +#endif
  112 + }
  113 +
  114 + public void SetContent( DebugLogEntry logEntry, DebugLogEntryTimestamp? logEntryTimestamp, int entryIndex, bool isExpanded )
  115 + {
  116 + this.logEntry = logEntry;
  117 + this.logEntryTimestamp = logEntryTimestamp;
  118 + this.Index = entryIndex;
  119 + this.isExpanded = isExpanded;
  120 +
  121 + Vector2 size = transformComponent.sizeDelta;
  122 + if( isExpanded )
  123 + {
  124 + logText.horizontalOverflow = HorizontalWrapMode.Wrap;
  125 + size.y = listView.SelectedItemHeight;
  126 +
  127 + if( !copyLogButton.gameObject.activeSelf )
  128 + {
  129 + copyLogButton.gameObject.SetActive( true );
  130 +
  131 + logText.rectTransform.anchoredPosition = new Vector2( logTextOriginalPosition.x, logTextOriginalPosition.y + copyLogButtonHeight * 0.5f );
  132 + logText.rectTransform.sizeDelta = logTextOriginalSize - new Vector2( 0f, copyLogButtonHeight );
  133 + }
  134 + }
  135 + else
  136 + {
  137 + logText.horizontalOverflow = HorizontalWrapMode.Overflow;
  138 + size.y = listView.ItemHeight;
  139 +
  140 + if( copyLogButton.gameObject.activeSelf )
  141 + {
  142 + copyLogButton.gameObject.SetActive( false );
  143 +
  144 + logText.rectTransform.anchoredPosition = logTextOriginalPosition;
  145 + logText.rectTransform.sizeDelta = logTextOriginalSize;
  146 + }
  147 + }
  148 +
  149 + transformComponent.sizeDelta = size;
  150 +
  151 + SetText( logEntry, logEntryTimestamp, isExpanded );
  152 + logTypeImage.sprite = logEntry.logTypeSpriteRepresentation;
  153 + }
  154 +
  155 + // Show the collapsed count of the debug entry
  156 + public void ShowCount()
  157 + {
  158 + logCountText.text = logEntry.count.ToString();
  159 +
  160 + if( !logCountParent.activeSelf )
  161 + logCountParent.SetActive( true );
  162 + }
  163 +
  164 + // Hide the collapsed count of the debug entry
  165 + public void HideCount()
  166 + {
  167 + if( logCountParent.activeSelf )
  168 + logCountParent.SetActive( false );
  169 + }
  170 +
  171 + // Update the debug entry's displayed timestamp
  172 + public void UpdateTimestamp( DebugLogEntryTimestamp timestamp )
  173 + {
  174 + logEntryTimestamp = timestamp;
  175 +
  176 + if( isExpanded || listView.manager.alwaysDisplayTimestamps )
  177 + SetText( logEntry, timestamp, isExpanded );
  178 + }
  179 +
  180 + private void SetText( DebugLogEntry logEntry, DebugLogEntryTimestamp? logEntryTimestamp, bool isExpanded )
  181 + {
  182 + if( !logEntryTimestamp.HasValue || ( !isExpanded && !listView.manager.alwaysDisplayTimestamps ) )
  183 + logText.text = isExpanded ? logEntry.ToString() : logEntry.logString;
  184 + else
  185 + {
  186 + StringBuilder sb = listView.manager.sharedStringBuilder;
  187 + sb.Length = 0;
  188 +
  189 + if( isExpanded )
  190 + {
  191 + logEntryTimestamp.Value.AppendFullTimestamp( sb );
  192 + sb.Append( ": " ).Append( logEntry.ToString() );
  193 + }
  194 + else
  195 + {
  196 + logEntryTimestamp.Value.AppendTime( sb );
  197 + sb.Append( " " ).Append( logEntry.logString );
  198 + }
  199 +
  200 + logText.text = sb.ToString();
  201 + }
  202 + }
  203 +
  204 + // This log item is clicked, show the debug entry's stack trace
  205 + public void OnPointerClick( PointerEventData eventData )
  206 + {
  207 +#if UNITY_EDITOR
  208 + if( eventData.button == PointerEventData.InputButton.Right )
  209 + {
  210 + Match regex = Regex.Match( logEntry.stackTrace, @"\(at .*\.cs:[0-9]+\)$", RegexOptions.Multiline );
  211 + if( regex.Success )
  212 + {
  213 + string line = logEntry.stackTrace.Substring( regex.Index + 4, regex.Length - 5 );
  214 + int lineSeparator = line.IndexOf( ':' );
  215 + MonoScript script = AssetDatabase.LoadAssetAtPath<MonoScript>( line.Substring( 0, lineSeparator ) );
  216 + if( script != null )
  217 + AssetDatabase.OpenAsset( script, int.Parse( line.Substring( lineSeparator + 1 ) ) );
  218 + }
  219 + }
  220 + else
  221 + listView.OnLogItemClicked( this );
  222 +#else
  223 + listView.OnLogItemClicked( this );
  224 +#endif
  225 + }
  226 +
  227 + public void CopyLog()
  228 + {
  229 +#if UNITY_EDITOR || !UNITY_WEBGL
  230 + string log = GetCopyContent();
  231 + if( string.IsNullOrEmpty( log ) )
  232 + return;
  233 +
  234 +#if UNITY_EDITOR || UNITY_2018_1_OR_NEWER || ( !UNITY_ANDROID && !UNITY_IOS )
  235 + GUIUtility.systemCopyBuffer = log;
  236 +#elif UNITY_ANDROID
  237 + AJC.CallStatic( "CopyText", Context, log );
  238 +#elif UNITY_IOS
  239 + _DebugConsole_CopyText( log );
  240 +#endif
  241 +#endif
  242 + }
  243 +
  244 + internal string GetCopyContent()
  245 + {
  246 + if( !logEntryTimestamp.HasValue )
  247 + return logEntry.ToString();
  248 + else
  249 + {
  250 + StringBuilder sb = listView.manager.sharedStringBuilder;
  251 + sb.Length = 0;
  252 +
  253 + logEntryTimestamp.Value.AppendFullTimestamp( sb );
  254 + sb.Append( ": " ).Append( logEntry.ToString() );
  255 +
  256 + return sb.ToString();
  257 + }
  258 + }
  259 +
  260 + public float CalculateExpandedHeight( DebugLogEntry logEntry, DebugLogEntryTimestamp? logEntryTimestamp )
  261 + {
  262 + string text = logText.text;
  263 + HorizontalWrapMode wrapMode = logText.horizontalOverflow;
  264 +
  265 + SetText( logEntry, logEntryTimestamp, true );
  266 + logText.horizontalOverflow = HorizontalWrapMode.Wrap;
  267 +
  268 + float result = logText.preferredHeight + copyLogButtonHeight;
  269 +
  270 + logText.text = text;
  271 + logText.horizontalOverflow = wrapMode;
  272 +
  273 + return Mathf.Max( listView.ItemHeight, result );
  274 + }
  275 +
  276 + // Return a string containing complete information about the debug entry
  277 + public override string ToString()
  278 + {
  279 + return logEntry.ToString();
  280 + }
  281 + }
  282 +}
  1 +fileFormatVersion: 2
  2 +guid: d2ea291be9de70a4abfec595203c96c1
  3 +timeCreated: 1465919949
  4 +licenseType: Store
  5 +MonoImporter:
  6 + serializedVersion: 2
  7 + defaultReferences: []
  8 + executionOrder: 0
  9 + icon: {instanceID: 0}
  10 + userData:
  11 + assetBundleName:
  12 + assetBundleVariant:
  1 +#if !UNITY_EDITOR && UNITY_WEBGL
  2 +using System.Runtime.InteropServices;
  3 +using UnityEngine;
  4 +using UnityEngine.EventSystems;
  5 +
  6 +namespace IngameDebugConsole
  7 +{
  8 + public class DebugLogItemCopyWebGL : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
  9 + {
  10 + [DllImport( "__Internal" )]
  11 + private static extern void IngameDebugConsoleStartCopy( string textToCopy );
  12 + [DllImport( "__Internal" )]
  13 + private static extern void IngameDebugConsoleCancelCopy();
  14 +
  15 + private DebugLogItem logItem;
  16 +
  17 + public void Initialize( DebugLogItem logItem )
  18 + {
  19 + this.logItem = logItem;
  20 + }
  21 +
  22 + public void OnPointerDown( PointerEventData eventData )
  23 + {
  24 + string log = logItem.GetCopyContent();
  25 + if( !string.IsNullOrEmpty( log ) )
  26 + IngameDebugConsoleStartCopy( log );
  27 + }
  28 +
  29 + public void OnPointerUp( PointerEventData eventData )
  30 + {
  31 + if( eventData.dragging )
  32 + IngameDebugConsoleCancelCopy();
  33 + }
  34 + }
  35 +}
  36 +#endif
  1 +fileFormatVersion: 2
  2 +guid: 5a7d9d894141e704d8160fb4632121ac
  3 +MonoImporter:
  4 + externalObjects: {}
  5 + serializedVersion: 2
  6 + defaultReferences: []
  7 + executionOrder: 0
  8 + icon: {instanceID: 0}
  9 + userData:
  10 + assetBundleName:
  11 + assetBundleVariant: