diff --git a/src/DotTiled.Tests/TestData/Maps/map-with-multiline-string-prop/map-with-multiline-string-prop.cs b/src/DotTiled.Tests/TestData/Maps/map-with-multiline-string-prop/map-with-multiline-string-prop.cs new file mode 100644 index 0000000..06fc07f --- /dev/null +++ b/src/DotTiled.Tests/TestData/Maps/map-with-multiline-string-prop/map-with-multiline-string-prop.cs @@ -0,0 +1,65 @@ +using System.Globalization; + +namespace DotTiled.Tests; + +public partial class TestData +{ + public static Map MapWithMultilineStringProp() => new Map + { + Class = "", + Orientation = MapOrientation.Isometric, + Width = 5, + Height = 5, + TileWidth = 32, + TileHeight = 16, + Infinite = false, + ParallaxOriginX = 0, + ParallaxOriginY = 0, + RenderOrder = RenderOrder.RightDown, + CompressionLevel = -1, + BackgroundColor = Color.Parse("#00ff00", CultureInfo.InvariantCulture), + Version = "1.10", + TiledVersion = "1.11.0", + NextLayerID = 2, + NextObjectID = 1, + Layers = [ + new TileLayer + { + ID = 1, + Name = "Tile Layer 1", + Width = 5, + Height = 5, + Data = new Data + { + Encoding = DataEncoding.Csv, + GlobalTileIDs = new Optional([ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0 + ]), + FlippingFlags = new Optional([ + FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, + FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, + FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, + FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, + FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None + ]) + } + } + ], + Properties = + [ + new BoolProperty { Name = "boolprop", Value = true }, + new ColorProperty { Name = "colorprop", Value = Color.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 = "stringmultiline", Value = "hello there\n\ni am a multiline\nstring property" }, + new StringProperty { Name = "stringprop", Value = "This is a string, hello world!" }, + new StringProperty { Name = "unsetstringprop", Value = "" } + ] + }; +} diff --git a/src/DotTiled.Tests/TestData/Maps/map-with-multiline-string-prop/map-with-multiline-string-prop.tmj b/src/DotTiled.Tests/TestData/Maps/map-with-multiline-string-prop/map-with-multiline-string-prop.tmj new file mode 100644 index 0000000..44465f2 --- /dev/null +++ b/src/DotTiled.Tests/TestData/Maps/map-with-multiline-string-prop/map-with-multiline-string-prop.tmj @@ -0,0 +1,80 @@ +{ "backgroundcolor":"#00ff00", + "compressionlevel":-1, + "height":5, + "infinite":false, + "layers":[ + { + "data":[0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0], + "height":5, + "id":1, + "name":"Tile Layer 1", + "opacity":1, + "type":"tilelayer", + "visible":true, + "width":5, + "x":0, + "y":0 + }], + "nextlayerid":2, + "nextobjectid":1, + "orientation":"isometric", + "properties":[ + { + "name":"boolprop", + "type":"bool", + "value":true + }, + { + "name":"colorprop", + "type":"color", + "value":"#ff55ffff" + }, + { + "name":"fileprop", + "type":"file", + "value":"file.txt" + }, + { + "name":"floatprop", + "type":"float", + "value":4.2 + }, + { + "name":"intprop", + "type":"int", + "value":8 + }, + + { + "name":"objectprop", + "type":"object", + "value":5 + }, + { + "name":"stringmultiline", + "type":"string", + "value":"hello there\n\ni am a multiline\nstring property" + }, + { + "name":"stringprop", + "type":"string", + "value":"This is a string, hello world!" + }, + { + "name":"unsetstringprop", + "type":"string", + "value":"" + }], + "renderorder":"right-down", + "tiledversion":"1.11.0", + "tileheight":16, + "tilesets":[], + "tilewidth":32, + "type":"map", + "version":"1.10", + "width":5 +} \ No newline at end of file diff --git a/src/DotTiled.Tests/TestData/Maps/map-with-multiline-string-prop/map-with-multiline-string-prop.tmx b/src/DotTiled.Tests/TestData/Maps/map-with-multiline-string-prop/map-with-multiline-string-prop.tmx new file mode 100644 index 0000000..de55ee1 --- /dev/null +++ b/src/DotTiled.Tests/TestData/Maps/map-with-multiline-string-prop/map-with-multiline-string-prop.tmx @@ -0,0 +1,26 @@ + + + + + + + + + + hello there + +i am a multiline +string property + + + + + +0,0,0,0,0, +0,0,0,0,0, +0,0,0,0,0, +0,0,0,0,0, +0,0,0,0,0 + + + diff --git a/src/DotTiled.Tests/UnitTests/Serialization/TestData.cs b/src/DotTiled.Tests/UnitTests/Serialization/TestData.cs index eb13942..b59622e 100644 --- a/src/DotTiled.Tests/UnitTests/Serialization/TestData.cs +++ b/src/DotTiled.Tests/UnitTests/Serialization/TestData.cs @@ -42,6 +42,7 @@ public static partial class TestData [GetMapPath("map-external-tileset-multi"), (string f) => MapExternalTilesetMulti(f), Array.Empty()], [GetMapPath("map-external-tileset-wangset"), (string f) => MapExternalTilesetWangset(f), Array.Empty()], [GetMapPath("map-with-many-layers"), (string f) => MapWithManyLayers(f), Array.Empty()], + [GetMapPath("map-with-multiline-string-prop"), (string f) => MapWithMultilineStringProp(), Array.Empty()], [GetMapPath("map-with-deep-props"), (string f) => MapWithDeepProps(), MapWithDeepPropsCustomTypeDefinitions()], [GetMapPath("map-with-class"), (string f) => MapWithClass(), MapWithClassCustomTypeDefinitions()], [GetMapPath("map-with-class-and-props"), (string f) => MapWithClassAndProps(), MapWithClassAndPropsCustomTypeDefinitions()], diff --git a/src/DotTiled/Serialization/Tmx/TmxReaderBase.Properties.cs b/src/DotTiled/Serialization/Tmx/TmxReaderBase.Properties.cs index bfdb93d..32b6a5c 100644 --- a/src/DotTiled/Serialization/Tmx/TmxReaderBase.Properties.cs +++ b/src/DotTiled/Serialization/Tmx/TmxReaderBase.Properties.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Linq; using System.Xml; @@ -32,9 +33,14 @@ public abstract partial class TmxReaderBase return ReadPropertyWithCustomType(); } + if (type == PropertyType.String) + { + return ReadStringProperty(name); + } + IProperty property = type switch { - PropertyType.String => new StringProperty { Name = name, Value = r.GetRequiredAttribute("value") }, + PropertyType.String => throw new InvalidOperationException("String properties should be handled elsewhere."), PropertyType.Int => new IntProperty { Name = name, Value = r.GetRequiredAttributeParseable("value") }, PropertyType.Float => new FloatProperty { Name = name, Value = r.GetRequiredAttributeParseable("value") }, PropertyType.Bool => new BoolProperty { Name = name, Value = r.GetRequiredAttributeParseable("value") }, @@ -49,6 +55,25 @@ public abstract partial class TmxReaderBase }); } + internal StringProperty ReadStringProperty(string name) + { + var valueAttrib = _reader.GetOptionalAttribute("value"); + if (valueAttrib.HasValue) + { + return new StringProperty { Name = name, Value = valueAttrib.Value }; + } + + if (!_reader.IsEmptyElement) + { + _reader.ReadStartElement("property"); + var value = _reader.ReadContentAsString(); + _reader.ReadEndElement(); + return new StringProperty { Name = name, Value = value }; + } + + return new StringProperty { Name = name, Value = string.Empty }; + } + internal IProperty ReadPropertyWithCustomType() { var isClass = _reader.GetOptionalAttribute("type") == "class";