范川铭

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 @@
</Reference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="IngameDebugConsole.Editor.csproj">
<Project>{9b47dfc7-464c-e716-7c49-c01c25245e7d}</Project>
<Name>IngameDebugConsole.Editor</Name>
</ProjectReference>
<ProjectReference Include="IngameDebugConsole.Runtime.csproj">
<Project>{f455341b-6302-350b-c7b4-f9a38305d0ae}</Project>
<Name>IngameDebugConsole.Runtime</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
... ...
... ... @@ -763,6 +763,14 @@
<Project>{0fb0da77-85a4-96d4-1dc2-8ddaab877745}</Project>
<Name>Assembly-CSharp-firstpass</Name>
</ProjectReference>
<ProjectReference Include="IngameDebugConsole.Editor.csproj">
<Project>{9b47dfc7-464c-e716-7c49-c01c25245e7d}</Project>
<Name>IngameDebugConsole.Editor</Name>
</ProjectReference>
<ProjectReference Include="IngameDebugConsole.Runtime.csproj">
<Project>{f455341b-6302-350b-c7b4-f9a38305d0ae}</Project>
<Name>IngameDebugConsole.Runtime</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
... ...
fileFormatVersion: 2
guid: 3c57523b63ddb094b835b6613da12763
folderAsset: yes
timeCreated: 1596819199
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:
... ...
fileFormatVersion: 2
guid: 3d7d7a61a5341904eb3c65af025b1d86
folderAsset: yes
timeCreated: 1510075633
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:
... ...
#if UNITY_EDITOR || UNITY_ANDROID
using System.Collections.Generic;
using UnityEngine;
// Credit: https://stackoverflow.com/a/41018028/2373034
namespace IngameDebugConsole
{
public class DebugLogLogcatListener : AndroidJavaProxy
{
private Queue<string> queuedLogs;
private AndroidJavaObject nativeObject;
public DebugLogLogcatListener() : base( "com.yasirkula.unity.DebugConsoleLogcatLogReceiver" )
{
queuedLogs = new Queue<string>( 16 );
}
~DebugLogLogcatListener()
{
Stop();
if( nativeObject != null )
nativeObject.Dispose();
}
public void Start( string arguments )
{
if( nativeObject == null )
nativeObject = new AndroidJavaObject( "com.yasirkula.unity.DebugConsoleLogcatLogger" );
nativeObject.Call( "Start", this, arguments );
}
public void Stop()
{
if( nativeObject != null )
nativeObject.Call( "Stop" );
}
[UnityEngine.Scripting.Preserve]
public void OnLogReceived( string log )
{
queuedLogs.Enqueue( log );
}
public string GetLog()
{
if( queuedLogs.Count > 0 )
return queuedLogs.Dequeue();
return null;
}
}
}
#endif
\ No newline at end of file
... ...
fileFormatVersion: 2
guid: dd3b7385882055d4a8c2b91deb6b2470
timeCreated: 1510076185
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
... ...
fileFormatVersion: 2
guid: bf909fab1c14af446b0a854de42289b2
timeCreated: 1510086220
licenseType: Store
PluginImporter:
serializedVersion: 2
iconMap: {}
executionOrder: {}
isPreloaded: 0
isOverridable: 0
platformData:
data:
first:
Android: Android
second:
enabled: 1
settings: {}
data:
first:
Any:
second:
enabled: 0
settings: {}
data:
first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
userData:
assetBundleName:
assetBundleVariant:
... ...
fileFormatVersion: 2
guid: 86f54622630720f4abe279acdbb8886f
folderAsset: yes
timeCreated: 1561217660
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:
... ...
using UnityEditor;
using UnityEngine;
namespace IngameDebugConsole
{
[CustomEditor( typeof( DebugLogManager ) )]
public class DebugLogManagerEditor : Editor
{
private SerializedProperty singleton;
private SerializedProperty minimumHeight;
private SerializedProperty enableHorizontalResizing;
private SerializedProperty resizeFromRight;
private SerializedProperty minimumWidth;
private SerializedProperty logWindowOpacity;
private SerializedProperty popupOpacity;
private SerializedProperty popupVisibility;
private SerializedProperty popupVisibilityLogFilter;
private SerializedProperty startMinimized;
private SerializedProperty toggleWithKey;
private SerializedProperty toggleKey;
private SerializedProperty enableSearchbar;
private SerializedProperty topSearchbarMinWidth;
private SerializedProperty receiveLogsWhileInactive;
private SerializedProperty receiveInfoLogs;
private SerializedProperty receiveWarningLogs;
private SerializedProperty receiveErrorLogs;
private SerializedProperty receiveExceptionLogs;
private SerializedProperty captureLogTimestamps;
private SerializedProperty alwaysDisplayTimestamps;
private SerializedProperty maxLogCount;
private SerializedProperty logsToRemoveAfterMaxLogCount;
private SerializedProperty queuedLogLimit;
private SerializedProperty clearCommandAfterExecution;
private SerializedProperty commandHistorySize;
private SerializedProperty showCommandSuggestions;
private SerializedProperty receiveLogcatLogsInAndroid;
private SerializedProperty logcatArguments;
private SerializedProperty avoidScreenCutout;
private SerializedProperty popupAvoidsScreenCutout;
private SerializedProperty autoFocusOnCommandInputField;
#if UNITY_2017_3_OR_NEWER
private readonly GUIContent popupVisibilityLogFilterLabel = new GUIContent( "Log Filter", "Determines which log types will show the popup on screen" );
#endif
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" );
private readonly GUIContent receiveInfoLogsLabel = new GUIContent( "Info" );
private readonly GUIContent receiveWarningLogsLabel = new GUIContent( "Warning" );
private readonly GUIContent receiveErrorLogsLabel = new GUIContent( "Error" );
private readonly GUIContent receiveExceptionLogsLabel = new GUIContent( "Exception" );
private void OnEnable()
{
singleton = serializedObject.FindProperty( "singleton" );
minimumHeight = serializedObject.FindProperty( "minimumHeight" );
enableHorizontalResizing = serializedObject.FindProperty( "enableHorizontalResizing" );
resizeFromRight = serializedObject.FindProperty( "resizeFromRight" );
minimumWidth = serializedObject.FindProperty( "minimumWidth" );
logWindowOpacity = serializedObject.FindProperty( "logWindowOpacity" );
popupOpacity = serializedObject.FindProperty( "popupOpacity" );
popupVisibility = serializedObject.FindProperty( "popupVisibility" );
popupVisibilityLogFilter = serializedObject.FindProperty( "popupVisibilityLogFilter" );
startMinimized = serializedObject.FindProperty( "startMinimized" );
toggleWithKey = serializedObject.FindProperty( "toggleWithKey" );
#if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER
toggleKey = serializedObject.FindProperty( "toggleBinding" );
#else
toggleKey = serializedObject.FindProperty( "toggleKey" );
#endif
enableSearchbar = serializedObject.FindProperty( "enableSearchbar" );
topSearchbarMinWidth = serializedObject.FindProperty( "topSearchbarMinWidth" );
receiveLogsWhileInactive = serializedObject.FindProperty( "receiveLogsWhileInactive" );
receiveInfoLogs = serializedObject.FindProperty( "receiveInfoLogs" );
receiveWarningLogs = serializedObject.FindProperty( "receiveWarningLogs" );
receiveErrorLogs = serializedObject.FindProperty( "receiveErrorLogs" );
receiveExceptionLogs = serializedObject.FindProperty( "receiveExceptionLogs" );
captureLogTimestamps = serializedObject.FindProperty( "captureLogTimestamps" );
alwaysDisplayTimestamps = serializedObject.FindProperty( "alwaysDisplayTimestamps" );
maxLogCount = serializedObject.FindProperty( "maxLogCount" );
logsToRemoveAfterMaxLogCount = serializedObject.FindProperty( "logsToRemoveAfterMaxLogCount" );
queuedLogLimit = serializedObject.FindProperty( "queuedLogLimit" );
clearCommandAfterExecution = serializedObject.FindProperty( "clearCommandAfterExecution" );
commandHistorySize = serializedObject.FindProperty( "commandHistorySize" );
showCommandSuggestions = serializedObject.FindProperty( "showCommandSuggestions" );
receiveLogcatLogsInAndroid = serializedObject.FindProperty( "receiveLogcatLogsInAndroid" );
logcatArguments = serializedObject.FindProperty( "logcatArguments" );
avoidScreenCutout = serializedObject.FindProperty( "avoidScreenCutout" );
popupAvoidsScreenCutout = serializedObject.FindProperty( "popupAvoidsScreenCutout" );
autoFocusOnCommandInputField = serializedObject.FindProperty( "autoFocusOnCommandInputField" );
}
public override void OnInspectorGUI()
{
serializedObject.Update();
EditorGUILayout.PropertyField( singleton );
EditorGUILayout.Space();
EditorGUILayout.PropertyField( minimumHeight );
EditorGUILayout.PropertyField( enableHorizontalResizing );
if( enableHorizontalResizing.boolValue )
{
DrawSubProperty( resizeFromRight );
DrawSubProperty( minimumWidth );
}
EditorGUILayout.PropertyField( avoidScreenCutout );
DrawSubProperty( popupAvoidsScreenCutout );
EditorGUILayout.Space();
EditorGUILayout.PropertyField( startMinimized );
EditorGUILayout.PropertyField( logWindowOpacity );
EditorGUILayout.PropertyField( popupOpacity );
EditorGUILayout.PropertyField( popupVisibility );
if( popupVisibility.intValue == (int) PopupVisibility.WhenLogReceived )
{
EditorGUI.indentLevel++;
#if UNITY_2017_3_OR_NEWER
Rect rect = EditorGUILayout.GetControlRect();
EditorGUI.BeginProperty( rect, GUIContent.none, popupVisibilityLogFilter );
popupVisibilityLogFilter.intValue = (int) (DebugLogFilter) EditorGUI.EnumFlagsField( rect, popupVisibilityLogFilterLabel, (DebugLogFilter) popupVisibilityLogFilter.intValue );
#else
EditorGUI.BeginProperty( new Rect(), GUIContent.none, popupVisibilityLogFilter );
EditorGUI.BeginChangeCheck();
bool infoLog = EditorGUILayout.Toggle( "Info", ( (DebugLogFilter) popupVisibilityLogFilter.intValue & DebugLogFilter.Info ) == DebugLogFilter.Info );
bool warningLog = EditorGUILayout.Toggle( "Warning", ( (DebugLogFilter) popupVisibilityLogFilter.intValue & DebugLogFilter.Warning ) == DebugLogFilter.Warning );
bool errorLog = EditorGUILayout.Toggle( "Error", ( (DebugLogFilter) popupVisibilityLogFilter.intValue & DebugLogFilter.Error ) == DebugLogFilter.Error );
if( EditorGUI.EndChangeCheck() )
popupVisibilityLogFilter.intValue = ( infoLog ? (int) DebugLogFilter.Info : 0 ) | ( warningLog ? (int) DebugLogFilter.Warning : 0 ) | ( errorLog ? (int) DebugLogFilter.Error : 0 );
#endif
EditorGUI.EndProperty();
EditorGUI.indentLevel--;
}
EditorGUILayout.PropertyField( toggleWithKey );
if( toggleWithKey.boolValue )
DrawSubProperty( toggleKey );
EditorGUILayout.Space();
EditorGUILayout.PropertyField( enableSearchbar );
if( enableSearchbar.boolValue )
DrawSubProperty( topSearchbarMinWidth );
EditorGUILayout.Space();
EditorGUILayout.PropertyField( receiveLogsWhileInactive );
EditorGUILayout.PrefixLabel( receivedLogTypesLabel );
EditorGUI.indentLevel++;
EditorGUILayout.PropertyField( receiveInfoLogs, receiveInfoLogsLabel );
EditorGUILayout.PropertyField( receiveWarningLogs, receiveWarningLogsLabel );
EditorGUILayout.PropertyField( receiveErrorLogs, receiveErrorLogsLabel );
EditorGUILayout.PropertyField( receiveExceptionLogs, receiveExceptionLogsLabel );
EditorGUI.indentLevel--;
EditorGUILayout.PropertyField( receiveLogcatLogsInAndroid );
if( receiveLogcatLogsInAndroid.boolValue )
DrawSubProperty( logcatArguments );
EditorGUILayout.PropertyField( captureLogTimestamps );
if( captureLogTimestamps.boolValue )
DrawSubProperty( alwaysDisplayTimestamps );
EditorGUILayout.PropertyField( maxLogCount );
DrawSubProperty( logsToRemoveAfterMaxLogCount );
EditorGUILayout.PropertyField( queuedLogLimit );
EditorGUILayout.Space();
EditorGUILayout.PropertyField( clearCommandAfterExecution );
EditorGUILayout.PropertyField( commandHistorySize );
EditorGUILayout.PropertyField( showCommandSuggestions );
EditorGUILayout.PropertyField( autoFocusOnCommandInputField );
EditorGUILayout.Space();
DrawPropertiesExcluding( serializedObject, "m_Script" );
serializedObject.ApplyModifiedProperties();
}
private void DrawSubProperty( SerializedProperty property )
{
EditorGUI.indentLevel++;
EditorGUILayout.PropertyField( property );
EditorGUI.indentLevel--;
}
}
}
\ No newline at end of file
... ...
fileFormatVersion: 2
guid: 4c23e5c521cb0c54b9a638b2a653d1d3
timeCreated: 1561217671
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
... ...
{
"name": "IngameDebugConsole.Editor",
"references": [
"IngameDebugConsole.Runtime"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}
\ No newline at end of file
... ...
fileFormatVersion: 2
guid: 466e67dabd1db22468246c39eddb6c3f
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
... ...
{
"name": "IngameDebugConsole.Runtime",
"references": [
"Unity.InputSystem"
]
}
\ No newline at end of file
... ...
fileFormatVersion: 2
guid: 3de88c88fbbb8f944b9210d496af9762
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
... ...
This diff could not be displayed because it is too large.
fileFormatVersion: 2
guid: 67117722a812a2e46ab8cb8eafbf5f5e
timeCreated: 1466014755
licenseType: Store
NativeFormatImporter:
userData:
assetBundleName:
assetBundleVariant:
... ...
fileFormatVersion: 2
guid: 7dbc36665bc0d684db9a4447e27a7a4b
folderAsset: yes
timeCreated: 1520417401
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:
... ...
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1001 &100100000
Prefab:
m_ObjectHideFlags: 1
serializedVersion: 2
m_Modification:
m_TransformParent: {fileID: 0}
m_Modifications: []
m_RemovedComponents: []
m_ParentPrefab: {fileID: 0}
m_RootGameObject: {fileID: 1386426139070838}
m_IsPrefabParent: 1
--- !u!1 &1386426139070838
GameObject:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
serializedVersion: 5
m_Component:
- component: {fileID: 224955737853170496}
- component: {fileID: 222541766812100524}
- component: {fileID: 114169395487023046}
m_Layer: 5
m_Name: CommandSuggestion
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &114169395487023046
MonoBehaviour:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 1386426139070838}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 708705254, guid: f70555f144d8491a825f0804e09c671c, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 0.83823526, g: 0.84439874, b: 0.84439874, a: 1}
m_RaycastTarget: 0
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
m_FontData:
m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
m_FontSize: 16
m_FontStyle: 0
m_BestFit: 0
m_MinSize: 1
m_MaxSize: 40
m_Alignment: 3
m_AlignByGeometry: 0
m_RichText: 1
m_HorizontalOverflow: 0
m_VerticalOverflow: 0
m_LineSpacing: 1
m_Text: help
--- !u!222 &222541766812100524
CanvasRenderer:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 1386426139070838}
--- !u!224 &224955737853170496
RectTransform:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 1386426139070838}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0.5, y: 0.5}
... ...
fileFormatVersion: 2
guid: 5e66896448428cf46a1854dbdc014914
timeCreated: 1601390136
licenseType: Store
NativeFormatImporter:
mainObjectFileID: 100100000
userData:
assetBundleName:
assetBundleVariant:
... ...
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &104862
GameObject:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
serializedVersion: 5
m_Component:
- component: {fileID: 22461494}
- component: {fileID: 22233942}
- component: {fileID: 11411806}
m_Layer: 5
m_Name: LogCount
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 0
--- !u!1 &151462
GameObject:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
serializedVersion: 5
m_Component:
- component: {fileID: 22420350}
- component: {fileID: 22200920}
- component: {fileID: 11432936}
m_Layer: 5
m_Name: LogCountText
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!1 &152362
GameObject:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
serializedVersion: 5
m_Component:
- component: {fileID: 22427300}
- component: {fileID: 22262284}
- component: {fileID: 11404142}
m_Layer: 5
m_Name: LogType
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!1 &166880
GameObject:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
serializedVersion: 5
m_Component:
- component: {fileID: 22479264}
- component: {fileID: 22288988}
- component: {fileID: 11459012}
- component: {fileID: 11408050}
- component: {fileID: 11456372}
- component: {fileID: 225819852034701160}
m_Layer: 5
m_Name: DebugLogItem
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &11404142
MonoBehaviour:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 152362}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: -765806418, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 0
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
m_Sprite: {fileID: 21300000, guid: 33b115bf5efdfa04d8e2e0b70a6643cd, type: 3}
m_Type: 0
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
--- !u!114 &11408050
MonoBehaviour:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 166880}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d2ea291be9de70a4abfec595203c96c1, type: 3}
m_Name:
m_EditorClassIdentifier:
transformComponent: {fileID: 22479264}
imageComponent: {fileID: 11459012}
canvasGroupComponent: {fileID: 225819852034701160}
logText: {fileID: 114694493629914950}
logTypeImage: {fileID: 11404142}
logCountParent: {fileID: 104862}
logCountText: {fileID: 11432936}
copyLogButton: {fileID: 224006190298411330}
--- !u!114 &11411806
MonoBehaviour:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 104862}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: -765806418, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 0.42647058, g: 0.42647058, b: 0.42647058, a: 1}
m_RaycastTarget: 0
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
m_Sprite: {fileID: 21300000, guid: b3f0d976f6d6802479d6465d11b3aa68, type: 3}
m_Type: 1
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
--- !u!114 &11432936
MonoBehaviour:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 151462}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 708705254, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 0.83823526, g: 0.84439874, b: 0.84439874, a: 1}
m_RaycastTarget: 0
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
m_FontData:
m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
m_FontSize: 16
m_FontStyle: 0
m_BestFit: 1
m_MinSize: 1
m_MaxSize: 16
m_Alignment: 4
m_AlignByGeometry: 0
m_RichText: 1
m_HorizontalOverflow: 0
m_VerticalOverflow: 0
m_LineSpacing: 1
m_Text: 1
--- !u!114 &11456372
MonoBehaviour:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 166880}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 1392445389, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Navigation:
m_Mode: 3
m_SelectOnUp: {fileID: 0}
m_SelectOnDown: {fileID: 0}
m_SelectOnLeft: {fileID: 0}
m_SelectOnRight: {fileID: 0}
m_Transition: 1
m_Colors:
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
m_ColorMultiplier: 1
m_FadeDuration: 0.1
m_SpriteState:
m_HighlightedSprite: {fileID: 0}
m_PressedSprite: {fileID: 0}
m_DisabledSprite: {fileID: 0}
m_AnimationTriggers:
m_NormalTrigger: Normal
m_HighlightedTrigger: Highlighted
m_PressedTrigger: Pressed
m_DisabledTrigger: Disabled
m_Interactable: 1
m_TargetGraphic: {fileID: 11459012}
m_OnClick:
m_PersistentCalls:
m_Calls: []
m_TypeName: UnityEngine.UI.Button+ButtonClickedEvent, UnityEngine.UI, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=null
--- !u!114 &11459012
MonoBehaviour:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 166880}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: -765806418, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 0.23529412, g: 0.23529412, b: 0.23529412, a: 0.697}
m_RaycastTarget: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
m_Sprite: {fileID: 21300000, guid: 98e8e1cf8dc7dbf469617c2e40c8a944, type: 3}
m_Type: 1
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
--- !u!222 &22200920
CanvasRenderer:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 151462}
--- !u!222 &22233942
CanvasRenderer:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 104862}
--- !u!222 &22262284
CanvasRenderer:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 152362}
--- !u!222 &22288988
CanvasRenderer:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 166880}
--- !u!224 &22420350
RectTransform:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 151462}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 22461494}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: -2, y: 0}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!224 &22427300
RectTransform:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 152362}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 22479264}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0.5}
m_AnchorMax: {x: 0, y: 0.5}
m_AnchoredPosition: {x: 18, y: 0}
m_SizeDelta: {x: 25, y: 25}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!224 &22461494
RectTransform:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 104862}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children:
- {fileID: 22420350}
m_Father: {fileID: 22479264}
m_RootOrder: 2
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 1, y: 0.5}
m_AnchorMax: {x: 1, y: 0.5}
m_AnchoredPosition: {x: -28, y: 0}
m_SizeDelta: {x: 38, y: 28}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!224 &22479264
RectTransform:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 166880}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children:
- {fileID: 22427300}
- {fileID: 224737693311518052}
- {fileID: 22461494}
- {fileID: 224006190298411330}
m_Father: {fileID: 0}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 35}
m_Pivot: {x: 0, y: 1}
--- !u!1001 &100100000
Prefab:
m_ObjectHideFlags: 1
serializedVersion: 2
m_Modification:
m_TransformParent: {fileID: 0}
m_Modifications: []
m_RemovedComponents: []
m_ParentPrefab: {fileID: 0}
m_RootGameObject: {fileID: 166880}
m_IsPrefabParent: 1
--- !u!1 &1396836967994216
GameObject:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
serializedVersion: 5
m_Component:
- component: {fileID: 224006190298411330}
- component: {fileID: 222870443111501910}
- component: {fileID: 114119781176956926}
- component: {fileID: 114694923173451186}
m_Layer: 5
m_Name: CopyLogButton
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 0
--- !u!1 &1503640463151286
GameObject:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
serializedVersion: 5
m_Component:
- component: {fileID: 224887990600088790}
- component: {fileID: 222313182602304162}
- component: {fileID: 114549765989288124}
m_Layer: 5
m_Name: Text
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!1 &1785910143472904
GameObject:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
serializedVersion: 5
m_Component:
- component: {fileID: 224737693311518052}
- component: {fileID: 222175805939703770}
- component: {fileID: 114694493629914950}
m_Layer: 5
m_Name: LogText
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &114119781176956926
MonoBehaviour:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 1396836967994216}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: -765806418, guid: f70555f144d8491a825f0804e09c671c, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 0.42647058, g: 0.42647058, b: 0.42647058, a: 1}
m_RaycastTarget: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
m_Sprite: {fileID: 21300000, guid: 066d3840badf4d24dba1d42b4c59b888, type: 3}
m_Type: 1
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
--- !u!114 &114549765989288124
MonoBehaviour:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 1503640463151286}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 708705254, guid: f70555f144d8491a825f0804e09c671c, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 0.83823526, g: 0.84439874, b: 0.84439874, a: 1}
m_RaycastTarget: 0
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
m_FontData:
m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
m_FontSize: 16
m_FontStyle: 0
m_BestFit: 0
m_MinSize: 1
m_MaxSize: 40
m_Alignment: 4
m_AlignByGeometry: 0
m_RichText: 1
m_HorizontalOverflow: 0
m_VerticalOverflow: 0
m_LineSpacing: 1
m_Text: Copy
--- !u!114 &114694493629914950
MonoBehaviour:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 1785910143472904}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 708705254, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 0.83823526, g: 0.84439874, b: 0.84439874, a: 1}
m_RaycastTarget: 0
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
m_FontData:
m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
m_FontSize: 15
m_FontStyle: 0
m_BestFit: 0
m_MinSize: 1
m_MaxSize: 40
m_Alignment: 3
m_AlignByGeometry: 0
m_RichText: 1
m_HorizontalOverflow: 1
m_VerticalOverflow: 0
m_LineSpacing: 1
m_Text: Debug.Log summary
--- !u!114 &114694923173451186
MonoBehaviour:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 1396836967994216}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 1392445389, guid: f70555f144d8491a825f0804e09c671c, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Navigation:
m_Mode: 3
m_SelectOnUp: {fileID: 0}
m_SelectOnDown: {fileID: 0}
m_SelectOnLeft: {fileID: 0}
m_SelectOnRight: {fileID: 0}
m_Transition: 1
m_Colors:
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
m_ColorMultiplier: 1
m_FadeDuration: 0.1
m_SpriteState:
m_HighlightedSprite: {fileID: 0}
m_PressedSprite: {fileID: 0}
m_DisabledSprite: {fileID: 0}
m_AnimationTriggers:
m_NormalTrigger: Normal
m_HighlightedTrigger: Highlighted
m_PressedTrigger: Pressed
m_DisabledTrigger: Disabled
m_Interactable: 1
m_TargetGraphic: {fileID: 114119781176956926}
m_OnClick:
m_PersistentCalls:
m_Calls:
- m_Target: {fileID: 11408050}
m_MethodName: CopyLog
m_Mode: 1
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
m_IntArgument: 0
m_FloatArgument: 0
m_StringArgument:
m_BoolArgument: 0
m_CallState: 2
m_TypeName: UnityEngine.UI.Button+ButtonClickedEvent, UnityEngine.UI, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=null
--- !u!222 &222175805939703770
CanvasRenderer:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 1785910143472904}
--- !u!222 &222313182602304162
CanvasRenderer:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 1503640463151286}
--- !u!222 &222870443111501910
CanvasRenderer:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 1396836967994216}
--- !u!224 &224006190298411330
RectTransform:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 1396836967994216}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children:
- {fileID: 224887990600088790}
m_Father: {fileID: 22479264}
m_RootOrder: 3
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 0}
m_AnchoredPosition: {x: 0, y: 2}
m_SizeDelta: {x: -70, y: 36}
m_Pivot: {x: 0.5, y: 0}
--- !u!224 &224737693311518052
RectTransform:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 1785910143472904}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 22479264}
m_RootOrder: 1
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 15, y: 0}
m_SizeDelta: {x: -40, y: -2}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!224 &224887990600088790
RectTransform:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 1503640463151286}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 224006190298411330}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!225 &225819852034701160
CanvasGroup:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 166880}
m_Enabled: 1
m_Alpha: 1
m_Interactable: 1
m_BlocksRaycasts: 1
m_IgnoreParentGroups: 0
... ...
fileFormatVersion: 2
guid: 391be5df5ef62f345bb76a1051c04da7
timeCreated: 1465919887
licenseType: Store
NativeFormatImporter:
userData:
assetBundleName:
assetBundleVariant:
... ...
= In-game Debug Console (v1.6.8) =
Documentation: https://github.com/yasirkula/UnityIngameDebugConsole
FAQ: https://github.com/yasirkula/UnityIngameDebugConsole#faq
E-mail: yasirkula@gmail.com
You can simply place the IngameDebugConsole prefab to your scene. Hovering the cursor over its properties in the Inspector will reveal explanatory tooltips.
\ No newline at end of file
... ...
fileFormatVersion: 2
guid: edf2ac73f7bc3064c96d53009106dc53
timeCreated: 1563307881
licenseType: Store
TextScriptImporter:
userData:
assetBundleName:
assetBundleVariant:
... ...
fileFormatVersion: 2
guid: 860c08388401a6d4e858fe4910ea9337
folderAsset: yes
timeCreated: 1465930645
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:
... ...
using System;
using UnityEngine;
namespace IngameDebugConsole
{
public class CircularBuffer<T>
{
private readonly T[] array;
private int startIndex;
public int Count { get; private set; }
public T this[int index] { get { return array[( startIndex + index ) % array.Length]; } }
public CircularBuffer( int capacity )
{
array = new T[capacity];
}
// Old elements are overwritten when capacity is reached
public void Add( T value )
{
if( Count < array.Length )
array[Count++] = value;
else
{
array[startIndex] = value;
if( ++startIndex >= array.Length )
startIndex = 0;
}
}
}
public class DynamicCircularBuffer<T>
{
private T[] array;
private int startIndex;
public int Count { get; private set; }
public int Capacity { get { return array.Length; } }
public T this[int index]
{
get { return array[( startIndex + index ) % array.Length]; }
set { array[( startIndex + index ) % array.Length] = value; }
}
public DynamicCircularBuffer( int initialCapacity = 2 )
{
array = new T[initialCapacity];
}
private void SetCapacity( int capacity )
{
T[] newArray = new T[capacity];
if( Count > 0 )
{
int elementsBeforeWrap = Mathf.Min( Count, array.Length - startIndex );
Array.Copy( array, startIndex, newArray, 0, elementsBeforeWrap );
if( elementsBeforeWrap < Count )
Array.Copy( array, 0, newArray, elementsBeforeWrap, Count - elementsBeforeWrap );
}
array = newArray;
startIndex = 0;
}
/// <summary>Inserts the value to the beginning of the collection.</summary>
public void AddFirst( T value )
{
if( array.Length == Count )
SetCapacity( Mathf.Max( array.Length * 2, 4 ) );
startIndex = ( startIndex > 0 ) ? ( startIndex - 1 ) : ( array.Length - 1 );
array[startIndex] = value;
Count++;
}
/// <summary>Adds the value to the end of the collection.</summary>
public void Add( T value )
{
if( array.Length == Count )
SetCapacity( Mathf.Max( array.Length * 2, 4 ) );
this[Count++] = value;
}
public void AddRange( DynamicCircularBuffer<T> other )
{
if( other.Count == 0 )
return;
if( array.Length < Count + other.Count )
SetCapacity( Mathf.Max( array.Length * 2, Count + other.Count ) );
int insertStartIndex = ( startIndex + Count ) % array.Length;
int elementsBeforeWrap = Mathf.Min( other.Count, array.Length - insertStartIndex );
int otherElementsBeforeWrap = Mathf.Min( other.Count, other.array.Length - other.startIndex );
Array.Copy( other.array, other.startIndex, array, insertStartIndex, Mathf.Min( elementsBeforeWrap, otherElementsBeforeWrap ) );
if( elementsBeforeWrap < otherElementsBeforeWrap ) // This array wrapped before the other array
Array.Copy( other.array, other.startIndex + elementsBeforeWrap, array, 0, otherElementsBeforeWrap - elementsBeforeWrap );
else if( elementsBeforeWrap > otherElementsBeforeWrap ) // The other array wrapped before this array
Array.Copy( other.array, 0, array, insertStartIndex + otherElementsBeforeWrap, elementsBeforeWrap - otherElementsBeforeWrap );
int copiedElements = Mathf.Max( elementsBeforeWrap, otherElementsBeforeWrap );
if( copiedElements < other.Count ) // Both arrays wrapped and there's still some elements left to copy
Array.Copy( other.array, copiedElements - otherElementsBeforeWrap, array, copiedElements - elementsBeforeWrap, other.Count - copiedElements );
Count += other.Count;
}
public T RemoveFirst()
{
T element = array[startIndex];
array[startIndex] = default( T );
if( ++startIndex == array.Length )
startIndex = 0;
Count--;
return element;
}
public T RemoveLast()
{
int index = ( startIndex + Count - 1 ) % array.Length;
T element = array[index];
array[index] = default( T );
Count--;
return element;
}
public int RemoveAll( Predicate<T> shouldRemoveElement )
{
return RemoveAll<T>( shouldRemoveElement, null, null );
}
public int RemoveAll<Y>( Predicate<T> shouldRemoveElement, Action<T, int> onElementIndexChanged, DynamicCircularBuffer<Y> synchronizedBuffer )
{
Y[] synchronizedArray = ( synchronizedBuffer != null ) ? synchronizedBuffer.array : null;
int elementsBeforeWrap = Mathf.Min( Count, array.Length - startIndex );
int removedElements = 0;
int i = startIndex, newIndex = startIndex, endIndex = startIndex + elementsBeforeWrap;
for( ; i < endIndex; i++ )
{
if( shouldRemoveElement( array[i] ) )
removedElements++;
else
{
if( removedElements > 0 )
{
T element = array[i];
array[newIndex] = element;
if( synchronizedArray != null )
synchronizedArray[newIndex] = synchronizedArray[i];
if( onElementIndexChanged != null )
onElementIndexChanged( element, newIndex - startIndex );
}
newIndex++;
}
}
i = 0;
endIndex = Count - elementsBeforeWrap;
if( newIndex < array.Length )
{
for( ; i < endIndex; i++ )
{
if( shouldRemoveElement( array[i] ) )
removedElements++;
else
{
T element = array[i];
array[newIndex] = element;
if( synchronizedArray != null )
synchronizedArray[newIndex] = synchronizedArray[i];
if( onElementIndexChanged != null )
onElementIndexChanged( element, newIndex - startIndex );
if( ++newIndex == array.Length )
{
i++;
break;
}
}
}
}
if( newIndex == array.Length )
{
newIndex = 0;
for( ; i < endIndex; i++ )
{
if( shouldRemoveElement( array[i] ) )
removedElements++;
else
{
if( removedElements > 0 )
{
T element = array[i];
array[newIndex] = element;
if( synchronizedArray != null )
synchronizedArray[newIndex] = synchronizedArray[i];
if( onElementIndexChanged != null )
onElementIndexChanged( element, newIndex + elementsBeforeWrap );
}
newIndex++;
}
}
}
TrimEnd( removedElements );
if( synchronizedBuffer != null )
synchronizedBuffer.TrimEnd( removedElements );
return removedElements;
}
public void TrimStart( int trimCount, Action<T> perElementCallback = null )
{
TrimInternal( trimCount, startIndex, perElementCallback );
startIndex = ( startIndex + trimCount ) % array.Length;
}
public void TrimEnd( int trimCount, Action<T> perElementCallback = null )
{
TrimInternal( trimCount, ( startIndex + Count - trimCount ) % array.Length, perElementCallback );
}
private void TrimInternal( int trimCount, int startIndex, Action<T> perElementCallback )
{
int elementsBeforeWrap = Mathf.Min( trimCount, array.Length - startIndex );
if( perElementCallback == null )
{
Array.Clear( array, startIndex, elementsBeforeWrap );
if( elementsBeforeWrap < trimCount )
Array.Clear( array, 0, trimCount - elementsBeforeWrap );
}
else
{
for( int i = startIndex, endIndex = startIndex + elementsBeforeWrap; i < endIndex; i++ )
{
perElementCallback( array[i] );
array[i] = default( T );
}
for( int i = 0, endIndex = trimCount - elementsBeforeWrap; i < endIndex; i++ )
{
perElementCallback( array[i] );
array[i] = default( T );
}
}
Count -= trimCount;
}
public void Clear()
{
int elementsBeforeWrap = Mathf.Min( Count, array.Length - startIndex );
Array.Clear( array, startIndex, elementsBeforeWrap );
if( elementsBeforeWrap < Count )
Array.Clear( array, 0, Count - elementsBeforeWrap );
startIndex = 0;
Count = 0;
}
public int IndexOf( T value )
{
int elementsBeforeWrap = Mathf.Min( Count, array.Length - startIndex );
int index = Array.IndexOf( array, value, startIndex, elementsBeforeWrap );
if( index >= 0 )
return index - startIndex;
if( elementsBeforeWrap < Count )
{
index = Array.IndexOf( array, value, 0, Count - elementsBeforeWrap );
if( index >= 0 )
return index + elementsBeforeWrap;
}
return -1;
}
public void ForEach( Action<T> action )
{
int elementsBeforeWrap = Mathf.Min( Count, array.Length - startIndex );
for( int i = startIndex, endIndex = startIndex + elementsBeforeWrap; i < endIndex; i++ )
action( array[i] );
for( int i = 0, endIndex = Count - elementsBeforeWrap; i < endIndex; i++ )
action( array[i] );
}
}
}
\ No newline at end of file
... ...
fileFormatVersion: 2
guid: 6136cb3c00eac0149901b8e7f2fecef8
timeCreated: 1550943949
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
... ...
fileFormatVersion: 2
guid: bb9b6e1ab379cec46bfae8f8abcc1f45
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
... ...
#if IDG_ENABLE_HELPER_COMMANDS
using UnityEngine;
namespace IngameDebugConsole.Commands
{
public class PlayerPrefsCommands
{
[ConsoleMethod( "prefs.int", "Returns the value of an Integer PlayerPrefs field" ), UnityEngine.Scripting.Preserve]
public static string PlayerPrefsGetInt( string key )
{
if( !PlayerPrefs.HasKey( key ) ) return "Key Not Found";
return PlayerPrefs.GetInt( key ).ToString();
}
[ConsoleMethod( "prefs.int", "Sets the value of an Integer PlayerPrefs field" ), UnityEngine.Scripting.Preserve]
public static void PlayerPrefsSetInt( string key, int value )
{
PlayerPrefs.SetInt( key, value );
}
[ConsoleMethod( "prefs.float", "Returns the value of a Float PlayerPrefs field" ), UnityEngine.Scripting.Preserve]
public static string PlayerPrefsGetFloat( string key )
{
if( !PlayerPrefs.HasKey( key ) ) return "Key Not Found";
return PlayerPrefs.GetFloat( key ).ToString();
}
[ConsoleMethod( "prefs.float", "Sets the value of a Float PlayerPrefs field" ), UnityEngine.Scripting.Preserve]
public static void PlayerPrefsSetFloat( string key, float value )
{
PlayerPrefs.SetFloat( key, value );
}
[ConsoleMethod( "prefs.string", "Returns the value of a String PlayerPrefs field" ), UnityEngine.Scripting.Preserve]
public static string PlayerPrefsGetString( string key )
{
if( !PlayerPrefs.HasKey( key ) ) return "Key Not Found";
return PlayerPrefs.GetString( key );
}
[ConsoleMethod( "prefs.string", "Sets the value of a String PlayerPrefs field" ), UnityEngine.Scripting.Preserve]
public static void PlayerPrefsSetString( string key, string value )
{
PlayerPrefs.SetString( key, value );
}
[ConsoleMethod( "prefs.delete", "Deletes a PlayerPrefs field" ), UnityEngine.Scripting.Preserve]
public static void PlayerPrefsDelete( string key )
{
PlayerPrefs.DeleteKey( key );
}
[ConsoleMethod( "prefs.clear", "Deletes all PlayerPrefs fields" ), UnityEngine.Scripting.Preserve]
public static void PlayerPrefsClear()
{
PlayerPrefs.DeleteAll();
}
}
}
#endif
\ No newline at end of file
... ...
fileFormatVersion: 2
guid: 33fb3ee25c8764f4c905fa3ac7c4eb89
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
... ...
#if IDG_ENABLE_HELPER_COMMANDS
using UnityEngine;
using UnityEngine.SceneManagement;
namespace IngameDebugConsole.Commands
{
public class SceneCommands
{
[ConsoleMethod( "scene.load", "Loads a scene" ), UnityEngine.Scripting.Preserve]
public static void LoadScene( string sceneName )
{
LoadSceneInternal( sceneName, false, LoadSceneMode.Single );
}
[ConsoleMethod( "scene.load", "Loads a scene" ), UnityEngine.Scripting.Preserve]
public static void LoadScene( string sceneName, LoadSceneMode mode )
{
LoadSceneInternal( sceneName, false, mode );
}
[ConsoleMethod( "scene.loadasync", "Loads a scene asynchronously" ), UnityEngine.Scripting.Preserve]
public static void LoadSceneAsync( string sceneName )
{
LoadSceneInternal( sceneName, true, LoadSceneMode.Single );
}
[ConsoleMethod( "scene.loadasync", "Loads a scene asynchronously" ), UnityEngine.Scripting.Preserve]
public static void LoadSceneAsync( string sceneName, LoadSceneMode mode )
{
LoadSceneInternal( sceneName, true, mode );
}
private static void LoadSceneInternal( string sceneName, bool isAsync, LoadSceneMode mode )
{
if( SceneManager.GetSceneByName( sceneName ).IsValid() )
{
Debug.Log( "Scene " + sceneName + " is already loaded" );
return;
}
if( isAsync )
SceneManager.LoadSceneAsync( sceneName, mode );
else
SceneManager.LoadScene( sceneName, mode );
}
[ConsoleMethod( "scene.unload", "Unloads a scene" ), UnityEngine.Scripting.Preserve]
public static void UnloadScene( string sceneName )
{
SceneManager.UnloadSceneAsync( sceneName );
}
[ConsoleMethod( "scene.restart", "Restarts the active scene" ), UnityEngine.Scripting.Preserve]
public static void RestartScene()
{
SceneManager.LoadScene( SceneManager.GetActiveScene().name, LoadSceneMode.Single );
}
}
}
#endif
\ No newline at end of file
... ...
fileFormatVersion: 2
guid: 45984eacd62d9a3489fd62689265a23c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
... ...
#if IDG_ENABLE_HELPER_COMMANDS
using UnityEngine;
namespace IngameDebugConsole.Commands
{
public class TimeCommands
{
[ConsoleMethod( "time.scale", "Sets the Time.timeScale value" ), UnityEngine.Scripting.Preserve]
public static void SetTimeScale( float value )
{
Time.timeScale = Mathf.Max( value, 0f );
}
[ConsoleMethod( "time.scale", "Returns the current Time.timeScale value" ), UnityEngine.Scripting.Preserve]
public static float GetTimeScale()
{
return Time.timeScale;
}
}
}
#endif
\ No newline at end of file
... ...
fileFormatVersion: 2
guid: bb12a1f557fffa541909fcfe92d9c1bf
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
... ...
using System;
namespace IngameDebugConsole
{
[AttributeUsage( AttributeTargets.Method, Inherited = false, AllowMultiple = true )]
public class ConsoleMethodAttribute : Attribute
{
private string m_command;
private string m_description;
private string[] m_parameterNames;
public string Command { get { return m_command; } }
public string Description { get { return m_description; } }
public string[] ParameterNames { get { return m_parameterNames; } }
public ConsoleMethodAttribute( string command, string description, params string[] parameterNames )
{
m_command = command;
m_description = description;
m_parameterNames = parameterNames;
}
}
}
\ No newline at end of file
... ...
fileFormatVersion: 2
guid: 324bb39c0bff0f74fa42f83e91f07e3a
timeCreated: 1520710946
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
... ...
#if UNITY_EDITOR || UNITY_STANDALONE
// Unity's Text component doesn't render <b> tag correctly on mobile devices
#define USE_BOLD_COMMAND_SIGNATURES
#endif
using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;
using System.Text;
using Object = UnityEngine.Object;
#if UNITY_EDITOR && UNITY_2021_1_OR_NEWER
using SystemInfo = UnityEngine.Device.SystemInfo; // To support Device Simulator on Unity 2021.1+
#endif
// Manages the console commands, parses console input and handles execution of commands
// Supported method parameter types: int, float, bool, string, Vector2, Vector3, Vector4
// Helper class to store important information about a command
namespace IngameDebugConsole
{
public class ConsoleMethodInfo
{
public readonly MethodInfo method;
public readonly Type[] parameterTypes;
public readonly object instance;
public readonly string command;
public readonly string signature;
public readonly string[] parameters;
public ConsoleMethodInfo( MethodInfo method, Type[] parameterTypes, object instance, string command, string signature, string[] parameters )
{
this.method = method;
this.parameterTypes = parameterTypes;
this.instance = instance;
this.command = command;
this.signature = signature;
this.parameters = parameters;
}
public bool IsValid()
{
if( !method.IsStatic && ( instance == null || instance.Equals( null ) ) )
return false;
return true;
}
}
public static class DebugLogConsole
{
public delegate bool ParseFunction( string input, out object output );
public delegate void CommandExecutedDelegate( string command, object[] parameters );
public static event CommandExecutedDelegate OnCommandExecuted;
// All the commands
private static readonly List<ConsoleMethodInfo> methods = new List<ConsoleMethodInfo>();
private static readonly List<ConsoleMethodInfo> matchingMethods = new List<ConsoleMethodInfo>( 4 );
// All the parse functions
private static readonly Dictionary<Type, ParseFunction> parseFunctions = new Dictionary<Type, ParseFunction>()
{
{ typeof( string ), ParseString },
{ typeof( bool ), ParseBool },
{ typeof( int ), ParseInt },
{ typeof( uint ), ParseUInt },
{ typeof( long ), ParseLong },
{ typeof( ulong ), ParseULong },
{ typeof( byte ), ParseByte },
{ typeof( sbyte ), ParseSByte },
{ typeof( short ), ParseShort },
{ typeof( ushort ), ParseUShort },
{ typeof( char ), ParseChar },
{ typeof( float ), ParseFloat },
{ typeof( double ), ParseDouble },
{ typeof( decimal ), ParseDecimal },
{ typeof( Vector2 ), ParseVector2 },
{ typeof( Vector3 ), ParseVector3 },
{ typeof( Vector4 ), ParseVector4 },
{ typeof( Quaternion ), ParseQuaternion },
{ typeof( Color ), ParseColor },
{ typeof( Color32 ), ParseColor32 },
{ typeof( Rect ), ParseRect },
{ typeof( RectOffset ), ParseRectOffset },
{ typeof( Bounds ), ParseBounds },
{ typeof( GameObject ), ParseGameObject },
#if UNITY_2017_2_OR_NEWER
{ typeof( Vector2Int ), ParseVector2Int },
{ typeof( Vector3Int ), ParseVector3Int },
{ typeof( RectInt ), ParseRectInt },
{ typeof( BoundsInt ), ParseBoundsInt },
#endif
};
// All the readable names of accepted types
private static readonly Dictionary<Type, string> typeReadableNames = new Dictionary<Type, string>()
{
{ typeof( string ), "String" },
{ typeof( bool ), "Boolean" },
{ typeof( int ), "Integer" },
{ typeof( uint ), "Unsigned Integer" },
{ typeof( long ), "Long" },
{ typeof( ulong ), "Unsigned Long" },
{ typeof( byte ), "Byte" },
{ typeof( sbyte ), "Short Byte" },
{ typeof( short ), "Short" },
{ typeof( ushort ), "Unsigned Short" },
{ typeof( char ), "Char" },
{ typeof( float ), "Float" },
{ typeof( double ), "Double" },
{ typeof( decimal ), "Decimal" }
};
// Split arguments of an entered command
private static readonly List<string> commandArguments = new List<string>( 8 );
// Command parameter delimeter groups
private static readonly string[] inputDelimiters = new string[] { "\"\"", "''", "{}", "()", "[]" };
// CompareInfo used for case-insensitive command name comparison
internal static readonly CompareInfo caseInsensitiveComparer = new CultureInfo( "en-US" ).CompareInfo;
static DebugLogConsole()
{
#if !IDG_DISABLE_HELP_COMMAND
AddCommand( "help", "Prints all commands", LogAllCommands );
AddCommand<string>( "help", "Prints all matching commands", LogAllCommandsWithName );
#endif
#if IDG_ENABLE_HELPER_COMMANDS || IDG_ENABLE_SYSINFO_COMMAND
AddCommand( "sysinfo", "Prints system information", LogSystemInfo );
#endif
#if UNITY_EDITOR || !NETFX_CORE
// Find all [ConsoleMethod] functions
// Don't search built-in assemblies for console methods since they can't have any
string[] ignoredAssemblies = new string[]
{
"Unity",
"System",
"Mono.",
"mscorlib",
"netstandard",
"TextMeshPro",
"Microsoft.GeneratedCode",
"I18N",
"Boo.",
"UnityScript.",
"ICSharpCode.",
"ExCSS.Unity",
#if UNITY_EDITOR
"Assembly-CSharp-Editor",
"Assembly-UnityScript-Editor",
"nunit.",
"SyntaxTree.",
"AssetStoreTools",
#endif
};
#endif
#if UNITY_EDITOR || !NETFX_CORE
foreach( Assembly assembly in AppDomain.CurrentDomain.GetAssemblies() )
#else
foreach( Assembly assembly in new Assembly[] { typeof( DebugLogConsole ).Assembly } ) // On UWP, at least search this plugin's Assembly for console methods
#endif
{
#if( NET_4_6 || NET_STANDARD_2_0 ) && ( UNITY_EDITOR || !NETFX_CORE )
if( assembly.IsDynamic )
continue;
#endif
#if UNITY_EDITOR || !NETFX_CORE
string assemblyName = assembly.GetName().Name;
bool ignoreAssembly = false;
for( int i = 0; i < ignoredAssemblies.Length; i++ )
{
if( caseInsensitiveComparer.IsPrefix( assemblyName, ignoredAssemblies[i], CompareOptions.IgnoreCase ) )
{
ignoreAssembly = true;
break;
}
}
if( ignoreAssembly )
continue;
#endif
SearchAssemblyForConsoleMethods( assembly );
}
}
public static void SearchAssemblyForConsoleMethods( Assembly assembly )
{
try
{
foreach( Type type in assembly.GetExportedTypes() )
{
foreach( MethodInfo method in type.GetMethods( BindingFlags.Static | BindingFlags.Public | BindingFlags.DeclaredOnly ) )
{
foreach( object attribute in method.GetCustomAttributes( typeof( ConsoleMethodAttribute ), false ) )
{
ConsoleMethodAttribute consoleMethod = attribute as ConsoleMethodAttribute;
if( consoleMethod != null )
AddCommand( consoleMethod.Command, consoleMethod.Description, method, null, consoleMethod.ParameterNames );
}
}
}
}
catch( NotSupportedException ) { }
catch( System.IO.FileNotFoundException ) { }
catch( ReflectionTypeLoadException ) { }
catch( Exception e )
{
Debug.LogError( "Couldn't search assembly for [ConsoleMethod] attributes: " + assembly.GetName().Name + "\n" + e.ToString() );
}
}
public static List<ConsoleMethodInfo> GetAllCommands()
{
return methods;
}
// Logs the list of available commands
public static void LogAllCommands()
{
int length = 25;
for( int i = 0; i < methods.Count; i++ )
{
if( methods[i].IsValid() )
length += methods[i].signature.Length + 7;
}
StringBuilder stringBuilder = new StringBuilder( length );
stringBuilder.Append( "Available commands:" );
for( int i = 0; i < methods.Count; i++ )
{
if( methods[i].IsValid() )
stringBuilder.Append( "\n - " ).Append( methods[i].signature );
}
Debug.Log( stringBuilder.ToString() );
// After typing help, the log that lists all the commands should automatically be expanded for better UX
if( DebugLogManager.Instance )
DebugLogManager.Instance.AdjustLatestPendingLog( true, true );
}
// Logs the list of available commands that are either equal to commandName or contain commandName as substring
public static void LogAllCommandsWithName( string commandName )
{
matchingMethods.Clear();
// First, try to find commands that exactly match the commandName. If there are no such commands, try to find
// commands that contain commandName as substring
FindCommands( commandName, false, matchingMethods );
if( matchingMethods.Count == 0 )
FindCommands( commandName, true, matchingMethods );
if( matchingMethods.Count == 0 )
Debug.LogWarning( string.Concat( "ERROR: can't find command '", commandName, "'" ) );
else
{
int commandsLength = 25;
for( int i = 0; i < matchingMethods.Count; i++ )
commandsLength += matchingMethods[i].signature.Length + 7;
StringBuilder stringBuilder = new StringBuilder( commandsLength );
stringBuilder.Append( "Matching commands:" );
for( int i = 0; i < matchingMethods.Count; i++ )
stringBuilder.Append( "\n - " ).Append( matchingMethods[i].signature );
Debug.Log( stringBuilder.ToString() );
if( DebugLogManager.Instance )
DebugLogManager.Instance.AdjustLatestPendingLog( true, true );
}
}
// Logs system information
public static void LogSystemInfo()
{
StringBuilder stringBuilder = new StringBuilder( 1024 );
stringBuilder.Append( "Rig: " ).AppendSysInfoIfPresent( SystemInfo.deviceModel ).AppendSysInfoIfPresent( SystemInfo.processorType )
.AppendSysInfoIfPresent( SystemInfo.systemMemorySize, "MB RAM" ).Append( SystemInfo.processorCount ).Append( " cores\n" );
stringBuilder.Append( "OS: " ).Append( SystemInfo.operatingSystem ).Append( "\n" );
stringBuilder.Append( "GPU: " ).Append( SystemInfo.graphicsDeviceName ).Append( " " ).Append( SystemInfo.graphicsMemorySize )
.Append( "MB " ).Append( SystemInfo.graphicsDeviceVersion )
.Append( SystemInfo.graphicsMultiThreaded ? " multi-threaded\n" : "\n" );
stringBuilder.Append( "Data Path: " ).Append( Application.dataPath ).Append( "\n" );
stringBuilder.Append( "Persistent Data Path: " ).Append( Application.persistentDataPath ).Append( "\n" );
stringBuilder.Append( "StreamingAssets Path: " ).Append( Application.streamingAssetsPath ).Append( "\n" );
stringBuilder.Append( "Temporary Cache Path: " ).Append( Application.temporaryCachePath ).Append( "\n" );
stringBuilder.Append( "Device ID: " ).Append( SystemInfo.deviceUniqueIdentifier ).Append( "\n" );
stringBuilder.Append( "Max Texture Size: " ).Append( SystemInfo.maxTextureSize ).Append( "\n" );
#if UNITY_5_6_OR_NEWER
stringBuilder.Append( "Max Cubemap Size: " ).Append( SystemInfo.maxCubemapSize ).Append( "\n" );
#endif
stringBuilder.Append( "Accelerometer: " ).Append( SystemInfo.supportsAccelerometer ? "supported\n" : "not supported\n" );
stringBuilder.Append( "Gyro: " ).Append( SystemInfo.supportsGyroscope ? "supported\n" : "not supported\n" );
stringBuilder.Append( "Location Service: " ).Append( SystemInfo.supportsLocationService ? "supported\n" : "not supported\n" );
#if !UNITY_2019_1_OR_NEWER
stringBuilder.Append( "Image Effects: " ).Append( SystemInfo.supportsImageEffects ? "supported\n" : "not supported\n" );
stringBuilder.Append( "RenderToCubemap: " ).Append( SystemInfo.supportsRenderToCubemap ? "supported\n" : "not supported\n" );
#endif
stringBuilder.Append( "Compute Shaders: " ).Append( SystemInfo.supportsComputeShaders ? "supported\n" : "not supported\n" );
stringBuilder.Append( "Shadows: " ).Append( SystemInfo.supportsShadows ? "supported\n" : "not supported\n" );
stringBuilder.Append( "Instancing: " ).Append( SystemInfo.supportsInstancing ? "supported\n" : "not supported\n" );
stringBuilder.Append( "Motion Vectors: " ).Append( SystemInfo.supportsMotionVectors ? "supported\n" : "not supported\n" );
stringBuilder.Append( "3D Textures: " ).Append( SystemInfo.supports3DTextures ? "supported\n" : "not supported\n" );
#if UNITY_5_6_OR_NEWER
stringBuilder.Append( "3D Render Textures: " ).Append( SystemInfo.supports3DRenderTextures ? "supported\n" : "not supported\n" );
#endif
stringBuilder.Append( "2D Array Textures: " ).Append( SystemInfo.supports2DArrayTextures ? "supported\n" : "not supported\n" );
stringBuilder.Append( "Cubemap Array Textures: " ).Append( SystemInfo.supportsCubemapArrayTextures ? "supported" : "not supported" );
Debug.Log( stringBuilder.ToString() );
// After typing sysinfo, the log that lists system information should automatically be expanded for better UX
if( DebugLogManager.Instance )
DebugLogManager.Instance.AdjustLatestPendingLog( true, true );
}
private static StringBuilder AppendSysInfoIfPresent( this StringBuilder sb, string info, string postfix = null )
{
if( info != SystemInfo.unsupportedIdentifier )
{
sb.Append( info );
if( postfix != null )
sb.Append( postfix );
sb.Append( " " );
}
return sb;
}
private static StringBuilder AppendSysInfoIfPresent( this StringBuilder sb, int info, string postfix = null )
{
if( info > 0 )
{
sb.Append( info );
if( postfix != null )
sb.Append( postfix );
sb.Append( " " );
}
return sb;
}
// Add a custom Type to the list of recognized command parameter Types
public static void AddCustomParameterType( Type type, ParseFunction parseFunction, string typeReadableName = null )
{
if( type == null )
{
Debug.LogError( "Parameter type can't be null!" );
return;
}
else if( parseFunction == null )
{
Debug.LogError( "Parameter parseFunction can't be null!" );
return;
}
parseFunctions[type] = parseFunction;
if( !string.IsNullOrEmpty( typeReadableName ) )
typeReadableNames[type] = typeReadableName;
}
// Remove a custom Type from the list of recognized command parameter Types
public static void RemoveCustomParameterType( Type type )
{
parseFunctions.Remove( type );
typeReadableNames.Remove( type );
}
// Add a command related with an instance method (i.e. non static method)
public static void AddCommandInstance( string command, string description, string methodName, object instance, params string[] parameterNames )
{
if( instance == null )
{
Debug.LogError( "Instance can't be null!" );
return;
}
AddCommand( command, description, methodName, instance.GetType(), instance, parameterNames );
}
// Add a command related with a static method (i.e. no instance is required to call the method)
public static void AddCommandStatic( string command, string description, string methodName, Type ownerType, params string[] parameterNames )
{
AddCommand( command, description, methodName, ownerType, null, parameterNames );
}
// Add a command that can be related to either a static or an instance method
public static void AddCommand( string command, string description, Action method ) { AddCommand( command, description, method.Method, method.Target, null ); }
public static void AddCommand<T1>( string command, string description, Action<T1> method ) { AddCommand( command, description, method.Method, method.Target, null ); }
public static void AddCommand<T1>( string command, string description, Func<T1> method ) { AddCommand( command, description, method.Method, method.Target, null ); }
public static void AddCommand<T1, T2>( string command, string description, Action<T1, T2> method ) { AddCommand( command, description, method.Method, method.Target, null ); }
public static void AddCommand<T1, T2>( string command, string description, Func<T1, T2> method ) { AddCommand( command, description, method.Method, method.Target, null ); }
public static void AddCommand<T1, T2, T3>( string command, string description, Action<T1, T2, T3> method ) { AddCommand( command, description, method.Method, method.Target, null ); }
public static void AddCommand<T1, T2, T3>( string command, string description, Func<T1, T2, T3> method ) { AddCommand( command, description, method.Method, method.Target, null ); }
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 ); }
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 ); }
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 ); }
public static void AddCommand( string command, string description, Delegate method ) { AddCommand( command, description, method.Method, method.Target, null ); }
// Add a command with custom parameter names
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 } ); }
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 } ); }
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 } ); }
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 } ); }
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 } ); }
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 } ); }
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 } ); }
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 } ); }
public static void AddCommand( string command, string description, Delegate method, params string[] parameterNames ) { AddCommand( command, description, method.Method, method.Target, parameterNames ); }
// Create a new command and set its properties
private static void AddCommand( string command, string description, string methodName, Type ownerType, object instance, string[] parameterNames )
{
// Get the method from the class
MethodInfo method = ownerType.GetMethod( methodName, BindingFlags.Public | BindingFlags.NonPublic | ( instance != null ? BindingFlags.Instance : BindingFlags.Static ) );
if( method == null )
{
Debug.LogError( methodName + " does not exist in " + ownerType );
return;
}
AddCommand( command, description, method, instance, parameterNames );
}
private static void AddCommand( string command, string description, MethodInfo method, object instance, string[] parameterNames )
{
if( string.IsNullOrEmpty( command ) )
{
Debug.LogError( "Command name can't be empty!" );
return;
}
command = command.Trim();
if( command.IndexOf( ' ' ) >= 0 )
{
Debug.LogError( "Command name can't contain whitespace: " + command );
return;
}
// Fetch the parameters of the class
ParameterInfo[] parameters = method.GetParameters();
if( parameters == null )
parameters = new ParameterInfo[0];
// Store the parameter types in an array
Type[] parameterTypes = new Type[parameters.Length];
for( int i = 0; i < parameters.Length; i++ )
{
if( parameters[i].ParameterType.IsByRef )
{
Debug.LogError( "Command can't have 'out' or 'ref' parameters" );
return;
}
Type parameterType = parameters[i].ParameterType;
if( parseFunctions.ContainsKey( parameterType ) || typeof( Component ).IsAssignableFrom( parameterType ) || parameterType.IsEnum || IsSupportedArrayType( parameterType ) )
parameterTypes[i] = parameterType;
else
{
Debug.LogError( string.Concat( "Parameter ", parameters[i].Name, "'s Type ", parameterType, " isn't supported" ) );
return;
}
}
int commandIndex = FindCommandIndex( command );
if( commandIndex < 0 )
commandIndex = ~commandIndex;
else
{
int commandFirstIndex = commandIndex;
int commandLastIndex = commandIndex;
while( commandFirstIndex > 0 && caseInsensitiveComparer.Compare( methods[commandFirstIndex - 1].command, command, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ) == 0 )
commandFirstIndex--;
while( commandLastIndex < methods.Count - 1 && caseInsensitiveComparer.Compare( methods[commandLastIndex + 1].command, command, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ) == 0 )
commandLastIndex++;
commandIndex = commandFirstIndex;
for( int i = commandFirstIndex; i <= commandLastIndex; i++ )
{
int parameterCountDiff = methods[i].parameterTypes.Length - parameterTypes.Length;
if( parameterCountDiff <= 0 )
{
// We are sorting the commands in 2 steps:
// 1: Sorting by their 'command' names which is handled by FindCommandIndex
// 2: Sorting by their parameter counts which is handled here (parameterCountDiff <= 0)
commandIndex = i + 1;
// Check if this command has been registered before and if it is, overwrite that command
if( parameterCountDiff == 0 )
{
int j = 0;
while( j < parameterTypes.Length && parameterTypes[j] == methods[i].parameterTypes[j] )
j++;
if( j >= parameterTypes.Length )
{
commandIndex = i;
commandLastIndex--;
methods.RemoveAt( i-- );
continue;
}
}
}
}
}
// Create the command
StringBuilder methodSignature = new StringBuilder( 256 );
string[] parameterSignatures = new string[parameterTypes.Length];
#if USE_BOLD_COMMAND_SIGNATURES
methodSignature.Append( "<b>" );
#endif
methodSignature.Append( command );
if( parameterTypes.Length > 0 )
{
methodSignature.Append( " " );
for( int i = 0; i < parameterTypes.Length; i++ )
{
int parameterSignatureStartIndex = methodSignature.Length;
methodSignature.Append( "[" ).Append( GetTypeReadableName( parameterTypes[i] ) ).Append( " " ).Append( ( parameterNames != null && i < parameterNames.Length && !string.IsNullOrEmpty( parameterNames[i] ) ) ? parameterNames[i] : parameters[i].Name ).Append( "]" );
if( i < parameterTypes.Length - 1 )
methodSignature.Append( " " );
parameterSignatures[i] = methodSignature.ToString( parameterSignatureStartIndex, methodSignature.Length - parameterSignatureStartIndex );
}
}
#if USE_BOLD_COMMAND_SIGNATURES
methodSignature.Append( "</b>" );
#endif
if( !string.IsNullOrEmpty( description ) )
methodSignature.Append( ": " ).Append( description );
methods.Insert( commandIndex, new ConsoleMethodInfo( method, parameterTypes, instance, command, methodSignature.ToString(), parameterSignatures ) );
}
// Remove all commands with the matching command name from the console
public static void RemoveCommand( string command )
{
if( !string.IsNullOrEmpty( command ) )
{
for( int i = methods.Count - 1; i >= 0; i-- )
{
if( caseInsensitiveComparer.Compare( methods[i].command, command, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ) == 0 )
methods.RemoveAt( i );
}
}
}
// Remove all commands with the matching method from the console
public static void RemoveCommand( Action method ) { RemoveCommand( method.Method ); }
public static void RemoveCommand<T1>( Action<T1> method ) { RemoveCommand( method.Method ); }
public static void RemoveCommand<T1>( Func<T1> method ) { RemoveCommand( method.Method ); }
public static void RemoveCommand<T1, T2>( Action<T1, T2> method ) { RemoveCommand( method.Method ); }
public static void RemoveCommand<T1, T2>( Func<T1, T2> method ) { RemoveCommand( method.Method ); }
public static void RemoveCommand<T1, T2, T3>( Action<T1, T2, T3> method ) { RemoveCommand( method.Method ); }
public static void RemoveCommand<T1, T2, T3>( Func<T1, T2, T3> method ) { RemoveCommand( method.Method ); }
public static void RemoveCommand<T1, T2, T3, T4>( Action<T1, T2, T3, T4> method ) { RemoveCommand( method.Method ); }
public static void RemoveCommand<T1, T2, T3, T4>( Func<T1, T2, T3, T4> method ) { RemoveCommand( method.Method ); }
public static void RemoveCommand<T1, T2, T3, T4, T5>( Func<T1, T2, T3, T4, T5> method ) { RemoveCommand( method.Method ); }
public static void RemoveCommand( Delegate method ) { RemoveCommand( method.Method ); }
public static void RemoveCommand( MethodInfo method )
{
if( method != null )
{
for( int i = methods.Count - 1; i >= 0; i-- )
{
if( methods[i].method == method )
methods.RemoveAt( i );
}
}
}
// Returns the first command that starts with the entered argument
public static string GetAutoCompleteCommand( string commandStart, string previousSuggestion )
{
int commandIndex = FindCommandIndex( !string.IsNullOrEmpty( previousSuggestion ) ? previousSuggestion : commandStart );
if( commandIndex < 0 )
{
commandIndex = ~commandIndex;
return ( commandIndex < methods.Count && caseInsensitiveComparer.IsPrefix( methods[commandIndex].command, commandStart, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ) ) ? methods[commandIndex].command : null;
}
// Find the next command that starts with commandStart and is different from previousSuggestion
for( int i = commandIndex + 1; i < methods.Count; i++ )
{
if( caseInsensitiveComparer.Compare( methods[i].command, previousSuggestion, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ) == 0 )
continue;
else if( caseInsensitiveComparer.IsPrefix( methods[i].command, commandStart, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ) )
return methods[i].command;
else
break;
}
// Couldn't find a command that follows previousSuggestion and satisfies commandStart, loop back to the beginning of the autocomplete suggestions
string result = null;
for( int i = commandIndex - 1; i >= 0 && caseInsensitiveComparer.IsPrefix( methods[i].command, commandStart, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ); i-- )
result = methods[i].command;
return result;
}
// Parse the command and try to execute it
public static void ExecuteCommand( string command )
{
if( command == null )
return;
command = command.Trim();
if( command.Length == 0 )
return;
// Split the command's arguments
commandArguments.Clear();
FetchArgumentsFromCommand( command, commandArguments );
// Find all matching commands
matchingMethods.Clear();
bool parameterCountMismatch = false;
int commandIndex = FindCommandIndex( commandArguments[0] );
if( commandIndex >= 0 )
{
string _command = commandArguments[0];
int commandLastIndex = commandIndex;
while( commandIndex > 0 && caseInsensitiveComparer.Compare( methods[commandIndex - 1].command, _command, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ) == 0 )
commandIndex--;
while( commandLastIndex < methods.Count - 1 && caseInsensitiveComparer.Compare( methods[commandLastIndex + 1].command, _command, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ) == 0 )
commandLastIndex++;
while( commandIndex <= commandLastIndex )
{
if( !methods[commandIndex].IsValid() )
{
methods.RemoveAt( commandIndex );
commandLastIndex--;
}
else
{
// Check if number of parameters match
if( methods[commandIndex].parameterTypes.Length == commandArguments.Count - 1 )
matchingMethods.Add( methods[commandIndex] );
else
parameterCountMismatch = true;
commandIndex++;
}
}
}
if( matchingMethods.Count == 0 )
{
string _command = commandArguments[0];
FindCommands( _command, !parameterCountMismatch, matchingMethods );
if( matchingMethods.Count == 0 )
Debug.LogWarning( string.Concat( "ERROR: can't find command '", _command, "'" ) );
else
{
int commandsLength = _command.Length + 75;
for( int i = 0; i < matchingMethods.Count; i++ )
commandsLength += matchingMethods[i].signature.Length + 7;
StringBuilder stringBuilder = new StringBuilder( commandsLength );
if( parameterCountMismatch )
stringBuilder.Append( "ERROR: '" ).Append( _command ).Append( "' doesn't take " ).Append( commandArguments.Count - 1 ).Append( " parameter(s). Available command(s):" );
else
stringBuilder.Append( "ERROR: can't find command '" ).Append( _command ).Append( "'. Did you mean:" );
for( int i = 0; i < matchingMethods.Count; i++ )
stringBuilder.Append( "\n - " ).Append( matchingMethods[i].signature );
Debug.LogWarning( stringBuilder.ToString() );
// The log that lists method signature(s) for this command should automatically be expanded for better UX
if( DebugLogManager.Instance )
DebugLogManager.Instance.AdjustLatestPendingLog( true, true );
}
return;
}
ConsoleMethodInfo methodToExecute = null;
object[] parameters = new object[commandArguments.Count - 1];
string errorMessage = null;
for( int i = 0; i < matchingMethods.Count && methodToExecute == null; i++ )
{
ConsoleMethodInfo methodInfo = matchingMethods[i];
// Parse the parameters into objects
bool success = true;
for( int j = 0; j < methodInfo.parameterTypes.Length && success; j++ )
{
try
{
string argument = commandArguments[j + 1];
Type parameterType = methodInfo.parameterTypes[j];
object val;
if( ParseArgument( argument, parameterType, out val ) )
parameters[j] = val;
else
{
success = false;
errorMessage = string.Concat( "ERROR: couldn't parse ", argument, " to ", GetTypeReadableName( parameterType ) );
}
}
catch( Exception e )
{
success = false;
errorMessage = "ERROR: " + e.ToString();
}
}
if( success )
methodToExecute = methodInfo;
}
if( methodToExecute == null )
Debug.LogWarning( !string.IsNullOrEmpty( errorMessage ) ? errorMessage : "ERROR: something went wrong" );
else
{
// Execute the method associated with the command
object result = methodToExecute.method.Invoke( methodToExecute.instance, parameters );
if( methodToExecute.method.ReturnType != typeof( void ) )
{
// Print the returned value to the console
if( result == null || result.Equals( null ) )
Debug.Log( "Returned: null" );
else
Debug.Log( "Returned: " + result.ToString() );
}
if( OnCommandExecuted != null )
OnCommandExecuted( methodToExecute.command, parameters );
}
}
public static void FetchArgumentsFromCommand( string command, List<string> commandArguments )
{
for( int i = 0; i < command.Length; i++ )
{
if( char.IsWhiteSpace( command[i] ) )
continue;
int delimiterIndex = IndexOfDelimiterGroup( command[i] );
if( delimiterIndex >= 0 )
{
int endIndex = IndexOfDelimiterGroupEnd( command, delimiterIndex, i + 1 );
commandArguments.Add( command.Substring( i + 1, endIndex - i - 1 ) );
i = ( endIndex < command.Length - 1 && command[endIndex + 1] == ',' ) ? endIndex + 1 : endIndex;
}
else
{
int endIndex = IndexOfChar( command, ' ', i + 1 );
commandArguments.Add( command.Substring( i, command[endIndex - 1] == ',' ? endIndex - 1 - i : endIndex - i ) );
i = endIndex;
}
}
}
public static void FindCommands( string commandName, bool allowSubstringMatching, List<ConsoleMethodInfo> matchingCommands )
{
if( allowSubstringMatching )
{
for( int i = 0; i < methods.Count; i++ )
{
if( methods[i].IsValid() && caseInsensitiveComparer.IndexOf( methods[i].command, commandName, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ) >= 0 )
matchingCommands.Add( methods[i] );
}
}
else
{
for( int i = 0; i < methods.Count; i++ )
{
if( methods[i].IsValid() && caseInsensitiveComparer.Compare( methods[i].command, commandName, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ) == 0 )
matchingCommands.Add( methods[i] );
}
}
}
// Finds all commands that have a matching signature with command
// - caretIndexIncrements: indices inside "string command" that separate two arguments in the command. This is used to
// figure out which argument the caret is standing on
// - commandName: command's name (first argument)
internal static void GetCommandSuggestions( string command, List<ConsoleMethodInfo> matchingCommands, List<int> caretIndexIncrements, ref string commandName, out int numberOfParameters )
{
bool commandNameCalculated = false;
bool commandNameFullyTyped = false;
numberOfParameters = -1;
for( int i = 0; i < command.Length; i++ )
{
if( char.IsWhiteSpace( command[i] ) )
continue;
int delimiterIndex = IndexOfDelimiterGroup( command[i] );
if( delimiterIndex >= 0 )
{
int endIndex = IndexOfDelimiterGroupEnd( command, delimiterIndex, i + 1 );
if( !commandNameCalculated )
{
commandNameCalculated = true;
commandNameFullyTyped = command.Length > endIndex;
int commandNameLength = endIndex - i - 1;
if( commandName == null || commandNameLength == 0 || commandName.Length != commandNameLength || caseInsensitiveComparer.IndexOf( command, commandName, i + 1, commandNameLength, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ) != i + 1 )
commandName = command.Substring( i + 1, commandNameLength );
}
i = ( endIndex < command.Length - 1 && command[endIndex + 1] == ',' ) ? endIndex + 1 : endIndex;
caretIndexIncrements.Add( i + 1 );
}
else
{
int endIndex = IndexOfChar( command, ' ', i + 1 );
if( !commandNameCalculated )
{
commandNameCalculated = true;
commandNameFullyTyped = command.Length > endIndex;
int commandNameLength = command[endIndex - 1] == ',' ? endIndex - 1 - i : endIndex - i;
if( commandName == null || commandNameLength == 0 || commandName.Length != commandNameLength || caseInsensitiveComparer.IndexOf( command, commandName, i, commandNameLength, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ) != i )
commandName = command.Substring( i, commandNameLength );
}
i = endIndex;
caretIndexIncrements.Add( i );
}
numberOfParameters++;
}
if( !commandNameCalculated )
commandName = string.Empty;
if( !string.IsNullOrEmpty( commandName ) )
{
int commandIndex = FindCommandIndex( commandName );
if( commandIndex < 0 )
commandIndex = ~commandIndex;
int commandLastIndex = commandIndex;
if( !commandNameFullyTyped )
{
// Match all commands that start with commandName
if( commandIndex < methods.Count && caseInsensitiveComparer.IsPrefix( methods[commandIndex].command, commandName, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ) )
{
while( commandIndex > 0 && caseInsensitiveComparer.IsPrefix( methods[commandIndex - 1].command, commandName, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ) )
commandIndex--;
while( commandLastIndex < methods.Count - 1 && caseInsensitiveComparer.IsPrefix( methods[commandLastIndex + 1].command, commandName, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ) )
commandLastIndex++;
}
else
commandLastIndex = -1;
}
else
{
// Match only the commands that are equal to commandName
if( commandIndex < methods.Count && caseInsensitiveComparer.Compare( methods[commandIndex].command, commandName, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ) == 0 )
{
while( commandIndex > 0 && caseInsensitiveComparer.Compare( methods[commandIndex - 1].command, commandName, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ) == 0 )
commandIndex--;
while( commandLastIndex < methods.Count - 1 && caseInsensitiveComparer.Compare( methods[commandLastIndex + 1].command, commandName, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ) == 0 )
commandLastIndex++;
}
else
commandLastIndex = -1;
}
for( ; commandIndex <= commandLastIndex; commandIndex++ )
{
if( methods[commandIndex].parameterTypes.Length >= numberOfParameters )
matchingCommands.Add( methods[commandIndex] );
}
}
}
// Find the index of the delimiter group that 'c' belongs to
private static int IndexOfDelimiterGroup( char c )
{
for( int i = 0; i < inputDelimiters.Length; i++ )
{
if( c == inputDelimiters[i][0] )
return i;
}
return -1;
}
private static int IndexOfDelimiterGroupEnd( string command, int delimiterIndex, int startIndex )
{
char startChar = inputDelimiters[delimiterIndex][0];
char endChar = inputDelimiters[delimiterIndex][1];
// Check delimiter's depth for array support (e.g. [[1 2] [3 4]] for Vector2 array)
int depth = 1;
for( int i = startIndex; i < command.Length; i++ )
{
char c = command[i];
if( c == endChar && --depth <= 0 )
return i;
else if( c == startChar )
depth++;
}
return command.Length;
}
// Find the index of char in the string, or return the length of string instead of -1
private static int IndexOfChar( string command, char c, int startIndex )
{
int result = command.IndexOf( c, startIndex );
if( result < 0 )
result = command.Length;
return result;
}
// Find command's index in the list of registered commands using binary search
private static int FindCommandIndex( string command )
{
int min = 0;
int max = methods.Count - 1;
while( min <= max )
{
int mid = ( min + max ) / 2;
int comparison = caseInsensitiveComparer.Compare( command, methods[mid].command, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace );
if( comparison == 0 )
return mid;
else if( comparison < 0 )
max = mid - 1;
else
min = mid + 1;
}
return ~min;
}
public static bool IsSupportedArrayType( Type type )
{
if( type.IsArray )
{
if( type.GetArrayRank() != 1 )
return false;
type = type.GetElementType();
}
else if( type.IsGenericType )
{
if( type.GetGenericTypeDefinition() != typeof( List<> ) )
return false;
type = type.GetGenericArguments()[0];
}
else
return false;
return parseFunctions.ContainsKey( type ) || typeof( Component ).IsAssignableFrom( type ) || type.IsEnum;
}
public static string GetTypeReadableName( Type type )
{
string result;
if( typeReadableNames.TryGetValue( type, out result ) )
return result;
if( IsSupportedArrayType( type ) )
{
Type elementType = type.IsArray ? type.GetElementType() : type.GetGenericArguments()[0];
if( typeReadableNames.TryGetValue( elementType, out result ) )
return result + "[]";
else
return elementType.Name + "[]";
}
return type.Name;
}
public static bool ParseArgument( string input, Type argumentType, out object output )
{
ParseFunction parseFunction;
if( parseFunctions.TryGetValue( argumentType, out parseFunction ) )
return parseFunction( input, out output );
else if( typeof( Component ).IsAssignableFrom( argumentType ) )
return ParseComponent( input, argumentType, out output );
else if( argumentType.IsEnum )
return ParseEnum( input, argumentType, out output );
else if( IsSupportedArrayType( argumentType ) )
return ParseArray( input, argumentType, out output );
else
{
output = null;
return false;
}
}
public static bool ParseString( string input, out object output )
{
output = input;
return true;
}
public static bool ParseBool( string input, out object output )
{
if( input == "1" || input.ToLowerInvariant() == "true" )
{
output = true;
return true;
}
if( input == "0" || input.ToLowerInvariant() == "false" )
{
output = false;
return true;
}
output = false;
return false;
}
public static bool ParseInt( string input, out object output )
{
int value;
bool result = int.TryParse( input, out value );
output = value;
return result;
}
public static bool ParseUInt( string input, out object output )
{
uint value;
bool result = uint.TryParse( input, out value );
output = value;
return result;
}
public static bool ParseLong( string input, out object output )
{
long value;
bool result = long.TryParse( !input.EndsWith( "L", StringComparison.OrdinalIgnoreCase ) ? input : input.Substring( 0, input.Length - 1 ), out value );
output = value;
return result;
}
public static bool ParseULong( string input, out object output )
{
ulong value;
bool result = ulong.TryParse( !input.EndsWith( "L", StringComparison.OrdinalIgnoreCase ) ? input : input.Substring( 0, input.Length - 1 ), out value );
output = value;
return result;
}
public static bool ParseByte( string input, out object output )
{
byte value;
bool result = byte.TryParse( input, out value );
output = value;
return result;
}
public static bool ParseSByte( string input, out object output )
{
sbyte value;
bool result = sbyte.TryParse( input, out value );
output = value;
return result;
}
public static bool ParseShort( string input, out object output )
{
short value;
bool result = short.TryParse( input, out value );
output = value;
return result;
}
public static bool ParseUShort( string input, out object output )
{
ushort value;
bool result = ushort.TryParse( input, out value );
output = value;
return result;
}
public static bool ParseChar( string input, out object output )
{
char value;
bool result = char.TryParse( input, out value );
output = value;
return result;
}
public static bool ParseFloat( string input, out object output )
{
float value;
bool result = float.TryParse( !input.EndsWith( "f", StringComparison.OrdinalIgnoreCase ) ? input : input.Substring( 0, input.Length - 1 ), NumberStyles.Float, CultureInfo.InvariantCulture, out value );
output = value;
return result;
}
public static bool ParseDouble( string input, out object output )
{
double value;
bool result = double.TryParse( !input.EndsWith( "f", StringComparison.OrdinalIgnoreCase ) ? input : input.Substring( 0, input.Length - 1 ), NumberStyles.Float, CultureInfo.InvariantCulture, out value );
output = value;
return result;
}
public static bool ParseDecimal( string input, out object output )
{
decimal value;
bool result = decimal.TryParse( !input.EndsWith( "f", StringComparison.OrdinalIgnoreCase ) ? input : input.Substring( 0, input.Length - 1 ), NumberStyles.Float, CultureInfo.InvariantCulture, out value );
output = value;
return result;
}
public static bool ParseVector2( string input, out object output )
{
return ParseVector( input, typeof( Vector2 ), out output );
}
public static bool ParseVector3( string input, out object output )
{
return ParseVector( input, typeof( Vector3 ), out output );
}
public static bool ParseVector4( string input, out object output )
{
return ParseVector( input, typeof( Vector4 ), out output );
}
public static bool ParseQuaternion( string input, out object output )
{
return ParseVector( input, typeof( Quaternion ), out output );
}
public static bool ParseColor( string input, out object output )
{
return ParseVector( input, typeof( Color ), out output );
}
public static bool ParseColor32( string input, out object output )
{
return ParseVector( input, typeof( Color32 ), out output );
}
public static bool ParseRect( string input, out object output )
{
return ParseVector( input, typeof( Rect ), out output );
}
public static bool ParseRectOffset( string input, out object output )
{
return ParseVector( input, typeof( RectOffset ), out output );
}
public static bool ParseBounds( string input, out object output )
{
return ParseVector( input, typeof( Bounds ), out output );
}
#if UNITY_2017_2_OR_NEWER
public static bool ParseVector2Int( string input, out object output )
{
return ParseVector( input, typeof( Vector2Int ), out output );
}
public static bool ParseVector3Int( string input, out object output )
{
return ParseVector( input, typeof( Vector3Int ), out output );
}
public static bool ParseRectInt( string input, out object output )
{
return ParseVector( input, typeof( RectInt ), out output );
}
public static bool ParseBoundsInt( string input, out object output )
{
return ParseVector( input, typeof( BoundsInt ), out output );
}
#endif
public static bool ParseGameObject( string input, out object output )
{
output = input == "null" ? null : GameObject.Find( input );
return true;
}
public static bool ParseComponent( string input, Type componentType, out object output )
{
GameObject gameObject = input == "null" ? null : GameObject.Find( input );
output = gameObject ? gameObject.GetComponent( componentType ) : null;
return true;
}
public static bool ParseEnum( string input, Type enumType, out object output )
{
const int NONE = 0, OR = 1, AND = 2;
int outputInt = 0;
int operation = NONE; // 0: nothing, 1: OR with outputInt, 2: AND with outputInt
for( int i = 0; i < input.Length; i++ )
{
string enumStr;
int orIndex = input.IndexOf( '|', i );
int andIndex = input.IndexOf( '&', i );
if( orIndex < 0 )
enumStr = input.Substring( i, ( andIndex < 0 ? input.Length : andIndex ) - i ).Trim();
else
enumStr = input.Substring( i, ( andIndex < 0 ? orIndex : Mathf.Min( andIndex, orIndex ) ) - i ).Trim();
int value;
if( !int.TryParse( enumStr, out value ) )
{
try
{
// Case-insensitive enum parsing
value = Convert.ToInt32( Enum.Parse( enumType, enumStr, true ) );
}
catch
{
output = null;
return false;
}
}
if( operation == NONE )
outputInt = value;
else if( operation == OR )
outputInt |= value;
else
outputInt &= value;
if( orIndex >= 0 )
{
if( andIndex > orIndex )
{
operation = AND;
i = andIndex;
}
else
{
operation = OR;
i = orIndex;
}
}
else if( andIndex >= 0 )
{
operation = AND;
i = andIndex;
}
else
i = input.Length;
}
output = Enum.ToObject( enumType, outputInt );
return true;
}
public static bool ParseArray( string input, Type arrayType, out object output )
{
List<string> valuesToParse = new List<string>( 2 );
FetchArgumentsFromCommand( input, valuesToParse );
IList result = (IList) Activator.CreateInstance( arrayType, new object[1] { valuesToParse.Count } );
output = result;
if( arrayType.IsArray )
{
Type elementType = arrayType.GetElementType();
for( int i = 0; i < valuesToParse.Count; i++ )
{
object obj;
if( !ParseArgument( valuesToParse[i], elementType, out obj ) )
return false;
result[i] = obj;
}
}
else
{
Type elementType = arrayType.GetGenericArguments()[0];
for( int i = 0; i < valuesToParse.Count; i++ )
{
object obj;
if( !ParseArgument( valuesToParse[i], elementType, out obj ) )
return false;
result.Add( obj );
}
}
return true;
}
// Create a vector of specified type (fill the blank slots with 0 or ignore unnecessary slots)
private static bool ParseVector( string input, Type vectorType, out object output )
{
List<string> tokens = new List<string>( input.Replace( ',', ' ' ).Trim().Split( ' ' ) );
for( int i = tokens.Count - 1; i >= 0; i-- )
{
tokens[i] = tokens[i].Trim();
if( tokens[i].Length == 0 )
tokens.RemoveAt( i );
}
float[] tokenValues = new float[tokens.Count];
for( int i = 0; i < tokens.Count; i++ )
{
object val;
if( !ParseFloat( tokens[i], out val ) )
{
if( vectorType == typeof( Vector3 ) )
output = Vector3.zero;
else if( vectorType == typeof( Vector2 ) )
output = Vector2.zero;
else
output = Vector4.zero;
return false;
}
tokenValues[i] = (float) val;
}
if( vectorType == typeof( Vector3 ) )
{
Vector3 result = Vector3.zero;
for( int i = 0; i < tokenValues.Length && i < 3; i++ )
result[i] = tokenValues[i];
output = result;
}
else if( vectorType == typeof( Vector2 ) )
{
Vector2 result = Vector2.zero;
for( int i = 0; i < tokenValues.Length && i < 2; i++ )
result[i] = tokenValues[i];
output = result;
}
else if( vectorType == typeof( Vector4 ) )
{
Vector4 result = Vector4.zero;
for( int i = 0; i < tokenValues.Length && i < 4; i++ )
result[i] = tokenValues[i];
output = result;
}
else if( vectorType == typeof( Quaternion ) )
{
Quaternion result = Quaternion.identity;
for( int i = 0; i < tokenValues.Length && i < 4; i++ )
result[i] = tokenValues[i];
output = result;
}
else if( vectorType == typeof( Color ) )
{
Color result = Color.black;
for( int i = 0; i < tokenValues.Length && i < 4; i++ )
result[i] = tokenValues[i];
output = result;
}
else if( vectorType == typeof( Color32 ) )
{
Color32 result = new Color32( 0, 0, 0, 255 );
if( tokenValues.Length > 0 )
result.r = (byte) Mathf.RoundToInt( tokenValues[0] );
if( tokenValues.Length > 1 )
result.g = (byte) Mathf.RoundToInt( tokenValues[1] );
if( tokenValues.Length > 2 )
result.b = (byte) Mathf.RoundToInt( tokenValues[2] );
if( tokenValues.Length > 3 )
result.a = (byte) Mathf.RoundToInt( tokenValues[3] );
output = result;
}
else if( vectorType == typeof( Rect ) )
{
Rect result = Rect.zero;
if( tokenValues.Length > 0 )
result.x = tokenValues[0];
if( tokenValues.Length > 1 )
result.y = tokenValues[1];
if( tokenValues.Length > 2 )
result.width = tokenValues[2];
if( tokenValues.Length > 3 )
result.height = tokenValues[3];
output = result;
}
else if( vectorType == typeof( RectOffset ) )
{
RectOffset result = new RectOffset();
if( tokenValues.Length > 0 )
result.left = Mathf.RoundToInt( tokenValues[0] );
if( tokenValues.Length > 1 )
result.right = Mathf.RoundToInt( tokenValues[1] );
if( tokenValues.Length > 2 )
result.top = Mathf.RoundToInt( tokenValues[2] );
if( tokenValues.Length > 3 )
result.bottom = Mathf.RoundToInt( tokenValues[3] );
output = result;
}
else if( vectorType == typeof( Bounds ) )
{
Vector3 center = Vector3.zero;
for( int i = 0; i < tokenValues.Length && i < 3; i++ )
center[i] = tokenValues[i];
Vector3 size = Vector3.zero;
for( int i = 3; i < tokenValues.Length && i < 6; i++ )
size[i - 3] = tokenValues[i];
output = new Bounds( center, size );
}
#if UNITY_2017_2_OR_NEWER
else if( vectorType == typeof( Vector3Int ) )
{
Vector3Int result = Vector3Int.zero;
for( int i = 0; i < tokenValues.Length && i < 3; i++ )
result[i] = Mathf.RoundToInt( tokenValues[i] );
output = result;
}
else if( vectorType == typeof( Vector2Int ) )
{
Vector2Int result = Vector2Int.zero;
for( int i = 0; i < tokenValues.Length && i < 2; i++ )
result[i] = Mathf.RoundToInt( tokenValues[i] );
output = result;
}
else if( vectorType == typeof( RectInt ) )
{
RectInt result = new RectInt();
if( tokenValues.Length > 0 )
result.x = Mathf.RoundToInt( tokenValues[0] );
if( tokenValues.Length > 1 )
result.y = Mathf.RoundToInt( tokenValues[1] );
if( tokenValues.Length > 2 )
result.width = Mathf.RoundToInt( tokenValues[2] );
if( tokenValues.Length > 3 )
result.height = Mathf.RoundToInt( tokenValues[3] );
output = result;
}
else if( vectorType == typeof( BoundsInt ) )
{
Vector3Int center = Vector3Int.zero;
for( int i = 0; i < tokenValues.Length && i < 3; i++ )
center[i] = Mathf.RoundToInt( tokenValues[i] );
Vector3Int size = Vector3Int.zero;
for( int i = 3; i < tokenValues.Length && i < 6; i++ )
size[i - 3] = Mathf.RoundToInt( tokenValues[i] );
output = new BoundsInt( center, size );
}
#endif
else
{
output = null;
return false;
}
return true;
}
}
}
\ No newline at end of file
... ...
fileFormatVersion: 2
guid: d15693a03d0d33b4892c6365a2a97e19
timeCreated: 1472036503
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
... ...
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using UnityEngine;
// Container for a simple debug entry
namespace IngameDebugConsole
{
public class DebugLogEntry
{
private const int HASH_NOT_CALCULATED = -623218;
public string logString;
public string stackTrace;
private string completeLog;
// Sprite to show with this entry
public Sprite logTypeSpriteRepresentation;
// Collapsed count
public int count;
// Index of this entry among all collapsed entries
public int collapsedIndex;
private int hashValue;
public void Initialize( string logString, string stackTrace )
{
this.logString = logString;
this.stackTrace = stackTrace;
completeLog = null;
count = 1;
hashValue = HASH_NOT_CALCULATED;
}
public void Clear()
{
logString = null;
stackTrace = null;
completeLog = null;
}
// Checks if logString or stackTrace contains the search term
public bool MatchesSearchTerm( string searchTerm )
{
return ( logString != null && DebugLogConsole.caseInsensitiveComparer.IndexOf( logString, searchTerm, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ) >= 0 ) ||
( stackTrace != null && DebugLogConsole.caseInsensitiveComparer.IndexOf( stackTrace, searchTerm, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ) >= 0 );
}
// Return a string containing complete information about this debug entry
public override string ToString()
{
if( completeLog == null )
completeLog = string.Concat( logString, "\n", stackTrace );
return completeLog;
}
// Credit: https://stackoverflow.com/a/19250516/2373034
public int GetContentHashCode()
{
if( hashValue == HASH_NOT_CALCULATED )
{
unchecked
{
hashValue = 17;
hashValue = hashValue * 23 + ( logString == null ? 0 : logString.GetHashCode() );
hashValue = hashValue * 23 + ( stackTrace == null ? 0 : stackTrace.GetHashCode() );
}
}
return hashValue;
}
}
public struct QueuedDebugLogEntry
{
public readonly string logString;
public readonly string stackTrace;
public readonly LogType logType;
public QueuedDebugLogEntry( string logString, string stackTrace, LogType logType )
{
this.logString = logString;
this.stackTrace = stackTrace;
this.logType = logType;
}
// Checks if logString or stackTrace contains the search term
public bool MatchesSearchTerm( string searchTerm )
{
return ( logString != null && DebugLogConsole.caseInsensitiveComparer.IndexOf( logString, searchTerm, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ) >= 0 ) ||
( stackTrace != null && DebugLogConsole.caseInsensitiveComparer.IndexOf( stackTrace, searchTerm, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ) >= 0 );
}
}
public struct DebugLogEntryTimestamp
{
public readonly System.DateTime dateTime;
#if !IDG_OMIT_ELAPSED_TIME
public readonly float elapsedSeconds;
#endif
#if !IDG_OMIT_FRAMECOUNT
public readonly int frameCount;
#endif
#if !IDG_OMIT_ELAPSED_TIME && !IDG_OMIT_FRAMECOUNT
public DebugLogEntryTimestamp( System.DateTime dateTime, float elapsedSeconds, int frameCount )
#elif !IDG_OMIT_ELAPSED_TIME
public DebugLogEntryTimestamp( System.DateTime dateTime, float elapsedSeconds )
#elif !IDG_OMIT_FRAMECOUNT
public DebugLogEntryTimestamp( System.DateTime dateTime, int frameCount )
#else
public DebugLogEntryTimestamp( System.DateTime dateTime )
#endif
{
this.dateTime = dateTime;
#if !IDG_OMIT_ELAPSED_TIME
this.elapsedSeconds = elapsedSeconds;
#endif
#if !IDG_OMIT_FRAMECOUNT
this.frameCount = frameCount;
#endif
}
public void AppendTime( StringBuilder sb )
{
// Add DateTime in format: [HH:mm:ss]
sb.Append( "[" );
int hour = dateTime.Hour;
if( hour >= 10 )
sb.Append( hour );
else
sb.Append( "0" ).Append( hour );
sb.Append( ":" );
int minute = dateTime.Minute;
if( minute >= 10 )
sb.Append( minute );
else
sb.Append( "0" ).Append( minute );
sb.Append( ":" );
int second = dateTime.Second;
if( second >= 10 )
sb.Append( second );
else
sb.Append( "0" ).Append( second );
sb.Append( "]" );
}
public void AppendFullTimestamp( StringBuilder sb )
{
AppendTime( sb );
#if !IDG_OMIT_ELAPSED_TIME && !IDG_OMIT_FRAMECOUNT
// Append elapsed seconds and frame count in format: [1.0s at #Frame]
sb.Append( "[" ).Append( elapsedSeconds.ToString( "F1" ) ).Append( "s at " ).Append( "#" ).Append( frameCount ).Append( "]" );
#elif !IDG_OMIT_ELAPSED_TIME
// Append elapsed seconds in format: [1.0s]
sb.Append( "[" ).Append( elapsedSeconds.ToString( "F1" ) ).Append( "s]" );
#elif !IDG_OMIT_FRAMECOUNT
// Append frame count in format: [#Frame]
sb.Append( "[#" ).Append( frameCount ).Append( "]" );
#endif
}
}
public class DebugLogEntryContentEqualityComparer : EqualityComparer<DebugLogEntry>
{
public override bool Equals( DebugLogEntry x, DebugLogEntry y )
{
return x.logString == y.logString && x.stackTrace == y.stackTrace;
}
public override int GetHashCode( DebugLogEntry obj )
{
return obj.GetContentHashCode();
}
}
}
\ No newline at end of file
... ...
fileFormatVersion: 2
guid: e7b1a420c564be040bf73b8a377fc2c2
timeCreated: 1466375168
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
... ...
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System.Text;
#if UNITY_EDITOR
using UnityEditor;
using System.Text.RegularExpressions;
#endif
// A UI element to show information about a debug entry
namespace IngameDebugConsole
{
public class DebugLogItem : MonoBehaviour, IPointerClickHandler
{
#region Platform Specific Elements
#if !UNITY_2018_1_OR_NEWER
#if !UNITY_EDITOR && UNITY_ANDROID
private static AndroidJavaClass m_ajc = null;
private static AndroidJavaClass AJC
{
get
{
if( m_ajc == null )
m_ajc = new AndroidJavaClass( "com.yasirkula.unity.DebugConsole" );
return m_ajc;
}
}
private static AndroidJavaObject m_context = null;
private static AndroidJavaObject Context
{
get
{
if( m_context == null )
{
using( AndroidJavaObject unityClass = new AndroidJavaClass( "com.unity3d.player.UnityPlayer" ) )
{
m_context = unityClass.GetStatic<AndroidJavaObject>( "currentActivity" );
}
}
return m_context;
}
}
#elif !UNITY_EDITOR && UNITY_IOS
[System.Runtime.InteropServices.DllImport( "__Internal" )]
private static extern void _DebugConsole_CopyText( string text );
#endif
#endif
#endregion
#pragma warning disable 0649
// Cached components
[SerializeField]
private RectTransform transformComponent;
public RectTransform Transform { get { return transformComponent; } }
[SerializeField]
private Image imageComponent;
public Image Image { get { return imageComponent; } }
[SerializeField]
private CanvasGroup canvasGroupComponent;
public CanvasGroup CanvasGroup { get { return canvasGroupComponent; } }
[SerializeField]
private Text logText;
[SerializeField]
private Image logTypeImage;
// Objects related to the collapsed count of the debug entry
[SerializeField]
private GameObject logCountParent;
[SerializeField]
private Text logCountText;
[SerializeField]
private RectTransform copyLogButton;
#pragma warning restore 0649
// Debug entry to show with this log item
private DebugLogEntry logEntry;
public DebugLogEntry Entry { get { return logEntry; } }
private DebugLogEntryTimestamp? logEntryTimestamp;
public DebugLogEntryTimestamp? Timestamp { get { return logEntryTimestamp; } }
// Index of the entry in the list of entries
[System.NonSerialized] public int Index;
private bool isExpanded;
public bool Expanded { get { return isExpanded; } }
private Vector2 logTextOriginalPosition;
private Vector2 logTextOriginalSize;
private float copyLogButtonHeight;
private DebugLogRecycledListView listView;
public void Initialize( DebugLogRecycledListView listView )
{
this.listView = listView;
logTextOriginalPosition = logText.rectTransform.anchoredPosition;
logTextOriginalSize = logText.rectTransform.sizeDelta;
copyLogButtonHeight = copyLogButton.anchoredPosition.y + copyLogButton.sizeDelta.y + 2f; // 2f: space between text and button
#if !UNITY_EDITOR && UNITY_WEBGL
copyLogButton.gameObject.AddComponent<DebugLogItemCopyWebGL>().Initialize( this );
#endif
}
public void SetContent( DebugLogEntry logEntry, DebugLogEntryTimestamp? logEntryTimestamp, int entryIndex, bool isExpanded )
{
this.logEntry = logEntry;
this.logEntryTimestamp = logEntryTimestamp;
this.Index = entryIndex;
this.isExpanded = isExpanded;
Vector2 size = transformComponent.sizeDelta;
if( isExpanded )
{
logText.horizontalOverflow = HorizontalWrapMode.Wrap;
size.y = listView.SelectedItemHeight;
if( !copyLogButton.gameObject.activeSelf )
{
copyLogButton.gameObject.SetActive( true );
logText.rectTransform.anchoredPosition = new Vector2( logTextOriginalPosition.x, logTextOriginalPosition.y + copyLogButtonHeight * 0.5f );
logText.rectTransform.sizeDelta = logTextOriginalSize - new Vector2( 0f, copyLogButtonHeight );
}
}
else
{
logText.horizontalOverflow = HorizontalWrapMode.Overflow;
size.y = listView.ItemHeight;
if( copyLogButton.gameObject.activeSelf )
{
copyLogButton.gameObject.SetActive( false );
logText.rectTransform.anchoredPosition = logTextOriginalPosition;
logText.rectTransform.sizeDelta = logTextOriginalSize;
}
}
transformComponent.sizeDelta = size;
SetText( logEntry, logEntryTimestamp, isExpanded );
logTypeImage.sprite = logEntry.logTypeSpriteRepresentation;
}
// Show the collapsed count of the debug entry
public void ShowCount()
{
logCountText.text = logEntry.count.ToString();
if( !logCountParent.activeSelf )
logCountParent.SetActive( true );
}
// Hide the collapsed count of the debug entry
public void HideCount()
{
if( logCountParent.activeSelf )
logCountParent.SetActive( false );
}
// Update the debug entry's displayed timestamp
public void UpdateTimestamp( DebugLogEntryTimestamp timestamp )
{
logEntryTimestamp = timestamp;
if( isExpanded || listView.manager.alwaysDisplayTimestamps )
SetText( logEntry, timestamp, isExpanded );
}
private void SetText( DebugLogEntry logEntry, DebugLogEntryTimestamp? logEntryTimestamp, bool isExpanded )
{
if( !logEntryTimestamp.HasValue || ( !isExpanded && !listView.manager.alwaysDisplayTimestamps ) )
logText.text = isExpanded ? logEntry.ToString() : logEntry.logString;
else
{
StringBuilder sb = listView.manager.sharedStringBuilder;
sb.Length = 0;
if( isExpanded )
{
logEntryTimestamp.Value.AppendFullTimestamp( sb );
sb.Append( ": " ).Append( logEntry.ToString() );
}
else
{
logEntryTimestamp.Value.AppendTime( sb );
sb.Append( " " ).Append( logEntry.logString );
}
logText.text = sb.ToString();
}
}
// This log item is clicked, show the debug entry's stack trace
public void OnPointerClick( PointerEventData eventData )
{
#if UNITY_EDITOR
if( eventData.button == PointerEventData.InputButton.Right )
{
Match regex = Regex.Match( logEntry.stackTrace, @"\(at .*\.cs:[0-9]+\)$", RegexOptions.Multiline );
if( regex.Success )
{
string line = logEntry.stackTrace.Substring( regex.Index + 4, regex.Length - 5 );
int lineSeparator = line.IndexOf( ':' );
MonoScript script = AssetDatabase.LoadAssetAtPath<MonoScript>( line.Substring( 0, lineSeparator ) );
if( script != null )
AssetDatabase.OpenAsset( script, int.Parse( line.Substring( lineSeparator + 1 ) ) );
}
}
else
listView.OnLogItemClicked( this );
#else
listView.OnLogItemClicked( this );
#endif
}
public void CopyLog()
{
#if UNITY_EDITOR || !UNITY_WEBGL
string log = GetCopyContent();
if( string.IsNullOrEmpty( log ) )
return;
#if UNITY_EDITOR || UNITY_2018_1_OR_NEWER || ( !UNITY_ANDROID && !UNITY_IOS )
GUIUtility.systemCopyBuffer = log;
#elif UNITY_ANDROID
AJC.CallStatic( "CopyText", Context, log );
#elif UNITY_IOS
_DebugConsole_CopyText( log );
#endif
#endif
}
internal string GetCopyContent()
{
if( !logEntryTimestamp.HasValue )
return logEntry.ToString();
else
{
StringBuilder sb = listView.manager.sharedStringBuilder;
sb.Length = 0;
logEntryTimestamp.Value.AppendFullTimestamp( sb );
sb.Append( ": " ).Append( logEntry.ToString() );
return sb.ToString();
}
}
public float CalculateExpandedHeight( DebugLogEntry logEntry, DebugLogEntryTimestamp? logEntryTimestamp )
{
string text = logText.text;
HorizontalWrapMode wrapMode = logText.horizontalOverflow;
SetText( logEntry, logEntryTimestamp, true );
logText.horizontalOverflow = HorizontalWrapMode.Wrap;
float result = logText.preferredHeight + copyLogButtonHeight;
logText.text = text;
logText.horizontalOverflow = wrapMode;
return Mathf.Max( listView.ItemHeight, result );
}
// Return a string containing complete information about the debug entry
public override string ToString()
{
return logEntry.ToString();
}
}
}
\ No newline at end of file
... ...
fileFormatVersion: 2
guid: d2ea291be9de70a4abfec595203c96c1
timeCreated: 1465919949
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
... ...
#if !UNITY_EDITOR && UNITY_WEBGL
using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.EventSystems;
namespace IngameDebugConsole
{
public class DebugLogItemCopyWebGL : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
{
[DllImport( "__Internal" )]
private static extern void IngameDebugConsoleStartCopy( string textToCopy );
[DllImport( "__Internal" )]
private static extern void IngameDebugConsoleCancelCopy();
private DebugLogItem logItem;
public void Initialize( DebugLogItem logItem )
{
this.logItem = logItem;
}
public void OnPointerDown( PointerEventData eventData )
{
string log = logItem.GetCopyContent();
if( !string.IsNullOrEmpty( log ) )
IngameDebugConsoleStartCopy( log );
}
public void OnPointerUp( PointerEventData eventData )
{
if( eventData.dragging )
IngameDebugConsoleCancelCopy();
}
}
}
#endif
\ No newline at end of file
... ...
fileFormatVersion: 2
guid: 5a7d9d894141e704d8160fb4632121ac
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
... ...