This commit is contained in:
Michael Yoo 2014-03-09 20:01:02 +10:30
commit b28bc3ae9b
89 changed files with 4058 additions and 1695 deletions

View File

@ -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

View File

@ -1,12 +1,12 @@
![](http://www.pocketmine.net/favicon.png) ![](http://cdn.pocketmine.net/img/PocketMine-MP-h.png)
# PocketMine-MP Contribution Guidelines # PocketMine-MP Contribution Guidelines
Before contributing to PocketMine-MP, please read this. Before contributing to PocketMine-MP, please read this. Also, take a look if your contribution fits the PocketMine-MP goals below.
## I've a question ## I've a question
* For questions, please refer to the _#pocketmine_ or _#mcpedevs_ IRC channel on Freenode. There is a [WebIRC](http://webchat.freenode.net?channels=pockdetmine,mcpedevs&uio=d4) if you want. * For questions, please refer to the _#pocketmine_ or _#mcpedevs_ IRC channel on Freenode. There is a [WebIRC](http://webchat.freenode.net?channels=pocketmine,mcpedevs&uio=d4) if you want.
* You can ask directly to _[@PocketMine](https://twitter.com/PocketMine)_ in Twitter, but don't expect an inmediate reply. * You can ask directly to _[@PocketMine](https://twitter.com/PocketMine)_ in Twitter, but don't expect an inmediate reply.
## I want to create an issue ## I want to create an issue
@ -28,8 +28,7 @@ __Thanks for contributing to PocketMine-MP!__
### Code syntax
#### Code syntax
It is mainly [PSR-2](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md) with a few exceptions. It is mainly [PSR-2](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md) with a few exceptions.
* Opening braces MUST go on the same line. * Opening braces MUST go on the same line.
@ -39,7 +38,7 @@ It is mainly [PSR-2](https://github.com/php-fig/fig-standards/blob/master/accept
* Long arrays MAY be split across multiple lines, where each subsequent line is indented once. * Long arrays MAY be split across multiple lines, where each subsequent line is indented once.
* Files MUST use only the `<?php` tag. * Files MUST use only the `<?php` tag.
* Files MUST NOT have an ending `?>` tag. * Files MUST NOT have an ending `?>` tag.
* Code MUST NOT use namespaces. _(This restriction will be lifted on the Alpha_1.4 code)_ * Code MUST NOT use namespaces. Descriptive and unique class names are enforced.
* Strings SHOULD use the double quote `"` except when the single quote is required. * Strings SHOULD use the double quote `"` except when the single quote is required.
* Arrays SHOULD be declared using `array()`, not the `[]` shortcut. * Arrays SHOULD be declared using `array()`, not the `[]` shortcut.
* Argument lists MAY NOT be split across multiple lines, except long arrays. * Argument lists MAY NOT be split across multiple lines, except long arrays.

View File

@ -32,7 +32,7 @@ class BanAPI{
private $ops; private $ops;
/** @var Config */ /** @var Config */
private $bannedIPs; private $bannedIPs;
private $cmdWL = array();//Command WhiteList private $cmdWhitelist = array();//Command WhiteList
function __construct(){ function __construct(){
$this->server = ServerAPI::request(); $this->server = ServerAPI::request();
} }
@ -48,7 +48,7 @@ class BanAPI{
$this->server->api->console->register("whitelist", "<on|off|list|add|remove|reload> [username]", array($this, "commandHandler")); $this->server->api->console->register("whitelist", "<on|off|list|add|remove|reload> [username]", array($this, "commandHandler"));
$this->server->api->console->register("op", "<player>", array($this, "commandHandler")); $this->server->api->console->register("op", "<player>", array($this, "commandHandler"));
$this->server->api->console->register("deop", "<player>", array($this, "commandHandler")); $this->server->api->console->register("deop", "<player>", array($this, "commandHandler"));
$this->server->api->console->register("sudo", "<player>", array($this, "commandHandler")); $this->server->api->console->register("sudo", "<player> <command>", array($this, "commandHandler"));
$this->server->api->console->alias("ban-ip", "banip add"); $this->server->api->console->alias("ban-ip", "banip add");
$this->server->api->console->alias("banlist", "ban list"); $this->server->api->console->alias("banlist", "ban list");
$this->server->api->console->alias("pardon", "ban remove"); $this->server->api->console->alias("pardon", "ban remove");
@ -104,7 +104,6 @@ class BanAPI{
} }
} }
return; return;
break;
case "console.command"://Checks if a command is allowed with the current user permissions. case "console.command"://Checks if a command is allowed with the current user permissions.
if(isset($this->cmdWhitelist[$data["cmd"]])){ if(isset($this->cmdWhitelist[$data["cmd"]])){
return; return;
@ -118,7 +117,6 @@ class BanAPI{
return; return;
} }
return false; return false;
break;
} }
} }
@ -152,7 +150,7 @@ class BanAPI{
$player = $this->server->api->player->get($user); $player = $this->server->api->player->get($user);
if(!($player instanceof Player)){ if(!($player instanceof Player)){
$this->ops->set($user); $this->ops->set($user);
$this->ops->save($user); $this->ops->save();
$output .= $user." is now op\n"; $output .= $user." is now op\n";
break; break;
} }

View File

@ -341,7 +341,7 @@ class BlockAPI{
} }
} }
if((!$target->isBreakable($item, $player) and $this->server->api->dhandle("player.block.break.invalid", array("player" => $player, "target" => $target, "item" => $item)) !== true) or ($player->gamemode & 0x02) === 0x02 or (($player->lastBreak - $player->getLag() / 1000) + $target->getBreakTime($item, $player) - 0.1) >= microtime(true)){ if((!$target->isBreakable($item, $player) and $this->server->api->dhandle("player.block.break.invalid", array("player" => $player, "target" => $target, "item" => $item)) !== true) or ($player->gamemode & 0x02) === 0x02 or (($player->lastBreak - $player->getLag() / 1000) + $target->getBreakTime($item, $player) - 0.2) >= microtime(true)){
if($this->server->api->dhandle("player.block.break.bypass", array("player" => $player, "target" => $target, "item" => $item)) !== true){ if($this->server->api->dhandle("player.block.break.bypass", array("player" => $player, "target" => $target, "item" => $item)) !== true){
return $this->cancelAction($target, $player, false); return $this->cancelAction($target, $player, false);
} }
@ -516,13 +516,9 @@ class BlockAPI{
public function nextRandomUpdate(Position $pos){ public function nextRandomUpdate(Position $pos){
if(!isset($this->scheduledUpdates[$pos->x.".".$pos->y.".".$pos->z.".".$pos->level->getName().".".BLOCK_UPDATE_RANDOM])){ if(!isset($this->scheduledUpdates[$pos->x.".".$pos->y.".".$pos->z.".".$pos->level->getName().".".BLOCK_UPDATE_RANDOM])){
$X = (($pos->x >> 4) << 4);
$Y = (($pos->y >> 4) << 4);
$Z = (($pos->z >> 4) << 4);
$time = microtime(true); $time = microtime(true);
$i = 0;
$offset = 0; $offset = 0;
while(true){ do{
$t = $offset + Utils::getRandomUpdateTicks() * 0.05; $t = $offset + Utils::getRandomUpdateTicks() * 0.05;
$update = $this->server->query("SELECT COUNT(*) FROM blockUpdates WHERE level = '".$pos->level->getName()."' AND type = ".BLOCK_UPDATE_RANDOM." AND delay >= ".($time + $t - 1)." AND delay <= ".($time + $t + 1).";"); $update = $this->server->query("SELECT COUNT(*) FROM blockUpdates WHERE level = '".$pos->level->getName()."' AND type = ".BLOCK_UPDATE_RANDOM." AND delay >= ".($time + $t - 1)." AND delay <= ".($time + $t + 1).";");
if($update instanceof SQLite3Result){ if($update instanceof SQLite3Result){
@ -534,7 +530,7 @@ class BlockAPI{
break; break;
} }
$offset += mt_rand(25, 75); $offset += mt_rand(25, 75);
} }while(true);
$this->scheduleBlockUpdate($pos, $t / 0.05, BLOCK_UPDATE_RANDOM); $this->scheduleBlockUpdate($pos, $t / 0.05, BLOCK_UPDATE_RANDOM);
} }
} }

View File

@ -26,7 +26,6 @@ class ConsoleAPI{
$this->cmds = array(); $this->cmds = array();
$this->alias = array(); $this->alias = array();
$this->server = ServerAPI::request(); $this->server = ServerAPI::request();
$this->last = microtime(true);
} }
public function init(){ public function init(){
@ -250,7 +249,7 @@ class ConsoleAPI{
if(($d1 = $this->server->api->dhandle("console.command.".$cmd, array("cmd" => $cmd, "parameters" => $params, "issuer" => $issuer, "alias" => $alias))) === false if(($d1 = $this->server->api->dhandle("console.command.".$cmd, array("cmd" => $cmd, "parameters" => $params, "issuer" => $issuer, "alias" => $alias))) === false
or ($d2 = $this->server->api->dhandle("console.command", array("cmd" => $cmd, "parameters" => $params, "issuer" => $issuer, "alias" => $alias))) === false){ or ($d2 = $this->server->api->dhandle("console.command", array("cmd" => $cmd, "parameters" => $params, "issuer" => $issuer, "alias" => $alias))) === false){
$output = "You don't have permissions to use this command.\n"; $output = "You don't have permissions to use this command.\n";
}elseif($d1 !== true and $d2 !== true){ }elseif($d1 !== true and (!isset($d2) or $d2 !== true)){
if(isset($this->cmds[$cmd]) and is_callable($this->cmds[$cmd])){ if(isset($this->cmds[$cmd]) and is_callable($this->cmds[$cmd])){
$output = @call_user_func($this->cmds[$cmd], $cmd, $params, $issuer, $alias); $output = @call_user_func($this->cmds[$cmd], $cmd, $params, $issuer, $alias);
}elseif($this->server->api->dhandle("console.command.unknown", array("cmd" => $cmd, "params" => $params, "issuer" => $issuer, "alias" => $alias)) !== false){ }elseif($this->server->api->dhandle("console.command.unknown", array("cmd" => $cmd, "params" => $params, "issuer" => $issuer, "alias" => $alias)) !== false){
@ -326,7 +325,7 @@ class ConsoleLoop extends Thread{
} }
if(!extension_loaded("readline")){ if(!extension_loaded("readline")){
@fclose($fp); @fclose($this->fp);
} }
exit(0); exit(0);
} }

View File

@ -94,7 +94,7 @@ class LevelAPI{
if(strtoupper($this->server->api->getProperty("level-type")) == "FLAT"){ if(strtoupper($this->server->api->getProperty("level-type")) == "FLAT"){
$generator = new SuperflatGenerator($options); $generator = new SuperflatGenerator($options);
}else{ }else{
$generator = new TemporalGenerator($options); $generator = new NormalGenerator($options);
} }
} }
$gen = new WorldGenerator($generator, $name, $seed === false ? Utils::readInt(Utils::getRandomBytes(4, false)):(int) $seed); $gen = new WorldGenerator($generator, $name, $seed === false ? Utils::readInt(Utils::getRandomBytes(4, false)):(int) $seed);
@ -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");
@ -194,7 +198,6 @@ class LevelAPI{
$t = $this->server->api->tile->add($this->levels[$name], $tile["id"], $tile["x"], $tile["y"], $tile["z"], $tile); $t = $this->server->api->tile->add($this->levels[$name], $tile["id"], $tile["x"], $tile["y"], $tile["z"], $tile);
} }
$timeu = microtime(true);
foreach($blockUpdates->getAll() as $bupdate){ foreach($blockUpdates->getAll() as $bupdate){
$this->server->api->block->scheduleBlockUpdate(new Position((int) $bupdate["x"],(int) $bupdate["y"],(int) $bupdate["z"], $this->levels[$name]), (float) $bupdate["delay"], (int) $bupdate["type"]); $this->server->api->block->scheduleBlockUpdate(new Position((int) $bupdate["x"],(int) $bupdate["y"],(int) $bupdate["z"], $this->levels[$name]), (float) $bupdate["delay"], (int) $bupdate["type"]);
} }
@ -223,20 +226,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;
} }

View File

@ -20,309 +20,331 @@
*/ */
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; }
} }
}
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(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;
}
}elseif(isset($params[0])){
if(!($this->server->api->player->get($params[0]) instanceof Player)){
if($issuer instanceof Player){
$setgm = $params[0];
$player = $issuer;
}
}
}
$output .= "Spawnpoint set correctly!\n"; if(!($player instanceof Player) or !isset($gms[strtolower($setgm)])){
break; $output .= "Usage: /$cmd <mode> [player] or /$cmd [player] <mode>\n";
case "spawn": break;
if(!($issuer instanceof Player)){ }
$output .= "Please run this command in-game.\n"; if($player->setGamemode($gms[strtolower($setgm)])){
break; $output .= "Gamemode of ".$player->username." changed to ".$player->getGamemode()."\n";
} }
$issuer->teleport($this->server->spawn); break;
break; case "tp":
case "ping": if(count($params) <= 2 or substr($params[0], 0, 2) === "w:" or substr($params[1], 0, 2) === "w:"){
if(!($issuer instanceof Player)){ if((!isset($params[1]) or substr($params[0], 0, 2) === "w:") and isset($params[0]) and ($issuer instanceof Player)){
$output .= "Please run this command in-game.\n"; $name = $issuer->username;
break; $target = implode(" ", $params);
} }elseif(isset($params[1]) and isset($params[0])){
$output .= "ping ".round($issuer->getLag(), 2)."ms, packet loss ".round($issuer->getPacketLoss() * 100, 2)."%, ".round($issuer->getBandwidth() / 1024, 2)." KB/s\n"; $name = array_shift($params);
break; $target = implode(" ", $params);
case "gamemode": }else{
$player = false; $output .= "Usage: /$cmd [target player] <destination player | w:world>\n";
$setgm = false; break;
$gms = array( }
"0" => SURVIVAL, if($this->teleport($name, $target) !== false){
"survival" => SURVIVAL, $output .= "\"$name\" teleported to \"$target\"\n";
"s" => SURVIVAL, }else{
"1" => CREATIVE, $output .= "Couldn't teleport.\n";
"creative" => CREATIVE, }
"c" => CREATIVE, }else{
"2" => ADVENTURE, if(!isset($params[3]) and isset($params[2]) and isset($params[1]) and isset($params[0]) and ($issuer instanceof Player)){
"adventure" => ADVENTURE, $name = $issuer->username;
"a" => ADVENTURE, $x = $params[0];
"3" => VIEW, $y = $params[1];
"view" => VIEW, $z = $params[2];
"viewer" => VIEW, }elseif(isset($params[3]) and isset($params[2]) and isset($params[1]) and isset($params[0])){
"spectator" => VIEW, $name = $params[0];
"v" => VIEW, $x = $params[1];
); $y = $params[2];
if($issuer instanceof Player){ $z = $params[3];
$player = $issuer; }else{
} $output .= "Usage: /$cmd [player] <x> <y> <z>\n";
if(isset($params[1])){ break;
if($this->server->api->player->get($params[1]) instanceof Player){ }
$player = $this->server->api->player->get($params[1]); if($this->tppos($name, $x, $y, $z)){
$setgm = $params[0]; $output .= "\"$name\" teleported to ($x, $y, $z)\n";
}elseif($this->server->api->player->get($params[0]) instanceof Player){ }else{
$player = $this->server->api->player->get($params[0]); $output .= "Couldn't teleport.\n";
$setgm = $params[1]; }
}else{ }
$output .= "Usage: /$cmd <mode> [player] or /$cmd [player] <mode>\n"; break;
break; case "kill":
} case "suicide":
} if(!isset($params[0]) and ($issuer instanceof Player)){
if(!($player instanceof Player) or !isset($gms[strtolower($setgm)])){ $player = $issuer;
$output .= "Usage: /$cmd <mode> [player] or /$cmd [player] <mode>\n"; }else{
break; $player = $this->get($params[0]);
} }
if($player->setGamemode($gms[strtolower($setgm)])){ if($player instanceof Player){
$output .= "Gamemode of ".$player->username." changed to ".$player->getGamemode()."\n"; $player->entity->harm(1000, "console", true);
} $player->sendChat("Ouch. That looks like it hurt.\n");
break; }else{
case "tp": $output .= "Usage: /$cmd [player]\n";
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)){ break;
$name = $issuer->username; case "list":
$target = implode(" ", $params); $output .= "There are ".count($this->server->clients)."/".$this->server->maxClients." players online:\n";
}elseif(isset($params[1]) and isset($params[0])){ if(count($this->server->clients) == 0){
$name = array_shift($params); break;
$target = implode(" ", $params); }
}else{ foreach($this->server->clients as $c){
$output .= "Usage: /$cmd [target player] <destination player>\n"; $output .= $c->username.", ";
break; }
} $output = substr($output, 0, -2)."\n";
if($this->teleport($name, $target) !== false){ break;
$output .= "\"$name\" teleported to \"$target\"\n"; }
}else{ return $output;
$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 teleport(&$name, &$target){
if(substr($target, 0, 2) === "w:"){ if(substr($target, 0, 2) === "w:"){
$lv = $this->server->api->level->get(substr($target, 2)); $lv = $this->server->api->level->get(substr($target, 2));
if($lv instanceof Level){ if($lv instanceof Level){
$origin = $this->get($name); $origin = $this->get($name);
if($origin instanceof Player){ if($origin instanceof Player){
$name = $origin->username; $name = $origin->username;
return $origin->teleport($lv->getSafeSpawn()); return $origin->teleport($lv->getSafeSpawn());
} }
}else{ }else{
return false; return false;
} }
} }
$player = $this->get($target); $player = $this->get($target);
if(($player instanceof Player) and ($player->entity instanceof Entity)){ if(($player instanceof Player) and ($player->entity instanceof Entity)){
$target = $player->username; $target = $player->username;
$origin = $this->get($name); $origin = $this->get($name);
if($origin instanceof Player){ if($origin instanceof Player){
$name = $origin->username; $name = $origin->username;
return $origin->teleport($player->entity); return $origin->teleport($player->entity);
} }
} }
return false; return false;
} }
public function tppos(&$name, &$x, &$y, &$z){ public function tppos(&$name, &$x, &$y, &$z){
$player = $this->get($name); $player = $this->get($name);
if(($player instanceof Player) and ($player->entity instanceof Entity)){ if(($player instanceof Player) and ($player->entity instanceof Entity)){
$name = $player->username; $name = $player->username;
$x = $x{0} === "~" ? $player->entity->x + floatval(substr($x, 1)):floatval($x); $x = $x{0} === "~" ? $player->entity->x + floatval(substr($x, 1)):floatval($x);
$y = $y{0} === "~" ? $player->entity->y + floatval(substr($y, 1)):floatval($y); $y = $y{0} === "~" ? $player->entity->y + floatval(substr($y, 1)):floatval($y);
$z = $z{0} === "~" ? $player->entity->z + floatval(substr($z, 1)):floatval($z); $z = $z{0} === "~" ? $player->entity->z + floatval(substr($z, 1)):floatval($z);
$player->teleport(new Vector3($x, $y, $z)); $player->teleport(new Vector3($x, $y, $z));
return true; return true;
} }
return false; return false;
} }
public function get($name, $alike = true, $multiple = false){ public function get($name, $alike = true, $multiple = false){
$name = trim(strtolower($name)); $name = trim(strtolower($name));
if($name === ""){ if($name === ""){
return false; return false;
} }
$query = $this->server->query("SELECT ip,port,name FROM players WHERE name ".($alike === true ? "LIKE '%".$name."%'":"= '".$name."'").";"); $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 = MainServer::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];
if($multiple === false and $d["name"] === $name){ if($multiple === false and $d["name"] === $name){
return $players[$CID]; return $players[$CID];
} }
} }
} }
} }
if($multiple === false){ if($multiple === false){
@ -334,74 +356,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 = MainServer::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 +431,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 +449,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();
} }
} }

View File

