Пример #1
0
        public unsafe static void CompressMapSimple(Player p, Stream stream, LevelChunkStream dst)
        {
            const int bufferSize = 64 * 1024;

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

            // Store on stack instead of performing function call for every block in map
            byte *conv = stackalloc byte[Block.ExtendedCount];

            CalcFallbacks(p, conv);
            Level lvl = p.level;

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

            // compress the map data in 64 kb chunks
            for (int i = 0; i < blocks.Length; ++i)
            {
                buffer[bIndex] = conv[blocks[i]];
                bIndex++;

                if (bIndex == bufferSize)
                {
                    // '0' to indicate classic blocks
                    dst.chunkValue = p.hasExtBlocks ? (byte)0 : (byte)(i * progScale);
                    stream.Write(buffer, 0, bufferSize); bIndex = 0;
                }
            }
            if (bIndex > 0)
            {
                stream.Write(buffer, 0, bIndex);
            }
        }
Пример #2
0
 public static void SendLevel(ClassicProtocol session, Level level, int volume)
 {
     using (LevelChunkStream dst = new LevelChunkStream(session))
         using (Stream stream = dst.CompressMapHeader(volume))
         {
             if (level.MightHaveCustomBlocks())
             {
                 CompressMap(level, stream, dst);
             }
             else
             {
                 CompressMapSimple(level, stream, dst);
             }
         }
 }
Пример #3
0
        public void SendLevel(Level prev, Level level)
        {
            int volume = level.blocks.Length;

            if (player.Supports(CpeExt.FastMap))
            {
                Send(Packet.LevelInitaliseExt(volume));
            }
            else
            {
                Send(Packet.LevelInitalise());
            }

            if (player.hasBlockDefs)
            {
                if (prev != null && prev != level)
                {
                    RemoveOldLevelCustomBlocks(prev);
                }
                BlockDefinition.SendLevelCustomBlocks(player);

                if (player.Supports(CpeExt.InventoryOrder))
                {
                    BlockDefinition.SendLevelInventoryOrder(player);
                }
            }

            using (LevelChunkStream dst = new LevelChunkStream(player))
                using (Stream stream = LevelChunkStream.CompressMapHeader(player, volume, dst))
                {
                    if (level.MightHaveCustomBlocks())
                    {
                        LevelChunkStream.CompressMap(player, stream, dst);
                    }
                    else
                    {
                        LevelChunkStream.CompressMapSimple(player, stream, dst);
                    }
                }

            // Force players to read the MOTD (clamped to 3 seconds at most)
            if (level.Config.LoadDelay > 0)
            {
                Thread.Sleep(level.Config.LoadDelay);
            }

            Send(Packet.LevelFinalise(level.Width, level.Height, level.Length));
        }
Пример #4
0
        internal static Stream CompressMapHeader(Player player, int volume, LevelChunkStream dst)
        {
            Stream stream = null;

            if (player.Supports(CpeExt.FastMap))
            {
                stream = new DeflateStream(dst, CompressionMode.Compress, true);
            }
            else
            {
                stream = new GZipStream(dst, CompressionMode.Compress, true);
                byte[] buffer = new byte[4]; NetUtils.WriteI32(volume, buffer, 0);
                stream.Write(buffer, 0, sizeof(int));
            }
            return(stream);
        }
Пример #5
0
        unsafe static void CompressMapSimple(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[256];

            for (int i = 0; i < 256; i++)
            {
                conv[i] = (byte)s.ConvertBlock((BlockID)i);
            }

            // compress the map data in 64 kb chunks
            for (int i = 0; i < blocks.Length; ++i)
            {
                buffer[bIndex] = conv[blocks[i]];
                bIndex++;

                if (bIndex == bufferSize)
                {
                    // '0' to indicate this chunk has lower 8 bits of block ids
                    dst.chunkValue = s.hasExtBlocks ? (byte)0 : (byte)(i * progScale);
                    stream.Write(buffer, 0, bufferSize); bIndex = 0;
                }
            }
            if (bIndex > 0)
            {
                stream.Write(buffer, 0, bIndex);
            }
        }
Пример #6
0
        public override void SendLevel(Level prev, Level level)
        {
            int volume = level.blocks.Length;

            if (Supports(CpeExt.FastMap))
            {
                Send(Packet.LevelInitaliseExt(volume));
            }
            else
            {
                Send(Packet.LevelInitalise());
            }

            if (hasBlockDefs)
            {
                if (prev != null && prev != level)
                {
                    RemoveOldLevelCustomBlocks(prev);
                }
                BlockDefinition.SendLevelCustomBlocks(player);

                if (Supports(CpeExt.InventoryOrder))
                {
                    BlockDefinition.SendLevelInventoryOrder(player);
                }
            }

            LevelChunkStream.SendLevel(this, level, volume);

            // Force players to read the MOTD (clamped to 3 seconds at most)
            if (level.Config.LoadDelay > 0)
            {
                Thread.Sleep(level.Config.LoadDelay);
            }

            Send(Packet.LevelFinalise(level.Width, level.Height, level.Length));
        }
