World generation with biomes!

This commit is contained in:
Shoghi Cervantes 2015-03-22 22:57:40 +01:00
parent 1666602652
commit 9da26fdb88
No known key found for this signature in database
GPG Key ID: 78464DB0A7837F89
23 changed files with 404 additions and 104 deletions

View File

@ -616,7 +616,7 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
$Z = null;
Level::getXZ($index, $X, $Z);
if(!$this->level->populateChunk($X, $Z)){
if(!$this->level->populateChunk($X, $Z, !$this->spawned or count($this->usedChunks) < ($this->viewDistance - 24))){
if($this->spawned){
continue;
}else{

View File

@ -583,15 +583,15 @@ class Level implements ChunkManager, Metadatable{
$this->timings->doTickTiles->stopTiming();
if(count($this->changedBlocks) > 0){
if(count($this->players) > 0){
if(count($this->players) > 5){
foreach($this->changedBlocks as $index => $blocks){
if(count($blocks) > 512){
Level::getXZ($index, $X, $Z);
if(count($blocks) > 512){
foreach($this->getUsingChunk($X, $Z) as $p){
$p->unloadChunk($X, $Z);
}
}else{
$this->sendBlocks($this->getUsingChunk($pos->x >> 4, $pos->z >> 4), $blocks);
$this->sendBlocks($this->getUsingChunk($X, $Z), $blocks);
}
}
}
@ -1821,15 +1821,19 @@ class Level implements ChunkManager, Metadatable{
}
public function generateChunkCallback($x, $z, FullChunk $chunk){
Timings::$generationTimer->startTiming();
if(isset($this->chunkGenerationQueue[$index = Level::chunkHash($x, $z)])){
$oldChunk = $this->getChunk($x, $z, false);
unset($this->chunkGenerationQueue[Level::chunkHash($x, $z)]);
unset($this->chunkGenerationQueue[$index = Level::chunkHash($x, $z)]);
$chunk->setProvider($this->provider);
$this->setChunk($x, $z, $chunk);
$chunk = $this->getChunk($x, $z, false);
if($chunk !== null and ($oldChunk === null or $oldChunk->isPopulated() === false) and $chunk->isPopulated()){
if($chunk !== null and ($oldChunk === null or $oldChunk->isPopulated() === false) and $chunk->isPopulated() and $chunk->getProvider() !== null){
$this->server->getPluginManager()->callEvent(new ChunkPopulateEvent($chunk));
}
}
Timings::$generationTimer->stopTiming();
}
public function setChunk($x, $z, FullChunk $chunk, $unload = true){
$index = Level::chunkHash($x, $z);
@ -2079,7 +2083,12 @@ class Level implements ChunkManager, Metadatable{
}
}
if($chunk->getProvider() !== null){
$this->server->getPluginManager()->callEvent(new ChunkLoadEvent($chunk, !$chunk->isGenerated()));
}else{
$this->unloadChunk($x, $z, false);
return false;
}
return true;
}
@ -2114,7 +2123,7 @@ class Level implements ChunkManager, Metadatable{
$chunk = $this->getChunk($x, $z);
if($chunk !== null){
if($chunk !== null and $chunk->getProvider() !== null){
$this->server->getPluginManager()->callEvent($ev = new ChunkUnloadEvent($chunk));
if($ev->isCancelled()){
return false;
@ -2291,24 +2300,30 @@ class Level implements ChunkManager, Metadatable{
}
public function populateChunk($x, $z){
public function populateChunk($x, $z, $force = false){
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);
$this->generateChunk($x + $xx, $z + $zz, $force);
}
}
}
if($this->chunksPopulated < $this->chunksPopulatedPerTick and $populate){
Timings::$generationTimer->startTiming();
$this->generatorInstance->populateChunk($x, $z);
$chunk = $this->getChunk($x, $z);
$chunk->setPopulated(true);
if($chunk->getProvider() !== null){
$this->server->getPluginManager()->callEvent(new ChunkPopulateEvent($chunk));
}else{
$this->unloadChunk($x, $z, false);
}
++$this->chunksPopulated;
Timings::$generationTimer->stopTiming();
return true;
}
@ -2317,12 +2332,17 @@ class Level implements ChunkManager, Metadatable{
return true;
}
public function generateChunk($x, $z){
public function generateChunk($x, $z, $force = false){
if(!isset($this->chunkGenerationQueue[$index = Level::chunkHash($x, $z)])){
$this->chunkGenerationQueue[$index] = true;
$this->chunkGenerationQueue[$index] = 0;
$this->server->getGenerationManager()->requestChunk($this, $x, $z, $this->getChunk($x, $z, true));
}elseif($force){
$value = ++$this->chunkGenerationQueue[$index];
if($value % 40 === 0){
$this->server->getGenerationManager()->requestChunk($this, $x, $z);
}
}
}
public function regenerateChunk($x, $z){
$this->unloadChunk($x, $z, false);

View File

@ -177,8 +177,9 @@ class GenerationManager{
if($this->needsChunk[$levelID][0] === $chunk->getX() and $this->needsChunk[$levelID][1] === $chunk->getZ()){
$this->needsChunk[$levelID] = $chunk;
}
}elseif(isset($this->levels[$levelID])){
$this->levels[$levelID]->setChunk($chunk->getX(), $chunk->getZ(), $chunk);
}
//TODO: set new received chunks
}
/**

View File

@ -74,9 +74,12 @@ class GenerationRequestManager{
$this->generationThread->pushMainToThreadPacket($buffer);
}
public function requestChunk(Level $level, $chunkX, $chunkZ){
public function requestChunk(Level $level, $chunkX, $chunkZ, FullChunk $chunk = null){
$buffer = chr(GenerationManager::PACKET_REQUEST_CHUNK) . Binary::writeInt($level->getId()) . Binary::writeInt($chunkX) . Binary::writeInt($chunkZ);
$this->generationThread->pushMainToThreadPacket($buffer);
if($chunk !== null){
$this->sendChunk($level->getId(), $chunk);
}
}
protected function handleRequest($levelID, $chunkX, $chunkZ){

View File

@ -23,14 +23,16 @@ 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\SwampBiome;
use pocketmine\level\generator\normal\biome\DesertBiome;
use pocketmine\level\generator\normal\biome\ForestBiome;
use pocketmine\level\generator\normal\biome\IcePlainsBiome;
use pocketmine\level\generator\normal\biome\MountainsBiome;
use pocketmine\level\generator\normal\biome\OceanBiome;
use pocketmine\level\generator\normal\biome\PlainBiome;
use pocketmine\level\generator\normal\biome\RiverBiome;
use pocketmine\level\generator\normal\biome\SmallMountainsBiome;
use pocketmine\level\generator\normal\biome\TaigaBiome;
use pocketmine\level\generator\populator\Populator;
use pocketmine\utils\Random;
@ -41,14 +43,19 @@ abstract class Biome{
const DESERT = 2;
const MOUNTAINS = 3;
const FOREST = 4;
const TAIGA = 5;
const SWAMP = 6;
const RIVER = 7;
const BEACH = 16;
const ICE_PLAINS = 12;
const SMALL_MOUNTAINS = 20;
const BIRCH_FOREST = 27;
const MAX_BIOMES = 256;
/** @var Biome[] */
@ -64,6 +71,9 @@ abstract class Biome{
private $groundCover = [];
protected $rainfall = 0.5;
protected $temperature = 0.5;
protected static function register($id, Biome $biome){
self::$biomes[(int) $id] = $biome;
$biome->setId((int) $id);
@ -75,12 +85,17 @@ abstract class Biome{
self::register(self::DESERT, new DesertBiome());
self::register(self::MOUNTAINS, new MountainsBiome());
self::register(self::FOREST, new ForestBiome());
self::register(self::TAIGA, new TaigaBiome());
self::register(self::RIVER, new RiverBiome());
self::register(self::BEACH, new BeachBiome());
self::register(self::ICE_PLAINS, new IcePlainsBiome());
self::register(self::SWAMP, new SwampBiome());
self::register(self::SMALL_MOUNTAINS, new SmallMountainsBiome());
self::register(self::BIRCH_FOREST, new ForestBiome(ForestBiome::TYPE_BIRCH));
}
/**
@ -89,7 +104,7 @@ abstract class Biome{
* @return Biome
*/
public static function getBiome($id){
return isset(self::$biomes[$id]) ? self::$biomes[$id] : null;
return isset(self::$biomes[$id]) ? self::$biomes[$id] : self::$biomes[self::OCEAN];
}
public function clearPopulators(){
@ -149,4 +164,18 @@ abstract class Biome{
public function setGroundCover(array $covers){
$this->groundCover = $covers;
}
public function getTemperature(){
return $this->temperature;
}
public function getRainfall(){
return $this->rainfall;
}
/**
* @return int (randomness|Red|Green|Blue)
*/
abstract public function getColor();
}

View File

@ -37,17 +37,37 @@ class BiomeSelector{
/** @var Biome[] */
private $biomes = [];
private $select = [];
private $map = [];
public function __construct(Random $random, Biome $fallback){
private $lookup;
public function __construct(Random $random, callable $lookup, Biome $fallback){
$this->fallback = $fallback;
$this->temperature = new Simplex($random, 1, 0.004, 0.5, 2);
$this->rainfall = new Simplex($random, 2, 0.004, 0.5, 2);
$this->lookup = $lookup;
$this->temperature = new Simplex($random, 1, 0.001, 1, 1);
$this->rainfall = new Simplex($random, 1, 0.001, 1, 1);
}
public function addBiome(Biome $biome, $start, $end){
public function recalculate(){
$this->map = new \SplFixedArray(64 * 64);
for($i = 0; $i < 64; ++$i){
for($j = 0; $j < 64; ++$j){
$this->map[$i + ($j << 6)] = call_user_func($this->lookup, $i / 63, $j / 63);
}
}
}
public function addBiome(Biome $biome){
$this->biomes[$biome->getId()] = $biome;
$this->select[$biome->getId()] = [$biome->getId(), $start, $end];
}
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;
}
/**
@ -57,27 +77,10 @@ class BiomeSelector{
* @return Biome
*/
public function pickBiome($x, $z){
$temperature = (int) ($this->getTemperature($x, $z) * 63);
$rainfall = (int) ($this->getRainfall($x, $z) * 63);
//$temperature = $this->temperature->noise2D($x, $z);
$rainfall = $this->rainfall->noise2D($x, $z);
if($rainfall > 0.9){
return Biome::getBiome(Biome::OCEAN);
}elseif($rainfall > 0.7){
return Biome::getBiome(Biome::RIVER);
}elseif($rainfall > 0.6){
return Biome::getBiome(Biome::BEACH);
}elseif($rainfall > 0.2){
return Biome::getBiome(Biome::FOREST);
}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);
}
$biomeId = $this->map[$temperature + ($rainfall << 6)];
return isset($this->biomes[$biomeId]) ? $this->biomes[$biomeId] : $this->fallback;
}
}

View File

@ -83,9 +83,7 @@ class Normal extends Generator{
$bellHeight = 2 * self::$SMOOTH_SIZE;
for($sx = -self::$SMOOTH_SIZE; $sx <= self::$SMOOTH_SIZE; ++$sx){
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);
self::$GAUSSIAN_KERNEL[$sx + self::$SMOOTH_SIZE][$sz + self::$SMOOTH_SIZE] = 10 / sqrt($sx ** 2 + $sz ** 2 + 0.2);
}
}
}
@ -102,9 +100,54 @@ class Normal extends Generator{
$this->level = $level;
$this->random = $random;
$this->random->setSeed($this->level->getSeed());
$this->noiseBase = new Simplex($this->random, 16, 0.012, 0.5, 2);
$this->noiseBase = new Simplex($this->random, 16, 0.02, 0.5, 2);
$this->random->setSeed($this->level->getSeed());
$this->selector = new BiomeSelector($this->random, Biome::getBiome(Biome::OCEAN));
$this->selector = new BiomeSelector($this->random, function($temperature, $rainfall){
$rainfall *= $temperature;
if($temperature < 0.10){
return Biome::ICE_PLAINS;
}elseif($rainfall < 0.20){
if($temperature < 0.50){
return Biome::ICE_PLAINS;
}elseif($temperature < 0.95){
return Biome::SMALL_MOUNTAINS;
}else{
return Biome::DESERT;
}
}elseif($rainfall > 0.5 and $temperature < 0.7){
return Biome::SWAMP;
}elseif($temperature < 0.50){
return Biome::TAIGA;
}elseif($temperature < 0.97){
if($rainfall < 0.35){
return Biome::MOUNTAINS;
}else {
return Biome::RIVER;
}
}else{
if($rainfall < 0.45){
return Biome::PLAINS;
}elseif($rainfall < 0.90){
return Biome::FOREST;
}else{
return Biome::BIRCH_FOREST;
}
}
}, Biome::getBiome(Biome::OCEAN));
$this->selector->addBiome(Biome::getBiome(Biome::OCEAN));
$this->selector->addBiome(Biome::getBiome(Biome::PLAINS));
$this->selector->addBiome(Biome::getBiome(Biome::DESERT));
$this->selector->addBiome(Biome::getBiome(Biome::MOUNTAINS));
$this->selector->addBiome(Biome::getBiome(Biome::FOREST));
$this->selector->addBiome(Biome::getBiome(Biome::TAIGA));
$this->selector->addBiome(Biome::getBiome(Biome::SWAMP));
$this->selector->addBiome(Biome::getBiome(Biome::RIVER));
$this->selector->addBiome(Biome::getBiome(Biome::ICE_PLAINS));
$this->selector->addBiome(Biome::getBiome(Biome::SMALL_MOUNTAINS));
$this->selector->addBiome(Biome::getBiome(Biome::BIRCH_FOREST));
$this->selector->recalculate();
$cover = new GroundCover();
$this->generationPopulators[] = $cover;
@ -127,7 +170,7 @@ class Normal extends Generator{
public function generateChunk($chunkX, $chunkZ){
$this->random->setSeed(0xdeadbeef ^ ($chunkX << 8) ^ $chunkZ ^ $this->level->getSeed());
$noise = Generator::getFastNoise3D($this->noiseBase, 16, 128, 16, 8, 8, 8, $chunkX * 16, 0, $chunkZ * 16);
$noise = Generator::getFastNoise3D($this->noiseBase, 16, 128, 16, 4, 8, 4, $chunkX * 16, 0, $chunkZ * 16);
$chunk = $this->level->getChunk($chunkX, $chunkZ);
@ -139,16 +182,16 @@ class Normal extends Generator{
$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));
$color = $biome->getColor();
$chunk->setBiomeColor($x, $z, $color >> 16, ($color >> 8) & 0xff, $color & 0xff);
for($sx = -self::$SMOOTH_SIZE; $sx <= self::$SMOOTH_SIZE; ++$sx){
for($sz = -self::$SMOOTH_SIZE; $sz <= self::$SMOOTH_SIZE; ++$sz){
if($sx === 0 and $sz === 0){
$adjacent = $biome;
continue;
}else{
$adjacent = $this->selector->pickBiome($chunkX * 16 + $x + $sx * 16, $chunkZ * 16 + $z + $sz * 16);
$adjacent = $this->selector->pickBiome($chunkX * 16 + $x + $sx * 8, $chunkZ * 16 + $z + $sz * 8);
}
/** @var NormalBiome $adjacent */
$weight = self::$GAUSSIAN_KERNEL[$sx + self::$SMOOTH_SIZE][$sz + self::$SMOOTH_SIZE];
$minSum += $adjacent->getMinElevation() * $weight;
$maxSum += $adjacent->getMaxElevation() * $weight;

View File

@ -28,6 +28,9 @@ class DesertBiome extends SandyBiome{
public function __construct(){
parent::__construct();
$this->setElevation(63, 74);
$this->temperature = 2;
$this->rainfall = 0;
}
public function getName(){

View File

@ -21,15 +21,23 @@
namespace pocketmine\level\generator\normal\biome;
use pocketmine\block\Sapling;
use pocketmine\level\generator\populator\TallGrass;
use pocketmine\level\generator\populator\Tree;
class ForestBiome extends GrassyBiome{
public function __construct(){
const TYPE_NORMAL = 0;
const TYPE_BIRCH = 1;
public $type;
public function __construct($type = self::TYPE_NORMAL){
parent::__construct();
$trees = new Tree();
$this->type = $type;
$trees = new Tree($type === self::TYPE_BIRCH ? Sapling::BIRCH : Sapling::OAK);
$trees->setBaseAmount(5);
$this->addPopulator($trees);
@ -39,9 +47,21 @@ class ForestBiome extends GrassyBiome{
$this->addPopulator($tallGrass);
$this->setElevation(63, 81);
if($type === self::TYPE_BIRCH){
$this->temperature = 0.5;
$this->rainfall = 0.5;
}else{
$this->temperature = 0.7;
$this->temperature = 0.8;
}
}
public function getName(){
return "Forest";
return $this->type === self::TYPE_BIRCH ? "Birch Forest" : "Forest";
}
public function getColor(){
return 0x056621;
}
}

View File

@ -0,0 +1,49 @@
<?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\normal\biome;
use pocketmine\level\generator\populator\TallGrass;
class IcePlainsBiome extends SnowyBiome{
public function __construct(){
parent::__construct();
$tallGrass = new TallGrass();
$tallGrass->setBaseAmount(5);
$this->addPopulator($tallGrass);
$this->setElevation(63, 74);
$this->temperature = 0.05;
$this->rainfall = 0.8;
}
public function getName(){
return "Ice Plains";
}
public function getColor(){
return 0x163933;
}
}

View File

@ -41,6 +41,9 @@ class MountainsBiome extends GrassyBiome{
//TODO: add emerald
$this->setElevation(63, 127);
$this->temperature = 0.4;
$this->rainfall = 0.5;
}
public function getName(){

View File

@ -24,5 +24,7 @@ namespace pocketmine\level\generator\normal\biome;
use pocketmine\level\generator\biome\Biome;
abstract class NormalBiome extends Biome{
public function getColor(){
return 0xffb360; //Detect wrong biomes
}
}

View File

@ -34,9 +34,16 @@ class OceanBiome extends GrassyBiome{
$this->addPopulator($tallGrass);
$this->setElevation(46, 58);
$this->temperature = 0.5;
$this->rainfall = 0.5;
}
public function getName(){
return "Ocean";
}
public function getColor(){
return 0x8da360;
}
}

View File

@ -29,14 +29,21 @@ class PlainBiome extends GrassyBiome{
parent::__construct();
$tallGrass = new TallGrass();
$tallGrass->setBaseAmount(5);
$tallGrass->setBaseAmount(12);
$this->addPopulator($tallGrass);
$this->setElevation(63, 74);
$this->temperature = 0.8;
$this->rainfall = 0.4;
}
public function getName(){
return "Plains";
}
public function getColor(){
return 0x8db360;
}
}

View File

@ -34,9 +34,16 @@ class RiverBiome extends GrassyBiome{
$this->addPopulator($tallGrass);
$this->setElevation(58, 62);
$this->temperature = 0.5;
$this->rainfall = 0.7;
}
public function getName(){
return "River";
}
public function getColor(){
return 0x8dc360;
}
}

View File

@ -0,0 +1,37 @@
<?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\normal\biome;
use pocketmine\block\Block;
abstract class SnowyBiome extends NormalBiome{
public function __construct(){
$this->setGroundCover([
Block::get(Block::SNOW_LAYER, 0),
Block::get(Block::GRASS, 0),
Block::get(Block::DIRT, 0),
Block::get(Block::DIRT, 0),
Block::get(Block::DIRT, 0),
]);
}
}

View File

@ -21,15 +21,22 @@
namespace pocketmine\level\generator\normal\biome;
class BeachBiome extends GrassyBiome{
class SwampBiome extends GrassyBiome{
public function __construct(){
parent::__construct();
$this->setElevation(62, 65);
$this->setElevation(62, 63);
$this->temperature = 0.8;
$this->rainfall = 0.9;
}
public function getName(){
return "Beach";
return "Swamp";
}
public function getColor(){
return 0x07f9b2;
}
}

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/
*
*
*/
namespace pocketmine\level\generator\normal\biome;
use pocketmine\block\Sapling;
use pocketmine\level\generator\populator\TallGrass;
use pocketmine\level\generator\populator\Tree;
class TaigaBiome extends SnowyBiome{
public function __construct(){
parent::__construct();
$trees = new Tree(Sapling::SPRUCE);
$trees->setBaseAmount(10);
$this->addPopulator($trees);
$tallGrass = new TallGrass();
$tallGrass->setBaseAmount(1);
$this->addPopulator($tallGrass);
$this->setElevation(63, 81);
$this->temperature = 0.05;
$this->rainfall = 0.8;
}
public function getName(){
return "Taiga";
}
public function getColor(){
return 0x0b6659;
}
}

View File

@ -21,6 +21,7 @@
namespace pocketmine\level\generator\object;
use pocketmine\block\Block;
use pocketmine\block\Sapling;
use pocketmine\level\ChunkManager;
use pocketmine\utils\Random;
@ -33,6 +34,9 @@ class Tree{
6 => true,
17 => true,
18 => true,
Block::SNOW_LAYER => true,
Block::LOG2 => true,
Block::LEAVES2 => true
];
public static function growTree(ChunkManager $level, $x, $y, $z, Random $random, $type = 0){

View File

@ -35,16 +35,24 @@ class GroundCover extends Populator{
$biome = Biome::getBiome($chunk->getBiomeId($x, $z));
$cover = $biome->getGroundCover();
if(count($cover) > 0){
$diffY = 0;
if(!$cover[0]->isSolid()){
$diffY = 1;
}
$column = $chunk->getBlockIdColumn($x, $z);
for($y = 127; $y > 0; --$y){
if($column{$y} !== "\x00" and Block::get(ord($column{$y}))->isSolid()){
if($column{$y} !== "\x00" and !Block::get(ord($column{$y}))->isTransparent()){
break;
}
}
$startY = $y;
$startY = min(127, $y + $diffY);
$endY = $startY - count($cover);
for($y = $startY; $y > $endY and $y >= 0; --$y){
$b = $cover[$startY - $y];
if($column{$y} === "\x00" and $b->isSolid()){
break;
}
if($b->getDamage() === 0){
$chunk->setBlockId($x, $y, $z, $b->getId());
}else{

View File

@ -43,37 +43,30 @@ class TallGrass extends Populator{
$this->level = $level;
$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);
for($size = 30; $size > 0; --$size){
$xx = $x - 7 + $random->nextRange(0, 15);
$zz = $z - 7 + $random->nextRange(0, 15);
$yy = $this->getHighestWorkableBlock($xx, $zz);
$x = $random->nextRange($chunkX * 16, $chunkX * 16 + 15);
$z = $random->nextRange($chunkZ * 16, $chunkZ * 16 + 15);
$y = $this->getHighestWorkableBlock($x, $z);
if($yy !== -1 and $this->canTallGrassStay($xx, $yy, $zz)){
$this->level->setBlockIdAt($xx, $yy, $zz, Block::TALL_GRASS);
$this->level->setBlockDataAt($xx, $yy, $zz, 1);
}
if($y !== -1 and $this->canTallGrassStay($x, $y, $z)){
$this->level->setBlockIdAt($x, $y, $z, Block::TALL_GRASS);
$this->level->setBlockDataAt($x, $y, $z, 1);
}
}
}
private function canTallGrassStay($x, $y, $z){
return $this->level->getBlockIdAt($x, $y, $z) === Block::AIR and $this->level->getBlockIdAt($x, $y - 1, $z) === Block::GRASS;
$b = $this->level->getBlockIdAt($x, $y, $z);
return ($b === Block::AIR or $b === Block::SNOW_LAYER) and $this->level->getBlockIdAt($x, $y - 1, $z) === Block::GRASS;
}
private function getHighestWorkableBlock($x, $z){
for($y = 128; $y > 0; --$y){
for($y = 127; $y >= 0; --$y){
$b = $this->level->getBlockIdAt($x, $y, $z);
if($b === Block::AIR or $b === Block::LEAVES){
if(--$y <= 0){
return -1;
}
}else{
if($b !== Block::AIR and $b !== Block::LEAVES and $b !== Block::SNOW_LAYER){
break;
}
}
return ++$y;
return $y === 0 ? -1 : ++$y;
}
}

View File

@ -33,6 +33,12 @@ class Tree extends Populator{
private $randomAmount;
private $baseAmount;
private $type;
public function __construct($type = Sapling::OAK){
$this->type = $type;
}
public function setRandomAmount($amount){
$this->randomAmount = $amount;
}
@ -51,24 +57,17 @@ class Tree extends Populator{
if($y === -1){
continue;
}
if($random->nextFloat() > 0.75){
$meta = Sapling::BIRCH;
}else{
$meta = Sapling::OAK;
}
ObjectTree::growTree($this->level, $x, $y, $z, $random, $meta);
ObjectTree::growTree($this->level, $x, $y, $z, $random, $this->type);
}
}
private function getHighestWorkableBlock($x, $z){
for($y = 128; $y > 0; --$y){
for($y = 127; $y > 0; --$y){
$b = $this->level->getBlockIdAt($x, $y, $z);
if($b !== Block::DIRT and $b !== Block::GRASS){
if(--$y <= 0){
return -1;
}
}else{
if($b === Block::DIRT or $b === Block::GRASS){
break;
}elseif($b !== 0 and $b !== Block::SNOW_LAYER){
return -1;
}
}

@ -1 +1 @@
Subproject commit 5ad5b3535c9519b2e013a61a2d55fccae014e037
Subproject commit 3db41e1266811b20c3f52f749265f6c9d416c1bb