New Level Generator API & Support for MC Superflat Presets

This commit is contained in:
Shoghi Cervantes Pueyo 2013-05-18 02:05:56 +02:00
parent edb93d6312
commit 5ea6052a8a
8 changed files with 809 additions and 440 deletions

View File

@ -86,18 +86,18 @@ class LevelAPI{
}
public function generateLevel($name, $seed = false){
$path = DATA_PATH."worlds/".$name."/";
$generator = "SuperflatGenerator";
$options = array();
if($this->server->api->getProperty("generator-settings") !== false and trim($this->server->api->getProperty("generator-settings")) != ""){
$options["preset"] = $this->server->api->getProperty("generator-settings");
}
if($this->server->api->getProperty("generator") !== false and class_exists($this->server->api->getProperty("generator"))){
$generator = $this->server->api->getProperty("generator");
$generator = new $generator($options);
}else{
$generator = new SuperflatGenerator($options);
}
$gen = new WorldGenerator($generator, ($seed === false ? Utils::readInt(Utils::getRandomBytes(4, false)):(int) $seed));
if($this->server->api->getProperty("generator-settings") !== false and trim($this->server->api->getProperty("generator-settings")) != ""){
$gen->set("preset", $this->server->api->getProperty("generator-settings"));
}
$gen->init();
$gen = new WorldGenerator($generator, $name, $seed === false ? Utils::readInt(Utils::getRandomBytes(4, false)):(int) $seed);
$gen->generate();
$gen->save($path, $name);
}
public function loadLevel($name){

View File

@ -0,0 +1,524 @@
<?php
/*
Mersenne Twister, 1.1.0
-----------------------
This is an implementation of the Mersenne Twister. The current version
number is 1.1.0.
Much of the code here was derived from the C code in the file
mt19937ar.c, which is in the archive mt19937ar.sep.tgz, available from
http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/emt19937ar.html.
Some of the original C code is preserved in a few of the comments below.
It is non-trivial to map the C code onto PHP, because PHP has no
unsigned integer type. What we do here is to use integers when we can,
and floats when we must.
Only the class `twister' is part of the API; everything else is private.
http://kingfisher.nfshost.com/sw/twister/
*/
namespace mersenne_twister;
const N = 624;
const M = 397;
const MATRIX_A = 0x9908b0df;
const UPPER_MASK = 0x80000000;
const LOWER_MASK = 0x7fffffff;
function define_constants() {
$code = "";
$namespace = __NAMESPACE__;
foreach (array(10, 11, 12, 14, 20, 21, 22, 26, 27, 31) as $n) {
$val = ~((~0) << $n);
$code .= "namespace $namespace { const MASK$n = $val; }\n";
}
foreach (array(16, 31, 32) as $n) {
$val = pow(2, $n);
$code .= "namespace $namespace { const TWO_TO_THE_$n = $val; }\n";
}
eval($code);
$val = MASK31 | (MASK31 << 1);
eval("namespace $namespace { const MASK32 = $val; }");
}
define_constants();
class twister {
const N = N;
# the class constant is not used anywhere in this namespace,
# but it makes the API cleaner.
function __construct() {
$this->bits32 = PHP_INT_MAX == 2147483647;
if(func_num_args() == 1) {
$this->init_with_integer(func_get_arg(0));
}
}
function init_with_integer($integer_seed) {
$integer_seed = force_32_bit_int($integer_seed);
$mt = &$this->mt;
$mti = &$this->mti;
$mt = array_fill(0, N, 0);
$mt[0] = $integer_seed;
for($mti = 1; $mti < N; $mti++) {
$mt[$mti] = add_2(mul(1812433253,
($mt[$mti - 1] ^ (($mt[$mti - 1] >> 30) & 3))), $mti);
/*
mt[mti] =
(1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti);
*/
}
}
function init_with_array(array $integer_array) {
$integer_array =
array_map(__NAMESPACE__ . "\\force_32_bit_int", $integer_array);
$mt = &$this->mt;
$mti = &$this->mti;
$key_length = count($integer_array);
$this->init_with_integer(19650218);
$i=1; $j=0;
$k = (N>$key_length ? N : $key_length);
for (; $k; $k--) {
$mt[$i] = add_3($mt[$i] ^
mul_by_1664525($mt[$i-1] ^ (($mt[$i-1] >> 30) & 3)),
$integer_array[$j], $j);
/*
mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525UL))
+ init_key[j] + j;
*/
$i++; $j++;
if ($i>=N) { $mt[0] = $mt[N-1]; $i=1; }
if ($j>=$key_length) $j=0;
}
for ($k=N-1; $k; $k--) {
$mt[$i] = sub($mt[$i] ^
mul($mt[$i-1] ^ (($mt[$i-1] >> 30) & 3), 1566083941), $i);
/*
mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941UL))
- i;
*/
$i++;
if ($i>=N) { $mt[0] = $mt[N-1]; $i=1; }
}
$mt[0] = (1 << 31); /* MSB is 1; assuring non-zero initial array */
}
function init_with_string($string) {
$remainder = strlen($string) % 4;
if($remainder > 0)
$string .= str_repeat("\0", 4 - $remainder);
$integer_array = array_values(unpack("N*", $string));
$this->init_with_array($integer_array);
}
function init_with_files(array $filenames, $max_ints = -1) {
$limit_applies = $max_ints !== -1;
if($limit_applies)
$limit = $max_ints * 4; # 32 bits is 4 characters
$data = "";
foreach ($filenames as $filename) {
$contents =
file_get_contents($filename, FALSE, NULL, 0,
$limit_applies? $limit - strlen($data): -1);
if($contents === FALSE) {
throw new Exception("problem reading from $filename");
} else {
$data .= $contents;
if($limit_applies && strlen($data) == $limit) {
break;
}
}
}
$this->init_with_string($data);
}
function init_with_file($filename, $max_ints = -1) {
$this->init_with_files(array($filename), $max_ints);
}
function int32() {
static $mag01 = array(0, MATRIX_A);
$mt = &$this->mt;
$mti = &$this->mti;
if ($mti >= N) { /* generate N words all at once */
for ($kk=0;$kk<N-M;$kk++) {
$y = ($mt[$kk]&UPPER_MASK)|($mt[$kk+1]&LOWER_MASK);
$mt[$kk] = $mt[$kk+M] ^ (($y >> 1) & MASK31) ^ $mag01[$y & 1];
}
for (;$kk<N-1;$kk++) {
$y = ($mt[$kk]&UPPER_MASK)|($mt[$kk+1]&LOWER_MASK);
$mt[$kk] =
$mt[$kk+(M-N)] ^ (($y >> 1) & MASK31) ^ $mag01[$y & 1];
}
$y = ($mt[N-1]&UPPER_MASK)|($mt[0]&LOWER_MASK);
$mt[N-1] = $mt[M-1] ^ (($y >> 1) & MASK31) ^ $mag01[$y & 1];
$mti = 0;
}
$y = $mt[$mti++];
/* Tempering */
$y ^= ($y >> 11) & MASK21;
$y ^= ($y << 7) & ((0x9d2c << 16) | 0x5680);
$y ^= ($y << 15) & (0xefc6 << 16);
$y ^= ($y >> 18) & MASK14;
return $y;
}
function int31() {
return $this->int32() & MASK31;
}
/* generates a random number on [0,1]-real-interval */
function real_closed() {
return
signed2unsigned($this->int32()) * (1.0 / 4294967295.0);
}
/* generates a random number on [0,1)-real-interval */
function real_halfopen() {
return
signed2unsigned($this->int32()) * (1.0 / 4294967296.0);
}
/* generates a random number on (0,1)-real-interval */
function real_open() {
return (signed2unsigned($this->int32()) + .5) *
(1.0 / 4294967296.0);
}
/* generates a random number on [0,1) with 53-bit resolution */
function real_halfopen2() {
return
((($this->int32() & MASK27) * 67108864.0) +
($this->int32() & MASK26)) *
(1.0 / 9007199254740992.0);
}
function rangeint($lower_bound, $upper_bound) {
$lower_bound = intval($lower_bound);
$upper_bound = intval($upper_bound);
if($this->bits32) {
$pow_2_32 = pow(2, 32);
$size_of_range = $upper_bound - $lower_bound + 1;
$remainder = fmod($pow_2_32, $size_of_range);
if($remainder == 0) {
return $lower_bound +
($this->int32() & unsigned2signed($size_of_range - 1));
} else {
$start_of_partial_range = $pow_2_32 - $remainder;
$start_as_int = unsigned2signed($start_of_partial_range);
do {
$rand = $this->int32();
} while($rand >= $start_as_int && $rand < 0);
$result = $lower_bound +
fmod(signed2unsigned($rand), $size_of_range);
return intval($result);
}
} else {
if($lower_bound == -PHP_INT_MAX - 1 && $upper_bound == PHP_INT_MAX) {
return ($this->int32() << 32) & $this->int32();
} else {
$pow_2_32 = 1 << 32;
$size_of_range = $upper_bound - $lower_bound + 1;
if($size_of_range > $pow_2_32) {
$size_of_range >>= 32;
$shift = 32;
$low_bits = $this->int32();
} else {
$shift = 0;
$low_bits = 0;
}
$remainder = $pow_2_32 % $size_of_range;
if($remainder == 0) {
$high_bits = $this->int32() & ($size_of_range - 1);
} else {
$start_of_partial_range = $pow_2_32 - $remainder;
do {
$rand = $this->int32();
} while($rand >= $start_of_partial_range);
$high_bits = $rand % $size_of_range;
}
return $lower_bound + (($high_bits << $shift) | $low_bits);
}
}
}
/*
in each of the next 3 functions, we loop until we have a number that
meets the function's post-condition. this may be more work than
is really necessary, but i am concerned about rounding errors.
why no rangereal_closed? because, due to the aforementioned
rounding errors, i am unable to guarantee that $upper_bound
would be a possible return value of such a function.
*/
function rangereal_open($lower_bound, $upper_bound) {
do {
$rand = $lower_bound +
$this->real_open() * ($upper_bound - $lower_bound);
} while($rand <= $lower_bound || $rand >= $upper_bound);
return $rand;
}
function rangereal_halfopen($lower_bound, $upper_bound) {
do {
$rand = $lower_bound +
$this->real_halfopen() * ($upper_bound - $lower_bound);
} while($rand >= $upper_bound);
/*
$rand cannot go any lower than $lower_bound, because
$this->real_halfopen() cannot go any lower than 0
*/
return $rand;
}
function rangereal_halfopen2($lower_bound, $upper_bound) {
do {
$rand = $lower_bound +
$this->real_halfopen2() * ($upper_bound - $lower_bound);
} while($rand >= $upper_bound);
return $rand;
}
function test() {
ob_start();
$this->exercise();
$output = ob_get_clean();
if(md5($output) !== "cb33e6acc162cbe20f7fcac26adddd02") {
print "Test failed.\n";
}
}
private function exercise() {
/*
we keep the names "genrand_int32" and "genrand_real2" because
we want the output of this function to be identical to that
produced by mtTest.c. (The file mtTest.c is part of the archive
mt19937ar.sep.tgz, mentioned above.)
*/
$this->init_with_array(array(0x123, 0x234, 0x345, 0x456));
printf("1000 outputs of genrand_int32()\n");
for ($i=0; $i<1000; $i++) {
printf("%10lu ", $this->int32());
if ($i%5==4) printf("\n");
}
printf("\n1000 outputs of genrand_real2()\n");
for ($i=0; $i<1000; $i++) {
printf("%10.8f ", $this->real_halfopen());
if ($i%5==4) printf("\n");
}
}
}
function signed2unsigned($signed_integer) {
## assert(is_integer($signed_integer));
## assert(($signed_integer & ~MASK32) === 0);
return $signed_integer >= 0? $signed_integer:
TWO_TO_THE_32 + $signed_integer;
}
function unsigned2signed($unsigned_integer) {
## assert($unsigned_integer >= 0);
## assert($unsigned_integer < pow(2, 32));
## assert(floor($unsigned_integer) === floatval($unsigned_integer));
return intval($unsigned_integer < TWO_TO_THE_31? $unsigned_integer:
$unsigned_integer - TWO_TO_THE_32);
}
function force_32_bit_int($x) {
/*
it would be un-PHP-like to require is_integer($x),
so we have to handle cases like this:
$x === pow(2, 31)
$x === strval(pow(2, 31))
we are also opting to do something sensible (rather than dying)
if the seed is outside the range of a 32-bit unsigned integer.
*/
if(is_integer($x)) {
/*
we mask in case we are on a 64-bit machine and at least one
bit is set between position 32 and position 63.
*/
return $x & MASK32;
} else {
$x = floatval($x);
$x = $x < 0? ceil($x): floor($x);
$x = fmod($x, TWO_TO_THE_32);
if($x < 0)
$x += TWO_TO_THE_32;
return unsigned2signed($x);
}
}
/*
takes 2 integers, treats them as unsigned 32-bit integers,
and adds them.
it works by splitting each integer into
2 "half-integers", then adding the high and low half-integers
separately.
a slight complication is that the sum of the low half-integers
may not fit into 16 bits; any "overspill" is added to the sum
of the high half-integers.
*/
function add_2($n1, $n2) {
$x = ($n1 & 0xffff) + ($n2 & 0xffff);
return
(((($n1 >> 16) & 0xffff) +
(($n2 >> 16) & 0xffff) +
($x >> 16)) << 16) | ($x & 0xffff);
}
# takes 2 integers, treats them as unsigned 32-bit integers,
# and adds them.
#
# for how it works, see the comment for add_2.
#
function add_3($n1, $n2, $n3) {
$x = ($n1 & 0xffff) + ($n2 & 0xffff) + ($n3 & 0xffff);
return
(((($n1 >> 16) & 0xffff) +
(($n2 >> 16) & 0xffff) +
(($n3 >> 16) & 0xffff) +
($x >> 16)) << 16) | ($x & 0xffff);
}
# takes 2 integers, treats them as unsigned 32-bit integers,
# and subtracts the second from the first.
#
# the explanation of why this works is too long to be
# included here, so it has been moved into the file why-sub-works.txt.
#
function sub($a, $b) {
return (($a & MASK31) - ($b & MASK31)) ^
(($a ^ $b) & 0x80000000);
}
function mul($a, $b) {
/*
a and b, considered as unsigned integers, can be expressed as follows:
a = 2**16 * a1 + a2,
b = 2**16 * b1 + b2,
where
0 <= a2 < 2**16,
0 <= b2 < 2**16.
given those 2 equations, what this function essentially does is to
use the following identity:
a * b = 2**32 * a1 * b1 + 2**16 * a1 * b2 + 2**16 * b1 * a2 + a2 * b2
note that the first term, i.e. 2**32 * a1 * b1, is unnecessary here,
so we don't compute it.
we could make the following code clearer by using intermediate
variables, but that would probably hurt performance.
*/
return
unsigned2signed(
fmod(
TWO_TO_THE_16 *
/*
the next line of code calculates a1 * b2,
the line after that calculates b1 * a2,
and the line after that calculates a2 * b2.
*/
((($a >> 16) & 0xffff) * ($b & 0xffff) +
(($b >> 16) & 0xffff) * ($a & 0xffff)) +
($a & 0xffff) * ($b & 0xffff),
TWO_TO_THE_32));
}
/*
mul_by_1664525($x) should be more efficient than mul(1664525, $x).
*/
function mul_by_1664525($n) {
return unsigned2signed(fmod(1664525 * ($n >= 0?
$n: (TWO_TO_THE_32 + $n)), TWO_TO_THE_32));
}
function do_bc_op($bc_op, array $numbers) {
$modulus = pow(2, 32);
$result =
call_user_func_array($bc_op,
array_map(__NAMESPACE__ . "\\signed2unsigned", $numbers));
$result = bcmod($result, $modulus);
return unsigned2signed(bccomp($result, 0) < 0?
bcadd($result, $modulus): $result);
}
function get_random_32bit_int() {
return rand(0, 0xffff) | (rand(0, 0xffff) << 16);
}

61
src/utils/Random.php Normal file
View File

@ -0,0 +1,61 @@
<?php
/*
-
/ \
/ \
/ PocketMine \
/ MP \
|\ @shoghicp /|
|. \ / .|
| .. \ / .. |
| .. | .. |
| .. | .. |
\ | /
\ | /
\ | /
\ | /
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.
*/
//Unsecure, not used for "Real Randomness"
class Random{
private $random;
public function __construct($seed = false){
$this->random = new mersenne_twister\twister(0);
$this->setSeed($seed);
}
public function setSeed($seed = false){
$this->random->init_with_integer($seed !== false ? (int) $seed:Utils::readInt(Utils::getRandomBytes(4, false)));
}
public function nextInt(){
return $this->random->int32();
}
public function nextFloat(){
return $this->random->real_closed();
}
public function nextBytes($byteCount){
$bytes = "";
for($i = 0; $i < $byteCount; ++$i){
$bytes .= chr($this->random->rangeint(0, 0xFF));
}
return $bytes;
}
public function nextBoolean(){
return $this->random->rangeint(0, 1) === 1;
}
}

View File

@ -85,8 +85,8 @@ class Level{
unset($this->level);
}
public function save(){
if($this->server->saveEnabled === false){
public function save($force = false){
if($this->server->saveEnabled === false and $force === false){
return;
}
$entities = array();
@ -169,6 +169,10 @@ class Level{
return BlockAPI::get($b[0], $b[1], new Position($pos->x, $pos->y, $pos->z, $this));
}
public function setBlockRaw(Vector3 $pos, Block $block){
return $this->level->setBlock($pos->x, $pos->y, $pos->z, $block->getID(), $block->getMetadata());
}
public function setBlock(Vector3 $pos, Block $block, $update = true, $tiles = false){
if((($pos instanceof Position) and $pos->level !== $this) or $pos->x < 0 or $pos->y < 0 or $pos->z < 0){
return false;
@ -195,12 +199,12 @@ class Level{
return false;
}
public function getMiniChunk($X, $Z){
public function getMiniChunk($X, $Y, $Z){
return $this->level->getMiniChunk($X, $Z);
}
public function setMiniChunk($X, $Z, $data){
return $this->level->setMiniChunk($X, $Z, $data);
public function setMiniChunk($X, $Y, $Z, $data){
return $this->level->setMiniChunk($X, $Y, $Z, $data);
}
public function loadChunk($X, $Z){

View File

@ -1,357 +0,0 @@
<?php
/*
-
/ \
/ \
/ PocketMine \
/ MP \
|\ @shoghicp /|
|. \ / .|
| .. \ / .. |
| .. | .. |
| .. | .. |
\ | /
\ | /
\ | /
\ | /
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.
*/
class WorldGenerator{
private $gen, $seed, $genName, $raw;
public function __construct($genName, $seed){
$this->seed = (int) $seed;
$this->raw = b"";
$this->genName = $genName;
$this->gen = new $genName($this->seed);
}
public function getSpawn(){
return $this->gen->getSpawn();
}
public function set($name, $value){
$this->gen->set($name, $value);
}
public function init(){
$this->raw = "\x15\x01\x00\x00\x15\x16\x00\x00\x15\x2b\x00\x00\x15\x40\x00\x00". //Location Header
"\x15\x55\x00\x00\x15\x6a\x00\x00\x15\x7f\x00\x00\x15\x94\x00\x00".
"\x15\xa9\x00\x00\x15\xbe\x00\x00\x15\xd3\x00\x00\x15\xe8\x00\x00".
"\x15\xfd\x00\x00\x15\x12\x01\x00\x15\x27\x01\x00\x15\x3c\x01\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x15\x51\x01\x00\x15\x66\x01\x00\x15\x7b\x01\x00\x15\x90\x01\x00".
"\x15\xa5\x01\x00\x15\xba\x01\x00\x15\xcf\x01\x00\x15\xe4\x01\x00".
"\x15\xf9\x01\x00\x15\x0e\x02\x00\x15\x23\x02\x00\x15\x38\x02\x00".
"\x15\x4d\x02\x00\x15\x62\x02\x00\x15\x77\x02\x00\x15\x8c\x02\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x15\xa1\x02\x00\x15\xb6\x02\x00\x15\xcb\x02\x00\x15\xe0\x02\x00".
"\x15\xf5\x02\x00\x15\x0a\x03\x00\x15\x1f\x03\x00\x15\x34\x03\x00".
"\x15\x49\x03\x00\x15\x5e\x03\x00\x15\x73\x03\x00\x15\x88\x03\x00".
"\x15\x9d\x03\x00\x15\xb2\x03\x00\x15\xc7\x03\x00\x15\xdc\x03\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x15\xf1\x03\x00\x15\x06\x04\x00\x15\x1b\x04\x00\x15\x30\x04\x00".
"\x15\x45\x04\x00\x15\x5a\x04\x00\x15\x6f\x04\x00\x15\x84\x04\x00".
"\x15\x99\x04\x00\x15\xae\x04\x00\x15\xc3\x04\x00\x15\xd8\x04\x00".
"\x15\xed\x04\x00\x15\x02\x05\x00\x15\x17\x05\x00\x15\x2c\x05\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x15\x41\x05\x00\x15\x56\x05\x00\x15\x6b\x05\x00\x15\x80\x05\x00".
"\x15\x95\x05\x00\x15\xaa\x05\x00\x15\xbf\x05\x00\x15\xd4\x05\x00".
"\x15\xe9\x05\x00\x15\xfe\x05\x00\x15\x13\x06\x00\x15\x28\x06\x00".
"\x15\x3d\x06\x00\x15\x52\x06\x00\x15\x67\x06\x00\x15\x7c\x06\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x15\x91\x06\x00\x15\xa6\x06\x00\x15\xbb\x06\x00\x15\xd0\x06\x00".
"\x15\xe5\x06\x00\x15\xfa\x06\x00\x15\x0f\x07\x00\x15\x24\x07\x00".
"\x15\x39\x07\x00\x15\x4e\x07\x00\x15\x63\x07\x00\x15\x78\x07\x00".
"\x15\x8d\x07\x00\x15\xa2\x07\x00\x15\xb7\x07\x00\x15\xcc\x07\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x15\xe1\x07\x00\x15\xf6\x07\x00\x15\x0b\x08\x00\x15\x20\x08\x00".
"\x15\x35\x08\x00\x15\x4a\x08\x00\x15\x5f\x08\x00\x15\x74\x08\x00".
"\x15\x89\x08\x00\x15\x9e\x08\x00\x15\xb3\x08\x00\x15\xc8\x08\x00".
"\x15\xdd\x08\x00\x15\xf2\x08\x00\x15\x07\x09\x00\x15\x1c\x09\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x15\x31\x09\x00\x15\x46\x09\x00\x15\x5b\x09\x00\x15\x70\x09\x00".
"\x15\x85\x09\x00\x15\x9a\x09\x00\x15\xaf\x09\x00\x15\xc4\x09\x00".
"\x15\xd9\x09\x00\x15\xee\x09\x00\x15\x03\x0a\x00\x15\x18\x0a\x00".
"\x15\x2d\x0a\x00\x15\x42\x0a\x00\x15\x57\x0a\x00\x15\x6c\x0a\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x15\x81\x0a\x00\x15\x96\x0a\x00\x15\xab\x0a\x00\x15\xc0\x0a\x00".
"\x15\xd5\x0a\x00\x15\xea\x0a\x00\x15\xff\x0a\x00\x15\x14\x0b\x00".
"\x15\x29\x0b\x00\x15\x3e\x0b\x00\x15\x53\x0b\x00\x15\x68\x0b\x00".
"\x15\x7d\x0b\x00\x15\x92\x0b\x00\x15\xa7\x0b\x00\x15\xbc\x0b\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x15\xd1\x0b\x00\x15\xe6\x0b\x00\x15\xfb\x0b\x00\x15\x10\x0c\x00".
"\x15\x25\x0c\x00\x15\x3a\x0c\x00\x15\x4f\x0c\x00\x15\x64\x0c\x00".
"\x15\x79\x0c\x00\x15\x8e\x0c\x00\x15\xa3\x0c\x00\x15\xb8\x0c\x00".
"\x15\xcd\x0c\x00\x15\xe2\x0c\x00\x15\xf7\x0c\x00\x15\x0c\x0d\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x15\x21\x0d\x00\x15\x36\x0d\x00\x15\x4b\x0d\x00\x15\x60\x0d\x00".
"\x15\x75\x0d\x00\x15\x8a\x0d\x00\x15\x9f\x0d\x00\x15\xb4\x0d\x00".
"\x15\xc9\x0d\x00\x15\xde\x0d\x00\x15\xf3\x0d\x00\x15\x08\x0e\x00".
"\x15\x1d\x0e\x00\x15\x32\x0e\x00\x15\x47\x0e\x00\x15\x5c\x0e\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x15\x71\x0e\x00\x15\x86\x0e\x00\x15\x9b\x0e\x00\x15\xb0\x0e\x00".
"\x15\xc5\x0e\x00\x15\xda\x0e\x00\x15\xef\x0e\x00\x15\x04\x0f\x00".
"\x15\x19\x0f\x00\x15\x2e\x0f\x00\x15\x43\x0f\x00\x15\x58\x0f\x00".
"\x15\x6d\x0f\x00\x15\x82\x0f\x00\x15\x97\x0f\x00\x15\xac\x0f\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x15\xc1\x0f\x00\x15\xd6\x0f\x00\x15\xeb\x0f\x00\x15\x00\x10\x00".
"\x15\x15\x10\x00\x15\x2a\x10\x00\x15\x3f\x10\x00\x15\x54\x10\x00".
"\x15\x69\x10\x00\x15\x7e\x10\x00\x15\x93\x10\x00\x15\xa8\x10\x00".
"\x15\xbd\x10\x00\x15\xd2\x10\x00\x15\xe7\x10\x00\x15\xfc\x10\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x15\x11\x11\x00\x15\x26\x11\x00\x15\x3b\x11\x00\x15\x50\x11\x00".
"\x15\x65\x11\x00\x15\x7a\x11\x00\x15\x8f\x11\x00\x15\xa4\x11\x00".
"\x15\xb9\x11\x00\x15\xce\x11\x00\x15\xe3\x11\x00\x15\xf8\x11\x00".
"\x15\x0d\x12\x00\x15\x22\x12\x00\x15\x37\x12\x00\x15\x4c\x12\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x15\x61\x12\x00\x15\x76\x12\x00\x15\x8b\x12\x00\x15\xa0\x12\x00".
"\x15\xb5\x12\x00\x15\xca\x12\x00\x15\xdf\x12\x00\x15\xf4\x12\x00".
"\x15\x09\x13\x00\x15\x1e\x13\x00\x15\x33\x13\x00\x15\x48\x13\x00".
"\x15\x5d\x13\x00\x15\x72\x13\x00\x15\x87\x13\x00\x15\x9c\x13\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x15\xb1\x13\x00\x15\xc6\x13\x00\x15\xdb\x13\x00\x15\xf0\x13\x00".
"\x15\x05\x14\x00\x15\x1a\x14\x00\x15\x2f\x14\x00\x15\x44\x14\x00".
"\x15\x59\x14\x00\x15\x6e\x14\x00\x15\x83\x14\x00\x15\x98\x14\x00".
"\x15\xad\x14\x00\x15\xc2\x14\x00\x15\xd7\x14\x00\x15\xec\x14\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
$this->gen->init();
}
public function generate(){
for($Z = 0; $Z < 16; ++$Z){
for($X = 0; $X < 16; ++$X){
$chunk = str_pad($this->getChunk($X, $Z), 86012, "\x00", STR_PAD_RIGHT);
$this->raw .= Utils::writeLInt(strlen($chunk)) . $chunk;
}
console("[NOTICE] Generating level ".ceil(($Z + 1)/0.16)."%");
}
return true;
}
private function getChunk($X, $Z){
$chunk = b"";
$columns = array();
$X *= 16;
$Z *= 16;
for($x = 0; $x < 16; ++$x){
for($z = 0; $z < 16; ++$z){
$columns[$x * 16 + $z] = $this->gen->getColumn($X + $x, $Z + $z);
}
}
for($i = 0; $i < 4; ++$i){
for($x = 0; $x < 16; ++$x){
for($z = 0; $z < 16; ++$z){
$chunk .= $columns[$x * 16 + $z][$i];
}
}
}
unset($columns);
return $chunk;
}
public function save($dir, $name){
@mkdir($dir, 0777, true);
file_put_contents($dir."chunks.dat", $this->raw);
$s = $this->getSpawn();
$array = array();
file_put_contents($dir."entities.dat", serialize($array));
file_put_contents($dir."tileEntities.dat", serialize($array));
$level = array(
"LevelName" => $name,
"Time" => 0,
"Gamemode" => CREATIVE,
"RandomSeed" => $this->seed,
"Generator" => $this->genName,
"SpawnX" => $s[0],
"SpawnY" => $s[1],
"SpawnZ" => $s[2],
);
file_put_contents($dir."level.dat", serialize($level));
}
}

View File

@ -0,0 +1,38 @@
<?php
/*
-
/ \
/ \
/ PocketMine \
/ MP \
|\ @shoghicp /|
|. \ / .|
| .. \ / .. |
| .. | .. |
| .. | .. |
\ | /
\ | /
\ | /
\ | /
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.
*/
interface LevelGenerator{
public function __construct(array $options = array());
public function generateChunk(Level $level, $chunkX, $chunkY, $chunkZ, Random $random);
public function populateChunk(Level $level, $chunkX, $chunkY, $chunkZ, Random $random);
public function populateLevel(Level $level, Random $random);
public function getSpawn(Random $random);
}

View File

@ -26,82 +26,113 @@ the Free Software Foundation, either version 3 of the License, or
*/
class SuperflatGenerator{
private $config, $spawn, $structure;
public function __construct($seed){
$this->config = array(
"preset" => "7;70x1;3x3;2",
"spawn-surface" => 24,
"spawn-radius" => 10,
"torches" => 0,
"seed" => (int) $seed,
);
$this->parsePreset();
}
public function set($name, $value){
$this->config[$name] = $value;
if($name === "preset"){
$this->parsePreset();
class SuperflatGenerator implements LevelGenerator{
private $config, $structure, $chunks, $options, $floorLevel;
public function __construct(array $options = array()){
$this->preset = "2;7,2x3,2;1;spawn(radius=10 block=24)";
$this->options = $options;
if(isset($options["preset"])){
$this->parsePreset($options["preset"]);
}else{
$this->parsePreset($this->preset);
}
}
private function parsePreset(){
$this->structure = array(
0 => "",
1 => "",
2 => str_repeat("\x00", 64),
3 => str_repeat("\x00", 64),
);
$preset = explode(";", trim($this->config["preset"]));
foreach($preset as $i => $data){
$num = 1;
if(preg_match('#([a-zA-Z\-_]*)\((.*)\)#', $data, $matches) > 0){ //Property
$this->config[$matches[1]] = $matches[2];
continue;
}elseif(preg_match('#([0-9]*)x([0-9:]*)#', $data, $matches) > 0){
$num = (int) $matches[1];
$d = explode(":", $matches[2]);
}else{
$d = explode(":", $data);
}
$block = (int) array_shift($d);
$meta = (int) @array_shift($d);
for($j = 0; $j < $num; ++$j){
$this->structure[0] .= chr($block & 0xFF);
$this->structure[1] .= dechex($meta & 0x0F);
public function parsePreset($preset){
$this->preset = $preset;
$preset = explode(";", $preset);
$version = (int) $preset[0];
$blocks = @$preset[1];
$biome = isset($preset[2]) ? $preset[2]:1;
$options = isset($preset[3]) ? $preset[3]:"";
preg_match_all('#(([0-9]{0,})x?([0-9]{1,3}:?[0-9]{0,2})),?#', $blocks, $matches);
$y = 0;
$this->structure = array();
$this->chunks = array();
foreach($matches[3] as $i => $b){
$b = BlockAPI::fromString($b);
$cnt = $matches[2][$i] === "" ? 1:intval($matches[2][$i]);
for($cY = $y, $y += $cnt; $cY < $y; ++$cY){
$this->structure[$cY] = $b;
}
}
$this->structure[1] = pack("h*", str_pad($this->structure[1], (strlen($this->structure[1])&0xFE) + 2, "0", STR_PAD_RIGHT)); //invert nibbles
$this->structure[0] = substr($this->structure[0], 0, 128);
$this->structure[1] = substr($this->structure[1], 0, 64);
$this->structure[2] = substr($this->structure[2], 0, 64);
$this->structure[3] = substr($this->structure[3], 0, 64);
}
public function init(){
$this->spawn = array(128, strlen($this->structure[0]), 128);
}
public function getSpawn(){
return $this->spawn;
}
public function getColumn($x, $z){
$x = (int) $x;
$z = (int) $z;
$column = $this->structure;
if(floor(sqrt(pow($x - $this->spawn[0], 2) + pow($z - $this->spawn[2], 2))) <= $this->config["spawn-radius"]){
$column[0]{strlen($column[0])-1} = chr($this->config["spawn-surface"]);
$this->floorLevel = $y;
for(;$y < 0xFF; ++$y){
$this->structure[$y] = new AirBlock();
}
if(($x % 8) === 0 and ($z % 8) === 0 and $this->config["torches"] == "1"){
$column[0] .= chr(50);
for($Y = 0; $Y < 8; ++$Y){
$this->chunks[$Y] = "";
$startY = $Y << 4;
$endY = $startY + 16;
for($Z = 0; $Z < 16; ++$Z){
for($X = 0; $X < 16; ++$X){
$blocks = "";
$metas = "";
for($y = $startY; $y < $endY; ++$y){
$blocks .= chr($this->structure[$y]->getID());
$metas .= substr(dechex($this->structure[$y]->getMetadata()), -1);
}
$this->chunks[$Y] .= $blocks.Utils::hexToStr($metas)."\x00\x00\x00\x00\x00\x00\x00\x00";
}
}
}
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 = array();
$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;
}
$column[0] .= str_repeat(chr(0), 128 - strlen($column[0]));
$column[1] .= str_repeat(chr(0), 64 - strlen($column[1]));
$column[2] .= str_repeat(chr(0), 64 - strlen($column[2]));
$column[3] .= str_repeat(chr(0), 64 - strlen($column[3]));
return $column;
}
public function generateChunk(Level $level, $chunkX, $chunkY, $chunkZ, Random $random){
$level->setMiniChunk($chunkX, $chunkZ, $chunkY, $this->chunks[$chunkY]);
}
public function populateChunk(Level $level, $chunkX, $chunkY, $chunkZ, Random $random){
}
public function populateLevel(Level $level, Random $random){
if(isset($this->options["spawn"])){
$spawn = array(10, new SandstoneBlock());
if(isset($this->options["spawn"]["radius"])){
$spawn[0] = intval($this->options["spawn"]["radius"]);
}
if(isset($this->options["spawn"]["block"])){
$spawn[1] = BlockAPI::fromString($this->options["spawn"]["block"])->getBlock();
if(!($spawn[1] instanceof Block)){
$spawn[1] = new SandstoneBlock();
}
}
$start = 128 - $spawn[0];
$end = 128 + $spawn[0];
for($x = $start; $x <= $end; ++$x){
for($z = $start; $z <= $end; ++$z){
if(floor(sqrt(pow($x - 128, 2) + pow($z - 128, 2))) <= $spawn[0]){
$level->setBlock(new Vector3($x, $this->floorLevel - 1, $z), $spawn[1]);
}
}
}
}
}
public function getSpawn(Random $random){
return new Vector3(128, $this->floorLevel, 128);
}
}

View File

@ -0,0 +1,68 @@
<?php
/*
-
/ \
/ \
/ PocketMine \
/ MP \
|\ @shoghicp /|
|. \ / .|
| .. \ / .. |
| .. | .. |
| .. | .. |
\ | /
\ | /
\ | /
\ | /
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.
*/
class WorldGenerator{
private $seed, $level, $path, $random, $generator, $width;
public function __construct(LevelGenerator $generator, $name, $seed = false, $width = 16, $height = 8){
$this->seed = $seed !== false ? (int) $seed:Utils::readInt(Utils::getRandomBytes(4, false));
$this->random = new Random($this->seed);
$this->width = (int) $width;
$this->height = (int) $height;
$this->path = DATA_PATH."worlds/".$name."/";
$this->generator = $generator;
$level = new PMFLevel($this->path."level.pmf", array(
"name" => $name,
"seed" => $this->seed,
"time" => 0,
"spawnX" => 128,
"spawnY" => 128,
"spawnZ" => 128,
"extra" => "",
"width" => $this->width,
"height" => $this->height
));
$entities = new Config($this->path."entities.yml", CONFIG_YAML);
$tileEntities = new Config($this->path."tileEntities.yml", CONFIG_YAML);
$this->level = new Level($level, $entities, $tileEntities, $name);
}
public function generate(){
for($Z = 0; $Z < $this->width; ++$Z){
for($X = 0; $X < $this->width; ++$X){
for($Y = 0; $Y < $this->height; ++$Y){
$this->generator->generateChunk($this->level, $X, $Y, $Z, $this->random);
$this->generator->populateChunk($this->level, $X, $Y, $Z, $this->random);
}
}
console("[NOTICE] Generating level ".ceil((($Z + 1)/$this->width) * 100)."%");
}
$this->generator->populateLevel($this->level, $this->random);
$this->level->setSpawn($this->generator->getSpawn($this->random));
$this->level->save(true);
}
}