Files
ichni_Creator_Studio/Assets/Scripts/Console/EditorConsole.cs

296 lines
10 KiB
C#
Raw Normal View History

using System;
using System.Collections.Generic;
using UnityEngine;
using DynamicExpresso;
2025-02-04 15:05:05 +08:00
using System.Text.RegularExpressions;
using System.Linq;
2025-02-14 22:04:21 -05:00
using UnityEngine.InputSystem;
using TMPro;
2025-05-04 16:41:23 +08:00
using System.Reflection;
using System.Linq.Expressions;
using Sirenix.Utilities;
using System.Collections;
using DG.Tweening;
2025-02-14 22:04:21 -05:00
//又在写大粪 ——神币
namespace Ichni.Editor
{
public partial class EditorConsole : MonoBehaviour
{
public Interpreter functionInterpreter;
public TMP_InputField InputCommand;
2025-02-22 00:05:36 +08:00
private Dictionary<int, string> historyCommand = new Dictionary<int, string>();
private int historycount = 0;
2025-02-04 15:05:05 +08:00
public GameObject ConsoleUI;
public TMP_Text cueText;
2025-02-22 00:05:36 +08:00
bool isHide = true;
2025-06-08 12:57:49 +08:00
private string FillCueCommand(MethodInfo method)
{
if (method == null)
{
return "";
}
string methodName = method.Name;
// 3. 获取参数信息
var parameters = method.GetParameters();
if (parameters.Length == 0)
{
2025-02-22 00:05:36 +08:00
2025-06-08 12:57:49 +08:00
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";
}
2025-02-22 00:05:36 +08:00
public void GetChange(string change)
{
2025-06-08 12:57:49 +08:00
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)
{
2025-06-08 12:57:49 +08:00
cueText.text += FillCueCommand(method);
}
if (cueText.text.IsNullOrWhitespace())
{
cueText.text = "No matching commands found.";
}
// });
// t.RunSynchronously();
}
public void GetCommand(string Command)//当提交命令时
2025-02-04 15:05:05 +08:00
{
2025-02-22 00:05:36 +08:00
try
{
functionInterpreter.Eval(Command);
}
catch (Exception e)
{
Debug.LogWarning("WTF Command! " + e);
LogWindow.Log("Unknow Command!", Color.red);
}
2025-02-04 15:05:05 +08:00
}
2025-02-22 00:05:36 +08:00
private void Update()
{
UIscale();
2025-02-22 00:05:36 +08:00
if (InputCommand.isFocused) InputDect();
}
2025-02-22 00:05:36 +08:00
private void UIscale()
{
if (Keyboard.current.backquoteKey.wasPressedThisFrame)
{
2025-02-22 00:05:36 +08:00
isHide = !isHide;
if (!isHide)
{
ConsoleUI.SetActive(true);
}
else
ConsoleUI.SetActive(false);
}
}
2025-02-22 00:05:36 +08:00
//这是史,不要看
private void InputDect()
{
2025-06-07 15:09:22 +08:00
// 向下翻历史命令
2025-02-22 00:05:36 +08:00
if (Keyboard.current.downArrowKey.wasPressedThisFrame)
{
if (historyCommand.Count - 1 > historycount)
{
historycount++;
InputCommand.text = historyCommand[historycount];
}
2025-02-22 00:05:36 +08:00
else
{
InputCommand.text = "";
historycount = historyCommand.Count;
}
2025-06-07 15:09:22 +08:00
return;
2025-02-22 00:05:36 +08:00
}
2025-06-07 15:09:22 +08:00
// 向上翻历史命令
2025-02-22 00:05:36 +08:00
if (Keyboard.current.upArrowKey.wasPressedThisFrame && historycount != 0)
{
historycount--;
InputCommand.text = historyCommand[historycount];
2025-06-07 15:09:22 +08:00
return;
2025-02-22 00:05:36 +08:00
}
2025-06-07 15:09:22 +08:00
// 提交命令
2025-02-22 00:05:36 +08:00
if (Keyboard.current.enterKey.wasPressedThisFrame)
{
2025-06-07 15:09:22 +08:00
string input = InputCommand.text;
if (string.IsNullOrWhiteSpace(input))
2025-02-22 00:05:36 +08:00
{
2025-06-07 15:09:22 +08:00
InputCommand.text = "";
return;
2025-02-22 00:05:36 +08:00
}
string ExpoCommand = TransformCommand(input);
2025-06-07 15:09:22 +08:00
2025-02-22 00:05:36 +08:00
print(ExpoCommand);
GetCommand(ExpoCommand);
2025-06-07 15:09:22 +08:00
// 记录历史命令
if (historyCommand.ContainsKey(historycount))
historyCommand[historycount] = input;
else
historyCommand.Add(historycount, input);
2025-02-22 00:05:36 +08:00
historycount++;
InputCommand.text = "";
}
}
private string TransformCommand(string input)
{
string getFloatorInt(string a)
{
return a.Contains(".") ? $"{a}f" : a;
}
// 处理命令格式,适配 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();
2025-02-22 00:05:36 +08:00
// 匹配参数:中括号、引号、或连续非空白
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({getFloatorInt(nums[0])},{getFloatorInt(nums[1])})");
else if (nums.Length == 3)
processedArgs.Add($"new Vector3({getFloatorInt(nums[0])},{getFloatorInt(nums[1])},{getFloatorInt(nums[2])})");
else
processedArgs.Add(a); // 不是2或3维原样返回
}
// 已有引号的字符串
else if (a.StartsWith("\"") && a.EndsWith("\""))
{
processedArgs.Add(a);
}
// 数字
else if (Regex.IsMatch(a, @"^-?\d+(\.\d+)?([eE][+-]?\d+)?$"))
{
processedArgs.Add(getFloatorInt(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()
{
2025-02-22 00:05:36 +08:00
SetUpFunctions();
2025-02-22 00:05:36 +08:00
//Test
// functionInterpreter.Eval("print(\"Hello World!\")");
// functionInterpreter.Eval("log(\"Hello World but debug!\")");
}
}
2025-02-22 00:05:36 +08:00
public partial class EditorConsole
{
2025-05-04 16:41:23 +08:00
public Inspector inspector => EditorManager.instance.uiManager.inspector;
public Hierarchy hierarchy => EditorManager.instance.uiManager.hierarchy;
public LogWindow logWindow => EditorManager.instance.uiManager.mainPage.logWindow;
2025-02-22 00:05:36 +08:00
2025-05-04 16:41:23 +08:00
public List<string> commandList = new List<string>();
public void SetUpFunctions()
{
functionInterpreter = new Interpreter()
.Reference(typeof(Vector3))
.Reference(typeof(Vector2));//这是AI给的东西
2025-05-04 16:41:23 +08:00
foreach (MethodInfo i in typeof(EditorConsoleMethods).GetMethods().
ToList().Where(i => i.IsStatic && i.IsPublic && (i.ReturnType == typeof(void))))
2025-05-04 16:41:23 +08:00
{
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);
}
}
2025-05-04 16:41:23 +08:00
}
}