Skip to content

Commit 9390375

Browse files
author
benni-tec
committed
Merge branch 'flame-engine#70-tsx-provider' into gamut
# Conflicts: # packages/tiled/lib/src/tileset/tile.dart # packages/tiled/pubspec.yaml # packages/tiled/test/parser_test.dart
2 parents 3a057e0 + 838bb52 commit 9390375

23 files changed

+253
-152
lines changed

README.md

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,15 @@ Load a TMX file into a string by any means, and then pass the string to TileMapP
2929
final TiledMap mapTmx = TileMapParser.parseTmx(tmxBody);
3030
```
3131

32-
If your tmx file includes a external tsx reference, you have to add a CustomParser
32+
If your tmx file includes a external tsx reference, you have to add a CustomParser. This can either be done by using extending the TsxProviderBase, which can match multiple files, or by extending TsxProvider, which only matches on file by its name.
3333
```dart
34-
class CustomTsxProvider extends TsxProvider {
34+
class MultipleTsxProvider extends TsxProviderBase {
35+
@override
36+
bool checkProvidable(String filename) => ["external1.tsx", "external2.tsx"].contains(filename);
37+
38+
@override
39+
Parser? getCachedSource(String filename) => null;
40+
3541
@override
3642
Parser getSource(String fileName) {
3743
final xml = File(fileName).readAsStringSync();
@@ -40,10 +46,27 @@ class CustomTsxProvider extends TsxProvider {
4046
}
4147
}
4248
```
43-
And use it in the parseTmx method
49+
50+
```dart
51+
class SingleTsxProvider extends TsxProvider {
52+
@override
53+
String get filename => "external.tsx";
54+
55+
@override
56+
Parser? getCachedSource() => null;
57+
58+
@override
59+
Parser getSource(String _) {
60+
final xml = File(filename).readAsStringSync();
61+
final node = XmlDocument.parse(xml).rootElement;
62+
return XmlParser(node);
63+
}
64+
}
65+
```
66+
And use it in the parseTmx method. Keep in mind that the first TsxProvider that can provide a source is used!
4467
```dart
4568
final String tmxBody = /* ... */;
46-
final TiledMap mapTmx = TileMapParser.parseTmx(tmxBody, tsx: CustomTsxProvider());
69+
final TiledMap mapTmx = TileMapParser.parseTmx(tmxBody, tsxProviders: [SingleTsxProvider(), MultipleTsxProvider()]);
4770
4871
```
4972

packages/tiled/lib/src/layer.dart

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ abstract class Layer with Exportable {
112112
this.properties = CustomProperties.empty,
113113
});
114114

115-
static Layer parse(Parser parser) {
115+
static Layer parse(Parser parser, {List<ParserProvider>? templateProviders}) {
116116
final type = parser.formatSpecificParsing(
117117
(json) => json.getLayerType('type'),
118118
(xml) => LayerTypeExtension.parseFromTmx(xml.element.name.toString()),
@@ -272,7 +272,10 @@ abstract class Layer with Exportable {
272272

273273
static List<Layer> parseLayers(Parser parser) {
274274
return parser.formatSpecificParsing(
275-
(json) => json.getChildrenAs('layers', Layer.parse),
275+
(json) => json.getChildrenAs(
276+
'layers',
277+
Layer.parse,
278+
),
276279
(xml) {
277280
// It's very important not change the order of the layers
278281
// during parsing!

packages/tiled/lib/src/objects/tiled_object.dart

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,9 @@ class TiledObject with Exportable {
5959
bool point;
6060
bool rectangle;
6161

62+
String? templatePath;
6263
Template? template;
64+
6365
Text? text;
6466
bool visible;
6567

@@ -84,6 +86,7 @@ class TiledObject with Exportable {
8486
this.ellipse = false,
8587
this.point = false,
8688
this.rectangle = false,
89+
this.templatePath,
8790
this.template,
8891
this.text,
8992
this.visible = true,
@@ -102,7 +105,8 @@ class TiledObject with Exportable {
102105

103106
bool get isRectangle => rectangle;
104107

105-
factory TiledObject.parse(Parser parser) {
108+
factory TiledObject.parse(
109+
Parser parser) {
106110
final x = parser.getDouble('x', defaults: 0);
107111
final y = parser.getDouble('y', defaults: 0);
108112
final height = parser.getDouble('height', defaults: 0);
@@ -130,7 +134,17 @@ class TiledObject with Exportable {
130134
(xml) => xml.getChildren('point').isNotEmpty,
131135
);
132136
final text = parser.getSingleChildOrNullAs('text', Text.parse);
133-
final template = parser.getSingleChildOrNullAs('template', Template.parse);
137+
final templatePath = parser.getStringOrNull('template');
138+
final templateProvider = templatePath == null
139+
? null
140+
: parser.templateProviders?.firstWhere((e) => e.canProvide(templatePath));
141+
final template = templateProvider == null
142+
? null
143+
: Template.parse(
144+
templateProvider.getCachedSource(templatePath!) ??
145+
templateProvider.getSource(templatePath),
146+
);
147+
134148
final properties = parser.getProperties();
135149

136150
final polygon = parsePointList(parser, 'polygon');
@@ -151,6 +165,7 @@ class TiledObject with Exportable {
151165
ellipse: ellipse,
152166
point: point,
153167
rectangle: rectangle,
168+
templatePath: templatePath,
154169
template: template,
155170
text: text,
156171
visible: visible,

packages/tiled/lib/src/parser.dart

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,25 @@ class ParsingException implements Exception {
44
final String name;
55
final String? valueFound;
66
final String reason;
7+
78
ParsingException(this.name, this.valueFound, this.reason);
89
}
910

1011
class XmlParser extends Parser {
1112
final XmlElement element;
12-
XmlParser(this.element);
13+
14+
XmlParser(this.element, {super.tsxProviders, super.templateProviders});
15+
16+
factory XmlParser.fromString(
17+
String string, {
18+
List<ParserProvider>? tsxProviders,
19+
List<ParserProvider>? templateProviders,
20+
}) =>
21+
XmlParser(
22+
XmlDocument.parse(string).rootElement,
23+
tsxProviders: tsxProviders,
24+
templateProviders: templateProviders,
25+
);
1326

1427
@override
1528
String? getStringOrNull(String name, {String? defaults}) {
@@ -21,15 +34,23 @@ class XmlParser extends Parser {
2134
return element.children
2235
.whereType<XmlElement>()
2336
.where((e) => e.name.local == name)
24-
.map(XmlParser.new)
37+
.map((e) => XmlParser(
38+
e,
39+
templateProviders: templateProviders,
40+
tsxProviders: tsxProviders,
41+
))
2542
.toList();
2643
}
2744

2845
List<Parser> getChildrenWithNames(Set<String> names) {
2946
return element.children
3047
.whereType<XmlElement>()
3148
.where((e) => names.contains(e.name.local))
32-
.map(XmlParser.new)
49+
.map((e) => XmlParser(
50+
e,
51+
tsxProviders: tsxProviders,
52+
templateProviders: templateProviders,
53+
))
3354
.toList();
3455
}
3556

@@ -44,7 +65,19 @@ class XmlParser extends Parser {
4465

4566
class JsonParser extends Parser {
4667
final Map<String, dynamic> json;
47-
JsonParser(this.json);
68+
69+
JsonParser(this.json, {super.tsxProviders, super.templateProviders});
70+
71+
factory JsonParser.fromString(
72+
String string, {
73+
List<ParserProvider>? tsxProviders,
74+
List<ParserProvider>? templateProviders,
75+
}) =>
76+
JsonParser(
77+
jsonDecode(string) as Map<String, dynamic>,
78+
tsxProviders: tsxProviders,
79+
templateProviders: templateProviders,
80+
);
4881

4982
@override
5083
String? getStringOrNull(String name, {String? defaults}) {
@@ -57,7 +90,11 @@ class JsonParser extends Parser {
5790
return [];
5891
}
5992
return (json[name] as List<dynamic>)
60-
.map((dynamic e) => JsonParser(e as Map<String, dynamic>))
93+
.map((dynamic e) => JsonParser(
94+
e as Map<String, dynamic>,
95+
templateProviders: templateProviders,
96+
tsxProviders: tsxProviders,
97+
))
6198
.toList();
6299
}
63100

@@ -75,6 +112,11 @@ class JsonParser extends Parser {
75112
}
76113

77114
abstract class Parser {
115+
final List<ParserProvider>? templateProviders;
116+
final List<ParserProvider>? tsxProviders;
117+
118+
Parser({this.tsxProviders, this.templateProviders});
119+
78120
String? getStringOrNull(String name, {String? defaults});
79121

80122
List<Parser> getChildren(String name);

packages/tiled/lib/src/provider.dart

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
part of tiled;
2+
3+
abstract class Provider<T> {
4+
bool canProvide(String path);
5+
6+
T getSource(String path);
7+
T? getCachedSource(String path);
8+
}
9+
10+
typedef ParserProvider = Provider<Parser>;
11+
typedef ImagePathProvider = Provider<String>;

packages/tiled/lib/src/template.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,7 @@ class Template {
3434
object: parser.getSingleChildOrNullAs('object', TiledObject.parse),
3535
);
3636
}
37+
38+
class TemplateReference {
39+
40+
}

packages/tiled/lib/src/tile_map_parser.dart

Lines changed: 0 additions & 21 deletions
This file was deleted.

packages/tiled/lib/src/tiled_map.dart

Lines changed: 64 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -125,28 +125,31 @@ class TiledMap with Exportable {
125125
/// the [TsxProvider]s returned from the [tsxProviderFunction].
126126
/// The [tsxProviderFunction] is most commonly your static [TsxProvider.parse]
127127
/// implementation.
128-
static Future<TiledMap> fromString(
129-
String contents,
130-
Future<TsxProvider> Function(String key) tsxProviderFunction,
131-
) async {
132-
final tsxSourcePaths = XmlDocument.parse(contents)
133-
.rootElement
134-
.children
135-
.whereType<XmlElement>()
136-
.where((element) => element.name.local == 'tileset')
137-
.map((e) => e.getAttribute('source'));
138-
139-
final tsxProviders = await Future.wait(
140-
tsxSourcePaths
141-
.where((key) => key != null)
142-
.map((key) async => tsxProviderFunction(key!)),
143-
);
144-
145-
return TileMapParser.parseTmx(
146-
contents,
147-
tsxList: tsxProviders.isEmpty ? null : tsxProviders,
148-
);
149-
}
128+
// TODO: why is this here? same as parseTmx???
129+
// static Future<TiledMap> fromString(
130+
// String contents, {
131+
// List<ParserProvider>? tsxProviders,
132+
// List<ParserProvider>? templateProviders,
133+
// List<ImagePathProvider>? imageProviders,
134+
// }) async {
135+
// final tsxSourcePaths = XmlDocument.parse(contents)
136+
// .rootElement
137+
// .children
138+
// .whereType<XmlElement>()
139+
// .where((element) => element.name.local == 'tileset')
140+
// .map((e) => e.getAttribute('source'));
141+
//
142+
// final tsxProviders = await Future.wait(
143+
// tsxSourcePaths
144+
// .where((key) => key != null)
145+
// .map((key) async => tsxProviderFunction(key!)),
146+
// );
147+
//
148+
// return TileMapParser.parseTmx(
149+
// contents,
150+
// tsxList: tsxProviders.isEmpty ? null : tsxProviders,
151+
// );
152+
// }
150153

151154
// Convenience Methods
152155
Tile? tileByGid(int tileGid) {
@@ -286,7 +289,41 @@ class TiledMap with Exportable {
286289
);
287290
}
288291

289-
factory TiledMap.parse(Parser parser, {List<TsxProvider>? tsxList}) {
292+
static TiledMap parseJson(
293+
String json, {
294+
List<ParserProvider>? tsxProviders,
295+
List<ParserProvider>? templateProviders,
296+
}) {
297+
final parser = JsonParser(
298+
jsonDecode(json) as Map<String, dynamic>,
299+
templateProviders: templateProviders,
300+
tsxProviders: tsxProviders,
301+
);
302+
return TiledMap.parse(parser);
303+
}
304+
305+
/// Parses the provided map xml.
306+
///
307+
/// Accepts an optional list of external TsxProviders for external tilesets
308+
/// referenced in the map file.
309+
factory TiledMap.parseTmx(
310+
String xml, {
311+
List<ParserProvider>? tsxProviders,
312+
List<ParserProvider>? templateProviders,
313+
}) {
314+
final xmlElement = XmlDocument.parse(xml).rootElement;
315+
if (xmlElement.name.local != 'map') {
316+
throw 'XML is not in TMX format';
317+
}
318+
final parser = XmlParser(
319+
xmlElement,
320+
tsxProviders: tsxProviders,
321+
templateProviders: templateProviders,
322+
);
323+
return TiledMap.parse(parser);
324+
}
325+
326+
factory TiledMap.parse(Parser parser) {
290327
final backgroundColorHex = parser.getStringOrNull('backgroundcolor');
291328
final backgroundColor = parser.getColorOrNull('backgroundcolor');
292329
final compressionLevel = parser.getInt('compressionlevel', defaults: -1);
@@ -313,11 +350,12 @@ class TiledMap with Exportable {
313350
'tileset',
314351
(tilesetData) {
315352
final tilesetSource = tilesetData.getStringOrNull('source');
316-
if (tilesetSource == null || tsxList == null) {
353+
if (tilesetSource == null || parser.tsxProviders == null) {
317354
return Tileset.parse(tilesetData);
318355
}
319-
final matchingTsx = tsxList.where(
320-
(tsx) => tsx.filename == tilesetSource,
356+
357+
final matchingTsx = parser.tsxProviders!.where(
358+
(tsx) => tsx.canProvide(tilesetSource),
321359
);
322360

323361
return Tileset.parse(

0 commit comments

Comments
 (0)