Removed pocketmine subdirectory, map PSR-4 style

This commit is contained in:
Dylan K. Taylor
2019-07-30 19:14:57 +01:00
parent 7a77d3dc30
commit 5499ac620c
1044 changed files with 3 additions and 3 deletions

View File

@ -0,0 +1,186 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\world\generator;
use pocketmine\block\VanillaBlocks;
use pocketmine\item\ItemFactory;
use pocketmine\world\ChunkManager;
use pocketmine\world\format\Chunk;
use pocketmine\world\generator\object\OreType;
use pocketmine\world\generator\populator\Ore;
use pocketmine\world\generator\populator\Populator;
use function array_map;
use function count;
use function explode;
use function preg_match;
use function preg_match_all;
class Flat extends Generator{
/** @var Chunk */
private $chunk;
/** @var Populator[] */
private $populators = [];
/** @var int[] */
private $structure;
/** @var int */
private $floorLevel;
/** @var int */
private $biome;
/** @var string */
private $preset;
/**
* @param ChunkManager $world
* @param int $seed
* @param array $options
*
* @throws InvalidGeneratorOptionsException
*/
public function __construct(ChunkManager $world, int $seed, array $options = []){
parent::__construct($world, $seed, $options);
if(isset($this->options["preset"]) and $this->options["preset"] != ""){
$this->preset = $this->options["preset"];
}else{
$this->preset = "2;7,2x3,2;1;";
//$this->preset = "2;7,59x1,3x3,2;1;spawn(radius=10 block=89),decoration(treecount=80 grasscount=45)";
}
$this->parsePreset();
if(isset($this->options["decoration"])){
$ores = new Ore();
$ores->setOreTypes([
new OreType(VanillaBlocks::COAL_ORE(), 20, 16, 0, 128),
new OreType(VanillaBlocks::IRON_ORE(), 20, 8, 0, 64),
new OreType(VanillaBlocks::REDSTONE_ORE(), 8, 7, 0, 16),
new OreType(VanillaBlocks::LAPIS_LAZULI_ORE(), 1, 6, 0, 32),
new OreType(VanillaBlocks::GOLD_ORE(), 2, 8, 0, 32),
new OreType(VanillaBlocks::DIAMOND_ORE(), 1, 7, 0, 16),
new OreType(VanillaBlocks::DIRT(), 20, 32, 0, 128),
new OreType(VanillaBlocks::GRAVEL(), 10, 16, 0, 128)
]);
$this->populators[] = $ores;
}
$this->generateBaseChunk();
}
/**
* @param string $layers
*
* @return int[]
* @throws InvalidGeneratorOptionsException
*/
public static function parseLayers(string $layers) : array{
$result = [];
$split = array_map('\trim', explode(',', $layers));
$y = 0;
foreach($split as $line){
preg_match('#^(?:(\d+)[x|*])?(.+)$#', $line, $matches);
if(count($matches) !== 3){
throw new InvalidGeneratorOptionsException("Invalid preset layer \"$line\"");
}
$cnt = $matches[1] !== "" ? (int) $matches[1] : 1;
try{
$b = ItemFactory::fromString($matches[2])->getBlock();
}catch(\InvalidArgumentException $e){
throw new InvalidGeneratorOptionsException("Invalid preset layer \"$line\": " . $e->getMessage(), 0, $e);
}
for($cY = $y, $y += $cnt; $cY < $y; ++$cY){
$result[$cY] = $b->getFullId();
}
}
return $result;
}
protected function parsePreset() : void{
$preset = explode(";", $this->preset);
$blocks = (string) ($preset[1] ?? "");
$this->biome = (int) ($preset[2] ?? 1);
$options = (string) ($preset[3] ?? "");
$this->structure = self::parseLayers($blocks);
$this->floorLevel = count($this->structure);
//TODO: more error checking
preg_match_all('#(([0-9a-z_]{1,})\(?([0-9a-z_ =:]{0,})\)?),?#', $options, $matches);
foreach($matches[2] as $i => $option){
$params = true;
if($matches[3][$i] !== ""){
$params = [];
$p = explode(" ", $matches[3][$i]);
foreach($p as $k){
$k = explode("=", $k);
if(isset($k[1])){
$params[$k[0]] = $k[1];
}
}
}
$this->options[$option] = $params;
}
}
protected function generateBaseChunk() : void{
$this->chunk = new Chunk(0, 0);
$this->chunk->setGenerated();
for($Z = 0; $Z < 16; ++$Z){
for($X = 0; $X < 16; ++$X){
$this->chunk->setBiomeId($X, $Z, $this->biome);
}
}
$count = count($this->structure);
for($sy = 0; $sy < $count; $sy += 16){
$subchunk = $this->chunk->getSubChunk($sy >> 4, true);
for($y = 0; $y < 16 and isset($this->structure[$y | $sy]); ++$y){
$id = $this->structure[$y | $sy];
for($Z = 0; $Z < 16; ++$Z){
for($X = 0; $X < 16; ++$X){
$subchunk->setFullBlock($X, $y, $Z, $id);
}
}
}
}
}
public function generateChunk(int $chunkX, int $chunkZ) : void{
$chunk = clone $this->chunk;
$chunk->setX($chunkX);
$chunk->setZ($chunkZ);
$this->world->setChunk($chunkX, $chunkZ, $chunk);
}
public function populateChunk(int $chunkX, int $chunkZ) : void{
$this->random->setSeed(0xdeadbeef ^ ($chunkX << 8) ^ $chunkZ ^ $this->seed);
foreach($this->populators as $populator){
$populator->populate($this->world, $chunkX, $chunkZ, $this->random);
}
}
}

View File

@ -0,0 +1,82 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
/**
* Noise classes used in world generation
*/
namespace pocketmine\world\generator;
use pocketmine\utils\Random;
use pocketmine\utils\Utils;
use pocketmine\world\ChunkManager;
use function preg_match;
abstract class Generator{
/**
* Converts a string world seed into an integer for use by the generator.
*
* @param string $seed
*
* @return int|null
*/
public static function convertSeed(string $seed) : ?int{
if($seed === ""){ //empty seed should cause a random seed to be selected - can't use 0 here because 0 is a valid seed
$convertedSeed = null;
}elseif(preg_match('/^-?\d+$/', $seed) === 1){ //this avoids treating seeds like "404.4" as integer seeds
$convertedSeed = (int) $seed;
}else{
$convertedSeed = Utils::javaStringHash($seed);
}
return $convertedSeed;
}
/** @var ChunkManager */
protected $world;
/** @var int */
protected $seed;
/** @var array */
protected $options;
/** @var Random */
protected $random;
/**
* @param ChunkManager $world
* @param int $seed
* @param array $options
*
* @throws InvalidGeneratorOptionsException
*/
public function __construct(ChunkManager $world, int $seed, array $options = []){
$this->world = $world;
$this->seed = $seed;
$this->options = $options;
$this->random = new Random($seed);
}
abstract public function generateChunk(int $chunkX, int $chunkZ) : void;
abstract public function populateChunk(int $chunkX, int $chunkZ) : void;
}

View File

@ -0,0 +1,38 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\world\generator;
use pocketmine\world\format\Chunk;
use pocketmine\world\SimpleChunkManager;
use pocketmine\world\World;
class GeneratorChunkManager extends SimpleChunkManager{
public function getChunk(int $chunkX, int $chunkZ, bool $create = false) : ?Chunk{
if(!isset($this->chunks[World::chunkHash($chunkX, $chunkZ)])){
throw new \InvalidArgumentException("Chunk does not exist");
}
return parent::getChunk($chunkX, $chunkZ, $create);
}
}

View File

