• 注册
  • 技术交流 技术交流 关注:8 内容:20

    [OpenMod]插件的服务

  • 查看作者
  • 打赏作者
  • 当前位置: 未转变者中文社区 > 技术交流 > 正文
    大版主
    Lv.15

    搬运自OpenMod官网,经过翻译,可能有些不足,欢迎指正!原文链接

    服务和依赖注入

    OpenMod与其他基于.NET的现代框架一样,使用依赖注入模式。本指南旨在简化它,并解释它对使用OpenMod的插件开发人员意味着什么。

    插件、命令、事件监听器和服务可以自动获取对插件或OpenMod提供的任何其他服务的引用,只需将它们的接口添加到构造函数中。请参见下面的示例。

    依赖注入示例

    让我们看看这个活动:

    这就是你的插件通常的样子:

    public class MyPlugin(IServiceProvider serviceProvider) : base(serviceProvider)
    {
     
    }

    如果您想访问IStringLocalizer服务,您可以这样做:

    public class MyPlugin(IStringLocalizer stringLocalizer, IServiceProvider serviceProvider) : base(serviceProvider)
    {
       // 用stringLocalizer做些什么
    }

    假设您希望通过命令访问插件实例和配置。以下是您的方法:

    private readonly IConfiguration m_Configuration;
    private readonly MyPlugin m_MyPlugin;
     
    public EchoCommand(
        IServiceProvider serviceProvider, 
        MyPlugin myPlugin,
        IConfiguration configuration) : base(serviceProvider)
        m_MyPlugin = myPlugin;
        m_Configuration = configuration;
    }

    注册您自己的服务

    注册服务有两种方法:

    使用接口的[Service]属性和具体类的[PluginServiceImplementation]进行注册。

    通过实现IServiceConfiguratorIContainerConfigurator接口手动注册。当配置IoC容器时,实现这些接口的类将自动实例化,并可用于直接配置容器。

    您可以实现IDisposableIAsyncDisposable接口,以便在OpenMod或插件卸载时清理资源。

    以下是清理车辆的示例服务:

    [Service]
    public interface IVehicleClearingService
    {
        Task ClearVehiclesAsync();
    }
     
    [PluginServiceImplementation(Lifetime = ServiceLifetime.Transient)]
    public class VehicleClearingService : IVehicleClearingService, IAsyncDisposable
    {
        private readonly IStringLocalizer m_StringLocalizer;
        private readonly ILogger<VehicleClearingService> m_Logger;
        public VehicleClearingService(
            ILogger<VehicleClearingService> logger, 
            IPluginAccessor<VehicleClearerPlugin> pluginAccessor)
        {
            VehicleClearerPlugin plugin = pluginAccessor.Instance;
     
            // 服务位于全局OpenMod作用域中,该作用域不提供IStringLocalizer。
            // 因为IStringLocalizer不在这个范围内,所以我们必须使用plugins范围。
            m_StringLocalizer = plugin.Lifetime.Resolve<IStringLocalizer>();
            m_Logger = logger;
        }
        public async Task ClearVehiclesAsync() 
        {
            m_Logger.LogInformation(m_StringLocalizer["messages:clearing_vehicles"]); // 翻译是从plugins translation中读取的
            // 调用游戏API清除车辆...
        }
        // 在OpenMod重载或服务器关闭时调用服务dispose方法 
        public async ValueTask DisposeAsync()
        {
            await ClearVehiclesAsync(); // 确保车辆在重新装载或关闭时被清除
        }
    }

    现在,您可以通过在命令、事件侦听器、插件类或其他服务中注入IVehicleClearingService来访问此服务。

    服务期限

    您可能已经注意到,VehicleClearningService的生存期设置为Lifetime = ServiceLifetime.Transient

    以下生存期可用:

    Transient-每次解析时都会重新创建服务。此服务的每个解析和注入都将有一个唯一的实例。这是默认的生存期。

    Scoped-服务将在同一命令或事件中共享同一实例。

    Singleton-服务将只有一个实例的生存期与OpenMod IoC容器的生命周期相同(直到OpenMod重新加载或服务器关闭)。

    避免使用单例服务。如果您的服务具有暂时的或作用域的依赖关系,这可能会导致问题。

    服务范围

    服务可以有两个作用域:插件作用域和全局作用域。

    插件作用域服务仅在定义插件本身中使用,其他插件无法访问。它们也不能覆盖OpenMod本身或其他插件的全局范围服务。插件作用域服务是使用[PluginServiceImplementation]属性实现的。插件作用域服务是在加载插件时构造的,在关闭插件时释放。

    全局作用域服务用于所有插件和OpenMod本身。全局作用域服务是使用[ServiceImplementation]属性实现的。如果您想为每个人替换例如IStringLocalizer,您需要在全局范围内实现它。全局作用域服务在OpenMod重新加载或服务器关闭时被释放。全局作用域服务是在OpenMod加载并被释放和OpenMod关闭时构建的。

    在实现全局范围服务时避免依赖于插件。仅创建对其他全局范围服务的依赖关系。由于全局范围服务的生存期与插件不同,因此不能注入插件实例。一种解决方法是注入Lazy<IPluginAccessor<YourPlugin>>并稍后解析。请记住,即使您的插件无法加载或卸载,您的全局范围服务仍将保持活动状态。

    内置的OpenMod服务

    服务 说明
    IConfiguration 提供配置文件中的值
    ICommandContextBuilder 生成命令上下文
    ICommandExecutor 执行命令
    ICommandStore 提供命令注册
    ICommandPermissionBuilder 定义命令的权限
    ICommandParameterResolver 从字符串分析命令参数
    ICurrentCommandContextAccessor 访问当前命令上下文
    IDataStore 序列化和反序列化持久数据
    IDataStoreFactory 创建数据存储
    IEventBus 订阅事件并发出它们
    IJobSchgeduler 任务和管理作业
    ILogger<T> 为T类提供日志记录
    ILoggerFactory 创建者记录器
    IOpenModStringLocalizer 本地化来自OpenMod自己的翻译文件的消息
    IOpenModDataStoreAccessor 访问OpenMod自己的数据存储
    IOpenModHost OpenMod主机平台抽象
    IPermissionChecker 检查权限
    IPermissionRoleStore 存储权限角色
    IPermissionRegistry 注册和存储权限
    IPluginAccessor<TPlugin> 访问插件实例
    IPluginActivator 加载并激活插件
    IRuntime 创建并托管OpenMod运行时
    IStringLocalizer 本地化来自插件翻译文件的消息
    IUserDataSeeder 在第一次连接时种子用户数据
    IUserDataStore 存储和管理用户数据
    IUserManager 保姆用户

    Lv.1
    […] 之后,必须通过ServiceConfigurator注册它们: […]
    回复
    Lv.1
    […] 实现IPermissionStore接口并通过ServiceConfigurator进行注册: […]
    回复

    请登录之后再进行评论

    登录
  • 发布内容
  • 任务中心
  • 实时动态
  • 偏好设置
  • 帖子间隔 侧栏位置: