mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-05-17 11:18:52 +00:00
Merge remote-tracking branch 'origin/master' into Entities
This commit is contained in:
commit
7ea0bf5067
@ -1,7 +1,9 @@
|
|||||||
language: php
|
language: php
|
||||||
|
|
||||||
php:
|
php:
|
||||||
|
- 5.4
|
||||||
- 5.5
|
- 5.5
|
||||||
|
- 5.6
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
- pecl install channel://pecl.php.net/pthreads-0.1.0
|
- pecl install channel://pecl.php.net/pthreads-0.1.0
|
||||||
|
@ -151,6 +151,10 @@ class LevelAPI{
|
|||||||
$path = DATA_PATH."worlds/".$name."/";
|
$path = DATA_PATH."worlds/".$name."/";
|
||||||
console("[INFO] Preparing level \"".$name."\"");
|
console("[INFO] Preparing level \"".$name."\"");
|
||||||
$level = new PMFLevel($path."level.pmf");
|
$level = new PMFLevel($path."level.pmf");
|
||||||
|
if(!$level->isLoaded){
|
||||||
|
console("[ERROR] Could not load level \"".$name."\"");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
$entities = new Config($path."entities.yml", CONFIG_YAML);
|
$entities = new Config($path."entities.yml", CONFIG_YAML);
|
||||||
if(file_exists($path."tileEntities.yml")){
|
if(file_exists($path."tileEntities.yml")){
|
||||||
@rename($path."tileEntities.yml", $path."tiles.yml");
|
@rename($path."tileEntities.yml", $path."tiles.yml");
|
||||||
@ -223,20 +227,6 @@ class LevelAPI{
|
|||||||
return $this->server->spawn;
|
return $this->server->spawn;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function loadMap(){
|
|
||||||
if($this->mapName !== false and trim($this->mapName) !== ""){
|
|
||||||
if(!file_exists($this->mapDir."level.pmf")){
|
|
||||||
$level = new LevelImport($this->mapDir);
|
|
||||||
$level->import();
|
|
||||||
}
|
|
||||||
$this->level = new PMFLevel($this->mapDir."level.pmf");
|
|
||||||
console("[INFO] Preparing level \"".$this->level->getData("name")."\"");
|
|
||||||
$this->time = (int) $this->level->getData("time");
|
|
||||||
$this->seed = (int) $this->level->getData("seed");
|
|
||||||
$this->spawn = $this->level->getSpawn();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getAll(){
|
public function getAll(){
|
||||||
return $this->levels;
|
return $this->levels;
|
||||||
}
|
}
|
||||||
|
@ -20,301 +20,319 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class PlayerAPI{
|
class PlayerAPI{
|
||||||
private $server;
|
private $server;
|
||||||
function __construct(){
|
function __construct(){
|
||||||
$this->server = ServerAPI::request();
|
$this->server = ServerAPI::request();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function init(){
|
public function init(){
|
||||||
$this->server->schedule(20 * 15, array($this, "handle"), 1, true, "server.regeneration");
|
$this->server->schedule(20 * 15, array($this, "handle"), 1, true, "server.regeneration");
|
||||||
$this->server->addHandler("player.death", array($this, "handle"), 1);
|
$this->server->addHandler("player.death", array($this, "handle"), 1);
|
||||||
$this->server->api->console->register("list", "", array($this, "commandHandler"));
|
$this->server->api->console->register("list", "", array($this, "commandHandler"));
|
||||||
$this->server->api->console->register("kill", "<player>", array($this, "commandHandler"));
|
$this->server->api->console->register("kill", "<player>", array($this, "commandHandler"));
|
||||||
$this->server->api->console->register("gamemode", "<mode> [player]", array($this, "commandHandler"));
|
$this->server->api->console->register("gamemode", "<mode> [player]", array($this, "commandHandler"));
|
||||||
$this->server->api->console->register("tp", "[target player] <destination player|w:world> OR /tp [target player] <x> <y> <z>", array($this, "commandHandler"));
|
$this->server->api->console->register("tp", "[target player] <destination player | w:world> OR /tp [target player] <x> <y> <z>", array($this, "commandHandler"));
|
||||||
$this->server->api->console->register("spawnpoint", "[player] [x] [y] [z]", array($this, "commandHandler"));
|
$this->server->api->console->register("spawnpoint", "[player | w:world] [x] [y] [z]", array($this, "commandHandler"));
|
||||||
$this->server->api->console->register("spawn", "", array($this, "commandHandler"));
|
$this->server->api->console->register("spawn", "", array($this, "commandHandler"));
|
||||||
$this->server->api->console->register("ping", "", array($this, "commandHandler"));
|
$this->server->api->console->register("ping", "", array($this, "commandHandler"));
|
||||||
$this->server->api->console->alias("lag", "ping");
|
$this->server->api->console->alias("lag", "ping");
|
||||||
$this->server->api->console->alias("suicide", "kill");
|
$this->server->api->console->alias("suicide", "kill");
|
||||||
$this->server->api->console->alias("tppos", "tp");
|
$this->server->api->console->alias("tppos", "tp");
|
||||||
$this->server->api->ban->cmdWhitelist("list");
|
$this->server->api->ban->cmdWhitelist("list");
|
||||||
$this->server->api->ban->cmdWhitelist("ping");
|
$this->server->api->ban->cmdWhitelist("ping");
|
||||||
$this->server->api->ban->cmdWhitelist("spawn");
|
$this->server->api->ban->cmdWhitelist("spawn");
|
||||||
$this->server->preparedSQL->selectPlayersToHeal = $this->server->database->prepare("SELECT EID FROM entities WHERE class = ".ENTITY_PLAYER." AND health < 20;");
|
$this->server->preparedSQL->selectPlayersToHeal = $this->server->database->prepare("SELECT EID FROM entities WHERE class = ".ENTITY_PLAYER." AND health < 20;");
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handle($data, $event){
|
public function handle($data, $event){
|
||||||
switch($event){
|
switch($event){
|
||||||
case "server.regeneration":
|
case "server.regeneration":
|
||||||
if($this->server->difficulty === 0){
|
if($this->server->difficulty === 0){
|
||||||
$result = $this->server->preparedSQL->selectPlayersToHeal->execute();
|
$result = $this->server->preparedSQL->selectPlayersToHeal->execute();
|
||||||
if($result !== false){
|
if($result !== false){
|
||||||
while(($player = $result->fetchArray()) !== false){
|
while(($player = $result->fetchArray()) !== false){
|
||||||
if(($player = $this->server->api->entity->get($player["EID"])) !== false){
|
if(($player = $this->server->api->entity->get($player["EID"])) !== false){
|
||||||
if($player->getHealth() <= 0){
|
if($player->getHealth() <= 0){
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$player->setHealth(min(20, $player->getHealth() + $data), "regeneration");
|
$player->setHealth(min(20, $player->getHealth() + $data), "regeneration");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "player.death":
|
case "player.death":
|
||||||
if(is_numeric($data["cause"])){
|
if(is_numeric($data["cause"])){
|
||||||
$e = $this->server->api->entity->get($data["cause"]);
|
$e = $this->server->api->entity->get($data["cause"]);
|
||||||
if($e instanceof Entity){
|
if($e instanceof Entity){
|
||||||
switch($e->class){
|
switch($e->class){
|
||||||
case ENTITY_PLAYER:
|
case ENTITY_PLAYER:
|
||||||
$message = " was killed by ".$e->name;
|
$message = " was killed by ".$e->name;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
$message = " was killed";
|
$message = " was killed";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
switch($data["cause"]){
|
switch($data["cause"]){
|
||||||
case "cactus":
|
case "cactus":
|
||||||
$message = " was pricked to death";
|
$message = " was pricked to death";
|
||||||
break;
|
break;
|
||||||
case "lava":
|
case "lava":
|
||||||
$message = " tried to swim in lava";
|
$message = " tried to swim in lava";
|
||||||
break;
|
break;
|
||||||
case "fire":
|
case "fire":
|
||||||
$message = " went up in flames";
|
$message = " went up in flames";
|
||||||
break;
|
break;
|
||||||
case "burning":
|
case "burning":
|
||||||
$message = " burned to death";
|
$message = " burned to death";
|
||||||
break;
|
break;
|
||||||
case "suffocation":
|
case "suffocation":
|
||||||
$message = " suffocated in a wall";
|
$message = " suffocated in a wall";
|
||||||
break;
|
break;
|
||||||
case "water":
|
case "water":
|
||||||
$message = " drowned";
|
$message = " drowned";
|
||||||
break;
|
break;
|
||||||
case "void":
|
case "void":
|
||||||
$message = " fell out of the world";
|
$message = " fell out of the world";
|
||||||
break;
|
break;
|
||||||
case "fall":
|
case "fall":
|
||||||
$message = " hit the ground too hard";
|
$message = " hit the ground too hard";
|
||||||
break;
|
break;
|
||||||
case "explosion":
|
case "explosion":
|
||||||
$message = " blew up";
|
$message = " blew up";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
$message = " died";
|
$message = " died";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$this->server->api->chat->broadcast($data["player"]->username . $message);
|
$this->server->api->chat->broadcast($data["player"]->username . $message);
|
||||||
return true;
|
return true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function commandHandler($cmd, $params, $issuer, $alias){
|
public function commandHandler($cmd, $params, $issuer, $alias){
|
||||||
$output = "";
|
$output = "";
|
||||||
switch($cmd){
|
switch($cmd){
|
||||||
case "spawnpoint":
|
case "spawnpoint":
|
||||||
if(!($issuer instanceof Player)){
|
if(count($params) === 0){
|
||||||
$output .= "Please run this command in-game.\n";
|
$output .= "Usage: /$cmd [player | w:world] [x] [y] [z]\n";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if(!($issuer instanceof Player) and count($params) < 4){
|
||||||
|
$output .= "Please run this command in-game.\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if(count($params) === 1 or count($params) === 4){
|
if(count($params) === 1 or count($params) === 4){
|
||||||
$target = $this->server->api->player->get(array_shift($params));
|
$tg = array_shift($params);
|
||||||
}else{
|
if(count($params) === 3 and substr($tg, 0, 2) === "w:"){
|
||||||
$target = $issuer;
|
$target = $this->server->api->level->get(substr($tg, 2));
|
||||||
}
|
}else{
|
||||||
|
$target = $this->server->api->player->get($tg);
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
$target = $issuer;
|
||||||
|
}
|
||||||
|
|
||||||
if(!($target instanceof Player)){
|
if(!($target instanceof Player) and !($target instanceof Level)){
|
||||||
$output .= "That player cannot be found.\n";
|
$output .= "That player cannot be found.\n";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(count($params) === 3){
|
if(count($params) === 3){
|
||||||
$spawn = new Position(floatval(array_shift($params)), floatval(array_shift($params)), floatval(array_shift($params)), $issuer->level);
|
if($target instanceof Level){
|
||||||
}else{
|
$spawn = new Vector3(floatval(array_shift($params)), floatval(array_shift($params)), floatval(array_shift($params)));
|
||||||
$spawn = new Position($issuer->entity->x, $issuer->entity->y, $issuer->entity->z, $issuer->entity->level);
|
}else{
|
||||||
}
|
$spawn = new Position(floatval(array_shift($params)), floatval(array_shift($params)), floatval(array_shift($params)), $issuer->level);
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
$spawn = new Position($issuer->entity->x, $issuer->entity->y, $issuer->entity->z, $issuer->entity->level);
|
||||||
|
}
|
||||||
|
|
||||||
$target->setSpawn($spawn);
|
$target->setSpawn($spawn);
|
||||||
|
if($target instanceof Level){
|
||||||
|
$output .= "Spawnpoint of world ".$target->getName()." set correctly!\n";
|
||||||
|
}elseif($target !== $issuer){
|
||||||
|
$output .= "Spawnpoint of ".$target->username." set correctly!\n";
|
||||||
|
}else{
|
||||||
|
$output .= "Spawnpoint set correctly!\n";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "spawn":
|
||||||
|
if(!($issuer instanceof Player)){
|
||||||
|
$output .= "Please run this command in-game.\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$issuer->teleport($this->server->spawn);
|
||||||
|
break;
|
||||||
|
case "ping":
|
||||||
|
if(!($issuer instanceof Player)){
|
||||||
|
$output .= "Please run this command in-game.\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$output .= "ping ".round($issuer->getLag(), 2)."ms, packet loss ".round($issuer->getPacketLoss() * 100, 2)."%, ".round($issuer->getBandwidth() / 1024, 2)." KB/s\n";
|
||||||
|
break;
|
||||||
|
case "gamemode":
|
||||||
|
$player = false;
|
||||||
|
$setgm = false;
|
||||||
|
$gms = array(
|
||||||
|
"0" => SURVIVAL,
|
||||||
|
"survival" => SURVIVAL,
|
||||||
|
"s" => SURVIVAL,
|
||||||
|
"1" => CREATIVE,
|
||||||
|
"creative" => CREATIVE,
|
||||||
|
"c" => CREATIVE,
|
||||||
|
"2" => ADVENTURE,
|
||||||
|
"adventure" => ADVENTURE,
|
||||||
|
"a" => ADVENTURE,
|
||||||
|
"3" => VIEW,
|
||||||
|
"view" => VIEW,
|
||||||
|
"viewer" => VIEW,
|
||||||
|
"spectator" => VIEW,
|
||||||
|
"v" => VIEW,
|
||||||
|
);
|
||||||
|
if($issuer instanceof Player){
|
||||||
|
$player = $issuer;
|
||||||
|
}
|
||||||
|
if(isset($params[1])){
|
||||||
|
if($this->server->api->player->get($params[1]) instanceof Player){
|
||||||
|
$player = $this->server->api->player->get($params[1]);
|
||||||
|
$setgm = $params[0];
|
||||||
|
}elseif($this->server->api->player->get($params[0]) instanceof Player){
|
||||||
|
$player = $this->server->api->player->get($params[0]);
|
||||||
|
$setgm = $params[1];
|
||||||
|
}else{
|
||||||
|
$output .= "Usage: /$cmd <mode> [player] or /$cmd [player] <mode>\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!($player instanceof Player) or !isset($gms[strtolower($setgm)])){
|
||||||
|
$output .= "Usage: /$cmd <mode> [player] or /$cmd [player] <mode>\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if($player->setGamemode($gms[strtolower($setgm)])){
|
||||||
|
$output .= "Gamemode of ".$player->username." changed to ".$player->getGamemode()."\n";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "tp":
|
||||||
|
if(count($params) <= 2 or substr($params[0], 0, 2) === "w:" or substr($params[1], 0, 2) === "w:"){
|
||||||
|
if((!isset($params[1]) or substr($params[0], 0, 2) === "w:") and isset($params[0]) and ($issuer instanceof Player)){
|
||||||
|
$name = $issuer->username;
|
||||||
|
$target = implode(" ", $params);
|
||||||
|
}elseif(isset($params[1]) and isset($params[0])){
|
||||||
|
$name = array_shift($params);
|
||||||
|
$target = implode(" ", $params);
|
||||||
|
}else{
|
||||||
|
$output .= "Usage: /$cmd [target player] <destination player | w:world>\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if($this->teleport($name, $target) !== false){
|
||||||
|
$output .= "\"$name\" teleported to \"$target\"\n";
|
||||||
|
}else{
|
||||||
|
$output .= "Couldn't teleport.\n";
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
if(!isset($params[3]) and isset($params[2]) and isset($params[1]) and isset($params[0]) and ($issuer instanceof Player)){
|
||||||
|
$name = $issuer->username;
|
||||||
|
$x = $params[0];
|
||||||
|
$y = $params[1];
|
||||||
|
$z = $params[2];
|
||||||
|
}elseif(isset($params[3]) and isset($params[2]) and isset($params[1]) and isset($params[0])){
|
||||||
|
$name = $params[0];
|
||||||
|
$x = $params[1];
|
||||||
|
$y = $params[2];
|
||||||
|
$z = $params[3];
|
||||||
|
}else{
|
||||||
|
$output .= "Usage: /$cmd [player] <x> <y> <z>\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if($this->tppos($name, $x, $y, $z)){
|
||||||
|
$output .= "\"$name\" teleported to ($x, $y, $z)\n";
|
||||||
|
}else{
|
||||||
|
$output .= "Couldn't teleport.\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "kill":
|
||||||
|
case "suicide":
|
||||||
|
if(!isset($params[0]) and ($issuer instanceof Player)){
|
||||||
|
$player = $issuer;
|
||||||
|
}else{
|
||||||
|
$player = $this->get($params[0]);
|
||||||
|
}
|
||||||
|
if($player instanceof Player){
|
||||||
|
$player->entity->harm(1000, "console", true);
|
||||||
|
$player->sendChat("Ouch. That looks like it hurt.\n");
|
||||||
|
}else{
|
||||||
|
$output .= "Usage: /$cmd [player]\n";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "list":
|
||||||
|
$output .= "There are ".count($this->server->clients)."/".$this->server->maxClients." players online:\n";
|
||||||
|
if(count($this->server->clients) == 0){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
foreach($this->server->clients as $c){
|
||||||
|
$output .= $c->username.", ";
|
||||||
|
}
|
||||||
|
$output = substr($output, 0, -2)."\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return $output;
|
||||||
|
}
|
||||||
|
|
||||||
$output .= "Spawnpoint set correctly!\n";
|
public function teleport(&$name, &$target){
|
||||||
break;
|
if(substr($target, 0, 2) === "w:"){
|
||||||
case "spawn":
|
$lv = $this->server->api->level->get(substr($target, 2));
|
||||||
if(!($issuer instanceof Player)){
|
if($lv instanceof Level){
|
||||||
$output .= "Please run this command in-game.\n";
|
$origin = $this->get($name);
|
||||||
break;
|
if($origin instanceof Player){
|
||||||
}
|
$name = $origin->username;
|
||||||
$issuer->teleport($this->server->spawn);
|
return $origin->teleport($lv->getSafeSpawn());
|
||||||
break;
|
}
|
||||||
case "ping":
|
}else{
|
||||||
if(!($issuer instanceof Player)){
|
return false;
|
||||||
$output .= "Please run this command in-game.\n";
|
}
|
||||||
break;
|
}
|
||||||
}
|
$player = $this->get($target);
|
||||||
$output .= "ping ".round($issuer->getLag(), 2)."ms, packet loss ".round($issuer->getPacketLoss() * 100, 2)."%, ".round($issuer->getBandwidth() / 1024, 2)." KB/s\n";
|
if(($player instanceof Player) and ($player->entity instanceof Entity)){
|
||||||
break;
|
$target = $player->username;
|
||||||
case "gamemode":
|
$origin = $this->get($name);
|
||||||
$player = false;
|
if($origin instanceof Player){
|
||||||
$setgm = false;
|
$name = $origin->username;
|
||||||
$gms = array(
|
return $origin->teleport($player->entity);
|
||||||
"0" => SURVIVAL,
|
}
|
||||||
"survival" => SURVIVAL,
|
}
|
||||||
"s" => SURVIVAL,
|
return false;
|
||||||
"1" => CREATIVE,
|
}
|
||||||
"creative" => CREATIVE,
|
|
||||||
"c" => CREATIVE,
|
|
||||||
"2" => ADVENTURE,
|
|
||||||
"adventure" => ADVENTURE,
|
|
||||||
"a" => ADVENTURE,
|
|
||||||
"3" => VIEW,
|
|
||||||
"view" => VIEW,
|
|
||||||
"viewer" => VIEW,
|
|
||||||
"spectator" => VIEW,
|
|
||||||
"v" => VIEW,
|
|
||||||
);
|
|
||||||
if($issuer instanceof Player){
|
|
||||||
$player = $issuer;
|
|
||||||
}
|
|
||||||
if(isset($params[1])){
|
|
||||||
if($this->server->api->player->get($params[1]) instanceof Player){
|
|
||||||
$player = $this->server->api->player->get($params[1]);
|
|
||||||
$setgm = $params[0];
|
|
||||||
}elseif($this->server->api->player->get($params[0]) instanceof Player){
|
|
||||||
$player = $this->server->api->player->get($params[0]);
|
|
||||||
$setgm = $params[1];
|
|
||||||
}else{
|
|
||||||
$output .= "Usage: /$cmd <mode> [player] or /$cmd [player] <mode>\n";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!($player instanceof Player) or !isset($gms[strtolower($setgm)])){
|
|
||||||
$output .= "Usage: /$cmd <mode> [player] or /$cmd [player] <mode>\n";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if($player->setGamemode($gms[strtolower($setgm)])){
|
|
||||||
$output .= "Gamemode of ".$player->username." changed to ".$player->getGamemode()."\n";
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "tp":
|
|
||||||
if(count($params) <= 2 or substr($params[0], 0, 2) === "w:" or substr($params[1], 0, 2) === "w:"){
|
|
||||||
if((!isset($params[1]) or substr($params[0], 0, 2) === "w:") and isset($params[0]) and ($issuer instanceof Player)){
|
|
||||||
$name = $issuer->username;
|
|
||||||
$target = implode(" ", $params);
|
|
||||||
}elseif(isset($params[1]) and isset($params[0])){
|
|
||||||
$name = array_shift($params);
|
|
||||||
$target = implode(" ", $params);
|
|
||||||
}else{
|
|
||||||
$output .= "Usage: /$cmd [target player] <destination player>\n";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if($this->teleport($name, $target) !== false){
|
|
||||||
$output .= "\"$name\" teleported to \"$target\"\n";
|
|
||||||
}else{
|
|
||||||
$output .= "Couldn't teleport.\n";
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
if(!isset($params[3]) and isset($params[2]) and isset($params[1]) and isset($params[0]) and ($issuer instanceof Player)){
|
|
||||||
$name = $issuer->username;
|
|
||||||
$x = $params[0];
|
|
||||||
$y = $params[1];
|
|
||||||
$z = $params[2];
|
|
||||||
}elseif(isset($params[3]) and isset($params[2]) and isset($params[1]) and isset($params[0])){
|
|
||||||
$name = $params[0];
|
|
||||||
$x = $params[1];
|
|
||||||
$y = $params[2];
|
|
||||||
$z = $params[3];
|
|
||||||
}else{
|
|
||||||
$output .= "Usage: /$cmd [player] <x> <y> <z>\n";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if($this->tppos($name, $x, $y, $z)){
|
|
||||||
$output .= "\"$name\" teleported to ($x, $y, $z)\n";
|
|
||||||
}else{
|
|
||||||
$output .= "Couldn't teleport.\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "kill":
|
|
||||||
case "suicide":
|
|
||||||
if(!isset($params[0]) and ($issuer instanceof Player)){
|
|
||||||
$player = $issuer;
|
|
||||||
}else{
|
|
||||||
$player = $this->get($params[0]);
|
|
||||||
}
|
|
||||||
if($player instanceof Player){
|
|
||||||
$player->entity->harm(1000, "console", true);
|
|
||||||
$player->sendChat("Ouch. That looks like it hurt.\n");
|
|
||||||
}else{
|
|
||||||
$output .= "Usage: /$cmd [player]\n";
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "list":
|
|
||||||
$output .= "There are ".count($this->server->clients)."/".$this->server->maxClients." players online:\n";
|
|
||||||
if(count($this->server->clients) == 0){
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
foreach($this->server->clients as $c){
|
|
||||||
$output .= $c->username.", ";
|
|
||||||
}
|
|
||||||
$output = substr($output, 0, -2)."\n";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return $output;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function teleport(&$name, &$target){
|
public function tppos(&$name, &$x, &$y, &$z){
|
||||||
if(substr($target, 0, 2) === "w:"){
|
$player = $this->get($name);
|
||||||
$lv = $this->server->api->level->get(substr($target, 2));
|
if(($player instanceof Player) and ($player->entity instanceof Entity)){
|
||||||
if($lv instanceof Level){
|
$name = $player->username;
|
||||||
$origin = $this->get($name);
|
$x = $x{0} === "~" ? $player->entity->x + floatval(substr($x, 1)):floatval($x);
|
||||||
if($origin instanceof Player){
|
$y = $y{0} === "~" ? $player->entity->y + floatval(substr($y, 1)):floatval($y);
|
||||||
$name = $origin->username;
|
$z = $z{0} === "~" ? $player->entity->z + floatval(substr($z, 1)):floatval($z);
|
||||||
return $origin->teleport($lv->getSafeSpawn());
|
$player->teleport(new Vector3($x, $y, $z));
|
||||||
}
|
return true;
|
||||||
}else{
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
$player = $this->get($target);
|
|
||||||
if(($player instanceof Player) and ($player->entity instanceof Entity)){
|
|
||||||
$target = $player->username;
|
|
||||||
$origin = $this->get($name);
|
|
||||||
if($origin instanceof Player){
|
|
||||||
$name = $origin->username;
|
|
||||||
return $origin->teleport($player->entity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function tppos(&$name, &$x, &$y, &$z){
|
public function get($name, $alike = true, $multiple = false){
|
||||||
$player = $this->get($name);
|
$name = trim(strtolower($name));
|
||||||
if(($player instanceof Player) and ($player->entity instanceof Entity)){
|
if($name === ""){
|
||||||
$name = $player->username;
|
return false;
|
||||||
$x = $x{0} === "~" ? $player->entity->x + floatval(substr($x, 1)):floatval($x);
|
}
|
||||||
$y = $y{0} === "~" ? $player->entity->y + floatval(substr($y, 1)):floatval($y);
|
$query = $this->server->query("SELECT ip,port,name FROM players WHERE name ".($alike === true ? "LIKE '%".$name."%'":"= '".$name."'").";");
|
||||||
$z = $z{0} === "~" ? $player->entity->z + floatval(substr($z, 1)):floatval($z);
|
|
||||||
$player->teleport(new Vector3($x, $y, $z));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function get($name, $alike = true, $multiple = false){
|
|
||||||
$name = trim(strtolower($name));
|
|
||||||
if($name === ""){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$query = $this->server->query("SELECT ip,port,name FROM players WHERE name ".($alike === true ? "LIKE '%".$name."%'":"= '".$name."'").";");
|
|
||||||
$players = array();
|
$players = array();
|
||||||
if($query !== false and $query !== true){
|
if($query !== false and $query !== true){
|
||||||
while(($d = $query->fetchArray(SQLITE3_ASSOC)) !== false){
|
while(($d = $query->fetchArray(SQLITE3_ASSOC)) !== false){
|
||||||
$CID = PocketMinecraftServer::clientID($d["ip"], $d["port"]);
|
$CID = PocketMinecraftServer::clientID($d["ip"], $d["port"]);
|
||||||
if(isset($this->server->clients[$CID])){
|
if(isset($this->server->clients[$CID])){
|
||||||
$players[$CID] = $this->server->clients[$CID];
|
$players[$CID] = $this->server->clients[$CID];
|
||||||
@ -322,7 +340,7 @@ class PlayerAPI{
|
|||||||
return $players[$CID];
|
return $players[$CID];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if($multiple === false){
|
if($multiple === false){
|
||||||
@ -334,74 +352,74 @@ class PlayerAPI{
|
|||||||
}else{
|
}else{
|
||||||
return $players;
|
return $players;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getAll($level = null){
|
public function getAll($level = null){
|
||||||
if($level instanceof Level){
|
if($level instanceof Level){
|
||||||
$clients = array();
|
$clients = array();
|
||||||
$l = $this->server->query("SELECT EID FROM entities WHERE level = '".$level->getName()."' AND class = '".ENTITY_PLAYER."';");
|
$l = $this->server->query("SELECT EID FROM entities WHERE level = '".$level->getName()."' AND class = '".ENTITY_PLAYER."';");
|
||||||
if($l !== false and $l !== true){
|
if($l !== false and $l !== true){
|
||||||
while(($e = $l->fetchArray(SQLITE3_ASSOC)) !== false){
|
while(($e = $l->fetchArray(SQLITE3_ASSOC)) !== false){
|
||||||
$e = $this->getByEID($e["EID"]);
|
$e = $this->getByEID($e["EID"]);
|
||||||
if($e instanceof Player){
|
if($e instanceof Player){
|
||||||
$clients[$e->CID] = $e;
|
$clients[$e->CID] = $e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $clients;
|
return $clients;
|
||||||
}
|
}
|
||||||
return $this->server->clients;
|
return $this->server->clients;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function broadcastPacket(array $players, RakNetDataPacket $packet){
|
public function broadcastPacket(array $players, RakNetDataPacket $packet){
|
||||||
foreach($players as $p){
|
foreach($players as $p){
|
||||||
$p->dataPacket(clone $packet);
|
$p->dataPacket(clone $packet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getByEID($eid){
|
public function getByEID($eid){
|
||||||
$eid = (int) $eid;
|
$eid = (int) $eid;
|
||||||
$CID = $this->server->query("SELECT ip,port FROM players WHERE EID = '".$eid."';", true);
|
$CID = $this->server->query("SELECT ip,port FROM players WHERE EID = '".$eid."';", true);
|
||||||
$CID = PocketMinecraftServer::clientID($CID["ip"], $CID["port"]);
|
$CID = PocketMinecraftServer::clientID($CID["ip"], $CID["port"]);
|
||||||
if(isset($this->server->clients[$CID])){
|
if(isset($this->server->clients[$CID])){
|
||||||
return $this->server->clients[$CID];
|
return $this->server->clients[$CID];
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function online(){
|
public function online(){
|
||||||
$o = array();
|
$o = array();
|
||||||
foreach($this->server->clients as $p){
|
foreach($this->server->clients as $p){
|
||||||
if($p->auth === true){
|
if($p->auth === true){
|
||||||
$o[] = $p->username;
|
$o[] = $p->username;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $o;
|
return $o;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function add($CID){
|
public function add($CID){
|
||||||
if(isset($this->server->clients[$CID])){
|
if(isset($this->server->clients[$CID])){
|
||||||
$player = $this->server->clients[$CID];
|
$player = $this->server->clients[$CID];
|
||||||
$player->data = $this->getOffline($player->username);
|
$player->data = $this->getOffline($player->username);
|
||||||
$player->gamemode = $player->data->get("gamemode");
|
$player->gamemode = $player->data->get("gamemode");
|
||||||
if(($player->level = $this->server->api->level->get($player->data->get("position")["level"])) === false){
|
if(($player->level = $this->server->api->level->get($player->data->get("position")["level"])) === false){
|
||||||
$player->level = $this->server->api->level->getDefault();
|
$player->level = $this->server->api->level->getDefault();
|
||||||
$player->data->set("position", array(
|
$player->data->set("position", array(
|
||||||
"level" => $player->level->getName(),
|
"level" => $player->level->getName(),
|
||||||
"x" => $player->level->getSpawn()->x,
|
"x" => $player->level->getSpawn()->x,
|
||||||
"y" => $player->level->getSpawn()->y,
|
"y" => $player->level->getSpawn()->y,
|
||||||
"z" => $player->level->getSpawn()->z,
|
"z" => $player->level->getSpawn()->z,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
$this->server->query("INSERT OR REPLACE INTO players (CID, ip, port, name) VALUES (".$player->CID.", '".$player->ip."', ".$player->port.", '".strtolower($player->username)."');");
|
$this->server->query("INSERT OR REPLACE INTO players (CID, ip, port, name) VALUES (".$player->CID.", '".$player->ip."', ".$player->port.", '".strtolower($player->username)."');");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function spawnAllPlayers(Player $player){
|
public function spawnAllPlayers(Player $player){
|
||||||
foreach($this->getAll() as $p){
|
foreach($this->getAll() as $p){
|
||||||
if($p !== $player and ($p->entity instanceof Entity)){
|
if($p !== $player and ($p->entity instanceof Entity)){
|
||||||
$p->entity->spawn($player);
|
$p->entity->spawn($player);
|
||||||
if($p->level !== $player->level){
|
if($p->level !== $player->level){
|
||||||
$pk = new MoveEntityPacket_PosRot;
|
$pk = new MoveEntityPacket_PosRot;
|
||||||
$pk->eid = $p->entity->eid;
|
$pk->eid = $p->entity->eid;
|
||||||
$pk->x = -256;
|
$pk->x = -256;
|
||||||
@ -409,17 +427,17 @@ class PlayerAPI{
|
|||||||
$pk->z = -256;
|
$pk->z = -256;
|
||||||
$pk->yaw = 0;
|
$pk->yaw = 0;
|
||||||
$pk->pitch = 0;
|
$pk->pitch = 0;
|
||||||
$player->dataPacket($pk);
|
$player->dataPacket($pk);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function spawnToAllPlayers(Player $player){
|
public function spawnToAllPlayers(Player $player){
|
||||||
foreach($this->getAll() as $p){
|
foreach($this->getAll() as $p){
|
||||||
if($p !== $player and ($p->entity instanceof Entity) and ($player->entity instanceof Entity)){
|
if($p !== $player and ($p->entity instanceof Entity) and ($player->entity instanceof Entity)){
|
||||||
$player->entity->spawn($p);
|
$player->entity->spawn($p);
|
||||||
if($p->level !== $player->level){
|
if($p->level !== $player->level){
|
||||||
$pk = new MoveEntityPacket_PosRot;
|
$pk = new MoveEntityPacket_PosRot;
|
||||||
$pk->eid = $player->entity->eid;
|
$pk->eid = $player->entity->eid;
|
||||||
$pk->x = -256;
|
$pk->x = -256;
|
||||||
@ -427,74 +445,74 @@ class PlayerAPI{
|
|||||||
$pk->z = -256;
|
$pk->z = -256;
|
||||||
$pk->yaw = 0;
|
$pk->yaw = 0;
|
||||||
$pk->pitch = 0;
|
$pk->pitch = 0;
|
||||||
$p->dataPacket($pk);
|
$p->dataPacket($pk);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function remove($CID){
|
public function remove($CID){
|
||||||
if(isset($this->server->clients[$CID])){
|
if(isset($this->server->clients[$CID])){
|
||||||
$player = $this->server->clients[$CID];
|
$player = $this->server->clients[$CID];
|
||||||
unset($this->server->clients[$CID]);
|
unset($this->server->clients[$CID]);
|
||||||
$player->close();
|
$player->close();
|
||||||
if($player->username != "" and ($player->data instanceof Config)){
|
if($player->username != "" and ($player->data instanceof Config)){
|
||||||
$this->saveOffline($player->data);
|
$this->saveOffline($player->data);
|
||||||
}
|
}
|
||||||
$this->server->query("DELETE FROM players WHERE name = '".$player->username."';");
|
$this->server->query("DELETE FROM players WHERE name = '".$player->username."';");
|
||||||
if($player->entity instanceof Entity){
|
if($player->entity instanceof Entity){
|
||||||
unset($player->entity->player);
|
unset($player->entity->player);
|
||||||
//unset($player->entity);
|
//unset($player->entity);
|
||||||
}
|
}
|
||||||
$this->server->api->entity->remove($player->eid);
|
$this->server->api->entity->remove($player->eid);
|
||||||
$player = null;
|
$player = null;
|
||||||
unset($player);
|
unset($player);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getOffline($name){
|
public function getOffline($name){
|
||||||
$iname = strtolower($name);
|
$iname = strtolower($name);
|
||||||
$default = array(
|
$default = array(
|
||||||
"caseusername" => $name,
|
"caseusername" => $name,
|
||||||
"position" => array(
|
"position" => array(
|
||||||
"level" => $this->server->spawn->level->getName(),
|
"level" => $this->server->spawn->level->getName(),
|
||||||
"x" => $this->server->spawn->x,
|
"x" => $this->server->spawn->x,
|
||||||
"y" => $this->server->spawn->y,
|
"y" => $this->server->spawn->y,
|
||||||
"z" => $this->server->spawn->z,
|
"z" => $this->server->spawn->z,
|
||||||
),
|
),
|
||||||
"spawn" => array(
|
"spawn" => array(
|
||||||
"level" => $this->server->spawn->level->getName(),
|
"level" => $this->server->spawn->level->getName(),
|
||||||
"x" => $this->server->spawn->x,
|
"x" => $this->server->spawn->x,
|
||||||
"y" => $this->server->spawn->y,
|
"y" => $this->server->spawn->y,
|
||||||
"z" => $this->server->spawn->z,
|
"z" => $this->server->spawn->z,
|
||||||
),
|
),
|
||||||
"inventory" => array_fill(0, PLAYER_SURVIVAL_SLOTS, array(AIR, 0, 0)),
|
"inventory" => array_fill(0, PLAYER_SURVIVAL_SLOTS, array(AIR, 0, 0)),
|
||||||
"hotbar" => array(0, -1, -1, -1, -1, -1, -1, -1, -1),
|
"hotbar" => array(0, -1, -1, -1, -1, -1, -1, -1, -1),
|
||||||
"armor" => array_fill(0, 4, array(AIR, 0)),
|
"armor" => array_fill(0, 4, array(AIR, 0)),
|
||||||
"gamemode" => $this->server->gamemode,
|
"gamemode" => $this->server->gamemode,
|
||||||
"health" => 20,
|
"health" => 20,
|
||||||
"lastIP" => "",
|
"lastIP" => "",
|
||||||
"lastID" => 0,
|
"lastID" => 0,
|
||||||
"achievements" => array(),
|
"achievements" => array(),
|
||||||
);
|
);
|
||||||
|
|
||||||
if(!file_exists(DATA_PATH."players/".$iname.".yml")){
|
if(!file_exists(DATA_PATH."players/".$iname.".yml")){
|
||||||
console("[NOTICE] Player data not found for \"".$iname."\", creating new profile");
|
console("[NOTICE] Player data not found for \"".$iname."\", creating new profile");
|
||||||
$data = new Config(DATA_PATH."players/".$iname.".yml", CONFIG_YAML, $default);
|
$data = new Config(DATA_PATH."players/".$iname.".yml", CONFIG_YAML, $default);
|
||||||
$data->save();
|
$data->save();
|
||||||
}else{
|
}else{
|
||||||
$data = new Config(DATA_PATH."players/".$iname.".yml", CONFIG_YAML, $default);
|
$data = new Config(DATA_PATH."players/".$iname.".yml", CONFIG_YAML, $default);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(($data->get("gamemode") & 0x01) === 1){
|
if(($data->get("gamemode") & 0x01) === 1){
|
||||||
$data->set("health", 20);
|
$data->set("health", 20);
|
||||||
}
|
}
|
||||||
$this->server->handle("player.offline.get", $data);
|
$this->server->handle("player.offline.get", $data);
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function saveOffline(Config $data){
|
public function saveOffline(Config $data){
|
||||||
$this->server->handle("player.offline.save", $data);
|
$this->server->handle("player.offline.save", $data);
|
||||||
$data->save();
|
$data->save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -147,7 +147,7 @@ class ServerAPI{
|
|||||||
//Load advanced properties
|
//Load advanced properties
|
||||||
define("DEBUG", $this->getProperty("debug", 1));
|
define("DEBUG", $this->getProperty("debug", 1));
|
||||||
define("ADVANCED_CACHE", $this->getProperty("enable-advanced-cache", false));
|
define("ADVANCED_CACHE", $this->getProperty("enable-advanced-cache", false));
|
||||||
define("MAX_CHUNK_RATE", 20 / $this->getProperty("max-chunks-per-second", 8)); //Default rate ~512 kB/s
|
define("MAX_CHUNK_RATE", 20 / $this->getProperty("max-chunks-per-second", 7)); //Default rate ~448 kB/s
|
||||||
if(ADVANCED_CACHE == true){
|
if(ADVANCED_CACHE == true){
|
||||||
console("[INFO] Advanced cache enabled");
|
console("[INFO] Advanced cache enabled");
|
||||||
}
|
}
|
||||||
|
@ -420,6 +420,11 @@ class PocketMinecraftServer{
|
|||||||
$dump .= "[".($l + 1)."] ".@$file[$l]."\r\n";
|
$dump .= "[".($l + 1)."] ".@$file[$l]."\r\n";
|
||||||
}
|
}
|
||||||
$dump .= "\r\n\r\n";
|
$dump .= "\r\n\r\n";
|
||||||
|
$dump .= "Backtrace: \r\n";
|
||||||
|
foreach(getTrace() as $line){
|
||||||
|
$dump .= "$line\r\n";
|
||||||
|
}
|
||||||
|
$dump .= "\r\n\r\n";
|
||||||
$version = new VersionString();
|
$version = new VersionString();
|
||||||
$dump .= "PocketMine-MP version: ".$version." #".$version->getNumber()." [Protocol ".ProtocolInfo::CURRENT_PROTOCOL."; API ".CURRENT_API_VERSION."]\r\n";
|
$dump .= "PocketMine-MP version: ".$version." #".$version->getNumber()." [Protocol ".ProtocolInfo::CURRENT_PROTOCOL."; API ".CURRENT_API_VERSION."]\r\n";
|
||||||
$dump .= "Git commit: ".GIT_COMMIT."\r\n";
|
$dump .= "Git commit: ".GIT_COMMIT."\r\n";
|
||||||
|
@ -217,6 +217,21 @@ function console($message, $EOL = true, $log = true, $level = 1){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getTrace($start = 1){
|
||||||
|
$e = new Exception();
|
||||||
|
$trace = $e->getTrace();
|
||||||
|
$messages = array();
|
||||||
|
$j = 0;
|
||||||
|
for($i = (int) $start; isset($trace[$i]); ++$i, ++$j){
|
||||||
|
$params = "";
|
||||||
|
foreach($trace[$i]["args"] as $name => $value){
|
||||||
|
$params .= (is_object($value) ? get_class($value)." ".(method_exists($value, "__toString") ? $value->__toString() : "object"):gettype($value)." ".@strval($value)).", ";
|
||||||
|
}
|
||||||
|
$messages[] = "#$j ".(isset($trace[$i]["file"]) ? $trace[$i]["file"]:"")."(".(isset($trace[$i]["line"]) ? $trace[$i]["line"]:"")."): ".(isset($trace[$i]["class"]) ? $trace[$i]["class"].$trace[$i]["type"]:"").$trace[$i]["function"]."(".substr($params, 0, -2).")";
|
||||||
|
}
|
||||||
|
return $messages;
|
||||||
|
}
|
||||||
|
|
||||||
function error_handler($errno, $errstr, $errfile, $errline){
|
function error_handler($errno, $errstr, $errfile, $errline){
|
||||||
if(error_reporting() === 0){ //@ error-control
|
if(error_reporting() === 0){ //@ error-control
|
||||||
return false;
|
return false;
|
||||||
@ -240,6 +255,9 @@ function error_handler($errno, $errstr, $errfile, $errline){
|
|||||||
);
|
);
|
||||||
$errno = isset($errorConversion[$errno]) ? $errorConversion[$errno]:$errno;
|
$errno = isset($errorConversion[$errno]) ? $errorConversion[$errno]:$errno;
|
||||||
console("[ERROR] A ".$errno." error happened: \"$errstr\" in \"$errfile\" at line $errline", true, true, 0);
|
console("[ERROR] A ".$errno." error happened: \"$errstr\" in \"$errfile\" at line $errline", true, true, 0);
|
||||||
|
foreach(getTrace() as $i => $line){
|
||||||
|
console("[TRACE] $line");
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,13 +46,16 @@ class PMFLevel extends PMF{
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function close(){
|
public function closeLevel(){
|
||||||
$this->chunks = null;
|
$this->chunks = null;
|
||||||
unset($this->chunks, $this->chunkChange, $this->chunkInfo, $this->level);
|
unset($this->chunks, $this->chunkChange, $this->chunkInfo, $this->level);
|
||||||
parent::close();
|
$this->close();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __construct($file, $blank = false){
|
public function __construct($file, $blank = false){
|
||||||
|
$this->chunks = array();
|
||||||
|
$this->chunkChange = array();
|
||||||
|
$this->chunkInfo = array();
|
||||||
if(is_array($blank)){
|
if(is_array($blank)){
|
||||||
$this->create($file, 0);
|
$this->create($file, 0);
|
||||||
$this->levelData = $blank;
|
$this->levelData = $blank;
|
||||||
@ -145,8 +148,6 @@ class PMFLevel extends PMF{
|
|||||||
$X = $index & 0x0F;
|
$X = $index & 0x0F;
|
||||||
$Z = $index >> 4;
|
$Z = $index >> 4;
|
||||||
|
|
||||||
$this->chunks[$index] = false;
|
|
||||||
$this->chunkChange[$index] = false;
|
|
||||||
$bitflags = Utils::readShort($this->read(2));
|
$bitflags = Utils::readShort($this->read(2));
|
||||||
$oldPath = dirname($this->file)."/chunks/".$Z.".".$X.".pmc";
|
$oldPath = dirname($this->file)."/chunks/".$Z.".".$X.".pmc";
|
||||||
$chunkOld = gzopen($oldPath, "rb");
|
$chunkOld = gzopen($oldPath, "rb");
|
||||||
@ -168,7 +169,7 @@ class PMFLevel extends PMF{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static function getIndex($X, $Z){
|
public static function getIndex($X, $Z){
|
||||||
return ($Z << 16) + $X;
|
return ($Z << 16) | ($X < 0 ? (~--$X & 0x7fff) | 0x1000 : $X & 0xFFFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getXZ($index, &$X = null, &$Z = null){
|
public static function getXZ($index, &$X = null, &$Z = null){
|
||||||
@ -186,15 +187,36 @@ class PMFLevel extends PMF{
|
|||||||
if(!file_exists(dirname($path))){
|
if(!file_exists(dirname($path))){
|
||||||
@mkdir(dirname($path), 0755);
|
@mkdir(dirname($path), 0755);
|
||||||
}
|
}
|
||||||
++$this->isGenerating;
|
|
||||||
$this->initCleanChunk($X, $Z);
|
$this->initCleanChunk($X, $Z);
|
||||||
$ret = $this->level->generateChunk($X, $Z);
|
$ret = $this->level->generateChunk($X, $Z);
|
||||||
$ret = $ret and $this->level->populateChunk($X, $Z);
|
|
||||||
$this->saveChunk($X, $Z);
|
$this->saveChunk($X, $Z);
|
||||||
--$this->isGenerating;
|
$this->populateChunk($X - 1, $Z);
|
||||||
|
$this->populateChunk($X + 1, $Z);
|
||||||
|
$this->populateChunk($X, $Z - 1);
|
||||||
|
$this->populateChunk($X, $Z + 1);
|
||||||
|
$this->populateChunk($X + 1, $Z + 1);
|
||||||
|
$this->populateChunk($X + 1, $Z - 1);
|
||||||
|
$this->populateChunk($X - 1, $Z - 1);
|
||||||
|
$this->populateChunk($X - 1, $Z + 1);
|
||||||
return $ret;
|
return $ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function populateChunk($X, $Z){
|
||||||
|
if($this->isGenerating === 0 and
|
||||||
|
!$this->isPopulated($X, $Z) and
|
||||||
|
$this->isGenerated($X - 1, $Z) and
|
||||||
|
$this->isGenerated($X, $Z - 1) and
|
||||||
|
$this->isGenerated($X + 1, $Z) and
|
||||||
|
$this->isGenerated($X, $Z + 1) and
|
||||||
|
$this->isGenerated($X + 1, $Z + 1) and
|
||||||
|
$this->isGenerated($X - 1, $Z - 1) and
|
||||||
|
$this->isGenerated($X + 1, $Z - 1) and
|
||||||
|
$this->isGenerated($X - 1, $Z + 1)){
|
||||||
|
$this->level->populateChunk($X, $Z);
|
||||||
|
$this->saveChunk($X, $Z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function loadChunk($X, $Z){
|
public function loadChunk($X, $Z){
|
||||||
$X = (int) $X;
|
$X = (int) $X;
|
||||||
$Z = (int) $Z;
|
$Z = (int) $Z;
|
||||||
@ -204,20 +226,14 @@ class PMFLevel extends PMF{
|
|||||||
}
|
}
|
||||||
$path = $this->getChunkPath($X, $Z);
|
$path = $this->getChunkPath($X, $Z);
|
||||||
if(!file_exists($path)){
|
if(!file_exists($path)){
|
||||||
if($this->isGenerating > 0){
|
if($this->generateChunk($X, $Z) === false){
|
||||||
$this->level->generateChunk($X, $Z);
|
|
||||||
$this->saveChunk($X, $Z);
|
|
||||||
}elseif($this->generateChunk($X, $Z) === false){
|
|
||||||
return false;
|
return false;
|
||||||
|
}elseif($this->isGenerating === 0){
|
||||||
|
$this->populateChunk($X, $Z);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if($this->isGenerating === 0 and !$this->isPopulated($X, $Z)){
|
|
||||||
++$this->isGenerating;
|
|
||||||
$this->level->populateChunk($X, $Z);
|
|
||||||
--$this->isGenerating;
|
|
||||||
}
|
|
||||||
|
|
||||||
$chunk = @gzopen($path, "rb");
|
$chunk = @gzopen($path, "rb");
|
||||||
if($chunk === false){
|
if($chunk === false){
|
||||||
return false;
|
return false;
|
||||||
@ -233,7 +249,7 @@ class PMFLevel extends PMF{
|
|||||||
if(($this->chunkInfo[$index][0] & $t) === $t){
|
if(($this->chunkInfo[$index][0] & $t) === $t){
|
||||||
// 4096 + 2048 + 2048, Block Data, Meta, Light
|
// 4096 + 2048 + 2048, Block Data, Meta, Light
|
||||||
if(strlen($this->chunks[$index][$Y] = gzread($chunk, 8192)) < 8192){
|
if(strlen($this->chunks[$index][$Y] = gzread($chunk, 8192)) < 8192){
|
||||||
console("[NOTICE] Empty corrupt chunk detected [$X,$Z,:$Y], recovering contents");
|
console("[NOTICE] Empty corrupt chunk detected [$X,$Z,:$Y], recovering contents", true, true, 2);
|
||||||
$this->fillMiniChunk($X, $Z, $Y);
|
$this->fillMiniChunk($X, $Z, $Y);
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
@ -241,6 +257,9 @@ class PMFLevel extends PMF{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
@gzclose($chunk);
|
@gzclose($chunk);
|
||||||
|
if($this->isGenerating === 0 and !$this->isPopulated($X, $Z)){
|
||||||
|
$this->populateChunk($X, $Z);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -262,15 +281,15 @@ class PMFLevel extends PMF{
|
|||||||
|
|
||||||
public function isChunkLoaded($X, $Z){
|
public function isChunkLoaded($X, $Z){
|
||||||
$index = self::getIndex($X, $Z);
|
$index = self::getIndex($X, $Z);
|
||||||
if(!isset($this->chunks[$index]) or $this->chunks[$index] === false){
|
if(!isset($this->chunks[$index])){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function isMiniChunkEmpty($X, $Z, $Y){
|
public function isMiniChunkEmpty($X, $Z, $Y){
|
||||||
$index = self::getIndex($X, $Z);
|
$index = self::getIndex($X, $Z);
|
||||||
if($this->chunks[$index][$Y] !== false){
|
if(isset($this->chunks[$index]) and $this->chunks[$index][$Y] !== false){
|
||||||
if(substr_count($this->chunks[$index][$Y], "\x00") < 8192){
|
if(substr_count($this->chunks[$index][$Y], "\x00") < 8192){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -291,7 +310,7 @@ class PMFLevel extends PMF{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getMiniChunk($X, $Z, $Y){
|
public function getMiniChunk($X, $Z, $Y){
|
||||||
if($this->loadChunk($X, $Z) === false){
|
if($this->isChunkLoaded($X, $Z) === false and $this->loadChunk($X, $Z) === false){
|
||||||
return str_repeat("\x00", 8192);
|
return str_repeat("\x00", 8192);
|
||||||
}
|
}
|
||||||
$index = self::getIndex($X, $Z);
|
$index = self::getIndex($X, $Z);
|
||||||
@ -314,7 +333,17 @@ class PMFLevel extends PMF{
|
|||||||
6 => false,
|
6 => false,
|
||||||
7 => false,
|
7 => false,
|
||||||
);
|
);
|
||||||
$this->chunkChange[$index] = array(-1 => false);
|
$this->chunkChange[$index] = array(
|
||||||
|
-1 => true,
|
||||||
|
0 => 8192,
|
||||||
|
1 => 8192,
|
||||||
|
2 => 8192,
|
||||||
|
3 => 8192,
|
||||||
|
4 => 8192,
|
||||||
|
5 => 8192,
|
||||||
|
6 => 8192,
|
||||||
|
7 => 8192,
|
||||||
|
);
|
||||||
$this->chunkInfo[$index] = array(
|
$this->chunkInfo[$index] = array(
|
||||||
0 => 0,
|
0 => 0,
|
||||||
1 => 0,
|
1 => 0,
|
||||||
@ -347,7 +376,7 @@ class PMFLevel extends PMF{
|
|||||||
$Z = $z >> 4;
|
$Z = $z >> 4;
|
||||||
$Y = $y >> 4;
|
$Y = $y >> 4;
|
||||||
$index = self::getIndex($X, $Z);
|
$index = self::getIndex($X, $Z);
|
||||||
if(!isset($this->chunks[$index]) or $this->chunks[$index] === false){
|
if(!isset($this->chunks[$index])){
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
$aX = $x - ($X << 4);
|
$aX = $x - ($X << 4);
|
||||||
@ -366,7 +395,7 @@ class PMFLevel extends PMF{
|
|||||||
$Y = $y >> 4;
|
$Y = $y >> 4;
|
||||||
$block &= 0xFF;
|
$block &= 0xFF;
|
||||||
$index = self::getIndex($X, $Z);
|
$index = self::getIndex($X, $Z);
|
||||||
if(!isset($this->chunks[$index]) or $this->chunks[$index] === false){
|
if(!isset($this->chunks[$index])){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$aX = $x - ($X << 4);
|
$aX = $x - ($X << 4);
|
||||||
@ -390,7 +419,7 @@ class PMFLevel extends PMF{
|
|||||||
$Z = $z >> 4;
|
$Z = $z >> 4;
|
||||||
$Y = $y >> 4;
|
$Y = $y >> 4;
|
||||||
$index = self::getIndex($X, $Z);
|
$index = self::getIndex($X, $Z);
|
||||||
if(!isset($this->chunks[$index]) or $this->chunks[$index] === false){
|
if(!isset($this->chunks[$index])){
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
$aX = $x - ($X << 4);
|
$aX = $x - ($X << 4);
|
||||||
@ -414,7 +443,7 @@ class PMFLevel extends PMF{
|
|||||||
$Y = $y >> 4;
|
$Y = $y >> 4;
|
||||||
$damage &= 0x0F;
|
$damage &= 0x0F;
|
||||||
$index = self::getIndex($X, $Z);
|
$index = self::getIndex($X, $Z);
|
||||||
if(!isset($this->chunks[$index]) or $this->chunks[$index] === false){
|
if(!isset($this->chunks[$index])){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$aX = $x - ($X << 4);
|
$aX = $x - ($X << 4);
|
||||||
@ -449,10 +478,8 @@ class PMFLevel extends PMF{
|
|||||||
return array(AIR, 0);
|
return array(AIR, 0);
|
||||||
}
|
}
|
||||||
$index = self::getIndex($X, $Z);
|
$index = self::getIndex($X, $Z);
|
||||||
if(!isset($this->chunks[$index]) or $this->chunks[$index] === false){
|
if(!isset($this->chunks[$index]) and $this->loadChunk($X, $Z) === false){
|
||||||
if($this->loadChunk($X, $Z) === false){
|
return array(AIR, 0);
|
||||||
return array(AIR, 0);
|
|
||||||
}
|
|
||||||
}elseif($this->chunks[$index][$Y] === false){
|
}elseif($this->chunks[$index][$Y] === false){
|
||||||
return array(AIR, 0);
|
return array(AIR, 0);
|
||||||
}
|
}
|
||||||
@ -479,10 +506,8 @@ class PMFLevel extends PMF{
|
|||||||
$block &= 0xFF;
|
$block &= 0xFF;
|
||||||
$meta &= 0x0F;
|
$meta &= 0x0F;
|
||||||
$index = self::getIndex($X, $Z);
|
$index = self::getIndex($X, $Z);
|
||||||
if(!isset($this->chunks[$index]) or $this->chunks[$index] === false){
|
if(!isset($this->chunks[$index]) and $this->loadChunk($X, $Z) === false){
|
||||||
if($this->loadChunk($X, $Z) === false){
|
return false;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}elseif($this->chunks[$index][$Y] === false){
|
}elseif($this->chunks[$index][$Y] === false){
|
||||||
$this->fillMiniChunk($X, $Z, $Y);
|
$this->fillMiniChunk($X, $Z, $Y);
|
||||||
}
|
}
|
||||||
@ -508,17 +533,6 @@ class PMFLevel extends PMF{
|
|||||||
++$this->chunkChange[$index][$Y];
|
++$this->chunkChange[$index][$Y];
|
||||||
}
|
}
|
||||||
$this->chunkChange[$index][-1] = true;
|
$this->chunkChange[$index][-1] = true;
|
||||||
if($old_b instanceof LiquidBlock){
|
|
||||||
$pos = new Position($x, $y, $z, $this->level);
|
|
||||||
for($side = 0; $side <= 5; ++$side){
|
|
||||||
$b = $pos->getSide($side);
|
|
||||||
if($b instanceof LavaBlock){
|
|
||||||
ServerAPI::request()->api->block->scheduleBlockUpdate(new Position($b, 0, 0, $this->level), 40, BLOCK_UPDATE_NORMAL);
|
|
||||||
}else{
|
|
||||||
ServerAPI::request()->api->block->scheduleBlockUpdate(new Position($b, 0, 0, $this->level), 10, BLOCK_UPDATE_NORMAL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -527,9 +541,7 @@ class PMFLevel extends PMF{
|
|||||||
public function saveChunk($X, $Z){
|
public function saveChunk($X, $Z){
|
||||||
$X = (int) $X;
|
$X = (int) $X;
|
||||||
$Z = (int) $Z;
|
$Z = (int) $Z;
|
||||||
if($this->isGenerating > 0){
|
if(!$this->isChunkLoaded($X, $Z)){
|
||||||
$this->initCleanChunk($X, $Z);
|
|
||||||
}elseif(!$this->isChunkLoaded($X, $Z)){
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$index = self::getIndex($X, $Z);
|
$index = self::getIndex($X, $Z);
|
||||||
@ -552,7 +564,7 @@ class PMFLevel extends PMF{
|
|||||||
}
|
}
|
||||||
$chunk = @gzopen($path, "wb".PMFLevel::DEFLATE_LEVEL);
|
$chunk = @gzopen($path, "wb".PMFLevel::DEFLATE_LEVEL);
|
||||||
gzwrite($chunk, chr($bitmap));
|
gzwrite($chunk, chr($bitmap));
|
||||||
gzwrite($chunk, Utils::writeInt($this->chunkInfo[$index][0]));
|
gzwrite($chunk, Utils::writeInt($this->chunkInfo[$index][1]));
|
||||||
for($Y = 0; $Y < 8; ++$Y){
|
for($Y = 0; $Y < 8; ++$Y){
|
||||||
$t = 1 << $Y;
|
$t = 1 << $Y;
|
||||||
if(($bitmap & $t) === $t){
|
if(($bitmap & $t) === $t){
|
||||||
@ -589,6 +601,10 @@ class PMFLevel extends PMF{
|
|||||||
return ($this->chunkInfo[$index][1] & 0b00000000000000000000000000000001) > 0;
|
return ($this->chunkInfo[$index][1] & 0b00000000000000000000000000000001) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function isGenerated($X, $Z){
|
||||||
|
return file_exists($this->getChunkPath($X, $Z));
|
||||||
|
}
|
||||||
|
|
||||||
public function doSaveRound(){
|
public function doSaveRound(){
|
||||||
foreach($this->chunks as $index => $chunk){
|
foreach($this->chunks as $index => $chunk){
|
||||||
self::getXZ($index, $X, $Z);
|
self::getXZ($index, $X, $Z);
|
||||||
|
@ -26,7 +26,6 @@ class Level{
|
|||||||
public function __construct(PMFLevel $level, Config $entities, Config $tiles, Config $blockUpdates, $name){
|
public function __construct(PMFLevel $level, Config $entities, Config $tiles, Config $blockUpdates, $name){
|
||||||
$this->server = ServerAPI::request();
|
$this->server = ServerAPI::request();
|
||||||
$this->level = $level;
|
$this->level = $level;
|
||||||
$level->level = $this;
|
|
||||||
$this->level->level = $this;
|
$this->level->level = $this;
|
||||||
$this->entities = $entities;
|
$this->entities = $entities;
|
||||||
$this->tiles = $tiles;
|
$this->tiles = $tiles;
|
||||||
@ -148,17 +147,22 @@ class Level{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function generateChunk($X, $Z){
|
public function generateChunk($X, $Z){
|
||||||
|
++$this->level->isGenerating;
|
||||||
$this->generator->generateChunk($X, $Z);
|
$this->generator->generateChunk($X, $Z);
|
||||||
|
--$this->level->isGenerating;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function populateChunk($X, $Z){
|
public function populateChunk($X, $Z){
|
||||||
|
$this->level->setPopulated($X, $Z);
|
||||||
$this->generator->populateChunk($X, $Z);
|
$this->generator->populateChunk($X, $Z);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __destruct(){
|
public function __destruct(){
|
||||||
if(isset($this->level)){
|
if(isset($this->level)){
|
||||||
$this->save(false, false);
|
$this->save(false, false);
|
||||||
$this->level->close();
|
$this->level->closeLevel();
|
||||||
unset($this->level);
|
unset($this->level);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,13 +30,10 @@ class NormalGenerator implements LevelGenerator{
|
|||||||
private $random;
|
private $random;
|
||||||
private $worldHeight = 65;
|
private $worldHeight = 65;
|
||||||
private $waterHeight = 63;
|
private $waterHeight = 63;
|
||||||
|
private $noiseHills;
|
||||||
|
private $noisePatches;
|
||||||
|
private $noisePatchesSmall;
|
||||||
private $noiseBase;
|
private $noiseBase;
|
||||||
private $noiseGen1;
|
|
||||||
private $noiseGen2;
|
|
||||||
private $noiseGen3;
|
|
||||||
private $noiseGen4;
|
|
||||||
private $noiseGen5;
|
|
||||||
private $noiseGen6;
|
|
||||||
|
|
||||||
public function __construct(array $options = array()){
|
public function __construct(array $options = array()){
|
||||||
|
|
||||||
@ -50,9 +47,10 @@ class NormalGenerator implements LevelGenerator{
|
|||||||
$this->level = $level;
|
$this->level = $level;
|
||||||
$this->random = $random;
|
$this->random = $random;
|
||||||
$this->random->setSeed($this->level->getSeed());
|
$this->random->setSeed($this->level->getSeed());
|
||||||
$this->noiseBase = new NoiseGeneratorSimplex($this->random, 4);
|
$this->noiseHills = new NoiseGeneratorSimplex($this->random, 3);
|
||||||
$this->noiseGen1 = new NoiseGeneratorPerlin($this->random, 4);
|
$this->noisePatches = new NoiseGeneratorSimplex($this->random, 2);
|
||||||
$this->noiseGen2 = new NoiseGeneratorPerlin($this->random, 4);
|
$this->noisePatchesSmall = new NoiseGeneratorSimplex($this->random, 2);
|
||||||
|
$this->noiseBase = new NoiseGeneratorSimplex($this->random, 16);
|
||||||
|
|
||||||
|
|
||||||
$ores = new OrePopulator();
|
$ores = new OrePopulator();
|
||||||
@ -67,10 +65,36 @@ class NormalGenerator implements LevelGenerator{
|
|||||||
new OreType(new GravelBlock(), 10, 16, 0, 128),
|
new OreType(new GravelBlock(), 10, 16, 0, 128),
|
||||||
));
|
));
|
||||||
$this->populators[] = $ores;
|
$this->populators[] = $ores;
|
||||||
|
|
||||||
|
$trees = new TreePopulator();
|
||||||
|
$trees->setBaseAmount(3);
|
||||||
|
$trees->setRandomAmount(0);
|
||||||
|
$this->populators[] = $trees;
|
||||||
|
|
||||||
|
$tallGrass = new TallGrassPopulator();
|
||||||
|
$tallGrass->setBaseAmount(5);
|
||||||
|
$tallGrass->setRandomAmount(0);
|
||||||
|
$this->populators[] = $tallGrass;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function generateChunk($chunkX, $chunkZ){
|
public function generateChunk($chunkX, $chunkZ){
|
||||||
$this->random->setSeed(0xdeadbeef ^ ($chunkX << 8) ^ $chunkZ ^ $this->level->getSeed());
|
$this->random->setSeed(0xdeadbeef ^ ($chunkX << 8) ^ $chunkZ ^ $this->level->getSeed());
|
||||||
|
$hills = array();
|
||||||
|
$patchesSmall = array();
|
||||||
|
$base = array();
|
||||||
|
for($z = 0; $z < 16; ++$z){
|
||||||
|
for($x = 0; $x < 16; ++$x){
|
||||||
|
$i = ($z << 4) + $x;
|
||||||
|
$hills[$i] = $this->noiseHills->noise2D($x + ($chunkX << 4), $z + ($chunkZ << 4), 0.11, 12, true);
|
||||||
|
$patches[$i] = $this->noisePatches->noise2D($x + ($chunkX << 4), $z + ($chunkZ << 4), 0.03, 16, true);
|
||||||
|
$patchesSmall[$i] = $this->noisePatchesSmall->noise2D($x + ($chunkX << 4), $z + ($chunkZ << 4), 0.5, 4, true);
|
||||||
|
$base[$i] = $this->noiseBase->noise2D($x + ($chunkX << 4), $z + ($chunkZ << 4), 0.7, 16, true);
|
||||||
|
|
||||||
|
if($base[$i] < 0){
|
||||||
|
$base[$i] *= 0.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for($chunkY = 0; $chunkY < 8; ++$chunkY){
|
for($chunkY = 0; $chunkY < 8; ++$chunkY){
|
||||||
$chunk = "";
|
$chunk = "";
|
||||||
@ -78,27 +102,46 @@ class NormalGenerator implements LevelGenerator{
|
|||||||
$endY = $startY + 16;
|
$endY = $startY + 16;
|
||||||
for($z = 0; $z < 16; ++$z){
|
for($z = 0; $z < 16; ++$z){
|
||||||
for($x = 0; $x < 16; ++$x){
|
for($x = 0; $x < 16; ++$x){
|
||||||
$noise1 = $this->noiseGen1->noise2D($x + ($chunkX << 4), $z + ($chunkZ << 4), 0.6, 32, true) * 2;
|
$i = ($z << 4) + $x;
|
||||||
$noise2 = $this->noiseGen2->noise2D($x + ($chunkX << 4), $z + ($chunkZ << 4), 0.35, 64, true) * 15;
|
$height = $this->worldHeight + $hills[$i] * 14 + $base[$i] * 7;
|
||||||
$noiseBase = $this->noiseBase->noise2D($x + ($chunkX << 4), $z + ($chunkZ << 4), 1/5, 16, true) * 3;
|
$height = (int) $height;
|
||||||
$height = (int) ($this->worldHeight + $noise1 + $noise2 + $noiseBase);
|
|
||||||
|
|
||||||
for($y = $startY; $y < $endY; ++$y){
|
for($y = $startY; $y < $endY; ++$y){
|
||||||
$diff = $height - $y;
|
$diff = $height - $y;
|
||||||
if($y <= 4 and ($y === 0 or $this->random->nextFloat() < 0.75)){
|
if($y <= 4 and ($y === 0 or $this->random->nextFloat() < 0.75)){
|
||||||
$chunk .= "\x07"; //bedrock
|
$chunk .= "\x07"; //bedrock
|
||||||
}elseif($diff > 3){
|
}elseif($diff > 2){
|
||||||
$chunk .= "\x01"; //stone
|
$chunk .= "\x01"; //stone
|
||||||
}elseif($diff > 0){
|
}elseif($diff > 0){
|
||||||
$chunk .= "\x03"; //dirt
|
if($patches[$i] > 0.7){
|
||||||
|
$chunk .= "\x01"; //stone
|
||||||
|
}elseif($patches[$i] < -0.8){
|
||||||
|
$chunk .= "\x0d"; //gravel
|
||||||
|
}else{
|
||||||
|
$chunk .= "\x03"; //dirt
|
||||||
|
}
|
||||||
}elseif($y <= $this->waterHeight){
|
}elseif($y <= $this->waterHeight){
|
||||||
if($y === $this->waterHeight and $diff === 0){
|
if(($this->waterHeight - $y) <= 1 and $diff === 0){
|
||||||
$chunk .= "\x0c"; //sand
|
$chunk .= "\x0c"; //sand
|
||||||
|
}elseif($diff === 0){
|
||||||
|
if($patchesSmall[$i] > 0.3){
|
||||||
|
$chunk .= "\x0d"; //gravel
|
||||||
|
}elseif($patchesSmall[$i] < -0.45){
|
||||||
|
$chunk .= "\x0c"; //sand
|
||||||
|
}else{
|
||||||
|
$chunk .= "\x03"; //dirt
|
||||||
|
}
|
||||||
}else{
|
}else{
|
||||||
$chunk .= "\x09"; //still_water
|
$chunk .= "\x09"; //still_water
|
||||||
}
|
}
|
||||||
}elseif($diff === 0){
|
}elseif($diff === 0){
|
||||||
$chunk .= "\x02"; //grass
|
if($patches[$i] > 0.7){
|
||||||
|
$chunk .= "\x01"; //stone
|
||||||
|
}elseif($patches[$i] < -0.8){
|
||||||
|
$chunk .= "\x0d"; //gravel
|
||||||
|
}else{
|
||||||
|
$chunk .= "\x02"; //grass
|
||||||
|
}
|
||||||
}else{
|
}else{
|
||||||
$chunk .= "\x00";
|
$chunk .= "\x00";
|
||||||
}
|
}
|
||||||
@ -112,16 +155,11 @@ class NormalGenerator implements LevelGenerator{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function populateChunk($chunkX, $chunkZ){
|
public function populateChunk($chunkX, $chunkZ){
|
||||||
|
$this->random->setSeed(0xdeadbeef ^ ($chunkX << 8) ^ $chunkZ ^ $this->level->getSeed());
|
||||||
foreach($this->populators as $populator){
|
foreach($this->populators as $populator){
|
||||||
$this->random->setSeed(0xdeadbeef ^ ($chunkX << 8) ^ $chunkZ ^ $this->level->getSeed());
|
$this->random->setSeed(0xdeadbeef ^ ($chunkX << 8) ^ $chunkZ ^ $this->level->getSeed());
|
||||||
$populator->populate($this->level, $chunkX, $chunkZ, $this->random);
|
$populator->populate($this->level, $chunkX, $chunkZ, $this->random);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->level->level->setPopulated($chunkX, $chunkZ);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function populateLevel(){
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getSpawn(){
|
public function getSpawn(){
|
||||||
|
@ -130,11 +130,10 @@ class SuperflatGenerator implements LevelGenerator{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function populateChunk($chunkX, $chunkZ){
|
public function populateChunk($chunkX, $chunkZ){
|
||||||
|
$this->random->setSeed(0xdeadbeef ^ ($chunkX << 8) ^ $chunkZ ^ $this->level->getSeed());
|
||||||
foreach($this->populators as $populator){
|
foreach($this->populators as $populator){
|
||||||
$this->random->setSeed(0xdeadbeef ^ ($chunkX << 8) ^ $chunkZ ^ $this->level->getSeed());
|
|
||||||
$populator->populate($this->level, $chunkX, $chunkZ, $this->random);
|
$populator->populate($this->level, $chunkX, $chunkZ, $this->random);
|
||||||
}
|
}
|
||||||
$this->level->level->setPopulated($chunkX, $chunkZ);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function populateLevel(){
|
public function populateLevel(){
|
||||||
|
@ -46,24 +46,16 @@ class WorldGenerator{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function generate(){
|
public function generate(){
|
||||||
++$this->level->level->isGenerating;
|
|
||||||
$this->generator->init($this->level, $this->random);
|
$this->generator->init($this->level, $this->random);
|
||||||
|
|
||||||
for($Z = 7; $Z <= 9; ++$Z){
|
//Generate 4 chunks for spawning players
|
||||||
for($X = 7; $X <= 9; ++$X){
|
for($Z = 7; $Z <= 8; ++$Z){
|
||||||
$this->generator->generateChunk($X, $Z);
|
for($X = 7; $X <= 8; ++$X){
|
||||||
}
|
$this->level->level->loadChunk($X, $Z);
|
||||||
}
|
|
||||||
|
|
||||||
for($Z = 7; $Z <= 9; ++$Z){
|
|
||||||
for($X = 7; $X <= 9; ++$X){
|
|
||||||
$this->generator->populateChunk($X, $Z);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->level->setSpawn($this->generator->getSpawn());
|
$this->level->setSpawn($this->generator->getSpawn());
|
||||||
$this->level->save(true, true);
|
|
||||||
--$this->level->level->isGenerating;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function close(){
|
public function close(){
|
||||||
|
@ -23,6 +23,8 @@
|
|||||||
class TreeObject{
|
class TreeObject{
|
||||||
public $overridable = array(
|
public $overridable = array(
|
||||||
0 => true,
|
0 => true,
|
||||||
|
2 => true,
|
||||||
|
3 => true,
|
||||||
6 => true,
|
6 => true,
|
||||||
17 => true,
|
17 => true,
|
||||||
18 => true,
|
18 => true,
|
||||||
|
@ -25,9 +25,9 @@ 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){
|
||||||
$x = $random->nextRange($chunkX << 4, ($chunkX << 4) + 16);
|
$x = $random->nextRange($chunkX << 4, ($chunkX << 4) + 15);
|
||||||
$y = $random->nextRange($ore->type->minHeight, $ore->type->maxHeight);
|
$y = $random->nextRange($ore->type->minHeight, $ore->type->maxHeight);
|
||||||
$z = $random->nextRange($chunkZ << 4, ($chunkZ << 4) + 16);
|
$z = $random->nextRange($chunkZ << 4, ($chunkZ << 4) + 15);
|
||||||
if($ore->canPlaceObject($level, $x, $y, $z)){
|
if($ore->canPlaceObject($level, $x, $y, $z)){
|
||||||
$ore->placeObject($level, new Vector3($x, $y, $z));
|
$ore->placeObject($level, new Vector3($x, $y, $z));
|
||||||
}
|
}
|
||||||
|
70
src/world/generator/populator/TallGrassPopulator.php
Normal file
70
src/world/generator/populator/TallGrassPopulator.php
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
<?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/
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
class TallGrassPopulator extends Populator{
|
||||||
|
private $level;
|
||||||
|
private $randomAmount;
|
||||||
|
private $baseAmount;
|
||||||
|
|
||||||
|
public function setRandomAmount($amount){
|
||||||
|
$this->randomAmount = $amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setBaseAmount($amount){
|
||||||
|
$this->baseAmount = $amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function populate(Level $level, $chunkX, $chunkZ, Random $random){
|
||||||
|
$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);
|
||||||
|
$vector = new Vector3($xx, $yy, $zz);
|
||||||
|
if($yy !== -1 and $this->canTallGrassStay($this->level->getBlockRaw($vector))){
|
||||||
|
$this->level->setBlockRaw($vector, new TallGrassBlock(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function canTallGrassStay(Block $block){
|
||||||
|
return $block->getID() === AIR and $block->getSide(0)->getID() === GRASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getHighestWorkableBlock($x, $z){
|
||||||
|
for($y = 128; $y > 0; --$y){
|
||||||
|
$b = $this->level->getBlockRaw(new Vector3($x, $y, $z));
|
||||||
|
if($b->getID() === AIR or $b->getID() === LEAVES){
|
||||||
|
if(--$y <= 0){
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ++$y;
|
||||||
|
}
|
||||||
|
}
|
67
src/world/generator/populator/TreePopulator.php
Normal file
67
src/world/generator/populator/TreePopulator.php
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
<?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/
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
class TreePopulator extends Populator{
|
||||||
|
private $level;
|
||||||
|
private $randomAmount;
|
||||||
|
private $baseAmount;
|
||||||
|
|
||||||
|
public function setRandomAmount($amount){
|
||||||
|
$this->randomAmount = $amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setBaseAmount($amount){
|
||||||
|
$this->baseAmount = $amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function populate(Level $level, $chunkX, $chunkZ, Random $random){
|
||||||
|
$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);
|
||||||
|
$y = $this->getHighestWorkableBlock($x, $z);
|
||||||
|
if($y === -1){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if($random->nextFloat() > 0.75){
|
||||||
|
$meta = SaplingBlock::BIRCH;
|
||||||
|
}else{
|
||||||
|
$meta = SaplingBlock::OAK;
|
||||||
|
}
|
||||||
|
TreeObject::growTree($this->level, new Vector3($x, $y, $z), $random, $meta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getHighestWorkableBlock($x, $z){
|
||||||
|
for($y = 128; $y > 0; --$y){
|
||||||
|
$b = $this->level->getBlockRaw(new Vector3($x, $y, $z));
|
||||||
|
if($b->getID() !== DIRT and $b->getID() !== GRASS){
|
||||||
|
if(--$y <= 0){
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ++$y;
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user