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
php:
- 5.4
- 5.5
- 5.6
before_script:
- 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
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
* 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.
## 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.
* 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.
* Files MUST use only the `<?php` 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.
* Arrays SHOULD be declared using `array()`, not the `[]` shortcut.
* Argument lists MAY NOT be split across multiple lines, except long arrays.
@ -70,4 +69,4 @@ class ExampleClass{
}
}
```
```

View File

@ -32,7 +32,7 @@ class BanAPI{
private $ops;
/** @var Config */
private $bannedIPs;
private $cmdWL = array();//Command WhiteList
private $cmdWhitelist = array();//Command WhiteList
function __construct(){
$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("op", "<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("banlist", "ban list");
$this->server->api->console->alias("pardon", "ban remove");
@ -104,7 +104,6 @@ class BanAPI{
}
}
return;
break;
case "console.command"://Checks if a command is allowed with the current user permissions.
if(isset($this->cmdWhitelist[$data["cmd"]])){
return;
@ -118,7 +117,6 @@ class BanAPI{
return;
}
return false;
break;
}
}
@ -152,7 +150,7 @@ class BanAPI{
$player = $this->server->api->player->get($user);
if(!($player instanceof Player)){
$this->ops->set($user);
$this->ops->save($user);
$this->ops->save();
$output .= $user." is now op\n";
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){
return $this->cancelAction($target, $player, false);
}
@ -516,13 +516,9 @@ class BlockAPI{
public function nextRandomUpdate(Position $pos){
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);
$i = 0;
$offset = 0;
while(true){
do{
$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).";");
if($update instanceof SQLite3Result){
@ -534,7 +530,7 @@ class BlockAPI{
break;
}
$offset += mt_rand(25, 75);
}
}while(true);
$this->scheduleBlockUpdate($pos, $t / 0.05, BLOCK_UPDATE_RANDOM);
}
}

View File

@ -26,7 +26,6 @@ class ConsoleAPI{
$this->cmds = array();
$this->alias = array();
$this->server = ServerAPI::request();
$this->last = microtime(true);
}
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
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";
}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])){
$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){
@ -326,7 +325,7 @@ class ConsoleLoop extends Thread{
}
if(!extension_loaded("readline")){
@fclose($fp);
@fclose($this->fp);
}
exit(0);
}

View File

