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);
             }
         }
 }
示例#2
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));
        }
示例#3
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);
            }
        }
        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);
            }
        }