server = $server; $this->generationThread = new GenerationThread($server->getLogger(), $server->getLoader()); $this->socket = $this->generationThread->getExternalSocket(); } /** * @param Level $level * @param string $generator * @param array $options */ public function openLevel(Level $level, $generator, array $options = []){ $buffer = chr(GenerationManager::PACKET_OPEN_LEVEL) . Binary::writeInt($level->getID()) . Binary::writeInt($level->getSeed()) . Binary::writeShort(strlen($generator)) . $generator . serialize($options); @socket_write($this->socket, Binary::writeInt(strlen($buffer)) . $buffer); } /** * @param Level $level */ public function closeLevel(Level $level){ $buffer = chr(GenerationManager::PACKET_CLOSE_LEVEL) . Binary::writeInt($level->getID()); @socket_write($this->socket, Binary::writeInt(strlen($buffer)) . $buffer); } public function addNamespace($namespace, $path){ $buffer = chr(GenerationManager::PACKET_ADD_NAMESPACE) . Binary::writeShort(strlen($namespace)) . $namespace . $path; @socket_write($this->socket, Binary::writeInt(strlen($buffer)) . $buffer); } protected function socketRead($len){ $buffer = ""; while(strlen($buffer) < $len){ $buffer .= @socket_read($this->socket, $len - strlen($buffer)); } return $buffer; } protected function sendChunk($levelID, FullChunk $chunk){ $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); } public function requestChunk(Level $level, $chunkX, $chunkZ){ $buffer = chr(GenerationManager::PACKET_REQUEST_CHUNK) . Binary::writeInt($level->getID()) . Binary::writeInt($chunkX) . Binary::writeInt($chunkZ); @socket_write($this->socket, Binary::writeInt(strlen($buffer)) . $buffer); } protected function handleRequest($levelID, $chunkX, $chunkZ){ if(($level = $this->server->getLevel($levelID)) instanceof Level){ $this->sendChunk($levelID, $level->getChunkAt($chunkX, $chunkZ, true)); }else{ $buffer = chr(GenerationManager::PACKET_CLOSE_LEVEL) . Binary::writeInt($levelID); @socket_write($this->socket, Binary::writeInt(strlen($buffer)) . $buffer); } } protected function receiveChunk($levelID, FullChunk $chunk){ if(($level = $this->server->getLevel($levelID)) instanceof Level){ $level->generateChunkCallback($chunk->getX(), $chunk->getZ(), $chunk); }else{ $buffer = chr(GenerationManager::PACKET_CLOSE_LEVEL) . Binary::writeInt($levelID); @socket_write($this->socket, Binary::writeInt(strlen($buffer)) . $buffer); } } public function handlePackets(){ if(($len = @socket_read($this->socket, 4)) !== false and $len !== ""){ if(strlen($len) < 4){ $len .= $this->socketRead(4 - strlen($len)); } $packet = $this->socketRead(Binary::readInt($len)); $pid = ord($packet{0}); $offset = 1; if($pid === GenerationManager::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->handleRequest($levelID, $chunkX, $chunkZ); }elseif($pid === GenerationManager::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; $level = $this->server->getLevel($levelID); if($level instanceof Level){ $chunk = $class::fromBinary(substr($packet, $offset), $level->getProvider()); $this->receiveChunk($levelID, $chunk); } } } } public function shutdown(){ $buffer = chr(GenerationManager::PACKET_SHUTDOWN); @socket_write($this->socket, Binary::writeInt(strlen($buffer)) . $buffer); $this->generationThread->join(); } }