Example #1
0
class LuaPlugin(WritableMapFormat):
    def __init__(self):
        super().__init__()

        self.mMapDir = QDir()
        self.mError = ''
        self.mGidMapper = GidMapper()

    # MapWriterInterface
    def write(self, map, fileName):
        file = QSaveFile(fileName)
        if (not file.open(QIODevice.WriteOnly | QIODevice.Text)) :
            self.mError = self.tr("Could not open file for writing.")
            return False
        
        self.mMapDir = QDir(QFileInfo(fileName).path())
        writer = LuaTableWriter(file)
        writer.writeStartDocument()
        self.writeMap(writer, map)
        writer.writeEndDocument()
        if (file.error() != QFile.NoError) :
            self.mError = file.errorString()
            return False
        
        if (not file.commit()) :
            self.mError = file.errorString()
            return False
        return True
    
    def nameFilter(self):
        return self.tr("Lua files (*.lua)")
    
    def errorString(self):
        return self.mError

    def writeMap(self, writer, map):
        writer.writeStartReturnTable()
        writer.writeKeyAndValue("version", "1.1")
        writer.writeKeyAndValue("luaversion", "5.1")
        writer.writeKeyAndValue("tiledversion", QCoreApplication.applicationVersion())
        orientation = orientationToString(map.orientation())
        renderOrder = renderOrderToString(map.renderOrder())
        writer.writeKeyAndValue("orientation", orientation)
        writer.writeKeyAndValue("renderorder", renderOrder)
        writer.writeKeyAndValue("width", map.width())
        writer.writeKeyAndValue("height", map.height())
        writer.writeKeyAndValue("tilewidth", map.tileWidth())
        writer.writeKeyAndValue("tileheight", map.tileHeight())
        writer.writeKeyAndValue("nextobjectid", map.nextObjectId())
        if (map.orientation() == Map.Orientation.Hexagonal):
            writer.writeKeyAndValue("hexsidelength", map.hexSideLength())
        if (map.orientation() == Map.Orientation.Staggered or map.orientation() == Map.Orientation.Hexagonal) :
            writer.writeKeyAndValue("staggeraxis", staggerAxisToString(map.staggerAxis()))
            writer.writeKeyAndValue("staggerindex", staggerIndexToString(map.staggerIndex()))
        
        backgroundColor = map.backgroundColor()
        if (backgroundColor.isValid()) :
            # Example: backgroundcolor = { 255, 200, 100 }
            writer.writeStartTable("backgroundcolor")
            writer.setSuppressNewlines(True)
            writer.writeValue(backgroundColor.red())
            writer.writeValue(backgroundColor.green())
            writer.writeValue(backgroundColor.blue())
            if (backgroundColor.alpha() != 255):
                writer.writeValue(backgroundColor.alpha())
            writer.writeEndTable()
            writer.setSuppressNewlines(False)
        
        self.writeProperties(writer, map.properties())
        writer.writeStartTable("tilesets")
        self.mGidMapper.clear()
        firstGid = 1
        for tileset in map.tilesets():
            self.writeTileset(writer, tileset, firstGid)
            self.mGidMapper.insert(firstGid, tileset)
            firstGid += tileset.tileCount()
        
        writer.writeEndTable()
        writer.writeStartTable("layers")
        for layer in map.layers():
            x = layer.layerType()
            if x==Layer.TileLayerType:
                self.writeTileLayer(writer, layer, map.layerDataFormat())
            elif x==Layer.ObjectGroupType:
                self.writeObjectGroup(writer, layer)
            elif x==Layer.ImageLayerType:
                self.writeImageLayer(writer, layer)

        writer.writeEndTable()
        writer.writeEndTable()
    
    def writeProperties(self, writer, properties):
        writer.writeStartTable("properties")
        for it in properties:
            writer.writeQuotedKeyAndValue(it[0], it[1])
        writer.writeEndTable()

    def writeTileset(self, writer, tileset, firstGid):
        writer.writeStartTable()
        writer.writeKeyAndValue("name", tileset.name())
        writer.writeKeyAndValue("firstgid", firstGid)
        if tileset.fileName() != '':
            rel = self.mMapDir.relativeFilePath(tileset.fileName())
            writer.writeKeyAndValue("filename", rel)
        
        ## 
        # Include all tileset information even for external tilesets, since the
        # external reference is generally a .tsx file (in XML format).
        ##
        writer.writeKeyAndValue("tilewidth", tileset.tileWidth())
        writer.writeKeyAndValue("tileheight", tileset.tileHeight())
        writer.writeKeyAndValue("spacing", tileset.tileSpacing())
        writer.writeKeyAndValue("margin", tileset.margin())
        if tileset.imageSource() != '':
            rel = self.mMapDir.relativeFilePath(tileset.imageSource())
            writer.writeKeyAndValue("image", rel)
            writer.writeKeyAndValue("imagewidth", tileset.imageWidth())
            writer.writeKeyAndValue("imageheight", tileset.imageHeight())
        
        if (tileset.transparentColor().isValid()):
            writer.writeKeyAndValue("transparentcolor",tileset.transparentColor().name())

        offset = tileset.tileOffset()
        writer.writeStartTable("tileoffset")
        writer.writeKeyAndValue("x", offset.x())
        writer.writeKeyAndValue("y", offset.y())
        writer.writeEndTable()
        self.writeProperties(writer, tileset.properties())
        writer.writeStartTable("terrains")
        for i in range(tileset.terrainCount()):
            t = tileset.terrain(i)
            writer.writeStartTable()
            writer.writeKeyAndValue("name", t.name())
            writer.writeKeyAndValue("tile", t.imageTileId())
            self.writeProperties(writer, t.properties())
            writer.writeEndTable()

        writer.writeEndTable()
        writer.writeKeyAndValue("tilecount", tileset.tileCount())
        writer.writeStartTable("tiles")
        for i in range(0, tileset.tileCount()):
            tile = tileset.tileAt(i)
            # For brevity only write tiles with interesting properties
            if (not includeTile(tile)):
                continue
            writer.writeStartTable()
            writer.writeKeyAndValue("id", i)
            if (not tile.properties().isEmpty()):
                self.writeProperties(writer, tile.properties())
            if tile.imageSource() != '':
                src = self.mMapDir.relativeFilePath(tile.imageSource())
                tileSize = tile.size()
                writer.writeKeyAndValue("image", src)
                if (not tileSize.isNull()) :
                    writer.writeKeyAndValue("width", tileSize.width())
                    writer.writeKeyAndValue("height", tileSize.height())

            terrain = tile.terrain()
            if (terrain != 0xFFFFFFFF) :
                writer.writeStartTable("terrain")
                writer.setSuppressNewlines(True)
                for i in range(0, 4):
                    writer.writeValue(tile.cornerTerrainId(i))
                writer.writeEndTable()
                writer.setSuppressNewlines(False)
            
            if (tile.probability() != 1.0):
                writer.writeKeyAndValue("probability", tile.probability())
            objectGroup = tile.objectGroup()
            if objectGroup:
                self.writeObjectGroup(writer, objectGroup, "objectGroup")
            if (tile.isAnimated()) :
                frames = tile.frames()
                writer.writeStartTable("animation")
                for frame in frames:
                    writer.writeStartTable()
                    writer.writeKeyAndValue("tileid", QString.number(frame.tileId))
                    writer.writeKeyAndValue("duration", QString.number(frame.duration))
                    writer.writeEndTable()
                
                writer.writeEndTable() # animation
            
            writer.writeEndTable() # tile
        
        writer.writeEndTable() # tiles
        writer.writeEndTable() # tileset
    
    def writeTileLayer(self, writer, tileLayer, format):
        writer.writeStartTable()
        writer.writeKeyAndValue("type", "tilelayer")
        writer.writeKeyAndValue("name", tileLayer.name())
        writer.writeKeyAndValue("x", tileLayer.x())
        writer.writeKeyAndValue("y", tileLayer.y())
        writer.writeKeyAndValue("width", tileLayer.width())
        writer.writeKeyAndValue("height", tileLayer.height())
        writer.writeKeyAndValue("visible", tileLayer.isVisible())
        writer.writeKeyAndValue("opacity", tileLayer.opacity())
        offset = tileLayer.offset()
        writer.writeKeyAndValue("offsetx", offset.x())
        writer.writeKeyAndValue("offsety", offset.y())

        if format==Map.LayerDataFormat.XML or format==Map.LayerDataFormat.CSV:
            self.writeProperties(writer, tileLayer.properties())
            writer.writeKeyAndValue("encoding", "lua")
            writer.writeStartTable("data")
            for y in range(0, tileLayer.height()):
                if (y > 0):
                    writer.prepareNewLine()
                for x in range(0, tileLayer.width()):
                    writer.writeValue(self.mGidMapper.cellToGid(tileLayer.cellAt(x, y)))
        elif format==Map.LayerDataFormat.Base64 \
            or format==Map.LayerDataFormat.Base64Zlib \
            or format==Map.LayerDataFormat.Base64Gzip:
            writer.writeKeyAndValue("encoding", "base64")

            if format == Map.LayerDataFormat.Base64Zlib:
                writer.writeKeyAndValue("compression", "zlib")
            elif format == Map.LayerDataFormat.Base64Gzip:
                writer.writeKeyAndValue("compression", "gzip")

            layerData = self.mGidMapper.encodeLayerData(tileLayer, format)
            writer.writeKeyAndValue("data", layerData)

        writer.writeEndTable()
        writer.writeEndTable()
    
    def writeObjectGroup(self, writer, objectGroup, key=QByteArray()):
        if key=='':
            writer.writeStartTable()
        else:
            writer.writeStartTable(key)
        writer.writeKeyAndValue("type", "objectgroup")
        writer.writeKeyAndValue("name", objectGroup.name())
        writer.writeKeyAndValue("visible", objectGroup.isVisible())
        writer.writeKeyAndValue("opacity", objectGroup.opacity())
        
        offset = objectGroup.offset()
        writer.writeKeyAndValue("offsetx", offset.x())
        writer.writeKeyAndValue("offsety", offset.y())

        self.writeProperties(writer, objectGroup.properties())
        writer.writeStartTable("objects")
        for mapObject in objectGroup.objects():
            self.writeMapObject(writer, mapObject)
        writer.writeEndTable()
        writer.writeEndTable()
    
    def writeImageLayer(self, writer, imageLayer):
        writer.writeStartTable()
        writer.writeKeyAndValue("type", "imagelayer")
        writer.writeKeyAndValue("name", imageLayer.name())
        writer.writeKeyAndValue("x", imageLayer.x())
        writer.writeKeyAndValue("y", imageLayer.y())
        writer.writeKeyAndValue("visible", imageLayer.isVisible())
        writer.writeKeyAndValue("opacity", imageLayer.opacity())
        rel = self.mMapDir.relativeFilePath(imageLayer.imageSource())
        writer.writeKeyAndValue("image", rel)
        if (imageLayer.transparentColor().isValid()) :
            writer.writeKeyAndValue("transparentcolor",
                                    imageLayer.transparentColor().name())
        
        self.writeProperties(writer, imageLayer.properties())
        writer.writeEndTable()
    
    def writeMapObject(self, writer, mapObject):
        writer.writeStartTable()
        writer.writeKeyAndValue("id", mapObject.id())
        writer.writeKeyAndValue("name", mapObject.name())
        writer.writeKeyAndValue("type", mapObject.type())
        writer.writeKeyAndValue("shape", toString(mapObject.shape()))
        writer.writeKeyAndValue("x", mapObject.x())
        writer.writeKeyAndValue("y", mapObject.y())
        writer.writeKeyAndValue("width", mapObject.width())
        writer.writeKeyAndValue("height", mapObject.height())
        writer.writeKeyAndValue("rotation", mapObject.rotation())
        if (not mapObject.cell().isEmpty()):
            writer.writeKeyAndValue("gid", self.mGidMapper.cellToGid(mapObject.cell()))
        writer.writeKeyAndValue("visible", mapObject.isVisible())
        polygon = mapObject.polygon()
        if (not polygon.isEmpty()) :
            if (mapObject.shape() == MapObject.Polygon):
                writer.writeStartTable("polygon")
            else:
                writer.writeStartTable("polyline")
    #if defined(POLYGON_FORMAT_FULL)
            ## This format is the easiest to read and understand:
            #
            #  :
            #    { x = 1, y = 1 },
            #    { x = 2, y = 2 },
            #    { x = 3, y = 3 },
            #    ...
            #  }
            ##
            for point in polygon:
                writer.writeStartTable()
                writer.setSuppressNewlines(True)
                writer.writeKeyAndValue("x", point.x())
                writer.writeKeyAndValue("y", point.y())
                writer.writeEndTable()
                writer.setSuppressNewlines(False)
            
    #elif defined(POLYGON_FORMAT_PAIRS)
            ## This is an alternative that takes about 25% less memory.
            #
            #  :
            #    { 1, 1 },
            #    { 2, 2 },
            #    { 3, 3 },
            #    ...
            #  }
            ##
            for point in polygon:
                writer.writeStartTable()
                writer.setSuppressNewlines(True)
                writer.writeValue(point.x())
                writer.writeValue(point.y())
                writer.writeEndTable()
                writer.setSuppressNewlines(False)
            
    #elif defined(POLYGON_FORMAT_OPTIMAL)
            ## Writing it out in two tables, one for the x coordinates and one for
            # the y coordinates. It is a compromise between code readability and # performance. This takes the least amount of memory (60% less than
            # the first approach).
            #
            # x = { 1, 2, 3, ... }
            # y = { 1, 2, 3, ... }
            ##
            writer.writeStartTable("x")
            writer.setSuppressNewlines(True)
            for point in polygon:
                writer.writeValue(point.x())
            writer.writeEndTable()
            writer.setSuppressNewlines(False)
            writer.writeStartTable("y")
            writer.setSuppressNewlines(True)
            for point in polygon:
                writer.writeValue(point.y())
            writer.writeEndTable()
            writer.setSuppressNewlines(False)
    #endif
            writer.writeEndTable()
        
        self.writeProperties(writer, mapObject.properties())
        writer.writeEndTable()
