use pocketmine\entity\Entity; use pocketmine\item\Item; use pocketmine\network\mcpe\NetworkSession; use pocketmine\utils\BinaryStream; use pocketmine\utils\Utils; abstract class DataPacket extends BinaryStream{ const NETWORK_ID = 0; public $isEncoded = false; public function pid(){ return $this::NETWORK_ID; } public function getName() : string{ return (new \ReflectionClass($this))->getShortName(); } public function canBeBatched() : bool{ return true; } public function canBeSentBeforeLogin() : bool{ return false; } abstract public function encode(); abstract public function decode(); /** * Performs handling for this packet. Usually you'll want an appropriately named method in the NetworkSession for this. * * This method returns a bool to indicate whether the packet was handled or not. If the packet was unhandled, a debug message will be logged with a hexdump of the packet. * Typically this method returns the return value of the handler in the supplied NetworkSession. See other packets for examples how to implement this. * * @param NetworkSession $session * * @return bool true if the packet was handled successfully, false if not. */ abstract public function handle(NetworkSession $session) : bool; public function reset(){ $this->buffer = chr($this::NETWORK_ID); $this->offset = 0; } public function clean(){ $this->buffer = null; $this->isEncoded = false; $this->offset = 0; return $this; } public function __debugInfo(){ $data = []; foreach($this as $k => $v){ if($k === "buffer"){ $data[$k] = bin2hex($v); }elseif(is_string($v) or (is_object($v) and method_exists($v, "__toString"))){ $data[$k] = Utils::printable((string) $v); }else{ $data[$k] = $v; } } return $data; } /** * Decodes entity metadata from the stream. * * @param bool $types Whether to include metadata types along with values in the returned array * * @return array */ public function getEntityMetadata(bool $types = true) : array{ $count = $this->getUnsignedVarInt(); $data = []; for($i = 0; $i < $count; ++$i){ $key = $this->getUnsignedVarInt(); $type = $this->getUnsignedVarInt(); $value = null; switch($type){ case Entity::DATA_TYPE_BYTE: $value = $this->getByte(); break; case Entity::DATA_TYPE_SHORT: $value = $this->getLShort(true); //signed break; case Entity::DATA_TYPE_INT: $value = $this->getVarInt(); break; case Entity::DATA_TYPE_FLOAT: $value = $this->getLFloat(); break; case Entity::DATA_TYPE_STRING: $value = $this->getString(); break; case Entity::DATA_TYPE_SLOT: //TODO: use objects directly $value = []; $item = $this->getSlot(); $value[0] = $item->getId(); $value[1] = $item->getCount(); $value[2] = $item->getDamage(); break; case Entity::DATA_TYPE_POS: $value = [0, 0, 0]; $this->getSignedBlockPosition(...$value); break; case Entity::DATA_TYPE_LONG: $value = $this->getVarLong(); break; case Entity::DATA_TYPE_VECTOR3F: $value = [0.0, 0.0, 0.0]; $this->getVector3f(...$value); break; default: $value = []; } if($types === true){ $data[$key] = [$value, $type]; }else{ $data[$key] = $value; } } return $data; } /** * Writes entity metadata to the packet buffer. * * @param array $metadata */ public function putEntityMetadata(array $metadata){ $this->putUnsignedVarInt(count($metadata)); foreach($metadata as $key => $d){ $this->putUnsignedVarInt($key); //data key $this->putUnsignedVarInt($d[0]); //data type switch($d[0]){ case Entity::DATA_TYPE_BYTE: $this->putByte($d[1]); break; case Entity::DATA_TYPE_SHORT: $this->putLShort($d[1]); //SIGNED short! break; case Entity::DATA_TYPE_INT: $this->putVarInt($d[1]); break; case Entity::DATA_TYPE_FLOAT: $this->putLFloat($d[1]); break; case Entity::DATA_TYPE_STRING: $this->putString($d[1]); break; case Entity::DATA_TYPE_SLOT: //TODO: change this implementation (use objects) $this->putSlot(Item::get($d[1][0], $d[1][2], $d[1][1])); //ID, damage, count break; case Entity::DATA_TYPE_POS: //TODO: change this implementation (use objects) $this->putSignedBlockPosition(...$d[1]); break; case Entity::DATA_TYPE_LONG: $this->putVarLong($d[1]); break; case Entity::DATA_TYPE_VECTOR3F: //TODO: change this implementation (use objects) $this->putVector3f(...$d[1]); //x, y, z } } } /** * Reads and returns an EntityUniqueID * @return int|string */ public function getEntityUniqueId(){ return $this->getVarLong(); } /** * Writes an EntityUniqueID * @param int|string $eid */ public function putEntityUniqueId($eid){ $this->putVarLong($eid); } /** * Reads and returns an EntityRuntimeID * @return int|string */ public function getEntityRuntimeId(){ return $this->getUnsignedVarLong(); } /** * Writes an EntityUniqueID * @param int|string $eid */ public function putEntityRuntimeId($eid){ $this->putUnsignedVarLong($eid); } /** * Reads an block position with unsigned Y coordinate. * @param int $x * @param int $y 0-255 * @param int $z */ public function getBlockPosition(&$x, &$y, &$z){ $x = $this->getVarInt(); $y = $this->getUnsignedVarInt(); $z = $this->getVarInt(); } /** * Writes a block position with unsigned Y coordinate. * @param int &$x * @param int &$y * @param int &$z */ public function putBlockPosition($x, $y, $z){ $this->putVarInt($x); $this->putUnsignedVarInt($y); $this->putVarInt($z); } /** * Reads a block position with a signed Y coordinate. * @param int &$x * @param int &$y * @param int &$z */ public function getSignedBlockPosition(&$x, &$y, &$z){ $x = $this->getVarInt(); $y = $this->getVarInt(); $z = $this->getVarInt(); } /** * Writes a block position with a signed Y coordinate. * @param int $x * @param int $y * @param int $z */ public function putSignedBlockPosition($x, $y, $z){ $this->putVarInt($x); $this->putVarInt($y); $this->putVarInt($z); } /** * Reads a floating-point vector3 rounded to 4dp. * @param float $x * @param float $y * @param float $z */ public function getVector3f(&$x, &$y, &$z){ $x = $this->getLFloat(4); $y = $this->getLFloat(4); $z = $this->getLFloat(4); } /** * Writes a floating-point vector3 * @param float $x * @param float $y * @param float $z */ public function putVector3f($x, $y, $z){ $this->putLFloat($x); $this->putLFloat($y); $this->putLFloat($z); } }