2020-04-28 01:50:50 +01:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Handles parsing and execution of console commands, as well as collecting log output.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
|
|
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.Linq;
|
|
|
|
|
|
using System.Reflection;
|
|
|
|
|
|
using System.Runtime.CompilerServices;
|
|
|
|
|
|
using System.Text;
|
2020-04-28 04:21:04 +01:00
|
|
|
|
using System.Text.RegularExpressions;
|
2020-04-28 01:50:50 +01:00
|
|
|
|
using UnityEngine.SceneManagement;
|
|
|
|
|
|
using Object = UnityEngine.Object;
|
|
|
|
|
|
|
|
|
|
|
|
public class ConsoleController
|
|
|
|
|
|
{
|
2020-05-07 03:53:54 +01:00
|
|
|
|
public static Component MessageReceiver;
|
2020-11-29 22:50:12 +00:00
|
|
|
|
private static ConsoleController _instance;
|
|
|
|
|
|
private static Regex _permittedCharacters = new Regex("[^a-zA-Z0-9 -]");
|
|
|
|
|
|
private static Dictionary<string, Action<string[]>> _commands = new Dictionary<string, Action<string[]>>();
|
2020-04-28 01:50:50 +01:00
|
|
|
|
|
|
|
|
|
|
private ConsoleController()
|
|
|
|
|
|
{
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static ConsoleController Instance
|
|
|
|
|
|
{
|
2020-11-29 22:50:12 +00:00
|
|
|
|
get => _instance ?? (_instance = new ConsoleController());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static void AddCommand(string command, Action<string[]> action)
|
|
|
|
|
|
{
|
|
|
|
|
|
var lower = command.ToLowerInvariant();
|
|
|
|
|
|
if(!_commands.ContainsKey(lower))
|
|
|
|
|
|
_commands.Add(lower, action);
|
2020-04-28 01:50:50 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#region Event declarations
|
|
|
|
|
|
// Used to communicate with ConsoleView
|
|
|
|
|
|
public delegate void LogChangedHandler(string[] log);
|
|
|
|
|
|
public event LogChangedHandler LogChanged;
|
|
|
|
|
|
|
|
|
|
|
|
public delegate void VisibilityChangedHandler(bool visible);
|
|
|
|
|
|
public event VisibilityChangedHandler VisibilityChanged;
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// How many log lines should be retained?
|
|
|
|
|
|
/// Note that strings submitted to appendLogLine with embedded newlines will be counted as a single line.
|
|
|
|
|
|
/// </summary>
|
2020-11-29 22:50:12 +00:00
|
|
|
|
private const int ScrollbackSize = 100;
|
2020-04-28 01:50:50 +01:00
|
|
|
|
|
2020-11-29 22:50:12 +00:00
|
|
|
|
private readonly Queue<string> _scrollback = new Queue<string>(ScrollbackSize);
|
|
|
|
|
|
private readonly List<string> _commandHistory = new List<string>();
|
2020-04-28 01:50:50 +01:00
|
|
|
|
|
|
|
|
|
|
public string[] Log { get; private set; } //Copy of scrollback as an array for easier use by ConsoleView
|
|
|
|
|
|
|
|
|
|
|
|
public void AppendLogLine(string line) {
|
2020-11-29 22:50:12 +00:00
|
|
|
|
if (_scrollback.Count >= ScrollbackSize) {
|
2020-04-28 01:50:50 +01:00
|
|
|
|
_scrollback.Dequeue();
|
|
|
|
|
|
}
|
|
|
|
|
|
_scrollback.Enqueue(line);
|
|
|
|
|
|
|
|
|
|
|
|
Log = _scrollback.ToArray();
|
2020-11-29 22:50:12 +00:00
|
|
|
|
LogChanged?.Invoke(Log);
|
2020-04-28 01:50:50 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void RunCommandString(string commandString) {
|
2020-11-29 22:50:12 +00:00
|
|
|
|
AppendLogLine($"$ {commandString}");
|
2020-04-28 01:50:50 +01:00
|
|
|
|
|
|
|
|
|
|
string[] commandSplit = ParseArguments(commandString);
|
|
|
|
|
|
string[] args = {"",""};
|
|
|
|
|
|
if (commandSplit.Length < 1) {
|
2020-11-29 22:50:12 +00:00
|
|
|
|
AppendLogLine($"Unable to process command '{commandString}'");
|
2020-04-28 01:50:50 +01:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
if (commandSplit.Length >= 2) {
|
|
|
|
|
|
int numArgs = commandSplit.Length - 1;
|
|
|
|
|
|
args = new string[numArgs];
|
|
|
|
|
|
Array.Copy(commandSplit, 1, args, 0, numArgs);
|
|
|
|
|
|
}
|
2020-11-29 22:50:12 +00:00
|
|
|
|
|
|
|
|
|
|
var cmd = commandSplit[0].ToLower();
|
|
|
|
|
|
if(_commands.ContainsKey(cmd))
|
|
|
|
|
|
_commands[cmd].Invoke(args);
|
|
|
|
|
|
else AppendLogLine("Invalid command!");
|
|
|
|
|
|
//MessageReceiver.SendMessage(commandSplit[0].ToLower(), args, SendMessageOptions.DontRequireReceiver);
|
2020-04-28 01:50:50 +01:00
|
|
|
|
_commandHistory.Add(commandString);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static string[] ParseArguments(string commandString)
|
|
|
|
|
|
{
|
2020-11-29 22:50:12 +00:00
|
|
|
|
var parmChars = new LinkedList<char>(commandString.ToCharArray());
|
|
|
|
|
|
var inQuote = false;
|
2020-04-28 01:50:50 +01:00
|
|
|
|
var node = parmChars.First;
|
|
|
|
|
|
while (node != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
var next = node.Next;
|
|
|
|
|
|
if (node.Value == '"') {
|
|
|
|
|
|
inQuote = !inQuote;
|
|
|
|
|
|
parmChars.Remove(node);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!inQuote && node.Value == ' ') {
|
|
|
|
|
|
node.Value = '\n';
|
|
|
|
|
|
}
|
|
|
|
|
|
node = next;
|
|
|
|
|
|
}
|
2020-11-29 22:50:12 +00:00
|
|
|
|
var parmCharsArr = new char[parmChars.Count];
|
2020-04-28 01:50:50 +01:00
|
|
|
|
parmChars.CopyTo(parmCharsArr, 0);
|
2020-04-28 04:21:04 +01:00
|
|
|
|
var args = new string(parmCharsArr).Split(new[] {'\n'}, StringSplitOptions.RemoveEmptyEntries);
|
|
|
|
|
|
for (var i = 0; i < args.Length; i++)
|
|
|
|
|
|
{
|
2020-11-29 22:50:12 +00:00
|
|
|
|
args[i] = _permittedCharacters.Replace(args[i], "");
|
2020-04-28 04:21:04 +01:00
|
|
|
|
}
|
|
|
|
|
|
return args;
|
2020-04-28 01:50:50 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|