diff --git a/src/pocketmine/Player.php b/src/pocketmine/Player.php index 4763c0113..ad6f7b3ed 100644 --- a/src/pocketmine/Player.php +++ b/src/pocketmine/Player.php @@ -1566,6 +1566,15 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade $this->teleport($ev->getTo()); }else{ $this->level->addEntityMovement($this->x >> 4, $this->z >> 4, $this->getId(), $this->x, $this->y + $this->getEyeHeight(), $this->z, $this->yaw, $this->pitch, $this->yaw); + + $distance = $from->distance($to); + + //TODO: check swimming (adds 0.015 exhaustion in MCPE) + if($this->isSprinting()){ + $this->exhaust(0.1 * $distance, PlayerExhaustEvent::CAUSE_SPRINTING); + }else{ + $this->exhaust(0.01 * $distance, PlayerExhaustEvent::CAUSE_WALKING); + } } } } @@ -2675,6 +2684,10 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade $this->removeAllEffects(); $this->setHealth($this->getMaxHealth()); + foreach($this->attributeMap->getAll() as $attr){ + $attr->resetToDefault(); + } + $this->sendData($this); $this->sendSettings(); @@ -2685,6 +2698,7 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade $this->scheduleUpdate(); break; case PlayerActionPacket::ACTION_JUMP: + $this->jump(); return true; case PlayerActionPacket::ACTION_START_SPRINT: $ev = new PlayerToggleSprintEvent($this, true); @@ -3684,6 +3698,17 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade return; } + parent::kill(); + + $pk = new RespawnPacket(); + $pos = $this->getSpawn(); + $pk->x = $pos->x; + $pk->y = $pos->y; + $pk->z = $pos->z; + $this->dataPacket($pk); + } + + protected function callDeathEvent(){ $message = "death.attack.generic"; $params = [ @@ -3793,10 +3818,9 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade break; default: + break; } - Entity::kill(); - $this->server->getPluginManager()->callEvent($ev = new PlayerDeathEvent($this, $this->getDrops(), new TranslationContainer($message, $params))); if(!$ev->getKeepInventory()){ @@ -3814,13 +3838,6 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade if($ev->getDeathMessage() != ""){ $this->server->broadcast($ev->getDeathMessage(), Server::BROADCAST_CHANNEL_USERS); } - - $pk = new RespawnPacket(); - $pos = $this->getSpawn(); - $pk->x = $pos->x; - $pk->y = $pos->y; - $pk->z = $pos->z; - $this->dataPacket($pk); } public function attack($damage, EntityDamageEvent $source){ diff --git a/src/pocketmine/entity/Attribute.php b/src/pocketmine/entity/Attribute.php index be5a6cfae..c48534c63 100644 --- a/src/pocketmine/entity/Attribute.php +++ b/src/pocketmine/entity/Attribute.php @@ -165,6 +165,10 @@ class Attribute{ return $this; } + public function resetToDefault(){ + $this->setValue($this->getDefaultValue()); + } + public function getValue(){ return $this->currentValue; } diff --git a/src/pocketmine/entity/AttributeMap.php b/src/pocketmine/entity/AttributeMap.php index cdf821c52..b74492f08 100644 --- a/src/pocketmine/entity/AttributeMap.php +++ b/src/pocketmine/entity/AttributeMap.php @@ -38,6 +38,9 @@ class AttributeMap implements \ArrayAccess{ return $this->attributes[$id] ?? null; } + /** + * @return Attribute[] + */ public function getAll(): array{ return $this->attributes; } diff --git a/src/pocketmine/entity/Human.php b/src/pocketmine/entity/Human.php index 732dd23f8..5d8db656c 100644 --- a/src/pocketmine/entity/Human.php +++ b/src/pocketmine/entity/Human.php @@ -99,6 +99,15 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{ $this->skinId = $skinId; } + public function jump(){ + parent::jump(); + if($this->isSprinting()){ + $this->exhaust(0.8, PlayerExhaustEvent::CAUSE_SPRINT_JUMPING); + }else{ + $this->exhaust(0.2, PlayerExhaustEvent::CAUSE_JUMPING); + } + } + public function getFood() : float{ return $this->attributeMap->getAttribute(Attribute::HUNGER)->getValue(); } @@ -355,31 +364,35 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{ if($this->isAlive()){ $food = $this->getFood(); $health = $this->getHealth(); - if($food >= 18){ - $this->foodTickTimer++; - if($this->foodTickTimer >= 80 and $health < $this->getMaxHealth()){ - $this->heal(1, new EntityRegainHealthEvent($this, 1, EntityRegainHealthEvent::CAUSE_SATURATION)); - $this->exhaust(3.0, PlayerExhaustEvent::CAUSE_HEALTH_REGEN); - $this->foodTickTimer = 0; + $difficulty = $this->server->getDifficulty(); + $this->foodTickTimer++; + if($this->foodTickTimer >= 80){ + $this->foodTickTimer = 0; + } + + if($difficulty === 0 and $this->foodTickTimer % 10 === 0){ //Peaceful + if($food < 20){ + $this->addFood(1.0); } - }elseif($food === 0){ - $this->foodTickTimer++; - if($this->foodTickTimer >= 80){ - $diff = $this->server->getDifficulty(); - $can = false; - if($diff === 1){ - $can = $health > 10; - }elseif($diff === 2){ - $can = $health > 1; - }elseif($diff === 3){ - $can = true; + if($this->foodTickTimer % 20 === 0 and $health < $this->getMaxHealth()){ + $this->heal(1, new EntityRegainHealthEvent($this, 1, EntityRegainHealthEvent::CAUSE_SATURATION)); + } + } + + if($this->foodTickTimer === 0){ + if($food >= 18){ + if($health < $this->getMaxHealth()){ + $this->heal(1, new EntityRegainHealthEvent($this, 1, EntityRegainHealthEvent::CAUSE_SATURATION)); + $this->exhaust(3.0, PlayerExhaustEvent::CAUSE_HEALTH_REGEN); } - if($can){ + }elseif($food <= 0){ + if(($difficulty === 1 and $health > 10) or ($difficulty === 2 and $health > 1) or $difficulty === 3){ $this->attack(1, new EntityDamageEvent($this, EntityDamageEvent::CAUSE_STARVATION, 1)); } } } + if($food <= 6){ if($this->isSprinting()){ $this->setSprinting(false); diff --git a/src/pocketmine/entity/Living.php b/src/pocketmine/entity/Living.php index 7a0a93e91..985b4fe3a 100644 --- a/src/pocketmine/entity/Living.php +++ b/src/pocketmine/entity/Living.php @@ -43,6 +43,8 @@ abstract class Living extends Entity implements Damageable{ protected $invisible = false; + protected $jumpVelocity = 0.42; + protected function initEntity(){ parent::initEntity(); @@ -115,6 +117,23 @@ abstract class Living extends Entity implements Damageable{ $this->attackTime = 0; } + /** + * Returns the initial upwards velocity of a jumping entity in blocks/tick, including additional velocity due to effects. + * @return float + */ + public function getJumpVelocity() : float{ + return $this->jumpVelocity + ($this->hasEffect(Effect::JUMP) ? (($this->getEffect(Effect::JUMP)->getAmplifier() + 1) / 10) : 0); + } + + /** + * Called when the entity jumps from the ground. This method adds upwards velocity to the entity. + */ + public function jump(){ + if($this->onGround){ + $this->motionY = $this->getJumpVelocity(); //Y motion should already be 0 if we're jumping from the ground. + } + } + public function attack($damage, EntityDamageEvent $source){ if($this->attackTime > 0 or $this->noDamageTicks > 0){ $lastCause = $this->getLastDamageCause(); @@ -183,6 +202,10 @@ abstract class Living extends Entity implements Damageable{ return; } parent::kill(); + $this->callDeathEvent(); + } + + protected function callDeathEvent(){ $this->server->getPluginManager()->callEvent($ev = new EntityDeathEvent($this, $this->getDrops())); foreach($ev->getDrops() as $item){ $this->getLevel()->dropItem($this, $item); diff --git a/src/pocketmine/event/player/PlayerExhaustEvent.php b/src/pocketmine/event/player/PlayerExhaustEvent.php index 623b5fdf4..747988fb5 100644 --- a/src/pocketmine/event/player/PlayerExhaustEvent.php +++ b/src/pocketmine/event/player/PlayerExhaustEvent.php @@ -34,19 +34,21 @@ class PlayerExhaustEvent extends PlayerEvent implements Cancellable{ const CAUSE_HEALTH_REGEN = 4; const CAUSE_POTION = 5; const CAUSE_WALKING = 6; - const CAUSE_SNEAKING = 7; + const CAUSE_SPRINTING = 7; const CAUSE_SWIMMING = 8; - const CAUSE_JUMPING = 10; + const CAUSE_JUMPING = 9; + const CAUSE_SPRINT_JUMPING = 10; const CAUSE_CUSTOM = 11; - const CAUSE_FLAG_SPRINT = 0x10000; - /** @var float */ private $amount; + /** @var int */ + private $cause; public function __construct(Human $human, float $amount, int $cause){ $this->player = $human; $this->amount = $amount; + $this->cause = $cause; } /** @@ -63,4 +65,12 @@ class PlayerExhaustEvent extends PlayerEvent implements Cancellable{ public function setAmount(float $amount){ $this->amount = $amount; } + + /** + * Returns an int cause of the exhaustion - one of the constants at the top of this class. + * @return int + */ + public function getCause() : int{ + return $this->cause; + } }