@ -26,6 +26,30 @@ class PluginAPI extends stdClass{
public function __construct(){ public function __construct(){
$this->server = ServerAPI::request(); $this->server = ServerAPI::request();
$this->randomNonce = Utils::getRandomBytes(16, false); $this->randomNonce = Utils::getRandomBytes(16, false);
$this->server->api->console->register("plugins", "", array($this, "commandHandler"));
$this->server->api->console->register("version", "", array($this, "commandHandler"));
$this->server->api->ban->cmdWhitelist("version");
}
public function commandHandler($cmd, $params, $issuer, $alias){
$output = "";
switch($cmd){
case "plugins":
$output = "Plugins: ";
foreach($this->getList() as $plugin){
$output .= $plugin["name"] . ": ".$plugin["version"] .", ";
}
$output = $output === "Plugins: " ? "No plugins installed.\n" : substr($output, 0, -2)."\n";
break;
case "version":
$output = "PocketMine-MP ".MAJOR_VERSION."".CODENAME."」 API #".CURRENT_API_VERSION." for Minecraft: PE ".CURRENT_MINECRAFT_VERSION." protocol #".ProtocolInfo::CURRENT_PROTOCOL;
if(GIT_COMMIT !== str_repeat("00", 20)){
$output .= " (git ".GIT_COMMIT.")";
}
$output .= "\n";
break;
}
return $output;
} }
public function __destruct(){ public function __destruct(){
@ -172,19 +196,6 @@ class PluginAPI extends stdClass{
return $path; return $path;
} }
private function fillDefaults($default, &$yaml){
foreach($default as $k => $v){
if(is_array($v)){
if(!isset($yaml[$k]) or !is_array($yaml[$k])){
$yaml[$k] = array();
}
$this->fillDefaults($v, $yaml[$k]);
}elseif(!isset($yaml[$k])){
$yaml[$k] = $v;
}
}
}
public function readYAML($file){ public function readYAML($file){
return yaml_parse(preg_replace("#^([ ]*)([a-zA-Z_]{1}[^\:]*)\:#m", "$1\"$2\":", file_get_contents($file))); return yaml_parse(preg_replace("#^([ ]*)([a-zA-Z_]{1}[^\:]*)\:#m", "$1\"$2\":", file_get_contents($file)));
} }

View File

@ -28,7 +28,8 @@ class ServerAPI{
private $apiList = array(); private $apiList = array();
private $asyncCnt = 0; private $asyncCnt = 0;
private $rcon; private $rcon;
private $query;
public $query;
//TODO: Instead of hard-coding functions, use PHPDoc-compatible methods to load APIs. //TODO: Instead of hard-coding functions, use PHPDoc-compatible methods to load APIs.
@ -78,7 +79,7 @@ class ServerAPI{
public $tile; public $tile;
/** /**
* @return PocketMinecraftServer * @return MainServer
*/ */
public static function request(){ public static function request(){
return self::$serverRequest; return self::$serverRequest;
@ -97,6 +98,14 @@ class ServerAPI{
@mkdir(DATA_PATH."players/", 0755); @mkdir(DATA_PATH."players/", 0755);
@mkdir(DATA_PATH."worlds/", 0755); @mkdir(DATA_PATH."worlds/", 0755);
@mkdir(DATA_PATH."plugins/", 0755); @mkdir(DATA_PATH."plugins/", 0755);
//Init all the events
foreach(get_declared_classes() as $class){
if(is_subclass_of($class, "BaseEvent") and property_exists($class, "handlers") and property_exists($class, "handlerPriority")){
$class::unregisterAll();
}
}
$version = new VersionString(); $version = new VersionString();
console("[INFO] Starting Minecraft PE server version ".FORMAT_AQUA.CURRENT_MINECRAFT_VERSION); console("[INFO] Starting Minecraft PE server version ".FORMAT_AQUA.CURRENT_MINECRAFT_VERSION);
@ -129,33 +138,29 @@ class ServerAPI{
"enable-query" => true, "enable-query" => true,
"enable-rcon" => false, "enable-rcon" => false,
"rcon.password" => substr(base64_encode(Utils::getRandomBytes(20, false)), 3, 10), "rcon.password" => substr(base64_encode(Utils::getRandomBytes(20, false)), 3, 10),
"send-usage" => true,
"auto-save" => true, "auto-save" => true,
)); ));
$this->parseProperties(); $this->parseProperties();
//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));
if($this->getProperty("port") !== false){ define("MAX_CHUNK_RATE", 20 / $this->getProperty("max-chunks-per-second", 7)); //Default rate ~448 kB/s
$this->setProperty("server-port", $this->getProperty("port")); if(ADVANCED_CACHE == true){
$this->config->remove("port"); console("[INFO] Advanced cache enabled");
$this->config->remove("invisible");
} }
$this->server = new PocketMinecraftServer($this->getProperty("server-name"), $this->getProperty("gamemode"), ($seed = $this->getProperty("level-seed")) != "" ? (int) $seed:false, $this->getProperty("server-port"), ($ip = $this->getProperty("server-ip")) != "" ? $ip:"0.0.0.0"); if($this->getProperty("upnp-forwarding") == true){
console("[INFO] [UPnP] Trying to port forward...");
UPnP_PortForward($this->getProperty("server-port"));
}
$this->server = new MainServer($this->getProperty("server-name"), $this->getProperty("gamemode"), ($seed = $this->getProperty("level-seed")) != "" ? (int) $seed:false, $this->getProperty("server-port"), ($ip = $this->getProperty("server-ip")) != "" ? $ip:"0.0.0.0");
$this->server->api = $this; $this->server->api = $this;
self::$serverRequest = $this->server; self::$serverRequest = $this->server;
console("[INFO] This server is running PocketMine-MP version ".($version->isDev() ? FORMAT_YELLOW:"").MAJOR_VERSION.FORMAT_RESET." \"".CODENAME."\" (MCPE: ".CURRENT_MINECRAFT_VERSION.") (API ".CURRENT_API_VERSION.")", true, true, 0); console("[INFO] This server is running PocketMine-MP version ".($version->isDev() ? FORMAT_YELLOW:"").MAJOR_VERSION.FORMAT_RESET." \"".CODENAME."\" (MCPE: ".CURRENT_MINECRAFT_VERSION.") (API ".CURRENT_API_VERSION.")", true, true, 0);
console("[INFO] PocketMine-MP is distributed under the LGPL License", true, true, 0); console("[INFO] PocketMine-MP is distributed under the LGPL License", true, true, 0);
if(ADVANCED_CACHE == true){
console("[INFO] Advanced cache enabled");
}
if($this->getProperty("upnp-forwarding") === true){
console("[INFO] [UPnP] Trying to port forward...");
UPnP_PortForward($this->getProperty("server-port"));
}
if($this->getProperty("last-update") === false or ($this->getProperty("last-update") + 3600) < time()){ if($this->getProperty("last-update") === false or ($this->getProperty("last-update") + 3600) < time()){
console("[INFO] Checking for new server version"); console("[INFO] Checking for new server version");
console("[INFO] Last check: ".FORMAT_AQUA.date("Y-m-d H:i:s", $this->getProperty("last-update"))."\x1b[0m"); console("[INFO] Last check: ".FORMAT_AQUA.date("Y-m-d H:i:s", $this->getProperty("last-update"))."\x1b[0m");
@ -287,7 +292,7 @@ class ServerAPI{
$this->setProperty("memory-limit", "128M"); $this->setProperty("memory-limit", "128M");
} }
if($this->server instanceof PocketMinecraftServer){ if($this->server instanceof MainServer){
$this->server->setType($this->getProperty("server-type")); $this->server->setType($this->getProperty("server-type"));
$this->server->maxClients = $this->getProperty("max-players"); $this->server->maxClients = $this->getProperty("max-players");
$this->server->description = $this->getProperty("description"); $this->server->description = $this->getProperty("description");
@ -333,11 +338,11 @@ class ServerAPI{
} }
public function init(){ public function init(){
if(!(self::$serverRequest instanceof PocketMinecraftServer)){ if(!(self::$serverRequest instanceof MainServer)){
self::$serverRequest = $this->server; self::$serverRequest = $this->server;
} }
if($this->getProperty("send-usage") !== false){ if($this->getProperty("send-usage", true) !== false){
$this->server->schedule(6000, array($this, "sendUsage"), array(), true); //Send the info after 5 minutes have passed $this->server->schedule(6000, array($this, "sendUsage"), array(), true); //Send the info after 5 minutes have passed
$this->sendUsage(); $this->sendUsage();
} }
@ -349,7 +354,7 @@ class ServerAPI{
} }
if($this->getProperty("enable-query") === true){ if($this->getProperty("enable-query") === true){
$this->query = new Query(); $this->query = new QueryHandler();
} }
CraftingRecipes::init(); CraftingRecipes::init();
$this->server->init(); $this->server->init();

136
src/BaseEvent.php Normal file
View File

@ -0,0 +1,136 @@
<?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/
*
*
*/
abstract class BaseEvent{
const ALLOW = 0;
const DENY = 1;
const NORMAL = 2;
const FORCE = 0x80000000;
/**
* Any callable event must declare the static variables
*
* public static $handlers;
* public static $handlerPriority;
*
* Not doing so will deny the proper event initialization
*/
protected $eventName = null;
private $status = BaseEvent::NORMAL;
private $prioritySlot;
final public function getEventName(){
return $this->eventName !== null ? get_class($this) : $this->eventName;
}
final public function setPrioritySlot($slot){
$this->prioritySlot = (int) $slot;
}
final public function getPrioritySlot(){
return (int) $this->prioritySlot;
}
public function isAllowed(){
return ($this->status & 0x7FFFFFFF) === BaseEvent::ALLOW;
}
public function setAllowed($forceAllow = false){
$this->status = BaseEvent::ALLOW | ($forceAllow === true ? BaseEvent::FORCE : 0);
}
public function isCancelled(){
return ($this->status & 0x7FFFFFFF) === BaseEvent::DENY;
}
public function setCancelled($forceCancel = false){
if($this instanceof CancellableEvent){
$this->status = BaseEvent::DENY | ($forceCancel === true ? BaseEvent::FORCE : 0);
}
return false;
}
public function isNormal(){
return $this->status === BaseEvent::NORMAL;
}
public function setNormal(){
$this->status = BaseEvent::NORMAL;
}
public function isForced(){
return ($this->status & BaseEvent::FORCE) > 0;
}
public static function getHandlerList(){
return static::$handlers;
}
public static function getPriorityList(){
return static::$handlerPriority;
}
public static function unregisterAll(){
static::$handlers = array();
static::$handlerPriority = array();
}
public static function register(callable $handler, $priority = EventPriority::NORMAL){
if($priority < EventPriority::MONITOR or $priority > EventPriority::LOWEST){
return false;
}
$identifier = Utils::getCallableIdentifier($handler);
if(isset(static::$handlers[$identifier])){ //Already registered
return false;
}else{
static::$handlers[$identifier] = $handler;
if(!isset(static::$handlerPriority[(int) $priority])){
static::$handlerPriority[(int) $priority] = array();
krsort(static::$handlerPriority);
}
static::$handlerPriority[(int) $priority][$identifier] = $handler;
return true;
}
}
public static function unregister(callable $handler, $priority = EventPriority::NORMAL){
$identifier = Utils::getCallableIdentifier($handler);
if(isset(static::$handlers[$identifier])){
if(isset(static::$handlerPriority[(int) $priority][$identifier])){
unset(static::$handlerPriority[(int) $priority][$identifier]);
}else{
for($priority = EventPriority::MONITOR; $priority <= EventPriority::LOWEST; ++$priority){
unset(static::$handlerPriority[$priority][$identifier]);
if(count(static::$handlerPriority[$priority]) === 0){
unset(static::$handlerPriority[$priority]);
}
}
}
unset(static::$handlers[$identifier]);
return true;
}else{
return false;
}
}
}

View File

@ -19,10 +19,10 @@
* *
*/ */
class PocketMinecraftServer{ class MainServer{
public $tCnt; public $tCnt;
public $serverID, $interface, $database, $version, $invisible, $tickMeasure, $preparedSQL, $seed, $gamemode, $name, $maxClients, $clients, $eidCnt, $custom, $description, $motd, $port, $saveEnabled; public $serverID, $interface, $database, $version, $invisible, $tickMeasure, $preparedSQL, $spawn, $whitelist, $seed, $stop, $gamemode, $difficulty, $name, $maxClients, $clients, $eidCnt, $custom, $description, $motd, $port, $saveEnabled;
private $serverip, $evCnt, $handCnt, $events, $eventsID, $handlers, $serverType, $lastTick, $ticks, $memoryStats, $async = array(), $asyncID = 0; private $serverip, $evCnt, $handCnt, $events, $eventsID, $handlers, $serverType, $lastTick, $doTick, $ticks, $memoryStats, $schedule, $asyncThread, $async = array(), $asyncID = 0;
/** /**
* @var ServerAPI * @var ServerAPI
@ -45,10 +45,7 @@ class PocketMinecraftServer{
$this->eventsID = array(); $this->eventsID = array();
$this->handlers = array(); $this->handlers = array();
$this->invisible = false; $this->invisible = false;
$this->levelData = false;
$this->difficulty = 1; $this->difficulty = 1;
$this->tiles = array();
$this->entities = array();
$this->custom = array(); $this->custom = array();
$this->evCnt = 1; $this->evCnt = 1;
$this->handCnt = 1; $this->handCnt = 1;
@ -57,14 +54,14 @@ class PocketMinecraftServer{
$this->schedule = array(); $this->schedule = array();
$this->scheduleCnt = 1; $this->scheduleCnt = 1;
$this->description = ""; $this->description = "";
$this->whitelist = false;
$this->memoryStats = array(); $this->memoryStats = array();
$this->clients = array(); $this->clients = array();
$this->spawn = false; $this->spawn = false;
$this->saveEnabled = true; $this->saveEnabled = true;
$this->whitelist = false;
$this->tickMeasure = array_fill(0, 40, 0); $this->tickMeasure = array_fill(0, 40, 0);
$this->setType("normal"); $this->setType("normal");
$this->interface = new MinecraftInterface($this, "255.255.255.255", $this->port, true, false, $this->serverip); $this->interface = new MinecraftInterface("255.255.255.255", $this->port, $this->serverip);
$this->stop = false; $this->stop = false;
$this->ticks = 0; $this->ticks = 0;
if(!defined("NO_THREADS")){ if(!defined("NO_THREADS")){
@ -129,7 +126,7 @@ class PocketMinecraftServer{
public function startDatabase(){ public function startDatabase(){
$this->preparedSQL = new stdClass(); $this->preparedSQL = new stdClass();
$this->preparedSQL->entity = new stdClass(); $this->preparedSQL->entity = new stdClass();
$this->database = new SQLite3(":memory:"); $this->database = new SQLite3(":memory:", SQLITE3_OPEN_READWRITE | SQLITE3_OPEN_CREATE);
$this->query("PRAGMA journal_mode = OFF;"); $this->query("PRAGMA journal_mode = OFF;");
$this->query("PRAGMA encoding = \"UTF-8\";"); $this->query("PRAGMA encoding = \"UTF-8\";");
$this->query("PRAGMA secure_delete = OFF;"); $this->query("PRAGMA secure_delete = OFF;");
@ -231,6 +228,10 @@ class PocketMinecraftServer{
$d .= Utils::writeShort(strlen($key)).$key . Utils::writeInt(strlen($value)).$value; $d .= Utils::writeShort(strlen($key)).$key . Utils::writeInt(strlen($value)).$value;
} }
break; break;
case ASYNC_FUNCTION:
$params = serialize($data["arguments"]);
$d .= Utils::writeShort(strlen($data["function"])).$data["function"] . Utils::writeInt(strlen($params)) . $params;
break;
default: default:
return false; return false;
} }
@ -259,6 +260,12 @@ class PocketMinecraftServer{
$data["result"] = substr($this->asyncThread->output, $offset, $len); $data["result"] = substr($this->asyncThread->output, $offset, $len);
$offset += $len; $offset += $len;
break; break;
case ASYNC_FUNCTION:
$len = Utils::readInt(substr($this->asyncThread->output, $offset, 4));
$offset += 4;
$data["result"] = unserialize(substr($this->asyncThread->output, $offset, $len));
$offset += $len;
break;
} }
$this->asyncThread->output = substr($this->asyncThread->output, $offset); $this->asyncThread->output = substr($this->asyncThread->output, $offset);
if(isset($this->async[$ID]) and $this->async[$ID] !== null and is_callable($this->async[$ID])){ if(isset($this->async[$ID]) and $this->async[$ID] !== null and is_callable($this->async[$ID])){
@ -316,7 +323,6 @@ class PocketMinecraftServer{
$handlers->finalize(); $handlers->finalize();
foreach($call as $hnid => $boolean){ foreach($call as $hnid => $boolean){
if($result !== false and $result !== true){ if($result !== false and $result !== true){
$called[$hnid] = true;
$handler = $this->handlers[$hnid]; $handler = $this->handlers[$hnid];
if(is_array($handler)){ if(is_array($handler)){
$method = $handler[1]; $method = $handler[1];
@ -388,6 +394,7 @@ class PocketMinecraftServer{
if($this->stop === true){ if($this->stop === true){
return; return;
} }
ini_set("memory_limit", "-1"); //Fix error dump not dumped on memory problems
console("[SEVERE] An unrecovereable has ocurred and the server has crashed. Creating an error dump"); console("[SEVERE] An unrecovereable has ocurred and the server has crashed. Creating an error dump");
$dump = "```\r\n# PocketMine-MP Error Dump ".date("D M j H:i:s T Y")."\r\n"; $dump = "```\r\n# PocketMine-MP Error Dump ".date("D M j H:i:s T Y")."\r\n";
$er = error_get_last(); $er = error_get_last();
@ -420,6 +427,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";
@ -451,6 +463,7 @@ class PocketMinecraftServer{
} }
$dump .= "Loaded Modules: ".var_export($extensions, true)."\r\n"; $dump .= "Loaded Modules: ".var_export($extensions, true)."\r\n";
$this->checkMemory();
$dump .= "Memory Usage Tracking: \r\n".chunk_split(base64_encode(gzdeflate(implode(";", $this->memoryStats), 9)))."\r\n"; $dump .= "Memory Usage Tracking: \r\n".chunk_split(base64_encode(gzdeflate(implode(";", $this->memoryStats), 9)))."\r\n";
ob_start(); ob_start();
phpinfo(); phpinfo();
@ -479,7 +492,7 @@ class PocketMinecraftServer{
public function packetHandler(Packet $packet){ public function packetHandler(Packet $packet){
$data =& $packet; $data =& $packet;
$CID = PocketMinecraftServer::clientID($packet->ip, $packet->port); $CID = MainServer::clientID($packet->ip, $packet->port);
if(isset($this->clients[$CID])){ if(isset($this->clients[$CID])){
$this->clients[$CID]->handlePacket($packet); $this->clients[$CID]->handlePacket($packet);
}else{ }else{

View File

@ -63,6 +63,7 @@ class Player{
public $blocked = true; public $blocked = true;
public $achievements = array(); public $achievements = array();
public $chunksLoaded = array(); public $chunksLoaded = array();
private $viewDistance;
private $chunksOrder = array(); private $chunksOrder = array();
private $lastMeasure = 0; private $lastMeasure = 0;
private $bandwidthRaw = 0; private $bandwidthRaw = 0;
@ -103,7 +104,7 @@ class Player{
$this->server = ServerAPI::request(); $this->server = ServerAPI::request();
$this->lastBreak = microtime(true); $this->lastBreak = microtime(true);
$this->clientID = $clientID; $this->clientID = $clientID;
$this->CID = PocketMinecraftServer::clientID($ip, $port); $this->CID = MainServer::clientID($ip, $port);
$this->ip = $ip; $this->ip = $ip;
$this->port = $port; $this->port = $port;
$this->spawnPosition = $this->server->spawn; $this->spawnPosition = $this->server->spawn;
@ -112,6 +113,7 @@ class Player{
$this->armor = array(); $this->armor = array();
$this->gamemode = $this->server->gamemode; $this->gamemode = $this->server->gamemode;
$this->level = $this->server->api->level->getDefault(); $this->level = $this->server->api->level->getDefault();
$this->viewDistance = (int) $this->server->api->getProperty("view-distance");
$this->slot = 0; $this->slot = 0;
$this->hotbar = array(0, -1, -1, -1, -1, -1, -1, -1, -1); $this->hotbar = array(0, -1, -1, -1, -1, -1, -1, -1, -1);
$this->packetStats = array(0,0); $this->packetStats = array(0,0);
@ -148,22 +150,35 @@ class Player{
if(!($this->entity instanceof Entity) or $this->connected === false){ if(!($this->entity instanceof Entity) or $this->connected === false){
return false; return false;
} }
$X = ($this->entity->x - 0.5) / 16;
$Z = ($this->entity->z - 0.5) / 16; $newOrder = array();
$v = new Vector2($X, $Z); $lastLoaded = $this->chunksLoaded;
$this->chunksOrder = array(); $centerX = intval(($this->entity->x - 0.5) / 16);
for($x = 0; $x < 16; ++$x){ $centerZ = intval(($this->entity->z - 0.5) / 16);
for($z = 0; $z < 16; ++$z){ $startX = $centerX - $this->viewDistance;
$dist = $v->distance(new Vector2($x, $z)); $startZ = $centerZ - $this->viewDistance;
for($y = 0; $y < 8; ++$y){ $finalX = $centerX + $this->viewDistance;
$d = $x.":".$y.":".$z; $finalZ = $centerZ + $this->viewDistance;
if(!isset($this->chunksLoaded[$d])){ for($X = $startX; $X <= $finalX; ++$X){
$this->chunksOrder[$d] = $dist; for($Z = $startZ; $Z <= $finalZ; ++$Z){
$distance = abs($X - $centerX) + abs($Z - $centerZ);
for($Y = 0; $Y < 8; ++$Y){
$index = "$X:$Y:$Z";
if(!isset($lastLoaded[$index])){
$newOrder[$index] = $distance;
}else{
unset($lastLoaded[$index]);
} }
} }
} }
} }
asort($this->chunksOrder); asort($newOrder);
$this->chunksOrder = $newOrder;
foreach($lastLoaded as $index => $distance){
$id = explode(":", $index);
$this->level->freeChunk($id[0], $id[2], $this);
unset($this->chunksLoaded[$index]);
}
} }
public function getNextChunk(){ public function getNextChunk(){
@ -195,8 +210,8 @@ class Player{
$c = key($this->chunksOrder); $c = key($this->chunksOrder);
$d = @$this->chunksOrder[$c]; $d = @$this->chunksOrder[$c];
if($c === null or $d > $this->server->api->getProperty("view-distance")){ if($c === null or $d === null){
$this->server->schedule(50, array($this, "getNextChunk")); $this->server->schedule(40, array($this, "getNextChunk"));
return false; return false;
} }
unset($this->chunksOrder[$c]); unset($this->chunksOrder[$c]);
@ -207,7 +222,6 @@ class Player{
$Y = $id[1]; $Y = $id[1];
$x = $X << 4; $x = $X << 4;
$z = $Z << 4; $z = $Z << 4;
$y = $Y << 4;
$this->level->useChunk($X, $Z, $this); $this->level->useChunk($X, $Z, $this);
$Yndex = 1 << $Y; $Yndex = 1 << $Y;
for($iY = 0; $iY < 8; ++$iY){ for($iY = 0; $iY < 8; ++$iY){
@ -218,8 +232,8 @@ class Player{
} }
} }
$pk = new ChunkDataPacket; $pk = new ChunkDataPacket;
$pk->x = $X; $pk->chunkX = $X;
$pk->z = $Z; $pk->chunkZ = $Z;
$pk->data = $this->level->getOrderedChunk($X, $Z, $Yndex); $pk->data = $this->level->getOrderedChunk($X, $Z, $Yndex);
$cnt = $this->dataPacket($pk); $cnt = $this->dataPacket($pk);
if($cnt === false){ if($cnt === false){
@ -294,7 +308,6 @@ class Player{
$this->directDataPacket(new DisconnectPacket); $this->directDataPacket(new DisconnectPacket);
$this->connected = false; $this->connected = false;
$this->level->freeAllChunks($this); $this->level->freeAllChunks($this);
$this->spawned = false;
$this->loggedIn = false; $this->loggedIn = false;
$this->buffer = null; $this->buffer = null;
unset($this->buffer); unset($this->buffer);
@ -306,6 +319,7 @@ class Player{
if($msg === true and $this->username != "" and $this->spawned !== false){ if($msg === true and $this->username != "" and $this->spawned !== false){
$this->server->api->chat->broadcast($this->username." left the game"); $this->server->api->chat->broadcast($this->username." left the game");
} }
$this->spawned = false;
console("[INFO] ".FORMAT_AQUA.$this->username.FORMAT_RESET."[/".$this->ip.":".$this->port."] logged out due to ".$reason); console("[INFO] ".FORMAT_AQUA.$this->username.FORMAT_RESET."[/".$this->ip.":".$this->port."] logged out due to ".$reason);
$this->windows = array(); $this->windows = array();
$this->armor = array(); $this->armor = array();
@ -313,7 +327,7 @@ class Player{
$this->chunksLoaded = array(); $this->chunksLoaded = array();
$this->chunksOrder = array(); $this->chunksOrder = array();
$this->chunkCount = array(); $this->chunkCount = array();
$this->cratingItems = array(); $this->craftingItems = array();
$this->received = array(); $this->received = array();
} }
} }
@ -683,11 +697,10 @@ class Player{
return; return;
}else{ }else{
$message = $data->get(); $message = $data->get();
$this->sendChat(preg_replace('/\x1b\[[0-9;]*m/', "", $message["message"]), $message["player"]); //Remove ANSI codes from chat $this->sendChat($message["message"], $message["player"]);
} }
}else{ }else{
$message = (string) $data; $this->sendChat((string) $data);
$this->sendChat(preg_replace('/\x1b\[[0-9;]*m/', "", (string) $data)); //Remove ANSI codes from chat
} }
break; break;
} }
@ -1253,6 +1266,11 @@ class Player{
if($this->connected === false){ if($this->connected === false){
return; return;
} }
if(EventHandler::callEvent(new DataPacketReceiveEvent($this, $packet)) === BaseEvent::DENY){
return;
}
switch($packet->pid()){ switch($packet->pid()){
case 0x01: case 0x01:
break; break;
@ -1286,8 +1304,10 @@ class Player{
if($this->loggedIn === true){ if($this->loggedIn === true){
break; break;
} }
$this->username = $packet->username;
$this->iusername = strtolower($this->username);
$this->loginData = array("clientId" => $packet->clientId, "loginData" => $packet->loginData); $this->loginData = array("clientId" => $packet->clientId, "loginData" => $packet->loginData);
if(count($this->server->clients) > $this->server->maxClients){ if(count($this->server->clients) > $this->server->maxClients and !$this->server->api->ban->isOp($this->iusername)){
$this->close("server is full!", false); $this->close("server is full!", false);
return; return;
} }
@ -1302,16 +1322,11 @@ class Player{
$this->directDataPacket($pk); $this->directDataPacket($pk);
} }
$this->close("Incorrect protocol #".$packet->protocol1, false); $this->close("Incorrect protocol #".$packet->protocol1, false);
break; return;
} }
if(preg_match('#[^a-zA-Z0-9_]#', $packet->username) == 0 and $packet->username != ""){ if(preg_match('#^[a-zA-Z0-9_]{3,16}$#', $this->username) == 0 or $this->username === "" or $this->iusername === "rcon" or $this->iusername === "console"){
$this->username = $packet->username;
$this->iusername = strtolower($this->username);
}else{
$this->username = $packet->username;
$this->iusername = strtolower($this->username);
$this->close("Bad username", false); $this->close("Bad username", false);
break; return;
} }
if($this->server->api->handle("player.connect", $this) === false){ if($this->server->api->handle("player.connect", $this) === false){
$this->close("Unknown reason", false); $this->close("Unknown reason", false);
@ -1360,8 +1375,8 @@ class Player{
$inv[] = array($item[0], $item[1], 1); $inv[] = array($item[0], $item[1], 1);
} }
} }
$this->data->set("inventory", $inv);
} }
$this->data->set("inventory", $inv);
} }
$this->achievements = $this->data->get("achievements"); $this->achievements = $this->data->get("achievements");
$this->data->set("caseusername", $this->username); $this->data->set("caseusername", $this->username);
@ -1466,7 +1481,7 @@ class Player{
} }
$this->sendInventory(); $this->sendInventory();
$this->sendSettings(); $this->sendSettings();
$this->server->schedule(50, array($this, "orderChunks"), array(), true); $this->server->schedule(30, array($this, "orderChunks"), array(), true);
$this->blocked = false; $this->blocked = false;
$pk = new SetTimePacket; $pk = new SetTimePacket;
@ -1643,7 +1658,7 @@ class Player{
$this->entity->updateMetadata(); $this->entity->updateMetadata();
} }
if($this->blocked === true or ($this->entity->position instanceof Vector3 and $blockVector->distance($this->entity->position) > 10)){ if($this->blocked === true or ($this->entity instanceof Entity and $blockVector->distance($this->entity) > 10)){
}elseif($this->getSlot($this->slot)->getID() !== $packet->item or ($this->getSlot($this->slot)->isTool() === false and $this->getSlot($this->slot)->getMetadata() !== $packet->meta)){ }elseif($this->getSlot($this->slot)->getID() !== $packet->item or ($this->getSlot($this->slot)->isTool() === false and $this->getSlot($this->slot)->getMetadata() !== $packet->meta)){
$this->sendInventorySlot($this->slot); $this->sendInventorySlot($this->slot);
@ -1990,6 +2005,7 @@ class Player{
$packet->item = $this->getSlot($this->slot); $packet->item = $this->getSlot($this->slot);
$this->craftingItems = array(); $this->craftingItems = array();
$this->toCraft = array(); $this->toCraft = array();
$data = array();
$data["eid"] = $packet->eid; $data["eid"] = $packet->eid;
$data["unknown"] = $packet->unknown; $data["unknown"] = $packet->unknown;
$data["item"] = $packet->item; $data["item"] = $packet->item;
@ -2009,6 +2025,7 @@ class Player{
} }
$this->craftingItems = array(); $this->craftingItems = array();
$this->toCraft = array(); $this->toCraft = array();
$packet->message = TextFormat::clean($packet->message);
if(trim($packet->message) != "" and strlen($packet->message) <= 255){ if(trim($packet->message) != "" and strlen($packet->message) <= 255){
$message = $packet->message; $message = $packet->message;
if($message{0} === "/"){ //Command if($message{0} === "/"){ //Command
@ -2153,6 +2170,7 @@ class Player{
if($item->getID() !== AIR and $slot->getID() == $item->getID()){ if($item->getID() !== AIR and $slot->getID() == $item->getID()){
if($slot->count < $item->count){ if($slot->count < $item->count){
if($this->removeItem($item->getID(), $item->getMetadata(), $item->count - $slot->count, false) === false){ if($this->removeItem($item->getID(), $item->getMetadata(), $item->count - $slot->count, false) === false){
$this->sendInventory();
break; break;
} }
}elseif($slot->count > $item->count){ }elseif($slot->count > $item->count){
@ -2160,6 +2178,7 @@ class Player{
} }
}else{ }else{
if($this->removeItem($item->getID(), $item->getMetadata(), $item->count, false) === false){ if($this->removeItem($item->getID(), $item->getMetadata(), $item->count, false) === false){
$this->sendInventory();
break; break;
} }
$this->addItem($slot->getID(), $slot->getMetadata(), $slot->count, false); $this->addItem($slot->getID(), $slot->getMetadata(), $slot->count, false);
@ -2199,6 +2218,7 @@ class Player{
if($item->getID() !== AIR and $slot->getID() == $item->getID()){ if($item->getID() !== AIR and $slot->getID() == $item->getID()){
if($slot->count < $item->count){ if($slot->count < $item->count){
if($this->removeItem($item->getID(), $item->getMetadata(), $item->count - $slot->count, false) === false){ if($this->removeItem($item->getID(), $item->getMetadata(), $item->count - $slot->count, false) === false){
$this->sendInventory();
break; break;
} }
}elseif($slot->count > $item->count){ }elseif($slot->count > $item->count){
@ -2206,6 +2226,7 @@ class Player{
} }
}else{ }else{
if($this->removeItem($item->getID(), $item->getMetadata(), $item->count, false) === false){ if($this->removeItem($item->getID(), $item->getMetadata(), $item->count, false) === false){
$this->sendInventory();
break; break;
} }
$this->addItem($slot->getID(), $slot->getMetadata(), $slot->count, false); $this->addItem($slot->getID(), $slot->getMetadata(), $slot->count, false);
@ -2230,12 +2251,11 @@ class Player{
$t->spawn($this); $t->spawn($this);
}else{ }else{
$nbt = new NBT(); $nbt = new NBT();
$nbt->load($packet->namedtag); $nbt->read($packet->namedtag);
$d = array_shift($nbt->tree); if($nbt->id !== TILE_SIGN){
if($d["id"] !== TILE_SIGN){
$t->spawn($this); $t->spawn($this);
}else{ }else{
$t->setText($d["Text1"], $d["Text2"], $d["Text3"], $d["Text4"]); $t->setText($nbt->Text1, $nbt->Text2, $nbt->Text3, $nbt->Text4);
} }
} }
} }
@ -2305,17 +2325,19 @@ class Player{
} }
public function sendBuffer(){ public function sendBuffer(){
if($this->bufferLen > 0 and $this->buffer instanceof RakNetPacket){ if($this->connected === true){
$this->buffer->seqNumber = $this->counter[0]++; if($this->bufferLen > 0 and $this->buffer instanceof RakNetPacket){
$this->send($this->buffer); $this->buffer->seqNumber = $this->counter[0]++;
$this->send($this->buffer);
}
$this->bufferLen = 0;
$this->buffer = new RakNetPacket(RakNetInfo::DATA_PACKET_0);
$this->buffer->data = array();
$this->nextBuffer = microtime(true) + 0.1;
} }
$this->bufferLen = 0;
$this->buffer = new RakNetPacket(RakNetInfo::DATA_PACKET_0);
$this->buffer->data = array();
$this->nextBuffer = microtime(true) + 0.1;
} }
public function directBigRawPacket(RakNetDataPacket $packet){ private function directBigRawPacket(RakNetDataPacket $packet){
if($this->connected === false){ if($this->connected === false){
return false; return false;
} }
@ -2351,10 +2373,14 @@ class Player{
return $cnts; return $cnts;
} }
public function directDataPacket(RakNetDataPacket $packet, $reliability = 0, $recover = true){ public function directDataPacket(RakNetDataPacket $packet, $recover = true){
if($this->connected === false){ if($this->connected === false){
return false; return false;
} }
if(EventHandler::callEvent(new DataPacketSendEvent($this, $packet)) === BaseEvent::DENY){
return array();
}
$packet->encode(); $packet->encode();
$pk = new RakNetPacket(RakNetInfo::DATA_PACKET_0); $pk = new RakNetPacket(RakNetInfo::DATA_PACKET_0);
$pk->data[] = $packet; $pk->data[] = $packet;
@ -2378,6 +2404,11 @@ class Player{
if($this->connected === false){ if($this->connected === false){
return false; return false;
} }
if(EventHandler::callEvent(new DataPacketSendEvent($this, $packet)) === BaseEvent::DENY){
return;
}
$packet->encode(); $packet->encode();
$len = strlen($packet->buffer) + 1; $len = strlen($packet->buffer) + 1;
$MTU = $this->MTU - 24; $MTU = $this->MTU - 24;
@ -2391,7 +2422,7 @@ class Player{
$packet->messageIndex = $this->counter[3]++; $packet->messageIndex = $this->counter[3]++;
$packet->reliability = 2; $packet->reliability = 2;
$this->buffer->data[] = $packet; @$this->buffer->data[] = $packet;
$this->bufferLen += 6 + $len; $this->bufferLen += 6 + $len;
return array(); return array();
} }

View File

@ -1,17 +1,16 @@
#!/bin/bash #!/bin/bash
COMPILER_VERSION="0.16" PHP_VERSION="5.5.10"
PHP_VERSION="5.5.9"
ZEND_VM="GOTO" ZEND_VM="GOTO"
LIBEDIT_VERSION="0.3"
ZLIB_VERSION="1.2.8" ZLIB_VERSION="1.2.8"
OPENSSL_VERSION="1.0.0l"
CURL_VERSION="curl-7_35_0"
LIBEDIT_VERSION="0.3"
PTHREADS_VERSION="0.1.0" PTHREADS_VERSION="0.1.0"
PHPYAML_VERSION="1.1.1" PHPYAML_VERSION="1.1.1"
YAML_VERSION="0.1.4" YAML_VERSION="0.1.4"
CURL_VERSION="curl-7_35_0"
echo "[PocketMine] PHP installer and compiler for Linux & Mac" echo "[PocketMine] PHP compiler for Linux, MacOS and Android"
DIR="$(pwd)" DIR="$(pwd)"
date > "$DIR/install.log" 2>&1 date > "$DIR/install.log" 2>&1
uname -a >> "$DIR/install.log" 2>&1 uname -a >> "$DIR/install.log" 2>&1
@ -42,43 +41,82 @@ export CC="gcc"
COMPILE_FOR_ANDROID=no COMPILE_FOR_ANDROID=no
RANLIB=ranlib RANLIB=ranlib
HAVE_MYSQLI="--with-mysqli=mysqlnd" HAVE_MYSQLI="--with-mysqli=mysqlnd"
if [ "$1" == "rpi" ]; then COMPILE_TARGET=""
[ -z "$march" ] && march=armv6zk; COMPILE_OPENSSL="no"
[ -z "$mtune" ] && mtune=arm1176jzf-s; COMPILE_CURL="default"
[ -z "$CFLAGS" ] && CFLAGS="-mfloat-abi=hard -mfpu=vfp"; COMPILE_LIBEDIT="no"
echo "[INFO] Compiling for Raspberry Pi ARMv6zk hard float" IS_CROSSCOMPILE="no"
elif [ "$1" == "mac" ]; then DO_OPTIMIZE="no"
[ -z "$march" ] && march=prescott; while getopts "::t:oj:cxff:" OPTION; do
[ -z "$mtune" ] && mtune=generic; case $OPTION in
[ -z "$CFLAGS" ] && CFLAGS="-fomit-frame-pointer"; t)
echo "[INFO] Compiling for Intel MacOS" echo "[opt] Set target to $OPTARG"
elif [ "$1" == "ios" ]; then COMPILE_TARGET="$OPTARG"
[ -z "$march" ] && march=armv6; ;;
[ -z "$mtune" ] && mtune=cortex-a8; j)
echo "[INFO] Compiling for iOS ARMv6" echo "[opt] Set make threads to $OPTARG"
elif [ "$1" == "crosscompile" ]; then THREADS="$OPTARG"
HAVE_MYSQLI="--without-mysqli" ;;
if [ "$2" == "android" ] || [ "$2" == "android-armv6" ]; then o)
echo "[opt] Will compile OpenSSL"
COMPILE_OPENSSL="yes"
;;
l)
echo "[opt] Will compile libedit"
COMPILE_LIBEDIT="yes"
;;
c)
echo "[opt] Will force compile cURL"
COMPILE_CURL="yes"
;;
x)
echo "[opt] Doing cross-compile"
IS_CROSSCOMPILE="yes"
;;
f)
echo "[opt] Enabling abusive optimizations..."
DO_OPTIMIZE="yes"
ffast_math="-fno-math-errno -funsafe-math-optimizations -fno-trapping-math -ffinite-math-only -fno-rounding-math -fno-signaling-nans -fcx-limited-range" #workaround SQLite3 fail
CFLAGS="$CFLAGS -O2 -DSQLITE_HAVE_ISNAN $ffast_math -fno-signed-zeros -finline-functions -funsafe-loop-optimizations -fomit-frame-pointer -frename-registers -funroll-loops -funswitch-loops -fpredictive-commoning -fgcse-after-reload -ftree-vectorize -ftracer -ftree-loop-im -fivopts -ftree-parallelize-loops=4 -fomit-frame-pointer"
if [ "$OPTARG" == "arm" ]; then
CFLAGS="$CFLAGS -mfloat-abi=softfp -mfpu=vfp"
elif [ "$OPTARG" == "x86_64" ]; then
CFLAGS="$CFLAGS -mmx -msse -msse2 -msse3 -mfpmath=sse -free -msahf"
elif [ "$OPTARG" == "x86" ]; then
CFLAGS="$CFLAGS -mmx -msse -msse2 -mfpmath=sse -m128bit-long-double -malign-double"
fi
;;
\?)
echo "Invalid option: -$OPTION$OPTARG" >&2
exit 1
;;
esac
done
if [ "$IS_CROSSCOMPILE" == "yes" ]; then
if [ "$COMPILE_TARGET" == "android" ] || [ "$COMPILE_TARGET" == "android-armv6" ]; then
COMPILE_FOR_ANDROID=yes COMPILE_FOR_ANDROID=yes
[ -z "$march" ] && march=armv6; [ -z "$march" ] && march=armv6;
[ -z "$mtune" ] && mtune=arm1136jf-s; [ -z "$mtune" ] && mtune=arm1136jf-s;
TOOLCHAIN_PREFIX="arm-unknown-linux-uclibcgnueabi" TOOLCHAIN_PREFIX="arm-unknown-linux-uclibcgnueabi"
export CC="$TOOLCHAIN_PREFIX-gcc" export CC="$TOOLCHAIN_PREFIX-gcc"
CONFIGURE_FLAGS="--host=$TOOLCHAIN_PREFIX --enable-static-link --disable-ipv6" CONFIGURE_FLAGS="--host=$TOOLCHAIN_PREFIX --enable-static-link --disable-ipv6"
CFLAGS="-uclibc --static $CFLAGS"; CFLAGS="-static -uclibc -Wl,-Bdynamic $CFLAGS"
LDFLAGS="--static"
echo "[INFO] Cross-compiling for Android ARMv6" echo "[INFO] Cross-compiling for Android ARMv6"
elif [ "$2" == "android-armv7" ]; then OPENSSL_TARGET="android"
HAVE_MYSQLI="--without-mysqli"
elif [ "$COMPILE_TARGET" == "android-armv7" ]; then
COMPILE_FOR_ANDROID=yes COMPILE_FOR_ANDROID=yes
[ -z "$march" ] && march=armv7-a; [ -z "$march" ] && march=armv7-a;
[ -z "$mtune" ] && mtune=cortex-a8; [ -z "$mtune" ] && mtune=cortex-a8;
TOOLCHAIN_PREFIX="arm-unknown-linux-uclibcgnueabi" TOOLCHAIN_PREFIX="arm-unknown-linux-uclibcgnueabi"
export CC="$TOOLCHAIN_PREFIX-gcc" export CC="$TOOLCHAIN_PREFIX-gcc"
CONFIGURE_FLAGS="--host=$TOOLCHAIN_PREFIX --enable-static-link --disable-ipv6" CONFIGURE_FLAGS="--host=$TOOLCHAIN_PREFIX --enable-static-link --disable-ipv6"
CFLAGS="-uclibc --static $CFLAGS"; CFLAGS="-static -uclibc -Wl,-Bdynamic $CFLAGS"
LDFLAGS="--static"
echo "[INFO] Cross-compiling for Android ARMv7" echo "[INFO] Cross-compiling for Android ARMv7"
elif [ "$2" == "rpi" ]; then OPENSSL_TARGET="android-armv7"
HAVE_MYSQLI="--without-mysqli"
elif [ "$COMPILE_TARGET" == "rpi" ]; then
TOOLCHAIN_PREFIX="arm-linux-gnueabihf" TOOLCHAIN_PREFIX="arm-linux-gnueabihf"
[ -z "$march" ] && march=armv6zk; [ -z "$march" ] && march=armv6zk;
[ -z "$mtune" ] && mtune=arm1176jzf-s; [ -z "$mtune" ] && mtune=arm1176jzf-s;
@ -86,8 +124,9 @@ elif [ "$1" == "crosscompile" ]; then
export CC="$TOOLCHAIN_PREFIX-gcc" export CC="$TOOLCHAIN_PREFIX-gcc"
CONFIGURE_FLAGS="--host=$TOOLCHAIN_PREFIX" CONFIGURE_FLAGS="--host=$TOOLCHAIN_PREFIX"
[ -z "$CFLAGS" ] && CFLAGS="-uclibc"; [ -z "$CFLAGS" ] && CFLAGS="-uclibc";
OPENSSL_TARGET="linux-armv4"
echo "[INFO] Cross-compiling for Raspberry Pi ARMv6zk hard float" echo "[INFO] Cross-compiling for Raspberry Pi ARMv6zk hard float"
elif [ "$2" == "mac" ]; then elif [ "$COMPILE_TARGET" == "mac" ]; then
[ -z "$march" ] && march=prescott; [ -z "$march" ] && march=prescott;
[ -z "$mtune" ] && mtune=generic; [ -z "$mtune" ] && mtune=generic;
[ -z "$CFLAGS" ] && CFLAGS="-fomit-frame-pointer"; [ -z "$CFLAGS" ] && CFLAGS="-fomit-frame-pointer";
@ -96,33 +135,75 @@ elif [ "$1" == "crosscompile" ]; then
CONFIGURE_FLAGS="--host=$TOOLCHAIN_PREFIX" CONFIGURE_FLAGS="--host=$TOOLCHAIN_PREFIX"
#zlib doesn't use the correct ranlib #zlib doesn't use the correct ranlib
RANLIB=$TOOLCHAIN_PREFIX-ranlib RANLIB=$TOOLCHAIN_PREFIX-ranlib
OPENSSL_TARGET="darwin64-x86_64-cc"
echo "[INFO] Cross-compiling for Intel MacOS" echo "[INFO] Cross-compiling for Intel MacOS"
elif [ "$2" == "ios" ] || [ "$2" == "ios-armv6" ]; then elif [ "$COMPILE_TARGET" == "ios" ] || [ "$COMPILE_TARGET" == "ios-armv6" ]; then
[ -z "$march" ] && march=armv6; [ -z "$march" ] && march=armv6;
[ -z "$mtune" ] && mtune=generic-armv6; [ -z "$mtune" ] && mtune=arm1176jzf-s;
CONFIGURE_FLAGS="--target=arm-apple-darwin10" TOOLCHAIN_PREFIX="arm-apple-darwin10"
elif [ "$2" == "ios-armv7" ]; then export CC="$TOOLCHAIN_PREFIX-gcc"
CONFIGURE_FLAGS="--host=$TOOLCHAIN_PREFIX --target=$TOOLCHAIN_PREFIX -miphoneos-version-min=4.2"
OPENSSL_TARGET="BSD-generic32"
HAVE_MYSQLI="--without-mysqli"
elif [ "$COMPILE_TARGET" == "ios-armv7" ]; then
[ -z "$march" ] && march=armv7-a; [ -z "$march" ] && march=armv7-a;
[ -z "$mtune" ] && mtune=generic-armv7-a; [ -z "$mtune" ] && mtune=cortex-a8;
CONFIGURE_FLAGS="--target=arm-apple-darwin10" TOOLCHAIN_PREFIX="arm-apple-darwin10"
export CC="$TOOLCHAIN_PREFIX-gcc"
CONFIGURE_FLAGS="--host=$TOOLCHAIN_PREFIX --target=$TOOLCHAIN_PREFIX -miphoneos-version-min=4.2"
OPENSSL_TARGET="BSD-generic32"
HAVE_MYSQLI="--without-mysqli"
if [ "$DO_OPTIMIZE" == "yes" ]; then
CFLAGS="$CFLAGS -mfpu=neon"
fi
else else
echo "Please supply a proper platform [android android-armv6 android-armv7 rpi mac ios ios-armv6 ios-armv7] to cross-compile" echo "Please supply a proper platform [android android-armv6 android-armv7 rpi mac ios ios-armv6 ios-armv7] to cross-compile"
exit 1 exit 1
fi fi
elif [ "$COMPILE_TARGET" == "rpi" ]; then
[ -z "$march" ] && march=armv6zk;
[ -z "$mtune" ] && mtune=arm1176jzf-s;
[ -z "$CFLAGS" ] && CFLAGS="-mfloat-abi=hard -mfpu=vfp";
OPENSSL_TARGET="linux-armv4"
echo "[INFO] Compiling for Raspberry Pi ARMv6zk hard float"
elif [ "$COMPILE_TARGET" == "mac" ] || [ "$COMPILE_TARGET" == "mac32" ]; then
[ -z "$march" ] && march=prescott;
[ -z "$mtune" ] && mtune=generic;
[ -z "$CFLAGS" ] && CFLAGS="-m32 -arch i386 -fomit-frame-pointer -mmacosx-version-min=10.5";
[ -z "$LDFLAGS" ] && LDFLAGS="-Wl,-rpath,@loader_path/../lib";
export DYLD_LIBRARY_PATH="@loader_path/../lib"
OPENSSL_TARGET="darwin-i386-cc"
echo "[INFO] Compiling for Intel MacOS x86"
elif [ "$COMPILE_TARGET" == "mac64" ]; then
[ -z "$march" ] && march=core2;
[ -z "$mtune" ] && mtune=generic;
[ -z "$CFLAGS" ] && CFLAGS="-m64 -arch x86_64 -fomit-frame-pointer -mmacosx-version-min=10.5";
[ -z "$LDFLAGS" ] && LDFLAGS="-Wl,-rpath,@loader_path/../lib";
export DYLD_LIBRARY_PATH="@loader_path/../lib"
OPENSSL_TARGET="darwin64-x86_64-cc"
echo "[INFO] Compiling for Intel MacOS x86_64"
elif [ "$COMPILE_TARGET" == "ios" ]; then
[ -z "$march" ] && march=armv7-a;
[ -z "$mtune" ] && mtune=cortex-a8;
echo "[INFO] Compiling for iOS ARMv7"
OPENSSL_TARGET="linux-armv4"
elif [ -z "$CFLAGS" ]; then elif [ -z "$CFLAGS" ]; then
if [ `getconf LONG_BIT` = "64" ]; then if [ `getconf LONG_BIT` == "64" ]; then
echo "[INFO] Compiling for current machine using 64-bit" echo "[INFO] Compiling for current machine using 64-bit"
CFLAGS="-m64 $CFLAGS" CFLAGS="-m64 $CFLAGS"
OPENSSL_TARGET="linux-x86_64"
else else
echo "[INFO] Compiling for current machine using 32-bit" echo "[INFO] Compiling for current machine using 32-bit"
CFLAGS="-m32 $CFLAGS" CFLAGS="-m32 $CFLAGS"
OPENSSL_TARGET="linux-generic32"
fi fi
fi fi
cat > test.c <<'CTEST' cat > test.c <<'CTEST'
#include <stdio.h> #include <stdio.h>
main(){ int main(void){
printf("Hello world\n"); printf("Hello world\n");
return 0;
} }
CTEST CTEST
@ -133,7 +214,7 @@ type $CC >> "$DIR/install.log" 2>&1 || { echo >&2 "[ERROR] Please install \"$CC\
[ -z "$march" ] && march=native; [ -z "$march" ] && march=native;
[ -z "$mtune" ] && mtune=native; [ -z "$mtune" ] && mtune=native;
[ -z "$CFLAGS" ] && CFLAGS=""; [ -z "$CFLAGS" ] && CFLAGS="";
[ -z "$LDFLAGS" ] && LDFLAGS=""; [ -z "$LDFLAGS" ] && LDFLAGS="-Wl,-rpath='\$\$ORIGIN/../lib'";
[ -z "$CONFIGURE_FLAGS" ] && CONFIGURE_FLAGS=""; [ -z "$CONFIGURE_FLAGS" ] && CONFIGURE_FLAGS="";
@ -149,16 +230,17 @@ else
fi fi
fi fi
rm test.* >> "$DIR/install.log" 2>&1
rm test >> "$DIR/install.log" 2>&1 rm test >> "$DIR/install.log" 2>&1
rm test.c >> "$DIR/install.log" 2>&1
export CFLAGS="-O2 $CFLAGS" export CFLAGS="-O2 $CFLAGS"
export LDFLAGS="$LDFLAGS" export LDFLAGS="$LDFLAGS"
rm -r -f install_data/ >> "$DIR/install.log" 2>&1 rm -r -f install_data/ >> "$DIR/install.log" 2>&1
rm -r -f bin/ >> "$DIR/install.log" 2>&1 rm -r -f bin/ >> "$DIR/install.log" 2>&1
mkdir -m 0777 install_data >> "$DIR/install.log" 2>&1 mkdir -m 0755 install_data >> "$DIR/install.log" 2>&1
mkdir -m 0777 bin >> "$DIR/install.log" 2>&1 mkdir -m 0755 bin >> "$DIR/install.log" 2>&1
mkdir -m 0755 bin/php5 >> "$DIR/install.log" 2>&1
cd install_data cd install_data
set -e set -e
@ -168,38 +250,43 @@ download_file "http://php.net/get/php-$PHP_VERSION.tar.gz/from/this/mirror" | ta
mv php-$PHP_VERSION php mv php-$PHP_VERSION php
echo " done!" echo " done!"
if [ 1 ] || [ "$1" == "crosscompile" ] || [ "$1" == "rpi" ]; then if [ "$IS_CROSSCOMPILE" == "yes" ] || [ "$COMPILE_TARGET" == "rpi" ] || [ "$COMPILE_TARGET" == "mac" ] || [ "$COMPILE_LIBEDIT" != "yes" ]; then
HAVE_LIBEDIT="--without-libedit" HAVE_LIBEDIT="--without-readline --without-libedit"
else else
#libedit #libedit
set +e
echo -n "[libedit] downloading $LIBEDIT_VERSION..." echo -n "[libedit] downloading $LIBEDIT_VERSION..."
download_file "http://download.sourceforge.net/project/libedit/libedit/libedit-$LIBEDIT_VERSION/libedit-$LIBEDIT_VERSION.tar.gz" | tar -zx >> "$DIR/install.log" 2>&1 download_file "http://download.sourceforge.net/project/libedit/libedit/libedit-$LIBEDIT_VERSION/libedit-$LIBEDIT_VERSION.tar.gz" | tar -zx >> "$DIR/install.log" 2>&1
echo -n " checking..." echo -n " checking..."
cd libedit cd libedit
./configure --prefix="$DIR/install_data/php/ext/libedit" --enable-static >> "$DIR/install.log" 2>&1 ./configure --prefix="$DIR/bin/php5" \
--enable-shared=yes \
--enable-static=no \
$CONFIGURE_FLAGS >> "$DIR/install.log" 2>&1
echo -n " compiling..." echo -n " compiling..."
if make -j $THREADS >> "$DIR/install.log" 2>&1; then if make -j $THREADS >> "$DIR/install.log" 2>&1; then
echo -n " installing..." echo -n " installing..."
make install >> "$DIR/install.log" 2>&1 make install >> "$DIR/install.log" 2>&1
HAVE_LIBEDIT="--with-libedit=\"$DIR/install_data/php/ext/libedit\"" HAVE_LIBEDIT="--without-readline --with-libedit=\"$DIR/bin/php5\""
else else
echo -n " disabling..." echo -n " disabling..."
HAVE_LIBEDIT="--without-libedit" HAVE_LIBEDIT="--without-readline --without-libedit"
fi fi
echo -n " cleaning..." echo -n " cleaning..."
cd .. cd ..
rm -r -f ./libedit rm -r -f ./libedit
echo " done!" echo " done!"
set -e
fi fi
#zlib #zlib
download_file "https://github.com/madler/zlib/archive/v$ZLIB_VERSION.tar.gz" | tar -zx >> "$DIR/install.log" 2>&1
echo -n "[zlib] downloading $ZLIB_VERSION..." echo -n "[zlib] downloading $ZLIB_VERSION..."
download_file "http://zlib.net/zlib-$ZLIB_VERSION.tar.gz" | tar -zx >> "$DIR/install.log" 2>&1
mv zlib-$ZLIB_VERSION zlib mv zlib-$ZLIB_VERSION zlib
echo -n " checking..." echo -n " checking..."
cd zlib cd zlib
RANLIB=$RANLIB ./configure --prefix="$DIR/install_data/php/ext/zlib" \ RANLIB=$RANLIB ./configure --prefix="$DIR/bin/php5" \
--static >> "$DIR/install.log" 2>&1 --shared >> "$DIR/install.log" 2>&1
echo -n " compiling..." echo -n " compiling..."
make -j $THREADS >> "$DIR/install.log" 2>&1 make -j $THREADS >> "$DIR/install.log" 2>&1
echo -n " installing..." echo -n " installing..."
@ -209,7 +296,48 @@ cd ..
rm -r -f ./zlib rm -r -f ./zlib
echo " done!" echo " done!"
if [ "$(uname -s)" == "Darwin" ] && [ "$1" != "crosscompile" ] && [ "$2" != "curl" ]; then if [ "$COMPILE_OPENSSL" == "yes" ] || [ "$COMPILE_CURL" != "no" ] && [ "$IS_CROSSCOMPILE" != "yes" ]; then
#OpenSSL
WITH_SSL="--with-ssl=$DIR/bin/php5"
WITH_OPENSSL="--with-openssl=$DIR/bin/php5"
echo -n "[OpenSSL] downloading $OPENSSL_VERSION..."
download_file "http://www.openssl.org/source/openssl-$OPENSSL_VERSION.tar.gz" | tar -zx >> "$DIR/install.log" 2>&1
mv openssl-$OPENSSL_VERSION openssl
echo -n " checking..."
cd openssl
RANLIB=$RANLIB ./Configure \
$OPENSSL_TARGET \
--prefix="$DIR/bin/php5" \
--openssldir="$DIR/bin/php5" \
zlib \
zlib-dynamic \
--with-zlib-lib="$DIR/bin/php5/lib" \
--with-zlib-include="$DIR/bin/php5/include" \
shared \
no-ssl2 \
no-asm \
no-hw \
no-engines \
no-static \
$CONFIGURE_FLAGS >> "$DIR/install.log" 2>&1
echo -n " compiling..."
make depend >> "$DIR/install.log" 2>&1
make >> "$DIR/install.log" 2>&1
echo -n " installing..."
make install >> "$DIR/install.log" 2>&1
echo -n " cleaning..."
cd ..
rm -r -f ./openssh
echo " done!"
else
WITH_SSL="--with-ssl"
WITH_OPENSSL="--without-ssl"
if [ "$(uname -s)" == "Darwin" ] && [ "$COMPILE_TARGET" != "crosscompile" ]; then
WITH_SSL="--with-darwinssl"
fi
fi
if [ "$(uname -s)" == "Darwin" ] && [ "$IS_CROSSCOMPILE" != "yes" ] && [ "$COMPILE_CURL" != "yes" ]; then
HAVE_CURL="shared,/usr" HAVE_CURL="shared,/usr"
else else
#curl #curl
@ -221,13 +349,14 @@ else
if [ ! -f ./configure ]; then if [ ! -f ./configure ]; then
./buildconf --force >> "$DIR/install.log" 2>&1 ./buildconf --force >> "$DIR/install.log" 2>&1
fi fi
./configure --disable-dependency-tracking \ RANLIB=$RANLIB ./configure --disable-dependency-tracking \
--enable-ipv6 \ --enable-ipv6 \
--enable-optimize \ --enable-optimize \
--enable-http \ --enable-http \
--enable-ftp \ --enable-ftp \
--disable-dict \ --disable-dict \
--enable-file \ --enable-file \
--without-librtmp \
--disable-gopher \ --disable-gopher \
--disable-imap \ --disable-imap \
--disable-pop3 \ --disable-pop3 \
@ -238,8 +367,10 @@ else
--disable-ldap \ --disable-ldap \
--disable-ldaps \ --disable-ldaps \
--without-libidn \ --without-libidn \
--with-zlib="$DIR/bin/php5" \
$WITH_SSL \
--enable-threaded-resolver \ --enable-threaded-resolver \
--prefix="$DIR/install_data/php/ext/curl" \ --prefix="$DIR/bin/php5" \
--disable-shared \ --disable-shared \
--enable-static \ --enable-static \
$CONFIGURE_FLAGS >> "$DIR/install.log" 2>&1 $CONFIGURE_FLAGS >> "$DIR/install.log" 2>&1
@ -251,7 +382,7 @@ else
cd .. cd ..
rm -r -f ./curl rm -r -f ./curl
echo " done!" echo " done!"
HAVE_CURL="$DIR/install_data/php/ext/curl" HAVE_CURL="$DIR/bin/php5"
fi fi
#pthreads #pthreads
@ -273,9 +404,9 @@ mv yaml-$YAML_VERSION yaml
echo -n " checking..." echo -n " checking..."
cd yaml cd yaml
RANLIB=$RANLIB ./configure \ RANLIB=$RANLIB ./configure \
--prefix="$DIR/install_data/php/ext/yaml" \ --prefix="$DIR/bin/php5" \
--enable-static \ --disable-static \
--disable-shared \ --enable-shared \
$CONFIGURE_FLAGS >> "$DIR/install.log" 2>&1 $CONFIGURE_FLAGS >> "$DIR/install.log" 2>&1
echo -n " compiling..." echo -n " compiling..."
make -j $THREADS >> "$DIR/install.log" 2>&1 make -j $THREADS >> "$DIR/install.log" 2>&1
@ -287,37 +418,29 @@ rm -r -f ./yaml
echo " done!" echo " done!"
echo -n "[PHP]" echo -n "[PHP]"
set +e
if which free >/dev/null; then if [ "$DO_OPTIMIZE" != "no" ]; then
MAX_MEMORY=$(free -m | awk '/^Mem:/{print $2}')
else
MAX_MEMORY=$(top -l 1 | grep PhysMem: | awk '{print $10}' | tr -d 'a-zA-Z')
fi
if [ $MAX_MEMORY -gt 512 ] && [ "$1" != "crosscompile" ]; then
echo -n " enabling optimizations..." echo -n " enabling optimizations..."
OPTIMIZATION="--enable-inline-optimization " PHP_OPTIMIZATION="--enable-inline-optimization "
else else
OPTIMIZATION="--disable-inline-optimization " PHP_OPTIMIZATION="--disable-inline-optimization "
fi fi
set -e
echo -n " checking..." echo -n " checking..."
cd php cd php
rm -rf ./aclocal.m4 >> "$DIR/install.log" 2>&1 rm -rf ./aclocal.m4 >> "$DIR/install.log" 2>&1
rm -rf ./autom4te.cache/ >> "$DIR/install.log" 2>&1 rm -rf ./autom4te.cache/ >> "$DIR/install.log" 2>&1
rm -f ./configure >> "$DIR/install.log" 2>&1 rm -f ./configure >> "$DIR/install.log" 2>&1
./buildconf --force >> "$DIR/install.log" 2>&1 ./buildconf --force >> "$DIR/install.log" 2>&1
if [ "$1" == "crosscompile" ]; then if [ "$IS_CROSSCOMPILE" == "yes" ]; then
sed -i 's/pthreads_working=no/pthreads_working=yes/' ./configure sed -i=".backup" 's/pthreads_working=no/pthreads_working=yes/' ./configure
export LIBS="-lpthread -ldl" export LIBS="-lpthread -ldl -lresolv"
CONFIGURE_FLAGS="$CONFIGURE_FLAGS --enable-opcache=no" CONFIGURE_FLAGS="$CONFIGURE_FLAGS --enable-opcache=no"
fi fi
./configure $OPTIMIZATION--prefix="$DIR/bin/php5" \ RANLIB=$RANLIB ./configure $PHP_OPTIMIZATION--prefix="$DIR/bin/php5" \
--exec-prefix="$DIR/bin/php5" \ --exec-prefix="$DIR/bin/php5" \
--with-curl="$HAVE_CURL" \ --with-curl="$HAVE_CURL" \
--with-zlib="$DIR/install_data/php/ext/zlib" \ --with-zlib="$DIR/bin/php5" \
--with-zlib-dir="$DIR/install_data/php/ext/zlib" \ --with-yaml="$DIR/bin/php5" \
--with-yaml="$DIR/install_data/php/ext/yaml" \
$HAVE_LIBEDIT \ $HAVE_LIBEDIT \
--disable-libxml \ --disable-libxml \
--disable-xml \ --disable-xml \
@ -328,11 +451,11 @@ $HAVE_LIBEDIT \
--disable-cgi \ --disable-cgi \
--disable-session \ --disable-session \
--disable-debug \ --disable-debug \
--disable-phar \
--disable-pdo \ --disable-pdo \
--without-pear \ --without-pear \
--without-iconv \ --without-iconv \
--without-pdo-sqlite \ --without-pdo-sqlite \
--enable-phar \
--enable-ctype \ --enable-ctype \
--enable-sockets \ --enable-sockets \
--enable-shared=no \ --enable-shared=no \
@ -350,39 +473,63 @@ $HAVE_MYSQLI \
--with-zend-vm=$ZEND_VM \ --with-zend-vm=$ZEND_VM \
$CONFIGURE_FLAGS >> "$DIR/install.log" 2>&1 $CONFIGURE_FLAGS >> "$DIR/install.log" 2>&1
echo -n " compiling..." echo -n " compiling..."
if [ $COMPILE_FOR_ANDROID == "yes" ]; then if [ "$COMPILE_FOR_ANDROID" == "yes" ]; then
sed -i 's/-export-dynamic/-all-static/g' Makefile sed -i=".backup" 's/-export-dynamic/-all-static/g' Makefile
fi fi
sed -i=".backup" 's/PHP_BINARIES. pharcmd$/PHP_BINARIES)/g' Makefile
sed -i=".backup" 's/install-programs install-pharcmd$/install-programs/g' Makefile
make -j $THREADS >> "$DIR/install.log" 2>&1 make -j $THREADS >> "$DIR/install.log" 2>&1
echo -n " installing..." echo -n " installing..."
make install >> "$DIR/install.log" 2>&1 make install >> "$DIR/install.log" 2>&1
echo " generating php.ini..."
if [ "$(uname -s)" == "Darwin" ] && [ "$IS_CROSSCOMPILE" != "yes" ]; then
set +e
install_name_tool -delete_rpath "$DIR/bin/php5/lib" "$DIR/bin/php5/bin/php" >> "$DIR/install.log" 2>&1
install_name_tool -change "$DIR/bin/php5/lib/libz.1.dylib" "@loader_path/../lib/libz.1.dylib" "$DIR/bin/php5/bin/php" >> "$DIR/install.log" 2>&1
install_name_tool -change "$DIR/bin/php5/lib/libyaml-0.2.dylib" "@loader_path/../lib/libyaml-0.2.dylib" "$DIR/bin/php5/bin/php" >> "$DIR/install.log" 2>&1
install_name_tool -change "$DIR/bin/php5/lib/libssl.1.0.0.dylib" "@loader_path/../lib/libssl.1.0.0.dylib" "$DIR/bin/php5/bin/php" >> "$DIR/install.log" 2>&1
install_name_tool -change "$DIR/bin/php5/lib/libcrypto.1.0.0.dylib" "@loader_path/../lib/libcrypto.1.0.0.dylib" "$DIR/bin/php5/bin/php" >> "$DIR/install.log" 2>&1
chmod 0777 "$DIR/bin/php5/lib/libssl.1.0.0.dylib" >> "$DIR/install.log" 2>&1
install_name_tool -change "$DIR/bin/php5/lib/libcrypto.1.0.0.dylib" "@loader_path/libcrypto.1.0.0.dylib" "$DIR/bin/php5/lib/libssl.1.0.0.dylib" >> "$DIR/install.log" 2>&1
chmod 0755 "$DIR/bin/php5/lib/libssl.1.0.0.dylib" >> "$DIR/install.log" 2>&1
set -e
fi
echo -n " generating php.ini..."
TIMEZONE=$(date +%Z) TIMEZONE=$(date +%Z)
touch "$DIR/bin/php5/lib/php.ini" echo "date.timezone=$TIMEZONE" > "$DIR/bin/php5/bin/php.ini"
if [ "$1" != "crosscompile" ]; then echo "short_open_tag=0" >> "$DIR/bin/php5/bin/php.ini"
OPCACHE_PATH=$(find "$DIR/bin/php5" -name opcache.so) echo "asp_tags=0" >> "$DIR/bin/php5/bin/php.ini"
echo "zend_extension=\"$OPCACHE_PATH\"" >> "$DIR/bin/php5/lib/php.ini" echo "phar.readonly=0" >> "$DIR/bin/php5/bin/php.ini"
echo "opcache.enable=1" >> "$DIR/bin/php5/lib/php.ini" echo "phar.require_hash=1" >> "$DIR/bin/php5/bin/php.ini"
echo "opcache.enable_cli=1" >> "$DIR/bin/php5/lib/php.ini" if [ "$IS_CROSSCOMPILE" != "crosscompile" ]; then
echo "opcache.save_comments=0" >> "$DIR/bin/php5/lib/php.ini" echo "zend_extension=opcache.so" >> "$DIR/bin/php5/bin/php.ini"
echo "opcache.fast_shutdown=1" >> "$DIR/bin/php5/lib/php.ini" echo "opcache.enable=1" >> "$DIR/bin/php5/bin/php.ini"
echo "opcache.max_accelerated_files=4096" >> "$DIR/bin/php5/lib/php.ini" echo "opcache.enable_cli=1" >> "$DIR/bin/php5/bin/php.ini"
echo "opcache.interned_strings_buffer=8" >> "$DIR/bin/php5/lib/php.ini" echo "opcache.save_comments=0" >> "$DIR/bin/php5/bin/php.ini"
echo "opcache.memory_consumption=128" >> "$DIR/bin/php5/lib/php.ini" echo "opcache.fast_shutdown=1" >> "$DIR/bin/php5/bin/php.ini"
echo "opcache.optimization_level=0xffffffff" >> "$DIR/bin/php5/lib/php.ini" echo "opcache.max_accelerated_files=4096" >> "$DIR/bin/php5/bin/php.ini"
echo "opcache.interned_strings_buffer=8" >> "$DIR/bin/php5/bin/php.ini"
echo "opcache.memory_consumption=128" >> "$DIR/bin/php5/bin/php.ini"
echo "opcache.optimization_level=0xffffffff" >> "$DIR/bin/php5/bin/php.ini"
fi fi
if [ "$HAVE_CURL" == "shared,/usr" ]; then if [ "$HAVE_CURL" == "shared,/usr" ]; then
echo "extension=curl.so" >> "$DIR/bin/php5/lib/php.ini" echo "extension=curl.so" >> "$DIR/bin/php5/bin/php.ini"
fi fi
echo "date.timezone=$TIMEZONE" >> "$DIR/bin/php5/lib/php.ini"
echo "short_open_tag=0" >> "$DIR/bin/php5/lib/php.ini"
echo "asp_tags=0" >> "$DIR/bin/php5/lib/php.ini"
echo " done!" echo " done!"
cd "$DIR" cd "$DIR"
echo -n "[INFO] Cleaning up..." echo -n "[INFO] Cleaning up..."
rm -r -f install_data/ >> "$DIR/install.log" 2>&1 rm -r -f install_data/ >> "$DIR/install.log" 2>&1
rm -f bin/php5/bin/curl >> "$DIR/install.log" 2>&1
rm -f bin/php5/bin/curl-config >> "$DIR/install.log" 2>&1
rm -f bin/php5/bin/c_rehash >> "$DIR/install.log" 2>&1
rm -f bin/php5/bin/openssl >> "$DIR/install.log" 2>&1
rm -r -f bin/php5/man >> "$DIR/install.log" 2>&1
rm -r -f bin/php5/php >> "$DIR/install.log" 2>&1
rm -r -f bin/php5/share >> "$DIR/install.log" 2>&1
rm -r -f bin/php5/misc >> "$DIR/install.log" 2>&1
date >> "$DIR/install.log" 2>&1 date >> "$DIR/install.log" 2>&1
echo " done!" echo " done!"
echo "[PocketMine] You should start the server now using \"./start.sh.\"" echo "[PocketMine] You should start the server now using \"./start.sh.\""

View File

@ -1,10 +1,17 @@
#!/bin/bash #!/bin/bash
PMMP_VERSION="" PMMP_VERSION=""
MAC_BUILD="PHP_5.5.9_x86_MacOS" LINUX_32_BUILD="PHP_5.5.10_x86_Linux"
LINUX_64_BUILD="PHP_5.5.10_x86-64_Linux"
MAC_32_BUILD="PHP_5.5.10_x86_MacOS"
MAC_64_BUILD="PHP_5.5.10_x86-64_MacOS"
RPI_BUILD="PHP_5.5.9_ARM_Raspbian_hard" RPI_BUILD="PHP_5.5.9_ARM_Raspbian_hard"
# Temporal build
ODROID_BUILD="PHP_5.5.9_ARM_Raspbian_hard"
AND_BUILD="PHP_5.5.9_ARMv7_Android" AND_BUILD="PHP_5.5.9_ARMv7_Android"
IOS_BUILD="PHP_5.5.9_ARMv6_iOS" IOS_BUILD="PHP_5.5.9_ARMv6_iOS"
update=off update=off
forcecompile=off
alldone=no
#Needed to use aliases #Needed to use aliases
shopt -s expand_aliases shopt -s expand_aliases
@ -21,11 +28,14 @@ else
fi fi
while getopts "udv:" opt; do while getopts "ucdv:" opt; do
case $opt in case $opt in
u) u)
update=on update=on
;; ;;
c)
forcecompile=on
;;
d) d)
PMMP_VERSION="master" PMMP_VERSION="master"
;; ;;
@ -58,79 +68,175 @@ rm -f LICENSE
rm -f start.sh rm -f start.sh
rm -f start.bat rm -f start.bat
echo "[1/3] Downloading PocketMine-MP $PMMP_VERSION..." echo "[1/3] Downloading PocketMine-MP $PMMP_VERSION..."
set -e
download_file "https://github.com/PocketMine/PocketMine-MP/archive/$PMMP_VERSION.tar.gz" | tar -zx > /dev/null download_file "https://github.com/PocketMine/PocketMine-MP/archive/$PMMP_VERSION.tar.gz" | tar -zx > /dev/null
mv -f PocketMine-MP-$PMMP_VERSION/* ./ mv -f PocketMine-MP-$PMMP_VERSION/* ./
rm -f -r PocketMine-MP-$PMMP_VERSION/ rm -f -r PocketMine-MP-$PMMP_VERSION/
rm -f ./start.cmd rm -f ./start.cmd
chmod +x ./start.sh chmod +x ./start.sh
chmod +x ./src/build/compile.sh chmod +x ./src/build/compile.sh
if [ $update == on ]; then if [ "$update" == "on" ]; then
echo "[3/3] Skipping PHP recompilation due to user request" echo "[3/3] Skipping PHP recompilation due to user request"
else else
echo -n "[3/3] Obtaining PHP:" echo -n "[3/3] Obtaining PHP:"
echo " detecting if build is available..." echo " detecting if build is available..."
if [ "$(uname -s)" == "Darwin" ]; then if [ "$forcecompile" == "off" ] && [ "$(uname -s)" == "Darwin" ]; then
set +e set +e
UNAME_M=$(uname -m) UNAME_M=$(uname -m)
IS_IOS=$(expr match $UNAME_M 'iP[a-zA-Z0-9,]*') IS_IOS=$(expr match $UNAME_M 'iP[a-zA-Z0-9,]*' 2> /dev/null)
set -e set -e
if [ $IS_IOS -gt 0 ]; then if [[ "$IS_IOS" -gt 0 ]]; then
rm -r -f bin/ >> /dev/null 2>&1 rm -r -f bin/ >> /dev/null 2>&1
echo -n "[3/3] iOS PHP build available, downloading $IOS_BUILD.tar.gz..." echo -n "[3/3] iOS PHP build available, downloading $IOS_BUILD.tar.gz..."
download_file "http://sourceforge.net/projects/pocketmine/files/builds/$IOS_BUILD.tar.gz" | tar -zx > /dev/null 2>&1 download_file "http://sourceforge.net/projects/pocketmine/files/builds/$IOS_BUILD.tar.gz" | tar -zx > /dev/null 2>&1
chmod +x ./bin/php5/bin/* chmod +x ./bin/php5/bin/*
echo -n " regenerating php.ini..." echo -n " checking..."
echo "date.timezone=$TIMEZONE" >> "./bin/php5/lib/php.ini" if [ $(./bin/php5/bin/php -r 'echo "yes";' 2>/dev/null) == "yes" ]; then
echo "short_open_tag=0" >> "./bin/php5/lib/php.ini" echo -n " regenerating php.ini..."
echo "asp_tags=0" >> "./bin/php5/lib/php.ini" TIMEZONE=$(date +%Z)
echo " done" echo "date.timezone=$TIMEZONE" >> "./bin/php5/bin/php.ini"
echo "short_open_tag=0" >> "./bin/php5/bin/php.ini"
echo "asp_tags=0" >> "./bin/php5/bin/php.ini"
echo "phar.readonly=0" >> "./bin/php5/bin/php.ini"
echo "phar.require_hash=1" >> "./bin/php5/bin/php.ini"
echo " done"
alldone=yes
else
echo " invalid build detected"
fi
else else
rm -r -f bin/ >> /dev/null 2>&1 rm -r -f bin/ >> /dev/null 2>&1
echo -n "[3/3] Mac OSX PHP build available, downloading $MAC_BUILD.tar.gz..." if [ `getconf LONG_BIT` == "64" ]; then
echo -n "[3/3] MacOS 64-bit PHP build available, downloading $MAC_64_BUILD.tar.gz..."
MAC_BUILD="$MAC_64_BUILD"
else
echo -n "[3/3] MacOS 32-bit PHP build available, downloading $MAC_32_BUILD.tar.gz..."
MAC_BUILD="$MAC_32_BUILD"
fi
download_file "http://sourceforge.net/projects/pocketmine/files/builds/$MAC_BUILD.tar.gz" | tar -zx > /dev/null 2>&1 download_file "http://sourceforge.net/projects/pocketmine/files/builds/$MAC_BUILD.tar.gz" | tar -zx > /dev/null 2>&1
chmod +x ./bin/php5/bin/* chmod +x ./bin/php5/bin/*
echo -n " regenerating php.ini..." echo -n " checking..."
OPCACHE_PATH=$(find "./bin/php5" -name opcache.so) if [ $(./bin/php5/bin/php -r 'echo "yes";' 2>/dev/null) == "yes" ]; then
echo "zend_extension=\"$OPCACHE_PATH\"" > "./bin/php5/lib/php.ini" echo -n " regenerating php.ini..."
echo "opcache.enable=1" >> "./bin/php5/lib/php.ini" TIMEZONE=$(date +%Z)
echo "opcache.enable_cli=1" >> "./bin/php5/lib/php.ini" OPCACHE_PATH="$(find $(pwd) -name opcache.so)"
echo "opcache.save_comments=0" >> "./bin/php5/lib/php.ini" echo "zend_extension=\"$OPCACHE_PATH\"" > "./bin/php5/bin/php.ini"
echo "opcache.fast_shutdown=1" >> "./bin/php5/lib/php.ini" echo "opcache.enable=1" >> "./bin/php5/bin/php.ini"
echo "opcache.max_accelerated_files=4096" >> "./bin/php5/lib/php.ini" echo "opcache.enable_cli=1" >> "./bin/php5/bin/php.ini"
echo "opcache.interned_strings_buffer=8" >> "./bin/php5/lib/php.ini" echo "opcache.save_comments=0" >> "./bin/php5/bin/php.ini"
echo "opcache.memory_consumption=128" >> "./bin/php5/lib/php.ini" echo "opcache.fast_shutdown=1" >> "./bin/php5/bin/php.ini"
echo "opcache.optimization_level=0xffffffff" >> "./bin/php5/lib/php.ini" echo "opcache.max_accelerated_files=4096" >> "./bin/php5/bin/php.ini"
echo "date.timezone=$TIMEZONE" >> "./bin/php5/lib/php.ini" echo "opcache.interned_strings_buffer=8" >> "./bin/php5/bin/php.ini"
echo "short_open_tag=0" >> "./bin/php5/lib/php.ini" echo "opcache.memory_consumption=128" >> "./bin/php5/bin/php.ini"
echo "asp_tags=0" >> "./bin/php5/lib/php.ini" echo "opcache.optimization_level=0xffffffff" >> "./bin/php5/bin/php.ini"
echo " done" echo "date.timezone=$TIMEZONE" >> "./bin/php5/bin/php.ini"
echo "short_open_tag=0" >> "./bin/php5/bin/php.ini"
echo "asp_tags=0" >> "./bin/php5/bin/php.ini"
echo "phar.readonly=0" >> "./bin/php5/bin/php.ini"
echo "phar.require_hash=1" >> "./bin/php5/bin/php.ini"
echo " done"
alldone=yes
else
echo " invalid build detected"
fi
fi fi
else else
set +e
grep -q BCM2708 /proc/cpuinfo > /dev/null 2>&1 grep -q BCM2708 /proc/cpuinfo > /dev/null 2>&1
if [ $? -eq 0 ]; then IS_RPI=$?
set -e grep -q ODROID /proc/cpuinfo > /dev/null 2>&1
IS_ODROID=$?
if [ "$IS_RPI" -eq 0 ] && [ "$forcecompile" == "off" ]; then
rm -r -f bin/ >> /dev/null 2>&1 rm -r -f bin/ >> /dev/null 2>&1
echo -n "[3/3] Raspberry Pi PHP build available, downloading $RPI_BUILD.tar.gz..." echo -n "[3/3] Raspberry Pi PHP build available, downloading $RPI_BUILD.tar.gz..."
download_file "http://sourceforge.net/projects/pocketmine/files/builds/$RPI_BUILD.tar.gz" | tar -zx > /dev/null 2>&1 download_file "http://sourceforge.net/projects/pocketmine/files/builds/$RPI_BUILD.tar.gz" | tar -zx > /dev/null 2>&1
chmod +x ./bin/php5/bin/* chmod +x ./bin/php5/bin/*
echo -n " regenerating php.ini..." echo -n " checking..."
OPCACHE_PATH=$(find "./bin/php5" -name opcache.so) if [ $(./bin/php5/bin/php -r 'echo "yes";' 2>/dev/null) == "yes" ]; then
echo "zend_extension=\"$OPCACHE_PATH\"" > "./bin/php5/lib/php.ini" echo -n " regenerating php.ini..."
echo "opcache.enable=1" >> "./bin/php5/lib/php.ini" TIMEZONE=$(date +%Z)
echo "opcache.enable_cli=1" >> "./bin/php5/lib/php.ini" OPCACHE_PATH="$(find $(pwd) -name opcache.so)"
echo "opcache.save_comments=0" >> "./bin/php5/lib/php.ini" echo "zend_extension=\"$OPCACHE_PATH\"" > "./bin/php5/bin/php.ini"
echo "opcache.fast_shutdown=1" >> "./bin/php5/lib/php.ini" echo "opcache.enable=1" >> "./bin/php5/bin/php.ini"
echo "opcache.max_accelerated_files=4096" >> "./bin/php5/lib/php.ini" echo "opcache.enable_cli=1" >> "./bin/php5/bin/php.ini"
echo "opcache.interned_strings_buffer=8" >> "./bin/php5/lib/php.ini" echo "opcache.save_comments=0" >> "./bin/php5/bin/php.ini"
echo "opcache.memory_consumption=128" >> "./bin/php5/lib/php.ini" echo "opcache.fast_shutdown=1" >> "./bin/php5/bin/php.ini"
echo "opcache.optimization_level=0xffffffff" >> "./bin/php5/lib/php.ini" echo "opcache.max_accelerated_files=4096" >> "./bin/php5/bin/php.ini"
echo "date.timezone=$TIMEZONE" >> "./bin/php5/lib/php.ini" echo "opcache.interned_strings_buffer=8" >> "./bin/php5/bin/php.ini"
echo "short_open_tag=0" >> "./bin/php5/lib/php.ini" echo "opcache.memory_consumption=128" >> "./bin/php5/bin/php.ini"
echo "asp_tags=0" >> "./bin/php5/lib/php.ini" echo "opcache.optimization_level=0xffffffff" >> "./bin/php5/bin/php.ini"
echo " done" echo "date.timezone=$TIMEZONE" >> "./bin/php5/bin/php.ini"
else echo "short_open_tag=0" >> "./bin/php5/bin/php.ini"
echo "asp_tags=0" >> "./bin/php5/bin/php.ini"
echo "phar.readonly=0" >> "./bin/php5/bin/php.ini"
echo "phar.require_hash=1" >> "./bin/php5/bin/php.ini"
echo " done"
alldone=yes
else
echo " invalid build detected"
fi
elif [ "$IS_ODROID" -eq 0 ] && [ "$forcecompile" == "off" ]; then
rm -r -f bin/ >> /dev/null 2>&1
echo -n "[3/3] ODROID PHP build available, downloading $ODROID_BUILD.tar.gz..."
download_file "http://sourceforge.net/projects/pocketmine/files/builds/$ODROID_BUILD.tar.gz" | tar -zx > /dev/null 2>&1
chmod +x ./bin/php5/bin/*
echo -n " checking..."
if [ $(./bin/php5/bin/php -r 'echo "yes";' 2>/dev/null) == "yes" ]; then
echo -n " regenerating php.ini..."
OPCACHE_PATH="$(find $(pwd) -name opcache.so)"
echo "zend_extension=\"$OPCACHE_PATH\"" > "./bin/php5/bin/php.ini"
echo "opcache.enable=1" >> "./bin/php5/bin/php.ini"
echo "opcache.enable_cli=1" >> "./bin/php5/bin/php.ini"
echo "opcache.save_comments=0" >> "./bin/php5/bin/php.ini"
echo "opcache.fast_shutdown=1" >> "./bin/php5/bin/php.ini"
echo "opcache.max_accelerated_files=4096" >> "./bin/php5/bin/php.ini"
echo "opcache.interned_strings_buffer=8" >> "./bin/php5/bin/php.ini"
echo "opcache.memory_consumption=128" >> "./bin/php5/bin/php.ini"
echo "opcache.optimization_level=0xffffffff" >> "./bin/php5/bin/php.ini"
echo "date.timezone=$TIMEZONE" >> "./bin/php5/bin/php.ini"
echo "short_open_tag=0" >> "./bin/php5/bin/php.ini"
echo "asp_tags=0" >> "./bin/php5/bin/php.ini"
echo "phar.readonly=0" >> "./bin/php5/bin/php.ini"
echo "phar.require_hash=1" >> "./bin/php5/bin/php.ini"
echo " done"
alldone=yes
else
echo " invalid build detected"
fi
elif [ "$forcecompile" == "off" ] && [ "$(uname -s)" == "Linux" ]; then
rm -r -f bin/ >> /dev/null 2>&1
if [ `getconf LONG_BIT` = "64" ]; then
echo -n "[3/3] Linux 64-bit PHP build available, downloading $LINUX_64_BUILD.tar.gz..."
LINUX_BUILD="$LINUX_64_BUILD"
else
echo -n "[3/3] Linux 32-bit PHP build available, downloading $LINUX_32_BUILD.tar.gz..."
LINUX_BUILD="$LINUX_32_BUILD"
fi
download_file "http://sourceforge.net/projects/pocketmine/files/builds/$LINUX_BUILD.tar.gz" | tar -zx > /dev/null 2>&1
chmod +x ./bin/php5/bin/*
echo -n " checking..."
if [ $(./bin/php5/bin/php -r 'echo "yes";' 2>/dev/null) == "yes" ]; then
echo -n " regenerating php.ini..."
OPCACHE_PATH="$(find $(pwd) -name opcache.so)"
echo "zend_extension=\"$OPCACHE_PATH\"" > "./bin/php5/bin/php.ini"
echo "opcache.enable=1" >> "./bin/php5/bin/php.ini"
echo "opcache.enable_cli=1" >> "./bin/php5/bin/php.ini"
echo "opcache.save_comments=0" >> "./bin/php5/bin/php.ini"
echo "opcache.fast_shutdown=1" >> "./bin/php5/bin/php.ini"
echo "opcache.max_accelerated_files=4096" >> "./bin/php5/bin/php.ini"
echo "opcache.interned_strings_buffer=8" >> "./bin/php5/bin/php.ini"
echo "opcache.memory_consumption=128" >> "./bin/php5/bin/php.ini"
echo "opcache.optimization_level=0xffffffff" >> "./bin/php5/bin/php.ini"
echo "date.timezone=$TIMEZONE" >> "./bin/php5/bin/php.ini"
echo "short_open_tag=0" >> "./bin/php5/bin/php.ini"
echo "asp_tags=0" >> "./bin/php5/bin/php.ini"
echo "phar.readonly=0" >> "./bin/php5/bin/php.ini"
echo "phar.require_hash=1" >> "./bin/php5/bin/php.ini"
echo " done"
alldone=yes
else
echo " invalid build detected"
fi
fi
if [ "$alldone" == "no" ]; then
set -e set -e
echo "[3/3] no build found, compiling PHP" echo "[3/3] no build found, compiling PHP"
exec ./src/build/compile.sh exec ./src/build/compile.sh

View File

@ -1,6 +1,7 @@
#!/bin/bash -x #!/bin/bash -x
export PATH=/opt/arm-2013.05/bin:/opt/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin:/opt/arm-unknown-linux-uclibcgnueabi/bin:$PATH export PATH="/opt/arm-2013.05/bin:/opt/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin:/opt/arm-unknown-linux-uclibcgnueabi/bin:$PATH"
export THREADS=2 export THREADS=2
PHP_VERSION="5.5.10"
#Needed to use aliases #Needed to use aliases
shopt -s expand_aliases shopt -s expand_aliases
@ -20,20 +21,21 @@ rm -rf $WORKSPACE/compile.sh
download_file "https://github.com/PocketMine/PocketMine-MP/raw/master/src/build/compile.sh" > $WORKSPACE/compile.sh download_file "https://github.com/PocketMine/PocketMine-MP/raw/master/src/build/compile.sh" > $WORKSPACE/compile.sh
chmod +x $WORKSPACE/compile.sh chmod +x $WORKSPACE/compile.sh
SCRIPT="$WORKSPACE/compile.sh" SCRIPT="$WORKSPACE/compile.sh"
ARCHIVE=$WORKSPACE/archive ARCHIVE="$WORKSPACE/archive"
COMPILEDIR=$WORKSPACE/compile COMPILEDIR="$WORKSPACE/compile"
rm -rf $ARCHIVE $COMPILEDIR rm -rf "$ARCHIVE" "$COMPILEDIR"
mkdir -p $ARCHIVE mkdir -p "$ARCHIVE"
mkdir -p $COMPILEDIR mkdir -p "$COMPILEDIR"
if [ "$COMPILE_LINUX_32BIT" = "true" ]; if [ "$COMPILE_LINUX_32BIT" = "true" ];
then then
mkdir -p {$COMPILEDIR,$ARCHIVE}/linux/32bit mkdir -p {$COMPILEDIR,$ARCHIVE}/linux/32bit
cd $COMPILEDIR/linux/32bit cd $COMPILEDIR/linux/32bit
CFLAGS=-m32 march=i686 mtune=generic $SCRIPT OPENSSL_TARGET="linux-generic32" CFLAGS="-m32" march=i686 mtune=pentium4 $SCRIPT -t linux -o -j 1 -c -f x86
cp -r $COMPILEDIR/linux/32bit/{install.log,bin/*,install_data/*} $ARCHIVE/linux/32bit/ tar -czf PHP_${PHP_VERSION}_x86_Linux.tar.gz bin/
cp -r $COMPILEDIR/linux/32bit/{install.log,PHP_${PHP_VERSION}_x86_Linux.tar.gz,install_data/*} $ARCHIVE/linux/32bit/
if [ ! -f $COMPILEDIR/linux/32bit/bin/php5/bin/php ]; then if [ ! -f $COMPILEDIR/linux/32bit/bin/php5/bin/php ]; then
exit 1 exit 1
fi fi
@ -44,18 +46,19 @@ then
mkdir -p {$COMPILEDIR,$ARCHIVE}/linux/64bit mkdir -p {$COMPILEDIR,$ARCHIVE}/linux/64bit
cd $COMPILEDIR/linux/64bit cd $COMPILEDIR/linux/64bit
$SCRIPT OPENSSL_TARGET="linux-x86_64" CFLAGS="-m64" march=x86-64 mtune=nocona $SCRIPT -t linux -o -j 1 -c -f x86_64
cp -r $COMPILEDIR/linux/64bit/{install.log,bin/*,install_data/*} $ARCHIVE/linux/64bit/ tar -czf PHP_${PHP_VERSION}_x86-64_Linux.tar.gz bin/
cp -r $COMPILEDIR/linux/64bit/{install.log,PHP_${PHP_VERSION}_x86-64_Linux.tar.gz,install_data/*} $ARCHIVE/linux/64bit/
if [ ! -f $COMPILEDIR/linux/64bit/bin/php5/bin/php ]; then if [ ! -f $COMPILEDIR/linux/64bit/bin/php5/bin/php ]; then
exit 1 exit 1
fi fi
fi fi
if [ "$COMPILE_MAC" = "true" ]; if [ "$COMPILE_MAC_32" = "true" ];
then then
mkdir -p {$COMPILEDIR,$ARCHIVE}/mac mkdir -p {$COMPILEDIR,$ARCHIVE}/mac32
cd $COMPILEDIR/mac cd $COMPILEDIR/mac32
curl -L http://ftpmirror.gnu.org/libtool/libtool-2.4.2.tar.gz | tar -xz > /dev/null curl -L http://ftpmirror.gnu.org/libtool/libtool-2.4.2.tar.gz | tar -xz > /dev/null
cd libtool-2.4.2 cd libtool-2.4.2
@ -66,10 +69,34 @@ then
rm -rf libtool-2.4.2 rm -rf libtool-2.4.2
export LIBTOOL="$COMPILEDIR/mac/libtool/bin/libtool" export LIBTOOL="$COMPILEDIR/mac/libtool/bin/libtool"
export LIBTOOLIZE="$COMPILEDIR/mac/libtool/bin/libtoolize" export LIBTOOLIZE="$COMPILEDIR/mac/libtool/bin/libtoolize"
$SCRIPT mac curl $SCRIPT -t mac32 -o -j 1 -c -f
cp -r $COMPILEDIR/mac/{install.log,bin/*,install_data/*} $ARCHIVE/mac/ tar -czf PHP_${PHP_VERSION}_x86_MacOS.tar.gz bin/
if [ ! -f $COMPILEDIR/mac/bin/php5/bin/php ]; then cp -r $COMPILEDIR/mac32/{install.log,PHP_${PHP_VERSION}_x86_MacOS.tar.gz,install_data/*} $ARCHIVE/mac32/
if [ ! -f $COMPILEDIR/mac32/bin/php5/bin/php ]; then
exit 1
fi
fi
if [ "$COMPILE_MAC_64" = "true" ];
then
mkdir -p {$COMPILEDIR,$ARCHIVE}/mac64
cd $COMPILEDIR/mac64
curl -L http://ftpmirror.gnu.org/libtool/libtool-2.4.2.tar.gz | tar -xz > /dev/null
cd libtool-2.4.2
./configure --prefix="$COMPILEDIR/mac/libtool" > /dev/null
make > /dev/null
make install
cd ../
rm -rf libtool-2.4.2
export LIBTOOL="$COMPILEDIR/mac/libtool/bin/libtool"
export LIBTOOLIZE="$COMPILEDIR/mac/libtool/bin/libtoolize"
$SCRIPT -t mac64 -o -j 1 -c -f
tar -czf PHP_${PHP_VERSION}_x86-64_MacOS.tar.gz bin/
cp -r $COMPILEDIR/mac64/{install.log,PHP_${PHP_VERSION}_x86-64_MacOS.tar.gz,install_data/*} $ARCHIVE/mac64
if [ ! -f $COMPILEDIR/mac64/bin/php5/bin/php ]; then
exit 1 exit 1
fi fi
fi fi
@ -79,9 +106,10 @@ then
mkdir -p {$COMPILEDIR,$ARCHIVE}/rpi mkdir -p {$COMPILEDIR,$ARCHIVE}/rpi
cd $COMPILEDIR/rpi cd $COMPILEDIR/rpi
$SCRIPT rpi $SCRIPT -t rpi -o -j 1 -c -f arm
cp -r $COMPILEDIR/rpi/{install.log,bin/*,install_data/*} $ARCHIVE/rpi/ tar -czf PHP_${PHP_VERSION}_ARM_Raspbian_hard.tar.gz bin/
cp -r $COMPILEDIR/rpi/{install.log,PHP_${PHP_VERSION}_ARM_Raspbian_hard.tar.gz,install_data/*} $ARCHIVE/rpi/
if [ ! -f $COMPILEDIR/rpi/bin/php5/bin/php ]; then if [ ! -f $COMPILEDIR/rpi/bin/php5/bin/php ]; then
exit 1 exit 1
fi fi
@ -92,9 +120,10 @@ then
mkdir -p {$COMPILEDIR,$ARCHIVE}/crosscompile/android-armv6 mkdir -p {$COMPILEDIR,$ARCHIVE}/crosscompile/android-armv6
cd $COMPILEDIR/crosscompile/android-armv6 cd $COMPILEDIR/crosscompile/android-armv6
$SCRIPT crosscompile android-armv6 $SCRIPT -t android-armv6 -o -j 1 -c -x -f arm
cp -r $COMPILEDIR/crosscompile/android-armv6/{install.log,bin/*,install_data/*} $ARCHIVE/crosscompile/android-armv6/ tar -czf PHP_${PHP_VERSION}_ARMv6_Android.tar.gz bin/
cp -r $COMPILEDIR/crosscompile/android-armv6/{install.log,PHP_${PHP_VERSION}_ARMv6_Android.tar.gz,install_data/*} $ARCHIVE/crosscompile/android-armv6/
if [ ! -f $COMPILEDIR/crosscompile/android-armv6/bin/php5/bin/php ]; then if [ ! -f $COMPILEDIR/crosscompile/android-armv6/bin/php5/bin/php ]; then
exit 1 exit 1
fi fi
@ -105,9 +134,10 @@ then
mkdir -p {$COMPILEDIR,$ARCHIVE}/crosscompile/android-armv7 mkdir -p {$COMPILEDIR,$ARCHIVE}/crosscompile/android-armv7
cd $COMPILEDIR/crosscompile/android-armv7 cd $COMPILEDIR/crosscompile/android-armv7
$SCRIPT crosscompile android-armv7 $SCRIPT -t android-armv7 -o -j 1 -c -x -f arm
cp -r $COMPILEDIR/crosscompile/android-armv7/{install.log,bin/*,install_data/*} $ARCHIVE/crosscompile/android-armv7/ tar -czf PHP_${PHP_VERSION}_ARMv7_Android.tar.gz bin/
cp -r $COMPILEDIR/crosscompile/android-armv7/{install.log,PHP_${PHP_VERSION}_ARMv7_Android.tar.gz,install_data/*} $ARCHIVE/crosscompile/android-armv7/
if [ ! -f $COMPILEDIR/crosscompile/android-armv7/bin/php5/bin/php ]; then if [ ! -f $COMPILEDIR/crosscompile/android-armv7/bin/php5/bin/php ]; then
exit 1 exit 1
fi fi
@ -126,7 +156,7 @@ then
rm -rf libtool-2.4.2 rm -rf libtool-2.4.2
export LIBTOOL="$COMPILEDIR/crosscompile/ios-armv6/libtool/bin/libtool" export LIBTOOL="$COMPILEDIR/crosscompile/ios-armv6/libtool/bin/libtool"
export LIBTOOLIZE="$COMPILEDIR/crosscompile/ios-armv6/libtool/bin/libtoolize" export LIBTOOLIZE="$COMPILEDIR/crosscompile/ios-armv6/libtool/bin/libtoolize"
PATH="/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin:$PATH" $SCRIPT crosscompile ios-armv6 PATH="/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin:$PATH" $SCRIPT -t ios-armv6 -o -j 1 -c -x
cp -r $COMPILEDIR/crosscompile/ios-armv6/{install.log,bin/*,install_data/*} $ARCHIVE/crosscompile/ios-armv6/ cp -r $COMPILEDIR/crosscompile/ios-armv6/{install.log,bin/*,install_data/*} $ARCHIVE/crosscompile/ios-armv6/
if [ ! -f $COMPILEDIR/crosscompile/ios-armv6/bin/php5/bin/php ]; then if [ ! -f $COMPILEDIR/crosscompile/ios-armv6/bin/php5/bin/php ]; then
@ -147,7 +177,7 @@ then
rm -rf libtool-2.4.2 rm -rf libtool-2.4.2
export LIBTOOL="$COMPILEDIR/crosscompile/ios-armv7/libtool/bin/libtool" export LIBTOOL="$COMPILEDIR/crosscompile/ios-armv7/libtool/bin/libtool"
export LIBTOOLIZE="$COMPILEDIR/crosscompile/ios-armv7/libtool/bin/libtoolize" export LIBTOOLIZE="$COMPILEDIR/crosscompile/ios-armv7/libtool/bin/libtoolize"
PATH="/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin:$PATH" $SCRIPT crosscompile ios-armv7 PATH="/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin:$PATH" $SCRIPT -t ios-armv6 -o -j 1 -c -x
cp -r $COMPILEDIR/crosscompile/ios-armv7/{install.log,bin/*,install_data/*} $ARCHIVE/crosscompile/ios-armv7/ cp -r $COMPILEDIR/crosscompile/ios-armv7/{install.log,bin/*,install_data/*} $ARCHIVE/crosscompile/ios-armv7/
if [ ! -f $COMPILEDIR/crosscompile/ios-armv7/bin/php5/bin/php ]; then if [ ! -f $COMPILEDIR/crosscompile/ios-armv7/bin/php5/bin/php ]; then
@ -160,9 +190,10 @@ then
mkdir -p {$COMPILEDIR,$ARCHIVE}/crosscompile/rpi mkdir -p {$COMPILEDIR,$ARCHIVE}/crosscompile/rpi
cd $COMPILEDIR/crosscompile/rpi cd $COMPILEDIR/crosscompile/rpi
$SCRIPT crosscompile rpi $SCRIPT -t rpi -o -j 1 -c -x -f arm
cp -r $COMPILEDIR/crosscompile/rpi/{install.log,bin/*,install_data/*} $ARCHIVE/crosscompile/rpi/ tar -czf PHP_${PHP_VERSION}_ARM_Raspbian_hard.tar.gz bin/
cp -r $COMPILEDIR/crosscompile/rpi/{install.log,PHP_${PHP_VERSION}_ARM_Raspbian_hard.tar.gz,install_data/*} $ARCHIVE/crosscompile/rpi/
if [ ! -f $COMPILEDIR/crosscompile/rpi/bin/php5/bin/php ]; then if [ ! -f $COMPILEDIR/crosscompile/rpi/bin/php5/bin/php ]; then
exit 1 exit 1
fi fi
@ -173,7 +204,7 @@ then
mkdir -p {$COMPILEDIR,$ARCHIVE}/crosscompile/mac mkdir -p {$COMPILEDIR,$ARCHIVE}/crosscompile/mac
cd $COMPILEDIR/crosscompile/mac cd $COMPILEDIR/crosscompile/mac
$SCRIPT crosscompile mac curl $SCRIPT -t mac -o -j 1 -c -f -x
cp -r $COMPILEDIR/crosscompile/mac/{install.log,bin/*,install_data/*} $ARCHIVE/crosscompile/mac/ cp -r $COMPILEDIR/crosscompile/mac/{install.log,bin/*,install_data/*} $ARCHIVE/crosscompile/mac/
if [ ! -f $COMPILEDIR/crosscompile/mac/bin/php5/bin/php ]; then if [ ! -f $COMPILEDIR/crosscompile/mac/bin/php5/bin/php ]; then

View File

@ -67,10 +67,10 @@ set_include_path(get_include_path() . PATH_SEPARATOR . FILE_PATH);
ini_set("memory_limit", "128M"); //Default ini_set("memory_limit", "128M"); //Default
define("LOG", true); define("LOG", true);
define("START_TIME", microtime(true)); define("START_TIME", microtime(true));
define("MAJOR_VERSION", "Alpha_1.3.12dev"); define("MAJOR_VERSION", "Alpha_1.4dev");
define("CODENAME", "変梃(Henteko)マインカート(Minecart)"); define("CODENAME", "絶好(Zekkou)ケーキ(Cake)");
define("CURRENT_MINECRAFT_VERSION", "v0.8.1 alpha"); define("CURRENT_MINECRAFT_VERSION", "v0.8.1 alpha");
define("CURRENT_API_VERSION", 12); define("CURRENT_API_VERSION", 13);
define("CURRENT_PHP_VERSION", "5.5"); define("CURRENT_PHP_VERSION", "5.5");
$gitsha1 = false; $gitsha1 = false;
if(file_exists(FILE_PATH.".git/refs/heads/master")){ //Found Git information! if(file_exists(FILE_PATH.".git/refs/heads/master")){ //Found Git information!

View File

@ -31,7 +31,6 @@ define("VIEWER", 3);
//Players //Players
define("MAX_CHUNK_RATE", 20 / arg("max-chunks-per-second", 4)); //Default rate ~256 kB/s
define("PLAYER_MAX_QUEUE", 1024); define("PLAYER_MAX_QUEUE", 1024);
define("PLAYER_SURVIVAL_SLOTS", 36); define("PLAYER_SURVIVAL_SLOTS", 36);

View File

@ -0,0 +1,28 @@
<?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/
*
*
*/
/**
* Events that can be cancelled must use the interface CancellableEvent
*/
interface CancellableEvent{
}

View File

@ -0,0 +1,51 @@
<?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/
*
*
*/
abstract class EventHandler{
public static function callEvent(BaseEvent $event){
foreach($event::$handlerPriority as $priority => $handlerList){
if(count($handlerList) > 0){
$event->setPrioritySlot($priority);
foreach($handlerList as $handler){
call_user_func($handler, $event);
}
if($event->isForced()){
if($event instanceof CancellableEvent and $event->isCancelled()){
return BaseEvent::DENY;
}else{
return BaseEvent::ALLOW;
}
}
}
}
if($event instanceof CancellableEvent and $event->isCancelled()){
return BaseEvent::DENY;
}elseif($event->isAllowed()){
return BaseEvent::ALLOW;
}else{
return BaseEvent::NORMAL;
}
}
}

View File

@ -0,0 +1,52 @@
<?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/
*
*
*/
abstract class EventPriority{
/**
* Event call is of very low importance and should be ran first, to allow
* other plugins to further customise the outcome
*/
const LOWEST = 5;
/**
* Event call is of low importance
*/
const LOW = 4;
/**
* Event call is neither important or unimportant, and may be ran normally
*/
const NORMAL = 3;
/**
* Event call is of high importance
*/
const HIGH = 2;
/**
* Event call is critical and must have the final say in what happens
* to the event
*/
const HIGHEST = 1;
/**
* Event is listened to purely for monitoring the outcome of an event.
*
* No modifications to the event should be made under this priority
*/
const MONITOR = 0;
}

29
src/event/PluginEvent.php Normal file
View File

@ -0,0 +1,29 @@
<?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/
*
*
*/
/**
* Plugins that create events must use this class as the base
*/
abstract class PluginEvent extends BaseEvent{
}

24
src/event/ServerEvent.php Normal file
View File

@ -0,0 +1,24 @@
<?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/
*
*
*/
abstract class ServerEvent extends BaseEvent{
}

View File

@ -0,0 +1,41 @@
<?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 DataPacketReceiveEvent extends ServerEvent implements CancellableEvent{
public static $handlers;
public static $handlerPriority;
private $packet;
private $player;
public function __construct(Player $player, RakNetDataPacket $packet){
$this->packet = $packet;
$this->player = $player;
}
public function getPacket(){
return $this->packet;
}
public function getPlayer(){
return $this->player;
}
}

View File

@ -0,0 +1,41 @@
<?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 DataPacketSendEvent extends ServerEvent implements CancellableEvent{
public static $handlers;
public static $handlerPriority;
private $packet;
private $player;
public function __construct(Player $player, RakNetDataPacket $packet){
$this->packet = $packet;
$this->player = $player;
}
public function getPacket(){
return $this->packet;
}
public function getPlayer(){
return $this->player;
}
}

View File

@ -0,0 +1,36 @@
<?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 PacketReceiveEvent extends ServerEvent implements CancellableEvent{
public static $handlers;
public static $handlerPriority;
private $packet;
public function __construct(Packet $packet){
$this->packet = $packet;
}
public function getPacket(){
return $this->packet;
}
}

View File

@ -0,0 +1,36 @@
<?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 PacketSendEvent extends ServerEvent implements CancellableEvent{
public static $handlers;
public static $handlerPriority;
private $packet;
public function __construct(Packet $packet){
$this->packet = $packet;
}
public function getPacket(){
return $this->packet;
}
}

View File

@ -140,7 +140,7 @@ function arguments ( $args ){
$args = array(); $args = array();
} }
array_shift( $args ); array_shift( $args );
$args = join( $args, ' ' ); $args = implode(' ', $args);
preg_match_all('/ (--[\w\-]+ (?:[= ] [^-\s]+ )? ) | (-\w+) | (\w+) /x', $args, $match ); preg_match_all('/ (--[\w\-]+ (?:[= ] [^-\s]+ )? ) | (-\w+) | (\w+) /x', $args, $match );
$args = array_shift( $match ); $args = array_shift( $match );
@ -158,7 +158,7 @@ function arguments ( $args ){
$value = preg_split( '/[= ]/', $arg, 2 ); $value = preg_split( '/[= ]/', $arg, 2 );
$com = substr( array_shift($value), 2 ); $com = substr( array_shift($value), 2 );
$value = join($value); $value = implode($value);
$ret['commands'][$com] = !empty($value) ? $value : true; $ret['commands'][$com] = !empty($value) ? $value : true;
continue; continue;
@ -218,6 +218,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;
@ -241,6 +256,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;
} }

View File

@ -41,7 +41,7 @@ class SignPostBlock extends TransparentBlock{
return true; return true;
}else{ }else{
$this->meta = $faces[$face]; $this->meta = $faces[$face];
$this->level->setBlock($block, BlockAPI::get(WALL_SIGN, $this->meta, true, false, true)); $this->level->setBlock($block, BlockAPI::get(WALL_SIGN, $this->meta), true, false, true);
return true; return true;
} }
} }

View File

@ -22,7 +22,7 @@
class TallGrassBlock extends FlowableBlock{ class TallGrassBlock extends FlowableBlock{
public function __construct($meta = 1){ public function __construct($meta = 1){
parent::__construct(TALL_GRASS, $meta, "Tall Grass"); parent::__construct(TALL_GRASS, $meta, "Tall Grass");
//$this->isReplaceable = true; $this->isReplaceable = true;
$names = array( $names = array(
0 => "Dead Shrub", 0 => "Dead Shrub",
1 => "Tall Grass", 1 => "Tall Grass",

View File

@ -43,7 +43,6 @@ class SpawnEggItem extends Item{
--$this->count; --$this->count;
} }
return true; return true;
break;
} }
return false; return false;
} }

224
src/nbt/NBT.php Normal file
View File

@ -0,0 +1,224 @@
<?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 NBT{
const LITTLE_ENDIAN = 0;
const BIG_ENDIAN = 1;
private $buffer;
private $offset;
private $endianness;
private $data;
public function get($len){
if($len < 0){
$this->offset = strlen($this->buffer) - 1;
return "";
}
if($len === true){
return substr($this->buffer, $this->offset);
}
$this->offset += $len;
return substr($this->buffer, $this->offset - $len, $len);
}
public function put($v){
$this->buffer .= $v;
}
public function feof(){
return !isset($this->buffer{$this->offset});
}
public function __construct($endianness = NBT::LITTLE_ENDIAN){
$this->offset = 0;
$this->endianness = $endianness & 0x01;
}
public function read($buffer){
$this->offset = 0;
$this->buffer = $buffer;
$this->data = $this->readTag();
}
public function write(){
$this->offset = 0;
if($this->data instanceof NBTTag_Compound){
$this->writeTag($this->data);
return $this->buffer;
}else{
return false;
}
}
public function readTag(){
switch($this->getByte()){
case NBTTag::TAG_Byte:
$tag = new NBTTag_Byte($this->getString());
$tag->read($this);
break;
case NBTTag::TAG_Byte:
$tag = new NBTTag_Byte($this->getString());
$tag->read($this);
break;
case NBTTag::TAG_Short:
$tag = new NBTTag_Short($this->getString());
$tag->read($this);
break;
case NBTTag::TAG_Int:
$tag = new NBTTag_Int($this->getString());
$tag->read($this);
break;
case NBTTag::TAG_Long:
$tag = new NBTTag_Long($this->getString());
$tag->read($this);
break;
case NBTTag::TAG_Float:
$tag = new NBTTag_Float($this->getString());
$tag->read($this);
break;
case NBTTag::TAG_Double:
$tag = new NBTTag_Double($this->getString());
$tag->read($this);
break;
case NBTTag::TAG_Byte_Array:
$tag = new NBTTag_Byte_Array($this->getString());
$tag->read($this);
break;
case NBTTag::TAG_String:
$tag = new NBTTag_String($this->getString());
$tag->read($this);
break;
case NBTTag::TAG_List:
$tag = new NBTTag_List($this->getString());
$tag->read($this);
break;
case NBTTag::TAG_Compound:
$tag = new NBTTag_Compound($this->getString());
$tag->read($this);
break;
case NBTTag::TAG_Int_Array:
$tag = new NBTTag_Int_Array($this->getString());
$tag->read($this);
break;
case NBTTag::TAG_End: //No named tag
default:
$tag = new NBTTag_End;
break;
}
return $tag;
}
public function writeTag(NBTTag $tag){
$this->putByte($tag->getType());
if($tag instanceof NamedNBTTag and $tag->getName() !== false){
$this->putString($tag->getName());
}
$tag->write($this);
}
public function getByte(){
return Utils::readByte($this->get(1), true);
}
public function putByte($v){
$this->buffer .= Utils::writeByte($v);
}
public function getShort(){
return $this->endianness === self::BIG_ENDIAN ? Utils::readShort($this->get(2)) : Utils::readLShort($this->get(2));
}
public function putShort($v){
$this->buffer .= $this->endianness === self::BIG_ENDIAN ? Utils::writeShort($v) : Utils::writeLShort($v);
}
public function getInt(){
return $this->endianness === self::BIG_ENDIAN ? Utils::readInt($this->get(4)) : Utils::readLInt($this->get(4));
}
public function putInt($v){
$this->buffer .= $this->endianness === self::BIG_ENDIAN ? Utils::writeInt($v) : Utils::writeLInt($v);
}
public function getLong(){
return $this->endianness === self::BIG_ENDIAN ? Utils::readLong($this->get(8)) : Utils::readLLong($this->get(8));
}
public function putLong($v){
$this->buffer .= $this->endianness === self::BIG_ENDIAN ? Utils::writeLong($v) : Utils::writeLLong($v);
}
public function getFloat(){
return $this->endianness === self::BIG_ENDIAN ? Utils::readFloat($this->get(4)) : Utils::readLFloat($this->get(4));
}
public function putFloat($v){
$this->buffer .= $this->endianness === self::BIG_ENDIAN ? Utils::writeFloat($v) : Utils::writeLFloat($v);
}
public function getDouble(){
return $this->endianness === self::BIG_ENDIAN ? Utils::readDouble($this->get(8)) : Utils::readLDouble($this->get(8));
}
public function putDouble($v){
$this->buffer .= $this->endianness === self::BIG_ENDIAN ? Utils::writeDouble($v) : Utils::writeLDouble($v);
}
public function getString(){
return $this->get($this->getShort());
}
public function putString($v){
$this->putShort(strlen($v));
$this->buffer .= $v;
}
public function __get($name){
return $this->data instanceof NBTTag_Compound ? $this->data->{$name} : false;
}
public function __set($name, $value){
if($this->data instanceof NBTTag_Compound){
$this->data->{$name} = $value;
}
}
public function __isset($name){
return $this->data instanceof NBTTag_Compound ? isset($this->data->{$name}) : false;
}
public function __unset($name){
if($this->data instanceof NBTTag_Compound){
unset($this->data->{$name});
}
}
public function getData(){
return $this->data;
}
public function setData(NBTTag_Compound $data){
$this->data = $data;
}
}

55
src/nbt/NBTTag.php Normal file
View File

@ -0,0 +1,55 @@
<?php
/**
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
abstract class NBTTag{
const TAG_End = 0;
const TAG_Byte = 1;
const TAG_Short = 2;
const TAG_Int = 3;
const TAG_Long = 4;
const TAG_Float = 5;
const TAG_Double = 6;
const TAG_Byte_Array = 7;
const TAG_String = 8;
const TAG_List = 9;
const TAG_Compound = 10;
const TAG_Int_Array = 11;
protected $value = 0;
public function getValue(){
return $this->value;
}
public abstract function getType();
public function setValue($value){
$this->value = $value;
}
abstract public function write(NBT $nbt);
abstract public function read(NBT $nbt);
public final function __toString(){
return $this->value;
}
}

43
src/nbt/NamedNBTTag.php Normal file
View File

@ -0,0 +1,43 @@
<?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/
*
*
*/
/***REM_START***/
require_once("NBTTag.php");
/***REM_END***/
abstract class NamedNBTTag extends NBTTag{
protected $name;
public function __construct($name = "", $value = false){
$this->name = $name;
if($value !== false){
$this->value = $value;
}
}
public function getName(){
return $this->name;
}
public function setName($name){
$this->name = $name;
}
}

35
src/nbt/tags/TAG_Byte.php Normal file
View File

@ -0,0 +1,35 @@
<?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 NBTTag_Byte extends NamedNBTTag{
public function getType(){
return NBTTag::TAG_Byte;
}
public function read(NBT $nbt){
$this->value = $nbt->getByte();
}
public function write(NBT $nbt){
$nbt->putByte($this->value);
}
}

View File

@ -0,0 +1,36 @@
<?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 NBTTag_Byte_Array extends NamedNBTTag{
public function getType(){
return NBTTag::TAG_Byte_Array;
}
public function read(NBT $nbt){
$this->value = $nbt->get($this->getInt());
}
public function write(NBT $nbt){
$nbt->putInt(strlen($this->value));
$nbt->put($this->value);
}
}

View File

@ -0,0 +1,63 @@
<?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 NBTTag_Compound extends NamedNBTTag{
public function getType(){
return NBTTag::TAG_Compound;
}
public function __get($name){
return isset($this->value[$name]) ? $this->value[$name]->getValue() : false;
}
public function __set($name, $value){
if(isset($this->value[$name])){
$this->value[$name]->setValue($value);
}
}
public function __isset($name){
return isset($this->value[$name]);
}
public function __unset($name){
unset($this->value[$name]);
}
public function read(NBT $nbt){
$this->value = array();
do{
$tag = $nbt->readTag();
if($tag instanceof NamedNBTTag and $tag->getName() !== ""){
$this->value[$tag->getName()] = $tag;
}else{
$this->value[] = $tag;
}
}while(!($tag instanceof NBTTag_End) and !$nbt->feof());
}
public function write(NBT $nbt){
foreach($this->value as $tag){
$nbt->writeTag($tag);
}
}
}

View File

@ -0,0 +1,35 @@
<?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 NBTTag_Double extends NamedNBTTag{
public function getType(){
return NBTTag::TAG_Double;
}
public function read(NBT $nbt){
$this->value = $nbt->getDouble();
}
public function write(NBT $nbt){
$nbt->putDouble($this->value);
}
}

35
src/nbt/tags/TAG_End.php Normal file
View File

@ -0,0 +1,35 @@
<?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 NBTTag_End extends NBTTag{
public function getType(){
return NBTTag::TAG_End;
}
public function read(NBT $nbt){
}
public function write(NBT $nbt){
}
}

View File

@ -0,0 +1,35 @@
<?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 NBTTag_Float extends NamedNBTTag{
public function getType(){
return NBTTag::TAG_Float;
}
public function read(NBT $nbt){
$this->value = $nbt->getFloat();
}
public function write(NBT $nbt){
$nbt->putFloat($this->value);
}
}

35
src/nbt/tags/TAG_Int.php Normal file
View File

@ -0,0 +1,35 @@
<?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 NBTTag_Int extends NamedNBTTag{
public function getType(){
return NBTTag::TAG_Int;
}
public function read(NBT $nbt){
$this->value = $nbt->getInt();
}
public function write(NBT $nbt){
$nbt->putInt($this->value);
}
}

View File

@ -0,0 +1,42 @@
<?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 NBTTag_Int_Array extends NamedNBTTag{
public function getType(){
return NBTTag::TAG_Int_Array;
}
public function read(NBT $nbt){
$this->value = array();
$size = $nbt->getInt();
for($i = 0; $i < $size and !$nbt->feof(); ++$i){
$this->value[] = $nbt->getInt();
}
}
public function write(NBT $nbt){
$nbt->putInt(count($this->value));
foreach($this->value as $v){
$nbt->putInt($v);
}
}
}

126
src/nbt/tags/TAG_List.php Normal file
View File

@ -0,0 +1,126 @@
<?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 NBTTag_List extends NamedNBTTag{
public function getType(){
return NBTTag::TAG_List;
}
public function __get($name){
return isset($this->value[$name]) ? $this->value[$name]->getValue() : false;
}
public function __set($name, $value){
if(isset($this->value[$name])){
$this->value[$name]->setValue($value);
}
}
public function __isset($name){
return isset($this->value[$name]);
}
public function __unset($name){
unset($this->value[$name]);
}
public function read(NBT $nbt){
$this->value = array();
$tagId = $nbt->getByte();
$this->value[-1] = $tagId;
$size = $nbt->getInt();
for($i = 0; $i < $size and !$nbt->feof(); ++$i){
switch($tagId){
case NBTTag::TAG_Byte:
$tag = new NBTTag_Byte(false);
$tag->read($nbt);
$this->value[] = $tag;
break;
case NBTTag::TAG_Byte:
$tag = new NBTTag_Byte(false);
$tag->read($nbt);
$this->value[] = $tag;
break;
case NBTTag::TAG_Short:
$tag = new NBTTag_Short(false);
$tag->read($nbt);
$this->value[] = $tag;
break;
case NBTTag::TAG_Int:
$tag = new NBTTag_Int(false);
$tag->read($nbt);
$this->value[] = $tag;
break;
case NBTTag::TAG_Long:
$tag = new NBTTag_Long(false);
$tag->read($nbt);
$this->value[] = $tag;
break;
case NBTTag::TAG_Float:
$tag = new NBTTag_Float(false);
$tag->read($nbt);
$this->value[] = $tag;
break;
case NBTTag::TAG_Double:
$tag = new NBTTag_Double(false);
$tag->read($nbt);
$this->value[] = $tag;
break;
case NBTTag::TAG_Byte_Array:
$tag = new NBTTag_Byte_Array(false);
$tag->read($nbt);
$this->value[] = $tag;
break;
case NBTTag::TAG_String:
$tag = new NBTTag_String(false);
$tag->read($nbt);
$this->value[] = $tag;
break;
case NBTTag::TAG_List:
$tag = new NBTTag_List(false);
$tag->read($nbt);
$this->value[] = $tag;
break;
case NBTTag::TAG_Compound:
$tag = new NBTTag_Compound(false);
$tag->read($nbt);
$this->value[] = $tag;
break;
case NBTTag::TAG_Int_Array:
$tag = new NBTTag_Int_Array(false);
$tag->read($nbt);
$this->value[] = $tag;
break;
}
}
}
public function write(NBT $nbt){
$nbt->putByte($this->value[-1]);
$nbt->putInt(count($this->value) - 1);
foreach($this->value as $tag){
if($tag instanceof NBTTag){
$nbt->writeTag($tag);
}
}
}
}

35
src/nbt/tags/TAG_Long.php Normal file
View File

@ -0,0 +1,35 @@
<?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 NBTTag_Long extends NamedNBTTag{
public function getType(){
return NBTTag::TAG_Long;
}
public function read(NBT $nbt){
$this->value = $nbt->getLong();
}
public function write(NBT $nbt){
$nbt->putLong($this->value);
}
}

View File

@ -0,0 +1,35 @@
<?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 NBTTag_Short extends NamedNBTTag{
public function getType(){
return NBTTag::TAG_Short;
}
public function read(NBT $nbt){
$this->value = $nbt->getShort();
}
public function write(NBT $nbt){
$nbt->putShort($this->value);
}
}

View File

@ -0,0 +1,36 @@
<?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 NBTTag_String extends NamedNBTTag{
public function getType(){
return NBTTag::TAG_String;
}
public function read(NBT $nbt){
$this->value = $nbt->get($nbt->getShort());
}
public function write(NBT $nbt){
$nbt->putShort(strlen($this->value));
$nbt->put($this->value);
}
}

View File

@ -20,19 +20,16 @@
*/ */
class MinecraftInterface{ class MinecraftInterface{
public $client;
public $bandwidth; public $bandwidth;
private $socket; private $socket;
private $packets; private $packets;
function __construct($object, $server, $port = 25565, $listen = false, $client = false, $serverip = "0.0.0.0"){ function __construct($server, $port = 25565, $serverip = "0.0.0.0"){
$this->socket = new UDPSocket($server, $port, (bool) $listen, $serverip); $this->socket = new UDPSocket($server, $port, true, $serverip);
if($this->socket->connected === false){ if($this->socket->connected === false){
console("[SEVERE] Couldn't bind to $serverip:".$port, true, true, 0); console("[SEVERE] Couldn't bind to $serverip:".$port, true, true, 0);
exit(1); exit(1);
} }
$this->bandwidth = array(0, 0, microtime(true)); $this->bandwidth = array(0, 0, microtime(true));
$this->client = (bool) $client;
$this->start = microtime(true);
$this->packets = array(); $this->packets = array();
} }
@ -41,12 +38,9 @@ class MinecraftInterface{
} }
public function readPacket(){ public function readPacket(){
if($this->socket->connected === false){ $buf = null;
return false; $source = null;
} $port = null;
$buf = "";
$source = false;
$port = 1;
$len = $this->socket->read($buf, $source, $port); $len = $this->socket->read($buf, $source, $port);
if($len === false or $len === 0){ if($len === false or $len === 0){
return false; return false;
@ -57,29 +51,42 @@ class MinecraftInterface{
private function parsePacket($buffer, $source, $port){ private function parsePacket($buffer, $source, $port){
$pid = ord($buffer{0}); $pid = ord($buffer{0});
if(RakNetInfo::isValid($pid)){ if(RakNetInfo::isValid($pid)){
$parser = new RakNetParser($buffer); $parser = new RakNetParser($buffer);
if($parser->packet !== false){ if($parser->packet !== false){
$parser->packet->ip = $source; $parser->packet->ip = $source;
$parser->packet->port = $port; $parser->packet->port = $port;
if(EventHandler::callEvent(new PacketReceiveEvent($parser->packet)) === BaseEvent::DENY){
return false;
}
return $parser->packet; return $parser->packet;
} }
return false; return false;
}elseif($pid === 0xfe and $buffer{1} === "\xfd" and ServerAPI::request()->api->query instanceof QueryHandler){
$packet = new QueryPacket;
$packet->ip = $source;
$packet->port = $port;
$packet->buffer =& $buffer;
if(EventHandler::callEvent(new PacketReceiveEvent($packet)) === BaseEvent::DENY){
return false;
}
ServerAPI::request()->api->query->handle($packet);
}else{ }else{
$packet = new Packet(); $packet = new Packet();
$packet->ip = $source; $packet->ip = $source;
$packet->port = $port; $packet->port = $port;
$packet->buffer = $buffer; $packet->buffer =& $buffer;
if(ServerAPI::request()->api->dhandle("server.unknownpacket.$pid", $packet) !== true){ EventHandler::callEvent(new PacketReceiveEvent($packet));
console("[ERROR] Unknown Packet ID 0x".Utils::strToHex(chr($pid)), true, true, 2);
}
return false; return false;
} }
} }
public function writePacket(Packet $packet){ public function writePacket(Packet $packet){
if($packet instanceof RakNetPacket){ if(EventHandler::callEvent(new PacketSendEvent($packet)) === BaseEvent::DENY){
$codec = new RakNetCodec($packet); return 0;
}elseif($packet instanceof RakNetPacket){
new RakNetCodec($packet);
} }
$write = $this->socket->write($packet->buffer, $packet->ip, $packet->port); $write = $this->socket->write($packet->buffer, $packet->ip, $packet->port);
$this->bandwidth[1] += $write; $this->bandwidth[1] += $write;

View File

@ -104,7 +104,11 @@ class RCONInstance extends Thread{
} }
private function writePacket($client, $requestID, $packetType, $payload){ private function writePacket($client, $requestID, $packetType, $payload){
return socket_write($client, Utils::writeLInt(strlen($payload)).Utils::writeLInt((int) $requestID).Utils::writeLInt((int) $packetType).($payload === "" ? "\x00":$payload)."\x00"); $pk = Utils::writeLInt((int) $requestID)
. Utils::writeLInt((int) $packetType)
. $payload
. "\x00\x00"; //Terminate payload and packet
return socket_write($client, Utils::writeLInt(strlen($pk)).$pk);
} }
private function readPacket($client, &$size, &$requestID, &$packetType, &$payload){ private function readPacket($client, &$size, &$requestID, &$packetType, &$payload){

View File

@ -22,7 +22,7 @@
class UDPSocket{ class UDPSocket{
public $connected, $sock, $server; public $connected, $sock, $server, $port;
function __construct($server, $port, $listen = false, $serverip = "0.0.0.0"){ function __construct($server, $port, $listen = false, $serverip = "0.0.0.0"){
$this->server = $server; $this->server = $server;
$this->port = $port; $this->port = $port;
@ -34,7 +34,7 @@ class UDPSocket{
}else{ }else{
if(socket_bind($this->sock, $serverip, $port) === true){ if(socket_bind($this->sock, $serverip, $port) === true){
socket_set_option($this->sock, SOL_SOCKET, SO_REUSEADDR, 0); socket_set_option($this->sock, SOL_SOCKET, SO_REUSEADDR, 0);
socket_set_option($this->sock, SOL_SOCKET, SO_SNDBUF, 1024 * 1024 * 8); //8MB socket_set_option($this->sock, SOL_SOCKET, SO_SNDBUF, 1024 * 1024 * 2); //2MB
socket_set_option($this->sock, SOL_SOCKET, SO_RCVBUF, 1024 * 1024); //1MB socket_set_option($this->sock, SOL_SOCKET, SO_RCVBUF, 1024 * 1024); //1MB
$this->unblock(); $this->unblock();
$this->connected = true; $this->connected = true;
@ -45,7 +45,6 @@ class UDPSocket{
} }
public function close($error = 125){ public function close($error = 125){
$this->connected = false;
return @socket_close($this->sock); return @socket_close($this->sock);
} }
@ -58,16 +57,10 @@ class UDPSocket{
} }
public function read(&$buf, &$source, &$port){ public function read(&$buf, &$source, &$port){
if($this->connected === false){
return false;
}
return @socket_recvfrom($this->sock, $buf, 65535, 0, $source, $port); return @socket_recvfrom($this->sock, $buf, 65535, 0, $source, $port);
} }
public function write($data, $dest, $port){ public function write($data, $dest, $port){
if($this->connected === false){
return false;
}
return @socket_sendto($this->sock, $data, strlen($data), 0, $dest, $port); return @socket_sendto($this->sock, $data, strlen($data), 0, $dest, $port);
} }

View File

@ -20,7 +20,7 @@
*/ */
class ProtocolInfo{ abstract class ProtocolInfo{
const CURRENT_PROTOCOL = 14; const CURRENT_PROTOCOL = 14;
@ -96,63 +96,6 @@ class ProtocolInfo{
const ENTITY_DATA_PACKET = 0xb8; const ENTITY_DATA_PACKET = 0xb8;
//const PLAYER_INPUT_PACKET = 0xb9; //const PLAYER_INPUT_PACKET = 0xb9;
public static $packets = array(
-1 => "UnknownPacket",
ProtocolInfo::PING_PACKET => "PingPacket",
ProtocolInfo::PONG_PACKET => "PongPacket",
ProtocolInfo::CLIENT_CONNECT_PACKET => "ClientConnectPacket",
ProtocolInfo::SERVER_HANDSHAKE_PACKET => "ServerHandshakePacket",
ProtocolInfo::DISCONNECT_PACKET => "DisconnectPacket",
ProtocolInfo::LOGIN_PACKET => "LoginPacket",
ProtocolInfo::LOGIN_STATUS_PACKET => "LoginStatusPacket",
ProtocolInfo::READY_PACKET => "ReadyPacket",
ProtocolInfo::MESSAGE_PACKET => "MessagePacket",
ProtocolInfo::SET_TIME_PACKET => "SetTimePacket",
ProtocolInfo::START_GAME_PACKET => "StartGamePacket",
ProtocolInfo::ADD_MOB_PACKET => "AddMobPacket",
ProtocolInfo::ADD_PLAYER_PACKET => "AddPlayerPacket",
ProtocolInfo::REMOVE_PLAYER_PACKET => "RemovePlayerPacket",
ProtocolInfo::ADD_ENTITY_PACKET => "AddEntityPacket",
ProtocolInfo::REMOVE_ENTITY_PACKET => "RemoveEntityPacket",
ProtocolInfo::ADD_ITEM_ENTITY_PACKET => "AddItemEntityPacket",
ProtocolInfo::TAKE_ITEM_ENTITY_PACKET => "TakeItemEntityPacket",
ProtocolInfo::MOVE_ENTITY_PACKET => "MoveEntityPacket",
ProtocolInfo::MOVE_ENTITY_PACKET_POSROT => "MoveEntityPacket_PosRot",
ProtocolInfo::ROTATE_HEAD_PACKET => "RotateHeadPacket",
ProtocolInfo::MOVE_PLAYER_PACKET => "MovePlayerPacket",
ProtocolInfo::REMOVE_BLOCK_PACKET => "RemoveBlockPacket",
ProtocolInfo::UPDATE_BLOCK_PACKET => "UpdateBlockPacket",
ProtocolInfo::ADD_PAINTING_PACKET => "AddPaintingPacket",
ProtocolInfo::EXPLODE_PACKET => "ExplodePacket",
ProtocolInfo::LEVEL_EVENT_PACKET => "LevelEventPacket",
ProtocolInfo::TILE_EVENT_PACKET => "TileEventPacket",
ProtocolInfo::ENTITY_EVENT_PACKET => "EntityEventPacket",
ProtocolInfo::REQUEST_CHUNK_PACKET => "RequestChunkPacket",
ProtocolInfo::CHUNK_DATA_PACKET => "ChunkDataPacket",
ProtocolInfo::PLAYER_EQUIPMENT_PACKET => "PlayerEquipmentPacket",
ProtocolInfo::PLAYER_ARMOR_EQUIPMENT_PACKET => "PlayerArmorEquipmentPacket",
ProtocolInfo::INTERACT_PACKET => "InteractPacket",
ProtocolInfo::USE_ITEM_PACKET => "UseItemPacket",
ProtocolInfo::PLAYER_ACTION_PACKET => "PlayerActionPacket",
ProtocolInfo::HURT_ARMOR_PACKET => "HurtArmorPacket",
ProtocolInfo::SET_ENTITY_DATA_PACKET => "SetEntityDataPacket",
ProtocolInfo::SET_ENTITY_MOTION_PACKET => "SetEntityMotionPacket",
ProtocolInfo::SET_HEALTH_PACKET => "SetHealthPacket",
ProtocolInfo::SET_SPAWN_POSITION_PACKET => "SetSpawnPositionPacket",
ProtocolInfo::ANIMATE_PACKET => "AnimatePacket",
ProtocolInfo::RESPAWN_PACKET => "RespawnPacket",
ProtocolInfo::SEND_INVENTORY_PACKET => "SendInventoryPacket",
ProtocolInfo::DROP_ITEM_PACKET => "DropItemPacket",
ProtocolInfo::CONTAINER_OPEN_PACKET => "ContainerOpenPacket",
ProtocolInfo::CONTAINER_CLOSE_PACKET => "ContainerClosePacket",
ProtocolInfo::CONTAINER_SET_SLOT_PACKET => "ContainerSetSlotPacket",
ProtocolInfo::CONTAINER_SET_DATA_PACKET => "ContainerSetDataPacket",
ProtocolInfo::CONTAINER_SET_CONTENT_PACKET => "ContainerSetContentPacket",
ProtocolInfo::CHAT_PACKET => "ChatPacket",
ProtocolInfo::ADVENTURE_SETTINGS_PACKET => "AdventureSettingsPacket",
ProtocolInfo::ENTITY_DATA_PACKET => "EntityDataPacket",
);
} }
/***REM_START***/ /***REM_START***/

View File

@ -20,8 +20,8 @@
*/ */
class ChunkDataPacket extends RakNetDataPacket{ class ChunkDataPacket extends RakNetDataPacket{
public $x; public $chunkX;
public $z; public $chunkZ;
public $data; public $data;
public function pid(){ public function pid(){
@ -34,8 +34,8 @@ class ChunkDataPacket extends RakNetDataPacket{
public function encode(){ public function encode(){
$this->reset(); $this->reset();
$this->putInt($this->x); $this->putInt($this->chunkX);
$this->putInt($this->z); $this->putInt($this->chunkZ);
$this->put($this->data); $this->put($this->data);
} }

View File

@ -25,7 +25,7 @@ class ClientHandshakePacket extends RakNetDataPacket{
public $port; public $port;
public $dataArray0; public $dataArray0;
public $dataArray; public $dataArray;
public $timespamp; public $timestamp;
public $session2; public $session2;
public $session; public $session;
@ -39,7 +39,7 @@ class ClientHandshakePacket extends RakNetDataPacket{
$this->port = $this->getShort(true); $this->port = $this->getShort(true);
$this->dataArray0 = $this->get($this->getByte()); $this->dataArray0 = $this->get($this->getByte());
$this->dataArray = $this->getDataArray(9); $this->dataArray = $this->getDataArray(9);
$this->timespamp = $this->get(2); $this->timestamp = $this->get(2);
$this->session2 = $this->getLong(); $this->session2 = $this->getLong();
$this->session = $this->getLong(); $this->session = $this->getLong();
} }

View File

@ -20,16 +20,16 @@
*/ */
class RequestChunkPacket extends RakNetDataPacket{ class RequestChunkPacket extends RakNetDataPacket{
public $x; public $chunkX;
public $z; public $chunkZ;
public function pid(){ public function pid(){
return ProtocolInfo::REQUEST_CHUNK_PACKET; return ProtocolInfo::REQUEST_CHUNK_PACKET;
} }
public function decode(){ public function decode(){
$this->x = $this->getInt(); $this->chunkX = $this->getInt();
$this->z = $this->getInt(); $this->chunkZ = $this->getInt();
} }
public function encode(){ public function encode(){

View File

@ -36,7 +36,7 @@ class SendInventoryPacket extends RakNetDataPacket{
for($s = 0; $s < $count and !$this->feof(); ++$s){ for($s = 0; $s < $count and !$this->feof(); ++$s){
$this->slots[$s] = $this->getSlot(); $this->slots[$s] = $this->getSlot();
} }
if($this->windowid === 1){ //Armir is sent if($this->windowid === 1){ //Armor is sent
for($s = 0; $s < 4; ++$s){ for($s = 0; $s < 4; ++$s){
$this->armor[$s] = $this->getSlot(); $this->armor[$s] = $this->getSlot();
} }

View File

@ -24,7 +24,7 @@ Implementation of the UT3 Query Protocol (GameSpot)
Source: http://wiki.unrealadmin.org/UT3_query_protocol Source: http://wiki.unrealadmin.org/UT3_query_protocol
*/ */
class Query{ class QueryHandler{
private $socket, $server, $lastToken, $token, $longData, $timeout; private $socket, $server, $lastToken, $token, $longData, $timeout;
public function __construct(){ public function __construct(){
@ -41,7 +41,7 @@ class Query{
Then, the Query class handles itself sending the packets in raw form, because Then, the Query class handles itself sending the packets in raw form, because
packets can conflict with the MCPE ones. packets can conflict with the MCPE ones.
*/ */
$this->server->addHandler("server.unknownpacket.254", array($this, "packetHandler"), 50);
$this->server->schedule(20 * 30, array($this, "regenerateToken"), array(), true); $this->server->schedule(20 * 30, array($this, "regenerateToken"), array(), true);
$this->regenerateToken(); $this->regenerateToken();
$this->lastToken = $this->token; $this->lastToken = $this->token;
@ -91,51 +91,48 @@ class Query{
public function regenerateToken(){ public function regenerateToken(){
$this->lastToken = $this->token; $this->lastToken = $this->token;
$this->token = Utils::readInt("\x00".Utils::getRandomBytes(3, false)); $this->token = Utils::getRandomBytes(16, false);
} }
public function packetHandler($packet, $event){ public static function getTokenString($token, $salt){
if($event !== "server.unknownpacket.254"){ return Utils::readInt(substr(hash("sha512", $salt . ":". $token, true), 7, 4));
return; }
}
$magic = substr($packet->buffer, 0, 2); public function handle(QueryPacket $packet){
$offset = 2; $packet->decode();
if($magic !== "\xfe\xfd"){ switch($packet->packetType){
return; case QueryPacket::HANDSHAKE: //Handshake
} $pk = new QueryPacket;
$type = ord($packet->buffer{2});
++$offset;
$sessionID = Utils::readInt(substr($packet->buffer, $offset, 4));
$offset += 4;
$payload = substr($packet->buffer, $offset);
switch($type){
case 9: //Handshake
$pk = new Packet;
$pk->ip = $packet->ip; $pk->ip = $packet->ip;
$pk->port = $packet->port; $pk->port = $packet->port;
$pk->buffer = chr(9).Utils::writeInt($sessionID).$this->token."\x00"; $pk->packetType = QueryPacket::HANDSHAKE;
$pk->sessionID = $packet->sessionID;
$pk->payload = self::getTokenString($this->token, $packet->ip)."\x00";
$pk->encode();
$this->server->send($pk); $this->server->send($pk);
break; break;
case 0: //Stat case QueryPacket::STATISTICS: //Stat
$token = Utils::readInt(substr($payload, 0, 4)); $token = Utils::readInt(substr($packet->payload, 0, 4));
if($token !== $this->token and $token !== $this->lastToken){ if($token !== self::getTokenString($this->token, $packet->ip) and $token !== self::getTokenString($this->lastToken, $packet->ip)){
break; break;
} }
$pk = new Packet; $pk = new QueryPacket;
$pk->ip = $packet->ip; $pk->ip = $packet->ip;
$pk->port = $packet->port; $pk->port = $packet->port;
if(strlen($payload) === 8){ $pk->packetType = QueryPacket::STATISTICS;
$pk->sessionID = $packet->sessionID;
if(strlen($packet->payload) === 8){
if($this->timeout < microtime(true)){ if($this->timeout < microtime(true)){
$this->regenerateInfo(); $this->regenerateInfo();
} }
$pk->buffer = chr(0).Utils::writeInt($sessionID).$this->longData; $pk->payload = $this->longData;
}else{ }else{
$pk->buffer = chr(0).Utils::writeInt($sessionID).$this->server->name."\x00".(($this->server->gamemode & 0x01) === 0 ? "SMP":"CMP")."\x00".$this->server->api->level->getDefault()->getName()."\x00".count($this->server->clients)."\x00".$this->server->maxClients."\x00".Utils::writeLShort($this->server->api->getProperty("server-port")).$this->server->api->getProperty("server-ip", "0.0.0.0")."\x00"; $pk->payload = $this->server->name."\x00".(($this->server->gamemode & 0x01) === 0 ? "SMP":"CMP")."\x00".$this->server->api->level->getDefault()->getName()."\x00".count($this->server->clients)."\x00".$this->server->maxClients."\x00".Utils::writeLShort($this->server->api->getProperty("server-port")).$this->server->api->getProperty("server-ip", "0.0.0.0")."\x00";
} }
$pk->encode();
$this->server->send($pk); $this->server->send($pk);
break; break;
} }
return true;
} }
} }

View File

@ -0,0 +1,41 @@
<?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 QueryPacket extends Packet{
const HANDSHAKE = 9;
const STATISTICS = 0;
public $packetType;
public $sessionID;
public $payload;
public function decode(){
$this->packetType = ord($this->buffer{2});
$this->sessionID = Utils::readInt(substr($this->buffer, 3, 4));
$this->payload = substr($this->buffer, 7);
}
public function encode(){
$this->buffer .= chr($this->packetType);
$this->buffer .= Utils::writeInt($this->sessionID);
$this->buffer .= $this->payload;
}
}

View File

@ -21,6 +21,7 @@
class RakNetCodec{ class RakNetCodec{
public $packet; public $packet;
private $buffer;
public function __construct(RakNetPacket $packet){ public function __construct(RakNetPacket $packet){
$this->packet = $packet; $this->packet = $packet;
$this->buffer =& $this->packet->buffer; $this->buffer =& $this->packet->buffer;

View File

@ -76,8 +76,8 @@ abstract class RakNetDataPacket extends stdClass{
$this->buffer .= Utils::writeLong($v); $this->buffer .= Utils::writeLong($v);
} }
protected function getInt($unsigned = false){ protected function getInt(){
return Utils::readInt($this->get(4), $unsigned); return Utils::readInt($this->get(4));
} }
protected function putInt($v){ protected function putInt($v){

View File

@ -19,7 +19,7 @@
* *
*/ */
class RakNetInfo{ abstract class RakNetInfo{
const STRUCTURE = 5; const STRUCTURE = 5;
const MAGIC = "\x00\xff\xff\x00\xfe\xfe\xfe\xfe\xfd\xfd\xfd\xfd\x12\x34\x56\x78"; const MAGIC = "\x00\xff\xff\x00\xfe\xfe\xfe\xfe\xfd\xfd\xfd\xfd\x12\x34\x56\x78";
const UNCONNECTED_PING = 0x01; const UNCONNECTED_PING = 0x01;

View File

@ -50,8 +50,8 @@ class RakNetParser{
return Utils::readLong($this->get(8), $unsigned); return Utils::readLong($this->get(8), $unsigned);
} }
private function getInt($unsigned = false){ private function getInt(){
return Utils::readInt($this->get(4), $unsigned); return Utils::readInt($this->get(4));
} }
private function getShort($unsigned = false){ private function getShort($unsigned = false){
@ -186,11 +186,170 @@ class RakNetParser{
if(strlen($buffer) < ($length - 1)){ if(strlen($buffer) < ($length - 1)){
return false; return false;
} }
if(isset(ProtocolInfo::$packets[$pid])){ switch($pid){
$data = new ProtocolInfo::$packets[$pid]; case ProtocolInfo::PING_PACKET:
}else{ $data = new PingPacket;
$data = new UnknownPacket(); break;
$data->packetID = $pid; case ProtocolInfo::PONG_PACKET:
$data = new PongPacket;
break;
case ProtocolInfo::CLIENT_CONNECT_PACKET:
$data = new ClientConnectPacket;
break;
case ProtocolInfo::SERVER_HANDSHAKE_PACKET:
$data = new ServerHandshakePacket;
break;
case ProtocolInfo::DISCONNECT_PACKET:
$data = new DisconnectPacket;
break;
case ProtocolInfo::LOGIN_PACKET:
$data = new LoginPacket;
break;
case ProtocolInfo::LOGIN_STATUS_PACKET:
$data = new LoginStatusPacket;
break;
case ProtocolInfo::READY_PACKET:
$data = new ReadyPacket;
break;
case ProtocolInfo::MESSAGE_PACKET:
$data = new MessagePacket;
break;
case ProtocolInfo::SET_TIME_PACKET:
$data = new SetTimePacket;
break;
case ProtocolInfo::START_GAME_PACKET:
$data = new StartGamePacket;
break;
case ProtocolInfo::ADD_MOB_PACKET:
$data = new AddMobPacket;
break;
case ProtocolInfo::ADD_PLAYER_PACKET:
$data = new AddPlayerPacket;
break;
case ProtocolInfo::REMOVE_PLAYER_PACKET:
$data = new RemovePlayerPacket;
break;
case ProtocolInfo::ADD_ENTITY_PACKET:
$data = new AddEntityPacket;
break;
case ProtocolInfo::REMOVE_ENTITY_PACKET:
$data = new RemoveEntityPacket;
break;
case ProtocolInfo::ADD_ITEM_ENTITY_PACKET:
$data = new AddItemEntityPacket;
break;
case ProtocolInfo::TAKE_ITEM_ENTITY_PACKET:
$data = new TakeItemEntityPacket;
break;
case ProtocolInfo::MOVE_ENTITY_PACKET:
$data = new MoveEntityPacket;
break;
case ProtocolInfo::MOVE_ENTITY_PACKET_POSROT:
$data = new MoveEntityPacket_PosRot;
break;
case ProtocolInfo::ROTATE_HEAD_PACKET:
$data = new RotateHeadPacket;
break;
case ProtocolInfo::MOVE_PLAYER_PACKET:
$data = new MovePlayerPacket;
break;
case ProtocolInfo::REMOVE_BLOCK_PACKET:
$data = new RemoveBlockPacket;
break;
case ProtocolInfo::UPDATE_BLOCK_PACKET:
$data = new UpdateBlockPacket;
break;
case ProtocolInfo::ADD_PAINTING_PACKET:
$data = new AddPaintingPacket;
break;
case ProtocolInfo::EXPLODE_PACKET:
$data = new ExplodePacket;
break;
case ProtocolInfo::LEVEL_EVENT_PACKET:
$data = new LevelEventPacket;
break;
case ProtocolInfo::TILE_EVENT_PACKET:
$data = new TileEventPacket;
break;
case ProtocolInfo::ENTITY_EVENT_PACKET:
$data = new EntityEventPacket;
break;
case ProtocolInfo::REQUEST_CHUNK_PACKET:
$data = new RequestChunkPacket;
break;
case ProtocolInfo::CHUNK_DATA_PACKET:
$data = new ChunkDataPacket;
break;
case ProtocolInfo::PLAYER_EQUIPMENT_PACKET:
$data = new PlayerEquipmentPacket;
break;
case ProtocolInfo::PLAYER_ARMOR_EQUIPMENT_PACKET:
$data = new PlayerArmorEquipmentPacket;
break;
case ProtocolInfo::INTERACT_PACKET:
$data = new InteractPacket;
break;
case ProtocolInfo::USE_ITEM_PACKET:
$data = new UseItemPacket;
break;
case ProtocolInfo::PLAYER_ACTION_PACKET:
$data = new PlayerActionPacket;
break;
case ProtocolInfo::HURT_ARMOR_PACKET:
$data = new HurtArmorPacket;
break;
case ProtocolInfo::SET_ENTITY_DATA_PACKET:
$data = new SetEntityDataPacket;
break;
case ProtocolInfo::SET_ENTITY_MOTION_PACKET:
$data = new SetEntityMotionPacket;
break;
case ProtocolInfo::SET_HEALTH_PACKET:
$data = new SetHealthPacket;
break;
case ProtocolInfo::SET_SPAWN_POSITION_PACKET:
$data = new SetSpawnPositionPacket;
break;
case ProtocolInfo::ANIMATE_PACKET:
$data = new AnimatePacket;
break;
case ProtocolInfo::RESPAWN_PACKET:
$data = new RespawnPacket;
break;
case ProtocolInfo::SEND_INVENTORY_PACKET:
$data = new SendInventoryPacket;
break;
case ProtocolInfo::DROP_ITEM_PACKET:
$data = new DropItemPacket;
break;
case ProtocolInfo::CONTAINER_OPEN_PACKET:
$data = new ContainerOpenPacket;
break;
case ProtocolInfo::CONTAINER_CLOSE_PACKET:
$data = new ContainerClosePacket;
break;
case ProtocolInfo::CONTAINER_SET_SLOT_PACKET:
$data = new ContainerSetSlotPacket;
break;
case ProtocolInfo::CONTAINER_SET_DATA_PACKET:
$data = new ContainerSetDataPacket;
break;
case ProtocolInfo::CONTAINER_SET_CONTENT_PACKET:
$data = new ContainerSetContentPacket;
break;
case ProtocolInfo::CHAT_PACKET:
$data = new ChatPacket;
break;
case ProtocolInfo::ADVENTURE_SETTINGS_PACKET:
$data = new AdventureSettingsPacket;
break;
case ProtocolInfo::ENTITY_DATA_PACKET:
$data = new EntityDataPacket;
break;
default:
$data = new UnknownPacket();
$data->packetID = $pid;
break;
} }
$data->reliability = $reliability; $data->reliability = $reliability;
$data->hasSplit = $hasSplit; $data->hasSplit = $hasSplit;

View File

@ -19,16 +19,17 @@
* *
*/ */
define("PMF_CURRENT_LEVEL_VERSION", 0x00);
class PMFLevel extends PMF{ class PMFLevel extends PMF{
private $levelData = array(); const VERSION = 0x01;
private $locationTable = array(); const DEFLATE_LEVEL = 9;
public $level;
public $levelData = array();
public $isLoaded = true; public $isLoaded = true;
private $log = 4;
private $payloadOffset = 0;
private $chunks = array(); private $chunks = array();
private $chunkChange = array(); private $chunkChange = array();
private $chunkInfo = array();
public $isGenerating = 0;
public function getData($index){ public function getData($index){
if(!isset($this->levelData[$index])){ if(!isset($this->levelData[$index])){
@ -45,19 +46,21 @@ class PMFLevel extends PMF{
return true; return true;
} }
public function close(){ public function closeLevel(){
$chunks = null; $this->chunks = null;
unset($chunks, $chunkChange, $locationTable); 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;
$this->createBlank(); $this->createBlank();
$this->isLoaded = true; $this->isLoaded = true;
$this->log = (int) ((string) log($this->levelData["width"], 2));
}else{ }else{
if($this->load($file) !== false){ if($this->load($file) !== false){
$this->parseInfo(); $this->parseInfo();
@ -65,7 +68,6 @@ class PMFLevel extends PMF{
$this->isLoaded = false; $this->isLoaded = false;
}else{ }else{
$this->isLoaded = true; $this->isLoaded = true;
$this->log = (int) ((string) log($this->levelData["width"], 2));
} }
}else{ }else{
$this->isLoaded = false; $this->isLoaded = false;
@ -73,8 +75,8 @@ class PMFLevel extends PMF{
} }
} }
public function saveData($locationTable = true){ public function saveData(){
$this->levelData["version"] = PMF_CURRENT_LEVEL_VERSION; $this->levelData["version"] = PMFLevel::VERSION;
@ftruncate($this->fp, 5); @ftruncate($this->fp, 5);
$this->seek(5); $this->seek(5);
$this->write(chr($this->levelData["version"])); $this->write(chr($this->levelData["version"]));
@ -84,33 +86,17 @@ class PMFLevel extends PMF{
$this->write(Utils::writeFloat($this->levelData["spawnX"])); $this->write(Utils::writeFloat($this->levelData["spawnX"]));
$this->write(Utils::writeFloat($this->levelData["spawnY"])); $this->write(Utils::writeFloat($this->levelData["spawnY"]));
$this->write(Utils::writeFloat($this->levelData["spawnZ"])); $this->write(Utils::writeFloat($this->levelData["spawnZ"]));
$this->write(chr($this->levelData["width"]));
$this->write(chr($this->levelData["height"])); $this->write(chr($this->levelData["height"]));
$extra = gzdeflate($this->levelData["extra"], PMF_LEVEL_DEFLATE_LEVEL); $this->write(Utils::writeShort(strlen($this->levelData["generator"])).$this->levelData["generator"]);
$settings = serialize($this->levelData["generatorSettings"]);
$this->write(Utils::writeShort(strlen($settings)).$settings);
$extra = gzdeflate($this->levelData["extra"], PMFLevel::DEFLATE_LEVEL);
$this->write(Utils::writeShort(strlen($extra)).$extra); $this->write(Utils::writeShort(strlen($extra)).$extra);
$this->payloadOffset = ftell($this->fp);
if($locationTable !== false){
$this->writeLocationTable();
}
} }
private function createBlank(){ private function createBlank(){
$this->saveData(false); $this->saveData();
$this->locationTable = array();
$cnt = pow($this->levelData["width"], 2);
@mkdir(dirname($this->file)."/chunks/", 0755); @mkdir(dirname($this->file)."/chunks/", 0755);
for($index = 0; $index < $cnt; ++$index){
$this->chunks[$index] = false;
$this->chunkChange[$index] = false;
$this->locationTable[$index] = array(
0 => 0,
);
$this->write(Utils::writeShort(0));
$X = $Z = null;
$this->getXZ($index, $X, $Z);
@file_put_contents($this->getChunkPath($X, $Z), gzdeflate("", PMF_LEVEL_DEFLATE_LEVEL));
}
if(!file_exists(dirname($this->file)."/entities.yml")){ if(!file_exists(dirname($this->file)."/entities.yml")){
$entities = new Config(dirname($this->file)."/entities.yml", CONFIG_YAML); $entities = new Config(dirname($this->file)."/entities.yml", CONFIG_YAML);
$entities->save(); $entities->save();
@ -127,7 +113,8 @@ class PMFLevel extends PMF{
} }
$this->seek(5); $this->seek(5);
$this->levelData["version"] = ord($this->read(1)); $this->levelData["version"] = ord($this->read(1));
if($this->levelData["version"] > PMF_CURRENT_LEVEL_VERSION){ if($this->levelData["version"] > PMFLevel::VERSION){
console("[ERROR] New unsupported PMF Level format version #".$this->levelData["version"].", current version is #".PMFLevel::VERSION);
return false; return false;
} }
$this->levelData["name"] = $this->read(Utils::readShort($this->read(2), false)); $this->levelData["name"] = $this->read(Utils::readShort($this->read(2), false));
@ -136,93 +123,136 @@ class PMFLevel extends PMF{
$this->levelData["spawnX"] = Utils::readFloat($this->read(4)); $this->levelData["spawnX"] = Utils::readFloat($this->read(4));
$this->levelData["spawnY"] = Utils::readFloat($this->read(4)); $this->levelData["spawnY"] = Utils::readFloat($this->read(4));
$this->levelData["spawnZ"] = Utils::readFloat($this->read(4)); $this->levelData["spawnZ"] = Utils::readFloat($this->read(4));
$this->levelData["width"] = ord($this->read(1)); if($this->levelData["version"] === 0){
$this->levelData["height"] = ord($this->read(1)); $this->read(1);
if(($this->levelData["width"] !== 16 and $this->levelData["width"] !== 32) or $this->levelData["height"] !== 8){ $this->levelData["height"] = ord($this->read(1));
return false;
}
$lastseek = ftell($this->fp);
if(($len = $this->read(2)) === false or ($this->levelData["extra"] = @gzinflate($this->read(Utils::readShort($len, false)))) === false){ //Corruption protection
console("[NOTICE] Empty/corrupt location table detected, forcing recovery");
fseek($this->fp, $lastseek);
$c = gzdeflate("");
$this->write(Utils::writeShort(strlen($c)).$c);
$this->payloadOffset = ftell($this->fp);
$this->levelData["extra"] = "";
$cnt = pow($this->levelData["width"], 2);
for($index = 0; $index < $cnt; ++$index){
$this->write("\x00\xFF"); //Force index recreation
}
fseek($this->fp, $this->payloadOffset);
}else{ }else{
$this->payloadOffset = ftell($this->fp); $this->levelData["height"] = ord($this->read(1));
if($this->levelData["height"] !== 8){
return false;
}
$this->levelData["generator"] = $this->read(Utils::readShort($this->read(2), false));
$this->levelData["generatorSettings"] = unserialize($this->read(Utils::readShort($this->read(2), false)));
}
$this->levelData["extra"] = @gzinflate($this->read(Utils::readShort($this->read(2), false)));
if($this->levelData["version"] === 0){
$this->upgrade_From0_To1();
} }
return $this->readLocationTable();
} }
public function getIndex($X, $Z){ private function upgrade_From0_To1(){
$X = (int) $X; console("[NOTICE] Old PMF Level format version #0 detected, upgrading to version #1");
$Z = (int) $Z; for($index = 0; $index < 256; ++$index){
return ($Z << $this->log) + $X; $X = $index & 0x0F;
$Z = $index >> 4;
$bitflags = Utils::readShort($this->read(2));
$oldPath = dirname($this->file)."/chunks/".$Z.".".$X.".pmc";
$chunkOld = gzopen($oldPath, "rb");
$newPath = dirname($this->file)."/chunks/".(($X ^ $Z) & 0xff)."/".$Z.".".$X.".pmc";
@mkdir(dirname($newPath));
$chunkNew = gzopen($newPath, "wb".PMFLevel::DEFLATE_LEVEL);
gzwrite($chunkNew, chr($bitflags) . "\x00\x00\x00\x01");
while(gzeof($chunkOld) === false){
gzwrite($chunkNew, gzread($chunkOld, 65535));
}
gzclose($chunkNew);
gzclose($chunkOld);
@unlink($oldPath);
}
$this->levelData["version"] = 0x01;
$this->levelData["generator"] = "NormalGenerator";
$this->levelData["generatorSettings"] = "";
$this->saveData();
} }
public function getXZ($index, &$X = null, &$Z = null){ public static function getIndex($X, $Z){
$X = $index >> $this->log; return ($Z << 16) | ($X < 0 ? (~--$X & 0x7fff) | 0x8000 : $X & 0x7fff);
$Z = $index & (pow($this->log, 2) - 1); }
public static function getXZ($index, &$X = null, &$Z = null){
$Z = $index >> 16;
$X = ($index & 0x8000) === 0x8000 ? -($index & 0x7fff) : $index & 0x7fff;
return array($X, $Z); return array($X, $Z);
} }
private function readLocationTable(){
$this->locationTable = array();
$cnt = pow($this->levelData["width"], 2);
$this->seek($this->payloadOffset);
for($index = 0; $index < $cnt; ++$index){
$this->chunks[$index] = false;
$this->chunkChange[$index] = false;
$this->locationTable[$index] = array(
0 => Utils::readShort($this->read(2)), //16 bit flags
);
}
return true;
}
private function writeLocationTable(){
$cnt = pow($this->levelData["width"], 2);
@ftruncate($this->fp, $this->payloadOffset);
$this->seek($this->payloadOffset);
for($index = 0; $index < $cnt; ++$index){
$this->write(Utils::writeShort($this->locationTable[$index][0]));
}
}
private function getChunkPath($X, $Z){ private function getChunkPath($X, $Z){
return dirname($this->file)."/chunks/".$Z.".".$X.".pmc"; return dirname($this->file)."/chunks/".(((int) $X ^ (int) $Z) & 0xff)."/".$Z.".".$X.".pmc";
}
public function generateChunk($X, $Z){
$path = $this->getChunkPath($X, $Z);
if(!file_exists(dirname($path))){
@mkdir(dirname($path), 0755);
}
$this->initCleanChunk($X, $Z);
if($this->level instanceof Level){
$ret = $this->level->generateChunk($X, $Z);
$this->saveChunk($X, $Z);
$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;
}
}
public function populateChunk($X, $Z){
if($this->level instanceof Level){
if($this->isGenerating === 0 and
$this->isChunkLoaded($X, $Z) 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;
$Z = (int) $Z;
$index = $this->getIndex($X, $Z);
if($this->isChunkLoaded($X, $Z)){ if($this->isChunkLoaded($X, $Z)){
return true; return true;
}elseif(!isset($this->locationTable[$index])){
return false;
} }
$info = $this->locationTable[$index]; $index = self::getIndex($X, $Z);
$this->seek($info[0]); $path = $this->getChunkPath($X, $Z);
if(!file_exists($path)){
if($this->generateChunk($X, $Z) === false){
return false;
}
if($this->isGenerating === 0){
$this->populateChunk($X, $Z);
}
return true;
}
$chunk = @gzopen($this->getChunkPath($X, $Z), "rb"); $chunk = @gzopen($path, "rb");
if($chunk === false){ if($chunk === false){
return false; return false;
} }
$this->chunkInfo[$index] = array(
0 => ord(gzread($chunk, 1)),
1 => Utils::readInt(gzread($chunk, 4)),
);
$this->chunks[$index] = array(); $this->chunks[$index] = array();
$this->chunkChange[$index] = array(-1 => false); $this->chunkChange[$index] = array(-1 => false);
for($Y = 0; $Y < $this->levelData["height"]; ++$Y){ for($Y = 0; $Y < 8; ++$Y){
$t = 1 << $Y; if(($this->chunkInfo[$index][0] & (1 << $Y)) !== 0){
if(($info[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{
@ -230,6 +260,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;
} }
@ -241,24 +274,25 @@ class PMFLevel extends PMF{
}elseif($save !== false){ }elseif($save !== false){
$this->saveChunk($X, $Z); $this->saveChunk($X, $Z);
} }
$index = $this->getIndex($X, $Z); $index = self::getIndex($X, $Z);
$this->chunks[$index] = null; $this->chunks[$index] = null;
$this->chunkChange[$index] = null; $this->chunkChange[$index] = null;
unset($this->chunks[$index], $this->chunkChange[$index]); $this->chunkInfo[$index] = null;
unset($this->chunks[$index], $this->chunkChange[$index], $this->chunkInfo[$index]);
return true; return true;
} }
public function isChunkLoaded($X, $Z){ public function isChunkLoaded($X, $Z){
$index = $this->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 = $this->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;
} }
@ -270,48 +304,84 @@ class PMFLevel extends PMF{
if($this->isChunkLoaded($X, $Z) === false){ if($this->isChunkLoaded($X, $Z) === false){
return false; return false;
} }
$index = $this->getIndex($X, $Z); $index = self::getIndex($X, $Z);
$this->chunks[$index][$Y] = str_repeat("\x00", 8192); $this->chunks[$index][$Y] = str_repeat("\x00", 8192);
$this->chunkChange[$index][-1] = true; $this->chunkChange[$index][-1] = true;
$this->chunkChange[$index][$Y] = 8192; $this->chunkChange[$index][$Y] = 8192;
$this->locationTable[$index][0] |= 1 << $Y; $this->chunkInfo[$index][0] |= 1 << $Y;
return true; return true;
} }
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 = $this->getIndex($X, $Z); $index = self::getIndex($X, $Z);
if(!isset($this->chunks[$index][$Y]) or $this->chunks[$index][$Y] === false){ if(!isset($this->chunks[$index][$Y]) or $this->chunks[$index][$Y] === false){
return str_repeat("\x00", 8192); return str_repeat("\x00", 8192);
} }
return $this->chunks[$index][$Y]; return $this->chunks[$index][$Y];
} }
public function initCleanChunk($X, $Z){
$index = self::getIndex($X, $Z);
if(!isset($this->chunks[$index])){
$this->chunks[$index] = array(
0 => false,
1 => false,
2 => false,
3 => false,
4 => false,
5 => false,
6 => false,
7 => 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(
0 => 0,
1 => 0,
);
}
}
public function setMiniChunk($X, $Z, $Y, $data){ public function setMiniChunk($X, $Z, $Y, $data){
if($this->isChunkLoaded($X, $Z) === false){ if($this->isGenerating > 0){
$this->initCleanChunk($X, $Z);
}elseif($this->isChunkLoaded($X, $Z) === false){
$this->loadChunk($X, $Z); $this->loadChunk($X, $Z);
} }
if(strlen($data) !== 8192){ if(strlen($data) !== 8192){
return false; return false;
} }
$index = $this->getIndex($X, $Z); $index = self::getIndex($X, $Z);
$this->chunks[$index][$Y] = (string) $data; $this->chunks[$index][$Y] = (string) $data;
$this->chunkChange[$index][-1] = true; $this->chunkChange[$index][-1] = true;
$this->chunkChange[$index][$Y] = 8192; $this->chunkChange[$index][$Y] = 8192;
$this->locationTable[$index][0] |= 1 << $Y; $this->chunkInfo[$index][0] |= 1 << $Y;
return true; return true;
} }
public function getBlockID($x, $y, $z){ public function getBlockID($x, $y, $z){
if($y > 127 or $y < 0 or $x < 0 or $z < 0 or $x > 255 or $z > 255){ if($y > 127 or $y < 0){
return 0; return 0;
} }
$X = $x >> 4; $X = $x >> 4;
$Z = $z >> 4; $Z = $z >> 4;
$Y = $y >> 4; $Y = $y >> 4;
$index = $this->getIndex($X, $Z); $index = self::getIndex($X, $Z);
if(!isset($this->chunks[$index])){
return 0;
}
$aX = $x - ($X << 4); $aX = $x - ($X << 4);
$aZ = $z - ($Z << 4); $aZ = $z - ($Z << 4);
$aY = $y - ($Y << 4); $aY = $y - ($Y << 4);
@ -320,17 +390,17 @@ class PMFLevel extends PMF{
} }
public function setBlockID($x, $y, $z, $block){ public function setBlockID($x, $y, $z, $block){
if($y > 127 or $y < 0 or $x < 0 or $z < 0 or $x > 255 or $z > 255){ if($y > 127 or $y < 0){
return false; return false;
} }
$X = $x >> 4; $X = $x >> 4;
$Z = $z >> 4; $Z = $z >> 4;
$Y = $y >> 4; $Y = $y >> 4;
$block &= 0xFF; $block &= 0xFF;
if($X >= 32 or $Z >= 32 or $Y >= $this->levelData["height"] or $y < 0){ $index = self::getIndex($X, $Z);
if(!isset($this->chunks[$index])){
return false; return false;
} }
$index = $this->getIndex($X, $Z);
$aX = $x - ($X << 4); $aX = $x - ($X << 4);
$aZ = $z - ($Z << 4); $aZ = $z - ($Z << 4);
$aY = $y - ($Y << 4); $aY = $y - ($Y << 4);
@ -345,13 +415,16 @@ class PMFLevel extends PMF{
} }
public function getBlockDamage($x, $y, $z){ public function getBlockDamage($x, $y, $z){
if($y > 127 or $y < 0 or $x < 0 or $z < 0 or $x > 255 or $z > 255){ if($y > 127 or $y < 0){
return 0; return 0;
} }
$X = $x >> 4; $X = $x >> 4;
$Z = $z >> 4; $Z = $z >> 4;
$Y = $y >> 4; $Y = $y >> 4;
$index = $this->getIndex($X, $Z); $index = self::getIndex($X, $Z);
if(!isset($this->chunks[$index])){
return 0;
}
$aX = $x - ($X << 4); $aX = $x - ($X << 4);
$aZ = $z - ($Z << 4); $aZ = $z - ($Z << 4);
$aY = $y - ($Y << 4); $aY = $y - ($Y << 4);
@ -365,17 +438,17 @@ class PMFLevel extends PMF{
} }
public function setBlockDamage($x, $y, $z, $damage){ public function setBlockDamage($x, $y, $z, $damage){
if($y > 127 or $y < 0 or $x < 0 or $z < 0 or $x > 255 or $z > 255){ if($y > 127 or $y < 0){
return false; return false;
} }
$X = $x >> 4; $X = $x >> 4;
$Z = $z >> 4; $Z = $z >> 4;
$Y = $y >> 4; $Y = $y >> 4;
$damage &= 0x0F; $damage &= 0x0F;
if($X >= 32 or $Z >= 32 or $Y >= $this->levelData["height"] or $y < 0){ $index = self::getIndex($X, $Z);
if(!isset($this->chunks[$index])){
return false; return false;
} }
$index = $this->getIndex($X, $Z);
$aX = $x - ($X << 4); $aX = $x - ($X << 4);
$aZ = $z - ($Z << 4); $aZ = $z - ($Z << 4);
$aY = $y - ($Y << 4); $aY = $y - ($Y << 4);
@ -404,14 +477,12 @@ class PMFLevel extends PMF{
$X = $x >> 4; $X = $x >> 4;
$Z = $z >> 4; $Z = $z >> 4;
$Y = $y >> 4; $Y = $y >> 4;
if($x < 0 or $z < 0 or $X >= $this->levelData["width"] or $Z >= $this->levelData["width"] or $Y >= $this->levelData["height"] or $y < 0){ if($y < 0 or $y > 127){
return array(AIR, 0); return array(AIR, 0);
} }
$index = $this->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);
} }
@ -429,19 +500,17 @@ class PMFLevel extends PMF{
} }
public function setBlock($x, $y, $z, $block, $meta = 0){ public function setBlock($x, $y, $z, $block, $meta = 0){
if($y > 127 or $y < 0){
return false;
}
$X = $x >> 4; $X = $x >> 4;
$Z = $z >> 4; $Z = $z >> 4;
$Y = $y >> 4; $Y = $y >> 4;
$block &= 0xFF; $block &= 0xFF;
$meta &= 0x0F; $meta &= 0x0F;
if($X >= 32 or $Z >= 32 or $Y >= $this->levelData["height"] or $y < 0){ $index = self::getIndex($X, $Z);
if(!isset($this->chunks[$index]) and $this->loadChunk($X, $Z) === false){
return false; return false;
}
$index = $this->getIndex($X, $Z);
if(!isset($this->chunks[$index]) or $this->chunks[$index] === false){
if($this->loadChunk($X, $Z) === 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);
} }
@ -467,17 +536,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;
@ -489,32 +547,70 @@ class PMFLevel extends PMF{
if(!$this->isChunkLoaded($X, $Z)){ if(!$this->isChunkLoaded($X, $Z)){
return false; return false;
} }
$index = $this->getIndex($X, $Z); $index = self::getIndex($X, $Z);
if(!isset($this->chunkChange[$index]) or $this->chunkChange[$index][-1] === false){//No changes in chunk if(!isset($this->chunkChange[$index]) or $this->chunkChange[$index][-1] === false){//No changes in chunk
return true; return true;
} }
$chunk = @gzopen($this->getChunkPath($X, $Z), "wb".PMF_LEVEL_DEFLATE_LEVEL); $path = $this->getChunkPath($X, $Z);
if(!file_exists(dirname($path))){
@mkdir(dirname($path), 0755);
}
$bitmap = 0; $bitmap = 0;
for($Y = 0; $Y < $this->levelData["height"]; ++$Y){ for($Y = 0; $Y < 8; ++$Y){
if($this->chunks[$index][$Y] !== false and ((isset($this->chunkChange[$index][$Y]) and $this->chunkChange[$index][$Y] === 0) or !$this->isMiniChunkEmpty($X, $Z, $Y))){ if($this->chunks[$index][$Y] !== false and ((isset($this->chunkChange[$index][$Y]) and $this->chunkChange[$index][$Y] === 0) or !$this->isMiniChunkEmpty($X, $Z, $Y))){
gzwrite($chunk, $this->chunks[$index][$Y]);
$bitmap |= 1 << $Y; $bitmap |= 1 << $Y;
}else{ }else{
$this->chunks[$index][$Y] = false; $this->chunks[$index][$Y] = false;
} }
$this->chunkChange[$index][$Y] = 0; $this->chunkChange[$index][$Y] = 0;
} }
$chunk = @gzopen($path, "wb".PMFLevel::DEFLATE_LEVEL);
gzwrite($chunk, chr($bitmap));
gzwrite($chunk, Utils::writeInt($this->chunkInfo[$index][1]));
for($Y = 0; $Y < 8; ++$Y){
$t = 1 << $Y;
if(($bitmap & $t) === $t){
gzwrite($chunk, $this->chunks[$index][$Y]);
}
}
gzclose($chunk);
$this->chunkChange[$index][-1] = false; $this->chunkChange[$index][-1] = false;
$this->locationTable[$index][0] = $bitmap; $this->chunkInfo[$index][0] = $bitmap;
$this->seek($this->payloadOffset + ($index << 1));
$this->write(Utils::writeShort($this->locationTable[$index][0]));
return true; return true;
} }
public function setPopulated($X, $Z){
if(!$this->isChunkLoaded($X, $Z)){
return false;
}
$index = self::getIndex($X, $Z);
$this->chunkInfo[$index][1] |= 0b00000000000000000000000000000001;
}
public function unsetPopulated($X, $Z){
if(!$this->isChunkLoaded($X, $Z)){
return false;
}
$index = self::getIndex($X, $Z);
$this->chunkInfo[$index][1] &= ~0b00000000000000000000000000000001;
}
public function isPopulated($X, $Z){
if(!$this->isChunkLoaded($X, $Z)){
return false;
}
$index = self::getIndex($X, $Z);
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){
$this->getXZ($index, $X, $Z); self::getXZ($index, $X, $Z);
$this->saveChunk($X, $Z); $this->saveChunk($X, $Z);
} }
} }

View File

@ -12,7 +12,7 @@
} }
} }
if(!class_exists("PocketMinecraftServer", false)){ if(!class_exists("MainServer", false)){
define("NO_THREADS", true); define("NO_THREADS", true);
require_once(dirname(__FILE__)."/../dependencies.php"); require_once(dirname(__FILE__)."/../dependencies.php");
require_once(FILE_PATH."/src/functions.php"); require_once(FILE_PATH."/src/functions.php");

View File

@ -76,7 +76,6 @@ class Config{
*/ */
public function __construct($file, $type = CONFIG_DETECT, $default = array(), &$correct = null){ public function __construct($file, $type = CONFIG_DETECT, $default = array(), &$correct = null){
$this->load($file, $type, $default); $this->load($file, $type, $default);
$correct = $this->check();
} }
public function reload(){ public function reload(){
@ -84,7 +83,6 @@ class Config{
unset($this->correct); unset($this->correct);
unset($this->type); unset($this->type);
$this->load($this->file); $this->load($this->file);
$correct = $this->check();
} }
public function fixYAMLIndexes($str){ public function fixYAMLIndexes($str){
@ -141,7 +139,6 @@ class Config{
default: default:
$this->correct = false; $this->correct = false;
return false; return false;
break;
} }
if(!is_array($this->config)){ if(!is_array($this->config)){
$this->config = $default; $this->config = $default;

View File

@ -1,209 +0,0 @@
<?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 NBT{
public $tree = array();
public $binary = b"";
private $offset = 0;
const TAG_END = 0;
const TAG_BYTE = 1;
const TAG_SHORT = 2;
const TAG_INT = 3;
const TAG_LONG = 4;
const TAG_FLOAT = 5;
const TAG_DOUBLE = 6;
const TAG_BYTE_ARRAY = 7;
const TAG_STRING = 8;
const TAG_LIST = 9;
const TAG_COMPOUND = 10;
public function read($n){
if($n <= 0){
return "";
}
$this->offset += $n;
return substr($this->binary, $this->offset - $n, $n);
}
public function write($bin){
$this->binary .= $bin;
}
public function load($str){
$this->offset = 0;
$this->binary = (string) $str;
$this->parseTree($this->tree);
}
public function readTAG_BYTE(){
return Utils::readByte($this->read(1));
}
public function readTAG_SHORT(){
return Utils::readLShort($this->read(2));
}
public function readTAG_INT(){
return Utils::readLInt($this->read(4));
}
public function readTAG_LONG(){
return Utils::readLLong($this->read(8));
}
public function readTAG_FLOAT(){
return Utils::readLFloat($this->read(4));
}
public function readTAG_DOUBLE(){
return Utils::readLDouble($this->read(8));
}
public function readTAG_BYTE_ARRAY(){
return $this->read($this->readTAG_INT());
}
public function readTAG_STRING(){
return $this->read(Utils::readLShort($this->read(2), false));
}
public function writeTAG_BYTE($v){
$this->binary .= chr($v);
}
public function writeTAG_SHORT($v){
$this->binary .= Utils::writeLShort($v);
}
public function writeTAG_INT($v){
$this->binary .= Utils::writeLInt($v);
}
public function writeTAG_LONG($v){
$this->binary .= Utils::writeLLong($v);
}
public function writeTAG_FLOAT($v){
$this->binary .= Utils::writeLFloar($v);
}
public function writeTAG_DOUBLE($v){
$this->binary .= Utils::writeLDouble($v);
}
public function writeTAG_BYTE_ARRAY($v){
$this->binary .= $this->writeTAG_INT(strlen($v)).$v;
}
public function writeTAG_STRING($v){
$this->binary .= $this->writeTAG_SHORT(strlen($v)).$v;
}
private function parseList(&$node, $tag, $cnt){
for($i = 0; $i < $cnt; ++$i){
switch($tag){
case self::TAG_BYTE:
$value = $this->readTAG_BYTE();
break;
case self::TAG_SHORT:
$value = $this->readTAG_SHORT();
break;
case self::TAG_INT:
$value = $this->readTAG_INT();
break;
case self::TAG_LONG:
$value = $this->readTAG_LONG();
break;
case self::TAG_FLOAT:
$value = $this->readTAG_FLOAT();
break;
case self::TAG_DOUBLE:
$value = $this->readTAG_DOUBLE();
break;
case self::TAG_BYTE_ARRAY:
$value = $this->readTAG_BYTE_ARRAY();
break;
case self::TAG_STRING:
$value = $this->readTAG_STRING();
break;
case self::TAG_LIST:
$value = array();
$this->parseList($value, ord($this->read(1)), Utils::readLInt($this->read(4)));
break;
case self::TAG_COMPOUND:
$value = array();
$this->parseTree($value);
break;
default:
echo bin2hex(substr($this->binary, $this->offset - 1)).PHP_EOL.PHP_EOL;
die("Invalid NBT Tag $tag");
break;
}
$node[] = $value;
}
}
private function parseTree(&$node){
while(($tag = ord($this->read(1))) !== self::TAG_END){
$name = $this->readTAG_STRING();
switch($tag){
case self::TAG_BYTE:
$value = $this->readTAG_BYTE();
break;
case self::TAG_SHORT:
$value = $this->readTAG_SHORT();
break;
case self::TAG_INT:
$value = $this->readTAG_INT();
break;
case self::TAG_LONG:
$value = $this->readTAG_LONG();
break;
case self::TAG_FLOAT:
$value = $this->readTAG_FLOAT();
break;
case self::TAG_DOUBLE:
$value = $this->readTAG_DOUBLE();
break;
case self::TAG_BYTE_ARRAY:
$value = $this->readTAG_BYTE_ARRAY();
break;
case self::TAG_STRING:
$value = $this->readTAG_STRING();
break;
case self::TAG_LIST:
$value = array();
$this->parseList($value, ord($this->read(1)), Utils::readLInt($this->read(4)));
break;
case self::TAG_COMPOUND:
$value = array();
$this->parseTree($value);
break;
default:
echo bin2hex(substr($this->binary, $this->offset - 1)).PHP_EOL.PHP_EOL;
die("Invalid NBT Tag $tag");
break;
}
$node[$name] = $value;
}
}
}

View File

@ -22,50 +22,45 @@
//Unsecure, not used for "Real Randomness" //Unsecure, not used for "Real Randomness"
class Random{ class Random{
private $x, $y, $z, $w; private $z, $w;
public function __construct($seed = false){ public function __construct($seed = false){
$this->setSeed($seed); $this->setSeed($seed);
} }
public function setSeed($seed = false){ public function setSeed($seed = false){
$seed = $seed !== false ? Utils::writeInt((int) $seed):Utils::getRandomBytes(4, false); $seed = $seed !== false ? (int) $seed:Utils::readInt(Utils::getRandomBytes(4, false));
$state = array(); $this->z = $seed ^ 0xdeadbeef;
for($i = 0; $i < 256; ++$i){ $this->w = $seed ^ 0xc0de1337;
$state[] = $i;
}
for($i = $j = 0; $i < 256; ++$i){
$j = ($j + ord($seed{$i & 0x03}) + $state[$i]) & 0xFF;
$state[$i] ^= $state[$j];
$state[$j] ^= $state[$i];
$state[$i] ^= $state[$j];
}
$this->state = $state;
$this->i = $this->j = 0;
} }
public function nextInt(){ public function nextInt(){
return Utils::readInt($this->nextBytes(4)) & 0x7FFFFFFF; return Utils::readInt($this->nextBytes(4)) & 0x7FFFFFFF;
} }
public function nextSignedInt(){
return Utils::readInt($this->nextBytes(4));
}
public function nextFloat(){ public function nextFloat(){
return $this->nextInt() / 0x7FFFFFFF; return $this->nextInt() / 0x7FFFFFFF;
} }
public function nextSignedFloat(){
return $this->nextSignedInt() / 0x7FFFFFFF;
}
public function nextBytes($byteCount){ public function nextBytes($byteCount){
$bytes = ""; $bytes = "";
for($i = 0; $i < $byteCount; ++$i){ while(strlen($bytes) < $byteCount){
$this->i = ($this->i + 1) & 0xFF; $this->z = 36969 * ($this->z & 65535) + ($this->z >> 16);
$this->j = ($this->j + $this->state[$this->i]) & 0xFF; $this->w = 18000 * ($this->w & 65535) + ($this->w >> 16);
$this->state[$this->i] ^= $this->state[$this->j]; $bytes .= pack("N", ($this->z << 16) + $this->w);
$this->state[$this->j] ^= $this->state[$this->i];
$this->state[$this->i] ^= $this->state[$this->j];
$bytes .= chr($this->state[($this->state[$this->i] + $this->state[$this->j]) & 0xFF]);
} }
return $bytes; return substr($bytes, 0, $byteCount);
} }
public function nextBoolean(){ public function nextBoolean(){
return ($this->nextBytes(1) & 0x01) == 0; return ($this->nextSignedInt() & 0x01) === 0;
} }
public function nextRange($start = 0, $end = PHP_INT_MAX){ public function nextRange($start = 0, $end = PHP_INT_MAX){

View File

@ -31,6 +31,14 @@ class Utils{
return ((@fsockopen("8.8.8.8", 80, $e = null, $n = null, 2) !== false or @fsockopen("www.linux.org", 80, $e = null, $n = null, 2) !== false or @fsockopen("www.php.net", 80, $e = null, $n = null, 2) !== false) ? true:false); return ((@fsockopen("8.8.8.8", 80, $e = null, $n = null, 2) !== false or @fsockopen("www.linux.org", 80, $e = null, $n = null, 2) !== false or @fsockopen("www.php.net", 80, $e = null, $n = null, 2) !== false) ? true:false);
} }
public static function getCallableIdentifier(callable $variable){
if(is_array($variable)){
return sha1(strtolower(get_class($variable[0]))."::".strtolower($variable[1]));
}else{
return sha1(strtolower($variable));
}
}
public static function getUniqueID($raw = false, $extra = ""){ public static function getUniqueID($raw = false, $extra = ""){
$machine = php_uname("a"); $machine = php_uname("a");
$machine .= file_exists("/proc/cpuinfo") ? file_get_contents("/proc/cpuinfo") : ""; $machine .= file_exists("/proc/cpuinfo") ? file_get_contents("/proc/cpuinfo") : "";
@ -612,7 +620,7 @@ class Utils{
} }
public static function writeLLong($value){ public static function writeLLong($value){
return strrev(Utils::writeLong($str)); return strrev(Utils::writeLong($value));
} }

View File

@ -33,6 +33,7 @@ class VersionString{
private $release; private $release;
private $minor; private $minor;
private $development = false; private $development = false;
private $generation;
public function __construct($version = MAJOR_VERSION){ public function __construct($version = MAJOR_VERSION){
if(is_int($version)){ if(is_int($version)){
$this->minor = $version & 0x1F; $this->minor = $version & 0x1F;

View File

@ -21,6 +21,7 @@
define("ASYNC_CURL_GET", 1); define("ASYNC_CURL_GET", 1);
define("ASYNC_CURL_POST", 2); define("ASYNC_CURL_POST", 2);
define("ASYNC_FUNCTION", 3);
class StackableArray extends Stackable{ class StackableArray extends Stackable{
public function __construct(){ public function __construct(){
@ -87,13 +88,19 @@ class AsyncMultipleQueue extends Thread{
$d = array(); $d = array();
for($c = 0; $c < $cnt; ++$c){ for($c = 0; $c < $cnt; ++$c){
$key = $this->get(Utils::readShort($this->get(2), false)); $key = $this->get(Utils::readShort($this->get(2), false));
$d[$key] = $this->get(Utils::readInt($this->get(4), false)); $d[$key] = $this->get(Utils::readInt($this->get(4)));
} }
$res = (string) Utils::curl_post($url, $d, $timeout); $res = (string) Utils::curl_post($url, $d, $timeout);
$this->lock(); $this->lock();
$this->output .= Utils::writeInt($rID).Utils::writeShort(ASYNC_CURL_POST).Utils::writeInt(strlen($res)).$res; $this->output .= Utils::writeInt($rID).Utils::writeShort(ASYNC_CURL_POST).Utils::writeInt(strlen($res)).$res;
$this->unlock(); $this->unlock();
break; break;
case ASYNC_FUNCTION:
$function = $this->get(Utils::readShort($this->get(2), false));
$params = unserialize($this->get(Utils::readInt($this->get(4))));
$res = serialize(@call_user_func_array($function, $params));
$this->output .= Utils::writeInt($rID).Utils::writeShort(ASYNC_FUNCTION).Utils::writeInt(strlen($res)).$res;
break;
} }
} }
usleep(10000); usleep(10000);

View File

@ -43,8 +43,16 @@ class Entity extends Position{
public $attach; public $attach;
public $closed; public $closed;
public $player; public $player;
public $status;
public $fallY; public $fallY;
public $health;
public $fire;
public $crouched;
public $invincible;
public $fallStart; public $fallStart;
public $stack;
public $meta;
private $position;
private $tickCounter; private $tickCounter;
private $speedMeasure = array(0, 0, 0, 0, 0, 0, 0); private $speedMeasure = array(0, 0, 0, 0, 0, 0, 0);
private $server; private $server;
@ -164,7 +172,7 @@ class Entity extends Position{
} }
public function getDrops(){ public function getDrops(){
if($this->class === ENTITY_PLAYER and ($this->player->gamemode & 0x01) === 0){ if($this->class === ENTITY_PLAYER and $this->player instanceof Player and ($this->player->gamemode & 0x01) === 0){
$inv = array(); $inv = array();
for($i = 0; $i < PLAYER_SURVIVAL_SLOTS; ++$i){ for($i = 0; $i < PLAYER_SURVIVAL_SLOTS; ++$i){
$slot = $this->player->getSlot($i); $slot = $this->player->getSlot($i);
@ -296,7 +304,7 @@ class Entity extends Position{
} }
} }
if($this->class !== ENTITY_PLAYER and ($this->x <= 0 or $this->z <= 0 or $this->x >= 256 or $this->z >= 256 or $this->y >= 128 or $this->y <= 0)){ if($this->class !== ENTITY_PLAYER and ($this->y >= 128 or $this->y <= 0)){
$this->close(); $this->close();
return false; return false;
} }
@ -526,8 +534,8 @@ class Entity extends Position{
} }
}elseif($this->fallY !== false){ //Fall damage! }elseif($this->fallY !== false){ //Fall damage!
if($y < $this->fallY){ if($y < $this->fallY){
$d = $this->level->getBlock(new Vector3($x, $y + 1, $z)); $d = $this->level->getBlock(new Vector3($this->x, $y + 1, $this->z));
$d2 = $this->level->getBlock(new Vector3($x, $y + 2, $z)); $d2 = $this->level->getBlock(new Vector3($this->x, $y + 2, $this->z));
$dmg = ($this->fallY - $y) - 3; $dmg = ($this->fallY - $y) - 3;
if($dmg > 0 and !($d instanceof LiquidBlock) and $d->getID() !== LADDER and $d->getID() !== COBWEB and !($d2 instanceof LiquidBlock) and $d2->getID() !== LADDER and $d2->getID() !== COBWEB){ if($dmg > 0 and !($d instanceof LiquidBlock) and $d->getID() !== LADDER and $d->getID() !== COBWEB and !($d2 instanceof LiquidBlock) and $d2->getID() !== LADDER and $d2->getID() !== COBWEB){
$this->harm($dmg, "fall"); $this->harm($dmg, "fall");
@ -562,10 +570,10 @@ class Entity extends Position{
if($this->isStatic === false and ($this->last[0] != $this->x or $this->last[1] != $this->y or $this->last[2] != $this->z or $this->last[3] != $this->yaw or $this->last[4] != $this->pitch)){ if($this->isStatic === false and ($this->last[0] != $this->x or $this->last[1] != $this->y or $this->last[2] != $this->z or $this->last[3] != $this->yaw or $this->last[4] != $this->pitch)){
if($this->class === ENTITY_PLAYER or ($this->last[5] + 8) < $now){ if($this->class === ENTITY_PLAYER or ($this->last[5] + 8) < $now){
if($this->server->api->handle("entity.move", $this) === false){ if($this->server->api->handle("entity.move", $this) === false){
if($this->class === ENTITY_PLAYER){ if($this->class === ENTITY_PLAYER and $this->player instanceof Player){
$this->player->teleport(new Vector3($this->last[0], $this->last[1], $this->last[2]), $this->last[3], $this->last[4]); $this->player->teleport(new Vector3($this->last[0], $this->last[1], $this->last[2]), $this->last[3], $this->last[4]);
}else{ }else{
$this->setPosition($this->last[0], $this->last[1], $this->last[2], $this->last[3], $this->last[4]); $this->setPosition(new Vector3($this->last[0], $this->last[1], $this->last[2]), $this->last[3], $this->last[4]);
} }
}else{ }else{
$this->updateLast(); $this->updateLast();
@ -593,7 +601,7 @@ class Entity extends Position{
} }
} }
}else{ }else{
$this->updatePosition($this->x, $this->y, $this->z, $this->yaw, $this->pitch); $this->updatePosition();
} }
} }
$this->lastUpdate = $now; $this->lastUpdate = $now;
@ -658,7 +666,7 @@ class Entity extends Position{
} }
switch($this->class){ switch($this->class){
case ENTITY_PLAYER: case ENTITY_PLAYER:
if($this->player->connected !== true or $this->player->spawned === false){ if(!($this->player instanceof Player) or $this->player->connected !== true or $this->player->spawned === false){
return false; return false;
} }

View File

@ -21,7 +21,7 @@
class Level{ class Level{
public $entities, $tiles, $blockUpdates, $nextSave, $players = array(), $level; public $entities, $tiles, $blockUpdates, $nextSave, $players = array(), $level;
private $time, $startCheck, $startTime, $server, $name, $usedChunks, $changedBlocks, $changedCount, $stopTime; private $time, $startCheck, $startTime, $server, $name, $usedChunks, $changedBlocks, $changedCount, $stopTime, $generator;
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();
@ -34,12 +34,23 @@ class Level{
$this->nextSave = $this->startCheck = microtime(true); $this->nextSave = $this->startCheck = microtime(true);
$this->nextSave += 90; $this->nextSave += 90;
$this->stopTime = false; $this->stopTime = false;
$this->server->schedule(15, array($this, "checkThings"), array(), true); $this->server->schedule(2, array($this, "checkThings"), array(), true);
$this->server->schedule(20 * 13, array($this, "checkTime"), array(), true); $this->server->schedule(20 * 13, array($this, "checkTime"), array(), true);
$this->name = $name; $this->name = $name;
$this->usedChunks = array(); $this->usedChunks = array();
$this->changedBlocks = array(); $this->changedBlocks = array();
$this->changedCount = array(); $this->changedCount = array();
if(class_exists($this->level->levelData["generator"])){
$gen = $this->level->levelData["generator"];
$this->generator = new $gen((array) $this->level->levelData["generatorSettings"]);
}else{
if(strtoupper($this->server->api->getProperty("level-type")) == "FLAT"){
$this->generator = new SuperflatGenerator();
}else{
$this->generator = new NormalGenerator();
}
}
$this->generator->init($this, new Random($this->level->levelData["seed"]));
} }
public function close(){ public function close(){
@ -66,6 +77,10 @@ class Level{
unset($this->usedChunks[$X.".".$Z][$player->CID]); unset($this->usedChunks[$X.".".$Z][$player->CID]);
} }
public function isChunkPopulated($X, $Z){
return $this->level->isPopulated($X, $Z);
}
public function checkTime(){ public function checkTime(){
if(!isset($this->level)){ if(!isset($this->level)){
return false; return false;
@ -93,9 +108,8 @@ class Level{
$now = microtime(true); $now = microtime(true);
$this->players = $this->server->api->player->getAll($this); $this->players = $this->server->api->player->getAll($this);
if(count($this->changedCount) > 0){ if($this->level->isGenerating === 0 and count($this->changedCount) > 0){
arsort($this->changedCount); arsort($this->changedCount);
$resendChunks = array();
foreach($this->changedCount as $index => $count){ foreach($this->changedCount as $index => $count){
if($count < 582){//Optimal value, calculated using the relation between minichunks and single packets if($count < 582){//Optimal value, calculated using the relation between minichunks and single packets
break; break;
@ -128,18 +142,34 @@ class Level{
if(count($c) === 0){ if(count($c) === 0){
unset($this->usedChunks[$i]); unset($this->usedChunks[$i]);
$X = explode(".", $i); $X = explode(".", $i);
$Z = array_pop($X); $Z = (int) array_pop($X);
$this->level->unloadChunk((int) array_pop($X), (int) $Z, $this->server->saveEnabled); $X = (int) array_pop($X);
if(!$this->isSpawnChunk($X, $Z)){
$this->level->unloadChunk($X, $Z, $this->server->saveEnabled);
}
} }
} }
$this->save(false, false); $this->save(false, false);
} }
} }
public function generateChunk($X, $Z){
++$this->level->isGenerating;
$this->generator->generateChunk($X, $Z);
--$this->level->isGenerating;
return true;
}
public function populateChunk($X, $Z){
$this->level->setPopulated($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);
} }
} }
@ -385,14 +415,24 @@ class Level{
return $this->level->loadChunk($X, $Z); return $this->level->loadChunk($X, $Z);
} }
public function unloadChunk($X, $Z){ public function unloadChunk($X, $Z, $force = false){
if(!isset($this->level)){ if(!isset($this->level)){
return false; return false;
} }
if($force !== true and $this->isSpawnChunk($X, $Z)){
return false;
}
Cache::remove("world:{$this->name}:$X:$Z"); Cache::remove("world:{$this->name}:$X:$Z");
return $this->level->unloadChunk($X, $Z, $this->server->saveEnabled); return $this->level->unloadChunk($X, $Z, $this->server->saveEnabled);
} }
public function isSpawnChunk($X, $Z){
$spawnX = $this->level->getData("spawnX") >> 4;
$spawnZ = $this->level->getData("spawnZ") >> 4;
return abs($X - $spawnX) <= 1 and abs($Z - $spawnZ) <= 1;
}
public function getOrderedChunk($X, $Z, $Yndex){ public function getOrderedChunk($X, $Z, $Yndex){
if(!isset($this->level)){ if(!isset($this->level)){
return false; return false;

View File

@ -34,21 +34,21 @@ class LevelImport{
$tiles = new Config($this->path."tiles.yml", CONFIG_YAML, unserialize(file_get_contents($this->path."tileEntities.dat"))); $tiles = new Config($this->path."tiles.yml", CONFIG_YAML, unserialize(file_get_contents($this->path."tileEntities.dat")));
$tiles->save(); $tiles->save();
}elseif(file_exists($this->path."chunks.dat") and file_exists($this->path."level.dat")){ //Pocket }elseif(file_exists($this->path."chunks.dat") and file_exists($this->path."level.dat")){ //Pocket
$nbt = new NBT(); $nbt = new NBT(NBT::LITTLE_ENDIAN);
$nbt->load(substr(file_get_contents($this->path."level.dat"), 8)); $nbt->read(substr(file_get_contents($this->path."level.dat"), 8));
$level = array_shift($nbt->tree); $level = $nbt->getData();
if($level["LevelName"] == ""){ if($level->LevelName == ""){
$level["LevelName"] = "world".time(); $level->LevelName = "world".time();
} }
console("[INFO] Importing Pocket level \"".$level["LevelName"]."\" to PMF format"); console("[INFO] Importing Pocket level \"".$level->LevelName."\" to PMF format");
unset($level["Player"]); unset($level->Player);
$nbt->load(substr(file_get_contents($this->path."entities.dat"), 12)); $nbt->read(substr(file_get_contents($this->path."entities.dat"), 12));
$entities = array_shift($nbt->tree); $entities = $nbt->getData();
if(!isset($entities["TileEntities"])){ if(!isset($entities->TileEntities)){
$entities["TileEntities"] = array(); $entities->TileEntities = array();
} }
$tiles = $entities["TileEntities"]; $tiles = $entities->TileEntities;
$entities = $entities["Entities"]; $entities = $entities->Entities;
$entities = new Config($this->path."entities.yml", CONFIG_YAML, $entities); $entities = new Config($this->path."entities.yml", CONFIG_YAML, $entities);
$entities->save(); $entities->save();
$tiles = new Config($this->path."tiles.yml", CONFIG_YAML, $tiles); $tiles = new Config($this->path."tiles.yml", CONFIG_YAML, $tiles);
@ -58,15 +58,16 @@ class LevelImport{
} }
$pmf = new PMFLevel($this->path."level.pmf", array( $pmf = new PMFLevel($this->path."level.pmf", array(
"name" => $level["LevelName"], "name" => $level->LevelName,
"seed" => $level["RandomSeed"], "seed" => $level->RandomSeed,
"time" => $level["Time"], "time" => $level->Time,
"spawnX" => $level["SpawnX"], "spawnX" => $level->SpawnX,
"spawnY" => $level["SpawnY"], "spawnY" => $level->SpawnY,
"spawnZ" => $level["SpawnZ"], "spawnZ" => $level->SpawnZ,
"extra" => "", "height" => 8,
"width" => 16, "generator" => "NormalGenerator",
"height" => 8 "generatorSettings" => "",
"extra" => ""
)); ));
$chunks = new PocketChunkParser(); $chunks = new PocketChunkParser();
$chunks->loadFile($this->path."chunks.dat"); $chunks->loadFile($this->path."chunks.dat");
@ -83,6 +84,7 @@ class LevelImport{
6 => "", 6 => "",
7 => "" 7 => ""
); );
for($z = 0; $z < 16; ++$z){ for($z = 0; $z < 16; ++$z){
for($x = 0; $x < 16; ++$x){ for($x = 0; $x < 16; ++$x){
$block = $chunks->getChunkColumn($X, $Z, $x, $z, 0); $block = $chunks->getChunkColumn($X, $Z, $x, $z, 0);
@ -94,13 +96,17 @@ class LevelImport{
} }
} }
} }
$pmf->initCleanChunk($X, $Z);
foreach($chunk as $Y => $data){ foreach($chunk as $Y => $data){
$pmf->setMiniChunk($X, $Z, $Y, $data); $pmf->setMiniChunk($X, $Z, $Y, $data);
} }
$pmf->setPopulated($X, $Z);
$pmf->saveChunk($X, $Z); $pmf->saveChunk($X, $Z);
} }
console("[NOTICE] Importing level ".ceil(($Z + 1)/0.16)."%"); console("[NOTICE] Importing level ".ceil(($Z + 1)/0.16)."%");
} }
$pmf->saveData();
$chunks->map = null; $chunks->map = null;
$chunks = null; $chunks = null;
@unlink($this->path."level.dat"); @unlink($this->path."level.dat");

View File

@ -19,14 +19,19 @@
* *
*/ */
/**
* WARNING: This code is old, and only supports the file format partially (reverse engineering)
* It can break, lock, or hit you in the face in any moment.
*
*/
class PocketChunkParser{ class PocketChunkParser{
private $location, $raw = b"", $file; private $location, $raw = b"", $file;
var $sectorLength = 4096; //16 * 16 * 16 public $sectorLength = 4096; //16 * 16 * 16
var $chunkLength = 86016; //21 * $sectorLength public $chunkLength = 86016; //21 * $sectorLength
var $map; public $map = array();
function __construct(){ public function __construct(){
$map = array();
} }
private function loadLocationTable(){ private function loadLocationTable(){

View File

@ -31,6 +31,8 @@ class Tile extends Position{
public $attach; public $attach;
public $metadata; public $metadata;
public $closed; public $closed;
private $lastUpdate;
private $scheduledUpdate;
private $server; private $server;
function __construct(Level $level, $id, $class, $x, $y, $z, $data = array()){ function __construct(Level $level, $id, $class, $x, $y, $z, $data = array()){
$this->server = ServerAPI::request(); $this->server = ServerAPI::request();
@ -354,87 +356,52 @@ class Tile extends Position{
} }
switch($this->class){ switch($this->class){
case TILE_CHEST: case TILE_CHEST:
$nbt = new NBT(); $nbt = new NBT(NBT::LITTLE_ENDIAN);
$nbt->write(chr(NBT::TAG_COMPOUND)."\x00\x00");
$nbt->write(chr(NBT::TAG_STRING));
$nbt->writeTAG_String("id");
$nbt->writeTAG_String($this->class);
$nbt->write(chr(NBT::TAG_INT));
$nbt->writeTAG_String("x");
$nbt->writeTAG_Int((int) $this->x);
$nbt->write(chr(NBT::TAG_INT));
$nbt->writeTAG_String("y");
$nbt->writeTAG_Int((int) $this->y);
$nbt->write(chr(NBT::TAG_INT));
$nbt->writeTAG_String("z");
$nbt->writeTAG_Int((int) $this->z);
if($this->isPaired()){ if($this->isPaired()){
$nbt->write(chr(NBT::TAG_INT)); $nbt->setData(new NBTTag_Compound("", array(
$nbt->writeTAG_String("pairx"); new NBTTag_String("id", $this->class),
$nbt->writeTAG_Int((int) $this->data["pairx"]); new NBTTag_Int("x", (int) $this->x),
new NBTTag_Int("y", (int) $this->y),
$nbt->write(chr(NBT::TAG_INT)); new NBTTag_Int("z", (int) $this->z),
$nbt->writeTAG_String("pairz"); new NBTTag_Int("pairx", (int) $this->data["pairx"]),
$nbt->writeTAG_Int((int) $this->data["pairz"]); new NBTTag_Int("pairz", (int) $this->data["pairz"]),
new NBTTag_End
)));
}else{
$nbt->setData(new NBTTag_Compound("", array(
new NBTTag_String("id", $this->class),
new NBTTag_Int("x", (int) $this->x),
new NBTTag_Int("y", (int) $this->y),
new NBTTag_Int("z", (int) $this->z),
new NBTTag_End
)));
} }
$nbt->write(chr(NBT::TAG_END));
$pk = new EntityDataPacket; $pk = new EntityDataPacket;
$pk->x = $this->x; $pk->x = $this->x;
$pk->y = $this->y; $pk->y = $this->y;
$pk->z = $this->z; $pk->z = $this->z;
$pk->namedtag = $nbt->binary; $pk->namedtag = $nbt->write();
$player->dataPacket($pk); $player->dataPacket($pk);
break; break;
case TILE_SIGN: case TILE_SIGN:
$nbt = new NBT(); $nbt = new NBT(NBT::LITTLE_ENDIAN);
$nbt->write(chr(NBT::TAG_COMPOUND)."\x00\x00"); $nbt->setData(new NBTTag_Compound("", array(
new NBTTag_String("Text1", $this->data["Text1"]),
$nbt->write(chr(NBT::TAG_STRING)); new NBTTag_String("Text2", $this->data["Text2"]),
$nbt->writeTAG_String("Text1"); new NBTTag_String("Text3", $this->data["Text3"]),
$nbt->writeTAG_String($this->data["Text1"]); new NBTTag_String("Text4", $this->data["Text4"]),
new NBTTag_String("id", $this->class),
$nbt->write(chr(NBT::TAG_STRING)); new NBTTag_Int("x", (int) $this->x),
$nbt->writeTAG_String("Text2"); new NBTTag_Int("y", (int) $this->y),
$nbt->writeTAG_String($this->data["Text2"]); new NBTTag_Int("z", (int) $this->z),
new NBTTag_End
$nbt->write(chr(NBT::TAG_STRING)); )));
$nbt->writeTAG_String("Text3");
$nbt->writeTAG_String($this->data["Text3"]);
$nbt->write(chr(NBT::TAG_STRING));
$nbt->writeTAG_String("Text4");
$nbt->writeTAG_String($this->data["Text4"]);
$nbt->write(chr(NBT::TAG_STRING));
$nbt->writeTAG_String("id");
$nbt->writeTAG_String($this->class);
$nbt->write(chr(NBT::TAG_INT));
$nbt->writeTAG_String("x");
$nbt->writeTAG_Int((int) $this->x);
$nbt->write(chr(NBT::TAG_INT));
$nbt->writeTAG_String("y");
$nbt->writeTAG_Int((int) $this->y);
$nbt->write(chr(NBT::TAG_INT));
$nbt->writeTAG_String("z");
$nbt->writeTAG_Int((int) $this->z);
$nbt->write(chr(NBT::TAG_END));
$pk = new EntityDataPacket; $pk = new EntityDataPacket;
$pk->x = $this->x; $pk->x = $this->x;
$pk->y = $this->y; $pk->y = $this->y;
$pk->z = $this->z; $pk->z = $this->z;
$pk->namedtag = $nbt->binary; $pk->namedtag = $nbt->write();
$player->dataPacket($pk); $player->dataPacket($pk);
break; break;
} }

View File

@ -20,7 +20,8 @@
*/ */
interface LevelGenerator{ interface LevelGenerator{
public function __construct(array $options = array());
public function __construct(array $settings = array());
public function init(Level $level, Random $random); public function init(Level $level, Random $random);
@ -28,7 +29,9 @@ interface LevelGenerator{
public function populateChunk($chunkX, $chunkZ); public function populateChunk($chunkX, $chunkZ);
public function populateLevel(); public function getSettings();
//public function populateLevel();
public function getSpawn(); public function getSpawn();
} }

View File

@ -0,0 +1,170 @@
<?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/
*
*
*/
/***REM_START***/
require_once("LevelGenerator.php");
/***REM_END***/
class NormalGenerator implements LevelGenerator{
private $populators = array();
private $level;
private $random;
private $worldHeight = 65;
private $waterHeight = 63;
private $noiseHills;
private $noisePatches;
private $noisePatchesSmall;
private $noiseBase;
public function __construct(array $options = array()){
}
public function getSettings(){
return array();
}
public function init(Level $level, Random $random){
$this->level = $level;
$this->random = $random;
$this->random->setSeed($this->level->getSeed());
$this->noiseHills = new NoiseGeneratorSimplex($this->random, 3);
$this->noisePatches = new NoiseGeneratorSimplex($this->random, 2);
$this->noisePatchesSmall = new NoiseGeneratorSimplex($this->random, 2);
$this->noiseBase = new NoiseGeneratorSimplex($this->random, 16);
$ores = new OrePopulator();
$ores->setOreTypes(array(
new OreType(new CoalOreBlock(), 20, 16, 0, 128),
new OreType(New IronOreBlock(), 20, 8, 0, 64),
new OreType(new RedstoneOreBlock(), 8, 7, 0, 16),
new OreType(new LapisOreBlock(), 1, 6, 0, 32),
new OreType(new GoldOreBlock(), 2, 8, 0, 32),
new OreType(new DiamondOreBlock(), 1, 7, 0, 16),
new OreType(new DirtBlock(), 20, 32, 0, 128),
new OreType(new GravelBlock(), 10, 16, 0, 128),
));
$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){
$this->random->setSeed(0xdeadbeef ^ ($chunkX << 8) ^ $chunkZ ^ $this->level->getSeed());
$hills = array();
$patches = 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){
$chunk = "";
$startY = $chunkY << 4;
$endY = $startY + 16;
for($z = 0; $z < 16; ++$z){
for($x = 0; $x < 16; ++$x){
$i = ($z << 4) + $x;
$height = $this->worldHeight + $hills[$i] * 14 + $base[$i] * 7;
$height = (int) $height;
for($y = $startY; $y < $endY; ++$y){
$diff = $height - $y;
if($y <= 4 and ($y === 0 or $this->random->nextFloat() < 0.75)){
$chunk .= "\x07"; //bedrock
}elseif($diff > 2){
$chunk .= "\x01"; //stone
}elseif($diff > 0){
if($patches[$i] > 0.7){
$chunk .= "\x01"; //stone
}elseif($patches[$i] < -0.8){
$chunk .= "\x0d"; //gravel
}else{
$chunk .= "\x03"; //dirt
}
}elseif($y <= $this->waterHeight){
if(($this->waterHeight - $y) <= 1 and $diff === 0){
$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{
$chunk .= "\x09"; //still_water
}
}elseif($diff === 0){
if($patches[$i] > 0.7){
$chunk .= "\x01"; //stone
}elseif($patches[$i] < -0.8){
$chunk .= "\x0d"; //gravel
}else{
$chunk .= "\x02"; //grass
}
}else{
$chunk .= "\x00";
}
}
$chunk .= "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
}
}
$this->level->setMiniChunk($chunkX, $chunkZ, $chunkY, $chunk);
}
}
public function populateChunk($chunkX, $chunkZ){
$this->random->setSeed(0xdeadbeef ^ ($chunkX << 8) ^ $chunkZ ^ $this->level->getSeed());
foreach($this->populators as $populator){
$this->random->setSeed(0xdeadbeef ^ ($chunkX << 8) ^ $chunkZ ^ $this->level->getSeed());
$populator->populate($this->level, $chunkX, $chunkZ, $this->random);
}
}
public function getSpawn(){
return $this->level->getSafeSpawn(new Vector3(127.5, 128, 127.5));
}
}

View File

@ -24,7 +24,11 @@ require_once("LevelGenerator.php");
/***REM_END***/ /***REM_END***/
class SuperflatGenerator implements LevelGenerator{ class SuperflatGenerator implements LevelGenerator{
private $level, $random, $structure, $chunks, $options, $floorLevel, $populators = array(); private $level, $random, $structure, $chunks, $options, $floorLevel, $preset, $populators = array();
public function getSettings(){
return $this->options;
}
public function __construct(array $options = array()){ public function __construct(array $options = array()){
$this->preset = "2;7,59x1,3x3,2;1;spawn(radius=10 block=89),decoration(treecount=80 grasscount=45)"; $this->preset = "2;7,59x1,3x3,2;1;spawn(radius=10 block=89),decoration(treecount=80 grasscount=45)";
@ -126,8 +130,8 @@ 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((int) ($chunkX * 0xdead + $chunkZ * 0xbeef) ^ $this->level->getSeed());
$populator->populate($this->level, $chunkX, $chunkZ, $this->random); $populator->populate($this->level, $chunkX, $chunkZ, $this->random);
} }
} }

File diff suppressed because one or more lines are too long

View File

@ -20,11 +20,10 @@
*/ */
class WorldGenerator{ class WorldGenerator{
private $seed, $level, $path, $random, $generator, $width; private $seed, $level, $path, $random, $generator, $height;
public function __construct(LevelGenerator $generator, $name, $seed = false, $width = 16, $height = 8){ public function __construct(LevelGenerator $generator, $name, $seed = false, $height = 8){
$this->seed = $seed !== false ? (int) $seed:Utils::readInt(Utils::getRandomBytes(4, false)); $this->seed = $seed !== false ? (int) $seed:Utils::readInt(Utils::getRandomBytes(4, false));
$this->random = new Random($this->seed); $this->random = new Random($this->seed);
$this->width = (int) $width;
$this->height = (int) $height; $this->height = (int) $height;
$this->path = DATA_PATH."worlds/".$name."/"; $this->path = DATA_PATH."worlds/".$name."/";
$this->generator = $generator; $this->generator = $generator;
@ -35,9 +34,10 @@ class WorldGenerator{
"spawnX" => 128, "spawnX" => 128,
"spawnY" => 128, "spawnY" => 128,
"spawnZ" => 128, "spawnZ" => 128,
"extra" => "", "height" => $this->height,
"width" => $this->width, "generator" => get_class($this->generator),
"height" => $this->height "generatorSettings" => $this->generator->getSettings(),
"extra" => ""
)); ));
$entities = new Config($this->path."entities.yml", CONFIG_YAML); $entities = new Config($this->path."entities.yml", CONFIG_YAML);
$tiles = new Config($this->path."tiles.yml", CONFIG_YAML); $tiles = new Config($this->path."tiles.yml", CONFIG_YAML);
@ -47,23 +47,15 @@ class WorldGenerator{
public function generate(){ public function generate(){
$this->generator->init($this->level, $this->random); $this->generator->init($this->level, $this->random);
for($Z = 0; $Z < $this->width; ++$Z){
for($X = 0; $X < $this->width; ++$X){ //Generate 4 chunks for spawning players
$this->generator->generateChunk($X, $Z); for($Z = 7; $Z <= 8; ++$Z){
for($X = 7; $X <= 9; ++$X){
$this->level->level->loadChunk($X, $Z);
} }
console("[NOTICE] Generating level ".ceil((($Z + 1)/$this->width) * 100)."%");
}
console("[NOTICE] Populating level");
$this->generator->populateLevel();
for($Z = 0; $Z < $this->width; ++$Z){
for($X = 0; $X < $this->width; ++$X){
$this->generator->populateChunk($X, $Z);
}
console("[NOTICE] Populating level ".ceil((($Z + 1)/$this->width) * 100)."%");
} }
$this->level->setSpawn($this->generator->getSpawn()); $this->level->setSpawn($this->generator->getSpawn());
$this->level->save(true, true);
} }
public function close(){ public function close(){

View File

@ -19,6 +19,78 @@
* *
*/ */
abstract class NoiseGenerator{
abstract class NoiseGenerator{
protected $perm = array();
protected $offsetX = 0;
protected $offsetY = 0;
protected $offsetZ = 0;
protected $octaves = 8;
public static function floor($x){
return $x >= 0 ? (int) $x : (int) ($x - 1);
}
public static function fade($x){
return $x * $x * $x * ($x * ($x * 6 - 15) + 10);
}
public static function lerp($x, $y, $z){
return $y + $x * ($z - $y);
}
public static function grad($hash, $x, $y, $z){
$hash &= 15;
$u = $hash < 8 ? $x : $y;
$v = $hash < 4 ? $y : (($hash === 12 or $hash === 14) ? $x : $z);
return (($hash & 1) === 0 ? $u : -$u) + (($hash & 2) === 0 ? $v : -$v);
}
abstract public function getNoise2D($x, $z);
abstract public function getNoise3D($x, $y, $z);
public function noise2D($x, $z, $frequency, $amplitude, $normalized = false){
$result = 0;
$amp = 1;
$freq = 1;
$max = 0;
for($i = 0; $i < $this->octaves; ++$i){
$result += $this->getNoise2D($x * $freq, $z * $freq) * $amp;
$max += $amp;
$freq *= $frequency;
$amp *= $amplitude;
}
if($normalized === true){
$result /= $max;
}
return $result;
}
public function noise3D($x, $y, $z, $frequency, $amplitude, $normalized = false){
$result = 0;
$amp = 1;
$freq = 1;
$max = 0;
for($i = 0; $i < $this->octaves; ++$i){
$result += $this->getNoise3D($x * $freq, $y * $freq, $z * $freq) * $amp;
$max += $amp;
$freq *= $frequency;
$amp *= $amplitude;
}
if($normalized === true){
$result /= $max;
}
return $result;
}
public function setOffset($x, $y, $z){
$this->offsetX = $x;
$this->offsetY = $y;
$this->offsetZ = $z;
}
} }

View File

@ -1,68 +0,0 @@
<?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/
*
*
*/
/***REM_START***/
require_once("NoiseGenerator.php");
/***REM_END***/
class NoiseGeneratorOctaves extends NoiseGenerator{
public $octaves;
private $generatorCollection;
public function __construct(Random $random, $octaves){
$this->generatorCollection = array();
$this->octaves = (int) $octaves;
for($o = 0; $o < $this->octaves; ++$o){
$this->generatorCollection[$o] = new NoiseGeneratorPerlin($random);
}
}
public function generateNoiseOctaves($int1, $int2, $int3, $int4, $int5, $int6, $par1 = false, $par2 = false, $par3 = false){
if($par1 === false or $par2 === false or $par3 === false){
return $this->generateNoiseOctaves($int1, 10, $int2, $int3, 1, $int4, $int5, 1, $int6);
}
$floats = array();
$cnt = $int4 * $int5 * $int6;
for($i = 0; $i < $cnt; ++$i){
$floats[$i] = 0;
}
$d1 = 1;
for($j = 0; $j < $this->octaves; ++$j){
$d2 = $int1 * $d1 * $par1;
$d3 = $int2 * $d1 * $par2;
$d4 = $int3 * $d1 * $par3;
$l1 = floor($d2);
$l2 = floor($d4);
$d2 -= $l1;
$d4 -= $l2;
$l1 %= 16777216;
$l2 %= 16777216;
$d2 += $l1;
$d4 += $l2;
$this->generatorCollection[$j]->populateNoiseArray($floats, $d2, $d3, $d4, $int4, $int5, $int6, $par1 * $d1, $par2 * $d1, $par3 * $d1, $d1);
$d1 /= 2;
}
return $floats;
}
}

View File

@ -24,146 +24,79 @@ require_once("NoiseGenerator.php");
/***REM_END***/ /***REM_END***/
class NoiseGeneratorPerlin extends NoiseGenerator{ class NoiseGeneratorPerlin extends NoiseGenerator{
private $permutations = array(); public static $grad3 = [
public $xCoord, $yCoord, $zCoord; [1, 1, 0], [-1, 1, 0], [1, -1, 0], [-1, -1, 0],
[1, 0, 1], [-1, 0, 1], [1, 0, -1], [-1, 0, -1],
[0, 1, 1], [0, -1, 1], [0, 1, -1], [0, -1, -1]
];
public function __construct($random = false){
if(!($random instanceof Random)){ public function __construct(Random $random, $octaves){
$random = new Random(); $this->octaves = $octaves;
} $this->offsetX = $random->nextFloat() * 256;
$this->xCoord = $random->nextFloat() * 256; $this->offsetY = $random->nextFloat() * 256;
$this->yCoord = $random->nextFloat() * 256; $this->offsetZ = $random->nextFloat() * 256;
$this->zCoord = $random->nextFloat() * 256;
for($i = 0; $i < 512; ++$i){ for($i = 0; $i < 512; ++$i){
$this->permutations[$i] = 0; $this->perm[$i] = 0;
}
for($i = 0; $i < 256; ++$i){
$this->permutations[$i] = $i;
} }
for($i = 0; $i < 256; ++$i){ for($i = 0; $i < 256; ++$i){
$j = $random->nextRange(0, 256 - $i) + $i; $this->perm[$i] = $random->nextRange(0, 255);
$k = $this->permutations[$i]; }
$this->permutations[$i] = $this->permutations[$j];
$this->permutations[$j] = $k; for($i = 0; $i < 256; ++$i){
$this->permutations[$i + 256] = $this->permutations[$i]; $pos = $random->nextRange(0, 255 - $i) + $i;
$old = $this->perm[$i];
$this->perm[$i] = $this->perm[$pos];
$this->perm[$pos] = $old;
$this->perm[$i + 256] = $this->perm[$i];
} }
} }
public final function curve($par1, $par2, $par3){ public function getNoise3D($x, $y, $z){
return $par2 + $par1 * ($par3 - $par2); $x += $this->offsetX;
$y += $this->offsetY;
$z += $this->offsetZ;
$floorX = self::floor($x);
$floorY = self::floor($y);
$floorZ = self::floor($z);
$X = $floorX & 0xFF;
$Y = $floorY & 0xFF;
$Z = $floorZ & 0xFF;
$x -= $floorX;
$y -= $floorY;
$z -= $floorZ;
//Fade curves
$fX = self::fade($x);
$fY = self::fade($y);
$fZ = self::fade($z);
//Cube corners
$A = $this->perm[$X] + $Y;
$AA = $this->perm[$A] + $Z;
$AB = $this->perm[$A + 1] + $Z;
$B = $this->perm[$X + 1] + $Y;
$BA = $this->perm[$B] + $Z;
$BB = $this->perm[$B + 1] + $Z;
return self::lerp($fZ, self::lerp($fY, self::lerp($fX, self::grad($this->perm[$AA], $x, $y, $z),
self::grad($this->perm[$BA], $x - 1, $y, $z)),
self::lerp($fX, self::grad($this->perm[$AB], $x, $y - 1, $z),
self::grad($this->perm[$BB], $x - 1, $y - 1, $z))),
self::lerp($fY, self::lerp($fX, self::grad($this->perm[$AA + 1], $x, $y, $z - 1),
self::grad($this->perm[$BA + 1], $x - 1, $y, $z - 1)),
self::lerp($fX, self::grad($this->perm[$AB + 1], $x, $y - 1, $z - 1),
self::grad($this->perm[$BB + 1], $x - 1, $y - 1, $z - 1))));
} }
public function grad2D($int, $par1, $par2){ public function getNoise2D($x, $y){
$i = $int & 0x0F; return $this->getNoise3D($x, $y, 0);
$d1 = (1 - (($i & 0x08) >> 3)) * $par1;
$d2 = ($i === 12 or $i === 14) ? $par1:($i < 4 ? 0:$par2);
return (($i & 0x01) === 0 ? $d1:-$d1) + (($i & 0x02) === 0 ? $d2:-$d2);
}
public function grad3D($int, $par1, $par2, $par3){
$i = $int & 0x0F;
$d1 = $i < 8 ? $par1 : $par2;
$d2 = ($i === 12 or $i === 14) ? $par1:($i < 4 ? $par2:$par3);
return (($i & 0x01) === 0 ? $d1:-$d1) + (($i & 0x02) === 0 ? $d2:-$d2);
}
public function populateNoiseArray(&$floats, $par1, $par2, $par3, $int1, $int2, $int3, $par4, $par5, $par6, $par7){
if($int2 === 1){
$n = 0;
$d3 = 1 / $par7;
for($i1 = 0; $i1 < $int1; ++$i1){
$d4 = $par1 + $i1 * $par4 + $this->xCoord;
$i2 = (int) $d4;
if($d4 < $i2){
--$i2;
}
$i3 = $i2 & 0xFF;
$d4 -= $i2;
$d5 = $d4 * $d4 * $d4 * ($d4 * ($d4 * 6 - 15) + 10);
for($i4 = 0; $i4 < $int3; ++$i4){
$d6 = $par3 + $i4 * $par6 + $this->zCoord;
$i5 = (int) $d6;
if($d6 < $i5){
--$i5;
}
$i6 = $i5 & 0xFF;
$d6 -= $i5;
$d7 = $d6 * $d6 * $d6 * ($d6 * ($d6 * 6 - 15) + 10);
$i = $this->permutations[$i3];
$j = $this->permutations[$i] + $i6;
$k = $this->permutations[$i3 + 1];
$m = $this->permutations[$k] + $i6;
$d1 = $this->curve($d5, $this->grad2D($this->permutations[$j], $d4, $d6), $this->grad3D($this->permutations[$m], $d4 - 1, 0, $d6));
$d2 = $this->curve($d5, $this->grad3D($this->permutations[$j + 1], $d4, 0, $d6 - 1), $this->grad3D($this->permutations[$m + 1], $d4 - 1, 0, $d6 - 1));
$d8 = $this->curve($d7, $d1, $d2);
$floats[$n++] += $d8 * $d3;
}
}
return;
}
$d9 = 1 / $par7;
$m = -1;
$n = 0;
$i = 0;
for($i4 = 0; $i4 < $int1; ++$i4){
$d6 = $par1 + $i4 * $par4 + $this->xCoord;
$i5 = (int) $d6;
if($d6 < $i5){
--$i5;
}
$i6 = $i5 & 0xFF;
$d6 -= $i5;
$d7 = $d6 * $d6 * $d6 * ($d6 * ($d6 * 6 - 15) + 10);
for($i12 = 0; $i12 < $int3; ++$i12){
$d12 = $par3 + $i12 * $par6 + $this->zCoord;
$i13 = (int) $d12;
if($d12 < $i13){
--$i13;
}
$i14 = $i13 & 0xFF;
$d12 -= $i13;
$d13 = $d12 * $d12 * $d12 * ($d12 * ($d12 * 6 - 15) + 10);
for($i15 = 0; $i15 < $int2; ++$i15){
$d14 = $par2 + $i15 * $par5 + $this->yCoord;
$i16 = (int) $d14;
if($d14 < $i16){
--$i16;
}
$d14 -= $i16;
$d15 = $d14 * $d14 * $d14 * ($d14 * ($d14 * 6 - 15) + 10);
if($i15 === 0 or $i17 !== $m){
$m = $i17;
$i7 = $this->permutations[$i6] + $i17;
$i8 = $this->permutations[$i7] + $i14;
$i9 = $this->permutations[$i7 + 1] + $i14;
$i10 = $this->permutations[$i6 + 1] + $i17;
$n = $this->permutations[$i10] + $i14;
$i11 = $this->permutations[$i10 + 1] + $i14;
$d10 = $this->curve($d7, $this->grad3D($this->permutations[$i8], $d6, $d14, $d12), $this->grad3D($this->permutations[$n], $d6 - 1, $d14, $d12));
$d4 = $this->curve($d7, $this->grad3D($this->permutations[$i9], $d6, $d14 - 1, $d12), $this->grad3D($this->permutations[$i11], $d6 - 1, $d14 - 1, $d12));
$d11 = $this->curve($d7, $this->grad3D($this->permutations[$i8 + 1], $d6, $d14, $d12 - 1), $this->grad3D($this->permutations[$n + 1], $d6 - 1, $d14, $d12 - 1));
$d5 = $this->curve($d7, $this->grad3D($this->permutations[$i9 + 1], $d6, $d14 - 1, $d12 - 1), $this->grad3D($this->permutations[$i11 + 1], $d6 - 1, $d14 - 1, $d12 - 1));
}
$d16 = $this->curve($d15, $d10, $d4);
$d17 = $this->curve($d15, $d11, $d5);
$d18 = $this->curve($d13, $d16, $d17);
$floats[$i++] += $d18 * $d9;
}
}
}
} }
} }

View File

@ -0,0 +1,438 @@
<?php
/***REM_START***/
require_once("NoiseGenerator.php");
require_once("NoiseGeneratorPerlin.php");
/***REM_END***/
/**
* Generates simplex-based noise.
* <p>
* This is a modified version of the freely published version in the paper by
* Stefan Gustavson at
* <a href="http://staffwww.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf">
* http://staffwww.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf</a>
*/
class NoiseGeneratorSimplex extends NoiseGeneratorPerlin{
protected static $SQRT_3;
protected static $SQRT_5;
protected static $F2;
protected static $G2;
protected static $G22;
protected static $F3;
protected static $G3;
protected static $F4;
protected static $G4;
protected static $G42;
protected static $G43;
protected static $G44;
protected static $grad4 = [[0, 1, 1, 1],[0, 1, 1, -1],[0, 1, -1, 1],[0, 1, -1, -1],
[0, -1, 1, 1],[0, -1, 1, -1],[0, -1, -1, 1],[0, -1, -1, -1],
[1, 0, 1, 1],[1, 0, 1, -1],[1, 0, -1, 1],[1, 0, -1, -1],
[-1, 0, 1, 1],[-1, 0, 1, -1],[-1, 0, -1, 1],[-1, 0, -1, -1],
[1, 1, 0, 1],[1, 1, 0, -1],[1, -1, 0, 1],[1, -1, 0, -1],
[-1, 1, 0, 1],[-1, 1, 0, -1],[-1, -1, 0, 1],[-1, -1, 0, -1],
[1, 1, 1, 0],[1, 1, -1, 0],[1, -1, 1, 0],[1, -1, -1, 0],
[-1, 1, 1, 0],[-1, 1, -1, 0],[-1, -1, 1, 0],[-1, -1, -1, 0]];
protected static $simplex = [
[0, 1, 2, 3],[0, 1, 3, 2],[0, 0, 0, 0],[0, 2, 3, 1],[0, 0, 0, 0],[0, 0, 0, 0],[0, 0, 0, 0],[1, 2, 3, 0],
[0, 2, 1, 3],[0, 0, 0, 0],[0, 3, 1, 2],[0, 3, 2, 1],[0, 0, 0, 0],[0, 0, 0, 0],[0, 0, 0, 0],[1, 3, 2, 0],
[0, 0, 0, 0],[0, 0, 0, 0],[0, 0, 0, 0],[0, 0, 0, 0],[0, 0, 0, 0],[0, 0, 0, 0],[0, 0, 0, 0],[0, 0, 0, 0],
[1, 2, 0, 3],[0, 0, 0, 0],[1, 3, 0, 2],[0, 0, 0, 0],[0, 0, 0, 0],[0, 0, 0, 0],[2, 3, 0, 1],[2, 3, 1, 0],
[1, 0, 2, 3],[1, 0, 3, 2],[0, 0, 0, 0],[0, 0, 0, 0],[0, 0, 0, 0],[2, 0, 3, 1],[0, 0, 0, 0],[2, 1, 3, 0],
[0, 0, 0, 0],[0, 0, 0, 0],[0, 0, 0, 0],[0, 0, 0, 0],[0, 0, 0, 0],[0, 0, 0, 0],[0, 0, 0, 0],[0, 0, 0, 0],
[2, 0, 1, 3],[0, 0, 0, 0],[0, 0, 0, 0],[0, 0, 0, 0],[3, 0, 1, 2],[3, 0, 2, 1],[0, 0, 0, 0],[3, 1, 2, 0],
[2, 1, 0, 3],[0, 0, 0, 0],[0, 0, 0, 0],[0, 0, 0, 0],[3, 1, 0, 2],[0, 0, 0, 0],[3, 2, 0, 1],[3, 2, 1, 0]];
protected $offsetW;
public function __construct(Random $random, $octaves){
parent::__construct($random, $octaves);
$this->offsetW = $random->nextFloat() * 256;
self::$SQRT_3 = sqrt(3);
self::$SQRT_5 = sqrt(5);
self::$F2 = 0.5 * (self::$SQRT_3 - 1);
self::$G2 = (3 - self::$SQRT_3) / 6;
self::$G22 = self::$G2 * 2.0 - 1;
self::$F3 = 1.0 / 3.0;
self::$G3 = 1.0 / 6.0;
self::$F4 = (self::$SQRT_5 - 1.0) / 4.0;
self::$G4 = (5.0 - self::$SQRT_5) / 20.0;
self::$G42 = self::$G4 * 2.0;
self::$G43 = self::$G4 * 3.0;
self::$G44 = self::$G4 * 4.0 - 1.0;
}
protected static function dot2D($g, $x, $y){
return $g[0] * $x + $g[1] * $y;
}
protected static function dot3D($g, $x, $y, $z){
return $g[0] * $x + $g[1] * $y + $g[2] * $z;
}
protected static function dot4D($g, $x, $y, $z, $w){
return $g[0] * $x + $g[1] * $y + $g[2] * $z + $g[3] * $w;
}
public function getNoise3D($x, $y, $z){
$x += $this->offsetX;
$y += $this->offsetY;
$z += $this->offsetZ;
// Skew the input space to determine which simplex cell we're in
$s = ($x + $y + $z) * self::$F3; // Very nice and simple skew factor for 3D
$i = self::floor($x + $s);
$j = self::floor($y + $s);
$k = self::floor($z + $s);
$t = ($i + $j + $k) * self::$G3;
$X0 = $i - $t; // Unskew the cell origin back to (x,y,z) space
$Y0 = $j - $t;
$Z0 = $k - $t;
$x0 = $x - $X0; // The x,y,z distances from the cell origin
$y0 = $y - $Y0;
$z0 = $z - $Z0;
// For the 3D case, the simplex shape is a slightly irregular tetrahedron.
// Determine which simplex we are in.
if($x0 >= $y0){
if($y0 >= $z0){
$i1 = 1;
$j1 = 0;
$k1 = 0;
$i2 = 1;
$j2 = 1;
$k2 = 0;
}// X Y Z order
elseif($x0 >= $z0){
$i1 = 1;
$j1 = 0;
$k1 = 0;
$i2 = 1;
$j2 = 0;
$k2 = 1;
}// X Z Y order
else{
$i1 = 0;
$j1 = 0;
$k1 = 1;
$i2 = 1;
$j2 = 0;
$k2 = 1;
}// Z X Y order
}else{ // x0<y0
if($y0 < $z0){
$i1 = 0;
$j1 = 0;
$k1 = 1;
$i2 = 0;
$j2 = 1;
$k2 = 1;
}// Z Y X order
elseif($x0 < $z0){
$i1 = 0;
$j1 = 1;
$k1 = 0;
$i2 = 0;
$j2 = 1;
$k2 = 1;
}// Y Z X order
else{
$i1 = 0;
$j1 = 1;
$k1 = 0;
$i2 = 1;
$j2 = 1;
$k2 = 0;
}// Y X Z order
}
// A step of (1,0,0) in (i,j,k) means a step of (1-c,-c,-c) in (x,y,z),
// a step of (0,1,0) in (i,j,k) means a step of (-c,1-c,-c) in (x,y,z), and
// a step of (0,0,1) in (i,j,k) means a step of (-c,-c,1-c) in (x,y,z), where
// c = 1/6.
$x1 = $x0 - $i1 + self::$G3; // Offsets for second corner in (x,y,z) coords
$y1 = $y0 - $j1 + self::$G3;
$z1 = $z0 - $k1 + self::$G3;
$x2 = $x0 - $i2 + 2.0 * self::$G3; // Offsets for third corner in (x,y,z) coords
$y2 = $y0 - $j2 + 2.0 * self::$G3;
$z2 = $z0 - $k2 + 2.0 * self::$G3;
$x3 = $x0 - 1.0 + 3.0 * self::$G3; // Offsets for last corner in (x,y,z) coords
$y3 = $y0 - 1.0 + 3.0 * self::$G3;
$z3 = $z0 - 1.0 + 3.0 * self::$G3;
// Work out the hashed gradient indices of the four simplex corners
$ii = $i & 255;
$jj = $j & 255;
$kk = $k & 255;
$gi0 = $this->perm[$ii + $this->perm[$jj + $this->perm[$kk]]] % 12;
$gi1 = $this->perm[$ii + $i1 + $this->perm[$jj + $j1 + $this->perm[$kk + $k1]]] % 12;
$gi2 = $this->perm[$ii + $i2 + $this->perm[$jj + $j2 + $this->perm[$kk + $k2]]] % 12;
$gi3 = $this->perm[$ii + 1 + $this->perm[$jj + 1 + $this->perm[$kk + 1]]] % 12;
// Calculate the contribution from the four corners
$t0 = 0.6 - $x0 * $x0 - $y0 * $y0 - $z0 * $z0;
if($t0 < 0){
$n0 = 0.0;
}else{
$t0 *= $t0;
$n0 = $t0 * $t0 * self::dot3D(self::$grad3[$gi0], $x0, $y0, $z0);
}
$t1 = 0.6 - $x1 * $x1 - $y1 * $y1 - $z1 * $z1;
if($t1 < 0){
$n1 = 0.0;
}else{
$t1 *= $t1;
$n1 = $t1 * $t1 * self::dot3D(self::$grad3[$gi1], $x1, $y1, $z1);
}
$t2 = 0.6 - $x2 * $x2 - $y2 * $y2 - $z2 * $z2;
if($t2 < 0){
$n2 = 0.0;
}else{
$t2 *= $t2;
$n2 = $t2 * $t2 * self::dot3D(self::$grad3[$gi2], $x2, $y2, $z2);
}
$t3 = 0.6 - $x3 * $x3 - $y3 * $y3 - $z3 * $z3;
if($t3 < 0){
$n3 = 0.0;
}else{
$t3 *= $t3;
$n3 = $t3 * $t3 * self::dot3D(self::$grad3[$gi3], $x3, $y3, $z3);
}
// Add contributions from each corner to get the noise value.
// The result is scaled to stay just inside [-1,1]
return 32.0 * ($n0 + $n1 + $n2 + $n3);
}
public function getNoise2D($x, $y){
$x += $this->offsetX;
$y += $this->offsetY;
// Skew the input space to determine which simplex cell we're in
$s = ($x + $y) * self::$F2; // Hairy factor for 2D
$i = self::floor($x + $s);
$j = self::floor($y + $s);
$t = ($i + $j) * self::$G2;
$X0 = $i - $t; // Unskew the cell origin back to (x,y) space
$Y0 = $j - $t;
$x0 = $x - $X0; // The x,y distances from the cell origin
$y0 = $y - $Y0;
// For the 2D case, the simplex shape is an equilateral triangle.
// Determine which simplex we are in.
if($x0 > $y0){
$i1 = 1;
$j1 = 0;
}// lower triangle, XY order: (0,0)->(1,0)->(1,1)
else{
$i1 = 0;
$j1 = 1;
}// upper triangle, YX order: (0,0)->(0,1)->(1,1)
// A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and
// a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where
// c = (3-sqrt(3))/6
$x1 = $x0 - $i1 + self::$G2; // Offsets for middle corner in (x,y) unskewed coords
$y1 = $y0 - $j1 + self::$G2;
$x2 = $x0 + self::$G22; // Offsets for last corner in (x,y) unskewed coords
$y2 = $y0 + self::$G22;
// Work out the hashed gradient indices of the three simplex corners
$ii = $i & 255;
$jj = $j & 255;
$gi0 = $this->perm[$ii + $this->perm[$jj]] % 12;
$gi1 = $this->perm[$ii + $i1 + $this->perm[$jj + $j1]] % 12;
$gi2 = $this->perm[$ii + 1 + $this->perm[$jj + 1]] % 12;
// Calculate the contribution from the three corners
$t0 = 0.5 - $x0 * $x0 - $y0 * $y0;
if($t0 < 0){
$n0 = 0.0;
}else{
$t0 *= $t0;
$n0 = $t0 * $t0 * self::dot2D(self::$grad3[$gi0], $x0, $y0); // (x,y) of grad3 used for 2D gradient
}
$t1 = 0.5 - $x1 * $x1 - $y1 * $y1;
if($t1 < 0){
$n1 = 0.0;
}else{
$t1 *= $t1;
$n1 = $t1 * $t1 * self::dot2D(self::$grad3[$gi1], $x1, $y1);
}
$t2 = 0.5 - $x2 * $x2 - $y2 * $y2;
if($t2 < 0){
$n2 = 0.0;
}else{
$t2 *= $t2;
$n2 = $t2 * $t2 * self::dot2D(self::$grad3[$gi2], $x2, $y2);
}
// Add contributions from each corner to get the noise value.
// The result is scaled to return values in the interval [-1,1].
return 70.0 * ($n0 + $n1 + $n2);
}
/**
* Computes and returns the 4D simplex noise for the given coordinates in
* 4D space
*
* @param x X coordinate
* @param y Y coordinate
* @param z Z coordinate
* @param w W coordinate
* @return Noise at given location, from range -1 to 1
*/
/*public function getNoise4D(x, y, z, w){
x += offsetX;
y += offsetY;
z += offsetZ;
w += offsetW;
n0, n1, n2, n3, n4; // Noise contributions from the five corners
// Skew the (x,y,z,w) space to determine which cell of 24 simplices we're in
s = (x + y + z + w) * self::$F4; // Factor for 4D skewing
i = floor(x + s);
j = floor(y + s);
k = floor(z + s);
l = floor(w + s);
t = (i + j + k + l) * self::$G4; // Factor for 4D unskewing
X0 = i - t; // Unskew the cell origin back to (x,y,z,w) space
Y0 = j - t;
Z0 = k - t;
W0 = l - t;
x0 = x - X0; // The x,y,z,w distances from the cell origin
y0 = y - Y0;
z0 = z - Z0;
w0 = w - W0;
// For the 4D case, the simplex is a 4D shape I won't even try to describe.
// To find out which of the 24 possible simplices we're in, we need to
// determine the magnitude ordering of x0, y0, z0 and w0.
// The method below is a good way of finding the ordering of x,y,z,w and
// then find the correct traversal order for the simplex were in.
// First, six pair-wise comparisons are performed between each possible pair
// of the four coordinates, and the results are used to add up binary bits
// for an integer index.
c1 = (x0 > y0) ? 32 : 0;
c2 = (x0 > z0) ? 16 : 0;
c3 = (y0 > z0) ? 8 : 0;
c4 = (x0 > w0) ? 4 : 0;
c5 = (y0 > w0) ? 2 : 0;
c6 = (z0 > w0) ? 1 : 0;
c = c1 + c2 + c3 + c4 + c5 + c6;
i1, j1, k1, l1; // The integer offsets for the second simplex corner
i2, j2, k2, l2; // The integer offsets for the third simplex corner
i3, j3, k3, l3; // The integer offsets for the fourth simplex corner
// simplex[c] is a 4-vector with the numbers 0, 1, 2 and 3 in some order.
// Many values of c will never occur, since e.g. x>y>z>w makes x<z, y<w and x<w
// impossible. Only the 24 indices which have non-zero entries make any sense.
// We use a thresholding to set the coordinates in turn from the largest magnitude.
// The number 3 in the "simplex" array is at the position of the largest coordinate.
i1 = simplex[c][0] >= 3 ? 1 : 0;
j1 = simplex[c][1] >= 3 ? 1 : 0;
k1 = simplex[c][2] >= 3 ? 1 : 0;
l1 = simplex[c][3] >= 3 ? 1 : 0;
// The number 2 in the "simplex" array is at the second largest coordinate.
i2 = simplex[c][0] >= 2 ? 1 : 0;
j2 = simplex[c][1] >= 2 ? 1 : 0;
k2 = simplex[c][2] >= 2 ? 1 : 0;
l2 = simplex[c][3] >= 2 ? 1 : 0;
// The number 1 in the "simplex" array is at the second smallest coordinate.
i3 = simplex[c][0] >= 1 ? 1 : 0;
j3 = simplex[c][1] >= 1 ? 1 : 0;
k3 = simplex[c][2] >= 1 ? 1 : 0;
l3 = simplex[c][3] >= 1 ? 1 : 0;
// The fifth corner has all coordinate offsets = 1, so no need to look that up.
x1 = x0 - i1 + self::$G4; // Offsets for second corner in (x,y,z,w) coords
y1 = y0 - j1 + self::$G4;
z1 = z0 - k1 + self::$G4;
w1 = w0 - l1 + self::$G4;
x2 = x0 - i2 + self::$G42; // Offsets for third corner in (x,y,z,w) coords
y2 = y0 - j2 + self::$G42;
z2 = z0 - k2 + self::$G42;
w2 = w0 - l2 + self::$G42;
x3 = x0 - i3 + self::$G43; // Offsets for fourth corner in (x,y,z,w) coords
y3 = y0 - j3 + self::$G43;
z3 = z0 - k3 + self::$G43;
w3 = w0 - l3 + self::$G43;
x4 = x0 + self::$G44; // Offsets for last corner in (x,y,z,w) coords
y4 = y0 + self::$G44;
z4 = z0 + self::$G44;
w4 = w0 + self::$G44;
// Work out the hashed gradient indices of the five simplex corners
ii = i & 255;
jj = j & 255;
kk = k & 255;
ll = l & 255;
gi0 = $this->perm[ii + $this->perm[jj + $this->perm[kk + $this->perm[ll]]]] % 32;
gi1 = $this->perm[ii + i1 + $this->perm[jj + j1 + $this->perm[kk + k1 + $this->perm[ll + l1]]]] % 32;
gi2 = $this->perm[ii + i2 + $this->perm[jj + j2 + $this->perm[kk + k2 + $this->perm[ll + l2]]]] % 32;
gi3 = $this->perm[ii + i3 + $this->perm[jj + j3 + $this->perm[kk + k3 + $this->perm[ll + l3]]]] % 32;
gi4 = $this->perm[ii + 1 + $this->perm[jj + 1 + $this->perm[kk + 1 + $this->perm[ll + 1]]]] % 32;
// Calculate the contribution from the five corners
t0 = 0.6 - x0 * x0 - y0 * y0 - z0 * z0 - w0 * w0;
if(t0 < 0){
n0 = 0.0;
}else{
t0 *= t0;
n0 = t0 * t0 * dot(grad4[gi0], x0, y0, z0, w0);
}
t1 = 0.6 - x1 * x1 - y1 * y1 - z1 * z1 - w1 * w1;
if(t1 < 0){
n1 = 0.0;
}else{
t1 *= t1;
n1 = t1 * t1 * dot(grad4[gi1], x1, y1, z1, w1);
}
t2 = 0.6 - x2 * x2 - y2 * y2 - z2 * z2 - w2 * w2;
if(t2 < 0){
n2 = 0.0;
}else{
t2 *= t2;
n2 = t2 * t2 * dot(grad4[gi2], x2, y2, z2, w2);
}
t3 = 0.6 - x3 * x3 - y3 * y3 - z3 * z3 - w3 * w3;
if(t3 < 0){
n3 = 0.0;
}else{
t3 *= t3;
n3 = t3 * t3 * dot(grad4[gi3], x3, y3, z3, w3);
}
t4 = 0.6 - x4 * x4 - y4 * y4 - z4 * z4 - w4 * w4;
if(t4 < 0){
n4 = 0.0;
}else{
t4 *= t4;
n4 = t4 * t4 * dot(grad4[gi4], x4, y4, z4, w4);
}
// Sum up and scale the result to cover the range [-1,1]
return 27.0 * (n0 + n1 + n2 + n3 + n4);
}*/
}

View File

@ -55,7 +55,7 @@ class SpruceTreeObject extends TreeObject{
public function placeObject(Level $level, Vector3 $pos, Random $random){ public function placeObject(Level $level, Vector3 $pos, Random $random){
if($this->leavesBottomY === -1 or $this->leavesMaxRadius === -1) { if($this->leavesBottomY === -1 or $this->leavesMaxRadius === -1) {
$this->findRandomLeavesSize(); $this->findRandomLeavesSize($random);
} }
$level->setBlockRaw(new Vector3($pos->x, $pos->y - 1, $pos->z), new DirtBlock()); $level->setBlockRaw(new Vector3($pos->x, $pos->y - 1, $pos->z), new DirtBlock());
$leavesRadius = 0; $leavesRadius = 0;

View File

@ -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,
@ -45,8 +47,8 @@ class TreeObject{
$tree = new SmallTreeObject(); $tree = new SmallTreeObject();
$tree->type = SaplingBlock::JUNGLE; $tree->type = SaplingBlock::JUNGLE;
break; break;
default:
case SaplingBlock::OAK: case SaplingBlock::OAK:
default:
/*if($random->nextRange(0, 9) === 0){ /*if($random->nextRange(0, 9) === 0){
$tree = new BigTreeObject(); $tree = new BigTreeObject();
}else{*/ }else{*/

View File

@ -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));
} }

View 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;
}
}

View 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;
}
}