Example #2
0
class MapToVariantConverter():

    def __init__(self):
        pass
        self.mMapDir = QDir()
        self.mGidMapper = GidMapper()
        
    def toVariant(self, arg1, arg2):
        tp1 = type(arg1)
        tp2 = type(arg2)
        if tp1==Map and tp2==QDir:
            ##
            # Converts the given \s map to a QVariant. The \a mapDir is used to
            # construct relative paths to external resources.
            ##
            map, mapDir = arg1, arg2
            self.mMapDir = mapDir
            self.mGidMapper.clear()
            mapVariant = {}
            mapVariant["version"] = 1.0
            mapVariant["orientation"] = orientationToString(map.orientation())
            mapVariant["renderorder"] = renderOrderToString(map.renderOrder())
            mapVariant["width"] = map.width()
            mapVariant["height"] = map.height()
            mapVariant["tilewidth"] = map.tileWidth()
            mapVariant["tileheight"] = map.tileHeight()
            mapVariant["properties"] = self.__toVariant(map.properties())
            mapVariant["nextobjectid"] = map.nextObjectId()
            if (map.orientation() == Map.Orientation.Hexagonal) :
                mapVariant["hexsidelength"] = map.hexSideLength()
            
            if (map.orientation() == Map.Orientation.Hexagonal or map.orientation() == Map.Orientation.Staggered) :
                mapVariant["staggeraxis"] = staggerAxisToString(map.staggerAxis())
                mapVariant["staggerindex"] = staggerIndexToString(map.staggerIndex())
            
            bgColor = map.backgroundColor()
            if (bgColor.isValid()):
                mapVariant["backgroundcolor"] = bgColor.name()
            tilesetVariants = []
            firstGid = 1
            for tileset in map.tilesets():
                tilesetVariants.append(self.__toVariant(tileset, firstGid))
                self.mGidMapper.insert(firstGid, tileset)
                firstGid += tileset.tileCount()
            
            mapVariant["tilesets"] = tilesetVariants
            layerVariants = []
            for layer in map.layers():
                x = layer.layerType()
                if x==Layer.TileLayerType:
                    layerVariants.append(self.__toVariant(layer, map.layerDataFormat()))
                elif x==Layer.ObjectGroupType:
                    layerVariants.append(self.__toVariant(layer))
                elif x==Layer.ImageLayerType:
                    layerVariants.append(self.__toVariant(layer))
            
            mapVariant["layers"] = layerVariants
            return mapVariant
        elif tp1==Tileset and tp2==QDir:
            ##
            # Converts the given \s tileset to a QVariant. The \a directory is used to
            # construct relative paths to external resources.
            ##
            tileset, directory = arg1, arg2
            self.mMapDir = directory
            return self.__toVariant(tileset, 0)
        
    def __toVariant(self, *args):
        l = len(args)
        if l==1:
            arg = args[0]
            tp = type(arg)
            if tp == Properties:
                properties = arg
                variantMap = {}
                for it in properties:
                    variantMap[it[0]] = it[1]
                return variantMap
            elif tp == ObjectGroup:
                objectGroup = arg
                objectGroupVariant = {}
                objectGroupVariant["type"] = "objectgroup"
                if (objectGroup.color().isValid()):
                    objectGroupVariant["color"] = objectGroup.color().name()
                objectGroupVariant["draworder"] = drawOrderToString(objectGroup.drawOrder())
                self.addLayerAttributes(objectGroupVariant, objectGroup)
                objectVariants = []
                for object in objectGroup.objects():
                    objectVariant = {}
                    name = object.name()
                    _type = object.type()
                    objectVariant["properties"] = self.__toVariant(object.properties())
                    objectVariant["id"] = object.id()
                    objectVariant["name"] = name
                    objectVariant["type"] = _type
                    if (not object.cell().isEmpty()):
                        objectVariant["gid"] = self.mGidMapper.cellToGid(object.cell())
                    objectVariant["x"] = object.x()
                    objectVariant["y"] = object.y()
                    objectVariant["width"] = object.width()
                    objectVariant["height"] = object.height()
                    objectVariant["rotation"] = object.rotation()
                    objectVariant["visible"] = object.isVisible()
                    ## Polygons are stored in this format:
                    #
                    #   "polygon/polyline": [
                    #       { "x": 0, "y": 0 },
                    #       { "x": 1, "y": 1 },
                    #       ...
                    #   ]
                    ##
                    polygon = object.polygon()
                    if (not polygon.isEmpty()) :
                        pointVariants = []
                        for point in polygon:
                            pointVariant = {}
                            pointVariant["x"] = point.x()
                            pointVariant["y"] = point.y()
                            pointVariants.append(pointVariant)
                        
                        if (object.shape() == MapObject.Polygon):
                            objectVariant["polygon"] = pointVariants
                        else:
                            objectVariant["polyline"] = pointVariants
                    
                    if (object.shape() == MapObject.Ellipse):
                        objectVariant["ellipse"] = True
                    objectVariants.append(objectVariant)
                
                objectGroupVariant["objects"] = objectVariants
                return objectGroupVariant
            elif tp == ImageLayer:
                imageLayer = arg
                imageLayerVariant = {}
                imageLayerVariant["type"] = "imagelayer"
                self.addLayerAttributes(imageLayerVariant, imageLayer)
                rel = self.mMapDir.relativeFilePath(imageLayer.imageSource())
                imageLayerVariant["image"] = rel
                transColor = imageLayer.transparentColor()
                if (transColor.isValid()):
                    imageLayerVariant["transparentcolor"] = transColor.name()
                return imageLayerVariant
        elif l==2:
            arg1, arg2 = args
            tp1 = type(arg1)
            tp2 = type(arg2)
            if tp1==Tileset and tp2==int:
                tileset, firstGid = arg1, arg2
                tilesetVariant = {}
                
                if firstGid > 0:
                    tilesetVariant["firstgid"] = firstGid

                fileName = tileset.fileName()
                if fileName != '':
                    source = self.mMapDir.relativeFilePath(fileName)
                    tilesetVariant["source"] = source
                    # Tileset is external, so no need to write any of the stuff below
                    return tilesetVariant
                
                tilesetVariant["firstgid"] = firstGid
                tilesetVariant["name"] = tileset.name()
                tilesetVariant["tilewidth"] = tileset.tileWidth()
                tilesetVariant["tileheight"] = tileset.tileHeight()
                tilesetVariant["spacing"] = tileset.tileSpacing()
                tilesetVariant["margin"] = tileset.margin()
                tilesetVariant["tilecount"] = tileset.tileCount()
                tilesetVariant["properties"] = self.__toVariant(tileset.properties())
                offset = tileset.tileOffset()
                if (not offset.isNull()) :
                    tileOffset = {}
                    tileOffset["x"] = offset.x()
                    tileOffset["y"] = offset.y()
                    tilesetVariant["tileoffset"] = tileOffset
                
                # Write the image element
                imageSource = tileset.imageSource()
                if imageSource != '':
                    rel = self.mMapDir.relativeFilePath(tileset.imageSource())
                    tilesetVariant["image"] = rel
                    transColor = tileset.transparentColor()
                    if (transColor.isValid()):
                        tilesetVariant["transparentcolor"] = transColor.name()
                    tilesetVariant["imagewidth"] = tileset.imageWidth()
                    tilesetVariant["imageheight"] = tileset.imageHeight()
                
                ##
                # Write the properties, terrain, external image, object group and
                # animation for those tiles that have them.
                ##
                tilePropertiesVariant = {}
                tilesVariant = {}
                for i in range(0, tileset.tileCount()):
                    tile = tileset.tileAt(i)
                    properties = tile.properties()
                    if (not properties.isEmpty()):
                        tilePropertiesVariant[QString.number(i)] = self.__toVariant(properties)
                    tileVariant = {}
                    if (tile.terrain() != 0xFFFFFFFF) :
                        terrainIds = []
                        for j in range(0, 4):
                            terrainIds.append(tile.cornerTerrainId(j))
                        tileVariant["terrain"] = terrainIds
                    
                    if (tile.probability() != 1.0):
                        tileVariant["probability"] = tile.probability()
                    if tile.imageSource() != '':
                        rel = self.mMapDir.relativeFilePath(tile.imageSource())
                        tileVariant["image"] = rel
                    
                    if (tile.objectGroup()):
                        tileVariant["objectgroup"] = self.__toVariant(tile.objectGroup())
                    if (tile.isAnimated()) :
                        frameVariants = []
                        for frame in tile.frames():
                            frameVariant = {}
                            frameVariant["tileid"] = frame.tileId
                            frameVariant["duration"] = frame.duration
                            frameVariants.append(frameVariant)
                        
                        tileVariant["animation"] = frameVariants
                    
                    if len(tileVariant) > 0:
                        tilesVariant[QString.number(i)] = tileVariant
                
                if len(tilePropertiesVariant) > 0:
                    tilesetVariant["tileproperties"] = tilePropertiesVariant
                if len(tilesVariant) > 0:
                    tilesetVariant["tiles"] = tilesVariant
                # Write terrains
                if (tileset.terrainCount() > 0) :
                    terrainsVariant = []
                    for i in range(0, tileset.terrainCount()):
                        terrain = tileset.terrain(i)
                        properties = terrain.properties()
                        terrainVariant = {}
                        terrainVariant["name"] = terrain.name()
                        if (not properties.isEmpty()):
                            terrainVariant["properties"] = self.__toVariant(properties)
                        terrainVariant["tile"] = terrain.imageTileId()
                        terrainsVariant.append(terrainVariant)
                    
                    tilesetVariant["terrains"] = terrainsVariant
                
                return tilesetVariant
            elif tp1==TileLayer and tp2==Map.LayerDataFormat:
                tileLayer, format = arg1, arg2
                tileLayerVariant = {}
                tileLayerVariant["type"] = "tilelayer"
                self.addLayerAttributes(tileLayerVariant, tileLayer)
                
                if format == Map.LayerDataFormat.XML or format == Map.LayerDataFormat.CSV:
                    tileVariants = []
                    for y in range(tileLayer.height()):
                        for x in range(tileLayer.width()):
                            tileVariants.append(self.mGidMapper.cellToGid(tileLayer.cellAt(x, y)))
                    tileLayerVariant["data"] = tileVariants
                elif format in [Map.LayerDataFormat.Base64, Map.LayerDataFormat.Base64Zlib, Map.LayerDataFormat.Base64Gzip]:
                    tileLayerVariant["encoding"] = "base64"

                    if format == Map.LayerDataFormat.Base64Zlib:
                        tileLayerVariant["compression"] = "zlib"
                    elif format == Map.LayerDataFormat.Base64Gzip:
                        tileLayerVariant["compression"] = "gzip"

                    layerData = self.mGidMapper.encodeLayerData(tileLayer, format)
                    tileLayerVariant["data"] = layerData.data().decode()
                    
                return tileLayerVariant
                
    def addLayerAttributes(self, layerVariant, layer):
        layerVariant["name"] = layer.name()
        layerVariant["width"] = layer.width()
        layerVariant["height"] = layer.height()
        layerVariant["x"] = layer.x()
        layerVariant["y"] = layer.y()
        layerVariant["visible"] = layer.isVisible()
        layerVariant["opacity"] = layer.opacity()
        offset = layer.offset()
        if not offset.isNull():
            layerVariant["offsetx"] = offset.x()
            layerVariant["offsety"] = offset.y()

        properties = layer.properties()
        if (not properties.isEmpty()):
            layerVariant["properties"] = self.__toVariant(properties)
