From 84d1f4596bdbd048b4b6e84cd936672ef484073a Mon Sep 17 00:00:00 2001 From: Shoghi Cervantes Date: Mon, 27 Apr 2015 14:43:25 +0200 Subject: [PATCH] Improved Anvil live conversion speed --- src/pocketmine/level/format/anvil/Anvil.php | 2 +- src/pocketmine/level/format/anvil/Chunk.php | 77 +++++++++++++++++++ .../level/format/anvil/ChunkRequestTask.php | 57 +++++--------- 3 files changed, 99 insertions(+), 37 deletions(-) diff --git a/src/pocketmine/level/format/anvil/Anvil.php b/src/pocketmine/level/format/anvil/Anvil.php index 4b2c35455..3f13c593a 100644 --- a/src/pocketmine/level/format/anvil/Anvil.php +++ b/src/pocketmine/level/format/anvil/Anvil.php @@ -66,7 +66,7 @@ class Anvil extends McRegion{ } public function requestChunkTask($x, $z){ - return new ChunkRequestTask($this, $this->getLevel()->getId(), $x, $z); + return new ChunkRequestTask($this->getLevel(), $this->getChunk($x, $z, true)); } /** diff --git a/src/pocketmine/level/format/anvil/Chunk.php b/src/pocketmine/level/format/anvil/Chunk.php index e50becebf..de8ad3af6 100644 --- a/src/pocketmine/level/format/anvil/Chunk.php +++ b/src/pocketmine/level/format/anvil/Chunk.php @@ -152,6 +152,83 @@ class Chunk extends BaseChunk{ } } + /** + * @param string $data + * @param LevelProvider $provider + * + * @return Chunk + */ + public static function fromFastBinary($data, LevelProvider $provider = null){ + $nbt = new NBT(NBT::BIG_ENDIAN); + + try{ + $nbt->read($data); + $chunk = $nbt->getData(); + + if(!isset($chunk->Level) or !($chunk->Level instanceof Compound)){ + return null; + } + + return new Chunk($provider instanceof LevelProvider ? $provider : Anvil::class, $chunk->Level); + }catch(\Exception $e){ + return null; + } + } + + public function toFastBinary(){ + $nbt = clone $this->getNBT(); + + $nbt->xPos = new Int("xPos", $this->x); + $nbt->zPos = new Int("zPos", $this->z); + + $nbt->Sections = new Enum("Sections", []); + $nbt->Sections->setTagType(NBT::TAG_Compound); + foreach($this->getSections() as $section){ + if($section instanceof EmptyChunkSection){ + continue; + } + $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()); + + $nbt->HeightMap = new IntArray("HeightMap", $this->getHeightMapArray()); + + $entities = []; + + foreach($this->getEntities() as $entity){ + if(!($entity instanceof Player) and !$entity->closed){ + $entity->saveNBT(); + $entities[] = $entity->namedtag; + } + } + + $nbt->Entities = new Enum("Entities", $entities); + $nbt->Entities->setTagType(NBT::TAG_Compound); + + + $tiles = []; + foreach($this->getTiles() as $tile){ + $tile->saveNBT(); + $tiles[] = $tile->namedtag; + } + + $nbt->TileEntities = new Enum("TileEntities", $tiles); + $nbt->TileEntities->setTagType(NBT::TAG_Compound); + $writer = new NBT(NBT::BIG_ENDIAN); + $nbt->setName("Level"); + $writer->setData(new Compound("", ["Level" => $nbt])); + + return $writer->write(); + } + public function toBinary(){ $nbt = clone $this->getNBT(); diff --git a/src/pocketmine/level/format/anvil/ChunkRequestTask.php b/src/pocketmine/level/format/anvil/ChunkRequestTask.php index 1145a1db2..f982fadcf 100644 --- a/src/pocketmine/level/format/anvil/ChunkRequestTask.php +++ b/src/pocketmine/level/format/anvil/ChunkRequestTask.php @@ -32,30 +32,19 @@ use pocketmine\utils\ChunkException; class ChunkRequestTask extends AsyncTask{ protected $levelId; + + protected $chunk; protected $chunkX; protected $chunkZ; - /** @var \pocketmine\level\format\ChunkSection[] */ - protected $sections; - /** @var string[256] */ - protected $biomeIds; - /** @var int[] */ - protected $biomeColors; - protected $tiles; - public function __construct(Anvil $level, $levelId, $chunkX, $chunkZ){ - $this->levelId = $levelId; - $this->chunkX = $chunkX; - $this->chunkZ = $chunkZ; - $chunk = $level->getChunk($chunkX, $chunkZ, false); - if(!($chunk instanceof Chunk)){ - throw new ChunkException("Invalid Chunk sent"); - } - $this->biomeIds = $chunk->getBiomeIdArray(); - $this->biomeColors = $chunk->getBiomeColorArray(); + public function __construct(Level $level, Chunk $chunk){ + $this->levelId = $level->getId(); - $this->sections = $chunk->getSections(); + $this->chunk = $chunk->toFastBinary(); + $this->chunkX = $chunk->getX(); + $this->chunkZ = $chunk->getZ(); $tiles = ""; $nbt = new NBT(NBT::LITTLE_ENDIAN); @@ -67,26 +56,22 @@ class ChunkRequestTask extends AsyncTask{ } $this->tiles = $tiles; - } public function onRun(){ + + $chunk = Chunk::fromFastBinary($this->chunk); + $ids = $chunk->getBlockIdArray(); + $meta = $chunk->getBlockDataArray(); + $blockLight = $chunk->getBlockLightArray(); + $skyLight = $chunk->getBlockSkyLightArray(); + + $orderedIds = ""; $orderedData = ""; $orderedSkyLight = ""; $orderedLight = ""; - $ids = ""; - $meta = ""; - $blockLight = ""; - $skyLight = ""; - - foreach($this->sections as $section){ - $ids .= $section->getIdArray(); - $meta .= $section->getDataArray(); - $blockLight .= $section->getLightArray(); - $skyLight .= $section->getSkyLightArray(); - } for($x = 0; $x < 16; ++$x){ for($z = 0; $z < 16; ++$z){ @@ -97,16 +82,16 @@ class ChunkRequestTask extends AsyncTask{ } } - $biomeColors = pack("N*", ...$this->biomeColors); + $biomeColors = pack("N*", ...$chunk->getBiomeColorArray()); - $ordered = $orderedIds . $orderedData . $orderedSkyLight . $orderedLight . $this->biomeIds . $biomeColors . $this->tiles; + $ordered = $orderedIds . $orderedData . $orderedSkyLight . $orderedLight . $chunk->getBiomeIdArray() . $biomeColors . $this->tiles; $this->setResult($ordered, false); } - public function getColumn(&$data, $x, $z){ - $i = ($z << 4) + $x; + public function getColumn($data, $x, $z){ $column = ""; + $i = ($z << 4) + $x; for($y = 0; $y < 128; ++$y){ $column .= $data{($y << 8) + $i}; } @@ -114,9 +99,9 @@ class ChunkRequestTask extends AsyncTask{ return $column; } - public function getHalfColumn(&$data, $x, $z){ - $i = ($z << 3) + ($x >> 1); + public function getHalfColumn($data, $x, $z){ $column = ""; + $i = ($z << 3) + ($x >> 1); if(($x & 1) === 0){ for($y = 0; $y < 128; $y += 2){ $column .= ($data{($y << 7) + $i} & "\x0f") | chr((ord($data{(($y + 1) << 7) + $i}) & 0x0f) << 4);