mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-04-22 00:33:59 +00:00
Fixed the half-done hunger implementation, fixed lots of bugs related to hunger
- Fixed starvation doesn't deal any damage at all (Human->getFood() returns a float, not an int, === 0 won't work so great) - Added exhaustion for sprinting, walking, jumping and sprint-jumping as per MCPE (these use MCPE values, and yes MCPE does walking exhaustion!) - Fixed attributes don't get reset after player death - Added food and hunger regeneration in peaceful difficulty - Added API methods Living->jump() (motion isn't updated yet, so this won't actually do much if plugins try to use it) and Living->getJumpVelocity() TODO: implement exhaustion for swimming
This commit is contained in:
parent
00a226921c
commit
2204942338
@ -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){
|
||||
|
@ -165,6 +165,10 @@ class Attribute{
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function resetToDefault(){
|
||||
$this->setValue($this->getDefaultValue());
|
||||
}
|
||||
|
||||
public function getValue(){
|
||||
return $this->currentValue;
|
||||
}
|
||||
|
@ -38,6 +38,9 @@ class AttributeMap implements \ArrayAccess{
|
||||
return $this->attributes[$id] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Attribute[]
|
||||
*/
|
||||
public function getAll(): array{
|
||||
return $this->attributes;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user