Spawn node: place assets at runtime into the play copy, Spawner demo behavior
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
c3a533c4e5
commit
91ee2feadd
13 files changed
+219
-37
No files matched your search
@@ -4,7 +4,7 @@ import { CommandStack } from '../../src/core/commands/CommandStack';
|
||||
import { AddNodeCommand, ConnectCommand, DisconnectCommand, RemoveNodeCommand, SetNodeParamCommand } from '../../src/core/commands/graphCommands';
|
||||
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 EntityHandle, type Graph, GraphInterpreter, type NodeContext, allNodeDefs, portsCompatible } from '../../src/core/graph';
|
||||
import type { BehaviorAsset } from '../../src/core/model/Asset';
|
||||
import { createEmptyProject } from '../../src/core/model/Project';
|
||||
import { deserializeProject, serializeProject } from '../../src/core/store/serialize';
|
||||
@@ -32,6 +32,7 @@ function context(overrides: Partial<NodeContext> = {}): NodeContext & { logs: st
|
||||
return { blockedX: false, blockedY: false };
|
||||
},
|
||||
log: (m: string) => logs.push(m),
|
||||
spawn: () => null,
|
||||
destroy: () => {},
|
||||
stop: () => { ctx.stopped = true; },
|
||||
...overrides,
|
||||
@@ -382,3 +383,41 @@ describe('behavior serialization', () => {
|
||||
expect(cleaned.graph.edges.length).toBe(behavior.graph.edges.length);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Spawn node', () => {
|
||||
const graph: Graph = {
|
||||
nodes: [
|
||||
{ id: 'start', type: 'OnStart', x: 0, y: 0, params: {} },
|
||||
{ id: 'spawn', type: 'Spawn', x: 0, y: 0, params: { asset: 'crate', x: 5, y: 7 } },
|
||||
{ id: 'log', type: 'Log', x: 0, y: 0, params: {} },
|
||||
],
|
||||
edges: [
|
||||
{ id: 'e1', from: { node: 'start', port: 'exec' }, to: { node: 'spawn', port: 'exec' } },
|
||||
{ id: 'e2', from: { node: 'spawn', port: 'exec' }, to: { node: 'log', port: 'exec' } },
|
||||
{ id: 'e3', from: { node: 'spawn', port: 'object' }, to: { node: 'log', port: 'message' } },
|
||||
],
|
||||
};
|
||||
|
||||
it('asks the context for a new instance at the inline position and outputs it', () => {
|
||||
const calls: unknown[] = [];
|
||||
const ctx = context({
|
||||
spawn: (assetId, position, parent) => {
|
||||
calls.push({ assetId, position, parent });
|
||||
return entity('Crate', position.x);
|
||||
},
|
||||
});
|
||||
new GraphInterpreter(graph).fire('OnStart', ctx);
|
||||
expect(calls).toEqual([{ assetId: 'crate', position: { x: 5, y: 7, z: 0 }, parent: null }]);
|
||||
expect(ctx.logs).toEqual(['Crate']); // the spawned object flowed into Log
|
||||
});
|
||||
|
||||
it('logs a hint and continues when no asset is selected or the asset is unknown', () => {
|
||||
const ctx = context({ spawn: () => null });
|
||||
const noAsset: Graph = { ...graph, nodes: graph.nodes.map((n) => (n.id === 'spawn' ? { ...n, params: {} } : n)) };
|
||||
new GraphInterpreter(noAsset).fire('OnStart', ctx);
|
||||
expect(ctx.logs).toEqual(['Spawn: no asset selected', '']);
|
||||
const ctx2 = context({ spawn: () => null });
|
||||
new GraphInterpreter(graph).fire('OnStart', ctx2);
|
||||
expect(ctx2.logs[0]).toBe('Spawn: asset crate not found');
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user