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\Block;
use pocketmine\block\Water; use pocketmine\block\Water;
use pocketmine\entity\animation\Animation;
use pocketmine\event\entity\EntityDamageEvent; use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\event\entity\EntityDespawnEvent; use pocketmine\event\entity\EntityDespawnEvent;
use pocketmine\event\entity\EntityMotionEvent; use pocketmine\event\entity\EntityMotionEvent;
@ -43,9 +44,7 @@ use pocketmine\nbt\tag\DoubleTag;
use pocketmine\nbt\tag\FloatTag; use pocketmine\nbt\tag\FloatTag;
use pocketmine\nbt\tag\ListTag; use pocketmine\nbt\tag\ListTag;
use pocketmine\nbt\tag\StringTag; use pocketmine\nbt\tag\StringTag;
use pocketmine\network\mcpe\protocol\ActorEventPacket;
use pocketmine\network\mcpe\protocol\AddActorPacket; use pocketmine\network\mcpe\protocol\AddActorPacket;
use pocketmine\network\mcpe\protocol\AnimatePacket;
use pocketmine\network\mcpe\protocol\MoveActorAbsolutePacket; use pocketmine\network\mcpe\protocol\MoveActorAbsolutePacket;
use pocketmine\network\mcpe\protocol\SetActorMotionPacket; use pocketmine\network\mcpe\protocol\SetActorMotionPacket;
use pocketmine\network\mcpe\protocol\types\entity\Attribute as NetworkAttribute; 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{ public function broadcastAnimation(Animation $animation, ?array $targets = null) : void{
$this->server->broadcastPackets($players ?? $this->getViewers(), [ActorEventPacket::create($this->id, $eventId, $eventData ?? 0)]); $this->server->broadcastPackets($targets ?? $this->getViewers(), $animation->encode());
}
/**
* @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 __destruct(){ public function __destruct(){

View File

@ -24,6 +24,7 @@ declare(strict_types=1);
namespace pocketmine\entity; namespace pocketmine\entity;
use pocketmine\block\inventory\EnderChestInventory; use pocketmine\block\inventory\EnderChestInventory;
use pocketmine\entity\animation\TotemUseAnimation;
use pocketmine\entity\effect\EffectInstance; use pocketmine\entity\effect\EffectInstance;
use pocketmine\entity\effect\VanillaEffects; use pocketmine\entity\effect\VanillaEffects;
use pocketmine\entity\projectile\ProjectileSource; use pocketmine\entity\projectile\ProjectileSource;
@ -43,7 +44,6 @@ use pocketmine\nbt\tag\ListTag;
use pocketmine\nbt\tag\StringTag; use pocketmine\nbt\tag\StringTag;
use pocketmine\network\mcpe\convert\SkinAdapterSingleton; use pocketmine\network\mcpe\convert\SkinAdapterSingleton;
use pocketmine\network\mcpe\convert\TypeConverter; use pocketmine\network\mcpe\convert\TypeConverter;
use pocketmine\network\mcpe\protocol\ActorEventPacket;
use pocketmine\network\mcpe\protocol\AddPlayerPacket; use pocketmine\network\mcpe\protocol\AddPlayerPacket;
use pocketmine\network\mcpe\protocol\MovePlayerPacket; use pocketmine\network\mcpe\protocol\MovePlayerPacket;
use pocketmine\network\mcpe\protocol\PlayerListPacket; 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::FIRE_RESISTANCE(), 40 * 20, 1));
$this->effectManager->add(new EffectInstance(VanillaEffects::ABSORPTION(), 5 * 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()); $this->getWorld()->addSound($this->location->add(0, $this->eyeHeight, 0), new TotemUseSound());
$hand = $this->inventory->getItemInHand(); $hand = $this->inventory->getItemInHand();

View File

@ -25,6 +25,9 @@ namespace pocketmine\entity;
use pocketmine\block\Block; use pocketmine\block\Block;
use pocketmine\block\BlockLegacyIds; 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\EffectInstance;
use pocketmine\entity\effect\EffectManager; use pocketmine\entity\effect\EffectManager;
use pocketmine\entity\effect\VanillaEffects; use pocketmine\entity\effect\VanillaEffects;
@ -46,7 +49,6 @@ use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\FloatTag; use pocketmine\nbt\tag\FloatTag;
use pocketmine\nbt\tag\ListTag; use pocketmine\nbt\tag\ListTag;
use pocketmine\nbt\tag\ShortTag; 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\EntityMetadataFlags;
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataProperties; use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataProperties;
use pocketmine\player\Player; use pocketmine\player\Player;
@ -164,7 +166,7 @@ abstract class Living extends Entity{
parent::setHealth($amount); parent::setHealth($amount);
$this->attributeMap->get(Attribute::HEALTH)->setValue(ceil($this->getHealth()), true); $this->attributeMap->get(Attribute::HEALTH)->setValue(ceil($this->getHealth()), true);
if($this->isAlive() and !$wasAlive){ 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{ 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{ 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{ protected function startDeathAnimation() : void{
$this->broadcastEntityEvent(ActorEventPacket::DEATH_ANIMATION); $this->broadcastAnimation(new DeathAnimation($this));
} }
protected function endDeathAnimation() : void{ protected function endDeathAnimation() : void{

View File

@ -23,12 +23,12 @@ declare(strict_types=1);
namespace pocketmine\entity; namespace pocketmine\entity;
use pocketmine\entity\animation\SquidInkCloudAnimation;
use pocketmine\event\entity\EntityDamageByEntityEvent; use pocketmine\event\entity\EntityDamageByEntityEvent;
use pocketmine\event\entity\EntityDamageEvent; use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\item\VanillaItems; use pocketmine\item\VanillaItems;
use pocketmine\math\Vector3; use pocketmine\math\Vector3;
use pocketmine\nbt\tag\CompoundTag; 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\EntityLegacyIds;
use function atan2; use function atan2;
use function mt_rand; use function mt_rand;
@ -71,7 +71,7 @@ class Squid extends WaterAnimal{
$this->swimDirection = $this->location->subtract($e->location)->normalize(); $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; namespace pocketmine\entity\projectile;
use pocketmine\block\Block; use pocketmine\block\Block;
use pocketmine\entity\animation\ArrowShakeAnimation;
use pocketmine\entity\Entity; use pocketmine\entity\Entity;
use pocketmine\event\entity\ProjectileHitEvent; use pocketmine\event\entity\ProjectileHitEvent;
use pocketmine\event\inventory\InventoryPickupArrowEvent; use pocketmine\event\inventory\InventoryPickupArrowEvent;
use pocketmine\item\VanillaItems; use pocketmine\item\VanillaItems;
use pocketmine\math\RayTraceResult; use pocketmine\math\RayTraceResult;
use pocketmine\nbt\tag\CompoundTag; 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\EntityLegacyIds;
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataFlags; use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataFlags;
use pocketmine\player\Player; use pocketmine\player\Player;
@ -140,7 +140,7 @@ class Arrow extends Projectile{
protected function onHitBlock(Block $blockHit, RayTraceResult $hitResult) : void{ protected function onHitBlock(Block $blockHit, RayTraceResult $hitResult) : void{
parent::onHitBlock($blockHit, $hitResult); 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{ 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\ItemFrame;
use pocketmine\block\Sign; use pocketmine\block\Sign;
use pocketmine\block\utils\SignText; use pocketmine\block\utils\SignText;
use pocketmine\entity\animation\ConsumingItemAnimation;
use pocketmine\event\player\PlayerEditBookEvent; use pocketmine\event\player\PlayerEditBookEvent;
use pocketmine\inventory\transaction\action\InventoryAction; use pocketmine\inventory\transaction\action\InventoryAction;
use pocketmine\inventory\transaction\CraftingTransaction; use pocketmine\inventory\transaction\CraftingTransaction;
@ -158,11 +159,11 @@ class InGamePacketHandler extends PacketHandler{
switch($packet->event){ switch($packet->event){
case ActorEventPacket::EATING_ITEM: //TODO: ignore this and handle it server-side 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; return false;
} }
$this->player->broadcastAnimation(new ConsumingItemAnimation($this->player, $this->player->getInventory()->getItemInHand()));
$this->player->broadcastEntityEvent(ActorEventPacket::EATING_ITEM, $packet->data);
break; break;
default: default:
return false; return false;

View File

@ -29,10 +29,14 @@ use pocketmine\block\UnknownBlock;
use pocketmine\block\VanillaBlocks; use pocketmine\block\VanillaBlocks;
use pocketmine\command\CommandSender; use pocketmine\command\CommandSender;
use pocketmine\crafting\CraftingGrid; 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\effect\VanillaEffects;
use pocketmine\entity\Entity; use pocketmine\entity\Entity;
use pocketmine\entity\EntityFactory; use pocketmine\entity\EntityFactory;
use pocketmine\entity\Human; use pocketmine\entity\Human;
use pocketmine\entity\Living;
use pocketmine\entity\object\ItemEntity; use pocketmine\entity\object\ItemEntity;
use pocketmine\entity\projectile\Arrow; use pocketmine\entity\projectile\Arrow;
use pocketmine\entity\Skin; use pocketmine\entity\Skin;
@ -80,7 +84,6 @@ use pocketmine\nbt\tag\DoubleTag;
use pocketmine\nbt\tag\IntTag; use pocketmine\nbt\tag\IntTag;
use pocketmine\nbt\tag\ListTag; use pocketmine\nbt\tag\ListTag;
use pocketmine\network\mcpe\NetworkSession; use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\ActorEventPacket;
use pocketmine\network\mcpe\protocol\AnimatePacket; use pocketmine\network\mcpe\protocol\AnimatePacket;
use pocketmine\network\mcpe\protocol\LevelEventPacket; use pocketmine\network\mcpe\protocol\LevelEventPacket;
use pocketmine\network\mcpe\protocol\MovePlayerPacket; use pocketmine\network\mcpe\protocol\MovePlayerPacket;
@ -995,7 +998,7 @@ class Player extends Human implements CommandSender, ChunkLoader, ChunkListener,
$this->getWorld()->setSleepTicks(0); $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()){ if($ev->isCancelled()){
return false; 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)){ if($target->onAttack($this->inventory->getItemInHand(), $face, $this)){
return true; return true;
} }
@ -1585,7 +1588,7 @@ class Player extends Human implements CommandSender, ChunkLoader, ChunkListener,
$block = $this->getWorld()->getBlock($pos); $block = $this->getWorld()->getBlock($pos);
$this->getWorld()->addParticle($pos, new BlockPunchParticle($block, $face)); $this->getWorld()->addParticle($pos, new BlockPunchParticle($block, $face));
$this->getWorld()->addSound($pos, new BlockPunchSound($block)); $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 //TODO: destroy-progress level event
} }
@ -1603,7 +1606,7 @@ class Player extends Human implements CommandSender, ChunkLoader, ChunkListener,
$this->doCloseInventory(); $this->doCloseInventory();
if($this->canInteract($pos->add(0.5, 0.5, 0.5), $this->isCreative() ? 13 : 7) and !$this->isSpectator()){ 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(); $item = $this->inventory->getItemInHand();
$oldItem = clone $item; $oldItem = clone $item;
if($this->getWorld()->useBreakOn($pos, $item, $this, true)){ if($this->getWorld()->useBreakOn($pos, $item, $this, true)){
@ -1627,7 +1630,7 @@ class Player extends Human implements CommandSender, ChunkLoader, ChunkListener,
$this->setUsingItem(false); $this->setUsingItem(false);
if($this->canInteract($pos->add(0.5, 0.5, 0.5), 13) and !$this->isSpectator()){ 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 $item = $this->inventory->getItemInHand(); //this is a copy of the real item
$oldItem = clone $item; $oldItem = clone $item;
if($this->getWorld()->useItemOn($pos, $item, $face, $clickOffset, $this, true)){ 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()){ if($ev->isCancelled()){
return false; return false;
} }
$this->broadcastEntityEvent(ActorEventPacket::ARM_SWING, null, $this->getViewers()); $this->broadcastAnimation(new ArmSwingAnimation($this), $this->getViewers());
if($ev->getModifier(EntityDamageEvent::MODIFIER_CRITICAL) > 0){ if($ev->getModifier(EntityDamageEvent::MODIFIER_CRITICAL) > 0 and $entity instanceof Living){
$entity->broadcastAnimation(null, AnimatePacket::ACTION_CRITICAL_HIT); $entity->broadcastAnimation(new CriticalHitAnimation($entity));
} }
foreach($meleeEnchantments as $enchantment){ 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. * Drops an item on the ground in front of the player.
*/ */
public function dropItem(Item $item) : void{ 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); $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)); $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{ public function broadcastAnimation(Animation $animation, ?array $targets = null) : void{
if($this->spawned and $players === null){ if($this->spawned and $targets === null){
$players = $this->getViewers(); $targets = $this->getViewers();
$players[] = $this; $targets[] = $this;
} }
parent::broadcastEntityEvent($eventId, $eventData, $players); parent::broadcastAnimation($animation, $targets);
}
public function broadcastAnimation(?array $players, int $animationId) : void{
if($this->spawned and $players === null){
$players = $this->getViewers();
$players[] = $this;
}
parent::broadcastAnimation($players, $animationId);
} }
public function getOffsetPosition(Vector3 $vector3) : Vector3{ public function getOffsetPosition(Vector3 $vector3) : Vector3{