This commit is contained in:
dcronqvist 2025-04-28 18:37:13 +00:00 committed by GitHub
commit cf7fc6cefa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
114 changed files with 3085 additions and 424 deletions

14
.github/CONTRIBUTING.md vendored Normal file
View file

@ -0,0 +1,14 @@
# Welcome to the DotTiled contribution guide!
Thanks for taking the time to contribute to DotTiled!
## Contribution Guidelines
- **Branching:** Always branch from the latest `dev` branch. Do not submit PRs directly to `master`.
- **Git**: Keep your commits small with intentful messages. Use `git rebase` to keep your commit history clean, never merge `dev` into your branch. If you need to update your branch with the latest changes from `dev`, use `git rebase dev`.
- **Pull Requests:** Open PRs against the `dev` branch only. Use the `.github/PULL_REQUEST_TEMPLATE/dev_template.md` PR template for your description, and ensure your PR is well-documented.
- **Testing:** All changes to DotTiled core must include relevant tests. PRs without tests will not be accepted.
- **Examples & Misc:** Updates to example projects or documentation are more flexible but should still be submitted as PRs to `dev`.
- **Code Style:** Follow existing code style and conventions.
Thank you for helping improve DotTiled!

View file

@ -13,23 +13,34 @@ jobs:
- name: Get version from PR branch
id: pr_version
run: |
PR_VERSION=$(grep '<Version>' **/*.csproj | sed -E 's/.*<Version>(.*)<\/Version>.*/\1/')
PR_VERSION=$(find . -name '*.csproj' -exec grep '<Version>' {} \; | sed -E 's/.*<Version>(.*)<\/Version>.*/\1/')
echo "PR_VERSION=$PR_VERSION" >> $GITHUB_ENV
- name: Checkout master branch
run: |
git fetch origin master
git checkout origin/master
- name: Checkout master branch to separate directory
uses: actions/checkout@v3
with:
ref: master
path: master_branch
- name: Get version from master branch
id: master_version
run: |
MASTER_VERSION=$(grep '<Version>' **/*.csproj | sed -E 's/.*<Version>(.*)<\/Version>.*/\1/')
MASTER_VERSION=$(find master_branch -name '*.csproj' -exec grep '<Version>' {} \; | sed -E 's/.*<Version>(.*)<\/Version>.*/\1/')
echo "MASTER_VERSION=$MASTER_VERSION" >> $GITHUB_ENV
- name: Debug $GITHUB_ENV
run: |
echo "PR_VERSION: $PR_VERSION"
echo "MASTER_VERSION: $MASTER_VERSION"
- name: Compare versions
run: |
if [ "$(printf '%s\n' "$PR_VERSION" "$MASTER_VERSION" | sort -V | head -n1)" = "$PR_VERSION" ] && [ "$PR_VERSION" != "$MASTER_VERSION" ]; then
if [ -z "$PR_VERSION" ] || [ -z "$MASTER_VERSION" ]; then
echo "One of the version variables is empty."
exit 1
fi
if [ "$(printf '%s\n' "$MASTER_VERSION" "$PR_VERSION" | sort -V | tail -n1)" != "$PR_VERSION" ] || [ "$PR_VERSION" = "$MASTER_VERSION" ]; then
echo "Version in PR is not higher than master."
exit 1
else

View file

@ -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.
```
BenchmarkDotNet v0.13.12, Windows 10 (10.0.19045.5131/22H2/2022Update)
BenchmarkDotNet v0.13.12, Windows 10 (10.0.19045.5737/22H2/2022Update)
12th Gen Intel Core i7-12700K, 1 CPU, 20 logical and 12 physical cores
.NET SDK 8.0.202
[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.5131/22H2/2022Update)
```
| Method | Categories | Mean | Ratio | Gen0 | Gen1 | Allocated | Alloc Ratio |
|------------ |------------------------- |---------:|------:|-------:|-------:|----------:|------------:|
| DotTiled | MapFromInMemoryTmjString | 4.602 μs | 1.00 | 0.5417 | - | 7 KB | 1.00 |
| TiledLib | MapFromInMemoryTmjString | 6.385 μs | 1.39 | 0.7019 | 0.0153 | 9.01 KB | 1.29 |
| DotTiled | MapFromInMemoryTmjString | 4.410 μs | 1.00 | 0.4501 | - | 5.81 KB | 1.00 |
| TiledLib | MapFromInMemoryTmjString | 6.170 μs | 1.40 | 0.7019 | 0.0305 | 9.01 KB | 1.55 |
| | | | | | | | |
| DotTiled | MapFromInMemoryTmxString | 3.216 μs | 1.00 | 1.3733 | 0.0610 | 17.68 KB | 1.00 |
| TiledLib | MapFromInMemoryTmxString | 5.721 μs | 1.78 | 1.8005 | 0.0916 | 23.32 KB | 1.32 |
| TiledCSPlus | MapFromInMemoryTmxString | 6.696 μs | 2.11 | 2.5940 | 0.1831 | 33.23 KB | 1.88 |
| DotTiled | MapFromInMemoryTmxString | 3.092 μs | 1.00 | 1.2970 | 0.0610 | 16.73 KB | 1.00 |
| TiledLib | MapFromInMemoryTmxString | 5.392 μs | 1.75 | 1.8158 | 0.1068 | 23.32 KB | 1.39 |
| TiledCSPlus | MapFromInMemoryTmxString | 6.479 μs | 2.10 | 2.5940 | 0.1831 | 33.16 KB | 1.98 |
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

@ -178,7 +178,7 @@ For enum definitions, the <xref:System.FlagsAttribute> can be used to indicate t
> 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.
> 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:DotTiled.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:DotTiled.EnumProperty> instances.
## Mapping properties to C# classes or enums

View file

@ -5,13 +5,10 @@ Loading maps with DotTiled is very flexible and allows you as a developer to fre
> [!TIP]
> For a quick and easy way to load maps from the filesystem, please refer to the [quickstart guide](../quickstart.md).
## File format caveats
## File formats
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.
> [!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:

View file

@ -12,6 +12,9 @@ Certain properties throughout the representation model are marked as *optional*
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.
You should use one of the versions of DotTiled that is compatible with the version of Tiled you are using.
| Tiled version | Compatible DotTiled version(s) |
|---------------|--------------------------------|
|----------------|--------------------------------|
| 1.11.1, 1.11.2 | 0.4.0 |
| 1.11 | 0.1.0, 0.2.0, 0.2.1, 0.3.0 |

View file

@ -67,3 +67,7 @@ var map = loader.LoadMap("path/to/map.tmx");
var chest = map.GetProperty<CustomClassProperty>("chest").Value;
var coinsToSpawn = chest.GetProperty<IntProperty>("coins").Value;
```
## Examples
See the [DotTiled.Examples](https://github.com/dcronqvist/DotTiled/tree/master/src/DotTiled.Examples) directory for more in-depth examples of how to use DotTiled. The [DotTiled.Example.Raylib](https://github.com/dcronqvist/DotTiled/tree/master/src/DotTiled.Examples/DotTiled.Example.Raylib) example is a good starting point for using DotTiled with Raylib or any similar library/framework. It demonstrates how to load and render a Tiled map, handle player movement, and perform collision detection.

View file

@ -79,6 +79,6 @@ public class Program
[
new CustomClassDefinition() { Name = "a" },
];
return allDefinedTypes.FirstOrDefault(ctd => ctd.Name == name) is ICustomTypeDefinition ctd ? new Optional<ICustomTypeDefinition>(ctd) : Optional<ICustomTypeDefinition>.Empty;
return allDefinedTypes.FirstOrDefault(ctd => ctd.Name == name) is ICustomTypeDefinition ctd ? new Optional<ICustomTypeDefinition>(ctd) : Optional.Empty;
}
}

View file

@ -62,6 +62,6 @@ public partial class MapParser : Node2D
[
new CustomClassDefinition() { Name = "a" },
];
return allDefinedTypes.FirstOrDefault(ctd => ctd.Name == name) is ICustomTypeDefinition ctd ? new Optional<ICustomTypeDefinition>(ctd) : Optional<ICustomTypeDefinition>.Empty;
return allDefinedTypes.FirstOrDefault(ctd => ctd.Name == name) is ICustomTypeDefinition ctd ? new Optional<ICustomTypeDefinition>(ctd) : Optional.Empty;
}
}

View file

@ -0,0 +1,36 @@
{
"version": 1,
"isRoot": true,
"tools": {
"dotnet-mgcb": {
"version": "3.8.3",
"commands": [
"mgcb"
]
},
"dotnet-mgcb-editor": {
"version": "3.8.3",
"commands": [
"mgcb-editor"
]
},
"dotnet-mgcb-editor-linux": {
"version": "3.8.3",
"commands": [
"mgcb-editor-linux"
]
},
"dotnet-mgcb-editor-windows": {
"version": "3.8.3",
"commands": [
"mgcb-editor-windows"
]
},
"dotnet-mgcb-editor-mac": {
"version": "3.8.3",
"commands": [
"mgcb-editor-mac"
]
}
}
}

View file

@ -0,0 +1,52 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace DotTiled.Example.MonoGame;
public class Camera2D
{
public float Zoom { get; set; }
public Vector2 Position { get; set; }
public Rectangle Bounds { get; protected set; }
public Rectangle VisibleArea { get; protected set; }
public Matrix Transform { get; protected set; }
public Camera2D(Viewport viewport)
{
Bounds = viewport.Bounds;
Zoom = 1f;
Position = Vector2.Zero;
}
private void UpdateVisibleArea()
{
var inverseViewMatrix = Matrix.Invert(Transform);
var tl = Vector2.Transform(Vector2.Zero, inverseViewMatrix);
var tr = Vector2.Transform(new Vector2(Bounds.X, 0), inverseViewMatrix);
var bl = Vector2.Transform(new Vector2(0, Bounds.Y), inverseViewMatrix);
var br = Vector2.Transform(new Vector2(Bounds.Width, Bounds.Height), inverseViewMatrix);
var min = new Vector2(
MathHelper.Min(tl.X, MathHelper.Min(tr.X, MathHelper.Min(bl.X, br.X))),
MathHelper.Min(tl.Y, MathHelper.Min(tr.Y, MathHelper.Min(bl.Y, br.Y))));
var max = new Vector2(
MathHelper.Max(tl.X, MathHelper.Max(tr.X, MathHelper.Max(bl.X, br.X))),
MathHelper.Max(tl.Y, MathHelper.Max(tr.Y, MathHelper.Max(bl.Y, br.Y))));
VisibleArea = new Rectangle((int)min.X, (int)min.Y, (int)(max.X - min.X), (int)(max.Y - min.Y));
}
private void UpdateMatrix()
{
Transform = Matrix.CreateTranslation(new Vector3(-Position.X, -Position.Y, 0)) *
Matrix.CreateScale(Zoom) *
Matrix.CreateTranslation(new Vector3(Bounds.Width * 0.5f, Bounds.Height * 0.5f, 0));
UpdateVisibleArea();
}
public void UpdateCamera(Viewport bounds)
{
Bounds = bounds.Bounds;
UpdateMatrix();
}
}

View file

@ -0,0 +1,33 @@
#----------------------------- Global Properties ----------------------------#
/outputDir:bin/$(Platform)
/intermediateDir:obj/$(Platform)
/platform:DesktopGL
/config:
/profile:Reach
/compress:False
#-------------------------------- References --------------------------------#
#---------------------------------- Content ---------------------------------#
#begin kenney_roguelike-rpg-pack/roguelikeSheet_transparent.png
/importer:TextureImporter
/processor:TextureProcessor
/processorParam:ColorKeyColor=255,0,255,255
/processorParam:ColorKeyEnabled=True
/processorParam:GenerateMipmaps=False
/processorParam:PremultiplyAlpha=True
/processorParam:ResizeToPowerOfTwo=False
/processorParam:MakeSquare=False
/processorParam:TextureFormat=Color
/build:kenney_roguelike-rpg-pack/roguelikeSheet_transparent.png
#begin world-tileset.tsx
/copy:world-tileset.tsx
#begin world.tmx
/copy:world.tmx

View file

@ -0,0 +1,23 @@
###############################################################################
Roguelike pack
by Kenney Vleugels for Kenney (www.kenney.nl)
with help by Lynn Evers (Twitter: @EversLynn)
------------------------------
License (Creative Commons Zero, CC0)
http://creativecommons.org/publicdomain/zero/1.0/
You may use these graphics in personal and commercial projects.
Credit (Kenney or www.kenney.nl) would be nice but is not mandatory.
------------------------------
Donate: http://donate.kenney.nl/
Request: http://request.kenney.nl/
###############################################################################

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

View file

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<tileset version="1.10" tiledversion="1.11.2" name="roguelikeSheet_transparent" tilewidth="16" tileheight="16" spacing="1" tilecount="1767" columns="57">
<image source="kenney_roguelike-rpg-pack/roguelikeSheet_transparent.png" width="968" height="526"/>
<wangsets>
<wangset name="Stuff" type="mixed" tile="-1">
<wangcolor name="Brown path" color="#ff0000" tile="692" probability="1"/>
<wangcolor name="Water" color="#00ff00" tile="-1" probability="1"/>
<wangtile tileid="2" wangid="0,0,2,2,2,0,0,0"/>
<wangtile tileid="3" wangid="0,0,2,2,2,2,2,0"/>
<wangtile tileid="4" wangid="0,0,0,0,2,2,2,0"/>
<wangtile tileid="57" wangid="2,2,2,0,2,2,2,2"/>
<wangtile tileid="58" wangid="2,2,2,2,2,0,2,2"/>
<wangtile tileid="59" wangid="2,2,2,2,2,0,0,0"/>
<wangtile tileid="60" wangid="2,2,2,2,2,2,2,2"/>
<wangtile tileid="61" wangid="2,0,0,0,2,2,2,2"/>
<wangtile tileid="114" wangid="2,0,2,2,2,2,2,2"/>
<wangtile tileid="115" wangid="2,2,2,2,2,2,2,0"/>
<wangtile tileid="116" wangid="2,2,2,0,0,0,0,0"/>
<wangtile tileid="117" wangid="2,2,2,0,0,0,2,2"/>
<wangtile tileid="118" wangid="2,0,0,0,0,0,2,2"/>
<wangtile tileid="404" wangid="0,0,1,0,1,0,1,0"/>
<wangtile tileid="405" wangid="1,0,0,0,1,0,1,0"/>
<wangtile tileid="406" wangid="0,0,1,0,1,0,0,0"/>
<wangtile tileid="407" wangid="0,0,0,0,1,0,1,0"/>
<wangtile tileid="408" wangid="1,0,0,0,1,0,0,0"/>
<wangtile tileid="461" wangid="1,0,1,0,1,0,0,0"/>
<wangtile tileid="462" wangid="1,0,1,0,0,0,1,0"/>
<wangtile tileid="463" wangid="1,0,1,0,0,0,0,0"/>
<wangtile tileid="464" wangid="1,0,0,0,0,0,1,0"/>
<wangtile tileid="465" wangid="0,0,1,0,0,0,1,0"/>
<wangtile tileid="632" wangid="1,0,0,0,0,0,0,0"/>
<wangtile tileid="633" wangid="0,0,0,0,1,0,0,0"/>
<wangtile tileid="689" wangid="0,0,0,0,0,0,1,0"/>
<wangtile tileid="690" wangid="0,0,1,0,0,0,0,0"/>
<wangtile tileid="691" wangid="1,0,1,0,1,0,1,0"/>
</wangset>
</wangsets>
</tileset>

View file

@ -0,0 +1,434 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.11.2" orientation="orthogonal" renderorder="right-down" width="50" height="50" tilewidth="16" tileheight="16" infinite="0" nextlayerid="13" nextobjectid="51">
<tileset firstgid="1" source="world-tileset.tsx"/>
<group id="11" name="Visuals">
<layer id="1" name="Ground" width="50" height="50">
<data encoding="csv">
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6
</data>
</layer>
<layer id="4" name="Ponds" width="50" height="50">
<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,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,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,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,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,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,0,0,0,0,0,0,0,0,0,0,0,0,0,3,4,4,5,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,3,4,4,4,116,61,61,115,5,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,3,4,4,116,61,61,61,61,61,61,61,115,5,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,3,116,61,61,61,61,61,61,61,61,61,61,61,62,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,3,116,61,61,61,61,58,118,118,59,61,61,61,61,115,5,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,60,61,61,61,58,118,119,0,0,117,118,59,61,61,61,62,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,60,61,61,58,119,0,0,0,0,0,0,60,61,61,61,62,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,3,116,61,61,62,0,0,0,0,0,0,3,116,61,61,61,62,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,60,61,61,61,115,5,0,0,0,0,0,60,61,61,61,61,62,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,60,61,61,61,61,115,4,4,4,4,4,116,61,61,61,61,62,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,60,61,61,61,61,61,61,61,61,61,61,61,61,61,61,58,119,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,117,59,61,61,61,61,61,61,61,61,61,61,61,61,61,62,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,60,61,61,61,61,61,61,61,61,61,61,61,58,118,119,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,117,118,118,118,118,118,118,118,118,118,118,118,119,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,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,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,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,3,4,4,4,4,4,4,5,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,60,61,61,61,61,61,61,115,4,5,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,3,116,61,61,61,61,61,61,61,61,115,4,5,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,60,61,61,61,61,61,61,61,61,61,61,61,115,4,5,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,3,116,61,61,61,61,61,61,61,61,61,61,61,61,61,115,4,5,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,60,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,115,5,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,60,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,62,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,3,116,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,58,119,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,60,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,58,119,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,3,116,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,58,119,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,60,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,58,119,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,60,61,61,61,61,61,61,61,61,61,61,61,61,61,58,118,119,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,117,59,61,61,61,61,61,61,61,61,61,58,118,118,119,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,117,118,118,59,61,61,61,58,118,118,119,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,117,118,118,118,119,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,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,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,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,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,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,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,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,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,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,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,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,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,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
</data>
</layer>
<layer id="3" name="Paths" width="50" height="50">
<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,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,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,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,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,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,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,407,466,466,466,466,466,466,466,466,466,690,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,407,466,466,466,466,466,466,466,466,466,465,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,409,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,409,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,409,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,409,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,409,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,409,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,464,466,408,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,464,466,408,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,464,466,408,0,0,634,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,464,466,405,406,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,464,463,408,0,0,0,0,634,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,464,466,408,0,0,409,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,464,466,466,463,408,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,464,466,466,466,466,466,466,408,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,464,466,466,466,466,466,466,408,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,464,466,466,466,408,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,409,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,409,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,409,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,407,465,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,409,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,409,0,0,0,0,634,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,462,466,466,466,466,465,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,407,466,466,465,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,407,466,466,466,466,465,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,407,466,466,466,466,465,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,407,466,405,465,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,407,466,465,0,409,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,407,465,0,0,0,409,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,407,466,465,0,0,0,0,409,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,407,466,465,0,0,0,0,0,0,409,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,407,466,466,466,466,466,466,466,466,466,466,466,466,466,466,466,465,0,0,0,0,0,0,0,0,464,408,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,409,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,464,408,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,409,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,464,408,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,409,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,464,466,408,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,409,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,464,466,408,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,409,0,0,634,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,464,466,466,466,466,466,466,690,0,0,0,0,0,0,0,
0,0,0,464,466,466,465,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,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,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,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,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
</data>
</layer>
<layer id="5" name="HouseWalls" width="50" height="50">
<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,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,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,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,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,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,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,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,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,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,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,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,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,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,873,874,875,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,873,874,875,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,870,869,872,0,0,0,873,874,875,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,873,874,875,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,870,869,872,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,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,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,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,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,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,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,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,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,873,874,875,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,873,874,875,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,870,869,872,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,873,874,875,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,873,874,875,0,0,873,874,875,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,873,874,875,0,0,870,869,872,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,870,869,872,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,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,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,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,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,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,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,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,873,874,875,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,873,874,875,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,873,874,875,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,873,874,875,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,870,869,872,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,870,869,872,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,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,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,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,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,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,0,0,0,0,0,0,0,0,0
</data>
</layer>
<layer id="8" name="HouseDoors" width="50" height="50">
<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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,41,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,33,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,0,0,0,0,0,46,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,33,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,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,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,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,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,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,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,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,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,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,43,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,33,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,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,43,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,41,0,0,0,0,33,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,33,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,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,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,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,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,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,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,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,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,41,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,43,0,43,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,33,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,33,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,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,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,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,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,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,0,0,0,0,0,0,0,0,0,0
</data>
</layer>
<layer id="7" name="FencesBushes" width="50" height="50">
<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,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,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,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,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,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,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,1360,1365,1365,1365,1365,1365,1365,1361,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,0,0,0,0,0,0,0,0,0,0,0,1360,1365,1365,1365,1365,1365,1365,1361,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,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,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,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,0,0,0,0,1362,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,1362,0,1363,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,1362,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,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,0,0,1360,1365,1361,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,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,1360,1361,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,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,1363,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,1360,1361,0,0,0,0,1362,0,1363,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,1362,0,1363,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,1360,1361,0,0,0,1362,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,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,1360,1365,1365,1365,1365,1365,1365,1361,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,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,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,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,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,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,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,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,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,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
</data>
</layer>
<layer id="6" name="HouseRoofs" width="50" height="50">
<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,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,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,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,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,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,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,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,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,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,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,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,1218,1223,1219,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,1275,1280,1276,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,1332,1277,1333,0,0,0,1218,1223,1219,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,1275,1280,1276,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,1332,1277,1333,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,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,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,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,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,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,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,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,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1218,1223,1219,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,1275,1280,1276,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,1332,1277,1333,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,1218,1223,1219,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,1218,1223,1219,0,0,1275,1280,1276,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,1275,1280,1276,0,0,1332,1277,1333,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,1332,1277,1333,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,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,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,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,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,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,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,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,1218,1223,1219,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,1218,1223,1219,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,1275,1280,1276,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,1275,1280,1276,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,1332,1277,1333,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,1332,1277,1333,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,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,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,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,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,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,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,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,0,0,0,0,0,0,0,0,0
</data>
</layer>
</group>
<objectgroup id="10" name="Collisions">
<object id="1" x="80" y="656" width="48" height="48"/>
<object id="2" x="496" y="480" width="48" height="48"/>
<object id="3" x="576" y="464" width="48" height="48"/>
<object id="4" x="608" y="656" width="48" height="48"/>
<object id="5" x="736" y="416" width="48" height="48"/>
<object id="6" x="368" y="240" width="48" height="48"/>
<object id="7" x="272" y="208" width="48" height="48"/>
<object id="10" x="144" y="640" width="128" height="16"/>
<object id="11" x="352" y="608" width="32" height="16"/>
<object id="12" x="336" y="576" width="32" height="16"/>
<object id="13" x="432" y="528" width="32" height="16"/>
<object id="14" x="444.826" y="576" width="3.17391" height="48"/>
<object id="15" x="464" y="560" width="3.17391" height="48"/>
<object id="16" x="668.875" y="432" width="3.125" height="48"/>
<object id="17" x="688" y="448" width="3.25" height="16"/>
<object id="19" x="704" y="496" width="48" height="16"/>
<object id="20" x="464" y="368" width="128" height="16"/>
<object id="21" x="160" y="96" width="128" height="16"/>
<object id="24" x="80" y="496" width="240" height="64"/>
<object id="25" x="96" y="560" width="176" height="16"/>
<object id="26" x="144" y="576" width="80" height="16"/>
<object id="28" x="144" y="352" width="128" height="144"/>
<object id="29" x="128" y="384" width="16" height="112"/>
<object id="30" x="112" y="416" width="16" height="80"/>
<object id="31" x="96" y="464" width="16" height="32"/>
<object id="32" x="272" y="368" width="32" height="128"/>
<object id="33" x="304" y="384" width="32" height="112"/>
<object id="35" x="336" y="400" width="32" height="128"/>
<object id="36" x="368" y="416" width="16" height="96"/>
<object id="37" x="384" y="416" width="16" height="80"/>
<object id="38" x="400" y="432" width="16" height="48"/>
<object id="39" x="320" y="496" width="16" height="48"/>
<object id="40" x="336" y="528" width="16" height="16"/>
<object id="41" x="464" y="224" width="208" height="80"/>
<object id="42" x="544" y="96" width="128" height="128"/>
<object id="43" x="448" y="192" width="16" height="80"/>
<object id="44" x="464" y="144" width="80" height="80"/>
<object id="45" x="496" y="112" width="48" height="32"/>
<object id="46" x="480" y="128" width="16" height="16"/>
<object id="47" x="608" y="80" width="64" height="16"/>
<object id="48" x="672" y="96" width="16" height="192"/>
<object id="49" x="688" y="112" width="16" height="176"/>
<object id="50" x="704" y="144" width="16" height="112"/>
</objectgroup>
<objectgroup id="12" name="PointsOfInterest">
<object id="8" name="PlayerSpawn" x="425" y="343.5">
<point/>
</object>
</objectgroup>
</map>

View file

@ -0,0 +1,36 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<RollForward>Major</RollForward>
<PublishReadyToRun>false</PublishReadyToRun>
<TieredCompilation>false</TieredCompilation>
</PropertyGroup>
<PropertyGroup>
<ApplicationManifest>app.manifest</ApplicationManifest>
<ApplicationIcon>Icon.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<None Remove="Icon.ico" />
<None Remove="Icon.bmp" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Icon.ico">
<LogicalName>Icon.ico</LogicalName>
</EmbeddedResource>
<EmbeddedResource Include="Icon.bmp">
<LogicalName>Icon.bmp</LogicalName>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.*" />
<PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.*" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\DotTiled\DotTiled.csproj" />
</ItemGroup>
<Target Name="RestoreDotnetTools" BeforeTargets="Restore">
<Message Text="Restoring dotnet tools" Importance="High" />
<Exec Command="dotnet tool restore" />
</Target>
</Project>

View file

@ -0,0 +1,231 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using DotTiled.Serialization;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
namespace DotTiled.Example.MonoGame;
/// <summary>
/// A beginner-friendly example of using DotTiled with MonoGame.
/// Loads a Tiled map, renders its layers, and allows basic player movement with collision.
/// </summary>
public class Game1 : Game
{
private readonly GraphicsDeviceManager _graphics;
private SpriteBatch _spriteBatch;
// Camera for following the player
private Camera2D _camera;
// DotTiled map and tileset textures
private Map _map;
private Dictionary<string, Texture2D> _tilesetTextures;
// Layers for collisions and points of interest
private ObjectLayer _collisionLayer;
private ObjectLayer _pointsOfInterestLayer;
// Player state
private Vector2 _playerPosition;
private Texture2D _playerTexture;
// Used for drawing rectangles (player)
private Texture2D _whitePixel;
public Game1()
{
_graphics = new GraphicsDeviceManager(this)
{
PreferredBackBufferWidth = 1280,
PreferredBackBufferHeight = 720
};
Content.RootDirectory = "Content";
IsMouseVisible = true;
}
/// <summary>
/// MonoGame initialization.
/// </summary>
protected override void Initialize() => base.Initialize();
/// <summary>
/// Load map, textures, and initialize player/camera.
/// </summary>
protected override void LoadContent()
{
_spriteBatch = new SpriteBatch(GraphicsDevice);
// Used for drawing rectangles (player)
_whitePixel = new Texture2D(GraphicsDevice, 1, 1);
_whitePixel.SetData(new[] { Color.White });
// Load the Tiled map using DotTiled
var loader = Loader.Default();
_map = loader.LoadMap(Path.Combine(Content.RootDirectory, "world.tmx"));
// Load all tileset textures referenced by the map
_tilesetTextures = LoadTilesetTextures(_map);
// Extract layers for collisions and points of interest
_collisionLayer = _map.Layers.OfType<ObjectLayer>().Single(l => l.Name == "Collisions");
_pointsOfInterestLayer = (ObjectLayer)_map.Layers.Single(l => l.Name == "PointsOfInterest");
// Get the player's spawn point from the PointsOfInterest layer
var playerSpawn = _pointsOfInterestLayer.Objects.Single(obj => obj.Name == "PlayerSpawn");
_playerPosition = new Vector2(playerSpawn.X, playerSpawn.Y);
// Set up the camera to follow the player
_camera = new Camera2D(GraphicsDevice.Viewport);
// Optionally, create a simple player texture (blue rectangle)
_playerTexture = new Texture2D(GraphicsDevice, 1, 1);
_playerTexture.SetData(new[] { Color.Blue });
}
/// <summary>
/// Loads all tileset textures referenced by the map.
/// </summary>
private Dictionary<string, Texture2D> LoadTilesetTextures(Map map)
{
// Remove ".png" for MonoGame Content Pipeline compatibility
return map.Tilesets.ToDictionary(
tileset => tileset.Image.Value.Source.Value,
tileset => Content.Load<Texture2D>(Path.GetDirectoryName(tileset.Image.Value.Source.Value) + "/" + Path.GetFileNameWithoutExtension(tileset.Image.Value.Source.Value))
);
}
/// <summary>
/// Handles player input and updates game logic.
/// </summary>
protected override void Update(GameTime gameTime)
{
// Exit on Escape
if (Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
_camera.UpdateCamera(GraphicsDevice.Viewport);
// Handle player movement input
var move = HandlePlayerInput(gameTime);
// Define the player's collision rectangle
var playerRect = new Rectangle((int)_playerPosition.X, (int)_playerPosition.Y, 12, 12);
// Collision detection with rectangles in the collision layer
foreach (var obj in _collisionLayer.Objects.OfType<RectangleObject>())
{
var objRect = new Rectangle((int)obj.X, (int)obj.Y, (int)obj.Width, (int)obj.Height);
// Horizontal collision
var movePlayerHRect = new Rectangle(playerRect.X + (int)move.X, playerRect.Y, playerRect.Width, playerRect.Height);
if (move.X != 0 && movePlayerHRect.Intersects(objRect))
move.X = 0;
// Vertical collision
var movePlayerVRect = new Rectangle(playerRect.X, playerRect.Y + (int)move.Y, playerRect.Width, playerRect.Height);
if (move.Y != 0 && movePlayerVRect.Intersects(objRect))
move.Y = 0;
}
// Update player position
_playerPosition += move;
// Smoothly update the camera to follow the player
var newCameraTarget = new Vector2(_playerPosition.X, _playerPosition.Y);
_camera.Position += (newCameraTarget - _camera.Position) * 15f * (float)gameTime.ElapsedGameTime.TotalSeconds;
base.Update(gameTime);
}
/// <summary>
/// Handles WASD input for player movement.
/// </summary>
private static Vector2 HandlePlayerInput(GameTime gameTime)
{
var move = Vector2.Zero;
var speed = 150f * (float)gameTime.ElapsedGameTime.TotalSeconds;
var state = Keyboard.GetState();
if (state.IsKeyDown(Keys.W)) move.Y -= speed;
if (state.IsKeyDown(Keys.S)) move.Y += speed;
if (state.IsKeyDown(Keys.A)) move.X -= speed;
if (state.IsKeyDown(Keys.D)) move.X += speed;
return move;
}
/// <summary>
/// Draws the map, player, and handles layer ordering.
/// </summary>
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Black);
_spriteBatch.Begin(transformMatrix: _camera.Transform);
// Get all visual tile layers from the "Visuals" group
var visualLayers = _map.Layers.OfType<Group>().Single(l => l.Name == "Visuals").Layers.OfType<TileLayer>();
// Render layers below the player
RenderLayers(_map, visualLayers, _tilesetTextures, ["Ground", "Ponds", "Paths", "HouseWalls", "HouseDoors", "FencesBushes"]);
// Draw the player as a blue rectangle (centered on tile)
var playerVisualRect = new Rectangle((int)_playerPosition.X, (int)_playerPosition.Y - 12, 12, 24);
_spriteBatch.Draw(_playerTexture, playerVisualRect, Color.White);
// Render layers above the player
RenderLayers(_map, visualLayers, _tilesetTextures, ["HouseRoofs"]);
_spriteBatch.End();
base.Draw(gameTime);
}
/// <summary>
/// Renders specific named layers from the map.
/// </summary>
private void RenderLayers(Map map, IEnumerable<TileLayer> visualLayers, Dictionary<string, Texture2D> tilesetTextures, string[] layerNames)
{
foreach (var layerName in layerNames)
{
var layer = visualLayers.Single(l => l.Name == layerName);
RenderLayer(map, layer, tilesetTextures);
}
}
/// <summary>
/// Renders a single tile layer.
/// </summary>
private void RenderLayer(Map map, TileLayer layer, Dictionary<string, Texture2D> tilesetTextures)
{
for (var y = 0; y < layer.Height; y++)
{
for (var x = 0; x < layer.Width; x++)
{
var tileGID = layer.GetGlobalTileIDAtCoord(x, y);
if (tileGID == 0) continue;
var tileset = map.ResolveTilesetForGlobalTileID(tileGID, out var localTileID);
var sourceRect = tileset.GetSourceRectangleForLocalTileID(localTileID);
var destination = new Vector2(x * tileset.TileWidth, y * tileset.TileHeight);
var sourceRectangle = new Rectangle(sourceRect.X + 1, sourceRect.Y + 1, sourceRect.Width - 2, sourceRect.Height - 2);
_spriteBatch.Draw(
tilesetTextures[tileset.Image.Value.Source.Value],
destination,
sourceRectangle,
Color.White,
0f,
Vector2.Zero,
Vector2.One * (1f / (14f / 16f)), // Shrink by a tiny amount to avoid seams (not a perfect solution)
SpriteEffects.None,
0f
);
}
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

View file

@ -0,0 +1,2 @@
using var game = new DotTiled.Example.MonoGame.Game1();
game.Run();

View file

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="DotTiled.Example.MonoGame"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- A list of the Windows versions that this application has been tested on and is
is designed to work with. Uncomment the appropriate elements and Windows will
automatically selected the most compatible environment. -->
<!-- Windows Vista -->
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">permonitorv2,permonitor</dpiAwareness>
</windowsSettings>
</application>
</assembly>

View file

@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>disable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Raylib-cs" Version="7.0.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\DotTiled\DotTiled.csproj" />
</ItemGroup>
<ItemGroup>
<Content Include="assets\**\*.*" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,203 @@
using System.Numerics;
using DotTiled.Serialization;
using Raylib_cs;
using RayColor = Raylib_cs.Color;
namespace DotTiled.Example
{
public class Program
{
public static void Main(string[] _)
{
// Initialize the Raylib window
Raylib.InitWindow(1280, 720, "DotTiled Example with Raylib");
Raylib.SetConfigFlags(ConfigFlags.VSyncHint);
// Load the Tiled map
var loader = Loader.Default();
var map = loader.LoadMap("assets/world.tmx");
// Load tileset textures
var tilesetTextures = LoadTilesetTextures(map);
// Extract layers from the map
var visualLayers = map.Layers.OfType<Group>().Single(l => l.Name == "Visuals").Layers.OfType<TileLayer>();
var collisionLayer = map.Layers.OfType<ObjectLayer>().Single(l => l.Name == "Collisions");
var pointsOfInterest = (ObjectLayer)map.Layers.Single(layer => layer.Name == "PointsOfInterest");
// Get the player's spawn point
var playerSpawnPoint = pointsOfInterest.Objects.Single(obj => obj.Name == "PlayerSpawn");
var playerPosition = new Vector2(playerSpawnPoint.X, playerSpawnPoint.Y);
// Set up the camera
var camera = new Camera2D
{
Target = playerPosition,
Offset = new Vector2(Raylib.GetScreenWidth() / 2, Raylib.GetScreenHeight() / 2),
Rotation = 0.0f,
Zoom = 1.0f
};
// Main game loop
while (!Raylib.WindowShouldClose())
{
// Update game logic
Update(ref playerPosition, collisionLayer, ref camera);
// Render the game
Render(map, visualLayers, tilesetTextures, playerPosition, camera);
}
// Clean up resources
Raylib.CloseWindow();
}
/// <summary>
/// Loads tileset textures from the map.
/// </summary>
private static Dictionary<string, Texture2D> LoadTilesetTextures(Map map)
{
return map.Tilesets.ToDictionary(
tileset => tileset.Image.Value.Source.Value,
tileset => Raylib.LoadTexture(Path.Combine("assets", tileset.Image.Value.Source.Value))
);
}
/// <summary>
/// Updates the player's position and camera.
/// </summary>
private static void Update(ref Vector2 playerPosition, ObjectLayer collisionLayer, ref Camera2D camera)
{
// Define the player's rectangle
var playerRect = new Rectangle(playerPosition.X, playerPosition.Y, 12, 12);
// Handle player movement
var move = HandlePlayerInput();
// Check for collisions
foreach (var obj in collisionLayer.Objects.OfType<RectangleObject>())
{
var objRect = new Rectangle(obj.X, obj.Y, obj.Width, obj.Height);
// Horizontal collision
var movePlayerHRect = new Rectangle(playerRect.X + move.X, playerRect.Y, playerRect.Width, playerRect.Height);
if (Raylib.CheckCollisionRecs(movePlayerHRect, objRect))
{
move.X = 0;
}
// Vertical collision
var movePlayerVRect = new Rectangle(playerRect.X, playerRect.Y + move.Y, playerRect.Width, playerRect.Height);
if (Raylib.CheckCollisionRecs(movePlayerVRect, objRect))
{
move.Y = 0;
}
}
// Update player position
playerPosition += move;
// Smoothly update the camera target
var newCameraTarget = new Vector2(playerPosition.X, playerPosition.Y);
camera.Target += (newCameraTarget - camera.Target) * 15f * Raylib.GetFrameTime();
}
/// <summary>
/// Handles player input for movement.
/// </summary>
private static Vector2 HandlePlayerInput()
{
var move = Vector2.Zero;
var playerSpeed = 150 * Raylib.GetFrameTime();
if (Raylib.IsKeyDown(KeyboardKey.W)) move.Y -= playerSpeed;
if (Raylib.IsKeyDown(KeyboardKey.S)) move.Y += playerSpeed;
if (Raylib.IsKeyDown(KeyboardKey.A)) move.X -= playerSpeed;
if (Raylib.IsKeyDown(KeyboardKey.D)) move.X += playerSpeed;
return move;
}
/// <summary>
/// Renders the game, including layers and the player.
/// </summary>
private static void Render(Map map, IEnumerable<TileLayer> visualLayers, Dictionary<string, Texture2D> tilesetTextures, Vector2 playerPosition, Camera2D camera)
{
Raylib.BeginDrawing();
Raylib.ClearBackground(RayColor.Blank);
Raylib.BeginMode2D(camera);
// Render layers below the player
RenderLayers(map, visualLayers, tilesetTextures, ["Ground", "Ponds", "Paths", "HouseWalls", "HouseDoors", "FencesBushes"]);
// Draw the player
var playerVisualRect = new Rectangle(playerPosition.X, playerPosition.Y - 12, 12, 24);
Raylib.DrawRectangleRec(playerVisualRect, RayColor.Blue);
// Render layers above the player
RenderLayers(map, visualLayers, tilesetTextures, ["HouseRoofs"]);
Raylib.EndMode2D();
Raylib.EndDrawing();
}
/// <summary>
/// Renders specific layers from the map.
/// </summary>
private static void RenderLayers(Map map, IEnumerable<TileLayer> visualLayers, Dictionary<string, Texture2D> tilesetTextures, string[] layerNames)
{
foreach (var layerName in layerNames)
{
var layer = visualLayers.OfType<TileLayer>().Single(l => l.Name == layerName);
RenderLayer(map, layer, tilesetTextures);
}
}
/// <summary>
/// Renders a single layer from the map.
/// </summary>
private static void RenderLayer(Map map, TileLayer layer, Dictionary<string, Texture2D> tilesetTextures)
{
for (var y = 0; y < layer.Height; y++)
{
for (var x = 0; x < layer.Width; x++)
{
var tileGID = layer.GetGlobalTileIDAtCoord(x, y);
if (tileGID == 0) continue;
var tileset = map.ResolveTilesetForGlobalTileID(tileGID, out var localTileID);
var sourceRect = tileset.GetSourceRectangleForLocalTileID(localTileID);
// Source rec is shrunk by tiny amount to avoid ugly seams between tiles
// when the camera is at certain subpixel positions
var raylibSourceRect = ShrinkRectangle(new Rectangle(sourceRect.X, sourceRect.Y, sourceRect.Width, sourceRect.Height), 0.01f);
var destinationRect = new Rectangle(x * tileset.TileWidth, y * tileset.TileHeight, tileset.TileWidth, tileset.TileHeight);
Raylib.DrawTexturePro(
tilesetTextures[tileset.Image.Value.Source.Value],
raylibSourceRect,
destinationRect,
Vector2.Zero,
0,
RayColor.White
);
}
}
}
/// <summary>
/// Shrinks a rectangle by a specified amount.
/// </summary>
private static Rectangle ShrinkRectangle(Rectangle rect, float amount)
{
return new Rectangle(
rect.X + amount,
rect.Y + amount,
rect.Width - (2 * amount),
rect.Height - (2 * amount)
);
}
}
}

View file

@ -0,0 +1,122 @@
# DotTiled Example with Raylib
This project demonstrates how to use the [DotTiled](https://github.com/dot-tiled/dot-tiled) library to load and render Tiled maps in a game using [Raylib](https://www.raylib.com/). It is designed to be beginner-friendly and serves as a starting point for anyone looking to integrate Tiled maps into their games.
<p>
<img align="right" src="media/raylib_screenshot.png" alt="Screenshot of map rendered using Raylib" hspace="2%" width="40%"/>
<img src="media/tiled_screenshot.png" alt="Screenshot of map in Tiled" hspace="2%" width="40%"/>
</p>
### How It Works
This example project loads a Tiled map (`world.tmx`), renders its layers, and allows basic player movement with collision detection. The project is structured to prioritize readability and ease of understanding.
#### Key Features:
1. **Loading Tiled Maps**: Uses DotTiled to parse `.tmx` files and extract map data.
2. **Rendering Layers**: Renders specific layers (e.g., ground, objects, roofs) using Raylib.
3. **Player Movement**: Handles player input and updates the player's position.
4. **Collision Detection**: Prevents the player from moving through objects defined in the collision layer.
5. **Camera Tracking**: Smoothly follows the player as they move.
### Map Structure
The Tiled map (`world.tmx`) is structured into different types of layers to organize the game world:
1. **Tile Layers (Visuals)**:
- These layers define the visual elements of the map, such as the ground, paths, ponds, walls, and roofs.
- Each layer is rendered in a specific order to ensure that the player appears between certain layers (e.g., under roofs but above the ground).
2. **Object Layers (Collisions)**:
- These layers define areas where the player cannot move, such as walls or obstacles.
- Each object in the layer is represented as a rectangle, and collision detection is performed against these objects.
3. **Object Layer (Player Spawn)**:
- This layer contains a single point object that defines the player's starting position.
- The object is named `PlayerSpawn` and is used to initialize the player's position in the game.
This is just one way to structure a map for use with DotTiled. As you become more comfortable with Tiled and DotTiled, you can experiment with different layer types and configurations to suit your game's needs.
### Project Structure
Main Components:
- `Main` **Method**: Initializes the game window, loads the map, and runs the main game loop.
- `Update` **Method**: Handles player movement, collision detection, and camera updates.
- `Render` **Method**: Draws the map layers and the player.
### Code Walkthrough
1. **Loading the Map**
The map is loaded using DotTiled's `Loader` class. The `world.tmx` file is located in the [assets](assets/) folder.
```csharp
var loader = Loader.Default();
var map = loader.LoadMap("assets/world.tmx");
```
2. **Rendering Layers**
The `RenderLayers` method renders specific layers from the map. For example, the ground and paths are rendered below the player, while roofs are rendered above.
```csharp
RenderLayers(map, visualLayers, tilesetTextures, new[] { "Ground", "Ponds", "Paths" });
```
3. **Player Movement**
Player movement is handled in the `HandlePlayerInput` method. The `W`, `A`, `S`, and `D` keys are used to move the player.
4. **Collision Detection**
The `Update` method checks for collisions between the player and objects in the collision layer. If a collision is detected, the player's movement is stopped.
```csharp
if (Raylib.CheckCollisionRecs(movePlayerHRect, objRect)) move.X = 0;
if (Raylib.CheckCollisionRecs(movePlayerVRect, objRect)) move.Y = 0;
```
5. **Camera Tracking**
The camera smoothly follows the player using linear interpolation.
```csharp
camera.Target += (newCameraTarget - camera.Target) * 15f * Raylib.GetFrameTime();
```
### Replacing Raylib with another library or framework
If you want to replace Raylib with another library or framework, you will need to modify the rendering and input handling code. The core logic for loading and parsing the Tiled map using DotTiled will remain the same.
1. **Window initialization**:
Replace the Raylib window initialization with the equivalent code for your chosen library or framework.
2. **Rendering**:
Modify the rendering code to use the graphics API of your chosen library. This includes loading textures, drawing sprites, and handling camera transformations.
For example, replace this tile rendering draw call with the equivalent in your library:
```csharp
Raylib.DrawTexturePro(
tilesetTextures[tileset.Image.Value.Source.Value],
raylibSourceRect,
destinationRect,
Vector2.Zero,
0,
RayColor.White
);
```
3. **Input handling**:
Replace the Raylib input handling code with the equivalent code for your chosen library. This includes checking for key presses or similar.
### Running the Example
1. Clone this repository
2. Navigate to the `DotTiled.Example.Raylib` directory.
3. Run the project using your preferred IDE or command line tool.
- `dotnet run` (if using .NET CLI)
- Open the project in your IDE of choice and run it from there.

View file

@ -0,0 +1,23 @@
###############################################################################
Roguelike pack
by Kenney Vleugels for Kenney (www.kenney.nl)
with help by Lynn Evers (Twitter: @EversLynn)
------------------------------
License (Creative Commons Zero, CC0)
http://creativecommons.org/publicdomain/zero/1.0/
You may use these graphics in personal and commercial projects.
Credit (Kenney or www.kenney.nl) would be nice but is not mandatory.
------------------------------
Donate: http://donate.kenney.nl/
Request: http://request.kenney.nl/
###############################################################################

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

View file

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<tileset version="1.10" tiledversion="1.11.2" name="roguelikeSheet_transparent" tilewidth="16" tileheight="16" spacing="1" tilecount="1767" columns="57">
<image source="kenney_roguelike-rpg-pack/roguelikeSheet_transparent.png" width="968" height="526"/>
<wangsets>
<wangset name="Stuff" type="mixed" tile="-1">
<wangcolor name="Brown path" color="#ff0000" tile="692" probability="1"/>
<wangcolor name="Water" color="#00ff00" tile="-1" probability="1"/>
<wangtile tileid="2" wangid="0,0,2,2,2,0,0,0"/>
<wangtile tileid="3" wangid="0,0,2,2,2,2,2,0"/>
<wangtile tileid="4" wangid="0,0,0,0,2,2,2,0"/>
<wangtile tileid="57" wangid="2,2,2,0,2,2,2,2"/>
<wangtile tileid="58" wangid="2,2,2,2,2,0,2,2"/>
<wangtile tileid="59" wangid="2,2,2,2,2,0,0,0"/>
<wangtile tileid="60" wangid="2,2,2,2,2,2,2,2"/>
<wangtile tileid="61" wangid="2,0,0,0,2,2,2,2"/>
<wangtile tileid="114" wangid="2,0,2,2,2,2,2,2"/>
<wangtile tileid="115" wangid="2,2,2,2,2,2,2,0"/>
<wangtile tileid="116" wangid="2,2,2,0,0,0,0,0"/>
<wangtile tileid="117" wangid="2,2,2,0,0,0,2,2"/>
<wangtile tileid="118" wangid="2,0,0,0,0,0,2,2"/>
<wangtile tileid="404" wangid="0,0,1,0,1,0,1,0"/>
<wangtile tileid="405" wangid="1,0,0,0,1,0,1,0"/>
<wangtile tileid="406" wangid="0,0,1,0,1,0,0,0"/>
<wangtile tileid="407" wangid="0,0,0,0,1,0,1,0"/>
<wangtile tileid="408" wangid="1,0,0,0,1,0,0,0"/>
<wangtile tileid="461" wangid="1,0,1,0,1,0,0,0"/>
<wangtile tileid="462" wangid="1,0,1,0,0,0,1,0"/>
<wangtile tileid="463" wangid="1,0,1,0,0,0,0,0"/>
<wangtile tileid="464" wangid="1,0,0,0,0,0,1,0"/>
<wangtile tileid="465" wangid="0,0,1,0,0,0,1,0"/>
<wangtile tileid="632" wangid="1,0,0,0,0,0,0,0"/>
<wangtile tileid="633" wangid="0,0,0,0,1,0,0,0"/>
<wangtile tileid="689" wangid="0,0,0,0,0,0,1,0"/>
<wangtile tileid="690" wangid="0,0,1,0,0,0,0,0"/>
<wangtile tileid="691" wangid="1,0,1,0,1,0,1,0"/>
</wangset>
</wangsets>
</tileset>

View file

@ -0,0 +1,434 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.11.2" orientation="orthogonal" renderorder="right-down" width="50" height="50" tilewidth="16" tileheight="16" infinite="0" nextlayerid="13" nextobjectid="51">
<tileset firstgid="1" source="world-tileset.tsx"/>
<group id="11" name="Visuals">
<layer id="1" name="Ground" width="50" height="50">
<data encoding="csv">
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6
</data>
</layer>
<layer id="4" name="Ponds" width="50" height="50">
<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,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,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,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,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,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,0,0,0,0,0,0,0,0,0,0,0,0,0,3,4,4,5,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,3,4,4,4,116,61,61,115,5,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,3,4,4,116,61,61,61,61,61,61,61,115,5,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,3,116,61,61,61,61,61,61,61,61,61,61,61,62,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,3,116,61,61,61,61,58,118,118,59,61,61,61,61,115,5,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,60,61,61,61,58,118,119,0,0,117,118,59,61,61,61,62,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,60,61,61,58,119,0,0,0,0,0,0,60,61,61,61,62,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,3,116,61,61,62,0,0,0,0,0,0,3,116,61,61,61,62,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,60,61,61,61,115,5,0,0,0,0,0,60,61,61,61,61,62,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,60,61,61,61,61,115,4,4,4,4,4,116,61,61,61,61,62,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,60,61,61,61,61,61,61,61,61,61,61,61,61,61,61,58,119,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,117,59,61,61,61,61,61,61,61,61,61,61,61,61,61,62,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,60,61,61,61,61,61,61,61,61,61,61,61,58,118,119,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,117,118,118,118,118,118,118,118,118,118,118,118,119,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,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,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,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,3,4,4,4,4,4,4,5,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,60,61,61,61,61,61,61,115,4,5,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,3,116,61,61,61,61,61,61,61,61,115,4,5,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,60,61,61,61,61,61,61,61,61,61,61,61,115,4,5,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,3,116,61,61,61,61,61,61,61,61,61,61,61,61,61,115,4,5,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,60,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,115,5,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,60,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,62,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,3,116,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,58,119,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,60,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,58,119,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,3,116,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,58,119,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,60,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,58,119,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,60,61,61,61,61,61,61,61,61,61,61,61,61,61,58,118,119,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,117,59,61,61,61,61,61,61,61,61,61,58,118,118,119,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,117,118,118,59,61,61,61,58,118,118,119,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,117,118,118,118,119,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,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,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,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,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,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,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,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,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,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,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,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,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,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
</data>
</layer>
<layer id="3" name="Paths" width="50" height="50">
<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,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,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,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,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,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,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,407,466,466,466,466,466,466,466,466,466,690,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,407,466,466,466,466,466,466,466,466,466,465,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,409,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,409,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,409,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,409,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,409,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,409,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,464,466,408,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,464,466,408,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,464,466,408,0,0,634,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,464,466,405,406,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,464,463,408,0,0,0,0,634,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,464,466,408,0,0,409,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,464,466,466,463,408,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,464,466,466,466,466,466,466,408,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,464,466,466,466,466,466,466,408,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,464,466,466,466,408,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,409,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,409,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,409,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,407,465,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,409,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,409,0,0,0,0,634,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,462,466,466,466,466,465,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,407,466,466,465,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,407,466,466,466,466,465,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,407,466,466,466,466,465,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,407,466,405,465,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,407,466,465,0,409,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,407,465,0,0,0,409,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,407,466,465,0,0,0,0,409,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,407,466,465,0,0,0,0,0,0,409,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,407,466,466,466,466,466,466,466,466,466,466,466,466,466,466,466,465,0,0,0,0,0,0,0,0,464,408,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,409,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,464,408,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,409,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,464,408,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,409,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,464,466,408,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,409,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,464,466,408,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,409,0,0,634,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,464,466,466,466,466,466,466,690,0,0,0,0,0,0,0,
0,0,0,464,466,466,465,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,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,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,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,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
</data>
</layer>
<layer id="5" name="HouseWalls" width="50" height="50">
<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,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,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,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,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,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,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,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,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,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,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,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,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,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,873,874,875,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,873,874,875,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,870,869,872,0,0,0,873,874,875,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,873,874,875,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,870,869,872,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,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,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,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,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,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,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,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,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,873,874,875,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,873,874,875,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,870,869,872,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,873,874,875,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,873,874,875,0,0,873,874,875,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,873,874,875,0,0,870,869,872,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,870,869,872,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,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,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,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,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,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,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,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,873,874,875,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,873,874,875,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,873,874,875,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,873,874,875,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,870,869,872,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,870,869,872,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,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,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,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,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,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,0,0,0,0,0,0,0,0,0
</data>
</layer>
<layer id="8" name="HouseDoors" width="50" height="50">
<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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,41,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,33,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,0,0,0,0,0,46,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,33,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,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,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,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,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,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,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,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,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,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,43,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,33,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,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,43,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,41,0,0,0,0,33,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,33,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,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,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,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,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,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,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,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,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,41,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,43,0,43,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,33,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,33,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,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,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,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,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,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,0,0,0,0,0,0,0,0,0,0
</data>
</layer>
<layer id="7" name="FencesBushes" width="50" height="50">
<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,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,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,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,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,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,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,1360,1365,1365,1365,1365,1365,1365,1361,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,0,0,0,0,0,0,0,0,0,0,0,1360,1365,1365,1365,1365,1365,1365,1361,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,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,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,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,0,0,0,0,1362,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,1362,0,1363,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,1362,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,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,0,0,1360,1365,1361,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,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,1360,1361,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,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,1363,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,1360,1361,0,0,0,0,1362,0,1363,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,1362,0,1363,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,1360,1361,0,0,0,1362,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,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,1360,1365,1365,1365,1365,1365,1365,1361,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,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,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,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,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,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,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,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,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,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
</data>
</layer>
<layer id="6" name="HouseRoofs" width="50" height="50">
<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,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,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,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,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,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,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,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,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,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,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,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,1218,1223,1219,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,1275,1280,1276,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,1332,1277,1333,0,0,0,1218,1223,1219,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,1275,1280,1276,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,1332,1277,1333,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,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,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,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,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,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,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,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,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1218,1223,1219,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,1275,1280,1276,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,1332,1277,1333,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,1218,1223,1219,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,1218,1223,1219,0,0,1275,1280,1276,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,1275,1280,1276,0,0,1332,1277,1333,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,1332,1277,1333,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,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,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,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,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,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,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,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,1218,1223,1219,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,1218,1223,1219,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,1275,1280,1276,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,1275,1280,1276,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,1332,1277,1333,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,1332,1277,1333,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,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,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,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,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,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,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,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,0,0,0,0,0,0,0,0,0
</data>
</layer>
</group>
<objectgroup id="10" name="Collisions">
<object id="1" x="80" y="656" width="48" height="48"/>
<object id="2" x="496" y="480" width="48" height="48"/>
<object id="3" x="576" y="464" width="48" height="48"/>
<object id="4" x="608" y="656" width="48" height="48"/>
<object id="5" x="736" y="416" width="48" height="48"/>
<object id="6" x="368" y="240" width="48" height="48"/>
<object id="7" x="272" y="208" width="48" height="48"/>
<object id="10" x="144" y="640" width="128" height="16"/>
<object id="11" x="352" y="608" width="32" height="16"/>
<object id="12" x="336" y="576" width="32" height="16"/>
<object id="13" x="432" y="528" width="32" height="16"/>
<object id="14" x="444.826" y="576" width="3.17391" height="48"/>
<object id="15" x="464" y="560" width="3.17391" height="48"/>
<object id="16" x="668.875" y="432" width="3.125" height="48"/>
<object id="17" x="688" y="448" width="3.25" height="16"/>
<object id="19" x="704" y="496" width="48" height="16"/>
<object id="20" x="464" y="368" width="128" height="16"/>
<object id="21" x="160" y="96" width="128" height="16"/>
<object id="24" x="80" y="496" width="240" height="64"/>
<object id="25" x="96" y="560" width="176" height="16"/>
<object id="26" x="144" y="576" width="80" height="16"/>
<object id="28" x="144" y="352" width="128" height="144"/>
<object id="29" x="128" y="384" width="16" height="112"/>
<object id="30" x="112" y="416" width="16" height="80"/>
<object id="31" x="96" y="464" width="16" height="32"/>
<object id="32" x="272" y="368" width="32" height="128"/>
<object id="33" x="304" y="384" width="32" height="112"/>
<object id="35" x="336" y="400" width="32" height="128"/>
<object id="36" x="368" y="416" width="16" height="96"/>
<object id="37" x="384" y="416" width="16" height="80"/>
<object id="38" x="400" y="432" width="16" height="48"/>
<object id="39" x="320" y="496" width="16" height="48"/>
<object id="40" x="336" y="528" width="16" height="16"/>
<object id="41" x="464" y="224" width="208" height="80"/>
<object id="42" x="544" y="96" width="128" height="128"/>
<object id="43" x="448" y="192" width="16" height="80"/>
<object id="44" x="464" y="144" width="80" height="80"/>
<object id="45" x="496" y="112" width="48" height="32"/>
<object id="46" x="480" y="128" width="16" height="16"/>
<object id="47" x="608" y="80" width="64" height="16"/>
<object id="48" x="672" y="96" width="16" height="192"/>
<object id="49" x="688" y="112" width="16" height="176"/>
<object id="50" x="704" y="144" width="16" height="112"/>
</objectgroup>
<objectgroup id="12" name="PointsOfInterest">
<object id="8" name="PlayerSpawn" x="425" y="343.5">
<point/>
</object>
</objectgroup>
</map>

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 KiB

View file

@ -35,8 +35,7 @@ public static partial class DotTiledAssert
AssertEqual(expected.X, actual.X, nameof(TileLayer.X));
AssertEqual(expected.Y, actual.Y, nameof(TileLayer.Y));
Assert.NotNull(actual.Data);
AssertData(expected.Data, actual.Data);
AssertOptionalsEqual(expected.Data, actual.Data, nameof(TileLayer.Data), AssertData);
}
private static void AssertLayer(ObjectLayer expected, ObjectLayer actual)
@ -60,8 +59,7 @@ public static partial class DotTiledAssert
AssertEqual(expected.X, actual.X, nameof(ImageLayer.X));
AssertEqual(expected.Y, actual.Y, nameof(ImageLayer.Y));
Assert.NotNull(actual.Image);
AssertImage(expected.Image, actual.Image);
AssertOptionalsEqual(expected.Image, actual.Image, nameof(ImageLayer.Image), AssertImage);
}
private static void AssertLayer(Group expected, Group actual)

View file

@ -33,12 +33,6 @@ public static partial class DotTiledAssert
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");
@ -51,12 +45,6 @@ public static partial class DotTiledAssert
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");

View file

@ -48,7 +48,7 @@ public class FromTypeUsedInLoaderTests
ParallaxOriginY = 0,
RenderOrder = RenderOrder.RightDown,
CompressionLevel = -1,
BackgroundColor = new Color { R = 0, G = 0, B = 0, A = 0 },
BackgroundColor = new TiledColor { R = 0, G = 0, B = 0, A = 0 },
Version = "1.10",
TiledVersion = "1.11.0",
NextLayerID = 2,
@ -133,7 +133,7 @@ public class FromTypeUsedInLoaderTests
ParallaxOriginY = 0,
RenderOrder = RenderOrder.RightDown,
CompressionLevel = -1,
BackgroundColor = new Color { R = 0, G = 0, B = 0, A = 0 },
BackgroundColor = new TiledColor { R = 0, G = 0, B = 0, A = 0 },
Version = "1.10",
TiledVersion = "1.11.0",
NextLayerID = 2,
@ -226,7 +226,7 @@ public class FromTypeUsedInLoaderTests
ParallaxOriginY = 0,
RenderOrder = RenderOrder.RightDown,
CompressionLevel = -1,
BackgroundColor = new Color { R = 0, G = 0, B = 0, A = 0 },
BackgroundColor = new TiledColor { R = 0, G = 0, B = 0, A = 0 },
Version = "1.10",
TiledVersion = "1.11.0",
NextLayerID = 2,

View file

@ -15,7 +15,7 @@ public partial class TestData
ParallaxOriginY = 0,
RenderOrder = RenderOrder.RightDown,
CompressionLevel = -1,
BackgroundColor = new Color { R = 0, G = 0, B = 0, A = 0 },
BackgroundColor = new TiledColor { R = 0, G = 0, B = 0, A = 0 },
Version = "1.10",
TiledVersion = "1.11.0",
NextLayerID = 2,

View file

@ -0,0 +1,131 @@
namespace DotTiled.Tests;
public partial class TestData
{
public static Map MapDuplicateObjectIdBug(string ext) => new Map
{
Class = "",
Orientation = MapOrientation.Orthogonal,
Width = 64,
Height = 64,
TileWidth = 16,
TileHeight = 16,
Infinite = true,
ParallaxOriginX = 0,
ParallaxOriginY = 0,
RenderOrder = RenderOrder.RightDown,
CompressionLevel = -1,
BackgroundColor = new TiledColor { R = 0, G = 0, B = 0, A = 0 },
Version = "1.10",
TiledVersion = "1.11.2",
NextLayerID = 2,
NextObjectID = 3,
Tilesets = [
new Tileset
{
FirstGID = 1,
Source = ext == "tmx" ? "tiles.tsx" : "tiles.tsj",
Version = "1.10",
TiledVersion = "1.11.2",
Name = "Tiles",
TileWidth = 16,
TileHeight = 16,
TileCount = 4,
Columns = 2,
Grid = new Grid
{
Orientation = GridOrientation.Orthogonal,
Width = 32,
Height = 32
},
Image = new Image
{
Source = "tiles.png",
Width = 32,
Height = 32,
Format = ImageFormat.Png
}
}
],
Layers = [
new TileLayer
{
ID = 1,
Name = "Tile Layer 1",
Width = ext == "tmx" ? 64 : 16,
Height = ext == "tmx" ? 64 : 16,
Data = new Data
{
Encoding = DataEncoding.Csv,
Chunks = new Optional<Chunk[]>([
new Chunk
{
X = 0,
Y = 0,
Width = 16,
Height = 16,
GlobalTileIDs = [
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
],
FlippingFlags = GetAllNoneFlippingFlags(16 * 16)
}
])
}
},
new ObjectLayer
{
ID = 3,
Name = "Object Layer 1",
Objects = [
new TileObject
{
ID = 1,
Template = ext == "tmx" ? "template.tx" : "template.tj",
X = 80,
Y = 144,
GID = 4,
Width = 16,
Height = 16,
},
new TileObject
{
ID = 2,
Template = ext == "tmx" ? "template.tx" : "template.tj",
X = 48,
Y = 144,
GID = 4,
Width = 16,
Height = 16,
}
]
}
]
};
private static FlippingFlags[] GetAllNoneFlippingFlags(int count)
{
var flippingFlags = new FlippingFlags[count];
for (int i = 0; i < count; i++)
{
flippingFlags[i] = FlippingFlags.None;
}
return flippingFlags;
}
}

View file

@ -0,0 +1,79 @@
{ "compressionlevel":-1,
"height":64,
"infinite":true,
"layers":[
{
"chunks":[
{
"data":[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
"height":16,
"width":16,
"x":0,
"y":0
}],
"height":16,
"id":1,
"name":"Tile Layer 1",
"opacity":1,
"startx":0,
"starty":0,
"type":"tilelayer",
"visible":true,
"width":16,
"x":0,
"y":0
},
{
"draworder":"topdown",
"id":3,
"name":"Object Layer 1",
"objects":[
{
"id":1,
"template":"template.tj",
"x":80,
"y":144
},
{
"id":2,
"template":"template.tj",
"x":48,
"y":144
}],
"opacity":1,
"type":"objectgroup",
"visible":true,
"x":0,
"y":0
}],
"nextlayerid":2,
"nextobjectid":3,
"orientation":"orthogonal",
"renderorder":"right-down",
"tiledversion":"1.11.2",
"tileheight":16,
"tilesets":[
{
"firstgid":1,
"source":"tiles.tsj"
}],
"tilewidth":16,
"type":"map",
"version":"1.10",
"width":64
}

View file

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.11.2" orientation="orthogonal" renderorder="right-down" width="64" height="64" tilewidth="16" tileheight="16" infinite="1" nextlayerid="2" nextobjectid="3">
<tileset firstgid="1" source="tiles.tsx"/>
<layer id="1" name="Tile Layer 1" width="64" height="64">
<data encoding="csv">
<chunk x="0" y="0" width="16" height="16">
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
</chunk>
</data>
</layer>
<objectgroup id="3" name="Object Layer 1">
<object id="1" template="template.tx" x="80" y="144"/>
<object id="2" template="template.tx" x="48" y="144"/>
</objectgroup>
</map>

View file

@ -0,0 +1,18 @@
{ "object":
{
"gid":4,
"height":16,
"id":2,
"name":"",
"rotation":0,
"type":"",
"visible":true,
"width":16
},
"tileset":
{
"firstgid":1,
"source":"tiles.tsj"
},
"type":"template"
}

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<template>
<tileset firstgid="1" source="tiles.tsx"/>
<object gid="4" width="16" height="16">
</object>
</template>

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 B

View file

@ -0,0 +1,20 @@
{ "columns":2,
"grid":
{
"height":32,
"orientation":"orthogonal",
"width":32
},
"image":"tiles.png",
"imageheight":32,
"imagewidth":32,
"margin":0,
"name":"Tiles",
"spacing":0,
"tilecount":4,
"tiledversion":"1.11.2",
"tileheight":16,
"tilewidth":16,
"type":"tileset",
"version":"1.10"
}

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<tileset version="1.10" tiledversion="1.11.2" name="Tiles" tilewidth="16" tileheight="16" tilecount="4" columns="2">
<grid orientation="orthogonal" width="32" height="32"/>
<image source="tiles.png" width="32" height="32"/>
</tileset>

View file

@ -17,7 +17,7 @@ public partial class TestData
ParallaxOriginY = 0,
RenderOrder = RenderOrder.RightDown,
CompressionLevel = -1,
BackgroundColor = Color.Parse("#00000000", CultureInfo.InvariantCulture),
BackgroundColor = TiledColor.Parse("#00000000", CultureInfo.InvariantCulture),
Version = "1.10",
TiledVersion = "1.11.0",
NextLayerID = 2,
@ -47,7 +47,7 @@ public partial class TestData
},
Properties = [
new BoolProperty { Name = "tilesetbool", Value = true },
new ColorProperty { Name = "tilesetcolor", Value = Color.Parse("#ffff0000", CultureInfo.InvariantCulture) },
new ColorProperty { Name = "tilesetcolor", Value = TiledColor.Parse("#ffff0000", CultureInfo.InvariantCulture) },
new FileProperty { Name = "tilesetfile", Value = "" },
new FloatProperty { Name = "tilesetfloat", Value = 5.2f },
new IntProperty { Name = "tilesetint", Value = 9 },

View file

@ -17,7 +17,7 @@ public partial class TestData
ParallaxOriginY = 0,
RenderOrder = RenderOrder.RightDown,
CompressionLevel = -1,
BackgroundColor = Color.Parse("#00000000", CultureInfo.InvariantCulture),
BackgroundColor = TiledColor.Parse("#00000000", CultureInfo.InvariantCulture),
Version = "1.10",
TiledVersion = "1.11.0",
NextLayerID = 2,
@ -63,21 +63,21 @@ public partial class TestData
new WangColor
{
Name = "Water",
Color = Color.Parse("#ff0000", CultureInfo.InvariantCulture),
Color = TiledColor.Parse("#ff0000", CultureInfo.InvariantCulture),
Tile = 0,
Probability = 1
},
new WangColor
{
Name = "Grass",
Color = Color.Parse("#00ff00", CultureInfo.InvariantCulture),
Color = TiledColor.Parse("#00ff00", CultureInfo.InvariantCulture),
Tile = -1,
Probability = 1
},
new WangColor
{
Name = "Stone",
Color = Color.Parse("#0000ff", CultureInfo.InvariantCulture),
Color = TiledColor.Parse("#0000ff", CultureInfo.InvariantCulture),
Tile = 29,
Probability = 1
}

View file

@ -17,7 +17,7 @@ public partial class TestData
ParallaxOriginY = 0,
RenderOrder = RenderOrder.RightDown,
CompressionLevel = -1,
BackgroundColor = new Color { R = 0, G = 0, B = 0, A = 0 },
BackgroundColor = new TiledColor { R = 0, G = 0, B = 0, A = 0 },
Version = "1.10",
TiledVersion = "1.11.0",
NextLayerID = 8,
@ -181,8 +181,8 @@ public partial class TestData
{
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
Width = fileExt == "tmx" ? 256 : 0, // Currently, json format does not
Height = fileExt == "tmx" ? 96 : 0 // include image dimensions in image layer https://github.com/mapeditor/tiled/issues/4028
},
RepeatX = true
},

View file

@ -15,7 +15,7 @@ public partial class TestData
ParallaxOriginY = 0,
RenderOrder = RenderOrder.RightDown,
CompressionLevel = -1,
BackgroundColor = new Color { R = 0, G = 0, B = 0, A = 0 },
BackgroundColor = new TiledColor { R = 0, G = 0, B = 0, A = 0 },
Version = "1.10",
TiledVersion = "1.11.0",
NextLayerID = 2,

View file

@ -15,7 +15,7 @@ public partial class TestData
ParallaxOriginY = 0,
RenderOrder = RenderOrder.RightDown,
CompressionLevel = -1,
BackgroundColor = new Color { R = 0, G = 0, B = 0, A = 0 },
BackgroundColor = new TiledColor { R = 0, G = 0, B = 0, A = 0 },
Version = "1.10",
TiledVersion = "1.11.0",
NextLayerID = 2,

View file

@ -17,7 +17,7 @@ public partial class TestData
ParallaxOriginY = 0,
RenderOrder = RenderOrder.RightDown,
CompressionLevel = -1,
BackgroundColor = Color.Parse("#00ff00", CultureInfo.InvariantCulture),
BackgroundColor = TiledColor.Parse("#00ff00", CultureInfo.InvariantCulture),
Version = "1.10",
TiledVersion = "1.11.0",
NextLayerID = 2,
@ -52,13 +52,13 @@ public partial class TestData
Properties =
[
new BoolProperty { Name = "boolprop", Value = true },
new ColorProperty { Name = "colorprop", Value = Color.Parse("#ff55ffff", CultureInfo.InvariantCulture) },
new ColorProperty { Name = "colorprop", Value = TiledColor.Parse("#ff55ffff", CultureInfo.InvariantCulture) },
new FileProperty { Name = "fileprop", Value = "file.txt" },
new FloatProperty { Name = "floatprop", Value = 4.2f },
new IntProperty { Name = "intprop", Value = 8 },
new ObjectProperty { Name = "objectprop", Value = 5 },
new StringProperty { Name = "stringprop", Value = "This is a string, hello world!" },
new ColorProperty { Name = "unsetcolorprop", Value = Optional<Color>.Empty }
new ColorProperty { Name = "unsetcolorprop", Value = Optional.Empty }
]
};
}

View file

@ -17,7 +17,7 @@ public partial class TestData
ParallaxOriginY = 0,
RenderOrder = RenderOrder.RightDown,
CompressionLevel = -1,
BackgroundColor = Color.Parse("#00000000", CultureInfo.InvariantCulture),
BackgroundColor = TiledColor.Parse("#00000000", CultureInfo.InvariantCulture),
Version = "1.10",
TiledVersion = "1.11.0",
NextLayerID = 2,

View file

@ -17,7 +17,7 @@ public partial class TestData
ParallaxOriginY = 0,
RenderOrder = RenderOrder.RightDown,
CompressionLevel = -1,
BackgroundColor = Color.Parse("#00000000", CultureInfo.InvariantCulture),
BackgroundColor = TiledColor.Parse("#00000000", CultureInfo.InvariantCulture),
Version = "1.10",
TiledVersion = "1.11.0",
NextLayerID = 2,
@ -56,7 +56,7 @@ public partial class TestData
PropertyType = "CustomClass",
Value = [
new BoolProperty { Name = "boolinclass", Value = true },
new ColorProperty { Name = "colorinclass", Value = Color.Parse("#000000ff", CultureInfo.InvariantCulture) },
new ColorProperty { Name = "colorinclass", Value = TiledColor.Parse("#000000ff", CultureInfo.InvariantCulture) },
new FileProperty { Name = "fileinclass", Value = "" },
new FloatProperty { Name = "floatinclass", Value = 13.37f },
new IntProperty { Name = "intinclass", Value = 0 },
@ -106,7 +106,7 @@ public partial class TestData
new ColorProperty
{
Name = "colorinclass",
Value = Color.Parse("#000000ff", CultureInfo.InvariantCulture)
Value = TiledColor.Parse("#000000ff", CultureInfo.InvariantCulture)
},
new FileProperty
{

View file

@ -17,7 +17,7 @@ public partial class TestData
ParallaxOriginY = 0,
RenderOrder = RenderOrder.RightDown,
CompressionLevel = -1,
BackgroundColor = Color.Parse("#00000000", CultureInfo.InvariantCulture),
BackgroundColor = TiledColor.Parse("#00000000", CultureInfo.InvariantCulture),
Version = "1.10",
TiledVersion = "1.11.0",
NextLayerID = 2,
@ -61,7 +61,7 @@ public partial class TestData
PropertyType = "CustomClass",
Value = [
new BoolProperty { Name = "boolinclass", Value = false },
new ColorProperty { Name = "colorinclass", Value = Color.Parse("#000000ff", CultureInfo.InvariantCulture) },
new ColorProperty { Name = "colorinclass", Value = TiledColor.Parse("#000000ff", CultureInfo.InvariantCulture) },
new FileProperty { Name = "fileinclass", Value = "" },
new FloatProperty { Name = "floatinclass", Value = 0f },
new IntProperty { Name = "intinclass", Value = 0 },
@ -82,7 +82,7 @@ public partial class TestData
PropertyType = "CustomClass",
Value = [
new BoolProperty { Name = "boolinclass", Value = true },
new ColorProperty { Name = "colorinclass", Value = Color.Parse("#000000ff", CultureInfo.InvariantCulture) },
new ColorProperty { Name = "colorinclass", Value = TiledColor.Parse("#000000ff", CultureInfo.InvariantCulture) },
new FileProperty { Name = "fileinclass", Value = "" },
new FloatProperty { Name = "floatinclass", Value = 13.37f },
new IntProperty { Name = "intinclass", Value = 0 },
@ -109,7 +109,7 @@ public partial class TestData
new ColorProperty
{
Name = "colorinclass",
Value = Color.Parse("#000000ff", CultureInfo.InvariantCulture)
Value = TiledColor.Parse("#000000ff", CultureInfo.InvariantCulture)
},
new FileProperty
{

View file

@ -17,7 +17,7 @@ public partial class TestData
ParallaxOriginY = 0,
RenderOrder = RenderOrder.RightDown,
CompressionLevel = -1,
BackgroundColor = Color.Parse("#00000000", CultureInfo.InvariantCulture),
BackgroundColor = TiledColor.Parse("#00000000", CultureInfo.InvariantCulture),
Version = "1.10",
TiledVersion = "1.11.0",
NextLayerID = 2,

View file

@ -17,7 +17,7 @@ public partial class TestData
ParallaxOriginY = 0,
RenderOrder = RenderOrder.RightDown,
CompressionLevel = -1,
BackgroundColor = Color.Parse("#00000000", CultureInfo.InvariantCulture),
BackgroundColor = TiledColor.Parse("#00000000", CultureInfo.InvariantCulture),
Version = "1.10",
TiledVersion = "1.11.0",
NextLayerID = 2,

View file

@ -17,7 +17,7 @@ public partial class TestData
ParallaxOriginY = 0,
RenderOrder = RenderOrder.RightDown,
CompressionLevel = -1,
BackgroundColor = Color.Parse("#00000000", CultureInfo.InvariantCulture),
BackgroundColor = TiledColor.Parse("#00000000", CultureInfo.InvariantCulture),
Version = "1.10",
TiledVersion = "1.11.0",
NextLayerID = 3,

View file

@ -17,11 +17,11 @@ public partial class TestData
ParallaxOriginY = 0,
RenderOrder = RenderOrder.RightDown,
CompressionLevel = -1,
BackgroundColor = new Color { R = 0, G = 0, B = 0, A = 0 },
BackgroundColor = new TiledColor { R = 0, G = 0, B = 0, A = 0 },
Version = "1.10",
TiledVersion = "1.11.0",
TiledVersion = "1.11.2",
NextLayerID = 8,
NextObjectID = 7,
NextObjectID = 8,
Tilesets = [
new Tileset
{
@ -104,6 +104,25 @@ public partial class TestData
Y = 110.333f,
Width = 64,
Height = 146
},
new TextObject
{
ID = 7,
Name = "Text1",
Rotation = 0,
Text = "Hello World!",
Visible = true,
Width = 116.869f,
Height = 19f,
X = 52.5197f,
Y = 4.0107f,
PixelSize = 18,
Wrap = true,
Bold = true,
Italic = true,
Underline = true,
Strikeout = true,
Kerning = false
}
]
},
@ -172,8 +191,8 @@ public partial class TestData
{
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
Width = 256,
Height = 96
},
RepeatX = true
},

View file

@ -62,6 +62,29 @@
"width":64,
"x":-35,
"y":110.333
},
{
"height":19,
"id":7,
"name":"Text1",
"rotation":0,
"text":
{
"bold":true,
"italic":true,
"kerning":false,
"pixelsize":18,
"strikeout":true,
"text":"Hello World!",
"underline":true,
"wrap":true
},
"type":"",
"visible":true,
"width":116.869277732794,
"x":52.5197,
"y":4.0107
}],
"opacity":1,
"type":"objectgroup",
@ -114,6 +137,8 @@
{
"id":4,
"image":"tileset.png",
"imageheight":96,
"imagewidth":256,
"name":"ImageLayer",
"opacity":1,
"repeatx":true,
@ -146,10 +171,10 @@
"y":0
}],
"nextlayerid":8,
"nextobjectid":7,
"nextobjectid":8,
"orientation":"orthogonal",
"renderorder":"right-down",
"tiledversion":"1.11.0",
"tiledversion":"1.11.2",
"tileheight":32,
"tilesets":[
{

View file

@ -1,5 +1,5 @@
<?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">
<map version="1.10" tiledversion="1.11.2" 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">
@ -12,6 +12,9 @@
</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" name="Text1" x="52.5197" y="4.0107" width="116.869" height="19">
<text pixelsize="18" wrap="1" bold="1" italic="1" underline="1" strikeout="1" kerning="0">Hello World!</text>
</object>
</objectgroup>
<group id="5" name="Sub">
<layer id="7" name="Tile 3" width="5" height="5">

View file

@ -17,7 +17,7 @@ public partial class TestData
ParallaxOriginY = 0,
RenderOrder = RenderOrder.RightDown,
CompressionLevel = -1,
BackgroundColor = Color.Parse("#00ff00", CultureInfo.InvariantCulture),
BackgroundColor = TiledColor.Parse("#00ff00", CultureInfo.InvariantCulture),
Version = "1.10",
TiledVersion = "1.11.0",
NextLayerID = 2,
@ -52,7 +52,7 @@ public partial class TestData
Properties =
[
new BoolProperty { Name = "boolprop", Value = true },
new ColorProperty { Name = "colorprop", Value = Color.Parse("#ff55ffff", CultureInfo.InvariantCulture) },
new ColorProperty { Name = "colorprop", Value = TiledColor.Parse("#ff55ffff", CultureInfo.InvariantCulture) },
new FileProperty { Name = "fileprop", Value = "file.txt" },
new FloatProperty { Name = "floatprop", Value = 4.2f },
new IntProperty { Name = "intprop", Value = 8 },

View file

@ -0,0 +1,132 @@
namespace DotTiled.Tests.UnitTests;
public class MapTests
{
[Fact]
public void ResolveTilesetForGlobalTileID_NoTilesets_ThrowsException()
{
// Arrange
var map = new Map
{
Version = "version",
Orientation = MapOrientation.Orthogonal,
Width = 10,
Height = 10,
TileWidth = 16,
TileHeight = 16,
NextLayerID = 1,
NextObjectID = 1
};
// Act & Assert
Assert.Throws<ArgumentException>(() => map.ResolveTilesetForGlobalTileID(1, out var _));
}
[Fact]
public void ResolveTilesetForGlobalTileID_GlobalTileIDOutOfRange_ThrowsException()
{
// Arrange
var map = new Map
{
Version = "version",
Orientation = MapOrientation.Orthogonal,
Width = 10,
Height = 10,
TileWidth = 16,
TileHeight = 16,
NextLayerID = 1,
NextObjectID = 1,
Tilesets = [
new Tileset
{
FirstGID = 1,
Name = "Tileset1",
TileWidth = 16,
TileHeight = 16,
TileCount = 5,
Columns = 5
}
]
};
// Act & Assert
Assert.Throws<ArgumentException>(() => map.ResolveTilesetForGlobalTileID(6, out var _));
}
[Fact]
public void ResolveTilesetForGlobalTileID_GlobalTileIDInRangeOfOnlyTileset_ReturnsTileset()
{
// Arrange
var tileset = new Tileset
{
FirstGID = 1,
Name = "Tileset1",
TileWidth = 16,
TileHeight = 16,
TileCount = 5,
Columns = 5
};
var map = new Map
{
Version = "version",
Orientation = MapOrientation.Orthogonal,
Width = 10,
Height = 10,
TileWidth = 16,
TileHeight = 16,
NextLayerID = 1,
NextObjectID = 1,
Tilesets = [tileset]
};
// Act
var result = map.ResolveTilesetForGlobalTileID(3, out var localTileID);
// Assert
Assert.Equal(tileset, result);
Assert.Equal(2, (int)localTileID); // 3 - 1 = 2 (local tile ID)
}
[Fact]
public void ResolveTilesetForGlobalTileID_GlobalTileIDInRangeOfMultipleTilesets_ReturnsCorrectTileset()
{
// Arrange
var tileset1 = new Tileset
{
FirstGID = 1,
Name = "Tileset1",
TileWidth = 16,
TileHeight = 16,
TileCount = 5,
Columns = 5
};
var tileset2 = new Tileset
{
FirstGID = 6,
Name = "Tileset2",
TileWidth = 16,
TileHeight = 16,
TileCount = 5,
Columns = 5
};
var map = new Map
{
Version = "version",
Orientation = MapOrientation.Orthogonal,
Width = 10,
Height = 10,
TileWidth = 16,
TileHeight = 16,
NextLayerID = 1,
NextObjectID = 1,
Tilesets = [tileset1, tileset2]
};
// Act
var result = map.ResolveTilesetForGlobalTileID(8, out var localTileID);
// Assert
Assert.Equal(tileset2, result);
Assert.Equal(2, (int)localTileID); // 8 - 6 = 2 (local tile ID)
}
}

View file

@ -59,30 +59,6 @@ public class OptionalTests
Assert.Equal(expectedValue, optional.Value);
}
[Fact]
public void ImplicitConversion_FromOptionalToValue_ShouldReturnValue_WhenHasValueIsTrue()
{
// Arrange
int expectedValue = 10;
var optional = new Optional<int>(expectedValue);
// Act
int value = optional;
// Assert
Assert.Equal(expectedValue, value);
}
[Fact]
public void ImplicitConversion_FromOptionalToValue_ShouldThrowException_WhenHasValueIsFalse()
{
// Arrange
var optional = new Optional<int>();
// Act & Assert
_ = Assert.Throws<InvalidOperationException>(() => { int value = optional; });
}
// ToString Method Tests
[Fact]
@ -237,18 +213,6 @@ public class OptionalTests
_ = Assert.Throws<InvalidOperationException>(() => optional.Value);
}
[Fact]
public void ImplicitConversion_WhenHasValueIsFalse_ShouldThrowInvalidOperationException()
{
// Arrange
var optional = new Optional<int>();
// Act & Assert
_ = Assert.Throws<InvalidOperationException>(() => { int value = optional; });
}
// Edge Cases
[Fact]
public void EmptyOptionalEquality_ShouldReturnTrue()
{

View file

@ -80,7 +80,7 @@ public class HasPropertiesBaseTests
private sealed class MapTo
{
public bool MapToBool { get; set; } = false;
public Color MapToColor { get; set; } = Color.Parse("#00000000", CultureInfo.InvariantCulture);
public TiledColor MapToColor { get; set; } = TiledColor.Parse("#00000000", CultureInfo.InvariantCulture);
public float MapToFloat { get; set; } = 0.0f;
public string MapToFile { get; set; } = "";
public int MapToInt { get; set; } = 0;
@ -130,7 +130,7 @@ public class HasPropertiesBaseTests
PropertyType = "MapTo",
Value = [
new BoolProperty { Name = "MapToBool", Value = true },
new ColorProperty { Name = "MapToColor", Value = Color.Parse("#FF0000FF", CultureInfo.InvariantCulture) },
new ColorProperty { Name = "MapToColor", Value = TiledColor.Parse("#FF0000FF", CultureInfo.InvariantCulture) },
new FloatProperty { Name = "MapToFloat", Value = 1.0f },
new StringProperty { Name = "MapToFile", Value = "Test" },
new IntProperty { Name = "MapToInt", Value = 1 },
@ -146,7 +146,7 @@ public class HasPropertiesBaseTests
// Assert
Assert.True(mappedProperty.MapToBool);
Assert.Equal(Color.Parse("#FF0000FF", CultureInfo.InvariantCulture), mappedProperty.MapToColor);
Assert.Equal(TiledColor.Parse("#FF0000FF", CultureInfo.InvariantCulture), mappedProperty.MapToColor);
Assert.Equal(1.0f, mappedProperty.MapToFloat);
Assert.Equal("Test", mappedProperty.MapToFile);
Assert.Equal(1, mappedProperty.MapToInt);
@ -175,7 +175,7 @@ public class HasPropertiesBaseTests
PropertyType = "MapTo",
Value = [
new BoolProperty { Name = "MapToBool", Value = true },
new ColorProperty { Name = "MapToColor", Value = Color.Parse("#FF0000FF", CultureInfo.InvariantCulture) },
new ColorProperty { Name = "MapToColor", Value = TiledColor.Parse("#FF0000FF", CultureInfo.InvariantCulture) },
new FloatProperty { Name = "MapToFloat", Value = 1.0f },
new StringProperty { Name = "MapToFile", Value = "Test" },
new IntProperty { Name = "MapToInt", Value = 1 },
@ -194,7 +194,7 @@ public class HasPropertiesBaseTests
// Assert
Assert.Equal("Test", mappedProperty.NestedMapToString);
Assert.True(mappedProperty.MapToInNested.MapToBool);
Assert.Equal(Color.Parse("#FF0000FF", CultureInfo.InvariantCulture), mappedProperty.MapToInNested.MapToColor);
Assert.Equal(TiledColor.Parse("#FF0000FF", CultureInfo.InvariantCulture), mappedProperty.MapToInNested.MapToColor);
Assert.Equal(1.0f, mappedProperty.MapToInNested.MapToFloat);
Assert.Equal("Test", mappedProperty.MapToInNested.MapToFile);
Assert.Equal(1, mappedProperty.MapToInNested.MapToInt);
@ -276,7 +276,7 @@ public class HasPropertiesBaseTests
// Arrange
List<IProperty> props = [
new BoolProperty { Name = "MapToBool", Value = true },
new ColorProperty { Name = "MapToColor", Value = Color.Parse("#FF0000FF", CultureInfo.InvariantCulture) },
new ColorProperty { Name = "MapToColor", Value = TiledColor.Parse("#FF0000FF", CultureInfo.InvariantCulture) },
new FloatProperty { Name = "MapToFloat", Value = 1.0f },
new StringProperty { Name = "MapToFile", Value = "Test" },
new IntProperty { Name = "MapToInt", Value = 1 },
@ -290,7 +290,7 @@ public class HasPropertiesBaseTests
// Assert
Assert.True(mappedProperty.MapToBool);
Assert.Equal(Color.Parse("#FF0000FF", CultureInfo.InvariantCulture), mappedProperty.MapToColor);
Assert.Equal(TiledColor.Parse("#FF0000FF", CultureInfo.InvariantCulture), mappedProperty.MapToColor);
Assert.Equal(1.0f, mappedProperty.MapToFloat);
Assert.Equal("Test", mappedProperty.MapToFile);
Assert.Equal(1, mappedProperty.MapToInt);

View file

@ -71,8 +71,8 @@ public class LoaderTests
""");
var resourceCache = Substitute.For<IResourceCache>();
resourceCache.GetTileset(Arg.Any<string>()).Returns(Optional<Tileset>.Empty);
resourceCache.GetTemplate(Arg.Any<string>()).Returns(Optional<Template>.Empty);
resourceCache.GetTileset(Arg.Any<string>()).Returns(Optional.Empty);
resourceCache.GetTemplate(Arg.Any<string>()).Returns(Optional.Empty);
var customTypeDefinitions = Enumerable.Empty<ICustomTypeDefinition>();
var loader = new Loader(resourceReader, resourceCache, customTypeDefinitions);
@ -134,8 +134,8 @@ public class LoaderTests
""");
var resourceCache = Substitute.For<IResourceCache>();
resourceCache.GetTileset(Arg.Any<string>()).Returns(Optional<Tileset>.Empty);
resourceCache.GetTemplate(Arg.Any<string>()).Returns(Optional<Template>.Empty);
resourceCache.GetTileset(Arg.Any<string>()).Returns(Optional.Empty);
resourceCache.GetTemplate(Arg.Any<string>()).Returns(Optional.Empty);
var customTypeDefinitions = Enumerable.Empty<ICustomTypeDefinition>();
var loader = new Loader(resourceReader, resourceCache, customTypeDefinitions);
@ -219,7 +219,7 @@ public class LoaderTests
""");
var resourceCache = Substitute.For<IResourceCache>();
resourceCache.GetTileset(Arg.Any<string>()).Returns(Optional<Tileset>.Empty);
resourceCache.GetTileset(Arg.Any<string>()).Returns(Optional.Empty);
resourceCache.GetTemplate("template.tx").Returns(new Optional<Template>(new Template
{
Object = new PolygonObject
@ -315,4 +315,39 @@ public class LoaderTests
// Assert
DotTiledAssert.AssertProperties(customClassDefinition.Members, result.Properties);
}
public static IEnumerable<object[]> Maps => TestData.MapTests;
[Theory]
[MemberData(nameof(Maps))]
public void LoadMap_ValidFilesExternalTilesetsAndTemplatesWithCache_ReturnsMapThatEqualsExpected(
string testDataFile,
Func<string, Map> expectedMap,
IReadOnlyCollection<ICustomTypeDefinition> customTypeDefinitions)
{
// Arrange
string[] fileFormats = [".tmx", ".tmj"];
foreach (var fileFormat in fileFormats)
{
var testDataFileWithFormat = testDataFile + fileFormat;
var resourceReader = Substitute.For<IResourceReader>();
resourceReader.Read(Arg.Any<string>()).Returns(callInfo =>
{
var filePath = callInfo.Arg<string>();
return TestData.GetRawStringFor(filePath);
});
var loader = Loader.DefaultWith(
resourceReader: resourceReader,
customTypeDefinitions: customTypeDefinitions);
// Act
var map = loader.LoadMap(testDataFileWithFormat);
// Assert
Assert.NotNull(map);
DotTiledAssert.AssertMap(expectedMap(fileFormat[1..]), map);
}
}
}

View file

@ -39,7 +39,7 @@ public partial class MapReaderTests
return new Optional<ICustomTypeDefinition>(ctd);
}
return Optional<ICustomTypeDefinition>.Empty;
return Optional.Empty;
}
using var mapReader = new MapReader(mapString, ResolveTileset, ResolveTemplate, ResolveCustomType);

View file

@ -34,6 +34,7 @@ public static partial class TestData
public static IEnumerable<object[]> MapTests =>
[
[GetMapPath("default-map"), (string f) => DefaultMap(), Array.Empty<ICustomTypeDefinition>()],
[GetMapPath("map-duplicate-object-id-bug"), (string f) => MapDuplicateObjectIdBug(f), Array.Empty<ICustomTypeDefinition>()],
[GetMapPath("map-with-common-props"), (string f) => MapWithCommonProps(), Array.Empty<ICustomTypeDefinition>()],
[GetMapPath("map-with-custom-type-props"), (string f) => MapWithCustomTypeProps(), MapWithCustomTypePropsCustomTypeDefinitions()],
[GetMapPath("map-with-custom-type-props-without-defs"), (string f) => MapWithCustomTypePropsWithoutDefs(), Array.Empty<ICustomTypeDefinition>()],

View file

@ -35,7 +35,7 @@ public partial class TmjMapReaderTests
return new Optional<ICustomTypeDefinition>(ctd);
}
return Optional<ICustomTypeDefinition>.Empty;
return Optional.Empty;
}
using var mapReader = new TmjMapReader(json, ResolveTileset, ResolveTemplate, ResolveCustomType);

View file

@ -35,7 +35,7 @@ public partial class TmxMapReaderTests
return new Optional<ICustomTypeDefinition>(ctd);
}
return Optional<ICustomTypeDefinition>.Empty;
return Optional.Empty;
}
using var mapReader = new TmxMapReader(reader, ResolveTileset, ResolveTemplate, ResolveCustomType);

View file

@ -0,0 +1,114 @@
namespace DotTiled.Tests.UnitTests;
public class TilesetTests
{
[Fact]
public void GetSourceRectangleForLocalTileID_TileIDOutOfRange_ThrowsException()
{
// Arrange
var tileset = new Tileset
{
FirstGID = 0,
Name = "Tileset1",
TileWidth = 16,
TileHeight = 16,
TileCount = 5,
Columns = 5
};
// Act & Assert
Assert.Throws<ArgumentException>(() => tileset.GetSourceRectangleForLocalTileID(6));
}
[Fact]
public void GetSourceRectangleForLocalTileID_ValidTileIDIsInTilesList_ReturnsCorrectRectangle()
{
// Arrange
var tileset = new Tileset
{
FirstGID = 0,
Name = "Tileset1",
TileWidth = 16,
TileHeight = 16,
TileCount = 2,
Columns = 2,
Tiles = [
new Tile
{
ID = 0,
X = 0,
Y = 0,
Width = 16,
Height = 16,
},
new Tile
{
ID = 1,
X = 16,
Y = 0,
Width = 16,
Height = 16,
}
]
};
// Act
var rectangle = tileset.GetSourceRectangleForLocalTileID(1);
// Assert
Assert.Equal(16, rectangle.X);
Assert.Equal(0, rectangle.Y);
Assert.Equal(16, rectangle.Width);
Assert.Equal(16, rectangle.Height);
}
[Fact]
public void GetSourceRectangleForLocalTileID_ValidTileIDIsNotInTilesListNoMarginNoSpacing_ReturnsCorrectRectangle()
{
// Arrange
var tileset = new Tileset
{
FirstGID = 0,
Name = "Tileset1",
TileWidth = 16,
TileHeight = 16,
TileCount = 5,
Columns = 5,
};
// Act
var rectangle = tileset.GetSourceRectangleForLocalTileID(3);
// Assert
Assert.Equal(48, rectangle.X);
Assert.Equal(0, rectangle.Y);
Assert.Equal(16, rectangle.Width);
Assert.Equal(16, rectangle.Height);
}
[Fact]
public void GetSourceRectangleForLocalTileID_ValidTileIDIsNotInTilesListWithMarginAndSpacing_ReturnsCorrectRectangle()
{
// Arrange
var tileset = new Tileset
{
FirstGID = 0,
Name = "Tileset1",
TileWidth = 16,
TileHeight = 16,
TileCount = 5,
Columns = 5,
Margin = 3,
Spacing = 1
};
// Act
var rectangle = tileset.GetSourceRectangleForLocalTileID(3);
// Assert
Assert.Equal(54, rectangle.X);
Assert.Equal(3, rectangle.Y);
Assert.Equal(16, rectangle.Width);
Assert.Equal(16, rectangle.Height);
}
}

View file

@ -15,6 +15,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotTiled.Example.Console",
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotTiled.Example.Godot", "DotTiled.Examples\DotTiled.Example.Godot\DotTiled.Example.Godot.csproj", "{7541A9B3-43A5-45A7-939E-6F542319D990}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DotTiled.Examples", "DotTiled.Examples", "{F3D6E648-AF8F-4EC9-A810-8C348DBB9924}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotTiled.Example.Raylib", "DotTiled.Examples\DotTiled.Example.Raylib\DotTiled.Example.Raylib.csproj", "{53585FB8-6E94-46F0-87E2-9692874E1714}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -44,9 +48,14 @@ Global
{7541A9B3-43A5-45A7-939E-6F542319D990}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7541A9B3-43A5-45A7-939E-6F542319D990}.Release|Any CPU.ActiveCfg = Debug|Any CPU
{7541A9B3-43A5-45A7-939E-6F542319D990}.Release|Any CPU.Build.0 = Debug|Any CPU
{53585FB8-6E94-46F0-87E2-9692874E1714}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{53585FB8-6E94-46F0-87E2-9692874E1714}.Debug|Any CPU.Build.0 = Debug|Any CPU
{53585FB8-6E94-46F0-87E2-9692874E1714}.Release|Any CPU.ActiveCfg = Release|Any CPU
{53585FB8-6E94-46F0-87E2-9692874E1714}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{F9892295-6C2C-4ABD-9D6F-2AC81D2C6E67} = {8C54542E-3C2C-486C-9BEF-4C510391AFDA}
{7541A9B3-43A5-45A7-939E-6F542319D990} = {8C54542E-3C2C-486C-9BEF-4C510391AFDA}
{53585FB8-6E94-46F0-87E2-9692874E1714} = {F3D6E648-AF8F-4EC9-A810-8C348DBB9924}
EndGlobalSection
EndGlobal

View file

@ -37,7 +37,7 @@ public abstract class BaseLayer : HasPropertiesBase
/// <summary>
/// A tint color that is multiplied with any tiles drawn by this layer.
/// </summary>
public Optional<Color> TintColor { get; set; } = Optional<Color>.Empty;
public Optional<TiledColor> TintColor { get; set; } = Optional.Empty;
/// <summary>
/// Horizontal offset for this layer in pixels.

View file

@ -90,12 +90,12 @@ public class Chunk
/// <summary>
/// The width of the chunk in tiles.
/// </summary>
public required uint Width { get; set; }
public required int Width { get; set; }
/// <summary>
/// The height of the chunk in tiles.
/// </summary>
public required uint Height { get; set; }
public required int Height { get; set; }
/// <summary>
/// The parsed chunk data, as a list of tile GIDs.
@ -118,27 +118,27 @@ public class Data
/// <summary>
/// The encoding used to encode the tile layer data.
/// </summary>
public Optional<DataEncoding> Encoding { get; set; } = Optional<DataEncoding>.Empty;
public Optional<DataEncoding> Encoding { get; set; } = Optional.Empty;
/// <summary>
/// The compression method used to compress the tile layer data.
/// </summary>
public Optional<DataCompression> Compression { get; set; } = Optional<DataCompression>.Empty;
public Optional<DataCompression> Compression { get; set; } = Optional.Empty;
/// <summary>
/// The parsed tile layer data, as a list of tile GIDs.
/// To get an actual tile ID, you map it to a local tile ID using the correct tileset. Please refer to
/// <see href="https://doc.mapeditor.org/en/stable/reference/global-tile-ids/#mapping-a-gid-to-a-local-tile-id">the documentation on how to do this</see>.
/// </summary>
public Optional<uint[]> GlobalTileIDs { get; set; } = Optional<uint[]>.Empty;
public Optional<uint[]> GlobalTileIDs { get; set; } = Optional.Empty;
/// <summary>
/// The parsed flipping flags for each tile in the layer. Appear in the same order as the tiles in the layer in <see cref="GlobalTileIDs"/>.
/// </summary>
public Optional<FlippingFlags[]> FlippingFlags { get; set; } = Optional<FlippingFlags[]>.Empty;
public Optional<FlippingFlags[]> FlippingFlags { get; set; } = Optional.Empty;
/// <summary>
/// If the map is infinite, it will instead contain a list of chunks.
/// </summary>
public Optional<Chunk[]> Chunks { get; set; } = Optional<Chunk[]>.Empty;
public Optional<Chunk[]> Chunks { get; set; } = Optional.Empty;
}

View file

@ -8,12 +8,12 @@ public class ImageLayer : BaseLayer
/// <summary>
/// The X position of the image layer in pixels.
/// </summary>
public uint X { get; set; } = 0;
public int X { get; set; } = 0;
/// <summary>
/// The Y position of the image layer in pixels.
/// </summary>
public Optional<uint> Y { get; set; } = 0;
public int Y { get; set; } = 0;
/// <summary>
/// Whether the image drawn by this layer is repeated along the X axis.

View file

@ -26,27 +26,27 @@ public class ObjectLayer : BaseLayer
/// <summary>
/// The X coordinate of the object layer in tiles.
/// </summary>
public uint X { get; set; } = 0;
public int X { get; set; } = 0;
/// <summary>
/// The Y coordinate of the object layer in tiles.
/// </summary>
public uint Y { get; set; } = 0;
public int Y { get; set; } = 0;
/// <summary>
/// The width of the object layer in tiles. Meaningless.
/// </summary>
public uint Width { get; set; } = 0;
public int Width { get; set; } = 0;
/// <summary>
/// The height of the object layer in tiles. Meaningless.
/// </summary>
public uint Height { get; set; } = 0;
public int Height { get; set; } = 0;
/// <summary>
/// A color that is multiplied with any tile objects drawn by this layer.
/// </summary>
public Optional<Color> Color { get; set; } = Optional<Color>.Empty;
public Optional<TiledColor> Color { get; set; } = Optional.Empty;
/// <summary>
/// Whether the objects are drawn according to the order of appearance (<see cref="DrawOrder.Index"/>) or sorted by their Y coordinate (<see cref="DrawOrder.TopDown"/>).

View file

@ -1,7 +1,25 @@
using System.Linq;
namespace DotTiled;
/// <summary>
/// An ellipse object in a map. The existing <see cref="Object.X"/>, <see cref="Object.Y"/>, <see cref="Object.Width"/>,
/// and <see cref="Object.Height"/> properties are used to determine the size of the ellipse.
/// </summary>
public class EllipseObject : Object { }
public class EllipseObject : Object
{
internal override Object Clone() => new EllipseObject
{
ID = ID,
Name = Name,
Type = Type,
X = X,
Y = Y,
Width = Width,
Height = Height,
Rotation = Rotation,
Visible = Visible,
Template = Template,
Properties = Properties.Select(p => p.Clone()).ToList(),
};
}

View file

@ -10,7 +10,7 @@ public abstract class Object : HasPropertiesBase
/// <summary>
/// Unique ID of the objects. Each object that is placed on a map gets a unique ID. Even if an object was deleted, no object gets the same ID.
/// </summary>
public Optional<uint> ID { get; set; } = Optional<uint>.Empty;
public Optional<uint> ID { get; set; } = Optional.Empty;
/// <summary>
/// The name of the object. An arbitrary string.
@ -55,7 +55,7 @@ public abstract class Object : HasPropertiesBase
/// <summary>
/// A reference to a template file.
/// </summary>
public Optional<string> Template { get; set; } = Optional<string>.Empty;
public Optional<string> Template { get; set; } = Optional.Empty;
/// <summary>
/// Object properties.
@ -64,4 +64,10 @@ public abstract class Object : HasPropertiesBase
/// <inheritdoc/>
public override IList<IProperty> GetProperties() => Properties;
/// <summary>
/// Creates a deep copy of the object.
/// </summary>
/// <returns></returns>
internal abstract Object Clone();
}

View file

@ -1,7 +1,25 @@
using System.Linq;
namespace DotTiled;
/// <summary>
/// A point object in a map. The existing <see cref="Object.X"/> and <see cref="Object.Y"/> properties are used to
/// determine the position of the point.
/// </summary>
public class PointObject : Object { }
public class PointObject : Object
{
internal override Object Clone() => new PointObject
{
ID = ID,
Name = Name,
Type = Type,
X = X,
Y = Y,
Width = Width,
Height = Height,
Rotation = Rotation,
Visible = Visible,
Template = Template,
Properties = Properties.Select(p => p.Clone()).ToList(),
};
}

View file

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
namespace DotTiled;
@ -14,4 +15,20 @@ public class PolygonObject : Object
/// <see cref="Object.X"/> and <see cref="Object.Y"/> are used as the origin of the polygon.
/// </summary>
public required List<Vector2> Points { get; set; }
internal override Object Clone() => new PolygonObject
{
ID = ID,
Name = Name,
Type = Type,
X = X,
Y = Y,
Width = Width,
Height = Height,
Rotation = Rotation,
Visible = Visible,
Template = Template,
Properties = Properties.Select(p => p.Clone()).ToList(),
Points = Points.ToList(),
};
}

View file

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
namespace DotTiled;
@ -13,4 +14,20 @@ public class PolylineObject : Object
/// The points that make up the polyline. <see cref="Object.X"/> and <see cref="Object.Y"/> are used as the origin of the polyline.
/// </summary>
public required List<Vector2> Points { get; set; }
internal override Object Clone() => new PolylineObject
{
ID = ID,
Name = Name,
Type = Type,
X = X,
Y = Y,
Width = Width,
Height = Height,
Rotation = Rotation,
Visible = Visible,
Template = Template,
Properties = Properties.Select(p => p.Clone()).ToList(),
Points = Points.ToList(),
};
}

View file

@ -1,7 +1,25 @@
using System.Linq;
namespace DotTiled;
/// <summary>
/// A rectangle object in a map. The existing <see cref="Object.X"/>, <see cref="Object.Y"/>, <see cref="Object.Width"/>,
/// and <see cref="Object.Height"/> properties are used to determine the size of the rectangle.
/// </summary>
public class RectangleObject : Object { }
public class RectangleObject : Object
{
internal override Object Clone() => new RectangleObject
{
ID = ID,
Name = Name,
Type = Type,
X = X,
Y = Y,
Width = Width,
Height = Height,
Rotation = Rotation,
Visible = Visible,
Template = Template,
Properties = Properties.Select(p => p.Clone()).ToList(),
};
}

View file

@ -1,4 +1,5 @@
using System.Globalization;
using System.Linq;
namespace DotTiled;
@ -72,7 +73,7 @@ public class TextObject : Object
/// <summary>
/// The color of the text.
/// </summary>
public Color Color { get; set; } = Color.Parse("#000000", CultureInfo.InvariantCulture);
public TiledColor Color { get; set; } = TiledColor.Parse("#000000", CultureInfo.InvariantCulture);
/// <summary>
/// Whether the text is bold.
@ -113,4 +114,32 @@ public class TextObject : Object
/// The text to be displayed.
/// </summary>
public string Text { get; set; } = "";
internal override Object Clone() => new TextObject
{
ID = ID,
Name = Name,
Type = Type,
X = X,
Y = Y,
Width = Width,
Height = Height,
Rotation = Rotation,
Visible = Visible,
Template = Template,
Properties = Properties.Select(p => p.Clone()).ToList(),
FontFamily = FontFamily,
PixelSize = PixelSize,
Wrap = Wrap,
Color = Color,
Bold = Bold,
Italic = Italic,
Underline = Underline,
Strikeout = Strikeout,
Kerning = Kerning,
HorizontalAlignment = HorizontalAlignment,
VerticalAlignment = VerticalAlignment,
Text = Text,
};
}

View file

@ -1,3 +1,5 @@
using System.Linq;
namespace DotTiled;
/// <summary>
@ -14,4 +16,21 @@ public class TileObject : Object
/// The flipping flags for the tile.
/// </summary>
public FlippingFlags FlippingFlags { get; set; }
internal override Object Clone() => new TileObject
{
ID = ID,
Name = Name,
Type = Type,
X = X,
Y = Y,
Width = Width,
Height = Height,
Rotation = Rotation,
Visible = Visible,
Template = Template,
Properties = Properties.Select(p => p.Clone()).ToList(),
GID = GID,
FlippingFlags = FlippingFlags,
};
}

View file

@ -1,3 +1,5 @@
using System;
namespace DotTiled;
/// <summary>
@ -8,25 +10,47 @@ public class TileLayer : BaseLayer
/// <summary>
/// The X coordinate of the layer in tiles.
/// </summary>
public uint X { get; set; } = 0;
public int X { get; set; } = 0;
/// <summary>
/// The Y coordinate of the layer in tiles.
/// </summary>
public uint Y { get; set; } = 0;
public int Y { get; set; } = 0;
/// <summary>
/// The width of the layer in tiles. Always the same as the map width for fixed-size maps.
/// </summary>
public required uint Width { get; set; }
public required int Width { get; set; }
/// <summary>
/// The height of the layer in tiles. Always the same as the map height for fixed-size maps.
/// </summary>
public required uint Height { get; set; }
public required int Height { get; set; }
/// <summary>
/// The tile layer data.
/// </summary>
public Optional<Data> Data { get; set; } = Optional<Data>.Empty;
public Optional<Data> Data { get; set; } = Optional.Empty;
/// <summary>
/// Helper method to retrieve the Global Tile ID at a given coordinate in the layer.
/// </summary>
/// <param name="x">The X coordinate in the layer</param>
/// <param name="y">The Y coordinate in the layer</param>
/// <returns>The Global Tile ID at the given coordinate.</returns>
/// <exception cref="InvalidOperationException">Thrown when either <see cref="Data"/> or <see cref="Data.GlobalTileIDs"/> are missing values.</exception>
/// <exception cref="ArgumentException">Thrown when the given coordinate is not within bounds of the layer.</exception>
public uint GetGlobalTileIDAtCoord(int x, int y)
{
if (!Data.HasValue)
throw new InvalidOperationException("Data is not set.");
if (x < 0 || x >= Width || y < 0 || y >= Height)
throw new ArgumentException("Coordinates are out of bounds.");
if (!Data.Value.GlobalTileIDs.HasValue)
throw new InvalidOperationException("GlobalTileIDs is not set.");
return Data.Value.GlobalTileIDs.Value[(y * Width) + x];
}
}

View file

@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using System.Globalization;
@ -100,7 +101,7 @@ public class Map : HasPropertiesBase
/// <summary>
/// The Tiled version used to save the file.
/// </summary>
public Optional<string> TiledVersion { get; set; } = Optional<string>.Empty;
public Optional<string> TiledVersion { get; set; } = Optional.Empty;
/// <summary>
/// The class of this map.
@ -126,37 +127,37 @@ public class Map : HasPropertiesBase
/// <summary>
/// The width of the map in tiles.
/// </summary>
public required uint Width { get; set; }
public required int Width { get; set; }
/// <summary>
/// The height of the map in tiles.
/// </summary>
public required uint Height { get; set; }
public required int Height { get; set; }
/// <summary>
/// The width of a tile.
/// </summary>
public required uint TileWidth { get; set; }
public required int TileWidth { get; set; }
/// <summary>
/// The height of a tile.
/// </summary>
public required uint TileHeight { get; set; }
public required int TileHeight { get; set; }
/// <summary>
/// Only for hexagonal maps. Determines the width or height (depending on the staggered axis) of the tile's edge, in pixels.
/// </summary>
public Optional<uint> HexSideLength { get; set; } = Optional<uint>.Empty;
public Optional<int> HexSideLength { get; set; } = Optional.Empty;
/// <summary>
/// For staggered and hexagonal maps, determines which axis (X or Y) is staggered.
/// </summary>
public Optional<StaggerAxis> StaggerAxis { get; set; } = Optional<StaggerAxis>.Empty;
public Optional<StaggerAxis> StaggerAxis { get; set; } = Optional.Empty;
/// <summary>
/// For staggered and hexagonal maps, determines whether the "even" or "odd" indexes along the staggered axis are shifted.
/// </summary>
public Optional<StaggerIndex> StaggerIndex { get; set; } = Optional<StaggerIndex>.Empty;
public Optional<StaggerIndex> StaggerIndex { get; set; } = Optional.Empty;
/// <summary>
/// X coordinate of the parallax origin in pixels.
@ -171,7 +172,7 @@ public class Map : HasPropertiesBase
/// <summary>
/// The background color of the map.
/// </summary>
public Color BackgroundColor { get; set; } = Color.Parse("#00000000", CultureInfo.InvariantCulture);
public TiledColor BackgroundColor { get; set; } = TiledColor.Parse("#00000000", CultureInfo.InvariantCulture);
/// <summary>
/// Stores the next available ID for new layers. This number is used to prevent reuse of the same ID after layers have been removed.
@ -205,4 +206,31 @@ public class Map : HasPropertiesBase
/// Hierarchical list of layers. <see cref="Group"/> is a layer type which can contain sub-layers to create a hierarchy.
/// </summary>
public List<BaseLayer> Layers { get; set; } = [];
/// <summary>
/// Resolves which tileset a global tile ID belongs to, and returns the corresponding local tile ID.
/// </summary>
/// <param name="globalTileID">The global tile ID to resolve.</param>
/// <param name="localTileID">The local tile ID within the tileset.</param>
/// <returns>The tileset that contains the tile with the specified global tile ID.</returns>
/// <exception cref="ArgumentException">Thrown when no tileset is found for the specified global tile ID.</exception>
public Tileset ResolveTilesetForGlobalTileID(uint globalTileID, out uint localTileID)
{
for (int i = Tilesets.Count - 1; i >= 0; i--)
{
var tileset = Tilesets[i];
if (globalTileID >= tileset.FirstGID.Value
&& globalTileID < tileset.FirstGID.Value + tileset.TileCount)
{
localTileID = globalTileID - tileset.FirstGID.Value;
return tileset;
}
}
throw new ArgumentException(
$"No tileset found for global tile ID {globalTileID}.",
nameof(globalTileID)
);
}
}

View file

@ -2,62 +2,94 @@ using System;
namespace DotTiled;
/// <summary>
/// Represents an empty value.
/// </summary>
public readonly struct OptionalEmpty;
/// <summary>
/// Represents an empty <see cref="Optional{T}"/> object.
/// </summary>
public static class Optional
{
/// <summary>
/// Represents an empty <see cref="Optional{T}"/> object.
/// </summary>
public static readonly OptionalEmpty Empty = default;
}
/// <summary>
/// Represents a value that may or may not be present.
/// </summary>
/// <typeparam name="T">The type of the optionally present value.</typeparam>
public class Optional<T>
public readonly struct Optional<T>
{
#pragma warning disable IDE0032 // Use auto property
private readonly bool _hasValue;
private readonly T _value;
/// <summary>
/// Gets a value indicating whether the current <see cref="Optional{T}"/> object has a value.
/// Returns <see langword="true"/> if the <see cref="Value"/> will return a meaningful value.
/// </summary>
public bool HasValue { get; }
/// <returns></returns>
public bool HasValue => _hasValue;
#pragma warning restore IDE0032 // Use auto property
/// <summary>
/// Gets the value of the current <see cref="Optional{T}"/> object if it has been set; otherwise, throws an exception.
/// Constructs an <see cref="Optional{T}"/> with a meaningful value.
/// </summary>
/// <param name="value"></param>
public Optional(T value)
{
_hasValue = true;
_value = value;
}
/// <summary>
/// Gets the value of the current object. Not meaningful unless <see cref="HasValue"/> returns <see langword="true"/>.
/// </summary>
/// <remarks>
/// <para>Unlike <see cref="Nullable{T}.Value"/>, this property does not throw an exception when
/// <see cref="HasValue"/> is <see langword="false"/>.</para>
/// </remarks>
/// <returns>
/// <para>The value if <see cref="HasValue"/> is <see langword="true"/>; otherwise, the default value for type
/// <typeparamref name="T"/>.</para>
/// </returns>
public T Value => HasValue ? _value : throw new InvalidOperationException("Value is not set");
/// <summary>
/// Initializes a new instance of the <see cref="Optional{T}"/> class with the specified value.
/// Creates a new object initialized to a meaningful value.
/// </summary>
/// <param name="value">The value to be set.</param>
public Optional(T value)
{
_value = value;
HasValue = true;
}
/// <summary>
/// Initializes a new instance of the <see cref="Optional{T}"/> class with no value.
/// </summary>
public Optional()
{
_value = default!;
HasValue = false;
}
/// <summary>
/// Implicitly converts a value to an <see cref="Optional{T}"/> object.
/// </summary>
/// <param name="value">The value to be converted.</param>
/// <param name="value"></param>
public static implicit operator Optional<T>(T value)
{
if (value is null)
return new();
{
return default;
}
return new(value);
return new Optional<T>(value);
}
/// <summary>
/// Implicitly converts an <see cref="Optional{T}"/> object to a value.
/// Creates a new object initialized to an empty value.
/// </summary>
/// <param name="optional">The <see cref="Optional{T}"/> object to be converted.</param>
public static implicit operator T(Optional<T> optional)
/// <param name="_"></param>
public static implicit operator Optional<T>(OptionalEmpty _)
{
return optional.Value;
return default;
}
/// <summary>
/// Returns a string representation of this object.
/// </summary>
public override string ToString()
{
// Note: For nullable types, it's possible to have _hasValue true and _value null.
return _hasValue
? _value?.ToString() ?? "null"
: "Empty";
}
/// <summary>
@ -71,17 +103,6 @@ public class Optional<T>
return left.Equals(right);
}
/// <summary>
/// Determines whether the specified <see cref="Optional{T}"/> objects are not equal.
/// </summary>
/// <param name="left"></param>
/// <param name="right"></param>
/// <returns></returns>
public static bool operator !=(Optional<T> left, Optional<T> right)
{
return !left.Equals(right);
}
/// <summary>
/// Returns the value of the current <see cref="Optional{T}"/> object if it has been set; otherwise, returns the specified default value.
/// </summary>
@ -96,9 +117,6 @@ public class Optional<T>
/// <returns></returns>
public Optional<T> GetValueOrOptional(Optional<T> defaultValue) => HasValue ? this : defaultValue;
/// <inheritdoc />
public override string ToString() => HasValue ? _value.ToString() : "Empty";
/// <inheritdoc />
public override bool Equals(object obj)
{
@ -129,9 +147,13 @@ public class Optional<T>
public override int GetHashCode() => HasValue ? _value!.GetHashCode() : 0;
/// <summary>
/// Represents an empty <see cref="Optional{T}"/> object.
/// Determines whether the specified <see cref="Optional{T}"/> objects are not equal.
/// </summary>
#pragma warning disable CA1000 // Do not declare static members on generic types
public static Optional<T> Empty => new();
#pragma warning restore CA1000 // Do not declare static members on generic types
/// <param name="left"></param>
/// <param name="right"></param>
/// <returns></returns>
public static bool operator !=(Optional<T> left, Optional<T> right)
{
return !left.Equals(right);
}
}

View file

@ -3,7 +3,7 @@ namespace DotTiled;
/// <summary>
/// Represents a color property.
/// </summary>
public class ColorProperty : IProperty<Optional<Color>>
public class ColorProperty : IProperty<Optional<TiledColor>>
{
/// <inheritdoc/>
public required string Name { get; set; }
@ -14,7 +14,7 @@ public class ColorProperty : IProperty<Optional<Color>>
/// <summary>
/// The color value of the property.
/// </summary>
public required Optional<Color> Value { get; set; }
public required Optional<TiledColor> Value { get; set; }
/// <inheritdoc/>
public IProperty Clone() => new ColorProperty

View file

@ -78,7 +78,7 @@ public class CustomClassDefinition : HasPropertiesBase, ICustomTypeDefinition
/// <summary>
/// The color of the custom class inside the Tiled editor.
/// </summary>
public Color Color { get; set; }
public TiledColor Color { get; set; }
/// <summary>
/// Whether the custom class should be drawn with a fill color.
@ -155,8 +155,8 @@ public class CustomClassDefinition : HasPropertiesBase, ICustomTypeDefinition
{
case Type t when t == typeof(bool):
return new BoolProperty { Name = propertyInfo.Name, Value = (bool)propertyInfo.GetValue(instance) };
case Type t when t == typeof(Color):
return new ColorProperty { Name = propertyInfo.Name, Value = (Color)propertyInfo.GetValue(instance) };
case Type t when t == typeof(TiledColor):
return new ColorProperty { Name = propertyInfo.Name, Value = (TiledColor)propertyInfo.GetValue(instance) };
case Type t when t == typeof(float):
return new FloatProperty { Name = propertyInfo.Name, Value = (float)propertyInfo.GetValue(instance) };
case Type t when t == typeof(string):

View file

@ -7,7 +7,7 @@ namespace DotTiled;
/// <summary>
/// Represents a Tiled color.
/// </summary>
public class Color : IParsable<Color>, IEquatable<Color>
public class TiledColor : IParsable<TiledColor>, IEquatable<TiledColor>
{
/// <summary>
/// The red component of the color.
@ -30,31 +30,31 @@ public class Color : IParsable<Color>, IEquatable<Color>
public byte A { get; set; } = 255;
/// <summary>
/// Attempts to parse the specified string into a <see cref="Color"/>. Expects strings in the format <c>#RRGGBB</c> or <c>#AARRGGBB</c>.
/// Attempts to parse the specified string into a <see cref="TiledColor"/>. Expects strings in the format <c>#RRGGBB</c> or <c>#AARRGGBB</c>.
/// The leading <c>#</c> is optional.
/// </summary>
/// <param name="s">A string value to parse into a <see cref="Color"/></param>
/// <param name="s">A string value to parse into a <see cref="TiledColor"/></param>
/// <param name="provider">An object that supplies culture-specific information about the format of s.</param>
/// <returns>The parsed <see cref="Color"/></returns>
/// <returns>The parsed <see cref="TiledColor"/></returns>
/// <exception cref="FormatException">Thrown in case the provided string <paramref name="s"/> is not in a valid format.</exception>
public static Color Parse(string s, IFormatProvider provider)
public static TiledColor Parse(string s, IFormatProvider provider)
{
_ = TryParse(s, provider, out var result);
return result ?? throw new FormatException($"Invalid format for TiledColor: {s}");
}
/// <summary>
/// Attempts to parse the specified string into a <see cref="Color"/>. Expects strings in the format <c>#RRGGBB</c> or <c>#AARRGGBB</c>.
/// Attempts to parse the specified string into a <see cref="TiledColor"/>. Expects strings in the format <c>#RRGGBB</c> or <c>#AARRGGBB</c>.
/// The leading <c>#</c> is optional.
/// </summary>
/// <param name="s">A string value to parse into a <see cref="Color"/></param>
/// <param name="s">A string value to parse into a <see cref="TiledColor"/></param>
/// <param name="provider">An object that supplies culture-specific information about the format of s.</param>
/// <param name="result">When this method returns, contains the parsed <see cref="Color"/> or <c>null</c> on failure.</param>
/// <param name="result">When this method returns, contains the parsed <see cref="TiledColor"/> or <c>null</c> on failure.</param>
/// <returns><c>true</c> if <paramref name="s"/> was successfully parsed; otherwise, <c>false</c>.</returns>
public static bool TryParse(
[NotNullWhen(true)] string s,
IFormatProvider provider,
[MaybeNullWhen(false)] out Color result)
[MaybeNullWhen(false)] out TiledColor result)
{
if (s is not null && !s.StartsWith('#'))
return TryParse($"#{s}", provider, out result);
@ -68,7 +68,7 @@ public class Color : IParsable<Color>, IEquatable<Color>
if (s.Length == 7)
{
result = new Color
result = new TiledColor
{
R = byte.Parse(s[1..3], NumberStyles.HexNumber, provider),
G = byte.Parse(s[3..5], NumberStyles.HexNumber, provider),
@ -77,7 +77,7 @@ public class Color : IParsable<Color>, IEquatable<Color>
}
else
{
result = new Color
result = new TiledColor
{
A = byte.Parse(s[1..3], NumberStyles.HexNumber, provider),
R = byte.Parse(s[3..5], NumberStyles.HexNumber, provider),
@ -90,7 +90,7 @@ public class Color : IParsable<Color>, IEquatable<Color>
}
/// <inheritdoc/>
public bool Equals(Color other)
public bool Equals(TiledColor other)
{
if (other is null)
return false;
@ -99,7 +99,7 @@ public class Color : IParsable<Color>, IEquatable<Color>
}
/// <inheritdoc/>
public override bool Equals(object obj) => obj is Color other && Equals(other);
public override bool Equals(object obj) => obj is TiledColor other && Equals(other);
/// <inheritdoc/>
public override int GetHashCode() => HashCode.Combine(R, G, B, A);

View file

@ -16,7 +16,7 @@ public class DefaultResourceCache : IResourceCache
if (_templates.TryGetValue(path, out var template))
return new Optional<Template>(template);
return Optional<Template>.Empty;
return Optional.Empty;
}
/// <inheritdoc/>
@ -25,7 +25,7 @@ public class DefaultResourceCache : IResourceCache
if (_tilesets.TryGetValue(path, out var tileset))
return new Optional<Tileset>(tileset);
return Optional<Tileset>.Empty;
return Optional.Empty;
}
/// <inheritdoc/>

View file

@ -91,7 +91,7 @@ internal static partial class Helpers
if (string.IsNullOrWhiteSpace(className))
return null;
var customType = customTypeResolver(className) ?? throw new InvalidOperationException($"Could not resolve custom type '{className}'.");
var customType = customTypeResolver(className);
if (!customType.HasValue)
return null;

View file

@ -16,7 +16,7 @@ public interface IResourceCache
/// Retrieves a tileset from the cache with the given <paramref name="path"/>.
/// </summary>
/// <param name="path">The path to the tileset file.</param>
/// <returns>The tileset if it exists in the cache; otherwise, <see cref="Optional{Tileset}.Empty"/>.</returns>
/// <returns>The tileset if it exists in the cache; otherwise, <see cref="Optional.Empty"/>.</returns>
Optional<Tileset> GetTileset(string path);
/// <summary>
@ -30,6 +30,6 @@ public interface IResourceCache
/// Retrieves a template from the cache with the given <paramref name="path"/>.
/// </summary>
/// <param name="path">The path to the template file.</param>
/// <returns>The template if it exists in the cache; otherwise, <see cref="Optional{Template}.Empty"/>.</returns>
/// <returns>The template if it exists in the cache; otherwise, <see cref="Optional.Empty"/>.</returns>
Optional<Template> GetTemplate(string path);
}

View file

@ -119,6 +119,6 @@ public class Loader
if (_customTypeDefinitions.TryGetValue(name, out var customTypeDefinition))
return new Optional<ICustomTypeDefinition>(customTypeDefinition);
return Optional<ICustomTypeDefinition>.Empty;
return Optional.Empty;
}
}

View file

@ -18,10 +18,10 @@ internal static class ExtensionsJsonElement
internal static Optional<T> GetOptionalProperty<T>(this JsonElement element, string propertyName)
{
if (!element.TryGetProperty(propertyName, out var property))
return Optional<T>.Empty;
return Optional.Empty;
if (property.ValueKind == JsonValueKind.Null)
return Optional<T>.Empty;
return Optional.Empty;
return property.GetValueAs<T>();
}
@ -67,15 +67,15 @@ internal static class ExtensionsJsonElement
internal static Optional<T> GetOptionalPropertyParseable<T>(this JsonElement element, string propertyName) where T : IParsable<T>
{
if (!element.TryGetProperty(propertyName, out var property))
return Optional<T>.Empty;
return Optional.Empty;
return T.Parse(property.GetString()!, CultureInfo.InvariantCulture);
}
internal static Optional<T> GetOptionalPropertyParseable<T>(this JsonElement element, string propertyName, Func<string, T> parser)
internal static Optional<T> GetOptionalPropertyParseable<T>(this JsonElement element, string propertyName, Func<string, Optional<T>> parser)
{
if (!element.TryGetProperty(propertyName, out var property))
return Optional<T>.Empty;
return Optional.Empty;
return parser(property.GetString()!);
}
@ -91,7 +91,7 @@ internal static class ExtensionsJsonElement
internal static Optional<T> GetOptionalPropertyCustom<T>(this JsonElement element, string propertyName, Func<JsonElement, T> parser)
{
if (!element.TryGetProperty(propertyName, out var property))
return Optional<T>.Empty;
return Optional.Empty;
return parser(property);
}

View file

@ -19,12 +19,11 @@ public abstract partial class TmjReaderBase
internal static Chunk ReadChunk(JsonElement element, Optional<DataCompression> compression, DataEncoding encoding)
{
var data = ReadDataWithoutChunks(element, compression, encoding);
var data = element.GetRequiredPropertyCustom<Data>("data", e => ReadDataWithoutChunks(e, compression, encoding));
var x = element.GetRequiredProperty<int>("x");
var y = element.GetRequiredProperty<int>("y");
var width = element.GetRequiredProperty<uint>("width");
var height = element.GetRequiredProperty<uint>("height");
var width = element.GetRequiredProperty<int>("width");
var height = element.GetRequiredProperty<int>("height");
return new Chunk
{
@ -32,8 +31,8 @@ public abstract partial class TmjReaderBase
Y = y,
Width = width,
Height = height,
GlobalTileIDs = data.GlobalTileIDs,
FlippingFlags = data.FlippingFlags
GlobalTileIDs = data.GlobalTileIDs.Value,
FlippingFlags = data.FlippingFlags.Value
};
}

View file

@ -12,7 +12,7 @@ public abstract partial class TmjReaderBase
var @class = element.GetOptionalProperty<string>("class").GetValueOr("");
var opacity = element.GetOptionalProperty<float>("opacity").GetValueOr(1.0f);
var visible = element.GetOptionalProperty<bool>("visible").GetValueOr(true);
var tintColor = element.GetOptionalPropertyParseable<Color>("tintcolor");
var tintColor = element.GetOptionalPropertyParseable<TiledColor>("tintcolor");
var offsetX = element.GetOptionalProperty<float>("offsetx").GetValueOr(0.0f);
var offsetY = element.GetOptionalProperty<float>("offsety").GetValueOr(0.0f);
var parallaxX = element.GetOptionalProperty<float>("parallaxx").GetValueOr(1.0f);

View file

@ -11,7 +11,7 @@ public abstract partial class TmjReaderBase
var @class = element.GetOptionalProperty<string>("class").GetValueOr("");
var opacity = element.GetOptionalProperty<float>("opacity").GetValueOr(1.0f);
var visible = element.GetOptionalProperty<bool>("visible").GetValueOr(true);
var tintColor = element.GetOptionalPropertyParseable<Color>("tintcolor");
var tintColor = element.GetOptionalPropertyParseable<TiledColor>("tintcolor");
var offsetX = element.GetOptionalProperty<float>("offsetx").GetValueOr(0.0f);
var offsetY = element.GetOptionalProperty<float>("offsety").GetValueOr(0.0f);
var parallaxX = element.GetOptionalProperty<float>("parallaxx").GetValueOr(1.0f);
@ -19,17 +19,19 @@ public abstract partial class TmjReaderBase
var properties = ResolveAndMergeProperties(@class, element.GetOptionalPropertyCustom("properties", ReadProperties).GetValueOr([]));
var image = element.GetRequiredProperty<string>("image");
var imageWidth = element.GetOptionalProperty<int>("imagewidth").GetValueOr(0);
var imageHeight = element.GetOptionalProperty<int>("imageheight").GetValueOr(0);
var repeatX = element.GetOptionalProperty<bool>("repeatx").GetValueOr(false);
var repeatY = element.GetOptionalProperty<bool>("repeaty").GetValueOr(false);
var transparentColor = element.GetOptionalPropertyParseable<Color>("transparentcolor");
var x = element.GetOptionalProperty<uint>("x").GetValueOr(0);
var y = element.GetOptionalProperty<uint>("y").GetValueOr(0);
var transparentColor = element.GetOptionalPropertyParseable<TiledColor>("transparentcolor");
var x = element.GetOptionalProperty<int>("x").GetValueOr(0);
var y = element.GetOptionalProperty<int>("y").GetValueOr(0);
var imgModel = new Image
{
Format = Helpers.ParseImageFormatFromSource(image),
Height = 0,
Width = 0,
Height = imageHeight,
Width = imageWidth,
Source = image,
TransparentColor = transparentColor
};

View file

@ -28,11 +28,11 @@ public abstract partial class TmjReaderBase
_ => throw new JsonException($"Unknown render order '{s}'")
}).GetValueOr(RenderOrder.RightDown);
var compressionLevel = element.GetOptionalProperty<int>("compressionlevel").GetValueOr(-1);
var width = element.GetRequiredProperty<uint>("width");
var height = element.GetRequiredProperty<uint>("height");
var tileWidth = element.GetRequiredProperty<uint>("tilewidth");
var tileHeight = element.GetRequiredProperty<uint>("tileheight");
var hexSideLength = element.GetOptionalProperty<uint>("hexsidelength");
var width = element.GetRequiredProperty<int>("width");
var height = element.GetRequiredProperty<int>("height");
var tileWidth = element.GetRequiredProperty<int>("tilewidth");
var tileHeight = element.GetRequiredProperty<int>("tileheight");
var hexSideLength = element.GetOptionalProperty<int>("hexsidelength");
var staggerAxis = element.GetOptionalPropertyParseable<StaggerAxis>("staggeraxis", s => s switch
{
"x" => StaggerAxis.X,
@ -47,7 +47,7 @@ public abstract partial class TmjReaderBase
});
var parallaxOriginX = element.GetOptionalProperty<float>("parallaxoriginx").GetValueOr(0f);
var parallaxOriginY = element.GetOptionalProperty<float>("parallaxoriginy").GetValueOr(0f);
var backgroundColor = element.GetOptionalPropertyParseable<Color>("backgroundcolor").GetValueOr(Color.Parse("#00000000", CultureInfo.InvariantCulture));
var backgroundColor = element.GetOptionalPropertyParseable<TiledColor>("backgroundcolor").GetValueOr(TiledColor.Parse("#00000000", CultureInfo.InvariantCulture));
var nextLayerID = element.GetRequiredProperty<uint>("nextlayerid");
var nextObjectID = element.GetRequiredProperty<uint>("nextobjectid");
var infinite = element.GetOptionalProperty<bool>("infinite").GetValueOr(false);

View file

@ -15,18 +15,18 @@ public abstract partial class TmjReaderBase
var @class = element.GetOptionalProperty<string>("class").GetValueOr("");
var opacity = element.GetOptionalProperty<float>("opacity").GetValueOr(1.0f);
var visible = element.GetOptionalProperty<bool>("visible").GetValueOr(true);
var tintColor = element.GetOptionalPropertyParseable<Color>("tintcolor");
var tintColor = element.GetOptionalPropertyParseable<TiledColor>("tintcolor");
var offsetX = element.GetOptionalProperty<float>("offsetx").GetValueOr(0.0f);
var offsetY = element.GetOptionalProperty<float>("offsety").GetValueOr(0.0f);
var parallaxX = element.GetOptionalProperty<float>("parallaxx").GetValueOr(1.0f);
var parallaxY = element.GetOptionalProperty<float>("parallaxy").GetValueOr(1.0f);
var properties = ResolveAndMergeProperties(@class, element.GetOptionalPropertyCustom("properties", ReadProperties).GetValueOr([]));
var x = element.GetOptionalProperty<uint>("x").GetValueOr(0);
var y = element.GetOptionalProperty<uint>("y").GetValueOr(0);
var width = element.GetOptionalProperty<uint>("width").GetValueOr(0);
var height = element.GetOptionalProperty<uint>("height").GetValueOr(0);
var color = element.GetOptionalPropertyParseable<Color>("color");
var x = element.GetOptionalProperty<int>("x").GetValueOr(0);
var y = element.GetOptionalProperty<int>("y").GetValueOr(0);
var width = element.GetOptionalProperty<int>("width").GetValueOr(0);
var height = element.GetOptionalProperty<int>("height").GetValueOr(0);
var color = element.GetOptionalPropertyParseable<TiledColor>("color");
var drawOrder = element.GetOptionalPropertyParseable<DrawOrder>("draworder", s => s switch
{
"topdown" => DrawOrder.TopDown,
@ -61,7 +61,7 @@ public abstract partial class TmjReaderBase
internal DotTiled.Object ReadObject(JsonElement element)
{
Optional<uint> idDefault = Optional<uint>.Empty;
Optional<uint> idDefault = Optional.Empty;
string nameDefault = "";
string typeDefault = "";
float xDefault = 0f;
@ -76,12 +76,13 @@ public abstract partial class TmjReaderBase
List<Vector2> polygonDefault = null;
List<Vector2> polylineDefault = null;
List<IProperty> propertiesDefault = [];
Optional<uint> gidDefault = Optional.Empty;
var template = element.GetOptionalProperty<string>("template");
if (template.HasValue)
{
var resolvedTemplate = _externalTemplateResolver(template);
var templObj = resolvedTemplate.Object;
var resolvedTemplate = _externalTemplateResolver(template.Value);
var templObj = resolvedTemplate.Object.Clone();
idDefault = templObj.ID;
nameDefault = templObj.Name;
@ -97,10 +98,11 @@ public abstract partial class TmjReaderBase
pointDefault = templObj is PointObject;
polygonDefault = (templObj is PolygonObject polygonObj) ? polygonObj.Points : null;
polylineDefault = (templObj is PolylineObject polylineObj) ? polylineObj.Points : null;
gidDefault = (templObj is TileObject tileObj) ? tileObj.GID : Optional.Empty;
}
var ellipse = element.GetOptionalProperty<bool>("ellipse").GetValueOr(ellipseDefault);
var gid = element.GetOptionalProperty<uint>("gid");
var gid = element.GetOptionalProperty<uint>("gid").GetValueOrOptional(gidDefault);
var height = element.GetOptionalProperty<float>("height").GetValueOr(heightDefault);
var id = element.GetOptionalProperty<uint>("id").GetValueOrOptional(idDefault);
var name = element.GetOptionalProperty<string>("name").GetValueOr(nameDefault);
@ -225,7 +227,7 @@ public abstract partial class TmjReaderBase
text.Value.Visible = visible;
text.Value.Template = template;
text.Value.Properties = properties;
return text;
return text.Value;
}
return new RectangleObject
@ -255,7 +257,7 @@ public abstract partial class TmjReaderBase
internal static TextObject ReadText(JsonElement element)
{
var bold = element.GetOptionalProperty<bool>("bold").GetValueOr(false);
var color = element.GetOptionalPropertyParseable<Color>("color").GetValueOr(Color.Parse("#00000000", CultureInfo.InvariantCulture));
var color = element.GetOptionalPropertyParseable<TiledColor>("color").GetValueOr(TiledColor.Parse("#000000", CultureInfo.InvariantCulture));
var fontfamily = element.GetOptionalProperty<string>("fontfamily").GetValueOr("sans-serif");
var halign = element.GetOptionalPropertyParseable<TextHorizontalAlignment>("halign", s => s switch
{

View file

@ -36,7 +36,7 @@ public abstract partial class TmjReaderBase
PropertyType.Int => new IntProperty { Name = name, Value = e.GetRequiredProperty<int>("value") },
PropertyType.Float => new FloatProperty { Name = name, Value = e.GetRequiredProperty<float>("value") },
PropertyType.Bool => new BoolProperty { Name = name, Value = e.GetRequiredProperty<bool>("value") },
PropertyType.Color => new ColorProperty { Name = name, Value = e.GetRequiredPropertyParseable<Color>("value", s => s == "" ? default : Color.Parse(s, CultureInfo.InvariantCulture)) },
PropertyType.Color => new ColorProperty { Name = name, Value = e.GetRequiredPropertyParseable<TiledColor>("value", s => s == "" ? default : TiledColor.Parse(s, CultureInfo.InvariantCulture)) },
PropertyType.File => new FileProperty { Name = name, Value = e.GetRequiredProperty<string>("value") },
PropertyType.Object => new ObjectProperty { Name = name, Value = e.GetRequiredProperty<uint>("value") },
PropertyType.Class => throw new JsonException("Class property must have a property type"),
@ -163,7 +163,7 @@ public abstract partial class TmjReaderBase
PropertyType.Int => new IntProperty { Name = prop.Name, Value = propElement.GetValueAs<int>() },
PropertyType.Float => new FloatProperty { Name = prop.Name, Value = propElement.GetValueAs<float>() },
PropertyType.Bool => new BoolProperty { Name = prop.Name, Value = propElement.GetValueAs<bool>() },
PropertyType.Color => new ColorProperty { Name = prop.Name, Value = Color.Parse(propElement.GetValueAs<string>(), CultureInfo.InvariantCulture) },
PropertyType.Color => new ColorProperty { Name = prop.Name, Value = TiledColor.Parse(propElement.GetValueAs<string>(), CultureInfo.InvariantCulture) },
PropertyType.File => new FileProperty { Name = prop.Name, Value = propElement.GetValueAs<string>() },
PropertyType.Object => new ObjectProperty { Name = prop.Name, Value = propElement.GetValueAs<uint>() },
PropertyType.Enum => ReadEnumProperty(propElement),

View file

@ -16,13 +16,13 @@ public abstract partial class TmjReaderBase
{
"zlib" => DataCompression.ZLib,
"gzip" => DataCompression.GZip,
"" => Optional<DataCompression>.Empty,
"" => Optional.Empty,
_ => throw new JsonException($"Unsupported compression '{s}'.")
});
var chunks = element.GetOptionalPropertyCustom<Data>("chunks", e => ReadDataAsChunks(e, compression, encoding));
var @class = element.GetOptionalProperty<string>("class").GetValueOr("");
var data = element.GetOptionalPropertyCustom<Data>("data", e => ReadDataWithoutChunks(e, compression, encoding));
var height = element.GetRequiredProperty<uint>("height");
var height = element.GetRequiredProperty<int>("height");
var id = element.GetRequiredProperty<uint>("id");
var name = element.GetRequiredProperty<string>("name");
var offsetX = element.GetOptionalProperty<float>("offsetx").GetValueOr(0.0f);
@ -35,12 +35,12 @@ public abstract partial class TmjReaderBase
var repeatY = element.GetOptionalProperty<bool>("repeaty").GetValueOr(false);
var startX = element.GetOptionalProperty<int>("startx").GetValueOr(0);
var startY = element.GetOptionalProperty<int>("starty").GetValueOr(0);
var tintColor = element.GetOptionalPropertyParseable<Color>("tintcolor");
var transparentColor = element.GetOptionalPropertyParseable<Color>("transparentcolor");
var tintColor = element.GetOptionalPropertyParseable<TiledColor>("tintcolor");
var transparentColor = element.GetOptionalPropertyParseable<TiledColor>("transparentcolor");
var visible = element.GetOptionalProperty<bool>("visible").GetValueOr(true);
var width = element.GetRequiredProperty<uint>("width");
var x = element.GetRequiredProperty<uint>("x");
var y = element.GetRequiredProperty<uint>("y");
var width = element.GetRequiredProperty<int>("width");
var x = element.GetRequiredProperty<int>("x");
var y = element.GetRequiredProperty<int>("y");
if (!data.HasValue && !chunks.HasValue)
throw new JsonException("Tile layer does not contain data.");
@ -62,7 +62,7 @@ public abstract partial class TmjReaderBase
Y = y,
Width = width,
Height = height,
Data = data ?? chunks
Data = data.GetValueOrOptional(chunks)
};
}
}

View file

@ -7,25 +7,35 @@ public abstract partial class TmjReaderBase
{
internal Tileset ReadTileset(
JsonElement element,
Optional<string> parentVersion = null,
Optional<string> parentTiledVersion = null)
Optional<string> parentVersion = default,
Optional<string> parentTiledVersion = default)
{
var backgroundColor = element.GetOptionalPropertyParseable<Color>("backgroundcolor");
var source = element.GetOptionalProperty<string>("source");
var firstGID = element.GetOptionalProperty<uint>("firstgid");
if (source.HasValue)
{
var resolvedTileset = _externalTilesetResolver(source.Value);
resolvedTileset.FirstGID = firstGID;
resolvedTileset.Source = source;
return resolvedTileset;
}
var backgroundColor = element.GetOptionalPropertyParseable<TiledColor>("backgroundcolor");
var @class = element.GetOptionalProperty<string>("class").GetValueOr("");
var columns = element.GetOptionalProperty<uint>("columns");
var columns = element.GetRequiredProperty<int>("columns");
var fillMode = element.GetOptionalPropertyParseable<FillMode>("fillmode", s => s switch
{
"stretch" => FillMode.Stretch,
"preserve-aspect-fit" => FillMode.PreserveAspectFit,
_ => throw new JsonException($"Unknown fill mode '{s}'")
}).GetValueOr(FillMode.Stretch);
var firstGID = element.GetOptionalProperty<uint>("firstgid");
var grid = element.GetOptionalPropertyCustom<Grid>("grid", ReadGrid);
var image = element.GetOptionalProperty<string>("image");
var imageHeight = element.GetOptionalProperty<uint>("imageheight");
var imageWidth = element.GetOptionalProperty<uint>("imagewidth");
var margin = element.GetOptionalProperty<uint>("margin");
var name = element.GetOptionalProperty<string>("name");
var imageHeight = element.GetOptionalProperty<int>("imageheight");
var imageWidth = element.GetOptionalProperty<int>("imagewidth");
var margin = element.GetRequiredProperty<int>("margin");
var name = element.GetRequiredProperty<string>("name");
var objectAlignment = element.GetOptionalPropertyParseable<ObjectAlignment>("objectalignment", s => s switch
{
"unspecified" => ObjectAlignment.Unspecified,
@ -41,11 +51,10 @@ public abstract partial class TmjReaderBase
_ => throw new JsonException($"Unknown object alignment '{s}'")
}).GetValueOr(ObjectAlignment.Unspecified);
var properties = ResolveAndMergeProperties(@class, element.GetOptionalPropertyCustom("properties", ReadProperties).GetValueOr([]));
var source = element.GetOptionalProperty<string>("source");
var spacing = element.GetOptionalProperty<uint>("spacing");
var tileCount = element.GetOptionalProperty<uint>("tilecount");
var spacing = element.GetRequiredProperty<int>("spacing");
var tileCount = element.GetRequiredProperty<int>("tilecount");
var tiledVersion = element.GetOptionalProperty<string>("tiledversion").GetValueOrOptional(parentTiledVersion);
var tileHeight = element.GetOptionalProperty<uint>("tileheight");
var tileHeight = element.GetRequiredProperty<int>("tileheight");
var tileOffset = element.GetOptionalPropertyCustom<TileOffset>("tileoffset", ReadTileOffset);
var tileRenderSize = element.GetOptionalPropertyParseable<TileRenderSize>("tilerendersize", s => s switch
{
@ -54,29 +63,20 @@ public abstract partial class TmjReaderBase
_ => throw new JsonException($"Unknown tile render size '{s}'")
}).GetValueOr(TileRenderSize.Tile);
var tiles = element.GetOptionalPropertyCustom<List<Tile>>("tiles", ReadTiles).GetValueOr([]);
var tileWidth = element.GetOptionalProperty<uint>("tilewidth");
var transparentColor = element.GetOptionalPropertyParseable<Color>("transparentcolor");
var type = element.GetOptionalProperty<string>("type");
var tileWidth = element.GetRequiredProperty<int>("tilewidth");
var transparentColor = element.GetOptionalPropertyParseable<TiledColor>("transparentcolor");
var version = element.GetOptionalProperty<string>("version").GetValueOrOptional(parentVersion);
var transformations = element.GetOptionalPropertyCustom<Transformations>("transformations", ReadTransformations);
var wangsets = element.GetOptionalPropertyCustom<List<Wangset>>("wangsets", el => el.GetValueAsList<Wangset>(e => ReadWangset(e))).GetValueOr([]);
if (source.HasValue)
{
var resolvedTileset = _externalTilesetResolver(source);
resolvedTileset.FirstGID = firstGID;
resolvedTileset.Source = source;
return resolvedTileset;
}
Optional<Image> imageModel = image.HasValue ? new Image
{
Format = Helpers.ParseImageFormatFromSource(image),
Format = Helpers.ParseImageFormatFromSource(image.Value),
Source = image,
Height = imageHeight,
Width = imageWidth,
TransparentColor = transparentColor
} : Optional<Image>.Empty;
} : Optional.Empty;
return new Tileset
{
@ -129,8 +129,8 @@ public abstract partial class TmjReaderBase
"isometric" => GridOrientation.Isometric,
_ => throw new JsonException($"Unknown grid orientation '{s}'")
}).GetValueOr(GridOrientation.Orthogonal);
var height = element.GetRequiredProperty<uint>("height");
var width = element.GetRequiredProperty<uint>("width");
var height = element.GetRequiredProperty<int>("height");
var width = element.GetRequiredProperty<int>("width");
return new Grid
{
@ -158,12 +158,12 @@ public abstract partial class TmjReaderBase
var animation = e.GetOptionalPropertyCustom<List<Frame>>("animation", e => e.GetValueAsList<Frame>(ReadFrame)).GetValueOr([]);
var id = e.GetRequiredProperty<uint>("id");
var image = e.GetOptionalProperty<string>("image");
var imageHeight = e.GetOptionalProperty<uint>("imageheight");
var imageWidth = e.GetOptionalProperty<uint>("imagewidth");
var x = e.GetOptionalProperty<uint>("x").GetValueOr(0);
var y = e.GetOptionalProperty<uint>("y").GetValueOr(0);
var width = e.GetOptionalProperty<uint>("width").GetValueOr(imageWidth.GetValueOr(0));
var height = e.GetOptionalProperty<uint>("height").GetValueOr(imageHeight.GetValueOr(0));
var imageHeight = e.GetOptionalProperty<int>("imageheight");
var imageWidth = e.GetOptionalProperty<int>("imagewidth");
var x = e.GetOptionalProperty<int>("x").GetValueOr(0);
var y = e.GetOptionalProperty<int>("y").GetValueOr(0);
var width = e.GetOptionalProperty<int>("width").GetValueOr(imageWidth.GetValueOr(0));
var height = e.GetOptionalProperty<int>("height").GetValueOr(imageHeight.GetValueOr(0));
var objectGroup = e.GetOptionalPropertyCustom<ObjectLayer>("objectgroup", e => ReadObjectLayer(e));
var probability = e.GetOptionalProperty<float>("probability").GetValueOr(0.0f);
var type = e.GetOptionalProperty<string>("type").GetValueOr("");
@ -171,11 +171,11 @@ public abstract partial class TmjReaderBase
Optional<Image> imageModel = image.HasValue ? new Image
{
Format = Helpers.ParseImageFormatFromSource(image),
Format = Helpers.ParseImageFormatFromSource(image.Value),
Source = image,
Height = imageHeight ?? 0,
Width = imageWidth ?? 0
} : Optional<Image>.Empty;
Height = imageHeight.GetValueOr(0),
Width = imageWidth.GetValueOr(0)
} : Optional.Empty;
return new Tile
{
@ -195,7 +195,7 @@ public abstract partial class TmjReaderBase
internal static Frame ReadFrame(JsonElement element)
{
var duration = element.GetRequiredProperty<uint>("duration");
var duration = element.GetRequiredProperty<int>("duration");
var tileID = element.GetRequiredProperty<uint>("tileid");
return new Frame
@ -229,7 +229,7 @@ public abstract partial class TmjReaderBase
internal WangColor ReadWangColor(JsonElement element)
{
var @class = element.GetOptionalProperty<string>("class").GetValueOr("");
var color = element.GetRequiredPropertyParseable<Color>("color");
var color = element.GetRequiredPropertyParseable<TiledColor>("color");
var name = element.GetRequiredProperty<string>("name");
var probability = element.GetOptionalProperty<float>("probability").GetValueOr(1.0f);
var properties = ResolveAndMergeProperties(@class, element.GetOptionalPropertyCustom("properties", ReadProperties).GetValueOr([]));

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