@ -0,0 +1,115 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\world\generator;
use pocketmine\utils\Utils;
use pocketmine\world\generator\hell\Nether;
use pocketmine\world\generator\normal\Normal;
use function array_keys;
use function strtolower;
final class GeneratorManager{
/** @var string[] name => classname mapping */
private static $list = [];
/**
* Registers the default known generators.
*/
public static function registerDefaultGenerators() : void{
self::addGenerator(Flat::class, "flat");
self::addGenerator(Normal::class, "normal");
self::addGenerator(Normal::class, "default");
self::addGenerator(Nether::class, "hell");
self::addGenerator(Nether::class, "nether");
}
/**
* @param string $class Fully qualified name of class that extends \pocketmine\world\generator\Generator
* @param string $name Alias for this generator type that can be written in configs
* @param bool $overwrite Whether to force overwriting any existing registered generator with the same name
*
* @throws \InvalidArgumentException
*/
public static function addGenerator(string $class, string $name, bool $overwrite = false) : void{
Utils::testValidInstance($class, Generator::class);
if(!$overwrite and isset(self::$list[$name = strtolower($name)])){
throw new \InvalidArgumentException("Alias \"$name\" is already assigned");
}
self::$list[$name] = $class;
}
/**
* Returns a list of names for registered generators.
*
* @return string[]
*/
public static function getGeneratorList() : array{
return array_keys(self::$list);
}
/**
* Returns a class name of a registered Generator matching the given name.
*
* @param string $name
* @param bool $throwOnMissing @deprecated this is for backwards compatibility only
*
* @return string|Generator Name of class that extends Generator (not an actual Generator object)
* @throws \InvalidArgumentException if the generator type isn't registered
*/
public static function getGenerator(string $name, bool $throwOnMissing = false){
if(isset(self::$list[$name = strtolower($name)])){
return self::$list[$name];
}
if($throwOnMissing){
throw new \InvalidArgumentException("Alias \"$name\" does not map to any known generator");
}
return Normal::class;
}
/**
* Returns the registered name of the given Generator class.
*
* @param string $class Fully qualified name of class that extends \pocketmine\world\generator\Generator
*
* @return string
* @throws \InvalidArgumentException if the class type cannot be matched to a known alias
*/
public static function getGeneratorName(string $class) : string{
Utils::testValidInstance($class, Generator::class);
foreach(self::$list as $name => $c){
if($c === $class){
return $name;
}
}
throw new \InvalidArgumentException("Generator class $class is not registered");
}
private function __construct(){
//NOOP
}
}

View File

@ -0,0 +1,62 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\world\generator;
use pocketmine\block\BlockFactory;
use pocketmine\scheduler\AsyncTask;
use pocketmine\world\biome\Biome;
use pocketmine\world\World;
use function serialize;
use function unserialize;
class GeneratorRegisterTask extends AsyncTask{
public $generatorClass;
public $settings;
public $seed;
public $worldId;
public $worldHeight = World::Y_MAX;
public function __construct(World $world, string $generatorClass, array $generatorSettings = []){
$this->generatorClass = $generatorClass;
$this->settings = serialize($generatorSettings);
$this->seed = $world->getSeed();
$this->worldId = $world->getId();
$this->worldHeight = $world->getWorldHeight();
}
public function onRun() : void{
BlockFactory::init();
Biome::init();
$manager = new GeneratorChunkManager($this->worldHeight);
$this->worker->saveToThreadStore("generation.world{$this->worldId}.manager", $manager);
/**
* @var Generator $generator
* @see Generator::__construct()
*/
$generator = new $this->generatorClass($manager, $this->seed, unserialize($this->settings));
$this->worker->saveToThreadStore("generation.world{$this->worldId}.generator", $generator);
}
}

View File

@ -0,0 +1,41 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\world\generator;
use pocketmine\scheduler\AsyncTask;
use pocketmine\world\World;
class GeneratorUnregisterTask extends AsyncTask{
public $worldId;
public function __construct(World $world){
$this->worldId = $world->getId();
}
public function onRun() : void{
$this->worker->removeFromThreadStore("generation.world{$this->worldId}.manager");
$this->worker->removeFromThreadStore("generation.world{$this->worldId}.generator");
}
}

View File

@ -0,0 +1,28 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\world\generator;
class InvalidGeneratorOptionsException extends \UnexpectedValueException{
}

View File

@ -0,0 +1,165 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\world\generator;
use pocketmine\scheduler\AsyncTask;
use pocketmine\world\format\Chunk;
use pocketmine\world\format\io\FastChunkSerializer;
use pocketmine\world\SimpleChunkManager;
use pocketmine\world\World;
class PopulationTask extends AsyncTask{
private const TLS_KEY_WORLD = "world";
public $state;
public $worldId;
public $chunk;
public $chunk0;
public $chunk1;
public $chunk2;
public $chunk3;
//center chunk
public $chunk5;
public $chunk6;
public $chunk7;
public $chunk8;
public function __construct(World $world, Chunk $chunk){
$this->state = true;
$this->worldId = $world->getId();
$this->chunk = FastChunkSerializer::serialize($chunk);
foreach($world->getAdjacentChunks($chunk->getX(), $chunk->getZ()) as $i => $c){
$this->{"chunk$i"} = $c !== null ? FastChunkSerializer::serialize($c) : null;
}
$this->storeLocal(self::TLS_KEY_WORLD, $world);
}
public function onRun() : void{
/** @var SimpleChunkManager $manager */
$manager = $this->worker->getFromThreadStore("generation.world{$this->worldId}.manager");
/** @var Generator $generator */
$generator = $this->worker->getFromThreadStore("generation.world{$this->worldId}.generator");
if($manager === null or $generator === null){
$this->state = false;
return;
}
/** @var Chunk[] $chunks */
$chunks = [];
$chunk = FastChunkSerializer::deserialize($this->chunk);
for($i = 0; $i < 9; ++$i){
if($i === 4){
continue;
}
$xx = -1 + $i % 3;
$zz = -1 + (int) ($i / 3);
$ck = $this->{"chunk$i"};
if($ck === null){
$chunks[$i] = new Chunk($chunk->getX() + $xx, $chunk->getZ() + $zz);
}else{
$chunks[$i] = FastChunkSerializer::deserialize($ck);
}
}
$manager->setChunk($chunk->getX(), $chunk->getZ(), $chunk);
if(!$chunk->isGenerated()){
$generator->generateChunk($chunk->getX(), $chunk->getZ());
$chunk->setGenerated();
}
foreach($chunks as $c){
if($c !== null){
$manager->setChunk($c->getX(), $c->getZ(), $c);
if(!$c->isGenerated()){
$generator->generateChunk($c->getX(), $c->getZ());
$c = $manager->getChunk($c->getX(), $c->getZ());
$c->setGenerated();
}
}
}
$generator->populateChunk($chunk->getX(), $chunk->getZ());
$chunk = $manager->getChunk($chunk->getX(), $chunk->getZ());
$chunk->recalculateHeightMap();
$chunk->populateSkyLight();
$chunk->setLightPopulated();
$chunk->setPopulated();
$this->chunk = FastChunkSerializer::serialize($chunk);
$manager->setChunk($chunk->getX(), $chunk->getZ(), null);
foreach($chunks as $i => $c){
if($c !== null){
$c = $chunks[$i] = $manager->getChunk($c->getX(), $c->getZ());
if(!$c->hasChanged()){
$chunks[$i] = null;
}
}else{
//This way non-changed chunks are not set
$chunks[$i] = null;
}
}
$manager->cleanChunks();
for($i = 0; $i < 9; ++$i){
if($i === 4){
continue;
}
$this->{"chunk$i"} = $chunks[$i] !== null ? FastChunkSerializer::serialize($chunks[$i]) : null;
}
}
public function onCompletion() : void{
/** @var World $world */
$world = $this->fetchLocal(self::TLS_KEY_WORLD);
if(!$world->isClosed()){
if(!$this->state){
$world->registerGeneratorToWorker($this->worker->getAsyncWorkerId());
}
$chunk = FastChunkSerializer::deserialize($this->chunk);
for($i = 0; $i < 9; ++$i){
if($i === 4){
continue;
}
$c = $this->{"chunk$i"};
if($c !== null){
$c = FastChunkSerializer::deserialize($c);
$world->generateChunkCallback($c->getX(), $c->getZ(), $this->state ? $c : null);
}
}
$world->generateChunkCallback($chunk->getX(), $chunk->getZ(), $this->state ? $chunk : null);
}
}
}

View File

@ -0,0 +1,90 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\world\generator\biome;
use pocketmine\utils\Random;
use pocketmine\world\biome\Biome;
use pocketmine\world\biome\UnknownBiome;
use pocketmine\world\generator\noise\Simplex;
abstract class BiomeSelector{
/** @var Simplex */
private $temperature;
/** @var Simplex */
private $rainfall;
/** @var Biome[]|\SplFixedArray */
private $map = null;
public function __construct(Random $random){
$this->temperature = new Simplex($random, 2, 1 / 16, 1 / 512);
$this->rainfall = new Simplex($random, 2, 1 / 16, 1 / 512);
}
/**
* Lookup function called by recalculate() to determine the biome to use for this temperature and rainfall.
*
* @param float $temperature
* @param float $rainfall
*
* @return int biome ID 0-255
*/
abstract protected function lookup(float $temperature, float $rainfall) : int;
public function recalculate() : void{
$this->map = new \SplFixedArray(64 * 64);
for($i = 0; $i < 64; ++$i){
for($j = 0; $j < 64; ++$j){
$biome = Biome::getBiome($this->lookup($i / 63, $j / 63));
if($biome instanceof UnknownBiome){
throw new \RuntimeException("Unknown biome returned by selector with ID " . $biome->getId());
}
$this->map[$i + ($j << 6)] = $biome;
}
}
}
public function getTemperature($x, $z){
return ($this->temperature->noise2D($x, $z, true) + 1) / 2;
}
public function getRainfall($x, $z){
return ($this->rainfall->noise2D($x, $z, true) + 1) / 2;
}
/**
* TODO: not sure on types here
* @param int|float $x
* @param int|float $z
*
* @return Biome
*/
public function pickBiome($x, $z) : Biome{
$temperature = (int) ($this->getTemperature($x, $z) * 63);
$rainfall = (int) ($this->getRainfall($x, $z) * 63);
return $this->map[$temperature + ($rainfall << 6)];
}
}

