Skip to content
On this page

状态、表达式与 Flow

SpectrumGraphics 把视觉状态分为四个作用域,并在编译期检查类型和写权限。

状态声明

yaml
state:
  page:
    type: number
    scope: local
    default: 0
  profile.name:
    type: string
    scope: document
    default: Adventurer
    source:
      placeholder: "%player_name%"
  profile.rank:
    type: string
    scope: player
    default: Novice
    source:
      type: custom
      value: example:profile
      arguments: { field: rank }
      cost: 2
  server.motto:
    type: string
    scope: pack
    default: Welcome
scope所有者Flow 可写
local当前客户端文档
document服务端当前文档
player服务端玩家范围
pack服务端 Pack 共享范围

常用类型为 booleannumberstringcolor。服务器状态通过初始 snapshot 和有 revision/hash 的 patch 下发。

Placeholder 源在服务端解析。自定义源必须由附属插件通过 registerDataSource 注册,并声明足够的 cost;单次解析有总成本预算。

computed

yaml
computed:
  doubled: "= state.page * 2"
  canGoBack:
    type: boolean
    value: "= state.page > 0"
  title:
    type: string
    value: "= state.profile.name + ' · 第 ' + state.page + ' 页'"

computed 是只读派生状态。编译器提取精确依赖图、检查类型并拒绝循环;状态变化只让依赖它的节点失效。

binding、when 与表达式

yaml
title:
  type: text
  text: 默认标题
  when: "= state.page >= 0"
  bind:
    text: title
    visible: "= state.page < 10"
    opacity: "= state.canGoBack ? 1 : 0.5"
  • 直接状态引用可写 titlestate.title,具体位置应沿用生成 schema 与示例;
  • = 开头的是强类型表达式;
  • 表达式被编译成受限字节码,不接触 JavaScript、JVM、文件、网络或任意数据包;
  • when 控制节点是否存在;visible 只控制可见性,两者语义不同。

Flow 基础

yaml
flows:
  nextPage:
    concurrency: replace
    debounceMillis: 0
    throttleMillis: 50
    steps:
      - set: { state: page, value: "= state.page + 1" }
      - if:
          condition: "= state.page >= 5"
          then: reachedEnd
          else: playSound

  reachedEnd:
    - set: { state: status, value: 已到最后一页 }

  playSound:
    - effect:
        id: spectrumgraphics:sound-play
        arguments:
          sound: minecraft:ui.button.click
          volume: 0.7
          pitch: 1.1

Flow 在客户端 tick 调度,不创建脚本线程,不阻塞渲染线程。

指令表

指令用途
set写入 local 状态
toggle翻转本地 boolean
if条件选择后续 Flow
switch按标量值选择后续 Flow
sequence按声明顺序运行多个 Flow
parallel同一 tick 启动多个独立 Flow
delay延迟一次执行,不阻塞线程
every有次数上限的周期执行
commandfocusblurscroll-toset-text
effect调用已注册、受权限和预算限制的客户端 Effect
animation控制 transition/timeline/statechart
call调用强类型服务端 Action,并等待结果
close请求关闭当前 Minecraft Screen

并发、去抖与节流

concurrency行为
replace新调用取消并替换旧调用,默认值
drop运行中时丢弃新调用
queue排队顺序执行
parallel允许并行实例
yaml
flows:
  searchChanged:
    concurrency: replace
    debounceMillis: 150
    steps:
      - set: { state: status, value: 正在搜索 }

高频输入使用 debounce;滚动、拖动或连续数值变化使用 throttle;有业务副作用的 Action 通常用 dropqueue

调用服务端 Action

yaml
flows:
  purchase:
    - call:
        action: shop:purchase
        input:
          amount: "= state.amount"
        result:
          receipt: state.receipt
          balance: state.balance
        error:
          code: state.errorCode
          message: state.errorMessage
          retryable: state.retryable
        onSuccess: purchaseSucceeded
        onError: purchaseFailed

call 暂停当前 Flow。请求包含 request ID、文档 revision、Action ID 和有界类型输入;服务端验证 Pack 声明、ActionContract 和幂等键后返回类型化结果或结构化错误。

快捷键与生命周期

yaml
shortcuts:
  submit:
    key: enter
    flow: purchase
    trigger: press
    modifiers: [shift]
    consume: true
  closeWithEscape:
    key: escape
    flow: closeScreen

lifecycle:
  onOpen: initialize
  onClose: leaving
  onMount: mounted
  onUnmount: unmounted

onOpen/onClose 对应文档生命周期;onMount/onUnmount 对应文档附着或脱离某个匹配的 Minecraft Screen。

内置客户端 Effect 示例

yaml
- effect: { id: spectrumgraphics:screen-close, arguments: {} }
- effect: { id: spectrumgraphics:hud-visible, arguments: { element: player-status, visible: true } }
- effect: { id: spectrumgraphics:image-animation-restart, arguments: { source: example:logo.gif } }
- effect: { id: spectrumgraphics:container-click, arguments: { node: proxy/quick_move, button: 0 } }

Effect 不是任意客户端脚本。每个 Effect 都经过协商、权限、频率和加权资源预算检查;敏感 Effect 可能需要更严格授权。