state
读取、写入并观察当前游玩进程的故事变量
app.game.state 触及作者在 Studio 中声明的故事变量——场景局部变量、存档变量和持久变量。把一次游玩进程读出来,和把它重写掉,是完全不同的两件事,所以它们是两项能力:
{
"contributes": {
"runtimeCapabilities": ["state.read", "state.write"]
}
}state.read 授予 get 和 onChange。state.write 额外授予 set——并且隐含 state.read,所以你只声明 write 时,Studio 会替你补上读的那一半
方法
| 方法 | 签名 | 需要 |
|---|---|---|
get | <T>(scope, key: string) => T | null | state.read |
onChange | (listener: (change) => void) => RuntimePluginCleanup | state.read |
set | (scope, key: string, value: unknown) => void | state.write |
get 和 set 是同步的——变量表就在内存里。没有 state.write 时 set 会从对象上彻底消失,所以如果你的插件在两种声明下都能运行,请写成 app.game.state.set?.(...)
作用域
| 作用域 | 生命周期 |
|---|---|
"scene" | 当前场景。场景结束即消失 |
"saved" | 本次游玩进程。会写入存档槽位,并从中恢复 |
"persistent" | 玩家本人,跨越每一次游玩进程。开新游戏也不会丢 |
const count = app.game.state?.get<number>("saved", "timesAsked") ?? 0;
app.game.state?.set?.("saved", "timesAsked", count + 1);观察变化
type RuntimePluginStateChange = {
scope: "scene" | "saved" | "persistent";
key: string;
previous: unknown;
next: unknown;
};
const stop = app.game.state?.onChange(change => {
if (change.scope === "persistent" && change.key === "trueEndingSeen" && change.next === true) {
// 解锁点什么
}
});onChange 对来自故事、来自其他插件,以及来自你自己 set 的写入都会触发。它返回一个清理函数
持久变量是被精确观察的——变化与写入在同一帧抵达。场景变量和存档变量则是在故事可能写过它们的那些时点(一次动作变更、一句台词结束、场景挂载或卸载、存档被恢复,以及你自己的 set)与快照比对得出的,而且只在确实有人监听时才比对。实际用起来你能看到每一次变化;不能依赖的是场景或存档变化在一帧之内被报告的确切时刻
这不是插件 store
state 是作者的数据:他们在 Studio 中声明并接进故事里的变量。app.game.store 是你插件的数据,在自己的命名空间里,对故事不可见。用 state 参与作者的剧本;用 store 记住属于你自己的东西