diff --git a/src/pocketmine/network/mcpe/NetworkBinaryStream.php b/src/pocketmine/network/mcpe/NetworkBinaryStream.php new file mode 100644 index 000000000..a212f0a09 --- /dev/null +++ b/src/pocketmine/network/mcpe/NetworkBinaryStream.php @@ -0,0 +1,547 @@ + + +use pocketmine\entity\Attribute; +use pocketmine\entity\Entity; +use pocketmine\item\Item; +use pocketmine\item\ItemFactory; +use pocketmine\math\Vector3; +use pocketmine\network\mcpe\protocol\types\CommandOriginData; +use pocketmine\network\mcpe\protocol\types\EntityLink; +use pocketmine\utils\BinaryStream; +use pocketmine\utils\UUID; + +class NetworkBinaryStream extends BinaryStream{ + + public function getString() : string{ + return $this->get($this->getUnsignedVarInt()); + } + + public function putString(string $v){ + $this->putUnsignedVarInt(strlen($v)); + $this->put($v); + } + + public function getUUID() : UUID{ + //This is actually two little-endian longs: UUID Most followed by UUID Least + $part1 = $this->getLInt(); + $part0 = $this->getLInt(); + $part3 = $this->getLInt(); + $part2 = $this->getLInt(); + + return new UUID($part0, $part1, $part2, $part3); + } + + public function putUUID(UUID $uuid){ + $this->putLInt($uuid->getPart(1)); + $this->putLInt($uuid->getPart(0)); + $this->putLInt($uuid->getPart(3)); + $this->putLInt($uuid->getPart(2)); + } + + public function getSlot() : Item{ + $id = $this->getVarInt(); + if($id <= 0){ + return ItemFactory::get(0, 0, 0); + } + + $auxValue = $this->getVarInt(); + $data = $auxValue >> 8; + if($data === 0x7fff){ + $data = -1; + } + $cnt = $auxValue & 0xff; + + $nbtLen = $this->getLShort(); + $nbt = ""; + + if($nbtLen > 0){ + $nbt = $this->get($nbtLen); + } + + //TODO + $canPlaceOn = $this->getVarInt(); + if($canPlaceOn > 0){ + for($i = 0; $i < $canPlaceOn; ++$i){ + $this->getString(); + } + } + + //TODO + $canDestroy = $this->getVarInt(); + if($canDestroy > 0){ + for($i = 0; $i < $canDestroy; ++$i){ + $this->getString(); + } + } + + return ItemFactory::get($id, $data, $cnt, $nbt); + } + + + public function putSlot(Item $item){ + if($item->getId() === 0){ + $this->putVarInt(0); + + return; + } + + $this->putVarInt($item->getId()); + $auxValue = (($item->getDamage() & 0x7fff) << 8) | $item->getCount(); + $this->putVarInt($auxValue); + + $nbt = $item->getCompoundTag(); + $this->putLShort(strlen($nbt)); + $this->put($nbt); + + $this->putVarInt(0); //CanPlaceOn entry count (TODO) + $this->putVarInt(0); //CanDestroy entry count (TODO) + } + + /** + * 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->getSignedLShort(); + 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] = [$type, $value]; + }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(ItemFactory::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 a list of Attributes from the stream. + * @return Attribute[] + * + * @throws \UnexpectedValueException if reading an attribute with an unrecognized name + */ + public function getAttributeList() : array{ + $list = []; + $count = $this->getUnsignedVarInt(); + + for($i = 0; $i < $count; ++$i){ + $min = $this->getLFloat(); + $max = $this->getLFloat(); + $current = $this->getLFloat(); + $default = $this->getLFloat(); + $name = $this->getString(); + + $attr = Attribute::getAttributeByName($name); + if($attr !== null){ + $attr->setMinValue($min); + $attr->setMaxValue($max); + $attr->setValue($current); + $attr->setDefaultValue($default); + + $list[] = $attr; + }else{ + throw new \UnexpectedValueException("Unknown attribute type \"$name\""); + } + } + + return $list; + } + + /** + * Writes a list of Attributes to the packet buffer using the standard format. + * + * @param Attribute[] ...$attributes + */ + public function putAttributeList(Attribute ...$attributes){ + $this->putUnsignedVarInt(count($attributes)); + foreach($attributes as $attribute){ + $this->putLFloat($attribute->getMinValue()); + $this->putLFloat($attribute->getMaxValue()); + $this->putLFloat($attribute->getValue()); + $this->putLFloat($attribute->getDefaultValue()); + $this->putString($attribute->getName()); + } + } + + /** + * Reads and returns an EntityUniqueID + * @return int + */ + public function getEntityUniqueId() : int{ + return $this->getVarLong(); + } + + /** + * Writes an EntityUniqueID + * + * @param int $eid + */ + public function putEntityUniqueId(int $eid){ + $this->putVarLong($eid); + } + + /** + * Reads and returns an EntityRuntimeID + * @return int + */ + public function getEntityRuntimeId() : int{ + return $this->getUnsignedVarLong(); + } + + /** + * Writes an EntityUniqueID + * + * @param int $eid + */ + public function putEntityRuntimeId(int $eid){ + $this->putUnsignedVarLong($eid); + } + + /** + * Reads an block position with unsigned Y coordinate. + * + * @param int &$x + * @param int &$y + * @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(int $x, int $y, int $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(int $x, int $y, int $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->getRoundedLFloat(4); + $y = $this->getRoundedLFloat(4); + $z = $this->getRoundedLFloat(4); + } + + /** + * Writes a floating-point vector3 + * + * @param float $x + * @param float $y + * @param float $z + */ + public function putVector3f(float $x, float $y, float $z){ + $this->putLFloat($x); + $this->putLFloat($y); + $this->putLFloat($z); + } + + /** + * Reads a floating-point Vector3 object + * TODO: get rid of primitive methods and replace with this + * + * @return Vector3 + */ + public function getVector3Obj() : Vector3{ + return new Vector3( + $this->getRoundedLFloat(4), + $this->getRoundedLFloat(4), + $this->getRoundedLFloat(4) + ); + } + + /** + * Writes a floating-point Vector3 object, or 3x zero if null is given. + * + * Note: ONLY use this where it is reasonable to allow not specifying the vector. + * For all other purposes, use {@link DataPacket#putVector3Obj} + * + * @param Vector3|null $vector + */ + public function putVector3ObjNullable(Vector3 $vector = null){ + if($vector){ + $this->putVector3Obj($vector); + }else{ + $this->putLFloat(0.0); + $this->putLFloat(0.0); + $this->putLFloat(0.0); + } + } + + /** + * Writes a floating-point Vector3 object + * TODO: get rid of primitive methods and replace with this + * + * @param Vector3 $vector + */ + public function putVector3Obj(Vector3 $vector){ + $this->putLFloat($vector->x); + $this->putLFloat($vector->y); + $this->putLFloat($vector->z); + } + + public function getByteRotation() : float{ + return (float) ($this->getByte() * (360 / 256)); + } + + public function putByteRotation(float $rotation){ + $this->putByte((int) ($rotation / (360 / 256))); + } + + /** + * Reads gamerules + * TODO: implement this properly + * + * @return array + */ + public function getGameRules() : array{ + $count = $this->getUnsignedVarInt(); + $rules = []; + for($i = 0; $i < $count; ++$i){ + $name = $this->getString(); + $type = $this->getUnsignedVarInt(); + $value = null; + switch($type){ + case 1: + $value = $this->getBool(); + break; + case 2: + $value = $this->getUnsignedVarInt(); + break; + case 3: + $value = $this->getLFloat(); + break; + } + + $rules[$name] = [$type, $value]; + } + + return $rules; + } + + /** + * Writes a gamerule array + * TODO: implement this properly + * + * @param array $rules + */ + public function putGameRules(array $rules){ + $this->putUnsignedVarInt(count($rules)); + foreach($rules as $name => $rule){ + $this->putString($name); + $this->putUnsignedVarInt($rule[0]); + switch($rule[0]){ + case 1: + $this->putBool($rule[1]); + break; + case 2: + $this->putUnsignedVarInt($rule[1]); + break; + case 3: + $this->putLFloat($rule[1]); + break; + } + } + } + + /** + * @return EntityLink + */ + protected function getEntityLink() : EntityLink{ + $link = new EntityLink(); + + $link->fromEntityUniqueId = $this->getEntityUniqueId(); + $link->toEntityUniqueId = $this->getEntityUniqueId(); + $link->type = $this->getByte(); + $link->bool1 = $this->getBool(); + + return $link; + } + + /** + * @param EntityLink $link + */ + protected function putEntityLink(EntityLink $link){ + $this->putEntityUniqueId($link->fromEntityUniqueId); + $this->putEntityUniqueId($link->toEntityUniqueId); + $this->putByte($link->type); + $this->putBool($link->bool1); + } + + protected function getCommandOriginData() : CommandOriginData{ + $result = new CommandOriginData(); + + $result->type = $this->getUnsignedVarInt(); + $result->uuid = $this->getUUID(); + $result->requestId = $this->getString(); + + if($result->type === CommandOriginData::ORIGIN_DEV_CONSOLE or $result->type === CommandOriginData::ORIGIN_TEST){ + $result->varlong1 = $this->getVarLong(); + } + + return $result; + } + + protected function putCommandOriginData(CommandOriginData $data) : void{ + $this->putUnsignedVarInt($data->type); + $this->putUUID($data->uuid); + $this->putString($data->requestId); + + if($data->type === CommandOriginData::ORIGIN_DEV_CONSOLE or $data->type === CommandOriginData::ORIGIN_TEST){ + $this->putVarLong($data->varlong1); + } + } +} diff --git a/src/pocketmine/network/mcpe/protocol/BatchPacket.php b/src/pocketmine/network/mcpe/protocol/BatchPacket.php index ba9116db7..84cde69fe 100644 --- a/src/pocketmine/network/mcpe/protocol/BatchPacket.php +++ b/src/pocketmine/network/mcpe/protocol/BatchPacket.php @@ -26,11 +26,11 @@ namespace pocketmine\network\mcpe\protocol; #include +use pocketmine\network\mcpe\NetworkBinaryStream; use pocketmine\network\mcpe\NetworkSession; #ifndef COMPILE use pocketmine\utils\Binary; #endif -use pocketmine\utils\BinaryStream; class BatchPacket extends DataPacket{ public const NETWORK_ID = 0xfe; @@ -88,7 +88,7 @@ class BatchPacket extends DataPacket{ * @return \Generator */ public function getPackets(){ - $stream = new BinaryStream($this->payload); + $stream = new NetworkBinaryStream($this->payload); while(!$stream->feof()){ yield $stream->getString(); } diff --git a/src/pocketmine/network/mcpe/protocol/CraftingDataPacket.php b/src/pocketmine/network/mcpe/protocol/CraftingDataPacket.php index 18f8334f0..78fa3f2f2 100644 --- a/src/pocketmine/network/mcpe/protocol/CraftingDataPacket.php +++ b/src/pocketmine/network/mcpe/protocol/CraftingDataPacket.php @@ -30,8 +30,8 @@ use pocketmine\inventory\FurnaceRecipe; use pocketmine\inventory\ShapedRecipe; use pocketmine\inventory\ShapelessRecipe; use pocketmine\item\Item; +use pocketmine\network\mcpe\NetworkBinaryStream; use pocketmine\network\mcpe\NetworkSession; -use pocketmine\utils\BinaryStream; class CraftingDataPacket extends DataPacket{ public const NETWORK_ID = ProtocolInfo::CRAFTING_DATA_PACKET; @@ -114,7 +114,7 @@ class CraftingDataPacket extends DataPacket{ $this->getBool(); //cleanRecipes } - private static function writeEntry($entry, BinaryStream $stream){ + private static function writeEntry($entry, NetworkBinaryStream $stream){ if($entry instanceof ShapelessRecipe){ return self::writeShapelessRecipe($entry, $stream); }elseif($entry instanceof ShapedRecipe){ @@ -127,7 +127,7 @@ class CraftingDataPacket extends DataPacket{ return -1; } - private static function writeShapelessRecipe(ShapelessRecipe $recipe, BinaryStream $stream){ + private static function writeShapelessRecipe(ShapelessRecipe $recipe, NetworkBinaryStream $stream){ $stream->putUnsignedVarInt($recipe->getIngredientCount()); foreach($recipe->getIngredientList() as $item){ $stream->putSlot($item); @@ -144,7 +144,7 @@ class CraftingDataPacket extends DataPacket{ return CraftingDataPacket::ENTRY_SHAPELESS; } - private static function writeShapedRecipe(ShapedRecipe $recipe, BinaryStream $stream){ + private static function writeShapedRecipe(ShapedRecipe $recipe, NetworkBinaryStream $stream){ $stream->putVarInt($recipe->getWidth()); $stream->putVarInt($recipe->getHeight()); @@ -165,7 +165,7 @@ class CraftingDataPacket extends DataPacket{ return CraftingDataPacket::ENTRY_SHAPED; } - private static function writeFurnaceRecipe(FurnaceRecipe $recipe, BinaryStream $stream){ + private static function writeFurnaceRecipe(FurnaceRecipe $recipe, NetworkBinaryStream $stream){ if(!$recipe->getInput()->hasAnyDamageValue()){ //Data recipe $stream->putVarInt($recipe->getInput()->getId()); $stream->putVarInt($recipe->getInput()->getDamage()); @@ -195,7 +195,7 @@ class CraftingDataPacket extends DataPacket{ protected function encodePayload(){ $this->putUnsignedVarInt(count($this->entries)); - $writer = new BinaryStream(); + $writer = new NetworkBinaryStream(); foreach($this->entries as $d){ $entryType = self::writeEntry($d, $writer); if($entryType >= 0){ diff --git a/src/pocketmine/network/mcpe/protocol/DataPacket.php b/src/pocketmine/network/mcpe/protocol/DataPacket.php index 0a57caf4c..28694c379 100644 --- a/src/pocketmine/network/mcpe/protocol/DataPacket.php +++ b/src/pocketmine/network/mcpe/protocol/DataPacket.php @@ -25,18 +25,12 @@ namespace pocketmine\network\mcpe\protocol; #include -use pocketmine\entity\Attribute; -use pocketmine\entity\Entity; -use pocketmine\item\ItemFactory; -use pocketmine\math\Vector3; +use pocketmine\network\mcpe\NetworkBinaryStream; use pocketmine\network\mcpe\NetworkSession; -use pocketmine\network\mcpe\protocol\types\CommandOriginData; -use pocketmine\network\mcpe\protocol\types\EntityLink; -use pocketmine\utils\BinaryStream; use pocketmine\utils\Utils; -abstract class DataPacket extends BinaryStream{ +abstract class DataPacket extends NetworkBinaryStream{ public const NETWORK_ID = 0; @@ -148,418 +142,4 @@ abstract class DataPacket extends BinaryStream{ 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->getSignedLShort(); - 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] = [$type, $value]; - }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(ItemFactory::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 a list of Attributes from the stream. - * @return Attribute[] - * - * @throws \UnexpectedValueException if reading an attribute with an unrecognized name - */ - public function getAttributeList() : array{ - $list = []; - $count = $this->getUnsignedVarInt(); - - for($i = 0; $i < $count; ++$i){ - $min = $this->getLFloat(); - $max = $this->getLFloat(); - $current = $this->getLFloat(); - $default = $this->getLFloat(); - $name = $this->getString(); - - $attr = Attribute::getAttributeByName($name); - if($attr !== null){ - $attr->setMinValue($min); - $attr->setMaxValue($max); - $attr->setValue($current); - $attr->setDefaultValue($default); - - $list[] = $attr; - }else{ - throw new \UnexpectedValueException("Unknown attribute type \"$name\""); - } - } - - return $list; - } - - /** - * Writes a list of Attributes to the packet buffer using the standard format. - * @param Attribute[] ...$attributes - */ - public function putAttributeList(Attribute ...$attributes){ - $this->putUnsignedVarInt(count($attributes)); - foreach($attributes as $attribute){ - $this->putLFloat($attribute->getMinValue()); - $this->putLFloat($attribute->getMaxValue()); - $this->putLFloat($attribute->getValue()); - $this->putLFloat($attribute->getDefaultValue()); - $this->putString($attribute->getName()); - } - } - - /** - * Reads and returns an EntityUniqueID - * @return int - */ - public function getEntityUniqueId() : int{ - return $this->getVarLong(); - } - - /** - * Writes an EntityUniqueID - * @param int $eid - */ - public function putEntityUniqueId(int $eid){ - $this->putVarLong($eid); - } - - /** - * Reads and returns an EntityRuntimeID - * @return int - */ - public function getEntityRuntimeId() : int{ - return $this->getUnsignedVarLong(); - } - - /** - * Writes an EntityUniqueID - * @param int $eid - */ - public function putEntityRuntimeId(int $eid){ - $this->putUnsignedVarLong($eid); - } - - /** - * Reads an block position with unsigned Y coordinate. - * @param int &$x - * @param int &$y - * @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(int $x, int $y, int $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(int $x, int $y, int $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->getRoundedLFloat(4); - $y = $this->getRoundedLFloat(4); - $z = $this->getRoundedLFloat(4); - } - - /** - * Writes a floating-point vector3 - * @param float $x - * @param float $y - * @param float $z - */ - public function putVector3f(float $x, float $y, float $z){ - $this->putLFloat($x); - $this->putLFloat($y); - $this->putLFloat($z); - } - - /** - * Reads a floating-point Vector3 object - * TODO: get rid of primitive methods and replace with this - * - * @return Vector3 - */ - public function getVector3Obj() : Vector3{ - return new Vector3( - $this->getRoundedLFloat(4), - $this->getRoundedLFloat(4), - $this->getRoundedLFloat(4) - ); - } - - /** - * Writes a floating-point Vector3 object, or 3x zero if null is given. - * - * Note: ONLY use this where it is reasonable to allow not specifying the vector. - * For all other purposes, use {@link DataPacket#putVector3Obj} - * - * @param Vector3|null $vector - */ - public function putVector3ObjNullable(Vector3 $vector = null){ - if($vector){ - $this->putVector3Obj($vector); - }else{ - $this->putLFloat(0.0); - $this->putLFloat(0.0); - $this->putLFloat(0.0); - } - } - - /** - * Writes a floating-point Vector3 object - * TODO: get rid of primitive methods and replace with this - * - * @param Vector3 $vector - */ - public function putVector3Obj(Vector3 $vector){ - $this->putLFloat($vector->x); - $this->putLFloat($vector->y); - $this->putLFloat($vector->z); - } - - public function getByteRotation() : float{ - return (float) ($this->getByte() * (360 / 256)); - } - - public function putByteRotation(float $rotation){ - $this->putByte((int) ($rotation / (360 / 256))); - } - - /** - * Reads gamerules - * TODO: implement this properly - * - * @return array - */ - public function getGameRules() : array{ - $count = $this->getUnsignedVarInt(); - $rules = []; - for($i = 0; $i < $count; ++$i){ - $name = $this->getString(); - $type = $this->getUnsignedVarInt(); - $value = null; - switch($type){ - case 1: - $value = $this->getBool(); - break; - case 2: - $value = $this->getUnsignedVarInt(); - break; - case 3: - $value = $this->getLFloat(); - break; - } - - $rules[$name] = [$type, $value]; - } - - return $rules; - } - - /** - * Writes a gamerule array - * TODO: implement this properly - * - * @param array $rules - */ - public function putGameRules(array $rules){ - $this->putUnsignedVarInt(count($rules)); - foreach($rules as $name => $rule){ - $this->putString($name); - $this->putUnsignedVarInt($rule[0]); - switch($rule[0]){ - case 1: - $this->putBool($rule[1]); - break; - case 2: - $this->putUnsignedVarInt($rule[1]); - break; - case 3: - $this->putLFloat($rule[1]); - break; - } - } - } - - /** - * @return EntityLink - */ - protected function getEntityLink() : EntityLink{ - $link = new EntityLink(); - - $link->fromEntityUniqueId = $this->getEntityUniqueId(); - $link->toEntityUniqueId = $this->getEntityUniqueId(); - $link->type = $this->getByte(); - $link->bool1 = $this->getBool(); - - return $link; - } - - /** - * @param EntityLink $link - */ - protected function putEntityLink(EntityLink $link){ - $this->putEntityUniqueId($link->fromEntityUniqueId); - $this->putEntityUniqueId($link->toEntityUniqueId); - $this->putByte($link->type); - $this->putBool($link->bool1); - } - - protected function getCommandOriginData() : CommandOriginData{ - $result = new CommandOriginData(); - - $result->type = $this->getUnsignedVarInt(); - $result->uuid = $this->getUUID(); - $result->requestId = $this->getString(); - - if($result->type === CommandOriginData::ORIGIN_DEV_CONSOLE or $result->type === CommandOriginData::ORIGIN_TEST){ - $result->varlong1 = $this->getVarLong(); - } - - return $result; - } - - protected function putCommandOriginData(CommandOriginData $data) : void{ - $this->putUnsignedVarInt($data->type); - $this->putUUID($data->uuid); - $this->putString($data->requestId); - - if($data->type === CommandOriginData::ORIGIN_DEV_CONSOLE or $data->type === CommandOriginData::ORIGIN_TEST){ - $this->putVarLong($data->varlong1); - } - } } diff --git a/src/pocketmine/utils/BinaryStream.php b/src/pocketmine/utils/BinaryStream.php index c1a6ab601..27c1d1637 100644 --- a/src/pocketmine/utils/BinaryStream.php +++ b/src/pocketmine/utils/BinaryStream.php @@ -25,9 +25,6 @@ namespace pocketmine\utils; #include -use pocketmine\item\Item; -use pocketmine\item\ItemFactory; - class BinaryStream{ /** @var int */ @@ -219,91 +216,6 @@ class BinaryStream{ $this->buffer .= Binary::writeLLong($v); } - - public function getString() : string{ - return $this->get($this->getUnsignedVarInt()); - } - - public function putString(string $v){ - $this->putUnsignedVarInt(strlen($v)); - $this->put($v); - } - - - public function getUUID() : UUID{ - //This is actually two little-endian longs: UUID Most followed by UUID Least - $part1 = $this->getLInt(); - $part0 = $this->getLInt(); - $part3 = $this->getLInt(); - $part2 = $this->getLInt(); - return new UUID($part0, $part1, $part2, $part3); - } - - public function putUUID(UUID $uuid){ - $this->putLInt($uuid->getPart(1)); - $this->putLInt($uuid->getPart(0)); - $this->putLInt($uuid->getPart(3)); - $this->putLInt($uuid->getPart(2)); - } - - public function getSlot() : Item{ - $id = $this->getVarInt(); - if($id <= 0){ - return ItemFactory::get(0, 0, 0); - } - - $auxValue = $this->getVarInt(); - $data = $auxValue >> 8; - if($data === 0x7fff){ - $data = -1; - } - $cnt = $auxValue & 0xff; - - $nbtLen = $this->getLShort(); - $nbt = ""; - - if($nbtLen > 0){ - $nbt = $this->get($nbtLen); - } - - //TODO - $canPlaceOn = $this->getVarInt(); - if($canPlaceOn > 0){ - for($i = 0; $i < $canPlaceOn; ++$i){ - $this->getString(); - } - } - - //TODO - $canDestroy = $this->getVarInt(); - if($canDestroy > 0){ - for($i = 0; $i < $canDestroy; ++$i){ - $this->getString(); - } - } - - return ItemFactory::get($id, $data, $cnt, $nbt); - } - - - public function putSlot(Item $item){ - if($item->getId() === 0){ - $this->putVarInt(0); - return; - } - - $this->putVarInt($item->getId()); - $auxValue = (($item->getDamage() & 0x7fff) << 8) | $item->getCount(); - $this->putVarInt($auxValue); - - $nbt = $item->getCompoundTag(); - $this->putLShort(strlen($nbt)); - $this->put($nbt); - - $this->putVarInt(0); //CanPlaceOn entry count (TODO) - $this->putVarInt(0); //CanDestroy entry count (TODO) - } - /** * Reads a 32-bit variable-length unsigned integer from the buffer and returns it. * @return int