GUIConsole.cs 4.76 KB
Newer Older
cann-alberto's avatar
cann-alberto committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// People should be able to see and report errors to the developer very easily.
//
// Unity's Developer Console only works in development builds and it only shows
// errors. This class provides a console that works in all builds and also shows
// log and warnings in development builds.
//
// Note: we don't include the stack trace, because that can also be grabbed from
// the log files if needed.
//
// Note: there is no 'hide' button because we DO want people to see those errors
// and report them back to us.
//
// Note: normal Debug.Log messages can be shown by building in Debug/Development
//       mode.
using UnityEngine;
using System.Collections.Generic;

namespace Mirror
{
    struct LogEntry
    {
        public string message;
        public LogType type;

        public LogEntry(string message, LogType type)
        {
            this.message = message;
            this.type = type;
        }
    }

    public class GUIConsole : MonoBehaviour
    {
        public int height = 80;
        public int offsetY = 40;

        // only keep the recent 'n' entries. otherwise memory would grow forever
        // and drawing would get slower and slower.
        public int maxLogCount = 50;

        // Unity Editor has the Console window, we don't need to show it there.
        // unless for testing, so keep it as option.
        public bool showInEditor = false;

        // log as queue so we can remove the first entry easily
        readonly Queue<LogEntry> log = new Queue<LogEntry>();

        // hotkey to show/hide at runtime for easier debugging
        // (sometimes we need to temporarily hide/show it)
        // Default is BackQuote, because F keys are already assigned in browsers
        [Tooltip("Hotkey to show/hide the console at runtime\nBack Quote is usually on the left above Tab\nChange with caution - F keys are generally already taken in Browsers")]
        public KeyCode hotKey = KeyCode.BackQuote;

        // GUI
        bool visible;
        Vector2 scroll = Vector2.zero;

        // only show at runtime, or if showInEditor is enabled
        bool show => !Application.isEditor || showInEditor;

        void Awake()
        {
            // only show at runtime, or if showInEditor is enabled
            if (show)
                Application.logMessageReceived += OnLog;
        }

        // OnLog logs everything, even Debug.Log messages in release builds
        // => this makes a lot of things easier. e.g. addon initialization logs.
        // => it's really better to have than not to have those
        void OnLog(string message, string stackTrace, LogType type)
        {
            // is this important?
            // => always show exceptions & errors
            // => usually a good idea to show warnings too, otherwise it's too
            //    easy to miss OnDeserialize warnings etc. in builds
            bool isImportant = type == LogType.Error || type == LogType.Exception || type == LogType.Warning;

            // use stack trace only if important
            // (otherwise users would have to find and search the log file.
            //  seeing it in the console directly is way easier to deal with.)
            // => only add \n if stack trace is available (only in debug builds)
            if (isImportant && !string.IsNullOrWhiteSpace(stackTrace))
                message += $"\n{stackTrace}";

            // add to queue
            log.Enqueue(new LogEntry(message, type));

            // respect max entries
            if (log.Count > maxLogCount)
                log.Dequeue();

            // become visible if it was important
            // (no need to become visible for regular log. let the user decide.)
            if (isImportant)
                visible = true;

            // auto scroll
            scroll.y = float.MaxValue;
        }

        void Update()
        {
            if (show && Input.GetKeyDown(hotKey))
                visible = !visible;
        }

        void OnGUI()
        {
            if (!visible) return;

            // If this offset is changed, also change width in NetworkManagerHUD::OnGUI
            int offsetX = 300 + 20;

            GUILayout.BeginArea(new Rect(offsetX, offsetY, Screen.width - offsetX - 10, height));

            scroll = GUILayout.BeginScrollView(scroll, "Box", GUILayout.Width(Screen.width - offsetX - 10), GUILayout.Height(height));
            foreach (LogEntry entry in log)
            {
                if (entry.type == LogType.Error || entry.type == LogType.Exception)
                    GUI.color = Color.red;
                else if (entry.type == LogType.Warning)
                    GUI.color = Color.yellow;

                GUILayout.Label(entry.message);
                GUI.color = Color.white;
            }
            GUILayout.EndScrollView();

            GUILayout.EndArea();
        }
    }
}