[3] */ private $blockQueue; private $currentBlock = 0; /** @var Block */ private $currentBlockObject = null; private $currentDistance = 0; private $maxDistanceInt = 0; private $secondError; private $thirdError; private $secondStep; private $thirdStep; private $mainFace; private $secondFace; private $thirdFace; public function __construct(Level $level, Vector3 $start, Vector3 $direction, $yOffset = 0, $maxDistance = 0){ $this->level = $level; $this->maxDistance = (int) $maxDistance; $this->blockQueue = new \SplFixedArray(3); $startClone = new Vector3($start->x, $start->y, $start->z); $startClone->y += $yOffset; $this->currentDistance = 0; $mainDirection = 0; $secondDirection = 0; $thirdDirection = 0; $mainPosition = 0; $secondPosition = 0; $thirdPosition = 0; $pos = new Vector3($startClone->x, $startClone->y, $startClone->z); $startBlock = $this->level->getBlock(new Vector3(floor($pos->x), floor($pos->y), floor($pos->z))); if($this->getXLength($direction) > $mainDirection){ $this->mainFace = $this->getXFace($direction); $mainDirection = $this->getXLength($direction); $mainPosition = $this->getXPosition($direction, $startClone, $startBlock); $this->secondFace = $this->getYFace($direction); $secondDirection = $this->getYLength($direction); $secondPosition = $this->getYPosition($direction, $startClone, $startBlock); $this->thirdFace = $this->getZFace($direction); $thirdDirection = $this->getZLength($direction); $thirdPosition = $this->getZPosition($direction, $startClone, $startBlock); } if($this->getYLength($direction) > $mainDirection){ $this->mainFace = $this->getYFace($direction); $mainDirection = $this->getYLength($direction); $mainPosition = $this->getYPosition($direction, $startClone, $startBlock); $this->secondFace = $this->getZFace($direction); $secondDirection = $this->getZLength($direction); $secondPosition = $this->getZPosition($direction, $startClone, $startBlock); $this->thirdFace = $this->getXFace($direction); $thirdDirection = $this->getXLength($direction); $thirdPosition = $this->getXPosition($direction, $startClone, $startBlock); } if($this->getZLength($direction) > $mainDirection){ $this->mainFace = $this->getZFace($direction); $mainDirection = $this->getZLength($direction); $mainPosition = $this->getZPosition($direction, $startClone, $startBlock); $this->secondFace = $this->getXFace($direction); $secondDirection = $this->getXLength($direction); $secondPosition = $this->getXPosition($direction, $startClone, $startBlock); $this->thirdFace = $this->getYFace($direction); $thirdDirection = $this->getYLength($direction); $thirdPosition = $this->getYPosition($direction, $startClone, $startBlock); } $d = $mainPosition / $mainDirection; $secondd = $secondPosition - $secondDirection * $d; $thirdd = $thirdPosition - $thirdDirection * $d; $this->secondError = floor($secondd * self::$gridSize); $this->secondStep = round($secondDirection / $mainDirection * self::$gridSize); $this->thirdError = floor($thirdd * self::$gridSize); $this->thirdStep = round($thirdDirection / $mainDirection * self::$gridSize); if($this->secondError + $this->secondStep <= 0){ $this->secondError = -$this->secondStep + 1; } if($this->thirdError + $this->thirdStep <= 0){ $this->thirdError = -$this->thirdStep + 1; } $lastBlock = $startBlock->getSide(Vector3::getOppositeSide($this->mainFace)); if($this->secondError < 0){ $this->secondError += self::$gridSize; $lastBlock = $lastBlock->getSide(Vector3::getOppositeSide($this->secondFace)); } if($this->thirdError < 0){ $this->thirdError += self::$gridSize; $lastBlock = $lastBlock->getSide(Vector3::getOppositeSide($this->thirdFace)); } $this->secondError -= self::$gridSize; $this->thirdError -= self::$gridSize; $this->blockQueue[0] = $lastBlock; $this->currentBlock = -1; $this->scan(); $startBlockFound = false; for($cnt = $this->currentBlock; $cnt >= 0; --$cnt){ if($this->blockEquals($this->blockQueue[$cnt], $startBlock)){ $this->currentBlock = $cnt; $startBlockFound = true; break; } } if(!$startBlockFound){ throw new \InvalidStateException("Start block missed in BlockIterator"); } $this->maxDistanceInt = round($maxDistance / (sqrt($mainDirection ** 2 + $secondDirection ** 2 + $thirdDirection ** 2) / $mainDirection)); } private function blockEquals(Block $a, Block $b){ return $a->x === $b->x and $a->y === $b->y and $a->z === $b->z; } private function getXFace(Vector3 $direction){ return (($direction->x) > 0) ? Vector3::SIDE_EAST : Vector3::SIDE_WEST; } private function getYFace(Vector3 $direction){ return (($direction->y) > 0) ? Vector3::SIDE_UP : Vector3::SIDE_DOWN; } private function getZFace(Vector3 $direction){ return (($direction->z) > 0) ? Vector3::SIDE_SOUTH : Vector3::SIDE_NORTH; } private function getXLength(Vector3 $direction){ return abs($direction->x); } private function getYLength(Vector3 $direction){ return abs($direction->y); } private function getZLength(Vector3 $direction){ return abs($direction->z); } private function getPosition($direction, $position, $blockPosition){ return $direction > 0 ? ($position - $blockPosition) : ($blockPosition + 1 - $position); } private function getXPosition(Vector3 $direction, Vector3 $position, Block $block){ return $this->getPosition($direction->x, $position->x, $block->x); } private function getYPosition(Vector3 $direction, Vector3 $position, Block $block){ return $this->getPosition($direction->y, $position->y, $block->y); } private function getZPosition(Vector3 $direction, Vector3 $position, Block $block){ return $this->getPosition($direction->z, $position->z, $block->z); } public function next(){ $this->scan(); if($this->currentBlock <= -1){ throw new \OutOfBoundsException; }else{ $this->currentBlockObject = $this->blockQueue[$this->currentBlock--]; } } /** * @return Block * * @throws \OutOfBoundsException */ public function current(){ if($this->currentBlockObject === null){ throw new \OutOfBoundsException; } return $this->currentBlockObject; } public function rewind(){ throw new \InvalidStateException("BlockIterator doesn't support rewind()"); } public function key(){ return $this->currentBlock - 1; } public function valid(){ $this->scan(); return $this->currentBlock !== -1; } private function scan(){ if($this->currentBlock >= 0){ return; } if($this->maxDistance !== 0 and $this->currentDistance > $this->maxDistanceInt){ $this->end = true; return; } if($this->end){ return; } ++$this->currentDistance; $this->secondError += $this->secondStep; $this->thirdError += $this->thirdStep; if($this->secondError > 0 and $this->thirdError > 0){ $this->blockQueue[2] = $this->blockQueue[0]->getSide($this->mainFace); if(($this->secondStep * $this->thirdError) < ($this->thirdStep * $this->secondError)){ $this->blockQueue[1] = $this->blockQueue[2]->getSide($this->secondFace); $this->blockQueue[0] = $this->blockQueue[1]->getSide($this->thirdFace); }else{ $this->blockQueue[1] = $this->blockQueue[2]->getSide($this->thirdFace); $this->blockQueue[0] = $this->blockQueue[1]->getSide($this->secondFace); } $this->thirdError -= self::$gridSize; $this->secondError -= self::$gridSize; $this->currentBlock = 2; }elseif($this->secondError > 0){ $this->blockQueue[1] = $this->blockQueue[0]->getSide($this->mainFace); $this->blockQueue[0] = $this->blockQueue[1]->getSide($this->secondFace); $this->secondError -= self::$gridSize; $this->currentBlock = 1; }elseif($this->thirdError > 0){ $this->blockQueue[1] = $this->blockQueue[0]->getSide($this->mainFace); $this->blockQueue[0] = $this->blockQueue[1]->getSide($this->thirdFace); $this->thirdError -= self::$gridSize; $this->currentBlock = 1; }else{ $this->blockQueue[0] = $this->blockQueue[0]->getSide($this->mainFace); $this->currentBlock = 0; } } }