View File

@ -0,0 +1,129 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\world\generator\hell;
use pocketmine\block\VanillaBlocks;
use pocketmine\world\biome\Biome;
use pocketmine\world\ChunkManager;
use pocketmine\world\generator\Generator;
use pocketmine\world\generator\InvalidGeneratorOptionsException;
use pocketmine\world\generator\noise\Simplex;
use pocketmine\world\generator\populator\Populator;
use function abs;
class Nether extends Generator{
/** @var Populator[] */
private $populators = [];
/** @var int */
private $waterHeight = 32;
/** @var int */
private $emptyHeight = 64;
/** @var int */
private $emptyAmplitude = 1;
/** @var float */
private $density = 0.5;
/** @var Populator[] */
private $generationPopulators = [];
/** @var Simplex */
private $noiseBase;
/**
* @param ChunkManager $world
* @param int $seed
* @param array $options
*
* @throws InvalidGeneratorOptionsException
*/
public function __construct(ChunkManager $world, int $seed, array $options = []){
parent::__construct($world, $seed, $options);
$this->noiseBase = new Simplex($this->random, 4, 1 / 4, 1 / 64);
$this->random->setSeed($this->seed);
/*$ores = new Ore();
$ores->setOreTypes([
new OreType(new CoalOre(), 20, 16, 0, 128),
new OreType(new IronOre(), 20, 8, 0, 64),
new OreType(new RedstoneOre(), 8, 7, 0, 16),
new OreType(new LapisOre(), 1, 6, 0, 32),
new OreType(new GoldOre(), 2, 8, 0, 32),
new OreType(new DiamondOre(), 1, 7, 0, 16),
new OreType(new Dirt(), 20, 32, 0, 128),
new OreType(new Gravel(), 10, 16, 0, 128)
]);
$this->populators[] = $ores;*/
}
public function generateChunk(int $chunkX, int $chunkZ) : void{
$this->random->setSeed(0xdeadbeef ^ ($chunkX << 8) ^ $chunkZ ^ $this->seed);
$noise = $this->noiseBase->getFastNoise3D(16, 128, 16, 4, 8, 4, $chunkX * 16, 0, $chunkZ * 16);
$chunk = $this->world->getChunk($chunkX, $chunkZ);
$bedrock = VanillaBlocks::BEDROCK()->getFullId();
$netherrack = VanillaBlocks::NETHERRACK()->getFullId();
$stillLava = VanillaBlocks::LAVA()->getFullId();
for($x = 0; $x < 16; ++$x){
for($z = 0; $z < 16; ++$z){
$biome = Biome::getBiome(Biome::HELL);
$chunk->setBiomeId($x, $z, $biome->getId());
for($y = 0; $y < 128; ++$y){
if($y === 0 or $y === 127){
$chunk->setFullBlock($x, $y, $z, $bedrock);
continue;
}
$noiseValue = (abs($this->emptyHeight - $y) / $this->emptyHeight) * $this->emptyAmplitude - $noise[$x][$z][$y];
$noiseValue -= 1 - $this->density;
if($noiseValue > 0){
$chunk->setFullBlock($x, $y, $z, $netherrack);
}elseif($y <= $this->waterHeight){
$chunk->setFullBlock($x, $y, $z, $stillLava);
}
}
}
}
foreach($this->generationPopulators as $populator){
$populator->populate($this->world, $chunkX, $chunkZ, $this->random);
}
}
public function populateChunk(int $chunkX, int $chunkZ) : void{
$this->random->setSeed(0xdeadbeef ^ ($chunkX << 8) ^ $chunkZ ^ $this->seed);
foreach($this->populators as $populator){
$populator->populate($this->world, $chunkX, $chunkZ, $this->random);
}
$chunk = $this->world->getChunk($chunkX, $chunkZ);
$biome = Biome::getBiome($chunk->getBiomeId(7, 7));
$biome->populateChunk($this->world, $chunkX, $chunkZ, $this->random);
}
}

View File

