From c0e72b565ba2367f8e80c87cf0787dff772b7714 Mon Sep 17 00:00:00 2001 From: Saplonily Date: Thu, 29 Dec 2022 18:11:07 +0800 Subject: [PATCH] =?UTF-8?q?SimCommand=E7=8E=B0=E5=9C=A8=E6=94=AF=E6=8C=81p?= =?UTF-8?q?arams=E7=B1=BB=E5=9E=8B=E7=9A=84=E5=85=A5=E5=8F=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SaladimQBot.Extensions/SimCommandExecutor.cs | 149 +++++++++++------- SaladimSimCmd/Program.cs | 10 +- .../PublishProfiles/FolderProfile.pubxml.user | 2 +- SaladimWpf/SimCmdModules/TextMisc.cs | 30 ++-- 4 files changed, 113 insertions(+), 78 deletions(-) diff --git a/SaladimQBot.Extensions/SimCommandExecutor.cs b/SaladimQBot.Extensions/SimCommandExecutor.cs index 3a3d0fa..1595097 100644 --- a/SaladimQBot.Extensions/SimCommandExecutor.cs +++ b/SaladimQBot.Extensions/SimCommandExecutor.cs @@ -11,7 +11,7 @@ public sealed partial class SimCommandExecutor { public static readonly Type StringType = typeof(string); public static readonly Regex CommandParamRegex = new("(\"[^\"]*\")|[^\\s]+", RegexOptions.Compiled); - public static char SplitChar { get; set; } = ','; + public static char ArraySplitChar { get; set; } = ','; private readonly List commands; private readonly Func moduleInstanceFactory; @@ -46,22 +46,22 @@ public SimCommandExecutor(string rootCommandPrefix) [typeof(Vector2)] = s => CommonTypeParsers.Vector2(s), [typeof(Vector3)] = s => CommonTypeParsers.Vector3(s), - [typeof(int[])] = s => CommonTypeParsers.ArrayPacker(s, CommonTypeParsers.Int, SplitChar), - [typeof(uint[])] = s => CommonTypeParsers.ArrayPacker(s, CommonTypeParsers.Uint, SplitChar), - [typeof(byte[])] = s => CommonTypeParsers.ArrayPacker(s, CommonTypeParsers.Byte, SplitChar), - [typeof(char[])] = s => CommonTypeParsers.ArrayPacker(s, CommonTypeParsers.Char, SplitChar), - [typeof(long[])] = s => CommonTypeParsers.ArrayPacker(s, CommonTypeParsers.Long, SplitChar), - [typeof(sbyte[])] = s => CommonTypeParsers.ArrayPacker(s, CommonTypeParsers.Sbyte, SplitChar), - [typeof(float[])] = s => CommonTypeParsers.ArrayPacker(s, CommonTypeParsers.Float, SplitChar), - [typeof(short[])] = s => CommonTypeParsers.ArrayPacker(s, CommonTypeParsers.Short, SplitChar), - [typeof(ulong[])] = s => CommonTypeParsers.ArrayPacker(s, CommonTypeParsers.Ulong, SplitChar), - [typeof(Color[])] = s => CommonTypeParsers.ArrayPacker(s, CommonTypeParsers.Color, SplitChar), - [typeof(ushort[])] = s => CommonTypeParsers.ArrayPacker(s, CommonTypeParsers.Ushort, SplitChar), - [typeof(double[])] = s => CommonTypeParsers.ArrayPacker(s, CommonTypeParsers.Double, SplitChar), - [typeof(Vector2[])] = s => CommonTypeParsers.ArrayPacker(s, CommonTypeParsers.Vector2, SplitChar), - [typeof(Vector3[])] = s => CommonTypeParsers.ArrayPacker(s, CommonTypeParsers.Vector3, SplitChar), - - [typeof(string[])] = s => CommonTypeParsers.ArrayPacker(s, s => s, SplitChar), + [typeof(int[])] = s => CommonTypeParsers.ArrayPacker(s, CommonTypeParsers.Int, ArraySplitChar), + [typeof(uint[])] = s => CommonTypeParsers.ArrayPacker(s, CommonTypeParsers.Uint, ArraySplitChar), + [typeof(byte[])] = s => CommonTypeParsers.ArrayPacker(s, CommonTypeParsers.Byte, ArraySplitChar), + [typeof(char[])] = s => CommonTypeParsers.ArrayPacker(s, CommonTypeParsers.Char, ArraySplitChar), + [typeof(long[])] = s => CommonTypeParsers.ArrayPacker(s, CommonTypeParsers.Long, ArraySplitChar), + [typeof(sbyte[])] = s => CommonTypeParsers.ArrayPacker(s, CommonTypeParsers.Sbyte, ArraySplitChar), + [typeof(float[])] = s => CommonTypeParsers.ArrayPacker(s, CommonTypeParsers.Float, ArraySplitChar), + [typeof(short[])] = s => CommonTypeParsers.ArrayPacker(s, CommonTypeParsers.Short, ArraySplitChar), + [typeof(ulong[])] = s => CommonTypeParsers.ArrayPacker(s, CommonTypeParsers.Ulong, ArraySplitChar), + [typeof(Color[])] = s => CommonTypeParsers.ArrayPacker(s, CommonTypeParsers.Color, ArraySplitChar), + [typeof(ushort[])] = s => CommonTypeParsers.ArrayPacker(s, CommonTypeParsers.Ushort, ArraySplitChar), + [typeof(double[])] = s => CommonTypeParsers.ArrayPacker(s, CommonTypeParsers.Double, ArraySplitChar), + [typeof(Vector2[])] = s => CommonTypeParsers.ArrayPacker(s, CommonTypeParsers.Vector2, ArraySplitChar), + [typeof(Vector3[])] = s => CommonTypeParsers.ArrayPacker(s, CommonTypeParsers.Vector3, ArraySplitChar), + + [typeof(string[])] = s => CommonTypeParsers.ArrayPacker(s, s => s, ArraySplitChar), }; moduleInstanceFactory = Activator.CreateInstance; } @@ -99,23 +99,26 @@ public void MatchAndExecuteAll(IMessage msg) return true; return false; }) - //trim它 + //trim掉前后的空格 .Select(node => node.Text.Trim()); - //遍历这些文本节点 + + //遍历这些文本节点, 执行所有的指令 foreach (var matchedNodeText in matchedNodeTexts) { var cmdTextWithoutRootPrefix = matchedNodeText.AsSpan(RootCommandPrefix.Length); //现在这个字符串就形如 "add 1 2 3" 了 - //切分, 但忽略引号内的空格, 同时去除引号 + //以空格切分, 但忽略引号内的空格, 同时去除引号 var matches = CommandParamRegex.Matches(cmdTextWithoutRootPrefix.ToString()); if (matches.Count == 0) continue; string[] argAsString = new string[matches.Count - 1]; + //现在我们得到了它的参数的以字符串形式的参数数组 + //开始查找所有符合的指令 foreach (var cmd in commands) { if (cmd.Name == matches[0].Value) { - //昵称相同, 现在检查参数数目是否相同 - if (cmd.Parameters.Length != matches.Count - 1) + //昵称相同, 现在检查参数数目是否相同(如果不是params指令的话) + if (cmd.Parameters.Length != matches.Count - 1 && !cmd.IsParamsCommand) continue; //昵称相同参数相同, 生成参数字符串数组传递给ExecuteInternal让其解析为对应值 //并调用最后的实体方法 @@ -132,54 +135,81 @@ public void MatchAndExecuteAll(IMessage msg) internal bool ExecuteInternal(IMessage msg, MethodBasedCommand cmd, string[]? cmdParams) { var paramsLength = cmd.Parameters.Length; - Debug.Assert(cmd.Parameters.Length == cmdParams?.Length); + if (cmd.Parameters.Length != cmdParams?.Length && !cmd.IsParamsCommand) + return false; + if (moduleInstanceFactory?.Invoke(cmd.Method.DeclaringType!) is not CommandModule moduleIns) return false; moduleIns.Content = new(this, msg); - if (moduleIns.PreCheck(moduleIns.Content)) + if (!moduleIns.PreCheck(moduleIns.Content)) + return false; + + var paramsTypes = from p in cmd.Parameters select p.ParameterType; + if (cmd.IsParamsCommand) { - var paramsTypes = - from p in cmd.Parameters - select p.ParameterType; if (cmdParams is null) { - cmd.Method.Invoke(moduleIns, null); + cmd.Method.Invoke(moduleIns, new object[] { }); return true; } - else if (paramsTypes.All(t => t == StringType)) + else { - cmd.Method.Invoke(moduleIns, cmdParams); + Type baseType = cmd.Parameters[0].ParameterType.GetElementType(); + var invokingParamsTypes = Enumerable.Repeat(baseType, cmdParams.Length); + var array = Array.CreateInstance(baseType, cmdParams.Length); + object[]? paramObjects = ParseParams(cmdParams, invokingParamsTypes); + if (paramObjects is null) return false; + paramObjects.CopyTo(array, 0); + cmd.Method.Invoke(moduleIns, new object[] { array }); return true; } - else + } + + if (cmdParams is null) + { + cmd.Method.Invoke(moduleIns, null); + return true; + } + else if (paramsTypes.All(t => t == StringType)) + { + cmd.Method.Invoke(moduleIns, cmdParams); + return true; + } + else + { + object[]? paramObjects = ParseParams(cmdParams, paramsTypes); + if (paramObjects is null) return false; + cmd.Method.Invoke(moduleIns, paramObjects); + return true; + } + } + + internal object[]? ParseParams(string[] stringParams, IEnumerable paramsTypes) + { + var paramsLength = stringParams.Length; + object[] paramObjects = new object[paramsLength]; + for (int i = 0; i < paramsLength; i++) + { + Type paramsType = paramsTypes.ElementAt(i); + if (paramsType == StringType) { - object[] paramObjects = new object[paramsLength]; - for (int i = 0; i < paramsLength; i++) - { - Type paramsType = paramsTypes.ElementAt(i); - if (paramsType == StringType) - { - paramObjects[i] = cmdParams[i]; - continue; - } - if (!CommandParamParsers.TryGetValue(paramsType, out var parser)) - throw new KeyNotFoundException($"Not found parser for type `{paramsType}`"); - try - { - var parsedValue = parser(cmdParams[i]); - if (parsedValue is null) - return false; - paramObjects[i] = parsedValue; - } - catch - { - return false; - } - } - cmd.Method.Invoke(moduleIns, paramObjects); - return true; + paramObjects[i] = stringParams[i]; + continue; + } + if (!CommandParamParsers.TryGetValue(paramsType, out var parser)) + throw new KeyNotFoundException($"Not found parser for type `{paramsType}`"); + try + { + var parsedValue = parser(stringParams[i]); + if (parsedValue is null) + return null; + paramObjects[i] = parsedValue; + } + catch + { + return null; } } - return false; + return paramObjects; } public async Task MatchAndExecuteAllAsync(IMessage msg) @@ -191,11 +221,16 @@ internal class MethodBasedCommand public string Name; public MethodInfo Method; public ParameterInfo[] Parameters; + public bool IsParamsCommand = false; public MethodBasedCommand(string name, MethodInfo method) { Name = name; Method = method; Parameters = method.GetParameters(); + if (Parameters.Length != 0) + { + IsParamsCommand = Parameters[0].GetCustomAttributes().Any(); + } } } \ No newline at end of file diff --git a/SaladimSimCmd/Program.cs b/SaladimSimCmd/Program.cs index dc1e2a0..a55533c 100644 --- a/SaladimSimCmd/Program.cs +++ b/SaladimSimCmd/Program.cs @@ -1,4 +1,5 @@ -using System.Drawing; +using System.Diagnostics; +using System.Drawing; using System.Numerics; using System.Text; using Saladim.SalLogger; @@ -27,10 +28,13 @@ public static async Task Main(string[] args) private static void Client_OnGroupMessageReceived(GroupMessage message, JoinedGroup group) { + Stopwatch stopwatch = new(); + stopwatch.Start(); if (message.Group.GroupId == 860355679) { - simCmd.MatchAndExecuteAll(message); + _ = simCmd.MatchAndExecuteAllAsync(message); } + stopwatch.Stop(); } } @@ -83,7 +87,7 @@ public void GetVector3(Vector3 vector) } [Command("choose")] - public void Choose(string[] strs) + public void Choose(params string[] strs) { StringBuilder sb = new(); sb.AppendLine("你给出了如下的东西, 以\" | \"分隔"); diff --git a/SaladimWpf/Properties/PublishProfiles/FolderProfile.pubxml.user b/SaladimWpf/Properties/PublishProfiles/FolderProfile.pubxml.user index 84cd7ee..22ce3b2 100644 --- a/SaladimWpf/Properties/PublishProfiles/FolderProfile.pubxml.user +++ b/SaladimWpf/Properties/PublishProfiles/FolderProfile.pubxml.user @@ -4,7 +4,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121. --> - True|2022-12-28T08:24:51.9861635Z;True|2022-12-28T16:23:44.1004953+08:00;True|2022-12-28T16:21:08.2353403+08:00;True|2022-12-28T16:20:56.6429409+08:00;True|2022-12-23T19:22:48.4392831+08:00;True|2022-12-21T22:23:35.9045939+08:00;True|2022-12-21T22:18:16.0962966+08:00;True|2022-12-21T20:54:02.6827032+08:00;True|2022-12-21T20:52:52.1827338+08:00;True|2022-12-21T20:52:06.8220342+08:00;True|2022-12-21T20:51:17.2555457+08:00;True|2022-12-18T21:48:23.3182037+08:00;False|2022-12-18T21:46:45.4066089+08:00;False|2022-12-18T21:46:32.1453050+08:00;True|2022-12-18T21:45:56.8222951+08:00;True|2022-12-18T19:21:18.8207927+08:00;True|2022-12-17T22:46:09.3784351+08:00;True|2022-12-17T21:59:08.8587742+08:00;True|2022-12-17T20:48:28.8245676+08:00;True|2022-12-17T20:34:01.3071499+08:00;True|2022-12-17T20:32:23.5134227+08:00;True|2022-12-17T18:31:00.3332961+08:00;True|2022-12-17T12:29:27.2257800+08:00;True|2022-12-17T11:06:37.8176899+08:00;True|2022-12-15T08:00:13.6842411+08:00;True|2022-12-13T12:10:12.2530920+08:00;True|2022-12-13T10:10:50.0512184+08:00;True|2022-12-13T10:08:30.0309694+08:00;True|2022-12-13T10:04:52.6876847+08:00;True|2022-12-12T20:14:30.0623921+08:00;True|2022-12-12T20:13:38.1238116+08:00;True|2022-12-12T20:12:07.0936964+08:00;True|2022-12-11T13:10:18.2140245+08:00;True|2022-12-11T13:08:51.2427844+08:00;True|2022-12-10T13:00:16.6605746+08:00;True|2022-12-09T23:07:24.8079525+08:00;True|2022-12-09T19:58:04.0989594+08:00;True|2022-12-09T19:56:42.7195927+08:00;True|2022-12-09T19:53:31.8804030+08:00;True|2022-12-09T19:45:39.8557456+08:00;True|2022-11-29T10:02:12.9644217+08:00;True|2022-11-28T20:07:05.4948835+08:00;True|2022-11-28T20:06:52.1724049+08:00;True|2022-11-28T12:58:30.0455236+08:00;True|2022-11-28T12:56:29.6927989+08:00;True|2022-11-28T12:55:41.4295095+08:00;True|2022-11-28T12:53:49.0933314+08:00;True|2022-11-28T12:51:28.8301278+08:00;True|2022-11-28T12:50:46.0058585+08:00;True|2022-11-28T12:50:01.8716847+08:00;True|2022-11-28T12:49:25.7150025+08:00; + True|2022-12-29T09:08:57.3370321Z;True|2022-12-29T17:00:01.7295036+08:00;True|2022-12-28T22:08:08.7670608+08:00;True|2022-12-28T17:27:29.8124543+08:00;True|2022-12-28T16:24:51.9861635+08:00;True|2022-12-28T16:23:44.1004953+08:00;True|2022-12-28T16:21:08.2353403+08:00;True|2022-12-28T16:20:56.6429409+08:00;True|2022-12-23T19:22:48.4392831+08:00;True|2022-12-21T22:23:35.9045939+08:00;True|2022-12-21T22:18:16.0962966+08:00;True|2022-12-21T20:54:02.6827032+08:00;True|2022-12-21T20:52:52.1827338+08:00;True|2022-12-21T20:52:06.8220342+08:00;True|2022-12-21T20:51:17.2555457+08:00;True|2022-12-18T21:48:23.3182037+08:00;False|2022-12-18T21:46:45.4066089+08:00;False|2022-12-18T21:46:32.1453050+08:00;True|2022-12-18T21:45:56.8222951+08:00;True|2022-12-18T19:21:18.8207927+08:00;True|2022-12-17T22:46:09.3784351+08:00;True|2022-12-17T21:59:08.8587742+08:00;True|2022-12-17T20:48:28.8245676+08:00;True|2022-12-17T20:34:01.3071499+08:00;True|2022-12-17T20:32:23.5134227+08:00;True|2022-12-17T18:31:00.3332961+08:00;True|2022-12-17T12:29:27.2257800+08:00;True|2022-12-17T11:06:37.8176899+08:00;True|2022-12-15T08:00:13.6842411+08:00;True|2022-12-13T12:10:12.2530920+08:00;True|2022-12-13T10:10:50.0512184+08:00;True|2022-12-13T10:08:30.0309694+08:00;True|2022-12-13T10:04:52.6876847+08:00;True|2022-12-12T20:14:30.0623921+08:00;True|2022-12-12T20:13:38.1238116+08:00;True|2022-12-12T20:12:07.0936964+08:00;True|2022-12-11T13:10:18.2140245+08:00;True|2022-12-11T13:08:51.2427844+08:00;True|2022-12-10T13:00:16.6605746+08:00;True|2022-12-09T23:07:24.8079525+08:00;True|2022-12-09T19:58:04.0989594+08:00;True|2022-12-09T19:56:42.7195927+08:00;True|2022-12-09T19:53:31.8804030+08:00;True|2022-12-09T19:45:39.8557456+08:00;True|2022-11-29T10:02:12.9644217+08:00;True|2022-11-28T20:07:05.4948835+08:00;True|2022-11-28T20:06:52.1724049+08:00;True|2022-11-28T12:58:30.0455236+08:00;True|2022-11-28T12:56:29.6927989+08:00;True|2022-11-28T12:55:41.4295095+08:00;True|2022-11-28T12:53:49.0933314+08:00;True|2022-11-28T12:51:28.8301278+08:00;True|2022-11-28T12:50:46.0058585+08:00;True|2022-11-28T12:50:01.8716847+08:00;True|2022-11-28T12:49:25.7150025+08:00; \ No newline at end of file diff --git a/SaladimWpf/SimCmdModules/TextMisc.cs b/SaladimWpf/SimCmdModules/TextMisc.cs index 4bf44f9..29ffded 100644 --- a/SaladimWpf/SimCmdModules/TextMisc.cs +++ b/SaladimWpf/SimCmdModules/TextMisc.cs @@ -143,6 +143,7 @@ SysColor GetRandomColor() } } + [Command("做旗子")] public void MakeFlagInternal(params SysColor[] colors) { var pointsCount = colors.Length; @@ -159,28 +160,21 @@ public void MakeFlagInternal(params SysColor[] colors) } }); IMessageEntityBuilder builder = Content.Client.CreateMessageBuilder().WithImage(url); + StringBuilder sb = new(); foreach (var color in colors) { - builder.WithTextLine(GetColorText(color)); + sb.Append(GetColorText(color)); + sb.Append(" | "); + } + string s = sb.ToString(); + if (s.Length > 250) + { + s = "颜色信息长于250字符, 已默认屏蔽."; } + builder.WithTextLine(s); Content.MessageWindow.SendMessageAsync(builder.Build()); } - [Command("做旗子")] - public void MakeFlag(SysColor c1) => MakeFlagInternal(c1); - - [Command("做旗子")] - public void MakeFlag(SysColor c1, SysColor c2) => MakeFlagInternal(c1, c2); - - [Command("做旗子")] - public void MakeFlag(SysColor c1, SysColor c2, SysColor c3) => MakeFlagInternal(c1, c2, c3); - - [Command("做旗子")] - public void MakeFlag(SysColor c1, SysColor c2, SysColor c3, SysColor c4) => MakeFlagInternal(c1, c2, c3, c4); - - [Command("做旗子")] - public void MakeFlag(SysColor c1, SysColor c2, SysColor c3, SysColor c4, SysColor c5) => MakeFlagInternal(c1, c2, c3, c4, c5); - public static string GetColorText(SysColor color) => $"#{color.R:X2}{color.G:X2}{color.B:X2}({color.R},{color.G},{color.B})"; public static string HappyDrawing(int width, int height, Action processContext) @@ -229,8 +223,10 @@ public async void Integral(string s) { var service = serviceProvider.GetRequiredService(); var result = await service.IntegralOf(s).ConfigureAwait(false); - if (result != null) + if (!string.IsNullOrWhiteSpace(result)) + { await Content.MessageWindow.SendMessageAsync(result).ConfigureAwait(false); + } else await Content.MessageWindow.SendMessageAsync("计算错误").ConfigureAwait(false); }