public function requestChunkTask($x, $z) { $chunk = $this->getChunk($x, $z, false); if (!$chunk instanceof Chunk) { throw new ChunkException("Invalid Chunk sent"); } $tiles = ""; if (count($chunk->getTiles()) > 0) { $nbt = new NBT(NBT::LITTLE_ENDIAN); $list = []; foreach ($chunk->getTiles() as $tile) { if ($tile instanceof Spawnable) { $list[] = $tile->getSpawnCompound(); } } $nbt->setData($list); $tiles = $nbt->write(true); } $extraData = new BinaryStream(); $extraData->putLInt(count($chunk->getBlockExtraDataArray())); foreach ($chunk->getBlockExtraDataArray() as $key => $value) { $extraData->putLInt($key); $extraData->putLShort($value); } $ordered = $chunk->getBlockIdArray() . $chunk->getBlockDataArray() . $chunk->getBlockSkyLightArray() . $chunk->getBlockLightArray() . pack("C*", ...$chunk->getHeightMapArray()) . pack("N*", ...$chunk->getBiomeColorArray()) . $extraData->getBuffer() . $tiles; $this->getLevel()->chunkRequestCallback($x, $z, $ordered, FullChunkDataPacket::ORDER_LAYERED); return null; }
public function onRun() { $chunk = Chunk::fromFastBinary($this->chunk); $extraData = new BinaryStream(); $extraData->putLInt(count($chunk->getBlockExtraDataArray())); foreach ($chunk->getBlockExtraDataArray() as $key => $value) { $extraData->putLInt($key); $extraData->putLShort($value); } $ordered = $chunk->getBlockIdArray() . $chunk->getBlockDataArray() . $chunk->getBlockSkyLightArray() . $chunk->getBlockLightArray() . pack("C*", ...$chunk->getHeightMapArray()) . pack("N*", ...$chunk->getBiomeColorArray()) . $extraData->getBuffer() . $this->tiles; $this->setResult($ordered, false); }
private static function writeEnchantList(EnchantmentList $list, BinaryStream $stream) { $stream->putByte($list->getSize()); for ($i = 0; $i < $list->getSize(); ++$i) { $entry = $list->getSlot($i); $stream->putInt($entry->getCost()); $stream->putByte(count($entry->getEnchantments())); foreach ($entry->getEnchantments() as $enchantment) { $stream->putInt($enchantment->getId()); $stream->putInt($enchantment->getLevel()); } $stream->putString($entry->getRandomName()); } return CraftingDataPacket::ENTRY_ENCHANT_LIST; }
private static function writeFurnaceRecipe(FurnaceRecipe $recipe, BinaryStream $stream) { if ($recipe->getInput()->getDamage() !== null) { //Data recipe $stream->putVarInt($recipe->getInput()->getId()); $stream->putVarInt($recipe->getInput()->getDamage()); $stream->putSlot($recipe->getResult()); return CraftingDataPacket::ENTRY_FURNACE_DATA; } else { $stream->putVarInt($recipe->getInput()->getId()); $stream->putSlot($recipe->getResult()); return CraftingDataPacket::ENTRY_FURNACE; } }
public function toBinary() { $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->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); $extraData = new BinaryStream(); $extraData->putInt(\count($this->getBlockExtraDataArray())); foreach ($this->getBlockExtraDataArray() as $key => $value) { $extraData->putInt($key); $extraData->putShort($value); } $nbt->ExtraData = new ByteArray("ExtraData", $extraData->getBuffer()); $writer = new NBT(NBT::BIG_ENDIAN); $nbt->setName("Level"); $writer->setData(new Compound("", ["Level" => $nbt])); return $writer->writeCompressed(ZLIB_ENCODING_DEFLATE, RegionLoader::$COMPRESSION_LEVEL); }
public function requestChunkTask($x, $z) { $chunk = $this->getChunk($x, $z, \false); if (!$chunk instanceof Chunk) { throw new ChunkException("Invalid Chunk sent"); } $tiles = ""; $nbt = new NBT(NBT::LITTLE_ENDIAN); foreach ($chunk->getTiles() as $tile) { if ($tile instanceof Spawnable) { $nbt->setData($tile->getSpawnCompound()); $tiles .= $nbt->write(); } } $heightmap = \pack("C*", ...$chunk->getHeightMapArray()); $biomeColors = \pack("N*", ...$chunk->getBiomeColorArray()); $extraData = new BinaryStream(); $extraData->putLInt(\count($chunk->getBlockExtraDataArray())); foreach ($chunk->getBlockExtraDataArray() as $key => $value) { $extraData->putLInt($key); $extraData->putLShort($value); } $ordered = $chunk->getBlockIdArray() . $chunk->getBlockDataArray() . $chunk->getBlockSkyLightArray() . $chunk->getBlockLightArray() . $heightmap . $biomeColors . $extraData->getBuffer() . $tiles; $this->getLevel()->chunkRequestCallback($x, $z, $ordered); return \null; }
public function requestChunkTask($x, $z) { $chunk = $this->getChunk($x, $z, false); if (!$chunk instanceof Chunk) { throw new ChunkException("Invalid Chunk sent"); } $tiles = ""; $nbt = new NBT(NBT::LITTLE_ENDIAN); foreach ($chunk->getTiles() as $tile) { if ($tile instanceof Spawnable) { $nbt->setData($tile->getSpawnCompound()); $tiles .= $nbt->write(); } } $extraData = new BinaryStream(); $extraData->putLInt(count($chunk->getBlockExtraDataArray())); foreach ($chunk->getBlockExtraDataArray() as $key => $value) { $extraData->putLInt($key); $extraData->putLShort($value); } $ordered = $chunk->getBlockIdArray() . $chunk->getBlockDataArray() . $chunk->getBlockSkyLightArray() . $chunk->getBlockLightArray() . pack("C*", ...$chunk->getHeightMapArray()) . pack("N*", ...$chunk->getBiomeColorArray()) . $extraData->getBuffer() . $tiles; $pk = new FullChunkDataPacket(); $pk->chunkX = $x; $pk->chunkZ = $z; $pk->order = FullChunkDataPacket::ORDER_COLUMNS; $pk->data = $ordered; $pk->encode(); $str = ""; $str .= Binary::writeInt(strlen($pk->buffer)) . $pk->buffer; $this->getLevel()->chunkRequestCallback($x, $z, zlib_encode($str, ZLIB_ENCODING_DEFLATE, 7)); return null; }
public function toBinary($saveExtra = \false) { $chunkIndex = LevelDB::chunkIndex($this->getX(), $this->getZ()); $provider = $this->getProvider(); if ($saveExtra and $provider instanceof LevelDB) { $nbt = new NBT(NBT::LITTLE_ENDIAN); $entities = []; foreach ($this->getEntities() as $entity) { if (!$entity instanceof Player and !$entity->closed) { $entity->saveNBT(); $entities[] = $entity->namedtag; } } if (\count($entities) > 0) { $nbt->setData($entities); $provider->getDatabase()->put($chunkIndex . LevelDB::ENTRY_ENTITIES, $nbt->write()); } else { $provider->getDatabase()->delete($chunkIndex . LevelDB::ENTRY_ENTITIES); } $tiles = []; foreach ($this->getTiles() as $tile) { if (!$tile->closed) { $tile->saveNBT(); $tiles[] = $tile->namedtag; } } if (\count($tiles) > 0) { $nbt->setData($tiles); $provider->getDatabase()->put($chunkIndex . LevelDB::ENTRY_TILES, $nbt->write()); } else { $provider->getDatabase()->delete($chunkIndex . LevelDB::ENTRY_TILES); } if (\count($this->getBlockExtraDataArray()) > 0) { $extraData = new BinaryStream(); $extraData->putInt(\count($this->getBlockExtraDataArray())); foreach ($this->getBlockExtraDataArray() as $key => $value) { $extraData->putInt($key); $extraData->putShort($value); } $provider->getDatabase()->put($chunkIndex . LevelDB::ENTRY_EXTRA_DATA, $extraData->getBuffer()); } else { $provider->getDatabase()->delete($chunkIndex . LevelDB::ENTRY_EXTRA_DATA); } } $heightmap = \pack("C*", ...$this->getHeightMapArray()); $biomeColors = \pack("N*", ...$this->getBiomeColorArray()); return $chunkIndex . $this->getBlockIdArray() . $this->getBlockDataArray() . $this->getBlockSkyLightArray() . $this->getBlockLightArray() . $heightmap . $biomeColors . \chr(($this->isLightPopulated() ? 0x4 : 0) | ($this->isPopulated() ? 0x2 : 0) | ($this->isGenerated() ? 0x1 : 0)); }
public function processBatch(BatchPacket $packet, Player $p) { try { if (strlen($packet->payload) === 0) { //prevent zlib_decode errors for incorrectly-decoded packets throw new \InvalidArgumentException("BatchPacket payload is empty or packet decode error"); } $str = zlib_decode($packet->payload, 1024 * 1024 * 64); //Max 64MB $len = strlen($str); if ($len === 0) { throw new \InvalidStateException("Decoded BatchPacket payload is empty"); } $stream = new BinaryStream($str); while ($stream->offset < $len) { $buf = $stream->getString(); if (($pk = $this->getPacket(ord($buf[0]))) !== null) { if ($pk::NETWORK_ID === Info::BATCH_PACKET) { throw new \InvalidStateException("Invalid BatchPacket inside BatchPacket"); } $pk->setBuffer($buf, 1); $pk->decode(); assert($pk->feof(), "Still " . strlen(substr($pk->buffer, $pk->offset)) . " bytes unread in " . get_class($pk)); $p->handleDataPacket($pk); } } } catch (\Throwable $e) { if (\pocketmine\DEBUG > 1) { $logger = $this->server->getLogger(); $logger->debug("BatchPacket " . " 0x" . bin2hex($packet->payload)); $logger->logException($e); } } }
/** * Reads a metadata coded string * * @param $value * @param bool $types * * @return array */ public static function readMetadata($value, $types = false) { $stream = new BinaryStream(); $stream->setBuffer($value); $count = $stream->getUnsignedVarInt(); $data = []; for ($i = 0; $i < $count; ++$i) { $key = $stream->getUnsignedVarInt(); $type = $stream->getUnsignedVarInt(); $value = null; switch ($type) { case Entity::DATA_TYPE_BYTE: $value = $stream->getByte(); break; case Entity::DATA_TYPE_SHORT: $value = $stream->getLShort(true); //signed break; case Entity::DATA_TYPE_INT: $value = $stream->getVarInt(); break; case Entity::DATA_TYPE_FLOAT: $value = $stream->getLFloat(); break; case Entity::DATA_TYPE_STRING: $value = $stream->getString(); break; case Entity::DATA_TYPE_SLOT: //TODO: use objects directly $item = $stream->getSlot(); $value[0] = $item->getId(); $value[1] = $item->getCount(); $value[2] = $item->getDamage(); break; case Entity::DATA_TYPE_POS: $value = [0, 0, 0]; $stream->getBlockCoords($value[0], $value[1], $value[2]); break; case Entity::DATA_TYPE_LONG: $value = $stream->getVarInt(); //TODO: varint64 proper support break; case Entity::DATA_TYPE_VECTOR3F: $value = [0.0, 0.0, 0.0]; $stream->getVector3f($value[0], $value[1], $value[2]); break; default: $value = []; } if ($types === true) { $data[$key] = [$value, $type]; } else { $data[$key] = $value; } } return $data; }
public function toBinary() { $nbt = clone $this->getNBT(); $nbt->xPos = new IntTag("xPos", $this->x); $nbt->zPos = new IntTag("zPos", $this->z); if ($this->isGenerated()) { $nbt->Blocks = new ByteArrayTag("Blocks", $this->getBlockIdArray()); $nbt->Data = new ByteArrayTag("Data", $this->getBlockDataArray()); $nbt->SkyLight = new ByteArrayTag("SkyLight", $this->getBlockSkyLightArray()); $nbt->BlockLight = new ByteArrayTag("BlockLight", $this->getBlockLightArray()); $nbt->BiomeColors = new IntArrayTag("BiomeColors", $this->getBiomeColorArray()); $nbt->HeightMap = new IntArrayTag("HeightMap", $this->getHeightMapArray()); } $entities = []; foreach ($this->getEntities() as $entity) { if (!$entity instanceof Player and !$entity->closed) { $entity->saveNBT(); $entities[] = $entity->namedtag; } } $nbt->Entities = new ListTag("Entities", $entities); $nbt->Entities->setTagType(NBT::TAG_Compound); $tiles = []; foreach ($this->getTiles() as $tile) { $tile->saveNBT(); $tiles[] = $tile->namedtag; } $nbt->TileEntities = new ListTag("TileEntities", $tiles); $nbt->TileEntities->setTagType(NBT::TAG_Compound); $extraData = new BinaryStream(); $extraData->putInt(count($this->getBlockExtraDataArray())); foreach ($this->getBlockExtraDataArray() as $key => $value) { $extraData->putInt($key); $extraData->putShort($value); } $nbt->ExtraData = new ByteArrayTag("ExtraData", $extraData->getBuffer()); $writer = new NBT(NBT::BIG_ENDIAN); $nbt->setName("Level"); $writer->setData(new CompoundTag("", ["Level" => $nbt])); return $writer->writeCompressed(ZLIB_ENCODING_DEFLATE, RegionLoader::$COMPRESSION_LEVEL); }
public function __construct($level, Compound $nbt = null) { if ($nbt === null) { $this->provider = $level; $this->nbt = new Compound("Level", []); return; } $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->BiomeColors) or !$this->nbt->BiomeColors instanceof IntArray) { $this->nbt->BiomeColors = new IntArray("BiomeColors", array_fill(0, 256, 0)); } if (!isset($this->nbt->HeightMap) or !$this->nbt->HeightMap instanceof IntArray) { $this->nbt->HeightMap = new IntArray("HeightMap", array_fill(0, 256, 0)); } $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); } } $extraData = []; if (!isset($this->nbt->ExtraData) or !$this->nbt->ExtraData instanceof ByteArray) { $this->nbt->ExtraData = new ByteArray("ExtraData", Binary::writeInt(0)); } else { $stream = new BinaryStream($this->nbt->ExtraData->getValue()); $count = $stream->getInt(); for ($i = 0; $i < $count; ++$i) { $key = $stream->getInt(); $extraData[$key] = $stream->getShort(false); } } parent::__construct($level, (int) $this->nbt["xPos"], (int) $this->nbt["zPos"], $sections, $this->nbt->BiomeColors->getValue(), $this->nbt->HeightMap->getValue(), $this->nbt->Entities->getValue(), $this->nbt->TileEntities->getValue(), $extraData); if (isset($this->nbt->Biomes)) { // $this->checkOldBiomes($this->nbt->Biomes->getValue()); unset($this->nbt->Biomes); } unset($this->nbt->Sections, $this->nbt->ExtraData); }
/** * @param Compound $nbt * @return NBT */ protected function prepareChunkBinaryWriter(Compound $nbt) { $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); $extraData = new BinaryStream(); $extraData->putInt(count($this->getBlockExtraDataArray())); foreach ($this->getBlockExtraDataArray() as $key => $value) { $extraData->putInt($key); $extraData->putShort($value); } $nbt->ExtraData = new ByteArray("ExtraData", $extraData->getBuffer()); $writer = new NBT(NBT::BIG_ENDIAN); $nbt->setName("Level"); $writer->setData(new Compound("", ["Level" => $nbt])); return $writer; }