public function parsePreset($preset) { $PRESETS = ["overworld" => "nsfv1;7,59x1,3x3,2;1;" . "spawn(radius=10 block=89)," . "dsq(min=50 max=85 water=65 off=100)," . "decoration(treecount=1,1 grasscount=5:0)", "plains" => "nsfv1;temperate;1;" . 'spawn(radius=10 block=48),' . "dsq(min=50 max=70 strata=50:52:54:56:70 water=56 dotsz=0.6)," . "decoration(treecount=1:1 grasscount=5:0 desertplant=0:0)", "ocean" => "nsfv1;temperate;0;" . 'spawn(radius=10 block=24),' . "dsq(min=24 max=90 water=60 strata=30:54:60:74:80 dotsz=0.8)," . "decoration(treecount=1:1 grasscount=5:0 desertplant=0:0)", "hills" => "nsfv1;temperate;1;" . 'spawn(radius=10 block=48),' . "dsq(min=24 max=90 water=30 strata=25:27:29:32:80 dotsz=0.7)," . "decoration(treecount=1:1 grasscount=5:0 desertplant=0:0)", "mountains" => "nsfv1;temperate;1;" . 'spawn(radius=10 block=48),' . "dsq(min=24 max=90 water=30 strata=25:27:29:32:55 dotsz=1.0 fn=exp fdat=2)," . "decoration(treecount=1:1 grasscount=5:0 desertplant=0:0)", "flatland" => "nsfv1;7,59x1,3x3,12:7,59x1,3x3,2;1;" . 'spawn(radius=10 block=48),' . "dsq(min=53 max=57 strata=55 water=55 dotsz=0.7)," . "decoration(treecount=2:1 grasscount=5:5 desertplant=0:0)", "hell" => "nsfv1;hell;8;" . 'spawn(radius=10 block=89),' . "dsq(min=40 max=80 water=55 waterblock=11 fn=exp fndat=1.7 hell=1)", "desert" => "nsfv1;arid;2;" . 'spawn(radius=10 block=24),' . "dsq(min=50 max=70 strata=1:2:52:65:68 water=51 dotsz=0.8)," . "decoration(desertplant=5:1)", "mesa" => "nsfv1;temperate;1;" . 'spawn(radius=10 block=48),' . "dsq(min=24 max=90 water=30 strata=25:27:29:32:60 dotsz=0.9 fn=exp fdat=0.5)," . "decoration(treecount=1:1 grasscount=5:0 desertplant=0:0)", "desert hills" => "nsfv1;arid;2;" . 'spawn(radius=10 block=24),' . "dsq(min=30 max=80 strata=1:2:32:60:68 water=32 dotsz=0.8 fn=exp fndat=1.5)," . "decoration(desertplant=2:1)"]; $STRATA = ["temperate" => '7,59x1,3x3,2x13:' . '7,59x1,5x3:' . '7,59x1,3x3,2x12:' . '7,59x1,5x3,2x24,3x12:' . '7,59x1,3x3,2,12:' . '7,59x1,3x4,1', "arid" => '7,59x1,3x3,2x13:' . '7,59x1,5x3:' . '7,59x1,3x3,2x12:' . '7,3x1,52x24,8x12:' . '7,30x1,30x24:' . '7,30x1,30x13', "hell" => '7,2x87,10x11,20x87']; if (!$preset) { $ids = array_keys($PRESETS); $preset = $ids[intval($this->random->nextFloat() * count($ids))]; unset($ids); } else { $this->random->nextFloat(); } //echo("[DEBUG] preset=$preset\n"); if (isset($PRESETS[$preset])) { $preset = $PRESETS[$preset]; } // Make sense of preset line... $preset = explode(";", $preset); $version = (int) $preset[0]; $blocks = @$preset[1]; if (isset($STRATA[$blocks])) { $blocks = $STRATA[$blocks]; } $biome = isset($preset[2]) ? $preset[2] : 1; $options = isset($preset[3]) ? $preset[3] : ""; // Parse block structure $this->structure = array(); $j = 0; foreach (explode(":", $blocks) as $blkset) { $matches = array(); preg_match_all('#(([0-9]{0,})x?([0-9]{1,3}:?[0-9]{0,2})),?#', $blkset, $matches); $y = 0; $this->structure[$j] = array(); foreach ($matches[3] as $i => $b) { $b = Item::fromString($b); $cnt = $matches[2][$i] === "" ? 1 : intval($matches[2][$i]); for ($cY = $y, $y += $cnt; $cY < $y; ++$cY) { $this->structure[$j][$cY] = [$b->getID(), $b->getDamage()]; } } ++$j; } ////////////////////////////////////////////////////////////////////// // additional options preg_match_all('#(([0-9a-z_]{1,})\\(?([0-9a-z_ =:\\.]{0,})\\)?),?#', $options, $matches); foreach ($matches[2] as $i => $option) { $params = true; if ($matches[3][$i] !== "") { $params = array(); $p = explode(" ", $matches[3][$i]); foreach ($p as $k) { $k = explode("=", $k); if (isset($k[1])) { $params[$k[0]] = $k[1]; } } } $this->cfg[$option] = $params; } }
public function __construct(Random $random, $octaves, $persistence, $expansion = 1) { $this->octaves = $octaves; $this->persistence = $persistence; $this->expansion = $expansion; $this->offsetX = $random->nextFloat() * 256; $this->offsetY = $random->nextFloat() * 256; $this->offsetZ = $random->nextFloat() * 256; for ($i = 0; $i < 512; ++$i) { $this->perm[$i] = 0; } for ($i = 0; $i < 256; ++$i) { $this->perm[$i] = $random->nextBoundedInt(256); } for ($i = 0; $i < 256; ++$i) { $pos = $random->nextBoundedInt(256 - $i) + $i; $old = $this->perm[$i]; $this->perm[$i] = $this->perm[$pos]; $this->perm[$pos] = $old; $this->perm[$i + 256] = $this->perm[$i]; } }
public function __construct(Random $random, $octaves, $frequency, $amplitude) { $this->octaves = $octaves; $this->frequency = $frequency; $this->amplitude = $amplitude; $this->offsetX = $random->nextFloat() * 256; $this->offsetY = $random->nextFloat() * 256; $this->offsetZ = $random->nextFloat() * 256; for ($i = 0; $i < 512; ++$i) { $this->perm[$i] = 0; } for ($i = 0; $i < 256; ++$i) { $this->perm[$i] = $random->nextRange(0, 255); } for ($i = 0; $i < 256; ++$i) { $pos = $random->nextRange(0, 255 - $i) + $i; $old = $this->perm[$i]; $this->perm[$i] = $this->perm[$pos]; $this->perm[$pos] = $old; $this->perm[$i + 256] = $this->perm[$i]; } }
public function __construct(Random $random, $octaves, $frequency, $amplitude, $lacunarity) { $this->octaves = $octaves; $this->frequency = $frequency; $this->lacunarity = $lacunarity; $this->amplitude = $amplitude; $this->offsetX = $random->nextFloat() * 256; $this->offsetY = $random->nextFloat() * 256; $this->offsetZ = $random->nextFloat() * 256; for ($i = 0; $i < 512; ++$i) { $this->perm[$i] = 0; } for ($i = 0; $i < 256; ++$i) { $this->perm[$i] = $random->nextBoundedInt(256); } for ($i = 0; $i < 256; ++$i) { $pos = $random->nextBoundedInt(256 - $i) + $i; $old = $this->perm[$i]; $this->perm[$i] = $this->perm[$pos]; $this->perm[$pos] = $old; $this->perm[$i + 256] = $this->perm[$i]; } }
public function generateChunk($chunkX, $chunkZ) { $this->random->setSeed(0xdeadbeef ^ $chunkX << 8 ^ $chunkZ ^ $this->level->getSeed()); $hills = []; $base = []; for ($z = 0; $z < 16; ++$z) { for ($x = 0; $x < 16; ++$x) { $i = ($z << 4) + $x; $hills[$i] = $this->noiseHills->noise2D($x + ($chunkX << 4), $z + ($chunkZ << 4), true); $base[$i] = $this->noiseBase->noise2D($x + ($chunkX << 4), $z + ($chunkZ << 4), true); if ($base[$i] < 0) { $base[$i] *= 0.5; } } } $chunk = $this->level->getChunk($chunkX, $chunkZ); for ($z = 0; $z < 16; ++$z) { for ($x = 0; $x < 16; ++$x) { $i = ($z << 4) + $x; $height = $this->worldHeight + $hills[$i] * 14 + $base[$i] * 7; $height = (int) $height; for ($y = 0; $y < 128; ++$y) { $diff = $height - $y; if ($y <= 4 and ($y === 0 or $this->random->nextFloat() < 0.75)) { $chunk->setBlockId($x, $y, $z, Block::BEDROCK); } elseif ($diff > 2) { $chunk->setBlockId($x, $y, $z, Block::STONE); } elseif ($diff > 0) { $chunk->setBlockId($x, $y, $z, Block::DIRT); } elseif ($y <= $this->waterHeight) { if ($this->waterHeight - $y <= 1 and $diff === 0) { $chunk->setBlockId($x, $y, $z, Block::SAND); } elseif ($diff === 0) { $chunk->setBlockId($x, $y, $z, Block::DIRT); } else { $chunk->setBlockId($x, $y, $z, Block::STILL_WATER); } } elseif ($diff === 0) { $chunk->setBlockId($x, $y, $z, Block::GRASS); } } } } }
private function getLeafGroupPoints(ChunkManager $level, $x, $y, $z) { $amount = $this->leafAmount * $this->totalHeight / 13; $groupsPerLayer = (int) (1.382 + $amount * $amount); if ($groupsPerLayer == 0) { $groupsPerLayer = 1; } $trunkTopY = $y + $this->trunkHeight; $groups = []; $groupY = $y + $this->totalHeight - $this->leafDistanceLimit; $groups[] = [new Vector3($x, $groupY, $z), $trunkTopY]; for ($currentLayer = (int) ($this->totalHeight - $this->leafDistanceLimit); $currentLayer >= 0; $currentLayer--) { $layerSize = $this->getRoughLayerSize($currentLayer); if ($layerSize < 0) { $groupY--; continue; } for ($count = 0; $count < $groupsPerLayer; $count++) { $scale = $this->widthScale * $layerSize * ($this->random->nextFloat() + 0.328); $randomOffset = Vector2::createRandomDirection($this->random)->multiply($scale); $groupX = (int) ($randomOffset->getX() + $x + 0.5); $groupZ = (int) ($randomOffset->getY() + $z + 0.5); $group = new Vector3($groupX, $groupY, $groupZ); if ($this->getAvailableBlockSpace($level, $group, $group->add(0, $this->leafDistanceLimit, 0)) != -1) { continue; } $xOff = (int) ($x - $groupX); $zOff = (int) ($z - $groupZ); $horizontalDistanceToTrunk = sqrt($xOff * $xOff + $zOff * $zOff); $verticalDistanceToTrunk = $horizontalDistanceToTrunk * $this->branchSlope; $yDiff = (int) ($groupY - $verticalDistanceToTrunk); if ($yDiff > $trunkTopY) { $base = $trunkTopY; } else { $base = $yDiff; } if ($this->getAvailableBlockSpace($level, new Vector3($x, $base, $z), $group) == -1) { $groups[] = [$group, $base]; } } $groupY--; } return $groups; }
public function populate(ChunkManager $level, $chunkX, $chunkZ, Random $random) { $this->level = $level; $amount = $random->nextRange(0, $this->randomAmount + 1) + $this->baseAmount; for ($i = 0; $i < $amount; ++$i) { $x = $random->nextRange($chunkX << 4, ($chunkX << 4) + 15); $z = $random->nextRange($chunkZ << 4, ($chunkZ << 4) + 15); $y = $this->getHighestWorkableBlock($x, $z); if ($y === -1) { continue; } if ($random->nextFloat() > 0.75) { $meta = Sapling::BIRCH; } else { $meta = Sapling::OAK; } ObjectTree::growTree($this->level, $x, $y, $z, $random, $meta); } }
public static function createRandomDirection(Random $random) { return VectorMath::getDirection2D($random->nextFloat() * 2 * pi()); }
public function generateChunk($chunkX, $chunkZ) { $this->random->setSeed(0.0 ^ $chunkX << 8 ^ $chunkZ ^ $this->level->getSeed()); $hills = []; $patches = []; $patchesSmall = []; $base = []; for ($z = 0; $z < 16; ++$z) { for ($x = 0; $x < 16; ++$x) { $i = ($z << 4) + $x; $hills[$i] = $this->noiseHills->noise2D($x + ($chunkX << 4), $z + ($chunkZ << 4), true); $patches[$i] = $this->noisePatches->noise2D($x + ($chunkX << 4), $z + ($chunkZ << 4), true); $patchesSmall[$i] = $this->noisePatchesSmall->noise2D($x + ($chunkX << 4), $z + ($chunkZ << 4), true); $base[$i] = $this->noiseBase->noise2D($x + ($chunkX << 4), $z + ($chunkZ << 4), true); if ($base[$i] < 0) { $base[$i] *= 0.5; } } } $chunk = $this->level->getChunk($chunkX, $chunkZ); for ($chunkY = 0; $chunkY < 8; ++$chunkY) { $startY = $chunkY << 4; $endY = $startY + 16; for ($z = 0; $z < 16; ++$z) { for ($x = 0; $x < 16; ++$x) { $i = ($z << 4) + $x; $height = $this->worldHeight + $hills[$i] * 14 + $base[$i] * 7; $height = (int) $height; for ($y = $startY; $y < $endY; ++$y) { $diff = $height - $y; if ($y <= 4 and ($y === 0 or $this->random->nextFloat() < 0.75)) { $chunk->setBlockId($x, $y, $z, Block::BEDROCK); } elseif ($diff > 2) { $chunk->setBlockId($x, $y, $z, Block::STONE); } elseif ($diff > 0) { if ($patches[$i] > 0.7) { $chunk->setBlockId($x, $y, $z, Block::STONE); } elseif ($patches[$i] < -0.8) { $chunk->setBlockId($x, $y, $z, Block::GRAVEL); } else { $chunk->setBlockId($x, $y, $z, Block::DIRT); } } elseif ($y <= $this->waterHeight) { if ($this->waterHeight - $y <= 1 and $diff === 0) { $chunk->setBlockId($x, $y, $z, Block::SAND); } elseif ($diff === 0) { if ($patchesSmall[$i] > 0.3) { $chunk->setBlockId($x, $y, $z, Block::GRAVEL); } elseif ($patchesSmall[$i] < -0.45) { $chunk->setBlockId($x, $y, $z, Block::SAND); } else { $chunk->setBlockId($x, $y, $z, Block::DIRT); } } else { $chunk->setBlockId($x, $y, $z, Block::STILL_WATER); } } elseif ($diff === 0) { if ($patches[$i] > 0.7) { $chunk->setBlockId($x, $y, $z, Block::STONE); } elseif ($patches[$i] < -0.8) { $chunk->setBlockId($x, $y, $z, Block::GRAVEL); } else { $chunk->setBlockId($x, $y, $z, Block::GRASS); } } } } } } }
private function generateCaveBranch(ChunkManager $level, Vector3 $chunk, Vector3 $target, $horizontalScale, $verticalScale, $horizontalAngle, $verticalAngle, int $startingNode, int $nodeAmount, Random $random) { $middle = new Vector3($chunk->getX() + 8, 0, $chunk->getZ() + 8); $horizontalOffset = 0; $verticalOffset = 0; if ($nodeAmount <= 0) { $size = 7 * 16; $nodeAmount = $size - $random->nextBoundedInt($size / 4); } $intersectionMode = $random->nextBoundedInt($nodeAmount / 2) + $nodeAmount / 4; $extraVerticalScale = $random->nextBoundedInt(6) == 0; if ($startingNode == -1) { $startingNode = $nodeAmount / 2; $lastNode = true; } else { $lastNode = false; } for (; $startingNode < $nodeAmount; $startingNode++) { $horizontalSize = 1.5 + sin($startingNode * pi() / $nodeAmount) * $horizontalScale; $verticalSize = $horizontalSize * $verticalScale; $target = $target->add(VectorMath::getDirection3D($horizontalAngle, $verticalAngle)); if ($extraVerticalScale) { $verticalAngle *= 0.92; } else { $verticalScale *= 0.7; } $verticalAngle += $verticalOffset * 0.1; $horizontalAngle += $horizontalOffset * 0.1; $verticalOffset *= 0.9; $horizontalOffset *= 0.75; $verticalOffset += ($random->nextFloat() - $random->nextFloat()) * $random->nextFloat() * 2; $horizontalOffset += ($random->nextFloat() - $random->nextFloat()) * $random->nextFloat() * 4; if (!$lastNode) { if ($startingNode == $intersectionMode and $horizontalScale > 1 and $nodeAmount > 0) { $this->generateCaveBranch($level, $chunk, $target, $random->nextFloat() * 0.5 + 0.5, 1, $horizontalAngle - pi() / 2, $verticalAngle / 3, $startingNode, $nodeAmount, new Random($random->nextInt())); $this->generateCaveBranch($level, $chunk, $target, $random->nextFloat() * 0.5 + 0.5, 1, $horizontalAngle - pi() / 2, $verticalAngle / 3, $startingNode, $nodeAmount, new Random($random->nextInt())); return; } if ($random->nextBoundedInt(4) == 0) { continue; } } $xOffset = $target->getX() - $middle->getX(); $zOffset = $target->getZ() - $middle->getZ(); $nodesLeft = $nodeAmount - $startingNode; $offsetHorizontalScale = $horizontalScale + 18; if ($xOffset * $xOffset + $zOffset * $zOffset - $nodesLeft * $nodesLeft > $offsetHorizontalScale * $offsetHorizontalScale) { return; } if ($target->getX() < $middle->getX() - 16 - $horizontalSize * 2 or $target->getZ() < $middle->getZ() - 16 - $horizontalSize * 2 or $target->getX() > $middle->getX() + 16 + $horizontalSize * 2 or $target->getZ() > $middle->getZ() + 16 + $horizontalSize * 2) { continue; } $start = new Vector3(floor($target->getX() - $horizontalSize) - $chunk->getX() - 1, floor($target->getY() - $verticalSize) - 1, floor($target->getZ() - $horizontalSize) - $chunk->getZ() - 1); $end = new Vector3(floor($target->getX() + $horizontalSize) - $chunk->getX() + 1, floor($target->getY() + $verticalSize) + 1, floor($target->getZ() + $horizontalSize) - $chunk->getZ() + 1); $node = new CaveNode($level, $chunk, $start, $end, $target, $verticalSize, $horizontalSize); if ($node->canPlace()) { $node->place(); } if ($lastNode) { break; } } }