后台日志管理,回调debug,方便打包后调试数据

/**********************************************************************************************
 * 添加控制台命令的规则:
 * 1.在AddCmd方法中 使用cmds.ADD()方法新建一个Cmd类的实例
 * 2.根据有/无窗口的需求选择Cmd合适的构造参数 Cmd类的构造参数详情 请查阅Cmd类注释
 * 3.创建控制台的无参数调用方法 方法名需要与Cmd类构造器参数的GUIContent . text 名称一致
 * 4.创建控制台的调用方法的有参数重载 也就是控制台按钮的回调方法
 * 5.在有必要的情况下 创建控制台的小窗口回调方法 要使该方法有效 需要在第二步 选择Cmd类的重载构造
 * 快速获取Cmd类的实例:cmds[窗口id - AutoWindowStartId] 或者cmds[自己数下第几个添加的]
 **********************************************************************************************/

using System;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// 1.管理员身份验证(本地或网络)
/// 2.指令输入
/// 3.log信息管理与显示
/// 4.异常处理
/// 5.必要日志上传
/// </summary>
public class DeBugCommand : MonoBehaviour
{
    /// <summary> </summary>
    /// 
    public string CmdLoginAccount= "admin";
    public string CmdLoginPassword= "password";

    /// <summary>
    /// 日志信息结构
    /// </summary>
    struct Log
    {
        public string message;
        public string stackTrace;
        public LogType type;
    }

    /// <summary>
    /// 指令类
    /// </summary>
    class Cmd
    {
        public GUIContent CmdGUIContent;
        public Color color;
        public Action<GUIContent, int> BtnFunction;

        private bool WindowShow;
        public int WindowId;
        public Rect WindowRect;
        private Rect WindowStartRect;
        public Rect WindowTitle;
        public GUI.WindowFunction WindowFunction;

        public bool GetWindowShow() { return WindowShow; }
        public bool SetWindowShow(bool _WindowShow) { WindowShow = _WindowShow; if (false == WindowShow && WindowStartRect != null) { WindowRect = WindowStartRect; } return WindowShow; }

        /// <summary>
        /// 无参数构造器
        /// </summary>
        private Cmd() { }

        /// <summary>
        /// 构造器重载
        /// </summary>
        /// <param name="_CmdName">Gui元素的内容 参数一指令名称 参数二指令说明</param>
        /// <param name="_Color">按钮文字的颜色</param>
        /// <param name="_BtnFunction">回调并创建按钮的方法</param>
        public Cmd(GUIContent _CmdName, Color _Color, Action<GUIContent, int> _BtnFunction)
        {
            CmdGUIContent = _CmdName;
            color = _Color;
            BtnFunction = _BtnFunction;
            WindowShow = false;
        }

        /// <summary>
        /// 构造器重载
        /// </summary>
        /// <param name="_CmdName">Gui元素的内容 参数一指令名称 参数二指令说明</param>
        /// <param name="_Color">按钮文字的颜色</param>
        /// <param name="_BtnFunction">回调并创建按钮的方法</param>
        /// <param name="_WindowRect">创建窗口的位置与大小</param>
        /// <param name="_WindowFunction">窗口的回调方法</param>
        public Cmd(GUIContent _CmdName, Color _Color, Action<GUIContent, int> _BtnFunction, Rect _WindowRect, GUI.WindowFunction _WindowFunction)
        {
            WindowShow = false;
            CmdGUIContent = _CmdName;
            color = _Color;
            BtnFunction = _BtnFunction;
            WindowRect = _WindowRect;
            WindowStartRect = WindowRect;
            WindowTitle = new Rect(0, 0, _WindowRect.width, 30);
            WindowFunction = _WindowFunction;
            WindowShow = false;
        }
    }

    #region Inspector Settings

    /// <summary>
    /// 显示和隐藏控制台窗口的热键。
    /// </summary>
    public KeyCode toggleKey = KeyCode.BackQuote;

    /// <summary>
    /// 是否通过摇动设备来打开窗口(仅限移动设备)。
    /// </summary>
    public bool shakeToOpen = true;

    /// <summary>
    /// 窗口应打开的(平方)加速度。
    /// </summary>
    public float shakeAcceleration = 3f;

