Пример #1
0
        private bool LoadTMXSections(BinaryReader reader, ref TMXMapDef map)
        {
            while (true)
            {
                int section = reader.ReadByte();
                if (section == RetroBlit_TMX_SECTION_TILE_LAYER)
                {
                    if (!LoadTMXTileLayerDef(reader, ref map))
                    {
                        return(false);
                    }
                }
                else if (section == RetroBlit_TMX_SECTION_OBJECTGROUP)
                {
                    if (!LoadTMXObjectGroupDef(reader, ref map))
                    {
                        return(false);
                    }
                }
                else if (section == RetroBlit_TSX_PROPERTIES)
                {
                    if (!LoadTSXProperties(reader, ref map))
                    {
                        return(false);
                    }
                }
                else if (section == RetroBlit_TMX_SECTION_END)
                {
                    break;
                }
            }

            return(true);
        }
Пример #2
0
        private bool LoadTSXProperties(BinaryReader reader, ref TMXMapDef map)
        {
            int tsxLoops = 0;

            var allProps = new List <Dictionary <int, TMXProperties> >();

            int prevTsxIndex = -1;

            while (true)
            {
                var tsxIndex = reader.ReadInt32();
                if (tsxIndex == -1)
                {
                    // All done
                    break;
                }

                if (tsxIndex != prevTsxIndex + 1)
                {
                    Debug.LogError("TMX binary files had non-consequitive TSX property sets, TMX import is likely corrupt, please try reimporting " + map.realPathName);
                    return(false);
                }

                var propsSet = new Dictionary <int, TMXProperties>();

                while (true)
                {
                    var tid = reader.ReadInt32();
                    if (tid == -1)
                    {
                        // All done this tsx
                        break;
                    }

                    var props = new TMXProperties();

                    LoadProperties(reader, props);

                    propsSet.Add(tid, props);
                }

                allProps.Add(propsSet);

                prevTsxIndex = tsxIndex;

                // Break out if we loop for too long, TSX data could be corrupt
                tsxLoops++;
                if (tsxLoops > 256)
                {
                    Debug.Log("TSX properties data is invalid, please try to reimport " + map.realPathName);
                    return(false);
                }
            }

            map.allTileProperties = allProps;

            return(true);
        }
Пример #3
0
        private bool LoadTMXTileLayerDef(BinaryReader reader, ref TMXMapDef map)
        {
            TMXLayerDef layerDef     = new TMXLayerDef();
            string      name         = reader.ReadString();
            int         layerWidth   = reader.ReadInt32();
            int         layerHeight  = reader.ReadInt32();
            int         layerOffsetX = reader.ReadInt32();
            int         layerOffsetY = reader.ReadInt32();
            bool        layerVisible = reader.ReadBoolean();
            byte        layerAlpha   = reader.ReadByte();
            int         chunkCount   = 0;

            // Load properties if available
            bool propsAvailable = reader.ReadBoolean();

            if (propsAvailable)
            {
                var props = new TMXProperties();
                LoadProperties(reader, props);

                layerDef.SetProperties(props);
            }

            if (map.infinite)
            {
                chunkCount = reader.ReadInt32();
            }

            layerDef.chunkCount = chunkCount;
            layerDef.SetSize(new Vector2i(layerWidth, layerHeight));
            layerDef.SetOffset(new Vector2i(layerOffsetX, layerOffsetY));
            layerDef.SetVisible(layerVisible);
            layerDef.SetAlpha(layerAlpha);

            map.layers[name] = layerDef;

            return(true);
        }