Example #3
0
class MapWriterPrivate():

    def tr(self, sourceText, disambiguation = '', n = -1):
        return QCoreApplication.translate('MapWriter', sourceText, disambiguation, n)

    def trUtf8(self, sourceText, disambiguation = '', n = -1):
        return QCoreApplication.translate('MapWriter', sourceText, disambiguation, n)

    def __init__(self):
        self.mLayerDataFormat = Map.LayerDataFormat.Base64Zlib
        self.mDtdEnabled = False
        self.mUseAbsolutePaths = False

        self.mMapDir = QDir()
        self.mGidMapper = GidMapper()
        self.mError = ''

    def writeMap(self, map, device, path):
        self.mMapDir = QDir(path)
        self.mUseAbsolutePaths = path==''
        self.mLayerDataFormat = map.layerDataFormat()
        writer = createWriter(device)
        writer.writeStartDocument()
        if (self.mDtdEnabled):
            writer.writeDTD("<not DOCTYPE map SYSTEM \"http://mapeditor.org/dtd/1.0/map.dtd\">")

        self.__writeMap(writer, map)
        writer.writeEndDocument()
        del writer

    def writeTileset(self, tileset, device, path):
        self.mMapDir = QDir(path)
        self.mUseAbsolutePaths = path==''
        writer = createWriter(device)
        writer.writeStartDocument()
        if (self.mDtdEnabled):
            writer.writeDTD("<not DOCTYPE tileset SYSTEM \"http://mapeditor.org/dtd/1.0/map.dtd\">")

        self.__writeTileset(writer, tileset, 0)
        writer.writeEndDocument()
        del writer

    def openFile(self, file):
        if (not file.open(QIODevice.WriteOnly | QIODevice.Text)):
            self.mError = self.tr("Could not open file for writing.")
            return False

        return True

    def __writeMap(self, w, map):
        w.writeStartElement("map")
        orientation = orientationToString(map.orientation())
        renderOrder = renderOrderToString(map.renderOrder())
        w.writeAttribute("version", "1.0")
        w.writeAttribute("orientation", orientation)
        w.writeAttribute("renderorder", renderOrder)
        w.writeAttribute("width", str(map.width()))
        w.writeAttribute("height", str(map.height()))
        w.writeAttribute("tilewidth", str(map.tileWidth()))
        w.writeAttribute("tileheight", str(map.tileHeight()))
        if (map.orientation() == Map.Orientation.Hexagonal):
            w.writeAttribute("hexsidelength", str(map.hexSideLength()))

        if (map.orientation() == Map.Orientation.Staggered or map.orientation() == Map.Orientation.Hexagonal):
            w.writeAttribute("staggeraxis", staggerAxisToString(map.staggerAxis()))
            w.writeAttribute("staggerindex", staggerIndexToString(map.staggerIndex()))

        if (map.backgroundColor().isValid()):
            w.writeAttribute("backgroundcolor", map.backgroundColor().name())

        w.writeAttribute("nextobjectid", str(map.nextObjectId()))
        self.__writeProperties(w, map.properties())
        self.mGidMapper.clear()
        firstGid = 1
        for tileset in map.tilesets():
            self.__writeTileset(w, tileset, firstGid)
            self.mGidMapper.insert(firstGid, tileset)
            firstGid += tileset.tileCount()

        for layer in map.layers():
            type = layer.layerType()
            if (type == Layer.TileLayerType):
                self.__writeTileLayer(w, layer)
            elif (type == Layer.ObjectGroupType):
                self.__writeObjectGroup(w, layer)
            elif (type == Layer.ImageLayerType):
                self.__writeImageLayer(w, layer)

        w.writeEndElement()

    def __writeTileset(self, w, tileset, firstGid):
        w.writeStartElement("tileset")
        if (firstGid > 0):
            w.writeAttribute("firstgid", str(firstGid))
        fileName = tileset.fileName()
        if fileName != '':
            source = fileName
            if (not self.mUseAbsolutePaths):
                source = self.mMapDir.relativeFilePath(source)
            w.writeAttribute("source", source)
            # Tileset is external, so no need to write any of the stuff below
            w.writeEndElement()
            return

        w.writeAttribute("name", tileset.name())
        w.writeAttribute("tilewidth", str(tileset.tileWidth()))
        w.writeAttribute("tileheight", str(tileset.tileHeight()))
        tileSpacing = tileset.tileSpacing()
        margin = tileset.margin()
        if (tileSpacing != 0):
            w.writeAttribute("spacing",
                             str(tileSpacing))
        if (margin != 0):
            w.writeAttribute("margin", str(margin))
        
        w.writeAttribute("tilecount", str(tileset.tileCount()))
                     
        offset = tileset.tileOffset()
        if (not offset.isNull()):
            w.writeStartElement("tileoffset")
            w.writeAttribute("x", str(offset.x()))
            w.writeAttribute("y", str(offset.y()))
            w.writeEndElement()

        # Write the tileset properties
        self.__writeProperties(w, tileset.properties())
        # Write the image element
        imageSource = tileset.imageSource()
        if imageSource != '':
            w.writeStartElement("image")
            source = imageSource
            if (not self.mUseAbsolutePaths):
                source = self.mMapDir.relativeFilePath(source)
            w.writeAttribute("source", source)
            transColor = tileset.transparentColor()
            if (transColor.isValid()):
                w.writeAttribute("trans", transColor.name()[1])
            if (tileset.imageWidth() > 0):
                w.writeAttribute("width",
                                 str(tileset.imageWidth()))
            if (tileset.imageHeight() > 0):
                w.writeAttribute("height",
                                 str(tileset.imageHeight()))
            w.writeEndElement()

        # Write the terrain types
        if (tileset.terrainCount() > 0):
            w.writeStartElement("terraintypes")
            for i in range(tileset.terrainCount()):
                t = tileset.terrain(i)
                w.writeStartElement("terrain")
                w.writeAttribute("name", t.name())
                w.writeAttribute("tile", str(t.imageTileId()))
                self.__writeProperties(w, t.properties())
                w.writeEndElement()

            w.writeEndElement()

        # Write the properties for those tiles that have them
        for i in range(tileset.tileCount()):
            tile = tileset.tileAt(i)
            properties = tile.properties()
            terrain = tile.terrain()
            probability = tile.probability()
            objectGroup = tile.objectGroup()
            if (not properties.isEmpty() or terrain != 0xFFFFFFFF or probability != 1.0 or imageSource=='' or objectGroup or tile.isAnimated()):
                w.writeStartElement("tile")
                w.writeAttribute("id", str(i))
                if (terrain != 0xFFFFFFFF):
                    w.writeAttribute("terrain", makeTerrainAttribute(tile))
                if (probability != 1.0):
                    w.writeAttribute("probability", str(probability))
                if (not properties.isEmpty()):
                    self.__writeProperties(w, properties)
                if imageSource=='':
                    w.writeStartElement("image")
                    tileSize = tile.size()
                    if (not tileSize.isNull()):
                        w.writeAttribute("width",
                                         str(tileSize.width()))
                        w.writeAttribute("height",
                                         str(tileSize.height()))

                    if (tile.imageSource()==''):
                        w.writeAttribute("format",
                                         "png")
                        w.writeStartElement("data")
                        w.writeAttribute("encoding",
                                         "base64")
                        buffer = QBuffer()
                        tile.image().save(buffer, "png")
                        w.writeCharacters(buffer.data().toBase64())
                        w.writeEndElement() #
                    else:
                        source = tile.imageSource()
                        if (not self.mUseAbsolutePaths):
                            source = self.mMapDir.relativeFilePath(source)
                        w.writeAttribute("source", source)

                    w.writeEndElement() #

                if (objectGroup):
                    self.__writeObjectGroup(w, objectGroup)
                if (tile.isAnimated()):
                    frames = tile.frames()
                    w.writeStartElement("animation")
                    for frame in frames:
                        w.writeStartElement("frame")
                        w.writeAttribute("tileid", str(frame.tileId))
                        w.writeAttribute("duration", str(frame.duration))
                        w.writeEndElement() #

                    w.writeEndElement() #

                w.writeEndElement() #

        w.writeEndElement()

    def __writeTileLayer(self, w, tileLayer):
        w.writeStartElement("layer")
        self.__writeLayerAttributes(w, tileLayer)
        self.__writeProperties(w, tileLayer.properties())
        encoding = QString()
        compression = QString()
        if (self.mLayerDataFormat == Map.LayerDataFormat.Base64
                or self.mLayerDataFormat == Map.LayerDataFormat.Base64Gzip
                or self.mLayerDataFormat == Map.LayerDataFormat.Base64Zlib):
            encoding = "base64"
            if (self.mLayerDataFormat == Map.LayerDataFormat.Base64Gzip):
                compression = "gzip"
            elif (self.mLayerDataFormat == Map.LayerDataFormat.Base64Zlib):
                compression = "zlib"
        elif (self.mLayerDataFormat == Map.LayerDataFormat.CSV):
            encoding = "csv"
        w.writeStartElement("data")
        if encoding != '':
            w.writeAttribute("encoding", encoding)
        if compression != '':
            w.writeAttribute("compression", compression)
        if (self.mLayerDataFormat == Map.LayerDataFormat.XML):
            for y in range(tileLayer.height()):
                for x in range(tileLayer.width()):
                    gid = self.mGidMapper.cellToGid(tileLayer.cellAt(x, y))
                    w.writeStartElement("tile")
                    w.writeAttribute("gid", str(gid))
                    w.writeEndElement()
        elif (self.mLayerDataFormat == Map.LayerDataFormat.CSV):
            tileData = ''
            for y in range(tileLayer.height()):
                for x in range(tileLayer.width()):
                    gid = self.mGidMapper.cellToGid(tileLayer.cellAt(x, y))
                    tileData += str(gid)
                    if (x != tileLayer.width() - 1 or y != tileLayer.height() - 1):
                        tileData += ","

                tileData += "\n"

            w.writeCharacters("\n")
            w.writeCharacters(tileData)
        else:
            tileData = self.mGidMapper.encodeLayerData(tileLayer, self.mLayerDataFormat)
            
            w.writeCharacters("\n   ")
            w.writeCharacters(tileData.data().decode())
            w.writeCharacters("\n  ")

        w.writeEndElement() # </data>
        w.writeEndElement() # </layer>

    def __writeLayerAttributes(self, w, layer):
        if layer.name() != '':
            w.writeAttribute("name", layer.name())

        x = layer.x()
        y = layer.y()
        opacity = layer.opacity()
        if (x != 0):
            w.writeAttribute("x", str(x))
        if (y != 0):
            w.writeAttribute("y", str(y))
            
        if (layer.layerType() == Layer.TileLayerType):
            w.writeAttribute("width", str(layer.width()))
            w.writeAttribute("height", str(layer.height()))
            
        if (not layer.isVisible()):
            w.writeAttribute("visible", "0")
        if (opacity != 1.0):
            w.writeAttribute("opacity", str(opacity))
        
        offset = layer.offset()
        if (not offset.isNull()):
            w.writeAttribute("offsetx", str(offset.x()))
            w.writeAttribute("offsety", str(offset.y()))

    def __writeObjectGroup(self, w, objectGroup):
        w.writeStartElement("objectgroup")
        if (objectGroup.color().isValid()):
            w.writeAttribute("color", objectGroup.color().name())
        if (objectGroup.drawOrder() != ObjectGroup.DrawOrder.TopDownOrder):
            w.writeAttribute("draworder", drawOrderToString(objectGroup.drawOrder()))

        self.__writeLayerAttributes(w, objectGroup)
        self.__writeProperties(w, objectGroup.properties())
        for mapObject in objectGroup.objects():
            self.__writeObject(w, mapObject)
        w.writeEndElement()

    def __writeObject(self, w, mapObject):
        w.writeStartElement("object")
        w.writeAttribute("id", str(mapObject.id()))
        name = mapObject.name()
        type = mapObject.type()
        if name != '':
            w.writeAttribute("name", name)
        if type != '':
            w.writeAttribute("type", type)
        if (not mapObject.cell().isEmpty()):
            gid = self.mGidMapper.cellToGid(mapObject.cell())
            w.writeAttribute("gid", str(gid))

        pos = mapObject.position()
        size = mapObject.size()
        
        w.writeAttribute("x", str(pos.x()))
        w.writeAttribute("y", str(pos.y()))
        if (size.width() != 0):
            w.writeAttribute("width", str(size.width()))
        if (size.height() != 0):
            w.writeAttribute("height", str(size.height()))
        rotation = mapObject.rotation()
        if (rotation != 0.0):
            w.writeAttribute("rotation", str(rotation))
        if (not mapObject.isVisible()):
            w.writeAttribute("visible"), "0"
        self.__writeProperties(w, mapObject.properties())
        polygon = mapObject.polygon()
        if (not polygon.isEmpty()):
            if (mapObject.shape() == MapObject.Polygon):
                w.writeStartElement("polygon")
            else:
                w.writeStartElement("polyline")
            points = ''
            for point in polygon:
                points += str(point.x()) + ',' + str(point.y()) + ' '

            points = points[:-1]
            w.writeAttribute("points", points)
            w.writeEndElement()

        if (mapObject.shape() == MapObject.Ellipse):
            w.writeEmptyElement("ellipse")
        w.writeEndElement()

    def __writeImageLayer(self, w, imageLayer):
        w.writeStartElement("imagelayer")
        self.__writeLayerAttributes(w, imageLayer)
        # Write the image element
        imageSource = imageLayer.imageSource()
        if imageSource != '':
            w.writeStartElement("image")
            source = imageSource
            if (not self.mUseAbsolutePaths):
                source = self.mMapDir.relativeFilePath(source)
            w.writeAttribute("source", source)
            transColor = imageLayer.transparentColor()
            if (transColor.isValid()):
                w.writeAttribute("trans", transColor.name()[1])
            w.writeEndElement()

        self.__writeProperties(w, imageLayer.properties())
        w.writeEndElement()

    def __writeProperties(self, w, properties):
        if (properties.isEmpty()):
            return
        w.writeStartElement("properties")
        for it in properties:
            w.writeStartElement("property")
            w.writeAttribute("name", it[0])
            value = str(it[1])
            if value.__contains__('\n'):
                w.writeCharacters(value)
            else:
                w.writeAttribute("value", value)

            w.writeEndElement()

        w.writeEndElement()