feat!: Upgrade flame_tiled to tiled 0.12.0 - #4073
Merged
Merged
Conversation
tiled 0.12.0 resolves external tilesets and templates through ParserProvider and replaces TsxProvider, so flame_tiled is updated to the new API. - Load external files through the async TiledMap.fromString loader, which is given the path of each referenced file. Object templates are resolved through it as well now, not only tilesets. - FlameTsxProvider implements ParserProvider instead of the removed TsxProvider, so it can still be passed to TiledMap.parseTmx and TiledMap.parseJson for a preloaded tileset. - Drop the direct xml dependency from flame_tiled, it is not used anymore. - Allow xml 7 in flame_kenney_xml, since tiled 0.12 requires it and the workspace resolves a single version. BREAKING CHANGE: flame_tiled re-exports tiled 0.12.0, which replaces TsxProvider with ParserProvider. FlameTsxProvider no longer implements TsxProvider; it implements ParserProvider instead.
4 of 5 tasks
spydon
approved these changes
Sep 30, 2026
spydon
added a commit
that referenced
this pull request
Sep 30, 2026
Stacked on #4073, which upgrades `flame_tiled` to `tiled` 0.12.0. Adds support for infinite maps from the Tiled editor. Until now, loading an infinite map crashed with a null check error. Infinite maps don't have a single `tileData` grid. Tiled stores their tiles in chunks, usually 16×16, placed at any tile coordinate, including negative ones when you paint left of or above the origin. `flame_tiled` assumed a `width × height` grid starting at `(0, 0)` everywhere: `cacheTiles()` started with `layer.tileData!`, and cached transforms were indexed as `transforms[x][y]`. This PR builds on the new `TileLayer` tile access APIs from flame-engine/tiled.dart#94 (`contentBounds`, `tileAt`, `setTileAt`, `forEachTile`), which work the same way for finite and infinite layers. **Tile layers** (`FlameTileLayer` and the four orientation layers): - The transform cache now covers the layer's `contentBounds`: `(0, 0, width, height)` for finite layers, and the area covered by all chunks for infinite ones. Transforms are stored relative to that area's top-left corner (`originX`/`originY`), so negative coordinates work. `transformAt` and `storeTransform` do the offset, so nothing indexes the cache directly anymore. - Tiles are painted in row order: rows sorted by `y`, each row sorted by `x`, through `tilesByWorldRow()`. This matters because infinite layers store tiles chunk by chunk. Painting them in that order would draw all of one chunk before the first row of the chunk next to it. Tiles that overlap their neighbours (isometric, staggered, hexagonal and oversized tiles) would then stack wrongly along chunk borders. Finite maps are visited in the same order as before, so they render exactly the same. **`RenderableTiledMap`:** - `getTileData`/`setTileData` (and the `ByLayerIndex` variants) use `TileLayer.tileAt`/ `setTileAt`. They take the tile coordinates shown in the Tiled editor, so negative coordinates work on infinite maps. For cells outside the map (or outside every chunk), `getTileData` returns `null` and `setTileData` does nothing. Before, both threw a `RangeError` for cells outside a finite map. - `tileStack` uses `transformAt`, so it also works at negative coordinates. **Current limitations** (also documented in `tiled.md`): - All chunks in the file are cached at load time. Streaming chunks based on the camera isn't implemented yet. - `TiledComponent`'s size still comes from the map's `width` and `height`, so tiles at negative coordinates render outside the component's bounds. - `setTileData` can't create new chunks. **Tests:** - Loading an empty infinite map, and reading, writing and `tileStack` at negative coordinates. - Three goldens, rendered with a new `renderMapRegionToPng` helper that can capture negative coordinates: - `infinite_map.png`: a whole infinite map, with two layers across six chunks. - `infinite_oversized_tiles_orthogonal.png`: a dungeon room across the chunk border at `x = 0`, with a 32×32 door standing in front of the top wall, so its frame overlaps the walls of both chunks. I checked that this golden fails if tiles are painted chunk by chunk: the wall of the right chunk then covers half the door. - `infinite_oversized_tiles_isometric.png`: an isometric scene across the four chunks around the origin. --------- Co-authored-by: Lukas Klingsbo <me@lukas.fyi>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Upgrades
flame_tiledfromtiled0.11.0 to 0.12.0.0.12.0 has the new
TileLayertile access APIs (tileAt,setTileAt,forEachTile,contentBounds), which infinite map support needs. That support is in #4074, which is stacked onthis PR. This PR only does the upgrade, so the breaking part can be reviewed on its own.
The breaking change in 0.12.0 comes from flame-engine/tiled.dart#72: external tilesets and
templates are now resolved through
ParserProviderinstead ofTsxProvider, andTileMapParseris gone.flame_tiledre-exportspackage:tiled/tiled.dart, so this reachesFlame users directly.
Changes:
RenderableTiledMap.fromStringpasses a loader to the new asyncTiledMap.fromString. tiled calls it with the path of every external file the map references,relative to the map, and the loader reads it from the asset bundle. Before,
flame_tiledhad tocreate a
TsxProviderper tileset. External object templates (.tx) now load through the samepath, not only tilesets.
FlameTsxProvider: now implementsParserProviderinstead of the removedTsxProvider, soit can still be passed to
TiledMap.parseTmx/parseJsonfor a preloaded tileset.parse,filename,data,getSourceandgetCachedSourceare still there.flame_tiledno longer depends onxmldirectly. It was only used to build anXmlParser,and
Parser.fromStringfromtileddoes that now.flame_kenney_xmlnow allowsxml7 (>=6.5.0 <8.0.0). tiled 0.12 requiresxml: ^7.0.0,and the workspace resolves a single version, so without this the workspace doesn't resolve.
flame_kenney_xmldoesn't depend ontiled, and its tests pass on xml 7.0.1.TiledComponent.loadandRenderableTiledMap.fromFile/fromStringare used exactly as before.The existing tests for external tilesets and
FlameTsxProviderpass unchanged.Checklist
docsand added dartdoc comments with///.examplesordocs.Breaking Change?
Migration instructions
Nothing changes if you only load maps through
TiledComponent.loadorRenderableTiledMap. Ifyou use the
tiledparsing APIs thatflame_tiledre-exports:TileMapParser.parseTmx(xml, tsxList: [...])becomesTiledMap.parseTmx(xml, providers: [...]), andTileMapParser.parseJson(json)becomesTiledMap.parseJson(json).TsxProviderimplementations becomeParserProviderimplementations: implementcanProvide(path)andgetSource(path)instead offilename,getSource(filename)andgetCachedSource(). The path is relative to the map file.TiledMap.fromStringnow returns the contents of the requested fileinstead of a
TsxProvider:TiledMap.fromString(contents, (path) => bundle.loadString('$directory$path')).FlameTsxProvideris no longer aTsxProvider. Pass it throughproviders:ofTiledMap.parseTmx/parseJson.Related Issues
Needed for #2855 and #3932 (infinite map support), which #4074 resolves.