/** * @param LevelProvider $provider * @param int $x * @param int $z * @param string $blocks * @param string $data * @param string $skyLight * @param string $blockLight * @param string $biomeIds * @param int[] $biomeColors * @param int[] $heightMap * @param Compound[] $entities * @param Compound[] $tiles */ protected function __construct($provider, $x, $z, $blocks, $data, $skyLight, $blockLight, $biomeIds = null, array $biomeColors = [], array $heightMap = [], array $entities = [], array $tiles = []) { $this->provider = $provider; $this->x = (int) $x; $this->z = (int) $z; $this->blocks = $blocks; $this->data = $data; $this->skyLight = $skyLight; $this->blockLight = $blockLight; if (strlen($biomeIds) === 256) { $this->biomeIds = $biomeIds; } else { $this->biomeIds = str_repeat("", 256); } if (count($biomeColors) === 256) { $this->biomeColors = $biomeColors; } else { $this->biomeColors = array_fill(0, 256, Binary::readInt("…²J")); } if (count($heightMap) === 256) { $this->heightMap = $heightMap; } else { $this->heightMap = array_fill(0, 256, 127); } $this->NBTtiles = $tiles; $this->NBTentities = $entities; }
public function generateChunk($x, $z) { $nbt = new Compound("Level", []); $nbt->xPos = new Int("xPos", $this->getX() * 32 + $x); $nbt->zPos = new Int("zPos", $this->getZ() * 32 + $z); $nbt->LastUpdate = new Long("LastUpdate", 0); $nbt->LightPopulated = new Byte("LightPopulated", 0); $nbt->TerrainPopulated = new Byte("TerrainPopulated", 0); $nbt->V = new Byte("V", self::VERSION); $nbt->InhabitedTime = new Long("InhabitedTime", 0); $biomes = str_repeat(Binary::writeByte(-1), 256); $nbt->Biomes = new ByteArray("Biomes", $biomes); $nbt->BiomeColors = new IntArray("BiomeColors", array_fill(0, 156, Binary::readInt("…²J"))); $nbt->HeightMap = new IntArray("HeightMap", array_fill(0, 256, 127)); $nbt->Sections = new Enum("Sections", []); $nbt->Sections->setTagType(NBT::TAG_Compound); $nbt->Entities = new Enum("Entities", []); $nbt->Entities->setTagType(NBT::TAG_Compound); $nbt->TileEntities = new Enum("TileEntities", []); $nbt->TileEntities->setTagType(NBT::TAG_Compound); $nbt->TileTicks = new Enum("TileTicks", []); $nbt->TileTicks->setTagType(NBT::TAG_Compound); $writer = new NBT(NBT::BIG_ENDIAN); $nbt->setName("Level"); $writer->setData(new Compound("", ["Level" => $nbt])); $chunkData = $writer->writeCompressed(ZLIB_ENCODING_DEFLATE, RegionLoader::$COMPRESSION_LEVEL); $this->saveChunk($x, $z, $chunkData); }
/** * @param LevelProvider $provider * @param int $x * @param int $z * @param ChunkSection[] $sections * @param string $biomeIds * @param int[] $biomeColors * @param int[] $heightMap * @param Compound[] $entities * @param Compound[] $tiles * * @throws ChunkException */ protected function __construct($provider, $x, $z, array $sections, $biomeIds = null, array $biomeColors = [], array $heightMap = [], array $entities = [], array $tiles = []) { $this->provider = $provider; $this->x = (int) $x; $this->z = (int) $z; foreach ($sections as $Y => $section) { if ($section instanceof ChunkSection) { $this->sections[$Y] = $section; } else { throw new ChunkException("Received invalid ChunkSection instance"); } if ($Y >= self::SECTION_COUNT) { throw new ChunkException("Invalid amount of chunks"); } } if (strlen($biomeIds) === 256) { $this->biomeIds = $biomeIds; } else { $this->biomeIds = str_repeat("", 256); } if (count($biomeColors) === 256) { $this->biomeColors = $biomeColors; } else { $this->biomeColors = array_fill(0, 256, Binary::readInt("…²J")); } if (count($heightMap) === 256) { $this->heightMap = $heightMap; } else { $this->heightMap = array_fill(0, 256, 127); } $this->NBTtiles = $tiles; $this->NBTentities = $entities; }
public function handle($address, $port, $packet) { $offset = 2; $packetType = ord($packet[$offset++]); $sessionID = Binary::readInt(substr($packet, $offset, 4)); $offset += 4; $payload = substr($packet, $offset); switch ($packetType) { case self::HANDSHAKE: //Handshake $reply = chr(self::HANDSHAKE); $reply .= Binary::writeInt($sessionID); $reply .= self::getTokenString($this->token, $address) . ""; $this->server->getNetwork()->sendPacket($address, $port, $reply); break; case self::STATISTICS: //Stat $token = Binary::readInt(substr($payload, 0, 4)); if ($token !== self::getTokenString($this->token, $address) and $token !== self::getTokenString($this->lastToken, $address)) { break; } $reply = chr(self::STATISTICS); $reply .= Binary::writeInt($sessionID); if ($this->timeout < microtime(true)) { $this->regenerateInfo(); } if (strlen($payload) === 8) { $reply .= $this->longData; } else { $reply .= $this->shortData; } $this->server->getNetwork()->sendPacket($address, $port, $reply); break; } }
public function __construct($level, Compound $nbt) { $this->nbt = $nbt; if (!isset($this->nbt->Entities) or !$this->nbt->Entities instanceof Enum) { $this->nbt->Entities = new Enum("Entities", []); $this->nbt->Entities->setTagType(NBT::TAG_Compound); } if (!isset($this->nbt->TileEntities) or !$this->nbt->TileEntities instanceof Enum) { $this->nbt->TileEntities = new Enum("TileEntities", []); $this->nbt->TileEntities->setTagType(NBT::TAG_Compound); } if (!isset($this->nbt->TileTicks) or !$this->nbt->TileTicks instanceof Enum) { $this->nbt->TileTicks = new Enum("TileTicks", []); $this->nbt->TileTicks->setTagType(NBT::TAG_Compound); } if (!isset($this->nbt->Sections) or !$this->nbt->Sections instanceof Enum) { $this->nbt->Sections = new Enum("Sections", []); $this->nbt->Sections->setTagType(NBT::TAG_Compound); } if (!isset($this->nbt->Biomes) or !$this->nbt->Biomes instanceof ByteArray) { $this->nbt->Biomes = new ByteArray("Biomes", \str_repeat("", 256)); } if (!isset($this->nbt->BiomeColors) or !$this->nbt->BiomeColors instanceof IntArray) { $this->nbt->BiomeColors = new IntArray("BiomeColors", array_fill(0, 256, Binary::readInt("…²J"))); } if (!isset($this->nbt->HeightMap) or !$this->nbt->HeightMap instanceof IntArray) { $this->nbt->HeightMap = new IntArray("HeightMap", \array_fill(0, 256, 127)); } $sections = []; foreach ($this->nbt->Sections as $section) { if ($section instanceof Compound) { $y = (int) $section["Y"]; if ($y < 8) { $sections[$y] = new ChunkSection($section); } } } for ($y = 0; $y < 8; ++$y) { if (!isset($sections[$y])) { $sections[$y] = new EmptyChunkSection($y); } } parent::__construct($level, (int) $this->nbt["xPos"], (int) $this->nbt["zPos"], $sections, $this->nbt->Biomes->getValue(), $this->nbt->BiomeColors->getValue(), $this->nbt->HeightMap->getValue(), $this->nbt->Entities->getValue(), $this->nbt->TileEntities->getValue()); unset($this->nbt->Sections); }
public function __construct($level, Compound $nbt) { $this->nbt = $nbt; if (isset($this->nbt->Entities) and $this->nbt->Entities instanceof Enum) { $this->nbt->Entities->setTagType(NBT::TAG_Compound); } else { $this->nbt->Entities = new Enum("Entities", []); $this->nbt->Entities->setTagType(NBT::TAG_Compound); } if (isset($this->nbt->TileEntities) and $this->nbt->TileEntities instanceof Enum) { $this->nbt->TileEntities->setTagType(NBT::TAG_Compound); } else { $this->nbt->TileEntities = new Enum("TileEntities", []); $this->nbt->TileEntities->setTagType(NBT::TAG_Compound); } if (isset($this->nbt->TileTicks) and $this->nbt->TileTicks instanceof Enum) { $this->nbt->TileTicks->setTagType(NBT::TAG_Compound); } else { $this->nbt->TileTicks = new Enum("TileTicks", []); $this->nbt->TileTicks->setTagType(NBT::TAG_Compound); } if (!isset($this->nbt->Biomes) or !$this->nbt->Biomes instanceof ByteArray) { $this->nbt->Biomes = new ByteArray("Biomes", str_repeat("", 256)); } if (!isset($this->nbt->BiomeColors) or !$this->nbt->BiomeColors instanceof IntArray) { $this->nbt->BiomeColors = new IntArray("BiomeColors", array_fill(0, 256, Binary::readInt("…²J"))); } if (!isset($this->nbt->HeightMap) or !$this->nbt->HeightMap instanceof IntArray) { $this->nbt->HeightMap = new IntArray("HeightMap", array_fill(0, 256, 127)); } if (!isset($this->nbt->Blocks)) { $this->nbt->Blocks = new ByteArray("Blocks", str_repeat("", 32768)); } if (!isset($this->nbt->Data)) { $this->nbt->Data = new ByteArray("Data", $half = str_repeat("", 16384)); $this->nbt->SkyLight = new ByteArray("SkyLight", $half); $this->nbt->BlockLight = new ByteArray("BlockLight", $half); } parent::__construct($level, $this->nbt["xPos"], $this->nbt["zPos"], $this->nbt->Blocks->getValue(), $this->nbt->Data->getValue(), $this->nbt->SkyLight->getValue(), $this->nbt->BlockLight->getValue(), $this->nbt->Biomes->getValue(), $this->nbt->BiomeColors->getValue(), $this->nbt->HeightMap->getValue(), $this->nbt->Entities->getValue(), $this->nbt->TileEntities->getValue()); unset($this->nbt->Blocks); unset($this->nbt->Data); unset($this->nbt->SkyLight); unset($this->nbt->BlockLight); }
/** * Generates a new level if it does not exists * * @param string $name * @param int $seed * @param string $generator Class name that extends pocketmine\level\generator\Generator * @param array $options * * @return bool */ public function generateLevel($name, $seed = null, $generator = null, $options = []) { if (trim($name) === "" or $this->isLevelGenerated($name)) { return false; } $seed = $seed === null ? Binary::readInt(@Utils::getRandomBytes(4, false)) : (int) $seed; if ($generator !== null and class_exists($generator) and is_subclass_of($generator, Generator::class)) { $generator = new $generator($options); } else { $options["preset"] = $this->getConfigString("generator-settings", ""); $generator = Generator::getGenerator($this->getLevelType()); } if (($provider = LevelProviderManager::getProviderByName($providerName = $this->getProperty("level-settings.default-format", "mcregion"))) === null) { $provider = LevelProviderManager::getProviderByName($providerName = "mcregion"); } try { $path = $this->getDataPath() . "worlds/" . $name . "/"; /** @var \pocketmine\level\format\LevelProvider $provider */ $provider::generate($path, $name, $seed, $generator, $options); $level = new Level($this, $name, $path, $provider); $this->levels[$level->getId()] = $level; $level->initLevel(); } catch (\Exception $e) { $this->logger->error("Could not generate level \"" . $name . "\": " . $e->getMessage()); if ($this->logger instanceof MainLogger) { $this->logger->logException($e); } return false; } $this->getPluginManager()->callEvent(new LevelInitEvent($level)); $this->getPluginManager()->callEvent(new LevelLoadEvent($level)); $this->getLogger()->notice("Spawn terrain for level \"{$name}\" is being generated in the background"); $radiusSquared = ($this->getViewDistance() + 1) / M_PI; $radius = ceil(sqrt($radiusSquared)); $centerX = $level->getSpawnLocation()->getX() >> 4; $centerZ = $level->getSpawnLocation()->getZ() >> 4; $order = []; for ($X = -$radius; $X <= $radius; ++$X) { for ($Z = -$radius; $Z <= $radius; ++$Z) { $distance = $X ** 2 + $Z ** 2; if ($distance > $radiusSquared) { continue; } $chunkX = $X + $centerX; $chunkZ = $Z + $centerZ; $index = Level::chunkHash($chunkX, $chunkZ); $order[$index] = $distance; } } asort($order); $chunkX = $chunkZ = null; foreach ($order as $index => $distance) { Level::getXZ($index, $chunkX, $chunkZ); $level->generateChunk($chunkX, $chunkZ); } return true; }
public function readInt($signed = true) { $int = Binary::readInt($this->read(4)); if (!$signed and $int < 0) { $int += 0x100000000; } return $int; }
public function getInt() { return $this->endianness === self::BIG_ENDIAN ? Binary::readInt($this->get(4)) : Binary::readLInt($this->get(4)); }
public function loadChunk($X, $Z) { if ($this->isChunkLoaded($X, $Z)) { return true; } $index = self::getIndex($X, $Z); $path = $this->getChunkPath($X, $Z); if (!file_exists($path)) { if ($this->generateChunk($X, $Z) === false) { return false; } if ($this->isGenerating === 0) { $this->populateChunk($X, $Z); } return true; } $chunk = file_get_contents($path); if ($chunk === false) { return false; } $chunk = zlib_decode($chunk); $offset = 0; $this->chunkInfo[$index] = [0 => ord($chunk[0]), 1 => Binary::readInt(substr($chunk, 1, 4))]; $offset += 5; $len = Binary::readInt(substr($chunk, $offset, 4)); $offset += 4; $nbt = new NBT(NBT::BIG_ENDIAN); $nbt->read(substr($chunk, $offset, $len)); $this->chunkInfo[$index][2] = $nbt->getData(); $offset += $len; $this->chunks[$index] = []; $this->chunkChange[$index] = [-1 => false]; $this->chunkInfo[$index][3] = substr($chunk, $offset, 256); //Biome data $offset += 256; for ($Y = 0; $Y < 8; ++$Y) { if (($this->chunkInfo[$index][0] & 1 << $Y) !== 0) { // 4096 + 2048 + 2048, Block Data, Meta, Light if (strlen($this->chunks[$index][$Y] = substr($chunk, $offset, 8192)) < 8192) { MainLogger::getLogger()->notice("Empty corrupt chunk detected [{$X},{$Z},:{$Y}], recovering contents"); $this->fillMiniChunk($X, $Z, $Y); } $offset += 8192; } else { $this->chunks[$index][$Y] = false; } } if ($this->isGenerating === 0 and !$this->isPopulated($X, $Z)) { $this->populateChunk($X, $Z); } return true; }
/** * Generates a new level if it does not exists * * @param string $name * @param int $seed * @param string $generator Class name that extends pocketmine\level\generator\Noise * @param array $options * * @return bool */ public function generateLevel($name, $seed = null, $generator = null, $options = []) { if (trim($name) === "" or $this->isLevelGenerated($name)) { return false; } $seed = $seed === null ? Binary::readInt(@Utils::getRandomBytes(4, false)) : (int) $seed; if (!isset($options["preset"])) { $options["preset"] = $this->getConfigString("generator-settings", ""); } if (!($generator !== null and class_exists($generator, true) and is_subclass_of($generator, Generator::class))) { $generator = Generator::getGenerator($this->getLevelType()); } if (($provider = LevelProviderManager::getProviderByName($providerName = $this->getProperty("level-settings.default-format", "mcregion"))) === null) { $provider = LevelProviderManager::getProviderByName($providerName = "mcregion"); } try { $path = $this->getDataPath() . "worlds/" . $name . "/"; /** @var \pocketmine\level\format\LevelProvider $provider */ $provider::generate($path, $name, $seed, $generator, $options); $level = new Level($this, $name, $path, $provider); $this->levels[$level->getId()] = $level; $level->initLevel(); $level->setTickRate($this->baseTickRate); } catch (\Exception $e) { $this->logger->error($this->getLanguage()->translateString("pocketmine.level.generateError", [$name, $e->getMessage()])); if ($this->logger instanceof MainLogger) { $this->logger->logException($e); } return false; } $this->getPluginManager()->callEvent(new LevelInitEvent($level)); $this->getPluginManager()->callEvent(new LevelLoadEvent($level)); $this->getLogger()->notice($this->getLanguage()->translateString("pocketmine.level.backgroundGeneration", [$name])); $centerX = $level->getSpawnLocation()->getX() >> 4; $centerZ = $level->getSpawnLocation()->getZ() >> 4; $order = []; for ($X = -3; $X <= 3; ++$X) { for ($Z = -3; $Z <= 3; ++$Z) { $distance = $X ** 2 + $Z ** 2; $chunkX = $X + $centerX; $chunkZ = $Z + $centerZ; $index = Level::chunkHash($chunkX, $chunkZ); $order[$index] = $distance; } } asort($order); foreach ($order as $index => $distance) { Level::getXZ($index, $chunkX, $chunkZ); $level->populateChunk($chunkX, $chunkZ, true); } return true; }
public function doSlowCleanUp() { for ($i = 0; $i < 1024; ++$i) { if ($this->locationTable[$i][0] === 0 or $this->locationTable[$i][1] === 0) { continue; } fseek($this->filePointer, $this->locationTable[$i][0] << 12); $chunk = fread($this->filePointer, $this->locationTable[$i][1] << 12); $length = Binary::readInt(substr($chunk, 0, 4)); if ($length <= 1) { $this->locationTable[$i] = [0, 0, 0]; //Non-generated chunk, remove it from index } try { $chunk = zlib_decode(substr($chunk, 5)); } catch (\Exception $e) { $this->locationTable[$i] = [0, 0, 0]; //Corrupted chunk, remove it continue; } $chunk = chr(self::COMPRESSION_ZLIB) . zlib_encode($chunk, ZLIB_ENCODING_DEFLATE, 9); $chunk = Binary::writeInt(strlen($chunk)) . $chunk; $sectors = (int) ceil(strlen($chunk) / 4096); if ($sectors > $this->locationTable[$i][1]) { $this->locationTable[$i][0] = $this->lastSector + 1; $this->lastSector += $sectors; } fseek($this->filePointer, $this->locationTable[$i][0] << 12); fwrite($this->filePointer, str_pad($chunk, $sectors << 12, "", STR_PAD_RIGHT)); } $this->writeLocationTable(); $n = $this->cleanGarbage(); $this->writeLocationTable(); return $n; }
protected function getInt() { return Binary::readInt($this->get(4)); }
public function handle($address, $port, $packet) { $offset = 2; $packetType = ord($packet[$offset++]); $sessionID = Binary::readInt(substr($packet, $offset, 4)); $offset += 4; $payload = substr($packet, $offset); switch ($packetType) { case self::HANDSHAKE: //Handshake $reply = chr(self::HANDSHAKE); $reply .= Binary::writeInt($sessionID); $reply .= self::getTokenString($this->token, $address) . ""; $this->server->sendPacket($address, $port, $reply); break; case self::STATISTICS: //Stat $token = Binary::readInt(substr($payload, 0, 4)); if ($token !== self::getTokenString($this->token, $address) and $token !== self::getTokenString($this->lastToken, $address)) { break; } $reply = chr(self::STATISTICS); $reply .= Binary::writeInt($sessionID); if (strlen($payload) === 8) { if ($this->timeout < microtime(true)) { $this->regenerateInfo(); } $reply .= $this->longData; } else { $reply .= $this->server->getServerName() . "" . (($this->server->getGamemode() & 0x1) === 0 ? "SMP" : "CMP") . "" . ($this->server->getDefaultLevel() === null ? "unknown" : $this->server->getDefaultLevel()->getName()) . "" . count($this->server->getOnlinePlayers()) . "" . $this->server->getMaxPlayers() . "" . Binary::writeLShort($this->server->getPort()) . $this->server->getIp() . ""; } $this->server->sendPacket($address, $port, $reply); break; } }
public static function decompressName($compressed) { $int = substr($compressed, 0, 4); $long = substr($compressed, 4, 8); /** @var int $value */ $value = Binary::readInt($int, false); $value <<= 32; $value += Binary::readLong($long, false); $out = ""; for ($offset = 0; $offset <= 16; $offset++) { $ord = $value & 0b111111; if (0 <= $ord and $ord <= 9) { $chr = chr(ord("0") + $ord); } else { $ord -= 10; if ($ord <= 25) { $chr = chr(ord("a") + $ord); } else { $chr = "_"; } // corrupted databases will lead to a large amount of underscores } $out = $chr . $out; } return $out; }
public function getInt(bool $network = false) { if ($network === true) { return Binary::readVarInt($this); } return $this->endianness === self::BIG_ENDIAN ? Binary::readInt($this->get(4)) : Binary::readLInt($this->get(4)); }
public function handlePackets() { while (strlen($packet = $this->generationThread->readThreadToMainPacket()) > 0) { $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 readPacket() { $packets = []; if ($this->receiveBuffer !== "" && strlen($this->receiveBuffer) > 0) { $len = strlen($this->receiveBuffer); $offset = 0; while ($offset < $len) { if ($offset > $len - 4) { break; } $pkLen = Binary::readInt(substr($this->receiveBuffer, $offset, 4)); $offset += 4; if ($pkLen <= $len - $offset) { $buf = substr($this->receiveBuffer, $offset, $pkLen); $offset += $pkLen; $packets[] = $buf; } else { $offset -= 4; break; } } if ($offset < $len) { $this->receiveBuffer = substr($this->receiveBuffer, $offset); } else { $this->receiveBuffer = ""; } } return $packets; }
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 static function fromFastBinary($data, LevelProvider $provider = null) { try { $offset = 0; $chunk = new Chunk($provider instanceof LevelProvider ? $provider : McRegion::class, null); $chunk->provider = $provider; $chunk->x = Binary::readInt(substr($data, $offset, 4)); $offset += 4; $chunk->z = Binary::readInt(substr($data, $offset, 4)); $offset += 4; $chunk->blocks = substr($data, $offset, 32768); $offset += 32768; $chunk->data = substr($data, $offset, 16384); $offset += 16384; $chunk->skyLight = substr($data, $offset, 16384); $offset += 16384; $chunk->blockLight = substr($data, $offset, 16384); $offset += 16384; $chunk->heightMap = array_values(unpack("C*", substr($data, $offset, 256))); $offset += 256; $chunk->biomeColors = array_values(unpack("N*", substr($data, $offset, 1024))); $offset += 1024; $flags = ord($data[$offset++]); $chunk->nbt->TerrainGenerated = new Byte("TerrainGenerated", $flags & 0b1); $chunk->nbt->TerrainPopulated = new Byte("TerrainPopulated", $flags >> 1 & 0b1); $chunk->nbt->LightPopulated = new Byte("LightPopulated", $flags >> 2 & 0b1); return $chunk; } catch (\Exception $e) { return null; } }
public function processBatch(BatchPacket $packet, Player $p) { $str = zlib_decode($packet->payload, 1024 * 1024 * 64); //Max 64MB $len = strlen($str); $offset = 0; try { while ($offset < $len) { $pkLen = Binary::readInt(substr($str, $offset, 4)); $offset += 4; $buf = substr($str, $offset, $pkLen); $offset += $pkLen; if (($pk = $this->getPacket(ord($buf[1]))) !== null) { if ($pk::NETWORK_ID === Info::BATCH_PACKET) { throw new \InvalidStateException("Invalid BatchPacket inside BatchPacket"); } $pk->setBuffer($buf, 2); $pk->decode(); $p->handleDataPacket($pk); if ($pk->getOffset() <= 0) { return; } } } } catch (\Throwable $e) { if (\pocketmine\DEBUG > 1) { $logger = $this->server->getLogger(); if ($logger instanceof MainLogger) { $logger->debug("BatchPacket " . " 0x" . bin2hex($packet->payload)); $logger->logException($e); } } } }
/** * @param int $chunkX * @param int $chunkZ * @param LevelProvider $provider * * @return Chunk */ public static function getEmptyChunk($chunkX, $chunkZ, LevelProvider $provider = null) { try { $chunk = new Chunk($provider instanceof LevelProvider ? $provider : McRegion::class, null); $chunk->x = $chunkX; $chunk->z = $chunkZ; $chunk->data = str_repeat("", 16384); $chunk->blocks = $chunk->data . $chunk->data; $chunk->skyLight = str_repeat("ÿ", 16384); $chunk->blockLight = $chunk->data; $chunk->heightMap = array_fill(0, 256, 0); $chunk->biomeColors = array_fill(0, 256, Binary::readInt("…²J")); $chunk->nbt->V = new Byte("V", 1); $chunk->nbt->InhabitedTime = new Long("InhabitedTime", 0); $chunk->nbt->TerrainGenerated = new Byte("TerrainGenerated", 0); $chunk->nbt->TerrainPopulated = new Byte("TerrainPopulated", 0); $chunk->nbt->LightPopulated = new Byte("LightPopulated", 0); return $chunk; } catch (\Exception $e) { return null; } }
public function getInt() { return Binary::readInt($this->get(4)); }
public static function fromFastBinary($data, LevelProvider $provider = null) { try { $offset = 0; $chunk = new Chunk($provider instanceof LevelProvider ? $provider : McRegion::class, null); $chunk->provider = $provider; $chunk->x = Binary::readInt(substr($data, $offset, 4)); $offset += 4; $chunk->z = Binary::readInt(substr($data, $offset, 4)); $offset += 4; $chunk->blocks = substr($data, $offset, 32768); $offset += 32768; $chunk->data = substr($data, $offset, 16384); $offset += 16384; $chunk->skyLight = substr($data, $offset, 16384); $offset += 16384; $chunk->blockLight = substr($data, $offset, 16384); $offset += 16384; $chunk->biomeIds = substr($data, $offset, 256); $offset += 256; $chunk->biomeColors = []; $chunk->heightMap = []; $bc = unpack("N*", substr($data, $offset, 1024)); $offset += 1024; $hm = unpack("N*", substr($data, $offset, 1024)); $offset += 1024; for ($i = 0; $i < 256; ++$i) { $chunk->biomeColors[$i] = $bc[$i + 1]; $chunk->heightMap[$i] = $hm[$i + 1]; } $flags = ord($data[$offset++]); $chunk->nbt->TerrainGenerated = new Byte("TerrainGenerated", $flags & 0b1); $chunk->nbt->TerrainPopulated = new Byte("TerrainPopulated", $flags >> 1); return $chunk; } catch (\Exception $e) { return null; } }