diffScene function
Computes the node-id-keyed diff turning oldDocument into newDocument.
Both documents must be fully composed (no prefab instances); ids are assumed stable across the two (the same node keeps its id when its file is edited).
Implementation
SceneDiff diffScene(SceneDocument oldDocument, SceneDocument newDocument) {
final oldIds = oldDocument.nodes.keys.toSet();
final newIds = newDocument.nodes.keys.toSet();
final added = [
for (final id in newDocument.nodes.keys)
if (!oldIds.contains(id)) id,
];
final removed = [
for (final id in oldDocument.nodes.keys)
if (!newIds.contains(id)) id,
];
final oldParents = _parents(oldDocument);
final newParents = _parents(newDocument);
final changedResources = _changedResources(oldDocument, newDocument);
// Joints of these nodes are live Node objects that get recreated, so any
// skin binding them must be rebuilt even when its spec is unchanged.
final staleNodes = {...added, ...removed};
final changed = <NodeChange>[];
for (final id in newDocument.nodes.keys) {
if (!oldIds.contains(id)) continue;
final oldNode = oldDocument.nodes[id]!;
final newNode = newDocument.nodes[id]!;
final change = NodeChange(
id,
transform:
!_transformsEqual(oldNode.transform, newNode.transform) ||
oldNode.excludeFromWindingParity != newNode.excludeFromWindingParity,
name: oldNode.name != newNode.name,
layers: oldNode.layers != newNode.layers,
visible: oldNode.visible != newNode.visible,
reparented: oldParents[id] != newParents[id],
components:
!_componentsEqual(oldNode.components, newNode.components) ||
_referencesAny(newNode.components, changedResources),
skin: !_skinsEqual(
oldDocument,
newDocument,
oldNode,
newNode,
staleNodes,
),
);
if (change.transform ||
change.name ||
change.layers ||
change.visible ||
change.reparented ||
change.components ||
change.skin) {
changed.add(change);
}
}
return SceneDiff(
added: added,
removed: removed,
changed: changed,
animationsChanged: _animationsChanged(
oldDocument,
newDocument,
staleNodes,
changed,
),
stageChanged:
canonicalJson(encodeStage(oldDocument.stage)) !=
canonicalJson(encodeStage(newDocument.stage)),
);
}