├── .editorconfig ├── .github ├── FUNDING.yml ├── PULL_REQUEST_TEMPLATE │ ├── dev_template.md │ └── master_template.md └── workflows │ ├── deploy-docs.yml │ ├── master-pr.yml │ ├── pull-request.yml │ └── release-nuget.yml ├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── docs ├── docfx.json ├── docs │ ├── essentials │ │ ├── custom-properties.md │ │ ├── loading-maps.md │ │ └── representation-model.md │ ├── quickstart.md │ └── toc.yml ├── images │ ├── entity-type-enum.png │ ├── monster-spawner-class.png │ └── resolve-types.png ├── template │ └── public │ │ ├── main.css │ │ └── main.js └── toc.yml └── src ├── DotTiled.Benchmark ├── DotTiled.Benchmark.csproj └── Program.cs ├── DotTiled.Examples ├── DotTiled.Example.Console │ ├── DotTiled.Example.Console.csproj │ ├── Program.cs │ ├── tilemap.tmx │ ├── tileset.png │ └── tileset.tsx └── DotTiled.Example.Godot │ ├── .gitattributes │ ├── .gitignore │ ├── DotTiled.Example.Godot.csproj │ ├── DotTiled.Example.Godot.sln │ ├── MapParser.cs │ ├── blocks │ └── 1.tscn │ ├── icon.svg │ ├── icon.svg.import │ ├── main.tscn │ ├── project.godot │ ├── tilemap.tmx │ ├── tileset.png │ ├── tileset.png.import │ └── tileset.tsx ├── DotTiled.Tests ├── Assert │ ├── AssertCustomTypes.cs │ ├── AssertData.cs │ ├── AssertImage.cs │ ├── AssertLayer.cs │ ├── AssertMap.cs │ ├── AssertObject.cs │ ├── AssertProperties.cs │ └── AssertTileset.cs ├── DotTiled.Tests.csproj ├── IntegrationTests │ └── CustomTypes │ │ └── FromTypeUsedInLoaderTests.cs ├── TestData │ └── Maps │ │ ├── default-map │ │ ├── default-map.cs │ │ ├── default-map.tmj │ │ └── default-map.tmx │ │ ├── map-external-tileset-multi │ │ ├── map-external-tileset-multi.cs │ │ ├── map-external-tileset-multi.tmj │ │ ├── map-external-tileset-multi.tmx │ │ ├── multi-tileset.tsj │ │ ├── multi-tileset.tsx │ │ └── tileset.png │ │ ├── map-external-tileset-wangset │ │ ├── map-external-tileset-wangset.cs │ │ ├── map-external-tileset-wangset.tmj │ │ ├── map-external-tileset-wangset.tmx │ │ ├── tileset.png │ │ ├── wangset-tileset.tsj │ │ └── wangset-tileset.tsx │ │ ├── map-override-object-bug │ │ ├── map-override-object-bug.cs │ │ ├── map-override-object-bug.tmj │ │ ├── map-override-object-bug.tmx │ │ ├── poly.tj │ │ ├── poly.tx │ │ ├── random.tj │ │ ├── random.tx │ │ ├── tileset.png │ │ ├── tileset.tsj │ │ └── tileset.tsx │ │ ├── map-with-class-and-props │ │ ├── map-with-class-and-props.cs │ │ ├── map-with-class-and-props.tmj │ │ └── map-with-class-and-props.tmx │ │ ├── map-with-class │ │ ├── map-with-class.cs │ │ ├── map-with-class.tmj │ │ └── map-with-class.tmx │ │ ├── map-with-common-props │ │ ├── map-with-common-props.cs │ │ ├── map-with-common-props.tmj │ │ └── map-with-common-props.tmx │ │ ├── map-with-custom-type-props-without-defs │ │ ├── map-with-custom-type-props-without-defs.cs │ │ ├── map-with-custom-type-props-without-defs.tmj │ │ └── map-with-custom-type-props-without-defs.tmx │ │ ├── map-with-custom-type-props │ │ ├── map-with-custom-type-props.cs │ │ ├── map-with-custom-type-props.tmj │ │ ├── map-with-custom-type-props.tmx │ │ └── propertytypes.json │ │ ├── map-with-deep-props │ │ ├── map-with-deep-props.cs │ │ ├── map-with-deep-props.tmj │ │ └── map-with-deep-props.tmx │ │ ├── map-with-embedded-tileset │ │ ├── map-with-embedded-tileset.cs │ │ ├── map-with-embedded-tileset.tmj │ │ ├── map-with-embedded-tileset.tmx │ │ └── tileset.png │ │ ├── map-with-external-tileset │ │ ├── map-with-external-tileset.cs │ │ ├── map-with-external-tileset.tmj │ │ ├── map-with-external-tileset.tmx │ │ ├── tileset.png │ │ ├── tileset.tsj │ │ └── tileset.tsx │ │ ├── map-with-flippingflags │ │ ├── map-with-flippingflags.cs │ │ ├── map-with-flippingflags.tmj │ │ ├── map-with-flippingflags.tmx │ │ ├── tileset.png │ │ ├── tileset.tsj │ │ └── tileset.tsx │ │ ├── map-with-many-layers │ │ ├── map-with-many-layers.cs │ │ ├── map-with-many-layers.tmj │ │ ├── map-with-many-layers.tmx │ │ ├── poly.tj │ │ ├── poly.tx │ │ ├── tileset.png │ │ ├── tileset.tsj │ │ └── tileset.tsx │ │ └── map-with-multiline-string-prop │ │ ├── map-with-multiline-string-prop.cs │ │ ├── map-with-multiline-string-prop.tmj │ │ └── map-with-multiline-string-prop.tmx └── UnitTests │ ├── OptionalTests.cs │ ├── Properties │ ├── CustomTypes │ │ ├── CustomClassDefinitionTests.cs │ │ └── CustomEnumDefinitionTests.cs │ └── HasPropertiesBaseTests.cs │ └── Serialization │ ├── DefaultResourceCacheTests.cs │ ├── LoaderTests.cs │ ├── MapReaderTests.cs │ ├── TestData.cs │ ├── Tmj │ └── TmjMapReaderTests.cs │ └── Tmx │ └── TmxMapReaderTests.cs ├── DotTiled.sln └── DotTiled ├── Color.cs ├── DotTiled.csproj ├── Layers ├── BaseLayer.cs ├── Data.cs ├── Group.cs ├── ImageLayer.cs ├── ObjectLayer.cs ├── Objects │ ├── EllipseObject.cs │ ├── Object.cs │ ├── PointObject.cs │ ├── PolygonObject.cs │ ├── PolylineObject.cs │ ├── RectangleObject.cs │ ├── TextObject.cs │ └── TileObject.cs └── TileLayer.cs ├── Map.cs ├── Optional.cs ├── Properties ├── BoolProperty.cs ├── ClassProperty.cs ├── ColorProperty.cs ├── CustomTypes │ ├── CustomClassDefinition.cs │ ├── CustomEnumDefinition.cs │ └── CustomTypeDefinition.cs ├── EnumProperty.cs ├── FileProperty.cs ├── FloatProperty.cs ├── IHasProperties.cs ├── IProperty.cs ├── IntProperty.cs ├── ObjectProperty.cs ├── PropertyType.cs └── StringProperty.cs ├── README.md ├── Serialization ├── DefaultResourceCache.cs ├── FileSystemResourceReader.cs ├── Helpers.cs ├── IMapReader.cs ├── IResourceCache.cs ├── IResourceReader.cs ├── ITemplateReader.cs ├── ITilesetReader.cs ├── Loader.cs ├── MapReader.cs ├── TemplateReader.cs ├── TilesetReader.cs ├── Tmj │ ├── ExtensionsJsonElement.cs │ ├── TjTemplateReader.cs │ ├── TmjMapReader.cs │ ├── TmjReaderBase.Data.cs │ ├── TmjReaderBase.Group.cs │ ├── TmjReaderBase.ImageLayer.cs │ ├── TmjReaderBase.Layer.cs │ ├── TmjReaderBase.Map.cs │ ├── TmjReaderBase.ObjectLayer.cs │ ├── TmjReaderBase.Properties.cs │ ├── TmjReaderBase.Template.cs │ ├── TmjReaderBase.TileLayer.cs │ ├── TmjReaderBase.Tileset.cs │ ├── TmjReaderBase.cs │ └── TsjTilesetReader.cs └── Tmx │ ├── ExtensionsXmlReader.cs │ ├── TmxMapReader.cs │ ├── TmxReaderBase.Chunk.cs │ ├── TmxReaderBase.Data.cs │ ├── TmxReaderBase.Map.cs │ ├── TmxReaderBase.ObjectLayer.cs │ ├── TmxReaderBase.Properties.cs │ ├── TmxReaderBase.TileLayer.cs │ ├── TmxReaderBase.Tileset.cs │ ├── TmxReaderBase.cs │ ├── TsxTilesetReader.cs │ └── TxTemplateReader.cs ├── Template.cs └── Tilesets ├── Frame.cs ├── Grid.cs ├── Image.cs ├── Tile.cs ├── TileOffset.cs ├── Tileset.cs ├── Transformations.cs ├── WangColor.cs ├── WangTile.cs └── Wangset.cs /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [dcronqvist] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 12 | polar: # Replace with a single Polar username 13 | buy_me_a_coffee: # Replace with a single Buy Me a Coffee username 14 | thanks_dev: # Replace with a single thanks.dev username 15 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 16 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE/dev_template.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | 4 | ### Type of Change 5 | 6 | - [ ] Bug fix (non-breaking change which fixes an issue) 7 | - [ ] New feature (non-breaking change which adds functionality) 8 | - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) 9 | - [ ] Documentation update 10 | 11 | ## Checklist 12 | 13 | - [ ] Tests have been added/updated to cover new functionality. 14 | - [ ] Documentation has been updated for all new changes (e.g., usage examples, API documentation). 15 | 16 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE/master_template.md: -------------------------------------------------------------------------------- 1 | # Release vX.Y.Z 2 | 3 | 4 | 5 | ## Checklist for a release PR 6 | 7 | - [ ] Version compatibility matrix has been updated. 8 | - [ ] Tests have been added/updated to cover new functionality. 9 | - [ ] Documentation has been updated for all new changes (e.g., usage examples, API documentation). 10 | 11 | -------------------------------------------------------------------------------- /.github/workflows/deploy-docs.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - master 5 | 6 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages 7 | permissions: 8 | actions: read 9 | pages: write 10 | id-token: write 11 | 12 | # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. 13 | # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. 14 | concurrency: 15 | group: "pages" 16 | cancel-in-progress: false 17 | 18 | jobs: 19 | deploy-docs: 20 | environment: 21 | name: github-pages 22 | url: ${{ steps.deployment.outputs.page_url }} 23 | runs-on: ubuntu-latest 24 | steps: 25 | - name: Checkout code 26 | uses: actions/checkout@v2 27 | - name: Setup .NET 28 | uses: actions/setup-dotnet@v4 29 | with: 30 | dotnet-version: 8.0.x 31 | - name: Setup DocFX 32 | run: dotnet tool update -g docfx 33 | - name: Build docs 34 | run: make docs-build 35 | - name: Upload docs 36 | uses: actions/upload-pages-artifact@v3 37 | with: 38 | path: docs/_site 39 | - name: Deploy docs 40 | id: deployment 41 | uses: actions/deploy-pages@v4 42 | -------------------------------------------------------------------------------- /.github/workflows/master-pr.yml: -------------------------------------------------------------------------------- 1 | on: 2 | pull_request: 3 | branches: 4 | - master 5 | 6 | jobs: 7 | check-pr-version: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Checkout PR branch 11 | uses: actions/checkout@v3 12 | 13 | - name: Get version from PR branch 14 | id: pr_version 15 | run: | 16 | PR_VERSION=$(grep '' **/*.csproj | sed -E 's/.*(.*)<\/Version>.*/\1/') 17 | echo "PR_VERSION=$PR_VERSION" >> $GITHUB_ENV 18 | 19 | - name: Checkout master branch 20 | run: | 21 | git fetch origin master 22 | git checkout origin/master 23 | 24 | - name: Get version from master branch 25 | id: master_version 26 | run: | 27 | MASTER_VERSION=$(grep '' **/*.csproj | sed -E 's/.*(.*)<\/Version>.*/\1/') 28 | echo "MASTER_VERSION=$MASTER_VERSION" >> $GITHUB_ENV 29 | 30 | - name: Compare versions 31 | run: | 32 | if [ "$(printf '%s\n' "$PR_VERSION" "$MASTER_VERSION" | sort -V | head -n1)" = "$PR_VERSION" ] && [ "$PR_VERSION" != "$MASTER_VERSION" ]; then 33 | echo "Version in PR is not higher than master." 34 | exit 1 35 | else 36 | echo "Version in PR is higher than master." 37 | fi 38 | -------------------------------------------------------------------------------- /.github/workflows/pull-request.yml: -------------------------------------------------------------------------------- 1 | on: 2 | pull_request: 3 | branches: 4 | - master 5 | - dev 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | - name: Set up .NET 13 | uses: actions/setup-dotnet@v4 14 | with: 15 | dotnet-version: 8.0.x 16 | - name: Restore dependencies 17 | run: dotnet restore src/DotTiled.sln 18 | - name: Build 19 | run: dotnet build --no-restore src/DotTiled.sln 20 | - name: Test 21 | run: dotnet test --no-build --verbosity normal src/DotTiled.sln 22 | - name: Lint style 23 | run: dotnet format style --verify-no-changes --verbosity diagnostic src/DotTiled.sln 24 | - name: Lint analyzers 25 | run: dotnet format analyzers --verify-no-changes --verbosity diagnostic src/DotTiled.sln 26 | -------------------------------------------------------------------------------- /.github/workflows/release-nuget.yml: -------------------------------------------------------------------------------- 1 | on: 2 | release: 3 | types: [published] 4 | 5 | jobs: 6 | release-nuget: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - name: Checkout code 10 | uses: actions/checkout@v2 11 | - name: Setup .NET 12 | uses: actions/setup-dotnet@v4 13 | with: 14 | dotnet-version: 8.0.x 15 | - name: Restore dependencies 16 | run: dotnet restore src/DotTiled.sln 17 | - name: Build 18 | run: dotnet build --no-restore src/DotTiled.sln 19 | - name: Test 20 | run: dotnet test --no-build --verbosity normal src/DotTiled.sln 21 | - name: Lint style 22 | run: dotnet format style --verify-no-changes --verbosity diagnostic src/DotTiled.sln 23 | - name: Lint analyzers 24 | run: dotnet format analyzers --verify-no-changes --verbosity diagnostic src/DotTiled.sln 25 | - name: Pack 26 | run: make pack 27 | - name: Publish to NuGet.org 28 | run: | 29 | dotnet nuget push ./nupkg/*.nupkg -k ${{ secrets.NUGET_API_KEY }} -s https://api.nuget.org/v3/index.json --skip-duplicate 30 | dotnet nuget push ./nupkg/*.snupkg -k ${{ secrets.NUGET_API_KEY }} -s https://api.nuget.org/v3/index.json --skip-duplicate 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Daniel Cronqvist (daniel@dcronqvist.se) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | dotnet build src/DotTiled.sln 3 | dotnet test src/DotTiled.sln 4 | dotnet run --project src/DotTiled.Examples/DotTiled.Example.Console/DotTiled.Example.Console.csproj -- src/DotTiled.Examples/DotTiled.Example.Console 5 | 6 | docs-serve: docs/index.md 7 | docfx docs/docfx.json --serve 8 | 9 | docs-build: docs/index.md 10 | docfx docs/docfx.json 11 | 12 | docs/index.md: README.md 13 | cp README.md docs/index.md 14 | 15 | lint: 16 | dotnet format style --verify-no-changes src/DotTiled.sln 17 | dotnet format analyzers --verify-no-changes src/DotTiled.sln 18 | 19 | pack: 20 | dotnet pack src/DotTiled/DotTiled.csproj -c Release -o ./nupkg -p:IncludeSymbols=true -p:SymbolPackageFormat=snupkg 21 | 22 | BENCHMARK_SOURCES = src/DotTiled.Benchmark/Program.cs src/DotTiled.Benchmark/DotTiled.Benchmark.csproj 23 | BENCHMARK_OUTPUTDIR = src/DotTiled.Benchmark/BenchmarkDotNet.Artifacts 24 | .PHONY: benchmark 25 | benchmark: $(BENCHMARK_OUTPUTDIR)/results/MyBenchmarks.MapLoading-report-github.md 26 | 27 | $(BENCHMARK_OUTPUTDIR)/results/MyBenchmarks.MapLoading-report-github.md: $(BENCHMARK_SOURCES) 28 | dotnet run --project src/DotTiled.Benchmark/DotTiled.Benchmark.csproj -c Release -- $(BENCHMARK_OUTPUTDIR) -------------------------------------------------------------------------------- /docs/docfx.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": [ 3 | { 4 | "src": [ 5 | { 6 | "src": "../src", 7 | "files": [ 8 | "DotTiled/DotTiled.csproj" 9 | ] 10 | } 11 | ], 12 | "dest": "api", 13 | "enumSortOrder": "declaringOrder" 14 | } 15 | ], 16 | "build": { 17 | "content": [ 18 | { 19 | "files": [ 20 | "**/*.{md,yml}" 21 | ], 22 | "exclude": [ 23 | "_site/**" 24 | ] 25 | } 26 | ], 27 | "resource": [ 28 | { 29 | "files": [ 30 | "images/**" 31 | ] 32 | } 33 | ], 34 | "output": "_site", 35 | "template": [ 36 | "default", 37 | "modern", 38 | "template" 39 | ], 40 | "globalMetadata": { 41 | "_appName": "DotTiled", 42 | "_appTitle": "DotTiled", 43 | "_enableSearch": true, 44 | "pdf": false 45 | }, 46 | "xref": [ 47 | "https://learn.microsoft.com/en-us/dotnet/.xrefmap.json" 48 | ] 49 | } 50 | } -------------------------------------------------------------------------------- /docs/docs/essentials/representation-model.md: -------------------------------------------------------------------------------- 1 | # Representation model 2 | 3 | Tiled map files contain various types of data, such as tilesets, layers, and object groups. The representation model is a way to represent this data in a structured way. By using the `.tmx` file format as inspiration, the representation model is a collection of classes which mimic the structure of a Tiled map file. 4 | 5 | Certain properties throughout the representation model are marked as *optional* by being either wrapped in a or by having a set default value. 6 | 7 | - Properties that make use of the [required](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/required) keyword must be present in the file, otherwise an error will be raised. 8 | - Properties that have default values will use the default value if the property is not present in the file, and are not marked as required or optional since you must not provide a value for them. 9 | - Properties that are wrapped in may or may not be present in the file, and have no default value. 10 | 11 | ## Version compatibility 12 | 13 | The representation model is designed to be compatible with the latest version of Tiled. This means that it may not be able to read files from older versions of Tiled, or files that use features that are not yet supported by the representation model. However, here is a table of which versions of Tiled are supported by which versions of DotTiled. 14 | 15 | | Tiled version | Compatible DotTiled version(s) | 16 | |---------------|--------------------------------| 17 | | 1.11 | 0.1.0, 0.2.0, 0.2.1, 0.3.0 | -------------------------------------------------------------------------------- /docs/docs/quickstart.md: -------------------------------------------------------------------------------- 1 | # Quick Start 2 | 3 | Install DotTiled from NuGet: 4 | 5 | ```bash 6 | dotnet add package DotTiled 7 | ``` 8 | 9 | Use the `DotTiled` namespace (if you want). 10 | 11 | ```csharp 12 | using DotTiled; 13 | ``` 14 | 15 | Or fully qualify all `DotTiled` types e.g. `DotTiled.Loader`. 16 | 17 | ## Loading a map from the file system 18 | 19 | This will create a loader that will load files from the underlying file system using . It will also be configured to use an in-memory cache to avoid loading the same tileset or template multiple times using . 20 | 21 | ```csharp 22 | var loader = Loader.Default(); 23 | var map = loader.LoadMap("path/to/map.tmx"); 24 | ``` 25 | 26 | ## Loading a map from a different source 27 | 28 | If you want to load resources (maps, tilesets, templates) from a different source than the underlying file system, you can override the that is being used with your own implementation of . 29 | 30 | ```csharp 31 | var loader = Loader.DefaultWith( 32 | resourceReader: new MyCustomResourceReader()); 33 | var map = loader.LoadMap("path/to/map.tmx"); 34 | ``` 35 | 36 | ## Caching resources 37 | 38 | Similarly, you can override the that is being used with your own implementation of . 39 | 40 | ```csharp 41 | var loader = Loader.DefaultWith( 42 | resourceReader: new MyCustomResourceReader(), 43 | resourceCache: new MyCustomResourceCache()); 44 | var map = loader.LoadMap("path/to/map.tmx"); 45 | ``` 46 | 47 | ## Custom types 48 | 49 | If you have custom types in your map, you can provide any `IEnumerable` to the loader. This will allow the loader to deserialize the custom types in your map. 50 | 51 | ```csharp 52 | var monsterSpawnerDef = new CustomClassDefinition { ... }; 53 | var chestDef = new CustomClassDefinition 54 | { 55 | Name = "Chest", 56 | UseAs = CustomClassUseAs.All, 57 | Members = [ 58 | new IntProperty { Name = "coins", Value = 0 }, 59 | new BoolProperty { Name = "locked", Value = true } 60 | ] 61 | }; 62 | 63 | var loader = Loader.DefaultWith( 64 | customTypeDefinitions: [monsterSpawnerDef, chestDef]); 65 | var map = loader.LoadMap("path/to/map.tmx"); 66 | 67 | var chest = map.GetProperty("chest").Value; 68 | var coinsToSpawn = chest.GetProperty("coins").Value; 69 | ``` -------------------------------------------------------------------------------- /docs/docs/toc.yml: -------------------------------------------------------------------------------- 1 | - name: Introduction 2 | - href: ../index.md 3 | - href: quickstart.md 4 | 5 | - name: Essentials 6 | - href: essentials/loading-maps.md 7 | - href: essentials/representation-model.md 8 | - href: essentials/custom-properties.md -------------------------------------------------------------------------------- /docs/images/entity-type-enum.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcronqvist/DotTiled/7f78a971f981e64a96a9d74f60d3af21c1d216ff/docs/images/entity-type-enum.png -------------------------------------------------------------------------------- /docs/images/monster-spawner-class.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcronqvist/DotTiled/7f78a971f981e64a96a9d74f60d3af21c1d216ff/docs/images/monster-spawner-class.png -------------------------------------------------------------------------------- /docs/images/resolve-types.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcronqvist/DotTiled/7f78a971f981e64a96a9d74f60d3af21c1d216ff/docs/images/resolve-types.png -------------------------------------------------------------------------------- /docs/template/public/main.css: -------------------------------------------------------------------------------- 1 | body { 2 | --bs-link-color-rgb: 66, 184, 131 !important; 3 | --bs-link-hover-color-rgb: 64, 180, 128 !important; 4 | } -------------------------------------------------------------------------------- /docs/template/public/main.js: -------------------------------------------------------------------------------- 1 | export default { 2 | iconLinks: [ 3 | { 4 | icon: 'github', 5 | href: 'https://github.com/dcronqvist/DotTiled', 6 | title: 'GitHub' 7 | } 8 | ] 9 | } -------------------------------------------------------------------------------- /docs/toc.yml: -------------------------------------------------------------------------------- 1 | - name: Docs 2 | href: docs/ 3 | - name: API 4 | href: api/ -------------------------------------------------------------------------------- /src/DotTiled.Benchmark/DotTiled.Benchmark.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net8.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/DotTiled.Examples/DotTiled.Example.Console/DotTiled.Example.Console.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net8.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/DotTiled.Examples/DotTiled.Example.Console/tilemap.tmx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAA== 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/DotTiled.Examples/DotTiled.Example.Console/tileset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcronqvist/DotTiled/7f78a971f981e64a96a9d74f60d3af21c1d216ff/src/DotTiled.Examples/DotTiled.Example.Console/tileset.png -------------------------------------------------------------------------------- /src/DotTiled.Examples/DotTiled.Example.Console/tileset.tsx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/DotTiled.Examples/DotTiled.Example.Godot/.gitattributes: -------------------------------------------------------------------------------- 1 | # Normalize EOL for all files that Git considers text files. 2 | * text=auto eol=lf 3 | -------------------------------------------------------------------------------- /src/DotTiled.Examples/DotTiled.Example.Godot/.gitignore: -------------------------------------------------------------------------------- 1 | # Godot 4+ specific ignores 2 | .godot/ 3 | -------------------------------------------------------------------------------- /src/DotTiled.Examples/DotTiled.Example.Godot/DotTiled.Example.Godot.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net8.0 4 | net7.0 5 | net8.0 6 | true 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/DotTiled.Examples/DotTiled.Example.Godot/DotTiled.Example.Godot.sln: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 12.00 2 | # Visual Studio 2012 3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotTiled.Example.Godot", "DotTiled.Example.Godot.csproj", "{61468FCF-ACC1-4E3B-B4B4-270279E45BF5}" 4 | EndProject 5 | Global 6 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 7 | Debug|Any CPU = Debug|Any CPU 8 | ExportDebug|Any CPU = ExportDebug|Any CPU 9 | ExportRelease|Any CPU = ExportRelease|Any CPU 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {61468FCF-ACC1-4E3B-B4B4-270279E45BF5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 13 | {61468FCF-ACC1-4E3B-B4B4-270279E45BF5}.Debug|Any CPU.Build.0 = Debug|Any CPU 14 | {61468FCF-ACC1-4E3B-B4B4-270279E45BF5}.ExportDebug|Any CPU.ActiveCfg = ExportDebug|Any CPU 15 | {61468FCF-ACC1-4E3B-B4B4-270279E45BF5}.ExportDebug|Any CPU.Build.0 = ExportDebug|Any CPU 16 | {61468FCF-ACC1-4E3B-B4B4-270279E45BF5}.ExportRelease|Any CPU.ActiveCfg = ExportRelease|Any CPU 17 | {61468FCF-ACC1-4E3B-B4B4-270279E45BF5}.ExportRelease|Any CPU.Build.0 = ExportRelease|Any CPU 18 | EndGlobalSection 19 | EndGlobal 20 | -------------------------------------------------------------------------------- /src/DotTiled.Examples/DotTiled.Example.Godot/MapParser.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | using System.Linq; 3 | using DotTiled.Serialization; 4 | using Godot; 5 | 6 | namespace DotTiled.Example.Godot; 7 | public partial class MapParser : Node2D 8 | { 9 | public override void _Ready() 10 | { 11 | // Load map 12 | var mapString = FileAccess.Open("res://tilemap.tmx", FileAccess.ModeFlags.Read).GetAsText(); //Get file from Godot filesystem 13 | using var mapReader = new MapReader(mapString, ResolveTileset, ResolveTemplate, ResolveCustomType); 14 | var map = mapReader.ReadMap(); 15 | 16 | TileLayer layer0 = (TileLayer)map.Layers[0]; 17 | 18 | for (int y = 0; y < layer0.Height; y++) 19 | { 20 | for (int x = 0; x < layer0.Width; x++) 21 | { 22 | uint tile = layer0.Data.Value.GlobalTileIDs.Value[(y * layer0.Width) + x]; 23 | if (tile == 0) continue; // If block is 0, i.e. air, then continue 24 | 25 | // Load actual block from Godot resources 26 | Node2D block = (Node2D)GD.Load($"res://blocks/{tile}.tscn").Instantiate(); 27 | 28 | // Calculate where block should be 29 | Vector2I scale = (Vector2I)block.GetNode(tile.ToString(CultureInfo.CurrentCulture)).Scale; 30 | int blockX = (block.GetNode(tile.ToString(CultureInfo.CurrentCulture)).Texture.GetWidth() * scale.X / 2) + 31 | (x * block.GetNode(tile.ToString(CultureInfo.CurrentCulture)).Texture.GetWidth() * scale.X); 32 | int blockY = (block.GetNode(tile.ToString(CultureInfo.CurrentCulture)).Texture.GetHeight() * scale.Y / 2) + 33 | (y * block.GetNode(tile.ToString(CultureInfo.CurrentCulture)).Texture.GetHeight() * scale.Y); 34 | block.Position = new Vector2(blockX, blockY); 35 | 36 | // Add block to current scene 37 | AddChild(block); 38 | GD.Print($"{blockX}, {blockY}: {tile}"); 39 | } 40 | } 41 | } 42 | 43 | private Tileset ResolveTileset(string source) 44 | { 45 | string tilesetString = FileAccess.Open($"res://{source}", FileAccess.ModeFlags.Read).GetAsText(); 46 | using TilesetReader tilesetReader = 47 | new TilesetReader(tilesetString, ResolveTileset, ResolveTemplate, ResolveCustomType); 48 | return tilesetReader.ReadTileset(); 49 | } 50 | 51 | private Template ResolveTemplate(string source) 52 | { 53 | string templateString = FileAccess.Open($"res://{source}", FileAccess.ModeFlags.Read).GetAsText(); 54 | using TemplateReader templateReader = 55 | new TemplateReader(templateString, ResolveTileset, ResolveTemplate, ResolveCustomType); 56 | return templateReader.ReadTemplate(); 57 | } 58 | 59 | private static Optional ResolveCustomType(string name) 60 | { 61 | ICustomTypeDefinition[] allDefinedTypes = 62 | [ 63 | new CustomClassDefinition() { Name = "a" }, 64 | ]; 65 | return allDefinedTypes.FirstOrDefault(ctd => ctd.Name == name) is ICustomTypeDefinition ctd ? new Optional(ctd) : Optional.Empty; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/DotTiled.Examples/DotTiled.Example.Godot/blocks/1.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=3 uid="uid://ce10iald4cb3f"] 2 | 3 | [ext_resource type="Texture2D" uid="uid://da08vay832u8c" path="res://tileset.png" id="1_c5fs4"] 4 | 5 | [node name="1" type="Node2D"] 6 | 7 | [node name="1" type="Sprite2D" parent="."] 8 | scale = Vector2(2, 2) 9 | texture = ExtResource("1_c5fs4") 10 | -------------------------------------------------------------------------------- /src/DotTiled.Examples/DotTiled.Example.Godot/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/DotTiled.Examples/DotTiled.Example.Godot/icon.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://0kywmrvvqqyr" 6 | path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://icon.svg" 14 | dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | svg/scale=1.0 36 | editor/scale_with_editor_scale=false 37 | editor/convert_colors_with_editor_theme=false 38 | -------------------------------------------------------------------------------- /src/DotTiled.Examples/DotTiled.Example.Godot/main.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=3 uid="uid://p4rpwsvyslew"] 2 | 3 | [ext_resource type="Script" path="res://MapParser.cs" id="1_xjmxv"] 4 | 5 | [node name="Node2D" type="Node2D"] 6 | script = ExtResource("1_xjmxv") 7 | -------------------------------------------------------------------------------- /src/DotTiled.Examples/DotTiled.Example.Godot/project.godot: -------------------------------------------------------------------------------- 1 | ; Engine configuration file. 2 | ; It's best edited using the editor UI and not directly, 3 | ; since the parameters that go here are not all obvious. 4 | ; 5 | ; Format: 6 | ; [section] ; section goes between [] 7 | ; param=value ; assign values to parameters 8 | 9 | config_version=5 10 | 11 | [application] 12 | 13 | config/name="DotTiled.Example.Godot" 14 | run/main_scene="res://main.tscn" 15 | config/features=PackedStringArray("4.3", "C#", "Forward Plus") 16 | config/icon="res://icon.svg" 17 | 18 | [dotnet] 19 | 20 | project/assembly_name="DotTiled.Example.Godot" 21 | -------------------------------------------------------------------------------- /src/DotTiled.Examples/DotTiled.Example.Godot/tilemap.tmx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAA== 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/DotTiled.Examples/DotTiled.Example.Godot/tileset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcronqvist/DotTiled/7f78a971f981e64a96a9d74f60d3af21c1d216ff/src/DotTiled.Examples/DotTiled.Example.Godot/tileset.png -------------------------------------------------------------------------------- /src/DotTiled.Examples/DotTiled.Example.Godot/tileset.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://da08vay832u8c" 6 | path="res://.godot/imported/tileset.png-a39e944f25b35d62f55d4f98a36e2b5e.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://tileset.png" 14 | dest_files=["res://.godot/imported/tileset.png-a39e944f25b35d62f55d4f98a36e2b5e.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | -------------------------------------------------------------------------------- /src/DotTiled.Examples/DotTiled.Example.Godot/tileset.tsx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/DotTiled.Tests/Assert/AssertCustomTypes.cs: -------------------------------------------------------------------------------- 1 | namespace DotTiled.Tests; 2 | 3 | public static partial class DotTiledAssert 4 | { 5 | internal static void AssertCustomClassDefinitionEqual(CustomClassDefinition expected, CustomClassDefinition actual) 6 | { 7 | AssertEqual(expected.ID, actual.ID, nameof(CustomClassDefinition.ID)); 8 | AssertEqual(expected.Name, actual.Name, nameof(CustomClassDefinition.Name)); 9 | AssertEqual(expected.Color, actual.Color, nameof(CustomClassDefinition.Color)); 10 | AssertEqual(expected.DrawFill, actual.DrawFill, nameof(CustomClassDefinition.DrawFill)); 11 | AssertEqual(expected.UseAs, actual.UseAs, nameof(CustomClassDefinition.UseAs)); 12 | AssertProperties(expected.Members, actual.Members); 13 | } 14 | 15 | internal static void AssertCustomEnumDefinitionEqual(CustomEnumDefinition expected, CustomEnumDefinition actual) 16 | { 17 | AssertEqual(expected.ID, actual.ID, nameof(CustomEnumDefinition.ID)); 18 | AssertEqual(expected.Name, actual.Name, nameof(CustomEnumDefinition.Name)); 19 | AssertEqual(expected.StorageType, actual.StorageType, nameof(CustomEnumDefinition.StorageType)); 20 | AssertEqual(expected.ValueAsFlags, actual.ValueAsFlags, nameof(CustomEnumDefinition.ValueAsFlags)); 21 | AssertListOrdered(expected.Values, actual.Values, nameof(CustomEnumDefinition.Values)); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/DotTiled.Tests/Assert/AssertData.cs: -------------------------------------------------------------------------------- 1 | namespace DotTiled.Tests; 2 | 3 | public static partial class DotTiledAssert 4 | { 5 | internal static void AssertData(Data expected, Data actual) 6 | { 7 | if (expected is null) 8 | { 9 | Assert.Null(actual); 10 | return; 11 | } 12 | 13 | // Attributes 14 | Assert.NotNull(actual); 15 | AssertEqual(expected.Encoding, actual.Encoding, nameof(Data.Encoding)); 16 | AssertEqual(expected.Compression, actual.Compression, nameof(Data.Compression)); 17 | 18 | // Data 19 | AssertEqual(expected.GlobalTileIDs, actual.GlobalTileIDs, nameof(Data.GlobalTileIDs)); 20 | AssertEqual(expected.FlippingFlags, actual.FlippingFlags, nameof(Data.FlippingFlags)); 21 | AssertOptionalsEqual(expected.Chunks, actual.Chunks, nameof(Data.Chunks), (a, b) => AssertListOrdered(a, b, nameof(Chunk), AssertChunk)); 22 | } 23 | 24 | private static void AssertChunk(Chunk expected, Chunk actual) 25 | { 26 | // Attributes 27 | AssertEqual(expected.X, actual.X, nameof(Chunk.X)); 28 | AssertEqual(expected.Y, actual.Y, nameof(Chunk.Y)); 29 | AssertEqual(expected.Width, actual.Width, nameof(Chunk.Width)); 30 | AssertEqual(expected.Height, actual.Height, nameof(Chunk.Height)); 31 | 32 | // Data 33 | AssertEqual(expected.GlobalTileIDs, actual.GlobalTileIDs, nameof(Chunk.GlobalTileIDs)); 34 | AssertEqual(expected.FlippingFlags, actual.FlippingFlags, nameof(Chunk.FlippingFlags)); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/DotTiled.Tests/Assert/AssertImage.cs: -------------------------------------------------------------------------------- 1 | namespace DotTiled.Tests; 2 | 3 | public static partial class DotTiledAssert 4 | { 5 | internal static void AssertImage(Image expected, Image actual) 6 | { 7 | if (expected is null) 8 | { 9 | Assert.Null(actual); 10 | return; 11 | } 12 | 13 | // Attributes 14 | Assert.NotNull(actual); 15 | AssertEqual(expected.Format, actual.Format, nameof(Image.Format)); 16 | AssertEqual(expected.Source, actual.Source, nameof(Image.Source)); 17 | AssertEqual(expected.TransparentColor, actual.TransparentColor, nameof(Image.TransparentColor)); 18 | AssertEqual(expected.Width, actual.Width, nameof(Image.Width)); 19 | AssertEqual(expected.Height, actual.Height, nameof(Image.Height)); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/DotTiled.Tests/Assert/AssertLayer.cs: -------------------------------------------------------------------------------- 1 | namespace DotTiled.Tests; 2 | 3 | public static partial class DotTiledAssert 4 | { 5 | internal static void AssertLayer(BaseLayer expected, BaseLayer actual) 6 | { 7 | if (expected is null) 8 | { 9 | Assert.Null(actual); 10 | return; 11 | } 12 | 13 | // Attributes 14 | Assert.NotNull(actual); 15 | AssertEqual(expected.ID, actual.ID, nameof(BaseLayer.ID)); 16 | AssertEqual(expected.Name, actual.Name, nameof(BaseLayer.Name)); 17 | AssertEqual(expected.Class, actual.Class, nameof(BaseLayer.Class)); 18 | AssertEqual(expected.Opacity, actual.Opacity, nameof(BaseLayer.Opacity)); 19 | AssertEqual(expected.Visible, actual.Visible, nameof(BaseLayer.Visible)); 20 | AssertEqual(expected.TintColor, actual.TintColor, nameof(BaseLayer.TintColor)); 21 | AssertEqual(expected.OffsetX, actual.OffsetX, nameof(BaseLayer.OffsetX)); 22 | AssertEqual(expected.OffsetY, actual.OffsetY, nameof(BaseLayer.OffsetY)); 23 | AssertEqual(expected.ParallaxX, actual.ParallaxX, nameof(BaseLayer.ParallaxX)); 24 | AssertEqual(expected.ParallaxY, actual.ParallaxY, nameof(BaseLayer.ParallaxY)); 25 | 26 | AssertProperties(expected.Properties, actual.Properties); 27 | AssertLayer((dynamic)expected, (dynamic)actual); 28 | } 29 | 30 | private static void AssertLayer(TileLayer expected, TileLayer actual) 31 | { 32 | // Attributes 33 | AssertEqual(expected.Width, actual.Width, nameof(TileLayer.Width)); 34 | AssertEqual(expected.Height, actual.Height, nameof(TileLayer.Height)); 35 | AssertEqual(expected.X, actual.X, nameof(TileLayer.X)); 36 | AssertEqual(expected.Y, actual.Y, nameof(TileLayer.Y)); 37 | 38 | Assert.NotNull(actual.Data); 39 | AssertData(expected.Data, actual.Data); 40 | } 41 | 42 | private static void AssertLayer(ObjectLayer expected, ObjectLayer actual) 43 | { 44 | // Attributes 45 | AssertEqual(expected.DrawOrder, actual.DrawOrder, nameof(ObjectLayer.DrawOrder)); 46 | AssertEqual(expected.X, actual.X, nameof(ObjectLayer.X)); 47 | AssertEqual(expected.Y, actual.Y, nameof(ObjectLayer.Y)); 48 | 49 | Assert.NotNull(actual.Objects); 50 | AssertEqual(expected.Objects.Count, actual.Objects.Count, "Objects.Count"); 51 | for (var i = 0; i < expected.Objects.Count; i++) 52 | AssertObject(expected.Objects[i], actual.Objects[i]); 53 | } 54 | 55 | private static void AssertLayer(ImageLayer expected, ImageLayer actual) 56 | { 57 | // Attributes 58 | AssertEqual(expected.RepeatX, actual.RepeatX, nameof(ImageLayer.RepeatX)); 59 | AssertEqual(expected.RepeatY, actual.RepeatY, nameof(ImageLayer.RepeatY)); 60 | AssertEqual(expected.X, actual.X, nameof(ImageLayer.X)); 61 | AssertEqual(expected.Y, actual.Y, nameof(ImageLayer.Y)); 62 | 63 | Assert.NotNull(actual.Image); 64 | AssertImage(expected.Image, actual.Image); 65 | } 66 | 67 | private static void AssertLayer(Group expected, Group actual) 68 | { 69 | // Attributes 70 | Assert.NotNull(actual.Layers); 71 | AssertEqual(expected.Layers.Count, actual.Layers.Count, "Layers.Count"); 72 | for (var i = 0; i < expected.Layers.Count; i++) 73 | AssertLayer(expected.Layers[i], actual.Layers[i]); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/DotTiled.Tests/Assert/AssertObject.cs: -------------------------------------------------------------------------------- 1 | namespace DotTiled.Tests; 2 | 3 | public static partial class DotTiledAssert 4 | { 5 | internal static void AssertObject(DotTiled.Object expected, DotTiled.Object actual) 6 | { 7 | // Attributes 8 | #pragma warning disable IDE0002 9 | AssertEqual(expected.ID, actual.ID, nameof(DotTiled.Object.ID)); 10 | AssertEqual(expected.Name, actual.Name, nameof(DotTiled.Object.Name)); 11 | AssertEqual(expected.Type, actual.Type, nameof(DotTiled.Object.Type)); 12 | AssertEqual(expected.X, actual.X, nameof(DotTiled.Object.X)); 13 | AssertEqual(expected.Y, actual.Y, nameof(DotTiled.Object.Y)); 14 | AssertEqual(expected.Width, actual.Width, nameof(DotTiled.Object.Width)); 15 | AssertEqual(expected.Height, actual.Height, nameof(DotTiled.Object.Height)); 16 | AssertEqual(expected.Rotation, actual.Rotation, nameof(DotTiled.Object.Rotation)); 17 | AssertEqual(expected.Visible, actual.Visible, nameof(DotTiled.Object.Visible)); 18 | AssertEqual(expected.Template, actual.Template, nameof(DotTiled.Object.Template)); 19 | #pragma warning restore IDE0002 20 | 21 | AssertProperties(expected.Properties, actual.Properties); 22 | 23 | Assert.True(expected.GetType() == actual.GetType(), $"Expected object type {expected.GetType()} but got {actual.GetType()}"); 24 | AssertObject((dynamic)expected, (dynamic)actual); 25 | } 26 | 27 | private static void AssertObject(RectangleObject _, RectangleObject __) => Assert.True(true); // A rectangle object is the same as the abstract Object 28 | 29 | private static void AssertObject(EllipseObject _, EllipseObject __) => Assert.True(true); // An ellipse object is the same as the abstract Object 30 | 31 | private static void AssertObject(PointObject _, PointObject __) => Assert.True(true); // A point object is the same as the abstract Object 32 | 33 | private static void AssertObject(PolygonObject expected, PolygonObject actual) => AssertEqual(expected.Points, actual.Points, nameof(PolygonObject.Points)); 34 | 35 | private static void AssertObject(PolylineObject expected, PolylineObject actual) => AssertEqual(expected.Points, actual.Points, nameof(PolylineObject.Points)); 36 | 37 | private static void AssertObject(TextObject expected, TextObject actual) 38 | { 39 | // Attributes 40 | AssertEqual(expected.FontFamily, actual.FontFamily, nameof(TextObject.FontFamily)); 41 | AssertEqual(expected.PixelSize, actual.PixelSize, nameof(TextObject.PixelSize)); 42 | AssertEqual(expected.Wrap, actual.Wrap, nameof(TextObject.Wrap)); 43 | AssertEqual(expected.Color, actual.Color, nameof(TextObject.Color)); 44 | AssertEqual(expected.Bold, actual.Bold, nameof(TextObject.Bold)); 45 | AssertEqual(expected.Italic, actual.Italic, nameof(TextObject.Italic)); 46 | AssertEqual(expected.Underline, actual.Underline, nameof(TextObject.Underline)); 47 | AssertEqual(expected.Strikeout, actual.Strikeout, nameof(TextObject.Strikeout)); 48 | AssertEqual(expected.Kerning, actual.Kerning, nameof(TextObject.Kerning)); 49 | AssertEqual(expected.HorizontalAlignment, actual.HorizontalAlignment, nameof(TextObject.HorizontalAlignment)); 50 | AssertEqual(expected.VerticalAlignment, actual.VerticalAlignment, nameof(TextObject.VerticalAlignment)); 51 | 52 | AssertEqual(expected.Text, actual.Text, nameof(TextObject.Text)); 53 | } 54 | 55 | private static void AssertObject(TileObject expected, TileObject actual) => AssertEqual(expected.GID, actual.GID, nameof(TileObject.GID)); 56 | } 57 | -------------------------------------------------------------------------------- /src/DotTiled.Tests/Assert/AssertProperties.cs: -------------------------------------------------------------------------------- 1 | namespace DotTiled.Tests; 2 | 3 | public static partial class DotTiledAssert 4 | { 5 | internal static void AssertProperties(IList expected, IList actual) 6 | { 7 | if (expected is null) 8 | { 9 | Assert.Null(actual); 10 | return; 11 | } 12 | 13 | Assert.NotNull(actual); 14 | AssertEqual(expected.Count, actual.Count, "Properties.Count"); 15 | foreach (var prop in expected) 16 | { 17 | Assert.Contains(actual, p => p.Name == prop.Name); 18 | 19 | var actualProp = actual.First(p => p.Name == prop.Name); 20 | AssertEqual(prop.Type, actualProp.Type, "Property.Type"); 21 | AssertEqual(prop.Name, actualProp.Name, "Property.Name"); 22 | 23 | AssertProperty((dynamic)prop, (dynamic)actualProp); 24 | } 25 | } 26 | 27 | private static void AssertProperty(StringProperty expected, StringProperty actual) => AssertEqual(expected.Value, actual.Value, "StringProperty.Value"); 28 | 29 | private static void AssertProperty(IntProperty expected, IntProperty actual) => AssertEqual(expected.Value, actual.Value, "IntProperty.Value"); 30 | 31 | private static void AssertProperty(FloatProperty expected, FloatProperty actual) => AssertEqual(expected.Value, actual.Value, "FloatProperty.Value"); 32 | 33 | private static void AssertProperty(BoolProperty expected, BoolProperty actual) => AssertEqual(expected.Value, actual.Value, "BoolProperty.Value"); 34 | 35 | private static void AssertProperty(ColorProperty expected, ColorProperty actual) => AssertEqual(expected.Value, actual.Value, "ColorProperty.Value"); 36 | 37 | private static void AssertProperty(FileProperty expected, FileProperty actual) => AssertEqual(expected.Value, actual.Value, "FileProperty.Value"); 38 | 39 | private static void AssertProperty(ObjectProperty expected, ObjectProperty actual) => AssertEqual(expected.Value, actual.Value, "ObjectProperty.Value"); 40 | 41 | private static void AssertProperty(ClassProperty expected, ClassProperty actual) 42 | { 43 | AssertEqual(expected.PropertyType, actual.PropertyType, "ClassProperty.PropertyType"); 44 | AssertProperties(expected.Value, actual.Value); 45 | } 46 | 47 | private static void AssertProperty(EnumProperty expected, EnumProperty actual) 48 | { 49 | AssertEqual(expected.PropertyType, actual.PropertyType, "EnumProperty.PropertyType"); 50 | AssertEqual(expected.Value.Count, actual.Value.Count, "EnumProperty.Value.Count"); 51 | foreach (var value in expected.Value) 52 | { 53 | Assert.Contains(actual.Value, v => v == value); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/DotTiled.Tests/DotTiled.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | 7 | false 8 | true 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/default-map/default-map.cs: -------------------------------------------------------------------------------- 1 | namespace DotTiled.Tests; 2 | 3 | public partial class TestData 4 | { 5 | public static Map DefaultMap() => new Map 6 | { 7 | Class = "", 8 | Orientation = MapOrientation.Orthogonal, 9 | Width = 5, 10 | Height = 5, 11 | TileWidth = 32, 12 | TileHeight = 32, 13 | Infinite = false, 14 | ParallaxOriginX = 0, 15 | ParallaxOriginY = 0, 16 | RenderOrder = RenderOrder.RightDown, 17 | CompressionLevel = -1, 18 | BackgroundColor = new Color { R = 0, G = 0, B = 0, A = 0 }, 19 | Version = "1.10", 20 | TiledVersion = "1.11.0", 21 | NextLayerID = 2, 22 | NextObjectID = 1, 23 | Layers = [ 24 | new TileLayer 25 | { 26 | ID = 1, 27 | Name = "Tile Layer 1", 28 | Width = 5, 29 | Height = 5, 30 | Data = new Data 31 | { 32 | Encoding = DataEncoding.Csv, 33 | GlobalTileIDs = new Optional([ 34 | 0, 0, 0, 0, 0, 35 | 0, 0, 0, 0, 0, 36 | 0, 0, 0, 0, 0, 37 | 0, 0, 0, 0, 0, 38 | 0, 0, 0, 0, 0 39 | ]), 40 | FlippingFlags = new Optional([ 41 | FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, 42 | FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, 43 | FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, 44 | FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, 45 | FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None 46 | ]) 47 | } 48 | } 49 | ] 50 | }; 51 | } 52 | -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/default-map/default-map.tmj: -------------------------------------------------------------------------------- 1 | { "compressionlevel":-1, 2 | "height":5, 3 | "infinite":false, 4 | "layers":[ 5 | { 6 | "data":[0, 0, 0, 0, 0, 7 | 0, 0, 0, 0, 0, 8 | 0, 0, 0, 0, 0, 9 | 0, 0, 0, 0, 0, 10 | 0, 0, 0, 0, 0], 11 | "height":5, 12 | "id":1, 13 | "name":"Tile Layer 1", 14 | "opacity":1, 15 | "type":"tilelayer", 16 | "visible":true, 17 | "width":5, 18 | "x":0, 19 | "y":0 20 | }], 21 | "nextlayerid":2, 22 | "nextobjectid":1, 23 | "orientation":"orthogonal", 24 | "renderorder":"right-down", 25 | "tiledversion":"1.11.0", 26 | "tileheight":32, 27 | "tilesets":[], 28 | "tilewidth":32, 29 | "type":"map", 30 | "version":"1.10", 31 | "width":5 32 | } -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/default-map/default-map.tmx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 0,0,0,0,0, 6 | 0,0,0,0,0, 7 | 0,0,0,0,0, 8 | 0,0,0,0,0, 9 | 0,0,0,0,0 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-external-tileset-multi/map-external-tileset-multi.tmj: -------------------------------------------------------------------------------- 1 | { "compressionlevel":-1, 2 | "height":5, 3 | "infinite":false, 4 | "layers":[ 5 | { 6 | "data":[0, 0, 0, 0, 0, 7 | 0, 0, 0, 0, 0, 8 | 1, 0, 0, 0, 0, 9 | 0, 0, 0, 0, 0, 10 | 0, 2, 0, 0, 0], 11 | "height":5, 12 | "id":1, 13 | "name":"Tile Layer 1", 14 | "opacity":1, 15 | "type":"tilelayer", 16 | "visible":true, 17 | "width":5, 18 | "x":0, 19 | "y":0 20 | }], 21 | "nextlayerid":2, 22 | "nextobjectid":1, 23 | "orientation":"orthogonal", 24 | "renderorder":"right-down", 25 | "tiledversion":"1.11.0", 26 | "tileheight":32, 27 | "tilesets":[ 28 | { 29 | "firstgid":1, 30 | "source":"multi-tileset.tsj" 31 | }], 32 | "tilewidth":32, 33 | "type":"map", 34 | "version":"1.10", 35 | "width":5 36 | } -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-external-tileset-multi/map-external-tileset-multi.tmx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 0,0,0,0,0, 7 | 0,0,0,0,0, 8 | 1,0,0,0,0, 9 | 0,0,0,0,0, 10 | 0,2,0,0,0 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-external-tileset-multi/multi-tileset.tsj: -------------------------------------------------------------------------------- 1 | { "columns":0, 2 | "grid": 3 | { 4 | "height":1, 5 | "orientation":"orthogonal", 6 | "width":1 7 | }, 8 | "margin":0, 9 | "name":"multi-tileset", 10 | "properties":[ 11 | { 12 | "name":"tilesetbool", 13 | "type":"bool", 14 | "value":true 15 | }, 16 | { 17 | "name":"tilesetcolor", 18 | "type":"color", 19 | "value":"#ffff0000" 20 | }, 21 | { 22 | "name":"tilesetfile", 23 | "type":"file", 24 | "value":"" 25 | }, 26 | { 27 | "name":"tilesetfloat", 28 | "type":"float", 29 | "value":5.2 30 | }, 31 | { 32 | "name":"tilesetint", 33 | "type":"int", 34 | "value":9 35 | }, 36 | { 37 | "name":"tilesetobject", 38 | "type":"object", 39 | "value":0 40 | }, 41 | { 42 | "name":"tilesetstring", 43 | "type":"string", 44 | "value":"hello world!" 45 | }], 46 | "spacing":0, 47 | "tilecount":2, 48 | "tiledversion":"1.11.0", 49 | "tileheight":96, 50 | "tileoffset": 51 | { 52 | "x":1, 53 | "y":5 54 | }, 55 | "tiles":[ 56 | { 57 | "id":0, 58 | "image":"tileset.png", 59 | "imageheight":96, 60 | "imagewidth":256 61 | }, 62 | { 63 | "id":1, 64 | "image":"tileset.png", 65 | "imageheight":96, 66 | "imagewidth":256 67 | }], 68 | "tilewidth":256, 69 | "type":"tileset", 70 | "version":"1.10" 71 | } -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-external-tileset-multi/multi-tileset.tsx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-external-tileset-multi/tileset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcronqvist/DotTiled/7f78a971f981e64a96a9d74f60d3af21c1d216ff/src/DotTiled.Tests/TestData/Maps/map-external-tileset-multi/tileset.png -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-external-tileset-wangset/map-external-tileset-wangset.tmj: -------------------------------------------------------------------------------- 1 | { "compressionlevel":-1, 2 | "height":5, 3 | "infinite":false, 4 | "layers":[ 5 | { 6 | "data":[2147483650, 2, 2147483660, 2147483659, 0, 7 | 1073741825, 12, 1, 3221225483, 0, 8 | 2, 1, 0, 3221225473, 0, 9 | 12, 11, 12, 2147483650, 0, 10 | 0, 0, 0, 0, 0], 11 | "height":5, 12 | "id":1, 13 | "name":"Tile Layer 1", 14 | "opacity":1, 15 | "type":"tilelayer", 16 | "visible":true, 17 | "width":5, 18 | "x":0, 19 | "y":0 20 | }], 21 | "nextlayerid":2, 22 | "nextobjectid":1, 23 | "orientation":"orthogonal", 24 | "renderorder":"right-down", 25 | "tiledversion":"1.11.0", 26 | "tileheight":24, 27 | "tilesets":[ 28 | { 29 | "firstgid":1, 30 | "source":"wangset-tileset.tsj" 31 | }], 32 | "tilewidth":24, 33 | "type":"map", 34 | "version":"1.10", 35 | "width":5 36 | } -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-external-tileset-wangset/map-external-tileset-wangset.tmx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 2147483650,2,2147483660,2147483659,0, 7 | 1073741825,12,1,3221225483,0, 8 | 2,1,0,3221225473,0, 9 | 12,11,12,2147483650,0, 10 | 0,0,0,0,0 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-external-tileset-wangset/tileset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcronqvist/DotTiled/7f78a971f981e64a96a9d74f60d3af21c1d216ff/src/DotTiled.Tests/TestData/Maps/map-external-tileset-wangset/tileset.png -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-external-tileset-wangset/wangset-tileset.tsj: -------------------------------------------------------------------------------- 1 | { "columns":10, 2 | "grid": 3 | { 4 | "height":32, 5 | "orientation":"orthogonal", 6 | "width":32 7 | }, 8 | "image":"tileset.png", 9 | "imageheight":96, 10 | "imagewidth":256, 11 | "margin":0, 12 | "name":"tileset", 13 | "spacing":0, 14 | "tilecount":48, 15 | "tiledversion":"1.11.0", 16 | "tileheight":24, 17 | "tilewidth":24, 18 | "transformations": 19 | { 20 | "hflip":true, 21 | "preferuntransformed":false, 22 | "rotate":false, 23 | "vflip":true 24 | }, 25 | "type":"tileset", 26 | "version":"1.10", 27 | "wangsets":[ 28 | { 29 | "colors":[ 30 | { 31 | "color":"#ff0000", 32 | "name":"Water", 33 | "probability":1, 34 | "tile":0 35 | }, 36 | { 37 | "color":"#00ff00", 38 | "name":"Grass", 39 | "probability":1, 40 | "tile":-1 41 | }, 42 | { 43 | "color":"#0000ff", 44 | "name":"Stone", 45 | "probability":1, 46 | "tile":29 47 | }], 48 | "name":"test-terrain", 49 | "tile":-1, 50 | "type":"mixed", 51 | "wangtiles":[ 52 | { 53 | "tileid":0, 54 | "wangid":[1, 1, 0, 0, 0, 1, 1, 1] 55 | }, 56 | { 57 | "tileid":1, 58 | "wangid":[1, 1, 1, 1, 0, 0, 0, 1] 59 | }, 60 | { 61 | "tileid":10, 62 | "wangid":[0, 0, 0, 1, 1, 1, 1, 1] 63 | }, 64 | { 65 | "tileid":11, 66 | "wangid":[0, 1, 1, 1, 1, 1, 0, 0] 67 | }] 68 | }] 69 | } -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-external-tileset-wangset/wangset-tileset.tsx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-override-object-bug/map-override-object-bug.tmx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 0,0,0,0,0, 21 | 0,0,0,0,0, 22 | 0,0,0,0,0, 23 | 0,0,0,0,0, 24 | 0,0,0,0,0 25 | 26 | 27 | 28 | 29 | 0,15,15,0,0, 30 | 0,15,15,0,0, 31 | 0,15,15,15,0, 32 | 15,15,15,0,0, 33 | 0,0,0,0,0 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 1,1,1,1,1, 43 | 0,0,0,0,0, 44 | 0,0,0,0,0, 45 | 0,0,0,0,0, 46 | 0,0,0,0,0 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-override-object-bug/poly.tj: -------------------------------------------------------------------------------- 1 | { "object": 2 | { 3 | "height":0, 4 | "id":5, 5 | "name":"Poly", 6 | "polygon":[ 7 | { 8 | "x":0, 9 | "y":0 10 | }, 11 | { 12 | "x":104, 13 | "y":20 14 | }, 15 | { 16 | "x":35.6667, 17 | "y":32.3333 18 | }], 19 | "properties":[ 20 | { 21 | "name":"templateprop", 22 | "type":"string", 23 | "value":"helo there" 24 | }], 25 | "rotation":0, 26 | "type":"", 27 | "visible":true, 28 | "width":0 29 | }, 30 | "type":"template" 31 | } -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-override-object-bug/poly.tx: -------------------------------------------------------------------------------- 1 | 2 | 10 | -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-override-object-bug/random.tj: -------------------------------------------------------------------------------- 1 | { "object": 2 | { 3 | "height":0, 4 | "id":7, 5 | "name":"", 6 | "rotation":0, 7 | "type":"randomclass", 8 | "visible":true, 9 | "width":0 10 | }, 11 | "type":"template" 12 | } -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-override-object-bug/random.tx: -------------------------------------------------------------------------------- 1 | 2 | 5 | -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-override-object-bug/tileset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcronqvist/DotTiled/7f78a971f981e64a96a9d74f60d3af21c1d216ff/src/DotTiled.Tests/TestData/Maps/map-override-object-bug/tileset.png -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-override-object-bug/tileset.tsj: -------------------------------------------------------------------------------- 1 | { "columns":8, 2 | "image":"tileset.png", 3 | "imageheight":96, 4 | "imagewidth":256, 5 | "margin":0, 6 | "name":"tileset", 7 | "spacing":0, 8 | "tilecount":24, 9 | "tiledversion":"1.11.0", 10 | "tileheight":32, 11 | "tilewidth":32, 12 | "type":"tileset", 13 | "version":"1.10" 14 | } -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-override-object-bug/tileset.tsx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-with-class-and-props/map-with-class-and-props.cs: -------------------------------------------------------------------------------- 1 | namespace DotTiled.Tests; 2 | 3 | public partial class TestData 4 | { 5 | public static Map MapWithClassAndProps() => new Map 6 | { 7 | Class = "TestClass", 8 | Orientation = MapOrientation.Orthogonal, 9 | Width = 5, 10 | Height = 5, 11 | TileWidth = 32, 12 | TileHeight = 32, 13 | Infinite = false, 14 | ParallaxOriginX = 0, 15 | ParallaxOriginY = 0, 16 | RenderOrder = RenderOrder.RightDown, 17 | CompressionLevel = -1, 18 | BackgroundColor = new Color { R = 0, G = 0, B = 0, A = 0 }, 19 | Version = "1.10", 20 | TiledVersion = "1.11.0", 21 | NextLayerID = 2, 22 | NextObjectID = 1, 23 | Layers = [ 24 | new TileLayer 25 | { 26 | ID = 1, 27 | Name = "Tile Layer 1", 28 | Width = 5, 29 | Height = 5, 30 | Data = new Data 31 | { 32 | Encoding = DataEncoding.Csv, 33 | GlobalTileIDs = new Optional([ 34 | 0, 0, 0, 0, 0, 35 | 0, 0, 0, 0, 0, 36 | 0, 0, 0, 0, 0, 37 | 0, 0, 0, 0, 0, 38 | 0, 0, 0, 0, 0 39 | ]), 40 | FlippingFlags = new Optional([ 41 | FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, 42 | FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, 43 | FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, 44 | FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, 45 | FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None 46 | ]) 47 | } 48 | } 49 | ], 50 | Properties = [ 51 | new BoolProperty 52 | { 53 | Name = "classbool", 54 | Value = true 55 | }, 56 | new StringProperty 57 | { 58 | Name = "classstring", 59 | Value = "I am not default value" 60 | } 61 | ] 62 | }; 63 | 64 | public static IReadOnlyCollection MapWithClassAndPropsCustomTypeDefinitions() => [ 65 | new CustomClassDefinition 66 | { 67 | Name = "TestClass", 68 | UseAs = CustomClassUseAs.Map, 69 | Members = [ 70 | new BoolProperty 71 | { 72 | Name = "classbool", 73 | Value = true 74 | }, 75 | new StringProperty 76 | { 77 | Name = "classstring", 78 | Value = "Hello there default value" 79 | } 80 | ] 81 | }, 82 | ]; 83 | } 84 | -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-with-class-and-props/map-with-class-and-props.tmj: -------------------------------------------------------------------------------- 1 | { "class":"TestClass", 2 | "compressionlevel":-1, 3 | "height":5, 4 | "infinite":false, 5 | "layers":[ 6 | { 7 | "data":[0, 0, 0, 0, 0, 8 | 0, 0, 0, 0, 0, 9 | 0, 0, 0, 0, 0, 10 | 0, 0, 0, 0, 0, 11 | 0, 0, 0, 0, 0], 12 | "height":5, 13 | "id":1, 14 | "name":"Tile Layer 1", 15 | "opacity":1, 16 | "type":"tilelayer", 17 | "visible":true, 18 | "width":5, 19 | "x":0, 20 | "y":0 21 | }], 22 | "nextlayerid":2, 23 | "nextobjectid":1, 24 | "orientation":"orthogonal", 25 | "properties":[ 26 | { 27 | "name":"classstring", 28 | "type":"string", 29 | "value":"I am not default value" 30 | }], 31 | "renderorder":"right-down", 32 | "tiledversion":"1.11.0", 33 | "tileheight":32, 34 | "tilesets":[], 35 | "tilewidth":32, 36 | "type":"map", 37 | "version":"1.10", 38 | "width":5 39 | } -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-with-class-and-props/map-with-class-and-props.tmx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 0,0,0,0,0, 9 | 0,0,0,0,0, 10 | 0,0,0,0,0, 11 | 0,0,0,0,0, 12 | 0,0,0,0,0 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-with-class/map-with-class.cs: -------------------------------------------------------------------------------- 1 | namespace DotTiled.Tests; 2 | 3 | public partial class TestData 4 | { 5 | public static Map MapWithClass() => new Map 6 | { 7 | Class = "TestClass", 8 | Orientation = MapOrientation.Orthogonal, 9 | Width = 5, 10 | Height = 5, 11 | TileWidth = 32, 12 | TileHeight = 32, 13 | Infinite = false, 14 | ParallaxOriginX = 0, 15 | ParallaxOriginY = 0, 16 | RenderOrder = RenderOrder.RightDown, 17 | CompressionLevel = -1, 18 | BackgroundColor = new Color { R = 0, G = 0, B = 0, A = 0 }, 19 | Version = "1.10", 20 | TiledVersion = "1.11.0", 21 | NextLayerID = 2, 22 | NextObjectID = 1, 23 | Layers = [ 24 | new TileLayer 25 | { 26 | ID = 1, 27 | Name = "Tile Layer 1", 28 | Width = 5, 29 | Height = 5, 30 | Data = new Data 31 | { 32 | Encoding = DataEncoding.Csv, 33 | GlobalTileIDs = new Optional([ 34 | 0, 0, 0, 0, 0, 35 | 0, 0, 0, 0, 0, 36 | 0, 0, 0, 0, 0, 37 | 0, 0, 0, 0, 0, 38 | 0, 0, 0, 0, 0 39 | ]), 40 | FlippingFlags = new Optional([ 41 | FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, 42 | FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, 43 | FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, 44 | FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, 45 | FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None 46 | ]) 47 | } 48 | } 49 | ], 50 | Properties = [ 51 | new BoolProperty 52 | { 53 | Name = "classbool", 54 | Value = true 55 | }, 56 | new StringProperty 57 | { 58 | Name = "classstring", 59 | Value = "Hello there default value" 60 | } 61 | ] 62 | }; 63 | 64 | public static IReadOnlyCollection MapWithClassCustomTypeDefinitions() => [ 65 | new CustomClassDefinition 66 | { 67 | Name = "TestClass", 68 | UseAs = CustomClassUseAs.Map, 69 | Members = [ 70 | new BoolProperty 71 | { 72 | Name = "classbool", 73 | Value = true 74 | }, 75 | new StringProperty 76 | { 77 | Name = "classstring", 78 | Value = "Hello there default value" 79 | } 80 | ] 81 | }, 82 | ]; 83 | } 84 | -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-with-class/map-with-class.tmj: -------------------------------------------------------------------------------- 1 | { "class":"TestClass", 2 | "compressionlevel":-1, 3 | "height":5, 4 | "infinite":false, 5 | "layers":[ 6 | { 7 | "data":[0, 0, 0, 0, 0, 8 | 0, 0, 0, 0, 0, 9 | 0, 0, 0, 0, 0, 10 | 0, 0, 0, 0, 0, 11 | 0, 0, 0, 0, 0], 12 | "height":5, 13 | "id":1, 14 | "name":"Tile Layer 1", 15 | "opacity":1, 16 | "type":"tilelayer", 17 | "visible":true, 18 | "width":5, 19 | "x":0, 20 | "y":0 21 | }], 22 | "nextlayerid":2, 23 | "nextobjectid":1, 24 | "orientation":"orthogonal", 25 | "renderorder":"right-down", 26 | "tiledversion":"1.11.0", 27 | "tileheight":32, 28 | "tilesets":[], 29 | "tilewidth":32, 30 | "type":"map", 31 | "version":"1.10", 32 | "width":5 33 | } -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-with-class/map-with-class.tmx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 0,0,0,0,0, 6 | 0,0,0,0,0, 7 | 0,0,0,0,0, 8 | 0,0,0,0,0, 9 | 0,0,0,0,0 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-with-common-props/map-with-common-props.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | 3 | namespace DotTiled.Tests; 4 | 5 | public partial class TestData 6 | { 7 | public static Map MapWithCommonProps() => new Map 8 | { 9 | Class = "", 10 | Orientation = MapOrientation.Isometric, 11 | Width = 5, 12 | Height = 5, 13 | TileWidth = 32, 14 | TileHeight = 16, 15 | Infinite = false, 16 | ParallaxOriginX = 0, 17 | ParallaxOriginY = 0, 18 | RenderOrder = RenderOrder.RightDown, 19 | CompressionLevel = -1, 20 | BackgroundColor = Color.Parse("#00ff00", CultureInfo.InvariantCulture), 21 | Version = "1.10", 22 | TiledVersion = "1.11.0", 23 | NextLayerID = 2, 24 | NextObjectID = 1, 25 | Layers = [ 26 | new TileLayer 27 | { 28 | ID = 1, 29 | Name = "Tile Layer 1", 30 | Width = 5, 31 | Height = 5, 32 | Data = new Data 33 | { 34 | Encoding = DataEncoding.Csv, 35 | GlobalTileIDs = new Optional([ 36 | 0, 0, 0, 0, 0, 37 | 0, 0, 0, 0, 0, 38 | 0, 0, 0, 0, 0, 39 | 0, 0, 0, 0, 0, 40 | 0, 0, 0, 0, 0 41 | ]), 42 | FlippingFlags = new Optional([ 43 | FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, 44 | FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, 45 | FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, 46 | FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, 47 | FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None 48 | ]) 49 | } 50 | } 51 | ], 52 | Properties = 53 | [ 54 | new BoolProperty { Name = "boolprop", Value = true }, 55 | new ColorProperty { Name = "colorprop", Value = Color.Parse("#ff55ffff", CultureInfo.InvariantCulture) }, 56 | new FileProperty { Name = "fileprop", Value = "file.txt" }, 57 | new FloatProperty { Name = "floatprop", Value = 4.2f }, 58 | new IntProperty { Name = "intprop", Value = 8 }, 59 | new ObjectProperty { Name = "objectprop", Value = 5 }, 60 | new StringProperty { Name = "stringprop", Value = "This is a string, hello world!" }, 61 | new ColorProperty { Name = "unsetcolorprop", Value = Optional.Empty } 62 | ] 63 | }; 64 | } 65 | -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-with-common-props/map-with-common-props.tmj: -------------------------------------------------------------------------------- 1 | { "backgroundcolor":"#00ff00", 2 | "compressionlevel":-1, 3 | "height":5, 4 | "infinite":false, 5 | "layers":[ 6 | { 7 | "data":[0, 0, 0, 0, 0, 8 | 0, 0, 0, 0, 0, 9 | 0, 0, 0, 0, 0, 10 | 0, 0, 0, 0, 0, 11 | 0, 0, 0, 0, 0], 12 | "height":5, 13 | "id":1, 14 | "name":"Tile Layer 1", 15 | "opacity":1, 16 | "type":"tilelayer", 17 | "visible":true, 18 | "width":5, 19 | "x":0, 20 | "y":0 21 | }], 22 | "nextlayerid":2, 23 | "nextobjectid":1, 24 | "orientation":"isometric", 25 | "properties":[ 26 | { 27 | "name":"boolprop", 28 | "type":"bool", 29 | "value":true 30 | }, 31 | { 32 | "name":"colorprop", 33 | "type":"color", 34 | "value":"#ff55ffff" 35 | }, 36 | { 37 | "name":"fileprop", 38 | "type":"file", 39 | "value":"file.txt" 40 | }, 41 | { 42 | "name":"floatprop", 43 | "type":"float", 44 | "value":4.2 45 | }, 46 | { 47 | "name":"intprop", 48 | "type":"int", 49 | "value":8 50 | }, 51 | 52 | { 53 | "name":"objectprop", 54 | "type":"object", 55 | "value":5 56 | }, 57 | { 58 | "name":"stringprop", 59 | "type":"string", 60 | "value":"This is a string, hello world!" 61 | }, 62 | { 63 | "name":"unsetcolorprop", 64 | "type":"color", 65 | "value":"" 66 | }], 67 | "renderorder":"right-down", 68 | "tiledversion":"1.11.0", 69 | "tileheight":16, 70 | "tilesets":[], 71 | "tilewidth":32, 72 | "type":"map", 73 | "version":"1.10", 74 | "width":5 75 | } -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-with-common-props/map-with-common-props.tmx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 0,0,0,0,0, 16 | 0,0,0,0,0, 17 | 0,0,0,0,0, 18 | 0,0,0,0,0, 19 | 0,0,0,0,0 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-with-custom-type-props-without-defs/map-with-custom-type-props-without-defs.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | 3 | namespace DotTiled.Tests; 4 | 5 | public partial class TestData 6 | { 7 | public static Map MapWithCustomTypePropsWithoutDefs() => new Map 8 | { 9 | Class = "", 10 | Orientation = MapOrientation.Orthogonal, 11 | Width = 5, 12 | Height = 5, 13 | TileWidth = 32, 14 | TileHeight = 32, 15 | Infinite = false, 16 | ParallaxOriginX = 0, 17 | ParallaxOriginY = 0, 18 | RenderOrder = RenderOrder.RightDown, 19 | CompressionLevel = -1, 20 | BackgroundColor = Color.Parse("#00000000", CultureInfo.InvariantCulture), 21 | Version = "1.10", 22 | TiledVersion = "1.11.0", 23 | NextLayerID = 2, 24 | NextObjectID = 1, 25 | Layers = [ 26 | new TileLayer 27 | { 28 | ID = 1, 29 | Name = "Tile Layer 1", 30 | Width = 5, 31 | Height = 5, 32 | Data = new Data 33 | { 34 | Encoding = DataEncoding.Csv, 35 | GlobalTileIDs = new Optional([ 36 | 0, 0, 0, 0, 0, 37 | 0, 0, 0, 0, 0, 38 | 0, 0, 0, 0, 0, 39 | 0, 0, 0, 0, 0, 40 | 0, 0, 0, 0, 0 41 | ]), 42 | FlippingFlags = new Optional([ 43 | FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, 44 | FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, 45 | FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, 46 | FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, 47 | FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None 48 | ]) 49 | } 50 | } 51 | ], 52 | Properties = [ 53 | new ClassProperty 54 | { 55 | Name = "customclassprop", 56 | PropertyType = "CustomClass", 57 | Value = [ 58 | new BoolProperty { Name = "boolinclass", Value = true }, 59 | new FloatProperty { Name = "floatinclass", Value = 13.37f }, 60 | new StringProperty { Name = "stringinclass", Value = "This is a set string" } 61 | ] 62 | }, 63 | new IntProperty 64 | { 65 | Name = "customenumintflagsprop", 66 | Value = 6 67 | }, 68 | new IntProperty 69 | { 70 | Name = "customenumintprop", 71 | Value = 3 72 | }, 73 | new StringProperty 74 | { 75 | Name = "customenumstringprop", 76 | Value = "CustomEnumString_2" 77 | }, 78 | new StringProperty 79 | { 80 | Name = "customenumstringflagsprop", 81 | Value = "CustomEnumStringFlags_1,CustomEnumStringFlags_2" 82 | } 83 | ] 84 | }; 85 | } 86 | -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-with-custom-type-props-without-defs/map-with-custom-type-props-without-defs.tmj: -------------------------------------------------------------------------------- 1 | { "compressionlevel":-1, 2 | "height":5, 3 | "infinite":false, 4 | "layers":[ 5 | { 6 | "data":[0, 0, 0, 0, 0, 7 | 0, 0, 0, 0, 0, 8 | 0, 0, 0, 0, 0, 9 | 0, 0, 0, 0, 0, 10 | 0, 0, 0, 0, 0], 11 | "height":5, 12 | "id":1, 13 | "name":"Tile Layer 1", 14 | "opacity":1, 15 | "type":"tilelayer", 16 | "visible":true, 17 | "width":5, 18 | "x":0, 19 | "y":0 20 | }], 21 | "nextlayerid":2, 22 | "nextobjectid":1, 23 | "orientation":"orthogonal", 24 | "properties":[ 25 | { 26 | "name":"customclassprop", 27 | "propertytype":"CustomClass", 28 | "type":"class", 29 | "value": 30 | { 31 | "boolinclass":true, 32 | "floatinclass":13.37, 33 | "stringinclass":"This is a set string" 34 | } 35 | }, 36 | { 37 | "name":"customenumintflagsprop", 38 | "propertytype":"CustomEnumIntFlags", 39 | "type":"int", 40 | "value":6 41 | }, 42 | { 43 | "name":"customenumintprop", 44 | "propertytype":"CustomEnumInt", 45 | "type":"int", 46 | "value":3 47 | }, 48 | { 49 | "name":"customenumstringflagsprop", 50 | "propertytype":"CustomEnumStringFlags", 51 | "type":"string", 52 | "value":"CustomEnumStringFlags_1,CustomEnumStringFlags_2" 53 | }, 54 | { 55 | "name":"customenumstringprop", 56 | "propertytype":"CustomEnumString", 57 | "type":"string", 58 | "value":"CustomEnumString_2" 59 | }], 60 | "renderorder":"right-down", 61 | "tiledversion":"1.11.0", 62 | "tileheight":32, 63 | "tilesets":[], 64 | "tilewidth":32, 65 | "type":"map", 66 | "version":"1.10", 67 | "width":5 68 | } -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-with-custom-type-props-without-defs/map-with-custom-type-props-without-defs.tmx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 0,0,0,0,0, 19 | 0,0,0,0,0, 20 | 0,0,0,0,0, 21 | 0,0,0,0,0, 22 | 0,0,0,0,0 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-with-custom-type-props/map-with-custom-type-props.tmj: -------------------------------------------------------------------------------- 1 | { "compressionlevel":-1, 2 | "height":5, 3 | "infinite":false, 4 | "layers":[ 5 | { 6 | "data":[0, 0, 0, 0, 0, 7 | 0, 0, 0, 0, 0, 8 | 0, 0, 0, 0, 0, 9 | 0, 0, 0, 0, 0, 10 | 0, 0, 0, 0, 0], 11 | "height":5, 12 | "id":1, 13 | "name":"Tile Layer 1", 14 | "opacity":1, 15 | "type":"tilelayer", 16 | "visible":true, 17 | "width":5, 18 | "x":0, 19 | "y":0 20 | }], 21 | "nextlayerid":2, 22 | "nextobjectid":1, 23 | "orientation":"orthogonal", 24 | "properties":[ 25 | { 26 | "name":"customclassprop", 27 | "propertytype":"CustomClass", 28 | "type":"class", 29 | "value": 30 | { 31 | "boolinclass":true, 32 | "floatinclass":13.37, 33 | "stringinclass":"This is a set string" 34 | } 35 | }, 36 | { 37 | "name":"customenumintflagsprop", 38 | "propertytype":"CustomEnumIntFlags", 39 | "type":"int", 40 | "value":6 41 | }, 42 | { 43 | "name":"customenumintprop", 44 | "propertytype":"CustomEnumInt", 45 | "type":"int", 46 | "value":3 47 | }, 48 | { 49 | "name":"customenumstringflagsprop", 50 | "propertytype":"CustomEnumStringFlags", 51 | "type":"string", 52 | "value":"CustomEnumStringFlags_1,CustomEnumStringFlags_2" 53 | }, 54 | { 55 | "name":"customenumstringprop", 56 | "propertytype":"CustomEnumString", 57 | "type":"string", 58 | "value":"CustomEnumString_2" 59 | }], 60 | "renderorder":"right-down", 61 | "tiledversion":"1.11.0", 62 | "tileheight":32, 63 | "tilesets":[], 64 | "tilewidth":32, 65 | "type":"map", 66 | "version":"1.10", 67 | "width":5 68 | } -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-with-custom-type-props/map-with-custom-type-props.tmx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 0,0,0,0,0, 19 | 0,0,0,0,0, 20 | 0,0,0,0,0, 21 | 0,0,0,0,0, 22 | 0,0,0,0,0 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-with-custom-type-props/propertytypes.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "color": "#ffa0a0a4", 4 | "drawFill": true, 5 | "id": 8, 6 | "members": [ 7 | { 8 | "name": "boolinclass", 9 | "type": "bool", 10 | "value": false 11 | }, 12 | { 13 | "name": "colorinclass", 14 | "type": "color", 15 | "value": "" 16 | }, 17 | { 18 | "name": "fileinclass", 19 | "type": "file", 20 | "value": "" 21 | }, 22 | { 23 | "name": "floatinclass", 24 | "type": "float", 25 | "value": 0 26 | }, 27 | { 28 | "name": "intinclass", 29 | "type": "int", 30 | "value": 0 31 | }, 32 | { 33 | "name": "objectinclass", 34 | "type": "object", 35 | "value": 0 36 | }, 37 | { 38 | "name": "stringinclass", 39 | "type": "string", 40 | "value": "" 41 | } 42 | ], 43 | "name": "CustomClass", 44 | "type": "class", 45 | "useAs": [ 46 | "property" 47 | ] 48 | } 49 | ] 50 | -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-with-deep-props/map-with-deep-props.tmj: -------------------------------------------------------------------------------- 1 | { "compressionlevel":-1, 2 | "height":5, 3 | "infinite":false, 4 | "layers":[ 5 | { 6 | "data":[0, 0, 0, 0, 0, 7 | 0, 0, 0, 0, 0, 8 | 0, 0, 0, 0, 0, 9 | 0, 0, 0, 0, 0, 10 | 0, 0, 0, 0, 0], 11 | "height":5, 12 | "id":1, 13 | "name":"Tile Layer 1", 14 | "opacity":1, 15 | "type":"tilelayer", 16 | "visible":true, 17 | "width":5, 18 | "x":0, 19 | "y":0 20 | }], 21 | "nextlayerid":2, 22 | "nextobjectid":1, 23 | "orientation":"orthogonal", 24 | "properties":[ 25 | { 26 | "name":"customouterclassprop", 27 | "propertytype":"CustomOuterClass", 28 | "type":"class", 29 | "value": 30 | { 31 | 32 | } 33 | }, 34 | { 35 | "name":"customouterclasspropset", 36 | "propertytype":"CustomOuterClass", 37 | "type":"class", 38 | "value": 39 | { 40 | "customclasspropinclass": 41 | { 42 | "boolinclass":true, 43 | "floatinclass":13.37 44 | } 45 | } 46 | }], 47 | "renderorder":"right-down", 48 | "tiledversion":"1.11.0", 49 | "tileheight":32, 50 | "tilesets":[], 51 | "tilewidth":32, 52 | "type":"map", 53 | "version":"1.10", 54 | "width":5 55 | } -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-with-deep-props/map-with-deep-props.tmx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 0,0,0,0,0, 19 | 0,0,0,0,0, 20 | 0,0,0,0,0, 21 | 0,0,0,0,0, 22 | 0,0,0,0,0 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-with-embedded-tileset/map-with-embedded-tileset.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | 3 | namespace DotTiled.Tests; 4 | 5 | public partial class TestData 6 | { 7 | public static Map MapWithEmbeddedTileset() => new Map 8 | { 9 | Class = "", 10 | Orientation = MapOrientation.Orthogonal, 11 | Width = 5, 12 | Height = 5, 13 | TileWidth = 32, 14 | TileHeight = 32, 15 | Infinite = false, 16 | ParallaxOriginX = 0, 17 | ParallaxOriginY = 0, 18 | RenderOrder = RenderOrder.RightDown, 19 | CompressionLevel = -1, 20 | BackgroundColor = Color.Parse("#00000000", CultureInfo.InvariantCulture), 21 | Version = "1.10", 22 | TiledVersion = "1.11.0", 23 | NextLayerID = 2, 24 | NextObjectID = 1, 25 | Tilesets = [ 26 | new Tileset 27 | { 28 | Version = "1.10", 29 | TiledVersion = "1.11.0", 30 | FirstGID = 1, 31 | Name = "tileset", 32 | TileWidth = 32, 33 | TileHeight = 32, 34 | TileCount = 24, 35 | Columns = 8, 36 | Image = new Image 37 | { 38 | Format = ImageFormat.Png, 39 | Source = "tileset.png", 40 | Width = 256, 41 | Height = 96, 42 | } 43 | } 44 | ], 45 | Layers = [ 46 | new TileLayer 47 | { 48 | ID = 1, 49 | Name = "Tile Layer 1", 50 | Width = 5, 51 | Height = 5, 52 | Data = new Data 53 | { 54 | Encoding = DataEncoding.Csv, 55 | GlobalTileIDs = new Optional([ 56 | 1, 1, 0, 0, 7, 57 | 1, 1, 0, 0, 7, 58 | 0, 0, 0, 0, 7, 59 | 9, 10, 0, 0, 7, 60 | 17, 18, 0, 0, 0 61 | ]), 62 | FlippingFlags = new Optional([ 63 | FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, 64 | FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, 65 | FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, 66 | FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, 67 | FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None 68 | ]) 69 | } 70 | } 71 | ] 72 | }; 73 | } 74 | -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-with-embedded-tileset/map-with-embedded-tileset.tmj: -------------------------------------------------------------------------------- 1 | { "compressionlevel":-1, 2 | "height":5, 3 | "infinite":false, 4 | "layers":[ 5 | { 6 | "data":[1, 1, 0, 0, 7, 7 | 1, 1, 0, 0, 7, 8 | 0, 0, 0, 0, 7, 9 | 9, 10, 0, 0, 7, 10 | 17, 18, 0, 0, 0], 11 | "height":5, 12 | "id":1, 13 | "name":"Tile Layer 1", 14 | "opacity":1, 15 | "type":"tilelayer", 16 | "visible":true, 17 | "width":5, 18 | "x":0, 19 | "y":0 20 | }], 21 | "nextlayerid":2, 22 | "nextobjectid":1, 23 | "orientation":"orthogonal", 24 | "renderorder":"right-down", 25 | "tiledversion":"1.11.0", 26 | "tileheight":32, 27 | "tilesets":[ 28 | { 29 | "columns":8, 30 | "firstgid":1, 31 | "image":"tileset.png", 32 | "imageheight":96, 33 | "imagewidth":256, 34 | "margin":0, 35 | "name":"tileset", 36 | "spacing":0, 37 | "tilecount":24, 38 | "tileheight":32, 39 | "tilewidth":32 40 | }], 41 | "tilewidth":32, 42 | "type":"map", 43 | "version":"1.10", 44 | "width":5 45 | } -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-with-embedded-tileset/map-with-embedded-tileset.tmx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 1,1,0,0,7, 9 | 1,1,0,0,7, 10 | 0,0,0,0,7, 11 | 9,10,0,0,7, 12 | 17,18,0,0,0 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-with-embedded-tileset/tileset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcronqvist/DotTiled/7f78a971f981e64a96a9d74f60d3af21c1d216ff/src/DotTiled.Tests/TestData/Maps/map-with-embedded-tileset/tileset.png -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-with-external-tileset/map-with-external-tileset.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | 3 | namespace DotTiled.Tests; 4 | 5 | public partial class TestData 6 | { 7 | public static Map MapWithExternalTileset(string fileExt) => new Map 8 | { 9 | Class = "", 10 | Orientation = MapOrientation.Orthogonal, 11 | Width = 5, 12 | Height = 5, 13 | TileWidth = 32, 14 | TileHeight = 32, 15 | Infinite = false, 16 | ParallaxOriginX = 0, 17 | ParallaxOriginY = 0, 18 | RenderOrder = RenderOrder.RightDown, 19 | CompressionLevel = -1, 20 | BackgroundColor = Color.Parse("#00000000", CultureInfo.InvariantCulture), 21 | Version = "1.10", 22 | TiledVersion = "1.11.0", 23 | NextLayerID = 2, 24 | NextObjectID = 1, 25 | Tilesets = [ 26 | new Tileset 27 | { 28 | Version = "1.10", 29 | TiledVersion = "1.11.0", 30 | FirstGID = 1, 31 | Name = "tileset", 32 | TileWidth = 32, 33 | TileHeight = 32, 34 | TileCount = 24, 35 | Columns = 8, 36 | Source = $"tileset.{(fileExt == "tmx" ? "tsx" : "tsj")}", 37 | Image = new Image 38 | { 39 | Format = ImageFormat.Png, 40 | Source = "tileset.png", 41 | Width = 256, 42 | Height = 96, 43 | } 44 | } 45 | ], 46 | Layers = [ 47 | new TileLayer 48 | { 49 | ID = 1, 50 | Name = "Tile Layer 1", 51 | Width = 5, 52 | Height = 5, 53 | Data = new Data 54 | { 55 | Encoding = DataEncoding.Csv, 56 | GlobalTileIDs = new Optional([ 57 | 1, 1, 0, 0, 7, 58 | 1, 1, 0, 0, 7, 59 | 0, 0, 1, 0, 7, 60 | 0, 0, 0, 1, 7, 61 | 21, 21, 21, 21, 1 62 | ]), 63 | FlippingFlags = new Optional([ 64 | FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, 65 | FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, 66 | FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, 67 | FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, 68 | FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None 69 | ]) 70 | } 71 | } 72 | ] 73 | }; 74 | } 75 | -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-with-external-tileset/map-with-external-tileset.tmj: -------------------------------------------------------------------------------- 1 | { "compressionlevel":-1, 2 | "height":5, 3 | "infinite":false, 4 | "layers":[ 5 | { 6 | "data":[1, 1, 0, 0, 7, 7 | 1, 1, 0, 0, 7, 8 | 0, 0, 1, 0, 7, 9 | 0, 0, 0, 1, 7, 10 | 21, 21, 21, 21, 1], 11 | "height":5, 12 | "id":1, 13 | "name":"Tile Layer 1", 14 | "opacity":1, 15 | "type":"tilelayer", 16 | "visible":true, 17 | "width":5, 18 | "x":0, 19 | "y":0 20 | }], 21 | "nextlayerid":2, 22 | "nextobjectid":1, 23 | "orientation":"orthogonal", 24 | "renderorder":"right-down", 25 | "tiledversion":"1.11.0", 26 | "tileheight":32, 27 | "tilesets":[ 28 | { 29 | "firstgid":1, 30 | "source":"tileset.tsj" 31 | }], 32 | "tilewidth":32, 33 | "type":"map", 34 | "version":"1.10", 35 | "width":5 36 | } -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-with-external-tileset/map-with-external-tileset.tmx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 1,1,0,0,7, 7 | 1,1,0,0,7, 8 | 0,0,1,0,7, 9 | 0,0,0,1,7, 10 | 21,21,21,21,1 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-with-external-tileset/tileset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcronqvist/DotTiled/7f78a971f981e64a96a9d74f60d3af21c1d216ff/src/DotTiled.Tests/TestData/Maps/map-with-external-tileset/tileset.png -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-with-external-tileset/tileset.tsj: -------------------------------------------------------------------------------- 1 | { "columns":8, 2 | "image":"tileset.png", 3 | "imageheight":96, 4 | "imagewidth":256, 5 | "margin":0, 6 | "name":"tileset", 7 | "spacing":0, 8 | "tilecount":24, 9 | "tiledversion":"1.11.0", 10 | "tileheight":32, 11 | "tilewidth":32, 12 | "type":"tileset", 13 | "version":"1.10" 14 | } -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-with-external-tileset/tileset.tsx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-with-flippingflags/map-with-flippingflags.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | 3 | namespace DotTiled.Tests; 4 | 5 | public partial class TestData 6 | { 7 | public static Map MapWithFlippingFlags(string fileExt) => new Map 8 | { 9 | Class = "", 10 | Orientation = MapOrientation.Orthogonal, 11 | Width = 5, 12 | Height = 5, 13 | TileWidth = 32, 14 | TileHeight = 32, 15 | Infinite = false, 16 | ParallaxOriginX = 0, 17 | ParallaxOriginY = 0, 18 | RenderOrder = RenderOrder.RightDown, 19 | CompressionLevel = -1, 20 | BackgroundColor = Color.Parse("#00000000", CultureInfo.InvariantCulture), 21 | Version = "1.10", 22 | TiledVersion = "1.11.0", 23 | NextLayerID = 3, 24 | NextObjectID = 3, 25 | Tilesets = [ 26 | new Tileset 27 | { 28 | Version = "1.10", 29 | TiledVersion = "1.11.0", 30 | FirstGID = 1, 31 | Name = "tileset", 32 | TileWidth = 32, 33 | TileHeight = 32, 34 | TileCount = 24, 35 | Columns = 8, 36 | Source = $"tileset.{(fileExt == "tmx" ? "tsx" : "tsj")}", 37 | Image = new Image 38 | { 39 | Format = ImageFormat.Png, 40 | Source = "tileset.png", 41 | Width = 256, 42 | Height = 96, 43 | } 44 | } 45 | ], 46 | Layers = [ 47 | new TileLayer 48 | { 49 | ID = 1, 50 | Name = "Tile Layer 1", 51 | Width = 5, 52 | Height = 5, 53 | Data = new Data 54 | { 55 | Encoding = DataEncoding.Csv, 56 | GlobalTileIDs = new Optional([ 57 | 1, 1, 0, 0, 7, 58 | 1, 1, 0, 0, 7, 59 | 0, 0, 1, 0, 7, 60 | 0, 0, 0, 1, 7, 61 | 21, 21, 21, 21, 1 62 | ]), 63 | FlippingFlags = new Optional([ 64 | FlippingFlags.None, FlippingFlags.FlippedDiagonally | FlippingFlags.FlippedHorizontally, FlippingFlags.None, FlippingFlags.None, FlippingFlags.FlippedVertically, 65 | FlippingFlags.FlippedDiagonally | FlippingFlags.FlippedVertically, FlippingFlags.FlippedVertically | FlippingFlags.FlippedHorizontally, FlippingFlags.None, FlippingFlags.None, FlippingFlags.FlippedVertically, 66 | FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.FlippedVertically, 67 | FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.FlippedVertically, 68 | FlippingFlags.FlippedHorizontally, FlippingFlags.FlippedHorizontally, FlippingFlags.FlippedHorizontally, FlippingFlags.FlippedHorizontally, FlippingFlags.None 69 | ]) 70 | } 71 | }, 72 | new ObjectLayer 73 | { 74 | ID = 2, 75 | Name = "Object Layer 1", 76 | Objects = [ 77 | new TileObject 78 | { 79 | ID = 1, 80 | GID = 21, 81 | X = 80.0555f, 82 | Y = 48.3887f, 83 | Width = 32, 84 | Height = 32, 85 | FlippingFlags = FlippingFlags.FlippedHorizontally 86 | }, 87 | new TileObject 88 | { 89 | ID = 2, 90 | GID = 21, 91 | X = 15.833f, 92 | Y = 112.056f, 93 | Width = 32, 94 | Height = 32, 95 | FlippingFlags = FlippingFlags.FlippedHorizontally | FlippingFlags.FlippedVertically 96 | } 97 | ] 98 | } 99 | ] 100 | }; 101 | } 102 | -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-with-flippingflags/map-with-flippingflags.tmj: -------------------------------------------------------------------------------- 1 | { "compressionlevel":-1, 2 | "height":5, 3 | "infinite":false, 4 | "layers":[ 5 | { 6 | "data":[1, 2684354561, 0, 0, 1073741831, 7 | 1610612737, 3221225473, 0, 0, 1073741831, 8 | 0, 0, 1, 0, 1073741831, 9 | 0, 0, 0, 1, 1073741831, 10 | 2147483669, 2147483669, 2147483669, 2147483669, 1], 11 | "height":5, 12 | "id":1, 13 | "name":"Tile Layer 1", 14 | "opacity":1, 15 | "type":"tilelayer", 16 | "visible":true, 17 | "width":5, 18 | "x":0, 19 | "y":0 20 | }, 21 | { 22 | "draworder":"topdown", 23 | "id":2, 24 | "name":"Object Layer 1", 25 | "objects":[ 26 | { 27 | "gid":2147483669, 28 | "height":32, 29 | "id":1, 30 | "name":"", 31 | "rotation":0, 32 | "type":"", 33 | "visible":true, 34 | "width":32, 35 | "x":80.0555234239445, 36 | "y":48.3886639676113 37 | }, 38 | { 39 | "gid":1073741845, 40 | "height":32, 41 | "id":2, 42 | "name":"", 43 | "rotation":0, 44 | "type":"", 45 | "visible":true, 46 | "width":32, 47 | "x":15.8334297281666, 48 | "y":112.055523423944 49 | }], 50 | "opacity":1, 51 | "type":"objectgroup", 52 | "visible":true, 53 | "x":0, 54 | "y":0 55 | }], 56 | "nextlayerid":3, 57 | "nextobjectid":3, 58 | "orientation":"orthogonal", 59 | "renderorder":"right-down", 60 | "tiledversion":"1.11.0", 61 | "tileheight":32, 62 | "tilesets":[ 63 | { 64 | "firstgid":1, 65 | "source":"tileset.tsj" 66 | }], 67 | "tilewidth":32, 68 | "type":"map", 69 | "version":"1.10", 70 | "width":5 71 | } -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-with-flippingflags/map-with-flippingflags.tmx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 1,2684354561,0,0,1073741831, 7 | 1610612737,3221225473,0,0,1073741831, 8 | 0,0,1,0,1073741831, 9 | 0,0,0,1,1073741831, 10 | 2147483669,2147483669,2147483669,2147483669,1 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-with-flippingflags/tileset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcronqvist/DotTiled/7f78a971f981e64a96a9d74f60d3af21c1d216ff/src/DotTiled.Tests/TestData/Maps/map-with-flippingflags/tileset.png -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-with-flippingflags/tileset.tsj: -------------------------------------------------------------------------------- 1 | { "columns":8, 2 | "image":"tileset.png", 3 | "imageheight":96, 4 | "imagewidth":256, 5 | "margin":0, 6 | "name":"tileset", 7 | "spacing":0, 8 | "tilecount":24, 9 | "tiledversion":"1.11.0", 10 | "tileheight":32, 11 | "tilewidth":32, 12 | "type":"tileset", 13 | "version":"1.10" 14 | } -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-with-flippingflags/tileset.tsx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-with-many-layers/map-with-many-layers.tmx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 0,0,0,0,0, 20 | 0,0,0,0,0, 21 | 0,0,0,0,0, 22 | 0,0,0,0,0, 23 | 0,0,0,0,0 24 | 25 | 26 | 27 | 28 | 0,15,15,0,0, 29 | 0,15,15,0,0, 30 | 0,15,15,15,0, 31 | 15,15,15,0,0, 32 | 0,0,0,0,0 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 1,1,1,1,1, 42 | 0,0,0,0,0, 43 | 0,0,0,0,0, 44 | 0,0,0,0,0, 45 | 0,0,0,0,0 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-with-many-layers/poly.tj: -------------------------------------------------------------------------------- 1 | { "object": 2 | { 3 | "height":0, 4 | "id":5, 5 | "name":"Poly", 6 | "polygon":[ 7 | { 8 | "x":0, 9 | "y":0 10 | }, 11 | { 12 | "x":104, 13 | "y":20 14 | }, 15 | { 16 | "x":35.6667, 17 | "y":32.3333 18 | }], 19 | "properties":[ 20 | { 21 | "name":"templateprop", 22 | "type":"string", 23 | "value":"helo there" 24 | }], 25 | "rotation":0, 26 | "type":"", 27 | "visible":true, 28 | "width":0 29 | }, 30 | "type":"template" 31 | } -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-with-many-layers/poly.tx: -------------------------------------------------------------------------------- 1 | 2 | 10 | -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-with-many-layers/tileset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcronqvist/DotTiled/7f78a971f981e64a96a9d74f60d3af21c1d216ff/src/DotTiled.Tests/TestData/Maps/map-with-many-layers/tileset.png -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-with-many-layers/tileset.tsj: -------------------------------------------------------------------------------- 1 | { "columns":8, 2 | "image":"tileset.png", 3 | "imageheight":96, 4 | "imagewidth":256, 5 | "margin":0, 6 | "name":"tileset", 7 | "spacing":0, 8 | "tilecount":24, 9 | "tiledversion":"1.11.0", 10 | "tileheight":32, 11 | "tilewidth":32, 12 | "type":"tileset", 13 | "version":"1.10" 14 | } -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-with-many-layers/tileset.tsx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-with-multiline-string-prop/map-with-multiline-string-prop.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | 3 | namespace DotTiled.Tests; 4 | 5 | public partial class TestData 6 | { 7 | public static Map MapWithMultilineStringProp() => new Map 8 | { 9 | Class = "", 10 | Orientation = MapOrientation.Isometric, 11 | Width = 5, 12 | Height = 5, 13 | TileWidth = 32, 14 | TileHeight = 16, 15 | Infinite = false, 16 | ParallaxOriginX = 0, 17 | ParallaxOriginY = 0, 18 | RenderOrder = RenderOrder.RightDown, 19 | CompressionLevel = -1, 20 | BackgroundColor = Color.Parse("#00ff00", CultureInfo.InvariantCulture), 21 | Version = "1.10", 22 | TiledVersion = "1.11.0", 23 | NextLayerID = 2, 24 | NextObjectID = 1, 25 | Layers = [ 26 | new TileLayer 27 | { 28 | ID = 1, 29 | Name = "Tile Layer 1", 30 | Width = 5, 31 | Height = 5, 32 | Data = new Data 33 | { 34 | Encoding = DataEncoding.Csv, 35 | GlobalTileIDs = new Optional([ 36 | 0, 0, 0, 0, 0, 37 | 0, 0, 0, 0, 0, 38 | 0, 0, 0, 0, 0, 39 | 0, 0, 0, 0, 0, 40 | 0, 0, 0, 0, 0 41 | ]), 42 | FlippingFlags = new Optional([ 43 | FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, 44 | FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, 45 | FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, 46 | FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, 47 | FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None 48 | ]) 49 | } 50 | } 51 | ], 52 | Properties = 53 | [ 54 | new BoolProperty { Name = "boolprop", Value = true }, 55 | new ColorProperty { Name = "colorprop", Value = Color.Parse("#ff55ffff", CultureInfo.InvariantCulture) }, 56 | new FileProperty { Name = "fileprop", Value = "file.txt" }, 57 | new FloatProperty { Name = "floatprop", Value = 4.2f }, 58 | new IntProperty { Name = "intprop", Value = 8 }, 59 | new ObjectProperty { Name = "objectprop", Value = 5 }, 60 | new StringProperty { Name = "stringmultiline", Value = "hello there\n\ni am a multiline\nstring property" }, 61 | new StringProperty { Name = "stringprop", Value = "This is a string, hello world!" }, 62 | new StringProperty { Name = "unsetstringprop", Value = "" } 63 | ] 64 | }; 65 | } 66 | -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-with-multiline-string-prop/map-with-multiline-string-prop.tmj: -------------------------------------------------------------------------------- 1 | { "backgroundcolor":"#00ff00", 2 | "compressionlevel":-1, 3 | "height":5, 4 | "infinite":false, 5 | "layers":[ 6 | { 7 | "data":[0, 0, 0, 0, 0, 8 | 0, 0, 0, 0, 0, 9 | 0, 0, 0, 0, 0, 10 | 0, 0, 0, 0, 0, 11 | 0, 0, 0, 0, 0], 12 | "height":5, 13 | "id":1, 14 | "name":"Tile Layer 1", 15 | "opacity":1, 16 | "type":"tilelayer", 17 | "visible":true, 18 | "width":5, 19 | "x":0, 20 | "y":0 21 | }], 22 | "nextlayerid":2, 23 | "nextobjectid":1, 24 | "orientation":"isometric", 25 | "properties":[ 26 | { 27 | "name":"boolprop", 28 | "type":"bool", 29 | "value":true 30 | }, 31 | { 32 | "name":"colorprop", 33 | "type":"color", 34 | "value":"#ff55ffff" 35 | }, 36 | { 37 | "name":"fileprop", 38 | "type":"file", 39 | "value":"file.txt" 40 | }, 41 | { 42 | "name":"floatprop", 43 | "type":"float", 44 | "value":4.2 45 | }, 46 | { 47 | "name":"intprop", 48 | "type":"int", 49 | "value":8 50 | }, 51 | 52 | { 53 | "name":"objectprop", 54 | "type":"object", 55 | "value":5 56 | }, 57 | { 58 | "name":"stringmultiline", 59 | "type":"string", 60 | "value":"hello there\n\ni am a multiline\nstring property" 61 | }, 62 | { 63 | "name":"stringprop", 64 | "type":"string", 65 | "value":"This is a string, hello world!" 66 | }, 67 | { 68 | "name":"unsetstringprop", 69 | "type":"string", 70 | "value":"" 71 | }], 72 | "renderorder":"right-down", 73 | "tiledversion":"1.11.0", 74 | "tileheight":16, 75 | "tilesets":[], 76 | "tilewidth":32, 77 | "type":"map", 78 | "version":"1.10", 79 | "width":5 80 | } -------------------------------------------------------------------------------- /src/DotTiled.Tests/TestData/Maps/map-with-multiline-string-prop/map-with-multiline-string-prop.tmx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | hello there 11 | 12 | i am a multiline 13 | string property 14 | 15 | 16 | 17 | 18 | 19 | 0,0,0,0,0, 20 | 0,0,0,0,0, 21 | 0,0,0,0,0, 22 | 0,0,0,0,0, 23 | 0,0,0,0,0 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/DotTiled.Tests/UnitTests/Properties/CustomTypes/CustomEnumDefinitionTests.cs: -------------------------------------------------------------------------------- 1 | namespace DotTiled.Tests; 2 | 3 | public class CustomEnumDefinitionTests 4 | { 5 | [Fact] 6 | public void FromEnum_Type_WhenTypeIsNotEnum_ThrowsArgumentException() 7 | { 8 | // Arrange 9 | var type = typeof(string); 10 | 11 | // Act & Assert 12 | Assert.Throws(() => CustomEnumDefinition.FromEnum(type)); 13 | } 14 | 15 | private enum TestEnum1 { Value1, Value2, Value3 } 16 | 17 | [Theory] 18 | [InlineData(CustomEnumStorageType.String)] 19 | [InlineData(CustomEnumStorageType.Int)] 20 | public void FromEnum_Type_WhenTypeIsEnum_ReturnsCustomEnumDefinition(CustomEnumStorageType storageType) 21 | { 22 | // Arrange 23 | var type = typeof(TestEnum1); 24 | var expected = new CustomEnumDefinition 25 | { 26 | ID = 0, 27 | Name = "TestEnum1", 28 | StorageType = storageType, 29 | Values = ["Value1", "Value2", "Value3"], 30 | ValueAsFlags = false 31 | }; 32 | 33 | // Act 34 | var result = CustomEnumDefinition.FromEnum(type, storageType); 35 | 36 | // Assert 37 | DotTiledAssert.AssertCustomEnumDefinitionEqual(expected, result); 38 | } 39 | 40 | [Flags] 41 | private enum TestEnum2 { Value1, Value2, Value3 } 42 | 43 | [Theory] 44 | [InlineData(CustomEnumStorageType.String)] 45 | [InlineData(CustomEnumStorageType.Int)] 46 | public void FromEnum_Type_WhenEnumIsFlags_ReturnsCustomEnumDefinition(CustomEnumStorageType storageType) 47 | { 48 | // Arrange 49 | var type = typeof(TestEnum2); 50 | var expected = new CustomEnumDefinition 51 | { 52 | ID = 0, 53 | Name = "TestEnum2", 54 | StorageType = storageType, 55 | Values = ["Value1", "Value2", "Value3"], 56 | ValueAsFlags = true 57 | }; 58 | 59 | // Act 60 | var result = CustomEnumDefinition.FromEnum(type, storageType); 61 | 62 | // Assert 63 | DotTiledAssert.AssertCustomEnumDefinitionEqual(expected, result); 64 | } 65 | 66 | [Theory] 67 | [InlineData(CustomEnumStorageType.String)] 68 | [InlineData(CustomEnumStorageType.Int)] 69 | public void FromEnum_T_WhenTypeIsEnum_ReturnsCustomEnumDefinition(CustomEnumStorageType storageType) 70 | { 71 | // Arrange 72 | var expected = new CustomEnumDefinition 73 | { 74 | ID = 0, 75 | Name = "TestEnum1", 76 | StorageType = storageType, 77 | Values = ["Value1", "Value2", "Value3"], 78 | ValueAsFlags = false 79 | }; 80 | 81 | // Act 82 | var result = CustomEnumDefinition.FromEnum(storageType); 83 | 84 | // Assert 85 | DotTiledAssert.AssertCustomEnumDefinitionEqual(expected, result); 86 | } 87 | 88 | [Theory] 89 | [InlineData(CustomEnumStorageType.String)] 90 | [InlineData(CustomEnumStorageType.Int)] 91 | public void FromEnum_T_WhenEnumIsFlags_ReturnsCustomEnumDefinition(CustomEnumStorageType storageType) 92 | { 93 | // Arrange 94 | var expected = new CustomEnumDefinition 95 | { 96 | ID = 0, 97 | Name = "TestEnum2", 98 | StorageType = storageType, 99 | Values = ["Value1", "Value2", "Value3"], 100 | ValueAsFlags = true 101 | }; 102 | 103 | // Act 104 | var result = CustomEnumDefinition.FromEnum(storageType); 105 | 106 | // Assert 107 | DotTiledAssert.AssertCustomEnumDefinitionEqual(expected, result); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/DotTiled.Tests/UnitTests/Serialization/DefaultResourceCacheTests.cs: -------------------------------------------------------------------------------- 1 | using DotTiled.Serialization; 2 | 3 | namespace DotTiled.Tests; 4 | 5 | public class DefaultResourceCacheTests 6 | { 7 | [Fact] 8 | public void GetTemplate_TemplateDoesNotExist_ReturnsEmptyOptional() 9 | { 10 | // Arrange 11 | var cache = new DefaultResourceCache(); 12 | var path = "template.tsx"; 13 | 14 | // Act 15 | var result = cache.GetTemplate(path); 16 | 17 | // Assert 18 | Assert.False(result.HasValue); 19 | } 20 | 21 | [Fact] 22 | public void GetTemplate_TemplateHasBeenInserted_ReturnsTemplate() 23 | { 24 | // Arrange 25 | var cache = new DefaultResourceCache(); 26 | var path = "template.tsx"; 27 | var template = new Template 28 | { 29 | Object = new EllipseObject { } 30 | }; 31 | 32 | // Act 33 | cache.InsertTemplate(path, template); 34 | var result = cache.GetTemplate(path); 35 | 36 | // Assert 37 | Assert.True(result.HasValue); 38 | Assert.Same(template, result.Value); 39 | } 40 | 41 | [Fact] 42 | public void GetTileset_TilesetDoesNotExist_ReturnsEmptyOptional() 43 | { 44 | // Arrange 45 | var cache = new DefaultResourceCache(); 46 | var path = "tileset.tsx"; 47 | 48 | // Act 49 | var result = cache.GetTileset(path); 50 | 51 | // Assert 52 | Assert.False(result.HasValue); 53 | } 54 | 55 | [Fact] 56 | public void GetTileset_TilesetHasBeenInserted_ReturnsTileset() 57 | { 58 | // Arrange 59 | var cache = new DefaultResourceCache(); 60 | var path = "tileset.tsx"; 61 | var tileset = new Tileset 62 | { 63 | Name = "Tileset", 64 | TileWidth = 32, 65 | TileHeight = 32, 66 | TileCount = 1, 67 | Columns = 1 68 | }; 69 | 70 | // Act 71 | cache.InsertTileset(path, tileset); 72 | var result = cache.GetTileset(path); 73 | 74 | // Assert 75 | Assert.True(result.HasValue); 76 | Assert.Same(tileset, result.Value); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/DotTiled.Tests/UnitTests/Serialization/MapReaderTests.cs: -------------------------------------------------------------------------------- 1 | using DotTiled.Serialization; 2 | 3 | namespace DotTiled.Tests; 4 | 5 | public partial class MapReaderTests 6 | { 7 | public static IEnumerable Maps => TestData.MapTests; 8 | [Theory] 9 | [MemberData(nameof(Maps))] 10 | public void MapReaderReadMap_ValidFilesExternalTilesetsAndTemplates_ReturnsMapThatEqualsExpected( 11 | string testDataFile, 12 | Func expectedMap, 13 | IReadOnlyCollection customTypeDefinitions) 14 | { 15 | // Arrange 16 | string[] fileFormats = [".tmx", ".tmj"]; 17 | 18 | foreach (var fileFormat in fileFormats) 19 | { 20 | var testDataFileWithFormat = testDataFile + fileFormat; 21 | var fileDir = Path.GetDirectoryName(testDataFileWithFormat); 22 | var mapString = TestData.GetRawStringFor(testDataFileWithFormat); 23 | Template ResolveTemplate(string source) 24 | { 25 | var templateString = TestData.GetRawStringFor($"{fileDir}/{source}"); 26 | using var templateReader = new TemplateReader(templateString, ResolveTileset, ResolveTemplate, ResolveCustomType); 27 | return templateReader.ReadTemplate(); 28 | } 29 | Tileset ResolveTileset(string source) 30 | { 31 | var tilesetString = TestData.GetRawStringFor($"{fileDir}/{source}"); 32 | using var tilesetReader = new TilesetReader(tilesetString, ResolveTileset, ResolveTemplate, ResolveCustomType); 33 | return tilesetReader.ReadTileset(); 34 | } 35 | Optional ResolveCustomType(string name) 36 | { 37 | if (customTypeDefinitions.FirstOrDefault(ctd => ctd.Name == name) is ICustomTypeDefinition ctd) 38 | { 39 | return new Optional(ctd); 40 | } 41 | 42 | return Optional.Empty; 43 | } 44 | using var mapReader = new MapReader(mapString, ResolveTileset, ResolveTemplate, ResolveCustomType); 45 | 46 | // Act 47 | var map = mapReader.ReadMap(); 48 | 49 | // Assert 50 | Assert.NotNull(map); 51 | DotTiledAssert.AssertMap(expectedMap(fileFormat[1..]), map); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/DotTiled.Tests/UnitTests/Serialization/TestData.cs: -------------------------------------------------------------------------------- 1 | using System.Xml; 2 | 3 | namespace DotTiled.Tests; 4 | 5 | public static partial class TestData 6 | { 7 | public static XmlReader GetXmlReaderFor(string testDataFile) 8 | { 9 | var fullyQualifiedTestDataFile = $"DotTiled.Tests.{ConvertPathToAssemblyResourcePath(testDataFile)}"; 10 | using var stream = typeof(TestData).Assembly.GetManifestResourceStream(fullyQualifiedTestDataFile) 11 | ?? throw new ArgumentException($"Test data file '{fullyQualifiedTestDataFile}' not found"); 12 | 13 | using var stringReader = new StreamReader(stream); 14 | var xml = stringReader.ReadToEnd(); 15 | var xmlStringReader = new StringReader(xml); 16 | return XmlReader.Create(xmlStringReader); 17 | } 18 | 19 | public static string GetRawStringFor(string testDataFile) 20 | { 21 | var fullyQualifiedTestDataFile = $"DotTiled.Tests.{ConvertPathToAssemblyResourcePath(testDataFile)}"; 22 | using var stream = typeof(TestData).Assembly.GetManifestResourceStream(fullyQualifiedTestDataFile) 23 | ?? throw new ArgumentException($"Test data file '{fullyQualifiedTestDataFile}' not found"); 24 | 25 | using var stringReader = new StreamReader(stream); 26 | return stringReader.ReadToEnd(); 27 | } 28 | 29 | private static string ConvertPathToAssemblyResourcePath(string path) => 30 | path.Replace("/", ".").Replace("\\", ".").Replace(" ", "_"); 31 | 32 | private static string GetMapPath(string mapName) => $"TestData/Maps/{mapName.Replace('-', '_')}/{mapName}"; 33 | 34 | public static IEnumerable MapTests => 35 | [ 36 | [GetMapPath("default-map"), (string f) => DefaultMap(), Array.Empty()], 37 | [GetMapPath("map-with-common-props"), (string f) => MapWithCommonProps(), Array.Empty()], 38 | [GetMapPath("map-with-custom-type-props"), (string f) => MapWithCustomTypeProps(), MapWithCustomTypePropsCustomTypeDefinitions()], 39 | [GetMapPath("map-with-custom-type-props-without-defs"), (string f) => MapWithCustomTypePropsWithoutDefs(), Array.Empty()], 40 | [GetMapPath("map-with-embedded-tileset"), (string f) => MapWithEmbeddedTileset(), Array.Empty()], 41 | [GetMapPath("map-with-external-tileset"), (string f) => MapWithExternalTileset(f), Array.Empty()], 42 | [GetMapPath("map-with-flippingflags"), (string f) => MapWithFlippingFlags(f), Array.Empty()], 43 | [GetMapPath("map-external-tileset-multi"), (string f) => MapExternalTilesetMulti(f), Array.Empty()], 44 | [GetMapPath("map-external-tileset-wangset"), (string f) => MapExternalTilesetWangset(f), Array.Empty()], 45 | [GetMapPath("map-with-many-layers"), (string f) => MapWithManyLayers(f), Array.Empty()], 46 | [GetMapPath("map-with-multiline-string-prop"), (string f) => MapWithMultilineStringProp(), Array.Empty()], 47 | [GetMapPath("map-with-deep-props"), (string f) => MapWithDeepProps(), MapWithDeepPropsCustomTypeDefinitions()], 48 | [GetMapPath("map-with-class"), (string f) => MapWithClass(), MapWithClassCustomTypeDefinitions()], 49 | [GetMapPath("map-with-class-and-props"), (string f) => MapWithClassAndProps(), MapWithClassAndPropsCustomTypeDefinitions()], 50 | [GetMapPath("map-override-object-bug"), (string f) => MapOverrideObjectBug(f), MapOverrideObjectBugCustomTypeDefinitions()], 51 | ]; 52 | } 53 | -------------------------------------------------------------------------------- /src/DotTiled.Tests/UnitTests/Serialization/Tmj/TmjMapReaderTests.cs: -------------------------------------------------------------------------------- 1 | using DotTiled.Serialization.Tmj; 2 | 3 | namespace DotTiled.Tests; 4 | 5 | public partial class TmjMapReaderTests 6 | { 7 | public static IEnumerable Maps => TestData.MapTests; 8 | [Theory] 9 | [MemberData(nameof(Maps))] 10 | public void TmxMapReaderReadMap_ValidTmjExternalTilesetsAndTemplates_ReturnsMapThatEqualsExpected( 11 | string testDataFile, 12 | Func expectedMap, 13 | IReadOnlyCollection customTypeDefinitions) 14 | { 15 | // Arrange 16 | testDataFile += ".tmj"; 17 | var fileDir = Path.GetDirectoryName(testDataFile); 18 | var json = TestData.GetRawStringFor(testDataFile); 19 | Template ResolveTemplate(string source) 20 | { 21 | var templateJson = TestData.GetRawStringFor($"{fileDir}/{source}"); 22 | using var templateReader = new TjTemplateReader(templateJson, ResolveTileset, ResolveTemplate, ResolveCustomType); 23 | return templateReader.ReadTemplate(); 24 | } 25 | Tileset ResolveTileset(string source) 26 | { 27 | var tilesetJson = TestData.GetRawStringFor($"{fileDir}/{source}"); 28 | using var tilesetReader = new TsjTilesetReader(tilesetJson, ResolveTileset, ResolveTemplate, ResolveCustomType); 29 | return tilesetReader.ReadTileset(); 30 | } 31 | Optional ResolveCustomType(string name) 32 | { 33 | if (customTypeDefinitions.FirstOrDefault(ctd => ctd.Name == name) is ICustomTypeDefinition ctd) 34 | { 35 | return new Optional(ctd); 36 | } 37 | 38 | return Optional.Empty; 39 | } 40 | using var mapReader = new TmjMapReader(json, ResolveTileset, ResolveTemplate, ResolveCustomType); 41 | 42 | // Act 43 | var map = mapReader.ReadMap(); 44 | 45 | // Assert 46 | Assert.NotNull(map); 47 | DotTiledAssert.AssertMap(expectedMap("tmj"), map); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/DotTiled.Tests/UnitTests/Serialization/Tmx/TmxMapReaderTests.cs: -------------------------------------------------------------------------------- 1 | using DotTiled.Serialization.Tmx; 2 | 3 | namespace DotTiled.Tests; 4 | 5 | public partial class TmxMapReaderTests 6 | { 7 | public static IEnumerable Maps => TestData.MapTests; 8 | [Theory] 9 | [MemberData(nameof(Maps))] 10 | public void TmxMapReaderReadMap_ValidXmlExternalTilesetsAndTemplates_ReturnsMapThatEqualsExpected( 11 | string testDataFile, 12 | Func expectedMap, 13 | IReadOnlyCollection customTypeDefinitions) 14 | { 15 | // Arrange 16 | testDataFile += ".tmx"; 17 | var fileDir = Path.GetDirectoryName(testDataFile); 18 | using var reader = TestData.GetXmlReaderFor(testDataFile); 19 | Template ResolveTemplate(string source) 20 | { 21 | using var xmlTemplateReader = TestData.GetXmlReaderFor($"{fileDir}/{source}"); 22 | using var templateReader = new TxTemplateReader(xmlTemplateReader, ResolveTileset, ResolveTemplate, ResolveCustomType); 23 | return templateReader.ReadTemplate(); 24 | } 25 | Tileset ResolveTileset(string source) 26 | { 27 | using var xmlTilesetReader = TestData.GetXmlReaderFor($"{fileDir}/{source}"); 28 | using var tilesetReader = new TsxTilesetReader(xmlTilesetReader, ResolveTileset, ResolveTemplate, ResolveCustomType); 29 | return tilesetReader.ReadTileset(); 30 | } 31 | Optional ResolveCustomType(string name) 32 | { 33 | if (customTypeDefinitions.FirstOrDefault(ctd => ctd.Name == name) is ICustomTypeDefinition ctd) 34 | { 35 | return new Optional(ctd); 36 | } 37 | 38 | return Optional.Empty; 39 | } 40 | using var mapReader = new TmxMapReader(reader, ResolveTileset, ResolveTemplate, ResolveCustomType); 41 | 42 | // Act 43 | var map = mapReader.ReadMap(); 44 | 45 | // Assert 46 | Assert.NotNull(map); 47 | DotTiledAssert.AssertMap(expectedMap("tmx"), map); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/DotTiled.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.0.31903.59 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotTiled", "DotTiled\DotTiled.csproj", "{80A60DE7-D6AE-4CC7-825F-75308D83F36D}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotTiled.Tests", "DotTiled.Tests\DotTiled.Tests.csproj", "{C1311A5A-5206-467C-B323-B131CA11FDB8}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotTiled.Benchmark", "DotTiled.Benchmark\DotTiled.Benchmark.csproj", "{510F3077-8EA4-47D1-8D01-E2D538F1B899}" 11 | EndProject 12 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples", "Examples", "{8C54542E-3C2C-486C-9BEF-4C510391AFDA}" 13 | EndProject 14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotTiled.Example.Console", "DotTiled.Examples\DotTiled.Example.Console\DotTiled.Example.Console.csproj", "{F9892295-6C2C-4ABD-9D6F-2AC81D2C6E67}" 15 | EndProject 16 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotTiled.Example.Godot", "DotTiled.Examples\DotTiled.Example.Godot\DotTiled.Example.Godot.csproj", "{7541A9B3-43A5-45A7-939E-6F542319D990}" 17 | EndProject 18 | Global 19 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 20 | Debug|Any CPU = Debug|Any CPU 21 | Release|Any CPU = Release|Any CPU 22 | EndGlobalSection 23 | GlobalSection(SolutionProperties) = preSolution 24 | HideSolutionNode = FALSE 25 | EndGlobalSection 26 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 27 | {80A60DE7-D6AE-4CC7-825F-75308D83F36D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 28 | {80A60DE7-D6AE-4CC7-825F-75308D83F36D}.Debug|Any CPU.Build.0 = Debug|Any CPU 29 | {80A60DE7-D6AE-4CC7-825F-75308D83F36D}.Release|Any CPU.ActiveCfg = Release|Any CPU 30 | {80A60DE7-D6AE-4CC7-825F-75308D83F36D}.Release|Any CPU.Build.0 = Release|Any CPU 31 | {C1311A5A-5206-467C-B323-B131CA11FDB8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 32 | {C1311A5A-5206-467C-B323-B131CA11FDB8}.Debug|Any CPU.Build.0 = Debug|Any CPU 33 | {C1311A5A-5206-467C-B323-B131CA11FDB8}.Release|Any CPU.ActiveCfg = Release|Any CPU 34 | {C1311A5A-5206-467C-B323-B131CA11FDB8}.Release|Any CPU.Build.0 = Release|Any CPU 35 | {510F3077-8EA4-47D1-8D01-E2D538F1B899}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 36 | {510F3077-8EA4-47D1-8D01-E2D538F1B899}.Debug|Any CPU.Build.0 = Debug|Any CPU 37 | {510F3077-8EA4-47D1-8D01-E2D538F1B899}.Release|Any CPU.ActiveCfg = Release|Any CPU 38 | {510F3077-8EA4-47D1-8D01-E2D538F1B899}.Release|Any CPU.Build.0 = Release|Any CPU 39 | {F9892295-6C2C-4ABD-9D6F-2AC81D2C6E67}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 40 | {F9892295-6C2C-4ABD-9D6F-2AC81D2C6E67}.Debug|Any CPU.Build.0 = Debug|Any CPU 41 | {F9892295-6C2C-4ABD-9D6F-2AC81D2C6E67}.Release|Any CPU.ActiveCfg = Release|Any CPU 42 | {F9892295-6C2C-4ABD-9D6F-2AC81D2C6E67}.Release|Any CPU.Build.0 = Release|Any CPU 43 | {7541A9B3-43A5-45A7-939E-6F542319D990}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 44 | {7541A9B3-43A5-45A7-939E-6F542319D990}.Debug|Any CPU.Build.0 = Debug|Any CPU 45 | {7541A9B3-43A5-45A7-939E-6F542319D990}.Release|Any CPU.ActiveCfg = Debug|Any CPU 46 | {7541A9B3-43A5-45A7-939E-6F542319D990}.Release|Any CPU.Build.0 = Debug|Any CPU 47 | EndGlobalSection 48 | GlobalSection(NestedProjects) = preSolution 49 | {F9892295-6C2C-4ABD-9D6F-2AC81D2C6E67} = {8C54542E-3C2C-486C-9BEF-4C510391AFDA} 50 | {7541A9B3-43A5-45A7-939E-6F542319D990} = {8C54542E-3C2C-486C-9BEF-4C510391AFDA} 51 | EndGlobalSection 52 | EndGlobal 53 | -------------------------------------------------------------------------------- /src/DotTiled/DotTiled.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | true 6 | 7 | 8 | 9 | DotTiled 10 | dcronqvist 11 | DotTiled 12 | DotTiled is a general-purpose Tiled map parser for all your .NET needs. 13 | git 14 | https://github.com/dcronqvist/DotTiled 15 | README.md 16 | gamedev;parser;tiled;mapeditor;tmx;tsx;maps 17 | https://github.com/dcronqvist/DotTiled 18 | true 19 | Copyright © 2024 dcronqvist 20 | LICENSE 21 | 0.3.0 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/DotTiled/Layers/BaseLayer.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace DotTiled; 4 | 5 | /// 6 | /// Base class for all layer types in a map. 7 | /// To check the type of a layer, use C# pattern matching, 8 | /// or some other mechanism to determine the type of the layer at runtime. 9 | /// 10 | public abstract class BaseLayer : HasPropertiesBase 11 | { 12 | /// 13 | /// Unique ID of the layer. Each layer that is added to a map gets a unique ID. Even if a layer is deleted, no layer ever gets the same ID. 14 | /// 15 | public required uint ID { get; set; } 16 | 17 | /// 18 | /// The name of the layer. 19 | /// 20 | public string Name { get; set; } = ""; 21 | 22 | /// 23 | /// The class of the layer. 24 | /// 25 | public string Class { get; set; } = ""; 26 | 27 | /// 28 | /// The opacity of the layer as a value from 0 (fully transparent) to 1 (fully opaque). 29 | /// 30 | public float Opacity { get; set; } = 1.0f; 31 | 32 | /// 33 | /// Whether the layer is shown (true) or hidden (false). 34 | /// 35 | public bool Visible { get; set; } = true; 36 | 37 | /// 38 | /// A tint color that is multiplied with any tiles drawn by this layer. 39 | /// 40 | public Optional TintColor { get; set; } = Optional.Empty; 41 | 42 | /// 43 | /// Horizontal offset for this layer in pixels. 44 | /// 45 | public float OffsetX { get; set; } = 0.0f; 46 | 47 | /// 48 | /// Vertical offset for this layer in pixels. 49 | /// 50 | public float OffsetY { get; set; } = 0.0f; 51 | 52 | /// 53 | /// Horizontal parallax factor for this layer. 54 | /// 55 | public float ParallaxX { get; set; } = 1.0f; 56 | 57 | /// 58 | /// Vertical parallax factor for this layer. 59 | /// 60 | public float ParallaxY { get; set; } = 1.0f; 61 | 62 | /// 63 | /// Layer properties. 64 | /// 65 | public List Properties { get; set; } = []; 66 | 67 | /// 68 | public override IList GetProperties() => Properties; 69 | } 70 | -------------------------------------------------------------------------------- /src/DotTiled/Layers/Group.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace DotTiled; 4 | 5 | /// 6 | /// Represents a group of layers, to form a hierarchy. 7 | /// 8 | public class Group : BaseLayer 9 | { 10 | /// 11 | /// The contained sub-layers in the group. 12 | /// 13 | public List Layers { get; set; } = []; 14 | } 15 | -------------------------------------------------------------------------------- /src/DotTiled/Layers/ImageLayer.cs: -------------------------------------------------------------------------------- 1 | namespace DotTiled; 2 | 3 | /// 4 | /// Represents an image layer in a map. 5 | /// 6 | public class ImageLayer : BaseLayer 7 | { 8 | /// 9 | /// The X position of the image layer in pixels. 10 | /// 11 | public uint X { get; set; } = 0; 12 | 13 | /// 14 | /// The Y position of the image layer in pixels. 15 | /// 16 | public Optional Y { get; set; } = 0; 17 | 18 | /// 19 | /// Whether the image drawn by this layer is repeated along the X axis. 20 | /// 21 | public Optional RepeatX { get; set; } = false; 22 | 23 | /// 24 | /// Whether the image drawn by this layer is repeated along the Y axis. 25 | /// 26 | public Optional RepeatY { get; set; } = false; 27 | 28 | /// 29 | /// The image to be drawn by this image layer. 30 | /// 31 | public Optional Image { get; set; } 32 | } 33 | -------------------------------------------------------------------------------- /src/DotTiled/Layers/ObjectLayer.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace DotTiled; 4 | 5 | /// 6 | /// Represents the order in which objects can be drawn. 7 | /// 8 | public enum DrawOrder 9 | { 10 | /// 11 | /// Objects are drawn sorted by their Y coordinate. 12 | /// 13 | TopDown, 14 | 15 | /// 16 | /// Objects are drawn in the order of appearance in the object layer. 17 | /// 18 | Index 19 | } 20 | 21 | /// 22 | /// Represents an object layer in a map. In Tiled documentation, it is often called an "object group". 23 | /// 24 | public class ObjectLayer : BaseLayer 25 | { 26 | /// 27 | /// The X coordinate of the object layer in tiles. 28 | /// 29 | public uint X { get; set; } = 0; 30 | 31 | /// 32 | /// The Y coordinate of the object layer in tiles. 33 | /// 34 | public uint Y { get; set; } = 0; 35 | 36 | /// 37 | /// The width of the object layer in tiles. Meaningless. 38 | /// 39 | public uint Width { get; set; } = 0; 40 | 41 | /// 42 | /// The height of the object layer in tiles. Meaningless. 43 | /// 44 | public uint Height { get; set; } = 0; 45 | 46 | /// 47 | /// A color that is multiplied with any tile objects drawn by this layer. 48 | /// 49 | public Optional Color { get; set; } = Optional.Empty; 50 | 51 | /// 52 | /// Whether the objects are drawn according to the order of appearance () or sorted by their Y coordinate (). 53 | /// 54 | public DrawOrder DrawOrder { get; set; } = DrawOrder.TopDown; 55 | 56 | /// 57 | /// The objects in the object layer. 58 | /// 59 | public required List Objects { get; set; } 60 | } 61 | -------------------------------------------------------------------------------- /src/DotTiled/Layers/Objects/EllipseObject.cs: -------------------------------------------------------------------------------- 1 | namespace DotTiled; 2 | 3 | /// 4 | /// An ellipse object in a map. The existing , , , 5 | /// and properties are used to determine the size of the ellipse. 6 | /// 7 | public class EllipseObject : Object { } 8 | -------------------------------------------------------------------------------- /src/DotTiled/Layers/Objects/Object.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace DotTiled; 4 | 5 | /// 6 | /// Base class for objects in object layers. 7 | /// 8 | public abstract class Object : HasPropertiesBase 9 | { 10 | /// 11 | /// Unique ID of the objects. Each object that is placed on a map gets a unique ID. Even if an object was deleted, no object gets the same ID. 12 | /// 13 | public Optional ID { get; set; } = Optional.Empty; 14 | 15 | /// 16 | /// The name of the object. An arbitrary string. 17 | /// 18 | public string Name { get; set; } = ""; 19 | 20 | /// 21 | /// The class of the object. An arbitrary string. 22 | /// 23 | public string Type { get; set; } = ""; 24 | 25 | /// 26 | /// The X coordinate of the object in pixels. 27 | /// 28 | public float X { get; set; } = 0f; 29 | 30 | /// 31 | /// The Y coordinate of the object in pixels. 32 | /// 33 | public float Y { get; set; } = 0f; 34 | 35 | /// 36 | /// The width of the object in pixels. 37 | /// 38 | public float Width { get; set; } = 0f; 39 | 40 | /// 41 | /// The height of the object in pixels. 42 | /// 43 | public float Height { get; set; } = 0f; 44 | 45 | /// 46 | /// The rotation of the object in degrees clockwise around (X, Y). 47 | /// 48 | public float Rotation { get; set; } = 0f; 49 | 50 | /// 51 | /// Whether the object is shown (true) or hidden (false). 52 | /// 53 | public bool Visible { get; set; } = true; 54 | 55 | /// 56 | /// A reference to a template file. 57 | /// 58 | public Optional Template { get; set; } = Optional.Empty; 59 | 60 | /// 61 | /// Object properties. 62 | /// 63 | public List Properties { get; set; } = []; 64 | 65 | /// 66 | public override IList GetProperties() => Properties; 67 | } 68 | -------------------------------------------------------------------------------- /src/DotTiled/Layers/Objects/PointObject.cs: -------------------------------------------------------------------------------- 1 | namespace DotTiled; 2 | 3 | /// 4 | /// A point object in a map. The existing and properties are used to 5 | /// determine the position of the point. 6 | /// 7 | public class PointObject : Object { } 8 | -------------------------------------------------------------------------------- /src/DotTiled/Layers/Objects/PolygonObject.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Numerics; 3 | 4 | namespace DotTiled; 5 | 6 | /// 7 | /// A polygon object in a map. The existing and properties are used as 8 | /// the origin of the polygon. 9 | /// 10 | public class PolygonObject : Object 11 | { 12 | /// 13 | /// The points that make up the polygon. 14 | /// and are used as the origin of the polygon. 15 | /// 16 | public required List Points { get; set; } 17 | } 18 | -------------------------------------------------------------------------------- /src/DotTiled/Layers/Objects/PolylineObject.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Numerics; 3 | 4 | namespace DotTiled; 5 | 6 | /// 7 | /// A polyline object in a map. The existing and properties are used as 8 | /// the origin of the polyline. 9 | /// 10 | public class PolylineObject : Object 11 | { 12 | /// 13 | /// The points that make up the polyline. and are used as the origin of the polyline. 14 | /// 15 | public required List Points { get; set; } 16 | } 17 | -------------------------------------------------------------------------------- /src/DotTiled/Layers/Objects/RectangleObject.cs: -------------------------------------------------------------------------------- 1 | namespace DotTiled; 2 | 3 | /// 4 | /// A rectangle object in a map. The existing , , , 5 | /// and properties are used to determine the size of the rectangle. 6 | /// 7 | public class RectangleObject : Object { } 8 | -------------------------------------------------------------------------------- /src/DotTiled/Layers/Objects/TextObject.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | 3 | namespace DotTiled; 4 | 5 | /// 6 | /// The horizontal alignment of text. 7 | /// 8 | public enum TextHorizontalAlignment 9 | { 10 | /// 11 | /// The text is aligned to the left. 12 | /// 13 | Left, 14 | 15 | /// 16 | /// The text is aligned to the center. 17 | /// 18 | Center, 19 | 20 | /// 21 | /// The text is aligned to the right. 22 | /// 23 | Right, 24 | 25 | /// 26 | /// The text is justified. 27 | /// 28 | Justify 29 | } 30 | 31 | /// 32 | /// The vertical alignment of text. 33 | /// 34 | public enum TextVerticalAlignment 35 | { 36 | /// 37 | /// The text is aligned to the top. 38 | /// 39 | Top, 40 | 41 | /// 42 | /// The text is aligned to the center. 43 | /// 44 | Center, 45 | 46 | /// 47 | /// The text is aligned to the bottom. 48 | /// 49 | Bottom 50 | } 51 | 52 | /// 53 | /// A text object in a map. 54 | /// 55 | public class TextObject : Object 56 | { 57 | /// 58 | /// The font family used for the text. 59 | /// 60 | public string FontFamily { get; set; } = "sans-serif"; 61 | 62 | /// 63 | /// The size of the font in pixels. 64 | /// 65 | public int PixelSize { get; set; } = 16; 66 | 67 | /// 68 | /// Whether word wrapping is enabled. 69 | /// 70 | public bool Wrap { get; set; } = false; 71 | 72 | /// 73 | /// The color of the text. 74 | /// 75 | public Color Color { get; set; } = Color.Parse("#000000", CultureInfo.InvariantCulture); 76 | 77 | /// 78 | /// Whether the text is bold. 79 | /// 80 | public bool Bold { get; set; } = false; 81 | 82 | /// 83 | /// Whether the text is italic. 84 | /// 85 | public bool Italic { get; set; } = false; 86 | 87 | /// 88 | /// Whether a line should be drawn below the text. 89 | /// 90 | public bool Underline { get; set; } = false; 91 | 92 | /// 93 | /// Whether a line should be drawn through the text. 94 | /// 95 | public bool Strikeout { get; set; } = false; 96 | 97 | /// 98 | /// Whether kerning should be used while rendering the text. 99 | /// 100 | public bool Kerning { get; set; } = true; 101 | 102 | /// 103 | /// The horizontal alignment of the text. 104 | /// 105 | public TextHorizontalAlignment HorizontalAlignment { get; set; } = TextHorizontalAlignment.Left; 106 | 107 | /// 108 | /// The vertical alignment of the text. 109 | /// 110 | public TextVerticalAlignment VerticalAlignment { get; set; } = TextVerticalAlignment.Top; 111 | 112 | /// 113 | /// The text to be displayed. 114 | /// 115 | public string Text { get; set; } = ""; 116 | } 117 | -------------------------------------------------------------------------------- /src/DotTiled/Layers/Objects/TileObject.cs: -------------------------------------------------------------------------------- 1 | namespace DotTiled; 2 | 3 | /// 4 | /// A tile object in a map. 5 | /// 6 | public class TileObject : Object 7 | { 8 | /// 9 | /// A reference to a tile. 10 | /// 11 | public uint GID { get; set; } 12 | 13 | /// 14 | /// The flipping flags for the tile. 15 | /// 16 | public FlippingFlags FlippingFlags { get; set; } 17 | } 18 | -------------------------------------------------------------------------------- /src/DotTiled/Layers/TileLayer.cs: -------------------------------------------------------------------------------- 1 | namespace DotTiled; 2 | 3 | /// 4 | /// Represents a tile layer in a map. 5 | /// 6 | public class TileLayer : BaseLayer 7 | { 8 | /// 9 | /// The X coordinate of the layer in tiles. 10 | /// 11 | public uint X { get; set; } = 0; 12 | 13 | /// 14 | /// The Y coordinate of the layer in tiles. 15 | /// 16 | public uint Y { get; set; } = 0; 17 | 18 | /// 19 | /// The width of the layer in tiles. Always the same as the map width for fixed-size maps. 20 | /// 21 | public required uint Width { get; set; } 22 | 23 | /// 24 | /// The height of the layer in tiles. Always the same as the map height for fixed-size maps. 25 | /// 26 | public required uint Height { get; set; } 27 | 28 | /// 29 | /// The tile layer data. 30 | /// 31 | public Optional Data { get; set; } = Optional.Empty; 32 | } 33 | -------------------------------------------------------------------------------- /src/DotTiled/Properties/BoolProperty.cs: -------------------------------------------------------------------------------- 1 | namespace DotTiled; 2 | 3 | /// 4 | /// Represents a boolean property. 5 | /// 6 | public class BoolProperty : IProperty 7 | { 8 | /// 9 | public required string Name { get; set; } 10 | 11 | /// 12 | public PropertyType Type => PropertyType.Bool; 13 | 14 | /// 15 | /// The boolean value of the property. 16 | /// 17 | public required bool Value { get; set; } 18 | 19 | /// 20 | public IProperty Clone() => new BoolProperty 21 | { 22 | Name = Name, 23 | Value = Value 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /src/DotTiled/Properties/ClassProperty.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | 4 | namespace DotTiled; 5 | 6 | /// 7 | /// Represents a class property. 8 | /// 9 | public class ClassProperty : HasPropertiesBase, IProperty> 10 | { 11 | /// 12 | public required string Name { get; set; } 13 | 14 | /// 15 | public PropertyType Type => DotTiled.PropertyType.Class; 16 | 17 | /// 18 | /// The type of the class property. This will be the name of a custom defined 19 | /// type in Tiled. 20 | /// 21 | public required string PropertyType { get; set; } 22 | 23 | /// 24 | /// The properties of the class property. 25 | /// 26 | public required IList Value { get; set; } 27 | 28 | /// 29 | public IProperty Clone() => new ClassProperty 30 | { 31 | Name = Name, 32 | PropertyType = PropertyType, 33 | Value = Value.Select(property => property.Clone()).ToList() 34 | }; 35 | 36 | /// 37 | public override IList GetProperties() => Value; 38 | } 39 | -------------------------------------------------------------------------------- /src/DotTiled/Properties/ColorProperty.cs: -------------------------------------------------------------------------------- 1 | namespace DotTiled; 2 | 3 | /// 4 | /// Represents a color property. 5 | /// 6 | public class ColorProperty : IProperty> 7 | { 8 | /// 9 | public required string Name { get; set; } 10 | 11 | /// 12 | public PropertyType Type => PropertyType.Color; 13 | 14 | /// 15 | /// The color value of the property. 16 | /// 17 | public required Optional Value { get; set; } 18 | 19 | /// 20 | public IProperty Clone() => new ColorProperty 21 | { 22 | Name = Name, 23 | Value = Value 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /src/DotTiled/Properties/CustomTypes/CustomEnumDefinition.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace DotTiled; 6 | 7 | /// 8 | /// Represents the storage type of a custom enum. 9 | /// 10 | public enum CustomEnumStorageType 11 | { 12 | /// 13 | /// The backing value is an integer. 14 | /// 15 | Int, 16 | 17 | /// 18 | /// The backing value is a string. 19 | /// 20 | String 21 | } 22 | 23 | /// 24 | /// Represents a custom enum definition in Tiled. Refer to the 25 | /// documentation of custom types to understand how they work. 26 | /// 27 | public class CustomEnumDefinition : ICustomTypeDefinition 28 | { 29 | /// 30 | public uint ID { get; set; } 31 | 32 | /// 33 | public required string Name { get; set; } 34 | 35 | /// 36 | /// The storage type of the custom enum. 37 | /// 38 | public CustomEnumStorageType StorageType { get; set; } 39 | 40 | /// 41 | /// The values of the custom enum. 42 | /// 43 | public List Values { get; set; } = []; 44 | 45 | /// 46 | /// Whether the value should be treated as flags. 47 | /// 48 | public bool ValueAsFlags { get; set; } 49 | 50 | /// 51 | /// Creates a custom enum definition from the specified enum type. 52 | /// 53 | /// 54 | /// The storage type of the custom enum. Defaults to to be consistent with Tiled. 55 | /// 56 | public static CustomEnumDefinition FromEnum(CustomEnumStorageType storageType = CustomEnumStorageType.String) where T : Enum 57 | { 58 | var type = typeof(T); 59 | var isFlags = type.GetCustomAttributes(typeof(FlagsAttribute), false).Length != 0; 60 | 61 | return new CustomEnumDefinition 62 | { 63 | Name = type.Name, 64 | StorageType = storageType, 65 | Values = Enum.GetNames(type).ToList(), 66 | ValueAsFlags = isFlags 67 | }; 68 | } 69 | 70 | /// 71 | /// Creates a custom enum definition from the specified enum type. 72 | /// 73 | /// The enum type to create a custom enum definition from. 74 | /// The storage type of the custom enum. Defaults to to be consistent with Tiled. 75 | /// 76 | public static CustomEnumDefinition FromEnum(Type type, CustomEnumStorageType storageType = CustomEnumStorageType.String) 77 | { 78 | if (!type.IsEnum) 79 | throw new ArgumentException("Type must be an enum.", nameof(type)); 80 | 81 | var isFlags = type.GetCustomAttributes(typeof(FlagsAttribute), false).Length != 0; 82 | 83 | return new CustomEnumDefinition 84 | { 85 | Name = type.Name, 86 | StorageType = storageType, 87 | Values = Enum.GetNames(type).ToList(), 88 | ValueAsFlags = isFlags 89 | }; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/DotTiled/Properties/CustomTypes/CustomTypeDefinition.cs: -------------------------------------------------------------------------------- 1 | namespace DotTiled; 2 | 3 | /// 4 | /// Base class for custom type definitions. 5 | /// 6 | public interface ICustomTypeDefinition 7 | { 8 | /// 9 | /// The ID of the custom type. 10 | /// 11 | public uint ID { get; set; } 12 | 13 | /// 14 | /// The name of the custom type. 15 | /// 16 | public string Name { get; set; } 17 | } 18 | -------------------------------------------------------------------------------- /src/DotTiled/Properties/EnumProperty.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | 4 | namespace DotTiled; 5 | 6 | /// 7 | /// Represents an enum property. 8 | /// 9 | public class EnumProperty : IProperty> 10 | { 11 | /// 12 | public required string Name { get; set; } 13 | 14 | /// 15 | public PropertyType Type => DotTiled.PropertyType.Enum; 16 | 17 | /// 18 | /// The type of the class property. This will be the name of a custom defined 19 | /// type in Tiled. 20 | /// 21 | public required string PropertyType { get; set; } 22 | 23 | /// 24 | /// The value of the enum property. 25 | /// 26 | public required ISet Value { get; set; } 27 | 28 | /// 29 | public IProperty Clone() => new EnumProperty 30 | { 31 | Name = Name, 32 | PropertyType = PropertyType, 33 | Value = Value.ToHashSet() 34 | }; 35 | 36 | /// 37 | /// Determines whether the enum property is equal to the specified value. 38 | /// For enums which have multiple values (e.g. flag enums), this method will only return true if it is the only value. 39 | /// 40 | /// The value to check. 41 | /// True if the enum property is equal to the specified value; otherwise, false. 42 | public bool IsValue(string value) => Value.Contains(value) && Value.Count == 1; 43 | 44 | /// 45 | /// Determines whether the enum property has the specified value. This method is very similar to the common method. 46 | /// 47 | /// The value to check. 48 | /// True if the enum property has the specified value as one of its values; otherwise, false. 49 | public bool HasValue(string value) => Value.Contains(value); 50 | } 51 | -------------------------------------------------------------------------------- /src/DotTiled/Properties/FileProperty.cs: -------------------------------------------------------------------------------- 1 | namespace DotTiled; 2 | 3 | /// 4 | /// Represents a file property. 5 | /// 6 | public class FileProperty : IProperty 7 | { 8 | /// 9 | public required string Name { get; set; } 10 | 11 | /// 12 | public PropertyType Type => PropertyType.File; 13 | 14 | /// 15 | /// The value of the property. 16 | /// 17 | public required string Value { get; set; } 18 | 19 | /// 20 | public IProperty Clone() => new FileProperty 21 | { 22 | Name = Name, 23 | Value = Value 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /src/DotTiled/Properties/FloatProperty.cs: -------------------------------------------------------------------------------- 1 | namespace DotTiled; 2 | 3 | /// 4 | /// Represents a float property. 5 | /// 6 | public class FloatProperty : IProperty 7 | { 8 | /// 9 | public required string Name { get; set; } 10 | 11 | /// 12 | public PropertyType Type => PropertyType.Float; 13 | 14 | /// 15 | /// The float value of the property. 16 | /// 17 | public required float Value { get; set; } 18 | 19 | /// 20 | public IProperty Clone() => new FloatProperty 21 | { 22 | Name = Name, 23 | Value = Value 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /src/DotTiled/Properties/IProperty.cs: -------------------------------------------------------------------------------- 1 | namespace DotTiled; 2 | 3 | /// 4 | /// Interface for properties that can be attached to objects, tiles, tilesets, maps etc. 5 | /// 6 | public interface IProperty 7 | { 8 | /// 9 | /// The name of the property. 10 | /// 11 | public string Name { get; set; } 12 | 13 | /// 14 | /// The type of the property. 15 | /// 16 | public PropertyType Type { get; } 17 | 18 | /// 19 | /// Clones the property, only used for copying properties when performing overriding 20 | /// with templates. 21 | /// 22 | /// An identical, but non-reference-equal, instance of the same property. 23 | IProperty Clone(); 24 | } 25 | 26 | /// 27 | /// Interface for properties that can be attached to objects, tiles, tilesets, maps etc. 28 | /// 29 | /// The type of the property value. 30 | public interface IProperty : IProperty 31 | { 32 | /// 33 | /// The value of the property. 34 | /// 35 | public T Value { get; set; } 36 | } 37 | -------------------------------------------------------------------------------- /src/DotTiled/Properties/IntProperty.cs: -------------------------------------------------------------------------------- 1 | namespace DotTiled; 2 | 3 | /// 4 | /// Represents an integer property. 5 | /// 6 | public class IntProperty : IProperty 7 | { 8 | /// 9 | public required string Name { get; set; } 10 | 11 | /// 12 | public PropertyType Type => PropertyType.Int; 13 | 14 | /// 15 | /// The integer value of the property. 16 | /// 17 | public required int Value { get; set; } 18 | 19 | /// 20 | public IProperty Clone() => new IntProperty 21 | { 22 | Name = Name, 23 | Value = Value 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /src/DotTiled/Properties/ObjectProperty.cs: -------------------------------------------------------------------------------- 1 | namespace DotTiled; 2 | 3 | /// 4 | /// Represents an object property. 5 | /// 6 | public class ObjectProperty : IProperty 7 | { 8 | /// 9 | public required string Name { get; set; } 10 | 11 | /// 12 | public PropertyType Type => PropertyType.Object; 13 | 14 | /// 15 | /// The object identifier referenced by the property. 16 | /// 17 | public required uint Value { get; set; } 18 | 19 | /// 20 | public IProperty Clone() => new ObjectProperty 21 | { 22 | Name = Name, 23 | Value = Value 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /src/DotTiled/Properties/PropertyType.cs: -------------------------------------------------------------------------------- 1 | namespace DotTiled; 2 | 3 | /// 4 | /// Represents the type of a property. 5 | /// 6 | public enum PropertyType 7 | { 8 | /// 9 | /// A string property. 10 | /// 11 | String, 12 | 13 | /// 14 | /// An integer property. 15 | /// 16 | Int, 17 | 18 | /// 19 | /// A float property. 20 | /// 21 | Float, 22 | 23 | /// 24 | /// A boolean property. 25 | /// 26 | Bool, 27 | 28 | /// 29 | /// A color property. 30 | /// 31 | Color, 32 | 33 | /// 34 | /// A file property. 35 | /// 36 | File, 37 | 38 | /// 39 | /// An object property. 40 | /// 41 | Object, 42 | 43 | /// 44 | /// A class property. 45 | /// 46 | Class, 47 | 48 | /// 49 | /// An enum property. 50 | /// 51 | Enum 52 | } 53 | -------------------------------------------------------------------------------- /src/DotTiled/Properties/StringProperty.cs: -------------------------------------------------------------------------------- 1 | namespace DotTiled; 2 | 3 | /// 4 | /// Represents a string property. 5 | /// 6 | public class StringProperty : IProperty 7 | { 8 | /// 9 | public required string Name { get; set; } 10 | 11 | /// 12 | public PropertyType Type => PropertyType.String; 13 | 14 | /// 15 | /// The string value of the property. 16 | /// 17 | public required string Value { get; set; } 18 | 19 | /// 20 | public IProperty Clone() => new StringProperty 21 | { 22 | Name = Name, 23 | Value = Value 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /src/DotTiled/Serialization/DefaultResourceCache.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace DotTiled.Serialization; 4 | 5 | /// 6 | /// A default implementation of that uses an in-memory dictionary to cache resources. 7 | /// 8 | public class DefaultResourceCache : IResourceCache 9 | { 10 | private readonly Dictionary _templates = []; 11 | private readonly Dictionary _tilesets = []; 12 | 13 | /// 14 | public Optional