diff --git a/assets/tilesets/testLoadTileset.tsx b/assets/tilesets/testLoadTileset.tsx
new file mode 100644
index 0000000..6d4eeb9
--- /dev/null
+++ b/assets/tilesets/testLoadTileset.tsx
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/assets/tilesets/testLoadTilesetTile.tsx b/assets/tilesets/testLoadTilesetTile.tsx
new file mode 100644
index 0000000..2867ede
--- /dev/null
+++ b/assets/tilesets/testLoadTilesetTile.tsx
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/go.sum b/go.sum
index 32e3988..e47987d 100644
--- a/go.sum
+++ b/go.sum
@@ -4,10 +4,7 @@ github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
-github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8 h1:hVwzHzIUGRjiF7EcUjqNxk3NCfkPxbDKRdnNE1Rpg0U=
diff --git a/tiled.go b/tiled.go
index 4a912b0..6d1c0f5 100644
--- a/tiled.go
+++ b/tiled.go
@@ -86,3 +86,29 @@ func (l *Loader) LoadFromFile(fileName string) (*Map, error) {
dir := filepath.Dir(fileName)
return l.LoadFromReader(dir, f)
}
+
+// LoadTilesetFromReader loads a .tsx file into a Tileset structure
+func LoadTilesetFromReader(baseDir string, r io.Reader) (*Tileset, error) {
+ d := xml.NewDecoder(r)
+
+ m := &Tileset{
+ baseDir: baseDir,
+ SourceLoaded: true,
+ }
+ if err := d.Decode(m); err != nil {
+ return nil, err
+ }
+
+ return m, nil
+}
+
+// SaveTilesetToWriter saves a Tileset structure into a given writer
+func SaveTilesetToWriter(tileset *Tileset, w io.Writer) error {
+ encoder := xml.NewEncoder(w)
+ encoder.Indent("", " ")
+ return encoder.Encode(tileset)
+}
+
+func b(v bool) *bool {
+ return &v
+}
diff --git a/tiled_test.go b/tiled_test.go
index 5468bce..e4ec294 100644
--- a/tiled_test.go
+++ b/tiled_test.go
@@ -85,12 +85,12 @@ func TestLoadFromFile(t *testing.T) {
// Test ObjectGroups.Visible defaults to true
assert.Len(t, m.ObjectGroups, 1)
assert.Equal(t, uint32(2), m.ObjectGroups[0].ID)
- assert.Equal(t, true, m.ObjectGroups[0].Visible)
+ assert.Equal(t, true, *m.ObjectGroups[0].Visible)
// Test Object.Visible defaults to true
assert.Len(t, m.ObjectGroups[0].Objects, 1)
assert.Equal(t, uint32(2), m.ObjectGroups[0].Objects[0].ID)
- assert.Equal(t, true, m.ObjectGroups[0].Objects[0].Visible)
+ assert.Equal(t, true, *m.ObjectGroups[0].Objects[0].Visible)
}
func TestLoadFromFileError(t *testing.T) {
@@ -197,7 +197,7 @@ func TestFont(t *testing.T) {
assert.Equal(t, false, text.Italic)
assert.Equal(t, false, text.Underline)
assert.Equal(t, false, text.Strikethrough)
- assert.Equal(t, true, text.Kerning)
+ assert.Equal(t, true, *text.Kerning)
assert.Equal(t, "left", text.HAlign)
assert.Equal(t, "top", text.VAlign)
}
diff --git a/tmx_defaults.go b/tmx_defaults.go
index cf20e5a..ef6c684 100644
--- a/tmx_defaults.go
+++ b/tmx_defaults.go
@@ -57,12 +57,12 @@ func (a *aliasMap) SetDefaults() {
// SetDefaults provides default values for Object.
func (a *aliasObject) SetDefaults() {
- a.Visible = true
+ a.Visible = b(true)
}
// SetDefaults provides default values for ObjectGroup.
func (a *aliasObjectGroup) SetDefaults() {
- a.Visible = true
+ a.Visible = b(true)
a.Opacity = 1
}
@@ -70,7 +70,7 @@ func (a *aliasObjectGroup) SetDefaults() {
func (a *aliasText) SetDefaults() {
a.FontFamily = "sans-serif"
a.Size = 16
- a.Kerning = true
+ a.Kerning = b(true)
a.HAlign = "left"
a.VAlign = "top"
a.Color = &HexColor{}
diff --git a/tmx_group.go b/tmx_group.go
index 2d05ae2..fd84537 100644
--- a/tmx_group.go
+++ b/tmx_group.go
@@ -43,7 +43,7 @@ type Group struct {
// Whether the layer is shown (1) or hidden (0). Defaults to 1.
Visible bool `xml:"visible,attr"`
// Custom properties
- Properties Properties `xml:"properties>property"`
+ Properties *Properties `xml:"properties"`
// Map layers
Layers []*Layer `xml:"layer"`
// Map object groups
diff --git a/tmx_image.go b/tmx_image.go
index 933c204..50d1720 100644
--- a/tmx_image.go
+++ b/tmx_image.go
@@ -47,7 +47,7 @@ type ImageLayer struct {
// Whether the layer is shown (1) or hidden (0). Defaults to 1.
Visible bool `xml:"visible,attr"`
// Custom properties
- Properties Properties `xml:"properties>property"`
+ Properties *Properties `xml:"properties"`
// The group image
Image *Image `xml:"image"`
}
@@ -69,16 +69,16 @@ func (l *ImageLayer) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error
// Image source
type Image struct {
// Used for embedded images, in combination with a data child element. Valid values are file extensions like png, gif, jpg, bmp, etc.
- Format string `xml:"format,attr"`
+ Format string `xml:"format,attr,omitempty"`
// The reference to the tileset image file
Source string `xml:"source,attr"`
// Defines a specific color that is treated as transparent (example value: "#FF00FF" for magenta).
// Up until Tiled 0.12, this value is written out without a # but this is planned to change.
- Trans *HexColor `xml:"trans,attr"`
+ Trans *HexColor `xml:"trans,attr,omitempty"`
// The image width in pixels (optional, used for tile index correction when the image changes)
- Width int `xml:"width,attr"`
+ Width int `xml:"width,attr,omitempty"`
// The image height in pixels (optional)
- Height int `xml:"height,attr"`
+ Height int `xml:"height,attr,omitempty"`
// Embedded image content
- Data *Data `xml:"data,attr"`
+ Data *Data `xml:"data,attr,omitempty"`
}
diff --git a/tmx_layer.go b/tmx_layer.go
index 432f7e0..b96216e 100644
--- a/tmx_layer.go
+++ b/tmx_layer.go
@@ -79,7 +79,7 @@ type Layer struct {
// Rendering offset for this layer in pixels. Defaults to 0. (since 0.14)
OffsetY int `xml:"offsety,attr"`
// Custom properties
- Properties Properties `xml:"properties>property"`
+ Properties *Properties `xml:"properties"`
// This is the attribute you'd like to use, not Data. Tile entry at (x,y) is obtained using l.DecodedTiles[y*map.Width+x].
Tiles []*LayerTile
// Data
diff --git a/tmx_map.go b/tmx_map.go
index 7045095..b4e0031 100644
--- a/tmx_map.go
+++ b/tmx_map.go
@@ -79,7 +79,7 @@ type Map struct {
// Stores the next available ID for new objects. This number is stored to prevent reuse of the same ID after objects have been removed. (since 0.11)
NextObjectID uint32 `xml:"nextobjectid,attr"`
// Custom properties
- Properties *Properties `xml:"properties>property"`
+ Properties *Properties `xml:"properties"`
// Map tilesets
Tilesets []*Tileset `xml:"tileset"`
// Map layers
diff --git a/tmx_object.go b/tmx_object.go
index 78c9ded..26fb545 100644
--- a/tmx_object.go
+++ b/tmx_object.go
@@ -40,25 +40,25 @@ type ObjectGroup struct {
// Unique ID of the layer.
// Each layer that added to a map gets a unique id. Even if a layer is deleted,
// no layer ever gets the same ID. Can not be changed in Tiled. (since Tiled 1.2)
- ID uint32 `xml:"id,attr"`
+ ID uint32 `xml:"id,attr,omitempty"`
// The name of the object group.
- Name string `xml:"name,attr"`
+ Name string `xml:"name,attr,omitempty"`
// The color used to display the objects in this group.
- Color *HexColor `xml:"color,attr"`
+ Color *HexColor `xml:"color,attr,omitempty"`
// The opacity of the layer as a value from 0 to 1. Defaults to 1.
- Opacity float32 `xml:"opacity,attr"`
+ Opacity float32 `xml:"opacity,attr,omitempty"`
// Whether the layer is shown (1) or hidden (0). Defaults to 1.
- Visible bool `xml:"visible,attr"`
+ Visible *bool `xml:"visible,attr"`
// Rendering offset for this layer in pixels. Defaults to 0. (since 0.14)
- OffsetX int `xml:"offsetx,attr"`
+ OffsetX int `xml:"offsetx,attr,omitempty"`
// Rendering offset for this layer in pixels. Defaults to 0. (since 0.14)
- OffsetY int `xml:"offsety,attr"`
+ OffsetY int `xml:"offsety,attr,omitempty"`
// Whether the objects are drawn according to the order of appearance ("index") or sorted by their y-coordinate ("topdown"). Defaults to "topdown".
- DrawOrder string `xml:"draworder,attr"`
+ DrawOrder string `xml:"draworder,attr,omitempty"`
// Custom properties
- Properties Properties `xml:"properties>property"`
+ Properties *Properties `xml:"properties,omitempty"`
// Group objects
- Objects []*Object `xml:"object"`
+ Objects []*Object `xml:"object,omitempty"`
}
// DecodeObjectGroup decodes object group data
@@ -94,37 +94,37 @@ func (g *ObjectGroup) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error
type Object struct {
// Unique ID of the object. Each object that is placed on a map gets a unique id. Even if an object was deleted, no object gets the same ID.
// Can not be changed in Tiled Qt. (since Tiled 0.11)
- ID uint32 `xml:"id,attr"`
+ ID uint32 `xml:"id,attr,omitempty"`
// The name of the object. An arbitrary string.
- Name string `xml:"name,attr"`
+ Name string `xml:"name,attr,omitempty"`
// The type of the object. An arbitrary string.
- Type string `xml:"type,attr"`
+ Type string `xml:"type,attr,omitempty"`
// The x coordinate of the object.
- X float64 `xml:"x,attr"`
+ X float64 `xml:"x,attr,omitempty"`
// The y coordinate of the object.
- Y float64 `xml:"y,attr"`
+ Y float64 `xml:"y,attr,omitempty"`
// The width of the object (defaults to 0).
- Width float64 `xml:"width,attr"`
+ Width float64 `xml:"width,attr,omitempty"`
// The height of the object (defaults to 0).
- Height float64 `xml:"height,attr"`
+ Height float64 `xml:"height,attr,omitempty"`
// The rotation of the object in degrees clockwise (defaults to 0). (since 0.10)
- Rotation float64 `xml:"rotation,attr"`
+ Rotation float64 `xml:"rotation,attr,omitempty"`
// An reference to a tile (optional).
- GID uint32 `xml:"gid,attr"`
+ GID uint32 `xml:"gid,attr,omitempty"`
// Whether the object is shown (1) or hidden (0). Defaults to 1. (since 0.9)
- Visible bool `xml:"visible,attr"`
+ Visible *bool `xml:"visible,attr"`
// Custom properties
- Properties Properties `xml:"properties>property"`
+ Properties *Properties `xml:"properties,omitempty"`
// Used to mark an object as an ellipse. The existing x, y, width and height attributes are used to determine the size of the ellipse.
- Ellipses []*Ellipse `xml:"ellipse"`
+ Ellipses []*Ellipse `xml:"ellipse,omitempty"`
// Polygons
- Polygons []*Polygon `xml:"polygon"`
+ Polygons []*Polygon `xml:"polygon,omitempty"`
// Poly lines
- PolyLines []*PolyLine `xml:"polyline"`
+ PolyLines []*PolyLine `xml:"polyline,omitempty"`
// Text
- Text *Text `xml:"text"`
+ Text *Text `xml:"text,omitempty"`
// Template
- TemplateSource string `xml:"template,attr"`
+ TemplateSource string `xml:"template,attr,omitempty"`
TemplateLoaded bool `xml:"-"`
Template *Template
}
@@ -241,31 +241,32 @@ type Text struct {
// The actual text
Text string `xml:",chardata"`
// The font family used (default: "sans-serif")
- FontFamily string `xml:"fontfamily,attr"`
+ FontFamily string `xml:"fontfamily,attr,omitempty"`
// The size of the font in pixels (not using points, because other sizes in the TMX format are also using pixels) (default: 16)
- Size int `xml:"pixelsize,attr"`
+ Size int `xml:"pixelsize,attr,omitempty"`
// Whether word wrapping is enabled (1) or disabled (0). Defaults to 0.
- Wrap bool `xml:"wrap,attr"`
+ Wrap bool `xml:"wrap,attr,omitempty"`
// Color of the text in #AARRGGBB or #RRGGBB format (default: #000000)
- Color *HexColor `xml:"color,attr"`
+ Color *HexColor `xml:"color,attr,omitempty"`
// Whether the font is bold (1) or not (0). Defaults to 0.
- Bold bool `xml:"bold,attr"`
+ Bold bool `xml:"bold,attr,omitempty"`
// Whether the font is italic (1) or not (0). Defaults to 0.
- Italic bool `xml:"italic,attr"`
+ Italic bool `xml:"italic,attr,omitempty"`
// Whether a line should be drawn below the text (1) or not (0). Defaults to 0.
- Underline bool `xml:"underline,attr"`
+ Underline bool `xml:"underline,attr,omitempty"`
// Whether a line should be drawn through the text (1) or not (0). Defaults to 0.
- Strikethrough bool `xml:"strikeout,attr"`
+ Strikethrough bool `xml:"strikeout,attr,omitempty"`
// Whether kerning should be used while rendering the text (1) or not (0). Default to 1.
- Kerning bool `xml:"kerning,attr"`
+ Kerning *bool `xml:"kerning,attr,omitempty"`
// Horizontal alignment of the text within the object (left (default), center, right or justify (since Tiled 1.2.1))
- HAlign string `xml:"halign,attr"`
+ HAlign string `xml:"halign,attr,omitempty"`
// Vertical alignment of the text within the object (top (default), center or bottom)
- VAlign string `xml:"valign,attr"`
+ VAlign string `xml:"valign,attr,omitempty"`
}
// UnmarshalXML decodes a single XML element beginning with the given start element.
func (t *Text) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
+
item := aliasText{}
item.SetDefaults()
diff --git a/tmx_property.go b/tmx_property.go
index 836c930..e4a8aef 100644
--- a/tmx_property.go
+++ b/tmx_property.go
@@ -25,7 +25,9 @@ package tiled
import "strconv"
// Properties wraps any number of custom properties
-type Properties []*Property
+type Properties struct {
+ Property []*Property `xml:"property"`
+}
// Property is used for custom properties
type Property struct {
@@ -43,7 +45,7 @@ type Property struct {
// Get finds all properties by specified name
func (p Properties) Get(name string) []string {
var values []string
- for _, property := range p {
+ for _, property := range p.Property {
if property.Name == name {
values = append(values, property.Value)
}
@@ -54,7 +56,7 @@ func (p Properties) Get(name string) []string {
// GetString finds first string property by specified name
func (p Properties) GetString(name string) string {
var v string
- for _, property := range p {
+ for _, property := range p.Property {
if property.Name == name {
if property.Type == "" {
return property.Value
@@ -68,7 +70,7 @@ func (p Properties) GetString(name string) string {
// GetBool finds first bool property by specified name
func (p Properties) GetBool(name string) bool {
- for _, property := range p {
+ for _, property := range p.Property {
if property.Name == name && property.Type == "boolean" {
return property.Value == "true"
}
@@ -78,7 +80,7 @@ func (p Properties) GetBool(name string) bool {
// GetInt finds first int property by specified name
func (p Properties) GetInt(name string) int {
- for _, property := range p {
+ for _, property := range p.Property {
if property.Name == name && property.Type == "int" {
v, err := strconv.Atoi(property.Value)
if err != nil {
@@ -92,7 +94,7 @@ func (p Properties) GetInt(name string) int {
// GetFloat finds first float property by specified name
func (p Properties) GetFloat(name string) float64 {
- for _, property := range p {
+ for _, property := range p.Property {
if property.Name == name && property.Type == "float" {
v, err := strconv.ParseFloat(property.Value, 64)
if err != nil {
diff --git a/tmx_property_test.go b/tmx_property_test.go
index 074246f..4271ba4 100644
--- a/tmx_property_test.go
+++ b/tmx_property_test.go
@@ -31,25 +31,27 @@ import (
func TestGetProperty(t *testing.T) {
props := Properties{
- {
- Name: "string-name",
- Type: "string",
- Value: "string-value",
- },
- {
- Name: "int-name",
- Type: "int",
- Value: "123",
- },
- {
- Name: "float-name",
- Type: "float",
- Value: "1.23",
- },
- {
- Name: "bool-name",
- Type: "boolean",
- Value: "true",
+ Property: []*Property{
+ {
+ Name: "string-name",
+ Type: "string",
+ Value: "string-value",
+ },
+ {
+ Name: "int-name",
+ Type: "int",
+ Value: "123",
+ },
+ {
+ Name: "float-name",
+ Type: "float",
+ Value: "1.23",
+ },
+ {
+ Name: "bool-name",
+ Type: "boolean",
+ Value: "true",
+ },
},
}
@@ -57,4 +59,5 @@ func TestGetProperty(t *testing.T) {
assert.Equal(t, 123, props.GetInt("int-name"))
assert.Equal(t, 1.23, props.GetFloat("float-name"))
assert.Equal(t, true, props.GetBool("bool-name"))
+
}
diff --git a/tmx_tileset.go b/tmx_tileset.go
index 7f62017..1e2352b 100644
--- a/tmx_tileset.go
+++ b/tmx_tileset.go
@@ -10,43 +10,46 @@ type Tileset struct {
// Base directory
baseDir string
+ // XMLName holds the xml name for this struct
+ XMLName struct{} `xml:"tileset"`
+
// The TMX format version, generally 1.0.
- Version string `xml:"version,attr"`
+ Version string `xml:"version,attr,omitempty"`
// The Tiled version used to generate this file
- TiledVersion string `xml:"tiledversion,attr"`
+ TiledVersion string `xml:"tiledversion,attr,omitempty"`
// The first global tile ID of this tileset (this global ID maps to the first tile in this tileset).
- FirstGID uint32 `xml:"firstgid,attr"`
+ FirstGID uint32 `xml:"firstgid,attr,omitempty"`
// If this tileset is stored in an external TSX (Tile Set XML) file, this attribute refers to that file.
// That TSX file has the same structure as the element described here. (There is the firstgid
// attribute missing and this source attribute is also not there. These two attributes are kept in the
// TMX map, since they are map specific.)
- Source string `xml:"source,attr"`
+ Source string `xml:"source,attr,omitempty"`
// External TSX source loaded.
SourceLoaded bool `xml:"-"`
// The name of this tileset.
- Name string `xml:"name,attr"`
+ Name string `xml:"name,attr,omitempty"`
// The (maximum) width of the tiles in this tileset.
- TileWidth int `xml:"tilewidth,attr"`
+ TileWidth int `xml:"tilewidth,attr,omitempty"`
// The (maximum) height of the tiles in this tileset.
- TileHeight int `xml:"tileheight,attr"`
+ TileHeight int `xml:"tileheight,attr,omitempty"`
// The spacing in pixels between the tiles in this tileset (applies to the tileset image).
- Spacing int `xml:"spacing,attr"`
+ Spacing int `xml:"spacing,attr,omitempty"`
// The margin around the tiles in this tileset (applies to the tileset image).
- Margin int `xml:"margin,attr"`
+ Margin int `xml:"margin,attr,omitempty"`
// The number of tiles in this tileset (since 0.13)
- TileCount int `xml:"tilecount,attr"`
+ TileCount int `xml:"tilecount,attr,omitempty"`
// The number of tile columns in the tileset. For image collection tilesets it is editable and is used when displaying the tileset. (since 0.15)
- Columns int `xml:"columns,attr"`
+ Columns int `xml:"columns,attr,omitempty"`
// Offset in pixels, to be applied when drawing a tile from the related tileset. When not present, no offset is applied.
- TileOffset *TilesetTileOffset `xml:"tileoffset"`
+ TileOffset *TilesetTileOffset `xml:"tileoffset,omitempty"`
// Custom properties
- Properties Properties `xml:"properties>property"`
+ Properties *Properties `xml:"properties,omitempty"`
// Embedded image
- Image *Image `xml:"image"`
+ Image *Image `xml:"image,omitempty"`
// Defines an array of terrain types, which can be referenced from the terrain of the tile element.
- TerrainTypes []*Terrain `xml:"terraintypes>terrain"`
+ TerrainTypes *TerrainTypes `xml:"terraintypes,omitempty"`
// Tiles in tileset
- Tiles []*TilesetTile `xml:"tile"`
+ Tiles []*TilesetTile `xml:"tile,omitempty"`
}
// GetFileFullPath returns path to file relative to tileset file
@@ -62,6 +65,11 @@ type TilesetTileOffset struct {
Y int `xml:"y,attr"`
}
+// TerrainTypes represent a list of Terrains
+type TerrainTypes struct {
+ Terrain []*Terrain
+}
+
// Terrain type
type Terrain struct {
// The name of the terrain type.
@@ -69,7 +77,7 @@ type Terrain struct {
// The local tile-id of the tile that represents the terrain visually.
Tile uint32 `xml:"tile,attr"`
// Custom properties
- Properties Properties `xml:"properties>property"`
+ Properties *Properties `xml:"properties"`
}
// TilesetTile information
@@ -77,21 +85,26 @@ type TilesetTile struct {
// The local tile ID within its tileset.
ID uint32 `xml:"id,attr"`
// The type of the tile. Refers to an object type and is used by tile objects. (optional) (since 1.0)
- Type string `xml:"type,attr"`
+ Type string `xml:"type,attr,omitempty"`
// Defines the terrain type of each corner of the tile, given as comma-separated indexes in the terrain types
// array in the order top-left, top-right, bottom-left, bottom-right.
// Leaving out a value means that corner has no terrain. (optional) (since 0.9)
- Terrain string `xml:"terrain,attr"`
+ Terrain string `xml:"terrain,attr,omitempty"`
// A percentage indicating the probability that this tile is chosen when it competes with others while editing with the terrain tool. (optional) (since 0.9)
- Probability float32 `xml:"probability,attr"`
+ Probability float32 `xml:"probability,attr,omitempty"`
// Custom properties
- Properties Properties `xml:"properties>property"`
+ Properties *Properties `xml:"properties,omitempty"`
// Embedded image
Image *Image `xml:"image"`
// Tile object groups
- ObjectGroups []*ObjectGroup `xml:"objectgroup"`
+ ObjectGroups []*ObjectGroup `xml:"objectgroup,omitempty"`
// List of animation frames
- Animation []*AnimationFrame `xml:"animation>frame"`
+ Animation *Animation `xml:"animation,omitempty"`
+}
+
+// Animation represents a list of AnimationFrames
+type Animation struct {
+ Frame []*AnimationFrame `xml:"frame"`
}
// AnimationFrame is single frame of animation
diff --git a/tmx_tileset_test.go b/tmx_tileset_test.go
index 2a4ea68..b426225 100644
--- a/tmx_tileset_test.go
+++ b/tmx_tileset_test.go
@@ -23,7 +23,12 @@ SOFTWARE.
package tiled
import (
+ "bytes"
+ "encoding/xml"
"image"
+ "io"
+ "os"
+ "path/filepath"
"testing"
"github.com/stretchr/testify/assert"
@@ -165,5 +170,179 @@ func TestGetTileRect(t *testing.T) {
}
})
}
+}
+
+var testLoadTilesetFile = &Tileset{
+ baseDir: ".",
+ Columns: 64,
+ FirstGID: 0,
+ Image: &Image{
+ Format: "",
+ Data: nil,
+ Height: 3040,
+ Width: 2048,
+ Source: "ProjectUtumno_full.png",
+ Trans: nil,
+ },
+ Margin: 0,
+ Name: "ProjectUtumno_full",
+ Properties: nil,
+ Source: "",
+ SourceLoaded: true,
+ Spacing: 0,
+ TerrainTypes: nil,
+ TileCount: 6080,
+ TileHeight: 32,
+ TileOffset: nil,
+ TileWidth: 32,
+ TiledVersion: "1.2.3",
+ Tiles: []*TilesetTile{
+ {
+ ID: 116,
+ Type: "door",
+ Animation: nil,
+ Image: nil,
+ ObjectGroups: nil,
+ Probability: 0,
+ Properties: nil,
+ Terrain: "",
+ },
+ },
+ Version: "1.2",
+}
+
+var testLoadTilesetTileFile = &TilesetTile{
+ ID: 464,
+ Animation: &Animation{
+ Frame: []*AnimationFrame{
+ {
+ Duration: 500,
+ TileID: 75,
+ },
+ {
+ Duration: 500,
+ TileID: 76,
+ },
+ },
+ },
+ Image: nil,
+ ObjectGroups: []*ObjectGroup{
+ {
+ ID: 0,
+ Color: nil,
+ DrawOrder: "index",
+ Name: "",
+ Objects: []*Object{
+ {
+ GID: 0,
+ Ellipses: nil,
+ Height: 6.125,
+ ID: 1,
+ Name: "",
+ PolyLines: nil,
+ Polygons: nil,
+ Properties: nil,
+ Rotation: 0,
+ Text: nil,
+ Type: "",
+ Visible: b(true),
+ Width: 32.375,
+ X: -0.25,
+ Y: 17.75,
+ },
+ },
+ OffsetX: 0,
+ OffsetY: 0,
+ Opacity: 1,
+ Properties: nil,
+ Visible: b(true),
+ },
+ },
+}
+
+func TestLoadTileset(t *testing.T) {
+ tsxFile, err := os.Open(filepath.Join(GetAssetsDirectory(), "tilesets/testLoadTileset.tsx"))
+ assert.Nil(t, err)
+ defer tsxFile.Close()
+
+ tsx, err := LoadTilesetFromReader(".", tsxFile)
+ assert.Nil(t, err)
+ assert.Equal(t, testLoadTilesetFile, tsx)
+}
+
+func TestSaveTileset(t *testing.T) {
+ tsxFile, err := os.Open(filepath.Join(GetAssetsDirectory(), "tilesets/testLoadTileset.tsx"))
+ assert.Nil(t, err)
+ defer tsxFile.Close()
+
+ buffer := &bytes.Buffer{}
+ err = SaveTilesetToWriter(testLoadTilesetFile, buffer)
+ assert.Nil(t, err)
+
+ assertXMLEqual(t, tsxFile, buffer)
+}
+
+func TestLoadTile(t *testing.T) {
+ tsxFile, err := os.Open(filepath.Join(GetAssetsDirectory(), "tilesets/testLoadTilesetTile.tsx"))
+ assert.Nil(t, err)
+ defer tsxFile.Close()
+
+ tsx, err := LoadTilesetFromReader(".", tsxFile)
+ assert.Nil(t, err)
+ assert.Len(t, tsx.Tiles, 1)
+
+ tile := tsx.Tiles[0]
+ assert.Equal(t, testLoadTilesetTileFile, tile)
+}
+
+func TestSaveTile(t *testing.T) {
+ tsxFile, err := os.Open(filepath.Join(GetAssetsDirectory(), "tilesets/testLoadTilesetTile.tsx"))
+ assert.Nil(t, err)
+ defer tsxFile.Close()
+
+ tsx, err := LoadTilesetFromReader(".", tsxFile)
+ assert.Nil(t, err)
+
+ buffer := &bytes.Buffer{}
+ xml.NewEncoder(buffer).Encode(tsx)
+
+ tsxFile.Seek(0, 0)
+ assertXMLEqual(t, tsxFile, buffer)
+
+}
+
+func assertXMLEqual(t *testing.T, expected io.Reader, obtained io.Reader) {
+ var expec node
+ var obt node
+ var err error
+
+ err = xml.NewDecoder(expected).Decode(&expec)
+ assert.Nil(t, err)
+ err = xml.NewDecoder(obtained).Decode(&obt)
+ assert.Nil(t, err)
+
+ assert.Equal(t, expec, obt)
+}
+
+type node struct {
+ XMLName xml.Name
+ Attrs []xml.Attr `xml:",any,attr"`
+ Content string `xml:",innerxml"`
+ Nodes []node `xml:",any"`
+}
+
+func (n *node) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
+ type inNode node
+
+ err := d.DecodeElement((*inNode)(n), &start)
+ if err != nil {
+ return err
+ }
+
+ //Discard content if there are child nodes
+ if len(n.Nodes) > 0 {
+ n.Content = ""
+ }
+ return nil
}