Files
ichni_Creator_Studio/Assets/Scripts/Console/EditorConsole.cs
2025-06-09 12:42:23 +08:00

283 lines
10 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.Generic;
using UnityEngine;
using DynamicExpresso;
using System.Text.RegularExpressions;
using System.Linq;
using UnityEngine.InputSystem;
using TMPro;
using System.Reflection;
using System.Linq.Expressions;
using Sirenix.Utilities;
//又在写大粪 ——神币
namespace Ichni.Editor
{
public partial class EditorConsole : MonoBehaviour
{
public Interpreter functionInterpreter;
public TMP_InputField InputCommand;
private Dictionary<int, string> historyCommand = new Dictionary<int, string>();
private int historycount = 0;
public GameObject ConsoleUI;
public TMP_Text cueText;
bool isHide = true;
private string FillCueCommand(MethodInfo method)
{
if (method == null)
{
return "";
}
string methodName = method.Name;
// 3. 获取参数信息
var parameters = method.GetParameters();
if (parameters.Length == 0)
{
return $"{methodName} " + "\n";
}
// 4. 生成参数提示
string paramHint = string.Join(" ", parameters.Select(p =>
p.IsOptional ? $"[{p.ParameterType.Name}:{p.Name}]" : $"{p.ParameterType.Name}:{p.Name}"
));
return $"{methodName} {paramHint}".Trim() + "\n";
}
public void GetChange(string change)
{
if (change == "help")
{
List<MethodInfo> Allmethods = typeof(EditorConsoleMethods).GetMethods().
Where(m => m.IsStatic && m.IsPublic && m.ReturnType == typeof(void)).
ToList();
cueText.text = "";
foreach (MethodInfo method in Allmethods)
{
cueText.text += FillCueCommand(method);
}
return;
}
// Task t = new Task(() =>
// {
// 1. 提取命令名
string trimmed = change.Trim();
if (string.IsNullOrEmpty(trimmed))
{
cueText.text = "";
return;
}
// 支持 func(...) 或 func abc 123
var match = Regex.Match(trimmed, @"^(\w+)");
if (!match.Success)
{
cueText.text = "";
return;
}
string funcName = match.Groups[1].Value;
// 2. 查找方法
List<MethodInfo> methods = typeof(EditorConsoleMethods).GetMethods()
.Where(m => m.IsStatic && m.IsPublic && m.ReturnType == typeof(void) && m.Name.Contains(funcName)).ToList();
cueText.text = "";
foreach (MethodInfo method in methods)
{
cueText.text += FillCueCommand(method);
}
if (cueText.text.IsNullOrWhitespace())
{
cueText.text = "No matching commands found.";
}
// });
// t.RunSynchronously();
}
public void GetCommand(string Command)//当提交命令时
{
try
{
functionInterpreter.Eval(Command);
}
catch (Exception e)
{
Debug.LogWarning("WTF Command! " + e);
LogWindow.Log("Unknow Command!", Color.red);
}
}
private void Update()
{
UIscale();
if (InputCommand.isFocused) InputDect();
}
private void UIscale()
{
if (Keyboard.current.backquoteKey.wasPressedThisFrame)
{
ConsoleUI.SetActive(isHide);
isHide = !isHide;
if (!isHide) StartCoroutine(WindowAnim.ShowPanelOnScale(InputCommand.gameObject));
}
}
//这是史,不要看
private void InputDect()
{
// 向下翻历史命令
if (Keyboard.current.downArrowKey.wasPressedThisFrame)
{
if (historyCommand.Count - 1 > historycount)
{
historycount++;
InputCommand.text = historyCommand[historycount];
}
else
{
InputCommand.text = "";
historycount = historyCommand.Count;
}
return;
}
// 向上翻历史命令
if (Keyboard.current.upArrowKey.wasPressedThisFrame && historycount != 0)
{
historycount--;
InputCommand.text = historyCommand[historycount];
return;
}
// 提交命令
if (Keyboard.current.enterKey.wasPressedThisFrame)
{
string input = InputCommand.text;
if (string.IsNullOrWhiteSpace(input))
{
InputCommand.text = "";
return;
}
string ExpoCommand = TransformCommand(input);
print(ExpoCommand);
GetCommand(ExpoCommand);
// 记录历史命令
if (historyCommand.ContainsKey(historycount))
historyCommand[historycount] = input;
else
historyCommand.Add(historycount, input);
historycount++;
InputCommand.text = "";
}
}
private string TransformCommand(string input)
{
// 处理命令格式,适配 DynamicExpresso
string trimmed = input.Trim();
// 1. 直接支持 func(...) 形式
if (Regex.IsMatch(trimmed, @"^\w+\s*\(.*\)$"))
return trimmed;
// 2. 直接支持赋值表达式
if (trimmed.Contains("="))
return trimmed;
// 3. 支持 func abc 123 [1,2,3] 形式
var match = Regex.Match(trimmed, @"^(\w+)\s*(.*)$");
if (match.Success)
{
string func = match.Groups[1].Value;
string args = match.Groups[2].Value.Trim();
// 匹配参数:中括号、引号、或连续非空白
var argMatches = Regex.Matches(args, @"(\[[^\]]+\]|""(?:[^""\\]|\\.)*""|\S+)");
var argList = argMatches.Cast<Match>().Select(m => m.Value).ToList();
List<string> processedArgs = new List<string>();
foreach (var arg in argList)
{
string a = arg.Trim();
// Vector2/3: [1,2] 或 [1,2,3]
if (Regex.IsMatch(a, @"^\[\s*-?\d+(\.\d+)?\s*,\s*-?\d+(\.\d+)?(\s*,\s*-?\d+(\.\d+)?)*\s*\]$"))
{
// 去除中括号和空格
string content = a.Substring(1, a.Length - 2).Trim();
var nums = content.Split(',').Select(s => s.Trim()).ToArray();
if (nums.Length == 2)
processedArgs.Add($"new Vector2({nums[0]},{nums[1]})");
else if (nums.Length == 3)
processedArgs.Add($"new Vector3({nums[0]},{nums[1]},{nums[2]})");
else
processedArgs.Add(a); // 不是2或3维原样返回
}
// 已有引号的字符串
else if (a.StartsWith("\"") && a.EndsWith("\""))
{
processedArgs.Add(a);
}
// 数字
else if (Regex.IsMatch(a, @"^-?\d+(\.\d+)?$"))
{
processedArgs.Add(a);
}
// 变量名(字母开头,允许字母数字下划线)
else if (Regex.IsMatch(a, @"^[a-zA-Z_]\w*$"))
{
processedArgs.Add(a);
}
// 其它未加引号的参数,自动加引号
else
{
processedArgs.Add($"\"{a}\"");
}
}
string joinedArgs = string.Join(",", processedArgs);
return string.IsNullOrEmpty(joinedArgs) ? $"{func}()" : $"{func}({joinedArgs})";
}
return trimmed;
}
private void Start()
{
SetUpFunctions();
//Test
// functionInterpreter.Eval("print(\"Hello World!\")");
// functionInterpreter.Eval("log(\"Hello World but debug!\")");
}
}
public partial class EditorConsole
{
public Inspector inspector => EditorManager.instance.uiManager.inspector;
public Hierarchy hierarchy => EditorManager.instance.uiManager.hierarchy;
public LogWindow logWindow => EditorManager.instance.uiManager.mainPage.logWindow;
public List<string> commandList = new List<string>();
public void SetUpFunctions()
{
functionInterpreter = new Interpreter()
.Reference(typeof(Vector3))
.Reference(typeof(Vector2));//这是AI给的东西
foreach (MethodInfo i in typeof(EditorConsoleMethods).GetMethods().
ToList().Where(i => i.IsStatic && i.IsPublic && i.ReturnType == typeof(void)))
{
var parameters = i.GetParameters().Select(p => p.ParameterType).ToArray();
var delegateType = Expression.GetDelegateType(parameters.Concat(new[] { i.ReturnType }).ToArray());
functionInterpreter.SetFunction(i.Name, i.CreateDelegate(delegateType));
commandList.Add(i.Name);
}
}
}
}