A behavior has rows of its own, so loading no longer drops Run in editor
`deserializeProject` builds each asset's effective schema in pass 1 and coerces
`props` against it in pass 2. For a behavior that schema was
`[...COMMON_PROPS, ...variables]` -- but `runInEditor` lives in
`ASSET_SCHEMAS.behavior`, not in `COMMON_PROPS`, so `normalizeBag` dropped the
value as undeclared. The flag therefore survived no save: every reload switched
it back off.
The fix is the full schema, `schemaFor('behavior')`, which is what
`schemaForAsset` hands out everywhere else.
Found by a round-trip test comparing the whole project rather than one field. An
existing test had the loss written down as its expectation
(`{ enabled, speed }`), which is why nothing ever reported it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
68c92daaa6
commit
9027a86edd
3 files changed
+15
-4
No files matched your search
@@ -40,7 +40,6 @@ import {
|
||||
import { type FlatItem, makeFlatItem } from '../properties/listItems';
|
||||
import {
|
||||
coerceValue,
|
||||
COMMON_PROPS,
|
||||
isValidFieldName,
|
||||
isValidVariableName,
|
||||
type PropertyDef,
|
||||
@@ -76,7 +75,9 @@ export function deserializeProject(raw: unknown, fallbackId = ''): Project {
|
||||
if (a.type === 'behavior') {
|
||||
const vars = normalizeVariables(a.variables);
|
||||
variables.set(a.id, vars);
|
||||
schemas.set(a.id, [...COMMON_PROPS, ...vars]);
|
||||
// The full schema, not just the common rows: this is what pass 2 coerces `props` against, and
|
||||
// a behavior's own `runInEditor` would be dropped as undeclared.
|
||||
schemas.set(a.id, [...schemaFor('behavior'), ...vars]);
|
||||
} else if (a.type === 'particles') {
|
||||
// A source's rows end with its own graph's parameters, so the graph is needed before the
|
||||
// overrides of the objects placed from it can be coerced.
|
||||
|
||||
@@ -475,7 +475,7 @@ describe('behavior serialization', () => {
|
||||
const loaded = findAsset(roundTrip(project), behavior.id) as BehaviorAsset;
|
||||
expect(loaded.variables).toEqual(behavior.variables);
|
||||
expect(loaded.graph).toEqual(behavior.graph);
|
||||
expect(loaded.props).toEqual({ enabled: true, speed: 0 });
|
||||
expect(loaded.props).toEqual({ enabled: true, runInEditor: false, speed: 0 });
|
||||
|
||||
const raw = serializeProject(project) as {
|
||||
assets: { id: string; graph?: { nodes: unknown[]; edges: unknown[] } }[];
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { SetAssetPropertyCommand } from '../../src/core/commands/assetCommands';
|
||||
import { SetOverrideCommand } from '../../src/core/commands/sceneObjectCommands';
|
||||
import { deserializeProject } from '../../src/core/store/serialize';
|
||||
import { makeSpriteScene, place, roundTrip } from '../helpers';
|
||||
import { makeBehavior, makeSpriteScene, place, roundTrip } from '../helpers';
|
||||
|
||||
describe('serialize', () => {
|
||||
it('round-trips a project', () => {
|
||||
@@ -11,6 +12,15 @@ describe('serialize', () => {
|
||||
expect(roundTrip(f.project)).toEqual(f.project);
|
||||
});
|
||||
|
||||
/** A behavior's own rows are not the common ones: coercing against those alone dropped the value. */
|
||||
it('keeps a behavior running in the editor across a save', () => {
|
||||
const f = makeSpriteScene();
|
||||
const behavior = makeBehavior(f, 'B');
|
||||
f.stack.execute(new SetAssetPropertyCommand(behavior.id, 'runInEditor', true));
|
||||
const loaded = roundTrip(f.project).assets.find((a) => a.id === behavior.id)!;
|
||||
expect(loaded.props.runInEditor).toBe(true);
|
||||
});
|
||||
|
||||
it('repairs broken documents', () => {
|
||||
const project = deserializeProject(
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user