diff --git a/README.md b/README.md index 06d9197..f2d7706 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,32 @@ -# RealWorld +# GenPainterPE Pocketmine Generator for Earth and heightmap based generation. -# Installation -Note: This section is only for *nix users (Linux, MacOS, Unix, FreeBSD). Pmmp's windows' prebuilt binaries includes GD by default. +## What is GenPainterPE? +GenPainterPE is a PocketMine plugin which allows you to generate minecraft maps just with an heightmap. + +## How to use GenPainterPE? +First, look at [the installation part](#installation). +Creating a world would take the default config.yml settings, and then apply them to map creation (note: changing theses settings afterwards won't change them for the map. You should regenerate one another to change settings). +To create a world, you can: +- use a world utility which include a world generation +(such as [BetterGen](https://download.ad5001.eu/en/plugins) or ManyWorld) with the generator "genpainter" or, +- go to your pocketmine.yml, and at the end of the file, add a new world with the generator "genpainter". + +## Customizing GenPainterPE +You can customize GenPainterPE's generation by modifing some values in the config.yml. + +You can also add your own heightmap. [What is an heightmap?](https://en.wikipedia.org/wiki/Heightmap) +How to do that? +1. Get your heightmap in a png form (.png) +2. Put it into the GenPainterPE/heightmaps folder +3. Change the "heightmap_name" in the config.yml to the name of your heightmap (WITHOUT THE .png AT THE END) +4. Create a new world with the genpainter generator + +(note: you can modify your config afterwards and remove the .png as the world heightmap and data has been saved to your generated map) + + +## Installation +Note: This section is only for *nix users (Linux, MacOS, Unix, FreeBSD). PMMP's windows' prebuilt binaries includes GD by default. To support all the features including your own heightmap creation, you may need to install the PHP GD extension. Don't have it and don't know how to install it? - For PocketMine Server Manager users, check if the plugin is working, if not, just delete the folder located in <YOUR\_OWN\_FOLDER>/.pocketmine/php and restart PocketMine Server Manager. diff --git a/heightmap.png b/heightmap.png deleted file mode 100644 index bfdd562..0000000 Binary files a/heightmap.png and /dev/null differ diff --git a/plugin.yml b/plugin.yml index c3edb81..51110ba 100644 --- a/plugin.yml +++ b/plugin.yml @@ -1,9 +1,9 @@ --- -name: RealWorld +name: GenPainterPE author: Ad5001 version: 1.0 api: [3.0.0-ALPHA9] -main: Ad5001\RealWorld\Main +main: Ad5001\GenPainterPE\Main commands: [] permissions: [] ... \ No newline at end of file diff --git a/resources/big_5400x2700.png b/resources/big_5400x2700.png new file mode 100644 index 0000000..3b03291 Binary files /dev/null and b/resources/big_5400x2700.png differ diff --git a/resources/config.yml b/resources/config.yml new file mode 100644 index 0000000..e9cd2cb --- /dev/null +++ b/resources/config.yml @@ -0,0 +1,21 @@ +# Welcome to GenPainter's config. + +# Name of the heightmap to generate. +# Default heightmaps: big_5400x2700, normal_1000x500, and small_250_150. +# How to add a custom heightmap: https://github.com/Ad5001/GenPainterPE#add-heightmap +heightmap_name: normal_1000x500 + +# Should the generator generate caves and ravines? (BetterGen's) +generate_caves: true + +# Should the generator generate structures? (Trees, bushes, ...) +generate_structures: true + +# Should the generator generate biome's ground? (Grass blocks, sand, dirt, ...) +generate_custom_ground: true + +# Should the generator generate ores? (Diamond, gold, iron... but also dirt, gravel,...) +generate_ores: true + +# Should the generator generate biomes? +generate_biomes: true \ No newline at end of file diff --git a/resources/heightmap.jpg b/resources/heightmap.jpg deleted file mode 100644 index 24730b0..0000000 Binary files a/resources/heightmap.jpg and /dev/null differ diff --git a/resources/heightmap.png b/resources/heightmap.png deleted file mode 100644 index bfdd562..0000000 Binary files a/resources/heightmap.png and /dev/null differ diff --git a/resources/normal_1000x500.png b/resources/normal_1000x500.png new file mode 100644 index 0000000..90bc6ca Binary files /dev/null and b/resources/normal_1000x500.png differ diff --git a/resources/small_250x150.png b/resources/small_250x150.png new file mode 100644 index 0000000..3ee704d Binary files /dev/null and b/resources/small_250x150.png differ diff --git a/src/Ad5001/GenPainterPE/Main.php b/src/Ad5001/GenPainterPE/Main.php new file mode 100644 index 0000000..eeef544 --- /dev/null +++ b/src/Ad5001/GenPainterPE/Main.php @@ -0,0 +1,146 @@ +getDataFolder()); + @mkdir($this->getDataFolder() . "tmp"); + @mkdir($this->getDataFolder() . "heightmaps"); + $this->saveDefaultConfig(); + if(!file_exists($this->getDataFolder() . "heightmaps/big_5400x2700.png")) file_put_contents($this->getDataFolder() . "heightmaps/big_5400x2700.png", $this->getResource("big_5400x2700.png")); + if(!file_exists($this->getDataFolder() . "heightmaps/normal_1000x500.png")) file_put_contents($this->getDataFolder() . "heightmaps/normal_1000x500.png", $this->getResource("normal_1000x500.png")); + if(!file_exists($this->getDataFolder() . "heightmaps/small_250x150.png")) file_put_contents($this->getDataFolder() . "heightmaps/small_250x150.png", $this->getResource("small_250x150.png")); + $this->getServer()->getPluginManager()->registerEvents($this, $this); + // Register generators + Generator::addGenerator(GenPainter::class, "genpainter"); + } + + /** + * Checks when a command is sent. + * + * @param CommandSender $sender + * @param Command $cmd + * @param string $label + * @param array $args + * @return bool + */ + public function onCommand(CommandSender $sender, Command $cmd, string $label, array $args): bool{ + switch($cmd->getName()){ + case "default": + break; + } + return false; + } + + + /** + * Called when the plugin disables + */ + public function onDisable() { + foreach(array_diff(scandir($this->getDataFolder() . "tmp"), ["..", "."]) as $link){ + unlink($this->getDataFolder() . "tmp/" . $link); + } + } + + + /** + * Checks when a world will start being generated to give it's id to it and start generation + * + * @param EntityLevelChangeEvent $ev + * @return void + */ + public function onEntityLevelChange(EntityLevelChangeEvent $event){ + if($event->getTarget()->getProvider()->getGenerator() == "worldpainter" && + $event->getEntity() instanceof Player){ + $spawnpoint = json_decode( + file_get_contents( + get_cwd() . "/worlds/" . $event->getTarget()->getFolderName() . "/gendata/geninfos.json" + ) + )->startPoint; + $event->getEntity()->setSpawn(new Position($spawnpoint[0], $spawnpoint[1], $spawnpoint[2], $event->getTarget())); + } + } + + /** + * Generates all ranges for biomes. + * Default WATER_HEIGHT is 100. + * Sorry for the formating, but it's the crisis. + * Big screens are too expensive. + * + * @return void + */ + public static function generateRanges(){ + self::$BIOMES_BY_RANGE = []; + self::$BIOMES_BY_RANGE[Biome::OCEAN] = new Range( + GenPainter::MIN_HEIGHT, + GenPainter::WATER_HEIGHT); + self::$BIOMES_BY_RANGE[Biome::RIVER] = new Range(GenPainter::WATER_HEIGHT, + GenPainter::WATER_HEIGHT + (17 * GenPainter::DEPTH_MULTIPLICATOR)); + self::$BIOMES_BY_RANGE[Biome::SWAMP] = new Range(GenPainter::WATER_HEIGHT, + GenPainter::WATER_HEIGHT + (17 * GenPainter::DEPTH_MULTIPLICATOR)); + self::$BIOMES_BY_RANGE[Biome::DESERT] = new Range( + GenPainter::WATER_HEIGHT + (8 * GenPainter::DEPTH_MULTIPLICATOR), + GenPainter::WATER_HEIGHT + (52 * GenPainter::DEPTH_MULTIPLICATOR)); + self::$BIOMES_BY_RANGE[Biome::ICE_PLAINS] = new Range( + GenPainter::WATER_HEIGHT + (17 * GenPainter::DEPTH_MULTIPLICATOR), + GenPainter::WATER_HEIGHT + (46 * GenPainter::DEPTH_MULTIPLICATOR)); + self::$BIOMES_BY_RANGE[Biome::PLAINS] = new Range( + GenPainter::WATER_HEIGHT + (17 * GenPainter::DEPTH_MULTIPLICATOR), + GenPainter::WATER_HEIGHT + (52 * GenPainter::DEPTH_MULTIPLICATOR)); + self::$BIOMES_BY_RANGE[Biome::FOREST] = new Range( + GenPainter::WATER_HEIGHT + (40 * GenPainter::DEPTH_MULTIPLICATOR), + GenPainter::WATER_HEIGHT + (78 * GenPainter::DEPTH_MULTIPLICATOR)); + self::$BIOMES_BY_RANGE[Biome::BIRCH_FOREST] = new Range( + GenPainter::WATER_HEIGHT + (40 * GenPainter::DEPTH_MULTIPLICATOR), + GenPainter::WATER_HEIGHT + (78 * GenPainter::DEPTH_MULTIPLICATOR)); + self::$BIOMES_BY_RANGE[Biome::TAIGA] = new Range( + GenPainter::WATER_HEIGHT + (52 * GenPainter::DEPTH_MULTIPLICATOR), + GenPainter::WATER_HEIGHT + (78 * GenPainter::DEPTH_MULTIPLICATOR)); + self::$BIOMES_BY_RANGE[Biome::SMALL_MOUNTAINS] = new Range( + GenPainter::WATER_HEIGHT + (78 * GenPainter::DEPTH_MULTIPLICATOR), + GenPainter::WATER_HEIGHT + (158 * GenPainter::DEPTH_MULTIPLICATOR)); + self::$BIOMES_BY_RANGE[Biome::MOUNTAINS] = new Range( + GenPainter::WATER_HEIGHT + (158 * GenPainter::DEPTH_MULTIPLICATOR), + GenPainter::WATER_HEIGHT + (258 * GenPainter::DEPTH_MULTIPLICATOR)); + } + + + /** + * Prompts the command line for a message + * + * @param string $message + * @return void + */ + public static function prompt(string $message): string{ + if (PHP_OS == 'WINNT') { + echo $message; + $line = stream_get_line(STDIN, 1024, PHP_EOL); + } else { + $line = readline($message); + } + return $line; + } +} \ No newline at end of file diff --git a/src/Ad5001/RealWorld/generator/RealWorld.php b/src/Ad5001/GenPainterPE/generator/GenPainter.php similarity index 50% rename from src/Ad5001/RealWorld/generator/RealWorld.php rename to src/Ad5001/GenPainterPE/generator/GenPainter.php index 6fd0237..9445346 100644 --- a/src/Ad5001/RealWorld/generator/RealWorld.php +++ b/src/Ad5001/GenPainterPE/generator/GenPainter.php @@ -1,5 +1,5 @@ genid = Main::$GENERATOR_IDS++; + } /** - * Inits the class for the variables. mw create Test 902874635 realworld + * Inits the class for the variables. mw create Test 902874635 worldpainter * Executed on the main thread. * $level is actually a level instance. * @param ChunkManager $level @@ -82,41 +84,53 @@ class RealWorld extends Generator{ $this->level = $level; $this->random = $random; $this->random->setSeed($this->level->getSeed()); - if($level instanceof Level) { // First init in main thread - $this->worldpath = getcwd() . "/worlds/" . $level->getName() . "/"; + if($level instanceof Level && + isset($this->genid)) { // First init in main thread + $this->worldpath = getcwd() . "/worlds/" . $level->getName() . "/"; // Initing folder data @mkdir($this->worldpath . "gendata"); + $config = yaml_parse(file_get_contents(getcwd() . "/plugins/GenPainterPE/config.yml")); // Checking heightmap if(!file_exists($this->worldpath . "gendata/heightmap.png")) { - copy(getcwd() . "/plugins/RealWorld/heightmap.png", $this->worldpath . "gendata/heightmap.png"); + copy(getcwd() . "/plugins/GenPainterPE/heightmaps/" . $config["heightmap_name"] . ".png", $this->worldpath . "gendata/heightmap.png"); } $this->heightmap = \imagecreatefrompng($this->worldpath . "gendata/heightmap.png"); // Checking gen infos (startpoint, ...) if(!file_exists($this->worldpath . "gendata/geninfos.json")) { $data = []; - $data["#"] = "DO NOT MODIFY THIS FILE. IT HAS BEEN GENERATED BY RealWorld AND UNEXEPTED ISSUES MAY OCCUR IF YOU MODIFY ANY OF THESES VALUES."; // Do not modify comment in file for noobs. + $data["#"] = "DO NOT MODIFY THIS FILE. IT HAS BEEN GENERATED BY GenPainterPE AND UNEXEPTED ISSUES MAY OCCUR IF YOU MODIFY ANY OF THESES VALUES."; // Do not modify comment in file for noobs. + $spawn = $this->getSpawnsFromImg(); $data["startPoint"] = [ - $random->nextRange(round(-imagesy($this->heightmap)) / 2, round(imagesy($this->heightmap) / 2)), - $random->nextRange(round(-imagesx($this->heightmap)) / 2, round(imagesx($this->heightmap) / 2)), + $spawn->x, + $spawn->y, + $spawn->z ]; + $data = array_merge($data, $config); + unset($data["heightmap_name"]); file_put_contents($this->worldpath . "gendata/geninfos.json", json_encode($data)); + if($this->getServer()->getPluginManager()->getPlugin("PSMCore") !== null) \Ad5001\PSMCore\API::displayNotification("GenPainter", "Generating world " . $level->getName() . "..."); } - $options = json_decode(file_get_contents($this->worldpath . "gendata/geninfos.json")); - $this->startPoint = $options->startPoint; - } else { - var_dump($this); + // Adding symlink to get path later. + if(file_exists(getcwd() . "/plugins/GenPainterPE/tmp/" . $this->genid)) unlink(getcwd() . "/plugins/GenPainterPE/tmp/" . $this->genid); + symlink($this->worldpath, getcwd() . "/plugins/GenPainterPE/tmp/" . $this->genid); } + // Regetting the vars from the symlinked folder + $this->worldpath = readlink(getcwd() . "/plugins/GenPainterPE/tmp/" . $this->genid); + $this->heightmap = \imagecreatefrompng($this->worldpath . "gendata/heightmap.png"); + $this->options = json_decode(file_get_contents($this->worldpath . "gendata/geninfos.json")); + $this->startPoint = $this->options->startPoint; // Making selector $this->selector = new BiomeSelector($this->random, function($temperature, $rainfall){ // Checking the nearest candidate biome that have the closest $temperature and $rainfall. - $bestBiome = [PHP_INT_MAX, Biome::getBiome(Biome::OCEAN)]; // Default biome + $bestBiome = [405001, Biome::getBiome(Biome::OCEAN)]; // Default biome. Should be enough. foreach($this->candidatesBiomes as $b){ $diffRainFall = abs($b->getRainfall() - $rainfall); $diffTemperature = abs($b->getTemperature() - $temperature); $diff = $diffRainFall + $diffTemperature; // Total diff. if($diff < $bestBiome[0]) $bestBiome = [$diff, $b]; } + return $bestBiome[1]->getId(); }, Biome::getBiome(Biome::OCEAN)); $this->selector->addBiome(Biome::getBiome(Biome::OCEAN)); @@ -130,31 +144,36 @@ class RealWorld extends Generator{ $this->selector->addBiome(Biome::getBiome(Biome::ICE_PLAINS)); $this->selector->addBiome(Biome::getBiome(Biome::SMALL_MOUNTAINS)); $this->selector->addBiome(Biome::getBiome(Biome::BIRCH_FOREST)); - $this->selector->recalculate(); // Populators - $cover = new GroundCover(); - $this->generationPopulators[] = $cover; - $cave = new CavePopulator (); - $cave->setBaseAmount(0); - $cave->setRandomAmount(2); - $this->generationPopulators[] = $cave; - $ravine = new RavinePopulator (); - $ravine->setBaseAmount(0); - $ravine->setRandomAmount(51); - $this->generationPopulators[] = $ravine; - $ores = new Ore(); - $ores->setOreTypes([ - new OreType(BlockFactory::get(Block::COAL_ORE), 20, 16, 0, 128), - new OreType(BlockFactory::get(Block::IRON_ORE), 20, 8, 0, 64), - new OreType(BlockFactory::get(Block::REDSTONE_ORE), 8, 7, 0, 16), - new OreType(BlockFactory::get(Block::LAPIS_ORE), 1, 6, 0, 32), - new OreType(BlockFactory::get(Block::GOLD_ORE), 2, 8, 0, 32), - new OreType(BlockFactory::get(Block::DIAMOND_ORE), 1, 7, 0, 16), - new OreType(BlockFactory::get(Block::DIRT), 20, 32, 0, 128), - new OreType(BlockFactory::get(Block::GRAVEL), 10, 16, 0, 128) - ]); - $this->populators[] = $ores; + if($this->options->generate_custom_ground){ + $cover = new GroundCover(); + $this->generationPopulators[] = $cover; + } + if($this->options->generate_caves){ + $cave = new CavePopulator (); + $cave->setBaseAmount(0); + $cave->setRandomAmount(2); + $this->generationPopulators[] = $cave; + $ravine = new RavinePopulator (); + $ravine->setBaseAmount(0); + $ravine->setRandomAmount(51); + $this->generationPopulators[] = $ravine; + } + if($this->options->generate_ores) { + $ores = new Ore(); + $ores->setOreTypes([ + new OreType(BlockFactory::get(Block::COAL_ORE), 20, 16, 0, 128), + new OreType(BlockFactory::get(Block::IRON_ORE), 20, 8, 0, 64), + new OreType(BlockFactory::get(Block::REDSTONE_ORE), 8, 7, 0, 16), + new OreType(BlockFactory::get(Block::LAPIS_ORE), 1, 6, 0, 32), + new OreType(BlockFactory::get(Block::GOLD_ORE), 2, 8, 0, 32), + new OreType(BlockFactory::get(Block::DIAMOND_ORE), 1, 7, 0, 16), + new OreType(BlockFactory::get(Block::DIRT), 20, 32, 0, 128), + new OreType(BlockFactory::get(Block::GRAVEL), 10, 16, 0, 128) + ]); + $this->generationPopulators[] = $ores; + } } /** @@ -166,29 +185,35 @@ class RealWorld extends Generator{ */ public function generateChunk(int $chunkX, int $chunkZ){ $this->random->setSeed(0xdeadbeef ^ ($chunkX << 8) ^ $chunkZ ^ $this->level->getSeed()); - $chunk = $this->level->getChunk($chunkX, $chunkZ); + $chunk = $this->level->getChunk($chunkX, $chunkZ); for($x = 0; $x < 16; $x++) { for($z = 0; $z < 16; $z++) { // Getting biome & height $currentX = $chunkX * 16 + $x; - $currentZ = $chunkZ * 16 + $x; + $currentZ = $chunkZ * 16 + $z; $height = $this->getHeightFromImg($currentX, $currentZ); $biome = $this->getBiomeFromPos($currentX, $currentZ); $chunk->setBiomeId($x, $z, $biome->getId()); // Building terrain - for($y = 0; $y < 128; ++$y) { + for($y = 0; $y < 256; ++$y) { if($y === 0) { $chunk->setBlockId($x, $y, $z, Block::BEDROCK); - continue; - } - if($y <= $height) { + } elseif($y <= self::BEDROCK_MAX_HEIGHT && $this->random->nextBoundedInt(2) == 0) { + $chunk->setBlockId($x, $y, $z, Block::BEDROCK); + } elseif($y <= $height) { $chunk->setBlockId($x, $y, $z, Block::STONE); - } elseif($y <= $this->waterHeight) { + } elseif($y <= self::WATER_HEIGHT) { $chunk->setBlockId($x, $y, $z, Block::STILL_WATER); } } } } + foreach($this->generationPopulators as $populator){ + $populator->populate($this->level, $chunkX, $chunkZ, $this->random); + } + // Logging + echo "Land at " . ($chunkX * 16 + 7) . ", " . ($chunkZ * 16 + 7) . + " with biome " . $this->getBiomeFromPos($chunkZ * 16 + 7, $chunkZ * 16 + 7)->getName() . "\n"; } @@ -200,13 +225,16 @@ class RealWorld extends Generator{ * @return void */ public function populateChunk(int $chunkX, int $chunkZ){ - $this->random->setSeed(0xdeadbeef ^ ($chunkX << 8) ^ $chunkZ ^ $this->level->getSeed()); - foreach($this->populators as $populator){ - $populator->populate($this->level, $chunkX, $chunkZ, $this->random); - } - $chunk = $this->level->getChunk($chunkX, $chunkZ); - $biome = Biome::getBiome($chunk->getBiomeId(7, 7)); - $biome->populateChunk($this->level, $chunkX, $chunkZ, $this->random); + $this->random->setSeed(0xdeadbeef ^ ($chunkX << 8) ^ $chunkZ ^ $this->level->getSeed()); + // Check if the generator should generate structures. + if($this->options->generate_structures) { + foreach($this->populators as $populator){ + $populator->populate($this->level, $chunkX, $chunkZ, $this->random); + } + $chunk = $this->level->getChunk($chunkX, $chunkZ); + $biome = Biome::getBiome($chunk->getBiomeId(7, 7)); + $biome->populateChunk($this->level, $chunkX, $chunkZ, $this->random); + } } @@ -219,15 +247,23 @@ class RealWorld extends Generator{ */ public function getBiomeFromPos(int $x, int $z): Biome{ $this->candidatesBiomes = []; - if(count(Main::$BIOMES_BY_RANGE) < 0) Main::generateRanges(); + if(count(Main::$BIOMES_BY_RANGE) < 1) Main::generateRanges(); $height = $this->getHeightFromImg($x, $z); + // Check if the generator should generate biomes + if(!$this->options->generate_biomes) { + if($height > self::WATER_HEIGHT) { + return Biome::get(Biome::PLAINS); + } else { + return Biome::get(Biome::OCEAN); + } + } // Foreaching all biomes to see which ones could be generated foreach(Main::$BIOMES_BY_RANGE as $biomeId => $range){ if($range->isInRange($height)) $this->candidatesBiomes[] = Biome::getBiome($biomeId); } // Checking wether there are multiple candidates or not. // If so, choose a biome. - if(count($this->candidatesBiomes == 1)){ + if(count($this->candidatesBiomes) == 1){ $biome = $this->candidatesBiomes[0]; } else { $hash = $x * 2345803 ^ $z * 9236449 ^ $this->level->getSeed(); @@ -257,33 +293,46 @@ class RealWorld extends Generator{ public function getHeightFromImg(int $x, int $z): int{ if(isset(self::$cachedHeights[$x . ";" . $z])) return round(self::$cachedHeights[$x . ";" . $z]); // Getting height px of the world - $imgGetDatX = ($x - $this->startPoint[0]) % imagesy($this->heightmap); - if($imgGetDatX < 0) $imgGetDatX += imagesy($this->heightmap); + $imgGetDatX = abs($x) % imagesy($this->heightmap); // Getting width px of the world - $imgGetDatZ = ($z - $this->startPoint[1]) % imagesx($this->heightmap); - if($imgGetDatZ < 0) $z += imagesx($this->heightmap); + $imgGetDatZ = abs($z) % imagesx($this->heightmap); // Finally, getting the px to determine the height of the top block - $imgheight = (imagecolorat($this->heightmap, 10, 15) >> 16) & 0xFF; // Getting height from the red channel. + $imgheight = imagecolorsforindex($this->heightmap, imagecolorat($this->heightmap, $imgGetDatZ, $imgGetDatX))["red"]; // Getting height from the red channel. // In a normal heightmap, all the chanel ouputs the same (exepct alpha) // Smoothing out. $surroundValues = []; // Getting surround values if(isset(self::$cachedHeights[($x+1) . ";" . ($z+1)])) $surroundValues[] = self::$cachedHeights[($x+1) . ";" . ($z+1)]; - if(isset(self::$cachedHeights[($x+1) . ";" . ($z)])) $surroundValues[] = self::$cachedHeights[($x+1) . ";" . ($z+1)]; - if(isset(self::$cachedHeights[($x+1) . ";" . ($z-1)])) $surroundValues[] = self::$cachedHeights[($x+1) . ";" . ($z+1)]; - if(isset(self::$cachedHeights[($x) . ";" . ($z+1)])) $surroundValues[] = self::$cachedHeights[($x+1) . ";" . ($z+1)]; - if(isset(self::$cachedHeights[($x) . ";" . ($z-1)])) $surroundValues[] = self::$cachedHeights[($x+1) . ";" . ($z+1)]; - if(isset(self::$cachedHeights[($x-1) . ";" . ($z+1)])) $surroundValues[] = self::$cachedHeights[($x+1) . ";" . ($z+1)]; - if(isset(self::$cachedHeights[($x-1) . ";" . ($z)])) $surroundValues[] = self::$cachedHeights[($x+1) . ";" . ($z+1)]; - if(isset(self::$cachedHeights[($x-1) . ";" . ($z-1)])) $surroundValues[] = self::$cachedHeights[($x+1) . ";" . ($z+1)]; - $surroundValues[] = $imgheight * self::DEPTH_MULTIPLICATOR + self::WATER_HEIGHT + $this->random->nextBoundedInt(4) - 1; + if(isset(self::$cachedHeights[($x+1) . ";" . ($z)])) $surroundValues[] = self::$cachedHeights[($x+1) . ";" . ($z)]; + if(isset(self::$cachedHeights[($x+1) . ";" . ($z-1)])) $surroundValues[] = self::$cachedHeights[($x+1) . ";" . ($z-1)]; + if(isset(self::$cachedHeights[($x) . ";" . ($z+1)])) $surroundValues[] = self::$cachedHeights[($x) . ";" . ($z+1)]; + if(isset(self::$cachedHeights[($x) . ";" . ($z-1)])) $surroundValues[] = self::$cachedHeights[($x) . ";" . ($z-1)]; + if(isset(self::$cachedHeights[($x-1) . ";" . ($z+1)])) $surroundValues[] = self::$cachedHeights[($x-1) . ";" . ($z+1)]; + if(isset(self::$cachedHeights[($x-1) . ";" . ($z)])) $surroundValues[] = self::$cachedHeights[($x-1) . ";" . ($z)]; + if(isset(self::$cachedHeights[($x-1) . ";" . ($z-1)])) $surroundValues[] = self::$cachedHeights[($x-1) . ";" . ($z-1)]; + + $imgValue = $imgheight * self::DEPTH_MULTIPLICATOR + self::WATER_HEIGHT; + if($imgheight == 0) { + // Calculating presmooth value (to generate $imgheight water value alot smoother and going deeper) + if(count($surroundValues) !== 0) { + $preSmoothValue = 0; + foreach($surroundValues as $v) $preSmoothValue += $v; + $preSmoothValue /= count($surroundValues); + } else { + $preSmoothValue = 100; + } + $calcDiffValue = ($preSmoothValue - 100) / 2; + if(round($calcDiffValue) == -3) $calcDiffValue--; + $imgValue += -$this->random->nextBoundedInt(3 + round($calcDiffValue)) - 3 + $calcDiffValue;// Used to make water depth. + } // Calculating smooth value - $smoothValue = -1; // Starting at -1 to make water depth. - foreach($surroundValues as $v) $smoothValue += $v; - $smoothValue /= count($surroundValues); - if($smoothValue < self::MIN_HEIGHT) $smoothValue = self::MIN_HEIGHT; - self::$cachedHeights[$x . ";" . $z] = $smoothValue; - return round($smoothValue); // Rounding it so that we can use it as a block height + // $smoothValue = -1; + // foreach($surroundValues as $v) $smoothValue += $v; + // $smoothValue += $imgValue * 3; + // $smoothValue /= count($surroundValues) + 3; + if($imgValue < self::MIN_HEIGHT) $imgValue = self::MIN_HEIGHT; + self::$cachedHeights[$x . ";" . $z] = $imgValue; + return round($imgValue); // Rounding it so that we can use it as a block height } @@ -294,7 +343,7 @@ class RealWorld extends Generator{ * @return string */ public function getName(): string { - return "realworld"; + return "worldpainter"; } /** @@ -311,15 +360,20 @@ class RealWorld extends Generator{ * @return Vector3 */ public function getSpawn(): Vector3 { - return new Vector3(127.5, 128, 127.5); - } + return new Vector3($this->spawnPoint[0], + $this->spawnPoint[1], + $this->spawnPoint[2]); + } + /** * Returns a safe spawn location * * @return Vector3 */ public function getSafeSpawn() { - return new Vector3(127.5, $this->getHighestWorkableBlock(127, 127), 127.5); + return new Vector3($this->spawnPoint[0], + $this->spawnPoint[1], + $this->spawnPoint[2]); } /* @@ -338,5 +392,28 @@ class RealWorld extends Generator{ } return ++$y; - } + } + + + /** + * Checks the image for a safes spawns (not in water) then saves it. + * + * @return void + */ + public function getSpawnsFromImg(): Vector3{ + $spawn = new Vector3(128, 128, 128); + $found = []; + mt_srand($this->random->getSeed()); + for($i = 0; $i < 1028; $i++){ // Checking 1028 spots to check for a spawn. If none are found, default to 128 128 128. + $x = mt_rand(0, imagesy($this->heightmap) - 1); + $z = mt_rand(0, imagesx($this->heightmap) - 1); + $imgheight = imagecolorsforindex($this->heightmap, imagecolorat($this->heightmap, $z, $x))["red"]; + if($imgheight !== 0){ + $imgValue = $imgheight * self::DEPTH_MULTIPLICATOR + self::WATER_HEIGHT + 2; // +2 is here so that the player will not get stuck in a block. + $found[] = new Vector3($x, round($imgValue), $z); + } + } + if(count($found) == 0) return $spawn; + return $found[mt_rand(0, count($found) - 1)]; + } } \ No newline at end of file diff --git a/src/Ad5001/RealWorld/populator/AmountPopulator.php b/src/Ad5001/GenPainterPE/populator/AmountPopulator.php similarity index 96% rename from src/Ad5001/RealWorld/populator/AmountPopulator.php rename to src/Ad5001/GenPainterPE/populator/AmountPopulator.php index be5d3b5..281f53c 100644 --- a/src/Ad5001/RealWorld/populator/AmountPopulator.php +++ b/src/Ad5001/GenPainterPE/populator/AmountPopulator.php @@ -3,7 +3,7 @@ * Imported from BetterGen (https://github.com/Ad5001/BetterGen/blob/master/src/Ad5001/BetterGen/populator/AmountPopulator.php) */ -namespace Ad5001\RealWorld\populator; +namespace Ad5001\GenPainterPE\populator; use pocketmine\level\generator\populator\Populator; use pocketmine\utils\Random; diff --git a/src/Ad5001/RealWorld/populator/CavePopulator.php b/src/Ad5001/GenPainterPE/populator/CavePopulator.php similarity index 98% rename from src/Ad5001/RealWorld/populator/CavePopulator.php rename to src/Ad5001/GenPainterPE/populator/CavePopulator.php index 9e28c89..82cc767 100644 --- a/src/Ad5001/RealWorld/populator/CavePopulator.php +++ b/src/Ad5001/GenPainterPE/populator/CavePopulator.php @@ -3,9 +3,9 @@ * Imported from BetterGen (https://github.com/Ad5001/BetterGen/blob/master/src/Ad5001/BetterGen/populator/CavePopulator.php) */ -namespace Ad5001\RealWorld\populator; +namespace Ad5001\GenPainterPE\populator; -use Ad5001\RealWorld\utils\BuildingUtils; +use Ad5001\GenPainterPE\utils\BuildingUtils; use pocketmine\block\Block; use pocketmine\level\ChunkManager; use pocketmine\level\Level; diff --git a/src/Ad5001/RealWorld/populator/RavinePopulator.php b/src/Ad5001/GenPainterPE/populator/RavinePopulator.php similarity index 97% rename from src/Ad5001/RealWorld/populator/RavinePopulator.php rename to src/Ad5001/GenPainterPE/populator/RavinePopulator.php index 05fea7a..e6493b7 100644 --- a/src/Ad5001/RealWorld/populator/RavinePopulator.php +++ b/src/Ad5001/GenPainterPE/populator/RavinePopulator.php @@ -3,9 +3,9 @@ * Imported from BetterGen (https://github.com/Ad5001/BetterGen/blob/master/src/Ad5001/BetterGen/populator/RavinePopulator.php) */ -namespace Ad5001\RealWorld\populator; +namespace Ad5001\GenPainterPE\populator; -use Ad5001\RealWorld\utils\BuildingUtils; +use Ad5001\GenPainterPE\utils\BuildingUtils; use pocketmine\block\Block; use pocketmine\level\ChunkManager; use pocketmine\level\Level; diff --git a/src/Ad5001/GenPainterPE/utils/BiomeSelector.php b/src/Ad5001/GenPainterPE/utils/BiomeSelector.php new file mode 100644 index 0000000..0c61303 --- /dev/null +++ b/src/Ad5001/GenPainterPE/utils/BiomeSelector.php @@ -0,0 +1,75 @@ +fallback = $fallback; + $this->lookup = $lookup; + $this->temperature = new Simplex($random, 2, 1 / 16, 1 / 512); + $this->rainfall = new Simplex($random, 2, 1 / 16, 1 / 512); + } + + /** + * Adds a biome to the selector + * + * @param Biome $biome + * @return void + */ + public function addBiome(Biome $biome){ + $this->biomes[$biome->getId()] = $biome; + } + + /** + * Returns the temperature of a biome + * + * @param [type] $x + * @param [type] $z + * @return void + */ + public function getTemperature($x, $z){ + return ($this->temperature->noise2D($x, $z, true) + 1) / 2; + } + + /** + * Returns the rainfall of a location + * + * @param int $x + * @param int $z + * @return void + */ + public function getRainfall($x, $z){ + return ($this->rainfall->noise2D($x, $z, true) + 1) / 2; + } + + /** + * @param $x + * @param $z + * + * @return Biome + */ + public function pickBiome($x, $z) : Biome{ + $temperature = (int) ($this->getTemperature($x, $z) * 63); + $rainfall = (int) ($this->getRainfall($x, $z) * 63); + $biomeId = call_user_func($this->lookup, $temperature / 63, $rainfall / 63); + return $this->biomes[$biomeId] ?? $this->fallback; + } +} \ No newline at end of file diff --git a/src/Ad5001/RealWorld/utils/BuildingUtils.php b/src/Ad5001/GenPainterPE/utils/BuildingUtils.php similarity index 99% rename from src/Ad5001/RealWorld/utils/BuildingUtils.php rename to src/Ad5001/GenPainterPE/utils/BuildingUtils.php index 6a7f371..e2cfbe1 100644 --- a/src/Ad5001/RealWorld/utils/BuildingUtils.php +++ b/src/Ad5001/GenPainterPE/utils/BuildingUtils.php @@ -3,7 +3,7 @@ * Imported from BetterGen (https://github.com/Ad5001/BetterGen/blob/master/src/Ad5001/BetterGen/utils/BuildingUtils.php) */ -namespace Ad5001\RealWorld\utils; +namespace Ad5001\GenPainterPE\utils; use pocketmine\block\Block; use pocketmine\level\ChunkManager; @@ -18,7 +18,7 @@ class BuildingUtils { Block::LAVA, Block::BEDROCK, Block::CACTUS, - Block::PLANK + Block::PLANKS ]; /** diff --git a/src/Ad5001/RealWorld/utils/Range.php b/src/Ad5001/GenPainterPE/utils/Range.php similarity index 93% rename from src/Ad5001/RealWorld/utils/Range.php rename to src/Ad5001/GenPainterPE/utils/Range.php index 4135b2f..19a5c56 100644 --- a/src/Ad5001/RealWorld/utils/Range.php +++ b/src/Ad5001/GenPainterPE/utils/Range.php @@ -1,6 +1,6 @@ getDataFolder()); - if(!file_exists($this->getDataFolder() . "heightmap.png")) { // Get default world HeightMap - file_put_contents($this->getDataFolder() . "heightmap.png", $this->getResource("heightmap.png")); - } - $this->getServer()->getPluginManager()->registerEvents($this, $this); - // Register generators - Generator::addGenerator(RealWorld::class, "realworld"); - } - - /** - * Checks when a command is sent. - * - * @param CommandSender $sender - * @param Command $cmd - * @param string $label - * @param array $args - * @return bool - */ - public function onCommand(CommandSender $sender, Command $cmd, string $label, array $args): bool{ - switch($cmd->getName()){ - case "default": - break; - } - return false; - } - - - // /** - // * Checks when a world will start being generated to give it's id to it and start generation - // * - // * @param LevelInitEvent $ev - // * @return void - // */ - // public function onLevelInit(LevelInitEvent $ev){ - // $lvl = $ev->getLevel(); - // $contents = ""; - // if(file_exists($this->getDataFolder() . "worldsids.txt")){ - // $contents = file_get_contents($this->getDataFolder() . "worldsids.txt") . "\n"; - // } - // $contents .= $lvl->getId() . ": " . $lvl->getName(); - // file_put_contents($this->getDataFolder() . "worldsids.txt") - // } - - /** - * Generates all ranges for biomes. - * Default WATER_HEIGHT is 100 - * - * @return void - */ - public static function generateRanges(){ - self::$BIOMES_BY_RANGE = []; - self::$BIOMES_BY_RANGE[Biome::OCEAN] = new Range(RealWorld::MIN_HEIGHT, RealWorld::WATER_HEIGHT); - self::$BIOMES_BY_RANGE[Biome::RIVER] = new Range(RealWorld::WATER_HEIGHT, RealWorld::WATER_HEIGHT + 10); - self::$BIOMES_BY_RANGE[Biome::SWAMP] = new Range(RealWorld::WATER_HEIGHT, RealWorld::WATER_HEIGHT + 10); - self::$BIOMES_BY_RANGE[Biome::DESERT] = new Range(RealWorld::WATER_HEIGHT + 5, RealWorld::WATER_HEIGHT + 31); - self::$BIOMES_BY_RANGE[Biome::ICE_PLAINS] = new Range(RealWorld::WATER_HEIGHT + 10, RealWorld::WATER_HEIGHT + 31); - self::$BIOMES_BY_RANGE[Biome::PLAINS] = new Range(RealWorld::WATER_HEIGHT + 10, RealWorld::WATER_HEIGHT + 31); - self::$BIOMES_BY_RANGE[Biome::FOREST] = new Range(RealWorld::WATER_HEIGHT + 24, RealWorld::WATER_HEIGHT + 47); - self::$BIOMES_BY_RANGE[Biome::BIRCH_FOREST] = new Range(RealWorld::WATER_HEIGHT + 24, RealWorld::WATER_HEIGHT + 47); - self::$BIOMES_BY_RANGE[Biome::TAIGA] = new Range(RealWorld::WATER_HEIGHT + 31, RealWorld::WATER_HEIGHT + 47); - self::$BIOMES_BY_RANGE[Biome::SMALL_MOUNTAINS] = new Range(RealWorld::WATER_HEIGHT + 47, RealWorld::WATER_HEIGHT + 95); - self::$BIOMES_BY_RANGE[Biome::MOUNTAINS] = new Range(RealWorld::WATER_HEIGHT + 95, RealWorld::WATER_HEIGHT + 155); - } -} \ No newline at end of file diff --git a/src/Ad5001/RealWorld/generator/RealWorldLarge.php b/src/Ad5001/RealWorld/generator/RealWorldLarge.php deleted file mode 100644 index 0281539..0000000 --- a/src/Ad5001/RealWorld/generator/RealWorldLarge.php +++ /dev/null @@ -1,22 +0,0 @@ -