protected function readPacket()
 {
     if (strlen($packet = $this->thread->readMainToThreadPacket()) > 0) {
         $pid = ord($packet[0]);
         $offset = 1;
         if ($pid === self::PACKET_REQUEST_CHUNK) {
             $levelID = Binary::readInt(substr($packet, $offset, 4));
             $offset += 4;
             $chunkX = Binary::readInt(substr($packet, $offset, 4));
             $offset += 4;
             $chunkZ = Binary::readInt(substr($packet, $offset, 4));
             $this->enqueueChunk($levelID, $chunkX, $chunkZ);
         } elseif ($pid === self::PACKET_SEND_CHUNK) {
             $levelID = Binary::readInt(substr($packet, $offset, 4));
             $offset += 4;
             $len = ord($packet[$offset++]);
             /** @var FullChunk $class */
             $class = substr($packet, $offset, $len);
             $offset += $len;
             $chunk = $class::fromBinary(substr($packet, $offset));
             $this->receiveChunk($levelID, $chunk);
         } elseif ($pid === self::PACKET_OPEN_LEVEL) {
             $levelID = Binary::readInt(substr($packet, $offset, 4));
             $offset += 4;
             $seed = Binary::readInt(substr($packet, $offset, 4));
             $offset += 4;
             $len = Binary::readShort(substr($packet, $offset, 2));
             $offset += 2;
             $class = substr($packet, $offset, $len);
             $offset += $len;
             $options = unserialize(substr($packet, $offset));
             $this->openLevel($levelID, $seed, $class, $options);
         } elseif ($pid === self::PACKET_CLOSE_LEVEL) {
             $levelID = Binary::readInt(substr($packet, $offset, 4));
             $this->closeLevel($levelID);
         } elseif ($pid === self::PACKET_ADD_NAMESPACE) {
             $len = Binary::readShort(substr($packet, $offset, 2));
             $offset += 2;
             $namespace = substr($packet, $offset, $len);
             $offset += $len;
             $path = substr($packet, $offset);
             $this->loader->addPath($path);
         } elseif ($pid === self::PACKET_SHUTDOWN) {
             foreach ($this->levels as $level) {
                 $level->shutdown();
             }
             $this->levels = [];
             $this->shutdown = true;
         }
     } elseif (count($this->thread->getInternalQueue()) === 0) {
         $this->thread->synchronized(function () {
             $this->thread->wait(50000);
         });
     }
 }
 public function shutdown()
 {
     $buffer = chr(GenerationManager::PACKET_SHUTDOWN);
     $this->generationThread->pushMainToThreadPacket($buffer);
 }