unsafe static void CompressMap(Level lvl, Stream stream, LevelChunkStream dst)
        {
            const int bufferSize = 64 * 1024;

            byte[] buffer = new byte[bufferSize];
            int    bIndex = 0;

            ClassicProtocol s = dst.session;

            byte[] blocks    = lvl.blocks;
            float  progScale = 100.0f / blocks.Length;

            // Store on stack instead of performing function call for every block in map
            byte *conv    = stackalloc byte[Block.SUPPORTED_COUNT];
            byte *convExt = conv + 256;  // 256 blocks per group/class

            #if TEN_BIT_BLOCKS
            byte *convExt2 = conv + 256 * 2;
            byte *convExt3 = conv + 256 * 3;
            #endif

            for (int j = 0; j < Block.SUPPORTED_COUNT; j++)
            {
                conv[j] = (byte)s.ConvertBlock((BlockID)j);
            }

            // compress the map data in 64 kb chunks
            #if TEN_BIT_BLOCKS
            if (s.hasExtBlocks)
            {
                // Initially assume all custom blocks are <= 255
                int i;
                for (i = 0; i < blocks.Length; i++)
                {
                    byte block = blocks[i];
                    if (block == Block.custom_block)
                    {
                        buffer[bIndex] = lvl.GetExtTile(i);
                    }
                    else if (block == Block.custom_block_2)
                    {
                        break;
                    }
                    else if (block == Block.custom_block_3)
                    {
                        break;
                    }
                    else
                    {
                        buffer[bIndex] = conv[block];
                    }

                    bIndex++;
                    if (bIndex == bufferSize)
                    {
                        stream.Write(buffer, 0, bufferSize);
                        bIndex = 0;
                    }
                }

                // Check if map only used custom blocks <= 255
                if (bIndex > 0)
                {
                    stream.Write(buffer, 0, bIndex);
                }
                if (i == blocks.Length)
                {
                    return;
                }
                bIndex = 0;

                // Nope - have to go slower path now
                using (LevelChunkStream dst2 = new LevelChunkStream(s))
                    using (Stream stream2 = dst2.CompressMapHeader(blocks.Length))
                    {
                        dst2.chunkValue = 1; // 'extended' blocks
                        byte[] buffer2 = new byte[bufferSize];

                        // Need to fill in all the upper 8 bits of blocks before this one with 0
                        for (int j = 0; j < i; j += bufferSize)
                        {
                            int len = Math.Min(bufferSize, i - j);
                            stream2.Write(buffer2, 0, len);
                        }

                        for (; i < blocks.Length; i++)
                        {
                            byte block = blocks[i];
                            if (block == Block.custom_block)
                            {
                                buffer[bIndex]  = lvl.GetExtTile(i);
                                buffer2[bIndex] = 0;
                            }
                            else if (block == Block.custom_block_2)
                            {
                                buffer[bIndex]  = lvl.GetExtTile(i);
                                buffer2[bIndex] = 1;
                            }
                            else if (block == Block.custom_block_3)
                            {
                                buffer[bIndex]  = lvl.GetExtTile(i);
                                buffer2[bIndex] = 2;
                            }
                            else
                            {
                                buffer[bIndex]  = conv[block];
                                buffer2[bIndex] = 0;
                            }

                            bIndex++;
                            if (bIndex == bufferSize)
                            {
                                stream.Write(buffer, 0, bufferSize);
                                stream2.Write(buffer2, 0, bufferSize);
                                bIndex = 0;
                            }
                        }
                        if (bIndex > 0)
                        {
                            stream2.Write(buffer2, 0, bIndex);
                        }
                    }
            }
            else
            {
                for (int i = 0; i < blocks.Length; i++)
                {
                    byte block = blocks[i];
                    if (block == Block.custom_block)
                    {
                        buffer[bIndex] = convExt[lvl.GetExtTile(i)];
                    }
                    else if (block == Block.custom_block_2)
                    {
                        buffer[bIndex] = convExt2[lvl.GetExtTile(i)];
                    }
                    else if (block == Block.custom_block_3)
                    {
                        buffer[bIndex] = convExt3[lvl.GetExtTile(i)];
                    }
                    else
                    {
                        buffer[bIndex] = conv[block];
                    }

                    bIndex++;
                    if (bIndex == bufferSize)
                    {
                        dst.chunkValue = (byte)(i * progScale);
                        stream.Write(buffer, 0, bufferSize); bIndex = 0;
                    }
                }
            }
            #else
            if (s.hasBlockDefs)
            {
                for (int i = 0; i < blocks.Length; i++)
                {
                    byte block = blocks[i];
                    if (block == Block.custom_block)
                    {
                        buffer[bIndex] = lvl.GetExtTile(i);
                    }
                    else
                    {
                        buffer[bIndex] = conv[block];
                    }

                    bIndex++;
                    if (bIndex == bufferSize)
                    {
                        dst.chunkValue = (byte)(i * progScale);
                        stream.Write(buffer, 0, bufferSize); bIndex = 0;
                    }
                }
            }
            else
            {
                for (int i = 0; i < blocks.Length; i++)
                {
                    byte block = blocks[i];
                    if (block == Block.custom_block)
                    {
                        buffer[bIndex] = convExt[lvl.GetExtTile(i)];
                    }
                    else
                    {
                        buffer[bIndex] = conv[block];
                    }

                    bIndex++;
                    if (bIndex == bufferSize)
                    {
                        dst.chunkValue = (byte)(i * progScale);
                        stream.Write(buffer, 0, bufferSize); bIndex = 0;
                    }
                }
            }
            #endif

            if (bIndex > 0)
            {
                stream.Write(buffer, 0, bIndex);
            }
        }