@ -0,0 +1,290 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
/**
* Different noise generators for world generation
*/
namespace pocketmine\world\generator\noise;
use function array_fill;
use function assert;
abstract class Noise{
public static function linearLerp($x, $x1, $x2, $q0, $q1){
return (($x2 - $x) / ($x2 - $x1)) * $q0 + (($x - $x1) / ($x2 - $x1)) * $q1;
}
public static function bilinearLerp($x, $y, $q00, $q01, $q10, $q11, $x1, $x2, $y1, $y2){
$dx1 = (($x2 - $x) / ($x2 - $x1));
$dx2 = (($x - $x1) / ($x2 - $x1));
return (($y2 - $y) / ($y2 - $y1)) * (
$dx1 * $q00 + $dx2 * $q10
) + (($y - $y1) / ($y2 - $y1)) * (
$dx1 * $q01 + $dx2 * $q11
);
}
public static function trilinearLerp($x, $y, $z, $q000, $q001, $q010, $q011, $q100, $q101, $q110, $q111, $x1, $x2, $y1, $y2, $z1, $z2){
$dx1 = (($x2 - $x) / ($x2 - $x1));
$dx2 = (($x - $x1) / ($x2 - $x1));
$dy1 = (($y2 - $y) / ($y2 - $y1));
$dy2 = (($y - $y1) / ($y2 - $y1));
return (($z2 - $z) / ($z2 - $z1)) * (
$dy1 * (
$dx1 * $q000 + $dx2 * $q100
) + $dy2 * (
$dx1 * $q001 + $dx2 * $q101
)
) + (($z - $z1) / ($z2 - $z1)) * (
$dy1 * (
$dx1 * $q010 + $dx2 * $q110
) + $dy2 * (
$dx1 * $q011 + $dx2 * $q111
)
);
}
/** @var float */
protected $persistence;
/** @var float */
protected $expansion;
/** @var int */
protected $octaves;
public function __construct(int $octaves, float $persistence, float $expansion){
$this->octaves = $octaves;
$this->persistence = $persistence;
$this->expansion = $expansion;
}
abstract public function getNoise2D($x, $z);
abstract public function getNoise3D($x, $y, $z);
public function noise2D($x, $z, $normalized = false){
$result = 0;
$amp = 1;
$freq = 1;
$max = 0;
$x *= $this->expansion;
$z *= $this->expansion;
for($i = 0; $i < $this->octaves; ++$i){
$result += $this->getNoise2D($x * $freq, $z * $freq) * $amp;
$max += $amp;
$freq *= 2;
$amp *= $this->persistence;
}
if($normalized === true){
$result /= $max;
}
return $result;
}
public function noise3D($x, $y, $z, $normalized = false){
$result = 0;
$amp = 1;
$freq = 1;
$max = 0;
$x *= $this->expansion;
$y *= $this->expansion;
$z *= $this->expansion;
for($i = 0; $i < $this->octaves; ++$i){
$result += $this->getNoise3D($x * $freq, $y * $freq, $z * $freq) * $amp;
$max += $amp;
$freq *= 2;
$amp *= $this->persistence;
}
if($normalized === true){
$result /= $max;
}
return $result;
}
/**
* @param int $xSize
* @param int $samplingRate
* @param int $x
* @param int $y
* @param int $z
*
* @return \SplFixedArray
*/
public function getFastNoise1D(int $xSize, int $samplingRate, int $x, int $y, int $z) : \SplFixedArray{
if($samplingRate === 0){
throw new \InvalidArgumentException("samplingRate cannot be 0");
}
if($xSize % $samplingRate !== 0){
throw new \InvalidArgumentException("xSize % samplingRate must return 0");
}
$noiseArray = new \SplFixedArray($xSize + 1);
for($xx = 0; $xx <= $xSize; $xx += $samplingRate){
$noiseArray[$xx] = $this->noise3D($xx + $x, $y, $z);
}
for($xx = 0; $xx < $xSize; ++$xx){
if($xx % $samplingRate !== 0){
$nx = (int) ($xx / $samplingRate) * $samplingRate;
$noiseArray[$xx] = self::linearLerp($xx, $nx, $nx + $samplingRate, $noiseArray[$nx], $noiseArray[$nx + $samplingRate]);
}
}
return $noiseArray;
}
/**
* @param int $xSize
* @param int $zSize
* @param int $samplingRate
* @param int $x
* @param int $y
* @param int $z
*
* @return \SplFixedArray
*/
public function getFastNoise2D(int $xSize, int $zSize, int $samplingRate, int $x, int $y, int $z) : \SplFixedArray{
assert($samplingRate !== 0, new \InvalidArgumentException("samplingRate cannot be 0"));
assert($xSize % $samplingRate === 0, new \InvalidArgumentException("xSize % samplingRate must return 0"));
assert($zSize % $samplingRate === 0, new \InvalidArgumentException("zSize % samplingRate must return 0"));
$noiseArray = new \SplFixedArray($xSize + 1);
for($xx = 0; $xx <= $xSize; $xx += $samplingRate){
$noiseArray[$xx] = new \SplFixedArray($zSize + 1);
for($zz = 0; $zz <= $zSize; $zz += $samplingRate){
$noiseArray[$xx][$zz] = $this->noise3D($x + $xx, $y, $z + $zz);
}
}
for($xx = 0; $xx < $xSize; ++$xx){
if($xx % $samplingRate !== 0){
$noiseArray[$xx] = new \SplFixedArray($zSize + 1);
}
for($zz = 0; $zz < $zSize; ++$zz){
if($xx % $samplingRate !== 0 or $zz % $samplingRate !== 0){
$nx = (int) ($xx / $samplingRate) * $samplingRate;
$nz = (int) ($zz / $samplingRate) * $samplingRate;
$noiseArray[$xx][$zz] = Noise::bilinearLerp(
$xx, $zz, $noiseArray[$nx][$nz], $noiseArray[$nx][$nz + $samplingRate],
$noiseArray[$nx + $samplingRate][$nz], $noiseArray[$nx + $samplingRate][$nz + $samplingRate],
$nx, $nx + $samplingRate, $nz, $nz + $samplingRate
);
}
}
}
return $noiseArray;
}
/**
* @param int $xSize
* @param int $ySize
* @param int $zSize
* @param int $xSamplingRate
* @param int $ySamplingRate
* @param int $zSamplingRate
* @param int $x
* @param int $y
* @param int $z
*
* @return array
*/
public function getFastNoise3D(int $xSize, int $ySize, int $zSize, int $xSamplingRate, int $ySamplingRate, int $zSamplingRate, int $x, int $y, int $z) : array{
assert($xSamplingRate !== 0, new \InvalidArgumentException("xSamplingRate cannot be 0"));
assert($zSamplingRate !== 0, new \InvalidArgumentException("zSamplingRate cannot be 0"));
assert($ySamplingRate !== 0, new \InvalidArgumentException("ySamplingRate cannot be 0"));
assert($xSize % $xSamplingRate === 0, new \InvalidArgumentException("xSize % xSamplingRate must return 0"));
assert($zSize % $zSamplingRate === 0, new \InvalidArgumentException("zSize % zSamplingRate must return 0"));
assert($ySize % $ySamplingRate === 0, new \InvalidArgumentException("ySize % ySamplingRate must return 0"));
$noiseArray = array_fill(0, $xSize + 1, array_fill(0, $zSize + 1, []));
for($xx = 0; $xx <= $xSize; $xx += $xSamplingRate){
for($zz = 0; $zz <= $zSize; $zz += $zSamplingRate){
for($yy = 0; $yy <= $ySize; $yy += $ySamplingRate){
$noiseArray[$xx][$zz][$yy] = $this->noise3D($x + $xx, $y + $yy, $z + $zz, true);
}
}
}
for($xx = 0; $xx < $xSize; ++$xx){
for($zz = 0; $zz < $zSize; ++$zz){
for($yy = 0; $yy < $ySize; ++$yy){
if($xx % $xSamplingRate !== 0 or $zz % $zSamplingRate !== 0 or $yy % $ySamplingRate !== 0){
$nx = (int) ($xx / $xSamplingRate) * $xSamplingRate;
$ny = (int) ($yy / $ySamplingRate) * $ySamplingRate;
$nz = (int) ($zz / $zSamplingRate) * $zSamplingRate;
$nnx = $nx + $xSamplingRate;
$nny = $ny + $ySamplingRate;
$nnz = $nz + $zSamplingRate;
/**
* This code has been manually inlined.
* @see Noise::trilinearLerp()
*/
$dx1 = (($nnx - $xx) / ($nnx - $nx));
$dx2 = (($xx - $nx) / ($nnx - $nx));
$dy1 = (($nny - $yy) / ($nny - $ny));
$dy2 = (($yy - $ny) / ($nny - $ny));
$noiseArray[$xx][$zz][$yy] = (($nnz - $zz) / ($nnz - $nz)) * (
$dy1 * (
$dx1 * $noiseArray[$nx][$nz][$ny] + $dx2 * $noiseArray[$nnx][$nz][$ny]
) + $dy2 * (
$dx1 * $noiseArray[$nx][$nz][$nny] + $dx2 * $noiseArray[$nnx][$nz][$nny]
)
) + (($zz - $nz) / ($nnz - $nz)) * (
$dy1 * (
$dx1 * $noiseArray[$nx][$nnz][$ny] + $dx2 * $noiseArray[$nnx][$nnz][$ny]
) + $dy2 * (
$dx1 * $noiseArray[$nx][$nnz][$nny] + $dx2 * $noiseArray[$nnx][$nnz][$nny]
)
);
}
}
}
}
return $noiseArray;
}
}

View File

