Let a behavior be a node in another graph
A behavior that has a Start and an End node can now be dropped into any other graph as a node of its own. What is declared on the start node becomes the inputs of that node, what hangs on the end node its outputs; the port list is derived from the sub graph, not copied, so declaring a port in one graph grows the node in the other without touching it. The node carries the behavior's name and the palette lists behaviors by name, so a call is one grab instead of a node plus a dropdown. An embedded behavior has no object and therefore no place for variables: every call starts on the asset defaults and communicates only through its ports. That is the conservative direction - state can still be added later, and shared state already has a home in a behavior object in the scene. Node ids are unique per graph only, so each call gets its own pulse cache; without that, two graphs would collide. Renaming a port used to silently drop the value typed on the calling node. It is carried along now, project wide, like the edges.
This commit is contained in:
1 parent
64e034ffb9
commit
6702ff8abe
31 files changed
+1402
-107
No files matched your search
@@ -1,5 +1,6 @@
|
||||
import { edgesInto, findNode, type Graph, type PortType, portsCompatible } from './Graph';
|
||||
import { type NodeDef, nodeDef } from './NodeRegistry';
|
||||
import { type BehaviorLookup, resolveDef } from './nested';
|
||||
import type { NodeDef } from './NodeRegistry';
|
||||
|
||||
/** One end of an edge being dragged: a port on a node, seen from its own side. */
|
||||
export interface PortSide {
|
||||
@@ -8,18 +9,18 @@ export interface PortSide {
|
||||
isOutput: boolean;
|
||||
}
|
||||
|
||||
export function portTypeOf(graph: Graph, side: PortSide): PortType | undefined {
|
||||
export function portTypeOf(graph: Graph, side: PortSide, lookup: BehaviorLookup): PortType | undefined {
|
||||
const node = findNode(graph, side.nodeId);
|
||||
const def = node && nodeDef(node.type);
|
||||
const def = node && resolveDef(node, lookup);
|
||||
const list = side.isOutput ? def?.outputs : def?.inputs;
|
||||
return list?.find((p) => p.key === side.port)?.type;
|
||||
}
|
||||
|
||||
/** Whether a drag from `from` may land on `to`, i.e. whether ConnectCommand would accept it. */
|
||||
export function canConnect(graph: Graph, from: PortSide, to: PortSide): boolean {
|
||||
export function canConnect(graph: Graph, from: PortSide, to: PortSide, lookup: BehaviorLookup): boolean {
|
||||
if (from.isOutput === to.isOutput || from.nodeId === to.nodeId) return false;
|
||||
const fromType = portTypeOf(graph, from);
|
||||
const toType = portTypeOf(graph, to);
|
||||
const fromType = portTypeOf(graph, from, lookup);
|
||||
const toType = portTypeOf(graph, to, lookup);
|
||||
if (fromType === undefined || toType === undefined) return false;
|
||||
const [out, inp] = from.isOutput ? [fromType, toType] : [toType, fromType];
|
||||
return portsCompatible(out, inp) && !linked(graph, from, to);
|
||||
@@ -30,11 +31,16 @@ export function canConnect(graph: Graph, from: PortSide, to: PortSide): boolean
|
||||
* the first free compatible one, or – when none is free – the last compatible one, whose edge is
|
||||
* then replaced. Returns null when the node offers nothing to connect to.
|
||||
*/
|
||||
export function dropTargetPort(graph: Graph, from: PortSide, nodeId: string): PortSide | null {
|
||||
export function dropTargetPort(
|
||||
graph: Graph,
|
||||
from: PortSide,
|
||||
nodeId: string,
|
||||
lookup: BehaviorLookup,
|
||||
): PortSide | null {
|
||||
if (nodeId === from.nodeId) return null;
|
||||
const node = findNode(graph, nodeId);
|
||||
const def = node && nodeDef(node.type);
|
||||
const fromType = portTypeOf(graph, from);
|
||||
const def = node && resolveDef(node, lookup);
|
||||
const fromType = portTypeOf(graph, from, lookup);
|
||||
if (!def || fromType === undefined) return null;
|
||||
const candidates = compatiblePorts(def, fromType, from.isOutput)
|
||||
.map((p) => ({ side: { nodeId, port: p.key, isOutput: !from.isOutput }, type: p.type }))
|
||||
|
||||
Reference in new issue
Block a user