Пример #4
0
        private Dictionary <ulong, ChunkDef> GetLayerIndexTable(TMXMapDef tmx, int layerName)
        {
            if (tmx == null)
            {
                return(null);
            }

            var fileName = tmx.realPathName + "layer_" + layerName.ToString("x") + "_index";

            var cached = tmx.mLayerIndexLRU.Get(fileName);

            if (cached != null)
            {
                return(cached);
            }

            var indexTableFile = Resources.Load <TextAsset>(fileName);

            if (indexTableFile == null)
            {
                Debug.Log("TMX could not find layer index table");
                return(null);
            }

            try
            {
                var reader = new BinaryReader(new MemoryStream(indexTableFile.bytes));

                int byteSize = 0;

                int chunkCount = reader.ReadInt32();
                byteSize += 4;

                var table = new Dictionary <ulong, ChunkDef>();

                // Return empty table if there are no chunks
                if (chunkCount == 0)
                {
                    return(table);
                }

                for (int i = 0; i < chunkCount; i++)
                {
                    var chunkDef = new ChunkDef();

                    ulong offset = reader.ReadUInt64();
                    byteSize += 8;
                    chunkDef.segmentIndex = reader.ReadUInt16();
                    byteSize += 2;
                    chunkDef.segmentOffset = reader.ReadUInt16();
                    byteSize += 2;
                    chunkDef.compressedLength = reader.ReadUInt16();
                    byteSize += 2;

                    table[offset] = chunkDef;
                }

                tmx.mLayerIndexLRU.Add(fileName, table, byteSize);

                return(table);
            }
            catch (IOException e)
            {
                Debug.Log("Failed to load layer index from file " + fileName + ", " + e.ToString());
                return(null);
            }
        }
Пример #5
0
        /// <summary>
        /// Load a map definition from a parsed binary TMX file
        /// </summary>
        /// <param name="fileName">Filename</param>
        /// <returns>Map definition</returns>
        public TMXMap LoadTMX(string fileName)
        {
            var map = new TMXMapDef(fileName);

            if (fileName == null)
            {
                return(null);
            }

            map.realPathName = Path.GetDirectoryName(fileName) + "/" + Path.GetFileNameWithoutExtension(fileName) + ".tmx.rb/";
            map.realPathName = map.realPathName.Replace('\\', '/');

            string infoFileName = map.realPathName + "info";
            var    tmxFile      = Resources.Load <TextAsset>(infoFileName);

            if (tmxFile == null)
            {
                Debug.Log("Can't find TMX map at " + fileName + ". If TMX file exists then please try re-importing your TMX file.");
                return(null);
            }

            try
            {
                var reader = new BinaryReader(new MemoryStream(tmxFile.bytes));

                var magicNum = reader.ReadUInt16();
                var version  = reader.ReadUInt16();

                if (magicNum != RetroBlit_TMX_MAGIC)
                {
                    Debug.Log(fileName + " is not a TMX file");
                    Debug.Log("Magic: " + magicNum + " expected " + RetroBlit_TMX_MAGIC);
                    return(null);
                }

                if (version > RetroBlit_TMX_VERSION)
                {
                    Debug.Log(fileName + " is of a newer version than this version of RetroBlit supports, try reimporting your TMX file into Unity.");
                    return(null);
                }

                byte type = reader.ReadByte();

                if (type != RetroBlit_TMX_TYPE_MAP)
                {
                    Debug.Log(fileName + " is a RetroBlit TMX file but it is of the wrong type.");
                    return(null);
                }

                int  mapWidth  = reader.ReadInt32();
                int  mapHeight = reader.ReadInt32();
                byte r         = reader.ReadByte();
                byte g         = reader.ReadByte();
                byte b         = reader.ReadByte();
                byte a         = reader.ReadByte();
                bool infinite  = reader.ReadBoolean();

                map.SetSize(new Vector2i(mapWidth, mapHeight));
                map.SetBackgroundColor(new Color32(r, g, b, a));
                map.SetInfinite(infinite);

                int chunkWidth  = reader.ReadInt32();
                int chunkHeight = reader.ReadInt32();

                map.chunkSize = new Vector2i(chunkWidth, chunkHeight);

                // Load properties if available
                bool propsAvailable = reader.ReadBoolean();
                if (propsAvailable)
                {
                    var props = new TMXProperties();
                    LoadProperties(reader, props);

                    map.SetProperties(props);
                }

                if (!LoadTMXSections(reader, ref map))
                {
                    Debug.Log("Failed to load TMX sections from " + fileName);
                    return(null);
                }
            }
            catch (IOException e)
            {
                Debug.Log("Failed to load TMX from file " + fileName + ", " + e.ToString());
                return(null);
            }

            return(map);
        }
