import type { Asset } from '../model/Asset'; import { type PropertyBag, type PropertyValue, sameValue } from '../model/Properties'; import type { SceneObject } from '../model/SceneObject'; import { propDef, schemaForAsset } from './PropertySchema'; /** * Schema defaults filled with the asset's own values. Keys unknown to the schema are ignored, so * stale data never leaks into the editor. */ export function resolveAssetProps(asset: Asset): PropertyBag { const bag: PropertyBag = {}; for (const def of schemaForAsset(asset)) { const own = asset.props[def.key]; bag[def.key] = own !== undefined ? own : def.default; } return bag; } /** The only place where overrides are merged onto asset values. */ export function resolveSceneObjectProps(asset: Asset, object: SceneObject): PropertyBag { const bag = resolveAssetProps(asset); for (const def of schemaForAsset(asset)) { const override = object.overrides[def.key]; if (override !== undefined) bag[def.key] = override; } return bag; } /** Whether the asset's own value differs from the schema default – the asset-level override. */ export function isModified(asset: Asset, key: string): boolean { const def = propDef(asset, key); if (!def) return false; const own = asset.props[key]; return own !== undefined && !sameValue(own, def.default); } /** The value the object would have without its override for `key`. */ export function inheritedValue(asset: Asset, key: string): PropertyValue | undefined { return resolveAssetProps(asset)[key]; } /** An override that happens to carry the asset's own value does not count as a deviation. */ export function deviatesFromAsset(object: SceneObject, asset: Asset, key: string): boolean { const own = object.overrides[key]; return own !== undefined && !sameValue(own, inheritedValue(asset, key)); } /** * Compared as overrides, not as effective values: both sides resolve against the same asset, so * "neither overrides" means equal even when the asset value changed since. */ export function deviatesFromTemplate(object: SceneObject, base: SceneObject, key: string): boolean { return !sameValue(object.overrides[key], base.overrides[key]); }