--$x, Facing::EAST => ++$x, Facing::NORTH => --$z, Facing::SOUTH => ++$z }; if(!isset($this->flowCostVisited[$hash = World::blockHash($x, $y, $z)])){ if(!$this->world->isInWorld($x, $y, $z) || !$this->canFlowInto($this->world->getBlockAt($x, $y, $z))){ $this->flowCostVisited[$hash] = self::BLOCKED; }elseif($this->world->getBlockAt($x, $y - 1, $z)->canBeFlowedInto()){ $this->flowCostVisited[$hash] = self::CAN_FLOW_DOWN; }else{ $this->flowCostVisited[$hash] = self::CAN_FLOW; } } $status = $this->flowCostVisited[$hash]; if($status === self::BLOCKED){ continue; }elseif($status === self::CAN_FLOW_DOWN){ return $accumulatedCost; } if($accumulatedCost >= $maxCost){ continue; } $realCost = $this->calculateFlowCost($x, $y, $z, $accumulatedCost + 1, $maxCost, $originOpposite, Facing::opposite($j)); if($realCost < $cost){ $cost = $realCost; } } return $cost; } /** * @return int[] */ public function getOptimalFlowDirections(int $originX, int $originY, int $originZ) : array{ $flowCost = array_fill(0, 4, 1000); $maxCost = intdiv(4, $this->flowDecayPerBlock); foreach(Facing::HORIZONTAL as $j){ $x = $originX; $y = $originY; $z = $originZ; match($j){ Facing::WEST => --$x, Facing::EAST => ++$x, Facing::NORTH => --$z, Facing::SOUTH => ++$z }; if(!$this->world->isInWorld($x, $y, $z) || !$this->canFlowInto($this->world->getBlockAt($x, $y, $z))){ $this->flowCostVisited[World::blockHash($x, $y, $z)] = self::BLOCKED; }elseif($this->world->getBlockAt($x, $y - 1, $z)->canBeFlowedInto()){ $this->flowCostVisited[World::blockHash($x, $y, $z)] = self::CAN_FLOW_DOWN; $flowCost[$j] = $maxCost = 0; }elseif($maxCost > 0){ $this->flowCostVisited[World::blockHash($x, $y, $z)] = self::CAN_FLOW; $opposite = Facing::opposite($j); $flowCost[$j] = $this->calculateFlowCost($x, $y, $z, 1, $maxCost, $opposite, $opposite); $maxCost = min($maxCost, $flowCost[$j]); } } $this->flowCostVisited = []; $minCost = min($flowCost); $isOptimalFlowDirection = []; foreach($flowCost as $facing => $cost){ if($cost === $minCost){ $isOptimalFlowDirection[] = $facing; } } return $isOptimalFlowDirection; } private function canFlowInto(Block $block) : bool{ return ($this->canFlowInto)($block); } }