    /// <summary>
    ///是否仅保留一定数量的日志。/n
    ///
    ///如果担心内存使用情况,则设置此选项将很有帮助。
    /// </summary>
    public bool restrictLogCount = false;

    /// <summary>
    /// 删除旧日志之前要保留的日志数。
    /// </summary>
    public int maxLogs = 1000;

    /// <summary>Debug界面显示/隐藏 </summary>
    public bool DebugShow = false;

    #endregion

    #region Inspector Statement




    bool ConsoleVisible = false;

    /// <summary>窗口边幅 </summary>
    const int margin = 20;

    const int AutoWindowStartId = 1000;


    /// <summary>日志信息的视觉元素 颜色定义: </summary>
    static readonly Dictionary<LogType, Color> logTypeColors = new Dictionary<LogType, Color>
        {
            { LogType.Assert, Color.white },
            { LogType.Error, Color.red },
            { LogType.Exception, Color.red },
            { LogType.Log, Color.white },
            { LogType.Warning, Color.yellow },
        };


    //登录窗口声明
    #region Inspector LoginWindow 

    bool LoginBoxShow = true;
    private string LoginAccountString = "";
    private string LoginPasswordString = "";
    private string LoginMessage = "";
    private readonly string LoginStart = "请输入管理员账号/密码。";
    private readonly string LoginError = "账号或密码错误,请重新输入。";

    static readonly GUIContent O_LoginWin = new GUIContent("管理员验证", "验证是否为系统管理员以打开控制台.");
    static readonly GUIContent O_LoginBtn = new GUIContent("登录", "用以验证是否为系统管理员.");



    Rect LoginWindowRect = new Rect(Screen.width / 2 - 100, Screen.height / 2 - 100, 200, 200);
    readonly Rect LoginTitleBarRect = new Rect(0, 0, 200, 20);


    #endregion

    //日志窗口声明
    #region Inspector LogsWindow

    /// <summary>日志链表 </summary>
    readonly List<Log> logs = new List<Log>();

    /// <summary>自动布局滚动视图的位置 </summary>
    Vector2 LogsScrollPosition;

    /// <summary>是否折叠 合并相同的信息 </summary>
    bool collapse;

    const string LogsWindowTitle = "Logs";


    static readonly GUIContent clearLabel = new GUIContent("清除", "清楚控制台内容.");
    static readonly GUIContent ExitLoginLabel = new GUIContent("退出登录", "退出管理员账户登录状态与控制台模式.");
    static readonly GUIContent collapseLabel = new GUIContent("折叠", "显示/隐藏折叠的重复内容.");

    readonly Rect LogsTitleBarRect = new Rect(0, 0, Screen.width * 0.7f - margin, margin);
    Rect LogsWindowRect = new Rect(margin, margin, Screen.width * 0.7f - margin, Screen.height - margin);

    #endregion

    //控制台窗口声明
    #region Inspector ConsoleWindow

    /// <summary>日志链表 </summary>
    readonly List<Cmd> cmds = new List<Cmd>();

    const string ConsoleWindowTitle = "Console";

    /// <summary>自动布局滚动视图的位置 </summary>
    Vector2 ConsoleScrollPosition;

    /// <summary>键盘的输入信息 </summary>
    private string ConsoleCmdString = "";


    static readonly GUIContent cmdRun = new GUIContent("运行", "执行指令.");

    readonly Rect ConsoleTitleBarRect = new Rect(0, 0, Screen.width * 0.3f - margin, margin);
    Rect ConsoleWindowRect = new Rect(Screen.width * 0.7f, margin, Screen.width * 0.3f - margin, Screen.height - margin);

    #endregion
    #endregion

    private void Awake()
    {
        DebugShow = false;
        ConsoleVisible = false;
        LoginBoxShow = true;
        LoginMessage = LoginStart;
        AddCmd();

    }

    void OnEnable()
    {
        UnityEngine.Application.logMessageReceived += HandleLog;
    }

    void OnDisable()
    {
        UnityEngine.Application.logMessageReceived -= HandleLog;
    }