Пример #6
0
        private bool LoadTMXObjectGroupDef(BinaryReader reader, ref TMXMapDef map)
        {
            var objectGroup = new TMXObjectGroupDef();

            var name    = reader.ReadString();
            var r       = reader.ReadByte();
            var g       = reader.ReadByte();
            var b       = reader.ReadByte();
            var a       = reader.ReadByte();
            var alpha   = reader.ReadByte();
            var visible = reader.ReadBoolean();
            var offsetX = reader.ReadInt32();
            var offsetY = reader.ReadInt32();

            objectGroup.SetName(name);
            objectGroup.SetColor(new Color32(r, g, b, a));
            objectGroup.SetAlpha(alpha);
            objectGroup.SetVisible(visible);
            objectGroup.SetOffset(new Vector2i(offsetX, offsetY));

            // Load properties if available
            bool propsAvailable = reader.ReadBoolean();

            if (propsAvailable)
            {
                var props = new TMXProperties();
                LoadProperties(reader, props);

                objectGroup.SetProperties(props);
            }

            // Now load objects
            var objects     = new List <TMXObject>();
            var objectCount = reader.ReadInt32();

            for (int i = 0; i < objectCount; i++)
            {
                var objName    = reader.ReadString();
                var objType    = reader.ReadString();
                var rectX      = reader.ReadInt32();
                var rectY      = reader.ReadInt32();
                var rectWidth  = reader.ReadInt32();
                var rectHeight = reader.ReadInt32();
                var rotation   = reader.ReadSingle();
                var objVisible = reader.ReadBoolean();
                var shape      = reader.ReadInt32();

                var points      = new List <Vector2i>();
                var pointsCount = reader.ReadInt32();
                for (int j = 0; j < pointsCount; j++)
                {
                    var pointX = reader.ReadInt32();
                    var pointY = reader.ReadInt32();
                    points.Add(new Vector2i(pointX, pointY));
                }

                var tmxObject = new TMXObjectDef();
                tmxObject.SetName(objName);
                tmxObject.SetType(objType);
                tmxObject.SetShape((TMXObject.Shape)shape);
                tmxObject.SetRect(new Rect2i(rectX, rectY, rectWidth, rectHeight));
                tmxObject.SetRotation(rotation);
                tmxObject.SetVisible(objVisible);
                tmxObject.SetPoints(points);

                // Load properties if available
                propsAvailable = reader.ReadBoolean();
                if (propsAvailable)
                {
                    var props = new TMXProperties();
                    LoadProperties(reader, props);

                    tmxObject.SetProperties(props);
                }

                objects.Add(tmxObject);
            }

            objectGroup.SetObjects(objects);

            map.objectGroups[name] = objectGroup;

            return(true);
        }
