PageRenderTime 49ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

/src/pocketmine/PocketMine.php

https://gitlab.com/kennethgomad01/genisys
PHP | 486 lines | 341 code | 74 blank | 71 comment | 52 complexity | 32eb045707e2e81f0aa17febcc7b573c MD5 | raw file
  1. <?php
  2. /*
  3. *
  4. * ____ _ _ __ __ _ __ __ ____
  5. * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
  6. * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
  7. * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
  8. * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
  9. *
  10. * This program is free software: you can redistribute it and/or modify
  11. * it under the terms of the GNU Lesser General Public License as published by
  12. * the Free Software Foundation, either version 3 of the License, or
  13. * (at your option) any later version.
  14. *
  15. * @author PocketMine Team
  16. * @link http://www.pocketmine.net/
  17. *
  18. *
  19. */
  20. namespace {
  21. function safe_var_dump(){
  22. static $cnt = 0;
  23. foreach(func_get_args() as $var){
  24. switch(true){
  25. case is_array($var):
  26. echo str_repeat(" ", $cnt) . "array(" . count($var) . ") {" . PHP_EOL;
  27. foreach($var as $key => $value){
  28. echo str_repeat(" ", $cnt + 1) . "[" . (is_integer($key) ? $key : '"' . $key . '"') . "]=>" . PHP_EOL;
  29. ++$cnt;
  30. safe_var_dump($value);
  31. --$cnt;
  32. }
  33. echo str_repeat(" ", $cnt) . "}" . PHP_EOL;
  34. break;
  35. case is_int($var):
  36. echo str_repeat(" ", $cnt) . "int(" . $var . ")" . PHP_EOL;
  37. break;
  38. case is_float($var):
  39. echo str_repeat(" ", $cnt) . "float(" . $var . ")" . PHP_EOL;
  40. break;
  41. case is_bool($var):
  42. echo str_repeat(" ", $cnt) . "bool(" . ($var === true ? "true" : "false") . ")" . PHP_EOL;
  43. break;
  44. case is_string($var):
  45. echo str_repeat(" ", $cnt) . "string(" . strlen($var) . ") \"$var\"" . PHP_EOL;
  46. break;
  47. case is_resource($var):
  48. echo str_repeat(" ", $cnt) . "resource() of type (" . get_resource_type($var) . ")" . PHP_EOL;
  49. break;
  50. case is_object($var):
  51. echo str_repeat(" ", $cnt) . "object(" . get_class($var) . ")" . PHP_EOL;
  52. break;
  53. case is_null($var):
  54. echo str_repeat(" ", $cnt) . "NULL" . PHP_EOL;
  55. break;
  56. }
  57. }
  58. }
  59. function dummy(){
  60. }
  61. }
  62. namespace pocketmine {
  63. use pocketmine\utils\Binary;
  64. use pocketmine\utils\MainLogger;
  65. use pocketmine\utils\ServerKiller;
  66. use pocketmine\utils\Terminal;
  67. use pocketmine\utils\Utils;
  68. use pocketmine\wizard\Installer;
  69. const VERSION = "1.1dev";
  70. const API_VERSION = "2.0.0";
  71. const CODENAME = "Ikaros";
  72. const MINECRAFT_VERSION = "v0.14.x alpha";
  73. const MINECRAFT_VERSION_NETWORK = "0.14.3";
  74. const GENISYS_API_VERSION = '1.7.3';
  75. /*
  76. * Startup code. Do not look at it, it may harm you.
  77. * Most of them are hacks to fix date-related bugs, or basic functions used after this
  78. * This is the only non-class based file on this project.
  79. * Enjoy it as much as I did writing it. I don't want to do it again.
  80. */
  81. if(\Phar::running(true) !== ""){
  82. @define('pocketmine\PATH', \Phar::running(true) . "/");
  83. }else{
  84. @define('pocketmine\PATH', \getcwd() . DIRECTORY_SEPARATOR);
  85. }
  86. if(version_compare("7.0", PHP_VERSION) > 0){
  87. echo "[CRITICAL] You must use PHP >= 7.0" . PHP_EOL;
  88. echo "[CRITICAL] Please use the installer provided on the homepage." . PHP_EOL;
  89. exit(1);
  90. }
  91. if(!extension_loaded("pthreads")){
  92. echo "[CRITICAL] Unable to find the pthreads extension." . PHP_EOL;
  93. echo "[CRITICAL] Please use the installer provided on the homepage." . PHP_EOL;
  94. exit(1);
  95. }
  96. if(!class_exists("ClassLoader", false)){
  97. require_once(\pocketmine\PATH . "src/spl/ClassLoader.php");
  98. require_once(\pocketmine\PATH . "src/spl/BaseClassLoader.php");
  99. require_once(\pocketmine\PATH . "src/pocketmine/CompatibleClassLoader.php");
  100. }
  101. $autoloader = new CompatibleClassLoader();
  102. $autoloader->addPath(\pocketmine\PATH . "src");
  103. $autoloader->addPath(\pocketmine\PATH . "src" . DIRECTORY_SEPARATOR . "spl");
  104. $autoloader->register(true);
  105. set_time_limit(0); //Who set it to 30 seconds?!?!
  106. gc_enable();
  107. error_reporting(-1);
  108. ini_set("allow_url_fopen", 1);
  109. ini_set("display_errors", 1);
  110. ini_set("display_startup_errors", 1);
  111. ini_set("default_charset", "utf-8");
  112. ini_set("memory_limit", -1);
  113. define('pocketmine\START_TIME', microtime(true));
  114. $opts = getopt("", ["data:", "plugins:", "no-wizard", "enable-profiler"]);
  115. define('pocketmine\DATA', isset($opts["data"]) ? $opts["data"] . DIRECTORY_SEPARATOR : \getcwd() . DIRECTORY_SEPARATOR);
  116. define('pocketmine\PLUGIN_PATH', isset($opts["plugins"]) ? $opts["plugins"] . DIRECTORY_SEPARATOR : \getcwd() . DIRECTORY_SEPARATOR . "plugins" . DIRECTORY_SEPARATOR);
  117. Terminal::init();
  118. define('pocketmine\ANSI', Terminal::hasFormattingCodes());
  119. if(!file_exists(\pocketmine\DATA)){
  120. mkdir(\pocketmine\DATA, 0777, true);
  121. }
  122. //Logger has a dependency on timezone, so we'll set it to UTC until we can get the actual timezone.
  123. date_default_timezone_set("UTC");
  124. $logger = new MainLogger(\pocketmine\DATA . "server.log", \pocketmine\ANSI);
  125. if(!ini_get("date.timezone")){
  126. if(($timezone = detect_system_timezone()) and date_default_timezone_set($timezone)){
  127. //Success! Timezone has already been set and validated in the if statement.
  128. //This here is just for redundancy just in case some program wants to read timezone data from the ini.
  129. ini_set("date.timezone", $timezone);
  130. }else{
  131. //If system timezone detection fails or timezone is an invalid value.
  132. if($response = Utils::getURL("http://ip-api.com/json")
  133. and $ip_geolocation_data = json_decode($response, true)
  134. and $ip_geolocation_data['status'] != 'fail'
  135. and date_default_timezone_set($ip_geolocation_data['timezone'])
  136. ){
  137. //Again, for redundancy.
  138. ini_set("date.timezone", $ip_geolocation_data['timezone']);
  139. }else{
  140. ini_set("date.timezone", "UTC");
  141. date_default_timezone_set("UTC");
  142. $logger->warning("Timezone could not be automatically determined. An incorrect timezone will result in incorrect timestamps on console logs. It has been set to \"UTC\" by default. You can change it on the php.ini file.");
  143. }
  144. }
  145. }else{
  146. /*
  147. * This is here so that people don't come to us complaining and fill up the issue tracker when they put
  148. * an incorrect timezone abbreviation in php.ini apparently.
  149. */
  150. $timezone = ini_get("date.timezone");
  151. if(strpos($timezone, "/") === false){
  152. $default_timezone = timezone_name_from_abbr($timezone);
  153. ini_set("date.timezone", $default_timezone);
  154. date_default_timezone_set($default_timezone);
  155. } else {
  156. date_default_timezone_set($timezone);
  157. }
  158. }
  159. function detect_system_timezone(){
  160. switch(Utils::getOS()){
  161. case 'win':
  162. $regex = '/(UTC)(\+*\-*\d*\d*\:*\d*\d*)/';
  163. /*
  164. * wmic timezone get Caption
  165. * Get the timezone offset
  166. *
  167. * Sample Output var_dump
  168. * array(3) {
  169. * [0] =>
  170. * string(7) "Caption"
  171. * [1] =>
  172. * string(20) "(UTC+09:30) Adelaide"
  173. * [2] =>
  174. * string(0) ""
  175. * }
  176. */
  177. exec("wmic timezone get Caption", $output);
  178. $string = trim(implode("\n", $output));
  179. //Detect the Time Zone string
  180. preg_match($regex, $string, $matches);
  181. if(!isset($matches[2])){
  182. return false;
  183. }
  184. $offset = $matches[2];
  185. if($offset == ""){
  186. return "UTC";
  187. }
  188. return parse_offset($offset);
  189. break;
  190. case 'linux':
  191. // Ubuntu / Debian.
  192. if(file_exists('/etc/timezone')){
  193. $data = file_get_contents('/etc/timezone');
  194. if($data){
  195. return trim($data);
  196. }
  197. }
  198. // RHEL / CentOS
  199. if(file_exists('/etc/sysconfig/clock')){
  200. $data = parse_ini_file('/etc/sysconfig/clock');
  201. if(!empty($data['ZONE'])){
  202. return trim($data['ZONE']);
  203. }
  204. }
  205. //Portable method for incompatible linux distributions.
  206. $offset = trim(exec('date +%:z'));
  207. if($offset == "+00:00"){
  208. return "UTC";
  209. }
  210. return parse_offset($offset);
  211. break;
  212. case 'mac':
  213. if(is_link('/etc/localtime')){
  214. $filename = readlink('/etc/localtime');
  215. if(strpos($filename, '/usr/share/zoneinfo/') === 0){
  216. $timezone = substr($filename, 20);
  217. return trim($timezone);
  218. }
  219. }
  220. return false;
  221. break;
  222. default:
  223. return false;
  224. break;
  225. }
  226. }
  227. /**
  228. * @param string $offset In the format of +09:00, +02:00, -04:00 etc.
  229. *
  230. * @return string
  231. */
  232. function parse_offset($offset){
  233. //Make signed offsets unsigned for date_parse
  234. if(strpos($offset, '-') !== false){
  235. $negative_offset = true;
  236. $offset = str_replace('-', '', $offset);
  237. }else{
  238. if(strpos($offset, '+') !== false){
  239. $negative_offset = false;
  240. $offset = str_replace('+', '', $offset);
  241. }else{
  242. return false;
  243. }
  244. }
  245. $parsed = date_parse($offset);
  246. $offset = $parsed['hour'] * 3600 + $parsed['minute'] * 60 + $parsed['second'];
  247. //After date_parse is done, put the sign back
  248. if($negative_offset == true){
  249. $offset = -abs($offset);
  250. }
  251. //And then, look the offset up.
  252. //timezone_name_from_abbr is not used because it returns false on some(most) offsets because it's mapping function is weird.
  253. //That's been a bug in PHP since 2008!
  254. foreach(timezone_abbreviations_list() as $zones){
  255. foreach($zones as $timezone){
  256. if($timezone['offset'] == $offset){
  257. return $timezone['timezone_id'];
  258. }
  259. }
  260. }
  261. return false;
  262. }
  263. if(isset($opts["enable-profiler"])){
  264. if(function_exists("profiler_enable")){
  265. \profiler_enable();
  266. $logger->notice("Execution is being profiled");
  267. }else{
  268. $logger->notice("No profiler found. Please install https://github.com/krakjoe/profiler");
  269. }
  270. }
  271. function kill($pid){
  272. switch(Utils::getOS()){
  273. case "win":
  274. exec("taskkill.exe /F /PID " . ((int) $pid) . " > NUL");
  275. break;
  276. case "mac":
  277. case "linux":
  278. default:
  279. if(function_exists("posix_kill")){
  280. posix_kill($pid, SIGKILL);
  281. }else{
  282. exec("kill -9 " . ((int)$pid) . " > /dev/null 2>&1");
  283. }
  284. }
  285. }
  286. /**
  287. * @param object $value
  288. * @param bool $includeCurrent
  289. *
  290. * @return int
  291. */
  292. function getReferenceCount($value, $includeCurrent = true){
  293. ob_start();
  294. debug_zval_dump($value);
  295. $ret = explode("\n", ob_get_contents());
  296. ob_end_clean();
  297. if(count($ret) >= 1 and preg_match('/^.* refcount\\(([0-9]+)\\)\\{$/', trim($ret[0]), $m) > 0){
  298. return ((int) $m[1]) - ($includeCurrent ? 3 : 4); //$value + zval call + extra call
  299. }
  300. return -1;
  301. }
  302. function getTrace($start = 1, $trace = null){
  303. if($trace === null){
  304. if(function_exists("xdebug_get_function_stack")){
  305. $trace = array_reverse(xdebug_get_function_stack());
  306. }else{
  307. $e = new \Exception();
  308. $trace = $e->getTrace();
  309. }
  310. }
  311. $messages = [];
  312. $j = 0;
  313. for($i = (int) $start; isset($trace[$i]); ++$i, ++$j){
  314. $params = "";
  315. if(isset($trace[$i]["args"]) or isset($trace[$i]["params"])){
  316. if(isset($trace[$i]["args"])){
  317. $args = $trace[$i]["args"];
  318. }else{
  319. $args = $trace[$i]["params"];
  320. }
  321. foreach($args as $name => $value){
  322. $params .= (is_object($value) ? get_class($value) . " " . (method_exists($value, "__toString") ? $value->__toString() : "object") : gettype($value) . " " . (is_array($value) ? "Array()" : Utils::printable(@strval($value)))) . ", ";
  323. }
  324. }
  325. $messages[] = "#$j " . (isset($trace[$i]["file"]) ? cleanPath($trace[$i]["file"]) : "") . "(" . (isset($trace[$i]["line"]) ? $trace[$i]["line"] : "") . "): " . (isset($trace[$i]["class"]) ? $trace[$i]["class"] . (($trace[$i]["type"] === "dynamic" or $trace[$i]["type"] === "->") ? "->" : "::") : "") . $trace[$i]["function"] . "(" . Utils::printable(substr($params, 0, -2)) . ")";
  326. }
  327. return $messages;
  328. }
  329. function cleanPath($path){
  330. return rtrim(str_replace(["\\", ".php", "phar://", rtrim(str_replace(["\\", "phar://"], ["/", ""], \pocketmine\PATH), "/"), rtrim(str_replace(["\\", "phar://"], ["/", ""], \pocketmine\PLUGIN_PATH), "/")], ["/", "", "", "", ""], $path), "/");
  331. }
  332. $errors = 0;
  333. if(php_sapi_name() !== "cli"){
  334. $logger->critical("You must run PocketMine-MP using the CLI.");
  335. ++$errors;
  336. }
  337. if(!extension_loaded("sockets")){
  338. $logger->critical("Unable to find the Socket extension.");
  339. ++$errors;
  340. }
  341. $pthreads_version = phpversion("pthreads");
  342. if(substr_count($pthreads_version, ".") < 2){
  343. $pthreads_version = "0.$pthreads_version";
  344. }
  345. if(version_compare($pthreads_version, "3.1.5") < 0){
  346. $logger->critical("pthreads >= 3.1.5 is required, while you have $pthreads_version.");
  347. ++$errors;
  348. }
  349. if(!extension_loaded("uopz")){
  350. //$logger->notice("Couldn't find the uopz extension. Some functions may be limited");
  351. }
  352. if(extension_loaded("pocketmine")){
  353. if(version_compare(phpversion("pocketmine"), "0.0.1") < 0){
  354. $logger->critical("You have the native PocketMine extension, but your version is lower than 0.0.1.");
  355. ++$errors;
  356. }elseif(version_compare(phpversion("pocketmine"), "0.0.4") > 0){
  357. $logger->critical("You have the native PocketMine extension, but your version is higher than 0.0.4.");
  358. ++$errors;
  359. }
  360. }
  361. if(!extension_loaded("curl")){
  362. $logger->critical("Unable to find the cURL extension.");
  363. ++$errors;
  364. }
  365. if(!extension_loaded("yaml")){
  366. $logger->critical("Unable to find the YAML extension.");
  367. ++$errors;
  368. }
  369. if(!extension_loaded("sqlite3")){
  370. $logger->critical("Unable to find the SQLite3 extension.");
  371. ++$errors;
  372. }
  373. if(!extension_loaded("zlib")){
  374. $logger->critical("Unable to find the Zlib extension.");
  375. ++$errors;
  376. }
  377. if($errors > 0){
  378. $logger->critical("Please use the installer provided on the homepage, or recompile PHP again.");
  379. $logger->shutdown();
  380. $logger->join();
  381. exit(1); //Exit with error
  382. }
  383. if(file_exists(\pocketmine\PATH . ".git/refs/heads/master")){ //Found Git information!
  384. define('pocketmine\GIT_COMMIT', strtolower(trim(file_get_contents(\pocketmine\PATH . ".git/refs/heads/master"))));
  385. }else{ //Unknown :(
  386. define('pocketmine\GIT_COMMIT', str_repeat("00", 20));
  387. }
  388. @define("ENDIANNESS", (pack("d", 1) === "\77\360\0\0\0\0\0\0" ? Binary::BIG_ENDIAN : Binary::LITTLE_ENDIAN));
  389. @define("INT32_MASK", is_int(0xffffffff) ? 0xffffffff : -1);
  390. @ini_set("opcache.mmap_base", bin2hex(Utils::getRandomBytes(8, false))); //Fix OPCache address errors
  391. $lang = "unknown";
  392. if(!file_exists(\pocketmine\DATA . "server.properties") and !isset($opts["no-wizard"])){
  393. $inst = new Installer();
  394. $lang = $inst->getDefaultLang();
  395. }
  396. /*if(\Phar::running(true) === ""){
  397. $logger->warning("Non-packaged PocketMine-MP installation detected, do not use on production.");
  398. }*/
  399. ThreadManager::init();
  400. $server = new Server($autoloader, $logger, \pocketmine\PATH, \pocketmine\DATA, \pocketmine\PLUGIN_PATH, $lang);
  401. $logger->info("Stopping other threads");
  402. foreach(ThreadManager::getInstance()->getAll() as $id => $thread){
  403. $logger->debug("Stopping " . (new \ReflectionClass($thread))->getShortName() . " thread");
  404. $thread->quit();
  405. }
  406. $killer = new ServerKiller(8);
  407. $killer->start();
  408. $logger->shutdown();
  409. $logger->join();
  410. echo "Server has stopped" . Terminal::$FORMAT_RESET . "\n";
  411. exit(0);
  412. }