22declare(strict_types=1);
26 use Composer\InstalledVersions;
39 use Symfony\Component\Filesystem\Path;
41 use
function extension_loaded;
42 use
function function_exists;
47 use
function phpversion;
48 use
function preg_match;
49 use
function preg_quote;
51 use
function realpath;
52 use
function version_compare;
53 use
const DIRECTORY_SEPARATOR;
56 require_once __DIR__ .
'/VersionInfo.php';
58 const MIN_PHP_VERSION =
"8.1.0";
65 echo
"[ERROR] $message" . PHP_EOL;
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",
103 "igbinary" =>
"igbinary",
105 "leveldb" =>
"LevelDB",
106 "mbstring" =>
"Multibyte String",
107 "morton" =>
"morton",
108 "openssl" =>
"OpenSSL",
111 "pmmpthread" =>
"pmmpthread",
112 "reflection" =>
"Reflection",
113 "sockets" =>
"Sockets",
120 foreach($extensions as $ext => $name){
121 if(!extension_loaded($ext)){
122 $messages[] =
"Unable to find the $name ($ext) extension.";
126 if(($pmmpthread_version = phpversion(
"pmmpthread")) !==
false){
127 if(version_compare($pmmpthread_version,
"6.1.0") < 0 || version_compare($pmmpthread_version,
"7.0.0") >= 0){
128 $messages[] =
"pmmpthread ^6.1.0 is required, while you have $pmmpthread_version.";
132 if(($leveldb_version = phpversion(
"leveldb")) !==
false){
133 if(version_compare($leveldb_version,
"0.2.1") < 0){
134 $messages[] =
"php-leveldb >= 0.2.1 is required, while you have $leveldb_version.";
136 if(!defined(
'LEVELDB_ZLIB_RAW_COMPRESSION')){
137 $messages[] =
"Given version of php-leveldb doesn't support ZLIB_RAW compression (use https://github.com/pmmp/php-leveldb)";
141 $chunkutils2_version = phpversion(
"chunkutils2");
142 $wantedVersionLock =
"0.3";
143 $wantedVersionMin =
"$wantedVersionLock.0";
144 if($chunkutils2_version !==
false && (
145 version_compare($chunkutils2_version, $wantedVersionMin) < 0 ||
146 preg_match(
"/^" . preg_quote($wantedVersionLock,
"/") .
"\.\d+(?:-dev)?$/", $chunkutils2_version) === 0
148 $messages[] =
"chunkutils2 ^$wantedVersionMin is required, while you have $chunkutils2_version.";
151 if(($libdeflate_version = phpversion(
"libdeflate")) !==
false){
153 if(version_compare($libdeflate_version,
"0.2.0") < 0 || version_compare($libdeflate_version,
"0.3.0") >= 0){
154 $messages[] =
"php-libdeflate ^0.2.0 is required, while you have $libdeflate_version.";
158 if(extension_loaded(
"pocketmine")){
159 $messages[] =
"The native PocketMine extension is no longer supported.";
162 if(!defined(
'AF_INET6')){
163 $messages[] =
"IPv6 support is required, but your PHP binary was built without IPv6 support.";
173 if(ZEND_DEBUG_BUILD){
174 $logger->
warning(
"This PHP binary was compiled in debug mode. This has a major impact on performance.");
176 if(extension_loaded(
"xdebug") && (!function_exists(
'xdebug_info') || count(xdebug_info(
'mode')) !== 0)){
177 $logger->
warning(
"Xdebug extension is enabled. This has a major impact on performance.");
179 if(((
int) ini_get(
'zend.assertions')) !== -1){
180 $logger->
warning(
"Debugging assertions are enabled. This may degrade performance. To disable them, set `zend.assertions = -1` in php.ini.");
182 if(\Phar::running(
true) ===
""){
183 $logger->
warning(
"Non-packaged installation detected. This will degrade autoloading speed and make startup times longer.");
185 if(function_exists(
'opcache_get_status') && ($opcacheStatus = opcache_get_status(
false)) !==
false){
186 $jitEnabled = $opcacheStatus[
"jit"][
"on"] ??
false;
187 if($jitEnabled !==
false){
188 $logger->
warning(<<<
'JIT_WARNING'
191 --------------------------------------- ! WARNING ! ---------------------------------------
192 You
're using PHP with JIT enabled. This provides significant performance improvements.
193 HOWEVER, it is EXPERIMENTAL, and has already been seen to cause weird and unexpected bugs.
194 Proceed with caution.
195 If you want to report any bugs, make sure to mention that you have enabled PHP JIT.
196 To turn off JIT, change `opcache.jit` to `0` in your php.ini file.
197 -------------------------------------------------------------------------------------------
208 function set_ini_entries(){
209 ini_set("allow_url_fopen", '1
');
210 ini_set("display_errors", '1
');
211 ini_set("display_startup_errors", '1
');
212 ini_set("default_charset", "utf-8");
213 ini_set('assert.exception
', '1
');
216 function getopt_string(string $opt) : ?string{
217 $opts = getopt("", ["$opt:"]);
218 if(isset($opts[$opt])){
219 if(is_string($opts[$opt])){
222 if(is_array($opts[$opt])){
223 critical_error("Cannot specify --$opt multiple times");
225 critical_error("Missing value for --$opt");
236 if(count($messages = check_platform_dependencies()) > 0){
238 $binary = version_compare(PHP_VERSION, "5.4") >= 0 ? PHP_BINARY : "unknown";
239 critical_error("Selected PHP binary does not satisfy some requirements.");
240 foreach($messages as $m){
241 echo " - $m" . PHP_EOL;
243 critical_error("PHP binary used: " . $binary);
244 critical_error("Loaded php.ini: " . (($file = php_ini_loaded_file()) !== false ? $file : "none"));
245 $phprc = getenv("PHPRC");
246 critical_error("Value of PHPRC environment variable: " . ($phprc === false ? "" : $phprc));
247 critical_error("Please recompile PHP with the needed configuration, or refer to the installation instructions at http://pmmp.rtfd.io/en/rtfd/installation.html.");
256 $bootstrap = dirname(__FILE__, 2) . '/vendor/autoload.php
';
257 if(!is_file($bootstrap)){
258 critical_error("Composer autoloader not found at " . $bootstrap);
259 critical_error("Please install/update Composer dependencies or use provided builds.");
262 require_once($bootstrap);
265 if($composerGitHash !== null){
266 //we can't verify dependency versions
if we were installed without
using git
267 $currentGitHash = explode(
"-", VersionInfo::GIT_HASH())[0];
268 if($currentGitHash !== $composerGitHash){
269 critical_error(
"Composer dependencies and/or autoloader are out of sync.");
271 critical_error(
"- Composer dependencies were last synchronized for revision $composerGitHash");
272 critical_error(
"Out-of-sync Composer dependencies may result in crashes and classes not being found.");
273 critical_error(
"Please synchronize Composer dependencies before running the server.");
281 printf(
"%s %s (git hash %s) for Minecraft: Bedrock Edition %s\n", VersionInfo::NAME, VersionInfo::VERSION()->getFullVersion(
true), VersionInfo::GIT_HASH(),
ProtocolInfo::MINECRAFT_VERSION);
288 Filesystem::addCleanedPath($pluginPath, Filesystem::CLEAN_PATH_PLUGINS_PREFIX);
290 if(!@mkdir($dataPath, 0777,
true) && !is_dir($dataPath)){
291 critical_error(
"Unable to create/access data directory at $dataPath. Check that the target location is accessible by the current user.");
295 $dataPath = realpath($dataPath) . DIRECTORY_SEPARATOR;
297 $lockFilePath = Path::join($dataPath,
'server.lock');
300 }
catch(\InvalidArgumentException $e){
302 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.");
306 critical_error(
"Another " . VersionInfo::NAME .
" instance (PID $pid) is already using this folder (" . realpath($dataPath) .
").");
307 critical_error(
"Please stop the other server first before running a new one.");
311 if(!@mkdir($pluginPath, 0777,
true) && !is_dir($pluginPath)){
312 critical_error(
"Unable to create plugin directory at $pluginPath. Check that the target location is accessible by the current user.");
315 $pluginPath = realpath($pluginPath) . DIRECTORY_SEPARATOR;
322 Terminal::init(
true);
324 Terminal::init(
false);
330 $logger =
new MainLogger($logFile, Terminal::hasFormattingCodes(),
"Server",
new \DateTimeZone(Timezone::get()),
false, Path::join($dataPath,
"log_archive"));
331 if($logFile ===
null){
332 $logger->
notice(
"Logging to file disabled. Ensure logs are collected by other means (e.g. Docker logs).");
335 \GlobalLogger::set($logger);
342 $installer =
new SetupWizard($dataPath);
343 if(!$installer->run()){
352 $autoloader =
new ThreadSafeClassLoader();
353 $autoloader->register(
false);
355 new Server($autoloader, $logger, $dataPath, $pluginPath);
357 $logger->
info(
"Stopping other threads");
359 $killer =
new ServerKiller(8);
363 if(ThreadManager::getInstance()->stopAll() > 0){
364 $logger->
debug(
"Some threads could not be stopped, performing a force-kill");
369 $logger->shutdownLogWriterThread();
371 echo Terminal::$FORMAT_RESET . PHP_EOL;
378 \pocketmine\server();
static set(int $levels=E_WARNING|E_NOTICE)
static createLockFile(string $lockFilePath)
static releaseLockFile(string $lockFilePath)
static kill(int $pid, bool $subprocesses=false)
static assumeNotFalse(mixed $value, \Closure|string $context="This should never be false")
check_platform_dependencies()
emit_performance_warnings(\Logger $logger)