/**********************************************************************************************
* 添加控制台命令的规则:
* 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
}
后台日志管理,回调debug,方便打包后调试数据
最新推荐文章于 2024-06-30 19:29:46 发布