quakeball/Assets/Scripts/Interface/Terminal.cs

205 lines
8.0 KiB
C#
Raw Permalink Normal View History

2020-08-06 23:37:23 +02:00
using System.Collections.Generic;
using System;
2020-08-08 02:57:37 +02:00
using System.Text;
2020-08-06 23:37:23 +02:00
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.EventSystems;
2020-08-08 02:57:37 +02:00
using UnityEngine.UI;
2020-08-07 20:24:43 +02:00
using NeonTea.Quakeball.Players;
2020-08-06 23:37:23 +02:00
using TMPro;
namespace NeonTea.Quakeball.Interface {
public class Terminal : MonoBehaviour {
public RectTransform TerminalPanel;
public TMP_InputField InputField;
public TMP_Text TextField;
public LocalPlayer Player;
2020-08-08 02:57:37 +02:00
[Tooltip("Used to optimize the amount of text rendered. 0 for no optimization.")]
public float LinesVisibleAtOnce;
public Scrollbar TerminalScrollbar;
2020-08-06 23:37:23 +02:00
private InputAction ToggleTerminalAction;
private InputAction SubmitTerminal;
private float DesiredTerminalPos;
private bool OpenUpdated;
2020-08-06 23:37:23 +02:00
private bool IsOpen = false;
2020-08-07 00:22:54 +02:00
private Dictionary<string, Func<string[], bool>> Commands = new Dictionary<string, Func<string[], bool>>();
private Dictionary<string, string> Helps = new Dictionary<string, string>();
2020-08-07 00:22:54 +02:00
2020-08-06 23:37:23 +02:00
private List<string> Messages = new List<string>();
2020-08-07 00:22:54 +02:00
private List<string> PreviousRuns = new List<string>();
private int CurrentScroll = -1;
private bool JustScrolled = false;
2020-08-06 23:37:23 +02:00
public static string INFO_COLOR = "#FE8";
2020-08-07 00:22:54 +02:00
public static string ERROR_COLOR = "#F33";
2020-08-06 23:37:23 +02:00
2020-08-07 00:47:24 +02:00
public static Terminal Singleton => GameObject.FindGameObjectWithTag("Terminal").GetComponent<Terminal>();
private void Start() {
2020-08-06 23:37:23 +02:00
ToggleTerminalAction = new InputAction("Toggle Terminal", binding: "<Keyboard>/backquote");
ToggleTerminalAction.Enable();
ToggleTerminalAction.performed += ToggleTerminal;
SubmitTerminal = new InputAction("Terminal Submit", binding: "<Keyboard>/enter");
SubmitTerminal.Enable();
SubmitTerminal.performed += Submit;
2020-08-07 00:22:54 +02:00
SubmitTerminal = new InputAction("Terminal ScrollUp", binding: "<Keyboard>/uparrow");
SubmitTerminal.Enable();
SubmitTerminal.performed += _ => { Scroll(1); };
SubmitTerminal = new InputAction("Terminal ScrollDown", binding: "<Keyboard>/downarrow");
SubmitTerminal.Enable();
SubmitTerminal.performed += _ => { Scroll(-1); };
2020-08-06 23:37:23 +02:00
DesiredTerminalPos = (TerminalPanel.rect.height / 2) * (IsOpen ? -1 : 1);
InputField.restoreOriginalTextOnEscape = false;
2020-08-07 00:22:54 +02:00
InputField.onValueChanged.AddListener(_ => {
if (JustScrolled) {
JustScrolled = false;
return;
}
CurrentScroll = -1;
});
2020-08-06 23:37:23 +02:00
RegisterCommand("help", args => {
if (args.Length == 0) {
2020-08-08 01:32:56 +02:00
foreach (string command in Commands.Keys) {
string help = Helps.ContainsKey(command) ? Helps[command] : "No help info";
Println($"{command}: {help}");
}
}
foreach (string command in args) {
if (Helps.ContainsKey(command)) {
Println($"help {command}: {Helps[command]}");
} else {
2020-08-08 01:32:56 +02:00
Println($"<color={ERROR_COLOR}>Help for command {command} not found.</color>");
}
}
return true;
2020-08-08 01:32:56 +02:00
}, "help [command [...]] - Displays help information for the given commands");
Println($"<color={INFO_COLOR}>Welcome to Quakeball!</color>");
2020-08-06 23:37:23 +02:00
}
public void ToggleTerminal(InputAction.CallbackContext context) {
IsOpen = !IsOpen;
DesiredTerminalPos = (TerminalPanel.rect.height / 2) * (IsOpen ? -1 : 1);
if (IsOpen) {
InputField.text = "";
}
InputField.readOnly = true;
if (Player != null) {
if (IsOpen) {
Player.DisableInput += 1;
} else {
Player.DisableInput -= 1;
}
2020-08-06 23:37:23 +02:00
}
}
2020-08-07 00:47:24 +02:00
private void Update() {
2020-08-06 23:37:23 +02:00
Vector3 pos = TerminalPanel.anchoredPosition;
pos.y = Mathf.Lerp(pos.y, DesiredTerminalPos, Time.deltaTime * 10);
TerminalPanel.anchoredPosition = pos;
if (IsOpened() && EventSystem.current.currentSelectedGameObject != InputField) {
InputField.Select();
InputField.ActivateInputField();
InputField.readOnly = false;
}
2020-08-07 20:28:43 +02:00
if (IsOpen) {
2020-08-08 02:57:37 +02:00
if (LinesVisibleAtOnce == 0) {
TextField.text = String.Join("\n", Messages);
} else {
float VisibleLinesCenterIndex = (1 - TerminalScrollbar.value) * Messages.Count;
int StartIndex = Mathf.Max(0, (int)(VisibleLinesCenterIndex - LinesVisibleAtOnce / 2));
int EndIndex = Mathf.Min(Messages.Count - 1, (int)(VisibleLinesCenterIndex + LinesVisibleAtOnce / 2));
StringBuilder OptimizedText = new StringBuilder();
for (int i = 0; i < Messages.Count; i++) {
if (i < StartIndex || i > EndIndex) {
OptimizedText.AppendLine();
} else {
OptimizedText.AppendLine(Messages[i]);
}
}
TextField.text = OptimizedText.ToString();
}
2020-08-07 20:28:43 +02:00
}
2020-08-06 23:37:23 +02:00
}
2020-08-07 00:22:54 +02:00
public bool RegisterCommand(string name, Func<string[], bool> command) {
if (Commands.ContainsKey(name)) {
return false;
}
Commands.Add(name, command);
return true;
}
public bool RegisterCommand(string name, Func<string[], bool> command, string help) {
if (RegisterCommand(name, command)) {
Helps.Add(name, help);
return true;
}
return false;
}
2020-08-07 00:22:54 +02:00
public void Run(string command) {
string[] parts = command.Split(new char[] { ' ' });
string name = parts[0];
if (Commands.ContainsKey(name)) {
Func<string[], bool> func = Commands[name];
string[] args = new string[parts.Length - 1];
Array.Copy(parts, 1, args, 0, parts.Length - 1);
int message = Println($"> {command}");
if (!func(args)) {
EditPrintln(message, $"<color={ERROR_COLOR}>> {command}</color>");
2020-08-07 00:22:54 +02:00
}
} else {
Println($"<color={ERROR_COLOR}>> {command}</color>");
Println("No such command exists!");
2020-08-07 00:22:54 +02:00
}
PreviousRuns.Insert(0, command);
}
public int Println(string message) {
2020-08-06 23:37:23 +02:00
Messages.Add(message);
return Messages.Count - 1;
}
public void EditPrintln(int idx, string message) {
if (0 > idx || idx >= Messages.Count) {
return;
}
Messages[idx] = message;
2020-08-06 23:37:23 +02:00
}
2020-08-11 00:08:05 +02:00
public List<string> GetMessagesSince(ref int startIndex) {
List<string> messages = new List<string>();
for (int i = startIndex; i < Messages.Count; i++) {
messages.Add(Messages[i]);
}
startIndex = Messages.Count;
return messages;
}
2020-08-07 00:22:54 +02:00
private void Scroll(int amount) {
if (IsOpened() && PreviousRuns.Count > 0) {
JustScrolled = true;
CurrentScroll = Math.Min(Math.Max(0, CurrentScroll + amount), PreviousRuns.Count - 1);
InputField.text = PreviousRuns[CurrentScroll];
}
}
2020-08-06 23:37:23 +02:00
private void Submit(InputAction.CallbackContext context) {
if (IsOpened()) {
2020-08-07 00:22:54 +02:00
Run(InputField.text);
2020-08-06 23:37:23 +02:00
InputField.text = "";
}
}
private bool IsOpened() {
return IsOpen && (TerminalPanel.anchoredPosition.y + TerminalPanel.rect.height / 2) < 10;
}
}
}