Generator works!

This commit is contained in:
Shoghi Cervantes 2015-03-15 16:40:18 +01:00
parent 5bfc747622
commit d5601b0c9f
No known key found for this signature in database
GPG Key ID: 78464DB0A7837F89
19 changed files with 317 additions and 182 deletions

View File

@ -71,6 +71,7 @@ use pocketmine\inventory\StonecutterShapelessRecipe;
use pocketmine\item\Item;
use pocketmine\level\format\FullChunk;
use pocketmine\level\format\LevelProvider;
use pocketmine\level\generator\biome\Biome;
use pocketmine\level\Level;
use pocketmine\level\Location;
use pocketmine\level\Position;
@ -619,8 +620,7 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
$Z = null;
Level::getXZ($index, $X, $Z);
if(!$this->level->isChunkPopulated($X, $Z)){
$this->level->generateChunk($X, $Z);
if(!$this->level->populateChunk($X, $Z)){
if($this->spawned){
continue;
}else{
@ -628,6 +628,7 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
}
}
++$count;
unset($this->loadQueue[$index]);
@ -1251,6 +1252,8 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
$this->entityBaseTick(1);
if($currentTick % 80 === 0) $this->sendMessage(TextFormat::ITALIC . TextFormat::GRAY . "Y: ".round($this->y)."; biome: ". Biome::getBiome($this->level->getBiomeId((int) $this->x, (int) $this->z))->getName());
if($this->speed and $this->isSurvival()){
$speed = sqrt($this->speed->x ** 2 + $this->speed->z ** 2);
if($speed > 0.45){

View File

@ -21,6 +21,8 @@
namespace pocketmine\level;
use pocketmine\level\format\FullChunk;
interface ChunkManager{
/**
* Gets the raw block id.
@ -63,4 +65,26 @@ interface ChunkManager{
* @param int $data 0-15
*/
public function setBlockDataAt($x, $y, $z, $data);
/**
* @param int $chunkX
* @param int $chunkZ
*
* @return FullChunk
*/
public function getChunk($chunkX, $chunkZ);
/**
* @param int $chunkX
* @param int $chunkZ
* @param FullChunk $chunk
*/
public function setChunk($chunkX, $chunkZ, FullChunk $chunk);
/**
* Gets the level seed
*
* @return int
*/
public function getSeed();
}

View File

@ -93,6 +93,7 @@ use pocketmine\tile\Tile;
use pocketmine\utils\Cache;
use pocketmine\utils\LevelException;
use pocketmine\utils\MainLogger;
use pocketmine\utils\Random;
use pocketmine\utils\ReversePriorityQueue;
use pocketmine\utils\TextFormat;
use pocketmine\level\particle\Particle;
@ -191,6 +192,8 @@ class Level implements ChunkManager, Metadatable{
protected $chunkTickRadius;
protected $chunkTickList = [];
protected $chunksPerTick;
protected $chunksPopulatedPerTick;
protected $chunksPopulated = 0;
protected $clearChunksOnTick;
protected $randomTickBlocks = [
Block::GRASS => Grass::class,
@ -219,7 +222,10 @@ class Level implements ChunkManager, Metadatable{
/** @var LevelTimings */
public $timings;
/** @var Generator */
protected $generator;
/** @var Generator */
protected $generatorInstance;
/**
* Returns the chunk unique hash/key
@ -298,6 +304,7 @@ class Level implements ChunkManager, Metadatable{
$this->chunkTickRadius = min($this->server->getViewDistance(), max(1, (int) $this->server->getProperty("chunk-ticking.tick-radius", 4)));
$this->chunksPerTick = (int) $this->server->getProperty("chunk-ticking.per-tick", 260);
$this->chunksPopulatedPerTick = (int) $this->server->getProperty("chunk-generation.populations-per-tick", 1);
$this->chunkTickList = [];
$this->clearChunksOnTick = (bool) $this->server->getProperty("chunk-ticking.clear-tick-list", false);
@ -308,6 +315,9 @@ class Level implements ChunkManager, Metadatable{
public function initLevel(){
$this->server->getGenerationManager()->openLevel($this, $this->generator, $this->provider->getGeneratorOptions());
$generator = $this->generator;
$this->generatorInstance = new $generator($this->provider->getGeneratorOptions());
$this->generatorInstance->init($this, new Random($this->getSeed()));
}
/**
@ -592,6 +602,8 @@ class Level implements ChunkManager, Metadatable{
$this->processChunkRequest();
$this->chunksPopulated = 0;
$this->timings->doTick->stopTiming();
}
@ -2275,6 +2287,32 @@ class Level implements ChunkManager, Metadatable{
}
public function populateChunk($x, $z){
if(!$this->isChunkPopulated($x, $z)){
$populate = true;
for($xx = -1; $xx <= 1; ++$xx){
for($zz = -1; $zz <= 1; ++$zz){
if(!$this->isChunkGenerated($x + $xx, $z + $zz)){
$populate = false;
$this->generateChunk($x + $xx, $z + $zz);
}
}
}
if($this->chunksPopulated < $this->chunksPopulatedPerTick and $populate){
$this->generatorInstance->populateChunk($x, $z);
$chunk = $this->getChunk($x, $z);
$chunk->setPopulated(true);
$this->server->getPluginManager()->callEvent(new ChunkPopulateEvent($chunk));
++$this->chunksPopulated;
return true;
}
return false;
}
return true;
}
public function generateChunk($x, $z){
if(!isset($this->chunkGenerationQueue[$index = Level::chunkHash($x, $z)])){
$this->chunkGenerationQueue[$index] = true;

View File

@ -295,13 +295,9 @@ class McRegion extends BaseLevelProvider{
}
protected function loadRegion($x, $z){
if(isset($this->regions[$index = Level::chunkHash($x, $z)])){
return true;
}
if(!isset($this->regions[$index = Level::chunkHash($x, $z)])){
$this->regions[$index] = new RegionLoader($this, $x, $z);
return true;
}
}
public function close(){

View File

@ -30,6 +30,7 @@ use pocketmine\block\IronOre;
use pocketmine\block\LapisOre;
use pocketmine\block\RedstoneOre;
use pocketmine\item\Item;
use pocketmine\level\ChunkManager;
use pocketmine\level\format\FullChunk;
use pocketmine\level\generator\populator\Ore;
use pocketmine\level\generator\populator\Populator;
@ -37,7 +38,7 @@ use pocketmine\math\Vector3;
use pocketmine\utils\Random;
class Flat extends Generator{
/** @var GenerationChunkManager */
/** @var ChunkManager */
private $level;
/** @var FullChunk */
private $chunk;
@ -135,7 +136,7 @@ class Flat extends Generator{
}
}
public function init(GenerationChunkManager $level, Random $random){
public function init(ChunkManager $level, Random $random){
$this->level = $level;
$this->random = $random;

View File

@ -42,8 +42,6 @@ class GenerationChunkManager implements ChunkManager{
protected $seed;
protected $changes = [];
public function __construct(GenerationManager $manager, $levelID, $seed, $class, array $options){
if(!class_exists($class, true) or !is_subclass_of($class, Generator::class)){
throw new \InvalidStateException("Class $class does not exists or is not a subclass of Noise");
@ -88,33 +86,8 @@ class GenerationChunkManager implements ChunkManager{
return $chunk;
}
/**
* @return FullChunk[]
*/
public function getChangedChunks(){
return $this->changes;
}
public function cleanChangedChunks(){
$this->changes = [];
}
public function cleanChangedChunk($index){
unset($this->changes[$index]);
}
public function doGarbageCollection(){
$count = 0;
foreach($this->chunks as $index => $chunk){
if(!isset($this->changes[$index]) or $chunk->isPopulated()){
unset($this->chunks[$index]);
unset($this->changes[$index]);
++$count;
}
}
return $count;
}
public function generateChunk($chunkX, $chunkZ){
@ -163,7 +136,6 @@ class GenerationChunkManager implements ChunkManager{
try{
$chunk = $this->getChunk($chunkX, $chunkZ);
$chunk->setGenerated(true);
$this->changes[Level::chunkHash($chunkX, $chunkZ)] = $chunk;
}catch(\Exception $e){
}
}
@ -172,7 +144,6 @@ class GenerationChunkManager implements ChunkManager{
try{
$chunk = $this->getChunk($chunkX, $chunkZ);
$chunk->setPopulated(true);
$this->changes[Level::chunkHash($chunkX, $chunkZ)] = $chunk;
}catch(\Exception $e){
}
}
@ -191,10 +162,6 @@ class GenerationChunkManager implements ChunkManager{
*/
public function setChunk($chunkX, $chunkZ, FullChunk $chunk){
$this->chunks[$index = Level::chunkHash($chunkX, $chunkZ)] = $chunk;
$this->changes[$index] = $chunk;
if($chunk->isPopulated()){
//TODO: Queue to be sent
}
}
/**

View File

@ -72,15 +72,10 @@ class GenerationLevelManager extends GenerationManager{
public function generateChunk($levelID, $chunkX, $chunkZ){
if(isset($this->levels[$levelID])){
$this->levels[$levelID]->populateChunk($chunkX, $chunkZ); //Request population directly
$this->levels[$levelID]->generateChunk($chunkX, $chunkZ); //Request population directly
if(isset($this->levels[$levelID])){
foreach($this->levels[$levelID]->getChangedChunks() as $index => $chunk){
$this->sendChunk($levelID, $chunk);
$this->levels[$levelID]->cleanChangedChunk($index);
}
$this->levels[$levelID]->doGarbageCollection();
$this->levels[$levelID]->cleanChangedChunks();
$this->sendChunk($levelID, $this->levels[$levelID]->getChunk($chunkX, $chunkZ));
$this->levels[$levelID]->cleanChangedChunk(Level::chunkHash($chunkX, $chunkZ));
}
}
}

View File

@ -21,6 +21,7 @@
namespace pocketmine\level\generator;
use pocketmine\block\Block;
use pocketmine\level\format\FullChunk;
use pocketmine\level\generator\biome\Biome;
use pocketmine\level\Level;
@ -111,6 +112,7 @@ class GenerationManager{
$this->logger = $logger;
$this->loader = $loader;
$chunkX = $chunkZ = null;
Block::init();
Biome::init();
while($this->shutdown !== true){
@ -130,7 +132,7 @@ class GenerationManager{
$this->readPacket();
}
}catch(\Exception $e){
$this->logger->warning("[Noise Thread] Exception: " . $e->getMessage() . " on file \"" . $e->getFile() . "\" line " . $e->getLine());
$this->logger->warning("[Generation Thread] Exception: " . $e->getMessage() . " on file \"" . $e->getFile() . "\" line " . $e->getLine());
}
}
}
@ -143,17 +145,10 @@ class GenerationManager{
protected function generateChunk($levelID, $chunkX, $chunkZ){
if(isset($this->levels[$levelID])){
$this->levels[$levelID]->populateChunk($chunkX, $chunkZ); //Request population directly
$this->levels[$levelID]->generateChunk($chunkX, $chunkZ);
if(isset($this->levels[$levelID])){
foreach($this->levels[$levelID]->getChangedChunks() as $index => $chunk){
if($chunk->isPopulated()){
$this->sendChunk($levelID, $chunk);
$this->levels[$levelID]->cleanChangedChunk($index);
}
}
$this->levels[$levelID]->doGarbageCollection();
$this->levels[$levelID]->cleanChangedChunks();
$this->sendChunk($levelID, $this->levels[$levelID]->getChunk($chunkX, $chunkZ));
$this->levels[$levelID]->cleanChangedChunk(Level::chunkHash($chunkX, $chunkZ));
}
}
}

View File

@ -24,6 +24,7 @@
*/
namespace pocketmine\level\generator;
use pocketmine\level\ChunkManager;
use pocketmine\level\generator\noise\Noise;
use pocketmine\level\generator\normal\Normal;
use pocketmine\utils\Random;
@ -41,6 +42,11 @@ abstract class Generator{
return false;
}
/**
* @param $name
*
* @return Generator
*/
public static function getGenerator($name){
if(isset(Generator::$list[$name = strtolower($name)])){
return Generator::$list[$name];
@ -229,7 +235,7 @@ abstract class Generator{
public abstract function __construct(array $settings = []);
public abstract function init(GenerationChunkManager $level, Random $random);
public abstract function init(ChunkManager $level, Random $random);
public abstract function generateChunk($chunkX, $chunkZ);

View File

@ -21,6 +21,7 @@
namespace pocketmine\level\generator\biome;
use pocketmine\block\Block;
use pocketmine\level\ChunkManager;
use pocketmine\level\generator\normal\biome\BeachBiome;
use pocketmine\level\generator\normal\biome\DesertBiome;
@ -58,6 +59,11 @@ abstract class Biome{
/** @var Populator[] */
private $populators = [];
private $minElevation;
private $maxElevation;
private $groundCover = [];
protected static function register($id, Biome $biome){
self::$biomes[(int) $id] = $biome;
$biome->setId((int) $id);
@ -116,4 +122,31 @@ abstract class Biome{
}
public abstract function getName();
public function getMinElevation(){
return $this->minElevation;
}
public function getMaxElevation(){
return $this->maxElevation;
}
public function setElevation($min, $max){
$this->minElevation = $min;
$this->maxElevation = $max;
}
/**
* @return Block[]
*/
public function getGroundCover(){
return $this->groundCover;
}
/**
* @param Block[] $covers
*/
public function setGroundCover(array $covers){
$this->groundCover = $covers;
}
}

View File

@ -42,7 +42,7 @@ class BiomeSelector{
public function __construct(Random $random, Biome $fallback){
$this->fallback = $fallback;
$this->temperature = new Simplex($random, 1, 0.004, 0.5, 2);
$this->rainfall = new Simplex($random, 1, 0.004, 0.5, 2);
$this->rainfall = new Simplex($random, 2, 0.004, 0.5, 2);
}
public function addBiome(Biome $biome, $start, $end){
@ -58,8 +58,6 @@ class BiomeSelector{
*/
public function pickBiome($x, $z){
return Biome::getBiome(Biome::PLAINS);
//$temperature = $this->temperature->noise2D($x, $z);
$rainfall = $this->rainfall->noise2D($x, $z);
@ -70,11 +68,15 @@ class BiomeSelector{
}elseif($rainfall > 0.6){
return Biome::getBiome(Biome::BEACH);
}elseif($rainfall > 0.2){
return Biome::getBiome(Biome::PLAINS);
}elseif($rainfall > -0.3){
return Biome::getBiome(Biome::FOREST);
}else{
}elseif($rainfall > -0.3){
return Biome::getBiome(Biome::PLAINS);
}elseif($rainfall > -0.6){
return Biome::getBiome(Biome::DESERT);
}elseif($rainfall > -0.7){
return Biome::getBiome(Biome::BEACH);
}else{
return Biome::getBiome(Biome::OCEAN);
}
}

View File

@ -64,9 +64,9 @@ class Perlin extends Noise{
$y += $this->offsetY;
$z += $this->offsetZ;
$floorX = (int) floor($x);
$floorY = (int) floor($y);
$floorZ = (int) floor($z);
$floorX = (int) $x;
$floorY = (int) $y;
$floorZ = (int) $z;
$X = $floorX & 0xFF;
$Y = $floorY & 0xFF;
@ -77,26 +77,70 @@ class Perlin extends Noise{
$z -= $floorZ;
//Fade curves
$fX = self::fade($x);
$fY = self::fade($y);
$fZ = self::fade($z);
//$fX = self::fade($x);
//$fY = self::fade($y);
//$fZ = self::fade($z);
$fX = $x ** 3 * ($x * ($x * 6 - 15) + 10);
$fY = $y ** 3 * ($y * ($y * 6 - 15) + 10);
$fZ = $z ** 3 * ($z * ($z * 6 - 15) + 10);
//Cube corners
$A = $this->perm[$X] + $Y;
$B = $this->perm[$X + 1] + $Y;
$AA = $this->perm[$A] + $Z;
$AB = $this->perm[$A + 1] + $Z;
$B = $this->perm[$X + 1] + $Y;
$BA = $this->perm[$B] + $Z;
$BB = $this->perm[$B + 1] + $Z;
return self::lerp($fZ, self::lerp($fY, self::lerp($fX, self::grad($this->perm[$AA], $x, $y, $z),
self::grad($this->perm[$BA], $x - 1, $y, $z)),
self::lerp($fX, self::grad($this->perm[$AB], $x, $y - 1, $z),
self::grad($this->perm[$BB], $x - 1, $y - 1, $z))),
self::lerp($fY, self::lerp($fX, self::grad($this->perm[$AA + 1], $x, $y, $z - 1),
self::grad($this->perm[$BA + 1], $x - 1, $y, $z - 1)),
self::lerp($fX, self::grad($this->perm[$AB + 1], $x, $y - 1, $z - 1),
self::grad($this->perm[$BB + 1], $x - 1, $y - 1, $z - 1))));
$AA1 = self::grad($this->perm[$AA], $x, $y, $z);
$BA1 = self::grad($this->perm[$BA], $x - 1, $y, $z);
$AB1 = self::grad($this->perm[$AB], $x, $y - 1, $z);
$BB1 = self::grad($this->perm[$BB], $x - 1, $y - 1, $z);
$AA2 = self::grad($this->perm[$AA + 1], $x, $y, $z - 1);
$BA2 = self::grad($this->perm[$BA + 1], $x - 1, $y, $z - 1);
$AB2 = self::grad($this->perm[$AB + 1], $x, $y - 1, $z - 1);
$BB2 = self::grad($this->perm[$BB + 1], $x - 1, $y - 1, $z - 1);
$xLerp11 = $AA1 + $fX * ($BA1 - $AA1);
$zLerp1 = $xLerp11 + $fY * ($AB1 + $fX * ($BB1 - $AB1) - $xLerp11);
$xLerp21 = $AA2 + $fX * ($BA2 - $AA2);
return $zLerp1 + $fZ * ($xLerp21 + $fY * ($AB2 + $fX * ($BB2 - $AB2) - $xLerp21) - $zLerp1);
/*
return self::lerp(
$fZ,
self::lerp(
$fY,
self::lerp(
$fX,
self::grad($this->perm[$AA], $x, $y, $z),
self::grad($this->perm[$BA], $x - 1, $y, $z)
),
self::lerp(
$fX,
self::grad($this->perm[$AB], $x, $y - 1, $z),
self::grad($this->perm[$BB], $x - 1, $y - 1, $z)
)
),
self::lerp(
$fY,
self::lerp(
$fX,
self::grad($this->perm[$AA + 1], $x, $y, $z - 1),
self::grad($this->perm[$BA + 1], $x - 1, $y, $z - 1)
),
self::lerp(
$fX,
self::grad($this->perm[$AB + 1], $x, $y - 1, $z - 1),
self::grad($this->perm[$BB + 1], $x - 1, $y - 1, $z - 1)
)
)
);
*/
}
public function getNoise2D($x, $y){

View File

@ -99,16 +99,14 @@ class Simplex extends Perlin{
// 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) floor($x + $s);
$j = (int) floor($y + $s);
$k = (int) floor($z + $s);
$i = (int) ($x + $s);
$j = (int) ($y + $s);
$k = (int) ($z + $s);
$t = ($i + $j + $k) * self::$G3;
$X0 = $i - $t; // Unskew the cell origin back to (x,y,z) space
$Y0 = $j - $t;
$Z0 = $k - $t;
$x0 = $x - $X0; // The x,y,z distances from the cell origin
$y0 = $y - $Y0;
$z0 = $z - $Z0;
// 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.
@ -185,47 +183,37 @@ class Simplex extends Perlin{
$ii = $i & 255;
$jj = $j & 255;
$kk = $k & 255;
$gi0 = $this->perm[$ii + $this->perm[$jj + $this->perm[$kk]]] % 12;
$gi1 = $this->perm[$ii + $i1 + $this->perm[$jj + $j1 + $this->perm[$kk + $k1]]] % 12;
$gi2 = $this->perm[$ii + $i2 + $this->perm[$jj + $j2 + $this->perm[$kk + $k2]]] % 12;
$gi3 = $this->perm[$ii + 1 + $this->perm[$jj + 1 + $this->perm[$kk + 1]]] % 12;
$n = 0;
// Calculate the contribution from the four corners
$t0 = 0.6 - $x0 ** 2 - $y0 ** 2 - $z0 ** 2;
if($t0 < 0){
$n0 = 0.0;
}else{
$t0 **= 2;
$n0 = $t0 ** 2 * self::dot3D(self::$grad3[$gi0], $x0, $y0, $z0);
if($t0 > 0){
$gi0 = self::$grad3[$this->perm[$ii + $this->perm[$jj + $this->perm[$kk]]] % 12];
$n += $t0 ** 4 * ($gi0[0] * $x0 + $gi0[1] * $y0 + $gi0[2] * $z0);
}
$t1 = 0.6 - $x1 ** 2 - $y1 ** 2 - $z1 ** 2;
if($t1 < 0){
$n1 = 0.0;
}else{
$t1 **= 2;
$n1 = $t1 ** 2 * self::dot3D(self::$grad3[$gi1], $x1, $y1, $z1);
if($t1 > 0){
$gi1 = self::$grad3[$this->perm[$ii + $i1 + $this->perm[$jj + $j1 + $this->perm[$kk + $k1]]] % 12];
$n += $t1 ** 4 * ($gi1[0] * $x1 + $gi1[1] * $y1 + $gi1[2] * $z1);
}
$t2 = 0.6 - $x2 ** 2 - $y2 ** 2 - $z2 ** 2;
if($t2 < 0){
$n2 = 0.0;
}else{
$t2 **= 2;
$n2 = $t2 ** 2 * self::dot3D(self::$grad3[$gi2], $x2, $y2, $z2);
if($t2 > 0){
$gi2 = self::$grad3[$this->perm[$ii + $i2 + $this->perm[$jj + $j2 + $this->perm[$kk + $k2]]] % 12];
$n += $t2 ** 4 * ($gi2[0] * $x2 + $gi2[1] * $y2 + $gi2[2] * $z2);
}
$t3 = 0.6 - $x3 ** 2 - $y3 ** 2 - $z3 ** 2;
if($t3 < 0){
$n3 = 0.0;
}else{
$t3 **= 2;
$n3 = $t3 ** 2 * self::dot3D(self::$grad3[$gi3], $x3, $y3, $z3);
if($t3 > 0){
$gi3 = self::$grad3[$this->perm[$ii + 1 + $this->perm[$jj + 1 + $this->perm[$kk + 1]]] % 12];
$n += $t3 ** 4 * ($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 * ($n0 + $n1 + $n2 + $n3);
return 32.0 * $n;
}
public function getNoise2D($x, $y){
@ -234,13 +222,12 @@ class Simplex extends Perlin{
// Skew the input space to determine which simplex cell we're in
$s = ($x + $y) * self::$F2; // Hairy factor for 2D
$i = (int) floor($x + $s);
$j = (int) floor($y + $s);
$i = (int) ($x + $s);
$j = (int) ($y + $s);
$t = ($i + $j) * self::$G2;
$X0 = $i - $t; // Unskew the cell origin back to (x,y) space
$Y0 = $j - $t;
$x0 = $x - $X0; // The x,y distances from the cell origin
$y0 = $y - $Y0;
// 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.
@ -267,26 +254,26 @@ class Simplex extends Perlin{
// Work out the hashed gradient indices of the three simplex corners
$ii = $i & 255;
$jj = $j & 255;
$gi0 = $this->perm[$ii + $this->perm[$jj]] % 12;
$gi1 = $this->perm[$ii + $i1 + $this->perm[$jj + $j1]] % 12;
$gi2 = $this->perm[$ii + 1 + $this->perm[$jj + 1]] % 12;
$n = 0;
// Calculate the contribution from the three corners
$t = 0.5 - $x0 ** 2 - $y0 ** 2;
if($t > 0){
$n += $t ** 4 * self::dot2D(self::$grad3[$gi0], $x0, $y0); // (x,y) of grad3 used for 2D gradient
$t0 = 0.5 - $x0 ** 2 - $y0 ** 2;
if($t0 > 0){
$gi0 = self::$grad3[$this->perm[$ii + $this->perm[$jj]] % 12];
$n += $t0 ** 4 * ($gi0[0] * $x0 + $gi0[1] * $y0); // (x,y) of grad3 used for 2D gradient
}
$t = 0.5 - $x1 ** 2 - $y1 ** 2;
if($t > 0){
$n += $t ** 4 * self::dot2D(self::$grad3[$gi1], $x1, $y1);
$t1 = 0.5 - $x1 ** 2 - $y1 ** 2;
if($t1 > 0){
$gi1 = self::$grad3[$this->perm[$ii + $i1 + $this->perm[$jj + $j1]] % 12];
$n += $t1 ** 4 * ($gi1[0] * $x1 + $gi1[1] * $y1);
}
$t = 0.5 - $x2 ** 2 - $y2 ** 2;
if($t > 0){
$n += $t ** 4 * self::dot2D(self::$grad3[$gi2], $x2, $y2);
$t2 = 0.5 - $x2 ** 2 - $y2 ** 2;
if($t2 > 0){
$gi2 = self::$grad3[$this->perm[$ii + 1 + $this->perm[$jj + 1]] % 12];
$n += $t2 ** 4 * ($gi2[0] * $x2 + $gi2[1] * $y2);
}
// Add contributions from each corner to get the noise value.

View File

@ -30,14 +30,17 @@ 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\biome\BiomeSelector;
use pocketmine\level\generator\GenerationChunkManager;
use pocketmine\level\generator\GenerationManager;
use pocketmine\level\generator\Generator;
use pocketmine\level\generator\noise\Perlin;
use pocketmine\level\generator\noise\Simplex;
use pocketmine\level\generator\normal\biome\NormalBiome;
use pocketmine\level\generator\object\OreType;
use pocketmine\level\generator\populator\GroundCover;
use pocketmine\level\generator\populator\Ore;
use pocketmine\level\generator\populator\Populator;
use pocketmine\level\generator\populator\TallGrass;
@ -50,12 +53,15 @@ class Normal extends Generator{
/** @var Populator[] */
private $populators = [];
/** @var GenerationChunkManager */
/** @var ChunkManager */
private $level;
/** @var Random */
private $random;
private $waterHeight = 62;
private $bedrockDepth = 5;
/** @var Populator[] */
private $generationPopulators = [];
/** @var Simplex */
private $noiseBase;
@ -92,7 +98,7 @@ class Normal extends Generator{
return [];
}
public function init(GenerationChunkManager $level, Random $random){
public function init(ChunkManager $level, Random $random){
$this->level = $level;
$this->random = $random;
$this->random->setSeed($this->level->getSeed());
@ -100,6 +106,9 @@ class Normal extends Generator{
$this->random->setSeed($this->level->getSeed());
$this->selector = new BiomeSelector($this->random, Biome::getBiome(Biome::OCEAN));
$cover = new GroundCover();
$this->generationPopulators[] = $cover;
$ores = new Ore();
$ores->setOreTypes([
@ -113,16 +122,6 @@ class Normal extends Generator{
new OreType(new Gravel(), 10, 16, 0, 128),
]);
$this->populators[] = $ores;
$trees = new Tree();
$trees->setBaseAmount(1);
$trees->setRandomAmount(1);
$this->populators[] = $trees;
$tallGrass = new TallGrass();
$tallGrass->setBaseAmount(5);
$tallGrass->setRandomAmount(0);
$this->populators[] = $tallGrass;
}
public function generateChunk($chunkX, $chunkZ){
@ -132,21 +131,22 @@ class Normal extends Generator{
$chunk = $this->level->getChunk($chunkX, $chunkZ);
$biomeCache = [];
for($x = 0; $x < 16; ++$x){
for($z = 0; $z < 16; ++$z){
$minSum = 0;
$maxSum = 0;
$weightSum = 0;
$biome = $this->selector->pickBiome($chunkX * 16 + $x, $chunkZ * 16 + $z);
$chunk->setBiomeId($x, $z, $biome->getId());
$chunk->setBiomeColor($x, $z, 255 - (($biome->getId() * 1377) % 255), 255 - (($biome->getId() * 4096) % 255), 255 - (($biome->getId() * 31337) % 255));
for($sx = -self::$SMOOTH_SIZE; $sx <= self::$SMOOTH_SIZE; ++$sx){
for($sz = -self::$SMOOTH_SIZE; $sz <= self::$SMOOTH_SIZE; ++$sz){
if(isset($biomeCache[$index = (($chunkX * 16 + $x + $sx * 16) >> 2) . ":" . (($chunkZ * 16 + $z + $sz * 16) >> 2)])){
$adjacent = $biomeCache[$index];
if($sx === 0 and $sz === 0){
$adjacent = $biome;
}else{
$adjacent = $this->selector->pickBiome($chunkX * 16 + $x + $sx * 16, $chunkZ * 16 + $z + $sz * 16);
$biomeCache[$index] = $adjacent;
}
/** @var NormalBiome $adjacent */
$weight = self::$GAUSSIAN_KERNEL[$sx + self::$SMOOTH_SIZE][$sz + self::$SMOOTH_SIZE];
@ -182,14 +182,21 @@ class Normal extends Generator{
}
}
}
foreach($this->generationPopulators as $populator){
$populator->populate($this->level, $chunkX, $chunkZ, $this->random);
}
}
public function populateChunk($chunkX, $chunkZ){
$this->random->setSeed(0xdeadbeef ^ ($chunkX << 8) ^ $chunkZ ^ $this->level->getSeed());
foreach($this->populators as $populator){
$this->random->setSeed(0xdeadbeef ^ ($chunkX << 8) ^ $chunkZ ^ $this->level->getSeed());
$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);
}
public function getSpawn(){

View File

@ -21,11 +21,12 @@
namespace pocketmine\level\generator\normal\biome;
class DesertBiome extends GrassyBiome{
use pocketmine\block\Block;
class DesertBiome extends SandyBiome{
public function __construct(){
parent::__construct();
$this->setElevation(63, 74);
}

View File

@ -25,29 +25,4 @@ use pocketmine\level\generator\biome\Biome;
abstract class NormalBiome extends Biome{
private $minElevation;
private $maxElevation;
private $groundCover = [];
public function getMinElevation(){
return $this->minElevation;
}
public function getMaxElevation(){
return $this->maxElevation;
}
public function setElevation($min, $max){
$this->minElevation = $min;
$this->maxElevation = $max;
}
public function getGroundCover(){
return $this->groundCover;
}
public function setGroundCover(array $covers){
$this->groundCover = $covers;
}
}

View File

@ -27,6 +27,7 @@ abstract class SandyBiome extends NormalBiome{
public function __construct(){
$this->setGroundCover([
Block::get(Block::SAND, 0),
Block::get(Block::SAND, 0),
Block::get(Block::SANDSTONE, 0),
Block::get(Block::SANDSTONE, 0),

View File

@ -0,0 +1,58 @@
<?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/
*
*
*/
namespace pocketmine\level\generator\populator;
use pocketmine\block\Block;
use pocketmine\level\ChunkManager;
use pocketmine\level\generator\biome\Biome;
use pocketmine\utils\Random;
class GroundCover extends Populator{
public function populate(ChunkManager $level, $chunkX, $chunkZ, Random $random){
$chunk = $level->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){
$column = $chunk->getBlockIdColumn($x, $z);
for($y = 127; $y > 0; --$y){
if($column{$y} !== "\x00" and Block::get(ord($column{$y}))->isSolid()){
break;
}
}
$startY = $y;
$endY = $startY - count($cover);
for($y = $startY; $y > $endY and $y >= 0; --$y){
$b = $cover[$startY - $y];
if($b->getDamage() === 0){
$chunk->setBlockId($x, $y, $z, $b->getId());
}else{
$chunk->setBlock($x, $y, $z, $b->getId(), $b->getDamage());
}
}
}
}
}
}
}

View File

@ -55,6 +55,8 @@ chunk-generation:
use-async: true
#Max. amount of chunks to generate per tick, only for use-async: false
per-tick: 1
#Max. amount of chunks to populate per tick
populations-per-tick: 1
chunk-gc:
period-in-ticks: 600