mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-05-16 18:59:00 +00:00
Merge branch 'master' of https://github.com/PocketMine/PocketMine-MP
This commit is contained in:
commit
b28bc3ae9b
@ -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
|
||||
|
@ -1,12 +1,12 @@
|
||||

|
||||

|
||||
|
||||
# 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{
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
```
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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)));
|
||||
}
|
||||
|
@ -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
136
src/BaseEvent.php
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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{
|
129
src/Player.php
129
src/Player.php
@ -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();
|
||||
}
|
||||
|
@ -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.\""
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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!
|
||||
|
@ -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);
|
||||
|
28
src/event/CancellableEvent.php
Normal file
28
src/event/CancellableEvent.php
Normal 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{
|
||||
|
||||
}
|
51
src/event/EventHandler.php
Normal file
51
src/event/EventHandler.php
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
52
src/event/EventPriority.php
Normal file
52
src/event/EventPriority.php
Normal 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
29
src/event/PluginEvent.php
Normal 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
24
src/event/ServerEvent.php
Normal 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{
|
||||
|
||||
}
|
41
src/event/server/DataPacketReceiveEvent.php
Normal file
41
src/event/server/DataPacketReceiveEvent.php
Normal 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;
|
||||
}
|
||||
}
|
41
src/event/server/DataPacketSendEvent.php
Normal file
41
src/event/server/DataPacketSendEvent.php
Normal 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;
|
||||
}
|
||||
}
|
36
src/event/server/PacketReceiveEvent.php
Normal file
36
src/event/server/PacketReceiveEvent.php
Normal 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;
|
||||
}
|
||||
}
|
36
src/event/server/PacketSendEvent.php
Normal file
36
src/event/server/PacketSendEvent.php
Normal 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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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",
|
||||
|
@ -43,7 +43,6 @@ class SpawnEggItem extends Item{
|
||||
--$this->count;
|
||||
}
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
224
src/nbt/NBT.php
Normal file
224
src/nbt/NBT.php
Normal 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
55
src/nbt/NBTTag.php
Normal 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
43
src/nbt/NamedNBTTag.php
Normal 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
35
src/nbt/tags/TAG_Byte.php
Normal 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);
|
||||
}
|
||||
}
|
36
src/nbt/tags/TAG_Byte_Array.php
Normal file
36
src/nbt/tags/TAG_Byte_Array.php
Normal 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);
|
||||
}
|
||||
}
|
63
src/nbt/tags/TAG_Compound.php
Normal file
63
src/nbt/tags/TAG_Compound.php
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
35
src/nbt/tags/TAG_Double.php
Normal file
35
src/nbt/tags/TAG_Double.php
Normal 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
35
src/nbt/tags/TAG_End.php
Normal 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){
|
||||
|
||||
}
|
||||
}
|
35
src/nbt/tags/TAG_Float.php
Normal file
35
src/nbt/tags/TAG_Float.php
Normal 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
35
src/nbt/tags/TAG_Int.php
Normal 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);
|
||||
}
|
||||
}
|
42
src/nbt/tags/TAG_Int_Array.php
Normal file
42
src/nbt/tags/TAG_Int_Array.php
Normal 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
126
src/nbt/tags/TAG_List.php
Normal 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
35
src/nbt/tags/TAG_Long.php
Normal 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);
|
||||
}
|
||||
}
|
35
src/nbt/tags/TAG_Short.php
Normal file
35
src/nbt/tags/TAG_Short.php
Normal 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);
|
||||
}
|
||||
}
|
36
src/nbt/tags/TAG_String.php
Normal file
36
src/nbt/tags/TAG_String.php
Normal 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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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){
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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",
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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(){
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
41
src/network/query/QueryPacket.php
Normal file
41
src/network/query/QueryPacket.php
Normal 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;
|
||||
}
|
||||
}
|
@ -21,6 +21,7 @@
|
||||
|
||||
class RakNetCodec{
|
||||
public $packet;
|
||||
private $buffer;
|
||||
public function __construct(RakNetPacket $packet){
|
||||
$this->packet = $packet;
|
||||
$this->buffer =& $this->packet->buffer;
|
||||
|
@ -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){
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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");
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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){
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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)){
|
||||
|
@ -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");
|
||||
|
@ -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(){
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
170
src/world/generator/NormalGenerator.php
Normal file
170
src/world/generator/NormalGenerator.php
Normal 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));
|
||||
}
|
||||
|
||||
}
|
@ -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
@ -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(){
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
438
src/world/generator/noise/NoiseGeneratorSimplex.php
Normal file
438
src/world/generator/noise/NoiseGeneratorSimplex.php
Normal 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 we’re 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);
|
||||
}*/
|
||||
}
|
@ -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;
|
||||
|
@ -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{*/
|
||||
|
@ -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));
|
||||
}
|
||||
|
70
src/world/generator/populator/TallGrassPopulator.php
Normal file
70
src/world/generator/populator/TallGrassPopulator.php
Normal file
@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
class TallGrassPopulator extends Populator{
|
||||
private $level;
|
||||
private $randomAmount;
|
||||
private $baseAmount;
|
||||
|
||||
public function setRandomAmount($amount){
|
||||
$this->randomAmount = $amount;
|
||||
}
|
||||
|
||||
public function setBaseAmount($amount){
|
||||
$this->baseAmount = $amount;
|
||||
}
|
||||
|
||||
public function populate(Level $level, $chunkX, $chunkZ, Random $random){
|
||||
$this->level = $level;
|
||||
$amount = $random->nextRange(0, $this->randomAmount + 1) + $this->baseAmount;
|
||||
for($i = 0; $i < $amount; ++$i){
|
||||
$x = $random->nextRange($chunkX << 4, ($chunkX << 4) + 15);
|
||||
$z = $random->nextRange($chunkZ << 4, ($chunkZ << 4) + 15);
|
||||
for($size = 30; $size > 0; --$size){
|
||||
$xx = $x - 7 + $random->nextRange(0, 15);
|
||||
$zz = $z - 7 + $random->nextRange(0, 15);
|
||||
$yy = $this->getHighestWorkableBlock($xx, $zz);
|
||||
$vector = new Vector3($xx, $yy, $zz);
|
||||
if($yy !== -1 and $this->canTallGrassStay($this->level->getBlockRaw($vector))){
|
||||
$this->level->setBlockRaw($vector, new TallGrassBlock(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function canTallGrassStay(Block $block){
|
||||
return $block->getID() === AIR and $block->getSide(0)->getID() === GRASS;
|
||||
}
|
||||
|
||||
private function getHighestWorkableBlock($x, $z){
|
||||
for($y = 128; $y > 0; --$y){
|
||||
$b = $this->level->getBlockRaw(new Vector3($x, $y, $z));
|
||||
if($b->getID() === AIR or $b->getID() === LEAVES){
|
||||
if(--$y <= 0){
|
||||
return -1;
|
||||
}
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ++$y;
|
||||
}
|
||||
}
|
67
src/world/generator/populator/TreePopulator.php
Normal file
67
src/world/generator/populator/TreePopulator.php
Normal file
@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
class TreePopulator extends Populator{
|
||||
private $level;
|
||||
private $randomAmount;
|
||||
private $baseAmount;
|
||||
|
||||
public function setRandomAmount($amount){
|
||||
$this->randomAmount = $amount;
|
||||
}
|
||||
|
||||
public function setBaseAmount($amount){
|
||||
$this->baseAmount = $amount;
|
||||
}
|
||||
|
||||
public function populate(Level $level, $chunkX, $chunkZ, Random $random){
|
||||
$this->level = $level;
|
||||
$amount = $random->nextRange(0, $this->randomAmount + 1) + $this->baseAmount;
|
||||
for($i = 0; $i < $amount; ++$i){
|
||||
$x = $random->nextRange($chunkX << 4, ($chunkX << 4) + 15);
|
||||
$z = $random->nextRange($chunkZ << 4, ($chunkZ << 4) + 15);
|
||||
$y = $this->getHighestWorkableBlock($x, $z);
|
||||
if($y === -1){
|
||||
continue;
|
||||
}
|
||||
if($random->nextFloat() > 0.75){
|
||||
$meta = SaplingBlock::BIRCH;
|
||||
}else{
|
||||
$meta = SaplingBlock::OAK;
|
||||
}
|
||||
TreeObject::growTree($this->level, new Vector3($x, $y, $z), $random, $meta);
|
||||
}
|
||||
}
|
||||
|
||||
private function getHighestWorkableBlock($x, $z){
|
||||
for($y = 128; $y > 0; --$y){
|
||||
$b = $this->level->getBlockRaw(new Vector3($x, $y, $z));
|
||||
if($b->getID() !== DIRT and $b->getID() !== GRASS){
|
||||
if(--$y <= 0){
|
||||
return -1;
|
||||
}
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ++$y;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user