Entity: replace separate height/width/eyeHeight fields with an EntitySizeInfo structure

this will make it easier to implement stuff like sleeping (properly), swimming and gliding without needing to duplicate all the fields.
This commit is contained in:
Dylan K. Taylor
2021-01-08 00:10:11 +00:00
parent 574b615b4c
commit e53b57732b
15 changed files with 103 additions and 60 deletions

View File

@ -118,13 +118,8 @@ abstract class Entity{
/** @var bool */ /** @var bool */
public $onGround = false; public $onGround = false;
/** @var float */ /** @var EntitySizeInfo */
public $eyeHeight = null; public $size;
/** @var float */
public $height;
/** @var float */
public $width;
/** @var float */ /** @var float */
private $health = 20.0; private $health = 20.0;
@ -218,9 +213,7 @@ abstract class Entity{
public function __construct(Location $location, ?CompoundTag $nbt = null){ public function __construct(Location $location, ?CompoundTag $nbt = null){
$this->timings = Timings::getEntityTimings($this); $this->timings = Timings::getEntityTimings($this);
if($this->eyeHeight === null){ $this->size = $this->getInitialSizeInfo();
$this->eyeHeight = $this->height / 2 + 0.1;
}
$this->id = self::nextRuntimeId(); $this->id = self::nextRuntimeId();
$this->server = $location->getWorld()->getServer(); $this->server = $location->getWorld()->getServer();
@ -259,6 +252,8 @@ abstract class Entity{
} }
abstract protected function getInitialSizeInfo() : EntitySizeInfo;
public function getNameTag() : string{ public function getNameTag() : string{
return $this->nameTag; return $this->nameTag;
} }
@ -299,11 +294,7 @@ abstract class Entity{
if($value <= 0){ if($value <= 0){
throw new \InvalidArgumentException("Scale must be greater than 0"); throw new \InvalidArgumentException("Scale must be greater than 0");
} }
$multiplier = $value / $this->getScale(); $this->size = $this->getInitialSizeInfo()->scale($value);
$this->width *= $multiplier;
$this->height *= $multiplier;
$this->eyeHeight *= $multiplier;
$this->scale = $value; $this->scale = $value;
@ -315,14 +306,14 @@ abstract class Entity{
} }
protected function recalculateBoundingBox() : void{ protected function recalculateBoundingBox() : void{
$halfWidth = $this->width / 2; $halfWidth = $this->size->getWidth() / 2;
$this->boundingBox = new AxisAlignedBB( $this->boundingBox = new AxisAlignedBB(
$this->location->x - $halfWidth, $this->location->x - $halfWidth,
$this->location->y + $this->ySize, $this->location->y + $this->ySize,
$this->location->z - $halfWidth, $this->location->z - $halfWidth,
$this->location->x + $halfWidth, $this->location->x + $halfWidth,
$this->location->y + $this->height + $this->ySize, $this->location->y + $this->size->getHeight() + $this->ySize,
$this->location->z + $halfWidth $this->location->z + $halfWidth
); );
} }
@ -1042,7 +1033,7 @@ abstract class Entity{
} }
public function getEyeHeight() : float{ public function getEyeHeight() : float{
return $this->eyeHeight; return $this->size->getEyeHeight();
} }
public function getEyePos() : Vector3{ public function getEyePos() : Vector3{
@ -1585,8 +1576,8 @@ abstract class Entity{
protected function syncNetworkData(EntityMetadataCollection $properties) : void{ protected function syncNetworkData(EntityMetadataCollection $properties) : void{
$properties->setByte(EntityMetadataProperties::ALWAYS_SHOW_NAMETAG, $this->alwaysShowNameTag ? 1 : 0); $properties->setByte(EntityMetadataProperties::ALWAYS_SHOW_NAMETAG, $this->alwaysShowNameTag ? 1 : 0);
$properties->setFloat(EntityMetadataProperties::BOUNDING_BOX_HEIGHT, $this->height); $properties->setFloat(EntityMetadataProperties::BOUNDING_BOX_HEIGHT, $this->size->getHeight());
$properties->setFloat(EntityMetadataProperties::BOUNDING_BOX_WIDTH, $this->width); $properties->setFloat(EntityMetadataProperties::BOUNDING_BOX_WIDTH, $this->size->getWidth());
$properties->setFloat(EntityMetadataProperties::SCALE, $this->scale); $properties->setFloat(EntityMetadataProperties::SCALE, $this->scale);
$properties->setLong(EntityMetadataProperties::LEAD_HOLDER_EID, -1); $properties->setLong(EntityMetadataProperties::LEAD_HOLDER_EID, -1);
$properties->setLong(EntityMetadataProperties::OWNER_EID, $this->ownerId ?? -1); $properties->setLong(EntityMetadataProperties::OWNER_EID, $this->ownerId ?? -1);

View File

@ -0,0 +1,53 @@
<?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;
final class EntitySizeInfo{
/** @var float */
private $height;
/** @var float */
private $width;
/** @var float */
private $eyeHeight;
public function __construct(float $height, float $width, ?float $eyeHeight = null){
$this->height = $height;
$this->width = $width;
$this->eyeHeight = $eyeHeight ?? min($this->height / 2 + 0.1, $this->height);
}
public function getHeight() : float{ return $this->height; }
public function getWidth() : float{ return $this->width; }
public function getEyeHeight() : float{ return $this->eyeHeight; }
public function scale(float $newScale) : self{
return new self(
$this->height * $newScale,
$this->width * $newScale,
$this->eyeHeight * $newScale
);
}
}

View File

@ -74,10 +74,6 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
/** @var UUID */ /** @var UUID */
protected $uuid; protected $uuid;
public $width = 0.6;
public $height = 1.8;
public $eyeHeight = 1.62;
/** @var Skin */ /** @var Skin */
protected $skin; protected $skin;
@ -94,6 +90,8 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
parent::__construct($location, $nbt); parent::__construct($location, $nbt);
} }
protected function getInitialSizeInfo() : EntitySizeInfo{ return new EntitySizeInfo(1.8, 0.6, 1.62); }
/** /**
* @throws InvalidSkinException * @throws InvalidSkinException
* @throws \UnexpectedValueException * @throws \UnexpectedValueException

View File

@ -715,7 +715,7 @@ abstract class Living extends Entity{
$blocks = []; $blocks = [];
$nextIndex = 0; $nextIndex = 0;
foreach(VoxelRayTrace::inDirection($this->location->add(0, $this->eyeHeight, 0), $this->getDirectionVector(), $maxDistance) as $vector3){ foreach(VoxelRayTrace::inDirection($this->location->add(0, $this->size->getEyeHeight(), 0), $this->getDirectionVector(), $maxDistance) as $vector3){
$block = $this->getWorld()->getBlockAt($vector3->x, $vector3->y, $vector3->z); $block = $this->getWorld()->getBlockAt($vector3->x, $vector3->y, $vector3->z);
$blocks[$nextIndex++] = $block; $blocks[$nextIndex++] = $block;

View File

@ -39,9 +39,6 @@ class Squid extends WaterAnimal{
public static function getNetworkTypeId() : string{ return EntityIds::SQUID; } public static function getNetworkTypeId() : string{ return EntityIds::SQUID; }
public $width = 0.95;
public $height = 0.95;
/** @var Vector3|null */ /** @var Vector3|null */
public $swimDirection = null; public $swimDirection = null;
/** @var float */ /** @var float */
@ -50,6 +47,8 @@ class Squid extends WaterAnimal{
/** @var int */ /** @var int */
private $switchDirectionTicker = 0; private $switchDirectionTicker = 0;
protected function getInitialSizeInfo() : EntitySizeInfo{ return new EntitySizeInfo(0.95, 0.95); }
public function initEntity(CompoundTag $nbt) : void{ public function initEntity(CompoundTag $nbt) : void{
$this->setMaxHealth(10); $this->setMaxHealth(10);
parent::initEntity($nbt); parent::initEntity($nbt);

View File

@ -38,14 +38,15 @@ class Villager extends Living implements Ageable{
public static function getNetworkTypeId() : string{ return EntityIds::VILLAGER; } public static function getNetworkTypeId() : string{ return EntityIds::VILLAGER; }
public $width = 0.6;
public $height = 1.8;
/** @var bool */ /** @var bool */
private $baby = false; private $baby = false;
/** @var int */ /** @var int */
private $profession = self::PROFESSION_FARMER; private $profession = self::PROFESSION_FARMER;
protected function getInitialSizeInfo() : EntitySizeInfo{
return new EntitySizeInfo(1.8, 0.6); //TODO: eye height??
}
public function getName() : string{ public function getName() : string{
return "Villager"; return "Villager";
} }

View File

@ -31,8 +31,9 @@ class Zombie extends Living{
public static function getNetworkTypeId() : string{ return EntityIds::ZOMBIE; } public static function getNetworkTypeId() : string{ return EntityIds::ZOMBIE; }
public $width = 0.6; protected function getInitialSizeInfo() : EntitySizeInfo{
public $height = 1.8; return new EntitySizeInfo(1.8, 0.6); //TODO: eye height ??
}
public function getName() : string{ public function getName() : string{
return "Zombie"; return "Zombie";

View File

@ -24,6 +24,7 @@ declare(strict_types=1);
namespace pocketmine\entity\object; namespace pocketmine\entity\object;
use pocketmine\entity\Entity; use pocketmine\entity\Entity;
use pocketmine\entity\EntitySizeInfo;
use pocketmine\entity\Human; use pocketmine\entity\Human;
use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\IntTag; use pocketmine\nbt\tag\IntTag;
@ -78,9 +79,6 @@ class ExperienceOrb extends Entity{
return $result; return $result;
} }
public $height = 0.25;
public $width = 0.25;
public $gravity = 0.04; public $gravity = 0.04;
public $drag = 0.02; public $drag = 0.02;
@ -102,6 +100,8 @@ class ExperienceOrb extends Entity{
/** @var int */ /** @var int */
protected $xpValue = 1; protected $xpValue = 1;
protected function getInitialSizeInfo() : EntitySizeInfo{ return new EntitySizeInfo(0.25, 0.25); }
protected function initEntity(CompoundTag $nbt) : void{ protected function initEntity(CompoundTag $nbt) : void{
parent::initEntity($nbt); parent::initEntity($nbt);

View File

@ -27,6 +27,7 @@ use pocketmine\block\Block;
use pocketmine\block\BlockFactory; use pocketmine\block\BlockFactory;
use pocketmine\block\utils\Fallable; use pocketmine\block\utils\Fallable;
use pocketmine\entity\Entity; use pocketmine\entity\Entity;
use pocketmine\entity\EntitySizeInfo;
use pocketmine\entity\Location; use pocketmine\entity\Location;
use pocketmine\event\entity\EntityBlockChangeEvent; use pocketmine\event\entity\EntityBlockChangeEvent;
use pocketmine\event\entity\EntityDamageEvent; use pocketmine\event\entity\EntityDamageEvent;
@ -44,9 +45,6 @@ class FallingBlock extends Entity{
public static function getNetworkTypeId() : string{ return EntityIds::FALLING_BLOCK; } public static function getNetworkTypeId() : string{ return EntityIds::FALLING_BLOCK; }
public $width = 0.98;
public $height = 0.98;
protected $gravity = 0.04; protected $gravity = 0.04;
protected $drag = 0.02; protected $drag = 0.02;
@ -60,6 +58,8 @@ class FallingBlock extends Entity{
parent::__construct($location, $nbt); parent::__construct($location, $nbt);
} }
protected function getInitialSizeInfo() : EntitySizeInfo{ return new EntitySizeInfo(0.98, 0.98); }
public static function parseBlockNBT(BlockFactory $factory, CompoundTag $nbt) : Block{ public static function parseBlockNBT(BlockFactory $factory, CompoundTag $nbt) : Block{
$blockId = 0; $blockId = 0;
@ -102,7 +102,7 @@ class FallingBlock extends Entity{
if(!$this->isFlaggedForDespawn()){ if(!$this->isFlaggedForDespawn()){
$world = $this->getWorld(); $world = $this->getWorld();
$pos = $this->location->add(-$this->width / 2, $this->height, -$this->width / 2)->floor(); $pos = $this->location->add(-$this->size->getWidth() / 2, $this->size->getHeight(), -$this->size->getWidth() / 2)->floor();
$this->block->position($world, $pos->x, $pos->y, $pos->z); $this->block->position($world, $pos->x, $pos->y, $pos->z);

View File

@ -24,6 +24,7 @@ declare(strict_types=1);
namespace pocketmine\entity\object; namespace pocketmine\entity\object;
use pocketmine\entity\Entity; use pocketmine\entity\Entity;
use pocketmine\entity\EntitySizeInfo;
use pocketmine\entity\Location; use pocketmine\entity\Location;
use pocketmine\event\entity\ItemDespawnEvent; use pocketmine\event\entity\ItemDespawnEvent;
use pocketmine\event\entity\ItemSpawnEvent; use pocketmine\event\entity\ItemSpawnEvent;
@ -54,9 +55,6 @@ class ItemEntity extends Entity{
/** @var Item */ /** @var Item */
protected $item; protected $item;
public $width = 0.25;
public $height = 0.25;
protected $gravity = 0.04; protected $gravity = 0.04;
protected $drag = 0.02; protected $drag = 0.02;
@ -73,6 +71,8 @@ class ItemEntity extends Entity{
parent::__construct($location, $nbt); parent::__construct($location, $nbt);
} }
protected function getInitialSizeInfo() : EntitySizeInfo{ return new EntitySizeInfo(0.25, 0.25); }
protected function initEntity(CompoundTag $nbt) : void{ protected function initEntity(CompoundTag $nbt) : void{
parent::initEntity($nbt); parent::initEntity($nbt);

View File

@ -25,6 +25,7 @@ namespace pocketmine\entity\object;
use pocketmine\block\VanillaBlocks; use pocketmine\block\VanillaBlocks;
use pocketmine\entity\Entity; use pocketmine\entity\Entity;
use pocketmine\entity\EntitySizeInfo;
use pocketmine\entity\Location; use pocketmine\entity\Location;
use pocketmine\event\entity\EntityDamageByEntityEvent; use pocketmine\event\entity\EntityDamageByEntityEvent;
use pocketmine\item\VanillaItems; use pocketmine\item\VanillaItems;
@ -60,12 +61,6 @@ class Painting extends Entity{
/** @var float */ /** @var float */
protected $drag = 1.0; protected $drag = 1.0;
//these aren't accurate, but it doesn't matter since they aren't used (vanilla PC does something similar)
/** @var float */
public $height = 0.5;
/** @var float */
public $width = 0.5;
/** @var Vector3 */ /** @var Vector3 */
protected $blockIn; protected $blockIn;
/** @var int */ /** @var int */
@ -80,6 +75,11 @@ class Painting extends Entity{
parent::__construct($location, $nbt); parent::__construct($location, $nbt);
} }
protected function getInitialSizeInfo() : EntitySizeInfo{
//these aren't accurate, but it doesn't matter since they aren't used (vanilla PC does something similar)
return new EntitySizeInfo(0.5, 0.5);
}
protected function initEntity(CompoundTag $nbt) : void{ protected function initEntity(CompoundTag $nbt) : void{
$this->setMaxHealth(1); $this->setMaxHealth(1);
$this->setHealth(1); $this->setHealth(1);

View File

@ -24,6 +24,7 @@ declare(strict_types=1);
namespace pocketmine\entity\object; namespace pocketmine\entity\object;
use pocketmine\entity\Entity; use pocketmine\entity\Entity;
use pocketmine\entity\EntitySizeInfo;
use pocketmine\entity\Explosive; use pocketmine\entity\Explosive;
use pocketmine\event\entity\EntityDamageEvent; use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\event\entity\ExplosionPrimeEvent; use pocketmine\event\entity\ExplosionPrimeEvent;
@ -40,9 +41,6 @@ class PrimedTNT extends Entity implements Explosive{
public static function getNetworkTypeId() : string{ return EntityIds::TNT; } public static function getNetworkTypeId() : string{ return EntityIds::TNT; }
public $width = 0.98;
public $height = 0.98;
protected $gravity = 0.04; protected $gravity = 0.04;
protected $drag = 0.02; protected $drag = 0.02;
@ -51,6 +49,8 @@ class PrimedTNT extends Entity implements Explosive{
public $canCollide = false; public $canCollide = false;
protected function getInitialSizeInfo() : EntitySizeInfo{ return new EntitySizeInfo(0.98, 0.98); }
public function getFuse() : int{ public function getFuse() : int{
return $this->fuse; return $this->fuse;
} }
@ -108,7 +108,7 @@ class PrimedTNT extends Entity implements Explosive{
$ev = new ExplosionPrimeEvent($this, 4); $ev = new ExplosionPrimeEvent($this, 4);
$ev->call(); $ev->call();
if(!$ev->isCancelled()){ if(!$ev->isCancelled()){
$explosion = new Explosion(Position::fromObject($this->location->add(0, $this->height / 2, 0), $this->getWorld()), $ev->getForce(), $this); $explosion = new Explosion(Position::fromObject($this->location->add(0, $this->size->getHeight() / 2, 0), $this->getWorld()), $ev->getForce(), $this);
if($ev->isBlockBreaking()){ if($ev->isBlockBreaking()){
$explosion->explodeA(); $explosion->explodeA();
} }

View File

@ -26,6 +26,7 @@ namespace pocketmine\entity\projectile;
use pocketmine\block\Block; use pocketmine\block\Block;
use pocketmine\entity\animation\ArrowShakeAnimation; use pocketmine\entity\animation\ArrowShakeAnimation;
use pocketmine\entity\Entity; use pocketmine\entity\Entity;
use pocketmine\entity\EntitySizeInfo;
use pocketmine\entity\Location; use pocketmine\entity\Location;
use pocketmine\event\entity\ProjectileHitEvent; use pocketmine\event\entity\ProjectileHitEvent;
use pocketmine\event\inventory\InventoryPickupArrowEvent; use pocketmine\event\inventory\InventoryPickupArrowEvent;
@ -50,9 +51,6 @@ class Arrow extends Projectile{
private const TAG_PICKUP = "pickup"; //TAG_Byte private const TAG_PICKUP = "pickup"; //TAG_Byte
public $width = 0.25;
public $height = 0.25;
protected $gravity = 0.05; protected $gravity = 0.05;
protected $drag = 0.01; protected $drag = 0.01;
@ -76,6 +74,8 @@ class Arrow extends Projectile{
$this->setCritical($critical); $this->setCritical($critical);
} }
protected function getInitialSizeInfo() : EntitySizeInfo{ return new EntitySizeInfo(0.25, 0.25); }
protected function initEntity(CompoundTag $nbt) : void{ protected function initEntity(CompoundTag $nbt) : void{
parent::initEntity($nbt); parent::initEntity($nbt);

View File

@ -24,16 +24,16 @@ declare(strict_types=1);
namespace pocketmine\entity\projectile; namespace pocketmine\entity\projectile;
use pocketmine\block\Block; use pocketmine\block\Block;
use pocketmine\entity\EntitySizeInfo;
use pocketmine\math\RayTraceResult; use pocketmine\math\RayTraceResult;
abstract class Throwable extends Projectile{ abstract class Throwable extends Projectile{
public $width = 0.25;
public $height = 0.25;
protected $gravity = 0.03; protected $gravity = 0.03;
protected $drag = 0.01; protected $drag = 0.01;
protected function getInitialSizeInfo() : EntitySizeInfo{ return new EntitySizeInfo(0.25, 0.25); }
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->flagForDespawn(); $this->flagForDespawn();

View File

@ -1657,7 +1657,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
$entity->attack($ev); $entity->attack($ev);
$soundPos = $entity->getPosition()->add(0, $entity->height / 2, 0); $soundPos = $entity->getPosition()->add(0, $entity->size->getHeight() / 2, 0);
if($ev->isCancelled()){ if($ev->isCancelled()){
$this->getWorld()->addSound($soundPos, new EntityAttackNoDamageSound()); $this->getWorld()->addSound($soundPos, new EntityAttackNoDamageSound());
return false; return false;