PocketMine-MP 5.15.1 git-08c6e63aac45a450fe3b437616ee8aa2500e04e2
FastChunkSerializer.php
1<?php
2
3/*
4 *
5 * ____ _ _ __ __ _ __ __ ____
6 * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
7 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
8 * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
9 * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
10 *
11 * This program is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation, either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * @author PocketMine Team
17 * @link http://www.pocketmine.net/
18 *
19 *
20 */
21
22declare(strict_types=1);
23
24namespace pocketmine\world\format\io;
25
29use pocketmine\world\format\PalettedBlockArray;
31use function array_values;
32use function count;
33use function pack;
34use function strlen;
35use function unpack;
36
42 private const FLAG_POPULATED = 1 << 1;
43
44 private function __construct(){
45 //NOOP
46 }
47
48 private static function serializePalettedArray(BinaryStream $stream, PalettedBlockArray $array) : void{
49 $wordArray = $array->getWordArray();
50 $palette = $array->getPalette();
51
52 $stream->putByte($array->getBitsPerBlock());
53 $stream->put($wordArray);
54 $serialPalette = pack("L*", ...$palette);
55 $stream->putInt(strlen($serialPalette));
56 $stream->put($serialPalette);
57 }
58
63 public static function serializeTerrain(Chunk $chunk) : string{
64 $stream = new BinaryStream();
65 $stream->putByte(
66 ($chunk->isPopulated() ? self::FLAG_POPULATED : 0)
67 );
68
69 //subchunks
70 $subChunks = $chunk->getSubChunks();
71 $count = count($subChunks);
72 $stream->putByte($count);
73
74 foreach($subChunks as $y => $subChunk){
75 $stream->putByte($y);
76 $stream->putInt($subChunk->getEmptyBlockId());
77 $layers = $subChunk->getBlockLayers();
78 $stream->putByte(count($layers));
79 foreach($layers as $blocks){
80 self::serializePalettedArray($stream, $blocks);
81 }
82 self::serializePalettedArray($stream, $subChunk->getBiomeArray());
83
84 }
85
86 return $stream->getBuffer();
87 }
88
89 private static function deserializePalettedArray(BinaryStream $stream) : PalettedBlockArray{
90 $bitsPerBlock = $stream->getByte();
91 $words = $stream->get(PalettedBlockArray::getExpectedWordArraySize($bitsPerBlock));
93 $unpackedPalette = unpack("L*", $stream->get($stream->getInt())); //unpack() will never fail here
94 $palette = array_values($unpackedPalette);
95
96 return PalettedBlockArray::fromData($bitsPerBlock, $words, $palette);
97 }
98
102 public static function deserializeTerrain(string $data) : Chunk{
103 $stream = new BinaryStream($data);
104
105 $flags = $stream->getByte();
106 $terrainPopulated = (bool) ($flags & self::FLAG_POPULATED);
107
108 $subChunks = [];
109
110 $count = $stream->getByte();
111 for($subCount = 0; $subCount < $count; ++$subCount){
112 $y = Binary::signByte($stream->getByte());
113 $airBlockId = $stream->getInt();
114
116 $layers = [];
117 for($i = 0, $layerCount = $stream->getByte(); $i < $layerCount; ++$i){
118 $layers[] = self::deserializePalettedArray($stream);
119 }
120 $biomeArray = self::deserializePalettedArray($stream);
121 $subChunks[$y] = new SubChunk($airBlockId, $layers, $biomeArray);
122 }
123
124 return new Chunk($subChunks, $terrainPopulated);
125 }
126}