Пример #7
0
        /// <summary>
        /// Load a single layer chunk
        /// </summary>
        /// <param name="tmx">Map definition</param>
        /// <param name="tmxSourceLayer">Name of source layer</param>
        /// <param name="destinationLayer">RetroBlit destination layer</param>
        /// <param name="chunkOffset">Chunk offset</param>
        /// <param name="destPos">Destination position</param>
        /// <param name="packedSpriteLookup">Lookup table for translating TMX tile indexes to packed sprites</param>
        /// <returns>True if successful</returns>
        public bool LoadTMXLayerChunk(TMXMap tmx, string tmxSourceLayer, int destinationLayer, Vector2i chunkOffset, Vector2i destPos, PackedSpriteID[] packedSpriteLookup)
        {
            TMXMapDef map = null;

            if (!(tmx is RetroBlitInternal.RetroBlitTilemap.TMXMapDef))
            {
                Debug.LogError("Can't load TMX layer, invalid map object!");
                return(false);
            }

            map = (TMXMapDef)tmx;

            if (map == null || map.realPathName == null || map.realPathName.Length == 0 || map.layers == null)
            {
                Debug.LogError("Can't load TMX layer, invalid map, or map not open yet!");
                return(false);
            }

            if (!map.infinite)
            {
                Debug.LogError("TMX map is not infinite, use LoadTMXLayer() instead");
                return(false);
            }

            if (!map.layers.ContainsKey(tmxSourceLayer))
            {
                Debug.LogError("Layer " + tmxSourceLayer + " not found");
                return(false);
            }

            int chunkWidth  = map.chunkSize.x;
            int chunkHeight = map.chunkSize.y;

            var tmxLayer = (TMXLayerDef)map.layers[tmxSourceLayer];

            ulong part1  = (ulong)chunkOffset.x;
            ulong part2  = (ulong)chunkOffset.y;
            ulong offset = ((part1 << 32) & 0xFFFFFFFF00000000) | (part2 & 0xFFFFFFFF);

            int layerNameHash = mWorkStr.Set(tmxSourceLayer).ToLowerInvariant().GetHashCode();
            var tupleKey      = new RetroBlitTuple <int, ulong>(layerNameHash, offset);

            var decompressed = map.mChunkLRU.Get(tupleKey);

            if (decompressed == null)
            {
                var chunkTable = GetLayerIndexTable(map, layerNameHash);

                if (chunkTable == null)
                {
                    Debug.LogError("TMX could not load chunk index table for layer " + tmxSourceLayer);
                    return(false);
                }

                // If the chunk can't be found then fail silently and wipe the chunk area. This will also
                // release the chunk geometry on next draw because it will not have any vertices
                if (!chunkTable.ContainsKey(offset))
                {
                    for (int y = destPos.y; y < destPos.y + chunkHeight; y++)
                    {
                        for (int x = destPos.x; x < destPos.x + chunkWidth; x++)
                        {
                            mRetroBlitAPI.Tilemap.SpriteSet(destinationLayer, x, y, RB.SPRITE_EMPTY, Color.white, 0);

                            Tile[] tilesArr;
                            int    tileIndex;
                            if (GetTileRef(destinationLayer, x, y, out tilesArr, out tileIndex, true))
                            {
                                tilesArr[tileIndex].data = null;
                            }
                        }
                    }

                    return(true);
                }

                var chunkDef = chunkTable[offset];

                var chunkFileName = map.realPathName + "layer_" + layerNameHash.ToString("x") + "_seg_" + chunkDef.segmentIndex;

                var chunkFile = Resources.Load <TextAsset>(chunkFileName);

                if (chunkFile == null)
                {
                    Debug.LogError("Can't find TMX file when loading TMX layer!");
                    return(false);
                }

                var chunkBytes = chunkFile.bytes;

                decompressed = RetroBlitDeflate.Decompress(chunkBytes, chunkDef.segmentOffset, chunkDef.compressedLength);
                if (decompressed == null || decompressed.Length <= 0)
                {
                    Debug.LogError("Could not decompress tile data for layer " + tmxSourceLayer);
                    return(false);
                }

                map.mChunkLRU.Add(tupleKey, decompressed, decompressed.Length);
            }

            var tileDataReader = new BinaryReader(new MemoryStream(decompressed));

            if (tileDataReader == null)
            {
                Debug.LogError("Could not read tile data for layer " + tmxSourceLayer);
                return(false);
            }

            Color32 color = Color.white;

            int sx = 0;
            int sy = 0;

            int dx = destPos.x;
            int dy = destPos.y;

            while (tileDataReader.PeekChar() >= 0)
            {
                // Skip tsxIndex, don't need it for now
                tileDataReader.ReadByte();

                byte flags  = tileDataReader.ReadByte();
                int  tileId = tileDataReader.ReadInt32();

                if (packedSpriteLookup != null)
                {
                    if (packedSpriteLookup != null)
                    {
                        if (tileId < packedSpriteLookup.Length && tileId >= 0)
                        {
                            tileId = packedSpriteLookup[tileId].id;
                            flags |= RetroBlitInternal.RetroBlitTilemap.SPRITEPACK;
                        }
                    }
                }

                SpriteSet(destinationLayer, dx, dy, tileId, color, flags);
                dx++;
                sx++;

                if (sx >= chunkWidth)
                {
                    sx = 0;
                    dx = destPos.x;
                    sy++;
                    dy++;
                }

                if (sy >= chunkHeight)
                {
                    break;
                }
            }

            return(true);
        }
