Renaming the plugin, adding more heightmaps, fixing the plugin.

This commit is contained in:
Adsooi 2017-10-25 00:22:50 +02:00
parent f49444442a
commit 5dd4de71ef
20 changed files with 441 additions and 232 deletions

View file

@ -1,8 +1,32 @@
# RealWorld # GenPainterPE
Pocketmine Generator for Earth and heightmap based generation. Pocketmine Generator for Earth and heightmap based generation.
# Installation ## What is GenPainterPE?
Note: This section is only for *nix users (Linux, MacOS, Unix, FreeBSD). Pmmp's windows' prebuilt binaries includes GD by default. 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.
<a id="add-heightmap"></a>
You can also <b>add your own heightmap</b>. [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. 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? 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 &lt;YOUR\_OWN\_FOLDER&gt;/.pocketmine/php and restart PocketMine Server Manager. - For PocketMine Server Manager users, check if the plugin is working, if not, just delete the folder located in &lt;YOUR\_OWN\_FOLDER&gt;/.pocketmine/php and restart PocketMine Server Manager.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 MiB

View file

@ -1,9 +1,9 @@
--- ---
name: RealWorld name: GenPainterPE
author: Ad5001 author: Ad5001
version: 1.0 version: 1.0
api: [3.0.0-ALPHA9] api: [3.0.0-ALPHA9]
main: Ad5001\RealWorld\Main main: Ad5001\GenPainterPE\Main
commands: [] commands: []
permissions: [] permissions: []
... ...

BIN
resources/big_5400x2700.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

21
resources/config.yml Normal file
View file

@ -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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

BIN
resources/small_250x150.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

View file

@ -0,0 +1,146 @@
<?php
namespace Ad5001\GenPainterPE;
use pocketmine\command\CommandSender;
use pocketmine\command\Command;
use pocketmine\plugin\PluginBase;
use pocketmine\Server;
use pocketmine\Player;
use pocketmine\utils\Utils;
use pocketmine\event\entity\EntityLevelChangeEvent;
use pocketmine\event\Listener;
use pocketmine\level\generator\Generator;
use pocketmine\level\generator\biome\Biome;
use Ad5001\GenPainterPE\utils\Range;
use Ad5001\GenPainterPE\generator\GenPainter;
class Main extends PluginBase implements Listener{
public static $GENERATOR_IDS = 0;
public static $BIOMES_BY_RANGE = [];
/**
* Loads the plugin
*
* @return void
*/
public function onEnable(){
@mkdir($this->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;
}
}

View file

@ -1,5 +1,5 @@
<?php <?php
namespace Ad5001\RealWorld\generator; namespace Ad5001\GenPainterPE\generator;
use pocketmine\level\generator\Generator; use pocketmine\level\generator\Generator;
use pocketmine\block\Block; use pocketmine\block\Block;
@ -17,7 +17,6 @@ use pocketmine\level\generator\biome\Biome;
use pocketmine\level\generator\noise\Simplex; use pocketmine\level\generator\noise\Simplex;
use pocketmine\level\generator\normal\object\OreType as OreType2; use pocketmine\level\generator\normal\object\OreType as OreType2;
use pocketmine\level\generator\object\OreType; use pocketmine\level\generator\object\OreType;
use pocketmine\level\generator\biome\BiomeSelector;
use pocketmine\level\generator\populator\GroundCover; use pocketmine\level\generator\populator\GroundCover;
use pocketmine\level\generator\populator\Ore; use pocketmine\level\generator\populator\Ore;
use pocketmine\level\generator\populator\Populator; use pocketmine\level\generator\populator\Populator;
@ -25,17 +24,20 @@ use pocketmine\level\Level;
use pocketmine\math\Vector3; use pocketmine\math\Vector3;
use pocketmine\utils\Random; use pocketmine\utils\Random;
use Ad5001\RealWorld\Main; use Ad5001\GenPainterPE\Main;
use Ad5001\RealWorld\populator\CavePopulator; use Ad5001\GenPainterPE\populator\CavePopulator;
use Ad5001\RealWorld\populator\RavinePopulator; use Ad5001\GenPainterPE\populator\RavinePopulator;
use Ad5001\GenPainterPE\utils\BiomeSelector;
class RealWorld extends Generator{ class GenPainter extends Generator{
/** Both two here tells the max and min of water. */ /** Both two here tells the max and min of water. */
const WATER_HEIGHT = 100; const WATER_HEIGHT = 100;
const MIN_HEIGHT = 60; const MIN_HEIGHT = 60;
/** Maximum height for bedrock */
const BEDROCK_MAX_HEIGHT = 5;
/** Converts the original picture height to a minecraft height */ /** Converts the original picture height to a minecraft height */
const DEPTH_MULTIPLICATOR = 0.6; const DEPTH_MULTIPLICATOR = 0.2;
/** /**
* @var array * @var array
@ -44,8 +46,6 @@ class RealWorld extends Generator{
protected $startPoint = []; protected $startPoint = [];
/** @var resource - Heightmap image resource */ /** @var resource - Heightmap image resource */
protected $heightmap; protected $heightmap;
/** @var string */
protected $worldpath;
/** @var ChunkManager */ /** @var ChunkManager */
protected $level; protected $level;
@ -67,11 +67,13 @@ class RealWorld extends Generator{
* *
* @param array $options * @param array $options
*/ */
public function __construct($options = []){} public function __construct($options = []){
$this->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. * Executed on the main thread.
* $level is actually a level instance. * $level is actually a level instance.
* @param ChunkManager $level * @param ChunkManager $level
@ -82,41 +84,53 @@ class RealWorld extends Generator{
$this->level = $level; $this->level = $level;
$this->random = $random; $this->random = $random;
$this->random->setSeed($this->level->getSeed()); $this->random->setSeed($this->level->getSeed());
if($level instanceof Level) { // First init in main thread if($level instanceof Level &&
$this->worldpath = getcwd() . "/worlds/" . $level->getName() . "/"; isset($this->genid)) { // First init in main thread
$this->worldpath = getcwd() . "/worlds/" . $level->getName() . "/";
// Initing folder data // Initing folder data
@mkdir($this->worldpath . "gendata"); @mkdir($this->worldpath . "gendata");
$config = yaml_parse(file_get_contents(getcwd() . "/plugins/GenPainterPE/config.yml"));
// Checking heightmap // Checking heightmap
if(!file_exists($this->worldpath . "gendata/heightmap.png")) { 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"); $this->heightmap = \imagecreatefrompng($this->worldpath . "gendata/heightmap.png");
// Checking gen infos (startpoint, ...) // Checking gen infos (startpoint, ...)
if(!file_exists($this->worldpath . "gendata/geninfos.json")) { if(!file_exists($this->worldpath . "gendata/geninfos.json")) {
$data = []; $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"] = [ $data["startPoint"] = [
$random->nextRange(round(-imagesy($this->heightmap)) / 2, round(imagesy($this->heightmap) / 2)), $spawn->x,
$random->nextRange(round(-imagesx($this->heightmap)) / 2, round(imagesx($this->heightmap) / 2)), $spawn->y,
$spawn->z
]; ];
$data = array_merge($data, $config);
unset($data["heightmap_name"]);
file_put_contents($this->worldpath . "gendata/geninfos.json", json_encode($data)); 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")); // Adding symlink to get path later.
$this->startPoint = $options->startPoint; if(file_exists(getcwd() . "/plugins/GenPainterPE/tmp/" . $this->genid)) unlink(getcwd() . "/plugins/GenPainterPE/tmp/" . $this->genid);
} else { symlink($this->worldpath, getcwd() . "/plugins/GenPainterPE/tmp/" . $this->genid);
var_dump($this);
} }
// 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 // Making selector
$this->selector = new BiomeSelector($this->random, function($temperature, $rainfall){ $this->selector = new BiomeSelector($this->random, function($temperature, $rainfall){
// Checking the nearest candidate biome that have the closest $temperature and $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){ foreach($this->candidatesBiomes as $b){
$diffRainFall = abs($b->getRainfall() - $rainfall); $diffRainFall = abs($b->getRainfall() - $rainfall);
$diffTemperature = abs($b->getTemperature() - $temperature); $diffTemperature = abs($b->getTemperature() - $temperature);
$diff = $diffRainFall + $diffTemperature; // Total diff. $diff = $diffRainFall + $diffTemperature; // Total diff.
if($diff < $bestBiome[0]) $bestBiome = [$diff, $b]; if($diff < $bestBiome[0]) $bestBiome = [$diff, $b];
} }
return $bestBiome[1]->getId();
}, Biome::getBiome(Biome::OCEAN)); }, Biome::getBiome(Biome::OCEAN));
$this->selector->addBiome(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::ICE_PLAINS));
$this->selector->addBiome(Biome::getBiome(Biome::SMALL_MOUNTAINS)); $this->selector->addBiome(Biome::getBiome(Biome::SMALL_MOUNTAINS));
$this->selector->addBiome(Biome::getBiome(Biome::BIRCH_FOREST)); $this->selector->addBiome(Biome::getBiome(Biome::BIRCH_FOREST));
$this->selector->recalculate();
// Populators // Populators
$cover = new GroundCover(); if($this->options->generate_custom_ground){
$this->generationPopulators[] = $cover; $cover = new GroundCover();
$cave = new CavePopulator (); $this->generationPopulators[] = $cover;
$cave->setBaseAmount(0); }
$cave->setRandomAmount(2); if($this->options->generate_caves){
$this->generationPopulators[] = $cave; $cave = new CavePopulator ();
$ravine = new RavinePopulator (); $cave->setBaseAmount(0);
$ravine->setBaseAmount(0); $cave->setRandomAmount(2);
$ravine->setRandomAmount(51); $this->generationPopulators[] = $cave;
$this->generationPopulators[] = $ravine; $ravine = new RavinePopulator ();
$ores = new Ore(); $ravine->setBaseAmount(0);
$ores->setOreTypes([ $ravine->setRandomAmount(51);
new OreType(BlockFactory::get(Block::COAL_ORE), 20, 16, 0, 128), $this->generationPopulators[] = $ravine;
new OreType(BlockFactory::get(Block::IRON_ORE), 20, 8, 0, 64), }
new OreType(BlockFactory::get(Block::REDSTONE_ORE), 8, 7, 0, 16), if($this->options->generate_ores) {
new OreType(BlockFactory::get(Block::LAPIS_ORE), 1, 6, 0, 32), $ores = new Ore();
new OreType(BlockFactory::get(Block::GOLD_ORE), 2, 8, 0, 32), $ores->setOreTypes([
new OreType(BlockFactory::get(Block::DIAMOND_ORE), 1, 7, 0, 16), new OreType(BlockFactory::get(Block::COAL_ORE), 20, 16, 0, 128),
new OreType(BlockFactory::get(Block::DIRT), 20, 32, 0, 128), new OreType(BlockFactory::get(Block::IRON_ORE), 20, 8, 0, 64),
new OreType(BlockFactory::get(Block::GRAVEL), 10, 16, 0, 128) new OreType(BlockFactory::get(Block::REDSTONE_ORE), 8, 7, 0, 16),
]); new OreType(BlockFactory::get(Block::LAPIS_ORE), 1, 6, 0, 32),
$this->populators[] = $ores; 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){ public function generateChunk(int $chunkX, int $chunkZ){
$this->random->setSeed(0xdeadbeef ^ ($chunkX << 8) ^ $chunkZ ^ $this->level->getSeed()); $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($x = 0; $x < 16; $x++) {
for($z = 0; $z < 16; $z++) { for($z = 0; $z < 16; $z++) {
// Getting biome & height // Getting biome & height
$currentX = $chunkX * 16 + $x; $currentX = $chunkX * 16 + $x;
$currentZ = $chunkZ * 16 + $x; $currentZ = $chunkZ * 16 + $z;
$height = $this->getHeightFromImg($currentX, $currentZ); $height = $this->getHeightFromImg($currentX, $currentZ);
$biome = $this->getBiomeFromPos($currentX, $currentZ); $biome = $this->getBiomeFromPos($currentX, $currentZ);
$chunk->setBiomeId($x, $z, $biome->getId()); $chunk->setBiomeId($x, $z, $biome->getId());
// Building terrain // Building terrain
for($y = 0; $y < 128; ++$y) { for($y = 0; $y < 256; ++$y) {
if($y === 0) { if($y === 0) {
$chunk->setBlockId($x, $y, $z, Block::BEDROCK); $chunk->setBlockId($x, $y, $z, Block::BEDROCK);
continue; } elseif($y <= self::BEDROCK_MAX_HEIGHT && $this->random->nextBoundedInt(2) == 0) {
} $chunk->setBlockId($x, $y, $z, Block::BEDROCK);
if($y <= $height) { } elseif($y <= $height) {
$chunk->setBlockId($x, $y, $z, Block::STONE); $chunk->setBlockId($x, $y, $z, Block::STONE);
} elseif($y <= $this->waterHeight) { } elseif($y <= self::WATER_HEIGHT) {
$chunk->setBlockId($x, $y, $z, Block::STILL_WATER); $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 * @return void
*/ */
public function populateChunk(int $chunkX, int $chunkZ){ public function populateChunk(int $chunkX, int $chunkZ){
$this->random->setSeed(0xdeadbeef ^ ($chunkX << 8) ^ $chunkZ ^ $this->level->getSeed()); $this->random->setSeed(0xdeadbeef ^ ($chunkX << 8) ^ $chunkZ ^ $this->level->getSeed());
foreach($this->populators as $populator){ // Check if the generator should generate structures.
$populator->populate($this->level, $chunkX, $chunkZ, $this->random); if($this->options->generate_structures) {
} foreach($this->populators as $populator){
$chunk = $this->level->getChunk($chunkX, $chunkZ); $populator->populate($this->level, $chunkX, $chunkZ, $this->random);
$biome = Biome::getBiome($chunk->getBiomeId(7, 7)); }
$biome->populateChunk($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{ public function getBiomeFromPos(int $x, int $z): Biome{
$this->candidatesBiomes = []; $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); $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 // Foreaching all biomes to see which ones could be generated
foreach(Main::$BIOMES_BY_RANGE as $biomeId => $range){ foreach(Main::$BIOMES_BY_RANGE as $biomeId => $range){
if($range->isInRange($height)) $this->candidatesBiomes[] = Biome::getBiome($biomeId); if($range->isInRange($height)) $this->candidatesBiomes[] = Biome::getBiome($biomeId);
} }
// Checking wether there are multiple candidates or not. // Checking wether there are multiple candidates or not.
// If so, choose a biome. // If so, choose a biome.
if(count($this->candidatesBiomes == 1)){ if(count($this->candidatesBiomes) == 1){
$biome = $this->candidatesBiomes[0]; $biome = $this->candidatesBiomes[0];
} else { } else {
$hash = $x * 2345803 ^ $z * 9236449 ^ $this->level->getSeed(); $hash = $x * 2345803 ^ $z * 9236449 ^ $this->level->getSeed();
@ -257,33 +293,46 @@ class RealWorld extends Generator{
public function getHeightFromImg(int $x, int $z): int{ public function getHeightFromImg(int $x, int $z): int{
if(isset(self::$cachedHeights[$x . ";" . $z])) return round(self::$cachedHeights[$x . ";" . $z]); if(isset(self::$cachedHeights[$x . ";" . $z])) return round(self::$cachedHeights[$x . ";" . $z]);
// Getting height px of the world // Getting height px of the world
$imgGetDatX = ($x - $this->startPoint[0]) % imagesy($this->heightmap); $imgGetDatX = abs($x) % imagesy($this->heightmap);
if($imgGetDatX < 0) $imgGetDatX += imagesy($this->heightmap);
// Getting width px of the world // Getting width px of the world
$imgGetDatZ = ($z - $this->startPoint[1]) % imagesx($this->heightmap); $imgGetDatZ = abs($z) % imagesx($this->heightmap);
if($imgGetDatZ < 0) $z += imagesx($this->heightmap);
// Finally, getting the px to determine the height of the top block // 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) // In a normal heightmap, all the chanel ouputs the same (exepct alpha)
// Smoothing out. // Smoothing out.
$surroundValues = []; $surroundValues = [];
// Getting surround values // 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+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)])) $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+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) . ";" . ($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) . ";" . ($z-1)];
if(isset(self::$cachedHeights[($x-1) . ";" . ($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)])) $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-1) . ";" . ($z-1)])) $surroundValues[] = self::$cachedHeights[($x-1) . ";" . ($z-1)];
$surroundValues[] = $imgheight * self::DEPTH_MULTIPLICATOR + self::WATER_HEIGHT + $this->random->nextBoundedInt(4) - 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 // Calculating smooth value
$smoothValue = -1; // Starting at -1 to make water depth. // $smoothValue = -1;
foreach($surroundValues as $v) $smoothValue += $v; // foreach($surroundValues as $v) $smoothValue += $v;
$smoothValue /= count($surroundValues); // $smoothValue += $imgValue * 3;
if($smoothValue < self::MIN_HEIGHT) $smoothValue = self::MIN_HEIGHT; // $smoothValue /= count($surroundValues) + 3;
self::$cachedHeights[$x . ";" . $z] = $smoothValue; if($imgValue < self::MIN_HEIGHT) $imgValue = self::MIN_HEIGHT;
return round($smoothValue); // Rounding it so that we can use it as a block 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 * @return string
*/ */
public function getName(): string { public function getName(): string {
return "realworld"; return "worldpainter";
} }
/** /**
@ -311,15 +360,20 @@ class RealWorld extends Generator{
* @return Vector3 * @return Vector3
*/ */
public function getSpawn(): 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 * Returns a safe spawn location
* *
* @return Vector3 * @return Vector3
*/ */
public function getSafeSpawn() { 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; 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)];
}
} }

View file

@ -3,7 +3,7 @@
* Imported from BetterGen (https://github.com/Ad5001/BetterGen/blob/master/src/Ad5001/BetterGen/populator/AmountPopulator.php) * 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\level\generator\populator\Populator;
use pocketmine\utils\Random; use pocketmine\utils\Random;

View file

@ -3,9 +3,9 @@
* Imported from BetterGen (https://github.com/Ad5001/BetterGen/blob/master/src/Ad5001/BetterGen/populator/CavePopulator.php) * 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\block\Block;
use pocketmine\level\ChunkManager; use pocketmine\level\ChunkManager;
use pocketmine\level\Level; use pocketmine\level\Level;

View file

@ -3,9 +3,9 @@
* Imported from BetterGen (https://github.com/Ad5001/BetterGen/blob/master/src/Ad5001/BetterGen/populator/RavinePopulator.php) * 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\block\Block;
use pocketmine\level\ChunkManager; use pocketmine\level\ChunkManager;
use pocketmine\level\Level; use pocketmine\level\Level;

View file

@ -0,0 +1,75 @@
<?php
/**
* Modified version of PocketMine's to allow a better implementation
*/
namespace Ad5001\GenPainterPE\utils;
use pocketmine\level\generator\noise\Simplex;
use pocketmine\utils\Random;
use pocketmine\level\generator\biome\Biome;
class BiomeSelector{
/** @var Biome */
private $fallback;
/** @var Simplex */
private $temperature;
/** @var Simplex */
private $rainfall;
/** @var Biome[] */
private $biomes = [];
/** @var \SplFixedArray */
private $map = null;
/** @var callable */
private $lookup;
public function __construct(Random $random, callable $lookup, Biome $fallback){
$this->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;
}
}

View file

@ -3,7 +3,7 @@
* Imported from BetterGen (https://github.com/Ad5001/BetterGen/blob/master/src/Ad5001/BetterGen/utils/BuildingUtils.php) * 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\block\Block;
use pocketmine\level\ChunkManager; use pocketmine\level\ChunkManager;
@ -18,7 +18,7 @@ class BuildingUtils {
Block::LAVA, Block::LAVA,
Block::BEDROCK, Block::BEDROCK,
Block::CACTUS, Block::CACTUS,
Block::PLANK Block::PLANKS
]; ];
/** /**

View file

@ -1,6 +1,6 @@
<?php <?php
namespace Ad5001\RealWorld\utils; namespace Ad5001\GenPainterPE\utils;
class Range { class Range {

View file

@ -1,90 +0,0 @@
<?php
namespace Ad5001\RealWorld;
use pocketmine\command\CommandSender;
use pocketmine\command\Command;
use pocketmine\plugin\PluginBase;
use pocketmine\Server;
use pocketmine\Player;
use pocketmine\utils\Utils;
use pocketmine\event\level\LevelInitEvent;
use pocketmine\event\Listener;
use pocketmine\level\generator\Generator;
use Ad5001\RealWorld\utils\Range;
use Ad5001\RealWorld\generator\RealWorld;
use Ad5001\RealWorld\generator\RealWorldLarge;
class Main extends PluginBase implements Listener{
public static $BIOMES_BY_RANGE = [];
/**
* Loads the plugin
*
* @return void
*/
public function onEnable(){
@mkdir($this->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);
}
}

View file

@ -1,22 +0,0 @@
<?php
namespace Ad5001\RealWorld\generator;
use pocketmine\level\generator\Generator;
use Ad5001\RealWorld\Main;
class RealWorldLarge extends Generator{
/**
* Inits the class for the var
* @param ChunkManager $level
* @param Random $random
* @return void
*/
public function init(ChunkManager $level, Random $random) {}
}

View file

@ -1,22 +0,0 @@
<?php
namespace Ad5001\RealWorld\generator;
use pocketmine\level\generator\Generator;
use Ad5001\RealWorld\Main;
class RealWorldLarge extends Generator{
/**
* Inits the class for the var
* @param ChunkManager $level
* @param Random $random
* @return void
*/
public function init(ChunkManager $level, Random $random) {}
}