Compare commits

...

102 commits

Author SHA1 Message Date
dcronqvist
7f78a971f9
Merge pull request #67 from dcronqvist/dev
Release v0.3.0
2024-12-02 22:03:37 +01:00
dcronqvist
de41fb5508
Merge pull request #68 from dcronqvist/fix-before-release
Add new version stuff
2024-12-02 22:02:20 +01:00
Daniel Cronqvist
a38df45869 Add new version stuff 2024-12-02 22:00:04 +01:00
dcronqvist
58e03188a8
Merge pull request #66 from dcronqvist/fix-benchmarks
Fix benchmarks and update ratio numbers in README
2024-12-02 21:35:23 +01:00
Daniel Cronqvist
111403d7fc Fix benchmarks and update ratio numbers in README 2024-12-02 21:33:09 +01:00
dcronqvist
fc710daf8c
Merge pull request #65 from dcronqvist/enum-bug
Enum properties were not being properly parsed due to incorrect usage of Optional
2024-12-02 20:55:31 +01:00
Daniel Cronqvist
88ceee46e5 Add some test cases for the enum parsing bug and fix issue with .tmj format 2024-11-27 22:53:28 +01:00
Daniel Cronqvist
b978b8b50d Add documentation about enum property behaviour 2024-11-27 22:20:42 +01:00
Daniel Cronqvist
ade3d8840a Fix bug where enum properties were mistakenly parsed as uint when they were string 2024-11-27 22:15:24 +01:00
dcronqvist
f3c4478125
Merge pull request #63 from dcronqvist/color-bug
Unset colors are now parsed correctly, color properties have optional colors
2024-11-22 21:18:59 +01:00
Daniel Cronqvist
94c1ac0f32 Unset colors are now parsed correctly, color properties have optional colors 2024-11-21 20:55:51 +01:00
dcronqvist
6deb28c1ce
Merge pull request #57 from dcronqvist/custom-types-not-required
Make custom types optional
2024-11-21 18:24:47 +01:00
dcronqvist
374f2b2194
Merge pull request #62 from dcronqvist/from-class-docs
Add disclaimer about FromClass with classes that contain enums
2024-11-21 18:05:05 +01:00
Daniel Cronqvist
f192a71c56 Add disclaimer about FromClass with classes that contain enums 2024-11-21 17:52:54 +01:00
dcronqvist
416cba6604
Merge pull request #61 from Metraberryy/enum-property-fromclass
Support enum properties in CustomClassDefinition.FromClass
2024-11-21 17:48:03 +01:00
Kat
7a7f360e22
Implement requested changes 2024-11-20 05:11:45 -08:00
Kat
1027b922fe
Enum properties in CustomClassDefinition.FromClass 2024-11-19 03:08:04 -08:00
dcronqvist
1e41443704
Merge pull request #60 from dcronqvist/overrideobject-bug
Add object override for rectangle objects
2024-11-17 15:56:37 +01:00
Daniel Cronqvist
c9e85c9fd6 Add object override for rectangle objects 2024-11-17 15:52:20 +01:00
dcronqvist
080f95c698
Merge pull request #59 from dcronqvist/fix-multiline-string-prop
Fix multiline string property value parsing
2024-11-17 15:13:30 +01:00
Daniel Cronqvist
90a57b125d Fix multiline string property value parsing 2024-11-17 09:15:19 +01:00
dcronqvist
52f148f71d
Merge pull request #58 from dcronqvist/tileobject-flippingflags
Add flipping flags parsing/clearing to tile objects
2024-11-17 09:03:25 +01:00
Daniel Cronqvist
54bc132154 Add flipping flags parsing/clearing to tile objects 2024-11-17 08:59:02 +01:00
Daniel Cronqvist
e553c8e05a Update custom type documentation with optionality disclaimer 2024-11-16 21:33:06 +01:00
Daniel Cronqvist
8c9068cc97 Make custom types optional 2024-11-16 21:14:23 +01:00
dcronqvist
67876c6532
Merge pull request #46 from differenceclouds/tilerendersize_fix
"rendersize" -> "tilerendersize" in TmxReaderBase.Tileset.cs
2024-11-16 19:39:19 +01:00
dcronqvist
66d59ffbe1
Merge pull request #56 from dcronqvist/fix-readme
Remove claims about map saving
2024-11-16 19:30:51 +01:00
Daniel Cronqvist
feb4375cd5 Make sure docs index.md depends on README.md as it is copied 2024-11-16 19:26:44 +01:00
Daniel Cronqvist
837f58bf68 Remove claims about being able to save Tiled maps 2024-11-16 19:26:14 +01:00
dcronqvist
23d218bac7
Merge pull request #54 from dcronqvist/from-enum-storage-type
Add storage type parameter to CustomEnumDefinition.FromEnum
2024-11-16 19:16:44 +01:00
dcronqvist
cbd03bc224
Merge pull request #55 from dcronqvist/fix-template-dir
Fix directory name of pull request templates
2024-11-16 19:06:52 +01:00
dcronqvist
dcdceb8b78
Fix directory name of pull request templates 2024-11-16 19:02:50 +01:00
Daniel Cronqvist
666a3433e3 Update docs section on CustomEnumDefinitions with new storage type parameter info 2024-11-16 18:48:15 +01:00
Daniel Cronqvist
2e8eaa5a72 Update FromEnum tests with storage type parameter 2024-11-16 18:35:59 +01:00
Daniel Cronqvist
35c6ba5002 Add storageType parameter to FromEnum, default value is consistent with Tiled 2024-11-16 18:35:21 +01:00
differenceclouds
50036075f5 "rendersize" -> "tilerendersize"
fix to match the XML.
2024-11-14 09:26:32 -05:00
dcronqvist
88352cfa45
Merge pull request #39 from dcronqvist/release-v0.2.1
Release v0.2.1
2024-10-04 21:26:48 +02:00
Daniel Cronqvist
d943a8d8b7 Update version in .csproj 2024-10-04 21:25:36 +02:00
Daniel Cronqvist
69f68d5853 Update version compatibility matrix 2024-10-04 21:22:43 +02:00
dcronqvist
aaa1ba7de4
Merge pull request #38 from dcronqvist/example-running
Make sure to run console example application as part of test suite
2024-10-04 21:18:16 +02:00
Daniel Cronqvist
e411d51573 Make sure to run console example application as part of test suite 2024-10-04 21:16:00 +02:00
dcronqvist
5969b509e4
Merge pull request #37 from Serdan/feature/visible-type-in-tileset
Fix type of visible attribute in tileset object group.
2024-10-04 21:05:42 +02:00
Anders Kehlet
782e771a41 Fix type of visible attribute in tileset object group. 2024-10-03 22:26:47 +02:00
dcronqvist
871270ab00
Merge pull request #36 from dcronqvist/dev
Documentation updates
2024-09-28 20:03:19 +02:00
dcronqvist
f8f21a8a7d
Merge pull request #35 from dcronqvist/remove-monogame-reference
Remove text about MonoGame support
2024-09-28 19:56:44 +02:00
dcronqvist
e8dc677341
Update README that is published with NuGet to reflect MonoGame support 2024-09-28 19:55:06 +02:00
dcronqvist
50c14011bc
Remove text about MonoGame support 2024-09-28 19:52:28 +02:00
dcronqvist
e66cd36f6d
Merge pull request #32 from krnlexception/dev
Example projects (.NET console and Godot)
2024-09-16 19:09:08 +02:00
krnlException
f72cfd397b Removed backup file 2024-09-16 16:33:07 +02:00
krnlexception
0515ba3256
Godot example 2024-09-13 19:32:24 +02:00
krnlException
3d649fab95 Program class to public and top-level warning disabled 2024-09-12 20:23:43 +02:00
krnlException
44cbf5b90a Style changes, and usage of embedded resources 2024-09-11 17:11:24 +02:00
krnlexception
eb22de169c
JetBrains Rider .idea directory ignore 2024-09-10 00:57:23 +02:00
krnlexception
7407edccb3
Example project 2024-09-10 00:56:24 +02:00
dcronqvist
01099daef1
Merge pull request #30 from dcronqvist/release-v0.2.0
Release v0.2.0
2024-09-07 22:05:33 +02:00
Daniel Cronqvist
89d3f022a4 Bump version and add to version compatibility matrix 2024-09-07 21:51:39 +02:00
dcronqvist
fb1c1499d6
Merge pull request #29 from dcronqvist/multi-version
Add version compatiblity matrix and PR templates
2024-09-07 21:47:23 +02:00
Daniel Cronqvist
40106b5472 Add different PR templates to make sure no release work is missed, and dev PRs are actually filled with useful information 2024-09-07 21:39:48 +02:00
Daniel Cronqvist
914a667c35 Add version compatibility matrix to docs 2024-09-07 21:21:16 +02:00
Daniel Cronqvist
373cdc991e Fix maintained status in NuGet README 2024-09-07 20:55:05 +02:00
dcronqvist
7f22f868e8
Merge pull request #28 from dcronqvist/map-custom-types
Add custom types generation and mapping API
2024-09-07 20:49:31 +02:00
Daniel Cronqvist
b3be5c3735 Add docs on how to map properties to classes 2024-09-07 18:44:46 +02:00
Daniel Cronqvist
9b665efe18 Add more tests to Loader for custom types 2024-09-07 15:54:51 +02:00
Daniel Cronqvist
e0252d263e Added test that creates class definition from C# class and uses to load map 2024-09-07 15:47:59 +02:00
Daniel Cronqvist
d23eec4433 Move test data and current tests into UnitTests 2024-09-07 13:23:32 +02:00
Daniel Cronqvist
0a77a9fec7 Add FromEnum to CustomEnumDefinition with tests 2024-09-07 13:16:29 +02:00
Daniel Cronqvist
58b0ad3493 Make use of generic type parameter in generic methods 2024-09-07 13:03:27 +02:00
Daniel Cronqvist
64f66421c2 Add tests for FromClass for CustomClassDefinition 2024-09-07 12:59:59 +02:00
Daniel Cronqvist
762e610904 Make sure to only embed map, tileset and template files in tests binary 2024-09-07 12:49:10 +02:00
Daniel Cronqvist
84b55fe005 Added some new FromClass methods to construct custom class definitions, tests not done 2024-09-05 22:25:13 +02:00
Daniel Cronqvist
e285f97825 Add some more tests to HasPropertiesBase 2024-09-05 21:15:39 +02:00
Daniel Cronqvist
53907b9c36 Add overload to MapPropertiesTo with supplied factory method 2024-09-05 21:02:34 +02:00
Daniel Cronqvist
612b5cdb33 Rename tests 2024-09-05 20:53:17 +02:00
Daniel Cronqvist
4e273cd521 Remove unecessary duplicate of API 2024-09-05 20:53:17 +02:00
Daniel Cronqvist
ce3d4e339c Rename parts of the property mapping API and simplify 2024-09-05 20:53:17 +02:00
Daniel Cronqvist
fda0922dcc Initial working concept of mapping properties to C# classes using reflection 2024-09-05 20:53:15 +02:00
dcronqvist
be71a1af85
Merge pull request #27 from dcronqvist/tiledcsplus-readme
TiledCSPlus README update
2024-09-05 20:49:48 +02:00
Daniel Cronqvist
f497968c8a Update TiledCSPlus maintained status 2024-09-05 20:48:02 +02:00
dcronqvist
2b05ab9a72
Merge pull request #26 from dcronqvist/resolve-class
Resolve properties from specified classes
2024-09-05 20:46:28 +02:00
Daniel Cronqvist
99fb910336 Affected parts of model should now inherit properties from their specified class 2024-09-05 20:43:12 +02:00
Daniel Cronqvist
ffc529ecb6 Now able to override properties from class in Map 2024-09-04 22:24:40 +02:00
Daniel Cronqvist
0ad1347bc1 Map now resolves props from class 2024-09-04 22:11:45 +02:00
dcronqvist
fef01eb41d
Merge pull request #25 from dcronqvist/nuget-fixes
NuGet fixes
2024-09-04 21:41:20 +02:00
Daniel Cronqvist
77a47856e2 Updated NuGet README to not have ugly formatting 2024-09-04 21:39:32 +02:00
Daniel Cronqvist
9abda9e244 Fix strange keywords 2024-09-04 21:35:19 +02:00
dcronqvist
4034e68cf3
Merge pull request #24 from dcronqvist/common-readers
Create easy-to-use Loader class with reader and cache
2024-09-04 21:33:07 +02:00
Daniel Cronqvist
b06bbd27c8 Made makefile use proper dependency for docs index.md 2024-09-04 21:31:07 +02:00
Daniel Cronqvist
8fd43d95aa Updated docs a bit 2024-09-04 21:27:18 +02:00
Daniel Cronqvist
247f9294af Simplified loader a bit and added more docs 2024-09-03 22:52:26 +02:00
Daniel Cronqvist
738a9fc5a8 Add docs to quickstart 2024-09-02 23:58:25 +02:00
Daniel Cronqvist
01bb3d4f23 Add better default loader creation 2024-09-02 21:14:56 +02:00
Daniel Cronqvist
9133f8887c Add loader to make it easier to start using library 2024-09-02 21:11:31 +02:00
dcronqvist
97307ccba2
Merge pull request #23 from dcronqvist/tiledlib-release 2024-09-02 17:53:09 +02:00
Daniel Cronqvist
fee686b348 Update TiledLib .NET targets since their latest release 2024-09-02 17:50:08 +02:00
dcronqvist
60e4adadb1
Merge pull request #22 from dcronqvist/optional
Use Optional<T> in model for explicit optionality for some properties
2024-09-02 17:39:28 +02:00
Daniel Cronqvist
3b6c5f8111 Remove nullables 2024-09-02 17:33:11 +02:00
Daniel Cronqvist
3185e038c0 Update docs on representation model 2024-09-02 17:30:12 +02:00
Daniel Cronqvist
df075eed8d Use proper list assertion and add optional to some Data properties 2024-09-01 22:09:03 +02:00
Daniel Cronqvist
4fd887e7c8 Further optional improvements, Tmj now supports it too 2024-09-01 22:03:05 +02:00
Daniel Cronqvist
88a5eadb74 Model now uses Optional correctly, I think, massive changes 2024-09-01 20:44:36 +02:00
dcronqvist
39d2838663
Merge pull request #21 from dcronqvist/objlayer-visibility
Fix incorrect type for visibility in layers
2024-08-31 17:09:14 +02:00
Daniel Cronqvist
4695a4f739 Fix incorrect type for visibility in layers 2024-08-31 17:07:50 +02:00
182 changed files with 5180 additions and 892 deletions

View file

@ -235,7 +235,9 @@ dotnet_diagnostic.IDE0004.severity = silent
dotnet_diagnostic.IDE0005.severity = error dotnet_diagnostic.IDE0005.severity = error
dotnet_diagnostic.IDE0008.severity = silent dotnet_diagnostic.IDE0008.severity = silent
dotnet_diagnostic.IDE0055.severity = silent dotnet_diagnostic.IDE0055.severity = silent
dotnet_diagnostic.IDE0058.severity = silent
dotnet_diagnostic.IDE0160.severity = none dotnet_diagnostic.IDE0160.severity = none
dotnet_diagnostic.IDE0210.severity = none
dotnet_diagnostic.CA1707.severity = silent dotnet_diagnostic.CA1707.severity = silent
dotnet_diagnostic.CA1852.severity = none dotnet_diagnostic.CA1852.severity = none
dotnet_diagnostic.CA1805.severity = none dotnet_diagnostic.CA1805.severity = none
@ -243,7 +245,7 @@ dotnet_diagnostic.CA1720.severity = silent
dotnet_diagnostic.CA1711.severity = silent dotnet_diagnostic.CA1711.severity = silent
dotnet_diagnostic.CA1716.severity = silent dotnet_diagnostic.CA1716.severity = silent
[.github/**/*.yml] [*.(yml|json|js)]
charset = utf-8 charset = utf-8
end_of_line = lf end_of_line = lf
indent_size = 2 indent_size = 2

View file

@ -0,0 +1,15 @@
## Description
<!-- Provide a clear and concise description of the changes introduced by this PR. Include the purpose and context for these changes. -->
### Type of Change
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] Documentation update
## Checklist
- [ ] Tests have been added/updated to cover new functionality.
- [ ] Documentation has been updated for all new changes (e.g., usage examples, API documentation).

View file

@ -0,0 +1,10 @@
# Release vX.Y.Z
<!-- Include a description of what is breaking/new/patched in this release. -->
## Checklist for a release PR
- [ ] Version compatibility matrix has been updated.
- [ ] Tests have been added/updated to cover new functionality.
- [ ] Documentation has been updated for all new changes (e.g., usage examples, API documentation).

