PocketMine-MP  1.4 - API 1.10.0
 All Classes Namespaces Functions Variables Pages
mcregion/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\mcregion;
23 
35 
36 class Chunk extends BaseFullChunk{
37 
39  protected $nbt;
40 
41  public function __construct($level, Compound $nbt){
42  $this->nbt = $nbt;
43 
44  if(isset($this->nbt->Entities) and $this->nbt->Entities instanceof Enum){
45  $this->nbt->Entities->setTagType(NBT::TAG_Compound);
46  }else{
47  $this->nbt->Entities = new Enum("Entities", []);
48  $this->nbt->Entities->setTagType(NBT::TAG_Compound);
49  }
50 
51  if(isset($this->nbt->TileEntities) and $this->nbt->TileEntities instanceof Enum){
52  $this->nbt->TileEntities->setTagType(NBT::TAG_Compound);
53  }else{
54  $this->nbt->TileEntities = new Enum("TileEntities", []);
55  $this->nbt->TileEntities->setTagType(NBT::TAG_Compound);
56  }
57 
58  if(isset($this->nbt->TileTicks) and $this->nbt->TileTicks instanceof Enum){
59  $this->nbt->TileTicks->setTagType(NBT::TAG_Compound);
60  }else{
61  $this->nbt->TileTicks = new Enum("TileTicks", []);
62  $this->nbt->TileTicks->setTagType(NBT::TAG_Compound);
63  }
64 
65  if(!isset($this->nbt->Biomes) or !($this->nbt->Biomes instanceof ByteArray)){
66  $this->nbt->Biomes = new ByteArray("Biomes", str_repeat("\x01", 256));
67  }
68 
69  if(!isset($this->nbt->BiomeColors) or !($this->nbt->BiomeColors instanceof IntArray)){
70  $this->nbt->BiomeColors = new IntArray("BiomeColors", array_fill(0, 256, Binary::readInt("\x00\x85\xb2\x4a")));
71  }
72 
73  if(!isset($this->nbt->HeightMap) or !($this->nbt->HeightMap instanceof IntArray)){
74  $this->nbt->HeightMap = new IntArray("HeightMap", array_fill(0, 256, 127));
75  }
76 
77  if(!isset($this->nbt->Blocks)){
78  $this->nbt->Blocks = new ByteArray("Blocks", str_repeat("\x00", 32768));
79  }
80 
81  if(!isset($this->nbt->Data)){
82  $this->nbt->Data = new ByteArray("Data", $half = str_repeat("\x00", 16384));
83  $this->nbt->SkyLight = new ByteArray("SkyLight", $half);
84  $this->nbt->BlockLight = new ByteArray("BlockLight", $half);
85  }
86 
87  parent::__construct($level, $this->nbt["xPos"], $this->nbt["zPos"], $this->nbt->Blocks->getValue(), $this->nbt->Data->getValue(), $this->nbt->SkyLight->getValue(), $this->nbt->BlockLight->getValue(), $this->nbt->Biomes->getValue(), $this->nbt->BiomeColors->getValue(), $this->nbt->HeightMap->getValue(), $this->nbt->Entities->getValue(), $this->nbt->TileEntities->getValue());
88  unset($this->nbt->Blocks);
89  unset($this->nbt->Data);
90  unset($this->nbt->SkyLight);
91  unset($this->nbt->BlockLight);
92  }
93 
94  public function getBlockId($x, $y, $z){
95  return ord($this->blocks{($x << 11) | ($z << 7) | $y});
96  }
97 
98  public function setBlockId($x, $y, $z, $id){
99  $this->blocks{($x << 11) | ($z << 7) | $y} = chr($id);
100  $this->hasChanged = true;
101  }
102 
103  public function getBlockData($x, $y, $z){
104  $m = ord($this->data{($x << 10) | ($z << 6) | ($y >> 1)});
105  if(($y & 1) === 0){
106  return $m & 0x0F;
107  }else{
108  return $m >> 4;
109  }
110  }
111 
112  public function setBlockData($x, $y, $z, $data){
113  $i = ($x << 10) | ($z << 6) | ($y >> 1);
114  $old_m = ord($this->data{$i});
115  if(($y & 1) === 0){
116  $this->data{$i} = chr(($old_m & 0xf0) | ($data & 0x0f));
117  }else{
118  $this->data{$i} = chr((($data & 0x0f) << 4) | ($old_m & 0x0f));
119  }
120  $this->hasChanged = true;
121  }
122 
123  public function getFullBlock($x, $y, $z){
124  $i = ($x << 11) | ($z << 7) | $y;
125  if(($y & 1) === 0){
126  return (ord($this->blocks{$i}) << 4) | (ord($this->data{$i >> 1}) & 0x0F);
127  }else{
128  return (ord($this->blocks{$i}) << 4) | (ord($this->data{$i >> 1}) >> 4);
129  }
130  }
131 
132  public function getBlock($x, $y, $z, &$blockId, &$meta = null){
133  $full = $this->getFullBlock($x, $y, $z);
134  $blockId = $full >> 4;
135  $meta = $full & 0x0f;
136  }
137 
138  public function setBlock($x, $y, $z, $blockId = null, $meta = null){
139  $i = ($x << 11) | ($z << 7) | $y;
140 
141  $changed = false;
142 
143  if($blockId !== null){
144  $blockId = chr($blockId);
145  if($this->blocks{$i} !== $blockId){
146  $this->blocks{$i} = $blockId;
147  $changed = true;
148  }
149  }
150 
151  if($meta !== null){
152  $i >>= 1;
153  $old_m = ord($this->data{$i});
154  if(($y & 1) === 0){
155  $this->data{$i} = chr(($old_m & 0xf0) | ($meta & 0x0f));
156  if(($old_m & 0x0f) !== $meta){
157  $changed = true;
158  }
159  }else{
160  $this->data{$i} = chr((($meta & 0x0f) << 4) | ($old_m & 0x0f));
161  if((($old_m & 0xf0) >> 4) !== $meta){
162  $changed = true;
163  }
164  }
165  }
166 
167  if($changed){
168  $this->hasChanged = true;
169  }
170 
171  return $changed;
172  }
173 
174  public function getBlockSkyLight($x, $y, $z){
175  $sl = ord($this->skyLight{($x << 10) | ($z << 6) | ($y >> 1)});
176  if(($y & 1) === 0){
177  return $sl & 0x0F;
178  }else{
179  return $sl >> 4;
180  }
181  }
182 
183  public function setBlockSkyLight($x, $y, $z, $level){
184  $i = ($x << 10) | ($z << 6) | ($y >> 1);
185  $old_sl = ord($this->skyLight{$i});
186  if(($y & 1) === 0){
187  $this->skyLight{$i} = chr(($old_sl & 0xf0) | ($level & 0x0f));
188  }else{
189  $this->skyLight{$i} = chr((($level & 0x0f) << 4) | ($old_sl & 0x0f));
190  }
191  $this->hasChanged = true;
192  }
193 
194  public function getBlockLight($x, $y, $z){
195  $l = ord($this->blockLight{($x << 10) | ($z << 6) | ($y >> 1)});
196  if(($y & 1) === 0){
197  return $l & 0x0F;
198  }else{
199  return $l >> 4;
200  }
201  }
202 
203  public function setBlockLight($x, $y, $z, $level){
204  $i = ($x << 10) | ($z << 6) | ($y >> 1);
205  $old_l = ord($this->blockLight{$i});
206  if(($y & 1) === 0){
207  $this->blockLight{$i} = chr(($old_l & 0xf0) | ($level & 0x0f));
208  }else{
209  $this->blockLight{$i} = chr((($level & 0x0f) << 4) | ($old_l & 0x0f));
210  }
211  $this->hasChanged = true;
212  }
213 
214  public function getBlockIdColumn($x, $z){
215  return substr($this->blocks, ($x << 11) + ($z << 7), 128);
216  }
217 
218  public function getBlockDataColumn($x, $z){
219  return substr($this->data, ($x << 10) + ($z << 6), 64);
220  }
221 
222  public function getBlockSkyLightColumn($x, $z){
223  return substr($this->skyLight, ($x << 10) + ($z << 6), 64);
224  }
225 
226  public function getBlockLightColumn($x, $z){
227  return substr($this->blockLight, ($x << 10) + ($z << 6), 64);
228  }
229 
233  public function isPopulated(){
234  return $this->nbt["TerrainPopulated"] > 0;
235  }
236 
240  public function setPopulated($value = 1){
241  $this->nbt->TerrainPopulated = new Byte("TerrainPopulated", $value);
242  }
243 
247  public function isGenerated(){
248  return $this->nbt["TerrainPopulated"] > 0 or (isset($this->nbt->TerrainGenerated) and $this->nbt["TerrainGenerated"] > 0);
249  }
250 
254  public function setGenerated($value = 1){
255  $this->nbt->TerrainGenerated = new Byte("TerrainGenerated", $value);
256  }
257 
264  public static function fromBinary($data, LevelProvider $provider = null){
265  $nbt = new NBT(NBT::BIG_ENDIAN);
266 
267  try{
268  $nbt->readCompressed($data, ZLIB_ENCODING_DEFLATE);
269  $chunk = $nbt->getData();
270 
271  if(!isset($chunk->Level) or !($chunk->Level instanceof Compound)){
272  return null;
273  }
274 
275  return new Chunk($provider instanceof LevelProvider ? $provider : McRegion::class, $chunk->Level);
276  }catch(\Exception $e){
277  return null;
278  }
279  }
280 
281  public function toBinary(){
282  $nbt = clone $this->getNBT();
283 
284  $nbt->xPos = new Int("xPos", $this->x);
285  $nbt->zPos = new Int("zPos", $this->z);
286 
287  if($this->isGenerated()){
288  $nbt->Blocks = new ByteArray("Blocks", $this->getBlockIdArray());
289  $nbt->Data = new ByteArray("Data", $this->getBlockDataArray());
290  $nbt->SkyLight = new ByteArray("SkyLight", $this->getBlockSkyLightArray());
291  $nbt->BlockLight = new ByteArray("BlockLight", $this->getBlockLightArray());
292 
293  $nbt->Biomes = new ByteArray("Biomes", $this->getBiomeIdArray());
294  $nbt->BiomeColors = new IntArray("BiomeColors", $this->getBiomeColorArray());
295 
296  $nbt->HeightMap = new IntArray("HeightMap", $this->getHeightMapArray());
297  }
298 
299  $entities = [];
300 
301  foreach($this->getEntities() as $entity){
302  if(!($entity instanceof Player) and !$entity->closed){
303  $entity->saveNBT();
304  $entities[] = $entity->namedtag;
305  }
306  }
307 
308  $nbt->Entities = new Enum("Entities", $entities);
309  $nbt->Entities->setTagType(NBT::TAG_Compound);
310 
311 
312  $tiles = [];
313  foreach($this->getTiles() as $tile){
314  $tile->saveNBT();
315  $tiles[] = $tile->namedtag;
316  }
317 
318  $nbt->TileEntities = new Enum("TileEntities", $tiles);
319  $nbt->TileEntities->setTagType(NBT::TAG_Compound);
320  $writer = new NBT(NBT::BIG_ENDIAN);
321  $nbt->setName("Level");
322  $writer->setData(new Compound("", ["Level" => $nbt]));
323 
324  return $writer->writeCompressed(ZLIB_ENCODING_DEFLATE, RegionLoader::$COMPRESSION_LEVEL);
325  }
326 
330  public function getNBT(){
331  return $this->nbt;
332  }
333 }
static fromBinary($data, LevelProvider $provider=null)
setBlock($x, $y, $z, $blockId=null, $meta=null)
getBlock($x, $y, $z, &$blockId, &$meta=null)