2017-05-08 01:29:12 +02:00
|
|
|
|
using System.Collections;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Text.RegularExpressions;
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
using UnityEngine.UI;
|
|
|
|
|
|
2017-05-08 23:03:02 +02:00
|
|
|
|
namespace Cyber.Console {
|
|
|
|
|
|
2017-05-08 21:14:52 +02:00
|
|
|
|
/// <summary>
|
2017-05-08 23:03:02 +02:00
|
|
|
|
/// Controls an input and an output to implement a console interface to call
|
|
|
|
|
/// arbitrary commands which can be set from anywhere in the program through
|
|
|
|
|
/// <see cref="Term"/>.
|
2017-05-08 21:14:52 +02:00
|
|
|
|
/// </summary>
|
2017-05-08 23:03:02 +02:00
|
|
|
|
public class DebugConsole : MonoBehaviour {
|
|
|
|
|
|
|
|
|
|
private static readonly Regex CommandPartRegex = new Regex("([^ \"]+ )|(\"[^\"]+\")");
|
2017-05-08 01:29:12 +02:00
|
|
|
|
|
2017-05-08 23:03:02 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// The parent of the <see cref="InputField"/> and <see cref="TextField"/>.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public GameObject Panel;
|
2017-05-08 01:29:12 +02:00
|
|
|
|
|
2017-05-08 23:03:02 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// The input for the console.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public InputField InputField;
|
2017-05-08 03:16:01 +02:00
|
|
|
|
|
2017-05-08 23:03:02 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// The output for the console.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public Text TextField;
|
2017-05-08 01:29:12 +02:00
|
|
|
|
|
2017-05-08 23:03:02 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Controls the visibility of the console. For how this is controlled in-game, see <see cref="Update"/>.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public bool Visible = false;
|
2017-05-08 01:29:12 +02:00
|
|
|
|
|
2017-05-10 19:30:30 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// The length of a row in the console in characters.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public int RowLength = 80;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2017-05-11 19:55:38 +02:00
|
|
|
|
/// How many lines are included in the <see cref="TextField"/> when
|
|
|
|
|
/// the total amount of lines exceeds this.
|
2017-05-10 19:30:30 +02:00
|
|
|
|
/// </summary>
|
2017-05-11 19:55:38 +02:00
|
|
|
|
public int LinesRendered = 15;
|
2017-05-10 19:30:30 +02:00
|
|
|
|
|
2017-05-08 23:03:02 +02:00
|
|
|
|
private Dictionary<string, DebugConsoleAction> Actions = new Dictionary<string, DebugConsoleAction>();
|
2017-05-10 19:30:30 +02:00
|
|
|
|
private List<string> Lines = new List<string>();
|
|
|
|
|
private List<string> Commands = new List<string>();
|
|
|
|
|
private int LastCommandIndex = 0;
|
|
|
|
|
private string LastUnexecutedCommand = "";
|
2017-05-11 22:15:05 +02:00
|
|
|
|
private int ScrollOffset = 0;
|
2017-05-08 01:29:12 +02:00
|
|
|
|
|
2017-05-08 23:03:02 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Creates a new <see cref="DebugConsole"/>, and sets the <see cref="Term"/>'s singleton.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public DebugConsole() {
|
|
|
|
|
Term.SetDebugConsole(this);
|
|
|
|
|
}
|
2017-05-08 01:29:12 +02:00
|
|
|
|
|
2017-05-08 23:03:02 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Tries to call the command in the <see cref="InputField"/>.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void CallCommand() {
|
|
|
|
|
if (InputField.text.Length == 0) {
|
|
|
|
|
return;
|
2017-05-08 21:14:52 +02:00
|
|
|
|
}
|
2017-05-10 19:30:30 +02:00
|
|
|
|
// Log this command
|
2017-05-08 23:03:02 +02:00
|
|
|
|
Println(InputField.text);
|
2017-05-10 19:30:30 +02:00
|
|
|
|
Commands.Add(InputField.text);
|
|
|
|
|
LastCommandIndex = Commands.Count;
|
|
|
|
|
|
2017-05-08 23:03:02 +02:00
|
|
|
|
List<string> Arguments = new List<string>();
|
|
|
|
|
MatchCollection Matches = CommandPartRegex.Matches(InputField.text + " ");
|
|
|
|
|
for (int i = 0; i < Matches.Count; i++) {
|
|
|
|
|
Arguments.Add(Matches[i].Value.Replace('"', ' ').Trim());
|
2017-05-08 21:14:52 +02:00
|
|
|
|
}
|
|
|
|
|
foreach (string Action in Actions.Keys) {
|
|
|
|
|
string[] Parts = Action.Split(' ');
|
2017-05-08 23:03:02 +02:00
|
|
|
|
if (Arguments.Count == Parts.Length && Arguments[0].Equals(Parts[0])) {
|
|
|
|
|
Arguments.RemoveAt(0);
|
|
|
|
|
Actions[Action].Call(Arguments);
|
|
|
|
|
break;
|
2017-05-08 21:14:52 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2017-05-10 19:30:30 +02:00
|
|
|
|
|
|
|
|
|
// Clear the input field
|
2017-05-08 23:03:02 +02:00
|
|
|
|
InputField.text = "";
|
|
|
|
|
InputField.ActivateInputField();
|
|
|
|
|
}
|
2017-05-08 21:14:52 +02:00
|
|
|
|
|
2017-05-08 23:03:02 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Adds a command to be used in the console.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="command">The command template that should be used.
|
|
|
|
|
/// eg. "print (text)" or "add (number) (number)".</param>
|
|
|
|
|
/// <param name="description">Description.</param>
|
|
|
|
|
/// <param name="action">Action.</param>
|
|
|
|
|
public void AddCommand(string command, string description, DebugConsoleAction.Action action) {
|
|
|
|
|
string PrettyDescription = command;
|
|
|
|
|
foreach (string Line in description.Split('\n')) {
|
|
|
|
|
PrettyDescription += "\n " + Line;
|
|
|
|
|
}
|
|
|
|
|
Actions[command] = new DebugConsoleAction(PrettyDescription, action);
|
|
|
|
|
}
|
2017-05-08 21:14:52 +02:00
|
|
|
|
|
2017-05-08 23:03:02 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Prints text into the DebugConsole and adds a newline.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="text">Text.</param>
|
|
|
|
|
public void Println(string text) {
|
|
|
|
|
Print(text + "\n");
|
2017-05-08 01:29:12 +02:00
|
|
|
|
}
|
2017-05-08 23:03:02 +02:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
2017-05-10 19:30:30 +02:00
|
|
|
|
/// Prints text into the Console. Wraps text at <see cref="RowLength"/>.
|
2017-05-08 23:03:02 +02:00
|
|
|
|
/// </summary>
|
2017-05-10 19:30:30 +02:00
|
|
|
|
/// <remarks>
|
|
|
|
|
/// If the linecount exceeds <see cref="MaxLinesUntilCleanup"/>, the
|
|
|
|
|
/// console is cleared to the point that it only has
|
|
|
|
|
/// <see cref="LineCountSavedFromCleanup"/> lines.
|
|
|
|
|
/// </remarks>
|
2017-05-08 23:03:02 +02:00
|
|
|
|
/// <param name="text">Text.</param>
|
|
|
|
|
public void Print(string text) {
|
2017-05-10 19:30:30 +02:00
|
|
|
|
// Wrap lines and log them to Lines
|
|
|
|
|
int Index = 0;
|
|
|
|
|
int EscapeIndex = 0;
|
|
|
|
|
do {
|
|
|
|
|
int NewLineIndex = text.IndexOf("\n", Index) + 1;
|
|
|
|
|
if (NewLineIndex == 0 || NewLineIndex > Index + RowLength) {
|
|
|
|
|
NewLineIndex = Index + Mathf.Min(text.Length - Index, RowLength);
|
|
|
|
|
}
|
|
|
|
|
string Line = text.Substring(Index, NewLineIndex - Index).Replace("\n", "");
|
|
|
|
|
Index = NewLineIndex;
|
|
|
|
|
Lines.Add(Line);
|
|
|
|
|
TextField.text += Line + "\n";
|
|
|
|
|
EscapeIndex++;
|
|
|
|
|
} while (Index < text.Length && EscapeIndex < 10);
|
2017-05-11 19:55:38 +02:00
|
|
|
|
UpdateTextField();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void UpdateTextField() {
|
|
|
|
|
string NewLog = "";
|
|
|
|
|
int LineAmt = Mathf.Min(LinesRendered, Lines.Count);
|
2017-05-11 22:15:05 +02:00
|
|
|
|
for (int i = LineAmt; i > 0; i--) {
|
2017-05-11 19:55:38 +02:00
|
|
|
|
int Index = Lines.Count - (i + ScrollOffset);
|
|
|
|
|
if (Index >= 0 && Index < Lines.Count) {
|
2017-05-11 22:15:05 +02:00
|
|
|
|
NewLog += Lines[Index] + "\n";
|
2017-05-10 19:30:30 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2017-05-11 19:55:38 +02:00
|
|
|
|
TextField.text = NewLog;
|
2017-05-08 23:03:02 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void Start() {
|
|
|
|
|
AddCommand("help", "Lists all commands.", (args) => {
|
|
|
|
|
Println("Commands:");
|
|
|
|
|
foreach (string Action in Actions.Keys) {
|
|
|
|
|
Println("- " + Action);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
AddCommand("help (command)", "Describes the given command.", (args) => {
|
|
|
|
|
// Check complete versions of the names (so you can do eg. help "help (command)")
|
|
|
|
|
foreach (string Action in Actions.Keys) {
|
|
|
|
|
if (Action.Equals(args[0])) {
|
|
|
|
|
Println(Actions[Action].Description);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Check just names
|
|
|
|
|
foreach (string Action in Actions.Keys) {
|
|
|
|
|
string[] Parts = Action.Split(' ');
|
|
|
|
|
if (Parts[0].Equals(args[0])) {
|
|
|
|
|
Println(Actions[Action].Description);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Println("That command doesn't exist.");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
AddCommand("print (text)", "Prints the given text.", (args) => {
|
|
|
|
|
Println(args[0]);
|
|
|
|
|
});
|
2017-05-09 12:30:56 +02:00
|
|
|
|
|
|
|
|
|
AddCommand("shutdown", "Shuts the game down.", (args) => {
|
|
|
|
|
Application.Quit();
|
|
|
|
|
});
|
2017-05-10 19:30:30 +02:00
|
|
|
|
|
2017-05-11 22:15:05 +02:00
|
|
|
|
Println("Use the \"help\" command for a list of commands.");
|
|
|
|
|
|
2017-05-10 19:30:30 +02:00
|
|
|
|
// Set an accurate row length (if the panel is set)
|
|
|
|
|
if (Panel != null && Panel.GetComponent<RectTransform>() != null) {
|
|
|
|
|
CharacterInfo CharInfo;
|
|
|
|
|
TextField.font.RequestCharactersInTexture("W", TextField.fontSize,
|
|
|
|
|
TextField.fontStyle);
|
|
|
|
|
TextField.font.GetCharacterInfo('W', out CharInfo,
|
|
|
|
|
TextField.fontSize, TextField.fontStyle);
|
|
|
|
|
float CharacterWidth = CharInfo.glyphWidth - 1;
|
|
|
|
|
float PanelWidth = Panel.GetComponent<RectTransform>().rect.width;
|
|
|
|
|
RowLength = (int) (PanelWidth / CharacterWidth);
|
|
|
|
|
}
|
2017-05-08 23:03:02 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void Update() {
|
2017-05-09 16:15:07 +02:00
|
|
|
|
// Inputs
|
2017-05-08 23:03:02 +02:00
|
|
|
|
if (Input.GetButtonDown("Console Toggle")) {
|
|
|
|
|
Visible = !Visible;
|
2017-05-08 01:29:12 +02:00
|
|
|
|
}
|
2017-05-09 16:15:07 +02:00
|
|
|
|
if (Input.GetButtonDown("Enter Command")) {
|
|
|
|
|
CallCommand();
|
|
|
|
|
}
|
2017-05-10 19:30:30 +02:00
|
|
|
|
if (Input.GetButtonDown("Previous Command")) {
|
|
|
|
|
if (LastCommandIndex - 1 >= 0) {
|
|
|
|
|
if (LastCommandIndex == Commands.Count) {
|
|
|
|
|
// The last command is the last one that was executed
|
|
|
|
|
// Save the currently written command so it can be returned to
|
|
|
|
|
LastUnexecutedCommand = InputField.text;
|
|
|
|
|
}
|
|
|
|
|
InputField.text = Commands[--LastCommandIndex];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (Input.GetButtonDown("Next Command")) {
|
|
|
|
|
if (LastCommandIndex + 1 < Commands.Count) {
|
|
|
|
|
InputField.text = Commands[++LastCommandIndex];
|
|
|
|
|
} else if (LastCommandIndex + 1 == Commands.Count) {
|
|
|
|
|
LastCommandIndex++;
|
|
|
|
|
InputField.text = LastUnexecutedCommand;
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-05-11 22:15:05 +02:00
|
|
|
|
if (Input.GetAxis("Mouse ScrollWheel") > 0 && ScrollOffset + 1 < Lines.Count) {
|
2017-05-11 19:55:38 +02:00
|
|
|
|
ScrollOffset++;
|
|
|
|
|
UpdateTextField();
|
|
|
|
|
}
|
2017-05-11 22:15:05 +02:00
|
|
|
|
if (Input.GetAxis("Mouse ScrollWheel") < 0 && ScrollOffset - 1 >= 0) {
|
2017-05-11 19:55:38 +02:00
|
|
|
|
ScrollOffset--;
|
|
|
|
|
UpdateTextField();
|
|
|
|
|
}
|
2017-05-09 16:15:07 +02:00
|
|
|
|
|
|
|
|
|
// Slide up/down animation
|
2017-05-08 23:03:02 +02:00
|
|
|
|
RectTransform Rect = Panel.GetComponent<RectTransform>();
|
|
|
|
|
Vector2 OffsetMin = Rect.offsetMin;
|
|
|
|
|
if (Visible) {
|
|
|
|
|
if (OffsetMin.y > 1) {
|
|
|
|
|
OffsetMin.y = Mathf.Lerp(OffsetMin.y, 0, 5f * Time.deltaTime);
|
|
|
|
|
}
|
|
|
|
|
if (!InputField.isFocused) {
|
|
|
|
|
InputField.ActivateInputField();
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (1000 - OffsetMin.y > 1) {
|
|
|
|
|
OffsetMin.y = Mathf.Lerp(OffsetMin.y, 1000, 1f * Time.deltaTime);
|
|
|
|
|
}
|
|
|
|
|
if (InputField.isFocused) {
|
|
|
|
|
InputField.DeactivateInputField();
|
|
|
|
|
}
|
2017-05-08 01:29:12 +02:00
|
|
|
|
}
|
2017-05-08 23:03:02 +02:00
|
|
|
|
Rect.offsetMin = OffsetMin;
|
2017-05-08 01:29:12 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|