Skip to content
On this page

插件示例开发

概述

本文将以开发者的视角开发一个通用平台的一言插件。

开发之前

首先,我们需要在项目的Release下载我们需要的Wrapper和Provider版本,在本文中我们仅以QQ平台作为我们的示例开发平台。

然后我们需要新建一个.NET 6.0 Libraries项目,并导入Interface的DLL引用。

当你可以引用Sorux的命名空间时,说明我们可以开始我们的开发了。

注册插件Register

创建一个Register类,并实现IBasicInformation接口。由于此插件有命令触发前缀的需求,因此我们同时也实现ICommandPrefix接口。

填写基本信息:

csharp
public class Register: IBasicInformationRegister , ICommandPrefix  
{  
    public string GetAuthor() => "EpicMo";  
  
    public string GetDescription() => "用于信息的手机、整理";  
  
    public string GetName() => "InformationCollector";  
  
    public string GetVersion() => "1.0.0-release";  
  
    public string GetDLL() => "EpicMo.Plugins.InformationCollector.dll";  
  
    public string GetCommandPrefix() => "#";  
}

其中,GetDLL()的返回值便是我们最后编译出来的DLL名称。

完成一个最基本的Controller

因为此插件只需要对接一言接口,因此我们只需要一个基本的Controller类即可。

首先,建立我们的类,并继承BotController接口:

csharp
public class YiYanController: BotController  
{

}

接着便是向框架请求相应的服务,因为我们需要向用户发送信息,因此我们需要请求BasicAPI服务,此外,我们可能会有日志记录的要求,因此我们也请求ILoggerService服务:

csharp
public class YiYanController: BotController  
{  
    private ILoggerService _loggerService;  
    private IBasicAPI _bot;  
    private RestClient _client;  
    public YiYanController(ILoggerService loggerService,IBasicAPI bot)  
    {        
	    this._loggerService = loggerService;  
        this._bot = bot;  
        _client = new RestClient("https://v1.hitokoto.cn/");  
    }
}

在这个地方,我们除了请求两个服务外,还在Controller中执行了初始化任务。

TIP

相较于以插件启用/禁用时调用插件的OnEnable和OnDisable方法,SoruxBot认为一个插件的最基本单位应该是功能集,而不是插件整体。因此,当你有初始化某个功能集的一些服务的需求时,请在Controller执行初始化服务。

TIP

特别的,插件的每一个Controller只会初始化一次,且初始化时间在所有消息和Action执行之前,由框架统一初始化

然后,分析我们的需求,我们在插件中需要提供一个命令,让在群聊中的用户能够触发得到一言句子的Action,同时,在一言的API文档中,我们发现我们可以手动指定得到句子的类型。

也就是我们既可以直接向一言请求句子,也可以指定句子类型再请求,那么我们的命令参数就应该是包含一个可选参数的命令。因此我们可以得到一个Action雏形:

csharp
[Event(EventType.GroupMessage)]  
[Command(CommandAttribute.Prefix.Single,"saying <type>")]  
public PluginFucFlag YiYanGet(MessageContext context,string? type)  
{
}

在这个Action里面,我们指定了命令的前缀是Single,也就是插件本身向框架注册的前缀,这个前缀就是你在Register里面指定的GetCommandPrefix(),此外,由于type是一个可选参数,因此由<>包围,而不是[],并且由于type为可选参数,因此他可空。关于插件的参数说明,可见插件的命令特性,关于插件的触发条件,可见插件的事件特性

TIP

虽然string本身可以为null,但是我们建议你声明可空类型string?而不是string。

由于我们只想本插件在saying被触发后执行,因此我们返回一个拦截消息请求,防止多个插件被触发。关于插件其他的返回请求请见插件的返回说明

csharp
[Event(EventType.GroupMessage)]  
[Command(CommandAttribute.Prefix.Single,"saying <type>")]  
public PluginFucFlag YiYanGet(MessageContext context,string? type)  
{
	return PluginFucFlag.MsgIntercepted;
}

TIP

这一种做法也可能被其他使用saying指令的Action操作。而遇到这个情况是本插件执行还是另一个插件执行,由插件配置中的优先级决定。关于优先级的说明可以见插件的Json配置说明

然后,我们需要具体编写Action的内容,这不是本文重点,因此我们直接给出代码:

csharp
[Event(EventType.GroupMessage)]  
[Command(CommandAttribute.Prefix.Single,"saying <type>")]  
public PluginFucFlag YiYanGet(MessageContext context,string? type)  
{  
    var request = new RestRequest();  
    request.Method = Method.Get;  
    if (!string.IsNullOrEmpty(type))  
    {        
	    request.AddQueryParameter("c", type);  
    }    
    var result = _client.Execute(request);  
    YiYan model = JsonConvert.DeserializeObject<YiYan>(result.Content!)!;  
    if (!string.IsNullOrEmpty(model.from_who))  
    {        
	    _bot.SendGroupMessage(context,model.hitokoto + "   ---" + model.from_who);  
    }    
    else  
    {  
        _bot.SendGroupMessage(context,model.hitokoto);  
    }    
    return PluginFucFlag.MsgIntercepted;  
}

在Action中,我们可以使用插件的BasicAPI来帮助我们快速的发送消息。在SoruxBot的体系中,API分为通用API和特定API,由于我们编写的插件是多平台的,因此使用BasicAPI的基本服务即可,可见我们的SendGroupMessage中并未包含任何与QQ聊天平台有关的信息,这也说明了我们的插件可以服务多个聊天平台。

在Action中,我们定义了一个YiYan,这个作为Json反序列化的模板。

制作Json

json
{
    "Name": "YiYan",
    "Privilege": 1,
    "PermissionNode":[],
    "PermissionDefaultConfig":[]
}

我们制作了一个最基本的Json,并让我们的默认优先级为1。关于Json的详细说明可以见插件Json说明

TIP

优先级是可以被用户更改的,因此我们无法保证运行时也是1。关于优先级冲突的叙述请见插件Json说明

运行插件

将插件放置在Wrapper/Plugins/Bin中,将Json放置在Wrapper/Plugins/Config中,然后重启Wrapper,并打开Provider.Cqhttp和Go-cqhttp,我们便完成了插件的运行。