Пример #8
0
        /// <summary>
        /// Load a layer definition from an map definition
        /// </summary>
        /// <param name="tmx">Map definition</param>
        /// <param name="tmxSourceLayer">Name of the layer to load</param>
        /// <param name="destinationLayer">Destination RetroBlit layer</param>
        /// <param name="sourceRect">Source rectangle</param>
        /// <param name="destPos">Destination position</param>
        /// <param name="packedSpriteLookup">Lookup table for translating TMX tile indexes to packed sprites</param>
        /// <returns>True if successful</returns>
        public bool LoadTMXLayer(TMXMap tmx, string tmxSourceLayer, int destinationLayer, Rect2i sourceRect, Vector2i destPos, PackedSpriteID[] packedSpriteLookup)
        {
            TMXMapDef map = null;

            if (!(tmx is RetroBlitInternal.RetroBlitTilemap.TMXMapDef))
            {
                Debug.LogError("Can't load TMX layer, invalid map object!");
                return(false);
            }

            map = (TMXMapDef)tmx;

            if (map == null || map.realPathName == null || map.realPathName.Length == 0 || map.layers == null)
            {
                Debug.LogError("Can't load TMX layer, invalid map, or map not open yet!");
                return(false);
            }

            if (map.infinite)
            {
                Debug.LogError("TMX map is infinite, use MapLoadTMXLayerChunk() instead");
                return(false);
            }

            if (!map.layers.ContainsKey(tmxSourceLayer))
            {
                Debug.LogError("Layer " + tmxSourceLayer + " not found");
                return(false);
            }

            var tmxLayer = (TMXLayerDef)map.layers[tmxSourceLayer];

            var layerNameHash = mWorkStr.Set(tmxSourceLayer).ToLowerInvariant().GetHashCode().ToString("x");

            var tmxFileName = map.realPathName + "layer_" + layerNameHash;
            var tmxFile     = Resources.Load <TextAsset>(tmxFileName);

            if (tmxFile == null)
            {
                Debug.LogError("Can't find TMX file when loading TMX layer!");
                return(false);
            }

            var tmxBytes = tmxFile.bytes;

            var decompressed = RetroBlitDeflate.Decompress(tmxBytes, 0, tmxBytes.Length);

            if (decompressed == null || decompressed.Length <= 0)
            {
                Debug.LogError("Could not decompress tile data for layer " + tmxSourceLayer);
                return(false);
            }

            var tileDataReader = new BinaryReader(new MemoryStream(decompressed));

            if (tileDataReader == null)
            {
                Debug.LogError("Could not read tile data for layer " + tmxSourceLayer);
                return(false);
            }

            Color32 color = Color.white;

            int sx = 0;
            int sy = 0;

            int sx0 = sourceRect.x;
            int sx1 = sourceRect.x + sourceRect.width;

            int sy0 = sourceRect.y;
            int sy1 = sourceRect.y + sourceRect.height;

            int dx = destPos.x;
            int dy = destPos.y;

            while (tileDataReader.PeekChar() >= 0)
            {
                byte tsxIndex = tileDataReader.ReadByte();
                byte flags    = tileDataReader.ReadByte();
                int  tileId   = tileDataReader.ReadInt32();

                if (packedSpriteLookup != null)
                {
                    if (tileId < packedSpriteLookup.Length && tileId >= 0)
                    {
                        tileId = packedSpriteLookup[tileId].id;
                        flags |= RetroBlitInternal.RetroBlitTilemap.SPRITEPACK;
                    }
                }

                if (sx >= sx0 && sx <= sx1 && sy >= sy0 && sy <= sy1)
                {
                    SpriteSet(destinationLayer, dx, dy, tileId, color, flags);

                    // Set properties if available
                    if (tsxIndex >= 0 && tsxIndex < map.allTileProperties.Count)
                    {
                        var props = map.allTileProperties[tsxIndex];
                        if (props != null)
                        {
                            if (props.ContainsKey(tileId))
                            {
                                DataSet <TMXProperties>(destinationLayer, dx, dy, props[tileId]);
                            }
                        }
                    }

                    dx++;
                }

                sx++;
                if (sx >= tmxLayer.size.x)
                {
                    sx = 0;
                    dx = destPos.x;
                    sy++;
                    dy++;
                }

                if (sy >= tmxLayer.size.y || sy >= sourceRect.y + sourceRect.height)
                {
                    break;
                }
            }

            return(true);
        }