155 lines
5.5 KiB
Dart
155 lines
5.5 KiB
Dart
part of 'command_executor.dart';
|
|
|
|
extension _CommandExecutorValidation on CommandExecutor {
|
|
void _validate(RuntimeCommand command) {
|
|
if (!RuntimeCommandType.isSupported(command.type)) {
|
|
throw UnsupportedError('Unsupported runtime command: ${command.type}');
|
|
}
|
|
RuntimeProtocolSchema.ensureKnownKeys(
|
|
command.payload,
|
|
allowed: RuntimeProtocolSchema.allowedCommandPayloadFields(command.type),
|
|
context: 'RuntimeCommand.${command.type}.payload',
|
|
);
|
|
_optionalString(command.payload['id'], 'id');
|
|
_optionalString(command.payload['group'], 'group');
|
|
_optionalString(command.payload['commandGroup'], 'commandGroup');
|
|
_optionalString(command.payload['scope'], 'scope');
|
|
_estimatedDuration(command);
|
|
}
|
|
|
|
double _estimatedDuration(RuntimeCommand command) {
|
|
_optionalString(command.payload['onComplete'], 'onComplete');
|
|
|
|
switch (command.type) {
|
|
case RuntimeCommandType.movePath:
|
|
_requiredTarget(command);
|
|
_validatePath(command.payload['path']);
|
|
return _duration(command, defaultValue: 0.4);
|
|
case RuntimeCommandType.moveTo:
|
|
_requiredTarget(command);
|
|
_requiredVector(command);
|
|
return _duration(command, defaultValue: 0.2);
|
|
case RuntimeCommandType.fadeTo:
|
|
_requiredTarget(command);
|
|
_requiredNormalizedDouble(command.payload['alpha'], 'fade_to.alpha');
|
|
return _duration(command, defaultValue: 0.2);
|
|
case RuntimeCommandType.scaleTo:
|
|
_requiredTarget(command);
|
|
_requiredDouble(command.payload['scale'], 'scale_to.scale');
|
|
return _duration(command, defaultValue: 0.2);
|
|
case RuntimeCommandType.rotateTo:
|
|
_requiredTarget(command);
|
|
_requiredDouble(command.payload['angle'], 'rotate_to.angle');
|
|
return _duration(command, defaultValue: 0.2);
|
|
case RuntimeCommandType.removeNode:
|
|
_requiredTarget(command);
|
|
return 0;
|
|
case RuntimeCommandType.delay:
|
|
return _duration(command, defaultValue: 0);
|
|
case RuntimeCommandType.sequence:
|
|
return _commandsFromPayload(
|
|
command,
|
|
).fold<double>(0, (sum, child) => sum + _estimatedDuration(child));
|
|
case RuntimeCommandType.parallel:
|
|
var maxDuration = 0.0;
|
|
for (final child in _commandsFromPayload(command)) {
|
|
final duration = _estimatedDuration(child);
|
|
if (duration > maxDuration) {
|
|
maxDuration = duration;
|
|
}
|
|
}
|
|
return maxDuration;
|
|
case RuntimeCommandType.toast:
|
|
_toastText(command);
|
|
return _duration(command, defaultValue: 1.8);
|
|
case RuntimeCommandType.playSound:
|
|
_requiredAudioResource(command);
|
|
_optionalVolume(command);
|
|
return 0;
|
|
case RuntimeCommandType.playBgm:
|
|
_requiredAudioResource(command);
|
|
_optionalVolume(command);
|
|
_audioChannel(command);
|
|
_optionalBool(command.payload['loop'], 'play_bgm.loop');
|
|
return 0;
|
|
case RuntimeCommandType.pauseBgm:
|
|
case RuntimeCommandType.resumeBgm:
|
|
case RuntimeCommandType.stopBgm:
|
|
_audioChannel(command);
|
|
return 0;
|
|
case RuntimeCommandType.preloadResources:
|
|
_requiredResourceGroup(command);
|
|
_optionalBool(
|
|
command.payload['failOnError'],
|
|
'preload_resources.failOnError',
|
|
);
|
|
return 0;
|
|
case RuntimeCommandType.evictResources:
|
|
_requiredResourceGroup(command);
|
|
return 0;
|
|
case RuntimeCommandType.cancelCommands:
|
|
_validateCancelCommands(command);
|
|
return 0;
|
|
case RuntimeCommandType.playSpineAnimation:
|
|
_requiredTarget(command);
|
|
_requiredSpineAnimation(command);
|
|
final track = _optionalInt(
|
|
command.payload['track'],
|
|
'play_spine_animation.track',
|
|
);
|
|
if (track != null && track < 0) {
|
|
throw const FormatException(
|
|
'play_spine_animation.track must be >= 0',
|
|
);
|
|
}
|
|
_optionalBool(command.payload['loop'], 'play_spine_animation.loop');
|
|
_optionalBool(command.payload['queue'], 'play_spine_animation.queue');
|
|
final delay = _readDouble(command.payload['delay']);
|
|
if (delay != null && delay < 0) {
|
|
throw const FormatException(
|
|
'play_spine_animation.delay must be >= 0',
|
|
);
|
|
}
|
|
return 0;
|
|
case RuntimeCommandType.copyText:
|
|
_requiredText(command, 'copy_text.text');
|
|
return 0;
|
|
default:
|
|
throw UnsupportedError('Unsupported runtime command: ${command.type}');
|
|
}
|
|
}
|
|
|
|
void _validatePath(Object? pathValue) {
|
|
if (pathValue is! List || pathValue.isEmpty) {
|
|
throw const FormatException('move_path.path must be a non-empty list');
|
|
}
|
|
for (final point in pathValue) {
|
|
if (point is! Map) {
|
|
throw const FormatException('move_path.path item must be a map');
|
|
}
|
|
final x = _readDouble(point['x']);
|
|
final y = _readDouble(point['y']);
|
|
if (x == null || y == null) {
|
|
throw const FormatException('move_path point requires x/y');
|
|
}
|
|
}
|
|
}
|
|
|
|
List<RuntimeCommand> _commandsFromPayload(RuntimeCommand command) {
|
|
final value = command.payload['commands'];
|
|
if (value is! List) {
|
|
throw FormatException('${command.type}.commands must be a list');
|
|
}
|
|
return value
|
|
.map((item) {
|
|
if (item is! Map) {
|
|
throw FormatException(
|
|
'${command.type}.commands item must be a map',
|
|
);
|
|
}
|
|
return RuntimeCommand.fromMap(Map<String, Object?>.from(item));
|
|
})
|
|
.toList(growable: false);
|
|
}
|
|
}
|