1
.gitignore vendored
View file

@ -402,3 +402,4 @@ FodyWeavers.xsd
# JetBrains Rider # JetBrains Rider
*.sln.iml *.sln.iml
.idea

View file

@ -1,14 +1,17 @@
test: test:
dotnet build src/DotTiled.sln dotnet build src/DotTiled.sln
dotnet test src/DotTiled.sln dotnet test src/DotTiled.sln
dotnet run --project src/DotTiled.Examples/DotTiled.Example.Console/DotTiled.Example.Console.csproj -- src/DotTiled.Examples/DotTiled.Example.Console
docs-serve: docs-serve: docs/index.md
docfx docs/docfx.json --serve docfx docs/docfx.json --serve
docs-build: docs-build: docs/index.md
cp README.md docs/index.md
docfx docs/docfx.json docfx docs/docfx.json
docs/index.md: README.md
cp README.md docs/index.md
lint: lint:
dotnet format style --verify-no-changes src/DotTiled.sln dotnet format style --verify-no-changes src/DotTiled.sln
dotnet format analyzers --verify-no-changes src/DotTiled.sln dotnet format analyzers --verify-no-changes src/DotTiled.sln

View file

@ -2,7 +2,7 @@
<img src="https://www.mapeditor.org/img/tiled-logo-white.png" align="right" width="20%"/> <img src="https://www.mapeditor.org/img/tiled-logo-white.png" align="right" width="20%"/>
DotTiled is a simple and easy-to-use library for loading, saving, and managing [Tiled maps and tilesets](https://mapeditor.org) in your .NET projects. After [TiledCS](https://github.com/TheBoneJarmer/TiledCS) unfortunately became unmaintained (since 2022), I aimed to create a new library that could fill its shoes. DotTiled is the result of that effort. DotTiled is a simple and easy-to-use library for loading [Tiled maps and tilesets](https://mapeditor.org) in your .NET projects. After [TiledCS](https://github.com/TheBoneJarmer/TiledCS) unfortunately became unmaintained (since 2022), I aimed to create a new library that could fill its shoes. DotTiled is the result of that effort.
DotTiled is designed to be a lightweight and efficient library that provides a simple API for loading and managing Tiled maps and tilesets. It is built with performance in mind and aims to be as fast and memory-efficient as possible. DotTiled is designed to be a lightweight and efficient library that provides a simple API for loading and managing Tiled maps and tilesets. It is built with performance in mind and aims to be as fast and memory-efficient as possible.
@ -16,17 +16,17 @@ Other similar libraries exist, and you may want to consider them for your projec
|**Comparison**|**DotTiled**|[TiledLib](https://github.com/Ragath/TiledLib.Net)|[TiledCSPlus](https://github.com/nolemretaWxd/TiledCSPlus)|[TiledSharp](https://github.com/marshallward/TiledSharp)|[TiledCS](https://github.com/TheBoneJarmer/TiledCS)|[TiledNet](https://github.com/napen123/Tiled.Net)| |**Comparison**|**DotTiled**|[TiledLib](https://github.com/Ragath/TiledLib.Net)|[TiledCSPlus](https://github.com/nolemretaWxd/TiledCSPlus)|[TiledSharp](https://github.com/marshallward/TiledSharp)|[TiledCS](https://github.com/TheBoneJarmer/TiledCS)|[TiledNet](https://github.com/napen123/Tiled.Net)|
|---------------------------------|:-----------------------:|:--------:|:-----------:|:----------:|:-------:|:------:| |---------------------------------|:-----------------------:|:--------:|:-----------:|:----------:|:-------:|:------:|
| Actively maintained | ✅ | ✅ | | ❌ | ❌ | ❌ | | Actively maintained | ✅ | ✅ | | ❌ | ❌ | ❌ |
| Benchmark (time)* | 1.00 | 1.83 | 2.16 | - | - | - | | Benchmark (time)* | 1.00 | 1.78 | 2.11 | - | - | - |
| Benchmark (memory)* | 1.00 | 1.43 | 2.03 | - | - | - | | Benchmark (memory)* | 1.00 | 1.32 | 1.88 | - | - | - |
| .NET Targets | `net8.0` |`net6.0`<br>`net7.0`|`netstandard2.1`|`netstandard2.0`|`netstandard2.0`|`net45`| | .NET Targets | `net8.0` | `net8.0` |`netstandard2.1`|`netstandard2.0`|`netstandard2.0`|`net45`|
| Docs |Usage, API,<br>XML Docs|Usage|Usage, API,<br>XML Docs|Usage, API|Usage, XML Docs|Usage, XML Docs| | Docs |Usage, API,<br>XML Docs|Usage|Usage, API,<br>XML Docs|Usage, API|Usage, XML Docs|Usage, XML Docs|
| License | MIT | MIT | MIT | Apache-2.0 | MIT | BSD 3-Clause | | License | MIT | MIT | MIT | Apache-2.0 | MIT | BSD 3-Clause |
> [!NOTE] > [!NOTE]
> *Both benchmark time and memory ratios are relative to DotTiled. Lower is better. Benchmark (time) refers to the execution time of loading the same map from an in-memory string that contains XML data in the `.tmx` format. Benchmark (memory) refers to the memory allocated during that loading process. For further details on the benchmark results, see the collapsible section below. > *Both benchmark time and memory ratios are relative to DotTiled. Lower is better. Benchmark (time) refers to the execution time of loading the same map from an in-memory string that contains XML data in the `.tmx` format. Benchmark (memory) refers to the memory allocated during that loading process. For further details on the benchmark results, see the collapsible section below.
[MonoGame](https://www.monogame.net) users may also want to consider using [MonoGame.Extended](https://github.com/craftworkgames/MonoGame.Extended) for loading Tiled maps and tilesets. Like MonoGame.Extended, DotTiled also provides a way to properly import Tiled maps and tilesets with the MonoGame content pipeline (with the DotTiled.MonoGame.Pipeline NuGet). However, unlike MonoGame.Extended, DotTiled does *not* include any kind of rendering capabilities, and it is up to you as a developer to implement any kind of rendering for your maps when using DotTiled. The feature coverage by MonoGame.Extended is less than that of DotTiled, so you may want to consider using DotTiled if you need access to more Tiled features and flexibility. [MonoGame](https://www.monogame.net) users may also want to consider using [MonoGame.Extended](https://github.com/craftworkgames/MonoGame.Extended) for loading Tiled maps and tilesets. The feature coverage by MonoGame.Extended is less than that of DotTiled, so you may want to consider using DotTiled if you need access to more Tiled features and flexibility.
<details> <details>
<summary> <summary>
@ -36,7 +36,7 @@ Benchmark details
The following benchmark results were gathered using the `DotTiled.Benchmark` project which uses [BenchmarkDotNet](https://benchmarkdotnet.org/) to compare the performance of DotTiled with other similar libraries. The benchmark results are grouped by category and show the mean execution time, memory consumption metrics, and ratio to DotTiled. The following benchmark results were gathered using the `DotTiled.Benchmark` project which uses [BenchmarkDotNet](https://benchmarkdotnet.org/) to compare the performance of DotTiled with other similar libraries. The benchmark results are grouped by category and show the mean execution time, memory consumption metrics, and ratio to DotTiled.
``` ```
BenchmarkDotNet v0.13.12, Windows 10 (10.0.19045.4651/22H2/2022Update) BenchmarkDotNet v0.13.12, Windows 10 (10.0.19045.5131/22H2/2022Update)
12th Gen Intel Core i7-12700K, 1 CPU, 20 logical and 12 physical cores 12th Gen Intel Core i7-12700K, 1 CPU, 20 logical and 12 physical cores
.NET SDK 8.0.202 .NET SDK 8.0.202
[Host] : .NET 8.0.3 (8.0.324.11423), X64 RyuJIT AVX2 [Host] : .NET 8.0.3 (8.0.324.11423), X64 RyuJIT AVX2
@ -44,12 +44,12 @@ BenchmarkDotNet v0.13.12, Windows 10 (10.0.19045.4651/22H2/2022Update)
``` ```
| Method | Categories | Mean | Ratio | Gen0 | Gen1 | Allocated | Alloc Ratio | | Method | Categories | Mean | Ratio | Gen0 | Gen1 | Allocated | Alloc Ratio |
|------------ |------------------------- |---------:|------:|-------:|-------:|----------:|------------:| |------------ |------------------------- |---------:|------:|-------:|-------:|----------:|------------:|
| DotTiled | MapFromInMemoryTmjString | 4.431 μs | 1.00 | 0.4349 | - | 5.58 KB | 1.00 | | DotTiled | MapFromInMemoryTmjString | 4.602 μs | 1.00 | 0.5417 | - | 7 KB | 1.00 |
| TiledLib | MapFromInMemoryTmjString | 6.369 μs | 1.44 | 0.7019 | 0.0153 | 9.01 KB | 1.61 | | TiledLib | MapFromInMemoryTmjString | 6.385 μs | 1.39 | 0.7019 | 0.0153 | 9.01 KB | 1.29 |
| | | | | | | | | | | | | | | | | |
| DotTiled | MapFromInMemoryTmxString | 3.125 μs | 1.00 | 1.2817 | 0.0610 | 16.36 KB | 1.00 | | DotTiled | MapFromInMemoryTmxString | 3.216 μs | 1.00 | 1.3733 | 0.0610 | 17.68 KB | 1.00 |
| TiledLib | MapFromInMemoryTmxString | 5.709 μs | 1.83 | 1.8005 | 0.0916 | 23.32 KB | 1.43 | | TiledLib | MapFromInMemoryTmxString | 5.721 μs | 1.78 | 1.8005 | 0.0916 | 23.32 KB | 1.32 |
| TiledCSPlus | MapFromInMemoryTmxString | 6.757 μs | 2.16 | 2.5940 | 0.1831 | 33.16 KB | 2.03 | | TiledCSPlus | MapFromInMemoryTmxString | 6.696 μs | 2.11 | 2.5940 | 0.1831 | 33.23 KB | 1.88 |
It is important to note that the above benchmark results come from loading a very small map with a single tile layer as I had to find a common denominator between the libraries so that they all could load the same map. The results aim to be indicative of the performance of the libraries, but should be taken with a grain of salt. Only the actively maintained libraries are included in the benchmark results. TiledCSPlus does not support the `.tmj` format, so it was not included for that benchmark category. It is important to note that the above benchmark results come from loading a very small map with a single tile layer as I had to find a common denominator between the libraries so that they all could load the same map. The results aim to be indicative of the performance of the libraries, but should be taken with a grain of salt. Only the actively maintained libraries are included in the benchmark results. TiledCSPlus does not support the `.tmj` format, so it was not included for that benchmark category.

View file

@ -41,7 +41,10 @@
"_appName": "DotTiled", "_appName": "DotTiled",
"_appTitle": "DotTiled", "_appTitle": "DotTiled",
"_enableSearch": true, "_enableSearch": true,
"pdf": true "pdf": false
} },
"xref": [
"https://learn.microsoft.com/en-us/dotnet/.xrefmap.json"
]
} }
} }

View file

