78 if(version_compare(MIN_PHP_VERSION, PHP_VERSION) > 0){
81 "PHP >= " . MIN_PHP_VERSION .
" is required, but you have PHP " . PHP_VERSION .
"."
88 $messages[] =
"32-bit systems/PHP are no longer supported. Please upgrade to a 64-bit system, or use a 64-bit PHP binary if this is a 64-bit system.";
91 if(php_sapi_name() !==
"cli"){
92 $messages[] =
"Only PHP CLI is supported.";
96 "chunkutils2" =>
"PocketMine ChunkUtils v2",
98 "crypto" =>
"php-crypto",
101 "encoding" =>
"pmmp/ext-encoding",
104 "igbinary" =>
"igbinary",
106 "leveldb" =>
"LevelDB",
107 "mbstring" =>
"Multibyte String",
108 "morton" =>
"morton",
109 "openssl" =>
"OpenSSL",
112 "pmmpthread" =>
"pmmpthread",
113 "reflection" =>
"Reflection",
114 "sockets" =>
"Sockets",
121 foreach($extensions as $ext => $name){
122 if(!extension_loaded($ext)){
123 $messages[] =
"Unable to find the $name ($ext) extension.";
127 if(($pmmpthread_version = phpversion(
"pmmpthread")) !==
false){
128 if(version_compare($pmmpthread_version,
"6.1.0") < 0 || version_compare($pmmpthread_version,
"7.0.0") >= 0){
129 $messages[] =
"pmmpthread ^6.1.0 is required, while you have $pmmpthread_version.";
133 if(($leveldb_version = phpversion(
"leveldb")) !==
false){
134 if(version_compare($leveldb_version,
"0.2.1") < 0){
135 $messages[] =
"php-leveldb >= 0.2.1 is required, while you have $leveldb_version.";
137 if(!defined(
'LEVELDB_ZLIB_RAW_COMPRESSION')){
138 $messages[] =
"Given version of php-leveldb doesn't support ZLIB_RAW compression (use https://github.com/pmmp/php-leveldb)";
142 $chunkutils2_version = phpversion(
"chunkutils2");
143 $wantedVersionLock =
"0.3";
144 $wantedVersionMin =
"$wantedVersionLock.0";
145 if($chunkutils2_version !==
false && (
146 version_compare($chunkutils2_version, $wantedVersionMin) < 0 ||
147 preg_match(
"/^" . preg_quote($wantedVersionLock,
"/") .
"\.\d+(?:-dev)?$/", $chunkutils2_version) === 0
149 $messages[] =
"chunkutils2 ^$wantedVersionMin is required, while you have $chunkutils2_version.";
152 if(($libdeflate_version = phpversion(
"libdeflate")) !==
false){
154 if(version_compare($libdeflate_version,
"0.2.0") < 0 || version_compare($libdeflate_version,
"0.3.0") >= 0){
155 $messages[] =
"php-libdeflate ^0.2.0 is required, while you have $libdeflate_version.";
159 if(($encoding_version = phpversion(
"encoding")) !==
false){
160 if(version_compare($encoding_version,
"1.0.0") < 0 || version_compare($encoding_version,
"2.0.0") >= 0){
161 $messages[] =
"pmmp/ext-encoding ^1.0.0 is required, while you have $encoding_version.";
165 if(extension_loaded(
"pocketmine")){
166 $messages[] =
"The native PocketMine extension is no longer supported.";
169 if(!defined(
'AF_INET6')){
170 $messages[] =
"IPv6 support is required, but your PHP binary was built without IPv6 support.";
243 if(count($messages = check_platform_dependencies()) > 0){
245 $binary = version_compare(PHP_VERSION, "5.4") >= 0 ? PHP_BINARY : "unknown";
246 critical_error("Selected PHP binary does not satisfy some requirements.");
247 foreach($messages as $m){
248 echo " - $m" . PHP_EOL;
250 critical_error("PHP binary used: " . $binary);
251 critical_error("Loaded php.ini: " . (($file = php_ini_loaded_file()) !== false ? $file : "none"));
252 $phprc = getenv("PHPRC");
253 critical_error("Value of PHPRC environment variable: " . ($phprc === false ? "" : $phprc));
254 critical_error("Please recompile PHP with the needed configuration, or refer to the installation instructions at http://pmmp.rtfd.io/en/rtfd/installation.html.");
263 $bootstrap = dirname(__FILE__, 2) . '/vendor/autoload.php
';
264 if(!is_file($bootstrap)){
265 critical_error("Composer autoloader not found at " . $bootstrap);
266 critical_error("Please install/update Composer dependencies or use provided builds.");
269 require_once($bootstrap);
272 if($composerGitHash !== null){
273 //we can't verify dependency versions
if we were installed without
using git
274 $currentGitHash = explode(
"-", VersionInfo::GIT_HASH(), 2)[0];
275 if($currentGitHash !== $composerGitHash){
276 critical_error(
"Composer dependencies and/or autoloader are out of sync.");
278 critical_error(
"- Composer dependencies were last synchronized for revision $composerGitHash");
279 critical_error(
"Out-of-sync Composer dependencies may result in crashes and classes not being found.");
280 critical_error(
"Please synchronize Composer dependencies before running the server.");
285 ErrorToExceptionHandler::set();
288 printf(
"%s %s (git hash %s) for Minecraft: Bedrock Edition %s\n", VersionInfo::NAME, VersionInfo::VERSION()->getFullVersion(
true), VersionInfo::GIT_HASH(), ProtocolInfo::MINECRAFT_VERSION);
292 if(defined(
'pocketmine\ORIGINAL_PHAR_PATH')){
294 Filesystem::addCleanedPath(ORIGINAL_PHAR_PATH, Filesystem::CLEAN_PATH_SRC_PREFIX);
297 $cwd = Utils::assumeNotFalse(realpath(Utils::assumeNotFalse(getcwd())));
300 Filesystem::addCleanedPath($pluginPath, Filesystem::CLEAN_PATH_PLUGINS_PREFIX);
302 if(!@mkdir($dataPath, 0777,
true) && !is_dir($dataPath)){
303 critical_error(
"Unable to create/access data directory at $dataPath. Check that the target location is accessible by the current user.");
307 $dataPath = realpath($dataPath) . DIRECTORY_SEPARATOR;
309 $lockFilePath = Path::join($dataPath,
'server.lock');
311 $pid = Filesystem::createLockFile($lockFilePath);
312 }
catch(\InvalidArgumentException $e){
314 critical_error(
"Please ensure that there is enough space on the disk and that the current user has read/write permissions to the selected data directory $dataPath.");
318 critical_error(
"Another " . VersionInfo::NAME .
" instance (PID $pid) is already using this folder (" . realpath($dataPath) .
").");
319 critical_error(
"Please stop the other server first before running a new one.");
323 if(!@mkdir($pluginPath, 0777,
true) && !is_dir($pluginPath)){
324 critical_error(
"Unable to create plugin directory at $pluginPath. Check that the target location is accessible by the current user.");
327 $pluginPath = realpath($pluginPath) . DIRECTORY_SEPARATOR;
334 Terminal::init(
true);
336 Terminal::init(
false);
342 $logger =
new MainLogger($logFile, Terminal::hasFormattingCodes(),
"Server",
new \DateTimeZone(Timezone::get()),
false, Path::join($dataPath,
"log_archive"));
343 if($logFile ===
null){
344 $logger->
notice(
"Logging to file disabled. Ensure logs are collected by other means (e.g. Docker logs).");
347 \GlobalLogger::set($logger);
354 $installer =
new SetupWizard($dataPath);
355 if(!$installer->run()){
364 $autoloader =
new ThreadSafeClassLoader();
365 $autoloader->register(
false);
367 new Server($autoloader, $logger, $dataPath, $pluginPath);
369 $logger->
info(
"Stopping other threads");
371 $killer =
new ServerKiller(8);
375 if(ThreadManager::getInstance()->stopAll() > 0){
376 $logger->
debug(
"Some threads could not be stopped, performing a force-kill");
377 Process::kill(Process::pid());
381 $logger->shutdownLogWriterThread();
383 echo Terminal::$FORMAT_RESET . PHP_EOL;
385 Filesystem::releaseLockFile($lockFilePath);