loadScene method

Future<Node> loadScene(
  1. String sourcePath, {
  2. String? package,
  3. AssetBundle? bundle,
  4. FsceneComponentRegistry? registry,
  5. SceneReloadCallback? onReload,
  6. Scene? applyStageTo,
})

Loads the scene whose source is sourcePath as a Node.

The composed document and its realized GPU resources (geometry, materials, textures) are cached per scene, so loading the same scene again instantiates a fresh node graph cheaply, sharing those resources.

Pass applyStageTo to also apply the document's stage render settings (environment, exposure, tone mapping, skybox, and sky lighting) to that scene, kept fresh across hot reloads. Pass a custom registry to realize app-defined component types, and onReload to re-apply per-instance customizations after a hot reload patches this instance in place.

Implementation

Future<Node> loadScene(
  String sourcePath, {
  String? package,
  AssetBundle? bundle,
  FsceneComponentRegistry? registry,
  SceneReloadCallback? onReload,
  Scene? applyStageTo,
}) async {
  // Debug source-direct mode: when the app was launched with a scene
  // source root and this scene's source exists there, read it (and its
  // prefabs) straight from the project so saves are visible without a
  // rebuild. Anything without a source file falls back to its DataAsset.
  final source = bundle == null ? activeSceneSourceLoader() : null;
  final sourceKey = source?.resolveScene(sourcePath);
  if (source != null && sourceKey != null) {
    try {
      return await _loadRealized(
        key: sourceKey,
        bundle: source.bundle,
        readComposed: (seen) => _readComposedSource(source, sourceKey, seen),
        registry: registry,
        onReload: onReload,
        applyStageTo: applyStageTo,
      );
    } catch (e) {
      // An unreadable source (sandboxed app) turns source loading off and
      // falls through to the bundled DataAsset below.
      if (!source.deactivateOnAccessError(e, sourceKey)) rethrow;
      if (activeSceneSourceLoader() == null) {
        // Deactivated. Templates cached under source keys are unreachable
        // by releaseScene now (it resolves DataAsset keys); drop them so
        // their claims cannot strand.
        for (final key
            in _sceneTemplates.keys.where(source.isSourceKey).toList()) {
          _sceneTemplates.remove(key);
          _sceneTemplateHolders.remove(key);
        }
      }
    }
  }

  final key = resolveKey(sourcePath, package: package);
  final assetBundle = bundle ?? rootBundle;

  // Reads the host document and expands any prefab instances, resolving
  // each referenced prefab by source path against this same registry,
  // collecting the asset keys touched into [seen]. (Lazily streamed
  // subtrees register their own assets when loaded; see [loadSubtree].)
  Future<SceneDocument> readComposed(Set<String> seen) async {
    final document = _resolveRefs(await _readDocument(key, assetBundle), key);
    return document.nodes.values.any((n) => n.instance != null)
        ? await composeSceneAsync(
            document,
            load: (ref) {
              final refKey = ref.key;
              seen.add(refKey);
              return _readDocument(
                refKey,
                assetBundle,
              ).then((document) => _resolveRefs(document, refKey));
            },
          )
        : document;
  }

  return _loadRealized(
    key: key,
    bundle: assetBundle,
    readComposed: readComposed,
    registry: registry,
    onReload: onReload,
    applyStageTo: applyStageTo,
  );
}