boundedInt(2, 0, self::MAX_AGE, $this->age); } public function getAge() : int{ return $this->age; } /** @return $this */ public function setAge(int $age) : self{ if($age < 0 || $age > self::MAX_AGE){ throw new \InvalidArgumentException("Age must be in range 0 ... " . self::MAX_AGE); } $this->age = $age; return $this; } public function onNearbyBlockChange() : void{ $world = $this->position->getWorld(); if(!$this->checkAdjacentBlocks(2)){ $world->useBreakOn($this->position); }else{ $world->scheduleDelayedBlockUpdate($this->position, mt_rand(20, 40)); } } public function onRandomTick() : void{ $world = $this->position->getWorld(); if((!$this->checkAdjacentBlocks(4) || mt_rand(0, 2) === 0) && $world->getHighestAdjacentFullLightAt($this->position->x, $this->position->y, $this->position->z) >= 12 - $this->age){ if($this->tryMelt()){ foreach($this->getAllSides() as $block){ if($block instanceof FrostedIce){ $block->tryMelt(); } } } }else{ $world->scheduleDelayedBlockUpdate($this->position, mt_rand(20, 40)); } } public function onScheduledUpdate() : void{ $this->onRandomTick(); } private function checkAdjacentBlocks(int $requirement) : bool{ $found = 0; for($x = -1; $x <= 1; ++$x){ for($z = -1; $z <= 1; ++$z){ if($x === 0 && $z === 0){ continue; } if( $this->position->getWorld()->getBlockAt($this->position->x + $x, $this->position->y, $this->position->z + $z) instanceof FrostedIce && ++$found >= $requirement ){ return true; } } } return false; } /** * Updates the age of the ice, destroying it if appropriate. * * @return bool Whether the ice was destroyed. */ private function tryMelt() : bool{ $world = $this->position->getWorld(); if($this->age >= self::MAX_AGE){ $ev = new BlockMeltEvent($this, VanillaBlocks::WATER()); $ev->call(); if(!$ev->isCancelled()){ $world->setBlock($this->position, $ev->getNewState()); } return true; } $this->age++; $world->setBlock($this->position, $this); $world->scheduleDelayedBlockUpdate($this->position, mt_rand(20, 40)); return false; } }