@ -0,0 +1,276 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\world\generator\noise;
use pocketmine\utils\Random;
use const M_SQRT3;
/**
* Generates simplex-based noise.
*
* This is a modified version of the freely published version in the paper by
* Stefan Gustavson at
* http://staffwww.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf
*/
class Simplex extends Noise{
protected const grad3 = [
[1, 1, 0], [-1, 1, 0], [1, -1, 0], [-1, -1, 0],
[1, 0, 1], [-1, 0, 1], [1, 0, -1], [-1, 0, -1],
[0, 1, 1], [0, -1, 1], [0, 1, -1], [0, -1, -1]
];
protected const F2 = 0.5 * (M_SQRT3 - 1);
protected const G2 = (3 - M_SQRT3) / 6;
protected const G22 = self::G2 * 2.0 - 1;
protected const F3 = 1.0 / 3.0;
protected const G3 = 1.0 / 6.0;
/** @var float */
protected $offsetX;
/** @var float */
protected $offsetZ;
/** @var float */
protected $offsetY;
/** @var int[] */
protected $perm = [];
public function __construct(Random $random, int $octaves, float $persistence, float $expansion){
parent::__construct($octaves, $persistence, $expansion);
$this->offsetX = $random->nextFloat() * 256;
$this->offsetY = $random->nextFloat() * 256;
$this->offsetZ = $random->nextFloat() * 256;
for($i = 0; $i < 512; ++$i){
$this->perm[$i] = 0;
}
for($i = 0; $i < 256; ++$i){
$this->perm[$i] = $random->nextBoundedInt(256);
}
for($i = 0; $i < 256; ++$i){
$pos = $random->nextBoundedInt(256 - $i) + $i;
$old = $this->perm[$i];
$this->perm[$i] = $this->perm[$pos];
$this->perm[$pos] = $old;
$this->perm[$i + 256] = $this->perm[$i];
}
//this dummy call is necessary to produce the same RNG state as before latest refactors to this file
//previously this value would be used for offsetW
//TODO: this really needs to reset the RNG seed to avoid future RNG contamination
$random->nextSignedInt();
}
public function getNoise3D($x, $y, $z){
$x += $this->offsetX;
$y += $this->offsetY;
$z += $this->offsetZ;
// Skew the input space to determine which simplex cell we're in
$s = ($x + $y + $z) * self::F3; // Very nice and simple skew factor for 3D
$i = (int) ($x + $s);
$j = (int) ($y + $s);
$k = (int) ($z + $s);
$t = ($i + $j + $k) * self::G3;
// Unskew the cell origin back to (x,y,z) space
$x0 = $x - ($i - $t); // The x,y,z distances from the cell origin
$y0 = $y - ($j - $t);
$z0 = $z - ($k - $t);
// For the 3D case, the simplex shape is a slightly irregular tetrahedron.
// Determine which simplex we are in.
if($x0 >= $y0){
if($y0 >= $z0){
$i1 = 1;
$j1 = 0;
$k1 = 0;
$i2 = 1;
$j2 = 1;
$k2 = 0;
} // X Y Z order
elseif($x0 >= $z0){
$i1 = 1;
$j1 = 0;
$k1 = 0;
$i2 = 1;
$j2 = 0;
$k2 = 1;
} // X Z Y order
else{
$i1 = 0;
$j1 = 0;
$k1 = 1;
$i2 = 1;
$j2 = 0;
$k2 = 1;
}
// Z X Y order
}else{ // x0<y0
if($y0 < $z0){
$i1 = 0;
$j1 = 0;
$k1 = 1;
$i2 = 0;
$j2 = 1;
$k2 = 1;
} // Z Y X order
elseif($x0 < $z0){
$i1 = 0;
$j1 = 1;
$k1 = 0;
$i2 = 0;
$j2 = 1;
$k2 = 1;
} // Y Z X order
else{
$i1 = 0;
$j1 = 1;
$k1 = 0;
$i2 = 1;
$j2 = 1;
$k2 = 0;
}
// Y X Z order
}
// A step of (1,0,0) in (i,j,k) means a step of (1-c,-c,-c) in (x,y,z),
// a step of (0,1,0) in (i,j,k) means a step of (-c,1-c,-c) in (x,y,z), and
// a step of (0,0,1) in (i,j,k) means a step of (-c,-c,1-c) in (x,y,z), where
// c = 1/6.
$x1 = $x0 - $i1 + self::G3; // Offsets for second corner in (x,y,z) coords
$y1 = $y0 - $j1 + self::G3;
$z1 = $z0 - $k1 + self::G3;
$x2 = $x0 - $i2 + 2.0 * self::G3; // Offsets for third corner in (x,y,z) coords
$y2 = $y0 - $j2 + 2.0 * self::G3;
$z2 = $z0 - $k2 + 2.0 * self::G3;
$x3 = $x0 - 1.0 + 3.0 * self::G3; // Offsets for last corner in (x,y,z) coords
$y3 = $y0 - 1.0 + 3.0 * self::G3;
$z3 = $z0 - 1.0 + 3.0 * self::G3;
// Work out the hashed gradient indices of the four simplex corners
$ii = $i & 255;
$jj = $j & 255;
$kk = $k & 255;
$n = 0;
// Calculate the contribution from the four corners
$t0 = 0.6 - $x0 * $x0 - $y0 * $y0 - $z0 * $z0;
if($t0 > 0){
$gi0 = self::grad3[$this->perm[$ii + $this->perm[$jj + $this->perm[$kk]]] % 12];
$n += $t0 * $t0 * $t0 * $t0 * ($gi0[0] * $x0 + $gi0[1] * $y0 + $gi0[2] * $z0);
}
$t1 = 0.6 - $x1 * $x1 - $y1 * $y1 - $z1 * $z1;
if($t1 > 0){
$gi1 = self::grad3[$this->perm[$ii + $i1 + $this->perm[$jj + $j1 + $this->perm[$kk + $k1]]] % 12];
$n += $t1 * $t1 * $t1 * $t1 * ($gi1[0] * $x1 + $gi1[1] * $y1 + $gi1[2] * $z1);
}
$t2 = 0.6 - $x2 * $x2 - $y2 * $y2 - $z2 * $z2;
if($t2 > 0){
$gi2 = self::grad3[$this->perm[$ii + $i2 + $this->perm[$jj + $j2 + $this->perm[$kk + $k2]]] % 12];
$n += $t2 * $t2 * $t2 * $t2 * ($gi2[0] * $x2 + $gi2[1] * $y2 + $gi2[2] * $z2);
}
$t3 = 0.6 - $x3 * $x3 - $y3 * $y3 - $z3 * $z3;
if($t3 > 0){
$gi3 = self::grad3[$this->perm[$ii + 1 + $this->perm[$jj + 1 + $this->perm[$kk + 1]]] % 12];
$n += $t3 * $t3 * $t3 * $t3 * ($gi3[0] * $x3 + $gi3[1] * $y3 + $gi3[2] * $z3);
}
// Add contributions from each corner to get the noise value.
// The result is scaled to stay just inside [-1,1]
return 32.0 * $n;
}
public function getNoise2D($x, $y){
$x += $this->offsetX;
$y += $this->offsetY;
// Skew the input space to determine which simplex cell we're in
$s = ($x + $y) * self::F2; // Hairy factor for 2D
$i = (int) ($x + $s);
$j = (int) ($y + $s);
$t = ($i + $j) * self::G2;
// Unskew the cell origin back to (x,y) space
$x0 = $x - ($i - $t); // The x,y distances from the cell origin
$y0 = $y - ($j - $t);
// For the 2D case, the simplex shape is an equilateral triangle.
// Determine which simplex we are in.
if($x0 > $y0){
$i1 = 1;
$j1 = 0;
} // lower triangle, XY order: (0,0)->(1,0)->(1,1)
else{
$i1 = 0;
$j1 = 1;
}
// upper triangle, YX order: (0,0)->(0,1)->(1,1)
// A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and
// a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where
// c = (3-sqrt(3))/6
$x1 = $x0 - $i1 + self::G2; // Offsets for middle corner in (x,y) unskewed coords
$y1 = $y0 - $j1 + self::G2;
$x2 = $x0 + self::G22; // Offsets for last corner in (x,y) unskewed coords
$y2 = $y0 + self::G22;
// Work out the hashed gradient indices of the three simplex corners
$ii = $i & 255;
$jj = $j & 255;
$n = 0;
// Calculate the contribution from the three corners
$t0 = 0.5 - $x0 * $x0 - $y0 * $y0;
if($t0 > 0){
$gi0 = self::grad3[$this->perm[$ii + $this->perm[$jj]] % 12];
$n += $t0 * $t0 * $t0 * $t0 * ($gi0[0] * $x0 + $gi0[1] * $y0); // (x,y) of grad3 used for 2D gradient
}
$t1 = 0.5 - $x1 * $x1 - $y1 * $y1;
if($t1 > 0){
$gi1 = self::grad3[$this->perm[$ii + $i1 + $this->perm[$jj + $j1]] % 12];
$n += $t1 * $t1 * $t1 * $t1 * ($gi1[0] * $x1 + $gi1[1] * $y1);
}
$t2 = 0.5 - $x2 * $x2 - $y2 * $y2;
if($t2 > 0){
$gi2 = self::grad3[$this->perm[$ii + 1 + $this->perm[$jj + 1]] % 12];
$n += $t2 * $t2 * $t2 * $t2 * ($gi2[0] * $x2 + $gi2[1] * $y2);
}
// Add contributions from each corner to get the noise value.
// The result is scaled to return values in the interval [-1,1].
return 70.0 * $n;
}
}

View File

