Re-organise some Entity methods

This commit is contained in:
Dylan K. Taylor 2017-10-19 18:25:01 +01:00
parent 50be26958a
commit 0a19a2611a

View File

@ -844,81 +844,6 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
}
/**
* @return Player[]
*/
public function getViewers() : array{
return $this->hasSpawned;
}
/**
* @param Player $player
*/
public function spawnTo(Player $player){
if(!isset($this->hasSpawned[$player->getLoaderId()]) and isset($player->usedChunks[Level::chunkHash($this->chunk->getX(), $this->chunk->getZ())])){
$this->hasSpawned[$player->getLoaderId()] = $player;
$this->sendSpawnPacket($player);
}
}
/**
* Called by spawnTo() to send whatever packets needed to spawn the entity to the client.
* @param Player $player
*/
protected function sendSpawnPacket(Player $player) : void{
$pk = new AddEntityPacket();
$pk->entityRuntimeId = $this->getId();
$pk->type = static::NETWORK_ID;
$pk->position = $this->asVector3();
$pk->motion = $this->getMotion();
$pk->yaw = $this->yaw;
$pk->pitch = $this->pitch;
$pk->metadata = $this->dataProperties;
$player->dataPacket($pk);
}
/**
* @param Player[]|Player $player
* @param array $data Properly formatted entity data, defaults to everything
*/
public function sendData($player, array $data = null){
if(!is_array($player)){
$player = [$player];
}
$pk = new SetEntityDataPacket();
$pk->entityRuntimeId = $this->getId();
$pk->metadata = $data ?? $this->dataProperties;
foreach($player as $p){
if($p === $this){
continue;
}
$p->dataPacket(clone $pk);
}
if($this instanceof Player){
$this->dataPacket($pk);
}
}
/**
* @param Player $player
* @param bool $send
*/
public function despawnFrom(Player $player, bool $send = true){
if(isset($this->hasSpawned[$player->getLoaderId()])){
if($send){
$pk = new RemoveEntityPacket();
$pk->entityUniqueId = $this->id;
$player->dataPacket($pk);
}
unset($this->hasSpawned[$player->getLoaderId()]);
}
}
/**
* @param EntityDamageEvent $source
*/
@ -945,6 +870,15 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
$this->setHealth($this->getHealth() + $source->getAmount());
}
public function kill(){
$this->health = 0;
$this->scheduleUpdate();
}
public function isAlive() : bool{
return $this->health > 0;
}
/**
* @return float
*/
@ -952,10 +886,6 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
return $this->health;
}
public function isAlive() : bool{
return $this->health > 0;
}
/**
* Sets the health of the Entity. This won't send any update to the players
*
@ -977,6 +907,20 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
}
}
/**
* @return int
*/
public function getMaxHealth() : int{
return $this->maxHealth;
}
/**
* @param int $amount
*/
public function setMaxHealth(int $amount){
$this->maxHealth = $amount;
}
/**
* @param EntityDamageEvent $type
*/
@ -995,24 +939,177 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
return $this->attributeMap;
}
/**
* @return int
*/
public function getMaxHealth() : int{
return $this->maxHealth;
public function entityBaseTick(int $tickDiff = 1) : bool{
//TODO: check vehicles
$this->justCreated = false;
if(count($this->changedDataProperties) > 0){
$this->sendData($this->hasSpawned, $this->changedDataProperties);
$this->changedDataProperties = [];
}
$hasUpdate = false;
$this->checkBlockCollision();
if($this->y <= -16 and $this->isAlive()){
$ev = new EntityDamageEvent($this, EntityDamageEvent::CAUSE_VOID, 10);
$this->attack($ev);
$hasUpdate = true;
}
if($this->isOnFire()){
$hasUpdate = ($hasUpdate || $this->doOnFireTick($tickDiff));
}
if($this->noDamageTicks > 0){
$this->noDamageTicks -= $tickDiff;
if($this->noDamageTicks < 0){
$this->noDamageTicks = 0;
}
}
$this->age += $tickDiff;
$this->ticksLived += $tickDiff;
return $hasUpdate;
}
public function isOnFire() : bool{
return $this->fireTicks > 0;
}
public function setOnFire(int $seconds){
$ticks = $seconds * 20;
if($ticks > $this->fireTicks){
$this->fireTicks = $ticks;
}
$this->setGenericFlag(self::DATA_FLAG_ONFIRE, true);
}
public function extinguish(){
$this->fireTicks = 0;
$this->setGenericFlag(self::DATA_FLAG_ONFIRE, false);
}
public function isFireProof() : bool{
return false;
}
protected function doOnFireTick(int $tickDiff = 1) : bool{
if($this->isFireProof() and $this->fireTicks > 1){
$this->fireTicks = 1;
}else{
$this->fireTicks -= $tickDiff;
}
if(($this->fireTicks % 20 === 0) or $tickDiff > 20){
$this->dealFireDamage();
}
if(!$this->isOnFire()){
$this->extinguish();
}else{
return true;
}
return false;
}
/**
* @param int $amount
* Called to deal damage to entities when they are on fire.
*/
public function setMaxHealth(int $amount){
$this->maxHealth = $amount;
protected function dealFireDamage(){
$ev = new EntityDamageEvent($this, EntityDamageEvent::CAUSE_FIRE_TICK, 1);
$this->attack($ev);
}
public function canCollideWith(Entity $entity) : bool{
return !$this->justCreated and $entity !== $this;
}
protected function updateMovement(){
$diffPosition = ($this->x - $this->lastX) ** 2 + ($this->y - $this->lastY) ** 2 + ($this->z - $this->lastZ) ** 2;
$diffRotation = ($this->yaw - $this->lastYaw) ** 2 + ($this->pitch - $this->lastPitch) ** 2;
$diffMotion = ($this->motionX - $this->lastMotionX) ** 2 + ($this->motionY - $this->lastMotionY) ** 2 + ($this->motionZ - $this->lastMotionZ) ** 2;
if($diffPosition > 0.0001 or $diffRotation > 1.0){
$this->lastX = $this->x;
$this->lastY = $this->y;
$this->lastZ = $this->z;
$this->lastYaw = $this->yaw;
$this->lastPitch = $this->pitch;
$this->broadcastMovement();
}
if($diffMotion > 0.0025 or ($diffMotion > 0.0001 and $this->getMotion()->lengthSquared() <= 0.0001)){ //0.05 ** 2
$this->lastMotionX = $this->motionX;
$this->lastMotionY = $this->motionY;
$this->lastMotionZ = $this->motionZ;
$this->broadcastMotion();
}
}
public function getOffsetPosition(Vector3 $vector3) : Vector3{
return new Vector3($vector3->x, $vector3->y + $this->baseOffset, $vector3->z);
}
protected function broadcastMovement(){
$pk = new MoveEntityPacket();
$pk->entityRuntimeId = $this->id;
$pk->position = $this->getOffsetPosition($this);
$pk->yaw = $this->yaw;
$pk->pitch = $this->pitch;
$pk->headYaw = $this->yaw; //TODO
$this->level->addChunkPacket($this->chunk->getX(), $this->chunk->getZ(), $pk);
}
protected function broadcastMotion(){
$pk = new SetEntityMotionPacket();
$pk->entityRuntimeId = $this->id;
$pk->motion = $this->getMotion();
$this->level->addChunkPacket($this->chunk->getX(), $this->chunk->getZ(), $pk);
}
protected function applyDragBeforeGravity() : bool{
return false;
}
protected function applyGravity(){
$this->motionY -= $this->gravity;
}
protected function tryChangeMovement(){
$friction = 1 - $this->drag;
if($this->applyDragBeforeGravity()){
$this->motionY *= $friction;
}
$this->applyGravity();
if(!$this->applyDragBeforeGravity()){
$this->motionY *= $friction;
}
if($this->onGround){
$friction *= $this->level->getBlock($this->floor()->subtract(0, 1, 0))->getFrictionFactor();
}
$this->motionX *= $friction;
$this->motionZ *= $friction;
}
protected function checkObstruction(float $x, float $y, float $z) : bool{
if(count($this->level->getCollisionCubes($this, $this->getBoundingBox(), false)) === 0){
return false;
@ -1108,151 +1205,27 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
return false;
}
public function entityBaseTick(int $tickDiff = 1) : bool{
//TODO: check vehicles
$this->justCreated = false;
if(count($this->changedDataProperties) > 0){
$this->sendData($this->hasSpawned, $this->changedDataProperties);
$this->changedDataProperties = [];
}
$hasUpdate = false;
$this->checkBlockCollision();
if($this->y <= -16 and $this->isAlive()){
$ev = new EntityDamageEvent($this, EntityDamageEvent::CAUSE_VOID, 10);
$this->attack($ev);
$hasUpdate = true;
}
if($this->isOnFire()){
$hasUpdate = ($hasUpdate || $this->doOnFireTick($tickDiff));
}
if($this->noDamageTicks > 0){
$this->noDamageTicks -= $tickDiff;
if($this->noDamageTicks < 0){
$this->noDamageTicks = 0;
}
}
$this->age += $tickDiff;
$this->ticksLived += $tickDiff;
return $hasUpdate;
}
protected function doOnFireTick(int $tickDiff = 1) : bool{
if($this->isFireProof() and $this->fireTicks > 1){
$this->fireTicks = 1;
}else{
$this->fireTicks -= $tickDiff;
}
if(($this->fireTicks % 20 === 0) or $tickDiff > 20){
$this->dealFireDamage();
}
if(!$this->isOnFire()){
$this->extinguish();
}else{
return true;
}
return false;
}
/**
* Called to deal damage to entities when they are on fire.
* @return int|null
*/
protected function dealFireDamage(){
$ev = new EntityDamageEvent($this, EntityDamageEvent::CAUSE_FIRE_TICK, 1);
$this->attack($ev);
}
protected function updateMovement(){
$diffPosition = ($this->x - $this->lastX) ** 2 + ($this->y - $this->lastY) ** 2 + ($this->z - $this->lastZ) ** 2;
$diffRotation = ($this->yaw - $this->lastYaw) ** 2 + ($this->pitch - $this->lastPitch) ** 2;
$diffMotion = ($this->motionX - $this->lastMotionX) ** 2 + ($this->motionY - $this->lastMotionY) ** 2 + ($this->motionZ - $this->lastMotionZ) ** 2;
if($diffPosition > 0.0001 or $diffRotation > 1.0){
$this->lastX = $this->x;
$this->lastY = $this->y;
$this->lastZ = $this->z;
$this->lastYaw = $this->yaw;
$this->lastPitch = $this->pitch;
$this->broadcastMovement();
public function getDirection(){
$rotation = ($this->yaw - 90) % 360;
if($rotation < 0){
$rotation += 360.0;
}
if($diffMotion > 0.0025 or ($diffMotion > 0.0001 and $this->getMotion()->lengthSquared() <= 0.0001)){ //0.05 ** 2
$this->lastMotionX = $this->motionX;
$this->lastMotionY = $this->motionY;
$this->lastMotionZ = $this->motionZ;
$this->broadcastMotion();
if((0 <= $rotation and $rotation < 45) or (315 <= $rotation and $rotation < 360)){
return 2; //North
}elseif(45 <= $rotation and $rotation < 135){
return 3; //East
}elseif(135 <= $rotation and $rotation < 225){
return 0; //South
}elseif(225 <= $rotation and $rotation < 315){
return 1; //West
}else{
return null;
}
}
public function getOffsetPosition(Vector3 $vector3) : Vector3{
return new Vector3($vector3->x, $vector3->y + $this->baseOffset, $vector3->z);
}
protected function broadcastMovement(){
$pk = new MoveEntityPacket();
$pk->entityRuntimeId = $this->id;
$pk->position = $this->getOffsetPosition($this);
$pk->yaw = $this->yaw;
$pk->pitch = $this->pitch;
$pk->headYaw = $this->yaw; //TODO
$this->level->addChunkPacket($this->chunk->getX(), $this->chunk->getZ(), $pk);
}
protected function broadcastMotion(){
$pk = new SetEntityMotionPacket();
$pk->entityRuntimeId = $this->id;
$pk->motion = $this->getMotion();
$this->level->addChunkPacket($this->chunk->getX(), $this->chunk->getZ(), $pk);
}
protected function applyDragBeforeGravity() : bool{
return false;
}
protected function applyGravity(){
$this->motionY -= $this->gravity;
}
protected function tryChangeMovement(){
$friction = 1 - $this->drag;
if($this->applyDragBeforeGravity()){
$this->motionY *= $friction;
}
$this->applyGravity();
if(!$this->applyDragBeforeGravity()){
$this->motionY *= $friction;
}
if($this->onGround){
$friction *= $this->level->getBlock($this->floor()->subtract(0, 1, 0))->getFrictionFactor();
}
$this->motionX *= $friction;
$this->motionZ *= $friction;
}
/**
* @return Vector3
*/
@ -1360,49 +1333,6 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
);
}
public function isOnFire() : bool{
return $this->fireTicks > 0;
}
public function setOnFire(int $seconds){
$ticks = $seconds * 20;
if($ticks > $this->fireTicks){
$this->fireTicks = $ticks;
}
$this->setGenericFlag(self::DATA_FLAG_ONFIRE, true);
}
public function extinguish(){
$this->fireTicks = 0;
$this->setGenericFlag(self::DATA_FLAG_ONFIRE, false);
}
public function isFireProof() : bool{
return false;
}
/**
* @return int|null
*/
public function getDirection(){
$rotation = ($this->yaw - 90) % 360;
if($rotation < 0){
$rotation += 360.0;
}
if((0 <= $rotation and $rotation < 45) or (315 <= $rotation and $rotation < 360)){
return 2; //North
}elseif(45 <= $rotation and $rotation < 135){
return 3; //East
}elseif(135 <= $rotation and $rotation < 225){
return 0; //South
}elseif(225 <= $rotation and $rotation < 315){
return 1; //West
}else{
return null;
}
}
public function canTriggerWalking() : bool{
return true;
}
@ -1451,39 +1381,6 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
}
protected function switchLevel(Level $targetLevel) : bool{
if($this->closed){
return false;
}
if($this->isValid()){
$this->server->getPluginManager()->callEvent($ev = new EntityLevelChangeEvent($this, $this->level, $targetLevel));
if($ev->isCancelled()){
return false;
}
$this->level->removeEntity($this);
if($this->chunk !== null){
$this->chunk->removeEntity($this);
}
$this->despawnFromAll();
}
$this->setLevel($targetLevel);
$this->level->addEntity($this);
$this->chunk = null;
return true;
}
public function getPosition() : Position{
return $this->asPosition();
}
public function getLocation() : Location{
return $this->asLocation();
}
public function isInsideOfWater() : bool{
$block = $this->level->getBlock($this->temporalVector->setComponents(Math::floorFloat($this->x), Math::floorFloat($y = ($this->y + $this->getEyeHeight())), Math::floorFloat($this->z)));
@ -1756,6 +1653,43 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
}
}
public function getPosition() : Position{
return $this->asPosition();
}
public function getLocation() : Location{
return $this->asLocation();
}
public function setPosition(Vector3 $pos){
if($this->closed){
return false;
}
if($pos instanceof Position and $pos->level !== null and $pos->level !== $this->level){
if($this->switchLevel($pos->getLevel()) === false){
return false;
}
}
$this->x = $pos->x;
$this->y = $pos->y;
$this->z = $pos->z;
$radius = $this->width / 2;
$this->boundingBox->setBounds($pos->x - $radius, $pos->y, $pos->z - $radius, $pos->x + $radius, $pos->y + $this->height, $pos->z + $radius);
$this->checkChunks();
return true;
}
public function setRotation(float $yaw, float $pitch){
$this->yaw = $yaw;
$this->pitch = $pitch;
$this->scheduleUpdate();
}
public function setPositionAndRotation(Vector3 $pos, float $yaw, float $pitch) : bool{
if($this->setPosition($pos) === true){
$this->setRotation($yaw, $pitch);
@ -1766,12 +1700,6 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
return false;
}
public function setRotation(float $yaw, float $pitch){
$this->yaw = $yaw;
$this->pitch = $pitch;
$this->scheduleUpdate();
}
protected function checkChunks(){
if($this->chunk === null or ($this->chunk->getX() !== ($this->x >> 4) or $this->chunk->getZ() !== ($this->z >> 4))){
if($this->chunk !== null){
@ -1801,29 +1729,6 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
}
}
public function setPosition(Vector3 $pos){
if($this->closed){
return false;
}
if($pos instanceof Position and $pos->level !== null and $pos->level !== $this->level){
if($this->switchLevel($pos->getLevel()) === false){
return false;
}
}
$this->x = $pos->x;
$this->y = $pos->y;
$this->z = $pos->z;
$radius = $this->width / 2;
$this->boundingBox->setBounds($pos->x - $radius, $pos->y, $pos->z - $radius, $pos->x + $radius, $pos->y + $this->height, $pos->z + $radius);
$this->checkChunks();
return true;
}
protected function resetLastMovements(){
list($this->lastX, $this->lastY, $this->lastZ) = [$this->x, $this->y, $this->z];
list($this->lastYaw, $this->lastPitch) = [$this->yaw, $this->pitch];
@ -1857,11 +1762,6 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
return $this->onGround === true;
}
public function kill(){
$this->health = 0;
$this->scheduleUpdate();
}
/**
* @param Vector3|Position|Location $pos
* @param float|null $yaw
@ -1903,14 +1803,68 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
return false;
}
protected function switchLevel(Level $targetLevel) : bool{
if($this->closed){
return false;
}
if($this->isValid()){
$this->server->getPluginManager()->callEvent($ev = new EntityLevelChangeEvent($this, $this->level, $targetLevel));
if($ev->isCancelled()){
return false;
}
$this->level->removeEntity($this);
if($this->chunk !== null){
$this->chunk->removeEntity($this);
}
$this->despawnFromAll();
}
$this->setLevel($targetLevel);
$this->level->addEntity($this);
$this->chunk = null;
return true;
}
public function getId() : int{
return $this->id;
}
public function respawnToAll(){
foreach($this->hasSpawned as $key => $player){
unset($this->hasSpawned[$key]);
$this->spawnTo($player);
/**
* @return Player[]
*/
public function getViewers() : array{
return $this->hasSpawned;
}
/**
* Called by spawnTo() to send whatever packets needed to spawn the entity to the client.
*
* @param Player $player
*/
protected function sendSpawnPacket(Player $player) : void{
$pk = new AddEntityPacket();
$pk->entityRuntimeId = $this->getId();
$pk->type = static::NETWORK_ID;
$pk->position = $this->asVector3();
$pk->motion = $this->getMotion();
$pk->yaw = $this->yaw;
$pk->pitch = $this->pitch;
$pk->metadata = $this->dataProperties;
$player->dataPacket($pk);
}
/**
* @param Player $player
*/
public function spawnTo(Player $player){
if(!isset($this->hasSpawned[$player->getLoaderId()]) and isset($player->usedChunks[Level::chunkHash($this->chunk->getX(), $this->chunk->getZ())])){
$this->hasSpawned[$player->getLoaderId()] = $player;
$this->sendSpawnPacket($player);
}
}
@ -1925,6 +1879,28 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
}
}
public function respawnToAll(){
foreach($this->hasSpawned as $key => $player){
unset($this->hasSpawned[$key]);
$this->spawnTo($player);
}
}
/**
* @param Player $player
* @param bool $send
*/
public function despawnFrom(Player $player, bool $send = true){
if(isset($this->hasSpawned[$player->getLoaderId()])){
if($send){
$pk = new RemoveEntityPacket();
$pk->entityUniqueId = $this->id;
$player->dataPacket($pk);
}
unset($this->hasSpawned[$player->getLoaderId()]);
}
}
public function despawnFromAll(){
foreach($this->hasSpawned as $player){
$this->despawnFrom($player);
@ -2054,11 +2030,35 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
$this->setDataFlag(self::DATA_FLAGS, $flagId, $value, self::DATA_TYPE_LONG);
}
/**
* @param Player[]|Player $player
* @param array $data Properly formatted entity data, defaults to everything
*/
public function sendData($player, array $data = null){
if(!is_array($player)){
$player = [$player];
}
$pk = new SetEntityDataPacket();
$pk->entityRuntimeId = $this->getId();
$pk->metadata = $data ?? $this->dataProperties;
foreach($player as $p){
if($p === $this){
continue;
}
$p->dataPacket(clone $pk);
}
if($this instanceof Player){
$this->dataPacket($pk);
}
}
public function __destruct(){
$this->close();
}
public function setMetadata(string $metadataKey, MetadataValue $newMetadataValue){
$this->server->getEntityMetadata()->setMetadata($this, $metadataKey, $newMetadataValue);
}