diffScene function

SceneDiff diffScene(
  1. SceneDocument oldDocument,
  2. SceneDocument newDocument
)

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)),
  );
}