Skip to content

Commit

Permalink
SimCommand现在支持params类型的入参
Browse files Browse the repository at this point in the history
  • Loading branch information
Saplonily committed Dec 29, 2022
1 parent 27f94ab commit c0e72b5
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 78 deletions.
149 changes: 92 additions & 57 deletions SaladimQBot.Extensions/SimCommandExecutor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<MethodBasedCommand> commands;
private readonly Func<Type, object?> moduleInstanceFactory;
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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让其解析为对应值
//并调用最后的实体方法
Expand All @@ -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<Type> 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)
Expand All @@ -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<ParamArrayAttribute>().Any();
}
}
}
10 changes: 7 additions & 3 deletions SaladimSimCmd/Program.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Drawing;
using System.Diagnostics;
using System.Drawing;
using System.Numerics;
using System.Text;
using Saladim.SalLogger;
Expand Down Expand Up @@ -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();
}
}

Expand Down Expand Up @@ -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("你给出了如下的东西, 以\" | \"分隔");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project>
<PropertyGroup>
<History>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;</History>
<History>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;</History>
<LastFailureDetails />
</PropertyGroup>
</Project>
30 changes: 13 additions & 17 deletions SaladimWpf/SimCmdModules/TextMisc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ SysColor GetRandomColor()
}
}

[Command("做旗子")]
public void MakeFlagInternal(params SysColor[] colors)
{
var pointsCount = colors.Length;
Expand All @@ -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<IImageProcessingContext> processContext)
Expand Down Expand Up @@ -229,8 +223,10 @@ public async void Integral(string s)
{
var service = serviceProvider.GetRequiredService<IntegralCalculatorService>();
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);
}
Expand Down

0 comments on commit c0e72b5

Please sign in to comment.