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); } }