diff --git a/README.md b/README.md index a2f8002..f12fb70 100644 --- a/README.md +++ b/README.md @@ -26,12 +26,23 @@ Load a TMX file into a string by any means, and then pass the string to TileMapP ```dart final String tmxBody = /* ... */; - final TiledMap mapTmx = TileMapParser.parseTmx(tmxBody); + final TiledMap mapTmx = TiledMap.parseTmx(tmxBody); ``` -If your tmx file includes a external tsx reference, you have to add a CustomParser +If your tmx file includes external reference, e.g. for .tsx files, you have to add providers. +These providers are then used to find these files and load their contents as a string, +as well as maybe caching them. + +To construct a provider for tsx files for example you can just extend the Provider +or ParserProvider class, which is just a type alias. ```dart -class CustomTsxProvider extends TsxProvider { +class MultipleTsxProvider extends ParserProvider { + @override + bool canProvide(String filename) => ["external1.tsx", "external2.tsx"].contains(filename); + + @override + Parser? getCachedSource(String filename) => null; + @override Parser getSource(String fileName) { final xml = File(fileName).readAsStringSync(); @@ -40,18 +51,65 @@ class CustomTsxProvider extends TsxProvider { } } ``` -And use it in the parseTmx method + +If, for example, all your tsx files are in one directory, +adding only one RelativeTsxProvider can allow the Parser to find all of them. + ```dart - final String tmxBody = /* ... */; - final TiledMap mapTmx = TileMapParser.parseTmx(tmxBody, tsx: CustomTsxProvider()); +class RelativeTsxProvider extends TsxProviderBase { + final String root; + + RelativeTsxProvider(this.root); + + @override + bool canProvide(String filename) { + if (cache.containsKey(filename)) return true; + + final exists = File(paths.join(root, filename)).existsSync(); + if (exists) cache[filename] = null; + + return exists; + } + Map cache = {}; + + @override + Parser? getCachedSource(String filename) => cache[filename]; + + @override + Parser getSource(String filename) { + final xml = XmlDocument.parse(File(paths.join(root, filename)).readAsStringSync()); + final element = xml.getElement("tileset"); + if (element == null) { + throw ParsingException( + "tileset", + null, + "This tsx file does not seem to contain a top-level tileset tag", + ); + } + + cache[filename] = XmlParser(element); + return cache[filename]!; + } +} +``` + +These providers are passed to the parseTmx or parseJson method. +Keep in mind that the first Provider that can provide a source is used! + +```dart + final String tmxBody = /* ... */; + final TiledMap mapTmx = TiledMap.parseTmx( + tmxBody, + tsxProviders: [SingleTsxProvider(), MultipleTsxProvider()], + ); ``` ### Load Json Files Alternatively load a json file. ```dart final String jsonBody = /* ... */; - final TiledMap mapTmx = TileMapParser.parseJson(jsonBody); + final TiledMap mapTmx = TiledMap.parseJson(jsonBody); ``` ### Implementation diff --git a/packages/tiled/lib/src/layer.dart b/packages/tiled/lib/src/layer.dart index dd25967..d544d22 100644 --- a/packages/tiled/lib/src/layer.dart +++ b/packages/tiled/lib/src/layer.dart @@ -117,7 +117,7 @@ abstract class Layer { this.properties = CustomProperties.empty, }); - static Layer parse(Parser parser) { + static Layer parse(Parser parser, {List? templateProviders}) { final type = parser.formatSpecificParsing( (json) => json.getLayerType('type'), (xml) => LayerTypeExtension.parseFromTmx(xml.element.name.toString()), @@ -277,7 +277,10 @@ abstract class Layer { static List parseLayers(Parser parser) { return parser.formatSpecificParsing( - (json) => json.getChildrenAs('layers', Layer.parse), + (json) => json.getChildrenAs( + 'layers', + Layer.parse, + ), (xml) { // It's very important not change the order of the layers // during parsing! diff --git a/packages/tiled/lib/src/objects/tiled_object.dart b/packages/tiled/lib/src/objects/tiled_object.dart index 0bee7a1..16f8b0e 100644 --- a/packages/tiled/lib/src/objects/tiled_object.dart +++ b/packages/tiled/lib/src/objects/tiled_object.dart @@ -59,7 +59,9 @@ class TiledObject { bool point; bool rectangle; + String? templatePath; Template? template; + Text? text; bool visible; @@ -84,6 +86,7 @@ class TiledObject { this.ellipse = false, this.point = false, this.rectangle = false, + this.templatePath, this.template, this.text, this.visible = true, @@ -93,9 +96,13 @@ class TiledObject { }); bool get isPolyline => polyline.isNotEmpty; + bool get isPolygon => polygon.isNotEmpty; + bool get isPoint => point; + bool get isEllipse => ellipse; + bool get isRectangle => rectangle; factory TiledObject.parse(Parser parser) { @@ -126,7 +133,18 @@ class TiledObject { (xml) => xml.getChildren('point').isNotEmpty, ); final text = parser.getSingleChildOrNullAs('text', Text.parse); - final template = parser.getSingleChildOrNullAs('template', Template.parse); + final templatePath = parser.getStringOrNull('template'); + final templateProvider = templatePath == null + ? null + : parser.templateProviders + ?.firstWhere((e) => e.canProvide(templatePath)); + final template = templateProvider == null + ? null + : Template.parse( + templateProvider.getCachedSource(templatePath!) ?? + templateProvider.getSource(templatePath), + ); + final properties = parser.getProperties(); final polygon = parsePointList(parser, 'polygon'); @@ -147,6 +165,7 @@ class TiledObject { ellipse: ellipse, point: point, rectangle: rectangle, + templatePath: templatePath, template: template, text: text, visible: visible, diff --git a/packages/tiled/lib/src/parser.dart b/packages/tiled/lib/src/parser.dart index 7716eca..2f6d64b 100644 --- a/packages/tiled/lib/src/parser.dart +++ b/packages/tiled/lib/src/parser.dart @@ -1,3 +1,5 @@ +import 'dart:convert'; + import 'package:tiled/tiled.dart'; import 'package:xml/xml.dart'; @@ -5,12 +7,20 @@ class ParsingException implements Exception { final String name; final String? valueFound; final String reason; + ParsingException(this.name, this.valueFound, this.reason); } class XmlParser extends Parser { final XmlElement element; - XmlParser(this.element); + + XmlParser(this.element, {super.tsxProviders, super.templateProviders}); + + XmlParser.fromString( + String string, { + super.tsxProviders, + super.templateProviders, + }) : element = XmlDocument.parse(string).rootElement; @override String? getInnerTextOrNull() => @@ -26,7 +36,13 @@ class XmlParser extends Parser { return element.children .whereType() .where((e) => e.name.local == name) - .map(XmlParser.new) + .map( + (e) => XmlParser( + e, + templateProviders: templateProviders, + tsxProviders: tsxProviders, + ), + ) .toList(); } @@ -34,7 +50,13 @@ class XmlParser extends Parser { return element.children .whereType() .where((e) => names.contains(e.name.local)) - .map(XmlParser.new) + .map( + (e) => XmlParser( + e, + tsxProviders: tsxProviders, + templateProviders: templateProviders, + ), + ) .toList(); } @@ -49,7 +71,14 @@ class XmlParser extends Parser { class JsonParser extends Parser { final Map json; - JsonParser(this.json); + + JsonParser(this.json, {super.tsxProviders, super.templateProviders}); + + JsonParser.fromString( + String string, { + super.tsxProviders, + super.templateProviders, + }) : json = jsonDecode(string) as Map; @override String? getInnerTextOrNull() => null; @@ -65,7 +94,13 @@ class JsonParser extends Parser { return []; } return (json[name] as List) - .map((dynamic e) => JsonParser(e as Map)) + .map( + (dynamic e) => JsonParser( + e as Map, + templateProviders: templateProviders, + tsxProviders: tsxProviders, + ), + ) .toList(); } @@ -83,6 +118,11 @@ class JsonParser extends Parser { } abstract class Parser { + final List? templateProviders; + final List? tsxProviders; + + Parser({this.tsxProviders, this.templateProviders}); + String? getInnerTextOrNull(); String? getStringOrNull(String name, {String? defaults}); diff --git a/packages/tiled/lib/src/provider.dart b/packages/tiled/lib/src/provider.dart new file mode 100644 index 0000000..fd122ba --- /dev/null +++ b/packages/tiled/lib/src/provider.dart @@ -0,0 +1,11 @@ +import 'package:tiled/tiled.dart'; + +abstract class Provider { + bool canProvide(String path); + + T getSource(String path); + T? getCachedSource(String path); +} + +typedef ParserProvider = Provider; +typedef ImagePathProvider = Provider; diff --git a/packages/tiled/lib/src/tile_map_parser.dart b/packages/tiled/lib/src/tile_map_parser.dart deleted file mode 100644 index 534747c..0000000 --- a/packages/tiled/lib/src/tile_map_parser.dart +++ /dev/null @@ -1,24 +0,0 @@ -import 'dart:convert'; - -import 'package:tiled/tiled.dart'; -import 'package:xml/xml.dart'; - -class TileMapParser { - static TiledMap parseJson(String json) { - final parser = JsonParser(jsonDecode(json) as Map); - return TiledMap.parse(parser); - } - - /// Parses the provided map xml. - /// - /// Accepts an optional list of external TsxProviders for external tilesets - /// referenced in the map file. - static TiledMap parseTmx(String xml, {List? tsxList}) { - final xmlElement = XmlDocument.parse(xml).rootElement; - if (xmlElement.name.local != 'map') { - throw 'XML is not in TMX format'; - } - final parser = XmlParser(xmlElement); - return TiledMap.parse(parser, tsxList: tsxList); - } -} diff --git a/packages/tiled/lib/src/tiled_map.dart b/packages/tiled/lib/src/tiled_map.dart index 1a11973..177475d 100644 --- a/packages/tiled/lib/src/tiled_map.dart +++ b/packages/tiled/lib/src/tiled_map.dart @@ -1,4 +1,5 @@ import 'dart:collection'; +import 'dart:convert'; import 'package:collection/collection.dart'; import 'package:tiled/tiled.dart'; @@ -128,33 +129,6 @@ class TiledMap { this.properties = CustomProperties.empty, }); - /// Takes a string [contents] and converts it to a [TiledMap] with the help of - /// the [TsxProvider]s returned from the [tsxProviderFunction]. - /// The [tsxProviderFunction] is most commonly your static [TsxProvider.parse] - /// implementation. - static Future fromString( - String contents, - Future Function(String key) tsxProviderFunction, - ) async { - final tsxSourcePaths = XmlDocument.parse(contents) - .rootElement - .children - .whereType() - .where((element) => element.name.local == 'tileset') - .map((e) => e.getAttribute('source')); - - final tsxProviders = await Future.wait( - tsxSourcePaths - .where((key) => key != null) - .map((key) async => tsxProviderFunction(key!)), - ); - - return TileMapParser.parseTmx( - contents, - tsxList: tsxProviders.isEmpty ? null : tsxProviders, - ); - } - // Convenience Methods Tile? tileByGid(int tileGid) { if (tileGid == 0) { @@ -315,7 +289,45 @@ class TiledMap { ); } - factory TiledMap.parse(Parser parser, {List? tsxList}) { + /// Parses the provided json. + /// + /// Accepts an optional list of external TsxProviders for external tilesets + /// referenced in the map file. + factory TiledMap.parseJson( + String json, { + List? tsxProviders, + List? templateProviders, + }) { + final parser = JsonParser( + jsonDecode(json) as Map, + templateProviders: templateProviders, + tsxProviders: tsxProviders, + ); + return TiledMap.parse(parser); + } + + /// Parses the provided map xml. + /// + /// Accepts an optional list of external TsxProviders for external tilesets + /// referenced in the map file. + factory TiledMap.parseTmx( + String xml, { + List? tsxProviders, + List? templateProviders, + }) { + final xmlElement = XmlDocument.parse(xml).rootElement; + if (xmlElement.name.local != 'map') { + throw 'XML is not in TMX format'; + } + final parser = XmlParser( + xmlElement, + tsxProviders: tsxProviders, + templateProviders: templateProviders, + ); + return TiledMap.parse(parser); + } + + factory TiledMap.parse(Parser parser) { final backgroundColorHex = parser.getStringOrNull('backgroundcolor'); final backgroundColor = parser.getColorOrNull('backgroundcolor'); final compressionLevel = parser.getInt('compressionlevel', defaults: -1); @@ -342,11 +354,12 @@ class TiledMap { 'tileset', (tilesetData) { final tilesetSource = tilesetData.getStringOrNull('source'); - if (tilesetSource == null || tsxList == null) { + if (tilesetSource == null || parser.tsxProviders == null) { return Tileset.parse(tilesetData); } - final matchingTsx = tsxList.where( - (tsx) => tsx.filename == tilesetSource, + + final matchingTsx = parser.tsxProviders!.where( + (tsx) => tsx.canProvide(tilesetSource), ); return Tileset.parse( diff --git a/packages/tiled/lib/src/tileset/tile.dart b/packages/tiled/lib/src/tileset/tile.dart index 2c4b11a..a91f961 100644 --- a/packages/tiled/lib/src/tileset/tile.dart +++ b/packages/tiled/lib/src/tileset/tile.dart @@ -52,7 +52,7 @@ class Tile { /// Will be same as [type]. String? get class_ => type; - Tile.parse(Parser parser) + Tile.parse(Parser parser, {List? templateProviders}) : this( localId: parser.getInt('id'), @@ -74,8 +74,10 @@ class Tile { parser.getDoubleOrNull('width') ?? 0, parser.getDoubleOrNull('height') ?? 0, ), - objectGroup: - parser.getSingleChildOrNullAs('objectgroup', Layer.parse), + objectGroup: parser.getSingleChildOrNullAs( + 'objectgroup', + (e) => Layer.parse(e, templateProviders: templateProviders), + ), animation: parser.formatSpecificParsing( (json) => json.getChildrenAs('animation', Frame.parse), (xml) => diff --git a/packages/tiled/lib/src/tileset/tileset.dart b/packages/tiled/lib/src/tileset/tileset.dart index 0f1ac92..82c0033 100644 --- a/packages/tiled/lib/src/tileset/tileset.dart +++ b/packages/tiled/lib/src/tileset/tileset.dart @@ -105,7 +105,7 @@ class Tileset { tileCount = this.tiles.length; } - factory Tileset.parse(Parser parser, {TsxProvider? tsx}) { + factory Tileset.parse(Parser parser, {ParserProvider? tsx}) { final backgroundColor = parser.getStringOrNull('backgroundcolor'); final columns = parser.getIntOrNull('columns'); final firstGid = parser.getIntOrNull('firstgid'); @@ -171,10 +171,10 @@ class Tileset { return result; } - void _checkIfExternalTsx(String? source, TsxProvider? tsx) { + void _checkIfExternalTsx(String? source, ParserProvider? tsx) { if (tsx != null && source != null) { final tileset = Tileset.parse( - tsx.getCachedSource() ?? tsx.getSource(source), + tsx.getCachedSource(source) ?? tsx.getSource(source), ); // Copy attributes if not null backgroundColor = tileset.backgroundColor ?? backgroundColor; diff --git a/packages/tiled/lib/src/tsx_provider.dart b/packages/tiled/lib/src/tsx_provider.dart deleted file mode 100644 index bc5a84b..0000000 --- a/packages/tiled/lib/src/tsx_provider.dart +++ /dev/null @@ -1,20 +0,0 @@ -import 'package:tiled/tiled.dart'; - -/// abstract class to be implemented for an external tileset data provider. -abstract class TsxProvider { - /// Unique filename for the tileset to be loaded. This should match the - /// 'source' property in the map.tmx file. - String get filename; - - /// Retrieves the external tileset data given the tileset filename. - Parser getSource(String filename); - - /// Used when provider implementations cache the data. Returns the cached - /// data for the exernal tileset. - Parser? getCachedSource(); - - /// Parses a file returning a [TsxProvider]. - static Future parse(String key) { - throw UnimplementedError(); - } -} diff --git a/packages/tiled/lib/tiled.dart b/packages/tiled/lib/tiled.dart index e0a7f2f..4bd636b 100644 --- a/packages/tiled/lib/tiled.dart +++ b/packages/tiled/lib/tiled.dart @@ -14,8 +14,8 @@ export 'src/layer.dart'; export 'src/objects/text.dart'; export 'src/objects/tiled_object.dart'; export 'src/parser.dart'; +export 'src/provider.dart'; export 'src/template.dart'; -export 'src/tile_map_parser.dart'; export 'src/tiled_map.dart'; export 'src/tileset/grid.dart'; export 'src/tileset/terrain.dart'; @@ -25,4 +25,3 @@ export 'src/tileset/tileset.dart'; export 'src/tileset/wang/wang_color.dart'; export 'src/tileset/wang/wang_set.dart'; export 'src/tileset/wang/wang_tile.dart'; -export 'src/tsx_provider.dart'; diff --git a/packages/tiled/pubspec.yaml b/packages/tiled/pubspec.yaml index abdb17b..14b3833 100644 --- a/packages/tiled/pubspec.yaml +++ b/packages/tiled/pubspec.yaml @@ -1,5 +1,5 @@ name: tiled -version: 0.10.2 +version: 0.10.1 description: A Dart Tiled library. Parse your TMX files into useful representations. Compatible with Flame. homepage: https://github.com/flame-engine/tiled.dart @@ -15,4 +15,5 @@ dependencies: dev_dependencies: dartdoc: ^8.3.1 flame_lint: ^1.1.2 + path: ^1.8.3 test: ^1.24.8 diff --git a/packages/tiled/test/complexmap_infinite_test.dart b/packages/tiled/test/complexmap_infinite_test.dart index ca5bf49..feaf67b 100644 --- a/packages/tiled/test/complexmap_infinite_test.dart +++ b/packages/tiled/test/complexmap_infinite_test.dart @@ -10,7 +10,7 @@ void main() { return File('./test/fixtures/complexmap_infinite.tmx') .readAsString() .then((xml) { - complexMapInfinite = TileMapParser.parseTmx(xml); + complexMapInfinite = TiledMap.parseTmx(xml); }); }); diff --git a/packages/tiled/test/image_layer_test.dart b/packages/tiled/test/image_layer_test.dart index 8996c45..a5f703d 100644 --- a/packages/tiled/test/image_layer_test.dart +++ b/packages/tiled/test/image_layer_test.dart @@ -7,7 +7,7 @@ void main() { late TiledMap map; setUp(() { return File('./test/fixtures/imagelayer.tmx').readAsString().then((xml) { - map = TileMapParser.parseTmx(xml); + map = TiledMap.parseTmx(xml); }); }); diff --git a/packages/tiled/test/isometric_staggered_test.dart b/packages/tiled/test/isometric_staggered_test.dart index 4e13832..59dc4ed 100644 --- a/packages/tiled/test/isometric_staggered_test.dart +++ b/packages/tiled/test/isometric_staggered_test.dart @@ -11,14 +11,14 @@ void main() { return File('./test/fixtures/isometric_staggered_grass_and_water.json') .readAsString() .then((xml) { - mapIsoStaggeredJson = TileMapParser.parseJson(xml); + mapIsoStaggeredJson = TiledMap.parseJson(xml); }); }); setUp(() { return File('./test/fixtures/isometric_staggered_grass_and_water.tmx') .readAsString() .then((xml) { - mapIsoStaggeredTmx = TileMapParser.parseTmx(xml); + mapIsoStaggeredTmx = TiledMap.parseTmx(xml); }); }); diff --git a/packages/tiled/test/isometric_test.dart b/packages/tiled/test/isometric_test.dart index 9c28c6a..ba885b4 100644 --- a/packages/tiled/test/isometric_test.dart +++ b/packages/tiled/test/isometric_test.dart @@ -10,7 +10,7 @@ void main() { return File('./test/fixtures/isometric_grass_and_water.tmx') .readAsString() .then((xml) { - mapIso = TileMapParser.parseTmx(xml); + mapIso = TiledMap.parseTmx(xml); }); }); diff --git a/packages/tiled/test/layer_test.dart b/packages/tiled/test/layer_test.dart index d967704..b3e3061 100644 --- a/packages/tiled/test/layer_test.dart +++ b/packages/tiled/test/layer_test.dart @@ -9,11 +9,11 @@ void main() { setUp(() { final f1 = File('./test/fixtures/test.tmx').readAsString().then((xml) { - mapTmx = TileMapParser.parseTmx(xml); + mapTmx = TiledMap.parseTmx(xml); }); final f2 = File('./test/fixtures/test_base64_gzip.tmx').readAsString().then((xml) { - mapTmxBase64Gzip = TileMapParser.parseTmx(xml); + mapTmxBase64Gzip = TiledMap.parseTmx(xml); }); return Future.wait([f1, f2]); diff --git a/packages/tiled/test/object_group_test.dart b/packages/tiled/test/object_group_test.dart index 0287622..432768b 100644 --- a/packages/tiled/test/object_group_test.dart +++ b/packages/tiled/test/object_group_test.dart @@ -7,7 +7,7 @@ void main() { late TiledMap map; setUp(() { return File('./test/fixtures/objectgroup.tmx').readAsString().then((xml) { - map = TileMapParser.parseTmx(xml); + map = TiledMap.parseTmx(xml); }); }); diff --git a/packages/tiled/test/overflow_bug_test.dart b/packages/tiled/test/overflow_bug_test.dart index 27e62b7..71b73be 100644 --- a/packages/tiled/test/overflow_bug_test.dart +++ b/packages/tiled/test/overflow_bug_test.dart @@ -11,11 +11,7 @@ void main() { setUp(() { return File('./test/fixtures/testoverflow_csv.tmx').readAsString().then( (mapString) { - return TiledMap.fromString(mapString, TsxProvider.parse).then( - (parsedMap) { - map = parsedMap; - }, - ); + map = TiledMap.parseTmx(mapString); }, ); }); diff --git a/packages/tiled/test/parser_compare_test.dart b/packages/tiled/test/parser_compare_test.dart index 4e8b421..961307c 100644 --- a/packages/tiled/test/parser_compare_test.dart +++ b/packages/tiled/test/parser_compare_test.dart @@ -7,28 +7,28 @@ void main() { late TiledMap oldMap; setUp(() { return File('./test/fixtures/test_old.tmx').readAsString().then((xml) { - oldMap = TileMapParser.parseTmx(xml); + oldMap = TiledMap.parseTmx(xml); }); }); late TiledMap map; setUp(() { return File('./test/fixtures/testcsv.json').readAsString().then((xml) { - map = TileMapParser.parseJson(xml); + map = TiledMap.parseJson(xml); }); }); late TiledMap map2; setUp(() { return File('./test/fixtures/testzlib.json').readAsString().then((xml) { - map2 = TileMapParser.parseJson(xml); + map2 = TiledMap.parseJson(xml); }); }); late TiledMap map3; setUp(() { return File('./test/fixtures/testgzip.json').readAsString().then((xml) { - map3 = TileMapParser.parseJson(xml); + map3 = TiledMap.parseJson(xml); }); }); @@ -37,49 +37,49 @@ void main() { return File('./test/fixtures/testbase64only.json') .readAsString() .then((xml) { - map4 = TileMapParser.parseJson(xml); + map4 = TiledMap.parseJson(xml); }); }); late TiledMap tileMapCsv; setUp(() { return File('./test/fixtures/test_csv.tmx').readAsString().then((xml) { - tileMapCsv = TileMapParser.parseTmx(xml); + tileMapCsv = TiledMap.parseTmx(xml); }); }); late TiledMap tileMap; setUp(() { return File('./test/fixtures/test.tmx').readAsString().then((xml) { - tileMap = TileMapParser.parseTmx(xml); + tileMap = TiledMap.parseTmx(xml); }); }); late TiledMap tileMapEllipse; setUp(() { return File('./test/fixtures/map.tmx').readAsString().then((xml) { - tileMapEllipse = TileMapParser.parseTmx(xml); + tileMapEllipse = TiledMap.parseTmx(xml); }); }); late TiledMap map5; setUp(() { return File('./test/fixtures/complexmap.json').readAsString().then((xml) { - map5 = TileMapParser.parseJson(xml); + map5 = TiledMap.parseJson(xml); }); }); late TiledMap map6; setUp(() { return File('./test/fixtures/complexmap.tmx').readAsString().then((xml) { - map6 = TileMapParser.parseTmx(xml); + map6 = TiledMap.parseTmx(xml); }); }); late TiledMap tileMapComplex; setUp(() { return File('./test/fixtures/complexmap.tmx').readAsString().then((xml) { - tileMapComplex = TileMapParser.parseTmx(xml); + tileMapComplex = TiledMap.parseTmx(xml); }); }); diff --git a/packages/tiled/test/parser_test.dart b/packages/tiled/test/parser_test.dart index 3ec9f5e..588d967 100644 --- a/packages/tiled/test/parser_test.dart +++ b/packages/tiled/test/parser_test.dart @@ -2,6 +2,7 @@ import 'dart:io'; import 'dart:math' show Rectangle; import 'package:collection/collection.dart'; +import 'package:path/path.dart' as paths; import 'package:test/test.dart'; import 'package:tiled/tiled.dart'; import 'package:xml/xml.dart'; @@ -10,14 +11,14 @@ void main() { late TiledMap map; setUp(() { return File('./test/fixtures/test.tmx').readAsString().then((xml) { - map = TileMapParser.parseTmx(xml); + map = TiledMap.parseTmx(xml); }); }); test('Parser.parse raises an error when the XML is empty', () { const wrongXml = ''; expect( - () => TileMapParser.parseTmx(wrongXml), + () => TiledMap.parseTmx(wrongXml), throwsA(const TypeMatcher()), ); }); @@ -25,7 +26,7 @@ void main() { test('Parser.parse raises an error when the XML is not in TMX format', () { const wrongXml = ''; expect( - () => TileMapParser.parseTmx(wrongXml), + () => TiledMap.parseTmx(wrongXml), throwsA('XML is not in TMX format'), ); }); @@ -88,10 +89,10 @@ void main() { equals('test_value'), ); expect( - properties.getValue('multiline string'), - Platform.isWindows - ? equals('Hello,\r\nWorld') - : equals('Hello,\nWorld'), + properties + .getValue('multiline string') + ?.replaceAll('\r\n', '\n'), + equals('Hello,\nWorld'), ); expect( properties.getValue('integer property'), @@ -209,7 +210,7 @@ void main() { group('Parser.parse populates Map with objectgroups', () { setUp(() { return File('./test/fixtures/objectgroup.tmx').readAsString().then((xml) { - map = TileMapParser.parseTmx(xml); + map = TiledMap.parseTmx(xml); }); }); @@ -252,9 +253,9 @@ void main() { group('Parser.parse fills Map with tileset & different img configs', () { setUp(() { return File('./test/fixtures/map_images.tmx').readAsString().then((xml) { - map = TileMapParser.parseTmx( + map = TiledMap.parseTmx( xml, - tsxList: [CustomTsxProvider.parse('tileset.tsx')], + tsxProviders: [FixtureTsxProvider.all()], ); }); }); @@ -313,9 +314,9 @@ void main() { return File('./test/fixtures/external_tileset_map.tmx') .readAsString() .then((xml) { - final map = TileMapParser.parseTmx( + final map = TiledMap.parseTmx( xml, - tsxList: [CustomTsxProvider.parse('tileid_over_tilecount.tsx')], + tsxProviders: [FixtureTsxProvider.all()], ); expect(map.tilesets[0].tileCount, 137); final tile = map.tileByGid(1)!; @@ -328,9 +329,9 @@ void main() { group('Parser.parse with tsx provider', () { test('it loads external tsx', () { return File('./test/fixtures/map_images.tmx').readAsString().then((xml) { - map = TileMapParser.parseTmx( + map = TiledMap.parseTmx( xml, - tsxList: [CustomTsxProvider.parse('tileset.tsx')], + tsxProviders: [FixtureTsxProvider.all()], ); expect( map.tilesetByName('external').image!.source, @@ -343,9 +344,9 @@ void main() { group('Parser.parse with multiple layers', () { test('it has 2 layers', () { return File('./test/fixtures/map_images.tmx').readAsString().then((xml) { - map = TileMapParser.parseTmx( + map = TiledMap.parseTmx( xml, - tsxList: [CustomTsxProvider.parse('tileset.tsx')], + tsxProviders: [FixtureTsxProvider.all()], ); expect(map.layers.length, equals(2)); }); @@ -358,19 +359,9 @@ void main() { return File('./test/fixtures/map_with_multiple_tilesets.tmx') .readAsString() .then((xml) { - final tilemapXml = XmlDocument.parse(xml).rootElement; - final tsxSourcePaths = tilemapXml.children - .whereType() - .where((element) => element.name.local == 'tileset') - .map((tsx) => tsx.getAttribute('source')); - - final tsxProviders = tsxSourcePaths - .where((key) => key != null) - .map((key) => CustomTsxProvider.parse(key!)); - - map = TileMapParser.parseTmx( + map = TiledMap.parseTmx( xml, - tsxList: tsxProviders.isEmpty ? null : tsxProviders.toList(), + tsxProviders: [FixtureTsxProvider.all()], ); return; }); @@ -428,7 +419,7 @@ void main() { test('support empty terrain values', () { final xml = File('./test/fixtures/map_with_empty_terrains.tmx') .readAsStringSync(); - final tiledMap = TileMapParser.parseTmx(xml); + final tiledMap = TiledMap.parseTmx(xml); final tileset = tiledMap.tilesets.first; final tile = tileset.tiles.first; @@ -437,28 +428,47 @@ void main() { }); } -class CustomTsxProvider extends TsxProvider { - final String _filename; - final String data; +class FixtureTsxProvider extends ParserProvider { + final List files; + final String root; + + FixtureTsxProvider(this.root, this.files); + + factory FixtureTsxProvider.all([String directory = './test/fixtures']) { + final dir = Directory(directory); + if (!dir.existsSync()) { + throw '[FixtureTsxProvider] Supplied directory does not exist!'; + } - CustomTsxProvider._(this.data, this._filename); + final names = dir + .listSync() + .whereType() + .where((e) => e.path.endsWith('.tsx')) + .map((e) => paths.basename(e.path)) + .toList(); - factory CustomTsxProvider.parse(String filename) { - final xml = File('./test/fixtures/$filename').readAsStringSync(); - return CustomTsxProvider._(xml, filename); + return FixtureTsxProvider(paths.absolute(directory), names); } + final Map cache = {}; + @override - String get filename => _filename; + bool canProvide(String filename) { + return files.contains(filename); + } @override - Parser getSource(String key) { - final node = XmlDocument.parse(data).rootElement; - return XmlParser(node); + Parser? getCachedSource(String filename) { + return cache.containsKey(filename) + ? XmlParser.fromString(cache[filename]!) + : null; } @override - Parser? getCachedSource() { - return getSource(''); + Parser getSource(String filename) { + final content = File(paths.join(root, filename)).readAsStringSync(); + cache[filename] = content; + + return XmlParser.fromString(content); } } diff --git a/packages/tiled/test/rectangle_map_test.dart b/packages/tiled/test/rectangle_map_test.dart index 797bb5b..45b154b 100644 --- a/packages/tiled/test/rectangle_map_test.dart +++ b/packages/tiled/test/rectangle_map_test.dart @@ -8,7 +8,7 @@ void main() { setUp(() { return File('./test/fixtures/rectangle.tmx').readAsString().then((xml) { - map = TileMapParser.parseTmx(xml); + map = TiledMap.parseTmx(xml); }); }); diff --git a/packages/tiled/test/tmx_object_test.dart b/packages/tiled/test/tmx_object_test.dart index 8579ed6..594f05d 100644 --- a/packages/tiled/test/tmx_object_test.dart +++ b/packages/tiled/test/tmx_object_test.dart @@ -7,7 +7,7 @@ void main() { late TiledMap map; setUp(() { return File('./test/fixtures/objectgroup.tmx').readAsString().then((xml) { - map = TileMapParser.parseTmx(xml); + map = TiledMap.parseTmx(xml); }); });