ctx.story 为扩展提供只读剧本快照。章节正文包含片段和 Studio 保存的原始 Block 数据,适合制作章节选择、台词检索、流程统计或辅助功能。
API
| 方法 | 返回值 | 说明 |
|---|
listChapters() | StoryChapterMeta[] | 同步读取章节目录,不加载正文 |
getChapter(id) | Promise<StoryChapter | null> | 按章节 id 读取完整章节;不存在时返回 null |
getAllChapters() | Promise<StoryChapter[]> | 按目录顺序读取当前宿主中的完整剧本 |
StoryChapter 的结构如下:
interface StoryChapter {
id: string;
name: string;
disabled?: boolean;
fragments: Array<{
id: string;
name: string;
blocks: StoryBlock[];
}>;
}
StoryBlock 保留原始 Block 的 id、type、content、props、children 和扩展自定义字段。返回结果是深拷贝;修改对象只会改变扩展自己的副本,不会修改 Studio 工程或正在运行的剧本。
案例:读取完整剧本中的所有对话块
输入: 项目包含多个章节,需要按章节统计 dialogue Block 数量。
const chapters = await ctx.story.getAllChapters();
const result = chapters.map((chapter) => ({
id: chapter.id,
name: chapter.name,
dialogueCount: chapter.fragments.reduce(
(count, fragment) =>
count + fragment.blocks.filter((block) => block.type === "dialogue").length,
0,
),
}));
console.log(result);
输出:
[
{ "id": "chapter-1", "name": "序章", "dialogueCount": 18 },
{ "id": "chapter-2", "name": "第一章", "dialogueCount": 42 }
]
加载与宿主差异
listChapters() 只返回轻量目录,适合先展示列表,再按需调用 getChapter()。
- Player 可能需要读取章节文件,因此
getChapter() 和 getAllChapters() 必须使用 await。getAllChapters() 的开销会随剧本大小增加,不建议在每次 React render 中调用。
- Studio 中可以读取工程里的禁用章节,此时目录和章节对象带有
disabled: true。
- 构建后的 Player 只能读取实际进入成品的章节;禁用章节不会被打包,因此不在目录和完整剧本中。
- 任一章节加载失败时,
getAllChapters() 会 reject。需要自行降级时,可以先用 listChapters(),再逐章调用 getChapter() 并捕获错误。
ctx.history.entries() 只包含玩家已经播放过的历史对话,不是完整剧本。需要读取未播放内容时请使用 ctx.story。