系统插槽是引擎预定义的语义 UI 入口。调用方只说「打开设置」或「打开存档」,项目绑定决定最终使用哪一份界面。 这种间接绑定让创作者以后可以替换整套游戏壳,而不必修改剧本和每个按钮。

九个系统插槽

插槽常量说明必需
标题画面INTERNAL_SYSTEM_SLOT.Title游戏启动和返回标题时打开
对话工具栏INTERNAL_SYSTEM_SLOT.Toolbar对话期间自动显示的操作工具栏
存档界面INTERNAL_SYSTEM_SLOT.Save以保存模式显示槽位
读档界面INTERNAL_SYSTEM_SLOT.Load以读取模式显示槽位
设置界面INTERNAL_SYSTEM_SLOT.Settings玩家运行时设置
历史记录INTERNAL_SYSTEM_SLOT.History对话回顾和语音重放
鉴赏画面INTERNAL_SYSTEM_SLOT.GalleryCG、音乐和剧情片段鉴赏
玩家输入INTERNAL_SYSTEM_SLOT.Input收集并校验玩家输入
选项界面INTERNAL_SYSTEM_SLOT.Choice显示剧情分支选项并返回原选项序号
默认游戏壳提供全部九个插槽。标题、对话工具栏、存档、读档、玩家输入和选项界面的绑定失效时,引擎会回退到内置实现。 对话工具栏由默认游戏壳的自治控制器跟随对话状态打开和关闭。把工具栏插槽改绑到其他界面后,这套显隐时机保持不变,只替换实际显示的界面。

绑定可视化界面

可视化界面不需要程序声明。创建界面后,进入 个性化 → 项目设置 → 游戏系统,在目标插槽中选择它即可。 任何启用扩展中的可视化界面都可以作为候选。系统或市场界面只读,需要修改时先创建项目副本,或复制到本地扩展。 选项界面需要包含「选项列表」智能组件,才能接收分支内容并返回选择结果。玩家输入界面需要使用输入对话框能力处理确认、取消和校验。可以从个性化直接打开默认实现进行修改。
界面里的按钮要打开另一个系统位置时,配置「打开存档」「打开设置」等系统动作。不要写死具体界面,这样按钮会跟随绑定变化。

声明程序 UI 支持

React 程序 UI 需要在 @extension 装饰器中声明 supportsSlot
import { Extension, extension, INTERNAL_SYSTEM_SLOT } from "@avg-studio/sdk";

@extension({
  id: "title-screen",
  label: "自定义标题画面",
  supportsSlot: INTERNAL_SYSTEM_SLOT.Title,
})
export class MyTitleScreen extends Extension {
  render() {
    return { component: TitleScreenComponent, props: {} };
  }
}
同一个模块可以支持多个插槽:
@extension({
  id: "save-screen",
  label: "存读档界面",
  supportsSlot: [
    INTERNAL_SYSTEM_SLOT.Save,
    INTERNAL_SYSTEM_SLOT.Load,
  ],
})
export class MySaveLoadScreen extends Extension {
  // 根据打开时的 payload 区分保存和读取模式
}
声明后,模块才会出现在对应插槽的程序 UI 候选中。

从程序触发插槽

// 打开当前绑定的存档界面
await ctx.system.invoke(INTERNAL_SYSTEM_SLOT.Save);

// 传递给目标 UI 的 payload
await ctx.system.invoke(
  INTERNAL_SYSTEM_SLOT.Save,
  { mode: "save" },
  {
    modal: true,
    containerOptions: {
      size: "(100%, 100%)",
      position: "(0, 0)",
    },
  },
);

const binding = ctx.system.getBinding(INTERNAL_SYSTEM_SLOT.Save);
const slots = ctx.system.listSlots();

// 常驻槽位可以由控制器主动收起
await ctx.system.close(INTERNAL_SYSTEM_SLOT.Toolbar);
invoke 的第三个参数可以设置 modal,以及容器的 sizepositioninteractable

选项界面的 payload

剧情分支会自动调用 INTERNAL_SYSTEM_SLOT.Choice,并传入:
  • branchId:当前分支 Block 标识;
  • choices:过滤后的可见选项,包括原始序号、文字和是否可用;
  • onSelect(originalIndex):界面确认选择后必须调用的回调。
自定义程序 UI 应只提交可用选项的 originalIndex,然后关闭自身。界面未选择就关闭或调用失败时,引擎会回退到内置选项界面,避免剧情中断。 玩家输入和剧情选项通常由引擎自动调用。普通扩展界面不应在缺少对应 payload 时直接打开这两个插槽。

在剧本中使用

显示 UI选择器的「系统插槽」分组会列出常规可打开入口。保存后使用 slot:internal.system.* 语义引用;项目之后改绑,已有剧本会自动跟随。玩家输入和剧情选项应由对应运行时流程调用,不建议作为普通显示 UI 使用。

内置动作(输入)

系统插槽是「系统 UI 位置」,内置动作是「玩家输入对应的语义」。两者是独立概念。
引擎定义了以下标准动作:
动作常量默认按键含义
推进对话INTERNAL_ACTION.Advance鼠标点击 / 空格 / Enter / 滚轮推进到下一句
跳过INTERNAL_ACTION.SkipCtrl快进到段尾
自动播放INTERNAL_ACTION.AutoToggleA切换自动模式
隐藏对话框INTERNAL_ACTION.HideDialogue右键 / Delete临时隐藏对话框
重放语音INTERNAL_ACTION.ReplayVoiceR重放当前角色语音

订阅内置动作

import { Extension, extension, INTERNAL_ACTION } from "@avg-studio/sdk";

@extension({ id: "my-hud", label: "HUD", autonomous: true })
export class MyHud extends Extension {
  static onRegister(ctx) {
    ctx.input.onAction(INTERNAL_ACTION.AutoToggle, () => {
      console.log("玩家切换了自动播放");
    });
  }
}

注册自定义动作

自定义动作会出现在 Studio 的「项目设置 → 输入按键」中:
static onRegister(ctx) {
  ctx.input.registerAction({
    id: "my-ext.open-inventory",
    label: "打开背包",
    defaultKeys: ["KeyI"],
  });

  ctx.input.onAction("my-ext.open-inventory", () => {
    void ctx.visualUI.open("@my-ext/inventory");
  });
}
自定义动作 id 必须以扩展 id 为前缀。internal.* 是引擎保留命名空间,扩展不能使用。
常量名是单数:INTERNAL_ACTION.AdvanceINTERNAL_SYSTEM_SLOT.Title。复数形式是元数据查询表,通常不需要直接使用。