39    private int $foodTickTimer = 0;
 
   41    private bool $enabled = 
true;
 
   43    public function __construct(
 
   46        $this->hungerAttr = self::fetchAttribute($entity, Attribute::HUNGER);
 
   47        $this->saturationAttr = self::fetchAttribute($entity, Attribute::SATURATION);
 
   48        $this->exhaustionAttr = self::fetchAttribute($entity, Attribute::EXHAUSTION);
 
   51    private static function fetchAttribute(
Entity $entity, 
string $attributeId) : 
Attribute{
 
   52        $attribute = AttributeFactory::getInstance()->mustGet($attributeId);
 
   53        $entity->getAttributeMap()->add($attribute);
 
   57    public function getFood() : 
float{
 
   58        return $this->hungerAttr->getValue();
 
   67    public function setFood(
float $new) : void{
 
   68        $old = $this->hungerAttr->getValue();
 
   69        $this->hungerAttr->setValue($new);
 
   72        foreach([17, 6, 0] as $bound){
 
   73            if(($old > $bound) !== ($new > $bound)){
 
   74                $this->foodTickTimer = 0;
 
 
   80    public function getMaxFood() : float{
 
   81        return $this->hungerAttr->getMaxValue();
 
   84    public function addFood(
float $amount) : void{
 
   85        $amount += $this->hungerAttr->getValue();
 
   86        $amount = max(min($amount, $this->hungerAttr->getMaxValue()), $this->hungerAttr->getMinValue());
 
   87        $this->setFood($amount);
 
   95        return $this->getFood() < $this->getMaxFood();
 
 
   98    public function getSaturation() : float{
 
   99        return $this->saturationAttr->getValue();
 
  109        $this->saturationAttr->setValue($saturation);
 
 
  112    public function addSaturation(
float $amount) : void{
 
  113        $this->saturationAttr->setValue($this->saturationAttr->getValue() + $amount, true);
 
  116    public function getExhaustion() : float{
 
  117        return $this->exhaustionAttr->getValue();
 
  125        $this->exhaustionAttr->setValue($exhaustion);
 
 
  133    public function exhaust(
float $amount, 
int $cause = EntityExhaustEvent::CAUSE_CUSTOM) : float{
 
  138        if(EntityExhaustEvent::hasHandlers()){
 
  141            if($ev->isCancelled()){
 
  144            $evAmount = $ev->getAmount();
 
  147        $exhaustion = $this->getExhaustion();
 
  148        $exhaustion += $evAmount;
 
  150        while($exhaustion >= 4.0){
 
  153            $saturation = $this->getSaturation();
 
  155                $saturation = max(0, $saturation - 1.0);
 
  156                $this->setSaturation($saturation);
 
  158                $food = $this->getFood();
 
  161                    $this->setFood(max($food, 0));
 
  165        $this->setExhaustion($exhaustion);
 
 
  170    public function getFoodTickTimer() : int{
 
  171        return $this->foodTickTimer;
 
  174    public function setFoodTickTimer(
int $foodTickTimer) : void{
 
  175        if($foodTickTimer < 0){
 
  176            throw new \InvalidArgumentException(
"Expected a non-negative value");
 
  178        $this->foodTickTimer = $foodTickTimer;
 
  181    public function tick(
int $tickDiff = 1) : void{
 
  182        if(!$this->entity->isAlive() || !$this->enabled){
 
  185        $food = $this->getFood();
 
  186        $health = $this->entity->getHealth();
 
  187        $difficulty = $this->entity->getWorld()->getDifficulty();
 
  189        $this->foodTickTimer += $tickDiff;
 
  190        if($this->foodTickTimer >= 80){
 
  191            $this->foodTickTimer = 0;
 
  194        if($difficulty === World::DIFFICULTY_PEACEFUL && $this->foodTickTimer % 10 === 0){
 
  195            if($food < $this->getMaxFood()){
 
  197                $food = $this->getFood();
 
  199            if($this->foodTickTimer % 20 === 0 && $health < $this->entity->getMaxHealth()){
 
  200                $this->entity->heal(
new EntityRegainHealthEvent($this->entity, 1, EntityRegainHealthEvent::CAUSE_SATURATION));
 
  204        if($this->foodTickTimer === 0){
 
  206                if($health < $this->entity->getMaxHealth()){
 
  207                    $this->entity->heal(
new EntityRegainHealthEvent($this->entity, 1, EntityRegainHealthEvent::CAUSE_SATURATION));
 
  208                    $this->exhaust(6.0, EntityExhaustEvent::CAUSE_HEALTH_REGEN);
 
  211                if(($difficulty === World::DIFFICULTY_EASY && $health > 10) || ($difficulty === World::DIFFICULTY_NORMAL && $health > 1) || $difficulty === World::DIFFICULTY_HARD){
 
  212                    $this->entity->attack(
new EntityDamageEvent($this->entity, EntityDamageEvent::CAUSE_STARVATION, 1));
 
  218            $this->entity->setSprinting(
false);
 
  222    public function isEnabled() : bool{
 
  223        return $this->enabled;
 
  226    public function setEnabled(
bool $enabled) : void{
 
  227        $this->enabled = $enabled;