daily pastebin goal
94%
SHARE
TWEET

Untitled

a guest Dec 7th, 2017 49 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. using System.Collections.Generic;
  2. using UnityEngine;
  3. using System.Reflection;
  4. using System.Collections;
  5.  
  6. namespace UTL {
  7.     /// <summary>
  8.     /// A console to display Unity's debug logs in-game.
  9.     /// </summary>
  10.     public class Console : MonoBehaviour
  11.     {
  12.         struct Log
  13.         {
  14.             public string message;
  15.             public string stackTrace;
  16.             public LogType type;
  17.         }
  18.  
  19.         /// <summary>
  20.         /// The hotkey to show and hide the console window.
  21.         /// </summary>
  22.         public KeyCode toggleKey = KeyCode.BackQuote;
  23.  
  24.  
  25.         /// <summary>
  26.         /// Dictionary used to enable and disable gameobjects via the toggleGameObject command
  27.         /// </summary>
  28.         Dictionary<string, GameObject> disableGODictionary = new Dictionary<string, GameObject>();
  29.  
  30.         public delegate void commandDelegate(Console console, string cmd);
  31.         Dictionary<string, commandDelegate> commands = new Dictionary<string, commandDelegate>() {
  32.             { "ls", cmdLogGameObjects},
  33.             {"exec", cmdExecuteGOMethod},
  34.             {"tog", cmdToggleGameObject},
  35.             {"help", cmdDisplayHelp}
  36.         };
  37.  
  38.         List<Log> logs = new List<Log>();
  39.         Vector2 scrollPosition;
  40.  
  41.         bool _allowToggleConsole = true;
  42.         bool show;
  43.         bool collapse;
  44.         const string commandInputStr = "commandInput";
  45.         string debugCmd = "";
  46.         List<string> prevCommands = new List<string>();
  47.         string prevCommand = "";
  48.  
  49.         // Visual elements:
  50.  
  51.         static readonly Dictionary<LogType, Color> logTypeColors = new Dictionary<LogType, Color>()
  52.         {
  53.             { LogType.Assert, Color.white },
  54.             { LogType.Error, Color.red },
  55.             { LogType.Exception, Color.red },
  56.             { LogType.Log, Color.white },
  57.             { LogType.Warning, Color.yellow },
  58.         };
  59.  
  60.         const int margin = 20;
  61.  
  62.         Rect windowRect = new Rect(margin, margin, Screen.width - (margin * 2), Screen.height - (margin * 2));
  63.         Rect titleBarRect = new Rect(0, 0, 10000, 20);
  64.         GUIContent clearLabel = new GUIContent("Clear", "Clear the contents of the console.");
  65.         GUIContent collapseLabel = new GUIContent("Collapse", "Hide repeated messages.");
  66.  
  67.         GUIContent commandLabel = new GUIContent("Command", "Execute debug command.");
  68.         void OnEnable ()
  69.         {
  70.             Application.RegisterLogCallback(HandleLog);
  71.         }
  72.  
  73.         void OnDisable ()
  74.         {
  75.             Application.RegisterLogCallback(null);
  76.         }
  77.  
  78.         void Update ()
  79.         {
  80.             // If toggleKey or at least four touches, open console
  81.             // But dont allow it to flicker fast bc thats annoying
  82.             if (_allowToggleConsole && (Input.GetKeyDown(toggleKey) || Input.touchCount >= 4)) {
  83.                 show = !show;
  84.                 _allowToggleConsole = false;
  85.                 StartCoroutine (allowToggleConsole());
  86.             }
  87.         }
  88.  
  89.         IEnumerator allowToggleConsole(){
  90.             yield return new WaitForSeconds (0.30f);
  91.             _allowToggleConsole = true;
  92.         }
  93.  
  94.         void OnGUI ()
  95.         {
  96.             if (!show) {
  97.                 return;
  98.             }
  99.  
  100.             windowRect = GUILayout.Window(123456, windowRect, ConsoleWindow, "Console");
  101.         }
  102.  
  103.         /// <summary>
  104.         /// A window that displayss the recorded logs.
  105.         /// </summary>
  106.         /// <param name="windowID">Window ID.</param>
  107.         void ConsoleWindow (int windowID)
  108.         {
  109.             scrollPosition = GUILayout.BeginScrollView(scrollPosition);
  110.  
  111.             // Iterate through the recorded logs.
  112.             for (int i = 0; i < logs.Count; i++) {
  113.                 var log = logs[i];
  114.  
  115.                 // Combine identical messages if collapse option is chosen.
  116.                 if (collapse) {
  117.                     var messageSameAsPrevious = i > 0 && log.message == logs[i - 1].message;
  118.  
  119.                     if (messageSameAsPrevious) {
  120.                         continue;
  121.                     }
  122.                 }
  123.  
  124.                 GUI.contentColor = logTypeColors[log.type];
  125.                 GUILayout.Label(log.message);
  126.             }
  127.  
  128.             GUILayout.EndScrollView();
  129.  
  130.             GUI.contentColor = Color.white;
  131.  
  132.              // Check return event before Unity Text because it use the KeyDown Event
  133.             bool pressedEnterInTextbox = false;
  134.             if (GUI.GetNameOfFocusedControl() == commandInputStr) {
  135.                 if (Event.current.type == EventType.KeyDown && (Event.current.keyCode == KeyCode.KeypadEnter || Event.current.keyCode == KeyCode.Return))
  136.                     pressedEnterInTextbox = true;
  137.             }
  138.  
  139.             if (GUI.GetNameOfFocusedControl() == commandInputStr) {
  140.                 if (Event.current.type == EventType.KeyDown && (Event.current.keyCode == KeyCode.UpArrow))
  141.                     // TODO - eventually iterate backwards through prevCommands
  142.                     debugCmd = prevCommand;
  143.             }
  144.  
  145.             GUILayout.BeginHorizontal();
  146.             string prevString = debugCmd;
  147.             GUI.SetNextControlName(commandInputStr);
  148.             debugCmd = GUILayout.TextField(debugCmd);
  149.             if(pressedEnterInTextbox || GUILayout.Button(commandLabel, GUILayout.ExpandWidth(false))){
  150.                 executeDebugCommand(debugCmd);
  151.  
  152.                 // Empty string and save command so we don't have to retype it hopefully
  153.                 prevCommand = debugCmd;
  154.                 debugCmd = "";
  155.             }
  156.  
  157.             GUILayout.EndHorizontal();
  158.  
  159.             GUILayout.BeginHorizontal();
  160.  
  161.             if (GUILayout.Button(clearLabel)) {
  162.                 logs.Clear();
  163.             }
  164.  
  165.             collapse = GUILayout.Toggle(collapse, collapseLabel, GUILayout.ExpandWidth(false));
  166.  
  167.             GUILayout.EndHorizontal();
  168.  
  169.             // Allow the window to be dragged by its title bar.
  170.             GUI.DragWindow(titleBarRect);
  171.         }
  172.  
  173.         /// <summary>
  174.         /// Records a log from the log callback.
  175.         /// </summary>
  176.         /// <param name="message">Message.</param>
  177.         /// <param name="stackTrace">Trace of where the message came from.</param>
  178.         /// <param name="type">Type of message (error, exception, warning, assert).</param>
  179.         void HandleLog (string message, string stackTrace, LogType type)
  180.         {
  181.             logs.Add(new Log() {
  182.                 message = message,
  183.                 stackTrace = stackTrace,
  184.                 type = type,
  185.             });
  186.  
  187.            
  188.         }
  189.  
  190.         /// <summary>
  191.         /// Shows the console.
  192.         /// </summary>
  193.         /// <param name="enable">If set to <c>true</c> to show the console.</param>
  194.         public void showConsole(bool enable){
  195.             show = enable;
  196.         }
  197.  
  198.         /// <summary>
  199.         /// Displays available commands
  200.         /// </summary>
  201.         /// <param name="console">Console.</param>
  202.         /// <param name="args">Arguments.</param>
  203.         public static void cmdDisplayHelp(Console console, string args) {
  204.            
  205.             print ("Commands available");
  206.             foreach (var cmdPair in console.commands) {
  207.                 print (" - " + cmdPair.Key);
  208.             }
  209.         }
  210.        
  211.         public void executeDebugCommand(string cmd){
  212.  
  213.             string callCmd = cmd.Split(' ')[0];
  214.  
  215.             if (commands.ContainsKey(callCmd)) {
  216.                 // Call command with argument string
  217.                 var args = cmd.Replace(callCmd, "");
  218.                 commands[callCmd](this, cmd.Replace(callCmd + " ", ""));
  219.             } else {
  220.                 Debug.Log("No command found matching=" + callCmd);
  221.             }
  222.         }
  223.  
  224.         private static void cmdExecuteGOMethod(Console console, string args) {
  225.             var pargs = args.Split(' ');
  226.             // Need gameobject name, component name, function name, and remaining args are string?? or something?? not sure how I could get this
  227.             // to work with any type...
  228.             string forceStringValue = "str";
  229.  
  230.             if (pargs.Length >= 3){
  231.                 var goName = pargs[0];
  232.                 var compName = pargs [1];
  233.                 var funcName = pargs[2];
  234.  
  235.                 // See if gameobject exists in scene
  236.                 var go = GameObject.Find(goName);
  237.                 if (go != null) {
  238.  
  239.                     // See if component exists on gameobject
  240.                     var comp = go.GetComponent (compName);
  241.                     if (comp != null) {
  242.  
  243.                         // See if method exists in class definition of component
  244.                         if (HasMethod (comp, funcName)) {
  245.  
  246.                             // See if optional argument to supply to command has been provided
  247.                             if (pargs.Length >= 4) {
  248.                                 var argIn = pargs [3];
  249.  
  250.                                 // Check if we want to pass as string or parse out values
  251.                                 if (argIn != forceStringValue) {
  252.                                     int n;
  253.                                     float f;
  254.                                     bool b;
  255.                                     bool isInt = int.TryParse (argIn, out n);
  256.                                     bool isFloat = float.TryParse (argIn, out f);
  257.                                     bool isBool = bool.TryParse (argIn, out b);
  258.  
  259.                                     if (isInt) {
  260.                                         comp.SendMessage (funcName, n, SendMessageOptions.DontRequireReceiver);
  261.                                     } else if (isFloat) {
  262.                                         comp.SendMessage (funcName, f, SendMessageOptions.DontRequireReceiver);
  263.                                     } else if (isBool) {
  264.                                         comp.SendMessage (funcName, b, SendMessageOptions.DontRequireReceiver);
  265.                                     } else {
  266.                                         comp.SendMessage (funcName, argIn.ToString (), SendMessageOptions.DontRequireReceiver);
  267.                                     }
  268.                                     Debug.LogFormat ("Calling {0}::{1}.{2}({3})",
  269.                                         goName,
  270.                                         compName,
  271.                                         funcName,
  272.                                         argIn);
  273.                                 } else {
  274.                                     var argInStr = pargs [4];
  275.                                     comp.SendMessage (funcName, argInStr.ToString (), SendMessageOptions.DontRequireReceiver);
  276.                                     Debug.LogFormat ("Calling {0}::{1}.{2}({3})",
  277.                                         goName,
  278.                                         compName,
  279.                                         funcName,
  280.                                         argInStr);
  281.                                 }
  282.                             } else {
  283.                                 comp.SendMessage (funcName, SendMessageOptions.DontRequireReceiver);
  284.                                 Debug.LogFormat ("Calling {0}::{1}.{2}()",
  285.                                     goName,
  286.                                     compName,
  287.                                     funcName);
  288.                             }
  289.                         } else {
  290.                             Debug.LogFormat ("No function {0} found in component {1}", funcName, compName);
  291.                         }
  292.                     } else {
  293.                         Debug.LogFormat ("No component {0} found on gameobject {1}", compName, goName);
  294.                     }
  295.                 } else {
  296.                     Debug.LogFormat ("No gameobject found with name {0}", goName);
  297.                 }
  298.             }
  299.            
  300.         }
  301.         private static void cmdLogGameObjects(Console console, string args) {
  302.             var objs = UnityEngine.Object.FindObjectsOfType<GameObject>();
  303.             foreach (var go in objs) {
  304.                 if (go != null){
  305.                     var goPath = GetGameObjectPath (go.transform);
  306.                     bool logDebugPath = args == "" || goPath.Contains (args);
  307.                     if (logDebugPath) {
  308.                         Debug.Log (goPath);
  309.                     }
  310.                 }
  311.             }
  312.             Debug.Log("\n");
  313.         }
  314.  
  315.         private static void cmdToggleGameObject(Console console, string args) {
  316.             var pargs = args.Split(' ');
  317.             var goName = pargs [0];
  318.  
  319.             if (!string.IsNullOrEmpty (goName)) {
  320.  
  321.                 if (console.disableGODictionary.ContainsKey(goName)) {
  322.                     console.disableGODictionary [goName].SetActive (true);
  323.                     console.disableGODictionary.Remove (goName);
  324.                     return;
  325.                 }
  326.  
  327.                 // Try and find the gameobject
  328.                 var go = GameObject.Find(goName);
  329.                 if (go != null) {
  330.                     console.disableGODictionary.Add (goName, go);
  331.                     go.SetActive (false);
  332.                     return;
  333.                 } else {
  334.                     Debug.Log ("Could not find gameobject " + goName);
  335.                 }
  336.             }
  337.         }
  338.  
  339.         // Helper methods for Commands
  340.  
  341.         private static string GetGameObjectPath(Transform transform)
  342.         {
  343.             string path = transform.name;
  344.             while (transform.parent != null)
  345.             {
  346.                 transform = transform.parent;
  347.                 path = transform.name + "/" + path;
  348.             }
  349.             return path;
  350.         }
  351.  
  352.         public static bool HasMethod(object objectToCheck, string methodName)
  353.         {
  354.             try
  355.             {
  356.                 var type = objectToCheck.GetType();
  357.                 return type.GetMethod(methodName) != null;
  358.             }
  359.             catch(AmbiguousMatchException)
  360.             {
  361.                 // ambiguous means there is more than one result,
  362.                 // which means: a method with that name does exist
  363.                 return true;
  364.             }
  365.         }
  366.     }
  367. }
RAW Paste Data
Top