@ -0,0 +1,247 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\world\generator\normal;
use pocketmine\block\VanillaBlocks;
use pocketmine\world\biome\Biome;
use pocketmine\world\ChunkManager;
use pocketmine\world\generator\biome\BiomeSelector;
use pocketmine\world\generator\Generator;
use pocketmine\world\generator\InvalidGeneratorOptionsException;
use pocketmine\world\generator\noise\Simplex;
use pocketmine\world\generator\object\OreType;
use pocketmine\world\generator\populator\GroundCover;
use pocketmine\world\generator\populator\Ore;
use pocketmine\world\generator\populator\Populator;
use pocketmine\world\World;
use function exp;
class Normal extends Generator{
/** @var Populator[] */
private $populators = [];
/** @var int */
private $waterHeight = 62;
/** @var Populator[] */
private $generationPopulators = [];
/** @var Simplex */
private $noiseBase;
/** @var BiomeSelector */
private $selector;
private static $GAUSSIAN_KERNEL = null;
private static $SMOOTH_SIZE = 2;
/**
* @param ChunkManager $world
* @param int $seed
* @param array $options
*
* @throws InvalidGeneratorOptionsException
*/
public function __construct(ChunkManager $world, int $seed, array $options = []){
parent::__construct($world, $seed, $options);
if(self::$GAUSSIAN_KERNEL === null){
self::generateKernel();
}
$this->noiseBase = new Simplex($this->random, 4, 1 / 4, 1 / 32);
$this->random->setSeed($this->seed);
$this->selector = new class($this->random) extends BiomeSelector{
protected function lookup(float $temperature, float $rainfall) : int{
if($rainfall < 0.25){
if($temperature < 0.7){
return Biome::OCEAN;
}elseif($temperature < 0.85){
return Biome::RIVER;
}else{
return Biome::SWAMP;
}
}elseif($rainfall < 0.60){
if($temperature < 0.25){
return Biome::ICE_PLAINS;
}elseif($temperature < 0.75){
return Biome::PLAINS;
}else{
return Biome::DESERT;
}
}elseif($rainfall < 0.80){
if($temperature < 0.25){
return Biome::TAIGA;
}elseif($temperature < 0.75){
return Biome::FOREST;
}else{
return Biome::BIRCH_FOREST;
}
}else{
//FIXME: This will always cause River to be used since the rainfall is always greater than 0.8 if we
//reached this branch. However I don't think that substituting temperature for rainfall is correct given
//that mountain biomes are supposed to be pretty cold.
if($rainfall < 0.25){
return Biome::MOUNTAINS;
}elseif($rainfall < 0.70){
return Biome::SMALL_MOUNTAINS;
}else{
return Biome::RIVER;
}
}
}
};
$this->selector->recalculate();
$cover = new GroundCover();
$this->generationPopulators[] = $cover;
$ores = new Ore();
$ores->setOreTypes([
new OreType(VanillaBlocks::COAL_ORE(), 20, 16, 0, 128),
new OreType(VanillaBlocks::IRON_ORE(), 20, 8, 0, 64),
new OreType(VanillaBlocks::REDSTONE_ORE(), 8, 7, 0, 16),
new OreType(VanillaBlocks::LAPIS_LAZULI_ORE(), 1, 6, 0, 32),
new OreType(VanillaBlocks::GOLD_ORE(), 2, 8, 0, 32),
new OreType(VanillaBlocks::DIAMOND_ORE(), 1, 7, 0, 16),
new OreType(VanillaBlocks::DIRT(), 20, 32, 0, 128),
new OreType(VanillaBlocks::GRAVEL(), 10, 16, 0, 128)
]);
$this->populators[] = $ores;
}
private static function generateKernel() : void{
self::$GAUSSIAN_KERNEL = [];
$bellSize = 1 / self::$SMOOTH_SIZE;
$bellHeight = 2 * self::$SMOOTH_SIZE;
for($sx = -self::$SMOOTH_SIZE; $sx <= self::$SMOOTH_SIZE; ++$sx){
self::$GAUSSIAN_KERNEL[$sx + self::$SMOOTH_SIZE] = [];
for($sz = -self::$SMOOTH_SIZE; $sz <= self::$SMOOTH_SIZE; ++$sz){
$bx = $bellSize * $sx;
$bz = $bellSize * $sz;
self::$GAUSSIAN_KERNEL[$sx + self::$SMOOTH_SIZE][$sz + self::$SMOOTH_SIZE] = $bellHeight * exp(-($bx * $bx + $bz * $bz) / 2);
}
}
}
private function pickBiome(int $x, int $z) : Biome{
$hash = $x * 2345803 ^ $z * 9236449 ^ $this->seed;
$hash *= $hash + 223;
$xNoise = $hash >> 20 & 3;
$zNoise = $hash >> 22 & 3;
if($xNoise == 3){
$xNoise = 1;
}
if($zNoise == 3){
$zNoise = 1;
}
return $this->selector->pickBiome($x + $xNoise - 1, $z + $zNoise - 1);
}
public function generateChunk(int $chunkX, int $chunkZ) : void{
$this->random->setSeed(0xdeadbeef ^ ($chunkX << 8) ^ $chunkZ ^ $this->seed);
$noise = $this->noiseBase->getFastNoise3D(16, 128, 16, 4, 8, 4, $chunkX * 16, 0, $chunkZ * 16);
$chunk = $this->world->getChunk($chunkX, $chunkZ);
$biomeCache = [];
$bedrock = VanillaBlocks::BEDROCK()->getFullId();
$stillWater = VanillaBlocks::WATER()->getFullId();
$stone = VanillaBlocks::STONE()->getFullId();
for($x = 0; $x < 16; ++$x){
for($z = 0; $z < 16; ++$z){
$minSum = 0;
$maxSum = 0;
$weightSum = 0;
$biome = $this->pickBiome($chunkX * 16 + $x, $chunkZ * 16 + $z);
$chunk->setBiomeId($x, $z, $biome->getId());
for($sx = -self::$SMOOTH_SIZE; $sx <= self::$SMOOTH_SIZE; ++$sx){
for($sz = -self::$SMOOTH_SIZE; $sz <= self::$SMOOTH_SIZE; ++$sz){
$weight = self::$GAUSSIAN_KERNEL[$sx + self::$SMOOTH_SIZE][$sz + self::$SMOOTH_SIZE];
if($sx === 0 and $sz === 0){
$adjacent = $biome;
}else{
$index = World::chunkHash($chunkX * 16 + $x + $sx, $chunkZ * 16 + $z + $sz);
if(isset($biomeCache[$index])){
$adjacent = $biomeCache[$index];
}else{
$biomeCache[$index] = $adjacent = $this->pickBiome($chunkX * 16 + $x + $sx, $chunkZ * 16 + $z + $sz);
}
}
$minSum += ($adjacent->getMinElevation() - 1) * $weight;
$maxSum += $adjacent->getMaxElevation() * $weight;
$weightSum += $weight;
}
}
$minSum /= $weightSum;
$maxSum /= $weightSum;
$smoothHeight = ($maxSum - $minSum) / 2;
for($y = 0; $y < 128; ++$y){
if($y === 0){
$chunk->setFullBlock($x, $y, $z, $bedrock);
continue;
}
$noiseValue = $noise[$x][$z][$y] - 1 / $smoothHeight * ($y - $smoothHeight - $minSum);
if($noiseValue > 0){
$chunk->setFullBlock($x, $y, $z, $stone);
}elseif($y <= $this->waterHeight){
$chunk->setFullBlock($x, $y, $z, $stillWater);
}
}
}
}
foreach($this->generationPopulators as $populator){
$populator->populate($this->world, $chunkX, $chunkZ, $this->random);
}
}
public function populateChunk(int $chunkX, int $chunkZ) : void{
$this->random->setSeed(0xdeadbeef ^ ($chunkX << 8) ^ $chunkZ ^ $this->seed);
foreach($this->populators as $populator){
$populator->populate($this->world, $chunkX, $chunkZ, $this->random);
}
$chunk = $this->world->getChunk($chunkX, $chunkZ);
$biome = Biome::getBiome($chunk->getBiomeId(7, 7));
$biome->populateChunk($this->world, $chunkX, $chunkZ, $this->random);
}
}

View File

@ -0,0 +1,46 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\world\generator\object;
use pocketmine\block\VanillaBlocks;
use pocketmine\utils\Random;
use pocketmine\world\ChunkManager;
class BirchTree extends Tree{
/** @var bool */
protected $superBirch = false;
public function __construct(bool $superBirch = false){
parent::__construct(VanillaBlocks::BIRCH_LOG(), VanillaBlocks::BIRCH_LEAVES());
$this->superBirch = $superBirch;
}
public function placeObject(ChunkManager $world, int $x, int $y, int $z, Random $random) : void{
$this->treeHeight = $random->nextBoundedInt(3) + 5;
if($this->superBirch){
$this->treeHeight += 5;
}
parent::placeObject($world, $x, $y, $z, $random);
}
}

View File

@ -0,0 +1,33 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\world\generator\object;
use pocketmine\block\VanillaBlocks;
class JungleTree extends Tree{
public function __construct(){
parent::__construct(VanillaBlocks::JUNGLE_LOG(), VanillaBlocks::JUNGLE_LEAVES(), 8);
}
}

View File

@ -0,0 +1,40 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\world\generator\object;
use pocketmine\block\VanillaBlocks;
use pocketmine\utils\Random;
use pocketmine\world\ChunkManager;
class OakTree extends Tree{
public function __construct(){
parent::__construct(VanillaBlocks::OAK_LOG(), VanillaBlocks::OAK_LEAVES());
}
public function placeObject(ChunkManager $world, int $x, int $y, int $z, Random $random) : void{
$this->treeHeight = $random->nextBoundedInt(3) + 4;
parent::placeObject($world, $x, $y, $z, $random);
}
}

View File

