Faster level generator

This commit is contained in:
Shoghi Cervantes 2013-09-09 03:32:24 +02:00
parent 4ccaccc126
commit b3c51c6d2e
11 changed files with 71 additions and 63 deletions

View File

@ -23,13 +23,9 @@ class Vector2{
public $x, $y; public $x, $y;
public function __construct($x = 0, $y = 0){ public function __construct($x = 0, $y = 0){
if(($x instanceof Vector2) === true){
$this->__construct($x->x, $x->y);
}else{
$this->x = $x; $this->x = $x;
$this->y = $y; $this->y = $y;
} }
}
public function getX(){ public function getX(){
return $this->x; return $this->x;

View File

@ -23,14 +23,10 @@ class Vector3{
public $x, $y, $z; public $x, $y, $z;
public function __construct($x = 0, $y = 0, $z = 0){ public function __construct($x = 0, $y = 0, $z = 0){
if(($x instanceof Vector3) === true){
$this->__construct($x->x, $x->y, $x->z);
}else{
$this->x = $x; $this->x = $x;
$this->y = $y; $this->y = $y;
$this->z = $z; $this->z = $z;
} }
}
public function getX(){ public function getX(){
return $this->x; return $this->x;

View File

@ -305,6 +305,9 @@ class PMFLevel extends PMF{
} }
public function getBlockID($x, $y, $z){ public function getBlockID($x, $y, $z){
if($y > 127 or $y < 0 or $x < 0 or $z < 0 or $x > 255 or $z > 255){
return 0;
}
$X = $x >> 4; $X = $x >> 4;
$Z = $z >> 4; $Z = $z >> 4;
$Y = $y >> 4; $Y = $y >> 4;
@ -312,11 +315,16 @@ class PMFLevel extends PMF{
$aX = $x - ($X << 4); $aX = $x - ($X << 4);
$aZ = $z - ($Z << 4); $aZ = $z - ($Z << 4);
$aY = $y - ($Y << 4); $aY = $y - ($Y << 4);
$b = ord($this->chunks[$index][$Y]{(int) ($aY + ($aX << 5) + ($aZ << 9))}); $b = ord($this->chunks[$index]
[$Y]
{(int) ($aY + ($aX << 5) + ($aZ << 9))});
return $b; return $b;
} }
public function setBlockID($x, $y, $z, $block){ public function setBlockID($x, $y, $z, $block){
if($y > 127 or $y < 0 or $x < 0 or $z < 0 or $x > 255 or $z > 255){
return false;
}
$X = $x >> 4; $X = $x >> 4;
$Z = $z >> 4; $Z = $z >> 4;
$Y = $y >> 4; $Y = $y >> 4;

View File

@ -22,38 +22,54 @@
//Unsecure, not used for "Real Randomness" //Unsecure, not used for "Real Randomness"
class Random{ class Random{
private $random; private $x, $y, $z, $w;
public function __construct($seed = false){ public function __construct($seed = false){
$this->random = new twister(0);
$this->setSeed($seed); $this->setSeed($seed);
} }
public function setSeed($seed = false){ public function setSeed($seed = false){
$this->random->init_with_integer($seed !== false ? (int) $seed:Utils::readInt(Utils::getRandomBytes(4, false))); $seed = $seed !== false ? Utils::writeInt((int) $seed):Utils::getRandomBytes(4, false);
$state = array();
for($i = 0; $i < 256; ++$i){
$state[] = $i;
}
for($i = $j = 0; $i < 256; ++$i){
$j = ($j + ord($seed{$i & 0x03}) + $state[$i]) & 0xFF;
$state[$i] ^= $state[$j];
$state[$j] ^= $state[$i];
$state[$i] ^= $state[$j];
}
$this->state = $state;
$this->i = $this->j = 0;
} }
public function nextInt(){ public function nextInt(){
return $this->random->int32(); return Utils::readInt($this->nextBytes(4)) & 0x7FFFFFFF;
} }
public function nextFloat(){ public function nextFloat(){
return $this->random->real_closed(); return $this->nextInt() / 0x7FFFFFFF;
} }
public function nextBytes($byteCount){ public function nextBytes($byteCount){
$bytes = ""; $bytes = "";
for($i = 0; $i < $byteCount; ++$i){ for($i = 0; $i < $byteCount; ++$i){
$bytes .= chr($this->random->rangeint(0, 0xFF)); $this->i = ($this->i + 1) & 0xFF;
$this->j = ($this->j + $this->state[$this->i]) & 0xFF;
$this->state[$this->i] ^= $this->state[$this->j];
$this->state[$this->j] ^= $this->state[$this->i];
$this->state[$this->i] ^= $this->state[$this->j];
$bytes .= chr($this->state[($this->state[$this->i] + $this->state[$this->j]) & 0xFF]);
} }
return $bytes; return $bytes;
} }
public function nextBoolean(){ public function nextBoolean(){
return $this->random->rangeint(0, 1) === 1; return ($this->nextBytes(1) & 0x01) == 0;
} }
public function nextRange($start = 0, $end = PHP_INT_MAX){ public function nextRange($start = 0, $end = PHP_INT_MAX){
return $this->random->rangeint($start, $end); return $start + ($this->nextInt() % ($end + 1 - $start));
} }
} }

View File

@ -127,7 +127,7 @@ class SuperflatGenerator implements LevelGenerator{
public function populateChunk($chunkX, $chunkZ){ public function populateChunk($chunkX, $chunkZ){
foreach($this->populators as $populator){ foreach($this->populators as $populator){
$this->random->setSeed((int) ($chunkX * 0xdead + $chunkZ * 0xbeef)); $this->random->setSeed((int) ($chunkX * 0xdead + $chunkZ * 0xbeef) ^ $this->level->getSeed());
$populator->populate($this->level, $chunkX, $chunkZ, $this->random); $populator->populate($this->level, $chunkX, $chunkZ, $this->random);
} }
} }
@ -167,17 +167,17 @@ class SuperflatGenerator implements LevelGenerator{
$grasscount = intval($this->options["spawn"]["grasscount"]); $grasscount = intval($this->options["spawn"]["grasscount"]);
} }
for($t = 0; $t < $treecount; ++$t){ for($t = 0; $t < $treecount; ++$t){
$centerX = $this->random->nextRange(0, 256); $centerX = $this->random->nextRange(0, 255);
$centerZ = $this->random->nextRange(0, 256); $centerZ = $this->random->nextRange(0, 255);
$down = $this->level->getBlock(new Vector3($centerX, $this->floorLevel - 1, $centerZ))->getID(); $down = $this->level->level->getBlockID($centerX, $this->floorLevel - 1, $centerZ);
if($down === DIRT or $down === GRASS or $down === FARMLAND){ if($down === DIRT or $down === GRASS or $down === FARMLAND){
TreeObject::growTree($this->level, new Vector3($centerX, $this->floorLevel, $centerZ), $this->random, $this->random->nextRange(0,3)); TreeObject::growTree($this->level, new Vector3($centerX, $this->floorLevel, $centerZ), $this->random, $this->random->nextRange(0,3));
} }
} }
for($t = 0; $t < $grasscount; ++$t){ for($t = 0; $t < $grasscount; ++$t){
$centerX = $this->random->nextRange(0, 256); $centerX = $this->random->nextRange(0, 255);
$centerZ = $this->random->nextRange(0, 256); $centerZ = $this->random->nextRange(0, 255);
$down = $this->level->getBlock(new Vector3($centerX, $this->floorLevel - 1, $centerZ))->getID(); $down = $this->level->level->getBlockID($centerX, $this->floorLevel - 1, $centerZ);
if($down === GRASS){ if($down === GRASS){
TallGrassObject::growGrass($this->level, new Vector3($centerX, $this->floorLevel - 1, $centerZ), $this->random, $this->random->nextRange(8, 40)); TallGrassObject::growGrass($this->level, new Vector3($centerX, $this->floorLevel - 1, $centerZ), $this->random, $this->random->nextRange(8, 40));
} }

View File

@ -32,13 +32,13 @@ class OreObject{
return $this->type; return $this->type;
} }
public function canPlaceObject(Level $level, Vector3 $pos){ public function canPlaceObject(Level $level, $x, $y, $z){
return ($level->getBlock($pos)->getID() !== AIR); return ($level->level->getBlockID($x, $y, $z) != AIR);
} }
public function placeObject(Level $level, Vector3 $pos){ public function placeObject(Level $level, Vector3 $pos){
$clusterSize = (int) $this->type->clusterSize; $clusterSize = (int) $this->type->clusterSize;
$angle = $this->random->nextFloat() * pi(); $angle = $this->random->nextFloat() * M_PI;
$offset = VectorMath::getDirection2D($angle)->multiply($clusterSize)->divide(8); $offset = VectorMath::getDirection2D($angle)->multiply($clusterSize)->divide(8);
$x1 = $pos->x + 8 + $offset->x; $x1 = $pos->x + 8 + $offset->x;
$x2 = $pos->x + 8 - $offset->x; $x2 = $pos->x + 8 - $offset->x;
@ -50,7 +50,7 @@ class OreObject{
$seedX = $x1 + ($x2 - $x1) * $count / $clusterSize; $seedX = $x1 + ($x2 - $x1) * $count / $clusterSize;
$seedY = $y1 + ($y2 - $y1) * $count / $clusterSize; $seedY = $y1 + ($y2 - $y1) * $count / $clusterSize;
$seedZ = $z1 + ($z2 - $z1) * $count / $clusterSize; $seedZ = $z1 + ($z2 - $z1) * $count / $clusterSize;
$size = ((sin($count * (pi() / $clusterSize)) + 1) * $this->random->nextFloat() * $clusterSize / 16 + 1) / 2; $size = ((sin($count * (M_PI / $clusterSize)) + 1) * $this->random->nextFloat() * $clusterSize / 16 + 1) / 2;
$startX = (int) ($seedX - $size); $startX = (int) ($seedX - $size);
$startY = (int) ($seedY - $size); $startY = (int) ($seedY - $size);
@ -67,9 +67,8 @@ class OreObject{
if($y > 0 and ($sizeX + $sizeY) < 1){ if($y > 0 and ($sizeX + $sizeY) < 1){
for($z = $startZ; $z <= $endZ; ++$z){ for($z = $startZ; $z <= $endZ; ++$z){
$sizeZ = pow(($z + 0.5 - $seedZ) / $size, 2); $sizeZ = pow(($z + 0.5 - $seedZ) / $size, 2);
$v = new Vector3($x, $y, $z); if(($sizeX + $sizeY + $sizeZ) < 1 and $level->level->getBlockID($x, $y, $z) === STONE){
if(($sizeX + $sizeY + $sizeZ) < 1 and $level->getBlock($v)->getID() === STONE){ $level->setBlockRaw(new Vector3($x, $y, $z), $this->type->material);
$level->setBlockRaw($v, $this->type->material);
} }
} }
} }

View File

@ -23,23 +23,21 @@
class TallGrassObject{ class TallGrassObject{
public static function growGrass(Level $level, Vector3 $pos, Random $random, $count = 15){ public static function growGrass(Level $level, Vector3 $pos, Random $random, $count = 15){
$arr = array( $arr = array(
array(DANDELION, 0), BlockAPI::get(DANDELION, 0),
array(CYAN_FLOWER, 0), BlockAPI::get(CYAN_FLOWER, 0),
array(TALL_GRASS, 1), BlockAPI::get(TALL_GRASS, 1),
array(TALL_GRASS, 1), BlockAPI::get(TALL_GRASS, 1),
array(TALL_GRASS, 1), BlockAPI::get(TALL_GRASS, 1),
array(TALL_GRASS, 1), BlockAPI::get(TALL_GRASS, 1)
array(AIR, 0),
); );
$radius = ceil(sqrt($count) / 2); $radius = 10;
$arrC = count($arr) - 1;
for($c = 0; $c < $count; ++$c){ for($c = 0; $c < $count; ++$c){
$x = $random->nextRange($pos->x - $radius, $pos->x + $radius); $x = $random->nextRange($pos->x - $radius, $pos->x + $radius);
$z = $random->nextRange($pos->z - $radius, $pos->z + $radius); $z = $random->nextRange($pos->z - $radius, $pos->z + $radius);
$b = $level->getBlock(new Vector3($x, $pos->y + 1, $z)); if($level->level->getBlockID($x, $pos->y + 1, $z) === AIR and $level->level->getBlockID($x, $pos->y, $z) === GRASS){
$d = $level->getBlock(new Vector3($x, $pos->y, $z)); $t = $arr[$random->nextRange(0, $arrC)];
if($b->getID() === AIR and $d->getID() === GRASS){ $level->setBlockRaw(new Vector3($x, $pos->y + 1, $z), $t);
$t = $arr[$random->nextRange(0, count($arr) - 1)];
$level->setBlockRaw($b, BlockAPI::get($t[0], $t[1]));
} }
} }
} }

View File

@ -38,8 +38,7 @@ class PineTreeObject extends TreeObject{
} }
for($xx = -$checkRadius; $xx < ($checkRadius + 1); ++$xx){ for($xx = -$checkRadius; $xx < ($checkRadius + 1); ++$xx){
for($zz = -$checkRadius; $zz < ($checkRadius + 1); ++$zz){ for($zz = -$checkRadius; $zz < ($checkRadius + 1); ++$zz){
$block = $level->getBlock(new Vector3($pos->x + $xx, $pos->y + $yy, $pos->z + $zz)); if(!isset($this->overridable[$level->level->getBlockID($pos->x + $xx, $pos->y + $yy, $pos->z + $zz)])){
if(!isset($this->overridable[$block->getID()])){
return false; return false;
} }
} }

View File

@ -41,8 +41,7 @@ class SmallTreeObject extends TreeObject{
} }
for($xx = -$radiusToCheck; $xx < ($radiusToCheck + 1); ++$xx){ for($xx = -$radiusToCheck; $xx < ($radiusToCheck + 1); ++$xx){
for($zz = -$radiusToCheck; $zz < ($radiusToCheck + 1); ++$zz){ for($zz = -$radiusToCheck; $zz < ($radiusToCheck + 1); ++$zz){
$block = $level->getBlock(new Vector3($pos->x + $xx, $pos->y + $yy, $pos->z + $zz)); if(!isset($this->overridable[$level->level->getBlockID($pos->x + $xx, $pos->y + $yy, $pos->z + $zz)])){
if(!isset($this->overridable[$block->getID()])){
return false; return false;
} }
} }

View File

@ -38,8 +38,7 @@ class SpruceTreeObject extends TreeObject{
} }
for($xx = -$checkRadius; $xx < ($checkRadius + 1); ++$xx){ for($xx = -$checkRadius; $xx < ($checkRadius + 1); ++$xx){
for($zz = -$checkRadius; $zz < ($checkRadius + 1); ++$zz){ for($zz = -$checkRadius; $zz < ($checkRadius + 1); ++$zz){
$block = $level->getBlock(new Vector3($pos->x + $xx, $pos->y + $yy, $pos->z + $zz)); if(!isset($this->overridable[$level->level->getBlockID($pos->x + $xx, $pos->y + $yy, $pos->z + $zz)])){
if(!isset($this->overridable[$block->getID()])){
return false; return false;
} }
} }

View File

@ -25,13 +25,11 @@ class OrePopulator extends Populator{
foreach($this->oreTypes as $type){ foreach($this->oreTypes as $type){
$ore = new OreObject($random, $type); $ore = new OreObject($random, $type);
for($i = 0; $i < $ore->type->clusterCount; ++$i){ for($i = 0; $i < $ore->type->clusterCount; ++$i){
$v = new Vector3( $x = $random->nextRange($chunkX << 4, ($chunkX << 4) + 16);
$random->nextRange($chunkX << 4, ($chunkX << 4) + 16), $y = $random->nextRange($ore->type->minHeight, $ore->type->maxHeight);
$random->nextRange($ore->type->minHeight, $ore->type->maxHeight), $z = $random->nextRange($chunkZ << 4, ($chunkZ << 4) + 16);
$random->nextRange($chunkZ << 4, ($chunkZ << 4) + 16) if($ore->canPlaceObject($level, $x, $y, $z)){
); $ore->placeObject($level, new Vector3($x, $y, $z));
if($ore->canPlaceObject($level, $v)){
$ore->placeObject($level, $v);
} }
} }
} }