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.
This commit is contained in:
Dylan K. Taylor 2020-05-01 13:57:26 +01:00
parent 9615186afd
commit 8682ea35f7
17 changed files with 471 additions and 48 deletions

View File

@ -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(){

View File

@ -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();

View File

@ -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{

View File

@ -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));
}
}

View File

@ -0,0 +1,36 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\entity\animation;
use pocketmine\network\mcpe\protocol\ClientboundPacket;
/**
* Represents an animation such as an arm swing, or other visual effect done by entities.
*/
interface Animation{
/**
* @return ClientboundPacket[]
*/
public function encode() : array;
}

View File

@ -0,0 +1,43 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\entity\animation;
use pocketmine\entity\Living;
use pocketmine\network\mcpe\protocol\ActorEventPacket;
final class ArmSwingAnimation implements Animation{
/** @var Living */
private $entity; //TODO: not sure if this should be constrained to humanoids, but we don't have any concept of that right now
public function __construct(Living $entity){
$this->entity = $entity;
}
public function encode() : array{
return [
ActorEventPacket::create($this->entity->getId(), ActorEventPacket::ARM_SWING, 0)
];
}
}

View File

@ -0,0 +1,46 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\entity\animation;
use pocketmine\entity\projectile\Arrow;
use pocketmine\network\mcpe\protocol\ActorEventPacket;
class ArrowShakeAnimation implements Animation{
/** @var Arrow */
private $arrow;
/** @var int */
private $durationInTicks;
public function __construct(Arrow $arrow, int $durationInTicks){
$this->arrow = $arrow;
$this->durationInTicks = $durationInTicks;
}
public function encode() : array{
return [
ActorEventPacket::create($this->arrow->getId(), ActorEventPacket::ARROW_SHAKE, $this->durationInTicks)
];
}
}

View File

@ -0,0 +1,49 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\entity\animation;
use pocketmine\entity\Human;
use pocketmine\item\Item;
use pocketmine\network\mcpe\protocol\ActorEventPacket;
final class ConsumingItemAnimation implements Animation{
/** @var Human */
private $human;
/** @var Item */
private $item;
public function __construct(Human $human, Item $item){
//TODO: maybe this can be expanded to more than just player entities?
$this->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())
];
}
}

View File

@ -0,0 +1,43 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\entity\animation;
use pocketmine\entity\Living;
use pocketmine\network\mcpe\protocol\AnimatePacket;
final class CriticalHitAnimation implements Animation{
/** @var Living */
private $entity;
public function __construct(Living $entity){
$this->entity = $entity;
}
public function encode() : array{
return [
AnimatePacket::create($this->entity->getId(), AnimatePacket::ACTION_CRITICAL_HIT)
];
}
}

View File

@ -0,0 +1,43 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\entity\animation;
use pocketmine\entity\Living;
use pocketmine\network\mcpe\protocol\ActorEventPacket;
final class DeathAnimation implements Animation{
/** @var Living */
private $entity;
public function __construct(Living $entity){
$this->entity = $entity;
}
public function encode() : array{
return [
ActorEventPacket::create($this->entity->getId(), ActorEventPacket::DEATH_ANIMATION, 0)
];
}
}

View File

@ -0,0 +1,43 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\entity\animation;
use pocketmine\entity\Living;
use pocketmine\network\mcpe\protocol\ActorEventPacket;
final class HurtAnimation implements Animation{
/** @var Living */
private $entity;
public function __construct(Living $entity){
$this->entity = $entity;
}
public function encode() : array{
return [
ActorEventPacket::create($this->entity->getId(), ActorEventPacket::HURT_ANIMATION, 0)
];
}
}

View File

@ -0,0 +1,43 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\entity\animation;
use pocketmine\entity\Living;
use pocketmine\network\mcpe\protocol\ActorEventPacket;
final class RespawnAnimation implements Animation{
/** @var Living */
private $entity;
public function __construct(Living $entity){
$this->entity = $entity;
}
public function encode() : array{
return [
ActorEventPacket::create($this->entity->getId(), ActorEventPacket::RESPAWN, 0)
];
}
}

View File

@ -0,0 +1,43 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\entity\animation;
use pocketmine\entity\Squid;
use pocketmine\network\mcpe\protocol\ActorEventPacket;
final class SquidInkCloudAnimation implements Animation{
/** @var Squid */
private $squid;
public function __construct(Squid $squid){
$this->squid = $squid;
}
public function encode() : array{
return [
ActorEventPacket::create($this->squid->getId(), ActorEventPacket::SQUID_INK_CLOUD, 0)
];
}
}

View File

@ -0,0 +1,44 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\entity\animation;
use pocketmine\entity\Human;
use pocketmine\network\mcpe\protocol\ActorEventPacket;
final class TotemUseAnimation implements Animation{
/** @var Human */
private $human;
public function __construct(Human $human){
//TODO: check if this can be expanded to more than just humans
$this->human = $human;
}
public function encode() : array{
return [
ActorEventPacket::create($this->human->getId(), ActorEventPacket::CONSUME_TOTEM, 0)
];
}
}

View File

@ -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{

View File

@ -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;

View File

@ -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{