Initial flame_lua_runtime package
This commit is contained in:
173
lib/runtime/models/game_diff.dart
Normal file
173
lib/runtime/models/game_diff.dart
Normal file
@@ -0,0 +1,173 @@
|
||||
import 'runtime_command.dart';
|
||||
import 'runtime_node.dart';
|
||||
|
||||
import '../protocol/runtime_protocol.dart';
|
||||
|
||||
class NodeUpdate {
|
||||
const NodeUpdate({required this.id, required this.props});
|
||||
|
||||
final String id;
|
||||
final Map<String, Object?> props;
|
||||
|
||||
static NodeUpdate fromMap(Map<String, Object?> map) {
|
||||
RuntimeProtocolSchema.ensureKnownKeys(
|
||||
map,
|
||||
allowed: RuntimeProtocolSchema.nodeUpdateFields,
|
||||
context: 'NodeUpdate',
|
||||
);
|
||||
final id = map[RuntimeProtocolField.id];
|
||||
if (id is! String || id.isEmpty) {
|
||||
throw const FormatException('NodeUpdate.id must be a string');
|
||||
}
|
||||
|
||||
final props = map[RuntimeProtocolField.props];
|
||||
if (props is! Map) {
|
||||
throw const FormatException('NodeUpdate.props must be a map');
|
||||
}
|
||||
|
||||
final typedProps = Map<String, Object?>.from(props);
|
||||
RuntimeProtocolSchema.ensureKnownKeys(
|
||||
typedProps,
|
||||
allowed: RuntimeProtocolSchema.nodePropsFields,
|
||||
context: 'RuntimeNode.props',
|
||||
);
|
||||
|
||||
return NodeUpdate(id: id, props: typedProps);
|
||||
}
|
||||
}
|
||||
|
||||
class NodeRemove {
|
||||
const NodeRemove({required this.id});
|
||||
|
||||
final String id;
|
||||
|
||||
static NodeRemove fromValue(Object? value) {
|
||||
if (value is String && value.isNotEmpty) {
|
||||
return NodeRemove(id: value);
|
||||
}
|
||||
if (value is Map) {
|
||||
RuntimeProtocolSchema.ensureKnownKeys(
|
||||
value,
|
||||
allowed: RuntimeProtocolSchema.nodeRemoveFields,
|
||||
context: 'NodeRemove',
|
||||
);
|
||||
final id = value[RuntimeProtocolField.id];
|
||||
if (id is String && id.isNotEmpty) {
|
||||
return NodeRemove(id: id);
|
||||
}
|
||||
}
|
||||
throw const FormatException('NodeRemove must be an id string or {id}');
|
||||
}
|
||||
}
|
||||
|
||||
class NodeDiff {
|
||||
const NodeDiff({
|
||||
this.creates = const [],
|
||||
this.updates = const [],
|
||||
this.removes = const [],
|
||||
});
|
||||
|
||||
final List<RuntimeNode> creates;
|
||||
final List<NodeUpdate> updates;
|
||||
final List<NodeRemove> removes;
|
||||
|
||||
static NodeDiff empty = const NodeDiff();
|
||||
|
||||
static NodeDiff fromMap(Object? value) {
|
||||
if (value == null) {
|
||||
return NodeDiff.empty;
|
||||
}
|
||||
if (value is! Map) {
|
||||
throw const FormatException('NodeDiff must be a map');
|
||||
}
|
||||
RuntimeProtocolSchema.ensureKnownKeys(
|
||||
value,
|
||||
allowed: RuntimeProtocolSchema.nodeDiffFields,
|
||||
context: 'NodeDiff',
|
||||
);
|
||||
|
||||
return NodeDiff(
|
||||
creates: _readList(
|
||||
value[RuntimeProtocolField.creates],
|
||||
(item) => RuntimeNode.fromMap(Map<String, Object?>.from(item as Map)),
|
||||
),
|
||||
updates: _readList(
|
||||
value[RuntimeProtocolField.updates],
|
||||
(item) => NodeUpdate.fromMap(Map<String, Object?>.from(item as Map)),
|
||||
),
|
||||
removes: _readList(
|
||||
value[RuntimeProtocolField.removes],
|
||||
NodeRemove.fromValue,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
static List<T> _readList<T>(Object? value, T Function(Object? value) mapper) {
|
||||
if (value == null) {
|
||||
return const [];
|
||||
}
|
||||
if (value is List) {
|
||||
return value.map(mapper).toList(growable: false);
|
||||
}
|
||||
if (value is Map && value.isEmpty) {
|
||||
return const [];
|
||||
}
|
||||
if (value is Map && value.keys.every(_isPositiveIntegerKey)) {
|
||||
final entries = value.entries.toList()
|
||||
..sort(
|
||||
(a, b) => int.parse(
|
||||
a.key.toString(),
|
||||
).compareTo(int.parse(b.key.toString())),
|
||||
);
|
||||
return entries
|
||||
.map((entry) => mapper(entry.value))
|
||||
.toList(growable: false);
|
||||
}
|
||||
throw const FormatException('Diff field must be a list');
|
||||
}
|
||||
|
||||
static bool _isPositiveIntegerKey(Object? key) {
|
||||
final value = int.tryParse(key.toString());
|
||||
return value != null && value > 0;
|
||||
}
|
||||
}
|
||||
|
||||
class GameDiff {
|
||||
const GameDiff({
|
||||
required this.render,
|
||||
required this.ui,
|
||||
required this.commands,
|
||||
});
|
||||
|
||||
final NodeDiff render;
|
||||
final NodeDiff ui;
|
||||
final List<RuntimeCommand> commands;
|
||||
|
||||
static const empty = GameDiff(
|
||||
render: NodeDiff(),
|
||||
ui: NodeDiff(),
|
||||
commands: [],
|
||||
);
|
||||
|
||||
static GameDiff fromMap(Map<String, Object?> map) {
|
||||
RuntimeProtocolSchema.ensureKnownKeys(
|
||||
map,
|
||||
allowed: RuntimeProtocolSchema.gameDiffFields,
|
||||
context: 'GameDiff',
|
||||
);
|
||||
final commandsValue = map[RuntimeProtocolField.commands];
|
||||
final commands = commandsValue == null
|
||||
? const <RuntimeCommand>[]
|
||||
: NodeDiff._readList(
|
||||
commandsValue,
|
||||
(item) =>
|
||||
RuntimeCommand.fromMap(Map<String, Object?>.from(item as Map)),
|
||||
);
|
||||
|
||||
return GameDiff(
|
||||
render: NodeDiff.fromMap(map[RuntimeProtocolField.render]),
|
||||
ui: NodeDiff.fromMap(map[RuntimeProtocolField.ui]),
|
||||
commands: commands,
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user