您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
266 行
7.5 KiB
266 行
7.5 KiB
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
using UnityEngine.EventSystems;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using UnityEngine.Events;
|
|
|
|
namespace UnityConsole
|
|
{
|
|
/// <summary>
|
|
/// The interactive front-end of the console.
|
|
/// </summary>
|
|
[DisallowMultipleComponent]
|
|
[RequireComponent(typeof(ConsoleController))]
|
|
public class ConsoleUI : MonoBehaviour, IScrollHandler
|
|
{
|
|
public event Action<bool> onToggleConsole;
|
|
public event Action<string> onSubmitCommand;
|
|
public event Action onClearConsole;
|
|
|
|
public Scrollbar scrollbar;
|
|
public Text outputText;
|
|
public ScrollRect outputArea;
|
|
public InputField inputField;
|
|
|
|
/// <summary>
|
|
/// Indicates whether the console is currently open or close.
|
|
/// </summary>
|
|
public bool isConsoleOpen => enabled;
|
|
|
|
void Awake()
|
|
{
|
|
inputField.onEndEdit.AddListener(OnSubmit);
|
|
Show(false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Opens or closes the console.
|
|
/// </summary>
|
|
public void ToggleConsole()
|
|
{
|
|
ClearInput();
|
|
enabled = !enabled;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Opens the console.
|
|
/// </summary>
|
|
public void OpenConsole()
|
|
{
|
|
enabled = true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Closes the console.
|
|
/// </summary>
|
|
public void CloseConsole()
|
|
{
|
|
enabled = false;
|
|
}
|
|
|
|
void OnEnable()
|
|
{
|
|
OnToggle(true);
|
|
}
|
|
|
|
void OnDisable()
|
|
{
|
|
OnToggle(false);
|
|
}
|
|
|
|
private void OnToggle(bool open)
|
|
{
|
|
Show(open);
|
|
|
|
if (open)
|
|
{
|
|
inputField.ActivateInputField();
|
|
}
|
|
else
|
|
{
|
|
ClearInput();
|
|
}
|
|
|
|
onToggleConsole?.Invoke(open);
|
|
}
|
|
|
|
private void Show(bool show)
|
|
{
|
|
inputField.gameObject.SetActive(show);
|
|
outputArea.gameObject.SetActive(show);
|
|
scrollbar.gameObject.SetActive(show);
|
|
}
|
|
|
|
/// <summary>
|
|
/// What to do when the user wants to submit a command.
|
|
/// </summary>
|
|
public void OnSubmit(string input)
|
|
{
|
|
if (EventSystem.current.alreadySelecting)
|
|
{
|
|
// if user selected something else, don't treat as a submit
|
|
return;
|
|
}
|
|
|
|
input = input.Replace('\n', ' ').Replace('\r', ' ');
|
|
|
|
if (input.Length > 0)
|
|
{
|
|
onSubmitCommand?.Invoke(input);
|
|
scrollbar.value = 0;
|
|
ClearInput();
|
|
}
|
|
|
|
inputField.ActivateInputField();
|
|
}
|
|
|
|
/// <summary>
|
|
/// What to do when the user uses the scrollwheel while hovering the console input.
|
|
/// </summary>
|
|
public void OnScroll(PointerEventData eventData)
|
|
{
|
|
scrollbar.value += 0.08f * eventData.scrollDelta.y;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Displays the given message as a new entry in the console output.
|
|
/// </summary>
|
|
public void AddNewOutputLine(string line)
|
|
{
|
|
int length = outputText.text.Length;
|
|
if (length > 8192)
|
|
outputText.text = outputText.text.Substring(length - 8192);
|
|
|
|
outputText.text += Environment.NewLine + line;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Clears the console output.
|
|
/// </summary>
|
|
public void ClearOutput()
|
|
{
|
|
outputText.text = "";
|
|
outputText.SetLayoutDirty();
|
|
onClearConsole?.Invoke();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Clears the console input.
|
|
/// </summary>
|
|
public void ClearInput()
|
|
{
|
|
SetInputText("");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Writes the given string into the console input, ready to be user submitted.
|
|
/// </summary>
|
|
public void SetInputText(string input)
|
|
{
|
|
inputField.MoveTextStart(false);
|
|
inputField.text = input;
|
|
inputField.MoveTextEnd(false);
|
|
inputField.caretPosition = inputField.text.Length;
|
|
}
|
|
|
|
public void TabComplete()
|
|
{
|
|
List<string> commandsPrefix = ConsoleCommandsDatabase.CommandsMatchingPrefix(inputField.text);
|
|
List<string> commandsContaining = ConsoleCommandsDatabase.CommandsContainingStrings(
|
|
new string[]
|
|
{
|
|
inputField.text
|
|
}, true);
|
|
|
|
if (commandsPrefix.Count == 0)
|
|
{
|
|
if (commandsContaining.Count == 0)
|
|
{
|
|
AddNewOutputLine("No command contains \"" + inputField.text + "\"");
|
|
return;
|
|
}
|
|
|
|
commandsPrefix = commandsContaining;
|
|
commandsContaining.Clear();
|
|
}
|
|
|
|
if (commandsPrefix.Count == 1)
|
|
{
|
|
SetInputText(commandsPrefix[0]);
|
|
}
|
|
else
|
|
{
|
|
string prefix = LongestCommonPrefix(commandsPrefix);
|
|
if (string.Equals(inputField.text, prefix, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
AddNewOutputLine("<b>Did you mean...</b>");
|
|
commandsPrefix.Sort();
|
|
foreach (var cmd in commandsPrefix)
|
|
{
|
|
AddNewOutputLine(" " + cmd);
|
|
}
|
|
|
|
if (commandsContaining.Count != 0)
|
|
{
|
|
AddNewOutputLine("<b>Or others containing this term...</b>");
|
|
commandsContaining.Sort();
|
|
foreach (var cmd in commandsContaining)
|
|
{
|
|
AddNewOutputLine(" " + cmd);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SetInputText(prefix);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static string LongestCommonPrefix(List<string> strs)
|
|
{
|
|
if (strs == null || strs.Count == 0)
|
|
{
|
|
return "";
|
|
}
|
|
|
|
int minLength = int.MaxValue;
|
|
foreach (var str in strs)
|
|
{
|
|
minLength = Math.Min(minLength, str.Length);
|
|
}
|
|
|
|
int left = 1;
|
|
int right = minLength;
|
|
while (left <= right)
|
|
{
|
|
int mid = (left + right) / 2;
|
|
if (IsCommonPrefix(strs, mid))
|
|
{
|
|
left = mid + 1;
|
|
}
|
|
else
|
|
{
|
|
right = mid - 1;
|
|
}
|
|
}
|
|
|
|
return strs[0].Substring(0, (left + right) / 2);
|
|
}
|
|
|
|
private static bool IsCommonPrefix(List<string> strs, int len)
|
|
{
|
|
string str = strs[0].Substring(0, len);
|
|
for (int index = 1; index < strs.Count; ++index)
|
|
{
|
|
if (!strs[index].StartsWith(str))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
}
|