From 8682ea35f7d8c6354db8dc0fb3ed81fae5a9a336 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 1 May 2020 13:57:26 +0100 Subject: [PATCH] Introduce some (not great) API for entity animations while this API is a bit yucky, it's a step forward for protocol isolation and offers the possibility of controlling animations by adding events. --- src/entity/Entity.php | 16 ++---- src/entity/Human.php | 4 +- src/entity/Living.php | 10 ++-- src/entity/Squid.php | 4 +- src/entity/animation/Animation.php | 36 ++++++++++++++ src/entity/animation/ArmSwingAnimation.php | 43 ++++++++++++++++ src/entity/animation/ArrowShakeAnimation.php | 46 +++++++++++++++++ .../animation/ConsumingItemAnimation.php | 49 +++++++++++++++++++ src/entity/animation/CriticalHitAnimation.php | 43 ++++++++++++++++ src/entity/animation/DeathAnimation.php | 43 ++++++++++++++++ src/entity/animation/HurtAnimation.php | 43 ++++++++++++++++ src/entity/animation/RespawnAnimation.php | 43 ++++++++++++++++ .../animation/SquidInkCloudAnimation.php | 43 ++++++++++++++++ src/entity/animation/TotemUseAnimation.php | 44 +++++++++++++++++ src/entity/projectile/Arrow.php | 4 +- .../mcpe/handler/InGamePacketHandler.php | 7 +-- src/player/Player.php | 41 +++++++--------- 17 files changed, 471 insertions(+), 48 deletions(-) create mode 100644 src/entity/animation/Animation.php create mode 100644 src/entity/animation/ArmSwingAnimation.php create mode 100644 src/entity/animation/ArrowShakeAnimation.php create mode 100644 src/entity/animation/ConsumingItemAnimation.php create mode 100644 src/entity/animation/CriticalHitAnimation.php create mode 100644 src/entity/animation/DeathAnimation.php create mode 100644 src/entity/animation/HurtAnimation.php create mode 100644 src/entity/animation/RespawnAnimation.php create mode 100644 src/entity/animation/SquidInkCloudAnimation.php create mode 100644 src/entity/animation/TotemUseAnimation.php diff --git a/src/entity/Entity.php b/src/entity/Entity.php index b75d99dcd..46e74f3b6 100644 --- a/src/entity/Entity.php +++ b/src/entity/Entity.php @@ -28,6 +28,7 @@ namespace pocketmine\entity; use pocketmine\block\Block; use pocketmine\block\Water; +use pocketmine\entity\animation\Animation; use pocketmine\event\entity\EntityDamageEvent; use pocketmine\event\entity\EntityDespawnEvent; use pocketmine\event\entity\EntityMotionEvent; @@ -43,9 +44,7 @@ use pocketmine\nbt\tag\DoubleTag; use pocketmine\nbt\tag\FloatTag; use pocketmine\nbt\tag\ListTag; use pocketmine\nbt\tag\StringTag; -use pocketmine\network\mcpe\protocol\ActorEventPacket; use pocketmine\network\mcpe\protocol\AddActorPacket; -use pocketmine\network\mcpe\protocol\AnimatePacket; use pocketmine\network\mcpe\protocol\MoveActorAbsolutePacket; use pocketmine\network\mcpe\protocol\SetActorMotionPacket; use pocketmine\network\mcpe\protocol\types\entity\Attribute as NetworkAttribute; @@ -1692,17 +1691,10 @@ abstract class Entity{ } /** - * @param Player[]|null $players + * @param Player[]|null $targets */ - public function broadcastEntityEvent(int $eventId, ?int $eventData = null, ?array $players = null) : void{ - $this->server->broadcastPackets($players ?? $this->getViewers(), [ActorEventPacket::create($this->id, $eventId, $eventData ?? 0)]); - } - - /** - * @param Player[]|null $players - */ - public function broadcastAnimation(?array $players, int $animationId) : void{ - $this->server->broadcastPackets($players ?? $this->getViewers(), [AnimatePacket::create($this->id, $animationId)]); + public function broadcastAnimation(Animation $animation, ?array $targets = null) : void{ + $this->server->broadcastPackets($targets ?? $this->getViewers(), $animation->encode()); } public function __destruct(){ diff --git a/src/entity/Human.php b/src/entity/Human.php index 3b99ba8da..2e647b84a 100644 --- a/src/entity/Human.php +++ b/src/entity/Human.php @@ -24,6 +24,7 @@ declare(strict_types=1); namespace pocketmine\entity; use pocketmine\block\inventory\EnderChestInventory; +use pocketmine\entity\animation\TotemUseAnimation; use pocketmine\entity\effect\EffectInstance; use pocketmine\entity\effect\VanillaEffects; use pocketmine\entity\projectile\ProjectileSource; @@ -43,7 +44,6 @@ use pocketmine\nbt\tag\ListTag; use pocketmine\nbt\tag\StringTag; use pocketmine\network\mcpe\convert\SkinAdapterSingleton; use pocketmine\network\mcpe\convert\TypeConverter; -use pocketmine\network\mcpe\protocol\ActorEventPacket; use pocketmine\network\mcpe\protocol\AddPlayerPacket; use pocketmine\network\mcpe\protocol\MovePlayerPacket; use pocketmine\network\mcpe\protocol\PlayerListPacket; @@ -303,7 +303,7 @@ class Human extends Living implements ProjectileSource, InventoryHolder{ $this->effectManager->add(new EffectInstance(VanillaEffects::FIRE_RESISTANCE(), 40 * 20, 1)); $this->effectManager->add(new EffectInstance(VanillaEffects::ABSORPTION(), 5 * 20, 1)); - $this->broadcastEntityEvent(ActorEventPacket::CONSUME_TOTEM); + $this->broadcastAnimation(new TotemUseAnimation($this)); $this->getWorld()->addSound($this->location->add(0, $this->eyeHeight, 0), new TotemUseSound()); $hand = $this->inventory->getItemInHand(); diff --git a/src/entity/Living.php b/src/entity/Living.php index d41567ce5..daa2a69c4 100644 --- a/src/entity/Living.php +++ b/src/entity/Living.php @@ -25,6 +25,9 @@ namespace pocketmine\entity; use pocketmine\block\Block; use pocketmine\block\BlockLegacyIds; +use pocketmine\entity\animation\DeathAnimation; +use pocketmine\entity\animation\HurtAnimation; +use pocketmine\entity\animation\RespawnAnimation; use pocketmine\entity\effect\EffectInstance; use pocketmine\entity\effect\EffectManager; use pocketmine\entity\effect\VanillaEffects; @@ -46,7 +49,6 @@ use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\FloatTag; use pocketmine\nbt\tag\ListTag; use pocketmine\nbt\tag\ShortTag; -use pocketmine\network\mcpe\protocol\ActorEventPacket; use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataFlags; use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataProperties; use pocketmine\player\Player; @@ -164,7 +166,7 @@ abstract class Living extends Entity{ parent::setHealth($amount); $this->attributeMap->get(Attribute::HEALTH)->setValue(ceil($this->getHealth()), true); if($this->isAlive() and !$wasAlive){ - $this->broadcastEntityEvent(ActorEventPacket::RESPAWN); + $this->broadcastAnimation(new RespawnAnimation($this)); } } @@ -451,7 +453,7 @@ abstract class Living extends Entity{ } protected function doHitAnimation() : void{ - $this->broadcastEntityEvent(ActorEventPacket::HURT_ANIMATION); + $this->broadcastAnimation(new HurtAnimation($this)); } public function knockBack(float $x, float $z, float $base = 0.4) : void{ @@ -504,7 +506,7 @@ abstract class Living extends Entity{ } protected function startDeathAnimation() : void{ - $this->broadcastEntityEvent(ActorEventPacket::DEATH_ANIMATION); + $this->broadcastAnimation(new DeathAnimation($this)); } protected function endDeathAnimation() : void{ diff --git a/src/entity/Squid.php b/src/entity/Squid.php index a5ec3a407..29fe795e7 100644 --- a/src/entity/Squid.php +++ b/src/entity/Squid.php @@ -23,12 +23,12 @@ declare(strict_types=1); namespace pocketmine\entity; +use pocketmine\entity\animation\SquidInkCloudAnimation; use pocketmine\event\entity\EntityDamageByEntityEvent; use pocketmine\event\entity\EntityDamageEvent; use pocketmine\item\VanillaItems; use pocketmine\math\Vector3; use pocketmine\nbt\tag\CompoundTag; -use pocketmine\network\mcpe\protocol\ActorEventPacket; use pocketmine\network\mcpe\protocol\types\entity\EntityLegacyIds; use function atan2; use function mt_rand; @@ -71,7 +71,7 @@ class Squid extends WaterAnimal{ $this->swimDirection = $this->location->subtract($e->location)->normalize(); } - $this->broadcastEntityEvent(ActorEventPacket::SQUID_INK_CLOUD); + $this->broadcastAnimation(new SquidInkCloudAnimation($this)); } } diff --git a/src/entity/animation/Animation.php b/src/entity/animation/Animation.php new file mode 100644 index 000000000..44dfa827b --- /dev/null +++ b/src/entity/animation/Animation.php @@ -0,0 +1,36 @@ +entity = $entity; + } + + public function encode() : array{ + return [ + ActorEventPacket::create($this->entity->getId(), ActorEventPacket::ARM_SWING, 0) + ]; + } +} diff --git a/src/entity/animation/ArrowShakeAnimation.php b/src/entity/animation/ArrowShakeAnimation.php new file mode 100644 index 000000000..925b93d3a --- /dev/null +++ b/src/entity/animation/ArrowShakeAnimation.php @@ -0,0 +1,46 @@ +arrow = $arrow; + $this->durationInTicks = $durationInTicks; + } + + public function encode() : array{ + return [ + ActorEventPacket::create($this->arrow->getId(), ActorEventPacket::ARROW_SHAKE, $this->durationInTicks) + ]; + } +} diff --git a/src/entity/animation/ConsumingItemAnimation.php b/src/entity/animation/ConsumingItemAnimation.php new file mode 100644 index 000000000..767d22caf --- /dev/null +++ b/src/entity/animation/ConsumingItemAnimation.php @@ -0,0 +1,49 @@ +human = $human; + $this->item = $item; + } + + public function encode() : array{ + return [ + //TODO: need to check the data values + ActorEventPacket::create($this->human->getId(), ActorEventPacket::EATING_ITEM, ($this->item->getId() << 16) | $this->item->getMeta()) + ]; + } +} diff --git a/src/entity/animation/CriticalHitAnimation.php b/src/entity/animation/CriticalHitAnimation.php new file mode 100644 index 000000000..f3a588b79 --- /dev/null +++ b/src/entity/animation/CriticalHitAnimation.php @@ -0,0 +1,43 @@ +entity = $entity; + } + + public function encode() : array{ + return [ + AnimatePacket::create($this->entity->getId(), AnimatePacket::ACTION_CRITICAL_HIT) + ]; + } +} diff --git a/src/entity/animation/DeathAnimation.php b/src/entity/animation/DeathAnimation.php new file mode 100644 index 000000000..35dab4597 --- /dev/null +++ b/src/entity/animation/DeathAnimation.php @@ -0,0 +1,43 @@ +entity = $entity; + } + + public function encode() : array{ + return [ + ActorEventPacket::create($this->entity->getId(), ActorEventPacket::DEATH_ANIMATION, 0) + ]; + } +} diff --git a/src/entity/animation/HurtAnimation.php b/src/entity/animation/HurtAnimation.php new file mode 100644 index 000000000..3ba5ebb8c --- /dev/null +++ b/src/entity/animation/HurtAnimation.php @@ -0,0 +1,43 @@ +entity = $entity; + } + + public function encode() : array{ + return [ + ActorEventPacket::create($this->entity->getId(), ActorEventPacket::HURT_ANIMATION, 0) + ]; + } +} diff --git a/src/entity/animation/RespawnAnimation.php b/src/entity/animation/RespawnAnimation.php new file mode 100644 index 000000000..defb26cf7 --- /dev/null +++ b/src/entity/animation/RespawnAnimation.php @@ -0,0 +1,43 @@ +entity = $entity; + } + + public function encode() : array{ + return [ + ActorEventPacket::create($this->entity->getId(), ActorEventPacket::RESPAWN, 0) + ]; + } +} diff --git a/src/entity/animation/SquidInkCloudAnimation.php b/src/entity/animation/SquidInkCloudAnimation.php new file mode 100644 index 000000000..fa3a9fd6b --- /dev/null +++ b/src/entity/animation/SquidInkCloudAnimation.php @@ -0,0 +1,43 @@ +squid = $squid; + } + + public function encode() : array{ + return [ + ActorEventPacket::create($this->squid->getId(), ActorEventPacket::SQUID_INK_CLOUD, 0) + ]; + } +} diff --git a/src/entity/animation/TotemUseAnimation.php b/src/entity/animation/TotemUseAnimation.php new file mode 100644 index 000000000..11eb68e46 --- /dev/null +++ b/src/entity/animation/TotemUseAnimation.php @@ -0,0 +1,44 @@ +human = $human; + } + + public function encode() : array{ + return [ + ActorEventPacket::create($this->human->getId(), ActorEventPacket::CONSUME_TOTEM, 0) + ]; + } +} diff --git a/src/entity/projectile/Arrow.php b/src/entity/projectile/Arrow.php index 86d3acfa9..cbf1e5ba7 100644 --- a/src/entity/projectile/Arrow.php +++ b/src/entity/projectile/Arrow.php @@ -24,13 +24,13 @@ declare(strict_types=1); namespace pocketmine\entity\projectile; use pocketmine\block\Block; +use pocketmine\entity\animation\ArrowShakeAnimation; use pocketmine\entity\Entity; use pocketmine\event\entity\ProjectileHitEvent; use pocketmine\event\inventory\InventoryPickupArrowEvent; use pocketmine\item\VanillaItems; use pocketmine\math\RayTraceResult; use pocketmine\nbt\tag\CompoundTag; -use pocketmine\network\mcpe\protocol\ActorEventPacket; use pocketmine\network\mcpe\protocol\types\entity\EntityLegacyIds; use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataFlags; use pocketmine\player\Player; @@ -140,7 +140,7 @@ class Arrow extends Projectile{ protected function onHitBlock(Block $blockHit, RayTraceResult $hitResult) : void{ parent::onHitBlock($blockHit, $hitResult); - $this->broadcastEntityEvent(ActorEventPacket::ARROW_SHAKE, 7); //7 ticks + $this->broadcastAnimation(new ArrowShakeAnimation($this, 7)); } protected function onHitEntity(Entity $entityHit, RayTraceResult $hitResult) : void{ diff --git a/src/network/mcpe/handler/InGamePacketHandler.php b/src/network/mcpe/handler/InGamePacketHandler.php index 0a4aa3722..f121d2bd2 100644 --- a/src/network/mcpe/handler/InGamePacketHandler.php +++ b/src/network/mcpe/handler/InGamePacketHandler.php @@ -26,6 +26,7 @@ namespace pocketmine\network\mcpe\handler; use pocketmine\block\ItemFrame; use pocketmine\block\Sign; use pocketmine\block\utils\SignText; +use pocketmine\entity\animation\ConsumingItemAnimation; use pocketmine\event\player\PlayerEditBookEvent; use pocketmine\inventory\transaction\action\InventoryAction; use pocketmine\inventory\transaction\CraftingTransaction; @@ -158,11 +159,11 @@ class InGamePacketHandler extends PacketHandler{ switch($packet->event){ case ActorEventPacket::EATING_ITEM: //TODO: ignore this and handle it server-side - if($packet->data === 0){ + $item = $this->player->getInventory()->getItemInHand(); + if($item->isNull()){ return false; } - - $this->player->broadcastEntityEvent(ActorEventPacket::EATING_ITEM, $packet->data); + $this->player->broadcastAnimation(new ConsumingItemAnimation($this->player, $this->player->getInventory()->getItemInHand())); break; default: return false; diff --git a/src/player/Player.php b/src/player/Player.php index f682514ba..2cce880e8 100644 --- a/src/player/Player.php +++ b/src/player/Player.php @@ -29,10 +29,14 @@ use pocketmine\block\UnknownBlock; use pocketmine\block\VanillaBlocks; use pocketmine\command\CommandSender; use pocketmine\crafting\CraftingGrid; +use pocketmine\entity\animation\Animation; +use pocketmine\entity\animation\ArmSwingAnimation; +use pocketmine\entity\animation\CriticalHitAnimation; use pocketmine\entity\effect\VanillaEffects; use pocketmine\entity\Entity; use pocketmine\entity\EntityFactory; use pocketmine\entity\Human; +use pocketmine\entity\Living; use pocketmine\entity\object\ItemEntity; use pocketmine\entity\projectile\Arrow; use pocketmine\entity\Skin; @@ -80,7 +84,6 @@ use pocketmine\nbt\tag\DoubleTag; use pocketmine\nbt\tag\IntTag; use pocketmine\nbt\tag\ListTag; use pocketmine\network\mcpe\NetworkSession; -use pocketmine\network\mcpe\protocol\ActorEventPacket; use pocketmine\network\mcpe\protocol\AnimatePacket; use pocketmine\network\mcpe\protocol\LevelEventPacket; use pocketmine\network\mcpe\protocol\MovePlayerPacket; @@ -995,7 +998,7 @@ class Player extends Human implements CommandSender, ChunkLoader, ChunkListener, $this->getWorld()->setSleepTicks(0); - $this->broadcastAnimation([$this], AnimatePacket::ACTION_STOP_SLEEP); + $this->networkSession->sendDataPacket(AnimatePacket::create($this->getId(), AnimatePacket::ACTION_STOP_SLEEP)); } } @@ -1559,7 +1562,7 @@ class Player extends Human implements CommandSender, ChunkLoader, ChunkListener, if($ev->isCancelled()){ return false; } - $this->broadcastEntityEvent(ActorEventPacket::ARM_SWING, null, $this->getViewers()); + $this->broadcastAnimation(new ArmSwingAnimation($this), $this->getViewers()); if($target->onAttack($this->inventory->getItemInHand(), $face, $this)){ return true; } @@ -1585,7 +1588,7 @@ class Player extends Human implements CommandSender, ChunkLoader, ChunkListener, $block = $this->getWorld()->getBlock($pos); $this->getWorld()->addParticle($pos, new BlockPunchParticle($block, $face)); $this->getWorld()->addSound($pos, new BlockPunchSound($block)); - $this->broadcastEntityEvent(ActorEventPacket::ARM_SWING, null, $this->getViewers()); + $this->broadcastAnimation(new ArmSwingAnimation($this), $this->getViewers()); //TODO: destroy-progress level event } @@ -1603,7 +1606,7 @@ class Player extends Human implements CommandSender, ChunkLoader, ChunkListener, $this->doCloseInventory(); if($this->canInteract($pos->add(0.5, 0.5, 0.5), $this->isCreative() ? 13 : 7) and !$this->isSpectator()){ - $this->broadcastEntityEvent(ActorEventPacket::ARM_SWING, null, $this->getViewers()); + $this->broadcastAnimation(new ArmSwingAnimation($this), $this->getViewers()); $item = $this->inventory->getItemInHand(); $oldItem = clone $item; if($this->getWorld()->useBreakOn($pos, $item, $this, true)){ @@ -1627,7 +1630,7 @@ class Player extends Human implements CommandSender, ChunkLoader, ChunkListener, $this->setUsingItem(false); if($this->canInteract($pos->add(0.5, 0.5, 0.5), 13) and !$this->isSpectator()){ - $this->broadcastEntityEvent(ActorEventPacket::ARM_SWING, null, $this->getViewers()); + $this->broadcastAnimation(new ArmSwingAnimation($this), $this->getViewers()); $item = $this->inventory->getItemInHand(); //this is a copy of the real item $oldItem = clone $item; if($this->getWorld()->useItemOn($pos, $item, $face, $clickOffset, $this, true)){ @@ -1686,10 +1689,10 @@ class Player extends Human implements CommandSender, ChunkLoader, ChunkListener, if($ev->isCancelled()){ return false; } - $this->broadcastEntityEvent(ActorEventPacket::ARM_SWING, null, $this->getViewers()); + $this->broadcastAnimation(new ArmSwingAnimation($this), $this->getViewers()); - if($ev->getModifier(EntityDamageEvent::MODIFIER_CRITICAL) > 0){ - $entity->broadcastAnimation(null, AnimatePacket::ACTION_CRITICAL_HIT); + if($ev->getModifier(EntityDamageEvent::MODIFIER_CRITICAL) > 0 and $entity instanceof Living){ + $entity->broadcastAnimation(new CriticalHitAnimation($entity)); } foreach($meleeEnchantments as $enchantment){ @@ -1756,7 +1759,7 @@ class Player extends Human implements CommandSender, ChunkLoader, ChunkListener, * Drops an item on the ground in front of the player. */ public function dropItem(Item $item) : void{ - $this->broadcastEntityEvent(ActorEventPacket::ARM_SWING, null, $this->getViewers()); + $this->broadcastAnimation(new ArmSwingAnimation($this), $this->getViewers()); $this->getWorld()->dropItem($this->location->add(0, 1.3, 0), $item, $this->getDirectionVector()->multiply(0.4), 40); } @@ -2172,20 +2175,12 @@ class Player extends Human implements CommandSender, ChunkLoader, ChunkListener, $this->networkProperties->setBlockPos(EntityMetadataProperties::PLAYER_BED_POSITION, $this->sleeping ?? new Vector3(0, 0, 0)); } - public function broadcastEntityEvent(int $eventId, ?int $eventData = null, ?array $players = null) : void{ - if($this->spawned and $players === null){ - $players = $this->getViewers(); - $players[] = $this; + public function broadcastAnimation(Animation $animation, ?array $targets = null) : void{ + if($this->spawned and $targets === null){ + $targets = $this->getViewers(); + $targets[] = $this; } - parent::broadcastEntityEvent($eventId, $eventData, $players); - } - - public function broadcastAnimation(?array $players, int $animationId) : void{ - if($this->spawned and $players === null){ - $players = $this->getViewers(); - $players[] = $this; - } - parent::broadcastAnimation($players, $animationId); + parent::broadcastAnimation($animation, $targets); } public function getOffsetPosition(Vector3 $vector3) : Vector3{