VR Development Framework
v 1.0.0
 All Classes Namespaces Functions Variables Enumerations Enumerator Properties Events Pages
AVR_DevConsole.cs
1 using System.Collections;
2 using System.Collections.Generic;
3 using UnityEngine;
4 using System.Linq;
5 #if UNITY_EDITOR
6 using UnityEditor;
7 #endif
8 
9 using AVR;
10 
11 namespace AVR.Core {
12  /// <summary>
13  /// Class for the arc-vr developer's console. Functions as a singleton with only static members. Multiple independent consoles per scene/instance is not possible.
14  /// </summary>
15  [ExecuteInEditMode]
16  [AVR.Core.Attributes.DocumentationUrl("class_a_v_r_1_1_core_1_1_a_v_r___dev_console.html")]
17  public class AVR_DevConsole
18  {
19  private static string output_s;
20 
21  private static List<string> output_history = new List<string>();
22 
23  private static List<string> command_history = new List<string>();
24  private static int command_history_limit = 10;
25  private static List<AVR_ConsoleCommand> commands = new List<AVR_ConsoleCommand>();
26 
27  private static bool initialized = false;
28 
29  private static int repeat_counter = 1;
30 
31  public static event System.Action<string> OnPrint = delegate { };
32  public static event System.Action<string> OnCommand = delegate { };
33 
34  /// <summary> Initializes the DevConsole. Only the first execution will have an effect. </summary>
35  #if UNITY_EDITOR
36  [InitializeOnLoadMethod]
37  #endif
38  [RuntimeInitializeOnLoadMethod]
39  public static void init() {
40  if(initialized) return;
41  if(AVR_Settings.get_bool("/settings/core/devConsole/relayLogMessages")) {
42  Application.logMessageReceived += HandleLog;
43  }
44  if (AVR_Settings.get_bool("/settings/core/devConsole/useConsoleCommandAttribute")) {
45  register_all_attribute_commands();
46  }
47  initialized = true;
48  }
49 
50  /// <summary> Executes a respective output based on logString, stackTrace and LogType. </summary>
51  public static void HandleLog(string logString, string stackTrace, LogType type) {
52  switch(type) {
53  case LogType.Log : { cprint(logString, "Debug.Log"); break; }
54  case LogType.Warning: { cwarn(logString, "Debug.Log"); break; }
55  case LogType.Error: { cerror(logString, stackTrace); break; }
56  case LogType.Exception: { cerror(logString, stackTrace); break; }
57  default : { cprint(logString, "Debug.Log"); break; }
58  }
59  }
60 
61  /// <summary>
62  /// Get the complete output of this console as text.
63  /// </summary>
64  public static string get_text() {
65  return output_s + (repeat_counter > 1 ? " [x"+repeat_counter+"]" : "");
66  }
67 
68  /// <summary> Clear console output entirely. </summary>
69  public static void clear() {
70  output_s = "";
71  }
72 
73  /// <summary> Print with a caller-context variable. </summary>
74  public static void cprint(string s, MonoBehaviour obj)
75  {
76  print(obj.name + "::" + obj.GetType().ToString() + ">> " + s);
77  }
78 
79  /// <summary> Print with a caller-context variable. </summary>
80  public static void cprint(string s, GameObject obj)
81  {
82  print(obj.name + ">> " + s);
83  }
84 
85  /// <summary> Print with a caller-context variable. </summary>
86  public static void cprint(string s, string obj)
87  {
88  print(obj + ">> " + s);
89  }
90 
91  /// <summary> Print success message with a caller-context variable. </summary>
92  public static void csuccess(string s, MonoBehaviour obj)
93  {
94  success(obj.name + "::" + obj.GetType().ToString() + ">> " + s);
95  }
96 
97  /// <summary> Print success message with a caller-context variable. </summary>
98  public static void csuccess(string s, GameObject obj) {
99  success(obj.name + ">> " + s);
100  }
101 
102  /// <summary> Print success message with a caller-context variable. </summary>
103  public static void csuccess(string s, string obj)
104  {
105  success(obj + ">> " + s);
106  }
107 
108  /// <summary> Print warning message with a caller-context variable. </summary>
109  public static void cwarn(string s, MonoBehaviour obj)
110  {
111  warn(obj.name + "::" + obj.GetType().ToString() + ">> " + s);
112  }
113 
114  /// <summary> Print warning message with a caller-context variable. </summary>
115  public static void cwarn(string s, GameObject obj)
116  {
117  warn(obj.name + ">> " + s);
118  }
119 
120  /// <summary> Print warning message with a caller-context variable. </summary>
121  public static void cwarn(string s, string obj)
122  {
123  warn(obj + ">> " + s);
124  }
125 
126  /// <summary> Print error message with a caller-context variable. </summary>
127  public static void cerror(string s, MonoBehaviour obj)
128  {
129  error(obj.name + "::" + obj.GetType().ToString() + ">> " + s);
130  }
131 
132  /// <summary> Print error message with a caller-context variable. </summary>
133  public static void cerror(string s, GameObject obj)
134  {
135  error(obj.name + ">> " + s);
136  }
137 
138  /// <summary> Print error message with a caller-context variable. </summary>
139  public static void cerror(string s, string obj)
140  {
141  error(obj + ">> " + s);
142  }
143 
144  public static void raw_print(string s) {
145  // Avoid duplicate outputs
146  if(output_history.Count>0 && s==output_history.Last()) {
147  repeat_counter++;
148  return;
149  }
150  else {
151  if(repeat_counter>1) output_s += " [x"+repeat_counter+"]";
152  repeat_counter = 1;
153  }
154 
155  output_history.Add(s);
156  output_s += s;
157 
158  OnPrint.Invoke(s);
159  }
160 
161  /// <summary>
162  /// Print a given string on the console.
163  /// </summary>
164  public static void print(string s)
165  {
166  raw_print("\n# " + s);
167  }
168 
169  /// <summary>
170  /// Print a success message string on the console.
171  /// </summary>
172  public static void success(string s)
173  {
174  raw_print("\n# <color=green><b>" + s + "</b></color>");
175  }
176 
177  /// <summary>
178  /// Print a given error string on the console.
179  /// </summary>
180  public static void error(string s)
181  {
182  raw_print("\n! <color=red><b>ERR:</b> " + s + "</color>");
183  }
184 
185  /// <summary>
186  /// Print a given warning string on the console.
187  /// </summary>
188  public static void warn(string s)
189  {
190  raw_print("\n! <color=yellow><b>WRN:</b> " + s + "</color>");
191  }
192 
193  private static void echo_command(string s)
194  {
195  raw_print("\n> <color=grey> " + s + "</color>");
196  }
197 
198  /// <summary>
199  /// Returns any command executed in the past.
200  /// <param name="t"> Index of the past command with t=0 being the most recent one. </param>
201  /// </summary>
202  public static string history(int t) {
203  if(command_history.Count<1) return "";
204  t = Mathf.Clamp(t, 0, command_history.Count-1);
205  return command_history[t];
206  }
207 
208  /// <summary>
209  /// Execute a given console command.
210  /// </summary>
211  public static void command(string s, bool addToHistory=true) {
212  if(addToHistory) {
213  command_history.Insert(0, s);
214  while(command_history.Count>command_history_limit) command_history.RemoveAt(0);
215  echo_command(s);
216  }
217 
218  s = s.Trim();
219 
220  string[] c = s.Split(' ');
221 
222  // Find the "best fit" - meaning the command whose min_args best fit the amount of given args
223  List<AVR_ConsoleCommand> cmds = commands.Where((cmd) => cmd.name == c[0]).ToList();
224  AVR_ConsoleCommand cmd = cmds.Where((cmd) => cmd.min_args <= c.Length - 1).OrderBy((cmd) => -cmd.min_args).FirstOrDefault();
225 
226  if(cmd != null && c.Length > cmd.min_args) {
227  cmd.func(c.Skip(1).ToArray());
228  }
229  else if(cmd == null && cmds.Count > 0) {
230  error("Command "+c[0]+" requires more arguments.");
231  }
232  else
233  {
234  error("Could not recognize command \"" + c[0] + "\"");
235  }
236 
237  OnCommand.Invoke(s);
238  }
239 
240  /// <summary> Represents a command for the AVR_Devconsole </summary>
241  public class AVR_ConsoleCommand {
242 
243  /// <summary>
244  /// Represents a command for the AVR_Devconsole
245  /// <param name="name"> Identifier-string for the command. This is the token a user should input to execute the command. Should contain no spaces. </param>
246  /// <param name="func"> Action performed when the command is executed. </param>
247  /// <param name="min_args"> Minimum amount of arguments the command requires. If less are provided an error is given to the user. </param>
248  /// <param name="desc"> Brief description of how the command works/what it does. Is provided when used with the "help" command. </param>
249  /// </summary>
250  public AVR_ConsoleCommand(string name, System.Action<string[]> func, int min_args = 0, string desc = "No description given.") {
251  this.name = name;
252  this.func = func;
253  this.min_args = min_args;
254  this.desc = desc;
255  }
256  public string name;
257  public System.Action<string[]> func;
258  public int min_args;
259  public string desc;
260  }
261 
262  /// <summary>
263  /// Registers a new command to the console.
264  /// </summary>
265  /// <param name="cmd"> AVR_ConsoleCommand object that represents the command. </param>
266  public static void register_command(AVR_ConsoleCommand cmd) {
267  commands.Add(cmd);
268  }
269 
270  /// <summary>
271  /// Registers a new command to the console.
272  /// </summary>
273  /// <param name="name"> Identifier-string for the command. This is the token a user should input to execute the command. Should contain no spaces. </param>
274  /// <param name="func"> Action performed when the command is executed. </param>
275  /// <param name="min_args"> Minimum amount of arguments the command requires. If less are provided an error is given to the user. </param>
276  /// <param name="desc"> Brief description of how the command works/what it does. Is provided when used with the "help" command. </param>
277  public static void register_command(string name, System.Action<string[]> func, int min_args=0, string desc = "No description given.") {
278  commands.Add(new AVR_ConsoleCommand(name, func, min_args, desc));
279  }
280 
281 
282  /// <summary>
283  /// Registers a new command to the console.
284  /// </summary>
285  /// <param name="name"> Identifier-string for the command. This is the token a user should input to execute the command. Should contain no spaces. </param>
286  /// <param name="func"> Action performed when the command is executed. </param>
287  /// <param name="desc"> Brief description of how the command works/what it does. Is provided when used with the "help" command. </param>
288  public static void register_command(string name, System.Action<string[]> func, string desc) {
289  commands.Add(new AVR_ConsoleCommand(name, func, 0, desc));
290  }
291 
292  private static void register_all_attribute_commands() {
293  // Find any and all methods marked as "ConsoleCommand" in all assemplies:
294  var methodsMarkedAsCommand =
295  from a in System.AppDomain.CurrentDomain.GetAssemblies().AsParallel()
296  from t in a.GetTypes()
297  from m in t.GetMethods(System.Reflection.BindingFlags.Static | (System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic))
298  let attributes = m.GetCustomAttributes(typeof(AVR.Core.Attributes.ConsoleCommand), true)
299  where attributes != null && attributes.Length > 0
300  select new { method = m, attributes = attributes.Cast<AVR.Core.Attributes.ConsoleCommand>() };
301 
302  // Register each as a command:
303  foreach(var result in methodsMarkedAsCommand) {
304  foreach(var att in result.attributes) {
305  try {
306  // Single string function static void func(string arg)
307  if (result.method.GetParameters().Count() == 1 && result.method.GetParameters()[0].ParameterType == typeof(System.String))
308  {
309  System.Action<string> action = (System.Action<string>)System.Delegate.CreateDelegate(typeof(System.Action<string>), result.method);
310  register_command(att.getCommandString(), (args) => action(args[0]), att.getMinArgs(), att.getDescription());
311  }
312  // String-array function static void func(string[] args)
313  else if(result.method.GetParameters().Count()>0) {
314  System.Action<string[]> action = (System.Action<string[]>)System.Delegate.CreateDelegate(typeof(System.Action<string[]>), result.method);
315  register_command(att.getCommandString(), action, att.getMinArgs(), att.getDescription());
316  }
317  // No-parameter function static void func()
318  else {
319  System.Action action = (System.Action)System.Delegate.CreateDelegate(typeof(System.Action), result.method);
320  register_command(att.getCommandString(), (args) => action(), att.getMinArgs(), att.getDescription());
321  }
322  }
323  catch (System.Exception) {
324  error("Following method is marked as ConsoleCommand, but doesnt follow the necessary requirements: " + result.method + "\n It needs to be static and void. Parameters have to be either none, a single string or a single array of strings.");
325  }
326  }
327  }
328  }
329 
330  [AVR.Core.Attributes.ConsoleCommand("help", 1, "Provides a description for a given console command. Example: help echo")]
331  private static void help_command(string arg) {
332  bool found = false;
333  foreach (AVR_ConsoleCommand cmd in commands)
334  {
335  if(cmd.name == arg) {
336  print("COMMAND: " + cmd.name);
337  print("MIN_ARGS: " + cmd.min_args);
338  print("DESCRIPTION: " + cmd.desc);
339  print("");
340  found = true;
341  }
342  }
343  if(!found) print("Command "+arg+" does not exist. Type \"commands\" to see a list of all available commands.");
344  }
345 
346  [AVR.Core.Attributes.ConsoleCommand("commands", "Provides a list of all available console commands")]
347  private static void print_all_available_commands() {
348  print("COMMAND \t\t MIN ARGS");
349  foreach(AVR_ConsoleCommand cmd in commands) {
350  print(cmd.name + "\t\t" + cmd.min_args);
351  }
352  }
353 
354  [AVR.Core.Attributes.ConsoleCommand("sample", "Sample command for demonstration purposes")]
355  private static void sample_command(string[] args) {
356  Debug.Log("This is a sample command.");
357  }
358  }
359 }
static void cerror(string s, string obj)
Print error message with a caller-context variable.
static void command(string s, bool addToHistory=true)
Execute a given console command.
Represents a command for the AVR_Devconsole
static void csuccess(string s, MonoBehaviour obj)
Print success message with a caller-context variable.
AVR_ConsoleCommand(string name, System.Action< string[]> func, int min_args=0, string desc="No description given.")
Represents a command for the AVR_Devconsole Identifier-string for the command. This is the token a us...
static void success(string s)
Print a success message string on the console.
static void raw_print(string s)
static void init()
Initializes the DevConsole. Only the first execution will have an effect.
static void cwarn(string s, MonoBehaviour obj)
Print warning message with a caller-context variable.
static void error(string s)
Print a given error string on the console.
static void register_all_attribute_commands()
static void register_command(string name, System.Action< string[]> func, string desc)
Registers a new command to the console.
static void csuccess(string s, string obj)
Print success message with a caller-context variable.
Class for the arc-vr developer's console. Functions as a singleton with only static members...
Contains constan values, settings etc. which can all be set through *.avr files. Duplicate settings w...
Definition: AVR_Settings.cs:14
static void cprint(string s, string obj)
Print with a caller-context variable.
static string history(int t)
Returns any command executed in the past. Index of the past command with t=0 being the most recent on...
static void HandleLog(string logString, string stackTrace, LogType type)
Executes a respective output based on logString, stackTrace and LogType.
static void cwarn(string s, GameObject obj)
Print warning message with a caller-context variable.
static string get_text()
Get the complete output of this console as text.
static void echo_command(string s)
static void cerror(string s, MonoBehaviour obj)
Print error message with a caller-context variable.
static void register_command(AVR_ConsoleCommand cmd)
Registers a new command to the console.
Sets the documentation html file inside of Packages/com.avr.core/Documentation/html of a given class...
static void cprint(string s, GameObject obj)
Print with a caller-context variable.
static void cwarn(string s, string obj)
Print warning message with a caller-context variable.
This attribute can be used to easily make a function into a command runnable through the AVR_DevConso...
static bool get_bool(string token)
Get a registered setting of the type bool.
static void register_command(string name, System.Action< string[]> func, int min_args=0, string desc="No description given.")
Registers a new command to the console.
static void print_all_available_commands()
static void print(string s)
Print a given string on the console.
static void sample_command(string[] args)
static void help_command(string arg)
static void csuccess(string s, GameObject obj)
Print success message with a caller-context variable.
static void cprint(string s, MonoBehaviour obj)
Print with a caller-context variable.
static void cerror(string s, GameObject obj)
Print error message with a caller-context variable.
static void warn(string s)
Print a given warning string on the console.
static void clear()
Clear console output entirely.