Adding current progress
This commit is contained in:
commit
24f9ede380
14 changed files with 1082 additions and 0 deletions
10
README.md
Normal file
10
README.md
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
# RealWorld
|
||||||
|
Pocketmine Generator for Earth and heightmap based generation.
|
||||||
|
|
||||||
|
# Installation
|
||||||
|
To support all the features including your own heightmap creation, you may need to install the PHP GD extension.
|
||||||
|
How to do that?
|
||||||
|
- 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.
|
||||||
|
- For regular pocketmine user, you can get <a href="https://psm.mcpe.fun/download/PHP/compile.sh">the following script to install a PHP with GD included </a>.
|
||||||
|
|
||||||
|
You may also need to install https://sourceforge.net/projects/libpng/.
|
BIN
heightmap.png
Normal file
BIN
heightmap.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 MiB |
9
plugin.yml
Normal file
9
plugin.yml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
---
|
||||||
|
name: RealWorld
|
||||||
|
author: Ad5001
|
||||||
|
version: 1.0
|
||||||
|
api: [3.0.0-ALPHA9]
|
||||||
|
main: Ad5001\RealWorld\Main
|
||||||
|
commands: []
|
||||||
|
permissions: []
|
||||||
|
...
|
BIN
resources/heightmap.jpg
Normal file
BIN
resources/heightmap.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.9 MiB |
BIN
resources/heightmap.png
Normal file
BIN
resources/heightmap.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 MiB |
90
src/Ad5001/RealWorld/Main.php
Normal file
90
src/Ad5001/RealWorld/Main.php
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
<?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);
|
||||||
|
}
|
||||||
|
}
|
342
src/Ad5001/RealWorld/generator/RealWorld.php
Normal file
342
src/Ad5001/RealWorld/generator/RealWorld.php
Normal file
|
@ -0,0 +1,342 @@
|
||||||
|
<?php
|
||||||
|
namespace Ad5001\RealWorld\generator;
|
||||||
|
|
||||||
|
use pocketmine\level\generator\Generator;
|
||||||
|
use pocketmine\block\Block;
|
||||||
|
use pocketmine\block\BlockFactory;
|
||||||
|
use pocketmine\block\CoalOre;
|
||||||
|
use pocketmine\block\DiamondOre;
|
||||||
|
use pocketmine\block\Dirt;
|
||||||
|
use pocketmine\block\GoldOre;
|
||||||
|
use pocketmine\block\Gravel;
|
||||||
|
use pocketmine\block\IronOre;
|
||||||
|
use pocketmine\block\LapisOre;
|
||||||
|
use pocketmine\block\RedstoneOre;
|
||||||
|
use pocketmine\level\ChunkManager;
|
||||||
|
use pocketmine\level\generator\biome\Biome;
|
||||||
|
use pocketmine\level\generator\noise\Simplex;
|
||||||
|
use pocketmine\level\generator\normal\object\OreType as OreType2;
|
||||||
|
use pocketmine\level\generator\object\OreType;
|
||||||
|
use pocketmine\level\generator\biome\BiomeSelector;
|
||||||
|
use pocketmine\level\generator\populator\GroundCover;
|
||||||
|
use pocketmine\level\generator\populator\Ore;
|
||||||
|
use pocketmine\level\generator\populator\Populator;
|
||||||
|
use pocketmine\level\Level;
|
||||||
|
use pocketmine\math\Vector3;
|
||||||
|
use pocketmine\utils\Random;
|
||||||
|
|
||||||
|
use Ad5001\RealWorld\Main;
|
||||||
|
use Ad5001\RealWorld\populator\CavePopulator;
|
||||||
|
use Ad5001\RealWorld\populator\RavinePopulator;
|
||||||
|
|
||||||
|
|
||||||
|
class RealWorld extends Generator{
|
||||||
|
/** Both two here tells the max and min of water. */
|
||||||
|
const WATER_HEIGHT = 100;
|
||||||
|
const MIN_HEIGHT = 60;
|
||||||
|
/** Converts the original picture height to a minecraft height */
|
||||||
|
const DEPTH_MULTIPLICATOR = 0.6;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
* Coordinates of the start point
|
||||||
|
*/
|
||||||
|
protected $startPoint = [];
|
||||||
|
/** @var resource - Heightmap image resource */
|
||||||
|
protected $heightmap;
|
||||||
|
/** @var string */
|
||||||
|
protected $worldpath;
|
||||||
|
|
||||||
|
/** @var ChunkManager */
|
||||||
|
protected $level;
|
||||||
|
/** @var Random */
|
||||||
|
protected $random;
|
||||||
|
/** @var BiomeSelector */
|
||||||
|
protected $selector;
|
||||||
|
/** @var int[] */
|
||||||
|
protected static $cachedHeights = [];
|
||||||
|
/** @var Biome[] - Biomes that are candidates to be choosen to be generated */
|
||||||
|
protected $candidatesBiomes = [];
|
||||||
|
/** @var Populator[] */
|
||||||
|
private $generationPopulators = [];
|
||||||
|
/** @var Populator[] */
|
||||||
|
private $populators = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs the class
|
||||||
|
*
|
||||||
|
* @param array $options
|
||||||
|
*/
|
||||||
|
public function __construct($options = []){}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inits the class for the variables. mw create Test 902874635 realworld
|
||||||
|
* Executed on the main thread.
|
||||||
|
* $level is actually a level instance.
|
||||||
|
* @param ChunkManager $level
|
||||||
|
* @param Random $random
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function init(ChunkManager $level, Random $random) {
|
||||||
|
$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() . "/";
|
||||||
|
// Initing folder data
|
||||||
|
@mkdir($this->worldpath . "gendata");
|
||||||
|
// Checking heightmap
|
||||||
|
if(!file_exists($this->worldpath . "gendata/heightmap.png")) {
|
||||||
|
copy(getcwd() . "/plugins/RealWorld/heightmap.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["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)),
|
||||||
|
];
|
||||||
|
file_put_contents($this->worldpath . "gendata/geninfos.json", json_encode($data));
|
||||||
|
}
|
||||||
|
$options = json_decode(file_get_contents($this->worldpath . "gendata/geninfos.json"));
|
||||||
|
$this->startPoint = $options->startPoint;
|
||||||
|
} else {
|
||||||
|
var_dump($this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
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];
|
||||||
|
}
|
||||||
|
}, Biome::getBiome(Biome::OCEAN));
|
||||||
|
|
||||||
|
$this->selector->addBiome(Biome::getBiome(Biome::OCEAN));
|
||||||
|
$this->selector->addBiome(Biome::getBiome(Biome::PLAINS));
|
||||||
|
$this->selector->addBiome(Biome::getBiome(Biome::DESERT));
|
||||||
|
$this->selector->addBiome(Biome::getBiome(Biome::MOUNTAINS));
|
||||||
|
$this->selector->addBiome(Biome::getBiome(Biome::FOREST));
|
||||||
|
$this->selector->addBiome(Biome::getBiome(Biome::TAIGA));
|
||||||
|
$this->selector->addBiome(Biome::getBiome(Biome::SWAMP));
|
||||||
|
$this->selector->addBiome(Biome::getBiome(Biome::RIVER));
|
||||||
|
$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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a chunk
|
||||||
|
*
|
||||||
|
* @param int $chunkX
|
||||||
|
* @param int $chunkZ
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function generateChunk(int $chunkX, int $chunkZ){
|
||||||
|
$this->random->setSeed(0xdeadbeef ^ ($chunkX << 8) ^ $chunkZ ^ $this->level->getSeed());
|
||||||
|
$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;
|
||||||
|
$height = $this->getHeightFromImg($currentX, $currentZ);
|
||||||
|
$biome = $this->getBiomeFromPos($currentX, $currentZ);
|
||||||
|
$chunk->setBiomeId($x, $z, $biome->getId());
|
||||||
|
// Building terrain
|
||||||
|
for($y = 0; $y < 128; ++$y) {
|
||||||
|
if($y === 0) {
|
||||||
|
$chunk->setBlockId($x, $y, $z, Block::BEDROCK);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if($y <= $height) {
|
||||||
|
$chunk->setBlockId($x, $y, $z, Block::STONE);
|
||||||
|
} elseif($y <= $this->waterHeight) {
|
||||||
|
$chunk->setBlockId($x, $y, $z, Block::STILL_WATER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Populates chunks.
|
||||||
|
*
|
||||||
|
* @param int $chunkX
|
||||||
|
* @param int $chunkZ
|
||||||
|
* @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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a biome from a pos.
|
||||||
|
*
|
||||||
|
* @param int $x
|
||||||
|
* @param int $z
|
||||||
|
* @return Biome
|
||||||
|
*/
|
||||||
|
public function getBiomeFromPos(int $x, int $z): Biome{
|
||||||
|
$this->candidatesBiomes = [];
|
||||||
|
if(count(Main::$BIOMES_BY_RANGE) < 0) Main::generateRanges();
|
||||||
|
$height = $this->getHeightFromImg($x, $z);
|
||||||
|
// 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)){
|
||||||
|
$biome = $this->candidatesBiomes[0];
|
||||||
|
} else {
|
||||||
|
$hash = $x * 2345803 ^ $z * 9236449 ^ $this->level->getSeed();
|
||||||
|
$hash *= $hash + 223;
|
||||||
|
$xNoise = $hash >> 20 & 3;
|
||||||
|
$zNoise = $hash >> 22 & 3;
|
||||||
|
if($xNoise == 3){
|
||||||
|
$xNoise = 1;
|
||||||
|
}
|
||||||
|
if($zNoise == 3){
|
||||||
|
$zNoise = 1;
|
||||||
|
}
|
||||||
|
$biome = $this->selector->pickBiome($x + $xNoise - 1, $z + $zNoise - 1);
|
||||||
|
}
|
||||||
|
return $biome;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a block height based on heightmap.
|
||||||
|
*
|
||||||
|
* @param int $x
|
||||||
|
* @param int $z
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
// Getting width px of the world
|
||||||
|
$imgGetDatZ = ($z - $this->startPoint[1]) % imagesx($this->heightmap);
|
||||||
|
if($imgGetDatZ < 0) $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.
|
||||||
|
// 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;
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the name of the generator
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getName(): string {
|
||||||
|
return "realworld";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gives the generators settings.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getSettings(): array {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Returns spawn location
|
||||||
|
*
|
||||||
|
* @return Vector3
|
||||||
|
*/
|
||||||
|
public function getSpawn(): Vector3 {
|
||||||
|
return new Vector3(127.5, 128, 127.5);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Returns a safe spawn location
|
||||||
|
*
|
||||||
|
* @return Vector3
|
||||||
|
*/
|
||||||
|
public function getSafeSpawn() {
|
||||||
|
return new Vector3(127.5, $this->getHighestWorkableBlock(127, 127), 127.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Gets the top block (y) on an x and z axes
|
||||||
|
* @param $x int
|
||||||
|
* @param $z int
|
||||||
|
*/
|
||||||
|
protected function getHighestWorkableBlock($x, $z) {
|
||||||
|
for($y = Level::Y_MAX - 1; $y > 0; -- $y) {
|
||||||
|
$b = $this->level->getBlockIdAt($x, $y, $z);
|
||||||
|
if ($b === Block::DIRT or $b === Block::GRASS or $b === Block::PODZOL) {
|
||||||
|
break;
|
||||||
|
} elseif ($b !== 0 and $b !== Block::SNOW_LAYER) {
|
||||||
|
return - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ++$y;
|
||||||
|
}
|
||||||
|
}
|
22
src/Ad5001/RealWorld/generator/RealWorldLarge.php
Normal file
22
src/Ad5001/RealWorld/generator/RealWorldLarge.php
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<?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) {}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
22
src/Ad5001/RealWorld/generator/RealWorldSmall.php
Normal file
22
src/Ad5001/RealWorld/generator/RealWorldSmall.php
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<?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) {}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
62
src/Ad5001/RealWorld/populator/AmountPopulator.php
Normal file
62
src/Ad5001/RealWorld/populator/AmountPopulator.php
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Imported from BetterGen (https://github.com/Ad5001/BetterGen/blob/master/src/Ad5001/BetterGen/populator/AmountPopulator.php)
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Ad5001\RealWorld\populator;
|
||||||
|
|
||||||
|
use pocketmine\level\generator\populator\Populator;
|
||||||
|
use pocketmine\utils\Random;
|
||||||
|
|
||||||
|
abstract class AmountPopulator extends Populator {
|
||||||
|
protected $baseAmount = 0;
|
||||||
|
protected $randomAmount = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crosssoftware class for random amount
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the random addition amount
|
||||||
|
* @param $amount int
|
||||||
|
*/
|
||||||
|
public function setRandomAmount(int $amount) {
|
||||||
|
$this->randomAmount = $amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the base addition amount
|
||||||
|
* @param $amount int
|
||||||
|
*/
|
||||||
|
public function setBaseAmount(int $amount) {
|
||||||
|
$this->baseAmount = $amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the amount based on random
|
||||||
|
*
|
||||||
|
* @param Random $random
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getAmount(Random $random) {
|
||||||
|
return $this->baseAmount + $random->nextRange(0, $this->randomAmount + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns base amount
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getBaseAmount(): int {
|
||||||
|
return $this->baseAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the random additional amount
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getRandomAmount(): int {
|
||||||
|
return $this->randomAmount;
|
||||||
|
}
|
||||||
|
}
|
158
src/Ad5001/RealWorld/populator/CavePopulator.php
Normal file
158
src/Ad5001/RealWorld/populator/CavePopulator.php
Normal file
|
@ -0,0 +1,158 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Imported from BetterGen (https://github.com/Ad5001/BetterGen/blob/master/src/Ad5001/BetterGen/populator/CavePopulator.php)
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Ad5001\RealWorld\populator;
|
||||||
|
|
||||||
|
use Ad5001\RealWorld\utils\BuildingUtils;
|
||||||
|
use pocketmine\block\Block;
|
||||||
|
use pocketmine\level\ChunkManager;
|
||||||
|
use pocketmine\level\Level;
|
||||||
|
use pocketmine\math\Vector3;
|
||||||
|
use pocketmine\utils\Random;
|
||||||
|
|
||||||
|
class CavePopulator extends AmountPopulator {
|
||||||
|
/** @var ChunkManager */
|
||||||
|
protected $level;
|
||||||
|
const STOP = false;
|
||||||
|
const CONTINUE = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Populates the chunk
|
||||||
|
*
|
||||||
|
* @param ChunkManager $level
|
||||||
|
* @param int $chunkX
|
||||||
|
* @param int $chunkZ
|
||||||
|
* @param Random $random
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function populate(ChunkManager $level, $chunkX, $chunkZ, Random $random) {
|
||||||
|
$this->level = $level;
|
||||||
|
$amount = $this->getAmount($random);
|
||||||
|
for($i = 0; $i < $amount; $i++) {
|
||||||
|
$x = $random->nextRange($chunkX << 4, ($chunkX << 4) + 15);
|
||||||
|
$z = $random->nextRange($chunkZ << 4, ($chunkZ << 4) + 15);
|
||||||
|
$y = $random->nextRange(10, $this->getHighestWorkableBlock($x, $z));
|
||||||
|
// echo "Generating cave at $x, $y, $z." . PHP_EOL;
|
||||||
|
$this->generateCave($x, $y, $z, $random);
|
||||||
|
}
|
||||||
|
// echo "Finished Populating chunk $chunkX, $chunkZ !" . PHP_EOL;
|
||||||
|
// Filling water & lava sources randomly
|
||||||
|
for($i = 0; $i < $random->nextBoundedInt(5) + 3; $i ++) {
|
||||||
|
$x = $random->nextRange($chunkX << 4, ($chunkX << 4) + 15);
|
||||||
|
$z = $random->nextRange($chunkZ << 4, ($chunkZ << 4) + 15);
|
||||||
|
$y = $random->nextRange(10, $this->getHighestWorkableBlock($x, $z));
|
||||||
|
if ($level->getBlockIdAt($x, $y, $z) == Block::STONE && ($level->getBlockIdAt($x + 1, $y, $z) == Block::AIR || $level->getBlockIdAt($x - 1, $y, $z) == Block::AIR || $level->getBlockIdAt($x, $y, $z + 1) == Block::AIR || $level->getBlockIdAt($x, $y, $z - 1) == Block::AIR) && $level->getBlockIdAt($x, $y - 1, $z) !== Block::AIR && $level->getBlockIdAt($x, $y + 1, $z) !== Block::AIR) {
|
||||||
|
if ($y < 40 && $random->nextBoolean ()) {
|
||||||
|
$level->setBlockIdAt($x, $y, $z, Block::LAVA);
|
||||||
|
} else {
|
||||||
|
$level->setBlockIdAt($x, $y, $z, Block::WATER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the top block (y) on an x and z axes
|
||||||
|
* @param int $x
|
||||||
|
* @param int $z
|
||||||
|
*/
|
||||||
|
protected function getHighestWorkableBlock($x, $z) {
|
||||||
|
for($y = Level::Y_MAX - 1; $y > 0; -- $y) {
|
||||||
|
$b = $this->level->getBlockIdAt($x, $y, $z);
|
||||||
|
if ($b === Block::DIRT or $b === Block::GRASS or $b === Block::PODZOL or $b === Block::SAND or $b === Block::SNOW_BLOCK or $b === Block::SANDSTONE) {
|
||||||
|
break;
|
||||||
|
} elseif ($b !== 0 and $b !== Block::SNOW_LAYER and $b !== Block::WATER) {
|
||||||
|
return - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ++$y;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a cave
|
||||||
|
*
|
||||||
|
* @param int $x
|
||||||
|
* @param int $y
|
||||||
|
* @param int $z
|
||||||
|
* @param Random $random
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function generateCave($x, $y, $z, Random $random) {
|
||||||
|
$generatedBranches = $random->nextBoundedInt(10) + 1;
|
||||||
|
foreach($gen = $this->generateBranch($x, $y, $z, 5, 3, 5, $random) as $v3) {
|
||||||
|
$generatedBranches --;
|
||||||
|
if ($generatedBranches <= 0) {
|
||||||
|
$gen->send(self::STOP);
|
||||||
|
} else {
|
||||||
|
$gen->send(self::CONTINUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a cave branch
|
||||||
|
*
|
||||||
|
* @param int $x
|
||||||
|
* @param int $y
|
||||||
|
* @param int $z
|
||||||
|
* @param int $length
|
||||||
|
* @param int $height
|
||||||
|
* @param int $depth
|
||||||
|
* @param Random $random
|
||||||
|
* @yield Vector3
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function generateBranch($x, $y, $z, $length, $height, $depth, Random $random) {
|
||||||
|
if (! (yield new Vector3($x, $y, $z))) {
|
||||||
|
for($i = 0; $i <= 4; $i ++) {
|
||||||
|
BuildingUtils::buildRandom($this->level, new Vector3($x, $y, $z), new Vector3($length - $i, $height - $i, $depth - $i), $random, Block::get(Block::AIR));
|
||||||
|
$x += round(($random->nextBoundedInt(round(30 * ($length / 10)) + 1) / 10 - 2));
|
||||||
|
$yP = $random->nextRange(-14, 14);
|
||||||
|
if ($yP > 12) {
|
||||||
|
$y ++;
|
||||||
|
} elseif ($yP < - 12) {
|
||||||
|
$y --;
|
||||||
|
}
|
||||||
|
$z += round(($random->nextBoundedInt(round(30 * ($depth / 10)) + 1) / 10 - 1));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$repeat = $random->nextBoundedInt(25) + 15;
|
||||||
|
while($repeat-- > 0) {
|
||||||
|
BuildingUtils::buildRandom($this->level, new Vector3($x, $y, $z), new Vector3($length, $height, $depth), $random, Block::get(Block::AIR));
|
||||||
|
$x += round(($random->nextBoundedInt(round(30 * ($length / 10)) + 1) / 10 - 2));
|
||||||
|
$yP = $random->nextRange(- 14, 14);
|
||||||
|
if ($yP > 12) {
|
||||||
|
$y ++;
|
||||||
|
} elseif ($yP < - 12) {
|
||||||
|
$y --;
|
||||||
|
}
|
||||||
|
$z += round(($random->nextBoundedInt(round(30 * ($depth / 10)) + 1) / 10 - 1));
|
||||||
|
$height += $random->nextBoundedInt(3) - 1;
|
||||||
|
$length += $random->nextBoundedInt(3) - 1;
|
||||||
|
$depth += $random->nextBoundedInt(3) - 1;
|
||||||
|
if ($height < 3)
|
||||||
|
$height = 3;
|
||||||
|
if ($length < 3)
|
||||||
|
$length = 3;
|
||||||
|
if ($height < 3)
|
||||||
|
$height = 3;
|
||||||
|
if ($height < 7)
|
||||||
|
$height = 7;
|
||||||
|
if ($length < 7)
|
||||||
|
$length = 7;
|
||||||
|
if ($height < 7)
|
||||||
|
$height = 7;
|
||||||
|
if ($random->nextBoundedInt(10) == 0) {
|
||||||
|
foreach($generator = $this->generateBranch($x, $y, $z, $length, $height, $depth, $random) as $gen) {
|
||||||
|
if (! (yield $gen))
|
||||||
|
$generator->send(self::STOP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
125
src/Ad5001/RealWorld/populator/RavinePopulator.php
Normal file
125
src/Ad5001/RealWorld/populator/RavinePopulator.php
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Imported from BetterGen (https://github.com/Ad5001/BetterGen/blob/master/src/Ad5001/BetterGen/populator/RavinePopulator.php)
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Ad5001\RealWorld\populator;
|
||||||
|
|
||||||
|
use Ad5001\RealWorld\utils\BuildingUtils;
|
||||||
|
use pocketmine\block\Block;
|
||||||
|
use pocketmine\level\ChunkManager;
|
||||||
|
use pocketmine\level\Level;
|
||||||
|
use pocketmine\utils\Random;
|
||||||
|
|
||||||
|
class RavinePopulator extends AmountPopulator {
|
||||||
|
/** @var ChunkManager */
|
||||||
|
protected $level;
|
||||||
|
const NOISE = 250;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Populates the chunk
|
||||||
|
*
|
||||||
|
* @param ChunkManager $level
|
||||||
|
* @param int $chunkX
|
||||||
|
* @param int $chunkZ
|
||||||
|
* @param Random $random
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function populate(ChunkManager $level, $chunkX, $chunkZ, Random $random) {
|
||||||
|
$this->level = $level;
|
||||||
|
$amount = $this->getAmount($random);
|
||||||
|
if ($amount > 50) { // Only build one per chunk
|
||||||
|
$depth = $random->nextBoundedInt(60) + 30; // 2Much4U?
|
||||||
|
$x = $random->nextRange($chunkX << 4, ($chunkX << 4) + 15);
|
||||||
|
$z = $random->nextRange($chunkZ << 4, ($chunkZ << 4) + 15);
|
||||||
|
$y = $random->nextRange(5, $this->getHighestWorkableBlock($x, $z));
|
||||||
|
$deffX = $x;
|
||||||
|
$deffZ = $z;
|
||||||
|
$height = $random->nextRange(15, 30);
|
||||||
|
$length = $random->nextRange(5, 12);
|
||||||
|
for($i = 0; $i < $depth; $i ++) {
|
||||||
|
$this->buildRavinePart($x, $y, $z, $height, $length, $random);
|
||||||
|
$diffX = $x - $deffX;
|
||||||
|
$diffZ = $z - $deffZ;
|
||||||
|
if ($diffX > $length / 2)
|
||||||
|
$diffX = $length / 2;
|
||||||
|
if ($diffX < - $length / 2)
|
||||||
|
$diffX = - $length / 2;
|
||||||
|
if ($diffZ > $length / 2)
|
||||||
|
$diffZ = $length / 2;
|
||||||
|
if ($diffZ < - $length / 2)
|
||||||
|
$diffZ = - $length / 2;
|
||||||
|
if ($length > 10)
|
||||||
|
$length = 10;
|
||||||
|
if ($length < 5)
|
||||||
|
$length = 5;
|
||||||
|
$x += $random->nextRange(0 + $diffX, 2 + $diffX) - 1;
|
||||||
|
$y += $random->nextRange(0, 2) - 1;
|
||||||
|
$z += $random->nextRange(0 + $diffZ, 2 + $diffZ) - 1;
|
||||||
|
$height += $random->nextRange(0, 2) - 1;
|
||||||
|
$length += $random->nextRange(0, 2) - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Gets the top block (y) on an x and z axes
|
||||||
|
* @param $x int
|
||||||
|
* @param $z int
|
||||||
|
*/
|
||||||
|
protected function getHighestWorkableBlock($x, $z) {
|
||||||
|
for($y = Level::Y_MAX - 1; $y > 0; -- $y) {
|
||||||
|
$b = $this->level->getBlockIdAt($x, $y, $z);
|
||||||
|
if ($b === Block::DIRT or $b === Block::GRASS or $b === Block::PODZOL or $b === Block::SAND or $b === Block::SNOW_BLOCK or $b === Block::SANDSTONE) {
|
||||||
|
break;
|
||||||
|
} elseif ($b !== 0 and $b !== Block::SNOW_LAYER and $b !== Block::WATER) {
|
||||||
|
return - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ++$y;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Buidls a ravine part
|
||||||
|
*
|
||||||
|
* @param int $x
|
||||||
|
* @param int $y
|
||||||
|
* @param int $z
|
||||||
|
* @param int $height
|
||||||
|
* @param int $length
|
||||||
|
* @param Random $random
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function buildRavinePart($x, $y, $z, $height, $length, Random $random) {
|
||||||
|
$xBounded = 0;
|
||||||
|
$zBounded = 0;
|
||||||
|
for($xx = $x - $length; $xx <= $x + $length; $xx ++) {
|
||||||
|
for($yy = $y; $yy <= $y + $height; $yy ++) {
|
||||||
|
for($zz = $z - $length; $zz <= $z + $length; $zz ++) {
|
||||||
|
$oldXB = $xBounded;
|
||||||
|
$xBounded = $random->nextBoundedInt(self::NOISE * 2) - self::NOISE;
|
||||||
|
$oldZB = $zBounded;
|
||||||
|
$zBounded = $random->nextBoundedInt(self::NOISE * 2) - self::NOISE;
|
||||||
|
if ($xBounded > self::NOISE - 2) {
|
||||||
|
$xBounded = 1;
|
||||||
|
} elseif ($xBounded < - self::NOISE + 2) {
|
||||||
|
$xBounded = -1;
|
||||||
|
} else {
|
||||||
|
$xBounded = $oldXB;
|
||||||
|
}
|
||||||
|
if ($zBounded > self::NOISE - 2) {
|
||||||
|
$zBounded = 1;
|
||||||
|
} elseif ($zBounded < - self::NOISE + 2) {
|
||||||
|
$zBounded = -1;
|
||||||
|
} else {
|
||||||
|
$zBounded = $oldZB;
|
||||||
|
}
|
||||||
|
if (abs((abs($xx) - abs($x)) ** 2 + (abs($zz) - abs($z)) ** 2) < ((($length / 2 - $xBounded) + ($length / 2 - $zBounded)) / 2) ** 2 && $y > 0 && ! in_array($this->level->getBlockIdAt(( int) round($xx),(int) round($yy),(int) round($zz)), BuildingUtils::TO_NOT_OVERWRITE) && ! in_array($this->level->getBlockIdAt(( int) round($xx),(int) round($yy + 1),(int) round($zz)), BuildingUtils::TO_NOT_OVERWRITE)) {
|
||||||
|
$this->level->setBlockIdAt(( int) round($xx),(int) round($yy),(int) round($zz), Block::AIR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
210
src/Ad5001/RealWorld/utils/BuildingUtils.php
Normal file
210
src/Ad5001/RealWorld/utils/BuildingUtils.php
Normal file
|
@ -0,0 +1,210 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Imported from BetterGen (https://github.com/Ad5001/BetterGen/blob/master/src/Ad5001/BetterGen/utils/BuildingUtils.php)
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Ad5001\RealWorld\utils;
|
||||||
|
|
||||||
|
use pocketmine\block\Block;
|
||||||
|
use pocketmine\level\ChunkManager;
|
||||||
|
use pocketmine\math\Vector3;
|
||||||
|
use pocketmine\utils\Random;
|
||||||
|
|
||||||
|
class BuildingUtils {
|
||||||
|
const TO_NOT_OVERWRITE = [
|
||||||
|
Block::WATER,
|
||||||
|
Block::STILL_WATER,
|
||||||
|
Block::STILL_LAVA,
|
||||||
|
Block::LAVA,
|
||||||
|
Block::BEDROCK,
|
||||||
|
Block::CACTUS,
|
||||||
|
Block::PLANK
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fills an area
|
||||||
|
*
|
||||||
|
* @param ChunkManager $level
|
||||||
|
* @param Vector3 $pos1
|
||||||
|
* @param Vector3 $pos2
|
||||||
|
* @param Block $block
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function fill(ChunkManager $level, Vector3 $pos1, Vector3 $pos2, Block $block = null) {
|
||||||
|
if ($block == null) $block = Block::get(Block::AIR);
|
||||||
|
list($pos1, $pos2) = self::minmax($pos1, $pos2);
|
||||||
|
for($x = $pos1->x; $x >= $pos2->x; $x --) for($y = $pos1->y; $y >= $pos2->y; $y --) for($z = $pos1->z; $z >= $pos2->z; $z --) {
|
||||||
|
$level->setBlockIdAt($x, $y, $z, $block->getId ());
|
||||||
|
$level->setBlockDataAt($x, $y, $z, $block->getDamage ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fills an area randomly
|
||||||
|
*
|
||||||
|
* @param ChunkManager $level
|
||||||
|
* @param Vector3 $pos1
|
||||||
|
* @param Vector3 $pos2
|
||||||
|
* @param Block $block
|
||||||
|
* @param Random $random
|
||||||
|
* @param int $randMax
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function fillRandom(ChunkManager $level, Vector3 $pos1, Vector3 $pos2, Block $block = null, Random $random = null, $randMax = 3) {
|
||||||
|
if ($block == null) $block = Block::get(Block::AIR);
|
||||||
|
list($pos1, $pos2) = self::minmax($pos1, $pos2);
|
||||||
|
for($x = $pos1->x; $x >= $pos2->x; $x --) for($y = $pos1->y; $y >= $pos2->y; $y --) for($z = $pos1->z; $z >= $pos2->z; $z --) if($random !== null ? $random->nextBoundedInt($randMax) == 0 : rand(0, $randMax) == 0) {
|
||||||
|
$level->setBlockIdAt($x, $y, $z, $block->getId ());
|
||||||
|
$level->setBlockDataAt($x, $y, $z, $block->getDamage ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom area filling
|
||||||
|
*
|
||||||
|
* @param Vector3 $pos1
|
||||||
|
* @param Vector3 $pos2
|
||||||
|
* @param callable $call
|
||||||
|
* @param array $params
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function fillCallback(Vector3 $pos1, Vector3 $pos2, callable $call, ...$params) : array {
|
||||||
|
list($pos1, $pos2) = self::minmax($pos1, $pos2);
|
||||||
|
$return = [];
|
||||||
|
for($x = $pos1->x; $x >= $pos2->x; $x --) for($y = $pos1->y; $y >= $pos2->y; $y --) for($z = $pos1->z; $z >= $pos2->z; $z --) {
|
||||||
|
$return[] = call_user_func($call, new Vector3($x, $y, $z), ...$params);
|
||||||
|
}
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates walls
|
||||||
|
*
|
||||||
|
* @param ChunkManager $level
|
||||||
|
* @param Vector3 $pos1
|
||||||
|
* @param Vector3 $pos2
|
||||||
|
* @param Block $block
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function walls(ChunkManager $level, Vector3 $pos1, Vector3 $pos2, Block $block) {
|
||||||
|
list($pos1, $pos2) = self::minmax($pos1, $pos2);
|
||||||
|
for($y = $pos1->y; $y >= $pos2->y; $y --) {
|
||||||
|
for($x = $pos1->x; $x >= $pos2->x; $x --) {
|
||||||
|
$level->setBlockIdAt($x, $y, $pos1->z, $block->getId ());
|
||||||
|
$level->setBlockDataAt($x, $y, $pos1->z, $block->getDamage ());
|
||||||
|
$level->setBlockIdAt($x, $y, $pos2->z, $block->getId ());
|
||||||
|
$level->setBlockDataAt($x, $y, $pos2->z, $block->getDamage ());
|
||||||
|
}
|
||||||
|
for($z = $pos1->z; $z >= $pos2->z; $z --) {
|
||||||
|
$level->setBlockIdAt($pos1->x, $y, $z, $block->getId ());
|
||||||
|
$level->setBlockDataAt($pos1->x, $y, $z, $block->getDamage ());
|
||||||
|
$level->setBlockIdAt($pos2->x, $y, $z, $block->getId ());
|
||||||
|
$level->setBlockDataAt($pos2->x, $y, $z, $block->getDamage ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the top of a structure
|
||||||
|
*
|
||||||
|
* @param ChunkManager $level
|
||||||
|
* @param Vector3 $pos1
|
||||||
|
* @param Vector3 $pos2
|
||||||
|
* @param Block $block
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function top(ChunkManager $level, Vector3 $pos1, Vector3 $pos2, Block $block) {
|
||||||
|
list($pos1, $pos2) = self::minmax($pos1, $pos2);
|
||||||
|
for($x = $pos1->x; $x >= $pos2->x; $x --)
|
||||||
|
for($z = $pos1->z; $z >= $pos2->z; $z --) {
|
||||||
|
$level->setBlockIdAt($x, $pos1->y, $z, $block->getId ());
|
||||||
|
$level->setBlockDataAt($x, $pos1->y, $z, $block->getDamage ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the corners of the structures. Used for mineshaft "towers"
|
||||||
|
*
|
||||||
|
* @param ChunkManager $level
|
||||||
|
* @param Vector3 $pos1
|
||||||
|
* @param Vector3 $pos2
|
||||||
|
* @param Block $block
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function corners(ChunkManager $level, Vector3 $pos1, Vector3 $pos2, Block $block) {
|
||||||
|
list($pos1, $pos2) = self::minmax($pos1, $pos2);
|
||||||
|
for($y = $pos1->y; $y >= $pos2->y; $y --) {
|
||||||
|
$level->setBlockIdAt($pos1->x, $y, $pos1->z, $block->getId ());
|
||||||
|
$level->setBlockDataAt($pos1->x, $y, $pos1->z, $block->getDamage ());
|
||||||
|
$level->setBlockIdAt($pos2->x, $y, $pos1->z, $block->getId ());
|
||||||
|
$level->setBlockDataAt($pos2->x, $y, $pos1->z, $block->getDamage ());
|
||||||
|
$level->setBlockIdAt($pos1->x, $y, $pos2->z, $block->getId ());
|
||||||
|
$level->setBlockDataAt($pos1->x, $y, $pos2->z, $block->getDamage ());
|
||||||
|
$level->setBlockIdAt($pos2->x, $y, $pos2->z, $block->getId ());
|
||||||
|
$level->setBlockDataAt($pos2->x, $y, $pos2->z, $block->getDamage ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fills the bottom of a structure
|
||||||
|
*
|
||||||
|
* @param ChunkManager $level
|
||||||
|
* @param Vector3 $pos1
|
||||||
|
* @param Vector3 $pos2
|
||||||
|
* @param Block $block
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function bottom(ChunkManager $level, Vector3 $pos1, Vector3 $pos2, Block $block) {
|
||||||
|
list($pos1, $pos2) = self::minmax($pos1, $pos2);
|
||||||
|
for($x = $pos1->x; $x >= $pos2->x; $x --)
|
||||||
|
for($z = $pos1->z; $z >= $pos2->z; $z --) {
|
||||||
|
$level->setBlockIdAt($x, $pos2->y, $z, $block->getId ());
|
||||||
|
$level->setBlockDataAt($x, $pos2->y, $z, $block->getDamage ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds a structure randomly based on a circle algorithm. Used in caves and lakes.
|
||||||
|
*
|
||||||
|
* @param ChunkManager $level
|
||||||
|
* @param Vector3 $pos
|
||||||
|
* @param Vector3 $infos
|
||||||
|
* @param Random $random
|
||||||
|
* @param Block $block
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function buildRandom(ChunkManager $level, Vector3 $pos, Vector3 $infos, Random $random, Block $block) {
|
||||||
|
$xBounded = $random->nextBoundedInt(3) - 1;
|
||||||
|
$yBounded = $random->nextBoundedInt(3) - 1;
|
||||||
|
$zBounded = $random->nextBoundedInt(3) - 1;
|
||||||
|
$pos = $pos->round ();
|
||||||
|
for($x = $pos->x - ($infos->x / 2); $x <= $pos->x + ($infos->x / 2); $x ++) {
|
||||||
|
for($y = $pos->y - ($infos->y / 2); $y <= $pos->y + ($infos->y / 2); $y ++) {
|
||||||
|
for($z = $pos->z - ($infos->z / 2); $z <= $pos->z + ($infos->z / 2); $z ++) {
|
||||||
|
// if(abs((abs($x) - abs($pos->x)) ** 2 + ($y - $pos->y) ** 2 + (abs($z) - abs($pos->z)) ** 2) < (abs($infos->x / 2 + $xBounded) + abs($infos->y / 2 + $yBounded) + abs($infos->z / 2 + $zBounded)) ** 2
|
||||||
|
if (abs((abs($x) - abs($pos->x)) ** 2 + ($y - $pos->y) ** 2 + (abs($z) - abs($pos->z)) ** 2) < ((($infos->x / 2 - $xBounded) + ($infos->y / 2 - $yBounded) + ($infos->z / 2 - $zBounded)) / 3) ** 2 && $y > 0 && ! in_array($level->getBlockIdAt($x, $y, $z), self::TO_NOT_OVERWRITE) && ! in_array($level->getBlockIdAt($x, $y + 1, $z), self::TO_NOT_OVERWRITE)) {
|
||||||
|
$level->setBlockIdAt($x, $y, $z, $block->getId ());
|
||||||
|
$level->setBlockDataAt($x, $y, $z, $block->getDamage ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns two Vector three, the biggest and lowest ones based on two provided vectors
|
||||||
|
*
|
||||||
|
* @param Vector3 $pos1
|
||||||
|
* @param Vector3 $pos2
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected static function minmax(Vector3 $pos1, Vector3 $pos2): array {
|
||||||
|
$v1 = new Vector3(max($pos1->x, $pos2->x), max($pos1->y, $pos2->y), max($pos1->z, $pos2->z));
|
||||||
|
$v2 = new Vector3(min($pos1->x, $pos2->x), min($pos1->y, $pos2->y), min($pos1->z, $pos2->z));
|
||||||
|
return [
|
||||||
|
$v1,
|
||||||
|
$v2
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
32
src/Ad5001/RealWorld/utils/Range.php
Normal file
32
src/Ad5001/RealWorld/utils/Range.php
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ad5001\RealWorld\utils;
|
||||||
|
|
||||||
|
class Range {
|
||||||
|
|
||||||
|
/** @var int */
|
||||||
|
public $from;
|
||||||
|
/** @var int */
|
||||||
|
public $to;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a Range class
|
||||||
|
*
|
||||||
|
* @param int $from
|
||||||
|
* @param int $to
|
||||||
|
*/
|
||||||
|
public function __construct(int $from, int $to) {
|
||||||
|
$this->from = $from;
|
||||||
|
$this->to = $to;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a number is in the range
|
||||||
|
*
|
||||||
|
* @param int $toTest
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function isInRange(int $toTest){
|
||||||
|
return $this->from <= $toTest && $toTest < $this->to;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue