From 4765242397d4d6185e2bf7a7a6920432b0e5e205 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 10 Jun 2017 16:11:28 +0100 Subject: [PATCH] Drop support for 32 bit systems/PHP (#984) * Cutting out 32-bit and minor improvements to bootstrap * Byeeeeee * Removing legacy code * added note to the issue template as suggested by @xxFlare --- .github/ISSUE_TEMPLATE.md | 9 +- src/pocketmine/MemoryManager.php | 5 - src/pocketmine/PocketMine.php | 220 ++++++++++++++-------------- src/pocketmine/level/Level.php | 27 +--- src/pocketmine/utils/Binary.php | 238 +++---------------------------- 5 files changed, 143 insertions(+), 356 deletions(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 84883b705..46ce1b203 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -16,9 +16,12 @@ Actual result: What actually happened? ### OS and versions * PocketMine-MP: * PHP: diff --git a/src/pocketmine/MemoryManager.php b/src/pocketmine/MemoryManager.php index 3c32dae8b..0585ae77b 100644 --- a/src/pocketmine/MemoryManager.php +++ b/src/pocketmine/MemoryManager.php @@ -91,11 +91,6 @@ class MemoryManager{ $hardLimit = ((int) $this->server->getProperty("memory.main-hard-limit", $defaultMemory)); - if(PHP_INT_SIZE === 4 and $hardLimit >= 4096){ - $this->server->getLogger()->warning("Cannot set memory limit higher than 4GB on 32-bit, defaulting to max 4095MB"); - $hardLimit = 4095; - } - if($hardLimit <= 0){ ini_set("memory_limit", -1); }else{ diff --git a/src/pocketmine/PocketMine.php b/src/pocketmine/PocketMine.php index 82063ae98..b8f6b860c 100644 --- a/src/pocketmine/PocketMine.php +++ b/src/pocketmine/PocketMine.php @@ -401,137 +401,135 @@ namespace pocketmine { return rtrim(str_replace(["\\", ".php", "phar://", rtrim(str_replace(["\\", "phar://"], ["/", ""], \pocketmine\PATH), "/"), rtrim(str_replace(["\\", "phar://"], ["/", ""], \pocketmine\PLUGIN_PATH), "/")], ["/", "", "", "", ""], $path), "/"); } - $errors = 0; + $exitCode = 0; - if(php_sapi_name() !== "cli"){ - $logger->critical("You must run PocketMine-MP using the CLI."); - ++$errors; - } + do{ + $errors = 0; - $pthreads_version = phpversion("pthreads"); - if(substr_count($pthreads_version, ".") < 2){ - $pthreads_version = "0.$pthreads_version"; - } - if(version_compare($pthreads_version, "3.1.5") < 0){ - $logger->critical("pthreads >= 3.1.5 is required, while you have $pthreads_version."); - ++$errors; - } + if(PHP_INT_SIZE < 8){ + $logger->critical("Running PocketMine-MP with 32-bit systems/PHP is no longer supported. Please upgrade to a 64-bit system or use a 64-bit PHP binary."); + $exitCode = 1; + break; + } - if(extension_loaded("pocketmine")){ - if(version_compare(phpversion("pocketmine"), "0.0.1") < 0){ - $logger->critical("You have the native PocketMine extension, but your version is lower than 0.0.1."); - ++$errors; - }elseif(version_compare(phpversion("pocketmine"), "0.0.4") > 0){ - $logger->critical("You have the native PocketMine extension, but your version is higher than 0.0.4."); + if(php_sapi_name() !== "cli"){ + $logger->critical("You must run PocketMine-MP using the CLI."); ++$errors; } - } - if(extension_loaded("xdebug")){ - $logger->warning(" - - - You are running PocketMine with xdebug enabled. This has a major impact on performance. - - "); - } - - $extensions = [ - "curl" => "cURL", - "json" => "JSON", - "mbstring" => "Multibyte String", - "yaml" => "YAML", - "sockets" => "Sockets", - "zip" => "Zip", - "zlib" => "Zlib" - ]; - - foreach($extensions as $ext => $name){ - if(!extension_loaded($ext)){ - $logger->critical("Unable to find the $name ($ext) extension."); + $pthreads_version = phpversion("pthreads"); + if(substr_count($pthreads_version, ".") < 2){ + $pthreads_version = "0.$pthreads_version"; + } + if(version_compare($pthreads_version, "3.1.5") < 0){ + $logger->critical("pthreads >= 3.1.5 is required, while you have $pthreads_version."); ++$errors; } - } - if($errors > 0){ - $logger->critical("Please use the installer provided on the homepage, or recompile PHP again."); - $logger->shutdown(); - $logger->join(); - exit(1); //Exit with error - } - - if(PHP_INT_SIZE < 8){ - $logger->warning("Running PocketMine-MP with 32-bit systems/PHP is deprecated. Support for 32-bit may be dropped in the future."); - } - - $gitHash = str_repeat("00", 20); - if(file_exists(\pocketmine\PATH . ".git/HEAD")){ //Found Git information! - $ref = trim(file_get_contents(\pocketmine\PATH . ".git/HEAD")); - if(preg_match('/^[0-9a-f]{40}$/i', $ref)){ - $gitHash = strtolower($ref); - }elseif(substr($ref, 0, 5) === "ref: "){ - $refFile = \pocketmine\PATH . ".git/" . substr($ref, 5); - if(is_file($refFile)){ - $gitHash = strtolower(trim(file_get_contents($refFile))); + if(extension_loaded("pocketmine")){ + if(version_compare(phpversion("pocketmine"), "0.0.1") < 0){ + $logger->critical("You have the native PocketMine extension, but your version is lower than 0.0.1."); + ++$errors; + }elseif(version_compare(phpversion("pocketmine"), "0.0.4") > 0){ + $logger->critical("You have the native PocketMine extension, but your version is higher than 0.0.4."); + ++$errors; } } - } - define('pocketmine\GIT_COMMIT', $gitHash); - - - @define("ENDIANNESS", (pack("d", 1) === "\77\360\0\0\0\0\0\0" ? Binary::BIG_ENDIAN : Binary::LITTLE_ENDIAN)); - @define("INT32_MASK", is_int(0xffffffff) ? 0xffffffff : -1); - @ini_set("opcache.mmap_base", bin2hex(random_bytes(8))); //Fix OPCache address errors - - - if(!file_exists(\pocketmine\DATA . "server.properties") and !isset($opts["no-wizard"])){ - $installer = new SetupWizard(); - if(!$installer->run()){ - $logger->shutdown(); - $logger->join(); - exit(-1); + if(extension_loaded("xdebug")){ + $logger->warning(PHP_EOL . PHP_EOL . PHP_EOL . "\tYou are running PocketMine with xdebug enabled. This has a major impact on performance." . PHP_EOL . PHP_EOL); } - } + $extensions = [ + "curl" => "cURL", + "json" => "JSON", + "mbstring" => "Multibyte String", + "yaml" => "YAML", + "sockets" => "Sockets", + "zip" => "Zip", + "zlib" => "Zlib" + ]; - if(\Phar::running(true) === ""){ - $logger->warning("Non-packaged PocketMine-MP installation detected, do not use on production."); - } - - ThreadManager::init(); - new Server($autoloader, $logger, \pocketmine\PATH, \pocketmine\DATA, \pocketmine\PLUGIN_PATH); - - $logger->info("Stopping other threads"); - - $killer = new ServerKiller(8); - $killer->start(); - usleep(10000); //Fixes ServerKiller not being able to start on single-core machines - - $erroredThreads = 0; - foreach(ThreadManager::getInstance()->getAll() as $id => $thread){ - $logger->debug("Stopping " . $thread->getThreadName() . " thread"); - try{ - $thread->quit(); - $logger->debug($thread->getThreadName() . " thread stopped successfully."); - }catch(\ThreadException $e){ - ++$erroredThreads; - $logger->debug("Could not stop " . $thread->getThreadName() . " thread: " . $e->getMessage()); + foreach($extensions as $ext => $name){ + if(!extension_loaded($ext)){ + $logger->critical("Unable to find the $name ($ext) extension."); + ++$errors; + } } - } + + if($errors > 0){ + $logger->critical("Please use the installer provided on the homepage, or recompile PHP again."); + $exitCode = 1; + break; + } + + $gitHash = str_repeat("00", 20); + if(file_exists(\pocketmine\PATH . ".git/HEAD")){ //Found Git information! + $ref = trim(file_get_contents(\pocketmine\PATH . ".git/HEAD")); + if(preg_match('/^[0-9a-f]{40}$/i', $ref)){ + $gitHash = strtolower($ref); + }elseif(substr($ref, 0, 5) === "ref: "){ + $refFile = \pocketmine\PATH . ".git/" . substr($ref, 5); + if(is_file($refFile)){ + $gitHash = strtolower(trim(file_get_contents($refFile))); + } + } + } + + define('pocketmine\GIT_COMMIT', $gitHash); + + + @define("ENDIANNESS", (pack("d", 1) === "\77\360\0\0\0\0\0\0" ? Binary::BIG_ENDIAN : Binary::LITTLE_ENDIAN)); + @define("INT32_MASK", is_int(0xffffffff) ? 0xffffffff : -1); + @ini_set("opcache.mmap_base", bin2hex(random_bytes(8))); //Fix OPCache address errors + + + if(!file_exists(\pocketmine\DATA . "server.properties") and !isset($opts["no-wizard"])){ + $installer = new SetupWizard(); + if(!$installer->run()){ + $exitCode = -1; + break; + } + } + + + if(\Phar::running(true) === ""){ + $logger->warning("Non-packaged PocketMine-MP installation detected, do not use on production."); + } + + ThreadManager::init(); + new Server($autoloader, $logger, \pocketmine\PATH, \pocketmine\DATA, \pocketmine\PLUGIN_PATH); + + $logger->info("Stopping other threads"); + + $killer = new ServerKiller(8); + $killer->start(); + usleep(10000); //Fixes ServerKiller not being able to start on single-core machines + + $erroredThreads = 0; + foreach(ThreadManager::getInstance()->getAll() as $id => $thread){ + $logger->debug("Stopping " . $thread->getThreadName() . " thread"); + try{ + $thread->quit(); + $logger->debug($thread->getThreadName() . " thread stopped successfully."); + }catch(\ThreadException $e){ + ++$erroredThreads; + $logger->debug("Could not stop " . $thread->getThreadName() . " thread: " . $e->getMessage()); + } + } + + if($erroredThreads > 0){ + if(\pocketmine\DEBUG > 1){ + echo "Some threads could not be stopped, performing a force-kill" . PHP_EOL . PHP_EOL; + } + kill(getmypid()); + } + }while(false); $logger->shutdown(); $logger->join(); echo Terminal::$FORMAT_RESET . PHP_EOL; - if($erroredThreads > 0){ - if(\pocketmine\DEBUG > 1){ - echo "Some threads could not be stopped, performing a force-kill" . PHP_EOL . PHP_EOL; - } - kill(getmypid()); - }else{ - exit(0); - } - + exit($exitCode); } diff --git a/src/pocketmine/level/Level.php b/src/pocketmine/level/Level.php index ad909d12d..3dd42bbb1 100644 --- a/src/pocketmine/level/Level.php +++ b/src/pocketmine/level/Level.php @@ -265,24 +265,17 @@ class Level implements ChunkManager, Metadatable{ private $closed = false; public static function chunkHash(int $x, int $z){ - return PHP_INT_SIZE === 8 ? (($x & 0xFFFFFFFF) << 32) | ($z & 0xFFFFFFFF) : $x . ":" . $z; + return (($x & 0xFFFFFFFF) << 32) | ($z & 0xFFFFFFFF); } public static function blockHash(int $x, int $y, int $z){ - return PHP_INT_SIZE === 8 ? (($x & 0xFFFFFFF) << 36) | (($y & Level::Y_MASK) << 28) | ($z & 0xFFFFFFF) : $x . ":" . $y . ":" . $z; + return (($x & 0xFFFFFFF) << 36) | (($y & Level::Y_MASK) << 28) | ($z & 0xFFFFFFF); } public static function getBlockXYZ($hash, &$x, &$y, &$z){ - if(PHP_INT_SIZE === 8){ - $x = $hash >> 36; - $y = ($hash >> 28) & Level::Y_MASK; //it's always positive - $z = ($hash & 0xFFFFFFF) << 36 >> 36; - }else{ - $hash = explode(":", $hash); - $x = (int) $hash[0]; - $y = (int) $hash[1]; - $z = (int) $hash[2]; - } + $x = $hash >> 36; + $y = ($hash >> 28) & Level::Y_MASK; //it's always positive + $z = ($hash & 0xFFFFFFF) << 36 >> 36; } /** @@ -291,14 +284,8 @@ class Level implements ChunkManager, Metadatable{ * @param int|null $z */ public static function getXZ($hash, &$x, &$z){ - if(PHP_INT_SIZE === 8){ - $x = $hash >> 32; - $z = ($hash & 0xFFFFFFFF) << 32 >> 32; - }else{ - $hash = explode(":", $hash); - $x = (int) $hash[0]; - $z = (int) $hash[1]; - } + $x = $hash >> 32; + $z = ($hash & 0xFFFFFFFF) << 32 >> 32; } public static function generateChunkLoaderId(ChunkLoader $loader) : int{ diff --git a/src/pocketmine/utils/Binary.php b/src/pocketmine/utils/Binary.php index b88b819f9..df7c3c9bc 100644 --- a/src/pocketmine/utils/Binary.php +++ b/src/pocketmine/utils/Binary.php @@ -73,7 +73,7 @@ class Binary{ * @return int */ public static function readSignedByte(string $c) : int{ - return PHP_INT_SIZE === 8 ? (ord($c{0}) << 56 >> 56) : (ord($c{0}) << 24 >> 24); + return ord($c{0}) << 56 >> 56; } /** @@ -106,11 +106,7 @@ class Binary{ */ public static function readSignedShort(string $str) : int{ self::checkLength($str, 2); - if(PHP_INT_SIZE === 8){ - return unpack("n", $str)[1] << 48 >> 48; - }else{ - return unpack("n", $str)[1] << 16 >> 16; - } + return unpack("n", $str)[1] << 48 >> 48; } /** @@ -145,11 +141,7 @@ class Binary{ */ public static function readSignedLShort(string $str) : int{ self::checkLength($str, 2); - if(PHP_INT_SIZE === 8){ - return unpack("v", $str)[1] << 48 >> 48; - }else{ - return unpack("v", $str)[1] << 16 >> 16; - } + return unpack("v", $str)[1] << 48 >> 48; } /** @@ -213,11 +205,7 @@ class Binary{ */ public static function readInt(string $str) : int{ self::checkLength($str, 4); - if(PHP_INT_SIZE === 8){ - return unpack("N", $str)[1] << 32 >> 32; - }else{ - return unpack("N", $str)[1]; - } + return unpack("N", $str)[1] << 32 >> 32; } /** @@ -238,11 +226,7 @@ class Binary{ */ public static function readLInt(string $str) : int{ self::checkLength($str, 4); - if(PHP_INT_SIZE === 8){ - return unpack("V", $str)[1] << 32 >> 32; - }else{ - return unpack("V", $str)[1]; - } + return unpack("V", $str)[1] << 32 >> 32; } /** @@ -381,22 +365,8 @@ class Binary{ */ public static function readLong(string $x){ self::checkLength($x, 8); - if(PHP_INT_SIZE === 8){ - $int = unpack("N*", $x); - return ($int[1] << 32) | $int[2]; - }else{ - $value = "0"; - for($i = 0; $i < 8; $i += 2){ - $value = bcmul($value, "65536", 0); - $value = bcadd($value, (string) self::readShort(substr($x, $i, 2)), 0); - } - - if(bccomp($value, "9223372036854775807") == 1){ - $value = bcadd($value, "-18446744073709551616"); - } - - return $value; - } + $int = unpack("N*", $x); + return ($int[1] << 32) | $int[2]; } /** @@ -406,23 +376,7 @@ class Binary{ * @return string */ public static function writeLong($value) : string{ - if(PHP_INT_SIZE === 8){ - return pack("NN", $value >> 32, $value & 0xFFFFFFFF); - }else{ - $x = ""; - $value = (string) $value; - - if(bccomp($value, "0") == -1){ - $value = bcadd($value, "18446744073709551616"); - } - - $x .= self::writeShort((int) bcmod(bcdiv($value, "281474976710656"), "65536")); - $x .= self::writeShort((int) bcmod(bcdiv($value, "4294967296"), "65536")); - $x .= self::writeShort((int) bcmod(bcdiv($value, "65536"), "65536")); - $x .= self::writeShort((int) bcmod($value, "65536")); - - return $x; - } + return pack("NN", $value >> 32, $value & 0xFFFFFFFF); } /** @@ -455,10 +409,9 @@ class Binary{ * @return int */ public static function readVarInt(string $buffer, int &$offset) : int{ - $shift = PHP_INT_SIZE === 8 ? 63 : 31; $raw = self::readUnsignedVarInt($buffer, $offset); - $temp = ((($raw << $shift) >> $shift) ^ $raw) >> 1; - return $temp ^ ($raw & (1 << $shift)); + $temp = ((($raw << 63) >> 63) ^ $raw) >> 1; + return $temp ^ ($raw & (1 << 63)); } /** @@ -494,9 +447,7 @@ class Binary{ * @return string */ public static function writeVarInt(int $v) : string{ - if(PHP_INT_SIZE === 8){ - $v = ($v << 32 >> 32); - } + $v = ($v << 32 >> 32); return self::writeUnsignedVarInt(($v << 1) ^ ($v >> 31)); } @@ -525,103 +476,28 @@ class Binary{ /** - * Reads a 64-bit zigzag-encoded variable-length integer from the supplied stream. - * - * @param string $buffer - * @param int &$offset - * - * @return int|string - */ - public static function readVarLong(string $buffer, int &$offset){ - if(PHP_INT_SIZE === 8){ - return self::readVarLong_64($buffer, $offset); - }else{ - return self::readVarLong_32($buffer, $offset); - } - } - - /** - * Legacy BC Math zigzag VarLong reader. Will work on 32-bit or 64-bit, but will be slower than the regular 64-bit method. - * - * @param string $buffer - * @param int &$offset - * - * @return string - */ - public static function readVarLong_32(string $buffer, int &$offset) : string{ - /** @var string $raw */ - $raw = self::readUnsignedVarLong_32($buffer, $offset); - $result = bcdiv($raw, "2"); - if(bcmod($raw, "2") === "1"){ - $result = bcsub(bcmul($result, "-1"), "1"); - } - - return $result; - } - - /** - * 64-bit zizgag VarLong reader. + * Reads a 64-bit zigzag-encoded variable-length integer. * * @param string $buffer * @param int &$offset * * @return int */ - public static function readVarLong_64(string $buffer, int &$offset) : int{ - $raw = self::readUnsignedVarLong_64($buffer, $offset); + public static function readVarLong(string $buffer, int &$offset) : int{ + $raw = self::readUnsignedVarLong($buffer, $offset); $temp = ((($raw << 63) >> 63) ^ $raw) >> 1; return $temp ^ ($raw & (1 << 63)); } /** - * Reads an unsigned VarLong from the supplied stream. - * - * @param string $buffer - * @param int &$offset - * - * @return int|string - */ - public static function readUnsignedVarLong(string $buffer, int &$offset){ - if(PHP_INT_SIZE === 8){ - return self::readUnsignedVarLong_64($buffer, $offset); - }else{ - return self::readUnsignedVarLong_32($buffer, $offset); - } - } - - /** - * Legacy BC Math unsigned VarLong reader. - * - * @param string $buffer - * @param int &$offset - * - * @return string - */ - public static function readUnsignedVarLong_32(string $buffer, int &$offset) : string{ - $value = "0"; - for($i = 0; $i <= 63; $i += 7){ - $b = ord($buffer{$offset++}); - $value = bcadd($value, bcmul((string) ($b & 0x7f), bcpow("2", "$i"))); - - if(($b & 0x80) === 0){ - return $value; - }elseif(!isset($buffer{$offset})){ - throw new \UnexpectedValueException("Expected more bytes, none left to read"); - } - } - - throw new \InvalidArgumentException("VarLong did not terminate after 10 bytes!"); - } - - /** - * 64-bit unsigned VarLong reader. + * Reads a 64-bit unsigned variable-length integer. * * @param string $buffer * @param int &$offset * * @return int */ - public static function readUnsignedVarLong_64(string $buffer, int &$offset) : int{ + public static function readUnsignedVarLong(string $buffer, int &$offset) : int{ $value = 0; for($i = 0; $i <= 63; $i += 7){ $b = ord($buffer{$offset++}); @@ -637,95 +513,23 @@ class Binary{ throw new \InvalidArgumentException("VarLong did not terminate after 10 bytes!"); } - - /** - * Writes a 64-bit integer as a variable-length long. - * - * @param int|string $v - * @return string up to 10 bytes - */ - public static function writeVarLong($v) : string{ - if(PHP_INT_SIZE === 8){ - return self::writeVarLong_64($v); - }else{ - return self::writeVarLong_32((string) $v); - } - } - - /** - * Legacy BC Math zigzag VarLong encoder. - * - * @param string $v - * @return string - */ - public static function writeVarLong_32(string $v) : string{ - $v = bcmod(bcmul($v, "2"), "18446744073709551616"); - if(bccomp($v, "0") == -1){ - $v = bcsub(bcmul($v, "-1"), "1"); - } - - return self::writeUnsignedVarLong_32($v); - } - - /** - * 64-bit VarLong encoder. + * Writes a 64-bit integer as a zigzag-encoded variable-length long. * * @param int $v * @return string */ - public static function writeVarLong_64(int $v) : string{ - return self::writeUnsignedVarLong_64(($v << 1) ^ ($v >> 63)); + public static function writeVarLong(int $v) : string{ + return self::writeUnsignedVarLong(($v << 1) ^ ($v >> 63)); } /** - * Writes a 64-bit integer as a variable-length long - * - * @param int|string $v - * @return string up to 10 bytes - */ - public static function writeUnsignedVarLong($v) : string{ - if(PHP_INT_SIZE === 8){ - return self::writeUnsignedVarLong_64($v); - }else{ - return self::writeUnsignedVarLong_32((string) $v); - } - } - - /** - * Legacy BC Math unsigned VarLong encoder. - * - * @param string $value - * @return string - */ - public static function writeUnsignedVarLong_32(string $value) : string{ - $buf = ""; - - if(bccomp($value, "0") == -1){ - $value = bcadd($value, "18446744073709551616"); - } - - for($i = 0; $i < 10; ++$i){ - $byte = (int) bcmod($value, "128"); - $value = bcdiv($value, "128"); - if($value !== "0"){ - $buf .= chr($byte | 0x80); - }else{ - $buf .= chr($byte); - return $buf; - } - } - - throw new \InvalidArgumentException("Value too large to be encoded as a VarLong"); - } - - /** - * 64-bit unsigned VarLong encoder. + * Writes a 64-bit unsigned integer as a variable-length long. * @param int $value * * @return string */ - public static function writeUnsignedVarLong_64(int $value) : string{ + public static function writeUnsignedVarLong(int $value) : string{ $buf = ""; for($i = 0; $i < 10; ++$i){ if(($value >> 7) !== 0){