106    public const OS_WINDOWS = 
"win";
 
  107    public const OS_IOS = 
"ios";
 
  108    public const OS_MACOS = 
"mac";
 
  109    public const OS_ANDROID = 
"android";
 
  110    public const OS_LINUX = 
"linux";
 
  111    public const OS_BSD = 
"bsd";
 
  112    public const OS_UNKNOWN = 
"other";
 
  114    private static ?
string $os = 
null;
 
  115    private static ?UuidInterface $serverUniqueId = 
null;
 
  116    private static ?
int $cpuCores = 
null;
 
  125        $func = new \ReflectionFunction($closure);
 
  126        if(!str_contains($func->getName(), 
'{closure')){
 
  130            $scope = $func->getClosureScopeClass();
 
  134                    ($func->getClosureThis() !== null ? 
"->" : 
"::") .
 
  139            return $func->getName();
 
  141        $filename = $func->getFileName();
 
  143        return "closure@" . ($filename !== 
false ?
 
  144                Filesystem::cleanPath($filename) . 
"#L" . $func->getStartLine() :
 
 
  155        $reflect = new \ReflectionClass($obj);
 
  156        if($reflect->isAnonymous()){
 
  157            $filename = $reflect->getFileName();
 
  159            return 
"anonymous@" . ($filename !== false ?
 
  160                    Filesystem::cleanPath($filename) . 
"#L" . $reflect->getStartLine() :
 
  165        return $reflect->getName();
 
 
  173        return static function(object $o){
 
 
  189        return array_map(fn(object $o) => clone $o, $array);
 
 
  201        if(self::$serverUniqueId !== null && $extra === 
""){
 
  202            return self::$serverUniqueId;
 
  205        $machine = php_uname(
"a");
 
  206        $cpuinfo = @file(
"/proc/cpuinfo");
 
  207        if($cpuinfo !== 
false){
 
  208            $cpuinfoLines = preg_grep(
"/(model name|Processor|Serial)/", $cpuinfo);
 
  209            if($cpuinfoLines === 
false){
 
  212            $machine .= implode(
"", $cpuinfoLines);
 
  214        $machine .= sys_get_temp_dir();
 
  216        $os = Utils::getOS();
 
  217        if($os === Utils::OS_WINDOWS){
 
  218            @exec(
"ipconfig /ALL", $mac);
 
  219            $mac = implode(
"\n", $mac);
 
  220            if(preg_match_all(
"#Physical Address[. ]{1,}: ([0-9A-F\\-]{17})#", $mac, $matches) > 0){
 
  221                foreach($matches[1] as $i => $v){
 
  222                    if($v === 
"00-00-00-00-00-00"){
 
  223                        unset($matches[1][$i]);
 
  226                $machine .= implode(
" ", $matches[1]); 
 
  228        }elseif($os === Utils::OS_LINUX){
 
  229            if(file_exists(
"/etc/machine-id")){
 
  230                $machine .= file_get_contents(
"/etc/machine-id");
 
  232                @exec(
"ifconfig 2>/dev/null", $mac);
 
  233                $mac = implode(
"\n", $mac);
 
  234                if(preg_match_all(
"#HWaddr[ \t]{1,}([0-9a-f:]{17})#", $mac, $matches) > 0){
 
  235                    foreach($matches[1] as $i => $v){
 
  236                        if($v === 
"00:00:00:00:00:00"){
 
  237                            unset($matches[1][$i]);
 
  240                    $machine .= implode(
" ", $matches[1]); 
 
  243        }elseif($os === Utils::OS_ANDROID){
 
  244            $machine .= @file_get_contents(
"/system/build.prop");
 
  245        }elseif($os === Utils::OS_MACOS){
 
  246            $machine .= shell_exec(
"system_profiler SPHardwareDataType | grep UUID");
 
  248        $data = $machine . PHP_MAXPATHLEN;
 
  249        $data .= PHP_INT_MAX;
 
  250        $data .= PHP_INT_SIZE;
 
  251        $data .= get_current_user();
 
  252        foreach(get_loaded_extensions() as $ext){
 
  253            $data .= $ext . 
":" . phpversion($ext);
 
  257        $uuid = Uuid::uuid3(Uuid::NIL, $data);
 
  260            self::$serverUniqueId = $uuid;
 
 
  269    public static function getOS(
bool $recalculate = 
false) : string{
 
  270        if(self::$os === null || $recalculate){
 
  271            $uname = php_uname(
"s");
 
  272            if(stripos($uname, 
"Darwin") !== 
false){
 
  273                if(str_starts_with(php_uname(
"m"), 
"iP")){
 
  274                    self::$os = self::OS_IOS;
 
  276                    self::$os = self::OS_MACOS;
 
  278            }elseif(stripos($uname, 
"Win") !== 
false || $uname === 
"Msys"){
 
  279                self::$os = self::OS_WINDOWS;
 
  280            }elseif(stripos($uname, 
"Linux") !== 
false){
 
  281                if(@file_exists(
"/system/build.prop")){
 
  282                    self::$os = self::OS_ANDROID;
 
  284                    self::$os = self::OS_LINUX;
 
  286            }elseif(stripos($uname, 
"BSD") !== 
false || $uname === 
"DragonFly"){
 
  287                self::$os = self::OS_BSD;
 
  289                self::$os = self::OS_UNKNOWN;
 
 
  296    public static function getCoreCount(
bool $recalculate = 
false) : int{
 
  297        if(self::$cpuCores !== null && !$recalculate){
 
  298            return self::$cpuCores;
 
  302        switch(Utils::getOS()){
 
  303            case Utils::OS_LINUX:
 
  304            case Utils::OS_ANDROID:
 
  305                if(($cpuinfo = @file(
'/proc/cpuinfo')) !== 
false){
 
  306                    foreach($cpuinfo as $l){
 
  307                        if(preg_match(
'/^processor[ \t]*:[ \t]*[0-9]+$/m', $l) > 0){
 
  311                }elseif(($cpuPresent = @file_get_contents(
"/sys/devices/system/cpu/present")) !== 
false){
 
  312                    if(preg_match(
"/^([0-9]+)\\-([0-9]+)$/", trim($cpuPresent), $matches) > 0){
 
  313                        $processors = ((int) $matches[2]) - ((
int) $matches[1]);
 
  318            case Utils::OS_MACOS:
 
  319                $processors = (int) shell_exec(
"sysctl -n hw.ncpu");
 
  321            case Utils::OS_WINDOWS:
 
  322                $processors = (int) getenv(
"NUMBER_OF_PROCESSORS");
 
  325        return self::$cpuCores = $processors;
 
  331    public static function hexdump(
string $bin) : string{
 
  333        $bin = str_split($bin, 16);
 
  334        foreach($bin as $counter => $line){
 
  335            $hex = chunk_split(chunk_split(str_pad(bin2hex($line), 32, 
" ", STR_PAD_RIGHT), 2, 
" "), 24, 
" ");
 
  336            $ascii = preg_replace(
'#([^\x20-\x7E])#', 
".", $line);
 
  337            $output .= str_pad(dechex($counter << 4), 4, 
"0", STR_PAD_LEFT) . 
"  " . $hex . 
" " . $ascii . PHP_EOL;
 
 
  347        if(!is_string($str)){
 
  348            return gettype($str);
 
  351        return preg_replace(
'#([^\x20-\x7E])#', 
'.', $str);
 
 
  354    public static function javaStringHash(
string $string) : int{
 
  356        for($i = 0, $len = strlen($string); $i < $len; $i++){
 
  357            $ord = ord($string[$i]);
 
  358            if(($ord & 0x80) !== 0){
 
  361            $hash = 31 * $hash + $ord;
 
  367    public static function getReferenceCount(
object $value, 
bool $includeCurrent = 
true) : int{
 
  369        debug_zval_dump($value);
 
  370        $contents = ob_get_contents();
 
  371        if($contents === 
false) 
throw new AssumptionFailedError(
"ob_get_contents() should never return false here");
 
  372        $ret = explode(
"\n", $contents, limit: 2);
 
  375        if(preg_match(
'/^.* refcount\\(([0-9]+)\\)\\{$/', trim($ret[0]), $m) > 0){
 
  376            return ((
int) $m[1]) - ($includeCurrent ? 3 : 4); 
 
  381    private static function printableExceptionMessage(\Throwable $e) : string{
 
  382        $errstr = preg_replace(
'/\s+/', 
' ', trim($e->getMessage()));
 
  384        $errno = $e->getCode();
 
  387                $errno = ErrorTypeToStringMap::get($errno);
 
  388            }
catch(\InvalidArgumentException $ex){
 
  393        $errfile = Filesystem::cleanPath($e->getFile());
 
  394        $errline = $e->getLine();
 
  396        return get_class($e) . 
": \"$errstr\" ($errno) in \"$errfile\" at line $errline";
 
  406            $trace = $e->getTrace();
 
  409        $lines = [self::printableExceptionMessage($e)];
 
  410        $lines[] = 
"--- Stack trace ---";
 
  411        foreach(Utils::printableTrace($trace) as $line){
 
  412            $lines[] = 
"  " . $line;
 
  414        for($prev = $e->getPrevious(); $prev !== 
null; $prev = $prev->getPrevious()){
 
  415            $lines[] = 
"--- Previous ---";
 
  416            $lines[] = self::printableExceptionMessage($prev);
 
  417            foreach(Utils::printableTrace($prev->getTrace()) as $line){
 
  418                $lines[] = 
"  " . $line;
 
  421        $lines[] = 
"--- End of exception information ---";
 
 
  425    private static function stringifyValueForTrace(mixed $value, 
int $maxStringLength) : string{
 
  427            is_object($value) => 
"object " . self::getNiceClassName($value) . 
"#" . spl_object_id($value),
 
  428            is_array($value) => 
"array[" . count($value) . 
"]",
 
  429            is_string($value) => 
"string[" . strlen($value) . 
"] " . substr(Utils::printable($value), 0, $maxStringLength),
 
  430            is_bool($value) => $value ? 
"true" : 
"false",
 
  431            is_int($value) => 
"int " . $value,
 
  432            is_float($value) => 
"float " . $value,
 
  433            $value === 
null => 
"null",
 
  434            default => gettype($value) . 
" " . Utils::printable((
string) $value)
 
  445    public static function printableTrace(array $trace, 
int $maxStringLength = 80) : array{
 
  447        for($i = 0; isset($trace[$i]); ++$i){
 
  449            if(isset($trace[$i][
"args"]) || isset($trace[$i][
"params"])){
 
  450                if(isset($trace[$i][
"args"])){
 
  451                    $args = $trace[$i][
"args"];
 
  453                    $args = $trace[$i][
"params"];
 
  459                foreach($args as $argId => $value){
 
  460                    $paramsList[] = ($argId === $offset ? 
"" : 
"$argId: ") . self::stringifyValueForTrace($value, $maxStringLength);
 
  463                $params = implode(
", ", $paramsList);
 
  465            $messages[] = 
"#$i " .
 
  466                (isset($trace[$i][
"file"]) ? Filesystem::cleanPath($trace[$i][
"file"]) : 
"") .
 
  467                "(" . (isset($trace[$i][
"line"]) ? $trace[$i][
"line"] : 
"") . 
"): " .
 
  468                (isset($trace[$i][
"class"]) ?
 
  469                    $trace[$i][
"class"] . (($trace[$i][
"type"] === 
"dynamic" || $trace[$i][
"type"] === 
"->") ? 
"->" : 
"::") :
 
  472                $trace[$i][
"function"] .
 
  473                "(" . Utils::printable($params) . 
")";
 
 
  488        $printableTrace = self::printableTrace($rawTrace, $maxStringLength);
 
  490        foreach($printableTrace as $frameId => $printableFrame){
 
  491            $rawFrame = $rawTrace[$frameId];
 
  494                $rawFrame[
"file"] ?? 
null,
 
  495                $rawFrame[
"line"] ?? 0
 
 
  508        if(function_exists(
"xdebug_get_function_stack") && count($trace = @xdebug_get_function_stack()) !== 0){
 
  509            $trace = array_reverse($trace);
 
  511            $e = new \Exception();
 
  512            $trace = $e->getTrace();
 
  514        for($i = 0; $i < $skipFrames; ++$i){
 
  517        return array_values($trace);
 
 
  524        return self::printableTrace(self::currentTrace(++$skipFrames));
 
 
  533        $rawDocComment = substr($docComment, 3, -2); 
 
  534        preg_match_all(
'/(*ANYCRLF)^[\t ]*(?:\* )?@([a-zA-Z\-]+)(?:[\t ]+(.+?))?[\t ]*$/m', $rawDocComment, $matches);
 
  536        return array_combine($matches[1], $matches[2]);
 
 
  544        $baseInterface = false;
 
  545        if(!class_exists($baseName)){
 
  546            if(!interface_exists($baseName)){
 
  547                throw new \InvalidArgumentException(
"Base class $baseName does not exist");
 
  549            $baseInterface = 
true;
 
  551        if(!class_exists($className)){
 
  552            throw new \InvalidArgumentException(
"Class $className does not exist or is not a class");
 
  554        if(!is_a($className, $baseName, 
true)){
 
  555            throw new \InvalidArgumentException(
"Class $className does not " . ($baseInterface ? 
"implement" : 
"extend") . 
" $baseName");
 
  557        $class = new \ReflectionClass($className);
 
  558        if(!$class->isInstantiable()){
 
  559            throw new \InvalidArgumentException(
"Class $className cannot be constructed");
 
 
  577            $signature = CallbackType::createFromCallable($signature);
 
  579        if(!$signature->isSatisfiedBy($subject)){
 
  580            throw new \TypeError(
"Declaration of callable `" . CallbackType::createFromCallable($subject) . 
"` must be compatible with `" . $signature . 
"`");
 
 
  590        foreach(
Utils::promoteKeys($array) as $k => $v){
 
  593            }
catch(\TypeError $e){
 
  594                throw new \TypeError(
"Incorrect type of element at \"$k\": " . $e->getMessage(), 0, $e);
 
 
  610        foreach($array as $key => $value){ 
 
  611            yield (
string) $key => $value;
 
 
  627    public static function checkUTF8(
string $string) : void{
 
  628        if(!mb_check_encoding($string, 
'UTF-8')){
 
  629            throw new \InvalidArgumentException(
"Text must be valid UTF-8");
 
  639    public static function assumeNotFalse(mixed $value, \Closure|
string $context = 
"This should never be false") : mixed{
 
  640        if($value === false){
 
  641            throw new AssumptionFailedError(
"Assumption failure: " . (is_string($context) ? $context : $context()) . 
" (THIS IS A BUG)");
 
 
  646    public static function checkFloatNotInfOrNaN(
string $name, 
float $float) : void{
 
  648            throw new \InvalidArgumentException(
"$name cannot be NaN");
 
  650        if(is_infinite($float)){
 
  651            throw new \InvalidArgumentException(
"$name cannot be infinite");
 
  655    public static function checkVector3NotInfOrNaN(Vector3 $vector3) : void{
 
  656        if($vector3 instanceof Location){ 
 
  657            self::checkFloatNotInfOrNaN(
"yaw", $vector3->yaw);
 
  658            self::checkFloatNotInfOrNaN(
"pitch", $vector3->pitch);
 
  660        self::checkFloatNotInfOrNaN(
"x", $vector3->x);
 
  661        self::checkFloatNotInfOrNaN(
"y", $vector3->y);
 
  662        self::checkFloatNotInfOrNaN(
"z", $vector3->z);
 
  665    public static function checkLocationNotInfOrNaN(Location $location) : void{
 
  666        self::checkVector3NotInfOrNaN($location);
 
  675            function_exists(
'opcache_get_status') &&
 
  676            ($opcacheStatus = opcache_get_status(false)) !== false &&
 
  677            isset($opcacheStatus[
"jit"][
"on"])
 
  679            $jit = $opcacheStatus[
"jit"];
 
  680            if($jit[
"on"] === 
true){
 
  681                return (($jit[
"opt_flags"] >> 2) * 1000) +
 
  682                    (($jit[
"opt_flags"] & 0x03) * 100) +
 
  683                    ($jit[
"kind"] * 10) +
 
 
  700        return mt_rand() / mt_getrandmax();