123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796 |
- using UnityEngine;
- using UnityEngine.UI;
- using UnityEngine.EventSystems;
- using System.Collections.Generic;
- using System.IO;
- // Receives debug entries and custom events (e.g. Clear, Collapse, Filter by Type)
- // and notifies the recycled list view of changes to the list of debug entries
- //
- // - Vocabulary -
- // Debug/Log entry: a Debug.Log/LogError/LogWarning/LogException/LogAssertion request made by
- // the client and intercepted by this manager object
- // Debug/Log item: a visual (uGUI) representation of a debug entry
- //
- // There can be a lot of debug entries in the system but there will only be a handful of log items
- // to show their properties on screen (these log items are recycled as the list is scrolled)
- // An enum to represent filtered log types
- namespace IngameDebugConsole
- {
- public enum DebugLogFilter
- {
- None = 0,
- Info = 1,
- Warning = 2,
- Error = 4,
- All = 7
- }
- public class DebugLogManager : MonoBehaviour
- {
- private static DebugLogManager instance = null;
- #pragma warning disable 0649
- // Debug console will persist between scenes
- [Header( "Properties" )]
- [SerializeField]
- [HideInInspector]
- private bool singleton = true;
- // Minimum height of the console window
- [SerializeField]
- [HideInInspector]
- private float minimumHeight = 200f;
- [SerializeField]
- [HideInInspector]
- private bool enablePopup = true;
- [SerializeField]
- [HideInInspector]
- private bool startInPopupMode = true;
- [SerializeField]
- [HideInInspector]
- private bool toggleWithKey = false;
- [SerializeField]
- [HideInInspector]
- private KeyCode toggleKey = KeyCode.BackQuote;
- // Should command input field be cleared after pressing Enter
- [SerializeField]
- [HideInInspector]
- private bool clearCommandAfterExecution = true;
- [SerializeField]
- [HideInInspector]
- private int commandHistorySize = 15;
- [SerializeField]
- [HideInInspector]
- private bool receiveLogcatLogsInAndroid = false;
- [SerializeField]
- [HideInInspector]
- private string logcatArguments;
- [Header( "Visuals" )]
- [SerializeField]
- private DebugLogItem logItemPrefab;
- // Visuals for different log types
- [SerializeField]
- private Sprite infoLog;
- [SerializeField]
- private Sprite warningLog;
- [SerializeField]
- private Sprite errorLog;
- private Dictionary<LogType, Sprite> logSpriteRepresentations;
- [SerializeField]
- private Color collapseButtonNormalColor;
- [SerializeField]
- private Color collapseButtonSelectedColor;
- [SerializeField]
- private Color filterButtonsNormalColor;
- [SerializeField]
- private Color filterButtonsSelectedColor;
- [Header( "Internal References" )]
- [SerializeField]
- private RectTransform logWindowTR;
- private RectTransform canvasTR;
- [SerializeField]
- private RectTransform logItemsContainer;
- [SerializeField]
- private InputField commandInputField;
- [SerializeField]
- private Image collapseButton;
- [SerializeField]
- private Image filterInfoButton;
- [SerializeField]
- private Image filterWarningButton;
- [SerializeField]
- private Image filterErrorButton;
- [SerializeField]
- private Text infoEntryCountText;
- [SerializeField]
- private Text warningEntryCountText;
- [SerializeField]
- private Text errorEntryCountText;
- [SerializeField]
- private GameObject snapToBottomButton;
- // Canvas group to modify visibility of the log window
- [SerializeField]
- private CanvasGroup logWindowCanvasGroup;
- [SerializeField]
- private DebugLogPopup popupManager;
- [SerializeField]
- private ScrollRect logItemsScrollRect;
- // Recycled list view to handle the log items efficiently
- [SerializeField]
- private DebugLogRecycledListView recycledListView;
- #pragma warning restore 0649
- // Number of entries filtered by their types
- private int infoEntryCount = 0, warningEntryCount = 0, errorEntryCount = 0;
- private bool isLogWindowVisible = true;
- private bool screenDimensionsChanged = false;
- // Filters to apply to the list of debug entries to show
- private bool isCollapseOn = false;
- private DebugLogFilter logFilter = DebugLogFilter.All;
- // If the last log item is completely visible (scrollbar is at the bottom),
- // scrollbar will remain at the bottom when new debug entries are received
- private bool snapToBottom = true;
- // List of unique debug entries (duplicates of entries are not kept)
- private List<DebugLogEntry> collapsedLogEntries;
- // Dictionary to quickly find if a log already exists in collapsedLogEntries
- private Dictionary<DebugLogEntry, int> collapsedLogEntriesMap;
- // The order the collapsedLogEntries are received
- // (duplicate entries have the same index (value))
- private DebugLogIndexList uncollapsedLogEntriesIndices;
- // Filtered list of debug entries to show
- private DebugLogIndexList indicesOfListEntriesToShow;
- // Logs that should be registered in Update-loop
- private List<QueuedDebugLogEntry> queuedLogs;
- private List<DebugLogItem> pooledLogItems;
- // History of the previously entered commands
- private CircularBuffer<string> commandHistory;
- private int commandHistoryIndex = -1;
- // Required in ValidateScrollPosition() function
- private PointerEventData nullPointerEventData;
- #if !UNITY_EDITOR && UNITY_ANDROID
- private DebugLogLogcatListener logcatListener;
- #endif
- private void Awake()
- {
- // Only one instance of debug console is allowed
- if( instance == null )
- {
- instance = this;
- // If it is a singleton object, don't destroy it between scene changes
- if( singleton )
- DontDestroyOnLoad( gameObject );
- }
- else if( this != instance )
- {
- Destroy( gameObject );
- return;
- }
- pooledLogItems = new List<DebugLogItem>();
- queuedLogs = new List<QueuedDebugLogEntry>();
- commandHistory = new CircularBuffer<string>( commandHistorySize );
- canvasTR = (RectTransform) transform;
- // Associate sprites with log types
- logSpriteRepresentations = new Dictionary<LogType, Sprite>
- {
- { LogType.Log, infoLog },
- { LogType.Warning, warningLog },
- { LogType.Error, errorLog },
- { LogType.Exception, errorLog },
- { LogType.Assert, errorLog }
- };
- // Initially, all log types are visible
- filterInfoButton.color = filterButtonsSelectedColor;
- filterWarningButton.color = filterButtonsSelectedColor;
- filterErrorButton.color = filterButtonsSelectedColor;
- collapsedLogEntries = new List<DebugLogEntry>( 128 );
- collapsedLogEntriesMap = new Dictionary<DebugLogEntry, int>( 128 );
- uncollapsedLogEntriesIndices = new DebugLogIndexList();
- indicesOfListEntriesToShow = new DebugLogIndexList();
- recycledListView.Initialize( this, collapsedLogEntries, indicesOfListEntriesToShow, logItemPrefab.Transform.sizeDelta.y );
- recycledListView.UpdateItemsInTheList( true );
- if( minimumHeight < 200f )
- minimumHeight = 200f;
- nullPointerEventData = new PointerEventData( null );
- }
- private void OnEnable()
- {
- // Intercept debug entries
- Application.logMessageReceived -= ReceivedLog;
- Application.logMessageReceived += ReceivedLog;
- // Listen for entered commands
- commandInputField.onValidateInput -= OnValidateCommand;
- commandInputField.onValidateInput += OnValidateCommand;
- if( receiveLogcatLogsInAndroid )
- {
- #if !UNITY_EDITOR && UNITY_ANDROID
- if( logcatListener == null )
- logcatListener = new DebugLogLogcatListener();
- logcatListener.Start( logcatArguments );
- #endif
- }
- DebugLogConsole.AddCommandInstance( "save_logs", "Saves logs to a file", "SaveLogsToFile", this );
- //Debug.LogAssertion( "assert" );
- //Debug.LogError( "error" );
- //Debug.LogException( new System.IO.EndOfStreamException() );
- //Debug.LogWarning( "warning" );
- //Debug.Log( "log" );
- }
- private void OnDisable()
- {
- if( instance != this )
- return;
- // Stop receiving debug entries
- Application.logMessageReceived -= ReceivedLog;
- #if !UNITY_EDITOR && UNITY_ANDROID
- if( logcatListener != null )
- logcatListener.Stop();
- #endif
- // Stop receiving commands
- commandInputField.onValidateInput -= OnValidateCommand;
- DebugLogConsole.RemoveCommand( "save_logs" );
- }
- // Launch in popup mode
- private void Start()
- {
- if( enablePopup && startInPopupMode )
- ShowPopup();
- else
- {
- ShowLogWindow();
- popupManager.gameObject.SetActive( enablePopup );
- }
- }
- // Window is resized, update the list
- private void OnRectTransformDimensionsChange()
- {
- screenDimensionsChanged = true;
- }
- // If snapToBottom is enabled, force the scrollbar to the bottom
- private void LateUpdate()
- {
- int queuedLogCount = queuedLogs.Count;
- if( queuedLogCount > 0 )
- {
- for( int i = 0; i < queuedLogCount; i++ )
- {
- QueuedDebugLogEntry logEntry = queuedLogs[i];
- ReceivedLog( logEntry.logString, logEntry.stackTrace, logEntry.logType );
- }
- queuedLogs.Clear();
- }
- if( screenDimensionsChanged )
- {
- // Update the recycled list view
- if( isLogWindowVisible )
- recycledListView.OnViewportDimensionsChanged();
- else
- popupManager.OnViewportDimensionsChanged();
- screenDimensionsChanged = false;
- }
- if( snapToBottom )
- {
- logItemsScrollRect.verticalNormalizedPosition = 0f;
- if( snapToBottomButton.activeSelf )
- snapToBottomButton.SetActive( false );
- }
- else
- {
- float scrollPos = logItemsScrollRect.verticalNormalizedPosition;
- if( snapToBottomButton.activeSelf != ( scrollPos > 1E-6f && scrollPos < 0.9999f ) )
- snapToBottomButton.SetActive( !snapToBottomButton.activeSelf );
- }
- if( toggleWithKey )
- {
- if( Input.GetKeyDown( toggleKey ) )
- {
- if( isLogWindowVisible )
- ShowPopup();
- else
- ShowLogWindow();
- }
- }
- if( isLogWindowVisible && commandInputField.isFocused )
- {
- if( Input.GetKeyDown( KeyCode.UpArrow ) )
- {
- if( commandHistoryIndex == -1 )
- commandHistoryIndex = commandHistory.Count - 1;
- else if( --commandHistoryIndex < 0 )
- commandHistoryIndex = 0;
- if( commandHistoryIndex >= 0 && commandHistoryIndex < commandHistory.Count )
- {
- commandInputField.text = commandHistory[commandHistoryIndex];
- commandInputField.caretPosition = commandInputField.text.Length;
- }
- }
- else if( Input.GetKeyDown( KeyCode.DownArrow ) )
- {
- if( commandHistoryIndex == -1 )
- commandHistoryIndex = commandHistory.Count - 1;
- else if( ++commandHistoryIndex >= commandHistory.Count )
- commandHistoryIndex = commandHistory.Count - 1;
- if( commandHistoryIndex >= 0 && commandHistoryIndex < commandHistory.Count )
- commandInputField.text = commandHistory[commandHistoryIndex];
- }
- }
- #if !UNITY_EDITOR && UNITY_ANDROID
- if( logcatListener != null )
- {
- string log;
- while( ( log = logcatListener.GetLog() ) != null )
- ReceivedLog( "LOGCAT: " + log, string.Empty, LogType.Log );
- }
- #endif
- }
- public void ShowLogWindow()
- {
- // Show the log window
- logWindowCanvasGroup.interactable = true;
- logWindowCanvasGroup.blocksRaycasts = true;
- logWindowCanvasGroup.alpha = 1f;
- popupManager.Hide();
- // Update the recycled list view
- // (in case new entries were intercepted while log window was hidden)
- recycledListView.OnLogEntriesUpdated( true );
- isLogWindowVisible = true;
- }
- public void ShowPopup()
- {
- // Hide the log window
- logWindowCanvasGroup.interactable = false;
- logWindowCanvasGroup.blocksRaycasts = false;
- logWindowCanvasGroup.alpha = 0f;
- popupManager.Show();
- commandHistoryIndex = -1;
- isLogWindowVisible = false;
- }
- // Command field input is changed, check if command is submitted
- public char OnValidateCommand( string text, int charIndex, char addedChar )
- {
- if( addedChar == '\t' ) // Autocomplete attempt
- {
- if( !string.IsNullOrEmpty( text ) )
- {
- string autoCompletedCommand = DebugLogConsole.GetAutoCompleteCommand( text );
- if( !string.IsNullOrEmpty( autoCompletedCommand ) )
- commandInputField.text = autoCompletedCommand;
- }
- return '\0';
- }
- else if( addedChar == '\n' ) // Command is submitted
- {
- // Clear the command field
- if( clearCommandAfterExecution )
- commandInputField.text = "";
- if( text.Length > 0 )
- {
- if( commandHistory.Count == 0 || commandHistory[commandHistory.Count - 1] != text )
- commandHistory.Add( text );
- commandHistoryIndex = -1;
- // Execute the command
- DebugLogConsole.ExecuteCommand( text );
- // Snap to bottom and select the latest entry
- SetSnapToBottom( true );
- }
- return '\0';
- }
- return addedChar;
- }
- // A debug entry is received
- private void ReceivedLog( string logString, string stackTrace, LogType logType )
- {
- if( CanvasUpdateRegistry.IsRebuildingGraphics() || CanvasUpdateRegistry.IsRebuildingLayout() )
- {
- // Trying to update the UI while the canvas is being rebuilt will throw warnings in the Unity console
- queuedLogs.Add( new QueuedDebugLogEntry( logString, stackTrace, logType ) );
- return;
- }
- DebugLogEntry logEntry = new DebugLogEntry( logString, stackTrace, null );
- // Check if this entry is a duplicate (i.e. has been received before)
- int logEntryIndex;
- bool isEntryInCollapsedEntryList = collapsedLogEntriesMap.TryGetValue( logEntry, out logEntryIndex );
- if( !isEntryInCollapsedEntryList )
- {
- // It is not a duplicate,
- // add it to the list of unique debug entries
- logEntry.logTypeSpriteRepresentation = logSpriteRepresentations[logType];
- logEntryIndex = collapsedLogEntries.Count;
- collapsedLogEntries.Add( logEntry );
- collapsedLogEntriesMap[logEntry] = logEntryIndex;
- }
- else
- {
- // It is a duplicate,
- // increment the original debug item's collapsed count
- logEntry = collapsedLogEntries[logEntryIndex];
- logEntry.count++;
- }
- // Add the index of the unique debug entry to the list
- // that stores the order the debug entries are received
- uncollapsedLogEntriesIndices.Add( logEntryIndex );
- // If this debug entry matches the current filters,
- // add it to the list of debug entries to show
- Sprite logTypeSpriteRepresentation = logEntry.logTypeSpriteRepresentation;
- if( isCollapseOn && isEntryInCollapsedEntryList )
- {
- if( isLogWindowVisible )
- recycledListView.OnCollapsedLogEntryAtIndexUpdated( logEntryIndex );
- }
- else if( logFilter == DebugLogFilter.All ||
- ( logTypeSpriteRepresentation == infoLog && ( ( logFilter & DebugLogFilter.Info ) == DebugLogFilter.Info ) ) ||
- ( logTypeSpriteRepresentation == warningLog && ( ( logFilter & DebugLogFilter.Warning ) == DebugLogFilter.Warning ) ) ||
- ( logTypeSpriteRepresentation == errorLog && ( ( logFilter & DebugLogFilter.Error ) == DebugLogFilter.Error ) ) )
- {
- indicesOfListEntriesToShow.Add( logEntryIndex );
- if( isLogWindowVisible )
- recycledListView.OnLogEntriesUpdated( false );
- }
- if( logType == LogType.Log )
- {
- infoEntryCount++;
- infoEntryCountText.text = infoEntryCount.ToString();
- // If debug popup is visible, notify it of the new debug entry
- if( !isLogWindowVisible )
- popupManager.NewInfoLogArrived();
- }
- else if( logType == LogType.Warning )
- {
- warningEntryCount++;
- warningEntryCountText.text = warningEntryCount.ToString();
- // If debug popup is visible, notify it of the new debug entry
- if( !isLogWindowVisible )
- popupManager.NewWarningLogArrived();
- }
- else
- {
- errorEntryCount++;
- errorEntryCountText.text = errorEntryCount.ToString();
- // If debug popup is visible, notify it of the new debug entry
- if( !isLogWindowVisible )
- popupManager.NewErrorLogArrived();
- }
- }
- // Value of snapToBottom is changed (user scrolled the list manually)
- public void SetSnapToBottom( bool snapToBottom )
- {
- this.snapToBottom = snapToBottom;
- }
- // Make sure the scroll bar of the scroll rect is adjusted properly
- public void ValidateScrollPosition()
- {
- logItemsScrollRect.OnScroll( nullPointerEventData );
- }
- // Hide button is clicked
- public void HideButtonPressed()
- {
- ShowPopup();
- }
- // Clear button is clicked
- public void ClearButtonPressed()
- {
- snapToBottom = true;
- infoEntryCount = 0;
- warningEntryCount = 0;
- errorEntryCount = 0;
- infoEntryCountText.text = "0";
- warningEntryCountText.text = "0";
- errorEntryCountText.text = "0";
- collapsedLogEntries.Clear();
- collapsedLogEntriesMap.Clear();
- uncollapsedLogEntriesIndices.Clear();
- indicesOfListEntriesToShow.Clear();
- recycledListView.DeselectSelectedLogItem();
- recycledListView.OnLogEntriesUpdated( true );
- }
- // Collapse button is clicked
- public void CollapseButtonPressed()
- {
- // Swap the value of collapse mode
- isCollapseOn = !isCollapseOn;
- snapToBottom = true;
- collapseButton.color = isCollapseOn ? collapseButtonSelectedColor : collapseButtonNormalColor;
- recycledListView.SetCollapseMode( isCollapseOn );
- // Determine the new list of debug entries to show
- FilterLogs();
- }
- // Filtering mode of info logs has been changed
- public void FilterLogButtonPressed()
- {
- logFilter = logFilter ^ DebugLogFilter.Info;
- if( ( logFilter & DebugLogFilter.Info ) == DebugLogFilter.Info )
- filterInfoButton.color = filterButtonsSelectedColor;
- else
- filterInfoButton.color = filterButtonsNormalColor;
- FilterLogs();
- }
- // Filtering mode of warning logs has been changed
- public void FilterWarningButtonPressed()
- {
- logFilter = logFilter ^ DebugLogFilter.Warning;
- if( ( logFilter & DebugLogFilter.Warning ) == DebugLogFilter.Warning )
- filterWarningButton.color = filterButtonsSelectedColor;
- else
- filterWarningButton.color = filterButtonsNormalColor;
- FilterLogs();
- }
- // Filtering mode of error logs has been changed
- public void FilterErrorButtonPressed()
- {
- logFilter = logFilter ^ DebugLogFilter.Error;
- if( ( logFilter & DebugLogFilter.Error ) == DebugLogFilter.Error )
- filterErrorButton.color = filterButtonsSelectedColor;
- else
- filterErrorButton.color = filterButtonsNormalColor;
- FilterLogs();
- }
- // Debug window is being resized,
- // Set the sizeDelta property of the window accordingly while
- // preventing window dimensions from going below the minimum dimensions
- public void Resize( BaseEventData dat )
- {
- PointerEventData eventData = (PointerEventData) dat;
- // Grab the resize button from top; 36f is the height of the resize button
- float newHeight = ( eventData.position.y - logWindowTR.position.y ) / -canvasTR.localScale.y + 36f;
- if( newHeight < minimumHeight )
- newHeight = minimumHeight;
- Vector2 anchorMin = logWindowTR.anchorMin;
- anchorMin.y = Mathf.Max( 0f, 1f - newHeight / canvasTR.sizeDelta.y );
- logWindowTR.anchorMin = anchorMin;
- // Update the recycled list view
- recycledListView.OnViewportDimensionsChanged();
- }
- // Determine the filtered list of debug entries to show on screen
- private void FilterLogs()
- {
- if( logFilter == DebugLogFilter.None )
- {
- // Show no entry
- indicesOfListEntriesToShow.Clear();
- }
- else if( logFilter == DebugLogFilter.All )
- {
- if( isCollapseOn )
- {
- // All the unique debug entries will be listed just once.
- // So, list of debug entries to show is the same as the
- // order these unique debug entries are added to collapsedLogEntries
- indicesOfListEntriesToShow.Clear();
- for( int i = 0; i < collapsedLogEntries.Count; i++ )
- indicesOfListEntriesToShow.Add( i );
- }
- else
- {
- indicesOfListEntriesToShow.Clear();
- for( int i = 0; i < uncollapsedLogEntriesIndices.Count; i++ )
- indicesOfListEntriesToShow.Add( uncollapsedLogEntriesIndices[i] );
- }
- }
- else
- {
- // Show only the debug entries that match the current filter
- bool isInfoEnabled = ( logFilter & DebugLogFilter.Info ) == DebugLogFilter.Info;
- bool isWarningEnabled = ( logFilter & DebugLogFilter.Warning ) == DebugLogFilter.Warning;
- bool isErrorEnabled = ( logFilter & DebugLogFilter.Error ) == DebugLogFilter.Error;
- if( isCollapseOn )
- {
- indicesOfListEntriesToShow.Clear();
- for( int i = 0; i < collapsedLogEntries.Count; i++ )
- {
- DebugLogEntry logEntry = collapsedLogEntries[i];
- if( logEntry.logTypeSpriteRepresentation == infoLog && isInfoEnabled )
- indicesOfListEntriesToShow.Add( i );
- else if( logEntry.logTypeSpriteRepresentation == warningLog && isWarningEnabled )
- indicesOfListEntriesToShow.Add( i );
- else if( logEntry.logTypeSpriteRepresentation == errorLog && isErrorEnabled )
- indicesOfListEntriesToShow.Add( i );
- }
- }
- else
- {
- indicesOfListEntriesToShow.Clear();
- for( int i = 0; i < uncollapsedLogEntriesIndices.Count; i++ )
- {
- DebugLogEntry logEntry = collapsedLogEntries[uncollapsedLogEntriesIndices[i]];
- if( logEntry.logTypeSpriteRepresentation == infoLog && isInfoEnabled )
- indicesOfListEntriesToShow.Add( uncollapsedLogEntriesIndices[i] );
- else if( logEntry.logTypeSpriteRepresentation == warningLog && isWarningEnabled )
- indicesOfListEntriesToShow.Add( uncollapsedLogEntriesIndices[i] );
- else if( logEntry.logTypeSpriteRepresentation == errorLog && isErrorEnabled )
- indicesOfListEntriesToShow.Add( uncollapsedLogEntriesIndices[i] );
- }
- }
- }
- // Update the recycled list view
- recycledListView.DeselectSelectedLogItem();
- recycledListView.OnLogEntriesUpdated( true );
- ValidateScrollPosition();
- }
- public string GetAllLogs()
- {
- int count = uncollapsedLogEntriesIndices.Count;
- int length = 0;
- int newLineLength = System.Environment.NewLine.Length;
- for( int i = 0; i < count; i++ )
- {
- DebugLogEntry entry = collapsedLogEntries[uncollapsedLogEntriesIndices[i]];
- length += entry.logString.Length + entry.stackTrace.Length + newLineLength * 3;
- }
- length += 100; // Just in case...
- System.Text.StringBuilder sb = new System.Text.StringBuilder( length );
- for( int i = 0; i < count; i++ )
- {
- DebugLogEntry entry = collapsedLogEntries[uncollapsedLogEntriesIndices[i]];
- sb.AppendLine( entry.logString ).AppendLine( entry.stackTrace ).AppendLine();
- }
- return sb.ToString();
- }
- private void SaveLogsToFile()
- {
- string path = Path.Combine( Application.persistentDataPath, System.DateTime.Now.ToString( "dd-MM-yyyy--HH-mm-ss" ) + ".txt" );
- File.WriteAllText( path, instance.GetAllLogs() );
- Debug.Log( "Logs saved to: " + path );
- }
- // Pool an unused log item
- public void PoolLogItem( DebugLogItem logItem )
- {
- logItem.gameObject.SetActive( false );
- pooledLogItems.Add( logItem );
- }
- // Fetch a log item from the pool
- public DebugLogItem PopLogItem()
- {
- DebugLogItem newLogItem;
- // If pool is not empty, fetch a log item from the pool,
- // create a new log item otherwise
- if( pooledLogItems.Count > 0 )
- {
- newLogItem = pooledLogItems[pooledLogItems.Count - 1];
- pooledLogItems.RemoveAt( pooledLogItems.Count - 1 );
- newLogItem.gameObject.SetActive( true );
- }
- else
- {
- newLogItem = (DebugLogItem) Instantiate( logItemPrefab, logItemsContainer, false );
- newLogItem.Initialize( recycledListView );
- }
- return newLogItem;
- }
- }
- }
|