public static MapChunkData GetMapChunkData(Chunk chunk, bool firstInit)
        {
            MapChunkData chunkData = new MapChunkData();

            ushort mask = 1;

            Queue<Section> sectionsToBeSent = new Queue<Section>();
            for (int i = 0; i < 16; ++i)
            {
                Section currentSection = chunk.Sections[i];
                if (currentSection != null && (firstInit || (chunk.SectionsToBeUpdated & 1) << i != 0))
                {
                    sectionsToBeSent.Enqueue(currentSection);
                }
            }

            int dataDim = sectionsToBeSent.Count * (Section.BYTESIZE + Section.SIZE);

            if (firstInit)
                dataDim += 256;

            chunkData.Data = new byte[dataDim];

            int halfSize = sectionsToBeSent.Count * Section.HALFSIZE;
            int offsetData = sectionsToBeSent.Count * Section.SIZE;
            int offsetLight = offsetData + halfSize;
            int offsetSkyLight = offsetLight + halfSize;

            int sectionIndex = 0;
            while(sectionsToBeSent.Count > 0)
            {
                Section section = sectionsToBeSent.Dequeue();

                Buffer.BlockCopy(section.Types, 0, chunkData.Data, sectionIndex * Section.SIZE, Section.SIZE);
                Buffer.BlockCopy(section.Data.Data, 0, chunkData.Data, offsetData + (sectionIndex * Section.HALFSIZE),
                                    Section.HALFSIZE);

                Buffer.BlockCopy(chunk.Light.Data, section.SectionId * Section.HALFSIZE, chunkData.Data, offsetLight + (sectionIndex * Section.HALFSIZE),
                                    Section.HALFSIZE);
                Buffer.BlockCopy(chunk.SkyLight.Data, section.SectionId * Section.HALFSIZE, chunkData.Data, offsetSkyLight + (sectionIndex * Section.HALFSIZE),
                                    Section.HALFSIZE);


                chunkData.PrimaryBitMask |= mask << section.SectionId;
                ++sectionIndex;
                // TODO: we leave add array and biome array to 0 (ocean), we need to change the chunk generator accordingly
            }

            return chunkData;
        }
        public override void Read(PacketReader stream)
        {
            int posX = stream.ReadInt();
            short posY = stream.ReadShort();
            int posZ = stream.ReadInt();
            byte sizeX = (byte)(stream.ReadByte() + 1);
            byte sizeY = (byte)(stream.ReadByte() + 1);
            byte sizeZ = (byte)(stream.ReadByte() + 1);

            int o = sizeX * sizeY * sizeZ;
            Chunk = new Chunk(null, new Vector3I(posX, posY, posZ));

            int len = stream.ReadInt();
            stream.ReadBytes(len);
        }
        internal static void MakeInitChunk( Chunk chunk, SMPPacketWriter Writer )
        {
            /* byte[] ChunkArray = null;
            lock ( chunk.blockslock ) {
                using ( MemoryStream memStream = new MemoryStream() ) {
                    for ( int a = 0; a < 16; a++ ) {
                        for ( int i = 0; i < ( 16 ); i++ ) {
                            // Write Blocks
                            memStream.WriteByte( 5 );
                        }
                        for ( int i = 0; i < ( 16 ); i++ ) {
                            // Write MetaData
                            memStream.WriteByte( ( ( 0 & 0x0F ) << 4 ) | ( 0 & 0x0F ) );
                        }
                        for ( int i = 0; i < ( 16 ); i++ ) {
                            // Write BlockLight
                            memStream.WriteByte( 0 );
                        }
                        for ( int i = 0; i < ( 16 ); i++ ) {
                            // Write SkyLight
                            memStream.WriteByte( ( ( 2 & 0x0F ) << 4 ) | ( 2 & 0x0F ) );
                        }
                      //  for ( int i = 0; i < ( 16 ); i++ ) {
                            //Biomes?
                         //   memStream.WriteByte( 0 );
                        //}
                    }
                    ChunkArray = Ionic.Zlib.ZlibStream.CompressBuffer(memStream.ToArray());
                    }

                    Logger.LogToConsole( "Init length: " + ChunkArray.Length.ToString() );
                }*/

            new InitChunkPacket() {
                X = chunk.X,
                Z = chunk.Z,
                PrimaryBitMap = 1,
                AddBitMap = 1,
                GroundUp = false,
                Sunlight = 2
            }.Write( Writer );
        }
        public static void MakeMapChunkPacket( Chunk chunk, SMPPacketWriter Writer )
        {
            var X = ( int )chunk.X;
            var Z = ( int )chunk.Z;

            byte[] blockData;
            byte[] metadata;
            byte[] blockLight;
            byte[] skyLight;

            ushort mask = 1, chunkY = 0;
            bool nonAir = true;

            // First pass calculates number of sections to send
            int totalSections = 0;
            for ( int i = 15; i >= 0; i-- ) {
                Section s = chunk.Sections[chunkY++];

                if ( s.IsAir )
                    nonAir = false;
                if ( nonAir )
                    totalSections++;
            }

            mask = 1;
            chunkY = 0;
            nonAir = true;
            blockData = new byte[totalSections * BlockDataLength];
            metadata = new byte[totalSections * NibbleDataLength];
            blockLight = new byte[totalSections * NibbleDataLength];
            skyLight = new byte[totalSections * NibbleDataLength];

            ushort PrimaryBitMap = 0, AddBitMap = 0;

            // Second pass produces the arrays
            for ( int i = 15; i >= 0; i-- ) {
                Section s = chunk.Sections[chunkY++];

                if ( s.IsAir )
                    nonAir = false;
                if ( nonAir ) {
                    Array.Copy( s.Blocks, 0, blockData, ( chunkY - 1 ) * BlockDataLength, BlockDataLength );
                    Array.Copy( s.Metadata.Data, 0, metadata, ( chunkY - 1 ) * NibbleDataLength, NibbleDataLength );
                    Array.Copy( s.BlockLight.Data, 0, blockLight, ( chunkY - 1 ) * NibbleDataLength, NibbleDataLength );
                    Array.Copy( s.SkyLight.Data, 0, skyLight, ( chunkY - 1 ) * NibbleDataLength, NibbleDataLength );

                    PrimaryBitMap |= mask;
                }

                mask <<= 1;
            }

            // Create the final array
            // TODO: Merge this into the other loop, reduce objects
            byte[] data = new byte[blockData.Length + metadata.Length +
                blockLight.Length + skyLight.Length + chunk.Biomes.Length];
            int index = 0;
            Array.Copy( blockData, 0, data, index, blockData.Length );
            index += blockData.Length;
            Array.Copy( metadata, 0, data, index, metadata.Length );
            index += metadata.Length;
            Array.Copy( blockLight, 0, data, index, blockLight.Length );
            index += blockLight.Length;
            Array.Copy( skyLight, 0, data, index, skyLight.Length );
            index += skyLight.Length;
            Array.Copy(chunk.Biomes, 0, data, index, chunk.Biomes.Length);

            // Compress the array
            var result = Ionic.Zlib.ZlibStream.CompressBuffer( data );
            var GroundUpContiguous = true;
            Logger.LogToConsole( "Chunk length: "+result.Length.ToString() );
            Writer.Write( 0x38 );
            Writer.Write( X );
            Writer.Write( Z );
            Writer.Write( GroundUpContiguous );
            Writer.Write( PrimaryBitMap );
            Writer.Write( AddBitMap );
            Writer.Write( result.Length );
            Writer.Write( result );

            Writer.Flush();
        }
        public void UpdateChunks()
        {
            lock ( chunkUpdateLock ) {
                Position pos = WorldManager.MainWorld.Map.Spawn;
                // Get neccesary chunk range
                int RequiredMinX = ( int )( ( int )pos.X / 16 ) - ( ChunkArea / 2 );
                int RequiredMinZ = ( int )( ( int )pos.Y / 16 ) - ( ChunkArea / 2 );

                // Check if new chunks are required
                if ( RequiredMinX == LoadedChunksMinX && RequiredMinZ == LoadedChunksMinZ )
                    return;
                List<Chunk> tosend = new List<Chunk>();
                // Send Pre-Chunks and Chunks
                for ( int Xchunk = RequiredMinX; Xchunk < ( RequiredMinX + ChunkArea ); Xchunk++ ) {
                    for ( int Zchunk = RequiredMinZ; Zchunk < ( RequiredMinZ + ChunkArea ); Zchunk++ ) {
                        if ( ( Xchunk >= ( LoadedChunksMinX + ChunkArea ) || Xchunk < ( LoadedChunksMinX ) || Zchunk >= ( LoadedChunksMinZ + ChunkArea ) || Zchunk < ( LoadedChunksMinZ ) ) || ( !HasChunks ) ) {
                            Chunk chunkToSend = new Chunk( Xchunk, Zchunk, WorldManager.MainWorld );
                                //Server.world.GetChunk( Xchunk, Zchunk );
                            if ( chunkToSend == null ) {
                                Logger.Log( LogType.Error, "Player.UpdateChunks: Error loading or generating chunk! ({0}, {1})", Xchunk, Zchunk );
                                //session.KickNow( "ERROR: Failed to load or generate chunk! (" + Xchunk + ", " + Zchunk + ")" );
                                return;
                            }
                           // chunkToSend.AddPlayer( this );
                            if ( !chunkToSend.terrainPopulated )
                                chunkToSend.CalculateLighting();
                            tosend.Add( chunkToSend );
                            SMPPacketWriter.MakeInitChunk( chunkToSend, smpWriter );
                            SMPPacketWriter.MakeMapChunkPacket( chunkToSend, smpWriter );
                           // session.SendNow( PacketWriter.MakePreChunk( Xchunk, Zchunk, true ) );
                            //session.SendNow( PacketWriter.MakeChunk( chunkToSend ) );
                        }
                    }
                }
            }
        }