BITFALL/Assets/BITKit/Unity/Scripts/Console/BITConsole.cs

290 lines
9.3 KiB
C#
Raw Normal View History

2023-11-15 23:54:54 +08:00
using System;
2023-06-08 14:09:50 +08:00
using System.Collections;
2024-01-27 04:09:57 +08:00
using System.Collections.Concurrent;
2023-06-08 14:09:50 +08:00
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;
using BITKit;
using BITKit.UX;
using System.Linq;
using UnityEngine.InputSystem;
using Cysharp.Threading.Tasks;
using System.Text;
using System.IO;
2024-01-27 04:09:57 +08:00
using System.Reflection;
using System.Reflection.Emit;
using Google.Apis.Http;
2023-11-15 23:54:54 +08:00
using UnityEngine.InputSystem.Interactions;
2024-01-27 04:09:57 +08:00
using Label = UnityEngine.UIElements.Label;
2023-11-15 23:54:54 +08:00
2023-06-08 14:09:50 +08:00
namespace BITKit.Console
{
2023-11-15 23:54:54 +08:00
public class BITConsole : MonoBehaviour
2023-06-08 14:09:50 +08:00
{
[BITCommand]
2023-11-15 23:54:54 +08:00
public static async void Clear()
2023-06-08 14:09:50 +08:00
{
2023-11-15 23:54:54 +08:00
await BITApp.SwitchToMainThread();
2023-06-08 14:09:50 +08:00
singleton.outputString.Clear();
singleton.text.text = string.Empty;
}
2024-01-27 04:09:57 +08:00
private static BITConsole singleton;
2023-11-15 23:54:54 +08:00
[SerializeField] private UIDocument document;
[SerializeReference] private InputActionReference toggleAction;
[SerializeReference] public InputActionReference nextOrPreviousAction;
2024-01-27 04:09:57 +08:00
private static ConcurrentQueue<(string condition, string stackTrace, LogType type)> logQueue = new();
private static void EnqueueLog(string condition, string stackTrace, LogType type)
{
logQueue.Enqueue((condition, stackTrace, type));
}
2023-11-15 23:54:54 +08:00
private readonly InputActionGroup _inputActionGroup=new()
{
allowGlobalActivation = false
};
2023-06-08 14:09:50 +08:00
public int logLineLimit = 64;
2024-01-27 04:09:57 +08:00
[UXBindPath("commands-listview")]
2023-11-15 23:54:54 +08:00
private ListView commandListView;
2024-01-27 04:09:57 +08:00
[UXBindPath("TextField")]
2023-08-12 01:43:24 +08:00
private TextField textField;
2024-01-27 04:09:57 +08:00
[UXBindPath("Text")]
2023-08-12 01:43:24 +08:00
private Label text;
2024-01-27 04:09:57 +08:00
[UXBindPath( "context-scrollview")]
2023-08-12 01:43:24 +08:00
private ScrollView scrollView;
2024-01-27 04:09:57 +08:00
private bool _isRunning;
2023-08-12 01:43:24 +08:00
private List<string> outputString = new();
2024-01-27 04:09:57 +08:00
private (MethodInfo[] methods,int currentIndex) _currentCommands;
2023-11-15 23:54:54 +08:00
private void Start()
{
2023-06-08 14:09:50 +08:00
singleton = this;
2024-01-27 04:09:57 +08:00
UXUtils.Inject(this);
2023-06-08 14:09:50 +08:00
textField.RegisterValueChangedCallback(OnTextFieldValieChanged);
textField.RegisterCallback<KeyDownEvent>(OnKeyDown);
2023-08-12 01:43:24 +08:00
commandListView.selectionChanged += OnSelectionChange;
2023-06-08 14:09:50 +08:00
nextOrPreviousAction.action.performed += OnNextCommand;
text.text = string.Empty;
commandListView.SetActive(false);
2023-11-15 23:54:54 +08:00
_inputActionGroup.RegisterCallback(toggleAction,Toggle);
2024-01-27 04:09:57 +08:00
//_inputActionGroup.RegisterCallback(nextOrPreviousAction, OnNextCommand);
2023-11-15 23:54:54 +08:00
_inputActionGroup.allowInput.AddElement(this);
Toggle(false);
2024-01-27 04:09:57 +08:00
BIT4Log.OnNextLine += OnNextLine;
destroyCancellationToken.Register(() =>
{
BIT4Log.OnNextLine -= OnNextLine;
});
}
private void OnEnable()
{
Application.logMessageReceived += EnqueueLog;
}
private void OnDisable()
{
Application.logMessageReceived -= EnqueueLog;
}
private void OnNextLine()
{
if (outputString.Count is not 0 && outputString.Last() != string.Empty)
outputString.Add(string.Empty);
2023-06-08 14:09:50 +08:00
}
2023-08-12 01:43:24 +08:00
private void OnDestroy()
2023-06-08 14:09:50 +08:00
{
2023-11-15 23:54:54 +08:00
_inputActionGroup.allowInput.RemoveElement(this);
2023-06-08 14:09:50 +08:00
}
2023-11-15 23:54:54 +08:00
public async void Toggle(bool active)
2023-06-08 14:09:50 +08:00
{
2023-11-15 23:54:54 +08:00
document.rootVisualElement.SetActive(active);
2024-01-27 04:09:57 +08:00
_isRunning = active;
2023-11-15 23:54:54 +08:00
BITAppForUnity.AllowCursor.SetElements(this,active);
BITInputSystem.AllowInput.SetDisableElements(this,active);
2023-06-08 14:09:50 +08:00
await UniTask.WaitForEndOfFrame(this);
if (active)
{
textField.SetValueWithoutNotify(string.Empty);
textField.Focus();
scrollView.ScrollToBottom();
}
else
{
text.Blur();
}
}
2023-11-15 23:54:54 +08:00
private void OnTextFieldValieChanged(ChangeEvent<string> callback)
2023-06-08 14:09:50 +08:00
{
if (callback.newValue.IsValid())
{
2023-08-12 01:43:24 +08:00
var commands = BITCommands.GetMethodInfos(callback.newValue).Select(x => x.Name).ToList();
2023-06-08 14:09:50 +08:00
if (commands.Count is 0)
{
commandListView.SetActive(false);
}
else
{
commandListView.itemsSource = commands;
commandListView.SetActive(true);
}
}
else
{
commandListView.SetActive(false);
}
}
2023-08-12 01:43:24 +08:00
private void OnDropdownValueChanged(ChangeEvent<string> callback)
2023-06-08 14:09:50 +08:00
{
textField.SetValueWithoutNotify(callback.newValue);
OnTextFieldValieChanged(callback);
2024-01-27 04:09:57 +08:00
textField.Blur();
2023-06-08 14:09:50 +08:00
textField.Focus();
}
2023-08-12 01:43:24 +08:00
private void OnNextCommand(InputAction.CallbackContext context)
2023-06-08 14:09:50 +08:00
{
2024-01-27 04:09:57 +08:00
switch (context)
2023-06-08 14:09:50 +08:00
{
2024-01-27 04:09:57 +08:00
case { interaction: PressInteraction, performed: true }:
//var index = context.ReadValue<float>();
if (int.TryParse(context.ReadValue<float>().ToString(), out var index) is false) return;
_currentCommands = (BITCommands.GetMethodInfos(textField.text).ToArray(),index);
break;
2023-06-08 14:09:50 +08:00
}
}
2024-01-27 04:09:57 +08:00
private async void OnKeyDown(KeyDownEvent keyDownEvent)
2023-06-08 14:09:50 +08:00
{
switch (keyDownEvent.keyCode)
{
case KeyCode.Return:
var cmd = textField.text;
LogCallback($">{cmd}", string.Empty, LogType.Log);
textField.SetValueWithoutNotify(string.Empty);
2024-01-27 04:09:57 +08:00
await UniTask.NextFrame();
if (destroyCancellationToken.IsCancellationRequested) return;
textField.Blur();
2023-06-08 14:09:50 +08:00
textField.Focus();
2023-08-12 01:43:24 +08:00
BITCommands.Excute(cmd);
2023-06-08 14:09:50 +08:00
break;
case KeyCode.Tab:
break;
2024-01-27 04:09:57 +08:00
case KeyCode.DownArrow when string.IsNullOrEmpty(textField.text) is false:
textField.cursorIndex -= 1;
break;
case KeyCode.UpArrow when string.IsNullOrEmpty(textField.text) is false:
textField.cursorIndex += 1;
break;
2023-06-08 14:09:50 +08:00
}
}
2023-11-15 23:54:54 +08:00
private void Toggle(InputAction.CallbackContext context)
2023-06-08 14:09:50 +08:00
{
2023-11-15 23:54:54 +08:00
switch (context)
2023-06-08 14:09:50 +08:00
{
2023-11-15 23:54:54 +08:00
case { interaction: PressInteraction, performed: true }:
2024-01-27 04:09:57 +08:00
Toggle(!_isRunning);
2023-06-08 14:09:50 +08:00
break;
}
2023-11-15 23:54:54 +08:00
}
2023-06-08 14:09:50 +08:00
2023-11-15 23:54:54 +08:00
private async void LogCallback(string condition, string stackTrace, LogType type)
{
2023-06-08 14:09:50 +08:00
try
{
2023-11-15 23:54:54 +08:00
switch (type)
{
case LogType.Error:
outputString.Add($"<color=red>{condition}</color>");
break;
case LogType.Warning:
outputString.Add($"<color=yellow>{condition}</color>");
break;
case LogType.Exception:
outputString.Add($"<color=red>{condition}</color>");
outputString.Add($"<color=red>{stackTrace}</color>");
break;
default:
outputString.Add(condition);
break;
}
var length = outputString.Count;
if (length > logLineLimit)
{
outputString = outputString.GetRange(length - logLineLimit, logLineLimit);
}
StringBuilder stringBuilder = new();
outputString.ForEach(x => stringBuilder.AppendLine(x));
try
{
await BITApp.SwitchToMainThread();
scrollView.ScrollToBottomAutomatic();
text.text = stringBuilder.ToString();
2024-01-27 04:09:57 +08:00
2023-11-15 23:54:54 +08:00
}
catch (OperationCanceledException)
{
}
2023-06-08 14:09:50 +08:00
}
2023-11-15 23:54:54 +08:00
catch (Exception e)
2023-06-08 14:09:50 +08:00
{
2023-11-15 23:54:54 +08:00
Debug.LogException(e);
2023-06-08 14:09:50 +08:00
}
}
2023-08-12 01:43:24 +08:00
private void Update()
2023-06-08 14:09:50 +08:00
{
2024-01-27 04:09:57 +08:00
while (logQueue.TryDequeue(out var log))
{
LogCallback(log.condition, log.stackTrace, log.type);
}
if (_isRunning is false) return;
2023-06-08 14:09:50 +08:00
var pos = textField.worldTransform.GetPosition();
var size = textField.layout.size;
commandListView.style.left = 0;
commandListView.style.top = 0;
pos.y += size.y;
commandListView.transform.position = pos;
commandListView.style.width = size.x;
}
2023-11-15 23:54:54 +08:00
private void OnSelectionChange(IEnumerable<object> selected)
2023-06-08 14:09:50 +08:00
{
var _selected = selected.First() as string;
textField.SetValueWithoutNotify(_selected);
commandListView.itemsSource?.Clear();
commandListView.SetActive(false);
}
}
}