private unsafe static void DecodeBlock(byte *input, int blockWidth, int blockHeight, uint *output) { if (input[0] == 0xfc && (input[1] & 1) == 1) { uint c = Color(input[9], input[11], input[13], input[15]); for (int i = 0; i < blockWidth * blockHeight; i++) { output[i] = c; } } else { BlockData blockData = new BlockData(); blockData.bw = blockWidth; blockData.bh = blockHeight; BlockData *blockPtr = &blockData; DecodeBlockParameters(input, blockPtr); DecodeEndpoints(input, blockPtr); DecodeWeights(input, blockPtr); if (blockData.part_num > 1) { SelectPartition(input, blockPtr); } ApplicateColor(blockPtr, output); } }
private unsafe static void ApplicateColor(BlockData *block, uint *output) { if (block->dual_plane != 0) { int *ps = stackalloc int[] { 0, 0, 0, 0 }; ps[block->plane_selector] = 1; if (block->part_num > 1) { for (int i = 0; i < block->bw * block->bh; i++) { int p = block->partition[i]; byte r = SelectColor(block->endpoints[p * 8 + 0], block->endpoints[p * 8 + 4], block->weights[i * 2 + ps[0]]); byte g = SelectColor(block->endpoints[p * 8 + 1], block->endpoints[p * 8 + 5], block->weights[i * 2 + ps[1]]); byte b = SelectColor(block->endpoints[p * 8 + 2], block->endpoints[p * 8 + 6], block->weights[i * 2 + ps[2]]); byte a = SelectColor(block->endpoints[p * 8 + 3], block->endpoints[p * 8 + 7], block->weights[i * 2 + ps[3]]); output[i] = Color(r, g, b, a); } } else { for (int i = 0; i < block->bw * block->bh; i++) { byte r = SelectColor(block->endpoints[0], block->endpoints[4], block->weights[i * 2 + ps[0]]); byte g = SelectColor(block->endpoints[1], block->endpoints[5], block->weights[i * 2 + ps[1]]); byte b = SelectColor(block->endpoints[2], block->endpoints[6], block->weights[i * 2 + ps[2]]); byte a = SelectColor(block->endpoints[3], block->endpoints[7], block->weights[i * 2 + ps[3]]); output[i] = Color(r, g, b, a); } } } else if (block->part_num > 1) { for (int i = 0; i < block->bw * block->bh; i++) { int p = block->partition[i]; byte r = SelectColor(block->endpoints[p * 8 + 0], block->endpoints[p * 8 + 4], block->weights[i * 2]); byte g = SelectColor(block->endpoints[p * 8 + 1], block->endpoints[p * 8 + 5], block->weights[i * 2]); byte b = SelectColor(block->endpoints[p * 8 + 2], block->endpoints[p * 8 + 6], block->weights[i * 2]); byte a = SelectColor(block->endpoints[p * 8 + 3], block->endpoints[p * 8 + 7], block->weights[i * 2]); output[i] = Color(r, g, b, a); } } else { for (int i = 0; i < block->bw * block->bh; i++) { byte r = SelectColor(block->endpoints[0], block->endpoints[4], block->weights[i * 2]); byte g = SelectColor(block->endpoints[1], block->endpoints[5], block->weights[i * 2]); byte b = SelectColor(block->endpoints[2], block->endpoints[6], block->weights[i * 2]); byte a = SelectColor(block->endpoints[3], block->endpoints[7], block->weights[i * 2]); output[i] = Color(r, g, b, a); } } }
private unsafe static void SelectPartition(byte *input, BlockData *block) { bool small_block = block->bw * block->bh < 31; int seed = (*((int *)input) >> 13 & 0x3ff) | (block->part_num - 1) << 10; uint rnum; unchecked { rnum = (uint)seed; rnum ^= rnum >> 15; rnum -= rnum << 17; rnum += rnum << 7; rnum += rnum << 4; rnum ^= rnum >> 5; rnum += rnum << 16; rnum ^= rnum >> 7; rnum ^= rnum >> 3; rnum ^= rnum << 6; rnum ^= rnum >> 17; } int *seeds = stackalloc int[8]; for (int i = 0; i < 8; i++) { seeds[i] = (int)((rnum >> (i * 4)) & 0xF); seeds[i] *= seeds[i]; } int *sh = stackalloc int[2]; sh[0] = (seed & 2) != 0 ? 4 : 5; sh[1] = block->part_num == 3 ? 6 : 5; if ((seed & 1) != 0) { for (int i = 0; i < 8; i++) { seeds[i] >>= sh[i % 2]; } } else { for (int i = 0; i < 8; i++) { seeds[i] >>= sh[1 - i % 2]; } } if (small_block) { for (int t = 0, i = 0; t < block->bh; t++) { for (int s = 0; s < block->bw; s++, i++) { int x = s << 1; int y = t << 1; int a = (int)((seeds[0] * x + seeds[1] * y + (rnum >> 14)) & 0x3f); int b = (int)((seeds[2] * x + seeds[3] * y + (rnum >> 10)) & 0x3f); int c = (int)(block->part_num < 3 ? 0 : (seeds[4] * x + seeds[5] * y + (rnum >> 6)) & 0x3f); int d = (int)(block->part_num < 4 ? 0 : (seeds[6] * x + seeds[7] * y + (rnum >> 2)) & 0x3f); block->partition[i] = (a >= b && a >= c && a >= d) ? 0 : (b >= c && b >= d) ? 1 : (c >= d) ? 2 : 3; } } } else { for (int y = 0, i = 0; y < block->bh; y++) { for (int x = 0; x < block->bw; x++, i++) { int a = (int)((seeds[0] * x + seeds[1] * y + (rnum >> 14)) & 0x3f); int b = (int)((seeds[2] * x + seeds[3] * y + (rnum >> 10)) & 0x3f); int c = (int)(block->part_num < 3 ? 0 : (seeds[4] * x + seeds[5] * y + (rnum >> 6)) & 0x3f); int d = (int)(block->part_num < 4 ? 0 : (seeds[6] * x + seeds[7] * y + (rnum >> 2)) & 0x3f); block->partition[i] = (a >= b && a >= c && a >= d) ? 0 : (b >= c && b >= d) ? 1 : (c >= d) ? 2 : 3; } } } }
private unsafe static void DecodeEndpoints(byte *input, BlockData *pBlock) { IntSeqData *epSeq = stackalloc IntSeqData[32]; DecodeIntseq(input, pBlock->part_num == 1 ? 17 : 29, CemTableA[pBlock->cem_range], CemTableB[pBlock->cem_range], pBlock->endpoint_value_num, false, epSeq); int *ev = stackalloc int[32]; switch (CemTableA[pBlock->cem_range]) { case 3: for (int i = 0, b = 0, c = DETritsTable[CemTableB[pBlock->cem_range]]; i < pBlock->endpoint_value_num; i++) { int a = (epSeq[i].bits & 1) * 0x1ff; int x = epSeq[i].bits >> 1; switch (CemTableB[pBlock->cem_range]) { case 1: b = 0; break; case 2: b = 0b100010110 * x; break; case 3: b = x << 7 | x << 2 | x; break; case 4: b = x << 6 | x; break; case 5: b = x << 5 | x >> 2; break; case 6: b = x << 4 | x >> 4; break; } ev[i] = (a & 0x80) | ((epSeq[i].nonbits * c + b) ^ a) >> 2; } break; case 5: for (int i = 0, b = 0, c = DEQuintsTable[CemTableB[pBlock->cem_range]]; i < pBlock->endpoint_value_num; i++) { int a = (epSeq[i].bits & 1) * 0x1ff; int x = epSeq[i].bits >> 1; switch (CemTableB[pBlock->cem_range]) { case 1: b = 0; break; case 2: b = 0b100001100 * x; break; case 3: b = x << 7 | x << 1 | x >> 1; break; case 4: b = x << 6 | x >> 1; break; case 5: b = x << 5 | x >> 3; break; } ev[i] = (a & 0x80) | ((epSeq[i].nonbits * c + b) ^ a) >> 2; } break; default: switch (CemTableB[pBlock->cem_range]) { case 1: for (int i = 0; i < pBlock->endpoint_value_num; i++) { ev[i] = epSeq[i].bits * 0xff; } break; case 2: for (int i = 0; i < pBlock->endpoint_value_num; i++) { ev[i] = epSeq[i].bits * 0x55; } break; case 3: for (int i = 0; i < pBlock->endpoint_value_num; i++) { ev[i] = epSeq[i].bits << 5 | epSeq[i].bits << 2 | epSeq[i].bits >> 1; } break; case 4: for (int i = 0; i < pBlock->endpoint_value_num; i++) { ev[i] = epSeq[i].bits << 4 | epSeq[i].bits; } break; case 5: for (int i = 0; i < pBlock->endpoint_value_num; i++) { ev[i] = epSeq[i].bits << 3 | epSeq[i].bits >> 2; } break; case 6: for (int i = 0; i < pBlock->endpoint_value_num; i++) { ev[i] = epSeq[i].bits << 2 | epSeq[i].bits >> 4; } break; case 7: for (int i = 0; i < pBlock->endpoint_value_num; i++) { ev[i] = epSeq[i].bits << 1 | epSeq[i].bits >> 6; } break; case 8: for (int i = 0; i < pBlock->endpoint_value_num; i++) { ev[i] = epSeq[i].bits; } break; } break; } int *v = ev; for (int cem = 0, cemOff = 0; cem < pBlock->part_num; v += (pBlock->cem[cem] / 4 + 1) * 2, cem++, cemOff += 8) { switch (pBlock->cem[cem]) { case 0: SetEndpoint(&pBlock->endpoints[cemOff], v[0], v[0], v[0], 255, v[1], v[1], v[1], 255); break; case 1: { int l0 = (v[0] >> 2) | (v[1] & 0xc0); int l1 = Clamp(l0 + (v[1] & 0x3f)); SetEndpoint(&pBlock->endpoints[cemOff], l0, l0, l0, 255, l1, l1, l1, 255); } break; case 4: SetEndpoint(&pBlock->endpoints[cemOff], v[0], v[0], v[0], v[2], v[1], v[1], v[1], v[3]); break; case 5: BitTransferSigned(&v[1], &v[0]); BitTransferSigned(&v[3], &v[2]); v[1] += v[0]; SetEndpointClamp(&pBlock->endpoints[cemOff], v[0], v[0], v[0], v[2], v[1], v[1], v[1], v[2] + v[3]); break; case 6: SetEndpoint(&pBlock->endpoints[cemOff], v[0] * v[3] >> 8, v[1] * v[3] >> 8, v[2] * v[3] >> 8, 255, v[0], v[1], v[2], 255); break; case 8: if (v[0] + v[2] + v[4] <= v[1] + v[3] + v[5]) { SetEndpoint(&pBlock->endpoints[cemOff], v[0], v[2], v[4], 255, v[1], v[3], v[5], 255); } else { SetEndpointBlue(&pBlock->endpoints[cemOff], v[1], v[3], v[5], 255, v[0], v[2], v[4], 255); } break; case 9: BitTransferSigned(&v[1], &v[0]); BitTransferSigned(&v[3], &v[2]); BitTransferSigned(&v[5], &v[4]); if (v[1] + v[3] + v[5] >= 0) { SetEndpointClamp(&pBlock->endpoints[cemOff], v[0], v[2], v[4], 255, v[0] + v[1], v[2] + v[3], v[4] + v[5], 255); } else { SetEndpointBlueClamp(&pBlock->endpoints[cemOff], v[0] + v[1], v[2] + v[3], v[4] + v[5], 255, v[0], v[2], v[4], 255); } break; case 10: SetEndpoint(&pBlock->endpoints[cemOff], v[0] * v[3] >> 8, v[1] * v[3] >> 8, v[2] * v[3] >> 8, v[4], v[0], v[1], v[2], v[5]); break; case 12: if (v[0] + v[2] + v[4] <= v[1] + v[3] + v[5]) { SetEndpoint(&pBlock->endpoints[cemOff], v[0], v[2], v[4], v[6], v[1], v[3], v[5], v[7]); } else { SetEndpointBlue(&pBlock->endpoints[cemOff], v[1], v[3], v[5], v[7], v[0], v[2], v[4], v[6]); } break; case 13: BitTransferSigned(&v[1], &v[0]); BitTransferSigned(&v[3], &v[2]); BitTransferSigned(&v[5], &v[4]); BitTransferSigned(&v[7], &v[6]); if (v[1] + v[3] + v[5] >= 0) { SetEndpointClamp(&pBlock->endpoints[cemOff], v[0], v[2], v[4], v[6], v[0] + v[1], v[2] + v[3], v[4] + v[5], v[6] + v[7]); } else { SetEndpointBlueClamp(&pBlock->endpoints[cemOff], v[0] + v[1], v[2] + v[3], v[4] + v[5], v[6] + v[7], v[0], v[2], v[4], v[6]); } break; } } }
private unsafe static void DecodeWeights(byte *input, BlockData *block) { IntSeqData *wSeq = stackalloc IntSeqData[128]; DecodeIntseq(input, 128, WeightPrecTableA[block->weight_range], WeightPrecTableB[block->weight_range], block->weight_num, true, wSeq); int *wv = stackalloc int[128]; if (WeightPrecTableA[block->weight_range] == 0) { switch (WeightPrecTableB[block->weight_range]) { case 1: for (int i = 0; i < block->weight_num; i++) { wv[i] = wSeq[i].bits != 0 ? 63 : 0; } break; case 2: for (int i = 0; i < block->weight_num; i++) { wv[i] = wSeq[i].bits << 4 | wSeq[i].bits << 2 | wSeq[i].bits; } break; case 3: for (int i = 0; i < block->weight_num; i++) { wv[i] = wSeq[i].bits << 3 | wSeq[i].bits; } break; case 4: for (int i = 0; i < block->weight_num; i++) { wv[i] = wSeq[i].bits << 2 | wSeq[i].bits >> 2; } break; case 5: for (int i = 0; i < block->weight_num; i++) { wv[i] = wSeq[i].bits << 1 | wSeq[i].bits >> 4; } break; } for (int i = 0; i < block->weight_num; i++) { if (wv[i] > 32) { ++wv[i]; } } } else if (WeightPrecTableB[block->weight_range] == 0) { int s = WeightPrecTableA[block->weight_range] == 3 ? 32 : 16; for (int i = 0; i < block->weight_num; i++) { wv[i] = wSeq[i].nonbits * s; } } else { if (WeightPrecTableA[block->weight_range] == 3) { switch (WeightPrecTableB[block->weight_range]) { case 1: for (int i = 0; i < block->weight_num; i++) { wv[i] = wSeq[i].nonbits * 50; } break; case 2: for (int i = 0; i < block->weight_num; i++) { wv[i] = wSeq[i].nonbits * 23; if ((wSeq[i].bits & 2) != 0) { wv[i] += 0b1000101; } } break; case 3: for (int i = 0; i < block->weight_num; i++) { wv[i] = wSeq[i].nonbits * 11 + ((wSeq[i].bits << 4 | wSeq[i].bits >> 1) & 0b1100011); } break; } } else if (WeightPrecTableA[block->weight_range] == 5) { switch (WeightPrecTableB[block->weight_range]) { case 1: for (int i = 0; i < block->weight_num; i++) { wv[i] = wSeq[i].nonbits * 28; } break; case 2: for (int i = 0; i < block->weight_num; i++) { wv[i] = wSeq[i].nonbits * 13; if ((wSeq[i].bits & 2) != 0) { wv[i] += 0b1000010; } } break; } } for (int i = 0; i < block->weight_num; i++) { int a = (wSeq[i].bits & 1) * 0x7f; wv[i] = (a & 0x20) | ((wv[i] ^ a) >> 2); if (wv[i] > 32) { ++wv[i]; } } } int ds = (1024 + block->bw / 2) / (block->bw - 1); int dt = (1024 + block->bh / 2) / (block->bh - 1); int pn = block->dual_plane != 0 ? 2 : 1; for (int t = 0, i = 0; t < block->bh; t++) { for (int s = 0; s < block->bw; s++, i++) { int gs = (ds * s * (block->width - 1) + 32) >> 6; int gt = (dt * t * (block->height - 1) + 32) >> 6; int fs = gs & 0xf; int ft = gt & 0xf; int v = (gs >> 4) + (gt >> 4) * block->width; int w11 = (fs * ft + 8) >> 4; int w10 = ft - w11; int w01 = fs - w11; int w00 = 16 - fs - ft + w11; for (int p = 0; p < pn; p++) { int p00 = wv[v * pn + p]; int p01 = wv[(v + 1) * pn + p]; int p10 = wv[(v + block->width) * pn + p]; int p11 = wv[(v + block->width + 1) * pn + p]; block->weights[i * 2 + p] = (p00 * w00 + p01 * w01 + p10 * w10 + p11 * w11 + 8) >> 4; } } } }
private unsafe static void DecodeBlockParameters(byte *input, BlockData *pBlock) { pBlock->dual_plane = (input[1] & 4) >> 2; pBlock->weight_range = (input[0] >> 4 & 1) | (input[1] << 2 & 8); if ((input[0] & 3) != 0) { pBlock->weight_range |= input[0] << 1 & 6; switch (input[0] & 0xc) { case 0: pBlock->width = (*((int *)input) >> 7 & 3) + 4; pBlock->height = (input[0] >> 5 & 3) + 2; break; case 4: pBlock->width = (*((int *)input) >> 7 & 3) + 8; pBlock->height = (input[0] >> 5 & 3) + 2; break; case 8: pBlock->width = (input[0] >> 5 & 3) + 2; pBlock->height = (*((int *)input) >> 7 & 3) + 8; break; case 12: if ((input[1] & 1) != 0) { pBlock->width = (input[0] >> 7 & 1) + 2; pBlock->height = (input[0] >> 5 & 3) + 2; } else { pBlock->width = (input[0] >> 5 & 3) + 2; pBlock->height = (input[0] >> 7 & 1) + 6; } break; } } else { pBlock->weight_range |= input[0] >> 1 & 6; switch ((*((int *)input)) & 0x180) { case 0: pBlock->width = 12; pBlock->height = (input[0] >> 5 & 3) + 2; break; case 0x80: pBlock->width = (input[0] >> 5 & 3) + 2; pBlock->height = 12; break; case 0x100: pBlock->width = (input[0] >> 5 & 3) + 6; pBlock->height = (input[1] >> 1 & 3) + 6; pBlock->dual_plane = 0; pBlock->weight_range &= 7; break; case 0x180: pBlock->width = (input[0] & 0x20) != 0 ? 10 : 6; pBlock->height = (input[0] & 0x20) != 0 ? 6 : 10; break; } } pBlock->part_num = (input[1] >> 3 & 3) + 1; pBlock->weight_num = pBlock->width * pBlock->height; if (pBlock->dual_plane != 0) { pBlock->weight_num *= 2; } int weight_bits, config_bits, cem_base = 0; switch (WeightPrecTableA[pBlock->weight_range]) { case 3: weight_bits = pBlock->weight_num * WeightPrecTableB[pBlock->weight_range] + (pBlock->weight_num * 8 + 4) / 5; break; case 5: weight_bits = pBlock->weight_num * WeightPrecTableB[pBlock->weight_range] + (pBlock->weight_num * 7 + 2) / 3; break; default: weight_bits = pBlock->weight_num * WeightPrecTableB[pBlock->weight_range]; break; } if (pBlock->part_num == 1) { pBlock->cem[0] = *((int *)(input + 1)) >> 5 & 0xf; config_bits = 17; } else { cem_base = *((int *)(input + 2)) >> 7 & 3; if (cem_base == 0) { int cem = input[3] >> 1 & 0xf; for (int i = 0; i < pBlock->part_num; i++) { pBlock->cem[i] = cem; } config_bits = 29; } else { for (int i = 0; i < pBlock->part_num; i++) { pBlock->cem[i] = ((input[3] >> (i + 1) & 1) + cem_base - 1) << 2; } switch (pBlock->part_num) { case 2: pBlock->cem[0] |= input[3] >> 3 & 3; pBlock->cem[1] |= GetBits(input, 126 - weight_bits, 2); break; case 3: pBlock->cem[0] |= input[3] >> 4 & 1; pBlock->cem[0] |= GetBits(input, 122 - weight_bits, 2) & 2; pBlock->cem[1] |= GetBits(input, 124 - weight_bits, 2); pBlock->cem[2] |= GetBits(input, 126 - weight_bits, 2); break; case 4: for (int i = 0; i < 4; i++) { pBlock->cem[i] |= GetBits(input, 120 + i * 2 - weight_bits, 2); } break; } config_bits = 25 + pBlock->part_num * 3; } } if (pBlock->dual_plane != 0) { config_bits += 2; pBlock->plane_selector = GetBits(input, cem_base != 0 ? 130 - weight_bits - pBlock->part_num * 3 : 126 - weight_bits, 2); } int remain_bits = 128 - config_bits - weight_bits; pBlock->endpoint_value_num = 0; for (int i = 0; i < pBlock->part_num; i++) { pBlock->endpoint_value_num += (pBlock->cem[i] >> 1 & 6) + 2; } for (int i = 0, endpoint_bits; i < CemTableA.Length; i++) { switch (CemTableA[i]) { case 3: endpoint_bits = pBlock->endpoint_value_num * CemTableB[i] + (pBlock->endpoint_value_num * 8 + 4) / 5; break; case 5: endpoint_bits = pBlock->endpoint_value_num * CemTableB[i] + (pBlock->endpoint_value_num * 7 + 2) / 3; break; default: endpoint_bits = pBlock->endpoint_value_num * CemTableB[i]; break; } if (endpoint_bits <= remain_bits) { pBlock->cem_range = i; break; } } }
internal static void Release(BlockData *data) { Marshal.FreeHGlobal((IntPtr)data); }
public bool DoDecompression() { var pools = Globals.WorkPool.GetPool(Chunk.ThreadID); var provider = Chunk.world.blockProvider; if (IsDifferential) { int blockPosSize = StructSerialization.TSSize <BlockPos> .ValueSize; int blockDataSize = StructSerialization.TSSize <BlockData> .ValueSize; m_positionsModified = new BlockPos[m_positionsBytes.Length / blockPosSize]; m_blocksModified = new BlockData[m_blocksBytes.Length / blockDataSize]; int i, j; unsafe { // Extract positions fixed(byte *pSrc = m_positionsBytes) { for (i = 0, j = 0; j < m_positionsModified.Length; i += blockPosSize, j++) { m_positionsModified[j] = *(BlockPos *)&pSrc[i]; } } // Extract block data fixed(byte *pSrc = m_blocksBytes) { for (i = 0, j = 0; j < m_blocksModified.Length; i += blockDataSize, j++) { BlockData *bd = (BlockData *)&pSrc[i]; // Convert global block types into internal optimized version ushort type = provider.GetTypeFromTypeInConfig(bd->Type); m_blocksModified[j] = new BlockData(type, bd->Solid); } } } } else { int blockDataSize = StructSerialization.TSSize <BlockData> .ValueSize; int requestedByteSize = Env.ChunkSizePow3 * blockDataSize; // Pop a large enough buffers from the pool var bytes = pools.ByteArrayPool.Pop(requestedByteSize); { // Decompress data int decompressedLength = CLZF2.lzf_decompress(m_blocksBytes, m_blocksBytes.Length, ref bytes); if (decompressedLength != Env.ChunkSizePow3 * blockDataSize) { m_blocksBytes = null; return(false); } // Fill chunk with decompressed data ChunkBlocks blocks = Chunk.Blocks; int i = 0; unsafe { fixed(byte *pSrc = bytes) { int index = Helpers.ZeroChunkIndex; int yOffset = Env.ChunkSizeWithPaddingPow2 - Env.ChunkSize * Env.ChunkSizeWithPadding; int zOffset = Env.ChunkSizeWithPadding - Env.ChunkSize; for (int y = 0; y < Env.ChunkSize; ++y, index += yOffset) { for (int z = 0; z < Env.ChunkSize; ++z, index += zOffset) { for (int x = 0; x < Env.ChunkSize; ++x, i += blockDataSize, ++index) { BlockData *bd = (BlockData *)&pSrc[i]; // Convert global block type into internal optimized version ushort type = provider.GetTypeFromTypeInConfig(bd->Type); blocks.SetRaw(index, new BlockData(type, bd->Solid)); } } } } } } // Return our temporary buffer back to the pool pools.ByteArrayPool.Push(bytes); } ResetTemporary(); return(true); }
public bool DoCompression() { if (Features.UseDifferentialSerialization) { var provider = Chunk.world.blockProvider; int blockPosSize = StructSerialization.TSSize <BlockPos> .ValueSize; int blockDataSize = StructSerialization.TSSize <BlockData> .ValueSize; int posLenBytes = m_blocksModified.Length * blockPosSize; int blkLenBytes = m_blocksModified.Length * blockDataSize; m_positionsBytes = new byte[posLenBytes]; m_blocksBytes = new byte[blkLenBytes]; unsafe { // Pack positions to a byte array fixed(byte *pDst = m_positionsBytes) { for (int i = 0, j = 0; i < m_blocksModified.Length; i++, j += blockPosSize) { *(BlockPos *)&pDst[j] = m_positionsModified[i]; } } // Pack block data to a byte array fixed(BlockData *pBD = m_blocksModified) fixed(byte *pDst = m_blocksBytes) { for (int i = 0, j = 0; i < m_blocksModified.Length; i++, j += blockDataSize) { BlockData *bd = &pBD[i]; // Convert block types from internal optimized version into global types ushort typeInConfig = provider.GetConfig(bd->Type).typeInConfig; *(BlockData *)&pDst[j] = new BlockData(typeInConfig, bd->Solid); } } } } else { var pools = Globals.WorkPool.GetPool(Chunk.ThreadID); var provider = Chunk.world.blockProvider; int blockDataSize = StructSerialization.TSSize <BlockData> .ValueSize; int requestedByteSize = Env.ChunkSizePow3 * blockDataSize; // Pop large enough buffers from the pool byte[] tmp = pools.ByteArrayPool.Pop(requestedByteSize); byte[] bytesCompressed = pools.ByteArrayPool.Pop(requestedByteSize); { ChunkBlocks blocks = Chunk.Blocks; int i = 0; int index = Helpers.ZeroChunkIndex; int yOffset = Env.ChunkSizeWithPaddingPow2 - Env.ChunkSize * Env.ChunkSizeWithPadding; int zOffset = Env.ChunkSizeWithPadding - Env.ChunkSize; for (int y = 0; y < Env.ChunkSize; ++y, index += yOffset) { for (int z = 0; z < Env.ChunkSize; ++z, index += zOffset) { for (int x = 0; x < Env.ChunkSize; ++x, i += blockDataSize, ++index) { BlockData bd = blocks.Get(index); // Convert block types from internal optimized version into global types ushort typeInConfig = provider.GetConfig(bd.Type).typeInConfig; // Write updated block data to destination buffer unsafe { fixed(byte *pDst = tmp) { *(BlockData *)&pDst[i] = new BlockData(typeInConfig, bd.Solid); } } } } } // Compress bytes int blkLenBytes = CLZF2.lzf_compress(tmp, requestedByteSize, ref bytesCompressed); m_blocksBytes = new byte[blkLenBytes]; // Copy data from a temporary buffer to block buffer Array.Copy(bytesCompressed, 0, m_blocksBytes, 0, blkLenBytes); } // Return our temporary buffer back to the pool pools.ByteArrayPool.Push(bytesCompressed); pools.ByteArrayPool.Push(tmp); } return(true); }
public bool DoDecompression() { LocalPools pools = Globals.WorkPool.GetPool(Chunk.ThreadID); BlockProvider provider = Chunk.World.blockProvider; if (IsDifferential) { int blockPosSize = StructSerialization.TSSize <BlockPos> .ValueSize; int blockDataSize = StructSerialization.TSSize <BlockData> .ValueSize; positionsModified = new BlockPos[positionsBytes.Length / blockPosSize]; blocksModified = new BlockData[blocksBytes.Length / blockDataSize]; int i, j; unsafe { // Extract positions fixed(byte *pSrc = positionsBytes) { for (i = 0, j = 0; j < positionsModified.Length; i += blockPosSize, j++) { positionsModified[j] = *(BlockPos *)&pSrc[i]; Chunk.Blocks.modifiedBlocks.Add(positionsModified[j]); } } // Extract block data fixed(byte *pSrc = blocksBytes) { for (i = 0, j = 0; j < blocksModified.Length; i += blockDataSize, j++) { BlockData *bd = (BlockData *)&pSrc[i]; // Convert global block types into internal optimized version ushort type = provider.GetTypeFromTypeInConfig(bd->Type); blocksModified[j] = new BlockData(type, bd->Solid); } } } } else { int blockDataSize = StructSerialization.TSSize <BlockData> .ValueSize; int requestedByteSize = Env.CHUNK_SIZE_POW_3 * blockDataSize; // Pop a large enough buffers from the pool byte[] bytes = pools.byteArrayPool.Pop(requestedByteSize); { // Decompress data int decompressedLength = CLZF2.lzf_decompress(blocksBytes, blocksBytes.Length, ref bytes); if (decompressedLength != Env.CHUNK_SIZE_POW_3 * blockDataSize) { blocksBytes = null; return(false); } // Fill chunk with decompressed data ChunkBlocks blocks = Chunk.Blocks; int i = 0; unsafe { fixed(byte *pSrc = bytes) { int index = Helpers.ZERO_CHUNK_INDEX; int yOffset = Env.CHUNK_SIZE_WITH_PADDING_POW_2 - Env.CHUNK_SIZE * Env.CHUNK_SIZE_WITH_PADDING; int zOffset = Env.CHUNK_SIZE_WITH_PADDING - Env.CHUNK_SIZE; for (int y = 0; y < Env.CHUNK_SIZE; ++y, index += yOffset) { for (int z = 0; z < Env.CHUNK_SIZE; ++z, index += zOffset) { for (int x = 0; x < Env.CHUNK_SIZE; ++x, i += blockDataSize, ++index) { BlockData *bd = (BlockData *)&pSrc[i]; // Convert global block type into internal optimized version ushort type = provider.GetTypeFromTypeInConfig(bd->Type); blocks.SetRaw(index, new BlockData(type, bd->Solid)); } } } } } } // Return our temporary buffer back to the pool pools.byteArrayPool.Push(bytes); } ResetTemporary(); return(true); }