use pocketmine\network\BadPacketException; use pocketmine\network\mcpe\handler\PacketHandler; use pocketmine\network\mcpe\protocol\types\DimensionIds; use pocketmine\network\mcpe\protocol\types\MapTrackedObject; use pocketmine\utils\Color; use function assert; use function count; #ifndef COMPILE use pocketmine\utils\Binary; #endif class ClientboundMapItemDataPacket extends DataPacket implements ClientboundPacket{ public const NETWORK_ID = ProtocolInfo::CLIENTBOUND_MAP_ITEM_DATA_PACKET; public const BITFLAG_TEXTURE_UPDATE = 0x02; public const BITFLAG_DECORATION_UPDATE = 0x04; /** @var int */ public $mapId; /** @var int */ public $type; /** @var int */ public $dimensionId = DimensionIds::OVERWORLD; /** @var bool */ public $isLocked = false; /** @var int[] */ public $eids = []; /** @var int */ public $scale; /** @var MapTrackedObject[] */ public $trackedEntities = []; /** @var array */ public $decorations = []; /** @var int */ public $width; /** @var int */ public $height; /** @var int */ public $xOffset = 0; /** @var int */ public $yOffset = 0; /** @var Color[][] */ public $colors = []; protected function decodePayload() : void{ $this->mapId = $this->getEntityUniqueId(); $this->type = $this->getUnsignedVarInt(); $this->dimensionId = $this->getByte(); $this->isLocked = $this->getBool(); if(($this->type & 0x08) !== 0){ $count = $this->getUnsignedVarInt(); for($i = 0; $i < $count; ++$i){ $this->eids[] = $this->getEntityUniqueId(); } } if(($this->type & (0x08 | self::BITFLAG_DECORATION_UPDATE | self::BITFLAG_TEXTURE_UPDATE)) !== 0){ //Decoration bitflag or colour bitflag $this->scale = $this->getByte(); } if(($this->type & self::BITFLAG_DECORATION_UPDATE) !== 0){ for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){ $object = new MapTrackedObject(); $object->type = $this->getLInt(); if($object->type === MapTrackedObject::TYPE_BLOCK){ $this->getBlockPosition($object->x, $object->y, $object->z); }elseif($object->type === MapTrackedObject::TYPE_ENTITY){ $object->entityUniqueId = $this->getEntityUniqueId(); }else{ throw new BadPacketException("Unknown map object type $object->type"); } $this->trackedEntities[] = $object; } for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){ $this->decorations[$i]["img"] = $this->getByte(); $this->decorations[$i]["rot"] = $this->getByte(); $this->decorations[$i]["xOffset"] = $this->getByte(); $this->decorations[$i]["yOffset"] = $this->getByte(); $this->decorations[$i]["label"] = $this->getString(); $this->decorations[$i]["color"] = Color::fromRGBA(Binary::flipIntEndianness($this->getUnsignedVarInt())); } } if(($this->type & self::BITFLAG_TEXTURE_UPDATE) !== 0){ $this->width = $this->getVarInt(); $this->height = $this->getVarInt(); $this->xOffset = $this->getVarInt(); $this->yOffset = $this->getVarInt(); $count = $this->getUnsignedVarInt(); if($count !== $this->width * $this->height){ throw new BadPacketException("Expected colour count of " . ($this->height * $this->width) . " (height $this->height * width $this->width), got $count"); } for($y = 0; $y < $this->height; ++$y){ for($x = 0; $x < $this->width; ++$x){ $this->colors[$y][$x] = Color::fromRGBA(Binary::flipIntEndianness($this->getUnsignedVarInt())); } } } } protected function encodePayload() : void{ $this->putEntityUniqueId($this->mapId); $type = 0; if(($eidsCount = count($this->eids)) > 0){ $type |= 0x08; } if(($decorationCount = count($this->decorations)) > 0){ $type |= self::BITFLAG_DECORATION_UPDATE; } if(count($this->colors) > 0){ $type |= self::BITFLAG_TEXTURE_UPDATE; } $this->putUnsignedVarInt($type); $this->putByte($this->dimensionId); $this->putBool($this->isLocked); if(($type & 0x08) !== 0){ //TODO: find out what these are for $this->putUnsignedVarInt($eidsCount); foreach($this->eids as $eid){ $this->putEntityUniqueId($eid); } } if(($type & (0x08 | self::BITFLAG_TEXTURE_UPDATE | self::BITFLAG_DECORATION_UPDATE)) !== 0){ $this->putByte($this->scale); } if(($type & self::BITFLAG_DECORATION_UPDATE) !== 0){ $this->putUnsignedVarInt(count($this->trackedEntities)); foreach($this->trackedEntities as $object){ $this->putLInt($object->type); if($object->type === MapTrackedObject::TYPE_BLOCK){ $this->putBlockPosition($object->x, $object->y, $object->z); }elseif($object->type === MapTrackedObject::TYPE_ENTITY){ $this->putEntityUniqueId($object->entityUniqueId); }else{ throw new \InvalidArgumentException("Unknown map object type $object->type"); } } $this->putUnsignedVarInt($decorationCount); foreach($this->decorations as $decoration){ $this->putByte($decoration["img"]); $this->putByte($decoration["rot"]); $this->putByte($decoration["xOffset"]); $this->putByte($decoration["yOffset"]); $this->putString($decoration["label"]); assert($decoration["color"] instanceof Color); $this->putUnsignedVarInt(Binary::flipIntEndianness($decoration["color"]->toRGBA())); } } if(($type & self::BITFLAG_TEXTURE_UPDATE) !== 0){ $this->putVarInt($this->width); $this->putVarInt($this->height); $this->putVarInt($this->xOffset); $this->putVarInt($this->yOffset); $this->putUnsignedVarInt($this->width * $this->height); //list count, but we handle it as a 2D array... thanks for the confusion mojang for($y = 0; $y < $this->height; ++$y){ for($x = 0; $x < $this->width; ++$x){ //if mojang had any sense this would just be a regular LE int $this->putUnsignedVarInt(Binary::flipIntEndianness($this->colors[$y][$x]->toRGBA())); } } } } public function handle(PacketHandler $handler) : bool{ return $handler->handleClientboundMapItemData($this); } }