load<T> method
Reads key's source, decodes it through the key's loader, and completes
with the loaded handle. A no-op returning the same handle if it is
already loaded.
Throws if key was never declared. That is deliberate rather than a
convenience lazy-declare: declaring here would assign an address on this
copy alone, and the two copies would silently disagree about every
address after it. Declare in a describeAssets pass, which both copies
run.
Call this only on the isolate that can decode - GameState.loadScene
already does exactly that for a scene's declared set.
Implementation
Future<Asset<T>> load<T>(AssetKey<T> key) {
final identity = _identityOf(key);
final asset = _byIdentity[identity] as Asset<T>?;
if (asset == null) {
throw StateError(
'${key.debugLabel} has not been declared, so there is nothing to load '
'into. Declare it from a describeAssets pass '
'(`descriptor.has(theKey)`) on a prefab or a SceneStruct: declaring is '
'what assigns the asset its address, and it has to happen on both '
'isolate copies in the same order for that address to mean the same '
'thing on both sides.',
);
}
if (asset.isLoaded) return Future<Asset<T>>.value(asset);
final inFlight = _loading[identity];
if (inFlight != null) return inFlight.then((_) => asset);
final future = _decode(key, asset, identity);
_loading[identity] = future;
return future.then((_) => asset);
}