This repository was archived by the owner on Mar 29, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
3 (3). 含有上下文的信息处理
DavidMeow edited this page Jan 14, 2023
·
7 revisions
- 本页例子将使用
全局端
讲述, 如果您含有多个端
, 请您自己添加自己端的签名等到参数位置
, 就如上一页面提到的.
- 交互端不分
好友信息
群信息
等类型(同步信息除外), 仅有收到信息这一个事件, - 且您无法订阅
Client
端内的OnFriendMessageRecieve
等事件, 防止影响程序正常解析工作. - 任何信息发送者将被解析成
ContextualSender
结构体. - 任何接收的信息将会转换为
ContextualMessage
结构体. - 任何接收到的信息会被存到一个集合索引为
ContextualSender
,元素为Queue<ContextualMessage>
的字典内 (Dictionary/HashSet) - 任何群号(如果私聊则为-1),和QQ号(一定含有)发送的信息将会被进入
Queue<ContextualMessage>
这个队列. - 任何群号和QQ号一致的发送人只拥有一个队列.
Global.G_Client = new ConClient("ws://......");
var c= (Global.G_Client as ConClient);
c.Connect();
c._OnMessageRecieve += (s) =>
{
Console.WriteLine($"{s.SenderId} {s.PeekPlainMsg()}");// PeekPlainMsg 是一个用于查看队列内第一个信息的方法(但是不会将元素移除)
s.DelMsgs();// DelMsg 是一个扩展方法, 用于从队列中移除指定数量元素.(*重要,务必添加*)
};
- 按上述写法,您的控制台内应该会打印出您发送的信息, 并且当执行完后这条信息会从
缓存区队列(Dictionary)
移除. - 关于
重要
的解释, 因为队列在设计时为了含有其他异步函数获取参数执行, 或校验指令树等操作, 并不会将元素出队, 按理论上来讲, 应该由SE
自动控制元素删除时间, 在此我们建议统一当您完成事务后进行删除
, 后续文章中含有异步编程(Action驱动形式)相关, 届时会生成带参数的信息删除方案, 请您务必注意相关条目
,若您以不正当的方式进行操作, 可能导致操作队列产生异常, 可能会使得堆区无缘无故变大, 导致驻留过多内存等问题
.
- 假设我们要做的步骤如下:
sequenceDiagram
participant bot
participant user
user ->> +bot: 命令A ("重复")
bot ->> +user: 您要重复的话是?
user ->> +bot: 命令A的B参数 ("这句话")
bot ->> +user: [返回 字符串 " '这句话' "]
user ->> +bot: 命令A的C参数 ("再重复一次")
bot ->> +user: [返回 字符串 "重复第二遍 '这句话',程序结束"]
using MeowMiraiLib.MultiContext
....//在某一个新的类(例如Command.cs文件的Command类中)
CMsgHelper cmh1 = new(null, //如果您没有使用全局Client,请在这个位置传递您的ConClient实例
(s, msgs) => //第一个语句的动作
{
if (msgs.GetPlainMsgAt(1).Trim() == "重复") // GetPlainMsgAt(num) 是一个扩展方法,可以获取当前的num个信息(队列第一个)
{
s.SendMsgBack(new Message[] { new Plain("您要重复的话是?") });
// SendMsgBack(Message[],Client) 也是一个扩展方法, 用于朝信息发送者的位置快速回信, 如果是群就发群里, 如果是私聊就发送至私聊.
// 但您也可以使用 SendMessageToFriend / SendMessageToGroup 强制发回群里或者私聊(前提是发送者含有)
// 或者你也可以使用原版的扩展 使用 Message[]{...}.SendToFriend(123456) *留空Client使用全局,或者传递Client实例.
}
},
(s, msgs) => //第二个语句的动作
{
if (msgs.GetPlainMsgAt(1).Trim() == "重复") //检查指令树结构 (必须第一次含有重复)
{
s.SendMsgBack(new Message[] { new Plain($"{msgs.GetPlainMsgAt(2)}") });
}
},
(s, msgs) => //第三个语句的动作
{
if (msgs.GetPlainMsgAt(1).Trim() == "重复" && msgs.GetPlainMsgAt(3) == "再重复一次") //检查指令树结构 (必须第一次含有重复且这一次说的是再重复一次)
{
s.SendMsgBack(new Message[] { new Plain($"重复第二遍: \n{msgs.GetPlainMsgAt(2)}, 程序结束") });
}
s.DelMsgs(3); //程序结束,清理驻留
}
);
/*
* 程序注意点:
* 1. 必须在程序结束的时候清理驻留, 使用delmsg, 您执行了几步就需要删除几个信息. 不要多删也不要少删. 防止后面程序执行错误.
* 2. 必须每次进入其他Action均 进 行 检 查 指 令 树 结 构, 避免如果多个任务异步接受信息产生信息错位的问题.
*/
- 按照这种写法您的交互辅助类已经写完了, 现在开始注入.
- 您需要在接受到信息后判定条件,然后转交辅助类进行处理.
- 程序示例如下:
//...在program.cs下
....
c._OnMessageRecieve += (s) =>
{
/*
var proc = true;
if(s.GroupId > 0) //如果是群聊
{
foreach (var i in s.PeekMsgs()) //查看信息类型
{
if (i is At && (i as At).target == 你Bot的QQ号) //确定at了本机器人
{
proc = true; //可以执行
}
else
{
proc = false;//不可以执行
}
}
}
if(proc)
{
*/
var m = s.PeekPlainMsg();//如造成群聊不断回复, 您应该加入at等判断(如上),或者删除最后一个一直回复的操作.
if (m == "重复")
{
Command.cmh1.Invoke(s);//注入并且启动
return;//执行后退出 (*重要*) (::因为内部我们已经让元素出队,所以要略过下方的删除元素,保持连贯)
}
else if (m == "Hello")
{
s.SendMsgBack(new Message[] { new Plain("Hello") });
//如果用户只说Hello的话就回Hello.
}
else
{
s.SendMsgBack(new Message[] { new Plain(".....?") });
//其他命令均回复".....?"
}
s.DelMsgs();//单回复的执行后删除队列元素 (*重要*)
/*}*/
};
while (true)
{
}
//阻塞主程序,直到程序被强制中断(按Ctrl+C)
- 符合预期,程序写作成功
**1.可实例化多个交互辅助类么 **
A: 可以, 但在接受端需要确定第一个接受的词, 引起正确的Action,
_OnMessageRecieve
务必注意判定条件和return;
**2.我可以使用上下文交互端写普通命令结构么? **
A: 可以, 其实本端和基础端并没有不同, 您也可以使用本端的 MsgSendBack(Message[],Client) 函数快速返回源地址一个信息, 省时省力. 如果您使用了全局端甚至可以不写Client参数.
**3.新的 快速编写类的功能参数都有什么 **
A: 参见 [AP. 1 (2) 上下文交互端扩展方法一览]