From 18d13fdc32824a62f480502c2615f1a3c088d111 Mon Sep 17 00:00:00 2001 From: Shoghi Cervantes Date: Thu, 31 Jul 2014 10:19:44 +0200 Subject: [PATCH] Added threaded chunk sending for all formats --- src/pocketmine/level/Level.php | 41 +----- src/pocketmine/level/format/LevelProvider.php | 10 ++ src/pocketmine/level/format/anvil/Anvil.php | 4 + .../{ => format/anvil}/ChunkRequestTask.php | 9 +- .../format/mcregion/ChunkRequestTask.php | 120 ++++++++++++++++++ .../level/format/mcregion/McRegion.php | 4 + 6 files changed, 147 insertions(+), 41 deletions(-) rename src/pocketmine/level/{ => format/anvil}/ChunkRequestTask.php (94%) create mode 100644 src/pocketmine/level/format/mcregion/ChunkRequestTask.php diff --git a/src/pocketmine/level/Level.php b/src/pocketmine/level/Level.php index 216776db0b..0bc901c26f 100644 --- a/src/pocketmine/level/Level.php +++ b/src/pocketmine/level/Level.php @@ -1408,45 +1408,12 @@ class Level implements ChunkManager, Metadatable{ } public function requestChunk($x, $z, Player $player, $order = LevelProvider::ORDER_ZXY){ - if($this->blockOrder === $order){ - $player->sendChunk($x, $z, $this->getNetworkChunk($x, $z)); - }else{ - $index = Level::chunkHash($x, $z); - if(!isset($this->chunkSendQueue[$index])){ - $this->chunkSendQueue[$index] = []; - } - - $this->chunkSendQueue[$index][spl_object_hash($player)] = $player; - } - } - - protected function getNetworkChunk($x, $z){ $index = Level::chunkHash($x, $z); - if(ADVANCED_CACHE == true and ($cache = Cache::get("world:".$this->getID().":" . $index)) !== false){ - return $cache; + if(!isset($this->chunkSendQueue[$index])){ + $this->chunkSendQueue[$index] = []; } - $chunk = $this->getChunkAt($x, $z, true); - $tiles = ""; - $nbt = new NBT(NBT::LITTLE_ENDIAN); - foreach($chunk->getTiles() as $tile){ - if($tile instanceof Spawnable){ - $nbt->setData($tile->getSpawnCompound()); - $tiles .= $nbt->write(); - } - } - - $biomeColors = ""; - foreach($chunk->getBiomeColorArray() as $color){ - $biomeColors .= Binary::writeInt($color); - } - - $encoded = zlib_encode(Binary::writeLInt($x) . Binary::writeLInt($z) . $chunk->getBlockIdArray() . $chunk->getBlockDataArray() . $chunk->getBlockSkyLightArray() . $chunk->getBlockLightArray() . $chunk->getBiomeIdArray() . $biomeColors . $tiles, ZLIB_ENCODING_DEFLATE, Level::$COMPRESSION_LEVEL); - if(ADVANCED_CACHE == true){ - Cache::add("world:".$this->getID().":" . $index, $encoded); - } - - return $encoded; + $this->chunkSendQueue[$index][spl_object_hash($player)] = $player; } protected function processChunkRequest(){ @@ -1467,7 +1434,7 @@ class Level implements ChunkManager, Metadatable{ } unset($this->chunkSendQueue[$index]); }else{ - $task = new ChunkRequestTask($this, $x, $z); + $task = $this->provider->requestChunkTask($x, $z); $this->server->getScheduler()->scheduleAsyncTask($task); $this->chunkSendTasks[$index] = true; } diff --git a/src/pocketmine/level/format/LevelProvider.php b/src/pocketmine/level/format/LevelProvider.php index 3b148b062f..6ae2cbf7d2 100644 --- a/src/pocketmine/level/format/LevelProvider.php +++ b/src/pocketmine/level/format/LevelProvider.php @@ -52,6 +52,16 @@ interface LevelProvider{ */ public static function usesChunkSection(); + /** + * Requests a MC: PE network chunk to be sent + * + * @param int $x + * @param int $z + * + * @return \pocketmine\scheduler\AsyncTask + */ + public function requestChunkTask($x, $z); + /** @return string */ public function getPath(); diff --git a/src/pocketmine/level/format/anvil/Anvil.php b/src/pocketmine/level/format/anvil/Anvil.php index b217201220..1a87d89db7 100644 --- a/src/pocketmine/level/format/anvil/Anvil.php +++ b/src/pocketmine/level/format/anvil/Anvil.php @@ -70,6 +70,10 @@ class Anvil extends McRegion{ return $isValid; } + public function requestChunkTask($x, $z){ + return new ChunkRequestTask($this, $this->getLevel()->getID(), $x, $z); + } + public function loadChunk($chunkX, $chunkZ, $create = false){ $index = Level::chunkHash($chunkX, $chunkZ); if(isset($this->chunks[$index])){ diff --git a/src/pocketmine/level/ChunkRequestTask.php b/src/pocketmine/level/format/anvil/ChunkRequestTask.php similarity index 94% rename from src/pocketmine/level/ChunkRequestTask.php rename to src/pocketmine/level/format/anvil/ChunkRequestTask.php index 01df7af0fb..d3d082d5c1 100644 --- a/src/pocketmine/level/ChunkRequestTask.php +++ b/src/pocketmine/level/format/anvil/ChunkRequestTask.php @@ -19,8 +19,9 @@ * */ -namespace pocketmine\level; +namespace pocketmine\level\format\anvil; +use pocketmine\level\Level; use pocketmine\nbt\NBT; use pocketmine\scheduler\AsyncTask; use pocketmine\Server; @@ -43,11 +44,11 @@ class ChunkRequestTask extends AsyncTask{ protected $tiles; - public function __construct(Level $level, $chunkX, $chunkZ){ - $this->levelId = $level->getID(); + public function __construct(Anvil $level, $levelId, $chunkX, $chunkZ){ + $this->levelId = $levelId; $this->chunkX = $chunkX; $this->chunkZ = $chunkZ; - $chunk = $level->getChunkAt($chunkX, $chunkZ, true); + $chunk = $level->getChunk($chunkX, $chunkZ, true); $this->biomeIds = $chunk->getBiomeIdArray(); $this->biomeColors = $chunk->getBiomeColorArray(); diff --git a/src/pocketmine/level/format/mcregion/ChunkRequestTask.php b/src/pocketmine/level/format/mcregion/ChunkRequestTask.php new file mode 100644 index 0000000000..ad0e7f9410 --- /dev/null +++ b/src/pocketmine/level/format/mcregion/ChunkRequestTask.php @@ -0,0 +1,120 @@ +levelId = $levelId; + $this->chunkX = $chunkX; + $this->chunkZ = $chunkZ; + $chunk = $level->getChunk($chunkX, $chunkZ, true); + $this->blocks = $chunk->getBlockIdArray(); + $this->data = $chunk->getBlockDataArray(); + $this->skyLight = $chunk->getBlockSkyLightArray(); + $this->blockLight = $chunk->getBlockLightArray(); + $this->biomeIds = $chunk->getBiomeIdArray(); + $this->biomeColors = $chunk->getBiomeColorArray(); + + $tiles = ""; + $nbt = new NBT(NBT::LITTLE_ENDIAN); + foreach($chunk->getTiles() as $tile){ + if($tile instanceof Spawnable){ + $nbt->setData($tile->getSpawnCompound()); + $tiles .= $nbt->write(); + } + } + + $this->tiles = $tiles; + + $this->compressionLevel = Level::$COMPRESSION_LEVEL; + + } + + public function onRun(){ + $biomeColors = ""; + + foreach($this->biomeColors as $color){ + $biomeColors .= Binary::writeInt($color); + } + + $ordered = zlib_encode(Binary::writeLInt($this->chunkX) . Binary::writeLInt($this->chunkZ) . $this->blocks . $this->data . $this->skyLight . $this->blockLight . $this->biomeIds . $biomeColors . $this->tiles, ZLIB_ENCODING_DEFLATE, $this->compressionLevel); + + $this->setResult($ordered); + } + + public function getColumn(&$data, $x, $z){ + $i = ($z << 4) + $x; + $column = ""; + for($y = 0; $y < 128; ++$y){ + $column .= $data{($y << 8) + $i}; + } + return $column; + } + + public function getHalfColumn(&$data, $x, $z){ + $i = ($z << 3) + ($x >> 1); + $column = ""; + 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); + } + }else{ + for($y = 0; $y < 128; $y += 2){ + $column .= chr((ord($data{($y << 7) + $i}) & 0xf0) >> 4) | ($data{(($y + 1) << 7) + $i} & "\xf0"); + } + } + return $column; + } + + public function onCompletion(Server $server){ + $level = $server->getLevel($this->levelId); + if($level instanceof Level and $this->hasResult()){ + $level->chunkRequestCallback($this->chunkX, $this->chunkZ, $this->getResult()); + } + } + +} \ No newline at end of file diff --git a/src/pocketmine/level/format/mcregion/McRegion.php b/src/pocketmine/level/format/mcregion/McRegion.php index 2a6de7a62f..2088a04a60 100644 --- a/src/pocketmine/level/format/mcregion/McRegion.php +++ b/src/pocketmine/level/format/mcregion/McRegion.php @@ -104,6 +104,10 @@ class McRegion extends BaseLevelProvider{ $z = $chunkZ >> 5; } + public function requestChunkTask($x, $z){ + return new ChunkRequestTask($this, $this->getLevel()->getID(), $x, $z); + } + public function unloadChunks(){ $this->chunks = []; }