hashCode()); $test .= Utils::writeDataArray(array("a", "b", "c", "\xff\xff\xff\xff")); $test .= Utils::hexToStr("012334567890"); file_put_contents(FILE_PATH."test.bin.log", $test); if(md5($test) !== TEST_MD5){ console("[ERROR] Test error, please send your console.log + test.bin.log to the Github repo"); die(); } } if(!file_exists(FILE_PATH."white-list.txt")){ console("[NOTICE] No white-list.txt found, creating blank file"); file_put_contents(FILE_PATH."white-list.txt", ""); } if(!file_exists(FILE_PATH."banned-ips.txt")){ console("[NOTICE] No banned-ips.txt found, creating blank file"); file_put_contents(FILE_PATH."banned-ips.txt", ""); } if(!file_exists(FILE_PATH."server.properties")){ console("[NOTICE] No server.properties found, using default settings"); copy(FILE_PATH."src/common/default.properties", FILE_PATH."server.properties"); } console("[DEBUG] Checking data folders...", true, true, 2); @mkdir(FILE_PATH."players/", 0777, true); @mkdir(FILE_PATH."worlds/", 0777); @mkdir(FILE_PATH."plugins/", 0777); console("[DEBUG] Loading server.properties...", true, true, 2); $this->parseProperties(); define("DEBUG", $this->config["debug"]); $this->server = new PocketMinecraftServer($this->getProperty("server-name"), $this->getProperty("gamemode"), false, CURRENT_PROTOCOL, $this->getProperty("port"), $this->getProperty("server-id")); $this->server->api = $this; if($this->getProperty("last-update") === false or ($this->getProperty("last-update") + 3600) < time()){ console("[INFO] Checking for new server version"); console("[INFO] Last check: ".date("Y-m-d H:i:s", $this->getProperty("last-update"))); $channel = "stable"; if($this->getProperty("update-channel") == "dev" or $this->getProperty("update-channel") == "development"){ $channel = "dev"; } $this->setProperty("update-channel", $channel); if($channel === "dev"){ $info = json_decode(Utils::curl_get("https://api.github.com/repos/shoghicp/PocketMine-MP"), true); if($info === false or !isset($info["updated_at"])){ console("[ERROR] GitHub API Error"); }else{ $last = new DateTime($info["updated_at"]); $last = $last->getTimestamp(); if($last >= $this->getProperty("last-update") and $this->getProperty("last-update") !== false){ console("[NOTICE] A new DEVELOPMENT version of PocketMine-MP has been released"); console("[NOTICE] If you want to update, get the latest version at https://github.com/shoghicp/PocketMine-MP/archive/master.zip"); console("[NOTICE] This message will dissapear when you issue the command \"/update-done\""); sleep(3); }else{ $this->setProperty("last-update", time()); console("[INFO] This is the latest DEVELOPMENT version"); } } }else{ $info = json_decode(Utils::curl_get("https://api.github.com/repos/shoghicp/PocketMine-MP/tags"), true); if($info === false or !isset($info[0])){ console("[ERROR] GitHub API Error"); }else{ $info = $info[0]; if($info["name"] != MAJOR_VERSION){ console("[NOTICE] A new STABLE version of PocketMine-MP has been released"); console("[NOTICE] Version \"".$info["name"]."\" [".substr($info["commit"]["sha"], 0, 10)."]"); console("[NOTICE] Download it at ".$info["zipball_url"]); console("[NOTICE] This message will dissapear as soon as you update\""); sleep(5); }else{ $this->setProperty("last-update", time()); console("[INFO] This is the latest STABLE version"); } } } } if(file_exists(FILE_PATH."worlds/level.dat")){ console("[NOTICE] Detected unimported map data. Importing..."); $this->importMap(FILE_PATH."worlds/", true); } $this->server->mapName = $this->getProperty("level-name"); $this->server->mapDir = FILE_PATH."worlds/".$this->server->mapName."/"; if($this->server->mapName === false or trim($this->server->mapName) === "" or !file_exists($this->server->mapDir."chunks.dat")){ if($this->server->mapName === false or trim($this->server->mapName) === ""){ $this->server->mapName = "world"; } $this->server->mapDir = FILE_PATH."worlds/".$this->server->mapName."/"; $generator = "SuperflatGenerator"; if($this->getProperty("generator") !== false and class_exists($this->getProperty("generator"))){ $generator = $this->getProperty("generator"); } $this->gen = new WorldGenerator($generator, $this->server->seed); if($this->getProperty("generator-settings") !== false and trim($this->getProperty("generator-settings")) != ""){ $this->gen->set("preset", $this->getProperty("generator-settings")); } $this->gen->init(); $this->gen->generate(); $this->gen->save($this->server->mapDir, $this->server->mapName); $this->setProperty("level-name", $this->server->mapName); $this->setProperty("gamemode", 1); } $this->loadProperties(); $this->server->loadMap(); //Autoload all default APIs console("[INFO] Loading default APIs"); $dir = dir(FILE_PATH."src/API/"); while(false !== ($file = $dir->read())){ if($file !== "." and $file !== ".."){ $API = basename($file, ".php"); if(strtolower($API) !== "serverapi"){ $name = strtolower(substr($API, 0, -3)); $this->loadAPI($name, $API); } } } foreach($this->apiList as $ob){ if(is_callable(array($ob, "init"))){ $ob->init(); } } $this->server->loadEntities(); } private function loadProperties(){ if(isset($this->config["memory-limit"])){ @ini_set("memory_limit", $this->config["memory-limit"]); }else{ $this->config["memory-limit"] = "256M"; } if(!isset($this->config["invisible"])){ $this->config["invisible"] = false; } if(is_object($this->server)){ $this->server->setType($this->config["server-type"]); $this->server->timePerSecond = $this->config["time-per-second"]; $this->server->invisible = $this->config["invisible"]; $this->server->maxClients = $this->config["max-players"]; $this->server->description = $this->config["description"]; $this->server->motd = $this->config["motd"]; $this->server->gamemode = $this->config["gamemode"]; $this->server->difficulty = $this->config["difficulty"]; $this->server->whitelist = $this->config["white-list"]; $this->server->reloadConfig(); } } private function writeProperties(){ if(is_object($this->server)){ $this->config["server-id"] = $this->server->serverID; } $config = $this->config; $config["white-list"] = $config["white-list"] === true ? "true":"false"; $config["invisible"] = $config["invisible"] === true ? "true":"false"; $prop = "#Pocket Minecraft PHP server properties\r\n#".date("D M j H:i:s T Y")."\r\n"; foreach($config as $n => $v){ $prop .= $n."=".$v."\r\n"; } file_put_contents(FILE_PATH."server.properties", $prop); } private function parseProperties(){ $prop = file_get_contents(FILE_PATH."server.properties"); $prop = explode("\n", str_replace("\r", "", $prop)); $this->config = array(); foreach($prop as $line){ if(trim($line) == "" or $line{0} == "#"){ continue; } $d = explode("=", $line); $n = strtolower(array_shift($d)); $v = implode("=", $d); switch(strtolower(trim($v))){ case "on": case "true": case "yes": $v = true; break; case "off": case "false": case "no": $v = false; break; } switch($n){ case "last-update": if($v === false){ $v = time(); }else{ $v = (int) $v; } break; case "gamemode": case "max-players": case "port": case "debug": case "difficulty": case "time-per-second": $v = (int) $v; break; case "server-id": if($v !== false){ $v = preg_match("/[^0-9\-]/", $v) > 0 ? Utils::readInt(substr(md5($v, true), 0, 4)):$v; } break; } $this->config[$n] = $v; } } public function start(){ $this->server->start(); unregister_tick_function(array($this->server, "tick")); unset($this->server); return $this->restart; } /*-------------------------------------------------------------*/ public function addHandler($e, $c, $p = 5){ return $this->server->addHandler($e, $c, $p); } public function handle($e, &$d){ return $this->server->handle($e, $d); } public function action($t, $c, $r = true){ return $this->server->action($t, $c, $r); } public function schedule($t, $c, $d, $r = false, $e = "server.schedule"){ return $this->server->schedule($t, $c, $d, $r, $e); } public function event($e, $d){ return $this->server->event($e, $d); } public function trigger($e, $d){ return $this->server->trigger($e, $d); } public function deleteEvent($id){ return $this->server->deleteEvent($id); } public function importMap($dir, $remove = false){ if(file_exists($dir."level.dat")){ $nbt = new NBT(); $level = parseNBTData($nbt->loadFile($dir."level.dat")); console("[DEBUG] Importing map \"".$level["LevelName"]."\" gamemode ".$level["GameType"]." with seed ".$level["RandomSeed"], true, true, 2); unset($level["Player"]); $lvName = $level["LevelName"]."/"; @mkdir(FILE_PATH."worlds/".$lvName, 0777); file_put_contents(FILE_PATH."worlds/".$lvName."level.dat", serialize($level)); $entities = parseNBTData($nbt->loadFile($dir."entities.dat")); file_put_contents(FILE_PATH."worlds/".$lvName."entities.dat", serialize($entities["Entities"])); if(!isset($entities["TileEntities"])){ $entities["TileEntities"] = array(); } file_put_contents(FILE_PATH."worlds/".$lvName."tileEntities.dat", serialize($entities["TileEntities"])); console("[DEBUG] Imported ".count($entities["Entities"])." Entities and ".count($entities["TileEntities"])." TileEntities", true, true, 2); if($remove === true){ rename($dir."chunks.dat", FILE_PATH."worlds/".$lvName."chunks.dat"); unlink($dir."level.dat"); @unlink($dir."level.dat_old"); @unlink($dir."player.dat"); unlink($dir."entities.dat"); }else{ copy($dir."chunks.dat", FILE_PATH."worlds/".$lvName."chunks.dat"); } if($this->getProperty("level-name") === false){ console("[INFO] Setting default level to \"".$level["LevelName"]."\""); $this->setProperty("level-name", $level["LevelName"]); $this->setProperty("gamemode", $level["GameType"]); $this->server->seed = $level["RandomSeed"]; $this->server->spawn = array("x" => $level["SpawnX"], "y" => $level["SpawnY"], "z" => $level["SpawnZ"]); $this->writeProperties(); } console("[INFO] Map \"".$level["LevelName"]."\" importing done!"); unset($level, $entities, $nbt); return true; } return false; } public function getProperty($name){ if(isset($this->config[$name])){ return $this->config[$name]; } return false; } public function setProperty($name, $value){ $this->config[$name] = $value; $this->writeProperties(); $this->loadProperties(); } public function getList(){ return $this->apiList; } public function loadAPI($name, $class, $dir = false){ if($dir === false){ $dir = FILE_PATH."src/API/"; } $file = $dir.$class.".php"; if(!file_exists($file)){ console("[ERROR] API ".$name." [".$class."] in ".$dir." doesn't exist", true, true, 0); return false; } require_once($file); $this->$name = new $class($this->server); $this->apiList[] = $this->$name; console("[INFO] API ".$name." [".$class."] loaded"); } }