import type { VariablesAsset } from '../model/Asset'; import type { PropertyBag, PropertyValue } from '../model/Properties'; import type { Project } from '../model/Project'; import { sharedScopeOf } from '../model/Scope'; import { coerceValue } from '../properties/PropertySchema'; /** What a save area holds: the values of each persistent Variables asset, keyed by asset id. */ export type SavedValues = Record; /** * Where the values of persistent Variables assets outlive the run (#166). Played and editor runs * are handed different areas, so trying a behavior in the editor leaves the player's save alone. */ export interface SaveArea { read(): SavedValues; write(saved: SavedValues): void; } /** * A `scene` asset is never persistent, whatever the flag says (#164): its values are thrown away * with every scene, so there is nothing about them worth keeping between runs. Answered here rather * than left to the commands, so no path can produce a saved value the scope would drop anyway. */ export function isPersistent(asset: VariablesAsset): boolean { return asset.persistent === true && sharedScopeOf(asset) !== 'scene'; } function persistentAssets(project: Project): VariablesAsset[] { return project.assets.filter((a): a is VariablesAsset => a.type === 'variables' && isPersistent(a)); } /** * Puts what was saved over the declared start values. The declaration is the truth: a key it no * longer has is ignored, and a value is coerced to the kind it declares now. */ export function restoreSaved( project: Project, variables: Record, saved: SavedValues, ): void { for (const asset of persistentAssets(project)) { const stored = saved[asset.id]; const bag = variables[asset.id]; if (!stored || !bag) continue; for (const def of asset.variables) if (def.key in stored) bag[def.key] = coerceValue(def, stored[def.key] as PropertyValue); } } /** The declared values of every persistent asset as they stand in the run – what a save writes. */ export function savedSnapshot(project: Project, variables: Record): SavedValues { const saved: SavedValues = {}; for (const asset of persistentAssets(project)) { const bag = variables[asset.id]; if (!bag) continue; const values: PropertyBag = {}; for (const def of asset.variables) if (def.key in bag) values[def.key] = bag[def.key]!; saved[asset.id] = values; } return saved; }