registerFlutter3dExtension function

Registration registerFlutter3dExtension(
  1. String name,
  2. VmExtensionHandler handler, {
  3. Set<String> answers = const <String>{},
  4. List<String> aliases = const <String>[],
})

Registers name, an ext.flutter3d.* extension, to be answered by handler, and lists it in ext.flutter3d.version.

answers are the keys of the JSON object handler answers with, the optional ones included: what api/<package>.vm snapshots as the extension's -> line, so a key dropped from an answer is a break the structure check names. Nothing reads it at run time; it is declared here, beside the handler, because an answer built by a toJson() or a helper cannot be read off the source.

aliases are old names of an extension that was renamed. Each is registered too, answers exactly as name does, and is listed under aliases in ext.flutter3d.version, until the next major removes it (CONTRIBUTING.md, "Tools for agents are a contract too": a rename keeps the old name as an alias). An alias follows name on and off.

The one door for the engine's extensions. It is dart:developer's registerExtension with two things added: the name is held to the ext.flutter3d. prefix, and the first call registers vmVersionExtension, so a tool attached to a running game asks one extension what the others are and which schema they speak.

The engine's alone. Exported from package:flutter3d_plugin_api/internal.dart, not from the public library: it takes any name under ext.flutter3d., the areas a minor adds to included, and the VM service cannot forget a name. A plugin and an application register through VmExtensions, which keeps them out of the engine's areas.

Registering a name twice, or an alias another extension has, throws a NameTakenException. Returns the Registration that switches it off: the VM service cannot forget a name, so a switched-off extension answers an error saying so until it is registered again.

Implementation

Registration registerFlutter3dExtension(
  String name,
  VmExtensionHandler handler, {
  Set<String> answers = const <String>{},
  List<String> aliases = const <String>[],
}) {
  _checkName(name, 'name');
  if (_registered[name] != null) {
    throw NameTakenException(name, what: 'the VM service extension');
  }
  for (final alias in aliases) {
    _checkName(alias, 'aliases');
    final held = _aliases[alias];
    if (alias == name ||
        _registered.containsKey(alias) ||
        (held != null && held != name)) {
      throw NameTakenException(
        alias,
        what: 'the VM service extension alias',
        detail: 'it is an extension\'s name or another extension\'s alias',
      );
    }
  }
  if (_registered.isEmpty) {
    // Spelled out rather than [vmVersionExtension], so the snapshot of this
    // package lists it.
    developer.registerExtension(
      'ext.flutter3d.version',
      (String method, Map<String, String> parameters) async =>
          developer.ServiceExtensionResponse.result(
            jsonEncode(<String, Object?>{
              'schemaVersion': vmSchemaVersion,
              'extensions': <String>[
                for (final MapEntry(:key, :value) in _registered.entries)
                  if (value != null) key,
              ]..sort(),
              'aliases': <String, String>{
                for (final old in _aliases.keys.toList()..sort())
                  if (_registered[_aliases[old]] != null) old: _aliases[old]!,
              },
            }),
          ),
    );
  }
  final known = _registered.containsKey(name);
  _registered[name] = handler;
  if (!known) developer.registerExtension(name, _dispatchTo(name));
  for (final alias in aliases) {
    if (_aliases.containsKey(alias)) continue;
    _aliases[alias] = name;
    developer.registerExtension(alias, _dispatchTo(name));
  }
  return Registration(() {
    if (identical(_registered[name], handler)) _registered[name] = null;
  });
}