├── .gitignore ├── README.md ├── plugin.yml └── src └── BlockHorizons └── BlockGenerator ├── Loader.php ├── biomes ├── CustomBiome.php ├── CustomBiomeSelector.php ├── DebugBiomeSelector.php ├── EmptyBiome.php ├── impl │ ├── UnknownBiome.php │ ├── beach │ │ ├── BeachBiome.php │ │ └── ColdBeachBiome.php │ ├── desert │ │ ├── DesertBiome.php │ │ ├── DesertHillsBiome.php │ │ └── DesertMBiome.php │ ├── extremehills │ │ ├── ExtremeHillsBiome.php │ │ ├── ExtremeHillsEdgeBiome.php │ │ ├── ExtremeHillsMBiome.php │ │ ├── ExtremeHillsPlusBiome.php │ │ ├── ExtremeHillsPlusMBiome.php │ │ └── StoneBeachBiome.php │ ├── forest │ │ ├── FlowerForestBiome.php │ │ ├── ForestBiome.php │ │ └── ForestHillsBiome.php │ ├── iceplains │ │ ├── IcePlainsBiome.php │ │ └── IcePlainsSpikesBiome.php │ ├── jungle │ │ ├── JungleBiome.php │ │ ├── JungleEdgeBiome.php │ │ ├── JungleEdgeMBiome.php │ │ ├── JungleHillsBiome.php │ │ └── JungleMBiome.php │ ├── mesa │ │ ├── MesaBiome.php │ │ ├── MesaBryceBiome.php │ │ ├── MesaPlateauBiome.php │ │ ├── MesaPlateauFBiome.php │ │ ├── MesaPlateauFMBiome.php │ │ └── MesaPlateauMBiome.php │ ├── mushroom │ │ ├── MushroomIslandBiome.php │ │ └── MushroomIslandShoreBiome.php │ ├── ocean │ │ ├── DeepOceanBiome.php │ │ ├── FrozenOceanBiome.php │ │ └── OceanBiome.php │ ├── plains │ │ ├── PlainsBiome.php │ │ └── SunflowerPlainsBiome.php │ ├── river │ │ ├── FrozenRiverBiome.php │ │ └── RiverBiome.php │ ├── roofedforest │ │ ├── RoofedForestBiome.php │ │ └── RoofedForestMBiome.php │ ├── savanna │ │ ├── SavannaBiome.php │ │ ├── SavannaMBiome.php │ │ ├── SavannaPlateauBiome.php │ │ └── SavannaPlateauMBiome.php │ ├── swamp │ │ ├── SwampBiome.php │ │ └── SwamplandMBiome.php │ └── taiga │ │ ├── ColdTaigaBiome.php │ │ ├── ColdTaigaHillsBiome.php │ │ ├── ColdTaigaMBiome.php │ │ ├── MegaSpruceTaigaBiome.php │ │ ├── MegaTaigaBiome.php │ │ ├── MegaTaigaHillsBiome.php │ │ ├── TaigaBiome.php │ │ ├── TaigaHillsBiome.php │ │ └── TaigaMBiome.php └── type │ ├── CoveredBiome.php │ ├── GrassyBiome.php │ ├── SandyBiome.php │ ├── SnowyBiome.php │ └── WateryBiome.php ├── generators ├── BlockGenerator.php ├── CustomGenerator.php └── UnoxGenerator.php ├── map └── BiomeMapGenerator.php ├── math ├── CustomRandom.php ├── FacingHelper.php └── MathHelper.php ├── noise ├── NoiseGeneratorImproved.php ├── NoiseGeneratorOctaves.php ├── PerlinF.php ├── PerlinNoiseGenerator.php └── SimplexF.php ├── object ├── AcaciaTree.php ├── BasicGenerator.php ├── BigJungleTree.php ├── BigSpruceTree.php ├── CustomTree.php ├── DarkOakTree.php ├── HugeTree.php ├── NewJungleTree.php ├── SwampTree.php └── mushroom │ └── BigMushroom.php ├── populator ├── BedrockPopulator.php ├── CactusPopulator.php ├── CavePopulator.php ├── DeadBushPopulator.php ├── DoublePlantPopulator.php ├── FlowerPopulator.php ├── GrassPopulator.php ├── GroundCoverPopulator.php ├── IceSpikesPopulator.php ├── KelpPopulator.php ├── LilyPadPopulator.php ├── MelonPopulator.php ├── MushroomPopulator.php ├── PopulatorCount.php ├── RavinesPopulator.php ├── SmallMushroomPopulator.php ├── SugarcanePopulator.php ├── SurfaceBlockPopulator.php ├── TreePopulator.php ├── WaterIcePopulator.php └── helper │ ├── EnsureBelow.php │ ├── EnsureCover.php │ ├── EnsureGrassBelow.php │ └── PopulatorHelpers.php └── renderer ├── Picasso.php └── Statistics.php /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | pocketmine -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BlockGenerator 2 | A custom world generator for PocketMine 3 | -------------------------------------------------------------------------------- /plugin.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: BlockGenerator 3 | author: BlockHorizons 4 | authors: [Chris-Prime] 5 | api: [4.0.0, 3.0.0] 6 | version: 0.1.0_beta 7 | main: BlockHorizons\BlockGenerator\Loader -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/Loader.php: -------------------------------------------------------------------------------- 1 | getServer()->getFilePath() . "worlds/real_level"); 18 | 19 | GeneratorManager::getInstance()->addGenerator(BlockGenerator::class, "vanilla", fn() => null); 20 | 21 | $options = new WorldCreationOptions(); 22 | $options->setSeed(mt_rand(PHP_INT_MIN, PHP_INT_MAX)); 23 | $options->setGeneratorClass(BlockGenerator::class); 24 | 25 | $this->getServer()->getWorldManager()->generateWorld("real_level", $options, true); 26 | $this->getServer()->getWorldManager()->loadWorld("real_level"); 27 | } 28 | 29 | public function onDisable(): void 30 | { 31 | @rmdir("worlds/real_level"); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/CustomBiome.php: -------------------------------------------------------------------------------- 1 | getPopulators(); 207 | $biome->clearPopulators(); 208 | foreach (array_reverse($p) as $pp) { 209 | $biome->addPopulator($pp); 210 | } 211 | } 212 | } 213 | 214 | protected static function register(int $id, Biome $biome) 215 | { 216 | self::$customBiomes[$id] = $biome; 217 | $biome->setId($id); 218 | } 219 | 220 | public static function getBiomes(): SplFixedArray 221 | { 222 | return self::$customBiomes; 223 | } 224 | 225 | public static function getBiome(int $id): CustomBiome 226 | { 227 | if ($id < 0 || $id > self::MAX_BIOMES) { 228 | return new UnknownBiome(); 229 | } 230 | 231 | if (!isset(self::$customBiomes[$id])) { 232 | self::register($id, new UnknownBiome()); 233 | } 234 | return self::$customBiomes[$id]; 235 | } 236 | 237 | public function getBaseHeight(): float 238 | { 239 | return $this->baseHeight; 240 | } 241 | 242 | public function setBaseHeight(float $baseHeight): void 243 | { 244 | $this->baseHeight = $baseHeight; 245 | } 246 | 247 | public function getHeightVariation(): float 248 | { 249 | return $this->heightVariation; 250 | } 251 | 252 | public function setHeightVariation(float $heightVariation): void 253 | { 254 | $this->heightVariation = $heightVariation; 255 | } 256 | 257 | public function doesOverhang(): bool 258 | { 259 | return false; 260 | } 261 | 262 | public function getHeightOffset(int $x, int $z): int 263 | { 264 | return 0; 265 | } 266 | 267 | public function isFreezing(): bool 268 | { 269 | return false; 270 | } 271 | 272 | // public function setTemperature(float $temp): void 273 | // { 274 | // $this->temperature = $temp; 275 | // } 276 | // 277 | // public function setRainfall(float $rainfall): void 278 | // { 279 | // $this->rainfall = $rainfall; 280 | // } 281 | 282 | } 283 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/CustomBiomeSelector.php: -------------------------------------------------------------------------------- 1 | _temperature = new Simplex($random, 2, 1 / 8, 1 / 2048); 25 | $this->rain = new Simplex($random, 2, 1 / 8, 1 / 2048); 26 | $this->river = new Simplex($random, 6, 2 / 4, 1 / 1024); 27 | $this->ocean = new Simplex($random, 6, 2 / 4, 1 / 2048); 28 | $this->hills = new Simplex($random, 2, 2 / 4, 1 / 2048); 29 | } 30 | 31 | public function pickBiome($x, $z): CustomBiome 32 | { 33 | $noiseOcean = $this->ocean->noise2D($x, $z, true); 34 | $noiseRiver = $this->river->noise2D($x, $z, true); 35 | $temperature = $this->_temperature->noise2D($x, $z, true); 36 | $rainfall = $this->rain->noise2D($x, $z, true); 37 | $hills = $this->hills->noise2D($x, $z, true); 38 | 39 | $biome = -1; 40 | if ($noiseOcean < -0.16) { 41 | if ($noiseOcean < -0.70) { 42 | if ($noiseOcean < -0.745) { 43 | $biome = CustomBiome::MUSHROOM_ISLAND; 44 | } else { 45 | $biome = CustomBiome::MUSHROOM_ISLAND_SHORE; 46 | } 47 | } else { 48 | if ($rainfall < 0.0) { 49 | $biome = CustomBiome::OCEAN; 50 | // } elseif ($temperature < 0) { 51 | // $biome = CustomBiome::FROZEN_OCEAN; 52 | } else { 53 | $biome = CustomBiome::DEEP_OCEAN; 54 | } 55 | } 56 | } elseif (abs($noiseRiver) < 0.04) { 57 | if ($temperature < -0.3) { 58 | $biome = CustomBiome::FROZEN_RIVER; 59 | } else { 60 | $biome = CustomBiome::RIVER; 61 | } 62 | } else { 63 | if ($temperature < -0.379) { 64 | //freezing 65 | if ($noiseOcean < -0.12) { 66 | $biome = CustomBiome::COLD_BEACH; 67 | } elseif ($rainfall < 0) { 68 | if ($hills < -0.1) { 69 | $biome = CustomBiome::COLD_TAIGA; 70 | } elseif ($hills < 0.2) { 71 | $biome = CustomBiome::COLD_TAIGA_HILLS; 72 | } else { 73 | $biome = CustomBiome::COLD_TAIGA_M; 74 | } 75 | } else { 76 | if ($hills < 0.7) { 77 | $biome = CustomBiome::ICE_PLAINS; 78 | } else { 79 | $biome = CustomBiome::ICE_PLAINS_SPIKES; 80 | } 81 | } 82 | } elseif ($noiseOcean < -0.12) { 83 | if ($noiseOcean < -0.1 && $hills > 0.5) { 84 | $biome = CustomBiome::STONE_BEACH; 85 | } else { 86 | $biome = CustomBiome::BEACH; 87 | } 88 | } elseif ($temperature < 0) { 89 | //cold 90 | if ($hills < -0.4) { 91 | if ($rainfall < -0.5) { 92 | $biome = CustomBiome::EXTREME_HILLS_M; 93 | } elseif ($rainfall > 0.5) { 94 | $biome = CustomBiome::EXTREME_HILLS_PLUS_M; 95 | } elseif ($rainfall < 0) { 96 | $biome = CustomBiome::EXTREME_HILLS; 97 | } else { 98 | $biome = CustomBiome::EXTREME_HILLS_PLUS; 99 | } 100 | } else { 101 | if ($rainfall < -0.25) { 102 | if ($hills > 0.5) { 103 | $biome = CustomBiome::MEGA_TAIGA_HILLS; 104 | } else { 105 | $biome = CustomBiome::MEGA_TAIGA; 106 | } 107 | } elseif ($hills > 0.5) { 108 | $biome = CustomBiome::TAIGA_HILLS; 109 | } elseif ($rainfall > 0.35) { 110 | $biome = CustomBiome::MEGA_SPRUCE_TAIGA; 111 | } elseif ($rainfall < 0.2) { 112 | $biome = CustomBiome::TAIGA; 113 | } else { 114 | $biome = CustomBiome::TAIGA_M; 115 | } 116 | } 117 | } elseif ($temperature < 0.5) { 118 | //normal 119 | if ($temperature < 0.25) { 120 | if ($rainfall < 0) { 121 | if ($noiseOcean < 0) { 122 | $biome = CustomBiome::SUNFLOWER_PLAINS; 123 | } else { 124 | $biome = CustomBiome::PLAINS; 125 | } 126 | } elseif ($rainfall < 0.25) { 127 | if ($hills < 0.2) { 128 | $biome = CustomBiome::FOREST_HILLS; 129 | } elseif ($noiseOcean < 0) { 130 | $biome = CustomBiome::FLOWER_FOREST; 131 | } else { 132 | $biome = CustomBiome::FOREST; 133 | } 134 | } else { 135 | if ($noiseOcean < 0) { 136 | if ($hills > 0.15) { 137 | $biome = CustomBiome::BIRCH_FOREST_HILLS_M; 138 | } else { 139 | $biome = CustomBiome::BIRCH_FOREST_M; 140 | } 141 | } else { 142 | if ($hills > 0.4) { 143 | $biome = CustomBiome::BIRCH_FOREST_HILLS; 144 | } else { 145 | $biome = CustomBiome::BIRCH_FOREST; 146 | } 147 | } 148 | } 149 | } else { 150 | if ($rainfall < -0.2) { 151 | if ($noiseOcean < 0) { 152 | $biome = CustomBiome::SWAMPLAND_M; 153 | } else { 154 | $biome = CustomBiome::SWAMP; 155 | } 156 | } elseif ($rainfall > 0.1) { 157 | if ($noiseOcean < 0.155) { 158 | if ($hills < -0.5) { 159 | $biome = CustomBiome::JUNGLE_HILLS; 160 | } elseif ($rainfall < 0.15) { 161 | $biome = CustomBiome::JUNGLE_EDGE; 162 | } elseif ($noiseOcean < 0.1) { 163 | if ($rainfall < 0.16) { 164 | $biome = CustomBiome::JUNGLE_EDGE_M; 165 | } else { 166 | $biome = CustomBiome::JUNGLE_M; 167 | } 168 | } else { 169 | $biome = CustomBiome::JUNGLE; 170 | } 171 | } 172 | } else { 173 | if ($noiseOcean < 0) { 174 | $biome = CustomBiome::ROOFED_FOREST_M; 175 | } else { 176 | $biome = CustomBiome::ROOFED_FOREST; 177 | } 178 | } 179 | } 180 | } else { 181 | //hot 182 | if ($rainfall < 0) { 183 | if ($noiseOcean < 0) { 184 | $biome = CustomBiome::DESERT_M; 185 | } elseif ($hills < 0) { 186 | $biome = CustomBiome::DESERT_HILLS; 187 | } else { 188 | $biome = CustomBiome::DESERT; 189 | } 190 | } elseif ($rainfall > 0.4) { 191 | if ($noiseOcean < 0.155) { 192 | if ($hills < 0) { 193 | $biome = CustomBiome::SAVANNA_PLATEAU_M; 194 | } else { 195 | $biome = CustomBiome::SAVANNA_M; 196 | } 197 | } else { 198 | if ($hills < 0.32) { 199 | $biome = CustomBiome::SAVANNA_PLATEAU; 200 | } else { 201 | $biome = CustomBiome::SAVANNA; 202 | } 203 | } 204 | } else { 205 | if ($noiseOcean < 0) { 206 | if ($hills < 0) { 207 | $biome = CustomBiome::MESA_PLATEAU_F; 208 | } else { 209 | $biome = CustomBiome::MESA_PLATEAU_F_M; 210 | } 211 | } elseif ($hills < 0) { 212 | if ($noiseOcean < 0.2) { 213 | $biome = CustomBiome::MESA_PLATEAU_M; 214 | } else { 215 | $biome = CustomBiome::MESA_PLATEAU; 216 | } 217 | } else { 218 | if ($noiseOcean < 0.1) { 219 | $biome = CustomBiome::MESA_BRYCE; 220 | } else { 221 | $biome = CustomBiome::MESA; 222 | } 223 | } 224 | } 225 | } 226 | } 227 | 228 | return CustomBiome::getBiome($biome); 229 | } 230 | 231 | protected function lookup(float $temperature, float $rainfall): int 232 | { 233 | return 0; 234 | } 235 | 236 | } -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/DebugBiomeSelector.php: -------------------------------------------------------------------------------- 1 | biomes = []; 23 | } 24 | 25 | public function pickBiome($x, $z): Biome 26 | { 27 | $x = $x >> 6; 28 | $z = $z >> 6; 29 | if (isset($this->biomes[$x][$z])) return $this->biomes[$x][$z]; 30 | 31 | $biomes = CustomBiome::getBiomes(); 32 | $biome = $biomes[array_rand(array_filter($biomes->toArray(), fn(?Biome $el) => $el))]; 33 | 34 | if (!isset($this->biomes[$x])) $this->biomes[$x] = []; 35 | $this->biomes[$x][$z] = $biome; 36 | 37 | return $biome; 38 | } 39 | 40 | protected function lookup(float $temperature, float $rainfall): int 41 | { 42 | return 0; 43 | } 44 | 45 | } -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/EmptyBiome.php: -------------------------------------------------------------------------------- 1 | setBaseHeight(0.2); 14 | $this->setHeightVariation(0.05); 15 | 16 | } 17 | 18 | public function getId(): int 19 | { 20 | return CustomBiome::VOID; 21 | } 22 | 23 | public function getName(): string 24 | { 25 | return "Empty"; 26 | } 27 | 28 | } -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/impl/UnknownBiome.php: -------------------------------------------------------------------------------- 1 | setBaseAmount(8); 18 | $sugarcane->setRandomAmount(5); 19 | 20 | $this->addPopulator($sugarcane); 21 | 22 | $this->setBaseHeight(0.0); 23 | $this->setHeightVariation(0.025); 24 | } 25 | 26 | public function getName(): string 27 | { 28 | return "Beach"; 29 | } 30 | 31 | } -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/impl/beach/ColdBeachBiome.php: -------------------------------------------------------------------------------- 1 | addPopulator($ice); 20 | 21 | $this->setBaseHeight(0); 22 | $this->setHeightVariation(0.025); 23 | } 24 | 25 | public function getCoverBlock(int $y): Block 26 | { 27 | return VanillaBlocks::SNOW_LAYER(); 28 | } 29 | 30 | public function getName(): string 31 | { 32 | return "Cold Beach"; 33 | } 34 | 35 | public function isFreezing(): bool 36 | { 37 | return true; 38 | } 39 | 40 | } -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/impl/desert/DesertBiome.php: -------------------------------------------------------------------------------- 1 | setBaseAmount(1); 19 | $this->addPopulator($cactus); 20 | 21 | $deadbush = new DeadBushPopulator(); 22 | $deadbush->setBaseAmount(1); 23 | $this->addPopulator($deadbush); 24 | 25 | $this->setBaseHeight(0.125); 26 | $this->setHeightVariation(0.05); 27 | } 28 | 29 | public function getName(): string 30 | { 31 | return "Desert"; 32 | } 33 | 34 | } -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/impl/desert/DesertHillsBiome.php: -------------------------------------------------------------------------------- 1 | setBaseHeight(0.45); 14 | $this->setHeightVariation(0.3); 15 | } 16 | 17 | public function getName(): string 18 | { 19 | return "Desert Hills"; 20 | } 21 | 22 | } -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/impl/desert/DesertMBiome.php: -------------------------------------------------------------------------------- 1 | setBaseHeight(0.225); 14 | $this->setHeightVariation(0.25); 15 | } 16 | 17 | public function getName(): string 18 | { 19 | return "Desert M"; 20 | } 21 | 22 | } -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/impl/extremehills/ExtremeHillsBiome.php: -------------------------------------------------------------------------------- 1 | setBaseAmount(2); 28 | $trees->setRandomAmount(2); 29 | $this->addPopulator($trees); 30 | } 31 | 32 | $this->setBaseHeight(1); 33 | $this->setHeightVariation(0.5); 34 | 35 | $this->snowNoise = new Simplex(new CustomRandom(1337), 8, 100.0 / 8.0, 1.0 / 9000); 36 | } 37 | 38 | public function getCoverBlock(int $y): Block 39 | { 40 | if($y > 92) { 41 | if($y > 102) { 42 | return parent::getCoverBlock($y); 43 | } 44 | return $this->isSnow ? parent::getCoverBlock($y) : VanillaBlocks::AIR(); 45 | } 46 | return VanillaBlocks::AIR(); 47 | } 48 | 49 | public function preCover(int $x, int $z): void 50 | { 51 | $this->isSnow = $this->snowNoise->noise2D($x, $z, true) > 0; 52 | } 53 | 54 | public function getName(): string 55 | { 56 | return "Extreme Hills"; 57 | } 58 | 59 | public function doesOverhang(): bool 60 | { 61 | return true; 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/impl/extremehills/ExtremeHillsEdgeBiome.php: -------------------------------------------------------------------------------- 1 | setBaseHeight(0.8); 15 | $this->setHeightVariation(0.3); 16 | } 17 | 18 | public function getName(): string 19 | { 20 | return "Extreme Hills Edge"; 21 | } 22 | 23 | } -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/impl/extremehills/ExtremeHillsMBiome.php: -------------------------------------------------------------------------------- 1 | gravelNoise = new SimplexF(1 / 64, 1, 1 / 4.0, new CustomRandom(0)); 28 | $this->iceNoise = new SimplexF(1 / 64, 1, 1 / 4.0, new CustomRandom(0)); 29 | 30 | $this->setBaseHeight(1); 31 | $this->setHeightVariation(0.5); 32 | } 33 | 34 | public function getName(): string 35 | { 36 | return "Extreme Hills M"; 37 | } 38 | 39 | public function getSurfaceBlock(int $y): Block 40 | { 41 | if($this->isIce && $y >= 136) { 42 | return VanillaBlocks::BLUE_ICE(); 43 | } elseif ($this->isSnowSurface && $y > 126) { 44 | return VanillaBlocks::SNOW(); 45 | } 46 | return $this->isGravel ? VanillaBlocks::GRAVEL() : parent::getSurfaceBlock($y); 47 | } 48 | 49 | #[Pure] 50 | public function getSurfaceDepth(int $y): int 51 | { 52 | if($this->isSnowSurface || $this->isIce) { 53 | return $this->snowNoise->getNoise2D($y, $y) < -0.1 ? 2 : 3; 54 | } 55 | return $this->isGravel ? 4 : parent::getSurfaceDepth($y); 56 | } 57 | 58 | #[Pure] 59 | public function getGroundDepth(int $y): int 60 | { 61 | return $this->isGravel ? 0 : parent::getGroundDepth($y); 62 | } 63 | 64 | public function preCover(int $x, int $z): void 65 | { 66 | parent::preCover($x, $z); 67 | 68 | $this->isSnowSurface = ($coldNoise = $this->iceNoise->noise2D($x, $z, true)) < -0.09; 69 | $this->isIce = $coldNoise < - 0.37; 70 | $this->isGravel = $this->gravelNoise->noise2D($x, $z, true) < -0.45;//-0.75; 71 | } 72 | 73 | public function doesOverhang(): bool 74 | { 75 | return false; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/impl/extremehills/ExtremeHillsPlusBiome.php: -------------------------------------------------------------------------------- 1 | setBaseHeight(1); 14 | $this->setHeightVariation(0.5); 15 | } 16 | 17 | public function getName(): string 18 | { 19 | return "Extreme Hills+"; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/impl/extremehills/ExtremeHillsPlusMBiome.php: -------------------------------------------------------------------------------- 1 | setBaseHeight(2); 14 | $this->setHeightVariation(1.2); 15 | } 16 | 17 | public function getName(): string 18 | { 19 | return "Extreme Hills+ M"; 20 | } 21 | 22 | public function doesOverhang(): bool 23 | { 24 | return false; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/impl/extremehills/StoneBeachBiome.php: -------------------------------------------------------------------------------- 1 | setBaseHeight(0.1); 18 | $this->setHeightVariation(0.8); 19 | } 20 | 21 | public function getSurfaceDepth(int $y): int 22 | { 23 | return 0; 24 | } 25 | 26 | public function getSurfaceBlock(int $y): Block 27 | { 28 | return VanillaBlocks::AIR(); 29 | } 30 | 31 | public function getGroundDepth(int $y): int 32 | { 33 | return 0; 34 | } 35 | 36 | public function getGroundBlock(int $y): Block 37 | { 38 | return VanillaBlocks::AIR(); 39 | } 40 | 41 | public function getName(): string 42 | { 43 | return "Stone Beach"; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/impl/forest/FlowerForestBiome.php: -------------------------------------------------------------------------------- 1 | setBaseAmount(10); 19 | $flower->addType(VanillaBlocks::DANDELION()); 20 | $flower->addType(VanillaBlocks::POPPY()); 21 | $flower->addType(VanillaBlocks::ALLIUM()); 22 | $flower->addType(VanillaBlocks::AZURE_BLUET()); 23 | $flower->addType(VanillaBlocks::RED_TULIP()); 24 | $flower->addType(VanillaBlocks::ORANGE_TULIP()); 25 | $flower->addType(VanillaBlocks::WHITE_TULIP()); 26 | $flower->addType(VanillaBlocks::PINK_TULIP()); 27 | $flower->addType(VanillaBlocks::OXEYE_DAISY()); 28 | $flower->addType(VanillaBlocks::SUNFLOWER()); 29 | $flower->addType(VanillaBlocks::LILAC()); 30 | $flower->addType(VanillaBlocks::ROSE_BUSH()); 31 | $this->addPopulator($flower); 32 | 33 | $this->setHeightVariation(0.4); 34 | } 35 | 36 | public function getName(): string 37 | { 38 | return $this->type == self::TYPE_BIRCH ? "Birch Forest" : "Forest"; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/impl/forest/ForestBiome.php: -------------------------------------------------------------------------------- 1 | type = $type; 24 | 25 | $trees = new TreePopulator( 26 | type: $type === self::TYPE_NORMAL 27 | ? TreeType::OAK() 28 | : TreeType::BIRCH(), 29 | super: $type === self::TYPE_BIRCH_TALL 30 | ); 31 | $trees->setBaseAmount($type === self::TYPE_NORMAL ? 3 : 6); 32 | $this->addPopulator($trees); 33 | 34 | if ($type == self::TYPE_NORMAL) { 35 | //normal forest biomes have both oak and birch trees 36 | $trees = new TreePopulator(TreeType::BIRCH()); 37 | $trees->setBaseAmount(3); 38 | $this->addPopulator($trees); 39 | } 40 | } 41 | 42 | public function getType(): int 43 | { 44 | return $this->type; 45 | } 46 | 47 | public function getName(): string 48 | { 49 | return match ($this->type) { 50 | self::TYPE_BIRCH => "Birch Forest", 51 | self::TYPE_BIRCH_TALL => "Birch Forest M", 52 | default => "Forest", 53 | }; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/impl/forest/ForestHillsBiome.php: -------------------------------------------------------------------------------- 1 | setBaseHeight(0.45); 14 | $this->setHeightVariation(0.3); 15 | } 16 | 17 | public function getName(): string 18 | { 19 | return match ($this->type) { 20 | self::TYPE_BIRCH => "Birch Forest Hills", 21 | self::TYPE_BIRCH_TALL => "Birch Forest Hills M", 22 | default => "Forest Hills", 23 | }; 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/impl/iceplains/IcePlainsBiome.php: -------------------------------------------------------------------------------- 1 | setBaseAmount(0); 19 | $tree->setRandomAmount(1); 20 | $this->addPopulator($tree); 21 | 22 | $this->setBaseHeight(0.125); 23 | $this->setHeightVariation(0.05); 24 | } 25 | 26 | public function getName(): string 27 | { 28 | return "Ice Plains"; 29 | } 30 | 31 | public function isFreezing() : bool { 32 | return true; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/impl/iceplains/IcePlainsSpikesBiome.php: -------------------------------------------------------------------------------- 1 | addPopulator($iceSpikes); 19 | } 20 | 21 | public function getSurfaceBlock(int $y): Block 22 | { 23 | return VanillaBlocks::SNOW(); 24 | } 25 | 26 | public function getName(): string 27 | { 28 | return "Ice Plains Spikes"; 29 | } 30 | 31 | public function isFreezing(): bool 32 | { 33 | return true; 34 | } 35 | 36 | } -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/impl/jungle/JungleBiome.php: -------------------------------------------------------------------------------- 1 | setBaseAmount(10); 21 | // $this->addPopulator($trees); 22 | // 23 | // $bigTrees = new BigJungleTreePopulator(); 24 | // $bigTrees->setBaseAmount(6); 25 | // $this->addPopulator($bigTrees); 26 | // 27 | // $melon = new MelonPopulator(); 28 | // $melon->setBaseAmount(-65); 29 | // $melon->setRandomAmount(70); 30 | // $this->addPopulator($melon); 31 | } 32 | 33 | public function getName(): string 34 | { 35 | return "Jungle"; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/impl/jungle/JungleEdgeBiome.php: -------------------------------------------------------------------------------- 1 | setBaseHeight(0.45); 14 | $this->setHeightVariation(0.3); 15 | } 16 | 17 | public function getName(): string 18 | { 19 | return "Jungle Hills"; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/impl/jungle/JungleMBiome.php: -------------------------------------------------------------------------------- 1 | setBaseAmount(10); 18 | // $floor->setRandomAmount(5); 19 | // $this->addPopulator($floor); 20 | 21 | $this->setBaseHeight(0.2); 22 | $this->setHeightVariation(0.4); 23 | } 24 | 25 | public function getName(): string 26 | { 27 | return "Jungle M"; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/impl/mesa/MesaBiome.php: -------------------------------------------------------------------------------- 1 | setBaseAmount(1); 40 | $cactus->setRandomAmount(1); 41 | $this->addPopulator($cactus); 42 | 43 | $deadBush = new DeadBushPopulator(); 44 | $deadBush->setBaseAmount(3); 45 | $deadBush->setRandomAmount(2); 46 | $this->addPopulator($deadBush); 47 | 48 | $this->colorLayer = []; 49 | $this->redSandNoise = new SimplexF(1 / 4.0, 2, 1 / 4, new CustomRandom(937478913)); 50 | $this->colorNoise = new SimplexF(1 / 32.0, 2, 1 / 4, new CustomRandom(193759875)); 51 | $this->moundNoise = new SimplexF($this->getMoundFrequency(), 2, 1 / 4, new CustomRandom(347228794)); 52 | 53 | $random = new CustomRandom(29864); 54 | 55 | for ($i = 0; $i < 64; $i++) { 56 | $this->colorLayer[$i] = -1; 57 | } 58 | $this->setRandomLayerColor($random, 14, 1); // orange 59 | $this->setRandomLayerColor($random, 8, 4); // yellow 60 | $this->setRandomLayerColor($random, 7, 12); // brown 61 | $this->setRandomLayerColor($random, 10, 14); // red 62 | for ($i = 0, $j = 0; $i < $random->nextBoundedInt(3) + 3; $i++) { 63 | $j += $random->nextBoundedInt(6) + 4; 64 | if ($j >= count($this->colorLayer) - 3) { 65 | break; 66 | } 67 | if ($random->nextBoundedInt(2) === 0 || $j < count($this->colorLayer) - 1 && $random->nextBoundedInt(2) === 0) { 68 | $this->colorLayer[$j - 1] = 8; // light gray 69 | } else { 70 | $this->colorLayer[$j] = 0; // white 71 | } 72 | } 73 | $this->setMoundHeight(17); 74 | 75 | $this->setBaseHeight(2.0); 76 | $this->setHeightVariation(1.5); 77 | } 78 | 79 | protected function getMoundFrequency(): float 80 | { 81 | return 1 / 128.0; 82 | } 83 | 84 | private function setRandomLayerColor(Random $random, int $sliceCount, int $color): void 85 | { 86 | for ($i = 0; $i < $random->nextBoundedInt(4) + $sliceCount; $i++) { 87 | $j = $random->nextBoundedInt(count($this->colorLayer)); 88 | $k = 0; 89 | while ($k < $random->nextBoundedInt(2) + 1 && $j < count($this->colorLayer)) { 90 | $this->colorLayer[$j++] = $color; 91 | $k++; 92 | } 93 | } 94 | } 95 | 96 | public function setMoundHeight(int $height): void 97 | { 98 | $this->moundHeight = $height; 99 | } 100 | 101 | public function getSurfaceDepth(int $y): int 102 | { 103 | $this->isRedSand = $y < $this->redSandThreshold; 104 | $this->startY = $y; 105 | 106 | return $this->isRedSand ? 3 : $y - 66; 107 | } 108 | 109 | public function getSurfaceBlock(int $y): Block 110 | { 111 | if ($this->isRedSand) { 112 | return VanillaBlocks::RED_SAND(); 113 | } else { 114 | $this->currMeta = $this->colorLayer[($y + $this->randY) & 0x3F]; 115 | return $this->currMeta === -1 116 | ? BlockFactory::getInstance()->get(172, 0) 117 | : BlockFactory::getInstance()->get(159, $this->currMeta); 118 | } 119 | } 120 | 121 | public function getGroundDepth(int $y): int 122 | { 123 | return $this->isRedSand ? 2 : 0; 124 | } 125 | 126 | public function getGroundBlock(int $y): Block 127 | { 128 | return VanillaBlocks::RED_SANDSTONE(); 129 | } 130 | 131 | public function getName(): string 132 | { 133 | return "Mesa"; 134 | } 135 | 136 | public function preCover(int $x, int $z): void 137 | { 138 | $this->randY = (int)round(($this->colorNoise->noise2D($x, $z, true) + 1) * 1.5); 139 | 140 | $this->redSandThreshold = 71 + (int)round(($this->redSandNoise->noise2D($x, $z, true) + 1) * 1.5); 141 | } 142 | 143 | public function getHeightOffset(int $x, int $z): int 144 | { 145 | $n = $this->moundNoise->noise2D($x, $z, true); 146 | $a = self::minHill(); 147 | return ($n > $a && $n < $a + 0.2) ? (int)(($n - $a) * 5 * $this->moundHeight) : ($n < $a + 0.1 ? 0 : $this->moundHeight); 148 | } 149 | 150 | protected function minHill(): float 151 | { 152 | return -0.1; 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/impl/mesa/MesaBryceBiome.php: -------------------------------------------------------------------------------- 1 | setBaseHeight(1.5); 14 | $this->setHeightVariation(0.025); 15 | 16 | $this->setMoundHeight(0); 17 | } 18 | 19 | public function getName(): string 20 | { 21 | return "Mesa Plateau"; 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/impl/mesa/MesaPlateauFBiome.php: -------------------------------------------------------------------------------- 1 | setBaseAmount(2); 20 | $tree->setRandomAmount(1); 21 | $this->addPopulator($tree); 22 | } 23 | 24 | public function getCoverBlock(int $y): Block 25 | { 26 | return VanillaBlocks::GRASS(); 27 | } 28 | 29 | public function getName(): string 30 | { 31 | return "Mesa Plateau F"; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/impl/mesa/MesaPlateauFMBiome.php: -------------------------------------------------------------------------------- 1 | setMoundHeight(10); 14 | } 15 | 16 | public function getName(): string 17 | { 18 | return "Mesa Plateau M"; 19 | } 20 | 21 | protected function getMoundFrequency(): float 22 | { 23 | return 1 / 50; 24 | } 25 | 26 | protected function minHill(): float 27 | { 28 | return 0.1; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/impl/mushroom/MushroomIslandBiome.php: -------------------------------------------------------------------------------- 1 | setBaseAmount(1); 20 | // $this->addPopulator($mushroomPopulator); 21 | 22 | $this->setBaseHeight(0.2); 23 | $this->setHeightVariation(0.3); 24 | } 25 | 26 | public function getName(): string 27 | { 28 | return "Mushroom Island"; 29 | } 30 | 31 | public function getSurfaceBlock(int $y): Block 32 | { 33 | return VanillaBlocks::MYCELIUM(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/impl/mushroom/MushroomIslandShoreBiome.php: -------------------------------------------------------------------------------- 1 | setBaseHeight(0); 14 | $this->setHeightVariation(0.025); 15 | } 16 | 17 | public function getName(): string 18 | { 19 | return "Mushroom Island Shore"; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/impl/ocean/DeepOceanBiome.php: -------------------------------------------------------------------------------- 1 | setBaseHeight(-1.8); 14 | $this->setHeightVariation(0.1); 15 | } 16 | 17 | public function getName(): string 18 | { 19 | return "Deep Ocean"; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/impl/ocean/FrozenOceanBiome.php: -------------------------------------------------------------------------------- 1 | addPopulator($ice); 17 | } 18 | 19 | public function getName(): string 20 | { 21 | return "Frozen Ocean"; 22 | } 23 | 24 | public function isFreezing(): bool 25 | { 26 | return true; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/impl/ocean/OceanBiome.php: -------------------------------------------------------------------------------- 1 | setBaseHeight(-1); 16 | $this->setHeightVariation(0.1); 17 | } 18 | 19 | public function getName(): string 20 | { 21 | return "Ocean"; 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/impl/plains/PlainsBiome.php: -------------------------------------------------------------------------------- 1 | setBaseHeight(0.175); 19 | $this->setHeightVariation(0.05); 20 | 21 | $flower = new FlowerPopulator(); 22 | $flower->setBaseAmount(10); 23 | $flower->addType(VanillaBlocks::DANDELION()); 24 | $flower->addType(VanillaBlocks::POPPY()); 25 | $flower->addType(VanillaBlocks::ALLIUM()); 26 | $flower->addType(VanillaBlocks::SUNFLOWER()); 27 | $flower->addType(VanillaBlocks::LILAC()); 28 | $flower->addType(VanillaBlocks::ROSE_BUSH()); 29 | $this->addPopulator($flower); 30 | } 31 | 32 | public function getName(): string 33 | { 34 | return "Plains"; 35 | } 36 | 37 | public function getId(): int 38 | { 39 | return CustomBiome::PLAINS; 40 | } 41 | 42 | } -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/impl/plains/SunflowerPlainsBiome.php: -------------------------------------------------------------------------------- 1 | setBaseAmount(8); 18 | $sunflower->setRandomAmount(5); 19 | $this->addPopulator($sunflower); 20 | } 21 | 22 | public function getName(): string 23 | { 24 | return "Sunflower Plains"; 25 | } 26 | } -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/impl/river/FrozenRiverBiome.php: -------------------------------------------------------------------------------- 1 | addPopulator($ice); 17 | } 18 | 19 | public function getName(): string 20 | { 21 | return "Frozen River"; 22 | } 23 | 24 | public function isFreezing(): bool 25 | { 26 | return true; 27 | } 28 | 29 | } -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/impl/river/RiverBiome.php: -------------------------------------------------------------------------------- 1 | setBaseHeight(-0.5); 16 | $this->setHeightVariation(0); 17 | } 18 | 19 | public function getName(): string 20 | { 21 | return "River"; 22 | } 23 | 24 | } -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/impl/roofedforest/RoofedForestBiome.php: -------------------------------------------------------------------------------- 1 | setBaseAmount(20); 21 | // $tree->setRandomAmount(10); 22 | // $this->addPopulator($tree); 23 | // 24 | // $flower = new FlowerPopulator(); 25 | // $flower->setBaseAmount(2); 26 | // $this->addPopulator($flower); 27 | // 28 | // $mushroom = new MushroomPopulator(); 29 | // $mushroom->setBaseAmount(0); 30 | // $mushroom->setRandomAmount(1); 31 | // $this->addPopulator($mushroom); 32 | } 33 | 34 | public function getName(): string 35 | { 36 | return "Roofed Forest"; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/impl/roofedforest/RoofedForestMBiome.php: -------------------------------------------------------------------------------- 1 | setBaseHeight(0.2); 16 | $this->setHeightVariation(0.4); 17 | } 18 | 19 | public function getName(): string 20 | { 21 | return "Roofed Forest M"; 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/impl/savanna/SavannaBiome.php: -------------------------------------------------------------------------------- 1 | setBaseAmount(1); 19 | $this->addPopulator($tree); 20 | 21 | $this->setBaseHeight(0.125); 22 | $this->setHeightVariation(0.05); 23 | } 24 | 25 | public function getName(): string 26 | { 27 | return "Savanna"; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/impl/savanna/SavannaMBiome.php: -------------------------------------------------------------------------------- 1 | setBaseHeight(0.3625); 14 | $this->setHeightVariation(1.225); 15 | } 16 | 17 | public function getName(): string 18 | { 19 | return "Savanna M"; 20 | } 21 | 22 | public function doesOverhang(): bool 23 | { 24 | return true; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/impl/savanna/SavannaPlateauBiome.php: -------------------------------------------------------------------------------- 1 | setBaseHeight(1.5); 14 | $this->setHeightVariation(0.025); 15 | } 16 | 17 | public function getName(): string 18 | { 19 | return "Savanna Plateau"; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/impl/savanna/SavannaPlateauMBiome.php: -------------------------------------------------------------------------------- 1 | setBaseHeight(1.05); 14 | $this->setHeightVariation(1.2125001); 15 | } 16 | 17 | public function getName(): string 18 | { 19 | return "Savanna Plateau M"; 20 | } 21 | 22 | public function doesOverhang(): bool 23 | { 24 | return true; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/impl/swamp/SwampBiome.php: -------------------------------------------------------------------------------- 1 | setBaseAmount(4); 23 | // $lilyPad->setRandomAmount(2); 24 | // $this->addPopulator($lilyPad); 25 | // 26 | // $trees = new SwampTreePopulator(); 27 | // $trees->setBaseAmount(2); 28 | // $this->addPopulator($trees); 29 | // 30 | // $flower = new FlowerPopulator(); 31 | // $flower->setBaseAmount(3); 32 | // $flower->setRandomAmount(2); 33 | // $flower->addType(Block::RED_FLOWER, Flower::TYPE_BLUE_ORCHID); 34 | // $this->addPopulator($flower); 35 | // 36 | // $mushroom = new MushroomPopulator(1); 37 | // $mushroom->setBaseAmount(-10); 38 | // $mushroom->setRandomAmount(11); 39 | // $this->addPopulator($mushroom); 40 | // 41 | // $smallMushroom = new SmallMushroomPopulator(); 42 | // $smallMushroom->setBaseAmount(0); 43 | // $smallMushroom->setRandomAmount(7); 44 | // $this->addPopulator($smallMushroom); 45 | 46 | $this->setBaseHeight(-0.2); 47 | $this->setHeightVariation(0.1); 48 | } 49 | 50 | public function getName(): string 51 | { 52 | return "Swamp"; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/impl/swamp/SwamplandMBiome.php: -------------------------------------------------------------------------------- 1 | addPopulator($ice); 20 | 21 | $this->setBaseHeight(0.2); 22 | $this->setHeightVariation(0.2); 23 | } 24 | 25 | public function getName(): string 26 | { 27 | return "Cold Taiga"; 28 | } 29 | 30 | public function getCoverBlock(int $y): Block 31 | { 32 | return VanillaBlocks::SNOW_LAYER(); 33 | } 34 | 35 | public function isFreezing(): bool 36 | { 37 | return true; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/impl/taiga/ColdTaigaHillsBiome.php: -------------------------------------------------------------------------------- 1 | setBaseHeight(0.45); 14 | $this->setHeightVariation(0.3); 15 | } 16 | 17 | public function getName(): string 18 | { 19 | return "Cold Taiga Hills"; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/impl/taiga/ColdTaigaMBiome.php: -------------------------------------------------------------------------------- 1 | setBaseAmount(6); 19 | $bigTrees->setRandomAmount(4); 20 | $this->addPopulator($bigTrees); 21 | 22 | $this->setBaseHeight(0.2); 23 | $this->setHeightVariation(0.2); 24 | } 25 | 26 | public function getName(): string 27 | { 28 | return "Mega Taiga"; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/impl/taiga/MegaTaigaHillsBiome.php: -------------------------------------------------------------------------------- 1 | setBaseHeight(0.45); 15 | $this->setHeightVariation(0.3); 16 | } 17 | 18 | public function getName(): string 19 | { 20 | return "Mega Taiga Hills"; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/impl/taiga/TaigaBiome.php: -------------------------------------------------------------------------------- 1 | setBaseAmount(10); 19 | $trees->setRandomAmount(5); 20 | $this->addPopulator($trees); 21 | 22 | $this->setBaseHeight(0.2); 23 | $this->setHeightVariation(0.2); 24 | } 25 | 26 | public function getName(): string 27 | { 28 | return "Taiga"; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/impl/taiga/TaigaHillsBiome.php: -------------------------------------------------------------------------------- 1 | setBaseHeight(0.25); 15 | $this->setHeightVariation(0.8); 16 | } 17 | 18 | public function getName(): string 19 | { 20 | return "Taiga Hills"; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/impl/taiga/TaigaMBiome.php: -------------------------------------------------------------------------------- 1 | setBaseHeight(0.3); 17 | $this->setHeightVariation(0.4); 18 | } 19 | 20 | public function getName(): string 21 | { 22 | return "Taiga M"; 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/type/CoveredBiome.php: -------------------------------------------------------------------------------- 1 | 25 | * If < 0 bad things will happen! 26 | *
27 | */ 28 | public function getSurfaceDepth(int $y): int 29 | { 30 | return 1; 31 | } 32 | 33 | /** 34 | * Between cover and ground 35 | */ 36 | public abstract function getSurfaceBlock(int $y): Block; 37 | 38 | 39 | /** 40 | * The amount of times the ground block should be used 41 | *42 | * If < 0 bad things will happen! 43 | *
44 | */ 45 | public function getGroundDepth(int $y): int 46 | { 47 | return 4; 48 | } 49 | 50 | /** 51 | * Between surface and stone 52 | */ 53 | public abstract function getGroundBlock(int $y): Block; 54 | 55 | /** 56 | * The block used as stone/below all other surface blocks 57 | */ 58 | public function getStoneBlock(): Block 59 | { 60 | return VanillaBlocks::STONE(); 61 | } 62 | 63 | /** 64 | * Called before a new block column is covered. Biomes can update any relevant variables here before covering. 65 | *66 | * Biome covering is synchronized on the biome, so thread safety isn't an issue. 67 | *
68 | */ 69 | public function preCover(int $x, int $z): void 70 | { 71 | 72 | } 73 | 74 | } -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/type/GrassyBiome.php: -------------------------------------------------------------------------------- 1 | setBaseAmount(30); 19 | $this->addPopulator($grass); 20 | 21 | // $tallGrass = new TallGrass(); 22 | // $tallGrass->setBaseAmount(30); 23 | // $this->addPopulator($tallGrass); 24 | } 25 | 26 | public function getSurfaceBlock(int $y): Block 27 | { 28 | return VanillaBlocks::GRASS(); 29 | } 30 | 31 | public function getGroundBlock(int $y): Block 32 | { 33 | return VanillaBlocks::DIRT(); 34 | } 35 | 36 | } -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/type/SandyBiome.php: -------------------------------------------------------------------------------- 1 | addPopulator($waterIce); 20 | } 21 | 22 | public function getCoverBlock(int $y): Block 23 | { 24 | if ($y < BlockGenerator::SEA_HEIGHT) { 25 | return parent::getCoverBlock($y); 26 | } 27 | return VanillaBlocks::SNOW_LAYER(); 28 | } 29 | 30 | public function isFreezing(): bool 31 | { 32 | return true; 33 | } 34 | 35 | } -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/biomes/type/WateryBiome.php: -------------------------------------------------------------------------------- 1 | settings = ["seed" => $seed]; 68 | $this->seed = $this->settings["seed"]; 69 | // wtf am I doing here ? ^ xD 70 | $this->settings["populate"] = true; 71 | 72 | for ($i = -2; $i <= 2; ++$i) { 73 | for ($j = -2; $j <= 2; ++$j) { 74 | self::$BIOME_WEIGHTS[$i + 2 + ($j + 2) * 5] = (10.0 / sqrt((float)($i * $i + $j * $j) + 0.2)); 75 | } 76 | } 77 | 78 | $this->random = new CustomRandom($seed); 79 | 80 | $this->localSeed1 = $this->random->nextSignedFloat(); 81 | 82 | $this->localSeed2 = $this->random->nextSignedFloat(); 83 | 84 | $this->random->setSeed($seed); 85 | 86 | $this->selector = new CustomBiomeSelector($this->random); 87 | 88 | $this->minLimitPerlinNoise = new NoiseGeneratorOctaves($this->random, 16); 89 | 90 | $this->maxLimitPerlinNoise = new NoiseGeneratorOctaves($this->random, 16); 91 | 92 | $this->mainPerlinNoise = new NoiseGeneratorOctaves($this->random, 8); 93 | 94 | $this->scaleNoise = new NoiseGeneratorOctaves($this->random, 10); 95 | 96 | $this->depthNoise = new NoiseGeneratorOctaves($this->random, 16); 97 | 98 | $cover = new GroundCoverPopulator(); 99 | $this->generationPopulators[] = $cover; 100 | 101 | $bedrock = new BedrockPopulator(); 102 | $this->generationPopulators[] = $bedrock; 103 | 104 | $ores = new Ore(); 105 | $stone = VanillaBlocks::STONE(); 106 | $ores->setOreTypes([ 107 | new OreType(VanillaBlocks::COAL_ORE(), $stone, 20, 17, 0, 128), 108 | new OreType(VanillaBlocks::IRON_ORE(), $stone, 20, 9, 0, 64), 109 | new OreType(VanillaBlocks::REDSTONE_ORE(), $stone, 8, 8, 0, 16), 110 | new OreType(VanillaBlocks::LAPIS_LAZULI_ORE(), $stone, 1, 7, 0, 16), 111 | new OreType(VanillaBlocks::GOLD_ORE(), $stone, 2, 9, 0, 32), 112 | new OreType(VanillaBlocks::DIAMOND_ORE(), $stone, 1, 8, 0, 16), 113 | new OreType(VanillaBlocks::DIRT(), $stone, 10, 33, 0, 128), 114 | new OreType(VanillaBlocks::GRAVEL(), $stone, 8, 33, 0, 128), 115 | new OreType(VanillaBlocks::GRANITE(), $stone, 10, 33, 0, 80), 116 | new OreType(VanillaBlocks::DIORITE(), $stone, 10, 33, 0, 80), 117 | new OreType(VanillaBlocks::ANDESITE(), $stone, 10, 33, 0, 80) 118 | ]); 119 | $this->populators[] = $ores; 120 | 121 | // $this->populators[] = new CavePopulator($this->seed); 122 | 123 | // $ravines = new RavinesPopulator(); 124 | // $this->populators[] = $ravines; 125 | // $this->ravinePop = $ravines; 126 | CustomBiome::init(); 127 | } 128 | 129 | public function generateChunk(ChunkManager $world, int $chunkX, int $chunkZ): void 130 | { 131 | $baseX = $chunkX * Chunk::EDGE_LENGTH; 132 | $baseZ = $chunkZ * Chunk::EDGE_LENGTH; 133 | $this->random->setSeed($chunkX * $this->localSeed1 ^ $chunkZ * $this->localSeed2 ^ $this->seed); 134 | 135 | $chunk = $world->getChunk($chunkX, $chunkZ); 136 | 137 | //generate base noise values 138 | $depthRegion = $this->depthNoise->generateNoiseOctaves8($this->depthRegion, $chunkX * 4, $chunkZ * 4, 5, 5, 200.0, 200.0, 0.5); 139 | 140 | $this->depthRegion = $depthRegion; 141 | 142 | $mainNoiseRegion = $this->mainPerlinNoise->generateNoiseOctaves($this->mainNoiseRegion, $chunkX * 4, 0, $chunkZ * 4, 5, 33, 5, 684.412 / 60, 684.412 / 160, 684.412 / 60); 143 | 144 | $this->mainNoiseRegion = $mainNoiseRegion; 145 | 146 | $minLimitRegion = $this->minLimitPerlinNoise->generateNoiseOctaves($this->minLimitRegion, $chunkX * 4, 0, $chunkZ * 4, 5, 33, 5, 684.412, 684.412, 684.412); 147 | 148 | $this->minLimitRegion = $minLimitRegion; 149 | 150 | $maxLimitRegion = $this->maxLimitPerlinNoise->generateNoiseOctaves($this->maxLimitRegion, $chunkX * 4, 0, $chunkZ * 4, 5, 33, 5, 684.412, 684.412, 684.412); 151 | 152 | $this->maxLimitRegion = $maxLimitRegion; 153 | 154 | $heightMap = $this->heightMap; 155 | 156 | //generate heightmap and smooth biome heights 157 | $horizCounter = 0; 158 | $vertCounter = 0; 159 | for ($xSeg = 0; $xSeg < 5; ++$xSeg) { 160 | for ($zSeg = 0; $zSeg < 5; ++$zSeg) { 161 | 162 | $heightVariationSum = 0.0; 163 | $baseHeightSum = 0.0; 164 | $biomeWeightSum = 0.0; 165 | 166 | $biome = $this->getSelector()->pickBiome($baseX + ($xSeg * 4), $baseZ + ($zSeg * 4)); 167 | 168 | for ($xSmooth = -2; $xSmooth <= 2; ++$xSmooth) { 169 | for ($zSmooth = -2; $zSmooth <= 2; ++$zSmooth) { 170 | 171 | $biome1 = $this->getSelector()->pickBiome($baseX + ($xSeg * 4) + $xSmooth, $baseZ + ($zSeg * 4) + $zSmooth); 172 | 173 | $baseHeight = $biome1->getBaseHeight(); 174 | $heightVariation = $biome1->getHeightVariation(); 175 | 176 | $scaledWeight = self::$BIOME_WEIGHTS[$xSmooth + 2 + ($zSmooth + 2) * 5] / ($baseHeight + 2.0); 177 | 178 | if ($biome1->getBaseHeight() > $biome->getBaseHeight()) { 179 | $scaledWeight /= 2.0; 180 | } 181 | 182 | $heightVariationSum += $heightVariation * $scaledWeight; 183 | $baseHeightSum += $baseHeight * $scaledWeight; 184 | $biomeWeightSum += $scaledWeight; 185 | } 186 | } 187 | 188 | $heightVariationSum = $heightVariationSum / $biomeWeightSum; 189 | $baseHeightSum = $baseHeightSum / $biomeWeightSum; 190 | $heightVariationSum = $heightVariationSum * 0.9 + 0.1; 191 | $baseHeightSum = ($baseHeightSum * 4.0 - 1.0) / 8.0; 192 | $depthNoise = $depthRegion[$vertCounter] / 8000.0; 193 | 194 | if ($depthNoise < 0.0) { 195 | $depthNoise = -$depthNoise * 0.3; 196 | } 197 | 198 | $depthNoise = $depthNoise * 3.0 - 2.0; 199 | 200 | if ($depthNoise < 0.0) { 201 | $depthNoise = $depthNoise / 2.0; 202 | 203 | if ($depthNoise < -1.0) { 204 | $depthNoise = -1.0; 205 | } 206 | 207 | $depthNoise = $depthNoise / 1.4; 208 | $depthNoise = $depthNoise / 2.0; 209 | } else { 210 | if ($depthNoise > 1.0) { 211 | $depthNoise = 1.0; 212 | } 213 | 214 | $depthNoise = $depthNoise / 8.0; 215 | } 216 | 217 | 218 | ++$vertCounter; 219 | 220 | $baseHeightClone = $baseHeightSum; 221 | $heightVariationClone = $heightVariationSum; 222 | $baseHeightClone = $baseHeightClone + $depthNoise * 0.2; 223 | $baseHeightClone = $baseHeightClone * 8.5 / 8.0; 224 | $baseHeightFactor = 8.5 + $baseHeightClone * 4.0; 225 | 226 | for ($ySeg = 0; $ySeg < 33; ++$ySeg) { 227 | $baseScale = ((float)$ySeg - $baseHeightFactor) * 12.0 * 128.0 / 256.0 / $heightVariationClone; 228 | 229 | if ($baseScale < 0.0) { 230 | $baseScale *= 4.0; 231 | } 232 | 233 | $minScaled = $minLimitRegion[$horizCounter] / 512.0; 234 | $maxScaled = $maxLimitRegion[$horizCounter] / 512.0; 235 | $noiseScaled = ($mainNoiseRegion[$horizCounter] / 10.0 + 1.0) / 2.0; 236 | $clamp = MathHelper::denormalizeClamp($minScaled, $maxScaled, $noiseScaled) - $baseScale; 237 | 238 | if ($ySeg > 29) { 239 | $yScaled = ((float)($ySeg - 29) / 3.0); 240 | $clamp = $clamp * (1.0 - $yScaled) + -10.0 * $yScaled; 241 | } 242 | 243 | $heightMap[$horizCounter] = $clamp; 244 | 245 | ++$horizCounter; 246 | } 247 | } 248 | } 249 | 250 | //place blocks 251 | for ($xSeg = 0; $xSeg < 4; ++$xSeg) { 252 | 253 | $xScale = $xSeg * 5; 254 | $xScaleEnd = ($xSeg + 1) * 5; 255 | 256 | for ($zSeg = 0; $zSeg < 4; ++$zSeg) { 257 | $zScale1 = ($xScale + $zSeg) * 33; 258 | $zScaleEnd1 = ($xScale + $zSeg + 1) * 33; 259 | $zScale2 = ($xScaleEnd + $zSeg) * 33; 260 | $zScaleEnd2 = ($xScaleEnd + $zSeg + 1) * 33; 261 | 262 | for ($ySeg = 0; $ySeg < 32; ++$ySeg) { 263 | $height1 = $heightMap[$zScale1 + $ySeg]; 264 | $height2 = $heightMap[$zScaleEnd1 + $ySeg]; 265 | $height3 = $heightMap[$zScale2 + $ySeg]; 266 | $height4 = $heightMap[$zScaleEnd2 + $ySeg]; 267 | $height5 = ($heightMap[$zScale1 + $ySeg + 1] - $height1) * 0.125; 268 | $height6 = ($heightMap[$zScaleEnd1 + $ySeg + 1] - $height2) * 0.125; 269 | $height7 = ($heightMap[$zScale2 + $ySeg + 1] - $height3) * 0.125; 270 | $height8 = ($heightMap[$zScaleEnd2 + $ySeg + 1] - $height4) * 0.125; 271 | 272 | for ($yIn = 0; $yIn < 8; ++$yIn) { 273 | 274 | $baseIncr = $height1; 275 | $baseIncr2 = $height2; 276 | $scaleY = ($height3 - $height1) * 0.25; 277 | $scaleY2 = ($height4 - $height2) * 0.25; 278 | 279 | for ($zIn = 0; $zIn < 4; ++$zIn) { 280 | 281 | $scaleZ = ($baseIncr2 - $baseIncr) * 0.25; 282 | $scaleZ2 = $baseIncr - $scaleZ; 283 | 284 | for ($xIn = 0; $xIn < 4; ++$xIn) { 285 | if (($scaleZ2 += $scaleZ) > 0.0) { 286 | $chunk->setFullBlock( 287 | x: $xSeg * 4 + $zIn, 288 | y: $ySeg * 8 + $yIn, 289 | z: $zSeg * 4 + $xIn, 290 | block: ($biome instanceof CoveredBiome ? $biome->getStoneBlock() : VanillaBlocks::STONE())->getFullId()); 291 | } elseif ($ySeg * 8 + $yIn <= $this->seaHeight) { 292 | $chunk->setFullBlock( 293 | x: $xSeg * 4 + $zIn, 294 | y: $ySeg * 8 + $yIn, 295 | z: $zSeg * 4 + $xIn, 296 | block: VanillaBlocks::WATER()->getFullId() 297 | ); 298 | } 299 | } 300 | 301 | $baseIncr += $scaleY; 302 | $baseIncr2 += $scaleY2; 303 | } 304 | 305 | $height1 += $height5; 306 | $height2 += $height6; 307 | $height3 += $height7; 308 | $height4 += $height8; 309 | } 310 | } 311 | } 312 | } 313 | 314 | for ($x = 0; $x < 16; $x++) { 315 | for ($z = 0; $z < 16; $z++) { 316 | $biome = $this->getSelector()->pickBiome($baseX | $x, $baseZ | $z); 317 | $chunk->setBiomeId($x, $z, $biome->getId()); 318 | } 319 | } 320 | 321 | foreach ($this->generationPopulators as $populator) { 322 | $populator->populate($world, $chunkX, $chunkZ, $this->random); 323 | } 324 | } 325 | 326 | public function populateChunk(ChunkManager $world, int $chunkX, int $chunkZ): void 327 | { 328 | $chunk = $world->getChunk($chunkX, $chunkZ); 329 | 330 | $this->random->setSeed(0xdeadbeef ^ ($chunkX << 8) ^ $chunkZ ^ $this->seed); 331 | 332 | foreach ($this->populators as $populator) { 333 | $populator->populate($world, $chunkX, $chunkZ, $this->random); 334 | } 335 | 336 | $biome = CustomBiome::getBiome($chunk->getBiomeId(7, 7)); 337 | 338 | if ($this->settings['populate'] === false) return; 339 | 340 | $biome->populateChunk($world, $chunkX, $chunkZ, $this->random); 341 | } 342 | 343 | public function getName(): string 344 | { 345 | return "BlockGenerator"; 346 | } 347 | 348 | #[Pure] 349 | public function getSpawn(): Vector3 350 | { 351 | return new Vector3(0.5, 256, 0.5); 352 | } 353 | 354 | public function getSelector(): CustomBiomeSelector 355 | { 356 | return $this->selector; 357 | } 358 | 359 | public function getSettings(): array 360 | { 361 | return $this->settings; 362 | } 363 | 364 | 365 | } 366 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/generators/CustomGenerator.php: -------------------------------------------------------------------------------- 1 | settings = $options; 18 | } 19 | 20 | public function getSettings(): array 21 | { 22 | return $this->settings; 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/generators/UnoxGenerator.php: -------------------------------------------------------------------------------- 1 | level->getChunk($chunkX, $chunkZ); 32 | 33 | for ($x = 0; $x < 16; $x++) { 34 | for ($z = 0; $z < 16; $z++) { 35 | $chunk->setBlockId($baseX + $x, 32, $baseZ + $z, BlockIds::STONE); 36 | } 37 | } 38 | } 39 | 40 | public function populateChunk(int $chunkX, int $chunkZ): void 41 | { 42 | // Unnecessary for now 43 | } 44 | 45 | public function getName(): string 46 | { 47 | return "UnoxGenerator"; 48 | } 49 | 50 | public function getSpawn(): Vector3 51 | { 52 | return new Vector3(0.5, 256, 0.5); 53 | } 54 | 55 | public function getSelector(): CustomBiomeSelector 56 | { 57 | return $this->selector; 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/map/BiomeMapGenerator.php: -------------------------------------------------------------------------------- 1 | [50, 50, 255], 14 | CustomBiome::OCEAN => [0, 0, 255], 15 | CustomBiome::PLAINS => [50, 255, 50], 16 | CustomBiome::EXTREME_HILLS => [50, 255, 80], 17 | CustomBiome::DESERT => [200, 200, 0], 18 | CustomBiome::FOREST => null, 19 | CustomBiome::TAIGA => [40, 240, 60], 20 | CustomBiome::SWAMP => [50, 100, 0], 21 | CustomBiome::HELL => [255, 0, 0], 22 | CustomBiome::END => [190, 200, 140], 23 | CustomBiome::FROZEN_OCEAN => [0, 180, 200], //DOES NOT GENERATE NATUALLY 24 | CustomBiome::FROZEN_RIVER => [0, 200, 220], 25 | CustomBiome::ICE_PLAINS => [20, 220, 240], 26 | CustomBiome::MUSHROOM_ISLAND => null,// 27 | CustomBiome::MUSHROOM_ISLAND_SHORE => null, 28 | CustomBiome::BEACH => [200, 200, 10], 29 | CustomBiome::DESERT_HILLS => [170, 170, 20], 30 | CustomBiome::FOREST_HILLS => [20, 230, 20], 31 | CustomBiome::TAIGA_HILLS => [20, 230, 60], 32 | CustomBiome::EXTREME_HILLS_EDGE => [40, 250, 80], //DOES NOT GENERATE NATUALLY 33 | CustomBiome::JUNGLE => [0, 150, 0], 34 | CustomBiome::JUNGLE_HILLS => [0, 200, 0], 35 | CustomBiome::JUNGLE_EDGE => [0, 130, 0], 36 | CustomBiome::DEEP_OCEAN => [0, 0, 150], 37 | CustomBiome::STONE_BEACH => [140, 140, 140], 38 | CustomBiome::COLD_BEACH => [140, 140, 210], 39 | CustomBiome::BIRCH_FOREST => [150, 255, 150], 40 | CustomBiome::BIRCH_FOREST_HILLS => [150, 255, 200], 41 | CustomBiome::ROOFED_FOREST => null, 42 | CustomBiome::COLD_TAIGA => [220, 220, 220], 43 | CustomBiome::COLD_TAIGA_HILLS => null, 44 | CustomBiome::MEGA_TAIGA => null, 45 | CustomBiome::MEGA_TAIGA_HILLS => null, 46 | CustomBiome::EXTREME_HILLS_PLUS => null, 47 | CustomBiome::SAVANNA => [230, 200, 10], 48 | CustomBiome::SAVANNA_PLATEAU => [230, 200, 30], 49 | CustomBiome::MESA => [200, 40, 40], 50 | CustomBiome::MESA_PLATEAU_F => [200, 40, 80], 51 | CustomBiome::MESA_PLATEAU => [200, 40, 60], 52 | CustomBiome::SUNFLOWER_PLAINS => [255, 180, 180], 53 | CustomBiome::DESERT_M => [255, 255, 80], 54 | CustomBiome::EXTREME_HILLS_M => null, 55 | CustomBiome::FLOWER_FOREST => null, 56 | CustomBiome::TAIGA_M => null, 57 | CustomBiome::SWAMPLAND_M => null, 58 | CustomBiome::ICE_PLAINS_SPIKES => null, 59 | CustomBiome::JUNGLE_M => null, 60 | CustomBiome::JUNGLE_EDGE_M => null, 61 | CustomBiome::BIRCH_FOREST_M => null, 62 | CustomBiome::BIRCH_FOREST_HILLS_M => null, 63 | CustomBiome::ROOFED_FOREST_M => null, 64 | CustomBiome::COLD_TAIGA_M => null, 65 | CustomBiome::MEGA_SPRUCE_TAIGA => null, 66 | CustomBiome::EXTREME_HILLS_PLUS_M => null, 67 | CustomBiome::SAVANNA_M => null, 68 | CustomBiome::SAVANNA_PLATEAU_M => null, 69 | CustomBiome::MESA_BRYCE => null, 70 | CustomBiome::MESA_PLATEAU_F_M => null, 71 | CustomBiome::MESA_PLATEAU_M => null, 72 | CustomBiome::VOID => null, 73 | ]; 74 | /** @var Generator */ 75 | protected $selector; 76 | 77 | public function __construct(BiomeSelector $selector) 78 | { 79 | $this->selector = $selector; 80 | } 81 | 82 | public static function saveMap(array $data, string $file): void 83 | { 84 | file_put_contents($file, json_encode($data)); 85 | } 86 | 87 | public static function readMap(string $file): array 88 | { 89 | return json_decode(file_get_contents($file)); 90 | } 91 | 92 | public function createMap(Vector2 $start, int $radius, int $step = 1): array 93 | { 94 | $map = []; 95 | for ($x = $start->x - $radius * $step; $x < $start->x + $radius * $step; $x += $step) { 96 | for ($z = $start->y - $radius * $step; $z < $start->y + $radius * $step; $z += $step) { 97 | $map[$x / $step][$z / $step] = $this->getPixel($x, $z); 98 | } 99 | } 100 | return $map; 101 | } 102 | 103 | public function getPixel(int $x, int $z): int 104 | { 105 | return self::rgbaToInt($this->getBiomeColor($this->getSelector()->pickBiome($x, $z)->getId())); 106 | } 107 | 108 | public static function rgbaToInt(array $rgba): int 109 | { 110 | $color = 0; 111 | $color |= ($rgba[3] ?? 0 & 255) << 24; 112 | $color |= ($rgba[0] & 255) << 16; 113 | $color |= ($rgba[1] & 255) << 8; 114 | $color |= ($rgba[2] & 255); 115 | return $color; 116 | } 117 | 118 | public static function getBiomeColor(int $id): array 119 | { 120 | return self::$colors[$id] ?? self::randomColor(); 121 | } 122 | 123 | public static function randomColor(): array 124 | { 125 | return [ 126 | mt_rand(50, 250), 127 | mt_rand(50, 250), 128 | mt_rand(50, 250), 129 | ]; 130 | } 131 | 132 | public function getSelector(): BiomeSelector 133 | { 134 | return $this->selector; 135 | } 136 | 137 | public function createImageFromMap(array $map) 138 | { 139 | if (empty($map) || !isset($map[0])) return null; 140 | 141 | $sizeX = count($map); 142 | $sizeZ = count($map[0]); 143 | $img = imagecreate($sizeX, $sizeZ); 144 | 145 | $half = (int)$sizeX / 2; 146 | 147 | $colors = []; 148 | foreach ($map as $x => $row) { 149 | foreach ($row as $z => $color) { 150 | if (isset($colors[$color])) { 151 | $color = $colors[$color]; 152 | } else { 153 | $rgba = self::intToRgba($color); 154 | $tc = $color; 155 | $color = imagecolorallocate($img, $rgba[1], $rgba[2], $rgba[3]); 156 | $colors[$tc] = $color; 157 | } 158 | imagesetpixel($img, $x + $half, $z + $half, $color); 159 | } 160 | } 161 | 162 | return $img; 163 | } 164 | 165 | public static function intToRgba(int $color): array 166 | { 167 | return [ 168 | $color >> 24 & 0xFF, 169 | $color >> 16 & 0xFF, 170 | $color >> 8 & 0xFF, 171 | $color & 0xFF 172 | ]; 173 | } 174 | 175 | } -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/math/CustomRandom.php: -------------------------------------------------------------------------------- 1 | nextBoundedInt(10)}/10" . PHP_EOL; 17 | echo "---- Testing nextInt ---- " . PHP_EOL; 18 | for ($i = 0; $i < 4 * 2; $i++) echo ($i + 1) . ": {$r->nextInt()}" . PHP_EOL; 19 | } 20 | 21 | public function nextLong(): int 22 | { 23 | return $this->nextSignedInt(); 24 | } 25 | 26 | public function nextBoundedInt(float|int $bound): int 27 | { 28 | return parent::nextBoundedInt((int) $bound); 29 | } 30 | 31 | } -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/math/FacingHelper.php: -------------------------------------------------------------------------------- 1 | self::NORTH, 57 | "South" => self::SOUTH, 58 | "West" => self::WEST, 59 | "East" => self::EAST, 60 | "Up" => self::UP, 61 | "Down" => self::DOWN 62 | ]; 63 | foreach ($faces as $name => $face) { 64 | echo " ---- Face: $name ----" . PHP_EOL; 65 | echo " xOffset: " . self::xOffset($face) . PHP_EOL; 66 | echo " yOffset: " . self::yOffset($face) . PHP_EOL; 67 | echo " zOffset: " . self::zOffset($face) . PHP_EOL; 68 | } 69 | } 70 | 71 | public static function xOffset(int $face): int 72 | { 73 | return self::offset($face, self::AXIS_X); 74 | } 75 | 76 | public static function offset(int $face, int $axis): int 77 | { 78 | return (self::axis($face) === $axis ? (($face % 2) > 0 ? 1 : -1) : 0); 79 | } 80 | 81 | public static function axis(int $direction): int 82 | { 83 | switch ($direction) { 84 | case self::EAST: 85 | case self::WEST: 86 | return self::AXIS_X; 87 | case self::NORTH: 88 | case self::SOUTH: 89 | return self::AXIS_Z; 90 | case self::UP: 91 | case self::DOWN: 92 | return self::AXIS_Y; 93 | default: 94 | return -1; 95 | } 96 | } 97 | 98 | public static function yOffset(int $face): int 99 | { 100 | return self::offset($face, self::AXIS_Y); 101 | } 102 | 103 | public static function zOffset(int $face): int 104 | { 105 | return self::offset($face, self::AXIS_Z); 106 | } 107 | 108 | } -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/math/MathHelper.php: -------------------------------------------------------------------------------- 1 | 1.0 ? $upperBnd : $lowerBnd + ($upperBnd - $lowerBnd) * $slide); 15 | } 16 | 17 | } -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/noise/NoiseGeneratorImproved.php: -------------------------------------------------------------------------------- 1 | permutations = []; // was fixed to 512 49 | 50 | for ($i = 0; $i < 512; $i++) $this->permutations[$i] = $i; 51 | 52 | $this->xCoord = $p_i45469_1_->nextFloat() * 256.0; 53 | $this->yCoord = $p_i45469_1_->nextFloat() * 256.0; 54 | $this->zCoord = $p_i45469_1_->nextFloat() * 256.0; 55 | 56 | for ($l = 0; $l < 512; ++$l) { 57 | 58 | $j = $p_i45469_1_->nextBoundedInt(512 - $l) + $l; 59 | 60 | $k = $this->permutations[$l]; 61 | 62 | $this->permutations[$l] = $this->permutations[$j]; 63 | 64 | $this->permutations[$j] = $k; 65 | 66 | $this->permutations[$l + 512] = $this->permutations[$l]; 67 | 68 | } 69 | 70 | } 71 | 72 | public function populateNoiseArray(array &$noiseArray, float $xOffset, float $yOffset, float $zOffset, int $xSize, int $ySize, int $zSize, float $xScale, float $yScale, float $zScale, float $noiseScale): void 73 | { 74 | 75 | if ($ySize == 1) { 76 | $i5 = 0; 77 | $j5 = 0; 78 | $j = 0; 79 | $k5 = 0; 80 | $d14 = 0.0; 81 | $d15 = 0.0; 82 | $l5 = 0; 83 | $d16 = 1.0 / $noiseScale; 84 | 85 | for ($j2 = 0; $j2 < $xSize; ++$j2) { 86 | $d17 = $xOffset + (float)$j2 * $xScale + $this->xCoord; 87 | $i6 = (int)$d17; 88 | 89 | if ($d17 < (float)$i6) { 90 | --$i6; 91 | } 92 | 93 | $k2 = $i6 & 255; 94 | $d17 = $d17 - (float)$i6; 95 | $d18 = $d17 * $d17 * $d17 * ($d17 * ($d17 * 6.0 - 15.0) + 10.0); 96 | 97 | for ($j6 = 0; $j6 < $zSize; ++$j6) { 98 | $d19 = $zOffset + (float)$j6 * $zScale + $this->zCoord; 99 | $k6 = (int)$d19; 100 | if ($d19 < (float)$k6) { 101 | --$k6; 102 | } 103 | 104 | $l6 = $k6 & 255; 105 | $d19 = $d19 - (float)$k6; 106 | $d20 = $d19 * $d19 * $d19 * ($d19 * ($d19 * 6.0 - 15.0) + 10.0); 107 | $i5 = $this->permutations[$k2] + 0; 108 | $j5 = $this->permutations[$i5] + $l6; 109 | $j = $this->permutations[$k2 + 1] + 0; 110 | $k5 = $this->permutations[$j] + $l6; 111 | $d14 = $this->lerp($d18, $this->grad2($this->permutations[$j5], $d17, $d19), $this->grad($this->permutations[$k5], $d17 - 1.0, 0.0, $d19)); 112 | $d15 = $this->lerp($d18, $this->grad($this->permutations[$j5 + 1], $d17, 0.0, $d19 - 1.0), $this->grad($this->permutations[$k5 + 1], $d17 - 1.0, 0.0, $d19 - 1.0)); 113 | $d21 = $this->lerp($d20, $d14, $d15); 114 | $i7 = $l5++; 115 | if (!isset($noiseArray[$i7])) $noiseArray[$i7] = 0; 116 | $noiseArray[$i7] += $d21 * $d16; 117 | } 118 | } 119 | } else { 120 | $i = 0; 121 | $d0 = 1.0 / $noiseScale; 122 | $k = -1; 123 | $l = 0; 124 | $i1 = 0; 125 | $j1 = 0; 126 | $k1 = 0; 127 | $l1 = 0; 128 | $i2 = 0; 129 | $d1 = 0.0; 130 | $d2 = 0.0; 131 | $d3 = 0.0; 132 | $d4 = 0.0; 133 | 134 | for ($l2 = 0; $l2 < $xSize; ++$l2) { 135 | $d5 = $xOffset + (float)$l2 * $xScale + $this->xCoord; 136 | $i3 = (int)$d5; 137 | 138 | if ($d5 < (float)$i3) { 139 | --$i3; 140 | } 141 | 142 | $j3 = $i3 & 255; 143 | $d5 = $d5 - (float)$i3; 144 | $d6 = $d5 * $d5 * $d5 * ($d5 * ($d5 * 6.0 - 15.0) + 10.0); 145 | 146 | for ($k3 = 0; $k3 < $zSize; ++$k3) { 147 | $d7 = $zOffset + (float)$k3 * $zScale + $this->zCoord; 148 | $l3 = (int)$d7; 149 | 150 | if ($d7 < (float)$l3) { 151 | --$l3; 152 | } 153 | 154 | $i4 = $l3 & 255; 155 | $d7 = $d7 - (float)$l3; 156 | $d8 = $d7 * $d7 * $d7 * ($d7 * ($d7 * 6.0 - 15.0) + 10.0); 157 | 158 | for ($j4 = 0; $j4 < $ySize; ++$j4) { 159 | $d9 = $yOffset + (float)$j4 * $yScale + $this->yCoord; 160 | $k4 = (int)$d9; 161 | 162 | if ($d9 < (float)$k4) { 163 | --$k4; 164 | } 165 | 166 | $l4 = $k4 & 255; 167 | $d9 = $d9 - (float)$k4; 168 | $d10 = $d9 * $d9 * $d9 * ($d9 * ($d9 * 6.0 - 15.0) + 10.0); 169 | 170 | 171 | if ($j4 == 0 || $l4 != $k) { 172 | $k = $l4; 173 | $l = $this->permutations[$j3] + $l4; 174 | $i1 = $this->permutations[$l] + $i4; 175 | $j1 = $this->permutations[$l + 1] + $i4; 176 | $k1 = $this->permutations[$j3 + 1] + $l4; 177 | $l1 = $this->permutations[$k1] + $i4; 178 | $i2 = $this->permutations[$k1 + 1] + $i4; 179 | $d1 = $this->lerp($d6, $this->grad($this->permutations[$i1], $d5, $d9, $d7), $this->grad($this->permutations[$l1], $d5 - 1.0, $d9, $d7)); 180 | $d2 = $this->lerp($d6, $this->grad($this->permutations[$j1], $d5, $d9 - 1.0, $d7), $this->grad($this->permutations[$i2], $d5 - 1.0, $d9 - 1.0, $d7)); 181 | $d3 = $this->lerp($d6, $this->grad($this->permutations[$i1 + 1], $d5, $d9, $d7 - 1.0), $this->grad($this->permutations[$l1 + 1], $d5 - 1.0, $d9, $d7 - 1.0)); 182 | $d4 = $this->lerp($d6, $this->grad($this->permutations[$j1 + 1], $d5, $d9 - 1.0, $d7 - 1.0), $this->grad($this->permutations[$i2 + 1], $d5 - 1.0, $d9 - 1.0, $d7 - 1.0)); 183 | } 184 | $d11 = $this->lerp($d10, $d1, $d2); 185 | $d12 = $this->lerp($d10, $d3, $d4); 186 | $d13 = $this->lerp($d8, $d11, $d12); 187 | $j7 = $i++; 188 | if (!isset($noiseArray[$j7])) $noiseArray[$j7] = 0; 189 | $noiseArray[$j7] += $d13 * $d0; 190 | } 191 | } 192 | } 193 | } 194 | } 195 | 196 | public function lerp(float $p_76311_1_, float $p_76311_3_, float $p_76311_5_): float 197 | { 198 | return $p_76311_3_ + $p_76311_1_ * ($p_76311_5_ - $p_76311_3_); 199 | } 200 | 201 | public function grad2(int $p_76309_1_, float $p_76309_2_, float $p_76309_4_): float 202 | { 203 | $i = $p_76309_1_ & 15; 204 | return self::GRAD_2X[$i] * $p_76309_2_ + self::GRAD_2Z[$i] * $p_76309_4_; 205 | } 206 | 207 | 208 | /* 209 | 210 | * noiseArray should be xSize*ySize*zSize in size 211 | 212 | */ 213 | 214 | public function grad(int $p_76310_1_, float $p_76310_2_, float $p_76310_4_, float $p_76310_6_): float 215 | { 216 | 217 | $i = $p_76310_1_ & 15; 218 | 219 | return self::GRAD_X[$i] * $p_76310_2_ + self::GRAD_Y[$i] * $p_76310_4_ + self::GRAD_Z[$i] * $p_76310_6_; 220 | 221 | } 222 | 223 | } -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/noise/NoiseGeneratorOctaves.php: -------------------------------------------------------------------------------- 1 | octaves = $octavesIn; 25 | $this->generatorCollection = new SplFixedArray($octavesIn); 26 | 27 | for ($i = 0; $i < $octavesIn; ++$i) { 28 | $this->generatorCollection[$i] = new NoiseGeneratorImproved($seed); 29 | } 30 | } 31 | 32 | 33 | /* 34 | * pars:(par2,3,4=noiseOffset ; so that adjacent noise segments connect) (pars5,6,7=x,y,zArraySize),(pars8,10,12 = 35 | * x,y,z noiseScale) 36 | */ 37 | 38 | public function generateNoiseOctaves8(array &$noiseArray, int $xOffset, int $zOffset, int $xSize, int $zSize, float $xScale, float $zScale, float $p_76305_10_) 39 | { 40 | return $this->generateNoiseOctaves($noiseArray, $xOffset, 10, $zOffset, $xSize, 1, $zSize, $xScale, 1.0, $zScale); 41 | } 42 | 43 | public function generateNoiseOctaves(array $noiseArray, int $xOffset, int $yOffset, int $zOffset, int $xSize, int $ySize, int $zSize, float $xScale, float $yScale, float $zScale) 44 | { 45 | 46 | if ($noiseArray == null) { 47 | $noiseArray = []; 48 | } else { 49 | for ($i = 0; $i < count($noiseArray); ++$i) { 50 | $noiseArray[$i] = 0.0; 51 | } 52 | } 53 | 54 | $d3 = 1.0; 55 | 56 | 57 | for ($j = 0; $j < $this->octaves; ++$j) { 58 | 59 | $d0 = $xOffset * $d3 * $xScale; 60 | $d1 = $yOffset * $d3 * $yScale; 61 | $d2 = $zOffset * $d3 * $zScale; 62 | 63 | $k = floor($d0); 64 | 65 | $l = floor($d2); 66 | 67 | $d0 = $d0 - ((float)$k); 68 | 69 | $d2 = $d2 - ((float)$l); 70 | 71 | $k = $k % 16777216; 72 | 73 | $l = $l % 16777216; 74 | 75 | $d0 = $d0 + ((float)$k); 76 | 77 | $d2 = $d2 + ((float)$l); 78 | 79 | $this->generatorCollection[$j]->populateNoiseArray($noiseArray, $d0, $d1, $d2, $xSize, $ySize, $zSize, $xScale * $d3, $yScale * $d3, $zScale * $d3, $d3); 80 | 81 | $d3 /= 2.0; 82 | } 83 | 84 | 85 | return $noiseArray; 86 | } 87 | 88 | } -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/noise/PerlinF.php: -------------------------------------------------------------------------------- 1 | offsetX = $random->nextFloat() * 256; 23 | $this->offsetY = $random->nextFloat() * 256; 24 | $this->offsetZ = $random->nextFloat() * 256; 25 | $this->permutations = []; 26 | for ($i = 0; $i < 256; ++$i) { 27 | $this->permutations[$i] = $random->nextBoundedInt(256); 28 | } 29 | for ($i = 0; $i < 256; ++$i) { 30 | $pos = $random->nextBoundedInt(256 - $i) + $i; 31 | $old = $this->permutations[$i]; 32 | $this->permutations[$i] = $this->permutations[$pos]; 33 | $this->permutations[$pos] = $old; 34 | $this->permutations[$i + 256] = $this->permutations[$i]; 35 | } 36 | } 37 | 38 | #[Pure] 39 | public function getNoise2D($x, $y): float 40 | { 41 | return $this->getNoise3D($x, $y, 0); 42 | } 43 | 44 | #[Pure] 45 | public function getNoise3D($x, $y, $z): float 46 | { 47 | $x += $this->offsetX; 48 | $y += $this->offsetY; 49 | $z += $this->offsetZ; 50 | 51 | $floorX = (int)$x; 52 | $floorY = (int)$y; 53 | $floorZ = (int)$z; 54 | 55 | $x1 = $floorX & 0xFF; 56 | $y1 = $floorY & 0xFF; 57 | $z1 = $floorZ & 0xFF; 58 | 59 | $x -= $floorX; 60 | $y -= $floorY; 61 | $z -= $floorZ; 62 | 63 | //Fade curves 64 | //fX = fade(x); 65 | //fY = fade(y); 66 | //fZ = fade(z); 67 | $fX = $x * $x * $x * ($x * ($x * 6 - 15) + 10); 68 | $fY = $y * $y * $y * ($y * ($y * 6 - 15) + 10); 69 | $fZ = $z * $z * $z * ($z * ($z * 6 - 15) + 10); 70 | 71 | //Cube corners 72 | $A = $this->permutations[$x1] + $y1; 73 | $B = $this->permutations[$x1 + 1] + $y1; 74 | 75 | $AA = $this->permutations[$A] + $z1; 76 | $AB = $this->permutations[$A + 1] + $z1; 77 | $BA = $this->permutations[$B] + $z1; 78 | $BB = $this->permutations[$B + 1] + $z1; 79 | 80 | $AA1 = self::grad($this->permutations[$AA], $x, $y, $z); 81 | $BA1 = self::grad($this->permutations[$BA], $x - 1, $y, $z); 82 | $AB1 = self::grad($this->permutations[$AB], $x, $y - 1, $z); 83 | $BB1 = self::grad($this->permutations[$BB], $x - 1, $y - 1, $z); 84 | $AA2 = self::grad($this->permutations[$AA + 1], $x, $y, $z - 1); 85 | $BA2 = self::grad($this->permutations[$BA + 1], $x - 1, $y, $z - 1); 86 | $AB2 = self::grad($this->permutations[$AB + 1], $x, $y - 1, $z - 1); 87 | $BB2 = self::grad($this->permutations[$BB + 1], $x - 1, $y - 1, $z - 1); 88 | 89 | $xLerp11 = $AA1 + $fX * ($BA1 - $AA1); 90 | 91 | $zLerp1 = $xLerp11 + $fY * ($AB1 + $fX * ($BB1 - $AB1) - $xLerp11); 92 | 93 | $xLerp21 = $AA2 + $fX * ($BA2 - $AA2); 94 | 95 | return $zLerp1 + $fZ * ($xLerp21 + $fY * ($AB2 + $fX * ($BB2 - $AB2) - $xLerp21) - $zLerp1); 96 | } 97 | 98 | public static function grad($hash, $x, $y, $z): float 99 | { 100 | $hash &= 15; 101 | $u = $hash < 8 ? $x : $y; 102 | $v = $hash < 4 ? $y : (($hash === 12 || $hash === 14) ? $x : 103 | $z); 104 | 105 | return (($hash & 1) === 0 ? $u : -$u) + (($hash & 2) === 0 ? $v : -$v); 106 | } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/noise/PerlinNoiseGenerator.php: -------------------------------------------------------------------------------- 1 | levels = $p_i45470_2_; 16 | $this->noiseLevels = new SimplexF($p_i45470_2_$p_i45470_2_); 17 | 18 | for ($i = 0; $i < $p_i45470_2_; ++$i) { 19 | $this->noiseLevels[$i] = new SimplexF($p_i45470_1_$p_i45470_1_); 20 | } 21 | } 22 | 23 | public function getValue(float $p_151601_1_, float $p_151601_3_): float 24 | { 25 | $d0 = 0.0; 26 | $d1 = 1.0; 27 | 28 | for ($i = 0; $i < $this->levels; ++$i) { 29 | $d0 += $this->noiseLevels[$i]->getValue($p_151601_1_ * $d1, $p_151601_3_ * $d1) / $d1; 30 | $d1 /= 2.0; 31 | } 32 | 33 | return $d0; 34 | } 35 | 36 | public function getRegion(array $p_151600_1_, float $p_151600_2_, float $p_151600_4_, int $p_151600_6_, int $p_151600_7_, float $p_151600_8_, float $p_151600_10_, float $p_151600_12_, float $p_151600_14_ = 0.5) 37 | { 38 | if ($p_151600_1_ !== null && count($p_151600_1_) >= $p_151600_6_ * $p_151600_7_) { 39 | for ($i = 0; $i < count($p_151600_1_); ++$i) { 40 | $p_151600_1_[$i] = 0.0; 41 | } 42 | } else { 43 | $p_151600_1_ = []; 44 | } 45 | 46 | $d1 = 1.0; 47 | $d0 = 1.0; 48 | 49 | for ($j = 0; $j < $this->levels; ++$j) { 50 | $this->noiseLevels[$j]->add($p_151600_1_, $p_151600_2_, $p_151600_4_, $p_151600_6_, $p_151600_7_, $p_151600_8_ * $d0 * $d1, $p_151600_10_ * $d0 * $d1, 0.55 / $d1); 51 | $d0 *= $p_151600_12_; 52 | $d1 *= $p_151600_14_; 53 | } 54 | 55 | return $p_151600_1_; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/noise/SimplexF.php: -------------------------------------------------------------------------------- 1 | $d10) { 36 | $k = 1; 37 | $l = 0; 38 | } else { 39 | $k = 0; 40 | $l = 1; 41 | } 42 | 43 | $d11 = $d9 - (float)$k + $d5; 44 | $d12 = $d10 - (float)$l + $d5; 45 | $d13 = $d9 - 1.0 + 2.0 * $d5; 46 | $d14 = $d10 - 1.0 + 2.0 * $d5; 47 | $i1 = $i & 255; 48 | $j1 = $j & 255; 49 | $k1 = $this->permutations[$i1 + $this->permutations[$j1]] % 12; 50 | $l1 = $this->permutations[$i1 + $k + $this->permutations[$j1 + $l]] % 12; 51 | $i2 = $this->permutations[$i1 + 1 + $this->permutations[$j1 + 1]] % 12; 52 | $d15 = 0.5 - $d9 * $d9 - $d10 * $d10; 53 | $d0 = 0.0; 54 | 55 | if ($d15 < 0.0) { 56 | $d0 = 0.0; 57 | } else { 58 | $d15 = $d15 * $d15; 59 | $d0 = $d15 * $d15 * self::dot(self::grad3[$k1], $d9, $d10); 60 | } 61 | 62 | $d16 = 0.5 - $d11 * $d11 - $d12 * $d12; 63 | 64 | if ($d16 < 0.0) { 65 | $d1 = 0.0; 66 | } else { 67 | $d16 = $d16 * $d16; 68 | $d1 = $d16 * $d16 * self::dot(self::grad3[$l1], $d11, $d12); 69 | } 70 | 71 | $d17 = 0.5 - $d13 * $d13 - $d14 * $d14; 72 | 73 | if ($d17 < 0.0) { 74 | $d2 = 0.0; 75 | } else { 76 | $d17 = $d17 * $d17; 77 | $d2 = $d17 * $d17 * self::dot(self::grad3[$i2], $d13, $d14); 78 | } 79 | 80 | return 70.0 * ($d0 + $d1 + $d2); 81 | } 82 | 83 | private static function fastFloor(float $value): int 84 | { 85 | return $value > 0.0 ? (int)$value : (int)$value - 1; 86 | } 87 | 88 | private static function dot(array $p_151604_0_, float $p_151604_1_, float $p_151604_3_): float 89 | { 90 | return (float)$p_151604_0_[0] * $p_151604_1_ + (float)$p_151604_0_[1] * $p_151604_3_; 91 | } 92 | 93 | public function add(array &$p_151606_1_, float $p_151606_2_, float $p_151606_4_, int $p_151606_6_, int $p_151606_7_, float $p_151606_8_, float $p_151606_10_, float $p_151606_12_) 94 | { 95 | 96 | $i = 0; 97 | 98 | for ($j = 0; $j < $p_151606_7_; ++$j) { 99 | 100 | $d0 = ($p_151606_4_ + (float)$j) * $p_151606_10_ + $this->offsetY; 101 | 102 | for ($k = 0; $k < $p_151606_6_; ++$k) { 103 | $d1 = ($p_151606_2_ + (float)$k) * $p_151606_8_ + $this->offsetX; 104 | $d5 = ($d1 + $d0) * self::F2; 105 | $l = self::fastFloor($d1 + $d5); 106 | $i1 = self::fastFloor($d0 + $d5); 107 | $d6 = (float)($l + $i1) * self::G2; 108 | $d7 = (float)$l - $d6; 109 | $d8 = (float)$i1 - $d6; 110 | $d9 = $d1 - $d7; 111 | $d10 = $d0 - $d8; 112 | 113 | $j1 = 0; 114 | $k1 = 0; 115 | 116 | if ($d9 > $d10) { 117 | $j1 = 1; 118 | $k1 = 0; 119 | } else { 120 | $j1 = 0; 121 | $k1 = 1; 122 | } 123 | 124 | $d11 = $d9 - (float)$j1 + self::G2; 125 | $d12 = $d10 - (float)$k1 + self::G2; 126 | $d13 = $d9 - 1.0 + 2.0 * self::G2; 127 | $d14 = $d10 - 1.0 + 2.0 * self::G2; 128 | $l1 = $l & 255; 129 | $i2 = $i1 & 255; 130 | $j2 = $this->permutations[$l1 + $this->permutations[$i2]] % 12; 131 | $k2 = $this->permutations[$l1 + $j1 + $this->permutations[$i2 + $k1]] % 12; 132 | $l2 = $this->permutations[$l1 + 1 + $this->permutations[$i2 + 1]] % 12; 133 | $d15 = 0.5 - $d9 * $d9 - $d10 * $d10; 134 | 135 | $d2 = 0.0; 136 | 137 | if ($d15 < 0.0) { 138 | $d2 = 0.0; 139 | } else { 140 | $d15 = $d15 * $d15; 141 | $d2 = $d15 * $d15 * self::dot(self::grad3[$j2], $d9, $d10); 142 | } 143 | 144 | $d16 = 0.5 - $d11 * $d11 - $d12 * $d12; 145 | $d3 = 0.0; 146 | 147 | if ($d16 < 0.0) { 148 | $d3 = 0.0; 149 | } else { 150 | $d16 = $d16 * $d16; 151 | $d3 = $d16 * $d16 * self::dot(self::grad3[$k2], $d11, $d12); 152 | } 153 | 154 | $d17 = 0.5 - $d13 * $d13 - $d14 * $d14; 155 | $d4 = 0.0; 156 | 157 | if ($d17 < 0.0) { 158 | $d4 = 0.0; 159 | } else { 160 | $d17 = $d17 * $d17; 161 | $d4 = $d17 * $d17 * self::dot(self::grad3[$l2], $d13, $d14); 162 | } 163 | 164 | $i3 = $i++; 165 | $p_151606_1_[$i3] += 70.0 * ($d2 + $d3 + $d4) * $p_151606_12_; 166 | } 167 | } 168 | } 169 | 170 | } 171 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/object/AcaciaTree.php: -------------------------------------------------------------------------------- 1 | nextBoundedInt(3) + $rand->nextBoundedInt(3) + 5; 20 | $flag = true; 21 | 22 | if ($y >= 1 && $y + $i + 1 <= 256) { 23 | for ($j = $y; $j <= $y + 1 + $i; ++$j) { 24 | $k = 1; 25 | 26 | if ($j === $y) { 27 | $k = 0; 28 | } 29 | 30 | if ($j >= $y + 1 + $i - 2) { 31 | $k = 2; 32 | } 33 | 34 | $vector3 = new Vector3(); 35 | 36 | for ($l = (int)$x - $k; $l <= $x + $k && $flag; ++$l) { 37 | for ($i1 = (int)$z - $k; $i1 <= $z + $k && $flag; ++$i1) { 38 | if ($j >= 0 && $j < 256) { 39 | 40 | $vector3->setComponents($l, $j, $i1); 41 | if (!$this->canOverride(Block::get($level->getBlockIdAt((int)$vector3->x, (int)$vector3->y, (int)$vector3->z)))) { 42 | $flag = false; 43 | } 44 | } else { 45 | $flag = false; 46 | } 47 | } 48 | } 49 | } 50 | 51 | if (!$flag) { 52 | return; 53 | } else { 54 | $block = $level->getBlockIdAt($x, $y - 1, $z); 55 | 56 | if (($block === Block::GRASS || $block === Block::DIRT) && $y < 256 - $i - 1) { 57 | 58 | $level->setBlockIdAt($x, $y - 1, $z, Block::DIRT); 59 | 60 | $face = FacingHelper::HORIZONTAL[$rand->nextBoundedInt(4)]; 61 | $k2 = $i - $rand->nextBoundedInt(4) - 1; 62 | $l2 = 3 - $rand->nextBoundedInt(3); 63 | $i3 = $x; 64 | $j1 = $z; 65 | $k1 = 0; 66 | 67 | for ($l1 = 0; $l1 < $i; ++$l1) { 68 | $i2 = $y + $l1; 69 | 70 | if ($l1 >= $k2 && $l2 > 0) { 71 | $i3 += FacingHelper::xOffset($face); 72 | $j1 += FacingHelper::zOffset($face); // z; 73 | $i3 += mt_rand(-1, 1); 74 | $j1 += mt_rand(-1, 1); 75 | --$l2; 76 | } 77 | 78 | $blockpos = new Vector3($i3, $i2, $j1); 79 | $material = $level->getBlockIdAt($blockpos->getFloorX(), $blockpos->getFloorY(), $blockpos->getFloorZ()); 80 | 81 | if ($material === Block::AIR || $material === Block::LEAVES) { 82 | $this->placeLogAt($level, $blockpos); 83 | $k1 = $i2; 84 | } 85 | } 86 | 87 | $blockpos2 = new Vector3($i3, $k1, $j1); 88 | 89 | for ($j3 = -3; $j3 <= 3; ++$j3) { 90 | for ($i4 = -3; $i4 <= 3; ++$i4) { 91 | if (abs($j3) !== 3 || abs($i4) !== 3) { 92 | $this->placeLeafAt($level, $blockpos2->add($j3, 0, $i4)); 93 | } 94 | } 95 | } 96 | 97 | $blockpos2 = $blockpos2->up(); 98 | 99 | for ($k3 = -1; $k3 <= 1; ++$k3) { 100 | for ($j4 = -1; $j4 <= 1; ++$j4) { 101 | $this->placeLeafAt($level, $blockpos2->add($k3, 0, $j4)); 102 | } 103 | } 104 | 105 | $this->placeLeafAt($level, $blockpos2->east(2)); 106 | $this->placeLeafAt($level, $blockpos2->west(2)); 107 | $this->placeLeafAt($level, $blockpos2->south(2)); 108 | $this->placeLeafAt($level, $blockpos2->north(2)); 109 | $i3 = $x; 110 | $j1 = $z; 111 | $face1 = FacingHelper::HORIZONTAL[$rand->nextBoundedInt(4)]; 112 | 113 | if ($face1 != $face) { 114 | $l3 = $k2 - $rand->nextBoundedInt(2) - 1; 115 | $k4 = 1 + $rand->nextBoundedInt(3); 116 | $k1 = 0; 117 | 118 | for ($l4 = $l3; $l4 < $i && $k4 > 0; --$k4) { 119 | if ($l4 >= 1) { 120 | $j2 = $y + $l4; 121 | $i3 += FacingHelper::xOffset($face); 122 | $j1 += FacingHelper::zOffset($face); 123 | $blockpos1 = new Vector3($i3, $j2, $j1); 124 | $material1 = $level->getBlockIdAt($blockpos1->getFloorX(), $blockpos1->getFloorY(), $blockpos1->getFloorZ()); 125 | 126 | if ($material1 === Block::AIR || $material1 === Block::LEAVES) { 127 | $this->placeLogAt($level, $blockpos1); 128 | $k1 = $j2; 129 | } 130 | } 131 | 132 | ++$l4; 133 | } 134 | 135 | if ($k1 > 0) { 136 | $blockpos3 = new Vector3($i3, $k1, $j1); 137 | 138 | for ($i5 = -2; $i5 <= 2; ++$i5) { 139 | for ($k5 = -2; $k5 <= 2; ++$k5) { 140 | if (abs($i5) != 2 || abs($k5) != 2) { 141 | $this->placeLeafAt($level, $blockpos3->add($i5, 0, $k5)); 142 | } 143 | } 144 | } 145 | 146 | $blockpos3 = $blockpos3->up(); 147 | 148 | for ($j5 = -1; $j5 <= 1; ++$j5) { 149 | for ($l5 = -1; $l5 <= 1; ++$l5) { 150 | $this->placeLeafAt($level, $blockpos3->add($j5, 0, $l5)); 151 | } 152 | } 153 | } 154 | } 155 | 156 | return; 157 | } else { 158 | return; 159 | } 160 | } 161 | } 162 | } 163 | 164 | private function placeLogAt(ChunkManager $level, Vector3 $pos): void 165 | { 166 | $level->setBlockIdAt($pos->x, $pos->y, $pos->z, $this->trunkBlock); 167 | $level->setBlockDataAt($pos->x, $pos->y, $pos->z, 3); 168 | } 169 | 170 | private function placeLeafAt(ChunkManager $worldIn, Vector3 $pos): void 171 | { 172 | $material = $worldIn->getBlockIdAt($pos->x, $pos->y, $pos->z); 173 | 174 | if ($material === Block::AIR || $material === Block::LEAVES) { 175 | $worldIn->setBlockIdAt($pos->x, $pos->y, $pos->z, $this->leafBlock); 176 | $worldIn->setBlockDataAt($pos->x, $pos->y, $pos->z, $this->blockMeta); 177 | } 178 | } 179 | 180 | } -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/object/BasicGenerator.php: -------------------------------------------------------------------------------- 1 | setBlock($level, $pos, $state); 23 | } 24 | 25 | //what autism is this? why are we using floating-point vectors for setting block IDs? 26 | protected function setBlock(ChunkManager $level, Vector3 $v, Block $b): void 27 | { 28 | $level->setBlockIdAt((int)$v->x, (int)$v->y, (int)$v->z, $b->getId()); 29 | $level->setBlockDataAt((int)$v->x, (int)$v->y, (int)$v->z, $b->getVariant()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/object/BigJungleTree.php: -------------------------------------------------------------------------------- 1 | getHeight($rand); 21 | 22 | if (!$this->ensureGrowable($level, $rand, $position, $height)) { 23 | return false; 24 | } else { 25 | $this->createCrown($level, $position->up($height), 2); 26 | 27 | for ($j = (int)$position->getY() + $height - 2 - $rand->nextBoundedInt(4); $j > $position->getY() + $height / 2; $j -= 2 + $rand->nextBoundedInt(4)) { 28 | $f = $rand->nextFloat() * ((float)M_PI * 2.0); 29 | $k = (int)($position->getX() + (0.5 + cos($f) * 4.0)); 30 | $l = (int)($position->getZ() + (0.5 + sin($f) * 4.0)); 31 | 32 | for ($i1 = 0; $i1 < 5; ++$i1) { 33 | $k = (int)($position->getX() + (1.5 + cos($f) * (float)$i1)); 34 | $l = (int)($position->getZ() + (1.5 + sin($f) * (float)$i1)); 35 | $this->setBlockAndNotifyAdequately($level, new Vector3($k, $j - 3 + $i1 / 2, $l), $this->woodMetadata); 36 | } 37 | 38 | $j2 = 1 + $rand->nextBoundedInt(2); 39 | $j1 = $j; 40 | 41 | for ($k1 = $j - $j2; $k1 <= $j1; ++$k1) { 42 | $l1 = $k1 - $j1; 43 | $this->growLeavesLayer($level, new Vector3($k, $k1, $l), 1 - $l1); 44 | } 45 | } 46 | 47 | for ($i2 = 0; $i2 < $height; ++$i2) { 48 | $blockpos = $position->up($i2); 49 | 50 | if ($this->canOverride(Block::get($level->getBlockIdAt($blockpos->x, $blockpos->y, $blockpos->z)))) { 51 | $this->setBlockAndNotifyAdequately($level, $blockpos, $this->woodMetadata); 52 | 53 | if ($i2 > 0) { 54 | $this->placeVine($level, $rand, $blockpos->west(), 8); 55 | $this->placeVine($level, $rand, $blockpos->north(), 1); 56 | } 57 | } 58 | 59 | if ($i2 < $height - 1) { 60 | $blockpos1 = $blockpos->east(); 61 | 62 | if ($this->canOverride(Block::get($level->getBlockIdAt((int)$blockpos1->x, (int)$blockpos1->y, (int)$blockpos1->z)))) { 63 | $this->setBlockAndNotifyAdequately($level, $blockpos1, $this->woodMetadata); 64 | 65 | if ($i2 > 0) { 66 | $this->placeVine($level, $rand, $blockpos1->east(), 2); 67 | $this->placeVine($level, $rand, $blockpos1->north(), 1); 68 | } 69 | } 70 | 71 | $blockpos2 = $blockpos->south()->east(); 72 | 73 | if ($this->canOverride(Block::get($level->getBlockIdAt((int)$blockpos2->x, (int)$blockpos2->y, (int)$blockpos2->z)))) { 74 | $this->setBlockAndNotifyAdequately($level, $blockpos2, $this->woodMetadata); 75 | 76 | if ($i2 > 0) { 77 | $this->placeVine($level, $rand, $blockpos2->east(), 2); 78 | $this->placeVine($level, $rand, $blockpos2->south(), 4); 79 | } 80 | } 81 | 82 | $blockpos3 = $blockpos->south(); 83 | 84 | if ($this->canOverride(Block::get($level->getBlockIdAt((int)$blockpos3->x, (int)$blockpos3->y, (int)$blockpos3->z)))) { 85 | $this->setBlockAndNotifyAdequately($level, $blockpos3, $this->woodMetadata); 86 | 87 | if ($i2 > 0) { 88 | $this->placeVine($level, $rand, $blockpos3->west(), 8); 89 | $this->placeVine($level, $rand, $blockpos3->south(), 4); 90 | } 91 | } 92 | } 93 | } 94 | 95 | return true; 96 | } 97 | } 98 | 99 | private function createCrown(ChunkManager $level, Vector3 $pos, int $i1): void 100 | { 101 | for ($j = -2; $j <= 0; ++$j) { 102 | $this->growLeavesLayerStrict($level, $pos->up($j), $i1 + 1 - $j); 103 | } 104 | } 105 | 106 | private function placeVine(ChunkManager $level, Random $random, Vector3 $pos, int $meta): void 107 | { 108 | if ($random->nextBoundedInt(3) > 0 && $level->getBlockIdAt((int)$pos->x, (int)$pos->y, (int)$pos->z) === 0) { 109 | $this->setBlockAndNotifyAdequately($level, $pos, Block::get(Block::VINE, $meta)); 110 | } 111 | } 112 | 113 | } 114 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/object/BigSpruceTree.php: -------------------------------------------------------------------------------- 1 | leafStartHeightMultiplier = $leafStartHeightMultiplier; 26 | $this->baseLeafRadius = $baseLeafRadius; 27 | } 28 | 29 | public function generateTrunkHeight(Random $random): int 30 | { 31 | return $this->treeHeight = $random->nextBoundedInt(15) + 20; 32 | } 33 | 34 | public function getBlockTransaction(ChunkManager $world, int $x, int $y, int $z, Random $random) : ?BlockTransaction{ 35 | $this->topSize = $this->treeHeight - (int)($this->treeHeight * $this->leafStartHeightMultiplier); 36 | $this->lRadius = $this->baseLeafRadius + $random->nextBoundedInt(2); 37 | 38 | return parent::getBlockTransaction($world, $x, $y, $z, $random); 39 | } 40 | 41 | public function placeTrunk(int $x, int $y, int $z, Random $random, int $trunkHeight, BlockTransaction $transaction): void 42 | { 43 | $transaction->addBlockAt($x, $y - 1, $z, VanillaBlocks::DIRT()); 44 | $radius = 2; 45 | 46 | for ($yy = 0; $yy < $trunkHeight; ++$yy) { 47 | for ($xx = 0; $xx < $radius; $xx++) { 48 | for ($zz = 0; $zz < $radius; $zz++) { 49 | $block = $transaction->fetchBlockAt($x, $y + $yy, $z); 50 | if ($this->canOverride($block)) { 51 | $transaction->addBlockAt($x + $xx, $y + $yy, $z + $zz, $this->trunkBlock); 52 | } 53 | } 54 | } 55 | } 56 | } 57 | 58 | protected function placeCanopy(int $x, int $y, int $z, Random $random, BlockTransaction $transaction) : void{ 59 | $radius = $random->nextBoundedInt(2); 60 | $maxR = 1; 61 | $minR = 0; 62 | 63 | for ($yy = 0; $yy <= $this->topSize; ++$yy) { 64 | $yyy = $y + $this->treeHeight - $yy; 65 | 66 | for ($xx = $x - $radius; $xx <= $x + $radius; ++$xx) { 67 | $xOff = abs($xx - $x); 68 | for ($zz = $z - $radius; $zz <= $z + $radius; ++$zz) { 69 | $zOff = abs($zz - $z); 70 | if ($xOff === $radius && $zOff === $radius && $radius > 0) { 71 | continue; 72 | } 73 | 74 | if ($this->canOverride($transaction->fetchBlockAt($xx, $yyy, $zz))) { 75 | $transaction->addBlockAt($xx, $yyy, $zz, $this->leafBlock); 76 | } 77 | } 78 | } 79 | 80 | if ($radius >= $maxR) { 81 | $radius = $minR; 82 | $minR = 1; 83 | if (++$maxR > $this->lRadius) { 84 | $maxR = $this->lRadius; 85 | } 86 | } else { 87 | ++$radius; 88 | } 89 | } 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/object/CustomTree.php: -------------------------------------------------------------------------------- 1 | nextBoundedInt(3) + $rand->nextBoundedInt(2) + 6; 30 | $j = $position->getFloorX(); 31 | $k = $position->getFloorY(); 32 | $l = $position->getFloorZ(); 33 | 34 | if ($k >= 1 && $k + $i + 1 < 256) { 35 | $blockpos = $position->down(); 36 | $block = $level->getBlockIdAt($blockpos->getFloorX(), $blockpos->getFloorY(), $blockpos->getFloorZ()); 37 | 38 | if ($block !== Block::GRASS && $block !== Block::DIRT) { 39 | return false; 40 | } elseif (!$this->placeTreeOfHeight($level, $position, $i)) { 41 | return false; 42 | } else { 43 | $this->setDirtAt($level, $blockpos); 44 | $this->setDirtAt($level, $blockpos->east()); 45 | $this->setDirtAt($level, $blockpos->south()); 46 | $this->setDirtAt($level, $blockpos->south()->east()); 47 | $face = FacingHelper::HORIZONTAL[$rand->nextBoundedInt(3)]; 48 | $i1 = $i - $rand->nextBoundedInt(4); 49 | $j1 = 2 - $rand->nextBoundedInt(3); 50 | $k1 = $j; 51 | $l1 = $l; 52 | $i2 = $k + $i - 1; 53 | 54 | for ($j2 = 0; $j2 < $i; ++$j2) { 55 | if ($j2 >= $i1 && $j1 > 0) { 56 | $k1 += FacingHelper::xOffset($face); 57 | $l1 += FacingHelper::zOffset($face); 58 | --$j1; 59 | } 60 | 61 | $k2 = $k + $j2; 62 | $blockpos1 = new Vector3($k1, $k2, $l1); 63 | $material = $level->getBlockIdAt($blockpos1->getFloorX(), $blockpos1->getFloorY(), $blockpos1->getFloorZ()); 64 | 65 | if ($material === Block::AIR || $material === Block::LEAVES) { 66 | $this->placeLogAt($level, $blockpos1); 67 | $this->placeLogAt($level, $blockpos1->east()); 68 | $this->placeLogAt($level, $blockpos1->south()); 69 | $this->placeLogAt($level, $blockpos1->east()->south()); 70 | } 71 | } 72 | 73 | for ($i3 = -2; $i3 <= 0; ++$i3) { 74 | for ($l3 = -2; $l3 <= 0; ++$l3) { 75 | $k4 = -1; 76 | place_leaves: 77 | $this->placeLeafAt($level, $k1 + $i3, $i2 + $k4, $l1 + $l3); 78 | $this->placeLeafAt($level, 1 + $k1 - $i3, $i2 + $k4, $l1 + $l3); 79 | $this->placeLeafAt($level, $k1 + $i3, $i2 + $k4, 1 + $l1 - $l3); 80 | $this->placeLeafAt($level, 1 + $k1 - $i3, $i2 + $k4, 1 + $l1 - $l3); 81 | 82 | if (($i3 > -2 || $l3 > -1) && ($i3 != -1 || $l3 != -2) && $k4 < 0) { 83 | $k4 = 1; 84 | goto place_leaves; 85 | } 86 | } 87 | } 88 | 89 | if ($rand->nextBoolean()) { 90 | $this->placeLeafAt($level, $k1, $i2 + 2, $l1); 91 | $this->placeLeafAt($level, $k1 + 1, $i2 + 2, $l1); 92 | $this->placeLeafAt($level, $k1 + 1, $i2 + 2, $l1 + 1); 93 | $this->placeLeafAt($level, $k1, $i2 + 2, $l1 + 1); 94 | } 95 | 96 | for ($j3 = -3; $j3 <= 4; ++$j3) { 97 | for ($i4 = -3; $i4 <= 4; ++$i4) { 98 | if (($j3 != -3 || $i4 != -3) && ($j3 != -3 || $i4 != 4) && ($j3 != 4 || $i4 != -3) && ($j3 != 4 || $i4 != 4) && (abs($j3) < 3 || abs($i4) < 3)) { 99 | $this->placeLeafAt($level, $k1 + $j3, $i2, $l1 + $i4); 100 | } 101 | } 102 | } 103 | 104 | for ($k3 = -1; $k3 <= 2; ++$k3) { 105 | for ($j4 = -1; $j4 <= 2; ++$j4) { 106 | if (($k3 < 0 || $k3 > 1 || $j4 < 0 || $j4 > 1) && $rand->nextBoundedInt(3) <= 0) { 107 | $l4 = $rand->nextBoundedInt(3) + 2; 108 | 109 | for ($i5 = 0; $i5 < $l4; ++$i5) { 110 | $this->placeLogAt($level, new Vector3($j + $k3, $i2 - $i5 - 1, $l + $j4)); 111 | } 112 | 113 | for ($j5 = -1; $j5 <= 1; ++$j5) { 114 | for ($l2 = -1; $l2 <= 1; ++$l2) { 115 | $this->placeLeafAt($level, $k1 + $k3 + $j5, $i2, $l1 + $j4 + $l2); 116 | } 117 | } 118 | 119 | for ($k5 = -2; $k5 <= 2; ++$k5) { 120 | for ($l5 = -2; $l5 <= 2; ++$l5) { 121 | if (abs($k5) != 2 || abs($l5) != 2) { 122 | $this->placeLeafAt($level, $k1 + $k3 + $k5, $i2 - 1, $l1 + $j4 + $l5); 123 | } 124 | } 125 | } 126 | } 127 | } 128 | } 129 | 130 | return true; 131 | } 132 | } else { 133 | return false; 134 | } 135 | } 136 | 137 | protected function placeTreeOfHeight(ChunkManager $worldIn, Vector3 $pos, int $height): bool 138 | { 139 | $i = $pos->getFloorX(); 140 | $j = $pos->getFloorY(); 141 | $k = $pos->getFloorZ(); 142 | $p2 = new Vector3(); 143 | 144 | for ($l = 0; $l <= $height + 1; ++$l) { 145 | $i1 = 1; 146 | 147 | if ($l === 0) { 148 | $i1 = 0; 149 | } 150 | 151 | if ($l >= $height - 1) { 152 | $i1 = 2; 153 | } 154 | 155 | for ($j1 = -$i1; $j1 <= $i1; ++$j1) { 156 | for ($k1 = -$i1; $k1 <= $i1; ++$k1) { 157 | $p2->setComponents($i + $j1, $j + $l, $k + $k1); 158 | if (!$this->canOverride(Block::get($worldIn->getBlockIdAt($p2->getX(), $p2->getY(), $p2->getZ())))) { 159 | return false; 160 | } 161 | } 162 | } 163 | } 164 | 165 | return true; 166 | } 167 | 168 | public function setDirtAt(ChunkManager $level, Vector3 $pos): void 169 | { 170 | $level->setBlockIdAt($pos->x, $pos->y, $pos->z, Block::DIRT); 171 | } 172 | 173 | protected function placeLogAt(ChunkManager $worldIn, Vector3 $pos): void 174 | { 175 | if ($this->canOverride(Block::get($worldIn->getBlockIdAt($pos->getX(), $pos->getY(), $pos->getZ())))) { 176 | $this->setBlockAndNotifyAdequately($worldIn, $pos, Block::get(Block::LOG2, Wood2::DARK_OAK)); 177 | } 178 | } 179 | 180 | public function setBlockAndNotifyAdequately(ChunkManager $level, Vector3 $pos, Block $block): void 181 | { 182 | $level->setBlockIdAt($pos->x, $pos->y, $pos->z, $block->getId()); 183 | $level->setBlockDataAt($pos->x, $pos->y, $pos->z, $block->getDamage()); 184 | } 185 | 186 | protected function placeLeafAt(ChunkManager $worldIn, int $x, int $y, int $z): void 187 | { 188 | $material = $worldIn->getBlockIdAt($x, $y, $z); 189 | 190 | if ($material === Block::AIR) { 191 | $this->setBlockAndNotifyAdequately($worldIn, new Vector3($x, $y, $z), Block::get(Block::LEAVES2, $this->metaLeaves)); 192 | } 193 | } 194 | 195 | } 196 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/object/HugeTree.php: -------------------------------------------------------------------------------- 1 | treeHeight = $treeHeightIn; 27 | $this->extraRandomHeight = $extraRandomHeightIn; 28 | $this->woodMetadata = $woodMetadataIn; 29 | $this->leavesMetadata = $leavesMetadataIn; 30 | } 31 | 32 | /* 33 | * Calculates the height based on this trees base height and its extra random height 34 | */ 35 | protected function getHeight(Random $rand) 36 | { 37 | $i = $rand->nextBoundedInt(3) + $this->treeHeight; 38 | 39 | if ($this->extraRandomHeight > 1) { 40 | $i += $rand->nextBoundedInt($this->extraRandomHeight); 41 | } 42 | 43 | return $i; 44 | } 45 | 46 | /* 47 | * returns whether or not there is space for a tree to grow at a certain position 48 | */ 49 | 50 | protected function ensureGrowable(ChunkManager $worldIn, Random $rand, Vector3 $treePos, int $p_175929_4_): bool 51 | { 52 | return $this->isSpaceAt($worldIn, $treePos, $p_175929_4_) && $this->ensureDirtsUnderneath($treePos, $worldIn); 53 | } 54 | 55 | /* 56 | * returns whether or not there is dirt underneath the block where the tree will be grown. 57 | * It also generates dirt around the block in a 2x2 square if there is dirt underneath the blockpos. 58 | */ 59 | 60 | private function isSpaceAt(ChunkManager $worldIn, Vector3 $leavesPos, int $height): bool 61 | { 62 | $flag = true; 63 | 64 | if ($leavesPos->getY() >= 1 && $leavesPos->getY() + $height + 1 <= 256) { 65 | for ($i = 0; $i <= 1 + $height; ++$i) { 66 | $j = 2; 67 | 68 | if ($i == 0) { 69 | $j = 1; 70 | } elseif ($i >= 1 + $height - 2) { 71 | $j = 2; 72 | } 73 | 74 | for ($k = -$j; $k <= $j && $flag; ++$k) { 75 | for ($l = -$j; $l <= $j && $flag; ++$l) { 76 | $blockPos = $leavesPos->add($k, $i, $l); 77 | if ($leavesPos->getY() + $i < 0 || $leavesPos->getY() + $i >= 256 || !$this->canOverride(Block::get($worldIn->getBlockIdAt((int)$blockPos->x, (int)$blockPos->y, (int)$blockPos->z)))) { 78 | $flag = false; 79 | } 80 | } 81 | } 82 | } 83 | 84 | return $flag; 85 | } else { 86 | return false; 87 | } 88 | } 89 | 90 | protected function ensureDirtsUnderneath(Vector3 $pos, ChunkManager $worldIn): bool 91 | { 92 | $blockpos = $pos->down(); 93 | $block = $worldIn->getBlockIdAt((int)$blockpos->x, (int)$blockpos->y, (int)$blockpos->z); 94 | 95 | if (($block === Block::GRASS || $block === Block::DIRT) && $pos->getY() >= 2) { 96 | $this->setDirtAt($worldIn, $blockpos); 97 | $this->setDirtAt($worldIn, $blockpos->east()); 98 | $this->setDirtAt($worldIn, $blockpos->south()); 99 | $this->setDirtAt($worldIn, $blockpos->south()->east()); 100 | return true; 101 | } else { 102 | return false; 103 | } 104 | } 105 | 106 | /* 107 | * returns whether or not a tree can grow at a specific position. 108 | * If it can, it generates surrounding dirt underneath. 109 | */ 110 | 111 | public function setDirtAt(ChunkManager $level, Vector3 $pos): void 112 | { 113 | $level->setBlockIdAt($pos->x, $pos->y, $pos->z, Block::DIRT); 114 | } 115 | 116 | /* 117 | * grow leaves in a circle with the outsides being within the circle 118 | */ 119 | 120 | protected function growLeavesLayerStrict(ChunkManager $worldIn, Vector3 $layerCenter, int $width): void 121 | { 122 | $i = $width * $width; 123 | 124 | for ($j = -$width; $j <= $width + 1; ++$j) { 125 | for ($k = -$width; $k <= $width + 1; ++$k) { 126 | $l = $j - 1; 127 | $i1 = $k - 1; 128 | 129 | if ($j * $j + $k * $k <= $i || $l * $l + $i1 * $i1 <= $i || $j * $j + $i1 * $i1 <= $i || $l * $l + $k * $k <= $i) { 130 | $blockpos = $layerCenter->add($j, 0, $k); 131 | $id = $worldIn->getBlockIdAt((int)$blockpos->x, (int)$blockpos->y, (int)$blockpos->z); 132 | 133 | if ($id === Block::AIR || $id === Block::LEAVES) { 134 | $this->setBlockAndNotifyAdequately($worldIn, $blockpos, $this->leavesMetadata); 135 | } 136 | } 137 | } 138 | } 139 | } 140 | 141 | /* 142 | * grow leaves in a circle 143 | */ 144 | 145 | public function setBlockAndNotifyAdequately(ChunkManager $level, Vector3 $pos, Block $block): void 146 | { 147 | $level->setBlockIdAt($pos->x, $pos->y, $pos->z, $block->getId()); 148 | $level->setBlockDataAt($pos->x, $pos->y, $pos->z, $block->getDamage()); 149 | } 150 | 151 | protected function growLeavesLayer(ChunkManager $worldIn, Vector3 $layerCenter, int $width) 152 | { 153 | $i = $width * $width; 154 | 155 | for ($j = -$width; $j <= $width; ++$j) { 156 | for ($k = -$width; $k <= $width; ++$k) { 157 | if ($j * $j + $k * $k <= $i) { 158 | $blockpos = $layerCenter->add($j, 0, $k); 159 | $id = $worldIn->getBlockIdAt((int)$blockpos->x, (int)$blockpos->y, (int)$blockpos->z); 160 | 161 | if ($id === Block::AIR || $id === Block::LEAVES) { 162 | $this->setBlockAndNotifyAdequately($worldIn, $blockpos, $this->leavesMetadata); 163 | } 164 | } 165 | } 166 | } 167 | } 168 | 169 | } 170 | 171 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/object/NewJungleTree.php: -------------------------------------------------------------------------------- 1 | minTreeHeight = $minTreeHeight; 37 | $this->maxTreeHeight = $maxTreeHeight; 38 | } 39 | 40 | public function generate(ChunkManager $worldIn, Random $rand, Vector3 $vectorPosition): bool 41 | { 42 | $position = new Vector3($vectorPosition->getFloorX(), $vectorPosition->getFloorY(), $vectorPosition->getFloorZ()); 43 | 44 | $i = $rand->nextBoundedInt($this->maxTreeHeight) + $this->minTreeHeight; 45 | $flag = true; 46 | 47 | if ($position->getY() >= 1 && $position->getY() + $i + 1 <= 256) { 48 | for ($j = $position->getY(); $j <= $position->getY() + 1 + $i; ++$j) { 49 | $k = 1; 50 | 51 | if ($j === $position->getY()) { 52 | $k = 0; 53 | } 54 | 55 | if ($j >= $position->getY() + 1 + $i - 2) { 56 | $k = 2; 57 | } 58 | 59 | $pos2 = new Vector3(); 60 | 61 | for ($l = $position->getX() - $k; $l <= $position->getX() + $k && $flag; ++$l) { 62 | for ($i1 = $position->getZ() - $k; $i1 <= $position->getZ() + $k && $flag; ++$i1) { 63 | if ($j >= 0 && $j < 256) { 64 | $pos2->setComponents($l, $j, $i1); 65 | if (!$this->canOverride(BlockFactory::get($worldIn->getBlockIdAt($pos2->x, $pos2->y, $pos2->z)))) { 66 | $flag = false; 67 | } 68 | } else { 69 | $flag = false; 70 | } 71 | } 72 | } 73 | } 74 | 75 | if (!$flag) { 76 | return false; 77 | } else { 78 | $down = $position->down(); 79 | $block = $worldIn->getBlockIdAt($down->x, $down->y, $down->z); 80 | 81 | if (($block === Block::GRASS || $block === Block::DIRT || $block === Block::FARMLAND) && $position->getY() < 256 - $i - 1) { 82 | $worldIn->setBlockIdAt($down->x, $down->y, $down->z, Block::DIRT); 83 | $k2 = 3; 84 | $l2 = 0; 85 | 86 | for ($i3 = $position->getY() - 3 + $i; $i3 <= $position->getY() + $i; ++$i3) { 87 | $i4 = $i3 - ($position->getY() + $i); 88 | $j1 = 1 - $i4 / 2; 89 | 90 | for ($k1 = $position->getX() - $j1; $k1 <= $position->getX() + $j1; ++$k1) { 91 | $l1 = $k1 - $position->getX(); 92 | 93 | for ($i2 = $position->getZ() - $j1; $i2 <= $position->getZ() + $j1; ++$i2) { 94 | $j2 = $i2 - $position->getZ(); 95 | 96 | if (abs($l1) !== $j1 || abs($j2) !== $j1 || $rand->nextBoundedInt(2) !== 0 && $i4 !== 0) { 97 | $blockpos = new Vector3($k1, $i3, $i2); 98 | $id = $worldIn->getBlockIdAt($blockpos->x, $blockpos->y, $blockpos->z); 99 | 100 | if ($id === Block::AIR || $id === Block::LEAVES || $id == Block::VINE) { 101 | $this->setBlockAndNotifyAdequately($worldIn, $blockpos, Block::get(Block::LEAVES, $this->metaLeaves)); 102 | } 103 | } 104 | } 105 | } 106 | } 107 | 108 | for ($j3 = 0; $j3 < $i; ++$j3) { 109 | $up = $position->up($j3); 110 | $id = $worldIn->getBlockIdAt($up->x, $up->y, $up->z); 111 | 112 | if ($id === Block::AIR || $id === Block::LEAVES || $id === Block::VINE) { 113 | $this->setBlockAndNotifyAdequately($worldIn, $up, Block::get(Block::LOG, $this->metaWood)); 114 | 115 | if ($j3 > 0) { 116 | if ($rand->nextBoundedInt(3) > 0 && $this->isAirBlock($worldIn, $position->add(-1, $j3, 0))) { 117 | $this->addVine($worldIn, $position->add(-1, $j3, 0), 8); 118 | } 119 | 120 | if ($rand->nextBoundedInt(3) > 0 && $this->isAirBlock($worldIn, $position->add(1, $j3, 0))) { 121 | $this->addVine($worldIn, $position->add(1, $j3, 0), 2); 122 | } 123 | 124 | if ($rand->nextBoundedInt(3) > 0 && $this->isAirBlock($worldIn, $position->add(0, $j3, -1))) { 125 | $this->addVine($worldIn, $position->add(0, $j3, -1), 1); 126 | } 127 | 128 | if ($rand->nextBoundedInt(3) > 0 && $this->isAirBlock($worldIn, $position->add(0, $j3, 1))) { 129 | $this->addVine($worldIn, $position->add(0, $j3, 1), 4); 130 | } 131 | } 132 | } 133 | } 134 | 135 | for ($k3 = $position->getY() - 3 + $i; $k3 <= $position->getY() + $i; ++$k3) { 136 | $j4 = $k3 - ($position->getY() + $i); 137 | $k4 = 2 - $j4 / 2; 138 | $pos2 = new Vector3(); 139 | 140 | for ($l4 = $position->getX() - $k4; $l4 <= $position->getX() + $k4; ++$l4) { 141 | for ($i5 = $position->getZ() - $k4; $i5 <= $position->getZ() + $k4; ++$i5) { 142 | $pos2->setComponents($l4, $k3, $i5); 143 | 144 | if ($worldIn->getBlockIdAt($pos2->x, $pos2->y, $pos2->z) === Block::LEAVES) { 145 | $blockpos2 = $pos2->west(); 146 | $blockpos3 = $pos2->east(); 147 | $blockpos4 = $pos2->north(); 148 | $blockpos1 = $pos2->south(); 149 | 150 | if ($rand->nextBoundedInt(4) === 0 && $worldIn->getBlockIdAt($blockpos2->x, $blockpos2->y, $blockpos2->z) === Block::AIR) { 151 | $this->addHangingVine($worldIn, $blockpos2, 8); 152 | } 153 | 154 | if ($rand->nextBoundedInt(4) === 0 && $worldIn->getBlockIdAt($blockpos3->x, $blockpos3->y, $blockpos3->z) === Block::AIR) { 155 | $this->addHangingVine($worldIn, $blockpos3, 2); 156 | } 157 | 158 | if ($rand->nextBoundedInt(4) === 0 && $worldIn->getBlockIdAt($blockpos4->x, $blockpos4->y, $blockpos4->z) === Block::AIR) { 159 | $this->addHangingVine($worldIn, $blockpos4, 1); 160 | } 161 | 162 | if ($rand->nextBoundedInt(4) === 0 && $worldIn->getBlockIdAt($blockpos1->x, $blockpos1->y, $blockpos1->z) === Block::AIR) { 163 | $this->addHangingVine($worldIn, $blockpos1, 4); 164 | } 165 | } 166 | } 167 | } 168 | } 169 | 170 | if ($rand->nextBoundedInt(5) === 0 && $i > 5) { 171 | for ($l3 = 0; $l3 < 2; ++$l3) { 172 | foreach (FacingHelper::HORIZONTAL as $face) { 173 | if ($rand->nextBoundedInt(4 - $l3) === 0) { 174 | $enumfacing1 = FacingHelper::opposite($face); 175 | $this->placeCocoa($worldIn, $rand->nextBoundedInt(3), $position->add(FacingHelper::xOffset($enumfacing1), $i - 5 + $l3, FacingHelper::zOffset($enumfacing1)), $face); 176 | } 177 | } 178 | } 179 | } 180 | 181 | return true; 182 | } else { 183 | return false; 184 | } 185 | } 186 | } else { 187 | return false; 188 | } 189 | } 190 | 191 | public function setBlockAndNotifyAdequately(ChunkManager $level, Vector3 $pos, Block $block): void 192 | { 193 | $level->setBlockIdAt($pos->x, $pos->y, $pos->z, $block->getId()); 194 | $level->setBlockDataAt($pos->x, $pos->y, $pos->z, $block->getDamage()); 195 | } 196 | 197 | private function isAirBlock(ChunkManager $level, Vector3 $v): bool 198 | { 199 | return $level->getBlockIdAt($v->x, $v->y, $v->z) === Block::AIR; 200 | } 201 | 202 | private function addVine(ChunkManager $worldIn, Vector3 $pos, int $meta): void 203 | { 204 | $this->setBlockAndNotifyAdequately($worldIn, $pos, Block::get(Block::VINE, $meta)); 205 | } 206 | 207 | private function addHangingVine(ChunkManager $worldIn, Vector3 $pos, int $meta): void 208 | { 209 | $this->addVine($worldIn, $pos, $meta); 210 | $i = 4; 211 | 212 | for ($pos = $pos->down(); $i > 0 && $worldIn->getBlockIdAt($pos->x, $pos->y, $pos->z) === Block::AIR; --$i) { 213 | $this->addVine($worldIn, $pos, $meta); 214 | $pos = $pos->down(); 215 | } 216 | } 217 | 218 | private function placeCocoa(ChunkManager $worldIn, int $age, Vector3 $pos, int $side): void 219 | { 220 | $meta = $this->getCocoaMeta($age, $side); 221 | 222 | $this->setBlockAndNotifyAdequately($worldIn, $pos, new UnknownBlock(127, $meta)); 223 | } 224 | 225 | private function getCocoaMeta(int $age, int $side): int 226 | { 227 | $meta = 0; 228 | 229 | $meta *= $age; 230 | 231 | //3 4 2 5 232 | switch ($side) { 233 | case 4: 234 | $meta++; 235 | break; 236 | case 2: 237 | $meta += 2; 238 | break; 239 | case 5: 240 | $meta += 3; 241 | break; 242 | } 243 | 244 | return $meta; 245 | } 246 | 247 | } 248 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/object/SwampTree.php: -------------------------------------------------------------------------------- 1 | floor(); 31 | 32 | $i = $rand->nextBoundedInt(4) + 5; 33 | $flag = true; 34 | 35 | if ($position->getY() >= 1 && $position->getY() + $i + 1 <= 256) { 36 | for ($j = $position->getY(); $j <= $position->getY() + 1 + $i; ++$j) { 37 | $k = 1; 38 | 39 | if ($j === $position->getY()) { 40 | $k = 0; 41 | } 42 | 43 | if ($j >= $position->getY() + 1 + $i - 2) { 44 | $k = 3; 45 | } 46 | 47 | $pos2 = new Vector3(); 48 | 49 | for ($l = $position->getX() - $k; $l <= $position->getX() + $k && $flag; ++$l) { 50 | for ($i1 = $position->getZ() - $k; $i1 <= $position->getZ() + $k && $flag; ++$i1) { 51 | if ($j >= 0 && $j < 256) { 52 | $pos2->setComponents($l, $j, $i1); 53 | if (!$this->canOverride(Block::get($worldIn->getBlockIdAt($pos2->x, $pos2->y, $pos2->z)))) { 54 | $flag = false; 55 | } 56 | } else { 57 | $flag = false; 58 | } 59 | } 60 | } 61 | } 62 | 63 | if (!$flag) { 64 | return false; 65 | } else { 66 | $down = $position->down(); 67 | $block = $worldIn->getBlockIdAt($down->x, $down->y, $down->z); 68 | 69 | if (($block === Block::GRASS || $block === Block::DIRT) && $position->getY() < 256 - $i - 1) { 70 | $worldIn->setBlockIdAt($down->x, $down->y, $down->z, Block::DIRT); 71 | 72 | for ($k1 = $position->getY() - 3 + $i; $k1 <= $position->getY() + $i; ++$k1) { 73 | $j2 = $k1 - ($position->getY() + $i); 74 | $l2 = 2 - $j2 / 2; 75 | 76 | for ($j3 = $position->getX() - $l2; $j3 <= $position->getX() + $l2; ++$j3) { 77 | $k3 = $j3 - $position->getX(); 78 | 79 | for ($i4 = $position->getZ() - $l2; $i4 <= $position->getZ() + $l2; ++$i4) { 80 | $j1 = $i4 - $position->getZ(); 81 | 82 | if (abs($k3) !== $l2 || abs($j1) !== $l2 || $rand->nextBoundedInt(2) !== 0 && $j2 !== 0) { 83 | $blockpos = new Vector3($j3, $k1, $i4); 84 | $id = $worldIn->getBlockIdAt($blockpos->x, $blockpos->y, $blockpos->z); 85 | 86 | if ($id === Block::AIR || $id === Block::LEAVES || $id === Block::VINE) { 87 | $this->setBlockAndNotifyAdequately($worldIn, $blockpos, Block::get(Block::LEAVES, $this->metaLeaves)); 88 | } 89 | } 90 | } 91 | } 92 | } 93 | 94 | for ($l1 = 0; $l1 < $i; ++$l1) { 95 | $up = $position->up($l1); 96 | $id = $worldIn->getBlockIdAt($up->x, $up->y, $up->z); 97 | 98 | if ($id === Block::AIR || $id === Block::LEAVES || $id === Block::WATER || $id === Block::STILL_WATER) { 99 | $this->setBlockAndNotifyAdequately($worldIn, $up, Block::get(Block::LOG, $this->metaWood)); 100 | } 101 | } 102 | 103 | for ($i2 = $position->getY() - 3 + $i; $i2 <= $position->getY() + $i; ++$i2) { 104 | $k2 = $i2 - ($position->getY() + $i); 105 | $i3 = 2 - $k2 / 2; 106 | $pos2 = new Vector3(); 107 | 108 | for ($l3 = $position->getX() - $i3; $l3 <= $position->getX() + $i3; ++$l3) { 109 | for ($j4 = $position->getZ() - $i3; $j4 <= $position->getZ() + $i3; ++$j4) { 110 | $pos2->setComponents($l3, $i2, $j4); 111 | 112 | if ($worldIn->getBlockIdAt($pos2->x, $pos2->y, $pos2->z) === Block::LEAVES) { 113 | $blockpos2 = $pos2->west(); 114 | $blockpos3 = $pos2->east(); 115 | $blockpos4 = $pos2->north(); 116 | $blockpos1 = $pos2->south(); 117 | 118 | if ($rand->nextBoundedInt(4) === 0 && $worldIn->getBlockIdAt($blockpos2->x, $blockpos2->y, $blockpos2->z) === Block::AIR) { 119 | $this->addHangingVine($worldIn, $blockpos2, 8); 120 | } 121 | 122 | if ($rand->nextBoundedInt(4) === 0 && $worldIn->getBlockIdAt($blockpos3->x, $blockpos3->y, $blockpos3->z) === Block::AIR) { 123 | $this->addHangingVine($worldIn, $blockpos3, 2); 124 | } 125 | 126 | if ($rand->nextBoundedInt(4) === 0 && $worldIn->getBlockIdAt($blockpos4->x, $blockpos4->y, $blockpos4->z) === Block::AIR) { 127 | $this->addHangingVine($worldIn, $blockpos4, 1); 128 | } 129 | 130 | if ($rand->nextBoundedInt(4) === 0 && $worldIn->getBlockIdAt($blockpos1->x, $blockpos1->y, $blockpos1->z) === Block::AIR) { 131 | $this->addHangingVine($worldIn, $blockpos1, 4); 132 | } 133 | } 134 | } 135 | } 136 | } 137 | return true; 138 | } else { 139 | return false; 140 | } 141 | } 142 | } else { 143 | return false; 144 | } 145 | } 146 | 147 | private function setBlockAndNotifyAdequately(ChunkManager $level, Vector3 $pos, Block $b): void 148 | { 149 | $level->setBlockIdAt($pos->x, $pos->y, $pos->z, $b->getId()); 150 | $level->setBlockDataAt($pos->x, $pos->y, $pos->z, $b->getVariant()); 151 | } 152 | 153 | private function addHangingVine(ChunkManager $worldIn, Vector3 $pos, int $meta): void 154 | { 155 | $this->addVine($worldIn, $pos, $meta); 156 | $i = 4; 157 | 158 | for ($pos = $pos->down(); $i > 0 && $worldIn->getBlockIdAt($pos->x, $pos->y, $pos->z) === Block::AIR; --$i) { 159 | $this->addVine($worldIn, $pos, $meta); 160 | $pos = $pos->down(); 161 | } 162 | } 163 | 164 | private function addVine(ChunkManager $worldIn, Vector3 $pos, int $meta): void 165 | { 166 | $this->setBlockAndNotifyAdequately($worldIn, $pos, Block::get(Block::VINE, $meta)); 167 | } 168 | 169 | } 170 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/object/mushroom/BigMushroom.php: -------------------------------------------------------------------------------- 1 | mushroomType = $mushroomType ?? -1; 38 | } 39 | 40 | public function generate(ChunkManager $level, Random $rand, Vector3 $position): bool 41 | { 42 | $block = $this->mushroomType; 43 | if ($block < 0) { 44 | $block = $rand->nextBoolean() ? self::RED : self::BROWN; 45 | } 46 | 47 | $mushroom = $block === 0 ? new BrownMushroomBlock() : new RedMushroomBlock(); 48 | 49 | $i = $rand->nextBoundedInt(3) + 4; 50 | 51 | if ($rand->nextBoundedInt(12) === 0) { 52 | $i *= 2; 53 | } 54 | 55 | $flag = true; 56 | 57 | if ($position->getY() >= 1 && $position->getY() + $i + 1 < 256) { 58 | for ($j = $position->getFloorY(); $j <= $position->getY() + 1 + $i; ++$j) { 59 | $k = 3; 60 | 61 | if ($j <= $position->getY() + 3) { 62 | $k = 0; 63 | } 64 | 65 | $pos = new Vector3(); 66 | 67 | for ($l = $position->getFloorX() - $k; $l <= $position->getX() + $k && $flag; ++$l) { 68 | for ($i1 = $position->getFloorZ() - $k; $i1 <= $position->getZ() + $k && $flag; ++$i1) { 69 | if ($j >= 0 && $j < 256) { 70 | $pos->setComponents($l, $j, $i1); 71 | $material = $level->getBlockIdAt($pos->getFloorX(), $pos->getFloorY(), $pos->getFloorZ()); 72 | 73 | if ($material !== Block::AIR && $material !== Block::LEAVES) { 74 | $flag = false; 75 | } 76 | } else { 77 | $flag = false; 78 | } 79 | } 80 | } 81 | } 82 | 83 | if (!$flag) { 84 | return false; 85 | } else { 86 | $pos2 = $position->down(); 87 | $block1 = $level->getBlockIdAt($pos2->getFloorX(), $pos2->getFloorY(), $pos2->getFloorZ()); 88 | 89 | if ($block1 !== Block::DIRT && $block1 !== Block::GRASS && $block1 !== Block::MYCELIUM) { 90 | return false; 91 | } else { 92 | $k2 = $position->getFloorY() + $i; 93 | 94 | if ($block === self::RED) { 95 | $k2 = $position->getFloorY() + $i - 3; 96 | } 97 | 98 | for ($l2 = $k2; $l2 <= $position->getY() + $i; ++$l2) { 99 | $j3 = 1; 100 | 101 | if ($l2 < $position->getY() + $i) { 102 | ++$j3; 103 | } 104 | 105 | if ($block === self::BROWN) { 106 | $j3 = 3; 107 | } 108 | 109 | $k3 = $position->getFloorX() - $j3; 110 | $l3 = $position->getFloorX() + $j3; 111 | $j1 = $position->getFloorZ() - $j3; 112 | $k1 = $position->getFloorZ() + $j3; 113 | 114 | for ($l1 = $k3; $l1 <= $l3; ++$l1) { 115 | for ($i2 = $j1; $i2 <= $k1; ++$i2) { 116 | $j2 = 5; 117 | 118 | if ($l1 === $k3) { 119 | --$j2; 120 | } elseif ($l1 === $l3) { 121 | ++$j2; 122 | } 123 | 124 | if ($i2 === $j1) { 125 | $j2 -= 3; 126 | } elseif ($i2 === $k1) { 127 | $j2 += 3; 128 | } 129 | 130 | $meta = $j2; 131 | 132 | if ($block === self::BROWN || $l2 < $position->getY() + $i) { 133 | if (($l1 == $k3 || $l1 === $l3) && ($i2 === $j1 || $i2 === $k1)) { 134 | continue; 135 | } 136 | 137 | if ($l1 === $position->getX() - ($j3 - 1) && $i2 === $j1) { 138 | $meta = self::NORTH_WEST; 139 | } 140 | 141 | if ($l1 === $k3 && $i2 === $position->getZ() - ($j3 - 1)) { 142 | $meta = self::NORTH_WEST; 143 | } 144 | 145 | if ($l1 === $position->getX() + ($j3 - 1) && $i2 === $j1) { 146 | $meta = self::NORTH_EAST; 147 | } 148 | 149 | if ($l1 === $l3 && $i2 === $position->getZ() - ($j3 - 1)) { 150 | $meta = self::NORTH_EAST; 151 | } 152 | 153 | if ($l1 === $position->getX() - ($j3 - 1) && $i2 === $k1) { 154 | $meta = self::SOUTH_WEST; 155 | } 156 | 157 | if ($l1 === $k3 && $i2 === $position->getZ() + ($j3 - 1)) { 158 | $meta = self::SOUTH_WEST; 159 | } 160 | 161 | if ($l1 === $position->getX() + ($j3 - 1) && $i2 === $k1) { 162 | $meta = self::SOUTH_EAST; 163 | } 164 | 165 | if ($l1 === $l3 && $i2 === $position->getZ() + ($j3 - 1)) { 166 | $meta = self::SOUTH_EAST; 167 | } 168 | } 169 | 170 | if ($meta === self::CENTER && $l2 < $position->getY() + $i) { 171 | $meta = self::ALL_INSIDE; 172 | } 173 | 174 | if ($position->getY() >= $position->getY() + $i - 1 || $meta !== self::ALL_INSIDE) { 175 | $blockPos = new Vector3($l1, $l2, $i2); 176 | 177 | if (!(Block::get($level->getBlockIdAt($blockPos->x, $blockPos->y, $blockPos->z))->isSolid())) { 178 | $this->setBlockAndNotifyAdequately($level, $blockPos, $mushroom); 179 | } 180 | } 181 | } 182 | } 183 | } 184 | 185 | for ($i3 = 0; $i3 < $i; ++$i3) { 186 | $pos = $position->up($i3); 187 | $id = $level->getBlockIdAt($pos->getFloorX(), $pos->getFloorY(), $pos->getFloorZ()); 188 | 189 | if (!(Block::get($id)->isSolid())) { 190 | $this->setBlockAndNotifyAdequately($level, $pos, Block::get($mushroom->getId(), self::STEM)); 191 | } 192 | } 193 | 194 | return true; 195 | } 196 | } 197 | } else { 198 | return false; 199 | } 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/populator/BedrockPopulator.php: -------------------------------------------------------------------------------- 1 | bedrock = VanillaBlocks::BEDROCK(); 20 | } 21 | 22 | public function populate(ChunkManager $world, int $chunkX, int $chunkZ, Random $random): void 23 | { 24 | $chunk = $world->getChunk($chunkX, $chunkZ); 25 | 26 | for ($x = 0; $x < 16; $x++) { 27 | for ($z = 0; $z < 16; $z++) { 28 | $chunk->setFullBlock($x, 0, $z, $this->bedrock->getFullId()); 29 | for ($i = 1; $i < 5; $i++) { 30 | if ($random->nextBoundedInt($i) == 0) 31 | $chunk->setFullBlock($x, $i, $z, $this->bedrock->getFullId()); 32 | } 33 | } 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/populator/CactusPopulator.php: -------------------------------------------------------------------------------- 1 | nextFloat() + $random->nextFloat() + $random->nextFloat() + $random->nextFloat())) / 2.0); 19 | 20 | for ($height = floor($height / 2) + 1; $height >= 0; $height--) { 21 | parent::placeBlock($x, (int)($y + $height), $z, $block, $world, $random); 22 | } 23 | } 24 | 25 | protected function canStay(int $x, int $y, int $z, ChunkManager $world): bool 26 | { 27 | return EnsureCover::ensureCover($x, $y, $z, $world) && EnsureBelow::ensureBelow($x, $y, $z, VanillaBlocks::SAND(), $world); 28 | } 29 | 30 | protected function getBlock(int $x, int $z, Random $random, ChunkManager $world): Block 31 | { 32 | return VanillaBlocks::CACTUS(); 33 | } 34 | } -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/populator/CavePopulator.php: -------------------------------------------------------------------------------- 1 | random = new CustomRandom($this->seed); 44 | 45 | $this->worldLong1 = $this->random->nextLong(); 46 | $this->worldLong2 = $this->random->nextLong(); 47 | 48 | $size = $this->checkAreaSize; 49 | 50 | for ($x = $chunkX - $size; $x <= $chunkX + $size; $x++) { 51 | for ($z = $chunkZ - $size; $z <= $chunkZ + $size; $z++) { 52 | echo 'Hey'; 53 | $randomX = $x * $this->worldLong1; 54 | $randomZ = $z * $this->worldLong2; 55 | $this->random->setSeed($randomX ^ $randomZ ^ $this->seed); 56 | $this->generateChunk($chunkX, $chunkZ, $world); 57 | } 58 | } 59 | } 60 | 61 | protected function generateChunk(int $chunkX, int $chunkZ, ChunkManager $world): void 62 | { 63 | $i = $this->random->nextBoundedInt($this->random->nextBoundedInt($this->random->nextBoundedInt(self::$caveFrequency) + 1) + 1); 64 | 65 | if (self::$evenCaveDistribution) $i = self::$caveFrequency; 66 | if ($this->random->nextBoundedInt(100) >= self::$caveRarity) $i = 0; 67 | 68 | for ($j = 0; $j < $i; $j++) { 69 | echo 'i: ' . PHP_EOL; 70 | $x = $chunkX * 16 + $this->random->nextBoundedInt(16); 71 | 72 | if (self::$evenCaveDistribution) { 73 | $y = self::numberInRange($this->random, self::$caveMinAltitude, self::$caveMaxAltitude); 74 | } else { 75 | $y = $this->random->nextBoundedInt($this->random->nextBoundedInt(self::$caveMaxAltitude - self::$caveMinAltitude + 1) + 1) + self::$caveMinAltitude; 76 | } 77 | 78 | $z = $chunkZ * 16 + $this->random->nextBoundedInt(16); 79 | 80 | $count = self::$caveSystemFrequency; 81 | $largeCaveSpawned = false; 82 | if ($this->random->nextBoundedInt(100) <= self::$individualCaveRarity) { 83 | echo 'Generating individual cave' . PHP_EOL; 84 | $this->generateLargeCaveNode($this->random->nextLong(), $world, $chunkX, $chunkZ, $x, $y, $z); 85 | $largeCaveSpawned = true; 86 | } 87 | 88 | if (($largeCaveSpawned) || ($this->random->nextBoundedInt(100) <= self::$caveSystemPocketChance - 1)) { 89 | $count += self::numberInRange($this->random, self::$caveSystemPocketMinSize, self::$caveSystemPocketMaxSize); 90 | } 91 | while ($count > 0) { 92 | $count--; 93 | 94 | $f1 = $this->random->nextFloat() * 3.141593 * 2.0; 95 | $f2 = ($this->random->nextFloat() - 0.5) * 2.0 / 8.0; 96 | $f3 = $this->random->nextFloat() * 2.0 + $this->random->nextFloat(); 97 | 98 | $this->generateCaveNode($this->random->nextLong(), $world, $chunkX, $chunkZ, $x, $y, $z, $f3, $f1, $f2, 0, 0, 1.0); 99 | } 100 | } 101 | } 102 | 103 | public static function numberInRange(Random $random, int $min, int $max): int 104 | { 105 | return $min + $random->nextBoundedInt($max - $min + 1); 106 | } 107 | 108 | protected function generateLargeCaveNode($seed, ChunkManager $world, int $chunkX, int $chunkZ, float $x, float $y, float $z): void 109 | { 110 | $this->generateCaveNode($seed, $world, $chunkX, $chunkZ, $x, $y, $z, 1.0 + $this->random->nextFloat() * 6.0, 0.0, 0.0, -1, -1, 0.5); 111 | } 112 | 113 | protected function generateCaveNode($seed, ChunkManager $world, int $chunkX, int $chunkZ, float $x, float $y, float $z, float $radius, float $angelOffset, float $angel, int $angle, int $maxAngle, float $scale): void 114 | { 115 | $realX = $chunkX * 16 + 8; 116 | $realZ = $chunkZ * 16 + 8; 117 | 118 | $f1 = 0.0; 119 | $f2 = 0.0; 120 | 121 | $localRandom = new CustomRandom($seed); 122 | 123 | if ($maxAngle <= 0) { 124 | $checkAreaSize = ($this->checkAreaSize * 8) * 16 - 16; 125 | $maxAngle = $checkAreaSize - $localRandom->nextBoundedInt($checkAreaSize / 4); 126 | } 127 | $isLargeCave = false; 128 | 129 | if ($angle == -1) { 130 | $angle = $maxAngle / 2; 131 | $isLargeCave = true; 132 | } 133 | 134 | $randomAngel = $localRandom->nextBoundedInt($maxAngle / 2) + $maxAngle / 4; 135 | $bigAngel = $localRandom->nextBoundedInt(6) == 0; 136 | 137 | echo 'Angle: ' . $angle . ' < maxAngle: ' . $maxAngle . PHP_EOL; 138 | for (; $angle < $maxAngle; $angle++) { 139 | $offsetXZ = 1.5 + sin($angle * 3.141593 / $maxAngle) * $radius * 1.0; 140 | $offsetY = $offsetXZ * $scale; 141 | 142 | $cos = cos($angel); 143 | $sin = sin($angel); 144 | $x += cos($angelOffset) * $cos; 145 | $y += $sin; 146 | $z += sin($angelOffset) * $cos; 147 | 148 | if ($bigAngel) 149 | $angel *= 0.92; 150 | else { 151 | $angel *= 0.7; 152 | } 153 | $angel += $f2 * 0.1; 154 | $angelOffset += $f1 * 0.1; 155 | 156 | $f2 *= 0.9; 157 | $f1 *= 0.75; 158 | $f2 += ($localRandom->nextFloat() - $localRandom->nextFloat()) * $localRandom->nextFloat() * 2.0; 159 | $f1 += ($localRandom->nextFloat() - $localRandom->nextFloat()) * $localRandom->nextFloat() * 4.0; 160 | 161 | 162 | if ((!$isLargeCave) && ($angle == $randomAngel) && ($radius > 1.0) && ($maxAngle > 0)) { 163 | $this->generateCaveNode($localRandom->nextLong(), $world, $chunkX, $chunkZ, $x, $y, $z, $localRandom->nextFloat() * 0.5 + 0.5, $angelOffset - 1.570796, $angel / 3.0, $angle, $maxAngle, 1.0); 164 | $this->generateCaveNode($localRandom->nextLong(), $world, $chunkX, $chunkZ, $x, $y, $z, $localRandom->nextFloat() * 0.5 + 0.5, $angelOffset + 1.570796, $angel / 3.0, $angle, $maxAngle, 1.0); 165 | return; 166 | } 167 | $ln = $localRandom->nextBoundedInt(4); 168 | if ((!$isLargeCave) && ($ln == 0)) { 169 | continue; 170 | } 171 | 172 | // Check if distance to working point (x and z) too larger than working radius (maybe ??) 173 | $distanceX = $x - $realX; 174 | $distanceZ = $z - $realZ; 175 | $angelDiff = $maxAngle - $angle; 176 | $newRadius = $radius + 2.0 + 16.0; 177 | echo 'Checking disatance ...' . PHP_EOL; 178 | if ($distanceX * $distanceX + $distanceZ * $distanceZ - $angelDiff * $angelDiff > $newRadius * $newRadius) { 179 | return; 180 | } 181 | echo 'Passed' . PHP_EOL; 182 | 183 | //Boundaries check. 184 | if (($x < $realX - 16.0 - $offsetXZ * 2.0) || ($z < $realZ - 16.0 - $offsetXZ * 2.0) || ($x > $realX + 16.0 + $offsetXZ * 2.0) || ($z > $realZ + 16.0 + $offsetXZ * 2.0)) { 185 | continue; 186 | } 187 | echo 'Passed 2' . PHP_EOL; 188 | 189 | $xFrom = floor($x - $offsetXZ) - $chunkX * 16 - 1; 190 | $xTo = floor($x + $offsetXZ) - $chunkX * 16 + 1; 191 | 192 | $yFrom = floor($y - $offsetY) - 1; 193 | $yTo = floor($y + $offsetY) + 1; 194 | 195 | $zFrom = floor($z - $offsetXZ) - $chunkZ * 16 - 1; 196 | $zTo = floor($z + $offsetXZ) - $chunkZ * 16 + 1; 197 | 198 | if ($xFrom < 0) 199 | $xFrom = 0; 200 | if ($xTo > 16) 201 | $xTo = 16; 202 | 203 | if ($yFrom < 1) 204 | $yFrom = 1; 205 | if ($yTo > $this->worldHeightCap - 8) { 206 | $yTo = $this->worldHeightCap - 8; 207 | } 208 | if ($zFrom < 0) 209 | $zFrom = 0; 210 | if ($zTo > 16) 211 | $zTo = 16; 212 | 213 | // Search for water 214 | $waterFound = false; 215 | 216 | $baseX = $chunkX * Chunk::EDGE_LENGTH; 217 | $baseZ = $chunkZ * Chunk::EDGE_LENGTH; 218 | 219 | for ($xx = $xFrom; (!$waterFound) && ($xx < $xTo); $xx++) { 220 | for ($zz = $zFrom; ($zz < $zTo); $zz++) { 221 | for ($yy = $yTo + 1; ($yy >= $yFrom - 1); $yy--) { 222 | if ($yy >= 0 && $yy < $this->worldHeightCap) { 223 | $block = $world->getBlockAt((int)$xx + $baseX, (int)$yy, (int)$zz + $baseZ); 224 | if ($block->getId() === BlockLegacyIds::WATER || $block->getId() == BlockLegacyIds::STILL_WATER) { 225 | $waterFound = true; 226 | } 227 | if (($yy != $yFrom - 1) && ($xx != $xFrom) && ($xx != $xTo - 1) && ($zz != $zFrom) && ($zz != $zTo - 1)) 228 | $yy = $yFrom; 229 | } 230 | } 231 | } 232 | } 233 | 234 | if ($waterFound) { 235 | continue; 236 | } 237 | 238 | $chunk = $world->getChunk($chunkX, $chunkZ); 239 | 240 | // Generate cave 241 | for ($xx = $xFrom; $xx < $xTo; $xx++) { 242 | $modX = ($xx + $chunkX * 16 + 0.5 - $x) / $offsetXZ; 243 | for ($zz = $zFrom; $zz < $zTo; $zz++) { 244 | $modZ = ($zz + $chunkZ * 16 + 0.5 - $z) / $offsetXZ; 245 | 246 | $grassFound = false; 247 | if ($modX * $modX + $modZ * $modZ < 1.0) { 248 | for ($yy = $yTo; $yy > $yFrom; $yy--) { 249 | $modY = (($yy - 1) + 0.5 - $y) / $offsetY; 250 | if (($modY > -0.7) && ($modX * $modX + $modY * $modY + $modZ * $modZ < 1.0)) { 251 | $biome = CustomBiome::getBiome($chunk->getBiomeId((int)$xx, (int)$zz)); 252 | if (!($biome instanceof CoveredBiome)) { 253 | continue; 254 | } 255 | 256 | $block = $world->getBlockAt((int)$xx + $baseX, (int)$yy, (int)$zz + $baseZ); 257 | if ($block->getId() === BlockLegacyIds::GRASS || $block->getId() === BlockLegacyIds::MYCELIUM) { 258 | $grassFound = true; 259 | } 260 | echo 'Setting blocks ...' . PHP_EOL; 261 | if ($yy - 1 < 10) { 262 | $world->setBlockAt((int)$xx + $baseX, (int)$yy, (int)$zz + $baseZ, VanillaBlocks::LAVA()); 263 | } else { 264 | $world->setBlockAt((int)$xx + $baseX, (int)$yy, (int)$zz + $baseZ, VanillaBlocks::AIR()); 265 | 266 | if ($grassFound && ($world->getBlockAt((int)$xx + $baseX, (int)$yy - 1, (int)$zz + $baseZ)->getId() === BlockLegacyIds::DIRT)) { 267 | $world->setBlockAt((int)$xx + $baseX, (int)$yy - 1, (int)+$baseZ, $biome->getSurfaceBlock((int)$yy - 1)); 268 | } 269 | } 270 | } 271 | } 272 | } 273 | } 274 | } 275 | 276 | if ($isLargeCave) { 277 | break; 278 | } 279 | } 280 | } 281 | 282 | } 283 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/populator/DeadBushPopulator.php: -------------------------------------------------------------------------------- 1 | setBlockAt($x, $y, $z, $block); 34 | $world->setBlockAt($x, $y + 1, $z, (clone $block)->setTop(true)); 35 | } 36 | 37 | protected function getBlock(int $x, int $z, Random $random, ChunkManager $world): DoublePlant 38 | { 39 | return $this->plant; 40 | } 41 | } -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/populator/FlowerPopulator.php: -------------------------------------------------------------------------------- 1 | flowerTypes[] = $flower; 24 | } 25 | 26 | protected function placeBlock(int $x, int $y, int $z, Block $block, ChunkManager $world, Random $random): void 27 | { 28 | $world->setBlockAt($x, $y, $z, $block); 29 | if ($block instanceof DoublePlant) { 30 | $world->setBlockAt($x, $y + 1, $z, (clone $block)->setTop(true)); 31 | } 32 | } 33 | 34 | protected function canStay(int $x, int $y, int $z, ChunkManager $world): bool 35 | { 36 | return EnsureCover::ensureCover($x, $y, $z, $world) && EnsureGrassBelow::ensureGrassBelow($x, $y, $z, $world); 37 | } 38 | 39 | protected function getBlock(int $x, int $z, Random $random, ChunkManager $world): Block 40 | { 41 | return $this->flowerTypes[$random->nextRange(0, count($this->flowerTypes) - 1)] ?? VanillaBlocks::AIR(); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/populator/GrassPopulator.php: -------------------------------------------------------------------------------- 1 | getChunk($chunkX, $chunkZ); 23 | 24 | for ($x = 0; $x < 16; ++$x) { 25 | for ($z = 0; $z < 16; ++$z) { 26 | $y = 254; 27 | 28 | $biome = CustomBiome::getBiome($chunk->getBiomeId($x, $z)); 29 | $realX = $baseX + $x; 30 | $realZ = $baseZ + $z; 31 | 32 | if ($biome instanceof CoveredBiome === false) { 33 | continue; 34 | } 35 | $biome->preCover($baseX | $x, $baseZ | $z); 36 | 37 | while (($y = $this->getNextStone($chunk, $x, $y, $z)) >= 0) { 38 | 39 | if (($coverBlock = $biome->getCoverBlock($y))->getId() > 0) { 40 | $world->setBlockAt($realX, $y + 1, $realZ, $coverBlock); 41 | } 42 | $maxSurfaceDepth = max(min( 43 | $stoneDepth = $y - ($this->getNextAir($chunk, $x, $y, $z) - 1), 44 | $biome->getSurfaceDepth($y) 45 | ), 0); 46 | 47 | for ($i = 0; $i < $maxSurfaceDepth; $i++) { 48 | $world->setBlockAt($realX, $realY = $y - $i, $realZ, $biome->getSurfaceBlock($realY)); 49 | } 50 | $y -= $maxSurfaceDepth; 51 | 52 | $remainingStones = $stoneDepth - $maxSurfaceDepth; 53 | if ($remainingStones === 0) { 54 | continue; 55 | } 56 | 57 | $maxGroundDepth = max(min( 58 | $remainingStones, 59 | $biome->getGroundDepth($y) 60 | ), 0); 61 | for ($i = 0; $i < $maxGroundDepth; $i++) { 62 | $world->setBlockAt($realX, $realY = $y - $i, $realZ, $biome->getGroundBlock($realY)); 63 | } 64 | 65 | $y = $this->getNextAir($chunk, $x, $y - $maxGroundDepth, $z); 66 | } 67 | } 68 | } 69 | } 70 | 71 | private function getNextStone(Chunk $chunk, int $x, int $y, int $z): int 72 | { 73 | for (; $y >= 0 && $chunk->getFullBlock($x, $y, $z) !== VanillaBlocks::STONE()->getFullId(); $y--) { 74 | // 75 | } 76 | return $y; 77 | } 78 | 79 | private function getNextAir(Chunk $chunk, int $x, int $y, int $z): int 80 | { 81 | for (; $y >= 0 && $chunk->getFullBlock($x, $y, $z) !== VanillaBlocks::AIR()->getFullId(); $y--) { 82 | // 83 | } 84 | return $y; 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/populator/IceSpikesPopulator.php: -------------------------------------------------------------------------------- 1 | packedIce = VanillaBlocks::PACKED_ICE(); 20 | } 21 | 22 | public function populate(ChunkManager $world, int $chunkX, int $chunkZ, Random $random): void 23 | { 24 | for ($i = 0; $i < 8; $i++) { 25 | $x = ($chunkX * Chunk::EDGE_LENGTH) + $random->nextBoundedInt(16); 26 | $z = ($chunkZ * Chunk::EDGE_LENGTH) + $random->nextBoundedInt(16); 27 | 28 | $chunk = $world->getChunk($chunkX, $chunkZ); 29 | 30 | $isTall = $random->nextBoundedInt(16) == 0; 31 | $height = 10 + $random->nextBoundedInt(16) + ($isTall ? $random->nextBoundedInt(31) : 0); 32 | 33 | $startY = $this->getHighestWorkableBlock($x, $z, $chunk); 34 | $maxY = $startY + $height; 35 | 36 | if ($isTall) { 37 | for ($y = $startY; $y < $maxY; $y++) { 38 | //center column 39 | $world->setBlockAt($x, $y, $z, $this->packedIce); 40 | //t shape 41 | $world->setBlockAt($x + 1, $y, $z, $this->packedIce); 42 | $world->setBlockAt($x - 1, $y, $z, $this->packedIce); 43 | $world->setBlockAt($x, $y, $z + 1, $this->packedIce); 44 | $world->setBlockAt($x, $y, $z - 1, $this->packedIce); 45 | //additional blocks on the side 46 | if ($random->nextBoolean()) { 47 | $world->setBlockAt($x + 1, $y, $z + 1, $this->packedIce); 48 | } 49 | if ($random->nextBoolean()) { 50 | $world->setBlockAt($x + 1, $y, $z - 1, $this->packedIce); 51 | } 52 | if ($random->nextBoolean()) { 53 | $world->setBlockAt($x - 1, $y, $z + 1, $this->packedIce); 54 | } 55 | if ($random->nextBoolean()) { 56 | $world->setBlockAt($x - 1, $y, $z - 1, $this->packedIce); 57 | } 58 | } 59 | //finish with a point 60 | $world->setBlockAt($x + 1, $maxY, $z, $this->packedIce); 61 | $world->setBlockAt($x - 1, $maxY, $z, $this->packedIce); 62 | $world->setBlockAt($x, $maxY, $z + 1, $this->packedIce); 63 | $world->setBlockAt($x, $maxY, $z - 1, $this->packedIce); 64 | for ($y = $maxY; $y < $maxY + 3; $maxY++) { 65 | $world->setBlockAt($x, $y, $z, $this->packedIce); 66 | } 67 | } else { 68 | //the maximum possible radius in blocks 69 | $baseWidth = $random->nextBoundedInt(1) + 4; 70 | $shrinkFactor = $baseWidth / $height; 71 | $currWidth = $baseWidth; 72 | for ($y = $startY; $y < $maxY; $y++) { 73 | for ($xx = (int)-$currWidth; $xx < $currWidth; $xx++) { 74 | for ($zz = (int)-$currWidth; $zz < $currWidth; $zz++) { 75 | $currDist = (int)sqrt($xx * $xx + $zz * $zz); 76 | if ((int)$currWidth != $currDist && $random->nextBoolean()) { 77 | $world->setBlockAt($x + $xx, $y, $z + $zz, $this->packedIce); 78 | } 79 | } 80 | } 81 | $currWidth -= $shrinkFactor; 82 | } 83 | } 84 | } 85 | } 86 | 87 | public function getHighestWorkableBlock(int $x, int $z, Chunk $chunk): int 88 | { 89 | return $chunk->getHighestBlockAt($x & 0xF, $z & 0xF) - 5; 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/populator/KelpPopulator.php: -------------------------------------------------------------------------------- 1 | nextBoundedInt(24); 18 | for ($yy = $y; $yy < BlockGenerator::SEA_HEIGHT && $age > 0; $yy++) { 19 | /////////////////////////////////// 20 | //$chunk->setBlock($x, $y, $z, ) // 21 | /////////////////////////////////// 22 | /// Kelp block id is unknown :/ 23 | } 24 | } 25 | 26 | protected function getHighestWorkableBlock(ChunkManager $level, int $x, int $z, Chunk $chunk) 27 | { 28 | $y = 0; 29 | //start at 254 because we add one afterwards 30 | for ($y = 254; $y >= 0; --$y) { 31 | $id = $chunk->getBlockId($x, $y, $z); 32 | if (!PopulatorHelpers::isNonSolid($id) && !$id === Block::STILL_WATER) { 33 | break; 34 | } 35 | } 36 | 37 | return $y === 0 ? -1 : ++$y; 38 | } 39 | 40 | protected function canStay(int $x, int $y, int $z, Chunk $chunk): bool 41 | { 42 | // TODO: Implement canStay() method. 43 | } 44 | 45 | protected function getBlockId(int $x, int $z, Random $random, Chunk $chunk): int 46 | { 47 | // TODO: Implement getBlockId() method. 48 | } 49 | } -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/populator/LilyPadPopulator.php: -------------------------------------------------------------------------------- 1 | type = $type === null ? mt_rand(0, 1) : $type; 19 | } 20 | 21 | public function populateCount(ChunkManager $world, int $chunkX, int $chunkZ, Random $random): void 22 | { 23 | $x = ($chunkX << 4) | $random->nextBoundedInt(16); 24 | $z = ($chunkZ << 4) | $random->nextBoundedInt(16); 25 | $y = $this->getHighestWorkableBlock($world, $x, $z, $world->getChunk($chunkX, $chunkZ)); 26 | if ($y !== -1) { 27 | (new BigMushroom($this->type))->generate($world, $random, new Vector3($x, $y, $z)); 28 | } 29 | } 30 | 31 | protected function getHighestWorkableBlock(ChunkManager $level, int $x, int $z, Chunk $chunk): int 32 | { 33 | $y = 0; 34 | $x &= 0xF; 35 | $z &= 0xF; 36 | for ($y = 254; $y > 0; --$y) { 37 | $b = $chunk->getBlockId($x, $y, $z); 38 | if ($b === Block::DIRT || $b === Block::GRASS || $b === Block::MYCELIUM) { 39 | break; 40 | } elseif ($b !== Block::AIR && $b !== Block::SNOW_LAYER) { 41 | return -1; 42 | } 43 | } 44 | 45 | return ++$y; 46 | } 47 | 48 | } -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/populator/PopulatorCount.php: -------------------------------------------------------------------------------- 1 | randomAmount = $randomAmount + 1; 21 | } 22 | 23 | public function setBaseAmount(int $baseAmount): void 24 | { 25 | $this->baseAmount = $baseAmount; 26 | } 27 | 28 | public function setSpreadChance(float $chance): void 29 | { 30 | $this->spreadChance = $chance; 31 | } 32 | 33 | public function populate(ChunkManager $world, int $chunkX, int $chunkZ, Random $random): void 34 | { 35 | $count = $this->baseAmount + $random->nextBoundedInt($this->randomAmount); 36 | for ($i = 0; $i < $count; $i++) { 37 | $this->populateCount($world, $chunkX, $chunkZ, $random); 38 | } 39 | } 40 | 41 | protected abstract function populateCount(ChunkManager $world, int $chunkX, int $chunkZ, Random $random): void; 42 | 43 | protected function spread(int $x, int $y, int $z, ChunkManager $world): ?Vector3 44 | { 45 | return null; 46 | } 47 | 48 | } -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/populator/RavinesPopulator.php: -------------------------------------------------------------------------------- 1 | true, 17 | Block::DIRT => true, 18 | Block::STONE => true, 19 | Block::IRON_ORE => true, 20 | Block::COAL_ORE => true, 21 | Block::DIAMOND_ORE => true, 22 | Block::LAPIS_ORE => true, 23 | Block::GOLD_ORE => true, 24 | Block::EMERALD_ORE => true, 25 | Block::GRAVEL => true 26 | ]; 27 | 28 | protected $checkAreaSize = 8; 29 | 30 | protected $random; 31 | protected $worldLong1; 32 | protected $worldLong2; 33 | 34 | protected $ravineRarity = 2; 35 | protected $ravineMinAltitude = 20; 36 | protected $ravineMaxAltitude = 70; 37 | protected $ravineMinLength = 84; 38 | protected $ravineMaxLength = 111; 39 | 40 | protected $ravineDepth = 20; 41 | 42 | protected $worldHeightCap = 1 << 8; 43 | 44 | protected $a = []; // 1024 45 | 46 | public function populate(ChunkManager $level, int $chunkX, int $chunkZ, Random $random): void 47 | { 48 | $this->random = new CustomRandom(); 49 | $this->random->setSeed($level->getSeed()); 50 | $worldLong1 = $this->random->nextLong(); 51 | $worldLong2 = $this->random->nextLong(); 52 | 53 | $i = $this->checkAreaSize; 54 | 55 | for ($x = $chunkX - $i; $x <= $chunkX + $i; $x++) 56 | for ($z = $chunkZ - $i; $z <= $chunkZ + $i; $z++) { 57 | $l3 = $x * $worldLong1; 58 | $l4 = $z * $worldLong2; 59 | $this->random->setSeed($l3 ^ $l4 ^ $level->getSeed()); 60 | $this->generateChunk($chunkX, $chunkZ, $level->getChunk($chunkX, $chunkZ)); 61 | } 62 | } 63 | 64 | protected function generateChunk(int $chunkX, int $chunkZ, Chunk $generatingChunkBuffer): void 65 | { 66 | if ($this->random->nextBoundedInt(300) >= $this->ravineRarity) return; 67 | $d1 = ($chunkX * 16) + $this->random->nextBoundedInt(16); 68 | $d2 = self::numberInRange($this->random, $this->ravineMinAltitude, $this->ravineMaxAltitude); 69 | $d3 = ($chunkZ * 16) + $this->random->nextBoundedInt(16); 70 | 71 | $i = 1; 72 | 73 | for ($j = 0; $j < $i; $j++) { 74 | $f1 = $this->random->nextFloat() * 3.141593 * 2.0; 75 | $f2 = ($this->random->nextFloat() - 0.5) * 2.0 / 8.0; 76 | $f3 = ($this->random->nextFloat() * 2.0 + $this->random->nextFloat()) * 2.0; 77 | 78 | $size = self::numberInRange($this->random, $this->ravineMinLength, $this->ravineMaxLength); 79 | 80 | $this->createRavine($this->random->nextLong(), $generatingChunkBuffer, $d1, $d2, $d3, $f3, $f1, $f2, $size, $this->ravineDepth); 81 | } 82 | } 83 | 84 | public static function numberInRange(Random $random, int $min, int $max): int 85 | { 86 | return $min + $random->nextBoundedInt($max - $min + 1); 87 | } 88 | 89 | protected function createRavine(int $paramLong, Chunk $generatingChunkBuffer, float $paramDouble1, float $paramDouble2, float $paramDouble3, float $paramFloat1, float $paramFloat2, float $paramFloat3, int $size, float $paramDouble4) 90 | { 91 | $localRandom = new CustomRandom($paramLong); 92 | 93 | $chunkX = $generatingChunkBuffer->getX(); 94 | $chunkZ = $generatingChunkBuffer->getZ(); 95 | 96 | $d1 = $chunkX * 16 + 8; 97 | $d2 = $chunkZ * 16 + 8; 98 | 99 | $f1 = 0.0; 100 | $f2 = 0.0; 101 | 102 | $i = 0; 103 | 104 | $f3 = 1.0; 105 | for ($j = 0; ; $j++) { 106 | if ($j >= $this->worldHeightCap) break; 107 | if (($j === 0) || ($localRandom->nextBoundedInt(3) === 0)) { 108 | $f3 = 1.0 + $localRandom->nextFloat() * $localRandom->nextFloat() * 1.0; 109 | } 110 | $this->a[$j] = ($f3 * $f3); 111 | } 112 | 113 | for ($stepCount = 0; $stepCount < $size; $stepCount++) { 114 | $d3 = 1.5 + sin($stepCount * 3.141593 / $size) * $paramFloat1 * 1.0; 115 | $d4 = $d3 * $paramDouble4; 116 | 117 | $d3 *= ($localRandom->nextFloat() * 0.25 + 0.75); 118 | $d4 *= ($localRandom->nextFloat() * 0.25 + 0.75); 119 | 120 | $f4 = cos($paramFloat3); 121 | $f5 = sin($paramFloat3); 122 | $paramDouble1 += cos($paramFloat2) * $f4; 123 | $paramDouble2 += $f5; 124 | $paramDouble3 += sin($paramFloat2) * $f4; 125 | 126 | $paramFloat3 *= 0.7; 127 | 128 | $paramFloat3 += $f2 * 0.05; 129 | $paramFloat2 += $f1 * 0.05; 130 | 131 | $f2 *= 0.8; 132 | $f1 *= 0.5; 133 | $f2 += ($localRandom->nextFloat() - $localRandom->nextFloat()) * $localRandom->nextFloat() * 2.0; 134 | $f1 += ($localRandom->nextFloat() - $localRandom->nextFloat()) * $localRandom->nextFloat() * 4.0; 135 | 136 | if (($i === 0) && ($localRandom->nextBoundedInt(4) === 0)) { 137 | continue; 138 | } 139 | $d5 = $paramDouble1 - $d1; 140 | $d6 = $paramDouble3 - $d2; 141 | $d7 = $size - $stepCount; 142 | $d8 = $paramFloat1 + 2.0 + 16.0; 143 | if ($d5 * $d5 + $d6 * $d6 - $d7 * $d7 > $d8 * $d8) { 144 | return; 145 | } 146 | 147 | if (($paramDouble1 < $d1 - 16.0 - $d3 * 2.0) || ($paramDouble3 < $d2 - 16.0 - $d3 * 2.0) || ($paramDouble1 > $d1 + 16.0 + $d3 * 2.0) || ($paramDouble3 > $d2 + 16.0 + $d3 * 2.0)) 148 | continue; 149 | $k = floor($paramDouble1 - $d3) - ($chunkX * 16) - 1; 150 | $m = floor($paramDouble1 + $d3) - ($chunkZ * 16) + 1; 151 | 152 | $maxY = floor($paramDouble2 - $d4) - 1; 153 | $minY = floor($paramDouble2 + $d4) + 1; 154 | 155 | $i2 = floor($paramDouble3 - $d3) - ($chunkX * 16) - 1; 156 | $i3 = floor($paramDouble3 + $d3) - ($chunkZ * 16) + 1; 157 | 158 | if ($k < 0) 159 | $k = 0; 160 | if ($m > 16) 161 | $m = 16; 162 | 163 | if ($maxY < 1) 164 | $maxY = 1; 165 | if ($minY > $this->worldHeightCap - 8) 166 | $minY = $this->worldHeightCap - 8; 167 | 168 | if ($i2 < 0) 169 | $i2 = 0; 170 | if ($i3 > 16) 171 | $i3 = 16; 172 | 173 | $i4 = 0; 174 | for ($localX = $k; ($i4 == 0) && ($localX < $m); $localX++) { 175 | for ($localZ = $i2; ($i4 == 0) && ($localZ < $i3); $localZ++) { 176 | for ($localY = $minY + 1; ($i4 == 0) && ($localY >= $maxY - 1); $localY--) { 177 | if ($localY < 0) 178 | continue; 179 | if ($localY < $this->worldHeightCap) { 180 | $materialAtPosition = $generatingChunkBuffer->getBlockId($localX, $localY, $localZ); 181 | if ($materialAtPosition === Block::WATER 182 | || $materialAtPosition === Block::STILL_WATER) { 183 | $i4 = 1; 184 | } 185 | if (($localY != $maxY - 1) && ($localX != $k) && ($localX != $m - 1) && ($localZ != $i2) && ($localZ != $i3 - 1)) 186 | $localY = $maxY; 187 | } 188 | } 189 | } 190 | } 191 | if ($i4 != 0) { 192 | continue; 193 | } 194 | for ($localX = $k; $localX < $m; $localX++) { 195 | $d9 = ($localX + ($chunkX * 16) + 0.5 - $paramDouble1) / $d3; 196 | for ($localZ = $i2; $localZ < $i3; $localZ++) { 197 | $d10 = ($localZ + ($chunkZ * 16) + 0.5 - $paramDouble3) / $d3; 198 | if ($d9 * $d9 + $d10 * $d10 < 1.0) { 199 | for ($localY = $minY; $localY >= $maxY; $localY--) { 200 | $d11 = (($localY - 1) + 0.5 - $paramDouble2) / $d4; 201 | if (($d9 * $d9 + $d10 * $d10) * $this->a[$localY - 1] + $d11 * $d11 / 6.0 < 1.0) { 202 | $material = $generatingChunkBuffer->getBlockId($localX, $localY, $localZ); 203 | if (self::canBeReplaced($material)) { 204 | if ($localY - 1 < 10) { 205 | $generatingChunkBuffer->setBlock($localX, $localY, $localZ, Block::LAVA); 206 | } else { 207 | $generatingChunkBuffer->setBlock($localX, $localY, $localZ, Block::AIR); 208 | } 209 | } 210 | } 211 | } 212 | } 213 | } 214 | } 215 | if ($i != 0) 216 | break; 217 | } 218 | } 219 | 220 | public static function canBeReplaced(int $id): bool 221 | { 222 | return isset(self::$replaceable[$id]); 223 | } 224 | } -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/populator/SmallMushroomPopulator.php: -------------------------------------------------------------------------------- 1 | getHighestWorkableBlock($world, $x, $z); 25 | if ($y < 0) break; 26 | 27 | if ($world->getBlockAt($x + $i, $y, $z + $j)->getId() !== BlockLegacyIds::SAND) { 28 | break; 29 | } 30 | } 31 | } 32 | if ($y < 0) return null; 33 | 34 | return new Vector3($x + $i, $y, $z + $j); 35 | } 36 | 37 | protected function canStay(int $x, int $y, int $z, ChunkManager $world): bool 38 | { 39 | return EnsureCover::ensureCover($x, $y, $z, $world) && (EnsureGrassBelow::ensureGrassBelow($x, $y, $z, $world) || EnsureBelow::ensureBelow($x, $y, $z, VanillaBlocks::SAND(), $world)) && $this->findWater($x, $y - 1, $z, $world); 40 | } 41 | 42 | private function findWater(int $x, int $y, int $z, ChunkManager $world): bool 43 | { 44 | $count = 0; 45 | for ($i = $x - 4; $i < ($x + 4); $i++) { 46 | for ($j = $z - 4; $j < ($z + 4); $j++) { 47 | if (!$i || !$j || $i > 15 || $j > 15) continue; // edge of chunk 48 | $b = $world->getBlockAt($i, $y, $j)->getId(); 49 | if ($b === BlockLegacyIds::WATER || $b === BlockLegacyIds::STILL_WATER) { 50 | $count++; 51 | } 52 | if ($count > 10) { 53 | return true; 54 | } 55 | } 56 | } 57 | return ($count > 10); 58 | } 59 | 60 | protected function getBlock(int $x, int $z, Random $random, ChunkManager $world): Block 61 | { 62 | return VanillaBlocks::SUGARCANE(); 63 | } 64 | } -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/populator/SurfaceBlockPopulator.php: -------------------------------------------------------------------------------- 1 | nextBoundedInt(16) + $chunkX * Chunk::EDGE_LENGTH; 18 | $realZ = $random->nextBoundedInt(16) + $chunkZ * Chunk::EDGE_LENGTH; 19 | 20 | $y = $this->getHighestWorkableBlock($world, $realX, $realZ, $world); 21 | if ($y > 0 && $this->canStay($realX, $y, $realZ, $world)) { 22 | $this->placeBlock($realX, $y, $realZ, $this->getBlock($realX, $realZ, $random, $world), $world, $random); 23 | } 24 | } 25 | 26 | protected function getHighestWorkableBlock(ChunkManager $world, int $x, int $z): int 27 | { 28 | $y = 0; 29 | //start at 254 because we add one afterwards 30 | for ($y = 254; $y >= 0; --$y) { 31 | if (!PopulatorHelpers::isNonSolid($world->getBlockAt($x, $y, $z)->getId())) { 32 | break; 33 | } 34 | } 35 | 36 | return $y === 0 ? -1 : ++$y; 37 | } 38 | 39 | protected abstract function canStay(int $x, int $y, int $z, ChunkManager $world): bool; 40 | 41 | protected function placeBlock(int $x, int $y, int $z, Block $block, ChunkManager $world, Random $random): void 42 | { 43 | $world->setBlockAt($x, $y, $z, $block); 44 | } 45 | 46 | protected abstract function getBlock(int $x, int $z, Random $random, ChunkManager $world): Block; 47 | 48 | } -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/populator/TreePopulator.php: -------------------------------------------------------------------------------- 1 | nextRange($chunkX * Chunk::EDGE_LENGTH, ($chunkX * Chunk::EDGE_LENGTH) + Chunk::EDGE_LENGTH - 1); 31 | $z = $random->nextRange($chunkZ * Chunk::EDGE_LENGTH, ($chunkZ * Chunk::EDGE_LENGTH) + Chunk::EDGE_LENGTH - 1); 32 | $y = $this->getHighestWorkableBlock($world, $x, $z); 33 | 34 | if ($y < 3) { 35 | return; 36 | } 37 | 38 | switch ($this->type) { 39 | case TreeType::SPRUCE(): 40 | if ($this->super) { 41 | $tree = new BigSpruceTree(2, 8); 42 | } else { 43 | $tree = new SpruceTree(); 44 | } 45 | break; 46 | case TreeType::BIRCH(): 47 | $tree = new BirchTree($this->super); 48 | break; 49 | case TreeType::JUNGLE(): 50 | $tree = new JungleTree(); 51 | break; 52 | // case TreeType::ACACIA(): 53 | // $tree = new AcaciaTree(); 54 | // break; 55 | // case TreeType::DARK_OAK(): 56 | // $tree = new DarkOakTree(); 57 | // return; //TODO 58 | default: 59 | $tree = new OakTree(); 60 | // if($random->nextRange(0, 9) === 0){ 61 | // $tree = new BigTree(); 62 | // }else{ 63 | // $tree = new OakTree(); 64 | // } 65 | break; 66 | } 67 | if ($tree->canPlaceObject($world, $x, $y, $z, $random)) { 68 | $transaction = $tree?->getBlockTransaction($world, $x, $y, $z, $random); 69 | $transaction?->apply(); 70 | } 71 | } 72 | 73 | private function getHighestWorkableBlock(ChunkManager $world, int $x, int $z): int 74 | { 75 | for ($y = 254; $y > 0; --$y) { 76 | $b = $world->getBlockAt($x, $y, $z)->getId(); 77 | if ($b === BlockLegacyIds::DIRT || $b === BlockLegacyIds::GRASS || $b === BlockLegacyIds::TALL_GRASS) { 78 | break; 79 | } elseif ($b !== BlockLegacyIds::AIR && $b !== BlockLegacyIds::SNOW_LAYER) { 80 | return -1; 81 | } 82 | } 83 | 84 | return ++$y; 85 | } 86 | 87 | } -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/populator/WaterIcePopulator.php: -------------------------------------------------------------------------------- 1 | getChunk($chunkX, $chunkZ); 20 | $baseX = $chunkX * Chunk::EDGE_LENGTH; 21 | $baseZ = $chunkZ * Chunk::EDGE_LENGTH; 22 | for ($x = 0; $x < 16; $x++) { 23 | for ($z = 0; $z < 16; $z++) { 24 | $biome = CustomBiome::getBiome($chunk->getBiomeId($x, $z)); 25 | if ($biome->isFreezing()) { 26 | $y = $chunk->getHighestBlockAt($x, $z); 27 | if ($world->getBlockAt($baseX + $x, $y, $baseZ + $z)->getId() == BlockLegacyIds::STILL_WATER) { 28 | $world->setBlockAt($baseX + $x, $y, $baseZ + $z, VanillaBlocks::ICE()); 29 | } 30 | } 31 | } 32 | } 33 | } 34 | 35 | } -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/populator/helper/EnsureBelow.php: -------------------------------------------------------------------------------- 1 | getBlockAt($x, $y - 1, $z)->getId() === $block->getId(); 19 | } 20 | 21 | } -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/populator/helper/EnsureCover.php: -------------------------------------------------------------------------------- 1 | getBlockAt($x, $y, $z)->canBeReplaced(); 18 | } 19 | 20 | } -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/populator/helper/EnsureGrassBelow.php: -------------------------------------------------------------------------------- 1 | true, 15 | BlockLegacyIds::LEAVES => true, 16 | BlockLegacyIds::LEAVES2 => true, 17 | BlockLegacyIds::SNOW_LAYER => false, 18 | BlockLegacyIds::TALL_GRASS => true, 19 | ]; 20 | 21 | private function __construct() 22 | { 23 | } 24 | 25 | public static function canGrassStay(ChunkManager $world, int $x, int $y, int $z): bool 26 | { 27 | return EnsureCover::ensureCover($x, $y, $z, $world) && EnsureGrassBelow::ensureGrassBelow($x, $y, $z, $world); 28 | } 29 | 30 | public static function isNonSolid(int $id): bool 31 | { 32 | return self::NON_SOLID[$id] ?? false; 33 | } 34 | 35 | } -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/renderer/Picasso.php: -------------------------------------------------------------------------------- 1 | createMap(new Vector2(0, 0), $radius, 16); 23 | 24 | if (extension_loaded("gd")) { 25 | $image = $maker->createImageFromMap($map); 26 | 27 | if ($image) { 28 | $fileName = $seed . mt_rand(0, 100) . ".jpg"; 29 | imagejpeg($image, $this->getDataFolder() . $fileName); 30 | $this->getLogger()->notice("Image of the map saved(Seed: $seed)!"); 31 | } else { 32 | $this->getLogger()->error("Failed to save map"); 33 | } 34 | } else { 35 | $this->getLogger()->error("Can not create image, gd extension not found!"); 36 | } 37 | //goto make_map; 38 | } 39 | 40 | 41 | } -------------------------------------------------------------------------------- /src/BlockHorizons/BlockGenerator/renderer/Statistics.php: -------------------------------------------------------------------------------- 1 | getConstants(); 22 | 23 | $this->getLogger()->info("Creating a statistics file for seed: $seed ..."); 24 | for ($x = -$radius; $x <= $radius; $x++) { 25 | for ($z = -$radius; $z <= $radius; $z++) { 26 | $total++; 27 | $cx = $x * 16; 28 | $cz = $z * 16; 29 | $id = $selector->pickBiome($cx, $cz)->getId(); 30 | $biomeMap[$x][$z] = $id; 31 | 32 | if (!isset($biomeCount[$id])) { 33 | $biomeCount[$id] = 0; 34 | } 35 | $biomeCount[$id]++; 36 | 37 | if (isset($found[$id])) continue; 38 | $found[$id] = [$cx, $cz]; 39 | } 40 | } 41 | 42 | $log = "--------- Seed: $seed ------------" . PHP_EOL; 43 | $log .= "Radius: $radius" . PHP_EOL; 44 | $log .= "Chunks processed: " . $total . PHP_EOL; 45 | $log .= "Biomes in total: " . count($allBiomes) . PHP_EOL; 46 | $log .= "Biomes found: " . count($found) . PHP_EOL; 47 | $log .= PHP_EOL; 48 | $log .= " * Statistics:" . PHP_EOL; 49 | foreach ($allBiomes as $constant => $id) { 50 | if ($constant === "MAX_BIOMES" || !isset($biomeCount[$id])) continue; 51 | 52 | $p = round(($biomeCount[$id] ?? 0) / $total * 100, 1); 53 | $log .= "- " . self::pretty_constant($constant) . ": {$p}% (" . (($biomeCount[$id] ?? 0)) . " chunks)" . PHP_EOL; 54 | } 55 | $log .= "--------- End of statistics ---------" . PHP_EOL; 56 | $log .= " * Coords:" . PHP_EOL; 57 | foreach ($found as $id => $coords) { 58 | $name = self::pretty_constant(array_search($id, $allBiomes)); 59 | $log .= "- {$name}: X: " . $coords[0] . ", Z: " . $coords[1] . PHP_EOL; 60 | } 61 | $log .= "--------- End of Coords ---------" . PHP_EOL; 62 | $s = ""; 63 | foreach ($allBiomes as $constant => $id) { 64 | if (isset($found[$id])) continue; 65 | $s .= self::pretty_constant($constant) . ", "; 66 | } 67 | $log .= "Biomes not included: " . (strlen($s) > 0 ? rtrim($s, ", ") : "none") . PHP_EOL; 68 | $log .= "--------- End of File ---------"; 69 | 70 | echo $log; 71 | 72 | file_put_contents($this->getDataFolder() . "seed_{$seed}.txt", $log); 73 | } 74 | 75 | } --------------------------------------------------------------------------------