@ -0,0 +1,99 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\world\generator\object;
use pocketmine\block\BlockLegacyIds;
use pocketmine\math\VectorMath;
use pocketmine\utils\Random;
use pocketmine\world\ChunkManager;
use function sin;
use const M_PI;
class Ore{
/** @var Random */
private $random;
/** @var OreType */
public $type;
public function __construct(Random $random, OreType $type){
$this->type = $type;
$this->random = $random;
}
public function getType() : OreType{
return $this->type;
}
public function canPlaceObject(ChunkManager $world, int $x, int $y, int $z) : bool{
return $world->getBlockAt($x, $y, $z)->getId() === BlockLegacyIds::STONE;
}
public function placeObject(ChunkManager $world, int $x, int $y, int $z) : void{
$clusterSize = $this->type->clusterSize;
$angle = $this->random->nextFloat() * M_PI;
$offset = VectorMath::getDirection2D($angle)->multiply($clusterSize / 8);
$x1 = $x + 8 + $offset->x;
$x2 = $x + 8 - $offset->x;
$z1 = $z + 8 + $offset->y;
$z2 = $z + 8 - $offset->y;
$y1 = $y + $this->random->nextBoundedInt(3) + 2;
$y2 = $y + $this->random->nextBoundedInt(3) + 2;
for($count = 0; $count <= $clusterSize; ++$count){
$seedX = $x1 + ($x2 - $x1) * $count / $clusterSize;
$seedY = $y1 + ($y2 - $y1) * $count / $clusterSize;
$seedZ = $z1 + ($z2 - $z1) * $count / $clusterSize;
$size = ((sin($count * (M_PI / $clusterSize)) + 1) * $this->random->nextFloat() * $clusterSize / 16 + 1) / 2;
$startX = (int) ($seedX - $size);
$startY = (int) ($seedY - $size);
$startZ = (int) ($seedZ - $size);
$endX = (int) ($seedX + $size);
$endY = (int) ($seedY + $size);
$endZ = (int) ($seedZ + $size);
for($x = $startX; $x <= $endX; ++$x){
$sizeX = ($x + 0.5 - $seedX) / $size;
$sizeX *= $sizeX;
if($sizeX < 1){
for($y = $startY; $y <= $endY; ++$y){
$sizeY = ($y + 0.5 - $seedY) / $size;
$sizeY *= $sizeY;
if($y > 0 and ($sizeX + $sizeY) < 1){
for($z = $startZ; $z <= $endZ; ++$z){
$sizeZ = ($z + 0.5 - $seedZ) / $size;
$sizeZ *= $sizeZ;
if(($sizeX + $sizeY + $sizeZ) < 1 and $world->getBlockAt($x, $y, $z)->getId() === BlockLegacyIds::STONE){
$world->setBlockAt($x, $y, $z, $this->type->material);
}
}
}
}
}
}
}
}
}

View File

@ -0,0 +1,47 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\world\generator\object;
use pocketmine\block\Block;
class OreType{
/** @var Block */
public $material;
/** @var int */
public $clusterCount;
/** @var int */
public $clusterSize;
/** @var int */
public $maxHeight;
/** @var int */
public $minHeight;
public function __construct(Block $material, int $clusterCount, int $clusterSize, int $minHeight, int $maxHeight){
$this->material = $material;
$this->clusterCount = $clusterCount;
$this->clusterSize = $clusterSize;
$this->maxHeight = $maxHeight;
$this->minHeight = $minHeight;
}
}

View File

@ -0,0 +1,82 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\world\generator\object;
use pocketmine\block\VanillaBlocks;
use pocketmine\utils\Random;
use pocketmine\world\BlockTransaction;
use pocketmine\world\ChunkManager;
use function abs;
class SpruceTree extends Tree{
public function __construct(){
parent::__construct(VanillaBlocks::SPRUCE_LOG(), VanillaBlocks::SPRUCE_LEAVES(), 10);
}
protected function generateChunkHeight(Random $random) : int{
return $this->treeHeight - $random->nextBoundedInt(3);
}
public function placeObject(ChunkManager $world, int $x, int $y, int $z, Random $random) : void{
$this->treeHeight = $random->nextBoundedInt(4) + 6;
parent::placeObject($world, $x, $y, $z, $random);
}
protected function placeCanopy(int $x, int $y, int $z, Random $random, BlockTransaction $transaction) : void{
$topSize = $this->treeHeight - (1 + $random->nextBoundedInt(2));
$lRadius = 2 + $random->nextBoundedInt(2);
$radius = $random->nextBoundedInt(2);
$maxR = 1;
$minR = 0;
for($yy = 0; $yy <= $topSize; ++$yy){
$yyy = $y + $this->treeHeight - $yy;
for($xx = $x - $radius; $xx <= $x + $radius; ++$xx){
$xOff = abs($xx - $x);
for($zz = $z - $radius; $zz <= $z + $radius; ++$zz){
$zOff = abs($zz - $z);
if($xOff === $radius and $zOff === $radius and $radius > 0){
continue;
}
if(!$transaction->fetchBlockAt($xx, $yyy, $zz)->isSolid()){
$transaction->addBlockAt($xx, $yyy, $zz, $this->leafBlock);
}
}
}
if($radius >= $maxR){
$radius = $minR;
$minR = 1;
if(++$maxR > $lRadius){
$maxR = $lRadius;
}
}else{
++$radius;
}
}
}
}

View File

@ -0,0 +1,55 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\world\generator\object;
use pocketmine\block\Block;
use pocketmine\block\BlockLegacyIds;
use pocketmine\block\VanillaBlocks;
use pocketmine\math\Vector3;
use pocketmine\utils\Random;
use pocketmine\world\ChunkManager;
use function count;
class TallGrass{
public static function growGrass(ChunkManager $world, Vector3 $pos, Random $random, int $count = 15, int $radius = 10) : void{
/** @var Block[] $arr */
$arr = [
VanillaBlocks::DANDELION(),
VanillaBlocks::POPPY(),
$tallGrass = VanillaBlocks::TALL_GRASS(),
$tallGrass,
$tallGrass,
$tallGrass
];
$arrC = count($arr) - 1;
for($c = 0; $c < $count; ++$c){
$x = $random->nextRange($pos->x - $radius, $pos->x + $radius);
$z = $random->nextRange($pos->z - $radius, $pos->z + $radius);
if($world->getBlockAt($x, $pos->y + 1, $z)->getId() === BlockLegacyIds::AIR and $world->getBlockAt($x, $pos->y, $z)->getId() === BlockLegacyIds::GRASS){
$world->setBlockAt($x, $pos->y + 1, $z, $arr[$random->nextRange(0, $arrC)]);
}
}
}
}

View File

@ -0,0 +1,154 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\world\generator\object;
use pocketmine\block\Block;
use pocketmine\block\Leaves;
use pocketmine\block\Sapling;
use pocketmine\block\utils\TreeType;
use pocketmine\block\VanillaBlocks;
use pocketmine\utils\Random;
use pocketmine\world\BlockTransaction;
use pocketmine\world\ChunkManager;
use function abs;
abstract class Tree{
/** @var Block */
protected $trunkBlock;
/** @var Block */
protected $leafBlock;
/** @var int */
protected $treeHeight;
public function __construct(Block $trunkBlock, Block $leafBlock, int $treeHeight = 7){
$this->trunkBlock = $trunkBlock;
$this->leafBlock = $leafBlock;
$this->treeHeight = $treeHeight;
}
/**
* @param ChunkManager $world
* @param int $x
* @param int $y
* @param int $z
* @param Random $random
* @param TreeType|null $type default oak
*
* @throws \InvalidArgumentException
*/
public static function growTree(ChunkManager $world, int $x, int $y, int $z, Random $random, ?TreeType $type = null) : void{
/** @var null|Tree $tree */
$tree = null;
$type = $type ?? TreeType::OAK();
if($type->equals(TreeType::SPRUCE())){
$tree = new SpruceTree();
}elseif($type->equals(TreeType::BIRCH())){
if($random->nextBoundedInt(39) === 0){
$tree = new BirchTree(true);
}else{
$tree = new BirchTree();
}
}elseif($type->equals(TreeType::JUNGLE())){
$tree = new JungleTree();
}elseif($type->equals(TreeType::OAK())){ //default
$tree = new OakTree();
/*if($random->nextRange(0, 9) === 0){
$tree = new BigTree();
}else{*/
//}
}
if($tree !== null and $tree->canPlaceObject($world, $x, $y, $z, $random)){
$tree->placeObject($world, $x, $y, $z, $random);
}
}
public function canPlaceObject(ChunkManager $world, int $x, int $y, int $z, Random $random) : bool{
$radiusToCheck = 0;
for($yy = 0; $yy < $this->treeHeight + 3; ++$yy){
if($yy === 1 or $yy === $this->treeHeight){
++$radiusToCheck;
}
for($xx = -$radiusToCheck; $xx < ($radiusToCheck + 1); ++$xx){
for($zz = -$radiusToCheck; $zz < ($radiusToCheck + 1); ++$zz){
if(!$this->canOverride($world->getBlockAt($x + $xx, $y + $yy, $z + $zz))){
return false;
}
}
}
}
return true;
}
public function placeObject(ChunkManager $world, int $x, int $y, int $z, Random $random) : void{
$transaction = new BlockTransaction($world);
$this->placeTrunk($x, $y, $z, $random, $this->generateChunkHeight($random), $transaction);
$this->placeCanopy($x, $y, $z, $random, $transaction);
$transaction->apply(); //TODO: handle return value on failure
}
protected function generateChunkHeight(Random $random) : int{
return $this->treeHeight - 1;
}
protected function placeTrunk(int $x, int $y, int $z, Random $random, int $trunkHeight, BlockTransaction $transaction) : void{
// The base dirt block
$transaction->addBlockAt($x, $y - 1, $z, VanillaBlocks::DIRT());
for($yy = 0; $yy < $trunkHeight; ++$yy){
if($this->canOverride($transaction->fetchBlockAt($x, $y + $yy, $z))){
$transaction->addBlockAt($x, $y + $yy, $z, $this->trunkBlock);
}
}
}
protected function placeCanopy(int $x, int $y, int $z, Random $random, BlockTransaction $transaction) : void{
for($yy = $y - 3 + $this->treeHeight; $yy <= $y + $this->treeHeight; ++$yy){
$yOff = $yy - ($y + $this->treeHeight);
$mid = (int) (1 - $yOff / 2);
for($xx = $x - $mid; $xx <= $x + $mid; ++$xx){
$xOff = abs($xx - $x);
for($zz = $z - $mid; $zz <= $z + $mid; ++$zz){
$zOff = abs($zz - $z);
if($xOff === $mid and $zOff === $mid and ($yOff === 0 or $random->nextBoundedInt(2) === 0)){
continue;
}
if(!$transaction->fetchBlockAt($xx, $yy, $zz)->isSolid()){
$transaction->addBlockAt($xx, $yy, $zz, $this->leafBlock);
}
}
}
}
}
protected function canOverride(Block $block) : bool{
return $block->canBeReplaced() or $block instanceof Sapling or $block instanceof Leaves;
}
}

