Scene hierarchy: parentId with local positions, tree panel, reparenting and Parent node
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
551a50ffc9
commit
26d5edc496
22 files changed
+729
-166
No files matched your search
+12
-13
@@ -2,7 +2,7 @@ import { describe, expect, it } from 'vitest';
|
||||
import { buildAsset } from '../../src/core/commands/assetCommands';
|
||||
import { CommandStack } from '../../src/core/commands/CommandStack';
|
||||
import { AddNodeCommand, ConnectCommand, DisconnectCommand, RemoveNodeCommand, SetNodeParamCommand } from '../../src/core/commands/graphCommands';
|
||||
import { PlaceAssetCommand, SetOwnerCommand } from '../../src/core/commands/sceneObjectCommands';
|
||||
import { PlaceAssetCommand, SetParentCommand } from '../../src/core/commands/sceneObjectCommands';
|
||||
import { AddVariableCommand, RemoveVariableCommand, RenameVariableCommand } from '../../src/core/commands/variableCommands';
|
||||
import { type EntityHandle, GraphInterpreter, type NodeContext, allNodeDefs, portsCompatible } from '../../src/core/graph';
|
||||
import type { BehaviorAsset } from '../../src/core/model/Asset';
|
||||
@@ -10,7 +10,7 @@ import { createEmptyProject } from '../../src/core/model/Project';
|
||||
import { deserializeProject, serializeProject } from '../../src/core/store/serialize';
|
||||
|
||||
function entity(name: string, x = 0): EntityHandle {
|
||||
return { id: name, name, x, y: 0, z: 0, props: {} };
|
||||
return { id: name, name, x, y: 0, z: 0, props: {}, parent: null };
|
||||
}
|
||||
|
||||
function context(overrides: Partial<NodeContext> = {}): NodeContext & { logs: string[]; stopped: boolean } {
|
||||
@@ -337,7 +337,7 @@ describe('variables', () => {
|
||||
expect(object.overrides).toEqual({ speed: 5 });
|
||||
});
|
||||
|
||||
it('owner references are validated and cleared when the owner disappears', () => {
|
||||
it('the owner is the parent: validated, kept across a round trip, dropped when dangling', () => {
|
||||
const project = createEmptyProject('p', 'P');
|
||||
const scene = buildAsset('scene', 'S', 's');
|
||||
const sprite = buildAsset('sprite', 'Box', 'box');
|
||||
@@ -348,16 +348,15 @@ describe('variables', () => {
|
||||
const placeB = new PlaceAssetCommand('s', 'b', { x: 0, y: 0 });
|
||||
stack.execute(placeBox);
|
||||
stack.execute(placeB);
|
||||
expect(() => stack.execute(new SetOwnerCommand('s', placeB.objectId, placeB.objectId))).toThrow(/itself/);
|
||||
stack.execute(new SetOwnerCommand('s', placeB.objectId, placeBox.objectId));
|
||||
const objects = () => (project.assets[0] as { objects: { id: string; ownerId: string }[] }).objects;
|
||||
expect(objects()[1]!.ownerId).toBe(placeBox.objectId);
|
||||
// Round trip keeps the owner; a dangling owner is dropped by the loader.
|
||||
const loaded = deserializeProject(serializeProject(project));
|
||||
expect((loaded.assets[0] as { objects: { ownerId: string }[] }).objects[1]!.ownerId).toBe(placeBox.objectId);
|
||||
const raw = serializeProject(project) as { assets: { objects?: { ownerId: string }[] }[] };
|
||||
raw.assets[0]!.objects![1]!.ownerId = 'ghost';
|
||||
expect((deserializeProject(raw).assets[0] as { objects: { ownerId: string }[] }).objects[1]!.ownerId).toBe('');
|
||||
expect(() => stack.execute(new SetParentCommand('s', placeB.objectId, placeB.objectId))).toThrow(/own parent/);
|
||||
stack.execute(new SetParentCommand('s', placeB.objectId, placeBox.objectId));
|
||||
const objectsOf = (p: unknown) => ((p as { assets: { objects: { id: string; parentId: string }[] }[] }).assets[0]!).objects;
|
||||
expect(objectsOf(project)[1]!.parentId).toBe(placeBox.objectId);
|
||||
// Round trip keeps the parent; a dangling parent is dropped by the loader.
|
||||
expect(objectsOf(deserializeProject(serializeProject(project)))[1]!.parentId).toBe(placeBox.objectId);
|
||||
const raw = serializeProject(project) as { assets: { objects?: { parentId: string }[] }[] };
|
||||
raw.assets[0]!.objects![1]!.parentId = 'ghost';
|
||||
expect(objectsOf(deserializeProject(raw))[1]!.parentId).toBe('');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in new issue
Block a user