@ -66,11 +66,17 @@ Tiled supports a variety of property types, which are represented in the DotTile
- `object` - <xref:DotTiled.ObjectProperty> - `object` - <xref:DotTiled.ObjectProperty>
- `string` - <xref:DotTiled.StringProperty> - `string` - <xref:DotTiled.StringProperty>
In addition to these primitive property types, [Tiled also supports more complex property types](https://doc.mapeditor.org/en/stable/manual/custom-properties/#custom-types). These custom property types are defined in Tiled according to the linked documentation, and to work with them in DotTiled, you *must* define their equivalences as a <xref:DotTiled.ICustomTypeDefinition>. You must then provide a resolving function to a defined type given a custom type name, as it is defined in Tiled. In addition to these primitive property types, [Tiled also supports more complex property types](https://doc.mapeditor.org/en/stable/manual/custom-properties/#custom-types). These custom property types are defined in Tiled according to the linked documentation, and to work with them in DotTiled, you *must* define their equivalences as a <xref:DotTiled.ICustomTypeDefinition>. This is because of how Tiled handles default values for custom property types, and DotTiled needs to know these defaults to be able to populate the properties correctly.
## Custom types ## Custom types
Tiled allows you to define custom property types that can be used in your maps. These custom property types can be of type `class` or `enum`. DotTiled supports custom property types by allowing you to define the equivalent in C# and then providing a custom type resolver function that will return the equivalent definition given a custom type name. Tiled allows you to define custom property types that can be used in your maps. These custom property types can be of type `class` or `enum`. DotTiled supports custom property types by allowing you to define the equivalent in C#. This section will guide you through how to define custom property types in DotTiled and how to map properties in loaded maps to C# classes or enums.
> [!NOTE]
> While custom types are powerful, they will incur a bit of overhead as you attempt to sync them between Tiled and DotTiled. Defining custom types is recommended, but not necessary for simple use cases as Tiled supports arbitrary strings as classes.
> [!IMPORTANT]
> If you choose to use custom types in your maps, but don't define them properly in DotTiled, you may get inconsistencies between the map in Tiled and the loaded map with DotTiled. If you still want to use custom types in Tiled without having to define them in DotTiled, it is recommended to set the `Resolve object types and properties` setting in Tiled to `true`. This will make Tiled resolve the custom types for you, but it will still require you to define the custom types in DotTiled if you want to access the properties in a type-safe manner.
### Class properties ### Class properties
@ -88,14 +94,39 @@ var monsterSpawnerDefinition = new CustomClassDefinition
Name = "MonsterSpawner", Name = "MonsterSpawner",
UseAs = CustomClassUseAs.All, // Not really validated by DotTiled UseAs = CustomClassUseAs.All, // Not really validated by DotTiled
Members = [ // Make sure that the default values match the Tiled UI Members = [ // Make sure that the default values match the Tiled UI
new BoolProperty { Name = "enabled", Value = true }, new BoolProperty { Name = "Enabled", Value = true },
new IntProperty { Name = "maxSpawnAmount", Value = 10 }, new IntProperty { Name = "MaxSpawnAmount", Value = 10 },
new IntProperty { Name = "minSpawnAmount", Value = 0 }, new IntProperty { Name = "MinSpawnAmount", Value = 0 },
new StringProperty { Name = "monsterNames", Value = "" } new StringProperty { Name = "MonsterNames", Value = "" }
] ]
}; };
``` ```
Luckily, you don't have to manually define these custom class definitions, even though you most definitively can for scenarios that require it. DotTiled provides a way to automatically generate these definitions for you from a C# class. This is done by using the <xref:DotTiled.CustomClassDefinition.FromClass``1> method, or one of its overloads. This method will generate a <xref:DotTiled.CustomClassDefinition> from a given C# class, and you can then use this definition when loading your maps.
```csharp
class MonsterSpawner
{
public bool Enabled { get; set; } = true;
public int MaxSpawnAmount { get; set; } = 10;
public int MinSpawnAmount { get; set; } = 0;
public string MonsterNames { get; set; } = "";
}
// ...
// These are all valid ways to create your custom class definitions from a C# class
// The first two require the class to have a default, parameterless constructor
var monsterSpawnerDefinition1 = CustomClassDefinition.FromClass<MonsterSpawner>();
var monsterSpawnerDefinition2 = CustomClassDefinition.FromClass(typeof(MonsterSpawner));
var monsterSpawnerDefinition3 = CustomClassDefinition.FromClass(() => new MonsterSpawner
{
Enabled = false // This will use the property values in the instance created by a factory method as the default values
});
```
The last one is especially useful if you have classes that may not have parameterless constructors, or if you want to provide custom default values for the properties. Finally, the generated custom class definition will be identical to the one defined manually in the first example.
### Enum properties ### Enum properties
Tiled also allows you to define custom property types that work as enums. Similarly to `class` properties, you must define the equivalent in DotTiled as a <xref:DotTiled.CustomEnumDefinition>. You can then return the corresponding definition in the resolving function. Tiled also allows you to define custom property types that work as enums. Similarly to `class` properties, you must define the equivalent in DotTiled as a <xref:DotTiled.CustomEnumDefinition>. You can then return the corresponding definition in the resolving function.
@ -121,23 +152,9 @@ var entityTypeDefinition = new CustomEnumDefinition
}; };
``` ```
### [Future] Automatically map custom property `class` types to C# classes Similarly to custom class definitions, you can also automatically generate custom enum definitions from C# enums. This is done by using the <xref:DotTiled.CustomEnumDefinition.FromEnum``1(DotTiled.CustomEnumStorageType)> method, or one of its overloads. This method will generate a <xref:DotTiled.CustomEnumDefinition> from a given C# enum, and you can then use this definition when loading your maps.
In the future, DotTiled will support automatically mapping custom property `class` types to C# classes. This will allow you to define a C# class that matches the structure of the `class` property in Tiled, and DotTiled will automatically map the properties of the `class` property to the properties of the C# class. This will make working with `class` properties much easier and more intuitive.
The idea is to expand on the <xref:DotTiled.IHasProperties> interface with a method like `GetMappedProperty<T>(string propertyName)`, where `T` is a class that matches the structure of the `class` property in Tiled.
This functionality would be accompanied by a way to automatically create a matching <xref:DotTiled.ICustomTypeDefinition> given a C# class or enum. Something like this would then be possible:
```csharp ```csharp
class MonsterSpawner
{
public bool Enabled { get; set; } = true;
public int MaxSpawnAmount { get; set; } = 10;
public int MinSpawnAmount { get; set; } = 0;
public string MonsterNames { get; set; } = "";
}
enum EntityType enum EntityType
{ {
Bomb, Bomb,
@ -146,16 +163,98 @@ enum EntityType
Chair Chair
} }
var monsterSpawnerDefinition = CustomClassDefinition.FromClass<MonsterSpawner>();
var entityTypeDefinition = CustomEnumDefinition.FromEnum<EntityType>();
// ... // ...
var map = LoadMap(); // These are both valid ways to create your custom enum definitions from a C# enum
var monsterSpawner = map.GetMappedProperty<MonsterSpawner>("monsterSpawnerPropertyInMap"); var entityTypeDefinition1 = CustomEnumDefinition.FromEnum<EntityType>();
var entityType = map.GetMappedProperty<EntityType>("entityTypePropertyInMap"); var entityTypeDefinition2 = CustomEnumDefinition.FromEnum(typeof(EntityType));
``` ```
Finally, it might be possible to also make some kind of exporting functionality for <xref:DotTiled.ICustomTypeDefinition>. Given a collection of custom type definitions, DotTiled could generate a corresponding `propertytypes.json` file that you then can import into Tiled. This would make it so that you only have to define your custom property types once (in C#) and then import them into Tiled to use them in your maps. The generated custom enum definition will be identical to the one defined manually in the first example.
Depending on implementation this might become something that can inhibit native AOT compilation due to potential reflection usage. Source generators could be used to mitigate this, but it is not yet clear how this will be implemented. For enum definitions, the <xref:System.FlagsAttribute> can be used to indicate that the enum should be treated as a flags enum. This will make it so the enum definition will have `ValueAsFlags = true` and the enum values will be treated as flags when working with them in DotTiled.
> [!NOTE]
> Tiled supports enums which can store their values as either strings or integers, and depending on the storage type you have specified in Tiled, you must make sure to have the same storage type in your <xref:DotTiled.CustomEnumDefinition>. This can be done by setting the `StorageType` property to either `CustomEnumStorageType.String` or `CustomEnumStorageType.Int` when creating the definition, or by passing the storage type as an argument to the <xref:DotTiled.CustomEnumDefinition.FromEnum``1(DotTiled.CustomEnumStorageType)> method. To be consistent with Tiled, <xref:DotTiled.CustomEnumDefinition.FromEnum``1(DotTiled.CustomEnumStorageType)> will default to `CustomEnumStorageType.String` for the storage type parameter.
> [!WARNING]
> If you have a custom enum type in Tiled, but do not define it in DotTiled, you must be aware that the type of the parsed property will be either <xref:DotTiled.StringProperty> or <xref:IntProperty>. It is not possible to determine the correct way to parse the enum property without the custom enum definition, which is why you will instead be given a property of type `string` or `int` when accessing the property in DotTiled. This can lead to inconsistencies between the map in Tiled and the loaded map with DotTiled. It is therefore recommended to define your custom enum types in DotTiled if you want to access the properties as <xref:EnumProperty> instances.
## Mapping properties to C# classes or enums
So far, we have only discussed how to define custom property types in DotTiled, and why they are needed. However, the most important part is how you can map properties inside your maps to their corresponding C# classes or enums.
The interface <xref:DotTiled.IHasProperties> has two overloads of the <xref:DotTiled.IHasProperties.MapPropertiesTo``1> method. These methods allow you to map a collection of properties to a given C# class. Let's look at an example:
```csharp
// Define a few Tiled compatible custom types
enum EntityType
{
Player,
Enemy,
Collectible,
Explosive
}
class EntityData
{
public EntityType Type { get; set; } = EntityType.Player;
public int Health { get; set; } = 100;
public string Name { get; set; } = "Unnamed Entity";
}
var entityTypeDef = CustomEnumDefinition.FromEnum<EntityType>();
var entityDataDef = CustomClassDefinition.FromClass<EntityData>();
```
The above gives us two custom type definitions that we can supply to our map loader. Given a map that looks like this:
> [!WARNING]
> For classes that you call `FromClass` on, which also contain enum properties (at some level of depth) that you want to map to a C# enum, you must also supply the custom enum definitions to the map loader. This is so that the map loader can resolve the enum values correctly.
```xml
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.11.0" orientation="orthogonal" renderorder="right-down" width="5" height="5" tilewidth="32" tileheight="32" infinite="0" nextlayerid="8" nextobjectid="7">
<tileset firstgid="1" source="tileset.tsx"/>
<layer id="1" name="Tile Layer 1" width="5" height="5">
<data encoding="csv">
1,1,1,1,1,
0,0,0,0,0,
0,0,0,0,0,
0,0,0,0,0,
0,0,0,0,0
</data>
</layer>
<objectgroup id="3" name="Objects">
<object id="4" name="Circle1" type="EntityData" x="77" y="72.3333" width="34.6667" height="34.6667">
<properties>
<property name="Health" type="int" value="1"/>
<property name="Name" value="Bomb Chest"/>
<property name="Type" type="int" propertytype="EntityType" value="3"/>
</properties>
<ellipse/>
</object>
</objectgroup>
</map>
```
We can see that there is an ellipse object in the map that has the type `EntityData` and it has set the three properties to some value other than their defaults. After having loaded this map, we can map the properties of the object to the `EntityData` class like this:
```csharp
var map = LoadMap([entityTypeDef, entityDataDef]); // Load the map somehow, using DotTiled.Loader or similar
// Retrieve the object layer from the map in some way
var objectLayer = map.Layers.Skip(1).First() as ObjectLayer;
// Retrieve the object from the object layer
var entityObject = objectLayer.Objects.First();
// Map the properties of the object to the EntityData class
var entityData = entityObject.MapPropertiesTo<EntityData>();
```
The above snippet will map the properties of the object to the `EntityData` class using reflection based on the property names. The `entityData` object will now have the properties set to the values found in the object in the map. If a property is not found in the object, the default value of the property in the `EntityData` class will be used. It will even map the nested enum to its corresponding value in C#. This will work for several levels of depth as it performs this kind of mapping recursively. <xref:DotTiled.IHasProperties.MapPropertiesTo``1> only supports mapping to classes that have a default, parameterless constructor.
### [Future] Exporting custom types
It might be possible to also make some kind of exporting functionality for <xref:DotTiled.ICustomTypeDefinition>. Given a collection of custom type definitions, DotTiled could generate a corresponding `propertytypes.json` file that you then can import into Tiled. This would make it so that you only have to define your custom property types once (in C#) and then import them into Tiled to use them in your maps.

View file

@ -1,15 +1,92 @@
# Loading maps # Loading maps
Loading maps with DotTiled is straightforward and easy. The <xref:DotTiled.Map> class is a representation of a Tiled map, mimicking the structure of a Tiled map file. Map files can either be in the [`.tmx`/XML](https://doc.mapeditor.org/en/stable/reference/tmx-map-format/) or [`.tmj`/json](https://doc.mapeditor.org/en/stable/reference/json-map-format/) format. DotTiled supports **both** formats fully. Loading maps with DotTiled is very flexible and allows you as a developer to freely choose how you want to load your maps and tilesets. This guide will show you how to customize the loading process to fit your needs. As the tip below suggests, you can also use the quickstart guide if you just want to load maps from the filesystem without any particular customization.
> [!NOTE] > [!TIP]
> Using the `.tmj` file format will result in <xref:DotTiled.ImageLayer.Image> not having the same amount of information as for the `.tmx` format. This is due to the fact that the `.tmj` format does not include the full information that the `.tmx` format does. This is not a problem with DotTiled, but rather a limitation of the `.tmj` format. > For a quick and easy way to load maps from the filesystem, please refer to the [quickstart guide](../quickstart.md).
## External resolution ## File format caveats
Tiled maps may consist of several external files, such as tilesets or object templates. In Tiled map files, they are typically referenced by their path relative to the map file. It would be annoying to have to first load all these external resources before loading a map (which is how some other similar libraries work), so loading a map with DotTiled is designed in a way that you only have to provide a function that resolves these external resources. This way, DotTiled will figure out which external resources are needed and will invoke the corresponding resolver function to load them. The <xref:DotTiled.Map> class is a representation of a Tiled map, mimicking the structure of a Tiled XML map file. Map files can either be in the [`.tmx`/XML](https://doc.mapeditor.org/en/stable/reference/tmx-map-format/) or [`.tmj`/json](https://doc.mapeditor.org/en/stable/reference/json-map-format/) format. DotTiled supports **both** formats fully.
Loading a map, tileset, or template will require you to specify **three** resolver functions. We'll go through each of them below. > [!WARNING]
> Using the `.tmj` file format will result in <xref:DotTiled.ImageLayer.Image> (the source image for image layers) not having the same amount of information as for the `.tmx` format. This is due to the fact that the `.tmj` format does not include the full information that the `.tmx` format does. This is not a problem with DotTiled, but rather a limitation of the `.tmj` format.
## The process of loading a map
Loading a map with DotTiled is not a complex process, but one that at least demands a basic understanding of how Tiled maps are structured. The process can be broken down into the following flow(-ish) chart:
```mermaid
flowchart LR
Z{{Loading a map
with DotTiled}} --> A
subgraph Parsing map
A[(Read map)] --> B(Parse map)
end
subgraph Parsing tileset
B -.->|References
external tileset| C[(Read tileset)]
C --> D(Parse tileset) --o|Store in map| B
end
subgraph Parsing template
B -.->|References external
template in object| E[(Read template)]
E --> F(Parse template) --o|Use as template
for object| B
end
F -.-> |References
external tileset| C
F -.-> |References
external template| E
```
As you can see, the process is quite simple. You read the map, parse it, and then read and parse any external tilesets or templates that are referenced in the map. The tilesets and templates are then stored in the map object that is returned to you.
However, because DotTiled works in the way that it does, you will need to provide a way to resolve these external resources. We'll go through how to do that in the next section.
## Loading a map with <xref:DotTiled.Serialization.Loader>
When using <xref:DotTiled.Serialization.Loader>, external resources like tilesets and templates will be resolved by the loader itself. Since Tiled saves the external resource paths relative to the map file, the loader will automatically resolve these paths and use the provided <xref:DotTiled.Serialization.IResourceReader> to read the external resources. Therefore, as long as the external resources are accessible in a "relative path" way using the provided <xref:DotTiled.Serialization.IResourceReader>, you don't have to worry about resolving them yourself.
```xml
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.11.0" orientation="orthogonal" renderorder="right-down" width="5" height="5" tilewidth="32" tileheight="32" infinite="0" nextlayerid="2" nextobjectid="1">
<tileset firstgid="1" source="tileset.tsx"/>
<layer id="1" name="Tile Layer 1" width="5" height="5">
<data encoding="csv">
1,1,0,0,7,
1,1,0,0,7,
0,0,1,0,7,
0,0,0,1,7,
21,21,21,21,1
</data>
</layer>
</map>
```
A map like the one above that is loaded by the following code will result in the loader calling `IResourceReader.Read("path/to/tileset.tsx")` to read the external tileset, since it will use the path relative to the map file to resolve the tileset.
```csharp
var loader = Loader.Default();
var map = loader.LoadMap("path/to/map.tmx");
```
Additionally, the loader will use an in-memory cache to avoid loading the same tileset or template multiple times. This is done using the <xref:DotTiled.Serialization.IResourceCache> that is provided to the loader. If you don't provide a cache, the loader will use the <xref:DotTiled.Serialization.DefaultResourceCache> by default.
## Loading a map manually with <xref:DotTiled.Serialization.MapReader>
While it is recommended to use the <xref:DotTiled.Serialization.Loader> class to perform the loading of maps and tilesets, you may have certain requirements that necessitate you to load maps in a more manual way. This section will guide you through how to load a map manually without the use of the provided loader.
### <xref:DotTiled.Serialization.MapReader>, <xref:DotTiled.Serialization.TilesetReader>, and <xref:DotTiled.Serialization.TemplateReader>
are the three classes that you will use to read the map, tileset, and template, respectively. They are designed to be used in a way that you can provide your own resolver functions to load external resources.
> [!IMPORTANT]
> The resolving functions will get the source path of the external resource as a parameter, *in the exact way it is written in the map file*. You will have to perform your own path resolution to load the external resources.
### `Func<string, Tileset>` - Tileset resolver ### `Func<string, Tileset>` - Tileset resolver
@ -38,17 +115,17 @@ Tileset ResolveTileset(string source)
### `Func<string, Template>` - Template resolver ### `Func<string, Template>` - Template resolver
This function is used to resolve external object templates by their source path. The function should return a <xref:DotTiled.Template> instance given the source path of the template. If you just want to load templates from the file system, you can use something very similar to the tileset resolver by replacing <xref:DotTiled.Serialization.TilesetReader> with <xref:DotTiled.Serialization.TemplateReader>. This function is used to resolve external object templates by their source path. The function should return a <xref:DotTiled.Template> instance given the source path of the template. If you just want to load templates from the file system, you can use something very similar to the example tileset resolver by replacing <xref:DotTiled.Serialization.TilesetReader> with <xref:DotTiled.Serialization.TemplateReader>.
### `Func<string, CustomType>` - Custom type resolver ### `Func<string, ICustomTypeDefinition>` - Custom type resolver
This function is used to resolve custom types that are defined in Tiled maps. Please refer to the [custom properties](custom-properties.md) documentation for more information on custom types. The function should return a <xref:DotTiled.ICustomTypeDefinition> instance given the custom type's name. This function is used to resolve custom types that are defined in your Tiled maps. Please refer to the [custom properties](custom-properties.md) documentation for more information on custom types. The function should return a <xref:DotTiled.ICustomTypeDefinition> instance given the custom type's name.
## Putting it all together ## Putting it all together
The following classes are the readers that you will need to use to read the map, tileset, and template: <xref:DotTiled.Serialization.MapReader>, <xref:DotTiled.Serialization.TilesetReader>, and <xref:DotTiled.Serialization.TemplateReader>. The following classes are the readers that you will need to use to read the map, tileset, and template: <xref:DotTiled.Serialization.MapReader>, <xref:DotTiled.Serialization.TilesetReader>, and <xref:DotTiled.Serialization.TemplateReader>.
Here is an example of how you can load a map with DotTiled: Here is an example of how you can load a map with DotTiled, and is very similar to how the <xref:DotTiled.Serialization.Loader> class works:
```csharp ```csharp
string mapPath = "path/to/map.tmx"; string mapPath = "path/to/map.tmx";

View file

@ -0,0 +1,17 @@
# Representation model
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.
Certain properties throughout the representation model are marked as *optional* by being either wrapped in a <xref:DotTiled.Optional`1> or by having a set default value.
- 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.
- 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.
- Properties that are wrapped in <xref:DotTiled.Optional`1> may or may not be present in the file, and have no default value.
## Version compatibility
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.
| Tiled version | Compatible DotTiled version(s) |
|---------------|--------------------------------|
| 1.11 | 0.1.0, 0.2.0, 0.2.1, 0.3.0 |

View file

@ -6,41 +6,64 @@ Install DotTiled from NuGet:
dotnet add package DotTiled dotnet add package DotTiled
``` ```
Load a map from file system: Use the `DotTiled` namespace (if you want).
```csharp ```csharp
string mapPath = "path/to/map.tmx"; using DotTiled;
string mapDirectory = Path.GetDirectoryName(mapPath);
Tileset ResolveTileset(string source)
{
string tilesetPath = Path.Combine(mapDirectory, source);
using var tilesetFileReader = new StreamReader(tilesetPath);
var tilesetString = tilesetReader.ReadToEnd();
using var tilesetReader = new TilesetReader(tilesetString, ResolveTileset, ResolveTemplate, ResolveCustomType);
return tilesetReader.ReadTileset();
}
Template ResolveTemplate(string source)
{
string templatePath = Path.Combine(mapDirectory, source);
using var templateFileReader = new StreamReader(templatePath);
var templateString = templateReader.ReadToEnd();
using var templateReader = new TemplateReader(templateString, ResolveTileset, ResolveTemplate, ResolveCustomType);
return templateReader.ReadTemplate();
}
ICustomTypeDefinition ResolveCustomType(string name)
{
var allDefinedTypes = [ ... ];
return allDefinedTypes.FirstOrDefault(type => type.Name == name);
}
using var mapFileReader = new StreamReader(mapPath);
var mapString = mapFileReader.ReadToEnd();
using var mapReader = new MapReader(mapString, ResolveTileset, ResolveTemplate, ResolveCustomType);
var map = mapReader.ReadMap();
``` ```
If the above looks intimidating, don't worry! DotTiled is designed to be flexible and allow you to load maps from any source, such as a database or a custom file format. The above example is just one way to load a map from a file system. Please look at [Loading Maps](essentials/loading-maps.md) for more information on how to load maps from different sources. Or fully qualify all `DotTiled` types e.g. `DotTiled.Loader`.
## Loading a map from the file system
This will create a loader that will load files from the underlying file system using <xref:DotTiled.Serialization.FileSystemResourceReader>. It will also be configured to use an in-memory cache to avoid loading the same tileset or template multiple times using <xref:DotTiled.Serialization.DefaultResourceCache>.
```csharp
var loader = Loader.Default();
var map = loader.LoadMap("path/to/map.tmx");
```
## Loading a map from a different source
If you want to load resources (maps, tilesets, templates) from a different source than the underlying file system, you can override the <xref:DotTiled.Serialization.FileSystemResourceReader> that is being used with your own implementation of <xref:DotTiled.Serialization.IResourceReader>.
```csharp
var loader = Loader.DefaultWith(
resourceReader: new MyCustomResourceReader());
var map = loader.LoadMap("path/to/map.tmx");
```
## Caching resources
Similarly, you can override the <xref:DotTiled.Serialization.DefaultResourceCache> that is being used with your own implementation of <xref:DotTiled.Serialization.IResourceCache>.
```csharp
var loader = Loader.DefaultWith(
resourceReader: new MyCustomResourceReader(),
resourceCache: new MyCustomResourceCache());
var map = loader.LoadMap("path/to/map.tmx");
```
## Custom types
If you have custom types in your map, you can provide any `IEnumerable<ICustomTypeDefinition>` to the loader. This will allow the loader to deserialize the custom types in your map.
```csharp
var monsterSpawnerDef = new CustomClassDefinition { ... };
var chestDef = new CustomClassDefinition
{
Name = "Chest",
UseAs = CustomClassUseAs.All,
Members = [
new IntProperty { Name = "coins", Value = 0 },
new BoolProperty { Name = "locked", Value = true }
]
};
var loader = Loader.DefaultWith(
customTypeDefinitions: [monsterSpawnerDef, chestDef]);
var map = loader.LoadMap("path/to/map.tmx");
var chest = map.GetProperty<CustomClassProperty>("chest").Value;
var coinsToSpawn = chest.GetProperty<IntProperty>("coins").Value;
```

View file

@ -4,4 +4,5 @@
- name: Essentials - name: Essentials
- href: essentials/loading-maps.md - href: essentials/loading-maps.md
- href: essentials/representation-model.md
- href: essentials/custom-properties.md - href: essentials/custom-properties.md

9
docs/template/public/main.js vendored Normal file
View file

@ -0,0 +1,9 @@
export default {
iconLinks: [
{
icon: 'github',
href: 'https://github.com/dcronqvist/DotTiled',
title: 'GitHub'
}
]
}

View file

@ -15,10 +15,10 @@ namespace DotTiled.Benchmark
[HideColumns(["StdDev", "Error", "RatioSD"])] [HideColumns(["StdDev", "Error", "RatioSD"])]
public class MapLoading public class MapLoading
{ {
private readonly string _tmxPath = @"DotTiled.Tests/Serialization/TestData/Map/default-map/default-map.tmx"; private readonly string _tmxPath = @"DotTiled.Tests/TestData/Maps/default-map/default-map.tmx";
private readonly string _tmxContents = ""; private readonly string _tmxContents = "";
private readonly string _tmjPath = @"DotTiled.Tests/Serialization/TestData/Map/default-map/default-map.tmj"; private readonly string _tmjPath = @"DotTiled.Tests/TestData/Maps/default-map/default-map.tmj";
private readonly string _tmjContents = ""; private readonly string _tmjContents = "";
public MapLoading() public MapLoading()

View file

@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\DotTiled\DotTiled.csproj" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="tilemap.tmx" />
<EmbeddedResource Include="tileset.png" />
<EmbeddedResource Include="tileset.tsx" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,84 @@
using System.Reflection;
using DotTiled.Serialization;
namespace DotTiled.Example;
public class Program
{
private static void Main(string[] args)
{
Quick(args[0]);
Manual();
}
// QUICK START
// Automatic and easy way to load tilemaps.
private static void Quick(string basePath)
{
var tilemapPath = Path.Combine(basePath, "tilemap.tmx");
var loader = Loader.Default();
var map = loader.LoadMap(tilemapPath);
// You can do stuff with it like...
Console.WriteLine($"Tile width and height: {map.TileWidth}x{map.TileHeight}");
TileLayer layer0 = (TileLayer)map.Layers[0]; // Get a layer
Console.WriteLine($"Tile in layer 0 at 0, 0: {layer0.Data.Value.GlobalTileIDs.Value[0]}");
}
// MANUAL
// Manually load a map, if you need to load from a custom source
private static void Manual()
{
using Stream? tilemapStream = Assembly.GetExecutingAssembly().GetManifestResourceStream($"DotTiled.Example.Console.tilemap.tmx")
?? throw new FileLoadException($"DotTiled.Example.Console.tilemap.tmx not found in assembly.");
string tileMapString = new StreamReader(tilemapStream).ReadToEnd();
using var mapReader = new MapReader(tileMapString, ResolveTileset, ResolveTemplate, ResolveCustomType);
var map = mapReader.ReadMap();
// Now do some other stuff with it...
StringProperty hello = map.GetProperty<StringProperty>("hello");
Console.WriteLine($"Layer 1 name: {map.Layers[0].Name}");
Console.WriteLine($"Property 'hello': {hello.Value}");
// Now with tileset
Tileset tileset = map.Tilesets[0];
Console.WriteLine($"Tileset 0 source: {tileset.Source.Value}");
Console.WriteLine($"Tileset 0 image 0 source: {tileset.Image.Value.Source.Value}");
}
// This function is responsible for loading all tilesets required by a tilemap, if you
// want to use a custom source.
private static Tileset ResolveTileset(string source)
{
// Read a file from assembly
// You can use any other source for files, eg. compressed archive, or even file from internet.
using Stream? tilesetStream = Assembly.GetExecutingAssembly().GetManifestResourceStream($"DotTiled.Example.Console.{source}")
?? throw new FileLoadException($"{source} not found in assembly.");
string tilesetString = new StreamReader(tilesetStream).ReadToEnd();
using TilesetReader tilesetReader = new TilesetReader(tilesetString, ResolveTileset, ResolveTemplate, ResolveCustomType); // Parse loaded tileset.
return tilesetReader.ReadTileset(); // Return loaded tileset
}
// This is pretty similar to above, but instead it loads templates, not tilesets.
private static Template ResolveTemplate(string source)
{
using Stream? templateStream = Assembly.GetExecutingAssembly().GetManifestResourceStream($"DotTiled.Example.Console.{source}")
?? throw new FileLoadException($"{source} not found in assembly.");
string templateString = new StreamReader(templateStream).ReadToEnd();
using TemplateReader templateReader = new TemplateReader(templateString, ResolveTileset, ResolveTemplate, ResolveCustomType);
return templateReader.ReadTemplate();
}
private static Optional<ICustomTypeDefinition> ResolveCustomType(string name)
{
ICustomTypeDefinition[] allDefinedTypes =
[
new CustomClassDefinition() { Name = "a" },
];
return allDefinedTypes.FirstOrDefault(ctd => ctd.Name == name) is ICustomTypeDefinition ctd ? new Optional<ICustomTypeDefinition>(ctd) : Optional<ICustomTypeDefinition>.Empty;
}
}

View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.11.0" orientation="orthogonal" renderorder="right-down" width="10" height="10" tilewidth="16" tileheight="16" infinite="0" nextlayerid="5" nextobjectid="1">
<properties>
<property name="hello" value="Hello from DotTiled!"/>
</properties>
<tileset firstgid="1" source="tileset.tsx"/>
<layer id="1" name="Tile Layer 1" width="10" height="10">
<data encoding="base64">
AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAA==
</data>
</layer>
</map>

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 B

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<tileset version="1.8" tiledversion="1.10.2" name="tileset" tilewidth="16" tileheight="16" tilecount="1" columns="1">
<image source="tileset.png" width="16" height="16"/>
</tileset>

View file

@ -0,0 +1,2 @@
# Normalize EOL for all files that Git considers text files.
* text=auto eol=lf

View file

@ -0,0 +1,2 @@
# Godot 4+ specific ignores
.godot/

View file

@ -0,0 +1,11 @@
<Project Sdk="Godot.NET.Sdk/4.3.0">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework Condition=" '$(GodotTargetPlatform)' == 'android' ">net7.0</TargetFramework>
<TargetFramework Condition=" '$(GodotTargetPlatform)' == 'ios' ">net8.0</TargetFramework>
<EnableDynamicLoading>true</EnableDynamicLoading>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\DotTiled\DotTiled.csproj" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,19 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2012
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotTiled.Example.Godot", "DotTiled.Example.Godot.csproj", "{61468FCF-ACC1-4E3B-B4B4-270279E45BF5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
ExportDebug|Any CPU = ExportDebug|Any CPU
ExportRelease|Any CPU = ExportRelease|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{61468FCF-ACC1-4E3B-B4B4-270279E45BF5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{61468FCF-ACC1-4E3B-B4B4-270279E45BF5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{61468FCF-ACC1-4E3B-B4B4-270279E45BF5}.ExportDebug|Any CPU.ActiveCfg = ExportDebug|Any CPU
{61468FCF-ACC1-4E3B-B4B4-270279E45BF5}.ExportDebug|Any CPU.Build.0 = ExportDebug|Any CPU
{61468FCF-ACC1-4E3B-B4B4-270279E45BF5}.ExportRelease|Any CPU.ActiveCfg = ExportRelease|Any CPU
{61468FCF-ACC1-4E3B-B4B4-270279E45BF5}.ExportRelease|Any CPU.Build.0 = ExportRelease|Any CPU
EndGlobalSection
EndGlobal

View file

@ -0,0 +1,67 @@
using System.Globalization;
using System.Linq;
using DotTiled.Serialization;
using Godot;
namespace DotTiled.Example.Godot;
public partial class MapParser : Node2D
{
public override void _Ready()
{
// Load map
var mapString = FileAccess.Open("res://tilemap.tmx", FileAccess.ModeFlags.Read).GetAsText(); //Get file from Godot filesystem
using var mapReader = new MapReader(mapString, ResolveTileset, ResolveTemplate, ResolveCustomType);
var map = mapReader.ReadMap();
TileLayer layer0 = (TileLayer)map.Layers[0];
for (int y = 0; y < layer0.Height; y++)
{
for (int x = 0; x < layer0.Width; x++)
{
uint tile = layer0.Data.Value.GlobalTileIDs.Value[(y * layer0.Width) + x];
if (tile == 0) continue; // If block is 0, i.e. air, then continue
// Load actual block from Godot resources
Node2D block = (Node2D)GD.Load<PackedScene>($"res://blocks/{tile}.tscn").Instantiate();
// Calculate where block should be
Vector2I scale = (Vector2I)block.GetNode<Sprite2D>(tile.ToString(CultureInfo.CurrentCulture)).Scale;
int blockX = (block.GetNode<Sprite2D>(tile.ToString(CultureInfo.CurrentCulture)).Texture.GetWidth() * scale.X / 2) +
(x * block.GetNode<Sprite2D>(tile.ToString(CultureInfo.CurrentCulture)).Texture.GetWidth() * scale.X);
int blockY = (block.GetNode<Sprite2D>(tile.ToString(CultureInfo.CurrentCulture)).Texture.GetHeight() * scale.Y / 2) +
(y * block.GetNode<Sprite2D>(tile.ToString(CultureInfo.CurrentCulture)).Texture.GetHeight() * scale.Y);
block.Position = new Vector2(blockX, blockY);
// Add block to current scene
AddChild(block);
GD.Print($"{blockX}, {blockY}: {tile}");
}
}
}
private Tileset ResolveTileset(string source)
{
string tilesetString = FileAccess.Open($"res://{source}", FileAccess.ModeFlags.Read).GetAsText();
using TilesetReader tilesetReader =
new TilesetReader(tilesetString, ResolveTileset, ResolveTemplate, ResolveCustomType);
return tilesetReader.ReadTileset();
}
private Template ResolveTemplate(string source)
{
string templateString = FileAccess.Open($"res://{source}", FileAccess.ModeFlags.Read).GetAsText();
using TemplateReader templateReader =
new TemplateReader(templateString, ResolveTileset, ResolveTemplate, ResolveCustomType);
return templateReader.ReadTemplate();
}
private static Optional<ICustomTypeDefinition> ResolveCustomType(string name)
{
ICustomTypeDefinition[] allDefinedTypes =
[
new CustomClassDefinition() { Name = "a" },
];
return allDefinedTypes.FirstOrDefault(ctd => ctd.Name == name) is ICustomTypeDefinition ctd ? new Optional<ICustomTypeDefinition>(ctd) : Optional<ICustomTypeDefinition>.Empty;
}
}

View file

@ -0,0 +1,9 @@
[gd_scene load_steps=2 format=3 uid="uid://ce10iald4cb3f"]
[ext_resource type="Texture2D" uid="uid://da08vay832u8c" path="res://tileset.png" id="1_c5fs4"]
[node name="1" type="Node2D"]
[node name="1" type="Sprite2D" parent="."]
scale = Vector2(2, 2)
texture = ExtResource("1_c5fs4")

View file

@ -0,0 +1 @@
<svg height="128" width="128" xmlns="http://www.w3.org/2000/svg"><rect x="2" y="2" width="124" height="124" rx="14" fill="#363d52" stroke="#212532" stroke-width="4"/><g transform="scale(.101) translate(122 122)"><g fill="#fff"><path d="M105 673v33q407 354 814 0v-33z"/><path d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 814 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H446l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z" fill="#478cbf"/><path d="M483 600c0 34 58 34 58 0v-86c0-34-58-34-58 0z"/><circle cx="725" cy="526" r="90"/><circle cx="299" cy="526" r="90"/></g><g fill="#414042"><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g></g></svg>

After

Width:  |  Height:  |  Size: 949 B

View file

@ -0,0 +1,37 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://0kywmrvvqqyr"
path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://icon.svg"
dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=false
editor/convert_colors_with_editor_theme=false

View file

@ -0,0 +1,6 @@
[gd_scene load_steps=2 format=3 uid="uid://p4rpwsvyslew"]
[ext_resource type="Script" path="res://MapParser.cs" id="1_xjmxv"]
[node name="Node2D" type="Node2D"]
script = ExtResource("1_xjmxv")

View file

@ -0,0 +1,20 @@
; Engine configuration file.
; It's best edited using the editor UI and not directly,
; since the parameters that go here are not all obvious.
;
; Format:
; [section] ; section goes between []
; param=value ; assign values to parameters
config_version=5
[application]
config/name="DotTiled.Example.Godot"
run/main_scene="res://main.tscn"
config/features=PackedStringArray("4.3", "C#", "Forward Plus")
config/icon="res://icon.svg"
[dotnet]
project/assembly_name="DotTiled.Example.Godot"

View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.11.0" orientation="orthogonal" renderorder="right-down" width="10" height="10" tilewidth="16" tileheight="16" infinite="0" nextlayerid="5" nextobjectid="1">
<properties>
<property name="hello" value="Hello from DotTiled!"/>
</properties>
<tileset firstgid="1" source="tileset.tsx"/>
<layer id="1" name="Tile Layer 1" width="10" height="10">
<data encoding="base64">
AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAA==
</data>
</layer>
</map>

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 B

View file

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://da08vay832u8c"
path="res://.godot/imported/tileset.png-a39e944f25b35d62f55d4f98a36e2b5e.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://tileset.png"
dest_files=["res://.godot/imported/tileset.png-a39e944f25b35d62f55d4f98a36e2b5e.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<tileset version="1.8" tiledversion="1.10.2" name="tileset" tilewidth="16" tileheight="16" tilecount="1" columns="1">
<image source="tileset.png" width="16" height="16"/>
</tileset>

View file

@ -0,0 +1,23 @@
namespace DotTiled.Tests;
public static partial class DotTiledAssert
{
internal static void AssertCustomClassDefinitionEqual(CustomClassDefinition expected, CustomClassDefinition actual)
{
AssertEqual(expected.ID, actual.ID, nameof(CustomClassDefinition.ID));
AssertEqual(expected.Name, actual.Name, nameof(CustomClassDefinition.Name));
AssertEqual(expected.Color, actual.Color, nameof(CustomClassDefinition.Color));
AssertEqual(expected.DrawFill, actual.DrawFill, nameof(CustomClassDefinition.DrawFill));
AssertEqual(expected.UseAs, actual.UseAs, nameof(CustomClassDefinition.UseAs));
AssertProperties(expected.Members, actual.Members);
}
internal static void AssertCustomEnumDefinitionEqual(CustomEnumDefinition expected, CustomEnumDefinition actual)
{
AssertEqual(expected.ID, actual.ID, nameof(CustomEnumDefinition.ID));
AssertEqual(expected.Name, actual.Name, nameof(CustomEnumDefinition.Name));
AssertEqual(expected.StorageType, actual.StorageType, nameof(CustomEnumDefinition.StorageType));
AssertEqual(expected.ValueAsFlags, actual.ValueAsFlags, nameof(CustomEnumDefinition.ValueAsFlags));
AssertListOrdered(expected.Values, actual.Values, nameof(CustomEnumDefinition.Values));
}
}

View file

@ -2,7 +2,7 @@ namespace DotTiled.Tests;
public static partial class DotTiledAssert public static partial class DotTiledAssert
{ {
internal static void AssertData(Data? expected, Data? actual) internal static void AssertData(Data expected, Data actual)
{ {
if (expected is null) if (expected is null)
{ {
@ -18,14 +18,7 @@ public static partial class DotTiledAssert
// Data // Data
AssertEqual(expected.GlobalTileIDs, actual.GlobalTileIDs, nameof(Data.GlobalTileIDs)); AssertEqual(expected.GlobalTileIDs, actual.GlobalTileIDs, nameof(Data.GlobalTileIDs));
AssertEqual(expected.FlippingFlags, actual.FlippingFlags, nameof(Data.FlippingFlags)); AssertEqual(expected.FlippingFlags, actual.FlippingFlags, nameof(Data.FlippingFlags));
AssertOptionalsEqual(expected.Chunks, actual.Chunks, nameof(Data.Chunks), (a, b) => AssertListOrdered(a, b, nameof(Chunk), AssertChunk));
if (expected.Chunks is not null)
{
Assert.NotNull(actual.Chunks);
AssertEqual(expected.Chunks.Length, actual.Chunks.Length, "Chunks.Length");
for (var i = 0; i < expected.Chunks.Length; i++)
AssertChunk(expected.Chunks[i], actual.Chunks[i]);
}
} }
private static void AssertChunk(Chunk expected, Chunk actual) private static void AssertChunk(Chunk expected, Chunk actual)

View file

@ -2,7 +2,7 @@ namespace DotTiled.Tests;
public static partial class DotTiledAssert public static partial class DotTiledAssert
{ {
internal static void AssertImage(Image? expected, Image? actual) internal static void AssertImage(Image expected, Image actual)
{ {
if (expected is null) if (expected is null)
{ {

View file

@ -2,7 +2,7 @@ namespace DotTiled.Tests;
public static partial class DotTiledAssert public static partial class DotTiledAssert
{ {
internal static void AssertLayer(BaseLayer? expected, BaseLayer? actual) internal static void AssertLayer(BaseLayer expected, BaseLayer actual)
{ {
if (expected is null) if (expected is null)
{ {

View file

@ -5,7 +5,69 @@ namespace DotTiled.Tests;
public static partial class DotTiledAssert public static partial class DotTiledAssert
{ {
private static void AssertEqual<T>(T expected, T actual, string nameof) internal static void AssertListOrdered<T>(IList<T> expected, IList<T> actual, string nameof, Action<T, T> assertEqual = null)
{
if (expected is null)
{
Assert.Null(actual);
return;
}
Assert.NotNull(actual);
AssertEqual(expected.Count, actual.Count, $"{nameof}.Count");
for (var i = 0; i < expected.Count; i++)
{
if (assertEqual is not null)
{
assertEqual(expected[i], actual[i]);
continue;
}
AssertEqual(expected[i], actual[i], $"{nameof}[{i}]");
}
}
internal static void AssertOptionalsEqual<T>(
Optional<T> expected,
Optional<T> actual,
string nameof,
Action<T, T> assertEqual)
{
if (expected is null)
{
Assert.Null(actual);
return;
}
if (expected.HasValue)
{
Assert.True(actual.HasValue, $"Expected {nameof} to have a value");
assertEqual(expected.Value, actual.Value);
return;
}
Assert.False(actual.HasValue, $"Expected {nameof} to not have a value");
}
internal static void AssertEqual<T>(Optional<T> expected, Optional<T> actual, string nameof)
{
if (expected is null)
{
Assert.Null(actual);
return;
}
if (expected.HasValue)
{
Assert.True(actual.HasValue, $"Expected {nameof} to have a value");
AssertEqual(expected.Value, actual.Value, nameof);
return;
}
Assert.False(actual.HasValue, $"Expected {nameof} to not have a value");
}
internal static void AssertEqual<T>(T expected, T actual, string nameof)
{ {
if (expected == null) if (expected == null)
{ {

View file

@ -2,7 +2,7 @@ namespace DotTiled.Tests;
public static partial class DotTiledAssert public static partial class DotTiledAssert
{ {
internal static void AssertProperties(IList<IProperty>? expected, IList<IProperty>? actual) internal static void AssertProperties(IList<IProperty> expected, IList<IProperty> actual)
{ {
if (expected is null) if (expected is null)
{ {

View file

@ -4,7 +4,6 @@ public static partial class DotTiledAssert
{ {
internal static void AssertTileset(Tileset expected, Tileset actual) internal static void AssertTileset(Tileset expected, Tileset actual)
{ {
// Attributes
AssertEqual(expected.Version, actual.Version, nameof(Tileset.Version)); AssertEqual(expected.Version, actual.Version, nameof(Tileset.Version));
AssertEqual(expected.TiledVersion, actual.TiledVersion, nameof(Tileset.TiledVersion)); AssertEqual(expected.TiledVersion, actual.TiledVersion, nameof(Tileset.TiledVersion));
AssertEqual(expected.FirstGID, actual.FirstGID, nameof(Tileset.FirstGID)); AssertEqual(expected.FirstGID, actual.FirstGID, nameof(Tileset.FirstGID));
@ -21,29 +20,16 @@ public static partial class DotTiledAssert
AssertEqual(expected.RenderSize, actual.RenderSize, nameof(Tileset.RenderSize)); AssertEqual(expected.RenderSize, actual.RenderSize, nameof(Tileset.RenderSize));
AssertEqual(expected.FillMode, actual.FillMode, nameof(Tileset.FillMode)); AssertEqual(expected.FillMode, actual.FillMode, nameof(Tileset.FillMode));
// At most one of AssertOptionalsEqual(expected.Image, actual.Image, nameof(Tileset.Image), AssertImage);
AssertImage(expected.Image, actual.Image); AssertOptionalsEqual(expected.TileOffset, actual.TileOffset, nameof(Tileset.TileOffset), AssertTileOffset);
AssertTileOffset(expected.TileOffset, actual.TileOffset); AssertOptionalsEqual(expected.Grid, actual.Grid, nameof(Tileset.Grid), AssertGrid);
AssertGrid(expected.Grid, actual.Grid);
AssertProperties(expected.Properties, actual.Properties); AssertProperties(expected.Properties, actual.Properties);
// TODO: AssertTerrainTypes(actual.TerrainTypes, expected.TerrainTypes); AssertListOrdered(expected.Wangsets, actual.Wangsets, nameof(Tileset.Wangsets), AssertWangset);
if (expected.Wangsets is not null) AssertOptionalsEqual(expected.Transformations, actual.Transformations, nameof(Tileset.Transformations), AssertTransformations);
{ AssertListOrdered(expected.Tiles, actual.Tiles, nameof(Tileset.Tiles), AssertTile);
Assert.NotNull(actual.Wangsets);
AssertEqual(expected.Wangsets.Count, actual.Wangsets.Count, "Wangsets.Count");
for (var i = 0; i < expected.Wangsets.Count; i++)
AssertWangset(expected.Wangsets[i], actual.Wangsets[i]);
}
AssertTransformations(expected.Transformations, actual.Transformations);
// Any number of
Assert.NotNull(actual.Tiles);
AssertEqual(expected.Tiles.Count, actual.Tiles.Count, "Tiles.Count");
for (var i = 0; i < expected.Tiles.Count; i++)
AssertTile(expected.Tiles[i], actual.Tiles[i]);
} }
private static void AssertTileOffset(TileOffset? expected, TileOffset? actual) private static void AssertTileOffset(TileOffset expected, TileOffset actual)
{ {
if (expected is null) if (expected is null)
{ {
@ -57,7 +43,7 @@ public static partial class DotTiledAssert
AssertEqual(expected.Y, actual.Y, nameof(TileOffset.Y)); AssertEqual(expected.Y, actual.Y, nameof(TileOffset.Y));
} }
private static void AssertGrid(Grid? expected, Grid? actual) private static void AssertGrid(Grid expected, Grid actual)
{ {
if (expected is null) if (expected is null)
{ {
@ -74,27 +60,17 @@ public static partial class DotTiledAssert
private static void AssertWangset(Wangset expected, Wangset actual) private static void AssertWangset(Wangset expected, Wangset actual)
{ {
// Attributes
AssertEqual(expected.Name, actual.Name, nameof(Wangset.Name)); AssertEqual(expected.Name, actual.Name, nameof(Wangset.Name));
AssertEqual(expected.Class, actual.Class, nameof(Wangset.Class)); AssertEqual(expected.Class, actual.Class, nameof(Wangset.Class));
AssertEqual(expected.Tile, actual.Tile, nameof(Wangset.Tile)); AssertEqual(expected.Tile, actual.Tile, nameof(Wangset.Tile));
// At most one of
AssertProperties(expected.Properties, actual.Properties); AssertProperties(expected.Properties, actual.Properties);
if (expected.WangColors is not null) AssertListOrdered(expected.WangColors, actual.WangColors, nameof(Wangset.WangColors), AssertWangColor);
{ AssertListOrdered(expected.WangTiles, actual.WangTiles, nameof(Wangset.WangTiles), AssertWangTile);
Assert.NotNull(actual.WangColors);
AssertEqual(expected.WangColors.Count, actual.WangColors.Count, "WangColors.Count");
for (var i = 0; i < expected.WangColors.Count; i++)
AssertWangColor(expected.WangColors[i], actual.WangColors[i]);
}
for (var i = 0; i < expected.WangTiles.Count; i++)
AssertWangTile(expected.WangTiles[i], actual.WangTiles[i]);
} }
private static void AssertWangColor(WangColor expected, WangColor actual) private static void AssertWangColor(WangColor expected, WangColor actual)
{ {
// Attributes
AssertEqual(expected.Name, actual.Name, nameof(WangColor.Name)); AssertEqual(expected.Name, actual.Name, nameof(WangColor.Name));
AssertEqual(expected.Class, actual.Class, nameof(WangColor.Class)); AssertEqual(expected.Class, actual.Class, nameof(WangColor.Class));
AssertEqual(expected.Color, actual.Color, nameof(WangColor.Color)); AssertEqual(expected.Color, actual.Color, nameof(WangColor.Color));
@ -106,12 +82,11 @@ public static partial class DotTiledAssert
private static void AssertWangTile(WangTile expected, WangTile actual) private static void AssertWangTile(WangTile expected, WangTile actual)
{ {
// Attributes
AssertEqual(expected.TileID, actual.TileID, nameof(WangTile.TileID)); AssertEqual(expected.TileID, actual.TileID, nameof(WangTile.TileID));
AssertEqual(expected.WangID, actual.WangID, nameof(WangTile.WangID)); AssertEqual(expected.WangID, actual.WangID, nameof(WangTile.WangID));
} }
private static void AssertTransformations(Transformations? expected, Transformations? actual) private static void AssertTransformations(Transformations expected, Transformations actual)
{ {
if (expected is null) if (expected is null)
{ {
@ -119,7 +94,6 @@ public static partial class DotTiledAssert
return; return;
} }
// Attributes
Assert.NotNull(actual); Assert.NotNull(actual);
AssertEqual(expected.HFlip, actual.HFlip, nameof(Transformations.HFlip)); AssertEqual(expected.HFlip, actual.HFlip, nameof(Transformations.HFlip));
AssertEqual(expected.VFlip, actual.VFlip, nameof(Transformations.VFlip)); AssertEqual(expected.VFlip, actual.VFlip, nameof(Transformations.VFlip));
@ -129,7 +103,6 @@ public static partial class DotTiledAssert
private static void AssertTile(Tile expected, Tile actual) private static void AssertTile(Tile expected, Tile actual)
{ {
// Attributes
AssertEqual(expected.ID, actual.ID, nameof(Tile.ID)); AssertEqual(expected.ID, actual.ID, nameof(Tile.ID));
AssertEqual(expected.Type, actual.Type, nameof(Tile.Type)); AssertEqual(expected.Type, actual.Type, nameof(Tile.Type));
AssertEqual(expected.Probability, actual.Probability, nameof(Tile.Probability)); AssertEqual(expected.Probability, actual.Probability, nameof(Tile.Probability));
@ -138,22 +111,14 @@ public static partial class DotTiledAssert
AssertEqual(expected.Width, actual.Width, nameof(Tile.Width)); AssertEqual(expected.Width, actual.Width, nameof(Tile.Width));
AssertEqual(expected.Height, actual.Height, nameof(Tile.Height)); AssertEqual(expected.Height, actual.Height, nameof(Tile.Height));
// Elements
AssertProperties(expected.Properties, actual.Properties); AssertProperties(expected.Properties, actual.Properties);
AssertImage(expected.Image, actual.Image); AssertOptionalsEqual(expected.Image, actual.Image, nameof(Tile.Image), AssertImage);
AssertLayer((BaseLayer?)expected.ObjectLayer, (BaseLayer?)actual.ObjectLayer); AssertOptionalsEqual(expected.ObjectLayer, actual.ObjectLayer, nameof(Tile.ObjectLayer), (a, b) => AssertLayer((BaseLayer)a, (BaseLayer)b));
if (expected.Animation is not null) AssertListOrdered(expected.Animation, actual.Animation, nameof(Tile.Animation), AssertFrame);
{
Assert.NotNull(actual.Animation);
AssertEqual(expected.Animation.Count, actual.Animation.Count, "Animation.Count");
for (var i = 0; i < expected.Animation.Count; i++)
AssertFrame(expected.Animation[i], actual.Animation[i]);
}
} }
private static void AssertFrame(Frame expected, Frame actual) private static void AssertFrame(Frame expected, Frame actual)
{ {
// Attributes
AssertEqual(expected.TileID, actual.TileID, nameof(Frame.TileID)); AssertEqual(expected.TileID, actual.TileID, nameof(Frame.TileID));
AssertEqual(expected.Duration, actual.Duration, nameof(Frame.Duration)); AssertEqual(expected.Duration, actual.Duration, nameof(Frame.Duration));
} }

View file

@ -3,7 +3,6 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject> <IsTestProject>true</IsTestProject>
@ -12,6 +11,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.0" /> <PackageReference Include="coverlet.collector" Version="6.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="NSubstitute" Version="5.1.0" />
<PackageReference Include="xunit" Version="2.5.3" /> <PackageReference Include="xunit" Version="2.5.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.5.3" />
</ItemGroup> </ItemGroup>
@ -26,7 +26,12 @@
<ItemGroup> <ItemGroup>
<!-- Test data --> <!-- Test data -->
<EmbeddedResource Include="Serialization/TestData/**/*" /> <EmbeddedResource Include="TestData/**/*.tmx" />
<EmbeddedResource Include="TestData/**/*.tmj" />
<EmbeddedResource Include="TestData/**/*.tsx" />
<EmbeddedResource Include="TestData/**/*.tsj" />
<EmbeddedResource Include="TestData/**/*.tx" />
<EmbeddedResource Include="TestData/**/*.tj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View file

@ -0,0 +1,272 @@
using DotTiled.Serialization;
using NSubstitute;
namespace DotTiled.Tests;
public class FromTypeUsedInLoaderTests
{
private sealed class TestClass
{
public string Name { get; set; } = "John Doe";
public int Age { get; set; } = 42;
}
[Fact]
public void LoadMap_MapHasClassAndClassIsDefined_ReturnsCorrectMap()
{
// Arrange
var resourceReader = Substitute.For<IResourceReader>();
resourceReader.Read("map.tmx").Returns(
"""
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.11.0" class="TestClass" orientation="orthogonal" renderorder="right-down" width="5" height="5" tilewidth="32" tileheight="32" infinite="0" nextlayerid="2" nextobjectid="1">
<layer id="1" name="Tile Layer 1" width="5" height="5">
<data encoding="csv">
0,0,0,0,0,
0,0,0,0,0,
0,0,0,0,0,
0,0,0,0,0,
0,0,0,0,0
</data>
</layer>
</map>
""");
var classDefinition = CustomClassDefinition.FromClass<TestClass>();
var loader = Loader.DefaultWith(
resourceReader: resourceReader,
customTypeDefinitions: [classDefinition]);
var expectedMap = new Map
{
Class = "TestClass",
Orientation = MapOrientation.Orthogonal,
Width = 5,
Height = 5,
TileWidth = 32,
TileHeight = 32,
Infinite = false,
ParallaxOriginX = 0,
ParallaxOriginY = 0,
RenderOrder = RenderOrder.RightDown,
CompressionLevel = -1,
BackgroundColor = new Color { R = 0, G = 0, B = 0, A = 0 },
Version = "1.10",
TiledVersion = "1.11.0",
NextLayerID = 2,
NextObjectID = 1,
Layers = [
new TileLayer
{
ID = 1,
Name = "Tile Layer 1",
Width = 5,
Height = 5,
Data = new Data
{
Encoding = DataEncoding.Csv,
GlobalTileIDs = new Optional<uint[]>([
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0
]),
FlippingFlags = new Optional<FlippingFlags[]>([
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None
])
}
}
],
Properties = [
new StringProperty { Name = "Name", Value = "John Doe" },
new IntProperty { Name = "Age", Value = 42 }
]
};
// Act
var result = loader.LoadMap("map.tmx");
// Assert
DotTiledAssert.AssertMap(expectedMap, result);
}
[Fact]
public void LoadMap_MapHasClassAndClassIsDefinedAndFieldIsOverridenFromDefault_ReturnsCorrectMap()
{
// Arrange
var resourceReader = Substitute.For<IResourceReader>();
resourceReader.Read("map.tmx").Returns(
"""
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.11.0" class="TestClass" orientation="orthogonal" renderorder="right-down" width="5" height="5" tilewidth="32" tileheight="32" infinite="0" nextlayerid="2" nextobjectid="1">
<properties>
<property name="Name" value="John Doe"/>
</properties>
<layer id="1" name="Tile Layer 1" width="5" height="5">
<data encoding="csv">
0,0,0,0,0,
0,0,0,0,0,
0,0,0,0,0,
0,0,0,0,0,
0,0,0,0,0
</data>
</layer>
</map>
""");
var classDefinition = CustomClassDefinition.FromClass<TestClass>();
var loader = Loader.DefaultWith(
resourceReader: resourceReader,
customTypeDefinitions: [classDefinition]);
var expectedMap = new Map
{
Class = "TestClass",
Orientation = MapOrientation.Orthogonal,
Width = 5,
Height = 5,
TileWidth = 32,
TileHeight = 32,
Infinite = false,
ParallaxOriginX = 0,
ParallaxOriginY = 0,
RenderOrder = RenderOrder.RightDown,
CompressionLevel = -1,
BackgroundColor = new Color { R = 0, G = 0, B = 0, A = 0 },
Version = "1.10",
TiledVersion = "1.11.0",
NextLayerID = 2,
NextObjectID = 1,
Layers = [
new TileLayer
{
ID = 1,
Name = "Tile Layer 1",
Width = 5,
Height = 5,
Data = new Data
{
Encoding = DataEncoding.Csv,
GlobalTileIDs = new Optional<uint[]>([
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0
]),
FlippingFlags = new Optional<FlippingFlags[]>([
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None
])
}
}
],
Properties = [
new StringProperty { Name = "Name", Value = "John Doe" },
new IntProperty { Name = "Age", Value = 42 }
]
};
// Act
var result = loader.LoadMap("map.tmx");
// Assert
DotTiledAssert.AssertMap(expectedMap, result);
}
private enum TestEnum
{
Value1,
Value2
}
private sealed class TestClassWithEnum
{
public TestEnum Enum { get; set; } = TestEnum.Value1;
}
[Fact]
public void LoadMap_MapHasClassWithEnumAndClassIsDefined_ReturnsCorrectMap()
{
// Arrange
var resourceReader = Substitute.For<IResourceReader>();
resourceReader.Read("map.tmx").Returns(
"""
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.11.0" class="TestClassWithEnum" orientation="orthogonal" renderorder="right-down" width="5" height="5" tilewidth="32" tileheight="32" infinite="0" nextlayerid="2" nextobjectid="1">
<layer id="1" name="Tile Layer 1" width="5" height="5">
<data encoding="csv">
0,0,0,0,0,
0,0,0,0,0,
0,0,0,0,0,
0,0,0,0,0,
0,0,0,0,0
</data>
</layer>
</map>
""");
var classDefinition = CustomClassDefinition.FromClass<TestClassWithEnum>();
var loader = Loader.DefaultWith(
resourceReader: resourceReader,
customTypeDefinitions: [classDefinition]);
var expectedMap = new Map
{
Class = "TestClassWithEnum",
Orientation = MapOrientation.Orthogonal,
Width = 5,
Height = 5,
TileWidth = 32,
TileHeight = 32,
Infinite = false,
ParallaxOriginX = 0,
ParallaxOriginY = 0,
RenderOrder = RenderOrder.RightDown,
CompressionLevel = -1,
BackgroundColor = new Color { R = 0, G = 0, B = 0, A = 0 },
Version = "1.10",
TiledVersion = "1.11.0",
NextLayerID = 2,
NextObjectID = 1,
Layers = [
new TileLayer
{
ID = 1,
Name = "Tile Layer 1",
Width = 5,
Height = 5,
Data = new Data
{
Encoding = DataEncoding.Csv,
GlobalTileIDs = new Optional<uint[]>([
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0
]),
FlippingFlags = new Optional<FlippingFlags[]>([
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None
])
}
}
],
Properties = [
new EnumProperty { Name = "Enum", PropertyType = "TestEnum", Value = new HashSet<string> { "Value1" } }
]
};
// Act
var result = loader.LoadMap("map.tmx");
// Assert
DotTiledAssert.AssertMap(expectedMap, result);
}
}

View file

@ -1,45 +0,0 @@
using System.Xml;
namespace DotTiled.Tests;
public static partial class TestData
{
public static XmlReader GetXmlReaderFor(string testDataFile)
{
var fullyQualifiedTestDataFile = $"DotTiled.Tests.{ConvertPathToAssemblyResourcePath(testDataFile)}";
using var stream = typeof(TestData).Assembly.GetManifestResourceStream(fullyQualifiedTestDataFile)
?? throw new ArgumentException($"Test data file '{fullyQualifiedTestDataFile}' not found");
using var stringReader = new StreamReader(stream);
var xml = stringReader.ReadToEnd();
var xmlStringReader = new StringReader(xml);
return XmlReader.Create(xmlStringReader);
}
public static string GetRawStringFor(string testDataFile)
{
var fullyQualifiedTestDataFile = $"DotTiled.Tests.{ConvertPathToAssemblyResourcePath(testDataFile)}";
using var stream = typeof(TestData).Assembly.GetManifestResourceStream(fullyQualifiedTestDataFile)
?? throw new ArgumentException($"Test data file '{fullyQualifiedTestDataFile}' not found");
using var stringReader = new StreamReader(stream);
return stringReader.ReadToEnd();
}
private static string ConvertPathToAssemblyResourcePath(string path) =>
path.Replace("/", ".").Replace("\\", ".").Replace(" ", "_");
public static IEnumerable<object[]> MapTests =>
[
["Serialization/TestData/Map/default_map/default-map", (string f) => DefaultMap(), Array.Empty<ICustomTypeDefinition>()],
["Serialization/TestData/Map/map_with_common_props/map-with-common-props", (string f) => MapWithCommonProps(), Array.Empty<ICustomTypeDefinition>()],
["Serialization/TestData/Map/map_with_custom_type_props/map-with-custom-type-props", (string f) => MapWithCustomTypeProps(), MapWithCustomTypePropsCustomTypeDefinitions()],
["Serialization/TestData/Map/map_with_embedded_tileset/map-with-embedded-tileset", (string f) => MapWithEmbeddedTileset(), Array.Empty<ICustomTypeDefinition>()],
["Serialization/TestData/Map/map_with_external_tileset/map-with-external-tileset", (string f) => MapWithExternalTileset(f), Array.Empty<ICustomTypeDefinition>()],
["Serialization/TestData/Map/map_with_flippingflags/map-with-flippingflags", (string f) => MapWithFlippingFlags(f), Array.Empty<ICustomTypeDefinition>()],
["Serialization/TestData/Map/map_external_tileset_multi/map-external-tileset-multi", (string f) => MapExternalTilesetMulti(f), Array.Empty<ICustomTypeDefinition>()],
["Serialization/TestData/Map/map_external_tileset_wangset/map-external-tileset-wangset", (string f) => MapExternalTilesetWangset(f), Array.Empty<ICustomTypeDefinition>()],
["Serialization/TestData/Map/map_with_many_layers/map-with-many-layers", (string f) => MapWithManyLayers(f), Array.Empty<ICustomTypeDefinition>()],
["Serialization/TestData/Map/map_with_deep_props/map-with-deep-props", (string f) => MapWithDeepProps(), MapWithDeepPropsCustomTypeDefinitions()],
];
}

View file

@ -11,9 +11,6 @@ public partial class TestData
TileWidth = 32, TileWidth = 32,
TileHeight = 32, TileHeight = 32,
Infinite = false, Infinite = false,
HexSideLength = null,
StaggerAxis = null,
StaggerIndex = null,
ParallaxOriginX = 0, ParallaxOriginX = 0,
ParallaxOriginY = 0, ParallaxOriginY = 0,
RenderOrder = RenderOrder.RightDown, RenderOrder = RenderOrder.RightDown,
@ -33,22 +30,20 @@ public partial class TestData
Data = new Data Data = new Data
{ {
Encoding = DataEncoding.Csv, Encoding = DataEncoding.Csv,
Chunks = null, GlobalTileIDs = new Optional<uint[]>([
Compression = null,
GlobalTileIDs = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0 0, 0, 0, 0, 0
], ]),
FlippingFlags = [ FlippingFlags = new Optional<FlippingFlags[]>([
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None
] ])
} }
} }
] ]

View file

@ -13,9 +13,6 @@ public partial class TestData
TileWidth = 32, TileWidth = 32,
TileHeight = 32, TileHeight = 32,
Infinite = false, Infinite = false,
HexSideLength = null,
StaggerAxis = null,
StaggerIndex = null,
ParallaxOriginX = 0, ParallaxOriginX = 0,
ParallaxOriginY = 0, ParallaxOriginY = 0,
RenderOrder = RenderOrder.RightDown, RenderOrder = RenderOrder.RightDown,
@ -97,22 +94,20 @@ public partial class TestData
Data = new Data Data = new Data
{ {
Encoding = DataEncoding.Csv, Encoding = DataEncoding.Csv,
Chunks = null, GlobalTileIDs = new Optional<uint[]>([
Compression = null,
GlobalTileIDs = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 1, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 2, 0, 0, 0 0, 2, 0, 0, 0
], ]),
FlippingFlags = [ FlippingFlags = new Optional<FlippingFlags[]>([
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None
] ])
} }
} }
] ]

View file

@ -13,9 +13,6 @@ public partial class TestData
TileWidth = 24, TileWidth = 24,
TileHeight = 24, TileHeight = 24,
Infinite = false, Infinite = false,
HexSideLength = null,
StaggerAxis = null,
StaggerIndex = null,
ParallaxOriginX = 0, ParallaxOriginX = 0,
ParallaxOriginY = 0, ParallaxOriginY = 0,
RenderOrder = RenderOrder.RightDown, RenderOrder = RenderOrder.RightDown,
@ -56,7 +53,59 @@ public partial class TestData
Source = "tileset.png", Source = "tileset.png",
Width = 256, Width = 256,
Height = 96, Height = 96,
} },
Wangsets = [
new Wangset
{
Name = "test-terrain",
Tile = -1,
WangColors = [
new WangColor
{
Name = "Water",
Color = Color.Parse("#ff0000", CultureInfo.InvariantCulture),
Tile = 0,
Probability = 1
},
new WangColor
{
Name = "Grass",
Color = Color.Parse("#00ff00", CultureInfo.InvariantCulture),
Tile = -1,
Probability = 1
},
new WangColor
{
Name = "Stone",
Color = Color.Parse("#0000ff", CultureInfo.InvariantCulture),
Tile = 29,
Probability = 1
}
],
WangTiles = [
new WangTile
{
TileID = 0,
WangID = [1,1,0,0,0,1,1,1]
},
new WangTile
{
TileID = 1,
WangID = [1,1,1,1,0,0,0,1]
},
new WangTile
{
TileID = 10,
WangID = [0,0,0,1,1,1,1,1]
},
new WangTile
{
TileID = 11,
WangID = [0,1,1,1,1,1,0,0]
}
]
}
]
} }
], ],
Layers = [ Layers = [
@ -69,22 +118,20 @@ public partial class TestData
Data = new Data Data = new Data
{ {
Encoding = DataEncoding.Csv, Encoding = DataEncoding.Csv,
Chunks = null, GlobalTileIDs = new Optional<uint[]>([
Compression = null,
GlobalTileIDs = [
2, 2, 12, 11, 0, 2, 2, 12, 11, 0,
1, 12, 1, 11, 0, 1, 12, 1, 11, 0,
2, 1, 0, 1, 0, 2, 1, 0, 1, 0,
12, 11, 12, 2, 0, 12, 11, 12, 2, 0,
0, 0, 0, 0, 0 0, 0, 0, 0, 0
], ]),
FlippingFlags = [ FlippingFlags = new Optional<FlippingFlags[]>([
FlippingFlags.FlippedHorizontally, FlippingFlags.None, FlippingFlags.FlippedHorizontally, FlippingFlags.FlippedHorizontally, FlippingFlags.None, FlippingFlags.FlippedHorizontally, FlippingFlags.None, FlippingFlags.FlippedHorizontally, FlippingFlags.FlippedHorizontally, FlippingFlags.None,
FlippingFlags.FlippedVertically, FlippingFlags.None, FlippingFlags.None, FlippingFlags.FlippedVertically | FlippingFlags.FlippedHorizontally, FlippingFlags.None, FlippingFlags.FlippedVertically, FlippingFlags.None, FlippingFlags.None, FlippingFlags.FlippedVertically | FlippingFlags.FlippedHorizontally, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.FlippedVertically | FlippingFlags.FlippedHorizontally, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.FlippedVertically | FlippingFlags.FlippedHorizontally, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.FlippedHorizontally, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.FlippedHorizontally, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None
] ])
} }
} }
] ]

View file

@ -0,0 +1,242 @@
using System.Numerics;
namespace DotTiled.Tests;
public partial class TestData
{
public static Map MapOverrideObjectBug(string fileExt) => new Map
{
Class = "",
Orientation = MapOrientation.Orthogonal,
Width = 5,
Height = 5,
TileWidth = 32,
TileHeight = 32,
Infinite = false,
ParallaxOriginX = 0,
ParallaxOriginY = 0,
RenderOrder = RenderOrder.RightDown,
CompressionLevel = -1,
BackgroundColor = new Color { R = 0, G = 0, B = 0, A = 0 },
Version = "1.10",
TiledVersion = "1.11.0",
NextLayerID = 8,
NextObjectID = 8,
Tilesets = [
new Tileset
{
Version = "1.10",
TiledVersion = "1.11.0",
FirstGID = 1,
Name = "tileset",
TileWidth = 32,
TileHeight = 32,
TileCount = 24,
Columns = 8,
Source = $"tileset.{(fileExt == "tmx" ? "tsx" : "tsj")}",
Image = new Image
{
Format = ImageFormat.Png,
Source = "tileset.png",
Width = 256,
Height = 96,
}
}
],
Layers = [
new Group
{
ID = 2,
Name = "Root",
Layers = [
new ObjectLayer
{
ID = 3,
Name = "Objects",
Objects = [
new RectangleObject
{
ID = 1,
Name = "Object 1",
X = 25.6667f,
Y = 28.6667f,
Width = 31.3333f,
Height = 31.3333f
},
new PointObject
{
ID = 3,
Name = "P1",
X = 117.667f,
Y = 48.6667f
},
new EllipseObject
{
ID = 4,
Name = "Circle1",
X = 77f,
Y = 72.3333f,
Width = 34.6667f,
Height = 34.6667f
},
new PolygonObject
{
ID = 5,
Name = "Poly",
X = 20.6667f,
Y = 114.667f,
Points = [
new Vector2(0, 0),
new Vector2(104,20),
new Vector2(35.6667f, 32.3333f)
],
Template = fileExt == "tmx" ? "poly.tx" : "poly.tj",
Properties = [
new StringProperty { Name = "templateprop", Value = "helo there" }
]
},
new TileObject
{
ID = 6,
Name = "TileObj",
GID = 7,
X = -35,
Y = 110.333f,
Width = 64,
Height = 146
},
new RectangleObject
{
ID = 7,
Name = "",
Template = fileExt == "tmx" ? "random.tx" : "random.tj",
Type = "randomclass",
X = 134.552f,
Y = 113.638f
}
]
},
new Group
{
ID = 5,
Name = "Sub",
Layers = [
new TileLayer
{
ID = 7,
Name = "Tile 3",
Width = 5,
Height = 5,
Data = new Data
{
Encoding = DataEncoding.Csv,
GlobalTileIDs = new Optional<uint[]>([
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0
]),
FlippingFlags = new Optional<FlippingFlags[]>([
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None
])
}
},
new TileLayer
{
ID = 6,
Name = "Tile 2",
Width = 5,
Height = 5,
Data = new Data
{
Encoding = DataEncoding.Csv,
GlobalTileIDs = new Optional<uint[]>([
0, 15, 15, 0, 0,
0, 15, 15, 0, 0,
0, 15, 15, 15, 0,
15, 15, 15, 0, 0,
0, 0, 0, 0, 0
]),
FlippingFlags = new Optional<FlippingFlags[]>([
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None
])
}
}
]
},
new ImageLayer
{
ID = 4,
Name = "ImageLayer",
Image = new Image
{
Format = ImageFormat.Png,
Source = "tileset.png",
Width = fileExt == "tmx" ? 256u : 0, // Currently, json format does not
Height = fileExt == "tmx" ? 96u : 0 // include image dimensions in image layer https://github.com/mapeditor/tiled/issues/4028
},
RepeatX = true
},
new TileLayer
{
ID = 1,
Name = "Tile Layer 1",
Width = 5,
Height = 5,
Data = new Data
{
Encoding = DataEncoding.Csv,
GlobalTileIDs = new Optional<uint[]>([
1, 1, 1, 1, 1,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0
]),
FlippingFlags = new Optional<FlippingFlags[]>([
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None
])
}
}
]
}
]
};
public static IReadOnlyCollection<ICustomTypeDefinition> MapOverrideObjectBugCustomTypeDefinitions() => [
new CustomClassDefinition
{
Name = "TestClass",
UseAs = CustomClassUseAs.Map,
Members = [
new BoolProperty
{
Name = "classbool",
Value = true
},
new StringProperty
{
Name = "classstring",
Value = "Hello there default value"
}
]
},
new CustomClassDefinition
{
Name = "randomclass"
}
];
}

View file

@ -0,0 +1,171 @@
{ "compressionlevel":-1,
"height":5,
"infinite":false,
"layers":[
{
"id":2,
"layers":[
{
"draworder":"topdown",
"id":3,
"name":"Objects",
"objects":[
{
"height":31.3333,
"id":1,
"name":"Object 1",
"rotation":0,
"type":"",
"visible":true,
"width":31.3333,
"x":25.6667,
"y":28.6667
},
{
"height":0,
"id":3,
"name":"P1",
"point":true,
"rotation":0,
"type":"",
"visible":true,
"width":0,
"x":117.667,
"y":48.6667
},
{
"ellipse":true,
"height":34.6667,
"id":4,
"name":"Circle1",
"rotation":0,
"type":"",
"visible":true,
"width":34.6667,
"x":77,
"y":72.3333
},
{
"id":5,
"template":"poly.tj",
"x":20.6667,
"y":114.667
},
{
"gid":7,
"height":146,
"id":6,
"name":"TileObj",
"rotation":0,
"type":"",
"visible":true,
"width":64,
"x":-35,
"y":110.333
},
{
"id":7,
"template":"random.tj",
"type":"randomclass",
"x":134.551764025448,
"y":113.637941006362
}],
"opacity":1,
"type":"objectgroup",
"visible":true,
"x":0,
"y":0
},
{
"id":5,
"layers":[
{
"data":[0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0],
"height":5,
"id":7,
"name":"Tile 3",
"opacity":1,
"type":"tilelayer",
"visible":true,
"width":5,
"x":0,
"y":0
},
{
"data":[0, 15, 15, 0, 0,
0, 15, 15, 0, 0,
0, 15, 15, 15, 0,
15, 15, 15, 0, 0,
0, 0, 0, 0, 0],
"height":5,
"id":6,
"name":"Tile 2",
"opacity":1,
"type":"tilelayer",
"visible":true,
"width":5,
"x":0,
"y":0
}],
"name":"Sub",
"opacity":1,
"type":"group",
"visible":true,
"x":0,
"y":0
},
{
"id":4,
"image":"tileset.png",
"name":"ImageLayer",
"opacity":1,
"repeatx":true,
"type":"imagelayer",
"visible":true,
"x":0,
"y":0
},
{
"data":[1, 1, 1, 1, 1,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0],
"height":5,
"id":1,
"name":"Tile Layer 1",
"opacity":1,
"type":"tilelayer",
"visible":true,
"width":5,
"x":0,
"y":0
}],
"name":"Root",
"opacity":1,
"type":"group",
"visible":true,
"x":0,
"y":0
}],
"nextlayerid":8,
"nextobjectid":8,
"orientation":"orthogonal",
"renderorder":"right-down",
"tiledversion":"1.11.0",
"tileheight":32,
"tilesets":[
{
"firstgid":1,
"source":"tileset.tsj"
}],
"tilewidth":32,
"type":"map",
"version":"1.10",
"width":5
}

View file

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.11.0" orientation="orthogonal" renderorder="right-down" width="5" height="5" tilewidth="32" tileheight="32" infinite="0" nextlayerid="8" nextobjectid="8">
<tileset firstgid="1" source="tileset.tsx"/>
<group id="2" name="Root">
<objectgroup id="3" name="Objects">
<object id="1" name="Object 1" x="25.6667" y="28.6667" width="31.3333" height="31.3333"/>
<object id="3" name="P1" x="117.667" y="48.6667">
<point/>
</object>
<object id="4" name="Circle1" x="77" y="72.3333" width="34.6667" height="34.6667">
<ellipse/>
</object>
<object id="5" template="poly.tx" x="20.6667" y="114.667"/>
<object id="6" name="TileObj" gid="7" x="-35" y="110.333" width="64" height="146"/>
<object id="7" template="random.tx" type="randomclass" x="134.552" y="113.638"/>
</objectgroup>
<group id="5" name="Sub">
<layer id="7" name="Tile 3" width="5" height="5">
<data encoding="csv">
0,0,0,0,0,
0,0,0,0,0,
0,0,0,0,0,
0,0,0,0,0,
0,0,0,0,0
</data>
</layer>
<layer id="6" name="Tile 2" width="5" height="5">
<data encoding="csv">
0,15,15,0,0,
0,15,15,0,0,
0,15,15,15,0,
15,15,15,0,0,
0,0,0,0,0
</data>
</layer>
</group>
<imagelayer id="4" name="ImageLayer" repeatx="1">
<image source="tileset.png" width="256" height="96"/>
</imagelayer>
<layer id="1" name="Tile Layer 1" width="5" height="5">
<data encoding="csv">
1,1,1,1,1,
0,0,0,0,0,
0,0,0,0,0,
0,0,0,0,0,
0,0,0,0,0
</data>
</layer>
</group>
</map>

View file

@ -0,0 +1,12 @@
{ "object":
{
"height":0,
"id":7,
"name":"",
"rotation":0,
"type":"randomclass",
"visible":true,
"width":0
},
"type":"template"
}

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<template>
<object type="randomclass"/>
</template>

View file

@ -0,0 +1,83 @@
namespace DotTiled.Tests;
public partial class TestData
{
public static Map MapWithClassAndProps() => new Map
{
Class = "TestClass",
Orientation = MapOrientation.Orthogonal,
Width = 5,
Height = 5,
TileWidth = 32,
TileHeight = 32,
Infinite = false,
ParallaxOriginX = 0,
ParallaxOriginY = 0,
RenderOrder = RenderOrder.RightDown,
CompressionLevel = -1,
BackgroundColor = new Color { R = 0, G = 0, B = 0, A = 0 },
Version = "1.10",
TiledVersion = "1.11.0",
NextLayerID = 2,
NextObjectID = 1,
Layers = [
new TileLayer
{
ID = 1,
Name = "Tile Layer 1",
Width = 5,
Height = 5,
Data = new Data
{
Encoding = DataEncoding.Csv,
GlobalTileIDs = new Optional<uint[]>([
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0
]),
FlippingFlags = new Optional<FlippingFlags[]>([
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None
])
}
}
],
Properties = [
new BoolProperty
{
Name = "classbool",
Value = true
},
new StringProperty
{
Name = "classstring",
Value = "I am not default value"
}
]
};
public static IReadOnlyCollection<ICustomTypeDefinition> MapWithClassAndPropsCustomTypeDefinitions() => [
new CustomClassDefinition
{
Name = "TestClass",
UseAs = CustomClassUseAs.Map,
Members = [
new BoolProperty
{
Name = "classbool",
Value = true
},
new StringProperty
{
Name = "classstring",
Value = "Hello there default value"
}
]
},
];
}

View file

@ -1,13 +1,14 @@
{ "compressionlevel":-1, { "class":"TestClass",
"compressionlevel":-1,
"height":5, "height":5,
"infinite":false, "infinite":false,
"layers":[ "layers":[
{ {
"data":[1, 2684354561, 0, 0, 1073741831, "data":[0, 0, 0, 0, 0,
1610612737, 3221225473, 0, 0, 1073741831, 0, 0, 0, 0, 0,
0, 0, 1, 0, 1073741831, 0, 0, 0, 0, 0,
0, 0, 0, 1, 1073741831, 0, 0, 0, 0, 0,
2147483669, 2147483669, 2147483669, 2147483669, 1], 0, 0, 0, 0, 0],
"height":5, "height":5,
"id":1, "id":1,
"name":"Tile Layer 1", "name":"Tile Layer 1",
@ -21,14 +22,16 @@
"nextlayerid":2, "nextlayerid":2,
"nextobjectid":1, "nextobjectid":1,
"orientation":"orthogonal", "orientation":"orthogonal",
"properties":[
{
"name":"classstring",
"type":"string",
"value":"I am not default value"
}],
"renderorder":"right-down", "renderorder":"right-down",
"tiledversion":"1.11.0", "tiledversion":"1.11.0",
"tileheight":32, "tileheight":32,
"tilesets":[ "tilesets":[],
{
"firstgid":1,
"source":"tileset.tsj"
}],
"tilewidth":32, "tilewidth":32,
"type":"map", "type":"map",
"version":"1.10", "version":"1.10",

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.11.0" class="TestClass" orientation="orthogonal" renderorder="right-down" width="5" height="5" tilewidth="32" tileheight="32" infinite="0" nextlayerid="2" nextobjectid="1">
<properties>
<property name="classstring" value="I am not default value"/>
</properties>
<layer id="1" name="Tile Layer 1" width="5" height="5">
<data encoding="csv">
0,0,0,0,0,
0,0,0,0,0,
0,0,0,0,0,
0,0,0,0,0,
0,0,0,0,0
</data>
</layer>
</map>

View file

@ -0,0 +1,83 @@
namespace DotTiled.Tests;
public partial class TestData
{
public static Map MapWithClass() => new Map
{
Class = "TestClass",
Orientation = MapOrientation.Orthogonal,
Width = 5,
Height = 5,
TileWidth = 32,
TileHeight = 32,
Infinite = false,
ParallaxOriginX = 0,
ParallaxOriginY = 0,
RenderOrder = RenderOrder.RightDown,
CompressionLevel = -1,
BackgroundColor = new Color { R = 0, G = 0, B = 0, A = 0 },
Version = "1.10",
TiledVersion = "1.11.0",
NextLayerID = 2,
NextObjectID = 1,
Layers = [
new TileLayer
{
ID = 1,
Name = "Tile Layer 1",
Width = 5,
Height = 5,
Data = new Data
{
Encoding = DataEncoding.Csv,
GlobalTileIDs = new Optional<uint[]>([
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0
]),
FlippingFlags = new Optional<FlippingFlags[]>([
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None
])
}
}
],
Properties = [
new BoolProperty
{
Name = "classbool",
Value = true
},
new StringProperty
{
Name = "classstring",
Value = "Hello there default value"
}
]
};
public static IReadOnlyCollection<ICustomTypeDefinition> MapWithClassCustomTypeDefinitions() => [
new CustomClassDefinition
{
Name = "TestClass",
UseAs = CustomClassUseAs.Map,
Members = [
new BoolProperty
{
Name = "classbool",
Value = true
},
new StringProperty
{
Name = "classstring",
Value = "Hello there default value"
}
]
},
];
}

View file

@ -0,0 +1,33 @@
{ "class":"TestClass",
"compressionlevel":-1,
"height":5,
"infinite":false,
"layers":[
{
"data":[0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0],
"height":5,
"id":1,
"name":"Tile Layer 1",
"opacity":1,
"type":"tilelayer",
"visible":true,
"width":5,
"x":0,
"y":0
}],
"nextlayerid":2,
"nextobjectid":1,
"orientation":"orthogonal",
"renderorder":"right-down",
"tiledversion":"1.11.0",
"tileheight":32,
"tilesets":[],
"tilewidth":32,
"type":"map",
"version":"1.10",
"width":5
}

View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.11.0" class="TestClass" orientation="orthogonal" renderorder="right-down" width="5" height="5" tilewidth="32" tileheight="32" infinite="0" nextlayerid="2" nextobjectid="1">
<layer id="1" name="Tile Layer 1" width="5" height="5">
<data encoding="csv">
0,0,0,0,0,
0,0,0,0,0,
0,0,0,0,0,
0,0,0,0,0,
0,0,0,0,0
</data>
</layer>
</map>

View file

@ -13,9 +13,6 @@ public partial class TestData
TileWidth = 32, TileWidth = 32,
TileHeight = 16, TileHeight = 16,
Infinite = false, Infinite = false,
HexSideLength = null,
StaggerAxis = null,
StaggerIndex = null,
ParallaxOriginX = 0, ParallaxOriginX = 0,
ParallaxOriginY = 0, ParallaxOriginY = 0,
RenderOrder = RenderOrder.RightDown, RenderOrder = RenderOrder.RightDown,
@ -35,22 +32,20 @@ public partial class TestData
Data = new Data Data = new Data
{ {
Encoding = DataEncoding.Csv, Encoding = DataEncoding.Csv,
Chunks = null, GlobalTileIDs = new Optional<uint[]>([
Compression = null,
GlobalTileIDs = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0 0, 0, 0, 0, 0
], ]),
FlippingFlags = [ FlippingFlags = new Optional<FlippingFlags[]>([
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None
] ])
} }
} }
], ],
@ -62,7 +57,8 @@ public partial class TestData
new FloatProperty { Name = "floatprop", Value = 4.2f }, new FloatProperty { Name = "floatprop", Value = 4.2f },
new IntProperty { Name = "intprop", Value = 8 }, new IntProperty { Name = "intprop", Value = 8 },
new ObjectProperty { Name = "objectprop", Value = 5 }, new ObjectProperty { Name = "objectprop", Value = 5 },
new StringProperty { Name = "stringprop", Value = "This is a string, hello world!" } new StringProperty { Name = "stringprop", Value = "This is a string, hello world!" },
new ColorProperty { Name = "unsetcolorprop", Value = Optional<Color>.Empty }
] ]
}; };
} }

View file

@ -58,6 +58,11 @@
"name":"stringprop", "name":"stringprop",
"type":"string", "type":"string",
"value":"This is a string, hello world!" "value":"This is a string, hello world!"
},
{
"name":"unsetcolorprop",
"type":"color",
"value":""
}], }],
"renderorder":"right-down", "renderorder":"right-down",
"tiledversion":"1.11.0", "tiledversion":"1.11.0",

View file

@ -8,6 +8,7 @@
<property name="intprop" type="int" value="8"/> <property name="intprop" type="int" value="8"/>
<property name="objectprop" type="object" value="5"/> <property name="objectprop" type="object" value="5"/>
<property name="stringprop" value="This is a string, hello world!"/> <property name="stringprop" value="This is a string, hello world!"/>
<property name="unsetcolorprop" type="color" value=""/>
</properties> </properties>
<layer id="1" name="Tile Layer 1" width="5" height="5"> <layer id="1" name="Tile Layer 1" width="5" height="5">
<data encoding="csv"> <data encoding="csv">

View file

@ -0,0 +1,85 @@
using System.Globalization;
namespace DotTiled.Tests;
public partial class TestData
{
public static Map MapWithCustomTypePropsWithoutDefs() => new Map
{
Class = "",
Orientation = MapOrientation.Orthogonal,
Width = 5,
Height = 5,
TileWidth = 32,
TileHeight = 32,
Infinite = false,
ParallaxOriginX = 0,
ParallaxOriginY = 0,
RenderOrder = RenderOrder.RightDown,
CompressionLevel = -1,
BackgroundColor = Color.Parse("#00000000", CultureInfo.InvariantCulture),
Version = "1.10",
TiledVersion = "1.11.0",
NextLayerID = 2,
NextObjectID = 1,
Layers = [
new TileLayer
{
ID = 1,
Name = "Tile Layer 1",
Width = 5,
Height = 5,
Data = new Data
{
Encoding = DataEncoding.Csv,
GlobalTileIDs = new Optional<uint[]>([
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0
]),
FlippingFlags = new Optional<FlippingFlags[]>([
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None
])
}
}
],
Properties = [
new ClassProperty
{
Name = "customclassprop",
PropertyType = "CustomClass",
Value = [
new BoolProperty { Name = "boolinclass", Value = true },
new FloatProperty { Name = "floatinclass", Value = 13.37f },
new StringProperty { Name = "stringinclass", Value = "This is a set string" }
]
},
new IntProperty
{
Name = "customenumintflagsprop",
Value = 6
},
new IntProperty
{
Name = "customenumintprop",
Value = 3
},
new StringProperty
{
Name = "customenumstringprop",
Value = "CustomEnumString_2"
},
new StringProperty
{
Name = "customenumstringflagsprop",
Value = "CustomEnumStringFlags_1,CustomEnumStringFlags_2"
}
]
};
}

View file

@ -13,9 +13,6 @@ public partial class TestData
TileWidth = 32, TileWidth = 32,
TileHeight = 32, TileHeight = 32,
Infinite = false, Infinite = false,
HexSideLength = null,
StaggerAxis = null,
StaggerIndex = null,
ParallaxOriginX = 0, ParallaxOriginX = 0,
ParallaxOriginY = 0, ParallaxOriginY = 0,
RenderOrder = RenderOrder.RightDown, RenderOrder = RenderOrder.RightDown,
@ -35,22 +32,20 @@ public partial class TestData
Data = new Data Data = new Data
{ {
Encoding = DataEncoding.Csv, Encoding = DataEncoding.Csv,
Chunks = null, GlobalTileIDs = new Optional<uint[]>([
Compression = null,
GlobalTileIDs = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0 0, 0, 0, 0, 0
], ]),
FlippingFlags = [ FlippingFlags = new Optional<FlippingFlags[]>([
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None
] ])
} }
} }
], ],

View file

@ -0,0 +1,68 @@
{ "compressionlevel":-1,
"height":5,
"infinite":false,
"layers":[
{
"data":[0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0],
"height":5,
"id":1,
"name":"Tile Layer 1",
"opacity":1,
"type":"tilelayer",
"visible":true,
"width":5,
"x":0,
"y":0
}],
"nextlayerid":2,
"nextobjectid":1,
"orientation":"orthogonal",
"properties":[
{
"name":"customclassprop",
"propertytype":"CustomClass",
"type":"class",
"value":
{
"boolinclass":true,
"floatinclass":13.37,
"stringinclass":"This is a set string"
}
},
{
"name":"customenumintflagsprop",
"propertytype":"CustomEnumIntFlags",
"type":"int",
"value":6
},
{
"name":"customenumintprop",
"propertytype":"CustomEnumInt",
"type":"int",
"value":3
},
{
"name":"customenumstringflagsprop",
"propertytype":"CustomEnumStringFlags",
"type":"string",
"value":"CustomEnumStringFlags_1,CustomEnumStringFlags_2"
},
{
"name":"customenumstringprop",
"propertytype":"CustomEnumString",
"type":"string",
"value":"CustomEnumString_2"
}],
"renderorder":"right-down",
"tiledversion":"1.11.0",
"tileheight":32,
"tilesets":[],
"tilewidth":32,
"type":"map",
"version":"1.10",
"width":5
}

View file

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.11.0" orientation="orthogonal" renderorder="right-down" width="5" height="5" tilewidth="32" tileheight="32" infinite="0" nextlayerid="2" nextobjectid="1">
<properties>
<property name="customclassprop" type="class" propertytype="CustomClass">
<properties>
<property name="boolinclass" type="bool" value="true"/>
<property name="floatinclass" type="float" value="13.37"/>
<property name="stringinclass" value="This is a set string"/>
</properties>
</property>
<property name="customenumintflagsprop" type="int" propertytype="CustomEnumIntFlags" value="6"/>
<property name="customenumintprop" type="int" propertytype="CustomEnumInt" value="3"/>
<property name="customenumstringflagsprop" propertytype="CustomEnumStringFlags" value="CustomEnumStringFlags_1,CustomEnumStringFlags_2"/>
<property name="customenumstringprop" propertytype="CustomEnumString" value="CustomEnumString_2"/>
</properties>
<layer id="1" name="Tile Layer 1" width="5" height="5">
<data encoding="csv">
0,0,0,0,0,
0,0,0,0,0,
0,0,0,0,0,
0,0,0,0,0,
0,0,0,0,0
</data>
</layer>
</map>

View file

@ -13,9 +13,6 @@ public partial class TestData
TileWidth = 32, TileWidth = 32,
TileHeight = 32, TileHeight = 32,
Infinite = false, Infinite = false,
HexSideLength = null,
StaggerAxis = null,
StaggerIndex = null,
ParallaxOriginX = 0, ParallaxOriginX = 0,
ParallaxOriginY = 0, ParallaxOriginY = 0,
RenderOrder = RenderOrder.RightDown, RenderOrder = RenderOrder.RightDown,
@ -35,22 +32,20 @@ public partial class TestData
Data = new Data Data = new Data
{ {
Encoding = DataEncoding.Csv, Encoding = DataEncoding.Csv,
Chunks = null, GlobalTileIDs = new Optional<uint[]>([
Compression = null,
GlobalTileIDs = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0 0, 0, 0, 0, 0
], ]),
FlippingFlags = [ FlippingFlags = new Optional<FlippingFlags[]>([
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None
] ])
} }
} }
], ],

View file

@ -13,9 +13,6 @@ public partial class TestData
TileWidth = 32, TileWidth = 32,
TileHeight = 32, TileHeight = 32,
Infinite = false, Infinite = false,
HexSideLength = null,
StaggerAxis = null,
StaggerIndex = null,
ParallaxOriginX = 0, ParallaxOriginX = 0,
ParallaxOriginY = 0, ParallaxOriginY = 0,
RenderOrder = RenderOrder.RightDown, RenderOrder = RenderOrder.RightDown,
@ -28,6 +25,8 @@ public partial class TestData
Tilesets = [ Tilesets = [
new Tileset new Tileset
{ {
Version = "1.10",
TiledVersion = "1.11.0",
FirstGID = 1, FirstGID = 1,
Name = "tileset", Name = "tileset",
TileWidth = 32, TileWidth = 32,
@ -53,22 +52,20 @@ public partial class TestData
Data = new Data Data = new Data
{ {
Encoding = DataEncoding.Csv, Encoding = DataEncoding.Csv,
Chunks = null, GlobalTileIDs = new Optional<uint[]>([
Compression = null,
GlobalTileIDs = [
1, 1, 0, 0, 7, 1, 1, 0, 0, 7,
1, 1, 0, 0, 7, 1, 1, 0, 0, 7,
0, 0, 0, 0, 7, 0, 0, 0, 0, 7,
9, 10, 0, 0, 7, 9, 10, 0, 0, 7,
17, 18, 0, 0, 0 17, 18, 0, 0, 0
], ]),
FlippingFlags = [ FlippingFlags = new Optional<FlippingFlags[]>([
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None
] ])
} }
} }
] ]

View file

@ -13,9 +13,6 @@ public partial class TestData
TileWidth = 32, TileWidth = 32,
TileHeight = 32, TileHeight = 32,
Infinite = false, Infinite = false,
HexSideLength = null,
StaggerAxis = null,
StaggerIndex = null,
ParallaxOriginX = 0, ParallaxOriginX = 0,
ParallaxOriginY = 0, ParallaxOriginY = 0,
RenderOrder = RenderOrder.RightDown, RenderOrder = RenderOrder.RightDown,
@ -56,22 +53,20 @@ public partial class TestData
Data = new Data Data = new Data
{ {
Encoding = DataEncoding.Csv, Encoding = DataEncoding.Csv,
Chunks = null, GlobalTileIDs = new Optional<uint[]>([
Compression = null,
GlobalTileIDs = [
1, 1, 0, 0, 7, 1, 1, 0, 0, 7,
1, 1, 0, 0, 7, 1, 1, 0, 0, 7,
0, 0, 1, 0, 7, 0, 0, 1, 0, 7,
0, 0, 0, 1, 7, 0, 0, 0, 1, 7,
21, 21, 21, 21, 1 21, 21, 21, 21, 1
], ]),
FlippingFlags = [ FlippingFlags = new Optional<FlippingFlags[]>([
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None
] ])
} }
} }
] ]

View file

@ -13,9 +13,6 @@ public partial class TestData
TileWidth = 32, TileWidth = 32,
TileHeight = 32, TileHeight = 32,
Infinite = false, Infinite = false,
HexSideLength = null,
StaggerAxis = null,
StaggerIndex = null,
ParallaxOriginX = 0, ParallaxOriginX = 0,
ParallaxOriginY = 0, ParallaxOriginY = 0,
RenderOrder = RenderOrder.RightDown, RenderOrder = RenderOrder.RightDown,
@ -23,8 +20,8 @@ public partial class TestData
BackgroundColor = Color.Parse("#00000000", CultureInfo.InvariantCulture), BackgroundColor = Color.Parse("#00000000", CultureInfo.InvariantCulture),
Version = "1.10", Version = "1.10",
TiledVersion = "1.11.0", TiledVersion = "1.11.0",
NextLayerID = 2, NextLayerID = 3,
NextObjectID = 1, NextObjectID = 3,
Tilesets = [ Tilesets = [
new Tileset new Tileset
{ {
@ -56,23 +53,48 @@ public partial class TestData
Data = new Data Data = new Data
{ {
Encoding = DataEncoding.Csv, Encoding = DataEncoding.Csv,
Chunks = null, GlobalTileIDs = new Optional<uint[]>([
Compression = null,
GlobalTileIDs = [
1, 1, 0, 0, 7, 1, 1, 0, 0, 7,
1, 1, 0, 0, 7, 1, 1, 0, 0, 7,
0, 0, 1, 0, 7, 0, 0, 1, 0, 7,
0, 0, 0, 1, 7, 0, 0, 0, 1, 7,
21, 21, 21, 21, 1 21, 21, 21, 21, 1
], ]),
FlippingFlags = [ FlippingFlags = new Optional<FlippingFlags[]>([
FlippingFlags.None, FlippingFlags.FlippedDiagonally | FlippingFlags.FlippedHorizontally, FlippingFlags.None, FlippingFlags.None, FlippingFlags.FlippedVertically, FlippingFlags.None, FlippingFlags.FlippedDiagonally | FlippingFlags.FlippedHorizontally, FlippingFlags.None, FlippingFlags.None, FlippingFlags.FlippedVertically,
FlippingFlags.FlippedDiagonally | FlippingFlags.FlippedVertically, FlippingFlags.FlippedVertically | FlippingFlags.FlippedHorizontally, FlippingFlags.None, FlippingFlags.None, FlippingFlags.FlippedVertically, FlippingFlags.FlippedDiagonally | FlippingFlags.FlippedVertically, FlippingFlags.FlippedVertically | FlippingFlags.FlippedHorizontally, FlippingFlags.None, FlippingFlags.None, FlippingFlags.FlippedVertically,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.FlippedVertically, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.FlippedVertically,
FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.FlippedVertically, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.FlippedVertically,
FlippingFlags.FlippedHorizontally, FlippingFlags.FlippedHorizontally, FlippingFlags.FlippedHorizontally, FlippingFlags.FlippedHorizontally, FlippingFlags.None FlippingFlags.FlippedHorizontally, FlippingFlags.FlippedHorizontally, FlippingFlags.FlippedHorizontally, FlippingFlags.FlippedHorizontally, FlippingFlags.None
] ])
} }
},
new ObjectLayer
{
ID = 2,
Name = "Object Layer 1",
Objects = [
new TileObject
{
ID = 1,
GID = 21,
X = 80.0555f,
Y = 48.3887f,
Width = 32,
Height = 32,
FlippingFlags = FlippingFlags.FlippedHorizontally
},
new TileObject
{
ID = 2,
GID = 21,
X = 15.833f,
Y = 112.056f,
Width = 32,
Height = 32,
FlippingFlags = FlippingFlags.FlippedHorizontally | FlippingFlags.FlippedVertically
}
]
} }
] ]
}; };

View file

@ -0,0 +1,71 @@
{ "compressionlevel":-1,
"height":5,
"infinite":false,
"layers":[
{
"data":[1, 2684354561, 0, 0, 1073741831,
1610612737, 3221225473, 0, 0, 1073741831,
0, 0, 1, 0, 1073741831,
0, 0, 0, 1, 1073741831,
2147483669, 2147483669, 2147483669, 2147483669, 1],
"height":5,
"id":1,
"name":"Tile Layer 1",
"opacity":1,
"type":"tilelayer",
"visible":true,
"width":5,
"x":0,
"y":0
},
{
"draworder":"topdown",
"id":2,
"name":"Object Layer 1",
"objects":[
{
"gid":2147483669,
"height":32,
"id":1,
"name":"",
"rotation":0,
"type":"",
"visible":true,
"width":32,
"x":80.0555234239445,
"y":48.3886639676113
},
{
"gid":1073741845,
"height":32,
"id":2,
"name":"",
"rotation":0,
"type":"",
"visible":true,
"width":32,
"x":15.8334297281666,
"y":112.055523423944
}],
"opacity":1,
"type":"objectgroup",
"visible":true,
"x":0,
"y":0
}],
"nextlayerid":3,
"nextobjectid":3,
"orientation":"orthogonal",
"renderorder":"right-down",
"tiledversion":"1.11.0",
"tileheight":32,
"tilesets":[
{
"firstgid":1,
"source":"tileset.tsj"
}],
"tilewidth":32,
"type":"map",
"version":"1.10",
"width":5
}

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.11.0" orientation="orthogonal" renderorder="right-down" width="5" height="5" tilewidth="32" tileheight="32" infinite="0" nextlayerid="2" nextobjectid="1"> <map version="1.10" tiledversion="1.11.0" orientation="orthogonal" renderorder="right-down" width="5" height="5" tilewidth="32" tileheight="32" infinite="0" nextlayerid="3" nextobjectid="3">
<tileset firstgid="1" source="tileset.tsx"/> <tileset firstgid="1" source="tileset.tsx"/>
<layer id="1" name="Tile Layer 1" width="5" height="5"> <layer id="1" name="Tile Layer 1" width="5" height="5">
<data encoding="csv"> <data encoding="csv">
@ -10,4 +10,8 @@
2147483669,2147483669,2147483669,2147483669,1 2147483669,2147483669,2147483669,2147483669,1
</data> </data>
</layer> </layer>
<objectgroup id="2" name="Object Layer 1">
<object id="1" gid="2147483669" x="80.0555" y="48.3887" width="32" height="32"/>
<object id="2" gid="1073741845" x="15.8334" y="112.056" width="32" height="32"/>
</objectgroup>
</map> </map>

Some files were not shown because too many files have changed in this diff Show more