diff --git a/src/pocketmine/entity/Entity.php b/src/pocketmine/entity/Entity.php index 8eeb82c08..80e699274 100644 --- a/src/pocketmine/entity/Entity.php +++ b/src/pocketmine/entity/Entity.php @@ -64,7 +64,7 @@ use pocketmine\nbt\tag\ListTag; use pocketmine\nbt\tag\StringTag; use pocketmine\network\mcpe\protocol\AddEntityPacket; use pocketmine\network\mcpe\protocol\EntityEventPacket; -use pocketmine\network\mcpe\protocol\MoveEntityPacket; +use pocketmine\network\mcpe\protocol\MoveEntityAbsolutePacket; use pocketmine\network\mcpe\protocol\RemoveEntityPacket; use pocketmine\network\mcpe\protocol\SetEntityDataPacket; use pocketmine\network\mcpe\protocol\SetEntityMotionPacket; @@ -1134,13 +1134,20 @@ abstract class Entity extends Location implements Metadatable, EntityIds{ protected function broadcastMovement(bool $teleport = false) : void{ if($this->chunk !== null){ - $pk = new MoveEntityPacket(); + $pk = new MoveEntityAbsolutePacket(); $pk->entityRuntimeId = $this->id; $pk->position = $this->getOffsetPosition($this); - $pk->yaw = $this->yaw; - $pk->pitch = $this->pitch; - $pk->headYaw = $this->yaw; //TODO - $pk->teleported = $teleport; + + //this looks very odd but is correct as of 1.5.0.7 + //for arrows this is actually x/y/z rotation + //for mobs x and z are used for pitch and yaw, and y is used for headyaw + $pk->xRot = $this->pitch; + $pk->yRot = $this->yaw; //TODO: head yaw + $pk->zRot = $this->yaw; + + if($teleport){ + $pk->flags |= MoveEntityAbsolutePacket::FLAG_TELEPORT; + } $this->level->addChunkPacket($this->chunk->getX(), $this->chunk->getZ(), $pk); } diff --git a/src/pocketmine/entity/Human.php b/src/pocketmine/entity/Human.php index 1a84e6c1e..da5a7220b 100644 --- a/src/pocketmine/entity/Human.php +++ b/src/pocketmine/entity/Human.php @@ -50,7 +50,9 @@ use pocketmine\network\mcpe\protocol\AddPlayerPacket; use pocketmine\network\mcpe\protocol\EntityEventPacket; use pocketmine\network\mcpe\protocol\LevelEventPacket; use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; +use pocketmine\network\mcpe\protocol\PlayerListPacket; use pocketmine\network\mcpe\protocol\PlayerSkinPacket; +use pocketmine\network\mcpe\protocol\types\PlayerListEntry; use pocketmine\Player; use pocketmine\utils\UUID; @@ -835,6 +837,14 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{ throw new \InvalidStateException((new \ReflectionClass($this))->getShortName() . " must have a valid skin set"); } + if(!($this instanceof Player)){ + /* we don't use Server->updatePlayerListData() because that uses batches, which could cause race conditions in async compression mode */ + $pk = new PlayerListPacket(); + $pk->type = PlayerListPacket::TYPE_ADD; + $pk->entries = [PlayerListEntry::createAdditionEntry($this->uuid, $this->id, $this->getName(), $this->getName(), 0, $this->skin)]; + $player->dataPacket($pk); + } + $pk = new AddPlayerPacket(); $pk->uuid = $this->getUniqueId(); $pk->username = $this->getName(); @@ -853,7 +863,10 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{ $this->armorInventory->sendContents($player); if(!($this instanceof Player)){ - $this->sendSkin([$player]); + $pk = new PlayerListPacket(); + $pk->type = PlayerListPacket::TYPE_REMOVE; + $pk->entries = [PlayerListEntry::createRemovalEntry($this->uuid)]; + $player->dataPacket($pk); } } diff --git a/src/pocketmine/level/particle/FloatingTextParticle.php b/src/pocketmine/level/particle/FloatingTextParticle.php index f9e460388..f393d22eb 100644 --- a/src/pocketmine/level/particle/FloatingTextParticle.php +++ b/src/pocketmine/level/particle/FloatingTextParticle.php @@ -29,8 +29,9 @@ use pocketmine\item\Item; use pocketmine\item\ItemFactory; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\AddPlayerPacket; -use pocketmine\network\mcpe\protocol\PlayerSkinPacket; +use pocketmine\network\mcpe\protocol\PlayerListPacket; use pocketmine\network\mcpe\protocol\RemoveEntityPacket; +use pocketmine\network\mcpe\protocol\types\PlayerListEntry; use pocketmine\utils\UUID; class FloatingTextParticle extends Particle{ @@ -89,9 +90,17 @@ class FloatingTextParticle extends Particle{ } if(!$this->invisible){ + $uuid = UUID::fromRandom(); + $name = $this->title . ($this->text !== "" ? "\n" . $this->text : ""); + + $add = new PlayerListPacket(); + $add->type = PlayerListPacket::TYPE_ADD; + $add->entries = [PlayerListEntry::createAdditionEntry($uuid, $this->entityId, $name, $name, 0, new Skin("Standard_Custom", str_repeat("\x00", 8192)))]; + $p[] = $add; + $pk = new AddPlayerPacket(); - $pk->uuid = $uuid = UUID::fromRandom(); - $pk->username = $this->title . ($this->text !== "" ? "\n" . $this->text : ""); + $pk->uuid = $uuid; + $pk->username = $name; $pk->entityRuntimeId = $this->entityId; $pk->position = $this->asVector3(); //TODO: check offset $pk->item = ItemFactory::get(Item::AIR, 0, 0); @@ -106,10 +115,10 @@ class FloatingTextParticle extends Particle{ $p[] = $pk; - $skinPk = new PlayerSkinPacket(); - $skinPk->uuid = $uuid; - $skinPk->skin = new Skin("Standard_Custom", str_repeat("\x00", 8192)); - $p[] = $skinPk; + $remove = new PlayerListPacket(); + $remove->type = PlayerListPacket::TYPE_REMOVE; + $remove->entries = [PlayerListEntry::createRemovalEntry($uuid)]; + $p[] = $remove; } return $p; diff --git a/src/pocketmine/network/mcpe/NetworkSession.php b/src/pocketmine/network/mcpe/NetworkSession.php index f90954b1e..67265e947 100644 --- a/src/pocketmine/network/mcpe/NetworkSession.php +++ b/src/pocketmine/network/mcpe/NetworkSession.php @@ -76,7 +76,8 @@ use pocketmine\network\mcpe\protocol\MobEffectPacket; use pocketmine\network\mcpe\protocol\MobEquipmentPacket; use pocketmine\network\mcpe\protocol\ModalFormRequestPacket; use pocketmine\network\mcpe\protocol\ModalFormResponsePacket; -use pocketmine\network\mcpe\protocol\MoveEntityPacket; +use pocketmine\network\mcpe\protocol\MoveEntityAbsolutePacket; +use pocketmine\network\mcpe\protocol\MoveEntityDeltaPacket; use pocketmine\network\mcpe\protocol\MovePlayerPacket; use pocketmine\network\mcpe\protocol\NpcRequestPacket; use pocketmine\network\mcpe\protocol\PhotoTransferPacket; @@ -111,6 +112,7 @@ use pocketmine\network\mcpe\protocol\SetEntityLinkPacket; use pocketmine\network\mcpe\protocol\SetEntityMotionPacket; use pocketmine\network\mcpe\protocol\SetHealthPacket; use pocketmine\network\mcpe\protocol\SetLastHurtByPacket; +use pocketmine\network\mcpe\protocol\SetLocalPlayerAsInitializedPacket; use pocketmine\network\mcpe\protocol\SetPlayerGameTypePacket; use pocketmine\network\mcpe\protocol\SetScorePacket; use pocketmine\network\mcpe\protocol\SetSpawnPositionPacket; @@ -207,7 +209,7 @@ abstract class NetworkSession{ return false; } - public function handleMoveEntity(MoveEntityPacket $packet) : bool{ + public function handleMoveEntityAbsolute(MoveEntityAbsolutePacket $packet) : bool{ return false; } @@ -578,4 +580,12 @@ abstract class NetworkSession{ public function handleUpdateBlockSynced(UpdateBlockSyncedPacket $packet) : bool{ return false; } + + public function handleMoveEntityDelta(MoveEntityDeltaPacket $packet) : bool{ + return false; + } + + public function handleSetLocalPlayerAsInitialized(SetLocalPlayerAsInitializedPacket $packet) : bool{ + return false; + } } diff --git a/src/pocketmine/network/mcpe/protocol/AddEntityPacket.php b/src/pocketmine/network/mcpe/protocol/AddEntityPacket.php index fb93f307c..88ab492ad 100644 --- a/src/pocketmine/network/mcpe/protocol/AddEntityPacket.php +++ b/src/pocketmine/network/mcpe/protocol/AddEntityPacket.php @@ -44,9 +44,11 @@ class AddEntityPacket extends DataPacket{ /** @var Vector3|null */ public $motion; /** @var float */ + public $pitch = 0.0; + /** @var float */ public $yaw = 0.0; /** @var float */ - public $pitch = 0.0; + public $headYaw = 0.0; /** @var Attribute[] */ public $attributes = []; @@ -63,6 +65,7 @@ class AddEntityPacket extends DataPacket{ $this->motion = $this->getVector3(); $this->pitch = $this->getLFloat(); $this->yaw = $this->getLFloat(); + $this->headYaw = $this->getLFloat(); $attrCount = $this->getUnsignedVarInt(); for($i = 0; $i < $attrCount; ++$i){ @@ -97,6 +100,7 @@ class AddEntityPacket extends DataPacket{ $this->putVector3Nullable($this->motion); $this->putLFloat($this->pitch); $this->putLFloat($this->yaw); + $this->putLFloat($this->headYaw); $this->putUnsignedVarInt(count($this->attributes)); foreach($this->attributes as $attribute){ diff --git a/src/pocketmine/network/mcpe/protocol/ClientboundMapItemDataPacket.php b/src/pocketmine/network/mcpe/protocol/ClientboundMapItemDataPacket.php index df6b1dcbc..2df98c735 100644 --- a/src/pocketmine/network/mcpe/protocol/ClientboundMapItemDataPacket.php +++ b/src/pocketmine/network/mcpe/protocol/ClientboundMapItemDataPacket.php @@ -29,6 +29,7 @@ namespace pocketmine\network\mcpe\protocol; use pocketmine\network\mcpe\NetworkSession; use pocketmine\network\mcpe\protocol\types\DimensionIds; +use pocketmine\network\mcpe\protocol\types\MapTrackedObject; use pocketmine\utils\Color; class ClientboundMapItemDataPacket extends DataPacket{ @@ -49,8 +50,8 @@ class ClientboundMapItemDataPacket extends DataPacket{ /** @var int */ public $scale; - /** @var int[] */ - public $decorationEntityUniqueIds = []; + /** @var MapTrackedObject[] */ + public $trackedEntities = []; /** @var array */ public $decorations = []; @@ -83,7 +84,16 @@ class ClientboundMapItemDataPacket extends DataPacket{ if(($this->type & self::BITFLAG_DECORATION_UPDATE) !== 0){ for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){ - $this->decorationEntityUniqueIds[] = $this->getEntityUniqueId(); + $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 \UnexpectedValueException("Unknown map object type"); + } + $this->trackedEntities[] = $object; } for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){ @@ -143,9 +153,16 @@ class ClientboundMapItemDataPacket extends DataPacket{ } if(($type & self::BITFLAG_DECORATION_UPDATE) !== 0){ - $this->putUnsignedVarInt(count($this->decorationEntityUniqueIds)); - foreach($this->decorationEntityUniqueIds as $id){ - $this->putEntityUniqueId($id); + $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 \UnexpectedValueException("Unknown map object type"); + } } $this->putUnsignedVarInt($decorationCount); diff --git a/src/pocketmine/network/mcpe/protocol/MoveEntityPacket.php b/src/pocketmine/network/mcpe/protocol/MoveEntityAbsolutePacket.php similarity index 66% rename from src/pocketmine/network/mcpe/protocol/MoveEntityPacket.php rename to src/pocketmine/network/mcpe/protocol/MoveEntityAbsolutePacket.php index a17e4de3e..33a0ccbd0 100644 --- a/src/pocketmine/network/mcpe/protocol/MoveEntityPacket.php +++ b/src/pocketmine/network/mcpe/protocol/MoveEntityAbsolutePacket.php @@ -29,45 +29,44 @@ namespace pocketmine\network\mcpe\protocol; use pocketmine\math\Vector3; use pocketmine\network\mcpe\NetworkSession; -class MoveEntityPacket extends DataPacket{ - public const NETWORK_ID = ProtocolInfo::MOVE_ENTITY_PACKET; +class MoveEntityAbsolutePacket extends DataPacket{ + public const NETWORK_ID = ProtocolInfo::MOVE_ENTITY_ABSOLUTE_PACKET; + + public const FLAG_GROUND = 0x01; + public const FLAG_TELEPORT = 0x02; /** @var int */ public $entityRuntimeId; + /** @var int */ + public $flags = 0; /** @var Vector3 */ public $position; /** @var float */ - public $yaw; + public $xRot; /** @var float */ - public $headYaw; + public $yRot; /** @var float */ - public $pitch; - /** @var bool */ - public $onGround = false; - /** @var bool */ - public $teleported = false; + public $zRot; protected function decodePayload(){ $this->entityRuntimeId = $this->getEntityRuntimeId(); + $this->flags = $this->getByte(); $this->position = $this->getVector3(); - $this->pitch = $this->getByteRotation(); - $this->headYaw = $this->getByteRotation(); - $this->yaw = $this->getByteRotation(); - $this->onGround = $this->getBool(); - $this->teleported = $this->getBool(); + $this->xRot = $this->getByteRotation(); + $this->yRot = $this->getByteRotation(); + $this->zRot = $this->getByteRotation(); } protected function encodePayload(){ $this->putEntityRuntimeId($this->entityRuntimeId); + $this->putByte($this->flags); $this->putVector3($this->position); - $this->putByteRotation($this->pitch); - $this->putByteRotation($this->headYaw); - $this->putByteRotation($this->yaw); - $this->putBool($this->onGround); - $this->putBool($this->teleported); + $this->putByteRotation($this->xRot); + $this->putByteRotation($this->yRot); + $this->putByteRotation($this->zRot); } public function handle(NetworkSession $session) : bool{ - return $session->handleMoveEntity($this); + return $session->handleMoveEntityAbsolute($this); } } diff --git a/src/pocketmine/network/mcpe/protocol/MoveEntityDeltaPacket.php b/src/pocketmine/network/mcpe/protocol/MoveEntityDeltaPacket.php new file mode 100644 index 000000000..53fc8f77c --- /dev/null +++ b/src/pocketmine/network/mcpe/protocol/MoveEntityDeltaPacket.php @@ -0,0 +1,104 @@ + + +use pocketmine\network\mcpe\NetworkSession; + +class MoveEntityDeltaPacket extends DataPacket{ + public const NETWORK_ID = ProtocolInfo::MOVE_ENTITY_DELTA_PACKET; + + public const FLAG_HAS_X = 0x01; + public const FLAG_HAS_Y = 0x02; + public const FLAG_HAS_Z = 0x04; + public const FLAG_HAS_ROT_X = 0x08; + public const FLAG_HAS_ROT_Y = 0x10; + public const FLAG_HAS_ROT_Z = 0x20; + + /** @var int */ + public $flags; + /** @var int */ + public $xDiff = 0; + /** @var int */ + public $yDiff = 0; + /** @var int */ + public $zDiff = 0; + /** @var float */ + public $xRot = 0.0; + /** @var float */ + public $yRot = 0.0; + /** @var float */ + public $zRot = 0.0; + + private function maybeReadCoord(int $flag) : int{ + if($this->flags & $flag){ + return $this->getVarInt(); + } + return 0; + } + + private function maybeReadRotation(int $flag) : float{ + if($this->flags & $flag){ + return $this->getByteRotation(); + } + return 0.0; + } + + protected function decodePayload(){ + $this->flags = $this->getByte(); + $this->xDiff = $this->maybeReadCoord(self::FLAG_HAS_X); + $this->yDiff = $this->maybeReadCoord(self::FLAG_HAS_Y); + $this->zDiff = $this->maybeReadCoord(self::FLAG_HAS_Z); + $this->xRot = $this->maybeReadRotation(self::FLAG_HAS_ROT_X); + $this->yRot = $this->maybeReadRotation(self::FLAG_HAS_ROT_Y); + $this->zRot = $this->maybeReadRotation(self::FLAG_HAS_ROT_Z); + } + + private function maybeWriteCoord(int $flag, int $val) : void{ + if($this->flags & $flag){ + $this->putVarInt($val); + } + } + + private function maybeWriteRotation(int $flag, float $val) : void{ + if($this->flags & $flag){ + $this->putByteRotation($val); + } + } + + protected function encodePayload(){ + $this->putByte($this->flags); + $this->maybeWriteCoord(self::FLAG_HAS_X, $this->xDiff); + $this->maybeWriteCoord(self::FLAG_HAS_Y, $this->yDiff); + $this->maybeWriteCoord(self::FLAG_HAS_Z, $this->zDiff); + $this->maybeWriteRotation(self::FLAG_HAS_ROT_X, $this->xRot); + $this->maybeWriteRotation(self::FLAG_HAS_ROT_Y, $this->yRot); + $this->maybeWriteRotation(self::FLAG_HAS_ROT_Z, $this->zRot); + } + + public function handle(NetworkSession $session) : bool{ + return $session->handleMoveEntityDelta($this); + } +} diff --git a/src/pocketmine/network/mcpe/protocol/PacketPool.php b/src/pocketmine/network/mcpe/protocol/PacketPool.php index af1f8b184..ac550f720 100644 --- a/src/pocketmine/network/mcpe/protocol/PacketPool.php +++ b/src/pocketmine/network/mcpe/protocol/PacketPool.php @@ -48,7 +48,7 @@ class PacketPool{ static::registerPacket(new AddItemEntityPacket()); static::registerPacket(new AddHangingEntityPacket()); static::registerPacket(new TakeItemEntityPacket()); - static::registerPacket(new MoveEntityPacket()); + static::registerPacket(new MoveEntityAbsolutePacket()); static::registerPacket(new MovePlayerPacket()); static::registerPacket(new RiderJumpPacket()); static::registerPacket(new UpdateBlockPacket()); @@ -141,6 +141,8 @@ class PacketPool{ static::registerPacket(new SetScorePacket()); static::registerPacket(new LabTablePacket()); static::registerPacket(new UpdateBlockSyncedPacket()); + static::registerPacket(new MoveEntityDeltaPacket()); + static::registerPacket(new SetLocalPlayerAsInitializedPacket()); static::registerPacket(new BatchPacket()); } diff --git a/src/pocketmine/network/mcpe/protocol/ProtocolInfo.php b/src/pocketmine/network/mcpe/protocol/ProtocolInfo.php index 275cb1b28..6aa8957b2 100644 --- a/src/pocketmine/network/mcpe/protocol/ProtocolInfo.php +++ b/src/pocketmine/network/mcpe/protocol/ProtocolInfo.php @@ -39,15 +39,15 @@ interface ProtocolInfo{ /** * Actual Minecraft: PE protocol version */ - public const CURRENT_PROTOCOL = 261; + public const CURRENT_PROTOCOL = 274; /** * Current Minecraft PE version reported by the server. This is usually the earliest currently supported version. */ - public const MINECRAFT_VERSION = 'v1.4.0'; + public const MINECRAFT_VERSION = 'v1.5.0'; /** * Version number sent to clients in ping responses. */ - public const MINECRAFT_VERSION_NETWORK = '1.4.0'; + public const MINECRAFT_VERSION_NETWORK = '1.5.0'; public const LOGIN_PACKET = 0x01; public const PLAY_STATUS_PACKET = 0x02; @@ -66,7 +66,7 @@ interface ProtocolInfo{ public const ADD_ITEM_ENTITY_PACKET = 0x0f; public const ADD_HANGING_ENTITY_PACKET = 0x10; public const TAKE_ITEM_ENTITY_PACKET = 0x11; - public const MOVE_ENTITY_PACKET = 0x12; + public const MOVE_ENTITY_ABSOLUTE_PACKET = 0x12; public const MOVE_PLAYER_PACKET = 0x13; public const RIDER_JUMP_PACKET = 0x14; public const UPDATE_BLOCK_PACKET = 0x15; @@ -159,5 +159,7 @@ interface ProtocolInfo{ public const SET_SCORE_PACKET = 0x6c; public const LAB_TABLE_PACKET = 0x6d; public const UPDATE_BLOCK_SYNCED_PACKET = 0x6e; + public const MOVE_ENTITY_DELTA_PACKET = 0x6f; + public const SET_LOCAL_PLAYER_AS_INITIALIZED_PACKET = 0x70; } diff --git a/src/pocketmine/network/mcpe/protocol/SetLocalPlayerAsInitializedPacket.php b/src/pocketmine/network/mcpe/protocol/SetLocalPlayerAsInitializedPacket.php new file mode 100644 index 000000000..12918f114 --- /dev/null +++ b/src/pocketmine/network/mcpe/protocol/SetLocalPlayerAsInitializedPacket.php @@ -0,0 +1,47 @@ + + +use pocketmine\network\mcpe\NetworkSession; + +class SetLocalPlayerAsInitializedPacket extends DataPacket{ + public const NETWORK_ID = ProtocolInfo::SET_LOCAL_PLAYER_AS_INITIALIZED_PACKET; + + /** @var int */ + public $entityRuntimeId; + + protected function decodePayload(){ + $this->entityRuntimeId = $this->getEntityRuntimeId(); + } + + protected function encodePayload(){ + $this->putEntityRuntimeId($this->entityRuntimeId); + } + + public function handle(NetworkSession $session) : bool{ + return $session->handleSetLocalPlayerAsInitialized($this); + } +} diff --git a/src/pocketmine/network/mcpe/protocol/types/MapTrackedObject.php b/src/pocketmine/network/mcpe/protocol/types/MapTrackedObject.php new file mode 100644 index 000000000..7c9f10954 --- /dev/null +++ b/src/pocketmine/network/mcpe/protocol/types/MapTrackedObject.php @@ -0,0 +1,43 @@ +