@ -94,7 +94,7 @@ class LevelAPI{
if(strtoupper($this->server->api->getProperty("level-type")) == "FLAT"){
$generator = new SuperflatGenerator($options);
}else{
$generator = new TemporalGenerator($options);
$generator = new NormalGenerator($options);
}
}
$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."/";
console("[INFO] Preparing level \"".$name."\"");
$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);
if(file_exists($path."tileEntities.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);
}
$timeu = microtime(true);
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"]);
}
@ -223,20 +226,6 @@ class LevelAPI{
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(){
return $this->levels;
}

View File

@ -20,309 +20,331 @@
*/
class PlayerAPI{
private $server;
function __construct(){
$this->server = ServerAPI::request();
}
private $server;
function __construct(){
$this->server = ServerAPI::request();
}
public function init(){
$this->server->schedule(20 * 15, array($this, "handle"), 1, true, "server.regeneration");
$this->server->addHandler("player.death", array($this, "handle"), 1);
$this->server->api->console->register("list", "", 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("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("spawn", "", array($this, "commandHandler"));
$this->server->api->console->register("ping", "", array($this, "commandHandler"));
$this->server->api->console->alias("lag", "ping");
$this->server->api->console->alias("suicide", "kill");
$this->server->api->console->alias("tppos", "tp");
$this->server->api->ban->cmdWhitelist("list");
$this->server->api->ban->cmdWhitelist("ping");
$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;");
}
public function init(){
$this->server->schedule(20 * 15, array($this, "handle"), 1, true, "server.regeneration");
$this->server->addHandler("player.death", array($this, "handle"), 1);
$this->server->api->console->register("list", "", 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("tp", "[target player] <destination player | w:world> OR /tp [target 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("ping", "", array($this, "commandHandler"));
$this->server->api->console->alias("lag", "ping");
$this->server->api->console->alias("suicide", "kill");
$this->server->api->console->alias("tppos", "tp");
$this->server->api->ban->cmdWhitelist("list");
$this->server->api->ban->cmdWhitelist("ping");
$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;");
}
public function handle($data, $event){
switch($event){
case "server.regeneration":
if($this->server->difficulty === 0){
$result = $this->server->preparedSQL->selectPlayersToHeal->execute();
if($result !== false){
while(($player = $result->fetchArray()) !== false){
if(($player = $this->server->api->entity->get($player["EID"])) !== false){
if($player->getHealth() <= 0){
continue;
}
$player->setHealth(min(20, $player->getHealth() + $data), "regeneration");
}
}
return true;
}
}
break;
case "player.death":
if(is_numeric($data["cause"])){
$e = $this->server->api->entity->get($data["cause"]);
if($e instanceof Entity){
switch($e->class){
case ENTITY_PLAYER:
$message = " was killed by ".$e->name;
break;
default:
$message = " was killed";
break;
}
}
}else{
switch($data["cause"]){
case "cactus":
$message = " was pricked to death";
break;
case "lava":
$message = " tried to swim in lava";
break;
case "fire":
$message = " went up in flames";
break;
case "burning":
$message = " burned to death";
break;
case "suffocation":
$message = " suffocated in a wall";
break;
case "water":
$message = " drowned";
break;
case "void":
$message = " fell out of the world";
break;
case "fall":
$message = " hit the ground too hard";
break;
case "explosion":
$message = " blew up";
break;
default:
$message = " died";
break;
}
}
$this->server->api->chat->broadcast($data["player"]->username . $message);
return true;
break;
}
}
public function handle($data, $event){
switch($event){
case "server.regeneration":
if($this->server->difficulty === 0){
$result = $this->server->preparedSQL->selectPlayersToHeal->execute();
if($result !== false){
while(($player = $result->fetchArray()) !== false){
if(($player = $this->server->api->entity->get($player["EID"])) !== false){
if($player->getHealth() <= 0){
continue;
}
$player->setHealth(min(20, $player->getHealth() + $data), "regeneration");
}
}
return true;
}
}
break;
case "player.death":
if(is_numeric($data["cause"])){
$e = $this->server->api->entity->get($data["cause"]);
if($e instanceof Entity){
switch($e->class){
case ENTITY_PLAYER:
$message = " was killed by ".$e->name;
break;
default:
$message = " was killed";
break;
}
}
}else{
switch($data["cause"]){
case "cactus":
$message = " was pricked to death";
break;
case "lava":
$message = " tried to swim in lava";
break;
case "fire":
$message = " went up in flames";
break;
case "burning":
$message = " burned to death";
break;
case "suffocation":
$message = " suffocated in a wall";
break;
case "water":
$message = " drowned";
break;
case "void":
$message = " fell out of the world";
break;
case "fall":
$message = " hit the ground too hard";
break;
case "explosion":
$message = " blew up";
break;
default:
$message = " died";
break;
}
}
$this->server->api->chat->broadcast($data["player"]->username . $message);
return true;
}
}
public function commandHandler($cmd, $params, $issuer, $alias){
$output = "";
switch($cmd){
case "spawnpoint":
if(!($issuer instanceof Player)){
$output .= "Please run this command in-game.\n";
break;
}
public function commandHandler($cmd, $params, $issuer, $alias){
$output = "";
switch($cmd){
case "spawnpoint":
if(count($params) === 0){
$output .= "Usage: /$cmd [player | w:world] [x] [y] [z]\n";
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){
$target = $this->server->api->player->get(array_shift($params));
}else{
$target = $issuer;
}
if(count($params) === 1 or count($params) === 4){
$tg = array_shift($params);
if(count($params) === 3 and substr($tg, 0, 2) === "w:"){
$target = $this->server->api->level->get(substr($tg, 2));
}else{
$target = $this->server->api->player->get($tg);
}
}else{
$target = $issuer;
}
if(!($target instanceof Player)){
$output .= "That player cannot be found.\n";
break;
}
if(!($target instanceof Player) and !($target instanceof Level)){
$output .= "That player cannot be found.\n";
break;
}
if(count($params) === 3){
$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);
}
if(count($params) === 3){
if($target instanceof Level){
$spawn = new Vector3(floatval(array_shift($params)), floatval(array_shift($params)), floatval(array_shift($params)));
}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";
break;
case "spawn":
if(!($issuer instanceof Player)){
$output .= "Please run this command in-game.\n";
break;
}
$issuer->teleport($this->server->spawn);
break;
case "ping":
if(!($issuer instanceof Player)){
$output .= "Please run this command in-game.\n";
break;
}
$output .= "ping ".round($issuer->getLag(), 2)."ms, packet loss ".round($issuer->getPacketLoss() * 100, 2)."%, ".round($issuer->getBandwidth() / 1024, 2)." KB/s\n";
break;
case "gamemode":
$player = false;
$setgm = false;
$gms = array(
"0" => SURVIVAL,
"survival" => SURVIVAL,
"s" => SURVIVAL,
"1" => CREATIVE,
"creative" => CREATIVE,
"c" => CREATIVE,
"2" => ADVENTURE,
"adventure" => ADVENTURE,
"a" => ADVENTURE,
"3" => VIEW,
"view" => VIEW,
"viewer" => VIEW,
"spectator" => VIEW,
"v" => VIEW,
);
if($issuer instanceof Player){
$player = $issuer;
}
if(isset($params[1])){
if($this->server->api->player->get($params[1]) instanceof Player){
$player = $this->server->api->player->get($params[1]);
$setgm = $params[0];
}elseif($this->server->api->player->get($params[0]) instanceof Player){
$player = $this->server->api->player->get($params[0]);
$setgm = $params[1];
}else{
$output .= "Usage: /$cmd <mode> [player] or /$cmd [player] <mode>\n";
break;
}
}
if(!($player instanceof Player) or !isset($gms[strtolower($setgm)])){
$output .= "Usage: /$cmd <mode> [player] or /$cmd [player] <mode>\n";
break;
}
if($player->setGamemode($gms[strtolower($setgm)])){
$output .= "Gamemode of ".$player->username." changed to ".$player->getGamemode()."\n";
}
break;
case "tp":
if(count($params) <= 2 or substr($params[0], 0, 2) === "w:" or substr($params[1], 0, 2) === "w:"){
if((!isset($params[1]) or substr($params[0], 0, 2) === "w:") and isset($params[0]) and ($issuer instanceof Player)){
$name = $issuer->username;
$target = implode(" ", $params);
}elseif(isset($params[1]) and isset($params[0])){
$name = array_shift($params);
$target = implode(" ", $params);
}else{
$output .= "Usage: /$cmd [target player] <destination player>\n";
break;
}
if($this->teleport($name, $target) !== false){
$output .= "\"$name\" teleported to \"$target\"\n";
}else{
$output .= "Couldn't teleport.\n";
}
}else{
if(!isset($params[3]) and isset($params[2]) and isset($params[1]) and isset($params[0]) and ($issuer instanceof Player)){
$name = $issuer->username;
$x = $params[0];
$y = $params[1];
$z = $params[2];
}elseif(isset($params[3]) and isset($params[2]) and isset($params[1]) and isset($params[0])){
$name = $params[0];
$x = $params[1];
$y = $params[2];
$z = $params[3];
}else{
$output .= "Usage: /$cmd [player] <x> <y> <z>\n";
break;
}
if($this->tppos($name, $x, $y, $z)){
$output .= "\"$name\" teleported to ($x, $y, $z)\n";
}else{
$output .= "Couldn't teleport.\n";
}
}
break;
case "kill":
case "suicide":
if(!isset($params[0]) and ($issuer instanceof Player)){
$player = $issuer;
}else{
$player = $this->get($params[0]);
}
if($player instanceof Player){
$player->entity->harm(1000, "console", true);
$player->sendChat("Ouch. That looks like it hurt.\n");
}else{
$output .= "Usage: /$cmd [player]\n";
}
break;
case "list":
$output .= "There are ".count($this->server->clients)."/".$this->server->maxClients." players online:\n";
if(count($this->server->clients) == 0){
break;
}
foreach($this->server->clients as $c){
$output .= $c->username.", ";
}
$output = substr($output, 0, -2)."\n";
break;
}
return $output;
}
if(!($player instanceof Player) or !isset($gms[strtolower($setgm)])){
$output .= "Usage: /$cmd <mode> [player] or /$cmd [player] <mode>\n";
break;
}
if($player->setGamemode($gms[strtolower($setgm)])){
$output .= "Gamemode of ".$player->username." changed to ".$player->getGamemode()."\n";
}
break;
case "tp":
if(count($params) <= 2 or substr($params[0], 0, 2) === "w:" or substr($params[1], 0, 2) === "w:"){
if((!isset($params[1]) or substr($params[0], 0, 2) === "w:") and isset($params[0]) and ($issuer instanceof Player)){
$name = $issuer->username;
$target = implode(" ", $params);
}elseif(isset($params[1]) and isset($params[0])){
$name = array_shift($params);
$target = implode(" ", $params);
}else{
$output .= "Usage: /$cmd [target player] <destination player | w:world>\n";
break;
}
if($this->teleport($name, $target) !== false){
$output .= "\"$name\" teleported to \"$target\"\n";
}else{
$output .= "Couldn't teleport.\n";
}
}else{
if(!isset($params[3]) and isset($params[2]) and isset($params[1]) and isset($params[0]) and ($issuer instanceof Player)){
$name = $issuer->username;
$x = $params[0];
$y = $params[1];
$z = $params[2];
}elseif(isset($params[3]) and isset($params[2]) and isset($params[1]) and isset($params[0])){
$name = $params[0];
$x = $params[1];
$y = $params[2];
$z = $params[3];
}else{
$output .= "Usage: /$cmd [player] <x> <y> <z>\n";
break;
}
if($this->tppos($name, $x, $y, $z)){
$output .= "\"$name\" teleported to ($x, $y, $z)\n";
}else{
$output .= "Couldn't teleport.\n";
}
}
break;
case "kill":
case "suicide":
if(!isset($params[0]) and ($issuer instanceof Player)){
$player = $issuer;
}else{
$player = $this->get($params[0]);
}
if($player instanceof Player){
$player->entity->harm(1000, "console", true);
$player->sendChat("Ouch. That looks like it hurt.\n");
}else{
$output .= "Usage: /$cmd [player]\n";
}
break;
case "list":
$output .= "There are ".count($this->server->clients)."/".$this->server->maxClients." players online:\n";
if(count($this->server->clients) == 0){
break;
}
foreach($this->server->clients as $c){
$output .= $c->username.", ";
}
$output = substr($output, 0, -2)."\n";
break;
}
return $output;
}
public function teleport(&$name, &$target){
if(substr($target, 0, 2) === "w:"){
$lv = $this->server->api->level->get(substr($target, 2));
if($lv instanceof Level){
$origin = $this->get($name);
if($origin instanceof Player){
$name = $origin->username;
return $origin->teleport($lv->getSafeSpawn());
}
}else{
return false;
}
}
$player = $this->get($target);
if(($player instanceof Player) and ($player->entity instanceof Entity)){
$target = $player->username;
$origin = $this->get($name);
if($origin instanceof Player){
$name = $origin->username;
return $origin->teleport($player->entity);
}
}
return false;
}
public function teleport(&$name, &$target){
if(substr($target, 0, 2) === "w:"){
$lv = $this->server->api->level->get(substr($target, 2));
if($lv instanceof Level){
$origin = $this->get($name);
if($origin instanceof Player){
$name = $origin->username;
return $origin->teleport($lv->getSafeSpawn());
}
}else{
return false;
}
}
$player = $this->get($target);
if(($player instanceof Player) and ($player->entity instanceof Entity)){
$target = $player->username;
$origin = $this->get($name);
if($origin instanceof Player){
$name = $origin->username;
return $origin->teleport($player->entity);
}
}
return false;
}
public function tppos(&$name, &$x, &$y, &$z){
$player = $this->get($name);
if(($player instanceof Player) and ($player->entity instanceof Entity)){
$name = $player->username;
$x = $x{0} === "~" ? $player->entity->x + floatval(substr($x, 1)):floatval($x);
$y = $y{0} === "~" ? $player->entity->y + floatval(substr($y, 1)):floatval($y);
$z = $z{0} === "~" ? $player->entity->z + floatval(substr($z, 1)):floatval($z);
$player->teleport(new Vector3($x, $y, $z));
return true;
}
return false;
}
public function tppos(&$name, &$x, &$y, &$z){
$player = $this->get($name);
if(($player instanceof Player) and ($player->entity instanceof Entity)){
$name = $player->username;
$x = $x{0} === "~" ? $player->entity->x + floatval(substr($x, 1)):floatval($x);
$y = $y{0} === "~" ? $player->entity->y + floatval(substr($y, 1)):floatval($y);
$z = $z{0} === "~" ? $player->entity->z + floatval(substr($z, 1)):floatval($z);
$player->teleport(new Vector3($x, $y, $z));
return true;
}
return false;
}
public function get($name, $alike = true, $multiple = false){
$name = trim(strtolower($name));
if($name === ""){
return false;
}
$query = $this->server->query("SELECT ip,port,name FROM players WHERE name ".($alike === true ? "LIKE '%".$name."%'":"= '".$name."'").";");
public function get($name, $alike = true, $multiple = false){
$name = trim(strtolower($name));
if($name === ""){
return false;
}
$query = $this->server->query("SELECT ip,port,name FROM players WHERE name ".($alike === true ? "LIKE '%".$name."%'":"= '".$name."'").";");
$players = array();
if($query !== false and $query !== true){
while(($d = $query->fetchArray(SQLITE3_ASSOC)) !== false){
$CID = PocketMinecraftServer::clientID($d["ip"], $d["port"]);
if($query !== false and $query !== true){
while(($d = $query->fetchArray(SQLITE3_ASSOC)) !== false){
$CID = MainServer::clientID($d["ip"], $d["port"]);
if(isset($this->server->clients[$CID])){
$players[$CID] = $this->server->clients[$CID];
if($multiple === false and $d["name"] === $name){
return $players[$CID];
}
}
}
}
}
if($multiple === false){
@ -334,74 +356,74 @@ class PlayerAPI{
}else{
return $players;
}
}
}
public function getAll($level = null){
if($level instanceof Level){
$clients = array();
$l = $this->server->query("SELECT EID FROM entities WHERE level = '".$level->getName()."' AND class = '".ENTITY_PLAYER."';");
if($l !== false and $l !== true){
while(($e = $l->fetchArray(SQLITE3_ASSOC)) !== false){
$e = $this->getByEID($e["EID"]);
if($e instanceof Player){
$clients[$e->CID] = $e;
}
}
}
return $clients;
}
return $this->server->clients;
}
public function getAll($level = null){
if($level instanceof Level){
$clients = array();
$l = $this->server->query("SELECT EID FROM entities WHERE level = '".$level->getName()."' AND class = '".ENTITY_PLAYER."';");
if($l !== false and $l !== true){
while(($e = $l->fetchArray(SQLITE3_ASSOC)) !== false){
$e = $this->getByEID($e["EID"]);
if($e instanceof Player){
$clients[$e->CID] = $e;
}
}
}
return $clients;
}
return $this->server->clients;
}
public function broadcastPacket(array $players, RakNetDataPacket $packet){
foreach($players as $p){
$p->dataPacket(clone $packet);
}
}
public function broadcastPacket(array $players, RakNetDataPacket $packet){
foreach($players as $p){
$p->dataPacket(clone $packet);
}
}
public function getByEID($eid){
$eid = (int) $eid;
$CID = $this->server->query("SELECT ip,port FROM players WHERE EID = '".$eid."';", true);
$CID = PocketMinecraftServer::clientID($CID["ip"], $CID["port"]);
if(isset($this->server->clients[$CID])){
return $this->server->clients[$CID];
}
return false;
}
public function getByEID($eid){
$eid = (int) $eid;
$CID = $this->server->query("SELECT ip,port FROM players WHERE EID = '".$eid."';", true);
$CID = MainServer::clientID($CID["ip"], $CID["port"]);
if(isset($this->server->clients[$CID])){
return $this->server->clients[$CID];
}
return false;
}
public function online(){
$o = array();
foreach($this->server->clients as $p){
if($p->auth === true){
$o[] = $p->username;
}
}
return $o;
}
public function online(){
$o = array();
foreach($this->server->clients as $p){
if($p->auth === true){
$o[] = $p->username;
}
}
return $o;
}
public function add($CID){
if(isset($this->server->clients[$CID])){
$player = $this->server->clients[$CID];
$player->data = $this->getOffline($player->username);
$player->gamemode = $player->data->get("gamemode");
if(($player->level = $this->server->api->level->get($player->data->get("position")["level"])) === false){
$player->level = $this->server->api->level->getDefault();
$player->data->set("position", array(
"level" => $player->level->getName(),
"x" => $player->level->getSpawn()->x,
"y" => $player->level->getSpawn()->y,
"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)."');");
}
}
public function add($CID){
if(isset($this->server->clients[$CID])){
$player = $this->server->clients[$CID];
$player->data = $this->getOffline($player->username);
$player->gamemode = $player->data->get("gamemode");
if(($player->level = $this->server->api->level->get($player->data->get("position")["level"])) === false){
$player->level = $this->server->api->level->getDefault();
$player->data->set("position", array(
"level" => $player->level->getName(),
"x" => $player->level->getSpawn()->x,
"y" => $player->level->getSpawn()->y,
"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)."');");
}
}
public function spawnAllPlayers(Player $player){
foreach($this->getAll() as $p){
if($p !== $player and ($p->entity instanceof Entity)){
$p->entity->spawn($player);
if($p->level !== $player->level){
public function spawnAllPlayers(Player $player){
foreach($this->getAll() as $p){
if($p !== $player and ($p->entity instanceof Entity)){
$p->entity->spawn($player);
if($p->level !== $player->level){
$pk = new MoveEntityPacket_PosRot;
$pk->eid = $p->entity->eid;
$pk->x = -256;
@ -409,17 +431,17 @@ class PlayerAPI{
$pk->z = -256;
$pk->yaw = 0;
$pk->pitch = 0;
$player->dataPacket($pk);
}
}
}
}
$player->dataPacket($pk);
}
}
}
}
public function spawnToAllPlayers(Player $player){
foreach($this->getAll() as $p){
if($p !== $player and ($p->entity instanceof Entity) and ($player->entity instanceof Entity)){
$player->entity->spawn($p);
if($p->level !== $player->level){
public function spawnToAllPlayers(Player $player){
foreach($this->getAll() as $p){
if($p !== $player and ($p->entity instanceof Entity) and ($player->entity instanceof Entity)){
$player->entity->spawn($p);
if($p->level !== $player->level){
$pk = new MoveEntityPacket_PosRot;
$pk->eid = $player->entity->eid;
$pk->x = -256;
@ -427,74 +449,74 @@ class PlayerAPI{
$pk->z = -256;
$pk->yaw = 0;
$pk->pitch = 0;
$p->dataPacket($pk);
}
}
}
}
$p->dataPacket($pk);
}
}
}
}
public function remove($CID){
if(isset($this->server->clients[$CID])){
$player = $this->server->clients[$CID];
unset($this->server->clients[$CID]);
$player->close();
if($player->username != "" and ($player->data instanceof Config)){
$this->saveOffline($player->data);
}
$this->server->query("DELETE FROM players WHERE name = '".$player->username."';");
if($player->entity instanceof Entity){
unset($player->entity->player);
//unset($player->entity);
}
$this->server->api->entity->remove($player->eid);
$player = null;
unset($player);
}
}
public function remove($CID){
if(isset($this->server->clients[$CID])){
$player = $this->server->clients[$CID];
unset($this->server->clients[$CID]);
$player->close();
if($player->username != "" and ($player->data instanceof Config)){
$this->saveOffline($player->data);
}
$this->server->query("DELETE FROM players WHERE name = '".$player->username."';");
if($player->entity instanceof Entity){
unset($player->entity->player);
//unset($player->entity);
}
$this->server->api->entity->remove($player->eid);
$player = null;
unset($player);
}
}
public function getOffline($name){
$iname = strtolower($name);
$default = array(
"caseusername" => $name,
"position" => array(
"level" => $this->server->spawn->level->getName(),
"x" => $this->server->spawn->x,
"y" => $this->server->spawn->y,
"z" => $this->server->spawn->z,
),
"spawn" => array(
"level" => $this->server->spawn->level->getName(),
"x" => $this->server->spawn->x,
"y" => $this->server->spawn->y,
"z" => $this->server->spawn->z,
),
"inventory" => array_fill(0, PLAYER_SURVIVAL_SLOTS, array(AIR, 0, 0)),
public function getOffline($name){
$iname = strtolower($name);
$default = array(
"caseusername" => $name,
"position" => array(
"level" => $this->server->spawn->level->getName(),
"x" => $this->server->spawn->x,
"y" => $this->server->spawn->y,
"z" => $this->server->spawn->z,
),
"spawn" => array(
"level" => $this->server->spawn->level->getName(),
"x" => $this->server->spawn->x,
"y" => $this->server->spawn->y,
"z" => $this->server->spawn->z,
),
"inventory" => array_fill(0, PLAYER_SURVIVAL_SLOTS, array(AIR, 0, 0)),
"hotbar" => array(0, -1, -1, -1, -1, -1, -1, -1, -1),
"armor" => array_fill(0, 4, array(AIR, 0)),
"gamemode" => $this->server->gamemode,
"health" => 20,
"lastIP" => "",
"lastID" => 0,
"achievements" => array(),
);
"armor" => array_fill(0, 4, array(AIR, 0)),
"gamemode" => $this->server->gamemode,
"health" => 20,
"lastIP" => "",
"lastID" => 0,
"achievements" => array(),
);
if(!file_exists(DATA_PATH."players/".$iname.".yml")){
console("[NOTICE] Player data not found for \"".$iname."\", creating new profile");
$data = new Config(DATA_PATH."players/".$iname.".yml", CONFIG_YAML, $default);
$data->save();
}else{
$data = new Config(DATA_PATH."players/".$iname.".yml", CONFIG_YAML, $default);
}
if(!file_exists(DATA_PATH."players/".$iname.".yml")){
console("[NOTICE] Player data not found for \"".$iname."\", creating new profile");
$data = new Config(DATA_PATH."players/".$iname.".yml", CONFIG_YAML, $default);
$data->save();
}else{
$data = new Config(DATA_PATH."players/".$iname.".yml", CONFIG_YAML, $default);
}
if(($data->get("gamemode") & 0x01) === 1){
$data->set("health", 20);
}
$this->server->handle("player.offline.get", $data);
return $data;
}
if(($data->get("gamemode") & 0x01) === 1){
$data->set("health", 20);
}
$this->server->handle("player.offline.get", $data);
return $data;
}
public function saveOffline(Config $data){
$this->server->handle("player.offline.save", $data);
$data->save();
}
public function saveOffline(Config $data){
$this->server->handle("player.offline.save", $data);
$data->save();
}
}

View File

@ -26,6 +26,30 @@ class PluginAPI extends stdClass{
public function __construct(){
$this->server = ServerAPI::request();
$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(){
@ -172,19 +196,6 @@ class PluginAPI extends stdClass{
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){
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 $asyncCnt = 0;
private $rcon;
private $query;
public $query;
//TODO: Instead of hard-coding functions, use PHPDoc-compatible methods to load APIs.
@ -78,7 +79,7 @@ class ServerAPI{
public $tile;
/**
* @return PocketMinecraftServer
* @return MainServer
*/
public static function request(){
return self::$serverRequest;
@ -97,6 +98,14 @@ class ServerAPI{
@mkdir(DATA_PATH."players/", 0755);
@mkdir(DATA_PATH."worlds/", 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();
console("[INFO] Starting Minecraft PE server version ".FORMAT_AQUA.CURRENT_MINECRAFT_VERSION);
@ -129,33 +138,29 @@ class ServerAPI{
"enable-query" => true,
"enable-rcon" => false,
"rcon.password" => substr(base64_encode(Utils::getRandomBytes(20, false)), 3, 10),
"send-usage" => true,
"auto-save" => true,
));
$this->parseProperties();
//Load advanced properties
define("DEBUG", $this->getProperty("debug", 1));
define("ADVANCED_CACHE", $this->getProperty("enable-advanced-cache", false));
if($this->getProperty("port") !== false){
$this->setProperty("server-port", $this->getProperty("port"));
$this->config->remove("port");
$this->config->remove("invisible");
define("MAX_CHUNK_RATE", 20 / $this->getProperty("max-chunks-per-second", 7)); //Default rate ~448 kB/s
if(ADVANCED_CACHE == true){
console("[INFO] Advanced cache enabled");
}
$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;
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] 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()){
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");
@ -287,7 +292,7 @@ class ServerAPI{
$this->setProperty("memory-limit", "128M");
}
if($this->server instanceof PocketMinecraftServer){
if($this->server instanceof MainServer){
$this->server->setType($this->getProperty("server-type"));
$this->server->maxClients = $this->getProperty("max-players");
$this->server->description = $this->getProperty("description");
@ -333,11 +338,11 @@ class ServerAPI{
}
public function init(){
if(!(self::$serverRequest instanceof PocketMinecraftServer)){
if(!(self::$serverRequest instanceof MainServer)){
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->sendUsage();
}
@ -349,7 +354,7 @@ class ServerAPI{
}
if($this->getProperty("enable-query") === true){
$this->query = new Query();
$this->query = new QueryHandler();
}
CraftingRecipes::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 $serverID, $interface, $database, $version, $invisible, $tickMeasure, $preparedSQL, $seed, $gamemode, $name, $maxClients, $clients, $eidCnt, $custom, $description, $motd, $port, $saveEnabled;
private $serverip, $evCnt, $handCnt, $events, $eventsID, $handlers, $serverType, $lastTick, $ticks, $memoryStats, $async = array(), $asyncID = 0;
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, $doTick, $ticks, $memoryStats, $schedule, $asyncThread, $async = array(), $asyncID = 0;
/**
* @var ServerAPI
@ -45,10 +45,7 @@ class PocketMinecraftServer{
$this->eventsID = array();
$this->handlers = array();
$this->invisible = false;
$this->levelData = false;
$this->difficulty = 1;
$this->tiles = array();
$this->entities = array();
$this->custom = array();
$this->evCnt = 1;
$this->handCnt = 1;
@ -57,14 +54,14 @@ class PocketMinecraftServer{
$this->schedule = array();
$this->scheduleCnt = 1;
$this->description = "";
$this->whitelist = false;
$this->memoryStats = array();
$this->clients = array();
$this->spawn = false;
$this->saveEnabled = true;
$this->whitelist = false;
$this->tickMeasure = array_fill(0, 40, 0);
$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->ticks = 0;
if(!defined("NO_THREADS")){
@ -129,7 +126,7 @@ class PocketMinecraftServer{
public function startDatabase(){
$this->preparedSQL = 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 encoding = \"UTF-8\";");
$this->query("PRAGMA secure_delete = OFF;");
@ -231,6 +228,10 @@ class PocketMinecraftServer{
$d .= Utils::writeShort(strlen($key)).$key . Utils::writeInt(strlen($value)).$value;
}
break;
case ASYNC_FUNCTION:
$params = serialize($data["arguments"]);
$d .= Utils::writeShort(strlen($data["function"])).$data["function"] . Utils::writeInt(strlen($params)) . $params;
break;
default:
return false;
}
@ -259,6 +260,12 @@ class PocketMinecraftServer{
$data["result"] = substr($this->asyncThread->output, $offset, $len);
$offset += $len;
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);
if(isset($this->async[$ID]) and $this->async[$ID] !== null and is_callable($this->async[$ID])){
@ -316,7 +323,6 @@ class PocketMinecraftServer{
$handlers->finalize();
foreach($call as $hnid => $boolean){
if($result !== false and $result !== true){
$called[$hnid] = true;
$handler = $this->handlers[$hnid];
if(is_array($handler)){
$method = $handler[1];
@ -388,6 +394,7 @@ class PocketMinecraftServer{
if($this->stop === true){
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");
$dump = "```\r\n# PocketMine-MP Error Dump ".date("D M j H:i:s T Y")."\r\n";
$er = error_get_last();
@ -420,6 +427,11 @@ class PocketMinecraftServer{
$dump .= "[".($l + 1)."] ".@$file[$l]."\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();
$dump .= "PocketMine-MP version: ".$version." #".$version->getNumber()." [Protocol ".ProtocolInfo::CURRENT_PROTOCOL."; API ".CURRENT_API_VERSION."]\r\n";
$dump .= "Git commit: ".GIT_COMMIT."\r\n";
@ -451,6 +463,7 @@ class PocketMinecraftServer{
}
$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";
ob_start();
phpinfo();
@ -479,7 +492,7 @@ class PocketMinecraftServer{
public function packetHandler(Packet $packet){
$data =& $packet;
$CID = PocketMinecraftServer::clientID($packet->ip, $packet->port);
$CID = MainServer::clientID($packet->ip, $packet->port);
if(isset($this->clients[$CID])){
$this->clients[$CID]->handlePacket($packet);
}else{

View File

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

View File

@ -1,17 +1,16 @@
#!/bin/bash
COMPILER_VERSION="0.16"
PHP_VERSION="5.5.9"
PHP_VERSION="5.5.10"
ZEND_VM="GOTO"
LIBEDIT_VERSION="0.3"
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"
PHPYAML_VERSION="1.1.1"
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)"
date > "$DIR/install.log" 2>&1
uname -a >> "$DIR/install.log" 2>&1
@ -42,43 +41,82 @@ export CC="gcc"
COMPILE_FOR_ANDROID=no
RANLIB=ranlib
HAVE_MYSQLI="--with-mysqli=mysqlnd"
if [ "$1" == "rpi" ]; then
[ -z "$march" ] && march=armv6zk;
[ -z "$mtune" ] && mtune=arm1176jzf-s;
[ -z "$CFLAGS" ] && CFLAGS="-mfloat-abi=hard -mfpu=vfp";
echo "[INFO] Compiling for Raspberry Pi ARMv6zk hard float"
elif [ "$1" == "mac" ]; then
[ -z "$march" ] && march=prescott;
[ -z "$mtune" ] && mtune=generic;
[ -z "$CFLAGS" ] && CFLAGS="-fomit-frame-pointer";
echo "[INFO] Compiling for Intel MacOS"
elif [ "$1" == "ios" ]; then
[ -z "$march" ] && march=armv6;
[ -z "$mtune" ] && mtune=cortex-a8;
echo "[INFO] Compiling for iOS ARMv6"
elif [ "$1" == "crosscompile" ]; then
HAVE_MYSQLI="--without-mysqli"
if [ "$2" == "android" ] || [ "$2" == "android-armv6" ]; then
COMPILE_TARGET=""
COMPILE_OPENSSL="no"
COMPILE_CURL="default"
COMPILE_LIBEDIT="no"
IS_CROSSCOMPILE="no"
DO_OPTIMIZE="no"
while getopts "::t:oj:cxff:" OPTION; do
case $OPTION in
t)
echo "[opt] Set target to $OPTARG"
COMPILE_TARGET="$OPTARG"
;;
j)
echo "[opt] Set make threads to $OPTARG"
THREADS="$OPTARG"
;;
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
[ -z "$march" ] && march=armv6;
[ -z "$mtune" ] && mtune=arm1136jf-s;
TOOLCHAIN_PREFIX="arm-unknown-linux-uclibcgnueabi"
export CC="$TOOLCHAIN_PREFIX-gcc"
CONFIGURE_FLAGS="--host=$TOOLCHAIN_PREFIX --enable-static-link --disable-ipv6"
CFLAGS="-uclibc --static $CFLAGS";
LDFLAGS="--static"
CFLAGS="-static -uclibc -Wl,-Bdynamic $CFLAGS"
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
[ -z "$march" ] && march=armv7-a;
[ -z "$mtune" ] && mtune=cortex-a8;
TOOLCHAIN_PREFIX="arm-unknown-linux-uclibcgnueabi"
export CC="$TOOLCHAIN_PREFIX-gcc"
CONFIGURE_FLAGS="--host=$TOOLCHAIN_PREFIX --enable-static-link --disable-ipv6"
CFLAGS="-uclibc --static $CFLAGS";
LDFLAGS="--static"
CFLAGS="-static -uclibc -Wl,-Bdynamic $CFLAGS"
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"
[ -z "$march" ] && march=armv6zk;
[ -z "$mtune" ] && mtune=arm1176jzf-s;
@ -86,8 +124,9 @@ elif [ "$1" == "crosscompile" ]; then
export CC="$TOOLCHAIN_PREFIX-gcc"
CONFIGURE_FLAGS="--host=$TOOLCHAIN_PREFIX"
[ -z "$CFLAGS" ] && CFLAGS="-uclibc";
OPENSSL_TARGET="linux-armv4"
echo "[INFO] Cross-compiling for Raspberry Pi ARMv6zk hard float"
elif [ "$2" == "mac" ]; then
elif [ "$COMPILE_TARGET" == "mac" ]; then
[ -z "$march" ] && march=prescott;
[ -z "$mtune" ] && mtune=generic;
[ -z "$CFLAGS" ] && CFLAGS="-fomit-frame-pointer";
@ -96,33 +135,75 @@ elif [ "$1" == "crosscompile" ]; then
CONFIGURE_FLAGS="--host=$TOOLCHAIN_PREFIX"
#zlib doesn't use the correct ranlib
RANLIB=$TOOLCHAIN_PREFIX-ranlib
OPENSSL_TARGET="darwin64-x86_64-cc"
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 "$mtune" ] && mtune=generic-armv6;
CONFIGURE_FLAGS="--target=arm-apple-darwin10"
elif [ "$2" == "ios-armv7" ]; then
[ -z "$mtune" ] && mtune=arm1176jzf-s;
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"
elif [ "$COMPILE_TARGET" == "ios-armv7" ]; then
[ -z "$march" ] && march=armv7-a;
[ -z "$mtune" ] && mtune=generic-armv7-a;
CONFIGURE_FLAGS="--target=arm-apple-darwin10"
[ -z "$mtune" ] && mtune=cortex-a8;
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
echo "Please supply a proper platform [android android-armv6 android-armv7 rpi mac ios ios-armv6 ios-armv7] to cross-compile"
exit 1
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
if [ `getconf LONG_BIT` = "64" ]; then
if [ `getconf LONG_BIT` == "64" ]; then
echo "[INFO] Compiling for current machine using 64-bit"
CFLAGS="-m64 $CFLAGS"
OPENSSL_TARGET="linux-x86_64"
else
echo "[INFO] Compiling for current machine using 32-bit"
CFLAGS="-m32 $CFLAGS"
OPENSSL_TARGET="linux-generic32"
fi
fi
cat > test.c <<'CTEST'
#include <stdio.h>
main(){
int main(void){
printf("Hello world\n");
return 0;
}
CTEST
@ -133,7 +214,7 @@ type $CC >> "$DIR/install.log" 2>&1 || { echo >&2 "[ERROR] Please install \"$CC\
[ -z "$march" ] && march=native;
[ -z "$mtune" ] && mtune=native;
[ -z "$CFLAGS" ] && CFLAGS="";
[ -z "$LDFLAGS" ] && LDFLAGS="";
[ -z "$LDFLAGS" ] && LDFLAGS="-Wl,-rpath='\$\$ORIGIN/../lib'";
[ -z "$CONFIGURE_FLAGS" ] && CONFIGURE_FLAGS="";
@ -149,16 +230,17 @@ else
fi
fi
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 LDFLAGS="$LDFLAGS"
rm -r -f install_data/ >> "$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 0777 bin >> "$DIR/install.log" 2>&1
mkdir -m 0755 install_data >> "$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
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
echo " done!"
if [ 1 ] || [ "$1" == "crosscompile" ] || [ "$1" == "rpi" ]; then
HAVE_LIBEDIT="--without-libedit"
if [ "$IS_CROSSCOMPILE" == "yes" ] || [ "$COMPILE_TARGET" == "rpi" ] || [ "$COMPILE_TARGET" == "mac" ] || [ "$COMPILE_LIBEDIT" != "yes" ]; then
HAVE_LIBEDIT="--without-readline --without-libedit"
else
#libedit
set +e
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
echo -n " checking..."
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..."
if make -j $THREADS >> "$DIR/install.log" 2>&1; then
echo -n " installing..."
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
echo -n " disabling..."
HAVE_LIBEDIT="--without-libedit"
HAVE_LIBEDIT="--without-readline --without-libedit"
fi
echo -n " cleaning..."
cd ..
rm -r -f ./libedit
echo " done!"
set -e
fi
#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..."
download_file "http://zlib.net/zlib-$ZLIB_VERSION.tar.gz" | tar -zx >> "$DIR/install.log" 2>&1
mv zlib-$ZLIB_VERSION zlib
echo -n " checking..."
cd zlib
RANLIB=$RANLIB ./configure --prefix="$DIR/install_data/php/ext/zlib" \
--static >> "$DIR/install.log" 2>&1
RANLIB=$RANLIB ./configure --prefix="$DIR/bin/php5" \
--shared >> "$DIR/install.log" 2>&1
echo -n " compiling..."
make -j $THREADS >> "$DIR/install.log" 2>&1
echo -n " installing..."
@ -209,7 +296,48 @@ cd ..
rm -r -f ./zlib
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"
else
#curl
@ -221,13 +349,14 @@ else
if [ ! -f ./configure ]; then
./buildconf --force >> "$DIR/install.log" 2>&1
fi
./configure --disable-dependency-tracking \
RANLIB=$RANLIB ./configure --disable-dependency-tracking \
--enable-ipv6 \
--enable-optimize \
--enable-http \
--enable-ftp \
--disable-dict \
--enable-file \
--without-librtmp \
--disable-gopher \
--disable-imap \
--disable-pop3 \
@ -238,8 +367,10 @@ else
--disable-ldap \
--disable-ldaps \
--without-libidn \
--with-zlib="$DIR/bin/php5" \
$WITH_SSL \
--enable-threaded-resolver \
--prefix="$DIR/install_data/php/ext/curl" \
--prefix="$DIR/bin/php5" \
--disable-shared \
--enable-static \
$CONFIGURE_FLAGS >> "$DIR/install.log" 2>&1
@ -251,7 +382,7 @@ else
cd ..
rm -r -f ./curl
echo " done!"
HAVE_CURL="$DIR/install_data/php/ext/curl"
HAVE_CURL="$DIR/bin/php5"
fi
#pthreads
@ -273,9 +404,9 @@ mv yaml-$YAML_VERSION yaml
echo -n " checking..."
cd yaml
RANLIB=$RANLIB ./configure \
--prefix="$DIR/install_data/php/ext/yaml" \
--enable-static \
--disable-shared \
--prefix="$DIR/bin/php5" \
--disable-static \
--enable-shared \
$CONFIGURE_FLAGS >> "$DIR/install.log" 2>&1
echo -n " compiling..."
make -j $THREADS >> "$DIR/install.log" 2>&1
@ -287,37 +418,29 @@ rm -r -f ./yaml
echo " done!"
echo -n "[PHP]"
set +e
if which free >/dev/null; 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
if [ "$DO_OPTIMIZE" != "no" ]; then
echo -n " enabling optimizations..."
OPTIMIZATION="--enable-inline-optimization "
PHP_OPTIMIZATION="--enable-inline-optimization "
else
OPTIMIZATION="--disable-inline-optimization "
PHP_OPTIMIZATION="--disable-inline-optimization "
fi
set -e
echo -n " checking..."
cd php
rm -rf ./aclocal.m4 >> "$DIR/install.log" 2>&1
rm -rf ./autom4te.cache/ >> "$DIR/install.log" 2>&1
rm -f ./configure >> "$DIR/install.log" 2>&1
./buildconf --force >> "$DIR/install.log" 2>&1
if [ "$1" == "crosscompile" ]; then
sed -i 's/pthreads_working=no/pthreads_working=yes/' ./configure
export LIBS="-lpthread -ldl"
if [ "$IS_CROSSCOMPILE" == "yes" ]; then
sed -i=".backup" 's/pthreads_working=no/pthreads_working=yes/' ./configure
export LIBS="-lpthread -ldl -lresolv"
CONFIGURE_FLAGS="$CONFIGURE_FLAGS --enable-opcache=no"
fi
./configure $OPTIMIZATION--prefix="$DIR/bin/php5" \
RANLIB=$RANLIB ./configure $PHP_OPTIMIZATION--prefix="$DIR/bin/php5" \
--exec-prefix="$DIR/bin/php5" \
--with-curl="$HAVE_CURL" \
--with-zlib="$DIR/install_data/php/ext/zlib" \
--with-zlib-dir="$DIR/install_data/php/ext/zlib" \
--with-yaml="$DIR/install_data/php/ext/yaml" \
--with-zlib="$DIR/bin/php5" \
--with-yaml="$DIR/bin/php5" \
$HAVE_LIBEDIT \
--disable-libxml \
--disable-xml \
@ -328,11 +451,11 @@ $HAVE_LIBEDIT \
--disable-cgi \
--disable-session \
--disable-debug \
--disable-phar \
--disable-pdo \
--without-pear \
--without-iconv \
--without-pdo-sqlite \
--enable-phar \
--enable-ctype \
--enable-sockets \
--enable-shared=no \
@ -350,39 +473,63 @@ $HAVE_MYSQLI \
--with-zend-vm=$ZEND_VM \
$CONFIGURE_FLAGS >> "$DIR/install.log" 2>&1
echo -n " compiling..."
if [ $COMPILE_FOR_ANDROID == "yes" ]; then
sed -i 's/-export-dynamic/-all-static/g' Makefile
if [ "$COMPILE_FOR_ANDROID" == "yes" ]; then
sed -i=".backup" 's/-export-dynamic/-all-static/g' Makefile
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
echo -n " installing..."
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)
touch "$DIR/bin/php5/lib/php.ini"
if [ "$1" != "crosscompile" ]; then
OPCACHE_PATH=$(find "$DIR/bin/php5" -name opcache.so)
echo "zend_extension=\"$OPCACHE_PATH\"" >> "$DIR/bin/php5/lib/php.ini"
echo "opcache.enable=1" >> "$DIR/bin/php5/lib/php.ini"
echo "opcache.enable_cli=1" >> "$DIR/bin/php5/lib/php.ini"
echo "opcache.save_comments=0" >> "$DIR/bin/php5/lib/php.ini"
echo "opcache.fast_shutdown=1" >> "$DIR/bin/php5/lib/php.ini"
echo "opcache.max_accelerated_files=4096" >> "$DIR/bin/php5/lib/php.ini"
echo "opcache.interned_strings_buffer=8" >> "$DIR/bin/php5/lib/php.ini"
echo "opcache.memory_consumption=128" >> "$DIR/bin/php5/lib/php.ini"
echo "opcache.optimization_level=0xffffffff" >> "$DIR/bin/php5/lib/php.ini"
echo "date.timezone=$TIMEZONE" > "$DIR/bin/php5/bin/php.ini"
echo "short_open_tag=0" >> "$DIR/bin/php5/bin/php.ini"
echo "asp_tags=0" >> "$DIR/bin/php5/bin/php.ini"
echo "phar.readonly=0" >> "$DIR/bin/php5/bin/php.ini"
echo "phar.require_hash=1" >> "$DIR/bin/php5/bin/php.ini"
if [ "$IS_CROSSCOMPILE" != "crosscompile" ]; then
echo "zend_extension=opcache.so" >> "$DIR/bin/php5/bin/php.ini"
echo "opcache.enable=1" >> "$DIR/bin/php5/bin/php.ini"
echo "opcache.enable_cli=1" >> "$DIR/bin/php5/bin/php.ini"
echo "opcache.save_comments=0" >> "$DIR/bin/php5/bin/php.ini"
echo "opcache.fast_shutdown=1" >> "$DIR/bin/php5/bin/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
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
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!"
cd "$DIR"
echo -n "[INFO] Cleaning up..."
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
echo " done!"
echo "[PocketMine] You should start the server now using \"./start.sh.\""

View File

@ -1,10 +1,17 @@
#!/bin/bash
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"
# Temporal build
ODROID_BUILD="PHP_5.5.9_ARM_Raspbian_hard"
AND_BUILD="PHP_5.5.9_ARMv7_Android"
IOS_BUILD="PHP_5.5.9_ARMv6_iOS"
update=off
forcecompile=off
alldone=no
#Needed to use aliases
shopt -s expand_aliases
@ -21,11 +28,14 @@ else
fi
while getopts "udv:" opt; do
while getopts "ucdv:" opt; do
case $opt in
u)
update=on
;;
c)
forcecompile=on
;;
d)
PMMP_VERSION="master"
;;
@ -58,79 +68,175 @@ rm -f LICENSE
rm -f start.sh
rm -f start.bat
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
mv -f PocketMine-MP-$PMMP_VERSION/* ./
rm -f -r PocketMine-MP-$PMMP_VERSION/
rm -f ./start.cmd
chmod +x ./start.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"
else
echo -n "[3/3] Obtaining PHP:"
echo " detecting if build is available..."
if [ "$(uname -s)" == "Darwin" ]; then
if [ "$forcecompile" == "off" ] && [ "$(uname -s)" == "Darwin" ]; then
set +e
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
if [ $IS_IOS -gt 0 ]; then
if [[ "$IS_IOS" -gt 0 ]]; then
rm -r -f bin/ >> /dev/null 2>&1
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
chmod +x ./bin/php5/bin/*
echo -n " regenerating php.ini..."
echo "date.timezone=$TIMEZONE" >> "./bin/php5/lib/php.ini"
echo "short_open_tag=0" >> "./bin/php5/lib/php.ini"
echo "asp_tags=0" >> "./bin/php5/lib/php.ini"
echo " done"
echo -n " checking..."
if [ $(./bin/php5/bin/php -r 'echo "yes";' 2>/dev/null) == "yes" ]; then
echo -n " regenerating php.ini..."
TIMEZONE=$(date +%Z)
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
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
chmod +x ./bin/php5/bin/*
echo -n " regenerating php.ini..."
OPCACHE_PATH=$(find "./bin/php5" -name opcache.so)
echo "zend_extension=\"$OPCACHE_PATH\"" > "./bin/php5/lib/php.ini"
echo "opcache.enable=1" >> "./bin/php5/lib/php.ini"
echo "opcache.enable_cli=1" >> "./bin/php5/lib/php.ini"
echo "opcache.save_comments=0" >> "./bin/php5/lib/php.ini"
echo "opcache.fast_shutdown=1" >> "./bin/php5/lib/php.ini"
echo "opcache.max_accelerated_files=4096" >> "./bin/php5/lib/php.ini"
echo "opcache.interned_strings_buffer=8" >> "./bin/php5/lib/php.ini"
echo "opcache.memory_consumption=128" >> "./bin/php5/lib/php.ini"
echo "opcache.optimization_level=0xffffffff" >> "./bin/php5/lib/php.ini"
echo "date.timezone=$TIMEZONE" >> "./bin/php5/lib/php.ini"
echo "short_open_tag=0" >> "./bin/php5/lib/php.ini"
echo "asp_tags=0" >> "./bin/php5/lib/php.ini"
echo " done"
echo -n " checking..."
if [ $(./bin/php5/bin/php -r 'echo "yes";' 2>/dev/null) == "yes" ]; then
echo -n " regenerating php.ini..."
TIMEZONE=$(date +%Z)
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
else
set +e
grep -q BCM2708 /proc/cpuinfo > /dev/null 2>&1
if [ $? -eq 0 ]; then
set -e
IS_RPI=$?
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
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
chmod +x ./bin/php5/bin/*
echo -n " regenerating php.ini..."
OPCACHE_PATH=$(find "./bin/php5" -name opcache.so)
echo "zend_extension=\"$OPCACHE_PATH\"" > "./bin/php5/lib/php.ini"
echo "opcache.enable=1" >> "./bin/php5/lib/php.ini"
echo "opcache.enable_cli=1" >> "./bin/php5/lib/php.ini"
echo "opcache.save_comments=0" >> "./bin/php5/lib/php.ini"
echo "opcache.fast_shutdown=1" >> "./bin/php5/lib/php.ini"
echo "opcache.max_accelerated_files=4096" >> "./bin/php5/lib/php.ini"
echo "opcache.interned_strings_buffer=8" >> "./bin/php5/lib/php.ini"
echo "opcache.memory_consumption=128" >> "./bin/php5/lib/php.ini"
echo "opcache.optimization_level=0xffffffff" >> "./bin/php5/lib/php.ini"
echo "date.timezone=$TIMEZONE" >> "./bin/php5/lib/php.ini"
echo "short_open_tag=0" >> "./bin/php5/lib/php.ini"
echo "asp_tags=0" >> "./bin/php5/lib/php.ini"
echo " done"
else
echo -n " checking..."
if [ $(./bin/php5/bin/php -r 'echo "yes";' 2>/dev/null) == "yes" ]; then
echo -n " regenerating php.ini..."
TIMEZONE=$(date +%Z)
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 [ "$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
echo "[3/3] no build found, compiling PHP"
exec ./src/build/compile.sh

View File

@ -1,6 +1,7 @@
#!/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
PHP_VERSION="5.5.10"
#Needed to use 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
chmod +x $WORKSPACE/compile.sh
SCRIPT="$WORKSPACE/compile.sh"
ARCHIVE=$WORKSPACE/archive
COMPILEDIR=$WORKSPACE/compile
rm -rf $ARCHIVE $COMPILEDIR
mkdir -p $ARCHIVE
mkdir -p $COMPILEDIR
ARCHIVE="$WORKSPACE/archive"
COMPILEDIR="$WORKSPACE/compile"
rm -rf "$ARCHIVE" "$COMPILEDIR"
mkdir -p "$ARCHIVE"
mkdir -p "$COMPILEDIR"
if [ "$COMPILE_LINUX_32BIT" = "true" ];
then
mkdir -p {$COMPILEDIR,$ARCHIVE}/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
exit 1
fi
@ -44,18 +46,19 @@ then
mkdir -p {$COMPILEDIR,$ARCHIVE}/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
exit 1
fi
fi
if [ "$COMPILE_MAC" = "true" ];
if [ "$COMPILE_MAC_32" = "true" ];
then
mkdir -p {$COMPILEDIR,$ARCHIVE}/mac
cd $COMPILEDIR/mac
mkdir -p {$COMPILEDIR,$ARCHIVE}/mac32
cd $COMPILEDIR/mac32
curl -L http://ftpmirror.gnu.org/libtool/libtool-2.4.2.tar.gz | tar -xz > /dev/null
cd libtool-2.4.2
@ -66,10 +69,34 @@ then
rm -rf libtool-2.4.2
export LIBTOOL="$COMPILEDIR/mac/libtool/bin/libtool"
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/
if [ ! -f $COMPILEDIR/mac/bin/php5/bin/php ]; then
tar -czf PHP_${PHP_VERSION}_x86_MacOS.tar.gz bin/
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
fi
fi
@ -79,9 +106,10 @@ then
mkdir -p {$COMPILEDIR,$ARCHIVE}/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
exit 1
fi
@ -92,9 +120,10 @@ then
mkdir -p {$COMPILEDIR,$ARCHIVE}/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
exit 1
fi
@ -105,9 +134,10 @@ then
mkdir -p {$COMPILEDIR,$ARCHIVE}/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
exit 1
fi
@ -126,7 +156,7 @@ then
rm -rf libtool-2.4.2
export LIBTOOL="$COMPILEDIR/crosscompile/ios-armv6/libtool/bin/libtool"
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/
if [ ! -f $COMPILEDIR/crosscompile/ios-armv6/bin/php5/bin/php ]; then
@ -147,7 +177,7 @@ then
rm -rf libtool-2.4.2
export LIBTOOL="$COMPILEDIR/crosscompile/ios-armv7/libtool/bin/libtool"
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/
if [ ! -f $COMPILEDIR/crosscompile/ios-armv7/bin/php5/bin/php ]; then
@ -160,9 +190,10 @@ then
mkdir -p {$COMPILEDIR,$ARCHIVE}/crosscompile/rpi
cd $COMPILEDIR/crosscompile/rpi
$SCRIPT crosscompile rpi
cp -r $COMPILEDIR/crosscompile/rpi/{install.log,bin/*,install_data/*} $ARCHIVE/crosscompile/rpi/
$SCRIPT -t rpi -o -j 1 -c -x -f arm
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
exit 1
fi
@ -173,7 +204,7 @@ then
mkdir -p {$COMPILEDIR,$ARCHIVE}/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/
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
define("LOG", true);
define("START_TIME", microtime(true));
define("MAJOR_VERSION", "Alpha_1.3.12dev");
define("CODENAME", "変梃(Henteko)マインカート(Minecart)");
define("MAJOR_VERSION", "Alpha_1.4dev");
define("CODENAME", "絶好(Zekkou)ケーキ(Cake)");
define("CURRENT_MINECRAFT_VERSION", "v0.8.1 alpha");
define("CURRENT_API_VERSION", 12);
define("CURRENT_API_VERSION", 13);
define("CURRENT_PHP_VERSION", "5.5");
$gitsha1 = false;
if(file_exists(FILE_PATH.".git/refs/heads/master")){ //Found Git information!

View File

@ -31,7 +31,6 @@ define("VIEWER", 3);
//Players
define("MAX_CHUNK_RATE", 20 / arg("max-chunks-per-second", 4)); //Default rate ~256 kB/s
define("PLAYER_MAX_QUEUE", 1024);
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();
}
array_shift( $args );
$args = join( $args, ' ' );
$args = implode(' ', $args);
preg_match_all('/ (--[\w\-]+ (?:[= ] [^-\s]+ )? ) | (-\w+) | (\w+) /x', $args, $match );
$args = array_shift( $match );
@ -158,7 +158,7 @@ function arguments ( $args ){
$value = preg_split( '/[= ]/', $arg, 2 );
$com = substr( array_shift($value), 2 );
$value = join($value);
$value = implode($value);
$ret['commands'][$com] = !empty($value) ? $value : true;
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){
if(error_reporting() === 0){ //@ error-control
return false;
@ -241,6 +256,9 @@ function error_handler($errno, $errstr, $errfile, $errline){
);
$errno = isset($errorConversion[$errno]) ? $errorConversion[$errno]:$errno;
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;
}

View File

@ -41,7 +41,7 @@ class SignPostBlock extends TransparentBlock{
return true;
}else{
$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;
}
}

View File

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

View File

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

View File

@ -104,7 +104,11 @@ class RCONInstance extends Thread{
}
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){

View File

@ -22,7 +22,7 @@
class UDPSocket{
public $connected, $sock, $server;
public $connected, $sock, $server, $port;
function __construct($server, $port, $listen = false, $serverip = "0.0.0.0"){
$this->server = $server;
$this->port = $port;
@ -34,7 +34,7 @@ class UDPSocket{
}else{
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_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
$this->unblock();
$this->connected = true;
@ -45,7 +45,6 @@ class UDPSocket{
}
public function close($error = 125){
$this->connected = false;
return @socket_close($this->sock);
}
@ -58,16 +57,10 @@ class UDPSocket{
}
public function read(&$buf, &$source, &$port){
if($this->connected === false){
return false;
}
return @socket_recvfrom($this->sock, $buf, 65535, 0, $source, $port);
}
public function write($data, $dest, $port){
if($this->connected === false){
return false;
}
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;
@ -95,63 +95,6 @@ class ProtocolInfo{
const ADVENTURE_SETTINGS_PACKET = 0xb7;
const ENTITY_DATA_PACKET = 0xb8;
//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",
);
}

View File

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

View File

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

View File

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

View File

@ -36,7 +36,7 @@ class SendInventoryPacket extends RakNetDataPacket{
for($s = 0; $s < $count and !$this->feof(); ++$s){
$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){
$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
*/
class Query{
class QueryHandler{
private $socket, $server, $lastToken, $token, $longData, $timeout;
public function __construct(){
@ -41,7 +41,7 @@ class Query{
Then, the Query class handles itself sending the packets in raw form, because
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->regenerateToken();
$this->lastToken = $this->token;
@ -91,51 +91,48 @@ class Query{
public function regenerateToken(){
$this->lastToken = $this->token;
$this->token = Utils::readInt("\x00".Utils::getRandomBytes(3, false));
$this->token = Utils::getRandomBytes(16, false);
}
public function packetHandler($packet, $event){
if($event !== "server.unknownpacket.254"){
return;
}
$magic = substr($packet->buffer, 0, 2);
$offset = 2;
if($magic !== "\xfe\xfd"){
return;
}
$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;
public static function getTokenString($token, $salt){
return Utils::readInt(substr(hash("sha512", $salt . ":". $token, true), 7, 4));
}
public function handle(QueryPacket $packet){
$packet->decode();
switch($packet->packetType){
case QueryPacket::HANDSHAKE: //Handshake
$pk = new QueryPacket;
$pk->ip = $packet->ip;
$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);
break;
case 0: //Stat
$token = Utils::readInt(substr($payload, 0, 4));
if($token !== $this->token and $token !== $this->lastToken){
case QueryPacket::STATISTICS: //Stat
$token = Utils::readInt(substr($packet->payload, 0, 4));
if($token !== self::getTokenString($this->token, $packet->ip) and $token !== self::getTokenString($this->lastToken, $packet->ip)){
break;
}
$pk = new Packet;
$pk = new QueryPacket;
$pk->ip = $packet->ip;
$pk->port = $packet->port;
if(strlen($payload) === 8){
$pk->port = $packet->port;
$pk->packetType = QueryPacket::STATISTICS;
$pk->sessionID = $packet->sessionID;
if(strlen($packet->payload) === 8){
if($this->timeout < microtime(true)){
$this->regenerateInfo();
}
$pk->buffer = chr(0).Utils::writeInt($sessionID).$this->longData;
$pk->payload = $this->longData;
}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);
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{
public $packet;
private $buffer;
public function __construct(RakNetPacket $packet){
$this->packet = $packet;
$this->buffer =& $this->packet->buffer;

View File

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

View File

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

View File

@ -50,8 +50,8 @@ class RakNetParser{
return Utils::readLong($this->get(8), $unsigned);
}
private function getInt($unsigned = false){
return Utils::readInt($this->get(4), $unsigned);
private function getInt(){
return Utils::readInt($this->get(4));
}
private function getShort($unsigned = false){
@ -186,11 +186,170 @@ class RakNetParser{
if(strlen($buffer) < ($length - 1)){
return false;
}
if(isset(ProtocolInfo::$packets[$pid])){
$data = new ProtocolInfo::$packets[$pid];
}else{
$data = new UnknownPacket();
$data->packetID = $pid;
switch($pid){
case ProtocolInfo::PING_PACKET:
$data = new PingPacket;
break;
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->hasSplit = $hasSplit;

View File

@ -19,16 +19,17 @@
*
*/
define("PMF_CURRENT_LEVEL_VERSION", 0x00);
class PMFLevel extends PMF{
private $levelData = array();
private $locationTable = array();
const VERSION = 0x01;
const DEFLATE_LEVEL = 9;
public $level;
public $levelData = array();
public $isLoaded = true;
private $log = 4;
private $payloadOffset = 0;
private $chunks = array();
private $chunkChange = array();
private $chunkInfo = array();
public $isGenerating = 0;
public function getData($index){
if(!isset($this->levelData[$index])){
@ -45,19 +46,21 @@ class PMFLevel extends PMF{
return true;
}
public function close(){
$chunks = null;
unset($chunks, $chunkChange, $locationTable);
parent::close();
public function closeLevel(){
$this->chunks = null;
unset($this->chunks, $this->chunkChange, $this->chunkInfo, $this->level);
$this->close();
}
public function __construct($file, $blank = false){
$this->chunks = array();
$this->chunkChange = array();
$this->chunkInfo = array();
if(is_array($blank)){
$this->create($file, 0);
$this->levelData = $blank;
$this->createBlank();
$this->isLoaded = true;
$this->log = (int) ((string) log($this->levelData["width"], 2));
}else{
if($this->load($file) !== false){
$this->parseInfo();
@ -65,7 +68,6 @@ class PMFLevel extends PMF{
$this->isLoaded = false;
}else{
$this->isLoaded = true;
$this->log = (int) ((string) log($this->levelData["width"], 2));
}
}else{
$this->isLoaded = false;
@ -73,8 +75,8 @@ class PMFLevel extends PMF{
}
}
public function saveData($locationTable = true){
$this->levelData["version"] = PMF_CURRENT_LEVEL_VERSION;
public function saveData(){
$this->levelData["version"] = PMFLevel::VERSION;
@ftruncate($this->fp, 5);
$this->seek(5);
$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["spawnY"]));
$this->write(Utils::writeFloat($this->levelData["spawnZ"]));
$this->write(chr($this->levelData["width"]));
$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->payloadOffset = ftell($this->fp);
if($locationTable !== false){
$this->writeLocationTable();
}
}
private function createBlank(){
$this->saveData(false);
$this->locationTable = array();
$cnt = pow($this->levelData["width"], 2);
$this->saveData();
@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")){
$entities = new Config(dirname($this->file)."/entities.yml", CONFIG_YAML);
$entities->save();
@ -127,7 +113,8 @@ class PMFLevel extends PMF{
}
$this->seek(5);
$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;
}
$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["spawnY"] = Utils::readFloat($this->read(4));
$this->levelData["spawnZ"] = Utils::readFloat($this->read(4));
$this->levelData["width"] = ord($this->read(1));
$this->levelData["height"] = ord($this->read(1));
if(($this->levelData["width"] !== 16 and $this->levelData["width"] !== 32) or $this->levelData["height"] !== 8){
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);
if($this->levelData["version"] === 0){
$this->read(1);
$this->levelData["height"] = ord($this->read(1));
}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){
$X = (int) $X;
$Z = (int) $Z;
return ($Z << $this->log) + $X;
private function upgrade_From0_To1(){
console("[NOTICE] Old PMF Level format version #0 detected, upgrading to version #1");
for($index = 0; $index < 256; ++$index){
$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){
$X = $index >> $this->log;
$Z = $index & (pow($this->log, 2) - 1);
public static function getIndex($X, $Z){
return ($Z << 16) | ($X < 0 ? (~--$X & 0x7fff) | 0x8000 : $X & 0x7fff);
}
public static function getXZ($index, &$X = null, &$Z = null){
$Z = $index >> 16;
$X = ($index & 0x8000) === 0x8000 ? -($index & 0x7fff) : $index & 0x7fff;
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){
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){
$X = (int) $X;
$Z = (int) $Z;
$index = $this->getIndex($X, $Z);
if($this->isChunkLoaded($X, $Z)){
return true;
}elseif(!isset($this->locationTable[$index])){
return false;
}
$info = $this->locationTable[$index];
$this->seek($info[0]);
$chunk = @gzopen($this->getChunkPath($X, $Z), "rb");
$index = self::getIndex($X, $Z);
$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($path, "rb");
if($chunk === false){
return false;
}
$this->chunkInfo[$index] = array(
0 => ord(gzread($chunk, 1)),
1 => Utils::readInt(gzread($chunk, 4)),
);
$this->chunks[$index] = array();
$this->chunkChange[$index] = array(-1 => false);
for($Y = 0; $Y < $this->levelData["height"]; ++$Y){
$t = 1 << $Y;
if(($info[0] & $t) === $t){
for($Y = 0; $Y < 8; ++$Y){
if(($this->chunkInfo[$index][0] & (1 << $Y)) !== 0){
// 4096 + 2048 + 2048, Block Data, Meta, Light
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);
}
}else{
@ -230,6 +260,9 @@ class PMFLevel extends PMF{
}
}
@gzclose($chunk);
if($this->isGenerating === 0 and !$this->isPopulated($X, $Z)){
$this->populateChunk($X, $Z);
}
return true;
}
@ -241,24 +274,25 @@ class PMFLevel extends PMF{
}elseif($save !== false){
$this->saveChunk($X, $Z);
}
$index = $this->getIndex($X, $Z);
$index = self::getIndex($X, $Z);
$this->chunks[$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;
}
public function isChunkLoaded($X, $Z){
$index = $this->getIndex($X, $Z);
if(!isset($this->chunks[$index]) or $this->chunks[$index] === false){
$index = self::getIndex($X, $Z);
if(!isset($this->chunks[$index])){
return false;
}
return true;
}
protected function isMiniChunkEmpty($X, $Z, $Y){
$index = $this->getIndex($X, $Z);
if($this->chunks[$index][$Y] !== false){
public function isMiniChunkEmpty($X, $Z, $Y){
$index = self::getIndex($X, $Z);
if(isset($this->chunks[$index]) and $this->chunks[$index][$Y] !== false){
if(substr_count($this->chunks[$index][$Y], "\x00") < 8192){
return false;
}
@ -270,48 +304,84 @@ class PMFLevel extends PMF{
if($this->isChunkLoaded($X, $Z) === false){
return false;
}
$index = $this->getIndex($X, $Z);
$index = self::getIndex($X, $Z);
$this->chunks[$index][$Y] = str_repeat("\x00", 8192);
$this->chunkChange[$index][-1] = true;
$this->chunkChange[$index][$Y] = 8192;
$this->locationTable[$index][0] |= 1 << $Y;
$this->chunkInfo[$index][0] |= 1 << $Y;
return true;
}
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);
}
$index = $this->getIndex($X, $Z);
$index = self::getIndex($X, $Z);
if(!isset($this->chunks[$index][$Y]) or $this->chunks[$index][$Y] === false){
return str_repeat("\x00", 8192);
}
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){
if($this->isChunkLoaded($X, $Z) === false){
if($this->isGenerating > 0){
$this->initCleanChunk($X, $Z);
}elseif($this->isChunkLoaded($X, $Z) === false){
$this->loadChunk($X, $Z);
}
if(strlen($data) !== 8192){
return false;
}
$index = $this->getIndex($X, $Z);
$index = self::getIndex($X, $Z);
$this->chunks[$index][$Y] = (string) $data;
$this->chunkChange[$index][-1] = true;
$this->chunkChange[$index][$Y] = 8192;
$this->locationTable[$index][0] |= 1 << $Y;
$this->chunkInfo[$index][0] |= 1 << $Y;
return true;
}
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;
}
$X = $x >> 4;
$Z = $z >> 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);
$aZ = $z - ($Z << 4);
$aY = $y - ($Y << 4);
@ -320,17 +390,17 @@ class PMFLevel extends PMF{
}
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;
}
$X = $x >> 4;
$Z = $z >> 4;
$Y = $y >> 4;
$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;
}
$index = $this->getIndex($X, $Z);
$aX = $x - ($X << 4);
$aZ = $z - ($Z << 4);
$aY = $y - ($Y << 4);
@ -345,13 +415,16 @@ class PMFLevel extends PMF{
}
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;
}
$X = $x >> 4;
$Z = $z >> 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);
$aZ = $z - ($Z << 4);
$aY = $y - ($Y << 4);
@ -365,17 +438,17 @@ class PMFLevel extends PMF{
}
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;
}
$X = $x >> 4;
$Z = $z >> 4;
$Y = $y >> 4;
$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;
}
$index = $this->getIndex($X, $Z);
$aX = $x - ($X << 4);
$aZ = $z - ($Z << 4);
$aY = $y - ($Y << 4);
@ -404,15 +477,13 @@ class PMFLevel extends PMF{
$X = $x >> 4;
$Z = $z >> 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);
}
$index = $this->getIndex($X, $Z);
if(!isset($this->chunks[$index]) or $this->chunks[$index] === false){
if($this->loadChunk($X, $Z) === false){
return array(AIR, 0);
}
}elseif($this->chunks[$index][$Y] === false){
$index = self::getIndex($X, $Z);
if(!isset($this->chunks[$index]) and $this->loadChunk($X, $Z) === false){
return array(AIR, 0);
}elseif($this->chunks[$index][$Y] === false){
return array(AIR, 0);
}
$aX = $x - ($X << 4);
@ -429,19 +500,17 @@ class PMFLevel extends PMF{
}
public function setBlock($x, $y, $z, $block, $meta = 0){
if($y > 127 or $y < 0){
return false;
}
$X = $x >> 4;
$Z = $z >> 4;
$Y = $y >> 4;
$block &= 0xFF;
$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;
}
$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){
$this->fillMiniChunk($X, $Z, $Y);
}
@ -467,17 +536,6 @@ class PMFLevel extends PMF{
++$this->chunkChange[$index][$Y];
}
$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 false;
@ -489,32 +547,70 @@ class PMFLevel extends PMF{
if(!$this->isChunkLoaded($X, $Z)){
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
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;
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))){
gzwrite($chunk, $this->chunks[$index][$Y]);
$bitmap |= 1 << $Y;
}else{
$this->chunks[$index][$Y] = false;
}
$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->locationTable[$index][0] = $bitmap;
$this->seek($this->payloadOffset + ($index << 1));
$this->write(Utils::writeShort($this->locationTable[$index][0]));
$this->chunkInfo[$index][0] = $bitmap;
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(){
foreach($this->chunks as $index => $chunk){
$this->getXZ($index, $X, $Z);
self::getXZ($index, $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);
require_once(dirname(__FILE__)."/../dependencies.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){
$this->load($file, $type, $default);
$correct = $this->check();
}
public function reload(){
@ -84,7 +83,6 @@ class Config{
unset($this->correct);
unset($this->type);
$this->load($this->file);
$correct = $this->check();
}
public function fixYAMLIndexes($str){
@ -141,7 +139,6 @@ class Config{
default:
$this->correct = false;
return false;
break;
}
if(!is_array($this->config)){
$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"
class Random{
private $x, $y, $z, $w;
private $z, $w;
public function __construct($seed = false){
$this->setSeed($seed);
}
public function setSeed($seed = false){
$seed = $seed !== false ? Utils::writeInt((int) $seed):Utils::getRandomBytes(4, false);
$state = array();
for($i = 0; $i < 256; ++$i){
$state[] = $i;
}
for($i = $j = 0; $i < 256; ++$i){
$j = ($j + ord($seed{$i & 0x03}) + $state[$i]) & 0xFF;
$state[$i] ^= $state[$j];
$state[$j] ^= $state[$i];
$state[$i] ^= $state[$j];
}
$this->state = $state;
$this->i = $this->j = 0;
$seed = $seed !== false ? (int) $seed:Utils::readInt(Utils::getRandomBytes(4, false));
$this->z = $seed ^ 0xdeadbeef;
$this->w = $seed ^ 0xc0de1337;
}
public function nextInt(){
return Utils::readInt($this->nextBytes(4)) & 0x7FFFFFFF;
}
public function nextSignedInt(){
return Utils::readInt($this->nextBytes(4));
}
public function nextFloat(){
return $this->nextInt() / 0x7FFFFFFF;
}
public function nextSignedFloat(){
return $this->nextSignedInt() / 0x7FFFFFFF;
}
public function nextBytes($byteCount){
$bytes = "";
for($i = 0; $i < $byteCount; ++$i){
$this->i = ($this->i + 1) & 0xFF;
$this->j = ($this->j + $this->state[$this->i]) & 0xFF;
$this->state[$this->i] ^= $this->state[$this->j];
$this->state[$this->j] ^= $this->state[$this->i];
$this->state[$this->i] ^= $this->state[$this->j];
$bytes .= chr($this->state[($this->state[$this->i] + $this->state[$this->j]) & 0xFF]);
while(strlen($bytes) < $byteCount){
$this->z = 36969 * ($this->z & 65535) + ($this->z >> 16);
$this->w = 18000 * ($this->w & 65535) + ($this->w >> 16);
$bytes .= pack("N", ($this->z << 16) + $this->w);
}
return $bytes;
return substr($bytes, 0, $byteCount);
}
public function nextBoolean(){
return ($this->nextBytes(1) & 0x01) == 0;
return ($this->nextSignedInt() & 0x01) === 0;
}
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);
}
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 = ""){
$machine = php_uname("a");
$machine .= file_exists("/proc/cpuinfo") ? file_get_contents("/proc/cpuinfo") : "";
@ -612,7 +620,7 @@ class Utils{
}
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 $minor;
private $development = false;
private $generation;
public function __construct($version = MAJOR_VERSION){
if(is_int($version)){
$this->minor = $version & 0x1F;

View File

@ -21,6 +21,7 @@
define("ASYNC_CURL_GET", 1);
define("ASYNC_CURL_POST", 2);
define("ASYNC_FUNCTION", 3);
class StackableArray extends Stackable{
public function __construct(){
@ -87,13 +88,19 @@ class AsyncMultipleQueue extends Thread{
$d = array();
for($c = 0; $c < $cnt; ++$c){
$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);
$this->lock();
$this->output .= Utils::writeInt($rID).Utils::writeShort(ASYNC_CURL_POST).Utils::writeInt(strlen($res)).$res;
$this->unlock();
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);

View File

@ -43,8 +43,16 @@ class Entity extends Position{
public $attach;
public $closed;
public $player;
public $status;
public $fallY;
public $health;
public $fire;
public $crouched;
public $invincible;
public $fallStart;
public $stack;
public $meta;
private $position;
private $tickCounter;
private $speedMeasure = array(0, 0, 0, 0, 0, 0, 0);
private $server;
@ -164,7 +172,7 @@ class Entity extends Position{
}
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();
for($i = 0; $i < PLAYER_SURVIVAL_SLOTS; ++$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();
return false;
}
@ -526,8 +534,8 @@ class Entity extends Position{
}
}elseif($this->fallY !== false){ //Fall damage!
if($y < $this->fallY){
$d = $this->level->getBlock(new Vector3($x, $y + 1, $z));
$d2 = $this->level->getBlock(new Vector3($x, $y + 2, $z));
$d = $this->level->getBlock(new Vector3($this->x, $y + 1, $this->z));
$d2 = $this->level->getBlock(new Vector3($this->x, $y + 2, $this->z));
$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){
$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->class === ENTITY_PLAYER or ($this->last[5] + 8) < $now){
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]);
}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{
$this->updateLast();
@ -593,7 +601,7 @@ class Entity extends Position{
}
}
}else{
$this->updatePosition($this->x, $this->y, $this->z, $this->yaw, $this->pitch);
$this->updatePosition();
}
}
$this->lastUpdate = $now;
@ -658,7 +666,7 @@ class Entity extends Position{
}
switch($this->class){
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;
}

View File

@ -21,7 +21,7 @@
class 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){
$this->server = ServerAPI::request();
@ -34,12 +34,23 @@ class Level{
$this->nextSave = $this->startCheck = microtime(true);
$this->nextSave += 90;
$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->name = $name;
$this->usedChunks = array();
$this->changedBlocks = 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(){
@ -66,6 +77,10 @@ class Level{
unset($this->usedChunks[$X.".".$Z][$player->CID]);
}
public function isChunkPopulated($X, $Z){
return $this->level->isPopulated($X, $Z);
}
public function checkTime(){
if(!isset($this->level)){
return false;
@ -93,9 +108,8 @@ class Level{
$now = microtime(true);
$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);
$resendChunks = array();
foreach($this->changedCount as $index => $count){
if($count < 582){//Optimal value, calculated using the relation between minichunks and single packets
break;
@ -128,18 +142,34 @@ class Level{
if(count($c) === 0){
unset($this->usedChunks[$i]);
$X = explode(".", $i);
$Z = array_pop($X);
$this->level->unloadChunk((int) array_pop($X), (int) $Z, $this->server->saveEnabled);
$Z = (int) array_pop($X);
$X = (int) array_pop($X);
if(!$this->isSpawnChunk($X, $Z)){
$this->level->unloadChunk($X, $Z, $this->server->saveEnabled);
}
}
}
$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(){
if(isset($this->level)){
$this->save(false, false);
$this->level->close();
$this->level->closeLevel();
unset($this->level);
}
}
@ -385,13 +415,23 @@ class Level{
return $this->level->loadChunk($X, $Z);
}
public function unloadChunk($X, $Z){
public function unloadChunk($X, $Z, $force = false){
if(!isset($this->level)){
return false;
}
if($force !== true and $this->isSpawnChunk($X, $Z)){
return false;
}
Cache::remove("world:{$this->name}:$X:$Z");
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){
if(!isset($this->level)){

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

View File

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

View File

@ -20,7 +20,8 @@
*/
interface LevelGenerator{
public function __construct(array $options = array());
public function __construct(array $settings = array());
public function init(Level $level, Random $random);
@ -28,7 +29,9 @@ interface LevelGenerator{
public function populateChunk($chunkX, $chunkZ);
public function populateLevel();
public function getSettings();
//public function populateLevel();
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***/
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()){
$this->preset = "2;7,59x1,3x3,2;1;spawn(radius=10 block=89),decoration(treecount=80 grasscount=45)";
@ -125,9 +129,9 @@ 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){
$this->random->setSeed((int) ($chunkX * 0xdead + $chunkZ * 0xbeef) ^ $this->level->getSeed());
$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{
private $seed, $level, $path, $random, $generator, $width;
public function __construct(LevelGenerator $generator, $name, $seed = false, $width = 16, $height = 8){
private $seed, $level, $path, $random, $generator, $height;
public function __construct(LevelGenerator $generator, $name, $seed = false, $height = 8){
$this->seed = $seed !== false ? (int) $seed:Utils::readInt(Utils::getRandomBytes(4, false));
$this->random = new Random($this->seed);
$this->width = (int) $width;
$this->height = (int) $height;
$this->path = DATA_PATH."worlds/".$name."/";
$this->generator = $generator;
@ -35,9 +34,10 @@ class WorldGenerator{
"spawnX" => 128,
"spawnY" => 128,
"spawnZ" => 128,
"extra" => "",
"width" => $this->width,
"height" => $this->height
"height" => $this->height,
"generator" => get_class($this->generator),
"generatorSettings" => $this->generator->getSettings(),
"extra" => ""
));
$entities = new Config($this->path."entities.yml", CONFIG_YAML);
$tiles = new Config($this->path."tiles.yml", CONFIG_YAML);
@ -47,23 +47,15 @@ class WorldGenerator{
public function generate(){
$this->generator->init($this->level, $this->random);
for($Z = 0; $Z < $this->width; ++$Z){
for($X = 0; $X < $this->width; ++$X){
$this->generator->generateChunk($X, $Z);
//Generate 4 chunks for spawning players
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->save(true, true);
}
public function close(){

View File

@ -19,6 +19,78 @@
*
*/
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***/
class NoiseGeneratorPerlin extends NoiseGenerator{
private $permutations = array();
public $xCoord, $yCoord, $zCoord;
public static $grad3 = [
[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)){
$random = new Random();
}
$this->xCoord = $random->nextFloat() * 256;
$this->yCoord = $random->nextFloat() * 256;
$this->zCoord = $random->nextFloat() * 256;
public function __construct(Random $random, $octaves){
$this->octaves = $octaves;
$this->offsetX = $random->nextFloat() * 256;
$this->offsetY = $random->nextFloat() * 256;
$this->offsetZ = $random->nextFloat() * 256;
for($i = 0; $i < 512; ++$i){
$this->permutations[$i] = 0;
}
for($i = 0; $i < 256; ++$i){
$this->permutations[$i] = $i;
$this->perm[$i] = 0;
}
for($i = 0; $i < 256; ++$i){
$j = $random->nextRange(0, 256 - $i) + $i;
$k = $this->permutations[$i];
$this->permutations[$i] = $this->permutations[$j];
$this->permutations[$j] = $k;
$this->permutations[$i + 256] = $this->permutations[$i];
}
}
public final function curve($par1, $par2, $par3){
return $par2 + $par1 * ($par3 - $par2);
}
public function grad2D($int, $par1, $par2){
$i = $int & 0x0F;
$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;
$this->perm[$i] = $random->nextRange(0, 255);
}
$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($i = 0; $i < 256; ++$i){
$pos = $random->nextRange(0, 255 - $i) + $i;
$old = $this->perm[$i];
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;
}
}
$this->perm[$i] = $this->perm[$pos];
$this->perm[$pos] = $old;
$this->perm[$i + 256] = $this->perm[$i];
}
}
public function getNoise3D($x, $y, $z){
$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 getNoise2D($x, $y){
return $this->getNoise3D($x, $y, 0);
}
}

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){
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());
$leavesRadius = 0;

View File

@ -23,6 +23,8 @@
class TreeObject{
public $overridable = array(
0 => true,
2 => true,
3 => true,
6 => true,
17 => true,
18 => true,
@ -45,8 +47,8 @@ class TreeObject{
$tree = new SmallTreeObject();
$tree->type = SaplingBlock::JUNGLE;
break;
default:
case SaplingBlock::OAK:
default:
/*if($random->nextRange(0, 9) === 0){
$tree = new BigTreeObject();
}else{*/

View File

@ -25,9 +25,9 @@ class OrePopulator extends Populator{
foreach($this->oreTypes as $type){
$ore = new OreObject($random, $type);
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);
$z = $random->nextRange($chunkZ << 4, ($chunkZ << 4) + 16);
$z = $random->nextRange($chunkZ << 4, ($chunkZ << 4) + 15);
if($ore->canPlaceObject($level, $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;
}
}