This commit is contained in:
GoaLitiuM
2021-02-19 18:54:36 +02:00
parent 2107a09ef1
commit 649b8a803c
65 changed files with 13860 additions and 80 deletions

View File

@@ -1,74 +1,11 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
namespace Cabrito
{
[AttributeUsage(AttributeTargets.All)]
public class ConsoleVariableAttribute : Attribute
{
public string name;
public ConsoleVariableAttribute(string name)
{
this.name = name;
}
}
[AttributeUsage(AttributeTargets.All)]
public class ConsoleCommandAttribute : Attribute
{
public string name;
public ConsoleCommandAttribute(string name)
{
this.name = name;
}
}
internal struct ConsoleVariable
{
private FieldInfo field;
public ConsoleVariable(FieldInfo field)
{
this.field = field;
}
public string GetValueString()
{
if (field.FieldType != typeof(string))
throw new Exception("cvar is not type of string");
return (string)field.GetValue(null);
}
public void SetValue(string value)
{
var type = field.FieldType;
if (type == typeof(string))
field.SetValue(null, value);
else
throw new Exception("Unsupported type for SetValue: " + type.Name);
}
}
internal struct ConsoleCommand
{
private MethodInfo method;
public ConsoleCommand(MethodInfo method)
{
this.method = method;
}
public void Invoke(params object[] parameters)
{
method.Invoke(null, parameters);
}
}
public static class Console
{
private static ConsoleScriptBase scriptInstance = null;
@@ -86,7 +23,7 @@ namespace Cabrito
// Called when Console is closed.
public static Action OnClose;
public static bool ShowExecutedLines = true;
public static string LinePrefix { get; internal set; } = "]";
@@ -121,37 +58,97 @@ namespace Cabrito
foreach (var type in assembly.GetTypes())
{
foreach (var method in type.GetMethods())
Dictionary<string, ConsoleCommand> cmdParsed = new Dictionary<string, ConsoleCommand>();
Dictionary<string, List<MethodInfo>> cmdMethods = new Dictionary<string, List<MethodInfo>>();
foreach (MethodInfo method in type.GetMethods())
{
if (!method.IsStatic)
continue;
Attribute[] attributes = Attribute.GetCustomAttributes(method);
foreach (var attr in attributes)
foreach (Attribute attr in attributes)
{
if (attr is ConsoleCommandAttribute cmdAttribute)
{
//Console.Print("found cmd '" + cmdAttribute.name + "' bound to field '" + method.Name + "'");
var cmd = new ConsoleCommand(method);
consoleCommands.Add(cmdAttribute.name.ToLower(), cmd);
// Defer constructing the command until we have parsed all the methods for it in this assembly.
List<MethodInfo> methods;
if (!cmdMethods.TryGetValue(cmdAttribute.name, out methods))
{
methods = new List<MethodInfo>();
cmdMethods.Add(cmdAttribute.name, methods);
}
methods.Add(method);
ConsoleCommand cmd = new ConsoleCommand(cmdAttribute.name, null);
if (!cmdParsed.ContainsKey(cmdAttribute.name))
cmdParsed.Add(cmdAttribute.name, cmd);
foreach (var alias in cmdAttribute.aliases)
{
if (!cmdParsed.ContainsKey(alias))
cmdParsed.Add(alias, cmd);
List<MethodInfo> aliasMethods;
if (!cmdMethods.TryGetValue(alias, out aliasMethods))
{
aliasMethods = new List<MethodInfo>();
cmdMethods.Add(alias, aliasMethods);
}
aliasMethods.Add(method);
}
}
}
}
foreach (var field in type.GetFields())
foreach (var kv in cmdParsed)
{
var methods = cmdMethods[kv.Key];
var definition = kv.Value;
ConsoleCommand cmd = new ConsoleCommand(definition.name, methods.ToArray());
consoleCommands.Add(kv.Key, cmd);
}
foreach (FieldInfo field in type.GetFields())
{
if (!field.IsStatic)
continue;
Attribute[] attributes = Attribute.GetCustomAttributes(field);
foreach (var attr in attributes)
foreach (Attribute attr in attributes)
{
if (attr is ConsoleVariableAttribute cvarAttribute)
{
//Console.Print("found cvar '" + cvarAttribute.name + "' bound to field '" + field.Name + "'");
var cvar = new ConsoleVariable(field);
consoleVariables.Add(cvarAttribute.name.ToLower(), cvar);
consoleVariables.Add(cvarAttribute.name, new ConsoleVariable(cvarAttribute.name, cvarAttribute.flags, field));
foreach (var alias in cvarAttribute.aliases)
consoleVariables.Add(alias, new ConsoleVariable(cvarAttribute.name, cvarAttribute.flags | ConsoleFlags.NoSerialize, field));
}
}
}
foreach (PropertyInfo prop in type.GetProperties())
{
MethodInfo getter = prop.GetGetMethod();
MethodInfo setter = prop.GetSetMethod();
if (getter == null || setter == null || !getter.IsStatic || !setter.IsStatic)
continue;
Attribute[] attributes = Attribute.GetCustomAttributes(prop);
foreach (Attribute attr in attributes)
{
if (attr is ConsoleVariableAttribute cvarAttribute)
{
//Console.Print("found cvar '" + cvarAttribute.name + "' bound to field '" + field.Name + "'");
consoleVariables.Add(cvarAttribute.name, new ConsoleVariable(cvarAttribute.name, cvarAttribute.flags, getter, setter));
foreach (var alias in cvarAttribute.aliases)
consoleVariables.Add(alias, new ConsoleVariable(cvarAttribute.name, cvarAttribute.flags | ConsoleFlags.NoSerialize, getter, setter));
}
}
}
@@ -255,16 +252,21 @@ namespace Cabrito
string[] strs = str.Split(' ');
string execute = strs[0];
string executeLower = execute.ToLowerInvariant();
string value = strs.Length > 1 ? str.Substring(execute.Length + 1) : null;
//Console.PrintDebug("Executed '" + execute + "' with params: '" + value + "'");
if (consoleCommands.TryGetValue(execute, out ConsoleCommand cmd))
if (consoleCommands.TryGetValue(executeLower, out ConsoleCommand cmd))
{
cmd.Invoke();
string[] values = strs.Skip(1).ToArray();
if (values.Length > 0)
cmd.Invoke(values);
else
cmd.Invoke();
//Console.Print("Command bound to '" + execute + "' is '" + cmd.method.Name + "'");
}
else if (consoleVariables.TryGetValue(execute, out ConsoleVariable cvar))
else if (consoleVariables.TryGetValue(executeLower, out ConsoleVariable cvar))
{
if (value != null)
cvar.SetValue(value);

View File

@@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Cabrito
{
[AttributeUsage(AttributeTargets.All)]
public abstract class ConsoleBaseAttribute : Attribute
{
internal string name;
// Additional aliases for this command, these should only be used with user interaction.
// Commands such as 'cvarlist' should not list these in order to avoid clutter.
internal string[] aliases = new string[0];
public ConsoleFlags flags { get; private set; }
public ConsoleBaseAttribute(string name)
{
this.name = name.ToLowerInvariant();
}
public ConsoleBaseAttribute(params string[] names)
{
this.name = names[0].ToLowerInvariant();
aliases = new List<string>(names).Skip(1).Select(x => x.ToLowerInvariant()).ToArray();
}
}
[AttributeUsage(AttributeTargets.All)]
public class ConsoleVariableAttribute : ConsoleBaseAttribute
{
public ConsoleVariableAttribute(string name) : base(name)
{
}
}
[AttributeUsage(AttributeTargets.All)]
public class ConsoleCommandAttribute : ConsoleBaseAttribute
{
/// <summary>
/// Registers a command to Console system.
/// </summary>
/// <param name="name">Name used for calling this command.</param>
public ConsoleCommandAttribute(string name) : base(name)
{
}
/// <summary>
/// Registers a command to Console system.
/// </summary>
/// <param name="names">Names used for calling this command. First name is the main name for this command, rest of the names are aliases.</param>
public ConsoleCommandAttribute(params string[] names) : base(names)
{
}
}
}

View File

@@ -0,0 +1,80 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace Cabrito
{
internal struct ConsoleCommand
{
public string name { get; private set; }
private MethodInfo[] methods;
public ConsoleCommand(string name, MethodInfo[] method)
{
this.name = name;
this.methods = method;
}
public void Invoke()
{
foreach (var method in methods)
{
var methodParameters = method.GetParameters();
if (methodParameters.Length != 0)
continue;
method.Invoke(null, null);
return;
}
throw new Exception("Unexpected number of parameters.");
}
public void Invoke(string[] parameters)
{
MethodInfo match = null;
foreach (var method in methods)
{
var methodParameters = method.GetParameters();
if (methodParameters.Length == 1 && methodParameters[0].ParameterType == typeof(string[]))
{
match = method;
continue;
}
else if (methodParameters.Length != parameters.Length)
continue;
// TODO: try to parse string parameters to needed types first,
// may require finding the exact match first instead of first matching one.
for (int i = 0; i < methodParameters.Length; i++)
//if (methodParameters[i].ParameterType != parameters[i].GetType())
if (methodParameters[i].ParameterType != typeof(string))
continue;
if (match != null)
{
// Prefer exact number of parameters over string[] match
if (methodParameters.Length != parameters.Length)
continue;
}
match = method;
}
if (match != null)
{
if (match.GetParameters().Length == 1 && match.GetParameters()[0].ParameterType == typeof(string[]))
match.Invoke(null, new object[] { parameters });
else
match.Invoke(null, parameters);
return;
}
throw new Exception("Unexpected number of parameters.");
}
}
}

View File

@@ -459,6 +459,7 @@ namespace Cabrito
}
}
#if false
public class ConsoleContentTextBox_Old : ConsoleTextBoxBase
{
[HideInEditor]
@@ -562,4 +563,5 @@ namespace Cabrito
return inputBox.OnCharInput(c);
}
}
#endif
}

