mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-04 00:55:14 +00:00
Removed SimpleChunk from generator, core, use binary representation of chunks
This commit is contained in:
@ -141,7 +141,7 @@ namespace pocketmine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gc_disable();
|
gc_enable();
|
||||||
error_reporting(-1);
|
error_reporting(-1);
|
||||||
ini_set("allow_url_fopen", 1);
|
ini_set("allow_url_fopen", 1);
|
||||||
ini_set("display_errors", 1);
|
ini_set("display_errors", 1);
|
||||||
|
@ -1830,7 +1830,6 @@ class Server{
|
|||||||
$lastLoop = 0;
|
$lastLoop = 0;
|
||||||
$connectionTimer = Timings::$connectionTimer;
|
$connectionTimer = Timings::$connectionTimer;
|
||||||
while($this->isRunning){
|
while($this->isRunning){
|
||||||
|
|
||||||
$connectionTimer->startTiming();
|
$connectionTimer->startTiming();
|
||||||
foreach($this->interfaces as $interface){
|
foreach($this->interfaces as $interface){
|
||||||
if($interface->process()){
|
if($interface->process()){
|
||||||
|
@ -40,7 +40,6 @@ use pocketmine\level\format\Chunk;
|
|||||||
use pocketmine\level\format\FullChunk;
|
use pocketmine\level\format\FullChunk;
|
||||||
use pocketmine\level\format\generic\EmptyChunkSection;
|
use pocketmine\level\format\generic\EmptyChunkSection;
|
||||||
use pocketmine\level\format\LevelProvider;
|
use pocketmine\level\format\LevelProvider;
|
||||||
use pocketmine\level\format\SimpleChunk;
|
|
||||||
use pocketmine\level\generator\Generator;
|
use pocketmine\level\generator\Generator;
|
||||||
use pocketmine\math\AxisAlignedBB;
|
use pocketmine\math\AxisAlignedBB;
|
||||||
use pocketmine\math\Vector2;
|
use pocketmine\math\Vector2;
|
||||||
@ -1292,51 +1291,17 @@ class Level implements ChunkManager, Metadatable{
|
|||||||
return isset($this->chunks[$index = "$x:$z"]) ? $this->chunks[$index] : $this->chunks[$index] = $this->provider->getChunk($x, $z, $create);
|
return isset($this->chunks[$index = "$x:$z"]) ? $this->chunks[$index] : $this->chunks[$index] = $this->provider->getChunk($x, $z, $create);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function generateChunkCallback($x, $z, FullChunk $chunk){
|
||||||
* @param int $x
|
|
||||||
* @param int $z
|
|
||||||
* @param bool $create
|
|
||||||
*
|
|
||||||
* @return SimpleChunk
|
|
||||||
*/
|
|
||||||
public function getChunk($x, $z, $create = false){
|
|
||||||
$chunk = $this->getChunkAt($x, $z, $create);
|
|
||||||
if($chunk === null){
|
|
||||||
return new SimpleChunk($x, $z, 0);
|
|
||||||
}else{
|
|
||||||
$flags = SimpleChunk::FLAG_GENERATED;
|
|
||||||
if($this->isChunkPopulated($x, $z)){
|
|
||||||
$flags |= SimpleChunk::FLAG_POPULATED;
|
|
||||||
}
|
|
||||||
$blockIds = [];
|
|
||||||
$data = [];
|
|
||||||
|
|
||||||
if(!$this->useSections){
|
|
||||||
//TODO
|
|
||||||
return new SimpleChunk($x, $z, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
for($Y = 0; $Y < 8; ++$Y){
|
|
||||||
$section = $chunk->getSection($Y);
|
|
||||||
$blockIds[$Y] = $section->getIdArray();
|
|
||||||
$data[$Y] = $section->getDataArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
return new SimpleChunk($x, $z, $flags, $blockIds, $data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function generateChunkCallback($x, $z, SimpleChunk $chunk){
|
|
||||||
unset($this->chunkGenerationQueue["$x:$z"]);
|
unset($this->chunkGenerationQueue["$x:$z"]);
|
||||||
$this->setChunk($x, $z, $chunk);
|
$this->setChunk($x, $z, $chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setChunk($x, $z, SimpleChunk $chunk){
|
public function setChunk($x, $z, FullChunk $chunk){
|
||||||
$index = Level::chunkHash($x, $z);
|
$index = Level::chunkHash($x, $z);
|
||||||
foreach($this->getUsingChunk($x, $z) as $player){
|
foreach($this->getUsingChunk($x, $z) as $player){
|
||||||
$player->unloadChunk($x, $z);
|
$player->unloadChunk($x, $z);
|
||||||
}
|
}
|
||||||
unset($this->chunks[Level::chunkHash($x, $z)]);
|
unset($this->chunks[$index]);
|
||||||
$this->provider->setChunk($x, $z, $chunk);
|
$this->provider->setChunk($x, $z, $chunk);
|
||||||
$this->loadChunk($x, $z);
|
$this->loadChunk($x, $z);
|
||||||
}
|
}
|
||||||
|
@ -1,93 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
*
|
|
||||||
* ____ _ _ __ __ _ __ __ ____
|
|
||||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
|
||||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
|
||||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
|
||||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* @author PocketMine Team
|
|
||||||
* @link http://www.pocketmine.net/
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace pocketmine\level\format;
|
|
||||||
|
|
||||||
interface ChunkSnapshot{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
public function getX();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
public function getZ();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getLevelName();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param int $x 0-15
|
|
||||||
* @param int $y 0-127
|
|
||||||
* @param int $z 0-15
|
|
||||||
*
|
|
||||||
* @return int 0-255
|
|
||||||
*/
|
|
||||||
public function getBlockId($x, $y, $z);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param int $x 0-15
|
|
||||||
* @param int $y 0-127
|
|
||||||
* @param int $z 0-15
|
|
||||||
*
|
|
||||||
* @return int 0-15
|
|
||||||
*/
|
|
||||||
public function getBlockData($x, $y, $z);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param int $x 0-15
|
|
||||||
* @param int $y 0-127
|
|
||||||
* @param int $z 0-15
|
|
||||||
*
|
|
||||||
* @return int 0-15
|
|
||||||
*/
|
|
||||||
public function getBlockSkyLight($x, $y, $z);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param int $x 0-15
|
|
||||||
* @param int $y 0-127
|
|
||||||
* @param int $z 0-15
|
|
||||||
*
|
|
||||||
* @return int 0-15
|
|
||||||
*/
|
|
||||||
public function getBlockLight($x, $y, $z);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param int $x 0-15
|
|
||||||
* @param int $z 0-15
|
|
||||||
*
|
|
||||||
* @return int 0-127
|
|
||||||
*/
|
|
||||||
public function getHighestBlockAt($x, $z);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param int $x 0-15
|
|
||||||
* @param int $z 0-15
|
|
||||||
*
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
public function getBiome($x, $z);
|
|
||||||
|
|
||||||
}
|
|
@ -36,6 +36,10 @@ interface FullChunk{
|
|||||||
*/
|
*/
|
||||||
public function getZ();
|
public function getZ();
|
||||||
|
|
||||||
|
public function setX($x);
|
||||||
|
|
||||||
|
public function setZ($z);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return \pocketmine\level\format\LevelProvider
|
* @return \pocketmine\level\format\LevelProvider
|
||||||
*/
|
*/
|
||||||
@ -179,16 +183,13 @@ interface FullChunk{
|
|||||||
*/
|
*/
|
||||||
public function setBiomeColor($x, $z, $R, $G, $B);
|
public function setBiomeColor($x, $z, $R, $G, $B);
|
||||||
|
|
||||||
/**
|
public function isPopulated();
|
||||||
* Thread-safe read-only chunk
|
|
||||||
*
|
public function setPopulated($value = 1);
|
||||||
* @param bool $includeMaxBlockY
|
|
||||||
* @param bool $includeBiome
|
public function isGenerated();
|
||||||
* @param bool $includeBiomeTemp
|
|
||||||
*
|
public function setGenerated($value = 1);
|
||||||
* @return ChunkSnapshot
|
|
||||||
*/
|
|
||||||
public function getChunkSnapshot($includeMaxBlockY = true, $includeBiome = false, $includeBiomeTemp = false);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Entity $entity
|
* @param Entity $entity
|
||||||
@ -260,4 +261,14 @@ interface FullChunk{
|
|||||||
|
|
||||||
public function getBlockLightArray();
|
public function getBlockLightArray();
|
||||||
|
|
||||||
|
public function toBinary();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $data
|
||||||
|
* @param LevelProvider $provider
|
||||||
|
*
|
||||||
|
* @return FullChunk
|
||||||
|
*/
|
||||||
|
public static function fromBinary($data, LevelProvider $provider = null);
|
||||||
|
|
||||||
}
|
}
|
@ -115,7 +115,7 @@ interface LevelProvider{
|
|||||||
*
|
*
|
||||||
* @return ChunkSection
|
* @return ChunkSection
|
||||||
*/
|
*/
|
||||||
public function createChunkSection($Y);
|
public static function createChunkSection($Y);
|
||||||
|
|
||||||
public function saveChunks();
|
public function saveChunks();
|
||||||
|
|
||||||
@ -170,13 +170,13 @@ interface LevelProvider{
|
|||||||
public function isChunkLoaded($X, $Z);
|
public function isChunkLoaded($X, $Z);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param int $chunkX
|
* @param int $chunkX
|
||||||
* @param int $chunkZ
|
* @param int $chunkZ
|
||||||
* @param SimpleChunk $chunk
|
* @param FullChunk $chunk
|
||||||
*
|
*
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public function setChunk($chunkX, $chunkZ, SimpleChunk $chunk);
|
public function setChunk($chunkX, $chunkZ, FullChunk $chunk);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return string
|
* @return string
|
||||||
|
@ -1,259 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
*
|
|
||||||
* ____ _ _ __ __ _ __ __ ____
|
|
||||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
|
||||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
|
||||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
|
||||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* @author PocketMine Team
|
|
||||||
* @link http://www.pocketmine.net/
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace pocketmine\level\format;
|
|
||||||
|
|
||||||
use pocketmine\utils\Binary;
|
|
||||||
|
|
||||||
class SimpleChunk{
|
|
||||||
|
|
||||||
const FLAG_GENERATED = 1;
|
|
||||||
const FLAG_POPULATED = 2;
|
|
||||||
|
|
||||||
protected static $HEIGHT = 8;
|
|
||||||
|
|
||||||
/** @var string[] */
|
|
||||||
protected $ids;
|
|
||||||
/** @var string[] */
|
|
||||||
protected $meta;
|
|
||||||
|
|
||||||
protected $x;
|
|
||||||
protected $z;
|
|
||||||
|
|
||||||
protected $flags = 0;
|
|
||||||
|
|
||||||
protected $changed = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param int $chunkX
|
|
||||||
* @param int $chunkZ
|
|
||||||
* @param int $flags
|
|
||||||
* @param string[] $ids
|
|
||||||
* @param string[] $meta
|
|
||||||
*/
|
|
||||||
public function __construct($chunkX, $chunkZ, $flags = 0, array $ids = [], array $meta = []){
|
|
||||||
$this->x = $chunkX;
|
|
||||||
$this->z = $chunkZ;
|
|
||||||
$this->flags = $flags;
|
|
||||||
for($y = 0; $y < self::$HEIGHT; ++$y){
|
|
||||||
$this->ids[$y] = (isset($ids[$y]) and strlen($ids[$y]) === 4096) ? $ids[$y] : str_repeat("\x00", 4096);
|
|
||||||
$this->meta[$y] = (isset($meta[$y]) and strlen($meta[$y]) === 2048) ? $meta[$y] : str_repeat("\x00", 2048);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function hasChanged($set = true){
|
|
||||||
if($this->changed === true and $set === true){
|
|
||||||
$this->changed = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->changed;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
public function getX(){
|
|
||||||
return $this->x;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
public function getZ(){
|
|
||||||
return $this->z;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param int $x
|
|
||||||
*/
|
|
||||||
public function setX($x){
|
|
||||||
$this->x = $x;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param int $z
|
|
||||||
*/
|
|
||||||
public function setZ($z){
|
|
||||||
$this->z = $z;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function isGenerated(){
|
|
||||||
return ($this->flags & self::FLAG_GENERATED) > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function isPopulated(){
|
|
||||||
return ($this->flags & self::FLAG_POPULATED) > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param bool $value
|
|
||||||
*/
|
|
||||||
public function setGenerated($value = true){
|
|
||||||
$this->changed = true;
|
|
||||||
$this->flags = ($this->flags & ~self::FLAG_GENERATED) | ($value === true ? self::FLAG_GENERATED : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param bool $value
|
|
||||||
*/
|
|
||||||
public function setPopulated($value = true){
|
|
||||||
$this->changed = true;
|
|
||||||
$this->flags = ($this->flags & ~self::FLAG_POPULATED) | ($value === true ? self::FLAG_POPULATED : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param int $x 0-15
|
|
||||||
* @param int $y 0-127
|
|
||||||
* @param int $z 0-15
|
|
||||||
*
|
|
||||||
* @return int 0-255
|
|
||||||
*/
|
|
||||||
public function getBlockId($x, $y, $z){
|
|
||||||
return ord(@$this->ids[$y >> 4]{(($y & 0x0f) << 8) + ($z << 4) + $x});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param int $x 0-15
|
|
||||||
* @param int $y 0-127
|
|
||||||
* @param int $z 0-15
|
|
||||||
* @param int $blockId 0-255
|
|
||||||
*/
|
|
||||||
public function setBlockId($x, $y, $z, $blockId){
|
|
||||||
$this->changed = true;
|
|
||||||
@$this->ids[$y >> 4]{(($y & 0x0f) << 8) + ($z << 4) + $x} = chr($blockId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param int $x 0-15
|
|
||||||
* @param int $y 0-127
|
|
||||||
* @param int $z 0-15
|
|
||||||
*
|
|
||||||
* @return int 0-15
|
|
||||||
*/
|
|
||||||
public function getBlockData($x, $y, $z){
|
|
||||||
$m = ord($this->meta[$y >> 4]{(($y & 0x0f) << 7) + ($z << 3) + ($x >> 1)});
|
|
||||||
if(($x & 1) === 0){
|
|
||||||
return $m & 0x0F;
|
|
||||||
}else{
|
|
||||||
return $m >> 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param int $x 0-15
|
|
||||||
* @param int $y 0-127
|
|
||||||
* @param int $z 0-15
|
|
||||||
* @param int $data 0-15
|
|
||||||
*/
|
|
||||||
public function setBlockData($x, $y, $z, $data){
|
|
||||||
$this->changed = true;
|
|
||||||
$i = (($y & 0x0f) << 7) + ($z << 3) + ($x >> 1);
|
|
||||||
$old_m = ord($this->meta[$y >> 4]{$i});
|
|
||||||
if(($x & 1) === 0){
|
|
||||||
$this->meta[$y >> 4]{$i} = chr(($old_m & 0xf0) | ($data & 0x0f));
|
|
||||||
}else{
|
|
||||||
$this->meta[$y >> 4]{$i} = chr((($data & 0x0f) << 4) | ($old_m & 0x0f));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param int $y 0-7
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getSectionIds($y){
|
|
||||||
return $this->ids[$y];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param int $y 0-7
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getSectionData($y){
|
|
||||||
return $this->meta[$y];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param int $y 0-7
|
|
||||||
* @param string $ids
|
|
||||||
* @param string $meta
|
|
||||||
*/
|
|
||||||
public function setSection($y, $ids = null, $meta = null){
|
|
||||||
$this->changed = true;
|
|
||||||
if($ids !== null){
|
|
||||||
$this->ids[$y] = $ids;
|
|
||||||
}
|
|
||||||
|
|
||||||
if($meta !== null){
|
|
||||||
$this->meta[$y] = $meta;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function toBinary(){
|
|
||||||
$binary = Binary::writeInt($this->x) . Binary::writeInt($this->z) . chr($this->flags);
|
|
||||||
if($this->isGenerated()){
|
|
||||||
for($y = 0; $y < self::$HEIGHT; ++$y){
|
|
||||||
$binary .= $this->getSectionIds($y);
|
|
||||||
$binary .= $this->getSectionData($y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $binary;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $binary
|
|
||||||
*
|
|
||||||
* @return SimpleChunk
|
|
||||||
*/
|
|
||||||
public static function fromBinary($binary){
|
|
||||||
$offset = 0;
|
|
||||||
$chunkX = Binary::readInt(substr($binary, $offset, 4));
|
|
||||||
$offset += 4;
|
|
||||||
$chunkZ = Binary::readInt(substr($binary, $offset, 4));
|
|
||||||
$offset += 4;
|
|
||||||
$flags = ord($binary{$offset++});
|
|
||||||
$ids = [];
|
|
||||||
$meta = [];
|
|
||||||
if(($flags & self::FLAG_GENERATED) > 0){
|
|
||||||
for($y = 0; $y < self::$HEIGHT; ++$y){
|
|
||||||
$ids[$y] = substr($binary, $offset, 4096);
|
|
||||||
$offset += 4096;
|
|
||||||
$meta[$y] = substr($binary, $offset, 2048);
|
|
||||||
$offset += 2048;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new SimpleChunk($chunkX, $chunkZ, $flags, $ids, $meta);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -21,19 +21,12 @@
|
|||||||
|
|
||||||
namespace pocketmine\level\format\anvil;
|
namespace pocketmine\level\format\anvil;
|
||||||
|
|
||||||
use pocketmine\level\format\generic\BaseLevelProvider;
|
use pocketmine\level\format\FullChunk;
|
||||||
use pocketmine\level\format\mcregion\McRegion;
|
use pocketmine\level\format\mcregion\McRegion;
|
||||||
use pocketmine\level\format\SimpleChunk;
|
|
||||||
use pocketmine\level\generator\Generator;
|
|
||||||
use pocketmine\level\Level;
|
use pocketmine\level\Level;
|
||||||
use pocketmine\nbt\NBT;
|
|
||||||
use pocketmine\nbt\tag\Byte;
|
use pocketmine\nbt\tag\Byte;
|
||||||
use pocketmine\nbt\tag\ByteArray;
|
use pocketmine\nbt\tag\ByteArray;
|
||||||
use pocketmine\nbt\tag\Compound;
|
use pocketmine\nbt\tag\Compound;
|
||||||
use pocketmine\nbt\tag\Int;
|
|
||||||
use pocketmine\nbt\tag\Long;
|
|
||||||
use pocketmine\nbt\tag\String;
|
|
||||||
use pocketmine\Player;
|
|
||||||
|
|
||||||
class Anvil extends McRegion{
|
class Anvil extends McRegion{
|
||||||
|
|
||||||
@ -105,8 +98,12 @@ class Anvil extends McRegion{
|
|||||||
return parent::getChunk($chunkX, $chunkZ, $create);
|
return parent::getChunk($chunkX, $chunkZ, $create);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setChunk($chunkX, $chunkZ, SimpleChunk $chunk){
|
public function setChunk($chunkX, $chunkZ, FullChunk $chunk){
|
||||||
if($chunk->isGenerated() === false){
|
if(!($chunk instanceof Chunk)){
|
||||||
|
throw new \Exception("Invalid Chunk class");
|
||||||
|
}
|
||||||
|
|
||||||
|
if($chunk->isPopulated() === false){
|
||||||
$this->unloadChunk($chunkX, $chunkZ, false);
|
$this->unloadChunk($chunkX, $chunkZ, false);
|
||||||
$regionX = $regionZ = null;
|
$regionX = $regionZ = null;
|
||||||
self::getRegionIndex($chunkX, $chunkZ, $regionX, $regionZ);
|
self::getRegionIndex($chunkX, $chunkZ, $regionX, $regionZ);
|
||||||
@ -115,26 +112,15 @@ class Anvil extends McRegion{
|
|||||||
$region->removeChunk($chunkX - $region->getX() * 32, $chunkZ - $region->getZ() * 32);
|
$region->removeChunk($chunkX - $region->getX() * 32, $chunkZ - $region->getZ() * 32);
|
||||||
$this->loadChunk($chunkX, $chunkZ);
|
$this->loadChunk($chunkX, $chunkZ);
|
||||||
}else{
|
}else{
|
||||||
$newChunk = $this->getChunk($chunkX, $chunkZ, true);
|
$newChunk = clone $chunk;
|
||||||
for($y = 0; $y < 8; ++$y){
|
$newChunk->setX($chunkX);
|
||||||
$section = new ChunkSection(new Compound(null, [
|
$newChunk->setZ($chunkZ);
|
||||||
"Y" => new Byte("Y", $y),
|
|
||||||
"Blocks" => new ByteArray("Blocks", $chunk->getSectionIds($y)),
|
|
||||||
"Data" => new ByteArray("Data", $chunk->getSectionData($y)),
|
|
||||||
"SkyLight" => new ByteArray("SkyLight", str_repeat("\xff", 2048)), //TODO
|
|
||||||
"BlockLight" => new ByteArray("BlockLight", str_repeat("\x00", 2048)) //TODO
|
|
||||||
]));
|
|
||||||
$newChunk->setSection($y, $section);
|
|
||||||
}
|
|
||||||
if($chunk->isPopulated()){
|
|
||||||
$newChunk->setPopulated(1);
|
|
||||||
}
|
|
||||||
$this->chunks[Level::chunkHash($chunkX, $chunkZ)] = $newChunk;
|
$this->chunks[Level::chunkHash($chunkX, $chunkZ)] = $newChunk;
|
||||||
$this->saveChunk($chunkX, $chunkZ);
|
//$this->saveChunk($chunkX, $chunkZ);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createChunkSection($Y){
|
public static function createChunkSection($Y){
|
||||||
return new ChunkSection(new Compound(null, [
|
return new ChunkSection(new Compound(null, [
|
||||||
"Y" => new Byte("Y", $Y),
|
"Y" => new Byte("Y", $Y),
|
||||||
"Blocks" => new ByteArray("Blocks", str_repeat("\xff", 4096)),
|
"Blocks" => new ByteArray("Blocks", str_repeat("\xff", 4096)),
|
||||||
@ -146,7 +132,7 @@ class Anvil extends McRegion{
|
|||||||
|
|
||||||
public function isChunkGenerated($chunkX, $chunkZ){
|
public function isChunkGenerated($chunkX, $chunkZ){
|
||||||
if(($region = $this->getRegion($chunkX >> 5, $chunkZ >> 5)) instanceof RegionLoader){
|
if(($region = $this->getRegion($chunkX >> 5, $chunkZ >> 5)) instanceof RegionLoader){
|
||||||
return $region->chunkExists($chunkX - $region->getX() * 32, $chunkZ - $region->getZ() * 32);
|
return $region->chunkExists($chunkX - $region->getX() * 32, $chunkZ - $region->getZ() * 32) and $this->getChunk($chunkX - $region->getX() * 32, $chunkZ - $region->getZ() * 32, true)->isGenerated();
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -30,6 +30,7 @@ use pocketmine\nbt\tag\ByteArray;
|
|||||||
use pocketmine\nbt\tag\Compound;
|
use pocketmine\nbt\tag\Compound;
|
||||||
use pocketmine\nbt\tag\Enum;
|
use pocketmine\nbt\tag\Enum;
|
||||||
use pocketmine\nbt\tag\IntArray;
|
use pocketmine\nbt\tag\IntArray;
|
||||||
|
use pocketmine\Player;
|
||||||
use pocketmine\utils\Binary;
|
use pocketmine\utils\Binary;
|
||||||
|
|
||||||
class Chunk extends BaseChunk{
|
class Chunk extends BaseChunk{
|
||||||
@ -37,7 +38,7 @@ class Chunk extends BaseChunk{
|
|||||||
/** @var Compound */
|
/** @var Compound */
|
||||||
protected $nbt;
|
protected $nbt;
|
||||||
|
|
||||||
public function __construct(LevelProvider $level, Compound $nbt){
|
public function __construct($level, Compound $nbt){
|
||||||
$this->nbt = $nbt;
|
$this->nbt = $nbt;
|
||||||
|
|
||||||
if(isset($this->nbt->Entities) and $this->nbt->Entities instanceof Enum){
|
if(isset($this->nbt->Entities) and $this->nbt->Entities instanceof Enum){
|
||||||
@ -108,35 +109,18 @@ class Chunk extends BaseChunk{
|
|||||||
$this->nbt->TerrainPopulated = new Byte("TerrainPopulated", $value);
|
$this->nbt->TerrainPopulated = new Byte("TerrainPopulated", $value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getChunkSnapshot($includeMaxBlockY = true, $includeBiome = false, $includeBiomeTemp = false){
|
/**
|
||||||
$blockId = "";
|
* @return bool
|
||||||
$blockData = "";
|
*/
|
||||||
$blockSkyLight = "";
|
public function isGenerated(){
|
||||||
$blockLight = "";
|
return $this->nbt["TerrainPopulated"] > 0 or (isset($this->nbt->TerrainGenerated) and $this->nbt["TerrainGenerated"] > 0);
|
||||||
$emptySections = [false, false, false, false, false, false, false, false];
|
}
|
||||||
|
|
||||||
$emptyBlocks = str_repeat("\x00", 4096);
|
/**
|
||||||
$emptyHalf = str_repeat("\x00", 2048);
|
* @param int $value
|
||||||
|
*/
|
||||||
foreach($this->sections as $i => $section){
|
public function setGenerated($value = 1){
|
||||||
if($section instanceof EmptyChunkSection){
|
$this->nbt->TerrainGenerated = new Byte("TerrainGenerated", $value);
|
||||||
$blockId .= $emptyBlocks;
|
|
||||||
$blockData .= $emptyHalf;
|
|
||||||
$blockSkyLight .= $emptyHalf;
|
|
||||||
$blockLight .= $emptyHalf;
|
|
||||||
$emptySections[$i] = true;
|
|
||||||
}else{
|
|
||||||
$blockId .= $section->getIdArray();
|
|
||||||
$blockData .= $section->getDataArray();
|
|
||||||
$blockSkyLight .= $section->getSkyLightArray();
|
|
||||||
$blockLight .= $section->getLightArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: maxBlockY, biomeMap, biomeTemp
|
|
||||||
|
|
||||||
//TODO: time
|
|
||||||
return new ChunkSnapshot($this->getX(), $this->getZ(), $this->getLevel()->getName(), 0 /*$this->getLevel()->getTime()*/, $blockId, $blockData, $blockSkyLight, $blockLight, $emptySections, null, null, null, null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -145,4 +129,69 @@ class Chunk extends BaseChunk{
|
|||||||
public function getNBT(){
|
public function getNBT(){
|
||||||
return $this->nbt;
|
return $this->nbt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $data
|
||||||
|
* @param LevelProvider $provider
|
||||||
|
*
|
||||||
|
* @return Chunk
|
||||||
|
*/
|
||||||
|
public static function fromBinary($data, LevelProvider $provider = null){
|
||||||
|
$nbt = new NBT(NBT::BIG_ENDIAN);
|
||||||
|
$nbt->readCompressed($data, ZLIB_ENCODING_DEFLATE);
|
||||||
|
$chunk = $nbt->getData();
|
||||||
|
|
||||||
|
if(!isset($chunk->Level) or !($chunk->Level instanceof Compound)){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Chunk($provider instanceof LevelProvider ? $provider : "pocketmine\\level\\format\\anvil\\Anvil", $chunk->Level);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toBinary(){
|
||||||
|
$nbt = $this->getNBT();
|
||||||
|
|
||||||
|
$nbt->Sections = new Enum("Sections", []);
|
||||||
|
$nbt->Sections->setTagType(NBT::TAG_Compound);
|
||||||
|
foreach($this->getSections() as $section){
|
||||||
|
$nbt->Sections[$section->getY()] = new Compound(null, [
|
||||||
|
"Y" => new Byte("Y", $section->getY()),
|
||||||
|
"Blocks" => new ByteArray("Blocks", $section->getIdArray()),
|
||||||
|
"Data" => new ByteArray("Data", $section->getDataArray()),
|
||||||
|
"BlockLight" => new ByteArray("BlockLight", $section->getLightArray()),
|
||||||
|
"SkyLight" => new ByteArray("SkyLight", $section->getSkyLightArray())
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$nbt->Biomes = new ByteArray("Biomes", $this->getBiomeIdArray());
|
||||||
|
$nbt->BiomeColors = new IntArray("BiomeColors", $this->getBiomeColorArray());
|
||||||
|
|
||||||
|
$entities = [];
|
||||||
|
|
||||||
|
foreach($this->getEntities() as $entity){
|
||||||
|
if(!($entity instanceof Player) and $entity->closed !== true){
|
||||||
|
$entity->saveNBT();
|
||||||
|
$entities[] = $entity->namedtag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$nbt->Entities = new Enum("Entities", $entities);
|
||||||
|
$nbt->Entities->setTagType(NBT::TAG_Compound);
|
||||||
|
|
||||||
|
|
||||||
|
$tiles = [];
|
||||||
|
foreach($this->getTiles() as $tile){
|
||||||
|
if($tile->closed !== true){
|
||||||
|
$tile->saveNBT();
|
||||||
|
$tiles[] = $tile->namedtag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$nbt->Entities = new Enum("TileEntities", $tiles);
|
||||||
|
$nbt->Entities->setTagType(NBT::TAG_Compound);
|
||||||
|
$writer = new NBT(NBT::BIG_ENDIAN);
|
||||||
|
$nbt->setName("Level");
|
||||||
|
$writer->setData(new Compound("", array("Level" => $nbt)));
|
||||||
|
return $writer->writeCompressed(ZLIB_ENCODING_DEFLATE, RegionLoader::$COMPRESSION_LEVEL);
|
||||||
|
}
|
||||||
}
|
}
|
@ -48,7 +48,10 @@ class ChunkRequestTask extends AsyncTask{
|
|||||||
$this->levelId = $levelId;
|
$this->levelId = $levelId;
|
||||||
$this->chunkX = $chunkX;
|
$this->chunkX = $chunkX;
|
||||||
$this->chunkZ = $chunkZ;
|
$this->chunkZ = $chunkZ;
|
||||||
$chunk = $level->getChunk($chunkX, $chunkZ, true);
|
$chunk = $level->getChunk($chunkX, $chunkZ, false);
|
||||||
|
if(!($chunk instanceof Chunk)){
|
||||||
|
throw new \Exception("Invalid Chunk sent");
|
||||||
|
}
|
||||||
$this->biomeIds = $chunk->getBiomeIdArray();
|
$this->biomeIds = $chunk->getBiomeIdArray();
|
||||||
$this->biomeColors = $chunk->getBiomeColorArray();
|
$this->biomeColors = $chunk->getBiomeColorArray();
|
||||||
|
|
||||||
|
@ -1,78 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
*
|
|
||||||
* ____ _ _ __ __ _ __ __ ____
|
|
||||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
|
||||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
|
||||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
|
||||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* @author PocketMine Team
|
|
||||||
* @link http://www.pocketmine.net/
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace pocketmine\level\format\anvil;
|
|
||||||
|
|
||||||
use pocketmine\level\format\generic\BaseChunkSnapshot;
|
|
||||||
|
|
||||||
class ChunkSnapshot extends BaseChunkSnapshot{
|
|
||||||
|
|
||||||
public function getBlockId($x, $y, $z){
|
|
||||||
return ord($this->blockId{
|
|
||||||
(($y >> 4) << 12) //get section index
|
|
||||||
+ ($y << 8) + ($z << 4) + $x //get block index in section
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getBlockData($x, $y, $z){
|
|
||||||
$data = ord($this->blockData{
|
|
||||||
(($y >> 4) << 11) //get section index
|
|
||||||
+ ($y << 7) + ($z << 3) + ($x >> 1) //get block index in section
|
|
||||||
});
|
|
||||||
if(($y & 1) === 0){
|
|
||||||
return $data & 0x0F;
|
|
||||||
}else{
|
|
||||||
return $data >> 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getBlockSkyLight($x, $y, $z){
|
|
||||||
$level = ord($this->skyLight{
|
|
||||||
(($y >> 4) << 11) //get section index
|
|
||||||
+ ($y << 7) + ($z << 3) + ($x >> 1) //get block index in section
|
|
||||||
});
|
|
||||||
if(($y & 1) === 0){
|
|
||||||
return $level & 0x0F;
|
|
||||||
}else{
|
|
||||||
return $level >> 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getBlockLight($x, $y, $z){
|
|
||||||
$level = ord($this->light{
|
|
||||||
(($y >> 4) << 11) //get section index
|
|
||||||
+ ($y << 7) + ($z << 3) + ($x >> 1) //get block index in section
|
|
||||||
});
|
|
||||||
if(($y & 1) === 0){
|
|
||||||
return $level & 0x0F;
|
|
||||||
}else{
|
|
||||||
return $level >> 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getBiome(){
|
|
||||||
return 0; //TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getHighestBlockAt($x, $z){
|
|
||||||
return 127; //TODO
|
|
||||||
}
|
|
||||||
}
|
|
@ -22,6 +22,7 @@
|
|||||||
namespace pocketmine\level\format\anvil;
|
namespace pocketmine\level\format\anvil;
|
||||||
|
|
||||||
use pocketmine\level\format\LevelProvider;
|
use pocketmine\level\format\LevelProvider;
|
||||||
|
use pocketmine\level\format\mcregion\Chunk;
|
||||||
use pocketmine\nbt\NBT;
|
use pocketmine\nbt\NBT;
|
||||||
use pocketmine\nbt\tag\Byte;
|
use pocketmine\nbt\tag\Byte;
|
||||||
use pocketmine\nbt\tag\ByteArray;
|
use pocketmine\nbt\tag\ByteArray;
|
||||||
@ -97,16 +98,9 @@ class RegionLoader extends \pocketmine\level\format\mcregion\RegionLoader{
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$nbt = new NBT(NBT::BIG_ENDIAN);
|
$chunk = Chunk::fromBinary(fread($this->filePointer, $length - 1), $this->levelProvider);
|
||||||
$nbt->readCompressed(fread($this->filePointer, $length - 1), $compression);
|
|
||||||
$chunk = $nbt->getData();
|
|
||||||
|
|
||||||
|
return $chunk instanceof Chunk ? $chunk : false;
|
||||||
if(!isset($chunk->Level) or !($chunk->Level instanceof Compound)){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Chunk($this->levelProvider, $chunk->Level);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function generateChunk($x, $z){
|
public function generateChunk($x, $z){
|
||||||
@ -129,51 +123,15 @@ class RegionLoader extends \pocketmine\level\format\mcregion\RegionLoader{
|
|||||||
$nbt->TileEntities->setTagType(NBT::TAG_Compound);
|
$nbt->TileEntities->setTagType(NBT::TAG_Compound);
|
||||||
$nbt->TileTicks = new Enum("TileTicks", []);
|
$nbt->TileTicks = new Enum("TileTicks", []);
|
||||||
$nbt->TileTicks->setTagType(NBT::TAG_Compound);
|
$nbt->TileTicks->setTagType(NBT::TAG_Compound);
|
||||||
$this->saveChunk($x, $z, $nbt);
|
$writer = new NBT(NBT::BIG_ENDIAN);
|
||||||
|
$nbt->setName("Level");
|
||||||
|
$writer->setData(new Compound("", array("Level" => $nbt)));
|
||||||
|
$chunkData= $writer->writeCompressed(ZLIB_ENCODING_DEFLATE, RegionLoader::$COMPRESSION_LEVEL);
|
||||||
|
$this->saveChunk($x, $z, $chunkData);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function writeChunk(Chunk $chunk){
|
public function writeChunk(Chunk $chunk){
|
||||||
$nbt = $chunk->getNBT();
|
$this->saveChunk($chunk->getX() - ($this->getX() * 32), $chunk->getZ() - ($this->getZ() * 32), $chunk->toBinary());
|
||||||
$nbt->Sections = new Enum("Sections", []);
|
|
||||||
$nbt->Sections->setTagType(NBT::TAG_Compound);
|
|
||||||
foreach($chunk->getSections() as $section){
|
|
||||||
$nbt->Sections[$section->getY()] = new Compound(null, [
|
|
||||||
"Y" => new Byte("Y", $section->getY()),
|
|
||||||
"Blocks" => new ByteArray("Blocks", $section->getIdArray()),
|
|
||||||
"Data" => new ByteArray("Data", $section->getDataArray()),
|
|
||||||
"BlockLight" => new ByteArray("BlockLight", $section->getLightArray()),
|
|
||||||
"SkyLight" => new ByteArray("SkyLight", $section->getSkyLightArray())
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
$nbt->Biomes = new ByteArray("Biomes", $chunk->getBiomeIdArray());
|
|
||||||
$nbt->BiomeColors = new IntArray("BiomeColors", $chunk->getBiomeColorArray());
|
|
||||||
|
|
||||||
$entities = [];
|
|
||||||
|
|
||||||
foreach($chunk->getEntities() as $entity){
|
|
||||||
if(!($entity instanceof Player) and $entity->closed !== true){
|
|
||||||
$entity->saveNBT();
|
|
||||||
$entities[] = $entity->namedtag;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$nbt->Entities = new Enum("Entities", $entities);
|
|
||||||
$nbt->Entities->setTagType(NBT::TAG_Compound);
|
|
||||||
|
|
||||||
|
|
||||||
$tiles = [];
|
|
||||||
foreach($chunk->getTiles() as $tile){
|
|
||||||
if($tile->closed !== true){
|
|
||||||
$tile->saveNBT();
|
|
||||||
$tiles[] = $tile->namedtag;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$nbt->Entities = new Enum("TileEntities", $tiles);
|
|
||||||
$nbt->Entities->setTagType(NBT::TAG_Compound);
|
|
||||||
|
|
||||||
$this->saveChunk($chunk->getX() - ($this->getX() * 32), $chunk->getZ() - ($this->getZ() * 32), $nbt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -70,8 +70,8 @@ abstract class BaseChunk extends BaseFullChunk implements Chunk{
|
|||||||
*
|
*
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
protected function __construct(LevelProvider $level, $x, $z, array $sections, $biomeIds = null, array $biomeColors = [], array $entities = [], array $tiles = []){
|
protected function __construct($level, $x, $z, array $sections, $biomeIds = null, array $biomeColors = [], array $entities = [], array $tiles = []){
|
||||||
$this->level = new \WeakRef($level);
|
$this->level = $level instanceof LevelProvider ? new \WeakRef($level) : $level;
|
||||||
$this->x = (int) $x;
|
$this->x = (int) $x;
|
||||||
$this->z = (int) $z;
|
$this->z = (int) $z;
|
||||||
foreach($sections as $Y => $section){
|
foreach($sections as $Y => $section){
|
||||||
@ -99,46 +99,48 @@ abstract class BaseChunk extends BaseFullChunk implements Chunk{
|
|||||||
$this->biomeColors = array_fill(0, 256, Binary::readInt("\x00\x85\xb2\x4a"));
|
$this->biomeColors = array_fill(0, 256, Binary::readInt("\x00\x85\xb2\x4a"));
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->getLevel()->getLevel()->timings->syncChunkLoadEntitiesTimer->startTiming();
|
if($this->getLevel() instanceof LevelProvider){
|
||||||
foreach($entities as $nbt){
|
$this->getLevel()->getLevel()->timings->syncChunkLoadEntitiesTimer->startTiming();
|
||||||
if($nbt instanceof Compound){
|
foreach($entities as $nbt){
|
||||||
if(!isset($nbt->id)){
|
if($nbt instanceof Compound){
|
||||||
continue;
|
if(!isset($nbt->id)){
|
||||||
}
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if($nbt->id instanceof String){ //New format
|
if($nbt->id instanceof String){ //New format
|
||||||
|
switch($nbt["id"]){
|
||||||
|
case "Item":
|
||||||
|
(new DroppedItem($this, $nbt))->spawnToAll();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}else{ //Old format
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->getLevel()->getLevel()->timings->syncChunkLoadEntitiesTimer->stopTiming();
|
||||||
|
|
||||||
|
$this->getLevel()->getLevel()->timings->syncChunkLoadTileEntitiesTimer->startTiming();
|
||||||
|
foreach($tiles as $nbt){
|
||||||
|
if($nbt instanceof Compound){
|
||||||
|
if(!isset($nbt->id)){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
switch($nbt["id"]){
|
switch($nbt["id"]){
|
||||||
case "Item":
|
case Tile::CHEST:
|
||||||
(new DroppedItem($this, $nbt))->spawnToAll();
|
new Chest($this, $nbt);
|
||||||
|
break;
|
||||||
|
case Tile::FURNACE:
|
||||||
|
new Furnace($this, $nbt);
|
||||||
|
break;
|
||||||
|
case Tile::SIGN:
|
||||||
|
new Sign($this, $nbt);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}else{ //Old format
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
$this->getLevel()->getLevel()->timings->syncChunkLoadTileEntitiesTimer->stopTiming();
|
||||||
}
|
}
|
||||||
$this->getLevel()->getLevel()->timings->syncChunkLoadEntitiesTimer->stopTiming();
|
|
||||||
|
|
||||||
$this->getLevel()->getLevel()->timings->syncChunkLoadTileEntitiesTimer->startTiming();
|
|
||||||
foreach($tiles as $nbt){
|
|
||||||
if($nbt instanceof Compound){
|
|
||||||
if(!isset($nbt->id)){
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
switch($nbt["id"]){
|
|
||||||
case Tile::CHEST:
|
|
||||||
new Chest($this, $nbt);
|
|
||||||
break;
|
|
||||||
case Tile::FURNACE:
|
|
||||||
new Furnace($this, $nbt);
|
|
||||||
break;
|
|
||||||
case Tile::SIGN:
|
|
||||||
new Sign($this, $nbt);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$this->getLevel()->getLevel()->timings->syncChunkLoadTileEntitiesTimer->stopTiming();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getBlock($x, $y, $z, &$blockId, &$meta = null){
|
public function getBlock($x, $y, $z, &$blockId, &$meta = null){
|
||||||
@ -149,7 +151,8 @@ abstract class BaseChunk extends BaseFullChunk implements Chunk{
|
|||||||
try{
|
try{
|
||||||
return $this->sections[$y >> 4]->setBlock($x, $y & 0x0f, $z, $blockId & 0xff, $meta & 0x0f);
|
return $this->sections[$y >> 4]->setBlock($x, $y & 0x0f, $z, $blockId & 0xff, $meta & 0x0f);
|
||||||
}catch(\Exception $e){
|
}catch(\Exception $e){
|
||||||
$this->setSection($Y = $y >> 4, $this->getLevel()->createChunkSection($Y));
|
$level = $this->getLevel();
|
||||||
|
$this->setSection($Y = $y >> 4, $level::createChunkSection($Y));
|
||||||
return $this->setBlock($x, $y, $z, $blockId, $meta);
|
return $this->setBlock($x, $y, $z, $blockId, $meta);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -162,7 +165,8 @@ abstract class BaseChunk extends BaseFullChunk implements Chunk{
|
|||||||
try{
|
try{
|
||||||
$this->sections[$y >> 4]->setBlockId($x, $y & 0x0f, $z, $id);
|
$this->sections[$y >> 4]->setBlockId($x, $y & 0x0f, $z, $id);
|
||||||
}catch(\Exception $e){
|
}catch(\Exception $e){
|
||||||
$this->setSection($Y = $y >> 4, $this->getLevel()->createChunkSection($Y));
|
$level = $this->getLevel();
|
||||||
|
$this->setSection($Y = $y >> 4, $level::createChunkSection($Y));
|
||||||
$this->setBlockId($x, $y, $z, $id);
|
$this->setBlockId($x, $y, $z, $id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -175,7 +179,8 @@ abstract class BaseChunk extends BaseFullChunk implements Chunk{
|
|||||||
try{
|
try{
|
||||||
$this->sections[$y >> 4]->setBlockData($x, $y & 0x0f, $z, $data);
|
$this->sections[$y >> 4]->setBlockData($x, $y & 0x0f, $z, $data);
|
||||||
}catch(\Exception $e){
|
}catch(\Exception $e){
|
||||||
$this->setSection($Y = $y >> 4, $this->getLevel()->createChunkSection($Y));
|
$level = $this->getLevel();
|
||||||
|
$this->setSection($Y = $y >> 4, $level::createChunkSection($Y));
|
||||||
$this->setBlockData($x, $y, $z, $data);
|
$this->setBlockData($x, $y, $z, $data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -188,7 +193,8 @@ abstract class BaseChunk extends BaseFullChunk implements Chunk{
|
|||||||
try{
|
try{
|
||||||
$this->sections[$y >> 4]->getBlockSkyLight($x, $y & 0x0f, $z, $data);
|
$this->sections[$y >> 4]->getBlockSkyLight($x, $y & 0x0f, $z, $data);
|
||||||
}catch(\Exception $e){
|
}catch(\Exception $e){
|
||||||
$this->setSection($Y = $y >> 4, $this->getLevel()->createChunkSection($Y));
|
$level = $this->getLevel();
|
||||||
|
$this->setSection($Y = $y >> 4, $level::createChunkSection($Y));
|
||||||
$this->setBlockSkyLight($x, $y, $z, $data);
|
$this->setBlockSkyLight($x, $y, $z, $data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -201,7 +207,8 @@ abstract class BaseChunk extends BaseFullChunk implements Chunk{
|
|||||||
try{
|
try{
|
||||||
$this->sections[$y >> 4]->getBlockSkyLight($x, $y & 0x0f, $z, $data);
|
$this->sections[$y >> 4]->getBlockSkyLight($x, $y & 0x0f, $z, $data);
|
||||||
}catch(\Exception $e){
|
}catch(\Exception $e){
|
||||||
$this->setSection($Y = $y >> 4, $this->getLevel()->createChunkSection($Y));
|
$level = $this->getLevel();
|
||||||
|
$this->setSection($Y = $y >> 4, $level::createChunkSection($Y));
|
||||||
$this->setBlockLight($x, $y, $z, $data);
|
$this->setBlockLight($x, $y, $z, $data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,64 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
*
|
|
||||||
* ____ _ _ __ __ _ __ __ ____
|
|
||||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
|
||||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
|
||||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
|
||||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* @author PocketMine Team
|
|
||||||
* @link http://www.pocketmine.net/
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace pocketmine\level\format\generic;
|
|
||||||
|
|
||||||
use pocketmine\level\format\ChunkSnapshot;
|
|
||||||
|
|
||||||
abstract class BaseChunkSnapshot implements ChunkSnapshot{
|
|
||||||
|
|
||||||
protected $blockId;
|
|
||||||
protected $blockData;
|
|
||||||
protected $skyLight;
|
|
||||||
protected $light;
|
|
||||||
|
|
||||||
protected $x;
|
|
||||||
protected $z;
|
|
||||||
protected $levelName;
|
|
||||||
protected $levelTime;
|
|
||||||
|
|
||||||
public function __construct($x, $z, $levelName, $levelTime, $blockId, $blockData, $skyLight, $light, $heightMap, $biome, $biomeTemp, $biomeRain){
|
|
||||||
$this->x = $x;
|
|
||||||
$this->z = $z;
|
|
||||||
$this->levelName = $levelName;
|
|
||||||
$this->levelTime = $levelTime;
|
|
||||||
$this->blockId = $blockId;
|
|
||||||
$this->blockData = $blockData;
|
|
||||||
$this->skyLight = $skyLight;
|
|
||||||
$this->light = $light;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getX(){
|
|
||||||
return $this->x;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getZ(){
|
|
||||||
return $this->z;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getLevelName(){
|
|
||||||
return $this->levelName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getLevelTime(){
|
|
||||||
return $this->levelTime;
|
|
||||||
}
|
|
||||||
}
|
|
@ -76,8 +76,8 @@ abstract class BaseFullChunk implements FullChunk{
|
|||||||
*
|
*
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
protected function __construct(LevelProvider $level, $x, $z, $blocks, $data, $skyLight, $blockLight, $biomeIds = null, array $biomeColors = [], array $entities = [], array $tiles = []){
|
protected function __construct($level, $x, $z, $blocks, $data, $skyLight, $blockLight, $biomeIds = null, array $biomeColors = [], array $entities = [], array $tiles = []){
|
||||||
$this->level = new \WeakRef($level);
|
$this->level = $level instanceof LevelProvider ? new \WeakRef($level) : $level;
|
||||||
$this->x = (int) $x;
|
$this->x = (int) $x;
|
||||||
$this->z = (int) $z;
|
$this->z = (int) $z;
|
||||||
|
|
||||||
@ -98,46 +98,48 @@ abstract class BaseFullChunk implements FullChunk{
|
|||||||
$this->biomeColors = array_fill(0, 256, Binary::readInt("\x00\x85\xb2\x4a"));
|
$this->biomeColors = array_fill(0, 256, Binary::readInt("\x00\x85\xb2\x4a"));
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->getLevel()->getLevel()->timings->syncChunkLoadEntitiesTimer->startTiming();
|
if($this->getLevel() instanceof LevelProvider){
|
||||||
foreach($entities as $nbt){
|
$this->getLevel()->getLevel()->timings->syncChunkLoadEntitiesTimer->startTiming();
|
||||||
if($nbt instanceof Compound){
|
foreach($entities as $nbt){
|
||||||
if(!isset($nbt->id)){
|
if($nbt instanceof Compound){
|
||||||
continue;
|
if(!isset($nbt->id)){
|
||||||
}
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if($nbt->id instanceof String){ //New format
|
if($nbt->id instanceof String){ //New format
|
||||||
|
switch($nbt["id"]){
|
||||||
|
case "Item":
|
||||||
|
(new DroppedItem($this, $nbt))->spawnToAll();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}else{ //Old format
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->getLevel()->getLevel()->timings->syncChunkLoadEntitiesTimer->stopTiming();
|
||||||
|
|
||||||
|
$this->getLevel()->getLevel()->timings->syncChunkLoadTileEntitiesTimer->startTiming();
|
||||||
|
foreach($tiles as $nbt){
|
||||||
|
if($nbt instanceof Compound){
|
||||||
|
if(!isset($nbt->id)){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
switch($nbt["id"]){
|
switch($nbt["id"]){
|
||||||
case "Item":
|
case Tile::CHEST:
|
||||||
(new DroppedItem($this, $nbt))->spawnToAll();
|
new Chest($this, $nbt);
|
||||||
|
break;
|
||||||
|
case Tile::FURNACE:
|
||||||
|
new Furnace($this, $nbt);
|
||||||
|
break;
|
||||||
|
case Tile::SIGN:
|
||||||
|
new Sign($this, $nbt);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}else{ //Old format
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
$this->getLevel()->getLevel()->timings->syncChunkLoadTileEntitiesTimer->stopTiming();
|
||||||
}
|
}
|
||||||
$this->getLevel()->getLevel()->timings->syncChunkLoadEntitiesTimer->stopTiming();
|
|
||||||
|
|
||||||
$this->getLevel()->getLevel()->timings->syncChunkLoadTileEntitiesTimer->startTiming();
|
|
||||||
foreach($tiles as $nbt){
|
|
||||||
if($nbt instanceof Compound){
|
|
||||||
if(!isset($nbt->id)){
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
switch($nbt["id"]){
|
|
||||||
case Tile::CHEST:
|
|
||||||
new Chest($this, $nbt);
|
|
||||||
break;
|
|
||||||
case Tile::FURNACE:
|
|
||||||
new Furnace($this, $nbt);
|
|
||||||
break;
|
|
||||||
case Tile::SIGN:
|
|
||||||
new Sign($this, $nbt);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$this->getLevel()->getLevel()->timings->syncChunkLoadTileEntitiesTimer->stopTiming();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getX(){
|
public function getX(){
|
||||||
@ -148,11 +150,19 @@ abstract class BaseFullChunk implements FullChunk{
|
|||||||
return $this->z;
|
return $this->z;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setX($x){
|
||||||
|
$this->x = $x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setZ($z){
|
||||||
|
$this->z = $z;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return LevelProvider
|
* @return LevelProvider
|
||||||
*/
|
*/
|
||||||
public function getLevel(){
|
public function getLevel(){
|
||||||
return $this->level->valid() ? $this->level->get() : null;
|
return $this->level instanceof \WeakRef ? ($this->level->valid() ? $this->level->get() : null) : $this->level;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getBiomeId($x, $z){
|
public function getBiomeId($x, $z){
|
||||||
|
@ -29,6 +29,7 @@ use pocketmine\nbt\tag\ByteArray;
|
|||||||
use pocketmine\nbt\tag\Compound;
|
use pocketmine\nbt\tag\Compound;
|
||||||
use pocketmine\nbt\tag\Enum;
|
use pocketmine\nbt\tag\Enum;
|
||||||
use pocketmine\nbt\tag\IntArray;
|
use pocketmine\nbt\tag\IntArray;
|
||||||
|
use pocketmine\Player;
|
||||||
use pocketmine\utils\Binary;
|
use pocketmine\utils\Binary;
|
||||||
|
|
||||||
class Chunk extends BaseFullChunk{
|
class Chunk extends BaseFullChunk{
|
||||||
@ -36,7 +37,7 @@ class Chunk extends BaseFullChunk{
|
|||||||
/** @var Compound */
|
/** @var Compound */
|
||||||
protected $nbt;
|
protected $nbt;
|
||||||
|
|
||||||
public function __construct(LevelProvider $level, Compound $nbt){
|
public function __construct($level, Compound $nbt){
|
||||||
$this->nbt = $nbt;
|
$this->nbt = $nbt;
|
||||||
|
|
||||||
if(isset($this->nbt->Entities) and $this->nbt->Entities instanceof Enum){
|
if(isset($this->nbt->Entities) and $this->nbt->Entities instanceof Enum){
|
||||||
@ -209,13 +210,76 @@ class Chunk extends BaseFullChunk{
|
|||||||
$this->nbt->TerrainPopulated = new Byte("TerrainPopulated", $value);
|
$this->nbt->TerrainPopulated = new Byte("TerrainPopulated", $value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getChunkSnapshot($includeMaxBlockY = true, $includeBiome = false, $includeBiomeTemp = false){
|
/**
|
||||||
$emptySections = [false, false, false, false, false, false, false, false];
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isGenerated(){
|
||||||
|
return $this->nbt["TerrainPopulated"] > 0 or (isset($this->nbt->TerrainGenerated) and $this->nbt["TerrainGenerated"] > 0);
|
||||||
|
}
|
||||||
|
|
||||||
//TODO: maxBlockY, biomeMap, biomeTemp
|
/**
|
||||||
|
* @param int $value
|
||||||
|
*/
|
||||||
|
public function setGenerated($value = 1){
|
||||||
|
$this->nbt->TerrainGenerated = new Byte("TerrainGenerated", $value);
|
||||||
|
}
|
||||||
|
|
||||||
//TODO: time
|
/**
|
||||||
return new ChunkSnapshot($this->getX(), $this->getZ(), $this->getLevel()->getName(), 0 /*$this->getLevel()->getTime()*/, $this->getBlockIdArray(), $this->getBlockDataArray(), $this->getBlockSkyLightArray(), $this->getBlockLightArray(), $emptySections, null, null, null, null);
|
* @param string $data
|
||||||
|
* @param LevelProvider $provider
|
||||||
|
*
|
||||||
|
* @return Chunk
|
||||||
|
*/
|
||||||
|
public static function fromBinary($data, LevelProvider $provider = null){
|
||||||
|
$nbt = new NBT(NBT::BIG_ENDIAN);
|
||||||
|
$nbt->readCompressed($data, ZLIB_ENCODING_DEFLATE);
|
||||||
|
$chunk = $nbt->getData();
|
||||||
|
|
||||||
|
if(!isset($chunk->Level) or !($chunk->Level instanceof Compound)){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Chunk($provider instanceof LevelProvider ? $provider : "pocketmine\\level\\format\\mcregion\\McRegion", $chunk->Level);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toBinary(){
|
||||||
|
$nbt = $this->getNBT();
|
||||||
|
|
||||||
|
$nbt->Blocks = new ByteArray("Blocks", $this->getBlockIdArray());
|
||||||
|
$nbt->Data = new ByteArray("Data", $this->getBlockDataArray());
|
||||||
|
$nbt->SkyLight = new ByteArray("SkyLight", $this->getBlockSkyLightArray());
|
||||||
|
$nbt->BlockLight = new ByteArray("BlockLight", $this->getBlockLightArray());
|
||||||
|
|
||||||
|
$nbt->Biomes = new ByteArray("Biomes", $this->getBiomeIdArray());
|
||||||
|
$nbt->BiomeColors = new IntArray("BiomeColors", $this->getBiomeColorArray());
|
||||||
|
|
||||||
|
$entities = [];
|
||||||
|
|
||||||
|
foreach($this->getEntities() as $entity){
|
||||||
|
if(!($entity instanceof Player) and $entity->closed !== true){
|
||||||
|
$entity->saveNBT();
|
||||||
|
$entities[] = $entity->namedtag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$nbt->Entities = new Enum("Entities", $entities);
|
||||||
|
$nbt->Entities->setTagType(NBT::TAG_Compound);
|
||||||
|
|
||||||
|
|
||||||
|
$tiles = [];
|
||||||
|
foreach($this->getTiles() as $tile){
|
||||||
|
if($tile->closed !== true){
|
||||||
|
$tile->saveNBT();
|
||||||
|
$tiles[] = $tile->namedtag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$nbt->Entities = new Enum("TileEntities", $tiles);
|
||||||
|
$nbt->Entities->setTagType(NBT::TAG_Compound);
|
||||||
|
$writer = new NBT(NBT::BIG_ENDIAN);
|
||||||
|
$nbt->setName("Level");
|
||||||
|
$writer->setData(new Compound("", array("Level" => $nbt)));
|
||||||
|
return $writer->writeCompressed(ZLIB_ENCODING_DEFLATE, RegionLoader::$COMPRESSION_LEVEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -51,7 +51,10 @@ class ChunkRequestTask extends AsyncTask{
|
|||||||
$this->levelId = $levelId;
|
$this->levelId = $levelId;
|
||||||
$this->chunkX = $chunkX;
|
$this->chunkX = $chunkX;
|
||||||
$this->chunkZ = $chunkZ;
|
$this->chunkZ = $chunkZ;
|
||||||
$chunk = $level->getChunk($chunkX, $chunkZ, true);
|
$chunk = $level->getChunk($chunkX, $chunkZ, false);
|
||||||
|
if(!($chunk instanceof Chunk)){
|
||||||
|
throw new \Exception("Invalid Chunk sent");
|
||||||
|
}
|
||||||
$this->blocks = $chunk->getBlockIdArray();
|
$this->blocks = $chunk->getBlockIdArray();
|
||||||
$this->data = $chunk->getBlockDataArray();
|
$this->data = $chunk->getBlockDataArray();
|
||||||
$this->skyLight = $chunk->getBlockSkyLightArray();
|
$this->skyLight = $chunk->getBlockSkyLightArray();
|
||||||
|
@ -1,78 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
*
|
|
||||||
* ____ _ _ __ __ _ __ __ ____
|
|
||||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
|
||||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
|
||||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
|
||||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* @author PocketMine Team
|
|
||||||
* @link http://www.pocketmine.net/
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace pocketmine\level\format\mcregion;
|
|
||||||
|
|
||||||
use pocketmine\level\format\generic\BaseChunkSnapshot;
|
|
||||||
|
|
||||||
class ChunkSnapshot extends BaseChunkSnapshot{
|
|
||||||
|
|
||||||
public function getBlockId($x, $y, $z){
|
|
||||||
return ord($this->blockId{
|
|
||||||
(($y >> 4) << 12) //get section index
|
|
||||||
+ ($y << 8) + ($z << 4) + $x //get block index in section
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getBlockData($x, $y, $z){
|
|
||||||
$data = ord($this->blockData{
|
|
||||||
(($y >> 4) << 11) //get section index
|
|
||||||
+ ($y << 7) + ($z << 3) + ($x >> 1) //get block index in section
|
|
||||||
});
|
|
||||||
if(($y & 1) === 0){
|
|
||||||
return $data & 0x0F;
|
|
||||||
}else{
|
|
||||||
return $data >> 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getBlockSkyLight($x, $y, $z){
|
|
||||||
$level = ord($this->skyLight{
|
|
||||||
(($y >> 4) << 11) //get section index
|
|
||||||
+ ($y << 7) + ($z << 3) + ($x >> 1) //get block index in section
|
|
||||||
});
|
|
||||||
if(($y & 1) === 0){
|
|
||||||
return $level & 0x0F;
|
|
||||||
}else{
|
|
||||||
return $level >> 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getBlockLight($x, $y, $z){
|
|
||||||
$level = ord($this->light{
|
|
||||||
(($y >> 4) << 11) //get section index
|
|
||||||
+ ($y << 7) + ($z << 3) + ($x >> 1) //get block index in section
|
|
||||||
});
|
|
||||||
if(($y & 1) === 0){
|
|
||||||
return $level & 0x0F;
|
|
||||||
}else{
|
|
||||||
return $level >> 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getBiome(){
|
|
||||||
return 0; //TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getHighestBlockAt($x, $z){
|
|
||||||
return 127; //TODO
|
|
||||||
}
|
|
||||||
}
|
|
@ -21,8 +21,8 @@
|
|||||||
|
|
||||||
namespace pocketmine\level\format\mcregion;
|
namespace pocketmine\level\format\mcregion;
|
||||||
|
|
||||||
|
use pocketmine\level\format\FullChunk;
|
||||||
use pocketmine\level\format\generic\BaseLevelProvider;
|
use pocketmine\level\format\generic\BaseLevelProvider;
|
||||||
use pocketmine\level\format\SimpleChunk;
|
|
||||||
use pocketmine\level\generator\Generator;
|
use pocketmine\level\generator\Generator;
|
||||||
use pocketmine\level\Level;
|
use pocketmine\level\Level;
|
||||||
use pocketmine\nbt\NBT;
|
use pocketmine\nbt\NBT;
|
||||||
@ -219,12 +219,12 @@ class McRegion extends BaseLevelProvider{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setChunk($chunkX, $chunkZ, SimpleChunk $chunk){
|
public function setChunk($chunkX, $chunkZ, FullChunk $chunk){
|
||||||
return;
|
if(!($chunk instanceof Chunk)){
|
||||||
//TODO!
|
throw new \Exception("Invalid Chunk class");
|
||||||
|
}
|
||||||
|
|
||||||
|
if($chunk->isPopulated() === false){
|
||||||
if($chunk->isGenerated() === false){
|
|
||||||
$this->unloadChunk($chunkX, $chunkZ, false);
|
$this->unloadChunk($chunkX, $chunkZ, false);
|
||||||
$regionX = $regionZ = null;
|
$regionX = $regionZ = null;
|
||||||
self::getRegionIndex($chunkX, $chunkZ, $regionX, $regionZ);
|
self::getRegionIndex($chunkX, $chunkZ, $regionX, $regionZ);
|
||||||
@ -233,38 +233,21 @@ class McRegion extends BaseLevelProvider{
|
|||||||
$region->removeChunk($chunkX - $region->getX() * 32, $chunkZ - $region->getZ() * 32);
|
$region->removeChunk($chunkX - $region->getX() * 32, $chunkZ - $region->getZ() * 32);
|
||||||
$this->loadChunk($chunkX, $chunkZ);
|
$this->loadChunk($chunkX, $chunkZ);
|
||||||
}else{
|
}else{
|
||||||
$newChunk = $this->getChunk($chunkX, $chunkZ, true);
|
$newChunk = clone $chunk;
|
||||||
for($y = 0; $y < 8; ++$y){
|
$newChunk->setX($chunkX);
|
||||||
/*$section = new ChunkSection(new Compound(null, [
|
$newChunk->setZ($chunkZ);
|
||||||
"Y" => new Byte("Y", $y),
|
|
||||||
"Blocks" => new ByteArray("Blocks", $chunk->getSectionIds($y)),
|
|
||||||
"Data" => new ByteArray("Data", $chunk->getSectionData($y)),
|
|
||||||
"SkyLight" => new ByteArray("SkyLight", str_repeat("\xff", 2048)), //TODO
|
|
||||||
"BlockLight" => new ByteArray("BlockLight", str_repeat("\x00", 2048)) //TODO
|
|
||||||
]));
|
|
||||||
$newChunk->setSection($y, $section);*/
|
|
||||||
}
|
|
||||||
if($chunk->isPopulated()){
|
|
||||||
$newChunk->setPopulated(1);
|
|
||||||
}
|
|
||||||
$this->chunks[Level::chunkHash($chunkX, $chunkZ)] = $newChunk;
|
$this->chunks[Level::chunkHash($chunkX, $chunkZ)] = $newChunk;
|
||||||
$this->saveChunk($chunkX, $chunkZ);
|
//$this->saveChunk($chunkX, $chunkZ);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createChunkSection($Y){
|
public static function createChunkSection($Y){
|
||||||
return new ChunkSection(
|
return null;
|
||||||
$Y,
|
|
||||||
str_repeat("\xff", 4096),
|
|
||||||
$half = str_repeat("\xff", 2048),
|
|
||||||
$half,
|
|
||||||
$half
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isChunkGenerated($chunkX, $chunkZ){
|
public function isChunkGenerated($chunkX, $chunkZ){
|
||||||
if(($region = $this->getRegion($chunkX >> 5, $chunkZ >> 5)) instanceof RegionLoader){
|
if(($region = $this->getRegion($chunkX >> 5, $chunkZ >> 5)) instanceof RegionLoader){
|
||||||
return $region->chunkExists($chunkX - $region->getX() * 32, $chunkZ - $region->getZ() * 32);
|
return $region->chunkExists($chunkX - $region->getX() * 32, $chunkZ - $region->getZ() * 32) and $this->getChunk($chunkX - $region->getX() * 32, $chunkZ - $region->getZ() * 32, true)->isGenerated();
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -119,16 +119,9 @@ class RegionLoader{
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$nbt = new NBT(NBT::BIG_ENDIAN);
|
$chunk = Chunk::fromBinary(fread($this->filePointer, $length - 1), $this->levelProvider);
|
||||||
$nbt->readCompressed(fread($this->filePointer, $length - 1), $compression);
|
|
||||||
$chunk = $nbt->getData();
|
|
||||||
|
|
||||||
|
return $chunk instanceof Chunk ? $chunk : false;
|
||||||
if(!isset($chunk->Level) or !($chunk->Level instanceof Compound)){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Chunk($this->levelProvider, $chunk->Level);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function chunkExists($x, $z){
|
public function chunkExists($x, $z){
|
||||||
@ -159,14 +152,15 @@ class RegionLoader{
|
|||||||
$nbt->TileEntities->setTagType(NBT::TAG_Compound);
|
$nbt->TileEntities->setTagType(NBT::TAG_Compound);
|
||||||
$nbt->TileTicks = new Enum("TileTicks", []);
|
$nbt->TileTicks = new Enum("TileTicks", []);
|
||||||
$nbt->TileTicks->setTagType(NBT::TAG_Compound);
|
$nbt->TileTicks->setTagType(NBT::TAG_Compound);
|
||||||
$this->saveChunk($x, $z, $nbt);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function saveChunk($x, $z, Compound $nbt){
|
|
||||||
$writer = new NBT(NBT::BIG_ENDIAN);
|
$writer = new NBT(NBT::BIG_ENDIAN);
|
||||||
$nbt->setName("Level");
|
$nbt->setName("Level");
|
||||||
$writer->setData(new Compound("", array("Level" => $nbt)));
|
$writer->setData(new Compound("", array("Level" => $nbt)));
|
||||||
$chunkData = $writer->writeCompressed(ZLIB_ENCODING_DEFLATE, self::$COMPRESSION_LEVEL);
|
$chunkData = $writer->writeCompressed(ZLIB_ENCODING_DEFLATE, self::$COMPRESSION_LEVEL);
|
||||||
|
|
||||||
|
$this->saveChunk($x, $z, $chunkData);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function saveChunk($x, $z, $chunkData){
|
||||||
$length = strlen($chunkData) + 1;
|
$length = strlen($chunkData) + 1;
|
||||||
$sectors = (int) ceil(($length + 4) / 4096);
|
$sectors = (int) ceil(($length + 4) / 4096);
|
||||||
$index = self::getChunkOffset($x, $z);
|
$index = self::getChunkOffset($x, $z);
|
||||||
@ -187,41 +181,7 @@ class RegionLoader{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function writeChunk(Chunk $chunk){
|
public function writeChunk(Chunk $chunk){
|
||||||
$nbt = $chunk->getNBT();
|
$this->saveChunk($chunk->getX() - ($this->getX() * 32), $chunk->getZ() - ($this->getZ() * 32), $chunk->toBinary());
|
||||||
|
|
||||||
$nbt->Blocks = new ByteArray("Blocks", $chunk->getBlockIdArray());
|
|
||||||
$nbt->Data = new ByteArray("Data", $chunk->getBlockDataArray());
|
|
||||||
$nbt->SkyLight = new ByteArray("SkyLight", $chunk->getBlockSkyLightArray());
|
|
||||||
$nbt->BlockLight = new ByteArray("BlockLight", $chunk->getBlockLightArray());
|
|
||||||
|
|
||||||
$nbt->Biomes = new ByteArray("Biomes", $chunk->getBiomeIdArray());
|
|
||||||
$nbt->BiomeColors = new IntArray("BiomeColors", $chunk->getBiomeColorArray());
|
|
||||||
|
|
||||||
$entities = [];
|
|
||||||
|
|
||||||
foreach($chunk->getEntities() as $entity){
|
|
||||||
if(!($entity instanceof Player) and $entity->closed !== true){
|
|
||||||
$entity->saveNBT();
|
|
||||||
$entities[] = $entity->namedtag;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$nbt->Entities = new Enum("Entities", $entities);
|
|
||||||
$nbt->Entities->setTagType(NBT::TAG_Compound);
|
|
||||||
|
|
||||||
|
|
||||||
$tiles = [];
|
|
||||||
foreach($chunk->getTiles() as $tile){
|
|
||||||
if($tile->closed !== true){
|
|
||||||
$tile->saveNBT();
|
|
||||||
$tiles[] = $tile->namedtag;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$nbt->Entities = new Enum("TileEntities", $tiles);
|
|
||||||
$nbt->Entities->setTagType(NBT::TAG_Compound);
|
|
||||||
|
|
||||||
$this->saveChunk($chunk->getX() - ($this->getX() * 32), $chunk->getZ() - ($this->getZ() * 32), $nbt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static function getChunkOffset($x, $z){
|
protected static function getChunkOffset($x, $z){
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
namespace pocketmine\level\generator;
|
namespace pocketmine\level\generator;
|
||||||
|
|
||||||
|
use pocketmine\level\format\FullChunk;
|
||||||
use pocketmine\block\CoalOre;
|
use pocketmine\block\CoalOre;
|
||||||
use pocketmine\block\DiamondOre;
|
use pocketmine\block\DiamondOre;
|
||||||
use pocketmine\block\Dirt;
|
use pocketmine\block\Dirt;
|
||||||
@ -30,7 +31,6 @@ use pocketmine\block\IronOre;
|
|||||||
use pocketmine\block\LapisOre;
|
use pocketmine\block\LapisOre;
|
||||||
use pocketmine\block\RedstoneOre;
|
use pocketmine\block\RedstoneOre;
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\level\format\SimpleChunk;
|
|
||||||
use pocketmine\level\generator\populator\Ore;
|
use pocketmine\level\generator\populator\Ore;
|
||||||
use pocketmine\level\generator\populator\Populator;
|
use pocketmine\level\generator\populator\Populator;
|
||||||
use pocketmine\math\Vector3 as Vector3;
|
use pocketmine\math\Vector3 as Vector3;
|
||||||
@ -39,7 +39,7 @@ use pocketmine\utils\Random;
|
|||||||
class Flat extends Generator{
|
class Flat extends Generator{
|
||||||
/** @var GenerationChunkManager */
|
/** @var GenerationChunkManager */
|
||||||
private $level;
|
private $level;
|
||||||
/** @var SimpleChunk */
|
/** @var FullChunk */
|
||||||
private $chunk;
|
private $chunk;
|
||||||
/** @var Random */
|
/** @var Random */
|
||||||
private $random;
|
private $random;
|
||||||
@ -59,11 +59,7 @@ class Flat extends Generator{
|
|||||||
$this->preset = "2;7,2x3,2;1;";
|
$this->preset = "2;7,2x3,2;1;";
|
||||||
//$this->preset = "2;7,59x1,3x3,2;1;spawn(radius=10 block=89),decoration(treecount=80 grasscount=45)";
|
//$this->preset = "2;7,59x1,3x3,2;1;spawn(radius=10 block=89),decoration(treecount=80 grasscount=45)";
|
||||||
$this->options = $options;
|
$this->options = $options;
|
||||||
if(isset($options["preset"]) and $options["preset"] != ""){
|
|
||||||
$this->parsePreset($options["preset"]);
|
|
||||||
}else{
|
|
||||||
$this->parsePreset($this->preset);
|
|
||||||
}
|
|
||||||
if(isset($this->options["decoration"])){
|
if(isset($this->options["decoration"])){
|
||||||
$ores = new Ore();
|
$ores = new Ore();
|
||||||
$ores->setOreTypes(array(
|
$ores->setOreTypes(array(
|
||||||
@ -110,7 +106,8 @@ class Flat extends Generator{
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$this->chunk = new SimpleChunk(null, null, SimpleChunk::FLAG_GENERATED);
|
$this->chunk = $this->level->getChunk(0, 0);
|
||||||
|
$this->chunk->setGenerated();
|
||||||
|
|
||||||
for($Z = 0; $Z < 16; ++$Z){
|
for($Z = 0; $Z < 16; ++$Z){
|
||||||
for($X = 0; $X < 16; ++$X){
|
for($X = 0; $X < 16; ++$X){
|
||||||
@ -145,6 +142,13 @@ class Flat extends Generator{
|
|||||||
public function init(GenerationChunkManager $level, Random $random){
|
public function init(GenerationChunkManager $level, Random $random){
|
||||||
$this->level = $level;
|
$this->level = $level;
|
||||||
$this->random = $random;
|
$this->random = $random;
|
||||||
|
|
||||||
|
if(isset($this->options["preset"]) and $this->options["preset"] != ""){
|
||||||
|
$this->parsePreset($this->options["preset"]);
|
||||||
|
}else{
|
||||||
|
$this->parsePreset($this->preset);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function generateChunk($chunkX, $chunkZ){
|
public function generateChunk($chunkX, $chunkZ){
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
namespace pocketmine\level\generator;
|
namespace pocketmine\level\generator;
|
||||||
|
|
||||||
use pocketmine\level\ChunkManager;
|
use pocketmine\level\ChunkManager;
|
||||||
use pocketmine\level\format\SimpleChunk;
|
use pocketmine\level\format\FullChunk;
|
||||||
use pocketmine\level\Level;
|
use pocketmine\level\Level;
|
||||||
use pocketmine\utils\Random;
|
use pocketmine\utils\Random;
|
||||||
|
|
||||||
@ -30,10 +30,10 @@ class GenerationChunkManager implements ChunkManager{
|
|||||||
|
|
||||||
protected $levelID;
|
protected $levelID;
|
||||||
|
|
||||||
/** @var SimpleChunk[] */
|
/** @var FullChunk[] */
|
||||||
protected $chunks = [];
|
protected $chunks = [];
|
||||||
|
|
||||||
/** @var \SplObjectStorage<SimpleChunk> */
|
/** @var \SplObjectStorage<FullChunk> */
|
||||||
protected $unloadQueue;
|
protected $unloadQueue;
|
||||||
|
|
||||||
/** @var Generator */
|
/** @var Generator */
|
||||||
@ -44,6 +44,8 @@ class GenerationChunkManager implements ChunkManager{
|
|||||||
|
|
||||||
protected $seed;
|
protected $seed;
|
||||||
|
|
||||||
|
protected $changes = [];
|
||||||
|
|
||||||
public function __construct(GenerationManager $manager, $levelID, $seed, $class, array $options){
|
public function __construct(GenerationManager $manager, $levelID, $seed, $class, array $options){
|
||||||
if(!is_subclass_of($class, "pocketmine\\level\\generator\\Generator")){
|
if(!is_subclass_of($class, "pocketmine\\level\\generator\\Generator")){
|
||||||
throw new \Exception("Class is not a subclass of Generator");
|
throw new \Exception("Class is not a subclass of Generator");
|
||||||
@ -77,7 +79,7 @@ class GenerationChunkManager implements ChunkManager{
|
|||||||
* @param $chunkX
|
* @param $chunkX
|
||||||
* @param $chunkZ
|
* @param $chunkZ
|
||||||
*
|
*
|
||||||
* @return SimpleChunk
|
* @return FullChunk
|
||||||
*/
|
*/
|
||||||
public function getChunk($chunkX, $chunkZ){
|
public function getChunk($chunkX, $chunkZ){
|
||||||
$index = Level::chunkHash($chunkX, $chunkZ);
|
$index = Level::chunkHash($chunkX, $chunkZ);
|
||||||
@ -87,28 +89,24 @@ class GenerationChunkManager implements ChunkManager{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param bool $set
|
* @return FullChunk[]
|
||||||
*
|
|
||||||
* @return SimpleChunk[]
|
|
||||||
*/
|
*/
|
||||||
public function getChangedChunks($set = true){
|
public function getChangedChunks(){
|
||||||
$changed = [];
|
return $this->changes;
|
||||||
foreach($this->chunks as $chunk){
|
}
|
||||||
if($chunk->hasChanged($set)){
|
|
||||||
$changed[] = $chunk;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $changed;
|
public function cleanChangedChunks(){
|
||||||
|
$this->changes = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function doGarbageCollection(){
|
public function doGarbageCollection(){
|
||||||
if($this->unloadQueue->count() > 0){
|
if($this->unloadQueue->count() > 0){
|
||||||
/** @var SimpleChunk $chunk */
|
/** @var FullChunk $chunk */
|
||||||
foreach($this->unloadQueue as $chunk){
|
foreach($this->unloadQueue as $chunk){
|
||||||
if(!$chunk->hasChanged(false)){
|
if(isset($this->changes[$index = Level::chunkHash($chunk->getX(), $chunk->getZ())])){
|
||||||
unset($this->chunks[Level::chunkHash($chunk->getX(), $chunk->getZ())]);
|
continue;
|
||||||
}
|
}
|
||||||
|
unset($this->chunks[$index]);
|
||||||
$this->unloadQueue->detach($chunk);
|
$this->unloadQueue->detach($chunk);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -119,7 +117,7 @@ class GenerationChunkManager implements ChunkManager{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function generateChunk($chunkX, $chunkZ){
|
public function generateChunk($chunkX, $chunkZ){
|
||||||
$this->chunks[Level::chunkHash($chunkX, $chunkZ)] = new SimpleChunk($chunkX, $chunkZ, 0);
|
$this->chunks[Level::chunkHash($chunkX, $chunkZ)] = $this->requestChunk($chunkX, $chunkZ);
|
||||||
$this->generator->generateChunk($chunkX, $chunkZ);
|
$this->generator->generateChunk($chunkX, $chunkZ);
|
||||||
$this->setChunkGenerated($chunkX, $chunkZ);
|
$this->setChunkGenerated($chunkX, $chunkZ);
|
||||||
}
|
}
|
||||||
@ -150,11 +148,15 @@ class GenerationChunkManager implements ChunkManager{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function setChunkGenerated($chunkX, $chunkZ){
|
public function setChunkGenerated($chunkX, $chunkZ){
|
||||||
$this->getChunk($chunkX, $chunkZ)->setGenerated(true);
|
$chunk = $this->getChunk($chunkX, $chunkZ);
|
||||||
|
$chunk->setGenerated(true);
|
||||||
|
$this->changes[Level::chunkHash($chunkX, $chunkZ)] = $chunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setChunkPopulated($chunkX, $chunkZ){
|
public function setChunkPopulated($chunkX, $chunkZ){
|
||||||
$this->getChunk($chunkX, $chunkZ)->setPopulated(true);
|
$chunk = $this->getChunk($chunkX, $chunkZ);
|
||||||
|
$chunk->setPopulated(true);
|
||||||
|
$this->changes[Level::chunkHash($chunkX, $chunkZ)] = $chunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function requestChunk($chunkX, $chunkZ){
|
protected function requestChunk($chunkX, $chunkZ){
|
||||||
@ -166,11 +168,12 @@ class GenerationChunkManager implements ChunkManager{
|
|||||||
/**
|
/**
|
||||||
* @param int $chunkX
|
* @param int $chunkX
|
||||||
* @param int $chunkZ
|
* @param int $chunkZ
|
||||||
* @param SimpleChunk $chunk
|
* @param FullChunk $chunk
|
||||||
*/
|
*/
|
||||||
public function setChunk($chunkX, $chunkZ, SimpleChunk $chunk){
|
public function setChunk($chunkX, $chunkZ, FullChunk $chunk){
|
||||||
$this->chunks[Level::chunkHash($chunkX, $chunkZ)] = $chunk;
|
$this->chunks[$index = Level::chunkHash($chunkX, $chunkZ)] = $chunk;
|
||||||
if($chunk->isGenerated() and $chunk->isPopulated()){
|
$this->changes[$index] = $chunk;
|
||||||
|
if($chunk->isPopulated()){
|
||||||
//TODO: Queue to be sent
|
//TODO: Queue to be sent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
namespace pocketmine\level\generator;
|
namespace pocketmine\level\generator;
|
||||||
|
|
||||||
use pocketmine\level\format\SimpleChunk;
|
use pocketmine\level\format\FullChunk;
|
||||||
use pocketmine\level\Level;
|
use pocketmine\level\Level;
|
||||||
use pocketmine\utils\Binary;
|
use pocketmine\utils\Binary;
|
||||||
|
|
||||||
@ -60,7 +60,8 @@ class GenerationManager{
|
|||||||
* int32 levelID
|
* int32 levelID
|
||||||
* int32 chunkX
|
* int32 chunkX
|
||||||
* int32 chunkZ
|
* int32 chunkZ
|
||||||
* byte flags (1 generated, 2 populated)
|
* byte className length
|
||||||
|
* byte[] className
|
||||||
* byte[] chunk (none if generated flag is not set)
|
* byte[] chunk (none if generated flag is not set)
|
||||||
*/
|
*/
|
||||||
const PACKET_SEND_CHUNK = 0x02;
|
const PACKET_SEND_CHUNK = 0x02;
|
||||||
@ -144,10 +145,11 @@ class GenerationManager{
|
|||||||
if(isset($this->levels[$levelID])){
|
if(isset($this->levels[$levelID])){
|
||||||
$this->generatedQueue[$levelID][$index] = true;
|
$this->generatedQueue[$levelID][$index] = true;
|
||||||
if(count($this->generatedQueue[$levelID]) > 6){
|
if(count($this->generatedQueue[$levelID]) > 6){
|
||||||
$this->levels[$levelID]->doGarbageCollection();
|
foreach($this->levels[$levelID]->getChangedChunks() as $chunk){
|
||||||
foreach($this->levels[$levelID]->getChangedChunks(true) as $chunk){
|
|
||||||
$this->sendChunk($levelID, $chunk);
|
$this->sendChunk($levelID, $chunk);
|
||||||
}
|
}
|
||||||
|
$this->levels[$levelID]->doGarbageCollection();
|
||||||
|
$this->levels[$levelID]->cleanChangedChunks();
|
||||||
$this->generatedQueue[$levelID] = [];
|
$this->generatedQueue[$levelID] = [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -166,7 +168,7 @@ class GenerationManager{
|
|||||||
$this->requestQueue->enqueue([$levelID, $chunkX, $chunkZ]);
|
$this->requestQueue->enqueue([$levelID, $chunkX, $chunkZ]);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function receiveChunk($levelID, SimpleChunk $chunk){
|
protected function receiveChunk($levelID, FullChunk $chunk){
|
||||||
if($this->needsChunk !== null and $this->needsChunk[0] === $levelID){
|
if($this->needsChunk !== null and $this->needsChunk[0] === $levelID){
|
||||||
if($this->needsChunk[1] === $chunk->getX() and $this->needsChunk[2] === $chunk->getZ()){
|
if($this->needsChunk[1] === $chunk->getX() and $this->needsChunk[2] === $chunk->getZ()){
|
||||||
$this->needsChunk = $chunk;
|
$this->needsChunk = $chunk;
|
||||||
@ -180,7 +182,7 @@ class GenerationManager{
|
|||||||
* @param $chunkX
|
* @param $chunkX
|
||||||
* @param $chunkZ
|
* @param $chunkZ
|
||||||
*
|
*
|
||||||
* @return SimpleChunk
|
* @return FullChunk
|
||||||
*/
|
*/
|
||||||
public function requestChunk($levelID, $chunkX, $chunkZ){
|
public function requestChunk($levelID, $chunkX, $chunkZ){
|
||||||
$this->needsChunk = [$levelID, $chunkX, $chunkZ];
|
$this->needsChunk = [$levelID, $chunkX, $chunkZ];
|
||||||
@ -188,19 +190,19 @@ class GenerationManager{
|
|||||||
@socket_write($this->socket, Binary::writeInt(strlen($binary)) . $binary);
|
@socket_write($this->socket, Binary::writeInt(strlen($binary)) . $binary);
|
||||||
do{
|
do{
|
||||||
$this->readPacket();
|
$this->readPacket();
|
||||||
}while($this->shutdown !== true and !($this->needsChunk instanceof SimpleChunk));
|
}while($this->shutdown !== true and !($this->needsChunk instanceof FullChunk));
|
||||||
|
|
||||||
$chunk = $this->needsChunk;
|
$chunk = $this->needsChunk;
|
||||||
$this->needsChunk = null;
|
$this->needsChunk = null;
|
||||||
if($chunk instanceof SimpleChunk){
|
if($chunk instanceof FullChunk){
|
||||||
return $chunk;
|
return $chunk;
|
||||||
}else{
|
}else{
|
||||||
return new SimpleChunk($chunkX, $chunkZ, 0);
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function sendChunk($levelID, SimpleChunk $chunk){
|
public function sendChunk($levelID, FullChunk $chunk){
|
||||||
$binary = chr(self::PACKET_SEND_CHUNK) . Binary::writeInt($levelID) . $chunk->toBinary();
|
$binary = chr(self::PACKET_SEND_CHUNK) . Binary::writeInt($levelID) . chr(strlen($class = get_class($chunk))) . $class . $chunk->toBinary();
|
||||||
@socket_write($this->socket, Binary::writeInt(strlen($binary)) . $binary);
|
@socket_write($this->socket, Binary::writeInt(strlen($binary)) . $binary);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -234,7 +236,11 @@ class GenerationManager{
|
|||||||
}elseif($pid === self::PACKET_SEND_CHUNK){
|
}elseif($pid === self::PACKET_SEND_CHUNK){
|
||||||
$levelID = Binary::readInt(substr($packet, $offset, 4));
|
$levelID = Binary::readInt(substr($packet, $offset, 4));
|
||||||
$offset += 4;
|
$offset += 4;
|
||||||
$chunk = SimpleChunk::fromBinary(substr($packet, $offset));
|
$len = ord($packet{$offset++});
|
||||||
|
/** @var FullChunk $class */
|
||||||
|
$class = substr($packet, $offset, $len);
|
||||||
|
$offset += $len;
|
||||||
|
$chunk = $class::fromBinary(substr($packet, $offset));
|
||||||
$this->receiveChunk($levelID, $chunk);
|
$this->receiveChunk($levelID, $chunk);
|
||||||
}elseif($pid === self::PACKET_OPEN_LEVEL){
|
}elseif($pid === self::PACKET_OPEN_LEVEL){
|
||||||
$levelID = Binary::readInt(substr($packet, $offset, 4));
|
$levelID = Binary::readInt(substr($packet, $offset, 4));
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
namespace pocketmine\level\generator;
|
namespace pocketmine\level\generator;
|
||||||
|
|
||||||
use pocketmine\level\format\SimpleChunk;
|
use pocketmine\level\format\FullChunk;
|
||||||
use pocketmine\level\Level;
|
use pocketmine\level\Level;
|
||||||
use pocketmine\Server;
|
use pocketmine\Server;
|
||||||
use pocketmine\utils\Binary;
|
use pocketmine\utils\Binary;
|
||||||
@ -77,8 +77,8 @@ class GenerationRequestManager{
|
|||||||
return $buffer;
|
return $buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function sendChunk($levelID, SimpleChunk $chunk){
|
protected function sendChunk($levelID, FullChunk $chunk){
|
||||||
$binary = chr(GenerationManager::PACKET_SEND_CHUNK) . Binary::writeInt($levelID) . $chunk->toBinary();
|
$binary = chr(GenerationManager::PACKET_SEND_CHUNK) . Binary::writeInt($levelID) . chr(strlen($class = get_class($chunk))) . $class . $chunk->toBinary();
|
||||||
@socket_write($this->socket, Binary::writeInt(strlen($binary)) . $binary);
|
@socket_write($this->socket, Binary::writeInt(strlen($binary)) . $binary);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,14 +89,14 @@ class GenerationRequestManager{
|
|||||||
|
|
||||||
protected function handleRequest($levelID, $chunkX, $chunkZ){
|
protected function handleRequest($levelID, $chunkX, $chunkZ){
|
||||||
if(($level = $this->server->getLevel($levelID)) instanceof Level){
|
if(($level = $this->server->getLevel($levelID)) instanceof Level){
|
||||||
$this->sendChunk($levelID, $level->getChunk($chunkX, $chunkZ, false));
|
$this->sendChunk($levelID, $level->getChunkAt($chunkX, $chunkZ, true));
|
||||||
}else{
|
}else{
|
||||||
$buffer = chr(GenerationManager::PACKET_CLOSE_LEVEL) . Binary::writeInt($levelID);
|
$buffer = chr(GenerationManager::PACKET_CLOSE_LEVEL) . Binary::writeInt($levelID);
|
||||||
@socket_write($this->socket, Binary::writeInt(strlen($buffer)) . $buffer);
|
@socket_write($this->socket, Binary::writeInt(strlen($buffer)) . $buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function receiveChunk($levelID, SimpleChunk $chunk){
|
protected function receiveChunk($levelID, FullChunk $chunk){
|
||||||
if(($level = $this->server->getLevel($levelID)) instanceof Level){
|
if(($level = $this->server->getLevel($levelID)) instanceof Level){
|
||||||
$level->generateChunkCallback($chunk->getX(), $chunk->getZ(), $chunk);
|
$level->generateChunkCallback($chunk->getX(), $chunk->getZ(), $chunk);
|
||||||
}else{
|
}else{
|
||||||
@ -106,10 +106,11 @@ class GenerationRequestManager{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function handlePackets(){
|
public function handlePackets(){
|
||||||
if(($len = @socket_read($this->socket, 4)) !== false){
|
if(($len = @socket_read($this->socket, 4)) !== false and $len !== ""){
|
||||||
if(strlen($len) < 4){
|
if(strlen($len) < 4){
|
||||||
$len .= $this->socketRead(4 - strlen($len));
|
$len .= $this->socketRead(4 - strlen($len));
|
||||||
}
|
}
|
||||||
|
|
||||||
$packet = $this->socketRead(Binary::readInt($len));
|
$packet = $this->socketRead(Binary::readInt($len));
|
||||||
$pid = ord($packet{0});
|
$pid = ord($packet{0});
|
||||||
$offset = 1;
|
$offset = 1;
|
||||||
@ -124,7 +125,11 @@ class GenerationRequestManager{
|
|||||||
}elseif($pid === GenerationManager::PACKET_SEND_CHUNK){
|
}elseif($pid === GenerationManager::PACKET_SEND_CHUNK){
|
||||||
$levelID = Binary::readInt(substr($packet, $offset, 4));
|
$levelID = Binary::readInt(substr($packet, $offset, 4));
|
||||||
$offset += 4;
|
$offset += 4;
|
||||||
$chunk = SimpleChunk::fromBinary(substr($packet, $offset));
|
$len = ord($packet{$offset++});
|
||||||
|
/** @var FullChunk $class */
|
||||||
|
$class = substr($packet, $offset, $len);
|
||||||
|
$offset += $len;
|
||||||
|
$chunk = $class::fromBinary(substr($packet, $offset));
|
||||||
$this->receiveChunk($levelID, $chunk);
|
$this->receiveChunk($levelID, $chunk);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -87,6 +87,7 @@ class GenerationThread extends \Thread{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function run(){
|
public function run(){
|
||||||
|
error_reporting(-1);
|
||||||
//Load removed dependencies, can't use require_once()
|
//Load removed dependencies, can't use require_once()
|
||||||
foreach($this->loadPaths as $name => $path){
|
foreach($this->loadPaths as $name => $path){
|
||||||
if(!class_exists($name, false) and !class_exists($name, false)){
|
if(!class_exists($name, false) and !class_exists($name, false)){
|
||||||
|
Reference in New Issue
Block a user