View File

@ -0,0 +1,72 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\world\generator\populator;
use pocketmine\block\BlockFactory;
use pocketmine\block\BlockLegacyIds;
use pocketmine\block\Liquid;
use pocketmine\utils\Random;
use pocketmine\world\biome\Biome;
use pocketmine\world\ChunkManager;
use function count;
use function min;
class GroundCover extends Populator{
public function populate(ChunkManager $world, int $chunkX, int $chunkZ, Random $random) : void{
$chunk = $world->getChunk($chunkX, $chunkZ);
for($x = 0; $x < 16; ++$x){
for($z = 0; $z < 16; ++$z){
$biome = Biome::getBiome($chunk->getBiomeId($x, $z));
$cover = $biome->getGroundCover();
if(count($cover) > 0){
$diffY = 0;
if(!$cover[0]->isSolid()){
$diffY = 1;
}
for($y = 127; $y > 0; --$y){
if(!BlockFactory::fromFullBlock($chunk->getFullBlock($x, $y, $z))->isTransparent()){
break;
}
}
$startY = min(127, $y + $diffY);
$endY = $startY - count($cover);
for($y = $startY; $y > $endY and $y >= 0; --$y){
$b = $cover[$startY - $y];
$id = BlockFactory::fromFullBlock($chunk->getFullBlock($x, $y, $z));
if($id->getId() === BlockLegacyIds::AIR and $b->isSolid()){
break;
}
if($b->canBeFlowedInto() and $id instanceof Liquid){
continue;
}
$chunk->setFullBlock($x, $y, $z, $b->getFullId());
}
}
}
}
}
}

View File

@ -0,0 +1,55 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\world\generator\populator;
use pocketmine\utils\Random;
use pocketmine\world\ChunkManager;
use pocketmine\world\generator\object\Ore as ObjectOre;
use pocketmine\world\generator\object\OreType;
class Ore extends Populator{
/** @var OreType[] */
private $oreTypes = [];
public function populate(ChunkManager $world, int $chunkX, int $chunkZ, Random $random) : void{
foreach($this->oreTypes as $type){
$ore = new ObjectOre($random, $type);
for($i = 0; $i < $ore->type->clusterCount; ++$i){
$x = $random->nextRange($chunkX << 4, ($chunkX << 4) + 15);
$y = $random->nextRange($ore->type->minHeight, $ore->type->maxHeight);
$z = $random->nextRange($chunkZ << 4, ($chunkZ << 4) + 15);
if($ore->canPlaceObject($world, $x, $y, $z)){
$ore->placeObject($world, $x, $y, $z);
}
}
}
}
/**
* @param OreType[] $types
*/
public function setOreTypes(array $types) : void{
$this->oreTypes = $types;
}
}

View File

@ -0,0 +1,41 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
/**
* All the Object populator classes
*/
namespace pocketmine\world\generator\populator;
use pocketmine\utils\Random;
use pocketmine\world\ChunkManager;
abstract class Populator{
/**
* @param ChunkManager $world
* @param int $chunkX
* @param int $chunkZ
* @param Random $random
*/
abstract public function populate(ChunkManager $world, int $chunkX, int $chunkZ, Random $random) : void;
}

View File

@ -0,0 +1,76 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\world\generator\populator;
use pocketmine\block\BlockLegacyIds;
use pocketmine\block\VanillaBlocks;
use pocketmine\utils\Random;
use pocketmine\world\ChunkManager;
class TallGrass extends Populator{
/** @var ChunkManager */
private $world;
private $randomAmount;
private $baseAmount;
public function setRandomAmount(int $amount) : void{
$this->randomAmount = $amount;
}
public function setBaseAmount(int $amount) : void{
$this->baseAmount = $amount;
}
public function populate(ChunkManager $world, int $chunkX, int $chunkZ, Random $random) : void{
$this->world = $world;
$amount = $random->nextRange(0, $this->randomAmount + 1) + $this->baseAmount;
$block = VanillaBlocks::TALL_GRASS();
for($i = 0; $i < $amount; ++$i){
$x = $random->nextRange($chunkX * 16, $chunkX * 16 + 15);
$z = $random->nextRange($chunkZ * 16, $chunkZ * 16 + 15);
$y = $this->getHighestWorkableBlock($x, $z);
if($y !== -1 and $this->canTallGrassStay($x, $y, $z)){
$this->world->setBlockAt($x, $y, $z, $block);
}
}
}
private function canTallGrassStay(int $x, int $y, int $z) : bool{
$b = $this->world->getBlockAt($x, $y, $z)->getId();
return ($b === BlockLegacyIds::AIR or $b === BlockLegacyIds::SNOW_LAYER) and $this->world->getBlockAt($x, $y - 1, $z)->getId() === BlockLegacyIds::GRASS;
}
private function getHighestWorkableBlock(int $x, int $z) : int{
for($y = 127; $y >= 0; --$y){
$b = $this->world->getBlockAt($x, $y, $z)->getId();
if($b !== BlockLegacyIds::AIR and $b !== BlockLegacyIds::LEAVES and $b !== BlockLegacyIds::LEAVES2 and $b !== BlockLegacyIds::SNOW_LAYER){
break;
}
}
return $y === 0 ? -1 : ++$y;
}
}

View File

@ -0,0 +1,82 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\world\generator\populator;
use pocketmine\block\BlockLegacyIds;
use pocketmine\block\utils\TreeType;
use pocketmine\utils\Random;
use pocketmine\world\ChunkManager;
use pocketmine\world\generator\object\Tree as ObjectTree;
class Tree extends Populator{
/** @var ChunkManager */
private $world;
private $randomAmount;
private $baseAmount;
/** @var TreeType */
private $type;
/**
* @param TreeType|null $type default oak
*/
public function __construct(?TreeType $type = null){
$this->type = $type ?? TreeType::OAK();
}
public function setRandomAmount(int $amount) : void{
$this->randomAmount = $amount;
}
public function setBaseAmount(int $amount) : void{
$this->baseAmount = $amount;
}
public function populate(ChunkManager $world, int $chunkX, int $chunkZ, Random $random) : void{
$this->world = $world;
$amount = $random->nextRange(0, $this->randomAmount + 1) + $this->baseAmount;
for($i = 0; $i < $amount; ++$i){
$x = $random->nextRange($chunkX << 4, ($chunkX << 4) + 15);
$z = $random->nextRange($chunkZ << 4, ($chunkZ << 4) + 15);
$y = $this->getHighestWorkableBlock($x, $z);
if($y === -1){
continue;
}
ObjectTree::growTree($this->world, $x, $y, $z, $random, $this->type);
}
}
private function getHighestWorkableBlock(int $x, int $z) : int{
for($y = 127; $y > 0; --$y){
$b = $this->world->getBlockAt($x, $y, $z)->getId();
if($b === BlockLegacyIds::DIRT or $b === BlockLegacyIds::GRASS){
break;
}elseif($b !== BlockLegacyIds::AIR and $b !== BlockLegacyIds::SNOW_LAYER){
return -1;
}
}
return ++$y;
}
}