    void Update()
    {
#if UNITY_EDITOR || Yangruihao
        if (Input.GetKeyDown(toggleKey))
        {
            DebugShow = !DebugShow;
        }

        if (shakeToOpen && Input.acceleration.sqrMagnitude > shakeAcceleration)
        {
            DebugShow = true;
        }
#endif
    }

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

        if (LoginBoxShow)
        {
            LoginWindowRect = GUILayout.Window(1, LoginWindowRect, LgoinWindow, O_LoginWin);
        }


        if (ConsoleVisible)
        {
            LogsWindowRect = GUILayout.Window(2, LogsWindowRect, LogsWindow, LogsWindowTitle);

            ConsoleWindowRect = GUILayout.Window(3, ConsoleWindowRect, ConsoleWindow, ConsoleWindowTitle);

            // 遍历记录的日志。
            for (var i = 0; i < cmds.Count; i++)
            {
                var cmd = cmds[i];

                if (cmd.GetWindowShow())
                {
                    cmd.WindowId = AutoWindowStartId + i;
                    cmd.WindowRect = GUILayout.Window(cmd.WindowId, cmd.WindowRect, cmd.WindowFunction, cmd.CmdGUIContent);
                }
            }


        }


    }


    /// <summary>
    /// 管理员验证
    /// </summary>
    /// <param name="windowID">Window ID.</param>
    void LgoinWindow(int windowID)
    {
        GUILayout.BeginVertical();

        if (LoginMessage == LoginError)
        {
            GUI.contentColor = Color.red;
        }
        else
        {
            GUI.contentColor = Color.white;
        }

        GUILayout.Label(LoginMessage);

        GUI.contentColor = Color.white;
        LoginAccountString = GUILayout.TextField(LoginAccountString);
        LoginPasswordString = GUILayout.PasswordField(LoginPasswordString, '*', 16);


        if (GUILayout.Button(O_LoginBtn))
        {
            if (CmdLoginAccount == LoginAccountString && CmdLoginPassword == LoginPasswordString)
            {
                LoginAccountString = "";
                LoginPasswordString = "";

                LoginBoxShow = false;
                ConsoleVisible = true;
                LoginMessage = LoginStart;

            }
            else
            {
                LoginAccountString = "";
                LoginPasswordString = "";
                LoginMessage = LoginError;

            }
        }

        GUILayout.EndVertical();

        //允许窗口被其标题栏拖动。
        GUI.DragWindow(LoginTitleBarRect);
    }

    /// <summary>
    /// 显示 列出log信息 (窗口回调)
    /// </summary>
    /// <param name="windowID">Window ID.</param>
    void LogsWindow(int windowID)
    {
        DrawLogsList();
        DrawToolbar();

        //允许窗口被其标题栏拖动。
        GUI.DragWindow(LogsTitleBarRect);
    }

    /// <summary>
    /// 显示日志的滚动列表。
    /// </summary>
    void DrawLogsList()
    {
        //开始自动布局滚动视图
        LogsScrollPosition = GUILayout.BeginScrollView(LogsScrollPosition);

        // 遍历记录的日志。
        for (var i = 0; i < logs.Count; i++)
        {
            var log = logs[i];

            // 如果选择了折叠选项,则合并相同的消息。
            if (collapse && i > 0)
            {
                var previousMessage = logs[i - 1].message;

                if (log.message == previousMessage)
                {
                    continue;
                }
            }

            GUI.contentColor = logTypeColors[log.type];
            GUILayout.Label(log.message);
        }

        GUILayout.EndScrollView();

        // 在绘制其他组件之前,请确保已重置GUI颜色。
        GUI.contentColor = Color.white;
    }

    /// <summary>
    /// 显示用于过滤和更改日志列表的选项。
    /// </summary>
    void DrawToolbar()
    {
        GUILayout.BeginHorizontal();

        if (GUILayout.Button(ExitLoginLabel))
        {
            ConsoleVisible = false;
            LoginBoxShow = true;
            DebugShow = false;
        }


        if (GUILayout.Button(clearLabel))
        {
            logs.Clear();
        }


        collapse = GUILayout.Toggle(collapse, collapseLabel, GUILayout.ExpandWidth(false));

        GUILayout.EndHorizontal();
    }

    /// <summary>
    /// 控制台窗口
    /// </summary>
    /// <param name="windowID">Window ID.</param>
    void ConsoleWindow(int windowID)
    {
        //开始自动布局滚动视图
        LogsScrollPosition = GUILayout.BeginScrollView(LogsScrollPosition);

        // 遍历记录的日志。
        for (var i = 0; i < cmds.Count; i++)
        {
            var cmd = cmds[i];

            GUI.contentColor = cmd.color;
            cmd.WindowId = AutoWindowStartId + i;
            cmd.BtnFunction(cmd.CmdGUIContent, cmd.WindowId);
        }


        GUILayout.EndScrollView();

        GUI.contentColor = Color.white;

        //开始水平自动布局
        GUILayout.BeginHorizontal();

        ConsoleCmdString = GUILayout.TextField(ConsoleCmdString);

        if (GUILayout.Button(cmdRun))
        {
            Invoke(ConsoleCmdString, 0);
            ConsoleCmdString = "";
        }

        GUILayout.EndHorizontal();

        GUI.DragWindow(ConsoleTitleBarRect);
    }

    /// <summary>
    /// 记录来自日志回调的日志。
    /// </summary>
    /// <param name="message">Message.</param>
    /// <param name="stackTrace">跟踪消息的来源。</param>
    /// <param name="type">Type of message (error, exception, warning, assert).</param>
    void HandleLog(string message, string stackTrace, LogType type)
    {
        logs.Add(new Log
        {
            message = message,
            stackTrace = stackTrace,
            type = type,
        });

        TrimExcessLogs();
    }

    /// <summary>
    /// 删除超过允许的最大数量的旧日志。
    /// </summary>
    void TrimExcessLogs()
    {
        if (!restrictLogCount)
        {
            return;
        }

        var amountToRemove = Mathf.Max(logs.Count - maxLogs, 0);

        if (amountToRemove == 0)
        {
            return;
        }

        logs.RemoveRange(0, amountToRemove);
    }

    /* *控制台命令的添加处 */
    #region command 


    /// <summary>
    /// 添加控制台命令
    /// </summary>
    void AddCmd()
    {
        cmds.Add(new Cmd(new GUIContent("CmdTest", "游戏测试."), Color.white, CmdTest));
        cmds.Add(new Cmd(new GUIContent("CmdTest_2", "游戏测试2."), Color.red, CmdTest_2,
                 new Rect(Screen.width / 2 - 100, Screen.height / 2 - 100, 200, 200), CmdTestWindow));
    }

    /// <summary>
    /// 控制台的无参数调用方法 
    /// 方法名需要与Cmd类构造器参数的GUIContent . text 名称一致
    /// </summary>
    #region CommandFuc

    public void CmdTest()
    {
        print("游戏测试任务001");

    }

    public void CmdTest_2()
    {

        print("游戏测试任务002");

        cmds[1].SetWindowShow(!cmds[1].GetWindowShow());

    }

    #endregion

    /// <summary>
    /// 控制台按钮回调方法
    /// </summary>
    /// <param name="content">GUI元素的内容。</param>
    /// <param name="winID">回调窗口的id</param>
    #region CommandBtn 
    public void CmdTest(GUIContent content, int winID)
    {

        if (GUILayout.Button(content))
        {
            print("游戏测试任务001");
        }

    }

    public void CmdTest_2(GUIContent content, int winID)
    {
        if (GUILayout.Button(content))
        {
            print("游戏测试任务002");

            cmds[winID - AutoWindowStartId].SetWindowShow(!cmds[winID - AutoWindowStartId].GetWindowShow());
        }
    }

    #endregion


    /// <summary>
    /// 控制台小窗口的回调方法
    /// </summary>
    /// <param name="id">窗口的id</param>
    #region CommandWindow 

    public void CmdTestWindow(int id)
    {
        GUILayout.Label("窗口测试。");

        if (GUILayout.Button("关闭窗口"))
        {
            cmds[id - AutoWindowStartId].SetWindowShow(false);
        }

        //允许窗口被其标题栏拖动。
        GUI.DragWindow(cmds[id - AutoWindowStartId].WindowTitle);
    }



    #endregion
    #endregion


}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值