PocketMine-MP  1.4 - API 1.10.0
 All Classes Namespaces Functions Variables Pages
leveldb/Chunk.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 
22 namespace pocketmine\level\format\leveldb;
23 
29 
30 class Chunk extends BaseFullChunk{
31 
32  protected $isPopulated = false;
33  protected $isGenerated = false;
34 
35  public function __construct($level, $chunkX, $chunkZ, $terrain, array $entityData = null, array $tileData = null){
36  $heightMap = array_fill(0, 256, 127);
37 
38  $offset = 0;
39 
40  $blocks = substr($terrain, $offset, 32768);
41  $offset += 32768;
42  $data = substr($terrain, $offset, 16384);
43  $offset += 16384;
44  $skyLight = substr($terrain, $offset, 16384);
45  $offset += 16384;
46  $blockLight = substr($terrain, $offset, 16384);
47  $offset += 16384;
48  $biomes = substr($terrain, $offset, 256);
49  $offset += 256;
50 
51  $biomeColors = [];
52  foreach(unpack("N*", substr($terrain, $offset, 1024)) as $c){
53  $biomeColors[] = $c;
54  }
55  $offset += 1024;
56 
57  parent::__construct($level, $chunkX, $chunkZ, $blocks, $data, $skyLight, $blockLight, $biomes, $biomeColors, $heightMap, $entityData === null ? [] : $entityData, $tileData === null ? [] : $tileData);
58  }
59 
60  public function getBlockId($x, $y, $z){
61  return ord($this->blocks{($x << 11) | ($z << 7) | $y});
62  }
63 
64  public function setBlockId($x, $y, $z, $id){
65  $this->blocks{($x << 11) | ($z << 7) | $y} = chr($id);
66  $this->hasChanged = true;
67  }
68 
69  public function getBlockData($x, $y, $z){
70  $m = ord($this->data{($x << 10) | ($z << 6) | ($y >> 1)});
71  if(($y & 1) === 0){
72  return $m & 0x0F;
73  }else{
74  return $m >> 4;
75  }
76  }
77 
78  public function setBlockData($x, $y, $z, $data){
79  $i = ($x << 10) | ($z << 6) | ($y >> 1);
80  $old_m = ord($this->data{$i});
81  if(($y & 1) === 0){
82  $this->data{$i} = chr(($old_m & 0xf0) | ($data & 0x0f));
83  }else{
84  $this->data{$i} = chr((($data & 0x0f) << 4) | ($old_m & 0x0f));
85  }
86  $this->hasChanged = true;
87  }
88 
89  public function getFullBlock($x, $y, $z){
90  $i = ($x << 11) | ($z << 7) | $y;
91  if(($y & 1) === 0){
92  return (ord($this->blocks{$i}) << 4) | (ord($this->data{$i >> 1}) & 0x0F);
93  }else{
94  return (ord($this->blocks{$i}) << 4) | (ord($this->data{$i >> 1}) >> 4);
95  }
96  }
97 
98  public function getBlock($x, $y, $z, &$blockId, &$meta = null){
99  $full = $this->getFullBlock($x, $y, $z);
100  $blockId = $full >> 4;
101  $meta = $full & 0x0f;
102  }
103 
104  public function setBlock($x, $y, $z, $blockId = null, $meta = null){
105  $i = ($x << 11) | ($z << 7) | $y;
106 
107  $changed = false;
108 
109  if($blockId !== null){
110  $blockId = chr($blockId);
111  if($this->blocks{$i} !== $blockId){
112  $this->blocks{$i} = $blockId;
113  $changed = true;
114  }
115  }
116 
117  if($meta !== null){
118  $i >>= 1;
119  $old_m = ord($this->data{$i});
120  if(($y & 1) === 0){
121  $this->data{$i} = chr(($old_m & 0xf0) | ($meta & 0x0f));
122  if(($old_m & 0x0f) !== $meta){
123  $changed = true;
124  }
125  }else{
126  $this->data{$i} = chr((($meta & 0x0f) << 4) | ($old_m & 0x0f));
127  if((($old_m & 0xf0) >> 4) !== $meta){
128  $changed = true;
129  }
130  }
131  }
132 
133  if($changed){
134  $this->hasChanged = true;
135  }
136 
137  return $changed;
138  }
139 
140  public function getBlockSkyLight($x, $y, $z){
141  $sl = ord($this->skyLight{($x << 10) | ($z << 6) | ($y >> 1)});
142  if(($y & 1) === 0){
143  return $sl & 0x0F;
144  }else{
145  return $sl >> 4;
146  }
147  }
148 
149  public function setBlockSkyLight($x, $y, $z, $level){
150  $i = ($x << 10) | ($z << 6) | ($y >> 1);
151  $old_sl = ord($this->skyLight{$i});
152  if(($y & 1) === 0){
153  $this->skyLight{$i} = chr(($old_sl & 0xf0) | ($level & 0x0f));
154  }else{
155  $this->skyLight{$i} = chr((($level & 0x0f) << 4) | ($old_sl & 0x0f));
156  }
157  $this->hasChanged = true;
158  }
159 
160  public function getBlockLight($x, $y, $z){
161  $l = ord($this->blockLight{($x << 10) | ($z << 6) | ($y >> 1)});
162  if(($y & 1) === 0){
163  return $l & 0x0F;
164  }else{
165  return $l >> 4;
166  }
167  }
168 
169  public function setBlockLight($x, $y, $z, $level){
170  $i = ($x << 10) | ($z << 6) | ($y >> 1);
171  $old_l = ord($this->blockLight{$i});
172  if(($y & 1) === 0){
173  $this->blockLight{$i} = chr(($old_l & 0xf0) | ($level & 0x0f));
174  }else{
175  $this->blockLight{$i} = chr((($level & 0x0f) << 4) | ($old_l & 0x0f));
176  }
177  $this->hasChanged = true;
178  }
179 
180  public function getBlockIdColumn($x, $z){
181  return substr($this->blocks, ($x << 11) + ($z << 7), 128);
182  }
183 
184  public function getBlockDataColumn($x, $z){
185  return substr($this->data, ($x << 10) + ($z << 6), 64);
186  }
187 
188  public function getBlockSkyLightColumn($x, $z){
189  return substr($this->skyLight, ($x << 10) + ($z << 6), 64);
190  }
191 
192  public function getBlockLightColumn($x, $z){
193  return substr($this->blockLight, ($x << 10) + ($z << 6), 64);
194  }
195 
199  public function isPopulated(){
200  return $this->isPopulated;
201  }
202 
206  public function setPopulated($value = 1){
207  $this->isPopulated = (bool) $value;
208  }
209 
213  public function isGenerated(){
214  return $this->isGenerated;
215  }
216 
220  public function setGenerated($value = 1){
221  $this->isGenerated = (bool) $value;
222  }
223 
230  public static function fromBinary($data, LevelProvider $provider = null){
231  try{
232  $chunkX = Binary::readLInt(substr($data, 0, 4));
233  $chunkZ = Binary::readLInt(substr($data, 4, 4));
234  $chunkData = substr($data, 8, -1);
235 
236  $flags = ord(substr($data, -1));
237 
238  $entities = null;
239  $tiles = null;
240 
241  if($provider instanceof LevelDB){
242  $nbt = new NBT(NBT::LITTLE_ENDIAN);
243 
244  $entityData = $provider->getDatabase()->get(substr($data, 0, 8) . "\x32");
245  if($entityData !== false and strlen($entityData) > 0){
246  $nbt->read($entityData, true);
247  $entities = $nbt->getData();
248  if(!is_array($entities)){
249  $entities = [$entities];
250  }
251  }
252  $tileData = $provider->getDatabase()->get(substr($data, 0, 8) . "\x31");
253  if($tileData !== false and strlen($tileData) > 0){
254  $nbt->read($tileData, true);
255  $tiles = $nbt->getData();
256  if(!is_array($tiles)){
257  $tiles = [$tiles];
258  }
259  }
260  }
261 
262  $chunk = new Chunk($provider instanceof LevelProvider ? $provider : LevelDB::class, $chunkX, $chunkZ, $chunkData, $entities, $tiles);
263  if($flags & 0x01){
264  $chunk->setGenerated();
265  }
266  if($flags & 0x02){
267  $chunk->setPopulated();
268  }
269  return $chunk;
270  }catch(\Exception $e){
271  echo $e;
272  return null;
273  }
274  }
275 
276  public function toBinary($saveExtra = false){
277  $chunkIndex = LevelDB::chunkIndex($this->getX(), $this->getZ());
278 
279  $provider = $this->getProvider();
280  if($saveExtra and $provider instanceof LevelDB){
281  $nbt = new NBT(NBT::LITTLE_ENDIAN);
282  $entities = [];
283 
284  foreach($this->getEntities() as $entity){
285  if(!($entity instanceof Player) and !$entity->closed){
286  $entity->saveNBT();
287  $nbt->setData($entity->namedtag);
288  $entities[] = $nbt->write();
289  }
290  }
291 
292  if(count($entities) > 0){
293  $provider->getDatabase()->put($chunkIndex . "\x32", implode($entities));
294  }else{
295  $provider->getDatabase()->delete($chunkIndex . "\x32");
296  }
297 
298 
299  $tiles = [];
300  foreach($this->getTiles() as $tile){
301  $tile->saveNBT();
302  $nbt->setData($tile->namedtag);
303  $tiles[] = $nbt->write();
304  }
305 
306  if(count($tiles) > 0){
307  $provider->getDatabase()->put($chunkIndex . "\x31", implode($tiles));
308  }else{
309  $provider->getDatabase()->delete($chunkIndex . "\x31");
310  }
311 
312 
313  }
314 
315  $biomeColors = pack("N*", ...$this->getBiomeColorArray());
316 
317  return $chunkIndex .
318  $this->getBlockIdArray() .
319  $this->getBlockDataArray() .
320  $this->getBlockSkyLightArray() .
321  $this->getBlockLightArray() .
322  $this->getBiomeIdArray() .
323  $biomeColors . chr(
324  ($this->isPopulated() ? 0x02 : 0) | ($this->isGenerated() ? 0x01 : 0)
325  );
326  }
327 }
static fromBinary($data, LevelProvider $provider=null)
getBlock($x, $y, $z, &$blockId, &$meta=null)
setBlock($x, $y, $z, $blockId=null, $meta=null)