Skip to content

引擎服务

大多数引擎功能都是通过引擎服务实现的。引擎服务是 IEngineService 接口的实现,用于处理特定工作,例如执行剧本脚本、管理 actor 或保存和加载游戏状态。

如果您希望与引擎系统交互,您很可能会使用引擎服务。您可以使用静态方法 Engine.GetService<TService>() 获取对引擎服务的引用,其中 TService 是您希望获取的服务的接口;例如,要获取 IScriptPlayer 服务:

csharp
var player = Engine.GetService<IScriptPlayer>();
player.Stop();

NOTE

引擎初始化过程是异步的,因此即使启用了自动初始化,在 Unity 加载场景后(例如,在 AwakeStartOnEnable MonoBehaviour ↗ 方法中),引擎 API(例如 GetService 方法)也可能无法立即可用;有关更多信息,请参阅 访问引擎 API 指南。

目前提供以下服务:

服务接口描述
IBackgroundManager管理 背景 actor。
ICharacterManager管理 角色 actor。
IChoiceHandlerManager管理 选项处理程序 actor。
ITextPrinterManager管理 文本打印机 actor。
IAudioManager管理音频:SFXBGM配音
IInputManager管理用户 输入处理
ILocalizationManager管理 本地化 活动。
ITextManager处理 管理文本 功能。
IMoviePlayer处理 电影 播放。
IScriptManager管理 剧本脚本 资源。
IScriptPlayer处理 剧本脚本 执行。
ICameraManager管理场景渲染所需的相机和其他系统。
IResourceProviderManager管理 IResourceProvider 对象。
IStateManager处理 IEngineService 相关的持久数据反序列化/序列化;提供 保存和加载 游戏状态的 API。
IUIManager管理 IManagedUI 对象并处理 UI 自定义 功能。
ICustomVariableManager提供访问并允许修改 自定义变量
ISpawnManager管理使用 @spawn 命令生成的对象。
IUnlockableManager管理 可解锁项(CG 和电影画廊项目、提示等)。

您可以在 Naninovel/Runtime 处存储的运行时源代码中找到服务的内置实现。

添加自定义服务

要添加新的自定义引擎服务,请实现 IEngineService 接口并将 InitializeAtRuntime 属性添加到实现类。在引擎初始化期间将自动创建实现的实例,并可通过 Engine.GetService<TService>() API 使用。

您可以使用 InitializeAtRuntime 属性的 InitializationPriority 参数强制您的自定义服务在其他服务之前或之后初始化;较低的值会将其推送到初始化队列中的其他服务之前,反之亦然。

要自动实例化,服务实现应具有兼容的构造函数(或默认构造函数)。允许以下构造函数参数(任意顺序):

  • 任意数量的其他服务(IEngineService 派生)
  • 任意数量的配置对象(Configuration 派生)
  • Unity MonoBehaviour 代理对象(IEngineBehaviour 派生)

请注意,在构造函数中使用其他服务是不安全的。相反,在 InitializeService 方法中执行任何需要其他服务的初始化活动;为确保在访问所需服务时已初始化它们,请在服务构造函数中列出它们(初始化队列根据构造函数参数按拓扑排序)。

如果您的自定义服务具有希望与其他引擎服务一起反序列化/序列化的持久状态,请实现 IStatefulService<TState> 接口,其中 TStateGameStateMapGlobalStateMapSettingsStateMap,具体取决于您是要将状态与特定于游戏会话、全局还是设置数据一起存储。如果需要,允许为单个服务实现所有三个接口。有关不同类型的引擎状态的更多信息,请参阅 状态管理指南

下面是带有使用说明的自定义引擎服务实现示例。

csharp
using Naninovel;
using UnityEngine;

[InitializeAtRuntime]
public class CustomService : IEngineService
{
    private readonly InputManager inputManager;
    private readonly ScriptPlayer scriptPlayer;

    public CustomService (InputManager inputManager, ScriptPlayer scriptPlayer)
    {
        // 服务可能尚未在此处初始化,
        // 请避免使用它们。
        this.inputManager = inputManager;
        this.scriptPlayer = scriptPlayer;
    }

    public Awaitable InitializeService ()
    {
        // 在此处初始化服务。
        // 现在可以安全地使用构造函数中请求的服务。
        Debug.Log(inputManager.ProcessInput);
        Debug.Log(scriptPlayer.PlayedScript);
        return Async.Completed;
    }

    public void ResetService ()
    {
        // 在此处重置服务状态。
    }

    public void DestroyService ()
    {
        // 在此处停止服务并释放任何使用的资源。
    }
}

您现在可以通过以下方式访问上述自定义服务:

csharp
var customService = Engine.GetService<CustomService>();

EXAMPLE

库存示例 中可以找到添加自定义引擎服务以管理项目资源和库存 UI 配置的另一个示例。具体来说,自定义引擎服务通过 Scripts/Runtime/Inventory/InventoryManager.cs 运行时脚本实现。

覆盖内置服务

所有内置服务都在引擎源代码中通过接口引用,这使得可以将其中任何一个替换为自定义实现。

以与上述相同的方式添加自定义服务,但不要实现 IEngineService,而是实现具体的引擎接口并通过 InitializeAtRuntime 属性指定被覆盖的类型(实现类型,而不是接口)。然后将初始化您的自定义实现而不是内置实现。

下面是一个虚拟 IInputManager 实现的示例,除了在其任何方法被调用时记录日志外,它什么也不做。

csharp
using Naninovel;
using UnityEngine;

[InitializeAtRuntime(@override: typeof(InputManager))]
public class CustomInputManager : IInputManager
{
    public InputConfiguration Configuration { get; }

    public CustomInputManager (InputConfiguration config)
    {
        Configuration = config;
    }

    public void AddMuter (object muter, IEnumerable<string> allowedIds = null)
    {
        Debug.Log("CustomInputManager::AddMuter()");
    }

    public void RemoveMuter (object muter)
    {
        Debug.Log("CustomInputManager::RemoveMuter()");
    }

    // 等等...
}

现在,当通过 Engine.GetService<IInputManager>() 请求输入管理器时,将使用您的自定义实现而不是内置的 Naninovel.InputManager