View File

@@ -56,8 +56,14 @@ namespace Cabrito
}
else if (key == KeyboardKeys.Return)
{
Console.Execute(Text);
Clear();
try
{
Console.Execute(Text);
}
finally
{
Clear();
}
return true;
}
else if (key == KeyboardKeys.ArrowUp || key == KeyboardKeys.ArrowDown)

View File

@@ -160,6 +160,7 @@ namespace Cabrito
Console.RegisterConsoleScript(this);
RefreshLayout();
#if false
//for (int i = 0; i < 10; i++)
{
string[] teststr = {
@@ -219,6 +220,23 @@ namespace Cabrito
foreach (var l in teststr)
Console.Print(l);
}
#endif
/*FlaxEditor.Editor.Options.OptionsChanged += (FlaxEditor.Options.EditorOptions options) =>
{
};*/
Debug.Logger.LogHandler.SendLog += OnSendLog;
Debug.Logger.LogHandler.SendExceptionLog += OnSendExceptionLog;
}
private void OnSendLog(LogType level, string msg, FlaxEngine.Object obj, string stackTrace)
{
Console.Print("[DEBUGs] " + msg);
}
private void OnSendExceptionLog(Exception exception, FlaxEngine.Object obj)
{
Console.Print("[EXCEP] " + exception.Message);
}
public override void OnDestroy()
@@ -229,6 +247,9 @@ namespace Cabrito
consoleBox?.Dispose();
backgroundImage?.DisposeChildren();
backgroundImage?.Dispose();
Debug.Logger.LogHandler.SendLog -= OnSendLog;
Debug.Logger.LogHandler.SendExceptionLog -= OnSendExceptionLog;
}
public void RefreshLayout()

View File

@@ -63,8 +63,8 @@ namespace Cabrito
[HideInEditor]
public virtual string TextPrefix { get; set; } = "";
[HideInEditor]
public override string Text => _text;
//[HideInEditor]
//public override string Text => _text;
public ConsoleTextBoxBase() : base()
{

View File

@@ -0,0 +1,75 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace Cabrito
{
[Flags]
public enum ConsoleFlags
{
NoSerialize = 1, // Value does not persist
Alias = NoSerialize,
}
internal struct ConsoleVariable
{
public string name { get; private set; }
public ConsoleFlags flags { get; private set; }
private FieldInfo field;
private MethodInfo getter;
private MethodInfo setter;
public ConsoleVariable(string name, ConsoleFlags flags, FieldInfo field)
{
this.name = name;
this.flags = flags;
this.field = field;
this.getter = null;
this.setter = null;
}
public ConsoleVariable(string name, ConsoleFlags flags, MethodInfo getter, MethodInfo setter)
{
this.name = name;
this.flags = flags;
this.field = null;
this.getter = getter;
this.setter = setter;
}
public string GetValueString()
{
var type = field != null ? field.FieldType : getter.ReturnType;
if (type == typeof(string))
{
if (field != null)
return (string)field.GetValue(null);
else if (setter != null)
return (string)getter.Invoke(null, null);
}
else
throw new Exception("cvar is not type of string");
throw new Exception("GetValueString no field or getter specified");
}
public void SetValue(string value)
{
var type = field != null ? field.FieldType : getter.ReturnType;
if (type == typeof(string))
{
if (field != null)
field.SetValue(null, value);
else if (setter != null)
setter.Invoke(null, new object[] { value });
}
else
throw new Exception("Unsupported type for SetValue: " + type.Name);
}
}
}