Пример #7
0
        public unsafe static void CompressMap(Player p, Stream stream, LevelChunkStream dst)
        {
            const int bufferSize = 64 * 1024;

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

            // Store on stack instead of performing function call for every block in map
            byte *conv    = stackalloc byte[Block.ExtendedCount];
            byte *convExt = conv + Block.Count;

            #if TEN_BIT_BLOCKS
            byte *convExt2 = conv + Block.Count * 2;
            byte *convExt3 = conv + Block.Count * 3;
            #endif

            CalcFallbacks(p, conv);
            Level  lvl       = p.level;
            byte[] blocks    = lvl.blocks;
            float  progScale = 100.0f / blocks.Length;

            // compress the map data in 64 kb chunks
            #if TEN_BIT_BLOCKS
            if (p.hasExtBlocks)
            {
                byte[] buffer2 = new byte[bufferSize];
                using (LevelChunkStream dst2 = new LevelChunkStream(p))
                    using (Stream stream2 = LevelChunkStream.CompressMapHeader(p, blocks.Length, dst2))
                    {
                        dst.chunkValue  = 0; // 'classic' blocks
                        dst2.chunkValue = 1; // 'extended' blocks

                        for (int i = 0; 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 if (p.hasBlockDefs)
            {
                for (int 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)
                    {
                        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
            {
                for (int i = 0; i < blocks.Length; ++i)
                {
                    byte block = blocks[i];
                    if (block == Block.custom_block)
                    {
                        block = convExt[lvl.GetExtTile(i)];
                    }
                    else if (block == Block.custom_block_2)
                    {
                        block = convExt2[lvl.GetExtTile(i)];
                    }
                    else if (block == Block.custom_block_3)
                    {
                        block = convExt3[lvl.GetExtTile(i)];
                    }
                    buffer[bIndex] = conv[block];

                    bIndex++;
                    if (bIndex == bufferSize)
                    {
                        dst.chunkValue = (byte)(i * progScale);
                        stream.Write(buffer, 0, bufferSize); bIndex = 0;
                    }
                }
            }
            #else
            if (p.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)
                    {
                        block = convExt[lvl.GetExtTile(i)];
                    }
                    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);
            }
        }
Пример #8
0
        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);
            }
        }
Пример #9
0
        public unsafe static void CompressMap(Player p, LevelChunkStream dst)
        {
            const int bufferSize = 64 * 1024;

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

            // Store on stack instead of performing function call for every block in map
            byte *conv    = stackalloc byte[Block.Count];
            byte *convCPE = stackalloc byte[Block.Count];

            for (int i = 0; i < 256; i++)
            {
                conv[i] = Block.Convert((byte)i);
            }

            // Convert custom blocks (that overwrote core blocks) to their fallbacks
            if (!p.hasBlockDefs)
            {
                for (int i = 0; i < Block.CpeCount; i++)
                {
                    BlockDefinition def = p.level.CustomBlockDefs[i];
                    if (def != null)
                    {
                        conv[i] = def.FallBack;
                    }
                }
            }

            // Convert CPE blocks to their fallbacks
            if (!p.hasCustomBlocks)
            {
                for (int i = 0; i < Block.Count; i++)
                {
                    convCPE[i] = Block.ConvertCPE((byte)i);
                    conv[i]    = Block.ConvertCPE(conv[i]);
                }
            }


            Level lvl          = p.level;
            bool  hasBlockDefs = p.hasBlockDefs;

            using (GZipStream gs = new GZipStream(dst, CompressionMode.Compress, true)) {
                byte[] blocks = lvl.blocks;
                NetUtils.WriteI32(blocks.Length, buffer, 0);
                gs.Write(buffer, 0, sizeof(int));
                dst.length = blocks.Length;

                // compress the map data in 64 kb chunks
                if (p.hasCustomBlocks)
                {
                    for (int i = 0; i < blocks.Length; ++i)
                    {
                        byte block = blocks[i];
                        if (block == Block.custom_block)
                        {
                            buffer[bIndex] = hasBlockDefs ? lvl.GetExtTile(i) : lvl.GetFallbackExtTile(i);
                        }
                        else
                        {
                            buffer[bIndex] = conv[block];
                        }

                        bIndex++;
                        if (bIndex == bufferSize)
                        {
                            dst.position = i;
                            gs.Write(buffer, 0, bufferSize); bIndex = 0;
                        }
                    }
                }
                else
                {
                    for (int i = 0; i < blocks.Length; ++i)
                    {
                        byte block = blocks[i];
                        if (block == Block.custom_block)
                        {
                            block          = hasBlockDefs ? lvl.GetExtTile(i) : lvl.GetFallbackExtTile(i);
                            buffer[bIndex] = convCPE[block];
                        }
                        else
                        {
                            buffer[bIndex] = conv[block];
                        }

                        bIndex++;
                        if (bIndex == bufferSize)
                        {
                            dst.position = i;
                            gs.Write(buffer, 0, bufferSize); bIndex = 0;
                        }
                    }
                }
                if (bIndex > 0)
                {
                    gs.Write(buffer, 0, bIndex);
                }
            }
        }