46    private int $waterHeight = 62;
 
   48    private array $populators = [];
 
   50    private array $generationPopulators = [];
 
   59        parent::__construct($seed, $preset);
 
   63        $this->noiseBase = 
new Simplex($this->random, 4, 1 / 4, 1 / 32);
 
   64        $this->random->setSeed($this->seed);
 
   66        $this->selector = 
new class($this->random) extends 
BiomeSelector{
 
   67            protected function lookup(
float $temperature, 
float $rainfall) : 
int{
 
   69                    if($temperature < 0.7){
 
   70                        return BiomeIds::OCEAN;
 
   71                    }elseif($temperature < 0.85){
 
   72                        return BiomeIds::RIVER;
 
   74                        return BiomeIds::SWAMPLAND;
 
   76                }elseif($rainfall < 0.60){
 
   77                    if($temperature < 0.25){
 
   78                        return BiomeIds::ICE_PLAINS;
 
   79                    }elseif($temperature < 0.75){
 
   80                        return BiomeIds::PLAINS;
 
   82                        return BiomeIds::DESERT;
 
   84                }elseif($rainfall < 0.80){
 
   85                    if($temperature < 0.25){
 
   86                        return BiomeIds::TAIGA;
 
   87                    }elseif($temperature < 0.75){
 
   88                        return BiomeIds::FOREST;
 
   90                        return BiomeIds::BIRCH_FOREST;
 
   93                    if($temperature < 0.20){
 
   94                        return BiomeIds::EXTREME_HILLS;
 
   95                    }elseif($temperature < 0.40){
 
   96                        return BiomeIds::EXTREME_HILLS_EDGE;
 
   98                        return BiomeIds::RIVER;
 
  104        $this->selector->recalculate();
 
  107        $this->generationPopulators[] = $cover;
 
  110        $stone = VanillaBlocks::STONE();
 
  112            new OreType(VanillaBlocks::COAL_ORE(), $stone, 20, 16, 0, 128),
 
  113            new OreType(VanillaBlocks::IRON_ORE(), $stone, 20, 8, 0, 64),
 
  114            new OreType(VanillaBlocks::REDSTONE_ORE(), $stone, 8, 7, 0, 16),
 
  115            new OreType(VanillaBlocks::LAPIS_LAZULI_ORE(), $stone, 1, 6, 0, 32),
 
  116            new OreType(VanillaBlocks::GOLD_ORE(), $stone, 2, 8, 0, 32),
 
  117            new OreType(VanillaBlocks::DIAMOND_ORE(), $stone, 1, 7, 0, 16),
 
  118            new OreType(VanillaBlocks::DIRT(), $stone, 20, 32, 0, 128),
 
  119            new OreType(VanillaBlocks::GRAVEL(), $stone, 10, 16, 0, 128)
 
  121        $this->populators[] = $ores;
 
 
  124    private function pickBiome(
int $x, 
int $z) : 
Biome{
 
  125        $hash = $x * 2345803 ^ $z * 9236449 ^ $this->seed;
 
  126        $hash *= $hash + 223;
 
  130        $hash = (int) fmod($hash, 2.0 ** 63);
 
  131        $xNoise = $hash >> 20 & 3;
 
  132        $zNoise = $hash >> 22 & 3;
 
  140        return $this->selector->pickBiome($x + $xNoise - 1, $z + $zNoise - 1);
 
  143    public function generateChunk(ChunkManager $world, 
int $chunkX, 
int $chunkZ) : void{
 
  144        $this->random->setSeed(0xdeadbeef ^ ($chunkX << 8) ^ $chunkZ ^ $this->seed);
 
  146        $noise = $this->noiseBase->getFastNoise3D(Chunk::EDGE_LENGTH, 128, Chunk::EDGE_LENGTH, 4, 8, 4, $chunkX * Chunk::EDGE_LENGTH, 0, $chunkZ * Chunk::EDGE_LENGTH);
 
  149        $chunk = $world->getChunk($chunkX, $chunkZ) ?? 
throw new \InvalidArgumentException(
"Chunk $chunkX $chunkZ does not yet exist");
 
  153        $bedrock = VanillaBlocks::BEDROCK()->getStateId();
 
  154        $stillWater = VanillaBlocks::WATER()->getStateId();
 
  155        $stone = VanillaBlocks::STONE()->getStateId();
 
  157        $baseX = $chunkX * Chunk::EDGE_LENGTH;
 
  158        $baseZ = $chunkZ * Chunk::EDGE_LENGTH;
 
  159        for($x = 0; $x < Chunk::EDGE_LENGTH; ++$x){
 
  160            $absoluteX = $baseX + $x;
 
  161            for($z = 0; $z < Chunk::EDGE_LENGTH; ++$z){
 
  162                $absoluteZ = $baseZ + $z;
 
  167                $biome = $this->pickBiome($absoluteX, $absoluteZ);
 
  168                for($y = World::Y_MIN; $y < World::Y_MAX; $y++){
 
  169                    $chunk->setBiomeId($x, $y, $z, $biome->getId());
 
  172                for($sx = -$this->gaussian->smoothSize; $sx <= $this->gaussian->smoothSize; ++$sx){
 
  173                    for($sz = -$this->gaussian->smoothSize; $sz <= $this->gaussian->smoothSize; ++$sz){
 
  175                        $weight = $this->gaussian->kernel[$sx + $this->gaussian->smoothSize][$sz + $this->gaussian->smoothSize];
 
  177                        if($sx === 0 && $sz === 0){
 
  181                            if(isset($biomeCache[$index])){
 
  182                                $adjacent = $biomeCache[$index];
 
  184                                $biomeCache[$index] = $adjacent = $this->pickBiome($absoluteX + $sx, $absoluteZ + $sz);
 
  188                        $minSum += ($adjacent->getMinElevation() - 1) * $weight;
 
  189                        $maxSum += $adjacent->getMaxElevation() * $weight;
 
  191                        $weightSum += $weight;
 
  195                $minSum /= $weightSum;
 
  196                $maxSum /= $weightSum;
 
  198                $smoothHeight = ($maxSum - $minSum) / 2;
 
  200                for($y = 0; $y < 128; ++$y){
 
  202                        $chunk->setBlockStateId($x, $y, $z, $bedrock);
 
  205                    $noiseValue = $noise[$x][$z][$y] - 1 / $smoothHeight * ($y - $smoothHeight - $minSum);
 
  208                        $chunk->setBlockStateId($x, $y, $z, $stone);
 
  209                    }elseif($y <= $this->waterHeight){
 
  210                        $chunk->setBlockStateId($x, $y, $z, $stillWater);
 
  216        foreach($this->generationPopulators as $populator){
 
  217            $populator->populate($world, $chunkX, $chunkZ, $this->random);
 
  221    public function populateChunk(ChunkManager $world, 
int $chunkX, 
int $chunkZ) : void{
 
  222        $this->random->setSeed(0xdeadbeef ^ ($chunkX << 8) ^ $chunkZ ^ $this->seed);
 
  223        foreach($this->populators as $populator){
 
  224            $populator->populate($world, $chunkX, $chunkZ, $this->random);
 
  227        $chunk = $world->getChunk($chunkX, $chunkZ);
 
  228        $biome = BiomeRegistry::getInstance()->getBiome($chunk->getBiomeId(7, 7, 7));
 
  229        $biome->populateChunk($world, $chunkX, $chunkZ, $this->random);