@@ -24,8 +24,10 @@ import Data.Aeson.Types (Parser, typeMismatch)
2424import qualified Data.ByteString.Lazy.Char8 as C8
2525import Data.Map (Map )
2626import qualified Data.Map as M
27+ import Data.Maybe (fromMaybe )
2728import Data.Text (Text )
2829import Data.Vector (Vector )
30+ import GHC.Exts (fromList , toList )
2931import GHC.Generics (Generic )
3032
3133
@@ -39,11 +41,42 @@ newtype LocalId = LocalId { unLocalId :: Int }
3941 deriving (Ord , Eq , Enum , Num , Generic , Show , FromJSON , ToJSON , FromJSONKey , ToJSONKey )
4042
4143
44+ data XYPair a = XYPair a a
45+
46+ instance FromJSON a => FromJSON (XYPair a ) where
47+ parseJSON (A. Object o) =
48+ XYPair <$> o .: " x"
49+ <*> o .: " y"
50+ parseJSON invalid = typeMismatch " Object" invalid
51+
52+ instance ToJSON a => ToJSON (XYPair a ) where
53+ toJSON (XYPair x y) =
54+ object [ " x" .= x
55+ , " y" .= y
56+ ]
57+
58+ fromXYPair :: XYPair a -> (a , a )
59+ fromXYPair (XYPair x y) = (x, y)
60+
61+ toXYPair :: (a , a ) -> XYPair a
62+ toXYPair (x, y) = XYPair x y
63+
64+ omitNulls :: Value -> Value
65+ omitNulls (A. Object hs) = A. Object
66+ . fromList
67+ . filter ((/= Null ) . snd )
68+ $ toList hs
69+ omitNulls x = x
70+
71+ parseDefault :: FromJSON a => A. Object -> Text -> a -> Parser a
72+ parseDefault o s d = fromMaybe d <$> o .:? s
73+
74+
4275data Object = Object { objectId :: Int
4376 -- ^ Incremental id - unique across all objects
44- , objectWidth :: Int
77+ , objectWidth :: Double
4578 -- ^ Width in pixels. Ignored if using a gid.
46- , objectHeight :: Int
79+ , objectHeight :: Double
4780 -- ^ Height in pixels. Ignored if using a gid.
4881 , objectName :: String
4982 -- ^ String assigned to name field in editor
@@ -53,19 +86,19 @@ data Object = Object { objectId :: Int
5386 -- ^ String key-value pairs
5487 , objectVisible :: Bool
5588 -- ^ Whether object is shown in editor.
56- , objectX :: Int
89+ , objectX :: Double
5790 -- ^ x coordinate in pixels
58- , objectY :: Int
91+ , objectY :: Double
5992 -- ^ y coordinate in pixels
6093 , objectRotation :: Float
6194 -- ^ Angle in degrees clockwise
62- , objectGid :: GlobalId
95+ , objectGid :: Maybe GlobalId
6396 -- ^ GID, only if object comes from a Tilemap
6497 , objectEllipse :: Bool
6598 -- ^ Used to mark an object as an ellipse
66- , objectPolygon :: Vector (Int , Int )
99+ , objectPolygon :: Maybe ( Vector (Double , Double ) )
67100 -- ^ A list of x,y coordinates in pixels
68- , objectPolyline :: Vector (Int , Int )
101+ , objectPolyline :: Maybe ( Vector (Double , Double ) )
69102 -- ^ A list of x,y coordinates in pixels
70103 , objectText :: Map Text Text
71104 -- ^ String key-value pairs
@@ -77,50 +110,51 @@ instance FromJSON Object where
77110 <*> o .: " height"
78111 <*> o .: " name"
79112 <*> o .: " type"
80- <*> o .: " properties"
113+ <*> parseDefault o " properties" M. empty
81114 <*> o .: " visible"
82115 <*> o .: " x"
83116 <*> o .: " y"
84117 <*> o .: " rotation"
85- <*> o .: " gid"
86- <*> o .: " ellipse"
87- <*> o .: " polygon"
88- <*> o .: " polyline"
89- <*> o .: " text"
118+ <*> o .:? " gid"
119+ <*> parseDefault o " ellipse" False
120+ <*> ( fmap . fmap . fmap ) fromXYPair ( o .:? " polygon" )
121+ <*> ( fmap . fmap . fmap ) fromXYPair ( o .:? " polyline" )
122+ <*> parseDefault o " text" M. empty
90123 parseJSON invalid = typeMismatch " Object" invalid
91124
92125instance ToJSON Object where
93- toJSON Object {.. } = object [ " id" .= objectId
94- , " width" .= objectWidth
95- , " height" .= objectHeight
96- , " name" .= objectName
97- , " type" .= objectType
98- , " properties" .= objectProperties
99- , " visible" .= objectVisible
100- , " x" .= objectX
101- , " y" .= objectY
102- , " rotation" .= objectRotation
103- , " gid" .= objectGid
104- , " ellipse" .= objectEllipse
105- , " polygon" .= objectPolygon
106- , " polyline" .= objectPolyline
107- , " text" .= objectText
108- ]
109-
110-
111- data Layer = Layer { layerWidth :: Int
126+ toJSON Object {.. } = omitNulls $
127+ object [ " id" .= objectId
128+ , " width" .= objectWidth
129+ , " height" .= objectHeight
130+ , " name" .= objectName
131+ , " type" .= objectType
132+ , " properties" .= objectProperties
133+ , " visible" .= objectVisible
134+ , " x" .= objectX
135+ , " y" .= objectY
136+ , " rotation" .= objectRotation
137+ , " gid" .= objectGid
138+ , " ellipse" .= objectEllipse
139+ , " polygon" .= (fmap . fmap ) toXYPair objectPolygon
140+ , " polyline" .= (fmap . fmap ) toXYPair objectPolyline
141+ , " text" .= objectText
142+ ]
143+
144+
145+ data Layer = Layer { layerWidth :: Double
112146 -- ^ Column count. Same as map width for fixed-size maps.
113- , layerHeight :: Int
147+ , layerHeight :: Double
114148 -- ^ Row count. Same as map height for fixed-size maps.
115149 , layerName :: String
116150 -- ^ Name assigned to this layer
117151 , layerType :: String
118152 -- ^ “tilelayer”, “objectgroup”, or “imagelayer”
119153 , layerVisible :: Bool
120154 -- ^ Whether layer is shown or hidden in editor
121- , layerX :: Int
155+ , layerX :: Double
122156 -- ^ Horizontal layer offset in tiles. Always 0.
123- , layerY :: Int
157+ , layerY :: Double
124158 -- ^ Vertical layer offset in tiles. Always 0.
125159 , layerData :: Maybe (Vector GlobalId )
126160 -- ^ Array of GIDs. tilelayer only.
@@ -143,26 +177,27 @@ instance FromJSON Layer where
143177 <*> o .: " x"
144178 <*> o .: " y"
145179 <*> (o .: " data" <|> pure Nothing )
146- <*> ( o .: " objects" <|> pure Nothing )
180+ <*> o .:? " objects"
147181 <*> (o .: " properties" <|> pure mempty )
148182 <*> o .: " opacity"
149183 <*> (o .: " draworder" <|> pure " topdown" )
150184 parseJSON invalid = typeMismatch " Layer" invalid
151185
152186instance ToJSON Layer where
153- toJSON Layer {.. } = object [ " width" .= layerWidth
154- , " height" .= layerHeight
155- , " name" .= layerName
156- , " type" .= layerType
157- , " visible" .= layerVisible
158- , " x" .= layerX
159- , " y" .= layerY
160- , " data" .= layerData
161- , " objects" .= layerObjects
162- , " properties" .= layerProperties
163- , " opacity" .= layerOpacity
164- , " draworder" .= layerDraworder
165- ]
187+ toJSON Layer {.. } = omitNulls $
188+ object [ " width" .= layerWidth
189+ , " height" .= layerHeight
190+ , " name" .= layerName
191+ , " type" .= layerType
192+ , " visible" .= layerVisible
193+ , " x" .= layerX
194+ , " y" .= layerY
195+ , " data" .= layerData
196+ , " objects" .= layerObjects
197+ , " properties" .= layerProperties
198+ , " opacity" .= layerOpacity
199+ , " draworder" .= layerDraworder
200+ ]
166201
167202
168203data Terrain = Terrain { terrainName :: String
@@ -313,9 +348,9 @@ data Tiledmap = Tiledmap { tiledmapVersion :: Float
313348 -- ^ Number of tile columns
314349 , tiledmapHeight :: Int
315350 -- ^ Number of tile rows
316- , tiledmapTilewidth :: Int
351+ , tiledmapTilewidth :: Double
317352 -- ^ Map grid width.
318- , tiledmapTileheight :: Int
353+ , tiledmapTileheight :: Double
319354 -- ^ Map grid height.
320355 , tiledmapOrientation :: String
321356 -- ^ Orthogonal, isometric, or staggered
0 commit comments